blob: 5c945353b0c77e70b9ae7c20ee1c6db469065d6c [file] [log] [blame]
sewardjc9a65702004-07-07 16:32:57 +00001
2/*--------------------------------------------------------------------*/
3/*--- ---*/
sewardjc0ee2ed2004-07-27 10:29:41 +00004/*--- This file (guest-x86/toIR.c) is ---*/
sewardjdbcfae72005-08-02 11:14:04 +00005/*--- Copyright (C) OpenWorks LLP. All rights reserved. ---*/
sewardjc9a65702004-07-07 16:32:57 +00006/*--- ---*/
7/*--------------------------------------------------------------------*/
8
sewardjf8ed9d82004-11-12 17:40:23 +00009/*
10 This file is part of LibVEX, a library for dynamic binary
11 instrumentation and translation.
12
sewardja26d8202008-02-11 11:35:40 +000013 Copyright (C) 2004-2008 OpenWorks LLP. All rights reserved.
sewardjf8ed9d82004-11-12 17:40:23 +000014
sewardj7bd6ffe2005-08-03 16:07:36 +000015 This library is made available under a dual licensing scheme.
sewardjf8ed9d82004-11-12 17:40:23 +000016
sewardj7bd6ffe2005-08-03 16:07:36 +000017 If you link LibVEX against other code all of which is itself
18 licensed under the GNU General Public License, version 2 dated June
19 1991 ("GPL v2"), then you may use LibVEX under the terms of the GPL
20 v2, as appearing in the file LICENSE.GPL. If the file LICENSE.GPL
21 is missing, you can obtain a copy of the GPL v2 from the Free
22 Software Foundation Inc., 51 Franklin St, Fifth Floor, Boston, MA
23 02110-1301, USA.
24
25 For any other uses of LibVEX, you must first obtain a commercial
26 license from OpenWorks LLP. Please contact info@open-works.co.uk
27 for information about commercial licensing.
28
29 This software is provided by OpenWorks LLP "as is" and any express
30 or implied warranties, including, but not limited to, the implied
31 warranties of merchantability and fitness for a particular purpose
32 are disclaimed. In no event shall OpenWorks LLP be liable for any
33 direct, indirect, incidental, special, exemplary, or consequential
34 damages (including, but not limited to, procurement of substitute
35 goods or services; loss of use, data, or profits; or business
36 interruption) however caused and on any theory of liability,
37 whether in contract, strict liability, or tort (including
38 negligence or otherwise) arising in any way out of the use of this
39 software, even if advised of the possibility of such damage.
sewardjf8ed9d82004-11-12 17:40:23 +000040
41 Neither the names of the U.S. Department of Energy nor the
42 University of California nor the names of its contributors may be
43 used to endorse or promote products derived from this software
44 without prior written permission.
sewardjf8ed9d82004-11-12 17:40:23 +000045*/
46
sewardj77b86be2004-07-11 13:28:24 +000047/* TODO:
sewardj45f1ff82005-05-05 12:04:14 +000048
sewardj3b3eacd2005-08-24 10:01:36 +000049 All Puts to CC_OP/CC_DEP1/CC_DEP2/CC_NDEP should really be checked
50 to ensure a 32-bit value is being written.
51
sewardj883b00b2004-09-11 09:30:24 +000052 FUCOMI(P): what happens to A and S flags? Currently are forced
53 to zero.
sewardj3f61ddb2004-10-16 20:51:05 +000054
sewardjce70a5c2004-10-18 14:09:54 +000055 x87 FP Limitations:
sewardja0e83b02005-01-06 12:36:38 +000056
57 * all arithmetic done at 64 bits
58
sewardj3f61ddb2004-10-16 20:51:05 +000059 * no FP exceptions, except for handling stack over/underflow
sewardja0e83b02005-01-06 12:36:38 +000060
sewardj3f61ddb2004-10-16 20:51:05 +000061 * FP rounding mode observed only for float->int conversions
sewardja0e83b02005-01-06 12:36:38 +000062 and int->float conversions which could lose accuracy, and
63 for float-to-float rounding. For all other operations,
64 round-to-nearest is used, regardless.
65
sewardj3f61ddb2004-10-16 20:51:05 +000066 * FP sin/cos/tan/sincos: C2 flag is always cleared. IOW the
67 simulation claims the argument is in-range (-2^63 <= arg <= 2^63)
68 even when it isn't.
sewardja0e83b02005-01-06 12:36:38 +000069
sewardje166ed02004-10-25 02:27:01 +000070 * some of the FCOM cases could do with testing -- not convinced
71 that the args are the right way round.
sewardj52444cb2004-12-13 14:09:01 +000072
sewardja0e83b02005-01-06 12:36:38 +000073 * FSAVE does not re-initialise the FPU; it should do
74
75 * FINIT not only initialises the FPU environment, it also
76 zeroes all the FP registers. It should leave the registers
77 unchanged.
78
sewardj9f8a3952005-04-06 10:27:11 +000079 RDTSC returns one, always.
sewardjcb2c99d2004-12-17 19:14:24 +000080
81 SAHF should cause eflags[1] == 1, and in fact it produces 0. As
82 per Intel docs this bit has no meaning anyway. Since PUSHF is the
83 only way to observe eflags[1], a proper fix would be to make that
84 bit be set by PUSHF.
85
sewardj6d269842005-08-06 11:45:02 +000086 The state of %eflags.AC (alignment check, bit 18) is recorded by
87 the simulation (viz, if you set it with popf then a pushf produces
88 the value you set it to), but it is otherwise ignored. In
89 particular, setting it to 1 does NOT cause alignment checking to
90 happen. Programs that set it to 1 and then rely on the resulting
91 SIGBUSs to inform them of misaligned accesses will not work.
92
sewardjf07ed032005-08-07 14:48:03 +000093 Implementation sysenter is necessarily partial. sysenter is a kind
94 of system call entry. When doing a sysenter, the return address is
95 not known -- that is something that is beyond Vex's knowledge. So
96 the generated IR forces a return to the scheduler, which can do
97 what it likes to simulate the systemter, but it MUST set this
98 thread's guest_EIP field with the continuation address before
99 resuming execution. If that doesn't happen, the thread will jump
100 to address zero, which is probably fatal.
101
sewardj52444cb2004-12-13 14:09:01 +0000102 This module uses global variables and so is not MT-safe (if that
sewardje395ae82005-02-26 02:00:50 +0000103 should ever become relevant).
104
105 The delta values are 32-bit ints, not 64-bit ints. That means
106 this module may not work right if run on a 64-bit host. That should
107 be fixed properly, really -- if anyone ever wants to use Vex to
sewardj45f1ff82005-05-05 12:04:14 +0000108 translate x86 code for execution on a 64-bit host. */
sewardje05c42c2004-07-08 20:25:10 +0000109
sewardj9f8a3952005-04-06 10:27:11 +0000110/* Performance holes:
111
112 - fcom ; fstsw %ax ; sahf
113 sahf does not update the O flag (sigh) and so O needs to
114 be computed. This is done expensively; it would be better
115 to have a calculate_eflags_o helper.
116
117 - emwarns; some FP codes can generate huge numbers of these
118 if the fpucw is changed in an inner loop. It would be
119 better for the guest state to have an emwarn-enable reg
120 which can be set zero or nonzero. If it is zero, emwarns
121 are not flagged, and instead control just flows all the
122 way through bbs as usual.
123*/
124
sewardjce02aa72006-01-12 12:27:58 +0000125/* "Special" instructions.
126
127 This instruction decoder can decode three special instructions
128 which mean nothing natively (are no-ops as far as regs/mem are
129 concerned) but have meaning for supporting Valgrind. A special
130 instruction is flagged by the 12-byte preamble C1C703 C1C70D C1C71D
131 C1C713 (in the standard interpretation, that means: roll $3, %edi;
132 roll $13, %edi; roll $29, %edi; roll $19, %edi). Following that,
133 one of the following 3 are allowed (standard interpretation in
134 parentheses):
135
136 87DB (xchgl %ebx,%ebx) %EDX = client_request ( %EAX )
137 87C9 (xchgl %ecx,%ecx) %EAX = guest_NRADDR
138 87D2 (xchgl %edx,%edx) call-noredir *%EAX
139
140 Any other bytes following the 12-byte preamble are illegal and
141 constitute a failure in instruction decoding. This all assumes
142 that the preamble will never occur except in specific code
143 fragments designed for Valgrind to catch.
144
145 No prefixes may precede a "Special" instruction.
146*/
147
148
sewardjc9a65702004-07-07 16:32:57 +0000149/* Translates x86 code to IR. */
150
151#include "libvex_basictypes.h"
152#include "libvex_ir.h"
sewardje87b4842004-07-10 12:23:30 +0000153#include "libvex.h"
sewardjf6dc3ce2004-10-19 01:03:46 +0000154#include "libvex_guest_x86.h"
sewardjc0ee2ed2004-07-27 10:29:41 +0000155
156#include "main/vex_util.h"
157#include "main/vex_globals.h"
sewardj9e6491a2005-07-02 19:24:10 +0000158#include "guest-generic/bb_to_IR.h"
sewardj879cee02006-03-07 01:15:50 +0000159#include "guest-generic/g_generic_x87.h"
sewardjc0ee2ed2004-07-27 10:29:41 +0000160#include "guest-x86/gdefs.h"
sewardjc9a65702004-07-07 16:32:57 +0000161
162
163/*------------------------------------------------------------*/
164/*--- Globals ---*/
165/*------------------------------------------------------------*/
166
sewardj9e6491a2005-07-02 19:24:10 +0000167/* These are set at the start of the translation of an insn, right
168 down in disInstr_X86, so that we don't have to pass them around
169 endlessly. They are all constant during the translation of any
170 given insn. */
sewardjc9a65702004-07-07 16:32:57 +0000171
172/* We need to know this to do sub-register accesses correctly. */
sewardjc9a65702004-07-07 16:32:57 +0000173static Bool host_is_bigendian;
174
sewardj9e6491a2005-07-02 19:24:10 +0000175/* Pointer to the guest code area (points to start of BB, not to the
176 insn being processed). */
sewardjc9a65702004-07-07 16:32:57 +0000177static UChar* guest_code;
178
179/* The guest address corresponding to guest_code[0]. */
sewardj9e6491a2005-07-02 19:24:10 +0000180static Addr32 guest_EIP_bbstart;
sewardjc9a65702004-07-07 16:32:57 +0000181
sewardj52444cb2004-12-13 14:09:01 +0000182/* The guest address for the instruction currently being
183 translated. */
sewardj9e6491a2005-07-02 19:24:10 +0000184static Addr32 guest_EIP_curr_instr;
sewardj52444cb2004-12-13 14:09:01 +0000185
sewardjdd40fdf2006-12-24 02:20:24 +0000186/* The IRSB* into which we're generating code. */
187static IRSB* irsb;
sewardjc9a65702004-07-07 16:32:57 +0000188
sewardjc9a65702004-07-07 16:32:57 +0000189
sewardjce70a5c2004-10-18 14:09:54 +0000190/*------------------------------------------------------------*/
191/*--- Debugging output ---*/
192/*------------------------------------------------------------*/
193
sewardjf48ac192004-10-29 00:41:29 +0000194#define DIP(format, args...) \
sewardj9e6491a2005-07-02 19:24:10 +0000195 if (vex_traceflags & VEX_TRACE_FE) \
sewardjce70a5c2004-10-18 14:09:54 +0000196 vex_printf(format, ## args)
197
sewardjf48ac192004-10-29 00:41:29 +0000198#define DIS(buf, format, args...) \
sewardj9e6491a2005-07-02 19:24:10 +0000199 if (vex_traceflags & VEX_TRACE_FE) \
sewardjce70a5c2004-10-18 14:09:54 +0000200 vex_sprintf(buf, format, ## args)
201
202
203/*------------------------------------------------------------*/
sewardjdcc85fc2004-10-26 13:26:20 +0000204/*--- Offsets of various parts of the x86 guest state. ---*/
205/*------------------------------------------------------------*/
206
sewardjc9a43662004-11-30 18:51:59 +0000207#define OFFB_EAX offsetof(VexGuestX86State,guest_EAX)
208#define OFFB_EBX offsetof(VexGuestX86State,guest_EBX)
209#define OFFB_ECX offsetof(VexGuestX86State,guest_ECX)
210#define OFFB_EDX offsetof(VexGuestX86State,guest_EDX)
211#define OFFB_ESP offsetof(VexGuestX86State,guest_ESP)
212#define OFFB_EBP offsetof(VexGuestX86State,guest_EBP)
213#define OFFB_ESI offsetof(VexGuestX86State,guest_ESI)
214#define OFFB_EDI offsetof(VexGuestX86State,guest_EDI)
sewardj2a2ba8b2004-11-08 13:14:06 +0000215
sewardjc9a43662004-11-30 18:51:59 +0000216#define OFFB_EIP offsetof(VexGuestX86State,guest_EIP)
sewardj2a2ba8b2004-11-08 13:14:06 +0000217
sewardjc9a43662004-11-30 18:51:59 +0000218#define OFFB_CC_OP offsetof(VexGuestX86State,guest_CC_OP)
219#define OFFB_CC_DEP1 offsetof(VexGuestX86State,guest_CC_DEP1)
220#define OFFB_CC_DEP2 offsetof(VexGuestX86State,guest_CC_DEP2)
221#define OFFB_CC_NDEP offsetof(VexGuestX86State,guest_CC_NDEP)
sewardj893aada2004-11-29 19:57:54 +0000222
sewardjc9a43662004-11-30 18:51:59 +0000223#define OFFB_FPREGS offsetof(VexGuestX86State,guest_FPREG[0])
224#define OFFB_FPTAGS offsetof(VexGuestX86State,guest_FPTAG[0])
225#define OFFB_DFLAG offsetof(VexGuestX86State,guest_DFLAG)
226#define OFFB_IDFLAG offsetof(VexGuestX86State,guest_IDFLAG)
sewardj6d269842005-08-06 11:45:02 +0000227#define OFFB_ACFLAG offsetof(VexGuestX86State,guest_ACFLAG)
sewardjc9a43662004-11-30 18:51:59 +0000228#define OFFB_FTOP offsetof(VexGuestX86State,guest_FTOP)
229#define OFFB_FC3210 offsetof(VexGuestX86State,guest_FC3210)
230#define OFFB_FPROUND offsetof(VexGuestX86State,guest_FPROUND)
231
232#define OFFB_CS offsetof(VexGuestX86State,guest_CS)
233#define OFFB_DS offsetof(VexGuestX86State,guest_DS)
234#define OFFB_ES offsetof(VexGuestX86State,guest_ES)
235#define OFFB_FS offsetof(VexGuestX86State,guest_FS)
236#define OFFB_GS offsetof(VexGuestX86State,guest_GS)
237#define OFFB_SS offsetof(VexGuestX86State,guest_SS)
sewardj3bd6f3e2004-12-13 10:48:19 +0000238#define OFFB_LDT offsetof(VexGuestX86State,guest_LDT)
239#define OFFB_GDT offsetof(VexGuestX86State,guest_GDT)
sewardjc9a43662004-11-30 18:51:59 +0000240
241#define OFFB_SSEROUND offsetof(VexGuestX86State,guest_SSEROUND)
242#define OFFB_XMM0 offsetof(VexGuestX86State,guest_XMM0)
243#define OFFB_XMM1 offsetof(VexGuestX86State,guest_XMM1)
244#define OFFB_XMM2 offsetof(VexGuestX86State,guest_XMM2)
245#define OFFB_XMM3 offsetof(VexGuestX86State,guest_XMM3)
246#define OFFB_XMM4 offsetof(VexGuestX86State,guest_XMM4)
247#define OFFB_XMM5 offsetof(VexGuestX86State,guest_XMM5)
248#define OFFB_XMM6 offsetof(VexGuestX86State,guest_XMM6)
249#define OFFB_XMM7 offsetof(VexGuestX86State,guest_XMM7)
250
251#define OFFB_EMWARN offsetof(VexGuestX86State,guest_EMWARN)
sewardjdcc85fc2004-10-26 13:26:20 +0000252
sewardjbfceb082005-11-15 11:16:30 +0000253#define OFFB_TISTART offsetof(VexGuestX86State,guest_TISTART)
254#define OFFB_TILEN offsetof(VexGuestX86State,guest_TILEN)
sewardjce02aa72006-01-12 12:27:58 +0000255#define OFFB_NRADDR offsetof(VexGuestX86State,guest_NRADDR)
256
sewardjdcc85fc2004-10-26 13:26:20 +0000257
258/*------------------------------------------------------------*/
sewardjce70a5c2004-10-18 14:09:54 +0000259/*--- Helper bits and pieces for deconstructing the ---*/
260/*--- x86 insn stream. ---*/
261/*------------------------------------------------------------*/
262
263/* This is the Intel register encoding -- integer regs. */
264#define R_EAX 0
265#define R_ECX 1
266#define R_EDX 2
267#define R_EBX 3
268#define R_ESP 4
269#define R_EBP 5
270#define R_ESI 6
271#define R_EDI 7
272
273#define R_AL (0+R_EAX)
274#define R_AH (4+R_EAX)
275
sewardj063f02f2004-10-20 12:36:12 +0000276/* This is the Intel register encoding -- segment regs. */
277#define R_ES 0
278#define R_CS 1
279#define R_SS 2
280#define R_DS 3
281#define R_FS 4
282#define R_GS 5
283
sewardjce70a5c2004-10-18 14:09:54 +0000284
sewardjc9a65702004-07-07 16:32:57 +0000285/* Add a statement to the list held by "irbb". */
sewardjd7cb8532004-08-17 23:59:23 +0000286static void stmt ( IRStmt* st )
sewardjc9a65702004-07-07 16:32:57 +0000287{
sewardjdd40fdf2006-12-24 02:20:24 +0000288 addStmtToIRSB( irsb, st );
sewardjc9a65702004-07-07 16:32:57 +0000289}
290
291/* Generate a new temporary of the given type. */
292static IRTemp newTemp ( IRType ty )
293{
sewardj496a58d2005-03-20 18:44:44 +0000294 vassert(isPlausibleIRType(ty));
sewardjdd40fdf2006-12-24 02:20:24 +0000295 return newIRTemp( irsb->tyenv, ty );
sewardjc9a65702004-07-07 16:32:57 +0000296}
297
sewardjce70a5c2004-10-18 14:09:54 +0000298/* Various simple conversions */
sewardjd1061ab2004-07-08 01:45:30 +0000299
sewardje05c42c2004-07-08 20:25:10 +0000300static UInt extend_s_8to32( UInt x )
sewardjd1061ab2004-07-08 01:45:30 +0000301{
302 return (UInt)((((Int)x) << 24) >> 24);
303}
304
sewardj0611d802004-07-11 02:37:54 +0000305static UInt extend_s_16to32 ( UInt x )
306{
307 return (UInt)((((Int)x) << 16) >> 16);
308}
309
sewardjd1061ab2004-07-08 01:45:30 +0000310/* Fetch a byte from the guest insn stream. */
sewardj52d04912005-07-03 00:52:48 +0000311static UChar getIByte ( Int delta )
sewardjd1061ab2004-07-08 01:45:30 +0000312{
313 return guest_code[delta];
314}
315
sewardjc9a65702004-07-07 16:32:57 +0000316/* Extract the reg field from a modRM byte. */
sewardje05c42c2004-07-08 20:25:10 +0000317static Int gregOfRM ( UChar mod_reg_rm )
sewardjc9a65702004-07-07 16:32:57 +0000318{
319 return (Int)( (mod_reg_rm >> 3) & 7 );
320}
321
322/* Figure out whether the mod and rm parts of a modRM byte refer to a
323 register or memory. If so, the byte will have the form 11XXXYYY,
324 where YYY is the register number. */
sewardje05c42c2004-07-08 20:25:10 +0000325static Bool epartIsReg ( UChar mod_reg_rm )
sewardjc9a65702004-07-07 16:32:57 +0000326{
sewardj2d49b432005-02-01 00:37:06 +0000327 return toBool(0xC0 == (mod_reg_rm & 0xC0));
sewardjc9a65702004-07-07 16:32:57 +0000328}
329
330/* ... and extract the register number ... */
sewardje05c42c2004-07-08 20:25:10 +0000331static Int eregOfRM ( UChar mod_reg_rm )
sewardjc9a65702004-07-07 16:32:57 +0000332{
333 return (Int)(mod_reg_rm & 0x7);
334}
335
sewardje05c42c2004-07-08 20:25:10 +0000336/* Get a 8/16/32-bit unsigned value out of the insn stream. */
337
sewardj52d04912005-07-03 00:52:48 +0000338static UChar getUChar ( Int delta )
sewardje05c42c2004-07-08 20:25:10 +0000339{
sewardj2d49b432005-02-01 00:37:06 +0000340 UChar v = guest_code[delta+0];
sewardj9b45b482005-02-07 01:42:18 +0000341 return toUChar(v);
sewardje05c42c2004-07-08 20:25:10 +0000342}
343
sewardj52d04912005-07-03 00:52:48 +0000344static UInt getUDisp16 ( Int delta )
sewardje05c42c2004-07-08 20:25:10 +0000345{
346 UInt v = guest_code[delta+1]; v <<= 8;
347 v |= guest_code[delta+0];
348 return v & 0xFFFF;
349}
350
sewardj52d04912005-07-03 00:52:48 +0000351static UInt getUDisp32 ( Int delta )
sewardjd1061ab2004-07-08 01:45:30 +0000352{
353 UInt v = guest_code[delta+3]; v <<= 8;
354 v |= guest_code[delta+2]; v <<= 8;
355 v |= guest_code[delta+1]; v <<= 8;
356 v |= guest_code[delta+0];
357 return v;
358}
359
sewardj52d04912005-07-03 00:52:48 +0000360static UInt getUDisp ( Int size, Int delta )
sewardje05c42c2004-07-08 20:25:10 +0000361{
362 switch (size) {
363 case 4: return getUDisp32(delta);
364 case 2: return getUDisp16(delta);
sewardj2d49b432005-02-01 00:37:06 +0000365 case 1: return (UInt)getUChar(delta);
sewardje05c42c2004-07-08 20:25:10 +0000366 default: vpanic("getUDisp(x86)");
367 }
368 return 0; /*notreached*/
369}
370
371
sewardjd1061ab2004-07-08 01:45:30 +0000372/* Get a byte value out of the insn stream and sign-extend to 32
373 bits. */
sewardj52d04912005-07-03 00:52:48 +0000374static UInt getSDisp8 ( Int delta )
sewardjd1061ab2004-07-08 01:45:30 +0000375{
376 return extend_s_8to32( (UInt) (guest_code[delta]) );
377}
378
sewardj52d04912005-07-03 00:52:48 +0000379static UInt getSDisp16 ( Int delta0 )
sewardj0611d802004-07-11 02:37:54 +0000380{
381 UChar* eip = (UChar*)(&guest_code[delta0]);
382 UInt d = *eip++;
383 d |= ((*eip++) << 8);
384 return extend_s_16to32(d);
385}
386
sewardj52d04912005-07-03 00:52:48 +0000387static UInt getSDisp ( Int size, Int delta )
sewardj0611d802004-07-11 02:37:54 +0000388{
389 switch (size) {
390 case 4: return getUDisp32(delta);
391 case 2: return getSDisp16(delta);
392 case 1: return getSDisp8(delta);
393 default: vpanic("getSDisp(x86)");
394 }
395 return 0; /*notreached*/
396}
sewardjd1061ab2004-07-08 01:45:30 +0000397
sewardjc9a65702004-07-07 16:32:57 +0000398
399/*------------------------------------------------------------*/
400/*--- Helpers for constructing IR. ---*/
401/*------------------------------------------------------------*/
402
403/* Create a 1/2/4 byte read of an x86 integer registers. For 16/8 bit
404 register references, we need to take the host endianness into
405 account. Supplied value is 0 .. 7 and in the Intel instruction
406 encoding. */
sewardje05c42c2004-07-08 20:25:10 +0000407
sewardj9334b0f2004-07-10 22:43:54 +0000408static IRType szToITy ( Int n )
409{
410 switch (n) {
411 case 1: return Ity_I8;
412 case 2: return Ity_I16;
413 case 4: return Ity_I32;
414 default: vpanic("szToITy(x86)");
415 }
416}
417
sewardj67e002d2004-12-02 18:16:33 +0000418/* On a little-endian host, less significant bits of the guest
419 registers are at lower addresses. Therefore, if a reference to a
420 register low half has the safe guest state offset as a reference to
421 the full register.
422*/
sewardj9334b0f2004-07-10 22:43:54 +0000423static Int integerGuestRegOffset ( Int sz, UInt archreg )
424{
425 vassert(archreg < 8);
426
sewardj9334b0f2004-07-10 22:43:54 +0000427 /* Correct for little-endian host only. */
sewardj67e002d2004-12-02 18:16:33 +0000428 vassert(!host_is_bigendian);
sewardj063f02f2004-10-20 12:36:12 +0000429
430 if (sz == 4 || sz == 2 || (sz == 1 && archreg < 4)) {
431 switch (archreg) {
sewardjc9a43662004-11-30 18:51:59 +0000432 case R_EAX: return OFFB_EAX;
433 case R_EBX: return OFFB_EBX;
434 case R_ECX: return OFFB_ECX;
435 case R_EDX: return OFFB_EDX;
436 case R_ESI: return OFFB_ESI;
437 case R_EDI: return OFFB_EDI;
438 case R_ESP: return OFFB_ESP;
439 case R_EBP: return OFFB_EBP;
sewardj063f02f2004-10-20 12:36:12 +0000440 default: vpanic("integerGuestRegOffset(x86,le)(4,2)");
441 }
442 }
443
444 vassert(archreg >= 4 && archreg < 8 && sz == 1);
445 switch (archreg-4) {
sewardjc9a43662004-11-30 18:51:59 +0000446 case R_EAX: return 1+ OFFB_EAX;
447 case R_EBX: return 1+ OFFB_EBX;
448 case R_ECX: return 1+ OFFB_ECX;
449 case R_EDX: return 1+ OFFB_EDX;
sewardj063f02f2004-10-20 12:36:12 +0000450 default: vpanic("integerGuestRegOffset(x86,le)(1h)");
451 }
452
453 /* NOTREACHED */
454 vpanic("integerGuestRegOffset(x86,le)");
455}
456
457static Int segmentGuestRegOffset ( UInt sreg )
458{
459 switch (sreg) {
sewardjc9a43662004-11-30 18:51:59 +0000460 case R_ES: return OFFB_ES;
461 case R_CS: return OFFB_CS;
462 case R_SS: return OFFB_SS;
463 case R_DS: return OFFB_DS;
464 case R_FS: return OFFB_FS;
465 case R_GS: return OFFB_GS;
sewardj063f02f2004-10-20 12:36:12 +0000466 default: vpanic("segmentGuestRegOffset(x86)");
sewardj9334b0f2004-07-10 22:43:54 +0000467 }
468}
469
sewardjc9a43662004-11-30 18:51:59 +0000470static Int xmmGuestRegOffset ( UInt xmmreg )
471{
472 switch (xmmreg) {
473 case 0: return OFFB_XMM0;
474 case 1: return OFFB_XMM1;
475 case 2: return OFFB_XMM2;
476 case 3: return OFFB_XMM3;
477 case 4: return OFFB_XMM4;
478 case 5: return OFFB_XMM5;
479 case 6: return OFFB_XMM6;
480 case 7: return OFFB_XMM7;
481 default: vpanic("xmmGuestRegOffset");
482 }
483}
484
sewardj67e002d2004-12-02 18:16:33 +0000485/* Lanes of vector registers are always numbered from zero being the
486 least significant lane (rightmost in the register). */
487
sewardje5854d62004-12-09 03:44:34 +0000488static Int xmmGuestRegLane16offset ( UInt xmmreg, Int laneno )
489{
490 /* Correct for little-endian host only. */
491 vassert(!host_is_bigendian);
492 vassert(laneno >= 0 && laneno < 8);
493 return xmmGuestRegOffset( xmmreg ) + 2 * laneno;
494}
495
sewardj67e002d2004-12-02 18:16:33 +0000496static Int xmmGuestRegLane32offset ( UInt xmmreg, Int laneno )
497{
498 /* Correct for little-endian host only. */
499 vassert(!host_is_bigendian);
500 vassert(laneno >= 0 && laneno < 4);
501 return xmmGuestRegOffset( xmmreg ) + 4 * laneno;
502}
503
504static Int xmmGuestRegLane64offset ( UInt xmmreg, Int laneno )
505{
506 /* Correct for little-endian host only. */
507 vassert(!host_is_bigendian);
508 vassert(laneno >= 0 && laneno < 2);
509 return xmmGuestRegOffset( xmmreg ) + 8 * laneno;
510}
511
sewardjd1061ab2004-07-08 01:45:30 +0000512static IRExpr* getIReg ( Int sz, UInt archreg )
sewardjc9a65702004-07-07 16:32:57 +0000513{
514 vassert(sz == 1 || sz == 2 || sz == 4);
515 vassert(archreg < 8);
sewardj9334b0f2004-07-10 22:43:54 +0000516 return IRExpr_Get( integerGuestRegOffset(sz,archreg),
sewardj5bd4d162004-11-10 13:02:48 +0000517 szToITy(sz) );
sewardjc9a65702004-07-07 16:32:57 +0000518}
519
520/* Ditto, but write to a reg instead. */
sewardj41f43bc2004-07-08 14:23:22 +0000521static void putIReg ( Int sz, UInt archreg, IRExpr* e )
sewardjc9a65702004-07-07 16:32:57 +0000522{
sewardjdd40fdf2006-12-24 02:20:24 +0000523 IRType ty = typeOfIRExpr(irsb->tyenv, e);
sewardjd24931d2005-03-20 12:51:39 +0000524 switch (sz) {
525 case 1: vassert(ty == Ity_I8); break;
526 case 2: vassert(ty == Ity_I16); break;
527 case 4: vassert(ty == Ity_I32); break;
528 default: vpanic("putIReg(x86)");
529 }
sewardjc9a65702004-07-07 16:32:57 +0000530 vassert(archreg < 8);
sewardjeeb9ef82004-07-15 12:39:03 +0000531 stmt( IRStmt_Put(integerGuestRegOffset(sz,archreg), e) );
sewardjd1061ab2004-07-08 01:45:30 +0000532}
533
sewardj063f02f2004-10-20 12:36:12 +0000534static IRExpr* getSReg ( UInt sreg )
535{
536 return IRExpr_Get( segmentGuestRegOffset(sreg), Ity_I16 );
537}
538
539static void putSReg ( UInt sreg, IRExpr* e )
540{
sewardjdd40fdf2006-12-24 02:20:24 +0000541 vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_I16);
sewardj063f02f2004-10-20 12:36:12 +0000542 stmt( IRStmt_Put( segmentGuestRegOffset(sreg), e ) );
543}
544
sewardjc9a43662004-11-30 18:51:59 +0000545static IRExpr* getXMMReg ( UInt xmmreg )
546{
547 return IRExpr_Get( xmmGuestRegOffset(xmmreg), Ity_V128 );
548}
549
sewardj67e002d2004-12-02 18:16:33 +0000550static IRExpr* getXMMRegLane64 ( UInt xmmreg, Int laneno )
551{
552 return IRExpr_Get( xmmGuestRegLane64offset(xmmreg,laneno), Ity_I64 );
553}
554
sewardjfd226452004-12-07 19:02:18 +0000555static IRExpr* getXMMRegLane64F ( UInt xmmreg, Int laneno )
sewardj67e002d2004-12-02 18:16:33 +0000556{
sewardjfd226452004-12-07 19:02:18 +0000557 return IRExpr_Get( xmmGuestRegLane64offset(xmmreg,laneno), Ity_F64 );
sewardj67e002d2004-12-02 18:16:33 +0000558}
559
sewardj9636b442004-12-04 01:38:37 +0000560static IRExpr* getXMMRegLane32 ( UInt xmmreg, Int laneno )
561{
562 return IRExpr_Get( xmmGuestRegLane32offset(xmmreg,laneno), Ity_I32 );
563}
564
sewardjfd226452004-12-07 19:02:18 +0000565static IRExpr* getXMMRegLane32F ( UInt xmmreg, Int laneno )
566{
567 return IRExpr_Get( xmmGuestRegLane32offset(xmmreg,laneno), Ity_F32 );
568}
569
sewardjc9a43662004-11-30 18:51:59 +0000570static void putXMMReg ( UInt xmmreg, IRExpr* e )
571{
sewardjdd40fdf2006-12-24 02:20:24 +0000572 vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_V128);
sewardjc9a43662004-11-30 18:51:59 +0000573 stmt( IRStmt_Put( xmmGuestRegOffset(xmmreg), e ) );
574}
575
sewardj67e002d2004-12-02 18:16:33 +0000576static void putXMMRegLane64 ( UInt xmmreg, Int laneno, IRExpr* e )
577{
sewardjdd40fdf2006-12-24 02:20:24 +0000578 vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_I64);
sewardj67e002d2004-12-02 18:16:33 +0000579 stmt( IRStmt_Put( xmmGuestRegLane64offset(xmmreg,laneno), e ) );
580}
581
sewardjfd226452004-12-07 19:02:18 +0000582static void putXMMRegLane64F ( UInt xmmreg, Int laneno, IRExpr* e )
583{
sewardjdd40fdf2006-12-24 02:20:24 +0000584 vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_F64);
sewardjfd226452004-12-07 19:02:18 +0000585 stmt( IRStmt_Put( xmmGuestRegLane64offset(xmmreg,laneno), e ) );
586}
587
sewardj4cb918d2004-12-03 19:43:31 +0000588static void putXMMRegLane32F ( UInt xmmreg, Int laneno, IRExpr* e )
sewardj67e002d2004-12-02 18:16:33 +0000589{
sewardjdd40fdf2006-12-24 02:20:24 +0000590 vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_F32);
sewardj67e002d2004-12-02 18:16:33 +0000591 stmt( IRStmt_Put( xmmGuestRegLane32offset(xmmreg,laneno), e ) );
592}
593
sewardj9636b442004-12-04 01:38:37 +0000594static void putXMMRegLane32 ( UInt xmmreg, Int laneno, IRExpr* e )
595{
sewardjdd40fdf2006-12-24 02:20:24 +0000596 vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_I32);
sewardj9636b442004-12-04 01:38:37 +0000597 stmt( IRStmt_Put( xmmGuestRegLane32offset(xmmreg,laneno), e ) );
598}
599
sewardje5854d62004-12-09 03:44:34 +0000600static void putXMMRegLane16 ( UInt xmmreg, Int laneno, IRExpr* e )
601{
sewardjdd40fdf2006-12-24 02:20:24 +0000602 vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_I16);
sewardje5854d62004-12-09 03:44:34 +0000603 stmt( IRStmt_Put( xmmGuestRegLane16offset(xmmreg,laneno), e ) );
604}
605
sewardj41f43bc2004-07-08 14:23:22 +0000606static void assign ( IRTemp dst, IRExpr* e )
sewardjd1061ab2004-07-08 01:45:30 +0000607{
sewardjdd40fdf2006-12-24 02:20:24 +0000608 stmt( IRStmt_WrTmp(dst, e) );
sewardjd1061ab2004-07-08 01:45:30 +0000609}
610
sewardj41f43bc2004-07-08 14:23:22 +0000611static void storeLE ( IRExpr* addr, IRExpr* data )
sewardjd1061ab2004-07-08 01:45:30 +0000612{
sewardjaf1ceca2005-06-30 23:31:27 +0000613 stmt( IRStmt_Store(Iend_LE,addr,data) );
sewardjd1061ab2004-07-08 01:45:30 +0000614}
615
sewardje87b4842004-07-10 12:23:30 +0000616static IRExpr* unop ( IROp op, IRExpr* a )
617{
618 return IRExpr_Unop(op, a);
619}
620
sewardjd1061ab2004-07-08 01:45:30 +0000621static IRExpr* binop ( IROp op, IRExpr* a1, IRExpr* a2 )
622{
623 return IRExpr_Binop(op, a1, a2);
624}
625
sewardjf1b5b1a2006-02-03 22:54:17 +0000626static IRExpr* triop ( IROp op, IRExpr* a1, IRExpr* a2, IRExpr* a3 )
627{
628 return IRExpr_Triop(op, a1, a2, a3);
629}
630
sewardjd1061ab2004-07-08 01:45:30 +0000631static IRExpr* mkexpr ( IRTemp tmp )
632{
sewardjdd40fdf2006-12-24 02:20:24 +0000633 return IRExpr_RdTmp(tmp);
sewardjd1061ab2004-07-08 01:45:30 +0000634}
635
sewardjc2ac51e2004-07-12 01:03:26 +0000636static IRExpr* mkU8 ( UInt i )
637{
638 vassert(i < 256);
sewardj2d49b432005-02-01 00:37:06 +0000639 return IRExpr_Const(IRConst_U8( (UChar)i ));
sewardjc2ac51e2004-07-12 01:03:26 +0000640}
641
642static IRExpr* mkU16 ( UInt i )
643{
644 vassert(i < 65536);
sewardj2d49b432005-02-01 00:37:06 +0000645 return IRExpr_Const(IRConst_U16( (UShort)i ));
sewardjc2ac51e2004-07-12 01:03:26 +0000646}
647
sewardjd1061ab2004-07-08 01:45:30 +0000648static IRExpr* mkU32 ( UInt i )
649{
650 return IRExpr_Const(IRConst_U32(i));
sewardjc9a65702004-07-07 16:32:57 +0000651}
652
sewardj95535fe2004-12-15 17:42:58 +0000653static IRExpr* mkU64 ( ULong i )
654{
655 return IRExpr_Const(IRConst_U64(i));
656}
657
sewardj41f43bc2004-07-08 14:23:22 +0000658static IRExpr* mkU ( IRType ty, UInt i )
659{
sewardjc2ac51e2004-07-12 01:03:26 +0000660 if (ty == Ity_I8) return mkU8(i);
661 if (ty == Ity_I16) return mkU16(i);
662 if (ty == Ity_I32) return mkU32(i);
sewardje90ad6a2004-07-10 19:02:10 +0000663 /* If this panics, it usually means you passed a size (1,2,4)
664 value as the IRType, rather than a real IRType. */
sewardj41f43bc2004-07-08 14:23:22 +0000665 vpanic("mkU(x86)");
666}
667
sewardj1e6ad742004-12-02 16:16:11 +0000668static IRExpr* mkV128 ( UShort mask )
669{
670 return IRExpr_Const(IRConst_V128(mask));
671}
672
sewardj41f43bc2004-07-08 14:23:22 +0000673static IRExpr* loadLE ( IRType ty, IRExpr* data )
674{
sewardjaf1ceca2005-06-30 23:31:27 +0000675 return IRExpr_Load(Iend_LE,ty,data);
sewardj41f43bc2004-07-08 14:23:22 +0000676}
677
678static IROp mkSizedOp ( IRType ty, IROp op8 )
679{
sewardje05c42c2004-07-08 20:25:10 +0000680 Int adj;
sewardj41f43bc2004-07-08 14:23:22 +0000681 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
682 vassert(op8 == Iop_Add8 || op8 == Iop_Sub8
sewardj41f43bc2004-07-08 14:23:22 +0000683 || op8 == Iop_Mul8
684 || op8 == Iop_Or8 || op8 == Iop_And8 || op8 == Iop_Xor8
sewardj5bd4d162004-11-10 13:02:48 +0000685 || op8 == Iop_Shl8 || op8 == Iop_Shr8 || op8 == Iop_Sar8
sewardje90ad6a2004-07-10 19:02:10 +0000686 || op8 == Iop_CmpEQ8 || op8 == Iop_CmpNE8
sewardjeb17e492007-08-25 23:07:44 +0000687 || op8 == Iop_Not8);
sewardje05c42c2004-07-08 20:25:10 +0000688 adj = ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
689 return adj + op8;
sewardj41f43bc2004-07-08 14:23:22 +0000690}
691
sewardj9334b0f2004-07-10 22:43:54 +0000692static IROp mkWidenOp ( Int szSmall, Int szBig, Bool signd )
sewardj41f43bc2004-07-08 14:23:22 +0000693{
sewardj9334b0f2004-07-10 22:43:54 +0000694 if (szSmall == 1 && szBig == 4) {
695 return signd ? Iop_8Sto32 : Iop_8Uto32;
sewardj41f43bc2004-07-08 14:23:22 +0000696 }
sewardj9334b0f2004-07-10 22:43:54 +0000697 if (szSmall == 1 && szBig == 2) {
698 return signd ? Iop_8Sto16 : Iop_8Uto16;
699 }
700 if (szSmall == 2 && szBig == 4) {
701 return signd ? Iop_16Sto32 : Iop_16Uto32;
702 }
sewardj948d48b2004-11-05 19:49:09 +0000703 vpanic("mkWidenOp(x86,guest)");
sewardj41f43bc2004-07-08 14:23:22 +0000704}
705
sewardjbaa66082005-08-23 17:29:27 +0000706static IRExpr* mkAnd1 ( IRExpr* x, IRExpr* y )
707{
sewardjdd40fdf2006-12-24 02:20:24 +0000708 vassert(typeOfIRExpr(irsb->tyenv,x) == Ity_I1);
709 vassert(typeOfIRExpr(irsb->tyenv,y) == Ity_I1);
sewardjbaa66082005-08-23 17:29:27 +0000710 return unop(Iop_32to1,
711 binop(Iop_And32,
712 unop(Iop_1Uto32,x),
713 unop(Iop_1Uto32,y)));
714}
715
sewardj41f43bc2004-07-08 14:23:22 +0000716
717/*------------------------------------------------------------*/
718/*--- Helpers for %eflags. ---*/
719/*------------------------------------------------------------*/
720
sewardj0611d802004-07-11 02:37:54 +0000721/* -------------- Evaluating the flags-thunk. -------------- */
sewardjc9a65702004-07-07 16:32:57 +0000722
sewardje87b4842004-07-10 12:23:30 +0000723/* Build IR to calculate all the eflags from stored
sewardj2a2ba8b2004-11-08 13:14:06 +0000724 CC_OP/CC_DEP1/CC_DEP2/CC_NDEP. Returns an expression ::
725 Ity_I32. */
sewardj2a9ad022004-11-25 02:46:58 +0000726static IRExpr* mk_x86g_calculate_eflags_all ( void )
sewardje87b4842004-07-10 12:23:30 +0000727{
sewardjf9655262004-10-31 20:02:16 +0000728 IRExpr** args
sewardj2a2ba8b2004-11-08 13:14:06 +0000729 = mkIRExprVec_4( IRExpr_Get(OFFB_CC_OP, Ity_I32),
730 IRExpr_Get(OFFB_CC_DEP1, Ity_I32),
731 IRExpr_Get(OFFB_CC_DEP2, Ity_I32),
732 IRExpr_Get(OFFB_CC_NDEP, Ity_I32) );
sewardj43c56462004-11-06 12:17:57 +0000733 IRExpr* call
734 = mkIRExprCCall(
735 Ity_I32,
736 0/*regparm*/,
sewardj2a9ad022004-11-25 02:46:58 +0000737 "x86g_calculate_eflags_all", &x86g_calculate_eflags_all,
sewardj43c56462004-11-06 12:17:57 +0000738 args
739 );
sewardj2a2ba8b2004-11-08 13:14:06 +0000740 /* Exclude OP and NDEP from definedness checking. We're only
741 interested in DEP1 and DEP2. */
742 call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<3);
sewardj43c56462004-11-06 12:17:57 +0000743 return call;
sewardje87b4842004-07-10 12:23:30 +0000744}
745
sewardj84ff0652004-08-23 16:16:08 +0000746/* Build IR to calculate some particular condition from stored
sewardj2a2ba8b2004-11-08 13:14:06 +0000747 CC_OP/CC_DEP1/CC_DEP2/CC_NDEP. Returns an expression ::
748 Ity_Bit. */
sewardj2a9ad022004-11-25 02:46:58 +0000749static IRExpr* mk_x86g_calculate_condition ( X86Condcode cond )
sewardj84ff0652004-08-23 16:16:08 +0000750{
sewardjf9655262004-10-31 20:02:16 +0000751 IRExpr** args
sewardj2a2ba8b2004-11-08 13:14:06 +0000752 = mkIRExprVec_5( mkU32(cond),
sewardjf9655262004-10-31 20:02:16 +0000753 IRExpr_Get(OFFB_CC_OP, Ity_I32),
sewardj2a2ba8b2004-11-08 13:14:06 +0000754 IRExpr_Get(OFFB_CC_DEP1, Ity_I32),
755 IRExpr_Get(OFFB_CC_DEP2, Ity_I32),
756 IRExpr_Get(OFFB_CC_NDEP, Ity_I32) );
sewardj43c56462004-11-06 12:17:57 +0000757 IRExpr* call
758 = mkIRExprCCall(
759 Ity_I32,
760 0/*regparm*/,
sewardj2a9ad022004-11-25 02:46:58 +0000761 "x86g_calculate_condition", &x86g_calculate_condition,
sewardj43c56462004-11-06 12:17:57 +0000762 args
763 );
sewardj2a2ba8b2004-11-08 13:14:06 +0000764 /* Exclude the requested condition, OP and NDEP from definedness
765 checking. We're only interested in DEP1 and DEP2. */
766 call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<1) | (1<<4);
sewardj43c56462004-11-06 12:17:57 +0000767 return unop(Iop_32to1, call);
768}
769
770/* Build IR to calculate just the carry flag from stored
sewardj2a2ba8b2004-11-08 13:14:06 +0000771 CC_OP/CC_DEP1/CC_DEP2/CC_NDEP. Returns an expression :: Ity_I32. */
sewardj2a9ad022004-11-25 02:46:58 +0000772static IRExpr* mk_x86g_calculate_eflags_c ( void )
sewardj43c56462004-11-06 12:17:57 +0000773{
774 IRExpr** args
sewardj2a2ba8b2004-11-08 13:14:06 +0000775 = mkIRExprVec_4( IRExpr_Get(OFFB_CC_OP, Ity_I32),
776 IRExpr_Get(OFFB_CC_DEP1, Ity_I32),
777 IRExpr_Get(OFFB_CC_DEP2, Ity_I32),
778 IRExpr_Get(OFFB_CC_NDEP, Ity_I32) );
sewardj43c56462004-11-06 12:17:57 +0000779 IRExpr* call
780 = mkIRExprCCall(
781 Ity_I32,
sewardj893a3302005-01-24 10:49:02 +0000782 3/*regparm*/,
sewardj2a9ad022004-11-25 02:46:58 +0000783 "x86g_calculate_eflags_c", &x86g_calculate_eflags_c,
sewardj43c56462004-11-06 12:17:57 +0000784 args
785 );
sewardj2a2ba8b2004-11-08 13:14:06 +0000786 /* Exclude OP and NDEP from definedness checking. We're only
787 interested in DEP1 and DEP2. */
788 call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<3);
sewardj43c56462004-11-06 12:17:57 +0000789 return call;
sewardj84ff0652004-08-23 16:16:08 +0000790}
791
sewardje87b4842004-07-10 12:23:30 +0000792
sewardj0611d802004-07-11 02:37:54 +0000793/* -------------- Building the flags-thunk. -------------- */
794
sewardjb9c5cf62004-08-24 15:10:38 +0000795/* The machinery in this section builds the flag-thunk following a
796 flag-setting operation. Hence the various setFlags_* functions.
sewardjb9c5cf62004-08-24 15:10:38 +0000797*/
798
799static Bool isAddSub ( IROp op8 )
800{
sewardj2d49b432005-02-01 00:37:06 +0000801 return toBool(op8 == Iop_Add8 || op8 == Iop_Sub8);
sewardjb9c5cf62004-08-24 15:10:38 +0000802}
sewardj0611d802004-07-11 02:37:54 +0000803
sewardj2a2ba8b2004-11-08 13:14:06 +0000804static Bool isLogic ( IROp op8 )
805{
sewardj2d49b432005-02-01 00:37:06 +0000806 return toBool(op8 == Iop_And8 || op8 == Iop_Or8 || op8 == Iop_Xor8);
sewardj2a2ba8b2004-11-08 13:14:06 +0000807}
808
sewardja2384712004-07-29 14:36:40 +0000809/* U-widen 8/16/32 bit int expr to 32. */
sewardjc22a6fd2004-07-29 23:41:47 +0000810static IRExpr* widenUto32 ( IRExpr* e )
sewardj443cd9d2004-07-18 23:06:45 +0000811{
sewardjdd40fdf2006-12-24 02:20:24 +0000812 switch (typeOfIRExpr(irsb->tyenv,e)) {
sewardj443cd9d2004-07-18 23:06:45 +0000813 case Ity_I32: return e;
814 case Ity_I16: return unop(Iop_16Uto32,e);
815 case Ity_I8: return unop(Iop_8Uto32,e);
816 default: vpanic("widenUto32");
817 }
818}
819
sewardjc22a6fd2004-07-29 23:41:47 +0000820/* S-widen 8/16/32 bit int expr to 32. */
821static IRExpr* widenSto32 ( IRExpr* e )
822{
sewardjdd40fdf2006-12-24 02:20:24 +0000823 switch (typeOfIRExpr(irsb->tyenv,e)) {
sewardjc22a6fd2004-07-29 23:41:47 +0000824 case Ity_I32: return e;
825 case Ity_I16: return unop(Iop_16Sto32,e);
826 case Ity_I8: return unop(Iop_8Sto32,e);
827 default: vpanic("widenSto32");
828 }
829}
830
sewardja2384712004-07-29 14:36:40 +0000831/* Narrow 8/16/32 bit int expr to 8/16/32. Clearly only some
832 of these combinations make sense. */
833static IRExpr* narrowTo ( IRType dst_ty, IRExpr* e )
834{
sewardjdd40fdf2006-12-24 02:20:24 +0000835 IRType src_ty = typeOfIRExpr(irsb->tyenv,e);
sewardja2384712004-07-29 14:36:40 +0000836 if (src_ty == dst_ty)
837 return e;
838 if (src_ty == Ity_I32 && dst_ty == Ity_I16)
839 return unop(Iop_32to16, e);
840 if (src_ty == Ity_I32 && dst_ty == Ity_I8)
841 return unop(Iop_32to8, e);
842
843 vex_printf("\nsrc, dst tys are: ");
844 ppIRType(src_ty);
845 vex_printf(", ");
846 ppIRType(dst_ty);
847 vex_printf("\n");
848 vpanic("narrowTo(x86)");
849}
850
sewardj443cd9d2004-07-18 23:06:45 +0000851
sewardj2a2ba8b2004-11-08 13:14:06 +0000852/* Set the flags thunk OP, DEP1 and DEP2 fields. The supplied op is
sewardj948d48b2004-11-05 19:49:09 +0000853 auto-sized up to the real op. */
sewardj0611d802004-07-11 02:37:54 +0000854
sewardj2a2ba8b2004-11-08 13:14:06 +0000855static
856void setFlags_DEP1_DEP2 ( IROp op8, IRTemp dep1, IRTemp dep2, IRType ty )
sewardj0611d802004-07-11 02:37:54 +0000857{
sewardjb9c5cf62004-08-24 15:10:38 +0000858 Int ccOp = ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
859
860 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
861
862 switch (op8) {
sewardj2a9ad022004-11-25 02:46:58 +0000863 case Iop_Add8: ccOp += X86G_CC_OP_ADDB; break;
864 case Iop_Sub8: ccOp += X86G_CC_OP_SUBB; break;
sewardjb9c5cf62004-08-24 15:10:38 +0000865 default: ppIROp(op8);
sewardj2a2ba8b2004-11-08 13:14:06 +0000866 vpanic("setFlags_DEP1_DEP2(x86)");
sewardjb9c5cf62004-08-24 15:10:38 +0000867 }
sewardj2a2ba8b2004-11-08 13:14:06 +0000868 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(ccOp)) );
869 stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto32(mkexpr(dep1))) );
870 stmt( IRStmt_Put( OFFB_CC_DEP2, widenUto32(mkexpr(dep2))) );
sewardja3b7e3a2005-04-05 01:54:19 +0000871 /* Set NDEP even though it isn't used. This makes redundant-PUT
872 elimination of previous stores to this field work better. */
873 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardjb9c5cf62004-08-24 15:10:38 +0000874}
875
876
sewardj2a2ba8b2004-11-08 13:14:06 +0000877/* Set the OP and DEP1 fields only, and write zero to DEP2. */
sewardjb9c5cf62004-08-24 15:10:38 +0000878
sewardj2a2ba8b2004-11-08 13:14:06 +0000879static
880void setFlags_DEP1 ( IROp op8, IRTemp dep1, IRType ty )
sewardjb9c5cf62004-08-24 15:10:38 +0000881{
882 Int ccOp = ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
sewardj0611d802004-07-11 02:37:54 +0000883
884 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
885
886 switch (op8) {
887 case Iop_Or8:
888 case Iop_And8:
sewardj2a9ad022004-11-25 02:46:58 +0000889 case Iop_Xor8: ccOp += X86G_CC_OP_LOGICB; break;
sewardj0611d802004-07-11 02:37:54 +0000890 default: ppIROp(op8);
sewardj2a2ba8b2004-11-08 13:14:06 +0000891 vpanic("setFlags_DEP1(x86)");
sewardj0611d802004-07-11 02:37:54 +0000892 }
sewardj2a2ba8b2004-11-08 13:14:06 +0000893 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(ccOp)) );
894 stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto32(mkexpr(dep1))) );
895 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0)) );
sewardja3b7e3a2005-04-05 01:54:19 +0000896 /* Set NDEP even though it isn't used. This makes redundant-PUT
897 elimination of previous stores to this field work better. */
898 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardj0611d802004-07-11 02:37:54 +0000899}
900
901
sewardj948d48b2004-11-05 19:49:09 +0000902/* For shift operations, we put in the result and the undershifted
903 result. Except if the shift amount is zero, the thunk is left
904 unchanged. */
sewardj0611d802004-07-11 02:37:54 +0000905
sewardj2a2ba8b2004-11-08 13:14:06 +0000906static void setFlags_DEP1_DEP2_shift ( IROp op32,
907 IRTemp res,
908 IRTemp resUS,
909 IRType ty,
910 IRTemp guard )
sewardj0611d802004-07-11 02:37:54 +0000911{
sewardjc22a6fd2004-07-29 23:41:47 +0000912 Int ccOp = ty==Ity_I8 ? 2 : (ty==Ity_I16 ? 1 : 0);
sewardj0611d802004-07-11 02:37:54 +0000913
914 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
915 vassert(guard);
916
sewardj2a2ba8b2004-11-08 13:14:06 +0000917 /* Both kinds of right shifts are handled by the same thunk
918 operation. */
sewardjc22a6fd2004-07-29 23:41:47 +0000919 switch (op32) {
920 case Iop_Shr32:
sewardj2a9ad022004-11-25 02:46:58 +0000921 case Iop_Sar32: ccOp = X86G_CC_OP_SHRL - ccOp; break;
922 case Iop_Shl32: ccOp = X86G_CC_OP_SHLL - ccOp; break;
sewardjc22a6fd2004-07-29 23:41:47 +0000923 default: ppIROp(op32);
sewardj2a2ba8b2004-11-08 13:14:06 +0000924 vpanic("setFlags_DEP1_DEP2_shift(x86)");
sewardj0611d802004-07-11 02:37:54 +0000925 }
926
sewardj2a2ba8b2004-11-08 13:14:06 +0000927 /* DEP1 contains the result, DEP2 contains the undershifted value. */
sewardjeeb9ef82004-07-15 12:39:03 +0000928 stmt( IRStmt_Put( OFFB_CC_OP,
sewardj4042c7e2004-07-18 01:28:30 +0000929 IRExpr_Mux0X( mkexpr(guard),
930 IRExpr_Get(OFFB_CC_OP,Ity_I32),
931 mkU32(ccOp))) );
sewardj2a2ba8b2004-11-08 13:14:06 +0000932 stmt( IRStmt_Put( OFFB_CC_DEP1,
sewardj4042c7e2004-07-18 01:28:30 +0000933 IRExpr_Mux0X( mkexpr(guard),
sewardj2a2ba8b2004-11-08 13:14:06 +0000934 IRExpr_Get(OFFB_CC_DEP1,Ity_I32),
sewardj948d48b2004-11-05 19:49:09 +0000935 widenUto32(mkexpr(res)))) );
sewardj2a2ba8b2004-11-08 13:14:06 +0000936 stmt( IRStmt_Put( OFFB_CC_DEP2,
sewardj4042c7e2004-07-18 01:28:30 +0000937 IRExpr_Mux0X( mkexpr(guard),
sewardj2a2ba8b2004-11-08 13:14:06 +0000938 IRExpr_Get(OFFB_CC_DEP2,Ity_I32),
sewardj948d48b2004-11-05 19:49:09 +0000939 widenUto32(mkexpr(resUS)))) );
sewardja3b7e3a2005-04-05 01:54:19 +0000940 /* Set NDEP even though it isn't used. This makes redundant-PUT
941 elimination of previous stores to this field work better. */
942 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardj0611d802004-07-11 02:37:54 +0000943}
944
945
sewardj2a2ba8b2004-11-08 13:14:06 +0000946/* For the inc/dec case, we store in DEP1 the result value and in NDEP
sewardj948d48b2004-11-05 19:49:09 +0000947 the former value of the carry flag, which unfortunately we have to
948 compute. */
sewardj0611d802004-07-11 02:37:54 +0000949
sewardj948d48b2004-11-05 19:49:09 +0000950static void setFlags_INC_DEC ( Bool inc, IRTemp res, IRType ty )
sewardj0611d802004-07-11 02:37:54 +0000951{
sewardj2a9ad022004-11-25 02:46:58 +0000952 Int ccOp = inc ? X86G_CC_OP_INCB : X86G_CC_OP_DECB;
sewardj0611d802004-07-11 02:37:54 +0000953
954 ccOp += ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
955 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
956
957 /* This has to come first, because calculating the C flag
sewardj2a2ba8b2004-11-08 13:14:06 +0000958 may require reading all four thunk fields. */
sewardj2a9ad022004-11-25 02:46:58 +0000959 stmt( IRStmt_Put( OFFB_CC_NDEP, mk_x86g_calculate_eflags_c()) );
sewardj2a2ba8b2004-11-08 13:14:06 +0000960 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(ccOp)) );
sewardj478646f2008-05-01 20:13:04 +0000961 stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto32(mkexpr(res))) );
sewardj2a2ba8b2004-11-08 13:14:06 +0000962 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0)) );
sewardj0611d802004-07-11 02:37:54 +0000963}
964
965
sewardj2a2ba8b2004-11-08 13:14:06 +0000966/* Multiplies are pretty much like add and sub: DEP1 and DEP2 hold the
967 two arguments. */
sewardjcf780b42004-07-13 18:42:17 +0000968
969static
sewardj2a2ba8b2004-11-08 13:14:06 +0000970void setFlags_MUL ( IRType ty, IRTemp arg1, IRTemp arg2, UInt base_op )
sewardjcf780b42004-07-13 18:42:17 +0000971{
972 switch (ty) {
sewardj2a2ba8b2004-11-08 13:14:06 +0000973 case Ity_I8:
974 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(base_op+0) ) );
975 break;
976 case Ity_I16:
977 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(base_op+1) ) );
978 break;
979 case Ity_I32:
980 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(base_op+2) ) );
981 break;
982 default:
983 vpanic("setFlags_MUL(x86)");
sewardjcf780b42004-07-13 18:42:17 +0000984 }
sewardj2a2ba8b2004-11-08 13:14:06 +0000985 stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto32(mkexpr(arg1)) ));
986 stmt( IRStmt_Put( OFFB_CC_DEP2, widenUto32(mkexpr(arg2)) ));
sewardja3b7e3a2005-04-05 01:54:19 +0000987 /* Set NDEP even though it isn't used. This makes redundant-PUT
988 elimination of previous stores to this field work better. */
989 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardjcf780b42004-07-13 18:42:17 +0000990}
991
992
sewardj3af115f2004-07-14 02:46:52 +0000993/* -------------- Condition codes. -------------- */
994
sewardje87b4842004-07-10 12:23:30 +0000995/* Condition codes, using the Intel encoding. */
sewardj0611d802004-07-11 02:37:54 +0000996
sewardj2d49b432005-02-01 00:37:06 +0000997static HChar* name_X86Condcode ( X86Condcode cond )
sewardje87b4842004-07-10 12:23:30 +0000998{
999 switch (cond) {
sewardj2a9ad022004-11-25 02:46:58 +00001000 case X86CondO: return "o";
1001 case X86CondNO: return "no";
1002 case X86CondB: return "b";
1003 case X86CondNB: return "nb";
1004 case X86CondZ: return "z";
1005 case X86CondNZ: return "nz";
1006 case X86CondBE: return "be";
1007 case X86CondNBE: return "nbe";
1008 case X86CondS: return "s";
1009 case X86CondNS: return "ns";
1010 case X86CondP: return "p";
1011 case X86CondNP: return "np";
1012 case X86CondL: return "l";
1013 case X86CondNL: return "nl";
1014 case X86CondLE: return "le";
1015 case X86CondNLE: return "nle";
1016 case X86CondAlways: return "ALWAYS";
1017 default: vpanic("name_X86Condcode");
sewardje87b4842004-07-10 12:23:30 +00001018 }
1019}
1020
sewardj2a9ad022004-11-25 02:46:58 +00001021static
1022X86Condcode positiveIse_X86Condcode ( X86Condcode cond,
sewardjdbf550c2005-01-24 11:54:11 +00001023 Bool* needInvert )
sewardje87b4842004-07-10 12:23:30 +00001024{
sewardj2a9ad022004-11-25 02:46:58 +00001025 vassert(cond >= X86CondO && cond <= X86CondNLE);
sewardje87b4842004-07-10 12:23:30 +00001026 if (cond & 1) {
1027 *needInvert = True;
1028 return cond-1;
1029 } else {
1030 *needInvert = False;
1031 return cond;
1032 }
1033}
1034
1035
sewardj3af115f2004-07-14 02:46:52 +00001036/* -------------- Helpers for ADD/SUB with carry. -------------- */
1037
sewardj948d48b2004-11-05 19:49:09 +00001038/* Given ta1, ta2 and tres, compute tres = ADC(ta1,ta2) and set flags
sewardj2a2ba8b2004-11-08 13:14:06 +00001039 appropriately.
sewardj3af115f2004-07-14 02:46:52 +00001040*/
1041static void helper_ADC ( Int sz,
sewardj5bd4d162004-11-10 13:02:48 +00001042 IRTemp tres, IRTemp ta1, IRTemp ta2 )
sewardj3af115f2004-07-14 02:46:52 +00001043{
1044 UInt thunkOp;
sewardj2a2ba8b2004-11-08 13:14:06 +00001045 IRType ty = szToITy(sz);
1046 IRTemp oldc = newTemp(Ity_I32);
1047 IRTemp oldcn = newTemp(ty);
1048 IROp plus = mkSizedOp(ty, Iop_Add8);
1049 IROp xor = mkSizedOp(ty, Iop_Xor8);
sewardja2384712004-07-29 14:36:40 +00001050
1051 vassert(sz == 1 || sz == 2 || sz == 4);
sewardj2a9ad022004-11-25 02:46:58 +00001052 thunkOp = sz==4 ? X86G_CC_OP_ADCL
1053 : (sz==2 ? X86G_CC_OP_ADCW : X86G_CC_OP_ADCB);
sewardj3af115f2004-07-14 02:46:52 +00001054
sewardj2a2ba8b2004-11-08 13:14:06 +00001055 /* oldc = old carry flag, 0 or 1 */
1056 assign( oldc, binop(Iop_And32,
sewardj2a9ad022004-11-25 02:46:58 +00001057 mk_x86g_calculate_eflags_c(),
sewardj5bd4d162004-11-10 13:02:48 +00001058 mkU32(1)) );
sewardj3af115f2004-07-14 02:46:52 +00001059
sewardj2a2ba8b2004-11-08 13:14:06 +00001060 assign( oldcn, narrowTo(ty, mkexpr(oldc)) );
1061
1062 assign( tres, binop(plus,
1063 binop(plus,mkexpr(ta1),mkexpr(ta2)),
1064 mkexpr(oldcn)) );
1065
1066 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(thunkOp) ) );
sewardj3b3eacd2005-08-24 10:01:36 +00001067 stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto32(mkexpr(ta1)) ));
1068 stmt( IRStmt_Put( OFFB_CC_DEP2, widenUto32(binop(xor, mkexpr(ta2),
1069 mkexpr(oldcn)) )) );
sewardj2a2ba8b2004-11-08 13:14:06 +00001070 stmt( IRStmt_Put( OFFB_CC_NDEP, mkexpr(oldc) ) );
sewardj3af115f2004-07-14 02:46:52 +00001071}
1072
1073
sewardj948d48b2004-11-05 19:49:09 +00001074/* Given ta1, ta2 and tres, compute tres = SBB(ta1,ta2) and set flags
sewardj2a2ba8b2004-11-08 13:14:06 +00001075 appropriately.
sewardjcaca9d02004-07-28 07:11:32 +00001076*/
1077static void helper_SBB ( Int sz,
sewardj5bd4d162004-11-10 13:02:48 +00001078 IRTemp tres, IRTemp ta1, IRTemp ta2 )
sewardjcaca9d02004-07-28 07:11:32 +00001079{
1080 UInt thunkOp;
sewardj2a2ba8b2004-11-08 13:14:06 +00001081 IRType ty = szToITy(sz);
1082 IRTemp oldc = newTemp(Ity_I32);
1083 IRTemp oldcn = newTemp(ty);
1084 IROp minus = mkSizedOp(ty, Iop_Sub8);
1085 IROp xor = mkSizedOp(ty, Iop_Xor8);
1086
1087 vassert(sz == 1 || sz == 2 || sz == 4);
sewardj2a9ad022004-11-25 02:46:58 +00001088 thunkOp = sz==4 ? X86G_CC_OP_SBBL
1089 : (sz==2 ? X86G_CC_OP_SBBW : X86G_CC_OP_SBBB);
sewardjcaca9d02004-07-28 07:11:32 +00001090
1091 /* oldc = old carry flag, 0 or 1 */
sewardja2384712004-07-29 14:36:40 +00001092 assign( oldc, binop(Iop_And32,
sewardj2a9ad022004-11-25 02:46:58 +00001093 mk_x86g_calculate_eflags_c(),
sewardj5bd4d162004-11-10 13:02:48 +00001094 mkU32(1)) );
sewardjcaca9d02004-07-28 07:11:32 +00001095
sewardj2a2ba8b2004-11-08 13:14:06 +00001096 assign( oldcn, narrowTo(ty, mkexpr(oldc)) );
sewardja2384712004-07-29 14:36:40 +00001097
sewardj2a2ba8b2004-11-08 13:14:06 +00001098 assign( tres, binop(minus,
1099 binop(minus,mkexpr(ta1),mkexpr(ta2)),
1100 mkexpr(oldcn)) );
sewardjcaca9d02004-07-28 07:11:32 +00001101
sewardj2a2ba8b2004-11-08 13:14:06 +00001102 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(thunkOp) ) );
sewardj3b3eacd2005-08-24 10:01:36 +00001103 stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto32(mkexpr(ta1) )) );
1104 stmt( IRStmt_Put( OFFB_CC_DEP2, widenUto32(binop(xor, mkexpr(ta2),
1105 mkexpr(oldcn)) )) );
sewardj2a2ba8b2004-11-08 13:14:06 +00001106 stmt( IRStmt_Put( OFFB_CC_NDEP, mkexpr(oldc) ) );
sewardjcaca9d02004-07-28 07:11:32 +00001107}
1108
1109
sewardj7dd2eb22005-01-05 10:38:54 +00001110/* -------------- Helpers for disassembly printing. -------------- */
sewardj41f43bc2004-07-08 14:23:22 +00001111
sewardjc9a43662004-11-30 18:51:59 +00001112static HChar* nameGrp1 ( Int opc_aux )
sewardj41f43bc2004-07-08 14:23:22 +00001113{
sewardjc9a43662004-11-30 18:51:59 +00001114 static HChar* grp1_names[8]
sewardj41f43bc2004-07-08 14:23:22 +00001115 = { "add", "or", "adc", "sbb", "and", "sub", "xor", "cmp" };
1116 if (opc_aux < 0 || opc_aux > 7) vpanic("nameGrp1(x86)");
1117 return grp1_names[opc_aux];
1118}
1119
sewardjc9a43662004-11-30 18:51:59 +00001120static HChar* nameGrp2 ( Int opc_aux )
sewardje90ad6a2004-07-10 19:02:10 +00001121{
sewardjc9a43662004-11-30 18:51:59 +00001122 static HChar* grp2_names[8]
sewardje90ad6a2004-07-10 19:02:10 +00001123 = { "rol", "ror", "rcl", "rcr", "shl", "shr", "shl", "sar" };
sewardjc2ac51e2004-07-12 01:03:26 +00001124 if (opc_aux < 0 || opc_aux > 7) vpanic("nameGrp2(x86)");
sewardje90ad6a2004-07-10 19:02:10 +00001125 return grp2_names[opc_aux];
1126}
1127
sewardjc9a43662004-11-30 18:51:59 +00001128static HChar* nameGrp4 ( Int opc_aux )
sewardjc2ac51e2004-07-12 01:03:26 +00001129{
sewardjc9a43662004-11-30 18:51:59 +00001130 static HChar* grp4_names[8]
sewardjc2ac51e2004-07-12 01:03:26 +00001131 = { "inc", "dec", "???", "???", "???", "???", "???", "???" };
1132 if (opc_aux < 0 || opc_aux > 1) vpanic("nameGrp4(x86)");
1133 return grp4_names[opc_aux];
1134}
sewardj0611d802004-07-11 02:37:54 +00001135
sewardjc9a43662004-11-30 18:51:59 +00001136static HChar* nameGrp5 ( Int opc_aux )
sewardj0611d802004-07-11 02:37:54 +00001137{
sewardjc9a43662004-11-30 18:51:59 +00001138 static HChar* grp5_names[8]
sewardj0611d802004-07-11 02:37:54 +00001139 = { "inc", "dec", "call*", "call*", "jmp*", "jmp*", "push", "???" };
1140 if (opc_aux < 0 || opc_aux > 6) vpanic("nameGrp5(x86)");
1141 return grp5_names[opc_aux];
1142}
1143
sewardj490ad382005-03-13 17:25:53 +00001144static HChar* nameGrp8 ( Int opc_aux )
1145{
1146 static HChar* grp8_names[8]
1147 = { "???", "???", "???", "???", "bt", "bts", "btr", "btc" };
1148 if (opc_aux < 4 || opc_aux > 7) vpanic("nameGrp8(x86)");
1149 return grp8_names[opc_aux];
1150}
sewardjc9a65702004-07-07 16:32:57 +00001151
sewardjc9a43662004-11-30 18:51:59 +00001152static HChar* nameIReg ( Int size, Int reg )
sewardjc9a65702004-07-07 16:32:57 +00001153{
sewardjc9a43662004-11-30 18:51:59 +00001154 static HChar* ireg32_names[8]
sewardjc9a65702004-07-07 16:32:57 +00001155 = { "%eax", "%ecx", "%edx", "%ebx",
1156 "%esp", "%ebp", "%esi", "%edi" };
sewardjc9a43662004-11-30 18:51:59 +00001157 static HChar* ireg16_names[8]
sewardjc9a65702004-07-07 16:32:57 +00001158 = { "%ax", "%cx", "%dx", "%bx", "%sp", "%bp", "%si", "%di" };
sewardjc9a43662004-11-30 18:51:59 +00001159 static HChar* ireg8_names[8]
sewardjc9a65702004-07-07 16:32:57 +00001160 = { "%al", "%cl", "%dl", "%bl",
1161 "%ah{sp}", "%ch{bp}", "%dh{si}", "%bh{di}" };
1162 if (reg < 0 || reg > 7) goto bad;
1163 switch (size) {
1164 case 4: return ireg32_names[reg];
1165 case 2: return ireg16_names[reg];
1166 case 1: return ireg8_names[reg];
1167 }
1168 bad:
1169 vpanic("nameIReg(X86)");
1170 return NULL; /*notreached*/
1171}
1172
sewardjc9a43662004-11-30 18:51:59 +00001173static HChar* nameSReg ( UInt sreg )
sewardj063f02f2004-10-20 12:36:12 +00001174{
1175 switch (sreg) {
1176 case R_ES: return "%es";
1177 case R_CS: return "%cs";
1178 case R_SS: return "%ss";
1179 case R_DS: return "%ds";
1180 case R_FS: return "%fs";
1181 case R_GS: return "%gs";
1182 default: vpanic("nameSReg(x86)");
1183 }
1184}
1185
sewardjc9a43662004-11-30 18:51:59 +00001186static HChar* nameMMXReg ( Int mmxreg )
sewardj464efa42004-11-19 22:17:29 +00001187{
sewardjc9a43662004-11-30 18:51:59 +00001188 static HChar* mmx_names[8]
sewardj464efa42004-11-19 22:17:29 +00001189 = { "%mm0", "%mm1", "%mm2", "%mm3", "%mm4", "%mm5", "%mm6", "%mm7" };
1190 if (mmxreg < 0 || mmxreg > 7) vpanic("nameMMXReg(x86,guest)");
1191 return mmx_names[mmxreg];
1192}
1193
sewardjc9a43662004-11-30 18:51:59 +00001194static HChar* nameXMMReg ( Int xmmreg )
1195{
1196 static HChar* xmm_names[8]
1197 = { "%xmm0", "%xmm1", "%xmm2", "%xmm3",
1198 "%xmm4", "%xmm5", "%xmm6", "%xmm7" };
1199 if (xmmreg < 0 || xmmreg > 7) vpanic("name_of_xmm_reg");
1200 return xmm_names[xmmreg];
1201}
sewardj464efa42004-11-19 22:17:29 +00001202
sewardj2d49b432005-02-01 00:37:06 +00001203static HChar* nameMMXGran ( Int gran )
sewardj464efa42004-11-19 22:17:29 +00001204{
1205 switch (gran) {
1206 case 0: return "b";
1207 case 1: return "w";
1208 case 2: return "d";
1209 case 3: return "q";
1210 default: vpanic("nameMMXGran(x86,guest)");
1211 }
1212}
sewardjc9a65702004-07-07 16:32:57 +00001213
sewardj2d49b432005-02-01 00:37:06 +00001214static HChar nameISize ( Int size )
sewardjc9a65702004-07-07 16:32:57 +00001215{
1216 switch (size) {
1217 case 4: return 'l';
1218 case 2: return 'w';
1219 case 1: return 'b';
1220 default: vpanic("nameISize(x86)");
1221 }
1222}
1223
sewardjd1061ab2004-07-08 01:45:30 +00001224
1225/*------------------------------------------------------------*/
1226/*--- JMP helpers ---*/
1227/*------------------------------------------------------------*/
1228
sewardj78c19df2004-07-12 22:49:27 +00001229static void jmp_lit( IRJumpKind kind, Addr32 d32 )
sewardjd1061ab2004-07-08 01:45:30 +00001230{
sewardjdd40fdf2006-12-24 02:20:24 +00001231 irsb->next = mkU32(d32);
1232 irsb->jumpkind = kind;
sewardjd1061ab2004-07-08 01:45:30 +00001233}
1234
sewardj78c19df2004-07-12 22:49:27 +00001235static void jmp_treg( IRJumpKind kind, IRTemp t )
sewardje05c42c2004-07-08 20:25:10 +00001236{
sewardjdd40fdf2006-12-24 02:20:24 +00001237 irsb->next = mkexpr(t);
1238 irsb->jumpkind = kind;
sewardje05c42c2004-07-08 20:25:10 +00001239}
sewardje87b4842004-07-10 12:23:30 +00001240
sewardj2a9ad022004-11-25 02:46:58 +00001241static
1242void jcc_01( X86Condcode cond, Addr32 d32_false, Addr32 d32_true )
sewardje87b4842004-07-10 12:23:30 +00001243{
sewardj2a9ad022004-11-25 02:46:58 +00001244 Bool invert;
1245 X86Condcode condPos;
1246 condPos = positiveIse_X86Condcode ( cond, &invert );
sewardje87b4842004-07-10 12:23:30 +00001247 if (invert) {
sewardj2a9ad022004-11-25 02:46:58 +00001248 stmt( IRStmt_Exit( mk_x86g_calculate_condition(condPos),
sewardj893aada2004-11-29 19:57:54 +00001249 Ijk_Boring,
sewardj78c19df2004-07-12 22:49:27 +00001250 IRConst_U32(d32_false) ) );
sewardjdd40fdf2006-12-24 02:20:24 +00001251 irsb->next = mkU32(d32_true);
1252 irsb->jumpkind = Ijk_Boring;
sewardje87b4842004-07-10 12:23:30 +00001253 } else {
sewardj2a9ad022004-11-25 02:46:58 +00001254 stmt( IRStmt_Exit( mk_x86g_calculate_condition(condPos),
sewardj893aada2004-11-29 19:57:54 +00001255 Ijk_Boring,
sewardj78c19df2004-07-12 22:49:27 +00001256 IRConst_U32(d32_true) ) );
sewardjdd40fdf2006-12-24 02:20:24 +00001257 irsb->next = mkU32(d32_false);
1258 irsb->jumpkind = Ijk_Boring;
sewardje87b4842004-07-10 12:23:30 +00001259 }
1260}
sewardjc9a65702004-07-07 16:32:57 +00001261
1262
sewardjd1061ab2004-07-08 01:45:30 +00001263/*------------------------------------------------------------*/
1264/*--- Disassembling addressing modes ---*/
1265/*------------------------------------------------------------*/
sewardjc9a65702004-07-07 16:32:57 +00001266
sewardjd1061ab2004-07-08 01:45:30 +00001267static
sewardj2d49b432005-02-01 00:37:06 +00001268HChar* sorbTxt ( UChar sorb )
sewardjd1061ab2004-07-08 01:45:30 +00001269{
1270 switch (sorb) {
1271 case 0: return ""; /* no override */
1272 case 0x3E: return "%ds";
1273 case 0x26: return "%es:";
1274 case 0x64: return "%fs:";
1275 case 0x65: return "%gs:";
sewardj7df596b2004-12-06 14:29:12 +00001276 default: vpanic("sorbTxt(x86,guest)");
sewardjd1061ab2004-07-08 01:45:30 +00001277 }
1278}
1279
1280
sewardj7df596b2004-12-06 14:29:12 +00001281/* 'virtual' is an IRExpr* holding a virtual address. Convert it to a
1282 linear address by adding any required segment override as indicated
1283 by sorb. */
sewardjd1061ab2004-07-08 01:45:30 +00001284static
1285IRExpr* handleSegOverride ( UChar sorb, IRExpr* virtual )
1286{
sewardj3bd6f3e2004-12-13 10:48:19 +00001287 Int sreg;
1288 IRType hWordTy;
1289 IRTemp ldt_ptr, gdt_ptr, seg_selector, r64;
sewardjd1061ab2004-07-08 01:45:30 +00001290
1291 if (sorb == 0)
1292 /* the common case - no override */
1293 return virtual;
1294
sewardjd1061ab2004-07-08 01:45:30 +00001295 switch (sorb) {
1296 case 0x3E: sreg = R_DS; break;
1297 case 0x26: sreg = R_ES; break;
1298 case 0x64: sreg = R_FS; break;
1299 case 0x65: sreg = R_GS; break;
sewardj7df596b2004-12-06 14:29:12 +00001300 default: vpanic("handleSegOverride(x86,guest)");
sewardjd1061ab2004-07-08 01:45:30 +00001301 }
1302
sewardj3bd6f3e2004-12-13 10:48:19 +00001303 hWordTy = sizeof(HWord)==4 ? Ity_I32 : Ity_I64;
sewardjd1061ab2004-07-08 01:45:30 +00001304
sewardj3bd6f3e2004-12-13 10:48:19 +00001305 seg_selector = newTemp(Ity_I32);
1306 ldt_ptr = newTemp(hWordTy);
1307 gdt_ptr = newTemp(hWordTy);
1308 r64 = newTemp(Ity_I64);
sewardjd1061ab2004-07-08 01:45:30 +00001309
sewardj3bd6f3e2004-12-13 10:48:19 +00001310 assign( seg_selector, unop(Iop_16Uto32, getSReg(sreg)) );
1311 assign( ldt_ptr, IRExpr_Get( OFFB_LDT, hWordTy ));
1312 assign( gdt_ptr, IRExpr_Get( OFFB_GDT, hWordTy ));
sewardj7df596b2004-12-06 14:29:12 +00001313
sewardj3bd6f3e2004-12-13 10:48:19 +00001314 /*
1315 Call this to do the translation and limit checks:
1316 ULong x86g_use_seg_selector ( HWord ldt, HWord gdt,
1317 UInt seg_selector, UInt virtual_addr )
1318 */
1319 assign(
1320 r64,
1321 mkIRExprCCall(
1322 Ity_I64,
1323 0/*regparms*/,
1324 "x86g_use_seg_selector",
1325 &x86g_use_seg_selector,
1326 mkIRExprVec_4( mkexpr(ldt_ptr), mkexpr(gdt_ptr),
1327 mkexpr(seg_selector), virtual)
1328 )
1329 );
sewardj7df596b2004-12-06 14:29:12 +00001330
sewardj52444cb2004-12-13 14:09:01 +00001331 /* If the high 32 of the result are non-zero, there was a
1332 failure in address translation. In which case, make a
1333 quick exit.
1334 */
1335 stmt(
1336 IRStmt_Exit(
1337 binop(Iop_CmpNE32, unop(Iop_64HIto32, mkexpr(r64)), mkU32(0)),
1338 Ijk_MapFail,
sewardj9e6491a2005-07-02 19:24:10 +00001339 IRConst_U32( guest_EIP_curr_instr )
sewardj52444cb2004-12-13 14:09:01 +00001340 )
1341 );
1342
1343 /* otherwise, here's the translated result. */
sewardj3bd6f3e2004-12-13 10:48:19 +00001344 return unop(Iop_64to32, mkexpr(r64));
sewardjd1061ab2004-07-08 01:45:30 +00001345}
1346
1347
1348/* Generate IR to calculate an address indicated by a ModRM and
1349 following SIB bytes. The expression, and the number of bytes in
1350 the address mode, are returned. Note that this fn should not be
1351 called if the R/M part of the address denotes a register instead of
1352 memory. If print_codegen is true, text of the addressing mode is
sewardj940e8c92004-07-11 16:53:24 +00001353 placed in buf.
1354
1355 The computed address is stored in a new tempreg, and the
1356 identity of the tempreg is returned. */
1357
1358static IRTemp disAMode_copy2tmp ( IRExpr* addr32 )
1359{
1360 IRTemp tmp = newTemp(Ity_I32);
1361 assign( tmp, addr32 );
1362 return tmp;
1363}
sewardjd1061ab2004-07-08 01:45:30 +00001364
1365static
sewardj52d04912005-07-03 00:52:48 +00001366IRTemp disAMode ( Int* len, UChar sorb, Int delta, HChar* buf )
sewardjd1061ab2004-07-08 01:45:30 +00001367{
1368 UChar mod_reg_rm = getIByte(delta);
1369 delta++;
1370
sewardj9ee82862004-12-14 01:16:59 +00001371 buf[0] = (UChar)0;
1372
sewardjd1061ab2004-07-08 01:45:30 +00001373 /* squeeze out the reg field from mod_reg_rm, since a 256-entry
1374 jump table seems a bit excessive.
1375 */
sewardj9b45b482005-02-07 01:42:18 +00001376 mod_reg_rm &= 0xC7; /* is now XX000YYY */
1377 mod_reg_rm = toUChar(mod_reg_rm | (mod_reg_rm >> 3));
1378 /* is now XX0XXYYY */
1379 mod_reg_rm &= 0x1F; /* is now 000XXYYY */
sewardjd1061ab2004-07-08 01:45:30 +00001380 switch (mod_reg_rm) {
1381
1382 /* (%eax) .. (%edi), not including (%esp) or (%ebp).
1383 --> GET %reg, t
1384 */
1385 case 0x00: case 0x01: case 0x02: case 0x03:
1386 /* ! 04 */ /* ! 05 */ case 0x06: case 0x07:
1387 { UChar rm = mod_reg_rm;
1388 DIS(buf, "%s(%s)", sorbTxt(sorb), nameIReg(4,rm));
1389 *len = 1;
sewardj5bd4d162004-11-10 13:02:48 +00001390 return disAMode_copy2tmp(
sewardj940e8c92004-07-11 16:53:24 +00001391 handleSegOverride(sorb, getIReg(4,rm)));
sewardjd1061ab2004-07-08 01:45:30 +00001392 }
1393
1394 /* d8(%eax) ... d8(%edi), not including d8(%esp)
1395 --> GET %reg, t ; ADDL d8, t
1396 */
1397 case 0x08: case 0x09: case 0x0A: case 0x0B:
1398 /* ! 0C */ case 0x0D: case 0x0E: case 0x0F:
sewardj9b45b482005-02-07 01:42:18 +00001399 { UChar rm = toUChar(mod_reg_rm & 7);
sewardjd1061ab2004-07-08 01:45:30 +00001400 UInt d = getSDisp8(delta);
sewardj2d49b432005-02-01 00:37:06 +00001401 DIS(buf, "%s%d(%s)", sorbTxt(sorb), (Int)d, nameIReg(4,rm));
sewardj5bd4d162004-11-10 13:02:48 +00001402 *len = 2;
1403 return disAMode_copy2tmp(
sewardj940e8c92004-07-11 16:53:24 +00001404 handleSegOverride(sorb,
1405 binop(Iop_Add32,getIReg(4,rm),mkU32(d))));
sewardjd1061ab2004-07-08 01:45:30 +00001406 }
1407
1408 /* d32(%eax) ... d32(%edi), not including d32(%esp)
1409 --> GET %reg, t ; ADDL d8, t
1410 */
1411 case 0x10: case 0x11: case 0x12: case 0x13:
1412 /* ! 14 */ case 0x15: case 0x16: case 0x17:
sewardj9b45b482005-02-07 01:42:18 +00001413 { UChar rm = toUChar(mod_reg_rm & 7);
sewardjd1061ab2004-07-08 01:45:30 +00001414 UInt d = getUDisp32(delta);
sewardj2d49b432005-02-01 00:37:06 +00001415 DIS(buf, "%s0x%x(%s)", sorbTxt(sorb), (Int)d, nameIReg(4,rm));
sewardj5bd4d162004-11-10 13:02:48 +00001416 *len = 5;
1417 return disAMode_copy2tmp(
sewardj940e8c92004-07-11 16:53:24 +00001418 handleSegOverride(sorb,
1419 binop(Iop_Add32,getIReg(4,rm),mkU32(d))));
sewardjd1061ab2004-07-08 01:45:30 +00001420 }
1421
1422 /* a register, %eax .. %edi. This shouldn't happen. */
1423 case 0x18: case 0x19: case 0x1A: case 0x1B:
1424 case 0x1C: case 0x1D: case 0x1E: case 0x1F:
1425 vpanic("disAMode(x86): not an addr!");
1426
1427 /* a 32-bit literal address
1428 --> MOV d32, tmp
1429 */
1430 case 0x05:
1431 { UInt d = getUDisp32(delta);
1432 *len = 5;
1433 DIS(buf, "%s(0x%x)", sorbTxt(sorb), d);
sewardj940e8c92004-07-11 16:53:24 +00001434 return disAMode_copy2tmp(
1435 handleSegOverride(sorb, mkU32(d)));
sewardjd1061ab2004-07-08 01:45:30 +00001436 }
1437
1438 case 0x04: {
1439 /* SIB, with no displacement. Special cases:
1440 -- %esp cannot act as an index value.
1441 If index_r indicates %esp, zero is used for the index.
1442 -- when mod is zero and base indicates EBP, base is instead
1443 a 32-bit literal.
1444 It's all madness, I tell you. Extract %index, %base and
1445 scale from the SIB byte. The value denoted is then:
1446 | %index == %ESP && %base == %EBP
1447 = d32 following SIB byte
1448 | %index == %ESP && %base != %EBP
1449 = %base
1450 | %index != %ESP && %base == %EBP
1451 = d32 following SIB byte + (%index << scale)
1452 | %index != %ESP && %base != %ESP
1453 = %base + (%index << scale)
1454
1455 What happens to the souls of CPU architects who dream up such
1456 horrendous schemes, do you suppose?
1457 */
1458 UChar sib = getIByte(delta);
sewardj9b45b482005-02-07 01:42:18 +00001459 UChar scale = toUChar((sib >> 6) & 3);
1460 UChar index_r = toUChar((sib >> 3) & 7);
1461 UChar base_r = toUChar(sib & 7);
sewardj5bd4d162004-11-10 13:02:48 +00001462 delta++;
sewardjd1061ab2004-07-08 01:45:30 +00001463
1464 if (index_r != R_ESP && base_r != R_EBP) {
1465 DIS(buf, "%s(%s,%s,%d)", sorbTxt(sorb),
1466 nameIReg(4,base_r), nameIReg(4,index_r), 1<<scale);
sewardj5bd4d162004-11-10 13:02:48 +00001467 *len = 2;
sewardj940e8c92004-07-11 16:53:24 +00001468 return
1469 disAMode_copy2tmp(
sewardj5bd4d162004-11-10 13:02:48 +00001470 handleSegOverride(sorb,
1471 binop(Iop_Add32,
sewardjd1061ab2004-07-08 01:45:30 +00001472 getIReg(4,base_r),
1473 binop(Iop_Shl32, getIReg(4,index_r),
sewardj6d2638e2004-07-15 09:38:27 +00001474 mkU8(scale)))));
sewardjd1061ab2004-07-08 01:45:30 +00001475 }
1476
1477 if (index_r != R_ESP && base_r == R_EBP) {
1478 UInt d = getUDisp32(delta);
1479 DIS(buf, "%s0x%x(,%s,%d)", sorbTxt(sorb), d,
1480 nameIReg(4,index_r), 1<<scale);
1481 *len = 6;
1482 return
sewardj940e8c92004-07-11 16:53:24 +00001483 disAMode_copy2tmp(
sewardjd1061ab2004-07-08 01:45:30 +00001484 handleSegOverride(sorb,
sewardj5bd4d162004-11-10 13:02:48 +00001485 binop(Iop_Add32,
1486 binop(Iop_Shl32, getIReg(4,index_r), mkU8(scale)),
sewardj940e8c92004-07-11 16:53:24 +00001487 mkU32(d))));
sewardjd1061ab2004-07-08 01:45:30 +00001488 }
1489
1490 if (index_r == R_ESP && base_r != R_EBP) {
1491 DIS(buf, "%s(%s,,)", sorbTxt(sorb), nameIReg(4,base_r));
sewardj5bd4d162004-11-10 13:02:48 +00001492 *len = 2;
1493 return disAMode_copy2tmp(
sewardj940e8c92004-07-11 16:53:24 +00001494 handleSegOverride(sorb, getIReg(4,base_r)));
sewardjd1061ab2004-07-08 01:45:30 +00001495 }
1496
1497 if (index_r == R_ESP && base_r == R_EBP) {
1498 UInt d = getUDisp32(delta);
sewardj9c3b25a2007-04-05 15:06:56 +00001499 DIS(buf, "%s0x%x(,,)", sorbTxt(sorb), d);
sewardj5bd4d162004-11-10 13:02:48 +00001500 *len = 6;
sewardj5bd4d162004-11-10 13:02:48 +00001501 return disAMode_copy2tmp(
sewardj940e8c92004-07-11 16:53:24 +00001502 handleSegOverride(sorb, mkU32(d)));
sewardjd1061ab2004-07-08 01:45:30 +00001503 }
sewardjba89f4c2005-04-07 17:31:27 +00001504 /*NOTREACHED*/
sewardjd1061ab2004-07-08 01:45:30 +00001505 vassert(0);
1506 }
1507
1508 /* SIB, with 8-bit displacement. Special cases:
1509 -- %esp cannot act as an index value.
1510 If index_r indicates %esp, zero is used for the index.
1511 Denoted value is:
1512 | %index == %ESP
1513 = d8 + %base
1514 | %index != %ESP
1515 = d8 + %base + (%index << scale)
1516 */
1517 case 0x0C: {
1518 UChar sib = getIByte(delta);
sewardj9b45b482005-02-07 01:42:18 +00001519 UChar scale = toUChar((sib >> 6) & 3);
1520 UChar index_r = toUChar((sib >> 3) & 7);
1521 UChar base_r = toUChar(sib & 7);
sewardjd1061ab2004-07-08 01:45:30 +00001522 UInt d = getSDisp8(delta+1);
1523
1524 if (index_r == R_ESP) {
sewardj2d49b432005-02-01 00:37:06 +00001525 DIS(buf, "%s%d(%s,,)", sorbTxt(sorb),
1526 (Int)d, nameIReg(4,base_r));
sewardj5bd4d162004-11-10 13:02:48 +00001527 *len = 3;
1528 return disAMode_copy2tmp(
sewardj940e8c92004-07-11 16:53:24 +00001529 handleSegOverride(sorb,
1530 binop(Iop_Add32, getIReg(4,base_r), mkU32(d)) ));
sewardjd1061ab2004-07-08 01:45:30 +00001531 } else {
sewardj2d49b432005-02-01 00:37:06 +00001532 DIS(buf, "%s%d(%s,%s,%d)", sorbTxt(sorb), (Int)d,
sewardjd1061ab2004-07-08 01:45:30 +00001533 nameIReg(4,base_r), nameIReg(4,index_r), 1<<scale);
sewardj5bd4d162004-11-10 13:02:48 +00001534 *len = 3;
1535 return
sewardj940e8c92004-07-11 16:53:24 +00001536 disAMode_copy2tmp(
1537 handleSegOverride(sorb,
sewardj77b86be2004-07-11 13:28:24 +00001538 binop(Iop_Add32,
1539 binop(Iop_Add32,
1540 getIReg(4,base_r),
1541 binop(Iop_Shl32,
sewardj6d2638e2004-07-15 09:38:27 +00001542 getIReg(4,index_r), mkU8(scale))),
sewardj940e8c92004-07-11 16:53:24 +00001543 mkU32(d))));
sewardjd1061ab2004-07-08 01:45:30 +00001544 }
sewardjba89f4c2005-04-07 17:31:27 +00001545 /*NOTREACHED*/
sewardjd1061ab2004-07-08 01:45:30 +00001546 vassert(0);
1547 }
1548
1549 /* SIB, with 32-bit displacement. Special cases:
1550 -- %esp cannot act as an index value.
1551 If index_r indicates %esp, zero is used for the index.
1552 Denoted value is:
1553 | %index == %ESP
1554 = d32 + %base
1555 | %index != %ESP
1556 = d32 + %base + (%index << scale)
1557 */
1558 case 0x14: {
1559 UChar sib = getIByte(delta);
sewardj9b45b482005-02-07 01:42:18 +00001560 UChar scale = toUChar((sib >> 6) & 3);
1561 UChar index_r = toUChar((sib >> 3) & 7);
1562 UChar base_r = toUChar(sib & 7);
sewardjd1061ab2004-07-08 01:45:30 +00001563 UInt d = getUDisp32(delta+1);
1564
1565 if (index_r == R_ESP) {
sewardj2d49b432005-02-01 00:37:06 +00001566 DIS(buf, "%s%d(%s,,)", sorbTxt(sorb),
1567 (Int)d, nameIReg(4,base_r));
sewardj5bd4d162004-11-10 13:02:48 +00001568 *len = 6;
1569 return disAMode_copy2tmp(
sewardj940e8c92004-07-11 16:53:24 +00001570 handleSegOverride(sorb,
1571 binop(Iop_Add32, getIReg(4,base_r), mkU32(d)) ));
sewardjd1061ab2004-07-08 01:45:30 +00001572 } else {
sewardj2d49b432005-02-01 00:37:06 +00001573 DIS(buf, "%s%d(%s,%s,%d)", sorbTxt(sorb), (Int)d,
1574 nameIReg(4,base_r), nameIReg(4,index_r), 1<<scale);
sewardj5bd4d162004-11-10 13:02:48 +00001575 *len = 6;
1576 return
sewardj940e8c92004-07-11 16:53:24 +00001577 disAMode_copy2tmp(
1578 handleSegOverride(sorb,
sewardj9334b0f2004-07-10 22:43:54 +00001579 binop(Iop_Add32,
1580 binop(Iop_Add32,
1581 getIReg(4,base_r),
1582 binop(Iop_Shl32,
sewardj6d2638e2004-07-15 09:38:27 +00001583 getIReg(4,index_r), mkU8(scale))),
sewardj940e8c92004-07-11 16:53:24 +00001584 mkU32(d))));
sewardjd1061ab2004-07-08 01:45:30 +00001585 }
sewardjba89f4c2005-04-07 17:31:27 +00001586 /*NOTREACHED*/
sewardjd1061ab2004-07-08 01:45:30 +00001587 vassert(0);
1588 }
1589
1590 default:
1591 vpanic("disAMode(x86)");
1592 return 0; /*notreached*/
1593 }
1594}
1595
1596
1597/* Figure out the number of (insn-stream) bytes constituting the amode
1598 beginning at delta. Is useful for getting hold of literals beyond
1599 the end of the amode before it has been disassembled. */
1600
sewardj52d04912005-07-03 00:52:48 +00001601static UInt lengthAMode ( Int delta )
sewardjd1061ab2004-07-08 01:45:30 +00001602{
1603 UChar mod_reg_rm = getIByte(delta); delta++;
1604
1605 /* squeeze out the reg field from mod_reg_rm, since a 256-entry
1606 jump table seems a bit excessive.
1607 */
1608 mod_reg_rm &= 0xC7; /* is now XX000YYY */
sewardj9b45b482005-02-07 01:42:18 +00001609 mod_reg_rm = toUChar(mod_reg_rm | (mod_reg_rm >> 3));
1610 /* is now XX0XXYYY */
sewardjd1061ab2004-07-08 01:45:30 +00001611 mod_reg_rm &= 0x1F; /* is now 000XXYYY */
1612 switch (mod_reg_rm) {
1613
1614 /* (%eax) .. (%edi), not including (%esp) or (%ebp). */
1615 case 0x00: case 0x01: case 0x02: case 0x03:
1616 /* ! 04 */ /* ! 05 */ case 0x06: case 0x07:
1617 return 1;
1618
1619 /* d8(%eax) ... d8(%edi), not including d8(%esp). */
1620 case 0x08: case 0x09: case 0x0A: case 0x0B:
1621 /* ! 0C */ case 0x0D: case 0x0E: case 0x0F:
1622 return 2;
1623
1624 /* d32(%eax) ... d32(%edi), not including d32(%esp). */
1625 case 0x10: case 0x11: case 0x12: case 0x13:
1626 /* ! 14 */ case 0x15: case 0x16: case 0x17:
1627 return 5;
1628
1629 /* a register, %eax .. %edi. (Not an addr, but still handled.) */
1630 case 0x18: case 0x19: case 0x1A: case 0x1B:
1631 case 0x1C: case 0x1D: case 0x1E: case 0x1F:
1632 return 1;
1633
1634 /* a 32-bit literal address. */
1635 case 0x05: return 5;
1636
1637 /* SIB, no displacement. */
1638 case 0x04: {
1639 UChar sib = getIByte(delta);
sewardj9b45b482005-02-07 01:42:18 +00001640 UChar base_r = toUChar(sib & 7);
sewardjd1061ab2004-07-08 01:45:30 +00001641 if (base_r == R_EBP) return 6; else return 2;
1642 }
1643 /* SIB, with 8-bit displacement. */
1644 case 0x0C: return 3;
1645
1646 /* SIB, with 32-bit displacement. */
1647 case 0x14: return 6;
1648
1649 default:
1650 vpanic("lengthAMode");
1651 return 0; /*notreached*/
1652 }
1653}
1654
1655/*------------------------------------------------------------*/
1656/*--- Disassembling common idioms ---*/
1657/*------------------------------------------------------------*/
1658
sewardje87b4842004-07-10 12:23:30 +00001659/* Handle binary integer instructions of the form
1660 op E, G meaning
1661 op reg-or-mem, reg
1662 Is passed the a ptr to the modRM byte, the actual operation, and the
1663 data size. Returns the address advanced completely over this
1664 instruction.
1665
1666 E(src) is reg-or-mem
1667 G(dst) is reg.
1668
1669 If E is reg, --> GET %G, tmp
1670 OP %E, tmp
1671 PUT tmp, %G
1672
1673 If E is mem and OP is not reversible,
1674 --> (getAddr E) -> tmpa
1675 LD (tmpa), tmpa
1676 GET %G, tmp2
1677 OP tmpa, tmp2
1678 PUT tmp2, %G
1679
1680 If E is mem and OP is reversible
1681 --> (getAddr E) -> tmpa
1682 LD (tmpa), tmpa
1683 OP %G, tmpa
1684 PUT tmpa, %G
1685*/
1686static
1687UInt dis_op2_E_G ( UChar sorb,
sewardj180e8b32004-07-29 01:40:11 +00001688 Bool addSubCarry,
sewardje87b4842004-07-10 12:23:30 +00001689 IROp op8,
1690 Bool keep,
1691 Int size,
sewardj52d04912005-07-03 00:52:48 +00001692 Int delta0,
sewardj2d49b432005-02-01 00:37:06 +00001693 HChar* t_x86opc )
sewardje87b4842004-07-10 12:23:30 +00001694{
sewardjc9a43662004-11-30 18:51:59 +00001695 HChar dis_buf[50];
sewardj9334b0f2004-07-10 22:43:54 +00001696 Int len;
sewardje87b4842004-07-10 12:23:30 +00001697 IRType ty = szToITy(size);
1698 IRTemp dst1 = newTemp(ty);
1699 IRTemp src = newTemp(ty);
1700 IRTemp dst0 = newTemp(ty);
1701 UChar rm = getUChar(delta0);
sewardj92d168d2004-11-15 14:22:12 +00001702 IRTemp addr = IRTemp_INVALID;
sewardje87b4842004-07-10 12:23:30 +00001703
sewardj180e8b32004-07-29 01:40:11 +00001704 /* addSubCarry == True indicates the intended operation is
1705 add-with-carry or subtract-with-borrow. */
1706 if (addSubCarry) {
1707 vassert(op8 == Iop_Add8 || op8 == Iop_Sub8);
1708 vassert(keep);
1709 }
1710
sewardje87b4842004-07-10 12:23:30 +00001711 if (epartIsReg(rm)) {
sewardje87b4842004-07-10 12:23:30 +00001712 /* Specially handle XOR reg,reg, because that doesn't really
1713 depend on reg, and doing the obvious thing potentially
1714 generates a spurious value check failure due to the bogus
sewardj55efbdf2005-05-02 17:07:02 +00001715 dependency. Ditto SBB reg,reg. */
1716 if ((op8 == Iop_Xor8 || (op8 == Iop_Sub8 && addSubCarry))
1717 && gregOfRM(rm) == eregOfRM(rm)) {
1718 putIReg(size, gregOfRM(rm), mkU(ty,0));
sewardje87b4842004-07-10 12:23:30 +00001719 }
sewardje87b4842004-07-10 12:23:30 +00001720 assign( dst0, getIReg(size,gregOfRM(rm)) );
1721 assign( src, getIReg(size,eregOfRM(rm)) );
sewardje87b4842004-07-10 12:23:30 +00001722
sewardj180e8b32004-07-29 01:40:11 +00001723 if (addSubCarry && op8 == Iop_Add8) {
sewardj180e8b32004-07-29 01:40:11 +00001724 helper_ADC( size, dst1, dst0, src );
sewardje87b4842004-07-10 12:23:30 +00001725 putIReg(size, gregOfRM(rm), mkexpr(dst1));
sewardj180e8b32004-07-29 01:40:11 +00001726 } else
1727 if (addSubCarry && op8 == Iop_Sub8) {
sewardj180e8b32004-07-29 01:40:11 +00001728 helper_SBB( size, dst1, dst0, src );
1729 putIReg(size, gregOfRM(rm), mkexpr(dst1));
1730 } else {
1731 assign( dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
sewardj5bd4d162004-11-10 13:02:48 +00001732 if (isAddSub(op8))
sewardj2a2ba8b2004-11-08 13:14:06 +00001733 setFlags_DEP1_DEP2(op8, dst0, src, ty);
sewardjb9c5cf62004-08-24 15:10:38 +00001734 else
sewardj2a2ba8b2004-11-08 13:14:06 +00001735 setFlags_DEP1(op8, dst1, ty);
sewardj180e8b32004-07-29 01:40:11 +00001736 if (keep)
1737 putIReg(size, gregOfRM(rm), mkexpr(dst1));
1738 }
sewardje87b4842004-07-10 12:23:30 +00001739
1740 DIP("%s%c %s,%s\n", t_x86opc, nameISize(size),
1741 nameIReg(size,eregOfRM(rm)),
1742 nameIReg(size,gregOfRM(rm)));
1743 return 1+delta0;
sewardje87b4842004-07-10 12:23:30 +00001744 } else {
sewardj9334b0f2004-07-10 22:43:54 +00001745 /* E refers to memory */
1746 addr = disAMode ( &len, sorb, delta0, dis_buf);
1747 assign( dst0, getIReg(size,gregOfRM(rm)) );
sewardj940e8c92004-07-11 16:53:24 +00001748 assign( src, loadLE(szToITy(size), mkexpr(addr)) );
sewardj9334b0f2004-07-10 22:43:54 +00001749
sewardj180e8b32004-07-29 01:40:11 +00001750 if (addSubCarry && op8 == Iop_Add8) {
sewardj180e8b32004-07-29 01:40:11 +00001751 helper_ADC( size, dst1, dst0, src );
sewardj9334b0f2004-07-10 22:43:54 +00001752 putIReg(size, gregOfRM(rm), mkexpr(dst1));
sewardj180e8b32004-07-29 01:40:11 +00001753 } else
1754 if (addSubCarry && op8 == Iop_Sub8) {
1755 helper_SBB( size, dst1, dst0, src );
1756 putIReg(size, gregOfRM(rm), mkexpr(dst1));
1757 } else {
1758 assign( dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
sewardj5bd4d162004-11-10 13:02:48 +00001759 if (isAddSub(op8))
sewardj2a2ba8b2004-11-08 13:14:06 +00001760 setFlags_DEP1_DEP2(op8, dst0, src, ty);
sewardjb9c5cf62004-08-24 15:10:38 +00001761 else
sewardj2a2ba8b2004-11-08 13:14:06 +00001762 setFlags_DEP1(op8, dst1, ty);
sewardj180e8b32004-07-29 01:40:11 +00001763 if (keep)
1764 putIReg(size, gregOfRM(rm), mkexpr(dst1));
1765 }
sewardj9334b0f2004-07-10 22:43:54 +00001766
sewardje87b4842004-07-10 12:23:30 +00001767 DIP("%s%c %s,%s\n", t_x86opc, nameISize(size),
1768 dis_buf,nameIReg(size,gregOfRM(rm)));
sewardj9334b0f2004-07-10 22:43:54 +00001769 return len+delta0;
sewardje87b4842004-07-10 12:23:30 +00001770 }
sewardje87b4842004-07-10 12:23:30 +00001771}
sewardje05c42c2004-07-08 20:25:10 +00001772
1773
1774
1775/* Handle binary integer instructions of the form
1776 op G, E meaning
1777 op reg, reg-or-mem
1778 Is passed the a ptr to the modRM byte, the actual operation, and the
1779 data size. Returns the address advanced completely over this
1780 instruction.
1781
1782 G(src) is reg.
1783 E(dst) is reg-or-mem
1784
1785 If E is reg, --> GET %E, tmp
1786 OP %G, tmp
1787 PUT tmp, %E
1788
1789 If E is mem, --> (getAddr E) -> tmpa
1790 LD (tmpa), tmpv
1791 OP %G, tmpv
1792 ST tmpv, (tmpa)
1793*/
1794static
1795UInt dis_op2_G_E ( UChar sorb,
sewardjcaca9d02004-07-28 07:11:32 +00001796 Bool addSubCarry,
sewardje05c42c2004-07-08 20:25:10 +00001797 IROp op8,
1798 Bool keep,
1799 Int size,
sewardj52d04912005-07-03 00:52:48 +00001800 Int delta0,
sewardj2d49b432005-02-01 00:37:06 +00001801 HChar* t_x86opc )
sewardje05c42c2004-07-08 20:25:10 +00001802{
sewardjc9a43662004-11-30 18:51:59 +00001803 HChar dis_buf[50];
sewardje87b4842004-07-10 12:23:30 +00001804 Int len;
sewardje05c42c2004-07-08 20:25:10 +00001805 IRType ty = szToITy(size);
1806 IRTemp dst1 = newTemp(ty);
1807 IRTemp src = newTemp(ty);
1808 IRTemp dst0 = newTemp(ty);
1809 UChar rm = getIByte(delta0);
sewardj92d168d2004-11-15 14:22:12 +00001810 IRTemp addr = IRTemp_INVALID;
sewardje05c42c2004-07-08 20:25:10 +00001811
sewardjcaca9d02004-07-28 07:11:32 +00001812 /* addSubCarry == True indicates the intended operation is
1813 add-with-carry or subtract-with-borrow. */
1814 if (addSubCarry) {
1815 vassert(op8 == Iop_Add8 || op8 == Iop_Sub8);
1816 vassert(keep);
1817 }
1818
sewardje05c42c2004-07-08 20:25:10 +00001819 if (epartIsReg(rm)) {
sewardje05c42c2004-07-08 20:25:10 +00001820 /* Specially handle XOR reg,reg, because that doesn't really
1821 depend on reg, and doing the obvious thing potentially
1822 generates a spurious value check failure due to the bogus
sewardj55efbdf2005-05-02 17:07:02 +00001823 dependency. Ditto SBB reg,reg.*/
1824 if ((op8 == Iop_Xor8 || (op8 == Iop_Sub8 && addSubCarry))
1825 && gregOfRM(rm) == eregOfRM(rm)) {
1826 putIReg(size, eregOfRM(rm), mkU(ty,0));
sewardje05c42c2004-07-08 20:25:10 +00001827 }
sewardje05c42c2004-07-08 20:25:10 +00001828 assign(dst0, getIReg(size,eregOfRM(rm)));
1829 assign(src, getIReg(size,gregOfRM(rm)));
sewardje05c42c2004-07-08 20:25:10 +00001830
sewardjcaca9d02004-07-28 07:11:32 +00001831 if (addSubCarry && op8 == Iop_Add8) {
sewardj1813dbe2004-07-28 17:09:04 +00001832 helper_ADC( size, dst1, dst0, src );
1833 putIReg(size, eregOfRM(rm), mkexpr(dst1));
sewardjcaca9d02004-07-28 07:11:32 +00001834 } else
1835 if (addSubCarry && op8 == Iop_Sub8) {
1836 helper_SBB( size, dst1, dst0, src );
sewardje05c42c2004-07-08 20:25:10 +00001837 putIReg(size, eregOfRM(rm), mkexpr(dst1));
sewardjcaca9d02004-07-28 07:11:32 +00001838 } else {
1839 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
sewardj5bd4d162004-11-10 13:02:48 +00001840 if (isAddSub(op8))
sewardj2a2ba8b2004-11-08 13:14:06 +00001841 setFlags_DEP1_DEP2(op8, dst0, src, ty);
sewardjb9c5cf62004-08-24 15:10:38 +00001842 else
sewardj2a2ba8b2004-11-08 13:14:06 +00001843 setFlags_DEP1(op8, dst1, ty);
sewardjcaca9d02004-07-28 07:11:32 +00001844 if (keep)
1845 putIReg(size, eregOfRM(rm), mkexpr(dst1));
1846 }
sewardje05c42c2004-07-08 20:25:10 +00001847
1848 DIP("%s%c %s,%s\n", t_x86opc, nameISize(size),
1849 nameIReg(size,gregOfRM(rm)),
1850 nameIReg(size,eregOfRM(rm)));
1851 return 1+delta0;
1852 }
1853
1854 /* E refers to memory */
1855 {
sewardje87b4842004-07-10 12:23:30 +00001856 addr = disAMode ( &len, sorb, delta0, dis_buf);
sewardj940e8c92004-07-11 16:53:24 +00001857 assign(dst0, loadLE(ty,mkexpr(addr)));
sewardje87b4842004-07-10 12:23:30 +00001858 assign(src, getIReg(size,gregOfRM(rm)));
sewardje05c42c2004-07-08 20:25:10 +00001859
sewardjcaca9d02004-07-28 07:11:32 +00001860 if (addSubCarry && op8 == Iop_Add8) {
1861 helper_ADC( size, dst1, dst0, src );
1862 storeLE(mkexpr(addr), mkexpr(dst1));
1863 } else
1864 if (addSubCarry && op8 == Iop_Sub8) {
1865 helper_SBB( size, dst1, dst0, src );
1866 storeLE(mkexpr(addr), mkexpr(dst1));
1867 } else {
1868 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
sewardj5bd4d162004-11-10 13:02:48 +00001869 if (isAddSub(op8))
sewardj2a2ba8b2004-11-08 13:14:06 +00001870 setFlags_DEP1_DEP2(op8, dst0, src, ty);
sewardjb9c5cf62004-08-24 15:10:38 +00001871 else
sewardj2a2ba8b2004-11-08 13:14:06 +00001872 setFlags_DEP1(op8, dst1, ty);
sewardjcaca9d02004-07-28 07:11:32 +00001873 if (keep)
1874 storeLE(mkexpr(addr), mkexpr(dst1));
1875 }
sewardje87b4842004-07-10 12:23:30 +00001876
sewardje05c42c2004-07-08 20:25:10 +00001877 DIP("%s%c %s,%s\n", t_x86opc, nameISize(size),
1878 nameIReg(size,gregOfRM(rm)), dis_buf);
sewardje87b4842004-07-10 12:23:30 +00001879 return len+delta0;
sewardje05c42c2004-07-08 20:25:10 +00001880 }
1881}
1882
1883
1884/* Handle move instructions of the form
1885 mov E, G meaning
1886 mov reg-or-mem, reg
1887 Is passed the a ptr to the modRM byte, and the data size. Returns
1888 the address advanced completely over this instruction.
1889
1890 E(src) is reg-or-mem
1891 G(dst) is reg.
1892
1893 If E is reg, --> GET %E, tmpv
1894 PUT tmpv, %G
1895
1896 If E is mem --> (getAddr E) -> tmpa
1897 LD (tmpa), tmpb
1898 PUT tmpb, %G
1899*/
1900static
1901UInt dis_mov_E_G ( UChar sorb,
1902 Int size,
sewardj52d04912005-07-03 00:52:48 +00001903 Int delta0 )
sewardje05c42c2004-07-08 20:25:10 +00001904{
1905 Int len;
1906 UChar rm = getIByte(delta0);
sewardjc9a43662004-11-30 18:51:59 +00001907 HChar dis_buf[50];
sewardje05c42c2004-07-08 20:25:10 +00001908
1909 if (epartIsReg(rm)) {
sewardj7ca37d92004-10-25 02:58:30 +00001910 putIReg(size, gregOfRM(rm), getIReg(size, eregOfRM(rm)));
sewardje05c42c2004-07-08 20:25:10 +00001911 DIP("mov%c %s,%s\n", nameISize(size),
1912 nameIReg(size,eregOfRM(rm)),
1913 nameIReg(size,gregOfRM(rm)));
sewardj7ca37d92004-10-25 02:58:30 +00001914 return 1+delta0;
sewardje05c42c2004-07-08 20:25:10 +00001915 }
1916
1917 /* E refers to memory */
1918 {
sewardj940e8c92004-07-11 16:53:24 +00001919 IRTemp addr = disAMode ( &len, sorb, delta0, dis_buf );
1920 putIReg(size, gregOfRM(rm), loadLE(szToITy(size), mkexpr(addr)));
sewardje05c42c2004-07-08 20:25:10 +00001921 DIP("mov%c %s,%s\n", nameISize(size),
1922 dis_buf,nameIReg(size,gregOfRM(rm)));
1923 return delta0+len;
1924 }
1925}
1926
1927
1928/* Handle move instructions of the form
1929 mov G, E meaning
1930 mov reg, reg-or-mem
1931 Is passed the a ptr to the modRM byte, and the data size. Returns
1932 the address advanced completely over this instruction.
1933
1934 G(src) is reg.
1935 E(dst) is reg-or-mem
1936
1937 If E is reg, --> GET %G, tmp
1938 PUT tmp, %E
1939
1940 If E is mem, --> (getAddr E) -> tmpa
1941 GET %G, tmpv
1942 ST tmpv, (tmpa)
1943*/
sewardjc9a65702004-07-07 16:32:57 +00001944static
1945UInt dis_mov_G_E ( UChar sorb,
1946 Int size,
sewardj52d04912005-07-03 00:52:48 +00001947 Int delta0 )
sewardjc9a65702004-07-07 16:32:57 +00001948{
sewardje05c42c2004-07-08 20:25:10 +00001949 Int len;
sewardjc9a65702004-07-07 16:32:57 +00001950 UChar rm = getIByte(delta0);
sewardjc9a43662004-11-30 18:51:59 +00001951 HChar dis_buf[50];
sewardjc9a65702004-07-07 16:32:57 +00001952
1953 if (epartIsReg(rm)) {
sewardj41f43bc2004-07-08 14:23:22 +00001954 putIReg(size, eregOfRM(rm), getIReg(size, gregOfRM(rm)));
sewardjc9a65702004-07-07 16:32:57 +00001955 DIP("mov%c %s,%s\n", nameISize(size),
1956 nameIReg(size,gregOfRM(rm)),
1957 nameIReg(size,eregOfRM(rm)));
1958 return 1+delta0;
1959 }
1960
sewardjc9a65702004-07-07 16:32:57 +00001961 /* E refers to memory */
1962 {
sewardj940e8c92004-07-11 16:53:24 +00001963 IRTemp addr = disAMode ( &len, sorb, delta0, dis_buf);
1964 storeLE( mkexpr(addr), getIReg(size, gregOfRM(rm)) );
sewardjc9a65702004-07-07 16:32:57 +00001965 DIP("mov%c %s,%s\n", nameISize(size),
1966 nameIReg(size,gregOfRM(rm)), dis_buf);
sewardje05c42c2004-07-08 20:25:10 +00001967 return len+delta0;
sewardjc9a65702004-07-07 16:32:57 +00001968 }
sewardjc9a65702004-07-07 16:32:57 +00001969}
1970
1971
sewardj0611d802004-07-11 02:37:54 +00001972/* op $immediate, AL/AX/EAX. */
1973static
1974UInt dis_op_imm_A ( Int size,
sewardja718d5d2005-04-03 14:59:54 +00001975 Bool carrying,
sewardj0611d802004-07-11 02:37:54 +00001976 IROp op8,
1977 Bool keep,
sewardj52d04912005-07-03 00:52:48 +00001978 Int delta,
sewardj2d49b432005-02-01 00:37:06 +00001979 HChar* t_x86opc )
sewardj0611d802004-07-11 02:37:54 +00001980{
1981 IRType ty = szToITy(size);
1982 IRTemp dst0 = newTemp(ty);
1983 IRTemp src = newTemp(ty);
1984 IRTemp dst1 = newTemp(ty);
1985 UInt lit = getUDisp(size,delta);
1986 assign(dst0, getIReg(size,R_EAX));
1987 assign(src, mkU(ty,lit));
sewardja718d5d2005-04-03 14:59:54 +00001988
1989 if (isAddSub(op8) && !carrying) {
1990 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
sewardj2a2ba8b2004-11-08 13:14:06 +00001991 setFlags_DEP1_DEP2(op8, dst0, src, ty);
sewardja718d5d2005-04-03 14:59:54 +00001992 }
sewardjb9c5cf62004-08-24 15:10:38 +00001993 else
sewardja718d5d2005-04-03 14:59:54 +00001994 if (isLogic(op8)) {
1995 vassert(!carrying);
1996 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
sewardj2a2ba8b2004-11-08 13:14:06 +00001997 setFlags_DEP1(op8, dst1, ty);
sewardja718d5d2005-04-03 14:59:54 +00001998 }
1999 else
2000 if (op8 == Iop_Add8 && carrying) {
2001 helper_ADC( size, dst1, dst0, src );
2002 }
sewardj2a2ba8b2004-11-08 13:14:06 +00002003 else
sewardj2fbae082005-10-03 02:07:08 +00002004 if (op8 == Iop_Sub8 && carrying) {
2005 helper_SBB( size, dst1, dst0, src );
2006 }
2007 else
sewardj2a2ba8b2004-11-08 13:14:06 +00002008 vpanic("dis_op_imm_A(x86,guest)");
sewardj0611d802004-07-11 02:37:54 +00002009
2010 if (keep)
2011 putIReg(size, R_EAX, mkexpr(dst1));
2012
2013 DIP("%s%c $0x%x, %s\n", t_x86opc, nameISize(size),
2014 lit, nameIReg(size,R_EAX));
2015 return delta+size;
2016}
sewardj9334b0f2004-07-10 22:43:54 +00002017
2018
2019/* Sign- and Zero-extending moves. */
2020static
sewardj52d04912005-07-03 00:52:48 +00002021UInt dis_movx_E_G ( UChar sorb,
2022 Int delta, Int szs, Int szd, Bool sign_extend )
sewardj9334b0f2004-07-10 22:43:54 +00002023{
sewardj9334b0f2004-07-10 22:43:54 +00002024 UChar rm = getIByte(delta);
2025 if (epartIsReg(rm)) {
2026 putIReg(szd, gregOfRM(rm),
sewardj5bd4d162004-11-10 13:02:48 +00002027 unop(mkWidenOp(szs,szd,sign_extend),
2028 getIReg(szs,eregOfRM(rm))));
sewardj9334b0f2004-07-10 22:43:54 +00002029 DIP("mov%c%c%c %s,%s\n", sign_extend ? 's' : 'z',
2030 nameISize(szs), nameISize(szd),
2031 nameIReg(szs,eregOfRM(rm)),
2032 nameIReg(szd,gregOfRM(rm)));
2033 return 1+delta;
2034 }
2035
2036 /* E refers to memory */
2037 {
sewardj940e8c92004-07-11 16:53:24 +00002038 Int len;
sewardjc9a43662004-11-30 18:51:59 +00002039 HChar dis_buf[50];
sewardj940e8c92004-07-11 16:53:24 +00002040 IRTemp addr = disAMode ( &len, sorb, delta, dis_buf );
sewardj0611d802004-07-11 02:37:54 +00002041
2042 putIReg(szd, gregOfRM(rm),
sewardj5bd4d162004-11-10 13:02:48 +00002043 unop(mkWidenOp(szs,szd,sign_extend),
sewardj940e8c92004-07-11 16:53:24 +00002044 loadLE(szToITy(szs),mkexpr(addr))));
sewardj9334b0f2004-07-10 22:43:54 +00002045 DIP("mov%c%c%c %s,%s\n", sign_extend ? 's' : 'z',
2046 nameISize(szs), nameISize(szd),
2047 dis_buf, nameIReg(szd,gregOfRM(rm)));
sewardj0611d802004-07-11 02:37:54 +00002048 return len+delta;
sewardj9334b0f2004-07-10 22:43:54 +00002049 }
2050}
2051
sewardj9690d922004-07-14 01:39:17 +00002052
2053/* Generate code to divide ArchRegs EDX:EAX / DX:AX / AX by the 32 /
2054 16 / 8 bit quantity in the given IRTemp. */
2055static
2056void codegen_div ( Int sz, IRTemp t, Bool signed_divide )
2057{
sewardje5427e82004-09-11 19:43:51 +00002058 IROp op = signed_divide ? Iop_DivModS64to32 : Iop_DivModU64to32;
2059 IRTemp src64 = newTemp(Ity_I64);
2060 IRTemp dst64 = newTemp(Ity_I64);
sewardj9690d922004-07-14 01:39:17 +00002061 switch (sz) {
sewardje5427e82004-09-11 19:43:51 +00002062 case 4:
sewardj9690d922004-07-14 01:39:17 +00002063 assign( src64, binop(Iop_32HLto64,
sewardje5427e82004-09-11 19:43:51 +00002064 getIReg(4,R_EDX), getIReg(4,R_EAX)) );
sewardj9690d922004-07-14 01:39:17 +00002065 assign( dst64, binop(op, mkexpr(src64), mkexpr(t)) );
sewardj8c7f1ab2004-07-29 20:31:09 +00002066 putIReg( 4, R_EAX, unop(Iop_64to32,mkexpr(dst64)) );
sewardj9690d922004-07-14 01:39:17 +00002067 putIReg( 4, R_EDX, unop(Iop_64HIto32,mkexpr(dst64)) );
2068 break;
sewardje5427e82004-09-11 19:43:51 +00002069 case 2: {
2070 IROp widen3264 = signed_divide ? Iop_32Sto64 : Iop_32Uto64;
2071 IROp widen1632 = signed_divide ? Iop_16Sto32 : Iop_16Uto32;
2072 assign( src64, unop(widen3264,
2073 binop(Iop_16HLto32,
2074 getIReg(2,R_EDX), getIReg(2,R_EAX))) );
2075 assign( dst64, binop(op, mkexpr(src64), unop(widen1632,mkexpr(t))) );
2076 putIReg( 2, R_EAX, unop(Iop_32to16,unop(Iop_64to32,mkexpr(dst64))) );
2077 putIReg( 2, R_EDX, unop(Iop_32to16,unop(Iop_64HIto32,mkexpr(dst64))) );
2078 break;
sewardj9690d922004-07-14 01:39:17 +00002079 }
sewardj4e82db72004-10-16 11:32:15 +00002080 case 1: {
2081 IROp widen3264 = signed_divide ? Iop_32Sto64 : Iop_32Uto64;
2082 IROp widen1632 = signed_divide ? Iop_16Sto32 : Iop_16Uto32;
2083 IROp widen816 = signed_divide ? Iop_8Sto16 : Iop_8Uto16;
2084 assign( src64, unop(widen3264, unop(widen1632, getIReg(2,R_EAX))) );
2085 assign( dst64,
2086 binop(op, mkexpr(src64),
2087 unop(widen1632, unop(widen816, mkexpr(t)))) );
2088 putIReg( 1, R_AL, unop(Iop_16to8, unop(Iop_32to16,
2089 unop(Iop_64to32,mkexpr(dst64)))) );
2090 putIReg( 1, R_AH, unop(Iop_16to8, unop(Iop_32to16,
2091 unop(Iop_64HIto32,mkexpr(dst64)))) );
2092 break;
2093 }
sewardj9690d922004-07-14 01:39:17 +00002094 default: vpanic("codegen_div(x86)");
2095 }
2096}
sewardj41f43bc2004-07-08 14:23:22 +00002097
2098
2099static
sewardje90ad6a2004-07-10 19:02:10 +00002100UInt dis_Grp1 ( UChar sorb,
sewardj52d04912005-07-03 00:52:48 +00002101 Int delta, UChar modrm,
sewardj41f43bc2004-07-08 14:23:22 +00002102 Int am_sz, Int d_sz, Int sz, UInt d32 )
2103{
sewardj41f43bc2004-07-08 14:23:22 +00002104 Int len;
sewardjc9a43662004-11-30 18:51:59 +00002105 HChar dis_buf[50];
sewardje05c42c2004-07-08 20:25:10 +00002106 IRType ty = szToITy(sz);
2107 IRTemp dst1 = newTemp(ty);
2108 IRTemp src = newTemp(ty);
2109 IRTemp dst0 = newTemp(ty);
sewardj92d168d2004-11-15 14:22:12 +00002110 IRTemp addr = IRTemp_INVALID;
sewardj66de2272004-07-16 21:19:05 +00002111 IROp op8 = Iop_INVALID;
sewardj180e8b32004-07-29 01:40:11 +00002112 UInt mask = sz==1 ? 0xFF : (sz==2 ? 0xFFFF : 0xFFFFFFFF);
sewardj41f43bc2004-07-08 14:23:22 +00002113
2114 switch (gregOfRM(modrm)) {
sewardje05c42c2004-07-08 20:25:10 +00002115 case 0: op8 = Iop_Add8; break; case 1: op8 = Iop_Or8; break;
sewardj66de2272004-07-16 21:19:05 +00002116 case 2: break; // ADC
2117 case 3: break; // SBB
sewardje05c42c2004-07-08 20:25:10 +00002118 case 4: op8 = Iop_And8; break; case 5: op8 = Iop_Sub8; break;
2119 case 6: op8 = Iop_Xor8; break; case 7: op8 = Iop_Sub8; break;
sewardjd51dc812007-03-20 14:18:45 +00002120 /*NOTREACHED*/
sewardj41f43bc2004-07-08 14:23:22 +00002121 default: vpanic("dis_Grp1: unhandled case");
2122 }
sewardj41f43bc2004-07-08 14:23:22 +00002123
2124 if (epartIsReg(modrm)) {
2125 vassert(am_sz == 1);
2126
2127 assign(dst0, getIReg(sz,eregOfRM(modrm)));
sewardj180e8b32004-07-29 01:40:11 +00002128 assign(src, mkU(ty,d32 & mask));
sewardj41f43bc2004-07-08 14:23:22 +00002129
sewardj180e8b32004-07-29 01:40:11 +00002130 if (gregOfRM(modrm) == 2 /* ADC */) {
2131 helper_ADC( sz, dst1, dst0, src );
2132 } else
2133 if (gregOfRM(modrm) == 3 /* SBB */) {
2134 helper_SBB( sz, dst1, dst0, src );
2135 } else {
2136 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
sewardj5bd4d162004-11-10 13:02:48 +00002137 if (isAddSub(op8))
sewardj2a2ba8b2004-11-08 13:14:06 +00002138 setFlags_DEP1_DEP2(op8, dst0, src, ty);
sewardjb9c5cf62004-08-24 15:10:38 +00002139 else
sewardj2a2ba8b2004-11-08 13:14:06 +00002140 setFlags_DEP1(op8, dst1, ty);
sewardj180e8b32004-07-29 01:40:11 +00002141 }
sewardj41f43bc2004-07-08 14:23:22 +00002142
2143 if (gregOfRM(modrm) < 7)
sewardje05c42c2004-07-08 20:25:10 +00002144 putIReg(sz, eregOfRM(modrm), mkexpr(dst1));
sewardj41f43bc2004-07-08 14:23:22 +00002145
2146 delta += (am_sz + d_sz);
2147 DIP("%s%c $0x%x, %s\n", nameGrp1(gregOfRM(modrm)), nameISize(sz), d32,
2148 nameIReg(sz,eregOfRM(modrm)));
2149 } else {
sewardje87b4842004-07-10 12:23:30 +00002150 addr = disAMode ( &len, sorb, delta, dis_buf);
sewardj41f43bc2004-07-08 14:23:22 +00002151
sewardj940e8c92004-07-11 16:53:24 +00002152 assign(dst0, loadLE(ty,mkexpr(addr)));
sewardj180e8b32004-07-29 01:40:11 +00002153 assign(src, mkU(ty,d32 & mask));
sewardj41f43bc2004-07-08 14:23:22 +00002154
sewardj66de2272004-07-16 21:19:05 +00002155 if (gregOfRM(modrm) == 2 /* ADC */) {
sewardj3af115f2004-07-14 02:46:52 +00002156 helper_ADC( sz, dst1, dst0, src );
2157 } else
sewardj66de2272004-07-16 21:19:05 +00002158 if (gregOfRM(modrm) == 3 /* SBB */) {
sewardje166ed02004-10-25 02:27:01 +00002159 helper_SBB( sz, dst1, dst0, src );
sewardj3af115f2004-07-14 02:46:52 +00002160 } else {
2161 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
sewardj5bd4d162004-11-10 13:02:48 +00002162 if (isAddSub(op8))
sewardj2a2ba8b2004-11-08 13:14:06 +00002163 setFlags_DEP1_DEP2(op8, dst0, src, ty);
sewardjb9c5cf62004-08-24 15:10:38 +00002164 else
sewardj2a2ba8b2004-11-08 13:14:06 +00002165 setFlags_DEP1(op8, dst1, ty);
sewardj3af115f2004-07-14 02:46:52 +00002166 }
sewardj41f43bc2004-07-08 14:23:22 +00002167
2168 if (gregOfRM(modrm) < 7)
sewardj940e8c92004-07-11 16:53:24 +00002169 storeLE(mkexpr(addr), mkexpr(dst1));
sewardj41f43bc2004-07-08 14:23:22 +00002170
2171 delta += (len+d_sz);
2172 DIP("%s%c $0x%x, %s\n", nameGrp1(gregOfRM(modrm)), nameISize(sz),
2173 d32, dis_buf);
2174 }
2175 return delta;
2176}
2177
2178
sewardj6d2638e2004-07-15 09:38:27 +00002179/* Group 2 extended opcodes. shift_expr must be an 8-bit typed
2180 expression. */
2181
sewardje90ad6a2004-07-10 19:02:10 +00002182static
sewardj52d04912005-07-03 00:52:48 +00002183UInt dis_Grp2 ( UChar sorb,
2184 Int delta, UChar modrm,
sewardj6d2638e2004-07-15 09:38:27 +00002185 Int am_sz, Int d_sz, Int sz, IRExpr* shift_expr,
sewardjd51dc812007-03-20 14:18:45 +00002186 HChar* shift_expr_txt, Bool* decode_OK )
sewardje90ad6a2004-07-10 19:02:10 +00002187{
2188 /* delta on entry points at the modrm byte. */
sewardjc9a43662004-11-30 18:51:59 +00002189 HChar dis_buf[50];
sewardj6d2638e2004-07-15 09:38:27 +00002190 Int len;
sewardj2eef7732005-08-23 15:41:14 +00002191 Bool isShift, isRotate, isRotateC;
sewardj6d2638e2004-07-15 09:38:27 +00002192 IRType ty = szToITy(sz);
2193 IRTemp dst0 = newTemp(ty);
2194 IRTemp dst1 = newTemp(ty);
sewardj92d168d2004-11-15 14:22:12 +00002195 IRTemp addr = IRTemp_INVALID;
sewardje90ad6a2004-07-10 19:02:10 +00002196
sewardjd51dc812007-03-20 14:18:45 +00002197 *decode_OK = True;
2198
sewardje90ad6a2004-07-10 19:02:10 +00002199 vassert(sz == 1 || sz == 2 || sz == 4);
2200
sewardje90ad6a2004-07-10 19:02:10 +00002201 /* Put value to shift/rotate in dst0. */
2202 if (epartIsReg(modrm)) {
2203 assign(dst0, getIReg(sz, eregOfRM(modrm)));
sewardj940e8c92004-07-11 16:53:24 +00002204 delta += (am_sz + d_sz);
sewardje90ad6a2004-07-10 19:02:10 +00002205 } else {
sewardj940e8c92004-07-11 16:53:24 +00002206 addr = disAMode ( &len, sorb, delta, dis_buf);
2207 assign(dst0, loadLE(ty,mkexpr(addr)));
2208 delta += len + d_sz;
sewardje90ad6a2004-07-10 19:02:10 +00002209 }
2210
2211 isShift = False;
2212 switch (gregOfRM(modrm)) { case 4: case 5: case 7: isShift = True; }
2213
sewardj750f4072004-07-26 22:39:11 +00002214 isRotate = False;
2215 switch (gregOfRM(modrm)) { case 0: case 1: isRotate = True; }
2216
sewardj2eef7732005-08-23 15:41:14 +00002217 isRotateC = False;
2218 switch (gregOfRM(modrm)) { case 2: case 3: isRotateC = True; }
sewardj9aebb0c2004-10-24 19:20:43 +00002219
sewardjd51dc812007-03-20 14:18:45 +00002220 if (gregOfRM(modrm) == 6) {
2221 *decode_OK = False;
2222 return delta;
2223 }
2224
sewardj2eef7732005-08-23 15:41:14 +00002225 if (!isShift && !isRotate && !isRotateC) {
sewardjd51dc812007-03-20 14:18:45 +00002226 /*NOTREACHED*/
sewardj8c7f1ab2004-07-29 20:31:09 +00002227 vpanic("dis_Grp2(Reg): unhandled case(x86)");
2228 }
2229
sewardj2eef7732005-08-23 15:41:14 +00002230 if (isRotateC) {
2231 /* call a helper; these insns are so ridiculous they do not
2232 deserve better */
2233 Bool left = toBool(gregOfRM(modrm) == 2);
sewardj9aebb0c2004-10-24 19:20:43 +00002234 IRTemp r64 = newTemp(Ity_I64);
sewardjf9655262004-10-31 20:02:16 +00002235 IRExpr** args
2236 = mkIRExprVec_4( widenUto32(mkexpr(dst0)), /* thing to rotate */
2237 widenUto32(shift_expr), /* rotate amount */
sewardj2a9ad022004-11-25 02:46:58 +00002238 widenUto32(mk_x86g_calculate_eflags_all()),
sewardjf9655262004-10-31 20:02:16 +00002239 mkU32(sz) );
2240 assign( r64, mkIRExprCCall(
sewardj8ea867b2004-10-30 19:03:02 +00002241 Ity_I64,
sewardjf9655262004-10-31 20:02:16 +00002242 0/*regparm*/,
sewardj2eef7732005-08-23 15:41:14 +00002243 left ? "x86g_calculate_RCL" : "x86g_calculate_RCR",
2244 left ? &x86g_calculate_RCL : &x86g_calculate_RCR,
sewardj8ea867b2004-10-30 19:03:02 +00002245 args
sewardjf9655262004-10-31 20:02:16 +00002246 )
2247 );
sewardj9aebb0c2004-10-24 19:20:43 +00002248 /* new eflags in hi half r64; new value in lo half r64 */
2249 assign( dst1, narrowTo(ty, unop(Iop_64to32, mkexpr(r64))) );
sewardj2a9ad022004-11-25 02:46:58 +00002250 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
sewardj2a2ba8b2004-11-08 13:14:06 +00002251 stmt( IRStmt_Put( OFFB_CC_DEP1, unop(Iop_64HIto32, mkexpr(r64)) ));
2252 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
sewardja3b7e3a2005-04-05 01:54:19 +00002253 /* Set NDEP even though it isn't used. This makes redundant-PUT
2254 elimination of previous stores to this field work better. */
2255 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardj9aebb0c2004-10-24 19:20:43 +00002256 }
2257
sewardje90ad6a2004-07-10 19:02:10 +00002258 if (isShift) {
2259
sewardjc22a6fd2004-07-29 23:41:47 +00002260 IRTemp pre32 = newTemp(Ity_I32);
2261 IRTemp res32 = newTemp(Ity_I32);
2262 IRTemp res32ss = newTemp(Ity_I32);
sewardj6d2638e2004-07-15 09:38:27 +00002263 IRTemp shift_amt = newTemp(Ity_I8);
sewardjc22a6fd2004-07-29 23:41:47 +00002264 IROp op32;
sewardje90ad6a2004-07-10 19:02:10 +00002265
2266 switch (gregOfRM(modrm)) {
sewardjc22a6fd2004-07-29 23:41:47 +00002267 case 4: op32 = Iop_Shl32; break;
2268 case 5: op32 = Iop_Shr32; break;
2269 case 7: op32 = Iop_Sar32; break;
sewardjd51dc812007-03-20 14:18:45 +00002270 /*NOTREACHED*/
sewardje90ad6a2004-07-10 19:02:10 +00002271 default: vpanic("dis_Grp2:shift"); break;
2272 }
2273
sewardjc22a6fd2004-07-29 23:41:47 +00002274 /* Widen the value to be shifted to 32 bits, do the shift, and
2275 narrow back down. This seems surprisingly long-winded, but
2276 unfortunately the Intel semantics requires that 8/16-bit
2277 shifts give defined results for shift values all the way up
2278 to 31, and this seems the simplest way to do it. It has the
2279 advantage that the only IR level shifts generated are of 32
2280 bit values, and the shift amount is guaranteed to be in the
2281 range 0 .. 31, thereby observing the IR semantics requiring
2282 all shift values to be in the range 0 .. 2^word_size-1. */
2283
2284 /* shift_amt = shift_expr & 31, regardless of operation size */
2285 assign( shift_amt, binop(Iop_And8, shift_expr, mkU8(31)) );
2286
2287 /* suitably widen the value to be shifted to 32 bits. */
2288 assign( pre32, op32==Iop_Sar32 ? widenSto32(mkexpr(dst0))
2289 : widenUto32(mkexpr(dst0)) );
2290
2291 /* res32 = pre32 `shift` shift_amt */
2292 assign( res32, binop(op32, mkexpr(pre32), mkexpr(shift_amt)) );
2293
2294 /* res32ss = pre32 `shift` ((shift_amt - 1) & 31) */
2295 assign( res32ss,
2296 binop(op32,
2297 mkexpr(pre32),
2298 binop(Iop_And8,
2299 binop(Iop_Sub8,
2300 mkexpr(shift_amt), mkU8(1)),
2301 mkU8(31))) );
sewardje90ad6a2004-07-10 19:02:10 +00002302
2303 /* Build the flags thunk. */
sewardj2a2ba8b2004-11-08 13:14:06 +00002304 setFlags_DEP1_DEP2_shift(op32, res32, res32ss, ty, shift_amt);
sewardjc22a6fd2004-07-29 23:41:47 +00002305
2306 /* Narrow the result back down. */
2307 assign( dst1, narrowTo(ty, mkexpr(res32)) );
sewardj750f4072004-07-26 22:39:11 +00002308
sewardj1813dbe2004-07-28 17:09:04 +00002309 } /* if (isShift) */
2310
2311 else
sewardj750f4072004-07-26 22:39:11 +00002312 if (isRotate) {
sewardj7ebbdae2004-08-26 12:30:48 +00002313 Int ccOp = ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
sewardj2d49b432005-02-01 00:37:06 +00002314 Bool left = toBool(gregOfRM(modrm) == 0);
sewardj7ebbdae2004-08-26 12:30:48 +00002315 IRTemp rot_amt = newTemp(Ity_I8);
2316 IRTemp rot_amt32 = newTemp(Ity_I8);
2317 IRTemp oldFlags = newTemp(Ity_I32);
sewardj750f4072004-07-26 22:39:11 +00002318
2319 /* rot_amt = shift_expr & mask */
sewardjc22a6fd2004-07-29 23:41:47 +00002320 /* By masking the rotate amount thusly, the IR-level Shl/Shr
2321 expressions never shift beyond the word size and thus remain
2322 well defined. */
sewardj7ebbdae2004-08-26 12:30:48 +00002323 assign(rot_amt32, binop(Iop_And8, shift_expr, mkU8(31)));
2324
2325 if (ty == Ity_I32)
2326 assign(rot_amt, mkexpr(rot_amt32));
2327 else
2328 assign(rot_amt, binop(Iop_And8, mkexpr(rot_amt32), mkU8(8*sz-1)));
sewardj750f4072004-07-26 22:39:11 +00002329
2330 if (left) {
sewardj1813dbe2004-07-28 17:09:04 +00002331
sewardj750f4072004-07-26 22:39:11 +00002332 /* dst1 = (dst0 << rot_amt) | (dst0 >>u (wordsize-rot_amt)) */
2333 assign(dst1,
2334 binop( mkSizedOp(ty,Iop_Or8),
2335 binop( mkSizedOp(ty,Iop_Shl8),
2336 mkexpr(dst0),
2337 mkexpr(rot_amt)
2338 ),
2339 binop( mkSizedOp(ty,Iop_Shr8),
2340 mkexpr(dst0),
2341 binop(Iop_Sub8,mkU8(8*sz), mkexpr(rot_amt))
2342 )
2343 )
2344 );
sewardj2a9ad022004-11-25 02:46:58 +00002345 ccOp += X86G_CC_OP_ROLB;
sewardj750f4072004-07-26 22:39:11 +00002346
sewardj1813dbe2004-07-28 17:09:04 +00002347 } else { /* right */
sewardj750f4072004-07-26 22:39:11 +00002348
sewardj1813dbe2004-07-28 17:09:04 +00002349 /* dst1 = (dst0 >>u rot_amt) | (dst0 << (wordsize-rot_amt)) */
2350 assign(dst1,
2351 binop( mkSizedOp(ty,Iop_Or8),
2352 binop( mkSizedOp(ty,Iop_Shr8),
2353 mkexpr(dst0),
2354 mkexpr(rot_amt)
2355 ),
2356 binop( mkSizedOp(ty,Iop_Shl8),
2357 mkexpr(dst0),
2358 binop(Iop_Sub8,mkU8(8*sz), mkexpr(rot_amt))
sewardj750f4072004-07-26 22:39:11 +00002359 )
2360 )
2361 );
sewardj2a9ad022004-11-25 02:46:58 +00002362 ccOp += X86G_CC_OP_RORB;
sewardjc22a6fd2004-07-29 23:41:47 +00002363
sewardj750f4072004-07-26 22:39:11 +00002364 }
sewardjc22a6fd2004-07-29 23:41:47 +00002365
sewardj1813dbe2004-07-28 17:09:04 +00002366 /* dst1 now holds the rotated value. Build flag thunk. We
2367 need the resulting value for this, and the previous flags.
2368 Except don't set it if the rotate count is zero. */
2369
sewardj2a9ad022004-11-25 02:46:58 +00002370 assign(oldFlags, mk_x86g_calculate_eflags_all());
sewardj1813dbe2004-07-28 17:09:04 +00002371
sewardj2a2ba8b2004-11-08 13:14:06 +00002372 /* CC_DEP1 is the rotated value. CC_NDEP is flags before. */
sewardj1813dbe2004-07-28 17:09:04 +00002373 stmt( IRStmt_Put( OFFB_CC_OP,
sewardj7ebbdae2004-08-26 12:30:48 +00002374 IRExpr_Mux0X( mkexpr(rot_amt32),
sewardj1813dbe2004-07-28 17:09:04 +00002375 IRExpr_Get(OFFB_CC_OP,Ity_I32),
2376 mkU32(ccOp))) );
sewardj2a2ba8b2004-11-08 13:14:06 +00002377 stmt( IRStmt_Put( OFFB_CC_DEP1,
sewardj7ebbdae2004-08-26 12:30:48 +00002378 IRExpr_Mux0X( mkexpr(rot_amt32),
sewardj2a2ba8b2004-11-08 13:14:06 +00002379 IRExpr_Get(OFFB_CC_DEP1,Ity_I32),
sewardjc22a6fd2004-07-29 23:41:47 +00002380 widenUto32(mkexpr(dst1)))) );
sewardj2a2ba8b2004-11-08 13:14:06 +00002381 stmt( IRStmt_Put( OFFB_CC_DEP2,
sewardj7ebbdae2004-08-26 12:30:48 +00002382 IRExpr_Mux0X( mkexpr(rot_amt32),
sewardj2a2ba8b2004-11-08 13:14:06 +00002383 IRExpr_Get(OFFB_CC_DEP2,Ity_I32),
2384 mkU32(0))) );
2385 stmt( IRStmt_Put( OFFB_CC_NDEP,
2386 IRExpr_Mux0X( mkexpr(rot_amt32),
2387 IRExpr_Get(OFFB_CC_NDEP,Ity_I32),
sewardj1813dbe2004-07-28 17:09:04 +00002388 mkexpr(oldFlags))) );
2389 } /* if (isRotate) */
sewardje90ad6a2004-07-10 19:02:10 +00002390
2391 /* Save result, and finish up. */
2392 if (epartIsReg(modrm)) {
2393 putIReg(sz, eregOfRM(modrm), mkexpr(dst1));
sewardjf48ac192004-10-29 00:41:29 +00002394 if (vex_traceflags & VEX_TRACE_FE) {
sewardje90ad6a2004-07-10 19:02:10 +00002395 vex_printf("%s%c ",
2396 nameGrp2(gregOfRM(modrm)), nameISize(sz) );
sewardj6d2638e2004-07-15 09:38:27 +00002397 if (shift_expr_txt)
2398 vex_printf("%s", shift_expr_txt);
2399 else
2400 ppIRExpr(shift_expr);
sewardje90ad6a2004-07-10 19:02:10 +00002401 vex_printf(", %s\n", nameIReg(sz,eregOfRM(modrm)));
2402 }
sewardje90ad6a2004-07-10 19:02:10 +00002403 } else {
sewardj940e8c92004-07-11 16:53:24 +00002404 storeLE(mkexpr(addr), mkexpr(dst1));
sewardjf48ac192004-10-29 00:41:29 +00002405 if (vex_traceflags & VEX_TRACE_FE) {
sewardj940e8c92004-07-11 16:53:24 +00002406 vex_printf("%s%c ",
2407 nameGrp2(gregOfRM(modrm)), nameISize(sz) );
sewardj6d2638e2004-07-15 09:38:27 +00002408 if (shift_expr_txt)
2409 vex_printf("%s", shift_expr_txt);
2410 else
2411 ppIRExpr(shift_expr);
sewardj940e8c92004-07-11 16:53:24 +00002412 vex_printf(", %s\n", dis_buf);
2413 }
sewardje90ad6a2004-07-10 19:02:10 +00002414 }
sewardje90ad6a2004-07-10 19:02:10 +00002415 return delta;
2416}
2417
2418
sewardj490ad382005-03-13 17:25:53 +00002419/* Group 8 extended opcodes (but BT/BTS/BTC/BTR only). */
2420static
sewardj52d04912005-07-03 00:52:48 +00002421UInt dis_Grp8_Imm ( UChar sorb,
2422 Int delta, UChar modrm,
sewardj490ad382005-03-13 17:25:53 +00002423 Int am_sz, Int sz, UInt src_val,
2424 Bool* decode_OK )
2425{
2426 /* src_val denotes a d8.
2427 And delta on entry points at the modrm byte. */
sewardje90ad6a2004-07-10 19:02:10 +00002428
sewardj490ad382005-03-13 17:25:53 +00002429 IRType ty = szToITy(sz);
2430 IRTemp t2 = newTemp(Ity_I32);
2431 IRTemp t2m = newTemp(Ity_I32);
2432 IRTemp t_addr = IRTemp_INVALID;
2433 HChar dis_buf[50];
2434 UInt mask;
sewardjd1061ab2004-07-08 01:45:30 +00002435
sewardj490ad382005-03-13 17:25:53 +00002436 /* we're optimists :-) */
2437 *decode_OK = True;
sewardjd1061ab2004-07-08 01:45:30 +00002438
sewardj490ad382005-03-13 17:25:53 +00002439 /* Limit src_val -- the bit offset -- to something within a word.
2440 The Intel docs say that literal offsets larger than a word are
2441 masked in this way. */
2442 switch (sz) {
2443 case 2: src_val &= 15; break;
2444 case 4: src_val &= 31; break;
2445 default: *decode_OK = False; return delta;
2446 }
sewardjcf780b42004-07-13 18:42:17 +00002447
sewardj490ad382005-03-13 17:25:53 +00002448 /* Invent a mask suitable for the operation. */
2449 switch (gregOfRM(modrm)) {
2450 case 4: /* BT */ mask = 0; break;
2451 case 5: /* BTS */ mask = 1 << src_val; break;
2452 case 6: /* BTR */ mask = ~(1 << src_val); break;
2453 case 7: /* BTC */ mask = 1 << src_val; break;
2454 /* If this needs to be extended, probably simplest to make a
2455 new function to handle the other cases (0 .. 3). The
2456 Intel docs do however not indicate any use for 0 .. 3, so
2457 we don't expect this to happen. */
2458 default: *decode_OK = False; return delta;
2459 }
2460
2461 /* Fetch the value to be tested and modified into t2, which is
2462 32-bits wide regardless of sz. */
2463 if (epartIsReg(modrm)) {
2464 vassert(am_sz == 1);
sewardj5a8334e2005-03-13 19:52:45 +00002465 assign( t2, widenUto32(getIReg(sz, eregOfRM(modrm))) );
sewardj490ad382005-03-13 17:25:53 +00002466 delta += (am_sz + 1);
2467 DIP("%s%c $0x%x, %s\n", nameGrp8(gregOfRM(modrm)), nameISize(sz),
2468 src_val, nameIReg(sz,eregOfRM(modrm)));
2469 } else {
2470 Int len;
2471 t_addr = disAMode ( &len, sorb, delta, dis_buf);
2472 delta += (len+1);
2473 assign( t2, widenUto32(loadLE(ty, mkexpr(t_addr))) );
2474 DIP("%s%c $0x%x, %s\n", nameGrp8(gregOfRM(modrm)), nameISize(sz),
2475 src_val, dis_buf);
2476 }
2477
2478 /* Copy relevant bit from t2 into the carry flag. */
2479 /* Flags: C=selected bit, O,S,Z,A,P undefined, so are set to zero. */
2480 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
2481 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
2482 stmt( IRStmt_Put(
2483 OFFB_CC_DEP1,
2484 binop(Iop_And32,
2485 binop(Iop_Shr32, mkexpr(t2), mkU8(src_val)),
2486 mkU32(1))
2487 ));
sewardja3b7e3a2005-04-05 01:54:19 +00002488 /* Set NDEP even though it isn't used. This makes redundant-PUT
2489 elimination of previous stores to this field work better. */
2490 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardj490ad382005-03-13 17:25:53 +00002491
2492 /* Compute the new value into t2m, if non-BT. */
2493 switch (gregOfRM(modrm)) {
2494 case 4: /* BT */
2495 break;
2496 case 5: /* BTS */
2497 assign( t2m, binop(Iop_Or32, mkU32(mask), mkexpr(t2)) );
2498 break;
2499 case 6: /* BTR */
2500 assign( t2m, binop(Iop_And32, mkU32(mask), mkexpr(t2)) );
2501 break;
2502 case 7: /* BTC */
2503 assign( t2m, binop(Iop_Xor32, mkU32(mask), mkexpr(t2)) );
2504 break;
sewardjba89f4c2005-04-07 17:31:27 +00002505 default:
2506 /*NOTREACHED*/ /*the previous switch guards this*/
sewardj490ad382005-03-13 17:25:53 +00002507 vassert(0);
2508 }
2509
2510 /* Write the result back, if non-BT. */
2511 if (gregOfRM(modrm) != 4 /* BT */) {
2512 if (epartIsReg(modrm)) {
2513 putIReg(sz, eregOfRM(modrm), narrowTo(ty, mkexpr(t2m)));
2514 } else {
2515 storeLE(mkexpr(t_addr), narrowTo(ty, mkexpr(t2m)));
2516 }
2517 }
2518
2519 return delta;
2520}
sewardjcf780b42004-07-13 18:42:17 +00002521
2522
sewardj1813dbe2004-07-28 17:09:04 +00002523/* Signed/unsigned widening multiply. Generate IR to multiply the
2524 value in EAX/AX/AL by the given IRTemp, and park the result in
2525 EDX:EAX/DX:AX/AX.
sewardjcf780b42004-07-13 18:42:17 +00002526*/
sewardj1813dbe2004-07-28 17:09:04 +00002527static void codegen_mulL_A_D ( Int sz, Bool syned,
sewardj2d49b432005-02-01 00:37:06 +00002528 IRTemp tmp, HChar* tmp_txt )
sewardjcf780b42004-07-13 18:42:17 +00002529{
sewardjcf780b42004-07-13 18:42:17 +00002530 IRType ty = szToITy(sz);
2531 IRTemp t1 = newTemp(ty);
sewardjcf780b42004-07-13 18:42:17 +00002532
sewardj1813dbe2004-07-28 17:09:04 +00002533 assign( t1, getIReg(sz, R_EAX) );
sewardjcf780b42004-07-13 18:42:17 +00002534
2535 switch (ty) {
sewardjb81f8b32004-07-30 10:17:50 +00002536 case Ity_I32: {
2537 IRTemp res64 = newTemp(Ity_I64);
sewardj948d48b2004-11-05 19:49:09 +00002538 IRTemp resHi = newTemp(Ity_I32);
2539 IRTemp resLo = newTemp(Ity_I32);
sewardjb81f8b32004-07-30 10:17:50 +00002540 IROp mulOp = syned ? Iop_MullS32 : Iop_MullU32;
sewardj2a9ad022004-11-25 02:46:58 +00002541 UInt tBaseOp = syned ? X86G_CC_OP_SMULB : X86G_CC_OP_UMULB;
sewardj2a2ba8b2004-11-08 13:14:06 +00002542 setFlags_MUL ( Ity_I32, t1, tmp, tBaseOp );
sewardjb81f8b32004-07-30 10:17:50 +00002543 assign( res64, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
sewardj948d48b2004-11-05 19:49:09 +00002544 assign( resHi, unop(Iop_64HIto32,mkexpr(res64)));
2545 assign( resLo, unop(Iop_64to32,mkexpr(res64)));
sewardj948d48b2004-11-05 19:49:09 +00002546 putIReg(4, R_EDX, mkexpr(resHi));
2547 putIReg(4, R_EAX, mkexpr(resLo));
sewardjb81f8b32004-07-30 10:17:50 +00002548 break;
2549 }
2550 case Ity_I16: {
2551 IRTemp res32 = newTemp(Ity_I32);
sewardj948d48b2004-11-05 19:49:09 +00002552 IRTemp resHi = newTemp(Ity_I16);
2553 IRTemp resLo = newTemp(Ity_I16);
sewardjb81f8b32004-07-30 10:17:50 +00002554 IROp mulOp = syned ? Iop_MullS16 : Iop_MullU16;
sewardj2a9ad022004-11-25 02:46:58 +00002555 UInt tBaseOp = syned ? X86G_CC_OP_SMULB : X86G_CC_OP_UMULB;
sewardj2a2ba8b2004-11-08 13:14:06 +00002556 setFlags_MUL ( Ity_I16, t1, tmp, tBaseOp );
sewardjb81f8b32004-07-30 10:17:50 +00002557 assign( res32, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
sewardj948d48b2004-11-05 19:49:09 +00002558 assign( resHi, unop(Iop_32HIto16,mkexpr(res32)));
2559 assign( resLo, unop(Iop_32to16,mkexpr(res32)));
sewardj948d48b2004-11-05 19:49:09 +00002560 putIReg(2, R_EDX, mkexpr(resHi));
2561 putIReg(2, R_EAX, mkexpr(resLo));
sewardjb81f8b32004-07-30 10:17:50 +00002562 break;
2563 }
2564 case Ity_I8: {
2565 IRTemp res16 = newTemp(Ity_I16);
sewardj948d48b2004-11-05 19:49:09 +00002566 IRTemp resHi = newTemp(Ity_I8);
2567 IRTemp resLo = newTemp(Ity_I8);
sewardjb81f8b32004-07-30 10:17:50 +00002568 IROp mulOp = syned ? Iop_MullS8 : Iop_MullU8;
sewardj2a9ad022004-11-25 02:46:58 +00002569 UInt tBaseOp = syned ? X86G_CC_OP_SMULB : X86G_CC_OP_UMULB;
sewardj2a2ba8b2004-11-08 13:14:06 +00002570 setFlags_MUL ( Ity_I8, t1, tmp, tBaseOp );
sewardjb81f8b32004-07-30 10:17:50 +00002571 assign( res16, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
sewardj948d48b2004-11-05 19:49:09 +00002572 assign( resHi, unop(Iop_16HIto8,mkexpr(res16)));
2573 assign( resLo, unop(Iop_16to8,mkexpr(res16)));
sewardjb81f8b32004-07-30 10:17:50 +00002574 putIReg(2, R_EAX, mkexpr(res16));
2575 break;
2576 }
2577 default:
2578 vpanic("codegen_mulL_A_D(x86)");
sewardjcf780b42004-07-13 18:42:17 +00002579 }
sewardj1813dbe2004-07-28 17:09:04 +00002580 DIP("%s%c %s\n", syned ? "imul" : "mul", nameISize(sz), tmp_txt);
sewardjcf780b42004-07-13 18:42:17 +00002581}
2582
sewardj940e8c92004-07-11 16:53:24 +00002583
2584/* Group 3 extended opcodes. */
2585static
sewardjd51dc812007-03-20 14:18:45 +00002586UInt dis_Grp3 ( UChar sorb, Int sz, Int delta, Bool* decode_OK )
sewardj940e8c92004-07-11 16:53:24 +00002587{
sewardjc9a43662004-11-30 18:51:59 +00002588 UInt d32;
2589 UChar modrm;
2590 HChar dis_buf[50];
2591 Int len;
sewardjc2ac51e2004-07-12 01:03:26 +00002592 IRTemp addr;
sewardj940e8c92004-07-11 16:53:24 +00002593 IRType ty = szToITy(sz);
2594 IRTemp t1 = newTemp(ty);
sewardj940e8c92004-07-11 16:53:24 +00002595 IRTemp dst1, src, dst0;
sewardjd51dc812007-03-20 14:18:45 +00002596
2597 *decode_OK = True; /* may change this later */
2598
sewardj940e8c92004-07-11 16:53:24 +00002599 modrm = getIByte(delta);
2600 if (epartIsReg(modrm)) {
2601 switch (gregOfRM(modrm)) {
sewardjc2ac51e2004-07-12 01:03:26 +00002602 case 0: { /* TEST */
2603 delta++; d32 = getUDisp(sz, delta); delta += sz;
sewardj5bd4d162004-11-10 13:02:48 +00002604 dst1 = newTemp(ty);
2605 assign(dst1, binop(mkSizedOp(ty,Iop_And8),
2606 getIReg(sz,eregOfRM(modrm)),
sewardjc2ac51e2004-07-12 01:03:26 +00002607 mkU(ty,d32)));
sewardj5bd4d162004-11-10 13:02:48 +00002608 setFlags_DEP1( Iop_And8, dst1, ty );
sewardjc2ac51e2004-07-12 01:03:26 +00002609 DIP("test%c $0x%x, %s\n", nameISize(sz), d32,
2610 nameIReg(sz, eregOfRM(modrm)));
2611 break;
2612 }
sewardjd51dc812007-03-20 14:18:45 +00002613 case 1: /* UNDEFINED */
2614 /* The Intel docs imply this insn is undefined and binutils
2615 agrees. Unfortunately Core 2 will run it (with who
2616 knows what result?) sandpile.org reckons it's an alias
2617 for case 0. We play safe. */
2618 *decode_OK = False;
2619 break;
sewardj940e8c92004-07-11 16:53:24 +00002620 case 2: /* NOT */
2621 delta++;
2622 putIReg(sz, eregOfRM(modrm),
2623 unop(mkSizedOp(ty,Iop_Not8),
2624 getIReg(sz, eregOfRM(modrm))));
2625 DIP("not%c %s\n", nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
2626 break;
2627 case 3: /* NEG */
2628 delta++;
2629 dst0 = newTemp(ty);
2630 src = newTemp(ty);
2631 dst1 = newTemp(ty);
sewardj5bd4d162004-11-10 13:02:48 +00002632 assign(dst0, mkU(ty,0));
sewardja511afc2004-07-29 22:26:03 +00002633 assign(src, getIReg(sz,eregOfRM(modrm)));
sewardjeb17e492007-08-25 23:07:44 +00002634 assign(dst1, binop(mkSizedOp(ty,Iop_Sub8), mkexpr(dst0), mkexpr(src)));
sewardj2a2ba8b2004-11-08 13:14:06 +00002635 setFlags_DEP1_DEP2(Iop_Sub8, dst0, src, ty);
sewardj5bd4d162004-11-10 13:02:48 +00002636 putIReg(sz, eregOfRM(modrm), mkexpr(dst1));
sewardj940e8c92004-07-11 16:53:24 +00002637 DIP("neg%c %s\n", nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
2638 break;
sewardjcf780b42004-07-13 18:42:17 +00002639 case 4: /* MUL (unsigned widening) */
2640 delta++;
sewardj1813dbe2004-07-28 17:09:04 +00002641 src = newTemp(ty);
sewardj5bd4d162004-11-10 13:02:48 +00002642 assign(src, getIReg(sz,eregOfRM(modrm)));
sewardj1813dbe2004-07-28 17:09:04 +00002643 codegen_mulL_A_D ( sz, False, src, nameIReg(sz,eregOfRM(modrm)) );
sewardjcf780b42004-07-13 18:42:17 +00002644 break;
sewardjcaca9d02004-07-28 07:11:32 +00002645 case 5: /* IMUL (signed widening) */
2646 delta++;
sewardj1813dbe2004-07-28 17:09:04 +00002647 src = newTemp(ty);
sewardj5bd4d162004-11-10 13:02:48 +00002648 assign(src, getIReg(sz,eregOfRM(modrm)));
sewardj1813dbe2004-07-28 17:09:04 +00002649 codegen_mulL_A_D ( sz, True, src, nameIReg(sz,eregOfRM(modrm)) );
sewardjcaca9d02004-07-28 07:11:32 +00002650 break;
sewardj68511542004-07-28 00:15:44 +00002651 case 6: /* DIV */
2652 delta++;
2653 assign( t1, getIReg(sz, eregOfRM(modrm)) );
2654 codegen_div ( sz, t1, False );
2655 DIP("div%c %s\n", nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
2656 break;
sewardjcaca9d02004-07-28 07:11:32 +00002657 case 7: /* IDIV */
2658 delta++;
2659 assign( t1, getIReg(sz, eregOfRM(modrm)) );
2660 codegen_div ( sz, t1, True );
2661 DIP("idiv%c %s\n", nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
2662 break;
sewardj940e8c92004-07-11 16:53:24 +00002663 default:
sewardjd51dc812007-03-20 14:18:45 +00002664 /* This can't happen - gregOfRM should return 0 .. 7 only */
sewardj940e8c92004-07-11 16:53:24 +00002665 vpanic("Grp3(x86)");
2666 }
2667 } else {
sewardjc2ac51e2004-07-12 01:03:26 +00002668 addr = disAMode ( &len, sorb, delta, dis_buf );
2669 t1 = newTemp(ty);
2670 delta += len;
2671 assign(t1, loadLE(ty,mkexpr(addr)));
2672 switch (gregOfRM(modrm)) {
2673 case 0: { /* TEST */
2674 d32 = getUDisp(sz, delta); delta += sz;
sewardj5bd4d162004-11-10 13:02:48 +00002675 dst1 = newTemp(ty);
2676 assign(dst1, binop(mkSizedOp(ty,Iop_And8),
2677 mkexpr(t1), mkU(ty,d32)));
2678 setFlags_DEP1( Iop_And8, dst1, ty );
sewardjc2ac51e2004-07-12 01:03:26 +00002679 DIP("test%c $0x%x, %s\n", nameISize(sz), d32, dis_buf);
2680 break;
2681 }
sewardjd51dc812007-03-20 14:18:45 +00002682 case 1: /* UNDEFINED */
2683 /* See comment above on R case */
2684 *decode_OK = False;
2685 break;
sewardj78fe7912004-08-20 23:38:07 +00002686 case 2: /* NOT */
2687 storeLE( mkexpr(addr), unop(mkSizedOp(ty,Iop_Not8), mkexpr(t1)));
2688 DIP("not%c %s\n", nameISize(sz), dis_buf);
2689 break;
sewardj0c12ea82004-07-12 08:18:16 +00002690 case 3: /* NEG */
2691 dst0 = newTemp(ty);
2692 src = newTemp(ty);
2693 dst1 = newTemp(ty);
sewardj5bd4d162004-11-10 13:02:48 +00002694 assign(dst0, mkU(ty,0));
sewardja511afc2004-07-29 22:26:03 +00002695 assign(src, mkexpr(t1));
sewardjeb17e492007-08-25 23:07:44 +00002696 assign(dst1, binop(mkSizedOp(ty,Iop_Sub8), mkexpr(dst0), mkexpr(src)));
sewardj2a2ba8b2004-11-08 13:14:06 +00002697 setFlags_DEP1_DEP2(Iop_Sub8, dst0, src, ty);
sewardj5bd4d162004-11-10 13:02:48 +00002698 storeLE( mkexpr(addr), mkexpr(dst1) );
sewardj0c12ea82004-07-12 08:18:16 +00002699 DIP("neg%c %s\n", nameISize(sz), dis_buf);
2700 break;
sewardj1813dbe2004-07-28 17:09:04 +00002701 case 4: /* MUL */
2702 codegen_mulL_A_D ( sz, False, t1, dis_buf );
2703 break;
2704 case 5: /* IMUL */
2705 codegen_mulL_A_D ( sz, True, t1, dis_buf );
2706 break;
sewardj9690d922004-07-14 01:39:17 +00002707 case 6: /* DIV */
2708 codegen_div ( sz, t1, False );
2709 DIP("div%c %s\n", nameISize(sz), dis_buf);
2710 break;
sewardj1813dbe2004-07-28 17:09:04 +00002711 case 7: /* IDIV */
2712 codegen_div ( sz, t1, True );
2713 DIP("idiv%c %s\n", nameISize(sz), dis_buf);
2714 break;
sewardjc2ac51e2004-07-12 01:03:26 +00002715 default:
sewardjd51dc812007-03-20 14:18:45 +00002716 /* This can't happen - gregOfRM should return 0 .. 7 only */
sewardjc2ac51e2004-07-12 01:03:26 +00002717 vpanic("Grp3(x86)");
2718 }
sewardj940e8c92004-07-11 16:53:24 +00002719 }
2720 return delta;
2721}
2722
2723
sewardjc2ac51e2004-07-12 01:03:26 +00002724/* Group 4 extended opcodes. */
2725static
sewardjd51dc812007-03-20 14:18:45 +00002726UInt dis_Grp4 ( UChar sorb, Int delta, Bool* decode_OK )
sewardjc2ac51e2004-07-12 01:03:26 +00002727{
sewardjc9a43662004-11-30 18:51:59 +00002728 Int alen;
sewardjc2ac51e2004-07-12 01:03:26 +00002729 UChar modrm;
sewardjc9a43662004-11-30 18:51:59 +00002730 HChar dis_buf[50];
sewardjc2ac51e2004-07-12 01:03:26 +00002731 IRType ty = Ity_I8;
sewardj7ed22952004-07-29 00:09:58 +00002732 IRTemp t1 = newTemp(ty);
2733 IRTemp t2 = newTemp(ty);
sewardjc2ac51e2004-07-12 01:03:26 +00002734
sewardjd51dc812007-03-20 14:18:45 +00002735 *decode_OK = True;
2736
sewardjc2ac51e2004-07-12 01:03:26 +00002737 modrm = getIByte(delta);
2738 if (epartIsReg(modrm)) {
sewardjc2ac51e2004-07-12 01:03:26 +00002739 assign(t1, getIReg(1, eregOfRM(modrm)));
2740 switch (gregOfRM(modrm)) {
sewardj7ed22952004-07-29 00:09:58 +00002741 case 0: /* INC */
2742 assign(t2, binop(Iop_Add8, mkexpr(t1), mkU8(1)));
2743 putIReg(1, eregOfRM(modrm), mkexpr(t2));
2744 setFlags_INC_DEC( True, t2, ty );
2745 break;
sewardjc2ac51e2004-07-12 01:03:26 +00002746 case 1: /* DEC */
sewardjc2ac51e2004-07-12 01:03:26 +00002747 assign(t2, binop(Iop_Sub8, mkexpr(t1), mkU8(1)));
2748 putIReg(1, eregOfRM(modrm), mkexpr(t2));
2749 setFlags_INC_DEC( False, t2, ty );
2750 break;
2751 default:
sewardjd51dc812007-03-20 14:18:45 +00002752 *decode_OK = False;
2753 return delta;
sewardjc2ac51e2004-07-12 01:03:26 +00002754 }
2755 delta++;
2756 DIP("%sb %s\n", nameGrp4(gregOfRM(modrm)),
2757 nameIReg(1, eregOfRM(modrm)));
2758 } else {
sewardj7ed22952004-07-29 00:09:58 +00002759 IRTemp addr = disAMode ( &alen, sorb, delta, dis_buf );
2760 assign( t1, loadLE(ty, mkexpr(addr)) );
2761 switch (gregOfRM(modrm)) {
sewardj588ea762004-09-10 18:56:32 +00002762 case 0: /* INC */
2763 assign(t2, binop(Iop_Add8, mkexpr(t1), mkU8(1)));
2764 storeLE( mkexpr(addr), mkexpr(t2) );
2765 setFlags_INC_DEC( True, t2, ty );
2766 break;
sewardj7ed22952004-07-29 00:09:58 +00002767 case 1: /* DEC */
2768 assign(t2, binop(Iop_Sub8, mkexpr(t1), mkU8(1)));
2769 storeLE( mkexpr(addr), mkexpr(t2) );
2770 setFlags_INC_DEC( False, t2, ty );
2771 break;
2772 default:
sewardjd51dc812007-03-20 14:18:45 +00002773 *decode_OK = False;
2774 return delta;
sewardj7ed22952004-07-29 00:09:58 +00002775 }
2776 delta += alen;
2777 DIP("%sb %s\n", nameGrp4(gregOfRM(modrm)), dis_buf);
sewardjc2ac51e2004-07-12 01:03:26 +00002778 }
2779 return delta;
2780}
sewardj0611d802004-07-11 02:37:54 +00002781
2782
2783/* Group 5 extended opcodes. */
2784static
sewardjd51dc812007-03-20 14:18:45 +00002785UInt dis_Grp5 ( UChar sorb, Int sz, Int delta,
2786 DisResult* dres, Bool* decode_OK )
sewardj0611d802004-07-11 02:37:54 +00002787{
2788 Int len;
2789 UChar modrm;
sewardjc9a43662004-11-30 18:51:59 +00002790 HChar dis_buf[50];
sewardj92d168d2004-11-15 14:22:12 +00002791 IRTemp addr = IRTemp_INVALID;
sewardj0611d802004-07-11 02:37:54 +00002792 IRType ty = szToITy(sz);
2793 IRTemp t1 = newTemp(ty);
sewardj92d168d2004-11-15 14:22:12 +00002794 IRTemp t2 = IRTemp_INVALID;
sewardj0611d802004-07-11 02:37:54 +00002795
sewardjd51dc812007-03-20 14:18:45 +00002796 *decode_OK = True;
2797
sewardj0611d802004-07-11 02:37:54 +00002798 modrm = getIByte(delta);
2799 if (epartIsReg(modrm)) {
sewardj940e8c92004-07-11 16:53:24 +00002800 assign(t1, getIReg(sz,eregOfRM(modrm)));
sewardj0611d802004-07-11 02:37:54 +00002801 switch (gregOfRM(modrm)) {
sewardj59ff5d42005-10-05 10:39:58 +00002802 case 0: /* INC */
2803 vassert(sz == 2 || sz == 4);
2804 t2 = newTemp(ty);
2805 assign(t2, binop(mkSizedOp(ty,Iop_Add8),
2806 mkexpr(t1), mkU(ty,1)));
2807 setFlags_INC_DEC( True, t2, ty );
2808 putIReg(sz,eregOfRM(modrm),mkexpr(t2));
2809 break;
2810 case 1: /* DEC */
2811 vassert(sz == 2 || sz == 4);
2812 t2 = newTemp(ty);
2813 assign(t2, binop(mkSizedOp(ty,Iop_Sub8),
2814 mkexpr(t1), mkU(ty,1)));
2815 setFlags_INC_DEC( False, t2, ty );
2816 putIReg(sz,eregOfRM(modrm),mkexpr(t2));
2817 break;
sewardjc2ac51e2004-07-12 01:03:26 +00002818 case 2: /* call Ev */
2819 vassert(sz == 4);
2820 t2 = newTemp(Ity_I32);
2821 assign(t2, binop(Iop_Sub32, getIReg(4,R_ESP), mkU32(4)));
2822 putIReg(4, R_ESP, mkexpr(t2));
sewardj9e6491a2005-07-02 19:24:10 +00002823 storeLE( mkexpr(t2), mkU32(guest_EIP_bbstart+delta+1));
sewardj5bd4d162004-11-10 13:02:48 +00002824 jmp_treg(Ijk_Call,t1);
sewardj9e6491a2005-07-02 19:24:10 +00002825 dres->whatNext = Dis_StopHere;
sewardjc2ac51e2004-07-12 01:03:26 +00002826 break;
sewardj0611d802004-07-11 02:37:54 +00002827 case 4: /* jmp Ev */
2828 vassert(sz == 4);
sewardj78c19df2004-07-12 22:49:27 +00002829 jmp_treg(Ijk_Boring,t1);
sewardj9e6491a2005-07-02 19:24:10 +00002830 dres->whatNext = Dis_StopHere;
sewardj0611d802004-07-11 02:37:54 +00002831 break;
sewardj28905822006-11-18 22:56:46 +00002832 case 6: /* PUSH Ev */
2833 vassert(sz == 4 || sz == 2);
2834 t2 = newTemp(Ity_I32);
2835 assign( t2, binop(Iop_Sub32,getIReg(4,R_ESP),mkU32(sz)) );
2836 putIReg(4, R_ESP, mkexpr(t2) );
2837 storeLE( mkexpr(t2), mkexpr(t1) );
2838 break;
sewardj0611d802004-07-11 02:37:54 +00002839 default:
sewardjd51dc812007-03-20 14:18:45 +00002840 *decode_OK = False;
2841 return delta;
sewardj0611d802004-07-11 02:37:54 +00002842 }
2843 delta++;
2844 DIP("%s%c %s\n", nameGrp5(gregOfRM(modrm)),
2845 nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
2846 } else {
2847 addr = disAMode ( &len, sorb, delta, dis_buf );
sewardj940e8c92004-07-11 16:53:24 +00002848 assign(t1, loadLE(ty,mkexpr(addr)));
sewardj0611d802004-07-11 02:37:54 +00002849 switch (gregOfRM(modrm)) {
2850 case 0: /* INC */
2851 t2 = newTemp(ty);
2852 assign(t2, binop(mkSizedOp(ty,Iop_Add8),
2853 mkexpr(t1), mkU(ty,1)));
2854 setFlags_INC_DEC( True, t2, ty );
sewardj940e8c92004-07-11 16:53:24 +00002855 storeLE(mkexpr(addr),mkexpr(t2));
sewardj0611d802004-07-11 02:37:54 +00002856 break;
sewardjc2ac51e2004-07-12 01:03:26 +00002857 case 1: /* DEC */
2858 t2 = newTemp(ty);
2859 assign(t2, binop(mkSizedOp(ty,Iop_Sub8),
2860 mkexpr(t1), mkU(ty,1)));
2861 setFlags_INC_DEC( False, t2, ty );
2862 storeLE(mkexpr(addr),mkexpr(t2));
2863 break;
sewardj77b86be2004-07-11 13:28:24 +00002864 case 2: /* call Ev */
2865 vassert(sz == 4);
2866 t2 = newTemp(Ity_I32);
2867 assign(t2, binop(Iop_Sub32, getIReg(4,R_ESP), mkU32(4)));
2868 putIReg(4, R_ESP, mkexpr(t2));
sewardj9e6491a2005-07-02 19:24:10 +00002869 storeLE( mkexpr(t2), mkU32(guest_EIP_bbstart+delta+len));
sewardj5bd4d162004-11-10 13:02:48 +00002870 jmp_treg(Ijk_Call,t1);
sewardj9e6491a2005-07-02 19:24:10 +00002871 dres->whatNext = Dis_StopHere;
sewardj77b86be2004-07-11 13:28:24 +00002872 break;
2873 case 4: /* JMP Ev */
2874 vassert(sz == 4);
sewardj78c19df2004-07-12 22:49:27 +00002875 jmp_treg(Ijk_Boring,t1);
sewardj9e6491a2005-07-02 19:24:10 +00002876 dres->whatNext = Dis_StopHere;
sewardj77b86be2004-07-11 13:28:24 +00002877 break;
sewardj0c12ea82004-07-12 08:18:16 +00002878 case 6: /* PUSH Ev */
2879 vassert(sz == 4 || sz == 2);
2880 t2 = newTemp(Ity_I32);
2881 assign( t2, binop(Iop_Sub32,getIReg(4,R_ESP),mkU32(sz)) );
2882 putIReg(4, R_ESP, mkexpr(t2) );
sewardj5bd4d162004-11-10 13:02:48 +00002883 storeLE( mkexpr(t2), mkexpr(t1) );
sewardj0c12ea82004-07-12 08:18:16 +00002884 break;
sewardj0611d802004-07-11 02:37:54 +00002885 default:
sewardjd51dc812007-03-20 14:18:45 +00002886 *decode_OK = False;
2887 return delta;
sewardj0611d802004-07-11 02:37:54 +00002888 }
2889 delta += len;
2890 DIP("%s%c %s\n", nameGrp5(gregOfRM(modrm)),
2891 nameISize(sz), dis_buf);
2892 }
2893 return delta;
2894}
2895
sewardj464efa42004-11-19 22:17:29 +00002896
sewardj64e1d652004-07-12 14:00:46 +00002897/*------------------------------------------------------------*/
2898/*--- Disassembling string ops (including REP prefixes) ---*/
2899/*------------------------------------------------------------*/
2900
2901/* Code shared by all the string ops */
2902static
2903void dis_string_op_increment(Int sz, Int t_inc)
2904{
2905 if (sz == 4 || sz == 2) {
2906 assign( t_inc,
2907 binop(Iop_Shl32, IRExpr_Get( OFFB_DFLAG, Ity_I32 ),
sewardj6d2638e2004-07-15 09:38:27 +00002908 mkU8(sz/2) ) );
sewardj64e1d652004-07-12 14:00:46 +00002909 } else {
2910 assign( t_inc,
2911 IRExpr_Get( OFFB_DFLAG, Ity_I32 ) );
2912 }
2913}
2914
sewardj64e1d652004-07-12 14:00:46 +00002915static
2916void dis_string_op( void (*dis_OP)( Int, IRTemp ),
sewardj2d49b432005-02-01 00:37:06 +00002917 Int sz, HChar* name, UChar sorb )
sewardj64e1d652004-07-12 14:00:46 +00002918{
2919 IRTemp t_inc = newTemp(Ity_I32);
sewardj9c3b25a2007-04-05 15:06:56 +00002920 vassert(sorb == 0); /* hmm. so what was the point of passing it in? */
sewardj64e1d652004-07-12 14:00:46 +00002921 dis_string_op_increment(sz, t_inc);
2922 dis_OP( sz, t_inc );
2923 DIP("%s%c\n", name, nameISize(sz));
2924}
sewardj64e1d652004-07-12 14:00:46 +00002925
2926static
2927void dis_MOVS ( Int sz, IRTemp t_inc )
2928{
2929 IRType ty = szToITy(sz);
sewardj64e1d652004-07-12 14:00:46 +00002930 IRTemp td = newTemp(Ity_I32); /* EDI */
2931 IRTemp ts = newTemp(Ity_I32); /* ESI */
2932
sewardj64e1d652004-07-12 14:00:46 +00002933 assign( td, getIReg(4, R_EDI) );
2934 assign( ts, getIReg(4, R_ESI) );
2935
sewardj64e1d652004-07-12 14:00:46 +00002936 storeLE( mkexpr(td), loadLE(ty,mkexpr(ts)) );
2937
sewardj64e1d652004-07-12 14:00:46 +00002938 putIReg( 4, R_EDI, binop(Iop_Add32, mkexpr(td), mkexpr(t_inc)) );
2939 putIReg( 4, R_ESI, binop(Iop_Add32, mkexpr(ts), mkexpr(t_inc)) );
2940}
2941
sewardj10ca4eb2005-05-30 11:19:54 +00002942static
2943void dis_LODS ( Int sz, IRTemp t_inc )
2944{
2945 IRType ty = szToITy(sz);
2946 IRTemp ts = newTemp(Ity_I32); /* ESI */
2947
2948 assign( ts, getIReg(4, R_ESI) );
2949
2950 putIReg( sz, R_EAX, loadLE(ty, mkexpr(ts)) );
2951
2952 putIReg( 4, R_ESI, binop(Iop_Add32, mkexpr(ts), mkexpr(t_inc)) );
2953}
sewardj64e1d652004-07-12 14:00:46 +00002954
2955static
2956void dis_STOS ( Int sz, IRTemp t_inc )
2957{
2958 IRType ty = szToITy(sz);
2959 IRTemp ta = newTemp(ty); /* EAX */
2960 IRTemp td = newTemp(Ity_I32); /* EDI */
2961
sewardj64e1d652004-07-12 14:00:46 +00002962 assign( ta, getIReg(sz, R_EAX) );
sewardj64e1d652004-07-12 14:00:46 +00002963 assign( td, getIReg(4, R_EDI) );
2964
sewardj6d2638e2004-07-15 09:38:27 +00002965 storeLE( mkexpr(td), mkexpr(ta) );
sewardj64e1d652004-07-12 14:00:46 +00002966
sewardj64e1d652004-07-12 14:00:46 +00002967 putIReg( 4, R_EDI, binop(Iop_Add32, mkexpr(td), mkexpr(t_inc)) );
2968}
2969
2970static
2971void dis_CMPS ( Int sz, IRTemp t_inc )
2972{
2973 IRType ty = szToITy(sz);
sewardj6d2638e2004-07-15 09:38:27 +00002974 IRTemp tdv = newTemp(ty); /* (EDI) */
2975 IRTemp tsv = newTemp(ty); /* (ESI) */
sewardj64e1d652004-07-12 14:00:46 +00002976 IRTemp td = newTemp(Ity_I32); /* EDI */
2977 IRTemp ts = newTemp(Ity_I32); /* ESI */
2978
sewardj64e1d652004-07-12 14:00:46 +00002979 assign( td, getIReg(4, R_EDI) );
sewardj64e1d652004-07-12 14:00:46 +00002980 assign( ts, getIReg(4, R_ESI) );
2981
sewardj64e1d652004-07-12 14:00:46 +00002982 assign( tdv, loadLE(ty,mkexpr(td)) );
sewardjb9c5cf62004-08-24 15:10:38 +00002983 assign( tsv, loadLE(ty,mkexpr(ts)) );
sewardj64e1d652004-07-12 14:00:46 +00002984
sewardj2a2ba8b2004-11-08 13:14:06 +00002985 setFlags_DEP1_DEP2 ( Iop_Sub8, tsv, tdv, ty );
sewardj64e1d652004-07-12 14:00:46 +00002986
sewardj64e1d652004-07-12 14:00:46 +00002987 putIReg(4, R_EDI, binop(Iop_Add32, mkexpr(td), mkexpr(t_inc)) );
sewardj64e1d652004-07-12 14:00:46 +00002988 putIReg(4, R_ESI, binop(Iop_Add32, mkexpr(ts), mkexpr(t_inc)) );
2989}
2990
sewardj64e1d652004-07-12 14:00:46 +00002991static
2992void dis_SCAS ( Int sz, IRTemp t_inc )
2993{
2994 IRType ty = szToITy(sz);
sewardj82292882004-07-27 00:15:59 +00002995 IRTemp ta = newTemp(ty); /* EAX */
sewardj64e1d652004-07-12 14:00:46 +00002996 IRTemp td = newTemp(Ity_I32); /* EDI */
2997 IRTemp tdv = newTemp(ty); /* (EDI) */
2998
sewardjb9c5cf62004-08-24 15:10:38 +00002999 assign( ta, getIReg(sz, R_EAX) );
sewardj64e1d652004-07-12 14:00:46 +00003000 assign( td, getIReg(4, R_EDI) );
3001
sewardj64e1d652004-07-12 14:00:46 +00003002 assign( tdv, loadLE(ty,mkexpr(td)) );
sewardj2a2ba8b2004-11-08 13:14:06 +00003003 setFlags_DEP1_DEP2 ( Iop_Sub8, ta, tdv, ty );
sewardj64e1d652004-07-12 14:00:46 +00003004
sewardj64e1d652004-07-12 14:00:46 +00003005 putIReg(4, R_EDI, binop(Iop_Add32, mkexpr(td), mkexpr(t_inc)) );
3006}
sewardj82292882004-07-27 00:15:59 +00003007
sewardj64e1d652004-07-12 14:00:46 +00003008
3009/* Wrap the appropriate string op inside a REP/REPE/REPNE.
3010 We assume the insn is the last one in the basic block, and so emit a jump
3011 to the next insn, rather than just falling through. */
3012static
sewardj2a9ad022004-11-25 02:46:58 +00003013void dis_REP_op ( X86Condcode cond,
sewardj64e1d652004-07-12 14:00:46 +00003014 void (*dis_OP)(Int, IRTemp),
sewardj2d49b432005-02-01 00:37:06 +00003015 Int sz, Addr32 eip, Addr32 eip_next, HChar* name )
sewardj64e1d652004-07-12 14:00:46 +00003016{
3017 IRTemp t_inc = newTemp(Ity_I32);
3018 IRTemp tc = newTemp(Ity_I32); /* ECX */
3019
sewardj64e1d652004-07-12 14:00:46 +00003020 assign( tc, getIReg(4,R_ECX) );
3021
sewardj64e1d652004-07-12 14:00:46 +00003022 stmt( IRStmt_Exit( binop(Iop_CmpEQ32,mkexpr(tc),mkU32(0)),
sewardj893aada2004-11-29 19:57:54 +00003023 Ijk_Boring,
sewardj64e1d652004-07-12 14:00:46 +00003024 IRConst_U32(eip_next) ) );
3025
sewardj64e1d652004-07-12 14:00:46 +00003026 putIReg(4, R_ECX, binop(Iop_Sub32, mkexpr(tc), mkU32(1)) );
3027
3028 dis_string_op_increment(sz, t_inc);
3029 dis_OP (sz, t_inc);
3030
sewardj2a9ad022004-11-25 02:46:58 +00003031 if (cond == X86CondAlways) {
sewardj78c19df2004-07-12 22:49:27 +00003032 jmp_lit(Ijk_Boring,eip);
sewardj64e1d652004-07-12 14:00:46 +00003033 } else {
sewardj2a9ad022004-11-25 02:46:58 +00003034 stmt( IRStmt_Exit( mk_x86g_calculate_condition(cond),
sewardj893aada2004-11-29 19:57:54 +00003035 Ijk_Boring,
sewardj5bd4d162004-11-10 13:02:48 +00003036 IRConst_U32(eip) ) );
sewardj78c19df2004-07-12 22:49:27 +00003037 jmp_lit(Ijk_Boring,eip_next);
sewardj64e1d652004-07-12 14:00:46 +00003038 }
3039 DIP("%s%c\n", name, nameISize(sz));
3040}
3041
sewardj464efa42004-11-19 22:17:29 +00003042
sewardj64e1d652004-07-12 14:00:46 +00003043/*------------------------------------------------------------*/
3044/*--- Arithmetic, etc. ---*/
3045/*------------------------------------------------------------*/
3046
sewardj2a2ba8b2004-11-08 13:14:06 +00003047/* IMUL E, G. Supplied eip points to the modR/M byte. */
sewardjcf780b42004-07-13 18:42:17 +00003048static
3049UInt dis_mul_E_G ( UChar sorb,
3050 Int size,
sewardj52d04912005-07-03 00:52:48 +00003051 Int delta0 )
sewardjcf780b42004-07-13 18:42:17 +00003052{
sewardj71a65362004-07-28 01:48:34 +00003053 Int alen;
sewardjc9a43662004-11-30 18:51:59 +00003054 HChar dis_buf[50];
sewardjcf780b42004-07-13 18:42:17 +00003055 UChar rm = getIByte(delta0);
3056 IRType ty = szToITy(size);
sewardj6d2638e2004-07-15 09:38:27 +00003057 IRTemp te = newTemp(ty);
3058 IRTemp tg = newTemp(ty);
sewardj948d48b2004-11-05 19:49:09 +00003059 IRTemp resLo = newTemp(ty);
sewardj71a65362004-07-28 01:48:34 +00003060
sewardj948d48b2004-11-05 19:49:09 +00003061 assign( tg, getIReg(size, gregOfRM(rm)) );
sewardjcf780b42004-07-13 18:42:17 +00003062 if (epartIsReg(rm)) {
sewardjcf780b42004-07-13 18:42:17 +00003063 assign( te, getIReg(size, eregOfRM(rm)) );
sewardj948d48b2004-11-05 19:49:09 +00003064 } else {
3065 IRTemp addr = disAMode( &alen, sorb, delta0, dis_buf );
3066 assign( te, loadLE(ty,mkexpr(addr)) );
3067 }
sewardjcf780b42004-07-13 18:42:17 +00003068
sewardj2a9ad022004-11-25 02:46:58 +00003069 setFlags_MUL ( ty, te, tg, X86G_CC_OP_SMULB );
sewardj948d48b2004-11-05 19:49:09 +00003070
sewardj2a2ba8b2004-11-08 13:14:06 +00003071 assign( resLo, binop( mkSizedOp(ty, Iop_Mul8), mkexpr(te), mkexpr(tg) ) );
sewardj948d48b2004-11-05 19:49:09 +00003072
3073 putIReg(size, gregOfRM(rm), mkexpr(resLo) );
3074
3075 if (epartIsReg(rm)) {
sewardj2a2ba8b2004-11-08 13:14:06 +00003076 DIP("imul%c %s, %s\n", nameISize(size),
3077 nameIReg(size,eregOfRM(rm)),
3078 nameIReg(size,gregOfRM(rm)));
sewardjcf780b42004-07-13 18:42:17 +00003079 return 1+delta0;
3080 } else {
sewardj2a2ba8b2004-11-08 13:14:06 +00003081 DIP("imul%c %s, %s\n", nameISize(size),
3082 dis_buf, nameIReg(size,gregOfRM(rm)));
sewardj71a65362004-07-28 01:48:34 +00003083 return alen+delta0;
sewardjcf780b42004-07-13 18:42:17 +00003084 }
3085}
3086
3087
sewardj1813dbe2004-07-28 17:09:04 +00003088/* IMUL I * E -> G. Supplied eip points to the modR/M byte. */
3089static
3090UInt dis_imul_I_E_G ( UChar sorb,
3091 Int size,
sewardj52d04912005-07-03 00:52:48 +00003092 Int delta,
sewardj1813dbe2004-07-28 17:09:04 +00003093 Int litsize )
3094{
sewardj883b00b2004-09-11 09:30:24 +00003095 Int d32, alen;
sewardjc9a43662004-11-30 18:51:59 +00003096 HChar dis_buf[50];
sewardjb81f8b32004-07-30 10:17:50 +00003097 UChar rm = getIByte(delta);
sewardj1813dbe2004-07-28 17:09:04 +00003098 IRType ty = szToITy(size);
3099 IRTemp te = newTemp(ty);
3100 IRTemp tl = newTemp(ty);
sewardj948d48b2004-11-05 19:49:09 +00003101 IRTemp resLo = newTemp(ty);
sewardj1813dbe2004-07-28 17:09:04 +00003102
sewardjb81f8b32004-07-30 10:17:50 +00003103 vassert(size == 1 || size == 2 || size == 4);
3104
sewardj1813dbe2004-07-28 17:09:04 +00003105 if (epartIsReg(rm)) {
3106 assign(te, getIReg(size, eregOfRM(rm)));
3107 delta++;
3108 } else {
sewardj883b00b2004-09-11 09:30:24 +00003109 IRTemp addr = disAMode( &alen, sorb, delta, dis_buf );
3110 assign(te, loadLE(ty, mkexpr(addr)));
3111 delta += alen;
sewardj1813dbe2004-07-28 17:09:04 +00003112 }
3113 d32 = getSDisp(litsize,delta);
3114 delta += litsize;
3115
sewardjb81f8b32004-07-30 10:17:50 +00003116 if (size == 1) d32 &= 0xFF;
3117 if (size == 2) d32 &= 0xFFFF;
3118
sewardj1813dbe2004-07-28 17:09:04 +00003119 assign(tl, mkU(ty,d32));
sewardj948d48b2004-11-05 19:49:09 +00003120
sewardj2a2ba8b2004-11-08 13:14:06 +00003121 assign( resLo, binop( mkSizedOp(ty, Iop_Mul8), mkexpr(te), mkexpr(tl) ));
sewardj948d48b2004-11-05 19:49:09 +00003122
sewardj2a9ad022004-11-25 02:46:58 +00003123 setFlags_MUL ( ty, te, tl, X86G_CC_OP_SMULB );
sewardj948d48b2004-11-05 19:49:09 +00003124
3125 putIReg(size, gregOfRM(rm), mkexpr(resLo));
sewardj1813dbe2004-07-28 17:09:04 +00003126
3127 DIP("imul %d, %s, %s\n", d32,
3128 ( epartIsReg(rm) ? nameIReg(size,eregOfRM(rm)) : dis_buf ),
3129 nameIReg(size,gregOfRM(rm)) );
3130 return delta;
sewardj948d48b2004-11-05 19:49:09 +00003131}
sewardj1813dbe2004-07-28 17:09:04 +00003132
3133
sewardjd1725d12004-08-12 20:46:53 +00003134/*------------------------------------------------------------*/
sewardj464efa42004-11-19 22:17:29 +00003135/*--- ---*/
3136/*--- x87 FLOATING POINT INSTRUCTIONS ---*/
3137/*--- ---*/
sewardjd1725d12004-08-12 20:46:53 +00003138/*------------------------------------------------------------*/
3139
sewardj207557a2004-08-27 12:00:18 +00003140/* --- Helper functions for dealing with the register stack. --- */
3141
sewardj893aada2004-11-29 19:57:54 +00003142/* --- Set the emulation-warning pseudo-register. --- */
3143
3144static void put_emwarn ( IRExpr* e /* :: Ity_I32 */ )
3145{
sewardjdd40fdf2006-12-24 02:20:24 +00003146 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I32);
sewardj893aada2004-11-29 19:57:54 +00003147 stmt( IRStmt_Put( OFFB_EMWARN, e ) );
3148}
3149
sewardj17442fe2004-09-20 14:54:28 +00003150/* --- Produce an IRExpr* denoting a 64-bit QNaN. --- */
sewardj207557a2004-08-27 12:00:18 +00003151
sewardj17442fe2004-09-20 14:54:28 +00003152static IRExpr* mkQNaN64 ( void )
sewardj207557a2004-08-27 12:00:18 +00003153{
sewardj17442fe2004-09-20 14:54:28 +00003154 /* QNaN is 0 2047 1 0(51times)
3155 == 0b 11111111111b 1 0(51times)
3156 == 0x7FF8 0000 0000 0000
3157 */
3158 return IRExpr_Const(IRConst_F64i(0x7FF8000000000000ULL));
sewardj207557a2004-08-27 12:00:18 +00003159}
3160
sewardj893aada2004-11-29 19:57:54 +00003161/* --------- Get/put the top-of-stack pointer. --------- */
sewardjd1725d12004-08-12 20:46:53 +00003162
3163static IRExpr* get_ftop ( void )
3164{
3165 return IRExpr_Get( OFFB_FTOP, Ity_I32 );
3166}
3167
sewardj207557a2004-08-27 12:00:18 +00003168static void put_ftop ( IRExpr* e )
sewardjd1725d12004-08-12 20:46:53 +00003169{
sewardjdd40fdf2006-12-24 02:20:24 +00003170 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I32);
sewardj207557a2004-08-27 12:00:18 +00003171 stmt( IRStmt_Put( OFFB_FTOP, e ) );
sewardjd1725d12004-08-12 20:46:53 +00003172}
3173
sewardj893aada2004-11-29 19:57:54 +00003174/* --------- Get/put the C3210 bits. --------- */
sewardjbdc7d212004-09-09 02:46:40 +00003175
sewardjc4be80c2004-09-10 16:17:45 +00003176static IRExpr* get_C3210 ( void )
sewardjbdc7d212004-09-09 02:46:40 +00003177{
sewardjc4be80c2004-09-10 16:17:45 +00003178 return IRExpr_Get( OFFB_FC3210, Ity_I32 );
sewardjbdc7d212004-09-09 02:46:40 +00003179}
3180
sewardjc4be80c2004-09-10 16:17:45 +00003181static void put_C3210 ( IRExpr* e )
sewardjbdc7d212004-09-09 02:46:40 +00003182{
sewardjc4be80c2004-09-10 16:17:45 +00003183 stmt( IRStmt_Put( OFFB_FC3210, e ) );
sewardjbdc7d212004-09-09 02:46:40 +00003184}
sewardjd1725d12004-08-12 20:46:53 +00003185
sewardj893aada2004-11-29 19:57:54 +00003186/* --------- Get/put the FPU rounding mode. --------- */
sewardjd01a9632004-11-30 13:18:37 +00003187static IRExpr* /* :: Ity_I32 */ get_fpround ( void )
sewardj8f3debf2004-09-08 23:42:23 +00003188{
sewardjd01a9632004-11-30 13:18:37 +00003189 return IRExpr_Get( OFFB_FPROUND, Ity_I32 );
sewardj8f3debf2004-09-08 23:42:23 +00003190}
3191
sewardjd01a9632004-11-30 13:18:37 +00003192static void put_fpround ( IRExpr* /* :: Ity_I32 */ e )
sewardj8f3debf2004-09-08 23:42:23 +00003193{
sewardjd01a9632004-11-30 13:18:37 +00003194 stmt( IRStmt_Put( OFFB_FPROUND, e ) );
sewardj8f3debf2004-09-08 23:42:23 +00003195}
3196
3197
sewardj893aada2004-11-29 19:57:54 +00003198/* --------- Synthesise a 2-bit FPU rounding mode. --------- */
sewardj8f3debf2004-09-08 23:42:23 +00003199/* Produces a value in 0 .. 3, which is encoded as per the type
sewardjd01a9632004-11-30 13:18:37 +00003200 IRRoundingMode. Since the guest_FPROUND value is also encoded as
3201 per IRRoundingMode, we merely need to get it and mask it for
3202 safety.
sewardj8f3debf2004-09-08 23:42:23 +00003203*/
3204static IRExpr* /* :: Ity_I32 */ get_roundingmode ( void )
3205{
sewardjd01a9632004-11-30 13:18:37 +00003206 return binop( Iop_And32, get_fpround(), mkU32(3) );
sewardj8f3debf2004-09-08 23:42:23 +00003207}
3208
sewardjf1b5b1a2006-02-03 22:54:17 +00003209static IRExpr* /* :: Ity_I32 */ get_FAKE_roundingmode ( void )
3210{
3211 return mkU32(Irrm_NEAREST);
3212}
3213
sewardj8f3debf2004-09-08 23:42:23 +00003214
sewardj207557a2004-08-27 12:00:18 +00003215/* --------- Get/set FP register tag bytes. --------- */
3216
sewardj207557a2004-08-27 12:00:18 +00003217/* Given i, and some expression e, generate 'ST_TAG(i) = e'. */
3218
3219static void put_ST_TAG ( Int i, IRExpr* value )
3220{
sewardjdd40fdf2006-12-24 02:20:24 +00003221 IRRegArray* descr;
3222 vassert(typeOfIRExpr(irsb->tyenv, value) == Ity_I8);
3223 descr = mkIRRegArray( OFFB_FPTAGS, Ity_I8, 8 );
sewardj2d3f77c2004-09-22 23:49:09 +00003224 stmt( IRStmt_PutI( descr, get_ftop(), i, value ) );
sewardj207557a2004-08-27 12:00:18 +00003225}
3226
3227/* Given i, generate an expression yielding 'ST_TAG(i)'. This will be
sewardjdb199622004-09-06 23:19:03 +00003228 zero to indicate "Empty" and nonzero to indicate "NonEmpty". */
sewardj207557a2004-08-27 12:00:18 +00003229
3230static IRExpr* get_ST_TAG ( Int i )
3231{
sewardjdd40fdf2006-12-24 02:20:24 +00003232 IRRegArray* descr = mkIRRegArray( OFFB_FPTAGS, Ity_I8, 8 );
sewardj2d3f77c2004-09-22 23:49:09 +00003233 return IRExpr_GetI( descr, get_ftop(), i );
sewardj207557a2004-08-27 12:00:18 +00003234}
3235
3236
3237/* --------- Get/set FP registers. --------- */
3238
sewardj2d3f77c2004-09-22 23:49:09 +00003239/* Given i, and some expression e, emit 'ST(i) = e' and set the
3240 register's tag to indicate the register is full. The previous
3241 state of the register is not checked. */
sewardj207557a2004-08-27 12:00:18 +00003242
3243static void put_ST_UNCHECKED ( Int i, IRExpr* value )
sewardjd1725d12004-08-12 20:46:53 +00003244{
sewardjdd40fdf2006-12-24 02:20:24 +00003245 IRRegArray* descr;
3246 vassert(typeOfIRExpr(irsb->tyenv, value) == Ity_F64);
3247 descr = mkIRRegArray( OFFB_FPREGS, Ity_F64, 8 );
sewardj2d3f77c2004-09-22 23:49:09 +00003248 stmt( IRStmt_PutI( descr, get_ftop(), i, value ) );
sewardj207557a2004-08-27 12:00:18 +00003249 /* Mark the register as in-use. */
3250 put_ST_TAG(i, mkU8(1));
sewardjd1725d12004-08-12 20:46:53 +00003251}
3252
sewardj207557a2004-08-27 12:00:18 +00003253/* Given i, and some expression e, emit
3254 ST(i) = is_full(i) ? NaN : e
3255 and set the tag accordingly.
3256*/
3257
3258static void put_ST ( Int i, IRExpr* value )
3259{
3260 put_ST_UNCHECKED( i,
sewardjdb199622004-09-06 23:19:03 +00003261 IRExpr_Mux0X( get_ST_TAG(i),
3262 /* 0 means empty */
3263 value,
3264 /* non-0 means full */
sewardj17442fe2004-09-20 14:54:28 +00003265 mkQNaN64()
sewardj207557a2004-08-27 12:00:18 +00003266 )
3267 );
3268}
3269
3270
sewardjd1725d12004-08-12 20:46:53 +00003271/* Given i, generate an expression yielding 'ST(i)'. */
3272
sewardj207557a2004-08-27 12:00:18 +00003273static IRExpr* get_ST_UNCHECKED ( Int i )
sewardjd1725d12004-08-12 20:46:53 +00003274{
sewardjdd40fdf2006-12-24 02:20:24 +00003275 IRRegArray* descr = mkIRRegArray( OFFB_FPREGS, Ity_F64, 8 );
sewardj2d3f77c2004-09-22 23:49:09 +00003276 return IRExpr_GetI( descr, get_ftop(), i );
sewardjd1725d12004-08-12 20:46:53 +00003277}
3278
sewardjc4be80c2004-09-10 16:17:45 +00003279
sewardj207557a2004-08-27 12:00:18 +00003280/* Given i, generate an expression yielding
3281 is_full(i) ? ST(i) : NaN
3282*/
3283
3284static IRExpr* get_ST ( Int i )
3285{
3286 return
3287 IRExpr_Mux0X( get_ST_TAG(i),
3288 /* 0 means empty */
sewardj17442fe2004-09-20 14:54:28 +00003289 mkQNaN64(),
sewardj207557a2004-08-27 12:00:18 +00003290 /* non-0 means full */
3291 get_ST_UNCHECKED(i));
3292}
3293
3294
sewardjd1725d12004-08-12 20:46:53 +00003295/* Adjust FTOP downwards by one register. */
3296
sewardj207557a2004-08-27 12:00:18 +00003297static void fp_push ( void )
sewardjd1725d12004-08-12 20:46:53 +00003298{
sewardj2d3f77c2004-09-22 23:49:09 +00003299 put_ftop( binop(Iop_Sub32, get_ftop(), mkU32(1)) );
sewardjd1725d12004-08-12 20:46:53 +00003300}
3301
sewardj207557a2004-08-27 12:00:18 +00003302/* Adjust FTOP upwards by one register, and mark the vacated register
3303 as empty. */
sewardja58ea662004-08-15 03:12:41 +00003304
sewardj207557a2004-08-27 12:00:18 +00003305static void fp_pop ( void )
sewardja58ea662004-08-15 03:12:41 +00003306{
sewardjdb199622004-09-06 23:19:03 +00003307 put_ST_TAG(0, mkU8(0));
sewardj2d3f77c2004-09-22 23:49:09 +00003308 put_ftop( binop(Iop_Add32, get_ftop(), mkU32(1)) );
sewardja58ea662004-08-15 03:12:41 +00003309}
3310
sewardj3f61ddb2004-10-16 20:51:05 +00003311/* Clear the C2 bit of the FPU status register, for
3312 sin/cos/tan/sincos. */
3313
3314static void clear_C2 ( void )
3315{
sewardj67e002d2004-12-02 18:16:33 +00003316 put_C3210( binop(Iop_And32, get_C3210(), mkU32(~X86G_FC_MASK_C2)) );
sewardj3f61ddb2004-10-16 20:51:05 +00003317}
3318
sewardjd24931d2005-03-20 12:51:39 +00003319/* Invent a plausible-looking FPU status word value:
3320 ((ftop & 7) << 11) | (c3210 & 0x4700)
3321 */
3322static IRExpr* get_FPU_sw ( void )
3323{
3324 return
3325 unop(Iop_32to16,
3326 binop(Iop_Or32,
3327 binop(Iop_Shl32,
3328 binop(Iop_And32, get_ftop(), mkU32(7)),
3329 mkU8(11)),
3330 binop(Iop_And32, get_C3210(), mkU32(0x4700))
3331 ));
3332}
3333
sewardj3f61ddb2004-10-16 20:51:05 +00003334
sewardj207557a2004-08-27 12:00:18 +00003335/* ------------------------------------------------------- */
3336/* Given all that stack-mangling junk, we can now go ahead
3337 and describe FP instructions.
3338*/
3339
sewardj3fd5e572004-09-09 22:43:51 +00003340/* ST(0) = ST(0) `op` mem64/32(addr)
sewardj207557a2004-08-27 12:00:18 +00003341 Need to check ST(0)'s tag on read, but not on write.
3342*/
sewardja58ea662004-08-15 03:12:41 +00003343static
sewardj2d49b432005-02-01 00:37:06 +00003344void fp_do_op_mem_ST_0 ( IRTemp addr, HChar* op_txt, HChar* dis_buf,
sewardja58ea662004-08-15 03:12:41 +00003345 IROp op, Bool dbl )
3346{
sewardj33dd31b2005-01-08 18:17:32 +00003347 DIP("f%s%c %s\n", op_txt, dbl?'l':'s', dis_buf);
sewardja58ea662004-08-15 03:12:41 +00003348 if (dbl) {
sewardj3fd5e572004-09-09 22:43:51 +00003349 put_ST_UNCHECKED(0,
sewardjf1b5b1a2006-02-03 22:54:17 +00003350 triop( op,
3351 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardj3fd5e572004-09-09 22:43:51 +00003352 get_ST(0),
3353 loadLE(Ity_F64,mkexpr(addr))
3354 ));
sewardja58ea662004-08-15 03:12:41 +00003355 } else {
sewardj3fd5e572004-09-09 22:43:51 +00003356 put_ST_UNCHECKED(0,
sewardjf1b5b1a2006-02-03 22:54:17 +00003357 triop( op,
3358 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardj3fd5e572004-09-09 22:43:51 +00003359 get_ST(0),
3360 unop(Iop_F32toF64, loadLE(Ity_F32,mkexpr(addr)))
3361 ));
3362 }
3363}
3364
3365
3366/* ST(0) = mem64/32(addr) `op` ST(0)
3367 Need to check ST(0)'s tag on read, but not on write.
3368*/
3369static
sewardj2d49b432005-02-01 00:37:06 +00003370void fp_do_oprev_mem_ST_0 ( IRTemp addr, HChar* op_txt, HChar* dis_buf,
sewardj883b00b2004-09-11 09:30:24 +00003371 IROp op, Bool dbl )
sewardj3fd5e572004-09-09 22:43:51 +00003372{
sewardj33dd31b2005-01-08 18:17:32 +00003373 DIP("f%s%c %s\n", op_txt, dbl?'l':'s', dis_buf);
sewardj3fd5e572004-09-09 22:43:51 +00003374 if (dbl) {
3375 put_ST_UNCHECKED(0,
sewardjf1b5b1a2006-02-03 22:54:17 +00003376 triop( op,
3377 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardj3fd5e572004-09-09 22:43:51 +00003378 loadLE(Ity_F64,mkexpr(addr)),
3379 get_ST(0)
3380 ));
3381 } else {
3382 put_ST_UNCHECKED(0,
sewardjf1b5b1a2006-02-03 22:54:17 +00003383 triop( op,
3384 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardj3fd5e572004-09-09 22:43:51 +00003385 unop(Iop_F32toF64, loadLE(Ity_F32,mkexpr(addr))),
3386 get_ST(0)
3387 ));
sewardja58ea662004-08-15 03:12:41 +00003388 }
3389}
3390
sewardjd1725d12004-08-12 20:46:53 +00003391
sewardjdb199622004-09-06 23:19:03 +00003392/* ST(dst) = ST(dst) `op` ST(src).
3393 Check dst and src tags when reading but not on write.
3394*/
3395static
sewardj2d49b432005-02-01 00:37:06 +00003396void fp_do_op_ST_ST ( HChar* op_txt, IROp op, UInt st_src, UInt st_dst,
sewardjbdc7d212004-09-09 02:46:40 +00003397 Bool pop_after )
sewardjdb199622004-09-06 23:19:03 +00003398{
sewardj2d49b432005-02-01 00:37:06 +00003399 DIP("f%s%s st(%d), st(%d)\n", op_txt, pop_after?"p":"",
3400 (Int)st_src, (Int)st_dst );
sewardjdb199622004-09-06 23:19:03 +00003401 put_ST_UNCHECKED(
3402 st_dst,
sewardjf1b5b1a2006-02-03 22:54:17 +00003403 triop( op,
3404 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
3405 get_ST(st_dst),
3406 get_ST(st_src) )
sewardjdb199622004-09-06 23:19:03 +00003407 );
sewardjbdc7d212004-09-09 02:46:40 +00003408 if (pop_after)
3409 fp_pop();
3410}
3411
3412/* ST(dst) = ST(src) `op` ST(dst).
3413 Check dst and src tags when reading but not on write.
3414*/
3415static
sewardj2d49b432005-02-01 00:37:06 +00003416void fp_do_oprev_ST_ST ( HChar* op_txt, IROp op, UInt st_src, UInt st_dst,
sewardj883b00b2004-09-11 09:30:24 +00003417 Bool pop_after )
sewardjbdc7d212004-09-09 02:46:40 +00003418{
sewardj2d49b432005-02-01 00:37:06 +00003419 DIP("f%s%s st(%d), st(%d)\n", op_txt, pop_after?"p":"",
3420 (Int)st_src, (Int)st_dst );
sewardjbdc7d212004-09-09 02:46:40 +00003421 put_ST_UNCHECKED(
3422 st_dst,
sewardjf1b5b1a2006-02-03 22:54:17 +00003423 triop( op,
3424 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
3425 get_ST(st_src),
3426 get_ST(st_dst) )
sewardjbdc7d212004-09-09 02:46:40 +00003427 );
3428 if (pop_after)
3429 fp_pop();
sewardjdb199622004-09-06 23:19:03 +00003430}
3431
sewardj8308aad2004-09-12 11:09:54 +00003432/* %eflags(Z,P,C) = UCOMI( st(0), st(i) ) */
3433static void fp_do_ucomi_ST0_STi ( UInt i, Bool pop_after )
3434{
sewardj2d49b432005-02-01 00:37:06 +00003435 DIP("fucomi%s %%st(0),%%st(%d)\n", pop_after ? "p" : "", (Int)i );
sewardj8308aad2004-09-12 11:09:54 +00003436 /* This is a bit of a hack (and isn't really right). It sets
3437 Z,P,C,O correctly, but forces A and S to zero, whereas the Intel
3438 documentation implies A and S are unchanged.
3439 */
sewardjfeeb8a82004-11-30 12:30:11 +00003440 /* It's also fishy in that it is used both for COMIP and
3441 UCOMIP, and they aren't the same (although similar). */
sewardj2a9ad022004-11-25 02:46:58 +00003442 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
sewardj2a2ba8b2004-11-08 13:14:06 +00003443 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
3444 stmt( IRStmt_Put( OFFB_CC_DEP1,
sewardj8308aad2004-09-12 11:09:54 +00003445 binop( Iop_And32,
3446 binop(Iop_CmpF64, get_ST(0), get_ST(i)),
3447 mkU32(0x45)
3448 )));
sewardja3b7e3a2005-04-05 01:54:19 +00003449 /* Set NDEP even though it isn't used. This makes redundant-PUT
3450 elimination of previous stores to this field work better. */
3451 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardj8308aad2004-09-12 11:09:54 +00003452 if (pop_after)
3453 fp_pop();
3454}
3455
sewardjdb199622004-09-06 23:19:03 +00003456
sewardjd1725d12004-08-12 20:46:53 +00003457static
sewardj52d04912005-07-03 00:52:48 +00003458UInt dis_FPU ( Bool* decode_ok, UChar sorb, Int delta )
sewardjd1725d12004-08-12 20:46:53 +00003459{
sewardja58ea662004-08-15 03:12:41 +00003460 Int len;
3461 UInt r_src, r_dst;
sewardjc9a43662004-11-30 18:51:59 +00003462 HChar dis_buf[50];
sewardj89cd0932004-09-08 18:23:25 +00003463 IRTemp t1, t2;
sewardjd1725d12004-08-12 20:46:53 +00003464
3465 /* On entry, delta points at the second byte of the insn (the modrm
3466 byte).*/
3467 UChar first_opcode = getIByte(delta-1);
3468 UChar modrm = getIByte(delta+0);
3469
3470 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xD8 opcodes +-+-+-+-+-+-+-+ */
3471
3472 if (first_opcode == 0xD8) {
sewardjdb199622004-09-06 23:19:03 +00003473 if (modrm < 0xC0) {
sewardj89cd0932004-09-08 18:23:25 +00003474
3475 /* bits 5,4,3 are an opcode extension, and the modRM also
3476 specifies an address. */
3477 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
3478 delta += len;
3479
3480 switch (gregOfRM(modrm)) {
3481
sewardj3fd5e572004-09-09 22:43:51 +00003482 case 0: /* FADD single-real */
3483 fp_do_op_mem_ST_0 ( addr, "add", dis_buf, Iop_AddF64, False );
3484 break;
3485
sewardj89cd0932004-09-08 18:23:25 +00003486 case 1: /* FMUL single-real */
3487 fp_do_op_mem_ST_0 ( addr, "mul", dis_buf, Iop_MulF64, False );
3488 break;
3489
sewardj7ca37d92004-10-25 02:58:30 +00003490 case 2: /* FCOM single-real */
3491 DIP("fcoms %s\n", dis_buf);
3492 /* This forces C1 to zero, which isn't right. */
3493 put_C3210(
3494 binop( Iop_And32,
3495 binop(Iop_Shl32,
3496 binop(Iop_CmpF64,
3497 get_ST(0),
3498 unop(Iop_F32toF64,
3499 loadLE(Ity_F32,mkexpr(addr)))),
3500 mkU8(8)),
3501 mkU32(0x4500)
3502 ));
3503 break;
3504
3505 case 3: /* FCOMP single-real */
sewardje166ed02004-10-25 02:27:01 +00003506 DIP("fcomps %s\n", dis_buf);
3507 /* This forces C1 to zero, which isn't right. */
3508 put_C3210(
3509 binop( Iop_And32,
3510 binop(Iop_Shl32,
3511 binop(Iop_CmpF64,
3512 get_ST(0),
3513 unop(Iop_F32toF64,
3514 loadLE(Ity_F32,mkexpr(addr)))),
3515 mkU8(8)),
3516 mkU32(0x4500)
3517 ));
3518 fp_pop();
3519 break;
3520
sewardj588ea762004-09-10 18:56:32 +00003521 case 4: /* FSUB single-real */
3522 fp_do_op_mem_ST_0 ( addr, "sub", dis_buf, Iop_SubF64, False );
3523 break;
3524
3525 case 5: /* FSUBR single-real */
3526 fp_do_oprev_mem_ST_0 ( addr, "subr", dis_buf, Iop_SubF64, False );
3527 break;
3528
sewardjbdc7d212004-09-09 02:46:40 +00003529 case 6: /* FDIV single-real */
3530 fp_do_op_mem_ST_0 ( addr, "div", dis_buf, Iop_DivF64, False );
3531 break;
3532
sewardj8308aad2004-09-12 11:09:54 +00003533 case 7: /* FDIVR single-real */
3534 fp_do_oprev_mem_ST_0 ( addr, "divr", dis_buf, Iop_DivF64, False );
3535 break;
3536
sewardj89cd0932004-09-08 18:23:25 +00003537 default:
3538 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
3539 vex_printf("first_opcode == 0xD8\n");
3540 goto decode_fail;
3541 }
sewardjdb199622004-09-06 23:19:03 +00003542 } else {
3543 delta++;
3544 switch (modrm) {
sewardj89cd0932004-09-08 18:23:25 +00003545
sewardjdb199622004-09-06 23:19:03 +00003546 case 0xC0 ... 0xC7: /* FADD %st(?),%st(0) */
sewardjbdc7d212004-09-09 02:46:40 +00003547 fp_do_op_ST_ST ( "add", Iop_AddF64, modrm - 0xC0, 0, False );
sewardjdb199622004-09-06 23:19:03 +00003548 break;
sewardj89cd0932004-09-08 18:23:25 +00003549
sewardj3fd5e572004-09-09 22:43:51 +00003550 case 0xC8 ... 0xCF: /* FMUL %st(?),%st(0) */
3551 fp_do_op_ST_ST ( "mul", Iop_MulF64, modrm - 0xC8, 0, False );
3552 break;
3553
sewardje166ed02004-10-25 02:27:01 +00003554 /* Dunno if this is right */
3555 case 0xD0 ... 0xD7: /* FCOM %st(?),%st(0) */
3556 r_dst = (UInt)modrm - 0xD0;
sewardj2d49b432005-02-01 00:37:06 +00003557 DIP("fcom %%st(0),%%st(%d)\n", (Int)r_dst);
sewardje166ed02004-10-25 02:27:01 +00003558 /* This forces C1 to zero, which isn't right. */
3559 put_C3210(
3560 binop( Iop_And32,
3561 binop(Iop_Shl32,
3562 binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
3563 mkU8(8)),
3564 mkU32(0x4500)
3565 ));
3566 break;
sewardj2d49b432005-02-01 00:37:06 +00003567
sewardj98169c52004-10-24 13:11:39 +00003568 /* Dunno if this is right */
3569 case 0xD8 ... 0xDF: /* FCOMP %st(?),%st(0) */
3570 r_dst = (UInt)modrm - 0xD8;
sewardj2d49b432005-02-01 00:37:06 +00003571 DIP("fcomp %%st(0),%%st(%d)\n", (Int)r_dst);
sewardj98169c52004-10-24 13:11:39 +00003572 /* This forces C1 to zero, which isn't right. */
3573 put_C3210(
3574 binop( Iop_And32,
3575 binop(Iop_Shl32,
3576 binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
3577 mkU8(8)),
3578 mkU32(0x4500)
3579 ));
3580 fp_pop();
3581 break;
sewardj2d49b432005-02-01 00:37:06 +00003582
sewardj89cd0932004-09-08 18:23:25 +00003583 case 0xE0 ... 0xE7: /* FSUB %st(?),%st(0) */
sewardjbdc7d212004-09-09 02:46:40 +00003584 fp_do_op_ST_ST ( "sub", Iop_SubF64, modrm - 0xE0, 0, False );
sewardj89cd0932004-09-08 18:23:25 +00003585 break;
3586
sewardj8308aad2004-09-12 11:09:54 +00003587 case 0xE8 ... 0xEF: /* FSUBR %st(?),%st(0) */
3588 fp_do_oprev_ST_ST ( "subr", Iop_SubF64, modrm - 0xE8, 0, False );
3589 break;
3590
sewardj3fd5e572004-09-09 22:43:51 +00003591 case 0xF0 ... 0xF7: /* FDIV %st(?),%st(0) */
3592 fp_do_op_ST_ST ( "div", Iop_DivF64, modrm - 0xF0, 0, False );
3593 break;
3594
3595 case 0xF8 ... 0xFF: /* FDIVR %st(?),%st(0) */
3596 fp_do_oprev_ST_ST ( "divr", Iop_DivF64, modrm - 0xF8, 0, False );
3597 break;
3598
sewardjdb199622004-09-06 23:19:03 +00003599 default:
3600 goto decode_fail;
3601 }
3602 }
sewardjd1725d12004-08-12 20:46:53 +00003603 }
3604
3605 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xD9 opcodes +-+-+-+-+-+-+-+ */
3606 else
3607 if (first_opcode == 0xD9) {
sewardjbb53f8c2004-08-14 11:50:01 +00003608 if (modrm < 0xC0) {
sewardj89cd0932004-09-08 18:23:25 +00003609
3610 /* bits 5,4,3 are an opcode extension, and the modRM also
sewardjfeeb8a82004-11-30 12:30:11 +00003611 specifies an address. */
sewardj89cd0932004-09-08 18:23:25 +00003612 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
3613 delta += len;
3614
3615 switch (gregOfRM(modrm)) {
3616
3617 case 0: /* FLD single-real */
sewardj33dd31b2005-01-08 18:17:32 +00003618 DIP("flds %s\n", dis_buf);
sewardj89cd0932004-09-08 18:23:25 +00003619 fp_push();
3620 put_ST(0, unop(Iop_F32toF64,
sewardj8f3debf2004-09-08 23:42:23 +00003621 loadLE(Ity_F32, mkexpr(addr))));
sewardj89cd0932004-09-08 18:23:25 +00003622 break;
3623
sewardj588ea762004-09-10 18:56:32 +00003624 case 2: /* FST single-real */
sewardj33dd31b2005-01-08 18:17:32 +00003625 DIP("fsts %s\n", dis_buf);
sewardj3bca9062004-12-04 14:36:09 +00003626 storeLE(mkexpr(addr),
3627 binop(Iop_F64toF32, get_roundingmode(), get_ST(0)));
sewardj588ea762004-09-10 18:56:32 +00003628 break;
3629
sewardj89cd0932004-09-08 18:23:25 +00003630 case 3: /* FSTP single-real */
sewardj33dd31b2005-01-08 18:17:32 +00003631 DIP("fstps %s\n", dis_buf);
sewardj3bca9062004-12-04 14:36:09 +00003632 storeLE(mkexpr(addr),
3633 binop(Iop_F64toF32, get_roundingmode(), get_ST(0)));
sewardj5bd4d162004-11-10 13:02:48 +00003634 fp_pop();
sewardj89cd0932004-09-08 18:23:25 +00003635 break;
3636
sewardjd24931d2005-03-20 12:51:39 +00003637 case 4: { /* FLDENV m28 */
sewardj7df596b2004-12-06 14:29:12 +00003638 /* Uses dirty helper:
sewardj4017a3b2005-06-13 12:17:27 +00003639 VexEmWarn x86g_do_FLDENV ( VexGuestX86State*, HWord ) */
sewardj7df596b2004-12-06 14:29:12 +00003640 IRTemp ew = newTemp(Ity_I32);
3641 IRDirty* d = unsafeIRDirty_0_N (
3642 0/*regparms*/,
3643 "x86g_dirtyhelper_FLDENV",
3644 &x86g_dirtyhelper_FLDENV,
3645 mkIRExprVec_1( mkexpr(addr) )
3646 );
3647 d->needsBBP = True;
3648 d->tmp = ew;
3649 /* declare we're reading memory */
3650 d->mFx = Ifx_Read;
3651 d->mAddr = mkexpr(addr);
3652 d->mSize = 28;
3653
3654 /* declare we're writing guest state */
sewardj46813fc2005-06-13 12:33:36 +00003655 d->nFxState = 4;
sewardj7df596b2004-12-06 14:29:12 +00003656
3657 d->fxState[0].fx = Ifx_Write;
3658 d->fxState[0].offset = OFFB_FTOP;
3659 d->fxState[0].size = sizeof(UInt);
3660
3661 d->fxState[1].fx = Ifx_Write;
sewardj46813fc2005-06-13 12:33:36 +00003662 d->fxState[1].offset = OFFB_FPTAGS;
3663 d->fxState[1].size = 8 * sizeof(UChar);
sewardj7df596b2004-12-06 14:29:12 +00003664
3665 d->fxState[2].fx = Ifx_Write;
sewardj46813fc2005-06-13 12:33:36 +00003666 d->fxState[2].offset = OFFB_FPROUND;
3667 d->fxState[2].size = sizeof(UInt);
sewardj7df596b2004-12-06 14:29:12 +00003668
3669 d->fxState[3].fx = Ifx_Write;
sewardj46813fc2005-06-13 12:33:36 +00003670 d->fxState[3].offset = OFFB_FC3210;
sewardj7df596b2004-12-06 14:29:12 +00003671 d->fxState[3].size = sizeof(UInt);
3672
sewardj7df596b2004-12-06 14:29:12 +00003673 stmt( IRStmt_Dirty(d) );
3674
3675 /* ew contains any emulation warning we may need to
3676 issue. If needed, side-exit to the next insn,
3677 reporting the warning, so that Valgrind's dispatcher
3678 sees the warning. */
3679 put_emwarn( mkexpr(ew) );
3680 stmt(
3681 IRStmt_Exit(
3682 binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
3683 Ijk_EmWarn,
sewardj9e6491a2005-07-02 19:24:10 +00003684 IRConst_U32( ((Addr32)guest_EIP_bbstart)+delta)
sewardj7df596b2004-12-06 14:29:12 +00003685 )
3686 );
3687
sewardj33dd31b2005-01-08 18:17:32 +00003688 DIP("fldenv %s\n", dis_buf);
sewardj7df596b2004-12-06 14:29:12 +00003689 break;
3690 }
3691
sewardj893aada2004-11-29 19:57:54 +00003692 case 5: {/* FLDCW */
3693 /* The only thing we observe in the control word is the
sewardjd01a9632004-11-30 13:18:37 +00003694 rounding mode. Therefore, pass the 16-bit value
3695 (x87 native-format control word) to a clean helper,
3696 getting back a 64-bit value, the lower half of which
3697 is the FPROUND value to store, and the upper half of
3698 which is the emulation-warning token which may be
3699 generated.
sewardj893aada2004-11-29 19:57:54 +00003700 */
3701 /* ULong x86h_check_fldcw ( UInt ); */
3702 IRTemp t64 = newTemp(Ity_I64);
3703 IRTemp ew = newTemp(Ity_I32);
sewardj33dd31b2005-01-08 18:17:32 +00003704 DIP("fldcw %s\n", dis_buf);
sewardj893aada2004-11-29 19:57:54 +00003705 assign( t64, mkIRExprCCall(
3706 Ity_I64, 0/*regparms*/,
sewardj3bd6f3e2004-12-13 10:48:19 +00003707 "x86g_check_fldcw",
3708 &x86g_check_fldcw,
sewardj893aada2004-11-29 19:57:54 +00003709 mkIRExprVec_1(
3710 unop( Iop_16Uto32,
3711 loadLE(Ity_I16, mkexpr(addr)))
3712 )
3713 )
3714 );
3715
sewardjd01a9632004-11-30 13:18:37 +00003716 put_fpround( unop(Iop_64to32, mkexpr(t64)) );
sewardj893aada2004-11-29 19:57:54 +00003717 assign( ew, unop(Iop_64HIto32, mkexpr(t64) ) );
3718 put_emwarn( mkexpr(ew) );
3719 /* Finally, if an emulation warning was reported,
3720 side-exit to the next insn, reporting the warning,
3721 so that Valgrind's dispatcher sees the warning. */
3722 stmt(
3723 IRStmt_Exit(
3724 binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
3725 Ijk_EmWarn,
sewardj9e6491a2005-07-02 19:24:10 +00003726 IRConst_U32( ((Addr32)guest_EIP_bbstart)+delta)
sewardj893aada2004-11-29 19:57:54 +00003727 )
3728 );
sewardj89cd0932004-09-08 18:23:25 +00003729 break;
sewardj893aada2004-11-29 19:57:54 +00003730 }
sewardj89cd0932004-09-08 18:23:25 +00003731
sewardj7df596b2004-12-06 14:29:12 +00003732 case 6: { /* FNSTENV m28 */
3733 /* Uses dirty helper:
sewardj4017a3b2005-06-13 12:17:27 +00003734 void x86g_do_FSTENV ( VexGuestX86State*, HWord ) */
sewardj7df596b2004-12-06 14:29:12 +00003735 IRDirty* d = unsafeIRDirty_0_N (
3736 0/*regparms*/,
3737 "x86g_dirtyhelper_FSTENV",
3738 &x86g_dirtyhelper_FSTENV,
3739 mkIRExprVec_1( mkexpr(addr) )
3740 );
3741 d->needsBBP = True;
3742 /* declare we're writing memory */
3743 d->mFx = Ifx_Write;
3744 d->mAddr = mkexpr(addr);
3745 d->mSize = 28;
3746
3747 /* declare we're reading guest state */
3748 d->nFxState = 4;
3749
3750 d->fxState[0].fx = Ifx_Read;
3751 d->fxState[0].offset = OFFB_FTOP;
3752 d->fxState[0].size = sizeof(UInt);
3753
3754 d->fxState[1].fx = Ifx_Read;
3755 d->fxState[1].offset = OFFB_FPTAGS;
3756 d->fxState[1].size = 8 * sizeof(UChar);
3757
3758 d->fxState[2].fx = Ifx_Read;
3759 d->fxState[2].offset = OFFB_FPROUND;
3760 d->fxState[2].size = sizeof(UInt);
3761
3762 d->fxState[3].fx = Ifx_Read;
3763 d->fxState[3].offset = OFFB_FC3210;
3764 d->fxState[3].size = sizeof(UInt);
3765
3766 stmt( IRStmt_Dirty(d) );
3767
sewardj33dd31b2005-01-08 18:17:32 +00003768 DIP("fnstenv %s\n", dis_buf);
sewardj7df596b2004-12-06 14:29:12 +00003769 break;
3770 }
3771
sewardj588ea762004-09-10 18:56:32 +00003772 case 7: /* FNSTCW */
sewardj893aada2004-11-29 19:57:54 +00003773 /* Fake up a native x87 FPU control word. The only
sewardjd01a9632004-11-30 13:18:37 +00003774 thing it depends on is FPROUND[1:0], so call a clean
sewardj893aada2004-11-29 19:57:54 +00003775 helper to cook it up. */
sewardjd01a9632004-11-30 13:18:37 +00003776 /* UInt x86h_create_fpucw ( UInt fpround ) */
sewardj33dd31b2005-01-08 18:17:32 +00003777 DIP("fnstcw %s\n", dis_buf);
sewardj893aada2004-11-29 19:57:54 +00003778 storeLE(
3779 mkexpr(addr),
3780 unop( Iop_32to16,
3781 mkIRExprCCall(
3782 Ity_I32, 0/*regp*/,
sewardj3bd6f3e2004-12-13 10:48:19 +00003783 "x86g_create_fpucw", &x86g_create_fpucw,
sewardjd01a9632004-11-30 13:18:37 +00003784 mkIRExprVec_1( get_fpround() )
sewardj893aada2004-11-29 19:57:54 +00003785 )
3786 )
3787 );
sewardj89cd0932004-09-08 18:23:25 +00003788 break;
3789
3790 default:
3791 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
3792 vex_printf("first_opcode == 0xD9\n");
3793 goto decode_fail;
3794 }
3795
sewardjbb53f8c2004-08-14 11:50:01 +00003796 } else {
3797 delta++;
3798 switch (modrm) {
sewardj89cd0932004-09-08 18:23:25 +00003799
sewardjbb53f8c2004-08-14 11:50:01 +00003800 case 0xC0 ... 0xC7: /* FLD %st(?) */
sewardja58ea662004-08-15 03:12:41 +00003801 r_src = (UInt)modrm - 0xC0;
sewardj2d49b432005-02-01 00:37:06 +00003802 DIP("fld %%st(%d)\n", (Int)r_src);
sewardj5bd4d162004-11-10 13:02:48 +00003803 t1 = newTemp(Ity_F64);
3804 assign(t1, get_ST(r_src));
3805 fp_push();
3806 put_ST(0, mkexpr(t1));
sewardjbb53f8c2004-08-14 11:50:01 +00003807 break;
3808
sewardj89cd0932004-09-08 18:23:25 +00003809 case 0xC8 ... 0xCF: /* FXCH %st(?) */
3810 r_src = (UInt)modrm - 0xC8;
sewardj2d49b432005-02-01 00:37:06 +00003811 DIP("fxch %%st(%d)\n", (Int)r_src);
sewardj89cd0932004-09-08 18:23:25 +00003812 t1 = newTemp(Ity_F64);
3813 t2 = newTemp(Ity_F64);
3814 assign(t1, get_ST(0));
3815 assign(t2, get_ST(r_src));
3816 put_ST_UNCHECKED(0, mkexpr(t2));
3817 put_ST_UNCHECKED(r_src, mkexpr(t1));
3818 break;
3819
sewardjcfded9a2004-09-09 11:44:16 +00003820 case 0xE0: /* FCHS */
3821 DIP("fchs\n");
3822 put_ST_UNCHECKED(0, unop(Iop_NegF64, get_ST(0)));
3823 break;
3824
sewardj883b00b2004-09-11 09:30:24 +00003825 case 0xE1: /* FABS */
3826 DIP("fabs\n");
3827 put_ST_UNCHECKED(0, unop(Iop_AbsF64, get_ST(0)));
3828 break;
sewardjc4be80c2004-09-10 16:17:45 +00003829
sewardj1c318772005-03-19 14:27:04 +00003830 case 0xE4: /* FTST */
3831 DIP("ftst\n");
3832 /* This forces C1 to zero, which isn't right. */
3833 /* Well, in fact the Intel docs say (bizarrely): "C1 is
3834 set to 0 if stack underflow occurred; otherwise, set
3835 to 0" which is pretty nonsensical. I guess it's a
3836 typo. */
3837 put_C3210(
3838 binop( Iop_And32,
3839 binop(Iop_Shl32,
3840 binop(Iop_CmpF64,
3841 get_ST(0),
3842 IRExpr_Const(IRConst_F64i(0x0ULL))),
3843 mkU8(8)),
3844 mkU32(0x4500)
3845 ));
3846 break;
3847
sewardj883b00b2004-09-11 09:30:24 +00003848 case 0xE5: { /* FXAM */
3849 /* This is an interesting one. It examines %st(0),
3850 regardless of whether the tag says it's empty or not.
3851 Here, just pass both the tag (in our format) and the
3852 value (as a double, actually a ULong) to a helper
3853 function. */
sewardjf9655262004-10-31 20:02:16 +00003854 IRExpr** args
3855 = mkIRExprVec_2( unop(Iop_8Uto32, get_ST_TAG(0)),
3856 unop(Iop_ReinterpF64asI64,
3857 get_ST_UNCHECKED(0)) );
3858 put_C3210(mkIRExprCCall(
sewardj8ea867b2004-10-30 19:03:02 +00003859 Ity_I32,
sewardjf9655262004-10-31 20:02:16 +00003860 0/*regparm*/,
sewardj2a9ad022004-11-25 02:46:58 +00003861 "x86g_calculate_FXAM", &x86g_calculate_FXAM,
sewardj8ea867b2004-10-30 19:03:02 +00003862 args
3863 ));
sewardj33dd31b2005-01-08 18:17:32 +00003864 DIP("fxam\n");
sewardj883b00b2004-09-11 09:30:24 +00003865 break;
3866 }
3867
3868 case 0xE8: /* FLD1 */
sewardj33dd31b2005-01-08 18:17:32 +00003869 DIP("fld1\n");
sewardjce646f22004-08-31 23:55:54 +00003870 fp_push();
sewardj9c323762005-01-10 16:49:19 +00003871 /* put_ST(0, IRExpr_Const(IRConst_F64(1.0))); */
3872 put_ST(0, IRExpr_Const(IRConst_F64i(0x3ff0000000000000ULL)));
sewardjce646f22004-08-31 23:55:54 +00003873 break;
3874
sewardj37158712004-10-15 21:23:12 +00003875 case 0xE9: /* FLDL2T */
sewardj33dd31b2005-01-08 18:17:32 +00003876 DIP("fldl2t\n");
sewardj37158712004-10-15 21:23:12 +00003877 fp_push();
sewardj9c323762005-01-10 16:49:19 +00003878 /* put_ST(0, IRExpr_Const(IRConst_F64(3.32192809488736234781))); */
3879 put_ST(0, IRExpr_Const(IRConst_F64i(0x400a934f0979a371ULL)));
sewardj37158712004-10-15 21:23:12 +00003880 break;
3881
sewardj8308aad2004-09-12 11:09:54 +00003882 case 0xEA: /* FLDL2E */
sewardj33dd31b2005-01-08 18:17:32 +00003883 DIP("fldl2e\n");
sewardj8308aad2004-09-12 11:09:54 +00003884 fp_push();
sewardj9c323762005-01-10 16:49:19 +00003885 /* put_ST(0, IRExpr_Const(IRConst_F64(1.44269504088896340739))); */
3886 put_ST(0, IRExpr_Const(IRConst_F64i(0x3ff71547652b82feULL)));
sewardj8308aad2004-09-12 11:09:54 +00003887 break;
3888
sewardja0d48d62004-09-20 21:19:03 +00003889 case 0xEB: /* FLDPI */
sewardj33dd31b2005-01-08 18:17:32 +00003890 DIP("fldpi\n");
sewardja0d48d62004-09-20 21:19:03 +00003891 fp_push();
sewardj9c323762005-01-10 16:49:19 +00003892 /* put_ST(0, IRExpr_Const(IRConst_F64(3.14159265358979323851))); */
3893 put_ST(0, IRExpr_Const(IRConst_F64i(0x400921fb54442d18ULL)));
sewardja0d48d62004-09-20 21:19:03 +00003894 break;
3895
sewardjdb199622004-09-06 23:19:03 +00003896 case 0xEC: /* FLDLG2 */
sewardj33dd31b2005-01-08 18:17:32 +00003897 DIP("fldlg2\n");
sewardjdb199622004-09-06 23:19:03 +00003898 fp_push();
sewardj9c323762005-01-10 16:49:19 +00003899 /* put_ST(0, IRExpr_Const(IRConst_F64(0.301029995663981143))); */
3900 put_ST(0, IRExpr_Const(IRConst_F64i(0x3fd34413509f79ffULL)));
sewardjdb199622004-09-06 23:19:03 +00003901 break;
3902
3903 case 0xED: /* FLDLN2 */
sewardj33dd31b2005-01-08 18:17:32 +00003904 DIP("fldln2\n");
sewardjdb199622004-09-06 23:19:03 +00003905 fp_push();
sewardj9c323762005-01-10 16:49:19 +00003906 /* put_ST(0, IRExpr_Const(IRConst_F64(0.69314718055994530942))); */
3907 put_ST(0, IRExpr_Const(IRConst_F64i(0x3fe62e42fefa39efULL)));
sewardjdb199622004-09-06 23:19:03 +00003908 break;
3909
sewardja58ea662004-08-15 03:12:41 +00003910 case 0xEE: /* FLDZ */
sewardj33dd31b2005-01-08 18:17:32 +00003911 DIP("fldz\n");
sewardj207557a2004-08-27 12:00:18 +00003912 fp_push();
sewardj9c323762005-01-10 16:49:19 +00003913 /* put_ST(0, IRExpr_Const(IRConst_F64(0.0))); */
3914 put_ST(0, IRExpr_Const(IRConst_F64i(0x0000000000000000ULL)));
sewardja58ea662004-08-15 03:12:41 +00003915 break;
3916
sewardj06c32a02004-09-12 12:07:34 +00003917 case 0xF0: /* F2XM1 */
3918 DIP("f2xm1\n");
sewardjf1b5b1a2006-02-03 22:54:17 +00003919 put_ST_UNCHECKED(0,
3920 binop(Iop_2xm1F64,
3921 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
3922 get_ST(0)));
sewardj06c32a02004-09-12 12:07:34 +00003923 break;
3924
sewardj52ace3e2004-09-11 17:10:08 +00003925 case 0xF1: /* FYL2X */
3926 DIP("fyl2x\n");
sewardjf1b5b1a2006-02-03 22:54:17 +00003927 put_ST_UNCHECKED(1,
3928 triop(Iop_Yl2xF64,
3929 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
3930 get_ST(1),
3931 get_ST(0)));
sewardj52ace3e2004-09-11 17:10:08 +00003932 fp_pop();
3933 break;
3934
sewardj99016a72004-10-15 22:09:17 +00003935 case 0xF2: /* FPTAN */
3936 DIP("ftan\n");
sewardjf1b5b1a2006-02-03 22:54:17 +00003937 put_ST_UNCHECKED(0,
3938 binop(Iop_TanF64,
3939 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
3940 get_ST(0)));
sewardj99016a72004-10-15 22:09:17 +00003941 fp_push();
3942 put_ST(0, IRExpr_Const(IRConst_F64(1.0)));
sewardj3f61ddb2004-10-16 20:51:05 +00003943 clear_C2(); /* HACK */
sewardj99016a72004-10-15 22:09:17 +00003944 break;
3945
sewardjcfded9a2004-09-09 11:44:16 +00003946 case 0xF3: /* FPATAN */
3947 DIP("fpatan\n");
sewardjf1b5b1a2006-02-03 22:54:17 +00003948 put_ST_UNCHECKED(1,
3949 triop(Iop_AtanF64,
3950 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
3951 get_ST(1),
3952 get_ST(0)));
sewardjcfded9a2004-09-09 11:44:16 +00003953 fp_pop();
3954 break;
3955
sewardjf1b5b1a2006-02-03 22:54:17 +00003956 case 0xF4: { /* FXTRACT */
sewardjfda10af2005-10-03 01:02:40 +00003957 IRTemp argF = newTemp(Ity_F64);
3958 IRTemp sigF = newTemp(Ity_F64);
3959 IRTemp expF = newTemp(Ity_F64);
3960 IRTemp argI = newTemp(Ity_I64);
3961 IRTemp sigI = newTemp(Ity_I64);
3962 IRTemp expI = newTemp(Ity_I64);
3963 DIP("fxtract\n");
3964 assign( argF, get_ST(0) );
3965 assign( argI, unop(Iop_ReinterpF64asI64, mkexpr(argF)));
3966 assign( sigI,
sewardj879cee02006-03-07 01:15:50 +00003967 mkIRExprCCall(
3968 Ity_I64, 0/*regparms*/,
3969 "x86amd64g_calculate_FXTRACT",
3970 &x86amd64g_calculate_FXTRACT,
3971 mkIRExprVec_2( mkexpr(argI),
3972 mkIRExpr_HWord(0)/*sig*/ ))
3973 );
sewardjfda10af2005-10-03 01:02:40 +00003974 assign( expI,
sewardj879cee02006-03-07 01:15:50 +00003975 mkIRExprCCall(
3976 Ity_I64, 0/*regparms*/,
3977 "x86amd64g_calculate_FXTRACT",
3978 &x86amd64g_calculate_FXTRACT,
3979 mkIRExprVec_2( mkexpr(argI),
3980 mkIRExpr_HWord(1)/*exp*/ ))
3981 );
sewardjfda10af2005-10-03 01:02:40 +00003982 assign( sigF, unop(Iop_ReinterpI64asF64, mkexpr(sigI)) );
3983 assign( expF, unop(Iop_ReinterpI64asF64, mkexpr(expI)) );
3984 /* exponent */
3985 put_ST_UNCHECKED(0, mkexpr(expF) );
3986 fp_push();
3987 /* significand */
3988 put_ST(0, mkexpr(sigF) );
3989 break;
3990 }
3991
sewardj442d0be2004-10-15 22:57:13 +00003992 case 0xF5: { /* FPREM1 -- IEEE compliant */
3993 IRTemp a1 = newTemp(Ity_F64);
3994 IRTemp a2 = newTemp(Ity_F64);
3995 DIP("fprem1\n");
3996 /* Do FPREM1 twice, once to get the remainder, and once
3997 to get the C3210 flag values. */
3998 assign( a1, get_ST(0) );
3999 assign( a2, get_ST(1) );
sewardjf47286e2006-02-04 15:20:13 +00004000 put_ST_UNCHECKED(0,
4001 triop(Iop_PRem1F64,
4002 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4003 mkexpr(a1),
4004 mkexpr(a2)));
4005 put_C3210(
4006 triop(Iop_PRem1C3210F64,
4007 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4008 mkexpr(a1),
4009 mkexpr(a2)) );
sewardj442d0be2004-10-15 22:57:13 +00004010 break;
4011 }
4012
sewardjfeeb8a82004-11-30 12:30:11 +00004013 case 0xF7: /* FINCSTP */
4014 DIP("fprem\n");
4015 put_ftop( binop(Iop_Add32, get_ftop(), mkU32(1)) );
4016 break;
4017
sewardj46de4072004-09-11 19:23:24 +00004018 case 0xF8: { /* FPREM -- not IEEE compliant */
4019 IRTemp a1 = newTemp(Ity_F64);
4020 IRTemp a2 = newTemp(Ity_F64);
4021 DIP("fprem\n");
4022 /* Do FPREM twice, once to get the remainder, and once
4023 to get the C3210 flag values. */
4024 assign( a1, get_ST(0) );
4025 assign( a2, get_ST(1) );
sewardjf47286e2006-02-04 15:20:13 +00004026 put_ST_UNCHECKED(0,
4027 triop(Iop_PRemF64,
4028 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4029 mkexpr(a1),
4030 mkexpr(a2)));
4031 put_C3210(
4032 triop(Iop_PRemC3210F64,
4033 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4034 mkexpr(a1),
4035 mkexpr(a2)) );
sewardj46de4072004-09-11 19:23:24 +00004036 break;
4037 }
4038
sewardj8308aad2004-09-12 11:09:54 +00004039 case 0xF9: /* FYL2XP1 */
4040 DIP("fyl2xp1\n");
sewardjf1b5b1a2006-02-03 22:54:17 +00004041 put_ST_UNCHECKED(1,
4042 triop(Iop_Yl2xp1F64,
4043 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4044 get_ST(1),
4045 get_ST(0)));
sewardj8308aad2004-09-12 11:09:54 +00004046 fp_pop();
4047 break;
4048
sewardjc4be80c2004-09-10 16:17:45 +00004049 case 0xFA: /* FSQRT */
4050 DIP("fsqrt\n");
sewardjf1b5b1a2006-02-03 22:54:17 +00004051 put_ST_UNCHECKED(0,
4052 binop(Iop_SqrtF64,
4053 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4054 get_ST(0)));
sewardjc4be80c2004-09-10 16:17:45 +00004055 break;
4056
sewardj519d66f2004-12-15 11:57:58 +00004057 case 0xFB: { /* FSINCOS */
4058 IRTemp a1 = newTemp(Ity_F64);
4059 assign( a1, get_ST(0) );
4060 DIP("fsincos\n");
sewardjf1b5b1a2006-02-03 22:54:17 +00004061 put_ST_UNCHECKED(0,
4062 binop(Iop_SinF64,
4063 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4064 mkexpr(a1)));
sewardj519d66f2004-12-15 11:57:58 +00004065 fp_push();
sewardjf1b5b1a2006-02-03 22:54:17 +00004066 put_ST(0,
4067 binop(Iop_CosF64,
4068 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4069 mkexpr(a1)));
sewardj88a69242005-04-01 20:19:20 +00004070 clear_C2(); /* HACK */
sewardj519d66f2004-12-15 11:57:58 +00004071 break;
4072 }
4073
sewardje6709112004-09-10 18:37:18 +00004074 case 0xFC: /* FRNDINT */
4075 DIP("frndint\n");
4076 put_ST_UNCHECKED(0,
sewardjb183b852006-02-03 16:08:03 +00004077 binop(Iop_RoundF64toInt, get_roundingmode(), get_ST(0)) );
sewardje6709112004-09-10 18:37:18 +00004078 break;
4079
sewardj06c32a02004-09-12 12:07:34 +00004080 case 0xFD: /* FSCALE */
4081 DIP("fscale\n");
sewardjf1b5b1a2006-02-03 22:54:17 +00004082 put_ST_UNCHECKED(0,
4083 triop(Iop_ScaleF64,
4084 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4085 get_ST(0),
4086 get_ST(1)));
sewardj06c32a02004-09-12 12:07:34 +00004087 break;
4088
sewardjcfded9a2004-09-09 11:44:16 +00004089 case 0xFE: /* FSIN */
4090 DIP("fsin\n");
sewardjf1b5b1a2006-02-03 22:54:17 +00004091 put_ST_UNCHECKED(0,
4092 binop(Iop_SinF64,
4093 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4094 get_ST(0)));
sewardj3f61ddb2004-10-16 20:51:05 +00004095 clear_C2(); /* HACK */
sewardjcfded9a2004-09-09 11:44:16 +00004096 break;
4097
4098 case 0xFF: /* FCOS */
4099 DIP("fcos\n");
sewardjf1b5b1a2006-02-03 22:54:17 +00004100 put_ST_UNCHECKED(0,
4101 binop(Iop_CosF64,
4102 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4103 get_ST(0)));
sewardj3f61ddb2004-10-16 20:51:05 +00004104 clear_C2(); /* HACK */
sewardjcfded9a2004-09-09 11:44:16 +00004105 break;
4106
sewardjbb53f8c2004-08-14 11:50:01 +00004107 default:
4108 goto decode_fail;
4109 }
4110 }
sewardjd1725d12004-08-12 20:46:53 +00004111 }
4112
4113 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDA opcodes +-+-+-+-+-+-+-+ */
4114 else
4115 if (first_opcode == 0xDA) {
sewardjbb53f8c2004-08-14 11:50:01 +00004116
4117 if (modrm < 0xC0) {
4118
sewardjfeeb8a82004-11-30 12:30:11 +00004119 /* bits 5,4,3 are an opcode extension, and the modRM also
sewardjbb53f8c2004-08-14 11:50:01 +00004120 specifies an address. */
sewardjce646f22004-08-31 23:55:54 +00004121 IROp fop;
sewardjbb53f8c2004-08-14 11:50:01 +00004122 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
4123 delta += len;
sewardjbb53f8c2004-08-14 11:50:01 +00004124 switch (gregOfRM(modrm)) {
sewardjce646f22004-08-31 23:55:54 +00004125
sewardjdb199622004-09-06 23:19:03 +00004126 case 0: /* FIADD m32int */ /* ST(0) += m32int */
sewardj33dd31b2005-01-08 18:17:32 +00004127 DIP("fiaddl %s\n", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00004128 fop = Iop_AddF64;
4129 goto do_fop_m32;
sewardjdb199622004-09-06 23:19:03 +00004130
sewardj207557a2004-08-27 12:00:18 +00004131 case 1: /* FIMUL m32int */ /* ST(0) *= m32int */
sewardj33dd31b2005-01-08 18:17:32 +00004132 DIP("fimull %s\n", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00004133 fop = Iop_MulF64;
4134 goto do_fop_m32;
sewardjce646f22004-08-31 23:55:54 +00004135
sewardj071895f2005-07-29 11:28:38 +00004136 case 2: /* FICOM m32int */
4137 DIP("ficoml %s\n", dis_buf);
4138 /* This forces C1 to zero, which isn't right. */
4139 put_C3210(
4140 binop( Iop_And32,
4141 binop(Iop_Shl32,
4142 binop(Iop_CmpF64,
4143 get_ST(0),
4144 unop(Iop_I32toF64,
4145 loadLE(Ity_I32,mkexpr(addr)))),
4146 mkU8(8)),
4147 mkU32(0x4500)
4148 ));
4149 break;
4150
4151 case 3: /* FICOMP m32int */
4152 DIP("ficompl %s\n", dis_buf);
4153 /* This forces C1 to zero, which isn't right. */
4154 put_C3210(
4155 binop( Iop_And32,
4156 binop(Iop_Shl32,
4157 binop(Iop_CmpF64,
4158 get_ST(0),
4159 unop(Iop_I32toF64,
4160 loadLE(Ity_I32,mkexpr(addr)))),
4161 mkU8(8)),
4162 mkU32(0x4500)
4163 ));
4164 fp_pop();
4165 break;
4166
sewardjce646f22004-08-31 23:55:54 +00004167 case 4: /* FISUB m32int */ /* ST(0) -= m32int */
sewardj33dd31b2005-01-08 18:17:32 +00004168 DIP("fisubl %s\n", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00004169 fop = Iop_SubF64;
4170 goto do_fop_m32;
sewardjce646f22004-08-31 23:55:54 +00004171
sewardj8308aad2004-09-12 11:09:54 +00004172 case 5: /* FISUBR m32int */ /* ST(0) = m32int - ST(0) */
sewardj33dd31b2005-01-08 18:17:32 +00004173 DIP("fisubrl %s\n", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00004174 fop = Iop_SubF64;
4175 goto do_foprev_m32;
sewardj8308aad2004-09-12 11:09:54 +00004176
sewardjce646f22004-08-31 23:55:54 +00004177 case 6: /* FIDIV m32int */ /* ST(0) /= m32int */
sewardj36917e92005-03-21 00:12:15 +00004178 DIP("fidivl %s\n", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00004179 fop = Iop_DivF64;
4180 goto do_fop_m32;
sewardjce646f22004-08-31 23:55:54 +00004181
sewardjc4eaff32004-09-10 20:25:11 +00004182 case 7: /* FIDIVR m32int */ /* ST(0) = m32int / ST(0) */
sewardj33dd31b2005-01-08 18:17:32 +00004183 DIP("fidivrl %s\n", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00004184 fop = Iop_DivF64;
4185 goto do_foprev_m32;
sewardjc4eaff32004-09-10 20:25:11 +00004186
sewardjce646f22004-08-31 23:55:54 +00004187 do_fop_m32:
sewardj207557a2004-08-27 12:00:18 +00004188 put_ST_UNCHECKED(0,
sewardjf1b5b1a2006-02-03 22:54:17 +00004189 triop(fop,
4190 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardj207557a2004-08-27 12:00:18 +00004191 get_ST(0),
sewardj89cd0932004-09-08 18:23:25 +00004192 unop(Iop_I32toF64,
4193 loadLE(Ity_I32, mkexpr(addr)))));
sewardjbb53f8c2004-08-14 11:50:01 +00004194 break;
4195
sewardjc4eaff32004-09-10 20:25:11 +00004196 do_foprev_m32:
4197 put_ST_UNCHECKED(0,
sewardjf1b5b1a2006-02-03 22:54:17 +00004198 triop(fop,
4199 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardjc4eaff32004-09-10 20:25:11 +00004200 unop(Iop_I32toF64,
4201 loadLE(Ity_I32, mkexpr(addr))),
4202 get_ST(0)));
4203 break;
4204
sewardjbb53f8c2004-08-14 11:50:01 +00004205 default:
4206 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
4207 vex_printf("first_opcode == 0xDA\n");
4208 goto decode_fail;
4209 }
sewardj4cb918d2004-12-03 19:43:31 +00004210
sewardjbb53f8c2004-08-14 11:50:01 +00004211 } else {
sewardjbdc7d212004-09-09 02:46:40 +00004212
4213 delta++;
4214 switch (modrm) {
4215
sewardj519d66f2004-12-15 11:57:58 +00004216 case 0xC0 ... 0xC7: /* FCMOVB ST(i), ST(0) */
4217 r_src = (UInt)modrm - 0xC0;
sewardj2d49b432005-02-01 00:37:06 +00004218 DIP("fcmovb %%st(%d), %%st(0)\n", (Int)r_src);
sewardj519d66f2004-12-15 11:57:58 +00004219 put_ST_UNCHECKED(0,
4220 IRExpr_Mux0X(
4221 unop(Iop_1Uto8,
4222 mk_x86g_calculate_condition(X86CondB)),
4223 get_ST(0), get_ST(r_src)) );
4224 break;
4225
sewardj3fd5e572004-09-09 22:43:51 +00004226 case 0xC8 ... 0xCF: /* FCMOVE(Z) ST(i), ST(0) */
4227 r_src = (UInt)modrm - 0xC8;
sewardj2d49b432005-02-01 00:37:06 +00004228 DIP("fcmovz %%st(%d), %%st(0)\n", (Int)r_src);
sewardj5bd4d162004-11-10 13:02:48 +00004229 put_ST_UNCHECKED(0,
sewardj3fd5e572004-09-09 22:43:51 +00004230 IRExpr_Mux0X(
sewardj2a9ad022004-11-25 02:46:58 +00004231 unop(Iop_1Uto8,
4232 mk_x86g_calculate_condition(X86CondZ)),
sewardj3fd5e572004-09-09 22:43:51 +00004233 get_ST(0), get_ST(r_src)) );
4234 break;
4235
sewardj519d66f2004-12-15 11:57:58 +00004236 case 0xD0 ... 0xD7: /* FCMOVBE ST(i), ST(0) */
4237 r_src = (UInt)modrm - 0xD0;
sewardj2d49b432005-02-01 00:37:06 +00004238 DIP("fcmovbe %%st(%d), %%st(0)\n", (Int)r_src);
sewardj519d66f2004-12-15 11:57:58 +00004239 put_ST_UNCHECKED(0,
4240 IRExpr_Mux0X(
4241 unop(Iop_1Uto8,
4242 mk_x86g_calculate_condition(X86CondBE)),
4243 get_ST(0), get_ST(r_src)) );
4244 break;
4245
sewardj8253ad32005-07-04 10:26:32 +00004246 case 0xD8 ... 0xDF: /* FCMOVU ST(i), ST(0) */
4247 r_src = (UInt)modrm - 0xD8;
sewardjd8862cf2006-03-06 19:17:17 +00004248 DIP("fcmovu %%st(%d), %%st(0)\n", (Int)r_src);
sewardj8253ad32005-07-04 10:26:32 +00004249 put_ST_UNCHECKED(0,
4250 IRExpr_Mux0X(
4251 unop(Iop_1Uto8,
4252 mk_x86g_calculate_condition(X86CondP)),
4253 get_ST(0), get_ST(r_src)) );
4254 break;
4255
sewardjbdc7d212004-09-09 02:46:40 +00004256 case 0xE9: /* FUCOMPP %st(0),%st(1) */
4257 DIP("fucompp %%st(0),%%st(1)\n");
sewardjc4be80c2004-09-10 16:17:45 +00004258 /* This forces C1 to zero, which isn't right. */
4259 put_C3210(
4260 binop( Iop_And32,
4261 binop(Iop_Shl32,
4262 binop(Iop_CmpF64, get_ST(0), get_ST(1)),
4263 mkU8(8)),
4264 mkU32(0x4500)
4265 ));
sewardjbdc7d212004-09-09 02:46:40 +00004266 fp_pop();
4267 fp_pop();
4268 break;
4269
sewardj5bd4d162004-11-10 13:02:48 +00004270 default:
sewardjbdc7d212004-09-09 02:46:40 +00004271 goto decode_fail;
sewardj5bd4d162004-11-10 13:02:48 +00004272 }
sewardjbdc7d212004-09-09 02:46:40 +00004273
sewardjbb53f8c2004-08-14 11:50:01 +00004274 }
sewardjd1725d12004-08-12 20:46:53 +00004275 }
4276
4277 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDB opcodes +-+-+-+-+-+-+-+ */
4278 else
4279 if (first_opcode == 0xDB) {
sewardj89cd0932004-09-08 18:23:25 +00004280 if (modrm < 0xC0) {
4281
sewardjfeeb8a82004-11-30 12:30:11 +00004282 /* bits 5,4,3 are an opcode extension, and the modRM also
sewardj89cd0932004-09-08 18:23:25 +00004283 specifies an address. */
4284 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
4285 delta += len;
4286
4287 switch (gregOfRM(modrm)) {
4288
4289 case 0: /* FILD m32int */
4290 DIP("fildl %s\n", dis_buf);
4291 fp_push();
4292 put_ST(0, unop(Iop_I32toF64,
4293 loadLE(Ity_I32, mkexpr(addr))));
4294 break;
4295
sewardjdd5d2042006-08-03 15:03:19 +00004296 case 1: /* FISTTPL m32 (SSE3) */
4297 DIP("fisttpl %s\n", dis_buf);
4298 storeLE( mkexpr(addr),
4299 binop(Iop_F64toI32, mkU32(Irrm_ZERO), get_ST(0)) );
4300 fp_pop();
4301 break;
4302
sewardj8f3debf2004-09-08 23:42:23 +00004303 case 2: /* FIST m32 */
sewardj33dd31b2005-01-08 18:17:32 +00004304 DIP("fistl %s\n", dis_buf);
sewardj8f3debf2004-09-08 23:42:23 +00004305 storeLE( mkexpr(addr),
4306 binop(Iop_F64toI32, get_roundingmode(), get_ST(0)) );
4307 break;
4308
sewardj89cd0932004-09-08 18:23:25 +00004309 case 3: /* FISTP m32 */
sewardj33dd31b2005-01-08 18:17:32 +00004310 DIP("fistpl %s\n", dis_buf);
sewardj8f3debf2004-09-08 23:42:23 +00004311 storeLE( mkexpr(addr),
4312 binop(Iop_F64toI32, get_roundingmode(), get_ST(0)) );
sewardj5bd4d162004-11-10 13:02:48 +00004313 fp_pop();
sewardj89cd0932004-09-08 18:23:25 +00004314 break;
sewardj17442fe2004-09-20 14:54:28 +00004315
sewardjb3bce0e2004-09-14 23:20:10 +00004316 case 5: { /* FLD extended-real */
sewardj7cb49d72004-10-24 22:31:25 +00004317 /* Uses dirty helper:
sewardj56579232005-03-26 21:49:42 +00004318 ULong x86g_loadF80le ( UInt )
sewardj7cb49d72004-10-24 22:31:25 +00004319 addr holds the address. First, do a dirty call to
sewardjb3bce0e2004-09-14 23:20:10 +00004320 get hold of the data. */
sewardjc5fc7aa2004-10-27 23:00:55 +00004321 IRTemp val = newTemp(Ity_I64);
4322 IRExpr** args = mkIRExprVec_1 ( mkexpr(addr) );
4323
sewardj8ea867b2004-10-30 19:03:02 +00004324 IRDirty* d = unsafeIRDirty_1_N (
4325 val,
sewardj2a9ad022004-11-25 02:46:58 +00004326 0/*regparms*/,
sewardj8f40b072005-08-23 19:30:58 +00004327 "x86g_dirtyhelper_loadF80le",
4328 &x86g_dirtyhelper_loadF80le,
sewardj8ea867b2004-10-30 19:03:02 +00004329 args
4330 );
sewardjb3bce0e2004-09-14 23:20:10 +00004331 /* declare that we're reading memory */
4332 d->mFx = Ifx_Read;
sewardj17442fe2004-09-20 14:54:28 +00004333 d->mAddr = mkexpr(addr);
sewardjb3bce0e2004-09-14 23:20:10 +00004334 d->mSize = 10;
sewardjc5fc7aa2004-10-27 23:00:55 +00004335
4336 /* execute the dirty call, dumping the result in val. */
sewardjb3bce0e2004-09-14 23:20:10 +00004337 stmt( IRStmt_Dirty(d) );
4338 fp_push();
sewardjc5fc7aa2004-10-27 23:00:55 +00004339 put_ST(0, unop(Iop_ReinterpI64asF64, mkexpr(val)));
4340
sewardj33dd31b2005-01-08 18:17:32 +00004341 DIP("fldt %s\n", dis_buf);
sewardjb3bce0e2004-09-14 23:20:10 +00004342 break;
4343 }
sewardj17442fe2004-09-20 14:54:28 +00004344
4345 case 7: { /* FSTP extended-real */
sewardj9fc9e782004-11-26 17:57:40 +00004346 /* Uses dirty helper: void x86g_storeF80le ( UInt, ULong ) */
sewardjc5fc7aa2004-10-27 23:00:55 +00004347 IRExpr** args
4348 = mkIRExprVec_2( mkexpr(addr),
4349 unop(Iop_ReinterpF64asI64, get_ST(0)) );
4350
sewardj8ea867b2004-10-30 19:03:02 +00004351 IRDirty* d = unsafeIRDirty_0_N (
sewardjf9655262004-10-31 20:02:16 +00004352 0/*regparms*/,
sewardj8f40b072005-08-23 19:30:58 +00004353 "x86g_dirtyhelper_storeF80le",
4354 &x86g_dirtyhelper_storeF80le,
sewardj8ea867b2004-10-30 19:03:02 +00004355 args
4356 );
sewardj17442fe2004-09-20 14:54:28 +00004357 /* declare we're writing memory */
4358 d->mFx = Ifx_Write;
4359 d->mAddr = mkexpr(addr);
4360 d->mSize = 10;
sewardjc5fc7aa2004-10-27 23:00:55 +00004361
sewardj17442fe2004-09-20 14:54:28 +00004362 /* execute the dirty call. */
4363 stmt( IRStmt_Dirty(d) );
4364 fp_pop();
sewardjc5fc7aa2004-10-27 23:00:55 +00004365
sewardj33dd31b2005-01-08 18:17:32 +00004366 DIP("fstpt\n %s", dis_buf);
sewardj17442fe2004-09-20 14:54:28 +00004367 break;
4368 }
4369
sewardjb3bce0e2004-09-14 23:20:10 +00004370 default:
sewardj89cd0932004-09-08 18:23:25 +00004371 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
4372 vex_printf("first_opcode == 0xDB\n");
4373 goto decode_fail;
4374 }
4375
4376 } else {
sewardj8308aad2004-09-12 11:09:54 +00004377
4378 delta++;
4379 switch (modrm) {
4380
sewardj519d66f2004-12-15 11:57:58 +00004381 case 0xC0 ... 0xC7: /* FCMOVNB ST(i), ST(0) */
4382 r_src = (UInt)modrm - 0xC0;
sewardj2d49b432005-02-01 00:37:06 +00004383 DIP("fcmovnb %%st(%d), %%st(0)\n", (Int)r_src);
sewardj519d66f2004-12-15 11:57:58 +00004384 put_ST_UNCHECKED(0,
4385 IRExpr_Mux0X(
4386 unop(Iop_1Uto8,
4387 mk_x86g_calculate_condition(X86CondNB)),
4388 get_ST(0), get_ST(r_src)) );
4389 break;
4390
sewardj4e82db72004-10-16 11:32:15 +00004391 case 0xC8 ... 0xCF: /* FCMOVNE(NZ) ST(i), ST(0) */
4392 r_src = (UInt)modrm - 0xC8;
sewardj2d49b432005-02-01 00:37:06 +00004393 DIP("fcmovnz %%st(%d), %%st(0)\n", (Int)r_src);
sewardj5bd4d162004-11-10 13:02:48 +00004394 put_ST_UNCHECKED(0,
sewardj4e82db72004-10-16 11:32:15 +00004395 IRExpr_Mux0X(
sewardj2a9ad022004-11-25 02:46:58 +00004396 unop(Iop_1Uto8,
4397 mk_x86g_calculate_condition(X86CondNZ)),
sewardj4e82db72004-10-16 11:32:15 +00004398 get_ST(0), get_ST(r_src)) );
4399 break;
4400
sewardj519d66f2004-12-15 11:57:58 +00004401 case 0xD0 ... 0xD7: /* FCMOVNBE ST(i), ST(0) */
4402 r_src = (UInt)modrm - 0xD0;
sewardj2d49b432005-02-01 00:37:06 +00004403 DIP("fcmovnbe %%st(%d), %%st(0)\n", (Int)r_src);
sewardj519d66f2004-12-15 11:57:58 +00004404 put_ST_UNCHECKED(0,
4405 IRExpr_Mux0X(
4406 unop(Iop_1Uto8,
4407 mk_x86g_calculate_condition(X86CondNBE)),
4408 get_ST(0), get_ST(r_src)) );
4409 break;
4410
sewardj8253ad32005-07-04 10:26:32 +00004411 case 0xD8 ... 0xDF: /* FCMOVNU ST(i), ST(0) */
4412 r_src = (UInt)modrm - 0xD8;
4413 DIP("fcmovnu %%st(%d), %%st(0)\n", (Int)r_src);
4414 put_ST_UNCHECKED(0,
4415 IRExpr_Mux0X(
4416 unop(Iop_1Uto8,
4417 mk_x86g_calculate_condition(X86CondNP)),
4418 get_ST(0), get_ST(r_src)) );
4419 break;
4420
sewardj7df596b2004-12-06 14:29:12 +00004421 case 0xE2:
4422 DIP("fnclex\n");
4423 break;
4424
sewardja0e83b02005-01-06 12:36:38 +00004425 case 0xE3: {
4426 /* Uses dirty helper:
4427 void x86g_do_FINIT ( VexGuestX86State* ) */
4428 IRDirty* d = unsafeIRDirty_0_N (
4429 0/*regparms*/,
4430 "x86g_dirtyhelper_FINIT",
4431 &x86g_dirtyhelper_FINIT,
4432 mkIRExprVec_0()
4433 );
4434 d->needsBBP = True;
4435
4436 /* declare we're writing guest state */
4437 d->nFxState = 5;
4438
4439 d->fxState[0].fx = Ifx_Write;
4440 d->fxState[0].offset = OFFB_FTOP;
4441 d->fxState[0].size = sizeof(UInt);
4442
4443 d->fxState[1].fx = Ifx_Write;
4444 d->fxState[1].offset = OFFB_FPREGS;
4445 d->fxState[1].size = 8 * sizeof(ULong);
4446
4447 d->fxState[2].fx = Ifx_Write;
4448 d->fxState[2].offset = OFFB_FPTAGS;
4449 d->fxState[2].size = 8 * sizeof(UChar);
4450
4451 d->fxState[3].fx = Ifx_Write;
4452 d->fxState[3].offset = OFFB_FPROUND;
4453 d->fxState[3].size = sizeof(UInt);
4454
4455 d->fxState[4].fx = Ifx_Write;
4456 d->fxState[4].offset = OFFB_FC3210;
4457 d->fxState[4].size = sizeof(UInt);
4458
4459 stmt( IRStmt_Dirty(d) );
4460
sewardj33dd31b2005-01-08 18:17:32 +00004461 DIP("fninit\n");
sewardja0e83b02005-01-06 12:36:38 +00004462 break;
4463 }
4464
sewardj8308aad2004-09-12 11:09:54 +00004465 case 0xE8 ... 0xEF: /* FUCOMI %st(0),%st(?) */
4466 fp_do_ucomi_ST0_STi( (UInt)modrm - 0xE8, False );
4467 break;
4468
sewardj37158712004-10-15 21:23:12 +00004469 case 0xF0 ... 0xF7: /* FCOMI %st(0),%st(?) */
4470 fp_do_ucomi_ST0_STi( (UInt)modrm - 0xF0, False );
4471 break;
4472
sewardj8308aad2004-09-12 11:09:54 +00004473 default:
4474 goto decode_fail;
sewardj17442fe2004-09-20 14:54:28 +00004475 }
sewardj89cd0932004-09-08 18:23:25 +00004476 }
sewardjd1725d12004-08-12 20:46:53 +00004477 }
4478
4479 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDC opcodes +-+-+-+-+-+-+-+ */
4480 else
4481 if (first_opcode == 0xDC) {
sewardja58ea662004-08-15 03:12:41 +00004482 if (modrm < 0xC0) {
4483
sewardj89cd0932004-09-08 18:23:25 +00004484 /* bits 5,4,3 are an opcode extension, and the modRM also
sewardjfeeb8a82004-11-30 12:30:11 +00004485 specifies an address. */
sewardja58ea662004-08-15 03:12:41 +00004486 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
4487 delta += len;
4488
4489 switch (gregOfRM(modrm)) {
4490
4491 case 0: /* FADD double-real */
4492 fp_do_op_mem_ST_0 ( addr, "add", dis_buf, Iop_AddF64, True );
4493 break;
4494
sewardjcfded9a2004-09-09 11:44:16 +00004495 case 1: /* FMUL double-real */
4496 fp_do_op_mem_ST_0 ( addr, "mul", dis_buf, Iop_MulF64, True );
4497 break;
4498
sewardje166ed02004-10-25 02:27:01 +00004499 case 2: /* FCOM double-real */
4500 DIP("fcoml %s\n", dis_buf);
4501 /* This forces C1 to zero, which isn't right. */
4502 put_C3210(
4503 binop( Iop_And32,
4504 binop(Iop_Shl32,
4505 binop(Iop_CmpF64,
4506 get_ST(0),
4507 loadLE(Ity_F64,mkexpr(addr))),
4508 mkU8(8)),
4509 mkU32(0x4500)
4510 ));
4511 break;
4512
sewardj883b00b2004-09-11 09:30:24 +00004513 case 3: /* FCOMP double-real */
sewardje166ed02004-10-25 02:27:01 +00004514 DIP("fcompl %s\n", dis_buf);
sewardj883b00b2004-09-11 09:30:24 +00004515 /* This forces C1 to zero, which isn't right. */
4516 put_C3210(
4517 binop( Iop_And32,
4518 binop(Iop_Shl32,
4519 binop(Iop_CmpF64,
4520 get_ST(0),
4521 loadLE(Ity_F64,mkexpr(addr))),
4522 mkU8(8)),
4523 mkU32(0x4500)
4524 ));
4525 fp_pop();
4526 break;
4527
sewardjcfded9a2004-09-09 11:44:16 +00004528 case 4: /* FSUB double-real */
4529 fp_do_op_mem_ST_0 ( addr, "sub", dis_buf, Iop_SubF64, True );
4530 break;
4531
sewardj3fd5e572004-09-09 22:43:51 +00004532 case 5: /* FSUBR double-real */
4533 fp_do_oprev_mem_ST_0 ( addr, "subr", dis_buf, Iop_SubF64, True );
4534 break;
4535
sewardjcfded9a2004-09-09 11:44:16 +00004536 case 6: /* FDIV double-real */
4537 fp_do_op_mem_ST_0 ( addr, "div", dis_buf, Iop_DivF64, True );
4538 break;
4539
sewardj883b00b2004-09-11 09:30:24 +00004540 case 7: /* FDIVR double-real */
4541 fp_do_oprev_mem_ST_0 ( addr, "divr", dis_buf, Iop_DivF64, True );
4542 break;
4543
sewardja58ea662004-08-15 03:12:41 +00004544 default:
4545 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
4546 vex_printf("first_opcode == 0xDC\n");
4547 goto decode_fail;
4548 }
4549
4550 } else {
sewardjbdc7d212004-09-09 02:46:40 +00004551
4552 delta++;
4553 switch (modrm) {
4554
sewardj3fd5e572004-09-09 22:43:51 +00004555 case 0xC0 ... 0xC7: /* FADD %st(0),%st(?) */
4556 fp_do_op_ST_ST ( "add", Iop_AddF64, 0, modrm - 0xC0, False );
4557 break;
4558
sewardjcfded9a2004-09-09 11:44:16 +00004559 case 0xC8 ... 0xCF: /* FMUL %st(0),%st(?) */
4560 fp_do_op_ST_ST ( "mul", Iop_MulF64, 0, modrm - 0xC8, False );
4561 break;
4562
sewardj47341042004-09-19 11:55:46 +00004563 case 0xE0 ... 0xE7: /* FSUBR %st(0),%st(?) */
4564 fp_do_oprev_ST_ST ( "subr", Iop_SubF64, 0, modrm - 0xE0, False );
4565 break;
4566
sewardjcfded9a2004-09-09 11:44:16 +00004567 case 0xE8 ... 0xEF: /* FSUB %st(0),%st(?) */
4568 fp_do_op_ST_ST ( "sub", Iop_SubF64, 0, modrm - 0xE8, False );
4569 break;
4570
sewardja0d48d62004-09-20 21:19:03 +00004571 case 0xF0 ... 0xF7: /* FDIVR %st(0),%st(?) */
4572 fp_do_oprev_ST_ST ( "divr", Iop_DivF64, 0, modrm - 0xF0, False );
4573 break;
4574
sewardjbdc7d212004-09-09 02:46:40 +00004575 case 0xF8 ... 0xFF: /* FDIV %st(0),%st(?) */
4576 fp_do_op_ST_ST ( "div", Iop_DivF64, 0, modrm - 0xF8, False );
4577 break;
4578
4579 default:
4580 goto decode_fail;
sewardj5bd4d162004-11-10 13:02:48 +00004581 }
sewardjbdc7d212004-09-09 02:46:40 +00004582
sewardja58ea662004-08-15 03:12:41 +00004583 }
sewardjd1725d12004-08-12 20:46:53 +00004584 }
4585
4586 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDD opcodes +-+-+-+-+-+-+-+ */
4587 else
4588 if (first_opcode == 0xDD) {
4589
4590 if (modrm < 0xC0) {
4591
sewardjfeeb8a82004-11-30 12:30:11 +00004592 /* bits 5,4,3 are an opcode extension, and the modRM also
sewardjd1725d12004-08-12 20:46:53 +00004593 specifies an address. */
sewardjbb53f8c2004-08-14 11:50:01 +00004594 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
4595 delta += len;
sewardjd1725d12004-08-12 20:46:53 +00004596
4597 switch (gregOfRM(modrm)) {
4598
4599 case 0: /* FLD double-real */
sewardj33dd31b2005-01-08 18:17:32 +00004600 DIP("fldl %s\n", dis_buf);
sewardj207557a2004-08-27 12:00:18 +00004601 fp_push();
sewardjaf1ceca2005-06-30 23:31:27 +00004602 put_ST(0, loadLE(Ity_F64, mkexpr(addr)));
sewardjbb53f8c2004-08-14 11:50:01 +00004603 break;
sewardjd1725d12004-08-12 20:46:53 +00004604
sewardjdd5d2042006-08-03 15:03:19 +00004605 case 1: /* FISTTPQ m64 (SSE3) */
4606 DIP("fistppll %s\n", dis_buf);
4607 storeLE( mkexpr(addr),
4608 binop(Iop_F64toI64, mkU32(Irrm_ZERO), get_ST(0)) );
4609 fp_pop();
4610 break;
4611
sewardjd1725d12004-08-12 20:46:53 +00004612 case 2: /* FST double-real */
sewardj33dd31b2005-01-08 18:17:32 +00004613 DIP("fstl %s\n", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00004614 storeLE(mkexpr(addr), get_ST(0));
sewardjd1725d12004-08-12 20:46:53 +00004615 break;
sewardj89cd0932004-09-08 18:23:25 +00004616
sewardja58ea662004-08-15 03:12:41 +00004617 case 3: /* FSTP double-real */
sewardj33dd31b2005-01-08 18:17:32 +00004618 DIP("fstpl %s\n", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00004619 storeLE(mkexpr(addr), get_ST(0));
4620 fp_pop();
sewardja58ea662004-08-15 03:12:41 +00004621 break;
sewardjd1725d12004-08-12 20:46:53 +00004622
sewardj9fc9e782004-11-26 17:57:40 +00004623 case 4: { /* FRSTOR m108 */
sewardj893aada2004-11-29 19:57:54 +00004624 /* Uses dirty helper:
4625 VexEmWarn x86g_do_FRSTOR ( VexGuestX86State*, Addr32 ) */
4626 IRTemp ew = newTemp(Ity_I32);
4627 IRDirty* d = unsafeIRDirty_0_N (
4628 0/*regparms*/,
4629 "x86g_dirtyhelper_FRSTOR",
4630 &x86g_dirtyhelper_FRSTOR,
4631 mkIRExprVec_1( mkexpr(addr) )
4632 );
sewardj9fc9e782004-11-26 17:57:40 +00004633 d->needsBBP = True;
sewardj893aada2004-11-29 19:57:54 +00004634 d->tmp = ew;
sewardj9fc9e782004-11-26 17:57:40 +00004635 /* declare we're reading memory */
4636 d->mFx = Ifx_Read;
4637 d->mAddr = mkexpr(addr);
4638 d->mSize = 108;
4639
4640 /* declare we're writing guest state */
sewardj893aada2004-11-29 19:57:54 +00004641 d->nFxState = 5;
sewardj9fc9e782004-11-26 17:57:40 +00004642
4643 d->fxState[0].fx = Ifx_Write;
sewardjc9a43662004-11-30 18:51:59 +00004644 d->fxState[0].offset = OFFB_FTOP;
sewardj9fc9e782004-11-26 17:57:40 +00004645 d->fxState[0].size = sizeof(UInt);
4646
4647 d->fxState[1].fx = Ifx_Write;
sewardjc9a43662004-11-30 18:51:59 +00004648 d->fxState[1].offset = OFFB_FPREGS;
sewardj9fc9e782004-11-26 17:57:40 +00004649 d->fxState[1].size = 8 * sizeof(ULong);
4650
4651 d->fxState[2].fx = Ifx_Write;
sewardjc9a43662004-11-30 18:51:59 +00004652 d->fxState[2].offset = OFFB_FPTAGS;
sewardj9fc9e782004-11-26 17:57:40 +00004653 d->fxState[2].size = 8 * sizeof(UChar);
4654
4655 d->fxState[3].fx = Ifx_Write;
sewardjc9a43662004-11-30 18:51:59 +00004656 d->fxState[3].offset = OFFB_FPROUND;
sewardj9fc9e782004-11-26 17:57:40 +00004657 d->fxState[3].size = sizeof(UInt);
4658
4659 d->fxState[4].fx = Ifx_Write;
sewardjc9a43662004-11-30 18:51:59 +00004660 d->fxState[4].offset = OFFB_FC3210;
sewardj9fc9e782004-11-26 17:57:40 +00004661 d->fxState[4].size = sizeof(UInt);
4662
4663 stmt( IRStmt_Dirty(d) );
4664
sewardj893aada2004-11-29 19:57:54 +00004665 /* ew contains any emulation warning we may need to
4666 issue. If needed, side-exit to the next insn,
4667 reporting the warning, so that Valgrind's dispatcher
4668 sees the warning. */
4669 put_emwarn( mkexpr(ew) );
4670 stmt(
4671 IRStmt_Exit(
4672 binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
4673 Ijk_EmWarn,
sewardj9e6491a2005-07-02 19:24:10 +00004674 IRConst_U32( ((Addr32)guest_EIP_bbstart)+delta)
sewardj893aada2004-11-29 19:57:54 +00004675 )
4676 );
4677
sewardj33dd31b2005-01-08 18:17:32 +00004678 DIP("frstor %s\n", dis_buf);
sewardj9fc9e782004-11-26 17:57:40 +00004679 break;
4680 }
4681
4682 case 6: { /* FNSAVE m108 */
sewardj893aada2004-11-29 19:57:54 +00004683 /* Uses dirty helper:
4684 void x86g_do_FSAVE ( VexGuestX86State*, UInt ) */
sewardj9fc9e782004-11-26 17:57:40 +00004685 IRDirty* d = unsafeIRDirty_0_N (
4686 0/*regparms*/,
4687 "x86g_dirtyhelper_FSAVE",
4688 &x86g_dirtyhelper_FSAVE,
4689 mkIRExprVec_1( mkexpr(addr) )
4690 );
4691 d->needsBBP = True;
4692 /* declare we're writing memory */
4693 d->mFx = Ifx_Write;
4694 d->mAddr = mkexpr(addr);
4695 d->mSize = 108;
4696
4697 /* declare we're reading guest state */
sewardj893aada2004-11-29 19:57:54 +00004698 d->nFxState = 5;
sewardj9fc9e782004-11-26 17:57:40 +00004699
4700 d->fxState[0].fx = Ifx_Read;
sewardjc9a43662004-11-30 18:51:59 +00004701 d->fxState[0].offset = OFFB_FTOP;
sewardj9fc9e782004-11-26 17:57:40 +00004702 d->fxState[0].size = sizeof(UInt);
4703
4704 d->fxState[1].fx = Ifx_Read;
sewardjc9a43662004-11-30 18:51:59 +00004705 d->fxState[1].offset = OFFB_FPREGS;
sewardj9fc9e782004-11-26 17:57:40 +00004706 d->fxState[1].size = 8 * sizeof(ULong);
4707
4708 d->fxState[2].fx = Ifx_Read;
sewardjc9a43662004-11-30 18:51:59 +00004709 d->fxState[2].offset = OFFB_FPTAGS;
sewardj9fc9e782004-11-26 17:57:40 +00004710 d->fxState[2].size = 8 * sizeof(UChar);
4711
4712 d->fxState[3].fx = Ifx_Read;
sewardjc9a43662004-11-30 18:51:59 +00004713 d->fxState[3].offset = OFFB_FPROUND;
sewardj9fc9e782004-11-26 17:57:40 +00004714 d->fxState[3].size = sizeof(UInt);
4715
4716 d->fxState[4].fx = Ifx_Read;
sewardjc9a43662004-11-30 18:51:59 +00004717 d->fxState[4].offset = OFFB_FC3210;
sewardj9fc9e782004-11-26 17:57:40 +00004718 d->fxState[4].size = sizeof(UInt);
4719
4720 stmt( IRStmt_Dirty(d) );
4721
sewardj33dd31b2005-01-08 18:17:32 +00004722 DIP("fnsave %s\n", dis_buf);
sewardj9fc9e782004-11-26 17:57:40 +00004723 break;
4724 }
4725
sewardjd24931d2005-03-20 12:51:39 +00004726 case 7: { /* FNSTSW m16 */
4727 IRExpr* sw = get_FPU_sw();
sewardjdd40fdf2006-12-24 02:20:24 +00004728 vassert(typeOfIRExpr(irsb->tyenv, sw) == Ity_I16);
sewardjd24931d2005-03-20 12:51:39 +00004729 storeLE( mkexpr(addr), sw );
4730 DIP("fnstsw %s\n", dis_buf);
4731 break;
4732 }
4733
sewardjd1725d12004-08-12 20:46:53 +00004734 default:
sewardjbb53f8c2004-08-14 11:50:01 +00004735 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
4736 vex_printf("first_opcode == 0xDD\n");
sewardjd1725d12004-08-12 20:46:53 +00004737 goto decode_fail;
sewardjbb53f8c2004-08-14 11:50:01 +00004738 }
sewardjd1725d12004-08-12 20:46:53 +00004739 } else {
sewardja58ea662004-08-15 03:12:41 +00004740 delta++;
4741 switch (modrm) {
sewardjbdc7d212004-09-09 02:46:40 +00004742
sewardj3ddedc42005-03-25 20:30:00 +00004743 case 0xC0 ... 0xC7: /* FFREE %st(?) */
4744 r_dst = (UInt)modrm - 0xC0;
sewardj4a6f3842005-03-26 11:59:23 +00004745 DIP("ffree %%st(%d)\n", (Int)r_dst);
sewardj3ddedc42005-03-25 20:30:00 +00004746 put_ST_TAG ( r_dst, mkU8(0) );
4747 break;
4748
sewardj06c32a02004-09-12 12:07:34 +00004749 case 0xD0 ... 0xD7: /* FST %st(0),%st(?) */
4750 r_dst = (UInt)modrm - 0xD0;
sewardj2d49b432005-02-01 00:37:06 +00004751 DIP("fst %%st(0),%%st(%d)\n", (Int)r_dst);
sewardj5bd4d162004-11-10 13:02:48 +00004752 /* P4 manual says: "If the destination operand is a
sewardj06c32a02004-09-12 12:07:34 +00004753 non-empty register, the invalid-operation exception
4754 is not generated. Hence put_ST_UNCHECKED. */
4755 put_ST_UNCHECKED(r_dst, get_ST(0));
4756 break;
4757
sewardja58ea662004-08-15 03:12:41 +00004758 case 0xD8 ... 0xDF: /* FSTP %st(0),%st(?) */
4759 r_dst = (UInt)modrm - 0xD8;
sewardj2d49b432005-02-01 00:37:06 +00004760 DIP("fstp %%st(0),%%st(%d)\n", (Int)r_dst);
sewardj5bd4d162004-11-10 13:02:48 +00004761 /* P4 manual says: "If the destination operand is a
sewardj207557a2004-08-27 12:00:18 +00004762 non-empty register, the invalid-operation exception
4763 is not generated. Hence put_ST_UNCHECKED. */
4764 put_ST_UNCHECKED(r_dst, get_ST(0));
4765 fp_pop();
sewardja58ea662004-08-15 03:12:41 +00004766 break;
sewardjbdc7d212004-09-09 02:46:40 +00004767
4768 case 0xE0 ... 0xE7: /* FUCOM %st(0),%st(?) */
4769 r_dst = (UInt)modrm - 0xE0;
sewardj2d49b432005-02-01 00:37:06 +00004770 DIP("fucom %%st(0),%%st(%d)\n", (Int)r_dst);
sewardjc4be80c2004-09-10 16:17:45 +00004771 /* This forces C1 to zero, which isn't right. */
4772 put_C3210(
4773 binop( Iop_And32,
4774 binop(Iop_Shl32,
4775 binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
4776 mkU8(8)),
4777 mkU32(0x4500)
4778 ));
sewardjbdc7d212004-09-09 02:46:40 +00004779 break;
4780
4781 case 0xE8 ... 0xEF: /* FUCOMP %st(0),%st(?) */
4782 r_dst = (UInt)modrm - 0xE8;
sewardj2d49b432005-02-01 00:37:06 +00004783 DIP("fucomp %%st(0),%%st(%d)\n", (Int)r_dst);
sewardjc4be80c2004-09-10 16:17:45 +00004784 /* This forces C1 to zero, which isn't right. */
4785 put_C3210(
4786 binop( Iop_And32,
4787 binop(Iop_Shl32,
4788 binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
4789 mkU8(8)),
4790 mkU32(0x4500)
4791 ));
sewardjbdc7d212004-09-09 02:46:40 +00004792 fp_pop();
4793 break;
4794
sewardj5bd4d162004-11-10 13:02:48 +00004795 default:
sewardja58ea662004-08-15 03:12:41 +00004796 goto decode_fail;
sewardj5bd4d162004-11-10 13:02:48 +00004797 }
sewardjd1725d12004-08-12 20:46:53 +00004798 }
4799 }
4800
4801 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDE opcodes +-+-+-+-+-+-+-+ */
4802 else
4803 if (first_opcode == 0xDE) {
sewardjbdc7d212004-09-09 02:46:40 +00004804
4805 if (modrm < 0xC0) {
sewardjfeeb8a82004-11-30 12:30:11 +00004806
4807 /* bits 5,4,3 are an opcode extension, and the modRM also
4808 specifies an address. */
4809 IROp fop;
4810 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
4811 delta += len;
4812
4813 switch (gregOfRM(modrm)) {
4814
4815 case 0: /* FIADD m16int */ /* ST(0) += m16int */
sewardj33dd31b2005-01-08 18:17:32 +00004816 DIP("fiaddw %s\n", dis_buf);
sewardjfeeb8a82004-11-30 12:30:11 +00004817 fop = Iop_AddF64;
4818 goto do_fop_m16;
4819
4820 case 1: /* FIMUL m16int */ /* ST(0) *= m16int */
sewardj33dd31b2005-01-08 18:17:32 +00004821 DIP("fimulw %s\n", dis_buf);
sewardjfeeb8a82004-11-30 12:30:11 +00004822 fop = Iop_MulF64;
4823 goto do_fop_m16;
4824
sewardj071895f2005-07-29 11:28:38 +00004825 case 2: /* FICOM m16int */
4826 DIP("ficomw %s\n", dis_buf);
4827 /* This forces C1 to zero, which isn't right. */
4828 put_C3210(
4829 binop( Iop_And32,
4830 binop(Iop_Shl32,
4831 binop(Iop_CmpF64,
4832 get_ST(0),
4833 unop(Iop_I32toF64,
4834 unop(Iop_16Sto32,
4835 loadLE(Ity_I16,mkexpr(addr))))),
4836 mkU8(8)),
4837 mkU32(0x4500)
4838 ));
4839 break;
4840
4841 case 3: /* FICOMP m16int */
4842 DIP("ficompw %s\n", dis_buf);
4843 /* This forces C1 to zero, which isn't right. */
4844 put_C3210(
4845 binop( Iop_And32,
4846 binop(Iop_Shl32,
4847 binop(Iop_CmpF64,
4848 get_ST(0),
4849 unop(Iop_I32toF64,
4850 unop(Iop_16Sto32,
sewardjf1b5b1a2006-02-03 22:54:17 +00004851 loadLE(Ity_I16,mkexpr(addr))))),
sewardj071895f2005-07-29 11:28:38 +00004852 mkU8(8)),
4853 mkU32(0x4500)
4854 ));
4855 fp_pop();
4856 break;
4857
sewardjfeeb8a82004-11-30 12:30:11 +00004858 case 4: /* FISUB m16int */ /* ST(0) -= m16int */
sewardj33dd31b2005-01-08 18:17:32 +00004859 DIP("fisubw %s\n", dis_buf);
sewardjfeeb8a82004-11-30 12:30:11 +00004860 fop = Iop_SubF64;
4861 goto do_fop_m16;
4862
4863 case 5: /* FISUBR m16int */ /* ST(0) = m16int - ST(0) */
sewardj33dd31b2005-01-08 18:17:32 +00004864 DIP("fisubrw %s\n", dis_buf);
sewardjfeeb8a82004-11-30 12:30:11 +00004865 fop = Iop_SubF64;
4866 goto do_foprev_m16;
4867
4868 case 6: /* FIDIV m16int */ /* ST(0) /= m16int */
sewardj33dd31b2005-01-08 18:17:32 +00004869 DIP("fisubw %s\n", dis_buf);
sewardjfeeb8a82004-11-30 12:30:11 +00004870 fop = Iop_DivF64;
4871 goto do_fop_m16;
4872
4873 case 7: /* FIDIVR m16int */ /* ST(0) = m16int / ST(0) */
sewardj33dd31b2005-01-08 18:17:32 +00004874 DIP("fidivrw %s\n", dis_buf);
sewardjfeeb8a82004-11-30 12:30:11 +00004875 fop = Iop_DivF64;
4876 goto do_foprev_m16;
4877
4878 do_fop_m16:
4879 put_ST_UNCHECKED(0,
sewardjf1b5b1a2006-02-03 22:54:17 +00004880 triop(fop,
4881 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardjfeeb8a82004-11-30 12:30:11 +00004882 get_ST(0),
4883 unop(Iop_I32toF64,
4884 unop(Iop_16Sto32,
4885 loadLE(Ity_I16, mkexpr(addr))))));
4886 break;
4887
4888 do_foprev_m16:
4889 put_ST_UNCHECKED(0,
sewardjf1b5b1a2006-02-03 22:54:17 +00004890 triop(fop,
4891 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardjfeeb8a82004-11-30 12:30:11 +00004892 unop(Iop_I32toF64,
4893 unop(Iop_16Sto32,
4894 loadLE(Ity_I16, mkexpr(addr)))),
4895 get_ST(0)));
4896 break;
4897
4898 default:
4899 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
4900 vex_printf("first_opcode == 0xDE\n");
4901 goto decode_fail;
4902 }
sewardjbdc7d212004-09-09 02:46:40 +00004903
4904 } else {
4905
4906 delta++;
sewardj5bd4d162004-11-10 13:02:48 +00004907 switch (modrm) {
sewardjbdc7d212004-09-09 02:46:40 +00004908
sewardjcfded9a2004-09-09 11:44:16 +00004909 case 0xC0 ... 0xC7: /* FADDP %st(0),%st(?) */
4910 fp_do_op_ST_ST ( "add", Iop_AddF64, 0, modrm - 0xC0, True );
4911 break;
4912
sewardjbdc7d212004-09-09 02:46:40 +00004913 case 0xC8 ... 0xCF: /* FMULP %st(0),%st(?) */
4914 fp_do_op_ST_ST ( "mul", Iop_MulF64, 0, modrm - 0xC8, True );
4915 break;
4916
sewardje166ed02004-10-25 02:27:01 +00004917 case 0xD9: /* FCOMPP %st(0),%st(1) */
4918 DIP("fuompp %%st(0),%%st(1)\n");
4919 /* This forces C1 to zero, which isn't right. */
4920 put_C3210(
4921 binop( Iop_And32,
4922 binop(Iop_Shl32,
4923 binop(Iop_CmpF64, get_ST(0), get_ST(1)),
4924 mkU8(8)),
4925 mkU32(0x4500)
4926 ));
4927 fp_pop();
4928 fp_pop();
4929 break;
4930
sewardjcfded9a2004-09-09 11:44:16 +00004931 case 0xE0 ... 0xE7: /* FSUBRP %st(0),%st(?) */
4932 fp_do_oprev_ST_ST ( "subr", Iop_SubF64, 0, modrm - 0xE0, True );
4933 break;
4934
sewardj3fd5e572004-09-09 22:43:51 +00004935 case 0xE8 ... 0xEF: /* FSUBP %st(0),%st(?) */
4936 fp_do_op_ST_ST ( "sub", Iop_SubF64, 0, modrm - 0xE8, True );
4937 break;
4938
sewardjbdc7d212004-09-09 02:46:40 +00004939 case 0xF0 ... 0xF7: /* FDIVRP %st(0),%st(?) */
4940 fp_do_oprev_ST_ST ( "divr", Iop_DivF64, 0, modrm - 0xF0, True );
4941 break;
4942
4943 case 0xF8 ... 0xFF: /* FDIVP %st(0),%st(?) */
4944 fp_do_op_ST_ST ( "div", Iop_DivF64, 0, modrm - 0xF8, True );
4945 break;
4946
4947 default:
4948 goto decode_fail;
sewardj5bd4d162004-11-10 13:02:48 +00004949 }
sewardjbdc7d212004-09-09 02:46:40 +00004950
4951 }
sewardjd1725d12004-08-12 20:46:53 +00004952 }
4953
4954 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDF opcodes +-+-+-+-+-+-+-+ */
4955 else
4956 if (first_opcode == 0xDF) {
sewardj89cd0932004-09-08 18:23:25 +00004957
4958 if (modrm < 0xC0) {
4959
sewardjfeeb8a82004-11-30 12:30:11 +00004960 /* bits 5,4,3 are an opcode extension, and the modRM also
sewardj89cd0932004-09-08 18:23:25 +00004961 specifies an address. */
4962 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
4963 delta += len;
4964
4965 switch (gregOfRM(modrm)) {
4966
sewardj883b00b2004-09-11 09:30:24 +00004967 case 0: /* FILD m16int */
4968 DIP("fildw %s\n", dis_buf);
4969 fp_push();
4970 put_ST(0, unop(Iop_I32toF64,
4971 unop(Iop_16Sto32,
4972 loadLE(Ity_I16, mkexpr(addr)))));
4973 break;
4974
sewardjdd5d2042006-08-03 15:03:19 +00004975 case 1: /* FISTTPS m16 (SSE3) */
4976 DIP("fisttps %s\n", dis_buf);
4977 storeLE( mkexpr(addr),
4978 binop(Iop_F64toI16, mkU32(Irrm_ZERO), get_ST(0)) );
4979 fp_pop();
4980 break;
4981
sewardj37158712004-10-15 21:23:12 +00004982 case 2: /* FIST m16 */
sewardj33dd31b2005-01-08 18:17:32 +00004983 DIP("fistp %s\n", dis_buf);
sewardj37158712004-10-15 21:23:12 +00004984 storeLE( mkexpr(addr),
4985 binop(Iop_F64toI16, get_roundingmode(), get_ST(0)) );
4986 break;
4987
sewardj89cd0932004-09-08 18:23:25 +00004988 case 3: /* FISTP m16 */
sewardj33dd31b2005-01-08 18:17:32 +00004989 DIP("fistps %s\n", dis_buf);
sewardj8f3debf2004-09-08 23:42:23 +00004990 storeLE( mkexpr(addr),
4991 binop(Iop_F64toI16, get_roundingmode(), get_ST(0)) );
4992 fp_pop();
sewardj89cd0932004-09-08 18:23:25 +00004993 break;
4994
sewardj89cd0932004-09-08 18:23:25 +00004995 case 5: /* FILD m64 */
4996 DIP("fildll %s\n", dis_buf);
4997 fp_push();
sewardj4cb918d2004-12-03 19:43:31 +00004998 put_ST(0, binop(Iop_I64toF64,
4999 get_roundingmode(),
5000 loadLE(Ity_I64, mkexpr(addr))));
sewardj89cd0932004-09-08 18:23:25 +00005001 break;
sewardj89cd0932004-09-08 18:23:25 +00005002
sewardjcfded9a2004-09-09 11:44:16 +00005003 case 7: /* FISTP m64 */
sewardj33dd31b2005-01-08 18:17:32 +00005004 DIP("fistpll %s\n", dis_buf);
sewardjcfded9a2004-09-09 11:44:16 +00005005 storeLE( mkexpr(addr),
5006 binop(Iop_F64toI64, get_roundingmode(), get_ST(0)) );
5007 fp_pop();
5008 break;
5009
sewardj89cd0932004-09-08 18:23:25 +00005010 default:
5011 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
5012 vex_printf("first_opcode == 0xDF\n");
5013 goto decode_fail;
5014 }
5015
5016 } else {
sewardjbdc7d212004-09-09 02:46:40 +00005017
5018 delta++;
sewardj5bd4d162004-11-10 13:02:48 +00005019 switch (modrm) {
sewardjbdc7d212004-09-09 02:46:40 +00005020
sewardj8fb88692005-07-29 11:57:00 +00005021 case 0xC0: /* FFREEP %st(0) */
5022 DIP("ffreep %%st(%d)\n", 0);
5023 put_ST_TAG ( 0, mkU8(0) );
5024 fp_pop();
5025 break;
5026
sewardjbdc7d212004-09-09 02:46:40 +00005027 case 0xE0: /* FNSTSW %ax */
5028 DIP("fnstsw %%ax\n");
sewardjd24931d2005-03-20 12:51:39 +00005029 /* Get the FPU status word value and dump it in %AX. */
sewardj1d2e77f2008-06-04 09:10:38 +00005030 if (0) {
5031 /* The obvious thing to do is simply dump the 16-bit
5032 status word value in %AX. However, due to a
5033 limitation in Memcheck's origin tracking
5034 machinery, this causes Memcheck not to track the
5035 origin of any undefinedness into %AH (only into
5036 %AL/%AX/%EAX), which means origins are lost in
5037 the sequence "fnstsw %ax; test $M,%ah; jcond .." */
5038 putIReg(2, R_EAX, get_FPU_sw());
5039 } else {
5040 /* So a somewhat lame kludge is to make it very
5041 clear to Memcheck that the value is written to
5042 both %AH and %AL. This generates marginally
5043 worse code, but I don't think it matters much. */
5044 IRTemp t16 = newTemp(Ity_I16);
5045 assign(t16, get_FPU_sw());
5046 putIReg( 1, R_AL, unop(Iop_16to8, mkexpr(t16)) );
5047 putIReg( 1, R_AH, unop(Iop_16HIto8, mkexpr(t16)) );
5048 }
sewardjbdc7d212004-09-09 02:46:40 +00005049 break;
5050
sewardj883b00b2004-09-11 09:30:24 +00005051 case 0xE8 ... 0xEF: /* FUCOMIP %st(0),%st(?) */
sewardj8308aad2004-09-12 11:09:54 +00005052 fp_do_ucomi_ST0_STi( (UInt)modrm - 0xE8, True );
sewardj883b00b2004-09-11 09:30:24 +00005053 break;
5054
sewardjfeeb8a82004-11-30 12:30:11 +00005055 case 0xF0 ... 0xF7: /* FCOMIP %st(0),%st(?) */
5056 /* not really right since COMIP != UCOMIP */
5057 fp_do_ucomi_ST0_STi( (UInt)modrm - 0xF0, True );
5058 break;
5059
sewardjbdc7d212004-09-09 02:46:40 +00005060 default:
5061 goto decode_fail;
sewardj5bd4d162004-11-10 13:02:48 +00005062 }
sewardj89cd0932004-09-08 18:23:25 +00005063 }
5064
sewardjd1725d12004-08-12 20:46:53 +00005065 }
5066
5067 else
5068 vpanic("dis_FPU(x86): invalid primary opcode");
5069
sewardj69d9d662004-10-14 21:58:52 +00005070 *decode_ok = True;
5071 return delta;
5072
sewardjd1725d12004-08-12 20:46:53 +00005073 decode_fail:
5074 *decode_ok = False;
5075 return delta;
5076}
5077
5078
sewardj464efa42004-11-19 22:17:29 +00005079/*------------------------------------------------------------*/
5080/*--- ---*/
5081/*--- MMX INSTRUCTIONS ---*/
5082/*--- ---*/
5083/*------------------------------------------------------------*/
sewardja06e5562004-07-14 13:18:05 +00005084
sewardj464efa42004-11-19 22:17:29 +00005085/* Effect of MMX insns on x87 FPU state (table 11-2 of
5086 IA32 arch manual, volume 3):
5087
5088 Read from, or write to MMX register (viz, any insn except EMMS):
5089 * All tags set to Valid (non-empty) -- FPTAGS[i] := nonzero
5090 * FP stack pointer set to zero
5091
5092 EMMS:
5093 * All tags set to Invalid (empty) -- FPTAGS[i] := zero
5094 * FP stack pointer set to zero
5095*/
5096
sewardj4cb918d2004-12-03 19:43:31 +00005097static void do_MMX_preamble ( void )
sewardj464efa42004-11-19 22:17:29 +00005098{
sewardjdd40fdf2006-12-24 02:20:24 +00005099 Int i;
5100 IRRegArray* descr = mkIRRegArray( OFFB_FPTAGS, Ity_I8, 8 );
5101 IRExpr* zero = mkU32(0);
5102 IRExpr* tag1 = mkU8(1);
sewardj464efa42004-11-19 22:17:29 +00005103 put_ftop(zero);
5104 for (i = 0; i < 8; i++)
5105 stmt( IRStmt_PutI( descr, zero, i, tag1 ) );
5106}
5107
sewardj4cb918d2004-12-03 19:43:31 +00005108static void do_EMMS_preamble ( void )
sewardj464efa42004-11-19 22:17:29 +00005109{
sewardjdd40fdf2006-12-24 02:20:24 +00005110 Int i;
5111 IRRegArray* descr = mkIRRegArray( OFFB_FPTAGS, Ity_I8, 8 );
5112 IRExpr* zero = mkU32(0);
5113 IRExpr* tag0 = mkU8(0);
sewardj464efa42004-11-19 22:17:29 +00005114 put_ftop(zero);
5115 for (i = 0; i < 8; i++)
5116 stmt( IRStmt_PutI( descr, zero, i, tag0 ) );
5117}
5118
5119
5120static IRExpr* getMMXReg ( UInt archreg )
5121{
5122 vassert(archreg < 8);
5123 return IRExpr_Get( OFFB_FPREGS + 8 * archreg, Ity_I64 );
5124}
5125
5126
5127static void putMMXReg ( UInt archreg, IRExpr* e )
5128{
5129 vassert(archreg < 8);
sewardjdd40fdf2006-12-24 02:20:24 +00005130 vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_I64);
sewardj464efa42004-11-19 22:17:29 +00005131 stmt( IRStmt_Put( OFFB_FPREGS + 8 * archreg, e ) );
5132}
5133
5134
sewardj38a3f862005-01-13 15:06:51 +00005135/* Helper for non-shift MMX insns. Note this is incomplete in the
5136 sense that it does not first call do_MMX_preamble() -- that is the
5137 responsibility of its caller. */
5138
sewardj464efa42004-11-19 22:17:29 +00005139static
sewardj2d49b432005-02-01 00:37:06 +00005140UInt dis_MMXop_regmem_to_reg ( UChar sorb,
sewardj52d04912005-07-03 00:52:48 +00005141 Int delta,
sewardj2d49b432005-02-01 00:37:06 +00005142 UChar opc,
5143 HChar* name,
5144 Bool show_granularity )
sewardj464efa42004-11-19 22:17:29 +00005145{
sewardjc9a43662004-11-30 18:51:59 +00005146 HChar dis_buf[50];
sewardj63ba4092004-11-21 12:30:18 +00005147 UChar modrm = getIByte(delta);
5148 Bool isReg = epartIsReg(modrm);
5149 IRExpr* argL = NULL;
5150 IRExpr* argR = NULL;
sewardj38a3f862005-01-13 15:06:51 +00005151 IRExpr* argG = NULL;
5152 IRExpr* argE = NULL;
sewardj63ba4092004-11-21 12:30:18 +00005153 IRTemp res = newTemp(Ity_I64);
sewardj464efa42004-11-19 22:17:29 +00005154
sewardj38a3f862005-01-13 15:06:51 +00005155 Bool invG = False;
5156 IROp op = Iop_INVALID;
5157 void* hAddr = NULL;
sewardj2d49b432005-02-01 00:37:06 +00005158 HChar* hName = NULL;
sewardj38a3f862005-01-13 15:06:51 +00005159 Bool eLeft = False;
5160
sewardj2b7a9202004-11-26 19:15:38 +00005161# define XXX(_name) do { hAddr = &_name; hName = #_name; } while (0)
sewardj464efa42004-11-19 22:17:29 +00005162
sewardj464efa42004-11-19 22:17:29 +00005163 switch (opc) {
sewardjb5452082004-12-04 20:33:02 +00005164 /* Original MMX ones */
sewardj38a3f862005-01-13 15:06:51 +00005165 case 0xFC: op = Iop_Add8x8; break;
5166 case 0xFD: op = Iop_Add16x4; break;
5167 case 0xFE: op = Iop_Add32x2; break;
sewardj464efa42004-11-19 22:17:29 +00005168
sewardj38a3f862005-01-13 15:06:51 +00005169 case 0xEC: op = Iop_QAdd8Sx8; break;
5170 case 0xED: op = Iop_QAdd16Sx4; break;
sewardj464efa42004-11-19 22:17:29 +00005171
sewardj38a3f862005-01-13 15:06:51 +00005172 case 0xDC: op = Iop_QAdd8Ux8; break;
5173 case 0xDD: op = Iop_QAdd16Ux4; break;
sewardj464efa42004-11-19 22:17:29 +00005174
sewardj38a3f862005-01-13 15:06:51 +00005175 case 0xF8: op = Iop_Sub8x8; break;
5176 case 0xF9: op = Iop_Sub16x4; break;
5177 case 0xFA: op = Iop_Sub32x2; break;
sewardj464efa42004-11-19 22:17:29 +00005178
sewardj38a3f862005-01-13 15:06:51 +00005179 case 0xE8: op = Iop_QSub8Sx8; break;
5180 case 0xE9: op = Iop_QSub16Sx4; break;
sewardj464efa42004-11-19 22:17:29 +00005181
sewardj38a3f862005-01-13 15:06:51 +00005182 case 0xD8: op = Iop_QSub8Ux8; break;
5183 case 0xD9: op = Iop_QSub16Ux4; break;
sewardj464efa42004-11-19 22:17:29 +00005184
sewardj38a3f862005-01-13 15:06:51 +00005185 case 0xE5: op = Iop_MulHi16Sx4; break;
5186 case 0xD5: op = Iop_Mul16x4; break;
5187 case 0xF5: XXX(x86g_calculate_mmx_pmaddwd); break;
sewardj4340dac2004-11-20 13:17:04 +00005188
sewardj38a3f862005-01-13 15:06:51 +00005189 case 0x74: op = Iop_CmpEQ8x8; break;
5190 case 0x75: op = Iop_CmpEQ16x4; break;
5191 case 0x76: op = Iop_CmpEQ32x2; break;
sewardj4340dac2004-11-20 13:17:04 +00005192
sewardj38a3f862005-01-13 15:06:51 +00005193 case 0x64: op = Iop_CmpGT8Sx8; break;
5194 case 0x65: op = Iop_CmpGT16Sx4; break;
5195 case 0x66: op = Iop_CmpGT32Sx2; break;
sewardj63ba4092004-11-21 12:30:18 +00005196
sewardj38a3f862005-01-13 15:06:51 +00005197 case 0x6B: op = Iop_QNarrow32Sx2; eLeft = True; break;
5198 case 0x63: op = Iop_QNarrow16Sx4; eLeft = True; break;
5199 case 0x67: op = Iop_QNarrow16Ux4; eLeft = True; break;
sewardj63ba4092004-11-21 12:30:18 +00005200
sewardj38a3f862005-01-13 15:06:51 +00005201 case 0x68: op = Iop_InterleaveHI8x8; eLeft = True; break;
5202 case 0x69: op = Iop_InterleaveHI16x4; eLeft = True; break;
5203 case 0x6A: op = Iop_InterleaveHI32x2; eLeft = True; break;
sewardj63ba4092004-11-21 12:30:18 +00005204
sewardj38a3f862005-01-13 15:06:51 +00005205 case 0x60: op = Iop_InterleaveLO8x8; eLeft = True; break;
5206 case 0x61: op = Iop_InterleaveLO16x4; eLeft = True; break;
5207 case 0x62: op = Iop_InterleaveLO32x2; eLeft = True; break;
sewardj63ba4092004-11-21 12:30:18 +00005208
sewardj38a3f862005-01-13 15:06:51 +00005209 case 0xDB: op = Iop_And64; break;
5210 case 0xDF: op = Iop_And64; invG = True; break;
5211 case 0xEB: op = Iop_Or64; break;
5212 case 0xEF: /* Possibly do better here if argL and argR are the
5213 same reg */
5214 op = Iop_Xor64; break;
sewardj464efa42004-11-19 22:17:29 +00005215
sewardjb5452082004-12-04 20:33:02 +00005216 /* Introduced in SSE1 */
sewardj38a3f862005-01-13 15:06:51 +00005217 case 0xE0: op = Iop_Avg8Ux8; break;
5218 case 0xE3: op = Iop_Avg16Ux4; break;
5219 case 0xEE: op = Iop_Max16Sx4; break;
5220 case 0xDE: op = Iop_Max8Ux8; break;
5221 case 0xEA: op = Iop_Min16Sx4; break;
5222 case 0xDA: op = Iop_Min8Ux8; break;
5223 case 0xE4: op = Iop_MulHi16Ux4; break;
5224 case 0xF6: XXX(x86g_calculate_mmx_psadbw); break;
sewardjb5452082004-12-04 20:33:02 +00005225
sewardj164f9272004-12-09 00:39:32 +00005226 /* Introduced in SSE2 */
sewardj38a3f862005-01-13 15:06:51 +00005227 case 0xD4: op = Iop_Add64; break;
5228 case 0xFB: op = Iop_Sub64; break;
sewardj164f9272004-12-09 00:39:32 +00005229
sewardj464efa42004-11-19 22:17:29 +00005230 default:
5231 vex_printf("\n0x%x\n", (Int)opc);
5232 vpanic("dis_MMXop_regmem_to_reg");
5233 }
5234
5235# undef XXX
5236
sewardj38a3f862005-01-13 15:06:51 +00005237 argG = getMMXReg(gregOfRM(modrm));
5238 if (invG)
5239 argG = unop(Iop_Not64, argG);
sewardj63ba4092004-11-21 12:30:18 +00005240
sewardj464efa42004-11-19 22:17:29 +00005241 if (isReg) {
sewardj464efa42004-11-19 22:17:29 +00005242 delta++;
sewardj38a3f862005-01-13 15:06:51 +00005243 argE = getMMXReg(eregOfRM(modrm));
sewardj464efa42004-11-19 22:17:29 +00005244 } else {
5245 Int len;
5246 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5247 delta += len;
sewardj38a3f862005-01-13 15:06:51 +00005248 argE = loadLE(Ity_I64, mkexpr(addr));
sewardj464efa42004-11-19 22:17:29 +00005249 }
5250
sewardj38a3f862005-01-13 15:06:51 +00005251 if (eLeft) {
5252 argL = argE;
5253 argR = argG;
5254 } else {
5255 argL = argG;
5256 argR = argE;
5257 }
5258
5259 if (op != Iop_INVALID) {
5260 vassert(hName == NULL);
5261 vassert(hAddr == NULL);
5262 assign(res, binop(op, argL, argR));
5263 } else {
5264 vassert(hName != NULL);
5265 vassert(hAddr != NULL);
5266 assign( res,
5267 mkIRExprCCall(
5268 Ity_I64,
5269 0/*regparms*/, hName, hAddr,
5270 mkIRExprVec_2( argL, argR )
5271 )
5272 );
sewardj63ba4092004-11-21 12:30:18 +00005273 }
5274
5275 putMMXReg( gregOfRM(modrm), mkexpr(res) );
5276
sewardj464efa42004-11-19 22:17:29 +00005277 DIP("%s%s %s, %s\n",
sewardj2d49b432005-02-01 00:37:06 +00005278 name, show_granularity ? nameMMXGran(opc & 3) : "",
sewardj464efa42004-11-19 22:17:29 +00005279 ( isReg ? nameMMXReg(eregOfRM(modrm)) : dis_buf ),
5280 nameMMXReg(gregOfRM(modrm)) );
5281
5282 return delta;
5283}
5284
5285
sewardj38a3f862005-01-13 15:06:51 +00005286/* Vector by scalar shift of G by the amount specified at the bottom
5287 of E. This is a straight copy of dis_SSE_shiftG_byE. */
5288
sewardj52d04912005-07-03 00:52:48 +00005289static UInt dis_MMX_shiftG_byE ( UChar sorb, Int delta,
sewardj38a3f862005-01-13 15:06:51 +00005290 HChar* opname, IROp op )
5291{
5292 HChar dis_buf[50];
5293 Int alen, size;
5294 IRTemp addr;
5295 Bool shl, shr, sar;
5296 UChar rm = getIByte(delta);
5297 IRTemp g0 = newTemp(Ity_I64);
5298 IRTemp g1 = newTemp(Ity_I64);
5299 IRTemp amt = newTemp(Ity_I32);
5300 IRTemp amt8 = newTemp(Ity_I8);
5301
5302 if (epartIsReg(rm)) {
5303 assign( amt, unop(Iop_64to32, getMMXReg(eregOfRM(rm))) );
5304 DIP("%s %s,%s\n", opname,
5305 nameMMXReg(eregOfRM(rm)),
5306 nameMMXReg(gregOfRM(rm)) );
5307 delta++;
5308 } else {
5309 addr = disAMode ( &alen, sorb, delta, dis_buf );
5310 assign( amt, loadLE(Ity_I32, mkexpr(addr)) );
5311 DIP("%s %s,%s\n", opname,
5312 dis_buf,
5313 nameMMXReg(gregOfRM(rm)) );
5314 delta += alen;
5315 }
5316 assign( g0, getMMXReg(gregOfRM(rm)) );
5317 assign( amt8, unop(Iop_32to8, mkexpr(amt)) );
5318
5319 shl = shr = sar = False;
5320 size = 0;
5321 switch (op) {
5322 case Iop_ShlN16x4: shl = True; size = 32; break;
5323 case Iop_ShlN32x2: shl = True; size = 32; break;
5324 case Iop_Shl64: shl = True; size = 64; break;
5325 case Iop_ShrN16x4: shr = True; size = 16; break;
5326 case Iop_ShrN32x2: shr = True; size = 32; break;
5327 case Iop_Shr64: shr = True; size = 64; break;
5328 case Iop_SarN16x4: sar = True; size = 16; break;
5329 case Iop_SarN32x2: sar = True; size = 32; break;
5330 default: vassert(0);
5331 }
5332
5333 if (shl || shr) {
5334 assign(
5335 g1,
5336 IRExpr_Mux0X(
5337 unop(Iop_1Uto8,binop(Iop_CmpLT32U,mkexpr(amt),mkU32(size))),
5338 mkU64(0),
5339 binop(op, mkexpr(g0), mkexpr(amt8))
5340 )
5341 );
5342 } else
5343 if (sar) {
5344 assign(
5345 g1,
5346 IRExpr_Mux0X(
5347 unop(Iop_1Uto8,binop(Iop_CmpLT32U,mkexpr(amt),mkU32(size))),
5348 binop(op, mkexpr(g0), mkU8(size-1)),
5349 binop(op, mkexpr(g0), mkexpr(amt8))
5350 )
5351 );
5352 } else {
sewardjba89f4c2005-04-07 17:31:27 +00005353 /*NOTREACHED*/
sewardj38a3f862005-01-13 15:06:51 +00005354 vassert(0);
5355 }
5356
5357 putMMXReg( gregOfRM(rm), mkexpr(g1) );
5358 return delta;
5359}
5360
5361
5362/* Vector by scalar shift of E by an immediate byte. This is a
5363 straight copy of dis_SSE_shiftE_imm. */
5364
5365static
sewardj52d04912005-07-03 00:52:48 +00005366UInt dis_MMX_shiftE_imm ( Int delta, HChar* opname, IROp op )
sewardj38a3f862005-01-13 15:06:51 +00005367{
5368 Bool shl, shr, sar;
5369 UChar rm = getIByte(delta);
5370 IRTemp e0 = newTemp(Ity_I64);
5371 IRTemp e1 = newTemp(Ity_I64);
5372 UChar amt, size;
5373 vassert(epartIsReg(rm));
5374 vassert(gregOfRM(rm) == 2
5375 || gregOfRM(rm) == 4 || gregOfRM(rm) == 6);
sewardj2d49b432005-02-01 00:37:06 +00005376 amt = getIByte(delta+1);
sewardj38a3f862005-01-13 15:06:51 +00005377 delta += 2;
5378 DIP("%s $%d,%s\n", opname,
5379 (Int)amt,
5380 nameMMXReg(eregOfRM(rm)) );
5381
5382 assign( e0, getMMXReg(eregOfRM(rm)) );
5383
5384 shl = shr = sar = False;
5385 size = 0;
5386 switch (op) {
5387 case Iop_ShlN16x4: shl = True; size = 16; break;
5388 case Iop_ShlN32x2: shl = True; size = 32; break;
5389 case Iop_Shl64: shl = True; size = 64; break;
5390 case Iop_SarN16x4: sar = True; size = 16; break;
5391 case Iop_SarN32x2: sar = True; size = 32; break;
5392 case Iop_ShrN16x4: shr = True; size = 16; break;
5393 case Iop_ShrN32x2: shr = True; size = 32; break;
5394 case Iop_Shr64: shr = True; size = 64; break;
5395 default: vassert(0);
5396 }
5397
5398 if (shl || shr) {
sewardjba89f4c2005-04-07 17:31:27 +00005399 assign( e1, amt >= size
5400 ? mkU64(0)
5401 : binop(op, mkexpr(e0), mkU8(amt))
5402 );
sewardj38a3f862005-01-13 15:06:51 +00005403 } else
5404 if (sar) {
sewardjba89f4c2005-04-07 17:31:27 +00005405 assign( e1, amt >= size
5406 ? binop(op, mkexpr(e0), mkU8(size-1))
5407 : binop(op, mkexpr(e0), mkU8(amt))
5408 );
sewardj38a3f862005-01-13 15:06:51 +00005409 } else {
sewardjba89f4c2005-04-07 17:31:27 +00005410 /*NOTREACHED*/
sewardj38a3f862005-01-13 15:06:51 +00005411 vassert(0);
5412 }
5413
5414 putMMXReg( eregOfRM(rm), mkexpr(e1) );
5415 return delta;
5416}
5417
5418
5419/* Completely handle all MMX instructions except emms. */
sewardj464efa42004-11-19 22:17:29 +00005420
5421static
sewardj52d04912005-07-03 00:52:48 +00005422UInt dis_MMX ( Bool* decode_ok, UChar sorb, Int sz, Int delta )
sewardj464efa42004-11-19 22:17:29 +00005423{
5424 Int len;
5425 UChar modrm;
sewardjc9a43662004-11-30 18:51:59 +00005426 HChar dis_buf[50];
sewardj464efa42004-11-19 22:17:29 +00005427 UChar opc = getIByte(delta);
5428 delta++;
5429
sewardj4cb918d2004-12-03 19:43:31 +00005430 /* dis_MMX handles all insns except emms. */
5431 do_MMX_preamble();
sewardj464efa42004-11-19 22:17:29 +00005432
5433 switch (opc) {
5434
sewardj2b7a9202004-11-26 19:15:38 +00005435 case 0x6E:
5436 /* MOVD (src)ireg-or-mem (E), (dst)mmxreg (G)*/
sewardj9df271d2004-12-31 22:37:42 +00005437 if (sz != 4)
5438 goto mmx_decode_failure;
sewardj2b7a9202004-11-26 19:15:38 +00005439 modrm = getIByte(delta);
5440 if (epartIsReg(modrm)) {
5441 delta++;
5442 putMMXReg(
5443 gregOfRM(modrm),
5444 binop( Iop_32HLto64,
5445 mkU32(0),
5446 getIReg(4, eregOfRM(modrm)) ) );
5447 DIP("movd %s, %s\n",
5448 nameIReg(4,eregOfRM(modrm)), nameMMXReg(gregOfRM(modrm)));
5449 } else {
5450 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5451 delta += len;
5452 putMMXReg(
5453 gregOfRM(modrm),
5454 binop( Iop_32HLto64,
5455 mkU32(0),
5456 loadLE(Ity_I32, mkexpr(addr)) ) );
5457 DIP("movd %s, %s\n", dis_buf, nameMMXReg(gregOfRM(modrm)));
5458 }
5459 break;
5460
5461 case 0x7E: /* MOVD (src)mmxreg (G), (dst)ireg-or-mem (E) */
sewardj9df271d2004-12-31 22:37:42 +00005462 if (sz != 4)
5463 goto mmx_decode_failure;
sewardj2b7a9202004-11-26 19:15:38 +00005464 modrm = getIByte(delta);
5465 if (epartIsReg(modrm)) {
5466 delta++;
5467 putIReg( 4, eregOfRM(modrm),
5468 unop(Iop_64to32, getMMXReg(gregOfRM(modrm)) ) );
5469 DIP("movd %s, %s\n",
5470 nameMMXReg(gregOfRM(modrm)), nameIReg(4,eregOfRM(modrm)));
5471 } else {
5472 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5473 delta += len;
5474 storeLE( mkexpr(addr),
5475 unop(Iop_64to32, getMMXReg(gregOfRM(modrm)) ) );
5476 DIP("movd %s, %s\n", nameMMXReg(gregOfRM(modrm)), dis_buf);
5477 }
5478 break;
5479
sewardj464efa42004-11-19 22:17:29 +00005480 case 0x6F:
5481 /* MOVQ (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005482 if (sz != 4)
5483 goto mmx_decode_failure;
sewardj464efa42004-11-19 22:17:29 +00005484 modrm = getIByte(delta);
5485 if (epartIsReg(modrm)) {
5486 delta++;
5487 putMMXReg( gregOfRM(modrm), getMMXReg(eregOfRM(modrm)) );
5488 DIP("movq %s, %s\n",
5489 nameMMXReg(eregOfRM(modrm)), nameMMXReg(gregOfRM(modrm)));
5490 } else {
5491 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5492 delta += len;
5493 putMMXReg( gregOfRM(modrm), loadLE(Ity_I64, mkexpr(addr)) );
5494 DIP("movq %s, %s\n",
5495 dis_buf, nameMMXReg(gregOfRM(modrm)));
5496 }
5497 break;
5498
5499 case 0x7F:
5500 /* MOVQ (src)mmxreg, (dst)mmxreg-or-mem */
sewardj9df271d2004-12-31 22:37:42 +00005501 if (sz != 4)
5502 goto mmx_decode_failure;
sewardj464efa42004-11-19 22:17:29 +00005503 modrm = getIByte(delta);
5504 if (epartIsReg(modrm)) {
sewardj9ca26402005-10-03 02:44:01 +00005505 delta++;
5506 putMMXReg( eregOfRM(modrm), getMMXReg(gregOfRM(modrm)) );
5507 DIP("movq %s, %s\n",
5508 nameMMXReg(gregOfRM(modrm)), nameMMXReg(eregOfRM(modrm)));
sewardj464efa42004-11-19 22:17:29 +00005509 } else {
5510 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5511 delta += len;
sewardj893aada2004-11-29 19:57:54 +00005512 storeLE( mkexpr(addr), getMMXReg(gregOfRM(modrm)) );
sewardj464efa42004-11-19 22:17:29 +00005513 DIP("mov(nt)q %s, %s\n",
5514 nameMMXReg(gregOfRM(modrm)), dis_buf);
5515 }
5516 break;
5517
sewardj4340dac2004-11-20 13:17:04 +00005518 case 0xFC:
5519 case 0xFD:
5520 case 0xFE: /* PADDgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005521 if (sz != 4)
5522 goto mmx_decode_failure;
sewardj464efa42004-11-19 22:17:29 +00005523 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "padd", True );
5524 break;
5525
sewardj4340dac2004-11-20 13:17:04 +00005526 case 0xEC:
5527 case 0xED: /* PADDSgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005528 if (sz != 4)
5529 goto mmx_decode_failure;
sewardj464efa42004-11-19 22:17:29 +00005530 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "padds", True );
5531 break;
5532
sewardj4340dac2004-11-20 13:17:04 +00005533 case 0xDC:
5534 case 0xDD: /* PADDUSgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005535 if (sz != 4)
5536 goto mmx_decode_failure;
sewardj464efa42004-11-19 22:17:29 +00005537 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "paddus", True );
5538 break;
5539
sewardj4340dac2004-11-20 13:17:04 +00005540 case 0xF8:
5541 case 0xF9:
5542 case 0xFA: /* PSUBgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005543 if (sz != 4)
5544 goto mmx_decode_failure;
sewardj464efa42004-11-19 22:17:29 +00005545 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "psub", True );
5546 break;
5547
sewardj4340dac2004-11-20 13:17:04 +00005548 case 0xE8:
5549 case 0xE9: /* PSUBSgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005550 if (sz != 4)
5551 goto mmx_decode_failure;
sewardj464efa42004-11-19 22:17:29 +00005552 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "psubs", True );
5553 break;
5554
sewardj4340dac2004-11-20 13:17:04 +00005555 case 0xD8:
5556 case 0xD9: /* PSUBUSgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005557 if (sz != 4)
5558 goto mmx_decode_failure;
sewardj464efa42004-11-19 22:17:29 +00005559 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "psubus", True );
5560 break;
5561
5562 case 0xE5: /* PMULHW (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005563 if (sz != 4)
5564 goto mmx_decode_failure;
sewardj464efa42004-11-19 22:17:29 +00005565 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pmulhw", False );
5566 break;
5567
5568 case 0xD5: /* PMULLW (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005569 if (sz != 4)
5570 goto mmx_decode_failure;
sewardj464efa42004-11-19 22:17:29 +00005571 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pmullw", False );
5572 break;
5573
sewardj4340dac2004-11-20 13:17:04 +00005574 case 0xF5: /* PMADDWD (src)mmxreg-or-mem, (dst)mmxreg */
5575 vassert(sz == 4);
5576 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pmaddwd", False );
5577 break;
5578
5579 case 0x74:
5580 case 0x75:
5581 case 0x76: /* PCMPEQgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005582 if (sz != 4)
5583 goto mmx_decode_failure;
sewardj4340dac2004-11-20 13:17:04 +00005584 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pcmpeq", True );
5585 break;
5586
5587 case 0x64:
5588 case 0x65:
5589 case 0x66: /* PCMPGTgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005590 if (sz != 4)
5591 goto mmx_decode_failure;
sewardj4340dac2004-11-20 13:17:04 +00005592 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pcmpgt", True );
5593 break;
5594
sewardj63ba4092004-11-21 12:30:18 +00005595 case 0x6B: /* PACKSSDW (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005596 if (sz != 4)
5597 goto mmx_decode_failure;
sewardj63ba4092004-11-21 12:30:18 +00005598 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "packssdw", False );
5599 break;
5600
5601 case 0x63: /* PACKSSWB (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005602 if (sz != 4)
5603 goto mmx_decode_failure;
sewardj63ba4092004-11-21 12:30:18 +00005604 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "packsswb", False );
5605 break;
5606
5607 case 0x67: /* PACKUSWB (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005608 if (sz != 4)
5609 goto mmx_decode_failure;
sewardj63ba4092004-11-21 12:30:18 +00005610 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "packuswb", False );
5611 break;
5612
5613 case 0x68:
5614 case 0x69:
5615 case 0x6A: /* PUNPCKHgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005616 if (sz != 4)
5617 goto mmx_decode_failure;
sewardj63ba4092004-11-21 12:30:18 +00005618 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "punpckh", True );
5619 break;
5620
5621 case 0x60:
5622 case 0x61:
5623 case 0x62: /* PUNPCKLgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005624 if (sz != 4)
5625 goto mmx_decode_failure;
sewardj63ba4092004-11-21 12:30:18 +00005626 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "punpckl", True );
5627 break;
5628
5629 case 0xDB: /* PAND (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005630 if (sz != 4)
5631 goto mmx_decode_failure;
sewardj63ba4092004-11-21 12:30:18 +00005632 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pand", False );
5633 break;
5634
5635 case 0xDF: /* PANDN (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005636 if (sz != 4)
5637 goto mmx_decode_failure;
sewardj63ba4092004-11-21 12:30:18 +00005638 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pandn", False );
5639 break;
5640
5641 case 0xEB: /* POR (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005642 if (sz != 4)
5643 goto mmx_decode_failure;
sewardj63ba4092004-11-21 12:30:18 +00005644 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "por", False );
5645 break;
5646
5647 case 0xEF: /* PXOR (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005648 if (sz != 4)
5649 goto mmx_decode_failure;
sewardj63ba4092004-11-21 12:30:18 +00005650 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pxor", False );
sewardj38a3f862005-01-13 15:06:51 +00005651 break;
sewardj63ba4092004-11-21 12:30:18 +00005652
sewardj38a3f862005-01-13 15:06:51 +00005653# define SHIFT_BY_REG(_name,_op) \
5654 delta = dis_MMX_shiftG_byE(sorb, delta, _name, _op); \
5655 break;
sewardj8d14a592004-11-21 17:04:50 +00005656
sewardj38a3f862005-01-13 15:06:51 +00005657 /* PSLLgg (src)mmxreg-or-mem, (dst)mmxreg */
5658 case 0xF1: SHIFT_BY_REG("psllw", Iop_ShlN16x4);
5659 case 0xF2: SHIFT_BY_REG("pslld", Iop_ShlN32x2);
5660 case 0xF3: SHIFT_BY_REG("psllq", Iop_Shl64);
sewardj8d14a592004-11-21 17:04:50 +00005661
sewardj38a3f862005-01-13 15:06:51 +00005662 /* PSRLgg (src)mmxreg-or-mem, (dst)mmxreg */
5663 case 0xD1: SHIFT_BY_REG("psrlw", Iop_ShrN16x4);
5664 case 0xD2: SHIFT_BY_REG("psrld", Iop_ShrN32x2);
5665 case 0xD3: SHIFT_BY_REG("psrlq", Iop_Shr64);
5666
5667 /* PSRAgg (src)mmxreg-or-mem, (dst)mmxreg */
5668 case 0xE1: SHIFT_BY_REG("psraw", Iop_SarN16x4);
5669 case 0xE2: SHIFT_BY_REG("psrad", Iop_SarN32x2);
5670
5671# undef SHIFT_BY_REG
sewardj8d14a592004-11-21 17:04:50 +00005672
sewardj2b7a9202004-11-26 19:15:38 +00005673 case 0x71:
5674 case 0x72:
5675 case 0x73: {
5676 /* (sz==4): PSLLgg/PSRAgg/PSRLgg mmxreg by imm8 */
sewardja8415ff2005-01-21 20:55:36 +00005677 UChar byte2, subopc;
sewardj38a3f862005-01-13 15:06:51 +00005678 if (sz != 4)
5679 goto mmx_decode_failure;
sewardj38a3f862005-01-13 15:06:51 +00005680 byte2 = getIByte(delta); /* amode / sub-opcode */
sewardj9b45b482005-02-07 01:42:18 +00005681 subopc = toUChar( (byte2 >> 3) & 7 );
sewardj2b7a9202004-11-26 19:15:38 +00005682
sewardj38a3f862005-01-13 15:06:51 +00005683# define SHIFT_BY_IMM(_name,_op) \
5684 do { delta = dis_MMX_shiftE_imm(delta,_name,_op); \
5685 } while (0)
sewardj2b7a9202004-11-26 19:15:38 +00005686
sewardj2b7a9202004-11-26 19:15:38 +00005687 if (subopc == 2 /*SRL*/ && opc == 0x71)
sewardj38a3f862005-01-13 15:06:51 +00005688 SHIFT_BY_IMM("psrlw", Iop_ShrN16x4);
sewardj2b7a9202004-11-26 19:15:38 +00005689 else if (subopc == 2 /*SRL*/ && opc == 0x72)
sewardj38a3f862005-01-13 15:06:51 +00005690 SHIFT_BY_IMM("psrld", Iop_ShrN32x2);
sewardj2b7a9202004-11-26 19:15:38 +00005691 else if (subopc == 2 /*SRL*/ && opc == 0x73)
sewardj38a3f862005-01-13 15:06:51 +00005692 SHIFT_BY_IMM("psrlq", Iop_Shr64);
sewardj2b7a9202004-11-26 19:15:38 +00005693
5694 else if (subopc == 4 /*SAR*/ && opc == 0x71)
sewardj38a3f862005-01-13 15:06:51 +00005695 SHIFT_BY_IMM("psraw", Iop_SarN16x4);
sewardj2b7a9202004-11-26 19:15:38 +00005696 else if (subopc == 4 /*SAR*/ && opc == 0x72)
sewardj38a3f862005-01-13 15:06:51 +00005697 SHIFT_BY_IMM("psrad", Iop_SarN32x2);
sewardj2b7a9202004-11-26 19:15:38 +00005698
5699 else if (subopc == 6 /*SHL*/ && opc == 0x71)
sewardj38a3f862005-01-13 15:06:51 +00005700 SHIFT_BY_IMM("psllw", Iop_ShlN16x4);
sewardj2b7a9202004-11-26 19:15:38 +00005701 else if (subopc == 6 /*SHL*/ && opc == 0x72)
sewardj38a3f862005-01-13 15:06:51 +00005702 SHIFT_BY_IMM("pslld", Iop_ShlN32x2);
sewardj2b7a9202004-11-26 19:15:38 +00005703 else if (subopc == 6 /*SHL*/ && opc == 0x73)
sewardj38a3f862005-01-13 15:06:51 +00005704 SHIFT_BY_IMM("psllq", Iop_Shl64);
sewardj2b7a9202004-11-26 19:15:38 +00005705
5706 else goto mmx_decode_failure;
5707
sewardj38a3f862005-01-13 15:06:51 +00005708# undef SHIFT_BY_IMM
sewardj2b7a9202004-11-26 19:15:38 +00005709 break;
5710 }
5711
sewardjd71ba832006-12-27 01:15:29 +00005712 case 0xF7: {
5713 IRTemp addr = newTemp(Ity_I32);
5714 IRTemp regD = newTemp(Ity_I64);
5715 IRTemp regM = newTemp(Ity_I64);
5716 IRTemp mask = newTemp(Ity_I64);
5717 IRTemp olddata = newTemp(Ity_I64);
5718 IRTemp newdata = newTemp(Ity_I64);
5719
5720 modrm = getIByte(delta);
5721 if (sz != 4 || (!epartIsReg(modrm)))
5722 goto mmx_decode_failure;
5723 delta++;
5724
5725 assign( addr, handleSegOverride( sorb, getIReg(4, R_EDI) ));
5726 assign( regM, getMMXReg( eregOfRM(modrm) ));
5727 assign( regD, getMMXReg( gregOfRM(modrm) ));
5728 assign( mask, binop(Iop_SarN8x8, mkexpr(regM), mkU8(7)) );
5729 assign( olddata, loadLE( Ity_I64, mkexpr(addr) ));
5730 assign( newdata,
5731 binop(Iop_Or64,
5732 binop(Iop_And64,
5733 mkexpr(regD),
5734 mkexpr(mask) ),
5735 binop(Iop_And64,
5736 mkexpr(olddata),
5737 unop(Iop_Not64, mkexpr(mask)))) );
5738 storeLE( mkexpr(addr), mkexpr(newdata) );
5739 DIP("maskmovq %s,%s\n", nameMMXReg( eregOfRM(modrm) ),
5740 nameMMXReg( gregOfRM(modrm) ) );
5741 break;
5742 }
5743
sewardj2b7a9202004-11-26 19:15:38 +00005744 /* --- MMX decode failure --- */
sewardj464efa42004-11-19 22:17:29 +00005745 default:
sewardj2b7a9202004-11-26 19:15:38 +00005746 mmx_decode_failure:
sewardj464efa42004-11-19 22:17:29 +00005747 *decode_ok = False;
5748 return delta; /* ignored */
5749
5750 }
5751
5752 *decode_ok = True;
5753 return delta;
5754}
5755
5756
5757/*------------------------------------------------------------*/
5758/*--- More misc arithmetic and other obscure insns. ---*/
5759/*------------------------------------------------------------*/
sewardja06e5562004-07-14 13:18:05 +00005760
5761/* Double length left and right shifts. Apparently only required in
5762 v-size (no b- variant). */
5763static
5764UInt dis_SHLRD_Gv_Ev ( UChar sorb,
sewardj52d04912005-07-03 00:52:48 +00005765 Int delta, UChar modrm,
sewardja06e5562004-07-14 13:18:05 +00005766 Int sz,
5767 IRExpr* shift_amt,
5768 Bool amt_is_literal,
sewardj2d49b432005-02-01 00:37:06 +00005769 HChar* shift_amt_txt,
sewardja06e5562004-07-14 13:18:05 +00005770 Bool left_shift )
5771{
5772 /* shift_amt :: Ity_I8 is the amount to shift. shift_amt_txt is used
5773 for printing it. And eip on entry points at the modrm byte. */
5774 Int len;
sewardjc9a43662004-11-30 18:51:59 +00005775 HChar dis_buf[50];
sewardja06e5562004-07-14 13:18:05 +00005776
sewardj6d2638e2004-07-15 09:38:27 +00005777 IRType ty = szToITy(sz);
5778 IRTemp gsrc = newTemp(ty);
5779 IRTemp esrc = newTemp(ty);
sewardj92d168d2004-11-15 14:22:12 +00005780 IRTemp addr = IRTemp_INVALID;
sewardj6d2638e2004-07-15 09:38:27 +00005781 IRTemp tmpSH = newTemp(Ity_I8);
sewardj92d168d2004-11-15 14:22:12 +00005782 IRTemp tmpL = IRTemp_INVALID;
5783 IRTemp tmpRes = IRTemp_INVALID;
5784 IRTemp tmpSubSh = IRTemp_INVALID;
sewardja06e5562004-07-14 13:18:05 +00005785 IROp mkpair;
5786 IROp getres;
5787 IROp shift;
sewardja06e5562004-07-14 13:18:05 +00005788 IRExpr* mask = NULL;
5789
5790 vassert(sz == 2 || sz == 4);
5791
5792 /* The E-part is the destination; this is shifted. The G-part
5793 supplies bits to be shifted into the E-part, but is not
5794 changed.
5795
5796 If shifting left, form a double-length word with E at the top
5797 and G at the bottom, and shift this left. The result is then in
5798 the high part.
5799
5800 If shifting right, form a double-length word with G at the top
5801 and E at the bottom, and shift this right. The result is then
5802 at the bottom. */
5803
5804 /* Fetch the operands. */
5805
5806 assign( gsrc, getIReg(sz, gregOfRM(modrm)) );
5807
5808 if (epartIsReg(modrm)) {
5809 delta++;
5810 assign( esrc, getIReg(sz, eregOfRM(modrm)) );
sewardj68511542004-07-28 00:15:44 +00005811 DIP("sh%cd%c %s, %s, %s\n",
sewardja06e5562004-07-14 13:18:05 +00005812 ( left_shift ? 'l' : 'r' ), nameISize(sz),
sewardj68511542004-07-28 00:15:44 +00005813 shift_amt_txt,
sewardja06e5562004-07-14 13:18:05 +00005814 nameIReg(sz, gregOfRM(modrm)), nameIReg(sz, eregOfRM(modrm)));
5815 } else {
5816 addr = disAMode ( &len, sorb, delta, dis_buf );
5817 delta += len;
5818 assign( esrc, loadLE(ty, mkexpr(addr)) );
sewardj68511542004-07-28 00:15:44 +00005819 DIP("sh%cd%c %s, %s, %s\n",
5820 ( left_shift ? 'l' : 'r' ), nameISize(sz),
5821 shift_amt_txt,
5822 nameIReg(sz, gregOfRM(modrm)), dis_buf);
sewardja06e5562004-07-14 13:18:05 +00005823 }
5824
5825 /* Round up the relevant primops. */
5826
5827 if (sz == 4) {
5828 tmpL = newTemp(Ity_I64);
5829 tmpRes = newTemp(Ity_I32);
5830 tmpSubSh = newTemp(Ity_I32);
sewardje539a402004-07-14 18:24:17 +00005831 mkpair = Iop_32HLto64;
sewardj8c7f1ab2004-07-29 20:31:09 +00005832 getres = left_shift ? Iop_64HIto32 : Iop_64to32;
sewardje539a402004-07-14 18:24:17 +00005833 shift = left_shift ? Iop_Shl64 : Iop_Shr64;
5834 mask = mkU8(31);
sewardja06e5562004-07-14 13:18:05 +00005835 } else {
5836 /* sz == 2 */
sewardj8c7f1ab2004-07-29 20:31:09 +00005837 tmpL = newTemp(Ity_I32);
5838 tmpRes = newTemp(Ity_I16);
5839 tmpSubSh = newTemp(Ity_I16);
5840 mkpair = Iop_16HLto32;
5841 getres = left_shift ? Iop_32HIto16 : Iop_32to16;
5842 shift = left_shift ? Iop_Shl32 : Iop_Shr32;
5843 mask = mkU8(15);
sewardja06e5562004-07-14 13:18:05 +00005844 }
5845
5846 /* Do the shift, calculate the subshift value, and set
5847 the flag thunk. */
5848
sewardj8c7f1ab2004-07-29 20:31:09 +00005849 assign( tmpSH, binop(Iop_And8, shift_amt, mask) );
5850
sewardja06e5562004-07-14 13:18:05 +00005851 if (left_shift)
5852 assign( tmpL, binop(mkpair, mkexpr(esrc), mkexpr(gsrc)) );
5853 else
5854 assign( tmpL, binop(mkpair, mkexpr(gsrc), mkexpr(esrc)) );
5855
5856 assign( tmpRes, unop(getres, binop(shift, mkexpr(tmpL), mkexpr(tmpSH)) ) );
5857 assign( tmpSubSh,
5858 unop(getres,
5859 binop(shift,
5860 mkexpr(tmpL),
5861 binop(Iop_And8,
5862 binop(Iop_Sub8, mkexpr(tmpSH), mkU8(1) ),
5863 mask))) );
sewardja06e5562004-07-14 13:18:05 +00005864
sewardj2a2ba8b2004-11-08 13:14:06 +00005865 setFlags_DEP1_DEP2_shift ( left_shift ? Iop_Shl32 : Iop_Sar32,
5866 tmpRes, tmpSubSh, ty, tmpSH );
sewardja06e5562004-07-14 13:18:05 +00005867
5868 /* Put result back. */
5869
5870 if (epartIsReg(modrm)) {
5871 putIReg(sz, eregOfRM(modrm), mkexpr(tmpRes));
5872 } else {
5873 storeLE( mkexpr(addr), mkexpr(tmpRes) );
5874 }
5875
5876 if (amt_is_literal) delta++;
5877 return delta;
5878}
5879
5880
sewardj1c6f9912004-09-07 10:15:24 +00005881/* Handle BT/BTS/BTR/BTC Gv, Ev. Apparently b-size is not
5882 required. */
5883
5884typedef enum { BtOpNone, BtOpSet, BtOpReset, BtOpComp } BtOp;
5885
sewardj2d49b432005-02-01 00:37:06 +00005886static HChar* nameBtOp ( BtOp op )
sewardj1c6f9912004-09-07 10:15:24 +00005887{
5888 switch (op) {
5889 case BtOpNone: return "";
5890 case BtOpSet: return "s";
5891 case BtOpReset: return "r";
5892 case BtOpComp: return "c";
5893 default: vpanic("nameBtOp(x86)");
5894 }
5895}
5896
5897
5898static
sewardj52d04912005-07-03 00:52:48 +00005899UInt dis_bt_G_E ( UChar sorb, Int sz, Int delta, BtOp op )
sewardj1c6f9912004-09-07 10:15:24 +00005900{
sewardjc9a43662004-11-30 18:51:59 +00005901 HChar dis_buf[50];
sewardj1c6f9912004-09-07 10:15:24 +00005902 UChar modrm;
5903 Int len;
5904 IRTemp t_fetched, t_bitno0, t_bitno1, t_bitno2, t_addr0,
5905 t_addr1, t_esp, t_mask;
5906
5907 vassert(sz == 2 || sz == 4);
5908
5909 t_fetched = t_bitno0 = t_bitno1 = t_bitno2
sewardj92d168d2004-11-15 14:22:12 +00005910 = t_addr0 = t_addr1 = t_esp = t_mask = IRTemp_INVALID;
sewardj1c6f9912004-09-07 10:15:24 +00005911
5912 t_fetched = newTemp(Ity_I8);
5913 t_bitno0 = newTemp(Ity_I32);
5914 t_bitno1 = newTemp(Ity_I32);
5915 t_bitno2 = newTemp(Ity_I8);
5916 t_addr1 = newTemp(Ity_I32);
5917 modrm = getIByte(delta);
5918
sewardj9ed16802005-08-24 10:46:19 +00005919 assign( t_bitno0, widenSto32(getIReg(sz, gregOfRM(modrm))) );
sewardj1c6f9912004-09-07 10:15:24 +00005920
5921 if (epartIsReg(modrm)) {
sewardj1c6f9912004-09-07 10:15:24 +00005922 delta++;
5923 /* Get it onto the client's stack. */
5924 t_esp = newTemp(Ity_I32);
5925 t_addr0 = newTemp(Ity_I32);
5926
5927 assign( t_esp, binop(Iop_Sub32, getIReg(4, R_ESP), mkU32(sz)) );
5928 putIReg(4, R_ESP, mkexpr(t_esp));
5929
5930 storeLE( mkexpr(t_esp), getIReg(sz, eregOfRM(modrm)) );
5931
5932 /* Make t_addr0 point at it. */
5933 assign( t_addr0, mkexpr(t_esp) );
5934
5935 /* Mask out upper bits of the shift amount, since we're doing a
5936 reg. */
5937 assign( t_bitno1, binop(Iop_And32,
5938 mkexpr(t_bitno0),
5939 mkU32(sz == 4 ? 31 : 15)) );
5940
5941 } else {
5942 t_addr0 = disAMode ( &len, sorb, delta, dis_buf );
5943 delta += len;
5944 assign( t_bitno1, mkexpr(t_bitno0) );
5945 }
5946
5947 /* At this point: t_addr0 is the address being operated on. If it
5948 was a reg, we will have pushed it onto the client's stack.
5949 t_bitno1 is the bit number, suitably masked in the case of a
5950 reg. */
5951
5952 /* Now the main sequence. */
5953 assign( t_addr1,
5954 binop(Iop_Add32,
5955 mkexpr(t_addr0),
5956 binop(Iop_Sar32, mkexpr(t_bitno1), mkU8(3))) );
5957
5958 /* t_addr1 now holds effective address */
5959
5960 assign( t_bitno2,
5961 unop(Iop_32to8,
5962 binop(Iop_And32, mkexpr(t_bitno1), mkU32(7))) );
5963
5964 /* t_bitno2 contains offset of bit within byte */
5965
5966 if (op != BtOpNone) {
5967 t_mask = newTemp(Ity_I8);
5968 assign( t_mask, binop(Iop_Shl8, mkU8(1), mkexpr(t_bitno2)) );
5969 }
sewardj4963a422004-10-14 23:34:03 +00005970
sewardj1c6f9912004-09-07 10:15:24 +00005971 /* t_mask is now a suitable byte mask */
5972
5973 assign( t_fetched, loadLE(Ity_I8, mkexpr(t_addr1)) );
5974
5975 if (op != BtOpNone) {
5976 switch (op) {
5977 case BtOpSet:
5978 storeLE( mkexpr(t_addr1),
5979 binop(Iop_Or8, mkexpr(t_fetched),
5980 mkexpr(t_mask)) );
5981 break;
5982 case BtOpComp:
5983 storeLE( mkexpr(t_addr1),
5984 binop(Iop_Xor8, mkexpr(t_fetched),
5985 mkexpr(t_mask)) );
5986 break;
5987 case BtOpReset:
5988 storeLE( mkexpr(t_addr1),
5989 binop(Iop_And8, mkexpr(t_fetched),
5990 unop(Iop_Not8, mkexpr(t_mask))) );
5991 break;
5992 default:
5993 vpanic("dis_bt_G_E(x86)");
5994 }
5995 }
5996
5997 /* Side effect done; now get selected bit into Carry flag */
sewardj2a2ba8b2004-11-08 13:14:06 +00005998 /* Flags: C=selected bit, O,S,Z,A,P undefined, so are set to zero. */
sewardj2a9ad022004-11-25 02:46:58 +00005999 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
sewardj2a2ba8b2004-11-08 13:14:06 +00006000 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
sewardj1c6f9912004-09-07 10:15:24 +00006001 stmt( IRStmt_Put(
sewardj2a2ba8b2004-11-08 13:14:06 +00006002 OFFB_CC_DEP1,
sewardj1c6f9912004-09-07 10:15:24 +00006003 binop(Iop_And32,
6004 binop(Iop_Shr32,
6005 unop(Iop_8Uto32, mkexpr(t_fetched)),
sewardj5bd4d162004-11-10 13:02:48 +00006006 mkexpr(t_bitno2)),
6007 mkU32(1)))
sewardj1c6f9912004-09-07 10:15:24 +00006008 );
sewardja3b7e3a2005-04-05 01:54:19 +00006009 /* Set NDEP even though it isn't used. This makes redundant-PUT
6010 elimination of previous stores to this field work better. */
6011 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardj1c6f9912004-09-07 10:15:24 +00006012
6013 /* Move reg operand from stack back to reg */
6014 if (epartIsReg(modrm)) {
6015 /* t_esp still points at it. */
sewardj4963a422004-10-14 23:34:03 +00006016 putIReg(sz, eregOfRM(modrm), loadLE(szToITy(sz), mkexpr(t_esp)) );
sewardj1c6f9912004-09-07 10:15:24 +00006017 putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t_esp), mkU32(sz)) );
6018 }
6019
6020 DIP("bt%s%c %s, %s\n",
6021 nameBtOp(op), nameISize(sz), nameIReg(sz, gregOfRM(modrm)),
6022 ( epartIsReg(modrm) ? nameIReg(sz, eregOfRM(modrm)) : dis_buf ) );
6023
6024 return delta;
6025}
sewardjce646f22004-08-31 23:55:54 +00006026
6027
6028
6029/* Handle BSF/BSR. Only v-size seems necessary. */
6030static
sewardj52d04912005-07-03 00:52:48 +00006031UInt dis_bs_E_G ( UChar sorb, Int sz, Int delta, Bool fwds )
sewardjce646f22004-08-31 23:55:54 +00006032{
6033 Bool isReg;
6034 UChar modrm;
sewardjc9a43662004-11-30 18:51:59 +00006035 HChar dis_buf[50];
sewardjce646f22004-08-31 23:55:54 +00006036
6037 IRType ty = szToITy(sz);
6038 IRTemp src = newTemp(ty);
6039 IRTemp dst = newTemp(ty);
6040
6041 IRTemp src32 = newTemp(Ity_I32);
6042 IRTemp dst32 = newTemp(Ity_I32);
6043 IRTemp src8 = newTemp(Ity_I8);
6044
6045 vassert(sz == 4 || sz == 2);
sewardjce646f22004-08-31 23:55:54 +00006046
6047 modrm = getIByte(delta);
6048
6049 isReg = epartIsReg(modrm);
6050 if (isReg) {
6051 delta++;
6052 assign( src, getIReg(sz, eregOfRM(modrm)) );
6053 } else {
6054 Int len;
6055 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
6056 delta += len;
6057 assign( src, loadLE(ty, mkexpr(addr)) );
6058 }
6059
6060 DIP("bs%c%c %s, %s\n",
6061 fwds ? 'f' : 'r', nameISize(sz),
6062 ( isReg ? nameIReg(sz, eregOfRM(modrm)) : dis_buf ),
6063 nameIReg(sz, gregOfRM(modrm)));
6064
6065 /* Generate an 8-bit expression which is zero iff the
6066 original is zero, and nonzero otherwise */
6067 assign( src8,
6068 unop(Iop_1Uto8, binop(mkSizedOp(ty,Iop_CmpNE8),
6069 mkexpr(src), mkU(ty,0))) );
6070
6071 /* Flags: Z is 1 iff source value is zero. All others
6072 are undefined -- we force them to zero. */
sewardj2a9ad022004-11-25 02:46:58 +00006073 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
sewardj2a2ba8b2004-11-08 13:14:06 +00006074 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
sewardjce646f22004-08-31 23:55:54 +00006075 stmt( IRStmt_Put(
sewardj2a2ba8b2004-11-08 13:14:06 +00006076 OFFB_CC_DEP1,
sewardjce646f22004-08-31 23:55:54 +00006077 IRExpr_Mux0X( mkexpr(src8),
6078 /* src==0 */
sewardj2a9ad022004-11-25 02:46:58 +00006079 mkU32(X86G_CC_MASK_Z),
sewardjce646f22004-08-31 23:55:54 +00006080 /* src!=0 */
6081 mkU32(0)
6082 )
6083 ));
sewardja3b7e3a2005-04-05 01:54:19 +00006084 /* Set NDEP even though it isn't used. This makes redundant-PUT
6085 elimination of previous stores to this field work better. */
6086 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardjce646f22004-08-31 23:55:54 +00006087
6088 /* Result: iff source value is zero, we can't use
6089 Iop_Clz32/Iop_Ctz32 as they have no defined result in that case.
6090 But anyway, Intel x86 semantics say the result is undefined in
6091 such situations. Hence handle the zero case specially. */
6092
6093 /* Bleh. What we compute:
6094
6095 bsf32: if src == 0 then 0 else Ctz32(src)
6096 bsr32: if src == 0 then 0 else 31 - Clz32(src)
6097
6098 bsf16: if src == 0 then 0 else Ctz32(16Uto32(src))
6099 bsr16: if src == 0 then 0 else 31 - Clz32(16Uto32(src))
6100
6101 First, widen src to 32 bits if it is not already.
sewardj37158712004-10-15 21:23:12 +00006102
6103 Postscript 15 Oct 04: it seems that at least VIA Nehemiah leaves the
6104 dst register unchanged when src == 0. Hence change accordingly.
sewardjce646f22004-08-31 23:55:54 +00006105 */
6106 if (sz == 2)
6107 assign( src32, unop(Iop_16Uto32, mkexpr(src)) );
6108 else
6109 assign( src32, mkexpr(src) );
6110
6111 /* The main computation, guarding against zero. */
6112 assign( dst32,
6113 IRExpr_Mux0X(
6114 mkexpr(src8),
sewardj37158712004-10-15 21:23:12 +00006115 /* src == 0 -- leave dst unchanged */
6116 widenUto32( getIReg( sz, gregOfRM(modrm) ) ),
sewardjce646f22004-08-31 23:55:54 +00006117 /* src != 0 */
6118 fwds ? unop(Iop_Ctz32, mkexpr(src32))
6119 : binop(Iop_Sub32,
6120 mkU32(31),
6121 unop(Iop_Clz32, mkexpr(src32)))
6122 )
6123 );
6124
6125 if (sz == 2)
6126 assign( dst, unop(Iop_32to16, mkexpr(dst32)) );
6127 else
6128 assign( dst, mkexpr(dst32) );
6129
6130 /* dump result back */
6131 putIReg( sz, gregOfRM(modrm), mkexpr(dst) );
6132
6133 return delta;
6134}
sewardj64e1d652004-07-12 14:00:46 +00006135
6136
6137static
6138void codegen_xchg_eAX_Reg ( Int sz, Int reg )
6139{
6140 IRType ty = szToITy(sz);
6141 IRTemp t1 = newTemp(ty);
6142 IRTemp t2 = newTemp(ty);
6143 vassert(sz == 2 || sz == 4);
6144 assign( t1, getIReg(sz, R_EAX) );
6145 assign( t2, getIReg(sz, reg) );
6146 putIReg( sz, R_EAX, mkexpr(t2) );
6147 putIReg( sz, reg, mkexpr(t1) );
6148 DIP("xchg%c %s, %s\n",
6149 nameISize(sz), nameIReg(sz, R_EAX), nameIReg(sz, reg));
6150}
6151
6152
sewardjbdc7d212004-09-09 02:46:40 +00006153static
6154void codegen_SAHF ( void )
6155{
6156 /* Set the flags to:
sewardj2a9ad022004-11-25 02:46:58 +00006157 (x86g_calculate_flags_all() & X86G_CC_MASK_O) -- retain the old O flag
6158 | (%AH & (X86G_CC_MASK_S|X86G_CC_MASK_Z|X86G_CC_MASK_A
6159 |X86G_CC_MASK_P|X86G_CC_MASK_C)
sewardjbdc7d212004-09-09 02:46:40 +00006160 */
sewardj2a9ad022004-11-25 02:46:58 +00006161 UInt mask_SZACP = X86G_CC_MASK_S|X86G_CC_MASK_Z|X86G_CC_MASK_A
6162 |X86G_CC_MASK_C|X86G_CC_MASK_P;
sewardjbdc7d212004-09-09 02:46:40 +00006163 IRTemp oldflags = newTemp(Ity_I32);
sewardj2a9ad022004-11-25 02:46:58 +00006164 assign( oldflags, mk_x86g_calculate_eflags_all() );
6165 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
sewardj905edbd2007-04-07 12:25:37 +00006166 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardj2a2ba8b2004-11-08 13:14:06 +00006167 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
6168 stmt( IRStmt_Put( OFFB_CC_DEP1,
sewardjbdc7d212004-09-09 02:46:40 +00006169 binop(Iop_Or32,
sewardj2a9ad022004-11-25 02:46:58 +00006170 binop(Iop_And32, mkexpr(oldflags), mkU32(X86G_CC_MASK_O)),
sewardjbdc7d212004-09-09 02:46:40 +00006171 binop(Iop_And32,
6172 binop(Iop_Shr32, getIReg(4, R_EAX), mkU8(8)),
6173 mkU32(mask_SZACP))
6174 )
6175 ));
sewardja3b7e3a2005-04-05 01:54:19 +00006176 /* Set NDEP even though it isn't used. This makes redundant-PUT
6177 elimination of previous stores to this field work better. */
6178 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardjbdc7d212004-09-09 02:46:40 +00006179}
6180
6181
sewardj8dfdc8a2005-10-03 11:39:02 +00006182static
6183void codegen_LAHF ( void )
6184{
6185 /* AH <- EFLAGS(SF:ZF:0:AF:0:PF:1:CF) */
6186 IRExpr* eax_with_hole;
6187 IRExpr* new_byte;
6188 IRExpr* new_eax;
6189 UInt mask_SZACP = X86G_CC_MASK_S|X86G_CC_MASK_Z|X86G_CC_MASK_A
6190 |X86G_CC_MASK_C|X86G_CC_MASK_P;
6191
6192 IRTemp flags = newTemp(Ity_I32);
6193 assign( flags, mk_x86g_calculate_eflags_all() );
6194
6195 eax_with_hole
6196 = binop(Iop_And32, getIReg(4, R_EAX), mkU32(0xFFFF00FF));
6197 new_byte
6198 = binop(Iop_Or32, binop(Iop_And32, mkexpr(flags), mkU32(mask_SZACP)),
6199 mkU32(1<<1));
6200 new_eax
6201 = binop(Iop_Or32, eax_with_hole,
6202 binop(Iop_Shl32, new_byte, mkU8(8)));
6203 putIReg(4, R_EAX, new_eax);
6204}
6205
sewardj458a6f82004-08-25 12:46:02 +00006206
6207static
6208UInt dis_cmpxchg_G_E ( UChar sorb,
6209 Int size,
sewardj52d04912005-07-03 00:52:48 +00006210 Int delta0 )
sewardj458a6f82004-08-25 12:46:02 +00006211{
sewardjc9a43662004-11-30 18:51:59 +00006212 HChar dis_buf[50];
sewardj458a6f82004-08-25 12:46:02 +00006213 Int len;
6214
6215 IRType ty = szToITy(size);
6216 IRTemp acc = newTemp(ty);
6217 IRTemp src = newTemp(ty);
sewardj2a2ba8b2004-11-08 13:14:06 +00006218 //IRTemp res = newTemp(ty);
sewardj458a6f82004-08-25 12:46:02 +00006219 IRTemp dest = newTemp(ty);
6220 IRTemp dest2 = newTemp(ty);
6221 IRTemp acc2 = newTemp(ty);
6222 IRTemp cond8 = newTemp(Ity_I8);
sewardj92d168d2004-11-15 14:22:12 +00006223 IRTemp addr = IRTemp_INVALID;
sewardj458a6f82004-08-25 12:46:02 +00006224 UChar rm = getUChar(delta0);
6225
6226 if (epartIsReg(rm)) {
6227 assign( dest, getIReg(size, eregOfRM(rm)) );
6228 delta0++;
6229 DIP("cmpxchg%c %s,%s\n", nameISize(size),
6230 nameIReg(size,gregOfRM(rm)),
6231 nameIReg(size,eregOfRM(rm)) );
sewardj458a6f82004-08-25 12:46:02 +00006232 } else {
6233 addr = disAMode ( &len, sorb, delta0, dis_buf );
6234 assign( dest, loadLE(ty, mkexpr(addr)) );
6235 delta0 += len;
6236 DIP("cmpxchg%c %s,%s\n", nameISize(size),
6237 nameIReg(size,gregOfRM(rm)), dis_buf);
6238 }
6239
6240 assign( src, getIReg(size, gregOfRM(rm)) );
6241 assign( acc, getIReg(size, R_EAX) );
sewardj2a2ba8b2004-11-08 13:14:06 +00006242 //assign( res, binop( mkSizedOp(ty,Iop_Sub8), mkexpr(acc), mkexpr(dest) ));
6243 setFlags_DEP1_DEP2(Iop_Sub8, acc, dest, ty);
sewardj2a9ad022004-11-25 02:46:58 +00006244 assign( cond8, unop(Iop_1Uto8, mk_x86g_calculate_condition(X86CondZ)) );
sewardj458a6f82004-08-25 12:46:02 +00006245 assign( dest2, IRExpr_Mux0X(mkexpr(cond8), mkexpr(dest), mkexpr(src)) );
6246 assign( acc2, IRExpr_Mux0X(mkexpr(cond8), mkexpr(dest), mkexpr(acc)) );
6247 putIReg(size, R_EAX, mkexpr(acc2));
6248
6249 if (epartIsReg(rm)) {
6250 putIReg(size, eregOfRM(rm), mkexpr(dest2));
6251 } else {
6252 storeLE( mkexpr(addr), mkexpr(dest2) );
6253 }
6254
6255 return delta0;
6256}
6257
6258
sewardjc9a65702004-07-07 16:32:57 +00006259//-- static
6260//-- Addr dis_cmpxchg8b ( UCodeBlock* cb,
6261//-- UChar sorb,
6262//-- Addr eip0 )
6263//-- {
6264//-- Int tal, tah, junkl, junkh, destl, desth, srcl, srch, accl, acch;
sewardjc9a43662004-11-30 18:51:59 +00006265//-- HChar dis_buf[50];
sewardjc9a65702004-07-07 16:32:57 +00006266//-- UChar rm;
6267//-- UInt pair;
6268//--
6269//-- rm = getUChar(eip0);
6270//-- accl = newTemp(cb);
6271//-- acch = newTemp(cb);
6272//-- srcl = newTemp(cb);
6273//-- srch = newTemp(cb);
6274//-- destl = newTemp(cb);
6275//-- desth = newTemp(cb);
6276//-- junkl = newTemp(cb);
6277//-- junkh = newTemp(cb);
6278//--
6279//-- vg_assert(!epartIsReg(rm));
6280//--
6281//-- pair = disAMode ( cb, sorb, eip0, dis_buf );
6282//-- tal = LOW24(pair);
6283//-- tah = newTemp(cb);
6284//-- uInstr2(cb, MOV, 4, TempReg, tal, TempReg, tah);
6285//-- uInstr2(cb, ADD, 4, Literal, 0, TempReg, tah);
6286//-- uLiteral(cb, 4);
6287//-- eip0 += HI8(pair);
6288//-- DIP("cmpxchg8b %s\n", dis_buf);
6289//--
6290//-- uInstr0(cb, CALLM_S, 0);
6291//--
6292//-- uInstr2(cb, LOAD, 4, TempReg, tah, TempReg, desth);
6293//-- uInstr1(cb, PUSH, 4, TempReg, desth);
6294//-- uInstr2(cb, LOAD, 4, TempReg, tal, TempReg, destl);
6295//-- uInstr1(cb, PUSH, 4, TempReg, destl);
6296//-- uInstr2(cb, GET, 4, ArchReg, R_ECX, TempReg, srch);
6297//-- uInstr1(cb, PUSH, 4, TempReg, srch);
6298//-- uInstr2(cb, GET, 4, ArchReg, R_EBX, TempReg, srcl);
6299//-- uInstr1(cb, PUSH, 4, TempReg, srcl);
6300//-- uInstr2(cb, GET, 4, ArchReg, R_EDX, TempReg, acch);
6301//-- uInstr1(cb, PUSH, 4, TempReg, acch);
6302//-- uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, accl);
6303//-- uInstr1(cb, PUSH, 4, TempReg, accl);
6304//--
6305//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_cmpxchg8b));
6306//-- uFlagsRWU(cb, FlagsEmpty, FlagZ, FlagsEmpty);
6307//--
6308//-- uInstr1(cb, POP, 4, TempReg, accl);
6309//-- uInstr2(cb, PUT, 4, TempReg, accl, ArchReg, R_EAX);
6310//-- uInstr1(cb, POP, 4, TempReg, acch);
6311//-- uInstr2(cb, PUT, 4, TempReg, acch, ArchReg, R_EDX);
6312//-- uInstr1(cb, POP, 4, TempReg, srcl);
6313//-- uInstr2(cb, PUT, 4, TempReg, srcl, ArchReg, R_EBX);
6314//-- uInstr1(cb, POP, 4, TempReg, srch);
6315//-- uInstr2(cb, PUT, 4, TempReg, srch, ArchReg, R_ECX);
6316//-- uInstr1(cb, POP, 4, TempReg, destl);
6317//-- uInstr2(cb, STORE, 4, TempReg, destl, TempReg, tal);
6318//-- uInstr1(cb, POP, 4, TempReg, desth);
6319//-- uInstr2(cb, STORE, 4, TempReg, desth, TempReg, tah);
6320//--
6321//-- uInstr0(cb, CALLM_E, 0);
6322//--
6323//-- return eip0;
6324//-- }
sewardj458a6f82004-08-25 12:46:02 +00006325
6326
6327/* Handle conditional move instructions of the form
6328 cmovcc E(reg-or-mem), G(reg)
6329
6330 E(src) is reg-or-mem
6331 G(dst) is reg.
6332
6333 If E is reg, --> GET %E, tmps
6334 GET %G, tmpd
6335 CMOVcc tmps, tmpd
6336 PUT tmpd, %G
6337
6338 If E is mem --> (getAddr E) -> tmpa
6339 LD (tmpa), tmps
6340 GET %G, tmpd
6341 CMOVcc tmps, tmpd
6342 PUT tmpd, %G
6343*/
6344static
6345UInt dis_cmov_E_G ( UChar sorb,
6346 Int sz,
sewardj2a9ad022004-11-25 02:46:58 +00006347 X86Condcode cond,
sewardj52d04912005-07-03 00:52:48 +00006348 Int delta0 )
sewardj458a6f82004-08-25 12:46:02 +00006349{
6350 UChar rm = getIByte(delta0);
sewardjc9a43662004-11-30 18:51:59 +00006351 HChar dis_buf[50];
sewardj458a6f82004-08-25 12:46:02 +00006352 Int len;
6353
sewardj883b00b2004-09-11 09:30:24 +00006354 IRType ty = szToITy(sz);
sewardj458a6f82004-08-25 12:46:02 +00006355 IRTemp tmps = newTemp(ty);
6356 IRTemp tmpd = newTemp(ty);
6357
6358 if (epartIsReg(rm)) {
6359 assign( tmps, getIReg(sz, eregOfRM(rm)) );
6360 assign( tmpd, getIReg(sz, gregOfRM(rm)) );
6361
6362 putIReg(sz, gregOfRM(rm),
sewardj2a9ad022004-11-25 02:46:58 +00006363 IRExpr_Mux0X( unop(Iop_1Uto8,
6364 mk_x86g_calculate_condition(cond)),
sewardj458a6f82004-08-25 12:46:02 +00006365 mkexpr(tmpd),
6366 mkexpr(tmps) )
6367 );
6368 DIP("cmov%c%s %s,%s\n", nameISize(sz),
sewardj2a9ad022004-11-25 02:46:58 +00006369 name_X86Condcode(cond),
sewardj458a6f82004-08-25 12:46:02 +00006370 nameIReg(sz,eregOfRM(rm)),
6371 nameIReg(sz,gregOfRM(rm)));
6372 return 1+delta0;
6373 }
6374
6375 /* E refers to memory */
6376 {
6377 IRTemp addr = disAMode ( &len, sorb, delta0, dis_buf );
6378 assign( tmps, loadLE(ty, mkexpr(addr)) );
6379 assign( tmpd, getIReg(sz, gregOfRM(rm)) );
6380
6381 putIReg(sz, gregOfRM(rm),
sewardj2a9ad022004-11-25 02:46:58 +00006382 IRExpr_Mux0X( unop(Iop_1Uto8,
6383 mk_x86g_calculate_condition(cond)),
sewardj458a6f82004-08-25 12:46:02 +00006384 mkexpr(tmpd),
6385 mkexpr(tmps) )
6386 );
6387
6388 DIP("cmov%c%s %s,%s\n", nameISize(sz),
sewardj2a9ad022004-11-25 02:46:58 +00006389 name_X86Condcode(cond),
sewardj458a6f82004-08-25 12:46:02 +00006390 dis_buf,
6391 nameIReg(sz,gregOfRM(rm)));
6392 return len+delta0;
6393 }
6394}
6395
6396
sewardj883b00b2004-09-11 09:30:24 +00006397static
sewardj0092e0d2006-03-06 13:35:42 +00006398UInt dis_xadd_G_E ( UChar sorb, Int sz, Int delta0, Bool* decodeOK )
sewardj883b00b2004-09-11 09:30:24 +00006399{
6400 Int len;
6401 UChar rm = getIByte(delta0);
sewardjc9a43662004-11-30 18:51:59 +00006402 HChar dis_buf[50];
sewardj883b00b2004-09-11 09:30:24 +00006403
6404 // Int tmpd = newTemp(cb);
6405 //Int tmpt = newTemp(cb);
6406
6407 IRType ty = szToITy(sz);
6408 IRTemp tmpd = newTemp(ty);
6409 IRTemp tmpt0 = newTemp(ty);
6410 IRTemp tmpt1 = newTemp(ty);
6411
6412 if (epartIsReg(rm)) {
sewardj0092e0d2006-03-06 13:35:42 +00006413 *decodeOK = False;
6414 return delta0;
6415 /* Currently we don't handle xadd_G_E with register operand. */
sewardj883b00b2004-09-11 09:30:24 +00006416#if 0
6417 uInstr2(cb, GET, sz, ArchReg, eregOfRM(rm), TempReg, tmpd);
6418 uInstr2(cb, GET, sz, ArchReg, gregOfRM(rm), TempReg, tmpt);
6419 uInstr2(cb, ADD, sz, TempReg, tmpd, TempReg, tmpt);
6420 setFlagsFromUOpcode(cb, ADD);
6421 uInstr2(cb, PUT, sz, TempReg, tmpd, ArchReg, gregOfRM(rm));
6422 uInstr2(cb, PUT, sz, TempReg, tmpt, ArchReg, eregOfRM(rm));
6423 DIP("xadd%c %s, %s\n",
6424 nameISize(sz), nameIReg(sz,gregOfRM(rm)), nameIReg(sz,eregOfRM(rm)));
6425 return 1+eip0;
6426#endif
6427 } else {
6428 IRTemp addr = disAMode ( &len, sorb, delta0, dis_buf );
6429 assign( tmpd, loadLE(ty, mkexpr(addr)) );
6430 assign( tmpt0, getIReg(sz, gregOfRM(rm)) );
sewardj883b00b2004-09-11 09:30:24 +00006431 assign( tmpt1, binop(mkSizedOp(ty,Iop_Add8), mkexpr(tmpd), mkexpr(tmpt0)) );
sewardj2a2ba8b2004-11-08 13:14:06 +00006432 setFlags_DEP1_DEP2( Iop_Add8, tmpd, tmpt0, ty );
sewardj883b00b2004-09-11 09:30:24 +00006433 storeLE( mkexpr(addr), mkexpr(tmpt1) );
6434 putIReg(sz, gregOfRM(rm), mkexpr(tmpd));
6435 DIP("xadd%c %s, %s\n",
6436 nameISize(sz), nameIReg(sz,gregOfRM(rm)), dis_buf);
sewardj0092e0d2006-03-06 13:35:42 +00006437 *decodeOK = True;
sewardj883b00b2004-09-11 09:30:24 +00006438 return len+delta0;
6439 }
6440}
6441
sewardjb64821b2004-12-14 10:00:16 +00006442/* Move 16 bits from Ew (ireg or mem) to G (a segment register). */
6443
sewardj7df596b2004-12-06 14:29:12 +00006444static
sewardj52d04912005-07-03 00:52:48 +00006445UInt dis_mov_Ew_Sw ( UChar sorb, Int delta0 )
sewardj7df596b2004-12-06 14:29:12 +00006446{
sewardjb64821b2004-12-14 10:00:16 +00006447 Int len;
6448 IRTemp addr;
6449 UChar rm = getIByte(delta0);
6450 HChar dis_buf[50];
sewardj7df596b2004-12-06 14:29:12 +00006451
6452 if (epartIsReg(rm)) {
6453 putSReg( gregOfRM(rm), getIReg(2, eregOfRM(rm)) );
6454 DIP("movw %s,%s\n", nameIReg(2,eregOfRM(rm)), nameSReg(gregOfRM(rm)));
6455 return 1+delta0;
sewardjb64821b2004-12-14 10:00:16 +00006456 } else {
6457 addr = disAMode ( &len, sorb, delta0, dis_buf );
6458 putSReg( gregOfRM(rm), loadLE(Ity_I16, mkexpr(addr)) );
6459 DIP("movw %s,%s\n", dis_buf, nameSReg(gregOfRM(rm)));
6460 return len+delta0;
sewardj7df596b2004-12-06 14:29:12 +00006461 }
6462}
6463
sewardjb64821b2004-12-14 10:00:16 +00006464/* Move 16 bits from G (a segment register) to Ew (ireg or mem). If
6465 dst is ireg and sz==4, zero out top half of it. */
6466
sewardj063f02f2004-10-20 12:36:12 +00006467static
6468UInt dis_mov_Sw_Ew ( UChar sorb,
6469 Int sz,
sewardj52d04912005-07-03 00:52:48 +00006470 Int delta0 )
sewardj063f02f2004-10-20 12:36:12 +00006471{
sewardjb64821b2004-12-14 10:00:16 +00006472 Int len;
6473 IRTemp addr;
6474 UChar rm = getIByte(delta0);
6475 HChar dis_buf[50];
sewardj063f02f2004-10-20 12:36:12 +00006476
6477 vassert(sz == 2 || sz == 4);
6478
6479 if (epartIsReg(rm)) {
6480 if (sz == 4)
6481 putIReg(4, eregOfRM(rm), unop(Iop_16Uto32, getSReg(gregOfRM(rm))));
6482 else
6483 putIReg(2, eregOfRM(rm), getSReg(gregOfRM(rm)));
6484
6485 DIP("mov %s,%s\n", nameSReg(gregOfRM(rm)), nameIReg(sz,eregOfRM(rm)));
6486 return 1+delta0;
sewardjb64821b2004-12-14 10:00:16 +00006487 } else {
6488 addr = disAMode ( &len, sorb, delta0, dis_buf );
6489 storeLE( mkexpr(addr), getSReg(gregOfRM(rm)) );
sewardj063f02f2004-10-20 12:36:12 +00006490 DIP("mov %s,%s\n", nameSReg(gregOfRM(rm)), dis_buf);
sewardjb64821b2004-12-14 10:00:16 +00006491 return len+delta0;
sewardj063f02f2004-10-20 12:36:12 +00006492 }
sewardj063f02f2004-10-20 12:36:12 +00006493}
6494
6495
sewardjb64821b2004-12-14 10:00:16 +00006496static
6497void dis_push_segreg ( UInt sreg, Int sz )
6498{
6499 IRTemp t1 = newTemp(Ity_I16);
6500 IRTemp ta = newTemp(Ity_I32);
6501 vassert(sz == 2 || sz == 4);
6502
6503 assign( t1, getSReg(sreg) );
6504 assign( ta, binop(Iop_Sub32, getIReg(4, R_ESP), mkU32(sz)) );
6505 putIReg(4, R_ESP, mkexpr(ta));
6506 storeLE( mkexpr(ta), mkexpr(t1) );
6507
sewardj5c5f72c2006-03-18 11:29:25 +00006508 DIP("push%c %s\n", sz==2 ? 'w' : 'l', nameSReg(sreg));
sewardjb64821b2004-12-14 10:00:16 +00006509}
6510
6511static
6512void dis_pop_segreg ( UInt sreg, Int sz )
6513{
6514 IRTemp t1 = newTemp(Ity_I16);
6515 IRTemp ta = newTemp(Ity_I32);
6516 vassert(sz == 2 || sz == 4);
6517
6518 assign( ta, getIReg(4, R_ESP) );
6519 assign( t1, loadLE(Ity_I16, mkexpr(ta)) );
6520
6521 putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(ta), mkU32(sz)) );
6522 putSReg( sreg, mkexpr(t1) );
sewardj5c5f72c2006-03-18 11:29:25 +00006523 DIP("pop%c %s\n", sz==2 ? 'w' : 'l', nameSReg(sreg));
sewardjb64821b2004-12-14 10:00:16 +00006524}
sewardje05c42c2004-07-08 20:25:10 +00006525
6526static
6527void dis_ret ( UInt d32 )
6528{
6529 IRTemp t1 = newTemp(Ity_I32), t2 = newTemp(Ity_I32);
6530 assign(t1, getIReg(4,R_ESP));
6531 assign(t2, loadLE(Ity_I32,mkexpr(t1)));
6532 putIReg(4, R_ESP,binop(Iop_Add32, mkexpr(t1), mkU32(4+d32)));
sewardj78c19df2004-07-12 22:49:27 +00006533 jmp_treg(Ijk_Ret,t2);
sewardje05c42c2004-07-08 20:25:10 +00006534}
6535
sewardj4cb918d2004-12-03 19:43:31 +00006536/*------------------------------------------------------------*/
6537/*--- SSE/SSE2/SSE3 helpers ---*/
6538/*------------------------------------------------------------*/
sewardjc9a43662004-11-30 18:51:59 +00006539
sewardj129b3d92004-12-05 15:42:05 +00006540/* Worker function; do not call directly.
6541 Handles full width G = G `op` E and G = (not G) `op` E.
6542*/
6543
6544static UInt dis_SSE_E_to_G_all_wrk (
sewardj52d04912005-07-03 00:52:48 +00006545 UChar sorb, Int delta,
sewardj1e6ad742004-12-02 16:16:11 +00006546 HChar* opname, IROp op,
6547 Bool invertG
6548 )
sewardjc9a43662004-11-30 18:51:59 +00006549{
sewardj1e6ad742004-12-02 16:16:11 +00006550 HChar dis_buf[50];
6551 Int alen;
6552 IRTemp addr;
6553 UChar rm = getIByte(delta);
6554 IRExpr* gpart
sewardjf0c1c582005-02-07 23:47:38 +00006555 = invertG ? unop(Iop_NotV128, getXMMReg(gregOfRM(rm)))
sewardj1e6ad742004-12-02 16:16:11 +00006556 : getXMMReg(gregOfRM(rm));
sewardjc9a43662004-11-30 18:51:59 +00006557 if (epartIsReg(rm)) {
6558 putXMMReg( gregOfRM(rm),
sewardj1e6ad742004-12-02 16:16:11 +00006559 binop(op, gpart,
6560 getXMMReg(eregOfRM(rm))) );
sewardjc9a43662004-11-30 18:51:59 +00006561 DIP("%s %s,%s\n", opname,
6562 nameXMMReg(eregOfRM(rm)),
6563 nameXMMReg(gregOfRM(rm)) );
6564 return delta+1;
6565 } else {
sewardj1e6ad742004-12-02 16:16:11 +00006566 addr = disAMode ( &alen, sorb, delta, dis_buf );
6567 putXMMReg( gregOfRM(rm),
6568 binop(op, gpart,
6569 loadLE(Ity_V128, mkexpr(addr))) );
6570 DIP("%s %s,%s\n", opname,
6571 dis_buf,
6572 nameXMMReg(gregOfRM(rm)) );
6573 return delta+alen;
sewardjc9a43662004-11-30 18:51:59 +00006574 }
6575}
6576
sewardj129b3d92004-12-05 15:42:05 +00006577
6578/* All lanes SSE binary operation, G = G `op` E. */
sewardj1e6ad742004-12-02 16:16:11 +00006579
6580static
sewardj52d04912005-07-03 00:52:48 +00006581UInt dis_SSE_E_to_G_all ( UChar sorb, Int delta, HChar* opname, IROp op )
sewardj1e6ad742004-12-02 16:16:11 +00006582{
sewardj129b3d92004-12-05 15:42:05 +00006583 return dis_SSE_E_to_G_all_wrk( sorb, delta, opname, op, False );
sewardj1e6ad742004-12-02 16:16:11 +00006584}
6585
sewardj129b3d92004-12-05 15:42:05 +00006586/* All lanes SSE binary operation, G = (not G) `op` E. */
6587
6588static
sewardj52d04912005-07-03 00:52:48 +00006589UInt dis_SSE_E_to_G_all_invG ( UChar sorb, Int delta,
sewardj129b3d92004-12-05 15:42:05 +00006590 HChar* opname, IROp op )
6591{
6592 return dis_SSE_E_to_G_all_wrk( sorb, delta, opname, op, True );
6593}
6594
sewardj164f9272004-12-09 00:39:32 +00006595
sewardj129b3d92004-12-05 15:42:05 +00006596/* Lowest 32-bit lane only SSE binary operation, G = G `op` E. */
6597
sewardj52d04912005-07-03 00:52:48 +00006598static UInt dis_SSE_E_to_G_lo32 ( UChar sorb, Int delta,
sewardj129b3d92004-12-05 15:42:05 +00006599 HChar* opname, IROp op )
6600{
6601 HChar dis_buf[50];
6602 Int alen;
6603 IRTemp addr;
6604 UChar rm = getIByte(delta);
6605 IRExpr* gpart = getXMMReg(gregOfRM(rm));
6606 if (epartIsReg(rm)) {
6607 putXMMReg( gregOfRM(rm),
6608 binop(op, gpart,
6609 getXMMReg(eregOfRM(rm))) );
6610 DIP("%s %s,%s\n", opname,
6611 nameXMMReg(eregOfRM(rm)),
6612 nameXMMReg(gregOfRM(rm)) );
6613 return delta+1;
6614 } else {
6615 /* We can only do a 32-bit memory read, so the upper 3/4 of the
6616 E operand needs to be made simply of zeroes. */
6617 IRTemp epart = newTemp(Ity_V128);
6618 addr = disAMode ( &alen, sorb, delta, dis_buf );
sewardjf0c1c582005-02-07 23:47:38 +00006619 assign( epart, unop( Iop_32UtoV128,
sewardj129b3d92004-12-05 15:42:05 +00006620 loadLE(Ity_I32, mkexpr(addr))) );
6621 putXMMReg( gregOfRM(rm),
6622 binop(op, gpart, mkexpr(epart)) );
6623 DIP("%s %s,%s\n", opname,
6624 dis_buf,
6625 nameXMMReg(gregOfRM(rm)) );
6626 return delta+alen;
6627 }
6628}
6629
sewardj164f9272004-12-09 00:39:32 +00006630
sewardj636ad762004-12-07 11:16:04 +00006631/* Lower 64-bit lane only SSE binary operation, G = G `op` E. */
6632
sewardj52d04912005-07-03 00:52:48 +00006633static UInt dis_SSE_E_to_G_lo64 ( UChar sorb, Int delta,
sewardj636ad762004-12-07 11:16:04 +00006634 HChar* opname, IROp op )
6635{
6636 HChar dis_buf[50];
6637 Int alen;
6638 IRTemp addr;
6639 UChar rm = getIByte(delta);
6640 IRExpr* gpart = getXMMReg(gregOfRM(rm));
6641 if (epartIsReg(rm)) {
6642 putXMMReg( gregOfRM(rm),
6643 binop(op, gpart,
6644 getXMMReg(eregOfRM(rm))) );
6645 DIP("%s %s,%s\n", opname,
6646 nameXMMReg(eregOfRM(rm)),
6647 nameXMMReg(gregOfRM(rm)) );
6648 return delta+1;
6649 } else {
6650 /* We can only do a 64-bit memory read, so the upper half of the
6651 E operand needs to be made simply of zeroes. */
6652 IRTemp epart = newTemp(Ity_V128);
6653 addr = disAMode ( &alen, sorb, delta, dis_buf );
sewardjf0c1c582005-02-07 23:47:38 +00006654 assign( epart, unop( Iop_64UtoV128,
sewardj636ad762004-12-07 11:16:04 +00006655 loadLE(Ity_I64, mkexpr(addr))) );
6656 putXMMReg( gregOfRM(rm),
6657 binop(op, gpart, mkexpr(epart)) );
6658 DIP("%s %s,%s\n", opname,
6659 dis_buf,
6660 nameXMMReg(gregOfRM(rm)) );
6661 return delta+alen;
6662 }
6663}
6664
sewardj164f9272004-12-09 00:39:32 +00006665
sewardj129b3d92004-12-05 15:42:05 +00006666/* All lanes unary SSE operation, G = op(E). */
6667
6668static UInt dis_SSE_E_to_G_unary_all (
sewardj52d04912005-07-03 00:52:48 +00006669 UChar sorb, Int delta,
sewardj0bd7ce62004-12-05 02:47:40 +00006670 HChar* opname, IROp op
6671 )
6672{
6673 HChar dis_buf[50];
6674 Int alen;
6675 IRTemp addr;
6676 UChar rm = getIByte(delta);
6677 if (epartIsReg(rm)) {
6678 putXMMReg( gregOfRM(rm),
6679 unop(op, getXMMReg(eregOfRM(rm))) );
6680 DIP("%s %s,%s\n", opname,
6681 nameXMMReg(eregOfRM(rm)),
6682 nameXMMReg(gregOfRM(rm)) );
6683 return delta+1;
6684 } else {
6685 addr = disAMode ( &alen, sorb, delta, dis_buf );
6686 putXMMReg( gregOfRM(rm),
6687 unop(op, loadLE(Ity_V128, mkexpr(addr))) );
6688 DIP("%s %s,%s\n", opname,
6689 dis_buf,
6690 nameXMMReg(gregOfRM(rm)) );
6691 return delta+alen;
6692 }
6693}
6694
sewardj164f9272004-12-09 00:39:32 +00006695
sewardj129b3d92004-12-05 15:42:05 +00006696/* Lowest 32-bit lane only unary SSE operation, G = op(E). */
sewardj0bd7ce62004-12-05 02:47:40 +00006697
sewardj129b3d92004-12-05 15:42:05 +00006698static UInt dis_SSE_E_to_G_unary_lo32 (
sewardj52d04912005-07-03 00:52:48 +00006699 UChar sorb, Int delta,
sewardj129b3d92004-12-05 15:42:05 +00006700 HChar* opname, IROp op
6701 )
6702{
6703 /* First we need to get the old G value and patch the low 32 bits
6704 of the E operand into it. Then apply op and write back to G. */
6705 HChar dis_buf[50];
6706 Int alen;
6707 IRTemp addr;
6708 UChar rm = getIByte(delta);
6709 IRTemp oldG0 = newTemp(Ity_V128);
6710 IRTemp oldG1 = newTemp(Ity_V128);
6711
6712 assign( oldG0, getXMMReg(gregOfRM(rm)) );
6713
6714 if (epartIsReg(rm)) {
6715 assign( oldG1,
sewardjf0c1c582005-02-07 23:47:38 +00006716 binop( Iop_SetV128lo32,
sewardj129b3d92004-12-05 15:42:05 +00006717 mkexpr(oldG0),
sewardj35579be2004-12-06 00:36:25 +00006718 getXMMRegLane32(eregOfRM(rm), 0)) );
sewardj129b3d92004-12-05 15:42:05 +00006719 putXMMReg( gregOfRM(rm), unop(op, mkexpr(oldG1)) );
6720 DIP("%s %s,%s\n", opname,
6721 nameXMMReg(eregOfRM(rm)),
6722 nameXMMReg(gregOfRM(rm)) );
6723 return delta+1;
6724 } else {
6725 addr = disAMode ( &alen, sorb, delta, dis_buf );
6726 assign( oldG1,
sewardjf0c1c582005-02-07 23:47:38 +00006727 binop( Iop_SetV128lo32,
sewardj129b3d92004-12-05 15:42:05 +00006728 mkexpr(oldG0),
6729 loadLE(Ity_I32, mkexpr(addr)) ));
6730 putXMMReg( gregOfRM(rm), unop(op, mkexpr(oldG1)) );
6731 DIP("%s %s,%s\n", opname,
6732 dis_buf,
6733 nameXMMReg(gregOfRM(rm)) );
6734 return delta+alen;
6735 }
6736}
6737
sewardj164f9272004-12-09 00:39:32 +00006738
sewardj008754b2004-12-08 14:37:10 +00006739/* Lowest 64-bit lane only unary SSE operation, G = op(E). */
6740
6741static UInt dis_SSE_E_to_G_unary_lo64 (
sewardj52d04912005-07-03 00:52:48 +00006742 UChar sorb, Int delta,
sewardj008754b2004-12-08 14:37:10 +00006743 HChar* opname, IROp op
6744 )
6745{
6746 /* First we need to get the old G value and patch the low 64 bits
6747 of the E operand into it. Then apply op and write back to G. */
6748 HChar dis_buf[50];
6749 Int alen;
6750 IRTemp addr;
6751 UChar rm = getIByte(delta);
6752 IRTemp oldG0 = newTemp(Ity_V128);
6753 IRTemp oldG1 = newTemp(Ity_V128);
6754
6755 assign( oldG0, getXMMReg(gregOfRM(rm)) );
6756
6757 if (epartIsReg(rm)) {
6758 assign( oldG1,
sewardjf0c1c582005-02-07 23:47:38 +00006759 binop( Iop_SetV128lo64,
sewardj008754b2004-12-08 14:37:10 +00006760 mkexpr(oldG0),
6761 getXMMRegLane64(eregOfRM(rm), 0)) );
6762 putXMMReg( gregOfRM(rm), unop(op, mkexpr(oldG1)) );
6763 DIP("%s %s,%s\n", opname,
6764 nameXMMReg(eregOfRM(rm)),
6765 nameXMMReg(gregOfRM(rm)) );
6766 return delta+1;
6767 } else {
6768 addr = disAMode ( &alen, sorb, delta, dis_buf );
6769 assign( oldG1,
sewardjf0c1c582005-02-07 23:47:38 +00006770 binop( Iop_SetV128lo64,
sewardj008754b2004-12-08 14:37:10 +00006771 mkexpr(oldG0),
6772 loadLE(Ity_I64, mkexpr(addr)) ));
6773 putXMMReg( gregOfRM(rm), unop(op, mkexpr(oldG1)) );
6774 DIP("%s %s,%s\n", opname,
6775 dis_buf,
6776 nameXMMReg(gregOfRM(rm)) );
6777 return delta+alen;
6778 }
6779}
6780
sewardj164f9272004-12-09 00:39:32 +00006781
6782/* SSE integer binary operation:
6783 G = G `op` E (eLeft == False)
6784 G = E `op` G (eLeft == True)
6785*/
6786static UInt dis_SSEint_E_to_G(
sewardj52d04912005-07-03 00:52:48 +00006787 UChar sorb, Int delta,
sewardj164f9272004-12-09 00:39:32 +00006788 HChar* opname, IROp op,
6789 Bool eLeft
6790 )
6791{
6792 HChar dis_buf[50];
6793 Int alen;
6794 IRTemp addr;
6795 UChar rm = getIByte(delta);
6796 IRExpr* gpart = getXMMReg(gregOfRM(rm));
6797 IRExpr* epart = NULL;
6798 if (epartIsReg(rm)) {
6799 epart = getXMMReg(eregOfRM(rm));
6800 DIP("%s %s,%s\n", opname,
6801 nameXMMReg(eregOfRM(rm)),
6802 nameXMMReg(gregOfRM(rm)) );
6803 delta += 1;
6804 } else {
6805 addr = disAMode ( &alen, sorb, delta, dis_buf );
6806 epart = loadLE(Ity_V128, mkexpr(addr));
6807 DIP("%s %s,%s\n", opname,
6808 dis_buf,
6809 nameXMMReg(gregOfRM(rm)) );
6810 delta += alen;
6811 }
6812 putXMMReg( gregOfRM(rm),
6813 eLeft ? binop(op, epart, gpart)
6814 : binop(op, gpart, epart) );
6815 return delta;
6816}
6817
6818
sewardjfd226452004-12-07 19:02:18 +00006819/* Helper for doing SSE FP comparisons. */
sewardj0bd7ce62004-12-05 02:47:40 +00006820
sewardj1e6ad742004-12-02 16:16:11 +00006821static void findSSECmpOp ( Bool* needNot, IROp* op,
6822 Int imm8, Bool all_lanes, Int sz )
6823{
6824 imm8 &= 7;
6825 *needNot = False;
6826 *op = Iop_INVALID;
6827 if (imm8 >= 4) {
6828 *needNot = True;
6829 imm8 -= 4;
6830 }
6831
6832 if (sz == 4 && all_lanes) {
6833 switch (imm8) {
6834 case 0: *op = Iop_CmpEQ32Fx4; return;
6835 case 1: *op = Iop_CmpLT32Fx4; return;
6836 case 2: *op = Iop_CmpLE32Fx4; return;
6837 case 3: *op = Iop_CmpUN32Fx4; return;
6838 default: break;
6839 }
6840 }
6841 if (sz == 4 && !all_lanes) {
6842 switch (imm8) {
6843 case 0: *op = Iop_CmpEQ32F0x4; return;
6844 case 1: *op = Iop_CmpLT32F0x4; return;
6845 case 2: *op = Iop_CmpLE32F0x4; return;
6846 case 3: *op = Iop_CmpUN32F0x4; return;
6847 default: break;
6848 }
6849 }
sewardjfd226452004-12-07 19:02:18 +00006850 if (sz == 8 && all_lanes) {
6851 switch (imm8) {
6852 case 0: *op = Iop_CmpEQ64Fx2; return;
6853 case 1: *op = Iop_CmpLT64Fx2; return;
6854 case 2: *op = Iop_CmpLE64Fx2; return;
6855 case 3: *op = Iop_CmpUN64Fx2; return;
6856 default: break;
6857 }
6858 }
6859 if (sz == 8 && !all_lanes) {
6860 switch (imm8) {
6861 case 0: *op = Iop_CmpEQ64F0x2; return;
6862 case 1: *op = Iop_CmpLT64F0x2; return;
6863 case 2: *op = Iop_CmpLE64F0x2; return;
6864 case 3: *op = Iop_CmpUN64F0x2; return;
6865 default: break;
6866 }
sewardj1e6ad742004-12-02 16:16:11 +00006867 }
6868 vpanic("findSSECmpOp(x86,guest)");
6869}
6870
sewardj33c69e52006-01-01 17:15:19 +00006871/* Handles SSE 32F/64F comparisons. */
sewardj129b3d92004-12-05 15:42:05 +00006872
sewardj52d04912005-07-03 00:52:48 +00006873static UInt dis_SSEcmp_E_to_G ( UChar sorb, Int delta,
sewardj1e6ad742004-12-02 16:16:11 +00006874 HChar* opname, Bool all_lanes, Int sz )
6875{
6876 HChar dis_buf[50];
6877 Int alen, imm8;
6878 IRTemp addr;
6879 Bool needNot = False;
6880 IROp op = Iop_INVALID;
6881 IRTemp plain = newTemp(Ity_V128);
6882 UChar rm = getIByte(delta);
6883 UShort mask = 0;
6884 vassert(sz == 4 || sz == 8);
6885 if (epartIsReg(rm)) {
6886 imm8 = getIByte(delta+1);
6887 findSSECmpOp(&needNot, &op, imm8, all_lanes, sz);
6888 assign( plain, binop(op, getXMMReg(gregOfRM(rm)),
6889 getXMMReg(eregOfRM(rm))) );
6890 delta += 2;
6891 DIP("%s $%d,%s,%s\n", opname,
6892 (Int)imm8,
6893 nameXMMReg(eregOfRM(rm)),
6894 nameXMMReg(gregOfRM(rm)) );
6895 } else {
6896 addr = disAMode ( &alen, sorb, delta, dis_buf );
6897 imm8 = getIByte(delta+alen);
6898 findSSECmpOp(&needNot, &op, imm8, all_lanes, sz);
sewardj33c69e52006-01-01 17:15:19 +00006899 assign( plain,
6900 binop(
6901 op,
6902 getXMMReg(gregOfRM(rm)),
6903 all_lanes ? loadLE(Ity_V128, mkexpr(addr))
6904 : sz == 8 ? unop( Iop_64UtoV128, loadLE(Ity_I64, mkexpr(addr)))
6905 : /*sz==4*/ unop( Iop_32UtoV128, loadLE(Ity_I32, mkexpr(addr)))
6906 )
6907 );
sewardj1e6ad742004-12-02 16:16:11 +00006908 delta += alen+1;
6909 DIP("%s $%d,%s,%s\n", opname,
6910 (Int)imm8,
6911 dis_buf,
6912 nameXMMReg(gregOfRM(rm)) );
6913 }
6914
sewardj2e383862004-12-12 16:46:47 +00006915 if (needNot && all_lanes) {
6916 putXMMReg( gregOfRM(rm),
sewardjf0c1c582005-02-07 23:47:38 +00006917 unop(Iop_NotV128, mkexpr(plain)) );
sewardj2e383862004-12-12 16:46:47 +00006918 }
6919 else
6920 if (needNot && !all_lanes) {
sewardj9b45b482005-02-07 01:42:18 +00006921 mask = toUShort( sz==4 ? 0x000F : 0x00FF );
sewardj2e383862004-12-12 16:46:47 +00006922 putXMMReg( gregOfRM(rm),
sewardjf0c1c582005-02-07 23:47:38 +00006923 binop(Iop_XorV128, mkexpr(plain), mkV128(mask)) );
sewardj2e383862004-12-12 16:46:47 +00006924 }
6925 else {
6926 putXMMReg( gregOfRM(rm), mkexpr(plain) );
6927 }
sewardj1e6ad742004-12-02 16:16:11 +00006928
sewardj1e6ad742004-12-02 16:16:11 +00006929 return delta;
6930}
6931
sewardjb9fa69b2004-12-09 23:25:14 +00006932
6933/* Vector by scalar shift of G by the amount specified at the bottom
6934 of E. */
6935
sewardj52d04912005-07-03 00:52:48 +00006936static UInt dis_SSE_shiftG_byE ( UChar sorb, Int delta,
sewardjb9fa69b2004-12-09 23:25:14 +00006937 HChar* opname, IROp op )
6938{
6939 HChar dis_buf[50];
6940 Int alen, size;
6941 IRTemp addr;
6942 Bool shl, shr, sar;
6943 UChar rm = getIByte(delta);
6944 IRTemp g0 = newTemp(Ity_V128);
6945 IRTemp g1 = newTemp(Ity_V128);
6946 IRTemp amt = newTemp(Ity_I32);
6947 IRTemp amt8 = newTemp(Ity_I8);
6948 if (epartIsReg(rm)) {
6949 assign( amt, getXMMRegLane32(eregOfRM(rm), 0) );
6950 DIP("%s %s,%s\n", opname,
6951 nameXMMReg(eregOfRM(rm)),
6952 nameXMMReg(gregOfRM(rm)) );
6953 delta++;
6954 } else {
6955 addr = disAMode ( &alen, sorb, delta, dis_buf );
6956 assign( amt, loadLE(Ity_I32, mkexpr(addr)) );
6957 DIP("%s %s,%s\n", opname,
6958 dis_buf,
6959 nameXMMReg(gregOfRM(rm)) );
6960 delta += alen;
6961 }
6962 assign( g0, getXMMReg(gregOfRM(rm)) );
6963 assign( amt8, unop(Iop_32to8, mkexpr(amt)) );
6964
6965 shl = shr = sar = False;
6966 size = 0;
6967 switch (op) {
6968 case Iop_ShlN16x8: shl = True; size = 32; break;
6969 case Iop_ShlN32x4: shl = True; size = 32; break;
6970 case Iop_ShlN64x2: shl = True; size = 64; break;
6971 case Iop_SarN16x8: sar = True; size = 16; break;
6972 case Iop_SarN32x4: sar = True; size = 32; break;
6973 case Iop_ShrN16x8: shr = True; size = 16; break;
6974 case Iop_ShrN32x4: shr = True; size = 32; break;
6975 case Iop_ShrN64x2: shr = True; size = 64; break;
6976 default: vassert(0);
6977 }
6978
6979 if (shl || shr) {
6980 assign(
6981 g1,
6982 IRExpr_Mux0X(
6983 unop(Iop_1Uto8,binop(Iop_CmpLT32U,mkexpr(amt),mkU32(size))),
6984 mkV128(0x0000),
6985 binop(op, mkexpr(g0), mkexpr(amt8))
6986 )
6987 );
6988 } else
6989 if (sar) {
6990 assign(
6991 g1,
6992 IRExpr_Mux0X(
6993 unop(Iop_1Uto8,binop(Iop_CmpLT32U,mkexpr(amt),mkU32(size))),
6994 binop(op, mkexpr(g0), mkU8(size-1)),
6995 binop(op, mkexpr(g0), mkexpr(amt8))
6996 )
6997 );
6998 } else {
sewardjba89f4c2005-04-07 17:31:27 +00006999 /*NOTREACHED*/
sewardjb9fa69b2004-12-09 23:25:14 +00007000 vassert(0);
7001 }
7002
7003 putXMMReg( gregOfRM(rm), mkexpr(g1) );
7004 return delta;
7005}
7006
7007
7008/* Vector by scalar shift of E by an immediate byte. */
7009
sewardj38a3f862005-01-13 15:06:51 +00007010static
sewardj52d04912005-07-03 00:52:48 +00007011UInt dis_SSE_shiftE_imm ( Int delta, HChar* opname, IROp op )
sewardjb9fa69b2004-12-09 23:25:14 +00007012{
7013 Bool shl, shr, sar;
7014 UChar rm = getIByte(delta);
sewardj38a3f862005-01-13 15:06:51 +00007015 IRTemp e0 = newTemp(Ity_V128);
7016 IRTemp e1 = newTemp(Ity_V128);
sewardjb9fa69b2004-12-09 23:25:14 +00007017 UChar amt, size;
7018 vassert(epartIsReg(rm));
7019 vassert(gregOfRM(rm) == 2
7020 || gregOfRM(rm) == 4 || gregOfRM(rm) == 6);
sewardj2d49b432005-02-01 00:37:06 +00007021 amt = getIByte(delta+1);
sewardjb9fa69b2004-12-09 23:25:14 +00007022 delta += 2;
7023 DIP("%s $%d,%s\n", opname,
7024 (Int)amt,
7025 nameXMMReg(eregOfRM(rm)) );
sewardj38a3f862005-01-13 15:06:51 +00007026 assign( e0, getXMMReg(eregOfRM(rm)) );
sewardjb9fa69b2004-12-09 23:25:14 +00007027
7028 shl = shr = sar = False;
7029 size = 0;
7030 switch (op) {
7031 case Iop_ShlN16x8: shl = True; size = 16; break;
7032 case Iop_ShlN32x4: shl = True; size = 32; break;
7033 case Iop_ShlN64x2: shl = True; size = 64; break;
7034 case Iop_SarN16x8: sar = True; size = 16; break;
7035 case Iop_SarN32x4: sar = True; size = 32; break;
7036 case Iop_ShrN16x8: shr = True; size = 16; break;
7037 case Iop_ShrN32x4: shr = True; size = 32; break;
7038 case Iop_ShrN64x2: shr = True; size = 64; break;
7039 default: vassert(0);
7040 }
7041
7042 if (shl || shr) {
sewardjba89f4c2005-04-07 17:31:27 +00007043 assign( e1, amt >= size
7044 ? mkV128(0x0000)
7045 : binop(op, mkexpr(e0), mkU8(amt))
7046 );
sewardjb9fa69b2004-12-09 23:25:14 +00007047 } else
7048 if (sar) {
sewardjba89f4c2005-04-07 17:31:27 +00007049 assign( e1, amt >= size
7050 ? binop(op, mkexpr(e0), mkU8(size-1))
7051 : binop(op, mkexpr(e0), mkU8(amt))
7052 );
sewardjb9fa69b2004-12-09 23:25:14 +00007053 } else {
sewardjba89f4c2005-04-07 17:31:27 +00007054 /*NOTREACHED*/
sewardjb9fa69b2004-12-09 23:25:14 +00007055 vassert(0);
7056 }
7057
sewardj38a3f862005-01-13 15:06:51 +00007058 putXMMReg( eregOfRM(rm), mkexpr(e1) );
sewardjb9fa69b2004-12-09 23:25:14 +00007059 return delta;
7060}
7061
7062
sewardjc1e7dfc2004-12-05 19:29:45 +00007063/* Get the current SSE rounding mode. */
sewardjc9a65702004-07-07 16:32:57 +00007064
sewardj4cb918d2004-12-03 19:43:31 +00007065static IRExpr* /* :: Ity_I32 */ get_sse_roundingmode ( void )
7066{
7067 return binop( Iop_And32,
7068 IRExpr_Get( OFFB_SSEROUND, Ity_I32 ),
7069 mkU32(3) );
7070}
7071
sewardj636ad762004-12-07 11:16:04 +00007072static void put_sse_roundingmode ( IRExpr* sseround )
7073{
sewardjdd40fdf2006-12-24 02:20:24 +00007074 vassert(typeOfIRExpr(irsb->tyenv, sseround) == Ity_I32);
sewardj636ad762004-12-07 11:16:04 +00007075 stmt( IRStmt_Put( OFFB_SSEROUND, sseround ) );
7076}
7077
sewardjc1e7dfc2004-12-05 19:29:45 +00007078/* Break a 128-bit value up into four 32-bit ints. */
7079
7080static void breakup128to32s ( IRTemp t128,
7081 /*OUTs*/
7082 IRTemp* t3, IRTemp* t2,
7083 IRTemp* t1, IRTemp* t0 )
7084{
7085 IRTemp hi64 = newTemp(Ity_I64);
7086 IRTemp lo64 = newTemp(Ity_I64);
sewardjf0c1c582005-02-07 23:47:38 +00007087 assign( hi64, unop(Iop_V128HIto64, mkexpr(t128)) );
7088 assign( lo64, unop(Iop_V128to64, mkexpr(t128)) );
sewardjc1e7dfc2004-12-05 19:29:45 +00007089
7090 vassert(t0 && *t0 == IRTemp_INVALID);
7091 vassert(t1 && *t1 == IRTemp_INVALID);
7092 vassert(t2 && *t2 == IRTemp_INVALID);
7093 vassert(t3 && *t3 == IRTemp_INVALID);
7094
7095 *t0 = newTemp(Ity_I32);
7096 *t1 = newTemp(Ity_I32);
7097 *t2 = newTemp(Ity_I32);
7098 *t3 = newTemp(Ity_I32);
7099 assign( *t0, unop(Iop_64to32, mkexpr(lo64)) );
7100 assign( *t1, unop(Iop_64HIto32, mkexpr(lo64)) );
7101 assign( *t2, unop(Iop_64to32, mkexpr(hi64)) );
7102 assign( *t3, unop(Iop_64HIto32, mkexpr(hi64)) );
7103}
7104
7105/* Construct a 128-bit value from four 32-bit ints. */
7106
7107static IRExpr* mk128from32s ( IRTemp t3, IRTemp t2,
7108 IRTemp t1, IRTemp t0 )
7109{
7110 return
sewardjf0c1c582005-02-07 23:47:38 +00007111 binop( Iop_64HLtoV128,
sewardjc1e7dfc2004-12-05 19:29:45 +00007112 binop(Iop_32HLto64, mkexpr(t3), mkexpr(t2)),
7113 binop(Iop_32HLto64, mkexpr(t1), mkexpr(t0))
7114 );
7115}
7116
sewardjb9fa69b2004-12-09 23:25:14 +00007117/* Break a 64-bit value up into four 16-bit ints. */
7118
7119static void breakup64to16s ( IRTemp t64,
7120 /*OUTs*/
7121 IRTemp* t3, IRTemp* t2,
7122 IRTemp* t1, IRTemp* t0 )
7123{
7124 IRTemp hi32 = newTemp(Ity_I32);
7125 IRTemp lo32 = newTemp(Ity_I32);
7126 assign( hi32, unop(Iop_64HIto32, mkexpr(t64)) );
7127 assign( lo32, unop(Iop_64to32, mkexpr(t64)) );
7128
7129 vassert(t0 && *t0 == IRTemp_INVALID);
7130 vassert(t1 && *t1 == IRTemp_INVALID);
7131 vassert(t2 && *t2 == IRTemp_INVALID);
7132 vassert(t3 && *t3 == IRTemp_INVALID);
7133
7134 *t0 = newTemp(Ity_I16);
7135 *t1 = newTemp(Ity_I16);
7136 *t2 = newTemp(Ity_I16);
7137 *t3 = newTemp(Ity_I16);
7138 assign( *t0, unop(Iop_32to16, mkexpr(lo32)) );
7139 assign( *t1, unop(Iop_32HIto16, mkexpr(lo32)) );
7140 assign( *t2, unop(Iop_32to16, mkexpr(hi32)) );
7141 assign( *t3, unop(Iop_32HIto16, mkexpr(hi32)) );
7142}
7143
7144/* Construct a 64-bit value from four 16-bit ints. */
7145
7146static IRExpr* mk64from16s ( IRTemp t3, IRTemp t2,
7147 IRTemp t1, IRTemp t0 )
7148{
7149 return
7150 binop( Iop_32HLto64,
7151 binop(Iop_16HLto32, mkexpr(t3), mkexpr(t2)),
7152 binop(Iop_16HLto32, mkexpr(t1), mkexpr(t0))
7153 );
7154}
7155
sewardj0e9a0f52008-01-04 01:22:41 +00007156/* Generate IR to set the guest %EFLAGS from the pushfl-format image
7157 in the given 32-bit temporary. The flags that are set are: O S Z A
7158 C P D ID AC.
7159
7160 In all cases, code to set AC is generated. However, VEX actually
7161 ignores the AC value and so can optionally emit an emulation
7162 warning when it is enabled. In this routine, an emulation warning
7163 is only emitted if emit_AC_emwarn is True, in which case
7164 next_insn_EIP must be correct (this allows for correct code
7165 generation for popfl/popfw). If emit_AC_emwarn is False,
7166 next_insn_EIP is unimportant (this allows for easy if kludgey code
7167 generation for IRET.) */
7168
7169static
7170void set_EFLAGS_from_value ( IRTemp t1,
7171 Bool emit_AC_emwarn,
7172 Addr32 next_insn_EIP )
7173{
7174 vassert(typeOfIRTemp(irsb->tyenv,t1) == Ity_I32);
7175
7176 /* t1 is the flag word. Mask out everything except OSZACP and set
7177 the flags thunk to X86G_CC_OP_COPY. */
7178 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
7179 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
7180 stmt( IRStmt_Put( OFFB_CC_DEP1,
7181 binop(Iop_And32,
7182 mkexpr(t1),
7183 mkU32( X86G_CC_MASK_C | X86G_CC_MASK_P
7184 | X86G_CC_MASK_A | X86G_CC_MASK_Z
7185 | X86G_CC_MASK_S| X86G_CC_MASK_O )
7186 )
7187 )
7188 );
7189 /* Set NDEP even though it isn't used. This makes redundant-PUT
7190 elimination of previous stores to this field work better. */
7191 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
7192
7193 /* Also need to set the D flag, which is held in bit 10 of t1.
7194 If zero, put 1 in OFFB_DFLAG, else -1 in OFFB_DFLAG. */
7195 stmt( IRStmt_Put(
7196 OFFB_DFLAG,
7197 IRExpr_Mux0X(
7198 unop(Iop_32to8,
7199 binop(Iop_And32,
7200 binop(Iop_Shr32, mkexpr(t1), mkU8(10)),
7201 mkU32(1))),
7202 mkU32(1),
7203 mkU32(0xFFFFFFFF)))
7204 );
7205
7206 /* Set the ID flag */
7207 stmt( IRStmt_Put(
7208 OFFB_IDFLAG,
7209 IRExpr_Mux0X(
7210 unop(Iop_32to8,
7211 binop(Iop_And32,
7212 binop(Iop_Shr32, mkexpr(t1), mkU8(21)),
7213 mkU32(1))),
7214 mkU32(0),
7215 mkU32(1)))
7216 );
7217
7218 /* And set the AC flag. If setting it 1 to, possibly emit an
7219 emulation warning. */
7220 stmt( IRStmt_Put(
7221 OFFB_ACFLAG,
7222 IRExpr_Mux0X(
7223 unop(Iop_32to8,
7224 binop(Iop_And32,
7225 binop(Iop_Shr32, mkexpr(t1), mkU8(18)),
7226 mkU32(1))),
7227 mkU32(0),
7228 mkU32(1)))
7229 );
7230
7231 if (emit_AC_emwarn) {
7232 put_emwarn( mkU32(EmWarn_X86_acFlag) );
7233 stmt(
7234 IRStmt_Exit(
7235 binop( Iop_CmpNE32,
7236 binop(Iop_And32, mkexpr(t1), mkU32(1<<18)),
7237 mkU32(0) ),
7238 Ijk_EmWarn,
7239 IRConst_U32( next_insn_EIP )
7240 )
7241 );
7242 }
7243}
7244
sewardj4cb918d2004-12-03 19:43:31 +00007245
sewardj150c9cd2008-02-09 01:16:02 +00007246/* Helper for the SSSE3 (not SSE3) PMULHRSW insns. Given two 64-bit
7247 values (aa,bb), computes, for each of the 4 16-bit lanes:
7248
7249 (((aa_lane *s32 bb_lane) >>u 14) + 1) >>u 1
7250*/
7251static IRExpr* dis_PMULHRSW_helper ( IRExpr* aax, IRExpr* bbx )
7252{
7253 IRTemp aa = newTemp(Ity_I64);
7254 IRTemp bb = newTemp(Ity_I64);
7255 IRTemp aahi32s = newTemp(Ity_I64);
7256 IRTemp aalo32s = newTemp(Ity_I64);
7257 IRTemp bbhi32s = newTemp(Ity_I64);
7258 IRTemp bblo32s = newTemp(Ity_I64);
7259 IRTemp rHi = newTemp(Ity_I64);
7260 IRTemp rLo = newTemp(Ity_I64);
7261 IRTemp one32x2 = newTemp(Ity_I64);
7262 assign(aa, aax);
7263 assign(bb, bbx);
7264 assign( aahi32s,
7265 binop(Iop_SarN32x2,
7266 binop(Iop_InterleaveHI16x4, mkexpr(aa), mkexpr(aa)),
7267 mkU8(16) ));
7268 assign( aalo32s,
7269 binop(Iop_SarN32x2,
7270 binop(Iop_InterleaveLO16x4, mkexpr(aa), mkexpr(aa)),
7271 mkU8(16) ));
7272 assign( bbhi32s,
7273 binop(Iop_SarN32x2,
7274 binop(Iop_InterleaveHI16x4, mkexpr(bb), mkexpr(bb)),
7275 mkU8(16) ));
7276 assign( bblo32s,
7277 binop(Iop_SarN32x2,
7278 binop(Iop_InterleaveLO16x4, mkexpr(bb), mkexpr(bb)),
7279 mkU8(16) ));
7280 assign(one32x2, mkU64( (1ULL << 32) + 1 ));
7281 assign(
7282 rHi,
7283 binop(
7284 Iop_ShrN32x2,
7285 binop(
7286 Iop_Add32x2,
7287 binop(
7288 Iop_ShrN32x2,
7289 binop(Iop_Mul32x2, mkexpr(aahi32s), mkexpr(bbhi32s)),
7290 mkU8(14)
7291 ),
7292 mkexpr(one32x2)
7293 ),
7294 mkU8(1)
7295 )
7296 );
7297 assign(
7298 rLo,
7299 binop(
7300 Iop_ShrN32x2,
7301 binop(
7302 Iop_Add32x2,
7303 binop(
7304 Iop_ShrN32x2,
7305 binop(Iop_Mul32x2, mkexpr(aalo32s), mkexpr(bblo32s)),
7306 mkU8(14)
7307 ),
7308 mkexpr(one32x2)
7309 ),
7310 mkU8(1)
7311 )
7312 );
7313 return
7314 binop(Iop_CatEvenLanes16x4, mkexpr(rHi), mkexpr(rLo));
7315}
7316
7317/* Helper for the SSSE3 (not SSE3) PSIGN{B,W,D} insns. Given two 64-bit
7318 values (aa,bb), computes, for each lane:
7319
7320 if aa_lane < 0 then - bb_lane
7321 else if aa_lane > 0 then bb_lane
7322 else 0
7323*/
7324static IRExpr* dis_PSIGN_helper ( IRExpr* aax, IRExpr* bbx, Int laneszB )
7325{
7326 IRTemp aa = newTemp(Ity_I64);
7327 IRTemp bb = newTemp(Ity_I64);
7328 IRTemp zero = newTemp(Ity_I64);
7329 IRTemp bbNeg = newTemp(Ity_I64);
7330 IRTemp negMask = newTemp(Ity_I64);
7331 IRTemp posMask = newTemp(Ity_I64);
7332 IROp opSub = Iop_INVALID;
7333 IROp opCmpGTS = Iop_INVALID;
7334
7335 switch (laneszB) {
7336 case 1: opSub = Iop_Sub8x8; opCmpGTS = Iop_CmpGT8Sx8; break;
7337 case 2: opSub = Iop_Sub16x4; opCmpGTS = Iop_CmpGT16Sx4; break;
7338 case 4: opSub = Iop_Sub32x2; opCmpGTS = Iop_CmpGT32Sx2; break;
7339 default: vassert(0);
7340 }
7341
7342 assign( aa, aax );
7343 assign( bb, bbx );
7344 assign( zero, mkU64(0) );
7345 assign( bbNeg, binop(opSub, mkexpr(zero), mkexpr(bb)) );
7346 assign( negMask, binop(opCmpGTS, mkexpr(zero), mkexpr(aa)) );
7347 assign( posMask, binop(opCmpGTS, mkexpr(aa), mkexpr(zero)) );
7348
7349 return
7350 binop(Iop_Or64,
7351 binop(Iop_And64, mkexpr(bb), mkexpr(posMask)),
7352 binop(Iop_And64, mkexpr(bbNeg), mkexpr(negMask)) );
7353
7354}
7355
7356/* Helper for the SSSE3 (not SSE3) PABS{B,W,D} insns. Given a 64-bit
7357 value aa, computes, for each lane
7358
7359 if aa < 0 then -aa else aa
7360
7361 Note that the result is interpreted as unsigned, so that the
7362 absolute value of the most negative signed input can be
7363 represented.
7364*/
7365static IRExpr* dis_PABS_helper ( IRExpr* aax, Int laneszB )
7366{
7367 IRTemp aa = newTemp(Ity_I64);
7368 IRTemp zero = newTemp(Ity_I64);
7369 IRTemp aaNeg = newTemp(Ity_I64);
7370 IRTemp negMask = newTemp(Ity_I64);
7371 IRTemp posMask = newTemp(Ity_I64);
7372 IROp opSub = Iop_INVALID;
7373 IROp opSarN = Iop_INVALID;
7374
7375 switch (laneszB) {
7376 case 1: opSub = Iop_Sub8x8; opSarN = Iop_SarN8x8; break;
7377 case 2: opSub = Iop_Sub16x4; opSarN = Iop_SarN16x4; break;
7378 case 4: opSub = Iop_Sub32x2; opSarN = Iop_SarN32x2; break;
7379 default: vassert(0);
7380 }
7381
7382 assign( aa, aax );
7383 assign( negMask, binop(opSarN, mkexpr(aa), mkU8(8*laneszB-1)) );
7384 assign( posMask, unop(Iop_Not64, mkexpr(negMask)) );
7385 assign( zero, mkU64(0) );
7386 assign( aaNeg, binop(opSub, mkexpr(zero), mkexpr(aa)) );
7387 return
7388 binop(Iop_Or64,
7389 binop(Iop_And64, mkexpr(aa), mkexpr(posMask)),
7390 binop(Iop_And64, mkexpr(aaNeg), mkexpr(negMask)) );
7391}
7392
7393static IRExpr* dis_PALIGNR_XMM_helper ( IRTemp hi64,
7394 IRTemp lo64, Int byteShift )
7395{
7396 vassert(byteShift >= 1 && byteShift <= 7);
7397 return
7398 binop(Iop_Or64,
7399 binop(Iop_Shl64, mkexpr(hi64), mkU8(8*(8-byteShift))),
7400 binop(Iop_Shr64, mkexpr(lo64), mkU8(8*byteShift))
7401 );
7402}
7403
7404/* Generate a SIGSEGV followed by a restart of the current instruction
7405 if effective_addr is not 16-aligned. This is required behaviour
7406 for some SSE3 instructions and all 128-bit SSSE3 instructions.
7407 This assumes that guest_RIP_curr_instr is set correctly! */
7408static void gen_SEGV_if_not_16_aligned ( IRTemp effective_addr )
7409{
7410 stmt(
7411 IRStmt_Exit(
7412 binop(Iop_CmpNE32,
7413 binop(Iop_And32,mkexpr(effective_addr),mkU32(0xF)),
7414 mkU32(0)),
7415 Ijk_SigSEGV,
7416 IRConst_U32(guest_EIP_curr_instr)
7417 )
7418 );
7419}
7420
7421
sewardjc4356f02007-11-09 21:15:04 +00007422/* Helper for deciding whether a given insn (starting at the opcode
7423 byte) may validly be used with a LOCK prefix. The following insns
7424 may be used with LOCK when their destination operand is in memory.
7425 Note, this is slightly too permissive. Oh well. Note also, AFAICS
7426 this is exactly the same for both 32-bit and 64-bit mode.
7427
7428 ADD 80 /0, 81 /0, 83 /0, 00, 01, 02, 03
7429 OR 80 /1, 81 /1, 83 /1, 08, 09, 0A, 0B
7430 ADC 80 /2, 81 /2, 83 /2, 10, 11, 12, 13
7431 SBB 81 /3, 81 /3, 83 /3, 18, 19, 1A, 1B
7432 AND 80 /4, 81 /4, 83 /4, 20, 21, 22, 23
7433 SUB 80 /5, 81 /5, 83 /5, 28, 29, 2A, 2B
7434 XOR 80 /6, 81 /6, 83 /6, 30, 31, 32, 33
7435
7436 DEC FE /1, FF /1
7437 INC FE /0, FF /0
7438
7439 NEG F6 /3, F7 /3
7440 NOT F6 /2, F7 /2
7441
7442 XCHG 86, 87
7443
7444 BTC 0F BB, 0F BA /7
7445 BTR 0F B3, 0F BA /6
7446 BTS 0F AB, 0F BA /5
7447
7448 CMPXCHG 0F B0, 0F B1
7449 CMPXCHG8B 0F C7 /1
7450
7451 XADD 0F C0, 0F C1
7452*/
7453static Bool can_be_used_with_LOCK_prefix ( UChar* opc )
7454{
7455 switch (opc[0]) {
7456 case 0x00: case 0x01: case 0x02: case 0x03: return True;
7457 case 0x08: case 0x09: case 0x0A: case 0x0B: return True;
7458 case 0x10: case 0x11: case 0x12: case 0x13: return True;
7459 case 0x18: case 0x19: case 0x1A: case 0x1B: return True;
7460 case 0x20: case 0x21: case 0x22: case 0x23: return True;
7461 case 0x28: case 0x29: case 0x2A: case 0x2B: return True;
7462 case 0x30: case 0x31: case 0x32: case 0x33: return True;
7463
7464 case 0x80: case 0x81: case 0x83:
7465 if (gregOfRM(opc[1]) >= 0 && gregOfRM(opc[1]) <= 6)
7466 return True;
7467 break;
7468
7469 case 0xFE: case 0xFF:
7470 if (gregOfRM(opc[1]) >= 0 && gregOfRM(opc[1]) <= 1)
7471 return True;
7472 break;
7473
7474 case 0xF6: case 0xF7:
7475 if (gregOfRM(opc[1]) >= 2 && gregOfRM(opc[1]) <= 3)
7476 return True;
7477 break;
7478
7479 case 0x86: case 0x87:
7480 return True;
7481
7482 case 0x0F: {
7483 switch (opc[1]) {
7484 case 0xBB: case 0xB3: case 0xAB:
7485 return True;
7486 case 0xBA:
7487 if (gregOfRM(opc[2]) >= 5 && gregOfRM(opc[2]) <= 7)
7488 return True;
7489 break;
7490 case 0xB0: case 0xB1:
7491 return True;
7492 case 0xC7:
7493 if (gregOfRM(opc[2]) == 1)
7494 return True;
7495 break;
7496 case 0xC0: case 0xC1:
7497 return True;
7498 default:
7499 break;
7500 } /* switch (opc[1]) */
7501 break;
7502 }
7503
7504 default:
7505 break;
7506 } /* switch (opc[0]) */
7507
7508 return False;
7509}
7510
7511
sewardjc9a65702004-07-07 16:32:57 +00007512/*------------------------------------------------------------*/
sewardjce70a5c2004-10-18 14:09:54 +00007513/*--- Disassemble a single instruction ---*/
sewardjc9a65702004-07-07 16:32:57 +00007514/*------------------------------------------------------------*/
7515
sewardjce70a5c2004-10-18 14:09:54 +00007516/* Disassemble a single instruction into IR. The instruction
sewardj9e6491a2005-07-02 19:24:10 +00007517 is located in host memory at &guest_code[delta]. */
7518
7519static
7520DisResult disInstr_X86_WRK (
7521 Bool put_IP,
sewardjc716aea2006-01-17 01:48:46 +00007522 Bool (*resteerOkFn) ( /*opaque*/void*, Addr64 ),
7523 void* callback_opaque,
sewardj9e6491a2005-07-02 19:24:10 +00007524 Long delta64,
7525 VexArchInfo* archinfo
7526 )
sewardjc9a65702004-07-07 16:32:57 +00007527{
sewardjce70a5c2004-10-18 14:09:54 +00007528 IRType ty;
sewardjb5452082004-12-04 20:33:02 +00007529 IRTemp addr, t0, t1, t2, t3, t4, t5, t6;
sewardjce70a5c2004-10-18 14:09:54 +00007530 Int alen;
sewardjc4356f02007-11-09 21:15:04 +00007531 UChar opc, modrm, abyte, pre;
sewardjce70a5c2004-10-18 14:09:54 +00007532 UInt d32;
sewardjc9a43662004-11-30 18:51:59 +00007533 HChar dis_buf[50];
sewardjc4356f02007-11-09 21:15:04 +00007534 Int am_sz, d_sz, n_prefixes;
sewardj9e6491a2005-07-02 19:24:10 +00007535 DisResult dres;
sewardjc9a43662004-11-30 18:51:59 +00007536 UChar* insn; /* used in SSE decoders */
sewardjce70a5c2004-10-18 14:09:54 +00007537
sewardj9e6491a2005-07-02 19:24:10 +00007538 /* The running delta */
7539 Int delta = (Int)delta64;
7540
sewardjc9a65702004-07-07 16:32:57 +00007541 /* Holds eip at the start of the insn, so that we can print
7542 consistent error messages for unimplemented insns. */
sewardj9e6491a2005-07-02 19:24:10 +00007543 Int delta_start = delta;
sewardjc9a65702004-07-07 16:32:57 +00007544
7545 /* sz denotes the nominal data-op size of the insn; we change it to
7546 2 if an 0x66 prefix is seen */
7547 Int sz = 4;
7548
7549 /* sorb holds the segment-override-prefix byte, if any. Zero if no
7550 prefix has been seen, else one of {0x26, 0x3E, 0x64, 0x65}
7551 indicating the prefix. */
7552 UChar sorb = 0;
7553
sewardjc4356f02007-11-09 21:15:04 +00007554 /* Gets set to True if a LOCK prefix is seen. */
7555 Bool pfx_lock = False;
7556
7557 /* do we need follow the insn with MBusEvent(BusUnlock) ? */
7558 Bool unlock_bus_after_insn = False;
7559
sewardj9e6491a2005-07-02 19:24:10 +00007560 /* Set result defaults. */
7561 dres.whatNext = Dis_Continue;
7562 dres.len = 0;
7563 dres.continueAt = 0;
sewardjce70a5c2004-10-18 14:09:54 +00007564
sewardjb5452082004-12-04 20:33:02 +00007565 addr = t0 = t1 = t2 = t3 = t4 = t5 = t6 = IRTemp_INVALID;
sewardjc9a65702004-07-07 16:32:57 +00007566
sewardj9e6491a2005-07-02 19:24:10 +00007567 DIP("\t0x%x: ", guest_EIP_bbstart+delta);
7568
7569 /* We may be asked to update the guest EIP before going further. */
7570 if (put_IP)
7571 stmt( IRStmt_Put( OFFB_EIP, mkU32(guest_EIP_curr_instr)) );
sewardjc9a65702004-07-07 16:32:57 +00007572
sewardjce02aa72006-01-12 12:27:58 +00007573 /* Spot "Special" instructions (see comment at top of file). */
sewardj750f4072004-07-26 22:39:11 +00007574 {
7575 UChar* code = (UChar*)(guest_code + delta);
sewardjce02aa72006-01-12 12:27:58 +00007576 /* Spot the 12-byte preamble:
7577 C1C703 roll $3, %edi
7578 C1C70D roll $13, %edi
7579 C1C71D roll $29, %edi
7580 C1C713 roll $19, %edi
sewardj750f4072004-07-26 22:39:11 +00007581 */
sewardjce02aa72006-01-12 12:27:58 +00007582 if (code[ 0] == 0xC1 && code[ 1] == 0xC7 && code[ 2] == 0x03 &&
7583 code[ 3] == 0xC1 && code[ 4] == 0xC7 && code[ 5] == 0x0D &&
7584 code[ 6] == 0xC1 && code[ 7] == 0xC7 && code[ 8] == 0x1D &&
7585 code[ 9] == 0xC1 && code[10] == 0xC7 && code[11] == 0x13) {
7586 /* Got a "Special" instruction preamble. Which one is it? */
7587 if (code[12] == 0x87 && code[13] == 0xDB /* xchgl %ebx,%ebx */) {
7588 /* %EDX = client_request ( %EAX ) */
7589 DIP("%%edx = client_request ( %%eax )\n");
7590 delta += 14;
7591 jmp_lit(Ijk_ClientReq, guest_EIP_bbstart+delta);
7592 dres.whatNext = Dis_StopHere;
7593 goto decode_success;
7594 }
7595 else
7596 if (code[12] == 0x87 && code[13] == 0xC9 /* xchgl %ecx,%ecx */) {
7597 /* %EAX = guest_NRADDR */
7598 DIP("%%eax = guest_NRADDR\n");
7599 delta += 14;
7600 putIReg(4, R_EAX, IRExpr_Get( OFFB_NRADDR, Ity_I32 ));
7601 goto decode_success;
7602 }
7603 else
7604 if (code[12] == 0x87 && code[13] == 0xD2 /* xchgl %edx,%edx */) {
7605 /* call-noredir *%EAX */
7606 DIP("call-noredir *%%eax\n");
7607 delta += 14;
7608 t1 = newTemp(Ity_I32);
7609 assign(t1, getIReg(4,R_EAX));
7610 t2 = newTemp(Ity_I32);
7611 assign(t2, binop(Iop_Sub32, getIReg(4,R_ESP), mkU32(4)));
7612 putIReg(4, R_ESP, mkexpr(t2));
7613 storeLE( mkexpr(t2), mkU32(guest_EIP_bbstart+delta));
7614 jmp_treg(Ijk_NoRedir,t1);
7615 dres.whatNext = Dis_StopHere;
7616 goto decode_success;
7617 }
7618 /* We don't know what it is. */
7619 goto decode_failure;
7620 /*NOTREACHED*/
sewardj750f4072004-07-26 22:39:11 +00007621 }
7622 }
sewardjc9a65702004-07-07 16:32:57 +00007623
sewardjc4356f02007-11-09 21:15:04 +00007624 /* Handle a couple of weird-ass NOPs that have been observed in the
7625 wild. */
7626 {
sewardjbb3f52d2005-01-07 14:14:50 +00007627 UChar* code = (UChar*)(guest_code + delta);
sewardjc4356f02007-11-09 21:15:04 +00007628 /* Sun's JVM 1.5.0 uses the following as a NOP:
7629 26 2E 64 65 90 %es:%cs:%fs:%gs:nop */
7630 if (code[0] == 0x26 && code[1] == 0x2E && code[2] == 0x64
7631 && code[3] == 0x65 && code[4] == 0x90) {
7632 DIP("%%es:%%cs:%%fs:%%gs:nop\n");
7633 delta += 5;
7634 goto decode_success;
sewardjbb3f52d2005-01-07 14:14:50 +00007635 }
sewardjc4356f02007-11-09 21:15:04 +00007636 /* don't barf on recent binutils padding
7637 66 2e 0f 1f 84 00 00 00 00 00 nopw %cs:0x0(%eax,%eax,1) */
7638 if (code[0] == 0x66
7639 && code[1] == 0x2E && code[2] == 0x0F && code[3] == 0x1F
7640 && code[4] == 0x84 && code[5] == 0x00 && code[6] == 0x00
7641 && code[7] == 0x00 && code[8] == 0x00 && code[9] == 0x00 ) {
7642 DIP("nopw %%cs:0x0(%%eax,%%eax,1)\n");
7643 delta += 10;
7644 goto decode_success;
sewardjce4a2822005-01-07 13:25:28 +00007645 }
sewardjc4356f02007-11-09 21:15:04 +00007646 }
sewardjbb3f52d2005-01-07 14:14:50 +00007647
sewardjc4356f02007-11-09 21:15:04 +00007648 /* Normal instruction handling starts here. */
sewardjc9a65702004-07-07 16:32:57 +00007649
sewardjc4356f02007-11-09 21:15:04 +00007650 /* Deal with some but not all prefixes:
7651 66(oso)
7652 F0(lock)
7653 2E(cs:) 3E(ds:) 26(es:) 64(fs:) 65(gs:) 36(ss:)
7654 Not dealt with (left in place):
7655 F2 F3
7656 */
7657 n_prefixes = 0;
7658 while (True) {
7659 if (n_prefixes > 7) goto decode_failure;
7660 pre = getUChar(delta);
7661 switch (pre) {
7662 case 0x66:
7663 sz = 2;
7664 break;
7665 case 0xF0:
7666 pfx_lock = True;
7667 break;
7668 case 0x3E: /* %DS: */
7669 case 0x26: /* %ES: */
7670 case 0x64: /* %FS: */
7671 case 0x65: /* %GS: */
7672 if (sorb != 0)
7673 goto decode_failure; /* only one seg override allowed */
7674 sorb = pre;
7675 break;
7676 case 0x2E: { /* %CS: */
7677 /* 2E prefix on a conditional branch instruction is a
7678 branch-prediction hint, which can safely be ignored. */
sewardjc9a65702004-07-07 16:32:57 +00007679 UChar op1 = getIByte(delta+1);
7680 UChar op2 = getIByte(delta+2);
7681 if ((op1 >= 0x70 && op1 <= 0x7F)
7682 || (op1 == 0xE3)
7683 || (op1 == 0x0F && op2 >= 0x80 && op2 <= 0x8F)) {
sewardj4dfb1992005-03-13 18:56:28 +00007684 if (0) vex_printf("vex x86->IR: ignoring branch hint\n");
sewardjc4356f02007-11-09 21:15:04 +00007685 } else {
7686 /* All other CS override cases are not handled */
7687 goto decode_failure;
sewardjc9a65702004-07-07 16:32:57 +00007688 }
sewardjc4356f02007-11-09 21:15:04 +00007689 break;
sewardjc9a65702004-07-07 16:32:57 +00007690 }
sewardjc4356f02007-11-09 21:15:04 +00007691 case 0x36: /* %SS: */
7692 /* SS override cases are not handled */
7693 goto decode_failure;
7694 default:
7695 goto not_a_prefix;
7696 }
7697 n_prefixes++;
7698 delta++;
sewardjc9a65702004-07-07 16:32:57 +00007699 }
7700
sewardjc4356f02007-11-09 21:15:04 +00007701 not_a_prefix:
7702
7703 /* Now we should be looking at the primary opcode byte or the
7704 leading F2 or F3. Check that any LOCK prefix is actually
7705 allowed. */
7706
7707 /* Kludge re LOCK prefixes. We assume here that all code generated
7708 by Vex is going to be run in a single-threaded context, in other
7709 words that concurrent executions of Vex-generated translations
7710 will not happen. So we don't need to worry too much about
7711 preserving atomicity. However, mark the fact that the notional
7712 hardware bus lock is being acquired (and, after the insn,
7713 released), so that thread checking tools know this is a locked
7714 insn.
7715
7716 We check for, and immediately reject, (most) inappropriate uses
7717 of the LOCK prefix. Later (at decode_failure: and
7718 decode_success:), if we've added a BusLock event, then we will
7719 follow up with a BusUnlock event. How do we know execution will
7720 actually ever get to the BusUnlock event? Because
7721 can_be_used_with_LOCK_prefix rejects all control-flow changing
7722 instructions.
7723
7724 One loophole, though: if a LOCK prefix insn (seg)faults, then
7725 the BusUnlock event will never be reached. This could cause
7726 tools which track bus hardware lock to lose track. Really, we
7727 should explicitly release the lock after every insn, but that's
7728 obviously way too expensive. Really, any tool which tracks the
7729 state of the bus lock needs to ask V's core/tool interface to
7730 notify it of signal deliveries. On delivery of SIGSEGV to the
7731 guest, the tool will be notified, in which case it should
7732 release the bus hardware lock if it is held.
7733
7734 Note, guest-amd64/toIR.c contains identical logic.
7735 */
7736 if (pfx_lock) {
7737 if (can_be_used_with_LOCK_prefix( (UChar*)&guest_code[delta] )) {
7738 stmt( IRStmt_MBE(Imbe_BusLock) );
7739 unlock_bus_after_insn = True;
7740 DIP("lock ");
7741 } else {
7742 goto decode_failure;
7743 }
7744 }
7745
7746
sewardjc9a43662004-11-30 18:51:59 +00007747 /* ---------------------------------------------------- */
7748 /* --- The SSE decoder. --- */
7749 /* ---------------------------------------------------- */
7750
sewardj4cb918d2004-12-03 19:43:31 +00007751 /* What did I do to deserve SSE ? Perhaps I was really bad in a
7752 previous life? */
7753
sewardj9df271d2004-12-31 22:37:42 +00007754 /* Note, this doesn't handle SSE2 or SSE3. That is handled in a
7755 later section, further on. */
7756
sewardja0e83b02005-01-06 12:36:38 +00007757 insn = (UChar*)&guest_code[delta];
7758
7759 /* Treat fxsave specially. It should be doable even on an SSE0
7760 (Pentium-II class) CPU. Hence be prepared to handle it on
7761 any subarchitecture variant.
7762 */
7763
7764 /* 0F AE /0 = FXSAVE m512 -- write x87 and SSE state to memory */
7765 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xAE
7766 && !epartIsReg(insn[2]) && gregOfRM(insn[2]) == 0) {
sewardj9a036bf2005-03-14 18:19:08 +00007767 IRDirty* d;
sewardja0e83b02005-01-06 12:36:38 +00007768 modrm = getIByte(delta+2);
7769 vassert(sz == 4);
7770 vassert(!epartIsReg(modrm));
7771
7772 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
7773 delta += 2+alen;
7774
sewardj33dd31b2005-01-08 18:17:32 +00007775 DIP("fxsave %s\n", dis_buf);
sewardja0e83b02005-01-06 12:36:38 +00007776
7777 /* Uses dirty helper:
7778 void x86g_do_FXSAVE ( VexGuestX86State*, UInt ) */
sewardj9a036bf2005-03-14 18:19:08 +00007779 d = unsafeIRDirty_0_N (
7780 0/*regparms*/,
7781 "x86g_dirtyhelper_FXSAVE",
7782 &x86g_dirtyhelper_FXSAVE,
7783 mkIRExprVec_1( mkexpr(addr) )
7784 );
sewardja0e83b02005-01-06 12:36:38 +00007785 d->needsBBP = True;
7786
7787 /* declare we're writing memory */
7788 d->mFx = Ifx_Write;
7789 d->mAddr = mkexpr(addr);
7790 d->mSize = 512;
7791
7792 /* declare we're reading guest state */
7793 d->nFxState = 7;
7794
7795 d->fxState[0].fx = Ifx_Read;
7796 d->fxState[0].offset = OFFB_FTOP;
7797 d->fxState[0].size = sizeof(UInt);
7798
7799 d->fxState[1].fx = Ifx_Read;
7800 d->fxState[1].offset = OFFB_FPREGS;
7801 d->fxState[1].size = 8 * sizeof(ULong);
7802
7803 d->fxState[2].fx = Ifx_Read;
7804 d->fxState[2].offset = OFFB_FPTAGS;
7805 d->fxState[2].size = 8 * sizeof(UChar);
7806
7807 d->fxState[3].fx = Ifx_Read;
7808 d->fxState[3].offset = OFFB_FPROUND;
7809 d->fxState[3].size = sizeof(UInt);
7810
7811 d->fxState[4].fx = Ifx_Read;
7812 d->fxState[4].offset = OFFB_FC3210;
7813 d->fxState[4].size = sizeof(UInt);
7814
7815 d->fxState[5].fx = Ifx_Read;
7816 d->fxState[5].offset = OFFB_XMM0;
7817 d->fxState[5].size = 8 * sizeof(U128);
7818
7819 d->fxState[6].fx = Ifx_Read;
7820 d->fxState[6].offset = OFFB_SSEROUND;
7821 d->fxState[6].size = sizeof(UInt);
7822
7823 /* Be paranoid ... this assertion tries to ensure the 8 %xmm
7824 images are packed back-to-back. If not, the value of
7825 d->fxState[5].size is wrong. */
7826 vassert(16 == sizeof(U128));
7827 vassert(OFFB_XMM7 == (OFFB_XMM0 + 7 * 16));
7828
7829 stmt( IRStmt_Dirty(d) );
7830
7831 goto decode_success;
7832 }
7833
sewardj3800e2d2008-05-09 13:24:43 +00007834 /* 0F AE /1 = FXRSTOR m512 -- read x87 and SSE state from memory */
7835 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xAE
7836 && !epartIsReg(insn[2]) && gregOfRM(insn[2]) == 1) {
7837 IRDirty* d;
7838 modrm = getIByte(delta+2);
7839 vassert(sz == 4);
7840 vassert(!epartIsReg(modrm));
7841
7842 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
7843 delta += 2+alen;
7844
7845 DIP("fxrstor %s\n", dis_buf);
7846
7847 /* Uses dirty helper:
7848 void x86g_do_FXRSTOR ( VexGuestX86State*, UInt ) */
7849 d = unsafeIRDirty_0_N (
7850 0/*regparms*/,
7851 "x86g_dirtyhelper_FXRSTOR",
7852 &x86g_dirtyhelper_FXRSTOR,
7853 mkIRExprVec_1( mkexpr(addr) )
7854 );
7855 d->needsBBP = True;
7856
7857 /* declare we're reading memory */
7858 d->mFx = Ifx_Read;
7859 d->mAddr = mkexpr(addr);
7860 d->mSize = 512;
7861
7862 /* declare we're writing guest state */
7863 d->nFxState = 7;
7864
7865 d->fxState[0].fx = Ifx_Write;
7866 d->fxState[0].offset = OFFB_FTOP;
7867 d->fxState[0].size = sizeof(UInt);
7868
7869 d->fxState[1].fx = Ifx_Write;
7870 d->fxState[1].offset = OFFB_FPREGS;
7871 d->fxState[1].size = 8 * sizeof(ULong);
7872
7873 d->fxState[2].fx = Ifx_Write;
7874 d->fxState[2].offset = OFFB_FPTAGS;
7875 d->fxState[2].size = 8 * sizeof(UChar);
7876
7877 d->fxState[3].fx = Ifx_Write;
7878 d->fxState[3].offset = OFFB_FPROUND;
7879 d->fxState[3].size = sizeof(UInt);
7880
7881 d->fxState[4].fx = Ifx_Write;
7882 d->fxState[4].offset = OFFB_FC3210;
7883 d->fxState[4].size = sizeof(UInt);
7884
7885 d->fxState[5].fx = Ifx_Write;
7886 d->fxState[5].offset = OFFB_XMM0;
7887 d->fxState[5].size = 8 * sizeof(U128);
7888
7889 d->fxState[6].fx = Ifx_Write;
7890 d->fxState[6].offset = OFFB_SSEROUND;
7891 d->fxState[6].size = sizeof(UInt);
7892
7893 /* Be paranoid ... this assertion tries to ensure the 8 %xmm
7894 images are packed back-to-back. If not, the value of
7895 d->fxState[5].size is wrong. */
7896 vassert(16 == sizeof(U128));
7897 vassert(OFFB_XMM7 == (OFFB_XMM0 + 7 * 16));
7898
7899 stmt( IRStmt_Dirty(d) );
7900
7901 goto decode_success;
7902 }
7903
sewardja0e83b02005-01-06 12:36:38 +00007904 /* ------ SSE decoder main ------ */
7905
sewardj9df271d2004-12-31 22:37:42 +00007906 /* Skip parts of the decoder which don't apply given the stated
7907 guest subarchitecture. */
sewardj5117ce12006-01-27 21:20:15 +00007908 if (archinfo->hwcaps == 0/*baseline, no sse at all*/)
sewardj9df271d2004-12-31 22:37:42 +00007909 goto after_sse_decoders;
7910
7911 /* Otherwise we must be doing sse1 or sse2, so we can at least try
7912 for SSE1 here. */
sewardjc9a43662004-11-30 18:51:59 +00007913
sewardjc9a43662004-11-30 18:51:59 +00007914 /* 0F 58 = ADDPS -- add 32Fx4 from R/M to R */
sewardj636ad762004-12-07 11:16:04 +00007915 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x58) {
sewardj129b3d92004-12-05 15:42:05 +00007916 delta = dis_SSE_E_to_G_all( sorb, delta+2, "addps", Iop_Add32Fx4 );
sewardjc9a43662004-11-30 18:51:59 +00007917 goto decode_success;
7918 }
7919
sewardj1e6ad742004-12-02 16:16:11 +00007920 /* F3 0F 58 = ADDSS -- add 32F0x4 from R/M to R */
7921 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x58) {
7922 vassert(sz == 4);
sewardj129b3d92004-12-05 15:42:05 +00007923 delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "addss", Iop_Add32F0x4 );
sewardj1e6ad742004-12-02 16:16:11 +00007924 goto decode_success;
7925 }
7926
7927 /* 0F 55 = ANDNPS -- G = (not G) and E */
sewardj636ad762004-12-07 11:16:04 +00007928 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x55) {
sewardjf0c1c582005-02-07 23:47:38 +00007929 delta = dis_SSE_E_to_G_all_invG( sorb, delta+2, "andnps", Iop_AndV128 );
sewardj1e6ad742004-12-02 16:16:11 +00007930 goto decode_success;
7931 }
7932
7933 /* 0F 54 = ANDPS -- G = G and E */
sewardj636ad762004-12-07 11:16:04 +00007934 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x54) {
sewardjf0c1c582005-02-07 23:47:38 +00007935 delta = dis_SSE_E_to_G_all( sorb, delta+2, "andps", Iop_AndV128 );
sewardj1e6ad742004-12-02 16:16:11 +00007936 goto decode_success;
7937 }
7938
7939 /* 0F C2 = CMPPS -- 32Fx4 comparison from R/M to R */
sewardj636ad762004-12-07 11:16:04 +00007940 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xC2) {
sewardj1e6ad742004-12-02 16:16:11 +00007941 delta = dis_SSEcmp_E_to_G( sorb, delta+2, "cmpps", True, 4 );
7942 goto decode_success;
7943 }
7944
7945 /* F3 0F C2 = CMPSS -- 32F0x4 comparison from R/M to R */
7946 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0xC2) {
7947 vassert(sz == 4);
7948 delta = dis_SSEcmp_E_to_G( sorb, delta+3, "cmpss", False, 4 );
7949 goto decode_success;
7950 }
sewardjc9a43662004-11-30 18:51:59 +00007951
sewardjfd226452004-12-07 19:02:18 +00007952 /* 0F 2F = COMISS -- 32F0x4 comparison G,E, and set ZCP */
sewardjc1e7dfc2004-12-05 19:29:45 +00007953 /* 0F 2E = UCOMISS -- 32F0x4 comparison G,E, and set ZCP */
sewardjfd226452004-12-07 19:02:18 +00007954 if (sz == 4 && insn[0] == 0x0F && (insn[1] == 0x2F || insn[1] == 0x2E)) {
sewardj67e002d2004-12-02 18:16:33 +00007955 IRTemp argL = newTemp(Ity_F32);
7956 IRTemp argR = newTemp(Ity_F32);
sewardj67e002d2004-12-02 18:16:33 +00007957 modrm = getIByte(delta+2);
7958 if (epartIsReg(modrm)) {
7959 assign( argR, getXMMRegLane32F( eregOfRM(modrm), 0/*lowest lane*/ ) );
7960 delta += 2+1;
sewardjc1e7dfc2004-12-05 19:29:45 +00007961 DIP("[u]comiss %s,%s\n", nameXMMReg(eregOfRM(modrm)),
7962 nameXMMReg(gregOfRM(modrm)) );
sewardj67e002d2004-12-02 18:16:33 +00007963 } else {
7964 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
7965 assign( argR, loadLE(Ity_F32, mkexpr(addr)) );
7966 delta += 2+alen;
sewardjc1e7dfc2004-12-05 19:29:45 +00007967 DIP("[u]comiss %s,%s\n", dis_buf,
7968 nameXMMReg(gregOfRM(modrm)) );
sewardj67e002d2004-12-02 18:16:33 +00007969 }
7970 assign( argL, getXMMRegLane32F( gregOfRM(modrm), 0/*lowest lane*/ ) );
7971
7972 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
7973 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
7974 stmt( IRStmt_Put(
7975 OFFB_CC_DEP1,
7976 binop( Iop_And32,
7977 binop(Iop_CmpF64,
7978 unop(Iop_F32toF64,mkexpr(argL)),
7979 unop(Iop_F32toF64,mkexpr(argR))),
7980 mkU32(0x45)
7981 )));
sewardja3b7e3a2005-04-05 01:54:19 +00007982 /* Set NDEP even though it isn't used. This makes redundant-PUT
7983 elimination of previous stores to this field work better. */
7984 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardj67e002d2004-12-02 18:16:33 +00007985 goto decode_success;
7986 }
sewardjc9a43662004-11-30 18:51:59 +00007987
sewardj4cb918d2004-12-03 19:43:31 +00007988 /* 0F 2A = CVTPI2PS -- convert 2 x I32 in mem/mmx to 2 x F32 in low
7989 half xmm */
sewardjfd226452004-12-07 19:02:18 +00007990 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x2A) {
sewardj4cb918d2004-12-03 19:43:31 +00007991 IRTemp arg64 = newTemp(Ity_I64);
7992 IRTemp rmode = newTemp(Ity_I32);
7993 vassert(sz == 4);
7994
7995 modrm = getIByte(delta+2);
7996 do_MMX_preamble();
7997 if (epartIsReg(modrm)) {
7998 assign( arg64, getMMXReg(eregOfRM(modrm)) );
7999 delta += 2+1;
8000 DIP("cvtpi2ps %s,%s\n", nameMMXReg(eregOfRM(modrm)),
8001 nameXMMReg(gregOfRM(modrm)));
8002 } else {
8003 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8004 assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
8005 delta += 2+alen;
8006 DIP("cvtpi2ps %s,%s\n", dis_buf,
8007 nameXMMReg(gregOfRM(modrm)) );
8008 }
8009
8010 assign( rmode, get_sse_roundingmode() );
8011
8012 putXMMRegLane32F(
sewardj3bca9062004-12-04 14:36:09 +00008013 gregOfRM(modrm), 0,
8014 binop(Iop_F64toF32,
sewardj4cb918d2004-12-03 19:43:31 +00008015 mkexpr(rmode),
sewardj3bca9062004-12-04 14:36:09 +00008016 unop(Iop_I32toF64,
8017 unop(Iop_64to32, mkexpr(arg64)) )) );
sewardj4cb918d2004-12-03 19:43:31 +00008018
8019 putXMMRegLane32F(
8020 gregOfRM(modrm), 1,
sewardj3bca9062004-12-04 14:36:09 +00008021 binop(Iop_F64toF32,
sewardj4cb918d2004-12-03 19:43:31 +00008022 mkexpr(rmode),
sewardj3bca9062004-12-04 14:36:09 +00008023 unop(Iop_I32toF64,
8024 unop(Iop_64HIto32, mkexpr(arg64)) )) );
sewardj4cb918d2004-12-03 19:43:31 +00008025
8026 goto decode_success;
8027 }
8028
8029 /* F3 0F 2A = CVTSI2SS -- convert I32 in mem/ireg to F32 in low
8030 quarter xmm */
8031 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x2A) {
8032 IRTemp arg32 = newTemp(Ity_I32);
8033 IRTemp rmode = newTemp(Ity_I32);
8034 vassert(sz == 4);
8035
8036 modrm = getIByte(delta+3);
sewardj4cb918d2004-12-03 19:43:31 +00008037 if (epartIsReg(modrm)) {
8038 assign( arg32, getIReg(4, eregOfRM(modrm)) );
8039 delta += 3+1;
8040 DIP("cvtsi2ss %s,%s\n", nameIReg(4, eregOfRM(modrm)),
8041 nameXMMReg(gregOfRM(modrm)));
8042 } else {
8043 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
8044 assign( arg32, loadLE(Ity_I32, mkexpr(addr)) );
8045 delta += 3+alen;
8046 DIP("cvtsi2ss %s,%s\n", dis_buf,
8047 nameXMMReg(gregOfRM(modrm)) );
8048 }
8049
8050 assign( rmode, get_sse_roundingmode() );
8051
8052 putXMMRegLane32F(
sewardj3bca9062004-12-04 14:36:09 +00008053 gregOfRM(modrm), 0,
8054 binop(Iop_F64toF32,
8055 mkexpr(rmode),
8056 unop(Iop_I32toF64, mkexpr(arg32)) ) );
sewardj4cb918d2004-12-03 19:43:31 +00008057
8058 goto decode_success;
8059 }
8060
8061 /* 0F 2D = CVTPS2PI -- convert 2 x F32 in mem/low half xmm to 2 x
8062 I32 in mmx, according to prevailing SSE rounding mode */
8063 /* 0F 2C = CVTTPS2PI -- convert 2 x F32 in mem/low half xmm to 2 x
8064 I32 in mmx, rounding towards zero */
sewardjfd226452004-12-07 19:02:18 +00008065 if (sz == 4 && insn[0] == 0x0F && (insn[1] == 0x2D || insn[1] == 0x2C)) {
sewardj4cb918d2004-12-03 19:43:31 +00008066 IRTemp dst64 = newTemp(Ity_I64);
8067 IRTemp rmode = newTemp(Ity_I32);
8068 IRTemp f32lo = newTemp(Ity_F32);
8069 IRTemp f32hi = newTemp(Ity_F32);
sewardj2d49b432005-02-01 00:37:06 +00008070 Bool r2zero = toBool(insn[1] == 0x2C);
sewardj4cb918d2004-12-03 19:43:31 +00008071
8072 do_MMX_preamble();
8073 modrm = getIByte(delta+2);
8074
8075 if (epartIsReg(modrm)) {
8076 delta += 2+1;
8077 assign(f32lo, getXMMRegLane32F(eregOfRM(modrm), 0));
8078 assign(f32hi, getXMMRegLane32F(eregOfRM(modrm), 1));
8079 DIP("cvt%sps2pi %s,%s\n", r2zero ? "t" : "",
8080 nameXMMReg(eregOfRM(modrm)),
8081 nameMMXReg(gregOfRM(modrm)));
8082 } else {
8083 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8084 assign(f32lo, loadLE(Ity_F32, mkexpr(addr)));
8085 assign(f32hi, loadLE(Ity_F32, binop( Iop_Add32,
8086 mkexpr(addr),
8087 mkU32(4) )));
8088 delta += 2+alen;
8089 DIP("cvt%sps2pi %s,%s\n", r2zero ? "t" : "",
8090 dis_buf,
8091 nameMMXReg(gregOfRM(modrm)));
8092 }
8093
8094 if (r2zero) {
8095 assign(rmode, mkU32((UInt)Irrm_ZERO) );
8096 } else {
8097 assign( rmode, get_sse_roundingmode() );
8098 }
8099
8100 assign(
8101 dst64,
8102 binop( Iop_32HLto64,
8103 binop( Iop_F64toI32,
8104 mkexpr(rmode),
8105 unop( Iop_F32toF64, mkexpr(f32hi) ) ),
8106 binop( Iop_F64toI32,
8107 mkexpr(rmode),
8108 unop( Iop_F32toF64, mkexpr(f32lo) ) )
8109 )
8110 );
8111
8112 putMMXReg(gregOfRM(modrm), mkexpr(dst64));
8113 goto decode_success;
8114 }
8115
8116 /* F3 0F 2D = CVTSS2SI -- convert F32 in mem/low quarter xmm to
8117 I32 in ireg, according to prevailing SSE rounding mode */
8118 /* F3 0F 2C = CVTTSS2SI -- convert F32 in mem/low quarter xmm to
sewardj0b210442005-02-23 13:28:27 +00008119 I32 in ireg, rounding towards zero */
sewardj4cb918d2004-12-03 19:43:31 +00008120 if (insn[0] == 0xF3 && insn[1] == 0x0F
8121 && (insn[2] == 0x2D || insn[2] == 0x2C)) {
8122 IRTemp rmode = newTemp(Ity_I32);
8123 IRTemp f32lo = newTemp(Ity_F32);
sewardj2d49b432005-02-01 00:37:06 +00008124 Bool r2zero = toBool(insn[2] == 0x2C);
sewardj4cb918d2004-12-03 19:43:31 +00008125 vassert(sz == 4);
8126
sewardj4cb918d2004-12-03 19:43:31 +00008127 modrm = getIByte(delta+3);
sewardj4cb918d2004-12-03 19:43:31 +00008128 if (epartIsReg(modrm)) {
8129 delta += 3+1;
8130 assign(f32lo, getXMMRegLane32F(eregOfRM(modrm), 0));
8131 DIP("cvt%sss2si %s,%s\n", r2zero ? "t" : "",
8132 nameXMMReg(eregOfRM(modrm)),
8133 nameIReg(4, gregOfRM(modrm)));
8134 } else {
8135 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
8136 assign(f32lo, loadLE(Ity_F32, mkexpr(addr)));
8137 delta += 3+alen;
8138 DIP("cvt%sss2si %s,%s\n", r2zero ? "t" : "",
8139 dis_buf,
8140 nameIReg(4, gregOfRM(modrm)));
8141 }
8142
8143 if (r2zero) {
sewardj7df596b2004-12-06 14:29:12 +00008144 assign( rmode, mkU32((UInt)Irrm_ZERO) );
sewardj4cb918d2004-12-03 19:43:31 +00008145 } else {
8146 assign( rmode, get_sse_roundingmode() );
8147 }
8148
8149 putIReg(4, gregOfRM(modrm),
8150 binop( Iop_F64toI32,
8151 mkexpr(rmode),
8152 unop( Iop_F32toF64, mkexpr(f32lo) ) )
8153 );
8154
8155 goto decode_success;
8156 }
8157
sewardj176a59c2004-12-03 20:08:31 +00008158 /* 0F 5E = DIVPS -- div 32Fx4 from R/M to R */
sewardjfd226452004-12-07 19:02:18 +00008159 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5E) {
sewardj129b3d92004-12-05 15:42:05 +00008160 delta = dis_SSE_E_to_G_all( sorb, delta+2, "divps", Iop_Div32Fx4 );
sewardj176a59c2004-12-03 20:08:31 +00008161 goto decode_success;
8162 }
8163
8164 /* F3 0F 5E = DIVSS -- div 32F0x4 from R/M to R */
8165 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5E) {
8166 vassert(sz == 4);
sewardj129b3d92004-12-05 15:42:05 +00008167 delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "divss", Iop_Div32F0x4 );
sewardj176a59c2004-12-03 20:08:31 +00008168 goto decode_success;
8169 }
8170
sewardj7df596b2004-12-06 14:29:12 +00008171 /* 0F AE /2 = LDMXCSR m32 -- load %mxcsr */
8172 if (insn[0] == 0x0F && insn[1] == 0xAE
8173 && !epartIsReg(insn[2]) && gregOfRM(insn[2]) == 2) {
8174
8175 IRTemp t64 = newTemp(Ity_I64);
8176 IRTemp ew = newTemp(Ity_I32);
8177
8178 modrm = getIByte(delta+2);
8179 vassert(!epartIsReg(modrm));
8180 vassert(sz == 4);
8181
8182 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8183 delta += 2+alen;
sewardj33dd31b2005-01-08 18:17:32 +00008184 DIP("ldmxcsr %s\n", dis_buf);
sewardj7df596b2004-12-06 14:29:12 +00008185
8186 /* The only thing we observe in %mxcsr is the rounding mode.
8187 Therefore, pass the 32-bit value (SSE native-format control
8188 word) to a clean helper, getting back a 64-bit value, the
8189 lower half of which is the SSEROUND value to store, and the
8190 upper half of which is the emulation-warning token which may
8191 be generated.
8192 */
8193 /* ULong x86h_check_ldmxcsr ( UInt ); */
8194 assign( t64, mkIRExprCCall(
8195 Ity_I64, 0/*regparms*/,
sewardj3bd6f3e2004-12-13 10:48:19 +00008196 "x86g_check_ldmxcsr",
8197 &x86g_check_ldmxcsr,
sewardj7df596b2004-12-06 14:29:12 +00008198 mkIRExprVec_1( loadLE(Ity_I32, mkexpr(addr)) )
8199 )
8200 );
8201
sewardj636ad762004-12-07 11:16:04 +00008202 put_sse_roundingmode( unop(Iop_64to32, mkexpr(t64)) );
sewardj7df596b2004-12-06 14:29:12 +00008203 assign( ew, unop(Iop_64HIto32, mkexpr(t64) ) );
8204 put_emwarn( mkexpr(ew) );
8205 /* Finally, if an emulation warning was reported, side-exit to
8206 the next insn, reporting the warning, so that Valgrind's
8207 dispatcher sees the warning. */
8208 stmt(
8209 IRStmt_Exit(
8210 binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
8211 Ijk_EmWarn,
sewardj9e6491a2005-07-02 19:24:10 +00008212 IRConst_U32( ((Addr32)guest_EIP_bbstart)+delta)
sewardj7df596b2004-12-06 14:29:12 +00008213 )
8214 );
8215 goto decode_success;
8216 }
8217
sewardjd71ba832006-12-27 01:15:29 +00008218 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8219 /* 0F F7 = MASKMOVQ -- 8x8 masked store */
8220 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xF7) {
8221 Bool ok = False;
8222 delta = dis_MMX( &ok, sorb, sz, delta+1 );
8223 if (!ok)
8224 goto decode_failure;
8225 goto decode_success;
8226 }
8227
sewardj176a59c2004-12-03 20:08:31 +00008228 /* 0F 5F = MAXPS -- max 32Fx4 from R/M to R */
sewardjc2feffc2004-12-08 12:31:22 +00008229 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5F) {
sewardj129b3d92004-12-05 15:42:05 +00008230 delta = dis_SSE_E_to_G_all( sorb, delta+2, "maxps", Iop_Max32Fx4 );
sewardj176a59c2004-12-03 20:08:31 +00008231 goto decode_success;
8232 }
8233
8234 /* F3 0F 5F = MAXSS -- max 32F0x4 from R/M to R */
8235 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5F) {
8236 vassert(sz == 4);
sewardj129b3d92004-12-05 15:42:05 +00008237 delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "maxss", Iop_Max32F0x4 );
sewardj176a59c2004-12-03 20:08:31 +00008238 goto decode_success;
8239 }
8240
8241 /* 0F 5D = MINPS -- min 32Fx4 from R/M to R */
sewardjc2feffc2004-12-08 12:31:22 +00008242 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5D) {
sewardj129b3d92004-12-05 15:42:05 +00008243 delta = dis_SSE_E_to_G_all( sorb, delta+2, "minps", Iop_Min32Fx4 );
sewardj176a59c2004-12-03 20:08:31 +00008244 goto decode_success;
8245 }
8246
8247 /* F3 0F 5D = MINSS -- min 32F0x4 from R/M to R */
8248 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5D) {
8249 vassert(sz == 4);
sewardj129b3d92004-12-05 15:42:05 +00008250 delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "minss", Iop_Min32F0x4 );
sewardj176a59c2004-12-03 20:08:31 +00008251 goto decode_success;
8252 }
sewardj4cb918d2004-12-03 19:43:31 +00008253
sewardj9636b442004-12-04 01:38:37 +00008254 /* 0F 28 = MOVAPS -- move from E (mem or xmm) to G (xmm). */
sewardjc2feffc2004-12-08 12:31:22 +00008255 /* 0F 10 = MOVUPS -- move from E (mem or xmm) to G (xmm). */
8256 if (sz == 4 && insn[0] == 0x0F && (insn[1] == 0x28 || insn[1] == 0x10)) {
sewardj9636b442004-12-04 01:38:37 +00008257 modrm = getIByte(delta+2);
sewardj9636b442004-12-04 01:38:37 +00008258 if (epartIsReg(modrm)) {
8259 putXMMReg( gregOfRM(modrm),
8260 getXMMReg( eregOfRM(modrm) ));
8261 DIP("mov[ua]ps %s,%s\n", nameXMMReg(eregOfRM(modrm)),
8262 nameXMMReg(gregOfRM(modrm)));
8263 delta += 2+1;
8264 } else {
8265 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8266 putXMMReg( gregOfRM(modrm),
8267 loadLE(Ity_V128, mkexpr(addr)) );
8268 DIP("mov[ua]ps %s,%s\n", dis_buf,
8269 nameXMMReg(gregOfRM(modrm)));
8270 delta += 2+alen;
8271 }
8272 goto decode_success;
8273 }
8274
sewardj09f41552004-12-15 12:35:00 +00008275 /* 0F 29 = MOVAPS -- move from G (xmm) to E (mem or xmm). */
sewardj3ed54842005-08-25 21:34:24 +00008276 /* 0F 11 = MOVUPS -- move from G (xmm) to E (mem or xmm). */
8277 if (sz == 4 && insn[0] == 0x0F
8278 && (insn[1] == 0x29 || insn[1] == 0x11)) {
sewardj09f41552004-12-15 12:35:00 +00008279 modrm = getIByte(delta+2);
sewardj09f41552004-12-15 12:35:00 +00008280 if (epartIsReg(modrm)) {
8281 /* fall through; awaiting test case */
8282 } else {
8283 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8284 storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) );
sewardj3ed54842005-08-25 21:34:24 +00008285 DIP("mov[ua]ps %s,%s\n", nameXMMReg(gregOfRM(modrm)),
8286 dis_buf );
sewardj09f41552004-12-15 12:35:00 +00008287 delta += 2+alen;
8288 goto decode_success;
8289 }
8290 }
8291
sewardj0bd7ce62004-12-05 02:47:40 +00008292 /* 0F 16 = MOVHPS -- move from mem to high half of XMM. */
8293 /* 0F 16 = MOVLHPS -- move from lo half to hi half of XMM. */
sewardjc2feffc2004-12-08 12:31:22 +00008294 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x16) {
sewardj0bd7ce62004-12-05 02:47:40 +00008295 modrm = getIByte(delta+2);
8296 if (epartIsReg(modrm)) {
8297 delta += 2+1;
8298 putXMMRegLane64( gregOfRM(modrm), 1/*upper lane*/,
8299 getXMMRegLane64( eregOfRM(modrm), 0 ) );
8300 DIP("movhps %s,%s\n", nameXMMReg(eregOfRM(modrm)),
8301 nameXMMReg(gregOfRM(modrm)));
8302 } else {
8303 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8304 delta += 2+alen;
8305 putXMMRegLane64( gregOfRM(modrm), 1/*upper lane*/,
8306 loadLE(Ity_I64, mkexpr(addr)) );
8307 DIP("movhps %s,%s\n", dis_buf,
sewardjc2feffc2004-12-08 12:31:22 +00008308 nameXMMReg( gregOfRM(modrm) ));
sewardj0bd7ce62004-12-05 02:47:40 +00008309 }
8310 goto decode_success;
8311 }
8312
8313 /* 0F 17 = MOVHPS -- move from high half of XMM to mem. */
sewardjc2feffc2004-12-08 12:31:22 +00008314 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x17) {
sewardj0bd7ce62004-12-05 02:47:40 +00008315 if (!epartIsReg(insn[2])) {
sewardj0bd7ce62004-12-05 02:47:40 +00008316 delta += 2;
8317 addr = disAMode ( &alen, sorb, delta, dis_buf );
8318 delta += alen;
8319 storeLE( mkexpr(addr),
8320 getXMMRegLane64( gregOfRM(insn[2]),
8321 1/*upper lane*/ ) );
8322 DIP("movhps %s,%s\n", nameXMMReg( gregOfRM(insn[2]) ),
8323 dis_buf);
8324 goto decode_success;
8325 }
8326 /* else fall through */
8327 }
8328
8329 /* 0F 12 = MOVLPS -- move from mem to low half of XMM. */
8330 /* OF 12 = MOVHLPS -- from from hi half to lo half of XMM. */
sewardjc2feffc2004-12-08 12:31:22 +00008331 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x12) {
sewardj0bd7ce62004-12-05 02:47:40 +00008332 modrm = getIByte(delta+2);
8333 if (epartIsReg(modrm)) {
8334 delta += 2+1;
8335 putXMMRegLane64( gregOfRM(modrm),
8336 0/*lower lane*/,
8337 getXMMRegLane64( eregOfRM(modrm), 1 ));
8338 DIP("movhlps %s, %s\n", nameXMMReg(eregOfRM(modrm)),
8339 nameXMMReg(gregOfRM(modrm)));
8340 } else {
8341 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8342 delta += 2+alen;
8343 putXMMRegLane64( gregOfRM(modrm), 0/*lower lane*/,
8344 loadLE(Ity_I64, mkexpr(addr)) );
8345 DIP("movlps %s, %s\n",
8346 dis_buf, nameXMMReg( gregOfRM(modrm) ));
8347 }
8348 goto decode_success;
8349 }
8350
8351 /* 0F 13 = MOVLPS -- move from low half of XMM to mem. */
sewardjc2feffc2004-12-08 12:31:22 +00008352 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x13) {
sewardj0bd7ce62004-12-05 02:47:40 +00008353 if (!epartIsReg(insn[2])) {
sewardj0bd7ce62004-12-05 02:47:40 +00008354 delta += 2;
8355 addr = disAMode ( &alen, sorb, delta, dis_buf );
8356 delta += alen;
8357 storeLE( mkexpr(addr),
8358 getXMMRegLane64( gregOfRM(insn[2]),
8359 0/*lower lane*/ ) );
8360 DIP("movlps %s, %s\n", nameXMMReg( gregOfRM(insn[2]) ),
8361 dis_buf);
8362 goto decode_success;
8363 }
8364 /* else fall through */
8365 }
8366
sewardj9636b442004-12-04 01:38:37 +00008367 /* 0F 50 = MOVMSKPS - move 4 sign bits from 4 x F32 in xmm(E)
8368 to 4 lowest bits of ireg(G) */
8369 if (insn[0] == 0x0F && insn[1] == 0x50) {
sewardj9636b442004-12-04 01:38:37 +00008370 modrm = getIByte(delta+2);
sewardjc2feffc2004-12-08 12:31:22 +00008371 if (sz == 4 && epartIsReg(modrm)) {
8372 Int src;
8373 t0 = newTemp(Ity_I32);
8374 t1 = newTemp(Ity_I32);
8375 t2 = newTemp(Ity_I32);
8376 t3 = newTemp(Ity_I32);
sewardj129b3d92004-12-05 15:42:05 +00008377 delta += 2+1;
8378 src = eregOfRM(modrm);
8379 assign( t0, binop( Iop_And32,
8380 binop(Iop_Shr32, getXMMRegLane32(src,0), mkU8(31)),
8381 mkU32(1) ));
8382 assign( t1, binop( Iop_And32,
8383 binop(Iop_Shr32, getXMMRegLane32(src,1), mkU8(30)),
8384 mkU32(2) ));
8385 assign( t2, binop( Iop_And32,
8386 binop(Iop_Shr32, getXMMRegLane32(src,2), mkU8(29)),
8387 mkU32(4) ));
8388 assign( t3, binop( Iop_And32,
8389 binop(Iop_Shr32, getXMMRegLane32(src,3), mkU8(28)),
8390 mkU32(8) ));
8391 putIReg(4, gregOfRM(modrm),
8392 binop(Iop_Or32,
8393 binop(Iop_Or32, mkexpr(t0), mkexpr(t1)),
8394 binop(Iop_Or32, mkexpr(t2), mkexpr(t3))
8395 )
8396 );
8397 DIP("movmskps %s,%s\n", nameXMMReg(src),
8398 nameIReg(4, gregOfRM(modrm)));
8399 goto decode_success;
8400 }
8401 /* else fall through */
sewardj9636b442004-12-04 01:38:37 +00008402 }
8403
8404 /* 0F 2B = MOVNTPS -- for us, just a plain SSE store. */
sewardj703d6d62005-05-11 02:55:00 +00008405 /* 66 0F 2B = MOVNTPD -- for us, just a plain SSE store. */
sewardj9636b442004-12-04 01:38:37 +00008406 if (insn[0] == 0x0F && insn[1] == 0x2B) {
8407 modrm = getIByte(delta+2);
8408 if (!epartIsReg(modrm)) {
8409 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8410 storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) );
sewardj703d6d62005-05-11 02:55:00 +00008411 DIP("movntp%s %s,%s\n", sz==2 ? "d" : "s",
8412 dis_buf,
8413 nameXMMReg(gregOfRM(modrm)));
sewardj9636b442004-12-04 01:38:37 +00008414 delta += 2+alen;
8415 goto decode_success;
8416 }
8417 /* else fall through */
8418 }
8419
sewardjc2feffc2004-12-08 12:31:22 +00008420 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
sewardj9636b442004-12-04 01:38:37 +00008421 /* 0F E7 = MOVNTQ -- for us, just a plain MMX store. Note, the
8422 Intel manual does not say anything about the usual business of
8423 the FP reg tags getting trashed whenever an MMX insn happens.
8424 So we just leave them alone.
8425 */
8426 if (insn[0] == 0x0F && insn[1] == 0xE7) {
8427 modrm = getIByte(delta+2);
sewardjc2feffc2004-12-08 12:31:22 +00008428 if (sz == 4 && !epartIsReg(modrm)) {
sewardj519d66f2004-12-15 11:57:58 +00008429 /* do_MMX_preamble(); Intel docs don't specify this */
sewardj9636b442004-12-04 01:38:37 +00008430 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8431 storeLE( mkexpr(addr), getMMXReg(gregOfRM(modrm)) );
8432 DIP("movntq %s,%s\n", dis_buf,
8433 nameMMXReg(gregOfRM(modrm)));
8434 delta += 2+alen;
8435 goto decode_success;
8436 }
8437 /* else fall through */
8438 }
8439
8440 /* F3 0F 10 = MOVSS -- move 32 bits from E (mem or lo 1/4 xmm) to G
8441 (lo 1/4 xmm). If E is mem, upper 3/4 of G is zeroed out. */
8442 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x10) {
8443 vassert(sz == 4);
8444 modrm = getIByte(delta+3);
8445 if (epartIsReg(modrm)) {
8446 putXMMRegLane32( gregOfRM(modrm), 0,
8447 getXMMRegLane32( eregOfRM(modrm), 0 ));
8448 DIP("movss %s,%s\n", nameXMMReg(eregOfRM(modrm)),
8449 nameXMMReg(gregOfRM(modrm)));
8450 delta += 3+1;
8451 } else {
8452 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
sewardjad50db02005-04-06 01:45:44 +00008453 /* zero bits 127:64 */
8454 putXMMRegLane64( gregOfRM(modrm), 1, mkU64(0) );
8455 /* zero bits 63:32 */
8456 putXMMRegLane32( gregOfRM(modrm), 1, mkU32(0) );
8457 /* write bits 31:0 */
sewardj9636b442004-12-04 01:38:37 +00008458 putXMMRegLane32( gregOfRM(modrm), 0,
8459 loadLE(Ity_I32, mkexpr(addr)) );
8460 DIP("movss %s,%s\n", dis_buf,
8461 nameXMMReg(gregOfRM(modrm)));
8462 delta += 3+alen;
8463 }
8464 goto decode_success;
8465 }
8466
8467 /* F3 0F 11 = MOVSS -- move 32 bits from G (lo 1/4 xmm) to E (mem
8468 or lo 1/4 xmm). */
8469 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x11) {
8470 vassert(sz == 4);
8471 modrm = getIByte(delta+3);
8472 if (epartIsReg(modrm)) {
8473 /* fall through, we don't yet have a test case */
8474 } else {
8475 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
8476 storeLE( mkexpr(addr),
sewardj519d66f2004-12-15 11:57:58 +00008477 getXMMRegLane32(gregOfRM(modrm), 0) );
8478 DIP("movss %s,%s\n", nameXMMReg(gregOfRM(modrm)),
sewardj9636b442004-12-04 01:38:37 +00008479 dis_buf);
8480 delta += 3+alen;
8481 goto decode_success;
8482 }
8483 }
8484
8485 /* 0F 59 = MULPS -- mul 32Fx4 from R/M to R */
sewardj008754b2004-12-08 14:37:10 +00008486 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x59) {
sewardj129b3d92004-12-05 15:42:05 +00008487 delta = dis_SSE_E_to_G_all( sorb, delta+2, "mulps", Iop_Mul32Fx4 );
sewardj9636b442004-12-04 01:38:37 +00008488 goto decode_success;
8489 }
8490
8491 /* F3 0F 59 = MULSS -- mul 32F0x4 from R/M to R */
8492 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x59) {
8493 vassert(sz == 4);
sewardj129b3d92004-12-05 15:42:05 +00008494 delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "mulss", Iop_Mul32F0x4 );
sewardj9636b442004-12-04 01:38:37 +00008495 goto decode_success;
8496 }
8497
8498 /* 0F 56 = ORPS -- G = G and E */
sewardj008754b2004-12-08 14:37:10 +00008499 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x56) {
sewardjf0c1c582005-02-07 23:47:38 +00008500 delta = dis_SSE_E_to_G_all( sorb, delta+2, "orps", Iop_OrV128 );
sewardj9636b442004-12-04 01:38:37 +00008501 goto decode_success;
8502 }
8503
sewardj3bca9062004-12-04 14:36:09 +00008504 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8505 /* 0F E0 = PAVGB -- 8x8 unsigned Packed Average, with rounding */
sewardj164f9272004-12-09 00:39:32 +00008506 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xE0) {
sewardjb5452082004-12-04 20:33:02 +00008507 do_MMX_preamble();
8508 delta = dis_MMXop_regmem_to_reg (
8509 sorb, delta+2, insn[1], "pavgb", False );
8510 goto decode_success;
sewardj3bca9062004-12-04 14:36:09 +00008511 }
8512
sewardjb5452082004-12-04 20:33:02 +00008513 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8514 /* 0F E3 = PAVGW -- 16x4 unsigned Packed Average, with rounding */
sewardj164f9272004-12-09 00:39:32 +00008515 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xE3) {
sewardjb5452082004-12-04 20:33:02 +00008516 do_MMX_preamble();
8517 delta = dis_MMXop_regmem_to_reg (
8518 sorb, delta+2, insn[1], "pavgw", False );
8519 goto decode_success;
8520 }
8521
8522 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8523 /* 0F C5 = PEXTRW -- extract 16-bit field from mmx(E) and put
8524 zero-extend of it in ireg(G). */
8525 if (insn[0] == 0x0F && insn[1] == 0xC5) {
8526 modrm = insn[2];
8527 if (sz == 4 && epartIsReg(modrm)) {
sewardjb9fa69b2004-12-09 23:25:14 +00008528 IRTemp sV = newTemp(Ity_I64);
8529 t5 = newTemp(Ity_I16);
sewardjb5452082004-12-04 20:33:02 +00008530 do_MMX_preamble();
sewardjb9fa69b2004-12-09 23:25:14 +00008531 assign(sV, getMMXReg(eregOfRM(modrm)));
8532 breakup64to16s( sV, &t3, &t2, &t1, &t0 );
sewardjb5452082004-12-04 20:33:02 +00008533 switch (insn[3] & 3) {
sewardjb9fa69b2004-12-09 23:25:14 +00008534 case 0: assign(t5, mkexpr(t0)); break;
8535 case 1: assign(t5, mkexpr(t1)); break;
8536 case 2: assign(t5, mkexpr(t2)); break;
8537 case 3: assign(t5, mkexpr(t3)); break;
sewardjba89f4c2005-04-07 17:31:27 +00008538 default: vassert(0); /*NOTREACHED*/
sewardjb5452082004-12-04 20:33:02 +00008539 }
sewardjb9fa69b2004-12-09 23:25:14 +00008540 putIReg(4, gregOfRM(modrm), unop(Iop_16Uto32, mkexpr(t5)));
sewardjb5452082004-12-04 20:33:02 +00008541 DIP("pextrw $%d,%s,%s\n",
8542 (Int)insn[3], nameMMXReg(eregOfRM(modrm)),
8543 nameIReg(4,gregOfRM(modrm)));
8544 delta += 4;
8545 goto decode_success;
8546 }
8547 /* else fall through */
8548 }
8549
8550 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8551 /* 0F C4 = PINSRW -- get 16 bits from E(mem or low half ireg) and
8552 put it into the specified lane of mmx(G). */
sewardje5854d62004-12-09 03:44:34 +00008553 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xC4) {
8554 /* Use t0 .. t3 to hold the 4 original 16-bit lanes of the
8555 mmx reg. t4 is the new lane value. t5 is the original
8556 mmx value. t6 is the new mmx value. */
8557 Int lane;
sewardje5854d62004-12-09 03:44:34 +00008558 t4 = newTemp(Ity_I16);
8559 t5 = newTemp(Ity_I64);
8560 t6 = newTemp(Ity_I64);
8561 modrm = insn[2];
8562 do_MMX_preamble();
sewardjb5452082004-12-04 20:33:02 +00008563
sewardje5854d62004-12-09 03:44:34 +00008564 assign(t5, getMMXReg(gregOfRM(modrm)));
sewardjb9fa69b2004-12-09 23:25:14 +00008565 breakup64to16s( t5, &t3, &t2, &t1, &t0 );
sewardjb5452082004-12-04 20:33:02 +00008566
sewardje5854d62004-12-09 03:44:34 +00008567 if (epartIsReg(modrm)) {
8568 assign(t4, getIReg(2, eregOfRM(modrm)));
sewardjaac7e082005-03-17 14:03:46 +00008569 delta += 3+1;
8570 lane = insn[3+1-1];
sewardje5854d62004-12-09 03:44:34 +00008571 DIP("pinsrw $%d,%s,%s\n", (Int)lane,
8572 nameIReg(2,eregOfRM(modrm)),
8573 nameMMXReg(gregOfRM(modrm)));
8574 } else {
sewardj7420b092005-03-13 20:19:19 +00008575 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8576 delta += 3+alen;
8577 lane = insn[3+alen-1];
8578 assign(t4, loadLE(Ity_I16, mkexpr(addr)));
8579 DIP("pinsrw $%d,%s,%s\n", (Int)lane,
8580 dis_buf,
8581 nameMMXReg(gregOfRM(modrm)));
sewardjb5452082004-12-04 20:33:02 +00008582 }
sewardje5854d62004-12-09 03:44:34 +00008583
8584 switch (lane & 3) {
sewardjb9fa69b2004-12-09 23:25:14 +00008585 case 0: assign(t6, mk64from16s(t3,t2,t1,t4)); break;
8586 case 1: assign(t6, mk64from16s(t3,t2,t4,t0)); break;
8587 case 2: assign(t6, mk64from16s(t3,t4,t1,t0)); break;
8588 case 3: assign(t6, mk64from16s(t4,t2,t1,t0)); break;
sewardjba89f4c2005-04-07 17:31:27 +00008589 default: vassert(0); /*NOTREACHED*/
sewardje5854d62004-12-09 03:44:34 +00008590 }
8591 putMMXReg(gregOfRM(modrm), mkexpr(t6));
8592 goto decode_success;
sewardjb5452082004-12-04 20:33:02 +00008593 }
8594
8595 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8596 /* 0F EE = PMAXSW -- 16x4 signed max */
sewardje5854d62004-12-09 03:44:34 +00008597 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xEE) {
sewardjb5452082004-12-04 20:33:02 +00008598 do_MMX_preamble();
8599 delta = dis_MMXop_regmem_to_reg (
8600 sorb, delta+2, insn[1], "pmaxsw", False );
8601 goto decode_success;
8602 }
8603
8604 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8605 /* 0F DE = PMAXUB -- 8x8 unsigned max */
sewardje5854d62004-12-09 03:44:34 +00008606 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xDE) {
sewardjb5452082004-12-04 20:33:02 +00008607 do_MMX_preamble();
8608 delta = dis_MMXop_regmem_to_reg (
8609 sorb, delta+2, insn[1], "pmaxub", False );
8610 goto decode_success;
8611 }
8612
8613 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8614 /* 0F EA = PMINSW -- 16x4 signed min */
sewardje5854d62004-12-09 03:44:34 +00008615 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xEA) {
sewardjb5452082004-12-04 20:33:02 +00008616 do_MMX_preamble();
8617 delta = dis_MMXop_regmem_to_reg (
8618 sorb, delta+2, insn[1], "pminsw", False );
8619 goto decode_success;
8620 }
8621
8622 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8623 /* 0F DA = PMINUB -- 8x8 unsigned min */
sewardje5854d62004-12-09 03:44:34 +00008624 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xDA) {
sewardjb5452082004-12-04 20:33:02 +00008625 do_MMX_preamble();
8626 delta = dis_MMXop_regmem_to_reg (
8627 sorb, delta+2, insn[1], "pminub", False );
8628 goto decode_success;
8629 }
8630
8631 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8632 /* 0F D7 = PMOVMSKB -- extract sign bits from each of 8 lanes in
8633 mmx(G), turn them into a byte, and put zero-extend of it in
8634 ireg(G). */
sewardje5854d62004-12-09 03:44:34 +00008635 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xD7) {
sewardjb5452082004-12-04 20:33:02 +00008636 modrm = insn[2];
sewardje5854d62004-12-09 03:44:34 +00008637 if (epartIsReg(modrm)) {
sewardjb5452082004-12-04 20:33:02 +00008638 do_MMX_preamble();
8639 t0 = newTemp(Ity_I64);
8640 t1 = newTemp(Ity_I32);
8641 assign(t0, getMMXReg(eregOfRM(modrm)));
8642 assign(t1, mkIRExprCCall(
8643 Ity_I32, 0/*regparms*/,
sewardj38a3f862005-01-13 15:06:51 +00008644 "x86g_calculate_mmx_pmovmskb",
8645 &x86g_calculate_mmx_pmovmskb,
sewardjb5452082004-12-04 20:33:02 +00008646 mkIRExprVec_1(mkexpr(t0))));
8647 putIReg(4, gregOfRM(modrm), mkexpr(t1));
8648 DIP("pmovmskb %s,%s\n", nameMMXReg(eregOfRM(modrm)),
8649 nameIReg(4,gregOfRM(modrm)));
8650 delta += 3;
8651 goto decode_success;
8652 }
8653 /* else fall through */
8654 }
8655
sewardj0bd7ce62004-12-05 02:47:40 +00008656 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8657 /* 0F E4 = PMULUH -- 16x4 hi-half of unsigned widening multiply */
sewardje5854d62004-12-09 03:44:34 +00008658 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xE4) {
sewardj0bd7ce62004-12-05 02:47:40 +00008659 do_MMX_preamble();
8660 delta = dis_MMXop_regmem_to_reg (
8661 sorb, delta+2, insn[1], "pmuluh", False );
8662 goto decode_success;
8663 }
8664
sewardj7df596b2004-12-06 14:29:12 +00008665 /* 0F 18 /0 = PREFETCHNTA -- prefetch into caches, */
8666 /* 0F 18 /1 = PREFETCH0 -- with various different hints */
8667 /* 0F 18 /2 = PREFETCH1 */
8668 /* 0F 18 /3 = PREFETCH2 */
8669 if (insn[0] == 0x0F && insn[1] == 0x18
8670 && !epartIsReg(insn[2])
8671 && gregOfRM(insn[2]) >= 0 && gregOfRM(insn[2]) <= 3) {
8672 HChar* hintstr = "??";
8673
8674 modrm = getIByte(delta+2);
8675 vassert(!epartIsReg(modrm));
8676
8677 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8678 delta += 2+alen;
8679
8680 switch (gregOfRM(modrm)) {
8681 case 0: hintstr = "nta"; break;
8682 case 1: hintstr = "t0"; break;
8683 case 2: hintstr = "t1"; break;
8684 case 3: hintstr = "t2"; break;
sewardjba89f4c2005-04-07 17:31:27 +00008685 default: vassert(0); /*NOTREACHED*/
sewardj7df596b2004-12-06 14:29:12 +00008686 }
8687
8688 DIP("prefetch%s %s\n", hintstr, dis_buf);
8689 goto decode_success;
8690 }
8691
sewardj85317682006-03-06 14:07:58 +00008692 /* 0F 0D /0 = PREFETCH m8 -- 3DNow! prefetch */
8693 /* 0F 0D /1 = PREFETCHW m8 -- ditto, with some other hint */
8694 if (insn[0] == 0x0F && insn[1] == 0x0D
8695 && !epartIsReg(insn[2])
8696 && gregOfRM(insn[2]) >= 0 && gregOfRM(insn[2]) <= 1) {
8697 HChar* hintstr = "??";
8698
8699 modrm = getIByte(delta+2);
8700 vassert(!epartIsReg(modrm));
8701
8702 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8703 delta += 2+alen;
8704
8705 switch (gregOfRM(modrm)) {
8706 case 0: hintstr = ""; break;
8707 case 1: hintstr = "w"; break;
8708 default: vassert(0); /*NOTREACHED*/
8709 }
8710
8711 DIP("prefetch%s %s\n", hintstr, dis_buf);
8712 goto decode_success;
8713 }
8714
sewardj0bd7ce62004-12-05 02:47:40 +00008715 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8716 /* 0F F6 = PSADBW -- sum of 8Ux8 absolute differences */
sewardj7b5b9982005-10-04 11:43:37 +00008717 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xF6) {
sewardj0bd7ce62004-12-05 02:47:40 +00008718 do_MMX_preamble();
8719 delta = dis_MMXop_regmem_to_reg (
8720 sorb, delta+2, insn[1], "psadbw", False );
8721 goto decode_success;
8722 }
8723
8724 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8725 /* 0F 70 = PSHUFW -- rearrange 4x16 from E(mmx or mem) to G(mmx) */
sewardjb9fa69b2004-12-09 23:25:14 +00008726 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x70) {
sewardj0bd7ce62004-12-05 02:47:40 +00008727 Int order;
sewardjb9fa69b2004-12-09 23:25:14 +00008728 IRTemp sV, dV, s3, s2, s1, s0;
8729 s3 = s2 = s1 = s0 = IRTemp_INVALID;
8730 sV = newTemp(Ity_I64);
8731 dV = newTemp(Ity_I64);
sewardj0bd7ce62004-12-05 02:47:40 +00008732 do_MMX_preamble();
8733 modrm = insn[2];
8734 if (epartIsReg(modrm)) {
sewardjb9fa69b2004-12-09 23:25:14 +00008735 assign( sV, getMMXReg(eregOfRM(modrm)) );
sewardj0bd7ce62004-12-05 02:47:40 +00008736 order = (Int)insn[3];
8737 delta += 2+2;
8738 DIP("pshufw $%d,%s,%s\n", order,
8739 nameMMXReg(eregOfRM(modrm)),
8740 nameMMXReg(gregOfRM(modrm)));
8741 } else {
8742 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
sewardjb9fa69b2004-12-09 23:25:14 +00008743 assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
sewardj0bd7ce62004-12-05 02:47:40 +00008744 order = (Int)insn[2+alen];
8745 delta += 3+alen;
8746 DIP("pshufw $%d,%s,%s\n", order,
8747 dis_buf,
8748 nameMMXReg(gregOfRM(modrm)));
8749 }
sewardjb9fa69b2004-12-09 23:25:14 +00008750 breakup64to16s( sV, &s3, &s2, &s1, &s0 );
sewardj0bd7ce62004-12-05 02:47:40 +00008751
sewardjb9fa69b2004-12-09 23:25:14 +00008752# define SEL(n) \
8753 ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
8754 assign(dV,
8755 mk64from16s( SEL((order>>6)&3), SEL((order>>4)&3),
8756 SEL((order>>2)&3), SEL((order>>0)&3) )
sewardj0bd7ce62004-12-05 02:47:40 +00008757 );
sewardjb9fa69b2004-12-09 23:25:14 +00008758 putMMXReg(gregOfRM(modrm), mkexpr(dV));
sewardj0bd7ce62004-12-05 02:47:40 +00008759# undef SEL
sewardj0bd7ce62004-12-05 02:47:40 +00008760 goto decode_success;
8761 }
8762
8763 /* 0F 53 = RCPPS -- approx reciprocal 32Fx4 from R/M to R */
8764 if (insn[0] == 0x0F && insn[1] == 0x53) {
8765 vassert(sz == 4);
sewardj129b3d92004-12-05 15:42:05 +00008766 delta = dis_SSE_E_to_G_unary_all( sorb, delta+2,
8767 "rcpps", Iop_Recip32Fx4 );
sewardj0bd7ce62004-12-05 02:47:40 +00008768 goto decode_success;
8769 }
8770
8771 /* F3 0F 53 = RCPSS -- approx reciprocal 32F0x4 from R/M to R */
8772 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x53) {
8773 vassert(sz == 4);
sewardj129b3d92004-12-05 15:42:05 +00008774 delta = dis_SSE_E_to_G_unary_lo32( sorb, delta+3,
8775 "rcpss", Iop_Recip32F0x4 );
sewardj0bd7ce62004-12-05 02:47:40 +00008776 goto decode_success;
8777 }
sewardjb5452082004-12-04 20:33:02 +00008778
sewardjc1e7dfc2004-12-05 19:29:45 +00008779 /* 0F 52 = RSQRTPS -- approx reciprocal sqrt 32Fx4 from R/M to R */
8780 if (insn[0] == 0x0F && insn[1] == 0x52) {
8781 vassert(sz == 4);
8782 delta = dis_SSE_E_to_G_unary_all( sorb, delta+2,
8783 "rsqrtps", Iop_RSqrt32Fx4 );
8784 goto decode_success;
8785 }
8786
8787 /* F3 0F 52 = RSQRTSS -- approx reciprocal sqrt 32F0x4 from R/M to R */
8788 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x52) {
8789 vassert(sz == 4);
8790 delta = dis_SSE_E_to_G_unary_lo32( sorb, delta+3,
8791 "rsqrtss", Iop_RSqrt32F0x4 );
8792 goto decode_success;
8793 }
8794
8795 /* 0F AE /7 = SFENCE -- flush pending operations to memory */
8796 if (insn[0] == 0x0F && insn[1] == 0xAE
sewardjc2feffc2004-12-08 12:31:22 +00008797 && epartIsReg(insn[2]) && gregOfRM(insn[2]) == 7) {
sewardjc1e7dfc2004-12-05 19:29:45 +00008798 vassert(sz == 4);
8799 delta += 3;
sewardj3e838932005-01-07 12:09:15 +00008800 /* Insert a memory fence. It's sometimes important that these
8801 are carried through to the generated code. */
sewardjc4356f02007-11-09 21:15:04 +00008802 stmt( IRStmt_MBE(Imbe_Fence) );
sewardjc1e7dfc2004-12-05 19:29:45 +00008803 DIP("sfence\n");
8804 goto decode_success;
8805 }
8806
8807 /* 0F C6 /r ib = SHUFPS -- shuffle packed F32s */
sewardj008754b2004-12-08 14:37:10 +00008808 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xC6) {
sewardjc1e7dfc2004-12-05 19:29:45 +00008809 Int select;
8810 IRTemp sV, dV;
8811 IRTemp s3, s2, s1, s0, d3, d2, d1, d0;
8812 sV = newTemp(Ity_V128);
8813 dV = newTemp(Ity_V128);
8814 s3 = s2 = s1 = s0 = d3 = d2 = d1 = d0 = IRTemp_INVALID;
sewardjc1e7dfc2004-12-05 19:29:45 +00008815 modrm = insn[2];
8816 assign( dV, getXMMReg(gregOfRM(modrm)) );
8817
8818 if (epartIsReg(modrm)) {
8819 assign( sV, getXMMReg(eregOfRM(modrm)) );
8820 select = (Int)insn[3];
8821 delta += 2+2;
8822 DIP("shufps $%d,%s,%s\n", select,
8823 nameXMMReg(eregOfRM(modrm)),
8824 nameXMMReg(gregOfRM(modrm)));
8825 } else {
8826 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8827 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
8828 select = (Int)insn[2+alen];
8829 delta += 3+alen;
8830 DIP("shufps $%d,%s,%s\n", select,
8831 dis_buf,
8832 nameXMMReg(gregOfRM(modrm)));
8833 }
8834
8835 breakup128to32s( dV, &d3, &d2, &d1, &d0 );
8836 breakup128to32s( sV, &s3, &s2, &s1, &s0 );
8837
8838# define SELD(n) ((n)==0 ? d0 : ((n)==1 ? d1 : ((n)==2 ? d2 : d3)))
8839# define SELS(n) ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
8840
8841 putXMMReg(
8842 gregOfRM(modrm),
8843 mk128from32s( SELS((select>>6)&3), SELS((select>>4)&3),
8844 SELD((select>>2)&3), SELD((select>>0)&3) )
8845 );
8846
8847# undef SELD
8848# undef SELS
8849
8850 goto decode_success;
8851 }
8852
8853 /* 0F 51 = SQRTPS -- approx sqrt 32Fx4 from R/M to R */
sewardj008754b2004-12-08 14:37:10 +00008854 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x51) {
sewardjc1e7dfc2004-12-05 19:29:45 +00008855 delta = dis_SSE_E_to_G_unary_all( sorb, delta+2,
8856 "sqrtps", Iop_Sqrt32Fx4 );
8857 goto decode_success;
8858 }
8859
8860 /* F3 0F 51 = SQRTSS -- approx sqrt 32F0x4 from R/M to R */
8861 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x51) {
8862 vassert(sz == 4);
8863 delta = dis_SSE_E_to_G_unary_lo32( sorb, delta+3,
8864 "sqrtss", Iop_Sqrt32F0x4 );
8865 goto decode_success;
8866 }
8867
sewardja0e83b02005-01-06 12:36:38 +00008868 /* 0F AE /3 = STMXCSR m32 -- store %mxcsr */
sewardj7df596b2004-12-06 14:29:12 +00008869 if (insn[0] == 0x0F && insn[1] == 0xAE
8870 && !epartIsReg(insn[2]) && gregOfRM(insn[2]) == 3) {
8871 modrm = getIByte(delta+2);
8872 vassert(sz == 4);
8873 vassert(!epartIsReg(modrm));
8874
8875 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8876 delta += 2+alen;
8877
8878 /* Fake up a native SSE mxcsr word. The only thing it depends
8879 on is SSEROUND[1:0], so call a clean helper to cook it up.
8880 */
8881 /* UInt x86h_create_mxcsr ( UInt sseround ) */
sewardj33dd31b2005-01-08 18:17:32 +00008882 DIP("stmxcsr %s\n", dis_buf);
sewardj7df596b2004-12-06 14:29:12 +00008883 storeLE( mkexpr(addr),
8884 mkIRExprCCall(
8885 Ity_I32, 0/*regp*/,
sewardj3bd6f3e2004-12-13 10:48:19 +00008886 "x86g_create_mxcsr", &x86g_create_mxcsr,
sewardja0e83b02005-01-06 12:36:38 +00008887 mkIRExprVec_1( get_sse_roundingmode() )
sewardj7df596b2004-12-06 14:29:12 +00008888 )
8889 );
8890 goto decode_success;
8891 }
8892
sewardjc1e7dfc2004-12-05 19:29:45 +00008893 /* 0F 5C = SUBPS -- sub 32Fx4 from R/M to R */
sewardj008754b2004-12-08 14:37:10 +00008894 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5C) {
sewardjc1e7dfc2004-12-05 19:29:45 +00008895 delta = dis_SSE_E_to_G_all( sorb, delta+2, "subps", Iop_Sub32Fx4 );
8896 goto decode_success;
8897 }
8898
sewardj008754b2004-12-08 14:37:10 +00008899 /* F3 0F 5C = SUBSS -- sub 32F0x4 from R/M to R */
sewardjc1e7dfc2004-12-05 19:29:45 +00008900 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5C) {
8901 vassert(sz == 4);
8902 delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "subss", Iop_Sub32F0x4 );
8903 goto decode_success;
8904 }
8905
8906 /* 0F 15 = UNPCKHPS -- unpack and interleave high part F32s */
8907 /* 0F 14 = UNPCKLPS -- unpack and interleave low part F32s */
8908 /* These just appear to be special cases of SHUFPS */
sewardj008754b2004-12-08 14:37:10 +00008909 if (sz == 4 && insn[0] == 0x0F && (insn[1] == 0x15 || insn[1] == 0x14)) {
sewardjc1e7dfc2004-12-05 19:29:45 +00008910 IRTemp sV, dV;
8911 IRTemp s3, s2, s1, s0, d3, d2, d1, d0;
sewardj2d49b432005-02-01 00:37:06 +00008912 Bool hi = toBool(insn[1] == 0x15);
sewardjc1e7dfc2004-12-05 19:29:45 +00008913 sV = newTemp(Ity_V128);
8914 dV = newTemp(Ity_V128);
8915 s3 = s2 = s1 = s0 = d3 = d2 = d1 = d0 = IRTemp_INVALID;
sewardjc1e7dfc2004-12-05 19:29:45 +00008916 modrm = insn[2];
8917 assign( dV, getXMMReg(gregOfRM(modrm)) );
8918
8919 if (epartIsReg(modrm)) {
8920 assign( sV, getXMMReg(eregOfRM(modrm)) );
8921 delta += 2+1;
8922 DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
8923 nameXMMReg(eregOfRM(modrm)),
8924 nameXMMReg(gregOfRM(modrm)));
8925 } else {
8926 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8927 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
8928 delta += 2+alen;
8929 DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
8930 dis_buf,
8931 nameXMMReg(gregOfRM(modrm)));
8932 }
8933
8934 breakup128to32s( dV, &d3, &d2, &d1, &d0 );
8935 breakup128to32s( sV, &s3, &s2, &s1, &s0 );
8936
8937 if (hi) {
8938 putXMMReg( gregOfRM(modrm), mk128from32s( s3, d3, s2, d2 ) );
8939 } else {
8940 putXMMReg( gregOfRM(modrm), mk128from32s( s1, d1, s0, d0 ) );
8941 }
8942
8943 goto decode_success;
8944 }
8945
8946 /* 0F 57 = XORPS -- G = G and E */
sewardj008754b2004-12-08 14:37:10 +00008947 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x57) {
sewardjf0c1c582005-02-07 23:47:38 +00008948 delta = dis_SSE_E_to_G_all( sorb, delta+2, "xorps", Iop_XorV128 );
sewardjc1e7dfc2004-12-05 19:29:45 +00008949 goto decode_success;
8950 }
8951
sewardj636ad762004-12-07 11:16:04 +00008952 /* ---------------------------------------------------- */
8953 /* --- end of the SSE decoder. --- */
8954 /* ---------------------------------------------------- */
8955
8956 /* ---------------------------------------------------- */
8957 /* --- start of the SSE2 decoder. --- */
8958 /* ---------------------------------------------------- */
8959
sewardj9df271d2004-12-31 22:37:42 +00008960 /* Skip parts of the decoder which don't apply given the stated
8961 guest subarchitecture. */
sewardj5117ce12006-01-27 21:20:15 +00008962 if (0 == (archinfo->hwcaps & VEX_HWCAPS_X86_SSE2))
8963 goto after_sse_decoders; /* no SSE2 capabilities */
sewardj9df271d2004-12-31 22:37:42 +00008964
sewardj636ad762004-12-07 11:16:04 +00008965 insn = (UChar*)&guest_code[delta];
8966
8967 /* 66 0F 58 = ADDPD -- add 32Fx4 from R/M to R */
8968 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x58) {
8969 delta = dis_SSE_E_to_G_all( sorb, delta+2, "addpd", Iop_Add64Fx2 );
8970 goto decode_success;
8971 }
8972
8973 /* F2 0F 58 = ADDSD -- add 64F0x2 from R/M to R */
8974 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x58) {
8975 vassert(sz == 4);
8976 delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "addsd", Iop_Add64F0x2 );
8977 goto decode_success;
8978 }
8979
8980 /* 66 0F 55 = ANDNPD -- G = (not G) and E */
8981 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x55) {
sewardjf0c1c582005-02-07 23:47:38 +00008982 delta = dis_SSE_E_to_G_all_invG( sorb, delta+2, "andnpd", Iop_AndV128 );
sewardj636ad762004-12-07 11:16:04 +00008983 goto decode_success;
8984 }
8985
8986 /* 66 0F 54 = ANDPD -- G = G and E */
8987 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x54) {
sewardjf0c1c582005-02-07 23:47:38 +00008988 delta = dis_SSE_E_to_G_all( sorb, delta+2, "andpd", Iop_AndV128 );
sewardj636ad762004-12-07 11:16:04 +00008989 goto decode_success;
8990 }
8991
sewardjfd226452004-12-07 19:02:18 +00008992 /* 66 0F C2 = CMPPD -- 64Fx2 comparison from R/M to R */
8993 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xC2) {
8994 delta = dis_SSEcmp_E_to_G( sorb, delta+2, "cmppd", True, 8 );
8995 goto decode_success;
8996 }
8997
8998 /* F2 0F C2 = CMPSD -- 64F0x2 comparison from R/M to R */
8999 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0xC2) {
9000 vassert(sz == 4);
9001 delta = dis_SSEcmp_E_to_G( sorb, delta+3, "cmpsd", False, 8 );
9002 goto decode_success;
9003 }
9004
9005 /* 66 0F 2F = COMISD -- 64F0x2 comparison G,E, and set ZCP */
9006 /* 66 0F 2E = UCOMISD -- 64F0x2 comparison G,E, and set ZCP */
9007 if (sz == 2 && insn[0] == 0x0F && (insn[1] == 0x2F || insn[1] == 0x2E)) {
9008 IRTemp argL = newTemp(Ity_F64);
9009 IRTemp argR = newTemp(Ity_F64);
9010 modrm = getIByte(delta+2);
9011 if (epartIsReg(modrm)) {
9012 assign( argR, getXMMRegLane64F( eregOfRM(modrm), 0/*lowest lane*/ ) );
9013 delta += 2+1;
9014 DIP("[u]comisd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9015 nameXMMReg(gregOfRM(modrm)) );
9016 } else {
9017 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9018 assign( argR, loadLE(Ity_F64, mkexpr(addr)) );
9019 delta += 2+alen;
9020 DIP("[u]comisd %s,%s\n", dis_buf,
9021 nameXMMReg(gregOfRM(modrm)) );
9022 }
9023 assign( argL, getXMMRegLane64F( gregOfRM(modrm), 0/*lowest lane*/ ) );
9024
9025 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
9026 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
9027 stmt( IRStmt_Put(
9028 OFFB_CC_DEP1,
9029 binop( Iop_And32,
9030 binop(Iop_CmpF64, mkexpr(argL), mkexpr(argR)),
9031 mkU32(0x45)
9032 )));
sewardja3b7e3a2005-04-05 01:54:19 +00009033 /* Set NDEP even though it isn't used. This makes redundant-PUT
9034 elimination of previous stores to this field work better. */
9035 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardjfd226452004-12-07 19:02:18 +00009036 goto decode_success;
9037 }
9038
9039 /* F3 0F E6 = CVTDQ2PD -- convert 2 x I32 in mem/lo half xmm to 2 x
9040 F64 in xmm(G) */
9041 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0xE6) {
9042 IRTemp arg64 = newTemp(Ity_I64);
9043 vassert(sz == 4);
9044
9045 modrm = getIByte(delta+3);
9046 if (epartIsReg(modrm)) {
9047 assign( arg64, getXMMRegLane64(eregOfRM(modrm), 0) );
9048 delta += 3+1;
9049 DIP("cvtdq2pd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9050 nameXMMReg(gregOfRM(modrm)));
9051 } else {
9052 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
9053 assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
9054 delta += 3+alen;
9055 DIP("cvtdq2pd %s,%s\n", dis_buf,
9056 nameXMMReg(gregOfRM(modrm)) );
9057 }
9058
9059 putXMMRegLane64F(
9060 gregOfRM(modrm), 0,
9061 unop(Iop_I32toF64, unop(Iop_64to32, mkexpr(arg64)))
9062 );
9063
9064 putXMMRegLane64F(
9065 gregOfRM(modrm), 1,
9066 unop(Iop_I32toF64, unop(Iop_64HIto32, mkexpr(arg64)))
9067 );
9068
9069 goto decode_success;
9070 }
9071
9072 /* 0F 5B = CVTDQ2PS -- convert 4 x I32 in mem/xmm to 4 x F32 in
9073 xmm(G) */
9074 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5B) {
9075 IRTemp argV = newTemp(Ity_V128);
9076 IRTemp rmode = newTemp(Ity_I32);
9077
9078 modrm = getIByte(delta+2);
9079 if (epartIsReg(modrm)) {
9080 assign( argV, getXMMReg(eregOfRM(modrm)) );
9081 delta += 2+1;
9082 DIP("cvtdq2ps %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9083 nameXMMReg(gregOfRM(modrm)));
9084 } else {
9085 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9086 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
9087 delta += 2+alen;
9088 DIP("cvtdq2ps %s,%s\n", dis_buf,
9089 nameXMMReg(gregOfRM(modrm)) );
9090 }
9091
9092 assign( rmode, get_sse_roundingmode() );
9093 breakup128to32s( argV, &t3, &t2, &t1, &t0 );
9094
9095# define CVT(_t) binop( Iop_F64toF32, \
9096 mkexpr(rmode), \
9097 unop(Iop_I32toF64,mkexpr(_t)))
9098
9099 putXMMRegLane32F( gregOfRM(modrm), 3, CVT(t3) );
9100 putXMMRegLane32F( gregOfRM(modrm), 2, CVT(t2) );
9101 putXMMRegLane32F( gregOfRM(modrm), 1, CVT(t1) );
9102 putXMMRegLane32F( gregOfRM(modrm), 0, CVT(t0) );
9103
9104# undef CVT
9105
9106 goto decode_success;
9107 }
9108
9109 /* F2 0F E6 = CVTPD2DQ -- convert 2 x F64 in mem/xmm to 2 x I32 in
9110 lo half xmm(G), and zero upper half */
9111 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0xE6) {
9112 IRTemp argV = newTemp(Ity_V128);
9113 IRTemp rmode = newTemp(Ity_I32);
9114 vassert(sz == 4);
9115
9116 modrm = getIByte(delta+3);
9117 if (epartIsReg(modrm)) {
9118 assign( argV, getXMMReg(eregOfRM(modrm)) );
9119 delta += 3+1;
9120 DIP("cvtpd2dq %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9121 nameXMMReg(gregOfRM(modrm)));
9122 } else {
9123 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
9124 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
9125 delta += 3+alen;
9126 DIP("cvtpd2dq %s,%s\n", dis_buf,
9127 nameXMMReg(gregOfRM(modrm)) );
9128 }
9129
9130 assign( rmode, get_sse_roundingmode() );
9131 t0 = newTemp(Ity_F64);
9132 t1 = newTemp(Ity_F64);
9133 assign( t0, unop(Iop_ReinterpI64asF64,
sewardjf0c1c582005-02-07 23:47:38 +00009134 unop(Iop_V128to64, mkexpr(argV))) );
sewardjfd226452004-12-07 19:02:18 +00009135 assign( t1, unop(Iop_ReinterpI64asF64,
sewardjf0c1c582005-02-07 23:47:38 +00009136 unop(Iop_V128HIto64, mkexpr(argV))) );
sewardjfd226452004-12-07 19:02:18 +00009137
9138# define CVT(_t) binop( Iop_F64toI32, \
9139 mkexpr(rmode), \
9140 mkexpr(_t) )
9141
9142 putXMMRegLane32( gregOfRM(modrm), 3, mkU32(0) );
9143 putXMMRegLane32( gregOfRM(modrm), 2, mkU32(0) );
9144 putXMMRegLane32( gregOfRM(modrm), 1, CVT(t1) );
9145 putXMMRegLane32( gregOfRM(modrm), 0, CVT(t0) );
9146
9147# undef CVT
9148
9149 goto decode_success;
9150 }
9151
9152 /* 66 0F 2D = CVTPD2PI -- convert 2 x F64 in mem/xmm to 2 x
9153 I32 in mmx, according to prevailing SSE rounding mode */
9154 /* 66 0F 2C = CVTTPD2PI -- convert 2 x F64 in mem/xmm to 2 x
9155 I32 in mmx, rounding towards zero */
9156 if (sz == 2 && insn[0] == 0x0F && (insn[1] == 0x2D || insn[1] == 0x2C)) {
9157 IRTemp dst64 = newTemp(Ity_I64);
9158 IRTemp rmode = newTemp(Ity_I32);
9159 IRTemp f64lo = newTemp(Ity_F64);
9160 IRTemp f64hi = newTemp(Ity_F64);
sewardj2d49b432005-02-01 00:37:06 +00009161 Bool r2zero = toBool(insn[1] == 0x2C);
sewardjfd226452004-12-07 19:02:18 +00009162
9163 do_MMX_preamble();
9164 modrm = getIByte(delta+2);
9165
9166 if (epartIsReg(modrm)) {
9167 delta += 2+1;
9168 assign(f64lo, getXMMRegLane64F(eregOfRM(modrm), 0));
9169 assign(f64hi, getXMMRegLane64F(eregOfRM(modrm), 1));
9170 DIP("cvt%spd2pi %s,%s\n", r2zero ? "t" : "",
9171 nameXMMReg(eregOfRM(modrm)),
9172 nameMMXReg(gregOfRM(modrm)));
9173 } else {
9174 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9175 assign(f64lo, loadLE(Ity_F64, mkexpr(addr)));
9176 assign(f64hi, loadLE(Ity_F64, binop( Iop_Add32,
9177 mkexpr(addr),
9178 mkU32(8) )));
9179 delta += 2+alen;
9180 DIP("cvt%spf2pi %s,%s\n", r2zero ? "t" : "",
9181 dis_buf,
9182 nameMMXReg(gregOfRM(modrm)));
9183 }
9184
9185 if (r2zero) {
9186 assign(rmode, mkU32((UInt)Irrm_ZERO) );
9187 } else {
9188 assign( rmode, get_sse_roundingmode() );
9189 }
9190
9191 assign(
9192 dst64,
9193 binop( Iop_32HLto64,
9194 binop( Iop_F64toI32, mkexpr(rmode), mkexpr(f64hi) ),
9195 binop( Iop_F64toI32, mkexpr(rmode), mkexpr(f64lo) )
9196 )
9197 );
9198
9199 putMMXReg(gregOfRM(modrm), mkexpr(dst64));
9200 goto decode_success;
9201 }
9202
9203 /* 66 0F 5A = CVTPD2PS -- convert 2 x F64 in mem/xmm to 2 x F32 in
9204 lo half xmm(G), and zero upper half */
9205 /* Note, this is practically identical to CVTPD2DQ. It would have
9206 been nicer to merge them together, but the insn[] offsets differ
9207 by one. */
9208 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5A) {
9209 IRTemp argV = newTemp(Ity_V128);
9210 IRTemp rmode = newTemp(Ity_I32);
9211
9212 modrm = getIByte(delta+2);
9213 if (epartIsReg(modrm)) {
9214 assign( argV, getXMMReg(eregOfRM(modrm)) );
9215 delta += 2+1;
9216 DIP("cvtpd2ps %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9217 nameXMMReg(gregOfRM(modrm)));
9218 } else {
9219 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9220 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
9221 delta += 2+alen;
9222 DIP("cvtpd2ps %s,%s\n", dis_buf,
9223 nameXMMReg(gregOfRM(modrm)) );
9224 }
9225
9226 assign( rmode, get_sse_roundingmode() );
9227 t0 = newTemp(Ity_F64);
9228 t1 = newTemp(Ity_F64);
9229 assign( t0, unop(Iop_ReinterpI64asF64,
sewardjf0c1c582005-02-07 23:47:38 +00009230 unop(Iop_V128to64, mkexpr(argV))) );
sewardjfd226452004-12-07 19:02:18 +00009231 assign( t1, unop(Iop_ReinterpI64asF64,
sewardjf0c1c582005-02-07 23:47:38 +00009232 unop(Iop_V128HIto64, mkexpr(argV))) );
sewardjfd226452004-12-07 19:02:18 +00009233
9234# define CVT(_t) binop( Iop_F64toF32, \
9235 mkexpr(rmode), \
9236 mkexpr(_t) )
9237
9238 putXMMRegLane32( gregOfRM(modrm), 3, mkU32(0) );
9239 putXMMRegLane32( gregOfRM(modrm), 2, mkU32(0) );
9240 putXMMRegLane32F( gregOfRM(modrm), 1, CVT(t1) );
9241 putXMMRegLane32F( gregOfRM(modrm), 0, CVT(t0) );
9242
9243# undef CVT
9244
9245 goto decode_success;
9246 }
9247
9248 /* 66 0F 2A = CVTPI2PD -- convert 2 x I32 in mem/mmx to 2 x F64 in
9249 xmm(G) */
9250 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x2A) {
9251 IRTemp arg64 = newTemp(Ity_I64);
9252
9253 modrm = getIByte(delta+2);
9254 do_MMX_preamble();
9255 if (epartIsReg(modrm)) {
9256 assign( arg64, getMMXReg(eregOfRM(modrm)) );
9257 delta += 2+1;
9258 DIP("cvtpi2pd %s,%s\n", nameMMXReg(eregOfRM(modrm)),
9259 nameXMMReg(gregOfRM(modrm)));
9260 } else {
9261 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9262 assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
9263 delta += 2+alen;
9264 DIP("cvtpi2pd %s,%s\n", dis_buf,
9265 nameXMMReg(gregOfRM(modrm)) );
9266 }
9267
9268 putXMMRegLane64F(
9269 gregOfRM(modrm), 0,
9270 unop(Iop_I32toF64, unop(Iop_64to32, mkexpr(arg64)) )
9271 );
9272
9273 putXMMRegLane64F(
9274 gregOfRM(modrm), 1,
9275 unop(Iop_I32toF64, unop(Iop_64HIto32, mkexpr(arg64)) )
9276 );
9277
9278 goto decode_success;
9279 }
9280
9281 /* 66 0F 5B = CVTPS2DQ -- convert 4 x F32 in mem/xmm to 4 x I32 in
9282 xmm(G) */
9283 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5B) {
9284 IRTemp argV = newTemp(Ity_V128);
9285 IRTemp rmode = newTemp(Ity_I32);
9286
9287 modrm = getIByte(delta+2);
9288 if (epartIsReg(modrm)) {
9289 assign( argV, getXMMReg(eregOfRM(modrm)) );
9290 delta += 2+1;
9291 DIP("cvtps2dq %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9292 nameXMMReg(gregOfRM(modrm)));
9293 } else {
9294 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9295 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
9296 delta += 2+alen;
9297 DIP("cvtps2dq %s,%s\n", dis_buf,
9298 nameXMMReg(gregOfRM(modrm)) );
9299 }
9300
9301 assign( rmode, get_sse_roundingmode() );
9302 breakup128to32s( argV, &t3, &t2, &t1, &t0 );
9303
9304 /* This is less than ideal. If it turns out to be a performance
9305 bottleneck it can be improved. */
9306# define CVT(_t) \
9307 binop( Iop_F64toI32, \
9308 mkexpr(rmode), \
9309 unop( Iop_F32toF64, \
9310 unop( Iop_ReinterpI32asF32, mkexpr(_t))) )
9311
9312 putXMMRegLane32( gregOfRM(modrm), 3, CVT(t3) );
9313 putXMMRegLane32( gregOfRM(modrm), 2, CVT(t2) );
9314 putXMMRegLane32( gregOfRM(modrm), 1, CVT(t1) );
9315 putXMMRegLane32( gregOfRM(modrm), 0, CVT(t0) );
9316
9317# undef CVT
9318
9319 goto decode_success;
9320 }
9321
9322 /* 0F 5A = CVTPS2PD -- convert 2 x F32 in low half mem/xmm to 2 x
9323 F64 in xmm(G). */
9324 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5A) {
9325 IRTemp f32lo = newTemp(Ity_F32);
9326 IRTemp f32hi = newTemp(Ity_F32);
9327
9328 modrm = getIByte(delta+2);
9329 if (epartIsReg(modrm)) {
9330 assign( f32lo, getXMMRegLane32F(eregOfRM(modrm), 0) );
9331 assign( f32hi, getXMMRegLane32F(eregOfRM(modrm), 1) );
9332 delta += 2+1;
9333 DIP("cvtps2pd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9334 nameXMMReg(gregOfRM(modrm)));
9335 } else {
9336 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9337 assign( f32lo, loadLE(Ity_F32, mkexpr(addr)) );
9338 assign( f32hi, loadLE(Ity_F32,
9339 binop(Iop_Add32,mkexpr(addr),mkU32(4))) );
9340 delta += 2+alen;
9341 DIP("cvtps2pd %s,%s\n", dis_buf,
9342 nameXMMReg(gregOfRM(modrm)) );
9343 }
9344
9345 putXMMRegLane64F( gregOfRM(modrm), 1,
9346 unop(Iop_F32toF64, mkexpr(f32hi)) );
9347 putXMMRegLane64F( gregOfRM(modrm), 0,
9348 unop(Iop_F32toF64, mkexpr(f32lo)) );
9349
9350 goto decode_success;
9351 }
9352
9353 /* F2 0F 2D = CVTSD2SI -- convert F64 in mem/low half xmm to
9354 I32 in ireg, according to prevailing SSE rounding mode */
9355 /* F2 0F 2C = CVTTSD2SI -- convert F64 in mem/low half xmm to
sewardj0b210442005-02-23 13:28:27 +00009356 I32 in ireg, rounding towards zero */
sewardjfd226452004-12-07 19:02:18 +00009357 if (insn[0] == 0xF2 && insn[1] == 0x0F
9358 && (insn[2] == 0x2D || insn[2] == 0x2C)) {
9359 IRTemp rmode = newTemp(Ity_I32);
9360 IRTemp f64lo = newTemp(Ity_F64);
sewardj2d49b432005-02-01 00:37:06 +00009361 Bool r2zero = toBool(insn[2] == 0x2C);
sewardjfd226452004-12-07 19:02:18 +00009362 vassert(sz == 4);
9363
9364 modrm = getIByte(delta+3);
9365 if (epartIsReg(modrm)) {
9366 delta += 3+1;
9367 assign(f64lo, getXMMRegLane64F(eregOfRM(modrm), 0));
9368 DIP("cvt%ssd2si %s,%s\n", r2zero ? "t" : "",
9369 nameXMMReg(eregOfRM(modrm)),
9370 nameIReg(4, gregOfRM(modrm)));
9371 } else {
9372 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
9373 assign(f64lo, loadLE(Ity_F64, mkexpr(addr)));
9374 delta += 3+alen;
9375 DIP("cvt%ssd2si %s,%s\n", r2zero ? "t" : "",
9376 dis_buf,
9377 nameIReg(4, gregOfRM(modrm)));
9378 }
9379
9380 if (r2zero) {
9381 assign( rmode, mkU32((UInt)Irrm_ZERO) );
9382 } else {
9383 assign( rmode, get_sse_roundingmode() );
9384 }
9385
9386 putIReg(4, gregOfRM(modrm),
9387 binop( Iop_F64toI32, mkexpr(rmode), mkexpr(f64lo)) );
9388
9389 goto decode_success;
9390 }
9391
9392 /* F2 0F 5A = CVTSD2SS -- convert F64 in mem/low half xmm to F32 in
9393 low 1/4 xmm(G), according to prevailing SSE rounding mode */
9394 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x5A) {
9395 IRTemp rmode = newTemp(Ity_I32);
9396 IRTemp f64lo = newTemp(Ity_F64);
9397 vassert(sz == 4);
9398
9399 modrm = getIByte(delta+3);
9400 if (epartIsReg(modrm)) {
9401 delta += 3+1;
9402 assign(f64lo, getXMMRegLane64F(eregOfRM(modrm), 0));
9403 DIP("cvtsd2ss %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9404 nameXMMReg(gregOfRM(modrm)));
9405 } else {
9406 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
9407 assign(f64lo, loadLE(Ity_F64, mkexpr(addr)));
9408 delta += 3+alen;
9409 DIP("cvtsd2ss %s,%s\n", dis_buf,
9410 nameXMMReg(gregOfRM(modrm)));
9411 }
9412
9413 assign( rmode, get_sse_roundingmode() );
9414 putXMMRegLane32F(
9415 gregOfRM(modrm), 0,
9416 binop( Iop_F64toF32, mkexpr(rmode), mkexpr(f64lo) )
9417 );
9418
9419 goto decode_success;
9420 }
9421
9422 /* F2 0F 2A = CVTSI2SD -- convert I32 in mem/ireg to F64 in low
9423 half xmm */
9424 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x2A) {
9425 IRTemp arg32 = newTemp(Ity_I32);
9426 vassert(sz == 4);
9427
9428 modrm = getIByte(delta+3);
sewardjfd226452004-12-07 19:02:18 +00009429 if (epartIsReg(modrm)) {
9430 assign( arg32, getIReg(4, eregOfRM(modrm)) );
9431 delta += 3+1;
9432 DIP("cvtsi2sd %s,%s\n", nameIReg(4, eregOfRM(modrm)),
9433 nameXMMReg(gregOfRM(modrm)));
9434 } else {
9435 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
9436 assign( arg32, loadLE(Ity_I32, mkexpr(addr)) );
9437 delta += 3+alen;
9438 DIP("cvtsi2sd %s,%s\n", dis_buf,
9439 nameXMMReg(gregOfRM(modrm)) );
9440 }
9441
9442 putXMMRegLane64F(
9443 gregOfRM(modrm), 0,
9444 unop(Iop_I32toF64, mkexpr(arg32)) );
9445
9446 goto decode_success;
9447 }
9448
9449 /* F3 0F 5A = CVTSS2SD -- convert F32 in mem/low 1/4 xmm to F64 in
9450 low half xmm(G) */
9451 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5A) {
9452 IRTemp f32lo = newTemp(Ity_F32);
9453 vassert(sz == 4);
9454
9455 modrm = getIByte(delta+3);
9456 if (epartIsReg(modrm)) {
9457 delta += 3+1;
9458 assign(f32lo, getXMMRegLane32F(eregOfRM(modrm), 0));
9459 DIP("cvtss2sd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9460 nameXMMReg(gregOfRM(modrm)));
9461 } else {
9462 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
9463 assign(f32lo, loadLE(Ity_F32, mkexpr(addr)));
9464 delta += 3+alen;
9465 DIP("cvtss2sd %s,%s\n", dis_buf,
9466 nameXMMReg(gregOfRM(modrm)));
9467 }
9468
9469 putXMMRegLane64F( gregOfRM(modrm), 0,
9470 unop( Iop_F32toF64, mkexpr(f32lo) ) );
9471
9472 goto decode_success;
9473 }
9474
9475 /* 66 0F E6 = CVTTPD2DQ -- convert 2 x F64 in mem/xmm to 2 x I32 in
9476 lo half xmm(G), and zero upper half, rounding towards zero */
9477 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE6) {
9478 IRTemp argV = newTemp(Ity_V128);
9479 IRTemp rmode = newTemp(Ity_I32);
9480
9481 modrm = getIByte(delta+2);
9482 if (epartIsReg(modrm)) {
9483 assign( argV, getXMMReg(eregOfRM(modrm)) );
9484 delta += 2+1;
9485 DIP("cvttpd2dq %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9486 nameXMMReg(gregOfRM(modrm)));
9487 } else {
9488 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9489 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
9490 delta += 2+alen;
9491 DIP("cvttpd2dq %s,%s\n", dis_buf,
9492 nameXMMReg(gregOfRM(modrm)) );
9493 }
9494
9495 assign( rmode, mkU32((UInt)Irrm_ZERO) );
9496
9497 t0 = newTemp(Ity_F64);
9498 t1 = newTemp(Ity_F64);
9499 assign( t0, unop(Iop_ReinterpI64asF64,
sewardjf0c1c582005-02-07 23:47:38 +00009500 unop(Iop_V128to64, mkexpr(argV))) );
sewardjfd226452004-12-07 19:02:18 +00009501 assign( t1, unop(Iop_ReinterpI64asF64,
sewardjf0c1c582005-02-07 23:47:38 +00009502 unop(Iop_V128HIto64, mkexpr(argV))) );
sewardjfd226452004-12-07 19:02:18 +00009503
9504# define CVT(_t) binop( Iop_F64toI32, \
9505 mkexpr(rmode), \
9506 mkexpr(_t) )
9507
9508 putXMMRegLane32( gregOfRM(modrm), 3, mkU32(0) );
9509 putXMMRegLane32( gregOfRM(modrm), 2, mkU32(0) );
9510 putXMMRegLane32( gregOfRM(modrm), 1, CVT(t1) );
9511 putXMMRegLane32( gregOfRM(modrm), 0, CVT(t0) );
9512
9513# undef CVT
9514
9515 goto decode_success;
9516 }
9517
9518 /* F3 0F 5B = CVTTPS2DQ -- convert 4 x F32 in mem/xmm to 4 x I32 in
9519 xmm(G), rounding towards zero */
9520 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5B) {
9521 IRTemp argV = newTemp(Ity_V128);
9522 IRTemp rmode = newTemp(Ity_I32);
9523 vassert(sz == 4);
9524
9525 modrm = getIByte(delta+3);
9526 if (epartIsReg(modrm)) {
9527 assign( argV, getXMMReg(eregOfRM(modrm)) );
9528 delta += 3+1;
9529 DIP("cvttps2dq %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9530 nameXMMReg(gregOfRM(modrm)));
9531 } else {
9532 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
9533 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
9534 delta += 3+alen;
9535 DIP("cvttps2dq %s,%s\n", dis_buf,
9536 nameXMMReg(gregOfRM(modrm)) );
9537 }
9538
9539 assign( rmode, mkU32((UInt)Irrm_ZERO) );
9540 breakup128to32s( argV, &t3, &t2, &t1, &t0 );
9541
9542 /* This is less than ideal. If it turns out to be a performance
9543 bottleneck it can be improved. */
9544# define CVT(_t) \
9545 binop( Iop_F64toI32, \
9546 mkexpr(rmode), \
9547 unop( Iop_F32toF64, \
9548 unop( Iop_ReinterpI32asF32, mkexpr(_t))) )
9549
9550 putXMMRegLane32( gregOfRM(modrm), 3, CVT(t3) );
9551 putXMMRegLane32( gregOfRM(modrm), 2, CVT(t2) );
9552 putXMMRegLane32( gregOfRM(modrm), 1, CVT(t1) );
9553 putXMMRegLane32( gregOfRM(modrm), 0, CVT(t0) );
9554
9555# undef CVT
9556
9557 goto decode_success;
9558 }
9559
9560 /* 66 0F 5E = DIVPD -- div 64Fx2 from R/M to R */
9561 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5E) {
9562 delta = dis_SSE_E_to_G_all( sorb, delta+2, "divpd", Iop_Div64Fx2 );
9563 goto decode_success;
9564 }
9565
sewardjc2feffc2004-12-08 12:31:22 +00009566 /* F2 0F 5E = DIVSD -- div 64F0x2 from R/M to R */
9567 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x5E) {
9568 vassert(sz == 4);
9569 delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "divsd", Iop_Div64F0x2 );
9570 goto decode_success;
9571 }
9572
9573 /* 0F AE /5 = LFENCE -- flush pending operations to memory */
9574 /* 0F AE /6 = MFENCE -- flush pending operations to memory */
9575 if (insn[0] == 0x0F && insn[1] == 0xAE
9576 && epartIsReg(insn[2])
9577 && (gregOfRM(insn[2]) == 5 || gregOfRM(insn[2]) == 6)) {
9578 vassert(sz == 4);
9579 delta += 3;
sewardj3e838932005-01-07 12:09:15 +00009580 /* Insert a memory fence. It's sometimes important that these
9581 are carried through to the generated code. */
sewardjc4356f02007-11-09 21:15:04 +00009582 stmt( IRStmt_MBE(Imbe_Fence) );
sewardjc2feffc2004-12-08 12:31:22 +00009583 DIP("%sfence\n", gregOfRM(insn[2])==5 ? "l" : "m");
9584 goto decode_success;
9585 }
9586
9587 /* 66 0F 5F = MAXPD -- max 64Fx2 from R/M to R */
9588 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5F) {
9589 delta = dis_SSE_E_to_G_all( sorb, delta+2, "maxpd", Iop_Max64Fx2 );
9590 goto decode_success;
9591 }
9592
9593 /* F2 0F 5F = MAXSD -- max 64F0x2 from R/M to R */
9594 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x5F) {
9595 vassert(sz == 4);
9596 delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "maxsd", Iop_Max64F0x2 );
9597 goto decode_success;
9598 }
9599
9600 /* 66 0F 5D = MINPD -- min 64Fx2 from R/M to R */
9601 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5D) {
9602 delta = dis_SSE_E_to_G_all( sorb, delta+2, "minpd", Iop_Min64Fx2 );
9603 goto decode_success;
9604 }
9605
9606 /* F2 0F 5D = MINSD -- min 64F0x2 from R/M to R */
9607 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x5D) {
9608 vassert(sz == 4);
9609 delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "minsd", Iop_Min64F0x2 );
9610 goto decode_success;
9611 }
9612
9613 /* 66 0F 28 = MOVAPD -- move from E (mem or xmm) to G (xmm). */
9614 /* 66 0F 10 = MOVUPD -- move from E (mem or xmm) to G (xmm). */
9615 /* 66 0F 6F = MOVDQA -- move from E (mem or xmm) to G (xmm). */
9616 if (sz == 2 && insn[0] == 0x0F
9617 && (insn[1] == 0x28 || insn[1] == 0x10 || insn[1] == 0x6F)) {
9618 HChar* wot = insn[1]==0x28 ? "apd" :
9619 insn[1]==0x10 ? "upd" : "dqa";
9620 modrm = getIByte(delta+2);
9621 if (epartIsReg(modrm)) {
9622 putXMMReg( gregOfRM(modrm),
9623 getXMMReg( eregOfRM(modrm) ));
9624 DIP("mov%s %s,%s\n", wot, nameXMMReg(eregOfRM(modrm)),
9625 nameXMMReg(gregOfRM(modrm)));
9626 delta += 2+1;
9627 } else {
9628 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9629 putXMMReg( gregOfRM(modrm),
9630 loadLE(Ity_V128, mkexpr(addr)) );
9631 DIP("mov%s %s,%s\n", wot, dis_buf,
9632 nameXMMReg(gregOfRM(modrm)));
9633 delta += 2+alen;
9634 }
9635 goto decode_success;
9636 }
9637
sewardj95535fe2004-12-15 17:42:58 +00009638 /* 66 0F 29 = MOVAPD -- move from G (xmm) to E (mem or xmm). */
sewardj1c318772005-03-19 14:27:04 +00009639 /* 66 0F 11 = MOVUPD -- move from G (xmm) to E (mem or xmm). */
9640 if (sz == 2 && insn[0] == 0x0F
9641 && (insn[1] == 0x29 || insn[1] == 0x11)) {
9642 HChar* wot = insn[1]==0x29 ? "apd" : "upd";
sewardj95535fe2004-12-15 17:42:58 +00009643 modrm = getIByte(delta+2);
9644 if (epartIsReg(modrm)) {
9645 /* fall through; awaiting test case */
9646 } else {
9647 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9648 storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) );
sewardj1c318772005-03-19 14:27:04 +00009649 DIP("mov%s %s,%s\n", wot, nameXMMReg(gregOfRM(modrm)),
9650 dis_buf );
sewardj95535fe2004-12-15 17:42:58 +00009651 delta += 2+alen;
9652 goto decode_success;
9653 }
9654 }
9655
sewardjc2feffc2004-12-08 12:31:22 +00009656 /* 66 0F 6E = MOVD from r/m32 to xmm, zeroing high 3/4 of xmm. */
9657 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x6E) {
9658 modrm = getIByte(delta+2);
9659 if (epartIsReg(modrm)) {
9660 delta += 2+1;
9661 putXMMReg(
9662 gregOfRM(modrm),
sewardjf0c1c582005-02-07 23:47:38 +00009663 unop( Iop_32UtoV128, getIReg(4, eregOfRM(modrm)) )
sewardjc2feffc2004-12-08 12:31:22 +00009664 );
9665 DIP("movd %s, %s\n",
9666 nameIReg(4,eregOfRM(modrm)), nameXMMReg(gregOfRM(modrm)));
9667 } else {
9668 addr = disAMode( &alen, sorb, delta+2, dis_buf );
9669 delta += 2+alen;
9670 putXMMReg(
9671 gregOfRM(modrm),
sewardjf0c1c582005-02-07 23:47:38 +00009672 unop( Iop_32UtoV128,loadLE(Ity_I32, mkexpr(addr)) )
sewardjc2feffc2004-12-08 12:31:22 +00009673 );
9674 DIP("movd %s, %s\n", dis_buf, nameXMMReg(gregOfRM(modrm)));
9675 }
9676 goto decode_success;
9677 }
9678
9679 /* 66 0F 7E = MOVD from xmm low 1/4 to r/m32. */
9680 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x7E) {
9681 modrm = getIByte(delta+2);
9682 if (epartIsReg(modrm)) {
9683 delta += 2+1;
9684 putIReg( 4, eregOfRM(modrm),
9685 getXMMRegLane32(gregOfRM(modrm), 0) );
9686 DIP("movd %s, %s\n",
9687 nameXMMReg(gregOfRM(modrm)), nameIReg(4,eregOfRM(modrm)));
9688 } else {
9689 addr = disAMode( &alen, sorb, delta+2, dis_buf );
9690 delta += 2+alen;
9691 storeLE( mkexpr(addr),
9692 getXMMRegLane32(gregOfRM(modrm), 0) );
9693 DIP("movd %s, %s\n", nameXMMReg(gregOfRM(modrm)), dis_buf);
9694 }
9695 goto decode_success;
9696 }
9697
9698 /* 66 0F 7F = MOVDQA -- move from G (xmm) to E (mem or xmm). */
9699 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x7F) {
9700 modrm = getIByte(delta+2);
9701 if (epartIsReg(modrm)) {
9702 delta += 2+1;
9703 putXMMReg( eregOfRM(modrm),
9704 getXMMReg(gregOfRM(modrm)) );
9705 DIP("movdqa %s, %s\n", nameXMMReg(gregOfRM(modrm)),
9706 nameXMMReg(eregOfRM(modrm)));
9707 } else {
9708 addr = disAMode( &alen, sorb, delta+2, dis_buf );
9709 delta += 2+alen;
9710 storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) );
9711 DIP("movdqa %s, %s\n", nameXMMReg(gregOfRM(modrm)), dis_buf);
9712 }
9713 goto decode_success;
9714 }
9715
9716 /* F3 0F 6F = MOVDQU -- move from E (mem or xmm) to G (xmm). */
9717 /* Unfortunately can't simply use the MOVDQA case since the
9718 prefix lengths are different (66 vs F3) */
9719 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x6F) {
9720 vassert(sz == 4);
9721 modrm = getIByte(delta+3);
9722 if (epartIsReg(modrm)) {
9723 putXMMReg( gregOfRM(modrm),
9724 getXMMReg( eregOfRM(modrm) ));
9725 DIP("movdqu %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9726 nameXMMReg(gregOfRM(modrm)));
9727 delta += 3+1;
9728 } else {
9729 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
9730 putXMMReg( gregOfRM(modrm),
9731 loadLE(Ity_V128, mkexpr(addr)) );
9732 DIP("movdqu %s,%s\n", dis_buf,
9733 nameXMMReg(gregOfRM(modrm)));
9734 delta += 3+alen;
9735 }
9736 goto decode_success;
9737 }
9738
9739 /* F3 0F 7F = MOVDQU -- move from G (xmm) to E (mem or xmm). */
9740 /* Unfortunately can't simply use the MOVDQA case since the
9741 prefix lengths are different (66 vs F3) */
9742 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x7F) {
9743 vassert(sz == 4);
9744 modrm = getIByte(delta+3);
9745 if (epartIsReg(modrm)) {
9746 delta += 3+1;
9747 putXMMReg( eregOfRM(modrm),
9748 getXMMReg(gregOfRM(modrm)) );
9749 DIP("movdqu %s, %s\n", nameXMMReg(gregOfRM(modrm)),
9750 nameXMMReg(eregOfRM(modrm)));
9751 } else {
9752 addr = disAMode( &alen, sorb, delta+3, dis_buf );
9753 delta += 3+alen;
9754 storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) );
9755 DIP("movdqu %s, %s\n", nameXMMReg(gregOfRM(modrm)), dis_buf);
9756 }
9757 goto decode_success;
9758 }
9759
9760 /* F2 0F D6 = MOVDQ2Q -- move from E (lo half xmm, not mem) to G (mmx). */
9761 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0xD6) {
9762 vassert(sz == 4);
9763 modrm = getIByte(delta+3);
9764 if (epartIsReg(modrm)) {
9765 do_MMX_preamble();
9766 putMMXReg( gregOfRM(modrm),
9767 getXMMRegLane64( eregOfRM(modrm), 0 ));
9768 DIP("movdq2q %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9769 nameMMXReg(gregOfRM(modrm)));
9770 delta += 3+1;
9771 goto decode_success;
9772 } else {
9773 /* fall through, apparently no mem case for this insn */
9774 }
9775 }
9776
9777 /* 66 0F 16 = MOVHPD -- move from mem to high half of XMM. */
9778 /* These seems identical to MOVHPS. This instruction encoding is
9779 completely crazy. */
9780 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x16) {
9781 modrm = getIByte(delta+2);
9782 if (epartIsReg(modrm)) {
9783 /* fall through; apparently reg-reg is not possible */
9784 } else {
9785 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9786 delta += 2+alen;
9787 putXMMRegLane64( gregOfRM(modrm), 1/*upper lane*/,
9788 loadLE(Ity_I64, mkexpr(addr)) );
9789 DIP("movhpd %s,%s\n", dis_buf,
9790 nameXMMReg( gregOfRM(modrm) ));
9791 goto decode_success;
9792 }
9793 }
9794
9795 /* 66 0F 17 = MOVHPD -- move from high half of XMM to mem. */
9796 /* Again, this seems identical to MOVHPS. */
9797 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x17) {
9798 if (!epartIsReg(insn[2])) {
9799 delta += 2;
9800 addr = disAMode ( &alen, sorb, delta, dis_buf );
9801 delta += alen;
9802 storeLE( mkexpr(addr),
9803 getXMMRegLane64( gregOfRM(insn[2]),
9804 1/*upper lane*/ ) );
9805 DIP("movhpd %s,%s\n", nameXMMReg( gregOfRM(insn[2]) ),
9806 dis_buf);
9807 goto decode_success;
9808 }
9809 /* else fall through */
9810 }
9811
9812 /* 66 0F 12 = MOVLPD -- move from mem to low half of XMM. */
9813 /* Identical to MOVLPS ? */
9814 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x12) {
9815 modrm = getIByte(delta+2);
9816 if (epartIsReg(modrm)) {
9817 /* fall through; apparently reg-reg is not possible */
9818 } else {
9819 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9820 delta += 2+alen;
9821 putXMMRegLane64( gregOfRM(modrm), 0/*lower lane*/,
9822 loadLE(Ity_I64, mkexpr(addr)) );
9823 DIP("movlpd %s, %s\n",
9824 dis_buf, nameXMMReg( gregOfRM(modrm) ));
9825 goto decode_success;
9826 }
9827 }
9828
9829 /* 66 0F 13 = MOVLPD -- move from low half of XMM to mem. */
9830 /* Identical to MOVLPS ? */
9831 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x13) {
9832 if (!epartIsReg(insn[2])) {
9833 delta += 2;
9834 addr = disAMode ( &alen, sorb, delta, dis_buf );
9835 delta += alen;
9836 storeLE( mkexpr(addr),
9837 getXMMRegLane64( gregOfRM(insn[2]),
9838 0/*lower lane*/ ) );
9839 DIP("movlpd %s, %s\n", nameXMMReg( gregOfRM(insn[2]) ),
9840 dis_buf);
9841 goto decode_success;
9842 }
9843 /* else fall through */
9844 }
9845
9846 /* 66 0F 50 = MOVMSKPD - move 2 sign bits from 2 x F64 in xmm(E) to
9847 2 lowest bits of ireg(G) */
9848 if (insn[0] == 0x0F && insn[1] == 0x50) {
9849 modrm = getIByte(delta+2);
9850 if (sz == 2 && epartIsReg(modrm)) {
9851 Int src;
9852 t0 = newTemp(Ity_I32);
9853 t1 = newTemp(Ity_I32);
9854 delta += 2+1;
9855 src = eregOfRM(modrm);
9856 assign( t0, binop( Iop_And32,
9857 binop(Iop_Shr32, getXMMRegLane32(src,1), mkU8(31)),
9858 mkU32(1) ));
9859 assign( t1, binop( Iop_And32,
9860 binop(Iop_Shr32, getXMMRegLane32(src,3), mkU8(30)),
9861 mkU32(2) ));
9862 putIReg(4, gregOfRM(modrm),
9863 binop(Iop_Or32, mkexpr(t0), mkexpr(t1))
9864 );
9865 DIP("movmskpd %s,%s\n", nameXMMReg(src),
9866 nameIReg(4, gregOfRM(modrm)));
9867 goto decode_success;
9868 }
9869 /* else fall through */
9870 }
9871
sewardjd71ba832006-12-27 01:15:29 +00009872 /* 66 0F F7 = MASKMOVDQU -- store selected bytes of double quadword */
9873 if (insn[0] == 0x0F && insn[1] == 0xF7) {
9874 modrm = getIByte(delta+2);
9875 if (sz == 2 && epartIsReg(modrm)) {
9876 IRTemp regD = newTemp(Ity_V128);
9877 IRTemp mask = newTemp(Ity_V128);
9878 IRTemp olddata = newTemp(Ity_V128);
9879 IRTemp newdata = newTemp(Ity_V128);
9880 addr = newTemp(Ity_I32);
9881
9882 assign( addr, handleSegOverride( sorb, getIReg(4, R_EDI) ));
9883 assign( regD, getXMMReg( gregOfRM(modrm) ));
9884
9885 /* Unfortunately can't do the obvious thing with SarN8x16
9886 here since that can't be re-emitted as SSE2 code - no such
9887 insn. */
9888 assign(
9889 mask,
9890 binop(Iop_64HLtoV128,
9891 binop(Iop_SarN8x8,
9892 getXMMRegLane64( eregOfRM(modrm), 1 ),
9893 mkU8(7) ),
9894 binop(Iop_SarN8x8,
9895 getXMMRegLane64( eregOfRM(modrm), 0 ),
9896 mkU8(7) ) ));
9897 assign( olddata, loadLE( Ity_V128, mkexpr(addr) ));
9898 assign( newdata,
9899 binop(Iop_OrV128,
9900 binop(Iop_AndV128,
9901 mkexpr(regD),
9902 mkexpr(mask) ),
9903 binop(Iop_AndV128,
9904 mkexpr(olddata),
9905 unop(Iop_NotV128, mkexpr(mask)))) );
9906 storeLE( mkexpr(addr), mkexpr(newdata) );
9907
9908 delta += 2+1;
9909 DIP("maskmovdqu %s,%s\n", nameXMMReg( eregOfRM(modrm) ),
9910 nameXMMReg( gregOfRM(modrm) ) );
9911 goto decode_success;
9912 }
9913 /* else fall through */
9914 }
9915
sewardjc2feffc2004-12-08 12:31:22 +00009916 /* 66 0F E7 = MOVNTDQ -- for us, just a plain SSE store. */
9917 if (insn[0] == 0x0F && insn[1] == 0xE7) {
9918 modrm = getIByte(delta+2);
9919 if (sz == 2 && !epartIsReg(modrm)) {
9920 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9921 storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) );
9922 DIP("movntdq %s,%s\n", dis_buf,
9923 nameXMMReg(gregOfRM(modrm)));
9924 delta += 2+alen;
9925 goto decode_success;
9926 }
9927 /* else fall through */
9928 }
9929
9930 /* 0F C3 = MOVNTI -- for us, just a plain ireg store. */
9931 if (insn[0] == 0x0F && insn[1] == 0xC3) {
9932 vassert(sz == 4);
9933 modrm = getIByte(delta+2);
9934 if (!epartIsReg(modrm)) {
9935 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9936 storeLE( mkexpr(addr), getIReg(4, gregOfRM(modrm)) );
9937 DIP("movnti %s,%s\n", dis_buf,
9938 nameIReg(4, gregOfRM(modrm)));
9939 delta += 2+alen;
9940 goto decode_success;
9941 }
9942 /* else fall through */
9943 }
9944
sewardj95535fe2004-12-15 17:42:58 +00009945 /* 66 0F D6 = MOVQ -- move 64 bits from G (lo half xmm) to E (mem
9946 or lo half xmm). */
sewardj9ee82862004-12-14 01:16:59 +00009947 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD6) {
9948 modrm = getIByte(delta+2);
9949 if (epartIsReg(modrm)) {
9950 /* fall through, awaiting test case */
sewardj6d7ccd52005-05-14 02:04:12 +00009951 /* dst: lo half copied, hi half zeroed */
sewardj9ee82862004-12-14 01:16:59 +00009952 } else {
9953 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9954 storeLE( mkexpr(addr),
9955 getXMMRegLane64( gregOfRM(modrm), 0 ));
9956 DIP("movq %s,%s\n", nameXMMReg(gregOfRM(modrm)), dis_buf );
9957 delta += 2+alen;
9958 goto decode_success;
9959 }
9960 }
9961
sewardjc2feffc2004-12-08 12:31:22 +00009962 /* F3 0F D6 = MOVQ2DQ -- move from E (mmx) to G (lo half xmm, zero
9963 hi half). */
9964 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0xD6) {
9965 vassert(sz == 4);
9966 modrm = getIByte(delta+3);
9967 if (epartIsReg(modrm)) {
9968 do_MMX_preamble();
9969 putXMMReg( gregOfRM(modrm),
sewardjf0c1c582005-02-07 23:47:38 +00009970 unop(Iop_64UtoV128, getMMXReg( eregOfRM(modrm) )) );
sewardjc2feffc2004-12-08 12:31:22 +00009971 DIP("movq2dq %s,%s\n", nameMMXReg(eregOfRM(modrm)),
9972 nameXMMReg(gregOfRM(modrm)));
9973 delta += 3+1;
9974 goto decode_success;
9975 } else {
9976 /* fall through, apparently no mem case for this insn */
9977 }
9978 }
9979
sewardj95535fe2004-12-15 17:42:58 +00009980 /* F3 0F 7E = MOVQ -- move 64 bits from E (mem or lo half xmm) to
sewardj6d7ccd52005-05-14 02:04:12 +00009981 G (lo half xmm). Upper half of G is zeroed out. */
sewardj95535fe2004-12-15 17:42:58 +00009982 /* F2 0F 10 = MOVSD -- move 64 bits from E (mem or lo half xmm) to
9983 G (lo half xmm). If E is mem, upper half of G is zeroed out.
sewardj6d7ccd52005-05-14 02:04:12 +00009984 If E is reg, upper half of G is unchanged. */
sewardj95535fe2004-12-15 17:42:58 +00009985 if ((insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x10)
9986 || (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x7E)) {
sewardjc2feffc2004-12-08 12:31:22 +00009987 vassert(sz == 4);
9988 modrm = getIByte(delta+3);
9989 if (epartIsReg(modrm)) {
9990 putXMMRegLane64( gregOfRM(modrm), 0,
9991 getXMMRegLane64( eregOfRM(modrm), 0 ));
sewardj6d7ccd52005-05-14 02:04:12 +00009992 if (insn[0] == 0xF3/*MOVQ*/) {
9993 /* zero bits 127:64 */
9994 putXMMRegLane64( gregOfRM(modrm), 1, mkU64(0) );
9995 }
sewardjc2feffc2004-12-08 12:31:22 +00009996 DIP("movsd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9997 nameXMMReg(gregOfRM(modrm)));
9998 delta += 3+1;
9999 } else {
10000 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
sewardjad50db02005-04-06 01:45:44 +000010001 /* zero bits 127:64 */
sewardj5bf1fd42005-04-06 01:11:08 +000010002 putXMMRegLane64( gregOfRM(modrm), 1, mkU64(0) );
sewardjad50db02005-04-06 01:45:44 +000010003 /* write bits 63:0 */
sewardjc2feffc2004-12-08 12:31:22 +000010004 putXMMRegLane64( gregOfRM(modrm), 0,
10005 loadLE(Ity_I64, mkexpr(addr)) );
10006 DIP("movsd %s,%s\n", dis_buf,
10007 nameXMMReg(gregOfRM(modrm)));
10008 delta += 3+alen;
10009 }
10010 goto decode_success;
10011 }
10012
10013 /* F2 0F 11 = MOVSD -- move 64 bits from G (lo half xmm) to E (mem
10014 or lo half xmm). */
10015 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x11) {
10016 vassert(sz == 4);
10017 modrm = getIByte(delta+3);
10018 if (epartIsReg(modrm)) {
10019 /* fall through, we don't yet have a test case */
10020 } else {
10021 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
10022 storeLE( mkexpr(addr),
sewardj519d66f2004-12-15 11:57:58 +000010023 getXMMRegLane64(gregOfRM(modrm), 0) );
10024 DIP("movsd %s,%s\n", nameXMMReg(gregOfRM(modrm)),
sewardjc2feffc2004-12-08 12:31:22 +000010025 dis_buf);
10026 delta += 3+alen;
10027 goto decode_success;
10028 }
10029 }
sewardjfd226452004-12-07 19:02:18 +000010030
sewardj008754b2004-12-08 14:37:10 +000010031 /* 66 0F 59 = MULPD -- mul 64Fx2 from R/M to R */
10032 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x59) {
10033 delta = dis_SSE_E_to_G_all( sorb, delta+2, "mulpd", Iop_Mul64Fx2 );
10034 goto decode_success;
10035 }
10036
10037 /* F2 0F 59 = MULSD -- mul 64F0x2 from R/M to R */
10038 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x59) {
10039 vassert(sz == 4);
10040 delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "mulsd", Iop_Mul64F0x2 );
10041 goto decode_success;
10042 }
10043
10044 /* 66 0F 56 = ORPD -- G = G and E */
10045 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x56) {
sewardjf0c1c582005-02-07 23:47:38 +000010046 delta = dis_SSE_E_to_G_all( sorb, delta+2, "orpd", Iop_OrV128 );
sewardj008754b2004-12-08 14:37:10 +000010047 goto decode_success;
10048 }
10049
10050 /* 66 0F C6 /r ib = SHUFPD -- shuffle packed F64s */
10051 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xC6) {
10052 Int select;
10053 IRTemp sV = newTemp(Ity_V128);
10054 IRTemp dV = newTemp(Ity_V128);
10055 IRTemp s1 = newTemp(Ity_I64);
10056 IRTemp s0 = newTemp(Ity_I64);
10057 IRTemp d1 = newTemp(Ity_I64);
10058 IRTemp d0 = newTemp(Ity_I64);
10059
10060 modrm = insn[2];
10061 assign( dV, getXMMReg(gregOfRM(modrm)) );
10062
10063 if (epartIsReg(modrm)) {
10064 assign( sV, getXMMReg(eregOfRM(modrm)) );
10065 select = (Int)insn[3];
10066 delta += 2+2;
10067 DIP("shufpd $%d,%s,%s\n", select,
10068 nameXMMReg(eregOfRM(modrm)),
10069 nameXMMReg(gregOfRM(modrm)));
10070 } else {
10071 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10072 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
10073 select = (Int)insn[2+alen];
10074 delta += 3+alen;
10075 DIP("shufpd $%d,%s,%s\n", select,
10076 dis_buf,
10077 nameXMMReg(gregOfRM(modrm)));
10078 }
10079
sewardjf0c1c582005-02-07 23:47:38 +000010080 assign( d1, unop(Iop_V128HIto64, mkexpr(dV)) );
10081 assign( d0, unop(Iop_V128to64, mkexpr(dV)) );
10082 assign( s1, unop(Iop_V128HIto64, mkexpr(sV)) );
10083 assign( s0, unop(Iop_V128to64, mkexpr(sV)) );
sewardj008754b2004-12-08 14:37:10 +000010084
10085# define SELD(n) mkexpr((n)==0 ? d0 : d1)
10086# define SELS(n) mkexpr((n)==0 ? s0 : s1)
10087
10088 putXMMReg(
10089 gregOfRM(modrm),
sewardjf0c1c582005-02-07 23:47:38 +000010090 binop(Iop_64HLtoV128, SELS((select>>1)&1), SELD((select>>0)&1) )
sewardj008754b2004-12-08 14:37:10 +000010091 );
10092
10093# undef SELD
10094# undef SELS
10095
10096 goto decode_success;
10097 }
10098
10099 /* 66 0F 51 = SQRTPD -- approx sqrt 64Fx2 from R/M to R */
10100 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x51) {
10101 delta = dis_SSE_E_to_G_unary_all( sorb, delta+2,
10102 "sqrtpd", Iop_Sqrt64Fx2 );
10103 goto decode_success;
10104 }
10105
10106 /* F2 0F 51 = SQRTSD -- approx sqrt 64F0x2 from R/M to R */
10107 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x51) {
10108 vassert(sz == 4);
10109 delta = dis_SSE_E_to_G_unary_lo64( sorb, delta+3,
10110 "sqrtsd", Iop_Sqrt64F0x2 );
10111 goto decode_success;
10112 }
10113
10114 /* 66 0F 5C = SUBPD -- sub 64Fx2 from R/M to R */
10115 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5C) {
10116 delta = dis_SSE_E_to_G_all( sorb, delta+2, "subpd", Iop_Sub64Fx2 );
10117 goto decode_success;
10118 }
10119
10120 /* F2 0F 5C = SUBSD -- sub 64F0x2 from R/M to R */
10121 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x5C) {
10122 vassert(sz == 4);
10123 delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "subsd", Iop_Sub64F0x2 );
10124 goto decode_success;
10125 }
10126
10127 /* 66 0F 15 = UNPCKHPD -- unpack and interleave high part F64s */
10128 /* 66 0F 14 = UNPCKLPD -- unpack and interleave low part F64s */
10129 /* These just appear to be special cases of SHUFPS */
10130 if (sz == 2 && insn[0] == 0x0F && (insn[1] == 0x15 || insn[1] == 0x14)) {
10131 IRTemp s1 = newTemp(Ity_I64);
10132 IRTemp s0 = newTemp(Ity_I64);
10133 IRTemp d1 = newTemp(Ity_I64);
10134 IRTemp d0 = newTemp(Ity_I64);
10135 IRTemp sV = newTemp(Ity_V128);
10136 IRTemp dV = newTemp(Ity_V128);
sewardj2d49b432005-02-01 00:37:06 +000010137 Bool hi = toBool(insn[1] == 0x15);
sewardj008754b2004-12-08 14:37:10 +000010138
10139 modrm = insn[2];
10140 assign( dV, getXMMReg(gregOfRM(modrm)) );
10141
10142 if (epartIsReg(modrm)) {
10143 assign( sV, getXMMReg(eregOfRM(modrm)) );
10144 delta += 2+1;
10145 DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
10146 nameXMMReg(eregOfRM(modrm)),
10147 nameXMMReg(gregOfRM(modrm)));
10148 } else {
10149 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10150 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
10151 delta += 2+alen;
10152 DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
10153 dis_buf,
10154 nameXMMReg(gregOfRM(modrm)));
10155 }
10156
sewardjf0c1c582005-02-07 23:47:38 +000010157 assign( d1, unop(Iop_V128HIto64, mkexpr(dV)) );
10158 assign( d0, unop(Iop_V128to64, mkexpr(dV)) );
10159 assign( s1, unop(Iop_V128HIto64, mkexpr(sV)) );
10160 assign( s0, unop(Iop_V128to64, mkexpr(sV)) );
sewardj008754b2004-12-08 14:37:10 +000010161
10162 if (hi) {
10163 putXMMReg( gregOfRM(modrm),
sewardjf0c1c582005-02-07 23:47:38 +000010164 binop(Iop_64HLtoV128, mkexpr(s1), mkexpr(d1)) );
sewardj008754b2004-12-08 14:37:10 +000010165 } else {
10166 putXMMReg( gregOfRM(modrm),
sewardjf0c1c582005-02-07 23:47:38 +000010167 binop(Iop_64HLtoV128, mkexpr(s0), mkexpr(d0)) );
sewardj008754b2004-12-08 14:37:10 +000010168 }
10169
10170 goto decode_success;
10171 }
10172
10173 /* 66 0F 57 = XORPD -- G = G and E */
10174 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x57) {
sewardjf0c1c582005-02-07 23:47:38 +000010175 delta = dis_SSE_E_to_G_all( sorb, delta+2, "xorpd", Iop_XorV128 );
sewardj008754b2004-12-08 14:37:10 +000010176 goto decode_success;
10177 }
sewardj636ad762004-12-07 11:16:04 +000010178
sewardj164f9272004-12-09 00:39:32 +000010179 /* 66 0F 6B = PACKSSDW */
10180 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x6B) {
10181 delta = dis_SSEint_E_to_G( sorb, delta+2,
10182 "packssdw", Iop_QNarrow32Sx4, True );
10183 goto decode_success;
10184 }
10185
10186 /* 66 0F 63 = PACKSSWB */
10187 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x63) {
10188 delta = dis_SSEint_E_to_G( sorb, delta+2,
10189 "packsswb", Iop_QNarrow16Sx8, True );
10190 goto decode_success;
10191 }
10192
10193 /* 66 0F 67 = PACKUSWB */
10194 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x67) {
10195 delta = dis_SSEint_E_to_G( sorb, delta+2,
10196 "packuswb", Iop_QNarrow16Ux8, True );
10197 goto decode_success;
10198 }
10199
10200 /* 66 0F FC = PADDB */
10201 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xFC) {
10202 delta = dis_SSEint_E_to_G( sorb, delta+2,
10203 "paddb", Iop_Add8x16, False );
10204 goto decode_success;
10205 }
10206
10207 /* 66 0F FE = PADDD */
10208 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xFE) {
10209 delta = dis_SSEint_E_to_G( sorb, delta+2,
10210 "paddd", Iop_Add32x4, False );
10211 goto decode_success;
10212 }
10213
10214 /* ***--- this is an MMX class insn introduced in SSE2 ---*** */
10215 /* 0F D4 = PADDQ -- add 64x1 */
10216 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xD4) {
10217 do_MMX_preamble();
10218 delta = dis_MMXop_regmem_to_reg (
10219 sorb, delta+2, insn[1], "paddq", False );
10220 goto decode_success;
10221 }
10222
10223 /* 66 0F D4 = PADDQ */
10224 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD4) {
10225 delta = dis_SSEint_E_to_G( sorb, delta+2,
10226 "paddq", Iop_Add64x2, False );
10227 goto decode_success;
10228 }
10229
10230 /* 66 0F FD = PADDW */
10231 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xFD) {
10232 delta = dis_SSEint_E_to_G( sorb, delta+2,
10233 "paddw", Iop_Add16x8, False );
10234 goto decode_success;
10235 }
10236
10237 /* 66 0F EC = PADDSB */
10238 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xEC) {
10239 delta = dis_SSEint_E_to_G( sorb, delta+2,
10240 "paddsb", Iop_QAdd8Sx16, False );
10241 goto decode_success;
10242 }
10243
10244 /* 66 0F ED = PADDSW */
10245 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xED) {
10246 delta = dis_SSEint_E_to_G( sorb, delta+2,
10247 "paddsw", Iop_QAdd16Sx8, False );
10248 goto decode_success;
10249 }
10250
10251 /* 66 0F DC = PADDUSB */
10252 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDC) {
10253 delta = dis_SSEint_E_to_G( sorb, delta+2,
10254 "paddusb", Iop_QAdd8Ux16, False );
10255 goto decode_success;
10256 }
10257
10258 /* 66 0F DD = PADDUSW */
10259 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDD) {
10260 delta = dis_SSEint_E_to_G( sorb, delta+2,
10261 "paddusw", Iop_QAdd16Ux8, False );
10262 goto decode_success;
10263 }
10264
10265 /* 66 0F DB = PAND */
10266 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDB) {
sewardjf0c1c582005-02-07 23:47:38 +000010267 delta = dis_SSE_E_to_G_all( sorb, delta+2, "pand", Iop_AndV128 );
sewardj164f9272004-12-09 00:39:32 +000010268 goto decode_success;
10269 }
10270
10271 /* 66 0F DF = PANDN */
10272 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDF) {
sewardjf0c1c582005-02-07 23:47:38 +000010273 delta = dis_SSE_E_to_G_all_invG( sorb, delta+2, "pandn", Iop_AndV128 );
sewardj164f9272004-12-09 00:39:32 +000010274 goto decode_success;
10275 }
10276
10277 /* 66 0F E0 = PAVGB */
10278 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE0) {
10279 delta = dis_SSEint_E_to_G( sorb, delta+2,
10280 "pavgb", Iop_Avg8Ux16, False );
10281 goto decode_success;
10282 }
10283
10284 /* 66 0F E3 = PAVGW */
10285 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE3) {
10286 delta = dis_SSEint_E_to_G( sorb, delta+2,
10287 "pavgw", Iop_Avg16Ux8, False );
10288 goto decode_success;
10289 }
10290
sewardje5854d62004-12-09 03:44:34 +000010291 /* 66 0F 74 = PCMPEQB */
10292 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x74) {
10293 delta = dis_SSEint_E_to_G( sorb, delta+2,
10294 "pcmpeqb", Iop_CmpEQ8x16, False );
10295 goto decode_success;
10296 }
10297
10298 /* 66 0F 76 = PCMPEQD */
10299 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x76) {
10300 delta = dis_SSEint_E_to_G( sorb, delta+2,
10301 "pcmpeqd", Iop_CmpEQ32x4, False );
10302 goto decode_success;
10303 }
10304
10305 /* 66 0F 75 = PCMPEQW */
10306 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x75) {
10307 delta = dis_SSEint_E_to_G( sorb, delta+2,
10308 "pcmpeqw", Iop_CmpEQ16x8, False );
10309 goto decode_success;
10310 }
10311
10312 /* 66 0F 64 = PCMPGTB */
10313 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x64) {
10314 delta = dis_SSEint_E_to_G( sorb, delta+2,
10315 "pcmpgtb", Iop_CmpGT8Sx16, False );
10316 goto decode_success;
10317 }
10318
10319 /* 66 0F 66 = PCMPGTD */
10320 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x66) {
10321 delta = dis_SSEint_E_to_G( sorb, delta+2,
10322 "pcmpgtd", Iop_CmpGT32Sx4, False );
10323 goto decode_success;
10324 }
10325
10326 /* 66 0F 65 = PCMPGTW */
10327 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x65) {
10328 delta = dis_SSEint_E_to_G( sorb, delta+2,
10329 "pcmpgtw", Iop_CmpGT16Sx8, False );
10330 goto decode_success;
10331 }
10332
10333 /* 66 0F C5 = PEXTRW -- extract 16-bit field from xmm(E) and put
10334 zero-extend of it in ireg(G). */
10335 if (insn[0] == 0x0F && insn[1] == 0xC5) {
10336 modrm = insn[2];
10337 if (sz == 2 && epartIsReg(modrm)) {
10338 t5 = newTemp(Ity_V128);
10339 t4 = newTemp(Ity_I16);
10340 assign(t5, getXMMReg(eregOfRM(modrm)));
10341 breakup128to32s( t5, &t3, &t2, &t1, &t0 );
10342 switch (insn[3] & 7) {
10343 case 0: assign(t4, unop(Iop_32to16, mkexpr(t0))); break;
10344 case 1: assign(t4, unop(Iop_32HIto16, mkexpr(t0))); break;
10345 case 2: assign(t4, unop(Iop_32to16, mkexpr(t1))); break;
10346 case 3: assign(t4, unop(Iop_32HIto16, mkexpr(t1))); break;
10347 case 4: assign(t4, unop(Iop_32to16, mkexpr(t2))); break;
10348 case 5: assign(t4, unop(Iop_32HIto16, mkexpr(t2))); break;
10349 case 6: assign(t4, unop(Iop_32to16, mkexpr(t3))); break;
10350 case 7: assign(t4, unop(Iop_32HIto16, mkexpr(t3))); break;
sewardjba89f4c2005-04-07 17:31:27 +000010351 default: vassert(0); /*NOTREACHED*/
sewardje5854d62004-12-09 03:44:34 +000010352 }
10353 putIReg(4, gregOfRM(modrm), unop(Iop_16Uto32, mkexpr(t4)));
10354 DIP("pextrw $%d,%s,%s\n",
10355 (Int)insn[3], nameXMMReg(eregOfRM(modrm)),
10356 nameIReg(4,gregOfRM(modrm)));
10357 delta += 4;
10358 goto decode_success;
10359 }
10360 /* else fall through */
10361 }
10362
10363 /* 66 0F C4 = PINSRW -- get 16 bits from E(mem or low half ireg) and
10364 put it into the specified lane of xmm(G). */
10365 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xC4) {
10366 Int lane;
10367 t4 = newTemp(Ity_I16);
10368 modrm = insn[2];
10369
10370 if (epartIsReg(modrm)) {
10371 assign(t4, getIReg(2, eregOfRM(modrm)));
sewardjaac7e082005-03-17 14:03:46 +000010372 delta += 3+1;
10373 lane = insn[3+1-1];
sewardje5854d62004-12-09 03:44:34 +000010374 DIP("pinsrw $%d,%s,%s\n", (Int)lane,
10375 nameIReg(2,eregOfRM(modrm)),
10376 nameXMMReg(gregOfRM(modrm)));
10377 } else {
sewardjaac7e082005-03-17 14:03:46 +000010378 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10379 delta += 3+alen;
10380 lane = insn[3+alen-1];
10381 assign(t4, loadLE(Ity_I16, mkexpr(addr)));
10382 DIP("pinsrw $%d,%s,%s\n", (Int)lane,
10383 dis_buf,
10384 nameXMMReg(gregOfRM(modrm)));
sewardje5854d62004-12-09 03:44:34 +000010385 }
10386
10387 putXMMRegLane16( gregOfRM(modrm), lane & 7, mkexpr(t4) );
10388 goto decode_success;
10389 }
10390
sewardjb8a3dea2005-10-04 20:00:49 +000010391 /* 66 0F F5 = PMADDWD -- Multiply and add packed integers from
10392 E(xmm or mem) to G(xmm) */
10393 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF5) {
10394 IRTemp s1V = newTemp(Ity_V128);
10395 IRTemp s2V = newTemp(Ity_V128);
10396 IRTemp dV = newTemp(Ity_V128);
10397 IRTemp s1Hi = newTemp(Ity_I64);
10398 IRTemp s1Lo = newTemp(Ity_I64);
10399 IRTemp s2Hi = newTemp(Ity_I64);
10400 IRTemp s2Lo = newTemp(Ity_I64);
10401 IRTemp dHi = newTemp(Ity_I64);
10402 IRTemp dLo = newTemp(Ity_I64);
10403 modrm = insn[2];
10404 if (epartIsReg(modrm)) {
10405 assign( s1V, getXMMReg(eregOfRM(modrm)) );
10406 delta += 2+1;
10407 DIP("pmaddwd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
10408 nameXMMReg(gregOfRM(modrm)));
10409 } else {
10410 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10411 assign( s1V, loadLE(Ity_V128, mkexpr(addr)) );
10412 delta += 2+alen;
10413 DIP("pmaddwd %s,%s\n", dis_buf,
10414 nameXMMReg(gregOfRM(modrm)));
10415 }
10416 assign( s2V, getXMMReg(gregOfRM(modrm)) );
10417 assign( s1Hi, unop(Iop_V128HIto64, mkexpr(s1V)) );
10418 assign( s1Lo, unop(Iop_V128to64, mkexpr(s1V)) );
10419 assign( s2Hi, unop(Iop_V128HIto64, mkexpr(s2V)) );
10420 assign( s2Lo, unop(Iop_V128to64, mkexpr(s2V)) );
10421 assign( dHi, mkIRExprCCall(
10422 Ity_I64, 0/*regparms*/,
10423 "x86g_calculate_mmx_pmaddwd",
10424 &x86g_calculate_mmx_pmaddwd,
10425 mkIRExprVec_2( mkexpr(s1Hi), mkexpr(s2Hi))
10426 ));
10427 assign( dLo, mkIRExprCCall(
10428 Ity_I64, 0/*regparms*/,
10429 "x86g_calculate_mmx_pmaddwd",
10430 &x86g_calculate_mmx_pmaddwd,
10431 mkIRExprVec_2( mkexpr(s1Lo), mkexpr(s2Lo))
10432 ));
10433 assign( dV, binop(Iop_64HLtoV128, mkexpr(dHi), mkexpr(dLo))) ;
10434 putXMMReg(gregOfRM(modrm), mkexpr(dV));
10435 goto decode_success;
10436 }
10437
sewardje5854d62004-12-09 03:44:34 +000010438 /* 66 0F EE = PMAXSW -- 16x8 signed max */
10439 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xEE) {
10440 delta = dis_SSEint_E_to_G( sorb, delta+2,
10441 "pmaxsw", Iop_Max16Sx8, False );
10442 goto decode_success;
10443 }
10444
10445 /* 66 0F DE = PMAXUB -- 8x16 unsigned max */
10446 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDE) {
10447 delta = dis_SSEint_E_to_G( sorb, delta+2,
10448 "pmaxub", Iop_Max8Ux16, False );
10449 goto decode_success;
10450 }
10451
10452 /* 66 0F EA = PMINSW -- 16x8 signed min */
10453 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xEA) {
10454 delta = dis_SSEint_E_to_G( sorb, delta+2,
10455 "pminsw", Iop_Min16Sx8, False );
10456 goto decode_success;
10457 }
10458
10459 /* 66 0F DA = PMINUB -- 8x16 unsigned min */
10460 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDA) {
10461 delta = dis_SSEint_E_to_G( sorb, delta+2,
10462 "pminub", Iop_Min8Ux16, False );
10463 goto decode_success;
10464 }
10465
10466 /* 66 0F D7 = PMOVMSKB -- extract sign bits from each of 16 lanes in
10467 xmm(G), turn them into a byte, and put zero-extend of it in
10468 ireg(G). Doing this directly is just too cumbersome; give up
10469 therefore and call a helper. */
10470 /* UInt x86g_calculate_sse_pmovmskb ( ULong w64hi, ULong w64lo ); */
10471 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD7) {
10472 modrm = insn[2];
10473 if (epartIsReg(modrm)) {
10474 t0 = newTemp(Ity_I64);
10475 t1 = newTemp(Ity_I64);
10476 assign(t0, getXMMRegLane64(eregOfRM(modrm), 0));
10477 assign(t1, getXMMRegLane64(eregOfRM(modrm), 1));
10478 t5 = newTemp(Ity_I32);
10479 assign(t5, mkIRExprCCall(
10480 Ity_I32, 0/*regparms*/,
10481 "x86g_calculate_sse_pmovmskb",
10482 &x86g_calculate_sse_pmovmskb,
sewardj28e5c832004-12-16 11:39:04 +000010483 mkIRExprVec_2( mkexpr(t1), mkexpr(t0) )));
sewardje5854d62004-12-09 03:44:34 +000010484 putIReg(4, gregOfRM(modrm), mkexpr(t5));
10485 DIP("pmovmskb %s,%s\n", nameXMMReg(eregOfRM(modrm)),
10486 nameIReg(4,gregOfRM(modrm)));
10487 delta += 3;
10488 goto decode_success;
10489 }
10490 /* else fall through */
10491 }
10492
10493 /* 66 0F E4 = PMULHUW -- 16x8 hi-half of unsigned widening multiply */
10494 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE4) {
10495 delta = dis_SSEint_E_to_G( sorb, delta+2,
10496 "pmulhuw", Iop_MulHi16Ux8, False );
10497 goto decode_success;
10498 }
10499
10500 /* 66 0F E5 = PMULHW -- 16x8 hi-half of signed widening multiply */
10501 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE5) {
10502 delta = dis_SSEint_E_to_G( sorb, delta+2,
10503 "pmulhw", Iop_MulHi16Sx8, False );
10504 goto decode_success;
10505 }
10506
10507 /* 66 0F D5 = PMULHL -- 16x8 multiply */
10508 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD5) {
10509 delta = dis_SSEint_E_to_G( sorb, delta+2,
10510 "pmullw", Iop_Mul16x8, False );
10511 goto decode_success;
10512 }
10513
10514 /* ***--- this is an MMX class insn introduced in SSE2 ---*** */
10515 /* 0F F4 = PMULUDQ -- unsigned widening multiply of 32-lanes 0 x
10516 0 to form 64-bit result */
10517 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xF4) {
10518 IRTemp sV = newTemp(Ity_I64);
10519 IRTemp dV = newTemp(Ity_I64);
10520 t1 = newTemp(Ity_I32);
10521 t0 = newTemp(Ity_I32);
10522 modrm = insn[2];
10523
10524 do_MMX_preamble();
10525 assign( dV, getMMXReg(gregOfRM(modrm)) );
10526
10527 if (epartIsReg(modrm)) {
10528 assign( sV, getMMXReg(eregOfRM(modrm)) );
10529 delta += 2+1;
10530 DIP("pmuludq %s,%s\n", nameMMXReg(eregOfRM(modrm)),
10531 nameMMXReg(gregOfRM(modrm)));
10532 } else {
10533 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10534 assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
10535 delta += 2+alen;
10536 DIP("pmuludq %s,%s\n", dis_buf,
10537 nameMMXReg(gregOfRM(modrm)));
10538 }
10539
10540 assign( t0, unop(Iop_64to32, mkexpr(dV)) );
10541 assign( t1, unop(Iop_64to32, mkexpr(sV)) );
10542 putMMXReg( gregOfRM(modrm),
10543 binop( Iop_MullU32, mkexpr(t0), mkexpr(t1) ) );
10544 goto decode_success;
10545 }
10546
10547 /* 66 0F F4 = PMULUDQ -- unsigned widening multiply of 32-lanes 0 x
10548 0 to form lower 64-bit half and lanes 2 x 2 to form upper 64-bit
10549 half */
10550 /* This is a really poor translation -- could be improved if
10551 performance critical */
10552 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF4) {
10553 IRTemp sV, dV;
10554 IRTemp s3, s2, s1, s0, d3, d2, d1, d0;
10555 sV = newTemp(Ity_V128);
10556 dV = newTemp(Ity_V128);
10557 s3 = s2 = s1 = s0 = d3 = d2 = d1 = d0 = IRTemp_INVALID;
10558 t1 = newTemp(Ity_I64);
10559 t0 = newTemp(Ity_I64);
10560 modrm = insn[2];
10561 assign( dV, getXMMReg(gregOfRM(modrm)) );
10562
10563 if (epartIsReg(modrm)) {
10564 assign( sV, getXMMReg(eregOfRM(modrm)) );
10565 delta += 2+1;
10566 DIP("pmuludq %s,%s\n", nameXMMReg(eregOfRM(modrm)),
10567 nameXMMReg(gregOfRM(modrm)));
10568 } else {
10569 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10570 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
10571 delta += 2+alen;
10572 DIP("pmuludq %s,%s\n", dis_buf,
10573 nameXMMReg(gregOfRM(modrm)));
10574 }
10575
10576 breakup128to32s( dV, &d3, &d2, &d1, &d0 );
10577 breakup128to32s( sV, &s3, &s2, &s1, &s0 );
10578
10579 assign( t0, binop( Iop_MullU32, mkexpr(d0), mkexpr(s0)) );
10580 putXMMRegLane64( gregOfRM(modrm), 0, mkexpr(t0) );
10581 assign( t1, binop( Iop_MullU32, mkexpr(d2), mkexpr(s2)) );
10582 putXMMRegLane64( gregOfRM(modrm), 1, mkexpr(t1) );
10583 goto decode_success;
10584 }
10585
10586 /* 66 0F EB = POR */
10587 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xEB) {
sewardjf0c1c582005-02-07 23:47:38 +000010588 delta = dis_SSE_E_to_G_all( sorb, delta+2, "por", Iop_OrV128 );
sewardje5854d62004-12-09 03:44:34 +000010589 goto decode_success;
10590 }
10591
sewardj7b5b9982005-10-04 11:43:37 +000010592 /* 66 0F F6 = PSADBW -- 2 x (8x8 -> 48 zeroes ++ u16) Sum Abs Diffs
10593 from E(xmm or mem) to G(xmm) */
10594 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF6) {
10595 IRTemp s1V = newTemp(Ity_V128);
10596 IRTemp s2V = newTemp(Ity_V128);
10597 IRTemp dV = newTemp(Ity_V128);
10598 IRTemp s1Hi = newTemp(Ity_I64);
10599 IRTemp s1Lo = newTemp(Ity_I64);
10600 IRTemp s2Hi = newTemp(Ity_I64);
10601 IRTemp s2Lo = newTemp(Ity_I64);
10602 IRTemp dHi = newTemp(Ity_I64);
10603 IRTemp dLo = newTemp(Ity_I64);
10604 modrm = insn[2];
10605 if (epartIsReg(modrm)) {
10606 assign( s1V, getXMMReg(eregOfRM(modrm)) );
10607 delta += 2+1;
10608 DIP("psadbw %s,%s\n", nameXMMReg(eregOfRM(modrm)),
10609 nameXMMReg(gregOfRM(modrm)));
10610 } else {
10611 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10612 assign( s1V, loadLE(Ity_V128, mkexpr(addr)) );
10613 delta += 2+alen;
10614 DIP("psadbw %s,%s\n", dis_buf,
10615 nameXMMReg(gregOfRM(modrm)));
10616 }
10617 assign( s2V, getXMMReg(gregOfRM(modrm)) );
10618 assign( s1Hi, unop(Iop_V128HIto64, mkexpr(s1V)) );
10619 assign( s1Lo, unop(Iop_V128to64, mkexpr(s1V)) );
10620 assign( s2Hi, unop(Iop_V128HIto64, mkexpr(s2V)) );
10621 assign( s2Lo, unop(Iop_V128to64, mkexpr(s2V)) );
10622 assign( dHi, mkIRExprCCall(
10623 Ity_I64, 0/*regparms*/,
10624 "x86g_calculate_mmx_psadbw",
10625 &x86g_calculate_mmx_psadbw,
10626 mkIRExprVec_2( mkexpr(s1Hi), mkexpr(s2Hi))
10627 ));
10628 assign( dLo, mkIRExprCCall(
10629 Ity_I64, 0/*regparms*/,
10630 "x86g_calculate_mmx_psadbw",
10631 &x86g_calculate_mmx_psadbw,
10632 mkIRExprVec_2( mkexpr(s1Lo), mkexpr(s2Lo))
10633 ));
10634 assign( dV, binop(Iop_64HLtoV128, mkexpr(dHi), mkexpr(dLo))) ;
10635 putXMMReg(gregOfRM(modrm), mkexpr(dV));
10636 goto decode_success;
10637 }
10638
sewardjb9fa69b2004-12-09 23:25:14 +000010639 /* 66 0F 70 = PSHUFD -- rearrange 4x32 from E(xmm or mem) to G(xmm) */
10640 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x70) {
10641 Int order;
10642 IRTemp sV, dV, s3, s2, s1, s0;
10643 s3 = s2 = s1 = s0 = IRTemp_INVALID;
10644 sV = newTemp(Ity_V128);
10645 dV = newTemp(Ity_V128);
10646 modrm = insn[2];
10647 if (epartIsReg(modrm)) {
10648 assign( sV, getXMMReg(eregOfRM(modrm)) );
10649 order = (Int)insn[3];
10650 delta += 2+2;
10651 DIP("pshufd $%d,%s,%s\n", order,
10652 nameXMMReg(eregOfRM(modrm)),
10653 nameXMMReg(gregOfRM(modrm)));
10654 } else {
10655 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10656 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
10657 order = (Int)insn[2+alen];
10658 delta += 3+alen;
10659 DIP("pshufd $%d,%s,%s\n", order,
10660 dis_buf,
10661 nameXMMReg(gregOfRM(modrm)));
10662 }
10663 breakup128to32s( sV, &s3, &s2, &s1, &s0 );
10664
10665# define SEL(n) \
10666 ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
10667 assign(dV,
10668 mk128from32s( SEL((order>>6)&3), SEL((order>>4)&3),
10669 SEL((order>>2)&3), SEL((order>>0)&3) )
10670 );
10671 putXMMReg(gregOfRM(modrm), mkexpr(dV));
10672# undef SEL
10673 goto decode_success;
10674 }
10675
10676 /* F3 0F 70 = PSHUFHW -- rearrange upper half 4x16 from E(xmm or
10677 mem) to G(xmm), and copy lower half */
10678 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x70) {
10679 Int order;
10680 IRTemp sVhi, dVhi, sV, dV, s3, s2, s1, s0;
10681 s3 = s2 = s1 = s0 = IRTemp_INVALID;
10682 sV = newTemp(Ity_V128);
10683 dV = newTemp(Ity_V128);
10684 sVhi = newTemp(Ity_I64);
10685 dVhi = newTemp(Ity_I64);
10686 modrm = insn[3];
10687 if (epartIsReg(modrm)) {
10688 assign( sV, getXMMReg(eregOfRM(modrm)) );
10689 order = (Int)insn[4];
10690 delta += 4+1;
10691 DIP("pshufhw $%d,%s,%s\n", order,
10692 nameXMMReg(eregOfRM(modrm)),
10693 nameXMMReg(gregOfRM(modrm)));
10694 } else {
10695 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
10696 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
10697 order = (Int)insn[3+alen];
10698 delta += 4+alen;
10699 DIP("pshufhw $%d,%s,%s\n", order,
10700 dis_buf,
10701 nameXMMReg(gregOfRM(modrm)));
10702 }
sewardjf0c1c582005-02-07 23:47:38 +000010703 assign( sVhi, unop(Iop_V128HIto64, mkexpr(sV)) );
sewardjb9fa69b2004-12-09 23:25:14 +000010704 breakup64to16s( sVhi, &s3, &s2, &s1, &s0 );
10705
10706# define SEL(n) \
10707 ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
10708 assign(dVhi,
10709 mk64from16s( SEL((order>>6)&3), SEL((order>>4)&3),
10710 SEL((order>>2)&3), SEL((order>>0)&3) )
10711 );
sewardjf0c1c582005-02-07 23:47:38 +000010712 assign(dV, binop( Iop_64HLtoV128,
sewardjb9fa69b2004-12-09 23:25:14 +000010713 mkexpr(dVhi),
sewardjf0c1c582005-02-07 23:47:38 +000010714 unop(Iop_V128to64, mkexpr(sV))) );
sewardjb9fa69b2004-12-09 23:25:14 +000010715 putXMMReg(gregOfRM(modrm), mkexpr(dV));
10716# undef SEL
10717 goto decode_success;
10718 }
10719
10720 /* F2 0F 70 = PSHUFLW -- rearrange lower half 4x16 from E(xmm or
10721 mem) to G(xmm), and copy upper half */
10722 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x70) {
10723 Int order;
10724 IRTemp sVlo, dVlo, sV, dV, s3, s2, s1, s0;
10725 s3 = s2 = s1 = s0 = IRTemp_INVALID;
10726 sV = newTemp(Ity_V128);
10727 dV = newTemp(Ity_V128);
10728 sVlo = newTemp(Ity_I64);
10729 dVlo = newTemp(Ity_I64);
10730 modrm = insn[3];
10731 if (epartIsReg(modrm)) {
10732 assign( sV, getXMMReg(eregOfRM(modrm)) );
10733 order = (Int)insn[4];
10734 delta += 4+1;
10735 DIP("pshuflw $%d,%s,%s\n", order,
10736 nameXMMReg(eregOfRM(modrm)),
10737 nameXMMReg(gregOfRM(modrm)));
10738 } else {
10739 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
10740 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
10741 order = (Int)insn[3+alen];
10742 delta += 4+alen;
10743 DIP("pshuflw $%d,%s,%s\n", order,
10744 dis_buf,
10745 nameXMMReg(gregOfRM(modrm)));
10746 }
sewardjf0c1c582005-02-07 23:47:38 +000010747 assign( sVlo, unop(Iop_V128to64, mkexpr(sV)) );
sewardjb9fa69b2004-12-09 23:25:14 +000010748 breakup64to16s( sVlo, &s3, &s2, &s1, &s0 );
10749
10750# define SEL(n) \
10751 ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
10752 assign(dVlo,
10753 mk64from16s( SEL((order>>6)&3), SEL((order>>4)&3),
10754 SEL((order>>2)&3), SEL((order>>0)&3) )
10755 );
sewardjf0c1c582005-02-07 23:47:38 +000010756 assign(dV, binop( Iop_64HLtoV128,
10757 unop(Iop_V128HIto64, mkexpr(sV)),
sewardjb9fa69b2004-12-09 23:25:14 +000010758 mkexpr(dVlo) ) );
10759 putXMMReg(gregOfRM(modrm), mkexpr(dV));
10760# undef SEL
10761 goto decode_success;
10762 }
10763
10764 /* 66 0F 72 /6 ib = PSLLD by immediate */
10765 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x72
10766 && epartIsReg(insn[2])
10767 && gregOfRM(insn[2]) == 6) {
sewardj38a3f862005-01-13 15:06:51 +000010768 delta = dis_SSE_shiftE_imm( delta+2, "pslld", Iop_ShlN32x4 );
sewardjb9fa69b2004-12-09 23:25:14 +000010769 goto decode_success;
10770 }
10771
10772 /* 66 0F F2 = PSLLD by E */
10773 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF2) {
10774 delta = dis_SSE_shiftG_byE( sorb, delta+2, "pslld", Iop_ShlN32x4 );
10775 goto decode_success;
10776 }
10777
sewardjb9fa69b2004-12-09 23:25:14 +000010778 /* 66 0F 73 /7 ib = PSLLDQ by immediate */
10779 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x73
10780 && epartIsReg(insn[2])
10781 && gregOfRM(insn[2]) == 7) {
sewardj0c9907c2005-01-10 20:37:31 +000010782 IRTemp sV, dV, hi64, lo64, hi64r, lo64r;
10783 Int imm = (Int)insn[3];
10784 Int reg = eregOfRM(insn[2]);
10785 DIP("pslldq $%d,%s\n", imm, nameXMMReg(reg));
10786 vassert(imm >= 0 && imm <= 255);
10787 delta += 4;
10788
10789 sV = newTemp(Ity_V128);
10790 dV = newTemp(Ity_V128);
10791 hi64 = newTemp(Ity_I64);
10792 lo64 = newTemp(Ity_I64);
10793 hi64r = newTemp(Ity_I64);
10794 lo64r = newTemp(Ity_I64);
10795
10796 if (imm >= 16) {
sewardj0c9907c2005-01-10 20:37:31 +000010797 putXMMReg(reg, mkV128(0x0000));
10798 goto decode_success;
10799 }
10800
10801 assign( sV, getXMMReg(reg) );
sewardjf0c1c582005-02-07 23:47:38 +000010802 assign( hi64, unop(Iop_V128HIto64, mkexpr(sV)) );
10803 assign( lo64, unop(Iop_V128to64, mkexpr(sV)) );
sewardj0c9907c2005-01-10 20:37:31 +000010804
sewardjba89f4c2005-04-07 17:31:27 +000010805 if (imm == 0) {
10806 assign( lo64r, mkexpr(lo64) );
10807 assign( hi64r, mkexpr(hi64) );
10808 }
10809 else
sewardj0c9907c2005-01-10 20:37:31 +000010810 if (imm == 8) {
10811 assign( lo64r, mkU64(0) );
10812 assign( hi64r, mkexpr(lo64) );
10813 }
sewardjc02043c2005-01-11 15:03:53 +000010814 else
sewardj0c9907c2005-01-10 20:37:31 +000010815 if (imm > 8) {
sewardj0c9907c2005-01-10 20:37:31 +000010816 assign( lo64r, mkU64(0) );
10817 assign( hi64r, binop( Iop_Shl64,
10818 mkexpr(lo64),
10819 mkU8( 8*(imm-8) ) ));
10820 } else {
10821 assign( lo64r, binop( Iop_Shl64,
10822 mkexpr(lo64),
10823 mkU8(8 * imm) ));
10824 assign( hi64r,
10825 binop( Iop_Or64,
10826 binop(Iop_Shl64, mkexpr(hi64),
10827 mkU8(8 * imm)),
10828 binop(Iop_Shr64, mkexpr(lo64),
10829 mkU8(8 * (8 - imm)) )
10830 )
10831 );
10832 }
sewardjf0c1c582005-02-07 23:47:38 +000010833 assign( dV, binop(Iop_64HLtoV128, mkexpr(hi64r), mkexpr(lo64r)) );
sewardj0c9907c2005-01-10 20:37:31 +000010834 putXMMReg(reg, mkexpr(dV));
sewardjb9fa69b2004-12-09 23:25:14 +000010835 goto decode_success;
10836 }
sewardjb9fa69b2004-12-09 23:25:14 +000010837
10838 /* 66 0F 73 /6 ib = PSLLQ by immediate */
10839 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x73
10840 && epartIsReg(insn[2])
10841 && gregOfRM(insn[2]) == 6) {
sewardj38a3f862005-01-13 15:06:51 +000010842 delta = dis_SSE_shiftE_imm( delta+2, "psllq", Iop_ShlN64x2 );
sewardjb9fa69b2004-12-09 23:25:14 +000010843 goto decode_success;
10844 }
10845
10846 /* 66 0F F3 = PSLLQ by E */
10847 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF3) {
10848 delta = dis_SSE_shiftG_byE( sorb, delta+2, "psllq", Iop_ShlN64x2 );
10849 goto decode_success;
10850 }
10851
10852 /* 66 0F 71 /6 ib = PSLLW by immediate */
10853 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x71
10854 && epartIsReg(insn[2])
10855 && gregOfRM(insn[2]) == 6) {
sewardj38a3f862005-01-13 15:06:51 +000010856 delta = dis_SSE_shiftE_imm( delta+2, "psllw", Iop_ShlN16x8 );
sewardjb9fa69b2004-12-09 23:25:14 +000010857 goto decode_success;
10858 }
10859
10860 /* 66 0F F1 = PSLLW by E */
10861 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF1) {
10862 delta = dis_SSE_shiftG_byE( sorb, delta+2, "psllw", Iop_ShlN16x8 );
10863 goto decode_success;
10864 }
10865
10866 /* 66 0F 72 /4 ib = PSRAD by immediate */
10867 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x72
10868 && epartIsReg(insn[2])
10869 && gregOfRM(insn[2]) == 4) {
sewardj38a3f862005-01-13 15:06:51 +000010870 delta = dis_SSE_shiftE_imm( delta+2, "psrad", Iop_SarN32x4 );
sewardjb9fa69b2004-12-09 23:25:14 +000010871 goto decode_success;
10872 }
10873
10874 /* 66 0F E2 = PSRAD by E */
10875 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE2) {
10876 delta = dis_SSE_shiftG_byE( sorb, delta+2, "psrad", Iop_SarN32x4 );
10877 goto decode_success;
10878 }
10879
10880 /* 66 0F 71 /4 ib = PSRAW by immediate */
10881 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x71
10882 && epartIsReg(insn[2])
10883 && gregOfRM(insn[2]) == 4) {
sewardj38a3f862005-01-13 15:06:51 +000010884 delta = dis_SSE_shiftE_imm( delta+2, "psraw", Iop_SarN16x8 );
sewardjb9fa69b2004-12-09 23:25:14 +000010885 goto decode_success;
10886 }
10887
10888 /* 66 0F E1 = PSRAW by E */
10889 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE1) {
10890 delta = dis_SSE_shiftG_byE( sorb, delta+2, "psraw", Iop_SarN16x8 );
10891 goto decode_success;
10892 }
10893
10894 /* 66 0F 72 /2 ib = PSRLD by immediate */
10895 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x72
10896 && epartIsReg(insn[2])
10897 && gregOfRM(insn[2]) == 2) {
sewardj38a3f862005-01-13 15:06:51 +000010898 delta = dis_SSE_shiftE_imm( delta+2, "psrld", Iop_ShrN32x4 );
sewardjb9fa69b2004-12-09 23:25:14 +000010899 goto decode_success;
10900 }
10901
10902 /* 66 0F D2 = PSRLD by E */
10903 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD2) {
10904 delta = dis_SSE_shiftG_byE( sorb, delta+2, "psrld", Iop_ShrN32x4 );
10905 goto decode_success;
10906 }
10907
sewardj9ee82862004-12-14 01:16:59 +000010908 /* 66 0F 73 /3 ib = PSRLDQ by immediate */
10909 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x73
10910 && epartIsReg(insn[2])
sewardj95535fe2004-12-15 17:42:58 +000010911 && gregOfRM(insn[2]) == 3) {
10912 IRTemp sV, dV, hi64, lo64, hi64r, lo64r;
sewardj9ee82862004-12-14 01:16:59 +000010913 Int imm = (Int)insn[3];
10914 Int reg = eregOfRM(insn[2]);
sewardj9ee82862004-12-14 01:16:59 +000010915 DIP("psrldq $%d,%s\n", imm, nameXMMReg(reg));
sewardj95535fe2004-12-15 17:42:58 +000010916 vassert(imm >= 0 && imm <= 255);
10917 delta += 4;
10918
10919 sV = newTemp(Ity_V128);
10920 dV = newTemp(Ity_V128);
10921 hi64 = newTemp(Ity_I64);
10922 lo64 = newTemp(Ity_I64);
10923 hi64r = newTemp(Ity_I64);
10924 lo64r = newTemp(Ity_I64);
10925
10926 if (imm >= 16) {
sewardj95535fe2004-12-15 17:42:58 +000010927 putXMMReg(reg, mkV128(0x0000));
10928 goto decode_success;
10929 }
10930
10931 assign( sV, getXMMReg(reg) );
sewardjf0c1c582005-02-07 23:47:38 +000010932 assign( hi64, unop(Iop_V128HIto64, mkexpr(sV)) );
10933 assign( lo64, unop(Iop_V128to64, mkexpr(sV)) );
sewardj95535fe2004-12-15 17:42:58 +000010934
sewardjba89f4c2005-04-07 17:31:27 +000010935 if (imm == 0) {
10936 assign( lo64r, mkexpr(lo64) );
10937 assign( hi64r, mkexpr(hi64) );
10938 }
10939 else
sewardj95535fe2004-12-15 17:42:58 +000010940 if (imm == 8) {
10941 assign( hi64r, mkU64(0) );
10942 assign( lo64r, mkexpr(hi64) );
10943 }
10944 else
10945 if (imm > 8) {
sewardj95535fe2004-12-15 17:42:58 +000010946 assign( hi64r, mkU64(0) );
10947 assign( lo64r, binop( Iop_Shr64,
10948 mkexpr(hi64),
10949 mkU8( 8*(imm-8) ) ));
10950 } else {
10951 assign( hi64r, binop( Iop_Shr64,
10952 mkexpr(hi64),
10953 mkU8(8 * imm) ));
10954 assign( lo64r,
10955 binop( Iop_Or64,
10956 binop(Iop_Shr64, mkexpr(lo64),
10957 mkU8(8 * imm)),
10958 binop(Iop_Shl64, mkexpr(hi64),
10959 mkU8(8 * (8 - imm)) )
10960 )
10961 );
10962 }
10963
sewardjf0c1c582005-02-07 23:47:38 +000010964 assign( dV, binop(Iop_64HLtoV128, mkexpr(hi64r), mkexpr(lo64r)) );
sewardj95535fe2004-12-15 17:42:58 +000010965 putXMMReg(reg, mkexpr(dV));
sewardj9ee82862004-12-14 01:16:59 +000010966 goto decode_success;
10967 }
10968
sewardjb9fa69b2004-12-09 23:25:14 +000010969 /* 66 0F 73 /2 ib = PSRLQ by immediate */
10970 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x73
10971 && epartIsReg(insn[2])
10972 && gregOfRM(insn[2]) == 2) {
sewardj38a3f862005-01-13 15:06:51 +000010973 delta = dis_SSE_shiftE_imm( delta+2, "psrlq", Iop_ShrN64x2 );
sewardjb9fa69b2004-12-09 23:25:14 +000010974 goto decode_success;
10975 }
10976
10977 /* 66 0F D3 = PSRLQ by E */
10978 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD3) {
10979 delta = dis_SSE_shiftG_byE( sorb, delta+2, "psrlq", Iop_ShrN64x2 );
10980 goto decode_success;
10981 }
10982
10983 /* 66 0F 71 /2 ib = PSRLW by immediate */
10984 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x71
10985 && epartIsReg(insn[2])
10986 && gregOfRM(insn[2]) == 2) {
sewardj38a3f862005-01-13 15:06:51 +000010987 delta = dis_SSE_shiftE_imm( delta+2, "psrlw", Iop_ShrN16x8 );
sewardjb9fa69b2004-12-09 23:25:14 +000010988 goto decode_success;
10989 }
10990
10991 /* 66 0F D1 = PSRLW by E */
10992 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD1) {
10993 delta = dis_SSE_shiftG_byE( sorb, delta+2, "psrlw", Iop_ShrN16x8 );
10994 goto decode_success;
10995 }
10996
10997 /* 66 0F F8 = PSUBB */
10998 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF8) {
10999 delta = dis_SSEint_E_to_G( sorb, delta+2,
11000 "psubb", Iop_Sub8x16, False );
11001 goto decode_success;
11002 }
11003
11004 /* 66 0F FA = PSUBD */
11005 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xFA) {
11006 delta = dis_SSEint_E_to_G( sorb, delta+2,
11007 "psubd", Iop_Sub32x4, False );
11008 goto decode_success;
11009 }
11010
11011 /* ***--- this is an MMX class insn introduced in SSE2 ---*** */
11012 /* 0F FB = PSUBQ -- sub 64x1 */
11013 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xFB) {
11014 do_MMX_preamble();
11015 delta = dis_MMXop_regmem_to_reg (
11016 sorb, delta+2, insn[1], "psubq", False );
11017 goto decode_success;
11018 }
11019
11020 /* 66 0F FB = PSUBQ */
11021 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xFB) {
11022 delta = dis_SSEint_E_to_G( sorb, delta+2,
11023 "psubq", Iop_Sub64x2, False );
11024 goto decode_success;
11025 }
11026
11027 /* 66 0F F9 = PSUBW */
11028 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF9) {
11029 delta = dis_SSEint_E_to_G( sorb, delta+2,
11030 "psubw", Iop_Sub16x8, False );
11031 goto decode_success;
11032 }
11033
11034 /* 66 0F E8 = PSUBSB */
11035 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE8) {
11036 delta = dis_SSEint_E_to_G( sorb, delta+2,
11037 "psubsb", Iop_QSub8Sx16, False );
11038 goto decode_success;
11039 }
11040
11041 /* 66 0F E9 = PSUBSW */
11042 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE9) {
11043 delta = dis_SSEint_E_to_G( sorb, delta+2,
11044 "psubsw", Iop_QSub16Sx8, False );
11045 goto decode_success;
11046 }
11047
11048 /* 66 0F D8 = PSUBSB */
11049 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD8) {
11050 delta = dis_SSEint_E_to_G( sorb, delta+2,
11051 "psubusb", Iop_QSub8Ux16, False );
11052 goto decode_success;
11053 }
11054
11055 /* 66 0F D9 = PSUBSW */
11056 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD9) {
11057 delta = dis_SSEint_E_to_G( sorb, delta+2,
11058 "psubusw", Iop_QSub16Ux8, False );
11059 goto decode_success;
11060 }
11061
sewardj9e203592004-12-10 01:48:18 +000011062 /* 66 0F 68 = PUNPCKHBW */
11063 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x68) {
11064 delta = dis_SSEint_E_to_G( sorb, delta+2,
11065 "punpckhbw",
11066 Iop_InterleaveHI8x16, True );
11067 goto decode_success;
11068 }
11069
11070 /* 66 0F 6A = PUNPCKHDQ */
11071 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x6A) {
11072 delta = dis_SSEint_E_to_G( sorb, delta+2,
11073 "punpckhdq",
11074 Iop_InterleaveHI32x4, True );
11075 goto decode_success;
11076 }
11077
11078 /* 66 0F 6D = PUNPCKHQDQ */
11079 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x6D) {
11080 delta = dis_SSEint_E_to_G( sorb, delta+2,
11081 "punpckhqdq",
11082 Iop_InterleaveHI64x2, True );
11083 goto decode_success;
11084 }
11085
11086 /* 66 0F 69 = PUNPCKHWD */
11087 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x69) {
11088 delta = dis_SSEint_E_to_G( sorb, delta+2,
11089 "punpckhwd",
11090 Iop_InterleaveHI16x8, True );
11091 goto decode_success;
11092 }
11093
11094 /* 66 0F 60 = PUNPCKLBW */
11095 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x60) {
11096 delta = dis_SSEint_E_to_G( sorb, delta+2,
11097 "punpcklbw",
11098 Iop_InterleaveLO8x16, True );
11099 goto decode_success;
11100 }
11101
11102 /* 66 0F 62 = PUNPCKLDQ */
11103 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x62) {
11104 delta = dis_SSEint_E_to_G( sorb, delta+2,
11105 "punpckldq",
11106 Iop_InterleaveLO32x4, True );
11107 goto decode_success;
11108 }
11109
11110 /* 66 0F 6C = PUNPCKLQDQ */
11111 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x6C) {
11112 delta = dis_SSEint_E_to_G( sorb, delta+2,
11113 "punpcklqdq",
11114 Iop_InterleaveLO64x2, True );
11115 goto decode_success;
11116 }
11117
11118 /* 66 0F 61 = PUNPCKLWD */
11119 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x61) {
11120 delta = dis_SSEint_E_to_G( sorb, delta+2,
11121 "punpcklwd",
11122 Iop_InterleaveLO16x8, True );
11123 goto decode_success;
11124 }
11125
11126 /* 66 0F EF = PXOR */
11127 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xEF) {
sewardjf0c1c582005-02-07 23:47:38 +000011128 delta = dis_SSE_E_to_G_all( sorb, delta+2, "pxor", Iop_XorV128 );
sewardj9e203592004-12-10 01:48:18 +000011129 goto decode_success;
11130 }
11131
sewardjc9a65702004-07-07 16:32:57 +000011132//-- /* FXSAVE/FXRSTOR m32 -- load/store the FPU/MMX/SSE state. */
11133//-- if (insn[0] == 0x0F && insn[1] == 0xAE
11134//-- && (!epartIsReg(insn[2]))
11135//-- && (gregOfRM(insn[2]) == 1 || gregOfRM(insn[2]) == 0) ) {
11136//-- Bool store = gregOfRM(insn[2]) == 0;
11137//-- vg_assert(sz == 4);
11138//-- pair = disAMode ( cb, sorb, eip+2, dis_buf );
11139//-- t1 = LOW24(pair);
11140//-- eip += 2+HI8(pair);
11141//-- uInstr3(cb, store ? SSE2a_MemWr : SSE2a_MemRd, 512,
11142//-- Lit16, (((UShort)insn[0]) << 8) | (UShort)insn[1],
11143//-- Lit16, (UShort)insn[2],
11144//-- TempReg, t1 );
11145//-- DIP("fx%s %s\n", store ? "save" : "rstor", dis_buf );
11146//-- goto decode_success;
11147//-- }
sewardjc9a65702004-07-07 16:32:57 +000011148
sewardjbfceb082005-11-15 11:16:30 +000011149 /* 0F AE /7 = CLFLUSH -- flush cache line */
11150 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xAE
11151 && !epartIsReg(insn[2]) && gregOfRM(insn[2]) == 7) {
11152
11153 /* This is something of a hack. We need to know the size of the
11154 cache line containing addr. Since we don't (easily), assume
11155 256 on the basis that no real cache would have a line that
11156 big. It's safe to invalidate more stuff than we need, just
11157 inefficient. */
11158 UInt lineszB = 256;
11159
11160 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
11161 delta += 2+alen;
11162
11163 /* Round addr down to the start of the containing block. */
11164 stmt( IRStmt_Put(
11165 OFFB_TISTART,
11166 binop( Iop_And32,
11167 mkexpr(addr),
11168 mkU32( ~(lineszB-1) ))) );
11169
11170 stmt( IRStmt_Put(OFFB_TILEN, mkU32(lineszB) ) );
11171
sewardjdd40fdf2006-12-24 02:20:24 +000011172 irsb->jumpkind = Ijk_TInval;
11173 irsb->next = mkU32(guest_EIP_bbstart+delta);
sewardjbfceb082005-11-15 11:16:30 +000011174 dres.whatNext = Dis_StopHere;
11175
11176 DIP("clflush %s\n", dis_buf);
11177 goto decode_success;
11178 }
sewardjc9a65702004-07-07 16:32:57 +000011179
11180 /* ---------------------------------------------------- */
sewardj90e91ee2005-11-07 14:23:52 +000011181 /* --- end of the SSE2 decoder. --- */
11182 /* ---------------------------------------------------- */
11183
11184 /* ---------------------------------------------------- */
11185 /* --- start of the SSE3 decoder. --- */
11186 /* ---------------------------------------------------- */
11187
11188 /* Skip parts of the decoder which don't apply given the stated
11189 guest subarchitecture. */
sewardj5117ce12006-01-27 21:20:15 +000011190 /* if (0 == (archinfo->hwcaps & VEX_HWCAPS_X86_SSE3)) */
11191 /* In fact this is highly bogus; we accept SSE3 insns even on a
11192 SSE2-only guest since they turn into IR which can be re-emitted
11193 successfully on an SSE2 host. */
11194 if (0 == (archinfo->hwcaps & VEX_HWCAPS_X86_SSE2))
11195 goto after_sse_decoders; /* no SSE3 capabilities */
sewardj90e91ee2005-11-07 14:23:52 +000011196
11197 insn = (UChar*)&guest_code[delta];
11198
11199 /* F3 0F 12 = MOVSLDUP -- move from E (mem or xmm) to G (xmm),
11200 duplicating some lanes (2:2:0:0). */
11201 /* F3 0F 16 = MOVSHDUP -- move from E (mem or xmm) to G (xmm),
11202 duplicating some lanes (3:3:1:1). */
11203 if (sz == 4 && insn[0] == 0xF3 && insn[1] == 0x0F
11204 && (insn[2] == 0x12 || insn[2] == 0x16)) {
11205 IRTemp s3, s2, s1, s0;
11206 IRTemp sV = newTemp(Ity_V128);
11207 Bool isH = insn[2] == 0x16;
11208 s3 = s2 = s1 = s0 = IRTemp_INVALID;
11209
11210 modrm = insn[3];
11211 if (epartIsReg(modrm)) {
11212 assign( sV, getXMMReg( eregOfRM(modrm)) );
11213 DIP("movs%cdup %s,%s\n", isH ? 'h' : 'l',
11214 nameXMMReg(eregOfRM(modrm)),
11215 nameXMMReg(gregOfRM(modrm)));
11216 delta += 3+1;
11217 } else {
11218 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
11219 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
11220 DIP("movs%cdup %s,%s\n", isH ? 'h' : 'l',
11221 dis_buf,
11222 nameXMMReg(gregOfRM(modrm)));
11223 delta += 3+alen;
11224 }
11225
11226 breakup128to32s( sV, &s3, &s2, &s1, &s0 );
11227 putXMMReg( gregOfRM(modrm),
11228 isH ? mk128from32s( s3, s3, s1, s1 )
11229 : mk128from32s( s2, s2, s0, s0 ) );
11230 goto decode_success;
11231 }
11232
sewardjdd5d2042006-08-03 15:03:19 +000011233 /* F2 0F 12 = MOVDDUP -- move from E (mem or xmm) to G (xmm),
11234 duplicating some lanes (0:1:0:1). */
11235 if (sz == 4 && insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x12) {
11236 IRTemp sV = newTemp(Ity_V128);
11237 IRTemp d0 = newTemp(Ity_I64);
11238
11239 modrm = insn[3];
11240 if (epartIsReg(modrm)) {
11241 assign( sV, getXMMReg( eregOfRM(modrm)) );
11242 DIP("movddup %s,%s\n", nameXMMReg(eregOfRM(modrm)),
11243 nameXMMReg(gregOfRM(modrm)));
11244 delta += 3+1;
11245 assign ( d0, unop(Iop_V128to64, mkexpr(sV)) );
11246 } else {
11247 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
11248 assign( d0, loadLE(Ity_I64, mkexpr(addr)) );
11249 DIP("movddup %s,%s\n", dis_buf,
11250 nameXMMReg(gregOfRM(modrm)));
11251 delta += 3+alen;
11252 }
11253
11254 putXMMReg( gregOfRM(modrm), binop(Iop_64HLtoV128,mkexpr(d0),mkexpr(d0)) );
11255 goto decode_success;
11256 }
11257
sewardj90e91ee2005-11-07 14:23:52 +000011258 /* F2 0F D0 = ADDSUBPS -- 32x4 +/-/+/- from E (mem or xmm) to G (xmm). */
11259 if (sz == 4 && insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0xD0) {
11260 IRTemp a3, a2, a1, a0, s3, s2, s1, s0;
11261 IRTemp eV = newTemp(Ity_V128);
11262 IRTemp gV = newTemp(Ity_V128);
11263 IRTemp addV = newTemp(Ity_V128);
11264 IRTemp subV = newTemp(Ity_V128);
11265 a3 = a2 = a1 = a0 = s3 = s2 = s1 = s0 = IRTemp_INVALID;
11266
11267 modrm = insn[3];
11268 if (epartIsReg(modrm)) {
11269 assign( eV, getXMMReg( eregOfRM(modrm)) );
11270 DIP("addsubps %s,%s\n", nameXMMReg(eregOfRM(modrm)),
11271 nameXMMReg(gregOfRM(modrm)));
11272 delta += 3+1;
11273 } else {
11274 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
11275 assign( eV, loadLE(Ity_V128, mkexpr(addr)) );
11276 DIP("addsubps %s,%s\n", dis_buf,
11277 nameXMMReg(gregOfRM(modrm)));
11278 delta += 3+alen;
11279 }
11280
11281 assign( gV, getXMMReg(gregOfRM(modrm)) );
11282
11283 assign( addV, binop(Iop_Add32Fx4, mkexpr(gV), mkexpr(eV)) );
11284 assign( subV, binop(Iop_Sub32Fx4, mkexpr(gV), mkexpr(eV)) );
11285
11286 breakup128to32s( addV, &a3, &a2, &a1, &a0 );
11287 breakup128to32s( subV, &s3, &s2, &s1, &s0 );
11288
11289 putXMMReg( gregOfRM(modrm), mk128from32s( a3, s2, a1, s0 ));
11290 goto decode_success;
11291 }
11292
sewardjdd5d2042006-08-03 15:03:19 +000011293 /* 66 0F D0 = ADDSUBPD -- 64x4 +/- from E (mem or xmm) to G (xmm). */
11294 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD0) {
11295 IRTemp eV = newTemp(Ity_V128);
11296 IRTemp gV = newTemp(Ity_V128);
11297 IRTemp addV = newTemp(Ity_V128);
11298 IRTemp subV = newTemp(Ity_V128);
11299 IRTemp a1 = newTemp(Ity_I64);
11300 IRTemp s0 = newTemp(Ity_I64);
11301
11302 modrm = insn[2];
11303 if (epartIsReg(modrm)) {
11304 assign( eV, getXMMReg( eregOfRM(modrm)) );
11305 DIP("addsubpd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
11306 nameXMMReg(gregOfRM(modrm)));
11307 delta += 2+1;
11308 } else {
11309 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
11310 assign( eV, loadLE(Ity_V128, mkexpr(addr)) );
11311 DIP("addsubpd %s,%s\n", dis_buf,
11312 nameXMMReg(gregOfRM(modrm)));
11313 delta += 2+alen;
11314 }
11315
11316 assign( gV, getXMMReg(gregOfRM(modrm)) );
11317
11318 assign( addV, binop(Iop_Add64Fx2, mkexpr(gV), mkexpr(eV)) );
11319 assign( subV, binop(Iop_Sub64Fx2, mkexpr(gV), mkexpr(eV)) );
11320
11321 assign( a1, unop(Iop_V128HIto64, mkexpr(addV) ));
11322 assign( s0, unop(Iop_V128to64, mkexpr(subV) ));
11323
11324 putXMMReg( gregOfRM(modrm),
11325 binop(Iop_64HLtoV128, mkexpr(a1), mkexpr(s0)) );
11326 goto decode_success;
11327 }
11328
11329 /* F2 0F 7D = HSUBPS -- 32x4 sub across from E (mem or xmm) to G (xmm). */
11330 /* F2 0F 7C = HADDPS -- 32x4 add across from E (mem or xmm) to G (xmm). */
11331 if (sz == 4 && insn[0] == 0xF2 && insn[1] == 0x0F
11332 && (insn[2] == 0x7C || insn[2] == 0x7D)) {
11333 IRTemp e3, e2, e1, e0, g3, g2, g1, g0;
11334 IRTemp eV = newTemp(Ity_V128);
11335 IRTemp gV = newTemp(Ity_V128);
11336 IRTemp leftV = newTemp(Ity_V128);
11337 IRTemp rightV = newTemp(Ity_V128);
11338 Bool isAdd = insn[2] == 0x7C;
11339 HChar* str = isAdd ? "add" : "sub";
11340 e3 = e2 = e1 = e0 = g3 = g2 = g1 = g0 = IRTemp_INVALID;
11341
11342 modrm = insn[3];
11343 if (epartIsReg(modrm)) {
11344 assign( eV, getXMMReg( eregOfRM(modrm)) );
11345 DIP("h%sps %s,%s\n", str, nameXMMReg(eregOfRM(modrm)),
11346 nameXMMReg(gregOfRM(modrm)));
11347 delta += 3+1;
11348 } else {
11349 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
11350 assign( eV, loadLE(Ity_V128, mkexpr(addr)) );
11351 DIP("h%sps %s,%s\n", str, dis_buf,
11352 nameXMMReg(gregOfRM(modrm)));
11353 delta += 3+alen;
11354 }
11355
11356 assign( gV, getXMMReg(gregOfRM(modrm)) );
11357
11358 breakup128to32s( eV, &e3, &e2, &e1, &e0 );
11359 breakup128to32s( gV, &g3, &g2, &g1, &g0 );
11360
11361 assign( leftV, mk128from32s( e2, e0, g2, g0 ) );
11362 assign( rightV, mk128from32s( e3, e1, g3, g1 ) );
11363
11364 putXMMReg( gregOfRM(modrm),
11365 binop(isAdd ? Iop_Add32Fx4 : Iop_Sub32Fx4,
11366 mkexpr(leftV), mkexpr(rightV) ) );
11367 goto decode_success;
11368 }
11369
11370 /* 66 0F 7D = HSUBPD -- 64x2 sub across from E (mem or xmm) to G (xmm). */
11371 /* 66 0F 7C = HADDPD -- 64x2 add across from E (mem or xmm) to G (xmm). */
11372 if (sz == 2 && insn[0] == 0x0F && (insn[1] == 0x7C || insn[1] == 0x7D)) {
11373 IRTemp e1 = newTemp(Ity_I64);
11374 IRTemp e0 = newTemp(Ity_I64);
11375 IRTemp g1 = newTemp(Ity_I64);
11376 IRTemp g0 = newTemp(Ity_I64);
11377 IRTemp eV = newTemp(Ity_V128);
11378 IRTemp gV = newTemp(Ity_V128);
11379 IRTemp leftV = newTemp(Ity_V128);
11380 IRTemp rightV = newTemp(Ity_V128);
11381 Bool isAdd = insn[1] == 0x7C;
11382 HChar* str = isAdd ? "add" : "sub";
11383
11384 modrm = insn[2];
11385 if (epartIsReg(modrm)) {
11386 assign( eV, getXMMReg( eregOfRM(modrm)) );
11387 DIP("h%spd %s,%s\n", str, nameXMMReg(eregOfRM(modrm)),
11388 nameXMMReg(gregOfRM(modrm)));
11389 delta += 2+1;
11390 } else {
11391 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
11392 assign( eV, loadLE(Ity_V128, mkexpr(addr)) );
11393 DIP("h%spd %s,%s\n", str, dis_buf,
11394 nameXMMReg(gregOfRM(modrm)));
11395 delta += 2+alen;
11396 }
11397
11398 assign( gV, getXMMReg(gregOfRM(modrm)) );
11399
11400 assign( e1, unop(Iop_V128HIto64, mkexpr(eV) ));
11401 assign( e0, unop(Iop_V128to64, mkexpr(eV) ));
11402 assign( g1, unop(Iop_V128HIto64, mkexpr(gV) ));
11403 assign( g0, unop(Iop_V128to64, mkexpr(gV) ));
11404
11405 assign( leftV, binop(Iop_64HLtoV128, mkexpr(e0),mkexpr(g0)) );
11406 assign( rightV, binop(Iop_64HLtoV128, mkexpr(e1),mkexpr(g1)) );
11407
11408 putXMMReg( gregOfRM(modrm),
11409 binop(isAdd ? Iop_Add64Fx2 : Iop_Sub64Fx2,
11410 mkexpr(leftV), mkexpr(rightV) ) );
11411 goto decode_success;
11412 }
11413
11414 /* F2 0F F0 = LDDQU -- move from E (mem or xmm) to G (xmm). */
11415 if (sz == 4 && insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0xF0) {
11416 modrm = getIByte(delta+3);
11417 if (epartIsReg(modrm)) {
11418 goto decode_failure;
11419 } else {
11420 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
11421 putXMMReg( gregOfRM(modrm),
11422 loadLE(Ity_V128, mkexpr(addr)) );
11423 DIP("lddqu %s,%s\n", dis_buf,
11424 nameXMMReg(gregOfRM(modrm)));
11425 delta += 3+alen;
11426 }
11427 goto decode_success;
11428 }
11429
sewardj90e91ee2005-11-07 14:23:52 +000011430 /* ---------------------------------------------------- */
11431 /* --- end of the SSE3 decoder. --- */
sewardjc9a65702004-07-07 16:32:57 +000011432 /* ---------------------------------------------------- */
11433
sewardj150c9cd2008-02-09 01:16:02 +000011434 /* ---------------------------------------------------- */
11435 /* --- start of the SSSE3 decoder. --- */
11436 /* ---------------------------------------------------- */
11437
11438 /* 0F 38 04 = PMADDUBSW -- Multiply and Add Packed Signed and
11439 Unsigned Bytes (MMX) */
11440 if (sz == 4
11441 && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x04) {
11442 IRTemp sV = newTemp(Ity_I64);
11443 IRTemp dV = newTemp(Ity_I64);
11444 IRTemp sVoddsSX = newTemp(Ity_I64);
11445 IRTemp sVevensSX = newTemp(Ity_I64);
11446 IRTemp dVoddsZX = newTemp(Ity_I64);
11447 IRTemp dVevensZX = newTemp(Ity_I64);
11448
11449 modrm = insn[3];
11450 do_MMX_preamble();
11451 assign( dV, getMMXReg(gregOfRM(modrm)) );
11452
11453 if (epartIsReg(modrm)) {
11454 assign( sV, getMMXReg(eregOfRM(modrm)) );
11455 delta += 3+1;
11456 DIP("pmaddubsw %s,%s\n", nameMMXReg(eregOfRM(modrm)),
11457 nameMMXReg(gregOfRM(modrm)));
11458 } else {
11459 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
11460 assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
11461 delta += 3+alen;
11462 DIP("pmaddubsw %s,%s\n", dis_buf,
11463 nameMMXReg(gregOfRM(modrm)));
11464 }
11465
11466 /* compute dV unsigned x sV signed */
11467 assign( sVoddsSX,
11468 binop(Iop_SarN16x4, mkexpr(sV), mkU8(8)) );
11469 assign( sVevensSX,
11470 binop(Iop_SarN16x4,
11471 binop(Iop_ShlN16x4, mkexpr(sV), mkU8(8)),
11472 mkU8(8)) );
11473 assign( dVoddsZX,
11474 binop(Iop_ShrN16x4, mkexpr(dV), mkU8(8)) );
11475 assign( dVevensZX,
11476 binop(Iop_ShrN16x4,
11477 binop(Iop_ShlN16x4, mkexpr(dV), mkU8(8)),
11478 mkU8(8)) );
11479
11480 putMMXReg(
11481 gregOfRM(modrm),
11482 binop(Iop_QAdd16Sx4,
11483 binop(Iop_Mul16x4, mkexpr(sVoddsSX), mkexpr(dVoddsZX)),
11484 binop(Iop_Mul16x4, mkexpr(sVevensSX), mkexpr(dVevensZX))
11485 )
11486 );
11487 goto decode_success;
11488 }
11489
11490 /* 66 0F 38 04 = PMADDUBSW -- Multiply and Add Packed Signed and
11491 Unsigned Bytes (XMM) */
11492 if (sz == 2
11493 && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x04) {
11494 IRTemp sV = newTemp(Ity_V128);
11495 IRTemp dV = newTemp(Ity_V128);
11496 IRTemp sVoddsSX = newTemp(Ity_V128);
11497 IRTemp sVevensSX = newTemp(Ity_V128);
11498 IRTemp dVoddsZX = newTemp(Ity_V128);
11499 IRTemp dVevensZX = newTemp(Ity_V128);
11500
11501 modrm = insn[3];
11502 assign( dV, getXMMReg(gregOfRM(modrm)) );
11503
11504 if (epartIsReg(modrm)) {
11505 assign( sV, getXMMReg(eregOfRM(modrm)) );
11506 delta += 3+1;
11507 DIP("pmaddubsw %s,%s\n", nameXMMReg(eregOfRM(modrm)),
11508 nameXMMReg(gregOfRM(modrm)));
11509 } else {
11510 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
11511 gen_SEGV_if_not_16_aligned( addr );
11512 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
11513 delta += 3+alen;
11514 DIP("pmaddubsw %s,%s\n", dis_buf,
11515 nameXMMReg(gregOfRM(modrm)));
11516 }
11517
11518 /* compute dV unsigned x sV signed */
11519 assign( sVoddsSX,
11520 binop(Iop_SarN16x8, mkexpr(sV), mkU8(8)) );
11521 assign( sVevensSX,
11522 binop(Iop_SarN16x8,
11523 binop(Iop_ShlN16x8, mkexpr(sV), mkU8(8)),
11524 mkU8(8)) );
11525 assign( dVoddsZX,
11526 binop(Iop_ShrN16x8, mkexpr(dV), mkU8(8)) );
11527 assign( dVevensZX,
11528 binop(Iop_ShrN16x8,
11529 binop(Iop_ShlN16x8, mkexpr(dV), mkU8(8)),
11530 mkU8(8)) );
11531
11532 putXMMReg(
11533 gregOfRM(modrm),
11534 binop(Iop_QAdd16Sx8,
11535 binop(Iop_Mul16x8, mkexpr(sVoddsSX), mkexpr(dVoddsZX)),
11536 binop(Iop_Mul16x8, mkexpr(sVevensSX), mkexpr(dVevensZX))
11537 )
11538 );
11539 goto decode_success;
11540 }
11541
11542 /* ***--- these are MMX class insns introduced in SSSE3 ---*** */
11543 /* 0F 38 03 = PHADDSW -- 16x4 signed qadd across from E (mem or
11544 mmx) and G to G (mmx). */
11545 /* 0F 38 07 = PHSUBSW -- 16x4 signed qsub across from E (mem or
11546 mmx) and G to G (mmx). */
11547 /* 0F 38 01 = PHADDW -- 16x4 add across from E (mem or mmx) and G
11548 to G (mmx). */
11549 /* 0F 38 05 = PHSUBW -- 16x4 sub across from E (mem or mmx) and G
11550 to G (mmx). */
11551 /* 0F 38 02 = PHADDD -- 32x2 add across from E (mem or mmx) and G
11552 to G (mmx). */
11553 /* 0F 38 06 = PHSUBD -- 32x2 sub across from E (mem or mmx) and G
11554 to G (mmx). */
11555
11556 if (sz == 4
11557 && insn[0] == 0x0F && insn[1] == 0x38
11558 && (insn[2] == 0x03 || insn[2] == 0x07 || insn[2] == 0x01
11559 || insn[2] == 0x05 || insn[2] == 0x02 || insn[2] == 0x06)) {
11560 HChar* str = "???";
11561 IROp opV64 = Iop_INVALID;
11562 IROp opCatO = Iop_CatOddLanes16x4;
11563 IROp opCatE = Iop_CatEvenLanes16x4;
11564 IRTemp sV = newTemp(Ity_I64);
11565 IRTemp dV = newTemp(Ity_I64);
11566
11567 modrm = insn[3];
11568
11569 switch (insn[2]) {
11570 case 0x03: opV64 = Iop_QAdd16Sx4; str = "addsw"; break;
11571 case 0x07: opV64 = Iop_QSub16Sx4; str = "subsw"; break;
11572 case 0x01: opV64 = Iop_Add16x4; str = "addw"; break;
11573 case 0x05: opV64 = Iop_Sub16x4; str = "subw"; break;
11574 case 0x02: opV64 = Iop_Add32x2; str = "addd"; break;
11575 case 0x06: opV64 = Iop_Sub32x2; str = "subd"; break;
11576 default: vassert(0);
11577 }
11578 if (insn[2] == 0x02 || insn[2] == 0x06) {
11579 opCatO = Iop_InterleaveHI32x2;
11580 opCatE = Iop_InterleaveLO32x2;
11581 }
11582
11583 do_MMX_preamble();
11584 assign( dV, getMMXReg(gregOfRM(modrm)) );
11585
11586 if (epartIsReg(modrm)) {
11587 assign( sV, getMMXReg(eregOfRM(modrm)) );
11588 delta += 3+1;
11589 DIP("ph%s %s,%s\n", str, nameMMXReg(eregOfRM(modrm)),
11590 nameMMXReg(gregOfRM(modrm)));
11591 } else {
11592 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
11593 assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
11594 delta += 3+alen;
11595 DIP("ph%s %s,%s\n", str, dis_buf,
11596 nameMMXReg(gregOfRM(modrm)));
11597 }
11598
11599 putMMXReg(
11600 gregOfRM(modrm),
11601 binop(opV64,
11602 binop(opCatE,mkexpr(sV),mkexpr(dV)),
11603 binop(opCatO,mkexpr(sV),mkexpr(dV))
11604 )
11605 );
11606 goto decode_success;
11607 }
11608
11609 /* 66 0F 38 03 = PHADDSW -- 16x8 signed qadd across from E (mem or
11610 xmm) and G to G (xmm). */
11611 /* 66 0F 38 07 = PHSUBSW -- 16x8 signed qsub across from E (mem or
11612 xmm) and G to G (xmm). */
11613 /* 66 0F 38 01 = PHADDW -- 16x8 add across from E (mem or xmm) and
11614 G to G (xmm). */
11615 /* 66 0F 38 05 = PHSUBW -- 16x8 sub across from E (mem or xmm) and
11616 G to G (xmm). */
11617 /* 66 0F 38 02 = PHADDD -- 32x4 add across from E (mem or xmm) and
11618 G to G (xmm). */
11619 /* 66 0F 38 06 = PHSUBD -- 32x4 sub across from E (mem or xmm) and
11620 G to G (xmm). */
11621
11622 if (sz == 2
11623 && insn[0] == 0x0F && insn[1] == 0x38
11624 && (insn[2] == 0x03 || insn[2] == 0x07 || insn[2] == 0x01
11625 || insn[2] == 0x05 || insn[2] == 0x02 || insn[2] == 0x06)) {
11626 HChar* str = "???";
11627 IROp opV64 = Iop_INVALID;
11628 IROp opCatO = Iop_CatOddLanes16x4;
11629 IROp opCatE = Iop_CatEvenLanes16x4;
11630 IRTemp sV = newTemp(Ity_V128);
11631 IRTemp dV = newTemp(Ity_V128);
11632 IRTemp sHi = newTemp(Ity_I64);
11633 IRTemp sLo = newTemp(Ity_I64);
11634 IRTemp dHi = newTemp(Ity_I64);
11635 IRTemp dLo = newTemp(Ity_I64);
11636
11637 modrm = insn[3];
11638
11639 switch (insn[2]) {
11640 case 0x03: opV64 = Iop_QAdd16Sx4; str = "addsw"; break;
11641 case 0x07: opV64 = Iop_QSub16Sx4; str = "subsw"; break;
11642 case 0x01: opV64 = Iop_Add16x4; str = "addw"; break;
11643 case 0x05: opV64 = Iop_Sub16x4; str = "subw"; break;
11644 case 0x02: opV64 = Iop_Add32x2; str = "addd"; break;
11645 case 0x06: opV64 = Iop_Sub32x2; str = "subd"; break;
11646 default: vassert(0);
11647 }
11648 if (insn[2] == 0x02 || insn[2] == 0x06) {
11649 opCatO = Iop_InterleaveHI32x2;
11650 opCatE = Iop_InterleaveLO32x2;
11651 }
11652
11653 assign( dV, getXMMReg(gregOfRM(modrm)) );
11654
11655 if (epartIsReg(modrm)) {
11656 assign( sV, getXMMReg( eregOfRM(modrm)) );
11657 DIP("ph%s %s,%s\n", str, nameXMMReg(eregOfRM(modrm)),
11658 nameXMMReg(gregOfRM(modrm)));
11659 delta += 3+1;
11660 } else {
11661 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
11662 gen_SEGV_if_not_16_aligned( addr );
11663 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
11664 DIP("ph%s %s,%s\n", str, dis_buf,
11665 nameXMMReg(gregOfRM(modrm)));
11666 delta += 3+alen;
11667 }
11668
11669 assign( dHi, unop(Iop_V128HIto64, mkexpr(dV)) );
11670 assign( dLo, unop(Iop_V128to64, mkexpr(dV)) );
11671 assign( sHi, unop(Iop_V128HIto64, mkexpr(sV)) );
11672 assign( sLo, unop(Iop_V128to64, mkexpr(sV)) );
11673
11674 /* This isn't a particularly efficient way to compute the
11675 result, but at least it avoids a proliferation of IROps,
11676 hence avoids complication all the backends. */
11677 putXMMReg(
11678 gregOfRM(modrm),
11679 binop(Iop_64HLtoV128,
11680 binop(opV64,
11681 binop(opCatE,mkexpr(sHi),mkexpr(sLo)),
11682 binop(opCatO,mkexpr(sHi),mkexpr(sLo))
11683 ),
11684 binop(opV64,
11685 binop(opCatE,mkexpr(dHi),mkexpr(dLo)),
11686 binop(opCatO,mkexpr(dHi),mkexpr(dLo))
11687 )
11688 )
11689 );
11690 goto decode_success;
11691 }
11692
11693 /* 0F 38 0B = PMULHRSW -- Packed Multiply High with Round and Scale
11694 (MMX) */
11695 if (sz == 4
11696 && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x0B) {
11697 IRTemp sV = newTemp(Ity_I64);
11698 IRTemp dV = newTemp(Ity_I64);
11699
11700 modrm = insn[3];
11701 do_MMX_preamble();
11702 assign( dV, getMMXReg(gregOfRM(modrm)) );
11703
11704 if (epartIsReg(modrm)) {
11705 assign( sV, getMMXReg(eregOfRM(modrm)) );
11706 delta += 3+1;
11707 DIP("pmulhrsw %s,%s\n", nameMMXReg(eregOfRM(modrm)),
11708 nameMMXReg(gregOfRM(modrm)));
11709 } else {
11710 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
11711 assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
11712 delta += 3+alen;
11713 DIP("pmulhrsw %s,%s\n", dis_buf,
11714 nameMMXReg(gregOfRM(modrm)));
11715 }
11716
11717 putMMXReg(
11718 gregOfRM(modrm),
11719 dis_PMULHRSW_helper( mkexpr(sV), mkexpr(dV) )
11720 );
11721 goto decode_success;
11722 }
11723
11724 /* 66 0F 38 0B = PMULHRSW -- Packed Multiply High with Round and
11725 Scale (XMM) */
11726 if (sz == 2
11727 && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x0B) {
11728 IRTemp sV = newTemp(Ity_V128);
11729 IRTemp dV = newTemp(Ity_V128);
11730 IRTemp sHi = newTemp(Ity_I64);
11731 IRTemp sLo = newTemp(Ity_I64);
11732 IRTemp dHi = newTemp(Ity_I64);
11733 IRTemp dLo = newTemp(Ity_I64);
11734
11735 modrm = insn[3];
11736 assign( dV, getXMMReg(gregOfRM(modrm)) );
11737
11738 if (epartIsReg(modrm)) {
11739 assign( sV, getXMMReg(eregOfRM(modrm)) );
11740 delta += 3+1;
11741 DIP("pmulhrsw %s,%s\n", nameXMMReg(eregOfRM(modrm)),
11742 nameXMMReg(gregOfRM(modrm)));
11743 } else {
11744 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
11745 gen_SEGV_if_not_16_aligned( addr );
11746 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
11747 delta += 3+alen;
11748 DIP("pmulhrsw %s,%s\n", dis_buf,
11749 nameXMMReg(gregOfRM(modrm)));
11750 }
11751
11752 assign( dHi, unop(Iop_V128HIto64, mkexpr(dV)) );
11753 assign( dLo, unop(Iop_V128to64, mkexpr(dV)) );
11754 assign( sHi, unop(Iop_V128HIto64, mkexpr(sV)) );
11755 assign( sLo, unop(Iop_V128to64, mkexpr(sV)) );
11756
11757 putXMMReg(
11758 gregOfRM(modrm),
11759 binop(Iop_64HLtoV128,
11760 dis_PMULHRSW_helper( mkexpr(sHi), mkexpr(dHi) ),
11761 dis_PMULHRSW_helper( mkexpr(sLo), mkexpr(dLo) )
11762 )
11763 );
11764 goto decode_success;
11765 }
11766
11767 /* 0F 38 08 = PSIGNB -- Packed Sign 8x8 (MMX) */
11768 /* 0F 38 09 = PSIGNW -- Packed Sign 16x4 (MMX) */
11769 /* 0F 38 09 = PSIGND -- Packed Sign 32x2 (MMX) */
11770 if (sz == 4
11771 && insn[0] == 0x0F && insn[1] == 0x38
11772 && (insn[2] == 0x08 || insn[2] == 0x09 || insn[2] == 0x0A)) {
11773 IRTemp sV = newTemp(Ity_I64);
11774 IRTemp dV = newTemp(Ity_I64);
11775 HChar* str = "???";
11776 Int laneszB = 0;
11777
11778 switch (insn[2]) {
11779 case 0x08: laneszB = 1; str = "b"; break;
11780 case 0x09: laneszB = 2; str = "w"; break;
11781 case 0x0A: laneszB = 4; str = "d"; break;
11782 default: vassert(0);
11783 }
11784
11785 modrm = insn[3];
11786 do_MMX_preamble();
11787 assign( dV, getMMXReg(gregOfRM(modrm)) );
11788
11789 if (epartIsReg(modrm)) {
11790 assign( sV, getMMXReg(eregOfRM(modrm)) );
11791 delta += 3+1;
11792 DIP("psign%s %s,%s\n", str, nameMMXReg(eregOfRM(modrm)),
11793 nameMMXReg(gregOfRM(modrm)));
11794 } else {
11795 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
11796 assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
11797 delta += 3+alen;
11798 DIP("psign%s %s,%s\n", str, dis_buf,
11799 nameMMXReg(gregOfRM(modrm)));
11800 }
11801
11802 putMMXReg(
11803 gregOfRM(modrm),
11804 dis_PSIGN_helper( mkexpr(sV), mkexpr(dV), laneszB )
11805 );
11806 goto decode_success;
11807 }
11808
11809 /* 66 0F 38 08 = PSIGNB -- Packed Sign 8x16 (XMM) */
11810 /* 66 0F 38 09 = PSIGNW -- Packed Sign 16x8 (XMM) */
11811 /* 66 0F 38 09 = PSIGND -- Packed Sign 32x4 (XMM) */
11812 if (sz == 2
11813 && insn[0] == 0x0F && insn[1] == 0x38
11814 && (insn[2] == 0x08 || insn[2] == 0x09 || insn[2] == 0x0A)) {
11815 IRTemp sV = newTemp(Ity_V128);
11816 IRTemp dV = newTemp(Ity_V128);
11817 IRTemp sHi = newTemp(Ity_I64);
11818 IRTemp sLo = newTemp(Ity_I64);
11819 IRTemp dHi = newTemp(Ity_I64);
11820 IRTemp dLo = newTemp(Ity_I64);
11821 HChar* str = "???";
11822 Int laneszB = 0;
11823
11824 switch (insn[2]) {
11825 case 0x08: laneszB = 1; str = "b"; break;
11826 case 0x09: laneszB = 2; str = "w"; break;
11827 case 0x0A: laneszB = 4; str = "d"; break;
11828 default: vassert(0);
11829 }
11830
11831 modrm = insn[3];
11832 assign( dV, getXMMReg(gregOfRM(modrm)) );
11833
11834 if (epartIsReg(modrm)) {
11835 assign( sV, getXMMReg(eregOfRM(modrm)) );
11836 delta += 3+1;
11837 DIP("psign%s %s,%s\n", str, nameXMMReg(eregOfRM(modrm)),
11838 nameXMMReg(gregOfRM(modrm)));
11839 } else {
11840 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
11841 gen_SEGV_if_not_16_aligned( addr );
11842 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
11843 delta += 3+alen;
11844 DIP("psign%s %s,%s\n", str, dis_buf,
11845 nameXMMReg(gregOfRM(modrm)));
11846 }
11847
11848 assign( dHi, unop(Iop_V128HIto64, mkexpr(dV)) );
11849 assign( dLo, unop(Iop_V128to64, mkexpr(dV)) );
11850 assign( sHi, unop(Iop_V128HIto64, mkexpr(sV)) );
11851 assign( sLo, unop(Iop_V128to64, mkexpr(sV)) );
11852
11853 putXMMReg(
11854 gregOfRM(modrm),
11855 binop(Iop_64HLtoV128,
11856 dis_PSIGN_helper( mkexpr(sHi), mkexpr(dHi), laneszB ),
11857 dis_PSIGN_helper( mkexpr(sLo), mkexpr(dLo), laneszB )
11858 )
11859 );
11860 goto decode_success;
11861 }
11862
11863 /* 0F 38 1C = PABSB -- Packed Absolute Value 8x8 (MMX) */
11864 /* 0F 38 1D = PABSW -- Packed Absolute Value 16x4 (MMX) */
11865 /* 0F 38 1E = PABSD -- Packed Absolute Value 32x2 (MMX) */
11866 if (sz == 4
11867 && insn[0] == 0x0F && insn[1] == 0x38
11868 && (insn[2] == 0x1C || insn[2] == 0x1D || insn[2] == 0x1E)) {
11869 IRTemp sV = newTemp(Ity_I64);
11870 HChar* str = "???";
11871 Int laneszB = 0;
11872
11873 switch (insn[2]) {
11874 case 0x1C: laneszB = 1; str = "b"; break;
11875 case 0x1D: laneszB = 2; str = "w"; break;
11876 case 0x1E: laneszB = 4; str = "d"; break;
11877 default: vassert(0);
11878 }
11879
11880 modrm = insn[3];
11881 do_MMX_preamble();
11882
11883 if (epartIsReg(modrm)) {
11884 assign( sV, getMMXReg(eregOfRM(modrm)) );
11885 delta += 3+1;
11886 DIP("pabs%s %s,%s\n", str, nameMMXReg(eregOfRM(modrm)),
11887 nameMMXReg(gregOfRM(modrm)));
11888 } else {
11889 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
11890 assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
11891 delta += 3+alen;
11892 DIP("pabs%s %s,%s\n", str, dis_buf,
11893 nameMMXReg(gregOfRM(modrm)));
11894 }
11895
11896 putMMXReg(
11897 gregOfRM(modrm),
11898 dis_PABS_helper( mkexpr(sV), laneszB )
11899 );
11900 goto decode_success;
11901 }
11902
11903 /* 66 0F 38 1C = PABSB -- Packed Absolute Value 8x16 (XMM) */
11904 /* 66 0F 38 1D = PABSW -- Packed Absolute Value 16x8 (XMM) */
11905 /* 66 0F 38 1E = PABSD -- Packed Absolute Value 32x4 (XMM) */
11906 if (sz == 2
11907 && insn[0] == 0x0F && insn[1] == 0x38
11908 && (insn[2] == 0x1C || insn[2] == 0x1D || insn[2] == 0x1E)) {
11909 IRTemp sV = newTemp(Ity_V128);
11910 IRTemp sHi = newTemp(Ity_I64);
11911 IRTemp sLo = newTemp(Ity_I64);
11912 HChar* str = "???";
11913 Int laneszB = 0;
11914
11915 switch (insn[2]) {
11916 case 0x1C: laneszB = 1; str = "b"; break;
11917 case 0x1D: laneszB = 2; str = "w"; break;
11918 case 0x1E: laneszB = 4; str = "d"; break;
11919 default: vassert(0);
11920 }
11921
11922 modrm = insn[3];
11923
11924 if (epartIsReg(modrm)) {
11925 assign( sV, getXMMReg(eregOfRM(modrm)) );
11926 delta += 3+1;
11927 DIP("pabs%s %s,%s\n", str, nameXMMReg(eregOfRM(modrm)),
11928 nameXMMReg(gregOfRM(modrm)));
11929 } else {
11930 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
11931 gen_SEGV_if_not_16_aligned( addr );
11932 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
11933 delta += 3+alen;
11934 DIP("pabs%s %s,%s\n", str, dis_buf,
11935 nameXMMReg(gregOfRM(modrm)));
11936 }
11937
11938 assign( sHi, unop(Iop_V128HIto64, mkexpr(sV)) );
11939 assign( sLo, unop(Iop_V128to64, mkexpr(sV)) );
11940
11941 putXMMReg(
11942 gregOfRM(modrm),
11943 binop(Iop_64HLtoV128,
11944 dis_PABS_helper( mkexpr(sHi), laneszB ),
11945 dis_PABS_helper( mkexpr(sLo), laneszB )
11946 )
11947 );
11948 goto decode_success;
11949 }
11950
11951 /* 0F 3A 0F = PALIGNR -- Packed Align Right (MMX) */
11952 if (sz == 4
11953 && insn[0] == 0x0F && insn[1] == 0x3A && insn[2] == 0x0F) {
11954 IRTemp sV = newTemp(Ity_I64);
11955 IRTemp dV = newTemp(Ity_I64);
11956 IRTemp res = newTemp(Ity_I64);
11957
11958 modrm = insn[3];
11959 do_MMX_preamble();
11960 assign( dV, getMMXReg(gregOfRM(modrm)) );
11961
11962 if (epartIsReg(modrm)) {
11963 assign( sV, getMMXReg(eregOfRM(modrm)) );
11964 d32 = (UInt)insn[3+1];
11965 delta += 3+1+1;
11966 DIP("palignr $%d,%s,%s\n", (Int)d32,
11967 nameMMXReg(eregOfRM(modrm)),
11968 nameMMXReg(gregOfRM(modrm)));
11969 } else {
11970 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
11971 assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
11972 d32 = (UInt)insn[3+alen];
11973 delta += 3+alen+1;
11974 DIP("palignr $%d%s,%s\n", (Int)d32,
11975 dis_buf,
11976 nameMMXReg(gregOfRM(modrm)));
11977 }
11978
11979 if (d32 == 0) {
11980 assign( res, mkexpr(sV) );
11981 }
11982 else if (d32 >= 1 && d32 <= 7) {
11983 assign(res,
11984 binop(Iop_Or64,
11985 binop(Iop_Shr64, mkexpr(sV), mkU8(8*d32)),
11986 binop(Iop_Shl64, mkexpr(dV), mkU8(8*(8-d32))
11987 )));
11988 }
11989 else if (d32 == 8) {
11990 assign( res, mkexpr(dV) );
11991 }
11992 else if (d32 >= 9 && d32 <= 15) {
11993 assign( res, binop(Iop_Shr64, mkexpr(dV), mkU8(8*(d32-8))) );
11994 }
11995 else if (d32 >= 16 && d32 <= 255) {
11996 assign( res, mkU64(0) );
11997 }
11998 else
11999 vassert(0);
12000
12001 putMMXReg( gregOfRM(modrm), mkexpr(res) );
12002 goto decode_success;
12003 }
12004
12005 /* 66 0F 3A 0F = PALIGNR -- Packed Align Right (XMM) */
12006 if (sz == 2
12007 && insn[0] == 0x0F && insn[1] == 0x3A && insn[2] == 0x0F) {
12008 IRTemp sV = newTemp(Ity_V128);
12009 IRTemp dV = newTemp(Ity_V128);
12010 IRTemp sHi = newTemp(Ity_I64);
12011 IRTemp sLo = newTemp(Ity_I64);
12012 IRTemp dHi = newTemp(Ity_I64);
12013 IRTemp dLo = newTemp(Ity_I64);
12014 IRTemp rHi = newTemp(Ity_I64);
12015 IRTemp rLo = newTemp(Ity_I64);
12016
12017 modrm = insn[3];
12018 assign( dV, getXMMReg(gregOfRM(modrm)) );
12019
12020 if (epartIsReg(modrm)) {
12021 assign( sV, getXMMReg(eregOfRM(modrm)) );
12022 d32 = (UInt)insn[3+1];
12023 delta += 3+1+1;
12024 DIP("palignr $%d,%s,%s\n", (Int)d32,
12025 nameXMMReg(eregOfRM(modrm)),
12026 nameXMMReg(gregOfRM(modrm)));
12027 } else {
12028 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12029 gen_SEGV_if_not_16_aligned( addr );
12030 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
12031 d32 = (UInt)insn[3+alen];
12032 delta += 3+alen+1;
12033 DIP("palignr $%d,%s,%s\n", (Int)d32,
12034 dis_buf,
12035 nameXMMReg(gregOfRM(modrm)));
12036 }
12037
12038 assign( dHi, unop(Iop_V128HIto64, mkexpr(dV)) );
12039 assign( dLo, unop(Iop_V128to64, mkexpr(dV)) );
12040 assign( sHi, unop(Iop_V128HIto64, mkexpr(sV)) );
12041 assign( sLo, unop(Iop_V128to64, mkexpr(sV)) );
12042
12043 if (d32 == 0) {
12044 assign( rHi, mkexpr(sHi) );
12045 assign( rLo, mkexpr(sLo) );
12046 }
12047 else if (d32 >= 1 && d32 <= 7) {
12048 assign( rHi, dis_PALIGNR_XMM_helper(dLo, sHi, d32) );
12049 assign( rLo, dis_PALIGNR_XMM_helper(sHi, sLo, d32) );
12050 }
12051 else if (d32 == 8) {
12052 assign( rHi, mkexpr(dLo) );
12053 assign( rLo, mkexpr(sHi) );
12054 }
12055 else if (d32 >= 9 && d32 <= 15) {
12056 assign( rHi, dis_PALIGNR_XMM_helper(dHi, dLo, d32-8) );
12057 assign( rLo, dis_PALIGNR_XMM_helper(dLo, sHi, d32-8) );
12058 }
12059 else if (d32 == 16) {
12060 assign( rHi, mkexpr(dHi) );
12061 assign( rLo, mkexpr(dLo) );
12062 }
12063 else if (d32 >= 17 && d32 <= 23) {
12064 assign( rHi, binop(Iop_Shr64, mkexpr(dHi), mkU8(8*(d32-16))) );
12065 assign( rLo, dis_PALIGNR_XMM_helper(dHi, dLo, d32-16) );
12066 }
12067 else if (d32 == 24) {
12068 assign( rHi, mkU64(0) );
12069 assign( rLo, mkexpr(dHi) );
12070 }
12071 else if (d32 >= 25 && d32 <= 31) {
12072 assign( rHi, mkU64(0) );
12073 assign( rLo, binop(Iop_Shr64, mkexpr(dHi), mkU8(8*(d32-24))) );
12074 }
12075 else if (d32 >= 32 && d32 <= 255) {
12076 assign( rHi, mkU64(0) );
12077 assign( rLo, mkU64(0) );
12078 }
12079 else
12080 vassert(0);
12081
12082 putXMMReg(
12083 gregOfRM(modrm),
12084 binop(Iop_64HLtoV128, mkexpr(rHi), mkexpr(rLo))
12085 );
12086 goto decode_success;
12087 }
12088
12089 /* 0F 38 00 = PSHUFB -- Packed Shuffle Bytes 8x8 (MMX) */
12090 if (sz == 4
12091 && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x00) {
12092 IRTemp sV = newTemp(Ity_I64);
12093 IRTemp dV = newTemp(Ity_I64);
12094
12095 modrm = insn[3];
12096 do_MMX_preamble();
12097 assign( dV, getMMXReg(gregOfRM(modrm)) );
12098
12099 if (epartIsReg(modrm)) {
12100 assign( sV, getMMXReg(eregOfRM(modrm)) );
12101 delta += 3+1;
12102 DIP("pshufb %s,%s\n", nameMMXReg(eregOfRM(modrm)),
12103 nameMMXReg(gregOfRM(modrm)));
12104 } else {
12105 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12106 assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
12107 delta += 3+alen;
12108 DIP("pshufb %s,%s\n", dis_buf,
12109 nameMMXReg(gregOfRM(modrm)));
12110 }
12111
12112 putMMXReg(
12113 gregOfRM(modrm),
12114 binop(
12115 Iop_And64,
12116 /* permute the lanes */
12117 binop(
12118 Iop_Perm8x8,
12119 mkexpr(dV),
12120 binop(Iop_And64, mkexpr(sV), mkU64(0x0707070707070707ULL))
12121 ),
12122 /* mask off lanes which have (index & 0x80) == 0x80 */
12123 unop(Iop_Not64, binop(Iop_SarN8x8, mkexpr(sV), mkU8(7)))
12124 )
12125 );
12126 goto decode_success;
12127 }
12128
12129 /* 66 0F 38 00 = PSHUFB -- Packed Shuffle Bytes 8x16 (XMM) */
12130 if (sz == 2
12131 && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x00) {
12132 IRTemp sV = newTemp(Ity_V128);
12133 IRTemp dV = newTemp(Ity_V128);
12134 IRTemp sHi = newTemp(Ity_I64);
12135 IRTemp sLo = newTemp(Ity_I64);
12136 IRTemp dHi = newTemp(Ity_I64);
12137 IRTemp dLo = newTemp(Ity_I64);
12138 IRTemp rHi = newTemp(Ity_I64);
12139 IRTemp rLo = newTemp(Ity_I64);
12140 IRTemp sevens = newTemp(Ity_I64);
12141 IRTemp mask0x80hi = newTemp(Ity_I64);
12142 IRTemp mask0x80lo = newTemp(Ity_I64);
12143 IRTemp maskBit3hi = newTemp(Ity_I64);
12144 IRTemp maskBit3lo = newTemp(Ity_I64);
12145 IRTemp sAnd7hi = newTemp(Ity_I64);
12146 IRTemp sAnd7lo = newTemp(Ity_I64);
12147 IRTemp permdHi = newTemp(Ity_I64);
12148 IRTemp permdLo = newTemp(Ity_I64);
12149
12150 modrm = insn[3];
12151 assign( dV, getXMMReg(gregOfRM(modrm)) );
12152
12153 if (epartIsReg(modrm)) {
12154 assign( sV, getXMMReg(eregOfRM(modrm)) );
12155 delta += 3+1;
12156 DIP("pshufb %s,%s\n", nameXMMReg(eregOfRM(modrm)),
12157 nameXMMReg(gregOfRM(modrm)));
12158 } else {
12159 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
12160 gen_SEGV_if_not_16_aligned( addr );
12161 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
12162 delta += 3+alen;
12163 DIP("pshufb %s,%s\n", dis_buf,
12164 nameXMMReg(gregOfRM(modrm)));
12165 }
12166
12167 assign( dHi, unop(Iop_V128HIto64, mkexpr(dV)) );
12168 assign( dLo, unop(Iop_V128to64, mkexpr(dV)) );
12169 assign( sHi, unop(Iop_V128HIto64, mkexpr(sV)) );
12170 assign( sLo, unop(Iop_V128to64, mkexpr(sV)) );
12171
12172 assign( sevens, mkU64(0x0707070707070707ULL) );
12173
12174 /*
12175 mask0x80hi = Not(SarN8x8(sHi,7))
12176 maskBit3hi = SarN8x8(ShlN8x8(sHi,4),7)
12177 sAnd7hi = And(sHi,sevens)
12178 permdHi = Or( And(Perm8x8(dHi,sAnd7hi),maskBit3hi),
12179 And(Perm8x8(dLo,sAnd7hi),Not(maskBit3hi)) )
12180 rHi = And(permdHi,mask0x80hi)
12181 */
12182 assign(
12183 mask0x80hi,
12184 unop(Iop_Not64, binop(Iop_SarN8x8,mkexpr(sHi),mkU8(7))));
12185
12186 assign(
12187 maskBit3hi,
12188 binop(Iop_SarN8x8,
12189 binop(Iop_ShlN8x8,mkexpr(sHi),mkU8(4)),
12190 mkU8(7)));
12191
12192 assign(sAnd7hi, binop(Iop_And64,mkexpr(sHi),mkexpr(sevens)));
12193
12194 assign(
12195 permdHi,
12196 binop(
12197 Iop_Or64,
12198 binop(Iop_And64,
12199 binop(Iop_Perm8x8,mkexpr(dHi),mkexpr(sAnd7hi)),
12200 mkexpr(maskBit3hi)),
12201 binop(Iop_And64,
12202 binop(Iop_Perm8x8,mkexpr(dLo),mkexpr(sAnd7hi)),
12203 unop(Iop_Not64,mkexpr(maskBit3hi))) ));
12204
12205 assign(rHi, binop(Iop_And64,mkexpr(permdHi),mkexpr(mask0x80hi)) );
12206
12207 /* And the same for the lower half of the result. What fun. */
12208
12209 assign(
12210 mask0x80lo,
12211 unop(Iop_Not64, binop(Iop_SarN8x8,mkexpr(sLo),mkU8(7))));
12212
12213 assign(
12214 maskBit3lo,
12215 binop(Iop_SarN8x8,
12216 binop(Iop_ShlN8x8,mkexpr(sLo),mkU8(4)),
12217 mkU8(7)));
12218
12219 assign(sAnd7lo, binop(Iop_And64,mkexpr(sLo),mkexpr(sevens)));
12220
12221 assign(
12222 permdLo,
12223 binop(
12224 Iop_Or64,
12225 binop(Iop_And64,
12226 binop(Iop_Perm8x8,mkexpr(dHi),mkexpr(sAnd7lo)),
12227 mkexpr(maskBit3lo)),
12228 binop(Iop_And64,
12229 binop(Iop_Perm8x8,mkexpr(dLo),mkexpr(sAnd7lo)),
12230 unop(Iop_Not64,mkexpr(maskBit3lo))) ));
12231
12232 assign(rLo, binop(Iop_And64,mkexpr(permdLo),mkexpr(mask0x80lo)) );
12233
12234 putXMMReg(
12235 gregOfRM(modrm),
12236 binop(Iop_64HLtoV128, mkexpr(rHi), mkexpr(rLo))
12237 );
12238 goto decode_success;
12239 }
12240
12241 /* ---------------------------------------------------- */
12242 /* --- end of the SSSE3 decoder. --- */
12243 /* ---------------------------------------------------- */
12244
sewardj9df271d2004-12-31 22:37:42 +000012245 after_sse_decoders:
12246
sewardjdc5d0842006-11-16 10:42:02 +000012247 /* ---------------------------------------------------- */
12248 /* --- deal with misc 0x67 pfxs (addr size override) -- */
12249 /* ---------------------------------------------------- */
12250
12251 /* 67 E3 = JCXZ (for JECXZ see below) */
12252 if (insn[0] == 0x67 && insn[1] == 0xE3 && sz == 4) {
12253 delta += 2;
12254 d32 = (((Addr32)guest_EIP_bbstart)+delta+1) + getSDisp8(delta);
12255 delta ++;
12256 stmt( IRStmt_Exit(
12257 binop(Iop_CmpEQ16, getIReg(2,R_ECX), mkU16(0)),
12258 Ijk_Boring,
12259 IRConst_U32(d32)
12260 ));
12261 DIP("jcxz 0x%x\n", d32);
12262 goto decode_success;
12263 }
12264
12265 /* ---------------------------------------------------- */
12266 /* --- start of the baseline insn decoder -- */
12267 /* ---------------------------------------------------- */
12268
sewardjc9a65702004-07-07 16:32:57 +000012269 /* Get the primary opcode. */
12270 opc = getIByte(delta); delta++;
12271
12272 /* We get here if the current insn isn't SSE, or this CPU doesn't
12273 support SSE. */
12274
12275 switch (opc) {
12276
12277 /* ------------------------ Control flow --------------- */
sewardj940e8c92004-07-11 16:53:24 +000012278
12279 case 0xC2: /* RET imm16 */
12280 d32 = getUDisp16(delta);
12281 delta += 2;
12282 dis_ret(d32);
sewardj9e6491a2005-07-02 19:24:10 +000012283 dres.whatNext = Dis_StopHere;
sewardj2d49b432005-02-01 00:37:06 +000012284 DIP("ret %d\n", (Int)d32);
sewardj940e8c92004-07-11 16:53:24 +000012285 break;
sewardje05c42c2004-07-08 20:25:10 +000012286 case 0xC3: /* RET */
12287 dis_ret(0);
sewardj9e6491a2005-07-02 19:24:10 +000012288 dres.whatNext = Dis_StopHere;
sewardje05c42c2004-07-08 20:25:10 +000012289 DIP("ret\n");
12290 break;
sewardj0e9a0f52008-01-04 01:22:41 +000012291
12292 case 0xCF: /* IRET */
12293 /* Note, this is an extremely kludgey and limited implementation
12294 of iret. All it really does is:
12295 popl %EIP; popl %CS; popl %EFLAGS.
12296 %CS is set but ignored (as it is in (eg) popw %cs)". */
12297 t1 = newTemp(Ity_I32); /* ESP */
12298 t2 = newTemp(Ity_I32); /* new EIP */
12299 t3 = newTemp(Ity_I32); /* new CS */
12300 t4 = newTemp(Ity_I32); /* new EFLAGS */
12301 assign(t1, getIReg(4,R_ESP));
12302 assign(t2, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t1),mkU32(0) )));
12303 assign(t3, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t1),mkU32(4) )));
12304 assign(t4, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t1),mkU32(8) )));
12305 /* Get stuff off stack */
12306 putIReg(4, R_ESP,binop(Iop_Add32, mkexpr(t1), mkU32(12)));
12307 /* set %CS (which is ignored anyway) */
12308 putSReg( R_CS, unop(Iop_32to16, mkexpr(t3)) );
12309 /* set %EFLAGS */
12310 set_EFLAGS_from_value( t4, False/*!emit_AC_emwarn*/, 0/*unused*/ );
12311 /* goto new EIP value */
12312 jmp_treg(Ijk_Ret,t2);
12313 dres.whatNext = Dis_StopHere;
12314 DIP("iret (very kludgey)\n");
12315 break;
12316
sewardjd1061ab2004-07-08 01:45:30 +000012317 case 0xE8: /* CALL J4 */
12318 d32 = getUDisp32(delta); delta += 4;
sewardj9e6491a2005-07-02 19:24:10 +000012319 d32 += (guest_EIP_bbstart+delta);
sewardjce70a5c2004-10-18 14:09:54 +000012320 /* (guest_eip_bbstart+delta) == return-to addr, d32 == call-to addr */
sewardj9e6491a2005-07-02 19:24:10 +000012321 if (d32 == guest_EIP_bbstart+delta && getIByte(delta) >= 0x58
sewardjce70a5c2004-10-18 14:09:54 +000012322 && getIByte(delta) <= 0x5F) {
sewardjd1061ab2004-07-08 01:45:30 +000012323 /* Specially treat the position-independent-code idiom
12324 call X
12325 X: popl %reg
12326 as
12327 movl %eip, %reg.
12328 since this generates better code, but for no other reason. */
12329 Int archReg = getIByte(delta) - 0x58;
sewardjc2ac51e2004-07-12 01:03:26 +000012330 /* vex_printf("-- fPIC thingy\n"); */
sewardj9e6491a2005-07-02 19:24:10 +000012331 putIReg(4, archReg, mkU32(guest_EIP_bbstart+delta));
sewardjd1061ab2004-07-08 01:45:30 +000012332 delta++; /* Step over the POP */
12333 DIP("call 0x%x ; popl %s\n",d32,nameIReg(4,archReg));
sewardjc2ac51e2004-07-12 01:03:26 +000012334 } else {
sewardjd1061ab2004-07-08 01:45:30 +000012335 /* The normal sequence for a call. */
12336 t1 = newTemp(Ity_I32);
sewardj41f43bc2004-07-08 14:23:22 +000012337 assign(t1, binop(Iop_Sub32, getIReg(4,R_ESP), mkU32(4)));
12338 putIReg(4, R_ESP, mkexpr(t1));
sewardj9e6491a2005-07-02 19:24:10 +000012339 storeLE( mkexpr(t1), mkU32(guest_EIP_bbstart+delta));
sewardjc716aea2006-01-17 01:48:46 +000012340 if (resteerOkFn( callback_opaque, (Addr64)(Addr32)d32 )) {
sewardjce70a5c2004-10-18 14:09:54 +000012341 /* follow into the call target. */
sewardj9e6491a2005-07-02 19:24:10 +000012342 dres.whatNext = Dis_Resteer;
12343 dres.continueAt = (Addr64)(Addr32)d32;
sewardjce70a5c2004-10-18 14:09:54 +000012344 } else {
12345 jmp_lit(Ijk_Call,d32);
sewardj9e6491a2005-07-02 19:24:10 +000012346 dres.whatNext = Dis_StopHere;
sewardjce70a5c2004-10-18 14:09:54 +000012347 }
sewardjd1061ab2004-07-08 01:45:30 +000012348 DIP("call 0x%x\n",d32);
12349 }
12350 break;
12351
sewardjc9a65702004-07-07 16:32:57 +000012352//-- case 0xC8: /* ENTER */
12353//-- d32 = getUDisp16(eip); eip += 2;
12354//-- abyte = getIByte(delta); delta++;
12355//--
12356//-- vg_assert(sz == 4);
12357//-- vg_assert(abyte == 0);
12358//--
12359//-- t1 = newTemp(cb); t2 = newTemp(cb);
12360//-- uInstr2(cb, GET, sz, ArchReg, R_EBP, TempReg, t1);
12361//-- uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t2);
12362//-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
12363//-- uLiteral(cb, sz);
12364//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
12365//-- uInstr2(cb, STORE, 4, TempReg, t1, TempReg, t2);
12366//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_EBP);
12367//-- if (d32) {
12368//-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
sewardj5bd4d162004-11-10 13:02:48 +000012369//-- uLiteral(cb, d32);
12370//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
sewardjc9a65702004-07-07 16:32:57 +000012371//-- }
12372//-- DIP("enter 0x%x, 0x%x", d32, abyte);
12373//-- break;
sewardjc2ac51e2004-07-12 01:03:26 +000012374
12375 case 0xC9: /* LEAVE */
12376 vassert(sz == 4);
12377 t1 = newTemp(Ity_I32); t2 = newTemp(Ity_I32);
12378 assign(t1, getIReg(4,R_EBP));
12379 /* First PUT ESP looks redundant, but need it because ESP must
12380 always be up-to-date for Memcheck to work... */
12381 putIReg(4, R_ESP, mkexpr(t1));
12382 assign(t2, loadLE(Ity_I32,mkexpr(t1)));
12383 putIReg(4, R_EBP, mkexpr(t2));
12384 putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t1), mkU32(4)) );
12385 DIP("leave\n");
12386 break;
12387
sewardj8edc36b2007-11-23 02:46:29 +000012388 /* ---------------- Misc weird-ass insns --------------- */
12389
12390 case 0x27: /* DAA */
12391 case 0x2F: /* DAS */
12392 case 0x37: /* AAA */
12393 case 0x3F: /* AAS */
12394 /* An ugly implementation for some ugly instructions. Oh
12395 well. */
12396 if (sz != 4) goto decode_failure;
12397 t1 = newTemp(Ity_I32);
12398 t2 = newTemp(Ity_I32);
12399 /* Make up a 32-bit value (t1), with the old value of AX in the
12400 bottom 16 bits, and the old OSZACP bitmask in the upper 16
12401 bits. */
12402 assign(t1,
12403 binop(Iop_16HLto32,
12404 unop(Iop_32to16,
12405 mk_x86g_calculate_eflags_all()),
12406 getIReg(2, R_EAX)
12407 ));
12408 /* Call the helper fn, to get a new AX and OSZACP value, and
12409 poke both back into the guest state. Also pass the helper
12410 the actual opcode so it knows which of the 4 instructions it
12411 is doing the computation for. */
12412 vassert(opc == 0x27 || opc == 0x2F || opc == 0x37 || opc == 0x3F);
12413 assign(t2,
12414 mkIRExprCCall(
12415 Ity_I32, 0/*regparm*/, "x86g_calculate_daa_das_aaa_aas",
12416 &x86g_calculate_daa_das_aaa_aas,
12417 mkIRExprVec_2( mkexpr(t1), mkU32( opc & 0xFF) )
12418 ));
12419 putIReg(2, R_EAX, unop(Iop_32to16, mkexpr(t2) ));
12420
12421 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
12422 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
12423 stmt( IRStmt_Put( OFFB_CC_DEP1,
12424 binop(Iop_And32,
12425 binop(Iop_Shr32, mkexpr(t2), mkU8(16)),
12426 mkU32( X86G_CC_MASK_C | X86G_CC_MASK_P
12427 | X86G_CC_MASK_A | X86G_CC_MASK_Z
12428 | X86G_CC_MASK_S| X86G_CC_MASK_O )
12429 )
12430 )
12431 );
12432 /* Set NDEP even though it isn't used. This makes redundant-PUT
12433 elimination of previous stores to this field work better. */
12434 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
12435 switch (opc) {
12436 case 0x27: DIP("daa\n"); break;
12437 case 0x2F: DIP("das\n"); break;
12438 case 0x37: DIP("aaa\n"); break;
12439 case 0x3F: DIP("aas\n"); break;
12440 default: vassert(0);
12441 }
12442 break;
12443
sewardjc9a65702004-07-07 16:32:57 +000012444//-- case 0xD4: /* AAM */
12445//-- case 0xD5: /* AAD */
12446//-- d32 = getIByte(delta); delta++;
12447//-- if (d32 != 10) VG_(core_panic)("disInstr: AAM/AAD but base not 10 !");
12448//-- t1 = newTemp(cb);
12449//-- uInstr2(cb, GET, 2, ArchReg, R_EAX, TempReg, t1);
12450//-- /* Widen %AX to 32 bits, so it's all defined when we push it. */
12451//-- uInstr1(cb, WIDEN, 4, TempReg, t1);
12452//-- uWiden(cb, 2, False);
12453//-- uInstr0(cb, CALLM_S, 0);
12454//-- uInstr1(cb, PUSH, 4, TempReg, t1);
12455//-- uInstr1(cb, CALLM, 0, Lit16,
12456//-- opc == 0xD4 ? VGOFF_(helper_AAM) : VGOFF_(helper_AAD) );
12457//-- uFlagsRWU(cb, FlagsEmpty, FlagsSZP, FlagsEmpty);
12458//-- uInstr1(cb, POP, 4, TempReg, t1);
12459//-- uInstr0(cb, CALLM_E, 0);
12460//-- uInstr2(cb, PUT, 2, TempReg, t1, ArchReg, R_EAX);
12461//-- DIP(opc == 0xD4 ? "aam\n" : "aad\n");
12462//-- break;
sewardj1c6f9912004-09-07 10:15:24 +000012463
12464 /* ------------------------ CWD/CDQ -------------------- */
12465
12466 case 0x98: /* CBW */
12467 if (sz == 4) {
12468 putIReg(4, R_EAX, unop(Iop_16Sto32, getIReg(2, R_EAX)));
12469 DIP("cwde\n");
12470 } else {
sewardj47341042004-09-19 11:55:46 +000012471 vassert(sz == 2);
12472 putIReg(2, R_EAX, unop(Iop_8Sto16, getIReg(1, R_EAX)));
12473 DIP("cbw\n");
sewardj1c6f9912004-09-07 10:15:24 +000012474 }
12475 break;
sewardj64e1d652004-07-12 14:00:46 +000012476
12477 case 0x99: /* CWD/CDQ */
12478 ty = szToITy(sz);
12479 putIReg(sz, R_EDX,
12480 binop(mkSizedOp(ty,Iop_Sar8),
12481 getIReg(sz, R_EAX),
sewardj9ee82862004-12-14 01:16:59 +000012482 mkU8(sz == 2 ? 15 : 31)) );
sewardj64e1d652004-07-12 14:00:46 +000012483 DIP(sz == 2 ? "cwdq\n" : "cdqq\n");
12484 break;
12485
sewardjbdc7d212004-09-09 02:46:40 +000012486 /* ------------------------ FPU ops -------------------- */
12487
12488 case 0x9E: /* SAHF */
12489 codegen_SAHF();
12490 DIP("sahf\n");
12491 break;
12492
sewardj8dfdc8a2005-10-03 11:39:02 +000012493 case 0x9F: /* LAHF */
12494 codegen_LAHF();
12495 DIP("lahf\n");
12496 break;
12497
sewardjbdc7d212004-09-09 02:46:40 +000012498 case 0x9B: /* FWAIT */
12499 /* ignore? */
12500 DIP("fwait\n");
12501 break;
12502
sewardjd1725d12004-08-12 20:46:53 +000012503 case 0xD8:
12504 case 0xD9:
12505 case 0xDA:
12506 case 0xDB:
12507 case 0xDC:
12508 case 0xDD:
12509 case 0xDE:
12510 case 0xDF: {
sewardj52d04912005-07-03 00:52:48 +000012511 Int delta0 = delta;
sewardjd1725d12004-08-12 20:46:53 +000012512 Bool decode_OK = False;
12513 delta = dis_FPU ( &decode_OK, sorb, delta );
12514 if (!decode_OK) {
12515 delta = delta0;
12516 goto decode_failure;
12517 }
12518 break;
12519 }
sewardj0611d802004-07-11 02:37:54 +000012520
12521 /* ------------------------ INC & DEC ------------------ */
12522
12523 case 0x40: /* INC eAX */
12524 case 0x41: /* INC eCX */
12525 case 0x42: /* INC eDX */
12526 case 0x43: /* INC eBX */
12527 case 0x44: /* INC eSP */
12528 case 0x45: /* INC eBP */
12529 case 0x46: /* INC eSI */
12530 case 0x47: /* INC eDI */
12531 vassert(sz == 2 || sz == 4);
12532 ty = szToITy(sz);
12533 t1 = newTemp(ty);
12534 assign( t1, binop(mkSizedOp(ty,Iop_Add8),
12535 getIReg(sz, (UInt)(opc - 0x40)),
12536 mkU(ty,1)) );
12537 setFlags_INC_DEC( True, t1, ty );
12538 putIReg(sz, (UInt)(opc - 0x40), mkexpr(t1));
12539 DIP("inc%c %s\n", nameISize(sz), nameIReg(sz,opc-0x40));
12540 break;
12541
12542 case 0x48: /* DEC eAX */
12543 case 0x49: /* DEC eCX */
12544 case 0x4A: /* DEC eDX */
12545 case 0x4B: /* DEC eBX */
12546 case 0x4C: /* DEC eSP */
12547 case 0x4D: /* DEC eBP */
12548 case 0x4E: /* DEC eSI */
12549 case 0x4F: /* DEC eDI */
12550 vassert(sz == 2 || sz == 4);
12551 ty = szToITy(sz);
12552 t1 = newTemp(ty);
12553 assign( t1, binop(mkSizedOp(ty,Iop_Sub8),
12554 getIReg(sz, (UInt)(opc - 0x48)),
12555 mkU(ty,1)) );
12556 setFlags_INC_DEC( False, t1, ty );
12557 putIReg(sz, (UInt)(opc - 0x48), mkexpr(t1));
12558 DIP("dec%c %s\n", nameISize(sz), nameIReg(sz,opc-0x48));
12559 break;
12560
12561 /* ------------------------ INT ------------------------ */
12562
sewardj322bfa02007-02-28 23:31:42 +000012563 case 0xCC: /* INT 3 */
sewardj0f500042007-08-29 09:09:17 +000012564 jmp_lit(Ijk_SigTRAP,((Addr32)guest_EIP_bbstart)+delta);
sewardj322bfa02007-02-28 23:31:42 +000012565 dres.whatNext = Dis_StopHere;
12566 DIP("int $0x3\n");
12567 break;
12568
sewardj0611d802004-07-11 02:37:54 +000012569 case 0xCD: /* INT imm8 */
12570 d32 = getIByte(delta); delta++;
sewardj0f500042007-08-29 09:09:17 +000012571
12572 /* Handle int $0x40 .. $0x43 by synthesising a segfault and a
12573 restart of this instruction (hence the "-2" two lines below,
12574 to get the restart EIP to be this instruction. This is
12575 probably Linux-specific and it would be more correct to only
12576 do this if the VexAbiInfo says that is what we should do. */
12577 if (d32 >= 0x40 && d32 <= 0x43) {
12578 jmp_lit(Ijk_SigSEGV,((Addr32)guest_EIP_bbstart)+delta-2);
12579 dres.whatNext = Dis_StopHere;
12580 DIP("int $0x%x\n", (Int)d32);
12581 break;
12582 }
12583
sewardj0611d802004-07-11 02:37:54 +000012584 if (d32 != 0x80) goto decode_failure;
12585 /* It's important that all ArchRegs carry their up-to-date value
12586 at this point. So we declare an end-of-block here, which
12587 forces any TempRegs caching ArchRegs to be flushed. */
sewardj4fa325a2005-11-03 13:27:24 +000012588 jmp_lit(Ijk_Sys_int128,((Addr32)guest_EIP_bbstart)+delta);
sewardj9e6491a2005-07-02 19:24:10 +000012589 dres.whatNext = Dis_StopHere;
sewardj0611d802004-07-11 02:37:54 +000012590 DIP("int $0x80\n");
12591 break;
12592
sewardj77b86be2004-07-11 13:28:24 +000012593 /* ------------------------ Jcond, byte offset --------- */
12594
12595 case 0xEB: /* Jb (jump, byte offset) */
sewardj9e6491a2005-07-02 19:24:10 +000012596 d32 = (((Addr32)guest_EIP_bbstart)+delta+1) + getSDisp8(delta);
sewardj77b86be2004-07-11 13:28:24 +000012597 delta++;
sewardjc716aea2006-01-17 01:48:46 +000012598 if (resteerOkFn( callback_opaque, (Addr64)(Addr32)d32) ) {
sewardj9e6491a2005-07-02 19:24:10 +000012599 dres.whatNext = Dis_Resteer;
12600 dres.continueAt = (Addr64)(Addr32)d32;
sewardjce70a5c2004-10-18 14:09:54 +000012601 } else {
12602 jmp_lit(Ijk_Boring,d32);
sewardj9e6491a2005-07-02 19:24:10 +000012603 dres.whatNext = Dis_StopHere;
sewardjce70a5c2004-10-18 14:09:54 +000012604 }
sewardj77b86be2004-07-11 13:28:24 +000012605 DIP("jmp-8 0x%x\n", d32);
12606 break;
sewardj0611d802004-07-11 02:37:54 +000012607
12608 case 0xE9: /* Jv (jump, 16/32 offset) */
12609 vassert(sz == 4); /* JRS added 2004 July 11 */
sewardj9e6491a2005-07-02 19:24:10 +000012610 d32 = (((Addr32)guest_EIP_bbstart)+delta+sz) + getSDisp(sz,delta);
sewardj0611d802004-07-11 02:37:54 +000012611 delta += sz;
sewardjc716aea2006-01-17 01:48:46 +000012612 if (resteerOkFn( callback_opaque, (Addr64)(Addr32)d32) ) {
sewardj9e6491a2005-07-02 19:24:10 +000012613 dres.whatNext = Dis_Resteer;
12614 dres.continueAt = (Addr64)(Addr32)d32;
sewardjce70a5c2004-10-18 14:09:54 +000012615 } else {
12616 jmp_lit(Ijk_Boring,d32);
sewardj9e6491a2005-07-02 19:24:10 +000012617 dres.whatNext = Dis_StopHere;
sewardjce70a5c2004-10-18 14:09:54 +000012618 }
sewardj0611d802004-07-11 02:37:54 +000012619 DIP("jmp 0x%x\n", d32);
12620 break;
sewardje87b4842004-07-10 12:23:30 +000012621
12622 case 0x70:
12623 case 0x71:
12624 case 0x72: /* JBb/JNAEb (jump below) */
12625 case 0x73: /* JNBb/JAEb (jump not below) */
12626 case 0x74: /* JZb/JEb (jump zero) */
12627 case 0x75: /* JNZb/JNEb (jump not zero) */
12628 case 0x76: /* JBEb/JNAb (jump below or equal) */
12629 case 0x77: /* JNBEb/JAb (jump not below or equal) */
12630 case 0x78: /* JSb (jump negative) */
12631 case 0x79: /* JSb (jump not negative) */
12632 case 0x7A: /* JP (jump parity even) */
12633 case 0x7B: /* JNP/JPO (jump parity odd) */
12634 case 0x7C: /* JLb/JNGEb (jump less) */
12635 case 0x7D: /* JGEb/JNLb (jump greater or equal) */
12636 case 0x7E: /* JLEb/JNGb (jump less or equal) */
12637 case 0x7F: /* JGb/JNLEb (jump greater) */
sewardj9e6491a2005-07-02 19:24:10 +000012638 d32 = (((Addr32)guest_EIP_bbstart)+delta+1) + getSDisp8(delta);
sewardje87b4842004-07-10 12:23:30 +000012639 delta++;
sewardjc716aea2006-01-17 01:48:46 +000012640 if (0 && resteerOkFn( callback_opaque, (Addr64)(Addr32)d32) ) {
sewardj9e6491a2005-07-02 19:24:10 +000012641 /* Unused experimental hack: speculatively follow one arm
12642 of a conditional branch. */
sewardjdbf550c2005-01-24 11:54:11 +000012643 /* Assume the branch is taken. So we need to emit a
12644 side-exit to the insn following this one, on the negation
12645 of the condition, and continue at the branch target
12646 address (d32). */
12647 if (0) vex_printf("resteer\n");
12648 stmt( IRStmt_Exit(
12649 mk_x86g_calculate_condition((X86Condcode)(1 ^ (opc - 0x70))),
12650 Ijk_Boring,
sewardj9e6491a2005-07-02 19:24:10 +000012651 IRConst_U32(guest_EIP_bbstart+delta) ) );
12652 dres.whatNext = Dis_Resteer;
12653 dres.continueAt = (Addr64)(Addr32)d32;
sewardjdbf550c2005-01-24 11:54:11 +000012654 } else {
sewardj9e6491a2005-07-02 19:24:10 +000012655 jcc_01((X86Condcode)(opc - 0x70), (Addr32)(guest_EIP_bbstart+delta), d32);
12656 dres.whatNext = Dis_StopHere;
sewardjdbf550c2005-01-24 11:54:11 +000012657 }
sewardj2a9ad022004-11-25 02:46:58 +000012658 DIP("j%s-8 0x%x\n", name_X86Condcode(opc - 0x70), d32);
sewardje87b4842004-07-10 12:23:30 +000012659 break;
12660
sewardjdc5d0842006-11-16 10:42:02 +000012661 case 0xE3: /* JECXZ (for JCXZ see above) */
sewardjbaa66082005-08-23 17:29:27 +000012662 if (sz != 4) goto decode_failure;
sewardj9e6491a2005-07-02 19:24:10 +000012663 d32 = (((Addr32)guest_EIP_bbstart)+delta+1) + getSDisp8(delta);
sewardjdc5d0842006-11-16 10:42:02 +000012664 delta ++;
sewardj458a6f82004-08-25 12:46:02 +000012665 stmt( IRStmt_Exit(
sewardjdc5d0842006-11-16 10:42:02 +000012666 binop(Iop_CmpEQ32, getIReg(4,R_ECX), mkU32(0)),
sewardj893aada2004-11-29 19:57:54 +000012667 Ijk_Boring,
sewardjdc5d0842006-11-16 10:42:02 +000012668 IRConst_U32(d32)
12669 ));
12670 DIP("jecxz 0x%x\n", d32);
sewardj458a6f82004-08-25 12:46:02 +000012671 break;
12672
sewardjbaa66082005-08-23 17:29:27 +000012673 case 0xE0: /* LOOPNE disp8: decrement count, jump if count != 0 && ZF==0 */
12674 case 0xE1: /* LOOPE disp8: decrement count, jump if count != 0 && ZF==1 */
12675 case 0xE2: /* LOOP disp8: decrement count, jump if count != 0 */
12676 { /* Again, the docs say this uses ECX/CX as a count depending on
12677 the address size override, not the operand one. Since we
12678 don't handle address size overrides, I guess that means
12679 ECX. */
12680 IRExpr* zbit = NULL;
12681 IRExpr* count = NULL;
12682 IRExpr* cond = NULL;
12683 HChar* xtra = NULL;
12684
12685 if (sz != 4) goto decode_failure;
12686 d32 = (((Addr32)guest_EIP_bbstart)+delta+1) + getSDisp8(delta);
12687 delta++;
12688 putIReg(4, R_ECX, binop(Iop_Sub32, getIReg(4,R_ECX), mkU32(1)));
12689
12690 count = getIReg(4,R_ECX);
12691 cond = binop(Iop_CmpNE32, count, mkU32(0));
12692 switch (opc) {
12693 case 0xE2:
12694 xtra = "";
12695 break;
12696 case 0xE1:
12697 xtra = "e";
12698 zbit = mk_x86g_calculate_condition( X86CondZ );
12699 cond = mkAnd1(cond, zbit);
12700 break;
12701 case 0xE0:
12702 xtra = "ne";
12703 zbit = mk_x86g_calculate_condition( X86CondNZ );
12704 cond = mkAnd1(cond, zbit);
12705 break;
12706 default:
12707 vassert(0);
12708 }
12709 stmt( IRStmt_Exit(cond, Ijk_Boring, IRConst_U32(d32)) );
12710
12711 DIP("loop%s 0x%x\n", xtra, d32);
12712 break;
12713 }
sewardj1813dbe2004-07-28 17:09:04 +000012714
12715 /* ------------------------ IMUL ----------------------- */
12716
12717 case 0x69: /* IMUL Iv, Ev, Gv */
12718 delta = dis_imul_I_E_G ( sorb, sz, delta, sz );
12719 break;
12720 case 0x6B: /* IMUL Ib, Ev, Gv */
12721 delta = dis_imul_I_E_G ( sorb, sz, delta, 1 );
12722 break;
sewardj0611d802004-07-11 02:37:54 +000012723
12724 /* ------------------------ MOV ------------------------ */
12725
12726 case 0x88: /* MOV Gb,Eb */
12727 delta = dis_mov_G_E(sorb, 1, delta);
12728 break;
sewardjc9a65702004-07-07 16:32:57 +000012729
12730 case 0x89: /* MOV Gv,Ev */
12731 delta = dis_mov_G_E(sorb, sz, delta);
12732 break;
12733
sewardjc2ac51e2004-07-12 01:03:26 +000012734 case 0x8A: /* MOV Eb,Gb */
12735 delta = dis_mov_E_G(sorb, 1, delta);
12736 break;
sewardje05c42c2004-07-08 20:25:10 +000012737
12738 case 0x8B: /* MOV Ev,Gv */
12739 delta = dis_mov_E_G(sorb, sz, delta);
12740 break;
12741
sewardje87b4842004-07-10 12:23:30 +000012742 case 0x8D: /* LEA M,Gv */
sewardje9460bd2005-01-28 13:45:42 +000012743 if (sz != 4)
12744 goto decode_failure;
sewardje05c42c2004-07-08 20:25:10 +000012745 modrm = getIByte(delta);
12746 if (epartIsReg(modrm))
sewardje9460bd2005-01-28 13:45:42 +000012747 goto decode_failure;
sewardje05c42c2004-07-08 20:25:10 +000012748 /* NOTE! this is the one place where a segment override prefix
12749 has no effect on the address calculation. Therefore we pass
12750 zero instead of sorb here. */
sewardje87b4842004-07-10 12:23:30 +000012751 addr = disAMode ( &alen, /*sorb*/ 0, delta, dis_buf );
12752 delta += alen;
sewardj940e8c92004-07-11 16:53:24 +000012753 putIReg(sz, gregOfRM(modrm), mkexpr(addr));
sewardje05c42c2004-07-08 20:25:10 +000012754 DIP("lea%c %s, %s\n", nameISize(sz), dis_buf,
12755 nameIReg(sz,gregOfRM(modrm)));
12756 break;
sewardje05c42c2004-07-08 20:25:10 +000012757
sewardj063f02f2004-10-20 12:36:12 +000012758 case 0x8C: /* MOV Sw,Ew -- MOV from a SEGMENT REGISTER */
12759 delta = dis_mov_Sw_Ew(sorb, sz, delta);
12760 break;
12761
sewardj7df596b2004-12-06 14:29:12 +000012762 case 0x8E: /* MOV Ew,Sw -- MOV to a SEGMENT REGISTER */
12763 delta = dis_mov_Ew_Sw(sorb, delta);
12764 break;
12765
sewardj43852812004-10-16 23:10:08 +000012766 case 0xA0: /* MOV Ob,AL */
12767 sz = 1;
12768 /* Fall through ... */
sewardj0c12ea82004-07-12 08:18:16 +000012769 case 0xA1: /* MOV Ov,eAX */
12770 d32 = getUDisp32(delta); delta += 4;
12771 ty = szToITy(sz);
12772 addr = newTemp(Ity_I32);
12773 assign( addr, handleSegOverride(sorb, mkU32(d32)) );
12774 putIReg(sz, R_EAX, loadLE(ty, mkexpr(addr)));
12775 DIP("mov%c %s0x%x, %s\n", nameISize(sz), sorbTxt(sorb),
12776 d32, nameIReg(sz,R_EAX));
12777 break;
12778
sewardj180e8b32004-07-29 01:40:11 +000012779 case 0xA2: /* MOV Ob,AL */
12780 sz = 1;
12781 /* Fall through ... */
sewardj750f4072004-07-26 22:39:11 +000012782 case 0xA3: /* MOV eAX,Ov */
12783 d32 = getUDisp32(delta); delta += 4;
12784 ty = szToITy(sz);
12785 addr = newTemp(Ity_I32);
12786 assign( addr, handleSegOverride(sorb, mkU32(d32)) );
12787 storeLE( mkexpr(addr), getIReg(sz,R_EAX) );
12788 DIP("mov%c %s, %s0x%x\n", nameISize(sz), nameIReg(sz,R_EAX),
12789 sorbTxt(sorb), d32);
12790 break;
sewardje87b4842004-07-10 12:23:30 +000012791
sewardjc2ac51e2004-07-12 01:03:26 +000012792 case 0xB0: /* MOV imm,AL */
12793 case 0xB1: /* MOV imm,CL */
12794 case 0xB2: /* MOV imm,DL */
12795 case 0xB3: /* MOV imm,BL */
12796 case 0xB4: /* MOV imm,AH */
12797 case 0xB5: /* MOV imm,CH */
12798 case 0xB6: /* MOV imm,DH */
12799 case 0xB7: /* MOV imm,BH */
12800 d32 = getIByte(delta); delta += 1;
12801 putIReg(1, opc-0xB0, mkU8(d32));
12802 DIP("movb $0x%x,%s\n", d32, nameIReg(1,opc-0xB0));
12803 break;
sewardj7ed22952004-07-29 00:09:58 +000012804
sewardje87b4842004-07-10 12:23:30 +000012805 case 0xB8: /* MOV imm,eAX */
12806 case 0xB9: /* MOV imm,eCX */
12807 case 0xBA: /* MOV imm,eDX */
12808 case 0xBB: /* MOV imm,eBX */
12809 case 0xBC: /* MOV imm,eSP */
12810 case 0xBD: /* MOV imm,eBP */
12811 case 0xBE: /* MOV imm,eSI */
12812 case 0xBF: /* MOV imm,eDI */
12813 d32 = getUDisp(sz,delta); delta += sz;
12814 putIReg(sz, opc-0xB8, mkU(szToITy(sz), d32));
12815 DIP("mov%c $0x%x,%s\n", nameISize(sz), d32, nameIReg(sz,opc-0xB8));
12816 break;
12817
sewardj77b86be2004-07-11 13:28:24 +000012818 case 0xC6: /* MOV Ib,Eb */
12819 sz = 1;
12820 goto do_Mov_I_E;
sewardje87b4842004-07-10 12:23:30 +000012821 case 0xC7: /* MOV Iv,Ev */
12822 goto do_Mov_I_E;
12823
12824 do_Mov_I_E:
12825 modrm = getIByte(delta);
12826 if (epartIsReg(modrm)) {
12827 delta++; /* mod/rm byte */
12828 d32 = getUDisp(sz,delta); delta += sz;
sewardj5bd4d162004-11-10 13:02:48 +000012829 putIReg(sz, eregOfRM(modrm), mkU(szToITy(sz), d32));
sewardje87b4842004-07-10 12:23:30 +000012830 DIP("mov%c $0x%x, %s\n", nameISize(sz), d32,
12831 nameIReg(sz,eregOfRM(modrm)));
sewardje87b4842004-07-10 12:23:30 +000012832 } else {
12833 addr = disAMode ( &alen, sorb, delta, dis_buf );
12834 delta += alen;
12835 d32 = getUDisp(sz,delta); delta += sz;
sewardj5bd4d162004-11-10 13:02:48 +000012836 storeLE(mkexpr(addr), mkU(szToITy(sz), d32));
sewardje87b4842004-07-10 12:23:30 +000012837 DIP("mov%c $0x%x, %s\n", nameISize(sz), d32, dis_buf);
12838 }
12839 break;
12840
sewardj1813dbe2004-07-28 17:09:04 +000012841 /* ------------------------ opl imm, A ----------------- */
12842
12843 case 0x04: /* ADD Ib, AL */
sewardja718d5d2005-04-03 14:59:54 +000012844 delta = dis_op_imm_A( 1, False, Iop_Add8, True, delta, "add" );
sewardj1813dbe2004-07-28 17:09:04 +000012845 break;
sewardj77b86be2004-07-11 13:28:24 +000012846 case 0x05: /* ADD Iv, eAX */
sewardja718d5d2005-04-03 14:59:54 +000012847 delta = dis_op_imm_A( sz, False, Iop_Add8, True, delta, "add" );
sewardj77b86be2004-07-11 13:28:24 +000012848 break;
12849
sewardj940e8c92004-07-11 16:53:24 +000012850 case 0x0C: /* OR Ib, AL */
sewardja718d5d2005-04-03 14:59:54 +000012851 delta = dis_op_imm_A( 1, False, Iop_Or8, True, delta, "or" );
sewardj940e8c92004-07-11 16:53:24 +000012852 break;
sewardj82292882004-07-27 00:15:59 +000012853 case 0x0D: /* OR Iv, eAX */
sewardja718d5d2005-04-03 14:59:54 +000012854 delta = dis_op_imm_A( sz, False, Iop_Or8, True, delta, "or" );
sewardj82292882004-07-27 00:15:59 +000012855 break;
12856
sewardjeca20362005-08-24 09:22:39 +000012857 case 0x14: /* ADC Ib, AL */
12858 delta = dis_op_imm_A( 1, True, Iop_Add8, True, delta, "adc" );
12859 break;
sewardja718d5d2005-04-03 14:59:54 +000012860 case 0x15: /* ADC Iv, eAX */
sewardjeca20362005-08-24 09:22:39 +000012861 delta = dis_op_imm_A( sz, True, Iop_Add8, True, delta, "adc" );
sewardja718d5d2005-04-03 14:59:54 +000012862 break;
12863
sewardj2fbae082005-10-03 02:07:08 +000012864 case 0x1C: /* SBB Ib, AL */
12865 delta = dis_op_imm_A( 1, True, Iop_Sub8, True, delta, "sbb" );
12866 break;
12867 case 0x1D: /* SBB Iv, eAX */
12868 delta = dis_op_imm_A( sz, True, Iop_Sub8, True, delta, "sbb" );
12869 break;
12870
sewardj940e8c92004-07-11 16:53:24 +000012871 case 0x24: /* AND Ib, AL */
sewardja718d5d2005-04-03 14:59:54 +000012872 delta = dis_op_imm_A( 1, False, Iop_And8, True, delta, "and" );
sewardj940e8c92004-07-11 16:53:24 +000012873 break;
sewardjc2ac51e2004-07-12 01:03:26 +000012874 case 0x25: /* AND Iv, eAX */
sewardja718d5d2005-04-03 14:59:54 +000012875 delta = dis_op_imm_A( sz, False, Iop_And8, True, delta, "and" );
sewardjc2ac51e2004-07-12 01:03:26 +000012876 break;
sewardj0611d802004-07-11 02:37:54 +000012877
12878 case 0x2C: /* SUB Ib, AL */
sewardja718d5d2005-04-03 14:59:54 +000012879 delta = dis_op_imm_A( 1, False, Iop_Sub8, True, delta, "sub" );
sewardj0611d802004-07-11 02:37:54 +000012880 break;
sewardj68511542004-07-28 00:15:44 +000012881 case 0x2D: /* SUB Iv, eAX */
sewardja718d5d2005-04-03 14:59:54 +000012882 delta = dis_op_imm_A( sz, False, Iop_Sub8, True, delta, "sub" );
sewardj68511542004-07-28 00:15:44 +000012883 break;
12884
sewardj1c6f9912004-09-07 10:15:24 +000012885 case 0x34: /* XOR Ib, AL */
sewardja718d5d2005-04-03 14:59:54 +000012886 delta = dis_op_imm_A( 1, False, Iop_Xor8, True, delta, "xor" );
sewardj1c6f9912004-09-07 10:15:24 +000012887 break;
sewardjcaca9d02004-07-28 07:11:32 +000012888 case 0x35: /* XOR Iv, eAX */
sewardja718d5d2005-04-03 14:59:54 +000012889 delta = dis_op_imm_A( sz, False, Iop_Xor8, True, delta, "xor" );
sewardjcaca9d02004-07-28 07:11:32 +000012890 break;
12891
sewardj0611d802004-07-11 02:37:54 +000012892 case 0x3C: /* CMP Ib, AL */
sewardja718d5d2005-04-03 14:59:54 +000012893 delta = dis_op_imm_A( 1, False, Iop_Sub8, False, delta, "cmp" );
sewardj0611d802004-07-11 02:37:54 +000012894 break;
12895 case 0x3D: /* CMP Iv, eAX */
sewardja718d5d2005-04-03 14:59:54 +000012896 delta = dis_op_imm_A( sz, False, Iop_Sub8, False, delta, "cmp" );
sewardj0611d802004-07-11 02:37:54 +000012897 break;
12898
sewardj77b86be2004-07-11 13:28:24 +000012899 case 0xA8: /* TEST Ib, AL */
sewardja718d5d2005-04-03 14:59:54 +000012900 delta = dis_op_imm_A( 1, False, Iop_And8, False, delta, "test" );
sewardj77b86be2004-07-11 13:28:24 +000012901 break;
sewardjc2ac51e2004-07-12 01:03:26 +000012902 case 0xA9: /* TEST Iv, eAX */
sewardja718d5d2005-04-03 14:59:54 +000012903 delta = dis_op_imm_A( sz, False, Iop_And8, False, delta, "test" );
sewardjc2ac51e2004-07-12 01:03:26 +000012904 break;
12905
sewardj1c6f9912004-09-07 10:15:24 +000012906 /* ------------------------ opl Ev, Gv ----------------- */
12907
sewardj89cd0932004-09-08 18:23:25 +000012908 case 0x02: /* ADD Eb,Gb */
12909 delta = dis_op2_E_G ( sorb, False, Iop_Add8, True, 1, delta, "add" );
12910 break;
sewardj9334b0f2004-07-10 22:43:54 +000012911 case 0x03: /* ADD Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +000012912 delta = dis_op2_E_G ( sorb, False, Iop_Add8, True, sz, delta, "add" );
sewardj9334b0f2004-07-10 22:43:54 +000012913 break;
12914
sewardj7ed22952004-07-29 00:09:58 +000012915 case 0x0A: /* OR Eb,Gb */
sewardj180e8b32004-07-29 01:40:11 +000012916 delta = dis_op2_E_G ( sorb, False, Iop_Or8, True, 1, delta, "or" );
sewardj7ed22952004-07-29 00:09:58 +000012917 break;
sewardjc2ac51e2004-07-12 01:03:26 +000012918 case 0x0B: /* OR Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +000012919 delta = dis_op2_E_G ( sorb, False, Iop_Or8, True, sz, delta, "or" );
sewardjc2ac51e2004-07-12 01:03:26 +000012920 break;
sewardj2fbae082005-10-03 02:07:08 +000012921
12922 case 0x12: /* ADC Eb,Gb */
12923 delta = dis_op2_E_G ( sorb, True, Iop_Add8, True, 1, delta, "adc" );
12924 break;
sewardjc4eaff32004-09-10 20:25:11 +000012925 case 0x13: /* ADC Ev,Gv */
12926 delta = dis_op2_E_G ( sorb, True, Iop_Add8, True, sz, delta, "adc" );
12927 break;
12928
sewardj2fbae082005-10-03 02:07:08 +000012929 case 0x1A: /* SBB Eb,Gb */
12930 delta = dis_op2_E_G ( sorb, True, Iop_Sub8, True, 1, delta, "sbb" );
12931 break;
sewardj180e8b32004-07-29 01:40:11 +000012932 case 0x1B: /* SBB Ev,Gv */
12933 delta = dis_op2_E_G ( sorb, True, Iop_Sub8, True, sz, delta, "sbb" );
sewardj940e8c92004-07-11 16:53:24 +000012934 break;
12935
sewardj1c6f9912004-09-07 10:15:24 +000012936 case 0x22: /* AND Eb,Gb */
12937 delta = dis_op2_E_G ( sorb, False, Iop_And8, True, 1, delta, "and" );
12938 break;
sewardj180e8b32004-07-29 01:40:11 +000012939 case 0x23: /* AND Ev,Gv */
12940 delta = dis_op2_E_G ( sorb, False, Iop_And8, True, sz, delta, "and" );
12941 break;
12942
12943 case 0x2A: /* SUB Eb,Gb */
12944 delta = dis_op2_E_G ( sorb, False, Iop_Sub8, True, 1, delta, "sub" );
12945 break;
sewardj0611d802004-07-11 02:37:54 +000012946 case 0x2B: /* SUB Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +000012947 delta = dis_op2_E_G ( sorb, False, Iop_Sub8, True, sz, delta, "sub" );
sewardj0611d802004-07-11 02:37:54 +000012948 break;
sewardjc2ac51e2004-07-12 01:03:26 +000012949
12950 case 0x32: /* XOR Eb,Gb */
sewardj180e8b32004-07-29 01:40:11 +000012951 delta = dis_op2_E_G ( sorb, False, Iop_Xor8, True, 1, delta, "xor" );
sewardjc2ac51e2004-07-12 01:03:26 +000012952 break;
sewardj1813dbe2004-07-28 17:09:04 +000012953 case 0x33: /* XOR Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +000012954 delta = dis_op2_E_G ( sorb, False, Iop_Xor8, True, sz, delta, "xor" );
sewardj1813dbe2004-07-28 17:09:04 +000012955 break;
12956
sewardjc2ac51e2004-07-12 01:03:26 +000012957 case 0x3A: /* CMP Eb,Gb */
sewardj180e8b32004-07-29 01:40:11 +000012958 delta = dis_op2_E_G ( sorb, False, Iop_Sub8, False, 1, delta, "cmp" );
sewardjc2ac51e2004-07-12 01:03:26 +000012959 break;
sewardje90ad6a2004-07-10 19:02:10 +000012960 case 0x3B: /* CMP Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +000012961 delta = dis_op2_E_G ( sorb, False, Iop_Sub8, False, sz, delta, "cmp" );
sewardje90ad6a2004-07-10 19:02:10 +000012962 break;
12963
sewardj0611d802004-07-11 02:37:54 +000012964 case 0x84: /* TEST Eb,Gb */
sewardj180e8b32004-07-29 01:40:11 +000012965 delta = dis_op2_E_G ( sorb, False, Iop_And8, False, 1, delta, "test" );
sewardj0611d802004-07-11 02:37:54 +000012966 break;
sewardje05c42c2004-07-08 20:25:10 +000012967 case 0x85: /* TEST Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +000012968 delta = dis_op2_E_G ( sorb, False, Iop_And8, False, sz, delta, "test" );
sewardje05c42c2004-07-08 20:25:10 +000012969 break;
12970
sewardj180e8b32004-07-29 01:40:11 +000012971 /* ------------------------ opl Gv, Ev ----------------- */
12972
12973 case 0x00: /* ADD Gb,Eb */
12974 delta = dis_op2_G_E ( sorb, False, Iop_Add8, True, 1, delta, "add" );
12975 break;
sewardje05c42c2004-07-08 20:25:10 +000012976 case 0x01: /* ADD Gv,Ev */
sewardjcaca9d02004-07-28 07:11:32 +000012977 delta = dis_op2_G_E ( sorb, False, Iop_Add8, True, sz, delta, "add" );
sewardje05c42c2004-07-08 20:25:10 +000012978 break;
12979
sewardj940e8c92004-07-11 16:53:24 +000012980 case 0x08: /* OR Gb,Eb */
sewardjcaca9d02004-07-28 07:11:32 +000012981 delta = dis_op2_G_E ( sorb, False, Iop_Or8, True, 1, delta, "or" );
sewardj940e8c92004-07-11 16:53:24 +000012982 break;
sewardj9334b0f2004-07-10 22:43:54 +000012983 case 0x09: /* OR Gv,Ev */
sewardjcaca9d02004-07-28 07:11:32 +000012984 delta = dis_op2_G_E ( sorb, False, Iop_Or8, True, sz, delta, "or" );
sewardj9334b0f2004-07-10 22:43:54 +000012985 break;
12986
sewardja2384712004-07-29 14:36:40 +000012987 case 0x10: /* ADC Gb,Eb */
12988 delta = dis_op2_G_E ( sorb, True, Iop_Add8, True, 1, delta, "adc" );
12989 break;
sewardjcaca9d02004-07-28 07:11:32 +000012990 case 0x11: /* ADC Gv,Ev */
12991 delta = dis_op2_G_E ( sorb, True, Iop_Add8, True, sz, delta, "adc" );
12992 break;
12993
sewardja2384712004-07-29 14:36:40 +000012994 case 0x18: /* SBB Gb,Eb */
12995 delta = dis_op2_G_E ( sorb, True, Iop_Sub8, True, 1, delta, "sbb" );
12996 break;
sewardjcaca9d02004-07-28 07:11:32 +000012997 case 0x19: /* SBB Gv,Ev */
12998 delta = dis_op2_G_E ( sorb, True, Iop_Sub8, True, sz, delta, "sbb" );
12999 break;
13000
sewardja2384712004-07-29 14:36:40 +000013001 case 0x20: /* AND Gb,Eb */
13002 delta = dis_op2_G_E ( sorb, False, Iop_And8, True, 1, delta, "and" );
13003 break;
sewardj0611d802004-07-11 02:37:54 +000013004 case 0x21: /* AND Gv,Ev */
sewardjcaca9d02004-07-28 07:11:32 +000013005 delta = dis_op2_G_E ( sorb, False, Iop_And8, True, sz, delta, "and" );
sewardj0611d802004-07-11 02:37:54 +000013006 break;
13007
sewardj180e8b32004-07-29 01:40:11 +000013008 case 0x28: /* SUB Gb,Eb */
13009 delta = dis_op2_G_E ( sorb, False, Iop_Sub8, True, 1, delta, "sub" );
13010 break;
sewardje05c42c2004-07-08 20:25:10 +000013011 case 0x29: /* SUB Gv,Ev */
sewardjcaca9d02004-07-28 07:11:32 +000013012 delta = dis_op2_G_E ( sorb, False, Iop_Sub8, True, sz, delta, "sub" );
sewardje05c42c2004-07-08 20:25:10 +000013013 break;
13014
sewardjc2ac51e2004-07-12 01:03:26 +000013015 case 0x30: /* XOR Gb,Eb */
sewardjcaca9d02004-07-28 07:11:32 +000013016 delta = dis_op2_G_E ( sorb, False, Iop_Xor8, True, 1, delta, "xor" );
sewardjc2ac51e2004-07-12 01:03:26 +000013017 break;
sewardje87b4842004-07-10 12:23:30 +000013018 case 0x31: /* XOR Gv,Ev */
sewardjcaca9d02004-07-28 07:11:32 +000013019 delta = dis_op2_G_E ( sorb, False, Iop_Xor8, True, sz, delta, "xor" );
sewardje87b4842004-07-10 12:23:30 +000013020 break;
13021
sewardj0611d802004-07-11 02:37:54 +000013022 case 0x38: /* CMP Gb,Eb */
sewardjcaca9d02004-07-28 07:11:32 +000013023 delta = dis_op2_G_E ( sorb, False, Iop_Sub8, False, 1, delta, "cmp" );
sewardj0611d802004-07-11 02:37:54 +000013024 break;
sewardje90ad6a2004-07-10 19:02:10 +000013025 case 0x39: /* CMP Gv,Ev */
sewardjcaca9d02004-07-28 07:11:32 +000013026 delta = dis_op2_G_E ( sorb, False, Iop_Sub8, False, sz, delta, "cmp" );
sewardje90ad6a2004-07-10 19:02:10 +000013027 break;
13028
sewardj9334b0f2004-07-10 22:43:54 +000013029 /* ------------------------ POP ------------------------ */
13030
13031 case 0x58: /* POP eAX */
13032 case 0x59: /* POP eCX */
13033 case 0x5A: /* POP eDX */
13034 case 0x5B: /* POP eBX */
13035 case 0x5D: /* POP eBP */
13036 case 0x5E: /* POP eSI */
13037 case 0x5F: /* POP eDI */
13038 case 0x5C: /* POP eSP */
13039 vassert(sz == 2 || sz == 4);
13040 t1 = newTemp(szToITy(sz)); t2 = newTemp(Ity_I32);
13041 assign(t2, getIReg(4, R_ESP));
13042 assign(t1, loadLE(szToITy(sz),mkexpr(t2)));
13043 putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t2), mkU32(sz)));
13044 putIReg(sz, opc-0x58, mkexpr(t1));
13045 DIP("pop%c %s\n", nameISize(sz), nameIReg(sz,opc-0x58));
13046 break;
13047
sewardja2384712004-07-29 14:36:40 +000013048 case 0x9D: /* POPF */
13049 vassert(sz == 2 || sz == 4);
sewardja2384712004-07-29 14:36:40 +000013050 t1 = newTemp(Ity_I32); t2 = newTemp(Ity_I32);
13051 assign(t2, getIReg(4, R_ESP));
sewardjc22a6fd2004-07-29 23:41:47 +000013052 assign(t1, widenUto32(loadLE(szToITy(sz),mkexpr(t2))));
sewardja2384712004-07-29 14:36:40 +000013053 putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t2), mkU32(sz)));
sewardja2384712004-07-29 14:36:40 +000013054
sewardj0e9a0f52008-01-04 01:22:41 +000013055 /* Generate IR to set %EFLAGS{O,S,Z,A,C,P,D,ID,AC} from the
13056 value in t1. */
13057 set_EFLAGS_from_value( t1, True/*emit_AC_emwarn*/,
13058 ((Addr32)guest_EIP_bbstart)+delta );
sewardj6d269842005-08-06 11:45:02 +000013059
sewardja2384712004-07-29 14:36:40 +000013060 DIP("popf%c\n", nameISize(sz));
13061 break;
13062
sewardjbbdc6222004-12-15 18:43:39 +000013063 case 0x61: /* POPA */
13064 /* This is almost certainly wrong for sz==2. So ... */
13065 if (sz != 4) goto decode_failure;
13066
13067 /* t5 is the old %ESP value. */
13068 t5 = newTemp(Ity_I32);
13069 assign( t5, getIReg(4, R_ESP) );
13070
13071 /* Reload all the registers, except %esp. */
13072 putIReg(4,R_EAX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(28)) ));
13073 putIReg(4,R_ECX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(24)) ));
13074 putIReg(4,R_EDX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(20)) ));
13075 putIReg(4,R_EBX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(16)) ));
13076 /* ignore saved %ESP */
13077 putIReg(4,R_EBP, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32( 8)) ));
13078 putIReg(4,R_ESI, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32( 4)) ));
13079 putIReg(4,R_EDI, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32( 0)) ));
13080
13081 /* and move %ESP back up */
13082 putIReg( 4, R_ESP, binop(Iop_Add32, mkexpr(t5), mkU32(8*4)) );
13083
sewardja3d1a662005-03-29 21:33:11 +000013084 DIP("popa%c\n", nameISize(sz));
sewardjbbdc6222004-12-15 18:43:39 +000013085 break;
sewardjfeeb8a82004-11-30 12:30:11 +000013086
13087 case 0x8F: /* POPL/POPW m32 */
sewardjfcff1782006-05-12 14:04:48 +000013088 { Int len;
13089 UChar rm = getIByte(delta);
sewardjfeeb8a82004-11-30 12:30:11 +000013090
13091 /* make sure this instruction is correct POP */
sewardjfcff1782006-05-12 14:04:48 +000013092 if (epartIsReg(rm) || gregOfRM(rm) != 0)
13093 goto decode_failure;
sewardjfeeb8a82004-11-30 12:30:11 +000013094 /* and has correct size */
sewardjfcff1782006-05-12 14:04:48 +000013095 if (sz != 4 && sz != 2)
13096 goto decode_failure;
13097 ty = szToITy(sz);
13098
13099 t1 = newTemp(Ity_I32); /* stack address */
13100 t3 = newTemp(ty); /* data */
sewardjfeeb8a82004-11-30 12:30:11 +000013101 /* set t1 to ESP: t1 = ESP */
13102 assign( t1, getIReg(4, R_ESP) );
13103 /* load M[ESP] to virtual register t3: t3 = M[t1] */
sewardjfcff1782006-05-12 14:04:48 +000013104 assign( t3, loadLE(ty, mkexpr(t1)) );
sewardjfeeb8a82004-11-30 12:30:11 +000013105
13106 /* increase ESP; must be done before the STORE. Intel manual says:
13107 If the ESP register is used as a base register for addressing
13108 a destination operand in memory, the POP instruction computes
13109 the effective address of the operand after it increments the
13110 ESP register.
13111 */
13112 putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t1), mkU32(sz)) );
13113
13114 /* resolve MODR/M */
13115 addr = disAMode ( &len, sorb, delta, dis_buf);
13116 storeLE( mkexpr(addr), mkexpr(t3) );
13117
sewardjfcff1782006-05-12 14:04:48 +000013118 DIP("pop%c %s\n", sz==2 ? 'w' : 'l', dis_buf);
sewardjfeeb8a82004-11-30 12:30:11 +000013119
13120 delta += len;
13121 break;
13122 }
13123
sewardj5c5f72c2006-03-18 11:29:25 +000013124 case 0x1F: /* POP %DS */
13125 dis_pop_segreg( R_DS, sz ); break;
13126 case 0x07: /* POP %ES */
13127 dis_pop_segreg( R_ES, sz ); break;
13128 case 0x17: /* POP %SS */
13129 dis_pop_segreg( R_SS, sz ); break;
sewardjd1061ab2004-07-08 01:45:30 +000013130
13131 /* ------------------------ PUSH ----------------------- */
13132
13133 case 0x50: /* PUSH eAX */
13134 case 0x51: /* PUSH eCX */
13135 case 0x52: /* PUSH eDX */
13136 case 0x53: /* PUSH eBX */
13137 case 0x55: /* PUSH eBP */
13138 case 0x56: /* PUSH eSI */
13139 case 0x57: /* PUSH eDI */
13140 case 0x54: /* PUSH eSP */
13141 /* This is the Right Way, in that the value to be pushed is
13142 established before %esp is changed, so that pushl %esp
13143 correctly pushes the old value. */
13144 vassert(sz == 2 || sz == 4);
13145 ty = sz==2 ? Ity_I16 : Ity_I32;
sewardj883b00b2004-09-11 09:30:24 +000013146 t1 = newTemp(ty); t2 = newTemp(Ity_I32);
sewardj41f43bc2004-07-08 14:23:22 +000013147 assign(t1, getIReg(sz, opc-0x50));
13148 assign(t2, binop(Iop_Sub32, getIReg(4, R_ESP), mkU32(sz)));
13149 putIReg(4, R_ESP, mkexpr(t2) );
13150 storeLE(mkexpr(t2),mkexpr(t1));
sewardjd1061ab2004-07-08 01:45:30 +000013151 DIP("push%c %s\n", nameISize(sz), nameIReg(sz,opc-0x50));
13152 break;
13153
13154
sewardj0c12ea82004-07-12 08:18:16 +000013155 case 0x68: /* PUSH Iv */
13156 d32 = getUDisp(sz,delta); delta += sz;
13157 goto do_push_I;
sewardj741153c2004-07-25 23:39:13 +000013158 case 0x6A: /* PUSH Ib, sign-extended to sz */
13159 d32 = getSDisp8(delta); delta += 1;
13160 goto do_push_I;
sewardj0c12ea82004-07-12 08:18:16 +000013161 do_push_I:
13162 ty = szToITy(sz);
13163 t1 = newTemp(Ity_I32); t2 = newTemp(ty);
13164 assign( t1, binop(Iop_Sub32,getIReg(4,R_ESP),mkU32(sz)) );
13165 putIReg(4, R_ESP, mkexpr(t1) );
sewardjc4255a02006-08-28 18:04:33 +000013166 /* stop mkU16 asserting if d32 is a negative 16-bit number
13167 (bug #132813) */
13168 if (ty == Ity_I16)
13169 d32 &= 0xFFFF;
sewardj0c12ea82004-07-12 08:18:16 +000013170 storeLE( mkexpr(t1), mkU(ty,d32) );
13171 DIP("push%c $0x%x\n", nameISize(sz), d32);
13172 break;
13173
sewardja2384712004-07-29 14:36:40 +000013174 case 0x9C: /* PUSHF */ {
sewardja2384712004-07-29 14:36:40 +000013175 vassert(sz == 2 || sz == 4);
sewardja2384712004-07-29 14:36:40 +000013176
13177 t1 = newTemp(Ity_I32);
13178 assign( t1, binop(Iop_Sub32,getIReg(4,R_ESP),mkU32(sz)) );
13179 putIReg(4, R_ESP, mkexpr(t1) );
13180
sewardjbc210942005-07-21 10:07:13 +000013181 /* Calculate OSZACP, and patch in fixed fields as per
13182 Intel docs.
13183 - bit 1 is always 1
13184 - bit 9 is Interrupt Enable (should always be 1 in user mode?)
13185 */
sewardja2384712004-07-29 14:36:40 +000013186 t2 = newTemp(Ity_I32);
sewardjbc210942005-07-21 10:07:13 +000013187 assign( t2, binop(Iop_Or32,
13188 mk_x86g_calculate_eflags_all(),
13189 mkU32( (1<<1)|(1<<9) ) ));
sewardja2384712004-07-29 14:36:40 +000013190
sewardjf9c74fe2004-12-16 02:54:54 +000013191 /* Patch in the D flag. This can simply be a copy of bit 10 of
13192 baseBlock[OFFB_DFLAG]. */
sewardja2384712004-07-29 14:36:40 +000013193 t3 = newTemp(Ity_I32);
13194 assign( t3, binop(Iop_Or32,
13195 mkexpr(t2),
13196 binop(Iop_And32,
sewardjf9c74fe2004-12-16 02:54:54 +000013197 IRExpr_Get(OFFB_DFLAG,Ity_I32),
sewardj5bd4d162004-11-10 13:02:48 +000013198 mkU32(1<<10)))
sewardja2384712004-07-29 14:36:40 +000013199 );
sewardj006a6a22004-10-26 00:50:52 +000013200
13201 /* And patch in the ID flag. */
13202 t4 = newTemp(Ity_I32);
13203 assign( t4, binop(Iop_Or32,
13204 mkexpr(t3),
13205 binop(Iop_And32,
sewardj5bd4d162004-11-10 13:02:48 +000013206 binop(Iop_Shl32, IRExpr_Get(OFFB_IDFLAG,Ity_I32),
sewardj006a6a22004-10-26 00:50:52 +000013207 mkU8(21)),
sewardj5bd4d162004-11-10 13:02:48 +000013208 mkU32(1<<21)))
sewardj006a6a22004-10-26 00:50:52 +000013209 );
13210
sewardj6d269842005-08-06 11:45:02 +000013211 /* And patch in the AC flag. */
13212 t5 = newTemp(Ity_I32);
13213 assign( t5, binop(Iop_Or32,
13214 mkexpr(t4),
13215 binop(Iop_And32,
13216 binop(Iop_Shl32, IRExpr_Get(OFFB_ACFLAG,Ity_I32),
13217 mkU8(18)),
13218 mkU32(1<<18)))
13219 );
13220
sewardja2384712004-07-29 14:36:40 +000013221 /* if sz==2, the stored value needs to be narrowed. */
13222 if (sz == 2)
sewardj6d269842005-08-06 11:45:02 +000013223 storeLE( mkexpr(t1), unop(Iop_32to16,mkexpr(t5)) );
sewardja2384712004-07-29 14:36:40 +000013224 else
sewardj6d269842005-08-06 11:45:02 +000013225 storeLE( mkexpr(t1), mkexpr(t5) );
sewardja2384712004-07-29 14:36:40 +000013226
13227 DIP("pushf%c\n", nameISize(sz));
13228 break;
13229 }
13230
sewardjbbdc6222004-12-15 18:43:39 +000013231 case 0x60: /* PUSHA */
13232 /* This is almost certainly wrong for sz==2. So ... */
13233 if (sz != 4) goto decode_failure;
13234
13235 /* This is the Right Way, in that the value to be pushed is
13236 established before %esp is changed, so that pusha
13237 correctly pushes the old %esp value. New value of %esp is
13238 pushed at start. */
13239 /* t0 is the %ESP value we're going to push. */
13240 t0 = newTemp(Ity_I32);
13241 assign( t0, getIReg(4, R_ESP) );
13242
13243 /* t5 will be the new %ESP value. */
13244 t5 = newTemp(Ity_I32);
13245 assign( t5, binop(Iop_Sub32, mkexpr(t0), mkU32(8*4)) );
13246
13247 /* Update guest state before prodding memory. */
13248 putIReg(4, R_ESP, mkexpr(t5));
13249
13250 /* Dump all the registers. */
13251 storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(28)), getIReg(4,R_EAX) );
13252 storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(24)), getIReg(4,R_ECX) );
13253 storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(20)), getIReg(4,R_EDX) );
13254 storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(16)), getIReg(4,R_EBX) );
13255 storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(12)), mkexpr(t0) /*esp*/);
13256 storeLE( binop(Iop_Add32,mkexpr(t5),mkU32( 8)), getIReg(4,R_EBP) );
13257 storeLE( binop(Iop_Add32,mkexpr(t5),mkU32( 4)), getIReg(4,R_ESI) );
13258 storeLE( binop(Iop_Add32,mkexpr(t5),mkU32( 0)), getIReg(4,R_EDI) );
13259
13260 DIP("pusha%c\n", nameISize(sz));
13261 break;
13262
sewardj5c5f72c2006-03-18 11:29:25 +000013263 case 0x0E: /* PUSH %CS */
13264 dis_push_segreg( R_CS, sz ); break;
13265 case 0x1E: /* PUSH %DS */
13266 dis_push_segreg( R_DS, sz ); break;
13267 case 0x06: /* PUSH %ES */
13268 dis_push_segreg( R_ES, sz ); break;
13269 case 0x16: /* PUSH %SS */
13270 dis_push_segreg( R_SS, sz ); break;
sewardj458a6f82004-08-25 12:46:02 +000013271
13272 /* ------------------------ SCAS et al ----------------- */
13273
13274 case 0xA4: /* MOVS, no REP prefix */
13275 case 0xA5:
sewardj9c3b25a2007-04-05 15:06:56 +000013276 if (sorb != 0)
13277 goto decode_failure; /* else dis_string_op asserts */
sewardj458a6f82004-08-25 12:46:02 +000013278 dis_string_op( dis_MOVS, ( opc == 0xA4 ? 1 : sz ), "movs", sorb );
13279 break;
13280
sewardj8d4d2232005-01-20 10:47:46 +000013281 case 0xA6: /* CMPSb, no REP prefix */
sewardj33b53542005-03-11 14:00:27 +000013282 case 0xA7:
sewardj9c3b25a2007-04-05 15:06:56 +000013283 if (sorb != 0)
13284 goto decode_failure; /* else dis_string_op asserts */
13285 dis_string_op( dis_CMPS, ( opc == 0xA6 ? 1 : sz ), "cmps", sorb );
13286 break;
sewardj33b53542005-03-11 14:00:27 +000013287
sewardj883b00b2004-09-11 09:30:24 +000013288 case 0xAA: /* STOS, no REP prefix */
sewardj47341042004-09-19 11:55:46 +000013289 case 0xAB:
sewardj9c3b25a2007-04-05 15:06:56 +000013290 if (sorb != 0)
13291 goto decode_failure; /* else dis_string_op asserts */
sewardj883b00b2004-09-11 09:30:24 +000013292 dis_string_op( dis_STOS, ( opc == 0xAA ? 1 : sz ), "stos", sorb );
13293 break;
sewardj33b53542005-03-11 14:00:27 +000013294
sewardj10ca4eb2005-05-30 11:19:54 +000013295 case 0xAC: /* LODS, no REP prefix */
13296 case 0xAD:
sewardj9c3b25a2007-04-05 15:06:56 +000013297 if (sorb != 0)
13298 goto decode_failure; /* else dis_string_op asserts */
sewardj10ca4eb2005-05-30 11:19:54 +000013299 dis_string_op( dis_LODS, ( opc == 0xAC ? 1 : sz ), "lods", sorb );
13300 break;
sewardj2d4c3a02004-10-15 00:03:23 +000013301
13302 case 0xAE: /* SCAS, no REP prefix */
13303 case 0xAF:
sewardj9c3b25a2007-04-05 15:06:56 +000013304 if (sorb != 0)
13305 goto decode_failure; /* else dis_string_op asserts */
sewardj2d4c3a02004-10-15 00:03:23 +000013306 dis_string_op( dis_SCAS, ( opc == 0xAE ? 1 : sz ), "scas", sorb );
13307 break;
sewardj64e1d652004-07-12 14:00:46 +000013308
13309
13310 case 0xFC: /* CLD */
sewardjeeb9ef82004-07-15 12:39:03 +000013311 stmt( IRStmt_Put( OFFB_DFLAG, mkU32(1)) );
sewardj64e1d652004-07-12 14:00:46 +000013312 DIP("cld\n");
13313 break;
13314
sewardj1813dbe2004-07-28 17:09:04 +000013315 case 0xFD: /* STD */
13316 stmt( IRStmt_Put( OFFB_DFLAG, mkU32(0xFFFFFFFF)) );
13317 DIP("std\n");
13318 break;
13319
sewardjbc210942005-07-21 10:07:13 +000013320 case 0xF8: /* CLC */
13321 case 0xF9: /* STC */
13322 case 0xF5: /* CMC */
13323 t0 = newTemp(Ity_I32);
13324 t1 = newTemp(Ity_I32);
13325 assign( t0, mk_x86g_calculate_eflags_all() );
13326 switch (opc) {
13327 case 0xF8:
13328 assign( t1, binop(Iop_And32, mkexpr(t0),
13329 mkU32(~X86G_CC_MASK_C)));
13330 DIP("clc\n");
13331 break;
13332 case 0xF9:
13333 assign( t1, binop(Iop_Or32, mkexpr(t0),
13334 mkU32(X86G_CC_MASK_C)));
13335 DIP("stc\n");
13336 break;
13337 case 0xF5:
13338 assign( t1, binop(Iop_Xor32, mkexpr(t0),
13339 mkU32(X86G_CC_MASK_C)));
13340 DIP("cmc\n");
13341 break;
13342 default:
13343 vpanic("disInstr(x86)(clc/stc/cmc)");
13344 }
13345 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
13346 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
13347 stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(t1) ));
13348 /* Set NDEP even though it isn't used. This makes redundant-PUT
13349 elimination of previous stores to this field work better. */
13350 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
13351 break;
sewardj82292882004-07-27 00:15:59 +000013352
sewardja384eb92007-11-16 02:30:38 +000013353 case 0xD6: /* SALC */
13354 t0 = newTemp(Ity_I32);
13355 t1 = newTemp(Ity_I32);
13356 assign( t0, binop(Iop_And32,
13357 mk_x86g_calculate_eflags_c(),
13358 mkU32(1)) );
13359 assign( t1, binop(Iop_Sar32,
13360 binop(Iop_Shl32, mkexpr(t0), mkU8(31)),
13361 mkU8(31)) );
13362 putIReg(1, R_EAX, unop(Iop_32to8, mkexpr(t1)) );
13363 DIP("salc\n");
13364 break;
13365
sewardj82292882004-07-27 00:15:59 +000013366 /* REPNE prefix insn */
13367 case 0xF2: {
sewardj068baa22008-05-11 10:11:58 +000013368 Addr32 eip_orig = guest_EIP_bbstart + delta_start;
sewardj9c3b25a2007-04-05 15:06:56 +000013369 if (sorb != 0) goto decode_failure;
sewardj82292882004-07-27 00:15:59 +000013370 abyte = getIByte(delta); delta++;
13371
13372 if (abyte == 0x66) { sz = 2; abyte = getIByte(delta); delta++; }
sewardj9e6491a2005-07-02 19:24:10 +000013373 dres.whatNext = Dis_StopHere;
sewardj82292882004-07-27 00:15:59 +000013374
13375 switch (abyte) {
13376 /* According to the Intel manual, "repne movs" should never occur, but
13377 * in practice it has happened, so allow for it here... */
sewardj180e8b32004-07-29 01:40:11 +000013378 case 0xA4: sz = 1; /* REPNE MOVS<sz> */
sewardjcea96622006-11-14 15:33:05 +000013379 case 0xA5:
13380 dis_REP_op ( X86CondNZ, dis_MOVS, sz, eip_orig,
13381 guest_EIP_bbstart+delta, "repne movs" );
13382 break;
sewardj842dfb42008-05-09 08:53:50 +000013383
13384 case 0xA6: sz = 1; /* REPNE CMP<sz> */
13385 case 0xA7:
13386 dis_REP_op ( X86CondNZ, dis_CMPS, sz, eip_orig,
13387 guest_EIP_bbstart+delta, "repne cmps" );
13388 break;
13389
sewardjb69a6fa2006-11-14 15:13:55 +000013390 case 0xAA: sz = 1; /* REPNE STOS<sz> */
13391 case 0xAB:
13392 dis_REP_op ( X86CondNZ, dis_STOS, sz, eip_orig,
13393 guest_EIP_bbstart+delta, "repne stos" );
13394 break;
13395
sewardj82292882004-07-27 00:15:59 +000013396 case 0xAE: sz = 1; /* REPNE SCAS<sz> */
sewardj2d4c3a02004-10-15 00:03:23 +000013397 case 0xAF:
sewardj2a9ad022004-11-25 02:46:58 +000013398 dis_REP_op ( X86CondNZ, dis_SCAS, sz, eip_orig,
sewardj9e6491a2005-07-02 19:24:10 +000013399 guest_EIP_bbstart+delta, "repne scas" );
sewardj82292882004-07-27 00:15:59 +000013400 break;
13401
13402 default:
13403 goto decode_failure;
13404 }
13405 break;
13406 }
sewardj64e1d652004-07-12 14:00:46 +000013407
13408 /* REP/REPE prefix insn (for SCAS and CMPS, 0xF3 means REPE,
13409 for the rest, it means REP) */
13410 case 0xF3: {
sewardj068baa22008-05-11 10:11:58 +000013411 Addr32 eip_orig = guest_EIP_bbstart + delta_start;
sewardj9c3b25a2007-04-05 15:06:56 +000013412 if (sorb != 0) goto decode_failure;
sewardj64e1d652004-07-12 14:00:46 +000013413 abyte = getIByte(delta); delta++;
13414
13415 if (abyte == 0x66) { sz = 2; abyte = getIByte(delta); delta++; }
sewardj9e6491a2005-07-02 19:24:10 +000013416 dres.whatNext = Dis_StopHere;
sewardj64e1d652004-07-12 14:00:46 +000013417
13418 switch (abyte) {
13419 case 0xA4: sz = 1; /* REP MOVS<sz> */
13420 case 0xA5:
sewardj2a9ad022004-11-25 02:46:58 +000013421 dis_REP_op ( X86CondAlways, dis_MOVS, sz, eip_orig,
sewardj9e6491a2005-07-02 19:24:10 +000013422 guest_EIP_bbstart+delta, "rep movs" );
sewardj64e1d652004-07-12 14:00:46 +000013423 break;
13424
13425 case 0xA6: sz = 1; /* REPE CMP<sz> */
sewardj2d4c3a02004-10-15 00:03:23 +000013426 case 0xA7:
sewardj2a9ad022004-11-25 02:46:58 +000013427 dis_REP_op ( X86CondZ, dis_CMPS, sz, eip_orig,
sewardj9e6491a2005-07-02 19:24:10 +000013428 guest_EIP_bbstart+delta, "repe cmps" );
sewardj64e1d652004-07-12 14:00:46 +000013429 break;
13430
13431 case 0xAA: sz = 1; /* REP STOS<sz> */
13432 case 0xAB:
sewardj2a9ad022004-11-25 02:46:58 +000013433 dis_REP_op ( X86CondAlways, dis_STOS, sz, eip_orig,
sewardj9e6491a2005-07-02 19:24:10 +000013434 guest_EIP_bbstart+delta, "rep stos" );
sewardj64e1d652004-07-12 14:00:46 +000013435 break;
sewardj576f3232006-04-12 17:30:46 +000013436
sewardjdfb038d2007-11-25 01:34:03 +000013437 case 0xAC: sz = 1; /* REP LODS<sz> */
13438 case 0xAD:
13439 dis_REP_op ( X86CondAlways, dis_LODS, sz, eip_orig,
13440 guest_EIP_bbstart+delta, "rep lods" );
13441 break;
13442
sewardj576f3232006-04-12 17:30:46 +000013443 case 0xAE: sz = 1; /* REPE SCAS<sz> */
13444 case 0xAF:
13445 dis_REP_op ( X86CondZ, dis_SCAS, sz, eip_orig,
13446 guest_EIP_bbstart+delta, "repe scas" );
13447 break;
sewardj43b8df12004-11-26 12:18:51 +000013448
13449 case 0x90: /* REP NOP (PAUSE) */
13450 /* a hint to the P4 re spin-wait loop */
13451 DIP("rep nop (P4 pause)\n");
sewardj7ec59f62005-03-12 16:47:18 +000013452 /* "observe" the hint. The Vex client needs to be careful not
13453 to cause very long delays as a result, though. */
sewardj9e6491a2005-07-02 19:24:10 +000013454 jmp_lit(Ijk_Yield, ((Addr32)guest_EIP_bbstart)+delta);
13455 dres.whatNext = Dis_StopHere;
sewardj43b8df12004-11-26 12:18:51 +000013456 break;
13457
sewardj7d3d3472005-08-12 23:51:31 +000013458 case 0xC3: /* REP RET -- same as normal ret? */
13459 dis_ret(0);
13460 dres.whatNext = Dis_StopHere;
13461 DIP("rep ret\n");
13462 break;
sewardj64e1d652004-07-12 14:00:46 +000013463
13464 default:
13465 goto decode_failure;
13466 }
13467 break;
13468 }
sewardj0611d802004-07-11 02:37:54 +000013469
13470 /* ------------------------ XCHG ----------------------- */
13471
sewardjc4356f02007-11-09 21:15:04 +000013472 /* XCHG reg,mem automatically asserts LOCK# even without a LOCK
13473 prefix. Therefore, surround it with a IRStmt_MBE(Imbe_BusLock)
13474 and IRStmt_MBE(Imbe_BusUnlock) pair. But be careful; if it is
13475 used with an explicit LOCK prefix, we don't want to end up with
13476 two IRStmt_MBE(Imbe_BusLock)s -- one made here and one made by
13477 the generic LOCK logic at the top of disInstr. */
sewardj0611d802004-07-11 02:37:54 +000013478 case 0x86: /* XCHG Gb,Eb */
13479 sz = 1;
13480 /* Fall through ... */
13481 case 0x87: /* XCHG Gv,Ev */
13482 modrm = getIByte(delta);
13483 ty = szToITy(sz);
13484 t1 = newTemp(ty); t2 = newTemp(ty);
13485 if (epartIsReg(modrm)) {
sewardj5bd4d162004-11-10 13:02:48 +000013486 assign(t1, getIReg(sz, eregOfRM(modrm)));
13487 assign(t2, getIReg(sz, gregOfRM(modrm)));
13488 putIReg(sz, gregOfRM(modrm), mkexpr(t1));
13489 putIReg(sz, eregOfRM(modrm), mkexpr(t2));
sewardj0611d802004-07-11 02:37:54 +000013490 delta++;
13491 DIP("xchg%c %s, %s\n",
13492 nameISize(sz), nameIReg(sz,gregOfRM(modrm)),
13493 nameIReg(sz,eregOfRM(modrm)));
13494 } else {
sewardjc4356f02007-11-09 21:15:04 +000013495 /* Need to add IRStmt_MBE(Imbe_BusLock). */
13496 if (pfx_lock) {
13497 /* check it's already been taken care of */
13498 vassert(unlock_bus_after_insn);
13499 } else {
13500 vassert(!unlock_bus_after_insn);
13501 stmt( IRStmt_MBE(Imbe_BusLock) );
13502 unlock_bus_after_insn = True;
13503 }
13504 /* Because unlock_bus_after_insn is now True, generic logic
13505 at the bottom of disInstr will add the
13506 IRStmt_MBE(Imbe_BusUnlock). */
sewardj0c12ea82004-07-12 08:18:16 +000013507 addr = disAMode ( &alen, sorb, delta, dis_buf );
sewardj5bd4d162004-11-10 13:02:48 +000013508 assign( t1, loadLE(ty,mkexpr(addr)) );
13509 assign( t2, getIReg(sz,gregOfRM(modrm)) );
13510 storeLE( mkexpr(addr), mkexpr(t2) );
13511 putIReg( sz, gregOfRM(modrm), mkexpr(t1) );
13512 delta += alen;
sewardj0611d802004-07-11 02:37:54 +000013513 DIP("xchg%c %s, %s\n", nameISize(sz),
13514 nameIReg(sz,gregOfRM(modrm)), dis_buf);
sewardj0611d802004-07-11 02:37:54 +000013515 }
13516 break;
sewardje87b4842004-07-10 12:23:30 +000013517
13518 case 0x90: /* XCHG eAX,eAX */
13519 DIP("nop\n");
13520 break;
sewardj64e1d652004-07-12 14:00:46 +000013521 case 0x91: /* XCHG eAX,eCX */
13522 case 0x92: /* XCHG eAX,eDX */
13523 case 0x93: /* XCHG eAX,eBX */
13524 case 0x94: /* XCHG eAX,eSP */
13525 case 0x95: /* XCHG eAX,eBP */
13526 case 0x96: /* XCHG eAX,eSI */
13527 case 0x97: /* XCHG eAX,eDI */
13528 codegen_xchg_eAX_Reg ( sz, opc - 0x90 );
13529 break;
13530
sewardj048de4d2006-11-12 22:25:21 +000013531 /* ------------------------ XLAT ----------------------- */
13532
13533 case 0xD7: /* XLAT */
13534 if (sz != 4) goto decode_failure; /* sz == 2 is also allowed (0x66) */
13535 putIReg(
13536 1,
13537 R_EAX/*AL*/,
13538 loadLE(Ity_I8,
13539 handleSegOverride(
13540 sorb,
13541 binop(Iop_Add32,
13542 getIReg(4, R_EBX),
13543 unop(Iop_8Uto32, getIReg(1, R_EAX/*AL*/))))));
13544
13545 DIP("xlat%c [ebx]\n", nameISize(sz));
13546 break;
sewardjd14c5702005-10-29 19:19:51 +000013547
13548 /* ------------------------ IN / OUT ----------------------- */
13549
13550 case 0xE4: /* IN imm8, AL */
13551 sz = 1;
13552 t1 = newTemp(Ity_I32);
13553 abyte = getIByte(delta); delta++;
13554 assign(t1, mkU32( abyte & 0xFF ));
13555 DIP("in%c $%d,%s\n", nameISize(sz), (Int)abyte, nameIReg(sz,R_EAX));
13556 goto do_IN;
13557 case 0xE5: /* IN imm8, eAX */
13558 vassert(sz == 2 || sz == 4);
13559 t1 = newTemp(Ity_I32);
13560 abyte = getIByte(delta); delta++;
13561 assign(t1, mkU32( abyte & 0xFF ));
13562 DIP("in%c $%d,%s\n", nameISize(sz), (Int)abyte, nameIReg(sz,R_EAX));
13563 goto do_IN;
13564 case 0xEC: /* IN %DX, AL */
13565 sz = 1;
13566 t1 = newTemp(Ity_I32);
13567 assign(t1, unop(Iop_16Uto32, getIReg(2, R_EDX)));
13568 DIP("in%c %s,%s\n", nameISize(sz), nameIReg(2,R_EDX),
13569 nameIReg(sz,R_EAX));
13570 goto do_IN;
13571 case 0xED: /* IN %DX, eAX */
13572 vassert(sz == 2 || sz == 4);
13573 t1 = newTemp(Ity_I32);
13574 assign(t1, unop(Iop_16Uto32, getIReg(2, R_EDX)));
13575 DIP("in%c %s,%s\n", nameISize(sz), nameIReg(2,R_EDX),
13576 nameIReg(sz,R_EAX));
13577 goto do_IN;
13578 do_IN: {
13579 /* At this point, sz indicates the width, and t1 is a 32-bit
13580 value giving port number. */
13581 IRDirty* d;
13582 vassert(sz == 1 || sz == 2 || sz == 4);
13583 ty = szToITy(sz);
13584 t2 = newTemp(Ity_I32);
13585 d = unsafeIRDirty_1_N(
13586 t2,
13587 0/*regparms*/,
13588 "x86g_dirtyhelper_IN",
13589 &x86g_dirtyhelper_IN,
13590 mkIRExprVec_2( mkexpr(t1), mkU32(sz) )
13591 );
13592 /* do the call, dumping the result in t2. */
13593 stmt( IRStmt_Dirty(d) );
13594 putIReg(sz, R_EAX, narrowTo( ty, mkexpr(t2) ) );
13595 break;
13596 }
13597
13598 case 0xE6: /* OUT AL, imm8 */
13599 sz = 1;
13600 t1 = newTemp(Ity_I32);
13601 abyte = getIByte(delta); delta++;
13602 assign( t1, mkU32( abyte & 0xFF ) );
13603 DIP("out%c %s,$%d\n", nameISize(sz), nameIReg(sz,R_EAX), (Int)abyte);
13604 goto do_OUT;
13605 case 0xE7: /* OUT eAX, imm8 */
13606 vassert(sz == 2 || sz == 4);
13607 t1 = newTemp(Ity_I32);
13608 abyte = getIByte(delta); delta++;
13609 assign( t1, mkU32( abyte & 0xFF ) );
13610 DIP("out%c %s,$%d\n", nameISize(sz), nameIReg(sz,R_EAX), (Int)abyte);
13611 goto do_OUT;
13612 case 0xEE: /* OUT AL, %DX */
13613 sz = 1;
13614 t1 = newTemp(Ity_I32);
13615 assign( t1, unop(Iop_16Uto32, getIReg(2, R_EDX)) );
13616 DIP("out%c %s,%s\n", nameISize(sz), nameIReg(sz,R_EAX),
13617 nameIReg(2,R_EDX));
13618 goto do_OUT;
13619 case 0xEF: /* OUT eAX, %DX */
13620 vassert(sz == 2 || sz == 4);
13621 t1 = newTemp(Ity_I32);
13622 assign( t1, unop(Iop_16Uto32, getIReg(2, R_EDX)) );
13623 DIP("out%c %s,%s\n", nameISize(sz), nameIReg(sz,R_EAX),
13624 nameIReg(2,R_EDX));
13625 goto do_OUT;
13626 do_OUT: {
13627 /* At this point, sz indicates the width, and t1 is a 32-bit
13628 value giving port number. */
13629 IRDirty* d;
13630 vassert(sz == 1 || sz == 2 || sz == 4);
13631 ty = szToITy(sz);
13632 d = unsafeIRDirty_0_N(
13633 0/*regparms*/,
13634 "x86g_dirtyhelper_OUT",
13635 &x86g_dirtyhelper_OUT,
13636 mkIRExprVec_3( mkexpr(t1),
13637 widenUto32( getIReg(sz, R_EAX) ),
13638 mkU32(sz) )
13639 );
13640 stmt( IRStmt_Dirty(d) );
13641 break;
13642 }
sewardj0611d802004-07-11 02:37:54 +000013643
13644 /* ------------------------ (Grp1 extensions) ---------- */
13645
13646 case 0x80: /* Grp1 Ib,Eb */
13647 modrm = getIByte(delta);
13648 am_sz = lengthAMode(delta);
13649 sz = 1;
13650 d_sz = 1;
sewardjc2ac51e2004-07-12 01:03:26 +000013651 d32 = getUChar(delta + am_sz);
sewardj0611d802004-07-11 02:37:54 +000013652 delta = dis_Grp1 ( sorb, delta, modrm, am_sz, d_sz, sz, d32 );
13653 break;
sewardje05c42c2004-07-08 20:25:10 +000013654
13655 case 0x81: /* Grp1 Iv,Ev */
13656 modrm = getIByte(delta);
13657 am_sz = lengthAMode(delta);
13658 d_sz = sz;
13659 d32 = getUDisp(d_sz, delta + am_sz);
13660 delta = dis_Grp1 ( sorb, delta, modrm, am_sz, d_sz, sz, d32 );
13661 break;
sewardjd1061ab2004-07-08 01:45:30 +000013662
13663 case 0x83: /* Grp1 Ib,Ev */
13664 modrm = getIByte(delta);
13665 am_sz = lengthAMode(delta);
13666 d_sz = 1;
13667 d32 = getSDisp8(delta + am_sz);
13668 delta = dis_Grp1 ( sorb, delta, modrm, am_sz, d_sz, sz, d32 );
13669 break;
13670
sewardjc2ac51e2004-07-12 01:03:26 +000013671 /* ------------------------ (Grp2 extensions) ---------- */
13672
sewardjd51dc812007-03-20 14:18:45 +000013673 case 0xC0: { /* Grp2 Ib,Eb */
13674 Bool decode_OK = True;
sewardjc2ac51e2004-07-12 01:03:26 +000013675 modrm = getIByte(delta);
13676 am_sz = lengthAMode(delta);
13677 d_sz = 1;
sewardj180e8b32004-07-29 01:40:11 +000013678 d32 = getUChar(delta + am_sz);
sewardjc2ac51e2004-07-12 01:03:26 +000013679 sz = 1;
sewardj6d2638e2004-07-15 09:38:27 +000013680 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
sewardjd51dc812007-03-20 14:18:45 +000013681 mkU8(d32 & 0xFF), NULL, &decode_OK );
13682 if (!decode_OK)
13683 goto decode_failure;
sewardjc2ac51e2004-07-12 01:03:26 +000013684 break;
sewardjd51dc812007-03-20 14:18:45 +000013685 }
13686 case 0xC1: { /* Grp2 Ib,Ev */
13687 Bool decode_OK = True;
sewardjc2ac51e2004-07-12 01:03:26 +000013688 modrm = getIByte(delta);
sewardje90ad6a2004-07-10 19:02:10 +000013689 am_sz = lengthAMode(delta);
13690 d_sz = 1;
sewardj180e8b32004-07-29 01:40:11 +000013691 d32 = getUChar(delta + am_sz);
sewardj6d2638e2004-07-15 09:38:27 +000013692 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
sewardjd51dc812007-03-20 14:18:45 +000013693 mkU8(d32 & 0xFF), NULL, &decode_OK );
13694 if (!decode_OK)
13695 goto decode_failure;
sewardje90ad6a2004-07-10 19:02:10 +000013696 break;
sewardjd51dc812007-03-20 14:18:45 +000013697 }
13698 case 0xD0: { /* Grp2 1,Eb */
13699 Bool decode_OK = True;
sewardj180e8b32004-07-29 01:40:11 +000013700 modrm = getIByte(delta);
13701 am_sz = lengthAMode(delta);
13702 d_sz = 0;
13703 d32 = 1;
13704 sz = 1;
13705 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
sewardjd51dc812007-03-20 14:18:45 +000013706 mkU8(d32), NULL, &decode_OK );
13707 if (!decode_OK)
13708 goto decode_failure;
sewardj180e8b32004-07-29 01:40:11 +000013709 break;
sewardjd51dc812007-03-20 14:18:45 +000013710 }
13711 case 0xD1: { /* Grp2 1,Ev */
13712 Bool decode_OK = True;
sewardjc2ac51e2004-07-12 01:03:26 +000013713 modrm = getUChar(delta);
13714 am_sz = lengthAMode(delta);
13715 d_sz = 0;
13716 d32 = 1;
sewardj6d2638e2004-07-15 09:38:27 +000013717 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
sewardjd51dc812007-03-20 14:18:45 +000013718 mkU8(d32), NULL, &decode_OK );
13719 if (!decode_OK)
13720 goto decode_failure;
sewardjc2ac51e2004-07-12 01:03:26 +000013721 break;
sewardjd51dc812007-03-20 14:18:45 +000013722 }
13723 case 0xD2: { /* Grp2 CL,Eb */
13724 Bool decode_OK = True;
sewardj8c7f1ab2004-07-29 20:31:09 +000013725 modrm = getUChar(delta);
13726 am_sz = lengthAMode(delta);
13727 d_sz = 0;
13728 sz = 1;
13729 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
sewardjd51dc812007-03-20 14:18:45 +000013730 getIReg(1,R_ECX), "%cl", &decode_OK );
13731 if (!decode_OK)
13732 goto decode_failure;
sewardj8c7f1ab2004-07-29 20:31:09 +000013733 break;
sewardjd51dc812007-03-20 14:18:45 +000013734 }
13735 case 0xD3: { /* Grp2 CL,Ev */
13736 Bool decode_OK = True;
sewardj9334b0f2004-07-10 22:43:54 +000013737 modrm = getIByte(delta);
13738 am_sz = lengthAMode(delta);
13739 d_sz = 0;
13740 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
sewardjd51dc812007-03-20 14:18:45 +000013741 getIReg(1,R_ECX), "%cl", &decode_OK );
13742 if (!decode_OK)
13743 goto decode_failure;
sewardj9334b0f2004-07-10 22:43:54 +000013744 break;
sewardjd51dc812007-03-20 14:18:45 +000013745 }
sewardj9334b0f2004-07-10 22:43:54 +000013746
sewardj940e8c92004-07-11 16:53:24 +000013747 /* ------------------------ (Grp3 extensions) ---------- */
13748
sewardjd51dc812007-03-20 14:18:45 +000013749 case 0xF6: { /* Grp3 Eb */
13750 Bool decode_OK = True;
13751 delta = dis_Grp3 ( sorb, 1, delta, &decode_OK );
13752 if (!decode_OK)
13753 goto decode_failure;
sewardj940e8c92004-07-11 16:53:24 +000013754 break;
sewardjd51dc812007-03-20 14:18:45 +000013755 }
13756 case 0xF7: { /* Grp3 Ev */
13757 Bool decode_OK = True;
13758 delta = dis_Grp3 ( sorb, sz, delta, &decode_OK );
13759 if (!decode_OK)
13760 goto decode_failure;
sewardj940e8c92004-07-11 16:53:24 +000013761 break;
sewardjd51dc812007-03-20 14:18:45 +000013762 }
sewardj940e8c92004-07-11 16:53:24 +000013763
sewardjc2ac51e2004-07-12 01:03:26 +000013764 /* ------------------------ (Grp4 extensions) ---------- */
13765
sewardjd51dc812007-03-20 14:18:45 +000013766 case 0xFE: { /* Grp4 Eb */
13767 Bool decode_OK = True;
13768 delta = dis_Grp4 ( sorb, delta, &decode_OK );
13769 if (!decode_OK)
13770 goto decode_failure;
sewardjc2ac51e2004-07-12 01:03:26 +000013771 break;
sewardjd51dc812007-03-20 14:18:45 +000013772 }
sewardj0611d802004-07-11 02:37:54 +000013773
13774 /* ------------------------ (Grp5 extensions) ---------- */
13775
sewardjd51dc812007-03-20 14:18:45 +000013776 case 0xFF: { /* Grp5 Ev */
13777 Bool decode_OK = True;
13778 delta = dis_Grp5 ( sorb, sz, delta, &dres, &decode_OK );
13779 if (!decode_OK)
13780 goto decode_failure;
sewardj0611d802004-07-11 02:37:54 +000013781 break;
sewardjd51dc812007-03-20 14:18:45 +000013782 }
sewardje87b4842004-07-10 12:23:30 +000013783
13784 /* ------------------------ Escapes to 2-byte opcodes -- */
13785
13786 case 0x0F: {
13787 opc = getIByte(delta); delta++;
13788 switch (opc) {
13789
sewardj490ad382005-03-13 17:25:53 +000013790 /* =-=-=-=-=-=-=-=-=- Grp8 =-=-=-=-=-=-=-=-=-=-=-= */
13791
13792 case 0xBA: { /* Grp8 Ib,Ev */
13793 Bool decode_OK = False;
13794 modrm = getUChar(delta);
13795 am_sz = lengthAMode(delta);
13796 d32 = getSDisp8(delta + am_sz);
13797 delta = dis_Grp8_Imm ( sorb, delta, modrm, am_sz, sz, d32,
13798 &decode_OK );
13799 if (!decode_OK)
13800 goto decode_failure;
13801 break;
13802 }
sewardjce646f22004-08-31 23:55:54 +000013803
13804 /* =-=-=-=-=-=-=-=-=- BSF/BSR -=-=-=-=-=-=-=-=-=-= */
13805
13806 case 0xBC: /* BSF Gv,Ev */
13807 delta = dis_bs_E_G ( sorb, sz, delta, True );
13808 break;
13809 case 0xBD: /* BSR Gv,Ev */
13810 delta = dis_bs_E_G ( sorb, sz, delta, False );
13811 break;
sewardj1c4208f2004-08-25 13:25:29 +000013812
13813 /* =-=-=-=-=-=-=-=-=- BSWAP -=-=-=-=-=-=-=-=-=-=-= */
13814
13815 case 0xC8: /* BSWAP %eax */
13816 case 0xC9:
13817 case 0xCA:
sewardjb4666cf2004-10-23 00:21:50 +000013818 case 0xCB:
13819 case 0xCC:
13820 case 0xCD:
sewardj1c4208f2004-08-25 13:25:29 +000013821 case 0xCE:
sewardj1c6f9912004-09-07 10:15:24 +000013822 case 0xCF: /* BSWAP %edi */
sewardj1c4208f2004-08-25 13:25:29 +000013823 /* AFAICS from the Intel docs, this only exists at size 4. */
13824 vassert(sz == 4);
13825 t1 = newTemp(Ity_I32);
13826 t2 = newTemp(Ity_I32);
13827 assign( t1, getIReg(4, opc-0xC8) );
13828
13829 assign( t2,
13830 binop(Iop_Or32,
13831 binop(Iop_Shl32, mkexpr(t1), mkU8(24)),
13832 binop(Iop_Or32,
13833 binop(Iop_And32, binop(Iop_Shl32, mkexpr(t1), mkU8(8)),
13834 mkU32(0x00FF0000)),
13835 binop(Iop_Or32,
13836 binop(Iop_And32, binop(Iop_Shr32, mkexpr(t1), mkU8(8)),
13837 mkU32(0x0000FF00)),
13838 binop(Iop_And32, binop(Iop_Shr32, mkexpr(t1), mkU8(24)),
13839 mkU32(0x000000FF) )
13840 )))
13841 );
13842
13843 putIReg(4, opc-0xC8, mkexpr(t2));
sewardj1c4208f2004-08-25 13:25:29 +000013844 DIP("bswapl %s\n", nameIReg(4, opc-0xC8));
13845 break;
13846
sewardj1c6f9912004-09-07 10:15:24 +000013847 /* =-=-=-=-=-=-=-=-=- BT/BTS/BTR/BTC =-=-=-=-=-=-= */
13848
13849 case 0xA3: /* BT Gv,Ev */
13850 delta = dis_bt_G_E ( sorb, sz, delta, BtOpNone );
13851 break;
sewardje6709112004-09-10 18:37:18 +000013852 case 0xB3: /* BTR Gv,Ev */
13853 delta = dis_bt_G_E ( sorb, sz, delta, BtOpReset );
13854 break;
sewardj1c6f9912004-09-07 10:15:24 +000013855 case 0xAB: /* BTS Gv,Ev */
13856 delta = dis_bt_G_E ( sorb, sz, delta, BtOpSet );
13857 break;
sewardj4963a422004-10-14 23:34:03 +000013858 case 0xBB: /* BTC Gv,Ev */
13859 delta = dis_bt_G_E ( sorb, sz, delta, BtOpComp );
13860 break;
sewardj458a6f82004-08-25 12:46:02 +000013861
13862 /* =-=-=-=-=-=-=-=-=- CMOV =-=-=-=-=-=-=-=-=-=-=-= */
13863
sewardj2d4c3a02004-10-15 00:03:23 +000013864 case 0x40:
13865 case 0x41:
sewardj458a6f82004-08-25 12:46:02 +000013866 case 0x42: /* CMOVBb/CMOVNAEb (cmov below) */
13867 case 0x43: /* CMOVNBb/CMOVAEb (cmov not below) */
13868 case 0x44: /* CMOVZb/CMOVEb (cmov zero) */
13869 case 0x45: /* CMOVNZb/CMOVNEb (cmov not zero) */
13870 case 0x46: /* CMOVBEb/CMOVNAb (cmov below or equal) */
13871 case 0x47: /* CMOVNBEb/CMOVAb (cmov not below or equal) */
sewardjce646f22004-08-31 23:55:54 +000013872 case 0x48: /* CMOVSb (cmov negative) */
sewardj458a6f82004-08-25 12:46:02 +000013873 case 0x49: /* CMOVSb (cmov not negative) */
sewardj2d4c3a02004-10-15 00:03:23 +000013874 case 0x4A: /* CMOVP (cmov parity even) */
13875 case 0x4B: /* CMOVNP (cmov parity odd) */
sewardj458a6f82004-08-25 12:46:02 +000013876 case 0x4C: /* CMOVLb/CMOVNGEb (cmov less) */
13877 case 0x4D: /* CMOVGEb/CMOVNLb (cmov greater or equal) */
13878 case 0x4E: /* CMOVLEb/CMOVNGb (cmov less or equal) */
13879 case 0x4F: /* CMOVGb/CMOVNLEb (cmov greater) */
sewardj2a9ad022004-11-25 02:46:58 +000013880 delta = dis_cmov_E_G(sorb, sz, (X86Condcode)(opc - 0x40), delta);
sewardj458a6f82004-08-25 12:46:02 +000013881 break;
13882
13883 /* =-=-=-=-=-=-=-=-=- CMPXCHG -=-=-=-=-=-=-=-=-=-= */
13884
sewardjc744e872004-08-26 11:24:39 +000013885 case 0xB0: /* CMPXCHG Gb,Eb */
13886 delta = dis_cmpxchg_G_E ( sorb, 1, delta );
13887 break;
sewardj458a6f82004-08-25 12:46:02 +000013888 case 0xB1: /* CMPXCHG Gv,Ev */
13889 delta = dis_cmpxchg_G_E ( sorb, sz, delta );
13890 break;
sewardj300bb872005-08-12 23:04:48 +000013891
13892 case 0xC7: { /* CMPXCHG8B Gv (0F C7 /1) */
13893 IRTemp m64_old = newTemp(Ity_I64);
13894 IRTemp m64_new = newTemp(Ity_I64);
13895 IRTemp da_old = newTemp(Ity_I64);
13896 IRTemp da_new = newTemp(Ity_I64);
13897 IRTemp cb_old = newTemp(Ity_I64);
13898 IRTemp flags_old = newTemp(Ity_I32);
13899 IRTemp flags_new = newTemp(Ity_I32);
13900 IRTemp cond = newTemp(Ity_I8);
13901
13902 /* Decode, and generate address. */
13903 modrm = getIByte(delta);
13904 if (epartIsReg(modrm)) goto decode_failure;
13905 if (gregOfRM(modrm) != 1) goto decode_failure;
13906 addr = disAMode ( &alen, sorb, delta, dis_buf );
13907 delta += alen;
13908
13909 /* Fetch the old 64-bit values and compute the guard. */
13910 assign( m64_old, loadLE(Ity_I64, mkexpr(addr) ));
13911 assign( da_old, binop(Iop_32HLto64,
13912 getIReg(4,R_EDX), getIReg(4,R_EAX)) );
13913 assign( cb_old, binop(Iop_32HLto64,
13914 getIReg(4,R_ECX), getIReg(4,R_EBX)) );
13915
13916 assign( cond,
13917 unop(Iop_1Uto8,
13918 binop(Iop_CmpEQ64, mkexpr(da_old), mkexpr(m64_old))) );
13919
13920 /* Compute new %edx:%eax and m64 values, and put in place */
13921 assign( da_new,
13922 IRExpr_Mux0X(mkexpr(cond), mkexpr(m64_old), mkexpr(da_old)));
13923 assign( m64_new,
13924 IRExpr_Mux0X(mkexpr(cond), mkexpr(m64_old), mkexpr(cb_old)));
13925
13926 putIReg(4, R_EDX, unop(Iop_64HIto32, mkexpr(da_new)) );
13927 putIReg(4, R_EAX, unop(Iop_64to32, mkexpr(da_new)) );
13928 storeLE( mkexpr(addr), mkexpr(m64_new) );
13929
13930 /* Copy the guard into the Z flag and leave the others unchanged */
13931 assign( flags_old, widenUto32(mk_x86g_calculate_eflags_all()));
13932 assign(
13933 flags_new,
13934 binop(Iop_Or32,
13935 binop(Iop_And32, mkexpr(flags_old),
13936 mkU32(~X86G_CC_MASK_Z)),
13937 binop(Iop_Shl32,
13938 binop(Iop_And32,
13939 unop(Iop_8Uto32, mkexpr(cond)), mkU32(1)),
13940 mkU8(X86G_CC_SHIFT_Z)) ));
13941
13942 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
13943 stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(flags_new) ));
13944 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
13945 /* Set NDEP even though it isn't used. This makes
13946 redundant-PUT elimination of previous stores to this field
13947 work better. */
13948 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
13949
13950 /* Sheesh. Aren't you glad it was me and not you that had to
13951 write and validate all this grunge? */
13952
13953 DIP("cmpxchg8b %s\n", dis_buf);
13954 break;
13955 }
13956
sewardj588ea762004-09-10 18:56:32 +000013957 /* =-=-=-=-=-=-=-=-=- CPUID -=-=-=-=-=-=-=-=-=-=-= */
13958
sewardj7cb49d72004-10-24 22:31:25 +000013959 case 0xA2: { /* CPUID */
13960 /* Uses dirty helper:
sewardj9df271d2004-12-31 22:37:42 +000013961 void dirtyhelper_CPUID_sse[012] ( VexGuestX86State* )
sewardj7cb49d72004-10-24 22:31:25 +000013962 declared to mod eax, wr ebx, ecx, edx
13963 */
sewardj9df271d2004-12-31 22:37:42 +000013964 IRDirty* d = NULL;
13965 HChar* fName = NULL;
13966 void* fAddr = NULL;
sewardj5117ce12006-01-27 21:20:15 +000013967 if (archinfo->hwcaps & VEX_HWCAPS_X86_SSE2) {
13968 fName = "x86g_dirtyhelper_CPUID_sse2";
13969 fAddr = &x86g_dirtyhelper_CPUID_sse2;
13970 }
13971 else
13972 if (archinfo->hwcaps & VEX_HWCAPS_X86_SSE1) {
13973 fName = "x86g_dirtyhelper_CPUID_sse1";
13974 fAddr = &x86g_dirtyhelper_CPUID_sse1;
13975 }
13976 else
13977 if (archinfo->hwcaps == 0/*no SSE*/) {
13978 fName = "x86g_dirtyhelper_CPUID_sse0";
13979 fAddr = &x86g_dirtyhelper_CPUID_sse0;
13980 } else
13981 vpanic("disInstr(x86)(cpuid)");
13982
sewardj9df271d2004-12-31 22:37:42 +000013983 vassert(fName); vassert(fAddr);
13984 d = unsafeIRDirty_0_N ( 0/*regparms*/,
13985 fName, fAddr, mkIRExprVec_0() );
sewardj7cb49d72004-10-24 22:31:25 +000013986 /* declare guest state effects */
sewardjc5fc7aa2004-10-27 23:00:55 +000013987 d->needsBBP = True;
sewardj7cb49d72004-10-24 22:31:25 +000013988 d->nFxState = 4;
13989 d->fxState[0].fx = Ifx_Modify;
13990 d->fxState[0].offset = OFFB_EAX;
13991 d->fxState[0].size = 4;
13992 d->fxState[1].fx = Ifx_Write;
13993 d->fxState[1].offset = OFFB_EBX;
13994 d->fxState[1].size = 4;
sewardj32bfd3e2008-02-10 13:29:19 +000013995 d->fxState[2].fx = Ifx_Modify;
sewardj7cb49d72004-10-24 22:31:25 +000013996 d->fxState[2].offset = OFFB_ECX;
13997 d->fxState[2].size = 4;
13998 d->fxState[3].fx = Ifx_Write;
13999 d->fxState[3].offset = OFFB_EDX;
14000 d->fxState[3].size = 4;
14001 /* execute the dirty call, side-effecting guest state */
14002 stmt( IRStmt_Dirty(d) );
sewardj55860d82005-01-08 18:25:05 +000014003 /* CPUID is a serialising insn. So, just in case someone is
14004 using it as a memory fence ... */
sewardjc4356f02007-11-09 21:15:04 +000014005 stmt( IRStmt_MBE(Imbe_Fence) );
sewardj517a7d62004-10-25 09:52:18 +000014006 DIP("cpuid\n");
sewardj588ea762004-09-10 18:56:32 +000014007 break;
sewardj7cb49d72004-10-24 22:31:25 +000014008 }
14009
sewardj5bd4d162004-11-10 13:02:48 +000014010//-- if (!VG_(cpu_has_feature)(VG_X86_FEAT_CPUID))
14011//-- goto decode_failure;
sewardjc9a65702004-07-07 16:32:57 +000014012//--
14013//-- t1 = newTemp(cb);
14014//-- t2 = newTemp(cb);
14015//-- t3 = newTemp(cb);
14016//-- t4 = newTemp(cb);
14017//-- uInstr0(cb, CALLM_S, 0);
14018//--
14019//-- uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, t1);
14020//-- uInstr1(cb, PUSH, 4, TempReg, t1);
14021//--
14022//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
14023//-- uLiteral(cb, 0);
14024//-- uInstr1(cb, PUSH, 4, TempReg, t2);
14025//--
14026//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t3);
14027//-- uLiteral(cb, 0);
14028//-- uInstr1(cb, PUSH, 4, TempReg, t3);
14029//--
14030//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t4);
14031//-- uLiteral(cb, 0);
14032//-- uInstr1(cb, PUSH, 4, TempReg, t4);
14033//--
14034//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_CPUID));
14035//-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
14036//--
14037//-- uInstr1(cb, POP, 4, TempReg, t4);
14038//-- uInstr2(cb, PUT, 4, TempReg, t4, ArchReg, R_EDX);
14039//--
14040//-- uInstr1(cb, POP, 4, TempReg, t3);
14041//-- uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_ECX);
14042//--
14043//-- uInstr1(cb, POP, 4, TempReg, t2);
14044//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_EBX);
14045//--
14046//-- uInstr1(cb, POP, 4, TempReg, t1);
14047//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_EAX);
14048//--
14049//-- uInstr0(cb, CALLM_E, 0);
14050//-- DIP("cpuid\n");
14051//-- break;
14052//--
sewardj9334b0f2004-07-10 22:43:54 +000014053 /* =-=-=-=-=-=-=-=-=- MOVZX, MOVSX =-=-=-=-=-=-=-= */
14054
14055 case 0xB6: /* MOVZXb Eb,Gv */
sewardj6ba982f2006-05-03 17:57:15 +000014056 if (sz != 2 && sz != 4)
14057 goto decode_failure;
14058 delta = dis_movx_E_G ( sorb, delta, 1, sz, False );
sewardj9334b0f2004-07-10 22:43:54 +000014059 break;
sewardj6ba982f2006-05-03 17:57:15 +000014060
sewardj940e8c92004-07-11 16:53:24 +000014061 case 0xB7: /* MOVZXw Ew,Gv */
sewardj6ba982f2006-05-03 17:57:15 +000014062 if (sz != 4)
14063 goto decode_failure;
sewardj940e8c92004-07-11 16:53:24 +000014064 delta = dis_movx_E_G ( sorb, delta, 2, 4, False );
14065 break;
14066
sewardj0611d802004-07-11 02:37:54 +000014067 case 0xBE: /* MOVSXb Eb,Gv */
sewardj6ba982f2006-05-03 17:57:15 +000014068 if (sz != 2 && sz != 4)
14069 goto decode_failure;
14070 delta = dis_movx_E_G ( sorb, delta, 1, sz, True );
sewardj0611d802004-07-11 02:37:54 +000014071 break;
sewardj6ba982f2006-05-03 17:57:15 +000014072
sewardj7ed22952004-07-29 00:09:58 +000014073 case 0xBF: /* MOVSXw Ew,Gv */
sewardj6ba982f2006-05-03 17:57:15 +000014074 if (sz != 4)
14075 goto decode_failure;
sewardj7ed22952004-07-29 00:09:58 +000014076 delta = dis_movx_E_G ( sorb, delta, 2, 4, True );
14077 break;
14078
sewardjc9a65702004-07-07 16:32:57 +000014079//-- /* =-=-=-=-=-=-=-=-=-=-= MOVNTI -=-=-=-=-=-=-=-=-= */
14080//--
14081//-- case 0xC3: /* MOVNTI Gv,Ev */
14082//-- vg_assert(sz == 4);
14083//-- modrm = getUChar(eip);
14084//-- vg_assert(!epartIsReg(modrm));
14085//-- t1 = newTemp(cb);
14086//-- uInstr2(cb, GET, 4, ArchReg, gregOfRM(modrm), TempReg, t1);
14087//-- pair = disAMode ( cb, sorb, eip, dis_buf );
14088//-- t2 = LOW24(pair);
14089//-- eip += HI8(pair);
14090//-- uInstr2(cb, STORE, 4, TempReg, t1, TempReg, t2);
14091//-- DIP("movnti %s,%s\n", nameIReg(4,gregOfRM(modrm)), dis_buf);
14092//-- break;
sewardjcf780b42004-07-13 18:42:17 +000014093
14094 /* =-=-=-=-=-=-=-=-=- MUL/IMUL =-=-=-=-=-=-=-=-=-= */
14095
14096 case 0xAF: /* IMUL Ev, Gv */
sewardj2a2ba8b2004-11-08 13:14:06 +000014097 delta = dis_mul_E_G ( sorb, sz, delta );
sewardjcf780b42004-07-13 18:42:17 +000014098 break;
sewardje87b4842004-07-10 12:23:30 +000014099
sewardjec387ca2006-08-01 18:36:25 +000014100 /* =-=-=-=-=-=-=-=-=- NOPs =-=-=-=-=-=-=-=-=-=-=-= */
14101
14102 case 0x1F:
14103 modrm = getUChar(delta);
14104 if (epartIsReg(modrm)) goto decode_failure;
14105 addr = disAMode ( &alen, sorb, delta, dis_buf );
14106 delta += alen;
14107 DIP("nop%c %s\n", nameISize(sz), dis_buf);
14108 break;
14109
sewardje87b4842004-07-10 12:23:30 +000014110 /* =-=-=-=-=-=-=-=-=- Jcond d32 -=-=-=-=-=-=-=-=-= */
14111 case 0x80:
14112 case 0x81:
14113 case 0x82: /* JBb/JNAEb (jump below) */
14114 case 0x83: /* JNBb/JAEb (jump not below) */
14115 case 0x84: /* JZb/JEb (jump zero) */
14116 case 0x85: /* JNZb/JNEb (jump not zero) */
14117 case 0x86: /* JBEb/JNAb (jump below or equal) */
14118 case 0x87: /* JNBEb/JAb (jump not below or equal) */
14119 case 0x88: /* JSb (jump negative) */
14120 case 0x89: /* JSb (jump not negative) */
14121 case 0x8A: /* JP (jump parity even) */
14122 case 0x8B: /* JNP/JPO (jump parity odd) */
14123 case 0x8C: /* JLb/JNGEb (jump less) */
14124 case 0x8D: /* JGEb/JNLb (jump greater or equal) */
14125 case 0x8E: /* JLEb/JNGb (jump less or equal) */
14126 case 0x8F: /* JGb/JNLEb (jump greater) */
sewardj9e6491a2005-07-02 19:24:10 +000014127 d32 = (((Addr32)guest_EIP_bbstart)+delta+4) + getUDisp32(delta);
sewardje87b4842004-07-10 12:23:30 +000014128 delta += 4;
sewardj2a9ad022004-11-25 02:46:58 +000014129 jcc_01( (X86Condcode)(opc - 0x80),
sewardj9e6491a2005-07-02 19:24:10 +000014130 (Addr32)(guest_EIP_bbstart+delta),
sewardj2a9ad022004-11-25 02:46:58 +000014131 d32 );
sewardj9e6491a2005-07-02 19:24:10 +000014132 dres.whatNext = Dis_StopHere;
sewardj2a9ad022004-11-25 02:46:58 +000014133 DIP("j%s-32 0x%x\n", name_X86Condcode(opc - 0x80), d32);
sewardje87b4842004-07-10 12:23:30 +000014134 break;
14135
sewardj89cd0932004-09-08 18:23:25 +000014136 /* =-=-=-=-=-=-=-=-=- RDTSC -=-=-=-=-=-=-=-=-=-=-= */
sewardj4ed64292005-08-23 19:24:29 +000014137 case 0x31: { /* RDTSC */
14138 IRTemp val = newTemp(Ity_I64);
14139 IRExpr** args = mkIRExprVec_0();
14140 IRDirty* d = unsafeIRDirty_1_N (
14141 val,
14142 0/*regparms*/,
14143 "x86g_dirtyhelper_RDTSC",
14144 &x86g_dirtyhelper_RDTSC,
14145 args
14146 );
sewardja5cbbdc2005-08-23 23:17:38 +000014147 /* execute the dirty call, dumping the result in val. */
14148 stmt( IRStmt_Dirty(d) );
14149 putIReg(4, R_EDX, unop(Iop_64HIto32, mkexpr(val)));
14150 putIReg(4, R_EAX, unop(Iop_64to32, mkexpr(val)));
14151 DIP("rdtsc\n");
14152 break;
sewardj4ed64292005-08-23 19:24:29 +000014153 }
sewardj77b86be2004-07-11 13:28:24 +000014154
sewardjb64821b2004-12-14 10:00:16 +000014155 /* =-=-=-=-=-=-=-=-=- PUSH/POP Sreg =-=-=-=-=-=-=-=-=-= */
14156
14157 case 0xA1: /* POP %FS */
14158 dis_pop_segreg( R_FS, sz ); break;
14159 case 0xA9: /* POP %GS */
14160 dis_pop_segreg( R_GS, sz ); break;
14161
14162 case 0xA0: /* PUSH %FS */
14163 dis_push_segreg( R_FS, sz ); break;
14164 case 0xA8: /* PUSH %GS */
14165 dis_push_segreg( R_GS, sz ); break;
14166
sewardj77b86be2004-07-11 13:28:24 +000014167 /* =-=-=-=-=-=-=-=-=- SETcc Eb =-=-=-=-=-=-=-=-=-= */
14168 case 0x90:
14169 case 0x91:
14170 case 0x92: /* set-Bb/set-NAEb (jump below) */
14171 case 0x93: /* set-NBb/set-AEb (jump not below) */
14172 case 0x94: /* set-Zb/set-Eb (jump zero) */
14173 case 0x95: /* set-NZb/set-NEb (jump not zero) */
14174 case 0x96: /* set-BEb/set-NAb (jump below or equal) */
14175 case 0x97: /* set-NBEb/set-Ab (jump not below or equal) */
14176 case 0x98: /* set-Sb (jump negative) */
14177 case 0x99: /* set-Sb (jump not negative) */
14178 case 0x9A: /* set-P (jump parity even) */
14179 case 0x9B: /* set-NP (jump parity odd) */
14180 case 0x9C: /* set-Lb/set-NGEb (jump less) */
14181 case 0x9D: /* set-GEb/set-NLb (jump greater or equal) */
14182 case 0x9E: /* set-LEb/set-NGb (jump less or equal) */
14183 case 0x9F: /* set-Gb/set-NLEb (jump greater) */
sewardj5bd4d162004-11-10 13:02:48 +000014184 t1 = newTemp(Ity_I8);
sewardj2a9ad022004-11-25 02:46:58 +000014185 assign( t1, unop(Iop_1Uto8,mk_x86g_calculate_condition(opc-0x90)) );
sewardj77b86be2004-07-11 13:28:24 +000014186 modrm = getIByte(delta);
14187 if (epartIsReg(modrm)) {
14188 delta++;
sewardj5bd4d162004-11-10 13:02:48 +000014189 putIReg(1, eregOfRM(modrm), mkexpr(t1));
sewardj2a9ad022004-11-25 02:46:58 +000014190 DIP("set%s %s\n", name_X86Condcode(opc-0x90),
sewardj77b86be2004-07-11 13:28:24 +000014191 nameIReg(1,eregOfRM(modrm)));
14192 } else {
sewardj750f4072004-07-26 22:39:11 +000014193 addr = disAMode ( &alen, sorb, delta, dis_buf );
14194 delta += alen;
14195 storeLE( mkexpr(addr), mkexpr(t1) );
sewardj2a9ad022004-11-25 02:46:58 +000014196 DIP("set%s %s\n", name_X86Condcode(opc-0x90), dis_buf);
sewardj77b86be2004-07-11 13:28:24 +000014197 }
14198 break;
14199
sewardj180e8b32004-07-29 01:40:11 +000014200 /* =-=-=-=-=-=-=-=-=- SHLD/SHRD -=-=-=-=-=-=-=-=-= */
14201
14202 case 0xA4: /* SHLDv imm8,Gv,Ev */
14203 modrm = getIByte(delta);
14204 d32 = delta + lengthAMode(delta);
sewardj2d49b432005-02-01 00:37:06 +000014205 vex_sprintf(dis_buf, "$%d", getIByte(d32));
sewardj180e8b32004-07-29 01:40:11 +000014206 delta = dis_SHLRD_Gv_Ev (
14207 sorb, delta, modrm, sz,
14208 mkU8(getIByte(d32)), True, /* literal */
14209 dis_buf, True );
14210 break;
sewardja06e5562004-07-14 13:18:05 +000014211 case 0xA5: /* SHLDv %cl,Gv,Ev */
14212 modrm = getIByte(delta);
14213 delta = dis_SHLRD_Gv_Ev (
14214 sorb, delta, modrm, sz,
14215 getIReg(1,R_ECX), False, /* not literal */
14216 "%cl", True );
14217 break;
14218
sewardj68511542004-07-28 00:15:44 +000014219 case 0xAC: /* SHRDv imm8,Gv,Ev */
14220 modrm = getIByte(delta);
14221 d32 = delta + lengthAMode(delta);
sewardj2d49b432005-02-01 00:37:06 +000014222 vex_sprintf(dis_buf, "$%d", getIByte(d32));
sewardj68511542004-07-28 00:15:44 +000014223 delta = dis_SHLRD_Gv_Ev (
14224 sorb, delta, modrm, sz,
14225 mkU8(getIByte(d32)), True, /* literal */
14226 dis_buf, False );
14227 break;
sewardja511afc2004-07-29 22:26:03 +000014228 case 0xAD: /* SHRDv %cl,Gv,Ev */
14229 modrm = getIByte(delta);
14230 delta = dis_SHLRD_Gv_Ev (
14231 sorb, delta, modrm, sz,
14232 getIReg(1,R_ECX), False, /* not literal */
14233 "%cl", False );
14234 break;
14235
sewardjf07ed032005-08-07 14:48:03 +000014236 /* =-=-=-=-=-=-=-=-=- SYSENTER -=-=-=-=-=-=-=-=-=-= */
14237
14238 case 0x34:
14239 /* Simple implementation needing a long explaination.
14240
14241 sysenter is a kind of syscall entry. The key thing here
14242 is that the return address is not known -- that is
14243 something that is beyond Vex's knowledge. So this IR
14244 forces a return to the scheduler, which can do what it
sewardj4fa325a2005-11-03 13:27:24 +000014245 likes to simulate the systenter, but it MUST set this
sewardjf07ed032005-08-07 14:48:03 +000014246 thread's guest_EIP field with the continuation address
14247 before resuming execution. If that doesn't happen, the
14248 thread will jump to address zero, which is probably
14249 fatal.
14250 */
sewardj4fa325a2005-11-03 13:27:24 +000014251 jmp_lit(Ijk_Sys_sysenter, 0/*bogus next EIP value*/);
sewardjf07ed032005-08-07 14:48:03 +000014252 dres.whatNext = Dis_StopHere;
14253 DIP("sysenter");
14254 break;
14255
sewardj464efa42004-11-19 22:17:29 +000014256 /* =-=-=-=-=-=-=-=-=- XADD -=-=-=-=-=-=-=-=-=-= */
14257
sewardj0092e0d2006-03-06 13:35:42 +000014258 case 0xC0: { /* XADD Gb,Eb */
14259 Bool decodeOK;
14260 delta = dis_xadd_G_E ( sorb, 1, delta, &decodeOK );
14261 if (!decodeOK) goto decode_failure;
sewardj883b00b2004-09-11 09:30:24 +000014262 break;
sewardj0092e0d2006-03-06 13:35:42 +000014263 }
14264 case 0xC1: { /* XADD Gv,Ev */
14265 Bool decodeOK;
14266 delta = dis_xadd_G_E ( sorb, sz, delta, &decodeOK );
14267 if (!decodeOK) goto decode_failure;
14268 break;
14269 }
sewardj883b00b2004-09-11 09:30:24 +000014270
sewardjf13f37b2004-12-08 17:01:23 +000014271 /* =-=-=-=-=-=-=-=-=- MMXery =-=-=-=-=-=-=-=-=-=-= */
sewardj464efa42004-11-19 22:17:29 +000014272
sewardj2b7a9202004-11-26 19:15:38 +000014273 case 0x71:
14274 case 0x72:
sewardj38a3f862005-01-13 15:06:51 +000014275 case 0x73: /* PSLLgg/PSRAgg/PSRLgg mmxreg by imm8 */
sewardj2b7a9202004-11-26 19:15:38 +000014276
14277 case 0x6E: /* MOVD (src)ireg-or-mem, (dst)mmxreg */
14278 case 0x7E: /* MOVD (src)mmxreg, (dst)ireg-or-mem */
sewardj464efa42004-11-19 22:17:29 +000014279 case 0x7F: /* MOVQ (src)mmxreg, (dst)mmxreg-or-mem */
sewardj2b7a9202004-11-26 19:15:38 +000014280 case 0x6F: /* MOVQ (src)mmxreg-or-mem, (dst)mmxreg */
sewardj464efa42004-11-19 22:17:29 +000014281
14282 case 0xFC:
14283 case 0xFD:
14284 case 0xFE: /* PADDgg (src)mmxreg-or-mem, (dst)mmxreg */
14285
14286 case 0xEC:
14287 case 0xED: /* PADDSgg (src)mmxreg-or-mem, (dst)mmxreg */
14288
14289 case 0xDC:
14290 case 0xDD: /* PADDUSgg (src)mmxreg-or-mem, (dst)mmxreg */
14291
14292 case 0xF8:
14293 case 0xF9:
14294 case 0xFA: /* PSUBgg (src)mmxreg-or-mem, (dst)mmxreg */
14295
14296 case 0xE8:
14297 case 0xE9: /* PSUBSgg (src)mmxreg-or-mem, (dst)mmxreg */
14298
14299 case 0xD8:
14300 case 0xD9: /* PSUBUSgg (src)mmxreg-or-mem, (dst)mmxreg */
14301
14302 case 0xE5: /* PMULHW (src)mmxreg-or-mem, (dst)mmxreg */
14303 case 0xD5: /* PMULLW (src)mmxreg-or-mem, (dst)mmxreg */
14304
sewardj4340dac2004-11-20 13:17:04 +000014305 case 0xF5: /* PMADDWD (src)mmxreg-or-mem, (dst)mmxreg */
14306
14307 case 0x74:
14308 case 0x75:
14309 case 0x76: /* PCMPEQgg (src)mmxreg-or-mem, (dst)mmxreg */
14310
14311 case 0x64:
14312 case 0x65:
14313 case 0x66: /* PCMPGTgg (src)mmxreg-or-mem, (dst)mmxreg */
14314
sewardj63ba4092004-11-21 12:30:18 +000014315 case 0x6B: /* PACKSSDW (src)mmxreg-or-mem, (dst)mmxreg */
14316 case 0x63: /* PACKSSWB (src)mmxreg-or-mem, (dst)mmxreg */
14317 case 0x67: /* PACKUSWB (src)mmxreg-or-mem, (dst)mmxreg */
14318
14319 case 0x68:
14320 case 0x69:
14321 case 0x6A: /* PUNPCKHgg (src)mmxreg-or-mem, (dst)mmxreg */
14322
14323 case 0x60:
14324 case 0x61:
14325 case 0x62: /* PUNPCKLgg (src)mmxreg-or-mem, (dst)mmxreg */
14326
14327 case 0xDB: /* PAND (src)mmxreg-or-mem, (dst)mmxreg */
14328 case 0xDF: /* PANDN (src)mmxreg-or-mem, (dst)mmxreg */
14329 case 0xEB: /* POR (src)mmxreg-or-mem, (dst)mmxreg */
14330 case 0xEF: /* PXOR (src)mmxreg-or-mem, (dst)mmxreg */
14331
sewardj38a3f862005-01-13 15:06:51 +000014332 case 0xF1: /* PSLLgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj8d14a592004-11-21 17:04:50 +000014333 case 0xF2:
sewardj38a3f862005-01-13 15:06:51 +000014334 case 0xF3:
sewardj8d14a592004-11-21 17:04:50 +000014335
sewardj38a3f862005-01-13 15:06:51 +000014336 case 0xD1: /* PSRLgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj8d14a592004-11-21 17:04:50 +000014337 case 0xD2:
sewardj38a3f862005-01-13 15:06:51 +000014338 case 0xD3:
sewardj8d14a592004-11-21 17:04:50 +000014339
sewardj38a3f862005-01-13 15:06:51 +000014340 case 0xE1: /* PSRAgg (src)mmxreg-or-mem, (dst)mmxreg */
14341 case 0xE2:
sewardj464efa42004-11-19 22:17:29 +000014342 {
sewardj52d04912005-07-03 00:52:48 +000014343 Int delta0 = delta-1;
sewardj464efa42004-11-19 22:17:29 +000014344 Bool decode_OK = False;
sewardj38a3f862005-01-13 15:06:51 +000014345
14346 /* If sz==2 this is SSE, and we assume sse idec has
14347 already spotted those cases by now. */
14348 if (sz != 4)
14349 goto decode_failure;
14350
sewardj464efa42004-11-19 22:17:29 +000014351 delta = dis_MMX ( &decode_OK, sorb, sz, delta-1 );
14352 if (!decode_OK) {
14353 delta = delta0;
14354 goto decode_failure;
14355 }
14356 break;
14357 }
14358
sewardj8d14a592004-11-21 17:04:50 +000014359 case 0x77: /* EMMS */
sewardj38a3f862005-01-13 15:06:51 +000014360 if (sz != 4)
14361 goto decode_failure;
sewardj4cb918d2004-12-03 19:43:31 +000014362 do_EMMS_preamble();
sewardj8d14a592004-11-21 17:04:50 +000014363 DIP("emms\n");
14364 break;
14365
sewardje87b4842004-07-10 12:23:30 +000014366 /* =-=-=-=-=-=-=-=-=- unimp2 =-=-=-=-=-=-=-=-=-=-= */
14367
14368 default:
14369 goto decode_failure;
14370 } /* switch (opc) for the 2-byte opcodes */
14371 goto decode_success;
14372 } /* case 0x0F: of primary opcode */
sewardjc9a65702004-07-07 16:32:57 +000014373
14374 /* ------------------------ ??? ------------------------ */
14375
14376 default:
sewardje87b4842004-07-10 12:23:30 +000014377 decode_failure:
sewardjc9a65702004-07-07 16:32:57 +000014378 /* All decode failures end up here. */
sewardj52444cb2004-12-13 14:09:01 +000014379 vex_printf("vex x86->IR: unhandled instruction bytes: "
sewardjc9a65702004-07-07 16:32:57 +000014380 "0x%x 0x%x 0x%x 0x%x\n",
14381 (Int)getIByte(delta_start+0),
14382 (Int)getIByte(delta_start+1),
14383 (Int)getIByte(delta_start+2),
14384 (Int)getIByte(delta_start+3) );
sewardj52444cb2004-12-13 14:09:01 +000014385
sewardjb64821b2004-12-14 10:00:16 +000014386 /* Tell the dispatcher that this insn cannot be decoded, and so has
14387 not been executed, and (is currently) the next to be executed.
14388 EIP should be up-to-date since it made so at the start of each
14389 insn, but nevertheless be paranoid and update it again right
14390 now. */
sewardj9e6491a2005-07-02 19:24:10 +000014391 stmt( IRStmt_Put( OFFB_EIP, mkU32(guest_EIP_curr_instr) ) );
sewardjc4356f02007-11-09 21:15:04 +000014392 if (unlock_bus_after_insn)
14393 stmt( IRStmt_MBE(Imbe_BusUnlock) );
sewardj9e6491a2005-07-02 19:24:10 +000014394 jmp_lit(Ijk_NoDecode, guest_EIP_curr_instr);
14395 dres.whatNext = Dis_StopHere;
14396 dres.len = 0;
14397 return dres;
sewardj52444cb2004-12-13 14:09:01 +000014398
sewardjc9a65702004-07-07 16:32:57 +000014399 } /* switch (opc) for the main (primary) opcode switch. */
14400
sewardje87b4842004-07-10 12:23:30 +000014401 decode_success:
sewardjc9a65702004-07-07 16:32:57 +000014402 /* All decode successes end up here. */
14403 DIP("\n");
sewardjc4356f02007-11-09 21:15:04 +000014404 if (unlock_bus_after_insn)
14405 stmt( IRStmt_MBE(Imbe_BusUnlock) );
sewardj9e6491a2005-07-02 19:24:10 +000014406 dres.len = delta - delta_start;
14407 return dres;
sewardjc9a65702004-07-07 16:32:57 +000014408}
14409
14410#undef DIP
14411#undef DIS
14412
sewardj9e6491a2005-07-02 19:24:10 +000014413
14414/*------------------------------------------------------------*/
14415/*--- Top-level fn ---*/
14416/*------------------------------------------------------------*/
14417
14418/* Disassemble a single instruction into IR. The instruction
14419 is located in host memory at &guest_code[delta]. */
14420
sewardjdd40fdf2006-12-24 02:20:24 +000014421DisResult disInstr_X86 ( IRSB* irsb_IN,
sewardj9e6491a2005-07-02 19:24:10 +000014422 Bool put_IP,
sewardjc716aea2006-01-17 01:48:46 +000014423 Bool (*resteerOkFn) ( void*, Addr64 ),
14424 void* callback_opaque,
sewardj9e6491a2005-07-02 19:24:10 +000014425 UChar* guest_code_IN,
14426 Long delta,
14427 Addr64 guest_IP,
sewardja5f55da2006-04-30 23:37:32 +000014428 VexArch guest_arch,
sewardj9e6491a2005-07-02 19:24:10 +000014429 VexArchInfo* archinfo,
sewardjdd40fdf2006-12-24 02:20:24 +000014430 VexAbiInfo* abiinfo,
sewardj9e6491a2005-07-02 19:24:10 +000014431 Bool host_bigendian_IN )
14432{
14433 DisResult dres;
14434
14435 /* Set globals (see top of this file) */
sewardja5f55da2006-04-30 23:37:32 +000014436 vassert(guest_arch == VexArchX86);
sewardj9e6491a2005-07-02 19:24:10 +000014437 guest_code = guest_code_IN;
sewardjdd40fdf2006-12-24 02:20:24 +000014438 irsb = irsb_IN;
sewardj9e6491a2005-07-02 19:24:10 +000014439 host_is_bigendian = host_bigendian_IN;
14440 guest_EIP_curr_instr = (Addr32)guest_IP;
14441 guest_EIP_bbstart = (Addr32)toUInt(guest_IP - delta);
14442
sewardjc716aea2006-01-17 01:48:46 +000014443 dres = disInstr_X86_WRK ( put_IP, resteerOkFn, callback_opaque,
sewardj9e6491a2005-07-02 19:24:10 +000014444 delta, archinfo );
14445
14446 return dres;
14447}
14448
14449
sewardjc9a65702004-07-07 16:32:57 +000014450/*--------------------------------------------------------------------*/
sewardjc0ee2ed2004-07-27 10:29:41 +000014451/*--- end guest-x86/toIR.c ---*/
sewardjc9a65702004-07-07 16:32:57 +000014452/*--------------------------------------------------------------------*/