blob: 515785dd5d685a705c601d8b9da785f21ccf267d [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
sewardj7bd6ffe2005-08-03 16:07:36 +000013 Copyright (C) 2004-2005 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
sewardj458a6f82004-08-25 12:46:02 +000049 check flag settings for cmpxchg
sewardj883b00b2004-09-11 09:30:24 +000050 FUCOMI(P): what happens to A and S flags? Currently are forced
51 to zero.
sewardj3f61ddb2004-10-16 20:51:05 +000052
sewardjce70a5c2004-10-18 14:09:54 +000053 x87 FP Limitations:
sewardja0e83b02005-01-06 12:36:38 +000054
55 * all arithmetic done at 64 bits
56
sewardj3f61ddb2004-10-16 20:51:05 +000057 * no FP exceptions, except for handling stack over/underflow
sewardja0e83b02005-01-06 12:36:38 +000058
sewardj3f61ddb2004-10-16 20:51:05 +000059 * FP rounding mode observed only for float->int conversions
sewardja0e83b02005-01-06 12:36:38 +000060 and int->float conversions which could lose accuracy, and
61 for float-to-float rounding. For all other operations,
62 round-to-nearest is used, regardless.
63
sewardj3f61ddb2004-10-16 20:51:05 +000064 * FP sin/cos/tan/sincos: C2 flag is always cleared. IOW the
65 simulation claims the argument is in-range (-2^63 <= arg <= 2^63)
66 even when it isn't.
sewardja0e83b02005-01-06 12:36:38 +000067
sewardje166ed02004-10-25 02:27:01 +000068 * some of the FCOM cases could do with testing -- not convinced
69 that the args are the right way round.
sewardj52444cb2004-12-13 14:09:01 +000070
sewardja0e83b02005-01-06 12:36:38 +000071 * FSAVE does not re-initialise the FPU; it should do
72
73 * FINIT not only initialises the FPU environment, it also
74 zeroes all the FP registers. It should leave the registers
75 unchanged.
76
sewardj9f8a3952005-04-06 10:27:11 +000077 RDTSC returns one, always.
sewardjcb2c99d2004-12-17 19:14:24 +000078
79 SAHF should cause eflags[1] == 1, and in fact it produces 0. As
80 per Intel docs this bit has no meaning anyway. Since PUSHF is the
81 only way to observe eflags[1], a proper fix would be to make that
82 bit be set by PUSHF.
83
sewardj6d269842005-08-06 11:45:02 +000084 The state of %eflags.AC (alignment check, bit 18) is recorded by
85 the simulation (viz, if you set it with popf then a pushf produces
86 the value you set it to), but it is otherwise ignored. In
87 particular, setting it to 1 does NOT cause alignment checking to
88 happen. Programs that set it to 1 and then rely on the resulting
89 SIGBUSs to inform them of misaligned accesses will not work.
90
sewardjf07ed032005-08-07 14:48:03 +000091 Implementation sysenter is necessarily partial. sysenter is a kind
92 of system call entry. When doing a sysenter, the return address is
93 not known -- that is something that is beyond Vex's knowledge. So
94 the generated IR forces a return to the scheduler, which can do
95 what it likes to simulate the systemter, but it MUST set this
96 thread's guest_EIP field with the continuation address before
97 resuming execution. If that doesn't happen, the thread will jump
98 to address zero, which is probably fatal.
99
sewardj52444cb2004-12-13 14:09:01 +0000100 This module uses global variables and so is not MT-safe (if that
sewardje395ae82005-02-26 02:00:50 +0000101 should ever become relevant).
102
103 The delta values are 32-bit ints, not 64-bit ints. That means
104 this module may not work right if run on a 64-bit host. That should
105 be fixed properly, really -- if anyone ever wants to use Vex to
sewardj45f1ff82005-05-05 12:04:14 +0000106 translate x86 code for execution on a 64-bit host. */
sewardje05c42c2004-07-08 20:25:10 +0000107
sewardj9f8a3952005-04-06 10:27:11 +0000108/* Performance holes:
109
110 - fcom ; fstsw %ax ; sahf
111 sahf does not update the O flag (sigh) and so O needs to
112 be computed. This is done expensively; it would be better
113 to have a calculate_eflags_o helper.
114
115 - emwarns; some FP codes can generate huge numbers of these
116 if the fpucw is changed in an inner loop. It would be
117 better for the guest state to have an emwarn-enable reg
118 which can be set zero or nonzero. If it is zero, emwarns
119 are not flagged, and instead control just flows all the
120 way through bbs as usual.
121*/
122
sewardjc9a65702004-07-07 16:32:57 +0000123/* Translates x86 code to IR. */
124
125#include "libvex_basictypes.h"
126#include "libvex_ir.h"
sewardje87b4842004-07-10 12:23:30 +0000127#include "libvex.h"
sewardjf6dc3ce2004-10-19 01:03:46 +0000128#include "libvex_guest_x86.h"
sewardjc0ee2ed2004-07-27 10:29:41 +0000129
130#include "main/vex_util.h"
131#include "main/vex_globals.h"
sewardj9e6491a2005-07-02 19:24:10 +0000132#include "guest-generic/bb_to_IR.h"
sewardjc0ee2ed2004-07-27 10:29:41 +0000133#include "guest-x86/gdefs.h"
sewardjc9a65702004-07-07 16:32:57 +0000134
135
136/*------------------------------------------------------------*/
137/*--- Globals ---*/
138/*------------------------------------------------------------*/
139
sewardj9e6491a2005-07-02 19:24:10 +0000140/* These are set at the start of the translation of an insn, right
141 down in disInstr_X86, so that we don't have to pass them around
142 endlessly. They are all constant during the translation of any
143 given insn. */
sewardjc9a65702004-07-07 16:32:57 +0000144
145/* We need to know this to do sub-register accesses correctly. */
sewardjc9a65702004-07-07 16:32:57 +0000146static Bool host_is_bigendian;
147
sewardj9e6491a2005-07-02 19:24:10 +0000148/* Pointer to the guest code area (points to start of BB, not to the
149 insn being processed). */
sewardjc9a65702004-07-07 16:32:57 +0000150static UChar* guest_code;
151
152/* The guest address corresponding to guest_code[0]. */
sewardj9e6491a2005-07-02 19:24:10 +0000153static Addr32 guest_EIP_bbstart;
sewardjc9a65702004-07-07 16:32:57 +0000154
sewardj52444cb2004-12-13 14:09:01 +0000155/* The guest address for the instruction currently being
156 translated. */
sewardj9e6491a2005-07-02 19:24:10 +0000157static Addr32 guest_EIP_curr_instr;
sewardj52444cb2004-12-13 14:09:01 +0000158
sewardjd7cb8532004-08-17 23:59:23 +0000159/* The IRBB* into which we're generating code. */
sewardjc9a65702004-07-07 16:32:57 +0000160static IRBB* irbb;
161
sewardjc9a65702004-07-07 16:32:57 +0000162
sewardjce70a5c2004-10-18 14:09:54 +0000163/*------------------------------------------------------------*/
164/*--- Debugging output ---*/
165/*------------------------------------------------------------*/
166
sewardjf48ac192004-10-29 00:41:29 +0000167#define DIP(format, args...) \
sewardj9e6491a2005-07-02 19:24:10 +0000168 if (vex_traceflags & VEX_TRACE_FE) \
sewardjce70a5c2004-10-18 14:09:54 +0000169 vex_printf(format, ## args)
170
sewardjf48ac192004-10-29 00:41:29 +0000171#define DIS(buf, format, args...) \
sewardj9e6491a2005-07-02 19:24:10 +0000172 if (vex_traceflags & VEX_TRACE_FE) \
sewardjce70a5c2004-10-18 14:09:54 +0000173 vex_sprintf(buf, format, ## args)
174
175
176/*------------------------------------------------------------*/
sewardjdcc85fc2004-10-26 13:26:20 +0000177/*--- Offsets of various parts of the x86 guest state. ---*/
178/*------------------------------------------------------------*/
179
sewardjc9a43662004-11-30 18:51:59 +0000180#define OFFB_EAX offsetof(VexGuestX86State,guest_EAX)
181#define OFFB_EBX offsetof(VexGuestX86State,guest_EBX)
182#define OFFB_ECX offsetof(VexGuestX86State,guest_ECX)
183#define OFFB_EDX offsetof(VexGuestX86State,guest_EDX)
184#define OFFB_ESP offsetof(VexGuestX86State,guest_ESP)
185#define OFFB_EBP offsetof(VexGuestX86State,guest_EBP)
186#define OFFB_ESI offsetof(VexGuestX86State,guest_ESI)
187#define OFFB_EDI offsetof(VexGuestX86State,guest_EDI)
sewardj2a2ba8b2004-11-08 13:14:06 +0000188
sewardjc9a43662004-11-30 18:51:59 +0000189#define OFFB_EIP offsetof(VexGuestX86State,guest_EIP)
sewardj2a2ba8b2004-11-08 13:14:06 +0000190
sewardjc9a43662004-11-30 18:51:59 +0000191#define OFFB_CC_OP offsetof(VexGuestX86State,guest_CC_OP)
192#define OFFB_CC_DEP1 offsetof(VexGuestX86State,guest_CC_DEP1)
193#define OFFB_CC_DEP2 offsetof(VexGuestX86State,guest_CC_DEP2)
194#define OFFB_CC_NDEP offsetof(VexGuestX86State,guest_CC_NDEP)
sewardj893aada2004-11-29 19:57:54 +0000195
sewardjc9a43662004-11-30 18:51:59 +0000196#define OFFB_FPREGS offsetof(VexGuestX86State,guest_FPREG[0])
197#define OFFB_FPTAGS offsetof(VexGuestX86State,guest_FPTAG[0])
198#define OFFB_DFLAG offsetof(VexGuestX86State,guest_DFLAG)
199#define OFFB_IDFLAG offsetof(VexGuestX86State,guest_IDFLAG)
sewardj6d269842005-08-06 11:45:02 +0000200#define OFFB_ACFLAG offsetof(VexGuestX86State,guest_ACFLAG)
sewardjc9a43662004-11-30 18:51:59 +0000201#define OFFB_FTOP offsetof(VexGuestX86State,guest_FTOP)
202#define OFFB_FC3210 offsetof(VexGuestX86State,guest_FC3210)
203#define OFFB_FPROUND offsetof(VexGuestX86State,guest_FPROUND)
204
205#define OFFB_CS offsetof(VexGuestX86State,guest_CS)
206#define OFFB_DS offsetof(VexGuestX86State,guest_DS)
207#define OFFB_ES offsetof(VexGuestX86State,guest_ES)
208#define OFFB_FS offsetof(VexGuestX86State,guest_FS)
209#define OFFB_GS offsetof(VexGuestX86State,guest_GS)
210#define OFFB_SS offsetof(VexGuestX86State,guest_SS)
sewardj3bd6f3e2004-12-13 10:48:19 +0000211#define OFFB_LDT offsetof(VexGuestX86State,guest_LDT)
212#define OFFB_GDT offsetof(VexGuestX86State,guest_GDT)
sewardjc9a43662004-11-30 18:51:59 +0000213
214#define OFFB_SSEROUND offsetof(VexGuestX86State,guest_SSEROUND)
215#define OFFB_XMM0 offsetof(VexGuestX86State,guest_XMM0)
216#define OFFB_XMM1 offsetof(VexGuestX86State,guest_XMM1)
217#define OFFB_XMM2 offsetof(VexGuestX86State,guest_XMM2)
218#define OFFB_XMM3 offsetof(VexGuestX86State,guest_XMM3)
219#define OFFB_XMM4 offsetof(VexGuestX86State,guest_XMM4)
220#define OFFB_XMM5 offsetof(VexGuestX86State,guest_XMM5)
221#define OFFB_XMM6 offsetof(VexGuestX86State,guest_XMM6)
222#define OFFB_XMM7 offsetof(VexGuestX86State,guest_XMM7)
223
224#define OFFB_EMWARN offsetof(VexGuestX86State,guest_EMWARN)
sewardjdcc85fc2004-10-26 13:26:20 +0000225
226
227/*------------------------------------------------------------*/
sewardjce70a5c2004-10-18 14:09:54 +0000228/*--- Helper bits and pieces for deconstructing the ---*/
229/*--- x86 insn stream. ---*/
230/*------------------------------------------------------------*/
231
232/* This is the Intel register encoding -- integer regs. */
233#define R_EAX 0
234#define R_ECX 1
235#define R_EDX 2
236#define R_EBX 3
237#define R_ESP 4
238#define R_EBP 5
239#define R_ESI 6
240#define R_EDI 7
241
242#define R_AL (0+R_EAX)
243#define R_AH (4+R_EAX)
244
sewardj063f02f2004-10-20 12:36:12 +0000245/* This is the Intel register encoding -- segment regs. */
246#define R_ES 0
247#define R_CS 1
248#define R_SS 2
249#define R_DS 3
250#define R_FS 4
251#define R_GS 5
252
sewardjce70a5c2004-10-18 14:09:54 +0000253
sewardjc9a65702004-07-07 16:32:57 +0000254/* Add a statement to the list held by "irbb". */
sewardjd7cb8532004-08-17 23:59:23 +0000255static void stmt ( IRStmt* st )
sewardjc9a65702004-07-07 16:32:57 +0000256{
sewardjd7cb8532004-08-17 23:59:23 +0000257 addStmtToIRBB( irbb, st );
sewardjc9a65702004-07-07 16:32:57 +0000258}
259
260/* Generate a new temporary of the given type. */
261static IRTemp newTemp ( IRType ty )
262{
sewardj496a58d2005-03-20 18:44:44 +0000263 vassert(isPlausibleIRType(ty));
sewardje539a402004-07-14 18:24:17 +0000264 return newIRTemp( irbb->tyenv, ty );
sewardjc9a65702004-07-07 16:32:57 +0000265}
266
sewardjc9a65702004-07-07 16:32:57 +0000267/* Bomb out if we can't handle something. */
sewardjd1061ab2004-07-08 01:45:30 +0000268__attribute__ ((noreturn))
sewardj2d49b432005-02-01 00:37:06 +0000269static void unimplemented ( HChar* str )
sewardjc9a65702004-07-07 16:32:57 +0000270{
271 vex_printf("x86toIR: unimplemented feature\n");
272 vpanic(str);
273}
274
sewardjce70a5c2004-10-18 14:09:54 +0000275/* Various simple conversions */
sewardjd1061ab2004-07-08 01:45:30 +0000276
sewardje05c42c2004-07-08 20:25:10 +0000277static UInt extend_s_8to32( UInt x )
sewardjd1061ab2004-07-08 01:45:30 +0000278{
279 return (UInt)((((Int)x) << 24) >> 24);
280}
281
sewardj0611d802004-07-11 02:37:54 +0000282static UInt extend_s_16to32 ( UInt x )
283{
284 return (UInt)((((Int)x) << 16) >> 16);
285}
286
sewardjd1061ab2004-07-08 01:45:30 +0000287/* Fetch a byte from the guest insn stream. */
sewardj52d04912005-07-03 00:52:48 +0000288static UChar getIByte ( Int delta )
sewardjd1061ab2004-07-08 01:45:30 +0000289{
290 return guest_code[delta];
291}
292
sewardjc9a65702004-07-07 16:32:57 +0000293/* Extract the reg field from a modRM byte. */
sewardje05c42c2004-07-08 20:25:10 +0000294static Int gregOfRM ( UChar mod_reg_rm )
sewardjc9a65702004-07-07 16:32:57 +0000295{
296 return (Int)( (mod_reg_rm >> 3) & 7 );
297}
298
299/* Figure out whether the mod and rm parts of a modRM byte refer to a
300 register or memory. If so, the byte will have the form 11XXXYYY,
301 where YYY is the register number. */
sewardje05c42c2004-07-08 20:25:10 +0000302static Bool epartIsReg ( UChar mod_reg_rm )
sewardjc9a65702004-07-07 16:32:57 +0000303{
sewardj2d49b432005-02-01 00:37:06 +0000304 return toBool(0xC0 == (mod_reg_rm & 0xC0));
sewardjc9a65702004-07-07 16:32:57 +0000305}
306
307/* ... and extract the register number ... */
sewardje05c42c2004-07-08 20:25:10 +0000308static Int eregOfRM ( UChar mod_reg_rm )
sewardjc9a65702004-07-07 16:32:57 +0000309{
310 return (Int)(mod_reg_rm & 0x7);
311}
312
sewardje05c42c2004-07-08 20:25:10 +0000313/* Get a 8/16/32-bit unsigned value out of the insn stream. */
314
sewardj52d04912005-07-03 00:52:48 +0000315static UChar getUChar ( Int delta )
sewardje05c42c2004-07-08 20:25:10 +0000316{
sewardj2d49b432005-02-01 00:37:06 +0000317 UChar v = guest_code[delta+0];
sewardj9b45b482005-02-07 01:42:18 +0000318 return toUChar(v);
sewardje05c42c2004-07-08 20:25:10 +0000319}
320
sewardj52d04912005-07-03 00:52:48 +0000321static UInt getUDisp16 ( Int delta )
sewardje05c42c2004-07-08 20:25:10 +0000322{
323 UInt v = guest_code[delta+1]; v <<= 8;
324 v |= guest_code[delta+0];
325 return v & 0xFFFF;
326}
327
sewardj52d04912005-07-03 00:52:48 +0000328static UInt getUDisp32 ( Int delta )
sewardjd1061ab2004-07-08 01:45:30 +0000329{
330 UInt v = guest_code[delta+3]; v <<= 8;
331 v |= guest_code[delta+2]; v <<= 8;
332 v |= guest_code[delta+1]; v <<= 8;
333 v |= guest_code[delta+0];
334 return v;
335}
336
sewardj52d04912005-07-03 00:52:48 +0000337static UInt getUDisp ( Int size, Int delta )
sewardje05c42c2004-07-08 20:25:10 +0000338{
339 switch (size) {
340 case 4: return getUDisp32(delta);
341 case 2: return getUDisp16(delta);
sewardj2d49b432005-02-01 00:37:06 +0000342 case 1: return (UInt)getUChar(delta);
sewardje05c42c2004-07-08 20:25:10 +0000343 default: vpanic("getUDisp(x86)");
344 }
345 return 0; /*notreached*/
346}
347
348
sewardjd1061ab2004-07-08 01:45:30 +0000349/* Get a byte value out of the insn stream and sign-extend to 32
350 bits. */
sewardj52d04912005-07-03 00:52:48 +0000351static UInt getSDisp8 ( Int delta )
sewardjd1061ab2004-07-08 01:45:30 +0000352{
353 return extend_s_8to32( (UInt) (guest_code[delta]) );
354}
355
sewardj52d04912005-07-03 00:52:48 +0000356static UInt getSDisp16 ( Int delta0 )
sewardj0611d802004-07-11 02:37:54 +0000357{
358 UChar* eip = (UChar*)(&guest_code[delta0]);
359 UInt d = *eip++;
360 d |= ((*eip++) << 8);
361 return extend_s_16to32(d);
362}
363
sewardj52d04912005-07-03 00:52:48 +0000364static UInt getSDisp ( Int size, Int delta )
sewardj0611d802004-07-11 02:37:54 +0000365{
366 switch (size) {
367 case 4: return getUDisp32(delta);
368 case 2: return getSDisp16(delta);
369 case 1: return getSDisp8(delta);
370 default: vpanic("getSDisp(x86)");
371 }
372 return 0; /*notreached*/
373}
sewardjd1061ab2004-07-08 01:45:30 +0000374
sewardjc9a65702004-07-07 16:32:57 +0000375
376/*------------------------------------------------------------*/
377/*--- Helpers for constructing IR. ---*/
378/*------------------------------------------------------------*/
379
380/* Create a 1/2/4 byte read of an x86 integer registers. For 16/8 bit
381 register references, we need to take the host endianness into
382 account. Supplied value is 0 .. 7 and in the Intel instruction
383 encoding. */
sewardje05c42c2004-07-08 20:25:10 +0000384
sewardj9334b0f2004-07-10 22:43:54 +0000385static IRType szToITy ( Int n )
386{
387 switch (n) {
388 case 1: return Ity_I8;
389 case 2: return Ity_I16;
390 case 4: return Ity_I32;
391 default: vpanic("szToITy(x86)");
392 }
393}
394
sewardj67e002d2004-12-02 18:16:33 +0000395/* On a little-endian host, less significant bits of the guest
396 registers are at lower addresses. Therefore, if a reference to a
397 register low half has the safe guest state offset as a reference to
398 the full register.
399*/
sewardj9334b0f2004-07-10 22:43:54 +0000400static Int integerGuestRegOffset ( Int sz, UInt archreg )
401{
402 vassert(archreg < 8);
403
sewardj9334b0f2004-07-10 22:43:54 +0000404 /* Correct for little-endian host only. */
sewardj67e002d2004-12-02 18:16:33 +0000405 vassert(!host_is_bigendian);
sewardj063f02f2004-10-20 12:36:12 +0000406
407 if (sz == 4 || sz == 2 || (sz == 1 && archreg < 4)) {
408 switch (archreg) {
sewardjc9a43662004-11-30 18:51:59 +0000409 case R_EAX: return OFFB_EAX;
410 case R_EBX: return OFFB_EBX;
411 case R_ECX: return OFFB_ECX;
412 case R_EDX: return OFFB_EDX;
413 case R_ESI: return OFFB_ESI;
414 case R_EDI: return OFFB_EDI;
415 case R_ESP: return OFFB_ESP;
416 case R_EBP: return OFFB_EBP;
sewardj063f02f2004-10-20 12:36:12 +0000417 default: vpanic("integerGuestRegOffset(x86,le)(4,2)");
418 }
419 }
420
421 vassert(archreg >= 4 && archreg < 8 && sz == 1);
422 switch (archreg-4) {
sewardjc9a43662004-11-30 18:51:59 +0000423 case R_EAX: return 1+ OFFB_EAX;
424 case R_EBX: return 1+ OFFB_EBX;
425 case R_ECX: return 1+ OFFB_ECX;
426 case R_EDX: return 1+ OFFB_EDX;
sewardj063f02f2004-10-20 12:36:12 +0000427 default: vpanic("integerGuestRegOffset(x86,le)(1h)");
428 }
429
430 /* NOTREACHED */
431 vpanic("integerGuestRegOffset(x86,le)");
432}
433
434static Int segmentGuestRegOffset ( UInt sreg )
435{
436 switch (sreg) {
sewardjc9a43662004-11-30 18:51:59 +0000437 case R_ES: return OFFB_ES;
438 case R_CS: return OFFB_CS;
439 case R_SS: return OFFB_SS;
440 case R_DS: return OFFB_DS;
441 case R_FS: return OFFB_FS;
442 case R_GS: return OFFB_GS;
sewardj063f02f2004-10-20 12:36:12 +0000443 default: vpanic("segmentGuestRegOffset(x86)");
sewardj9334b0f2004-07-10 22:43:54 +0000444 }
445}
446
sewardjc9a43662004-11-30 18:51:59 +0000447static Int xmmGuestRegOffset ( UInt xmmreg )
448{
449 switch (xmmreg) {
450 case 0: return OFFB_XMM0;
451 case 1: return OFFB_XMM1;
452 case 2: return OFFB_XMM2;
453 case 3: return OFFB_XMM3;
454 case 4: return OFFB_XMM4;
455 case 5: return OFFB_XMM5;
456 case 6: return OFFB_XMM6;
457 case 7: return OFFB_XMM7;
458 default: vpanic("xmmGuestRegOffset");
459 }
460}
461
sewardj67e002d2004-12-02 18:16:33 +0000462/* Lanes of vector registers are always numbered from zero being the
463 least significant lane (rightmost in the register). */
464
sewardje5854d62004-12-09 03:44:34 +0000465static Int xmmGuestRegLane16offset ( UInt xmmreg, Int laneno )
466{
467 /* Correct for little-endian host only. */
468 vassert(!host_is_bigendian);
469 vassert(laneno >= 0 && laneno < 8);
470 return xmmGuestRegOffset( xmmreg ) + 2 * laneno;
471}
472
sewardj67e002d2004-12-02 18:16:33 +0000473static Int xmmGuestRegLane32offset ( UInt xmmreg, Int laneno )
474{
475 /* Correct for little-endian host only. */
476 vassert(!host_is_bigendian);
477 vassert(laneno >= 0 && laneno < 4);
478 return xmmGuestRegOffset( xmmreg ) + 4 * laneno;
479}
480
481static Int xmmGuestRegLane64offset ( UInt xmmreg, Int laneno )
482{
483 /* Correct for little-endian host only. */
484 vassert(!host_is_bigendian);
485 vassert(laneno >= 0 && laneno < 2);
486 return xmmGuestRegOffset( xmmreg ) + 8 * laneno;
487}
488
sewardjd1061ab2004-07-08 01:45:30 +0000489static IRExpr* getIReg ( Int sz, UInt archreg )
sewardjc9a65702004-07-07 16:32:57 +0000490{
491 vassert(sz == 1 || sz == 2 || sz == 4);
492 vassert(archreg < 8);
sewardj9334b0f2004-07-10 22:43:54 +0000493 return IRExpr_Get( integerGuestRegOffset(sz,archreg),
sewardj5bd4d162004-11-10 13:02:48 +0000494 szToITy(sz) );
sewardjc9a65702004-07-07 16:32:57 +0000495}
496
497/* Ditto, but write to a reg instead. */
sewardj41f43bc2004-07-08 14:23:22 +0000498static void putIReg ( Int sz, UInt archreg, IRExpr* e )
sewardjc9a65702004-07-07 16:32:57 +0000499{
sewardjc9a43662004-11-30 18:51:59 +0000500 IRType ty = typeOfIRExpr(irbb->tyenv, e);
sewardjd24931d2005-03-20 12:51:39 +0000501 switch (sz) {
502 case 1: vassert(ty == Ity_I8); break;
503 case 2: vassert(ty == Ity_I16); break;
504 case 4: vassert(ty == Ity_I32); break;
505 default: vpanic("putIReg(x86)");
506 }
sewardjc9a65702004-07-07 16:32:57 +0000507 vassert(archreg < 8);
sewardjeeb9ef82004-07-15 12:39:03 +0000508 stmt( IRStmt_Put(integerGuestRegOffset(sz,archreg), e) );
sewardjd1061ab2004-07-08 01:45:30 +0000509}
510
sewardj063f02f2004-10-20 12:36:12 +0000511static IRExpr* getSReg ( UInt sreg )
512{
513 return IRExpr_Get( segmentGuestRegOffset(sreg), Ity_I16 );
514}
515
516static void putSReg ( UInt sreg, IRExpr* e )
517{
518 vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_I16);
519 stmt( IRStmt_Put( segmentGuestRegOffset(sreg), e ) );
520}
521
sewardjc9a43662004-11-30 18:51:59 +0000522static IRExpr* getXMMReg ( UInt xmmreg )
523{
524 return IRExpr_Get( xmmGuestRegOffset(xmmreg), Ity_V128 );
525}
526
sewardj67e002d2004-12-02 18:16:33 +0000527static IRExpr* getXMMRegLane64 ( UInt xmmreg, Int laneno )
528{
529 return IRExpr_Get( xmmGuestRegLane64offset(xmmreg,laneno), Ity_I64 );
530}
531
sewardjfd226452004-12-07 19:02:18 +0000532static IRExpr* getXMMRegLane64F ( UInt xmmreg, Int laneno )
sewardj67e002d2004-12-02 18:16:33 +0000533{
sewardjfd226452004-12-07 19:02:18 +0000534 return IRExpr_Get( xmmGuestRegLane64offset(xmmreg,laneno), Ity_F64 );
sewardj67e002d2004-12-02 18:16:33 +0000535}
536
sewardj9636b442004-12-04 01:38:37 +0000537static IRExpr* getXMMRegLane32 ( UInt xmmreg, Int laneno )
538{
539 return IRExpr_Get( xmmGuestRegLane32offset(xmmreg,laneno), Ity_I32 );
540}
541
sewardjfd226452004-12-07 19:02:18 +0000542static IRExpr* getXMMRegLane32F ( UInt xmmreg, Int laneno )
543{
544 return IRExpr_Get( xmmGuestRegLane32offset(xmmreg,laneno), Ity_F32 );
545}
546
sewardjc9a43662004-11-30 18:51:59 +0000547static void putXMMReg ( UInt xmmreg, IRExpr* e )
548{
549 vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_V128);
550 stmt( IRStmt_Put( xmmGuestRegOffset(xmmreg), e ) );
551}
552
sewardj67e002d2004-12-02 18:16:33 +0000553static void putXMMRegLane64 ( UInt xmmreg, Int laneno, IRExpr* e )
554{
555 vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_I64);
556 stmt( IRStmt_Put( xmmGuestRegLane64offset(xmmreg,laneno), e ) );
557}
558
sewardjfd226452004-12-07 19:02:18 +0000559static void putXMMRegLane64F ( UInt xmmreg, Int laneno, IRExpr* e )
560{
561 vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_F64);
562 stmt( IRStmt_Put( xmmGuestRegLane64offset(xmmreg,laneno), e ) );
563}
564
sewardj4cb918d2004-12-03 19:43:31 +0000565static void putXMMRegLane32F ( UInt xmmreg, Int laneno, IRExpr* e )
sewardj67e002d2004-12-02 18:16:33 +0000566{
sewardj4cb918d2004-12-03 19:43:31 +0000567 vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_F32);
sewardj67e002d2004-12-02 18:16:33 +0000568 stmt( IRStmt_Put( xmmGuestRegLane32offset(xmmreg,laneno), e ) );
569}
570
sewardj9636b442004-12-04 01:38:37 +0000571static void putXMMRegLane32 ( UInt xmmreg, Int laneno, IRExpr* e )
572{
573 vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_I32);
574 stmt( IRStmt_Put( xmmGuestRegLane32offset(xmmreg,laneno), e ) );
575}
576
sewardje5854d62004-12-09 03:44:34 +0000577static void putXMMRegLane16 ( UInt xmmreg, Int laneno, IRExpr* e )
578{
579 vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_I16);
580 stmt( IRStmt_Put( xmmGuestRegLane16offset(xmmreg,laneno), e ) );
581}
582
sewardj41f43bc2004-07-08 14:23:22 +0000583static void assign ( IRTemp dst, IRExpr* e )
sewardjd1061ab2004-07-08 01:45:30 +0000584{
sewardj41f43bc2004-07-08 14:23:22 +0000585 stmt( IRStmt_Tmp(dst, e) );
sewardjd1061ab2004-07-08 01:45:30 +0000586}
587
sewardj41f43bc2004-07-08 14:23:22 +0000588static void storeLE ( IRExpr* addr, IRExpr* data )
sewardjd1061ab2004-07-08 01:45:30 +0000589{
sewardjaf1ceca2005-06-30 23:31:27 +0000590 stmt( IRStmt_Store(Iend_LE,addr,data) );
sewardjd1061ab2004-07-08 01:45:30 +0000591}
592
sewardje87b4842004-07-10 12:23:30 +0000593static IRExpr* unop ( IROp op, IRExpr* a )
594{
595 return IRExpr_Unop(op, a);
596}
597
sewardjd1061ab2004-07-08 01:45:30 +0000598static IRExpr* binop ( IROp op, IRExpr* a1, IRExpr* a2 )
599{
600 return IRExpr_Binop(op, a1, a2);
601}
602
603static IRExpr* mkexpr ( IRTemp tmp )
604{
605 return IRExpr_Tmp(tmp);
606}
607
sewardjc2ac51e2004-07-12 01:03:26 +0000608static IRExpr* mkU8 ( UInt i )
609{
610 vassert(i < 256);
sewardj2d49b432005-02-01 00:37:06 +0000611 return IRExpr_Const(IRConst_U8( (UChar)i ));
sewardjc2ac51e2004-07-12 01:03:26 +0000612}
613
614static IRExpr* mkU16 ( UInt i )
615{
616 vassert(i < 65536);
sewardj2d49b432005-02-01 00:37:06 +0000617 return IRExpr_Const(IRConst_U16( (UShort)i ));
sewardjc2ac51e2004-07-12 01:03:26 +0000618}
619
sewardjd1061ab2004-07-08 01:45:30 +0000620static IRExpr* mkU32 ( UInt i )
621{
622 return IRExpr_Const(IRConst_U32(i));
sewardjc9a65702004-07-07 16:32:57 +0000623}
624
sewardj95535fe2004-12-15 17:42:58 +0000625static IRExpr* mkU64 ( ULong i )
626{
627 return IRExpr_Const(IRConst_U64(i));
628}
629
sewardj41f43bc2004-07-08 14:23:22 +0000630static IRExpr* mkU ( IRType ty, UInt i )
631{
sewardjc2ac51e2004-07-12 01:03:26 +0000632 if (ty == Ity_I8) return mkU8(i);
633 if (ty == Ity_I16) return mkU16(i);
634 if (ty == Ity_I32) return mkU32(i);
sewardje90ad6a2004-07-10 19:02:10 +0000635 /* If this panics, it usually means you passed a size (1,2,4)
636 value as the IRType, rather than a real IRType. */
sewardj41f43bc2004-07-08 14:23:22 +0000637 vpanic("mkU(x86)");
638}
639
sewardj1e6ad742004-12-02 16:16:11 +0000640static IRExpr* mkV128 ( UShort mask )
641{
642 return IRExpr_Const(IRConst_V128(mask));
643}
644
sewardj41f43bc2004-07-08 14:23:22 +0000645static IRExpr* loadLE ( IRType ty, IRExpr* data )
646{
sewardjaf1ceca2005-06-30 23:31:27 +0000647 return IRExpr_Load(Iend_LE,ty,data);
sewardj41f43bc2004-07-08 14:23:22 +0000648}
649
650static IROp mkSizedOp ( IRType ty, IROp op8 )
651{
sewardje05c42c2004-07-08 20:25:10 +0000652 Int adj;
sewardj41f43bc2004-07-08 14:23:22 +0000653 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
654 vassert(op8 == Iop_Add8 || op8 == Iop_Sub8
sewardj41f43bc2004-07-08 14:23:22 +0000655 || op8 == Iop_Mul8
656 || op8 == Iop_Or8 || op8 == Iop_And8 || op8 == Iop_Xor8
sewardj5bd4d162004-11-10 13:02:48 +0000657 || op8 == Iop_Shl8 || op8 == Iop_Shr8 || op8 == Iop_Sar8
sewardje90ad6a2004-07-10 19:02:10 +0000658 || op8 == Iop_CmpEQ8 || op8 == Iop_CmpNE8
sewardj71a35e72005-05-03 12:20:15 +0000659 || op8 == Iop_Not8 || op8 == Iop_Neg8);
sewardje05c42c2004-07-08 20:25:10 +0000660 adj = ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
661 return adj + op8;
sewardj41f43bc2004-07-08 14:23:22 +0000662}
663
sewardj9334b0f2004-07-10 22:43:54 +0000664static IROp mkWidenOp ( Int szSmall, Int szBig, Bool signd )
sewardj41f43bc2004-07-08 14:23:22 +0000665{
sewardj9334b0f2004-07-10 22:43:54 +0000666 if (szSmall == 1 && szBig == 4) {
667 return signd ? Iop_8Sto32 : Iop_8Uto32;
sewardj41f43bc2004-07-08 14:23:22 +0000668 }
sewardj9334b0f2004-07-10 22:43:54 +0000669 if (szSmall == 1 && szBig == 2) {
670 return signd ? Iop_8Sto16 : Iop_8Uto16;
671 }
672 if (szSmall == 2 && szBig == 4) {
673 return signd ? Iop_16Sto32 : Iop_16Uto32;
674 }
sewardj948d48b2004-11-05 19:49:09 +0000675 vpanic("mkWidenOp(x86,guest)");
sewardj41f43bc2004-07-08 14:23:22 +0000676}
677
sewardjbaa66082005-08-23 17:29:27 +0000678static IRExpr* mkAnd1 ( IRExpr* x, IRExpr* y )
679{
680 vassert(typeOfIRExpr(irbb->tyenv,x) == Ity_I1);
681 vassert(typeOfIRExpr(irbb->tyenv,y) == Ity_I1);
682 return unop(Iop_32to1,
683 binop(Iop_And32,
684 unop(Iop_1Uto32,x),
685 unop(Iop_1Uto32,y)));
686}
687
sewardj41f43bc2004-07-08 14:23:22 +0000688
689/*------------------------------------------------------------*/
690/*--- Helpers for %eflags. ---*/
691/*------------------------------------------------------------*/
692
sewardj0611d802004-07-11 02:37:54 +0000693/* -------------- Evaluating the flags-thunk. -------------- */
sewardjc9a65702004-07-07 16:32:57 +0000694
sewardje87b4842004-07-10 12:23:30 +0000695/* Build IR to calculate all the eflags from stored
sewardj2a2ba8b2004-11-08 13:14:06 +0000696 CC_OP/CC_DEP1/CC_DEP2/CC_NDEP. Returns an expression ::
697 Ity_I32. */
sewardj2a9ad022004-11-25 02:46:58 +0000698static IRExpr* mk_x86g_calculate_eflags_all ( void )
sewardje87b4842004-07-10 12:23:30 +0000699{
sewardjf9655262004-10-31 20:02:16 +0000700 IRExpr** args
sewardj2a2ba8b2004-11-08 13:14:06 +0000701 = mkIRExprVec_4( IRExpr_Get(OFFB_CC_OP, Ity_I32),
702 IRExpr_Get(OFFB_CC_DEP1, Ity_I32),
703 IRExpr_Get(OFFB_CC_DEP2, Ity_I32),
704 IRExpr_Get(OFFB_CC_NDEP, Ity_I32) );
sewardj43c56462004-11-06 12:17:57 +0000705 IRExpr* call
706 = mkIRExprCCall(
707 Ity_I32,
708 0/*regparm*/,
sewardj2a9ad022004-11-25 02:46:58 +0000709 "x86g_calculate_eflags_all", &x86g_calculate_eflags_all,
sewardj43c56462004-11-06 12:17:57 +0000710 args
711 );
sewardj2a2ba8b2004-11-08 13:14:06 +0000712 /* Exclude OP and NDEP from definedness checking. We're only
713 interested in DEP1 and DEP2. */
714 call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<3);
sewardj43c56462004-11-06 12:17:57 +0000715 return call;
sewardje87b4842004-07-10 12:23:30 +0000716}
717
sewardj84ff0652004-08-23 16:16:08 +0000718/* Build IR to calculate some particular condition from stored
sewardj2a2ba8b2004-11-08 13:14:06 +0000719 CC_OP/CC_DEP1/CC_DEP2/CC_NDEP. Returns an expression ::
720 Ity_Bit. */
sewardj2a9ad022004-11-25 02:46:58 +0000721static IRExpr* mk_x86g_calculate_condition ( X86Condcode cond )
sewardj84ff0652004-08-23 16:16:08 +0000722{
sewardjf9655262004-10-31 20:02:16 +0000723 IRExpr** args
sewardj2a2ba8b2004-11-08 13:14:06 +0000724 = mkIRExprVec_5( mkU32(cond),
sewardjf9655262004-10-31 20:02:16 +0000725 IRExpr_Get(OFFB_CC_OP, Ity_I32),
sewardj2a2ba8b2004-11-08 13:14:06 +0000726 IRExpr_Get(OFFB_CC_DEP1, Ity_I32),
727 IRExpr_Get(OFFB_CC_DEP2, Ity_I32),
728 IRExpr_Get(OFFB_CC_NDEP, Ity_I32) );
sewardj43c56462004-11-06 12:17:57 +0000729 IRExpr* call
730 = mkIRExprCCall(
731 Ity_I32,
732 0/*regparm*/,
sewardj2a9ad022004-11-25 02:46:58 +0000733 "x86g_calculate_condition", &x86g_calculate_condition,
sewardj43c56462004-11-06 12:17:57 +0000734 args
735 );
sewardj2a2ba8b2004-11-08 13:14:06 +0000736 /* Exclude the requested condition, OP and NDEP from definedness
737 checking. We're only interested in DEP1 and DEP2. */
738 call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<1) | (1<<4);
sewardj43c56462004-11-06 12:17:57 +0000739 return unop(Iop_32to1, call);
740}
741
742/* Build IR to calculate just the carry flag from stored
sewardj2a2ba8b2004-11-08 13:14:06 +0000743 CC_OP/CC_DEP1/CC_DEP2/CC_NDEP. Returns an expression :: Ity_I32. */
sewardj2a9ad022004-11-25 02:46:58 +0000744static IRExpr* mk_x86g_calculate_eflags_c ( void )
sewardj43c56462004-11-06 12:17:57 +0000745{
746 IRExpr** args
sewardj2a2ba8b2004-11-08 13:14:06 +0000747 = mkIRExprVec_4( IRExpr_Get(OFFB_CC_OP, Ity_I32),
748 IRExpr_Get(OFFB_CC_DEP1, Ity_I32),
749 IRExpr_Get(OFFB_CC_DEP2, Ity_I32),
750 IRExpr_Get(OFFB_CC_NDEP, Ity_I32) );
sewardj43c56462004-11-06 12:17:57 +0000751 IRExpr* call
752 = mkIRExprCCall(
753 Ity_I32,
sewardj893a3302005-01-24 10:49:02 +0000754 3/*regparm*/,
sewardj2a9ad022004-11-25 02:46:58 +0000755 "x86g_calculate_eflags_c", &x86g_calculate_eflags_c,
sewardj43c56462004-11-06 12:17:57 +0000756 args
757 );
sewardj2a2ba8b2004-11-08 13:14:06 +0000758 /* Exclude OP and NDEP from definedness checking. We're only
759 interested in DEP1 and DEP2. */
760 call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<3);
sewardj43c56462004-11-06 12:17:57 +0000761 return call;
sewardj84ff0652004-08-23 16:16:08 +0000762}
763
sewardje87b4842004-07-10 12:23:30 +0000764
sewardj0611d802004-07-11 02:37:54 +0000765/* -------------- Building the flags-thunk. -------------- */
766
sewardjb9c5cf62004-08-24 15:10:38 +0000767/* The machinery in this section builds the flag-thunk following a
768 flag-setting operation. Hence the various setFlags_* functions.
sewardjb9c5cf62004-08-24 15:10:38 +0000769*/
770
771static Bool isAddSub ( IROp op8 )
772{
sewardj2d49b432005-02-01 00:37:06 +0000773 return toBool(op8 == Iop_Add8 || op8 == Iop_Sub8);
sewardjb9c5cf62004-08-24 15:10:38 +0000774}
sewardj0611d802004-07-11 02:37:54 +0000775
sewardj2a2ba8b2004-11-08 13:14:06 +0000776static Bool isLogic ( IROp op8 )
777{
sewardj2d49b432005-02-01 00:37:06 +0000778 return toBool(op8 == Iop_And8 || op8 == Iop_Or8 || op8 == Iop_Xor8);
sewardj2a2ba8b2004-11-08 13:14:06 +0000779}
780
sewardja2384712004-07-29 14:36:40 +0000781/* U-widen 8/16/32 bit int expr to 32. */
sewardjc22a6fd2004-07-29 23:41:47 +0000782static IRExpr* widenUto32 ( IRExpr* e )
sewardj443cd9d2004-07-18 23:06:45 +0000783{
784 switch (typeOfIRExpr(irbb->tyenv,e)) {
785 case Ity_I32: return e;
786 case Ity_I16: return unop(Iop_16Uto32,e);
787 case Ity_I8: return unop(Iop_8Uto32,e);
788 default: vpanic("widenUto32");
789 }
790}
791
sewardjc22a6fd2004-07-29 23:41:47 +0000792/* S-widen 8/16/32 bit int expr to 32. */
793static IRExpr* widenSto32 ( IRExpr* e )
794{
795 switch (typeOfIRExpr(irbb->tyenv,e)) {
796 case Ity_I32: return e;
797 case Ity_I16: return unop(Iop_16Sto32,e);
798 case Ity_I8: return unop(Iop_8Sto32,e);
799 default: vpanic("widenSto32");
800 }
801}
802
sewardja2384712004-07-29 14:36:40 +0000803/* Narrow 8/16/32 bit int expr to 8/16/32. Clearly only some
804 of these combinations make sense. */
805static IRExpr* narrowTo ( IRType dst_ty, IRExpr* e )
806{
807 IRType src_ty = typeOfIRExpr(irbb->tyenv,e);
808 if (src_ty == dst_ty)
809 return e;
810 if (src_ty == Ity_I32 && dst_ty == Ity_I16)
811 return unop(Iop_32to16, e);
812 if (src_ty == Ity_I32 && dst_ty == Ity_I8)
813 return unop(Iop_32to8, e);
814
815 vex_printf("\nsrc, dst tys are: ");
816 ppIRType(src_ty);
817 vex_printf(", ");
818 ppIRType(dst_ty);
819 vex_printf("\n");
820 vpanic("narrowTo(x86)");
821}
822
sewardj443cd9d2004-07-18 23:06:45 +0000823
sewardj2a2ba8b2004-11-08 13:14:06 +0000824/* Set the flags thunk OP, DEP1 and DEP2 fields. The supplied op is
sewardj948d48b2004-11-05 19:49:09 +0000825 auto-sized up to the real op. */
sewardj0611d802004-07-11 02:37:54 +0000826
sewardj2a2ba8b2004-11-08 13:14:06 +0000827static
828void setFlags_DEP1_DEP2 ( IROp op8, IRTemp dep1, IRTemp dep2, IRType ty )
sewardj0611d802004-07-11 02:37:54 +0000829{
sewardjb9c5cf62004-08-24 15:10:38 +0000830 Int ccOp = ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
831
832 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
833
834 switch (op8) {
sewardj2a9ad022004-11-25 02:46:58 +0000835 case Iop_Add8: ccOp += X86G_CC_OP_ADDB; break;
836 case Iop_Sub8: ccOp += X86G_CC_OP_SUBB; break;
sewardjb9c5cf62004-08-24 15:10:38 +0000837 default: ppIROp(op8);
sewardj2a2ba8b2004-11-08 13:14:06 +0000838 vpanic("setFlags_DEP1_DEP2(x86)");
sewardjb9c5cf62004-08-24 15:10:38 +0000839 }
sewardj2a2ba8b2004-11-08 13:14:06 +0000840 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(ccOp)) );
841 stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto32(mkexpr(dep1))) );
842 stmt( IRStmt_Put( OFFB_CC_DEP2, widenUto32(mkexpr(dep2))) );
sewardja3b7e3a2005-04-05 01:54:19 +0000843 /* Set NDEP even though it isn't used. This makes redundant-PUT
844 elimination of previous stores to this field work better. */
845 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardjb9c5cf62004-08-24 15:10:38 +0000846}
847
848
sewardj2a2ba8b2004-11-08 13:14:06 +0000849/* Set the OP and DEP1 fields only, and write zero to DEP2. */
sewardjb9c5cf62004-08-24 15:10:38 +0000850
sewardj2a2ba8b2004-11-08 13:14:06 +0000851static
852void setFlags_DEP1 ( IROp op8, IRTemp dep1, IRType ty )
sewardjb9c5cf62004-08-24 15:10:38 +0000853{
854 Int ccOp = ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
sewardj0611d802004-07-11 02:37:54 +0000855
856 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
857
858 switch (op8) {
859 case Iop_Or8:
860 case Iop_And8:
sewardj2a9ad022004-11-25 02:46:58 +0000861 case Iop_Xor8: ccOp += X86G_CC_OP_LOGICB; break;
sewardj0611d802004-07-11 02:37:54 +0000862 default: ppIROp(op8);
sewardj2a2ba8b2004-11-08 13:14:06 +0000863 vpanic("setFlags_DEP1(x86)");
sewardj0611d802004-07-11 02:37:54 +0000864 }
sewardj2a2ba8b2004-11-08 13:14:06 +0000865 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(ccOp)) );
866 stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto32(mkexpr(dep1))) );
867 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0)) );
sewardja3b7e3a2005-04-05 01:54:19 +0000868 /* Set NDEP even though it isn't used. This makes redundant-PUT
869 elimination of previous stores to this field work better. */
870 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardj0611d802004-07-11 02:37:54 +0000871}
872
873
sewardj948d48b2004-11-05 19:49:09 +0000874/* For shift operations, we put in the result and the undershifted
875 result. Except if the shift amount is zero, the thunk is left
876 unchanged. */
sewardj0611d802004-07-11 02:37:54 +0000877
sewardj2a2ba8b2004-11-08 13:14:06 +0000878static void setFlags_DEP1_DEP2_shift ( IROp op32,
879 IRTemp res,
880 IRTemp resUS,
881 IRType ty,
882 IRTemp guard )
sewardj0611d802004-07-11 02:37:54 +0000883{
sewardjc22a6fd2004-07-29 23:41:47 +0000884 Int ccOp = ty==Ity_I8 ? 2 : (ty==Ity_I16 ? 1 : 0);
sewardj0611d802004-07-11 02:37:54 +0000885
886 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
887 vassert(guard);
888
sewardj2a2ba8b2004-11-08 13:14:06 +0000889 /* Both kinds of right shifts are handled by the same thunk
890 operation. */
sewardjc22a6fd2004-07-29 23:41:47 +0000891 switch (op32) {
892 case Iop_Shr32:
sewardj2a9ad022004-11-25 02:46:58 +0000893 case Iop_Sar32: ccOp = X86G_CC_OP_SHRL - ccOp; break;
894 case Iop_Shl32: ccOp = X86G_CC_OP_SHLL - ccOp; break;
sewardjc22a6fd2004-07-29 23:41:47 +0000895 default: ppIROp(op32);
sewardj2a2ba8b2004-11-08 13:14:06 +0000896 vpanic("setFlags_DEP1_DEP2_shift(x86)");
sewardj0611d802004-07-11 02:37:54 +0000897 }
898
sewardj2a2ba8b2004-11-08 13:14:06 +0000899 /* DEP1 contains the result, DEP2 contains the undershifted value. */
sewardjeeb9ef82004-07-15 12:39:03 +0000900 stmt( IRStmt_Put( OFFB_CC_OP,
sewardj4042c7e2004-07-18 01:28:30 +0000901 IRExpr_Mux0X( mkexpr(guard),
902 IRExpr_Get(OFFB_CC_OP,Ity_I32),
903 mkU32(ccOp))) );
sewardj2a2ba8b2004-11-08 13:14:06 +0000904 stmt( IRStmt_Put( OFFB_CC_DEP1,
sewardj4042c7e2004-07-18 01:28:30 +0000905 IRExpr_Mux0X( mkexpr(guard),
sewardj2a2ba8b2004-11-08 13:14:06 +0000906 IRExpr_Get(OFFB_CC_DEP1,Ity_I32),
sewardj948d48b2004-11-05 19:49:09 +0000907 widenUto32(mkexpr(res)))) );
sewardj2a2ba8b2004-11-08 13:14:06 +0000908 stmt( IRStmt_Put( OFFB_CC_DEP2,
sewardj4042c7e2004-07-18 01:28:30 +0000909 IRExpr_Mux0X( mkexpr(guard),
sewardj2a2ba8b2004-11-08 13:14:06 +0000910 IRExpr_Get(OFFB_CC_DEP2,Ity_I32),
sewardj948d48b2004-11-05 19:49:09 +0000911 widenUto32(mkexpr(resUS)))) );
sewardja3b7e3a2005-04-05 01:54:19 +0000912 /* Set NDEP even though it isn't used. This makes redundant-PUT
913 elimination of previous stores to this field work better. */
914 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardj0611d802004-07-11 02:37:54 +0000915}
916
917
sewardj2a2ba8b2004-11-08 13:14:06 +0000918/* For the inc/dec case, we store in DEP1 the result value and in NDEP
sewardj948d48b2004-11-05 19:49:09 +0000919 the former value of the carry flag, which unfortunately we have to
920 compute. */
sewardj0611d802004-07-11 02:37:54 +0000921
sewardj948d48b2004-11-05 19:49:09 +0000922static void setFlags_INC_DEC ( Bool inc, IRTemp res, IRType ty )
sewardj0611d802004-07-11 02:37:54 +0000923{
sewardj2a9ad022004-11-25 02:46:58 +0000924 Int ccOp = inc ? X86G_CC_OP_INCB : X86G_CC_OP_DECB;
sewardj0611d802004-07-11 02:37:54 +0000925
926 ccOp += ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
927 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
928
929 /* This has to come first, because calculating the C flag
sewardj2a2ba8b2004-11-08 13:14:06 +0000930 may require reading all four thunk fields. */
sewardj2a9ad022004-11-25 02:46:58 +0000931 stmt( IRStmt_Put( OFFB_CC_NDEP, mk_x86g_calculate_eflags_c()) );
sewardj2a2ba8b2004-11-08 13:14:06 +0000932 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(ccOp)) );
933 stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(res)) );
934 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0)) );
sewardj0611d802004-07-11 02:37:54 +0000935}
936
937
sewardj2a2ba8b2004-11-08 13:14:06 +0000938/* Multiplies are pretty much like add and sub: DEP1 and DEP2 hold the
939 two arguments. */
sewardjcf780b42004-07-13 18:42:17 +0000940
941static
sewardj2a2ba8b2004-11-08 13:14:06 +0000942void setFlags_MUL ( IRType ty, IRTemp arg1, IRTemp arg2, UInt base_op )
sewardjcf780b42004-07-13 18:42:17 +0000943{
944 switch (ty) {
sewardj2a2ba8b2004-11-08 13:14:06 +0000945 case Ity_I8:
946 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(base_op+0) ) );
947 break;
948 case Ity_I16:
949 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(base_op+1) ) );
950 break;
951 case Ity_I32:
952 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(base_op+2) ) );
953 break;
954 default:
955 vpanic("setFlags_MUL(x86)");
sewardjcf780b42004-07-13 18:42:17 +0000956 }
sewardj2a2ba8b2004-11-08 13:14:06 +0000957 stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto32(mkexpr(arg1)) ));
958 stmt( IRStmt_Put( OFFB_CC_DEP2, widenUto32(mkexpr(arg2)) ));
sewardja3b7e3a2005-04-05 01:54:19 +0000959 /* Set NDEP even though it isn't used. This makes redundant-PUT
960 elimination of previous stores to this field work better. */
961 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardjcf780b42004-07-13 18:42:17 +0000962}
963
964
sewardj3af115f2004-07-14 02:46:52 +0000965/* -------------- Condition codes. -------------- */
966
sewardje87b4842004-07-10 12:23:30 +0000967/* Condition codes, using the Intel encoding. */
sewardj0611d802004-07-11 02:37:54 +0000968
sewardj2d49b432005-02-01 00:37:06 +0000969static HChar* name_X86Condcode ( X86Condcode cond )
sewardje87b4842004-07-10 12:23:30 +0000970{
971 switch (cond) {
sewardj2a9ad022004-11-25 02:46:58 +0000972 case X86CondO: return "o";
973 case X86CondNO: return "no";
974 case X86CondB: return "b";
975 case X86CondNB: return "nb";
976 case X86CondZ: return "z";
977 case X86CondNZ: return "nz";
978 case X86CondBE: return "be";
979 case X86CondNBE: return "nbe";
980 case X86CondS: return "s";
981 case X86CondNS: return "ns";
982 case X86CondP: return "p";
983 case X86CondNP: return "np";
984 case X86CondL: return "l";
985 case X86CondNL: return "nl";
986 case X86CondLE: return "le";
987 case X86CondNLE: return "nle";
988 case X86CondAlways: return "ALWAYS";
989 default: vpanic("name_X86Condcode");
sewardje87b4842004-07-10 12:23:30 +0000990 }
991}
992
sewardj2a9ad022004-11-25 02:46:58 +0000993static
994X86Condcode positiveIse_X86Condcode ( X86Condcode cond,
sewardjdbf550c2005-01-24 11:54:11 +0000995 Bool* needInvert )
sewardje87b4842004-07-10 12:23:30 +0000996{
sewardj2a9ad022004-11-25 02:46:58 +0000997 vassert(cond >= X86CondO && cond <= X86CondNLE);
sewardje87b4842004-07-10 12:23:30 +0000998 if (cond & 1) {
999 *needInvert = True;
1000 return cond-1;
1001 } else {
1002 *needInvert = False;
1003 return cond;
1004 }
1005}
1006
1007
sewardj3af115f2004-07-14 02:46:52 +00001008/* -------------- Helpers for ADD/SUB with carry. -------------- */
1009
sewardj948d48b2004-11-05 19:49:09 +00001010/* Given ta1, ta2 and tres, compute tres = ADC(ta1,ta2) and set flags
sewardj2a2ba8b2004-11-08 13:14:06 +00001011 appropriately.
sewardj3af115f2004-07-14 02:46:52 +00001012*/
1013static void helper_ADC ( Int sz,
sewardj5bd4d162004-11-10 13:02:48 +00001014 IRTemp tres, IRTemp ta1, IRTemp ta2 )
sewardj3af115f2004-07-14 02:46:52 +00001015{
1016 UInt thunkOp;
sewardj2a2ba8b2004-11-08 13:14:06 +00001017 IRType ty = szToITy(sz);
1018 IRTemp oldc = newTemp(Ity_I32);
1019 IRTemp oldcn = newTemp(ty);
1020 IROp plus = mkSizedOp(ty, Iop_Add8);
1021 IROp xor = mkSizedOp(ty, Iop_Xor8);
sewardja2384712004-07-29 14:36:40 +00001022
1023 vassert(sz == 1 || sz == 2 || sz == 4);
sewardj2a9ad022004-11-25 02:46:58 +00001024 thunkOp = sz==4 ? X86G_CC_OP_ADCL
1025 : (sz==2 ? X86G_CC_OP_ADCW : X86G_CC_OP_ADCB);
sewardj3af115f2004-07-14 02:46:52 +00001026
sewardj2a2ba8b2004-11-08 13:14:06 +00001027 /* oldc = old carry flag, 0 or 1 */
1028 assign( oldc, binop(Iop_And32,
sewardj2a9ad022004-11-25 02:46:58 +00001029 mk_x86g_calculate_eflags_c(),
sewardj5bd4d162004-11-10 13:02:48 +00001030 mkU32(1)) );
sewardj3af115f2004-07-14 02:46:52 +00001031
sewardj2a2ba8b2004-11-08 13:14:06 +00001032 assign( oldcn, narrowTo(ty, mkexpr(oldc)) );
1033
1034 assign( tres, binop(plus,
1035 binop(plus,mkexpr(ta1),mkexpr(ta2)),
1036 mkexpr(oldcn)) );
1037
1038 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(thunkOp) ) );
1039 stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(ta1) ) );
sewardj2a9ad022004-11-25 02:46:58 +00001040 stmt( IRStmt_Put( OFFB_CC_DEP2, binop(xor, mkexpr(ta2),
1041 mkexpr(oldcn)) ) );
sewardj2a2ba8b2004-11-08 13:14:06 +00001042 stmt( IRStmt_Put( OFFB_CC_NDEP, mkexpr(oldc) ) );
sewardj3af115f2004-07-14 02:46:52 +00001043}
1044
1045
sewardj948d48b2004-11-05 19:49:09 +00001046/* Given ta1, ta2 and tres, compute tres = SBB(ta1,ta2) and set flags
sewardj2a2ba8b2004-11-08 13:14:06 +00001047 appropriately.
sewardjcaca9d02004-07-28 07:11:32 +00001048*/
1049static void helper_SBB ( Int sz,
sewardj5bd4d162004-11-10 13:02:48 +00001050 IRTemp tres, IRTemp ta1, IRTemp ta2 )
sewardjcaca9d02004-07-28 07:11:32 +00001051{
1052 UInt thunkOp;
sewardj2a2ba8b2004-11-08 13:14:06 +00001053 IRType ty = szToITy(sz);
1054 IRTemp oldc = newTemp(Ity_I32);
1055 IRTemp oldcn = newTemp(ty);
1056 IROp minus = mkSizedOp(ty, Iop_Sub8);
1057 IROp xor = mkSizedOp(ty, Iop_Xor8);
1058
1059 vassert(sz == 1 || sz == 2 || sz == 4);
sewardj2a9ad022004-11-25 02:46:58 +00001060 thunkOp = sz==4 ? X86G_CC_OP_SBBL
1061 : (sz==2 ? X86G_CC_OP_SBBW : X86G_CC_OP_SBBB);
sewardjcaca9d02004-07-28 07:11:32 +00001062
1063 /* oldc = old carry flag, 0 or 1 */
sewardja2384712004-07-29 14:36:40 +00001064 assign( oldc, binop(Iop_And32,
sewardj2a9ad022004-11-25 02:46:58 +00001065 mk_x86g_calculate_eflags_c(),
sewardj5bd4d162004-11-10 13:02:48 +00001066 mkU32(1)) );
sewardjcaca9d02004-07-28 07:11:32 +00001067
sewardj2a2ba8b2004-11-08 13:14:06 +00001068 assign( oldcn, narrowTo(ty, mkexpr(oldc)) );
sewardja2384712004-07-29 14:36:40 +00001069
sewardj2a2ba8b2004-11-08 13:14:06 +00001070 assign( tres, binop(minus,
1071 binop(minus,mkexpr(ta1),mkexpr(ta2)),
1072 mkexpr(oldcn)) );
sewardjcaca9d02004-07-28 07:11:32 +00001073
sewardj2a2ba8b2004-11-08 13:14:06 +00001074 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(thunkOp) ) );
1075 stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(ta1) ) );
sewardj2a9ad022004-11-25 02:46:58 +00001076 stmt( IRStmt_Put( OFFB_CC_DEP2, binop(xor, mkexpr(ta2),
1077 mkexpr(oldcn)) ) );
sewardj2a2ba8b2004-11-08 13:14:06 +00001078 stmt( IRStmt_Put( OFFB_CC_NDEP, mkexpr(oldc) ) );
sewardjcaca9d02004-07-28 07:11:32 +00001079}
1080
1081
sewardj7dd2eb22005-01-05 10:38:54 +00001082/* -------------- Helpers for disassembly printing. -------------- */
sewardj41f43bc2004-07-08 14:23:22 +00001083
sewardjc9a43662004-11-30 18:51:59 +00001084static HChar* nameGrp1 ( Int opc_aux )
sewardj41f43bc2004-07-08 14:23:22 +00001085{
sewardjc9a43662004-11-30 18:51:59 +00001086 static HChar* grp1_names[8]
sewardj41f43bc2004-07-08 14:23:22 +00001087 = { "add", "or", "adc", "sbb", "and", "sub", "xor", "cmp" };
1088 if (opc_aux < 0 || opc_aux > 7) vpanic("nameGrp1(x86)");
1089 return grp1_names[opc_aux];
1090}
1091
sewardjc9a43662004-11-30 18:51:59 +00001092static HChar* nameGrp2 ( Int opc_aux )
sewardje90ad6a2004-07-10 19:02:10 +00001093{
sewardjc9a43662004-11-30 18:51:59 +00001094 static HChar* grp2_names[8]
sewardje90ad6a2004-07-10 19:02:10 +00001095 = { "rol", "ror", "rcl", "rcr", "shl", "shr", "shl", "sar" };
sewardjc2ac51e2004-07-12 01:03:26 +00001096 if (opc_aux < 0 || opc_aux > 7) vpanic("nameGrp2(x86)");
sewardje90ad6a2004-07-10 19:02:10 +00001097 return grp2_names[opc_aux];
1098}
1099
sewardjc9a43662004-11-30 18:51:59 +00001100static HChar* nameGrp4 ( Int opc_aux )
sewardjc2ac51e2004-07-12 01:03:26 +00001101{
sewardjc9a43662004-11-30 18:51:59 +00001102 static HChar* grp4_names[8]
sewardjc2ac51e2004-07-12 01:03:26 +00001103 = { "inc", "dec", "???", "???", "???", "???", "???", "???" };
1104 if (opc_aux < 0 || opc_aux > 1) vpanic("nameGrp4(x86)");
1105 return grp4_names[opc_aux];
1106}
sewardj0611d802004-07-11 02:37:54 +00001107
sewardjc9a43662004-11-30 18:51:59 +00001108static HChar* nameGrp5 ( Int opc_aux )
sewardj0611d802004-07-11 02:37:54 +00001109{
sewardjc9a43662004-11-30 18:51:59 +00001110 static HChar* grp5_names[8]
sewardj0611d802004-07-11 02:37:54 +00001111 = { "inc", "dec", "call*", "call*", "jmp*", "jmp*", "push", "???" };
1112 if (opc_aux < 0 || opc_aux > 6) vpanic("nameGrp5(x86)");
1113 return grp5_names[opc_aux];
1114}
1115
sewardj490ad382005-03-13 17:25:53 +00001116static HChar* nameGrp8 ( Int opc_aux )
1117{
1118 static HChar* grp8_names[8]
1119 = { "???", "???", "???", "???", "bt", "bts", "btr", "btc" };
1120 if (opc_aux < 4 || opc_aux > 7) vpanic("nameGrp8(x86)");
1121 return grp8_names[opc_aux];
1122}
sewardjc9a65702004-07-07 16:32:57 +00001123
sewardjc9a43662004-11-30 18:51:59 +00001124static HChar* nameIReg ( Int size, Int reg )
sewardjc9a65702004-07-07 16:32:57 +00001125{
sewardjc9a43662004-11-30 18:51:59 +00001126 static HChar* ireg32_names[8]
sewardjc9a65702004-07-07 16:32:57 +00001127 = { "%eax", "%ecx", "%edx", "%ebx",
1128 "%esp", "%ebp", "%esi", "%edi" };
sewardjc9a43662004-11-30 18:51:59 +00001129 static HChar* ireg16_names[8]
sewardjc9a65702004-07-07 16:32:57 +00001130 = { "%ax", "%cx", "%dx", "%bx", "%sp", "%bp", "%si", "%di" };
sewardjc9a43662004-11-30 18:51:59 +00001131 static HChar* ireg8_names[8]
sewardjc9a65702004-07-07 16:32:57 +00001132 = { "%al", "%cl", "%dl", "%bl",
1133 "%ah{sp}", "%ch{bp}", "%dh{si}", "%bh{di}" };
1134 if (reg < 0 || reg > 7) goto bad;
1135 switch (size) {
1136 case 4: return ireg32_names[reg];
1137 case 2: return ireg16_names[reg];
1138 case 1: return ireg8_names[reg];
1139 }
1140 bad:
1141 vpanic("nameIReg(X86)");
1142 return NULL; /*notreached*/
1143}
1144
sewardjc9a43662004-11-30 18:51:59 +00001145static HChar* nameSReg ( UInt sreg )
sewardj063f02f2004-10-20 12:36:12 +00001146{
1147 switch (sreg) {
1148 case R_ES: return "%es";
1149 case R_CS: return "%cs";
1150 case R_SS: return "%ss";
1151 case R_DS: return "%ds";
1152 case R_FS: return "%fs";
1153 case R_GS: return "%gs";
1154 default: vpanic("nameSReg(x86)");
1155 }
1156}
1157
sewardjc9a43662004-11-30 18:51:59 +00001158static HChar* nameMMXReg ( Int mmxreg )
sewardj464efa42004-11-19 22:17:29 +00001159{
sewardjc9a43662004-11-30 18:51:59 +00001160 static HChar* mmx_names[8]
sewardj464efa42004-11-19 22:17:29 +00001161 = { "%mm0", "%mm1", "%mm2", "%mm3", "%mm4", "%mm5", "%mm6", "%mm7" };
1162 if (mmxreg < 0 || mmxreg > 7) vpanic("nameMMXReg(x86,guest)");
1163 return mmx_names[mmxreg];
1164}
1165
sewardjc9a43662004-11-30 18:51:59 +00001166static HChar* nameXMMReg ( Int xmmreg )
1167{
1168 static HChar* xmm_names[8]
1169 = { "%xmm0", "%xmm1", "%xmm2", "%xmm3",
1170 "%xmm4", "%xmm5", "%xmm6", "%xmm7" };
1171 if (xmmreg < 0 || xmmreg > 7) vpanic("name_of_xmm_reg");
1172 return xmm_names[xmmreg];
1173}
sewardj464efa42004-11-19 22:17:29 +00001174
sewardj2d49b432005-02-01 00:37:06 +00001175static HChar* nameMMXGran ( Int gran )
sewardj464efa42004-11-19 22:17:29 +00001176{
1177 switch (gran) {
1178 case 0: return "b";
1179 case 1: return "w";
1180 case 2: return "d";
1181 case 3: return "q";
1182 default: vpanic("nameMMXGran(x86,guest)");
1183 }
1184}
sewardjc9a65702004-07-07 16:32:57 +00001185
sewardj2d49b432005-02-01 00:37:06 +00001186static HChar nameISize ( Int size )
sewardjc9a65702004-07-07 16:32:57 +00001187{
1188 switch (size) {
1189 case 4: return 'l';
1190 case 2: return 'w';
1191 case 1: return 'b';
1192 default: vpanic("nameISize(x86)");
1193 }
1194}
1195
sewardjd1061ab2004-07-08 01:45:30 +00001196
1197/*------------------------------------------------------------*/
1198/*--- JMP helpers ---*/
1199/*------------------------------------------------------------*/
1200
sewardj78c19df2004-07-12 22:49:27 +00001201static void jmp_lit( IRJumpKind kind, Addr32 d32 )
sewardjd1061ab2004-07-08 01:45:30 +00001202{
sewardje539a402004-07-14 18:24:17 +00001203 irbb->next = mkU32(d32);
1204 irbb->jumpkind = kind;
sewardjd1061ab2004-07-08 01:45:30 +00001205}
1206
sewardj78c19df2004-07-12 22:49:27 +00001207static void jmp_treg( IRJumpKind kind, IRTemp t )
sewardje05c42c2004-07-08 20:25:10 +00001208{
sewardje539a402004-07-14 18:24:17 +00001209 irbb->next = mkexpr(t);
1210 irbb->jumpkind = kind;
sewardje05c42c2004-07-08 20:25:10 +00001211}
sewardje87b4842004-07-10 12:23:30 +00001212
sewardj2a9ad022004-11-25 02:46:58 +00001213static
1214void jcc_01( X86Condcode cond, Addr32 d32_false, Addr32 d32_true )
sewardje87b4842004-07-10 12:23:30 +00001215{
sewardj2a9ad022004-11-25 02:46:58 +00001216 Bool invert;
1217 X86Condcode condPos;
1218 condPos = positiveIse_X86Condcode ( cond, &invert );
sewardje87b4842004-07-10 12:23:30 +00001219 if (invert) {
sewardj2a9ad022004-11-25 02:46:58 +00001220 stmt( IRStmt_Exit( mk_x86g_calculate_condition(condPos),
sewardj893aada2004-11-29 19:57:54 +00001221 Ijk_Boring,
sewardj78c19df2004-07-12 22:49:27 +00001222 IRConst_U32(d32_false) ) );
sewardje539a402004-07-14 18:24:17 +00001223 irbb->next = mkU32(d32_true);
1224 irbb->jumpkind = Ijk_Boring;
sewardje87b4842004-07-10 12:23:30 +00001225 } else {
sewardj2a9ad022004-11-25 02:46:58 +00001226 stmt( IRStmt_Exit( mk_x86g_calculate_condition(condPos),
sewardj893aada2004-11-29 19:57:54 +00001227 Ijk_Boring,
sewardj78c19df2004-07-12 22:49:27 +00001228 IRConst_U32(d32_true) ) );
sewardje539a402004-07-14 18:24:17 +00001229 irbb->next = mkU32(d32_false);
1230 irbb->jumpkind = Ijk_Boring;
sewardje87b4842004-07-10 12:23:30 +00001231 }
1232}
sewardjc9a65702004-07-07 16:32:57 +00001233
1234
sewardjd1061ab2004-07-08 01:45:30 +00001235/*------------------------------------------------------------*/
1236/*--- Disassembling addressing modes ---*/
1237/*------------------------------------------------------------*/
sewardjc9a65702004-07-07 16:32:57 +00001238
sewardjd1061ab2004-07-08 01:45:30 +00001239static
sewardj2d49b432005-02-01 00:37:06 +00001240HChar* sorbTxt ( UChar sorb )
sewardjd1061ab2004-07-08 01:45:30 +00001241{
1242 switch (sorb) {
1243 case 0: return ""; /* no override */
1244 case 0x3E: return "%ds";
1245 case 0x26: return "%es:";
1246 case 0x64: return "%fs:";
1247 case 0x65: return "%gs:";
sewardj7df596b2004-12-06 14:29:12 +00001248 default: vpanic("sorbTxt(x86,guest)");
sewardjd1061ab2004-07-08 01:45:30 +00001249 }
1250}
1251
1252
sewardj7df596b2004-12-06 14:29:12 +00001253/* 'virtual' is an IRExpr* holding a virtual address. Convert it to a
1254 linear address by adding any required segment override as indicated
1255 by sorb. */
sewardjd1061ab2004-07-08 01:45:30 +00001256static
1257IRExpr* handleSegOverride ( UChar sorb, IRExpr* virtual )
1258{
sewardj3bd6f3e2004-12-13 10:48:19 +00001259 Int sreg;
1260 IRType hWordTy;
1261 IRTemp ldt_ptr, gdt_ptr, seg_selector, r64;
sewardjd1061ab2004-07-08 01:45:30 +00001262
1263 if (sorb == 0)
1264 /* the common case - no override */
1265 return virtual;
1266
sewardjd1061ab2004-07-08 01:45:30 +00001267 switch (sorb) {
1268 case 0x3E: sreg = R_DS; break;
1269 case 0x26: sreg = R_ES; break;
1270 case 0x64: sreg = R_FS; break;
1271 case 0x65: sreg = R_GS; break;
sewardj7df596b2004-12-06 14:29:12 +00001272 default: vpanic("handleSegOverride(x86,guest)");
sewardjd1061ab2004-07-08 01:45:30 +00001273 }
1274
sewardj3bd6f3e2004-12-13 10:48:19 +00001275 hWordTy = sizeof(HWord)==4 ? Ity_I32 : Ity_I64;
sewardjd1061ab2004-07-08 01:45:30 +00001276
sewardj3bd6f3e2004-12-13 10:48:19 +00001277 seg_selector = newTemp(Ity_I32);
1278 ldt_ptr = newTemp(hWordTy);
1279 gdt_ptr = newTemp(hWordTy);
1280 r64 = newTemp(Ity_I64);
sewardjd1061ab2004-07-08 01:45:30 +00001281
sewardj3bd6f3e2004-12-13 10:48:19 +00001282 assign( seg_selector, unop(Iop_16Uto32, getSReg(sreg)) );
1283 assign( ldt_ptr, IRExpr_Get( OFFB_LDT, hWordTy ));
1284 assign( gdt_ptr, IRExpr_Get( OFFB_GDT, hWordTy ));
sewardj7df596b2004-12-06 14:29:12 +00001285
sewardj3bd6f3e2004-12-13 10:48:19 +00001286 /*
1287 Call this to do the translation and limit checks:
1288 ULong x86g_use_seg_selector ( HWord ldt, HWord gdt,
1289 UInt seg_selector, UInt virtual_addr )
1290 */
1291 assign(
1292 r64,
1293 mkIRExprCCall(
1294 Ity_I64,
1295 0/*regparms*/,
1296 "x86g_use_seg_selector",
1297 &x86g_use_seg_selector,
1298 mkIRExprVec_4( mkexpr(ldt_ptr), mkexpr(gdt_ptr),
1299 mkexpr(seg_selector), virtual)
1300 )
1301 );
sewardj7df596b2004-12-06 14:29:12 +00001302
sewardj52444cb2004-12-13 14:09:01 +00001303 /* If the high 32 of the result are non-zero, there was a
1304 failure in address translation. In which case, make a
1305 quick exit.
1306 */
1307 stmt(
1308 IRStmt_Exit(
1309 binop(Iop_CmpNE32, unop(Iop_64HIto32, mkexpr(r64)), mkU32(0)),
1310 Ijk_MapFail,
sewardj9e6491a2005-07-02 19:24:10 +00001311 IRConst_U32( guest_EIP_curr_instr )
sewardj52444cb2004-12-13 14:09:01 +00001312 )
1313 );
1314
1315 /* otherwise, here's the translated result. */
sewardj3bd6f3e2004-12-13 10:48:19 +00001316 return unop(Iop_64to32, mkexpr(r64));
sewardjd1061ab2004-07-08 01:45:30 +00001317}
1318
1319
1320/* Generate IR to calculate an address indicated by a ModRM and
1321 following SIB bytes. The expression, and the number of bytes in
1322 the address mode, are returned. Note that this fn should not be
1323 called if the R/M part of the address denotes a register instead of
1324 memory. If print_codegen is true, text of the addressing mode is
sewardj940e8c92004-07-11 16:53:24 +00001325 placed in buf.
1326
1327 The computed address is stored in a new tempreg, and the
1328 identity of the tempreg is returned. */
1329
1330static IRTemp disAMode_copy2tmp ( IRExpr* addr32 )
1331{
1332 IRTemp tmp = newTemp(Ity_I32);
1333 assign( tmp, addr32 );
1334 return tmp;
1335}
sewardjd1061ab2004-07-08 01:45:30 +00001336
1337static
sewardj52d04912005-07-03 00:52:48 +00001338IRTemp disAMode ( Int* len, UChar sorb, Int delta, HChar* buf )
sewardjd1061ab2004-07-08 01:45:30 +00001339{
1340 UChar mod_reg_rm = getIByte(delta);
1341 delta++;
1342
sewardj9ee82862004-12-14 01:16:59 +00001343 buf[0] = (UChar)0;
1344
sewardjd1061ab2004-07-08 01:45:30 +00001345 /* squeeze out the reg field from mod_reg_rm, since a 256-entry
1346 jump table seems a bit excessive.
1347 */
sewardj9b45b482005-02-07 01:42:18 +00001348 mod_reg_rm &= 0xC7; /* is now XX000YYY */
1349 mod_reg_rm = toUChar(mod_reg_rm | (mod_reg_rm >> 3));
1350 /* is now XX0XXYYY */
1351 mod_reg_rm &= 0x1F; /* is now 000XXYYY */
sewardjd1061ab2004-07-08 01:45:30 +00001352 switch (mod_reg_rm) {
1353
1354 /* (%eax) .. (%edi), not including (%esp) or (%ebp).
1355 --> GET %reg, t
1356 */
1357 case 0x00: case 0x01: case 0x02: case 0x03:
1358 /* ! 04 */ /* ! 05 */ case 0x06: case 0x07:
1359 { UChar rm = mod_reg_rm;
1360 DIS(buf, "%s(%s)", sorbTxt(sorb), nameIReg(4,rm));
1361 *len = 1;
sewardj5bd4d162004-11-10 13:02:48 +00001362 return disAMode_copy2tmp(
sewardj940e8c92004-07-11 16:53:24 +00001363 handleSegOverride(sorb, getIReg(4,rm)));
sewardjd1061ab2004-07-08 01:45:30 +00001364 }
1365
1366 /* d8(%eax) ... d8(%edi), not including d8(%esp)
1367 --> GET %reg, t ; ADDL d8, t
1368 */
1369 case 0x08: case 0x09: case 0x0A: case 0x0B:
1370 /* ! 0C */ case 0x0D: case 0x0E: case 0x0F:
sewardj9b45b482005-02-07 01:42:18 +00001371 { UChar rm = toUChar(mod_reg_rm & 7);
sewardjd1061ab2004-07-08 01:45:30 +00001372 UInt d = getSDisp8(delta);
sewardj2d49b432005-02-01 00:37:06 +00001373 DIS(buf, "%s%d(%s)", sorbTxt(sorb), (Int)d, nameIReg(4,rm));
sewardj5bd4d162004-11-10 13:02:48 +00001374 *len = 2;
1375 return disAMode_copy2tmp(
sewardj940e8c92004-07-11 16:53:24 +00001376 handleSegOverride(sorb,
1377 binop(Iop_Add32,getIReg(4,rm),mkU32(d))));
sewardjd1061ab2004-07-08 01:45:30 +00001378 }
1379
1380 /* d32(%eax) ... d32(%edi), not including d32(%esp)
1381 --> GET %reg, t ; ADDL d8, t
1382 */
1383 case 0x10: case 0x11: case 0x12: case 0x13:
1384 /* ! 14 */ case 0x15: case 0x16: case 0x17:
sewardj9b45b482005-02-07 01:42:18 +00001385 { UChar rm = toUChar(mod_reg_rm & 7);
sewardjd1061ab2004-07-08 01:45:30 +00001386 UInt d = getUDisp32(delta);
sewardj2d49b432005-02-01 00:37:06 +00001387 DIS(buf, "%s0x%x(%s)", sorbTxt(sorb), (Int)d, nameIReg(4,rm));
sewardj5bd4d162004-11-10 13:02:48 +00001388 *len = 5;
1389 return disAMode_copy2tmp(
sewardj940e8c92004-07-11 16:53:24 +00001390 handleSegOverride(sorb,
1391 binop(Iop_Add32,getIReg(4,rm),mkU32(d))));
sewardjd1061ab2004-07-08 01:45:30 +00001392 }
1393
1394 /* a register, %eax .. %edi. This shouldn't happen. */
1395 case 0x18: case 0x19: case 0x1A: case 0x1B:
1396 case 0x1C: case 0x1D: case 0x1E: case 0x1F:
1397 vpanic("disAMode(x86): not an addr!");
1398
1399 /* a 32-bit literal address
1400 --> MOV d32, tmp
1401 */
1402 case 0x05:
1403 { UInt d = getUDisp32(delta);
1404 *len = 5;
1405 DIS(buf, "%s(0x%x)", sorbTxt(sorb), d);
sewardj940e8c92004-07-11 16:53:24 +00001406 return disAMode_copy2tmp(
1407 handleSegOverride(sorb, mkU32(d)));
sewardjd1061ab2004-07-08 01:45:30 +00001408 }
1409
1410 case 0x04: {
1411 /* SIB, with no displacement. Special cases:
1412 -- %esp cannot act as an index value.
1413 If index_r indicates %esp, zero is used for the index.
1414 -- when mod is zero and base indicates EBP, base is instead
1415 a 32-bit literal.
1416 It's all madness, I tell you. Extract %index, %base and
1417 scale from the SIB byte. The value denoted is then:
1418 | %index == %ESP && %base == %EBP
1419 = d32 following SIB byte
1420 | %index == %ESP && %base != %EBP
1421 = %base
1422 | %index != %ESP && %base == %EBP
1423 = d32 following SIB byte + (%index << scale)
1424 | %index != %ESP && %base != %ESP
1425 = %base + (%index << scale)
1426
1427 What happens to the souls of CPU architects who dream up such
1428 horrendous schemes, do you suppose?
1429 */
1430 UChar sib = getIByte(delta);
sewardj9b45b482005-02-07 01:42:18 +00001431 UChar scale = toUChar((sib >> 6) & 3);
1432 UChar index_r = toUChar((sib >> 3) & 7);
1433 UChar base_r = toUChar(sib & 7);
sewardj5bd4d162004-11-10 13:02:48 +00001434 delta++;
sewardjd1061ab2004-07-08 01:45:30 +00001435
1436 if (index_r != R_ESP && base_r != R_EBP) {
1437 DIS(buf, "%s(%s,%s,%d)", sorbTxt(sorb),
1438 nameIReg(4,base_r), nameIReg(4,index_r), 1<<scale);
sewardj5bd4d162004-11-10 13:02:48 +00001439 *len = 2;
sewardj940e8c92004-07-11 16:53:24 +00001440 return
1441 disAMode_copy2tmp(
sewardj5bd4d162004-11-10 13:02:48 +00001442 handleSegOverride(sorb,
1443 binop(Iop_Add32,
sewardjd1061ab2004-07-08 01:45:30 +00001444 getIReg(4,base_r),
1445 binop(Iop_Shl32, getIReg(4,index_r),
sewardj6d2638e2004-07-15 09:38:27 +00001446 mkU8(scale)))));
sewardjd1061ab2004-07-08 01:45:30 +00001447 }
1448
1449 if (index_r != R_ESP && base_r == R_EBP) {
1450 UInt d = getUDisp32(delta);
1451 DIS(buf, "%s0x%x(,%s,%d)", sorbTxt(sorb), d,
1452 nameIReg(4,index_r), 1<<scale);
1453 *len = 6;
1454 return
sewardj940e8c92004-07-11 16:53:24 +00001455 disAMode_copy2tmp(
sewardjd1061ab2004-07-08 01:45:30 +00001456 handleSegOverride(sorb,
sewardj5bd4d162004-11-10 13:02:48 +00001457 binop(Iop_Add32,
1458 binop(Iop_Shl32, getIReg(4,index_r), mkU8(scale)),
sewardj940e8c92004-07-11 16:53:24 +00001459 mkU32(d))));
sewardjd1061ab2004-07-08 01:45:30 +00001460 }
1461
1462 if (index_r == R_ESP && base_r != R_EBP) {
1463 DIS(buf, "%s(%s,,)", sorbTxt(sorb), nameIReg(4,base_r));
sewardj5bd4d162004-11-10 13:02:48 +00001464 *len = 2;
1465 return disAMode_copy2tmp(
sewardj940e8c92004-07-11 16:53:24 +00001466 handleSegOverride(sorb, getIReg(4,base_r)));
sewardjd1061ab2004-07-08 01:45:30 +00001467 }
1468
1469 if (index_r == R_ESP && base_r == R_EBP) {
1470 UInt d = getUDisp32(delta);
1471 DIS(buf, "%s0x%x()", sorbTxt(sorb), d);
sewardj5bd4d162004-11-10 13:02:48 +00001472 *len = 6;
sewardja340ee82005-01-26 01:24:34 +00001473 vpanic("disAMode(x86):untested amode: 8");
sewardj5bd4d162004-11-10 13:02:48 +00001474 return disAMode_copy2tmp(
sewardj940e8c92004-07-11 16:53:24 +00001475 handleSegOverride(sorb, mkU32(d)));
sewardjd1061ab2004-07-08 01:45:30 +00001476 }
sewardjba89f4c2005-04-07 17:31:27 +00001477 /*NOTREACHED*/
sewardjd1061ab2004-07-08 01:45:30 +00001478 vassert(0);
1479 }
1480
1481 /* SIB, with 8-bit displacement. Special cases:
1482 -- %esp cannot act as an index value.
1483 If index_r indicates %esp, zero is used for the index.
1484 Denoted value is:
1485 | %index == %ESP
1486 = d8 + %base
1487 | %index != %ESP
1488 = d8 + %base + (%index << scale)
1489 */
1490 case 0x0C: {
1491 UChar sib = getIByte(delta);
sewardj9b45b482005-02-07 01:42:18 +00001492 UChar scale = toUChar((sib >> 6) & 3);
1493 UChar index_r = toUChar((sib >> 3) & 7);
1494 UChar base_r = toUChar(sib & 7);
sewardjd1061ab2004-07-08 01:45:30 +00001495 UInt d = getSDisp8(delta+1);
1496
1497 if (index_r == R_ESP) {
sewardj2d49b432005-02-01 00:37:06 +00001498 DIS(buf, "%s%d(%s,,)", sorbTxt(sorb),
1499 (Int)d, nameIReg(4,base_r));
sewardj5bd4d162004-11-10 13:02:48 +00001500 *len = 3;
1501 return disAMode_copy2tmp(
sewardj940e8c92004-07-11 16:53:24 +00001502 handleSegOverride(sorb,
1503 binop(Iop_Add32, getIReg(4,base_r), mkU32(d)) ));
sewardjd1061ab2004-07-08 01:45:30 +00001504 } else {
sewardj2d49b432005-02-01 00:37:06 +00001505 DIS(buf, "%s%d(%s,%s,%d)", sorbTxt(sorb), (Int)d,
sewardjd1061ab2004-07-08 01:45:30 +00001506 nameIReg(4,base_r), nameIReg(4,index_r), 1<<scale);
sewardj5bd4d162004-11-10 13:02:48 +00001507 *len = 3;
1508 return
sewardj940e8c92004-07-11 16:53:24 +00001509 disAMode_copy2tmp(
1510 handleSegOverride(sorb,
sewardj77b86be2004-07-11 13:28:24 +00001511 binop(Iop_Add32,
1512 binop(Iop_Add32,
1513 getIReg(4,base_r),
1514 binop(Iop_Shl32,
sewardj6d2638e2004-07-15 09:38:27 +00001515 getIReg(4,index_r), mkU8(scale))),
sewardj940e8c92004-07-11 16:53:24 +00001516 mkU32(d))));
sewardjd1061ab2004-07-08 01:45:30 +00001517 }
sewardjba89f4c2005-04-07 17:31:27 +00001518 /*NOTREACHED*/
sewardjd1061ab2004-07-08 01:45:30 +00001519 vassert(0);
1520 }
1521
1522 /* SIB, with 32-bit displacement. Special cases:
1523 -- %esp cannot act as an index value.
1524 If index_r indicates %esp, zero is used for the index.
1525 Denoted value is:
1526 | %index == %ESP
1527 = d32 + %base
1528 | %index != %ESP
1529 = d32 + %base + (%index << scale)
1530 */
1531 case 0x14: {
1532 UChar sib = getIByte(delta);
sewardj9b45b482005-02-07 01:42:18 +00001533 UChar scale = toUChar((sib >> 6) & 3);
1534 UChar index_r = toUChar((sib >> 3) & 7);
1535 UChar base_r = toUChar(sib & 7);
sewardjd1061ab2004-07-08 01:45:30 +00001536 UInt d = getUDisp32(delta+1);
1537
1538 if (index_r == R_ESP) {
sewardj2d49b432005-02-01 00:37:06 +00001539 DIS(buf, "%s%d(%s,,)", sorbTxt(sorb),
1540 (Int)d, nameIReg(4,base_r));
sewardj5bd4d162004-11-10 13:02:48 +00001541 *len = 6;
1542 return disAMode_copy2tmp(
sewardj940e8c92004-07-11 16:53:24 +00001543 handleSegOverride(sorb,
1544 binop(Iop_Add32, getIReg(4,base_r), mkU32(d)) ));
sewardjd1061ab2004-07-08 01:45:30 +00001545 } else {
sewardj2d49b432005-02-01 00:37:06 +00001546 DIS(buf, "%s%d(%s,%s,%d)", sorbTxt(sorb), (Int)d,
1547 nameIReg(4,base_r), nameIReg(4,index_r), 1<<scale);
sewardj5bd4d162004-11-10 13:02:48 +00001548 *len = 6;
1549 return
sewardj940e8c92004-07-11 16:53:24 +00001550 disAMode_copy2tmp(
1551 handleSegOverride(sorb,
sewardj9334b0f2004-07-10 22:43:54 +00001552 binop(Iop_Add32,
1553 binop(Iop_Add32,
1554 getIReg(4,base_r),
1555 binop(Iop_Shl32,
sewardj6d2638e2004-07-15 09:38:27 +00001556 getIReg(4,index_r), mkU8(scale))),
sewardj940e8c92004-07-11 16:53:24 +00001557 mkU32(d))));
sewardjd1061ab2004-07-08 01:45:30 +00001558 }
sewardjba89f4c2005-04-07 17:31:27 +00001559 /*NOTREACHED*/
sewardjd1061ab2004-07-08 01:45:30 +00001560 vassert(0);
1561 }
1562
1563 default:
1564 vpanic("disAMode(x86)");
1565 return 0; /*notreached*/
1566 }
1567}
1568
1569
1570/* Figure out the number of (insn-stream) bytes constituting the amode
1571 beginning at delta. Is useful for getting hold of literals beyond
1572 the end of the amode before it has been disassembled. */
1573
sewardj52d04912005-07-03 00:52:48 +00001574static UInt lengthAMode ( Int delta )
sewardjd1061ab2004-07-08 01:45:30 +00001575{
1576 UChar mod_reg_rm = getIByte(delta); delta++;
1577
1578 /* squeeze out the reg field from mod_reg_rm, since a 256-entry
1579 jump table seems a bit excessive.
1580 */
1581 mod_reg_rm &= 0xC7; /* is now XX000YYY */
sewardj9b45b482005-02-07 01:42:18 +00001582 mod_reg_rm = toUChar(mod_reg_rm | (mod_reg_rm >> 3));
1583 /* is now XX0XXYYY */
sewardjd1061ab2004-07-08 01:45:30 +00001584 mod_reg_rm &= 0x1F; /* is now 000XXYYY */
1585 switch (mod_reg_rm) {
1586
1587 /* (%eax) .. (%edi), not including (%esp) or (%ebp). */
1588 case 0x00: case 0x01: case 0x02: case 0x03:
1589 /* ! 04 */ /* ! 05 */ case 0x06: case 0x07:
1590 return 1;
1591
1592 /* d8(%eax) ... d8(%edi), not including d8(%esp). */
1593 case 0x08: case 0x09: case 0x0A: case 0x0B:
1594 /* ! 0C */ case 0x0D: case 0x0E: case 0x0F:
1595 return 2;
1596
1597 /* d32(%eax) ... d32(%edi), not including d32(%esp). */
1598 case 0x10: case 0x11: case 0x12: case 0x13:
1599 /* ! 14 */ case 0x15: case 0x16: case 0x17:
1600 return 5;
1601
1602 /* a register, %eax .. %edi. (Not an addr, but still handled.) */
1603 case 0x18: case 0x19: case 0x1A: case 0x1B:
1604 case 0x1C: case 0x1D: case 0x1E: case 0x1F:
1605 return 1;
1606
1607 /* a 32-bit literal address. */
1608 case 0x05: return 5;
1609
1610 /* SIB, no displacement. */
1611 case 0x04: {
1612 UChar sib = getIByte(delta);
sewardj9b45b482005-02-07 01:42:18 +00001613 UChar base_r = toUChar(sib & 7);
sewardjd1061ab2004-07-08 01:45:30 +00001614 if (base_r == R_EBP) return 6; else return 2;
1615 }
1616 /* SIB, with 8-bit displacement. */
1617 case 0x0C: return 3;
1618
1619 /* SIB, with 32-bit displacement. */
1620 case 0x14: return 6;
1621
1622 default:
1623 vpanic("lengthAMode");
1624 return 0; /*notreached*/
1625 }
1626}
1627
1628/*------------------------------------------------------------*/
1629/*--- Disassembling common idioms ---*/
1630/*------------------------------------------------------------*/
1631
sewardje87b4842004-07-10 12:23:30 +00001632/* Handle binary integer instructions of the form
1633 op E, G meaning
1634 op reg-or-mem, reg
1635 Is passed the a ptr to the modRM byte, the actual operation, and the
1636 data size. Returns the address advanced completely over this
1637 instruction.
1638
1639 E(src) is reg-or-mem
1640 G(dst) is reg.
1641
1642 If E is reg, --> GET %G, tmp
1643 OP %E, tmp
1644 PUT tmp, %G
1645
1646 If E is mem and OP is not reversible,
1647 --> (getAddr E) -> tmpa
1648 LD (tmpa), tmpa
1649 GET %G, tmp2
1650 OP tmpa, tmp2
1651 PUT tmp2, %G
1652
1653 If E is mem and OP is reversible
1654 --> (getAddr E) -> tmpa
1655 LD (tmpa), tmpa
1656 OP %G, tmpa
1657 PUT tmpa, %G
1658*/
1659static
1660UInt dis_op2_E_G ( UChar sorb,
sewardj180e8b32004-07-29 01:40:11 +00001661 Bool addSubCarry,
sewardje87b4842004-07-10 12:23:30 +00001662 IROp op8,
1663 Bool keep,
1664 Int size,
sewardj52d04912005-07-03 00:52:48 +00001665 Int delta0,
sewardj2d49b432005-02-01 00:37:06 +00001666 HChar* t_x86opc )
sewardje87b4842004-07-10 12:23:30 +00001667{
sewardjc9a43662004-11-30 18:51:59 +00001668 HChar dis_buf[50];
sewardj9334b0f2004-07-10 22:43:54 +00001669 Int len;
sewardje87b4842004-07-10 12:23:30 +00001670 IRType ty = szToITy(size);
1671 IRTemp dst1 = newTemp(ty);
1672 IRTemp src = newTemp(ty);
1673 IRTemp dst0 = newTemp(ty);
1674 UChar rm = getUChar(delta0);
sewardj92d168d2004-11-15 14:22:12 +00001675 IRTemp addr = IRTemp_INVALID;
sewardje87b4842004-07-10 12:23:30 +00001676
sewardj180e8b32004-07-29 01:40:11 +00001677 /* addSubCarry == True indicates the intended operation is
1678 add-with-carry or subtract-with-borrow. */
1679 if (addSubCarry) {
1680 vassert(op8 == Iop_Add8 || op8 == Iop_Sub8);
1681 vassert(keep);
1682 }
1683
sewardje87b4842004-07-10 12:23:30 +00001684 if (epartIsReg(rm)) {
sewardje87b4842004-07-10 12:23:30 +00001685 /* Specially handle XOR reg,reg, because that doesn't really
1686 depend on reg, and doing the obvious thing potentially
1687 generates a spurious value check failure due to the bogus
sewardj55efbdf2005-05-02 17:07:02 +00001688 dependency. Ditto SBB reg,reg. */
1689 if ((op8 == Iop_Xor8 || (op8 == Iop_Sub8 && addSubCarry))
1690 && gregOfRM(rm) == eregOfRM(rm)) {
1691 putIReg(size, gregOfRM(rm), mkU(ty,0));
sewardje87b4842004-07-10 12:23:30 +00001692 }
sewardje87b4842004-07-10 12:23:30 +00001693 assign( dst0, getIReg(size,gregOfRM(rm)) );
1694 assign( src, getIReg(size,eregOfRM(rm)) );
sewardje87b4842004-07-10 12:23:30 +00001695
sewardj180e8b32004-07-29 01:40:11 +00001696 if (addSubCarry && op8 == Iop_Add8) {
sewardj180e8b32004-07-29 01:40:11 +00001697 helper_ADC( size, dst1, dst0, src );
sewardje87b4842004-07-10 12:23:30 +00001698 putIReg(size, gregOfRM(rm), mkexpr(dst1));
sewardj180e8b32004-07-29 01:40:11 +00001699 } else
1700 if (addSubCarry && op8 == Iop_Sub8) {
sewardj180e8b32004-07-29 01:40:11 +00001701 helper_SBB( size, dst1, dst0, src );
1702 putIReg(size, gregOfRM(rm), mkexpr(dst1));
1703 } else {
1704 assign( dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
sewardj5bd4d162004-11-10 13:02:48 +00001705 if (isAddSub(op8))
sewardj2a2ba8b2004-11-08 13:14:06 +00001706 setFlags_DEP1_DEP2(op8, dst0, src, ty);
sewardjb9c5cf62004-08-24 15:10:38 +00001707 else
sewardj2a2ba8b2004-11-08 13:14:06 +00001708 setFlags_DEP1(op8, dst1, ty);
sewardj180e8b32004-07-29 01:40:11 +00001709 if (keep)
1710 putIReg(size, gregOfRM(rm), mkexpr(dst1));
1711 }
sewardje87b4842004-07-10 12:23:30 +00001712
1713 DIP("%s%c %s,%s\n", t_x86opc, nameISize(size),
1714 nameIReg(size,eregOfRM(rm)),
1715 nameIReg(size,gregOfRM(rm)));
1716 return 1+delta0;
sewardje87b4842004-07-10 12:23:30 +00001717 } else {
sewardj9334b0f2004-07-10 22:43:54 +00001718 /* E refers to memory */
1719 addr = disAMode ( &len, sorb, delta0, dis_buf);
1720 assign( dst0, getIReg(size,gregOfRM(rm)) );
sewardj940e8c92004-07-11 16:53:24 +00001721 assign( src, loadLE(szToITy(size), mkexpr(addr)) );
sewardj9334b0f2004-07-10 22:43:54 +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 );
sewardj9334b0f2004-07-10 22:43:54 +00001725 putIReg(size, gregOfRM(rm), mkexpr(dst1));
sewardj180e8b32004-07-29 01:40:11 +00001726 } else
1727 if (addSubCarry && op8 == Iop_Sub8) {
1728 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 }
sewardj9334b0f2004-07-10 22:43:54 +00001739
sewardje87b4842004-07-10 12:23:30 +00001740 DIP("%s%c %s,%s\n", t_x86opc, nameISize(size),
1741 dis_buf,nameIReg(size,gregOfRM(rm)));
sewardj9334b0f2004-07-10 22:43:54 +00001742 return len+delta0;
sewardje87b4842004-07-10 12:23:30 +00001743 }
sewardje87b4842004-07-10 12:23:30 +00001744}
sewardje05c42c2004-07-08 20:25:10 +00001745
1746
1747
1748/* Handle binary integer instructions of the form
1749 op G, E meaning
1750 op reg, reg-or-mem
1751 Is passed the a ptr to the modRM byte, the actual operation, and the
1752 data size. Returns the address advanced completely over this
1753 instruction.
1754
1755 G(src) is reg.
1756 E(dst) is reg-or-mem
1757
1758 If E is reg, --> GET %E, tmp
1759 OP %G, tmp
1760 PUT tmp, %E
1761
1762 If E is mem, --> (getAddr E) -> tmpa
1763 LD (tmpa), tmpv
1764 OP %G, tmpv
1765 ST tmpv, (tmpa)
1766*/
1767static
1768UInt dis_op2_G_E ( UChar sorb,
sewardjcaca9d02004-07-28 07:11:32 +00001769 Bool addSubCarry,
sewardje05c42c2004-07-08 20:25:10 +00001770 IROp op8,
1771 Bool keep,
1772 Int size,
sewardj52d04912005-07-03 00:52:48 +00001773 Int delta0,
sewardj2d49b432005-02-01 00:37:06 +00001774 HChar* t_x86opc )
sewardje05c42c2004-07-08 20:25:10 +00001775{
sewardjc9a43662004-11-30 18:51:59 +00001776 HChar dis_buf[50];
sewardje87b4842004-07-10 12:23:30 +00001777 Int len;
sewardje05c42c2004-07-08 20:25:10 +00001778 IRType ty = szToITy(size);
1779 IRTemp dst1 = newTemp(ty);
1780 IRTemp src = newTemp(ty);
1781 IRTemp dst0 = newTemp(ty);
1782 UChar rm = getIByte(delta0);
sewardj92d168d2004-11-15 14:22:12 +00001783 IRTemp addr = IRTemp_INVALID;
sewardje05c42c2004-07-08 20:25:10 +00001784
sewardjcaca9d02004-07-28 07:11:32 +00001785 /* addSubCarry == True indicates the intended operation is
1786 add-with-carry or subtract-with-borrow. */
1787 if (addSubCarry) {
1788 vassert(op8 == Iop_Add8 || op8 == Iop_Sub8);
1789 vassert(keep);
1790 }
1791
sewardje05c42c2004-07-08 20:25:10 +00001792 if (epartIsReg(rm)) {
sewardje05c42c2004-07-08 20:25:10 +00001793 /* Specially handle XOR reg,reg, because that doesn't really
1794 depend on reg, and doing the obvious thing potentially
1795 generates a spurious value check failure due to the bogus
sewardj55efbdf2005-05-02 17:07:02 +00001796 dependency. Ditto SBB reg,reg.*/
1797 if ((op8 == Iop_Xor8 || (op8 == Iop_Sub8 && addSubCarry))
1798 && gregOfRM(rm) == eregOfRM(rm)) {
1799 putIReg(size, eregOfRM(rm), mkU(ty,0));
sewardje05c42c2004-07-08 20:25:10 +00001800 }
sewardje05c42c2004-07-08 20:25:10 +00001801 assign(dst0, getIReg(size,eregOfRM(rm)));
1802 assign(src, getIReg(size,gregOfRM(rm)));
sewardje05c42c2004-07-08 20:25:10 +00001803
sewardjcaca9d02004-07-28 07:11:32 +00001804 if (addSubCarry && op8 == Iop_Add8) {
sewardj1813dbe2004-07-28 17:09:04 +00001805 helper_ADC( size, dst1, dst0, src );
1806 putIReg(size, eregOfRM(rm), mkexpr(dst1));
sewardjcaca9d02004-07-28 07:11:32 +00001807 } else
1808 if (addSubCarry && op8 == Iop_Sub8) {
1809 helper_SBB( size, dst1, dst0, src );
sewardje05c42c2004-07-08 20:25:10 +00001810 putIReg(size, eregOfRM(rm), mkexpr(dst1));
sewardjcaca9d02004-07-28 07:11:32 +00001811 } else {
1812 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
sewardj5bd4d162004-11-10 13:02:48 +00001813 if (isAddSub(op8))
sewardj2a2ba8b2004-11-08 13:14:06 +00001814 setFlags_DEP1_DEP2(op8, dst0, src, ty);
sewardjb9c5cf62004-08-24 15:10:38 +00001815 else
sewardj2a2ba8b2004-11-08 13:14:06 +00001816 setFlags_DEP1(op8, dst1, ty);
sewardjcaca9d02004-07-28 07:11:32 +00001817 if (keep)
1818 putIReg(size, eregOfRM(rm), mkexpr(dst1));
1819 }
sewardje05c42c2004-07-08 20:25:10 +00001820
1821 DIP("%s%c %s,%s\n", t_x86opc, nameISize(size),
1822 nameIReg(size,gregOfRM(rm)),
1823 nameIReg(size,eregOfRM(rm)));
1824 return 1+delta0;
1825 }
1826
1827 /* E refers to memory */
1828 {
sewardje87b4842004-07-10 12:23:30 +00001829 addr = disAMode ( &len, sorb, delta0, dis_buf);
sewardj940e8c92004-07-11 16:53:24 +00001830 assign(dst0, loadLE(ty,mkexpr(addr)));
sewardje87b4842004-07-10 12:23:30 +00001831 assign(src, getIReg(size,gregOfRM(rm)));
sewardje05c42c2004-07-08 20:25:10 +00001832
sewardjcaca9d02004-07-28 07:11:32 +00001833 if (addSubCarry && op8 == Iop_Add8) {
1834 helper_ADC( size, dst1, dst0, src );
1835 storeLE(mkexpr(addr), mkexpr(dst1));
1836 } else
1837 if (addSubCarry && op8 == Iop_Sub8) {
1838 helper_SBB( size, dst1, dst0, src );
1839 storeLE(mkexpr(addr), mkexpr(dst1));
1840 } else {
1841 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
sewardj5bd4d162004-11-10 13:02:48 +00001842 if (isAddSub(op8))
sewardj2a2ba8b2004-11-08 13:14:06 +00001843 setFlags_DEP1_DEP2(op8, dst0, src, ty);
sewardjb9c5cf62004-08-24 15:10:38 +00001844 else
sewardj2a2ba8b2004-11-08 13:14:06 +00001845 setFlags_DEP1(op8, dst1, ty);
sewardjcaca9d02004-07-28 07:11:32 +00001846 if (keep)
1847 storeLE(mkexpr(addr), mkexpr(dst1));
1848 }
sewardje87b4842004-07-10 12:23:30 +00001849
sewardje05c42c2004-07-08 20:25:10 +00001850 DIP("%s%c %s,%s\n", t_x86opc, nameISize(size),
1851 nameIReg(size,gregOfRM(rm)), dis_buf);
sewardje87b4842004-07-10 12:23:30 +00001852 return len+delta0;
sewardje05c42c2004-07-08 20:25:10 +00001853 }
1854}
1855
1856
1857/* Handle move instructions of the form
1858 mov E, G meaning
1859 mov reg-or-mem, reg
1860 Is passed the a ptr to the modRM byte, and the data size. Returns
1861 the address advanced completely over this instruction.
1862
1863 E(src) is reg-or-mem
1864 G(dst) is reg.
1865
1866 If E is reg, --> GET %E, tmpv
1867 PUT tmpv, %G
1868
1869 If E is mem --> (getAddr E) -> tmpa
1870 LD (tmpa), tmpb
1871 PUT tmpb, %G
1872*/
1873static
1874UInt dis_mov_E_G ( UChar sorb,
1875 Int size,
sewardj52d04912005-07-03 00:52:48 +00001876 Int delta0 )
sewardje05c42c2004-07-08 20:25:10 +00001877{
1878 Int len;
1879 UChar rm = getIByte(delta0);
sewardjc9a43662004-11-30 18:51:59 +00001880 HChar dis_buf[50];
sewardje05c42c2004-07-08 20:25:10 +00001881
1882 if (epartIsReg(rm)) {
sewardj7ca37d92004-10-25 02:58:30 +00001883 putIReg(size, gregOfRM(rm), getIReg(size, eregOfRM(rm)));
sewardje05c42c2004-07-08 20:25:10 +00001884 DIP("mov%c %s,%s\n", nameISize(size),
1885 nameIReg(size,eregOfRM(rm)),
1886 nameIReg(size,gregOfRM(rm)));
sewardj7ca37d92004-10-25 02:58:30 +00001887 return 1+delta0;
sewardje05c42c2004-07-08 20:25:10 +00001888 }
1889
1890 /* E refers to memory */
1891 {
sewardj940e8c92004-07-11 16:53:24 +00001892 IRTemp addr = disAMode ( &len, sorb, delta0, dis_buf );
1893 putIReg(size, gregOfRM(rm), loadLE(szToITy(size), mkexpr(addr)));
sewardje05c42c2004-07-08 20:25:10 +00001894 DIP("mov%c %s,%s\n", nameISize(size),
1895 dis_buf,nameIReg(size,gregOfRM(rm)));
1896 return delta0+len;
1897 }
1898}
1899
1900
1901/* Handle move instructions of the form
1902 mov G, E meaning
1903 mov reg, reg-or-mem
1904 Is passed the a ptr to the modRM byte, and the data size. Returns
1905 the address advanced completely over this instruction.
1906
1907 G(src) is reg.
1908 E(dst) is reg-or-mem
1909
1910 If E is reg, --> GET %G, tmp
1911 PUT tmp, %E
1912
1913 If E is mem, --> (getAddr E) -> tmpa
1914 GET %G, tmpv
1915 ST tmpv, (tmpa)
1916*/
sewardjc9a65702004-07-07 16:32:57 +00001917static
1918UInt dis_mov_G_E ( UChar sorb,
1919 Int size,
sewardj52d04912005-07-03 00:52:48 +00001920 Int delta0 )
sewardjc9a65702004-07-07 16:32:57 +00001921{
sewardje05c42c2004-07-08 20:25:10 +00001922 Int len;
sewardjc9a65702004-07-07 16:32:57 +00001923 UChar rm = getIByte(delta0);
sewardjc9a43662004-11-30 18:51:59 +00001924 HChar dis_buf[50];
sewardjc9a65702004-07-07 16:32:57 +00001925
1926 if (epartIsReg(rm)) {
sewardj41f43bc2004-07-08 14:23:22 +00001927 putIReg(size, eregOfRM(rm), getIReg(size, gregOfRM(rm)));
sewardjc9a65702004-07-07 16:32:57 +00001928 DIP("mov%c %s,%s\n", nameISize(size),
1929 nameIReg(size,gregOfRM(rm)),
1930 nameIReg(size,eregOfRM(rm)));
1931 return 1+delta0;
1932 }
1933
sewardjc9a65702004-07-07 16:32:57 +00001934 /* E refers to memory */
1935 {
sewardj940e8c92004-07-11 16:53:24 +00001936 IRTemp addr = disAMode ( &len, sorb, delta0, dis_buf);
1937 storeLE( mkexpr(addr), getIReg(size, gregOfRM(rm)) );
sewardjc9a65702004-07-07 16:32:57 +00001938 DIP("mov%c %s,%s\n", nameISize(size),
1939 nameIReg(size,gregOfRM(rm)), dis_buf);
sewardje05c42c2004-07-08 20:25:10 +00001940 return len+delta0;
sewardjc9a65702004-07-07 16:32:57 +00001941 }
sewardjc9a65702004-07-07 16:32:57 +00001942}
1943
1944
sewardj0611d802004-07-11 02:37:54 +00001945/* op $immediate, AL/AX/EAX. */
1946static
1947UInt dis_op_imm_A ( Int size,
sewardja718d5d2005-04-03 14:59:54 +00001948 Bool carrying,
sewardj0611d802004-07-11 02:37:54 +00001949 IROp op8,
1950 Bool keep,
sewardj52d04912005-07-03 00:52:48 +00001951 Int delta,
sewardj2d49b432005-02-01 00:37:06 +00001952 HChar* t_x86opc )
sewardj0611d802004-07-11 02:37:54 +00001953{
1954 IRType ty = szToITy(size);
1955 IRTemp dst0 = newTemp(ty);
1956 IRTemp src = newTemp(ty);
1957 IRTemp dst1 = newTemp(ty);
1958 UInt lit = getUDisp(size,delta);
1959 assign(dst0, getIReg(size,R_EAX));
1960 assign(src, mkU(ty,lit));
sewardja718d5d2005-04-03 14:59:54 +00001961
1962 if (isAddSub(op8) && !carrying) {
1963 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
sewardj2a2ba8b2004-11-08 13:14:06 +00001964 setFlags_DEP1_DEP2(op8, dst0, src, ty);
sewardja718d5d2005-04-03 14:59:54 +00001965 }
sewardjb9c5cf62004-08-24 15:10:38 +00001966 else
sewardja718d5d2005-04-03 14:59:54 +00001967 if (isLogic(op8)) {
1968 vassert(!carrying);
1969 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
sewardj2a2ba8b2004-11-08 13:14:06 +00001970 setFlags_DEP1(op8, dst1, ty);
sewardja718d5d2005-04-03 14:59:54 +00001971 }
1972 else
1973 if (op8 == Iop_Add8 && carrying) {
1974 helper_ADC( size, dst1, dst0, src );
1975 }
sewardj2a2ba8b2004-11-08 13:14:06 +00001976 else
1977 vpanic("dis_op_imm_A(x86,guest)");
sewardj0611d802004-07-11 02:37:54 +00001978
1979 if (keep)
1980 putIReg(size, R_EAX, mkexpr(dst1));
1981
1982 DIP("%s%c $0x%x, %s\n", t_x86opc, nameISize(size),
1983 lit, nameIReg(size,R_EAX));
1984 return delta+size;
1985}
sewardj9334b0f2004-07-10 22:43:54 +00001986
1987
1988/* Sign- and Zero-extending moves. */
1989static
sewardj52d04912005-07-03 00:52:48 +00001990UInt dis_movx_E_G ( UChar sorb,
1991 Int delta, Int szs, Int szd, Bool sign_extend )
sewardj9334b0f2004-07-10 22:43:54 +00001992{
sewardj9334b0f2004-07-10 22:43:54 +00001993 UChar rm = getIByte(delta);
1994 if (epartIsReg(rm)) {
1995 putIReg(szd, gregOfRM(rm),
sewardj5bd4d162004-11-10 13:02:48 +00001996 unop(mkWidenOp(szs,szd,sign_extend),
1997 getIReg(szs,eregOfRM(rm))));
sewardj9334b0f2004-07-10 22:43:54 +00001998 DIP("mov%c%c%c %s,%s\n", sign_extend ? 's' : 'z',
1999 nameISize(szs), nameISize(szd),
2000 nameIReg(szs,eregOfRM(rm)),
2001 nameIReg(szd,gregOfRM(rm)));
2002 return 1+delta;
2003 }
2004
2005 /* E refers to memory */
2006 {
sewardj940e8c92004-07-11 16:53:24 +00002007 Int len;
sewardjc9a43662004-11-30 18:51:59 +00002008 HChar dis_buf[50];
sewardj940e8c92004-07-11 16:53:24 +00002009 IRTemp addr = disAMode ( &len, sorb, delta, dis_buf );
sewardj0611d802004-07-11 02:37:54 +00002010
2011 putIReg(szd, gregOfRM(rm),
sewardj5bd4d162004-11-10 13:02:48 +00002012 unop(mkWidenOp(szs,szd,sign_extend),
sewardj940e8c92004-07-11 16:53:24 +00002013 loadLE(szToITy(szs),mkexpr(addr))));
sewardj9334b0f2004-07-10 22:43:54 +00002014 DIP("mov%c%c%c %s,%s\n", sign_extend ? 's' : 'z',
2015 nameISize(szs), nameISize(szd),
2016 dis_buf, nameIReg(szd,gregOfRM(rm)));
sewardj0611d802004-07-11 02:37:54 +00002017 return len+delta;
sewardj9334b0f2004-07-10 22:43:54 +00002018 }
2019}
2020
sewardj9690d922004-07-14 01:39:17 +00002021
2022/* Generate code to divide ArchRegs EDX:EAX / DX:AX / AX by the 32 /
2023 16 / 8 bit quantity in the given IRTemp. */
2024static
2025void codegen_div ( Int sz, IRTemp t, Bool signed_divide )
2026{
sewardje5427e82004-09-11 19:43:51 +00002027 IROp op = signed_divide ? Iop_DivModS64to32 : Iop_DivModU64to32;
2028 IRTemp src64 = newTemp(Ity_I64);
2029 IRTemp dst64 = newTemp(Ity_I64);
sewardj9690d922004-07-14 01:39:17 +00002030 switch (sz) {
sewardje5427e82004-09-11 19:43:51 +00002031 case 4:
sewardj9690d922004-07-14 01:39:17 +00002032 assign( src64, binop(Iop_32HLto64,
sewardje5427e82004-09-11 19:43:51 +00002033 getIReg(4,R_EDX), getIReg(4,R_EAX)) );
sewardj9690d922004-07-14 01:39:17 +00002034 assign( dst64, binop(op, mkexpr(src64), mkexpr(t)) );
sewardj8c7f1ab2004-07-29 20:31:09 +00002035 putIReg( 4, R_EAX, unop(Iop_64to32,mkexpr(dst64)) );
sewardj9690d922004-07-14 01:39:17 +00002036 putIReg( 4, R_EDX, unop(Iop_64HIto32,mkexpr(dst64)) );
2037 break;
sewardje5427e82004-09-11 19:43:51 +00002038 case 2: {
2039 IROp widen3264 = signed_divide ? Iop_32Sto64 : Iop_32Uto64;
2040 IROp widen1632 = signed_divide ? Iop_16Sto32 : Iop_16Uto32;
2041 assign( src64, unop(widen3264,
2042 binop(Iop_16HLto32,
2043 getIReg(2,R_EDX), getIReg(2,R_EAX))) );
2044 assign( dst64, binop(op, mkexpr(src64), unop(widen1632,mkexpr(t))) );
2045 putIReg( 2, R_EAX, unop(Iop_32to16,unop(Iop_64to32,mkexpr(dst64))) );
2046 putIReg( 2, R_EDX, unop(Iop_32to16,unop(Iop_64HIto32,mkexpr(dst64))) );
2047 break;
sewardj9690d922004-07-14 01:39:17 +00002048 }
sewardj4e82db72004-10-16 11:32:15 +00002049 case 1: {
2050 IROp widen3264 = signed_divide ? Iop_32Sto64 : Iop_32Uto64;
2051 IROp widen1632 = signed_divide ? Iop_16Sto32 : Iop_16Uto32;
2052 IROp widen816 = signed_divide ? Iop_8Sto16 : Iop_8Uto16;
2053 assign( src64, unop(widen3264, unop(widen1632, getIReg(2,R_EAX))) );
2054 assign( dst64,
2055 binop(op, mkexpr(src64),
2056 unop(widen1632, unop(widen816, mkexpr(t)))) );
2057 putIReg( 1, R_AL, unop(Iop_16to8, unop(Iop_32to16,
2058 unop(Iop_64to32,mkexpr(dst64)))) );
2059 putIReg( 1, R_AH, unop(Iop_16to8, unop(Iop_32to16,
2060 unop(Iop_64HIto32,mkexpr(dst64)))) );
2061 break;
2062 }
sewardj9690d922004-07-14 01:39:17 +00002063 default: vpanic("codegen_div(x86)");
2064 }
2065}
sewardj41f43bc2004-07-08 14:23:22 +00002066
2067
2068static
sewardje90ad6a2004-07-10 19:02:10 +00002069UInt dis_Grp1 ( UChar sorb,
sewardj52d04912005-07-03 00:52:48 +00002070 Int delta, UChar modrm,
sewardj41f43bc2004-07-08 14:23:22 +00002071 Int am_sz, Int d_sz, Int sz, UInt d32 )
2072{
sewardj41f43bc2004-07-08 14:23:22 +00002073 Int len;
sewardjc9a43662004-11-30 18:51:59 +00002074 HChar dis_buf[50];
sewardje05c42c2004-07-08 20:25:10 +00002075 IRType ty = szToITy(sz);
2076 IRTemp dst1 = newTemp(ty);
2077 IRTemp src = newTemp(ty);
2078 IRTemp dst0 = newTemp(ty);
sewardj92d168d2004-11-15 14:22:12 +00002079 IRTemp addr = IRTemp_INVALID;
sewardj66de2272004-07-16 21:19:05 +00002080 IROp op8 = Iop_INVALID;
sewardj180e8b32004-07-29 01:40:11 +00002081 UInt mask = sz==1 ? 0xFF : (sz==2 ? 0xFFFF : 0xFFFFFFFF);
sewardj41f43bc2004-07-08 14:23:22 +00002082
2083 switch (gregOfRM(modrm)) {
sewardje05c42c2004-07-08 20:25:10 +00002084 case 0: op8 = Iop_Add8; break; case 1: op8 = Iop_Or8; break;
sewardj66de2272004-07-16 21:19:05 +00002085 case 2: break; // ADC
2086 case 3: break; // SBB
sewardje05c42c2004-07-08 20:25:10 +00002087 case 4: op8 = Iop_And8; break; case 5: op8 = Iop_Sub8; break;
2088 case 6: op8 = Iop_Xor8; break; case 7: op8 = Iop_Sub8; break;
sewardj41f43bc2004-07-08 14:23:22 +00002089 default: vpanic("dis_Grp1: unhandled case");
2090 }
sewardj41f43bc2004-07-08 14:23:22 +00002091
2092 if (epartIsReg(modrm)) {
2093 vassert(am_sz == 1);
2094
2095 assign(dst0, getIReg(sz,eregOfRM(modrm)));
sewardj180e8b32004-07-29 01:40:11 +00002096 assign(src, mkU(ty,d32 & mask));
sewardj41f43bc2004-07-08 14:23:22 +00002097
sewardj180e8b32004-07-29 01:40:11 +00002098 if (gregOfRM(modrm) == 2 /* ADC */) {
2099 helper_ADC( sz, dst1, dst0, src );
2100 } else
2101 if (gregOfRM(modrm) == 3 /* SBB */) {
2102 helper_SBB( sz, dst1, dst0, src );
2103 } else {
2104 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
sewardj5bd4d162004-11-10 13:02:48 +00002105 if (isAddSub(op8))
sewardj2a2ba8b2004-11-08 13:14:06 +00002106 setFlags_DEP1_DEP2(op8, dst0, src, ty);
sewardjb9c5cf62004-08-24 15:10:38 +00002107 else
sewardj2a2ba8b2004-11-08 13:14:06 +00002108 setFlags_DEP1(op8, dst1, ty);
sewardj180e8b32004-07-29 01:40:11 +00002109 }
sewardj41f43bc2004-07-08 14:23:22 +00002110
2111 if (gregOfRM(modrm) < 7)
sewardje05c42c2004-07-08 20:25:10 +00002112 putIReg(sz, eregOfRM(modrm), mkexpr(dst1));
sewardj41f43bc2004-07-08 14:23:22 +00002113
2114 delta += (am_sz + d_sz);
2115 DIP("%s%c $0x%x, %s\n", nameGrp1(gregOfRM(modrm)), nameISize(sz), d32,
2116 nameIReg(sz,eregOfRM(modrm)));
2117 } else {
sewardje87b4842004-07-10 12:23:30 +00002118 addr = disAMode ( &len, sorb, delta, dis_buf);
sewardj41f43bc2004-07-08 14:23:22 +00002119
sewardj940e8c92004-07-11 16:53:24 +00002120 assign(dst0, loadLE(ty,mkexpr(addr)));
sewardj180e8b32004-07-29 01:40:11 +00002121 assign(src, mkU(ty,d32 & mask));
sewardj41f43bc2004-07-08 14:23:22 +00002122
sewardj66de2272004-07-16 21:19:05 +00002123 if (gregOfRM(modrm) == 2 /* ADC */) {
sewardj3af115f2004-07-14 02:46:52 +00002124 helper_ADC( sz, dst1, dst0, src );
2125 } else
sewardj66de2272004-07-16 21:19:05 +00002126 if (gregOfRM(modrm) == 3 /* SBB */) {
sewardje166ed02004-10-25 02:27:01 +00002127 helper_SBB( sz, dst1, dst0, src );
sewardj3af115f2004-07-14 02:46:52 +00002128 } else {
2129 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
sewardj5bd4d162004-11-10 13:02:48 +00002130 if (isAddSub(op8))
sewardj2a2ba8b2004-11-08 13:14:06 +00002131 setFlags_DEP1_DEP2(op8, dst0, src, ty);
sewardjb9c5cf62004-08-24 15:10:38 +00002132 else
sewardj2a2ba8b2004-11-08 13:14:06 +00002133 setFlags_DEP1(op8, dst1, ty);
sewardj3af115f2004-07-14 02:46:52 +00002134 }
sewardj41f43bc2004-07-08 14:23:22 +00002135
2136 if (gregOfRM(modrm) < 7)
sewardj940e8c92004-07-11 16:53:24 +00002137 storeLE(mkexpr(addr), mkexpr(dst1));
sewardj41f43bc2004-07-08 14:23:22 +00002138
2139 delta += (len+d_sz);
2140 DIP("%s%c $0x%x, %s\n", nameGrp1(gregOfRM(modrm)), nameISize(sz),
2141 d32, dis_buf);
2142 }
2143 return delta;
2144}
2145
2146
sewardj6d2638e2004-07-15 09:38:27 +00002147/* Group 2 extended opcodes. shift_expr must be an 8-bit typed
2148 expression. */
2149
sewardje90ad6a2004-07-10 19:02:10 +00002150static
sewardj52d04912005-07-03 00:52:48 +00002151UInt dis_Grp2 ( UChar sorb,
2152 Int delta, UChar modrm,
sewardj6d2638e2004-07-15 09:38:27 +00002153 Int am_sz, Int d_sz, Int sz, IRExpr* shift_expr,
sewardj2d49b432005-02-01 00:37:06 +00002154 HChar* shift_expr_txt )
sewardje90ad6a2004-07-10 19:02:10 +00002155{
2156 /* delta on entry points at the modrm byte. */
sewardjc9a43662004-11-30 18:51:59 +00002157 HChar dis_buf[50];
sewardj6d2638e2004-07-15 09:38:27 +00002158 Int len;
sewardj2eef7732005-08-23 15:41:14 +00002159 Bool isShift, isRotate, isRotateC;
sewardj6d2638e2004-07-15 09:38:27 +00002160 IRType ty = szToITy(sz);
2161 IRTemp dst0 = newTemp(ty);
2162 IRTemp dst1 = newTemp(ty);
sewardj92d168d2004-11-15 14:22:12 +00002163 IRTemp addr = IRTemp_INVALID;
sewardje90ad6a2004-07-10 19:02:10 +00002164
2165 vassert(sz == 1 || sz == 2 || sz == 4);
2166
sewardje90ad6a2004-07-10 19:02:10 +00002167 /* Put value to shift/rotate in dst0. */
2168 if (epartIsReg(modrm)) {
2169 assign(dst0, getIReg(sz, eregOfRM(modrm)));
sewardj940e8c92004-07-11 16:53:24 +00002170 delta += (am_sz + d_sz);
sewardje90ad6a2004-07-10 19:02:10 +00002171 } else {
sewardj940e8c92004-07-11 16:53:24 +00002172 addr = disAMode ( &len, sorb, delta, dis_buf);
2173 assign(dst0, loadLE(ty,mkexpr(addr)));
2174 delta += len + d_sz;
sewardje90ad6a2004-07-10 19:02:10 +00002175 }
2176
2177 isShift = False;
2178 switch (gregOfRM(modrm)) { case 4: case 5: case 7: isShift = True; }
2179
sewardj750f4072004-07-26 22:39:11 +00002180 isRotate = False;
2181 switch (gregOfRM(modrm)) { case 0: case 1: isRotate = True; }
2182
sewardj2eef7732005-08-23 15:41:14 +00002183 isRotateC = False;
2184 switch (gregOfRM(modrm)) { case 2: case 3: isRotateC = True; }
sewardj9aebb0c2004-10-24 19:20:43 +00002185
sewardj2eef7732005-08-23 15:41:14 +00002186 if (!isShift && !isRotate && !isRotateC) {
sewardj8c7f1ab2004-07-29 20:31:09 +00002187 vex_printf("\ncase %d\n", gregOfRM(modrm));
2188 vpanic("dis_Grp2(Reg): unhandled case(x86)");
2189 }
2190
sewardj2eef7732005-08-23 15:41:14 +00002191 if (isRotateC) {
2192 /* call a helper; these insns are so ridiculous they do not
2193 deserve better */
2194 Bool left = toBool(gregOfRM(modrm) == 2);
sewardj9aebb0c2004-10-24 19:20:43 +00002195 IRTemp r64 = newTemp(Ity_I64);
sewardjf9655262004-10-31 20:02:16 +00002196 IRExpr** args
2197 = mkIRExprVec_4( widenUto32(mkexpr(dst0)), /* thing to rotate */
2198 widenUto32(shift_expr), /* rotate amount */
sewardj2a9ad022004-11-25 02:46:58 +00002199 widenUto32(mk_x86g_calculate_eflags_all()),
sewardjf9655262004-10-31 20:02:16 +00002200 mkU32(sz) );
2201 assign( r64, mkIRExprCCall(
sewardj8ea867b2004-10-30 19:03:02 +00002202 Ity_I64,
sewardjf9655262004-10-31 20:02:16 +00002203 0/*regparm*/,
sewardj2eef7732005-08-23 15:41:14 +00002204 left ? "x86g_calculate_RCL" : "x86g_calculate_RCR",
2205 left ? &x86g_calculate_RCL : &x86g_calculate_RCR,
sewardj8ea867b2004-10-30 19:03:02 +00002206 args
sewardjf9655262004-10-31 20:02:16 +00002207 )
2208 );
sewardj9aebb0c2004-10-24 19:20:43 +00002209 /* new eflags in hi half r64; new value in lo half r64 */
2210 assign( dst1, narrowTo(ty, unop(Iop_64to32, mkexpr(r64))) );
sewardj2a9ad022004-11-25 02:46:58 +00002211 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
sewardj2a2ba8b2004-11-08 13:14:06 +00002212 stmt( IRStmt_Put( OFFB_CC_DEP1, unop(Iop_64HIto32, mkexpr(r64)) ));
2213 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
sewardja3b7e3a2005-04-05 01:54:19 +00002214 /* Set NDEP even though it isn't used. This makes redundant-PUT
2215 elimination of previous stores to this field work better. */
2216 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardj9aebb0c2004-10-24 19:20:43 +00002217 }
2218
sewardje90ad6a2004-07-10 19:02:10 +00002219 if (isShift) {
2220
sewardjc22a6fd2004-07-29 23:41:47 +00002221 IRTemp pre32 = newTemp(Ity_I32);
2222 IRTemp res32 = newTemp(Ity_I32);
2223 IRTemp res32ss = newTemp(Ity_I32);
sewardj6d2638e2004-07-15 09:38:27 +00002224 IRTemp shift_amt = newTemp(Ity_I8);
sewardjc22a6fd2004-07-29 23:41:47 +00002225 IROp op32;
sewardje90ad6a2004-07-10 19:02:10 +00002226
2227 switch (gregOfRM(modrm)) {
sewardjc22a6fd2004-07-29 23:41:47 +00002228 case 4: op32 = Iop_Shl32; break;
2229 case 5: op32 = Iop_Shr32; break;
2230 case 7: op32 = Iop_Sar32; break;
sewardje90ad6a2004-07-10 19:02:10 +00002231 default: vpanic("dis_Grp2:shift"); break;
2232 }
2233
sewardjc22a6fd2004-07-29 23:41:47 +00002234 /* Widen the value to be shifted to 32 bits, do the shift, and
2235 narrow back down. This seems surprisingly long-winded, but
2236 unfortunately the Intel semantics requires that 8/16-bit
2237 shifts give defined results for shift values all the way up
2238 to 31, and this seems the simplest way to do it. It has the
2239 advantage that the only IR level shifts generated are of 32
2240 bit values, and the shift amount is guaranteed to be in the
2241 range 0 .. 31, thereby observing the IR semantics requiring
2242 all shift values to be in the range 0 .. 2^word_size-1. */
2243
2244 /* shift_amt = shift_expr & 31, regardless of operation size */
2245 assign( shift_amt, binop(Iop_And8, shift_expr, mkU8(31)) );
2246
2247 /* suitably widen the value to be shifted to 32 bits. */
2248 assign( pre32, op32==Iop_Sar32 ? widenSto32(mkexpr(dst0))
2249 : widenUto32(mkexpr(dst0)) );
2250
2251 /* res32 = pre32 `shift` shift_amt */
2252 assign( res32, binop(op32, mkexpr(pre32), mkexpr(shift_amt)) );
2253
2254 /* res32ss = pre32 `shift` ((shift_amt - 1) & 31) */
2255 assign( res32ss,
2256 binop(op32,
2257 mkexpr(pre32),
2258 binop(Iop_And8,
2259 binop(Iop_Sub8,
2260 mkexpr(shift_amt), mkU8(1)),
2261 mkU8(31))) );
sewardje90ad6a2004-07-10 19:02:10 +00002262
2263 /* Build the flags thunk. */
sewardj2a2ba8b2004-11-08 13:14:06 +00002264 setFlags_DEP1_DEP2_shift(op32, res32, res32ss, ty, shift_amt);
sewardjc22a6fd2004-07-29 23:41:47 +00002265
2266 /* Narrow the result back down. */
2267 assign( dst1, narrowTo(ty, mkexpr(res32)) );
sewardj750f4072004-07-26 22:39:11 +00002268
sewardj1813dbe2004-07-28 17:09:04 +00002269 } /* if (isShift) */
2270
2271 else
sewardj750f4072004-07-26 22:39:11 +00002272 if (isRotate) {
sewardj7ebbdae2004-08-26 12:30:48 +00002273 Int ccOp = ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
sewardj2d49b432005-02-01 00:37:06 +00002274 Bool left = toBool(gregOfRM(modrm) == 0);
sewardj7ebbdae2004-08-26 12:30:48 +00002275 IRTemp rot_amt = newTemp(Ity_I8);
2276 IRTemp rot_amt32 = newTemp(Ity_I8);
2277 IRTemp oldFlags = newTemp(Ity_I32);
sewardj750f4072004-07-26 22:39:11 +00002278
2279 /* rot_amt = shift_expr & mask */
sewardjc22a6fd2004-07-29 23:41:47 +00002280 /* By masking the rotate amount thusly, the IR-level Shl/Shr
2281 expressions never shift beyond the word size and thus remain
2282 well defined. */
sewardj7ebbdae2004-08-26 12:30:48 +00002283 assign(rot_amt32, binop(Iop_And8, shift_expr, mkU8(31)));
2284
2285 if (ty == Ity_I32)
2286 assign(rot_amt, mkexpr(rot_amt32));
2287 else
2288 assign(rot_amt, binop(Iop_And8, mkexpr(rot_amt32), mkU8(8*sz-1)));
sewardj750f4072004-07-26 22:39:11 +00002289
2290 if (left) {
sewardj1813dbe2004-07-28 17:09:04 +00002291
sewardj750f4072004-07-26 22:39:11 +00002292 /* dst1 = (dst0 << rot_amt) | (dst0 >>u (wordsize-rot_amt)) */
2293 assign(dst1,
2294 binop( mkSizedOp(ty,Iop_Or8),
2295 binop( mkSizedOp(ty,Iop_Shl8),
2296 mkexpr(dst0),
2297 mkexpr(rot_amt)
2298 ),
2299 binop( mkSizedOp(ty,Iop_Shr8),
2300 mkexpr(dst0),
2301 binop(Iop_Sub8,mkU8(8*sz), mkexpr(rot_amt))
2302 )
2303 )
2304 );
sewardj2a9ad022004-11-25 02:46:58 +00002305 ccOp += X86G_CC_OP_ROLB;
sewardj750f4072004-07-26 22:39:11 +00002306
sewardj1813dbe2004-07-28 17:09:04 +00002307 } else { /* right */
sewardj750f4072004-07-26 22:39:11 +00002308
sewardj1813dbe2004-07-28 17:09:04 +00002309 /* dst1 = (dst0 >>u rot_amt) | (dst0 << (wordsize-rot_amt)) */
2310 assign(dst1,
2311 binop( mkSizedOp(ty,Iop_Or8),
2312 binop( mkSizedOp(ty,Iop_Shr8),
2313 mkexpr(dst0),
2314 mkexpr(rot_amt)
2315 ),
2316 binop( mkSizedOp(ty,Iop_Shl8),
2317 mkexpr(dst0),
2318 binop(Iop_Sub8,mkU8(8*sz), mkexpr(rot_amt))
sewardj750f4072004-07-26 22:39:11 +00002319 )
2320 )
2321 );
sewardj2a9ad022004-11-25 02:46:58 +00002322 ccOp += X86G_CC_OP_RORB;
sewardjc22a6fd2004-07-29 23:41:47 +00002323
sewardj750f4072004-07-26 22:39:11 +00002324 }
sewardjc22a6fd2004-07-29 23:41:47 +00002325
sewardj1813dbe2004-07-28 17:09:04 +00002326 /* dst1 now holds the rotated value. Build flag thunk. We
2327 need the resulting value for this, and the previous flags.
2328 Except don't set it if the rotate count is zero. */
2329
sewardj2a9ad022004-11-25 02:46:58 +00002330 assign(oldFlags, mk_x86g_calculate_eflags_all());
sewardj1813dbe2004-07-28 17:09:04 +00002331
sewardj2a2ba8b2004-11-08 13:14:06 +00002332 /* CC_DEP1 is the rotated value. CC_NDEP is flags before. */
sewardj1813dbe2004-07-28 17:09:04 +00002333 stmt( IRStmt_Put( OFFB_CC_OP,
sewardj7ebbdae2004-08-26 12:30:48 +00002334 IRExpr_Mux0X( mkexpr(rot_amt32),
sewardj1813dbe2004-07-28 17:09:04 +00002335 IRExpr_Get(OFFB_CC_OP,Ity_I32),
2336 mkU32(ccOp))) );
sewardj2a2ba8b2004-11-08 13:14:06 +00002337 stmt( IRStmt_Put( OFFB_CC_DEP1,
sewardj7ebbdae2004-08-26 12:30:48 +00002338 IRExpr_Mux0X( mkexpr(rot_amt32),
sewardj2a2ba8b2004-11-08 13:14:06 +00002339 IRExpr_Get(OFFB_CC_DEP1,Ity_I32),
sewardjc22a6fd2004-07-29 23:41:47 +00002340 widenUto32(mkexpr(dst1)))) );
sewardj2a2ba8b2004-11-08 13:14:06 +00002341 stmt( IRStmt_Put( OFFB_CC_DEP2,
sewardj7ebbdae2004-08-26 12:30:48 +00002342 IRExpr_Mux0X( mkexpr(rot_amt32),
sewardj2a2ba8b2004-11-08 13:14:06 +00002343 IRExpr_Get(OFFB_CC_DEP2,Ity_I32),
2344 mkU32(0))) );
2345 stmt( IRStmt_Put( OFFB_CC_NDEP,
2346 IRExpr_Mux0X( mkexpr(rot_amt32),
2347 IRExpr_Get(OFFB_CC_NDEP,Ity_I32),
sewardj1813dbe2004-07-28 17:09:04 +00002348 mkexpr(oldFlags))) );
2349 } /* if (isRotate) */
sewardje90ad6a2004-07-10 19:02:10 +00002350
2351 /* Save result, and finish up. */
2352 if (epartIsReg(modrm)) {
2353 putIReg(sz, eregOfRM(modrm), mkexpr(dst1));
sewardjf48ac192004-10-29 00:41:29 +00002354 if (vex_traceflags & VEX_TRACE_FE) {
sewardje90ad6a2004-07-10 19:02:10 +00002355 vex_printf("%s%c ",
2356 nameGrp2(gregOfRM(modrm)), nameISize(sz) );
sewardj6d2638e2004-07-15 09:38:27 +00002357 if (shift_expr_txt)
2358 vex_printf("%s", shift_expr_txt);
2359 else
2360 ppIRExpr(shift_expr);
sewardje90ad6a2004-07-10 19:02:10 +00002361 vex_printf(", %s\n", nameIReg(sz,eregOfRM(modrm)));
2362 }
sewardje90ad6a2004-07-10 19:02:10 +00002363 } else {
sewardj940e8c92004-07-11 16:53:24 +00002364 storeLE(mkexpr(addr), mkexpr(dst1));
sewardjf48ac192004-10-29 00:41:29 +00002365 if (vex_traceflags & VEX_TRACE_FE) {
sewardj940e8c92004-07-11 16:53:24 +00002366 vex_printf("%s%c ",
2367 nameGrp2(gregOfRM(modrm)), nameISize(sz) );
sewardj6d2638e2004-07-15 09:38:27 +00002368 if (shift_expr_txt)
2369 vex_printf("%s", shift_expr_txt);
2370 else
2371 ppIRExpr(shift_expr);
sewardj940e8c92004-07-11 16:53:24 +00002372 vex_printf(", %s\n", dis_buf);
2373 }
sewardje90ad6a2004-07-10 19:02:10 +00002374 }
sewardje90ad6a2004-07-10 19:02:10 +00002375 return delta;
2376}
2377
2378
sewardj490ad382005-03-13 17:25:53 +00002379/* Group 8 extended opcodes (but BT/BTS/BTC/BTR only). */
2380static
sewardj52d04912005-07-03 00:52:48 +00002381UInt dis_Grp8_Imm ( UChar sorb,
2382 Int delta, UChar modrm,
sewardj490ad382005-03-13 17:25:53 +00002383 Int am_sz, Int sz, UInt src_val,
2384 Bool* decode_OK )
2385{
2386 /* src_val denotes a d8.
2387 And delta on entry points at the modrm byte. */
sewardje90ad6a2004-07-10 19:02:10 +00002388
sewardj490ad382005-03-13 17:25:53 +00002389 IRType ty = szToITy(sz);
2390 IRTemp t2 = newTemp(Ity_I32);
2391 IRTemp t2m = newTemp(Ity_I32);
2392 IRTemp t_addr = IRTemp_INVALID;
2393 HChar dis_buf[50];
2394 UInt mask;
sewardjd1061ab2004-07-08 01:45:30 +00002395
sewardj490ad382005-03-13 17:25:53 +00002396 /* we're optimists :-) */
2397 *decode_OK = True;
sewardjd1061ab2004-07-08 01:45:30 +00002398
sewardj490ad382005-03-13 17:25:53 +00002399 /* Limit src_val -- the bit offset -- to something within a word.
2400 The Intel docs say that literal offsets larger than a word are
2401 masked in this way. */
2402 switch (sz) {
2403 case 2: src_val &= 15; break;
2404 case 4: src_val &= 31; break;
2405 default: *decode_OK = False; return delta;
2406 }
sewardjcf780b42004-07-13 18:42:17 +00002407
sewardj490ad382005-03-13 17:25:53 +00002408 /* Invent a mask suitable for the operation. */
2409 switch (gregOfRM(modrm)) {
2410 case 4: /* BT */ mask = 0; break;
2411 case 5: /* BTS */ mask = 1 << src_val; break;
2412 case 6: /* BTR */ mask = ~(1 << src_val); break;
2413 case 7: /* BTC */ mask = 1 << src_val; break;
2414 /* If this needs to be extended, probably simplest to make a
2415 new function to handle the other cases (0 .. 3). The
2416 Intel docs do however not indicate any use for 0 .. 3, so
2417 we don't expect this to happen. */
2418 default: *decode_OK = False; return delta;
2419 }
2420
2421 /* Fetch the value to be tested and modified into t2, which is
2422 32-bits wide regardless of sz. */
2423 if (epartIsReg(modrm)) {
2424 vassert(am_sz == 1);
sewardj5a8334e2005-03-13 19:52:45 +00002425 assign( t2, widenUto32(getIReg(sz, eregOfRM(modrm))) );
sewardj490ad382005-03-13 17:25:53 +00002426 delta += (am_sz + 1);
2427 DIP("%s%c $0x%x, %s\n", nameGrp8(gregOfRM(modrm)), nameISize(sz),
2428 src_val, nameIReg(sz,eregOfRM(modrm)));
2429 } else {
2430 Int len;
2431 t_addr = disAMode ( &len, sorb, delta, dis_buf);
2432 delta += (len+1);
2433 assign( t2, widenUto32(loadLE(ty, mkexpr(t_addr))) );
2434 DIP("%s%c $0x%x, %s\n", nameGrp8(gregOfRM(modrm)), nameISize(sz),
2435 src_val, dis_buf);
2436 }
2437
2438 /* Copy relevant bit from t2 into the carry flag. */
2439 /* Flags: C=selected bit, O,S,Z,A,P undefined, so are set to zero. */
2440 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
2441 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
2442 stmt( IRStmt_Put(
2443 OFFB_CC_DEP1,
2444 binop(Iop_And32,
2445 binop(Iop_Shr32, mkexpr(t2), mkU8(src_val)),
2446 mkU32(1))
2447 ));
sewardja3b7e3a2005-04-05 01:54:19 +00002448 /* Set NDEP even though it isn't used. This makes redundant-PUT
2449 elimination of previous stores to this field work better. */
2450 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardj490ad382005-03-13 17:25:53 +00002451
2452 /* Compute the new value into t2m, if non-BT. */
2453 switch (gregOfRM(modrm)) {
2454 case 4: /* BT */
2455 break;
2456 case 5: /* BTS */
2457 assign( t2m, binop(Iop_Or32, mkU32(mask), mkexpr(t2)) );
2458 break;
2459 case 6: /* BTR */
2460 assign( t2m, binop(Iop_And32, mkU32(mask), mkexpr(t2)) );
2461 break;
2462 case 7: /* BTC */
2463 assign( t2m, binop(Iop_Xor32, mkU32(mask), mkexpr(t2)) );
2464 break;
sewardjba89f4c2005-04-07 17:31:27 +00002465 default:
2466 /*NOTREACHED*/ /*the previous switch guards this*/
sewardj490ad382005-03-13 17:25:53 +00002467 vassert(0);
2468 }
2469
2470 /* Write the result back, if non-BT. */
2471 if (gregOfRM(modrm) != 4 /* BT */) {
2472 if (epartIsReg(modrm)) {
2473 putIReg(sz, eregOfRM(modrm), narrowTo(ty, mkexpr(t2m)));
2474 } else {
2475 storeLE(mkexpr(t_addr), narrowTo(ty, mkexpr(t2m)));
2476 }
2477 }
2478
2479 return delta;
2480}
sewardjcf780b42004-07-13 18:42:17 +00002481
2482
sewardj1813dbe2004-07-28 17:09:04 +00002483/* Signed/unsigned widening multiply. Generate IR to multiply the
2484 value in EAX/AX/AL by the given IRTemp, and park the result in
2485 EDX:EAX/DX:AX/AX.
sewardjcf780b42004-07-13 18:42:17 +00002486*/
sewardj1813dbe2004-07-28 17:09:04 +00002487static void codegen_mulL_A_D ( Int sz, Bool syned,
sewardj2d49b432005-02-01 00:37:06 +00002488 IRTemp tmp, HChar* tmp_txt )
sewardjcf780b42004-07-13 18:42:17 +00002489{
sewardjcf780b42004-07-13 18:42:17 +00002490 IRType ty = szToITy(sz);
2491 IRTemp t1 = newTemp(ty);
sewardjcf780b42004-07-13 18:42:17 +00002492
sewardj1813dbe2004-07-28 17:09:04 +00002493 assign( t1, getIReg(sz, R_EAX) );
sewardjcf780b42004-07-13 18:42:17 +00002494
2495 switch (ty) {
sewardjb81f8b32004-07-30 10:17:50 +00002496 case Ity_I32: {
2497 IRTemp res64 = newTemp(Ity_I64);
sewardj948d48b2004-11-05 19:49:09 +00002498 IRTemp resHi = newTemp(Ity_I32);
2499 IRTemp resLo = newTemp(Ity_I32);
sewardjb81f8b32004-07-30 10:17:50 +00002500 IROp mulOp = syned ? Iop_MullS32 : Iop_MullU32;
sewardj2a9ad022004-11-25 02:46:58 +00002501 UInt tBaseOp = syned ? X86G_CC_OP_SMULB : X86G_CC_OP_UMULB;
sewardj2a2ba8b2004-11-08 13:14:06 +00002502 setFlags_MUL ( Ity_I32, t1, tmp, tBaseOp );
sewardjb81f8b32004-07-30 10:17:50 +00002503 assign( res64, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
sewardj948d48b2004-11-05 19:49:09 +00002504 assign( resHi, unop(Iop_64HIto32,mkexpr(res64)));
2505 assign( resLo, unop(Iop_64to32,mkexpr(res64)));
sewardj948d48b2004-11-05 19:49:09 +00002506 putIReg(4, R_EDX, mkexpr(resHi));
2507 putIReg(4, R_EAX, mkexpr(resLo));
sewardjb81f8b32004-07-30 10:17:50 +00002508 break;
2509 }
2510 case Ity_I16: {
2511 IRTemp res32 = newTemp(Ity_I32);
sewardj948d48b2004-11-05 19:49:09 +00002512 IRTemp resHi = newTemp(Ity_I16);
2513 IRTemp resLo = newTemp(Ity_I16);
sewardjb81f8b32004-07-30 10:17:50 +00002514 IROp mulOp = syned ? Iop_MullS16 : Iop_MullU16;
sewardj2a9ad022004-11-25 02:46:58 +00002515 UInt tBaseOp = syned ? X86G_CC_OP_SMULB : X86G_CC_OP_UMULB;
sewardj2a2ba8b2004-11-08 13:14:06 +00002516 setFlags_MUL ( Ity_I16, t1, tmp, tBaseOp );
sewardjb81f8b32004-07-30 10:17:50 +00002517 assign( res32, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
sewardj948d48b2004-11-05 19:49:09 +00002518 assign( resHi, unop(Iop_32HIto16,mkexpr(res32)));
2519 assign( resLo, unop(Iop_32to16,mkexpr(res32)));
sewardj948d48b2004-11-05 19:49:09 +00002520 putIReg(2, R_EDX, mkexpr(resHi));
2521 putIReg(2, R_EAX, mkexpr(resLo));
sewardjb81f8b32004-07-30 10:17:50 +00002522 break;
2523 }
2524 case Ity_I8: {
2525 IRTemp res16 = newTemp(Ity_I16);
sewardj948d48b2004-11-05 19:49:09 +00002526 IRTemp resHi = newTemp(Ity_I8);
2527 IRTemp resLo = newTemp(Ity_I8);
sewardjb81f8b32004-07-30 10:17:50 +00002528 IROp mulOp = syned ? Iop_MullS8 : Iop_MullU8;
sewardj2a9ad022004-11-25 02:46:58 +00002529 UInt tBaseOp = syned ? X86G_CC_OP_SMULB : X86G_CC_OP_UMULB;
sewardj2a2ba8b2004-11-08 13:14:06 +00002530 setFlags_MUL ( Ity_I8, t1, tmp, tBaseOp );
sewardjb81f8b32004-07-30 10:17:50 +00002531 assign( res16, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
sewardj948d48b2004-11-05 19:49:09 +00002532 assign( resHi, unop(Iop_16HIto8,mkexpr(res16)));
2533 assign( resLo, unop(Iop_16to8,mkexpr(res16)));
sewardjb81f8b32004-07-30 10:17:50 +00002534 putIReg(2, R_EAX, mkexpr(res16));
2535 break;
2536 }
2537 default:
2538 vpanic("codegen_mulL_A_D(x86)");
sewardjcf780b42004-07-13 18:42:17 +00002539 }
sewardj1813dbe2004-07-28 17:09:04 +00002540 DIP("%s%c %s\n", syned ? "imul" : "mul", nameISize(sz), tmp_txt);
sewardjcf780b42004-07-13 18:42:17 +00002541}
2542
sewardj940e8c92004-07-11 16:53:24 +00002543
2544/* Group 3 extended opcodes. */
2545static
sewardj52d04912005-07-03 00:52:48 +00002546UInt dis_Grp3 ( UChar sorb, Int sz, Int delta )
sewardj940e8c92004-07-11 16:53:24 +00002547{
sewardjc9a43662004-11-30 18:51:59 +00002548 UInt d32;
2549 UChar modrm;
2550 HChar dis_buf[50];
2551 Int len;
sewardjc2ac51e2004-07-12 01:03:26 +00002552 IRTemp addr;
sewardj940e8c92004-07-11 16:53:24 +00002553 IRType ty = szToITy(sz);
2554 IRTemp t1 = newTemp(ty);
sewardj92d168d2004-11-15 14:22:12 +00002555 // IRTemp t2 = IRTemp_INVALID;
sewardj940e8c92004-07-11 16:53:24 +00002556 IRTemp dst1, src, dst0;
2557 modrm = getIByte(delta);
2558 if (epartIsReg(modrm)) {
2559 switch (gregOfRM(modrm)) {
sewardjc2ac51e2004-07-12 01:03:26 +00002560 case 0: { /* TEST */
2561 delta++; d32 = getUDisp(sz, delta); delta += sz;
sewardj5bd4d162004-11-10 13:02:48 +00002562 dst1 = newTemp(ty);
2563 assign(dst1, binop(mkSizedOp(ty,Iop_And8),
2564 getIReg(sz,eregOfRM(modrm)),
sewardjc2ac51e2004-07-12 01:03:26 +00002565 mkU(ty,d32)));
sewardj5bd4d162004-11-10 13:02:48 +00002566 setFlags_DEP1( Iop_And8, dst1, ty );
sewardjc2ac51e2004-07-12 01:03:26 +00002567 DIP("test%c $0x%x, %s\n", nameISize(sz), d32,
2568 nameIReg(sz, eregOfRM(modrm)));
2569 break;
2570 }
sewardj940e8c92004-07-11 16:53:24 +00002571 case 2: /* NOT */
2572 delta++;
2573 putIReg(sz, eregOfRM(modrm),
2574 unop(mkSizedOp(ty,Iop_Not8),
2575 getIReg(sz, eregOfRM(modrm))));
2576 DIP("not%c %s\n", nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
2577 break;
2578 case 3: /* NEG */
2579 delta++;
2580 dst0 = newTemp(ty);
2581 src = newTemp(ty);
2582 dst1 = newTemp(ty);
sewardj5bd4d162004-11-10 13:02:48 +00002583 assign(dst0, mkU(ty,0));
sewardja511afc2004-07-29 22:26:03 +00002584 assign(src, getIReg(sz,eregOfRM(modrm)));
sewardj71a35e72005-05-03 12:20:15 +00002585 assign(dst1, unop(mkSizedOp(ty,Iop_Neg8), mkexpr(src)));
sewardj2a2ba8b2004-11-08 13:14:06 +00002586 setFlags_DEP1_DEP2(Iop_Sub8, dst0, src, ty);
sewardj5bd4d162004-11-10 13:02:48 +00002587 putIReg(sz, eregOfRM(modrm), mkexpr(dst1));
sewardj940e8c92004-07-11 16:53:24 +00002588 DIP("neg%c %s\n", nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
2589 break;
sewardjcf780b42004-07-13 18:42:17 +00002590 case 4: /* MUL (unsigned widening) */
2591 delta++;
sewardj1813dbe2004-07-28 17:09:04 +00002592 src = newTemp(ty);
sewardj5bd4d162004-11-10 13:02:48 +00002593 assign(src, getIReg(sz,eregOfRM(modrm)));
sewardj1813dbe2004-07-28 17:09:04 +00002594 codegen_mulL_A_D ( sz, False, src, nameIReg(sz,eregOfRM(modrm)) );
sewardjcf780b42004-07-13 18:42:17 +00002595 break;
sewardjcaca9d02004-07-28 07:11:32 +00002596 case 5: /* IMUL (signed widening) */
2597 delta++;
sewardj1813dbe2004-07-28 17:09:04 +00002598 src = newTemp(ty);
sewardj5bd4d162004-11-10 13:02:48 +00002599 assign(src, getIReg(sz,eregOfRM(modrm)));
sewardj1813dbe2004-07-28 17:09:04 +00002600 codegen_mulL_A_D ( sz, True, src, nameIReg(sz,eregOfRM(modrm)) );
sewardjcaca9d02004-07-28 07:11:32 +00002601 break;
sewardj68511542004-07-28 00:15:44 +00002602 case 6: /* DIV */
2603 delta++;
2604 assign( t1, getIReg(sz, eregOfRM(modrm)) );
2605 codegen_div ( sz, t1, False );
2606 DIP("div%c %s\n", nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
2607 break;
sewardjcaca9d02004-07-28 07:11:32 +00002608 case 7: /* IDIV */
2609 delta++;
2610 assign( t1, getIReg(sz, eregOfRM(modrm)) );
2611 codegen_div ( sz, t1, True );
2612 DIP("idiv%c %s\n", nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
2613 break;
sewardj940e8c92004-07-11 16:53:24 +00002614 default:
2615 vex_printf(
sewardj2d49b432005-02-01 00:37:06 +00002616 "unhandled Grp3(R) case %d\n", (Int)gregOfRM(modrm));
sewardj940e8c92004-07-11 16:53:24 +00002617 vpanic("Grp3(x86)");
2618 }
2619 } else {
sewardjc2ac51e2004-07-12 01:03:26 +00002620 addr = disAMode ( &len, sorb, delta, dis_buf );
2621 t1 = newTemp(ty);
2622 delta += len;
2623 assign(t1, loadLE(ty,mkexpr(addr)));
2624 switch (gregOfRM(modrm)) {
2625 case 0: { /* TEST */
2626 d32 = getUDisp(sz, delta); delta += sz;
sewardj5bd4d162004-11-10 13:02:48 +00002627 dst1 = newTemp(ty);
2628 assign(dst1, binop(mkSizedOp(ty,Iop_And8),
2629 mkexpr(t1), mkU(ty,d32)));
2630 setFlags_DEP1( Iop_And8, dst1, ty );
sewardjc2ac51e2004-07-12 01:03:26 +00002631 DIP("test%c $0x%x, %s\n", nameISize(sz), d32, dis_buf);
2632 break;
2633 }
sewardj78fe7912004-08-20 23:38:07 +00002634 case 2: /* NOT */
2635 storeLE( mkexpr(addr), unop(mkSizedOp(ty,Iop_Not8), mkexpr(t1)));
2636 DIP("not%c %s\n", nameISize(sz), dis_buf);
2637 break;
sewardj0c12ea82004-07-12 08:18:16 +00002638 case 3: /* NEG */
2639 dst0 = newTemp(ty);
2640 src = newTemp(ty);
2641 dst1 = newTemp(ty);
sewardj5bd4d162004-11-10 13:02:48 +00002642 assign(dst0, mkU(ty,0));
sewardja511afc2004-07-29 22:26:03 +00002643 assign(src, mkexpr(t1));
sewardj71a35e72005-05-03 12:20:15 +00002644 assign(dst1, unop(mkSizedOp(ty,Iop_Neg8), mkexpr(src)));
sewardj2a2ba8b2004-11-08 13:14:06 +00002645 setFlags_DEP1_DEP2(Iop_Sub8, dst0, src, ty);
sewardj5bd4d162004-11-10 13:02:48 +00002646 storeLE( mkexpr(addr), mkexpr(dst1) );
sewardj0c12ea82004-07-12 08:18:16 +00002647 DIP("neg%c %s\n", nameISize(sz), dis_buf);
2648 break;
sewardj1813dbe2004-07-28 17:09:04 +00002649 case 4: /* MUL */
2650 codegen_mulL_A_D ( sz, False, t1, dis_buf );
2651 break;
2652 case 5: /* IMUL */
2653 codegen_mulL_A_D ( sz, True, t1, dis_buf );
2654 break;
sewardj9690d922004-07-14 01:39:17 +00002655 case 6: /* DIV */
2656 codegen_div ( sz, t1, False );
2657 DIP("div%c %s\n", nameISize(sz), dis_buf);
2658 break;
sewardj1813dbe2004-07-28 17:09:04 +00002659 case 7: /* IDIV */
2660 codegen_div ( sz, t1, True );
2661 DIP("idiv%c %s\n", nameISize(sz), dis_buf);
2662 break;
sewardjc2ac51e2004-07-12 01:03:26 +00002663 default:
2664 vex_printf(
sewardj2d49b432005-02-01 00:37:06 +00002665 "unhandled Grp3(M) case %d\n", (Int)gregOfRM(modrm));
sewardjc2ac51e2004-07-12 01:03:26 +00002666 vpanic("Grp3(x86)");
2667 }
sewardj940e8c92004-07-11 16:53:24 +00002668 }
2669 return delta;
2670}
2671
2672
sewardjc2ac51e2004-07-12 01:03:26 +00002673/* Group 4 extended opcodes. */
2674static
sewardj52d04912005-07-03 00:52:48 +00002675UInt dis_Grp4 ( UChar sorb, Int delta )
sewardjc2ac51e2004-07-12 01:03:26 +00002676{
sewardjc9a43662004-11-30 18:51:59 +00002677 Int alen;
sewardjc2ac51e2004-07-12 01:03:26 +00002678 UChar modrm;
sewardjc9a43662004-11-30 18:51:59 +00002679 HChar dis_buf[50];
sewardjc2ac51e2004-07-12 01:03:26 +00002680 IRType ty = Ity_I8;
sewardj7ed22952004-07-29 00:09:58 +00002681 IRTemp t1 = newTemp(ty);
2682 IRTemp t2 = newTemp(ty);
sewardjc2ac51e2004-07-12 01:03:26 +00002683
2684 modrm = getIByte(delta);
2685 if (epartIsReg(modrm)) {
sewardjc2ac51e2004-07-12 01:03:26 +00002686 assign(t1, getIReg(1, eregOfRM(modrm)));
2687 switch (gregOfRM(modrm)) {
sewardj7ed22952004-07-29 00:09:58 +00002688 case 0: /* INC */
2689 assign(t2, binop(Iop_Add8, mkexpr(t1), mkU8(1)));
2690 putIReg(1, eregOfRM(modrm), mkexpr(t2));
2691 setFlags_INC_DEC( True, t2, ty );
2692 break;
sewardjc2ac51e2004-07-12 01:03:26 +00002693 case 1: /* DEC */
sewardjc2ac51e2004-07-12 01:03:26 +00002694 assign(t2, binop(Iop_Sub8, mkexpr(t1), mkU8(1)));
2695 putIReg(1, eregOfRM(modrm), mkexpr(t2));
2696 setFlags_INC_DEC( False, t2, ty );
2697 break;
2698 default:
2699 vex_printf(
sewardj2d49b432005-02-01 00:37:06 +00002700 "unhandled Grp4(R) case %d\n", (Int)gregOfRM(modrm));
sewardj7ed22952004-07-29 00:09:58 +00002701 vpanic("Grp4(x86,R)");
sewardjc2ac51e2004-07-12 01:03:26 +00002702 }
2703 delta++;
2704 DIP("%sb %s\n", nameGrp4(gregOfRM(modrm)),
2705 nameIReg(1, eregOfRM(modrm)));
2706 } else {
sewardj7ed22952004-07-29 00:09:58 +00002707 IRTemp addr = disAMode ( &alen, sorb, delta, dis_buf );
2708 assign( t1, loadLE(ty, mkexpr(addr)) );
2709 switch (gregOfRM(modrm)) {
sewardj588ea762004-09-10 18:56:32 +00002710 case 0: /* INC */
2711 assign(t2, binop(Iop_Add8, mkexpr(t1), mkU8(1)));
2712 storeLE( mkexpr(addr), mkexpr(t2) );
2713 setFlags_INC_DEC( True, t2, ty );
2714 break;
sewardj7ed22952004-07-29 00:09:58 +00002715 case 1: /* DEC */
2716 assign(t2, binop(Iop_Sub8, mkexpr(t1), mkU8(1)));
2717 storeLE( mkexpr(addr), mkexpr(t2) );
2718 setFlags_INC_DEC( False, t2, ty );
2719 break;
2720 default:
2721 vex_printf(
sewardj2d49b432005-02-01 00:37:06 +00002722 "unhandled Grp4(M) case %d\n", (Int)gregOfRM(modrm));
sewardj7ed22952004-07-29 00:09:58 +00002723 vpanic("Grp4(x86,M)");
2724 }
2725 delta += alen;
2726 DIP("%sb %s\n", nameGrp4(gregOfRM(modrm)), dis_buf);
sewardjc2ac51e2004-07-12 01:03:26 +00002727 }
2728 return delta;
2729}
sewardj0611d802004-07-11 02:37:54 +00002730
2731
2732/* Group 5 extended opcodes. */
2733static
sewardj52d04912005-07-03 00:52:48 +00002734UInt dis_Grp5 ( UChar sorb, Int sz, Int delta, DisResult* dres )
sewardj0611d802004-07-11 02:37:54 +00002735{
2736 Int len;
2737 UChar modrm;
sewardjc9a43662004-11-30 18:51:59 +00002738 HChar dis_buf[50];
sewardj92d168d2004-11-15 14:22:12 +00002739 IRTemp addr = IRTemp_INVALID;
sewardj0611d802004-07-11 02:37:54 +00002740 IRType ty = szToITy(sz);
2741 IRTemp t1 = newTemp(ty);
sewardj92d168d2004-11-15 14:22:12 +00002742 IRTemp t2 = IRTemp_INVALID;
sewardj0611d802004-07-11 02:37:54 +00002743
2744 modrm = getIByte(delta);
2745 if (epartIsReg(modrm)) {
sewardj940e8c92004-07-11 16:53:24 +00002746 assign(t1, getIReg(sz,eregOfRM(modrm)));
sewardj0611d802004-07-11 02:37:54 +00002747 switch (gregOfRM(modrm)) {
sewardjc9a65702004-07-07 16:32:57 +00002748//-- case 0: /* INC */
2749//-- uInstr1(cb, INC, sz, TempReg, t1);
2750//-- setFlagsFromUOpcode(cb, INC);
2751//-- uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, eregOfRM(modrm));
2752//-- break;
2753//-- case 1: /* DEC */
2754//-- uInstr1(cb, DEC, sz, TempReg, t1);
2755//-- setFlagsFromUOpcode(cb, DEC);
2756//-- uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, eregOfRM(modrm));
2757//-- break;
sewardjc2ac51e2004-07-12 01:03:26 +00002758 case 2: /* call Ev */
2759 vassert(sz == 4);
2760 t2 = newTemp(Ity_I32);
2761 assign(t2, binop(Iop_Sub32, getIReg(4,R_ESP), mkU32(4)));
2762 putIReg(4, R_ESP, mkexpr(t2));
sewardj9e6491a2005-07-02 19:24:10 +00002763 storeLE( mkexpr(t2), mkU32(guest_EIP_bbstart+delta+1));
sewardj5bd4d162004-11-10 13:02:48 +00002764 jmp_treg(Ijk_Call,t1);
sewardj9e6491a2005-07-02 19:24:10 +00002765 dres->whatNext = Dis_StopHere;
sewardjc2ac51e2004-07-12 01:03:26 +00002766 break;
sewardj0611d802004-07-11 02:37:54 +00002767 case 4: /* jmp Ev */
2768 vassert(sz == 4);
sewardj78c19df2004-07-12 22:49:27 +00002769 jmp_treg(Ijk_Boring,t1);
sewardj9e6491a2005-07-02 19:24:10 +00002770 dres->whatNext = Dis_StopHere;
sewardj0611d802004-07-11 02:37:54 +00002771 break;
2772 default:
2773 vex_printf(
sewardj2d49b432005-02-01 00:37:06 +00002774 "unhandled Grp5(R) case %d\n", (Int)gregOfRM(modrm));
sewardj0611d802004-07-11 02:37:54 +00002775 vpanic("Grp5(x86)");
2776 }
2777 delta++;
2778 DIP("%s%c %s\n", nameGrp5(gregOfRM(modrm)),
2779 nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
2780 } else {
2781 addr = disAMode ( &len, sorb, delta, dis_buf );
sewardj940e8c92004-07-11 16:53:24 +00002782 assign(t1, loadLE(ty,mkexpr(addr)));
sewardj0611d802004-07-11 02:37:54 +00002783 switch (gregOfRM(modrm)) {
2784 case 0: /* INC */
2785 t2 = newTemp(ty);
2786 assign(t2, binop(mkSizedOp(ty,Iop_Add8),
2787 mkexpr(t1), mkU(ty,1)));
2788 setFlags_INC_DEC( True, t2, ty );
sewardj940e8c92004-07-11 16:53:24 +00002789 storeLE(mkexpr(addr),mkexpr(t2));
sewardj0611d802004-07-11 02:37:54 +00002790 break;
sewardjc2ac51e2004-07-12 01:03:26 +00002791 case 1: /* DEC */
2792 t2 = newTemp(ty);
2793 assign(t2, binop(mkSizedOp(ty,Iop_Sub8),
2794 mkexpr(t1), mkU(ty,1)));
2795 setFlags_INC_DEC( False, t2, ty );
2796 storeLE(mkexpr(addr),mkexpr(t2));
2797 break;
sewardj77b86be2004-07-11 13:28:24 +00002798 case 2: /* call Ev */
2799 vassert(sz == 4);
2800 t2 = newTemp(Ity_I32);
2801 assign(t2, binop(Iop_Sub32, getIReg(4,R_ESP), mkU32(4)));
2802 putIReg(4, R_ESP, mkexpr(t2));
sewardj9e6491a2005-07-02 19:24:10 +00002803 storeLE( mkexpr(t2), mkU32(guest_EIP_bbstart+delta+len));
sewardj5bd4d162004-11-10 13:02:48 +00002804 jmp_treg(Ijk_Call,t1);
sewardj9e6491a2005-07-02 19:24:10 +00002805 dres->whatNext = Dis_StopHere;
sewardj77b86be2004-07-11 13:28:24 +00002806 break;
2807 case 4: /* JMP Ev */
2808 vassert(sz == 4);
sewardj78c19df2004-07-12 22:49:27 +00002809 jmp_treg(Ijk_Boring,t1);
sewardj9e6491a2005-07-02 19:24:10 +00002810 dres->whatNext = Dis_StopHere;
sewardj77b86be2004-07-11 13:28:24 +00002811 break;
sewardj0c12ea82004-07-12 08:18:16 +00002812 case 6: /* PUSH Ev */
2813 vassert(sz == 4 || sz == 2);
2814 t2 = newTemp(Ity_I32);
2815 assign( t2, binop(Iop_Sub32,getIReg(4,R_ESP),mkU32(sz)) );
2816 putIReg(4, R_ESP, mkexpr(t2) );
sewardj5bd4d162004-11-10 13:02:48 +00002817 storeLE( mkexpr(t2), mkexpr(t1) );
sewardj0c12ea82004-07-12 08:18:16 +00002818 break;
sewardj0611d802004-07-11 02:37:54 +00002819 default:
2820 vex_printf(
sewardj2d49b432005-02-01 00:37:06 +00002821 "unhandled Grp5(M) case %d\n", (Int)gregOfRM(modrm));
sewardj0611d802004-07-11 02:37:54 +00002822 vpanic("Grp5(x86)");
2823 }
2824 delta += len;
2825 DIP("%s%c %s\n", nameGrp5(gregOfRM(modrm)),
2826 nameISize(sz), dis_buf);
2827 }
2828 return delta;
2829}
2830
sewardj464efa42004-11-19 22:17:29 +00002831
sewardj64e1d652004-07-12 14:00:46 +00002832/*------------------------------------------------------------*/
2833/*--- Disassembling string ops (including REP prefixes) ---*/
2834/*------------------------------------------------------------*/
2835
2836/* Code shared by all the string ops */
2837static
2838void dis_string_op_increment(Int sz, Int t_inc)
2839{
2840 if (sz == 4 || sz == 2) {
2841 assign( t_inc,
2842 binop(Iop_Shl32, IRExpr_Get( OFFB_DFLAG, Ity_I32 ),
sewardj6d2638e2004-07-15 09:38:27 +00002843 mkU8(sz/2) ) );
sewardj64e1d652004-07-12 14:00:46 +00002844 } else {
2845 assign( t_inc,
2846 IRExpr_Get( OFFB_DFLAG, Ity_I32 ) );
2847 }
2848}
2849
sewardj64e1d652004-07-12 14:00:46 +00002850static
2851void dis_string_op( void (*dis_OP)( Int, IRTemp ),
sewardj2d49b432005-02-01 00:37:06 +00002852 Int sz, HChar* name, UChar sorb )
sewardj64e1d652004-07-12 14:00:46 +00002853{
2854 IRTemp t_inc = newTemp(Ity_I32);
2855 vassert(sorb == 0);
2856 dis_string_op_increment(sz, t_inc);
2857 dis_OP( sz, t_inc );
2858 DIP("%s%c\n", name, nameISize(sz));
2859}
sewardj64e1d652004-07-12 14:00:46 +00002860
2861static
2862void dis_MOVS ( Int sz, IRTemp t_inc )
2863{
2864 IRType ty = szToITy(sz);
sewardj64e1d652004-07-12 14:00:46 +00002865 IRTemp td = newTemp(Ity_I32); /* EDI */
2866 IRTemp ts = newTemp(Ity_I32); /* ESI */
2867
sewardj64e1d652004-07-12 14:00:46 +00002868 assign( td, getIReg(4, R_EDI) );
2869 assign( ts, getIReg(4, R_ESI) );
2870
sewardj64e1d652004-07-12 14:00:46 +00002871 storeLE( mkexpr(td), loadLE(ty,mkexpr(ts)) );
2872
sewardj64e1d652004-07-12 14:00:46 +00002873 putIReg( 4, R_EDI, binop(Iop_Add32, mkexpr(td), mkexpr(t_inc)) );
2874 putIReg( 4, R_ESI, binop(Iop_Add32, mkexpr(ts), mkexpr(t_inc)) );
2875}
2876
sewardj10ca4eb2005-05-30 11:19:54 +00002877static
2878void dis_LODS ( Int sz, IRTemp t_inc )
2879{
2880 IRType ty = szToITy(sz);
2881 IRTemp ts = newTemp(Ity_I32); /* ESI */
2882
2883 assign( ts, getIReg(4, R_ESI) );
2884
2885 putIReg( sz, R_EAX, loadLE(ty, mkexpr(ts)) );
2886
2887 putIReg( 4, R_ESI, binop(Iop_Add32, mkexpr(ts), mkexpr(t_inc)) );
2888}
sewardj64e1d652004-07-12 14:00:46 +00002889
2890static
2891void dis_STOS ( Int sz, IRTemp t_inc )
2892{
2893 IRType ty = szToITy(sz);
2894 IRTemp ta = newTemp(ty); /* EAX */
2895 IRTemp td = newTemp(Ity_I32); /* EDI */
2896
sewardj64e1d652004-07-12 14:00:46 +00002897 assign( ta, getIReg(sz, R_EAX) );
sewardj64e1d652004-07-12 14:00:46 +00002898 assign( td, getIReg(4, R_EDI) );
2899
sewardj6d2638e2004-07-15 09:38:27 +00002900 storeLE( mkexpr(td), mkexpr(ta) );
sewardj64e1d652004-07-12 14:00:46 +00002901
sewardj64e1d652004-07-12 14:00:46 +00002902 putIReg( 4, R_EDI, binop(Iop_Add32, mkexpr(td), mkexpr(t_inc)) );
2903}
2904
2905static
2906void dis_CMPS ( Int sz, IRTemp t_inc )
2907{
2908 IRType ty = szToITy(sz);
sewardj6d2638e2004-07-15 09:38:27 +00002909 IRTemp tdv = newTemp(ty); /* (EDI) */
2910 IRTemp tsv = newTemp(ty); /* (ESI) */
sewardj64e1d652004-07-12 14:00:46 +00002911 IRTemp td = newTemp(Ity_I32); /* EDI */
2912 IRTemp ts = newTemp(Ity_I32); /* ESI */
2913
sewardj64e1d652004-07-12 14:00:46 +00002914 assign( td, getIReg(4, R_EDI) );
sewardj64e1d652004-07-12 14:00:46 +00002915 assign( ts, getIReg(4, R_ESI) );
2916
sewardj64e1d652004-07-12 14:00:46 +00002917 assign( tdv, loadLE(ty,mkexpr(td)) );
sewardjb9c5cf62004-08-24 15:10:38 +00002918 assign( tsv, loadLE(ty,mkexpr(ts)) );
sewardj64e1d652004-07-12 14:00:46 +00002919
sewardj2a2ba8b2004-11-08 13:14:06 +00002920 setFlags_DEP1_DEP2 ( Iop_Sub8, tsv, tdv, ty );
sewardj64e1d652004-07-12 14:00:46 +00002921
sewardj64e1d652004-07-12 14:00:46 +00002922 putIReg(4, R_EDI, binop(Iop_Add32, mkexpr(td), mkexpr(t_inc)) );
sewardj64e1d652004-07-12 14:00:46 +00002923 putIReg(4, R_ESI, binop(Iop_Add32, mkexpr(ts), mkexpr(t_inc)) );
2924}
2925
sewardj64e1d652004-07-12 14:00:46 +00002926static
2927void dis_SCAS ( Int sz, IRTemp t_inc )
2928{
2929 IRType ty = szToITy(sz);
sewardj82292882004-07-27 00:15:59 +00002930 IRTemp ta = newTemp(ty); /* EAX */
sewardj64e1d652004-07-12 14:00:46 +00002931 IRTemp td = newTemp(Ity_I32); /* EDI */
2932 IRTemp tdv = newTemp(ty); /* (EDI) */
2933
sewardjb9c5cf62004-08-24 15:10:38 +00002934 assign( ta, getIReg(sz, R_EAX) );
sewardj64e1d652004-07-12 14:00:46 +00002935 assign( td, getIReg(4, R_EDI) );
2936
sewardj64e1d652004-07-12 14:00:46 +00002937 assign( tdv, loadLE(ty,mkexpr(td)) );
sewardj2a2ba8b2004-11-08 13:14:06 +00002938 setFlags_DEP1_DEP2 ( Iop_Sub8, ta, tdv, ty );
sewardj64e1d652004-07-12 14:00:46 +00002939
sewardj64e1d652004-07-12 14:00:46 +00002940 putIReg(4, R_EDI, binop(Iop_Add32, mkexpr(td), mkexpr(t_inc)) );
2941}
sewardj82292882004-07-27 00:15:59 +00002942
sewardj64e1d652004-07-12 14:00:46 +00002943
2944/* Wrap the appropriate string op inside a REP/REPE/REPNE.
2945 We assume the insn is the last one in the basic block, and so emit a jump
2946 to the next insn, rather than just falling through. */
2947static
sewardj2a9ad022004-11-25 02:46:58 +00002948void dis_REP_op ( X86Condcode cond,
sewardj64e1d652004-07-12 14:00:46 +00002949 void (*dis_OP)(Int, IRTemp),
sewardj2d49b432005-02-01 00:37:06 +00002950 Int sz, Addr32 eip, Addr32 eip_next, HChar* name )
sewardj64e1d652004-07-12 14:00:46 +00002951{
2952 IRTemp t_inc = newTemp(Ity_I32);
2953 IRTemp tc = newTemp(Ity_I32); /* ECX */
2954
sewardj64e1d652004-07-12 14:00:46 +00002955 assign( tc, getIReg(4,R_ECX) );
2956
sewardj64e1d652004-07-12 14:00:46 +00002957 stmt( IRStmt_Exit( binop(Iop_CmpEQ32,mkexpr(tc),mkU32(0)),
sewardj893aada2004-11-29 19:57:54 +00002958 Ijk_Boring,
sewardj64e1d652004-07-12 14:00:46 +00002959 IRConst_U32(eip_next) ) );
2960
sewardj64e1d652004-07-12 14:00:46 +00002961 putIReg(4, R_ECX, binop(Iop_Sub32, mkexpr(tc), mkU32(1)) );
2962
2963 dis_string_op_increment(sz, t_inc);
2964 dis_OP (sz, t_inc);
2965
sewardj2a9ad022004-11-25 02:46:58 +00002966 if (cond == X86CondAlways) {
sewardj78c19df2004-07-12 22:49:27 +00002967 jmp_lit(Ijk_Boring,eip);
sewardj64e1d652004-07-12 14:00:46 +00002968 } else {
sewardj2a9ad022004-11-25 02:46:58 +00002969 stmt( IRStmt_Exit( mk_x86g_calculate_condition(cond),
sewardj893aada2004-11-29 19:57:54 +00002970 Ijk_Boring,
sewardj5bd4d162004-11-10 13:02:48 +00002971 IRConst_U32(eip) ) );
sewardj78c19df2004-07-12 22:49:27 +00002972 jmp_lit(Ijk_Boring,eip_next);
sewardj64e1d652004-07-12 14:00:46 +00002973 }
2974 DIP("%s%c\n", name, nameISize(sz));
2975}
2976
sewardj464efa42004-11-19 22:17:29 +00002977
sewardj64e1d652004-07-12 14:00:46 +00002978/*------------------------------------------------------------*/
2979/*--- Arithmetic, etc. ---*/
2980/*------------------------------------------------------------*/
2981
sewardj2a2ba8b2004-11-08 13:14:06 +00002982/* IMUL E, G. Supplied eip points to the modR/M byte. */
sewardjcf780b42004-07-13 18:42:17 +00002983static
2984UInt dis_mul_E_G ( UChar sorb,
2985 Int size,
sewardj52d04912005-07-03 00:52:48 +00002986 Int delta0 )
sewardjcf780b42004-07-13 18:42:17 +00002987{
sewardj71a65362004-07-28 01:48:34 +00002988 Int alen;
sewardjc9a43662004-11-30 18:51:59 +00002989 HChar dis_buf[50];
sewardjcf780b42004-07-13 18:42:17 +00002990 UChar rm = getIByte(delta0);
2991 IRType ty = szToITy(size);
sewardj6d2638e2004-07-15 09:38:27 +00002992 IRTemp te = newTemp(ty);
2993 IRTemp tg = newTemp(ty);
sewardj948d48b2004-11-05 19:49:09 +00002994 IRTemp resLo = newTemp(ty);
sewardj71a65362004-07-28 01:48:34 +00002995
sewardj948d48b2004-11-05 19:49:09 +00002996 assign( tg, getIReg(size, gregOfRM(rm)) );
sewardjcf780b42004-07-13 18:42:17 +00002997 if (epartIsReg(rm)) {
sewardjcf780b42004-07-13 18:42:17 +00002998 assign( te, getIReg(size, eregOfRM(rm)) );
sewardj948d48b2004-11-05 19:49:09 +00002999 } else {
3000 IRTemp addr = disAMode( &alen, sorb, delta0, dis_buf );
3001 assign( te, loadLE(ty,mkexpr(addr)) );
3002 }
sewardjcf780b42004-07-13 18:42:17 +00003003
sewardj2a9ad022004-11-25 02:46:58 +00003004 setFlags_MUL ( ty, te, tg, X86G_CC_OP_SMULB );
sewardj948d48b2004-11-05 19:49:09 +00003005
sewardj2a2ba8b2004-11-08 13:14:06 +00003006 assign( resLo, binop( mkSizedOp(ty, Iop_Mul8), mkexpr(te), mkexpr(tg) ) );
sewardj948d48b2004-11-05 19:49:09 +00003007
3008 putIReg(size, gregOfRM(rm), mkexpr(resLo) );
3009
3010 if (epartIsReg(rm)) {
sewardj2a2ba8b2004-11-08 13:14:06 +00003011 DIP("imul%c %s, %s\n", nameISize(size),
3012 nameIReg(size,eregOfRM(rm)),
3013 nameIReg(size,gregOfRM(rm)));
sewardjcf780b42004-07-13 18:42:17 +00003014 return 1+delta0;
3015 } else {
sewardj2a2ba8b2004-11-08 13:14:06 +00003016 DIP("imul%c %s, %s\n", nameISize(size),
3017 dis_buf, nameIReg(size,gregOfRM(rm)));
sewardj71a65362004-07-28 01:48:34 +00003018 return alen+delta0;
sewardjcf780b42004-07-13 18:42:17 +00003019 }
3020}
3021
3022
sewardj1813dbe2004-07-28 17:09:04 +00003023/* IMUL I * E -> G. Supplied eip points to the modR/M byte. */
3024static
3025UInt dis_imul_I_E_G ( UChar sorb,
3026 Int size,
sewardj52d04912005-07-03 00:52:48 +00003027 Int delta,
sewardj1813dbe2004-07-28 17:09:04 +00003028 Int litsize )
3029{
sewardj883b00b2004-09-11 09:30:24 +00003030 Int d32, alen;
sewardjc9a43662004-11-30 18:51:59 +00003031 HChar dis_buf[50];
sewardjb81f8b32004-07-30 10:17:50 +00003032 UChar rm = getIByte(delta);
sewardj1813dbe2004-07-28 17:09:04 +00003033 IRType ty = szToITy(size);
3034 IRTemp te = newTemp(ty);
3035 IRTemp tl = newTemp(ty);
sewardj948d48b2004-11-05 19:49:09 +00003036 IRTemp resLo = newTemp(ty);
sewardj1813dbe2004-07-28 17:09:04 +00003037
sewardjb81f8b32004-07-30 10:17:50 +00003038 vassert(size == 1 || size == 2 || size == 4);
3039
sewardj1813dbe2004-07-28 17:09:04 +00003040 if (epartIsReg(rm)) {
3041 assign(te, getIReg(size, eregOfRM(rm)));
3042 delta++;
3043 } else {
sewardj883b00b2004-09-11 09:30:24 +00003044 IRTemp addr = disAMode( &alen, sorb, delta, dis_buf );
3045 assign(te, loadLE(ty, mkexpr(addr)));
3046 delta += alen;
sewardj1813dbe2004-07-28 17:09:04 +00003047 }
3048 d32 = getSDisp(litsize,delta);
3049 delta += litsize;
3050
sewardjb81f8b32004-07-30 10:17:50 +00003051 if (size == 1) d32 &= 0xFF;
3052 if (size == 2) d32 &= 0xFFFF;
3053
sewardj1813dbe2004-07-28 17:09:04 +00003054 assign(tl, mkU(ty,d32));
sewardj948d48b2004-11-05 19:49:09 +00003055
sewardj2a2ba8b2004-11-08 13:14:06 +00003056 assign( resLo, binop( mkSizedOp(ty, Iop_Mul8), mkexpr(te), mkexpr(tl) ));
sewardj948d48b2004-11-05 19:49:09 +00003057
sewardj2a9ad022004-11-25 02:46:58 +00003058 setFlags_MUL ( ty, te, tl, X86G_CC_OP_SMULB );
sewardj948d48b2004-11-05 19:49:09 +00003059
3060 putIReg(size, gregOfRM(rm), mkexpr(resLo));
sewardj1813dbe2004-07-28 17:09:04 +00003061
3062 DIP("imul %d, %s, %s\n", d32,
3063 ( epartIsReg(rm) ? nameIReg(size,eregOfRM(rm)) : dis_buf ),
3064 nameIReg(size,gregOfRM(rm)) );
3065 return delta;
sewardj948d48b2004-11-05 19:49:09 +00003066}
sewardj1813dbe2004-07-28 17:09:04 +00003067
3068
sewardjd1725d12004-08-12 20:46:53 +00003069/*------------------------------------------------------------*/
sewardj464efa42004-11-19 22:17:29 +00003070/*--- ---*/
3071/*--- x87 FLOATING POINT INSTRUCTIONS ---*/
3072/*--- ---*/
sewardjd1725d12004-08-12 20:46:53 +00003073/*------------------------------------------------------------*/
3074
sewardj207557a2004-08-27 12:00:18 +00003075/* --- Helper functions for dealing with the register stack. --- */
3076
sewardj893aada2004-11-29 19:57:54 +00003077/* --- Set the emulation-warning pseudo-register. --- */
3078
3079static void put_emwarn ( IRExpr* e /* :: Ity_I32 */ )
3080{
sewardj86ed7622005-03-27 02:20:56 +00003081 vassert(typeOfIRExpr(irbb->tyenv, e) == Ity_I32);
sewardj893aada2004-11-29 19:57:54 +00003082 stmt( IRStmt_Put( OFFB_EMWARN, e ) );
3083}
3084
sewardj17442fe2004-09-20 14:54:28 +00003085/* --- Produce an IRExpr* denoting a 64-bit QNaN. --- */
sewardj207557a2004-08-27 12:00:18 +00003086
sewardj17442fe2004-09-20 14:54:28 +00003087static IRExpr* mkQNaN64 ( void )
sewardj207557a2004-08-27 12:00:18 +00003088{
sewardj17442fe2004-09-20 14:54:28 +00003089 /* QNaN is 0 2047 1 0(51times)
3090 == 0b 11111111111b 1 0(51times)
3091 == 0x7FF8 0000 0000 0000
3092 */
3093 return IRExpr_Const(IRConst_F64i(0x7FF8000000000000ULL));
sewardj207557a2004-08-27 12:00:18 +00003094}
3095
sewardj893aada2004-11-29 19:57:54 +00003096/* --------- Get/put the top-of-stack pointer. --------- */
sewardjd1725d12004-08-12 20:46:53 +00003097
3098static IRExpr* get_ftop ( void )
3099{
3100 return IRExpr_Get( OFFB_FTOP, Ity_I32 );
3101}
3102
sewardj207557a2004-08-27 12:00:18 +00003103static void put_ftop ( IRExpr* e )
sewardjd1725d12004-08-12 20:46:53 +00003104{
sewardj86ed7622005-03-27 02:20:56 +00003105 vassert(typeOfIRExpr(irbb->tyenv, e) == Ity_I32);
sewardj207557a2004-08-27 12:00:18 +00003106 stmt( IRStmt_Put( OFFB_FTOP, e ) );
sewardjd1725d12004-08-12 20:46:53 +00003107}
3108
sewardj893aada2004-11-29 19:57:54 +00003109/* --------- Get/put the C3210 bits. --------- */
sewardjbdc7d212004-09-09 02:46:40 +00003110
sewardjc4be80c2004-09-10 16:17:45 +00003111static IRExpr* get_C3210 ( void )
sewardjbdc7d212004-09-09 02:46:40 +00003112{
sewardjc4be80c2004-09-10 16:17:45 +00003113 return IRExpr_Get( OFFB_FC3210, Ity_I32 );
sewardjbdc7d212004-09-09 02:46:40 +00003114}
3115
sewardjc4be80c2004-09-10 16:17:45 +00003116static void put_C3210 ( IRExpr* e )
sewardjbdc7d212004-09-09 02:46:40 +00003117{
sewardjc4be80c2004-09-10 16:17:45 +00003118 stmt( IRStmt_Put( OFFB_FC3210, e ) );
sewardjbdc7d212004-09-09 02:46:40 +00003119}
sewardjd1725d12004-08-12 20:46:53 +00003120
sewardj893aada2004-11-29 19:57:54 +00003121/* --------- Get/put the FPU rounding mode. --------- */
sewardjd01a9632004-11-30 13:18:37 +00003122static IRExpr* /* :: Ity_I32 */ get_fpround ( void )
sewardj8f3debf2004-09-08 23:42:23 +00003123{
sewardjd01a9632004-11-30 13:18:37 +00003124 return IRExpr_Get( OFFB_FPROUND, Ity_I32 );
sewardj8f3debf2004-09-08 23:42:23 +00003125}
3126
sewardjd01a9632004-11-30 13:18:37 +00003127static void put_fpround ( IRExpr* /* :: Ity_I32 */ e )
sewardj8f3debf2004-09-08 23:42:23 +00003128{
sewardjd01a9632004-11-30 13:18:37 +00003129 stmt( IRStmt_Put( OFFB_FPROUND, e ) );
sewardj8f3debf2004-09-08 23:42:23 +00003130}
3131
3132
sewardj893aada2004-11-29 19:57:54 +00003133/* --------- Synthesise a 2-bit FPU rounding mode. --------- */
sewardj8f3debf2004-09-08 23:42:23 +00003134/* Produces a value in 0 .. 3, which is encoded as per the type
sewardjd01a9632004-11-30 13:18:37 +00003135 IRRoundingMode. Since the guest_FPROUND value is also encoded as
3136 per IRRoundingMode, we merely need to get it and mask it for
3137 safety.
sewardj8f3debf2004-09-08 23:42:23 +00003138*/
3139static IRExpr* /* :: Ity_I32 */ get_roundingmode ( void )
3140{
sewardjd01a9632004-11-30 13:18:37 +00003141 return binop( Iop_And32, get_fpround(), mkU32(3) );
sewardj8f3debf2004-09-08 23:42:23 +00003142}
3143
3144
sewardj207557a2004-08-27 12:00:18 +00003145/* --------- Get/set FP register tag bytes. --------- */
3146
sewardj207557a2004-08-27 12:00:18 +00003147/* Given i, and some expression e, generate 'ST_TAG(i) = e'. */
3148
3149static void put_ST_TAG ( Int i, IRExpr* value )
3150{
sewardj2d3f77c2004-09-22 23:49:09 +00003151 IRArray* descr;
sewardj207557a2004-08-27 12:00:18 +00003152 vassert(typeOfIRExpr(irbb->tyenv, value) == Ity_I8);
sewardjf6dc3ce2004-10-19 01:03:46 +00003153 descr = mkIRArray( OFFB_FPTAGS, Ity_I8, 8 );
sewardj2d3f77c2004-09-22 23:49:09 +00003154 stmt( IRStmt_PutI( descr, get_ftop(), i, value ) );
sewardj207557a2004-08-27 12:00:18 +00003155}
3156
3157/* Given i, generate an expression yielding 'ST_TAG(i)'. This will be
sewardjdb199622004-09-06 23:19:03 +00003158 zero to indicate "Empty" and nonzero to indicate "NonEmpty". */
sewardj207557a2004-08-27 12:00:18 +00003159
3160static IRExpr* get_ST_TAG ( Int i )
3161{
sewardjf6dc3ce2004-10-19 01:03:46 +00003162 IRArray* descr = mkIRArray( OFFB_FPTAGS, Ity_I8, 8 );
sewardj2d3f77c2004-09-22 23:49:09 +00003163 return IRExpr_GetI( descr, get_ftop(), i );
sewardj207557a2004-08-27 12:00:18 +00003164}
3165
3166
3167/* --------- Get/set FP registers. --------- */
3168
sewardj2d3f77c2004-09-22 23:49:09 +00003169/* Given i, and some expression e, emit 'ST(i) = e' and set the
3170 register's tag to indicate the register is full. The previous
3171 state of the register is not checked. */
sewardj207557a2004-08-27 12:00:18 +00003172
3173static void put_ST_UNCHECKED ( Int i, IRExpr* value )
sewardjd1725d12004-08-12 20:46:53 +00003174{
sewardj2d3f77c2004-09-22 23:49:09 +00003175 IRArray* descr;
sewardjdb199622004-09-06 23:19:03 +00003176 vassert(typeOfIRExpr(irbb->tyenv, value) == Ity_F64);
sewardjf6dc3ce2004-10-19 01:03:46 +00003177 descr = mkIRArray( OFFB_FPREGS, Ity_F64, 8 );
sewardj2d3f77c2004-09-22 23:49:09 +00003178 stmt( IRStmt_PutI( descr, get_ftop(), i, value ) );
sewardj207557a2004-08-27 12:00:18 +00003179 /* Mark the register as in-use. */
3180 put_ST_TAG(i, mkU8(1));
sewardjd1725d12004-08-12 20:46:53 +00003181}
3182
sewardj207557a2004-08-27 12:00:18 +00003183/* Given i, and some expression e, emit
3184 ST(i) = is_full(i) ? NaN : e
3185 and set the tag accordingly.
3186*/
3187
3188static void put_ST ( Int i, IRExpr* value )
3189{
3190 put_ST_UNCHECKED( i,
sewardjdb199622004-09-06 23:19:03 +00003191 IRExpr_Mux0X( get_ST_TAG(i),
3192 /* 0 means empty */
3193 value,
3194 /* non-0 means full */
sewardj17442fe2004-09-20 14:54:28 +00003195 mkQNaN64()
sewardj207557a2004-08-27 12:00:18 +00003196 )
3197 );
3198}
3199
3200
sewardjd1725d12004-08-12 20:46:53 +00003201/* Given i, generate an expression yielding 'ST(i)'. */
3202
sewardj207557a2004-08-27 12:00:18 +00003203static IRExpr* get_ST_UNCHECKED ( Int i )
sewardjd1725d12004-08-12 20:46:53 +00003204{
sewardjf6dc3ce2004-10-19 01:03:46 +00003205 IRArray* descr = mkIRArray( OFFB_FPREGS, Ity_F64, 8 );
sewardj2d3f77c2004-09-22 23:49:09 +00003206 return IRExpr_GetI( descr, get_ftop(), i );
sewardjd1725d12004-08-12 20:46:53 +00003207}
3208
sewardjc4be80c2004-09-10 16:17:45 +00003209
sewardj207557a2004-08-27 12:00:18 +00003210/* Given i, generate an expression yielding
3211 is_full(i) ? ST(i) : NaN
3212*/
3213
3214static IRExpr* get_ST ( Int i )
3215{
3216 return
3217 IRExpr_Mux0X( get_ST_TAG(i),
3218 /* 0 means empty */
sewardj17442fe2004-09-20 14:54:28 +00003219 mkQNaN64(),
sewardj207557a2004-08-27 12:00:18 +00003220 /* non-0 means full */
3221 get_ST_UNCHECKED(i));
3222}
3223
3224
sewardjd1725d12004-08-12 20:46:53 +00003225/* Adjust FTOP downwards by one register. */
3226
sewardj207557a2004-08-27 12:00:18 +00003227static void fp_push ( void )
sewardjd1725d12004-08-12 20:46:53 +00003228{
sewardj2d3f77c2004-09-22 23:49:09 +00003229 put_ftop( binop(Iop_Sub32, get_ftop(), mkU32(1)) );
sewardjd1725d12004-08-12 20:46:53 +00003230}
3231
sewardj207557a2004-08-27 12:00:18 +00003232/* Adjust FTOP upwards by one register, and mark the vacated register
3233 as empty. */
sewardja58ea662004-08-15 03:12:41 +00003234
sewardj207557a2004-08-27 12:00:18 +00003235static void fp_pop ( void )
sewardja58ea662004-08-15 03:12:41 +00003236{
sewardjdb199622004-09-06 23:19:03 +00003237 put_ST_TAG(0, mkU8(0));
sewardj2d3f77c2004-09-22 23:49:09 +00003238 put_ftop( binop(Iop_Add32, get_ftop(), mkU32(1)) );
sewardja58ea662004-08-15 03:12:41 +00003239}
3240
sewardj3f61ddb2004-10-16 20:51:05 +00003241/* Clear the C2 bit of the FPU status register, for
3242 sin/cos/tan/sincos. */
3243
3244static void clear_C2 ( void )
3245{
sewardj67e002d2004-12-02 18:16:33 +00003246 put_C3210( binop(Iop_And32, get_C3210(), mkU32(~X86G_FC_MASK_C2)) );
sewardj3f61ddb2004-10-16 20:51:05 +00003247}
3248
sewardjd24931d2005-03-20 12:51:39 +00003249/* Invent a plausible-looking FPU status word value:
3250 ((ftop & 7) << 11) | (c3210 & 0x4700)
3251 */
3252static IRExpr* get_FPU_sw ( void )
3253{
3254 return
3255 unop(Iop_32to16,
3256 binop(Iop_Or32,
3257 binop(Iop_Shl32,
3258 binop(Iop_And32, get_ftop(), mkU32(7)),
3259 mkU8(11)),
3260 binop(Iop_And32, get_C3210(), mkU32(0x4700))
3261 ));
3262}
3263
sewardj3f61ddb2004-10-16 20:51:05 +00003264
sewardj207557a2004-08-27 12:00:18 +00003265/* ------------------------------------------------------- */
3266/* Given all that stack-mangling junk, we can now go ahead
3267 and describe FP instructions.
3268*/
3269
sewardj3fd5e572004-09-09 22:43:51 +00003270/* ST(0) = ST(0) `op` mem64/32(addr)
sewardj207557a2004-08-27 12:00:18 +00003271 Need to check ST(0)'s tag on read, but not on write.
3272*/
sewardja58ea662004-08-15 03:12:41 +00003273static
sewardj2d49b432005-02-01 00:37:06 +00003274void fp_do_op_mem_ST_0 ( IRTemp addr, HChar* op_txt, HChar* dis_buf,
sewardja58ea662004-08-15 03:12:41 +00003275 IROp op, Bool dbl )
3276{
sewardj33dd31b2005-01-08 18:17:32 +00003277 DIP("f%s%c %s\n", op_txt, dbl?'l':'s', dis_buf);
sewardja58ea662004-08-15 03:12:41 +00003278 if (dbl) {
sewardj3fd5e572004-09-09 22:43:51 +00003279 put_ST_UNCHECKED(0,
3280 binop( op,
3281 get_ST(0),
3282 loadLE(Ity_F64,mkexpr(addr))
3283 ));
sewardja58ea662004-08-15 03:12:41 +00003284 } else {
sewardj3fd5e572004-09-09 22:43:51 +00003285 put_ST_UNCHECKED(0,
3286 binop( op,
3287 get_ST(0),
3288 unop(Iop_F32toF64, loadLE(Ity_F32,mkexpr(addr)))
3289 ));
3290 }
3291}
3292
3293
3294/* ST(0) = mem64/32(addr) `op` ST(0)
3295 Need to check ST(0)'s tag on read, but not on write.
3296*/
3297static
sewardj2d49b432005-02-01 00:37:06 +00003298void fp_do_oprev_mem_ST_0 ( IRTemp addr, HChar* op_txt, HChar* dis_buf,
sewardj883b00b2004-09-11 09:30:24 +00003299 IROp op, Bool dbl )
sewardj3fd5e572004-09-09 22:43:51 +00003300{
sewardj33dd31b2005-01-08 18:17:32 +00003301 DIP("f%s%c %s\n", op_txt, dbl?'l':'s', dis_buf);
sewardj3fd5e572004-09-09 22:43:51 +00003302 if (dbl) {
3303 put_ST_UNCHECKED(0,
3304 binop( op,
3305 loadLE(Ity_F64,mkexpr(addr)),
3306 get_ST(0)
3307 ));
3308 } else {
3309 put_ST_UNCHECKED(0,
3310 binop( op,
3311 unop(Iop_F32toF64, loadLE(Ity_F32,mkexpr(addr))),
3312 get_ST(0)
3313 ));
sewardja58ea662004-08-15 03:12:41 +00003314 }
3315}
3316
sewardjd1725d12004-08-12 20:46:53 +00003317
sewardjdb199622004-09-06 23:19:03 +00003318/* ST(dst) = ST(dst) `op` ST(src).
3319 Check dst and src tags when reading but not on write.
3320*/
3321static
sewardj2d49b432005-02-01 00:37:06 +00003322void fp_do_op_ST_ST ( HChar* op_txt, IROp op, UInt st_src, UInt st_dst,
sewardjbdc7d212004-09-09 02:46:40 +00003323 Bool pop_after )
sewardjdb199622004-09-06 23:19:03 +00003324{
sewardj2d49b432005-02-01 00:37:06 +00003325 DIP("f%s%s st(%d), st(%d)\n", op_txt, pop_after?"p":"",
3326 (Int)st_src, (Int)st_dst );
sewardjdb199622004-09-06 23:19:03 +00003327 put_ST_UNCHECKED(
3328 st_dst,
3329 binop(op, get_ST(st_dst), get_ST(st_src) )
3330 );
sewardjbdc7d212004-09-09 02:46:40 +00003331 if (pop_after)
3332 fp_pop();
3333}
3334
3335/* ST(dst) = ST(src) `op` ST(dst).
3336 Check dst and src tags when reading but not on write.
3337*/
3338static
sewardj2d49b432005-02-01 00:37:06 +00003339void fp_do_oprev_ST_ST ( HChar* op_txt, IROp op, UInt st_src, UInt st_dst,
sewardj883b00b2004-09-11 09:30:24 +00003340 Bool pop_after )
sewardjbdc7d212004-09-09 02:46:40 +00003341{
sewardj2d49b432005-02-01 00:37:06 +00003342 DIP("f%s%s st(%d), st(%d)\n", op_txt, pop_after?"p":"",
3343 (Int)st_src, (Int)st_dst );
sewardjbdc7d212004-09-09 02:46:40 +00003344 put_ST_UNCHECKED(
3345 st_dst,
3346 binop(op, get_ST(st_src), get_ST(st_dst) )
3347 );
3348 if (pop_after)
3349 fp_pop();
sewardjdb199622004-09-06 23:19:03 +00003350}
3351
sewardj8308aad2004-09-12 11:09:54 +00003352/* %eflags(Z,P,C) = UCOMI( st(0), st(i) ) */
3353static void fp_do_ucomi_ST0_STi ( UInt i, Bool pop_after )
3354{
sewardj2d49b432005-02-01 00:37:06 +00003355 DIP("fucomi%s %%st(0),%%st(%d)\n", pop_after ? "p" : "", (Int)i );
sewardj8308aad2004-09-12 11:09:54 +00003356 /* This is a bit of a hack (and isn't really right). It sets
3357 Z,P,C,O correctly, but forces A and S to zero, whereas the Intel
3358 documentation implies A and S are unchanged.
3359 */
sewardjfeeb8a82004-11-30 12:30:11 +00003360 /* It's also fishy in that it is used both for COMIP and
3361 UCOMIP, and they aren't the same (although similar). */
sewardj2a9ad022004-11-25 02:46:58 +00003362 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
sewardj2a2ba8b2004-11-08 13:14:06 +00003363 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
3364 stmt( IRStmt_Put( OFFB_CC_DEP1,
sewardj8308aad2004-09-12 11:09:54 +00003365 binop( Iop_And32,
3366 binop(Iop_CmpF64, get_ST(0), get_ST(i)),
3367 mkU32(0x45)
3368 )));
sewardja3b7e3a2005-04-05 01:54:19 +00003369 /* Set NDEP even though it isn't used. This makes redundant-PUT
3370 elimination of previous stores to this field work better. */
3371 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardj8308aad2004-09-12 11:09:54 +00003372 if (pop_after)
3373 fp_pop();
3374}
3375
sewardjdb199622004-09-06 23:19:03 +00003376
sewardjd1725d12004-08-12 20:46:53 +00003377static
sewardj52d04912005-07-03 00:52:48 +00003378UInt dis_FPU ( Bool* decode_ok, UChar sorb, Int delta )
sewardjd1725d12004-08-12 20:46:53 +00003379{
sewardja58ea662004-08-15 03:12:41 +00003380 Int len;
3381 UInt r_src, r_dst;
sewardjc9a43662004-11-30 18:51:59 +00003382 HChar dis_buf[50];
sewardj89cd0932004-09-08 18:23:25 +00003383 IRTemp t1, t2;
sewardjd1725d12004-08-12 20:46:53 +00003384
3385 /* On entry, delta points at the second byte of the insn (the modrm
3386 byte).*/
3387 UChar first_opcode = getIByte(delta-1);
3388 UChar modrm = getIByte(delta+0);
3389
3390 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xD8 opcodes +-+-+-+-+-+-+-+ */
3391
3392 if (first_opcode == 0xD8) {
sewardjdb199622004-09-06 23:19:03 +00003393 if (modrm < 0xC0) {
sewardj89cd0932004-09-08 18:23:25 +00003394
3395 /* bits 5,4,3 are an opcode extension, and the modRM also
3396 specifies an address. */
3397 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
3398 delta += len;
3399
3400 switch (gregOfRM(modrm)) {
3401
sewardj3fd5e572004-09-09 22:43:51 +00003402 case 0: /* FADD single-real */
3403 fp_do_op_mem_ST_0 ( addr, "add", dis_buf, Iop_AddF64, False );
3404 break;
3405
sewardj89cd0932004-09-08 18:23:25 +00003406 case 1: /* FMUL single-real */
3407 fp_do_op_mem_ST_0 ( addr, "mul", dis_buf, Iop_MulF64, False );
3408 break;
3409
sewardj7ca37d92004-10-25 02:58:30 +00003410 case 2: /* FCOM single-real */
3411 DIP("fcoms %s\n", dis_buf);
3412 /* This forces C1 to zero, which isn't right. */
3413 put_C3210(
3414 binop( Iop_And32,
3415 binop(Iop_Shl32,
3416 binop(Iop_CmpF64,
3417 get_ST(0),
3418 unop(Iop_F32toF64,
3419 loadLE(Ity_F32,mkexpr(addr)))),
3420 mkU8(8)),
3421 mkU32(0x4500)
3422 ));
3423 break;
3424
3425 case 3: /* FCOMP single-real */
sewardje166ed02004-10-25 02:27:01 +00003426 DIP("fcomps %s\n", dis_buf);
3427 /* This forces C1 to zero, which isn't right. */
3428 put_C3210(
3429 binop( Iop_And32,
3430 binop(Iop_Shl32,
3431 binop(Iop_CmpF64,
3432 get_ST(0),
3433 unop(Iop_F32toF64,
3434 loadLE(Ity_F32,mkexpr(addr)))),
3435 mkU8(8)),
3436 mkU32(0x4500)
3437 ));
3438 fp_pop();
3439 break;
3440
sewardj588ea762004-09-10 18:56:32 +00003441 case 4: /* FSUB single-real */
3442 fp_do_op_mem_ST_0 ( addr, "sub", dis_buf, Iop_SubF64, False );
3443 break;
3444
3445 case 5: /* FSUBR single-real */
3446 fp_do_oprev_mem_ST_0 ( addr, "subr", dis_buf, Iop_SubF64, False );
3447 break;
3448
sewardjbdc7d212004-09-09 02:46:40 +00003449 case 6: /* FDIV single-real */
3450 fp_do_op_mem_ST_0 ( addr, "div", dis_buf, Iop_DivF64, False );
3451 break;
3452
sewardj8308aad2004-09-12 11:09:54 +00003453 case 7: /* FDIVR single-real */
3454 fp_do_oprev_mem_ST_0 ( addr, "divr", dis_buf, Iop_DivF64, False );
3455 break;
3456
sewardj89cd0932004-09-08 18:23:25 +00003457 default:
3458 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
3459 vex_printf("first_opcode == 0xD8\n");
3460 goto decode_fail;
3461 }
sewardjdb199622004-09-06 23:19:03 +00003462 } else {
3463 delta++;
3464 switch (modrm) {
sewardj89cd0932004-09-08 18:23:25 +00003465
sewardjdb199622004-09-06 23:19:03 +00003466 case 0xC0 ... 0xC7: /* FADD %st(?),%st(0) */
sewardjbdc7d212004-09-09 02:46:40 +00003467 fp_do_op_ST_ST ( "add", Iop_AddF64, modrm - 0xC0, 0, False );
sewardjdb199622004-09-06 23:19:03 +00003468 break;
sewardj89cd0932004-09-08 18:23:25 +00003469
sewardj3fd5e572004-09-09 22:43:51 +00003470 case 0xC8 ... 0xCF: /* FMUL %st(?),%st(0) */
3471 fp_do_op_ST_ST ( "mul", Iop_MulF64, modrm - 0xC8, 0, False );
3472 break;
3473
sewardje166ed02004-10-25 02:27:01 +00003474 /* Dunno if this is right */
3475 case 0xD0 ... 0xD7: /* FCOM %st(?),%st(0) */
3476 r_dst = (UInt)modrm - 0xD0;
sewardj2d49b432005-02-01 00:37:06 +00003477 DIP("fcom %%st(0),%%st(%d)\n", (Int)r_dst);
sewardje166ed02004-10-25 02:27:01 +00003478 /* This forces C1 to zero, which isn't right. */
3479 put_C3210(
3480 binop( Iop_And32,
3481 binop(Iop_Shl32,
3482 binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
3483 mkU8(8)),
3484 mkU32(0x4500)
3485 ));
3486 break;
sewardj2d49b432005-02-01 00:37:06 +00003487
sewardj98169c52004-10-24 13:11:39 +00003488 /* Dunno if this is right */
3489 case 0xD8 ... 0xDF: /* FCOMP %st(?),%st(0) */
3490 r_dst = (UInt)modrm - 0xD8;
sewardj2d49b432005-02-01 00:37:06 +00003491 DIP("fcomp %%st(0),%%st(%d)\n", (Int)r_dst);
sewardj98169c52004-10-24 13:11:39 +00003492 /* This forces C1 to zero, which isn't right. */
3493 put_C3210(
3494 binop( Iop_And32,
3495 binop(Iop_Shl32,
3496 binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
3497 mkU8(8)),
3498 mkU32(0x4500)
3499 ));
3500 fp_pop();
3501 break;
sewardj2d49b432005-02-01 00:37:06 +00003502
sewardj89cd0932004-09-08 18:23:25 +00003503 case 0xE0 ... 0xE7: /* FSUB %st(?),%st(0) */
sewardjbdc7d212004-09-09 02:46:40 +00003504 fp_do_op_ST_ST ( "sub", Iop_SubF64, modrm - 0xE0, 0, False );
sewardj89cd0932004-09-08 18:23:25 +00003505 break;
3506
sewardj8308aad2004-09-12 11:09:54 +00003507 case 0xE8 ... 0xEF: /* FSUBR %st(?),%st(0) */
3508 fp_do_oprev_ST_ST ( "subr", Iop_SubF64, modrm - 0xE8, 0, False );
3509 break;
3510
sewardj3fd5e572004-09-09 22:43:51 +00003511 case 0xF0 ... 0xF7: /* FDIV %st(?),%st(0) */
3512 fp_do_op_ST_ST ( "div", Iop_DivF64, modrm - 0xF0, 0, False );
3513 break;
3514
3515 case 0xF8 ... 0xFF: /* FDIVR %st(?),%st(0) */
3516 fp_do_oprev_ST_ST ( "divr", Iop_DivF64, modrm - 0xF8, 0, False );
3517 break;
3518
sewardjdb199622004-09-06 23:19:03 +00003519 default:
3520 goto decode_fail;
3521 }
3522 }
sewardjd1725d12004-08-12 20:46:53 +00003523 }
3524
3525 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xD9 opcodes +-+-+-+-+-+-+-+ */
3526 else
3527 if (first_opcode == 0xD9) {
sewardjbb53f8c2004-08-14 11:50:01 +00003528 if (modrm < 0xC0) {
sewardj89cd0932004-09-08 18:23:25 +00003529
3530 /* bits 5,4,3 are an opcode extension, and the modRM also
sewardjfeeb8a82004-11-30 12:30:11 +00003531 specifies an address. */
sewardj89cd0932004-09-08 18:23:25 +00003532 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
3533 delta += len;
3534
3535 switch (gregOfRM(modrm)) {
3536
3537 case 0: /* FLD single-real */
sewardj33dd31b2005-01-08 18:17:32 +00003538 DIP("flds %s\n", dis_buf);
sewardj89cd0932004-09-08 18:23:25 +00003539 fp_push();
3540 put_ST(0, unop(Iop_F32toF64,
sewardj8f3debf2004-09-08 23:42:23 +00003541 loadLE(Ity_F32, mkexpr(addr))));
sewardj89cd0932004-09-08 18:23:25 +00003542 break;
3543
sewardj588ea762004-09-10 18:56:32 +00003544 case 2: /* FST single-real */
sewardj33dd31b2005-01-08 18:17:32 +00003545 DIP("fsts %s\n", dis_buf);
sewardj3bca9062004-12-04 14:36:09 +00003546 storeLE(mkexpr(addr),
3547 binop(Iop_F64toF32, get_roundingmode(), get_ST(0)));
sewardj588ea762004-09-10 18:56:32 +00003548 break;
3549
sewardj89cd0932004-09-08 18:23:25 +00003550 case 3: /* FSTP single-real */
sewardj33dd31b2005-01-08 18:17:32 +00003551 DIP("fstps %s\n", dis_buf);
sewardj3bca9062004-12-04 14:36:09 +00003552 storeLE(mkexpr(addr),
3553 binop(Iop_F64toF32, get_roundingmode(), get_ST(0)));
sewardj5bd4d162004-11-10 13:02:48 +00003554 fp_pop();
sewardj89cd0932004-09-08 18:23:25 +00003555 break;
3556
sewardjd24931d2005-03-20 12:51:39 +00003557 case 4: { /* FLDENV m28 */
sewardj7df596b2004-12-06 14:29:12 +00003558 /* Uses dirty helper:
sewardj4017a3b2005-06-13 12:17:27 +00003559 VexEmWarn x86g_do_FLDENV ( VexGuestX86State*, HWord ) */
sewardj7df596b2004-12-06 14:29:12 +00003560 IRTemp ew = newTemp(Ity_I32);
3561 IRDirty* d = unsafeIRDirty_0_N (
3562 0/*regparms*/,
3563 "x86g_dirtyhelper_FLDENV",
3564 &x86g_dirtyhelper_FLDENV,
3565 mkIRExprVec_1( mkexpr(addr) )
3566 );
3567 d->needsBBP = True;
3568 d->tmp = ew;
3569 /* declare we're reading memory */
3570 d->mFx = Ifx_Read;
3571 d->mAddr = mkexpr(addr);
3572 d->mSize = 28;
3573
3574 /* declare we're writing guest state */
sewardj46813fc2005-06-13 12:33:36 +00003575 d->nFxState = 4;
sewardj7df596b2004-12-06 14:29:12 +00003576
3577 d->fxState[0].fx = Ifx_Write;
3578 d->fxState[0].offset = OFFB_FTOP;
3579 d->fxState[0].size = sizeof(UInt);
3580
3581 d->fxState[1].fx = Ifx_Write;
sewardj46813fc2005-06-13 12:33:36 +00003582 d->fxState[1].offset = OFFB_FPTAGS;
3583 d->fxState[1].size = 8 * sizeof(UChar);
sewardj7df596b2004-12-06 14:29:12 +00003584
3585 d->fxState[2].fx = Ifx_Write;
sewardj46813fc2005-06-13 12:33:36 +00003586 d->fxState[2].offset = OFFB_FPROUND;
3587 d->fxState[2].size = sizeof(UInt);
sewardj7df596b2004-12-06 14:29:12 +00003588
3589 d->fxState[3].fx = Ifx_Write;
sewardj46813fc2005-06-13 12:33:36 +00003590 d->fxState[3].offset = OFFB_FC3210;
sewardj7df596b2004-12-06 14:29:12 +00003591 d->fxState[3].size = sizeof(UInt);
3592
sewardj7df596b2004-12-06 14:29:12 +00003593 stmt( IRStmt_Dirty(d) );
3594
3595 /* ew contains any emulation warning we may need to
3596 issue. If needed, side-exit to the next insn,
3597 reporting the warning, so that Valgrind's dispatcher
3598 sees the warning. */
3599 put_emwarn( mkexpr(ew) );
3600 stmt(
3601 IRStmt_Exit(
3602 binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
3603 Ijk_EmWarn,
sewardj9e6491a2005-07-02 19:24:10 +00003604 IRConst_U32( ((Addr32)guest_EIP_bbstart)+delta)
sewardj7df596b2004-12-06 14:29:12 +00003605 )
3606 );
3607
sewardj33dd31b2005-01-08 18:17:32 +00003608 DIP("fldenv %s\n", dis_buf);
sewardj7df596b2004-12-06 14:29:12 +00003609 break;
3610 }
3611
sewardj893aada2004-11-29 19:57:54 +00003612 case 5: {/* FLDCW */
3613 /* The only thing we observe in the control word is the
sewardjd01a9632004-11-30 13:18:37 +00003614 rounding mode. Therefore, pass the 16-bit value
3615 (x87 native-format control word) to a clean helper,
3616 getting back a 64-bit value, the lower half of which
3617 is the FPROUND value to store, and the upper half of
3618 which is the emulation-warning token which may be
3619 generated.
sewardj893aada2004-11-29 19:57:54 +00003620 */
3621 /* ULong x86h_check_fldcw ( UInt ); */
3622 IRTemp t64 = newTemp(Ity_I64);
3623 IRTemp ew = newTemp(Ity_I32);
sewardj33dd31b2005-01-08 18:17:32 +00003624 DIP("fldcw %s\n", dis_buf);
sewardj893aada2004-11-29 19:57:54 +00003625 assign( t64, mkIRExprCCall(
3626 Ity_I64, 0/*regparms*/,
sewardj3bd6f3e2004-12-13 10:48:19 +00003627 "x86g_check_fldcw",
3628 &x86g_check_fldcw,
sewardj893aada2004-11-29 19:57:54 +00003629 mkIRExprVec_1(
3630 unop( Iop_16Uto32,
3631 loadLE(Ity_I16, mkexpr(addr)))
3632 )
3633 )
3634 );
3635
sewardjd01a9632004-11-30 13:18:37 +00003636 put_fpround( unop(Iop_64to32, mkexpr(t64)) );
sewardj893aada2004-11-29 19:57:54 +00003637 assign( ew, unop(Iop_64HIto32, mkexpr(t64) ) );
3638 put_emwarn( mkexpr(ew) );
3639 /* Finally, if an emulation warning was reported,
3640 side-exit to the next insn, reporting the warning,
3641 so that Valgrind's dispatcher sees the warning. */
3642 stmt(
3643 IRStmt_Exit(
3644 binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
3645 Ijk_EmWarn,
sewardj9e6491a2005-07-02 19:24:10 +00003646 IRConst_U32( ((Addr32)guest_EIP_bbstart)+delta)
sewardj893aada2004-11-29 19:57:54 +00003647 )
3648 );
sewardj89cd0932004-09-08 18:23:25 +00003649 break;
sewardj893aada2004-11-29 19:57:54 +00003650 }
sewardj89cd0932004-09-08 18:23:25 +00003651
sewardj7df596b2004-12-06 14:29:12 +00003652 case 6: { /* FNSTENV m28 */
3653 /* Uses dirty helper:
sewardj4017a3b2005-06-13 12:17:27 +00003654 void x86g_do_FSTENV ( VexGuestX86State*, HWord ) */
sewardj7df596b2004-12-06 14:29:12 +00003655 IRDirty* d = unsafeIRDirty_0_N (
3656 0/*regparms*/,
3657 "x86g_dirtyhelper_FSTENV",
3658 &x86g_dirtyhelper_FSTENV,
3659 mkIRExprVec_1( mkexpr(addr) )
3660 );
3661 d->needsBBP = True;
3662 /* declare we're writing memory */
3663 d->mFx = Ifx_Write;
3664 d->mAddr = mkexpr(addr);
3665 d->mSize = 28;
3666
3667 /* declare we're reading guest state */
3668 d->nFxState = 4;
3669
3670 d->fxState[0].fx = Ifx_Read;
3671 d->fxState[0].offset = OFFB_FTOP;
3672 d->fxState[0].size = sizeof(UInt);
3673
3674 d->fxState[1].fx = Ifx_Read;
3675 d->fxState[1].offset = OFFB_FPTAGS;
3676 d->fxState[1].size = 8 * sizeof(UChar);
3677
3678 d->fxState[2].fx = Ifx_Read;
3679 d->fxState[2].offset = OFFB_FPROUND;
3680 d->fxState[2].size = sizeof(UInt);
3681
3682 d->fxState[3].fx = Ifx_Read;
3683 d->fxState[3].offset = OFFB_FC3210;
3684 d->fxState[3].size = sizeof(UInt);
3685
3686 stmt( IRStmt_Dirty(d) );
3687
sewardj33dd31b2005-01-08 18:17:32 +00003688 DIP("fnstenv %s\n", dis_buf);
sewardj7df596b2004-12-06 14:29:12 +00003689 break;
3690 }
3691
sewardj588ea762004-09-10 18:56:32 +00003692 case 7: /* FNSTCW */
sewardj893aada2004-11-29 19:57:54 +00003693 /* Fake up a native x87 FPU control word. The only
sewardjd01a9632004-11-30 13:18:37 +00003694 thing it depends on is FPROUND[1:0], so call a clean
sewardj893aada2004-11-29 19:57:54 +00003695 helper to cook it up. */
sewardjd01a9632004-11-30 13:18:37 +00003696 /* UInt x86h_create_fpucw ( UInt fpround ) */
sewardj33dd31b2005-01-08 18:17:32 +00003697 DIP("fnstcw %s\n", dis_buf);
sewardj893aada2004-11-29 19:57:54 +00003698 storeLE(
3699 mkexpr(addr),
3700 unop( Iop_32to16,
3701 mkIRExprCCall(
3702 Ity_I32, 0/*regp*/,
sewardj3bd6f3e2004-12-13 10:48:19 +00003703 "x86g_create_fpucw", &x86g_create_fpucw,
sewardjd01a9632004-11-30 13:18:37 +00003704 mkIRExprVec_1( get_fpround() )
sewardj893aada2004-11-29 19:57:54 +00003705 )
3706 )
3707 );
sewardj89cd0932004-09-08 18:23:25 +00003708 break;
3709
3710 default:
3711 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
3712 vex_printf("first_opcode == 0xD9\n");
3713 goto decode_fail;
3714 }
3715
sewardjbb53f8c2004-08-14 11:50:01 +00003716 } else {
3717 delta++;
3718 switch (modrm) {
sewardj89cd0932004-09-08 18:23:25 +00003719
sewardjbb53f8c2004-08-14 11:50:01 +00003720 case 0xC0 ... 0xC7: /* FLD %st(?) */
sewardja58ea662004-08-15 03:12:41 +00003721 r_src = (UInt)modrm - 0xC0;
sewardj2d49b432005-02-01 00:37:06 +00003722 DIP("fld %%st(%d)\n", (Int)r_src);
sewardj5bd4d162004-11-10 13:02:48 +00003723 t1 = newTemp(Ity_F64);
3724 assign(t1, get_ST(r_src));
3725 fp_push();
3726 put_ST(0, mkexpr(t1));
sewardjbb53f8c2004-08-14 11:50:01 +00003727 break;
3728
sewardj89cd0932004-09-08 18:23:25 +00003729 case 0xC8 ... 0xCF: /* FXCH %st(?) */
3730 r_src = (UInt)modrm - 0xC8;
sewardj2d49b432005-02-01 00:37:06 +00003731 DIP("fxch %%st(%d)\n", (Int)r_src);
sewardj89cd0932004-09-08 18:23:25 +00003732 t1 = newTemp(Ity_F64);
3733 t2 = newTemp(Ity_F64);
3734 assign(t1, get_ST(0));
3735 assign(t2, get_ST(r_src));
3736 put_ST_UNCHECKED(0, mkexpr(t2));
3737 put_ST_UNCHECKED(r_src, mkexpr(t1));
3738 break;
3739
sewardjcfded9a2004-09-09 11:44:16 +00003740 case 0xE0: /* FCHS */
3741 DIP("fchs\n");
3742 put_ST_UNCHECKED(0, unop(Iop_NegF64, get_ST(0)));
3743 break;
3744
sewardj883b00b2004-09-11 09:30:24 +00003745 case 0xE1: /* FABS */
3746 DIP("fabs\n");
3747 put_ST_UNCHECKED(0, unop(Iop_AbsF64, get_ST(0)));
3748 break;
sewardjc4be80c2004-09-10 16:17:45 +00003749
sewardj1c318772005-03-19 14:27:04 +00003750 case 0xE4: /* FTST */
3751 DIP("ftst\n");
3752 /* This forces C1 to zero, which isn't right. */
3753 /* Well, in fact the Intel docs say (bizarrely): "C1 is
3754 set to 0 if stack underflow occurred; otherwise, set
3755 to 0" which is pretty nonsensical. I guess it's a
3756 typo. */
3757 put_C3210(
3758 binop( Iop_And32,
3759 binop(Iop_Shl32,
3760 binop(Iop_CmpF64,
3761 get_ST(0),
3762 IRExpr_Const(IRConst_F64i(0x0ULL))),
3763 mkU8(8)),
3764 mkU32(0x4500)
3765 ));
3766 break;
3767
sewardj883b00b2004-09-11 09:30:24 +00003768 case 0xE5: { /* FXAM */
3769 /* This is an interesting one. It examines %st(0),
3770 regardless of whether the tag says it's empty or not.
3771 Here, just pass both the tag (in our format) and the
3772 value (as a double, actually a ULong) to a helper
3773 function. */
sewardjf9655262004-10-31 20:02:16 +00003774 IRExpr** args
3775 = mkIRExprVec_2( unop(Iop_8Uto32, get_ST_TAG(0)),
3776 unop(Iop_ReinterpF64asI64,
3777 get_ST_UNCHECKED(0)) );
3778 put_C3210(mkIRExprCCall(
sewardj8ea867b2004-10-30 19:03:02 +00003779 Ity_I32,
sewardjf9655262004-10-31 20:02:16 +00003780 0/*regparm*/,
sewardj2a9ad022004-11-25 02:46:58 +00003781 "x86g_calculate_FXAM", &x86g_calculate_FXAM,
sewardj8ea867b2004-10-30 19:03:02 +00003782 args
3783 ));
sewardj33dd31b2005-01-08 18:17:32 +00003784 DIP("fxam\n");
sewardj883b00b2004-09-11 09:30:24 +00003785 break;
3786 }
3787
3788 case 0xE8: /* FLD1 */
sewardj33dd31b2005-01-08 18:17:32 +00003789 DIP("fld1\n");
sewardjce646f22004-08-31 23:55:54 +00003790 fp_push();
sewardj9c323762005-01-10 16:49:19 +00003791 /* put_ST(0, IRExpr_Const(IRConst_F64(1.0))); */
3792 put_ST(0, IRExpr_Const(IRConst_F64i(0x3ff0000000000000ULL)));
sewardjce646f22004-08-31 23:55:54 +00003793 break;
3794
sewardj37158712004-10-15 21:23:12 +00003795 case 0xE9: /* FLDL2T */
sewardj33dd31b2005-01-08 18:17:32 +00003796 DIP("fldl2t\n");
sewardj37158712004-10-15 21:23:12 +00003797 fp_push();
sewardj9c323762005-01-10 16:49:19 +00003798 /* put_ST(0, IRExpr_Const(IRConst_F64(3.32192809488736234781))); */
3799 put_ST(0, IRExpr_Const(IRConst_F64i(0x400a934f0979a371ULL)));
sewardj37158712004-10-15 21:23:12 +00003800 break;
3801
sewardj8308aad2004-09-12 11:09:54 +00003802 case 0xEA: /* FLDL2E */
sewardj33dd31b2005-01-08 18:17:32 +00003803 DIP("fldl2e\n");
sewardj8308aad2004-09-12 11:09:54 +00003804 fp_push();
sewardj9c323762005-01-10 16:49:19 +00003805 /* put_ST(0, IRExpr_Const(IRConst_F64(1.44269504088896340739))); */
3806 put_ST(0, IRExpr_Const(IRConst_F64i(0x3ff71547652b82feULL)));
sewardj8308aad2004-09-12 11:09:54 +00003807 break;
3808
sewardja0d48d62004-09-20 21:19:03 +00003809 case 0xEB: /* FLDPI */
sewardj33dd31b2005-01-08 18:17:32 +00003810 DIP("fldpi\n");
sewardja0d48d62004-09-20 21:19:03 +00003811 fp_push();
sewardj9c323762005-01-10 16:49:19 +00003812 /* put_ST(0, IRExpr_Const(IRConst_F64(3.14159265358979323851))); */
3813 put_ST(0, IRExpr_Const(IRConst_F64i(0x400921fb54442d18ULL)));
sewardja0d48d62004-09-20 21:19:03 +00003814 break;
3815
sewardjdb199622004-09-06 23:19:03 +00003816 case 0xEC: /* FLDLG2 */
sewardj33dd31b2005-01-08 18:17:32 +00003817 DIP("fldlg2\n");
sewardjdb199622004-09-06 23:19:03 +00003818 fp_push();
sewardj9c323762005-01-10 16:49:19 +00003819 /* put_ST(0, IRExpr_Const(IRConst_F64(0.301029995663981143))); */
3820 put_ST(0, IRExpr_Const(IRConst_F64i(0x3fd34413509f79ffULL)));
sewardjdb199622004-09-06 23:19:03 +00003821 break;
3822
3823 case 0xED: /* FLDLN2 */
sewardj33dd31b2005-01-08 18:17:32 +00003824 DIP("fldln2\n");
sewardjdb199622004-09-06 23:19:03 +00003825 fp_push();
sewardj9c323762005-01-10 16:49:19 +00003826 /* put_ST(0, IRExpr_Const(IRConst_F64(0.69314718055994530942))); */
3827 put_ST(0, IRExpr_Const(IRConst_F64i(0x3fe62e42fefa39efULL)));
sewardjdb199622004-09-06 23:19:03 +00003828 break;
3829
sewardja58ea662004-08-15 03:12:41 +00003830 case 0xEE: /* FLDZ */
sewardj33dd31b2005-01-08 18:17:32 +00003831 DIP("fldz\n");
sewardj207557a2004-08-27 12:00:18 +00003832 fp_push();
sewardj9c323762005-01-10 16:49:19 +00003833 /* put_ST(0, IRExpr_Const(IRConst_F64(0.0))); */
3834 put_ST(0, IRExpr_Const(IRConst_F64i(0x0000000000000000ULL)));
sewardja58ea662004-08-15 03:12:41 +00003835 break;
3836
sewardj06c32a02004-09-12 12:07:34 +00003837 case 0xF0: /* F2XM1 */
3838 DIP("f2xm1\n");
3839 put_ST_UNCHECKED(0, unop(Iop_2xm1F64, get_ST(0)));
3840 break;
3841
sewardj52ace3e2004-09-11 17:10:08 +00003842 case 0xF1: /* FYL2X */
3843 DIP("fyl2x\n");
3844 put_ST_UNCHECKED(1, binop(Iop_Yl2xF64,
3845 get_ST(1), get_ST(0)));
3846 fp_pop();
3847 break;
3848
sewardj99016a72004-10-15 22:09:17 +00003849 case 0xF2: /* FPTAN */
3850 DIP("ftan\n");
3851 put_ST_UNCHECKED(0, unop(Iop_TanF64, get_ST(0)));
3852 fp_push();
3853 put_ST(0, IRExpr_Const(IRConst_F64(1.0)));
sewardj3f61ddb2004-10-16 20:51:05 +00003854 clear_C2(); /* HACK */
sewardj99016a72004-10-15 22:09:17 +00003855 break;
3856
sewardjcfded9a2004-09-09 11:44:16 +00003857 case 0xF3: /* FPATAN */
3858 DIP("fpatan\n");
sewardj52ace3e2004-09-11 17:10:08 +00003859 put_ST_UNCHECKED(1, binop(Iop_AtanF64,
sewardjcfded9a2004-09-09 11:44:16 +00003860 get_ST(1), get_ST(0)));
3861 fp_pop();
3862 break;
3863
sewardj442d0be2004-10-15 22:57:13 +00003864 case 0xF5: { /* FPREM1 -- IEEE compliant */
3865 IRTemp a1 = newTemp(Ity_F64);
3866 IRTemp a2 = newTemp(Ity_F64);
3867 DIP("fprem1\n");
3868 /* Do FPREM1 twice, once to get the remainder, and once
3869 to get the C3210 flag values. */
3870 assign( a1, get_ST(0) );
3871 assign( a2, get_ST(1) );
3872 put_ST_UNCHECKED(0, binop(Iop_PRem1F64,
3873 mkexpr(a1), mkexpr(a2)));
3874 put_C3210( binop(Iop_PRem1C3210F64, mkexpr(a1), mkexpr(a2)) );
3875 break;
3876 }
3877
sewardjfeeb8a82004-11-30 12:30:11 +00003878 case 0xF7: /* FINCSTP */
3879 DIP("fprem\n");
3880 put_ftop( binop(Iop_Add32, get_ftop(), mkU32(1)) );
3881 break;
3882
sewardj46de4072004-09-11 19:23:24 +00003883 case 0xF8: { /* FPREM -- not IEEE compliant */
3884 IRTemp a1 = newTemp(Ity_F64);
3885 IRTemp a2 = newTemp(Ity_F64);
3886 DIP("fprem\n");
3887 /* Do FPREM twice, once to get the remainder, and once
3888 to get the C3210 flag values. */
3889 assign( a1, get_ST(0) );
3890 assign( a2, get_ST(1) );
3891 put_ST_UNCHECKED(0, binop(Iop_PRemF64,
3892 mkexpr(a1), mkexpr(a2)));
3893 put_C3210( binop(Iop_PRemC3210F64, mkexpr(a1), mkexpr(a2)) );
3894 break;
3895 }
3896
sewardj8308aad2004-09-12 11:09:54 +00003897 case 0xF9: /* FYL2XP1 */
3898 DIP("fyl2xp1\n");
3899 put_ST_UNCHECKED(1, binop(Iop_Yl2xp1F64,
3900 get_ST(1), get_ST(0)));
3901 fp_pop();
3902 break;
3903
sewardjc4be80c2004-09-10 16:17:45 +00003904 case 0xFA: /* FSQRT */
3905 DIP("fsqrt\n");
3906 put_ST_UNCHECKED(0, unop(Iop_SqrtF64, get_ST(0)));
3907 break;
3908
sewardj519d66f2004-12-15 11:57:58 +00003909 case 0xFB: { /* FSINCOS */
3910 IRTemp a1 = newTemp(Ity_F64);
3911 assign( a1, get_ST(0) );
3912 DIP("fsincos\n");
3913 put_ST_UNCHECKED(0, unop(Iop_SinF64, mkexpr(a1)));
3914 fp_push();
3915 put_ST(0, unop(Iop_CosF64, mkexpr(a1)));
sewardj88a69242005-04-01 20:19:20 +00003916 clear_C2(); /* HACK */
sewardj519d66f2004-12-15 11:57:58 +00003917 break;
3918 }
3919
sewardje6709112004-09-10 18:37:18 +00003920 case 0xFC: /* FRNDINT */
3921 DIP("frndint\n");
3922 put_ST_UNCHECKED(0,
3923 binop(Iop_RoundF64, get_roundingmode(), get_ST(0)) );
3924 break;
3925
sewardj06c32a02004-09-12 12:07:34 +00003926 case 0xFD: /* FSCALE */
3927 DIP("fscale\n");
3928 put_ST_UNCHECKED(0, binop(Iop_ScaleF64,
3929 get_ST(0), get_ST(1)));
3930 break;
3931
sewardjcfded9a2004-09-09 11:44:16 +00003932 case 0xFE: /* FSIN */
3933 DIP("fsin\n");
3934 put_ST_UNCHECKED(0, unop(Iop_SinF64, get_ST(0)));
sewardj3f61ddb2004-10-16 20:51:05 +00003935 clear_C2(); /* HACK */
sewardjcfded9a2004-09-09 11:44:16 +00003936 break;
3937
3938 case 0xFF: /* FCOS */
3939 DIP("fcos\n");
3940 put_ST_UNCHECKED(0, unop(Iop_CosF64, get_ST(0)));
sewardj3f61ddb2004-10-16 20:51:05 +00003941 clear_C2(); /* HACK */
sewardjcfded9a2004-09-09 11:44:16 +00003942 break;
3943
sewardjbb53f8c2004-08-14 11:50:01 +00003944 default:
3945 goto decode_fail;
3946 }
3947 }
sewardjd1725d12004-08-12 20:46:53 +00003948 }
3949
3950 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDA opcodes +-+-+-+-+-+-+-+ */
3951 else
3952 if (first_opcode == 0xDA) {
sewardjbb53f8c2004-08-14 11:50:01 +00003953
3954 if (modrm < 0xC0) {
3955
sewardjfeeb8a82004-11-30 12:30:11 +00003956 /* bits 5,4,3 are an opcode extension, and the modRM also
sewardjbb53f8c2004-08-14 11:50:01 +00003957 specifies an address. */
sewardjce646f22004-08-31 23:55:54 +00003958 IROp fop;
sewardjbb53f8c2004-08-14 11:50:01 +00003959 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
3960 delta += len;
sewardjbb53f8c2004-08-14 11:50:01 +00003961 switch (gregOfRM(modrm)) {
sewardjce646f22004-08-31 23:55:54 +00003962
sewardjdb199622004-09-06 23:19:03 +00003963 case 0: /* FIADD m32int */ /* ST(0) += m32int */
sewardj33dd31b2005-01-08 18:17:32 +00003964 DIP("fiaddl %s\n", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00003965 fop = Iop_AddF64;
3966 goto do_fop_m32;
sewardjdb199622004-09-06 23:19:03 +00003967
sewardj207557a2004-08-27 12:00:18 +00003968 case 1: /* FIMUL m32int */ /* ST(0) *= m32int */
sewardj33dd31b2005-01-08 18:17:32 +00003969 DIP("fimull %s\n", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00003970 fop = Iop_MulF64;
3971 goto do_fop_m32;
sewardjce646f22004-08-31 23:55:54 +00003972
sewardj071895f2005-07-29 11:28:38 +00003973 case 2: /* FICOM m32int */
3974 DIP("ficoml %s\n", dis_buf);
3975 /* This forces C1 to zero, which isn't right. */
3976 put_C3210(
3977 binop( Iop_And32,
3978 binop(Iop_Shl32,
3979 binop(Iop_CmpF64,
3980 get_ST(0),
3981 unop(Iop_I32toF64,
3982 loadLE(Ity_I32,mkexpr(addr)))),
3983 mkU8(8)),
3984 mkU32(0x4500)
3985 ));
3986 break;
3987
3988 case 3: /* FICOMP m32int */
3989 DIP("ficompl %s\n", dis_buf);
3990 /* This forces C1 to zero, which isn't right. */
3991 put_C3210(
3992 binop( Iop_And32,
3993 binop(Iop_Shl32,
3994 binop(Iop_CmpF64,
3995 get_ST(0),
3996 unop(Iop_I32toF64,
3997 loadLE(Ity_I32,mkexpr(addr)))),
3998 mkU8(8)),
3999 mkU32(0x4500)
4000 ));
4001 fp_pop();
4002 break;
4003
sewardjce646f22004-08-31 23:55:54 +00004004 case 4: /* FISUB m32int */ /* ST(0) -= m32int */
sewardj33dd31b2005-01-08 18:17:32 +00004005 DIP("fisubl %s\n", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00004006 fop = Iop_SubF64;
4007 goto do_fop_m32;
sewardjce646f22004-08-31 23:55:54 +00004008
sewardj8308aad2004-09-12 11:09:54 +00004009 case 5: /* FISUBR m32int */ /* ST(0) = m32int - ST(0) */
sewardj33dd31b2005-01-08 18:17:32 +00004010 DIP("fisubrl %s\n", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00004011 fop = Iop_SubF64;
4012 goto do_foprev_m32;
sewardj8308aad2004-09-12 11:09:54 +00004013
sewardjce646f22004-08-31 23:55:54 +00004014 case 6: /* FIDIV m32int */ /* ST(0) /= m32int */
sewardj36917e92005-03-21 00:12:15 +00004015 DIP("fidivl %s\n", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00004016 fop = Iop_DivF64;
4017 goto do_fop_m32;
sewardjce646f22004-08-31 23:55:54 +00004018
sewardjc4eaff32004-09-10 20:25:11 +00004019 case 7: /* FIDIVR m32int */ /* ST(0) = m32int / ST(0) */
sewardj33dd31b2005-01-08 18:17:32 +00004020 DIP("fidivrl %s\n", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00004021 fop = Iop_DivF64;
4022 goto do_foprev_m32;
sewardjc4eaff32004-09-10 20:25:11 +00004023
sewardjce646f22004-08-31 23:55:54 +00004024 do_fop_m32:
sewardj207557a2004-08-27 12:00:18 +00004025 put_ST_UNCHECKED(0,
sewardjce646f22004-08-31 23:55:54 +00004026 binop(fop,
sewardj207557a2004-08-27 12:00:18 +00004027 get_ST(0),
sewardj89cd0932004-09-08 18:23:25 +00004028 unop(Iop_I32toF64,
4029 loadLE(Ity_I32, mkexpr(addr)))));
sewardjbb53f8c2004-08-14 11:50:01 +00004030 break;
4031
sewardjc4eaff32004-09-10 20:25:11 +00004032 do_foprev_m32:
4033 put_ST_UNCHECKED(0,
4034 binop(fop,
4035 unop(Iop_I32toF64,
4036 loadLE(Ity_I32, mkexpr(addr))),
4037 get_ST(0)));
4038 break;
4039
sewardjbb53f8c2004-08-14 11:50:01 +00004040 default:
4041 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
4042 vex_printf("first_opcode == 0xDA\n");
4043 goto decode_fail;
4044 }
sewardj4cb918d2004-12-03 19:43:31 +00004045
sewardjbb53f8c2004-08-14 11:50:01 +00004046 } else {
sewardjbdc7d212004-09-09 02:46:40 +00004047
4048 delta++;
4049 switch (modrm) {
4050
sewardj519d66f2004-12-15 11:57:58 +00004051 case 0xC0 ... 0xC7: /* FCMOVB ST(i), ST(0) */
4052 r_src = (UInt)modrm - 0xC0;
sewardj2d49b432005-02-01 00:37:06 +00004053 DIP("fcmovb %%st(%d), %%st(0)\n", (Int)r_src);
sewardj519d66f2004-12-15 11:57:58 +00004054 put_ST_UNCHECKED(0,
4055 IRExpr_Mux0X(
4056 unop(Iop_1Uto8,
4057 mk_x86g_calculate_condition(X86CondB)),
4058 get_ST(0), get_ST(r_src)) );
4059 break;
4060
sewardj3fd5e572004-09-09 22:43:51 +00004061 case 0xC8 ... 0xCF: /* FCMOVE(Z) ST(i), ST(0) */
4062 r_src = (UInt)modrm - 0xC8;
sewardj2d49b432005-02-01 00:37:06 +00004063 DIP("fcmovz %%st(%d), %%st(0)\n", (Int)r_src);
sewardj5bd4d162004-11-10 13:02:48 +00004064 put_ST_UNCHECKED(0,
sewardj3fd5e572004-09-09 22:43:51 +00004065 IRExpr_Mux0X(
sewardj2a9ad022004-11-25 02:46:58 +00004066 unop(Iop_1Uto8,
4067 mk_x86g_calculate_condition(X86CondZ)),
sewardj3fd5e572004-09-09 22:43:51 +00004068 get_ST(0), get_ST(r_src)) );
4069 break;
4070
sewardj519d66f2004-12-15 11:57:58 +00004071 case 0xD0 ... 0xD7: /* FCMOVBE ST(i), ST(0) */
4072 r_src = (UInt)modrm - 0xD0;
sewardj2d49b432005-02-01 00:37:06 +00004073 DIP("fcmovbe %%st(%d), %%st(0)\n", (Int)r_src);
sewardj519d66f2004-12-15 11:57:58 +00004074 put_ST_UNCHECKED(0,
4075 IRExpr_Mux0X(
4076 unop(Iop_1Uto8,
4077 mk_x86g_calculate_condition(X86CondBE)),
4078 get_ST(0), get_ST(r_src)) );
4079 break;
4080
sewardj8253ad32005-07-04 10:26:32 +00004081 case 0xD8 ... 0xDF: /* FCMOVU ST(i), ST(0) */
4082 r_src = (UInt)modrm - 0xD8;
4083 DIP("fcmovnu %%st(%d), %%st(0)\n", (Int)r_src);
4084 put_ST_UNCHECKED(0,
4085 IRExpr_Mux0X(
4086 unop(Iop_1Uto8,
4087 mk_x86g_calculate_condition(X86CondP)),
4088 get_ST(0), get_ST(r_src)) );
4089 break;
4090
sewardjbdc7d212004-09-09 02:46:40 +00004091 case 0xE9: /* FUCOMPP %st(0),%st(1) */
4092 DIP("fucompp %%st(0),%%st(1)\n");
sewardjc4be80c2004-09-10 16:17:45 +00004093 /* This forces C1 to zero, which isn't right. */
4094 put_C3210(
4095 binop( Iop_And32,
4096 binop(Iop_Shl32,
4097 binop(Iop_CmpF64, get_ST(0), get_ST(1)),
4098 mkU8(8)),
4099 mkU32(0x4500)
4100 ));
sewardjbdc7d212004-09-09 02:46:40 +00004101 fp_pop();
4102 fp_pop();
4103 break;
4104
sewardj5bd4d162004-11-10 13:02:48 +00004105 default:
sewardjbdc7d212004-09-09 02:46:40 +00004106 goto decode_fail;
sewardj5bd4d162004-11-10 13:02:48 +00004107 }
sewardjbdc7d212004-09-09 02:46:40 +00004108
sewardjbb53f8c2004-08-14 11:50:01 +00004109 }
sewardjd1725d12004-08-12 20:46:53 +00004110 }
4111
4112 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDB opcodes +-+-+-+-+-+-+-+ */
4113 else
4114 if (first_opcode == 0xDB) {
sewardj89cd0932004-09-08 18:23:25 +00004115 if (modrm < 0xC0) {
4116
sewardjfeeb8a82004-11-30 12:30:11 +00004117 /* bits 5,4,3 are an opcode extension, and the modRM also
sewardj89cd0932004-09-08 18:23:25 +00004118 specifies an address. */
4119 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
4120 delta += len;
4121
4122 switch (gregOfRM(modrm)) {
4123
4124 case 0: /* FILD m32int */
4125 DIP("fildl %s\n", dis_buf);
4126 fp_push();
4127 put_ST(0, unop(Iop_I32toF64,
4128 loadLE(Ity_I32, mkexpr(addr))));
4129 break;
4130
sewardj8f3debf2004-09-08 23:42:23 +00004131 case 2: /* FIST m32 */
sewardj33dd31b2005-01-08 18:17:32 +00004132 DIP("fistl %s\n", dis_buf);
sewardj8f3debf2004-09-08 23:42:23 +00004133 storeLE( mkexpr(addr),
4134 binop(Iop_F64toI32, get_roundingmode(), get_ST(0)) );
4135 break;
4136
sewardj89cd0932004-09-08 18:23:25 +00004137 case 3: /* FISTP m32 */
sewardj33dd31b2005-01-08 18:17:32 +00004138 DIP("fistpl %s\n", dis_buf);
sewardj8f3debf2004-09-08 23:42:23 +00004139 storeLE( mkexpr(addr),
4140 binop(Iop_F64toI32, get_roundingmode(), get_ST(0)) );
sewardj5bd4d162004-11-10 13:02:48 +00004141 fp_pop();
sewardj89cd0932004-09-08 18:23:25 +00004142 break;
sewardj17442fe2004-09-20 14:54:28 +00004143
sewardjb3bce0e2004-09-14 23:20:10 +00004144 case 5: { /* FLD extended-real */
sewardj7cb49d72004-10-24 22:31:25 +00004145 /* Uses dirty helper:
sewardj56579232005-03-26 21:49:42 +00004146 ULong x86g_loadF80le ( UInt )
sewardj7cb49d72004-10-24 22:31:25 +00004147 addr holds the address. First, do a dirty call to
sewardjb3bce0e2004-09-14 23:20:10 +00004148 get hold of the data. */
sewardjc5fc7aa2004-10-27 23:00:55 +00004149 IRTemp val = newTemp(Ity_I64);
4150 IRExpr** args = mkIRExprVec_1 ( mkexpr(addr) );
4151
sewardj8ea867b2004-10-30 19:03:02 +00004152 IRDirty* d = unsafeIRDirty_1_N (
4153 val,
sewardj2a9ad022004-11-25 02:46:58 +00004154 0/*regparms*/,
4155 "x86g_loadF80le", &x86g_loadF80le,
sewardj8ea867b2004-10-30 19:03:02 +00004156 args
4157 );
sewardjb3bce0e2004-09-14 23:20:10 +00004158 /* declare that we're reading memory */
4159 d->mFx = Ifx_Read;
sewardj17442fe2004-09-20 14:54:28 +00004160 d->mAddr = mkexpr(addr);
sewardjb3bce0e2004-09-14 23:20:10 +00004161 d->mSize = 10;
sewardjc5fc7aa2004-10-27 23:00:55 +00004162
4163 /* execute the dirty call, dumping the result in val. */
sewardjb3bce0e2004-09-14 23:20:10 +00004164 stmt( IRStmt_Dirty(d) );
4165 fp_push();
sewardjc5fc7aa2004-10-27 23:00:55 +00004166 put_ST(0, unop(Iop_ReinterpI64asF64, mkexpr(val)));
4167
sewardj33dd31b2005-01-08 18:17:32 +00004168 DIP("fldt %s\n", dis_buf);
sewardjb3bce0e2004-09-14 23:20:10 +00004169 break;
4170 }
sewardj17442fe2004-09-20 14:54:28 +00004171
4172 case 7: { /* FSTP extended-real */
sewardj9fc9e782004-11-26 17:57:40 +00004173 /* Uses dirty helper: void x86g_storeF80le ( UInt, ULong ) */
sewardjc5fc7aa2004-10-27 23:00:55 +00004174 IRExpr** args
4175 = mkIRExprVec_2( mkexpr(addr),
4176 unop(Iop_ReinterpF64asI64, get_ST(0)) );
4177
sewardj8ea867b2004-10-30 19:03:02 +00004178 IRDirty* d = unsafeIRDirty_0_N (
sewardjf9655262004-10-31 20:02:16 +00004179 0/*regparms*/,
sewardj2a9ad022004-11-25 02:46:58 +00004180 "x86g_storeF80le", &x86g_storeF80le,
sewardj8ea867b2004-10-30 19:03:02 +00004181 args
4182 );
sewardj17442fe2004-09-20 14:54:28 +00004183 /* declare we're writing memory */
4184 d->mFx = Ifx_Write;
4185 d->mAddr = mkexpr(addr);
4186 d->mSize = 10;
sewardjc5fc7aa2004-10-27 23:00:55 +00004187
sewardj17442fe2004-09-20 14:54:28 +00004188 /* execute the dirty call. */
4189 stmt( IRStmt_Dirty(d) );
4190 fp_pop();
sewardjc5fc7aa2004-10-27 23:00:55 +00004191
sewardj33dd31b2005-01-08 18:17:32 +00004192 DIP("fstpt\n %s", dis_buf);
sewardj17442fe2004-09-20 14:54:28 +00004193 break;
4194 }
4195
sewardjb3bce0e2004-09-14 23:20:10 +00004196 default:
sewardj89cd0932004-09-08 18:23:25 +00004197 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
4198 vex_printf("first_opcode == 0xDB\n");
4199 goto decode_fail;
4200 }
4201
4202 } else {
sewardj8308aad2004-09-12 11:09:54 +00004203
4204 delta++;
4205 switch (modrm) {
4206
sewardj519d66f2004-12-15 11:57:58 +00004207 case 0xC0 ... 0xC7: /* FCMOVNB ST(i), ST(0) */
4208 r_src = (UInt)modrm - 0xC0;
sewardj2d49b432005-02-01 00:37:06 +00004209 DIP("fcmovnb %%st(%d), %%st(0)\n", (Int)r_src);
sewardj519d66f2004-12-15 11:57:58 +00004210 put_ST_UNCHECKED(0,
4211 IRExpr_Mux0X(
4212 unop(Iop_1Uto8,
4213 mk_x86g_calculate_condition(X86CondNB)),
4214 get_ST(0), get_ST(r_src)) );
4215 break;
4216
sewardj4e82db72004-10-16 11:32:15 +00004217 case 0xC8 ... 0xCF: /* FCMOVNE(NZ) ST(i), ST(0) */
4218 r_src = (UInt)modrm - 0xC8;
sewardj2d49b432005-02-01 00:37:06 +00004219 DIP("fcmovnz %%st(%d), %%st(0)\n", (Int)r_src);
sewardj5bd4d162004-11-10 13:02:48 +00004220 put_ST_UNCHECKED(0,
sewardj4e82db72004-10-16 11:32:15 +00004221 IRExpr_Mux0X(
sewardj2a9ad022004-11-25 02:46:58 +00004222 unop(Iop_1Uto8,
4223 mk_x86g_calculate_condition(X86CondNZ)),
sewardj4e82db72004-10-16 11:32:15 +00004224 get_ST(0), get_ST(r_src)) );
4225 break;
4226
sewardj519d66f2004-12-15 11:57:58 +00004227 case 0xD0 ... 0xD7: /* FCMOVNBE ST(i), ST(0) */
4228 r_src = (UInt)modrm - 0xD0;
sewardj2d49b432005-02-01 00:37:06 +00004229 DIP("fcmovnbe %%st(%d), %%st(0)\n", (Int)r_src);
sewardj519d66f2004-12-15 11:57:58 +00004230 put_ST_UNCHECKED(0,
4231 IRExpr_Mux0X(
4232 unop(Iop_1Uto8,
4233 mk_x86g_calculate_condition(X86CondNBE)),
4234 get_ST(0), get_ST(r_src)) );
4235 break;
4236
sewardj8253ad32005-07-04 10:26:32 +00004237 case 0xD8 ... 0xDF: /* FCMOVNU ST(i), ST(0) */
4238 r_src = (UInt)modrm - 0xD8;
4239 DIP("fcmovnu %%st(%d), %%st(0)\n", (Int)r_src);
4240 put_ST_UNCHECKED(0,
4241 IRExpr_Mux0X(
4242 unop(Iop_1Uto8,
4243 mk_x86g_calculate_condition(X86CondNP)),
4244 get_ST(0), get_ST(r_src)) );
4245 break;
4246
sewardj7df596b2004-12-06 14:29:12 +00004247 case 0xE2:
4248 DIP("fnclex\n");
4249 break;
4250
sewardja0e83b02005-01-06 12:36:38 +00004251 case 0xE3: {
4252 /* Uses dirty helper:
4253 void x86g_do_FINIT ( VexGuestX86State* ) */
4254 IRDirty* d = unsafeIRDirty_0_N (
4255 0/*regparms*/,
4256 "x86g_dirtyhelper_FINIT",
4257 &x86g_dirtyhelper_FINIT,
4258 mkIRExprVec_0()
4259 );
4260 d->needsBBP = True;
4261
4262 /* declare we're writing guest state */
4263 d->nFxState = 5;
4264
4265 d->fxState[0].fx = Ifx_Write;
4266 d->fxState[0].offset = OFFB_FTOP;
4267 d->fxState[0].size = sizeof(UInt);
4268
4269 d->fxState[1].fx = Ifx_Write;
4270 d->fxState[1].offset = OFFB_FPREGS;
4271 d->fxState[1].size = 8 * sizeof(ULong);
4272
4273 d->fxState[2].fx = Ifx_Write;
4274 d->fxState[2].offset = OFFB_FPTAGS;
4275 d->fxState[2].size = 8 * sizeof(UChar);
4276
4277 d->fxState[3].fx = Ifx_Write;
4278 d->fxState[3].offset = OFFB_FPROUND;
4279 d->fxState[3].size = sizeof(UInt);
4280
4281 d->fxState[4].fx = Ifx_Write;
4282 d->fxState[4].offset = OFFB_FC3210;
4283 d->fxState[4].size = sizeof(UInt);
4284
4285 stmt( IRStmt_Dirty(d) );
4286
sewardj33dd31b2005-01-08 18:17:32 +00004287 DIP("fninit\n");
sewardja0e83b02005-01-06 12:36:38 +00004288 break;
4289 }
4290
sewardj8308aad2004-09-12 11:09:54 +00004291 case 0xE8 ... 0xEF: /* FUCOMI %st(0),%st(?) */
4292 fp_do_ucomi_ST0_STi( (UInt)modrm - 0xE8, False );
4293 break;
4294
sewardj37158712004-10-15 21:23:12 +00004295 case 0xF0 ... 0xF7: /* FCOMI %st(0),%st(?) */
4296 fp_do_ucomi_ST0_STi( (UInt)modrm - 0xF0, False );
4297 break;
4298
sewardj8308aad2004-09-12 11:09:54 +00004299 default:
4300 goto decode_fail;
sewardj17442fe2004-09-20 14:54:28 +00004301 }
sewardj89cd0932004-09-08 18:23:25 +00004302 }
sewardjd1725d12004-08-12 20:46:53 +00004303 }
4304
4305 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDC opcodes +-+-+-+-+-+-+-+ */
4306 else
4307 if (first_opcode == 0xDC) {
sewardja58ea662004-08-15 03:12:41 +00004308 if (modrm < 0xC0) {
4309
sewardj89cd0932004-09-08 18:23:25 +00004310 /* bits 5,4,3 are an opcode extension, and the modRM also
sewardjfeeb8a82004-11-30 12:30:11 +00004311 specifies an address. */
sewardja58ea662004-08-15 03:12:41 +00004312 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
4313 delta += len;
4314
4315 switch (gregOfRM(modrm)) {
4316
4317 case 0: /* FADD double-real */
4318 fp_do_op_mem_ST_0 ( addr, "add", dis_buf, Iop_AddF64, True );
4319 break;
4320
sewardjcfded9a2004-09-09 11:44:16 +00004321 case 1: /* FMUL double-real */
4322 fp_do_op_mem_ST_0 ( addr, "mul", dis_buf, Iop_MulF64, True );
4323 break;
4324
sewardje166ed02004-10-25 02:27:01 +00004325 case 2: /* FCOM double-real */
4326 DIP("fcoml %s\n", dis_buf);
4327 /* This forces C1 to zero, which isn't right. */
4328 put_C3210(
4329 binop( Iop_And32,
4330 binop(Iop_Shl32,
4331 binop(Iop_CmpF64,
4332 get_ST(0),
4333 loadLE(Ity_F64,mkexpr(addr))),
4334 mkU8(8)),
4335 mkU32(0x4500)
4336 ));
4337 break;
4338
sewardj883b00b2004-09-11 09:30:24 +00004339 case 3: /* FCOMP double-real */
sewardje166ed02004-10-25 02:27:01 +00004340 DIP("fcompl %s\n", dis_buf);
sewardj883b00b2004-09-11 09:30:24 +00004341 /* This forces C1 to zero, which isn't right. */
4342 put_C3210(
4343 binop( Iop_And32,
4344 binop(Iop_Shl32,
4345 binop(Iop_CmpF64,
4346 get_ST(0),
4347 loadLE(Ity_F64,mkexpr(addr))),
4348 mkU8(8)),
4349 mkU32(0x4500)
4350 ));
4351 fp_pop();
4352 break;
4353
sewardjcfded9a2004-09-09 11:44:16 +00004354 case 4: /* FSUB double-real */
4355 fp_do_op_mem_ST_0 ( addr, "sub", dis_buf, Iop_SubF64, True );
4356 break;
4357
sewardj3fd5e572004-09-09 22:43:51 +00004358 case 5: /* FSUBR double-real */
4359 fp_do_oprev_mem_ST_0 ( addr, "subr", dis_buf, Iop_SubF64, True );
4360 break;
4361
sewardjcfded9a2004-09-09 11:44:16 +00004362 case 6: /* FDIV double-real */
4363 fp_do_op_mem_ST_0 ( addr, "div", dis_buf, Iop_DivF64, True );
4364 break;
4365
sewardj883b00b2004-09-11 09:30:24 +00004366 case 7: /* FDIVR double-real */
4367 fp_do_oprev_mem_ST_0 ( addr, "divr", dis_buf, Iop_DivF64, True );
4368 break;
4369
sewardja58ea662004-08-15 03:12:41 +00004370 default:
4371 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
4372 vex_printf("first_opcode == 0xDC\n");
4373 goto decode_fail;
4374 }
4375
4376 } else {
sewardjbdc7d212004-09-09 02:46:40 +00004377
4378 delta++;
4379 switch (modrm) {
4380
sewardj3fd5e572004-09-09 22:43:51 +00004381 case 0xC0 ... 0xC7: /* FADD %st(0),%st(?) */
4382 fp_do_op_ST_ST ( "add", Iop_AddF64, 0, modrm - 0xC0, False );
4383 break;
4384
sewardjcfded9a2004-09-09 11:44:16 +00004385 case 0xC8 ... 0xCF: /* FMUL %st(0),%st(?) */
4386 fp_do_op_ST_ST ( "mul", Iop_MulF64, 0, modrm - 0xC8, False );
4387 break;
4388
sewardj47341042004-09-19 11:55:46 +00004389 case 0xE0 ... 0xE7: /* FSUBR %st(0),%st(?) */
4390 fp_do_oprev_ST_ST ( "subr", Iop_SubF64, 0, modrm - 0xE0, False );
4391 break;
4392
sewardjcfded9a2004-09-09 11:44:16 +00004393 case 0xE8 ... 0xEF: /* FSUB %st(0),%st(?) */
4394 fp_do_op_ST_ST ( "sub", Iop_SubF64, 0, modrm - 0xE8, False );
4395 break;
4396
sewardja0d48d62004-09-20 21:19:03 +00004397 case 0xF0 ... 0xF7: /* FDIVR %st(0),%st(?) */
4398 fp_do_oprev_ST_ST ( "divr", Iop_DivF64, 0, modrm - 0xF0, False );
4399 break;
4400
sewardjbdc7d212004-09-09 02:46:40 +00004401 case 0xF8 ... 0xFF: /* FDIV %st(0),%st(?) */
4402 fp_do_op_ST_ST ( "div", Iop_DivF64, 0, modrm - 0xF8, False );
4403 break;
4404
4405 default:
4406 goto decode_fail;
sewardj5bd4d162004-11-10 13:02:48 +00004407 }
sewardjbdc7d212004-09-09 02:46:40 +00004408
sewardja58ea662004-08-15 03:12:41 +00004409 }
sewardjd1725d12004-08-12 20:46:53 +00004410 }
4411
4412 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDD opcodes +-+-+-+-+-+-+-+ */
4413 else
4414 if (first_opcode == 0xDD) {
4415
4416 if (modrm < 0xC0) {
4417
sewardjfeeb8a82004-11-30 12:30:11 +00004418 /* bits 5,4,3 are an opcode extension, and the modRM also
sewardjd1725d12004-08-12 20:46:53 +00004419 specifies an address. */
sewardjbb53f8c2004-08-14 11:50:01 +00004420 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
4421 delta += len;
sewardjd1725d12004-08-12 20:46:53 +00004422
4423 switch (gregOfRM(modrm)) {
4424
4425 case 0: /* FLD double-real */
sewardj33dd31b2005-01-08 18:17:32 +00004426 DIP("fldl %s\n", dis_buf);
sewardj207557a2004-08-27 12:00:18 +00004427 fp_push();
sewardjaf1ceca2005-06-30 23:31:27 +00004428 put_ST(0, loadLE(Ity_F64, mkexpr(addr)));
sewardjbb53f8c2004-08-14 11:50:01 +00004429 break;
sewardjd1725d12004-08-12 20:46:53 +00004430
sewardjd1725d12004-08-12 20:46:53 +00004431 case 2: /* FST double-real */
sewardj33dd31b2005-01-08 18:17:32 +00004432 DIP("fstl %s\n", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00004433 storeLE(mkexpr(addr), get_ST(0));
sewardjd1725d12004-08-12 20:46:53 +00004434 break;
sewardj89cd0932004-09-08 18:23:25 +00004435
sewardja58ea662004-08-15 03:12:41 +00004436 case 3: /* FSTP double-real */
sewardj33dd31b2005-01-08 18:17:32 +00004437 DIP("fstpl %s\n", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00004438 storeLE(mkexpr(addr), get_ST(0));
4439 fp_pop();
sewardja58ea662004-08-15 03:12:41 +00004440 break;
sewardjd1725d12004-08-12 20:46:53 +00004441
sewardj9fc9e782004-11-26 17:57:40 +00004442 case 4: { /* FRSTOR m108 */
sewardj893aada2004-11-29 19:57:54 +00004443 /* Uses dirty helper:
4444 VexEmWarn x86g_do_FRSTOR ( VexGuestX86State*, Addr32 ) */
4445 IRTemp ew = newTemp(Ity_I32);
4446 IRDirty* d = unsafeIRDirty_0_N (
4447 0/*regparms*/,
4448 "x86g_dirtyhelper_FRSTOR",
4449 &x86g_dirtyhelper_FRSTOR,
4450 mkIRExprVec_1( mkexpr(addr) )
4451 );
sewardj9fc9e782004-11-26 17:57:40 +00004452 d->needsBBP = True;
sewardj893aada2004-11-29 19:57:54 +00004453 d->tmp = ew;
sewardj9fc9e782004-11-26 17:57:40 +00004454 /* declare we're reading memory */
4455 d->mFx = Ifx_Read;
4456 d->mAddr = mkexpr(addr);
4457 d->mSize = 108;
4458
4459 /* declare we're writing guest state */
sewardj893aada2004-11-29 19:57:54 +00004460 d->nFxState = 5;
sewardj9fc9e782004-11-26 17:57:40 +00004461
4462 d->fxState[0].fx = Ifx_Write;
sewardjc9a43662004-11-30 18:51:59 +00004463 d->fxState[0].offset = OFFB_FTOP;
sewardj9fc9e782004-11-26 17:57:40 +00004464 d->fxState[0].size = sizeof(UInt);
4465
4466 d->fxState[1].fx = Ifx_Write;
sewardjc9a43662004-11-30 18:51:59 +00004467 d->fxState[1].offset = OFFB_FPREGS;
sewardj9fc9e782004-11-26 17:57:40 +00004468 d->fxState[1].size = 8 * sizeof(ULong);
4469
4470 d->fxState[2].fx = Ifx_Write;
sewardjc9a43662004-11-30 18:51:59 +00004471 d->fxState[2].offset = OFFB_FPTAGS;
sewardj9fc9e782004-11-26 17:57:40 +00004472 d->fxState[2].size = 8 * sizeof(UChar);
4473
4474 d->fxState[3].fx = Ifx_Write;
sewardjc9a43662004-11-30 18:51:59 +00004475 d->fxState[3].offset = OFFB_FPROUND;
sewardj9fc9e782004-11-26 17:57:40 +00004476 d->fxState[3].size = sizeof(UInt);
4477
4478 d->fxState[4].fx = Ifx_Write;
sewardjc9a43662004-11-30 18:51:59 +00004479 d->fxState[4].offset = OFFB_FC3210;
sewardj9fc9e782004-11-26 17:57:40 +00004480 d->fxState[4].size = sizeof(UInt);
4481
4482 stmt( IRStmt_Dirty(d) );
4483
sewardj893aada2004-11-29 19:57:54 +00004484 /* ew contains any emulation warning we may need to
4485 issue. If needed, side-exit to the next insn,
4486 reporting the warning, so that Valgrind's dispatcher
4487 sees the warning. */
4488 put_emwarn( mkexpr(ew) );
4489 stmt(
4490 IRStmt_Exit(
4491 binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
4492 Ijk_EmWarn,
sewardj9e6491a2005-07-02 19:24:10 +00004493 IRConst_U32( ((Addr32)guest_EIP_bbstart)+delta)
sewardj893aada2004-11-29 19:57:54 +00004494 )
4495 );
4496
sewardj33dd31b2005-01-08 18:17:32 +00004497 DIP("frstor %s\n", dis_buf);
sewardj9fc9e782004-11-26 17:57:40 +00004498 break;
4499 }
4500
4501 case 6: { /* FNSAVE m108 */
sewardj893aada2004-11-29 19:57:54 +00004502 /* Uses dirty helper:
4503 void x86g_do_FSAVE ( VexGuestX86State*, UInt ) */
sewardj9fc9e782004-11-26 17:57:40 +00004504 IRDirty* d = unsafeIRDirty_0_N (
4505 0/*regparms*/,
4506 "x86g_dirtyhelper_FSAVE",
4507 &x86g_dirtyhelper_FSAVE,
4508 mkIRExprVec_1( mkexpr(addr) )
4509 );
4510 d->needsBBP = True;
4511 /* declare we're writing memory */
4512 d->mFx = Ifx_Write;
4513 d->mAddr = mkexpr(addr);
4514 d->mSize = 108;
4515
4516 /* declare we're reading guest state */
sewardj893aada2004-11-29 19:57:54 +00004517 d->nFxState = 5;
sewardj9fc9e782004-11-26 17:57:40 +00004518
4519 d->fxState[0].fx = Ifx_Read;
sewardjc9a43662004-11-30 18:51:59 +00004520 d->fxState[0].offset = OFFB_FTOP;
sewardj9fc9e782004-11-26 17:57:40 +00004521 d->fxState[0].size = sizeof(UInt);
4522
4523 d->fxState[1].fx = Ifx_Read;
sewardjc9a43662004-11-30 18:51:59 +00004524 d->fxState[1].offset = OFFB_FPREGS;
sewardj9fc9e782004-11-26 17:57:40 +00004525 d->fxState[1].size = 8 * sizeof(ULong);
4526
4527 d->fxState[2].fx = Ifx_Read;
sewardjc9a43662004-11-30 18:51:59 +00004528 d->fxState[2].offset = OFFB_FPTAGS;
sewardj9fc9e782004-11-26 17:57:40 +00004529 d->fxState[2].size = 8 * sizeof(UChar);
4530
4531 d->fxState[3].fx = Ifx_Read;
sewardjc9a43662004-11-30 18:51:59 +00004532 d->fxState[3].offset = OFFB_FPROUND;
sewardj9fc9e782004-11-26 17:57:40 +00004533 d->fxState[3].size = sizeof(UInt);
4534
4535 d->fxState[4].fx = Ifx_Read;
sewardjc9a43662004-11-30 18:51:59 +00004536 d->fxState[4].offset = OFFB_FC3210;
sewardj9fc9e782004-11-26 17:57:40 +00004537 d->fxState[4].size = sizeof(UInt);
4538
4539 stmt( IRStmt_Dirty(d) );
4540
sewardj33dd31b2005-01-08 18:17:32 +00004541 DIP("fnsave %s\n", dis_buf);
sewardj9fc9e782004-11-26 17:57:40 +00004542 break;
4543 }
4544
sewardjd24931d2005-03-20 12:51:39 +00004545 case 7: { /* FNSTSW m16 */
4546 IRExpr* sw = get_FPU_sw();
4547 vassert(typeOfIRExpr(irbb->tyenv, sw) == Ity_I16);
4548 storeLE( mkexpr(addr), sw );
4549 DIP("fnstsw %s\n", dis_buf);
4550 break;
4551 }
4552
sewardjd1725d12004-08-12 20:46:53 +00004553 default:
sewardjbb53f8c2004-08-14 11:50:01 +00004554 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
4555 vex_printf("first_opcode == 0xDD\n");
sewardjd1725d12004-08-12 20:46:53 +00004556 goto decode_fail;
sewardjbb53f8c2004-08-14 11:50:01 +00004557 }
sewardjd1725d12004-08-12 20:46:53 +00004558 } else {
sewardja58ea662004-08-15 03:12:41 +00004559 delta++;
4560 switch (modrm) {
sewardjbdc7d212004-09-09 02:46:40 +00004561
sewardj3ddedc42005-03-25 20:30:00 +00004562 case 0xC0 ... 0xC7: /* FFREE %st(?) */
4563 r_dst = (UInt)modrm - 0xC0;
sewardj4a6f3842005-03-26 11:59:23 +00004564 DIP("ffree %%st(%d)\n", (Int)r_dst);
sewardj3ddedc42005-03-25 20:30:00 +00004565 put_ST_TAG ( r_dst, mkU8(0) );
4566 break;
4567
sewardj06c32a02004-09-12 12:07:34 +00004568 case 0xD0 ... 0xD7: /* FST %st(0),%st(?) */
4569 r_dst = (UInt)modrm - 0xD0;
sewardj2d49b432005-02-01 00:37:06 +00004570 DIP("fst %%st(0),%%st(%d)\n", (Int)r_dst);
sewardj5bd4d162004-11-10 13:02:48 +00004571 /* P4 manual says: "If the destination operand is a
sewardj06c32a02004-09-12 12:07:34 +00004572 non-empty register, the invalid-operation exception
4573 is not generated. Hence put_ST_UNCHECKED. */
4574 put_ST_UNCHECKED(r_dst, get_ST(0));
4575 break;
4576
sewardja58ea662004-08-15 03:12:41 +00004577 case 0xD8 ... 0xDF: /* FSTP %st(0),%st(?) */
4578 r_dst = (UInt)modrm - 0xD8;
sewardj2d49b432005-02-01 00:37:06 +00004579 DIP("fstp %%st(0),%%st(%d)\n", (Int)r_dst);
sewardj5bd4d162004-11-10 13:02:48 +00004580 /* P4 manual says: "If the destination operand is a
sewardj207557a2004-08-27 12:00:18 +00004581 non-empty register, the invalid-operation exception
4582 is not generated. Hence put_ST_UNCHECKED. */
4583 put_ST_UNCHECKED(r_dst, get_ST(0));
4584 fp_pop();
sewardja58ea662004-08-15 03:12:41 +00004585 break;
sewardjbdc7d212004-09-09 02:46:40 +00004586
4587 case 0xE0 ... 0xE7: /* FUCOM %st(0),%st(?) */
4588 r_dst = (UInt)modrm - 0xE0;
sewardj2d49b432005-02-01 00:37:06 +00004589 DIP("fucom %%st(0),%%st(%d)\n", (Int)r_dst);
sewardjc4be80c2004-09-10 16:17:45 +00004590 /* This forces C1 to zero, which isn't right. */
4591 put_C3210(
4592 binop( Iop_And32,
4593 binop(Iop_Shl32,
4594 binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
4595 mkU8(8)),
4596 mkU32(0x4500)
4597 ));
sewardjbdc7d212004-09-09 02:46:40 +00004598 break;
4599
4600 case 0xE8 ... 0xEF: /* FUCOMP %st(0),%st(?) */
4601 r_dst = (UInt)modrm - 0xE8;
sewardj2d49b432005-02-01 00:37:06 +00004602 DIP("fucomp %%st(0),%%st(%d)\n", (Int)r_dst);
sewardjc4be80c2004-09-10 16:17:45 +00004603 /* This forces C1 to zero, which isn't right. */
4604 put_C3210(
4605 binop( Iop_And32,
4606 binop(Iop_Shl32,
4607 binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
4608 mkU8(8)),
4609 mkU32(0x4500)
4610 ));
sewardjbdc7d212004-09-09 02:46:40 +00004611 fp_pop();
4612 break;
4613
sewardj5bd4d162004-11-10 13:02:48 +00004614 default:
sewardja58ea662004-08-15 03:12:41 +00004615 goto decode_fail;
sewardj5bd4d162004-11-10 13:02:48 +00004616 }
sewardjd1725d12004-08-12 20:46:53 +00004617 }
4618 }
4619
4620 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDE opcodes +-+-+-+-+-+-+-+ */
4621 else
4622 if (first_opcode == 0xDE) {
sewardjbdc7d212004-09-09 02:46:40 +00004623
4624 if (modrm < 0xC0) {
sewardjfeeb8a82004-11-30 12:30:11 +00004625
4626 /* bits 5,4,3 are an opcode extension, and the modRM also
4627 specifies an address. */
4628 IROp fop;
4629 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
4630 delta += len;
4631
4632 switch (gregOfRM(modrm)) {
4633
4634 case 0: /* FIADD m16int */ /* ST(0) += m16int */
sewardj33dd31b2005-01-08 18:17:32 +00004635 DIP("fiaddw %s\n", dis_buf);
sewardjfeeb8a82004-11-30 12:30:11 +00004636 fop = Iop_AddF64;
4637 goto do_fop_m16;
4638
4639 case 1: /* FIMUL m16int */ /* ST(0) *= m16int */
sewardj33dd31b2005-01-08 18:17:32 +00004640 DIP("fimulw %s\n", dis_buf);
sewardjfeeb8a82004-11-30 12:30:11 +00004641 fop = Iop_MulF64;
4642 goto do_fop_m16;
4643
sewardj071895f2005-07-29 11:28:38 +00004644 case 2: /* FICOM m16int */
4645 DIP("ficomw %s\n", dis_buf);
4646 /* This forces C1 to zero, which isn't right. */
4647 put_C3210(
4648 binop( Iop_And32,
4649 binop(Iop_Shl32,
4650 binop(Iop_CmpF64,
4651 get_ST(0),
4652 unop(Iop_I32toF64,
4653 unop(Iop_16Sto32,
4654 loadLE(Ity_I16,mkexpr(addr))))),
4655 mkU8(8)),
4656 mkU32(0x4500)
4657 ));
4658 break;
4659
4660 case 3: /* FICOMP m16int */
4661 DIP("ficompw %s\n", dis_buf);
4662 /* This forces C1 to zero, which isn't right. */
4663 put_C3210(
4664 binop( Iop_And32,
4665 binop(Iop_Shl32,
4666 binop(Iop_CmpF64,
4667 get_ST(0),
4668 unop(Iop_I32toF64,
4669 unop(Iop_16Sto32,
4670 loadLE(Ity_I16,mkexpr(addr))))),
4671 mkU8(8)),
4672 mkU32(0x4500)
4673 ));
4674 fp_pop();
4675 break;
4676
sewardjfeeb8a82004-11-30 12:30:11 +00004677 case 4: /* FISUB m16int */ /* ST(0) -= m16int */
sewardj33dd31b2005-01-08 18:17:32 +00004678 DIP("fisubw %s\n", dis_buf);
sewardjfeeb8a82004-11-30 12:30:11 +00004679 fop = Iop_SubF64;
4680 goto do_fop_m16;
4681
4682 case 5: /* FISUBR m16int */ /* ST(0) = m16int - ST(0) */
sewardj33dd31b2005-01-08 18:17:32 +00004683 DIP("fisubrw %s\n", dis_buf);
sewardjfeeb8a82004-11-30 12:30:11 +00004684 fop = Iop_SubF64;
4685 goto do_foprev_m16;
4686
4687 case 6: /* FIDIV m16int */ /* ST(0) /= m16int */
sewardj33dd31b2005-01-08 18:17:32 +00004688 DIP("fisubw %s\n", dis_buf);
sewardjfeeb8a82004-11-30 12:30:11 +00004689 fop = Iop_DivF64;
4690 goto do_fop_m16;
4691
4692 case 7: /* FIDIVR m16int */ /* ST(0) = m16int / ST(0) */
sewardj33dd31b2005-01-08 18:17:32 +00004693 DIP("fidivrw %s\n", dis_buf);
sewardjfeeb8a82004-11-30 12:30:11 +00004694 fop = Iop_DivF64;
4695 goto do_foprev_m16;
4696
4697 do_fop_m16:
4698 put_ST_UNCHECKED(0,
4699 binop(fop,
4700 get_ST(0),
4701 unop(Iop_I32toF64,
4702 unop(Iop_16Sto32,
4703 loadLE(Ity_I16, mkexpr(addr))))));
4704 break;
4705
4706 do_foprev_m16:
4707 put_ST_UNCHECKED(0,
4708 binop(fop,
4709 unop(Iop_I32toF64,
4710 unop(Iop_16Sto32,
4711 loadLE(Ity_I16, mkexpr(addr)))),
4712 get_ST(0)));
4713 break;
4714
4715 default:
4716 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
4717 vex_printf("first_opcode == 0xDE\n");
4718 goto decode_fail;
4719 }
sewardjbdc7d212004-09-09 02:46:40 +00004720
4721 } else {
4722
4723 delta++;
sewardj5bd4d162004-11-10 13:02:48 +00004724 switch (modrm) {
sewardjbdc7d212004-09-09 02:46:40 +00004725
sewardjcfded9a2004-09-09 11:44:16 +00004726 case 0xC0 ... 0xC7: /* FADDP %st(0),%st(?) */
4727 fp_do_op_ST_ST ( "add", Iop_AddF64, 0, modrm - 0xC0, True );
4728 break;
4729
sewardjbdc7d212004-09-09 02:46:40 +00004730 case 0xC8 ... 0xCF: /* FMULP %st(0),%st(?) */
4731 fp_do_op_ST_ST ( "mul", Iop_MulF64, 0, modrm - 0xC8, True );
4732 break;
4733
sewardje166ed02004-10-25 02:27:01 +00004734 case 0xD9: /* FCOMPP %st(0),%st(1) */
4735 DIP("fuompp %%st(0),%%st(1)\n");
4736 /* This forces C1 to zero, which isn't right. */
4737 put_C3210(
4738 binop( Iop_And32,
4739 binop(Iop_Shl32,
4740 binop(Iop_CmpF64, get_ST(0), get_ST(1)),
4741 mkU8(8)),
4742 mkU32(0x4500)
4743 ));
4744 fp_pop();
4745 fp_pop();
4746 break;
4747
sewardjcfded9a2004-09-09 11:44:16 +00004748 case 0xE0 ... 0xE7: /* FSUBRP %st(0),%st(?) */
4749 fp_do_oprev_ST_ST ( "subr", Iop_SubF64, 0, modrm - 0xE0, True );
4750 break;
4751
sewardj3fd5e572004-09-09 22:43:51 +00004752 case 0xE8 ... 0xEF: /* FSUBP %st(0),%st(?) */
4753 fp_do_op_ST_ST ( "sub", Iop_SubF64, 0, modrm - 0xE8, True );
4754 break;
4755
sewardjbdc7d212004-09-09 02:46:40 +00004756 case 0xF0 ... 0xF7: /* FDIVRP %st(0),%st(?) */
4757 fp_do_oprev_ST_ST ( "divr", Iop_DivF64, 0, modrm - 0xF0, True );
4758 break;
4759
4760 case 0xF8 ... 0xFF: /* FDIVP %st(0),%st(?) */
4761 fp_do_op_ST_ST ( "div", Iop_DivF64, 0, modrm - 0xF8, True );
4762 break;
4763
4764 default:
4765 goto decode_fail;
sewardj5bd4d162004-11-10 13:02:48 +00004766 }
sewardjbdc7d212004-09-09 02:46:40 +00004767
4768 }
sewardjd1725d12004-08-12 20:46:53 +00004769 }
4770
4771 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDF opcodes +-+-+-+-+-+-+-+ */
4772 else
4773 if (first_opcode == 0xDF) {
sewardj89cd0932004-09-08 18:23:25 +00004774
4775 if (modrm < 0xC0) {
4776
sewardjfeeb8a82004-11-30 12:30:11 +00004777 /* bits 5,4,3 are an opcode extension, and the modRM also
sewardj89cd0932004-09-08 18:23:25 +00004778 specifies an address. */
4779 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
4780 delta += len;
4781
4782 switch (gregOfRM(modrm)) {
4783
sewardj883b00b2004-09-11 09:30:24 +00004784 case 0: /* FILD m16int */
4785 DIP("fildw %s\n", dis_buf);
4786 fp_push();
4787 put_ST(0, unop(Iop_I32toF64,
4788 unop(Iop_16Sto32,
4789 loadLE(Ity_I16, mkexpr(addr)))));
4790 break;
4791
sewardj37158712004-10-15 21:23:12 +00004792 case 2: /* FIST m16 */
sewardj33dd31b2005-01-08 18:17:32 +00004793 DIP("fistp %s\n", dis_buf);
sewardj37158712004-10-15 21:23:12 +00004794 storeLE( mkexpr(addr),
4795 binop(Iop_F64toI16, get_roundingmode(), get_ST(0)) );
4796 break;
4797
sewardj89cd0932004-09-08 18:23:25 +00004798 case 3: /* FISTP m16 */
sewardj33dd31b2005-01-08 18:17:32 +00004799 DIP("fistps %s\n", dis_buf);
sewardj8f3debf2004-09-08 23:42:23 +00004800 storeLE( mkexpr(addr),
4801 binop(Iop_F64toI16, get_roundingmode(), get_ST(0)) );
4802 fp_pop();
sewardj89cd0932004-09-08 18:23:25 +00004803 break;
4804
sewardj89cd0932004-09-08 18:23:25 +00004805 case 5: /* FILD m64 */
4806 DIP("fildll %s\n", dis_buf);
4807 fp_push();
sewardj4cb918d2004-12-03 19:43:31 +00004808 put_ST(0, binop(Iop_I64toF64,
4809 get_roundingmode(),
4810 loadLE(Ity_I64, mkexpr(addr))));
sewardj89cd0932004-09-08 18:23:25 +00004811 break;
sewardj89cd0932004-09-08 18:23:25 +00004812
sewardjcfded9a2004-09-09 11:44:16 +00004813 case 7: /* FISTP m64 */
sewardj33dd31b2005-01-08 18:17:32 +00004814 DIP("fistpll %s\n", dis_buf);
sewardjcfded9a2004-09-09 11:44:16 +00004815 storeLE( mkexpr(addr),
4816 binop(Iop_F64toI64, get_roundingmode(), get_ST(0)) );
4817 fp_pop();
4818 break;
4819
sewardj89cd0932004-09-08 18:23:25 +00004820 default:
4821 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
4822 vex_printf("first_opcode == 0xDF\n");
4823 goto decode_fail;
4824 }
4825
4826 } else {
sewardjbdc7d212004-09-09 02:46:40 +00004827
4828 delta++;
sewardj5bd4d162004-11-10 13:02:48 +00004829 switch (modrm) {
sewardjbdc7d212004-09-09 02:46:40 +00004830
sewardj8fb88692005-07-29 11:57:00 +00004831 case 0xC0: /* FFREEP %st(0) */
4832 DIP("ffreep %%st(%d)\n", 0);
4833 put_ST_TAG ( 0, mkU8(0) );
4834 fp_pop();
4835 break;
4836
sewardjbdc7d212004-09-09 02:46:40 +00004837 case 0xE0: /* FNSTSW %ax */
4838 DIP("fnstsw %%ax\n");
sewardjd24931d2005-03-20 12:51:39 +00004839 /* Get the FPU status word value and dump it in %AX. */
4840 putIReg(2, R_EAX, get_FPU_sw());
sewardjbdc7d212004-09-09 02:46:40 +00004841 break;
4842
sewardj883b00b2004-09-11 09:30:24 +00004843 case 0xE8 ... 0xEF: /* FUCOMIP %st(0),%st(?) */
sewardj8308aad2004-09-12 11:09:54 +00004844 fp_do_ucomi_ST0_STi( (UInt)modrm - 0xE8, True );
sewardj883b00b2004-09-11 09:30:24 +00004845 break;
4846
sewardjfeeb8a82004-11-30 12:30:11 +00004847 case 0xF0 ... 0xF7: /* FCOMIP %st(0),%st(?) */
4848 /* not really right since COMIP != UCOMIP */
4849 fp_do_ucomi_ST0_STi( (UInt)modrm - 0xF0, True );
4850 break;
4851
sewardjbdc7d212004-09-09 02:46:40 +00004852 default:
4853 goto decode_fail;
sewardj5bd4d162004-11-10 13:02:48 +00004854 }
sewardj89cd0932004-09-08 18:23:25 +00004855 }
4856
sewardjd1725d12004-08-12 20:46:53 +00004857 }
4858
4859 else
4860 vpanic("dis_FPU(x86): invalid primary opcode");
4861
sewardj69d9d662004-10-14 21:58:52 +00004862 *decode_ok = True;
4863 return delta;
4864
sewardjd1725d12004-08-12 20:46:53 +00004865 decode_fail:
4866 *decode_ok = False;
4867 return delta;
4868}
4869
4870
sewardj464efa42004-11-19 22:17:29 +00004871/*------------------------------------------------------------*/
4872/*--- ---*/
4873/*--- MMX INSTRUCTIONS ---*/
4874/*--- ---*/
4875/*------------------------------------------------------------*/
sewardja06e5562004-07-14 13:18:05 +00004876
sewardj464efa42004-11-19 22:17:29 +00004877/* Effect of MMX insns on x87 FPU state (table 11-2 of
4878 IA32 arch manual, volume 3):
4879
4880 Read from, or write to MMX register (viz, any insn except EMMS):
4881 * All tags set to Valid (non-empty) -- FPTAGS[i] := nonzero
4882 * FP stack pointer set to zero
4883
4884 EMMS:
4885 * All tags set to Invalid (empty) -- FPTAGS[i] := zero
4886 * FP stack pointer set to zero
4887*/
4888
sewardj4cb918d2004-12-03 19:43:31 +00004889static void do_MMX_preamble ( void )
sewardj464efa42004-11-19 22:17:29 +00004890{
4891 Int i;
4892 IRArray* descr = mkIRArray( OFFB_FPTAGS, Ity_I8, 8 );
4893 IRExpr* zero = mkU32(0);
4894 IRExpr* tag1 = mkU8(1);
4895 put_ftop(zero);
4896 for (i = 0; i < 8; i++)
4897 stmt( IRStmt_PutI( descr, zero, i, tag1 ) );
4898}
4899
sewardj4cb918d2004-12-03 19:43:31 +00004900static void do_EMMS_preamble ( void )
sewardj464efa42004-11-19 22:17:29 +00004901{
4902 Int i;
4903 IRArray* descr = mkIRArray( OFFB_FPTAGS, Ity_I8, 8 );
4904 IRExpr* zero = mkU32(0);
4905 IRExpr* tag0 = mkU8(0);
4906 put_ftop(zero);
4907 for (i = 0; i < 8; i++)
4908 stmt( IRStmt_PutI( descr, zero, i, tag0 ) );
4909}
4910
4911
4912static IRExpr* getMMXReg ( UInt archreg )
4913{
4914 vassert(archreg < 8);
4915 return IRExpr_Get( OFFB_FPREGS + 8 * archreg, Ity_I64 );
4916}
4917
4918
4919static void putMMXReg ( UInt archreg, IRExpr* e )
4920{
4921 vassert(archreg < 8);
4922 vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_I64);
4923 stmt( IRStmt_Put( OFFB_FPREGS + 8 * archreg, e ) );
4924}
4925
4926
sewardj38a3f862005-01-13 15:06:51 +00004927/* Helper for non-shift MMX insns. Note this is incomplete in the
4928 sense that it does not first call do_MMX_preamble() -- that is the
4929 responsibility of its caller. */
4930
sewardj464efa42004-11-19 22:17:29 +00004931static
sewardj2d49b432005-02-01 00:37:06 +00004932UInt dis_MMXop_regmem_to_reg ( UChar sorb,
sewardj52d04912005-07-03 00:52:48 +00004933 Int delta,
sewardj2d49b432005-02-01 00:37:06 +00004934 UChar opc,
4935 HChar* name,
4936 Bool show_granularity )
sewardj464efa42004-11-19 22:17:29 +00004937{
sewardjc9a43662004-11-30 18:51:59 +00004938 HChar dis_buf[50];
sewardj63ba4092004-11-21 12:30:18 +00004939 UChar modrm = getIByte(delta);
4940 Bool isReg = epartIsReg(modrm);
4941 IRExpr* argL = NULL;
4942 IRExpr* argR = NULL;
sewardj38a3f862005-01-13 15:06:51 +00004943 IRExpr* argG = NULL;
4944 IRExpr* argE = NULL;
sewardj63ba4092004-11-21 12:30:18 +00004945 IRTemp res = newTemp(Ity_I64);
sewardj464efa42004-11-19 22:17:29 +00004946
sewardj38a3f862005-01-13 15:06:51 +00004947 Bool invG = False;
4948 IROp op = Iop_INVALID;
4949 void* hAddr = NULL;
sewardj2d49b432005-02-01 00:37:06 +00004950 HChar* hName = NULL;
sewardj38a3f862005-01-13 15:06:51 +00004951 Bool eLeft = False;
4952
sewardj2b7a9202004-11-26 19:15:38 +00004953# define XXX(_name) do { hAddr = &_name; hName = #_name; } while (0)
sewardj464efa42004-11-19 22:17:29 +00004954
sewardj464efa42004-11-19 22:17:29 +00004955 switch (opc) {
sewardjb5452082004-12-04 20:33:02 +00004956 /* Original MMX ones */
sewardj38a3f862005-01-13 15:06:51 +00004957 case 0xFC: op = Iop_Add8x8; break;
4958 case 0xFD: op = Iop_Add16x4; break;
4959 case 0xFE: op = Iop_Add32x2; break;
sewardj464efa42004-11-19 22:17:29 +00004960
sewardj38a3f862005-01-13 15:06:51 +00004961 case 0xEC: op = Iop_QAdd8Sx8; break;
4962 case 0xED: op = Iop_QAdd16Sx4; break;
sewardj464efa42004-11-19 22:17:29 +00004963
sewardj38a3f862005-01-13 15:06:51 +00004964 case 0xDC: op = Iop_QAdd8Ux8; break;
4965 case 0xDD: op = Iop_QAdd16Ux4; break;
sewardj464efa42004-11-19 22:17:29 +00004966
sewardj38a3f862005-01-13 15:06:51 +00004967 case 0xF8: op = Iop_Sub8x8; break;
4968 case 0xF9: op = Iop_Sub16x4; break;
4969 case 0xFA: op = Iop_Sub32x2; break;
sewardj464efa42004-11-19 22:17:29 +00004970
sewardj38a3f862005-01-13 15:06:51 +00004971 case 0xE8: op = Iop_QSub8Sx8; break;
4972 case 0xE9: op = Iop_QSub16Sx4; break;
sewardj464efa42004-11-19 22:17:29 +00004973
sewardj38a3f862005-01-13 15:06:51 +00004974 case 0xD8: op = Iop_QSub8Ux8; break;
4975 case 0xD9: op = Iop_QSub16Ux4; break;
sewardj464efa42004-11-19 22:17:29 +00004976
sewardj38a3f862005-01-13 15:06:51 +00004977 case 0xE5: op = Iop_MulHi16Sx4; break;
4978 case 0xD5: op = Iop_Mul16x4; break;
4979 case 0xF5: XXX(x86g_calculate_mmx_pmaddwd); break;
sewardj4340dac2004-11-20 13:17:04 +00004980
sewardj38a3f862005-01-13 15:06:51 +00004981 case 0x74: op = Iop_CmpEQ8x8; break;
4982 case 0x75: op = Iop_CmpEQ16x4; break;
4983 case 0x76: op = Iop_CmpEQ32x2; break;
sewardj4340dac2004-11-20 13:17:04 +00004984
sewardj38a3f862005-01-13 15:06:51 +00004985 case 0x64: op = Iop_CmpGT8Sx8; break;
4986 case 0x65: op = Iop_CmpGT16Sx4; break;
4987 case 0x66: op = Iop_CmpGT32Sx2; break;
sewardj63ba4092004-11-21 12:30:18 +00004988
sewardj38a3f862005-01-13 15:06:51 +00004989 case 0x6B: op = Iop_QNarrow32Sx2; eLeft = True; break;
4990 case 0x63: op = Iop_QNarrow16Sx4; eLeft = True; break;
4991 case 0x67: op = Iop_QNarrow16Ux4; eLeft = True; break;
sewardj63ba4092004-11-21 12:30:18 +00004992
sewardj38a3f862005-01-13 15:06:51 +00004993 case 0x68: op = Iop_InterleaveHI8x8; eLeft = True; break;
4994 case 0x69: op = Iop_InterleaveHI16x4; eLeft = True; break;
4995 case 0x6A: op = Iop_InterleaveHI32x2; eLeft = True; break;
sewardj63ba4092004-11-21 12:30:18 +00004996
sewardj38a3f862005-01-13 15:06:51 +00004997 case 0x60: op = Iop_InterleaveLO8x8; eLeft = True; break;
4998 case 0x61: op = Iop_InterleaveLO16x4; eLeft = True; break;
4999 case 0x62: op = Iop_InterleaveLO32x2; eLeft = True; break;
sewardj63ba4092004-11-21 12:30:18 +00005000
sewardj38a3f862005-01-13 15:06:51 +00005001 case 0xDB: op = Iop_And64; break;
5002 case 0xDF: op = Iop_And64; invG = True; break;
5003 case 0xEB: op = Iop_Or64; break;
5004 case 0xEF: /* Possibly do better here if argL and argR are the
5005 same reg */
5006 op = Iop_Xor64; break;
sewardj464efa42004-11-19 22:17:29 +00005007
sewardjb5452082004-12-04 20:33:02 +00005008 /* Introduced in SSE1 */
sewardj38a3f862005-01-13 15:06:51 +00005009 case 0xE0: op = Iop_Avg8Ux8; break;
5010 case 0xE3: op = Iop_Avg16Ux4; break;
5011 case 0xEE: op = Iop_Max16Sx4; break;
5012 case 0xDE: op = Iop_Max8Ux8; break;
5013 case 0xEA: op = Iop_Min16Sx4; break;
5014 case 0xDA: op = Iop_Min8Ux8; break;
5015 case 0xE4: op = Iop_MulHi16Ux4; break;
5016 case 0xF6: XXX(x86g_calculate_mmx_psadbw); break;
sewardjb5452082004-12-04 20:33:02 +00005017
sewardj164f9272004-12-09 00:39:32 +00005018 /* Introduced in SSE2 */
sewardj38a3f862005-01-13 15:06:51 +00005019 case 0xD4: op = Iop_Add64; break;
5020 case 0xFB: op = Iop_Sub64; break;
sewardj164f9272004-12-09 00:39:32 +00005021
sewardj464efa42004-11-19 22:17:29 +00005022 default:
5023 vex_printf("\n0x%x\n", (Int)opc);
5024 vpanic("dis_MMXop_regmem_to_reg");
5025 }
5026
5027# undef XXX
5028
sewardj38a3f862005-01-13 15:06:51 +00005029 argG = getMMXReg(gregOfRM(modrm));
5030 if (invG)
5031 argG = unop(Iop_Not64, argG);
sewardj63ba4092004-11-21 12:30:18 +00005032
sewardj464efa42004-11-19 22:17:29 +00005033 if (isReg) {
sewardj464efa42004-11-19 22:17:29 +00005034 delta++;
sewardj38a3f862005-01-13 15:06:51 +00005035 argE = getMMXReg(eregOfRM(modrm));
sewardj464efa42004-11-19 22:17:29 +00005036 } else {
5037 Int len;
5038 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5039 delta += len;
sewardj38a3f862005-01-13 15:06:51 +00005040 argE = loadLE(Ity_I64, mkexpr(addr));
sewardj464efa42004-11-19 22:17:29 +00005041 }
5042
sewardj38a3f862005-01-13 15:06:51 +00005043 if (eLeft) {
5044 argL = argE;
5045 argR = argG;
5046 } else {
5047 argL = argG;
5048 argR = argE;
5049 }
5050
5051 if (op != Iop_INVALID) {
5052 vassert(hName == NULL);
5053 vassert(hAddr == NULL);
5054 assign(res, binop(op, argL, argR));
5055 } else {
5056 vassert(hName != NULL);
5057 vassert(hAddr != NULL);
5058 assign( res,
5059 mkIRExprCCall(
5060 Ity_I64,
5061 0/*regparms*/, hName, hAddr,
5062 mkIRExprVec_2( argL, argR )
5063 )
5064 );
sewardj63ba4092004-11-21 12:30:18 +00005065 }
5066
5067 putMMXReg( gregOfRM(modrm), mkexpr(res) );
5068
sewardj464efa42004-11-19 22:17:29 +00005069 DIP("%s%s %s, %s\n",
sewardj2d49b432005-02-01 00:37:06 +00005070 name, show_granularity ? nameMMXGran(opc & 3) : "",
sewardj464efa42004-11-19 22:17:29 +00005071 ( isReg ? nameMMXReg(eregOfRM(modrm)) : dis_buf ),
5072 nameMMXReg(gregOfRM(modrm)) );
5073
5074 return delta;
5075}
5076
5077
sewardj38a3f862005-01-13 15:06:51 +00005078/* Vector by scalar shift of G by the amount specified at the bottom
5079 of E. This is a straight copy of dis_SSE_shiftG_byE. */
5080
sewardj52d04912005-07-03 00:52:48 +00005081static UInt dis_MMX_shiftG_byE ( UChar sorb, Int delta,
sewardj38a3f862005-01-13 15:06:51 +00005082 HChar* opname, IROp op )
5083{
5084 HChar dis_buf[50];
5085 Int alen, size;
5086 IRTemp addr;
5087 Bool shl, shr, sar;
5088 UChar rm = getIByte(delta);
5089 IRTemp g0 = newTemp(Ity_I64);
5090 IRTemp g1 = newTemp(Ity_I64);
5091 IRTemp amt = newTemp(Ity_I32);
5092 IRTemp amt8 = newTemp(Ity_I8);
5093
5094 if (epartIsReg(rm)) {
5095 assign( amt, unop(Iop_64to32, getMMXReg(eregOfRM(rm))) );
5096 DIP("%s %s,%s\n", opname,
5097 nameMMXReg(eregOfRM(rm)),
5098 nameMMXReg(gregOfRM(rm)) );
5099 delta++;
5100 } else {
5101 addr = disAMode ( &alen, sorb, delta, dis_buf );
5102 assign( amt, loadLE(Ity_I32, mkexpr(addr)) );
5103 DIP("%s %s,%s\n", opname,
5104 dis_buf,
5105 nameMMXReg(gregOfRM(rm)) );
5106 delta += alen;
5107 }
5108 assign( g0, getMMXReg(gregOfRM(rm)) );
5109 assign( amt8, unop(Iop_32to8, mkexpr(amt)) );
5110
5111 shl = shr = sar = False;
5112 size = 0;
5113 switch (op) {
5114 case Iop_ShlN16x4: shl = True; size = 32; break;
5115 case Iop_ShlN32x2: shl = True; size = 32; break;
5116 case Iop_Shl64: shl = True; size = 64; break;
5117 case Iop_ShrN16x4: shr = True; size = 16; break;
5118 case Iop_ShrN32x2: shr = True; size = 32; break;
5119 case Iop_Shr64: shr = True; size = 64; break;
5120 case Iop_SarN16x4: sar = True; size = 16; break;
5121 case Iop_SarN32x2: sar = True; size = 32; break;
5122 default: vassert(0);
5123 }
5124
5125 if (shl || shr) {
5126 assign(
5127 g1,
5128 IRExpr_Mux0X(
5129 unop(Iop_1Uto8,binop(Iop_CmpLT32U,mkexpr(amt),mkU32(size))),
5130 mkU64(0),
5131 binop(op, mkexpr(g0), mkexpr(amt8))
5132 )
5133 );
5134 } else
5135 if (sar) {
5136 assign(
5137 g1,
5138 IRExpr_Mux0X(
5139 unop(Iop_1Uto8,binop(Iop_CmpLT32U,mkexpr(amt),mkU32(size))),
5140 binop(op, mkexpr(g0), mkU8(size-1)),
5141 binop(op, mkexpr(g0), mkexpr(amt8))
5142 )
5143 );
5144 } else {
sewardjba89f4c2005-04-07 17:31:27 +00005145 /*NOTREACHED*/
sewardj38a3f862005-01-13 15:06:51 +00005146 vassert(0);
5147 }
5148
5149 putMMXReg( gregOfRM(rm), mkexpr(g1) );
5150 return delta;
5151}
5152
5153
5154/* Vector by scalar shift of E by an immediate byte. This is a
5155 straight copy of dis_SSE_shiftE_imm. */
5156
5157static
sewardj52d04912005-07-03 00:52:48 +00005158UInt dis_MMX_shiftE_imm ( Int delta, HChar* opname, IROp op )
sewardj38a3f862005-01-13 15:06:51 +00005159{
5160 Bool shl, shr, sar;
5161 UChar rm = getIByte(delta);
5162 IRTemp e0 = newTemp(Ity_I64);
5163 IRTemp e1 = newTemp(Ity_I64);
5164 UChar amt, size;
5165 vassert(epartIsReg(rm));
5166 vassert(gregOfRM(rm) == 2
5167 || gregOfRM(rm) == 4 || gregOfRM(rm) == 6);
sewardj2d49b432005-02-01 00:37:06 +00005168 amt = getIByte(delta+1);
sewardj38a3f862005-01-13 15:06:51 +00005169 delta += 2;
5170 DIP("%s $%d,%s\n", opname,
5171 (Int)amt,
5172 nameMMXReg(eregOfRM(rm)) );
5173
5174 assign( e0, getMMXReg(eregOfRM(rm)) );
5175
5176 shl = shr = sar = False;
5177 size = 0;
5178 switch (op) {
5179 case Iop_ShlN16x4: shl = True; size = 16; break;
5180 case Iop_ShlN32x2: shl = True; size = 32; break;
5181 case Iop_Shl64: shl = True; size = 64; break;
5182 case Iop_SarN16x4: sar = True; size = 16; break;
5183 case Iop_SarN32x2: sar = True; size = 32; break;
5184 case Iop_ShrN16x4: shr = True; size = 16; break;
5185 case Iop_ShrN32x2: shr = True; size = 32; break;
5186 case Iop_Shr64: shr = True; size = 64; break;
5187 default: vassert(0);
5188 }
5189
5190 if (shl || shr) {
sewardjba89f4c2005-04-07 17:31:27 +00005191 assign( e1, amt >= size
5192 ? mkU64(0)
5193 : binop(op, mkexpr(e0), mkU8(amt))
5194 );
sewardj38a3f862005-01-13 15:06:51 +00005195 } else
5196 if (sar) {
sewardjba89f4c2005-04-07 17:31:27 +00005197 assign( e1, amt >= size
5198 ? binop(op, mkexpr(e0), mkU8(size-1))
5199 : binop(op, mkexpr(e0), mkU8(amt))
5200 );
sewardj38a3f862005-01-13 15:06:51 +00005201 } else {
sewardjba89f4c2005-04-07 17:31:27 +00005202 /*NOTREACHED*/
sewardj38a3f862005-01-13 15:06:51 +00005203 vassert(0);
5204 }
5205
5206 putMMXReg( eregOfRM(rm), mkexpr(e1) );
5207 return delta;
5208}
5209
5210
5211/* Completely handle all MMX instructions except emms. */
sewardj464efa42004-11-19 22:17:29 +00005212
5213static
sewardj52d04912005-07-03 00:52:48 +00005214UInt dis_MMX ( Bool* decode_ok, UChar sorb, Int sz, Int delta )
sewardj464efa42004-11-19 22:17:29 +00005215{
5216 Int len;
5217 UChar modrm;
sewardjc9a43662004-11-30 18:51:59 +00005218 HChar dis_buf[50];
sewardj464efa42004-11-19 22:17:29 +00005219 UChar opc = getIByte(delta);
5220 delta++;
5221
sewardj4cb918d2004-12-03 19:43:31 +00005222 /* dis_MMX handles all insns except emms. */
5223 do_MMX_preamble();
sewardj464efa42004-11-19 22:17:29 +00005224
5225 switch (opc) {
5226
sewardj2b7a9202004-11-26 19:15:38 +00005227 case 0x6E:
5228 /* MOVD (src)ireg-or-mem (E), (dst)mmxreg (G)*/
sewardj9df271d2004-12-31 22:37:42 +00005229 if (sz != 4)
5230 goto mmx_decode_failure;
sewardj2b7a9202004-11-26 19:15:38 +00005231 modrm = getIByte(delta);
5232 if (epartIsReg(modrm)) {
5233 delta++;
5234 putMMXReg(
5235 gregOfRM(modrm),
5236 binop( Iop_32HLto64,
5237 mkU32(0),
5238 getIReg(4, eregOfRM(modrm)) ) );
5239 DIP("movd %s, %s\n",
5240 nameIReg(4,eregOfRM(modrm)), nameMMXReg(gregOfRM(modrm)));
5241 } else {
5242 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5243 delta += len;
5244 putMMXReg(
5245 gregOfRM(modrm),
5246 binop( Iop_32HLto64,
5247 mkU32(0),
5248 loadLE(Ity_I32, mkexpr(addr)) ) );
5249 DIP("movd %s, %s\n", dis_buf, nameMMXReg(gregOfRM(modrm)));
5250 }
5251 break;
5252
5253 case 0x7E: /* MOVD (src)mmxreg (G), (dst)ireg-or-mem (E) */
sewardj9df271d2004-12-31 22:37:42 +00005254 if (sz != 4)
5255 goto mmx_decode_failure;
sewardj2b7a9202004-11-26 19:15:38 +00005256 modrm = getIByte(delta);
5257 if (epartIsReg(modrm)) {
5258 delta++;
5259 putIReg( 4, eregOfRM(modrm),
5260 unop(Iop_64to32, getMMXReg(gregOfRM(modrm)) ) );
5261 DIP("movd %s, %s\n",
5262 nameMMXReg(gregOfRM(modrm)), nameIReg(4,eregOfRM(modrm)));
5263 } else {
5264 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5265 delta += len;
5266 storeLE( mkexpr(addr),
5267 unop(Iop_64to32, getMMXReg(gregOfRM(modrm)) ) );
5268 DIP("movd %s, %s\n", nameMMXReg(gregOfRM(modrm)), dis_buf);
5269 }
5270 break;
5271
sewardj464efa42004-11-19 22:17:29 +00005272 case 0x6F:
5273 /* MOVQ (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005274 if (sz != 4)
5275 goto mmx_decode_failure;
sewardj464efa42004-11-19 22:17:29 +00005276 modrm = getIByte(delta);
5277 if (epartIsReg(modrm)) {
5278 delta++;
5279 putMMXReg( gregOfRM(modrm), getMMXReg(eregOfRM(modrm)) );
5280 DIP("movq %s, %s\n",
5281 nameMMXReg(eregOfRM(modrm)), nameMMXReg(gregOfRM(modrm)));
5282 } else {
5283 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5284 delta += len;
5285 putMMXReg( gregOfRM(modrm), loadLE(Ity_I64, mkexpr(addr)) );
5286 DIP("movq %s, %s\n",
5287 dis_buf, nameMMXReg(gregOfRM(modrm)));
5288 }
5289 break;
5290
5291 case 0x7F:
5292 /* MOVQ (src)mmxreg, (dst)mmxreg-or-mem */
sewardj9df271d2004-12-31 22:37:42 +00005293 if (sz != 4)
5294 goto mmx_decode_failure;
sewardj464efa42004-11-19 22:17:29 +00005295 modrm = getIByte(delta);
5296 if (epartIsReg(modrm)) {
sewardjc2feffc2004-12-08 12:31:22 +00005297 /* Fall through. The assembler doesn't appear to generate
5298 these. */
5299 goto mmx_decode_failure;
sewardj464efa42004-11-19 22:17:29 +00005300 } else {
5301 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5302 delta += len;
sewardj893aada2004-11-29 19:57:54 +00005303 storeLE( mkexpr(addr), getMMXReg(gregOfRM(modrm)) );
sewardj464efa42004-11-19 22:17:29 +00005304 DIP("mov(nt)q %s, %s\n",
5305 nameMMXReg(gregOfRM(modrm)), dis_buf);
5306 }
5307 break;
5308
sewardj4340dac2004-11-20 13:17:04 +00005309 case 0xFC:
5310 case 0xFD:
5311 case 0xFE: /* PADDgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005312 if (sz != 4)
5313 goto mmx_decode_failure;
sewardj464efa42004-11-19 22:17:29 +00005314 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "padd", True );
5315 break;
5316
sewardj4340dac2004-11-20 13:17:04 +00005317 case 0xEC:
5318 case 0xED: /* PADDSgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005319 if (sz != 4)
5320 goto mmx_decode_failure;
sewardj464efa42004-11-19 22:17:29 +00005321 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "padds", True );
5322 break;
5323
sewardj4340dac2004-11-20 13:17:04 +00005324 case 0xDC:
5325 case 0xDD: /* PADDUSgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005326 if (sz != 4)
5327 goto mmx_decode_failure;
sewardj464efa42004-11-19 22:17:29 +00005328 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "paddus", True );
5329 break;
5330
sewardj4340dac2004-11-20 13:17:04 +00005331 case 0xF8:
5332 case 0xF9:
5333 case 0xFA: /* PSUBgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005334 if (sz != 4)
5335 goto mmx_decode_failure;
sewardj464efa42004-11-19 22:17:29 +00005336 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "psub", True );
5337 break;
5338
sewardj4340dac2004-11-20 13:17:04 +00005339 case 0xE8:
5340 case 0xE9: /* PSUBSgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005341 if (sz != 4)
5342 goto mmx_decode_failure;
sewardj464efa42004-11-19 22:17:29 +00005343 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "psubs", True );
5344 break;
5345
sewardj4340dac2004-11-20 13:17:04 +00005346 case 0xD8:
5347 case 0xD9: /* PSUBUSgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005348 if (sz != 4)
5349 goto mmx_decode_failure;
sewardj464efa42004-11-19 22:17:29 +00005350 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "psubus", True );
5351 break;
5352
5353 case 0xE5: /* PMULHW (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005354 if (sz != 4)
5355 goto mmx_decode_failure;
sewardj464efa42004-11-19 22:17:29 +00005356 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pmulhw", False );
5357 break;
5358
5359 case 0xD5: /* PMULLW (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005360 if (sz != 4)
5361 goto mmx_decode_failure;
sewardj464efa42004-11-19 22:17:29 +00005362 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pmullw", False );
5363 break;
5364
sewardj4340dac2004-11-20 13:17:04 +00005365 case 0xF5: /* PMADDWD (src)mmxreg-or-mem, (dst)mmxreg */
5366 vassert(sz == 4);
5367 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pmaddwd", False );
5368 break;
5369
5370 case 0x74:
5371 case 0x75:
5372 case 0x76: /* PCMPEQgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005373 if (sz != 4)
5374 goto mmx_decode_failure;
sewardj4340dac2004-11-20 13:17:04 +00005375 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pcmpeq", True );
5376 break;
5377
5378 case 0x64:
5379 case 0x65:
5380 case 0x66: /* PCMPGTgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005381 if (sz != 4)
5382 goto mmx_decode_failure;
sewardj4340dac2004-11-20 13:17:04 +00005383 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pcmpgt", True );
5384 break;
5385
sewardj63ba4092004-11-21 12:30:18 +00005386 case 0x6B: /* PACKSSDW (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005387 if (sz != 4)
5388 goto mmx_decode_failure;
sewardj63ba4092004-11-21 12:30:18 +00005389 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "packssdw", False );
5390 break;
5391
5392 case 0x63: /* PACKSSWB (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005393 if (sz != 4)
5394 goto mmx_decode_failure;
sewardj63ba4092004-11-21 12:30:18 +00005395 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "packsswb", False );
5396 break;
5397
5398 case 0x67: /* PACKUSWB (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005399 if (sz != 4)
5400 goto mmx_decode_failure;
sewardj63ba4092004-11-21 12:30:18 +00005401 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "packuswb", False );
5402 break;
5403
5404 case 0x68:
5405 case 0x69:
5406 case 0x6A: /* PUNPCKHgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005407 if (sz != 4)
5408 goto mmx_decode_failure;
sewardj63ba4092004-11-21 12:30:18 +00005409 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "punpckh", True );
5410 break;
5411
5412 case 0x60:
5413 case 0x61:
5414 case 0x62: /* PUNPCKLgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005415 if (sz != 4)
5416 goto mmx_decode_failure;
sewardj63ba4092004-11-21 12:30:18 +00005417 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "punpckl", True );
5418 break;
5419
5420 case 0xDB: /* PAND (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005421 if (sz != 4)
5422 goto mmx_decode_failure;
sewardj63ba4092004-11-21 12:30:18 +00005423 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pand", False );
5424 break;
5425
5426 case 0xDF: /* PANDN (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005427 if (sz != 4)
5428 goto mmx_decode_failure;
sewardj63ba4092004-11-21 12:30:18 +00005429 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pandn", False );
5430 break;
5431
5432 case 0xEB: /* POR (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005433 if (sz != 4)
5434 goto mmx_decode_failure;
sewardj63ba4092004-11-21 12:30:18 +00005435 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "por", False );
5436 break;
5437
5438 case 0xEF: /* PXOR (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005439 if (sz != 4)
5440 goto mmx_decode_failure;
sewardj63ba4092004-11-21 12:30:18 +00005441 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pxor", False );
sewardj38a3f862005-01-13 15:06:51 +00005442 break;
sewardj63ba4092004-11-21 12:30:18 +00005443
sewardj38a3f862005-01-13 15:06:51 +00005444# define SHIFT_BY_REG(_name,_op) \
5445 delta = dis_MMX_shiftG_byE(sorb, delta, _name, _op); \
5446 break;
sewardj8d14a592004-11-21 17:04:50 +00005447
sewardj38a3f862005-01-13 15:06:51 +00005448 /* PSLLgg (src)mmxreg-or-mem, (dst)mmxreg */
5449 case 0xF1: SHIFT_BY_REG("psllw", Iop_ShlN16x4);
5450 case 0xF2: SHIFT_BY_REG("pslld", Iop_ShlN32x2);
5451 case 0xF3: SHIFT_BY_REG("psllq", Iop_Shl64);
sewardj8d14a592004-11-21 17:04:50 +00005452
sewardj38a3f862005-01-13 15:06:51 +00005453 /* PSRLgg (src)mmxreg-or-mem, (dst)mmxreg */
5454 case 0xD1: SHIFT_BY_REG("psrlw", Iop_ShrN16x4);
5455 case 0xD2: SHIFT_BY_REG("psrld", Iop_ShrN32x2);
5456 case 0xD3: SHIFT_BY_REG("psrlq", Iop_Shr64);
5457
5458 /* PSRAgg (src)mmxreg-or-mem, (dst)mmxreg */
5459 case 0xE1: SHIFT_BY_REG("psraw", Iop_SarN16x4);
5460 case 0xE2: SHIFT_BY_REG("psrad", Iop_SarN32x2);
5461
5462# undef SHIFT_BY_REG
sewardj8d14a592004-11-21 17:04:50 +00005463
sewardj2b7a9202004-11-26 19:15:38 +00005464 case 0x71:
5465 case 0x72:
5466 case 0x73: {
5467 /* (sz==4): PSLLgg/PSRAgg/PSRLgg mmxreg by imm8 */
sewardja8415ff2005-01-21 20:55:36 +00005468 UChar byte2, subopc;
sewardj38a3f862005-01-13 15:06:51 +00005469 if (sz != 4)
5470 goto mmx_decode_failure;
sewardj38a3f862005-01-13 15:06:51 +00005471 byte2 = getIByte(delta); /* amode / sub-opcode */
sewardj9b45b482005-02-07 01:42:18 +00005472 subopc = toUChar( (byte2 >> 3) & 7 );
sewardj2b7a9202004-11-26 19:15:38 +00005473
sewardj38a3f862005-01-13 15:06:51 +00005474# define SHIFT_BY_IMM(_name,_op) \
5475 do { delta = dis_MMX_shiftE_imm(delta,_name,_op); \
5476 } while (0)
sewardj2b7a9202004-11-26 19:15:38 +00005477
sewardj2b7a9202004-11-26 19:15:38 +00005478 if (subopc == 2 /*SRL*/ && opc == 0x71)
sewardj38a3f862005-01-13 15:06:51 +00005479 SHIFT_BY_IMM("psrlw", Iop_ShrN16x4);
sewardj2b7a9202004-11-26 19:15:38 +00005480 else if (subopc == 2 /*SRL*/ && opc == 0x72)
sewardj38a3f862005-01-13 15:06:51 +00005481 SHIFT_BY_IMM("psrld", Iop_ShrN32x2);
sewardj2b7a9202004-11-26 19:15:38 +00005482 else if (subopc == 2 /*SRL*/ && opc == 0x73)
sewardj38a3f862005-01-13 15:06:51 +00005483 SHIFT_BY_IMM("psrlq", Iop_Shr64);
sewardj2b7a9202004-11-26 19:15:38 +00005484
5485 else if (subopc == 4 /*SAR*/ && opc == 0x71)
sewardj38a3f862005-01-13 15:06:51 +00005486 SHIFT_BY_IMM("psraw", Iop_SarN16x4);
sewardj2b7a9202004-11-26 19:15:38 +00005487 else if (subopc == 4 /*SAR*/ && opc == 0x72)
sewardj38a3f862005-01-13 15:06:51 +00005488 SHIFT_BY_IMM("psrad", Iop_SarN32x2);
sewardj2b7a9202004-11-26 19:15:38 +00005489
5490 else if (subopc == 6 /*SHL*/ && opc == 0x71)
sewardj38a3f862005-01-13 15:06:51 +00005491 SHIFT_BY_IMM("psllw", Iop_ShlN16x4);
sewardj2b7a9202004-11-26 19:15:38 +00005492 else if (subopc == 6 /*SHL*/ && opc == 0x72)
sewardj38a3f862005-01-13 15:06:51 +00005493 SHIFT_BY_IMM("pslld", Iop_ShlN32x2);
sewardj2b7a9202004-11-26 19:15:38 +00005494 else if (subopc == 6 /*SHL*/ && opc == 0x73)
sewardj38a3f862005-01-13 15:06:51 +00005495 SHIFT_BY_IMM("psllq", Iop_Shl64);
sewardj2b7a9202004-11-26 19:15:38 +00005496
5497 else goto mmx_decode_failure;
5498
sewardj38a3f862005-01-13 15:06:51 +00005499# undef SHIFT_BY_IMM
sewardj2b7a9202004-11-26 19:15:38 +00005500 break;
5501 }
5502
5503 /* --- MMX decode failure --- */
sewardj464efa42004-11-19 22:17:29 +00005504 default:
sewardj2b7a9202004-11-26 19:15:38 +00005505 mmx_decode_failure:
sewardj464efa42004-11-19 22:17:29 +00005506 *decode_ok = False;
5507 return delta; /* ignored */
5508
5509 }
5510
5511 *decode_ok = True;
5512 return delta;
5513}
5514
5515
5516/*------------------------------------------------------------*/
5517/*--- More misc arithmetic and other obscure insns. ---*/
5518/*------------------------------------------------------------*/
sewardja06e5562004-07-14 13:18:05 +00005519
5520/* Double length left and right shifts. Apparently only required in
5521 v-size (no b- variant). */
5522static
5523UInt dis_SHLRD_Gv_Ev ( UChar sorb,
sewardj52d04912005-07-03 00:52:48 +00005524 Int delta, UChar modrm,
sewardja06e5562004-07-14 13:18:05 +00005525 Int sz,
5526 IRExpr* shift_amt,
5527 Bool amt_is_literal,
sewardj2d49b432005-02-01 00:37:06 +00005528 HChar* shift_amt_txt,
sewardja06e5562004-07-14 13:18:05 +00005529 Bool left_shift )
5530{
5531 /* shift_amt :: Ity_I8 is the amount to shift. shift_amt_txt is used
5532 for printing it. And eip on entry points at the modrm byte. */
5533 Int len;
sewardjc9a43662004-11-30 18:51:59 +00005534 HChar dis_buf[50];
sewardja06e5562004-07-14 13:18:05 +00005535
sewardj6d2638e2004-07-15 09:38:27 +00005536 IRType ty = szToITy(sz);
5537 IRTemp gsrc = newTemp(ty);
5538 IRTemp esrc = newTemp(ty);
sewardj92d168d2004-11-15 14:22:12 +00005539 IRTemp addr = IRTemp_INVALID;
sewardj6d2638e2004-07-15 09:38:27 +00005540 IRTemp tmpSH = newTemp(Ity_I8);
sewardj92d168d2004-11-15 14:22:12 +00005541 IRTemp tmpL = IRTemp_INVALID;
5542 IRTemp tmpRes = IRTemp_INVALID;
5543 IRTemp tmpSubSh = IRTemp_INVALID;
sewardja06e5562004-07-14 13:18:05 +00005544 IROp mkpair;
5545 IROp getres;
5546 IROp shift;
sewardja06e5562004-07-14 13:18:05 +00005547 IRExpr* mask = NULL;
5548
5549 vassert(sz == 2 || sz == 4);
5550
5551 /* The E-part is the destination; this is shifted. The G-part
5552 supplies bits to be shifted into the E-part, but is not
5553 changed.
5554
5555 If shifting left, form a double-length word with E at the top
5556 and G at the bottom, and shift this left. The result is then in
5557 the high part.
5558
5559 If shifting right, form a double-length word with G at the top
5560 and E at the bottom, and shift this right. The result is then
5561 at the bottom. */
5562
5563 /* Fetch the operands. */
5564
5565 assign( gsrc, getIReg(sz, gregOfRM(modrm)) );
5566
5567 if (epartIsReg(modrm)) {
5568 delta++;
5569 assign( esrc, getIReg(sz, eregOfRM(modrm)) );
sewardj68511542004-07-28 00:15:44 +00005570 DIP("sh%cd%c %s, %s, %s\n",
sewardja06e5562004-07-14 13:18:05 +00005571 ( left_shift ? 'l' : 'r' ), nameISize(sz),
sewardj68511542004-07-28 00:15:44 +00005572 shift_amt_txt,
sewardja06e5562004-07-14 13:18:05 +00005573 nameIReg(sz, gregOfRM(modrm)), nameIReg(sz, eregOfRM(modrm)));
5574 } else {
5575 addr = disAMode ( &len, sorb, delta, dis_buf );
5576 delta += len;
5577 assign( esrc, loadLE(ty, mkexpr(addr)) );
sewardj68511542004-07-28 00:15:44 +00005578 DIP("sh%cd%c %s, %s, %s\n",
5579 ( left_shift ? 'l' : 'r' ), nameISize(sz),
5580 shift_amt_txt,
5581 nameIReg(sz, gregOfRM(modrm)), dis_buf);
sewardja06e5562004-07-14 13:18:05 +00005582 }
5583
5584 /* Round up the relevant primops. */
5585
5586 if (sz == 4) {
5587 tmpL = newTemp(Ity_I64);
5588 tmpRes = newTemp(Ity_I32);
5589 tmpSubSh = newTemp(Ity_I32);
sewardje539a402004-07-14 18:24:17 +00005590 mkpair = Iop_32HLto64;
sewardj8c7f1ab2004-07-29 20:31:09 +00005591 getres = left_shift ? Iop_64HIto32 : Iop_64to32;
sewardje539a402004-07-14 18:24:17 +00005592 shift = left_shift ? Iop_Shl64 : Iop_Shr64;
5593 mask = mkU8(31);
sewardja06e5562004-07-14 13:18:05 +00005594 } else {
5595 /* sz == 2 */
sewardj8c7f1ab2004-07-29 20:31:09 +00005596 tmpL = newTemp(Ity_I32);
5597 tmpRes = newTemp(Ity_I16);
5598 tmpSubSh = newTemp(Ity_I16);
5599 mkpair = Iop_16HLto32;
5600 getres = left_shift ? Iop_32HIto16 : Iop_32to16;
5601 shift = left_shift ? Iop_Shl32 : Iop_Shr32;
5602 mask = mkU8(15);
sewardja06e5562004-07-14 13:18:05 +00005603 }
5604
5605 /* Do the shift, calculate the subshift value, and set
5606 the flag thunk. */
5607
sewardj8c7f1ab2004-07-29 20:31:09 +00005608 assign( tmpSH, binop(Iop_And8, shift_amt, mask) );
5609
sewardja06e5562004-07-14 13:18:05 +00005610 if (left_shift)
5611 assign( tmpL, binop(mkpair, mkexpr(esrc), mkexpr(gsrc)) );
5612 else
5613 assign( tmpL, binop(mkpair, mkexpr(gsrc), mkexpr(esrc)) );
5614
5615 assign( tmpRes, unop(getres, binop(shift, mkexpr(tmpL), mkexpr(tmpSH)) ) );
5616 assign( tmpSubSh,
5617 unop(getres,
5618 binop(shift,
5619 mkexpr(tmpL),
5620 binop(Iop_And8,
5621 binop(Iop_Sub8, mkexpr(tmpSH), mkU8(1) ),
5622 mask))) );
sewardja06e5562004-07-14 13:18:05 +00005623
sewardj2a2ba8b2004-11-08 13:14:06 +00005624 setFlags_DEP1_DEP2_shift ( left_shift ? Iop_Shl32 : Iop_Sar32,
5625 tmpRes, tmpSubSh, ty, tmpSH );
sewardja06e5562004-07-14 13:18:05 +00005626
5627 /* Put result back. */
5628
5629 if (epartIsReg(modrm)) {
5630 putIReg(sz, eregOfRM(modrm), mkexpr(tmpRes));
5631 } else {
5632 storeLE( mkexpr(addr), mkexpr(tmpRes) );
5633 }
5634
5635 if (amt_is_literal) delta++;
5636 return delta;
5637}
5638
5639
sewardj1c6f9912004-09-07 10:15:24 +00005640/* Handle BT/BTS/BTR/BTC Gv, Ev. Apparently b-size is not
5641 required. */
5642
5643typedef enum { BtOpNone, BtOpSet, BtOpReset, BtOpComp } BtOp;
5644
sewardj2d49b432005-02-01 00:37:06 +00005645static HChar* nameBtOp ( BtOp op )
sewardj1c6f9912004-09-07 10:15:24 +00005646{
5647 switch (op) {
5648 case BtOpNone: return "";
5649 case BtOpSet: return "s";
5650 case BtOpReset: return "r";
5651 case BtOpComp: return "c";
5652 default: vpanic("nameBtOp(x86)");
5653 }
5654}
5655
5656
5657static
sewardj52d04912005-07-03 00:52:48 +00005658UInt dis_bt_G_E ( UChar sorb, Int sz, Int delta, BtOp op )
sewardj1c6f9912004-09-07 10:15:24 +00005659{
sewardjc9a43662004-11-30 18:51:59 +00005660 HChar dis_buf[50];
sewardj1c6f9912004-09-07 10:15:24 +00005661 UChar modrm;
5662 Int len;
5663 IRTemp t_fetched, t_bitno0, t_bitno1, t_bitno2, t_addr0,
5664 t_addr1, t_esp, t_mask;
5665
5666 vassert(sz == 2 || sz == 4);
5667
5668 t_fetched = t_bitno0 = t_bitno1 = t_bitno2
sewardj92d168d2004-11-15 14:22:12 +00005669 = t_addr0 = t_addr1 = t_esp = t_mask = IRTemp_INVALID;
sewardj1c6f9912004-09-07 10:15:24 +00005670
5671 t_fetched = newTemp(Ity_I8);
5672 t_bitno0 = newTemp(Ity_I32);
5673 t_bitno1 = newTemp(Ity_I32);
5674 t_bitno2 = newTemp(Ity_I8);
5675 t_addr1 = newTemp(Ity_I32);
5676 modrm = getIByte(delta);
5677
5678 assign( t_bitno0, widenUto32(getIReg(sz, gregOfRM(modrm))) );
5679
5680 if (epartIsReg(modrm)) {
sewardj1c6f9912004-09-07 10:15:24 +00005681 delta++;
5682 /* Get it onto the client's stack. */
5683 t_esp = newTemp(Ity_I32);
5684 t_addr0 = newTemp(Ity_I32);
5685
5686 assign( t_esp, binop(Iop_Sub32, getIReg(4, R_ESP), mkU32(sz)) );
5687 putIReg(4, R_ESP, mkexpr(t_esp));
5688
5689 storeLE( mkexpr(t_esp), getIReg(sz, eregOfRM(modrm)) );
5690
5691 /* Make t_addr0 point at it. */
5692 assign( t_addr0, mkexpr(t_esp) );
5693
5694 /* Mask out upper bits of the shift amount, since we're doing a
5695 reg. */
5696 assign( t_bitno1, binop(Iop_And32,
5697 mkexpr(t_bitno0),
5698 mkU32(sz == 4 ? 31 : 15)) );
5699
5700 } else {
5701 t_addr0 = disAMode ( &len, sorb, delta, dis_buf );
5702 delta += len;
5703 assign( t_bitno1, mkexpr(t_bitno0) );
5704 }
5705
5706 /* At this point: t_addr0 is the address being operated on. If it
5707 was a reg, we will have pushed it onto the client's stack.
5708 t_bitno1 is the bit number, suitably masked in the case of a
5709 reg. */
5710
5711 /* Now the main sequence. */
5712 assign( t_addr1,
5713 binop(Iop_Add32,
5714 mkexpr(t_addr0),
5715 binop(Iop_Sar32, mkexpr(t_bitno1), mkU8(3))) );
5716
5717 /* t_addr1 now holds effective address */
5718
5719 assign( t_bitno2,
5720 unop(Iop_32to8,
5721 binop(Iop_And32, mkexpr(t_bitno1), mkU32(7))) );
5722
5723 /* t_bitno2 contains offset of bit within byte */
5724
5725 if (op != BtOpNone) {
5726 t_mask = newTemp(Ity_I8);
5727 assign( t_mask, binop(Iop_Shl8, mkU8(1), mkexpr(t_bitno2)) );
5728 }
sewardj4963a422004-10-14 23:34:03 +00005729
sewardj1c6f9912004-09-07 10:15:24 +00005730 /* t_mask is now a suitable byte mask */
5731
5732 assign( t_fetched, loadLE(Ity_I8, mkexpr(t_addr1)) );
5733
5734 if (op != BtOpNone) {
5735 switch (op) {
5736 case BtOpSet:
5737 storeLE( mkexpr(t_addr1),
5738 binop(Iop_Or8, mkexpr(t_fetched),
5739 mkexpr(t_mask)) );
5740 break;
5741 case BtOpComp:
5742 storeLE( mkexpr(t_addr1),
5743 binop(Iop_Xor8, mkexpr(t_fetched),
5744 mkexpr(t_mask)) );
5745 break;
5746 case BtOpReset:
5747 storeLE( mkexpr(t_addr1),
5748 binop(Iop_And8, mkexpr(t_fetched),
5749 unop(Iop_Not8, mkexpr(t_mask))) );
5750 break;
5751 default:
5752 vpanic("dis_bt_G_E(x86)");
5753 }
5754 }
5755
5756 /* Side effect done; now get selected bit into Carry flag */
sewardj2a2ba8b2004-11-08 13:14:06 +00005757 /* Flags: C=selected bit, O,S,Z,A,P undefined, so are set to zero. */
sewardj2a9ad022004-11-25 02:46:58 +00005758 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
sewardj2a2ba8b2004-11-08 13:14:06 +00005759 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
sewardj1c6f9912004-09-07 10:15:24 +00005760 stmt( IRStmt_Put(
sewardj2a2ba8b2004-11-08 13:14:06 +00005761 OFFB_CC_DEP1,
sewardj1c6f9912004-09-07 10:15:24 +00005762 binop(Iop_And32,
5763 binop(Iop_Shr32,
5764 unop(Iop_8Uto32, mkexpr(t_fetched)),
sewardj5bd4d162004-11-10 13:02:48 +00005765 mkexpr(t_bitno2)),
5766 mkU32(1)))
sewardj1c6f9912004-09-07 10:15:24 +00005767 );
sewardja3b7e3a2005-04-05 01:54:19 +00005768 /* Set NDEP even though it isn't used. This makes redundant-PUT
5769 elimination of previous stores to this field work better. */
5770 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardj1c6f9912004-09-07 10:15:24 +00005771
5772 /* Move reg operand from stack back to reg */
5773 if (epartIsReg(modrm)) {
5774 /* t_esp still points at it. */
sewardj4963a422004-10-14 23:34:03 +00005775 putIReg(sz, eregOfRM(modrm), loadLE(szToITy(sz), mkexpr(t_esp)) );
sewardj1c6f9912004-09-07 10:15:24 +00005776 putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t_esp), mkU32(sz)) );
5777 }
5778
5779 DIP("bt%s%c %s, %s\n",
5780 nameBtOp(op), nameISize(sz), nameIReg(sz, gregOfRM(modrm)),
5781 ( epartIsReg(modrm) ? nameIReg(sz, eregOfRM(modrm)) : dis_buf ) );
5782
5783 return delta;
5784}
sewardjce646f22004-08-31 23:55:54 +00005785
5786
5787
5788/* Handle BSF/BSR. Only v-size seems necessary. */
5789static
sewardj52d04912005-07-03 00:52:48 +00005790UInt dis_bs_E_G ( UChar sorb, Int sz, Int delta, Bool fwds )
sewardjce646f22004-08-31 23:55:54 +00005791{
5792 Bool isReg;
5793 UChar modrm;
sewardjc9a43662004-11-30 18:51:59 +00005794 HChar dis_buf[50];
sewardjce646f22004-08-31 23:55:54 +00005795
5796 IRType ty = szToITy(sz);
5797 IRTemp src = newTemp(ty);
5798 IRTemp dst = newTemp(ty);
5799
5800 IRTemp src32 = newTemp(Ity_I32);
5801 IRTemp dst32 = newTemp(Ity_I32);
5802 IRTemp src8 = newTemp(Ity_I8);
5803
5804 vassert(sz == 4 || sz == 2);
sewardjce646f22004-08-31 23:55:54 +00005805
5806 modrm = getIByte(delta);
5807
5808 isReg = epartIsReg(modrm);
5809 if (isReg) {
5810 delta++;
5811 assign( src, getIReg(sz, eregOfRM(modrm)) );
5812 } else {
5813 Int len;
5814 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5815 delta += len;
5816 assign( src, loadLE(ty, mkexpr(addr)) );
5817 }
5818
5819 DIP("bs%c%c %s, %s\n",
5820 fwds ? 'f' : 'r', nameISize(sz),
5821 ( isReg ? nameIReg(sz, eregOfRM(modrm)) : dis_buf ),
5822 nameIReg(sz, gregOfRM(modrm)));
5823
5824 /* Generate an 8-bit expression which is zero iff the
5825 original is zero, and nonzero otherwise */
5826 assign( src8,
5827 unop(Iop_1Uto8, binop(mkSizedOp(ty,Iop_CmpNE8),
5828 mkexpr(src), mkU(ty,0))) );
5829
5830 /* Flags: Z is 1 iff source value is zero. All others
5831 are undefined -- we force them to zero. */
sewardj2a9ad022004-11-25 02:46:58 +00005832 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
sewardj2a2ba8b2004-11-08 13:14:06 +00005833 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
sewardjce646f22004-08-31 23:55:54 +00005834 stmt( IRStmt_Put(
sewardj2a2ba8b2004-11-08 13:14:06 +00005835 OFFB_CC_DEP1,
sewardjce646f22004-08-31 23:55:54 +00005836 IRExpr_Mux0X( mkexpr(src8),
5837 /* src==0 */
sewardj2a9ad022004-11-25 02:46:58 +00005838 mkU32(X86G_CC_MASK_Z),
sewardjce646f22004-08-31 23:55:54 +00005839 /* src!=0 */
5840 mkU32(0)
5841 )
5842 ));
sewardja3b7e3a2005-04-05 01:54:19 +00005843 /* Set NDEP even though it isn't used. This makes redundant-PUT
5844 elimination of previous stores to this field work better. */
5845 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardjce646f22004-08-31 23:55:54 +00005846
5847 /* Result: iff source value is zero, we can't use
5848 Iop_Clz32/Iop_Ctz32 as they have no defined result in that case.
5849 But anyway, Intel x86 semantics say the result is undefined in
5850 such situations. Hence handle the zero case specially. */
5851
5852 /* Bleh. What we compute:
5853
5854 bsf32: if src == 0 then 0 else Ctz32(src)
5855 bsr32: if src == 0 then 0 else 31 - Clz32(src)
5856
5857 bsf16: if src == 0 then 0 else Ctz32(16Uto32(src))
5858 bsr16: if src == 0 then 0 else 31 - Clz32(16Uto32(src))
5859
5860 First, widen src to 32 bits if it is not already.
sewardj37158712004-10-15 21:23:12 +00005861
5862 Postscript 15 Oct 04: it seems that at least VIA Nehemiah leaves the
5863 dst register unchanged when src == 0. Hence change accordingly.
sewardjce646f22004-08-31 23:55:54 +00005864 */
5865 if (sz == 2)
5866 assign( src32, unop(Iop_16Uto32, mkexpr(src)) );
5867 else
5868 assign( src32, mkexpr(src) );
5869
5870 /* The main computation, guarding against zero. */
5871 assign( dst32,
5872 IRExpr_Mux0X(
5873 mkexpr(src8),
sewardj37158712004-10-15 21:23:12 +00005874 /* src == 0 -- leave dst unchanged */
5875 widenUto32( getIReg( sz, gregOfRM(modrm) ) ),
sewardjce646f22004-08-31 23:55:54 +00005876 /* src != 0 */
5877 fwds ? unop(Iop_Ctz32, mkexpr(src32))
5878 : binop(Iop_Sub32,
5879 mkU32(31),
5880 unop(Iop_Clz32, mkexpr(src32)))
5881 )
5882 );
5883
5884 if (sz == 2)
5885 assign( dst, unop(Iop_32to16, mkexpr(dst32)) );
5886 else
5887 assign( dst, mkexpr(dst32) );
5888
5889 /* dump result back */
5890 putIReg( sz, gregOfRM(modrm), mkexpr(dst) );
5891
5892 return delta;
5893}
sewardj64e1d652004-07-12 14:00:46 +00005894
5895
5896static
5897void codegen_xchg_eAX_Reg ( Int sz, Int reg )
5898{
5899 IRType ty = szToITy(sz);
5900 IRTemp t1 = newTemp(ty);
5901 IRTemp t2 = newTemp(ty);
5902 vassert(sz == 2 || sz == 4);
5903 assign( t1, getIReg(sz, R_EAX) );
5904 assign( t2, getIReg(sz, reg) );
5905 putIReg( sz, R_EAX, mkexpr(t2) );
5906 putIReg( sz, reg, mkexpr(t1) );
5907 DIP("xchg%c %s, %s\n",
5908 nameISize(sz), nameIReg(sz, R_EAX), nameIReg(sz, reg));
5909}
5910
5911
sewardjbdc7d212004-09-09 02:46:40 +00005912static
5913void codegen_SAHF ( void )
5914{
5915 /* Set the flags to:
sewardj2a9ad022004-11-25 02:46:58 +00005916 (x86g_calculate_flags_all() & X86G_CC_MASK_O) -- retain the old O flag
5917 | (%AH & (X86G_CC_MASK_S|X86G_CC_MASK_Z|X86G_CC_MASK_A
5918 |X86G_CC_MASK_P|X86G_CC_MASK_C)
sewardjbdc7d212004-09-09 02:46:40 +00005919 */
sewardj2a9ad022004-11-25 02:46:58 +00005920 UInt mask_SZACP = X86G_CC_MASK_S|X86G_CC_MASK_Z|X86G_CC_MASK_A
5921 |X86G_CC_MASK_C|X86G_CC_MASK_P;
sewardjbdc7d212004-09-09 02:46:40 +00005922 IRTemp oldflags = newTemp(Ity_I32);
sewardj2a9ad022004-11-25 02:46:58 +00005923 assign( oldflags, mk_x86g_calculate_eflags_all() );
5924 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
sewardj2a2ba8b2004-11-08 13:14:06 +00005925 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
5926 stmt( IRStmt_Put( OFFB_CC_DEP1,
sewardjbdc7d212004-09-09 02:46:40 +00005927 binop(Iop_Or32,
sewardj2a9ad022004-11-25 02:46:58 +00005928 binop(Iop_And32, mkexpr(oldflags), mkU32(X86G_CC_MASK_O)),
sewardjbdc7d212004-09-09 02:46:40 +00005929 binop(Iop_And32,
5930 binop(Iop_Shr32, getIReg(4, R_EAX), mkU8(8)),
5931 mkU32(mask_SZACP))
5932 )
5933 ));
sewardja3b7e3a2005-04-05 01:54:19 +00005934 /* Set NDEP even though it isn't used. This makes redundant-PUT
5935 elimination of previous stores to this field work better. */
5936 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardjbdc7d212004-09-09 02:46:40 +00005937}
5938
5939
sewardjc9a65702004-07-07 16:32:57 +00005940//-- static
5941//-- void codegen_LAHF ( UCodeBlock* cb )
5942//-- {
5943//-- Int t = newTemp(cb);
5944//--
5945//-- /* Pushed arg is ignored, it just provides somewhere to put the
5946//-- return value. */
5947//-- uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, t);
5948//-- uInstr0(cb, CALLM_S, 0);
5949//-- uInstr1(cb, PUSH, 4, TempReg, t);
5950//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_LAHF));
5951//-- uFlagsRWU(cb, FlagsSZACP, FlagsEmpty, FlagsEmpty);
5952//-- uInstr1(cb, POP, 4, TempReg, t);
5953//-- uInstr0(cb, CALLM_E, 0);
5954//--
5955//-- /* At this point, the %ah sub-register in %eax has been updated,
5956//-- the rest is the same, so do a PUT of the whole thing. */
5957//-- uInstr2(cb, PUT, 4, TempReg, t, ArchReg, R_EAX);
5958//-- }
5959//--
sewardj458a6f82004-08-25 12:46:02 +00005960
5961static
5962UInt dis_cmpxchg_G_E ( UChar sorb,
5963 Int size,
sewardj52d04912005-07-03 00:52:48 +00005964 Int delta0 )
sewardj458a6f82004-08-25 12:46:02 +00005965{
sewardjc9a43662004-11-30 18:51:59 +00005966 HChar dis_buf[50];
sewardj458a6f82004-08-25 12:46:02 +00005967 Int len;
5968
5969 IRType ty = szToITy(size);
5970 IRTemp acc = newTemp(ty);
5971 IRTemp src = newTemp(ty);
sewardj2a2ba8b2004-11-08 13:14:06 +00005972 //IRTemp res = newTemp(ty);
sewardj458a6f82004-08-25 12:46:02 +00005973 IRTemp dest = newTemp(ty);
5974 IRTemp dest2 = newTemp(ty);
5975 IRTemp acc2 = newTemp(ty);
5976 IRTemp cond8 = newTemp(Ity_I8);
sewardj92d168d2004-11-15 14:22:12 +00005977 IRTemp addr = IRTemp_INVALID;
sewardj458a6f82004-08-25 12:46:02 +00005978 UChar rm = getUChar(delta0);
5979
5980 if (epartIsReg(rm)) {
5981 assign( dest, getIReg(size, eregOfRM(rm)) );
5982 delta0++;
5983 DIP("cmpxchg%c %s,%s\n", nameISize(size),
5984 nameIReg(size,gregOfRM(rm)),
5985 nameIReg(size,eregOfRM(rm)) );
sewardj458a6f82004-08-25 12:46:02 +00005986 } else {
5987 addr = disAMode ( &len, sorb, delta0, dis_buf );
5988 assign( dest, loadLE(ty, mkexpr(addr)) );
5989 delta0 += len;
5990 DIP("cmpxchg%c %s,%s\n", nameISize(size),
5991 nameIReg(size,gregOfRM(rm)), dis_buf);
5992 }
5993
5994 assign( src, getIReg(size, gregOfRM(rm)) );
5995 assign( acc, getIReg(size, R_EAX) );
sewardj2a2ba8b2004-11-08 13:14:06 +00005996 //assign( res, binop( mkSizedOp(ty,Iop_Sub8), mkexpr(acc), mkexpr(dest) ));
5997 setFlags_DEP1_DEP2(Iop_Sub8, acc, dest, ty);
sewardj2a9ad022004-11-25 02:46:58 +00005998 assign( cond8, unop(Iop_1Uto8, mk_x86g_calculate_condition(X86CondZ)) );
sewardj458a6f82004-08-25 12:46:02 +00005999 assign( dest2, IRExpr_Mux0X(mkexpr(cond8), mkexpr(dest), mkexpr(src)) );
6000 assign( acc2, IRExpr_Mux0X(mkexpr(cond8), mkexpr(dest), mkexpr(acc)) );
6001 putIReg(size, R_EAX, mkexpr(acc2));
6002
6003 if (epartIsReg(rm)) {
6004 putIReg(size, eregOfRM(rm), mkexpr(dest2));
6005 } else {
6006 storeLE( mkexpr(addr), mkexpr(dest2) );
6007 }
6008
6009 return delta0;
6010}
6011
6012
sewardjc9a65702004-07-07 16:32:57 +00006013//-- static
6014//-- Addr dis_cmpxchg8b ( UCodeBlock* cb,
6015//-- UChar sorb,
6016//-- Addr eip0 )
6017//-- {
6018//-- Int tal, tah, junkl, junkh, destl, desth, srcl, srch, accl, acch;
sewardjc9a43662004-11-30 18:51:59 +00006019//-- HChar dis_buf[50];
sewardjc9a65702004-07-07 16:32:57 +00006020//-- UChar rm;
6021//-- UInt pair;
6022//--
6023//-- rm = getUChar(eip0);
6024//-- accl = newTemp(cb);
6025//-- acch = newTemp(cb);
6026//-- srcl = newTemp(cb);
6027//-- srch = newTemp(cb);
6028//-- destl = newTemp(cb);
6029//-- desth = newTemp(cb);
6030//-- junkl = newTemp(cb);
6031//-- junkh = newTemp(cb);
6032//--
6033//-- vg_assert(!epartIsReg(rm));
6034//--
6035//-- pair = disAMode ( cb, sorb, eip0, dis_buf );
6036//-- tal = LOW24(pair);
6037//-- tah = newTemp(cb);
6038//-- uInstr2(cb, MOV, 4, TempReg, tal, TempReg, tah);
6039//-- uInstr2(cb, ADD, 4, Literal, 0, TempReg, tah);
6040//-- uLiteral(cb, 4);
6041//-- eip0 += HI8(pair);
6042//-- DIP("cmpxchg8b %s\n", dis_buf);
6043//--
6044//-- uInstr0(cb, CALLM_S, 0);
6045//--
6046//-- uInstr2(cb, LOAD, 4, TempReg, tah, TempReg, desth);
6047//-- uInstr1(cb, PUSH, 4, TempReg, desth);
6048//-- uInstr2(cb, LOAD, 4, TempReg, tal, TempReg, destl);
6049//-- uInstr1(cb, PUSH, 4, TempReg, destl);
6050//-- uInstr2(cb, GET, 4, ArchReg, R_ECX, TempReg, srch);
6051//-- uInstr1(cb, PUSH, 4, TempReg, srch);
6052//-- uInstr2(cb, GET, 4, ArchReg, R_EBX, TempReg, srcl);
6053//-- uInstr1(cb, PUSH, 4, TempReg, srcl);
6054//-- uInstr2(cb, GET, 4, ArchReg, R_EDX, TempReg, acch);
6055//-- uInstr1(cb, PUSH, 4, TempReg, acch);
6056//-- uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, accl);
6057//-- uInstr1(cb, PUSH, 4, TempReg, accl);
6058//--
6059//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_cmpxchg8b));
6060//-- uFlagsRWU(cb, FlagsEmpty, FlagZ, FlagsEmpty);
6061//--
6062//-- uInstr1(cb, POP, 4, TempReg, accl);
6063//-- uInstr2(cb, PUT, 4, TempReg, accl, ArchReg, R_EAX);
6064//-- uInstr1(cb, POP, 4, TempReg, acch);
6065//-- uInstr2(cb, PUT, 4, TempReg, acch, ArchReg, R_EDX);
6066//-- uInstr1(cb, POP, 4, TempReg, srcl);
6067//-- uInstr2(cb, PUT, 4, TempReg, srcl, ArchReg, R_EBX);
6068//-- uInstr1(cb, POP, 4, TempReg, srch);
6069//-- uInstr2(cb, PUT, 4, TempReg, srch, ArchReg, R_ECX);
6070//-- uInstr1(cb, POP, 4, TempReg, destl);
6071//-- uInstr2(cb, STORE, 4, TempReg, destl, TempReg, tal);
6072//-- uInstr1(cb, POP, 4, TempReg, desth);
6073//-- uInstr2(cb, STORE, 4, TempReg, desth, TempReg, tah);
6074//--
6075//-- uInstr0(cb, CALLM_E, 0);
6076//--
6077//-- return eip0;
6078//-- }
sewardj458a6f82004-08-25 12:46:02 +00006079
6080
6081/* Handle conditional move instructions of the form
6082 cmovcc E(reg-or-mem), G(reg)
6083
6084 E(src) is reg-or-mem
6085 G(dst) is reg.
6086
6087 If E is reg, --> GET %E, tmps
6088 GET %G, tmpd
6089 CMOVcc tmps, tmpd
6090 PUT tmpd, %G
6091
6092 If E is mem --> (getAddr E) -> tmpa
6093 LD (tmpa), tmps
6094 GET %G, tmpd
6095 CMOVcc tmps, tmpd
6096 PUT tmpd, %G
6097*/
6098static
6099UInt dis_cmov_E_G ( UChar sorb,
6100 Int sz,
sewardj2a9ad022004-11-25 02:46:58 +00006101 X86Condcode cond,
sewardj52d04912005-07-03 00:52:48 +00006102 Int delta0 )
sewardj458a6f82004-08-25 12:46:02 +00006103{
6104 UChar rm = getIByte(delta0);
sewardjc9a43662004-11-30 18:51:59 +00006105 HChar dis_buf[50];
sewardj458a6f82004-08-25 12:46:02 +00006106 Int len;
6107
sewardj883b00b2004-09-11 09:30:24 +00006108 IRType ty = szToITy(sz);
sewardj458a6f82004-08-25 12:46:02 +00006109 IRTemp tmps = newTemp(ty);
6110 IRTemp tmpd = newTemp(ty);
6111
6112 if (epartIsReg(rm)) {
6113 assign( tmps, getIReg(sz, eregOfRM(rm)) );
6114 assign( tmpd, getIReg(sz, gregOfRM(rm)) );
6115
6116 putIReg(sz, gregOfRM(rm),
sewardj2a9ad022004-11-25 02:46:58 +00006117 IRExpr_Mux0X( unop(Iop_1Uto8,
6118 mk_x86g_calculate_condition(cond)),
sewardj458a6f82004-08-25 12:46:02 +00006119 mkexpr(tmpd),
6120 mkexpr(tmps) )
6121 );
6122 DIP("cmov%c%s %s,%s\n", nameISize(sz),
sewardj2a9ad022004-11-25 02:46:58 +00006123 name_X86Condcode(cond),
sewardj458a6f82004-08-25 12:46:02 +00006124 nameIReg(sz,eregOfRM(rm)),
6125 nameIReg(sz,gregOfRM(rm)));
6126 return 1+delta0;
6127 }
6128
6129 /* E refers to memory */
6130 {
6131 IRTemp addr = disAMode ( &len, sorb, delta0, dis_buf );
6132 assign( tmps, loadLE(ty, mkexpr(addr)) );
6133 assign( tmpd, getIReg(sz, gregOfRM(rm)) );
6134
6135 putIReg(sz, gregOfRM(rm),
sewardj2a9ad022004-11-25 02:46:58 +00006136 IRExpr_Mux0X( unop(Iop_1Uto8,
6137 mk_x86g_calculate_condition(cond)),
sewardj458a6f82004-08-25 12:46:02 +00006138 mkexpr(tmpd),
6139 mkexpr(tmps) )
6140 );
6141
6142 DIP("cmov%c%s %s,%s\n", nameISize(sz),
sewardj2a9ad022004-11-25 02:46:58 +00006143 name_X86Condcode(cond),
sewardj458a6f82004-08-25 12:46:02 +00006144 dis_buf,
6145 nameIReg(sz,gregOfRM(rm)));
6146 return len+delta0;
6147 }
6148}
6149
6150
sewardj883b00b2004-09-11 09:30:24 +00006151static
sewardj52d04912005-07-03 00:52:48 +00006152UInt dis_xadd_G_E ( UChar sorb, Int sz, Int delta0 )
sewardj883b00b2004-09-11 09:30:24 +00006153{
6154 Int len;
6155 UChar rm = getIByte(delta0);
sewardjc9a43662004-11-30 18:51:59 +00006156 HChar dis_buf[50];
sewardj883b00b2004-09-11 09:30:24 +00006157
6158 // Int tmpd = newTemp(cb);
6159 //Int tmpt = newTemp(cb);
6160
6161 IRType ty = szToITy(sz);
6162 IRTemp tmpd = newTemp(ty);
6163 IRTemp tmpt0 = newTemp(ty);
6164 IRTemp tmpt1 = newTemp(ty);
6165
6166 if (epartIsReg(rm)) {
sewardja8415ff2005-01-21 20:55:36 +00006167 unimplemented("x86 xadd instruction with register operand");
sewardj883b00b2004-09-11 09:30:24 +00006168#if 0
6169 uInstr2(cb, GET, sz, ArchReg, eregOfRM(rm), TempReg, tmpd);
6170 uInstr2(cb, GET, sz, ArchReg, gregOfRM(rm), TempReg, tmpt);
6171 uInstr2(cb, ADD, sz, TempReg, tmpd, TempReg, tmpt);
6172 setFlagsFromUOpcode(cb, ADD);
6173 uInstr2(cb, PUT, sz, TempReg, tmpd, ArchReg, gregOfRM(rm));
6174 uInstr2(cb, PUT, sz, TempReg, tmpt, ArchReg, eregOfRM(rm));
6175 DIP("xadd%c %s, %s\n",
6176 nameISize(sz), nameIReg(sz,gregOfRM(rm)), nameIReg(sz,eregOfRM(rm)));
6177 return 1+eip0;
6178#endif
6179 } else {
6180 IRTemp addr = disAMode ( &len, sorb, delta0, dis_buf );
6181 assign( tmpd, loadLE(ty, mkexpr(addr)) );
6182 assign( tmpt0, getIReg(sz, gregOfRM(rm)) );
sewardj883b00b2004-09-11 09:30:24 +00006183 assign( tmpt1, binop(mkSizedOp(ty,Iop_Add8), mkexpr(tmpd), mkexpr(tmpt0)) );
sewardj2a2ba8b2004-11-08 13:14:06 +00006184 setFlags_DEP1_DEP2( Iop_Add8, tmpd, tmpt0, ty );
sewardj883b00b2004-09-11 09:30:24 +00006185 storeLE( mkexpr(addr), mkexpr(tmpt1) );
6186 putIReg(sz, gregOfRM(rm), mkexpr(tmpd));
6187 DIP("xadd%c %s, %s\n",
6188 nameISize(sz), nameIReg(sz,gregOfRM(rm)), dis_buf);
6189 return len+delta0;
6190 }
6191}
6192
sewardjb64821b2004-12-14 10:00:16 +00006193/* Move 16 bits from Ew (ireg or mem) to G (a segment register). */
6194
sewardj7df596b2004-12-06 14:29:12 +00006195static
sewardj52d04912005-07-03 00:52:48 +00006196UInt dis_mov_Ew_Sw ( UChar sorb, Int delta0 )
sewardj7df596b2004-12-06 14:29:12 +00006197{
sewardjb64821b2004-12-14 10:00:16 +00006198 Int len;
6199 IRTemp addr;
6200 UChar rm = getIByte(delta0);
6201 HChar dis_buf[50];
sewardj7df596b2004-12-06 14:29:12 +00006202
6203 if (epartIsReg(rm)) {
6204 putSReg( gregOfRM(rm), getIReg(2, eregOfRM(rm)) );
6205 DIP("movw %s,%s\n", nameIReg(2,eregOfRM(rm)), nameSReg(gregOfRM(rm)));
6206 return 1+delta0;
sewardjb64821b2004-12-14 10:00:16 +00006207 } else {
6208 addr = disAMode ( &len, sorb, delta0, dis_buf );
6209 putSReg( gregOfRM(rm), loadLE(Ity_I16, mkexpr(addr)) );
6210 DIP("movw %s,%s\n", dis_buf, nameSReg(gregOfRM(rm)));
6211 return len+delta0;
sewardj7df596b2004-12-06 14:29:12 +00006212 }
6213}
6214
sewardjb64821b2004-12-14 10:00:16 +00006215/* Move 16 bits from G (a segment register) to Ew (ireg or mem). If
6216 dst is ireg and sz==4, zero out top half of it. */
6217
sewardj063f02f2004-10-20 12:36:12 +00006218static
6219UInt dis_mov_Sw_Ew ( UChar sorb,
6220 Int sz,
sewardj52d04912005-07-03 00:52:48 +00006221 Int delta0 )
sewardj063f02f2004-10-20 12:36:12 +00006222{
sewardjb64821b2004-12-14 10:00:16 +00006223 Int len;
6224 IRTemp addr;
6225 UChar rm = getIByte(delta0);
6226 HChar dis_buf[50];
sewardj063f02f2004-10-20 12:36:12 +00006227
6228 vassert(sz == 2 || sz == 4);
6229
6230 if (epartIsReg(rm)) {
6231 if (sz == 4)
6232 putIReg(4, eregOfRM(rm), unop(Iop_16Uto32, getSReg(gregOfRM(rm))));
6233 else
6234 putIReg(2, eregOfRM(rm), getSReg(gregOfRM(rm)));
6235
6236 DIP("mov %s,%s\n", nameSReg(gregOfRM(rm)), nameIReg(sz,eregOfRM(rm)));
6237 return 1+delta0;
sewardjb64821b2004-12-14 10:00:16 +00006238 } else {
6239 addr = disAMode ( &len, sorb, delta0, dis_buf );
6240 storeLE( mkexpr(addr), getSReg(gregOfRM(rm)) );
sewardj063f02f2004-10-20 12:36:12 +00006241 DIP("mov %s,%s\n", nameSReg(gregOfRM(rm)), dis_buf);
sewardjb64821b2004-12-14 10:00:16 +00006242 return len+delta0;
sewardj063f02f2004-10-20 12:36:12 +00006243 }
sewardj063f02f2004-10-20 12:36:12 +00006244}
6245
6246
sewardjb64821b2004-12-14 10:00:16 +00006247static
6248void dis_push_segreg ( UInt sreg, Int sz )
6249{
6250 IRTemp t1 = newTemp(Ity_I16);
6251 IRTemp ta = newTemp(Ity_I32);
6252 vassert(sz == 2 || sz == 4);
6253
6254 assign( t1, getSReg(sreg) );
6255 assign( ta, binop(Iop_Sub32, getIReg(4, R_ESP), mkU32(sz)) );
6256 putIReg(4, R_ESP, mkexpr(ta));
6257 storeLE( mkexpr(ta), mkexpr(t1) );
6258
6259 DIP("pushw %s\n", nameSReg(sreg));
6260}
6261
6262static
6263void dis_pop_segreg ( UInt sreg, Int sz )
6264{
6265 IRTemp t1 = newTemp(Ity_I16);
6266 IRTemp ta = newTemp(Ity_I32);
6267 vassert(sz == 2 || sz == 4);
6268
6269 assign( ta, getIReg(4, R_ESP) );
6270 assign( t1, loadLE(Ity_I16, mkexpr(ta)) );
6271
6272 putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(ta), mkU32(sz)) );
6273 putSReg( sreg, mkexpr(t1) );
6274 DIP("pop %s\n", nameSReg(sreg));
6275}
sewardje05c42c2004-07-08 20:25:10 +00006276
6277static
6278void dis_ret ( UInt d32 )
6279{
6280 IRTemp t1 = newTemp(Ity_I32), t2 = newTemp(Ity_I32);
6281 assign(t1, getIReg(4,R_ESP));
6282 assign(t2, loadLE(Ity_I32,mkexpr(t1)));
6283 putIReg(4, R_ESP,binop(Iop_Add32, mkexpr(t1), mkU32(4+d32)));
sewardj78c19df2004-07-12 22:49:27 +00006284 jmp_treg(Ijk_Ret,t2);
sewardje05c42c2004-07-08 20:25:10 +00006285}
6286
sewardj4cb918d2004-12-03 19:43:31 +00006287/*------------------------------------------------------------*/
6288/*--- SSE/SSE2/SSE3 helpers ---*/
6289/*------------------------------------------------------------*/
sewardjc9a43662004-11-30 18:51:59 +00006290
sewardj129b3d92004-12-05 15:42:05 +00006291/* Worker function; do not call directly.
6292 Handles full width G = G `op` E and G = (not G) `op` E.
6293*/
6294
6295static UInt dis_SSE_E_to_G_all_wrk (
sewardj52d04912005-07-03 00:52:48 +00006296 UChar sorb, Int delta,
sewardj1e6ad742004-12-02 16:16:11 +00006297 HChar* opname, IROp op,
6298 Bool invertG
6299 )
sewardjc9a43662004-11-30 18:51:59 +00006300{
sewardj1e6ad742004-12-02 16:16:11 +00006301 HChar dis_buf[50];
6302 Int alen;
6303 IRTemp addr;
6304 UChar rm = getIByte(delta);
6305 IRExpr* gpart
sewardjf0c1c582005-02-07 23:47:38 +00006306 = invertG ? unop(Iop_NotV128, getXMMReg(gregOfRM(rm)))
sewardj1e6ad742004-12-02 16:16:11 +00006307 : getXMMReg(gregOfRM(rm));
sewardjc9a43662004-11-30 18:51:59 +00006308 if (epartIsReg(rm)) {
6309 putXMMReg( gregOfRM(rm),
sewardj1e6ad742004-12-02 16:16:11 +00006310 binop(op, gpart,
6311 getXMMReg(eregOfRM(rm))) );
sewardjc9a43662004-11-30 18:51:59 +00006312 DIP("%s %s,%s\n", opname,
6313 nameXMMReg(eregOfRM(rm)),
6314 nameXMMReg(gregOfRM(rm)) );
6315 return delta+1;
6316 } else {
sewardj1e6ad742004-12-02 16:16:11 +00006317 addr = disAMode ( &alen, sorb, delta, dis_buf );
6318 putXMMReg( gregOfRM(rm),
6319 binop(op, gpart,
6320 loadLE(Ity_V128, mkexpr(addr))) );
6321 DIP("%s %s,%s\n", opname,
6322 dis_buf,
6323 nameXMMReg(gregOfRM(rm)) );
6324 return delta+alen;
sewardjc9a43662004-11-30 18:51:59 +00006325 }
6326}
6327
sewardj129b3d92004-12-05 15:42:05 +00006328
6329/* All lanes SSE binary operation, G = G `op` E. */
sewardj1e6ad742004-12-02 16:16:11 +00006330
6331static
sewardj52d04912005-07-03 00:52:48 +00006332UInt dis_SSE_E_to_G_all ( UChar sorb, Int delta, HChar* opname, IROp op )
sewardj1e6ad742004-12-02 16:16:11 +00006333{
sewardj129b3d92004-12-05 15:42:05 +00006334 return dis_SSE_E_to_G_all_wrk( sorb, delta, opname, op, False );
sewardj1e6ad742004-12-02 16:16:11 +00006335}
6336
sewardj129b3d92004-12-05 15:42:05 +00006337/* All lanes SSE binary operation, G = (not G) `op` E. */
6338
6339static
sewardj52d04912005-07-03 00:52:48 +00006340UInt dis_SSE_E_to_G_all_invG ( UChar sorb, Int delta,
sewardj129b3d92004-12-05 15:42:05 +00006341 HChar* opname, IROp op )
6342{
6343 return dis_SSE_E_to_G_all_wrk( sorb, delta, opname, op, True );
6344}
6345
sewardj164f9272004-12-09 00:39:32 +00006346
sewardj129b3d92004-12-05 15:42:05 +00006347/* Lowest 32-bit lane only SSE binary operation, G = G `op` E. */
6348
sewardj52d04912005-07-03 00:52:48 +00006349static UInt dis_SSE_E_to_G_lo32 ( UChar sorb, Int delta,
sewardj129b3d92004-12-05 15:42:05 +00006350 HChar* opname, IROp op )
6351{
6352 HChar dis_buf[50];
6353 Int alen;
6354 IRTemp addr;
6355 UChar rm = getIByte(delta);
6356 IRExpr* gpart = getXMMReg(gregOfRM(rm));
6357 if (epartIsReg(rm)) {
6358 putXMMReg( gregOfRM(rm),
6359 binop(op, gpart,
6360 getXMMReg(eregOfRM(rm))) );
6361 DIP("%s %s,%s\n", opname,
6362 nameXMMReg(eregOfRM(rm)),
6363 nameXMMReg(gregOfRM(rm)) );
6364 return delta+1;
6365 } else {
6366 /* We can only do a 32-bit memory read, so the upper 3/4 of the
6367 E operand needs to be made simply of zeroes. */
6368 IRTemp epart = newTemp(Ity_V128);
6369 addr = disAMode ( &alen, sorb, delta, dis_buf );
sewardjf0c1c582005-02-07 23:47:38 +00006370 assign( epart, unop( Iop_32UtoV128,
sewardj129b3d92004-12-05 15:42:05 +00006371 loadLE(Ity_I32, mkexpr(addr))) );
6372 putXMMReg( gregOfRM(rm),
6373 binop(op, gpart, mkexpr(epart)) );
6374 DIP("%s %s,%s\n", opname,
6375 dis_buf,
6376 nameXMMReg(gregOfRM(rm)) );
6377 return delta+alen;
6378 }
6379}
6380
sewardj164f9272004-12-09 00:39:32 +00006381
sewardj636ad762004-12-07 11:16:04 +00006382/* Lower 64-bit lane only SSE binary operation, G = G `op` E. */
6383
sewardj52d04912005-07-03 00:52:48 +00006384static UInt dis_SSE_E_to_G_lo64 ( UChar sorb, Int delta,
sewardj636ad762004-12-07 11:16:04 +00006385 HChar* opname, IROp op )
6386{
6387 HChar dis_buf[50];
6388 Int alen;
6389 IRTemp addr;
6390 UChar rm = getIByte(delta);
6391 IRExpr* gpart = getXMMReg(gregOfRM(rm));
6392 if (epartIsReg(rm)) {
6393 putXMMReg( gregOfRM(rm),
6394 binop(op, gpart,
6395 getXMMReg(eregOfRM(rm))) );
6396 DIP("%s %s,%s\n", opname,
6397 nameXMMReg(eregOfRM(rm)),
6398 nameXMMReg(gregOfRM(rm)) );
6399 return delta+1;
6400 } else {
6401 /* We can only do a 64-bit memory read, so the upper half of the
6402 E operand needs to be made simply of zeroes. */
6403 IRTemp epart = newTemp(Ity_V128);
6404 addr = disAMode ( &alen, sorb, delta, dis_buf );
sewardjf0c1c582005-02-07 23:47:38 +00006405 assign( epart, unop( Iop_64UtoV128,
sewardj636ad762004-12-07 11:16:04 +00006406 loadLE(Ity_I64, mkexpr(addr))) );
6407 putXMMReg( gregOfRM(rm),
6408 binop(op, gpart, mkexpr(epart)) );
6409 DIP("%s %s,%s\n", opname,
6410 dis_buf,
6411 nameXMMReg(gregOfRM(rm)) );
6412 return delta+alen;
6413 }
6414}
6415
sewardj164f9272004-12-09 00:39:32 +00006416
sewardj129b3d92004-12-05 15:42:05 +00006417/* All lanes unary SSE operation, G = op(E). */
6418
6419static UInt dis_SSE_E_to_G_unary_all (
sewardj52d04912005-07-03 00:52:48 +00006420 UChar sorb, Int delta,
sewardj0bd7ce62004-12-05 02:47:40 +00006421 HChar* opname, IROp op
6422 )
6423{
6424 HChar dis_buf[50];
6425 Int alen;
6426 IRTemp addr;
6427 UChar rm = getIByte(delta);
6428 if (epartIsReg(rm)) {
6429 putXMMReg( gregOfRM(rm),
6430 unop(op, getXMMReg(eregOfRM(rm))) );
6431 DIP("%s %s,%s\n", opname,
6432 nameXMMReg(eregOfRM(rm)),
6433 nameXMMReg(gregOfRM(rm)) );
6434 return delta+1;
6435 } else {
6436 addr = disAMode ( &alen, sorb, delta, dis_buf );
6437 putXMMReg( gregOfRM(rm),
6438 unop(op, loadLE(Ity_V128, mkexpr(addr))) );
6439 DIP("%s %s,%s\n", opname,
6440 dis_buf,
6441 nameXMMReg(gregOfRM(rm)) );
6442 return delta+alen;
6443 }
6444}
6445
sewardj164f9272004-12-09 00:39:32 +00006446
sewardj129b3d92004-12-05 15:42:05 +00006447/* Lowest 32-bit lane only unary SSE operation, G = op(E). */
sewardj0bd7ce62004-12-05 02:47:40 +00006448
sewardj129b3d92004-12-05 15:42:05 +00006449static UInt dis_SSE_E_to_G_unary_lo32 (
sewardj52d04912005-07-03 00:52:48 +00006450 UChar sorb, Int delta,
sewardj129b3d92004-12-05 15:42:05 +00006451 HChar* opname, IROp op
6452 )
6453{
6454 /* First we need to get the old G value and patch the low 32 bits
6455 of the E operand into it. Then apply op and write back to G. */
6456 HChar dis_buf[50];
6457 Int alen;
6458 IRTemp addr;
6459 UChar rm = getIByte(delta);
6460 IRTemp oldG0 = newTemp(Ity_V128);
6461 IRTemp oldG1 = newTemp(Ity_V128);
6462
6463 assign( oldG0, getXMMReg(gregOfRM(rm)) );
6464
6465 if (epartIsReg(rm)) {
6466 assign( oldG1,
sewardjf0c1c582005-02-07 23:47:38 +00006467 binop( Iop_SetV128lo32,
sewardj129b3d92004-12-05 15:42:05 +00006468 mkexpr(oldG0),
sewardj35579be2004-12-06 00:36:25 +00006469 getXMMRegLane32(eregOfRM(rm), 0)) );
sewardj129b3d92004-12-05 15:42:05 +00006470 putXMMReg( gregOfRM(rm), unop(op, mkexpr(oldG1)) );
6471 DIP("%s %s,%s\n", opname,
6472 nameXMMReg(eregOfRM(rm)),
6473 nameXMMReg(gregOfRM(rm)) );
6474 return delta+1;
6475 } else {
6476 addr = disAMode ( &alen, sorb, delta, dis_buf );
6477 assign( oldG1,
sewardjf0c1c582005-02-07 23:47:38 +00006478 binop( Iop_SetV128lo32,
sewardj129b3d92004-12-05 15:42:05 +00006479 mkexpr(oldG0),
6480 loadLE(Ity_I32, mkexpr(addr)) ));
6481 putXMMReg( gregOfRM(rm), unop(op, mkexpr(oldG1)) );
6482 DIP("%s %s,%s\n", opname,
6483 dis_buf,
6484 nameXMMReg(gregOfRM(rm)) );
6485 return delta+alen;
6486 }
6487}
6488
sewardj164f9272004-12-09 00:39:32 +00006489
sewardj008754b2004-12-08 14:37:10 +00006490/* Lowest 64-bit lane only unary SSE operation, G = op(E). */
6491
6492static UInt dis_SSE_E_to_G_unary_lo64 (
sewardj52d04912005-07-03 00:52:48 +00006493 UChar sorb, Int delta,
sewardj008754b2004-12-08 14:37:10 +00006494 HChar* opname, IROp op
6495 )
6496{
6497 /* First we need to get the old G value and patch the low 64 bits
6498 of the E operand into it. Then apply op and write back to G. */
6499 HChar dis_buf[50];
6500 Int alen;
6501 IRTemp addr;
6502 UChar rm = getIByte(delta);
6503 IRTemp oldG0 = newTemp(Ity_V128);
6504 IRTemp oldG1 = newTemp(Ity_V128);
6505
6506 assign( oldG0, getXMMReg(gregOfRM(rm)) );
6507
6508 if (epartIsReg(rm)) {
6509 assign( oldG1,
sewardjf0c1c582005-02-07 23:47:38 +00006510 binop( Iop_SetV128lo64,
sewardj008754b2004-12-08 14:37:10 +00006511 mkexpr(oldG0),
6512 getXMMRegLane64(eregOfRM(rm), 0)) );
6513 putXMMReg( gregOfRM(rm), unop(op, mkexpr(oldG1)) );
6514 DIP("%s %s,%s\n", opname,
6515 nameXMMReg(eregOfRM(rm)),
6516 nameXMMReg(gregOfRM(rm)) );
6517 return delta+1;
6518 } else {
6519 addr = disAMode ( &alen, sorb, delta, dis_buf );
6520 assign( oldG1,
sewardjf0c1c582005-02-07 23:47:38 +00006521 binop( Iop_SetV128lo64,
sewardj008754b2004-12-08 14:37:10 +00006522 mkexpr(oldG0),
6523 loadLE(Ity_I64, mkexpr(addr)) ));
6524 putXMMReg( gregOfRM(rm), unop(op, mkexpr(oldG1)) );
6525 DIP("%s %s,%s\n", opname,
6526 dis_buf,
6527 nameXMMReg(gregOfRM(rm)) );
6528 return delta+alen;
6529 }
6530}
6531
sewardj164f9272004-12-09 00:39:32 +00006532
6533/* SSE integer binary operation:
6534 G = G `op` E (eLeft == False)
6535 G = E `op` G (eLeft == True)
6536*/
6537static UInt dis_SSEint_E_to_G(
sewardj52d04912005-07-03 00:52:48 +00006538 UChar sorb, Int delta,
sewardj164f9272004-12-09 00:39:32 +00006539 HChar* opname, IROp op,
6540 Bool eLeft
6541 )
6542{
6543 HChar dis_buf[50];
6544 Int alen;
6545 IRTemp addr;
6546 UChar rm = getIByte(delta);
6547 IRExpr* gpart = getXMMReg(gregOfRM(rm));
6548 IRExpr* epart = NULL;
6549 if (epartIsReg(rm)) {
6550 epart = getXMMReg(eregOfRM(rm));
6551 DIP("%s %s,%s\n", opname,
6552 nameXMMReg(eregOfRM(rm)),
6553 nameXMMReg(gregOfRM(rm)) );
6554 delta += 1;
6555 } else {
6556 addr = disAMode ( &alen, sorb, delta, dis_buf );
6557 epart = loadLE(Ity_V128, mkexpr(addr));
6558 DIP("%s %s,%s\n", opname,
6559 dis_buf,
6560 nameXMMReg(gregOfRM(rm)) );
6561 delta += alen;
6562 }
6563 putXMMReg( gregOfRM(rm),
6564 eLeft ? binop(op, epart, gpart)
6565 : binop(op, gpart, epart) );
6566 return delta;
6567}
6568
6569
sewardjfd226452004-12-07 19:02:18 +00006570/* Helper for doing SSE FP comparisons. */
sewardj0bd7ce62004-12-05 02:47:40 +00006571
sewardj1e6ad742004-12-02 16:16:11 +00006572static void findSSECmpOp ( Bool* needNot, IROp* op,
6573 Int imm8, Bool all_lanes, Int sz )
6574{
6575 imm8 &= 7;
6576 *needNot = False;
6577 *op = Iop_INVALID;
6578 if (imm8 >= 4) {
6579 *needNot = True;
6580 imm8 -= 4;
6581 }
6582
6583 if (sz == 4 && all_lanes) {
6584 switch (imm8) {
6585 case 0: *op = Iop_CmpEQ32Fx4; return;
6586 case 1: *op = Iop_CmpLT32Fx4; return;
6587 case 2: *op = Iop_CmpLE32Fx4; return;
6588 case 3: *op = Iop_CmpUN32Fx4; return;
6589 default: break;
6590 }
6591 }
6592 if (sz == 4 && !all_lanes) {
6593 switch (imm8) {
6594 case 0: *op = Iop_CmpEQ32F0x4; return;
6595 case 1: *op = Iop_CmpLT32F0x4; return;
6596 case 2: *op = Iop_CmpLE32F0x4; return;
6597 case 3: *op = Iop_CmpUN32F0x4; return;
6598 default: break;
6599 }
6600 }
sewardjfd226452004-12-07 19:02:18 +00006601 if (sz == 8 && all_lanes) {
6602 switch (imm8) {
6603 case 0: *op = Iop_CmpEQ64Fx2; return;
6604 case 1: *op = Iop_CmpLT64Fx2; return;
6605 case 2: *op = Iop_CmpLE64Fx2; return;
6606 case 3: *op = Iop_CmpUN64Fx2; return;
6607 default: break;
6608 }
6609 }
6610 if (sz == 8 && !all_lanes) {
6611 switch (imm8) {
6612 case 0: *op = Iop_CmpEQ64F0x2; return;
6613 case 1: *op = Iop_CmpLT64F0x2; return;
6614 case 2: *op = Iop_CmpLE64F0x2; return;
6615 case 3: *op = Iop_CmpUN64F0x2; return;
6616 default: break;
6617 }
sewardj1e6ad742004-12-02 16:16:11 +00006618 }
6619 vpanic("findSSECmpOp(x86,guest)");
6620}
6621
sewardj129b3d92004-12-05 15:42:05 +00006622/* Handles SSE 32F comparisons. */
6623
sewardj52d04912005-07-03 00:52:48 +00006624static UInt dis_SSEcmp_E_to_G ( UChar sorb, Int delta,
sewardj1e6ad742004-12-02 16:16:11 +00006625 HChar* opname, Bool all_lanes, Int sz )
6626{
6627 HChar dis_buf[50];
6628 Int alen, imm8;
6629 IRTemp addr;
6630 Bool needNot = False;
6631 IROp op = Iop_INVALID;
6632 IRTemp plain = newTemp(Ity_V128);
6633 UChar rm = getIByte(delta);
6634 UShort mask = 0;
6635 vassert(sz == 4 || sz == 8);
6636 if (epartIsReg(rm)) {
6637 imm8 = getIByte(delta+1);
6638 findSSECmpOp(&needNot, &op, imm8, all_lanes, sz);
6639 assign( plain, binop(op, getXMMReg(gregOfRM(rm)),
6640 getXMMReg(eregOfRM(rm))) );
6641 delta += 2;
6642 DIP("%s $%d,%s,%s\n", opname,
6643 (Int)imm8,
6644 nameXMMReg(eregOfRM(rm)),
6645 nameXMMReg(gregOfRM(rm)) );
6646 } else {
6647 addr = disAMode ( &alen, sorb, delta, dis_buf );
6648 imm8 = getIByte(delta+alen);
6649 findSSECmpOp(&needNot, &op, imm8, all_lanes, sz);
6650 assign( plain, binop(op, getXMMReg(gregOfRM(rm)),
6651 loadLE(Ity_V128, mkexpr(addr))) );
6652 delta += alen+1;
6653 DIP("%s $%d,%s,%s\n", opname,
6654 (Int)imm8,
6655 dis_buf,
6656 nameXMMReg(gregOfRM(rm)) );
6657 }
6658
sewardj2e383862004-12-12 16:46:47 +00006659 if (needNot && all_lanes) {
6660 putXMMReg( gregOfRM(rm),
sewardjf0c1c582005-02-07 23:47:38 +00006661 unop(Iop_NotV128, mkexpr(plain)) );
sewardj2e383862004-12-12 16:46:47 +00006662 }
6663 else
6664 if (needNot && !all_lanes) {
sewardj9b45b482005-02-07 01:42:18 +00006665 mask = toUShort( sz==4 ? 0x000F : 0x00FF );
sewardj2e383862004-12-12 16:46:47 +00006666 putXMMReg( gregOfRM(rm),
sewardjf0c1c582005-02-07 23:47:38 +00006667 binop(Iop_XorV128, mkexpr(plain), mkV128(mask)) );
sewardj2e383862004-12-12 16:46:47 +00006668 }
6669 else {
6670 putXMMReg( gregOfRM(rm), mkexpr(plain) );
6671 }
sewardj1e6ad742004-12-02 16:16:11 +00006672
sewardj1e6ad742004-12-02 16:16:11 +00006673 return delta;
6674}
6675
sewardjb9fa69b2004-12-09 23:25:14 +00006676
6677/* Vector by scalar shift of G by the amount specified at the bottom
6678 of E. */
6679
sewardj52d04912005-07-03 00:52:48 +00006680static UInt dis_SSE_shiftG_byE ( UChar sorb, Int delta,
sewardjb9fa69b2004-12-09 23:25:14 +00006681 HChar* opname, IROp op )
6682{
6683 HChar dis_buf[50];
6684 Int alen, size;
6685 IRTemp addr;
6686 Bool shl, shr, sar;
6687 UChar rm = getIByte(delta);
6688 IRTemp g0 = newTemp(Ity_V128);
6689 IRTemp g1 = newTemp(Ity_V128);
6690 IRTemp amt = newTemp(Ity_I32);
6691 IRTemp amt8 = newTemp(Ity_I8);
6692 if (epartIsReg(rm)) {
6693 assign( amt, getXMMRegLane32(eregOfRM(rm), 0) );
6694 DIP("%s %s,%s\n", opname,
6695 nameXMMReg(eregOfRM(rm)),
6696 nameXMMReg(gregOfRM(rm)) );
6697 delta++;
6698 } else {
6699 addr = disAMode ( &alen, sorb, delta, dis_buf );
6700 assign( amt, loadLE(Ity_I32, mkexpr(addr)) );
6701 DIP("%s %s,%s\n", opname,
6702 dis_buf,
6703 nameXMMReg(gregOfRM(rm)) );
6704 delta += alen;
6705 }
6706 assign( g0, getXMMReg(gregOfRM(rm)) );
6707 assign( amt8, unop(Iop_32to8, mkexpr(amt)) );
6708
6709 shl = shr = sar = False;
6710 size = 0;
6711 switch (op) {
6712 case Iop_ShlN16x8: shl = True; size = 32; break;
6713 case Iop_ShlN32x4: shl = True; size = 32; break;
6714 case Iop_ShlN64x2: shl = True; size = 64; break;
6715 case Iop_SarN16x8: sar = True; size = 16; break;
6716 case Iop_SarN32x4: sar = True; size = 32; break;
6717 case Iop_ShrN16x8: shr = True; size = 16; break;
6718 case Iop_ShrN32x4: shr = True; size = 32; break;
6719 case Iop_ShrN64x2: shr = True; size = 64; break;
6720 default: vassert(0);
6721 }
6722
6723 if (shl || shr) {
6724 assign(
6725 g1,
6726 IRExpr_Mux0X(
6727 unop(Iop_1Uto8,binop(Iop_CmpLT32U,mkexpr(amt),mkU32(size))),
6728 mkV128(0x0000),
6729 binop(op, mkexpr(g0), mkexpr(amt8))
6730 )
6731 );
6732 } else
6733 if (sar) {
6734 assign(
6735 g1,
6736 IRExpr_Mux0X(
6737 unop(Iop_1Uto8,binop(Iop_CmpLT32U,mkexpr(amt),mkU32(size))),
6738 binop(op, mkexpr(g0), mkU8(size-1)),
6739 binop(op, mkexpr(g0), mkexpr(amt8))
6740 )
6741 );
6742 } else {
sewardjba89f4c2005-04-07 17:31:27 +00006743 /*NOTREACHED*/
sewardjb9fa69b2004-12-09 23:25:14 +00006744 vassert(0);
6745 }
6746
6747 putXMMReg( gregOfRM(rm), mkexpr(g1) );
6748 return delta;
6749}
6750
6751
6752/* Vector by scalar shift of E by an immediate byte. */
6753
sewardj38a3f862005-01-13 15:06:51 +00006754static
sewardj52d04912005-07-03 00:52:48 +00006755UInt dis_SSE_shiftE_imm ( Int delta, HChar* opname, IROp op )
sewardjb9fa69b2004-12-09 23:25:14 +00006756{
6757 Bool shl, shr, sar;
6758 UChar rm = getIByte(delta);
sewardj38a3f862005-01-13 15:06:51 +00006759 IRTemp e0 = newTemp(Ity_V128);
6760 IRTemp e1 = newTemp(Ity_V128);
sewardjb9fa69b2004-12-09 23:25:14 +00006761 UChar amt, size;
6762 vassert(epartIsReg(rm));
6763 vassert(gregOfRM(rm) == 2
6764 || gregOfRM(rm) == 4 || gregOfRM(rm) == 6);
sewardj2d49b432005-02-01 00:37:06 +00006765 amt = getIByte(delta+1);
sewardjb9fa69b2004-12-09 23:25:14 +00006766 delta += 2;
6767 DIP("%s $%d,%s\n", opname,
6768 (Int)amt,
6769 nameXMMReg(eregOfRM(rm)) );
sewardj38a3f862005-01-13 15:06:51 +00006770 assign( e0, getXMMReg(eregOfRM(rm)) );
sewardjb9fa69b2004-12-09 23:25:14 +00006771
6772 shl = shr = sar = False;
6773 size = 0;
6774 switch (op) {
6775 case Iop_ShlN16x8: shl = True; size = 16; break;
6776 case Iop_ShlN32x4: shl = True; size = 32; break;
6777 case Iop_ShlN64x2: shl = True; size = 64; break;
6778 case Iop_SarN16x8: sar = True; size = 16; break;
6779 case Iop_SarN32x4: sar = True; size = 32; break;
6780 case Iop_ShrN16x8: shr = True; size = 16; break;
6781 case Iop_ShrN32x4: shr = True; size = 32; break;
6782 case Iop_ShrN64x2: shr = True; size = 64; break;
6783 default: vassert(0);
6784 }
6785
6786 if (shl || shr) {
sewardjba89f4c2005-04-07 17:31:27 +00006787 assign( e1, amt >= size
6788 ? mkV128(0x0000)
6789 : binop(op, mkexpr(e0), mkU8(amt))
6790 );
sewardjb9fa69b2004-12-09 23:25:14 +00006791 } else
6792 if (sar) {
sewardjba89f4c2005-04-07 17:31:27 +00006793 assign( e1, amt >= size
6794 ? binop(op, mkexpr(e0), mkU8(size-1))
6795 : binop(op, mkexpr(e0), mkU8(amt))
6796 );
sewardjb9fa69b2004-12-09 23:25:14 +00006797 } else {
sewardjba89f4c2005-04-07 17:31:27 +00006798 /*NOTREACHED*/
sewardjb9fa69b2004-12-09 23:25:14 +00006799 vassert(0);
6800 }
6801
sewardj38a3f862005-01-13 15:06:51 +00006802 putXMMReg( eregOfRM(rm), mkexpr(e1) );
sewardjb9fa69b2004-12-09 23:25:14 +00006803 return delta;
6804}
6805
6806
sewardjc1e7dfc2004-12-05 19:29:45 +00006807/* Get the current SSE rounding mode. */
sewardjc9a65702004-07-07 16:32:57 +00006808
sewardj4cb918d2004-12-03 19:43:31 +00006809static IRExpr* /* :: Ity_I32 */ get_sse_roundingmode ( void )
6810{
6811 return binop( Iop_And32,
6812 IRExpr_Get( OFFB_SSEROUND, Ity_I32 ),
6813 mkU32(3) );
6814}
6815
sewardj636ad762004-12-07 11:16:04 +00006816static void put_sse_roundingmode ( IRExpr* sseround )
6817{
6818 vassert(typeOfIRExpr(irbb->tyenv, sseround) == Ity_I32);
6819 stmt( IRStmt_Put( OFFB_SSEROUND, sseround ) );
6820}
6821
sewardjc1e7dfc2004-12-05 19:29:45 +00006822/* Break a 128-bit value up into four 32-bit ints. */
6823
6824static void breakup128to32s ( IRTemp t128,
6825 /*OUTs*/
6826 IRTemp* t3, IRTemp* t2,
6827 IRTemp* t1, IRTemp* t0 )
6828{
6829 IRTemp hi64 = newTemp(Ity_I64);
6830 IRTemp lo64 = newTemp(Ity_I64);
sewardjf0c1c582005-02-07 23:47:38 +00006831 assign( hi64, unop(Iop_V128HIto64, mkexpr(t128)) );
6832 assign( lo64, unop(Iop_V128to64, mkexpr(t128)) );
sewardjc1e7dfc2004-12-05 19:29:45 +00006833
6834 vassert(t0 && *t0 == IRTemp_INVALID);
6835 vassert(t1 && *t1 == IRTemp_INVALID);
6836 vassert(t2 && *t2 == IRTemp_INVALID);
6837 vassert(t3 && *t3 == IRTemp_INVALID);
6838
6839 *t0 = newTemp(Ity_I32);
6840 *t1 = newTemp(Ity_I32);
6841 *t2 = newTemp(Ity_I32);
6842 *t3 = newTemp(Ity_I32);
6843 assign( *t0, unop(Iop_64to32, mkexpr(lo64)) );
6844 assign( *t1, unop(Iop_64HIto32, mkexpr(lo64)) );
6845 assign( *t2, unop(Iop_64to32, mkexpr(hi64)) );
6846 assign( *t3, unop(Iop_64HIto32, mkexpr(hi64)) );
6847}
6848
6849/* Construct a 128-bit value from four 32-bit ints. */
6850
6851static IRExpr* mk128from32s ( IRTemp t3, IRTemp t2,
6852 IRTemp t1, IRTemp t0 )
6853{
6854 return
sewardjf0c1c582005-02-07 23:47:38 +00006855 binop( Iop_64HLtoV128,
sewardjc1e7dfc2004-12-05 19:29:45 +00006856 binop(Iop_32HLto64, mkexpr(t3), mkexpr(t2)),
6857 binop(Iop_32HLto64, mkexpr(t1), mkexpr(t0))
6858 );
6859}
6860
sewardjb9fa69b2004-12-09 23:25:14 +00006861/* Break a 64-bit value up into four 16-bit ints. */
6862
6863static void breakup64to16s ( IRTemp t64,
6864 /*OUTs*/
6865 IRTemp* t3, IRTemp* t2,
6866 IRTemp* t1, IRTemp* t0 )
6867{
6868 IRTemp hi32 = newTemp(Ity_I32);
6869 IRTemp lo32 = newTemp(Ity_I32);
6870 assign( hi32, unop(Iop_64HIto32, mkexpr(t64)) );
6871 assign( lo32, unop(Iop_64to32, mkexpr(t64)) );
6872
6873 vassert(t0 && *t0 == IRTemp_INVALID);
6874 vassert(t1 && *t1 == IRTemp_INVALID);
6875 vassert(t2 && *t2 == IRTemp_INVALID);
6876 vassert(t3 && *t3 == IRTemp_INVALID);
6877
6878 *t0 = newTemp(Ity_I16);
6879 *t1 = newTemp(Ity_I16);
6880 *t2 = newTemp(Ity_I16);
6881 *t3 = newTemp(Ity_I16);
6882 assign( *t0, unop(Iop_32to16, mkexpr(lo32)) );
6883 assign( *t1, unop(Iop_32HIto16, mkexpr(lo32)) );
6884 assign( *t2, unop(Iop_32to16, mkexpr(hi32)) );
6885 assign( *t3, unop(Iop_32HIto16, mkexpr(hi32)) );
6886}
6887
6888/* Construct a 64-bit value from four 16-bit ints. */
6889
6890static IRExpr* mk64from16s ( IRTemp t3, IRTemp t2,
6891 IRTemp t1, IRTemp t0 )
6892{
6893 return
6894 binop( Iop_32HLto64,
6895 binop(Iop_16HLto32, mkexpr(t3), mkexpr(t2)),
6896 binop(Iop_16HLto32, mkexpr(t1), mkexpr(t0))
6897 );
6898}
6899
sewardj4cb918d2004-12-03 19:43:31 +00006900
sewardjc9a65702004-07-07 16:32:57 +00006901/*------------------------------------------------------------*/
sewardjce70a5c2004-10-18 14:09:54 +00006902/*--- Disassemble a single instruction ---*/
sewardjc9a65702004-07-07 16:32:57 +00006903/*------------------------------------------------------------*/
6904
sewardjce70a5c2004-10-18 14:09:54 +00006905/* Disassemble a single instruction into IR. The instruction
sewardj9e6491a2005-07-02 19:24:10 +00006906 is located in host memory at &guest_code[delta]. */
6907
6908static
6909DisResult disInstr_X86_WRK (
6910 Bool put_IP,
6911 Bool (*resteerOkFn) ( Addr64 ),
6912 Long delta64,
6913 VexArchInfo* archinfo
6914 )
sewardjc9a65702004-07-07 16:32:57 +00006915{
sewardjce70a5c2004-10-18 14:09:54 +00006916 IRType ty;
sewardjb5452082004-12-04 20:33:02 +00006917 IRTemp addr, t0, t1, t2, t3, t4, t5, t6;
sewardjce70a5c2004-10-18 14:09:54 +00006918 Int alen;
6919 UChar opc, modrm, abyte;
6920 UInt d32;
sewardjc9a43662004-11-30 18:51:59 +00006921 HChar dis_buf[50];
sewardjce70a5c2004-10-18 14:09:54 +00006922 Int am_sz, d_sz;
sewardj9e6491a2005-07-02 19:24:10 +00006923 DisResult dres;
sewardjc9a43662004-11-30 18:51:59 +00006924 UChar* insn; /* used in SSE decoders */
sewardjce70a5c2004-10-18 14:09:54 +00006925
sewardj9e6491a2005-07-02 19:24:10 +00006926 /* The running delta */
6927 Int delta = (Int)delta64;
6928
sewardjc9a65702004-07-07 16:32:57 +00006929 /* Holds eip at the start of the insn, so that we can print
6930 consistent error messages for unimplemented insns. */
sewardj9e6491a2005-07-02 19:24:10 +00006931 Int delta_start = delta;
sewardjc9a65702004-07-07 16:32:57 +00006932
6933 /* sz denotes the nominal data-op size of the insn; we change it to
6934 2 if an 0x66 prefix is seen */
6935 Int sz = 4;
6936
6937 /* sorb holds the segment-override-prefix byte, if any. Zero if no
6938 prefix has been seen, else one of {0x26, 0x3E, 0x64, 0x65}
6939 indicating the prefix. */
6940 UChar sorb = 0;
6941
sewardj9e6491a2005-07-02 19:24:10 +00006942 /* Set result defaults. */
6943 dres.whatNext = Dis_Continue;
6944 dres.len = 0;
6945 dres.continueAt = 0;
sewardjce70a5c2004-10-18 14:09:54 +00006946
sewardjb5452082004-12-04 20:33:02 +00006947 addr = t0 = t1 = t2 = t3 = t4 = t5 = t6 = IRTemp_INVALID;
sewardjc9a65702004-07-07 16:32:57 +00006948
sewardj9e6491a2005-07-02 19:24:10 +00006949 DIP("\t0x%x: ", guest_EIP_bbstart+delta);
6950
6951 /* We may be asked to update the guest EIP before going further. */
6952 if (put_IP)
6953 stmt( IRStmt_Put( OFFB_EIP, mkU32(guest_EIP_curr_instr)) );
sewardjc9a65702004-07-07 16:32:57 +00006954
sewardj750f4072004-07-26 22:39:11 +00006955 /* Spot the client-request magic sequence. */
6956 {
6957 UChar* code = (UChar*)(guest_code + delta);
6958 /* Spot this:
6959 C1C01D roll $29, %eax
6960 C1C003 roll $3, %eax
6961 C1C81B rorl $27, %eax
6962 C1C805 rorl $5, %eax
6963 C1C00D roll $13, %eax
6964 C1C013 roll $19, %eax
6965 */
6966 if (code[ 0] == 0xC1 && code[ 1] == 0xC0 && code[ 2] == 0x1D &&
6967 code[ 3] == 0xC1 && code[ 4] == 0xC0 && code[ 5] == 0x03 &&
6968 code[ 6] == 0xC1 && code[ 7] == 0xC8 && code[ 8] == 0x1B &&
6969 code[ 9] == 0xC1 && code[10] == 0xC8 && code[11] == 0x05 &&
6970 code[12] == 0xC1 && code[13] == 0xC0 && code[14] == 0x0D &&
6971 code[15] == 0xC1 && code[16] == 0xC0 && code[17] == 0x13
6972 ) {
sewardjce70a5c2004-10-18 14:09:54 +00006973 DIP("%%edx = client_request ( %%eax )\n");
sewardj750f4072004-07-26 22:39:11 +00006974 delta += 18;
sewardj9e6491a2005-07-02 19:24:10 +00006975 jmp_lit(Ijk_ClientReq, guest_EIP_bbstart+delta);
6976 dres.whatNext = Dis_StopHere;
sewardjce70a5c2004-10-18 14:09:54 +00006977 goto decode_success;
sewardj750f4072004-07-26 22:39:11 +00006978 }
6979 }
sewardjc9a65702004-07-07 16:32:57 +00006980
6981 /* Skip a LOCK prefix. */
sewardjce4a2822005-01-07 13:25:28 +00006982 /* 2005 Jan 06: the following insns are observed to sometimes
6983 have a LOCK prefix:
6984 cmpxchgl %ecx,(%edx)
sewardjaade6d42005-01-07 13:36:14 +00006985 cmpxchgl %edx,0x278(%ebx) etc
sewardjce4a2822005-01-07 13:25:28 +00006986 xchgl %eax, (%ecx)
6987 xaddl %eax, (%ecx)
6988 We need to catch any such which appear to be being used as
6989 a memory barrier, for example lock addl $0,0(%esp)
6990 and emit an IR MFence construct.
6991 */
sewardjbb3f52d2005-01-07 14:14:50 +00006992 if (getIByte(delta) == 0xF0) {
6993
6994 UChar* code = (UChar*)(guest_code + delta);
6995
6996 /* Various bits of kernel headers use the following as a memory
6997 barrier. Hence, first emit an MFence and then let the insn
6998 go through as usual. */
6999 /* F08344240000: lock addl $0, 0(%esp) */
7000 if (code[0] == 0xF0 && code[1] == 0x83 && code[2] == 0x44 &&
7001 code[3] == 0x24 && code[4] == 0x00 && code[5] == 0x00) {
7002 stmt( IRStmt_MFence() );
7003 }
7004 else
7005 if (0) {
sewardjce4a2822005-01-07 13:25:28 +00007006 vex_printf("vex x86->IR: ignoring LOCK prefix on: ");
sewardj9e6491a2005-07-02 19:24:10 +00007007 /* insn_verbose = True; */
sewardjce4a2822005-01-07 13:25:28 +00007008 }
sewardjbb3f52d2005-01-07 14:14:50 +00007009
7010 /* In any case, skip the prefix. */
sewardjc9a65702004-07-07 16:32:57 +00007011 delta++;
7012 }
7013
7014 /* Detect operand-size overrides. */
7015 if (getIByte(delta) == 0x66) { sz = 2; delta++; };
7016
7017 /* segment override prefixes come after the operand-size override,
7018 it seems */
7019 switch (getIByte(delta)) {
7020 case 0x3E: /* %DS: */
7021 case 0x26: /* %ES: */
7022 case 0x64: /* %FS: */
7023 case 0x65: /* %GS: */
7024 sorb = getIByte(delta); delta++;
7025 break;
7026 case 0x2E: /* %CS: */
7027 /* 2E prefix on a conditional branch instruction is a
7028 branch-prediction hint, which can safely be ignored. */
7029 {
7030 UChar op1 = getIByte(delta+1);
7031 UChar op2 = getIByte(delta+2);
7032 if ((op1 >= 0x70 && op1 <= 0x7F)
7033 || (op1 == 0xE3)
7034 || (op1 == 0x0F && op2 >= 0x80 && op2 <= 0x8F)) {
sewardj4dfb1992005-03-13 18:56:28 +00007035 if (0) vex_printf("vex x86->IR: ignoring branch hint\n");
sewardjc9a65702004-07-07 16:32:57 +00007036 sorb = getIByte(delta); delta++;
7037 break;
7038 }
7039 }
7040 unimplemented("x86 segment override (SEG=CS) prefix");
7041 /*NOTREACHED*/
7042 break;
7043 case 0x36: /* %SS: */
7044 unimplemented("x86 segment override (SEG=SS) prefix");
7045 /*NOTREACHED*/
7046 break;
7047 default:
7048 break;
7049 }
7050
sewardjc9a43662004-11-30 18:51:59 +00007051 /* ---------------------------------------------------- */
7052 /* --- The SSE decoder. --- */
7053 /* ---------------------------------------------------- */
7054
sewardj4cb918d2004-12-03 19:43:31 +00007055 /* What did I do to deserve SSE ? Perhaps I was really bad in a
7056 previous life? */
7057
sewardj9df271d2004-12-31 22:37:42 +00007058 /* Note, this doesn't handle SSE2 or SSE3. That is handled in a
7059 later section, further on. */
7060
sewardja0e83b02005-01-06 12:36:38 +00007061 insn = (UChar*)&guest_code[delta];
7062
7063 /* Treat fxsave specially. It should be doable even on an SSE0
7064 (Pentium-II class) CPU. Hence be prepared to handle it on
7065 any subarchitecture variant.
7066 */
7067
7068 /* 0F AE /0 = FXSAVE m512 -- write x87 and SSE state to memory */
7069 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xAE
7070 && !epartIsReg(insn[2]) && gregOfRM(insn[2]) == 0) {
sewardj9a036bf2005-03-14 18:19:08 +00007071 IRDirty* d;
sewardja0e83b02005-01-06 12:36:38 +00007072 modrm = getIByte(delta+2);
7073 vassert(sz == 4);
7074 vassert(!epartIsReg(modrm));
7075
7076 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
7077 delta += 2+alen;
7078
sewardj33dd31b2005-01-08 18:17:32 +00007079 DIP("fxsave %s\n", dis_buf);
sewardja0e83b02005-01-06 12:36:38 +00007080
7081 /* Uses dirty helper:
7082 void x86g_do_FXSAVE ( VexGuestX86State*, UInt ) */
sewardj9a036bf2005-03-14 18:19:08 +00007083 d = unsafeIRDirty_0_N (
7084 0/*regparms*/,
7085 "x86g_dirtyhelper_FXSAVE",
7086 &x86g_dirtyhelper_FXSAVE,
7087 mkIRExprVec_1( mkexpr(addr) )
7088 );
sewardja0e83b02005-01-06 12:36:38 +00007089 d->needsBBP = True;
7090
7091 /* declare we're writing memory */
7092 d->mFx = Ifx_Write;
7093 d->mAddr = mkexpr(addr);
7094 d->mSize = 512;
7095
7096 /* declare we're reading guest state */
7097 d->nFxState = 7;
7098
7099 d->fxState[0].fx = Ifx_Read;
7100 d->fxState[0].offset = OFFB_FTOP;
7101 d->fxState[0].size = sizeof(UInt);
7102
7103 d->fxState[1].fx = Ifx_Read;
7104 d->fxState[1].offset = OFFB_FPREGS;
7105 d->fxState[1].size = 8 * sizeof(ULong);
7106
7107 d->fxState[2].fx = Ifx_Read;
7108 d->fxState[2].offset = OFFB_FPTAGS;
7109 d->fxState[2].size = 8 * sizeof(UChar);
7110
7111 d->fxState[3].fx = Ifx_Read;
7112 d->fxState[3].offset = OFFB_FPROUND;
7113 d->fxState[3].size = sizeof(UInt);
7114
7115 d->fxState[4].fx = Ifx_Read;
7116 d->fxState[4].offset = OFFB_FC3210;
7117 d->fxState[4].size = sizeof(UInt);
7118
7119 d->fxState[5].fx = Ifx_Read;
7120 d->fxState[5].offset = OFFB_XMM0;
7121 d->fxState[5].size = 8 * sizeof(U128);
7122
7123 d->fxState[6].fx = Ifx_Read;
7124 d->fxState[6].offset = OFFB_SSEROUND;
7125 d->fxState[6].size = sizeof(UInt);
7126
7127 /* Be paranoid ... this assertion tries to ensure the 8 %xmm
7128 images are packed back-to-back. If not, the value of
7129 d->fxState[5].size is wrong. */
7130 vassert(16 == sizeof(U128));
7131 vassert(OFFB_XMM7 == (OFFB_XMM0 + 7 * 16));
7132
7133 stmt( IRStmt_Dirty(d) );
7134
7135 goto decode_success;
7136 }
7137
7138 /* ------ SSE decoder main ------ */
7139
sewardj9df271d2004-12-31 22:37:42 +00007140 /* Skip parts of the decoder which don't apply given the stated
7141 guest subarchitecture. */
sewardj27e1dd62005-06-30 11:49:14 +00007142 if (archinfo->subarch == VexSubArchX86_sse0)
sewardj9df271d2004-12-31 22:37:42 +00007143 goto after_sse_decoders;
7144
7145 /* Otherwise we must be doing sse1 or sse2, so we can at least try
7146 for SSE1 here. */
sewardjc9a43662004-11-30 18:51:59 +00007147
sewardjc9a43662004-11-30 18:51:59 +00007148 /* 0F 58 = ADDPS -- add 32Fx4 from R/M to R */
sewardj636ad762004-12-07 11:16:04 +00007149 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x58) {
sewardj129b3d92004-12-05 15:42:05 +00007150 delta = dis_SSE_E_to_G_all( sorb, delta+2, "addps", Iop_Add32Fx4 );
sewardjc9a43662004-11-30 18:51:59 +00007151 goto decode_success;
7152 }
7153
sewardj1e6ad742004-12-02 16:16:11 +00007154 /* F3 0F 58 = ADDSS -- add 32F0x4 from R/M to R */
7155 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x58) {
7156 vassert(sz == 4);
sewardj129b3d92004-12-05 15:42:05 +00007157 delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "addss", Iop_Add32F0x4 );
sewardj1e6ad742004-12-02 16:16:11 +00007158 goto decode_success;
7159 }
7160
7161 /* 0F 55 = ANDNPS -- G = (not G) and E */
sewardj636ad762004-12-07 11:16:04 +00007162 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x55) {
sewardjf0c1c582005-02-07 23:47:38 +00007163 delta = dis_SSE_E_to_G_all_invG( sorb, delta+2, "andnps", Iop_AndV128 );
sewardj1e6ad742004-12-02 16:16:11 +00007164 goto decode_success;
7165 }
7166
7167 /* 0F 54 = ANDPS -- G = G and E */
sewardj636ad762004-12-07 11:16:04 +00007168 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x54) {
sewardjf0c1c582005-02-07 23:47:38 +00007169 delta = dis_SSE_E_to_G_all( sorb, delta+2, "andps", Iop_AndV128 );
sewardj1e6ad742004-12-02 16:16:11 +00007170 goto decode_success;
7171 }
7172
7173 /* 0F C2 = CMPPS -- 32Fx4 comparison from R/M to R */
sewardj636ad762004-12-07 11:16:04 +00007174 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xC2) {
sewardj1e6ad742004-12-02 16:16:11 +00007175 delta = dis_SSEcmp_E_to_G( sorb, delta+2, "cmpps", True, 4 );
7176 goto decode_success;
7177 }
7178
7179 /* F3 0F C2 = CMPSS -- 32F0x4 comparison from R/M to R */
7180 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0xC2) {
7181 vassert(sz == 4);
7182 delta = dis_SSEcmp_E_to_G( sorb, delta+3, "cmpss", False, 4 );
7183 goto decode_success;
7184 }
sewardjc9a43662004-11-30 18:51:59 +00007185
sewardjfd226452004-12-07 19:02:18 +00007186 /* 0F 2F = COMISS -- 32F0x4 comparison G,E, and set ZCP */
sewardjc1e7dfc2004-12-05 19:29:45 +00007187 /* 0F 2E = UCOMISS -- 32F0x4 comparison G,E, and set ZCP */
sewardjfd226452004-12-07 19:02:18 +00007188 if (sz == 4 && insn[0] == 0x0F && (insn[1] == 0x2F || insn[1] == 0x2E)) {
sewardj67e002d2004-12-02 18:16:33 +00007189 IRTemp argL = newTemp(Ity_F32);
7190 IRTemp argR = newTemp(Ity_F32);
sewardj67e002d2004-12-02 18:16:33 +00007191 modrm = getIByte(delta+2);
7192 if (epartIsReg(modrm)) {
7193 assign( argR, getXMMRegLane32F( eregOfRM(modrm), 0/*lowest lane*/ ) );
7194 delta += 2+1;
sewardjc1e7dfc2004-12-05 19:29:45 +00007195 DIP("[u]comiss %s,%s\n", nameXMMReg(eregOfRM(modrm)),
7196 nameXMMReg(gregOfRM(modrm)) );
sewardj67e002d2004-12-02 18:16:33 +00007197 } else {
7198 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
7199 assign( argR, loadLE(Ity_F32, mkexpr(addr)) );
7200 delta += 2+alen;
sewardjc1e7dfc2004-12-05 19:29:45 +00007201 DIP("[u]comiss %s,%s\n", dis_buf,
7202 nameXMMReg(gregOfRM(modrm)) );
sewardj67e002d2004-12-02 18:16:33 +00007203 }
7204 assign( argL, getXMMRegLane32F( gregOfRM(modrm), 0/*lowest lane*/ ) );
7205
7206 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
7207 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
7208 stmt( IRStmt_Put(
7209 OFFB_CC_DEP1,
7210 binop( Iop_And32,
7211 binop(Iop_CmpF64,
7212 unop(Iop_F32toF64,mkexpr(argL)),
7213 unop(Iop_F32toF64,mkexpr(argR))),
7214 mkU32(0x45)
7215 )));
sewardja3b7e3a2005-04-05 01:54:19 +00007216 /* Set NDEP even though it isn't used. This makes redundant-PUT
7217 elimination of previous stores to this field work better. */
7218 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardj67e002d2004-12-02 18:16:33 +00007219 goto decode_success;
7220 }
sewardjc9a43662004-11-30 18:51:59 +00007221
sewardj4cb918d2004-12-03 19:43:31 +00007222 /* 0F 2A = CVTPI2PS -- convert 2 x I32 in mem/mmx to 2 x F32 in low
7223 half xmm */
sewardjfd226452004-12-07 19:02:18 +00007224 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x2A) {
sewardj4cb918d2004-12-03 19:43:31 +00007225 IRTemp arg64 = newTemp(Ity_I64);
7226 IRTemp rmode = newTemp(Ity_I32);
7227 vassert(sz == 4);
7228
7229 modrm = getIByte(delta+2);
7230 do_MMX_preamble();
7231 if (epartIsReg(modrm)) {
7232 assign( arg64, getMMXReg(eregOfRM(modrm)) );
7233 delta += 2+1;
7234 DIP("cvtpi2ps %s,%s\n", nameMMXReg(eregOfRM(modrm)),
7235 nameXMMReg(gregOfRM(modrm)));
7236 } else {
7237 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
7238 assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
7239 delta += 2+alen;
7240 DIP("cvtpi2ps %s,%s\n", dis_buf,
7241 nameXMMReg(gregOfRM(modrm)) );
7242 }
7243
7244 assign( rmode, get_sse_roundingmode() );
7245
7246 putXMMRegLane32F(
sewardj3bca9062004-12-04 14:36:09 +00007247 gregOfRM(modrm), 0,
7248 binop(Iop_F64toF32,
sewardj4cb918d2004-12-03 19:43:31 +00007249 mkexpr(rmode),
sewardj3bca9062004-12-04 14:36:09 +00007250 unop(Iop_I32toF64,
7251 unop(Iop_64to32, mkexpr(arg64)) )) );
sewardj4cb918d2004-12-03 19:43:31 +00007252
7253 putXMMRegLane32F(
7254 gregOfRM(modrm), 1,
sewardj3bca9062004-12-04 14:36:09 +00007255 binop(Iop_F64toF32,
sewardj4cb918d2004-12-03 19:43:31 +00007256 mkexpr(rmode),
sewardj3bca9062004-12-04 14:36:09 +00007257 unop(Iop_I32toF64,
7258 unop(Iop_64HIto32, mkexpr(arg64)) )) );
sewardj4cb918d2004-12-03 19:43:31 +00007259
7260 goto decode_success;
7261 }
7262
7263 /* F3 0F 2A = CVTSI2SS -- convert I32 in mem/ireg to F32 in low
7264 quarter xmm */
7265 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x2A) {
7266 IRTemp arg32 = newTemp(Ity_I32);
7267 IRTemp rmode = newTemp(Ity_I32);
7268 vassert(sz == 4);
7269
7270 modrm = getIByte(delta+3);
sewardj4cb918d2004-12-03 19:43:31 +00007271 if (epartIsReg(modrm)) {
7272 assign( arg32, getIReg(4, eregOfRM(modrm)) );
7273 delta += 3+1;
7274 DIP("cvtsi2ss %s,%s\n", nameIReg(4, eregOfRM(modrm)),
7275 nameXMMReg(gregOfRM(modrm)));
7276 } else {
7277 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
7278 assign( arg32, loadLE(Ity_I32, mkexpr(addr)) );
7279 delta += 3+alen;
7280 DIP("cvtsi2ss %s,%s\n", dis_buf,
7281 nameXMMReg(gregOfRM(modrm)) );
7282 }
7283
7284 assign( rmode, get_sse_roundingmode() );
7285
7286 putXMMRegLane32F(
sewardj3bca9062004-12-04 14:36:09 +00007287 gregOfRM(modrm), 0,
7288 binop(Iop_F64toF32,
7289 mkexpr(rmode),
7290 unop(Iop_I32toF64, mkexpr(arg32)) ) );
sewardj4cb918d2004-12-03 19:43:31 +00007291
7292 goto decode_success;
7293 }
7294
7295 /* 0F 2D = CVTPS2PI -- convert 2 x F32 in mem/low half xmm to 2 x
7296 I32 in mmx, according to prevailing SSE rounding mode */
7297 /* 0F 2C = CVTTPS2PI -- convert 2 x F32 in mem/low half xmm to 2 x
7298 I32 in mmx, rounding towards zero */
sewardjfd226452004-12-07 19:02:18 +00007299 if (sz == 4 && insn[0] == 0x0F && (insn[1] == 0x2D || insn[1] == 0x2C)) {
sewardj4cb918d2004-12-03 19:43:31 +00007300 IRTemp dst64 = newTemp(Ity_I64);
7301 IRTemp rmode = newTemp(Ity_I32);
7302 IRTemp f32lo = newTemp(Ity_F32);
7303 IRTemp f32hi = newTemp(Ity_F32);
sewardj2d49b432005-02-01 00:37:06 +00007304 Bool r2zero = toBool(insn[1] == 0x2C);
sewardj4cb918d2004-12-03 19:43:31 +00007305
7306 do_MMX_preamble();
7307 modrm = getIByte(delta+2);
7308
7309 if (epartIsReg(modrm)) {
7310 delta += 2+1;
7311 assign(f32lo, getXMMRegLane32F(eregOfRM(modrm), 0));
7312 assign(f32hi, getXMMRegLane32F(eregOfRM(modrm), 1));
7313 DIP("cvt%sps2pi %s,%s\n", r2zero ? "t" : "",
7314 nameXMMReg(eregOfRM(modrm)),
7315 nameMMXReg(gregOfRM(modrm)));
7316 } else {
7317 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
7318 assign(f32lo, loadLE(Ity_F32, mkexpr(addr)));
7319 assign(f32hi, loadLE(Ity_F32, binop( Iop_Add32,
7320 mkexpr(addr),
7321 mkU32(4) )));
7322 delta += 2+alen;
7323 DIP("cvt%sps2pi %s,%s\n", r2zero ? "t" : "",
7324 dis_buf,
7325 nameMMXReg(gregOfRM(modrm)));
7326 }
7327
7328 if (r2zero) {
7329 assign(rmode, mkU32((UInt)Irrm_ZERO) );
7330 } else {
7331 assign( rmode, get_sse_roundingmode() );
7332 }
7333
7334 assign(
7335 dst64,
7336 binop( Iop_32HLto64,
7337 binop( Iop_F64toI32,
7338 mkexpr(rmode),
7339 unop( Iop_F32toF64, mkexpr(f32hi) ) ),
7340 binop( Iop_F64toI32,
7341 mkexpr(rmode),
7342 unop( Iop_F32toF64, mkexpr(f32lo) ) )
7343 )
7344 );
7345
7346 putMMXReg(gregOfRM(modrm), mkexpr(dst64));
7347 goto decode_success;
7348 }
7349
7350 /* F3 0F 2D = CVTSS2SI -- convert F32 in mem/low quarter xmm to
7351 I32 in ireg, according to prevailing SSE rounding mode */
7352 /* F3 0F 2C = CVTTSS2SI -- convert F32 in mem/low quarter xmm to
sewardj0b210442005-02-23 13:28:27 +00007353 I32 in ireg, rounding towards zero */
sewardj4cb918d2004-12-03 19:43:31 +00007354 if (insn[0] == 0xF3 && insn[1] == 0x0F
7355 && (insn[2] == 0x2D || insn[2] == 0x2C)) {
7356 IRTemp rmode = newTemp(Ity_I32);
7357 IRTemp f32lo = newTemp(Ity_F32);
sewardj2d49b432005-02-01 00:37:06 +00007358 Bool r2zero = toBool(insn[2] == 0x2C);
sewardj4cb918d2004-12-03 19:43:31 +00007359 vassert(sz == 4);
7360
sewardj4cb918d2004-12-03 19:43:31 +00007361 modrm = getIByte(delta+3);
sewardj4cb918d2004-12-03 19:43:31 +00007362 if (epartIsReg(modrm)) {
7363 delta += 3+1;
7364 assign(f32lo, getXMMRegLane32F(eregOfRM(modrm), 0));
7365 DIP("cvt%sss2si %s,%s\n", r2zero ? "t" : "",
7366 nameXMMReg(eregOfRM(modrm)),
7367 nameIReg(4, gregOfRM(modrm)));
7368 } else {
7369 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
7370 assign(f32lo, loadLE(Ity_F32, mkexpr(addr)));
7371 delta += 3+alen;
7372 DIP("cvt%sss2si %s,%s\n", r2zero ? "t" : "",
7373 dis_buf,
7374 nameIReg(4, gregOfRM(modrm)));
7375 }
7376
7377 if (r2zero) {
sewardj7df596b2004-12-06 14:29:12 +00007378 assign( rmode, mkU32((UInt)Irrm_ZERO) );
sewardj4cb918d2004-12-03 19:43:31 +00007379 } else {
7380 assign( rmode, get_sse_roundingmode() );
7381 }
7382
7383 putIReg(4, gregOfRM(modrm),
7384 binop( Iop_F64toI32,
7385 mkexpr(rmode),
7386 unop( Iop_F32toF64, mkexpr(f32lo) ) )
7387 );
7388
7389 goto decode_success;
7390 }
7391
sewardj176a59c2004-12-03 20:08:31 +00007392 /* 0F 5E = DIVPS -- div 32Fx4 from R/M to R */
sewardjfd226452004-12-07 19:02:18 +00007393 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5E) {
sewardj129b3d92004-12-05 15:42:05 +00007394 delta = dis_SSE_E_to_G_all( sorb, delta+2, "divps", Iop_Div32Fx4 );
sewardj176a59c2004-12-03 20:08:31 +00007395 goto decode_success;
7396 }
7397
7398 /* F3 0F 5E = DIVSS -- div 32F0x4 from R/M to R */
7399 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5E) {
7400 vassert(sz == 4);
sewardj129b3d92004-12-05 15:42:05 +00007401 delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "divss", Iop_Div32F0x4 );
sewardj176a59c2004-12-03 20:08:31 +00007402 goto decode_success;
7403 }
7404
sewardj7df596b2004-12-06 14:29:12 +00007405 /* 0F AE /2 = LDMXCSR m32 -- load %mxcsr */
7406 if (insn[0] == 0x0F && insn[1] == 0xAE
7407 && !epartIsReg(insn[2]) && gregOfRM(insn[2]) == 2) {
7408
7409 IRTemp t64 = newTemp(Ity_I64);
7410 IRTemp ew = newTemp(Ity_I32);
7411
7412 modrm = getIByte(delta+2);
7413 vassert(!epartIsReg(modrm));
7414 vassert(sz == 4);
7415
7416 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
7417 delta += 2+alen;
sewardj33dd31b2005-01-08 18:17:32 +00007418 DIP("ldmxcsr %s\n", dis_buf);
sewardj7df596b2004-12-06 14:29:12 +00007419
7420 /* The only thing we observe in %mxcsr is the rounding mode.
7421 Therefore, pass the 32-bit value (SSE native-format control
7422 word) to a clean helper, getting back a 64-bit value, the
7423 lower half of which is the SSEROUND value to store, and the
7424 upper half of which is the emulation-warning token which may
7425 be generated.
7426 */
7427 /* ULong x86h_check_ldmxcsr ( UInt ); */
7428 assign( t64, mkIRExprCCall(
7429 Ity_I64, 0/*regparms*/,
sewardj3bd6f3e2004-12-13 10:48:19 +00007430 "x86g_check_ldmxcsr",
7431 &x86g_check_ldmxcsr,
sewardj7df596b2004-12-06 14:29:12 +00007432 mkIRExprVec_1( loadLE(Ity_I32, mkexpr(addr)) )
7433 )
7434 );
7435
sewardj636ad762004-12-07 11:16:04 +00007436 put_sse_roundingmode( unop(Iop_64to32, mkexpr(t64)) );
sewardj7df596b2004-12-06 14:29:12 +00007437 assign( ew, unop(Iop_64HIto32, mkexpr(t64) ) );
7438 put_emwarn( mkexpr(ew) );
7439 /* Finally, if an emulation warning was reported, side-exit to
7440 the next insn, reporting the warning, so that Valgrind's
7441 dispatcher sees the warning. */
7442 stmt(
7443 IRStmt_Exit(
7444 binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
7445 Ijk_EmWarn,
sewardj9e6491a2005-07-02 19:24:10 +00007446 IRConst_U32( ((Addr32)guest_EIP_bbstart)+delta)
sewardj7df596b2004-12-06 14:29:12 +00007447 )
7448 );
7449 goto decode_success;
7450 }
7451
sewardj176a59c2004-12-03 20:08:31 +00007452 /* 0F 5F = MAXPS -- max 32Fx4 from R/M to R */
sewardjc2feffc2004-12-08 12:31:22 +00007453 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5F) {
sewardj129b3d92004-12-05 15:42:05 +00007454 delta = dis_SSE_E_to_G_all( sorb, delta+2, "maxps", Iop_Max32Fx4 );
sewardj176a59c2004-12-03 20:08:31 +00007455 goto decode_success;
7456 }
7457
7458 /* F3 0F 5F = MAXSS -- max 32F0x4 from R/M to R */
7459 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5F) {
7460 vassert(sz == 4);
sewardj129b3d92004-12-05 15:42:05 +00007461 delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "maxss", Iop_Max32F0x4 );
sewardj176a59c2004-12-03 20:08:31 +00007462 goto decode_success;
7463 }
7464
7465 /* 0F 5D = MINPS -- min 32Fx4 from R/M to R */
sewardjc2feffc2004-12-08 12:31:22 +00007466 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5D) {
sewardj129b3d92004-12-05 15:42:05 +00007467 delta = dis_SSE_E_to_G_all( sorb, delta+2, "minps", Iop_Min32Fx4 );
sewardj176a59c2004-12-03 20:08:31 +00007468 goto decode_success;
7469 }
7470
7471 /* F3 0F 5D = MINSS -- min 32F0x4 from R/M to R */
7472 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5D) {
7473 vassert(sz == 4);
sewardj129b3d92004-12-05 15:42:05 +00007474 delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "minss", Iop_Min32F0x4 );
sewardj176a59c2004-12-03 20:08:31 +00007475 goto decode_success;
7476 }
sewardj4cb918d2004-12-03 19:43:31 +00007477
sewardj9636b442004-12-04 01:38:37 +00007478 /* 0F 28 = MOVAPS -- move from E (mem or xmm) to G (xmm). */
sewardjc2feffc2004-12-08 12:31:22 +00007479 /* 0F 10 = MOVUPS -- move from E (mem or xmm) to G (xmm). */
7480 if (sz == 4 && insn[0] == 0x0F && (insn[1] == 0x28 || insn[1] == 0x10)) {
sewardj9636b442004-12-04 01:38:37 +00007481 modrm = getIByte(delta+2);
sewardj9636b442004-12-04 01:38:37 +00007482 if (epartIsReg(modrm)) {
7483 putXMMReg( gregOfRM(modrm),
7484 getXMMReg( eregOfRM(modrm) ));
7485 DIP("mov[ua]ps %s,%s\n", nameXMMReg(eregOfRM(modrm)),
7486 nameXMMReg(gregOfRM(modrm)));
7487 delta += 2+1;
7488 } else {
7489 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
7490 putXMMReg( gregOfRM(modrm),
7491 loadLE(Ity_V128, mkexpr(addr)) );
7492 DIP("mov[ua]ps %s,%s\n", dis_buf,
7493 nameXMMReg(gregOfRM(modrm)));
7494 delta += 2+alen;
7495 }
7496 goto decode_success;
7497 }
7498
sewardj09f41552004-12-15 12:35:00 +00007499 /* 0F 29 = MOVAPS -- move from G (xmm) to E (mem or xmm). */
7500 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x29) {
7501 modrm = getIByte(delta+2);
sewardj09f41552004-12-15 12:35:00 +00007502 if (epartIsReg(modrm)) {
7503 /* fall through; awaiting test case */
7504 } else {
7505 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
7506 storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) );
7507 DIP("movaps %s,%s\n", nameXMMReg(gregOfRM(modrm)),
7508 dis_buf );
7509 delta += 2+alen;
7510 goto decode_success;
7511 }
7512 }
7513
sewardj0bd7ce62004-12-05 02:47:40 +00007514 /* 0F 16 = MOVHPS -- move from mem to high half of XMM. */
7515 /* 0F 16 = MOVLHPS -- move from lo half to hi half of XMM. */
sewardjc2feffc2004-12-08 12:31:22 +00007516 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x16) {
sewardj0bd7ce62004-12-05 02:47:40 +00007517 modrm = getIByte(delta+2);
7518 if (epartIsReg(modrm)) {
7519 delta += 2+1;
7520 putXMMRegLane64( gregOfRM(modrm), 1/*upper lane*/,
7521 getXMMRegLane64( eregOfRM(modrm), 0 ) );
7522 DIP("movhps %s,%s\n", nameXMMReg(eregOfRM(modrm)),
7523 nameXMMReg(gregOfRM(modrm)));
7524 } else {
7525 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
7526 delta += 2+alen;
7527 putXMMRegLane64( gregOfRM(modrm), 1/*upper lane*/,
7528 loadLE(Ity_I64, mkexpr(addr)) );
7529 DIP("movhps %s,%s\n", dis_buf,
sewardjc2feffc2004-12-08 12:31:22 +00007530 nameXMMReg( gregOfRM(modrm) ));
sewardj0bd7ce62004-12-05 02:47:40 +00007531 }
7532 goto decode_success;
7533 }
7534
7535 /* 0F 17 = MOVHPS -- move from high half of XMM to mem. */
sewardjc2feffc2004-12-08 12:31:22 +00007536 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x17) {
sewardj0bd7ce62004-12-05 02:47:40 +00007537 if (!epartIsReg(insn[2])) {
sewardj0bd7ce62004-12-05 02:47:40 +00007538 delta += 2;
7539 addr = disAMode ( &alen, sorb, delta, dis_buf );
7540 delta += alen;
7541 storeLE( mkexpr(addr),
7542 getXMMRegLane64( gregOfRM(insn[2]),
7543 1/*upper lane*/ ) );
7544 DIP("movhps %s,%s\n", nameXMMReg( gregOfRM(insn[2]) ),
7545 dis_buf);
7546 goto decode_success;
7547 }
7548 /* else fall through */
7549 }
7550
7551 /* 0F 12 = MOVLPS -- move from mem to low half of XMM. */
7552 /* OF 12 = MOVHLPS -- from from hi half to lo half of XMM. */
sewardjc2feffc2004-12-08 12:31:22 +00007553 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x12) {
sewardj0bd7ce62004-12-05 02:47:40 +00007554 modrm = getIByte(delta+2);
7555 if (epartIsReg(modrm)) {
7556 delta += 2+1;
7557 putXMMRegLane64( gregOfRM(modrm),
7558 0/*lower lane*/,
7559 getXMMRegLane64( eregOfRM(modrm), 1 ));
7560 DIP("movhlps %s, %s\n", nameXMMReg(eregOfRM(modrm)),
7561 nameXMMReg(gregOfRM(modrm)));
7562 } else {
7563 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
7564 delta += 2+alen;
7565 putXMMRegLane64( gregOfRM(modrm), 0/*lower lane*/,
7566 loadLE(Ity_I64, mkexpr(addr)) );
7567 DIP("movlps %s, %s\n",
7568 dis_buf, nameXMMReg( gregOfRM(modrm) ));
7569 }
7570 goto decode_success;
7571 }
7572
7573 /* 0F 13 = MOVLPS -- move from low half of XMM to mem. */
sewardjc2feffc2004-12-08 12:31:22 +00007574 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x13) {
sewardj0bd7ce62004-12-05 02:47:40 +00007575 if (!epartIsReg(insn[2])) {
sewardj0bd7ce62004-12-05 02:47:40 +00007576 delta += 2;
7577 addr = disAMode ( &alen, sorb, delta, dis_buf );
7578 delta += alen;
7579 storeLE( mkexpr(addr),
7580 getXMMRegLane64( gregOfRM(insn[2]),
7581 0/*lower lane*/ ) );
7582 DIP("movlps %s, %s\n", nameXMMReg( gregOfRM(insn[2]) ),
7583 dis_buf);
7584 goto decode_success;
7585 }
7586 /* else fall through */
7587 }
7588
sewardj9636b442004-12-04 01:38:37 +00007589 /* 0F 50 = MOVMSKPS - move 4 sign bits from 4 x F32 in xmm(E)
7590 to 4 lowest bits of ireg(G) */
7591 if (insn[0] == 0x0F && insn[1] == 0x50) {
sewardj9636b442004-12-04 01:38:37 +00007592 modrm = getIByte(delta+2);
sewardjc2feffc2004-12-08 12:31:22 +00007593 if (sz == 4 && epartIsReg(modrm)) {
7594 Int src;
7595 t0 = newTemp(Ity_I32);
7596 t1 = newTemp(Ity_I32);
7597 t2 = newTemp(Ity_I32);
7598 t3 = newTemp(Ity_I32);
sewardj129b3d92004-12-05 15:42:05 +00007599 delta += 2+1;
7600 src = eregOfRM(modrm);
7601 assign( t0, binop( Iop_And32,
7602 binop(Iop_Shr32, getXMMRegLane32(src,0), mkU8(31)),
7603 mkU32(1) ));
7604 assign( t1, binop( Iop_And32,
7605 binop(Iop_Shr32, getXMMRegLane32(src,1), mkU8(30)),
7606 mkU32(2) ));
7607 assign( t2, binop( Iop_And32,
7608 binop(Iop_Shr32, getXMMRegLane32(src,2), mkU8(29)),
7609 mkU32(4) ));
7610 assign( t3, binop( Iop_And32,
7611 binop(Iop_Shr32, getXMMRegLane32(src,3), mkU8(28)),
7612 mkU32(8) ));
7613 putIReg(4, gregOfRM(modrm),
7614 binop(Iop_Or32,
7615 binop(Iop_Or32, mkexpr(t0), mkexpr(t1)),
7616 binop(Iop_Or32, mkexpr(t2), mkexpr(t3))
7617 )
7618 );
7619 DIP("movmskps %s,%s\n", nameXMMReg(src),
7620 nameIReg(4, gregOfRM(modrm)));
7621 goto decode_success;
7622 }
7623 /* else fall through */
sewardj9636b442004-12-04 01:38:37 +00007624 }
7625
7626 /* 0F 2B = MOVNTPS -- for us, just a plain SSE store. */
sewardj703d6d62005-05-11 02:55:00 +00007627 /* 66 0F 2B = MOVNTPD -- for us, just a plain SSE store. */
sewardj9636b442004-12-04 01:38:37 +00007628 if (insn[0] == 0x0F && insn[1] == 0x2B) {
7629 modrm = getIByte(delta+2);
7630 if (!epartIsReg(modrm)) {
7631 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
7632 storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) );
sewardj703d6d62005-05-11 02:55:00 +00007633 DIP("movntp%s %s,%s\n", sz==2 ? "d" : "s",
7634 dis_buf,
7635 nameXMMReg(gregOfRM(modrm)));
sewardj9636b442004-12-04 01:38:37 +00007636 delta += 2+alen;
7637 goto decode_success;
7638 }
7639 /* else fall through */
7640 }
7641
sewardjc2feffc2004-12-08 12:31:22 +00007642 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
sewardj9636b442004-12-04 01:38:37 +00007643 /* 0F E7 = MOVNTQ -- for us, just a plain MMX store. Note, the
7644 Intel manual does not say anything about the usual business of
7645 the FP reg tags getting trashed whenever an MMX insn happens.
7646 So we just leave them alone.
7647 */
7648 if (insn[0] == 0x0F && insn[1] == 0xE7) {
7649 modrm = getIByte(delta+2);
sewardjc2feffc2004-12-08 12:31:22 +00007650 if (sz == 4 && !epartIsReg(modrm)) {
sewardj519d66f2004-12-15 11:57:58 +00007651 /* do_MMX_preamble(); Intel docs don't specify this */
sewardj9636b442004-12-04 01:38:37 +00007652 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
7653 storeLE( mkexpr(addr), getMMXReg(gregOfRM(modrm)) );
7654 DIP("movntq %s,%s\n", dis_buf,
7655 nameMMXReg(gregOfRM(modrm)));
7656 delta += 2+alen;
7657 goto decode_success;
7658 }
7659 /* else fall through */
7660 }
7661
7662 /* F3 0F 10 = MOVSS -- move 32 bits from E (mem or lo 1/4 xmm) to G
7663 (lo 1/4 xmm). If E is mem, upper 3/4 of G is zeroed out. */
7664 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x10) {
7665 vassert(sz == 4);
7666 modrm = getIByte(delta+3);
7667 if (epartIsReg(modrm)) {
7668 putXMMRegLane32( gregOfRM(modrm), 0,
7669 getXMMRegLane32( eregOfRM(modrm), 0 ));
7670 DIP("movss %s,%s\n", nameXMMReg(eregOfRM(modrm)),
7671 nameXMMReg(gregOfRM(modrm)));
7672 delta += 3+1;
7673 } else {
7674 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
sewardjad50db02005-04-06 01:45:44 +00007675 /* zero bits 127:64 */
7676 putXMMRegLane64( gregOfRM(modrm), 1, mkU64(0) );
7677 /* zero bits 63:32 */
7678 putXMMRegLane32( gregOfRM(modrm), 1, mkU32(0) );
7679 /* write bits 31:0 */
sewardj9636b442004-12-04 01:38:37 +00007680 putXMMRegLane32( gregOfRM(modrm), 0,
7681 loadLE(Ity_I32, mkexpr(addr)) );
7682 DIP("movss %s,%s\n", dis_buf,
7683 nameXMMReg(gregOfRM(modrm)));
7684 delta += 3+alen;
7685 }
7686 goto decode_success;
7687 }
7688
7689 /* F3 0F 11 = MOVSS -- move 32 bits from G (lo 1/4 xmm) to E (mem
7690 or lo 1/4 xmm). */
7691 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x11) {
7692 vassert(sz == 4);
7693 modrm = getIByte(delta+3);
7694 if (epartIsReg(modrm)) {
7695 /* fall through, we don't yet have a test case */
7696 } else {
7697 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
7698 storeLE( mkexpr(addr),
sewardj519d66f2004-12-15 11:57:58 +00007699 getXMMRegLane32(gregOfRM(modrm), 0) );
7700 DIP("movss %s,%s\n", nameXMMReg(gregOfRM(modrm)),
sewardj9636b442004-12-04 01:38:37 +00007701 dis_buf);
7702 delta += 3+alen;
7703 goto decode_success;
7704 }
7705 }
7706
7707 /* 0F 59 = MULPS -- mul 32Fx4 from R/M to R */
sewardj008754b2004-12-08 14:37:10 +00007708 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x59) {
sewardj129b3d92004-12-05 15:42:05 +00007709 delta = dis_SSE_E_to_G_all( sorb, delta+2, "mulps", Iop_Mul32Fx4 );
sewardj9636b442004-12-04 01:38:37 +00007710 goto decode_success;
7711 }
7712
7713 /* F3 0F 59 = MULSS -- mul 32F0x4 from R/M to R */
7714 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x59) {
7715 vassert(sz == 4);
sewardj129b3d92004-12-05 15:42:05 +00007716 delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "mulss", Iop_Mul32F0x4 );
sewardj9636b442004-12-04 01:38:37 +00007717 goto decode_success;
7718 }
7719
7720 /* 0F 56 = ORPS -- G = G and E */
sewardj008754b2004-12-08 14:37:10 +00007721 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x56) {
sewardjf0c1c582005-02-07 23:47:38 +00007722 delta = dis_SSE_E_to_G_all( sorb, delta+2, "orps", Iop_OrV128 );
sewardj9636b442004-12-04 01:38:37 +00007723 goto decode_success;
7724 }
7725
sewardj3bca9062004-12-04 14:36:09 +00007726 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
7727 /* 0F E0 = PAVGB -- 8x8 unsigned Packed Average, with rounding */
sewardj164f9272004-12-09 00:39:32 +00007728 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xE0) {
sewardjb5452082004-12-04 20:33:02 +00007729 do_MMX_preamble();
7730 delta = dis_MMXop_regmem_to_reg (
7731 sorb, delta+2, insn[1], "pavgb", False );
7732 goto decode_success;
sewardj3bca9062004-12-04 14:36:09 +00007733 }
7734
sewardjb5452082004-12-04 20:33:02 +00007735 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
7736 /* 0F E3 = PAVGW -- 16x4 unsigned Packed Average, with rounding */
sewardj164f9272004-12-09 00:39:32 +00007737 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xE3) {
sewardjb5452082004-12-04 20:33:02 +00007738 do_MMX_preamble();
7739 delta = dis_MMXop_regmem_to_reg (
7740 sorb, delta+2, insn[1], "pavgw", False );
7741 goto decode_success;
7742 }
7743
7744 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
7745 /* 0F C5 = PEXTRW -- extract 16-bit field from mmx(E) and put
7746 zero-extend of it in ireg(G). */
7747 if (insn[0] == 0x0F && insn[1] == 0xC5) {
7748 modrm = insn[2];
7749 if (sz == 4 && epartIsReg(modrm)) {
sewardjb9fa69b2004-12-09 23:25:14 +00007750 IRTemp sV = newTemp(Ity_I64);
7751 t5 = newTemp(Ity_I16);
sewardjb5452082004-12-04 20:33:02 +00007752 do_MMX_preamble();
sewardjb9fa69b2004-12-09 23:25:14 +00007753 assign(sV, getMMXReg(eregOfRM(modrm)));
7754 breakup64to16s( sV, &t3, &t2, &t1, &t0 );
sewardjb5452082004-12-04 20:33:02 +00007755 switch (insn[3] & 3) {
sewardjb9fa69b2004-12-09 23:25:14 +00007756 case 0: assign(t5, mkexpr(t0)); break;
7757 case 1: assign(t5, mkexpr(t1)); break;
7758 case 2: assign(t5, mkexpr(t2)); break;
7759 case 3: assign(t5, mkexpr(t3)); break;
sewardjba89f4c2005-04-07 17:31:27 +00007760 default: vassert(0); /*NOTREACHED*/
sewardjb5452082004-12-04 20:33:02 +00007761 }
sewardjb9fa69b2004-12-09 23:25:14 +00007762 putIReg(4, gregOfRM(modrm), unop(Iop_16Uto32, mkexpr(t5)));
sewardjb5452082004-12-04 20:33:02 +00007763 DIP("pextrw $%d,%s,%s\n",
7764 (Int)insn[3], nameMMXReg(eregOfRM(modrm)),
7765 nameIReg(4,gregOfRM(modrm)));
7766 delta += 4;
7767 goto decode_success;
7768 }
7769 /* else fall through */
7770 }
7771
7772 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
7773 /* 0F C4 = PINSRW -- get 16 bits from E(mem or low half ireg) and
7774 put it into the specified lane of mmx(G). */
sewardje5854d62004-12-09 03:44:34 +00007775 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xC4) {
7776 /* Use t0 .. t3 to hold the 4 original 16-bit lanes of the
7777 mmx reg. t4 is the new lane value. t5 is the original
7778 mmx value. t6 is the new mmx value. */
7779 Int lane;
sewardje5854d62004-12-09 03:44:34 +00007780 t4 = newTemp(Ity_I16);
7781 t5 = newTemp(Ity_I64);
7782 t6 = newTemp(Ity_I64);
7783 modrm = insn[2];
7784 do_MMX_preamble();
sewardjb5452082004-12-04 20:33:02 +00007785
sewardje5854d62004-12-09 03:44:34 +00007786 assign(t5, getMMXReg(gregOfRM(modrm)));
sewardjb9fa69b2004-12-09 23:25:14 +00007787 breakup64to16s( t5, &t3, &t2, &t1, &t0 );
sewardjb5452082004-12-04 20:33:02 +00007788
sewardje5854d62004-12-09 03:44:34 +00007789 if (epartIsReg(modrm)) {
7790 assign(t4, getIReg(2, eregOfRM(modrm)));
sewardjaac7e082005-03-17 14:03:46 +00007791 delta += 3+1;
7792 lane = insn[3+1-1];
sewardje5854d62004-12-09 03:44:34 +00007793 DIP("pinsrw $%d,%s,%s\n", (Int)lane,
7794 nameIReg(2,eregOfRM(modrm)),
7795 nameMMXReg(gregOfRM(modrm)));
7796 } else {
sewardj7420b092005-03-13 20:19:19 +00007797 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
7798 delta += 3+alen;
7799 lane = insn[3+alen-1];
7800 assign(t4, loadLE(Ity_I16, mkexpr(addr)));
7801 DIP("pinsrw $%d,%s,%s\n", (Int)lane,
7802 dis_buf,
7803 nameMMXReg(gregOfRM(modrm)));
sewardjb5452082004-12-04 20:33:02 +00007804 }
sewardje5854d62004-12-09 03:44:34 +00007805
7806 switch (lane & 3) {
sewardjb9fa69b2004-12-09 23:25:14 +00007807 case 0: assign(t6, mk64from16s(t3,t2,t1,t4)); break;
7808 case 1: assign(t6, mk64from16s(t3,t2,t4,t0)); break;
7809 case 2: assign(t6, mk64from16s(t3,t4,t1,t0)); break;
7810 case 3: assign(t6, mk64from16s(t4,t2,t1,t0)); break;
sewardjba89f4c2005-04-07 17:31:27 +00007811 default: vassert(0); /*NOTREACHED*/
sewardje5854d62004-12-09 03:44:34 +00007812 }
7813 putMMXReg(gregOfRM(modrm), mkexpr(t6));
7814 goto decode_success;
sewardjb5452082004-12-04 20:33:02 +00007815 }
7816
7817 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
7818 /* 0F EE = PMAXSW -- 16x4 signed max */
sewardje5854d62004-12-09 03:44:34 +00007819 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xEE) {
sewardjb5452082004-12-04 20:33:02 +00007820 do_MMX_preamble();
7821 delta = dis_MMXop_regmem_to_reg (
7822 sorb, delta+2, insn[1], "pmaxsw", False );
7823 goto decode_success;
7824 }
7825
7826 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
7827 /* 0F DE = PMAXUB -- 8x8 unsigned max */
sewardje5854d62004-12-09 03:44:34 +00007828 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xDE) {
sewardjb5452082004-12-04 20:33:02 +00007829 do_MMX_preamble();
7830 delta = dis_MMXop_regmem_to_reg (
7831 sorb, delta+2, insn[1], "pmaxub", False );
7832 goto decode_success;
7833 }
7834
7835 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
7836 /* 0F EA = PMINSW -- 16x4 signed min */
sewardje5854d62004-12-09 03:44:34 +00007837 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xEA) {
sewardjb5452082004-12-04 20:33:02 +00007838 do_MMX_preamble();
7839 delta = dis_MMXop_regmem_to_reg (
7840 sorb, delta+2, insn[1], "pminsw", False );
7841 goto decode_success;
7842 }
7843
7844 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
7845 /* 0F DA = PMINUB -- 8x8 unsigned min */
sewardje5854d62004-12-09 03:44:34 +00007846 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xDA) {
sewardjb5452082004-12-04 20:33:02 +00007847 do_MMX_preamble();
7848 delta = dis_MMXop_regmem_to_reg (
7849 sorb, delta+2, insn[1], "pminub", False );
7850 goto decode_success;
7851 }
7852
7853 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
7854 /* 0F D7 = PMOVMSKB -- extract sign bits from each of 8 lanes in
7855 mmx(G), turn them into a byte, and put zero-extend of it in
7856 ireg(G). */
sewardje5854d62004-12-09 03:44:34 +00007857 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xD7) {
sewardjb5452082004-12-04 20:33:02 +00007858 modrm = insn[2];
sewardje5854d62004-12-09 03:44:34 +00007859 if (epartIsReg(modrm)) {
sewardjb5452082004-12-04 20:33:02 +00007860 do_MMX_preamble();
7861 t0 = newTemp(Ity_I64);
7862 t1 = newTemp(Ity_I32);
7863 assign(t0, getMMXReg(eregOfRM(modrm)));
7864 assign(t1, mkIRExprCCall(
7865 Ity_I32, 0/*regparms*/,
sewardj38a3f862005-01-13 15:06:51 +00007866 "x86g_calculate_mmx_pmovmskb",
7867 &x86g_calculate_mmx_pmovmskb,
sewardjb5452082004-12-04 20:33:02 +00007868 mkIRExprVec_1(mkexpr(t0))));
7869 putIReg(4, gregOfRM(modrm), mkexpr(t1));
7870 DIP("pmovmskb %s,%s\n", nameMMXReg(eregOfRM(modrm)),
7871 nameIReg(4,gregOfRM(modrm)));
7872 delta += 3;
7873 goto decode_success;
7874 }
7875 /* else fall through */
7876 }
7877
sewardj0bd7ce62004-12-05 02:47:40 +00007878 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
7879 /* 0F E4 = PMULUH -- 16x4 hi-half of unsigned widening multiply */
sewardje5854d62004-12-09 03:44:34 +00007880 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xE4) {
sewardj0bd7ce62004-12-05 02:47:40 +00007881 do_MMX_preamble();
7882 delta = dis_MMXop_regmem_to_reg (
7883 sorb, delta+2, insn[1], "pmuluh", False );
7884 goto decode_success;
7885 }
7886
sewardj7df596b2004-12-06 14:29:12 +00007887 /* 0F 18 /0 = PREFETCHNTA -- prefetch into caches, */
7888 /* 0F 18 /1 = PREFETCH0 -- with various different hints */
7889 /* 0F 18 /2 = PREFETCH1 */
7890 /* 0F 18 /3 = PREFETCH2 */
7891 if (insn[0] == 0x0F && insn[1] == 0x18
7892 && !epartIsReg(insn[2])
7893 && gregOfRM(insn[2]) >= 0 && gregOfRM(insn[2]) <= 3) {
7894 HChar* hintstr = "??";
7895
7896 modrm = getIByte(delta+2);
7897 vassert(!epartIsReg(modrm));
7898
7899 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
7900 delta += 2+alen;
7901
7902 switch (gregOfRM(modrm)) {
7903 case 0: hintstr = "nta"; break;
7904 case 1: hintstr = "t0"; break;
7905 case 2: hintstr = "t1"; break;
7906 case 3: hintstr = "t2"; break;
sewardjba89f4c2005-04-07 17:31:27 +00007907 default: vassert(0); /*NOTREACHED*/
sewardj7df596b2004-12-06 14:29:12 +00007908 }
7909
7910 DIP("prefetch%s %s\n", hintstr, dis_buf);
7911 goto decode_success;
7912 }
7913
sewardj0bd7ce62004-12-05 02:47:40 +00007914 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
7915 /* 0F F6 = PSADBW -- sum of 8Ux8 absolute differences */
7916 if (insn[0] == 0x0F && insn[1] == 0xF6) {
7917 vassert(sz == 4);
7918 do_MMX_preamble();
7919 delta = dis_MMXop_regmem_to_reg (
7920 sorb, delta+2, insn[1], "psadbw", False );
7921 goto decode_success;
7922 }
7923
7924 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
7925 /* 0F 70 = PSHUFW -- rearrange 4x16 from E(mmx or mem) to G(mmx) */
sewardjb9fa69b2004-12-09 23:25:14 +00007926 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x70) {
sewardj0bd7ce62004-12-05 02:47:40 +00007927 Int order;
sewardjb9fa69b2004-12-09 23:25:14 +00007928 IRTemp sV, dV, s3, s2, s1, s0;
7929 s3 = s2 = s1 = s0 = IRTemp_INVALID;
7930 sV = newTemp(Ity_I64);
7931 dV = newTemp(Ity_I64);
sewardj0bd7ce62004-12-05 02:47:40 +00007932 do_MMX_preamble();
7933 modrm = insn[2];
7934 if (epartIsReg(modrm)) {
sewardjb9fa69b2004-12-09 23:25:14 +00007935 assign( sV, getMMXReg(eregOfRM(modrm)) );
sewardj0bd7ce62004-12-05 02:47:40 +00007936 order = (Int)insn[3];
7937 delta += 2+2;
7938 DIP("pshufw $%d,%s,%s\n", order,
7939 nameMMXReg(eregOfRM(modrm)),
7940 nameMMXReg(gregOfRM(modrm)));
7941 } else {
7942 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
sewardjb9fa69b2004-12-09 23:25:14 +00007943 assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
sewardj0bd7ce62004-12-05 02:47:40 +00007944 order = (Int)insn[2+alen];
7945 delta += 3+alen;
7946 DIP("pshufw $%d,%s,%s\n", order,
7947 dis_buf,
7948 nameMMXReg(gregOfRM(modrm)));
7949 }
sewardjb9fa69b2004-12-09 23:25:14 +00007950 breakup64to16s( sV, &s3, &s2, &s1, &s0 );
sewardj0bd7ce62004-12-05 02:47:40 +00007951
sewardjb9fa69b2004-12-09 23:25:14 +00007952# define SEL(n) \
7953 ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
7954 assign(dV,
7955 mk64from16s( SEL((order>>6)&3), SEL((order>>4)&3),
7956 SEL((order>>2)&3), SEL((order>>0)&3) )
sewardj0bd7ce62004-12-05 02:47:40 +00007957 );
sewardjb9fa69b2004-12-09 23:25:14 +00007958 putMMXReg(gregOfRM(modrm), mkexpr(dV));
sewardj0bd7ce62004-12-05 02:47:40 +00007959# undef SEL
sewardj0bd7ce62004-12-05 02:47:40 +00007960 goto decode_success;
7961 }
7962
7963 /* 0F 53 = RCPPS -- approx reciprocal 32Fx4 from R/M to R */
7964 if (insn[0] == 0x0F && insn[1] == 0x53) {
7965 vassert(sz == 4);
sewardj129b3d92004-12-05 15:42:05 +00007966 delta = dis_SSE_E_to_G_unary_all( sorb, delta+2,
7967 "rcpps", Iop_Recip32Fx4 );
sewardj0bd7ce62004-12-05 02:47:40 +00007968 goto decode_success;
7969 }
7970
7971 /* F3 0F 53 = RCPSS -- approx reciprocal 32F0x4 from R/M to R */
7972 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x53) {
7973 vassert(sz == 4);
sewardj129b3d92004-12-05 15:42:05 +00007974 delta = dis_SSE_E_to_G_unary_lo32( sorb, delta+3,
7975 "rcpss", Iop_Recip32F0x4 );
sewardj0bd7ce62004-12-05 02:47:40 +00007976 goto decode_success;
7977 }
sewardjb5452082004-12-04 20:33:02 +00007978
sewardjc1e7dfc2004-12-05 19:29:45 +00007979 /* 0F 52 = RSQRTPS -- approx reciprocal sqrt 32Fx4 from R/M to R */
7980 if (insn[0] == 0x0F && insn[1] == 0x52) {
7981 vassert(sz == 4);
7982 delta = dis_SSE_E_to_G_unary_all( sorb, delta+2,
7983 "rsqrtps", Iop_RSqrt32Fx4 );
7984 goto decode_success;
7985 }
7986
7987 /* F3 0F 52 = RSQRTSS -- approx reciprocal sqrt 32F0x4 from R/M to R */
7988 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x52) {
7989 vassert(sz == 4);
7990 delta = dis_SSE_E_to_G_unary_lo32( sorb, delta+3,
7991 "rsqrtss", Iop_RSqrt32F0x4 );
7992 goto decode_success;
7993 }
7994
7995 /* 0F AE /7 = SFENCE -- flush pending operations to memory */
7996 if (insn[0] == 0x0F && insn[1] == 0xAE
sewardjc2feffc2004-12-08 12:31:22 +00007997 && epartIsReg(insn[2]) && gregOfRM(insn[2]) == 7) {
sewardjc1e7dfc2004-12-05 19:29:45 +00007998 vassert(sz == 4);
7999 delta += 3;
sewardj3e838932005-01-07 12:09:15 +00008000 /* Insert a memory fence. It's sometimes important that these
8001 are carried through to the generated code. */
8002 stmt( IRStmt_MFence() );
sewardjc1e7dfc2004-12-05 19:29:45 +00008003 DIP("sfence\n");
8004 goto decode_success;
8005 }
8006
8007 /* 0F C6 /r ib = SHUFPS -- shuffle packed F32s */
sewardj008754b2004-12-08 14:37:10 +00008008 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xC6) {
sewardjc1e7dfc2004-12-05 19:29:45 +00008009 Int select;
8010 IRTemp sV, dV;
8011 IRTemp s3, s2, s1, s0, d3, d2, d1, d0;
8012 sV = newTemp(Ity_V128);
8013 dV = newTemp(Ity_V128);
8014 s3 = s2 = s1 = s0 = d3 = d2 = d1 = d0 = IRTemp_INVALID;
sewardjc1e7dfc2004-12-05 19:29:45 +00008015 modrm = insn[2];
8016 assign( dV, getXMMReg(gregOfRM(modrm)) );
8017
8018 if (epartIsReg(modrm)) {
8019 assign( sV, getXMMReg(eregOfRM(modrm)) );
8020 select = (Int)insn[3];
8021 delta += 2+2;
8022 DIP("shufps $%d,%s,%s\n", select,
8023 nameXMMReg(eregOfRM(modrm)),
8024 nameXMMReg(gregOfRM(modrm)));
8025 } else {
8026 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8027 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
8028 select = (Int)insn[2+alen];
8029 delta += 3+alen;
8030 DIP("shufps $%d,%s,%s\n", select,
8031 dis_buf,
8032 nameXMMReg(gregOfRM(modrm)));
8033 }
8034
8035 breakup128to32s( dV, &d3, &d2, &d1, &d0 );
8036 breakup128to32s( sV, &s3, &s2, &s1, &s0 );
8037
8038# define SELD(n) ((n)==0 ? d0 : ((n)==1 ? d1 : ((n)==2 ? d2 : d3)))
8039# define SELS(n) ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
8040
8041 putXMMReg(
8042 gregOfRM(modrm),
8043 mk128from32s( SELS((select>>6)&3), SELS((select>>4)&3),
8044 SELD((select>>2)&3), SELD((select>>0)&3) )
8045 );
8046
8047# undef SELD
8048# undef SELS
8049
8050 goto decode_success;
8051 }
8052
8053 /* 0F 51 = SQRTPS -- approx sqrt 32Fx4 from R/M to R */
sewardj008754b2004-12-08 14:37:10 +00008054 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x51) {
sewardjc1e7dfc2004-12-05 19:29:45 +00008055 delta = dis_SSE_E_to_G_unary_all( sorb, delta+2,
8056 "sqrtps", Iop_Sqrt32Fx4 );
8057 goto decode_success;
8058 }
8059
8060 /* F3 0F 51 = SQRTSS -- approx sqrt 32F0x4 from R/M to R */
8061 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x51) {
8062 vassert(sz == 4);
8063 delta = dis_SSE_E_to_G_unary_lo32( sorb, delta+3,
8064 "sqrtss", Iop_Sqrt32F0x4 );
8065 goto decode_success;
8066 }
8067
sewardja0e83b02005-01-06 12:36:38 +00008068 /* 0F AE /3 = STMXCSR m32 -- store %mxcsr */
sewardj7df596b2004-12-06 14:29:12 +00008069 if (insn[0] == 0x0F && insn[1] == 0xAE
8070 && !epartIsReg(insn[2]) && gregOfRM(insn[2]) == 3) {
8071 modrm = getIByte(delta+2);
8072 vassert(sz == 4);
8073 vassert(!epartIsReg(modrm));
8074
8075 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8076 delta += 2+alen;
8077
8078 /* Fake up a native SSE mxcsr word. The only thing it depends
8079 on is SSEROUND[1:0], so call a clean helper to cook it up.
8080 */
8081 /* UInt x86h_create_mxcsr ( UInt sseround ) */
sewardj33dd31b2005-01-08 18:17:32 +00008082 DIP("stmxcsr %s\n", dis_buf);
sewardj7df596b2004-12-06 14:29:12 +00008083 storeLE( mkexpr(addr),
8084 mkIRExprCCall(
8085 Ity_I32, 0/*regp*/,
sewardj3bd6f3e2004-12-13 10:48:19 +00008086 "x86g_create_mxcsr", &x86g_create_mxcsr,
sewardja0e83b02005-01-06 12:36:38 +00008087 mkIRExprVec_1( get_sse_roundingmode() )
sewardj7df596b2004-12-06 14:29:12 +00008088 )
8089 );
8090 goto decode_success;
8091 }
8092
sewardjc1e7dfc2004-12-05 19:29:45 +00008093 /* 0F 5C = SUBPS -- sub 32Fx4 from R/M to R */
sewardj008754b2004-12-08 14:37:10 +00008094 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5C) {
sewardjc1e7dfc2004-12-05 19:29:45 +00008095 delta = dis_SSE_E_to_G_all( sorb, delta+2, "subps", Iop_Sub32Fx4 );
8096 goto decode_success;
8097 }
8098
sewardj008754b2004-12-08 14:37:10 +00008099 /* F3 0F 5C = SUBSS -- sub 32F0x4 from R/M to R */
sewardjc1e7dfc2004-12-05 19:29:45 +00008100 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5C) {
8101 vassert(sz == 4);
8102 delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "subss", Iop_Sub32F0x4 );
8103 goto decode_success;
8104 }
8105
8106 /* 0F 15 = UNPCKHPS -- unpack and interleave high part F32s */
8107 /* 0F 14 = UNPCKLPS -- unpack and interleave low part F32s */
8108 /* These just appear to be special cases of SHUFPS */
sewardj008754b2004-12-08 14:37:10 +00008109 if (sz == 4 && insn[0] == 0x0F && (insn[1] == 0x15 || insn[1] == 0x14)) {
sewardjc1e7dfc2004-12-05 19:29:45 +00008110 IRTemp sV, dV;
8111 IRTemp s3, s2, s1, s0, d3, d2, d1, d0;
sewardj2d49b432005-02-01 00:37:06 +00008112 Bool hi = toBool(insn[1] == 0x15);
sewardjc1e7dfc2004-12-05 19:29:45 +00008113 sV = newTemp(Ity_V128);
8114 dV = newTemp(Ity_V128);
8115 s3 = s2 = s1 = s0 = d3 = d2 = d1 = d0 = IRTemp_INVALID;
sewardjc1e7dfc2004-12-05 19:29:45 +00008116 modrm = insn[2];
8117 assign( dV, getXMMReg(gregOfRM(modrm)) );
8118
8119 if (epartIsReg(modrm)) {
8120 assign( sV, getXMMReg(eregOfRM(modrm)) );
8121 delta += 2+1;
8122 DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
8123 nameXMMReg(eregOfRM(modrm)),
8124 nameXMMReg(gregOfRM(modrm)));
8125 } else {
8126 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8127 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
8128 delta += 2+alen;
8129 DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
8130 dis_buf,
8131 nameXMMReg(gregOfRM(modrm)));
8132 }
8133
8134 breakup128to32s( dV, &d3, &d2, &d1, &d0 );
8135 breakup128to32s( sV, &s3, &s2, &s1, &s0 );
8136
8137 if (hi) {
8138 putXMMReg( gregOfRM(modrm), mk128from32s( s3, d3, s2, d2 ) );
8139 } else {
8140 putXMMReg( gregOfRM(modrm), mk128from32s( s1, d1, s0, d0 ) );
8141 }
8142
8143 goto decode_success;
8144 }
8145
8146 /* 0F 57 = XORPS -- G = G and E */
sewardj008754b2004-12-08 14:37:10 +00008147 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x57) {
sewardjf0c1c582005-02-07 23:47:38 +00008148 delta = dis_SSE_E_to_G_all( sorb, delta+2, "xorps", Iop_XorV128 );
sewardjc1e7dfc2004-12-05 19:29:45 +00008149 goto decode_success;
8150 }
8151
sewardj636ad762004-12-07 11:16:04 +00008152 /* ---------------------------------------------------- */
8153 /* --- end of the SSE decoder. --- */
8154 /* ---------------------------------------------------- */
8155
8156 /* ---------------------------------------------------- */
8157 /* --- start of the SSE2 decoder. --- */
8158 /* ---------------------------------------------------- */
8159
sewardj9df271d2004-12-31 22:37:42 +00008160 /* Skip parts of the decoder which don't apply given the stated
8161 guest subarchitecture. */
sewardj27e1dd62005-06-30 11:49:14 +00008162 if (archinfo->subarch == VexSubArchX86_sse0
8163 || archinfo->subarch == VexSubArchX86_sse1)
sewardj9df271d2004-12-31 22:37:42 +00008164 goto after_sse_decoders;
8165
sewardj636ad762004-12-07 11:16:04 +00008166 insn = (UChar*)&guest_code[delta];
8167
8168 /* 66 0F 58 = ADDPD -- add 32Fx4 from R/M to R */
8169 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x58) {
8170 delta = dis_SSE_E_to_G_all( sorb, delta+2, "addpd", Iop_Add64Fx2 );
8171 goto decode_success;
8172 }
8173
8174 /* F2 0F 58 = ADDSD -- add 64F0x2 from R/M to R */
8175 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x58) {
8176 vassert(sz == 4);
8177 delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "addsd", Iop_Add64F0x2 );
8178 goto decode_success;
8179 }
8180
8181 /* 66 0F 55 = ANDNPD -- G = (not G) and E */
8182 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x55) {
sewardjf0c1c582005-02-07 23:47:38 +00008183 delta = dis_SSE_E_to_G_all_invG( sorb, delta+2, "andnpd", Iop_AndV128 );
sewardj636ad762004-12-07 11:16:04 +00008184 goto decode_success;
8185 }
8186
8187 /* 66 0F 54 = ANDPD -- G = G and E */
8188 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x54) {
sewardjf0c1c582005-02-07 23:47:38 +00008189 delta = dis_SSE_E_to_G_all( sorb, delta+2, "andpd", Iop_AndV128 );
sewardj636ad762004-12-07 11:16:04 +00008190 goto decode_success;
8191 }
8192
sewardjfd226452004-12-07 19:02:18 +00008193 /* 66 0F C2 = CMPPD -- 64Fx2 comparison from R/M to R */
8194 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xC2) {
8195 delta = dis_SSEcmp_E_to_G( sorb, delta+2, "cmppd", True, 8 );
8196 goto decode_success;
8197 }
8198
8199 /* F2 0F C2 = CMPSD -- 64F0x2 comparison from R/M to R */
8200 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0xC2) {
8201 vassert(sz == 4);
8202 delta = dis_SSEcmp_E_to_G( sorb, delta+3, "cmpsd", False, 8 );
8203 goto decode_success;
8204 }
8205
8206 /* 66 0F 2F = COMISD -- 64F0x2 comparison G,E, and set ZCP */
8207 /* 66 0F 2E = UCOMISD -- 64F0x2 comparison G,E, and set ZCP */
8208 if (sz == 2 && insn[0] == 0x0F && (insn[1] == 0x2F || insn[1] == 0x2E)) {
8209 IRTemp argL = newTemp(Ity_F64);
8210 IRTemp argR = newTemp(Ity_F64);
8211 modrm = getIByte(delta+2);
8212 if (epartIsReg(modrm)) {
8213 assign( argR, getXMMRegLane64F( eregOfRM(modrm), 0/*lowest lane*/ ) );
8214 delta += 2+1;
8215 DIP("[u]comisd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
8216 nameXMMReg(gregOfRM(modrm)) );
8217 } else {
8218 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8219 assign( argR, loadLE(Ity_F64, mkexpr(addr)) );
8220 delta += 2+alen;
8221 DIP("[u]comisd %s,%s\n", dis_buf,
8222 nameXMMReg(gregOfRM(modrm)) );
8223 }
8224 assign( argL, getXMMRegLane64F( gregOfRM(modrm), 0/*lowest lane*/ ) );
8225
8226 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
8227 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
8228 stmt( IRStmt_Put(
8229 OFFB_CC_DEP1,
8230 binop( Iop_And32,
8231 binop(Iop_CmpF64, mkexpr(argL), mkexpr(argR)),
8232 mkU32(0x45)
8233 )));
sewardja3b7e3a2005-04-05 01:54:19 +00008234 /* Set NDEP even though it isn't used. This makes redundant-PUT
8235 elimination of previous stores to this field work better. */
8236 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardjfd226452004-12-07 19:02:18 +00008237 goto decode_success;
8238 }
8239
8240 /* F3 0F E6 = CVTDQ2PD -- convert 2 x I32 in mem/lo half xmm to 2 x
8241 F64 in xmm(G) */
8242 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0xE6) {
8243 IRTemp arg64 = newTemp(Ity_I64);
8244 vassert(sz == 4);
8245
8246 modrm = getIByte(delta+3);
8247 if (epartIsReg(modrm)) {
8248 assign( arg64, getXMMRegLane64(eregOfRM(modrm), 0) );
8249 delta += 3+1;
8250 DIP("cvtdq2pd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
8251 nameXMMReg(gregOfRM(modrm)));
8252 } else {
8253 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
8254 assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
8255 delta += 3+alen;
8256 DIP("cvtdq2pd %s,%s\n", dis_buf,
8257 nameXMMReg(gregOfRM(modrm)) );
8258 }
8259
8260 putXMMRegLane64F(
8261 gregOfRM(modrm), 0,
8262 unop(Iop_I32toF64, unop(Iop_64to32, mkexpr(arg64)))
8263 );
8264
8265 putXMMRegLane64F(
8266 gregOfRM(modrm), 1,
8267 unop(Iop_I32toF64, unop(Iop_64HIto32, mkexpr(arg64)))
8268 );
8269
8270 goto decode_success;
8271 }
8272
8273 /* 0F 5B = CVTDQ2PS -- convert 4 x I32 in mem/xmm to 4 x F32 in
8274 xmm(G) */
8275 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5B) {
8276 IRTemp argV = newTemp(Ity_V128);
8277 IRTemp rmode = newTemp(Ity_I32);
8278
8279 modrm = getIByte(delta+2);
8280 if (epartIsReg(modrm)) {
8281 assign( argV, getXMMReg(eregOfRM(modrm)) );
8282 delta += 2+1;
8283 DIP("cvtdq2ps %s,%s\n", nameXMMReg(eregOfRM(modrm)),
8284 nameXMMReg(gregOfRM(modrm)));
8285 } else {
8286 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8287 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
8288 delta += 2+alen;
8289 DIP("cvtdq2ps %s,%s\n", dis_buf,
8290 nameXMMReg(gregOfRM(modrm)) );
8291 }
8292
8293 assign( rmode, get_sse_roundingmode() );
8294 breakup128to32s( argV, &t3, &t2, &t1, &t0 );
8295
8296# define CVT(_t) binop( Iop_F64toF32, \
8297 mkexpr(rmode), \
8298 unop(Iop_I32toF64,mkexpr(_t)))
8299
8300 putXMMRegLane32F( gregOfRM(modrm), 3, CVT(t3) );
8301 putXMMRegLane32F( gregOfRM(modrm), 2, CVT(t2) );
8302 putXMMRegLane32F( gregOfRM(modrm), 1, CVT(t1) );
8303 putXMMRegLane32F( gregOfRM(modrm), 0, CVT(t0) );
8304
8305# undef CVT
8306
8307 goto decode_success;
8308 }
8309
8310 /* F2 0F E6 = CVTPD2DQ -- convert 2 x F64 in mem/xmm to 2 x I32 in
8311 lo half xmm(G), and zero upper half */
8312 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0xE6) {
8313 IRTemp argV = newTemp(Ity_V128);
8314 IRTemp rmode = newTemp(Ity_I32);
8315 vassert(sz == 4);
8316
8317 modrm = getIByte(delta+3);
8318 if (epartIsReg(modrm)) {
8319 assign( argV, getXMMReg(eregOfRM(modrm)) );
8320 delta += 3+1;
8321 DIP("cvtpd2dq %s,%s\n", nameXMMReg(eregOfRM(modrm)),
8322 nameXMMReg(gregOfRM(modrm)));
8323 } else {
8324 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
8325 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
8326 delta += 3+alen;
8327 DIP("cvtpd2dq %s,%s\n", dis_buf,
8328 nameXMMReg(gregOfRM(modrm)) );
8329 }
8330
8331 assign( rmode, get_sse_roundingmode() );
8332 t0 = newTemp(Ity_F64);
8333 t1 = newTemp(Ity_F64);
8334 assign( t0, unop(Iop_ReinterpI64asF64,
sewardjf0c1c582005-02-07 23:47:38 +00008335 unop(Iop_V128to64, mkexpr(argV))) );
sewardjfd226452004-12-07 19:02:18 +00008336 assign( t1, unop(Iop_ReinterpI64asF64,
sewardjf0c1c582005-02-07 23:47:38 +00008337 unop(Iop_V128HIto64, mkexpr(argV))) );
sewardjfd226452004-12-07 19:02:18 +00008338
8339# define CVT(_t) binop( Iop_F64toI32, \
8340 mkexpr(rmode), \
8341 mkexpr(_t) )
8342
8343 putXMMRegLane32( gregOfRM(modrm), 3, mkU32(0) );
8344 putXMMRegLane32( gregOfRM(modrm), 2, mkU32(0) );
8345 putXMMRegLane32( gregOfRM(modrm), 1, CVT(t1) );
8346 putXMMRegLane32( gregOfRM(modrm), 0, CVT(t0) );
8347
8348# undef CVT
8349
8350 goto decode_success;
8351 }
8352
8353 /* 66 0F 2D = CVTPD2PI -- convert 2 x F64 in mem/xmm to 2 x
8354 I32 in mmx, according to prevailing SSE rounding mode */
8355 /* 66 0F 2C = CVTTPD2PI -- convert 2 x F64 in mem/xmm to 2 x
8356 I32 in mmx, rounding towards zero */
8357 if (sz == 2 && insn[0] == 0x0F && (insn[1] == 0x2D || insn[1] == 0x2C)) {
8358 IRTemp dst64 = newTemp(Ity_I64);
8359 IRTemp rmode = newTemp(Ity_I32);
8360 IRTemp f64lo = newTemp(Ity_F64);
8361 IRTemp f64hi = newTemp(Ity_F64);
sewardj2d49b432005-02-01 00:37:06 +00008362 Bool r2zero = toBool(insn[1] == 0x2C);
sewardjfd226452004-12-07 19:02:18 +00008363
8364 do_MMX_preamble();
8365 modrm = getIByte(delta+2);
8366
8367 if (epartIsReg(modrm)) {
8368 delta += 2+1;
8369 assign(f64lo, getXMMRegLane64F(eregOfRM(modrm), 0));
8370 assign(f64hi, getXMMRegLane64F(eregOfRM(modrm), 1));
8371 DIP("cvt%spd2pi %s,%s\n", r2zero ? "t" : "",
8372 nameXMMReg(eregOfRM(modrm)),
8373 nameMMXReg(gregOfRM(modrm)));
8374 } else {
8375 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8376 assign(f64lo, loadLE(Ity_F64, mkexpr(addr)));
8377 assign(f64hi, loadLE(Ity_F64, binop( Iop_Add32,
8378 mkexpr(addr),
8379 mkU32(8) )));
8380 delta += 2+alen;
8381 DIP("cvt%spf2pi %s,%s\n", r2zero ? "t" : "",
8382 dis_buf,
8383 nameMMXReg(gregOfRM(modrm)));
8384 }
8385
8386 if (r2zero) {
8387 assign(rmode, mkU32((UInt)Irrm_ZERO) );
8388 } else {
8389 assign( rmode, get_sse_roundingmode() );
8390 }
8391
8392 assign(
8393 dst64,
8394 binop( Iop_32HLto64,
8395 binop( Iop_F64toI32, mkexpr(rmode), mkexpr(f64hi) ),
8396 binop( Iop_F64toI32, mkexpr(rmode), mkexpr(f64lo) )
8397 )
8398 );
8399
8400 putMMXReg(gregOfRM(modrm), mkexpr(dst64));
8401 goto decode_success;
8402 }
8403
8404 /* 66 0F 5A = CVTPD2PS -- convert 2 x F64 in mem/xmm to 2 x F32 in
8405 lo half xmm(G), and zero upper half */
8406 /* Note, this is practically identical to CVTPD2DQ. It would have
8407 been nicer to merge them together, but the insn[] offsets differ
8408 by one. */
8409 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5A) {
8410 IRTemp argV = newTemp(Ity_V128);
8411 IRTemp rmode = newTemp(Ity_I32);
8412
8413 modrm = getIByte(delta+2);
8414 if (epartIsReg(modrm)) {
8415 assign( argV, getXMMReg(eregOfRM(modrm)) );
8416 delta += 2+1;
8417 DIP("cvtpd2ps %s,%s\n", nameXMMReg(eregOfRM(modrm)),
8418 nameXMMReg(gregOfRM(modrm)));
8419 } else {
8420 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8421 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
8422 delta += 2+alen;
8423 DIP("cvtpd2ps %s,%s\n", dis_buf,
8424 nameXMMReg(gregOfRM(modrm)) );
8425 }
8426
8427 assign( rmode, get_sse_roundingmode() );
8428 t0 = newTemp(Ity_F64);
8429 t1 = newTemp(Ity_F64);
8430 assign( t0, unop(Iop_ReinterpI64asF64,
sewardjf0c1c582005-02-07 23:47:38 +00008431 unop(Iop_V128to64, mkexpr(argV))) );
sewardjfd226452004-12-07 19:02:18 +00008432 assign( t1, unop(Iop_ReinterpI64asF64,
sewardjf0c1c582005-02-07 23:47:38 +00008433 unop(Iop_V128HIto64, mkexpr(argV))) );
sewardjfd226452004-12-07 19:02:18 +00008434
8435# define CVT(_t) binop( Iop_F64toF32, \
8436 mkexpr(rmode), \
8437 mkexpr(_t) )
8438
8439 putXMMRegLane32( gregOfRM(modrm), 3, mkU32(0) );
8440 putXMMRegLane32( gregOfRM(modrm), 2, mkU32(0) );
8441 putXMMRegLane32F( gregOfRM(modrm), 1, CVT(t1) );
8442 putXMMRegLane32F( gregOfRM(modrm), 0, CVT(t0) );
8443
8444# undef CVT
8445
8446 goto decode_success;
8447 }
8448
8449 /* 66 0F 2A = CVTPI2PD -- convert 2 x I32 in mem/mmx to 2 x F64 in
8450 xmm(G) */
8451 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x2A) {
8452 IRTemp arg64 = newTemp(Ity_I64);
8453
8454 modrm = getIByte(delta+2);
8455 do_MMX_preamble();
8456 if (epartIsReg(modrm)) {
8457 assign( arg64, getMMXReg(eregOfRM(modrm)) );
8458 delta += 2+1;
8459 DIP("cvtpi2pd %s,%s\n", nameMMXReg(eregOfRM(modrm)),
8460 nameXMMReg(gregOfRM(modrm)));
8461 } else {
8462 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8463 assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
8464 delta += 2+alen;
8465 DIP("cvtpi2pd %s,%s\n", dis_buf,
8466 nameXMMReg(gregOfRM(modrm)) );
8467 }
8468
8469 putXMMRegLane64F(
8470 gregOfRM(modrm), 0,
8471 unop(Iop_I32toF64, unop(Iop_64to32, mkexpr(arg64)) )
8472 );
8473
8474 putXMMRegLane64F(
8475 gregOfRM(modrm), 1,
8476 unop(Iop_I32toF64, unop(Iop_64HIto32, mkexpr(arg64)) )
8477 );
8478
8479 goto decode_success;
8480 }
8481
8482 /* 66 0F 5B = CVTPS2DQ -- convert 4 x F32 in mem/xmm to 4 x I32 in
8483 xmm(G) */
8484 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5B) {
8485 IRTemp argV = newTemp(Ity_V128);
8486 IRTemp rmode = newTemp(Ity_I32);
8487
8488 modrm = getIByte(delta+2);
8489 if (epartIsReg(modrm)) {
8490 assign( argV, getXMMReg(eregOfRM(modrm)) );
8491 delta += 2+1;
8492 DIP("cvtps2dq %s,%s\n", nameXMMReg(eregOfRM(modrm)),
8493 nameXMMReg(gregOfRM(modrm)));
8494 } else {
8495 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8496 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
8497 delta += 2+alen;
8498 DIP("cvtps2dq %s,%s\n", dis_buf,
8499 nameXMMReg(gregOfRM(modrm)) );
8500 }
8501
8502 assign( rmode, get_sse_roundingmode() );
8503 breakup128to32s( argV, &t3, &t2, &t1, &t0 );
8504
8505 /* This is less than ideal. If it turns out to be a performance
8506 bottleneck it can be improved. */
8507# define CVT(_t) \
8508 binop( Iop_F64toI32, \
8509 mkexpr(rmode), \
8510 unop( Iop_F32toF64, \
8511 unop( Iop_ReinterpI32asF32, mkexpr(_t))) )
8512
8513 putXMMRegLane32( gregOfRM(modrm), 3, CVT(t3) );
8514 putXMMRegLane32( gregOfRM(modrm), 2, CVT(t2) );
8515 putXMMRegLane32( gregOfRM(modrm), 1, CVT(t1) );
8516 putXMMRegLane32( gregOfRM(modrm), 0, CVT(t0) );
8517
8518# undef CVT
8519
8520 goto decode_success;
8521 }
8522
8523 /* 0F 5A = CVTPS2PD -- convert 2 x F32 in low half mem/xmm to 2 x
8524 F64 in xmm(G). */
8525 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5A) {
8526 IRTemp f32lo = newTemp(Ity_F32);
8527 IRTemp f32hi = newTemp(Ity_F32);
8528
8529 modrm = getIByte(delta+2);
8530 if (epartIsReg(modrm)) {
8531 assign( f32lo, getXMMRegLane32F(eregOfRM(modrm), 0) );
8532 assign( f32hi, getXMMRegLane32F(eregOfRM(modrm), 1) );
8533 delta += 2+1;
8534 DIP("cvtps2pd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
8535 nameXMMReg(gregOfRM(modrm)));
8536 } else {
8537 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8538 assign( f32lo, loadLE(Ity_F32, mkexpr(addr)) );
8539 assign( f32hi, loadLE(Ity_F32,
8540 binop(Iop_Add32,mkexpr(addr),mkU32(4))) );
8541 delta += 2+alen;
8542 DIP("cvtps2pd %s,%s\n", dis_buf,
8543 nameXMMReg(gregOfRM(modrm)) );
8544 }
8545
8546 putXMMRegLane64F( gregOfRM(modrm), 1,
8547 unop(Iop_F32toF64, mkexpr(f32hi)) );
8548 putXMMRegLane64F( gregOfRM(modrm), 0,
8549 unop(Iop_F32toF64, mkexpr(f32lo)) );
8550
8551 goto decode_success;
8552 }
8553
8554 /* F2 0F 2D = CVTSD2SI -- convert F64 in mem/low half xmm to
8555 I32 in ireg, according to prevailing SSE rounding mode */
8556 /* F2 0F 2C = CVTTSD2SI -- convert F64 in mem/low half xmm to
sewardj0b210442005-02-23 13:28:27 +00008557 I32 in ireg, rounding towards zero */
sewardjfd226452004-12-07 19:02:18 +00008558 if (insn[0] == 0xF2 && insn[1] == 0x0F
8559 && (insn[2] == 0x2D || insn[2] == 0x2C)) {
8560 IRTemp rmode = newTemp(Ity_I32);
8561 IRTemp f64lo = newTemp(Ity_F64);
sewardj2d49b432005-02-01 00:37:06 +00008562 Bool r2zero = toBool(insn[2] == 0x2C);
sewardjfd226452004-12-07 19:02:18 +00008563 vassert(sz == 4);
8564
8565 modrm = getIByte(delta+3);
8566 if (epartIsReg(modrm)) {
8567 delta += 3+1;
8568 assign(f64lo, getXMMRegLane64F(eregOfRM(modrm), 0));
8569 DIP("cvt%ssd2si %s,%s\n", r2zero ? "t" : "",
8570 nameXMMReg(eregOfRM(modrm)),
8571 nameIReg(4, gregOfRM(modrm)));
8572 } else {
8573 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
8574 assign(f64lo, loadLE(Ity_F64, mkexpr(addr)));
8575 delta += 3+alen;
8576 DIP("cvt%ssd2si %s,%s\n", r2zero ? "t" : "",
8577 dis_buf,
8578 nameIReg(4, gregOfRM(modrm)));
8579 }
8580
8581 if (r2zero) {
8582 assign( rmode, mkU32((UInt)Irrm_ZERO) );
8583 } else {
8584 assign( rmode, get_sse_roundingmode() );
8585 }
8586
8587 putIReg(4, gregOfRM(modrm),
8588 binop( Iop_F64toI32, mkexpr(rmode), mkexpr(f64lo)) );
8589
8590 goto decode_success;
8591 }
8592
8593 /* F2 0F 5A = CVTSD2SS -- convert F64 in mem/low half xmm to F32 in
8594 low 1/4 xmm(G), according to prevailing SSE rounding mode */
8595 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x5A) {
8596 IRTemp rmode = newTemp(Ity_I32);
8597 IRTemp f64lo = newTemp(Ity_F64);
8598 vassert(sz == 4);
8599
8600 modrm = getIByte(delta+3);
8601 if (epartIsReg(modrm)) {
8602 delta += 3+1;
8603 assign(f64lo, getXMMRegLane64F(eregOfRM(modrm), 0));
8604 DIP("cvtsd2ss %s,%s\n", nameXMMReg(eregOfRM(modrm)),
8605 nameXMMReg(gregOfRM(modrm)));
8606 } else {
8607 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
8608 assign(f64lo, loadLE(Ity_F64, mkexpr(addr)));
8609 delta += 3+alen;
8610 DIP("cvtsd2ss %s,%s\n", dis_buf,
8611 nameXMMReg(gregOfRM(modrm)));
8612 }
8613
8614 assign( rmode, get_sse_roundingmode() );
8615 putXMMRegLane32F(
8616 gregOfRM(modrm), 0,
8617 binop( Iop_F64toF32, mkexpr(rmode), mkexpr(f64lo) )
8618 );
8619
8620 goto decode_success;
8621 }
8622
8623 /* F2 0F 2A = CVTSI2SD -- convert I32 in mem/ireg to F64 in low
8624 half xmm */
8625 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x2A) {
8626 IRTemp arg32 = newTemp(Ity_I32);
8627 vassert(sz == 4);
8628
8629 modrm = getIByte(delta+3);
sewardjfd226452004-12-07 19:02:18 +00008630 if (epartIsReg(modrm)) {
8631 assign( arg32, getIReg(4, eregOfRM(modrm)) );
8632 delta += 3+1;
8633 DIP("cvtsi2sd %s,%s\n", nameIReg(4, eregOfRM(modrm)),
8634 nameXMMReg(gregOfRM(modrm)));
8635 } else {
8636 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
8637 assign( arg32, loadLE(Ity_I32, mkexpr(addr)) );
8638 delta += 3+alen;
8639 DIP("cvtsi2sd %s,%s\n", dis_buf,
8640 nameXMMReg(gregOfRM(modrm)) );
8641 }
8642
8643 putXMMRegLane64F(
8644 gregOfRM(modrm), 0,
8645 unop(Iop_I32toF64, mkexpr(arg32)) );
8646
8647 goto decode_success;
8648 }
8649
8650 /* F3 0F 5A = CVTSS2SD -- convert F32 in mem/low 1/4 xmm to F64 in
8651 low half xmm(G) */
8652 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5A) {
8653 IRTemp f32lo = newTemp(Ity_F32);
8654 vassert(sz == 4);
8655
8656 modrm = getIByte(delta+3);
8657 if (epartIsReg(modrm)) {
8658 delta += 3+1;
8659 assign(f32lo, getXMMRegLane32F(eregOfRM(modrm), 0));
8660 DIP("cvtss2sd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
8661 nameXMMReg(gregOfRM(modrm)));
8662 } else {
8663 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
8664 assign(f32lo, loadLE(Ity_F32, mkexpr(addr)));
8665 delta += 3+alen;
8666 DIP("cvtss2sd %s,%s\n", dis_buf,
8667 nameXMMReg(gregOfRM(modrm)));
8668 }
8669
8670 putXMMRegLane64F( gregOfRM(modrm), 0,
8671 unop( Iop_F32toF64, mkexpr(f32lo) ) );
8672
8673 goto decode_success;
8674 }
8675
8676 /* 66 0F E6 = CVTTPD2DQ -- convert 2 x F64 in mem/xmm to 2 x I32 in
8677 lo half xmm(G), and zero upper half, rounding towards zero */
8678 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE6) {
8679 IRTemp argV = newTemp(Ity_V128);
8680 IRTemp rmode = newTemp(Ity_I32);
8681
8682 modrm = getIByte(delta+2);
8683 if (epartIsReg(modrm)) {
8684 assign( argV, getXMMReg(eregOfRM(modrm)) );
8685 delta += 2+1;
8686 DIP("cvttpd2dq %s,%s\n", nameXMMReg(eregOfRM(modrm)),
8687 nameXMMReg(gregOfRM(modrm)));
8688 } else {
8689 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8690 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
8691 delta += 2+alen;
8692 DIP("cvttpd2dq %s,%s\n", dis_buf,
8693 nameXMMReg(gregOfRM(modrm)) );
8694 }
8695
8696 assign( rmode, mkU32((UInt)Irrm_ZERO) );
8697
8698 t0 = newTemp(Ity_F64);
8699 t1 = newTemp(Ity_F64);
8700 assign( t0, unop(Iop_ReinterpI64asF64,
sewardjf0c1c582005-02-07 23:47:38 +00008701 unop(Iop_V128to64, mkexpr(argV))) );
sewardjfd226452004-12-07 19:02:18 +00008702 assign( t1, unop(Iop_ReinterpI64asF64,
sewardjf0c1c582005-02-07 23:47:38 +00008703 unop(Iop_V128HIto64, mkexpr(argV))) );
sewardjfd226452004-12-07 19:02:18 +00008704
8705# define CVT(_t) binop( Iop_F64toI32, \
8706 mkexpr(rmode), \
8707 mkexpr(_t) )
8708
8709 putXMMRegLane32( gregOfRM(modrm), 3, mkU32(0) );
8710 putXMMRegLane32( gregOfRM(modrm), 2, mkU32(0) );
8711 putXMMRegLane32( gregOfRM(modrm), 1, CVT(t1) );
8712 putXMMRegLane32( gregOfRM(modrm), 0, CVT(t0) );
8713
8714# undef CVT
8715
8716 goto decode_success;
8717 }
8718
8719 /* F3 0F 5B = CVTTPS2DQ -- convert 4 x F32 in mem/xmm to 4 x I32 in
8720 xmm(G), rounding towards zero */
8721 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5B) {
8722 IRTemp argV = newTemp(Ity_V128);
8723 IRTemp rmode = newTemp(Ity_I32);
8724 vassert(sz == 4);
8725
8726 modrm = getIByte(delta+3);
8727 if (epartIsReg(modrm)) {
8728 assign( argV, getXMMReg(eregOfRM(modrm)) );
8729 delta += 3+1;
8730 DIP("cvttps2dq %s,%s\n", nameXMMReg(eregOfRM(modrm)),
8731 nameXMMReg(gregOfRM(modrm)));
8732 } else {
8733 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
8734 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
8735 delta += 3+alen;
8736 DIP("cvttps2dq %s,%s\n", dis_buf,
8737 nameXMMReg(gregOfRM(modrm)) );
8738 }
8739
8740 assign( rmode, mkU32((UInt)Irrm_ZERO) );
8741 breakup128to32s( argV, &t3, &t2, &t1, &t0 );
8742
8743 /* This is less than ideal. If it turns out to be a performance
8744 bottleneck it can be improved. */
8745# define CVT(_t) \
8746 binop( Iop_F64toI32, \
8747 mkexpr(rmode), \
8748 unop( Iop_F32toF64, \
8749 unop( Iop_ReinterpI32asF32, mkexpr(_t))) )
8750
8751 putXMMRegLane32( gregOfRM(modrm), 3, CVT(t3) );
8752 putXMMRegLane32( gregOfRM(modrm), 2, CVT(t2) );
8753 putXMMRegLane32( gregOfRM(modrm), 1, CVT(t1) );
8754 putXMMRegLane32( gregOfRM(modrm), 0, CVT(t0) );
8755
8756# undef CVT
8757
8758 goto decode_success;
8759 }
8760
8761 /* 66 0F 5E = DIVPD -- div 64Fx2 from R/M to R */
8762 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5E) {
8763 delta = dis_SSE_E_to_G_all( sorb, delta+2, "divpd", Iop_Div64Fx2 );
8764 goto decode_success;
8765 }
8766
sewardjc2feffc2004-12-08 12:31:22 +00008767 /* F2 0F 5E = DIVSD -- div 64F0x2 from R/M to R */
8768 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x5E) {
8769 vassert(sz == 4);
8770 delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "divsd", Iop_Div64F0x2 );
8771 goto decode_success;
8772 }
8773
8774 /* 0F AE /5 = LFENCE -- flush pending operations to memory */
8775 /* 0F AE /6 = MFENCE -- flush pending operations to memory */
8776 if (insn[0] == 0x0F && insn[1] == 0xAE
8777 && epartIsReg(insn[2])
8778 && (gregOfRM(insn[2]) == 5 || gregOfRM(insn[2]) == 6)) {
8779 vassert(sz == 4);
8780 delta += 3;
sewardj3e838932005-01-07 12:09:15 +00008781 /* Insert a memory fence. It's sometimes important that these
8782 are carried through to the generated code. */
8783 stmt( IRStmt_MFence() );
sewardjc2feffc2004-12-08 12:31:22 +00008784 DIP("%sfence\n", gregOfRM(insn[2])==5 ? "l" : "m");
8785 goto decode_success;
8786 }
8787
8788 /* 66 0F 5F = MAXPD -- max 64Fx2 from R/M to R */
8789 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5F) {
8790 delta = dis_SSE_E_to_G_all( sorb, delta+2, "maxpd", Iop_Max64Fx2 );
8791 goto decode_success;
8792 }
8793
8794 /* F2 0F 5F = MAXSD -- max 64F0x2 from R/M to R */
8795 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x5F) {
8796 vassert(sz == 4);
8797 delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "maxsd", Iop_Max64F0x2 );
8798 goto decode_success;
8799 }
8800
8801 /* 66 0F 5D = MINPD -- min 64Fx2 from R/M to R */
8802 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5D) {
8803 delta = dis_SSE_E_to_G_all( sorb, delta+2, "minpd", Iop_Min64Fx2 );
8804 goto decode_success;
8805 }
8806
8807 /* F2 0F 5D = MINSD -- min 64F0x2 from R/M to R */
8808 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x5D) {
8809 vassert(sz == 4);
8810 delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "minsd", Iop_Min64F0x2 );
8811 goto decode_success;
8812 }
8813
8814 /* 66 0F 28 = MOVAPD -- move from E (mem or xmm) to G (xmm). */
8815 /* 66 0F 10 = MOVUPD -- move from E (mem or xmm) to G (xmm). */
8816 /* 66 0F 6F = MOVDQA -- move from E (mem or xmm) to G (xmm). */
8817 if (sz == 2 && insn[0] == 0x0F
8818 && (insn[1] == 0x28 || insn[1] == 0x10 || insn[1] == 0x6F)) {
8819 HChar* wot = insn[1]==0x28 ? "apd" :
8820 insn[1]==0x10 ? "upd" : "dqa";
8821 modrm = getIByte(delta+2);
8822 if (epartIsReg(modrm)) {
8823 putXMMReg( gregOfRM(modrm),
8824 getXMMReg( eregOfRM(modrm) ));
8825 DIP("mov%s %s,%s\n", wot, nameXMMReg(eregOfRM(modrm)),
8826 nameXMMReg(gregOfRM(modrm)));
8827 delta += 2+1;
8828 } else {
8829 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8830 putXMMReg( gregOfRM(modrm),
8831 loadLE(Ity_V128, mkexpr(addr)) );
8832 DIP("mov%s %s,%s\n", wot, dis_buf,
8833 nameXMMReg(gregOfRM(modrm)));
8834 delta += 2+alen;
8835 }
8836 goto decode_success;
8837 }
8838
sewardj95535fe2004-12-15 17:42:58 +00008839 /* 66 0F 29 = MOVAPD -- move from G (xmm) to E (mem or xmm). */
sewardj1c318772005-03-19 14:27:04 +00008840 /* 66 0F 11 = MOVUPD -- move from G (xmm) to E (mem or xmm). */
8841 if (sz == 2 && insn[0] == 0x0F
8842 && (insn[1] == 0x29 || insn[1] == 0x11)) {
8843 HChar* wot = insn[1]==0x29 ? "apd" : "upd";
sewardj95535fe2004-12-15 17:42:58 +00008844 modrm = getIByte(delta+2);
8845 if (epartIsReg(modrm)) {
8846 /* fall through; awaiting test case */
8847 } else {
8848 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8849 storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) );
sewardj1c318772005-03-19 14:27:04 +00008850 DIP("mov%s %s,%s\n", wot, nameXMMReg(gregOfRM(modrm)),
8851 dis_buf );
sewardj95535fe2004-12-15 17:42:58 +00008852 delta += 2+alen;
8853 goto decode_success;
8854 }
8855 }
8856
sewardjc2feffc2004-12-08 12:31:22 +00008857 /* 66 0F 6E = MOVD from r/m32 to xmm, zeroing high 3/4 of xmm. */
8858 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x6E) {
8859 modrm = getIByte(delta+2);
8860 if (epartIsReg(modrm)) {
8861 delta += 2+1;
8862 putXMMReg(
8863 gregOfRM(modrm),
sewardjf0c1c582005-02-07 23:47:38 +00008864 unop( Iop_32UtoV128, getIReg(4, eregOfRM(modrm)) )
sewardjc2feffc2004-12-08 12:31:22 +00008865 );
8866 DIP("movd %s, %s\n",
8867 nameIReg(4,eregOfRM(modrm)), nameXMMReg(gregOfRM(modrm)));
8868 } else {
8869 addr = disAMode( &alen, sorb, delta+2, dis_buf );
8870 delta += 2+alen;
8871 putXMMReg(
8872 gregOfRM(modrm),
sewardjf0c1c582005-02-07 23:47:38 +00008873 unop( Iop_32UtoV128,loadLE(Ity_I32, mkexpr(addr)) )
sewardjc2feffc2004-12-08 12:31:22 +00008874 );
8875 DIP("movd %s, %s\n", dis_buf, nameXMMReg(gregOfRM(modrm)));
8876 }
8877 goto decode_success;
8878 }
8879
8880 /* 66 0F 7E = MOVD from xmm low 1/4 to r/m32. */
8881 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x7E) {
8882 modrm = getIByte(delta+2);
8883 if (epartIsReg(modrm)) {
8884 delta += 2+1;
8885 putIReg( 4, eregOfRM(modrm),
8886 getXMMRegLane32(gregOfRM(modrm), 0) );
8887 DIP("movd %s, %s\n",
8888 nameXMMReg(gregOfRM(modrm)), nameIReg(4,eregOfRM(modrm)));
8889 } else {
8890 addr = disAMode( &alen, sorb, delta+2, dis_buf );
8891 delta += 2+alen;
8892 storeLE( mkexpr(addr),
8893 getXMMRegLane32(gregOfRM(modrm), 0) );
8894 DIP("movd %s, %s\n", nameXMMReg(gregOfRM(modrm)), dis_buf);
8895 }
8896 goto decode_success;
8897 }
8898
8899 /* 66 0F 7F = MOVDQA -- move from G (xmm) to E (mem or xmm). */
8900 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x7F) {
8901 modrm = getIByte(delta+2);
8902 if (epartIsReg(modrm)) {
8903 delta += 2+1;
8904 putXMMReg( eregOfRM(modrm),
8905 getXMMReg(gregOfRM(modrm)) );
8906 DIP("movdqa %s, %s\n", nameXMMReg(gregOfRM(modrm)),
8907 nameXMMReg(eregOfRM(modrm)));
8908 } else {
8909 addr = disAMode( &alen, sorb, delta+2, dis_buf );
8910 delta += 2+alen;
8911 storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) );
8912 DIP("movdqa %s, %s\n", nameXMMReg(gregOfRM(modrm)), dis_buf);
8913 }
8914 goto decode_success;
8915 }
8916
8917 /* F3 0F 6F = MOVDQU -- move from E (mem or xmm) to G (xmm). */
8918 /* Unfortunately can't simply use the MOVDQA case since the
8919 prefix lengths are different (66 vs F3) */
8920 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x6F) {
8921 vassert(sz == 4);
8922 modrm = getIByte(delta+3);
8923 if (epartIsReg(modrm)) {
8924 putXMMReg( gregOfRM(modrm),
8925 getXMMReg( eregOfRM(modrm) ));
8926 DIP("movdqu %s,%s\n", nameXMMReg(eregOfRM(modrm)),
8927 nameXMMReg(gregOfRM(modrm)));
8928 delta += 3+1;
8929 } else {
8930 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
8931 putXMMReg( gregOfRM(modrm),
8932 loadLE(Ity_V128, mkexpr(addr)) );
8933 DIP("movdqu %s,%s\n", dis_buf,
8934 nameXMMReg(gregOfRM(modrm)));
8935 delta += 3+alen;
8936 }
8937 goto decode_success;
8938 }
8939
8940 /* F3 0F 7F = MOVDQU -- move from G (xmm) to E (mem or xmm). */
8941 /* Unfortunately can't simply use the MOVDQA case since the
8942 prefix lengths are different (66 vs F3) */
8943 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x7F) {
8944 vassert(sz == 4);
8945 modrm = getIByte(delta+3);
8946 if (epartIsReg(modrm)) {
8947 delta += 3+1;
8948 putXMMReg( eregOfRM(modrm),
8949 getXMMReg(gregOfRM(modrm)) );
8950 DIP("movdqu %s, %s\n", nameXMMReg(gregOfRM(modrm)),
8951 nameXMMReg(eregOfRM(modrm)));
8952 } else {
8953 addr = disAMode( &alen, sorb, delta+3, dis_buf );
8954 delta += 3+alen;
8955 storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) );
8956 DIP("movdqu %s, %s\n", nameXMMReg(gregOfRM(modrm)), dis_buf);
8957 }
8958 goto decode_success;
8959 }
8960
8961 /* F2 0F D6 = MOVDQ2Q -- move from E (lo half xmm, not mem) to G (mmx). */
8962 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0xD6) {
8963 vassert(sz == 4);
8964 modrm = getIByte(delta+3);
8965 if (epartIsReg(modrm)) {
8966 do_MMX_preamble();
8967 putMMXReg( gregOfRM(modrm),
8968 getXMMRegLane64( eregOfRM(modrm), 0 ));
8969 DIP("movdq2q %s,%s\n", nameXMMReg(eregOfRM(modrm)),
8970 nameMMXReg(gregOfRM(modrm)));
8971 delta += 3+1;
8972 goto decode_success;
8973 } else {
8974 /* fall through, apparently no mem case for this insn */
8975 }
8976 }
8977
8978 /* 66 0F 16 = MOVHPD -- move from mem to high half of XMM. */
8979 /* These seems identical to MOVHPS. This instruction encoding is
8980 completely crazy. */
8981 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x16) {
8982 modrm = getIByte(delta+2);
8983 if (epartIsReg(modrm)) {
8984 /* fall through; apparently reg-reg is not possible */
8985 } else {
8986 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8987 delta += 2+alen;
8988 putXMMRegLane64( gregOfRM(modrm), 1/*upper lane*/,
8989 loadLE(Ity_I64, mkexpr(addr)) );
8990 DIP("movhpd %s,%s\n", dis_buf,
8991 nameXMMReg( gregOfRM(modrm) ));
8992 goto decode_success;
8993 }
8994 }
8995
8996 /* 66 0F 17 = MOVHPD -- move from high half of XMM to mem. */
8997 /* Again, this seems identical to MOVHPS. */
8998 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x17) {
8999 if (!epartIsReg(insn[2])) {
9000 delta += 2;
9001 addr = disAMode ( &alen, sorb, delta, dis_buf );
9002 delta += alen;
9003 storeLE( mkexpr(addr),
9004 getXMMRegLane64( gregOfRM(insn[2]),
9005 1/*upper lane*/ ) );
9006 DIP("movhpd %s,%s\n", nameXMMReg( gregOfRM(insn[2]) ),
9007 dis_buf);
9008 goto decode_success;
9009 }
9010 /* else fall through */
9011 }
9012
9013 /* 66 0F 12 = MOVLPD -- move from mem to low half of XMM. */
9014 /* Identical to MOVLPS ? */
9015 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x12) {
9016 modrm = getIByte(delta+2);
9017 if (epartIsReg(modrm)) {
9018 /* fall through; apparently reg-reg is not possible */
9019 } else {
9020 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9021 delta += 2+alen;
9022 putXMMRegLane64( gregOfRM(modrm), 0/*lower lane*/,
9023 loadLE(Ity_I64, mkexpr(addr)) );
9024 DIP("movlpd %s, %s\n",
9025 dis_buf, nameXMMReg( gregOfRM(modrm) ));
9026 goto decode_success;
9027 }
9028 }
9029
9030 /* 66 0F 13 = MOVLPD -- move from low half of XMM to mem. */
9031 /* Identical to MOVLPS ? */
9032 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x13) {
9033 if (!epartIsReg(insn[2])) {
9034 delta += 2;
9035 addr = disAMode ( &alen, sorb, delta, dis_buf );
9036 delta += alen;
9037 storeLE( mkexpr(addr),
9038 getXMMRegLane64( gregOfRM(insn[2]),
9039 0/*lower lane*/ ) );
9040 DIP("movlpd %s, %s\n", nameXMMReg( gregOfRM(insn[2]) ),
9041 dis_buf);
9042 goto decode_success;
9043 }
9044 /* else fall through */
9045 }
9046
9047 /* 66 0F 50 = MOVMSKPD - move 2 sign bits from 2 x F64 in xmm(E) to
9048 2 lowest bits of ireg(G) */
9049 if (insn[0] == 0x0F && insn[1] == 0x50) {
9050 modrm = getIByte(delta+2);
9051 if (sz == 2 && epartIsReg(modrm)) {
9052 Int src;
9053 t0 = newTemp(Ity_I32);
9054 t1 = newTemp(Ity_I32);
9055 delta += 2+1;
9056 src = eregOfRM(modrm);
9057 assign( t0, binop( Iop_And32,
9058 binop(Iop_Shr32, getXMMRegLane32(src,1), mkU8(31)),
9059 mkU32(1) ));
9060 assign( t1, binop( Iop_And32,
9061 binop(Iop_Shr32, getXMMRegLane32(src,3), mkU8(30)),
9062 mkU32(2) ));
9063 putIReg(4, gregOfRM(modrm),
9064 binop(Iop_Or32, mkexpr(t0), mkexpr(t1))
9065 );
9066 DIP("movmskpd %s,%s\n", nameXMMReg(src),
9067 nameIReg(4, gregOfRM(modrm)));
9068 goto decode_success;
9069 }
9070 /* else fall through */
9071 }
9072
9073 /* 66 0F E7 = MOVNTDQ -- for us, just a plain SSE store. */
9074 if (insn[0] == 0x0F && insn[1] == 0xE7) {
9075 modrm = getIByte(delta+2);
9076 if (sz == 2 && !epartIsReg(modrm)) {
9077 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9078 storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) );
9079 DIP("movntdq %s,%s\n", dis_buf,
9080 nameXMMReg(gregOfRM(modrm)));
9081 delta += 2+alen;
9082 goto decode_success;
9083 }
9084 /* else fall through */
9085 }
9086
9087 /* 0F C3 = MOVNTI -- for us, just a plain ireg store. */
9088 if (insn[0] == 0x0F && insn[1] == 0xC3) {
9089 vassert(sz == 4);
9090 modrm = getIByte(delta+2);
9091 if (!epartIsReg(modrm)) {
9092 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9093 storeLE( mkexpr(addr), getIReg(4, gregOfRM(modrm)) );
9094 DIP("movnti %s,%s\n", dis_buf,
9095 nameIReg(4, gregOfRM(modrm)));
9096 delta += 2+alen;
9097 goto decode_success;
9098 }
9099 /* else fall through */
9100 }
9101
sewardj95535fe2004-12-15 17:42:58 +00009102 /* 66 0F D6 = MOVQ -- move 64 bits from G (lo half xmm) to E (mem
9103 or lo half xmm). */
sewardj9ee82862004-12-14 01:16:59 +00009104 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD6) {
9105 modrm = getIByte(delta+2);
9106 if (epartIsReg(modrm)) {
9107 /* fall through, awaiting test case */
sewardj6d7ccd52005-05-14 02:04:12 +00009108 /* dst: lo half copied, hi half zeroed */
sewardj9ee82862004-12-14 01:16:59 +00009109 } else {
9110 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9111 storeLE( mkexpr(addr),
9112 getXMMRegLane64( gregOfRM(modrm), 0 ));
9113 DIP("movq %s,%s\n", nameXMMReg(gregOfRM(modrm)), dis_buf );
9114 delta += 2+alen;
9115 goto decode_success;
9116 }
9117 }
9118
sewardjc2feffc2004-12-08 12:31:22 +00009119 /* F3 0F D6 = MOVQ2DQ -- move from E (mmx) to G (lo half xmm, zero
9120 hi half). */
9121 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0xD6) {
9122 vassert(sz == 4);
9123 modrm = getIByte(delta+3);
9124 if (epartIsReg(modrm)) {
9125 do_MMX_preamble();
9126 putXMMReg( gregOfRM(modrm),
sewardjf0c1c582005-02-07 23:47:38 +00009127 unop(Iop_64UtoV128, getMMXReg( eregOfRM(modrm) )) );
sewardjc2feffc2004-12-08 12:31:22 +00009128 DIP("movq2dq %s,%s\n", nameMMXReg(eregOfRM(modrm)),
9129 nameXMMReg(gregOfRM(modrm)));
9130 delta += 3+1;
9131 goto decode_success;
9132 } else {
9133 /* fall through, apparently no mem case for this insn */
9134 }
9135 }
9136
sewardj95535fe2004-12-15 17:42:58 +00009137 /* F3 0F 7E = MOVQ -- move 64 bits from E (mem or lo half xmm) to
sewardj6d7ccd52005-05-14 02:04:12 +00009138 G (lo half xmm). Upper half of G is zeroed out. */
sewardj95535fe2004-12-15 17:42:58 +00009139 /* F2 0F 10 = MOVSD -- move 64 bits from E (mem or lo half xmm) to
9140 G (lo half xmm). If E is mem, upper half of G is zeroed out.
sewardj6d7ccd52005-05-14 02:04:12 +00009141 If E is reg, upper half of G is unchanged. */
sewardj95535fe2004-12-15 17:42:58 +00009142 if ((insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x10)
9143 || (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x7E)) {
sewardjc2feffc2004-12-08 12:31:22 +00009144 vassert(sz == 4);
9145 modrm = getIByte(delta+3);
9146 if (epartIsReg(modrm)) {
9147 putXMMRegLane64( gregOfRM(modrm), 0,
9148 getXMMRegLane64( eregOfRM(modrm), 0 ));
sewardj6d7ccd52005-05-14 02:04:12 +00009149 if (insn[0] == 0xF3/*MOVQ*/) {
9150 /* zero bits 127:64 */
9151 putXMMRegLane64( gregOfRM(modrm), 1, mkU64(0) );
9152 }
sewardjc2feffc2004-12-08 12:31:22 +00009153 DIP("movsd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9154 nameXMMReg(gregOfRM(modrm)));
9155 delta += 3+1;
9156 } else {
9157 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
sewardjad50db02005-04-06 01:45:44 +00009158 /* zero bits 127:64 */
sewardj5bf1fd42005-04-06 01:11:08 +00009159 putXMMRegLane64( gregOfRM(modrm), 1, mkU64(0) );
sewardjad50db02005-04-06 01:45:44 +00009160 /* write bits 63:0 */
sewardjc2feffc2004-12-08 12:31:22 +00009161 putXMMRegLane64( gregOfRM(modrm), 0,
9162 loadLE(Ity_I64, mkexpr(addr)) );
9163 DIP("movsd %s,%s\n", dis_buf,
9164 nameXMMReg(gregOfRM(modrm)));
9165 delta += 3+alen;
9166 }
9167 goto decode_success;
9168 }
9169
9170 /* F2 0F 11 = MOVSD -- move 64 bits from G (lo half xmm) to E (mem
9171 or lo half xmm). */
9172 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x11) {
9173 vassert(sz == 4);
9174 modrm = getIByte(delta+3);
9175 if (epartIsReg(modrm)) {
9176 /* fall through, we don't yet have a test case */
9177 } else {
9178 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
9179 storeLE( mkexpr(addr),
sewardj519d66f2004-12-15 11:57:58 +00009180 getXMMRegLane64(gregOfRM(modrm), 0) );
9181 DIP("movsd %s,%s\n", nameXMMReg(gregOfRM(modrm)),
sewardjc2feffc2004-12-08 12:31:22 +00009182 dis_buf);
9183 delta += 3+alen;
9184 goto decode_success;
9185 }
9186 }
sewardjfd226452004-12-07 19:02:18 +00009187
sewardj008754b2004-12-08 14:37:10 +00009188 /* 66 0F 59 = MULPD -- mul 64Fx2 from R/M to R */
9189 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x59) {
9190 delta = dis_SSE_E_to_G_all( sorb, delta+2, "mulpd", Iop_Mul64Fx2 );
9191 goto decode_success;
9192 }
9193
9194 /* F2 0F 59 = MULSD -- mul 64F0x2 from R/M to R */
9195 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x59) {
9196 vassert(sz == 4);
9197 delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "mulsd", Iop_Mul64F0x2 );
9198 goto decode_success;
9199 }
9200
9201 /* 66 0F 56 = ORPD -- G = G and E */
9202 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x56) {
sewardjf0c1c582005-02-07 23:47:38 +00009203 delta = dis_SSE_E_to_G_all( sorb, delta+2, "orpd", Iop_OrV128 );
sewardj008754b2004-12-08 14:37:10 +00009204 goto decode_success;
9205 }
9206
9207 /* 66 0F C6 /r ib = SHUFPD -- shuffle packed F64s */
9208 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xC6) {
9209 Int select;
9210 IRTemp sV = newTemp(Ity_V128);
9211 IRTemp dV = newTemp(Ity_V128);
9212 IRTemp s1 = newTemp(Ity_I64);
9213 IRTemp s0 = newTemp(Ity_I64);
9214 IRTemp d1 = newTemp(Ity_I64);
9215 IRTemp d0 = newTemp(Ity_I64);
9216
9217 modrm = insn[2];
9218 assign( dV, getXMMReg(gregOfRM(modrm)) );
9219
9220 if (epartIsReg(modrm)) {
9221 assign( sV, getXMMReg(eregOfRM(modrm)) );
9222 select = (Int)insn[3];
9223 delta += 2+2;
9224 DIP("shufpd $%d,%s,%s\n", select,
9225 nameXMMReg(eregOfRM(modrm)),
9226 nameXMMReg(gregOfRM(modrm)));
9227 } else {
9228 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9229 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
9230 select = (Int)insn[2+alen];
9231 delta += 3+alen;
9232 DIP("shufpd $%d,%s,%s\n", select,
9233 dis_buf,
9234 nameXMMReg(gregOfRM(modrm)));
9235 }
9236
sewardjf0c1c582005-02-07 23:47:38 +00009237 assign( d1, unop(Iop_V128HIto64, mkexpr(dV)) );
9238 assign( d0, unop(Iop_V128to64, mkexpr(dV)) );
9239 assign( s1, unop(Iop_V128HIto64, mkexpr(sV)) );
9240 assign( s0, unop(Iop_V128to64, mkexpr(sV)) );
sewardj008754b2004-12-08 14:37:10 +00009241
9242# define SELD(n) mkexpr((n)==0 ? d0 : d1)
9243# define SELS(n) mkexpr((n)==0 ? s0 : s1)
9244
9245 putXMMReg(
9246 gregOfRM(modrm),
sewardjf0c1c582005-02-07 23:47:38 +00009247 binop(Iop_64HLtoV128, SELS((select>>1)&1), SELD((select>>0)&1) )
sewardj008754b2004-12-08 14:37:10 +00009248 );
9249
9250# undef SELD
9251# undef SELS
9252
9253 goto decode_success;
9254 }
9255
9256 /* 66 0F 51 = SQRTPD -- approx sqrt 64Fx2 from R/M to R */
9257 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x51) {
9258 delta = dis_SSE_E_to_G_unary_all( sorb, delta+2,
9259 "sqrtpd", Iop_Sqrt64Fx2 );
9260 goto decode_success;
9261 }
9262
9263 /* F2 0F 51 = SQRTSD -- approx sqrt 64F0x2 from R/M to R */
9264 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x51) {
9265 vassert(sz == 4);
9266 delta = dis_SSE_E_to_G_unary_lo64( sorb, delta+3,
9267 "sqrtsd", Iop_Sqrt64F0x2 );
9268 goto decode_success;
9269 }
9270
9271 /* 66 0F 5C = SUBPD -- sub 64Fx2 from R/M to R */
9272 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5C) {
9273 delta = dis_SSE_E_to_G_all( sorb, delta+2, "subpd", Iop_Sub64Fx2 );
9274 goto decode_success;
9275 }
9276
9277 /* F2 0F 5C = SUBSD -- sub 64F0x2 from R/M to R */
9278 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x5C) {
9279 vassert(sz == 4);
9280 delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "subsd", Iop_Sub64F0x2 );
9281 goto decode_success;
9282 }
9283
9284 /* 66 0F 15 = UNPCKHPD -- unpack and interleave high part F64s */
9285 /* 66 0F 14 = UNPCKLPD -- unpack and interleave low part F64s */
9286 /* These just appear to be special cases of SHUFPS */
9287 if (sz == 2 && insn[0] == 0x0F && (insn[1] == 0x15 || insn[1] == 0x14)) {
9288 IRTemp s1 = newTemp(Ity_I64);
9289 IRTemp s0 = newTemp(Ity_I64);
9290 IRTemp d1 = newTemp(Ity_I64);
9291 IRTemp d0 = newTemp(Ity_I64);
9292 IRTemp sV = newTemp(Ity_V128);
9293 IRTemp dV = newTemp(Ity_V128);
sewardj2d49b432005-02-01 00:37:06 +00009294 Bool hi = toBool(insn[1] == 0x15);
sewardj008754b2004-12-08 14:37:10 +00009295
9296 modrm = insn[2];
9297 assign( dV, getXMMReg(gregOfRM(modrm)) );
9298
9299 if (epartIsReg(modrm)) {
9300 assign( sV, getXMMReg(eregOfRM(modrm)) );
9301 delta += 2+1;
9302 DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
9303 nameXMMReg(eregOfRM(modrm)),
9304 nameXMMReg(gregOfRM(modrm)));
9305 } else {
9306 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9307 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
9308 delta += 2+alen;
9309 DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
9310 dis_buf,
9311 nameXMMReg(gregOfRM(modrm)));
9312 }
9313
sewardjf0c1c582005-02-07 23:47:38 +00009314 assign( d1, unop(Iop_V128HIto64, mkexpr(dV)) );
9315 assign( d0, unop(Iop_V128to64, mkexpr(dV)) );
9316 assign( s1, unop(Iop_V128HIto64, mkexpr(sV)) );
9317 assign( s0, unop(Iop_V128to64, mkexpr(sV)) );
sewardj008754b2004-12-08 14:37:10 +00009318
9319 if (hi) {
9320 putXMMReg( gregOfRM(modrm),
sewardjf0c1c582005-02-07 23:47:38 +00009321 binop(Iop_64HLtoV128, mkexpr(s1), mkexpr(d1)) );
sewardj008754b2004-12-08 14:37:10 +00009322 } else {
9323 putXMMReg( gregOfRM(modrm),
sewardjf0c1c582005-02-07 23:47:38 +00009324 binop(Iop_64HLtoV128, mkexpr(s0), mkexpr(d0)) );
sewardj008754b2004-12-08 14:37:10 +00009325 }
9326
9327 goto decode_success;
9328 }
9329
9330 /* 66 0F 57 = XORPD -- G = G and E */
9331 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x57) {
sewardjf0c1c582005-02-07 23:47:38 +00009332 delta = dis_SSE_E_to_G_all( sorb, delta+2, "xorpd", Iop_XorV128 );
sewardj008754b2004-12-08 14:37:10 +00009333 goto decode_success;
9334 }
sewardj636ad762004-12-07 11:16:04 +00009335
sewardj164f9272004-12-09 00:39:32 +00009336 /* 66 0F 6B = PACKSSDW */
9337 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x6B) {
9338 delta = dis_SSEint_E_to_G( sorb, delta+2,
9339 "packssdw", Iop_QNarrow32Sx4, True );
9340 goto decode_success;
9341 }
9342
9343 /* 66 0F 63 = PACKSSWB */
9344 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x63) {
9345 delta = dis_SSEint_E_to_G( sorb, delta+2,
9346 "packsswb", Iop_QNarrow16Sx8, True );
9347 goto decode_success;
9348 }
9349
9350 /* 66 0F 67 = PACKUSWB */
9351 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x67) {
9352 delta = dis_SSEint_E_to_G( sorb, delta+2,
9353 "packuswb", Iop_QNarrow16Ux8, True );
9354 goto decode_success;
9355 }
9356
9357 /* 66 0F FC = PADDB */
9358 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xFC) {
9359 delta = dis_SSEint_E_to_G( sorb, delta+2,
9360 "paddb", Iop_Add8x16, False );
9361 goto decode_success;
9362 }
9363
9364 /* 66 0F FE = PADDD */
9365 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xFE) {
9366 delta = dis_SSEint_E_to_G( sorb, delta+2,
9367 "paddd", Iop_Add32x4, False );
9368 goto decode_success;
9369 }
9370
9371 /* ***--- this is an MMX class insn introduced in SSE2 ---*** */
9372 /* 0F D4 = PADDQ -- add 64x1 */
9373 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xD4) {
9374 do_MMX_preamble();
9375 delta = dis_MMXop_regmem_to_reg (
9376 sorb, delta+2, insn[1], "paddq", False );
9377 goto decode_success;
9378 }
9379
9380 /* 66 0F D4 = PADDQ */
9381 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD4) {
9382 delta = dis_SSEint_E_to_G( sorb, delta+2,
9383 "paddq", Iop_Add64x2, False );
9384 goto decode_success;
9385 }
9386
9387 /* 66 0F FD = PADDW */
9388 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xFD) {
9389 delta = dis_SSEint_E_to_G( sorb, delta+2,
9390 "paddw", Iop_Add16x8, False );
9391 goto decode_success;
9392 }
9393
9394 /* 66 0F EC = PADDSB */
9395 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xEC) {
9396 delta = dis_SSEint_E_to_G( sorb, delta+2,
9397 "paddsb", Iop_QAdd8Sx16, False );
9398 goto decode_success;
9399 }
9400
9401 /* 66 0F ED = PADDSW */
9402 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xED) {
9403 delta = dis_SSEint_E_to_G( sorb, delta+2,
9404 "paddsw", Iop_QAdd16Sx8, False );
9405 goto decode_success;
9406 }
9407
9408 /* 66 0F DC = PADDUSB */
9409 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDC) {
9410 delta = dis_SSEint_E_to_G( sorb, delta+2,
9411 "paddusb", Iop_QAdd8Ux16, False );
9412 goto decode_success;
9413 }
9414
9415 /* 66 0F DD = PADDUSW */
9416 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDD) {
9417 delta = dis_SSEint_E_to_G( sorb, delta+2,
9418 "paddusw", Iop_QAdd16Ux8, False );
9419 goto decode_success;
9420 }
9421
9422 /* 66 0F DB = PAND */
9423 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDB) {
sewardjf0c1c582005-02-07 23:47:38 +00009424 delta = dis_SSE_E_to_G_all( sorb, delta+2, "pand", Iop_AndV128 );
sewardj164f9272004-12-09 00:39:32 +00009425 goto decode_success;
9426 }
9427
9428 /* 66 0F DF = PANDN */
9429 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDF) {
sewardjf0c1c582005-02-07 23:47:38 +00009430 delta = dis_SSE_E_to_G_all_invG( sorb, delta+2, "pandn", Iop_AndV128 );
sewardj164f9272004-12-09 00:39:32 +00009431 goto decode_success;
9432 }
9433
9434 /* 66 0F E0 = PAVGB */
9435 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE0) {
9436 delta = dis_SSEint_E_to_G( sorb, delta+2,
9437 "pavgb", Iop_Avg8Ux16, False );
9438 goto decode_success;
9439 }
9440
9441 /* 66 0F E3 = PAVGW */
9442 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE3) {
9443 delta = dis_SSEint_E_to_G( sorb, delta+2,
9444 "pavgw", Iop_Avg16Ux8, False );
9445 goto decode_success;
9446 }
9447
sewardje5854d62004-12-09 03:44:34 +00009448 /* 66 0F 74 = PCMPEQB */
9449 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x74) {
9450 delta = dis_SSEint_E_to_G( sorb, delta+2,
9451 "pcmpeqb", Iop_CmpEQ8x16, False );
9452 goto decode_success;
9453 }
9454
9455 /* 66 0F 76 = PCMPEQD */
9456 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x76) {
9457 delta = dis_SSEint_E_to_G( sorb, delta+2,
9458 "pcmpeqd", Iop_CmpEQ32x4, False );
9459 goto decode_success;
9460 }
9461
9462 /* 66 0F 75 = PCMPEQW */
9463 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x75) {
9464 delta = dis_SSEint_E_to_G( sorb, delta+2,
9465 "pcmpeqw", Iop_CmpEQ16x8, False );
9466 goto decode_success;
9467 }
9468
9469 /* 66 0F 64 = PCMPGTB */
9470 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x64) {
9471 delta = dis_SSEint_E_to_G( sorb, delta+2,
9472 "pcmpgtb", Iop_CmpGT8Sx16, False );
9473 goto decode_success;
9474 }
9475
9476 /* 66 0F 66 = PCMPGTD */
9477 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x66) {
9478 delta = dis_SSEint_E_to_G( sorb, delta+2,
9479 "pcmpgtd", Iop_CmpGT32Sx4, False );
9480 goto decode_success;
9481 }
9482
9483 /* 66 0F 65 = PCMPGTW */
9484 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x65) {
9485 delta = dis_SSEint_E_to_G( sorb, delta+2,
9486 "pcmpgtw", Iop_CmpGT16Sx8, False );
9487 goto decode_success;
9488 }
9489
9490 /* 66 0F C5 = PEXTRW -- extract 16-bit field from xmm(E) and put
9491 zero-extend of it in ireg(G). */
9492 if (insn[0] == 0x0F && insn[1] == 0xC5) {
9493 modrm = insn[2];
9494 if (sz == 2 && epartIsReg(modrm)) {
9495 t5 = newTemp(Ity_V128);
9496 t4 = newTemp(Ity_I16);
9497 assign(t5, getXMMReg(eregOfRM(modrm)));
9498 breakup128to32s( t5, &t3, &t2, &t1, &t0 );
9499 switch (insn[3] & 7) {
9500 case 0: assign(t4, unop(Iop_32to16, mkexpr(t0))); break;
9501 case 1: assign(t4, unop(Iop_32HIto16, mkexpr(t0))); break;
9502 case 2: assign(t4, unop(Iop_32to16, mkexpr(t1))); break;
9503 case 3: assign(t4, unop(Iop_32HIto16, mkexpr(t1))); break;
9504 case 4: assign(t4, unop(Iop_32to16, mkexpr(t2))); break;
9505 case 5: assign(t4, unop(Iop_32HIto16, mkexpr(t2))); break;
9506 case 6: assign(t4, unop(Iop_32to16, mkexpr(t3))); break;
9507 case 7: assign(t4, unop(Iop_32HIto16, mkexpr(t3))); break;
sewardjba89f4c2005-04-07 17:31:27 +00009508 default: vassert(0); /*NOTREACHED*/
sewardje5854d62004-12-09 03:44:34 +00009509 }
9510 putIReg(4, gregOfRM(modrm), unop(Iop_16Uto32, mkexpr(t4)));
9511 DIP("pextrw $%d,%s,%s\n",
9512 (Int)insn[3], nameXMMReg(eregOfRM(modrm)),
9513 nameIReg(4,gregOfRM(modrm)));
9514 delta += 4;
9515 goto decode_success;
9516 }
9517 /* else fall through */
9518 }
9519
9520 /* 66 0F C4 = PINSRW -- get 16 bits from E(mem or low half ireg) and
9521 put it into the specified lane of xmm(G). */
9522 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xC4) {
9523 Int lane;
9524 t4 = newTemp(Ity_I16);
9525 modrm = insn[2];
9526
9527 if (epartIsReg(modrm)) {
9528 assign(t4, getIReg(2, eregOfRM(modrm)));
sewardjaac7e082005-03-17 14:03:46 +00009529 delta += 3+1;
9530 lane = insn[3+1-1];
sewardje5854d62004-12-09 03:44:34 +00009531 DIP("pinsrw $%d,%s,%s\n", (Int)lane,
9532 nameIReg(2,eregOfRM(modrm)),
9533 nameXMMReg(gregOfRM(modrm)));
9534 } else {
sewardjaac7e082005-03-17 14:03:46 +00009535 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9536 delta += 3+alen;
9537 lane = insn[3+alen-1];
9538 assign(t4, loadLE(Ity_I16, mkexpr(addr)));
9539 DIP("pinsrw $%d,%s,%s\n", (Int)lane,
9540 dis_buf,
9541 nameXMMReg(gregOfRM(modrm)));
sewardje5854d62004-12-09 03:44:34 +00009542 }
9543
9544 putXMMRegLane16( gregOfRM(modrm), lane & 7, mkexpr(t4) );
9545 goto decode_success;
9546 }
9547
9548 /* 66 0F EE = PMAXSW -- 16x8 signed max */
9549 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xEE) {
9550 delta = dis_SSEint_E_to_G( sorb, delta+2,
9551 "pmaxsw", Iop_Max16Sx8, False );
9552 goto decode_success;
9553 }
9554
9555 /* 66 0F DE = PMAXUB -- 8x16 unsigned max */
9556 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDE) {
9557 delta = dis_SSEint_E_to_G( sorb, delta+2,
9558 "pmaxub", Iop_Max8Ux16, False );
9559 goto decode_success;
9560 }
9561
9562 /* 66 0F EA = PMINSW -- 16x8 signed min */
9563 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xEA) {
9564 delta = dis_SSEint_E_to_G( sorb, delta+2,
9565 "pminsw", Iop_Min16Sx8, False );
9566 goto decode_success;
9567 }
9568
9569 /* 66 0F DA = PMINUB -- 8x16 unsigned min */
9570 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDA) {
9571 delta = dis_SSEint_E_to_G( sorb, delta+2,
9572 "pminub", Iop_Min8Ux16, False );
9573 goto decode_success;
9574 }
9575
9576 /* 66 0F D7 = PMOVMSKB -- extract sign bits from each of 16 lanes in
9577 xmm(G), turn them into a byte, and put zero-extend of it in
9578 ireg(G). Doing this directly is just too cumbersome; give up
9579 therefore and call a helper. */
9580 /* UInt x86g_calculate_sse_pmovmskb ( ULong w64hi, ULong w64lo ); */
9581 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD7) {
9582 modrm = insn[2];
9583 if (epartIsReg(modrm)) {
9584 t0 = newTemp(Ity_I64);
9585 t1 = newTemp(Ity_I64);
9586 assign(t0, getXMMRegLane64(eregOfRM(modrm), 0));
9587 assign(t1, getXMMRegLane64(eregOfRM(modrm), 1));
9588 t5 = newTemp(Ity_I32);
9589 assign(t5, mkIRExprCCall(
9590 Ity_I32, 0/*regparms*/,
9591 "x86g_calculate_sse_pmovmskb",
9592 &x86g_calculate_sse_pmovmskb,
sewardj28e5c832004-12-16 11:39:04 +00009593 mkIRExprVec_2( mkexpr(t1), mkexpr(t0) )));
sewardje5854d62004-12-09 03:44:34 +00009594 putIReg(4, gregOfRM(modrm), mkexpr(t5));
9595 DIP("pmovmskb %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9596 nameIReg(4,gregOfRM(modrm)));
9597 delta += 3;
9598 goto decode_success;
9599 }
9600 /* else fall through */
9601 }
9602
9603 /* 66 0F E4 = PMULHUW -- 16x8 hi-half of unsigned widening multiply */
9604 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE4) {
9605 delta = dis_SSEint_E_to_G( sorb, delta+2,
9606 "pmulhuw", Iop_MulHi16Ux8, False );
9607 goto decode_success;
9608 }
9609
9610 /* 66 0F E5 = PMULHW -- 16x8 hi-half of signed widening multiply */
9611 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE5) {
9612 delta = dis_SSEint_E_to_G( sorb, delta+2,
9613 "pmulhw", Iop_MulHi16Sx8, False );
9614 goto decode_success;
9615 }
9616
9617 /* 66 0F D5 = PMULHL -- 16x8 multiply */
9618 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD5) {
9619 delta = dis_SSEint_E_to_G( sorb, delta+2,
9620 "pmullw", Iop_Mul16x8, False );
9621 goto decode_success;
9622 }
9623
9624 /* ***--- this is an MMX class insn introduced in SSE2 ---*** */
9625 /* 0F F4 = PMULUDQ -- unsigned widening multiply of 32-lanes 0 x
9626 0 to form 64-bit result */
9627 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xF4) {
9628 IRTemp sV = newTemp(Ity_I64);
9629 IRTemp dV = newTemp(Ity_I64);
9630 t1 = newTemp(Ity_I32);
9631 t0 = newTemp(Ity_I32);
9632 modrm = insn[2];
9633
9634 do_MMX_preamble();
9635 assign( dV, getMMXReg(gregOfRM(modrm)) );
9636
9637 if (epartIsReg(modrm)) {
9638 assign( sV, getMMXReg(eregOfRM(modrm)) );
9639 delta += 2+1;
9640 DIP("pmuludq %s,%s\n", nameMMXReg(eregOfRM(modrm)),
9641 nameMMXReg(gregOfRM(modrm)));
9642 } else {
9643 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9644 assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
9645 delta += 2+alen;
9646 DIP("pmuludq %s,%s\n", dis_buf,
9647 nameMMXReg(gregOfRM(modrm)));
9648 }
9649
9650 assign( t0, unop(Iop_64to32, mkexpr(dV)) );
9651 assign( t1, unop(Iop_64to32, mkexpr(sV)) );
9652 putMMXReg( gregOfRM(modrm),
9653 binop( Iop_MullU32, mkexpr(t0), mkexpr(t1) ) );
9654 goto decode_success;
9655 }
9656
9657 /* 66 0F F4 = PMULUDQ -- unsigned widening multiply of 32-lanes 0 x
9658 0 to form lower 64-bit half and lanes 2 x 2 to form upper 64-bit
9659 half */
9660 /* This is a really poor translation -- could be improved if
9661 performance critical */
9662 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF4) {
9663 IRTemp sV, dV;
9664 IRTemp s3, s2, s1, s0, d3, d2, d1, d0;
9665 sV = newTemp(Ity_V128);
9666 dV = newTemp(Ity_V128);
9667 s3 = s2 = s1 = s0 = d3 = d2 = d1 = d0 = IRTemp_INVALID;
9668 t1 = newTemp(Ity_I64);
9669 t0 = newTemp(Ity_I64);
9670 modrm = insn[2];
9671 assign( dV, getXMMReg(gregOfRM(modrm)) );
9672
9673 if (epartIsReg(modrm)) {
9674 assign( sV, getXMMReg(eregOfRM(modrm)) );
9675 delta += 2+1;
9676 DIP("pmuludq %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9677 nameXMMReg(gregOfRM(modrm)));
9678 } else {
9679 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9680 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
9681 delta += 2+alen;
9682 DIP("pmuludq %s,%s\n", dis_buf,
9683 nameXMMReg(gregOfRM(modrm)));
9684 }
9685
9686 breakup128to32s( dV, &d3, &d2, &d1, &d0 );
9687 breakup128to32s( sV, &s3, &s2, &s1, &s0 );
9688
9689 assign( t0, binop( Iop_MullU32, mkexpr(d0), mkexpr(s0)) );
9690 putXMMRegLane64( gregOfRM(modrm), 0, mkexpr(t0) );
9691 assign( t1, binop( Iop_MullU32, mkexpr(d2), mkexpr(s2)) );
9692 putXMMRegLane64( gregOfRM(modrm), 1, mkexpr(t1) );
9693 goto decode_success;
9694 }
9695
9696 /* 66 0F EB = POR */
9697 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xEB) {
sewardjf0c1c582005-02-07 23:47:38 +00009698 delta = dis_SSE_E_to_G_all( sorb, delta+2, "por", Iop_OrV128 );
sewardje5854d62004-12-09 03:44:34 +00009699 goto decode_success;
9700 }
9701
sewardjb9fa69b2004-12-09 23:25:14 +00009702 /* 66 0F 70 = PSHUFD -- rearrange 4x32 from E(xmm or mem) to G(xmm) */
9703 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x70) {
9704 Int order;
9705 IRTemp sV, dV, s3, s2, s1, s0;
9706 s3 = s2 = s1 = s0 = IRTemp_INVALID;
9707 sV = newTemp(Ity_V128);
9708 dV = newTemp(Ity_V128);
9709 modrm = insn[2];
9710 if (epartIsReg(modrm)) {
9711 assign( sV, getXMMReg(eregOfRM(modrm)) );
9712 order = (Int)insn[3];
9713 delta += 2+2;
9714 DIP("pshufd $%d,%s,%s\n", order,
9715 nameXMMReg(eregOfRM(modrm)),
9716 nameXMMReg(gregOfRM(modrm)));
9717 } else {
9718 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9719 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
9720 order = (Int)insn[2+alen];
9721 delta += 3+alen;
9722 DIP("pshufd $%d,%s,%s\n", order,
9723 dis_buf,
9724 nameXMMReg(gregOfRM(modrm)));
9725 }
9726 breakup128to32s( sV, &s3, &s2, &s1, &s0 );
9727
9728# define SEL(n) \
9729 ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
9730 assign(dV,
9731 mk128from32s( SEL((order>>6)&3), SEL((order>>4)&3),
9732 SEL((order>>2)&3), SEL((order>>0)&3) )
9733 );
9734 putXMMReg(gregOfRM(modrm), mkexpr(dV));
9735# undef SEL
9736 goto decode_success;
9737 }
9738
9739 /* F3 0F 70 = PSHUFHW -- rearrange upper half 4x16 from E(xmm or
9740 mem) to G(xmm), and copy lower half */
9741 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x70) {
9742 Int order;
9743 IRTemp sVhi, dVhi, sV, dV, s3, s2, s1, s0;
9744 s3 = s2 = s1 = s0 = IRTemp_INVALID;
9745 sV = newTemp(Ity_V128);
9746 dV = newTemp(Ity_V128);
9747 sVhi = newTemp(Ity_I64);
9748 dVhi = newTemp(Ity_I64);
9749 modrm = insn[3];
9750 if (epartIsReg(modrm)) {
9751 assign( sV, getXMMReg(eregOfRM(modrm)) );
9752 order = (Int)insn[4];
9753 delta += 4+1;
9754 DIP("pshufhw $%d,%s,%s\n", order,
9755 nameXMMReg(eregOfRM(modrm)),
9756 nameXMMReg(gregOfRM(modrm)));
9757 } else {
9758 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
9759 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
9760 order = (Int)insn[3+alen];
9761 delta += 4+alen;
9762 DIP("pshufhw $%d,%s,%s\n", order,
9763 dis_buf,
9764 nameXMMReg(gregOfRM(modrm)));
9765 }
sewardjf0c1c582005-02-07 23:47:38 +00009766 assign( sVhi, unop(Iop_V128HIto64, mkexpr(sV)) );
sewardjb9fa69b2004-12-09 23:25:14 +00009767 breakup64to16s( sVhi, &s3, &s2, &s1, &s0 );
9768
9769# define SEL(n) \
9770 ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
9771 assign(dVhi,
9772 mk64from16s( SEL((order>>6)&3), SEL((order>>4)&3),
9773 SEL((order>>2)&3), SEL((order>>0)&3) )
9774 );
sewardjf0c1c582005-02-07 23:47:38 +00009775 assign(dV, binop( Iop_64HLtoV128,
sewardjb9fa69b2004-12-09 23:25:14 +00009776 mkexpr(dVhi),
sewardjf0c1c582005-02-07 23:47:38 +00009777 unop(Iop_V128to64, mkexpr(sV))) );
sewardjb9fa69b2004-12-09 23:25:14 +00009778 putXMMReg(gregOfRM(modrm), mkexpr(dV));
9779# undef SEL
9780 goto decode_success;
9781 }
9782
9783 /* F2 0F 70 = PSHUFLW -- rearrange lower half 4x16 from E(xmm or
9784 mem) to G(xmm), and copy upper half */
9785 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x70) {
9786 Int order;
9787 IRTemp sVlo, dVlo, sV, dV, s3, s2, s1, s0;
9788 s3 = s2 = s1 = s0 = IRTemp_INVALID;
9789 sV = newTemp(Ity_V128);
9790 dV = newTemp(Ity_V128);
9791 sVlo = newTemp(Ity_I64);
9792 dVlo = newTemp(Ity_I64);
9793 modrm = insn[3];
9794 if (epartIsReg(modrm)) {
9795 assign( sV, getXMMReg(eregOfRM(modrm)) );
9796 order = (Int)insn[4];
9797 delta += 4+1;
9798 DIP("pshuflw $%d,%s,%s\n", order,
9799 nameXMMReg(eregOfRM(modrm)),
9800 nameXMMReg(gregOfRM(modrm)));
9801 } else {
9802 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
9803 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
9804 order = (Int)insn[3+alen];
9805 delta += 4+alen;
9806 DIP("pshuflw $%d,%s,%s\n", order,
9807 dis_buf,
9808 nameXMMReg(gregOfRM(modrm)));
9809 }
sewardjf0c1c582005-02-07 23:47:38 +00009810 assign( sVlo, unop(Iop_V128to64, mkexpr(sV)) );
sewardjb9fa69b2004-12-09 23:25:14 +00009811 breakup64to16s( sVlo, &s3, &s2, &s1, &s0 );
9812
9813# define SEL(n) \
9814 ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
9815 assign(dVlo,
9816 mk64from16s( SEL((order>>6)&3), SEL((order>>4)&3),
9817 SEL((order>>2)&3), SEL((order>>0)&3) )
9818 );
sewardjf0c1c582005-02-07 23:47:38 +00009819 assign(dV, binop( Iop_64HLtoV128,
9820 unop(Iop_V128HIto64, mkexpr(sV)),
sewardjb9fa69b2004-12-09 23:25:14 +00009821 mkexpr(dVlo) ) );
9822 putXMMReg(gregOfRM(modrm), mkexpr(dV));
9823# undef SEL
9824 goto decode_success;
9825 }
9826
9827 /* 66 0F 72 /6 ib = PSLLD by immediate */
9828 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x72
9829 && epartIsReg(insn[2])
9830 && gregOfRM(insn[2]) == 6) {
sewardj38a3f862005-01-13 15:06:51 +00009831 delta = dis_SSE_shiftE_imm( delta+2, "pslld", Iop_ShlN32x4 );
sewardjb9fa69b2004-12-09 23:25:14 +00009832 goto decode_success;
9833 }
9834
9835 /* 66 0F F2 = PSLLD by E */
9836 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF2) {
9837 delta = dis_SSE_shiftG_byE( sorb, delta+2, "pslld", Iop_ShlN32x4 );
9838 goto decode_success;
9839 }
9840
sewardjb9fa69b2004-12-09 23:25:14 +00009841 /* 66 0F 73 /7 ib = PSLLDQ by immediate */
9842 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x73
9843 && epartIsReg(insn[2])
9844 && gregOfRM(insn[2]) == 7) {
sewardj0c9907c2005-01-10 20:37:31 +00009845 IRTemp sV, dV, hi64, lo64, hi64r, lo64r;
9846 Int imm = (Int)insn[3];
9847 Int reg = eregOfRM(insn[2]);
9848 DIP("pslldq $%d,%s\n", imm, nameXMMReg(reg));
9849 vassert(imm >= 0 && imm <= 255);
9850 delta += 4;
9851
9852 sV = newTemp(Ity_V128);
9853 dV = newTemp(Ity_V128);
9854 hi64 = newTemp(Ity_I64);
9855 lo64 = newTemp(Ity_I64);
9856 hi64r = newTemp(Ity_I64);
9857 lo64r = newTemp(Ity_I64);
9858
9859 if (imm >= 16) {
sewardj0c9907c2005-01-10 20:37:31 +00009860 putXMMReg(reg, mkV128(0x0000));
9861 goto decode_success;
9862 }
9863
9864 assign( sV, getXMMReg(reg) );
sewardjf0c1c582005-02-07 23:47:38 +00009865 assign( hi64, unop(Iop_V128HIto64, mkexpr(sV)) );
9866 assign( lo64, unop(Iop_V128to64, mkexpr(sV)) );
sewardj0c9907c2005-01-10 20:37:31 +00009867
sewardjba89f4c2005-04-07 17:31:27 +00009868 if (imm == 0) {
9869 assign( lo64r, mkexpr(lo64) );
9870 assign( hi64r, mkexpr(hi64) );
9871 }
9872 else
sewardj0c9907c2005-01-10 20:37:31 +00009873 if (imm == 8) {
9874 assign( lo64r, mkU64(0) );
9875 assign( hi64r, mkexpr(lo64) );
9876 }
sewardjc02043c2005-01-11 15:03:53 +00009877 else
sewardj0c9907c2005-01-10 20:37:31 +00009878 if (imm > 8) {
sewardj0c9907c2005-01-10 20:37:31 +00009879 assign( lo64r, mkU64(0) );
9880 assign( hi64r, binop( Iop_Shl64,
9881 mkexpr(lo64),
9882 mkU8( 8*(imm-8) ) ));
9883 } else {
9884 assign( lo64r, binop( Iop_Shl64,
9885 mkexpr(lo64),
9886 mkU8(8 * imm) ));
9887 assign( hi64r,
9888 binop( Iop_Or64,
9889 binop(Iop_Shl64, mkexpr(hi64),
9890 mkU8(8 * imm)),
9891 binop(Iop_Shr64, mkexpr(lo64),
9892 mkU8(8 * (8 - imm)) )
9893 )
9894 );
9895 }
sewardjf0c1c582005-02-07 23:47:38 +00009896 assign( dV, binop(Iop_64HLtoV128, mkexpr(hi64r), mkexpr(lo64r)) );
sewardj0c9907c2005-01-10 20:37:31 +00009897 putXMMReg(reg, mkexpr(dV));
sewardjb9fa69b2004-12-09 23:25:14 +00009898 goto decode_success;
9899 }
sewardjb9fa69b2004-12-09 23:25:14 +00009900
9901 /* 66 0F 73 /6 ib = PSLLQ by immediate */
9902 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x73
9903 && epartIsReg(insn[2])
9904 && gregOfRM(insn[2]) == 6) {
sewardj38a3f862005-01-13 15:06:51 +00009905 delta = dis_SSE_shiftE_imm( delta+2, "psllq", Iop_ShlN64x2 );
sewardjb9fa69b2004-12-09 23:25:14 +00009906 goto decode_success;
9907 }
9908
9909 /* 66 0F F3 = PSLLQ by E */
9910 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF3) {
9911 delta = dis_SSE_shiftG_byE( sorb, delta+2, "psllq", Iop_ShlN64x2 );
9912 goto decode_success;
9913 }
9914
9915 /* 66 0F 71 /6 ib = PSLLW by immediate */
9916 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x71
9917 && epartIsReg(insn[2])
9918 && gregOfRM(insn[2]) == 6) {
sewardj38a3f862005-01-13 15:06:51 +00009919 delta = dis_SSE_shiftE_imm( delta+2, "psllw", Iop_ShlN16x8 );
sewardjb9fa69b2004-12-09 23:25:14 +00009920 goto decode_success;
9921 }
9922
9923 /* 66 0F F1 = PSLLW by E */
9924 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF1) {
9925 delta = dis_SSE_shiftG_byE( sorb, delta+2, "psllw", Iop_ShlN16x8 );
9926 goto decode_success;
9927 }
9928
9929 /* 66 0F 72 /4 ib = PSRAD by immediate */
9930 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x72
9931 && epartIsReg(insn[2])
9932 && gregOfRM(insn[2]) == 4) {
sewardj38a3f862005-01-13 15:06:51 +00009933 delta = dis_SSE_shiftE_imm( delta+2, "psrad", Iop_SarN32x4 );
sewardjb9fa69b2004-12-09 23:25:14 +00009934 goto decode_success;
9935 }
9936
9937 /* 66 0F E2 = PSRAD by E */
9938 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE2) {
9939 delta = dis_SSE_shiftG_byE( sorb, delta+2, "psrad", Iop_SarN32x4 );
9940 goto decode_success;
9941 }
9942
9943 /* 66 0F 71 /4 ib = PSRAW by immediate */
9944 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x71
9945 && epartIsReg(insn[2])
9946 && gregOfRM(insn[2]) == 4) {
sewardj38a3f862005-01-13 15:06:51 +00009947 delta = dis_SSE_shiftE_imm( delta+2, "psraw", Iop_SarN16x8 );
sewardjb9fa69b2004-12-09 23:25:14 +00009948 goto decode_success;
9949 }
9950
9951 /* 66 0F E1 = PSRAW by E */
9952 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE1) {
9953 delta = dis_SSE_shiftG_byE( sorb, delta+2, "psraw", Iop_SarN16x8 );
9954 goto decode_success;
9955 }
9956
9957 /* 66 0F 72 /2 ib = PSRLD by immediate */
9958 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x72
9959 && epartIsReg(insn[2])
9960 && gregOfRM(insn[2]) == 2) {
sewardj38a3f862005-01-13 15:06:51 +00009961 delta = dis_SSE_shiftE_imm( delta+2, "psrld", Iop_ShrN32x4 );
sewardjb9fa69b2004-12-09 23:25:14 +00009962 goto decode_success;
9963 }
9964
9965 /* 66 0F D2 = PSRLD by E */
9966 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD2) {
9967 delta = dis_SSE_shiftG_byE( sorb, delta+2, "psrld", Iop_ShrN32x4 );
9968 goto decode_success;
9969 }
9970
sewardj9ee82862004-12-14 01:16:59 +00009971 /* 66 0F 73 /3 ib = PSRLDQ by immediate */
9972 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x73
9973 && epartIsReg(insn[2])
sewardj95535fe2004-12-15 17:42:58 +00009974 && gregOfRM(insn[2]) == 3) {
9975 IRTemp sV, dV, hi64, lo64, hi64r, lo64r;
sewardj9ee82862004-12-14 01:16:59 +00009976 Int imm = (Int)insn[3];
9977 Int reg = eregOfRM(insn[2]);
sewardj9ee82862004-12-14 01:16:59 +00009978 DIP("psrldq $%d,%s\n", imm, nameXMMReg(reg));
sewardj95535fe2004-12-15 17:42:58 +00009979 vassert(imm >= 0 && imm <= 255);
9980 delta += 4;
9981
9982 sV = newTemp(Ity_V128);
9983 dV = newTemp(Ity_V128);
9984 hi64 = newTemp(Ity_I64);
9985 lo64 = newTemp(Ity_I64);
9986 hi64r = newTemp(Ity_I64);
9987 lo64r = newTemp(Ity_I64);
9988
9989 if (imm >= 16) {
sewardj95535fe2004-12-15 17:42:58 +00009990 putXMMReg(reg, mkV128(0x0000));
9991 goto decode_success;
9992 }
9993
9994 assign( sV, getXMMReg(reg) );
sewardjf0c1c582005-02-07 23:47:38 +00009995 assign( hi64, unop(Iop_V128HIto64, mkexpr(sV)) );
9996 assign( lo64, unop(Iop_V128to64, mkexpr(sV)) );
sewardj95535fe2004-12-15 17:42:58 +00009997
sewardjba89f4c2005-04-07 17:31:27 +00009998 if (imm == 0) {
9999 assign( lo64r, mkexpr(lo64) );
10000 assign( hi64r, mkexpr(hi64) );
10001 }
10002 else
sewardj95535fe2004-12-15 17:42:58 +000010003 if (imm == 8) {
10004 assign( hi64r, mkU64(0) );
10005 assign( lo64r, mkexpr(hi64) );
10006 }
10007 else
10008 if (imm > 8) {
sewardj95535fe2004-12-15 17:42:58 +000010009 assign( hi64r, mkU64(0) );
10010 assign( lo64r, binop( Iop_Shr64,
10011 mkexpr(hi64),
10012 mkU8( 8*(imm-8) ) ));
10013 } else {
10014 assign( hi64r, binop( Iop_Shr64,
10015 mkexpr(hi64),
10016 mkU8(8 * imm) ));
10017 assign( lo64r,
10018 binop( Iop_Or64,
10019 binop(Iop_Shr64, mkexpr(lo64),
10020 mkU8(8 * imm)),
10021 binop(Iop_Shl64, mkexpr(hi64),
10022 mkU8(8 * (8 - imm)) )
10023 )
10024 );
10025 }
10026
sewardjf0c1c582005-02-07 23:47:38 +000010027 assign( dV, binop(Iop_64HLtoV128, mkexpr(hi64r), mkexpr(lo64r)) );
sewardj95535fe2004-12-15 17:42:58 +000010028 putXMMReg(reg, mkexpr(dV));
sewardj9ee82862004-12-14 01:16:59 +000010029 goto decode_success;
10030 }
10031
sewardjb9fa69b2004-12-09 23:25:14 +000010032 /* 66 0F 73 /2 ib = PSRLQ by immediate */
10033 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x73
10034 && epartIsReg(insn[2])
10035 && gregOfRM(insn[2]) == 2) {
sewardj38a3f862005-01-13 15:06:51 +000010036 delta = dis_SSE_shiftE_imm( delta+2, "psrlq", Iop_ShrN64x2 );
sewardjb9fa69b2004-12-09 23:25:14 +000010037 goto decode_success;
10038 }
10039
10040 /* 66 0F D3 = PSRLQ by E */
10041 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD3) {
10042 delta = dis_SSE_shiftG_byE( sorb, delta+2, "psrlq", Iop_ShrN64x2 );
10043 goto decode_success;
10044 }
10045
10046 /* 66 0F 71 /2 ib = PSRLW by immediate */
10047 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x71
10048 && epartIsReg(insn[2])
10049 && gregOfRM(insn[2]) == 2) {
sewardj38a3f862005-01-13 15:06:51 +000010050 delta = dis_SSE_shiftE_imm( delta+2, "psrlw", Iop_ShrN16x8 );
sewardjb9fa69b2004-12-09 23:25:14 +000010051 goto decode_success;
10052 }
10053
10054 /* 66 0F D1 = PSRLW by E */
10055 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD1) {
10056 delta = dis_SSE_shiftG_byE( sorb, delta+2, "psrlw", Iop_ShrN16x8 );
10057 goto decode_success;
10058 }
10059
10060 /* 66 0F F8 = PSUBB */
10061 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF8) {
10062 delta = dis_SSEint_E_to_G( sorb, delta+2,
10063 "psubb", Iop_Sub8x16, False );
10064 goto decode_success;
10065 }
10066
10067 /* 66 0F FA = PSUBD */
10068 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xFA) {
10069 delta = dis_SSEint_E_to_G( sorb, delta+2,
10070 "psubd", Iop_Sub32x4, False );
10071 goto decode_success;
10072 }
10073
10074 /* ***--- this is an MMX class insn introduced in SSE2 ---*** */
10075 /* 0F FB = PSUBQ -- sub 64x1 */
10076 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xFB) {
10077 do_MMX_preamble();
10078 delta = dis_MMXop_regmem_to_reg (
10079 sorb, delta+2, insn[1], "psubq", False );
10080 goto decode_success;
10081 }
10082
10083 /* 66 0F FB = PSUBQ */
10084 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xFB) {
10085 delta = dis_SSEint_E_to_G( sorb, delta+2,
10086 "psubq", Iop_Sub64x2, False );
10087 goto decode_success;
10088 }
10089
10090 /* 66 0F F9 = PSUBW */
10091 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF9) {
10092 delta = dis_SSEint_E_to_G( sorb, delta+2,
10093 "psubw", Iop_Sub16x8, False );
10094 goto decode_success;
10095 }
10096
10097 /* 66 0F E8 = PSUBSB */
10098 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE8) {
10099 delta = dis_SSEint_E_to_G( sorb, delta+2,
10100 "psubsb", Iop_QSub8Sx16, False );
10101 goto decode_success;
10102 }
10103
10104 /* 66 0F E9 = PSUBSW */
10105 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE9) {
10106 delta = dis_SSEint_E_to_G( sorb, delta+2,
10107 "psubsw", Iop_QSub16Sx8, False );
10108 goto decode_success;
10109 }
10110
10111 /* 66 0F D8 = PSUBSB */
10112 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD8) {
10113 delta = dis_SSEint_E_to_G( sorb, delta+2,
10114 "psubusb", Iop_QSub8Ux16, False );
10115 goto decode_success;
10116 }
10117
10118 /* 66 0F D9 = PSUBSW */
10119 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD9) {
10120 delta = dis_SSEint_E_to_G( sorb, delta+2,
10121 "psubusw", Iop_QSub16Ux8, False );
10122 goto decode_success;
10123 }
10124
sewardj9e203592004-12-10 01:48:18 +000010125 /* 66 0F 68 = PUNPCKHBW */
10126 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x68) {
10127 delta = dis_SSEint_E_to_G( sorb, delta+2,
10128 "punpckhbw",
10129 Iop_InterleaveHI8x16, True );
10130 goto decode_success;
10131 }
10132
10133 /* 66 0F 6A = PUNPCKHDQ */
10134 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x6A) {
10135 delta = dis_SSEint_E_to_G( sorb, delta+2,
10136 "punpckhdq",
10137 Iop_InterleaveHI32x4, True );
10138 goto decode_success;
10139 }
10140
10141 /* 66 0F 6D = PUNPCKHQDQ */
10142 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x6D) {
10143 delta = dis_SSEint_E_to_G( sorb, delta+2,
10144 "punpckhqdq",
10145 Iop_InterleaveHI64x2, True );
10146 goto decode_success;
10147 }
10148
10149 /* 66 0F 69 = PUNPCKHWD */
10150 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x69) {
10151 delta = dis_SSEint_E_to_G( sorb, delta+2,
10152 "punpckhwd",
10153 Iop_InterleaveHI16x8, True );
10154 goto decode_success;
10155 }
10156
10157 /* 66 0F 60 = PUNPCKLBW */
10158 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x60) {
10159 delta = dis_SSEint_E_to_G( sorb, delta+2,
10160 "punpcklbw",
10161 Iop_InterleaveLO8x16, True );
10162 goto decode_success;
10163 }
10164
10165 /* 66 0F 62 = PUNPCKLDQ */
10166 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x62) {
10167 delta = dis_SSEint_E_to_G( sorb, delta+2,
10168 "punpckldq",
10169 Iop_InterleaveLO32x4, True );
10170 goto decode_success;
10171 }
10172
10173 /* 66 0F 6C = PUNPCKLQDQ */
10174 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x6C) {
10175 delta = dis_SSEint_E_to_G( sorb, delta+2,
10176 "punpcklqdq",
10177 Iop_InterleaveLO64x2, True );
10178 goto decode_success;
10179 }
10180
10181 /* 66 0F 61 = PUNPCKLWD */
10182 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x61) {
10183 delta = dis_SSEint_E_to_G( sorb, delta+2,
10184 "punpcklwd",
10185 Iop_InterleaveLO16x8, True );
10186 goto decode_success;
10187 }
10188
10189 /* 66 0F EF = PXOR */
10190 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xEF) {
sewardjf0c1c582005-02-07 23:47:38 +000010191 delta = dis_SSE_E_to_G_all( sorb, delta+2, "pxor", Iop_XorV128 );
sewardj9e203592004-12-10 01:48:18 +000010192 goto decode_success;
10193 }
10194
sewardj164f9272004-12-09 00:39:32 +000010195
sewardjc9a65702004-07-07 16:32:57 +000010196//-- /* FXSAVE/FXRSTOR m32 -- load/store the FPU/MMX/SSE state. */
10197//-- if (insn[0] == 0x0F && insn[1] == 0xAE
10198//-- && (!epartIsReg(insn[2]))
10199//-- && (gregOfRM(insn[2]) == 1 || gregOfRM(insn[2]) == 0) ) {
10200//-- Bool store = gregOfRM(insn[2]) == 0;
10201//-- vg_assert(sz == 4);
10202//-- pair = disAMode ( cb, sorb, eip+2, dis_buf );
10203//-- t1 = LOW24(pair);
10204//-- eip += 2+HI8(pair);
10205//-- uInstr3(cb, store ? SSE2a_MemWr : SSE2a_MemRd, 512,
10206//-- Lit16, (((UShort)insn[0]) << 8) | (UShort)insn[1],
10207//-- Lit16, (UShort)insn[2],
10208//-- TempReg, t1 );
10209//-- DIP("fx%s %s\n", store ? "save" : "rstor", dis_buf );
10210//-- goto decode_success;
10211//-- }
10212//--
sewardjc9a65702004-07-07 16:32:57 +000010213//-- /* CLFLUSH -- flush cache line */
10214//-- if (insn[0] == 0x0F && insn[1] == 0xAE
10215//-- && (!epartIsReg(insn[2]))
10216//-- && (gregOfRM(insn[2]) == 7))
10217//-- {
10218//-- vg_assert(sz == 4);
10219//-- pair = disAMode ( cb, sorb, eip+2, dis_buf );
10220//-- t1 = LOW24(pair);
10221//-- eip += 2+HI8(pair);
10222//-- uInstr3(cb, SSE2a_MemRd, 0, /* ignore sz for internal ops */
10223//-- Lit16, (((UShort)0x0F) << 8) | (UShort)0xAE,
10224//-- Lit16, (UShort)insn[2],
10225//-- TempReg, t1 );
10226//-- DIP("clflush %s\n", dis_buf);
10227//-- goto decode_success;
10228//-- }
sewardjc9a65702004-07-07 16:32:57 +000010229
10230
10231 /* ---------------------------------------------------- */
sewardj9df271d2004-12-31 22:37:42 +000010232 /* --- end of the SSE/SSE2 decoder. --- */
sewardjc9a65702004-07-07 16:32:57 +000010233 /* ---------------------------------------------------- */
10234
sewardj9df271d2004-12-31 22:37:42 +000010235 after_sse_decoders:
10236
sewardjc9a65702004-07-07 16:32:57 +000010237 /* Get the primary opcode. */
10238 opc = getIByte(delta); delta++;
10239
10240 /* We get here if the current insn isn't SSE, or this CPU doesn't
10241 support SSE. */
10242
10243 switch (opc) {
10244
10245 /* ------------------------ Control flow --------------- */
sewardj940e8c92004-07-11 16:53:24 +000010246
10247 case 0xC2: /* RET imm16 */
10248 d32 = getUDisp16(delta);
10249 delta += 2;
10250 dis_ret(d32);
sewardj9e6491a2005-07-02 19:24:10 +000010251 dres.whatNext = Dis_StopHere;
sewardj2d49b432005-02-01 00:37:06 +000010252 DIP("ret %d\n", (Int)d32);
sewardj940e8c92004-07-11 16:53:24 +000010253 break;
sewardje05c42c2004-07-08 20:25:10 +000010254 case 0xC3: /* RET */
10255 dis_ret(0);
sewardj9e6491a2005-07-02 19:24:10 +000010256 dres.whatNext = Dis_StopHere;
sewardje05c42c2004-07-08 20:25:10 +000010257 DIP("ret\n");
10258 break;
sewardjd1061ab2004-07-08 01:45:30 +000010259
10260 case 0xE8: /* CALL J4 */
10261 d32 = getUDisp32(delta); delta += 4;
sewardj9e6491a2005-07-02 19:24:10 +000010262 d32 += (guest_EIP_bbstart+delta);
sewardjce70a5c2004-10-18 14:09:54 +000010263 /* (guest_eip_bbstart+delta) == return-to addr, d32 == call-to addr */
sewardj9e6491a2005-07-02 19:24:10 +000010264 if (d32 == guest_EIP_bbstart+delta && getIByte(delta) >= 0x58
sewardjce70a5c2004-10-18 14:09:54 +000010265 && getIByte(delta) <= 0x5F) {
sewardjd1061ab2004-07-08 01:45:30 +000010266 /* Specially treat the position-independent-code idiom
10267 call X
10268 X: popl %reg
10269 as
10270 movl %eip, %reg.
10271 since this generates better code, but for no other reason. */
10272 Int archReg = getIByte(delta) - 0x58;
sewardjc2ac51e2004-07-12 01:03:26 +000010273 /* vex_printf("-- fPIC thingy\n"); */
sewardj9e6491a2005-07-02 19:24:10 +000010274 putIReg(4, archReg, mkU32(guest_EIP_bbstart+delta));
sewardjd1061ab2004-07-08 01:45:30 +000010275 delta++; /* Step over the POP */
10276 DIP("call 0x%x ; popl %s\n",d32,nameIReg(4,archReg));
sewardjc2ac51e2004-07-12 01:03:26 +000010277 } else {
sewardjd1061ab2004-07-08 01:45:30 +000010278 /* The normal sequence for a call. */
10279 t1 = newTemp(Ity_I32);
sewardj41f43bc2004-07-08 14:23:22 +000010280 assign(t1, binop(Iop_Sub32, getIReg(4,R_ESP), mkU32(4)));
10281 putIReg(4, R_ESP, mkexpr(t1));
sewardj9e6491a2005-07-02 19:24:10 +000010282 storeLE( mkexpr(t1), mkU32(guest_EIP_bbstart+delta));
10283 if (resteerOkFn((Addr64)(Addr32)d32)) {
sewardjce70a5c2004-10-18 14:09:54 +000010284 /* follow into the call target. */
sewardj9e6491a2005-07-02 19:24:10 +000010285 dres.whatNext = Dis_Resteer;
10286 dres.continueAt = (Addr64)(Addr32)d32;
sewardjce70a5c2004-10-18 14:09:54 +000010287 } else {
10288 jmp_lit(Ijk_Call,d32);
sewardj9e6491a2005-07-02 19:24:10 +000010289 dres.whatNext = Dis_StopHere;
sewardjce70a5c2004-10-18 14:09:54 +000010290 }
sewardjd1061ab2004-07-08 01:45:30 +000010291 DIP("call 0x%x\n",d32);
10292 }
10293 break;
10294
sewardjc9a65702004-07-07 16:32:57 +000010295//-- case 0xC8: /* ENTER */
10296//-- d32 = getUDisp16(eip); eip += 2;
10297//-- abyte = getIByte(delta); delta++;
10298//--
10299//-- vg_assert(sz == 4);
10300//-- vg_assert(abyte == 0);
10301//--
10302//-- t1 = newTemp(cb); t2 = newTemp(cb);
10303//-- uInstr2(cb, GET, sz, ArchReg, R_EBP, TempReg, t1);
10304//-- uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t2);
10305//-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
10306//-- uLiteral(cb, sz);
10307//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
10308//-- uInstr2(cb, STORE, 4, TempReg, t1, TempReg, t2);
10309//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_EBP);
10310//-- if (d32) {
10311//-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
sewardj5bd4d162004-11-10 13:02:48 +000010312//-- uLiteral(cb, d32);
10313//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
sewardjc9a65702004-07-07 16:32:57 +000010314//-- }
10315//-- DIP("enter 0x%x, 0x%x", d32, abyte);
10316//-- break;
sewardjc2ac51e2004-07-12 01:03:26 +000010317
10318 case 0xC9: /* LEAVE */
10319 vassert(sz == 4);
10320 t1 = newTemp(Ity_I32); t2 = newTemp(Ity_I32);
10321 assign(t1, getIReg(4,R_EBP));
10322 /* First PUT ESP looks redundant, but need it because ESP must
10323 always be up-to-date for Memcheck to work... */
10324 putIReg(4, R_ESP, mkexpr(t1));
10325 assign(t2, loadLE(Ity_I32,mkexpr(t1)));
10326 putIReg(4, R_EBP, mkexpr(t2));
10327 putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t1), mkU32(4)) );
10328 DIP("leave\n");
10329 break;
10330
sewardjc9a65702004-07-07 16:32:57 +000010331//-- /* ---------------- Misc weird-ass insns --------------- */
10332//--
10333//-- case 0x27: /* DAA */
10334//-- case 0x2F: /* DAS */
10335//-- t1 = newTemp(cb);
10336//-- uInstr2(cb, GET, 1, ArchReg, R_AL, TempReg, t1);
10337//-- /* Widen %AL to 32 bits, so it's all defined when we push it. */
10338//-- uInstr1(cb, WIDEN, 4, TempReg, t1);
10339//-- uWiden(cb, 1, False);
10340//-- uInstr0(cb, CALLM_S, 0);
10341//-- uInstr1(cb, PUSH, 4, TempReg, t1);
10342//-- uInstr1(cb, CALLM, 0, Lit16,
10343//-- opc == 0x27 ? VGOFF_(helper_DAA) : VGOFF_(helper_DAS) );
10344//-- uFlagsRWU(cb, FlagsAC, FlagsSZACP, FlagO);
10345//-- uInstr1(cb, POP, 4, TempReg, t1);
10346//-- uInstr0(cb, CALLM_E, 0);
10347//-- uInstr2(cb, PUT, 1, TempReg, t1, ArchReg, R_AL);
10348//-- DIP(opc == 0x27 ? "daa\n" : "das\n");
10349//-- break;
10350//--
10351//-- case 0x37: /* AAA */
10352//-- case 0x3F: /* AAS */
10353//-- t1 = newTemp(cb);
10354//-- uInstr2(cb, GET, 2, ArchReg, R_EAX, TempReg, t1);
10355//-- /* Widen %AL to 32 bits, so it's all defined when we push it. */
10356//-- uInstr1(cb, WIDEN, 4, TempReg, t1);
10357//-- uWiden(cb, 2, False);
10358//-- uInstr0(cb, CALLM_S, 0);
10359//-- uInstr1(cb, PUSH, 4, TempReg, t1);
10360//-- uInstr1(cb, CALLM, 0, Lit16,
10361//-- opc == 0x37 ? VGOFF_(helper_AAA) : VGOFF_(helper_AAS) );
10362//-- uFlagsRWU(cb, FlagA, FlagsAC, FlagsEmpty);
10363//-- uInstr1(cb, POP, 4, TempReg, t1);
10364//-- uInstr0(cb, CALLM_E, 0);
10365//-- uInstr2(cb, PUT, 2, TempReg, t1, ArchReg, R_EAX);
10366//-- DIP(opc == 0x37 ? "aaa\n" : "aas\n");
10367//-- break;
10368//--
10369//-- case 0xD4: /* AAM */
10370//-- case 0xD5: /* AAD */
10371//-- d32 = getIByte(delta); delta++;
10372//-- if (d32 != 10) VG_(core_panic)("disInstr: AAM/AAD but base not 10 !");
10373//-- t1 = newTemp(cb);
10374//-- uInstr2(cb, GET, 2, ArchReg, R_EAX, TempReg, t1);
10375//-- /* Widen %AX to 32 bits, so it's all defined when we push it. */
10376//-- uInstr1(cb, WIDEN, 4, TempReg, t1);
10377//-- uWiden(cb, 2, False);
10378//-- uInstr0(cb, CALLM_S, 0);
10379//-- uInstr1(cb, PUSH, 4, TempReg, t1);
10380//-- uInstr1(cb, CALLM, 0, Lit16,
10381//-- opc == 0xD4 ? VGOFF_(helper_AAM) : VGOFF_(helper_AAD) );
10382//-- uFlagsRWU(cb, FlagsEmpty, FlagsSZP, FlagsEmpty);
10383//-- uInstr1(cb, POP, 4, TempReg, t1);
10384//-- uInstr0(cb, CALLM_E, 0);
10385//-- uInstr2(cb, PUT, 2, TempReg, t1, ArchReg, R_EAX);
10386//-- DIP(opc == 0xD4 ? "aam\n" : "aad\n");
10387//-- break;
sewardj1c6f9912004-09-07 10:15:24 +000010388
10389 /* ------------------------ CWD/CDQ -------------------- */
10390
10391 case 0x98: /* CBW */
10392 if (sz == 4) {
10393 putIReg(4, R_EAX, unop(Iop_16Sto32, getIReg(2, R_EAX)));
10394 DIP("cwde\n");
10395 } else {
sewardj47341042004-09-19 11:55:46 +000010396 vassert(sz == 2);
10397 putIReg(2, R_EAX, unop(Iop_8Sto16, getIReg(1, R_EAX)));
10398 DIP("cbw\n");
sewardj1c6f9912004-09-07 10:15:24 +000010399 }
10400 break;
sewardj64e1d652004-07-12 14:00:46 +000010401
10402 case 0x99: /* CWD/CDQ */
10403 ty = szToITy(sz);
10404 putIReg(sz, R_EDX,
10405 binop(mkSizedOp(ty,Iop_Sar8),
10406 getIReg(sz, R_EAX),
sewardj9ee82862004-12-14 01:16:59 +000010407 mkU8(sz == 2 ? 15 : 31)) );
sewardj64e1d652004-07-12 14:00:46 +000010408 DIP(sz == 2 ? "cwdq\n" : "cdqq\n");
10409 break;
10410
sewardjbdc7d212004-09-09 02:46:40 +000010411 /* ------------------------ FPU ops -------------------- */
10412
10413 case 0x9E: /* SAHF */
10414 codegen_SAHF();
10415 DIP("sahf\n");
10416 break;
10417
sewardjc9a65702004-07-07 16:32:57 +000010418//-- case 0x9F: /* LAHF */
10419//-- codegen_LAHF ( cb );
10420//-- DIP("lahf\n");
10421//-- break;
10422//--
sewardjbdc7d212004-09-09 02:46:40 +000010423 case 0x9B: /* FWAIT */
10424 /* ignore? */
10425 DIP("fwait\n");
10426 break;
10427
sewardjd1725d12004-08-12 20:46:53 +000010428 case 0xD8:
10429 case 0xD9:
10430 case 0xDA:
10431 case 0xDB:
10432 case 0xDC:
10433 case 0xDD:
10434 case 0xDE:
10435 case 0xDF: {
sewardj52d04912005-07-03 00:52:48 +000010436 Int delta0 = delta;
sewardjd1725d12004-08-12 20:46:53 +000010437 Bool decode_OK = False;
10438 delta = dis_FPU ( &decode_OK, sorb, delta );
10439 if (!decode_OK) {
10440 delta = delta0;
10441 goto decode_failure;
10442 }
10443 break;
10444 }
sewardj0611d802004-07-11 02:37:54 +000010445
10446 /* ------------------------ INC & DEC ------------------ */
10447
10448 case 0x40: /* INC eAX */
10449 case 0x41: /* INC eCX */
10450 case 0x42: /* INC eDX */
10451 case 0x43: /* INC eBX */
10452 case 0x44: /* INC eSP */
10453 case 0x45: /* INC eBP */
10454 case 0x46: /* INC eSI */
10455 case 0x47: /* INC eDI */
10456 vassert(sz == 2 || sz == 4);
10457 ty = szToITy(sz);
10458 t1 = newTemp(ty);
10459 assign( t1, binop(mkSizedOp(ty,Iop_Add8),
10460 getIReg(sz, (UInt)(opc - 0x40)),
10461 mkU(ty,1)) );
10462 setFlags_INC_DEC( True, t1, ty );
10463 putIReg(sz, (UInt)(opc - 0x40), mkexpr(t1));
10464 DIP("inc%c %s\n", nameISize(sz), nameIReg(sz,opc-0x40));
10465 break;
10466
10467 case 0x48: /* DEC eAX */
10468 case 0x49: /* DEC eCX */
10469 case 0x4A: /* DEC eDX */
10470 case 0x4B: /* DEC eBX */
10471 case 0x4C: /* DEC eSP */
10472 case 0x4D: /* DEC eBP */
10473 case 0x4E: /* DEC eSI */
10474 case 0x4F: /* DEC eDI */
10475 vassert(sz == 2 || sz == 4);
10476 ty = szToITy(sz);
10477 t1 = newTemp(ty);
10478 assign( t1, binop(mkSizedOp(ty,Iop_Sub8),
10479 getIReg(sz, (UInt)(opc - 0x48)),
10480 mkU(ty,1)) );
10481 setFlags_INC_DEC( False, t1, ty );
10482 putIReg(sz, (UInt)(opc - 0x48), mkexpr(t1));
10483 DIP("dec%c %s\n", nameISize(sz), nameIReg(sz,opc-0x48));
10484 break;
10485
10486 /* ------------------------ INT ------------------------ */
10487
10488 case 0xCD: /* INT imm8 */
10489 d32 = getIByte(delta); delta++;
10490 if (d32 != 0x80) goto decode_failure;
10491 /* It's important that all ArchRegs carry their up-to-date value
10492 at this point. So we declare an end-of-block here, which
10493 forces any TempRegs caching ArchRegs to be flushed. */
sewardj9e6491a2005-07-02 19:24:10 +000010494 jmp_lit(Ijk_Syscall,((Addr32)guest_EIP_bbstart)+delta);
10495 dres.whatNext = Dis_StopHere;
sewardj0611d802004-07-11 02:37:54 +000010496 DIP("int $0x80\n");
10497 break;
10498
sewardj77b86be2004-07-11 13:28:24 +000010499 /* ------------------------ Jcond, byte offset --------- */
10500
10501 case 0xEB: /* Jb (jump, byte offset) */
sewardj9e6491a2005-07-02 19:24:10 +000010502 d32 = (((Addr32)guest_EIP_bbstart)+delta+1) + getSDisp8(delta);
sewardj77b86be2004-07-11 13:28:24 +000010503 delta++;
sewardj9e6491a2005-07-02 19:24:10 +000010504 if (resteerOkFn((Addr64)(Addr32)d32)) {
10505 dres.whatNext = Dis_Resteer;
10506 dres.continueAt = (Addr64)(Addr32)d32;
sewardjce70a5c2004-10-18 14:09:54 +000010507 } else {
10508 jmp_lit(Ijk_Boring,d32);
sewardj9e6491a2005-07-02 19:24:10 +000010509 dres.whatNext = Dis_StopHere;
sewardjce70a5c2004-10-18 14:09:54 +000010510 }
sewardj77b86be2004-07-11 13:28:24 +000010511 DIP("jmp-8 0x%x\n", d32);
10512 break;
sewardj0611d802004-07-11 02:37:54 +000010513
10514 case 0xE9: /* Jv (jump, 16/32 offset) */
10515 vassert(sz == 4); /* JRS added 2004 July 11 */
sewardj9e6491a2005-07-02 19:24:10 +000010516 d32 = (((Addr32)guest_EIP_bbstart)+delta+sz) + getSDisp(sz,delta);
sewardj0611d802004-07-11 02:37:54 +000010517 delta += sz;
sewardj9e6491a2005-07-02 19:24:10 +000010518 if (resteerOkFn((Addr64)(Addr32)d32)) {
10519 dres.whatNext = Dis_Resteer;
10520 dres.continueAt = (Addr64)(Addr32)d32;
sewardjce70a5c2004-10-18 14:09:54 +000010521 } else {
10522 jmp_lit(Ijk_Boring,d32);
sewardj9e6491a2005-07-02 19:24:10 +000010523 dres.whatNext = Dis_StopHere;
sewardjce70a5c2004-10-18 14:09:54 +000010524 }
sewardj0611d802004-07-11 02:37:54 +000010525 DIP("jmp 0x%x\n", d32);
10526 break;
sewardje87b4842004-07-10 12:23:30 +000010527
10528 case 0x70:
10529 case 0x71:
10530 case 0x72: /* JBb/JNAEb (jump below) */
10531 case 0x73: /* JNBb/JAEb (jump not below) */
10532 case 0x74: /* JZb/JEb (jump zero) */
10533 case 0x75: /* JNZb/JNEb (jump not zero) */
10534 case 0x76: /* JBEb/JNAb (jump below or equal) */
10535 case 0x77: /* JNBEb/JAb (jump not below or equal) */
10536 case 0x78: /* JSb (jump negative) */
10537 case 0x79: /* JSb (jump not negative) */
10538 case 0x7A: /* JP (jump parity even) */
10539 case 0x7B: /* JNP/JPO (jump parity odd) */
10540 case 0x7C: /* JLb/JNGEb (jump less) */
10541 case 0x7D: /* JGEb/JNLb (jump greater or equal) */
10542 case 0x7E: /* JLEb/JNGb (jump less or equal) */
10543 case 0x7F: /* JGb/JNLEb (jump greater) */
sewardj9e6491a2005-07-02 19:24:10 +000010544 d32 = (((Addr32)guest_EIP_bbstart)+delta+1) + getSDisp8(delta);
sewardje87b4842004-07-10 12:23:30 +000010545 delta++;
sewardj9e6491a2005-07-02 19:24:10 +000010546 if (0 && resteerOkFn((Addr64)(Addr32)d32)) {
10547 /* Unused experimental hack: speculatively follow one arm
10548 of a conditional branch. */
sewardjdbf550c2005-01-24 11:54:11 +000010549 /* Assume the branch is taken. So we need to emit a
10550 side-exit to the insn following this one, on the negation
10551 of the condition, and continue at the branch target
10552 address (d32). */
10553 if (0) vex_printf("resteer\n");
10554 stmt( IRStmt_Exit(
10555 mk_x86g_calculate_condition((X86Condcode)(1 ^ (opc - 0x70))),
10556 Ijk_Boring,
sewardj9e6491a2005-07-02 19:24:10 +000010557 IRConst_U32(guest_EIP_bbstart+delta) ) );
10558 dres.whatNext = Dis_Resteer;
10559 dres.continueAt = (Addr64)(Addr32)d32;
sewardjdbf550c2005-01-24 11:54:11 +000010560 } else {
sewardj9e6491a2005-07-02 19:24:10 +000010561 jcc_01((X86Condcode)(opc - 0x70), (Addr32)(guest_EIP_bbstart+delta), d32);
10562 dres.whatNext = Dis_StopHere;
sewardjdbf550c2005-01-24 11:54:11 +000010563 }
sewardj2a9ad022004-11-25 02:46:58 +000010564 DIP("j%s-8 0x%x\n", name_X86Condcode(opc - 0x70), d32);
sewardje87b4842004-07-10 12:23:30 +000010565 break;
10566
sewardj458a6f82004-08-25 12:46:02 +000010567 case 0xE3: /* JECXZ or perhaps JCXZ, depending on OSO ? Intel
sewardjbaa66082005-08-23 17:29:27 +000010568 manual says it depends on address size override. */
10569 if (sz != 4) goto decode_failure;
sewardj9e6491a2005-07-02 19:24:10 +000010570 d32 = (((Addr32)guest_EIP_bbstart)+delta+1) + getSDisp8(delta);
sewardj458a6f82004-08-25 12:46:02 +000010571 delta++;
10572 ty = szToITy(sz);
10573 stmt( IRStmt_Exit(
10574 binop(mkSizedOp(ty,Iop_CmpEQ8),
10575 getIReg(sz,R_ECX),
10576 mkU(ty,0)),
sewardj893aada2004-11-29 19:57:54 +000010577 Ijk_Boring,
sewardj458a6f82004-08-25 12:46:02 +000010578 IRConst_U32(d32))
10579 );
10580
10581 DIP("j%sz 0x%x\n", nameIReg(sz, R_ECX), d32);
10582 break;
10583
sewardjbaa66082005-08-23 17:29:27 +000010584 case 0xE0: /* LOOPNE disp8: decrement count, jump if count != 0 && ZF==0 */
10585 case 0xE1: /* LOOPE disp8: decrement count, jump if count != 0 && ZF==1 */
10586 case 0xE2: /* LOOP disp8: decrement count, jump if count != 0 */
10587 { /* Again, the docs say this uses ECX/CX as a count depending on
10588 the address size override, not the operand one. Since we
10589 don't handle address size overrides, I guess that means
10590 ECX. */
10591 IRExpr* zbit = NULL;
10592 IRExpr* count = NULL;
10593 IRExpr* cond = NULL;
10594 HChar* xtra = NULL;
10595
10596 if (sz != 4) goto decode_failure;
10597 d32 = (((Addr32)guest_EIP_bbstart)+delta+1) + getSDisp8(delta);
10598 delta++;
10599 putIReg(4, R_ECX, binop(Iop_Sub32, getIReg(4,R_ECX), mkU32(1)));
10600
10601 count = getIReg(4,R_ECX);
10602 cond = binop(Iop_CmpNE32, count, mkU32(0));
10603 switch (opc) {
10604 case 0xE2:
10605 xtra = "";
10606 break;
10607 case 0xE1:
10608 xtra = "e";
10609 zbit = mk_x86g_calculate_condition( X86CondZ );
10610 cond = mkAnd1(cond, zbit);
10611 break;
10612 case 0xE0:
10613 xtra = "ne";
10614 zbit = mk_x86g_calculate_condition( X86CondNZ );
10615 cond = mkAnd1(cond, zbit);
10616 break;
10617 default:
10618 vassert(0);
10619 }
10620 stmt( IRStmt_Exit(cond, Ijk_Boring, IRConst_U32(d32)) );
10621
10622 DIP("loop%s 0x%x\n", xtra, d32);
10623 break;
10624 }
sewardj1813dbe2004-07-28 17:09:04 +000010625
10626 /* ------------------------ IMUL ----------------------- */
10627
10628 case 0x69: /* IMUL Iv, Ev, Gv */
10629 delta = dis_imul_I_E_G ( sorb, sz, delta, sz );
10630 break;
10631 case 0x6B: /* IMUL Ib, Ev, Gv */
10632 delta = dis_imul_I_E_G ( sorb, sz, delta, 1 );
10633 break;
sewardj0611d802004-07-11 02:37:54 +000010634
10635 /* ------------------------ MOV ------------------------ */
10636
10637 case 0x88: /* MOV Gb,Eb */
10638 delta = dis_mov_G_E(sorb, 1, delta);
10639 break;
sewardjc9a65702004-07-07 16:32:57 +000010640
10641 case 0x89: /* MOV Gv,Ev */
10642 delta = dis_mov_G_E(sorb, sz, delta);
10643 break;
10644
sewardjc2ac51e2004-07-12 01:03:26 +000010645 case 0x8A: /* MOV Eb,Gb */
10646 delta = dis_mov_E_G(sorb, 1, delta);
10647 break;
sewardje05c42c2004-07-08 20:25:10 +000010648
10649 case 0x8B: /* MOV Ev,Gv */
10650 delta = dis_mov_E_G(sorb, sz, delta);
10651 break;
10652
sewardje87b4842004-07-10 12:23:30 +000010653 case 0x8D: /* LEA M,Gv */
sewardje9460bd2005-01-28 13:45:42 +000010654 if (sz != 4)
10655 goto decode_failure;
sewardje05c42c2004-07-08 20:25:10 +000010656 modrm = getIByte(delta);
10657 if (epartIsReg(modrm))
sewardje9460bd2005-01-28 13:45:42 +000010658 goto decode_failure;
sewardje05c42c2004-07-08 20:25:10 +000010659 /* NOTE! this is the one place where a segment override prefix
10660 has no effect on the address calculation. Therefore we pass
10661 zero instead of sorb here. */
sewardje87b4842004-07-10 12:23:30 +000010662 addr = disAMode ( &alen, /*sorb*/ 0, delta, dis_buf );
10663 delta += alen;
sewardj940e8c92004-07-11 16:53:24 +000010664 putIReg(sz, gregOfRM(modrm), mkexpr(addr));
sewardje05c42c2004-07-08 20:25:10 +000010665 DIP("lea%c %s, %s\n", nameISize(sz), dis_buf,
10666 nameIReg(sz,gregOfRM(modrm)));
10667 break;
sewardje05c42c2004-07-08 20:25:10 +000010668
sewardj063f02f2004-10-20 12:36:12 +000010669 case 0x8C: /* MOV Sw,Ew -- MOV from a SEGMENT REGISTER */
10670 delta = dis_mov_Sw_Ew(sorb, sz, delta);
10671 break;
10672
sewardj7df596b2004-12-06 14:29:12 +000010673 case 0x8E: /* MOV Ew,Sw -- MOV to a SEGMENT REGISTER */
10674 delta = dis_mov_Ew_Sw(sorb, delta);
10675 break;
10676
sewardj43852812004-10-16 23:10:08 +000010677 case 0xA0: /* MOV Ob,AL */
10678 sz = 1;
10679 /* Fall through ... */
sewardj0c12ea82004-07-12 08:18:16 +000010680 case 0xA1: /* MOV Ov,eAX */
10681 d32 = getUDisp32(delta); delta += 4;
10682 ty = szToITy(sz);
10683 addr = newTemp(Ity_I32);
10684 assign( addr, handleSegOverride(sorb, mkU32(d32)) );
10685 putIReg(sz, R_EAX, loadLE(ty, mkexpr(addr)));
10686 DIP("mov%c %s0x%x, %s\n", nameISize(sz), sorbTxt(sorb),
10687 d32, nameIReg(sz,R_EAX));
10688 break;
10689
sewardj180e8b32004-07-29 01:40:11 +000010690 case 0xA2: /* MOV Ob,AL */
10691 sz = 1;
10692 /* Fall through ... */
sewardj750f4072004-07-26 22:39:11 +000010693 case 0xA3: /* MOV eAX,Ov */
10694 d32 = getUDisp32(delta); delta += 4;
10695 ty = szToITy(sz);
10696 addr = newTemp(Ity_I32);
10697 assign( addr, handleSegOverride(sorb, mkU32(d32)) );
10698 storeLE( mkexpr(addr), getIReg(sz,R_EAX) );
10699 DIP("mov%c %s, %s0x%x\n", nameISize(sz), nameIReg(sz,R_EAX),
10700 sorbTxt(sorb), d32);
10701 break;
sewardje87b4842004-07-10 12:23:30 +000010702
sewardjc2ac51e2004-07-12 01:03:26 +000010703 case 0xB0: /* MOV imm,AL */
10704 case 0xB1: /* MOV imm,CL */
10705 case 0xB2: /* MOV imm,DL */
10706 case 0xB3: /* MOV imm,BL */
10707 case 0xB4: /* MOV imm,AH */
10708 case 0xB5: /* MOV imm,CH */
10709 case 0xB6: /* MOV imm,DH */
10710 case 0xB7: /* MOV imm,BH */
10711 d32 = getIByte(delta); delta += 1;
10712 putIReg(1, opc-0xB0, mkU8(d32));
10713 DIP("movb $0x%x,%s\n", d32, nameIReg(1,opc-0xB0));
10714 break;
sewardj7ed22952004-07-29 00:09:58 +000010715
sewardje87b4842004-07-10 12:23:30 +000010716 case 0xB8: /* MOV imm,eAX */
10717 case 0xB9: /* MOV imm,eCX */
10718 case 0xBA: /* MOV imm,eDX */
10719 case 0xBB: /* MOV imm,eBX */
10720 case 0xBC: /* MOV imm,eSP */
10721 case 0xBD: /* MOV imm,eBP */
10722 case 0xBE: /* MOV imm,eSI */
10723 case 0xBF: /* MOV imm,eDI */
10724 d32 = getUDisp(sz,delta); delta += sz;
10725 putIReg(sz, opc-0xB8, mkU(szToITy(sz), d32));
10726 DIP("mov%c $0x%x,%s\n", nameISize(sz), d32, nameIReg(sz,opc-0xB8));
10727 break;
10728
sewardj77b86be2004-07-11 13:28:24 +000010729 case 0xC6: /* MOV Ib,Eb */
10730 sz = 1;
10731 goto do_Mov_I_E;
sewardje87b4842004-07-10 12:23:30 +000010732 case 0xC7: /* MOV Iv,Ev */
10733 goto do_Mov_I_E;
10734
10735 do_Mov_I_E:
10736 modrm = getIByte(delta);
10737 if (epartIsReg(modrm)) {
10738 delta++; /* mod/rm byte */
10739 d32 = getUDisp(sz,delta); delta += sz;
sewardj5bd4d162004-11-10 13:02:48 +000010740 putIReg(sz, eregOfRM(modrm), mkU(szToITy(sz), d32));
sewardje87b4842004-07-10 12:23:30 +000010741 DIP("mov%c $0x%x, %s\n", nameISize(sz), d32,
10742 nameIReg(sz,eregOfRM(modrm)));
sewardje87b4842004-07-10 12:23:30 +000010743 } else {
10744 addr = disAMode ( &alen, sorb, delta, dis_buf );
10745 delta += alen;
10746 d32 = getUDisp(sz,delta); delta += sz;
sewardj5bd4d162004-11-10 13:02:48 +000010747 storeLE(mkexpr(addr), mkU(szToITy(sz), d32));
sewardje87b4842004-07-10 12:23:30 +000010748 DIP("mov%c $0x%x, %s\n", nameISize(sz), d32, dis_buf);
10749 }
10750 break;
10751
sewardj1813dbe2004-07-28 17:09:04 +000010752 /* ------------------------ opl imm, A ----------------- */
10753
10754 case 0x04: /* ADD Ib, AL */
sewardja718d5d2005-04-03 14:59:54 +000010755 delta = dis_op_imm_A( 1, False, Iop_Add8, True, delta, "add" );
sewardj1813dbe2004-07-28 17:09:04 +000010756 break;
sewardj77b86be2004-07-11 13:28:24 +000010757 case 0x05: /* ADD Iv, eAX */
sewardja718d5d2005-04-03 14:59:54 +000010758 delta = dis_op_imm_A( sz, False, Iop_Add8, True, delta, "add" );
sewardj77b86be2004-07-11 13:28:24 +000010759 break;
10760
sewardj940e8c92004-07-11 16:53:24 +000010761 case 0x0C: /* OR Ib, AL */
sewardja718d5d2005-04-03 14:59:54 +000010762 delta = dis_op_imm_A( 1, False, Iop_Or8, True, delta, "or" );
sewardj940e8c92004-07-11 16:53:24 +000010763 break;
sewardj82292882004-07-27 00:15:59 +000010764 case 0x0D: /* OR Iv, eAX */
sewardja718d5d2005-04-03 14:59:54 +000010765 delta = dis_op_imm_A( sz, False, Iop_Or8, True, delta, "or" );
sewardj82292882004-07-27 00:15:59 +000010766 break;
10767
sewardjc9a65702004-07-07 16:32:57 +000010768//-- case 0x14: /* ADC Ib, AL */
sewardj77b86be2004-07-11 13:28:24 +000010769//-- delta = dis_op_imm_A( 1, ADC, True, delta, "adc" );
sewardjc9a65702004-07-07 16:32:57 +000010770//-- break;
sewardja718d5d2005-04-03 14:59:54 +000010771 case 0x15: /* ADC Iv, eAX */
10772 delta = dis_op_imm_A( sz, True, Iop_Add8, True, delta, "adc" );
10773 break;
10774
sewardjc9a65702004-07-07 16:32:57 +000010775//-- case 0x1C: /* SBB Ib, AL */
sewardj77b86be2004-07-11 13:28:24 +000010776//-- delta = dis_op_imm_A( 1, SBB, True, delta, "sbb" );
sewardjc9a65702004-07-07 16:32:57 +000010777//-- break;
10778//-- case 0x1D: /* SBB Iv, eAX */
sewardj77b86be2004-07-11 13:28:24 +000010779//-- delta = dis_op_imm_A( sz, SBB, True, delta, "sbb" );
sewardjc9a65702004-07-07 16:32:57 +000010780//-- break;
10781//--
sewardj940e8c92004-07-11 16:53:24 +000010782 case 0x24: /* AND Ib, AL */
sewardja718d5d2005-04-03 14:59:54 +000010783 delta = dis_op_imm_A( 1, False, Iop_And8, True, delta, "and" );
sewardj940e8c92004-07-11 16:53:24 +000010784 break;
sewardjc2ac51e2004-07-12 01:03:26 +000010785 case 0x25: /* AND Iv, eAX */
sewardja718d5d2005-04-03 14:59:54 +000010786 delta = dis_op_imm_A( sz, False, Iop_And8, True, delta, "and" );
sewardjc2ac51e2004-07-12 01:03:26 +000010787 break;
sewardj0611d802004-07-11 02:37:54 +000010788
10789 case 0x2C: /* SUB Ib, AL */
sewardja718d5d2005-04-03 14:59:54 +000010790 delta = dis_op_imm_A( 1, False, Iop_Sub8, True, delta, "sub" );
sewardj0611d802004-07-11 02:37:54 +000010791 break;
sewardj68511542004-07-28 00:15:44 +000010792 case 0x2D: /* SUB Iv, eAX */
sewardja718d5d2005-04-03 14:59:54 +000010793 delta = dis_op_imm_A( sz, False, Iop_Sub8, True, delta, "sub" );
sewardj68511542004-07-28 00:15:44 +000010794 break;
10795
sewardj1c6f9912004-09-07 10:15:24 +000010796 case 0x34: /* XOR Ib, AL */
sewardja718d5d2005-04-03 14:59:54 +000010797 delta = dis_op_imm_A( 1, False, Iop_Xor8, True, delta, "xor" );
sewardj1c6f9912004-09-07 10:15:24 +000010798 break;
sewardjcaca9d02004-07-28 07:11:32 +000010799 case 0x35: /* XOR Iv, eAX */
sewardja718d5d2005-04-03 14:59:54 +000010800 delta = dis_op_imm_A( sz, False, Iop_Xor8, True, delta, "xor" );
sewardjcaca9d02004-07-28 07:11:32 +000010801 break;
10802
sewardj0611d802004-07-11 02:37:54 +000010803 case 0x3C: /* CMP Ib, AL */
sewardja718d5d2005-04-03 14:59:54 +000010804 delta = dis_op_imm_A( 1, False, Iop_Sub8, False, delta, "cmp" );
sewardj0611d802004-07-11 02:37:54 +000010805 break;
10806 case 0x3D: /* CMP Iv, eAX */
sewardja718d5d2005-04-03 14:59:54 +000010807 delta = dis_op_imm_A( sz, False, Iop_Sub8, False, delta, "cmp" );
sewardj0611d802004-07-11 02:37:54 +000010808 break;
10809
sewardj77b86be2004-07-11 13:28:24 +000010810 case 0xA8: /* TEST Ib, AL */
sewardja718d5d2005-04-03 14:59:54 +000010811 delta = dis_op_imm_A( 1, False, Iop_And8, False, delta, "test" );
sewardj77b86be2004-07-11 13:28:24 +000010812 break;
sewardjc2ac51e2004-07-12 01:03:26 +000010813 case 0xA9: /* TEST Iv, eAX */
sewardja718d5d2005-04-03 14:59:54 +000010814 delta = dis_op_imm_A( sz, False, Iop_And8, False, delta, "test" );
sewardjc2ac51e2004-07-12 01:03:26 +000010815 break;
10816
sewardj1c6f9912004-09-07 10:15:24 +000010817 /* ------------------------ opl Ev, Gv ----------------- */
10818
sewardj89cd0932004-09-08 18:23:25 +000010819 case 0x02: /* ADD Eb,Gb */
10820 delta = dis_op2_E_G ( sorb, False, Iop_Add8, True, 1, delta, "add" );
10821 break;
sewardj9334b0f2004-07-10 22:43:54 +000010822 case 0x03: /* ADD Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +000010823 delta = dis_op2_E_G ( sorb, False, Iop_Add8, True, sz, delta, "add" );
sewardj9334b0f2004-07-10 22:43:54 +000010824 break;
10825
sewardj7ed22952004-07-29 00:09:58 +000010826 case 0x0A: /* OR Eb,Gb */
sewardj180e8b32004-07-29 01:40:11 +000010827 delta = dis_op2_E_G ( sorb, False, Iop_Or8, True, 1, delta, "or" );
sewardj7ed22952004-07-29 00:09:58 +000010828 break;
sewardjc2ac51e2004-07-12 01:03:26 +000010829 case 0x0B: /* OR Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +000010830 delta = dis_op2_E_G ( sorb, False, Iop_Or8, True, sz, delta, "or" );
sewardjc2ac51e2004-07-12 01:03:26 +000010831 break;
sewardjc9a65702004-07-07 16:32:57 +000010832//--
10833//-- case 0x12: /* ADC Eb,Gb */
sewardj180e8b32004-07-29 01:40:11 +000010834//-- delta = dis_op2_E_G ( sorb, True, ADC, True, 1, delta, "adc" );
sewardjc9a65702004-07-07 16:32:57 +000010835//-- break;
sewardjc4eaff32004-09-10 20:25:11 +000010836 case 0x13: /* ADC Ev,Gv */
10837 delta = dis_op2_E_G ( sorb, True, Iop_Add8, True, sz, delta, "adc" );
10838 break;
10839
sewardjc9a65702004-07-07 16:32:57 +000010840//-- case 0x1A: /* SBB Eb,Gb */
sewardj180e8b32004-07-29 01:40:11 +000010841//-- delta = dis_op2_E_G ( sorb, True, SBB, True, 1, delta, "sbb" );
sewardjc9a65702004-07-07 16:32:57 +000010842//-- break;
sewardj180e8b32004-07-29 01:40:11 +000010843 case 0x1B: /* SBB Ev,Gv */
10844 delta = dis_op2_E_G ( sorb, True, Iop_Sub8, True, sz, delta, "sbb" );
sewardj940e8c92004-07-11 16:53:24 +000010845 break;
10846
sewardj1c6f9912004-09-07 10:15:24 +000010847 case 0x22: /* AND Eb,Gb */
10848 delta = dis_op2_E_G ( sorb, False, Iop_And8, True, 1, delta, "and" );
10849 break;
sewardj180e8b32004-07-29 01:40:11 +000010850 case 0x23: /* AND Ev,Gv */
10851 delta = dis_op2_E_G ( sorb, False, Iop_And8, True, sz, delta, "and" );
10852 break;
10853
10854 case 0x2A: /* SUB Eb,Gb */
10855 delta = dis_op2_E_G ( sorb, False, Iop_Sub8, True, 1, delta, "sub" );
10856 break;
sewardj0611d802004-07-11 02:37:54 +000010857 case 0x2B: /* SUB Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +000010858 delta = dis_op2_E_G ( sorb, False, Iop_Sub8, True, sz, delta, "sub" );
sewardj0611d802004-07-11 02:37:54 +000010859 break;
sewardjc2ac51e2004-07-12 01:03:26 +000010860
10861 case 0x32: /* XOR Eb,Gb */
sewardj180e8b32004-07-29 01:40:11 +000010862 delta = dis_op2_E_G ( sorb, False, Iop_Xor8, True, 1, delta, "xor" );
sewardjc2ac51e2004-07-12 01:03:26 +000010863 break;
sewardj1813dbe2004-07-28 17:09:04 +000010864 case 0x33: /* XOR Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +000010865 delta = dis_op2_E_G ( sorb, False, Iop_Xor8, True, sz, delta, "xor" );
sewardj1813dbe2004-07-28 17:09:04 +000010866 break;
10867
sewardjc2ac51e2004-07-12 01:03:26 +000010868 case 0x3A: /* CMP Eb,Gb */
sewardj180e8b32004-07-29 01:40:11 +000010869 delta = dis_op2_E_G ( sorb, False, Iop_Sub8, False, 1, delta, "cmp" );
sewardjc2ac51e2004-07-12 01:03:26 +000010870 break;
sewardje90ad6a2004-07-10 19:02:10 +000010871 case 0x3B: /* CMP Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +000010872 delta = dis_op2_E_G ( sorb, False, Iop_Sub8, False, sz, delta, "cmp" );
sewardje90ad6a2004-07-10 19:02:10 +000010873 break;
10874
sewardj0611d802004-07-11 02:37:54 +000010875 case 0x84: /* TEST Eb,Gb */
sewardj180e8b32004-07-29 01:40:11 +000010876 delta = dis_op2_E_G ( sorb, False, Iop_And8, False, 1, delta, "test" );
sewardj0611d802004-07-11 02:37:54 +000010877 break;
sewardje05c42c2004-07-08 20:25:10 +000010878 case 0x85: /* TEST Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +000010879 delta = dis_op2_E_G ( sorb, False, Iop_And8, False, sz, delta, "test" );
sewardje05c42c2004-07-08 20:25:10 +000010880 break;
10881
sewardj180e8b32004-07-29 01:40:11 +000010882 /* ------------------------ opl Gv, Ev ----------------- */
10883
10884 case 0x00: /* ADD Gb,Eb */
10885 delta = dis_op2_G_E ( sorb, False, Iop_Add8, True, 1, delta, "add" );
10886 break;
sewardje05c42c2004-07-08 20:25:10 +000010887 case 0x01: /* ADD Gv,Ev */
sewardjcaca9d02004-07-28 07:11:32 +000010888 delta = dis_op2_G_E ( sorb, False, Iop_Add8, True, sz, delta, "add" );
sewardje05c42c2004-07-08 20:25:10 +000010889 break;
10890
sewardj940e8c92004-07-11 16:53:24 +000010891 case 0x08: /* OR Gb,Eb */
sewardjcaca9d02004-07-28 07:11:32 +000010892 delta = dis_op2_G_E ( sorb, False, Iop_Or8, True, 1, delta, "or" );
sewardj940e8c92004-07-11 16:53:24 +000010893 break;
sewardj9334b0f2004-07-10 22:43:54 +000010894 case 0x09: /* OR Gv,Ev */
sewardjcaca9d02004-07-28 07:11:32 +000010895 delta = dis_op2_G_E ( sorb, False, Iop_Or8, True, sz, delta, "or" );
sewardj9334b0f2004-07-10 22:43:54 +000010896 break;
10897
sewardja2384712004-07-29 14:36:40 +000010898 case 0x10: /* ADC Gb,Eb */
10899 delta = dis_op2_G_E ( sorb, True, Iop_Add8, True, 1, delta, "adc" );
10900 break;
sewardjcaca9d02004-07-28 07:11:32 +000010901 case 0x11: /* ADC Gv,Ev */
10902 delta = dis_op2_G_E ( sorb, True, Iop_Add8, True, sz, delta, "adc" );
10903 break;
10904
sewardja2384712004-07-29 14:36:40 +000010905 case 0x18: /* SBB Gb,Eb */
10906 delta = dis_op2_G_E ( sorb, True, Iop_Sub8, True, 1, delta, "sbb" );
10907 break;
sewardjcaca9d02004-07-28 07:11:32 +000010908 case 0x19: /* SBB Gv,Ev */
10909 delta = dis_op2_G_E ( sorb, True, Iop_Sub8, True, sz, delta, "sbb" );
10910 break;
10911
sewardja2384712004-07-29 14:36:40 +000010912 case 0x20: /* AND Gb,Eb */
10913 delta = dis_op2_G_E ( sorb, False, Iop_And8, True, 1, delta, "and" );
10914 break;
sewardj0611d802004-07-11 02:37:54 +000010915 case 0x21: /* AND Gv,Ev */
sewardjcaca9d02004-07-28 07:11:32 +000010916 delta = dis_op2_G_E ( sorb, False, Iop_And8, True, sz, delta, "and" );
sewardj0611d802004-07-11 02:37:54 +000010917 break;
10918
sewardj180e8b32004-07-29 01:40:11 +000010919 case 0x28: /* SUB Gb,Eb */
10920 delta = dis_op2_G_E ( sorb, False, Iop_Sub8, True, 1, delta, "sub" );
10921 break;
sewardje05c42c2004-07-08 20:25:10 +000010922 case 0x29: /* SUB Gv,Ev */
sewardjcaca9d02004-07-28 07:11:32 +000010923 delta = dis_op2_G_E ( sorb, False, Iop_Sub8, True, sz, delta, "sub" );
sewardje05c42c2004-07-08 20:25:10 +000010924 break;
10925
sewardjc2ac51e2004-07-12 01:03:26 +000010926 case 0x30: /* XOR Gb,Eb */
sewardjcaca9d02004-07-28 07:11:32 +000010927 delta = dis_op2_G_E ( sorb, False, Iop_Xor8, True, 1, delta, "xor" );
sewardjc2ac51e2004-07-12 01:03:26 +000010928 break;
sewardje87b4842004-07-10 12:23:30 +000010929 case 0x31: /* XOR Gv,Ev */
sewardjcaca9d02004-07-28 07:11:32 +000010930 delta = dis_op2_G_E ( sorb, False, Iop_Xor8, True, sz, delta, "xor" );
sewardje87b4842004-07-10 12:23:30 +000010931 break;
10932
sewardj0611d802004-07-11 02:37:54 +000010933 case 0x38: /* CMP Gb,Eb */
sewardjcaca9d02004-07-28 07:11:32 +000010934 delta = dis_op2_G_E ( sorb, False, Iop_Sub8, False, 1, delta, "cmp" );
sewardj0611d802004-07-11 02:37:54 +000010935 break;
sewardje90ad6a2004-07-10 19:02:10 +000010936 case 0x39: /* CMP Gv,Ev */
sewardjcaca9d02004-07-28 07:11:32 +000010937 delta = dis_op2_G_E ( sorb, False, Iop_Sub8, False, sz, delta, "cmp" );
sewardje90ad6a2004-07-10 19:02:10 +000010938 break;
10939
sewardj9334b0f2004-07-10 22:43:54 +000010940 /* ------------------------ POP ------------------------ */
10941
10942 case 0x58: /* POP eAX */
10943 case 0x59: /* POP eCX */
10944 case 0x5A: /* POP eDX */
10945 case 0x5B: /* POP eBX */
10946 case 0x5D: /* POP eBP */
10947 case 0x5E: /* POP eSI */
10948 case 0x5F: /* POP eDI */
10949 case 0x5C: /* POP eSP */
10950 vassert(sz == 2 || sz == 4);
10951 t1 = newTemp(szToITy(sz)); t2 = newTemp(Ity_I32);
10952 assign(t2, getIReg(4, R_ESP));
10953 assign(t1, loadLE(szToITy(sz),mkexpr(t2)));
10954 putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t2), mkU32(sz)));
10955 putIReg(sz, opc-0x58, mkexpr(t1));
10956 DIP("pop%c %s\n", nameISize(sz), nameIReg(sz,opc-0x58));
10957 break;
10958
sewardja2384712004-07-29 14:36:40 +000010959 case 0x9D: /* POPF */
10960 vassert(sz == 2 || sz == 4);
10961 vassert(sz == 4); // until we know a sz==2 test case exists
10962 t1 = newTemp(Ity_I32); t2 = newTemp(Ity_I32);
10963 assign(t2, getIReg(4, R_ESP));
sewardjc22a6fd2004-07-29 23:41:47 +000010964 assign(t1, widenUto32(loadLE(szToITy(sz),mkexpr(t2))));
sewardja2384712004-07-29 14:36:40 +000010965 putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t2), mkU32(sz)));
sewardj98169c52004-10-24 13:11:39 +000010966 /* t1 is the flag word. Mask out everything except OSZACP and
sewardj2a9ad022004-11-25 02:46:58 +000010967 set the flags thunk to X86G_CC_OP_COPY. */
10968 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
sewardj2a2ba8b2004-11-08 13:14:06 +000010969 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
10970 stmt( IRStmt_Put( OFFB_CC_DEP1,
sewardj5bd4d162004-11-10 13:02:48 +000010971 binop(Iop_And32,
10972 mkexpr(t1),
sewardj2a9ad022004-11-25 02:46:58 +000010973 mkU32( X86G_CC_MASK_C | X86G_CC_MASK_P
10974 | X86G_CC_MASK_A | X86G_CC_MASK_Z
10975 | X86G_CC_MASK_S| X86G_CC_MASK_O )
sewardj5bd4d162004-11-10 13:02:48 +000010976 )
10977 )
10978 );
sewardja3b7e3a2005-04-05 01:54:19 +000010979 /* Set NDEP even though it isn't used. This makes redundant-PUT
10980 elimination of previous stores to this field work better. */
10981 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardja2384712004-07-29 14:36:40 +000010982
10983 /* Also need to set the D flag, which is held in bit 10 of t1.
10984 If zero, put 1 in OFFB_DFLAG, else -1 in OFFB_DFLAG. */
10985 stmt( IRStmt_Put(
10986 OFFB_DFLAG,
10987 IRExpr_Mux0X(
10988 unop(Iop_32to8,
10989 binop(Iop_And32,
10990 binop(Iop_Shr32, mkexpr(t1), mkU8(10)),
10991 mkU32(1))),
10992 mkU32(1),
10993 mkU32(0xFFFFFFFF)))
10994 );
10995
sewardj6d269842005-08-06 11:45:02 +000010996 /* Set the ID flag */
sewardj006a6a22004-10-26 00:50:52 +000010997 stmt( IRStmt_Put(
10998 OFFB_IDFLAG,
10999 IRExpr_Mux0X(
11000 unop(Iop_32to8,
11001 binop(Iop_And32,
11002 binop(Iop_Shr32, mkexpr(t1), mkU8(21)),
11003 mkU32(1))),
11004 mkU32(0),
11005 mkU32(1)))
11006 );
11007
sewardj6d269842005-08-06 11:45:02 +000011008 /* And set the AC flag. If setting it 1 to, emit an emulation
11009 warning. */
11010 stmt( IRStmt_Put(
11011 OFFB_ACFLAG,
11012 IRExpr_Mux0X(
11013 unop(Iop_32to8,
11014 binop(Iop_And32,
11015 binop(Iop_Shr32, mkexpr(t1), mkU8(18)),
11016 mkU32(1))),
11017 mkU32(0),
11018 mkU32(1)))
11019 );
11020
11021 put_emwarn( mkU32(EmWarn_X86_acFlag) );
11022 stmt(
11023 IRStmt_Exit(
11024 binop( Iop_CmpNE32,
11025 binop(Iop_And32, mkexpr(t1), mkU32(1<<18)),
11026 mkU32(0) ),
11027 Ijk_EmWarn,
11028 IRConst_U32( ((Addr32)guest_EIP_bbstart)+delta)
11029 )
11030 );
11031
sewardja2384712004-07-29 14:36:40 +000011032 DIP("popf%c\n", nameISize(sz));
11033 break;
11034
sewardjbbdc6222004-12-15 18:43:39 +000011035 case 0x61: /* POPA */
11036 /* This is almost certainly wrong for sz==2. So ... */
11037 if (sz != 4) goto decode_failure;
11038
11039 /* t5 is the old %ESP value. */
11040 t5 = newTemp(Ity_I32);
11041 assign( t5, getIReg(4, R_ESP) );
11042
11043 /* Reload all the registers, except %esp. */
11044 putIReg(4,R_EAX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(28)) ));
11045 putIReg(4,R_ECX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(24)) ));
11046 putIReg(4,R_EDX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(20)) ));
11047 putIReg(4,R_EBX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(16)) ));
11048 /* ignore saved %ESP */
11049 putIReg(4,R_EBP, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32( 8)) ));
11050 putIReg(4,R_ESI, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32( 4)) ));
11051 putIReg(4,R_EDI, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32( 0)) ));
11052
11053 /* and move %ESP back up */
11054 putIReg( 4, R_ESP, binop(Iop_Add32, mkexpr(t5), mkU32(8*4)) );
11055
sewardja3d1a662005-03-29 21:33:11 +000011056 DIP("popa%c\n", nameISize(sz));
sewardjbbdc6222004-12-15 18:43:39 +000011057 break;
sewardjfeeb8a82004-11-30 12:30:11 +000011058
11059 case 0x8F: /* POPL/POPW m32 */
11060 { Int len;
11061 UChar rm = getIByte(delta);
11062
11063 /* make sure this instruction is correct POP */
11064 vassert(!epartIsReg(rm) && (gregOfRM(rm) == 0));
11065 /* and has correct size */
11066 vassert(sz == 4);
11067
11068 t1 = newTemp(Ity_I32); t3 = newTemp(Ity_I32);
11069 /* set t1 to ESP: t1 = ESP */
11070 assign( t1, getIReg(4, R_ESP) );
11071 /* load M[ESP] to virtual register t3: t3 = M[t1] */
11072 assign( t3, loadLE(Ity_I32, mkexpr(t1)) );
11073
11074 /* increase ESP; must be done before the STORE. Intel manual says:
11075 If the ESP register is used as a base register for addressing
11076 a destination operand in memory, the POP instruction computes
11077 the effective address of the operand after it increments the
11078 ESP register.
11079 */
11080 putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t1), mkU32(sz)) );
11081
11082 /* resolve MODR/M */
11083 addr = disAMode ( &len, sorb, delta, dis_buf);
11084 storeLE( mkexpr(addr), mkexpr(t3) );
11085
11086 DIP("popl %s\n", dis_buf);
11087
11088 delta += len;
11089 break;
11090 }
11091
sewardjc9a65702004-07-07 16:32:57 +000011092//-- case 0x1F: /* POP %DS */
11093//-- dis_pop_segreg( cb, R_DS, sz ); break;
11094//-- case 0x07: /* POP %ES */
11095//-- dis_pop_segreg( cb, R_ES, sz ); break;
11096//-- case 0x17: /* POP %SS */
11097//-- dis_pop_segreg( cb, R_SS, sz ); break;
sewardjd1061ab2004-07-08 01:45:30 +000011098
11099 /* ------------------------ PUSH ----------------------- */
11100
11101 case 0x50: /* PUSH eAX */
11102 case 0x51: /* PUSH eCX */
11103 case 0x52: /* PUSH eDX */
11104 case 0x53: /* PUSH eBX */
11105 case 0x55: /* PUSH eBP */
11106 case 0x56: /* PUSH eSI */
11107 case 0x57: /* PUSH eDI */
11108 case 0x54: /* PUSH eSP */
11109 /* This is the Right Way, in that the value to be pushed is
11110 established before %esp is changed, so that pushl %esp
11111 correctly pushes the old value. */
11112 vassert(sz == 2 || sz == 4);
11113 ty = sz==2 ? Ity_I16 : Ity_I32;
sewardj883b00b2004-09-11 09:30:24 +000011114 t1 = newTemp(ty); t2 = newTemp(Ity_I32);
sewardj41f43bc2004-07-08 14:23:22 +000011115 assign(t1, getIReg(sz, opc-0x50));
11116 assign(t2, binop(Iop_Sub32, getIReg(4, R_ESP), mkU32(sz)));
11117 putIReg(4, R_ESP, mkexpr(t2) );
11118 storeLE(mkexpr(t2),mkexpr(t1));
sewardjd1061ab2004-07-08 01:45:30 +000011119 DIP("push%c %s\n", nameISize(sz), nameIReg(sz,opc-0x50));
11120 break;
11121
11122
sewardj0c12ea82004-07-12 08:18:16 +000011123 case 0x68: /* PUSH Iv */
11124 d32 = getUDisp(sz,delta); delta += sz;
11125 goto do_push_I;
sewardj741153c2004-07-25 23:39:13 +000011126 case 0x6A: /* PUSH Ib, sign-extended to sz */
11127 d32 = getSDisp8(delta); delta += 1;
11128 goto do_push_I;
sewardj0c12ea82004-07-12 08:18:16 +000011129 do_push_I:
11130 ty = szToITy(sz);
11131 t1 = newTemp(Ity_I32); t2 = newTemp(ty);
11132 assign( t1, binop(Iop_Sub32,getIReg(4,R_ESP),mkU32(sz)) );
11133 putIReg(4, R_ESP, mkexpr(t1) );
11134 storeLE( mkexpr(t1), mkU(ty,d32) );
11135 DIP("push%c $0x%x\n", nameISize(sz), d32);
11136 break;
11137
sewardja2384712004-07-29 14:36:40 +000011138 case 0x9C: /* PUSHF */ {
sewardja2384712004-07-29 14:36:40 +000011139 vassert(sz == 2 || sz == 4);
11140 vassert(sz == 4); // wait for sz==2 test case
11141
11142 t1 = newTemp(Ity_I32);
11143 assign( t1, binop(Iop_Sub32,getIReg(4,R_ESP),mkU32(sz)) );
11144 putIReg(4, R_ESP, mkexpr(t1) );
11145
sewardjbc210942005-07-21 10:07:13 +000011146 /* Calculate OSZACP, and patch in fixed fields as per
11147 Intel docs.
11148 - bit 1 is always 1
11149 - bit 9 is Interrupt Enable (should always be 1 in user mode?)
11150 */
sewardja2384712004-07-29 14:36:40 +000011151 t2 = newTemp(Ity_I32);
sewardjbc210942005-07-21 10:07:13 +000011152 assign( t2, binop(Iop_Or32,
11153 mk_x86g_calculate_eflags_all(),
11154 mkU32( (1<<1)|(1<<9) ) ));
sewardja2384712004-07-29 14:36:40 +000011155
sewardjf9c74fe2004-12-16 02:54:54 +000011156 /* Patch in the D flag. This can simply be a copy of bit 10 of
11157 baseBlock[OFFB_DFLAG]. */
sewardja2384712004-07-29 14:36:40 +000011158 t3 = newTemp(Ity_I32);
11159 assign( t3, binop(Iop_Or32,
11160 mkexpr(t2),
11161 binop(Iop_And32,
sewardjf9c74fe2004-12-16 02:54:54 +000011162 IRExpr_Get(OFFB_DFLAG,Ity_I32),
sewardj5bd4d162004-11-10 13:02:48 +000011163 mkU32(1<<10)))
sewardja2384712004-07-29 14:36:40 +000011164 );
sewardj006a6a22004-10-26 00:50:52 +000011165
11166 /* And patch in the ID flag. */
11167 t4 = newTemp(Ity_I32);
11168 assign( t4, binop(Iop_Or32,
11169 mkexpr(t3),
11170 binop(Iop_And32,
sewardj5bd4d162004-11-10 13:02:48 +000011171 binop(Iop_Shl32, IRExpr_Get(OFFB_IDFLAG,Ity_I32),
sewardj006a6a22004-10-26 00:50:52 +000011172 mkU8(21)),
sewardj5bd4d162004-11-10 13:02:48 +000011173 mkU32(1<<21)))
sewardj006a6a22004-10-26 00:50:52 +000011174 );
11175
sewardj6d269842005-08-06 11:45:02 +000011176 /* And patch in the AC flag. */
11177 t5 = newTemp(Ity_I32);
11178 assign( t5, binop(Iop_Or32,
11179 mkexpr(t4),
11180 binop(Iop_And32,
11181 binop(Iop_Shl32, IRExpr_Get(OFFB_ACFLAG,Ity_I32),
11182 mkU8(18)),
11183 mkU32(1<<18)))
11184 );
11185
sewardja2384712004-07-29 14:36:40 +000011186 /* if sz==2, the stored value needs to be narrowed. */
11187 if (sz == 2)
sewardj6d269842005-08-06 11:45:02 +000011188 storeLE( mkexpr(t1), unop(Iop_32to16,mkexpr(t5)) );
sewardja2384712004-07-29 14:36:40 +000011189 else
sewardj6d269842005-08-06 11:45:02 +000011190 storeLE( mkexpr(t1), mkexpr(t5) );
sewardja2384712004-07-29 14:36:40 +000011191
11192 DIP("pushf%c\n", nameISize(sz));
11193 break;
11194 }
11195
sewardjbbdc6222004-12-15 18:43:39 +000011196 case 0x60: /* PUSHA */
11197 /* This is almost certainly wrong for sz==2. So ... */
11198 if (sz != 4) goto decode_failure;
11199
11200 /* This is the Right Way, in that the value to be pushed is
11201 established before %esp is changed, so that pusha
11202 correctly pushes the old %esp value. New value of %esp is
11203 pushed at start. */
11204 /* t0 is the %ESP value we're going to push. */
11205 t0 = newTemp(Ity_I32);
11206 assign( t0, getIReg(4, R_ESP) );
11207
11208 /* t5 will be the new %ESP value. */
11209 t5 = newTemp(Ity_I32);
11210 assign( t5, binop(Iop_Sub32, mkexpr(t0), mkU32(8*4)) );
11211
11212 /* Update guest state before prodding memory. */
11213 putIReg(4, R_ESP, mkexpr(t5));
11214
11215 /* Dump all the registers. */
11216 storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(28)), getIReg(4,R_EAX) );
11217 storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(24)), getIReg(4,R_ECX) );
11218 storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(20)), getIReg(4,R_EDX) );
11219 storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(16)), getIReg(4,R_EBX) );
11220 storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(12)), mkexpr(t0) /*esp*/);
11221 storeLE( binop(Iop_Add32,mkexpr(t5),mkU32( 8)), getIReg(4,R_EBP) );
11222 storeLE( binop(Iop_Add32,mkexpr(t5),mkU32( 4)), getIReg(4,R_ESI) );
11223 storeLE( binop(Iop_Add32,mkexpr(t5),mkU32( 0)), getIReg(4,R_EDI) );
11224
11225 DIP("pusha%c\n", nameISize(sz));
11226 break;
11227
11228
sewardjc9a65702004-07-07 16:32:57 +000011229//-- case 0x0E: /* PUSH %CS */
11230//-- dis_push_segreg( cb, R_CS, sz ); break;
11231//-- case 0x1E: /* PUSH %DS */
11232//-- dis_push_segreg( cb, R_DS, sz ); break;
11233//-- case 0x06: /* PUSH %ES */
11234//-- dis_push_segreg( cb, R_ES, sz ); break;
11235//-- case 0x16: /* PUSH %SS */
11236//-- dis_push_segreg( cb, R_SS, sz ); break;
sewardj458a6f82004-08-25 12:46:02 +000011237
11238 /* ------------------------ SCAS et al ----------------- */
11239
11240 case 0xA4: /* MOVS, no REP prefix */
11241 case 0xA5:
11242 dis_string_op( dis_MOVS, ( opc == 0xA4 ? 1 : sz ), "movs", sorb );
11243 break;
11244
sewardj8d4d2232005-01-20 10:47:46 +000011245 case 0xA6: /* CMPSb, no REP prefix */
sewardj33b53542005-03-11 14:00:27 +000011246 case 0xA7:
sewardj8d4d2232005-01-20 10:47:46 +000011247 dis_string_op( dis_CMPS, ( opc == 0xA6 ? 1 : sz ), "cmps", sorb );
11248 break;
sewardj33b53542005-03-11 14:00:27 +000011249
sewardj883b00b2004-09-11 09:30:24 +000011250 case 0xAA: /* STOS, no REP prefix */
sewardj47341042004-09-19 11:55:46 +000011251 case 0xAB:
sewardj883b00b2004-09-11 09:30:24 +000011252 dis_string_op( dis_STOS, ( opc == 0xAA ? 1 : sz ), "stos", sorb );
11253 break;
sewardj33b53542005-03-11 14:00:27 +000011254
sewardj10ca4eb2005-05-30 11:19:54 +000011255 case 0xAC: /* LODS, no REP prefix */
11256 case 0xAD:
11257 dis_string_op( dis_LODS, ( opc == 0xAC ? 1 : sz ), "lods", sorb );
11258 break;
sewardj2d4c3a02004-10-15 00:03:23 +000011259
11260 case 0xAE: /* SCAS, no REP prefix */
11261 case 0xAF:
11262 dis_string_op( dis_SCAS, ( opc == 0xAE ? 1 : sz ), "scas", sorb );
11263 break;
sewardj64e1d652004-07-12 14:00:46 +000011264
11265
11266 case 0xFC: /* CLD */
sewardjeeb9ef82004-07-15 12:39:03 +000011267 stmt( IRStmt_Put( OFFB_DFLAG, mkU32(1)) );
sewardj64e1d652004-07-12 14:00:46 +000011268 DIP("cld\n");
11269 break;
11270
sewardj1813dbe2004-07-28 17:09:04 +000011271 case 0xFD: /* STD */
11272 stmt( IRStmt_Put( OFFB_DFLAG, mkU32(0xFFFFFFFF)) );
11273 DIP("std\n");
11274 break;
11275
sewardjbc210942005-07-21 10:07:13 +000011276 case 0xF8: /* CLC */
11277 case 0xF9: /* STC */
11278 case 0xF5: /* CMC */
11279 t0 = newTemp(Ity_I32);
11280 t1 = newTemp(Ity_I32);
11281 assign( t0, mk_x86g_calculate_eflags_all() );
11282 switch (opc) {
11283 case 0xF8:
11284 assign( t1, binop(Iop_And32, mkexpr(t0),
11285 mkU32(~X86G_CC_MASK_C)));
11286 DIP("clc\n");
11287 break;
11288 case 0xF9:
11289 assign( t1, binop(Iop_Or32, mkexpr(t0),
11290 mkU32(X86G_CC_MASK_C)));
11291 DIP("stc\n");
11292 break;
11293 case 0xF5:
11294 assign( t1, binop(Iop_Xor32, mkexpr(t0),
11295 mkU32(X86G_CC_MASK_C)));
11296 DIP("cmc\n");
11297 break;
11298 default:
11299 vpanic("disInstr(x86)(clc/stc/cmc)");
11300 }
11301 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
11302 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
11303 stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(t1) ));
11304 /* Set NDEP even though it isn't used. This makes redundant-PUT
11305 elimination of previous stores to this field work better. */
11306 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
11307 break;
sewardj82292882004-07-27 00:15:59 +000011308
11309 /* REPNE prefix insn */
11310 case 0xF2: {
sewardj9e6491a2005-07-02 19:24:10 +000011311 Addr32 eip_orig = guest_EIP_bbstart + delta - 1;
sewardj82292882004-07-27 00:15:59 +000011312 vassert(sorb == 0);
11313 abyte = getIByte(delta); delta++;
11314
11315 if (abyte == 0x66) { sz = 2; abyte = getIByte(delta); delta++; }
sewardj9e6491a2005-07-02 19:24:10 +000011316 dres.whatNext = Dis_StopHere;
sewardj82292882004-07-27 00:15:59 +000011317
11318 switch (abyte) {
11319 /* According to the Intel manual, "repne movs" should never occur, but
11320 * in practice it has happened, so allow for it here... */
sewardj180e8b32004-07-29 01:40:11 +000011321 case 0xA4: sz = 1; /* REPNE MOVS<sz> */
sewardjb64821b2004-12-14 10:00:16 +000011322 goto decode_failure;
sewardjc9a65702004-07-07 16:32:57 +000011323//-- case 0xA5:
sewardj5bd4d162004-11-10 13:02:48 +000011324 // dis_REP_op ( CondNZ, dis_MOVS, sz, eip_orig,
11325 // guest_eip_bbstart+delta, "repne movs" );
11326 // break;
sewardjc9a65702004-07-07 16:32:57 +000011327//--
11328//-- case 0xA6: sz = 1; /* REPNE CMPS<sz> */
11329//-- case 0xA7:
11330//-- dis_REP_op ( cb, CondNZ, dis_CMPS, sz, eip_orig, eip, "repne cmps" );
11331//-- break;
11332//--
sewardj82292882004-07-27 00:15:59 +000011333 case 0xAE: sz = 1; /* REPNE SCAS<sz> */
sewardj2d4c3a02004-10-15 00:03:23 +000011334 case 0xAF:
sewardj2a9ad022004-11-25 02:46:58 +000011335 dis_REP_op ( X86CondNZ, dis_SCAS, sz, eip_orig,
sewardj9e6491a2005-07-02 19:24:10 +000011336 guest_EIP_bbstart+delta, "repne scas" );
sewardj82292882004-07-27 00:15:59 +000011337 break;
11338
11339 default:
11340 goto decode_failure;
11341 }
11342 break;
11343 }
sewardj64e1d652004-07-12 14:00:46 +000011344
11345 /* REP/REPE prefix insn (for SCAS and CMPS, 0xF3 means REPE,
11346 for the rest, it means REP) */
11347 case 0xF3: {
sewardj9e6491a2005-07-02 19:24:10 +000011348 Addr32 eip_orig = guest_EIP_bbstart + delta - 1;
sewardj64e1d652004-07-12 14:00:46 +000011349 vassert(sorb == 0);
11350 abyte = getIByte(delta); delta++;
11351
11352 if (abyte == 0x66) { sz = 2; abyte = getIByte(delta); delta++; }
sewardj9e6491a2005-07-02 19:24:10 +000011353 dres.whatNext = Dis_StopHere;
sewardj64e1d652004-07-12 14:00:46 +000011354
11355 switch (abyte) {
11356 case 0xA4: sz = 1; /* REP MOVS<sz> */
11357 case 0xA5:
sewardj2a9ad022004-11-25 02:46:58 +000011358 dis_REP_op ( X86CondAlways, dis_MOVS, sz, eip_orig,
sewardj9e6491a2005-07-02 19:24:10 +000011359 guest_EIP_bbstart+delta, "rep movs" );
sewardj64e1d652004-07-12 14:00:46 +000011360 break;
11361
11362 case 0xA6: sz = 1; /* REPE CMP<sz> */
sewardj2d4c3a02004-10-15 00:03:23 +000011363 case 0xA7:
sewardj2a9ad022004-11-25 02:46:58 +000011364 dis_REP_op ( X86CondZ, dis_CMPS, sz, eip_orig,
sewardj9e6491a2005-07-02 19:24:10 +000011365 guest_EIP_bbstart+delta, "repe cmps" );
sewardj64e1d652004-07-12 14:00:46 +000011366 break;
11367
11368 case 0xAA: sz = 1; /* REP STOS<sz> */
11369 case 0xAB:
sewardj2a9ad022004-11-25 02:46:58 +000011370 dis_REP_op ( X86CondAlways, dis_STOS, sz, eip_orig,
sewardj9e6491a2005-07-02 19:24:10 +000011371 guest_EIP_bbstart+delta, "rep stos" );
sewardj64e1d652004-07-12 14:00:46 +000011372 break;
sewardjc9a65702004-07-07 16:32:57 +000011373//--
11374//-- case 0xAE: sz = 1; /* REPE SCAS<sz> */
11375//-- case 0xAF:
11376//-- dis_REP_op ( cb, CondZ, dis_SCAS, sz, eip_orig, eip, "repe scas" );
11377//-- break;
sewardj43b8df12004-11-26 12:18:51 +000011378
11379 case 0x90: /* REP NOP (PAUSE) */
11380 /* a hint to the P4 re spin-wait loop */
11381 DIP("rep nop (P4 pause)\n");
sewardj7ec59f62005-03-12 16:47:18 +000011382 /* "observe" the hint. The Vex client needs to be careful not
11383 to cause very long delays as a result, though. */
sewardj9e6491a2005-07-02 19:24:10 +000011384 jmp_lit(Ijk_Yield, ((Addr32)guest_EIP_bbstart)+delta);
11385 dres.whatNext = Dis_StopHere;
sewardj43b8df12004-11-26 12:18:51 +000011386 break;
11387
sewardj7d3d3472005-08-12 23:51:31 +000011388 case 0xC3: /* REP RET -- same as normal ret? */
11389 dis_ret(0);
11390 dres.whatNext = Dis_StopHere;
11391 DIP("rep ret\n");
11392 break;
sewardj64e1d652004-07-12 14:00:46 +000011393
11394 default:
11395 goto decode_failure;
11396 }
11397 break;
11398 }
sewardj0611d802004-07-11 02:37:54 +000011399
11400 /* ------------------------ XCHG ----------------------- */
11401
11402 case 0x86: /* XCHG Gb,Eb */
11403 sz = 1;
11404 /* Fall through ... */
11405 case 0x87: /* XCHG Gv,Ev */
11406 modrm = getIByte(delta);
11407 ty = szToITy(sz);
11408 t1 = newTemp(ty); t2 = newTemp(ty);
11409 if (epartIsReg(modrm)) {
sewardj5bd4d162004-11-10 13:02:48 +000011410 assign(t1, getIReg(sz, eregOfRM(modrm)));
11411 assign(t2, getIReg(sz, gregOfRM(modrm)));
11412 putIReg(sz, gregOfRM(modrm), mkexpr(t1));
11413 putIReg(sz, eregOfRM(modrm), mkexpr(t2));
sewardj0611d802004-07-11 02:37:54 +000011414 delta++;
11415 DIP("xchg%c %s, %s\n",
11416 nameISize(sz), nameIReg(sz,gregOfRM(modrm)),
11417 nameIReg(sz,eregOfRM(modrm)));
11418 } else {
sewardj0c12ea82004-07-12 08:18:16 +000011419 addr = disAMode ( &alen, sorb, delta, dis_buf );
sewardj5bd4d162004-11-10 13:02:48 +000011420 assign( t1, loadLE(ty,mkexpr(addr)) );
11421 assign( t2, getIReg(sz,gregOfRM(modrm)) );
11422 storeLE( mkexpr(addr), mkexpr(t2) );
11423 putIReg( sz, gregOfRM(modrm), mkexpr(t1) );
11424 delta += alen;
sewardj0611d802004-07-11 02:37:54 +000011425 DIP("xchg%c %s, %s\n", nameISize(sz),
11426 nameIReg(sz,gregOfRM(modrm)), dis_buf);
sewardj0611d802004-07-11 02:37:54 +000011427 }
11428 break;
sewardje87b4842004-07-10 12:23:30 +000011429
11430 case 0x90: /* XCHG eAX,eAX */
11431 DIP("nop\n");
11432 break;
sewardj64e1d652004-07-12 14:00:46 +000011433 case 0x91: /* XCHG eAX,eCX */
11434 case 0x92: /* XCHG eAX,eDX */
11435 case 0x93: /* XCHG eAX,eBX */
11436 case 0x94: /* XCHG eAX,eSP */
11437 case 0x95: /* XCHG eAX,eBP */
11438 case 0x96: /* XCHG eAX,eSI */
11439 case 0x97: /* XCHG eAX,eDI */
11440 codegen_xchg_eAX_Reg ( sz, opc - 0x90 );
11441 break;
11442
sewardjc9a65702004-07-07 16:32:57 +000011443//-- /* ------------------------ XLAT ----------------------- */
11444//--
11445//-- case 0xD7: /* XLAT */
11446//-- t1 = newTemp(cb); t2 = newTemp(cb);
11447//-- uInstr2(cb, GET, sz, ArchReg, R_EBX, TempReg, t1); /* get eBX */
11448//-- handleSegOverride( cb, sorb, t1 ); /* make t1 DS:eBX */
11449//-- uInstr2(cb, GET, 1, ArchReg, R_AL, TempReg, t2); /* get AL */
11450//-- /* Widen %AL to 32 bits, so it's all defined when we add it. */
11451//-- uInstr1(cb, WIDEN, 4, TempReg, t2);
11452//-- uWiden(cb, 1, False);
11453//-- uInstr2(cb, ADD, sz, TempReg, t2, TempReg, t1); /* add AL to eBX */
11454//-- uInstr2(cb, LOAD, 1, TempReg, t1, TempReg, t2); /* get byte at t1 into t2 */
11455//-- uInstr2(cb, PUT, 1, TempReg, t2, ArchReg, R_AL); /* put byte into AL */
11456//--
11457//-- DIP("xlat%c [ebx]\n", nameISize(sz));
11458//-- break;
11459//--
11460//-- /* ------------------------ IN / OUT ----------------------- */
11461//--
11462//-- case 0xE4: /* IN ib, %al */
11463//-- case 0xE5: /* IN ib, %{e}ax */
11464//-- case 0xEC: /* IN (%dx),%al */
11465//-- case 0xED: /* IN (%dx),%{e}ax */
11466//-- t1 = newTemp(cb);
11467//-- t2 = newTemp(cb);
11468//-- t3 = newTemp(cb);
11469//--
11470//-- uInstr0(cb, CALLM_S, 0);
11471//-- /* operand size? */
11472//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t1);
11473//-- uLiteral(cb, ( opc == 0xE4 || opc == 0xEC ) ? 1 : sz);
11474//-- uInstr1(cb, PUSH, 4, TempReg, t1);
11475//-- /* port number ? */
11476//-- if ( opc == 0xE4 || opc == 0xE5 ) {
11477//-- abyte = getUChar(eip); eip++;
11478//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
11479//-- uLiteral(cb, abyte);
11480//-- }
11481//-- else
11482//-- uInstr2(cb, GET, 4, ArchReg, R_EDX, TempReg, t2);
11483//--
11484//-- uInstr1(cb, PUSH, 4, TempReg, t2);
11485//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_IN));
11486//-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
11487//-- uInstr1(cb, POP, 4, TempReg, t2);
11488//-- uInstr1(cb, CLEAR, 0, Lit16, 4);
11489//-- uInstr0(cb, CALLM_E, 0);
11490//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_EAX);
11491//-- if ( opc == 0xE4 || opc == 0xE5 ) {
11492//-- DIP("in 0x%x, %%eax/%%ax/%%al\n", getUChar(eip-1) );
11493//-- } else {
11494//-- DIP("in (%%dx), %%eax/%%ax/%%al\n");
11495//-- }
11496//-- break;
11497//-- case 0xE6: /* OUT %al,ib */
11498//-- case 0xE7: /* OUT %{e}ax,ib */
11499//-- case 0xEE: /* OUT %al,(%dx) */
11500//-- case 0xEF: /* OUT %{e}ax,(%dx) */
11501//-- t1 = newTemp(cb);
11502//-- t2 = newTemp(cb);
11503//-- t3 = newTemp(cb);
11504//--
11505//-- uInstr0(cb, CALLM_S, 0);
11506//-- /* operand size? */
11507//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t1);
11508//-- uLiteral(cb, ( opc == 0xE6 || opc == 0xEE ) ? 1 : sz);
11509//-- uInstr1(cb, PUSH, 4, TempReg, t1);
11510//-- /* port number ? */
11511//-- if ( opc == 0xE6 || opc == 0xE7 ) {
11512//-- abyte = getUChar(eip); eip++;
11513//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
11514//-- uLiteral(cb, abyte);
11515//-- }
11516//-- else
11517//-- uInstr2(cb, GET, 4, ArchReg, R_EDX, TempReg, t2);
11518//-- uInstr1(cb, PUSH, 4, TempReg, t2);
11519//-- uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, t3);
11520//-- uInstr1(cb, PUSH, 4, TempReg, t3);
11521//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_OUT));
11522//-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
11523//-- uInstr1(cb, CLEAR, 0, Lit16, 12);
11524//-- uInstr0(cb, CALLM_E, 0);
11525//-- if ( opc == 0xE4 || opc == 0xE5 ) {
11526//-- DIP("out %%eax/%%ax/%%al, 0x%x\n", getUChar(eip-1) );
11527//-- } else {
11528//-- DIP("out %%eax/%%ax/%%al, (%%dx)\n");
11529//-- }
11530//-- break;
sewardj0611d802004-07-11 02:37:54 +000011531
11532 /* ------------------------ (Grp1 extensions) ---------- */
11533
11534 case 0x80: /* Grp1 Ib,Eb */
11535 modrm = getIByte(delta);
11536 am_sz = lengthAMode(delta);
11537 sz = 1;
11538 d_sz = 1;
sewardjc2ac51e2004-07-12 01:03:26 +000011539 d32 = getUChar(delta + am_sz);
sewardj0611d802004-07-11 02:37:54 +000011540 delta = dis_Grp1 ( sorb, delta, modrm, am_sz, d_sz, sz, d32 );
11541 break;
sewardje05c42c2004-07-08 20:25:10 +000011542
11543 case 0x81: /* Grp1 Iv,Ev */
11544 modrm = getIByte(delta);
11545 am_sz = lengthAMode(delta);
11546 d_sz = sz;
11547 d32 = getUDisp(d_sz, delta + am_sz);
11548 delta = dis_Grp1 ( sorb, delta, modrm, am_sz, d_sz, sz, d32 );
11549 break;
sewardjd1061ab2004-07-08 01:45:30 +000011550
11551 case 0x83: /* Grp1 Ib,Ev */
11552 modrm = getIByte(delta);
11553 am_sz = lengthAMode(delta);
11554 d_sz = 1;
11555 d32 = getSDisp8(delta + am_sz);
11556 delta = dis_Grp1 ( sorb, delta, modrm, am_sz, d_sz, sz, d32 );
11557 break;
11558
sewardjc2ac51e2004-07-12 01:03:26 +000011559 /* ------------------------ (Grp2 extensions) ---------- */
11560
11561 case 0xC0: /* Grp2 Ib,Eb */
11562 modrm = getIByte(delta);
11563 am_sz = lengthAMode(delta);
11564 d_sz = 1;
sewardj180e8b32004-07-29 01:40:11 +000011565 d32 = getUChar(delta + am_sz);
sewardjc2ac51e2004-07-12 01:03:26 +000011566 sz = 1;
sewardj6d2638e2004-07-15 09:38:27 +000011567 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
11568 mkU8(d32 & 0xFF), NULL );
sewardjc2ac51e2004-07-12 01:03:26 +000011569 break;
sewardje90ad6a2004-07-10 19:02:10 +000011570
11571 case 0xC1: /* Grp2 Ib,Ev */
sewardjc2ac51e2004-07-12 01:03:26 +000011572 modrm = getIByte(delta);
sewardje90ad6a2004-07-10 19:02:10 +000011573 am_sz = lengthAMode(delta);
11574 d_sz = 1;
sewardj180e8b32004-07-29 01:40:11 +000011575 d32 = getUChar(delta + am_sz);
sewardj6d2638e2004-07-15 09:38:27 +000011576 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
11577 mkU8(d32 & 0xFF), NULL );
sewardje90ad6a2004-07-10 19:02:10 +000011578 break;
11579
sewardj180e8b32004-07-29 01:40:11 +000011580 case 0xD0: /* Grp2 1,Eb */
11581 modrm = getIByte(delta);
11582 am_sz = lengthAMode(delta);
11583 d_sz = 0;
11584 d32 = 1;
11585 sz = 1;
11586 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
11587 mkU8(d32), NULL );
11588 break;
sewardjc2ac51e2004-07-12 01:03:26 +000011589
11590 case 0xD1: /* Grp2 1,Ev */
11591 modrm = getUChar(delta);
11592 am_sz = lengthAMode(delta);
11593 d_sz = 0;
11594 d32 = 1;
sewardj6d2638e2004-07-15 09:38:27 +000011595 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
11596 mkU8(d32), NULL );
sewardjc2ac51e2004-07-12 01:03:26 +000011597 break;
11598
sewardj8c7f1ab2004-07-29 20:31:09 +000011599 case 0xD2: /* Grp2 CL,Eb */
11600 modrm = getUChar(delta);
11601 am_sz = lengthAMode(delta);
11602 d_sz = 0;
11603 sz = 1;
11604 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
11605 getIReg(1,R_ECX), "%cl" );
11606 break;
sewardj9334b0f2004-07-10 22:43:54 +000011607
11608 case 0xD3: /* Grp2 CL,Ev */
11609 modrm = getIByte(delta);
11610 am_sz = lengthAMode(delta);
11611 d_sz = 0;
11612 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
sewardj6d2638e2004-07-15 09:38:27 +000011613 getIReg(1,R_ECX), "%cl" );
sewardj9334b0f2004-07-10 22:43:54 +000011614 break;
11615
sewardj940e8c92004-07-11 16:53:24 +000011616 /* ------------------------ (Grp3 extensions) ---------- */
11617
11618 case 0xF6: /* Grp3 Eb */
11619 delta = dis_Grp3 ( sorb, 1, delta );
11620 break;
11621 case 0xF7: /* Grp3 Ev */
11622 delta = dis_Grp3 ( sorb, sz, delta );
11623 break;
11624
sewardjc2ac51e2004-07-12 01:03:26 +000011625 /* ------------------------ (Grp4 extensions) ---------- */
11626
11627 case 0xFE: /* Grp4 Eb */
11628 delta = dis_Grp4 ( sorb, delta );
11629 break;
sewardj0611d802004-07-11 02:37:54 +000011630
11631 /* ------------------------ (Grp5 extensions) ---------- */
11632
11633 case 0xFF: /* Grp5 Ev */
sewardj9e6491a2005-07-02 19:24:10 +000011634 delta = dis_Grp5 ( sorb, sz, delta, &dres );
sewardj0611d802004-07-11 02:37:54 +000011635 break;
sewardje87b4842004-07-10 12:23:30 +000011636
11637 /* ------------------------ Escapes to 2-byte opcodes -- */
11638
11639 case 0x0F: {
11640 opc = getIByte(delta); delta++;
11641 switch (opc) {
11642
sewardj490ad382005-03-13 17:25:53 +000011643 /* =-=-=-=-=-=-=-=-=- Grp8 =-=-=-=-=-=-=-=-=-=-=-= */
11644
11645 case 0xBA: { /* Grp8 Ib,Ev */
11646 Bool decode_OK = False;
11647 modrm = getUChar(delta);
11648 am_sz = lengthAMode(delta);
11649 d32 = getSDisp8(delta + am_sz);
11650 delta = dis_Grp8_Imm ( sorb, delta, modrm, am_sz, sz, d32,
11651 &decode_OK );
11652 if (!decode_OK)
11653 goto decode_failure;
11654 break;
11655 }
sewardjce646f22004-08-31 23:55:54 +000011656
11657 /* =-=-=-=-=-=-=-=-=- BSF/BSR -=-=-=-=-=-=-=-=-=-= */
11658
11659 case 0xBC: /* BSF Gv,Ev */
11660 delta = dis_bs_E_G ( sorb, sz, delta, True );
11661 break;
11662 case 0xBD: /* BSR Gv,Ev */
11663 delta = dis_bs_E_G ( sorb, sz, delta, False );
11664 break;
sewardj1c4208f2004-08-25 13:25:29 +000011665
11666 /* =-=-=-=-=-=-=-=-=- BSWAP -=-=-=-=-=-=-=-=-=-=-= */
11667
11668 case 0xC8: /* BSWAP %eax */
11669 case 0xC9:
11670 case 0xCA:
sewardjb4666cf2004-10-23 00:21:50 +000011671 case 0xCB:
11672 case 0xCC:
11673 case 0xCD:
sewardj1c4208f2004-08-25 13:25:29 +000011674 case 0xCE:
sewardj1c6f9912004-09-07 10:15:24 +000011675 case 0xCF: /* BSWAP %edi */
sewardj1c4208f2004-08-25 13:25:29 +000011676 /* AFAICS from the Intel docs, this only exists at size 4. */
11677 vassert(sz == 4);
11678 t1 = newTemp(Ity_I32);
11679 t2 = newTemp(Ity_I32);
11680 assign( t1, getIReg(4, opc-0xC8) );
11681
11682 assign( t2,
11683 binop(Iop_Or32,
11684 binop(Iop_Shl32, mkexpr(t1), mkU8(24)),
11685 binop(Iop_Or32,
11686 binop(Iop_And32, binop(Iop_Shl32, mkexpr(t1), mkU8(8)),
11687 mkU32(0x00FF0000)),
11688 binop(Iop_Or32,
11689 binop(Iop_And32, binop(Iop_Shr32, mkexpr(t1), mkU8(8)),
11690 mkU32(0x0000FF00)),
11691 binop(Iop_And32, binop(Iop_Shr32, mkexpr(t1), mkU8(24)),
11692 mkU32(0x000000FF) )
11693 )))
11694 );
11695
11696 putIReg(4, opc-0xC8, mkexpr(t2));
sewardj1c4208f2004-08-25 13:25:29 +000011697 DIP("bswapl %s\n", nameIReg(4, opc-0xC8));
11698 break;
11699
sewardj1c6f9912004-09-07 10:15:24 +000011700 /* =-=-=-=-=-=-=-=-=- BT/BTS/BTR/BTC =-=-=-=-=-=-= */
11701
11702 case 0xA3: /* BT Gv,Ev */
11703 delta = dis_bt_G_E ( sorb, sz, delta, BtOpNone );
11704 break;
sewardje6709112004-09-10 18:37:18 +000011705 case 0xB3: /* BTR Gv,Ev */
11706 delta = dis_bt_G_E ( sorb, sz, delta, BtOpReset );
11707 break;
sewardj1c6f9912004-09-07 10:15:24 +000011708 case 0xAB: /* BTS Gv,Ev */
11709 delta = dis_bt_G_E ( sorb, sz, delta, BtOpSet );
11710 break;
sewardj4963a422004-10-14 23:34:03 +000011711 case 0xBB: /* BTC Gv,Ev */
11712 delta = dis_bt_G_E ( sorb, sz, delta, BtOpComp );
11713 break;
sewardj458a6f82004-08-25 12:46:02 +000011714
11715 /* =-=-=-=-=-=-=-=-=- CMOV =-=-=-=-=-=-=-=-=-=-=-= */
11716
sewardj2d4c3a02004-10-15 00:03:23 +000011717 case 0x40:
11718 case 0x41:
sewardj458a6f82004-08-25 12:46:02 +000011719 case 0x42: /* CMOVBb/CMOVNAEb (cmov below) */
11720 case 0x43: /* CMOVNBb/CMOVAEb (cmov not below) */
11721 case 0x44: /* CMOVZb/CMOVEb (cmov zero) */
11722 case 0x45: /* CMOVNZb/CMOVNEb (cmov not zero) */
11723 case 0x46: /* CMOVBEb/CMOVNAb (cmov below or equal) */
11724 case 0x47: /* CMOVNBEb/CMOVAb (cmov not below or equal) */
sewardjce646f22004-08-31 23:55:54 +000011725 case 0x48: /* CMOVSb (cmov negative) */
sewardj458a6f82004-08-25 12:46:02 +000011726 case 0x49: /* CMOVSb (cmov not negative) */
sewardj2d4c3a02004-10-15 00:03:23 +000011727 case 0x4A: /* CMOVP (cmov parity even) */
11728 case 0x4B: /* CMOVNP (cmov parity odd) */
sewardj458a6f82004-08-25 12:46:02 +000011729 case 0x4C: /* CMOVLb/CMOVNGEb (cmov less) */
11730 case 0x4D: /* CMOVGEb/CMOVNLb (cmov greater or equal) */
11731 case 0x4E: /* CMOVLEb/CMOVNGb (cmov less or equal) */
11732 case 0x4F: /* CMOVGb/CMOVNLEb (cmov greater) */
sewardj2a9ad022004-11-25 02:46:58 +000011733 delta = dis_cmov_E_G(sorb, sz, (X86Condcode)(opc - 0x40), delta);
sewardj458a6f82004-08-25 12:46:02 +000011734 break;
11735
11736 /* =-=-=-=-=-=-=-=-=- CMPXCHG -=-=-=-=-=-=-=-=-=-= */
11737
sewardjc744e872004-08-26 11:24:39 +000011738 case 0xB0: /* CMPXCHG Gb,Eb */
11739 delta = dis_cmpxchg_G_E ( sorb, 1, delta );
11740 break;
sewardj458a6f82004-08-25 12:46:02 +000011741 case 0xB1: /* CMPXCHG Gv,Ev */
11742 delta = dis_cmpxchg_G_E ( sorb, sz, delta );
11743 break;
sewardj300bb872005-08-12 23:04:48 +000011744
11745 case 0xC7: { /* CMPXCHG8B Gv (0F C7 /1) */
11746 IRTemp m64_old = newTemp(Ity_I64);
11747 IRTemp m64_new = newTemp(Ity_I64);
11748 IRTemp da_old = newTemp(Ity_I64);
11749 IRTemp da_new = newTemp(Ity_I64);
11750 IRTemp cb_old = newTemp(Ity_I64);
11751 IRTemp flags_old = newTemp(Ity_I32);
11752 IRTemp flags_new = newTemp(Ity_I32);
11753 IRTemp cond = newTemp(Ity_I8);
11754
11755 /* Decode, and generate address. */
11756 modrm = getIByte(delta);
11757 if (epartIsReg(modrm)) goto decode_failure;
11758 if (gregOfRM(modrm) != 1) goto decode_failure;
11759 addr = disAMode ( &alen, sorb, delta, dis_buf );
11760 delta += alen;
11761
11762 /* Fetch the old 64-bit values and compute the guard. */
11763 assign( m64_old, loadLE(Ity_I64, mkexpr(addr) ));
11764 assign( da_old, binop(Iop_32HLto64,
11765 getIReg(4,R_EDX), getIReg(4,R_EAX)) );
11766 assign( cb_old, binop(Iop_32HLto64,
11767 getIReg(4,R_ECX), getIReg(4,R_EBX)) );
11768
11769 assign( cond,
11770 unop(Iop_1Uto8,
11771 binop(Iop_CmpEQ64, mkexpr(da_old), mkexpr(m64_old))) );
11772
11773 /* Compute new %edx:%eax and m64 values, and put in place */
11774 assign( da_new,
11775 IRExpr_Mux0X(mkexpr(cond), mkexpr(m64_old), mkexpr(da_old)));
11776 assign( m64_new,
11777 IRExpr_Mux0X(mkexpr(cond), mkexpr(m64_old), mkexpr(cb_old)));
11778
11779 putIReg(4, R_EDX, unop(Iop_64HIto32, mkexpr(da_new)) );
11780 putIReg(4, R_EAX, unop(Iop_64to32, mkexpr(da_new)) );
11781 storeLE( mkexpr(addr), mkexpr(m64_new) );
11782
11783 /* Copy the guard into the Z flag and leave the others unchanged */
11784 assign( flags_old, widenUto32(mk_x86g_calculate_eflags_all()));
11785 assign(
11786 flags_new,
11787 binop(Iop_Or32,
11788 binop(Iop_And32, mkexpr(flags_old),
11789 mkU32(~X86G_CC_MASK_Z)),
11790 binop(Iop_Shl32,
11791 binop(Iop_And32,
11792 unop(Iop_8Uto32, mkexpr(cond)), mkU32(1)),
11793 mkU8(X86G_CC_SHIFT_Z)) ));
11794
11795 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
11796 stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(flags_new) ));
11797 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
11798 /* Set NDEP even though it isn't used. This makes
11799 redundant-PUT elimination of previous stores to this field
11800 work better. */
11801 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
11802
11803 /* Sheesh. Aren't you glad it was me and not you that had to
11804 write and validate all this grunge? */
11805
11806 DIP("cmpxchg8b %s\n", dis_buf);
11807 break;
11808 }
11809
sewardj588ea762004-09-10 18:56:32 +000011810 /* =-=-=-=-=-=-=-=-=- CPUID -=-=-=-=-=-=-=-=-=-=-= */
11811
sewardj7cb49d72004-10-24 22:31:25 +000011812 case 0xA2: { /* CPUID */
11813 /* Uses dirty helper:
sewardj9df271d2004-12-31 22:37:42 +000011814 void dirtyhelper_CPUID_sse[012] ( VexGuestX86State* )
sewardj7cb49d72004-10-24 22:31:25 +000011815 declared to mod eax, wr ebx, ecx, edx
11816 */
sewardj9df271d2004-12-31 22:37:42 +000011817 IRDirty* d = NULL;
11818 HChar* fName = NULL;
11819 void* fAddr = NULL;
sewardj27e1dd62005-06-30 11:49:14 +000011820 switch (archinfo->subarch) {
sewardj9df271d2004-12-31 22:37:42 +000011821 case VexSubArchX86_sse0:
11822 fName = "x86g_dirtyhelper_CPUID_sse0";
11823 fAddr = &x86g_dirtyhelper_CPUID_sse0;
11824 break;
11825 case VexSubArchX86_sse1:
11826 fName = "x86g_dirtyhelper_CPUID_sse1";
11827 fAddr = &x86g_dirtyhelper_CPUID_sse1;
11828 break;
11829 case VexSubArchX86_sse2:
11830 fName = "x86g_dirtyhelper_CPUID_sse2";
11831 fAddr = &x86g_dirtyhelper_CPUID_sse2;
11832 break;
11833 default:
11834 vpanic("disInstr(x86)(cpuid)");
11835 }
11836 vassert(fName); vassert(fAddr);
11837 d = unsafeIRDirty_0_N ( 0/*regparms*/,
11838 fName, fAddr, mkIRExprVec_0() );
sewardj7cb49d72004-10-24 22:31:25 +000011839 /* declare guest state effects */
sewardjc5fc7aa2004-10-27 23:00:55 +000011840 d->needsBBP = True;
sewardj7cb49d72004-10-24 22:31:25 +000011841 d->nFxState = 4;
11842 d->fxState[0].fx = Ifx_Modify;
11843 d->fxState[0].offset = OFFB_EAX;
11844 d->fxState[0].size = 4;
11845 d->fxState[1].fx = Ifx_Write;
11846 d->fxState[1].offset = OFFB_EBX;
11847 d->fxState[1].size = 4;
11848 d->fxState[2].fx = Ifx_Write;
11849 d->fxState[2].offset = OFFB_ECX;
11850 d->fxState[2].size = 4;
11851 d->fxState[3].fx = Ifx_Write;
11852 d->fxState[3].offset = OFFB_EDX;
11853 d->fxState[3].size = 4;
11854 /* execute the dirty call, side-effecting guest state */
11855 stmt( IRStmt_Dirty(d) );
sewardj55860d82005-01-08 18:25:05 +000011856 /* CPUID is a serialising insn. So, just in case someone is
11857 using it as a memory fence ... */
11858 stmt( IRStmt_MFence() );
sewardj517a7d62004-10-25 09:52:18 +000011859 DIP("cpuid\n");
sewardj588ea762004-09-10 18:56:32 +000011860 break;
sewardj7cb49d72004-10-24 22:31:25 +000011861 }
11862
sewardj5bd4d162004-11-10 13:02:48 +000011863//-- if (!VG_(cpu_has_feature)(VG_X86_FEAT_CPUID))
11864//-- goto decode_failure;
sewardjc9a65702004-07-07 16:32:57 +000011865//--
11866//-- t1 = newTemp(cb);
11867//-- t2 = newTemp(cb);
11868//-- t3 = newTemp(cb);
11869//-- t4 = newTemp(cb);
11870//-- uInstr0(cb, CALLM_S, 0);
11871//--
11872//-- uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, t1);
11873//-- uInstr1(cb, PUSH, 4, TempReg, t1);
11874//--
11875//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
11876//-- uLiteral(cb, 0);
11877//-- uInstr1(cb, PUSH, 4, TempReg, t2);
11878//--
11879//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t3);
11880//-- uLiteral(cb, 0);
11881//-- uInstr1(cb, PUSH, 4, TempReg, t3);
11882//--
11883//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t4);
11884//-- uLiteral(cb, 0);
11885//-- uInstr1(cb, PUSH, 4, TempReg, t4);
11886//--
11887//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_CPUID));
11888//-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
11889//--
11890//-- uInstr1(cb, POP, 4, TempReg, t4);
11891//-- uInstr2(cb, PUT, 4, TempReg, t4, ArchReg, R_EDX);
11892//--
11893//-- uInstr1(cb, POP, 4, TempReg, t3);
11894//-- uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_ECX);
11895//--
11896//-- uInstr1(cb, POP, 4, TempReg, t2);
11897//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_EBX);
11898//--
11899//-- uInstr1(cb, POP, 4, TempReg, t1);
11900//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_EAX);
11901//--
11902//-- uInstr0(cb, CALLM_E, 0);
11903//-- DIP("cpuid\n");
11904//-- break;
11905//--
sewardj9334b0f2004-07-10 22:43:54 +000011906 /* =-=-=-=-=-=-=-=-=- MOVZX, MOVSX =-=-=-=-=-=-=-= */
11907
11908 case 0xB6: /* MOVZXb Eb,Gv */
11909 delta = dis_movx_E_G ( sorb, delta, 1, 4, False );
11910 break;
sewardj940e8c92004-07-11 16:53:24 +000011911 case 0xB7: /* MOVZXw Ew,Gv */
11912 delta = dis_movx_E_G ( sorb, delta, 2, 4, False );
11913 break;
11914
sewardj0611d802004-07-11 02:37:54 +000011915 case 0xBE: /* MOVSXb Eb,Gv */
11916 delta = dis_movx_E_G ( sorb, delta, 1, 4, True );
11917 break;
sewardj7ed22952004-07-29 00:09:58 +000011918 case 0xBF: /* MOVSXw Ew,Gv */
11919 delta = dis_movx_E_G ( sorb, delta, 2, 4, True );
11920 break;
11921
sewardjc9a65702004-07-07 16:32:57 +000011922//-- /* =-=-=-=-=-=-=-=-=-=-= MOVNTI -=-=-=-=-=-=-=-=-= */
11923//--
11924//-- case 0xC3: /* MOVNTI Gv,Ev */
11925//-- vg_assert(sz == 4);
11926//-- modrm = getUChar(eip);
11927//-- vg_assert(!epartIsReg(modrm));
11928//-- t1 = newTemp(cb);
11929//-- uInstr2(cb, GET, 4, ArchReg, gregOfRM(modrm), TempReg, t1);
11930//-- pair = disAMode ( cb, sorb, eip, dis_buf );
11931//-- t2 = LOW24(pair);
11932//-- eip += HI8(pair);
11933//-- uInstr2(cb, STORE, 4, TempReg, t1, TempReg, t2);
11934//-- DIP("movnti %s,%s\n", nameIReg(4,gregOfRM(modrm)), dis_buf);
11935//-- break;
sewardjcf780b42004-07-13 18:42:17 +000011936
11937 /* =-=-=-=-=-=-=-=-=- MUL/IMUL =-=-=-=-=-=-=-=-=-= */
11938
11939 case 0xAF: /* IMUL Ev, Gv */
sewardj2a2ba8b2004-11-08 13:14:06 +000011940 delta = dis_mul_E_G ( sorb, sz, delta );
sewardjcf780b42004-07-13 18:42:17 +000011941 break;
sewardje87b4842004-07-10 12:23:30 +000011942
11943 /* =-=-=-=-=-=-=-=-=- Jcond d32 -=-=-=-=-=-=-=-=-= */
11944 case 0x80:
11945 case 0x81:
11946 case 0x82: /* JBb/JNAEb (jump below) */
11947 case 0x83: /* JNBb/JAEb (jump not below) */
11948 case 0x84: /* JZb/JEb (jump zero) */
11949 case 0x85: /* JNZb/JNEb (jump not zero) */
11950 case 0x86: /* JBEb/JNAb (jump below or equal) */
11951 case 0x87: /* JNBEb/JAb (jump not below or equal) */
11952 case 0x88: /* JSb (jump negative) */
11953 case 0x89: /* JSb (jump not negative) */
11954 case 0x8A: /* JP (jump parity even) */
11955 case 0x8B: /* JNP/JPO (jump parity odd) */
11956 case 0x8C: /* JLb/JNGEb (jump less) */
11957 case 0x8D: /* JGEb/JNLb (jump greater or equal) */
11958 case 0x8E: /* JLEb/JNGb (jump less or equal) */
11959 case 0x8F: /* JGb/JNLEb (jump greater) */
sewardj9e6491a2005-07-02 19:24:10 +000011960 d32 = (((Addr32)guest_EIP_bbstart)+delta+4) + getUDisp32(delta);
sewardje87b4842004-07-10 12:23:30 +000011961 delta += 4;
sewardj2a9ad022004-11-25 02:46:58 +000011962 jcc_01( (X86Condcode)(opc - 0x80),
sewardj9e6491a2005-07-02 19:24:10 +000011963 (Addr32)(guest_EIP_bbstart+delta),
sewardj2a9ad022004-11-25 02:46:58 +000011964 d32 );
sewardj9e6491a2005-07-02 19:24:10 +000011965 dres.whatNext = Dis_StopHere;
sewardj2a9ad022004-11-25 02:46:58 +000011966 DIP("j%s-32 0x%x\n", name_X86Condcode(opc - 0x80), d32);
sewardje87b4842004-07-10 12:23:30 +000011967 break;
11968
sewardj89cd0932004-09-08 18:23:25 +000011969 /* =-=-=-=-=-=-=-=-=- RDTSC -=-=-=-=-=-=-=-=-=-=-= */
sewardj4ed64292005-08-23 19:24:29 +000011970 case 0x31: { /* RDTSC */
11971 IRTemp val = newTemp(Ity_I64);
11972 IRExpr** args = mkIRExprVec_0();
11973 IRDirty* d = unsafeIRDirty_1_N (
11974 val,
11975 0/*regparms*/,
11976 "x86g_dirtyhelper_RDTSC",
11977 &x86g_dirtyhelper_RDTSC,
11978 args
11979 );
11980 /* execute the dirty call, dumping the result in val. */
11981 stmt( IRStmt_Dirty(d) );
11982 putIReg(4, R_EDX, unop(Iop_64HIto32, mkexpr(val)));
11983 putIReg(4, R_EAX, unop(Iop_64to32, mkexpr(val)));
11984 DIP("rdtsc\n");
11985 break;
11986 }
sewardj77b86be2004-07-11 13:28:24 +000011987
sewardjb64821b2004-12-14 10:00:16 +000011988 /* =-=-=-=-=-=-=-=-=- PUSH/POP Sreg =-=-=-=-=-=-=-=-=-= */
11989
11990 case 0xA1: /* POP %FS */
11991 dis_pop_segreg( R_FS, sz ); break;
11992 case 0xA9: /* POP %GS */
11993 dis_pop_segreg( R_GS, sz ); break;
11994
11995 case 0xA0: /* PUSH %FS */
11996 dis_push_segreg( R_FS, sz ); break;
11997 case 0xA8: /* PUSH %GS */
11998 dis_push_segreg( R_GS, sz ); break;
11999
sewardj77b86be2004-07-11 13:28:24 +000012000 /* =-=-=-=-=-=-=-=-=- SETcc Eb =-=-=-=-=-=-=-=-=-= */
12001 case 0x90:
12002 case 0x91:
12003 case 0x92: /* set-Bb/set-NAEb (jump below) */
12004 case 0x93: /* set-NBb/set-AEb (jump not below) */
12005 case 0x94: /* set-Zb/set-Eb (jump zero) */
12006 case 0x95: /* set-NZb/set-NEb (jump not zero) */
12007 case 0x96: /* set-BEb/set-NAb (jump below or equal) */
12008 case 0x97: /* set-NBEb/set-Ab (jump not below or equal) */
12009 case 0x98: /* set-Sb (jump negative) */
12010 case 0x99: /* set-Sb (jump not negative) */
12011 case 0x9A: /* set-P (jump parity even) */
12012 case 0x9B: /* set-NP (jump parity odd) */
12013 case 0x9C: /* set-Lb/set-NGEb (jump less) */
12014 case 0x9D: /* set-GEb/set-NLb (jump greater or equal) */
12015 case 0x9E: /* set-LEb/set-NGb (jump less or equal) */
12016 case 0x9F: /* set-Gb/set-NLEb (jump greater) */
sewardj5bd4d162004-11-10 13:02:48 +000012017 t1 = newTemp(Ity_I8);
sewardj2a9ad022004-11-25 02:46:58 +000012018 assign( t1, unop(Iop_1Uto8,mk_x86g_calculate_condition(opc-0x90)) );
sewardj77b86be2004-07-11 13:28:24 +000012019 modrm = getIByte(delta);
12020 if (epartIsReg(modrm)) {
12021 delta++;
sewardj5bd4d162004-11-10 13:02:48 +000012022 putIReg(1, eregOfRM(modrm), mkexpr(t1));
sewardj2a9ad022004-11-25 02:46:58 +000012023 DIP("set%s %s\n", name_X86Condcode(opc-0x90),
sewardj77b86be2004-07-11 13:28:24 +000012024 nameIReg(1,eregOfRM(modrm)));
12025 } else {
sewardj750f4072004-07-26 22:39:11 +000012026 addr = disAMode ( &alen, sorb, delta, dis_buf );
12027 delta += alen;
12028 storeLE( mkexpr(addr), mkexpr(t1) );
sewardj2a9ad022004-11-25 02:46:58 +000012029 DIP("set%s %s\n", name_X86Condcode(opc-0x90), dis_buf);
sewardj77b86be2004-07-11 13:28:24 +000012030 }
12031 break;
12032
sewardj180e8b32004-07-29 01:40:11 +000012033 /* =-=-=-=-=-=-=-=-=- SHLD/SHRD -=-=-=-=-=-=-=-=-= */
12034
12035 case 0xA4: /* SHLDv imm8,Gv,Ev */
12036 modrm = getIByte(delta);
12037 d32 = delta + lengthAMode(delta);
sewardj2d49b432005-02-01 00:37:06 +000012038 vex_sprintf(dis_buf, "$%d", getIByte(d32));
sewardj180e8b32004-07-29 01:40:11 +000012039 delta = dis_SHLRD_Gv_Ev (
12040 sorb, delta, modrm, sz,
12041 mkU8(getIByte(d32)), True, /* literal */
12042 dis_buf, True );
12043 break;
sewardja06e5562004-07-14 13:18:05 +000012044 case 0xA5: /* SHLDv %cl,Gv,Ev */
12045 modrm = getIByte(delta);
12046 delta = dis_SHLRD_Gv_Ev (
12047 sorb, delta, modrm, sz,
12048 getIReg(1,R_ECX), False, /* not literal */
12049 "%cl", True );
12050 break;
12051
sewardj68511542004-07-28 00:15:44 +000012052 case 0xAC: /* SHRDv imm8,Gv,Ev */
12053 modrm = getIByte(delta);
12054 d32 = delta + lengthAMode(delta);
sewardj2d49b432005-02-01 00:37:06 +000012055 vex_sprintf(dis_buf, "$%d", getIByte(d32));
sewardj68511542004-07-28 00:15:44 +000012056 delta = dis_SHLRD_Gv_Ev (
12057 sorb, delta, modrm, sz,
12058 mkU8(getIByte(d32)), True, /* literal */
12059 dis_buf, False );
12060 break;
sewardja511afc2004-07-29 22:26:03 +000012061 case 0xAD: /* SHRDv %cl,Gv,Ev */
12062 modrm = getIByte(delta);
12063 delta = dis_SHLRD_Gv_Ev (
12064 sorb, delta, modrm, sz,
12065 getIReg(1,R_ECX), False, /* not literal */
12066 "%cl", False );
12067 break;
12068
sewardjf07ed032005-08-07 14:48:03 +000012069 /* =-=-=-=-=-=-=-=-=- SYSENTER -=-=-=-=-=-=-=-=-=-= */
12070
12071 case 0x34:
12072 /* Simple implementation needing a long explaination.
12073
12074 sysenter is a kind of syscall entry. The key thing here
12075 is that the return address is not known -- that is
12076 something that is beyond Vex's knowledge. So this IR
12077 forces a return to the scheduler, which can do what it
12078 likes to simulate the systemter, but it MUST set this
12079 thread's guest_EIP field with the continuation address
12080 before resuming execution. If that doesn't happen, the
12081 thread will jump to address zero, which is probably
12082 fatal.
12083 */
12084 jmp_lit(Ijk_SysenterX86, 0/*bogus next EIP value*/);
12085 dres.whatNext = Dis_StopHere;
12086 DIP("sysenter");
12087 break;
12088
sewardj464efa42004-11-19 22:17:29 +000012089 /* =-=-=-=-=-=-=-=-=- XADD -=-=-=-=-=-=-=-=-=-= */
12090
sewardjc9a65702004-07-07 16:32:57 +000012091//-- case 0xC0: /* XADD Gb,Eb */
12092//-- eip = dis_xadd_G_E ( cb, sorb, 1, eip );
12093//-- break;
sewardj883b00b2004-09-11 09:30:24 +000012094 case 0xC1: /* XADD Gv,Ev */
12095 delta = dis_xadd_G_E ( sorb, sz, delta );
12096 break;
12097
sewardjf13f37b2004-12-08 17:01:23 +000012098 /* =-=-=-=-=-=-=-=-=- MMXery =-=-=-=-=-=-=-=-=-=-= */
sewardj464efa42004-11-19 22:17:29 +000012099
sewardj2b7a9202004-11-26 19:15:38 +000012100 case 0x71:
12101 case 0x72:
sewardj38a3f862005-01-13 15:06:51 +000012102 case 0x73: /* PSLLgg/PSRAgg/PSRLgg mmxreg by imm8 */
sewardj2b7a9202004-11-26 19:15:38 +000012103
12104 case 0x6E: /* MOVD (src)ireg-or-mem, (dst)mmxreg */
12105 case 0x7E: /* MOVD (src)mmxreg, (dst)ireg-or-mem */
sewardj464efa42004-11-19 22:17:29 +000012106 case 0x7F: /* MOVQ (src)mmxreg, (dst)mmxreg-or-mem */
sewardj2b7a9202004-11-26 19:15:38 +000012107 case 0x6F: /* MOVQ (src)mmxreg-or-mem, (dst)mmxreg */
sewardj464efa42004-11-19 22:17:29 +000012108
12109 case 0xFC:
12110 case 0xFD:
12111 case 0xFE: /* PADDgg (src)mmxreg-or-mem, (dst)mmxreg */
12112
12113 case 0xEC:
12114 case 0xED: /* PADDSgg (src)mmxreg-or-mem, (dst)mmxreg */
12115
12116 case 0xDC:
12117 case 0xDD: /* PADDUSgg (src)mmxreg-or-mem, (dst)mmxreg */
12118
12119 case 0xF8:
12120 case 0xF9:
12121 case 0xFA: /* PSUBgg (src)mmxreg-or-mem, (dst)mmxreg */
12122
12123 case 0xE8:
12124 case 0xE9: /* PSUBSgg (src)mmxreg-or-mem, (dst)mmxreg */
12125
12126 case 0xD8:
12127 case 0xD9: /* PSUBUSgg (src)mmxreg-or-mem, (dst)mmxreg */
12128
12129 case 0xE5: /* PMULHW (src)mmxreg-or-mem, (dst)mmxreg */
12130 case 0xD5: /* PMULLW (src)mmxreg-or-mem, (dst)mmxreg */
12131
sewardj4340dac2004-11-20 13:17:04 +000012132 case 0xF5: /* PMADDWD (src)mmxreg-or-mem, (dst)mmxreg */
12133
12134 case 0x74:
12135 case 0x75:
12136 case 0x76: /* PCMPEQgg (src)mmxreg-or-mem, (dst)mmxreg */
12137
12138 case 0x64:
12139 case 0x65:
12140 case 0x66: /* PCMPGTgg (src)mmxreg-or-mem, (dst)mmxreg */
12141
sewardj63ba4092004-11-21 12:30:18 +000012142 case 0x6B: /* PACKSSDW (src)mmxreg-or-mem, (dst)mmxreg */
12143 case 0x63: /* PACKSSWB (src)mmxreg-or-mem, (dst)mmxreg */
12144 case 0x67: /* PACKUSWB (src)mmxreg-or-mem, (dst)mmxreg */
12145
12146 case 0x68:
12147 case 0x69:
12148 case 0x6A: /* PUNPCKHgg (src)mmxreg-or-mem, (dst)mmxreg */
12149
12150 case 0x60:
12151 case 0x61:
12152 case 0x62: /* PUNPCKLgg (src)mmxreg-or-mem, (dst)mmxreg */
12153
12154 case 0xDB: /* PAND (src)mmxreg-or-mem, (dst)mmxreg */
12155 case 0xDF: /* PANDN (src)mmxreg-or-mem, (dst)mmxreg */
12156 case 0xEB: /* POR (src)mmxreg-or-mem, (dst)mmxreg */
12157 case 0xEF: /* PXOR (src)mmxreg-or-mem, (dst)mmxreg */
12158
sewardj38a3f862005-01-13 15:06:51 +000012159 case 0xF1: /* PSLLgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj8d14a592004-11-21 17:04:50 +000012160 case 0xF2:
sewardj38a3f862005-01-13 15:06:51 +000012161 case 0xF3:
sewardj8d14a592004-11-21 17:04:50 +000012162
sewardj38a3f862005-01-13 15:06:51 +000012163 case 0xD1: /* PSRLgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj8d14a592004-11-21 17:04:50 +000012164 case 0xD2:
sewardj38a3f862005-01-13 15:06:51 +000012165 case 0xD3:
sewardj8d14a592004-11-21 17:04:50 +000012166
sewardj38a3f862005-01-13 15:06:51 +000012167 case 0xE1: /* PSRAgg (src)mmxreg-or-mem, (dst)mmxreg */
12168 case 0xE2:
sewardj464efa42004-11-19 22:17:29 +000012169 {
sewardj52d04912005-07-03 00:52:48 +000012170 Int delta0 = delta-1;
sewardj464efa42004-11-19 22:17:29 +000012171 Bool decode_OK = False;
sewardj38a3f862005-01-13 15:06:51 +000012172
12173 /* If sz==2 this is SSE, and we assume sse idec has
12174 already spotted those cases by now. */
12175 if (sz != 4)
12176 goto decode_failure;
12177
sewardj464efa42004-11-19 22:17:29 +000012178 delta = dis_MMX ( &decode_OK, sorb, sz, delta-1 );
12179 if (!decode_OK) {
12180 delta = delta0;
12181 goto decode_failure;
12182 }
12183 break;
12184 }
12185
sewardj8d14a592004-11-21 17:04:50 +000012186 case 0x77: /* EMMS */
sewardj38a3f862005-01-13 15:06:51 +000012187 if (sz != 4)
12188 goto decode_failure;
sewardj4cb918d2004-12-03 19:43:31 +000012189 do_EMMS_preamble();
sewardj8d14a592004-11-21 17:04:50 +000012190 DIP("emms\n");
12191 break;
12192
sewardje87b4842004-07-10 12:23:30 +000012193 /* =-=-=-=-=-=-=-=-=- unimp2 =-=-=-=-=-=-=-=-=-=-= */
12194
12195 default:
12196 goto decode_failure;
12197 } /* switch (opc) for the 2-byte opcodes */
12198 goto decode_success;
12199 } /* case 0x0F: of primary opcode */
sewardjc9a65702004-07-07 16:32:57 +000012200
12201 /* ------------------------ ??? ------------------------ */
12202
12203 default:
sewardje87b4842004-07-10 12:23:30 +000012204 decode_failure:
sewardjc9a65702004-07-07 16:32:57 +000012205 /* All decode failures end up here. */
sewardj52444cb2004-12-13 14:09:01 +000012206 vex_printf("vex x86->IR: unhandled instruction bytes: "
sewardjc9a65702004-07-07 16:32:57 +000012207 "0x%x 0x%x 0x%x 0x%x\n",
12208 (Int)getIByte(delta_start+0),
12209 (Int)getIByte(delta_start+1),
12210 (Int)getIByte(delta_start+2),
12211 (Int)getIByte(delta_start+3) );
sewardj52444cb2004-12-13 14:09:01 +000012212
sewardjb64821b2004-12-14 10:00:16 +000012213 /* Tell the dispatcher that this insn cannot be decoded, and so has
12214 not been executed, and (is currently) the next to be executed.
12215 EIP should be up-to-date since it made so at the start of each
12216 insn, but nevertheless be paranoid and update it again right
12217 now. */
sewardj9e6491a2005-07-02 19:24:10 +000012218 stmt( IRStmt_Put( OFFB_EIP, mkU32(guest_EIP_curr_instr) ) );
12219 jmp_lit(Ijk_NoDecode, guest_EIP_curr_instr);
12220 dres.whatNext = Dis_StopHere;
12221 dres.len = 0;
12222 return dres;
sewardj52444cb2004-12-13 14:09:01 +000012223
sewardjc9a65702004-07-07 16:32:57 +000012224 } /* switch (opc) for the main (primary) opcode switch. */
12225
sewardje87b4842004-07-10 12:23:30 +000012226 decode_success:
sewardjc9a65702004-07-07 16:32:57 +000012227 /* All decode successes end up here. */
12228 DIP("\n");
sewardjc9a65702004-07-07 16:32:57 +000012229
sewardj9e6491a2005-07-02 19:24:10 +000012230 dres.len = delta - delta_start;
12231 return dres;
sewardjc9a65702004-07-07 16:32:57 +000012232}
12233
12234#undef DIP
12235#undef DIS
12236
sewardj9e6491a2005-07-02 19:24:10 +000012237
12238/*------------------------------------------------------------*/
12239/*--- Top-level fn ---*/
12240/*------------------------------------------------------------*/
12241
12242/* Disassemble a single instruction into IR. The instruction
12243 is located in host memory at &guest_code[delta]. */
12244
12245DisResult disInstr_X86 ( IRBB* irbb_IN,
12246 Bool put_IP,
12247 Bool (*resteerOkFn) ( Addr64 ),
12248 UChar* guest_code_IN,
12249 Long delta,
12250 Addr64 guest_IP,
12251 VexArchInfo* archinfo,
12252 Bool host_bigendian_IN )
12253{
12254 DisResult dres;
12255
12256 /* Set globals (see top of this file) */
12257 guest_code = guest_code_IN;
12258 irbb = irbb_IN;
12259 host_is_bigendian = host_bigendian_IN;
12260 guest_EIP_curr_instr = (Addr32)guest_IP;
12261 guest_EIP_bbstart = (Addr32)toUInt(guest_IP - delta);
12262
12263 dres = disInstr_X86_WRK ( put_IP, resteerOkFn,
12264 delta, archinfo );
12265
12266 return dres;
12267}
12268
12269
sewardjc9a65702004-07-07 16:32:57 +000012270/*--------------------------------------------------------------------*/
sewardjc0ee2ed2004-07-27 10:29:41 +000012271/*--- end guest-x86/toIR.c ---*/
sewardjc9a65702004-07-07 16:32:57 +000012272/*--------------------------------------------------------------------*/