blob: 1d4345241d6e33aafb81909fcd73e573de2ff9ab [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 ---*/
sewardjd24931d2005-03-20 12:51:39 +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
sewardj496a58d2005-03-20 18:44:44 +000013 Copyright (C) 2004-2005 OpenWorks LLP.
sewardjf8ed9d82004-11-12 17:40:23 +000014
15 This program is free software; you can redistribute it and/or modify
16 it under the terms of the GNU General Public License as published by
17 the Free Software Foundation; Version 2 dated June 1991 of the
18 license.
19
20 This program is distributed in the hope that it will be useful,
21 but WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or liability
23 for damages. See the GNU General Public License for more details.
24
25 Neither the names of the U.S. Department of Energy nor the
26 University of California nor the names of its contributors may be
27 used to endorse or promote products derived from this software
28 without prior written permission.
29
30 You should have received a copy of the GNU General Public License
31 along with this program; if not, write to the Free Software
32 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
33 USA.
34*/
35
sewardj77b86be2004-07-11 13:28:24 +000036/* TODO:
sewardj45f1ff82005-05-05 12:04:14 +000037
sewardj458a6f82004-08-25 12:46:02 +000038 check flag settings for cmpxchg
sewardj883b00b2004-09-11 09:30:24 +000039 FUCOMI(P): what happens to A and S flags? Currently are forced
40 to zero.
sewardj3f61ddb2004-10-16 20:51:05 +000041
sewardjce70a5c2004-10-18 14:09:54 +000042 x87 FP Limitations:
sewardja0e83b02005-01-06 12:36:38 +000043
44 * all arithmetic done at 64 bits
45
sewardj3f61ddb2004-10-16 20:51:05 +000046 * no FP exceptions, except for handling stack over/underflow
sewardja0e83b02005-01-06 12:36:38 +000047
sewardj3f61ddb2004-10-16 20:51:05 +000048 * FP rounding mode observed only for float->int conversions
sewardja0e83b02005-01-06 12:36:38 +000049 and int->float conversions which could lose accuracy, and
50 for float-to-float rounding. For all other operations,
51 round-to-nearest is used, regardless.
52
sewardj3f61ddb2004-10-16 20:51:05 +000053 * FP sin/cos/tan/sincos: C2 flag is always cleared. IOW the
54 simulation claims the argument is in-range (-2^63 <= arg <= 2^63)
55 even when it isn't.
sewardja0e83b02005-01-06 12:36:38 +000056
sewardje166ed02004-10-25 02:27:01 +000057 * some of the FCOM cases could do with testing -- not convinced
58 that the args are the right way round.
sewardj52444cb2004-12-13 14:09:01 +000059
sewardja0e83b02005-01-06 12:36:38 +000060 * FSAVE does not re-initialise the FPU; it should do
61
62 * FINIT not only initialises the FPU environment, it also
63 zeroes all the FP registers. It should leave the registers
64 unchanged.
65
sewardj9f8a3952005-04-06 10:27:11 +000066 RDTSC returns one, always.
sewardjcb2c99d2004-12-17 19:14:24 +000067
68 SAHF should cause eflags[1] == 1, and in fact it produces 0. As
69 per Intel docs this bit has no meaning anyway. Since PUSHF is the
70 only way to observe eflags[1], a proper fix would be to make that
71 bit be set by PUSHF.
72
sewardj52444cb2004-12-13 14:09:01 +000073 This module uses global variables and so is not MT-safe (if that
sewardje395ae82005-02-26 02:00:50 +000074 should ever become relevant).
75
76 The delta values are 32-bit ints, not 64-bit ints. That means
77 this module may not work right if run on a 64-bit host. That should
78 be fixed properly, really -- if anyone ever wants to use Vex to
sewardj45f1ff82005-05-05 12:04:14 +000079 translate x86 code for execution on a 64-bit host. */
sewardje05c42c2004-07-08 20:25:10 +000080
sewardj9f8a3952005-04-06 10:27:11 +000081/* Performance holes:
82
83 - fcom ; fstsw %ax ; sahf
84 sahf does not update the O flag (sigh) and so O needs to
85 be computed. This is done expensively; it would be better
86 to have a calculate_eflags_o helper.
87
88 - emwarns; some FP codes can generate huge numbers of these
89 if the fpucw is changed in an inner loop. It would be
90 better for the guest state to have an emwarn-enable reg
91 which can be set zero or nonzero. If it is zero, emwarns
92 are not flagged, and instead control just flows all the
93 way through bbs as usual.
94*/
95
sewardjc9a65702004-07-07 16:32:57 +000096/* Translates x86 code to IR. */
97
98#include "libvex_basictypes.h"
99#include "libvex_ir.h"
sewardje87b4842004-07-10 12:23:30 +0000100#include "libvex.h"
sewardjf6dc3ce2004-10-19 01:03:46 +0000101#include "libvex_guest_x86.h"
sewardjc0ee2ed2004-07-27 10:29:41 +0000102
103#include "main/vex_util.h"
104#include "main/vex_globals.h"
sewardj9e6491a2005-07-02 19:24:10 +0000105#include "guest-generic/bb_to_IR.h"
sewardjc0ee2ed2004-07-27 10:29:41 +0000106#include "guest-x86/gdefs.h"
sewardjc9a65702004-07-07 16:32:57 +0000107
108
109/*------------------------------------------------------------*/
110/*--- Globals ---*/
111/*------------------------------------------------------------*/
112
sewardj9e6491a2005-07-02 19:24:10 +0000113/* These are set at the start of the translation of an insn, right
114 down in disInstr_X86, so that we don't have to pass them around
115 endlessly. They are all constant during the translation of any
116 given insn. */
sewardjc9a65702004-07-07 16:32:57 +0000117
118/* We need to know this to do sub-register accesses correctly. */
sewardjc9a65702004-07-07 16:32:57 +0000119static Bool host_is_bigendian;
120
sewardj9e6491a2005-07-02 19:24:10 +0000121/* Pointer to the guest code area (points to start of BB, not to the
122 insn being processed). */
sewardjc9a65702004-07-07 16:32:57 +0000123static UChar* guest_code;
124
125/* The guest address corresponding to guest_code[0]. */
sewardj9e6491a2005-07-02 19:24:10 +0000126static Addr32 guest_EIP_bbstart;
sewardjc9a65702004-07-07 16:32:57 +0000127
sewardj52444cb2004-12-13 14:09:01 +0000128/* The guest address for the instruction currently being
129 translated. */
sewardj9e6491a2005-07-02 19:24:10 +0000130static Addr32 guest_EIP_curr_instr;
sewardj52444cb2004-12-13 14:09:01 +0000131
sewardjd7cb8532004-08-17 23:59:23 +0000132/* The IRBB* into which we're generating code. */
sewardjc9a65702004-07-07 16:32:57 +0000133static IRBB* irbb;
134
sewardjc9a65702004-07-07 16:32:57 +0000135
sewardjce70a5c2004-10-18 14:09:54 +0000136/*------------------------------------------------------------*/
137/*--- Debugging output ---*/
138/*------------------------------------------------------------*/
139
sewardjf48ac192004-10-29 00:41:29 +0000140#define DIP(format, args...) \
sewardj9e6491a2005-07-02 19:24:10 +0000141 if (vex_traceflags & VEX_TRACE_FE) \
sewardjce70a5c2004-10-18 14:09:54 +0000142 vex_printf(format, ## args)
143
sewardjf48ac192004-10-29 00:41:29 +0000144#define DIS(buf, format, args...) \
sewardj9e6491a2005-07-02 19:24:10 +0000145 if (vex_traceflags & VEX_TRACE_FE) \
sewardjce70a5c2004-10-18 14:09:54 +0000146 vex_sprintf(buf, format, ## args)
147
148
149/*------------------------------------------------------------*/
sewardjdcc85fc2004-10-26 13:26:20 +0000150/*--- Offsets of various parts of the x86 guest state. ---*/
151/*------------------------------------------------------------*/
152
sewardjc9a43662004-11-30 18:51:59 +0000153#define OFFB_EAX offsetof(VexGuestX86State,guest_EAX)
154#define OFFB_EBX offsetof(VexGuestX86State,guest_EBX)
155#define OFFB_ECX offsetof(VexGuestX86State,guest_ECX)
156#define OFFB_EDX offsetof(VexGuestX86State,guest_EDX)
157#define OFFB_ESP offsetof(VexGuestX86State,guest_ESP)
158#define OFFB_EBP offsetof(VexGuestX86State,guest_EBP)
159#define OFFB_ESI offsetof(VexGuestX86State,guest_ESI)
160#define OFFB_EDI offsetof(VexGuestX86State,guest_EDI)
sewardj2a2ba8b2004-11-08 13:14:06 +0000161
sewardjc9a43662004-11-30 18:51:59 +0000162#define OFFB_EIP offsetof(VexGuestX86State,guest_EIP)
sewardj2a2ba8b2004-11-08 13:14:06 +0000163
sewardjc9a43662004-11-30 18:51:59 +0000164#define OFFB_CC_OP offsetof(VexGuestX86State,guest_CC_OP)
165#define OFFB_CC_DEP1 offsetof(VexGuestX86State,guest_CC_DEP1)
166#define OFFB_CC_DEP2 offsetof(VexGuestX86State,guest_CC_DEP2)
167#define OFFB_CC_NDEP offsetof(VexGuestX86State,guest_CC_NDEP)
sewardj893aada2004-11-29 19:57:54 +0000168
sewardjc9a43662004-11-30 18:51:59 +0000169#define OFFB_FPREGS offsetof(VexGuestX86State,guest_FPREG[0])
170#define OFFB_FPTAGS offsetof(VexGuestX86State,guest_FPTAG[0])
171#define OFFB_DFLAG offsetof(VexGuestX86State,guest_DFLAG)
172#define OFFB_IDFLAG offsetof(VexGuestX86State,guest_IDFLAG)
173#define OFFB_FTOP offsetof(VexGuestX86State,guest_FTOP)
174#define OFFB_FC3210 offsetof(VexGuestX86State,guest_FC3210)
175#define OFFB_FPROUND offsetof(VexGuestX86State,guest_FPROUND)
176
177#define OFFB_CS offsetof(VexGuestX86State,guest_CS)
178#define OFFB_DS offsetof(VexGuestX86State,guest_DS)
179#define OFFB_ES offsetof(VexGuestX86State,guest_ES)
180#define OFFB_FS offsetof(VexGuestX86State,guest_FS)
181#define OFFB_GS offsetof(VexGuestX86State,guest_GS)
182#define OFFB_SS offsetof(VexGuestX86State,guest_SS)
sewardj3bd6f3e2004-12-13 10:48:19 +0000183#define OFFB_LDT offsetof(VexGuestX86State,guest_LDT)
184#define OFFB_GDT offsetof(VexGuestX86State,guest_GDT)
sewardjc9a43662004-11-30 18:51:59 +0000185
186#define OFFB_SSEROUND offsetof(VexGuestX86State,guest_SSEROUND)
187#define OFFB_XMM0 offsetof(VexGuestX86State,guest_XMM0)
188#define OFFB_XMM1 offsetof(VexGuestX86State,guest_XMM1)
189#define OFFB_XMM2 offsetof(VexGuestX86State,guest_XMM2)
190#define OFFB_XMM3 offsetof(VexGuestX86State,guest_XMM3)
191#define OFFB_XMM4 offsetof(VexGuestX86State,guest_XMM4)
192#define OFFB_XMM5 offsetof(VexGuestX86State,guest_XMM5)
193#define OFFB_XMM6 offsetof(VexGuestX86State,guest_XMM6)
194#define OFFB_XMM7 offsetof(VexGuestX86State,guest_XMM7)
195
196#define OFFB_EMWARN offsetof(VexGuestX86State,guest_EMWARN)
sewardjdcc85fc2004-10-26 13:26:20 +0000197
198
199/*------------------------------------------------------------*/
sewardjce70a5c2004-10-18 14:09:54 +0000200/*--- Helper bits and pieces for deconstructing the ---*/
201/*--- x86 insn stream. ---*/
202/*------------------------------------------------------------*/
203
204/* This is the Intel register encoding -- integer regs. */
205#define R_EAX 0
206#define R_ECX 1
207#define R_EDX 2
208#define R_EBX 3
209#define R_ESP 4
210#define R_EBP 5
211#define R_ESI 6
212#define R_EDI 7
213
214#define R_AL (0+R_EAX)
215#define R_AH (4+R_EAX)
216
sewardj063f02f2004-10-20 12:36:12 +0000217/* This is the Intel register encoding -- segment regs. */
218#define R_ES 0
219#define R_CS 1
220#define R_SS 2
221#define R_DS 3
222#define R_FS 4
223#define R_GS 5
224
sewardjce70a5c2004-10-18 14:09:54 +0000225
sewardjc9a65702004-07-07 16:32:57 +0000226/* Add a statement to the list held by "irbb". */
sewardjd7cb8532004-08-17 23:59:23 +0000227static void stmt ( IRStmt* st )
sewardjc9a65702004-07-07 16:32:57 +0000228{
sewardjd7cb8532004-08-17 23:59:23 +0000229 addStmtToIRBB( irbb, st );
sewardjc9a65702004-07-07 16:32:57 +0000230}
231
232/* Generate a new temporary of the given type. */
233static IRTemp newTemp ( IRType ty )
234{
sewardj496a58d2005-03-20 18:44:44 +0000235 vassert(isPlausibleIRType(ty));
sewardje539a402004-07-14 18:24:17 +0000236 return newIRTemp( irbb->tyenv, ty );
sewardjc9a65702004-07-07 16:32:57 +0000237}
238
sewardjc9a65702004-07-07 16:32:57 +0000239/* Bomb out if we can't handle something. */
sewardjd1061ab2004-07-08 01:45:30 +0000240__attribute__ ((noreturn))
sewardj2d49b432005-02-01 00:37:06 +0000241static void unimplemented ( HChar* str )
sewardjc9a65702004-07-07 16:32:57 +0000242{
243 vex_printf("x86toIR: unimplemented feature\n");
244 vpanic(str);
245}
246
sewardjce70a5c2004-10-18 14:09:54 +0000247/* Various simple conversions */
sewardjd1061ab2004-07-08 01:45:30 +0000248
sewardje05c42c2004-07-08 20:25:10 +0000249static UInt extend_s_8to32( UInt x )
sewardjd1061ab2004-07-08 01:45:30 +0000250{
251 return (UInt)((((Int)x) << 24) >> 24);
252}
253
sewardj0611d802004-07-11 02:37:54 +0000254static UInt extend_s_16to32 ( UInt x )
255{
256 return (UInt)((((Int)x) << 16) >> 16);
257}
258
sewardjd1061ab2004-07-08 01:45:30 +0000259/* Fetch a byte from the guest insn stream. */
sewardj52d04912005-07-03 00:52:48 +0000260static UChar getIByte ( Int delta )
sewardjd1061ab2004-07-08 01:45:30 +0000261{
262 return guest_code[delta];
263}
264
sewardjc9a65702004-07-07 16:32:57 +0000265/* Extract the reg field from a modRM byte. */
sewardje05c42c2004-07-08 20:25:10 +0000266static Int gregOfRM ( UChar mod_reg_rm )
sewardjc9a65702004-07-07 16:32:57 +0000267{
268 return (Int)( (mod_reg_rm >> 3) & 7 );
269}
270
271/* Figure out whether the mod and rm parts of a modRM byte refer to a
272 register or memory. If so, the byte will have the form 11XXXYYY,
273 where YYY is the register number. */
sewardje05c42c2004-07-08 20:25:10 +0000274static Bool epartIsReg ( UChar mod_reg_rm )
sewardjc9a65702004-07-07 16:32:57 +0000275{
sewardj2d49b432005-02-01 00:37:06 +0000276 return toBool(0xC0 == (mod_reg_rm & 0xC0));
sewardjc9a65702004-07-07 16:32:57 +0000277}
278
279/* ... and extract the register number ... */
sewardje05c42c2004-07-08 20:25:10 +0000280static Int eregOfRM ( UChar mod_reg_rm )
sewardjc9a65702004-07-07 16:32:57 +0000281{
282 return (Int)(mod_reg_rm & 0x7);
283}
284
sewardje05c42c2004-07-08 20:25:10 +0000285/* Get a 8/16/32-bit unsigned value out of the insn stream. */
286
sewardj52d04912005-07-03 00:52:48 +0000287static UChar getUChar ( Int delta )
sewardje05c42c2004-07-08 20:25:10 +0000288{
sewardj2d49b432005-02-01 00:37:06 +0000289 UChar v = guest_code[delta+0];
sewardj9b45b482005-02-07 01:42:18 +0000290 return toUChar(v);
sewardje05c42c2004-07-08 20:25:10 +0000291}
292
sewardj52d04912005-07-03 00:52:48 +0000293static UInt getUDisp16 ( Int delta )
sewardje05c42c2004-07-08 20:25:10 +0000294{
295 UInt v = guest_code[delta+1]; v <<= 8;
296 v |= guest_code[delta+0];
297 return v & 0xFFFF;
298}
299
sewardj52d04912005-07-03 00:52:48 +0000300static UInt getUDisp32 ( Int delta )
sewardjd1061ab2004-07-08 01:45:30 +0000301{
302 UInt v = guest_code[delta+3]; v <<= 8;
303 v |= guest_code[delta+2]; v <<= 8;
304 v |= guest_code[delta+1]; v <<= 8;
305 v |= guest_code[delta+0];
306 return v;
307}
308
sewardj52d04912005-07-03 00:52:48 +0000309static UInt getUDisp ( Int size, Int delta )
sewardje05c42c2004-07-08 20:25:10 +0000310{
311 switch (size) {
312 case 4: return getUDisp32(delta);
313 case 2: return getUDisp16(delta);
sewardj2d49b432005-02-01 00:37:06 +0000314 case 1: return (UInt)getUChar(delta);
sewardje05c42c2004-07-08 20:25:10 +0000315 default: vpanic("getUDisp(x86)");
316 }
317 return 0; /*notreached*/
318}
319
320
sewardjd1061ab2004-07-08 01:45:30 +0000321/* Get a byte value out of the insn stream and sign-extend to 32
322 bits. */
sewardj52d04912005-07-03 00:52:48 +0000323static UInt getSDisp8 ( Int delta )
sewardjd1061ab2004-07-08 01:45:30 +0000324{
325 return extend_s_8to32( (UInt) (guest_code[delta]) );
326}
327
sewardj52d04912005-07-03 00:52:48 +0000328static UInt getSDisp16 ( Int delta0 )
sewardj0611d802004-07-11 02:37:54 +0000329{
330 UChar* eip = (UChar*)(&guest_code[delta0]);
331 UInt d = *eip++;
332 d |= ((*eip++) << 8);
333 return extend_s_16to32(d);
334}
335
sewardj52d04912005-07-03 00:52:48 +0000336static UInt getSDisp ( Int size, Int delta )
sewardj0611d802004-07-11 02:37:54 +0000337{
338 switch (size) {
339 case 4: return getUDisp32(delta);
340 case 2: return getSDisp16(delta);
341 case 1: return getSDisp8(delta);
342 default: vpanic("getSDisp(x86)");
343 }
344 return 0; /*notreached*/
345}
sewardjd1061ab2004-07-08 01:45:30 +0000346
sewardjc9a65702004-07-07 16:32:57 +0000347
348/*------------------------------------------------------------*/
349/*--- Helpers for constructing IR. ---*/
350/*------------------------------------------------------------*/
351
352/* Create a 1/2/4 byte read of an x86 integer registers. For 16/8 bit
353 register references, we need to take the host endianness into
354 account. Supplied value is 0 .. 7 and in the Intel instruction
355 encoding. */
sewardje05c42c2004-07-08 20:25:10 +0000356
sewardj9334b0f2004-07-10 22:43:54 +0000357static IRType szToITy ( Int n )
358{
359 switch (n) {
360 case 1: return Ity_I8;
361 case 2: return Ity_I16;
362 case 4: return Ity_I32;
363 default: vpanic("szToITy(x86)");
364 }
365}
366
sewardj67e002d2004-12-02 18:16:33 +0000367/* On a little-endian host, less significant bits of the guest
368 registers are at lower addresses. Therefore, if a reference to a
369 register low half has the safe guest state offset as a reference to
370 the full register.
371*/
sewardj9334b0f2004-07-10 22:43:54 +0000372static Int integerGuestRegOffset ( Int sz, UInt archreg )
373{
374 vassert(archreg < 8);
375
sewardj9334b0f2004-07-10 22:43:54 +0000376 /* Correct for little-endian host only. */
sewardj67e002d2004-12-02 18:16:33 +0000377 vassert(!host_is_bigendian);
sewardj063f02f2004-10-20 12:36:12 +0000378
379 if (sz == 4 || sz == 2 || (sz == 1 && archreg < 4)) {
380 switch (archreg) {
sewardjc9a43662004-11-30 18:51:59 +0000381 case R_EAX: return OFFB_EAX;
382 case R_EBX: return OFFB_EBX;
383 case R_ECX: return OFFB_ECX;
384 case R_EDX: return OFFB_EDX;
385 case R_ESI: return OFFB_ESI;
386 case R_EDI: return OFFB_EDI;
387 case R_ESP: return OFFB_ESP;
388 case R_EBP: return OFFB_EBP;
sewardj063f02f2004-10-20 12:36:12 +0000389 default: vpanic("integerGuestRegOffset(x86,le)(4,2)");
390 }
391 }
392
393 vassert(archreg >= 4 && archreg < 8 && sz == 1);
394 switch (archreg-4) {
sewardjc9a43662004-11-30 18:51:59 +0000395 case R_EAX: return 1+ OFFB_EAX;
396 case R_EBX: return 1+ OFFB_EBX;
397 case R_ECX: return 1+ OFFB_ECX;
398 case R_EDX: return 1+ OFFB_EDX;
sewardj063f02f2004-10-20 12:36:12 +0000399 default: vpanic("integerGuestRegOffset(x86,le)(1h)");
400 }
401
402 /* NOTREACHED */
403 vpanic("integerGuestRegOffset(x86,le)");
404}
405
406static Int segmentGuestRegOffset ( UInt sreg )
407{
408 switch (sreg) {
sewardjc9a43662004-11-30 18:51:59 +0000409 case R_ES: return OFFB_ES;
410 case R_CS: return OFFB_CS;
411 case R_SS: return OFFB_SS;
412 case R_DS: return OFFB_DS;
413 case R_FS: return OFFB_FS;
414 case R_GS: return OFFB_GS;
sewardj063f02f2004-10-20 12:36:12 +0000415 default: vpanic("segmentGuestRegOffset(x86)");
sewardj9334b0f2004-07-10 22:43:54 +0000416 }
417}
418
sewardjc9a43662004-11-30 18:51:59 +0000419static Int xmmGuestRegOffset ( UInt xmmreg )
420{
421 switch (xmmreg) {
422 case 0: return OFFB_XMM0;
423 case 1: return OFFB_XMM1;
424 case 2: return OFFB_XMM2;
425 case 3: return OFFB_XMM3;
426 case 4: return OFFB_XMM4;
427 case 5: return OFFB_XMM5;
428 case 6: return OFFB_XMM6;
429 case 7: return OFFB_XMM7;
430 default: vpanic("xmmGuestRegOffset");
431 }
432}
433
sewardj67e002d2004-12-02 18:16:33 +0000434/* Lanes of vector registers are always numbered from zero being the
435 least significant lane (rightmost in the register). */
436
sewardje5854d62004-12-09 03:44:34 +0000437static Int xmmGuestRegLane16offset ( UInt xmmreg, Int laneno )
438{
439 /* Correct for little-endian host only. */
440 vassert(!host_is_bigendian);
441 vassert(laneno >= 0 && laneno < 8);
442 return xmmGuestRegOffset( xmmreg ) + 2 * laneno;
443}
444
sewardj67e002d2004-12-02 18:16:33 +0000445static Int xmmGuestRegLane32offset ( UInt xmmreg, Int laneno )
446{
447 /* Correct for little-endian host only. */
448 vassert(!host_is_bigendian);
449 vassert(laneno >= 0 && laneno < 4);
450 return xmmGuestRegOffset( xmmreg ) + 4 * laneno;
451}
452
453static Int xmmGuestRegLane64offset ( UInt xmmreg, Int laneno )
454{
455 /* Correct for little-endian host only. */
456 vassert(!host_is_bigendian);
457 vassert(laneno >= 0 && laneno < 2);
458 return xmmGuestRegOffset( xmmreg ) + 8 * laneno;
459}
460
sewardjd1061ab2004-07-08 01:45:30 +0000461static IRExpr* getIReg ( Int sz, UInt archreg )
sewardjc9a65702004-07-07 16:32:57 +0000462{
463 vassert(sz == 1 || sz == 2 || sz == 4);
464 vassert(archreg < 8);
sewardj9334b0f2004-07-10 22:43:54 +0000465 return IRExpr_Get( integerGuestRegOffset(sz,archreg),
sewardj5bd4d162004-11-10 13:02:48 +0000466 szToITy(sz) );
sewardjc9a65702004-07-07 16:32:57 +0000467}
468
469/* Ditto, but write to a reg instead. */
sewardj41f43bc2004-07-08 14:23:22 +0000470static void putIReg ( Int sz, UInt archreg, IRExpr* e )
sewardjc9a65702004-07-07 16:32:57 +0000471{
sewardjc9a43662004-11-30 18:51:59 +0000472 IRType ty = typeOfIRExpr(irbb->tyenv, e);
sewardjd24931d2005-03-20 12:51:39 +0000473 switch (sz) {
474 case 1: vassert(ty == Ity_I8); break;
475 case 2: vassert(ty == Ity_I16); break;
476 case 4: vassert(ty == Ity_I32); break;
477 default: vpanic("putIReg(x86)");
478 }
sewardjc9a65702004-07-07 16:32:57 +0000479 vassert(archreg < 8);
sewardjeeb9ef82004-07-15 12:39:03 +0000480 stmt( IRStmt_Put(integerGuestRegOffset(sz,archreg), e) );
sewardjd1061ab2004-07-08 01:45:30 +0000481}
482
sewardj063f02f2004-10-20 12:36:12 +0000483static IRExpr* getSReg ( UInt sreg )
484{
485 return IRExpr_Get( segmentGuestRegOffset(sreg), Ity_I16 );
486}
487
488static void putSReg ( UInt sreg, IRExpr* e )
489{
490 vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_I16);
491 stmt( IRStmt_Put( segmentGuestRegOffset(sreg), e ) );
492}
493
sewardjc9a43662004-11-30 18:51:59 +0000494static IRExpr* getXMMReg ( UInt xmmreg )
495{
496 return IRExpr_Get( xmmGuestRegOffset(xmmreg), Ity_V128 );
497}
498
sewardj67e002d2004-12-02 18:16:33 +0000499static IRExpr* getXMMRegLane64 ( UInt xmmreg, Int laneno )
500{
501 return IRExpr_Get( xmmGuestRegLane64offset(xmmreg,laneno), Ity_I64 );
502}
503
sewardjfd226452004-12-07 19:02:18 +0000504static IRExpr* getXMMRegLane64F ( UInt xmmreg, Int laneno )
sewardj67e002d2004-12-02 18:16:33 +0000505{
sewardjfd226452004-12-07 19:02:18 +0000506 return IRExpr_Get( xmmGuestRegLane64offset(xmmreg,laneno), Ity_F64 );
sewardj67e002d2004-12-02 18:16:33 +0000507}
508
sewardj9636b442004-12-04 01:38:37 +0000509static IRExpr* getXMMRegLane32 ( UInt xmmreg, Int laneno )
510{
511 return IRExpr_Get( xmmGuestRegLane32offset(xmmreg,laneno), Ity_I32 );
512}
513
sewardjfd226452004-12-07 19:02:18 +0000514static IRExpr* getXMMRegLane32F ( UInt xmmreg, Int laneno )
515{
516 return IRExpr_Get( xmmGuestRegLane32offset(xmmreg,laneno), Ity_F32 );
517}
518
sewardjc9a43662004-11-30 18:51:59 +0000519static void putXMMReg ( UInt xmmreg, IRExpr* e )
520{
521 vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_V128);
522 stmt( IRStmt_Put( xmmGuestRegOffset(xmmreg), e ) );
523}
524
sewardj67e002d2004-12-02 18:16:33 +0000525static void putXMMRegLane64 ( UInt xmmreg, Int laneno, IRExpr* e )
526{
527 vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_I64);
528 stmt( IRStmt_Put( xmmGuestRegLane64offset(xmmreg,laneno), e ) );
529}
530
sewardjfd226452004-12-07 19:02:18 +0000531static void putXMMRegLane64F ( UInt xmmreg, Int laneno, IRExpr* e )
532{
533 vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_F64);
534 stmt( IRStmt_Put( xmmGuestRegLane64offset(xmmreg,laneno), e ) );
535}
536
sewardj4cb918d2004-12-03 19:43:31 +0000537static void putXMMRegLane32F ( UInt xmmreg, Int laneno, IRExpr* e )
sewardj67e002d2004-12-02 18:16:33 +0000538{
sewardj4cb918d2004-12-03 19:43:31 +0000539 vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_F32);
sewardj67e002d2004-12-02 18:16:33 +0000540 stmt( IRStmt_Put( xmmGuestRegLane32offset(xmmreg,laneno), e ) );
541}
542
sewardj9636b442004-12-04 01:38:37 +0000543static void putXMMRegLane32 ( UInt xmmreg, Int laneno, IRExpr* e )
544{
545 vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_I32);
546 stmt( IRStmt_Put( xmmGuestRegLane32offset(xmmreg,laneno), e ) );
547}
548
sewardje5854d62004-12-09 03:44:34 +0000549static void putXMMRegLane16 ( UInt xmmreg, Int laneno, IRExpr* e )
550{
551 vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_I16);
552 stmt( IRStmt_Put( xmmGuestRegLane16offset(xmmreg,laneno), e ) );
553}
554
sewardj41f43bc2004-07-08 14:23:22 +0000555static void assign ( IRTemp dst, IRExpr* e )
sewardjd1061ab2004-07-08 01:45:30 +0000556{
sewardj41f43bc2004-07-08 14:23:22 +0000557 stmt( IRStmt_Tmp(dst, e) );
sewardjd1061ab2004-07-08 01:45:30 +0000558}
559
sewardj41f43bc2004-07-08 14:23:22 +0000560static void storeLE ( IRExpr* addr, IRExpr* data )
sewardjd1061ab2004-07-08 01:45:30 +0000561{
sewardjaf1ceca2005-06-30 23:31:27 +0000562 stmt( IRStmt_Store(Iend_LE,addr,data) );
sewardjd1061ab2004-07-08 01:45:30 +0000563}
564
sewardje87b4842004-07-10 12:23:30 +0000565static IRExpr* unop ( IROp op, IRExpr* a )
566{
567 return IRExpr_Unop(op, a);
568}
569
sewardjd1061ab2004-07-08 01:45:30 +0000570static IRExpr* binop ( IROp op, IRExpr* a1, IRExpr* a2 )
571{
572 return IRExpr_Binop(op, a1, a2);
573}
574
575static IRExpr* mkexpr ( IRTemp tmp )
576{
577 return IRExpr_Tmp(tmp);
578}
579
sewardjc2ac51e2004-07-12 01:03:26 +0000580static IRExpr* mkU8 ( UInt i )
581{
582 vassert(i < 256);
sewardj2d49b432005-02-01 00:37:06 +0000583 return IRExpr_Const(IRConst_U8( (UChar)i ));
sewardjc2ac51e2004-07-12 01:03:26 +0000584}
585
586static IRExpr* mkU16 ( UInt i )
587{
588 vassert(i < 65536);
sewardj2d49b432005-02-01 00:37:06 +0000589 return IRExpr_Const(IRConst_U16( (UShort)i ));
sewardjc2ac51e2004-07-12 01:03:26 +0000590}
591
sewardjd1061ab2004-07-08 01:45:30 +0000592static IRExpr* mkU32 ( UInt i )
593{
594 return IRExpr_Const(IRConst_U32(i));
sewardjc9a65702004-07-07 16:32:57 +0000595}
596
sewardj95535fe2004-12-15 17:42:58 +0000597static IRExpr* mkU64 ( ULong i )
598{
599 return IRExpr_Const(IRConst_U64(i));
600}
601
sewardj41f43bc2004-07-08 14:23:22 +0000602static IRExpr* mkU ( IRType ty, UInt i )
603{
sewardjc2ac51e2004-07-12 01:03:26 +0000604 if (ty == Ity_I8) return mkU8(i);
605 if (ty == Ity_I16) return mkU16(i);
606 if (ty == Ity_I32) return mkU32(i);
sewardje90ad6a2004-07-10 19:02:10 +0000607 /* If this panics, it usually means you passed a size (1,2,4)
608 value as the IRType, rather than a real IRType. */
sewardj41f43bc2004-07-08 14:23:22 +0000609 vpanic("mkU(x86)");
610}
611
sewardj1e6ad742004-12-02 16:16:11 +0000612static IRExpr* mkV128 ( UShort mask )
613{
614 return IRExpr_Const(IRConst_V128(mask));
615}
616
sewardj41f43bc2004-07-08 14:23:22 +0000617static IRExpr* loadLE ( IRType ty, IRExpr* data )
618{
sewardjaf1ceca2005-06-30 23:31:27 +0000619 return IRExpr_Load(Iend_LE,ty,data);
sewardj41f43bc2004-07-08 14:23:22 +0000620}
621
622static IROp mkSizedOp ( IRType ty, IROp op8 )
623{
sewardje05c42c2004-07-08 20:25:10 +0000624 Int adj;
sewardj41f43bc2004-07-08 14:23:22 +0000625 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
626 vassert(op8 == Iop_Add8 || op8 == Iop_Sub8
sewardj41f43bc2004-07-08 14:23:22 +0000627 || op8 == Iop_Mul8
628 || op8 == Iop_Or8 || op8 == Iop_And8 || op8 == Iop_Xor8
sewardj5bd4d162004-11-10 13:02:48 +0000629 || op8 == Iop_Shl8 || op8 == Iop_Shr8 || op8 == Iop_Sar8
sewardje90ad6a2004-07-10 19:02:10 +0000630 || op8 == Iop_CmpEQ8 || op8 == Iop_CmpNE8
sewardj71a35e72005-05-03 12:20:15 +0000631 || op8 == Iop_Not8 || op8 == Iop_Neg8);
sewardje05c42c2004-07-08 20:25:10 +0000632 adj = ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
633 return adj + op8;
sewardj41f43bc2004-07-08 14:23:22 +0000634}
635
sewardj9334b0f2004-07-10 22:43:54 +0000636static IROp mkWidenOp ( Int szSmall, Int szBig, Bool signd )
sewardj41f43bc2004-07-08 14:23:22 +0000637{
sewardj9334b0f2004-07-10 22:43:54 +0000638 if (szSmall == 1 && szBig == 4) {
639 return signd ? Iop_8Sto32 : Iop_8Uto32;
sewardj41f43bc2004-07-08 14:23:22 +0000640 }
sewardj9334b0f2004-07-10 22:43:54 +0000641 if (szSmall == 1 && szBig == 2) {
642 return signd ? Iop_8Sto16 : Iop_8Uto16;
643 }
644 if (szSmall == 2 && szBig == 4) {
645 return signd ? Iop_16Sto32 : Iop_16Uto32;
646 }
sewardj948d48b2004-11-05 19:49:09 +0000647 vpanic("mkWidenOp(x86,guest)");
sewardj41f43bc2004-07-08 14:23:22 +0000648}
649
650
651/*------------------------------------------------------------*/
652/*--- Helpers for %eflags. ---*/
653/*------------------------------------------------------------*/
654
sewardj0611d802004-07-11 02:37:54 +0000655/* -------------- Evaluating the flags-thunk. -------------- */
sewardjc9a65702004-07-07 16:32:57 +0000656
sewardje87b4842004-07-10 12:23:30 +0000657/* Build IR to calculate all the eflags from stored
sewardj2a2ba8b2004-11-08 13:14:06 +0000658 CC_OP/CC_DEP1/CC_DEP2/CC_NDEP. Returns an expression ::
659 Ity_I32. */
sewardj2a9ad022004-11-25 02:46:58 +0000660static IRExpr* mk_x86g_calculate_eflags_all ( void )
sewardje87b4842004-07-10 12:23:30 +0000661{
sewardjf9655262004-10-31 20:02:16 +0000662 IRExpr** args
sewardj2a2ba8b2004-11-08 13:14:06 +0000663 = mkIRExprVec_4( IRExpr_Get(OFFB_CC_OP, Ity_I32),
664 IRExpr_Get(OFFB_CC_DEP1, Ity_I32),
665 IRExpr_Get(OFFB_CC_DEP2, Ity_I32),
666 IRExpr_Get(OFFB_CC_NDEP, Ity_I32) );
sewardj43c56462004-11-06 12:17:57 +0000667 IRExpr* call
668 = mkIRExprCCall(
669 Ity_I32,
670 0/*regparm*/,
sewardj2a9ad022004-11-25 02:46:58 +0000671 "x86g_calculate_eflags_all", &x86g_calculate_eflags_all,
sewardj43c56462004-11-06 12:17:57 +0000672 args
673 );
sewardj2a2ba8b2004-11-08 13:14:06 +0000674 /* Exclude OP and NDEP from definedness checking. We're only
675 interested in DEP1 and DEP2. */
676 call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<3);
sewardj43c56462004-11-06 12:17:57 +0000677 return call;
sewardje87b4842004-07-10 12:23:30 +0000678}
679
sewardj84ff0652004-08-23 16:16:08 +0000680/* Build IR to calculate some particular condition from stored
sewardj2a2ba8b2004-11-08 13:14:06 +0000681 CC_OP/CC_DEP1/CC_DEP2/CC_NDEP. Returns an expression ::
682 Ity_Bit. */
sewardj2a9ad022004-11-25 02:46:58 +0000683static IRExpr* mk_x86g_calculate_condition ( X86Condcode cond )
sewardj84ff0652004-08-23 16:16:08 +0000684{
sewardjf9655262004-10-31 20:02:16 +0000685 IRExpr** args
sewardj2a2ba8b2004-11-08 13:14:06 +0000686 = mkIRExprVec_5( mkU32(cond),
sewardjf9655262004-10-31 20:02:16 +0000687 IRExpr_Get(OFFB_CC_OP, Ity_I32),
sewardj2a2ba8b2004-11-08 13:14:06 +0000688 IRExpr_Get(OFFB_CC_DEP1, Ity_I32),
689 IRExpr_Get(OFFB_CC_DEP2, Ity_I32),
690 IRExpr_Get(OFFB_CC_NDEP, Ity_I32) );
sewardj43c56462004-11-06 12:17:57 +0000691 IRExpr* call
692 = mkIRExprCCall(
693 Ity_I32,
694 0/*regparm*/,
sewardj2a9ad022004-11-25 02:46:58 +0000695 "x86g_calculate_condition", &x86g_calculate_condition,
sewardj43c56462004-11-06 12:17:57 +0000696 args
697 );
sewardj2a2ba8b2004-11-08 13:14:06 +0000698 /* Exclude the requested condition, OP and NDEP from definedness
699 checking. We're only interested in DEP1 and DEP2. */
700 call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<1) | (1<<4);
sewardj43c56462004-11-06 12:17:57 +0000701 return unop(Iop_32to1, call);
702}
703
704/* Build IR to calculate just the carry flag from stored
sewardj2a2ba8b2004-11-08 13:14:06 +0000705 CC_OP/CC_DEP1/CC_DEP2/CC_NDEP. Returns an expression :: Ity_I32. */
sewardj2a9ad022004-11-25 02:46:58 +0000706static IRExpr* mk_x86g_calculate_eflags_c ( void )
sewardj43c56462004-11-06 12:17:57 +0000707{
708 IRExpr** args
sewardj2a2ba8b2004-11-08 13:14:06 +0000709 = mkIRExprVec_4( IRExpr_Get(OFFB_CC_OP, Ity_I32),
710 IRExpr_Get(OFFB_CC_DEP1, Ity_I32),
711 IRExpr_Get(OFFB_CC_DEP2, Ity_I32),
712 IRExpr_Get(OFFB_CC_NDEP, Ity_I32) );
sewardj43c56462004-11-06 12:17:57 +0000713 IRExpr* call
714 = mkIRExprCCall(
715 Ity_I32,
sewardj893a3302005-01-24 10:49:02 +0000716 3/*regparm*/,
sewardj2a9ad022004-11-25 02:46:58 +0000717 "x86g_calculate_eflags_c", &x86g_calculate_eflags_c,
sewardj43c56462004-11-06 12:17:57 +0000718 args
719 );
sewardj2a2ba8b2004-11-08 13:14:06 +0000720 /* Exclude OP and NDEP from definedness checking. We're only
721 interested in DEP1 and DEP2. */
722 call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<3);
sewardj43c56462004-11-06 12:17:57 +0000723 return call;
sewardj84ff0652004-08-23 16:16:08 +0000724}
725
sewardje87b4842004-07-10 12:23:30 +0000726
sewardj0611d802004-07-11 02:37:54 +0000727/* -------------- Building the flags-thunk. -------------- */
728
sewardjb9c5cf62004-08-24 15:10:38 +0000729/* The machinery in this section builds the flag-thunk following a
730 flag-setting operation. Hence the various setFlags_* functions.
sewardjb9c5cf62004-08-24 15:10:38 +0000731*/
732
733static Bool isAddSub ( IROp op8 )
734{
sewardj2d49b432005-02-01 00:37:06 +0000735 return toBool(op8 == Iop_Add8 || op8 == Iop_Sub8);
sewardjb9c5cf62004-08-24 15:10:38 +0000736}
sewardj0611d802004-07-11 02:37:54 +0000737
sewardj2a2ba8b2004-11-08 13:14:06 +0000738static Bool isLogic ( IROp op8 )
739{
sewardj2d49b432005-02-01 00:37:06 +0000740 return toBool(op8 == Iop_And8 || op8 == Iop_Or8 || op8 == Iop_Xor8);
sewardj2a2ba8b2004-11-08 13:14:06 +0000741}
742
sewardja2384712004-07-29 14:36:40 +0000743/* U-widen 8/16/32 bit int expr to 32. */
sewardjc22a6fd2004-07-29 23:41:47 +0000744static IRExpr* widenUto32 ( IRExpr* e )
sewardj443cd9d2004-07-18 23:06:45 +0000745{
746 switch (typeOfIRExpr(irbb->tyenv,e)) {
747 case Ity_I32: return e;
748 case Ity_I16: return unop(Iop_16Uto32,e);
749 case Ity_I8: return unop(Iop_8Uto32,e);
750 default: vpanic("widenUto32");
751 }
752}
753
sewardjc22a6fd2004-07-29 23:41:47 +0000754/* S-widen 8/16/32 bit int expr to 32. */
755static IRExpr* widenSto32 ( IRExpr* e )
756{
757 switch (typeOfIRExpr(irbb->tyenv,e)) {
758 case Ity_I32: return e;
759 case Ity_I16: return unop(Iop_16Sto32,e);
760 case Ity_I8: return unop(Iop_8Sto32,e);
761 default: vpanic("widenSto32");
762 }
763}
764
sewardja2384712004-07-29 14:36:40 +0000765/* Narrow 8/16/32 bit int expr to 8/16/32. Clearly only some
766 of these combinations make sense. */
767static IRExpr* narrowTo ( IRType dst_ty, IRExpr* e )
768{
769 IRType src_ty = typeOfIRExpr(irbb->tyenv,e);
770 if (src_ty == dst_ty)
771 return e;
772 if (src_ty == Ity_I32 && dst_ty == Ity_I16)
773 return unop(Iop_32to16, e);
774 if (src_ty == Ity_I32 && dst_ty == Ity_I8)
775 return unop(Iop_32to8, e);
776
777 vex_printf("\nsrc, dst tys are: ");
778 ppIRType(src_ty);
779 vex_printf(", ");
780 ppIRType(dst_ty);
781 vex_printf("\n");
782 vpanic("narrowTo(x86)");
783}
784
sewardj443cd9d2004-07-18 23:06:45 +0000785
sewardj2a2ba8b2004-11-08 13:14:06 +0000786/* Set the flags thunk OP, DEP1 and DEP2 fields. The supplied op is
sewardj948d48b2004-11-05 19:49:09 +0000787 auto-sized up to the real op. */
sewardj0611d802004-07-11 02:37:54 +0000788
sewardj2a2ba8b2004-11-08 13:14:06 +0000789static
790void setFlags_DEP1_DEP2 ( IROp op8, IRTemp dep1, IRTemp dep2, IRType ty )
sewardj0611d802004-07-11 02:37:54 +0000791{
sewardjb9c5cf62004-08-24 15:10:38 +0000792 Int ccOp = ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
793
794 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
795
796 switch (op8) {
sewardj2a9ad022004-11-25 02:46:58 +0000797 case Iop_Add8: ccOp += X86G_CC_OP_ADDB; break;
798 case Iop_Sub8: ccOp += X86G_CC_OP_SUBB; break;
sewardjb9c5cf62004-08-24 15:10:38 +0000799 default: ppIROp(op8);
sewardj2a2ba8b2004-11-08 13:14:06 +0000800 vpanic("setFlags_DEP1_DEP2(x86)");
sewardjb9c5cf62004-08-24 15:10:38 +0000801 }
sewardj2a2ba8b2004-11-08 13:14:06 +0000802 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(ccOp)) );
803 stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto32(mkexpr(dep1))) );
804 stmt( IRStmt_Put( OFFB_CC_DEP2, widenUto32(mkexpr(dep2))) );
sewardja3b7e3a2005-04-05 01:54:19 +0000805 /* Set NDEP even though it isn't used. This makes redundant-PUT
806 elimination of previous stores to this field work better. */
807 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardjb9c5cf62004-08-24 15:10:38 +0000808}
809
810
sewardj2a2ba8b2004-11-08 13:14:06 +0000811/* Set the OP and DEP1 fields only, and write zero to DEP2. */
sewardjb9c5cf62004-08-24 15:10:38 +0000812
sewardj2a2ba8b2004-11-08 13:14:06 +0000813static
814void setFlags_DEP1 ( IROp op8, IRTemp dep1, IRType ty )
sewardjb9c5cf62004-08-24 15:10:38 +0000815{
816 Int ccOp = ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
sewardj0611d802004-07-11 02:37:54 +0000817
818 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
819
820 switch (op8) {
821 case Iop_Or8:
822 case Iop_And8:
sewardj2a9ad022004-11-25 02:46:58 +0000823 case Iop_Xor8: ccOp += X86G_CC_OP_LOGICB; break;
sewardj0611d802004-07-11 02:37:54 +0000824 default: ppIROp(op8);
sewardj2a2ba8b2004-11-08 13:14:06 +0000825 vpanic("setFlags_DEP1(x86)");
sewardj0611d802004-07-11 02:37:54 +0000826 }
sewardj2a2ba8b2004-11-08 13:14:06 +0000827 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(ccOp)) );
828 stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto32(mkexpr(dep1))) );
829 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0)) );
sewardja3b7e3a2005-04-05 01:54:19 +0000830 /* Set NDEP even though it isn't used. This makes redundant-PUT
831 elimination of previous stores to this field work better. */
832 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardj0611d802004-07-11 02:37:54 +0000833}
834
835
sewardj948d48b2004-11-05 19:49:09 +0000836/* For shift operations, we put in the result and the undershifted
837 result. Except if the shift amount is zero, the thunk is left
838 unchanged. */
sewardj0611d802004-07-11 02:37:54 +0000839
sewardj2a2ba8b2004-11-08 13:14:06 +0000840static void setFlags_DEP1_DEP2_shift ( IROp op32,
841 IRTemp res,
842 IRTemp resUS,
843 IRType ty,
844 IRTemp guard )
sewardj0611d802004-07-11 02:37:54 +0000845{
sewardjc22a6fd2004-07-29 23:41:47 +0000846 Int ccOp = ty==Ity_I8 ? 2 : (ty==Ity_I16 ? 1 : 0);
sewardj0611d802004-07-11 02:37:54 +0000847
848 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
849 vassert(guard);
850
sewardj2a2ba8b2004-11-08 13:14:06 +0000851 /* Both kinds of right shifts are handled by the same thunk
852 operation. */
sewardjc22a6fd2004-07-29 23:41:47 +0000853 switch (op32) {
854 case Iop_Shr32:
sewardj2a9ad022004-11-25 02:46:58 +0000855 case Iop_Sar32: ccOp = X86G_CC_OP_SHRL - ccOp; break;
856 case Iop_Shl32: ccOp = X86G_CC_OP_SHLL - ccOp; break;
sewardjc22a6fd2004-07-29 23:41:47 +0000857 default: ppIROp(op32);
sewardj2a2ba8b2004-11-08 13:14:06 +0000858 vpanic("setFlags_DEP1_DEP2_shift(x86)");
sewardj0611d802004-07-11 02:37:54 +0000859 }
860
sewardj2a2ba8b2004-11-08 13:14:06 +0000861 /* DEP1 contains the result, DEP2 contains the undershifted value. */
sewardjeeb9ef82004-07-15 12:39:03 +0000862 stmt( IRStmt_Put( OFFB_CC_OP,
sewardj4042c7e2004-07-18 01:28:30 +0000863 IRExpr_Mux0X( mkexpr(guard),
864 IRExpr_Get(OFFB_CC_OP,Ity_I32),
865 mkU32(ccOp))) );
sewardj2a2ba8b2004-11-08 13:14:06 +0000866 stmt( IRStmt_Put( OFFB_CC_DEP1,
sewardj4042c7e2004-07-18 01:28:30 +0000867 IRExpr_Mux0X( mkexpr(guard),
sewardj2a2ba8b2004-11-08 13:14:06 +0000868 IRExpr_Get(OFFB_CC_DEP1,Ity_I32),
sewardj948d48b2004-11-05 19:49:09 +0000869 widenUto32(mkexpr(res)))) );
sewardj2a2ba8b2004-11-08 13:14:06 +0000870 stmt( IRStmt_Put( OFFB_CC_DEP2,
sewardj4042c7e2004-07-18 01:28:30 +0000871 IRExpr_Mux0X( mkexpr(guard),
sewardj2a2ba8b2004-11-08 13:14:06 +0000872 IRExpr_Get(OFFB_CC_DEP2,Ity_I32),
sewardj948d48b2004-11-05 19:49:09 +0000873 widenUto32(mkexpr(resUS)))) );
sewardja3b7e3a2005-04-05 01:54:19 +0000874 /* Set NDEP even though it isn't used. This makes redundant-PUT
875 elimination of previous stores to this field work better. */
876 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardj0611d802004-07-11 02:37:54 +0000877}
878
879
sewardj2a2ba8b2004-11-08 13:14:06 +0000880/* For the inc/dec case, we store in DEP1 the result value and in NDEP
sewardj948d48b2004-11-05 19:49:09 +0000881 the former value of the carry flag, which unfortunately we have to
882 compute. */
sewardj0611d802004-07-11 02:37:54 +0000883
sewardj948d48b2004-11-05 19:49:09 +0000884static void setFlags_INC_DEC ( Bool inc, IRTemp res, IRType ty )
sewardj0611d802004-07-11 02:37:54 +0000885{
sewardj2a9ad022004-11-25 02:46:58 +0000886 Int ccOp = inc ? X86G_CC_OP_INCB : X86G_CC_OP_DECB;
sewardj0611d802004-07-11 02:37:54 +0000887
888 ccOp += ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
889 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
890
891 /* This has to come first, because calculating the C flag
sewardj2a2ba8b2004-11-08 13:14:06 +0000892 may require reading all four thunk fields. */
sewardj2a9ad022004-11-25 02:46:58 +0000893 stmt( IRStmt_Put( OFFB_CC_NDEP, mk_x86g_calculate_eflags_c()) );
sewardj2a2ba8b2004-11-08 13:14:06 +0000894 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(ccOp)) );
895 stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(res)) );
896 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0)) );
sewardj0611d802004-07-11 02:37:54 +0000897}
898
899
sewardj2a2ba8b2004-11-08 13:14:06 +0000900/* Multiplies are pretty much like add and sub: DEP1 and DEP2 hold the
901 two arguments. */
sewardjcf780b42004-07-13 18:42:17 +0000902
903static
sewardj2a2ba8b2004-11-08 13:14:06 +0000904void setFlags_MUL ( IRType ty, IRTemp arg1, IRTemp arg2, UInt base_op )
sewardjcf780b42004-07-13 18:42:17 +0000905{
906 switch (ty) {
sewardj2a2ba8b2004-11-08 13:14:06 +0000907 case Ity_I8:
908 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(base_op+0) ) );
909 break;
910 case Ity_I16:
911 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(base_op+1) ) );
912 break;
913 case Ity_I32:
914 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(base_op+2) ) );
915 break;
916 default:
917 vpanic("setFlags_MUL(x86)");
sewardjcf780b42004-07-13 18:42:17 +0000918 }
sewardj2a2ba8b2004-11-08 13:14:06 +0000919 stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto32(mkexpr(arg1)) ));
920 stmt( IRStmt_Put( OFFB_CC_DEP2, widenUto32(mkexpr(arg2)) ));
sewardja3b7e3a2005-04-05 01:54:19 +0000921 /* Set NDEP even though it isn't used. This makes redundant-PUT
922 elimination of previous stores to this field work better. */
923 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardjcf780b42004-07-13 18:42:17 +0000924}
925
926
sewardj3af115f2004-07-14 02:46:52 +0000927/* -------------- Condition codes. -------------- */
928
sewardje87b4842004-07-10 12:23:30 +0000929/* Condition codes, using the Intel encoding. */
sewardj0611d802004-07-11 02:37:54 +0000930
sewardj2d49b432005-02-01 00:37:06 +0000931static HChar* name_X86Condcode ( X86Condcode cond )
sewardje87b4842004-07-10 12:23:30 +0000932{
933 switch (cond) {
sewardj2a9ad022004-11-25 02:46:58 +0000934 case X86CondO: return "o";
935 case X86CondNO: return "no";
936 case X86CondB: return "b";
937 case X86CondNB: return "nb";
938 case X86CondZ: return "z";
939 case X86CondNZ: return "nz";
940 case X86CondBE: return "be";
941 case X86CondNBE: return "nbe";
942 case X86CondS: return "s";
943 case X86CondNS: return "ns";
944 case X86CondP: return "p";
945 case X86CondNP: return "np";
946 case X86CondL: return "l";
947 case X86CondNL: return "nl";
948 case X86CondLE: return "le";
949 case X86CondNLE: return "nle";
950 case X86CondAlways: return "ALWAYS";
951 default: vpanic("name_X86Condcode");
sewardje87b4842004-07-10 12:23:30 +0000952 }
953}
954
sewardj2a9ad022004-11-25 02:46:58 +0000955static
956X86Condcode positiveIse_X86Condcode ( X86Condcode cond,
sewardjdbf550c2005-01-24 11:54:11 +0000957 Bool* needInvert )
sewardje87b4842004-07-10 12:23:30 +0000958{
sewardj2a9ad022004-11-25 02:46:58 +0000959 vassert(cond >= X86CondO && cond <= X86CondNLE);
sewardje87b4842004-07-10 12:23:30 +0000960 if (cond & 1) {
961 *needInvert = True;
962 return cond-1;
963 } else {
964 *needInvert = False;
965 return cond;
966 }
967}
968
969
sewardj3af115f2004-07-14 02:46:52 +0000970/* -------------- Helpers for ADD/SUB with carry. -------------- */
971
sewardj948d48b2004-11-05 19:49:09 +0000972/* Given ta1, ta2 and tres, compute tres = ADC(ta1,ta2) and set flags
sewardj2a2ba8b2004-11-08 13:14:06 +0000973 appropriately.
sewardj3af115f2004-07-14 02:46:52 +0000974*/
975static void helper_ADC ( Int sz,
sewardj5bd4d162004-11-10 13:02:48 +0000976 IRTemp tres, IRTemp ta1, IRTemp ta2 )
sewardj3af115f2004-07-14 02:46:52 +0000977{
978 UInt thunkOp;
sewardj2a2ba8b2004-11-08 13:14:06 +0000979 IRType ty = szToITy(sz);
980 IRTemp oldc = newTemp(Ity_I32);
981 IRTemp oldcn = newTemp(ty);
982 IROp plus = mkSizedOp(ty, Iop_Add8);
983 IROp xor = mkSizedOp(ty, Iop_Xor8);
sewardja2384712004-07-29 14:36:40 +0000984
985 vassert(sz == 1 || sz == 2 || sz == 4);
sewardj2a9ad022004-11-25 02:46:58 +0000986 thunkOp = sz==4 ? X86G_CC_OP_ADCL
987 : (sz==2 ? X86G_CC_OP_ADCW : X86G_CC_OP_ADCB);
sewardj3af115f2004-07-14 02:46:52 +0000988
sewardj2a2ba8b2004-11-08 13:14:06 +0000989 /* oldc = old carry flag, 0 or 1 */
990 assign( oldc, binop(Iop_And32,
sewardj2a9ad022004-11-25 02:46:58 +0000991 mk_x86g_calculate_eflags_c(),
sewardj5bd4d162004-11-10 13:02:48 +0000992 mkU32(1)) );
sewardj3af115f2004-07-14 02:46:52 +0000993
sewardj2a2ba8b2004-11-08 13:14:06 +0000994 assign( oldcn, narrowTo(ty, mkexpr(oldc)) );
995
996 assign( tres, binop(plus,
997 binop(plus,mkexpr(ta1),mkexpr(ta2)),
998 mkexpr(oldcn)) );
999
1000 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(thunkOp) ) );
1001 stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(ta1) ) );
sewardj2a9ad022004-11-25 02:46:58 +00001002 stmt( IRStmt_Put( OFFB_CC_DEP2, binop(xor, mkexpr(ta2),
1003 mkexpr(oldcn)) ) );
sewardj2a2ba8b2004-11-08 13:14:06 +00001004 stmt( IRStmt_Put( OFFB_CC_NDEP, mkexpr(oldc) ) );
sewardj3af115f2004-07-14 02:46:52 +00001005}
1006
1007
sewardj948d48b2004-11-05 19:49:09 +00001008/* Given ta1, ta2 and tres, compute tres = SBB(ta1,ta2) and set flags
sewardj2a2ba8b2004-11-08 13:14:06 +00001009 appropriately.
sewardjcaca9d02004-07-28 07:11:32 +00001010*/
1011static void helper_SBB ( Int sz,
sewardj5bd4d162004-11-10 13:02:48 +00001012 IRTemp tres, IRTemp ta1, IRTemp ta2 )
sewardjcaca9d02004-07-28 07:11:32 +00001013{
1014 UInt thunkOp;
sewardj2a2ba8b2004-11-08 13:14:06 +00001015 IRType ty = szToITy(sz);
1016 IRTemp oldc = newTemp(Ity_I32);
1017 IRTemp oldcn = newTemp(ty);
1018 IROp minus = mkSizedOp(ty, Iop_Sub8);
1019 IROp xor = mkSizedOp(ty, Iop_Xor8);
1020
1021 vassert(sz == 1 || sz == 2 || sz == 4);
sewardj2a9ad022004-11-25 02:46:58 +00001022 thunkOp = sz==4 ? X86G_CC_OP_SBBL
1023 : (sz==2 ? X86G_CC_OP_SBBW : X86G_CC_OP_SBBB);
sewardjcaca9d02004-07-28 07:11:32 +00001024
1025 /* oldc = old carry flag, 0 or 1 */
sewardja2384712004-07-29 14:36:40 +00001026 assign( oldc, binop(Iop_And32,
sewardj2a9ad022004-11-25 02:46:58 +00001027 mk_x86g_calculate_eflags_c(),
sewardj5bd4d162004-11-10 13:02:48 +00001028 mkU32(1)) );
sewardjcaca9d02004-07-28 07:11:32 +00001029
sewardj2a2ba8b2004-11-08 13:14:06 +00001030 assign( oldcn, narrowTo(ty, mkexpr(oldc)) );
sewardja2384712004-07-29 14:36:40 +00001031
sewardj2a2ba8b2004-11-08 13:14:06 +00001032 assign( tres, binop(minus,
1033 binop(minus,mkexpr(ta1),mkexpr(ta2)),
1034 mkexpr(oldcn)) );
sewardjcaca9d02004-07-28 07:11:32 +00001035
sewardj2a2ba8b2004-11-08 13:14:06 +00001036 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(thunkOp) ) );
1037 stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(ta1) ) );
sewardj2a9ad022004-11-25 02:46:58 +00001038 stmt( IRStmt_Put( OFFB_CC_DEP2, binop(xor, mkexpr(ta2),
1039 mkexpr(oldcn)) ) );
sewardj2a2ba8b2004-11-08 13:14:06 +00001040 stmt( IRStmt_Put( OFFB_CC_NDEP, mkexpr(oldc) ) );
sewardjcaca9d02004-07-28 07:11:32 +00001041}
1042
1043
sewardj7dd2eb22005-01-05 10:38:54 +00001044/* -------------- Helpers for disassembly printing. -------------- */
sewardj41f43bc2004-07-08 14:23:22 +00001045
sewardjc9a43662004-11-30 18:51:59 +00001046static HChar* nameGrp1 ( Int opc_aux )
sewardj41f43bc2004-07-08 14:23:22 +00001047{
sewardjc9a43662004-11-30 18:51:59 +00001048 static HChar* grp1_names[8]
sewardj41f43bc2004-07-08 14:23:22 +00001049 = { "add", "or", "adc", "sbb", "and", "sub", "xor", "cmp" };
1050 if (opc_aux < 0 || opc_aux > 7) vpanic("nameGrp1(x86)");
1051 return grp1_names[opc_aux];
1052}
1053
sewardjc9a43662004-11-30 18:51:59 +00001054static HChar* nameGrp2 ( Int opc_aux )
sewardje90ad6a2004-07-10 19:02:10 +00001055{
sewardjc9a43662004-11-30 18:51:59 +00001056 static HChar* grp2_names[8]
sewardje90ad6a2004-07-10 19:02:10 +00001057 = { "rol", "ror", "rcl", "rcr", "shl", "shr", "shl", "sar" };
sewardjc2ac51e2004-07-12 01:03:26 +00001058 if (opc_aux < 0 || opc_aux > 7) vpanic("nameGrp2(x86)");
sewardje90ad6a2004-07-10 19:02:10 +00001059 return grp2_names[opc_aux];
1060}
1061
sewardjc9a43662004-11-30 18:51:59 +00001062static HChar* nameGrp4 ( Int opc_aux )
sewardjc2ac51e2004-07-12 01:03:26 +00001063{
sewardjc9a43662004-11-30 18:51:59 +00001064 static HChar* grp4_names[8]
sewardjc2ac51e2004-07-12 01:03:26 +00001065 = { "inc", "dec", "???", "???", "???", "???", "???", "???" };
1066 if (opc_aux < 0 || opc_aux > 1) vpanic("nameGrp4(x86)");
1067 return grp4_names[opc_aux];
1068}
sewardj0611d802004-07-11 02:37:54 +00001069
sewardjc9a43662004-11-30 18:51:59 +00001070static HChar* nameGrp5 ( Int opc_aux )
sewardj0611d802004-07-11 02:37:54 +00001071{
sewardjc9a43662004-11-30 18:51:59 +00001072 static HChar* grp5_names[8]
sewardj0611d802004-07-11 02:37:54 +00001073 = { "inc", "dec", "call*", "call*", "jmp*", "jmp*", "push", "???" };
1074 if (opc_aux < 0 || opc_aux > 6) vpanic("nameGrp5(x86)");
1075 return grp5_names[opc_aux];
1076}
1077
sewardj490ad382005-03-13 17:25:53 +00001078static HChar* nameGrp8 ( Int opc_aux )
1079{
1080 static HChar* grp8_names[8]
1081 = { "???", "???", "???", "???", "bt", "bts", "btr", "btc" };
1082 if (opc_aux < 4 || opc_aux > 7) vpanic("nameGrp8(x86)");
1083 return grp8_names[opc_aux];
1084}
sewardjc9a65702004-07-07 16:32:57 +00001085
sewardjc9a43662004-11-30 18:51:59 +00001086static HChar* nameIReg ( Int size, Int reg )
sewardjc9a65702004-07-07 16:32:57 +00001087{
sewardjc9a43662004-11-30 18:51:59 +00001088 static HChar* ireg32_names[8]
sewardjc9a65702004-07-07 16:32:57 +00001089 = { "%eax", "%ecx", "%edx", "%ebx",
1090 "%esp", "%ebp", "%esi", "%edi" };
sewardjc9a43662004-11-30 18:51:59 +00001091 static HChar* ireg16_names[8]
sewardjc9a65702004-07-07 16:32:57 +00001092 = { "%ax", "%cx", "%dx", "%bx", "%sp", "%bp", "%si", "%di" };
sewardjc9a43662004-11-30 18:51:59 +00001093 static HChar* ireg8_names[8]
sewardjc9a65702004-07-07 16:32:57 +00001094 = { "%al", "%cl", "%dl", "%bl",
1095 "%ah{sp}", "%ch{bp}", "%dh{si}", "%bh{di}" };
1096 if (reg < 0 || reg > 7) goto bad;
1097 switch (size) {
1098 case 4: return ireg32_names[reg];
1099 case 2: return ireg16_names[reg];
1100 case 1: return ireg8_names[reg];
1101 }
1102 bad:
1103 vpanic("nameIReg(X86)");
1104 return NULL; /*notreached*/
1105}
1106
sewardjc9a43662004-11-30 18:51:59 +00001107static HChar* nameSReg ( UInt sreg )
sewardj063f02f2004-10-20 12:36:12 +00001108{
1109 switch (sreg) {
1110 case R_ES: return "%es";
1111 case R_CS: return "%cs";
1112 case R_SS: return "%ss";
1113 case R_DS: return "%ds";
1114 case R_FS: return "%fs";
1115 case R_GS: return "%gs";
1116 default: vpanic("nameSReg(x86)");
1117 }
1118}
1119
sewardjc9a43662004-11-30 18:51:59 +00001120static HChar* nameMMXReg ( Int mmxreg )
sewardj464efa42004-11-19 22:17:29 +00001121{
sewardjc9a43662004-11-30 18:51:59 +00001122 static HChar* mmx_names[8]
sewardj464efa42004-11-19 22:17:29 +00001123 = { "%mm0", "%mm1", "%mm2", "%mm3", "%mm4", "%mm5", "%mm6", "%mm7" };
1124 if (mmxreg < 0 || mmxreg > 7) vpanic("nameMMXReg(x86,guest)");
1125 return mmx_names[mmxreg];
1126}
1127
sewardjc9a43662004-11-30 18:51:59 +00001128static HChar* nameXMMReg ( Int xmmreg )
1129{
1130 static HChar* xmm_names[8]
1131 = { "%xmm0", "%xmm1", "%xmm2", "%xmm3",
1132 "%xmm4", "%xmm5", "%xmm6", "%xmm7" };
1133 if (xmmreg < 0 || xmmreg > 7) vpanic("name_of_xmm_reg");
1134 return xmm_names[xmmreg];
1135}
sewardj464efa42004-11-19 22:17:29 +00001136
sewardj2d49b432005-02-01 00:37:06 +00001137static HChar* nameMMXGran ( Int gran )
sewardj464efa42004-11-19 22:17:29 +00001138{
1139 switch (gran) {
1140 case 0: return "b";
1141 case 1: return "w";
1142 case 2: return "d";
1143 case 3: return "q";
1144 default: vpanic("nameMMXGran(x86,guest)");
1145 }
1146}
sewardjc9a65702004-07-07 16:32:57 +00001147
sewardj2d49b432005-02-01 00:37:06 +00001148static HChar nameISize ( Int size )
sewardjc9a65702004-07-07 16:32:57 +00001149{
1150 switch (size) {
1151 case 4: return 'l';
1152 case 2: return 'w';
1153 case 1: return 'b';
1154 default: vpanic("nameISize(x86)");
1155 }
1156}
1157
sewardjd1061ab2004-07-08 01:45:30 +00001158
1159/*------------------------------------------------------------*/
1160/*--- JMP helpers ---*/
1161/*------------------------------------------------------------*/
1162
sewardj78c19df2004-07-12 22:49:27 +00001163static void jmp_lit( IRJumpKind kind, Addr32 d32 )
sewardjd1061ab2004-07-08 01:45:30 +00001164{
sewardje539a402004-07-14 18:24:17 +00001165 irbb->next = mkU32(d32);
1166 irbb->jumpkind = kind;
sewardjd1061ab2004-07-08 01:45:30 +00001167}
1168
sewardj78c19df2004-07-12 22:49:27 +00001169static void jmp_treg( IRJumpKind kind, IRTemp t )
sewardje05c42c2004-07-08 20:25:10 +00001170{
sewardje539a402004-07-14 18:24:17 +00001171 irbb->next = mkexpr(t);
1172 irbb->jumpkind = kind;
sewardje05c42c2004-07-08 20:25:10 +00001173}
sewardje87b4842004-07-10 12:23:30 +00001174
sewardj2a9ad022004-11-25 02:46:58 +00001175static
1176void jcc_01( X86Condcode cond, Addr32 d32_false, Addr32 d32_true )
sewardje87b4842004-07-10 12:23:30 +00001177{
sewardj2a9ad022004-11-25 02:46:58 +00001178 Bool invert;
1179 X86Condcode condPos;
1180 condPos = positiveIse_X86Condcode ( cond, &invert );
sewardje87b4842004-07-10 12:23:30 +00001181 if (invert) {
sewardj2a9ad022004-11-25 02:46:58 +00001182 stmt( IRStmt_Exit( mk_x86g_calculate_condition(condPos),
sewardj893aada2004-11-29 19:57:54 +00001183 Ijk_Boring,
sewardj78c19df2004-07-12 22:49:27 +00001184 IRConst_U32(d32_false) ) );
sewardje539a402004-07-14 18:24:17 +00001185 irbb->next = mkU32(d32_true);
1186 irbb->jumpkind = Ijk_Boring;
sewardje87b4842004-07-10 12:23:30 +00001187 } else {
sewardj2a9ad022004-11-25 02:46:58 +00001188 stmt( IRStmt_Exit( mk_x86g_calculate_condition(condPos),
sewardj893aada2004-11-29 19:57:54 +00001189 Ijk_Boring,
sewardj78c19df2004-07-12 22:49:27 +00001190 IRConst_U32(d32_true) ) );
sewardje539a402004-07-14 18:24:17 +00001191 irbb->next = mkU32(d32_false);
1192 irbb->jumpkind = Ijk_Boring;
sewardje87b4842004-07-10 12:23:30 +00001193 }
1194}
sewardjc9a65702004-07-07 16:32:57 +00001195
1196
sewardjd1061ab2004-07-08 01:45:30 +00001197/*------------------------------------------------------------*/
1198/*--- Disassembling addressing modes ---*/
1199/*------------------------------------------------------------*/
sewardjc9a65702004-07-07 16:32:57 +00001200
sewardjd1061ab2004-07-08 01:45:30 +00001201static
sewardj2d49b432005-02-01 00:37:06 +00001202HChar* sorbTxt ( UChar sorb )
sewardjd1061ab2004-07-08 01:45:30 +00001203{
1204 switch (sorb) {
1205 case 0: return ""; /* no override */
1206 case 0x3E: return "%ds";
1207 case 0x26: return "%es:";
1208 case 0x64: return "%fs:";
1209 case 0x65: return "%gs:";
sewardj7df596b2004-12-06 14:29:12 +00001210 default: vpanic("sorbTxt(x86,guest)");
sewardjd1061ab2004-07-08 01:45:30 +00001211 }
1212}
1213
1214
sewardj7df596b2004-12-06 14:29:12 +00001215/* 'virtual' is an IRExpr* holding a virtual address. Convert it to a
1216 linear address by adding any required segment override as indicated
1217 by sorb. */
sewardjd1061ab2004-07-08 01:45:30 +00001218static
1219IRExpr* handleSegOverride ( UChar sorb, IRExpr* virtual )
1220{
sewardj3bd6f3e2004-12-13 10:48:19 +00001221 Int sreg;
1222 IRType hWordTy;
1223 IRTemp ldt_ptr, gdt_ptr, seg_selector, r64;
sewardjd1061ab2004-07-08 01:45:30 +00001224
1225 if (sorb == 0)
1226 /* the common case - no override */
1227 return virtual;
1228
sewardjd1061ab2004-07-08 01:45:30 +00001229 switch (sorb) {
1230 case 0x3E: sreg = R_DS; break;
1231 case 0x26: sreg = R_ES; break;
1232 case 0x64: sreg = R_FS; break;
1233 case 0x65: sreg = R_GS; break;
sewardj7df596b2004-12-06 14:29:12 +00001234 default: vpanic("handleSegOverride(x86,guest)");
sewardjd1061ab2004-07-08 01:45:30 +00001235 }
1236
sewardj3bd6f3e2004-12-13 10:48:19 +00001237 hWordTy = sizeof(HWord)==4 ? Ity_I32 : Ity_I64;
sewardjd1061ab2004-07-08 01:45:30 +00001238
sewardj3bd6f3e2004-12-13 10:48:19 +00001239 seg_selector = newTemp(Ity_I32);
1240 ldt_ptr = newTemp(hWordTy);
1241 gdt_ptr = newTemp(hWordTy);
1242 r64 = newTemp(Ity_I64);
sewardjd1061ab2004-07-08 01:45:30 +00001243
sewardj3bd6f3e2004-12-13 10:48:19 +00001244 assign( seg_selector, unop(Iop_16Uto32, getSReg(sreg)) );
1245 assign( ldt_ptr, IRExpr_Get( OFFB_LDT, hWordTy ));
1246 assign( gdt_ptr, IRExpr_Get( OFFB_GDT, hWordTy ));
sewardj7df596b2004-12-06 14:29:12 +00001247
sewardj3bd6f3e2004-12-13 10:48:19 +00001248 /*
1249 Call this to do the translation and limit checks:
1250 ULong x86g_use_seg_selector ( HWord ldt, HWord gdt,
1251 UInt seg_selector, UInt virtual_addr )
1252 */
1253 assign(
1254 r64,
1255 mkIRExprCCall(
1256 Ity_I64,
1257 0/*regparms*/,
1258 "x86g_use_seg_selector",
1259 &x86g_use_seg_selector,
1260 mkIRExprVec_4( mkexpr(ldt_ptr), mkexpr(gdt_ptr),
1261 mkexpr(seg_selector), virtual)
1262 )
1263 );
sewardj7df596b2004-12-06 14:29:12 +00001264
sewardj52444cb2004-12-13 14:09:01 +00001265 /* If the high 32 of the result are non-zero, there was a
1266 failure in address translation. In which case, make a
1267 quick exit.
1268 */
1269 stmt(
1270 IRStmt_Exit(
1271 binop(Iop_CmpNE32, unop(Iop_64HIto32, mkexpr(r64)), mkU32(0)),
1272 Ijk_MapFail,
sewardj9e6491a2005-07-02 19:24:10 +00001273 IRConst_U32( guest_EIP_curr_instr )
sewardj52444cb2004-12-13 14:09:01 +00001274 )
1275 );
1276
1277 /* otherwise, here's the translated result. */
sewardj3bd6f3e2004-12-13 10:48:19 +00001278 return unop(Iop_64to32, mkexpr(r64));
sewardjd1061ab2004-07-08 01:45:30 +00001279}
1280
1281
1282/* Generate IR to calculate an address indicated by a ModRM and
1283 following SIB bytes. The expression, and the number of bytes in
1284 the address mode, are returned. Note that this fn should not be
1285 called if the R/M part of the address denotes a register instead of
1286 memory. If print_codegen is true, text of the addressing mode is
sewardj940e8c92004-07-11 16:53:24 +00001287 placed in buf.
1288
1289 The computed address is stored in a new tempreg, and the
1290 identity of the tempreg is returned. */
1291
1292static IRTemp disAMode_copy2tmp ( IRExpr* addr32 )
1293{
1294 IRTemp tmp = newTemp(Ity_I32);
1295 assign( tmp, addr32 );
1296 return tmp;
1297}
sewardjd1061ab2004-07-08 01:45:30 +00001298
1299static
sewardj52d04912005-07-03 00:52:48 +00001300IRTemp disAMode ( Int* len, UChar sorb, Int delta, HChar* buf )
sewardjd1061ab2004-07-08 01:45:30 +00001301{
1302 UChar mod_reg_rm = getIByte(delta);
1303 delta++;
1304
sewardj9ee82862004-12-14 01:16:59 +00001305 buf[0] = (UChar)0;
1306
sewardjd1061ab2004-07-08 01:45:30 +00001307 /* squeeze out the reg field from mod_reg_rm, since a 256-entry
1308 jump table seems a bit excessive.
1309 */
sewardj9b45b482005-02-07 01:42:18 +00001310 mod_reg_rm &= 0xC7; /* is now XX000YYY */
1311 mod_reg_rm = toUChar(mod_reg_rm | (mod_reg_rm >> 3));
1312 /* is now XX0XXYYY */
1313 mod_reg_rm &= 0x1F; /* is now 000XXYYY */
sewardjd1061ab2004-07-08 01:45:30 +00001314 switch (mod_reg_rm) {
1315
1316 /* (%eax) .. (%edi), not including (%esp) or (%ebp).
1317 --> GET %reg, t
1318 */
1319 case 0x00: case 0x01: case 0x02: case 0x03:
1320 /* ! 04 */ /* ! 05 */ case 0x06: case 0x07:
1321 { UChar rm = mod_reg_rm;
1322 DIS(buf, "%s(%s)", sorbTxt(sorb), nameIReg(4,rm));
1323 *len = 1;
sewardj5bd4d162004-11-10 13:02:48 +00001324 return disAMode_copy2tmp(
sewardj940e8c92004-07-11 16:53:24 +00001325 handleSegOverride(sorb, getIReg(4,rm)));
sewardjd1061ab2004-07-08 01:45:30 +00001326 }
1327
1328 /* d8(%eax) ... d8(%edi), not including d8(%esp)
1329 --> GET %reg, t ; ADDL d8, t
1330 */
1331 case 0x08: case 0x09: case 0x0A: case 0x0B:
1332 /* ! 0C */ case 0x0D: case 0x0E: case 0x0F:
sewardj9b45b482005-02-07 01:42:18 +00001333 { UChar rm = toUChar(mod_reg_rm & 7);
sewardjd1061ab2004-07-08 01:45:30 +00001334 UInt d = getSDisp8(delta);
sewardj2d49b432005-02-01 00:37:06 +00001335 DIS(buf, "%s%d(%s)", sorbTxt(sorb), (Int)d, nameIReg(4,rm));
sewardj5bd4d162004-11-10 13:02:48 +00001336 *len = 2;
1337 return disAMode_copy2tmp(
sewardj940e8c92004-07-11 16:53:24 +00001338 handleSegOverride(sorb,
1339 binop(Iop_Add32,getIReg(4,rm),mkU32(d))));
sewardjd1061ab2004-07-08 01:45:30 +00001340 }
1341
1342 /* d32(%eax) ... d32(%edi), not including d32(%esp)
1343 --> GET %reg, t ; ADDL d8, t
1344 */
1345 case 0x10: case 0x11: case 0x12: case 0x13:
1346 /* ! 14 */ case 0x15: case 0x16: case 0x17:
sewardj9b45b482005-02-07 01:42:18 +00001347 { UChar rm = toUChar(mod_reg_rm & 7);
sewardjd1061ab2004-07-08 01:45:30 +00001348 UInt d = getUDisp32(delta);
sewardj2d49b432005-02-01 00:37:06 +00001349 DIS(buf, "%s0x%x(%s)", sorbTxt(sorb), (Int)d, nameIReg(4,rm));
sewardj5bd4d162004-11-10 13:02:48 +00001350 *len = 5;
1351 return disAMode_copy2tmp(
sewardj940e8c92004-07-11 16:53:24 +00001352 handleSegOverride(sorb,
1353 binop(Iop_Add32,getIReg(4,rm),mkU32(d))));
sewardjd1061ab2004-07-08 01:45:30 +00001354 }
1355
1356 /* a register, %eax .. %edi. This shouldn't happen. */
1357 case 0x18: case 0x19: case 0x1A: case 0x1B:
1358 case 0x1C: case 0x1D: case 0x1E: case 0x1F:
1359 vpanic("disAMode(x86): not an addr!");
1360
1361 /* a 32-bit literal address
1362 --> MOV d32, tmp
1363 */
1364 case 0x05:
1365 { UInt d = getUDisp32(delta);
1366 *len = 5;
1367 DIS(buf, "%s(0x%x)", sorbTxt(sorb), d);
sewardj940e8c92004-07-11 16:53:24 +00001368 return disAMode_copy2tmp(
1369 handleSegOverride(sorb, mkU32(d)));
sewardjd1061ab2004-07-08 01:45:30 +00001370 }
1371
1372 case 0x04: {
1373 /* SIB, with no displacement. Special cases:
1374 -- %esp cannot act as an index value.
1375 If index_r indicates %esp, zero is used for the index.
1376 -- when mod is zero and base indicates EBP, base is instead
1377 a 32-bit literal.
1378 It's all madness, I tell you. Extract %index, %base and
1379 scale from the SIB byte. The value denoted is then:
1380 | %index == %ESP && %base == %EBP
1381 = d32 following SIB byte
1382 | %index == %ESP && %base != %EBP
1383 = %base
1384 | %index != %ESP && %base == %EBP
1385 = d32 following SIB byte + (%index << scale)
1386 | %index != %ESP && %base != %ESP
1387 = %base + (%index << scale)
1388
1389 What happens to the souls of CPU architects who dream up such
1390 horrendous schemes, do you suppose?
1391 */
1392 UChar sib = getIByte(delta);
sewardj9b45b482005-02-07 01:42:18 +00001393 UChar scale = toUChar((sib >> 6) & 3);
1394 UChar index_r = toUChar((sib >> 3) & 7);
1395 UChar base_r = toUChar(sib & 7);
sewardj5bd4d162004-11-10 13:02:48 +00001396 delta++;
sewardjd1061ab2004-07-08 01:45:30 +00001397
1398 if (index_r != R_ESP && base_r != R_EBP) {
1399 DIS(buf, "%s(%s,%s,%d)", sorbTxt(sorb),
1400 nameIReg(4,base_r), nameIReg(4,index_r), 1<<scale);
sewardj5bd4d162004-11-10 13:02:48 +00001401 *len = 2;
sewardj940e8c92004-07-11 16:53:24 +00001402 return
1403 disAMode_copy2tmp(
sewardj5bd4d162004-11-10 13:02:48 +00001404 handleSegOverride(sorb,
1405 binop(Iop_Add32,
sewardjd1061ab2004-07-08 01:45:30 +00001406 getIReg(4,base_r),
1407 binop(Iop_Shl32, getIReg(4,index_r),
sewardj6d2638e2004-07-15 09:38:27 +00001408 mkU8(scale)))));
sewardjd1061ab2004-07-08 01:45:30 +00001409 }
1410
1411 if (index_r != R_ESP && base_r == R_EBP) {
1412 UInt d = getUDisp32(delta);
1413 DIS(buf, "%s0x%x(,%s,%d)", sorbTxt(sorb), d,
1414 nameIReg(4,index_r), 1<<scale);
1415 *len = 6;
1416 return
sewardj940e8c92004-07-11 16:53:24 +00001417 disAMode_copy2tmp(
sewardjd1061ab2004-07-08 01:45:30 +00001418 handleSegOverride(sorb,
sewardj5bd4d162004-11-10 13:02:48 +00001419 binop(Iop_Add32,
1420 binop(Iop_Shl32, getIReg(4,index_r), mkU8(scale)),
sewardj940e8c92004-07-11 16:53:24 +00001421 mkU32(d))));
sewardjd1061ab2004-07-08 01:45:30 +00001422 }
1423
1424 if (index_r == R_ESP && base_r != R_EBP) {
1425 DIS(buf, "%s(%s,,)", sorbTxt(sorb), nameIReg(4,base_r));
sewardj5bd4d162004-11-10 13:02:48 +00001426 *len = 2;
1427 return disAMode_copy2tmp(
sewardj940e8c92004-07-11 16:53:24 +00001428 handleSegOverride(sorb, getIReg(4,base_r)));
sewardjd1061ab2004-07-08 01:45:30 +00001429 }
1430
1431 if (index_r == R_ESP && base_r == R_EBP) {
1432 UInt d = getUDisp32(delta);
1433 DIS(buf, "%s0x%x()", sorbTxt(sorb), d);
sewardj5bd4d162004-11-10 13:02:48 +00001434 *len = 6;
sewardja340ee82005-01-26 01:24:34 +00001435 vpanic("disAMode(x86):untested amode: 8");
sewardj5bd4d162004-11-10 13:02:48 +00001436 return disAMode_copy2tmp(
sewardj940e8c92004-07-11 16:53:24 +00001437 handleSegOverride(sorb, mkU32(d)));
sewardjd1061ab2004-07-08 01:45:30 +00001438 }
sewardjba89f4c2005-04-07 17:31:27 +00001439 /*NOTREACHED*/
sewardjd1061ab2004-07-08 01:45:30 +00001440 vassert(0);
1441 }
1442
1443 /* SIB, with 8-bit displacement. Special cases:
1444 -- %esp cannot act as an index value.
1445 If index_r indicates %esp, zero is used for the index.
1446 Denoted value is:
1447 | %index == %ESP
1448 = d8 + %base
1449 | %index != %ESP
1450 = d8 + %base + (%index << scale)
1451 */
1452 case 0x0C: {
1453 UChar sib = getIByte(delta);
sewardj9b45b482005-02-07 01:42:18 +00001454 UChar scale = toUChar((sib >> 6) & 3);
1455 UChar index_r = toUChar((sib >> 3) & 7);
1456 UChar base_r = toUChar(sib & 7);
sewardjd1061ab2004-07-08 01:45:30 +00001457 UInt d = getSDisp8(delta+1);
1458
1459 if (index_r == R_ESP) {
sewardj2d49b432005-02-01 00:37:06 +00001460 DIS(buf, "%s%d(%s,,)", sorbTxt(sorb),
1461 (Int)d, nameIReg(4,base_r));
sewardj5bd4d162004-11-10 13:02:48 +00001462 *len = 3;
1463 return disAMode_copy2tmp(
sewardj940e8c92004-07-11 16:53:24 +00001464 handleSegOverride(sorb,
1465 binop(Iop_Add32, getIReg(4,base_r), mkU32(d)) ));
sewardjd1061ab2004-07-08 01:45:30 +00001466 } else {
sewardj2d49b432005-02-01 00:37:06 +00001467 DIS(buf, "%s%d(%s,%s,%d)", sorbTxt(sorb), (Int)d,
sewardjd1061ab2004-07-08 01:45:30 +00001468 nameIReg(4,base_r), nameIReg(4,index_r), 1<<scale);
sewardj5bd4d162004-11-10 13:02:48 +00001469 *len = 3;
1470 return
sewardj940e8c92004-07-11 16:53:24 +00001471 disAMode_copy2tmp(
1472 handleSegOverride(sorb,
sewardj77b86be2004-07-11 13:28:24 +00001473 binop(Iop_Add32,
1474 binop(Iop_Add32,
1475 getIReg(4,base_r),
1476 binop(Iop_Shl32,
sewardj6d2638e2004-07-15 09:38:27 +00001477 getIReg(4,index_r), mkU8(scale))),
sewardj940e8c92004-07-11 16:53:24 +00001478 mkU32(d))));
sewardjd1061ab2004-07-08 01:45:30 +00001479 }
sewardjba89f4c2005-04-07 17:31:27 +00001480 /*NOTREACHED*/
sewardjd1061ab2004-07-08 01:45:30 +00001481 vassert(0);
1482 }
1483
1484 /* SIB, with 32-bit displacement. Special cases:
1485 -- %esp cannot act as an index value.
1486 If index_r indicates %esp, zero is used for the index.
1487 Denoted value is:
1488 | %index == %ESP
1489 = d32 + %base
1490 | %index != %ESP
1491 = d32 + %base + (%index << scale)
1492 */
1493 case 0x14: {
1494 UChar sib = getIByte(delta);
sewardj9b45b482005-02-07 01:42:18 +00001495 UChar scale = toUChar((sib >> 6) & 3);
1496 UChar index_r = toUChar((sib >> 3) & 7);
1497 UChar base_r = toUChar(sib & 7);
sewardjd1061ab2004-07-08 01:45:30 +00001498 UInt d = getUDisp32(delta+1);
1499
1500 if (index_r == R_ESP) {
sewardj2d49b432005-02-01 00:37:06 +00001501 DIS(buf, "%s%d(%s,,)", sorbTxt(sorb),
1502 (Int)d, nameIReg(4,base_r));
sewardj5bd4d162004-11-10 13:02:48 +00001503 *len = 6;
1504 return disAMode_copy2tmp(
sewardj940e8c92004-07-11 16:53:24 +00001505 handleSegOverride(sorb,
1506 binop(Iop_Add32, getIReg(4,base_r), mkU32(d)) ));
sewardjd1061ab2004-07-08 01:45:30 +00001507 } else {
sewardj2d49b432005-02-01 00:37:06 +00001508 DIS(buf, "%s%d(%s,%s,%d)", sorbTxt(sorb), (Int)d,
1509 nameIReg(4,base_r), nameIReg(4,index_r), 1<<scale);
sewardj5bd4d162004-11-10 13:02:48 +00001510 *len = 6;
1511 return
sewardj940e8c92004-07-11 16:53:24 +00001512 disAMode_copy2tmp(
1513 handleSegOverride(sorb,
sewardj9334b0f2004-07-10 22:43:54 +00001514 binop(Iop_Add32,
1515 binop(Iop_Add32,
1516 getIReg(4,base_r),
1517 binop(Iop_Shl32,
sewardj6d2638e2004-07-15 09:38:27 +00001518 getIReg(4,index_r), mkU8(scale))),
sewardj940e8c92004-07-11 16:53:24 +00001519 mkU32(d))));
sewardjd1061ab2004-07-08 01:45:30 +00001520 }
sewardjba89f4c2005-04-07 17:31:27 +00001521 /*NOTREACHED*/
sewardjd1061ab2004-07-08 01:45:30 +00001522 vassert(0);
1523 }
1524
1525 default:
1526 vpanic("disAMode(x86)");
1527 return 0; /*notreached*/
1528 }
1529}
1530
1531
1532/* Figure out the number of (insn-stream) bytes constituting the amode
1533 beginning at delta. Is useful for getting hold of literals beyond
1534 the end of the amode before it has been disassembled. */
1535
sewardj52d04912005-07-03 00:52:48 +00001536static UInt lengthAMode ( Int delta )
sewardjd1061ab2004-07-08 01:45:30 +00001537{
1538 UChar mod_reg_rm = getIByte(delta); delta++;
1539
1540 /* squeeze out the reg field from mod_reg_rm, since a 256-entry
1541 jump table seems a bit excessive.
1542 */
1543 mod_reg_rm &= 0xC7; /* is now XX000YYY */
sewardj9b45b482005-02-07 01:42:18 +00001544 mod_reg_rm = toUChar(mod_reg_rm | (mod_reg_rm >> 3));
1545 /* is now XX0XXYYY */
sewardjd1061ab2004-07-08 01:45:30 +00001546 mod_reg_rm &= 0x1F; /* is now 000XXYYY */
1547 switch (mod_reg_rm) {
1548
1549 /* (%eax) .. (%edi), not including (%esp) or (%ebp). */
1550 case 0x00: case 0x01: case 0x02: case 0x03:
1551 /* ! 04 */ /* ! 05 */ case 0x06: case 0x07:
1552 return 1;
1553
1554 /* d8(%eax) ... d8(%edi), not including d8(%esp). */
1555 case 0x08: case 0x09: case 0x0A: case 0x0B:
1556 /* ! 0C */ case 0x0D: case 0x0E: case 0x0F:
1557 return 2;
1558
1559 /* d32(%eax) ... d32(%edi), not including d32(%esp). */
1560 case 0x10: case 0x11: case 0x12: case 0x13:
1561 /* ! 14 */ case 0x15: case 0x16: case 0x17:
1562 return 5;
1563
1564 /* a register, %eax .. %edi. (Not an addr, but still handled.) */
1565 case 0x18: case 0x19: case 0x1A: case 0x1B:
1566 case 0x1C: case 0x1D: case 0x1E: case 0x1F:
1567 return 1;
1568
1569 /* a 32-bit literal address. */
1570 case 0x05: return 5;
1571
1572 /* SIB, no displacement. */
1573 case 0x04: {
1574 UChar sib = getIByte(delta);
sewardj9b45b482005-02-07 01:42:18 +00001575 UChar base_r = toUChar(sib & 7);
sewardjd1061ab2004-07-08 01:45:30 +00001576 if (base_r == R_EBP) return 6; else return 2;
1577 }
1578 /* SIB, with 8-bit displacement. */
1579 case 0x0C: return 3;
1580
1581 /* SIB, with 32-bit displacement. */
1582 case 0x14: return 6;
1583
1584 default:
1585 vpanic("lengthAMode");
1586 return 0; /*notreached*/
1587 }
1588}
1589
1590/*------------------------------------------------------------*/
1591/*--- Disassembling common idioms ---*/
1592/*------------------------------------------------------------*/
1593
sewardje87b4842004-07-10 12:23:30 +00001594/* Handle binary integer instructions of the form
1595 op E, G meaning
1596 op reg-or-mem, reg
1597 Is passed the a ptr to the modRM byte, the actual operation, and the
1598 data size. Returns the address advanced completely over this
1599 instruction.
1600
1601 E(src) is reg-or-mem
1602 G(dst) is reg.
1603
1604 If E is reg, --> GET %G, tmp
1605 OP %E, tmp
1606 PUT tmp, %G
1607
1608 If E is mem and OP is not reversible,
1609 --> (getAddr E) -> tmpa
1610 LD (tmpa), tmpa
1611 GET %G, tmp2
1612 OP tmpa, tmp2
1613 PUT tmp2, %G
1614
1615 If E is mem and OP is reversible
1616 --> (getAddr E) -> tmpa
1617 LD (tmpa), tmpa
1618 OP %G, tmpa
1619 PUT tmpa, %G
1620*/
1621static
1622UInt dis_op2_E_G ( UChar sorb,
sewardj180e8b32004-07-29 01:40:11 +00001623 Bool addSubCarry,
sewardje87b4842004-07-10 12:23:30 +00001624 IROp op8,
1625 Bool keep,
1626 Int size,
sewardj52d04912005-07-03 00:52:48 +00001627 Int delta0,
sewardj2d49b432005-02-01 00:37:06 +00001628 HChar* t_x86opc )
sewardje87b4842004-07-10 12:23:30 +00001629{
sewardjc9a43662004-11-30 18:51:59 +00001630 HChar dis_buf[50];
sewardj9334b0f2004-07-10 22:43:54 +00001631 Int len;
sewardje87b4842004-07-10 12:23:30 +00001632 IRType ty = szToITy(size);
1633 IRTemp dst1 = newTemp(ty);
1634 IRTemp src = newTemp(ty);
1635 IRTemp dst0 = newTemp(ty);
1636 UChar rm = getUChar(delta0);
sewardj92d168d2004-11-15 14:22:12 +00001637 IRTemp addr = IRTemp_INVALID;
sewardje87b4842004-07-10 12:23:30 +00001638
sewardj180e8b32004-07-29 01:40:11 +00001639 /* addSubCarry == True indicates the intended operation is
1640 add-with-carry or subtract-with-borrow. */
1641 if (addSubCarry) {
1642 vassert(op8 == Iop_Add8 || op8 == Iop_Sub8);
1643 vassert(keep);
1644 }
1645
sewardje87b4842004-07-10 12:23:30 +00001646 if (epartIsReg(rm)) {
sewardje87b4842004-07-10 12:23:30 +00001647 /* Specially handle XOR reg,reg, because that doesn't really
1648 depend on reg, and doing the obvious thing potentially
1649 generates a spurious value check failure due to the bogus
sewardj55efbdf2005-05-02 17:07:02 +00001650 dependency. Ditto SBB reg,reg. */
1651 if ((op8 == Iop_Xor8 || (op8 == Iop_Sub8 && addSubCarry))
1652 && gregOfRM(rm) == eregOfRM(rm)) {
1653 putIReg(size, gregOfRM(rm), mkU(ty,0));
sewardje87b4842004-07-10 12:23:30 +00001654 }
sewardje87b4842004-07-10 12:23:30 +00001655 assign( dst0, getIReg(size,gregOfRM(rm)) );
1656 assign( src, getIReg(size,eregOfRM(rm)) );
sewardje87b4842004-07-10 12:23:30 +00001657
sewardj180e8b32004-07-29 01:40:11 +00001658 if (addSubCarry && op8 == Iop_Add8) {
sewardj180e8b32004-07-29 01:40:11 +00001659 helper_ADC( size, dst1, dst0, src );
sewardje87b4842004-07-10 12:23:30 +00001660 putIReg(size, gregOfRM(rm), mkexpr(dst1));
sewardj180e8b32004-07-29 01:40:11 +00001661 } else
1662 if (addSubCarry && op8 == Iop_Sub8) {
sewardj180e8b32004-07-29 01:40:11 +00001663 helper_SBB( size, dst1, dst0, src );
1664 putIReg(size, gregOfRM(rm), mkexpr(dst1));
1665 } else {
1666 assign( dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
sewardj5bd4d162004-11-10 13:02:48 +00001667 if (isAddSub(op8))
sewardj2a2ba8b2004-11-08 13:14:06 +00001668 setFlags_DEP1_DEP2(op8, dst0, src, ty);
sewardjb9c5cf62004-08-24 15:10:38 +00001669 else
sewardj2a2ba8b2004-11-08 13:14:06 +00001670 setFlags_DEP1(op8, dst1, ty);
sewardj180e8b32004-07-29 01:40:11 +00001671 if (keep)
1672 putIReg(size, gregOfRM(rm), mkexpr(dst1));
1673 }
sewardje87b4842004-07-10 12:23:30 +00001674
1675 DIP("%s%c %s,%s\n", t_x86opc, nameISize(size),
1676 nameIReg(size,eregOfRM(rm)),
1677 nameIReg(size,gregOfRM(rm)));
1678 return 1+delta0;
sewardje87b4842004-07-10 12:23:30 +00001679 } else {
sewardj9334b0f2004-07-10 22:43:54 +00001680 /* E refers to memory */
1681 addr = disAMode ( &len, sorb, delta0, dis_buf);
1682 assign( dst0, getIReg(size,gregOfRM(rm)) );
sewardj940e8c92004-07-11 16:53:24 +00001683 assign( src, loadLE(szToITy(size), mkexpr(addr)) );
sewardj9334b0f2004-07-10 22:43:54 +00001684
sewardj180e8b32004-07-29 01:40:11 +00001685 if (addSubCarry && op8 == Iop_Add8) {
sewardj180e8b32004-07-29 01:40:11 +00001686 helper_ADC( size, dst1, dst0, src );
sewardj9334b0f2004-07-10 22:43:54 +00001687 putIReg(size, gregOfRM(rm), mkexpr(dst1));
sewardj180e8b32004-07-29 01:40:11 +00001688 } else
1689 if (addSubCarry && op8 == Iop_Sub8) {
1690 helper_SBB( size, dst1, dst0, src );
1691 putIReg(size, gregOfRM(rm), mkexpr(dst1));
1692 } else {
1693 assign( dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
sewardj5bd4d162004-11-10 13:02:48 +00001694 if (isAddSub(op8))
sewardj2a2ba8b2004-11-08 13:14:06 +00001695 setFlags_DEP1_DEP2(op8, dst0, src, ty);
sewardjb9c5cf62004-08-24 15:10:38 +00001696 else
sewardj2a2ba8b2004-11-08 13:14:06 +00001697 setFlags_DEP1(op8, dst1, ty);
sewardj180e8b32004-07-29 01:40:11 +00001698 if (keep)
1699 putIReg(size, gregOfRM(rm), mkexpr(dst1));
1700 }
sewardj9334b0f2004-07-10 22:43:54 +00001701
sewardje87b4842004-07-10 12:23:30 +00001702 DIP("%s%c %s,%s\n", t_x86opc, nameISize(size),
1703 dis_buf,nameIReg(size,gregOfRM(rm)));
sewardj9334b0f2004-07-10 22:43:54 +00001704 return len+delta0;
sewardje87b4842004-07-10 12:23:30 +00001705 }
sewardje87b4842004-07-10 12:23:30 +00001706}
sewardje05c42c2004-07-08 20:25:10 +00001707
1708
1709
1710/* Handle binary integer instructions of the form
1711 op G, E meaning
1712 op reg, reg-or-mem
1713 Is passed the a ptr to the modRM byte, the actual operation, and the
1714 data size. Returns the address advanced completely over this
1715 instruction.
1716
1717 G(src) is reg.
1718 E(dst) is reg-or-mem
1719
1720 If E is reg, --> GET %E, tmp
1721 OP %G, tmp
1722 PUT tmp, %E
1723
1724 If E is mem, --> (getAddr E) -> tmpa
1725 LD (tmpa), tmpv
1726 OP %G, tmpv
1727 ST tmpv, (tmpa)
1728*/
1729static
1730UInt dis_op2_G_E ( UChar sorb,
sewardjcaca9d02004-07-28 07:11:32 +00001731 Bool addSubCarry,
sewardje05c42c2004-07-08 20:25:10 +00001732 IROp op8,
1733 Bool keep,
1734 Int size,
sewardj52d04912005-07-03 00:52:48 +00001735 Int delta0,
sewardj2d49b432005-02-01 00:37:06 +00001736 HChar* t_x86opc )
sewardje05c42c2004-07-08 20:25:10 +00001737{
sewardjc9a43662004-11-30 18:51:59 +00001738 HChar dis_buf[50];
sewardje87b4842004-07-10 12:23:30 +00001739 Int len;
sewardje05c42c2004-07-08 20:25:10 +00001740 IRType ty = szToITy(size);
1741 IRTemp dst1 = newTemp(ty);
1742 IRTemp src = newTemp(ty);
1743 IRTemp dst0 = newTemp(ty);
1744 UChar rm = getIByte(delta0);
sewardj92d168d2004-11-15 14:22:12 +00001745 IRTemp addr = IRTemp_INVALID;
sewardje05c42c2004-07-08 20:25:10 +00001746
sewardjcaca9d02004-07-28 07:11:32 +00001747 /* addSubCarry == True indicates the intended operation is
1748 add-with-carry or subtract-with-borrow. */
1749 if (addSubCarry) {
1750 vassert(op8 == Iop_Add8 || op8 == Iop_Sub8);
1751 vassert(keep);
1752 }
1753
sewardje05c42c2004-07-08 20:25:10 +00001754 if (epartIsReg(rm)) {
sewardje05c42c2004-07-08 20:25:10 +00001755 /* Specially handle XOR reg,reg, because that doesn't really
1756 depend on reg, and doing the obvious thing potentially
1757 generates a spurious value check failure due to the bogus
sewardj55efbdf2005-05-02 17:07:02 +00001758 dependency. Ditto SBB reg,reg.*/
1759 if ((op8 == Iop_Xor8 || (op8 == Iop_Sub8 && addSubCarry))
1760 && gregOfRM(rm) == eregOfRM(rm)) {
1761 putIReg(size, eregOfRM(rm), mkU(ty,0));
sewardje05c42c2004-07-08 20:25:10 +00001762 }
sewardje05c42c2004-07-08 20:25:10 +00001763 assign(dst0, getIReg(size,eregOfRM(rm)));
1764 assign(src, getIReg(size,gregOfRM(rm)));
sewardje05c42c2004-07-08 20:25:10 +00001765
sewardjcaca9d02004-07-28 07:11:32 +00001766 if (addSubCarry && op8 == Iop_Add8) {
sewardj1813dbe2004-07-28 17:09:04 +00001767 helper_ADC( size, dst1, dst0, src );
1768 putIReg(size, eregOfRM(rm), mkexpr(dst1));
sewardjcaca9d02004-07-28 07:11:32 +00001769 } else
1770 if (addSubCarry && op8 == Iop_Sub8) {
1771 helper_SBB( size, dst1, dst0, src );
sewardje05c42c2004-07-08 20:25:10 +00001772 putIReg(size, eregOfRM(rm), mkexpr(dst1));
sewardjcaca9d02004-07-28 07:11:32 +00001773 } else {
1774 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
sewardj5bd4d162004-11-10 13:02:48 +00001775 if (isAddSub(op8))
sewardj2a2ba8b2004-11-08 13:14:06 +00001776 setFlags_DEP1_DEP2(op8, dst0, src, ty);
sewardjb9c5cf62004-08-24 15:10:38 +00001777 else
sewardj2a2ba8b2004-11-08 13:14:06 +00001778 setFlags_DEP1(op8, dst1, ty);
sewardjcaca9d02004-07-28 07:11:32 +00001779 if (keep)
1780 putIReg(size, eregOfRM(rm), mkexpr(dst1));
1781 }
sewardje05c42c2004-07-08 20:25:10 +00001782
1783 DIP("%s%c %s,%s\n", t_x86opc, nameISize(size),
1784 nameIReg(size,gregOfRM(rm)),
1785 nameIReg(size,eregOfRM(rm)));
1786 return 1+delta0;
1787 }
1788
1789 /* E refers to memory */
1790 {
sewardje87b4842004-07-10 12:23:30 +00001791 addr = disAMode ( &len, sorb, delta0, dis_buf);
sewardj940e8c92004-07-11 16:53:24 +00001792 assign(dst0, loadLE(ty,mkexpr(addr)));
sewardje87b4842004-07-10 12:23:30 +00001793 assign(src, getIReg(size,gregOfRM(rm)));
sewardje05c42c2004-07-08 20:25:10 +00001794
sewardjcaca9d02004-07-28 07:11:32 +00001795 if (addSubCarry && op8 == Iop_Add8) {
1796 helper_ADC( size, dst1, dst0, src );
1797 storeLE(mkexpr(addr), mkexpr(dst1));
1798 } else
1799 if (addSubCarry && op8 == Iop_Sub8) {
1800 helper_SBB( size, dst1, dst0, src );
1801 storeLE(mkexpr(addr), mkexpr(dst1));
1802 } else {
1803 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
sewardj5bd4d162004-11-10 13:02:48 +00001804 if (isAddSub(op8))
sewardj2a2ba8b2004-11-08 13:14:06 +00001805 setFlags_DEP1_DEP2(op8, dst0, src, ty);
sewardjb9c5cf62004-08-24 15:10:38 +00001806 else
sewardj2a2ba8b2004-11-08 13:14:06 +00001807 setFlags_DEP1(op8, dst1, ty);
sewardjcaca9d02004-07-28 07:11:32 +00001808 if (keep)
1809 storeLE(mkexpr(addr), mkexpr(dst1));
1810 }
sewardje87b4842004-07-10 12:23:30 +00001811
sewardje05c42c2004-07-08 20:25:10 +00001812 DIP("%s%c %s,%s\n", t_x86opc, nameISize(size),
1813 nameIReg(size,gregOfRM(rm)), dis_buf);
sewardje87b4842004-07-10 12:23:30 +00001814 return len+delta0;
sewardje05c42c2004-07-08 20:25:10 +00001815 }
1816}
1817
1818
1819/* Handle move instructions of the form
1820 mov E, G meaning
1821 mov reg-or-mem, reg
1822 Is passed the a ptr to the modRM byte, and the data size. Returns
1823 the address advanced completely over this instruction.
1824
1825 E(src) is reg-or-mem
1826 G(dst) is reg.
1827
1828 If E is reg, --> GET %E, tmpv
1829 PUT tmpv, %G
1830
1831 If E is mem --> (getAddr E) -> tmpa
1832 LD (tmpa), tmpb
1833 PUT tmpb, %G
1834*/
1835static
1836UInt dis_mov_E_G ( UChar sorb,
1837 Int size,
sewardj52d04912005-07-03 00:52:48 +00001838 Int delta0 )
sewardje05c42c2004-07-08 20:25:10 +00001839{
1840 Int len;
1841 UChar rm = getIByte(delta0);
sewardjc9a43662004-11-30 18:51:59 +00001842 HChar dis_buf[50];
sewardje05c42c2004-07-08 20:25:10 +00001843
1844 if (epartIsReg(rm)) {
sewardj7ca37d92004-10-25 02:58:30 +00001845 putIReg(size, gregOfRM(rm), getIReg(size, eregOfRM(rm)));
sewardje05c42c2004-07-08 20:25:10 +00001846 DIP("mov%c %s,%s\n", nameISize(size),
1847 nameIReg(size,eregOfRM(rm)),
1848 nameIReg(size,gregOfRM(rm)));
sewardj7ca37d92004-10-25 02:58:30 +00001849 return 1+delta0;
sewardje05c42c2004-07-08 20:25:10 +00001850 }
1851
1852 /* E refers to memory */
1853 {
sewardj940e8c92004-07-11 16:53:24 +00001854 IRTemp addr = disAMode ( &len, sorb, delta0, dis_buf );
1855 putIReg(size, gregOfRM(rm), loadLE(szToITy(size), mkexpr(addr)));
sewardje05c42c2004-07-08 20:25:10 +00001856 DIP("mov%c %s,%s\n", nameISize(size),
1857 dis_buf,nameIReg(size,gregOfRM(rm)));
1858 return delta0+len;
1859 }
1860}
1861
1862
1863/* Handle move instructions of the form
1864 mov G, E meaning
1865 mov reg, reg-or-mem
1866 Is passed the a ptr to the modRM byte, and the data size. Returns
1867 the address advanced completely over this instruction.
1868
1869 G(src) is reg.
1870 E(dst) is reg-or-mem
1871
1872 If E is reg, --> GET %G, tmp
1873 PUT tmp, %E
1874
1875 If E is mem, --> (getAddr E) -> tmpa
1876 GET %G, tmpv
1877 ST tmpv, (tmpa)
1878*/
sewardjc9a65702004-07-07 16:32:57 +00001879static
1880UInt dis_mov_G_E ( UChar sorb,
1881 Int size,
sewardj52d04912005-07-03 00:52:48 +00001882 Int delta0 )
sewardjc9a65702004-07-07 16:32:57 +00001883{
sewardje05c42c2004-07-08 20:25:10 +00001884 Int len;
sewardjc9a65702004-07-07 16:32:57 +00001885 UChar rm = getIByte(delta0);
sewardjc9a43662004-11-30 18:51:59 +00001886 HChar dis_buf[50];
sewardjc9a65702004-07-07 16:32:57 +00001887
1888 if (epartIsReg(rm)) {
sewardj41f43bc2004-07-08 14:23:22 +00001889 putIReg(size, eregOfRM(rm), getIReg(size, gregOfRM(rm)));
sewardjc9a65702004-07-07 16:32:57 +00001890 DIP("mov%c %s,%s\n", nameISize(size),
1891 nameIReg(size,gregOfRM(rm)),
1892 nameIReg(size,eregOfRM(rm)));
1893 return 1+delta0;
1894 }
1895
sewardjc9a65702004-07-07 16:32:57 +00001896 /* E refers to memory */
1897 {
sewardj940e8c92004-07-11 16:53:24 +00001898 IRTemp addr = disAMode ( &len, sorb, delta0, dis_buf);
1899 storeLE( mkexpr(addr), getIReg(size, gregOfRM(rm)) );
sewardjc9a65702004-07-07 16:32:57 +00001900 DIP("mov%c %s,%s\n", nameISize(size),
1901 nameIReg(size,gregOfRM(rm)), dis_buf);
sewardje05c42c2004-07-08 20:25:10 +00001902 return len+delta0;
sewardjc9a65702004-07-07 16:32:57 +00001903 }
sewardjc9a65702004-07-07 16:32:57 +00001904}
1905
1906
sewardj0611d802004-07-11 02:37:54 +00001907/* op $immediate, AL/AX/EAX. */
1908static
1909UInt dis_op_imm_A ( Int size,
sewardja718d5d2005-04-03 14:59:54 +00001910 Bool carrying,
sewardj0611d802004-07-11 02:37:54 +00001911 IROp op8,
1912 Bool keep,
sewardj52d04912005-07-03 00:52:48 +00001913 Int delta,
sewardj2d49b432005-02-01 00:37:06 +00001914 HChar* t_x86opc )
sewardj0611d802004-07-11 02:37:54 +00001915{
1916 IRType ty = szToITy(size);
1917 IRTemp dst0 = newTemp(ty);
1918 IRTemp src = newTemp(ty);
1919 IRTemp dst1 = newTemp(ty);
1920 UInt lit = getUDisp(size,delta);
1921 assign(dst0, getIReg(size,R_EAX));
1922 assign(src, mkU(ty,lit));
sewardja718d5d2005-04-03 14:59:54 +00001923
1924 if (isAddSub(op8) && !carrying) {
1925 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
sewardj2a2ba8b2004-11-08 13:14:06 +00001926 setFlags_DEP1_DEP2(op8, dst0, src, ty);
sewardja718d5d2005-04-03 14:59:54 +00001927 }
sewardjb9c5cf62004-08-24 15:10:38 +00001928 else
sewardja718d5d2005-04-03 14:59:54 +00001929 if (isLogic(op8)) {
1930 vassert(!carrying);
1931 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
sewardj2a2ba8b2004-11-08 13:14:06 +00001932 setFlags_DEP1(op8, dst1, ty);
sewardja718d5d2005-04-03 14:59:54 +00001933 }
1934 else
1935 if (op8 == Iop_Add8 && carrying) {
1936 helper_ADC( size, dst1, dst0, src );
1937 }
sewardj2a2ba8b2004-11-08 13:14:06 +00001938 else
1939 vpanic("dis_op_imm_A(x86,guest)");
sewardj0611d802004-07-11 02:37:54 +00001940
1941 if (keep)
1942 putIReg(size, R_EAX, mkexpr(dst1));
1943
1944 DIP("%s%c $0x%x, %s\n", t_x86opc, nameISize(size),
1945 lit, nameIReg(size,R_EAX));
1946 return delta+size;
1947}
sewardj9334b0f2004-07-10 22:43:54 +00001948
1949
1950/* Sign- and Zero-extending moves. */
1951static
sewardj52d04912005-07-03 00:52:48 +00001952UInt dis_movx_E_G ( UChar sorb,
1953 Int delta, Int szs, Int szd, Bool sign_extend )
sewardj9334b0f2004-07-10 22:43:54 +00001954{
sewardj9334b0f2004-07-10 22:43:54 +00001955 UChar rm = getIByte(delta);
1956 if (epartIsReg(rm)) {
1957 putIReg(szd, gregOfRM(rm),
sewardj5bd4d162004-11-10 13:02:48 +00001958 unop(mkWidenOp(szs,szd,sign_extend),
1959 getIReg(szs,eregOfRM(rm))));
sewardj9334b0f2004-07-10 22:43:54 +00001960 DIP("mov%c%c%c %s,%s\n", sign_extend ? 's' : 'z',
1961 nameISize(szs), nameISize(szd),
1962 nameIReg(szs,eregOfRM(rm)),
1963 nameIReg(szd,gregOfRM(rm)));
1964 return 1+delta;
1965 }
1966
1967 /* E refers to memory */
1968 {
sewardj940e8c92004-07-11 16:53:24 +00001969 Int len;
sewardjc9a43662004-11-30 18:51:59 +00001970 HChar dis_buf[50];
sewardj940e8c92004-07-11 16:53:24 +00001971 IRTemp addr = disAMode ( &len, sorb, delta, dis_buf );
sewardj0611d802004-07-11 02:37:54 +00001972
1973 putIReg(szd, gregOfRM(rm),
sewardj5bd4d162004-11-10 13:02:48 +00001974 unop(mkWidenOp(szs,szd,sign_extend),
sewardj940e8c92004-07-11 16:53:24 +00001975 loadLE(szToITy(szs),mkexpr(addr))));
sewardj9334b0f2004-07-10 22:43:54 +00001976 DIP("mov%c%c%c %s,%s\n", sign_extend ? 's' : 'z',
1977 nameISize(szs), nameISize(szd),
1978 dis_buf, nameIReg(szd,gregOfRM(rm)));
sewardj0611d802004-07-11 02:37:54 +00001979 return len+delta;
sewardj9334b0f2004-07-10 22:43:54 +00001980 }
1981}
1982
sewardj9690d922004-07-14 01:39:17 +00001983
1984/* Generate code to divide ArchRegs EDX:EAX / DX:AX / AX by the 32 /
1985 16 / 8 bit quantity in the given IRTemp. */
1986static
1987void codegen_div ( Int sz, IRTemp t, Bool signed_divide )
1988{
sewardje5427e82004-09-11 19:43:51 +00001989 IROp op = signed_divide ? Iop_DivModS64to32 : Iop_DivModU64to32;
1990 IRTemp src64 = newTemp(Ity_I64);
1991 IRTemp dst64 = newTemp(Ity_I64);
sewardj9690d922004-07-14 01:39:17 +00001992 switch (sz) {
sewardje5427e82004-09-11 19:43:51 +00001993 case 4:
sewardj9690d922004-07-14 01:39:17 +00001994 assign( src64, binop(Iop_32HLto64,
sewardje5427e82004-09-11 19:43:51 +00001995 getIReg(4,R_EDX), getIReg(4,R_EAX)) );
sewardj9690d922004-07-14 01:39:17 +00001996 assign( dst64, binop(op, mkexpr(src64), mkexpr(t)) );
sewardj8c7f1ab2004-07-29 20:31:09 +00001997 putIReg( 4, R_EAX, unop(Iop_64to32,mkexpr(dst64)) );
sewardj9690d922004-07-14 01:39:17 +00001998 putIReg( 4, R_EDX, unop(Iop_64HIto32,mkexpr(dst64)) );
1999 break;
sewardje5427e82004-09-11 19:43:51 +00002000 case 2: {
2001 IROp widen3264 = signed_divide ? Iop_32Sto64 : Iop_32Uto64;
2002 IROp widen1632 = signed_divide ? Iop_16Sto32 : Iop_16Uto32;
2003 assign( src64, unop(widen3264,
2004 binop(Iop_16HLto32,
2005 getIReg(2,R_EDX), getIReg(2,R_EAX))) );
2006 assign( dst64, binop(op, mkexpr(src64), unop(widen1632,mkexpr(t))) );
2007 putIReg( 2, R_EAX, unop(Iop_32to16,unop(Iop_64to32,mkexpr(dst64))) );
2008 putIReg( 2, R_EDX, unop(Iop_32to16,unop(Iop_64HIto32,mkexpr(dst64))) );
2009 break;
sewardj9690d922004-07-14 01:39:17 +00002010 }
sewardj4e82db72004-10-16 11:32:15 +00002011 case 1: {
2012 IROp widen3264 = signed_divide ? Iop_32Sto64 : Iop_32Uto64;
2013 IROp widen1632 = signed_divide ? Iop_16Sto32 : Iop_16Uto32;
2014 IROp widen816 = signed_divide ? Iop_8Sto16 : Iop_8Uto16;
2015 assign( src64, unop(widen3264, unop(widen1632, getIReg(2,R_EAX))) );
2016 assign( dst64,
2017 binop(op, mkexpr(src64),
2018 unop(widen1632, unop(widen816, mkexpr(t)))) );
2019 putIReg( 1, R_AL, unop(Iop_16to8, unop(Iop_32to16,
2020 unop(Iop_64to32,mkexpr(dst64)))) );
2021 putIReg( 1, R_AH, unop(Iop_16to8, unop(Iop_32to16,
2022 unop(Iop_64HIto32,mkexpr(dst64)))) );
2023 break;
2024 }
sewardj9690d922004-07-14 01:39:17 +00002025 default: vpanic("codegen_div(x86)");
2026 }
2027}
sewardj41f43bc2004-07-08 14:23:22 +00002028
2029
2030static
sewardje90ad6a2004-07-10 19:02:10 +00002031UInt dis_Grp1 ( UChar sorb,
sewardj52d04912005-07-03 00:52:48 +00002032 Int delta, UChar modrm,
sewardj41f43bc2004-07-08 14:23:22 +00002033 Int am_sz, Int d_sz, Int sz, UInt d32 )
2034{
sewardj41f43bc2004-07-08 14:23:22 +00002035 Int len;
sewardjc9a43662004-11-30 18:51:59 +00002036 HChar dis_buf[50];
sewardje05c42c2004-07-08 20:25:10 +00002037 IRType ty = szToITy(sz);
2038 IRTemp dst1 = newTemp(ty);
2039 IRTemp src = newTemp(ty);
2040 IRTemp dst0 = newTemp(ty);
sewardj92d168d2004-11-15 14:22:12 +00002041 IRTemp addr = IRTemp_INVALID;
sewardj66de2272004-07-16 21:19:05 +00002042 IROp op8 = Iop_INVALID;
sewardj180e8b32004-07-29 01:40:11 +00002043 UInt mask = sz==1 ? 0xFF : (sz==2 ? 0xFFFF : 0xFFFFFFFF);
sewardj41f43bc2004-07-08 14:23:22 +00002044
2045 switch (gregOfRM(modrm)) {
sewardje05c42c2004-07-08 20:25:10 +00002046 case 0: op8 = Iop_Add8; break; case 1: op8 = Iop_Or8; break;
sewardj66de2272004-07-16 21:19:05 +00002047 case 2: break; // ADC
2048 case 3: break; // SBB
sewardje05c42c2004-07-08 20:25:10 +00002049 case 4: op8 = Iop_And8; break; case 5: op8 = Iop_Sub8; break;
2050 case 6: op8 = Iop_Xor8; break; case 7: op8 = Iop_Sub8; break;
sewardj41f43bc2004-07-08 14:23:22 +00002051 default: vpanic("dis_Grp1: unhandled case");
2052 }
sewardj41f43bc2004-07-08 14:23:22 +00002053
2054 if (epartIsReg(modrm)) {
2055 vassert(am_sz == 1);
2056
2057 assign(dst0, getIReg(sz,eregOfRM(modrm)));
sewardj180e8b32004-07-29 01:40:11 +00002058 assign(src, mkU(ty,d32 & mask));
sewardj41f43bc2004-07-08 14:23:22 +00002059
sewardj180e8b32004-07-29 01:40:11 +00002060 if (gregOfRM(modrm) == 2 /* ADC */) {
2061 helper_ADC( sz, dst1, dst0, src );
2062 } else
2063 if (gregOfRM(modrm) == 3 /* SBB */) {
2064 helper_SBB( sz, dst1, dst0, src );
2065 } else {
2066 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
sewardj5bd4d162004-11-10 13:02:48 +00002067 if (isAddSub(op8))
sewardj2a2ba8b2004-11-08 13:14:06 +00002068 setFlags_DEP1_DEP2(op8, dst0, src, ty);
sewardjb9c5cf62004-08-24 15:10:38 +00002069 else
sewardj2a2ba8b2004-11-08 13:14:06 +00002070 setFlags_DEP1(op8, dst1, ty);
sewardj180e8b32004-07-29 01:40:11 +00002071 }
sewardj41f43bc2004-07-08 14:23:22 +00002072
2073 if (gregOfRM(modrm) < 7)
sewardje05c42c2004-07-08 20:25:10 +00002074 putIReg(sz, eregOfRM(modrm), mkexpr(dst1));
sewardj41f43bc2004-07-08 14:23:22 +00002075
2076 delta += (am_sz + d_sz);
2077 DIP("%s%c $0x%x, %s\n", nameGrp1(gregOfRM(modrm)), nameISize(sz), d32,
2078 nameIReg(sz,eregOfRM(modrm)));
2079 } else {
sewardje87b4842004-07-10 12:23:30 +00002080 addr = disAMode ( &len, sorb, delta, dis_buf);
sewardj41f43bc2004-07-08 14:23:22 +00002081
sewardj940e8c92004-07-11 16:53:24 +00002082 assign(dst0, loadLE(ty,mkexpr(addr)));
sewardj180e8b32004-07-29 01:40:11 +00002083 assign(src, mkU(ty,d32 & mask));
sewardj41f43bc2004-07-08 14:23:22 +00002084
sewardj66de2272004-07-16 21:19:05 +00002085 if (gregOfRM(modrm) == 2 /* ADC */) {
sewardj3af115f2004-07-14 02:46:52 +00002086 helper_ADC( sz, dst1, dst0, src );
2087 } else
sewardj66de2272004-07-16 21:19:05 +00002088 if (gregOfRM(modrm) == 3 /* SBB */) {
sewardje166ed02004-10-25 02:27:01 +00002089 helper_SBB( sz, dst1, dst0, src );
sewardj3af115f2004-07-14 02:46:52 +00002090 } else {
2091 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
sewardj5bd4d162004-11-10 13:02:48 +00002092 if (isAddSub(op8))
sewardj2a2ba8b2004-11-08 13:14:06 +00002093 setFlags_DEP1_DEP2(op8, dst0, src, ty);
sewardjb9c5cf62004-08-24 15:10:38 +00002094 else
sewardj2a2ba8b2004-11-08 13:14:06 +00002095 setFlags_DEP1(op8, dst1, ty);
sewardj3af115f2004-07-14 02:46:52 +00002096 }
sewardj41f43bc2004-07-08 14:23:22 +00002097
2098 if (gregOfRM(modrm) < 7)
sewardj940e8c92004-07-11 16:53:24 +00002099 storeLE(mkexpr(addr), mkexpr(dst1));
sewardj41f43bc2004-07-08 14:23:22 +00002100
2101 delta += (len+d_sz);
2102 DIP("%s%c $0x%x, %s\n", nameGrp1(gregOfRM(modrm)), nameISize(sz),
2103 d32, dis_buf);
2104 }
2105 return delta;
2106}
2107
2108
sewardj6d2638e2004-07-15 09:38:27 +00002109/* Group 2 extended opcodes. shift_expr must be an 8-bit typed
2110 expression. */
2111
sewardje90ad6a2004-07-10 19:02:10 +00002112static
sewardj52d04912005-07-03 00:52:48 +00002113UInt dis_Grp2 ( UChar sorb,
2114 Int delta, UChar modrm,
sewardj6d2638e2004-07-15 09:38:27 +00002115 Int am_sz, Int d_sz, Int sz, IRExpr* shift_expr,
sewardj2d49b432005-02-01 00:37:06 +00002116 HChar* shift_expr_txt )
sewardje90ad6a2004-07-10 19:02:10 +00002117{
2118 /* delta on entry points at the modrm byte. */
sewardjc9a43662004-11-30 18:51:59 +00002119 HChar dis_buf[50];
sewardj6d2638e2004-07-15 09:38:27 +00002120 Int len;
sewardj9aebb0c2004-10-24 19:20:43 +00002121 Bool isShift, isRotate, isRotateRC;
sewardj6d2638e2004-07-15 09:38:27 +00002122 IRType ty = szToITy(sz);
2123 IRTemp dst0 = newTemp(ty);
2124 IRTemp dst1 = newTemp(ty);
sewardj92d168d2004-11-15 14:22:12 +00002125 IRTemp addr = IRTemp_INVALID;
sewardje90ad6a2004-07-10 19:02:10 +00002126
2127 vassert(sz == 1 || sz == 2 || sz == 4);
2128
sewardje90ad6a2004-07-10 19:02:10 +00002129 /* Put value to shift/rotate in dst0. */
2130 if (epartIsReg(modrm)) {
2131 assign(dst0, getIReg(sz, eregOfRM(modrm)));
sewardj940e8c92004-07-11 16:53:24 +00002132 delta += (am_sz + d_sz);
sewardje90ad6a2004-07-10 19:02:10 +00002133 } else {
sewardj940e8c92004-07-11 16:53:24 +00002134 addr = disAMode ( &len, sorb, delta, dis_buf);
2135 assign(dst0, loadLE(ty,mkexpr(addr)));
2136 delta += len + d_sz;
sewardje90ad6a2004-07-10 19:02:10 +00002137 }
2138
2139 isShift = False;
2140 switch (gregOfRM(modrm)) { case 4: case 5: case 7: isShift = True; }
2141
sewardj750f4072004-07-26 22:39:11 +00002142 isRotate = False;
2143 switch (gregOfRM(modrm)) { case 0: case 1: isRotate = True; }
2144
sewardj2d49b432005-02-01 00:37:06 +00002145 isRotateRC = toBool(gregOfRM(modrm) == 3);
sewardj9aebb0c2004-10-24 19:20:43 +00002146
2147 if (!isShift && !isRotate && !isRotateRC) {
sewardj8c7f1ab2004-07-29 20:31:09 +00002148 vex_printf("\ncase %d\n", gregOfRM(modrm));
2149 vpanic("dis_Grp2(Reg): unhandled case(x86)");
2150 }
2151
sewardj9aebb0c2004-10-24 19:20:43 +00002152 if (isRotateRC) {
2153 /* call a helper; this insn is so ridiculous it does not deserve
2154 better */
2155 IRTemp r64 = newTemp(Ity_I64);
sewardjf9655262004-10-31 20:02:16 +00002156 IRExpr** args
2157 = mkIRExprVec_4( widenUto32(mkexpr(dst0)), /* thing to rotate */
2158 widenUto32(shift_expr), /* rotate amount */
sewardj2a9ad022004-11-25 02:46:58 +00002159 widenUto32(mk_x86g_calculate_eflags_all()),
sewardjf9655262004-10-31 20:02:16 +00002160 mkU32(sz) );
2161 assign( r64, mkIRExprCCall(
sewardj8ea867b2004-10-30 19:03:02 +00002162 Ity_I64,
sewardjf9655262004-10-31 20:02:16 +00002163 0/*regparm*/,
sewardj2a9ad022004-11-25 02:46:58 +00002164 "x86g_calculate_RCR", &x86g_calculate_RCR,
sewardj8ea867b2004-10-30 19:03:02 +00002165 args
sewardjf9655262004-10-31 20:02:16 +00002166 )
2167 );
sewardj9aebb0c2004-10-24 19:20:43 +00002168 /* new eflags in hi half r64; new value in lo half r64 */
2169 assign( dst1, narrowTo(ty, unop(Iop_64to32, mkexpr(r64))) );
sewardj2a9ad022004-11-25 02:46:58 +00002170 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
sewardj2a2ba8b2004-11-08 13:14:06 +00002171 stmt( IRStmt_Put( OFFB_CC_DEP1, unop(Iop_64HIto32, mkexpr(r64)) ));
2172 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
sewardja3b7e3a2005-04-05 01:54:19 +00002173 /* Set NDEP even though it isn't used. This makes redundant-PUT
2174 elimination of previous stores to this field work better. */
2175 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardj9aebb0c2004-10-24 19:20:43 +00002176 }
2177
sewardje90ad6a2004-07-10 19:02:10 +00002178 if (isShift) {
2179
sewardjc22a6fd2004-07-29 23:41:47 +00002180 IRTemp pre32 = newTemp(Ity_I32);
2181 IRTemp res32 = newTemp(Ity_I32);
2182 IRTemp res32ss = newTemp(Ity_I32);
sewardj6d2638e2004-07-15 09:38:27 +00002183 IRTemp shift_amt = newTemp(Ity_I8);
sewardjc22a6fd2004-07-29 23:41:47 +00002184 IROp op32;
sewardje90ad6a2004-07-10 19:02:10 +00002185
2186 switch (gregOfRM(modrm)) {
sewardjc22a6fd2004-07-29 23:41:47 +00002187 case 4: op32 = Iop_Shl32; break;
2188 case 5: op32 = Iop_Shr32; break;
2189 case 7: op32 = Iop_Sar32; break;
sewardje90ad6a2004-07-10 19:02:10 +00002190 default: vpanic("dis_Grp2:shift"); break;
2191 }
2192
sewardjc22a6fd2004-07-29 23:41:47 +00002193 /* Widen the value to be shifted to 32 bits, do the shift, and
2194 narrow back down. This seems surprisingly long-winded, but
2195 unfortunately the Intel semantics requires that 8/16-bit
2196 shifts give defined results for shift values all the way up
2197 to 31, and this seems the simplest way to do it. It has the
2198 advantage that the only IR level shifts generated are of 32
2199 bit values, and the shift amount is guaranteed to be in the
2200 range 0 .. 31, thereby observing the IR semantics requiring
2201 all shift values to be in the range 0 .. 2^word_size-1. */
2202
2203 /* shift_amt = shift_expr & 31, regardless of operation size */
2204 assign( shift_amt, binop(Iop_And8, shift_expr, mkU8(31)) );
2205
2206 /* suitably widen the value to be shifted to 32 bits. */
2207 assign( pre32, op32==Iop_Sar32 ? widenSto32(mkexpr(dst0))
2208 : widenUto32(mkexpr(dst0)) );
2209
2210 /* res32 = pre32 `shift` shift_amt */
2211 assign( res32, binop(op32, mkexpr(pre32), mkexpr(shift_amt)) );
2212
2213 /* res32ss = pre32 `shift` ((shift_amt - 1) & 31) */
2214 assign( res32ss,
2215 binop(op32,
2216 mkexpr(pre32),
2217 binop(Iop_And8,
2218 binop(Iop_Sub8,
2219 mkexpr(shift_amt), mkU8(1)),
2220 mkU8(31))) );
sewardje90ad6a2004-07-10 19:02:10 +00002221
2222 /* Build the flags thunk. */
sewardj2a2ba8b2004-11-08 13:14:06 +00002223 setFlags_DEP1_DEP2_shift(op32, res32, res32ss, ty, shift_amt);
sewardjc22a6fd2004-07-29 23:41:47 +00002224
2225 /* Narrow the result back down. */
2226 assign( dst1, narrowTo(ty, mkexpr(res32)) );
sewardj750f4072004-07-26 22:39:11 +00002227
sewardj1813dbe2004-07-28 17:09:04 +00002228 } /* if (isShift) */
2229
2230 else
sewardj750f4072004-07-26 22:39:11 +00002231 if (isRotate) {
sewardj7ebbdae2004-08-26 12:30:48 +00002232 Int ccOp = ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
sewardj2d49b432005-02-01 00:37:06 +00002233 Bool left = toBool(gregOfRM(modrm) == 0);
sewardj7ebbdae2004-08-26 12:30:48 +00002234 IRTemp rot_amt = newTemp(Ity_I8);
2235 IRTemp rot_amt32 = newTemp(Ity_I8);
2236 IRTemp oldFlags = newTemp(Ity_I32);
sewardj750f4072004-07-26 22:39:11 +00002237
2238 /* rot_amt = shift_expr & mask */
sewardjc22a6fd2004-07-29 23:41:47 +00002239 /* By masking the rotate amount thusly, the IR-level Shl/Shr
2240 expressions never shift beyond the word size and thus remain
2241 well defined. */
sewardj7ebbdae2004-08-26 12:30:48 +00002242 assign(rot_amt32, binop(Iop_And8, shift_expr, mkU8(31)));
2243
2244 if (ty == Ity_I32)
2245 assign(rot_amt, mkexpr(rot_amt32));
2246 else
2247 assign(rot_amt, binop(Iop_And8, mkexpr(rot_amt32), mkU8(8*sz-1)));
sewardj750f4072004-07-26 22:39:11 +00002248
2249 if (left) {
sewardj1813dbe2004-07-28 17:09:04 +00002250
sewardj750f4072004-07-26 22:39:11 +00002251 /* dst1 = (dst0 << rot_amt) | (dst0 >>u (wordsize-rot_amt)) */
2252 assign(dst1,
2253 binop( mkSizedOp(ty,Iop_Or8),
2254 binop( mkSizedOp(ty,Iop_Shl8),
2255 mkexpr(dst0),
2256 mkexpr(rot_amt)
2257 ),
2258 binop( mkSizedOp(ty,Iop_Shr8),
2259 mkexpr(dst0),
2260 binop(Iop_Sub8,mkU8(8*sz), mkexpr(rot_amt))
2261 )
2262 )
2263 );
sewardj2a9ad022004-11-25 02:46:58 +00002264 ccOp += X86G_CC_OP_ROLB;
sewardj750f4072004-07-26 22:39:11 +00002265
sewardj1813dbe2004-07-28 17:09:04 +00002266 } else { /* right */
sewardj750f4072004-07-26 22:39:11 +00002267
sewardj1813dbe2004-07-28 17:09:04 +00002268 /* dst1 = (dst0 >>u rot_amt) | (dst0 << (wordsize-rot_amt)) */
2269 assign(dst1,
2270 binop( mkSizedOp(ty,Iop_Or8),
2271 binop( mkSizedOp(ty,Iop_Shr8),
2272 mkexpr(dst0),
2273 mkexpr(rot_amt)
2274 ),
2275 binop( mkSizedOp(ty,Iop_Shl8),
2276 mkexpr(dst0),
2277 binop(Iop_Sub8,mkU8(8*sz), mkexpr(rot_amt))
sewardj750f4072004-07-26 22:39:11 +00002278 )
2279 )
2280 );
sewardj2a9ad022004-11-25 02:46:58 +00002281 ccOp += X86G_CC_OP_RORB;
sewardjc22a6fd2004-07-29 23:41:47 +00002282
sewardj750f4072004-07-26 22:39:11 +00002283 }
sewardjc22a6fd2004-07-29 23:41:47 +00002284
sewardj1813dbe2004-07-28 17:09:04 +00002285 /* dst1 now holds the rotated value. Build flag thunk. We
2286 need the resulting value for this, and the previous flags.
2287 Except don't set it if the rotate count is zero. */
2288
sewardj2a9ad022004-11-25 02:46:58 +00002289 assign(oldFlags, mk_x86g_calculate_eflags_all());
sewardj1813dbe2004-07-28 17:09:04 +00002290
sewardj2a2ba8b2004-11-08 13:14:06 +00002291 /* CC_DEP1 is the rotated value. CC_NDEP is flags before. */
sewardj1813dbe2004-07-28 17:09:04 +00002292 stmt( IRStmt_Put( OFFB_CC_OP,
sewardj7ebbdae2004-08-26 12:30:48 +00002293 IRExpr_Mux0X( mkexpr(rot_amt32),
sewardj1813dbe2004-07-28 17:09:04 +00002294 IRExpr_Get(OFFB_CC_OP,Ity_I32),
2295 mkU32(ccOp))) );
sewardj2a2ba8b2004-11-08 13:14:06 +00002296 stmt( IRStmt_Put( OFFB_CC_DEP1,
sewardj7ebbdae2004-08-26 12:30:48 +00002297 IRExpr_Mux0X( mkexpr(rot_amt32),
sewardj2a2ba8b2004-11-08 13:14:06 +00002298 IRExpr_Get(OFFB_CC_DEP1,Ity_I32),
sewardjc22a6fd2004-07-29 23:41:47 +00002299 widenUto32(mkexpr(dst1)))) );
sewardj2a2ba8b2004-11-08 13:14:06 +00002300 stmt( IRStmt_Put( OFFB_CC_DEP2,
sewardj7ebbdae2004-08-26 12:30:48 +00002301 IRExpr_Mux0X( mkexpr(rot_amt32),
sewardj2a2ba8b2004-11-08 13:14:06 +00002302 IRExpr_Get(OFFB_CC_DEP2,Ity_I32),
2303 mkU32(0))) );
2304 stmt( IRStmt_Put( OFFB_CC_NDEP,
2305 IRExpr_Mux0X( mkexpr(rot_amt32),
2306 IRExpr_Get(OFFB_CC_NDEP,Ity_I32),
sewardj1813dbe2004-07-28 17:09:04 +00002307 mkexpr(oldFlags))) );
2308 } /* if (isRotate) */
sewardje90ad6a2004-07-10 19:02:10 +00002309
2310 /* Save result, and finish up. */
2311 if (epartIsReg(modrm)) {
2312 putIReg(sz, eregOfRM(modrm), mkexpr(dst1));
sewardjf48ac192004-10-29 00:41:29 +00002313 if (vex_traceflags & VEX_TRACE_FE) {
sewardje90ad6a2004-07-10 19:02:10 +00002314 vex_printf("%s%c ",
2315 nameGrp2(gregOfRM(modrm)), nameISize(sz) );
sewardj6d2638e2004-07-15 09:38:27 +00002316 if (shift_expr_txt)
2317 vex_printf("%s", shift_expr_txt);
2318 else
2319 ppIRExpr(shift_expr);
sewardje90ad6a2004-07-10 19:02:10 +00002320 vex_printf(", %s\n", nameIReg(sz,eregOfRM(modrm)));
2321 }
sewardje90ad6a2004-07-10 19:02:10 +00002322 } else {
sewardj940e8c92004-07-11 16:53:24 +00002323 storeLE(mkexpr(addr), mkexpr(dst1));
sewardjf48ac192004-10-29 00:41:29 +00002324 if (vex_traceflags & VEX_TRACE_FE) {
sewardj940e8c92004-07-11 16:53:24 +00002325 vex_printf("%s%c ",
2326 nameGrp2(gregOfRM(modrm)), nameISize(sz) );
sewardj6d2638e2004-07-15 09:38:27 +00002327 if (shift_expr_txt)
2328 vex_printf("%s", shift_expr_txt);
2329 else
2330 ppIRExpr(shift_expr);
sewardj940e8c92004-07-11 16:53:24 +00002331 vex_printf(", %s\n", dis_buf);
2332 }
sewardje90ad6a2004-07-10 19:02:10 +00002333 }
sewardje90ad6a2004-07-10 19:02:10 +00002334 return delta;
2335}
2336
2337
sewardj490ad382005-03-13 17:25:53 +00002338/* Group 8 extended opcodes (but BT/BTS/BTC/BTR only). */
2339static
sewardj52d04912005-07-03 00:52:48 +00002340UInt dis_Grp8_Imm ( UChar sorb,
2341 Int delta, UChar modrm,
sewardj490ad382005-03-13 17:25:53 +00002342 Int am_sz, Int sz, UInt src_val,
2343 Bool* decode_OK )
2344{
2345 /* src_val denotes a d8.
2346 And delta on entry points at the modrm byte. */
sewardje90ad6a2004-07-10 19:02:10 +00002347
sewardj490ad382005-03-13 17:25:53 +00002348 IRType ty = szToITy(sz);
2349 IRTemp t2 = newTemp(Ity_I32);
2350 IRTemp t2m = newTemp(Ity_I32);
2351 IRTemp t_addr = IRTemp_INVALID;
2352 HChar dis_buf[50];
2353 UInt mask;
sewardjd1061ab2004-07-08 01:45:30 +00002354
sewardj490ad382005-03-13 17:25:53 +00002355 /* we're optimists :-) */
2356 *decode_OK = True;
sewardjd1061ab2004-07-08 01:45:30 +00002357
sewardj490ad382005-03-13 17:25:53 +00002358 /* Limit src_val -- the bit offset -- to something within a word.
2359 The Intel docs say that literal offsets larger than a word are
2360 masked in this way. */
2361 switch (sz) {
2362 case 2: src_val &= 15; break;
2363 case 4: src_val &= 31; break;
2364 default: *decode_OK = False; return delta;
2365 }
sewardjcf780b42004-07-13 18:42:17 +00002366
sewardj490ad382005-03-13 17:25:53 +00002367 /* Invent a mask suitable for the operation. */
2368 switch (gregOfRM(modrm)) {
2369 case 4: /* BT */ mask = 0; break;
2370 case 5: /* BTS */ mask = 1 << src_val; break;
2371 case 6: /* BTR */ mask = ~(1 << src_val); break;
2372 case 7: /* BTC */ mask = 1 << src_val; break;
2373 /* If this needs to be extended, probably simplest to make a
2374 new function to handle the other cases (0 .. 3). The
2375 Intel docs do however not indicate any use for 0 .. 3, so
2376 we don't expect this to happen. */
2377 default: *decode_OK = False; return delta;
2378 }
2379
2380 /* Fetch the value to be tested and modified into t2, which is
2381 32-bits wide regardless of sz. */
2382 if (epartIsReg(modrm)) {
2383 vassert(am_sz == 1);
sewardj5a8334e2005-03-13 19:52:45 +00002384 assign( t2, widenUto32(getIReg(sz, eregOfRM(modrm))) );
sewardj490ad382005-03-13 17:25:53 +00002385 delta += (am_sz + 1);
2386 DIP("%s%c $0x%x, %s\n", nameGrp8(gregOfRM(modrm)), nameISize(sz),
2387 src_val, nameIReg(sz,eregOfRM(modrm)));
2388 } else {
2389 Int len;
2390 t_addr = disAMode ( &len, sorb, delta, dis_buf);
2391 delta += (len+1);
2392 assign( t2, widenUto32(loadLE(ty, mkexpr(t_addr))) );
2393 DIP("%s%c $0x%x, %s\n", nameGrp8(gregOfRM(modrm)), nameISize(sz),
2394 src_val, dis_buf);
2395 }
2396
2397 /* Copy relevant bit from t2 into the carry flag. */
2398 /* Flags: C=selected bit, O,S,Z,A,P undefined, so are set to zero. */
2399 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
2400 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
2401 stmt( IRStmt_Put(
2402 OFFB_CC_DEP1,
2403 binop(Iop_And32,
2404 binop(Iop_Shr32, mkexpr(t2), mkU8(src_val)),
2405 mkU32(1))
2406 ));
sewardja3b7e3a2005-04-05 01:54:19 +00002407 /* Set NDEP even though it isn't used. This makes redundant-PUT
2408 elimination of previous stores to this field work better. */
2409 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardj490ad382005-03-13 17:25:53 +00002410
2411 /* Compute the new value into t2m, if non-BT. */
2412 switch (gregOfRM(modrm)) {
2413 case 4: /* BT */
2414 break;
2415 case 5: /* BTS */
2416 assign( t2m, binop(Iop_Or32, mkU32(mask), mkexpr(t2)) );
2417 break;
2418 case 6: /* BTR */
2419 assign( t2m, binop(Iop_And32, mkU32(mask), mkexpr(t2)) );
2420 break;
2421 case 7: /* BTC */
2422 assign( t2m, binop(Iop_Xor32, mkU32(mask), mkexpr(t2)) );
2423 break;
sewardjba89f4c2005-04-07 17:31:27 +00002424 default:
2425 /*NOTREACHED*/ /*the previous switch guards this*/
sewardj490ad382005-03-13 17:25:53 +00002426 vassert(0);
2427 }
2428
2429 /* Write the result back, if non-BT. */
2430 if (gregOfRM(modrm) != 4 /* BT */) {
2431 if (epartIsReg(modrm)) {
2432 putIReg(sz, eregOfRM(modrm), narrowTo(ty, mkexpr(t2m)));
2433 } else {
2434 storeLE(mkexpr(t_addr), narrowTo(ty, mkexpr(t2m)));
2435 }
2436 }
2437
2438 return delta;
2439}
sewardjcf780b42004-07-13 18:42:17 +00002440
2441
sewardj1813dbe2004-07-28 17:09:04 +00002442/* Signed/unsigned widening multiply. Generate IR to multiply the
2443 value in EAX/AX/AL by the given IRTemp, and park the result in
2444 EDX:EAX/DX:AX/AX.
sewardjcf780b42004-07-13 18:42:17 +00002445*/
sewardj1813dbe2004-07-28 17:09:04 +00002446static void codegen_mulL_A_D ( Int sz, Bool syned,
sewardj2d49b432005-02-01 00:37:06 +00002447 IRTemp tmp, HChar* tmp_txt )
sewardjcf780b42004-07-13 18:42:17 +00002448{
sewardjcf780b42004-07-13 18:42:17 +00002449 IRType ty = szToITy(sz);
2450 IRTemp t1 = newTemp(ty);
sewardjcf780b42004-07-13 18:42:17 +00002451
sewardj1813dbe2004-07-28 17:09:04 +00002452 assign( t1, getIReg(sz, R_EAX) );
sewardjcf780b42004-07-13 18:42:17 +00002453
2454 switch (ty) {
sewardjb81f8b32004-07-30 10:17:50 +00002455 case Ity_I32: {
2456 IRTemp res64 = newTemp(Ity_I64);
sewardj948d48b2004-11-05 19:49:09 +00002457 IRTemp resHi = newTemp(Ity_I32);
2458 IRTemp resLo = newTemp(Ity_I32);
sewardjb81f8b32004-07-30 10:17:50 +00002459 IROp mulOp = syned ? Iop_MullS32 : Iop_MullU32;
sewardj2a9ad022004-11-25 02:46:58 +00002460 UInt tBaseOp = syned ? X86G_CC_OP_SMULB : X86G_CC_OP_UMULB;
sewardj2a2ba8b2004-11-08 13:14:06 +00002461 setFlags_MUL ( Ity_I32, t1, tmp, tBaseOp );
sewardjb81f8b32004-07-30 10:17:50 +00002462 assign( res64, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
sewardj948d48b2004-11-05 19:49:09 +00002463 assign( resHi, unop(Iop_64HIto32,mkexpr(res64)));
2464 assign( resLo, unop(Iop_64to32,mkexpr(res64)));
sewardj948d48b2004-11-05 19:49:09 +00002465 putIReg(4, R_EDX, mkexpr(resHi));
2466 putIReg(4, R_EAX, mkexpr(resLo));
sewardjb81f8b32004-07-30 10:17:50 +00002467 break;
2468 }
2469 case Ity_I16: {
2470 IRTemp res32 = newTemp(Ity_I32);
sewardj948d48b2004-11-05 19:49:09 +00002471 IRTemp resHi = newTemp(Ity_I16);
2472 IRTemp resLo = newTemp(Ity_I16);
sewardjb81f8b32004-07-30 10:17:50 +00002473 IROp mulOp = syned ? Iop_MullS16 : Iop_MullU16;
sewardj2a9ad022004-11-25 02:46:58 +00002474 UInt tBaseOp = syned ? X86G_CC_OP_SMULB : X86G_CC_OP_UMULB;
sewardj2a2ba8b2004-11-08 13:14:06 +00002475 setFlags_MUL ( Ity_I16, t1, tmp, tBaseOp );
sewardjb81f8b32004-07-30 10:17:50 +00002476 assign( res32, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
sewardj948d48b2004-11-05 19:49:09 +00002477 assign( resHi, unop(Iop_32HIto16,mkexpr(res32)));
2478 assign( resLo, unop(Iop_32to16,mkexpr(res32)));
sewardj948d48b2004-11-05 19:49:09 +00002479 putIReg(2, R_EDX, mkexpr(resHi));
2480 putIReg(2, R_EAX, mkexpr(resLo));
sewardjb81f8b32004-07-30 10:17:50 +00002481 break;
2482 }
2483 case Ity_I8: {
2484 IRTemp res16 = newTemp(Ity_I16);
sewardj948d48b2004-11-05 19:49:09 +00002485 IRTemp resHi = newTemp(Ity_I8);
2486 IRTemp resLo = newTemp(Ity_I8);
sewardjb81f8b32004-07-30 10:17:50 +00002487 IROp mulOp = syned ? Iop_MullS8 : Iop_MullU8;
sewardj2a9ad022004-11-25 02:46:58 +00002488 UInt tBaseOp = syned ? X86G_CC_OP_SMULB : X86G_CC_OP_UMULB;
sewardj2a2ba8b2004-11-08 13:14:06 +00002489 setFlags_MUL ( Ity_I8, t1, tmp, tBaseOp );
sewardjb81f8b32004-07-30 10:17:50 +00002490 assign( res16, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
sewardj948d48b2004-11-05 19:49:09 +00002491 assign( resHi, unop(Iop_16HIto8,mkexpr(res16)));
2492 assign( resLo, unop(Iop_16to8,mkexpr(res16)));
sewardjb81f8b32004-07-30 10:17:50 +00002493 putIReg(2, R_EAX, mkexpr(res16));
2494 break;
2495 }
2496 default:
2497 vpanic("codegen_mulL_A_D(x86)");
sewardjcf780b42004-07-13 18:42:17 +00002498 }
sewardj1813dbe2004-07-28 17:09:04 +00002499 DIP("%s%c %s\n", syned ? "imul" : "mul", nameISize(sz), tmp_txt);
sewardjcf780b42004-07-13 18:42:17 +00002500}
2501
sewardj940e8c92004-07-11 16:53:24 +00002502
2503/* Group 3 extended opcodes. */
2504static
sewardj52d04912005-07-03 00:52:48 +00002505UInt dis_Grp3 ( UChar sorb, Int sz, Int delta )
sewardj940e8c92004-07-11 16:53:24 +00002506{
sewardjc9a43662004-11-30 18:51:59 +00002507 UInt d32;
2508 UChar modrm;
2509 HChar dis_buf[50];
2510 Int len;
sewardjc2ac51e2004-07-12 01:03:26 +00002511 IRTemp addr;
sewardj940e8c92004-07-11 16:53:24 +00002512 IRType ty = szToITy(sz);
2513 IRTemp t1 = newTemp(ty);
sewardj92d168d2004-11-15 14:22:12 +00002514 // IRTemp t2 = IRTemp_INVALID;
sewardj940e8c92004-07-11 16:53:24 +00002515 IRTemp dst1, src, dst0;
2516 modrm = getIByte(delta);
2517 if (epartIsReg(modrm)) {
2518 switch (gregOfRM(modrm)) {
sewardjc2ac51e2004-07-12 01:03:26 +00002519 case 0: { /* TEST */
2520 delta++; d32 = getUDisp(sz, delta); delta += sz;
sewardj5bd4d162004-11-10 13:02:48 +00002521 dst1 = newTemp(ty);
2522 assign(dst1, binop(mkSizedOp(ty,Iop_And8),
2523 getIReg(sz,eregOfRM(modrm)),
sewardjc2ac51e2004-07-12 01:03:26 +00002524 mkU(ty,d32)));
sewardj5bd4d162004-11-10 13:02:48 +00002525 setFlags_DEP1( Iop_And8, dst1, ty );
sewardjc2ac51e2004-07-12 01:03:26 +00002526 DIP("test%c $0x%x, %s\n", nameISize(sz), d32,
2527 nameIReg(sz, eregOfRM(modrm)));
2528 break;
2529 }
sewardj940e8c92004-07-11 16:53:24 +00002530 case 2: /* NOT */
2531 delta++;
2532 putIReg(sz, eregOfRM(modrm),
2533 unop(mkSizedOp(ty,Iop_Not8),
2534 getIReg(sz, eregOfRM(modrm))));
2535 DIP("not%c %s\n", nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
2536 break;
2537 case 3: /* NEG */
2538 delta++;
2539 dst0 = newTemp(ty);
2540 src = newTemp(ty);
2541 dst1 = newTemp(ty);
sewardj5bd4d162004-11-10 13:02:48 +00002542 assign(dst0, mkU(ty,0));
sewardja511afc2004-07-29 22:26:03 +00002543 assign(src, getIReg(sz,eregOfRM(modrm)));
sewardj71a35e72005-05-03 12:20:15 +00002544 assign(dst1, unop(mkSizedOp(ty,Iop_Neg8), mkexpr(src)));
sewardj2a2ba8b2004-11-08 13:14:06 +00002545 setFlags_DEP1_DEP2(Iop_Sub8, dst0, src, ty);
sewardj5bd4d162004-11-10 13:02:48 +00002546 putIReg(sz, eregOfRM(modrm), mkexpr(dst1));
sewardj940e8c92004-07-11 16:53:24 +00002547 DIP("neg%c %s\n", nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
2548 break;
sewardjcf780b42004-07-13 18:42:17 +00002549 case 4: /* MUL (unsigned widening) */
2550 delta++;
sewardj1813dbe2004-07-28 17:09:04 +00002551 src = newTemp(ty);
sewardj5bd4d162004-11-10 13:02:48 +00002552 assign(src, getIReg(sz,eregOfRM(modrm)));
sewardj1813dbe2004-07-28 17:09:04 +00002553 codegen_mulL_A_D ( sz, False, src, nameIReg(sz,eregOfRM(modrm)) );
sewardjcf780b42004-07-13 18:42:17 +00002554 break;
sewardjcaca9d02004-07-28 07:11:32 +00002555 case 5: /* IMUL (signed widening) */
2556 delta++;
sewardj1813dbe2004-07-28 17:09:04 +00002557 src = newTemp(ty);
sewardj5bd4d162004-11-10 13:02:48 +00002558 assign(src, getIReg(sz,eregOfRM(modrm)));
sewardj1813dbe2004-07-28 17:09:04 +00002559 codegen_mulL_A_D ( sz, True, src, nameIReg(sz,eregOfRM(modrm)) );
sewardjcaca9d02004-07-28 07:11:32 +00002560 break;
sewardj68511542004-07-28 00:15:44 +00002561 case 6: /* DIV */
2562 delta++;
2563 assign( t1, getIReg(sz, eregOfRM(modrm)) );
2564 codegen_div ( sz, t1, False );
2565 DIP("div%c %s\n", nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
2566 break;
sewardjcaca9d02004-07-28 07:11:32 +00002567 case 7: /* IDIV */
2568 delta++;
2569 assign( t1, getIReg(sz, eregOfRM(modrm)) );
2570 codegen_div ( sz, t1, True );
2571 DIP("idiv%c %s\n", nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
2572 break;
sewardj940e8c92004-07-11 16:53:24 +00002573 default:
2574 vex_printf(
sewardj2d49b432005-02-01 00:37:06 +00002575 "unhandled Grp3(R) case %d\n", (Int)gregOfRM(modrm));
sewardj940e8c92004-07-11 16:53:24 +00002576 vpanic("Grp3(x86)");
2577 }
2578 } else {
sewardjc2ac51e2004-07-12 01:03:26 +00002579 addr = disAMode ( &len, sorb, delta, dis_buf );
2580 t1 = newTemp(ty);
2581 delta += len;
2582 assign(t1, loadLE(ty,mkexpr(addr)));
2583 switch (gregOfRM(modrm)) {
2584 case 0: { /* TEST */
2585 d32 = getUDisp(sz, delta); delta += sz;
sewardj5bd4d162004-11-10 13:02:48 +00002586 dst1 = newTemp(ty);
2587 assign(dst1, binop(mkSizedOp(ty,Iop_And8),
2588 mkexpr(t1), mkU(ty,d32)));
2589 setFlags_DEP1( Iop_And8, dst1, ty );
sewardjc2ac51e2004-07-12 01:03:26 +00002590 DIP("test%c $0x%x, %s\n", nameISize(sz), d32, dis_buf);
2591 break;
2592 }
sewardj78fe7912004-08-20 23:38:07 +00002593 case 2: /* NOT */
2594 storeLE( mkexpr(addr), unop(mkSizedOp(ty,Iop_Not8), mkexpr(t1)));
2595 DIP("not%c %s\n", nameISize(sz), dis_buf);
2596 break;
sewardj0c12ea82004-07-12 08:18:16 +00002597 case 3: /* NEG */
2598 dst0 = newTemp(ty);
2599 src = newTemp(ty);
2600 dst1 = newTemp(ty);
sewardj5bd4d162004-11-10 13:02:48 +00002601 assign(dst0, mkU(ty,0));
sewardja511afc2004-07-29 22:26:03 +00002602 assign(src, mkexpr(t1));
sewardj71a35e72005-05-03 12:20:15 +00002603 assign(dst1, unop(mkSizedOp(ty,Iop_Neg8), mkexpr(src)));
sewardj2a2ba8b2004-11-08 13:14:06 +00002604 setFlags_DEP1_DEP2(Iop_Sub8, dst0, src, ty);
sewardj5bd4d162004-11-10 13:02:48 +00002605 storeLE( mkexpr(addr), mkexpr(dst1) );
sewardj0c12ea82004-07-12 08:18:16 +00002606 DIP("neg%c %s\n", nameISize(sz), dis_buf);
2607 break;
sewardj1813dbe2004-07-28 17:09:04 +00002608 case 4: /* MUL */
2609 codegen_mulL_A_D ( sz, False, t1, dis_buf );
2610 break;
2611 case 5: /* IMUL */
2612 codegen_mulL_A_D ( sz, True, t1, dis_buf );
2613 break;
sewardj9690d922004-07-14 01:39:17 +00002614 case 6: /* DIV */
2615 codegen_div ( sz, t1, False );
2616 DIP("div%c %s\n", nameISize(sz), dis_buf);
2617 break;
sewardj1813dbe2004-07-28 17:09:04 +00002618 case 7: /* IDIV */
2619 codegen_div ( sz, t1, True );
2620 DIP("idiv%c %s\n", nameISize(sz), dis_buf);
2621 break;
sewardjc2ac51e2004-07-12 01:03:26 +00002622 default:
2623 vex_printf(
sewardj2d49b432005-02-01 00:37:06 +00002624 "unhandled Grp3(M) case %d\n", (Int)gregOfRM(modrm));
sewardjc2ac51e2004-07-12 01:03:26 +00002625 vpanic("Grp3(x86)");
2626 }
sewardj940e8c92004-07-11 16:53:24 +00002627 }
2628 return delta;
2629}
2630
2631
sewardjc2ac51e2004-07-12 01:03:26 +00002632/* Group 4 extended opcodes. */
2633static
sewardj52d04912005-07-03 00:52:48 +00002634UInt dis_Grp4 ( UChar sorb, Int delta )
sewardjc2ac51e2004-07-12 01:03:26 +00002635{
sewardjc9a43662004-11-30 18:51:59 +00002636 Int alen;
sewardjc2ac51e2004-07-12 01:03:26 +00002637 UChar modrm;
sewardjc9a43662004-11-30 18:51:59 +00002638 HChar dis_buf[50];
sewardjc2ac51e2004-07-12 01:03:26 +00002639 IRType ty = Ity_I8;
sewardj7ed22952004-07-29 00:09:58 +00002640 IRTemp t1 = newTemp(ty);
2641 IRTemp t2 = newTemp(ty);
sewardjc2ac51e2004-07-12 01:03:26 +00002642
2643 modrm = getIByte(delta);
2644 if (epartIsReg(modrm)) {
sewardjc2ac51e2004-07-12 01:03:26 +00002645 assign(t1, getIReg(1, eregOfRM(modrm)));
2646 switch (gregOfRM(modrm)) {
sewardj7ed22952004-07-29 00:09:58 +00002647 case 0: /* INC */
2648 assign(t2, binop(Iop_Add8, mkexpr(t1), mkU8(1)));
2649 putIReg(1, eregOfRM(modrm), mkexpr(t2));
2650 setFlags_INC_DEC( True, t2, ty );
2651 break;
sewardjc2ac51e2004-07-12 01:03:26 +00002652 case 1: /* DEC */
sewardjc2ac51e2004-07-12 01:03:26 +00002653 assign(t2, binop(Iop_Sub8, mkexpr(t1), mkU8(1)));
2654 putIReg(1, eregOfRM(modrm), mkexpr(t2));
2655 setFlags_INC_DEC( False, t2, ty );
2656 break;
2657 default:
2658 vex_printf(
sewardj2d49b432005-02-01 00:37:06 +00002659 "unhandled Grp4(R) case %d\n", (Int)gregOfRM(modrm));
sewardj7ed22952004-07-29 00:09:58 +00002660 vpanic("Grp4(x86,R)");
sewardjc2ac51e2004-07-12 01:03:26 +00002661 }
2662 delta++;
2663 DIP("%sb %s\n", nameGrp4(gregOfRM(modrm)),
2664 nameIReg(1, eregOfRM(modrm)));
2665 } else {
sewardj7ed22952004-07-29 00:09:58 +00002666 IRTemp addr = disAMode ( &alen, sorb, delta, dis_buf );
2667 assign( t1, loadLE(ty, mkexpr(addr)) );
2668 switch (gregOfRM(modrm)) {
sewardj588ea762004-09-10 18:56:32 +00002669 case 0: /* INC */
2670 assign(t2, binop(Iop_Add8, mkexpr(t1), mkU8(1)));
2671 storeLE( mkexpr(addr), mkexpr(t2) );
2672 setFlags_INC_DEC( True, t2, ty );
2673 break;
sewardj7ed22952004-07-29 00:09:58 +00002674 case 1: /* DEC */
2675 assign(t2, binop(Iop_Sub8, mkexpr(t1), mkU8(1)));
2676 storeLE( mkexpr(addr), mkexpr(t2) );
2677 setFlags_INC_DEC( False, t2, ty );
2678 break;
2679 default:
2680 vex_printf(
sewardj2d49b432005-02-01 00:37:06 +00002681 "unhandled Grp4(M) case %d\n", (Int)gregOfRM(modrm));
sewardj7ed22952004-07-29 00:09:58 +00002682 vpanic("Grp4(x86,M)");
2683 }
2684 delta += alen;
2685 DIP("%sb %s\n", nameGrp4(gregOfRM(modrm)), dis_buf);
sewardjc2ac51e2004-07-12 01:03:26 +00002686 }
2687 return delta;
2688}
sewardj0611d802004-07-11 02:37:54 +00002689
2690
2691/* Group 5 extended opcodes. */
2692static
sewardj52d04912005-07-03 00:52:48 +00002693UInt dis_Grp5 ( UChar sorb, Int sz, Int delta, DisResult* dres )
sewardj0611d802004-07-11 02:37:54 +00002694{
2695 Int len;
2696 UChar modrm;
sewardjc9a43662004-11-30 18:51:59 +00002697 HChar dis_buf[50];
sewardj92d168d2004-11-15 14:22:12 +00002698 IRTemp addr = IRTemp_INVALID;
sewardj0611d802004-07-11 02:37:54 +00002699 IRType ty = szToITy(sz);
2700 IRTemp t1 = newTemp(ty);
sewardj92d168d2004-11-15 14:22:12 +00002701 IRTemp t2 = IRTemp_INVALID;
sewardj0611d802004-07-11 02:37:54 +00002702
2703 modrm = getIByte(delta);
2704 if (epartIsReg(modrm)) {
sewardj940e8c92004-07-11 16:53:24 +00002705 assign(t1, getIReg(sz,eregOfRM(modrm)));
sewardj0611d802004-07-11 02:37:54 +00002706 switch (gregOfRM(modrm)) {
sewardjc9a65702004-07-07 16:32:57 +00002707//-- case 0: /* INC */
2708//-- uInstr1(cb, INC, sz, TempReg, t1);
2709//-- setFlagsFromUOpcode(cb, INC);
2710//-- uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, eregOfRM(modrm));
2711//-- break;
2712//-- case 1: /* DEC */
2713//-- uInstr1(cb, DEC, sz, TempReg, t1);
2714//-- setFlagsFromUOpcode(cb, DEC);
2715//-- uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, eregOfRM(modrm));
2716//-- break;
sewardjc2ac51e2004-07-12 01:03:26 +00002717 case 2: /* call Ev */
2718 vassert(sz == 4);
2719 t2 = newTemp(Ity_I32);
2720 assign(t2, binop(Iop_Sub32, getIReg(4,R_ESP), mkU32(4)));
2721 putIReg(4, R_ESP, mkexpr(t2));
sewardj9e6491a2005-07-02 19:24:10 +00002722 storeLE( mkexpr(t2), mkU32(guest_EIP_bbstart+delta+1));
sewardj5bd4d162004-11-10 13:02:48 +00002723 jmp_treg(Ijk_Call,t1);
sewardj9e6491a2005-07-02 19:24:10 +00002724 dres->whatNext = Dis_StopHere;
sewardjc2ac51e2004-07-12 01:03:26 +00002725 break;
sewardj0611d802004-07-11 02:37:54 +00002726 case 4: /* jmp Ev */
2727 vassert(sz == 4);
sewardj78c19df2004-07-12 22:49:27 +00002728 jmp_treg(Ijk_Boring,t1);
sewardj9e6491a2005-07-02 19:24:10 +00002729 dres->whatNext = Dis_StopHere;
sewardj0611d802004-07-11 02:37:54 +00002730 break;
2731 default:
2732 vex_printf(
sewardj2d49b432005-02-01 00:37:06 +00002733 "unhandled Grp5(R) case %d\n", (Int)gregOfRM(modrm));
sewardj0611d802004-07-11 02:37:54 +00002734 vpanic("Grp5(x86)");
2735 }
2736 delta++;
2737 DIP("%s%c %s\n", nameGrp5(gregOfRM(modrm)),
2738 nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
2739 } else {
2740 addr = disAMode ( &len, sorb, delta, dis_buf );
sewardj940e8c92004-07-11 16:53:24 +00002741 assign(t1, loadLE(ty,mkexpr(addr)));
sewardj0611d802004-07-11 02:37:54 +00002742 switch (gregOfRM(modrm)) {
2743 case 0: /* INC */
2744 t2 = newTemp(ty);
2745 assign(t2, binop(mkSizedOp(ty,Iop_Add8),
2746 mkexpr(t1), mkU(ty,1)));
2747 setFlags_INC_DEC( True, t2, ty );
sewardj940e8c92004-07-11 16:53:24 +00002748 storeLE(mkexpr(addr),mkexpr(t2));
sewardj0611d802004-07-11 02:37:54 +00002749 break;
sewardjc2ac51e2004-07-12 01:03:26 +00002750 case 1: /* DEC */
2751 t2 = newTemp(ty);
2752 assign(t2, binop(mkSizedOp(ty,Iop_Sub8),
2753 mkexpr(t1), mkU(ty,1)));
2754 setFlags_INC_DEC( False, t2, ty );
2755 storeLE(mkexpr(addr),mkexpr(t2));
2756 break;
sewardj77b86be2004-07-11 13:28:24 +00002757 case 2: /* call Ev */
2758 vassert(sz == 4);
2759 t2 = newTemp(Ity_I32);
2760 assign(t2, binop(Iop_Sub32, getIReg(4,R_ESP), mkU32(4)));
2761 putIReg(4, R_ESP, mkexpr(t2));
sewardj9e6491a2005-07-02 19:24:10 +00002762 storeLE( mkexpr(t2), mkU32(guest_EIP_bbstart+delta+len));
sewardj5bd4d162004-11-10 13:02:48 +00002763 jmp_treg(Ijk_Call,t1);
sewardj9e6491a2005-07-02 19:24:10 +00002764 dres->whatNext = Dis_StopHere;
sewardj77b86be2004-07-11 13:28:24 +00002765 break;
2766 case 4: /* JMP Ev */
2767 vassert(sz == 4);
sewardj78c19df2004-07-12 22:49:27 +00002768 jmp_treg(Ijk_Boring,t1);
sewardj9e6491a2005-07-02 19:24:10 +00002769 dres->whatNext = Dis_StopHere;
sewardj77b86be2004-07-11 13:28:24 +00002770 break;
sewardj0c12ea82004-07-12 08:18:16 +00002771 case 6: /* PUSH Ev */
2772 vassert(sz == 4 || sz == 2);
2773 t2 = newTemp(Ity_I32);
2774 assign( t2, binop(Iop_Sub32,getIReg(4,R_ESP),mkU32(sz)) );
2775 putIReg(4, R_ESP, mkexpr(t2) );
sewardj5bd4d162004-11-10 13:02:48 +00002776 storeLE( mkexpr(t2), mkexpr(t1) );
sewardj0c12ea82004-07-12 08:18:16 +00002777 break;
sewardj0611d802004-07-11 02:37:54 +00002778 default:
2779 vex_printf(
sewardj2d49b432005-02-01 00:37:06 +00002780 "unhandled Grp5(M) case %d\n", (Int)gregOfRM(modrm));
sewardj0611d802004-07-11 02:37:54 +00002781 vpanic("Grp5(x86)");
2782 }
2783 delta += len;
2784 DIP("%s%c %s\n", nameGrp5(gregOfRM(modrm)),
2785 nameISize(sz), dis_buf);
2786 }
2787 return delta;
2788}
2789
sewardj464efa42004-11-19 22:17:29 +00002790
sewardj64e1d652004-07-12 14:00:46 +00002791/*------------------------------------------------------------*/
2792/*--- Disassembling string ops (including REP prefixes) ---*/
2793/*------------------------------------------------------------*/
2794
2795/* Code shared by all the string ops */
2796static
2797void dis_string_op_increment(Int sz, Int t_inc)
2798{
2799 if (sz == 4 || sz == 2) {
2800 assign( t_inc,
2801 binop(Iop_Shl32, IRExpr_Get( OFFB_DFLAG, Ity_I32 ),
sewardj6d2638e2004-07-15 09:38:27 +00002802 mkU8(sz/2) ) );
sewardj64e1d652004-07-12 14:00:46 +00002803 } else {
2804 assign( t_inc,
2805 IRExpr_Get( OFFB_DFLAG, Ity_I32 ) );
2806 }
2807}
2808
sewardj64e1d652004-07-12 14:00:46 +00002809static
2810void dis_string_op( void (*dis_OP)( Int, IRTemp ),
sewardj2d49b432005-02-01 00:37:06 +00002811 Int sz, HChar* name, UChar sorb )
sewardj64e1d652004-07-12 14:00:46 +00002812{
2813 IRTemp t_inc = newTemp(Ity_I32);
2814 vassert(sorb == 0);
2815 dis_string_op_increment(sz, t_inc);
2816 dis_OP( sz, t_inc );
2817 DIP("%s%c\n", name, nameISize(sz));
2818}
sewardj64e1d652004-07-12 14:00:46 +00002819
2820static
2821void dis_MOVS ( Int sz, IRTemp t_inc )
2822{
2823 IRType ty = szToITy(sz);
sewardj64e1d652004-07-12 14:00:46 +00002824 IRTemp td = newTemp(Ity_I32); /* EDI */
2825 IRTemp ts = newTemp(Ity_I32); /* ESI */
2826
sewardj64e1d652004-07-12 14:00:46 +00002827 assign( td, getIReg(4, R_EDI) );
2828 assign( ts, getIReg(4, R_ESI) );
2829
sewardj64e1d652004-07-12 14:00:46 +00002830 storeLE( mkexpr(td), loadLE(ty,mkexpr(ts)) );
2831
sewardj64e1d652004-07-12 14:00:46 +00002832 putIReg( 4, R_EDI, binop(Iop_Add32, mkexpr(td), mkexpr(t_inc)) );
2833 putIReg( 4, R_ESI, binop(Iop_Add32, mkexpr(ts), mkexpr(t_inc)) );
2834}
2835
sewardj10ca4eb2005-05-30 11:19:54 +00002836static
2837void dis_LODS ( Int sz, IRTemp t_inc )
2838{
2839 IRType ty = szToITy(sz);
2840 IRTemp ts = newTemp(Ity_I32); /* ESI */
2841
2842 assign( ts, getIReg(4, R_ESI) );
2843
2844 putIReg( sz, R_EAX, loadLE(ty, mkexpr(ts)) );
2845
2846 putIReg( 4, R_ESI, binop(Iop_Add32, mkexpr(ts), mkexpr(t_inc)) );
2847}
sewardj64e1d652004-07-12 14:00:46 +00002848
2849static
2850void dis_STOS ( Int sz, IRTemp t_inc )
2851{
2852 IRType ty = szToITy(sz);
2853 IRTemp ta = newTemp(ty); /* EAX */
2854 IRTemp td = newTemp(Ity_I32); /* EDI */
2855
sewardj64e1d652004-07-12 14:00:46 +00002856 assign( ta, getIReg(sz, R_EAX) );
sewardj64e1d652004-07-12 14:00:46 +00002857 assign( td, getIReg(4, R_EDI) );
2858
sewardj6d2638e2004-07-15 09:38:27 +00002859 storeLE( mkexpr(td), mkexpr(ta) );
sewardj64e1d652004-07-12 14:00:46 +00002860
sewardj64e1d652004-07-12 14:00:46 +00002861 putIReg( 4, R_EDI, binop(Iop_Add32, mkexpr(td), mkexpr(t_inc)) );
2862}
2863
2864static
2865void dis_CMPS ( Int sz, IRTemp t_inc )
2866{
2867 IRType ty = szToITy(sz);
sewardj6d2638e2004-07-15 09:38:27 +00002868 IRTemp tdv = newTemp(ty); /* (EDI) */
2869 IRTemp tsv = newTemp(ty); /* (ESI) */
sewardj64e1d652004-07-12 14:00:46 +00002870 IRTemp td = newTemp(Ity_I32); /* EDI */
2871 IRTemp ts = newTemp(Ity_I32); /* ESI */
2872
sewardj64e1d652004-07-12 14:00:46 +00002873 assign( td, getIReg(4, R_EDI) );
sewardj64e1d652004-07-12 14:00:46 +00002874 assign( ts, getIReg(4, R_ESI) );
2875
sewardj64e1d652004-07-12 14:00:46 +00002876 assign( tdv, loadLE(ty,mkexpr(td)) );
sewardjb9c5cf62004-08-24 15:10:38 +00002877 assign( tsv, loadLE(ty,mkexpr(ts)) );
sewardj64e1d652004-07-12 14:00:46 +00002878
sewardj2a2ba8b2004-11-08 13:14:06 +00002879 setFlags_DEP1_DEP2 ( Iop_Sub8, tsv, tdv, ty );
sewardj64e1d652004-07-12 14:00:46 +00002880
sewardj64e1d652004-07-12 14:00:46 +00002881 putIReg(4, R_EDI, binop(Iop_Add32, mkexpr(td), mkexpr(t_inc)) );
sewardj64e1d652004-07-12 14:00:46 +00002882 putIReg(4, R_ESI, binop(Iop_Add32, mkexpr(ts), mkexpr(t_inc)) );
2883}
2884
sewardj64e1d652004-07-12 14:00:46 +00002885static
2886void dis_SCAS ( Int sz, IRTemp t_inc )
2887{
2888 IRType ty = szToITy(sz);
sewardj82292882004-07-27 00:15:59 +00002889 IRTemp ta = newTemp(ty); /* EAX */
sewardj64e1d652004-07-12 14:00:46 +00002890 IRTemp td = newTemp(Ity_I32); /* EDI */
2891 IRTemp tdv = newTemp(ty); /* (EDI) */
2892
sewardjb9c5cf62004-08-24 15:10:38 +00002893 assign( ta, getIReg(sz, R_EAX) );
sewardj64e1d652004-07-12 14:00:46 +00002894 assign( td, getIReg(4, R_EDI) );
2895
sewardj64e1d652004-07-12 14:00:46 +00002896 assign( tdv, loadLE(ty,mkexpr(td)) );
sewardj2a2ba8b2004-11-08 13:14:06 +00002897 setFlags_DEP1_DEP2 ( Iop_Sub8, ta, tdv, ty );
sewardj64e1d652004-07-12 14:00:46 +00002898
sewardj64e1d652004-07-12 14:00:46 +00002899 putIReg(4, R_EDI, binop(Iop_Add32, mkexpr(td), mkexpr(t_inc)) );
2900}
sewardj82292882004-07-27 00:15:59 +00002901
sewardj64e1d652004-07-12 14:00:46 +00002902
2903/* Wrap the appropriate string op inside a REP/REPE/REPNE.
2904 We assume the insn is the last one in the basic block, and so emit a jump
2905 to the next insn, rather than just falling through. */
2906static
sewardj2a9ad022004-11-25 02:46:58 +00002907void dis_REP_op ( X86Condcode cond,
sewardj64e1d652004-07-12 14:00:46 +00002908 void (*dis_OP)(Int, IRTemp),
sewardj2d49b432005-02-01 00:37:06 +00002909 Int sz, Addr32 eip, Addr32 eip_next, HChar* name )
sewardj64e1d652004-07-12 14:00:46 +00002910{
2911 IRTemp t_inc = newTemp(Ity_I32);
2912 IRTemp tc = newTemp(Ity_I32); /* ECX */
2913
sewardj64e1d652004-07-12 14:00:46 +00002914 assign( tc, getIReg(4,R_ECX) );
2915
sewardj64e1d652004-07-12 14:00:46 +00002916 stmt( IRStmt_Exit( binop(Iop_CmpEQ32,mkexpr(tc),mkU32(0)),
sewardj893aada2004-11-29 19:57:54 +00002917 Ijk_Boring,
sewardj64e1d652004-07-12 14:00:46 +00002918 IRConst_U32(eip_next) ) );
2919
sewardj64e1d652004-07-12 14:00:46 +00002920 putIReg(4, R_ECX, binop(Iop_Sub32, mkexpr(tc), mkU32(1)) );
2921
2922 dis_string_op_increment(sz, t_inc);
2923 dis_OP (sz, t_inc);
2924
sewardj2a9ad022004-11-25 02:46:58 +00002925 if (cond == X86CondAlways) {
sewardj78c19df2004-07-12 22:49:27 +00002926 jmp_lit(Ijk_Boring,eip);
sewardj64e1d652004-07-12 14:00:46 +00002927 } else {
sewardj2a9ad022004-11-25 02:46:58 +00002928 stmt( IRStmt_Exit( mk_x86g_calculate_condition(cond),
sewardj893aada2004-11-29 19:57:54 +00002929 Ijk_Boring,
sewardj5bd4d162004-11-10 13:02:48 +00002930 IRConst_U32(eip) ) );
sewardj78c19df2004-07-12 22:49:27 +00002931 jmp_lit(Ijk_Boring,eip_next);
sewardj64e1d652004-07-12 14:00:46 +00002932 }
2933 DIP("%s%c\n", name, nameISize(sz));
2934}
2935
sewardj464efa42004-11-19 22:17:29 +00002936
sewardj64e1d652004-07-12 14:00:46 +00002937/*------------------------------------------------------------*/
2938/*--- Arithmetic, etc. ---*/
2939/*------------------------------------------------------------*/
2940
sewardj2a2ba8b2004-11-08 13:14:06 +00002941/* IMUL E, G. Supplied eip points to the modR/M byte. */
sewardjcf780b42004-07-13 18:42:17 +00002942static
2943UInt dis_mul_E_G ( UChar sorb,
2944 Int size,
sewardj52d04912005-07-03 00:52:48 +00002945 Int delta0 )
sewardjcf780b42004-07-13 18:42:17 +00002946{
sewardj71a65362004-07-28 01:48:34 +00002947 Int alen;
sewardjc9a43662004-11-30 18:51:59 +00002948 HChar dis_buf[50];
sewardjcf780b42004-07-13 18:42:17 +00002949 UChar rm = getIByte(delta0);
2950 IRType ty = szToITy(size);
sewardj6d2638e2004-07-15 09:38:27 +00002951 IRTemp te = newTemp(ty);
2952 IRTemp tg = newTemp(ty);
sewardj948d48b2004-11-05 19:49:09 +00002953 IRTemp resLo = newTemp(ty);
sewardj71a65362004-07-28 01:48:34 +00002954
sewardj948d48b2004-11-05 19:49:09 +00002955 assign( tg, getIReg(size, gregOfRM(rm)) );
sewardjcf780b42004-07-13 18:42:17 +00002956 if (epartIsReg(rm)) {
sewardjcf780b42004-07-13 18:42:17 +00002957 assign( te, getIReg(size, eregOfRM(rm)) );
sewardj948d48b2004-11-05 19:49:09 +00002958 } else {
2959 IRTemp addr = disAMode( &alen, sorb, delta0, dis_buf );
2960 assign( te, loadLE(ty,mkexpr(addr)) );
2961 }
sewardjcf780b42004-07-13 18:42:17 +00002962
sewardj2a9ad022004-11-25 02:46:58 +00002963 setFlags_MUL ( ty, te, tg, X86G_CC_OP_SMULB );
sewardj948d48b2004-11-05 19:49:09 +00002964
sewardj2a2ba8b2004-11-08 13:14:06 +00002965 assign( resLo, binop( mkSizedOp(ty, Iop_Mul8), mkexpr(te), mkexpr(tg) ) );
sewardj948d48b2004-11-05 19:49:09 +00002966
2967 putIReg(size, gregOfRM(rm), mkexpr(resLo) );
2968
2969 if (epartIsReg(rm)) {
sewardj2a2ba8b2004-11-08 13:14:06 +00002970 DIP("imul%c %s, %s\n", nameISize(size),
2971 nameIReg(size,eregOfRM(rm)),
2972 nameIReg(size,gregOfRM(rm)));
sewardjcf780b42004-07-13 18:42:17 +00002973 return 1+delta0;
2974 } else {
sewardj2a2ba8b2004-11-08 13:14:06 +00002975 DIP("imul%c %s, %s\n", nameISize(size),
2976 dis_buf, nameIReg(size,gregOfRM(rm)));
sewardj71a65362004-07-28 01:48:34 +00002977 return alen+delta0;
sewardjcf780b42004-07-13 18:42:17 +00002978 }
2979}
2980
2981
sewardj1813dbe2004-07-28 17:09:04 +00002982/* IMUL I * E -> G. Supplied eip points to the modR/M byte. */
2983static
2984UInt dis_imul_I_E_G ( UChar sorb,
2985 Int size,
sewardj52d04912005-07-03 00:52:48 +00002986 Int delta,
sewardj1813dbe2004-07-28 17:09:04 +00002987 Int litsize )
2988{
sewardj883b00b2004-09-11 09:30:24 +00002989 Int d32, alen;
sewardjc9a43662004-11-30 18:51:59 +00002990 HChar dis_buf[50];
sewardjb81f8b32004-07-30 10:17:50 +00002991 UChar rm = getIByte(delta);
sewardj1813dbe2004-07-28 17:09:04 +00002992 IRType ty = szToITy(size);
2993 IRTemp te = newTemp(ty);
2994 IRTemp tl = newTemp(ty);
sewardj948d48b2004-11-05 19:49:09 +00002995 IRTemp resLo = newTemp(ty);
sewardj1813dbe2004-07-28 17:09:04 +00002996
sewardjb81f8b32004-07-30 10:17:50 +00002997 vassert(size == 1 || size == 2 || size == 4);
2998
sewardj1813dbe2004-07-28 17:09:04 +00002999 if (epartIsReg(rm)) {
3000 assign(te, getIReg(size, eregOfRM(rm)));
3001 delta++;
3002 } else {
sewardj883b00b2004-09-11 09:30:24 +00003003 IRTemp addr = disAMode( &alen, sorb, delta, dis_buf );
3004 assign(te, loadLE(ty, mkexpr(addr)));
3005 delta += alen;
sewardj1813dbe2004-07-28 17:09:04 +00003006 }
3007 d32 = getSDisp(litsize,delta);
3008 delta += litsize;
3009
sewardjb81f8b32004-07-30 10:17:50 +00003010 if (size == 1) d32 &= 0xFF;
3011 if (size == 2) d32 &= 0xFFFF;
3012
sewardj1813dbe2004-07-28 17:09:04 +00003013 assign(tl, mkU(ty,d32));
sewardj948d48b2004-11-05 19:49:09 +00003014
sewardj2a2ba8b2004-11-08 13:14:06 +00003015 assign( resLo, binop( mkSizedOp(ty, Iop_Mul8), mkexpr(te), mkexpr(tl) ));
sewardj948d48b2004-11-05 19:49:09 +00003016
sewardj2a9ad022004-11-25 02:46:58 +00003017 setFlags_MUL ( ty, te, tl, X86G_CC_OP_SMULB );
sewardj948d48b2004-11-05 19:49:09 +00003018
3019 putIReg(size, gregOfRM(rm), mkexpr(resLo));
sewardj1813dbe2004-07-28 17:09:04 +00003020
3021 DIP("imul %d, %s, %s\n", d32,
3022 ( epartIsReg(rm) ? nameIReg(size,eregOfRM(rm)) : dis_buf ),
3023 nameIReg(size,gregOfRM(rm)) );
3024 return delta;
sewardj948d48b2004-11-05 19:49:09 +00003025}
sewardj1813dbe2004-07-28 17:09:04 +00003026
3027
sewardjd1725d12004-08-12 20:46:53 +00003028/*------------------------------------------------------------*/
sewardj464efa42004-11-19 22:17:29 +00003029/*--- ---*/
3030/*--- x87 FLOATING POINT INSTRUCTIONS ---*/
3031/*--- ---*/
sewardjd1725d12004-08-12 20:46:53 +00003032/*------------------------------------------------------------*/
3033
sewardj207557a2004-08-27 12:00:18 +00003034/* --- Helper functions for dealing with the register stack. --- */
3035
sewardj893aada2004-11-29 19:57:54 +00003036/* --- Set the emulation-warning pseudo-register. --- */
3037
3038static void put_emwarn ( IRExpr* e /* :: Ity_I32 */ )
3039{
sewardj86ed7622005-03-27 02:20:56 +00003040 vassert(typeOfIRExpr(irbb->tyenv, e) == Ity_I32);
sewardj893aada2004-11-29 19:57:54 +00003041 stmt( IRStmt_Put( OFFB_EMWARN, e ) );
3042}
3043
sewardj17442fe2004-09-20 14:54:28 +00003044/* --- Produce an IRExpr* denoting a 64-bit QNaN. --- */
sewardj207557a2004-08-27 12:00:18 +00003045
sewardj17442fe2004-09-20 14:54:28 +00003046static IRExpr* mkQNaN64 ( void )
sewardj207557a2004-08-27 12:00:18 +00003047{
sewardj17442fe2004-09-20 14:54:28 +00003048 /* QNaN is 0 2047 1 0(51times)
3049 == 0b 11111111111b 1 0(51times)
3050 == 0x7FF8 0000 0000 0000
3051 */
3052 return IRExpr_Const(IRConst_F64i(0x7FF8000000000000ULL));
sewardj207557a2004-08-27 12:00:18 +00003053}
3054
sewardj893aada2004-11-29 19:57:54 +00003055/* --------- Get/put the top-of-stack pointer. --------- */
sewardjd1725d12004-08-12 20:46:53 +00003056
3057static IRExpr* get_ftop ( void )
3058{
3059 return IRExpr_Get( OFFB_FTOP, Ity_I32 );
3060}
3061
sewardj207557a2004-08-27 12:00:18 +00003062static void put_ftop ( IRExpr* e )
sewardjd1725d12004-08-12 20:46:53 +00003063{
sewardj86ed7622005-03-27 02:20:56 +00003064 vassert(typeOfIRExpr(irbb->tyenv, e) == Ity_I32);
sewardj207557a2004-08-27 12:00:18 +00003065 stmt( IRStmt_Put( OFFB_FTOP, e ) );
sewardjd1725d12004-08-12 20:46:53 +00003066}
3067
sewardj893aada2004-11-29 19:57:54 +00003068/* --------- Get/put the C3210 bits. --------- */
sewardjbdc7d212004-09-09 02:46:40 +00003069
sewardjc4be80c2004-09-10 16:17:45 +00003070static IRExpr* get_C3210 ( void )
sewardjbdc7d212004-09-09 02:46:40 +00003071{
sewardjc4be80c2004-09-10 16:17:45 +00003072 return IRExpr_Get( OFFB_FC3210, Ity_I32 );
sewardjbdc7d212004-09-09 02:46:40 +00003073}
3074
sewardjc4be80c2004-09-10 16:17:45 +00003075static void put_C3210 ( IRExpr* e )
sewardjbdc7d212004-09-09 02:46:40 +00003076{
sewardjc4be80c2004-09-10 16:17:45 +00003077 stmt( IRStmt_Put( OFFB_FC3210, e ) );
sewardjbdc7d212004-09-09 02:46:40 +00003078}
sewardjd1725d12004-08-12 20:46:53 +00003079
sewardj893aada2004-11-29 19:57:54 +00003080/* --------- Get/put the FPU rounding mode. --------- */
sewardjd01a9632004-11-30 13:18:37 +00003081static IRExpr* /* :: Ity_I32 */ get_fpround ( void )
sewardj8f3debf2004-09-08 23:42:23 +00003082{
sewardjd01a9632004-11-30 13:18:37 +00003083 return IRExpr_Get( OFFB_FPROUND, Ity_I32 );
sewardj8f3debf2004-09-08 23:42:23 +00003084}
3085
sewardjd01a9632004-11-30 13:18:37 +00003086static void put_fpround ( IRExpr* /* :: Ity_I32 */ e )
sewardj8f3debf2004-09-08 23:42:23 +00003087{
sewardjd01a9632004-11-30 13:18:37 +00003088 stmt( IRStmt_Put( OFFB_FPROUND, e ) );
sewardj8f3debf2004-09-08 23:42:23 +00003089}
3090
3091
sewardj893aada2004-11-29 19:57:54 +00003092/* --------- Synthesise a 2-bit FPU rounding mode. --------- */
sewardj8f3debf2004-09-08 23:42:23 +00003093/* Produces a value in 0 .. 3, which is encoded as per the type
sewardjd01a9632004-11-30 13:18:37 +00003094 IRRoundingMode. Since the guest_FPROUND value is also encoded as
3095 per IRRoundingMode, we merely need to get it and mask it for
3096 safety.
sewardj8f3debf2004-09-08 23:42:23 +00003097*/
3098static IRExpr* /* :: Ity_I32 */ get_roundingmode ( void )
3099{
sewardjd01a9632004-11-30 13:18:37 +00003100 return binop( Iop_And32, get_fpround(), mkU32(3) );
sewardj8f3debf2004-09-08 23:42:23 +00003101}
3102
3103
sewardj207557a2004-08-27 12:00:18 +00003104/* --------- Get/set FP register tag bytes. --------- */
3105
sewardj207557a2004-08-27 12:00:18 +00003106/* Given i, and some expression e, generate 'ST_TAG(i) = e'. */
3107
3108static void put_ST_TAG ( Int i, IRExpr* value )
3109{
sewardj2d3f77c2004-09-22 23:49:09 +00003110 IRArray* descr;
sewardj207557a2004-08-27 12:00:18 +00003111 vassert(typeOfIRExpr(irbb->tyenv, value) == Ity_I8);
sewardjf6dc3ce2004-10-19 01:03:46 +00003112 descr = mkIRArray( OFFB_FPTAGS, Ity_I8, 8 );
sewardj2d3f77c2004-09-22 23:49:09 +00003113 stmt( IRStmt_PutI( descr, get_ftop(), i, value ) );
sewardj207557a2004-08-27 12:00:18 +00003114}
3115
3116/* Given i, generate an expression yielding 'ST_TAG(i)'. This will be
sewardjdb199622004-09-06 23:19:03 +00003117 zero to indicate "Empty" and nonzero to indicate "NonEmpty". */
sewardj207557a2004-08-27 12:00:18 +00003118
3119static IRExpr* get_ST_TAG ( Int i )
3120{
sewardjf6dc3ce2004-10-19 01:03:46 +00003121 IRArray* descr = mkIRArray( OFFB_FPTAGS, Ity_I8, 8 );
sewardj2d3f77c2004-09-22 23:49:09 +00003122 return IRExpr_GetI( descr, get_ftop(), i );
sewardj207557a2004-08-27 12:00:18 +00003123}
3124
3125
3126/* --------- Get/set FP registers. --------- */
3127
sewardj2d3f77c2004-09-22 23:49:09 +00003128/* Given i, and some expression e, emit 'ST(i) = e' and set the
3129 register's tag to indicate the register is full. The previous
3130 state of the register is not checked. */
sewardj207557a2004-08-27 12:00:18 +00003131
3132static void put_ST_UNCHECKED ( Int i, IRExpr* value )
sewardjd1725d12004-08-12 20:46:53 +00003133{
sewardj2d3f77c2004-09-22 23:49:09 +00003134 IRArray* descr;
sewardjdb199622004-09-06 23:19:03 +00003135 vassert(typeOfIRExpr(irbb->tyenv, value) == Ity_F64);
sewardjf6dc3ce2004-10-19 01:03:46 +00003136 descr = mkIRArray( OFFB_FPREGS, Ity_F64, 8 );
sewardj2d3f77c2004-09-22 23:49:09 +00003137 stmt( IRStmt_PutI( descr, get_ftop(), i, value ) );
sewardj207557a2004-08-27 12:00:18 +00003138 /* Mark the register as in-use. */
3139 put_ST_TAG(i, mkU8(1));
sewardjd1725d12004-08-12 20:46:53 +00003140}
3141
sewardj207557a2004-08-27 12:00:18 +00003142/* Given i, and some expression e, emit
3143 ST(i) = is_full(i) ? NaN : e
3144 and set the tag accordingly.
3145*/
3146
3147static void put_ST ( Int i, IRExpr* value )
3148{
3149 put_ST_UNCHECKED( i,
sewardjdb199622004-09-06 23:19:03 +00003150 IRExpr_Mux0X( get_ST_TAG(i),
3151 /* 0 means empty */
3152 value,
3153 /* non-0 means full */
sewardj17442fe2004-09-20 14:54:28 +00003154 mkQNaN64()
sewardj207557a2004-08-27 12:00:18 +00003155 )
3156 );
3157}
3158
3159
sewardjd1725d12004-08-12 20:46:53 +00003160/* Given i, generate an expression yielding 'ST(i)'. */
3161
sewardj207557a2004-08-27 12:00:18 +00003162static IRExpr* get_ST_UNCHECKED ( Int i )
sewardjd1725d12004-08-12 20:46:53 +00003163{
sewardjf6dc3ce2004-10-19 01:03:46 +00003164 IRArray* descr = mkIRArray( OFFB_FPREGS, Ity_F64, 8 );
sewardj2d3f77c2004-09-22 23:49:09 +00003165 return IRExpr_GetI( descr, get_ftop(), i );
sewardjd1725d12004-08-12 20:46:53 +00003166}
3167
sewardjc4be80c2004-09-10 16:17:45 +00003168
sewardj207557a2004-08-27 12:00:18 +00003169/* Given i, generate an expression yielding
3170 is_full(i) ? ST(i) : NaN
3171*/
3172
3173static IRExpr* get_ST ( Int i )
3174{
3175 return
3176 IRExpr_Mux0X( get_ST_TAG(i),
3177 /* 0 means empty */
sewardj17442fe2004-09-20 14:54:28 +00003178 mkQNaN64(),
sewardj207557a2004-08-27 12:00:18 +00003179 /* non-0 means full */
3180 get_ST_UNCHECKED(i));
3181}
3182
3183
sewardjd1725d12004-08-12 20:46:53 +00003184/* Adjust FTOP downwards by one register. */
3185
sewardj207557a2004-08-27 12:00:18 +00003186static void fp_push ( void )
sewardjd1725d12004-08-12 20:46:53 +00003187{
sewardj2d3f77c2004-09-22 23:49:09 +00003188 put_ftop( binop(Iop_Sub32, get_ftop(), mkU32(1)) );
sewardjd1725d12004-08-12 20:46:53 +00003189}
3190
sewardj207557a2004-08-27 12:00:18 +00003191/* Adjust FTOP upwards by one register, and mark the vacated register
3192 as empty. */
sewardja58ea662004-08-15 03:12:41 +00003193
sewardj207557a2004-08-27 12:00:18 +00003194static void fp_pop ( void )
sewardja58ea662004-08-15 03:12:41 +00003195{
sewardjdb199622004-09-06 23:19:03 +00003196 put_ST_TAG(0, mkU8(0));
sewardj2d3f77c2004-09-22 23:49:09 +00003197 put_ftop( binop(Iop_Add32, get_ftop(), mkU32(1)) );
sewardja58ea662004-08-15 03:12:41 +00003198}
3199
sewardj3f61ddb2004-10-16 20:51:05 +00003200/* Clear the C2 bit of the FPU status register, for
3201 sin/cos/tan/sincos. */
3202
3203static void clear_C2 ( void )
3204{
sewardj67e002d2004-12-02 18:16:33 +00003205 put_C3210( binop(Iop_And32, get_C3210(), mkU32(~X86G_FC_MASK_C2)) );
sewardj3f61ddb2004-10-16 20:51:05 +00003206}
3207
sewardjd24931d2005-03-20 12:51:39 +00003208/* Invent a plausible-looking FPU status word value:
3209 ((ftop & 7) << 11) | (c3210 & 0x4700)
3210 */
3211static IRExpr* get_FPU_sw ( void )
3212{
3213 return
3214 unop(Iop_32to16,
3215 binop(Iop_Or32,
3216 binop(Iop_Shl32,
3217 binop(Iop_And32, get_ftop(), mkU32(7)),
3218 mkU8(11)),
3219 binop(Iop_And32, get_C3210(), mkU32(0x4700))
3220 ));
3221}
3222
sewardj3f61ddb2004-10-16 20:51:05 +00003223
sewardj207557a2004-08-27 12:00:18 +00003224/* ------------------------------------------------------- */
3225/* Given all that stack-mangling junk, we can now go ahead
3226 and describe FP instructions.
3227*/
3228
sewardj3fd5e572004-09-09 22:43:51 +00003229/* ST(0) = ST(0) `op` mem64/32(addr)
sewardj207557a2004-08-27 12:00:18 +00003230 Need to check ST(0)'s tag on read, but not on write.
3231*/
sewardja58ea662004-08-15 03:12:41 +00003232static
sewardj2d49b432005-02-01 00:37:06 +00003233void fp_do_op_mem_ST_0 ( IRTemp addr, HChar* op_txt, HChar* dis_buf,
sewardja58ea662004-08-15 03:12:41 +00003234 IROp op, Bool dbl )
3235{
sewardj33dd31b2005-01-08 18:17:32 +00003236 DIP("f%s%c %s\n", op_txt, dbl?'l':'s', dis_buf);
sewardja58ea662004-08-15 03:12:41 +00003237 if (dbl) {
sewardj3fd5e572004-09-09 22:43:51 +00003238 put_ST_UNCHECKED(0,
3239 binop( op,
3240 get_ST(0),
3241 loadLE(Ity_F64,mkexpr(addr))
3242 ));
sewardja58ea662004-08-15 03:12:41 +00003243 } else {
sewardj3fd5e572004-09-09 22:43:51 +00003244 put_ST_UNCHECKED(0,
3245 binop( op,
3246 get_ST(0),
3247 unop(Iop_F32toF64, loadLE(Ity_F32,mkexpr(addr)))
3248 ));
3249 }
3250}
3251
3252
3253/* ST(0) = mem64/32(addr) `op` ST(0)
3254 Need to check ST(0)'s tag on read, but not on write.
3255*/
3256static
sewardj2d49b432005-02-01 00:37:06 +00003257void fp_do_oprev_mem_ST_0 ( IRTemp addr, HChar* op_txt, HChar* dis_buf,
sewardj883b00b2004-09-11 09:30:24 +00003258 IROp op, Bool dbl )
sewardj3fd5e572004-09-09 22:43:51 +00003259{
sewardj33dd31b2005-01-08 18:17:32 +00003260 DIP("f%s%c %s\n", op_txt, dbl?'l':'s', dis_buf);
sewardj3fd5e572004-09-09 22:43:51 +00003261 if (dbl) {
3262 put_ST_UNCHECKED(0,
3263 binop( op,
3264 loadLE(Ity_F64,mkexpr(addr)),
3265 get_ST(0)
3266 ));
3267 } else {
3268 put_ST_UNCHECKED(0,
3269 binop( op,
3270 unop(Iop_F32toF64, loadLE(Ity_F32,mkexpr(addr))),
3271 get_ST(0)
3272 ));
sewardja58ea662004-08-15 03:12:41 +00003273 }
3274}
3275
sewardjd1725d12004-08-12 20:46:53 +00003276
sewardjdb199622004-09-06 23:19:03 +00003277/* ST(dst) = ST(dst) `op` ST(src).
3278 Check dst and src tags when reading but not on write.
3279*/
3280static
sewardj2d49b432005-02-01 00:37:06 +00003281void fp_do_op_ST_ST ( HChar* op_txt, IROp op, UInt st_src, UInt st_dst,
sewardjbdc7d212004-09-09 02:46:40 +00003282 Bool pop_after )
sewardjdb199622004-09-06 23:19:03 +00003283{
sewardj2d49b432005-02-01 00:37:06 +00003284 DIP("f%s%s st(%d), st(%d)\n", op_txt, pop_after?"p":"",
3285 (Int)st_src, (Int)st_dst );
sewardjdb199622004-09-06 23:19:03 +00003286 put_ST_UNCHECKED(
3287 st_dst,
3288 binop(op, get_ST(st_dst), get_ST(st_src) )
3289 );
sewardjbdc7d212004-09-09 02:46:40 +00003290 if (pop_after)
3291 fp_pop();
3292}
3293
3294/* ST(dst) = ST(src) `op` ST(dst).
3295 Check dst and src tags when reading but not on write.
3296*/
3297static
sewardj2d49b432005-02-01 00:37:06 +00003298void fp_do_oprev_ST_ST ( HChar* op_txt, IROp op, UInt st_src, UInt st_dst,
sewardj883b00b2004-09-11 09:30:24 +00003299 Bool pop_after )
sewardjbdc7d212004-09-09 02:46:40 +00003300{
sewardj2d49b432005-02-01 00:37:06 +00003301 DIP("f%s%s st(%d), st(%d)\n", op_txt, pop_after?"p":"",
3302 (Int)st_src, (Int)st_dst );
sewardjbdc7d212004-09-09 02:46:40 +00003303 put_ST_UNCHECKED(
3304 st_dst,
3305 binop(op, get_ST(st_src), get_ST(st_dst) )
3306 );
3307 if (pop_after)
3308 fp_pop();
sewardjdb199622004-09-06 23:19:03 +00003309}
3310
sewardj8308aad2004-09-12 11:09:54 +00003311/* %eflags(Z,P,C) = UCOMI( st(0), st(i) ) */
3312static void fp_do_ucomi_ST0_STi ( UInt i, Bool pop_after )
3313{
sewardj2d49b432005-02-01 00:37:06 +00003314 DIP("fucomi%s %%st(0),%%st(%d)\n", pop_after ? "p" : "", (Int)i );
sewardj8308aad2004-09-12 11:09:54 +00003315 /* This is a bit of a hack (and isn't really right). It sets
3316 Z,P,C,O correctly, but forces A and S to zero, whereas the Intel
3317 documentation implies A and S are unchanged.
3318 */
sewardjfeeb8a82004-11-30 12:30:11 +00003319 /* It's also fishy in that it is used both for COMIP and
3320 UCOMIP, and they aren't the same (although similar). */
sewardj2a9ad022004-11-25 02:46:58 +00003321 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
sewardj2a2ba8b2004-11-08 13:14:06 +00003322 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
3323 stmt( IRStmt_Put( OFFB_CC_DEP1,
sewardj8308aad2004-09-12 11:09:54 +00003324 binop( Iop_And32,
3325 binop(Iop_CmpF64, get_ST(0), get_ST(i)),
3326 mkU32(0x45)
3327 )));
sewardja3b7e3a2005-04-05 01:54:19 +00003328 /* Set NDEP even though it isn't used. This makes redundant-PUT
3329 elimination of previous stores to this field work better. */
3330 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardj8308aad2004-09-12 11:09:54 +00003331 if (pop_after)
3332 fp_pop();
3333}
3334
sewardjdb199622004-09-06 23:19:03 +00003335
sewardjd1725d12004-08-12 20:46:53 +00003336static
sewardj52d04912005-07-03 00:52:48 +00003337UInt dis_FPU ( Bool* decode_ok, UChar sorb, Int delta )
sewardjd1725d12004-08-12 20:46:53 +00003338{
sewardja58ea662004-08-15 03:12:41 +00003339 Int len;
3340 UInt r_src, r_dst;
sewardjc9a43662004-11-30 18:51:59 +00003341 HChar dis_buf[50];
sewardj89cd0932004-09-08 18:23:25 +00003342 IRTemp t1, t2;
sewardjd1725d12004-08-12 20:46:53 +00003343
3344 /* On entry, delta points at the second byte of the insn (the modrm
3345 byte).*/
3346 UChar first_opcode = getIByte(delta-1);
3347 UChar modrm = getIByte(delta+0);
3348
3349 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xD8 opcodes +-+-+-+-+-+-+-+ */
3350
3351 if (first_opcode == 0xD8) {
sewardjdb199622004-09-06 23:19:03 +00003352 if (modrm < 0xC0) {
sewardj89cd0932004-09-08 18:23:25 +00003353
3354 /* bits 5,4,3 are an opcode extension, and the modRM also
3355 specifies an address. */
3356 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
3357 delta += len;
3358
3359 switch (gregOfRM(modrm)) {
3360
sewardj3fd5e572004-09-09 22:43:51 +00003361 case 0: /* FADD single-real */
3362 fp_do_op_mem_ST_0 ( addr, "add", dis_buf, Iop_AddF64, False );
3363 break;
3364
sewardj89cd0932004-09-08 18:23:25 +00003365 case 1: /* FMUL single-real */
3366 fp_do_op_mem_ST_0 ( addr, "mul", dis_buf, Iop_MulF64, False );
3367 break;
3368
sewardj7ca37d92004-10-25 02:58:30 +00003369 case 2: /* FCOM single-real */
3370 DIP("fcoms %s\n", dis_buf);
3371 /* This forces C1 to zero, which isn't right. */
3372 put_C3210(
3373 binop( Iop_And32,
3374 binop(Iop_Shl32,
3375 binop(Iop_CmpF64,
3376 get_ST(0),
3377 unop(Iop_F32toF64,
3378 loadLE(Ity_F32,mkexpr(addr)))),
3379 mkU8(8)),
3380 mkU32(0x4500)
3381 ));
3382 break;
3383
3384 case 3: /* FCOMP single-real */
sewardje166ed02004-10-25 02:27:01 +00003385 DIP("fcomps %s\n", dis_buf);
3386 /* This forces C1 to zero, which isn't right. */
3387 put_C3210(
3388 binop( Iop_And32,
3389 binop(Iop_Shl32,
3390 binop(Iop_CmpF64,
3391 get_ST(0),
3392 unop(Iop_F32toF64,
3393 loadLE(Ity_F32,mkexpr(addr)))),
3394 mkU8(8)),
3395 mkU32(0x4500)
3396 ));
3397 fp_pop();
3398 break;
3399
sewardj588ea762004-09-10 18:56:32 +00003400 case 4: /* FSUB single-real */
3401 fp_do_op_mem_ST_0 ( addr, "sub", dis_buf, Iop_SubF64, False );
3402 break;
3403
3404 case 5: /* FSUBR single-real */
3405 fp_do_oprev_mem_ST_0 ( addr, "subr", dis_buf, Iop_SubF64, False );
3406 break;
3407
sewardjbdc7d212004-09-09 02:46:40 +00003408 case 6: /* FDIV single-real */
3409 fp_do_op_mem_ST_0 ( addr, "div", dis_buf, Iop_DivF64, False );
3410 break;
3411
sewardj8308aad2004-09-12 11:09:54 +00003412 case 7: /* FDIVR single-real */
3413 fp_do_oprev_mem_ST_0 ( addr, "divr", dis_buf, Iop_DivF64, False );
3414 break;
3415
sewardj89cd0932004-09-08 18:23:25 +00003416 default:
3417 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
3418 vex_printf("first_opcode == 0xD8\n");
3419 goto decode_fail;
3420 }
sewardjdb199622004-09-06 23:19:03 +00003421 } else {
3422 delta++;
3423 switch (modrm) {
sewardj89cd0932004-09-08 18:23:25 +00003424
sewardjdb199622004-09-06 23:19:03 +00003425 case 0xC0 ... 0xC7: /* FADD %st(?),%st(0) */
sewardjbdc7d212004-09-09 02:46:40 +00003426 fp_do_op_ST_ST ( "add", Iop_AddF64, modrm - 0xC0, 0, False );
sewardjdb199622004-09-06 23:19:03 +00003427 break;
sewardj89cd0932004-09-08 18:23:25 +00003428
sewardj3fd5e572004-09-09 22:43:51 +00003429 case 0xC8 ... 0xCF: /* FMUL %st(?),%st(0) */
3430 fp_do_op_ST_ST ( "mul", Iop_MulF64, modrm - 0xC8, 0, False );
3431 break;
3432
sewardje166ed02004-10-25 02:27:01 +00003433 /* Dunno if this is right */
3434 case 0xD0 ... 0xD7: /* FCOM %st(?),%st(0) */
3435 r_dst = (UInt)modrm - 0xD0;
sewardj2d49b432005-02-01 00:37:06 +00003436 DIP("fcom %%st(0),%%st(%d)\n", (Int)r_dst);
sewardje166ed02004-10-25 02:27:01 +00003437 /* This forces C1 to zero, which isn't right. */
3438 put_C3210(
3439 binop( Iop_And32,
3440 binop(Iop_Shl32,
3441 binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
3442 mkU8(8)),
3443 mkU32(0x4500)
3444 ));
3445 break;
sewardj2d49b432005-02-01 00:37:06 +00003446
sewardj98169c52004-10-24 13:11:39 +00003447 /* Dunno if this is right */
3448 case 0xD8 ... 0xDF: /* FCOMP %st(?),%st(0) */
3449 r_dst = (UInt)modrm - 0xD8;
sewardj2d49b432005-02-01 00:37:06 +00003450 DIP("fcomp %%st(0),%%st(%d)\n", (Int)r_dst);
sewardj98169c52004-10-24 13:11:39 +00003451 /* This forces C1 to zero, which isn't right. */
3452 put_C3210(
3453 binop( Iop_And32,
3454 binop(Iop_Shl32,
3455 binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
3456 mkU8(8)),
3457 mkU32(0x4500)
3458 ));
3459 fp_pop();
3460 break;
sewardj2d49b432005-02-01 00:37:06 +00003461
sewardj89cd0932004-09-08 18:23:25 +00003462 case 0xE0 ... 0xE7: /* FSUB %st(?),%st(0) */
sewardjbdc7d212004-09-09 02:46:40 +00003463 fp_do_op_ST_ST ( "sub", Iop_SubF64, modrm - 0xE0, 0, False );
sewardj89cd0932004-09-08 18:23:25 +00003464 break;
3465
sewardj8308aad2004-09-12 11:09:54 +00003466 case 0xE8 ... 0xEF: /* FSUBR %st(?),%st(0) */
3467 fp_do_oprev_ST_ST ( "subr", Iop_SubF64, modrm - 0xE8, 0, False );
3468 break;
3469
sewardj3fd5e572004-09-09 22:43:51 +00003470 case 0xF0 ... 0xF7: /* FDIV %st(?),%st(0) */
3471 fp_do_op_ST_ST ( "div", Iop_DivF64, modrm - 0xF0, 0, False );
3472 break;
3473
3474 case 0xF8 ... 0xFF: /* FDIVR %st(?),%st(0) */
3475 fp_do_oprev_ST_ST ( "divr", Iop_DivF64, modrm - 0xF8, 0, False );
3476 break;
3477
sewardjdb199622004-09-06 23:19:03 +00003478 default:
3479 goto decode_fail;
3480 }
3481 }
sewardjd1725d12004-08-12 20:46:53 +00003482 }
3483
3484 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xD9 opcodes +-+-+-+-+-+-+-+ */
3485 else
3486 if (first_opcode == 0xD9) {
sewardjbb53f8c2004-08-14 11:50:01 +00003487 if (modrm < 0xC0) {
sewardj89cd0932004-09-08 18:23:25 +00003488
3489 /* bits 5,4,3 are an opcode extension, and the modRM also
sewardjfeeb8a82004-11-30 12:30:11 +00003490 specifies an address. */
sewardj89cd0932004-09-08 18:23:25 +00003491 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
3492 delta += len;
3493
3494 switch (gregOfRM(modrm)) {
3495
3496 case 0: /* FLD single-real */
sewardj33dd31b2005-01-08 18:17:32 +00003497 DIP("flds %s\n", dis_buf);
sewardj89cd0932004-09-08 18:23:25 +00003498 fp_push();
3499 put_ST(0, unop(Iop_F32toF64,
sewardj8f3debf2004-09-08 23:42:23 +00003500 loadLE(Ity_F32, mkexpr(addr))));
sewardj89cd0932004-09-08 18:23:25 +00003501 break;
3502
sewardj588ea762004-09-10 18:56:32 +00003503 case 2: /* FST single-real */
sewardj33dd31b2005-01-08 18:17:32 +00003504 DIP("fsts %s\n", dis_buf);
sewardj3bca9062004-12-04 14:36:09 +00003505 storeLE(mkexpr(addr),
3506 binop(Iop_F64toF32, get_roundingmode(), get_ST(0)));
sewardj588ea762004-09-10 18:56:32 +00003507 break;
3508
sewardj89cd0932004-09-08 18:23:25 +00003509 case 3: /* FSTP single-real */
sewardj33dd31b2005-01-08 18:17:32 +00003510 DIP("fstps %s\n", dis_buf);
sewardj3bca9062004-12-04 14:36:09 +00003511 storeLE(mkexpr(addr),
3512 binop(Iop_F64toF32, get_roundingmode(), get_ST(0)));
sewardj5bd4d162004-11-10 13:02:48 +00003513 fp_pop();
sewardj89cd0932004-09-08 18:23:25 +00003514 break;
3515
sewardjd24931d2005-03-20 12:51:39 +00003516 case 4: { /* FLDENV m28 */
sewardj7df596b2004-12-06 14:29:12 +00003517 /* Uses dirty helper:
sewardj4017a3b2005-06-13 12:17:27 +00003518 VexEmWarn x86g_do_FLDENV ( VexGuestX86State*, HWord ) */
sewardj7df596b2004-12-06 14:29:12 +00003519 IRTemp ew = newTemp(Ity_I32);
3520 IRDirty* d = unsafeIRDirty_0_N (
3521 0/*regparms*/,
3522 "x86g_dirtyhelper_FLDENV",
3523 &x86g_dirtyhelper_FLDENV,
3524 mkIRExprVec_1( mkexpr(addr) )
3525 );
3526 d->needsBBP = True;
3527 d->tmp = ew;
3528 /* declare we're reading memory */
3529 d->mFx = Ifx_Read;
3530 d->mAddr = mkexpr(addr);
3531 d->mSize = 28;
3532
3533 /* declare we're writing guest state */
sewardj46813fc2005-06-13 12:33:36 +00003534 d->nFxState = 4;
sewardj7df596b2004-12-06 14:29:12 +00003535
3536 d->fxState[0].fx = Ifx_Write;
3537 d->fxState[0].offset = OFFB_FTOP;
3538 d->fxState[0].size = sizeof(UInt);
3539
3540 d->fxState[1].fx = Ifx_Write;
sewardj46813fc2005-06-13 12:33:36 +00003541 d->fxState[1].offset = OFFB_FPTAGS;
3542 d->fxState[1].size = 8 * sizeof(UChar);
sewardj7df596b2004-12-06 14:29:12 +00003543
3544 d->fxState[2].fx = Ifx_Write;
sewardj46813fc2005-06-13 12:33:36 +00003545 d->fxState[2].offset = OFFB_FPROUND;
3546 d->fxState[2].size = sizeof(UInt);
sewardj7df596b2004-12-06 14:29:12 +00003547
3548 d->fxState[3].fx = Ifx_Write;
sewardj46813fc2005-06-13 12:33:36 +00003549 d->fxState[3].offset = OFFB_FC3210;
sewardj7df596b2004-12-06 14:29:12 +00003550 d->fxState[3].size = sizeof(UInt);
3551
sewardj7df596b2004-12-06 14:29:12 +00003552 stmt( IRStmt_Dirty(d) );
3553
3554 /* ew contains any emulation warning we may need to
3555 issue. If needed, side-exit to the next insn,
3556 reporting the warning, so that Valgrind's dispatcher
3557 sees the warning. */
3558 put_emwarn( mkexpr(ew) );
3559 stmt(
3560 IRStmt_Exit(
3561 binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
3562 Ijk_EmWarn,
sewardj9e6491a2005-07-02 19:24:10 +00003563 IRConst_U32( ((Addr32)guest_EIP_bbstart)+delta)
sewardj7df596b2004-12-06 14:29:12 +00003564 )
3565 );
3566
sewardj33dd31b2005-01-08 18:17:32 +00003567 DIP("fldenv %s\n", dis_buf);
sewardj7df596b2004-12-06 14:29:12 +00003568 break;
3569 }
3570
sewardj893aada2004-11-29 19:57:54 +00003571 case 5: {/* FLDCW */
3572 /* The only thing we observe in the control word is the
sewardjd01a9632004-11-30 13:18:37 +00003573 rounding mode. Therefore, pass the 16-bit value
3574 (x87 native-format control word) to a clean helper,
3575 getting back a 64-bit value, the lower half of which
3576 is the FPROUND value to store, and the upper half of
3577 which is the emulation-warning token which may be
3578 generated.
sewardj893aada2004-11-29 19:57:54 +00003579 */
3580 /* ULong x86h_check_fldcw ( UInt ); */
3581 IRTemp t64 = newTemp(Ity_I64);
3582 IRTemp ew = newTemp(Ity_I32);
sewardj33dd31b2005-01-08 18:17:32 +00003583 DIP("fldcw %s\n", dis_buf);
sewardj893aada2004-11-29 19:57:54 +00003584 assign( t64, mkIRExprCCall(
3585 Ity_I64, 0/*regparms*/,
sewardj3bd6f3e2004-12-13 10:48:19 +00003586 "x86g_check_fldcw",
3587 &x86g_check_fldcw,
sewardj893aada2004-11-29 19:57:54 +00003588 mkIRExprVec_1(
3589 unop( Iop_16Uto32,
3590 loadLE(Ity_I16, mkexpr(addr)))
3591 )
3592 )
3593 );
3594
sewardjd01a9632004-11-30 13:18:37 +00003595 put_fpround( unop(Iop_64to32, mkexpr(t64)) );
sewardj893aada2004-11-29 19:57:54 +00003596 assign( ew, unop(Iop_64HIto32, mkexpr(t64) ) );
3597 put_emwarn( mkexpr(ew) );
3598 /* Finally, if an emulation warning was reported,
3599 side-exit to the next insn, reporting the warning,
3600 so that Valgrind's dispatcher sees the warning. */
3601 stmt(
3602 IRStmt_Exit(
3603 binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
3604 Ijk_EmWarn,
sewardj9e6491a2005-07-02 19:24:10 +00003605 IRConst_U32( ((Addr32)guest_EIP_bbstart)+delta)
sewardj893aada2004-11-29 19:57:54 +00003606 )
3607 );
sewardj89cd0932004-09-08 18:23:25 +00003608 break;
sewardj893aada2004-11-29 19:57:54 +00003609 }
sewardj89cd0932004-09-08 18:23:25 +00003610
sewardj7df596b2004-12-06 14:29:12 +00003611 case 6: { /* FNSTENV m28 */
3612 /* Uses dirty helper:
sewardj4017a3b2005-06-13 12:17:27 +00003613 void x86g_do_FSTENV ( VexGuestX86State*, HWord ) */
sewardj7df596b2004-12-06 14:29:12 +00003614 IRDirty* d = unsafeIRDirty_0_N (
3615 0/*regparms*/,
3616 "x86g_dirtyhelper_FSTENV",
3617 &x86g_dirtyhelper_FSTENV,
3618 mkIRExprVec_1( mkexpr(addr) )
3619 );
3620 d->needsBBP = True;
3621 /* declare we're writing memory */
3622 d->mFx = Ifx_Write;
3623 d->mAddr = mkexpr(addr);
3624 d->mSize = 28;
3625
3626 /* declare we're reading guest state */
3627 d->nFxState = 4;
3628
3629 d->fxState[0].fx = Ifx_Read;
3630 d->fxState[0].offset = OFFB_FTOP;
3631 d->fxState[0].size = sizeof(UInt);
3632
3633 d->fxState[1].fx = Ifx_Read;
3634 d->fxState[1].offset = OFFB_FPTAGS;
3635 d->fxState[1].size = 8 * sizeof(UChar);
3636
3637 d->fxState[2].fx = Ifx_Read;
3638 d->fxState[2].offset = OFFB_FPROUND;
3639 d->fxState[2].size = sizeof(UInt);
3640
3641 d->fxState[3].fx = Ifx_Read;
3642 d->fxState[3].offset = OFFB_FC3210;
3643 d->fxState[3].size = sizeof(UInt);
3644
3645 stmt( IRStmt_Dirty(d) );
3646
sewardj33dd31b2005-01-08 18:17:32 +00003647 DIP("fnstenv %s\n", dis_buf);
sewardj7df596b2004-12-06 14:29:12 +00003648 break;
3649 }
3650
sewardj588ea762004-09-10 18:56:32 +00003651 case 7: /* FNSTCW */
sewardj893aada2004-11-29 19:57:54 +00003652 /* Fake up a native x87 FPU control word. The only
sewardjd01a9632004-11-30 13:18:37 +00003653 thing it depends on is FPROUND[1:0], so call a clean
sewardj893aada2004-11-29 19:57:54 +00003654 helper to cook it up. */
sewardjd01a9632004-11-30 13:18:37 +00003655 /* UInt x86h_create_fpucw ( UInt fpround ) */
sewardj33dd31b2005-01-08 18:17:32 +00003656 DIP("fnstcw %s\n", dis_buf);
sewardj893aada2004-11-29 19:57:54 +00003657 storeLE(
3658 mkexpr(addr),
3659 unop( Iop_32to16,
3660 mkIRExprCCall(
3661 Ity_I32, 0/*regp*/,
sewardj3bd6f3e2004-12-13 10:48:19 +00003662 "x86g_create_fpucw", &x86g_create_fpucw,
sewardjd01a9632004-11-30 13:18:37 +00003663 mkIRExprVec_1( get_fpround() )
sewardj893aada2004-11-29 19:57:54 +00003664 )
3665 )
3666 );
sewardj89cd0932004-09-08 18:23:25 +00003667 break;
3668
3669 default:
3670 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
3671 vex_printf("first_opcode == 0xD9\n");
3672 goto decode_fail;
3673 }
3674
sewardjbb53f8c2004-08-14 11:50:01 +00003675 } else {
3676 delta++;
3677 switch (modrm) {
sewardj89cd0932004-09-08 18:23:25 +00003678
sewardjbb53f8c2004-08-14 11:50:01 +00003679 case 0xC0 ... 0xC7: /* FLD %st(?) */
sewardja58ea662004-08-15 03:12:41 +00003680 r_src = (UInt)modrm - 0xC0;
sewardj2d49b432005-02-01 00:37:06 +00003681 DIP("fld %%st(%d)\n", (Int)r_src);
sewardj5bd4d162004-11-10 13:02:48 +00003682 t1 = newTemp(Ity_F64);
3683 assign(t1, get_ST(r_src));
3684 fp_push();
3685 put_ST(0, mkexpr(t1));
sewardjbb53f8c2004-08-14 11:50:01 +00003686 break;
3687
sewardj89cd0932004-09-08 18:23:25 +00003688 case 0xC8 ... 0xCF: /* FXCH %st(?) */
3689 r_src = (UInt)modrm - 0xC8;
sewardj2d49b432005-02-01 00:37:06 +00003690 DIP("fxch %%st(%d)\n", (Int)r_src);
sewardj89cd0932004-09-08 18:23:25 +00003691 t1 = newTemp(Ity_F64);
3692 t2 = newTemp(Ity_F64);
3693 assign(t1, get_ST(0));
3694 assign(t2, get_ST(r_src));
3695 put_ST_UNCHECKED(0, mkexpr(t2));
3696 put_ST_UNCHECKED(r_src, mkexpr(t1));
3697 break;
3698
sewardjcfded9a2004-09-09 11:44:16 +00003699 case 0xE0: /* FCHS */
3700 DIP("fchs\n");
3701 put_ST_UNCHECKED(0, unop(Iop_NegF64, get_ST(0)));
3702 break;
3703
sewardj883b00b2004-09-11 09:30:24 +00003704 case 0xE1: /* FABS */
3705 DIP("fabs\n");
3706 put_ST_UNCHECKED(0, unop(Iop_AbsF64, get_ST(0)));
3707 break;
sewardjc4be80c2004-09-10 16:17:45 +00003708
sewardj1c318772005-03-19 14:27:04 +00003709 case 0xE4: /* FTST */
3710 DIP("ftst\n");
3711 /* This forces C1 to zero, which isn't right. */
3712 /* Well, in fact the Intel docs say (bizarrely): "C1 is
3713 set to 0 if stack underflow occurred; otherwise, set
3714 to 0" which is pretty nonsensical. I guess it's a
3715 typo. */
3716 put_C3210(
3717 binop( Iop_And32,
3718 binop(Iop_Shl32,
3719 binop(Iop_CmpF64,
3720 get_ST(0),
3721 IRExpr_Const(IRConst_F64i(0x0ULL))),
3722 mkU8(8)),
3723 mkU32(0x4500)
3724 ));
3725 break;
3726
sewardj883b00b2004-09-11 09:30:24 +00003727 case 0xE5: { /* FXAM */
3728 /* This is an interesting one. It examines %st(0),
3729 regardless of whether the tag says it's empty or not.
3730 Here, just pass both the tag (in our format) and the
3731 value (as a double, actually a ULong) to a helper
3732 function. */
sewardjf9655262004-10-31 20:02:16 +00003733 IRExpr** args
3734 = mkIRExprVec_2( unop(Iop_8Uto32, get_ST_TAG(0)),
3735 unop(Iop_ReinterpF64asI64,
3736 get_ST_UNCHECKED(0)) );
3737 put_C3210(mkIRExprCCall(
sewardj8ea867b2004-10-30 19:03:02 +00003738 Ity_I32,
sewardjf9655262004-10-31 20:02:16 +00003739 0/*regparm*/,
sewardj2a9ad022004-11-25 02:46:58 +00003740 "x86g_calculate_FXAM", &x86g_calculate_FXAM,
sewardj8ea867b2004-10-30 19:03:02 +00003741 args
3742 ));
sewardj33dd31b2005-01-08 18:17:32 +00003743 DIP("fxam\n");
sewardj883b00b2004-09-11 09:30:24 +00003744 break;
3745 }
3746
3747 case 0xE8: /* FLD1 */
sewardj33dd31b2005-01-08 18:17:32 +00003748 DIP("fld1\n");
sewardjce646f22004-08-31 23:55:54 +00003749 fp_push();
sewardj9c323762005-01-10 16:49:19 +00003750 /* put_ST(0, IRExpr_Const(IRConst_F64(1.0))); */
3751 put_ST(0, IRExpr_Const(IRConst_F64i(0x3ff0000000000000ULL)));
sewardjce646f22004-08-31 23:55:54 +00003752 break;
3753
sewardj37158712004-10-15 21:23:12 +00003754 case 0xE9: /* FLDL2T */
sewardj33dd31b2005-01-08 18:17:32 +00003755 DIP("fldl2t\n");
sewardj37158712004-10-15 21:23:12 +00003756 fp_push();
sewardj9c323762005-01-10 16:49:19 +00003757 /* put_ST(0, IRExpr_Const(IRConst_F64(3.32192809488736234781))); */
3758 put_ST(0, IRExpr_Const(IRConst_F64i(0x400a934f0979a371ULL)));
sewardj37158712004-10-15 21:23:12 +00003759 break;
3760
sewardj8308aad2004-09-12 11:09:54 +00003761 case 0xEA: /* FLDL2E */
sewardj33dd31b2005-01-08 18:17:32 +00003762 DIP("fldl2e\n");
sewardj8308aad2004-09-12 11:09:54 +00003763 fp_push();
sewardj9c323762005-01-10 16:49:19 +00003764 /* put_ST(0, IRExpr_Const(IRConst_F64(1.44269504088896340739))); */
3765 put_ST(0, IRExpr_Const(IRConst_F64i(0x3ff71547652b82feULL)));
sewardj8308aad2004-09-12 11:09:54 +00003766 break;
3767
sewardja0d48d62004-09-20 21:19:03 +00003768 case 0xEB: /* FLDPI */
sewardj33dd31b2005-01-08 18:17:32 +00003769 DIP("fldpi\n");
sewardja0d48d62004-09-20 21:19:03 +00003770 fp_push();
sewardj9c323762005-01-10 16:49:19 +00003771 /* put_ST(0, IRExpr_Const(IRConst_F64(3.14159265358979323851))); */
3772 put_ST(0, IRExpr_Const(IRConst_F64i(0x400921fb54442d18ULL)));
sewardja0d48d62004-09-20 21:19:03 +00003773 break;
3774
sewardjdb199622004-09-06 23:19:03 +00003775 case 0xEC: /* FLDLG2 */
sewardj33dd31b2005-01-08 18:17:32 +00003776 DIP("fldlg2\n");
sewardjdb199622004-09-06 23:19:03 +00003777 fp_push();
sewardj9c323762005-01-10 16:49:19 +00003778 /* put_ST(0, IRExpr_Const(IRConst_F64(0.301029995663981143))); */
3779 put_ST(0, IRExpr_Const(IRConst_F64i(0x3fd34413509f79ffULL)));
sewardjdb199622004-09-06 23:19:03 +00003780 break;
3781
3782 case 0xED: /* FLDLN2 */
sewardj33dd31b2005-01-08 18:17:32 +00003783 DIP("fldln2\n");
sewardjdb199622004-09-06 23:19:03 +00003784 fp_push();
sewardj9c323762005-01-10 16:49:19 +00003785 /* put_ST(0, IRExpr_Const(IRConst_F64(0.69314718055994530942))); */
3786 put_ST(0, IRExpr_Const(IRConst_F64i(0x3fe62e42fefa39efULL)));
sewardjdb199622004-09-06 23:19:03 +00003787 break;
3788
sewardja58ea662004-08-15 03:12:41 +00003789 case 0xEE: /* FLDZ */
sewardj33dd31b2005-01-08 18:17:32 +00003790 DIP("fldz\n");
sewardj207557a2004-08-27 12:00:18 +00003791 fp_push();
sewardj9c323762005-01-10 16:49:19 +00003792 /* put_ST(0, IRExpr_Const(IRConst_F64(0.0))); */
3793 put_ST(0, IRExpr_Const(IRConst_F64i(0x0000000000000000ULL)));
sewardja58ea662004-08-15 03:12:41 +00003794 break;
3795
sewardj06c32a02004-09-12 12:07:34 +00003796 case 0xF0: /* F2XM1 */
3797 DIP("f2xm1\n");
3798 put_ST_UNCHECKED(0, unop(Iop_2xm1F64, get_ST(0)));
3799 break;
3800
sewardj52ace3e2004-09-11 17:10:08 +00003801 case 0xF1: /* FYL2X */
3802 DIP("fyl2x\n");
3803 put_ST_UNCHECKED(1, binop(Iop_Yl2xF64,
3804 get_ST(1), get_ST(0)));
3805 fp_pop();
3806 break;
3807
sewardj99016a72004-10-15 22:09:17 +00003808 case 0xF2: /* FPTAN */
3809 DIP("ftan\n");
3810 put_ST_UNCHECKED(0, unop(Iop_TanF64, get_ST(0)));
3811 fp_push();
3812 put_ST(0, IRExpr_Const(IRConst_F64(1.0)));
sewardj3f61ddb2004-10-16 20:51:05 +00003813 clear_C2(); /* HACK */
sewardj99016a72004-10-15 22:09:17 +00003814 break;
3815
sewardjcfded9a2004-09-09 11:44:16 +00003816 case 0xF3: /* FPATAN */
3817 DIP("fpatan\n");
sewardj52ace3e2004-09-11 17:10:08 +00003818 put_ST_UNCHECKED(1, binop(Iop_AtanF64,
sewardjcfded9a2004-09-09 11:44:16 +00003819 get_ST(1), get_ST(0)));
3820 fp_pop();
3821 break;
3822
sewardj442d0be2004-10-15 22:57:13 +00003823 case 0xF5: { /* FPREM1 -- IEEE compliant */
3824 IRTemp a1 = newTemp(Ity_F64);
3825 IRTemp a2 = newTemp(Ity_F64);
3826 DIP("fprem1\n");
3827 /* Do FPREM1 twice, once to get the remainder, and once
3828 to get the C3210 flag values. */
3829 assign( a1, get_ST(0) );
3830 assign( a2, get_ST(1) );
3831 put_ST_UNCHECKED(0, binop(Iop_PRem1F64,
3832 mkexpr(a1), mkexpr(a2)));
3833 put_C3210( binop(Iop_PRem1C3210F64, mkexpr(a1), mkexpr(a2)) );
3834 break;
3835 }
3836
sewardjfeeb8a82004-11-30 12:30:11 +00003837 case 0xF7: /* FINCSTP */
3838 DIP("fprem\n");
3839 put_ftop( binop(Iop_Add32, get_ftop(), mkU32(1)) );
3840 break;
3841
sewardj46de4072004-09-11 19:23:24 +00003842 case 0xF8: { /* FPREM -- not IEEE compliant */
3843 IRTemp a1 = newTemp(Ity_F64);
3844 IRTemp a2 = newTemp(Ity_F64);
3845 DIP("fprem\n");
3846 /* Do FPREM twice, once to get the remainder, and once
3847 to get the C3210 flag values. */
3848 assign( a1, get_ST(0) );
3849 assign( a2, get_ST(1) );
3850 put_ST_UNCHECKED(0, binop(Iop_PRemF64,
3851 mkexpr(a1), mkexpr(a2)));
3852 put_C3210( binop(Iop_PRemC3210F64, mkexpr(a1), mkexpr(a2)) );
3853 break;
3854 }
3855
sewardj8308aad2004-09-12 11:09:54 +00003856 case 0xF9: /* FYL2XP1 */
3857 DIP("fyl2xp1\n");
3858 put_ST_UNCHECKED(1, binop(Iop_Yl2xp1F64,
3859 get_ST(1), get_ST(0)));
3860 fp_pop();
3861 break;
3862
sewardjc4be80c2004-09-10 16:17:45 +00003863 case 0xFA: /* FSQRT */
3864 DIP("fsqrt\n");
3865 put_ST_UNCHECKED(0, unop(Iop_SqrtF64, get_ST(0)));
3866 break;
3867
sewardj519d66f2004-12-15 11:57:58 +00003868 case 0xFB: { /* FSINCOS */
3869 IRTemp a1 = newTemp(Ity_F64);
3870 assign( a1, get_ST(0) );
3871 DIP("fsincos\n");
3872 put_ST_UNCHECKED(0, unop(Iop_SinF64, mkexpr(a1)));
3873 fp_push();
3874 put_ST(0, unop(Iop_CosF64, mkexpr(a1)));
sewardj88a69242005-04-01 20:19:20 +00003875 clear_C2(); /* HACK */
sewardj519d66f2004-12-15 11:57:58 +00003876 break;
3877 }
3878
sewardje6709112004-09-10 18:37:18 +00003879 case 0xFC: /* FRNDINT */
3880 DIP("frndint\n");
3881 put_ST_UNCHECKED(0,
3882 binop(Iop_RoundF64, get_roundingmode(), get_ST(0)) );
3883 break;
3884
sewardj06c32a02004-09-12 12:07:34 +00003885 case 0xFD: /* FSCALE */
3886 DIP("fscale\n");
3887 put_ST_UNCHECKED(0, binop(Iop_ScaleF64,
3888 get_ST(0), get_ST(1)));
3889 break;
3890
sewardjcfded9a2004-09-09 11:44:16 +00003891 case 0xFE: /* FSIN */
3892 DIP("fsin\n");
3893 put_ST_UNCHECKED(0, unop(Iop_SinF64, get_ST(0)));
sewardj3f61ddb2004-10-16 20:51:05 +00003894 clear_C2(); /* HACK */
sewardjcfded9a2004-09-09 11:44:16 +00003895 break;
3896
3897 case 0xFF: /* FCOS */
3898 DIP("fcos\n");
3899 put_ST_UNCHECKED(0, unop(Iop_CosF64, get_ST(0)));
sewardj3f61ddb2004-10-16 20:51:05 +00003900 clear_C2(); /* HACK */
sewardjcfded9a2004-09-09 11:44:16 +00003901 break;
3902
sewardjbb53f8c2004-08-14 11:50:01 +00003903 default:
3904 goto decode_fail;
3905 }
3906 }
sewardjd1725d12004-08-12 20:46:53 +00003907 }
3908
3909 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDA opcodes +-+-+-+-+-+-+-+ */
3910 else
3911 if (first_opcode == 0xDA) {
sewardjbb53f8c2004-08-14 11:50:01 +00003912
3913 if (modrm < 0xC0) {
3914
sewardjfeeb8a82004-11-30 12:30:11 +00003915 /* bits 5,4,3 are an opcode extension, and the modRM also
sewardjbb53f8c2004-08-14 11:50:01 +00003916 specifies an address. */
sewardjce646f22004-08-31 23:55:54 +00003917 IROp fop;
sewardjbb53f8c2004-08-14 11:50:01 +00003918 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
3919 delta += len;
sewardjbb53f8c2004-08-14 11:50:01 +00003920 switch (gregOfRM(modrm)) {
sewardjce646f22004-08-31 23:55:54 +00003921
sewardjdb199622004-09-06 23:19:03 +00003922 case 0: /* FIADD m32int */ /* ST(0) += m32int */
sewardj33dd31b2005-01-08 18:17:32 +00003923 DIP("fiaddl %s\n", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00003924 fop = Iop_AddF64;
3925 goto do_fop_m32;
sewardjdb199622004-09-06 23:19:03 +00003926
sewardj207557a2004-08-27 12:00:18 +00003927 case 1: /* FIMUL m32int */ /* ST(0) *= m32int */
sewardj33dd31b2005-01-08 18:17:32 +00003928 DIP("fimull %s\n", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00003929 fop = Iop_MulF64;
3930 goto do_fop_m32;
sewardjce646f22004-08-31 23:55:54 +00003931
3932 case 4: /* FISUB m32int */ /* ST(0) -= m32int */
sewardj33dd31b2005-01-08 18:17:32 +00003933 DIP("fisubl %s\n", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00003934 fop = Iop_SubF64;
3935 goto do_fop_m32;
sewardjce646f22004-08-31 23:55:54 +00003936
sewardj8308aad2004-09-12 11:09:54 +00003937 case 5: /* FISUBR m32int */ /* ST(0) = m32int - ST(0) */
sewardj33dd31b2005-01-08 18:17:32 +00003938 DIP("fisubrl %s\n", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00003939 fop = Iop_SubF64;
3940 goto do_foprev_m32;
sewardj8308aad2004-09-12 11:09:54 +00003941
sewardjce646f22004-08-31 23:55:54 +00003942 case 6: /* FIDIV m32int */ /* ST(0) /= m32int */
sewardj36917e92005-03-21 00:12:15 +00003943 DIP("fidivl %s\n", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00003944 fop = Iop_DivF64;
3945 goto do_fop_m32;
sewardjce646f22004-08-31 23:55:54 +00003946
sewardjc4eaff32004-09-10 20:25:11 +00003947 case 7: /* FIDIVR m32int */ /* ST(0) = m32int / ST(0) */
sewardj33dd31b2005-01-08 18:17:32 +00003948 DIP("fidivrl %s\n", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00003949 fop = Iop_DivF64;
3950 goto do_foprev_m32;
sewardjc4eaff32004-09-10 20:25:11 +00003951
sewardjce646f22004-08-31 23:55:54 +00003952 do_fop_m32:
sewardj207557a2004-08-27 12:00:18 +00003953 put_ST_UNCHECKED(0,
sewardjce646f22004-08-31 23:55:54 +00003954 binop(fop,
sewardj207557a2004-08-27 12:00:18 +00003955 get_ST(0),
sewardj89cd0932004-09-08 18:23:25 +00003956 unop(Iop_I32toF64,
3957 loadLE(Ity_I32, mkexpr(addr)))));
sewardjbb53f8c2004-08-14 11:50:01 +00003958 break;
3959
sewardjc4eaff32004-09-10 20:25:11 +00003960 do_foprev_m32:
3961 put_ST_UNCHECKED(0,
3962 binop(fop,
3963 unop(Iop_I32toF64,
3964 loadLE(Ity_I32, mkexpr(addr))),
3965 get_ST(0)));
3966 break;
3967
sewardjbb53f8c2004-08-14 11:50:01 +00003968 default:
3969 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
3970 vex_printf("first_opcode == 0xDA\n");
3971 goto decode_fail;
3972 }
sewardj4cb918d2004-12-03 19:43:31 +00003973
sewardjbb53f8c2004-08-14 11:50:01 +00003974 } else {
sewardjbdc7d212004-09-09 02:46:40 +00003975
3976 delta++;
3977 switch (modrm) {
3978
sewardj519d66f2004-12-15 11:57:58 +00003979 case 0xC0 ... 0xC7: /* FCMOVB ST(i), ST(0) */
3980 r_src = (UInt)modrm - 0xC0;
sewardj2d49b432005-02-01 00:37:06 +00003981 DIP("fcmovb %%st(%d), %%st(0)\n", (Int)r_src);
sewardj519d66f2004-12-15 11:57:58 +00003982 put_ST_UNCHECKED(0,
3983 IRExpr_Mux0X(
3984 unop(Iop_1Uto8,
3985 mk_x86g_calculate_condition(X86CondB)),
3986 get_ST(0), get_ST(r_src)) );
3987 break;
3988
sewardj3fd5e572004-09-09 22:43:51 +00003989 case 0xC8 ... 0xCF: /* FCMOVE(Z) ST(i), ST(0) */
3990 r_src = (UInt)modrm - 0xC8;
sewardj2d49b432005-02-01 00:37:06 +00003991 DIP("fcmovz %%st(%d), %%st(0)\n", (Int)r_src);
sewardj5bd4d162004-11-10 13:02:48 +00003992 put_ST_UNCHECKED(0,
sewardj3fd5e572004-09-09 22:43:51 +00003993 IRExpr_Mux0X(
sewardj2a9ad022004-11-25 02:46:58 +00003994 unop(Iop_1Uto8,
3995 mk_x86g_calculate_condition(X86CondZ)),
sewardj3fd5e572004-09-09 22:43:51 +00003996 get_ST(0), get_ST(r_src)) );
3997 break;
3998
sewardj519d66f2004-12-15 11:57:58 +00003999 case 0xD0 ... 0xD7: /* FCMOVBE ST(i), ST(0) */
4000 r_src = (UInt)modrm - 0xD0;
sewardj2d49b432005-02-01 00:37:06 +00004001 DIP("fcmovbe %%st(%d), %%st(0)\n", (Int)r_src);
sewardj519d66f2004-12-15 11:57:58 +00004002 put_ST_UNCHECKED(0,
4003 IRExpr_Mux0X(
4004 unop(Iop_1Uto8,
4005 mk_x86g_calculate_condition(X86CondBE)),
4006 get_ST(0), get_ST(r_src)) );
4007 break;
4008
sewardj8253ad32005-07-04 10:26:32 +00004009 case 0xD8 ... 0xDF: /* FCMOVU ST(i), ST(0) */
4010 r_src = (UInt)modrm - 0xD8;
4011 DIP("fcmovnu %%st(%d), %%st(0)\n", (Int)r_src);
4012 put_ST_UNCHECKED(0,
4013 IRExpr_Mux0X(
4014 unop(Iop_1Uto8,
4015 mk_x86g_calculate_condition(X86CondP)),
4016 get_ST(0), get_ST(r_src)) );
4017 break;
4018
sewardjbdc7d212004-09-09 02:46:40 +00004019 case 0xE9: /* FUCOMPP %st(0),%st(1) */
4020 DIP("fucompp %%st(0),%%st(1)\n");
sewardjc4be80c2004-09-10 16:17:45 +00004021 /* This forces C1 to zero, which isn't right. */
4022 put_C3210(
4023 binop( Iop_And32,
4024 binop(Iop_Shl32,
4025 binop(Iop_CmpF64, get_ST(0), get_ST(1)),
4026 mkU8(8)),
4027 mkU32(0x4500)
4028 ));
sewardjbdc7d212004-09-09 02:46:40 +00004029 fp_pop();
4030 fp_pop();
4031 break;
4032
sewardj5bd4d162004-11-10 13:02:48 +00004033 default:
sewardjbdc7d212004-09-09 02:46:40 +00004034 goto decode_fail;
sewardj5bd4d162004-11-10 13:02:48 +00004035 }
sewardjbdc7d212004-09-09 02:46:40 +00004036
sewardjbb53f8c2004-08-14 11:50:01 +00004037 }
sewardjd1725d12004-08-12 20:46:53 +00004038 }
4039
4040 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDB opcodes +-+-+-+-+-+-+-+ */
4041 else
4042 if (first_opcode == 0xDB) {
sewardj89cd0932004-09-08 18:23:25 +00004043 if (modrm < 0xC0) {
4044
sewardjfeeb8a82004-11-30 12:30:11 +00004045 /* bits 5,4,3 are an opcode extension, and the modRM also
sewardj89cd0932004-09-08 18:23:25 +00004046 specifies an address. */
4047 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
4048 delta += len;
4049
4050 switch (gregOfRM(modrm)) {
4051
4052 case 0: /* FILD m32int */
4053 DIP("fildl %s\n", dis_buf);
4054 fp_push();
4055 put_ST(0, unop(Iop_I32toF64,
4056 loadLE(Ity_I32, mkexpr(addr))));
4057 break;
4058
sewardj8f3debf2004-09-08 23:42:23 +00004059 case 2: /* FIST m32 */
sewardj33dd31b2005-01-08 18:17:32 +00004060 DIP("fistl %s\n", dis_buf);
sewardj8f3debf2004-09-08 23:42:23 +00004061 storeLE( mkexpr(addr),
4062 binop(Iop_F64toI32, get_roundingmode(), get_ST(0)) );
4063 break;
4064
sewardj89cd0932004-09-08 18:23:25 +00004065 case 3: /* FISTP m32 */
sewardj33dd31b2005-01-08 18:17:32 +00004066 DIP("fistpl %s\n", dis_buf);
sewardj8f3debf2004-09-08 23:42:23 +00004067 storeLE( mkexpr(addr),
4068 binop(Iop_F64toI32, get_roundingmode(), get_ST(0)) );
sewardj5bd4d162004-11-10 13:02:48 +00004069 fp_pop();
sewardj89cd0932004-09-08 18:23:25 +00004070 break;
sewardj17442fe2004-09-20 14:54:28 +00004071
sewardjb3bce0e2004-09-14 23:20:10 +00004072 case 5: { /* FLD extended-real */
sewardj7cb49d72004-10-24 22:31:25 +00004073 /* Uses dirty helper:
sewardj56579232005-03-26 21:49:42 +00004074 ULong x86g_loadF80le ( UInt )
sewardj7cb49d72004-10-24 22:31:25 +00004075 addr holds the address. First, do a dirty call to
sewardjb3bce0e2004-09-14 23:20:10 +00004076 get hold of the data. */
sewardjc5fc7aa2004-10-27 23:00:55 +00004077 IRTemp val = newTemp(Ity_I64);
4078 IRExpr** args = mkIRExprVec_1 ( mkexpr(addr) );
4079
sewardj8ea867b2004-10-30 19:03:02 +00004080 IRDirty* d = unsafeIRDirty_1_N (
4081 val,
sewardj2a9ad022004-11-25 02:46:58 +00004082 0/*regparms*/,
4083 "x86g_loadF80le", &x86g_loadF80le,
sewardj8ea867b2004-10-30 19:03:02 +00004084 args
4085 );
sewardjb3bce0e2004-09-14 23:20:10 +00004086 /* declare that we're reading memory */
4087 d->mFx = Ifx_Read;
sewardj17442fe2004-09-20 14:54:28 +00004088 d->mAddr = mkexpr(addr);
sewardjb3bce0e2004-09-14 23:20:10 +00004089 d->mSize = 10;
sewardjc5fc7aa2004-10-27 23:00:55 +00004090
4091 /* execute the dirty call, dumping the result in val. */
sewardjb3bce0e2004-09-14 23:20:10 +00004092 stmt( IRStmt_Dirty(d) );
4093 fp_push();
sewardjc5fc7aa2004-10-27 23:00:55 +00004094 put_ST(0, unop(Iop_ReinterpI64asF64, mkexpr(val)));
4095
sewardj33dd31b2005-01-08 18:17:32 +00004096 DIP("fldt %s\n", dis_buf);
sewardjb3bce0e2004-09-14 23:20:10 +00004097 break;
4098 }
sewardj17442fe2004-09-20 14:54:28 +00004099
4100 case 7: { /* FSTP extended-real */
sewardj9fc9e782004-11-26 17:57:40 +00004101 /* Uses dirty helper: void x86g_storeF80le ( UInt, ULong ) */
sewardjc5fc7aa2004-10-27 23:00:55 +00004102 IRExpr** args
4103 = mkIRExprVec_2( mkexpr(addr),
4104 unop(Iop_ReinterpF64asI64, get_ST(0)) );
4105
sewardj8ea867b2004-10-30 19:03:02 +00004106 IRDirty* d = unsafeIRDirty_0_N (
sewardjf9655262004-10-31 20:02:16 +00004107 0/*regparms*/,
sewardj2a9ad022004-11-25 02:46:58 +00004108 "x86g_storeF80le", &x86g_storeF80le,
sewardj8ea867b2004-10-30 19:03:02 +00004109 args
4110 );
sewardj17442fe2004-09-20 14:54:28 +00004111 /* declare we're writing memory */
4112 d->mFx = Ifx_Write;
4113 d->mAddr = mkexpr(addr);
4114 d->mSize = 10;
sewardjc5fc7aa2004-10-27 23:00:55 +00004115
sewardj17442fe2004-09-20 14:54:28 +00004116 /* execute the dirty call. */
4117 stmt( IRStmt_Dirty(d) );
4118 fp_pop();
sewardjc5fc7aa2004-10-27 23:00:55 +00004119
sewardj33dd31b2005-01-08 18:17:32 +00004120 DIP("fstpt\n %s", dis_buf);
sewardj17442fe2004-09-20 14:54:28 +00004121 break;
4122 }
4123
sewardjb3bce0e2004-09-14 23:20:10 +00004124 default:
sewardj89cd0932004-09-08 18:23:25 +00004125 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
4126 vex_printf("first_opcode == 0xDB\n");
4127 goto decode_fail;
4128 }
4129
4130 } else {
sewardj8308aad2004-09-12 11:09:54 +00004131
4132 delta++;
4133 switch (modrm) {
4134
sewardj519d66f2004-12-15 11:57:58 +00004135 case 0xC0 ... 0xC7: /* FCMOVNB ST(i), ST(0) */
4136 r_src = (UInt)modrm - 0xC0;
sewardj2d49b432005-02-01 00:37:06 +00004137 DIP("fcmovnb %%st(%d), %%st(0)\n", (Int)r_src);
sewardj519d66f2004-12-15 11:57:58 +00004138 put_ST_UNCHECKED(0,
4139 IRExpr_Mux0X(
4140 unop(Iop_1Uto8,
4141 mk_x86g_calculate_condition(X86CondNB)),
4142 get_ST(0), get_ST(r_src)) );
4143 break;
4144
sewardj4e82db72004-10-16 11:32:15 +00004145 case 0xC8 ... 0xCF: /* FCMOVNE(NZ) ST(i), ST(0) */
4146 r_src = (UInt)modrm - 0xC8;
sewardj2d49b432005-02-01 00:37:06 +00004147 DIP("fcmovnz %%st(%d), %%st(0)\n", (Int)r_src);
sewardj5bd4d162004-11-10 13:02:48 +00004148 put_ST_UNCHECKED(0,
sewardj4e82db72004-10-16 11:32:15 +00004149 IRExpr_Mux0X(
sewardj2a9ad022004-11-25 02:46:58 +00004150 unop(Iop_1Uto8,
4151 mk_x86g_calculate_condition(X86CondNZ)),
sewardj4e82db72004-10-16 11:32:15 +00004152 get_ST(0), get_ST(r_src)) );
4153 break;
4154
sewardj519d66f2004-12-15 11:57:58 +00004155 case 0xD0 ... 0xD7: /* FCMOVNBE ST(i), ST(0) */
4156 r_src = (UInt)modrm - 0xD0;
sewardj2d49b432005-02-01 00:37:06 +00004157 DIP("fcmovnbe %%st(%d), %%st(0)\n", (Int)r_src);
sewardj519d66f2004-12-15 11:57:58 +00004158 put_ST_UNCHECKED(0,
4159 IRExpr_Mux0X(
4160 unop(Iop_1Uto8,
4161 mk_x86g_calculate_condition(X86CondNBE)),
4162 get_ST(0), get_ST(r_src)) );
4163 break;
4164
sewardj8253ad32005-07-04 10:26:32 +00004165 case 0xD8 ... 0xDF: /* FCMOVNU ST(i), ST(0) */
4166 r_src = (UInt)modrm - 0xD8;
4167 DIP("fcmovnu %%st(%d), %%st(0)\n", (Int)r_src);
4168 put_ST_UNCHECKED(0,
4169 IRExpr_Mux0X(
4170 unop(Iop_1Uto8,
4171 mk_x86g_calculate_condition(X86CondNP)),
4172 get_ST(0), get_ST(r_src)) );
4173 break;
4174
sewardj7df596b2004-12-06 14:29:12 +00004175 case 0xE2:
4176 DIP("fnclex\n");
4177 break;
4178
sewardja0e83b02005-01-06 12:36:38 +00004179 case 0xE3: {
4180 /* Uses dirty helper:
4181 void x86g_do_FINIT ( VexGuestX86State* ) */
4182 IRDirty* d = unsafeIRDirty_0_N (
4183 0/*regparms*/,
4184 "x86g_dirtyhelper_FINIT",
4185 &x86g_dirtyhelper_FINIT,
4186 mkIRExprVec_0()
4187 );
4188 d->needsBBP = True;
4189
4190 /* declare we're writing guest state */
4191 d->nFxState = 5;
4192
4193 d->fxState[0].fx = Ifx_Write;
4194 d->fxState[0].offset = OFFB_FTOP;
4195 d->fxState[0].size = sizeof(UInt);
4196
4197 d->fxState[1].fx = Ifx_Write;
4198 d->fxState[1].offset = OFFB_FPREGS;
4199 d->fxState[1].size = 8 * sizeof(ULong);
4200
4201 d->fxState[2].fx = Ifx_Write;
4202 d->fxState[2].offset = OFFB_FPTAGS;
4203 d->fxState[2].size = 8 * sizeof(UChar);
4204
4205 d->fxState[3].fx = Ifx_Write;
4206 d->fxState[3].offset = OFFB_FPROUND;
4207 d->fxState[3].size = sizeof(UInt);
4208
4209 d->fxState[4].fx = Ifx_Write;
4210 d->fxState[4].offset = OFFB_FC3210;
4211 d->fxState[4].size = sizeof(UInt);
4212
4213 stmt( IRStmt_Dirty(d) );
4214
sewardj33dd31b2005-01-08 18:17:32 +00004215 DIP("fninit\n");
sewardja0e83b02005-01-06 12:36:38 +00004216 break;
4217 }
4218
sewardj8308aad2004-09-12 11:09:54 +00004219 case 0xE8 ... 0xEF: /* FUCOMI %st(0),%st(?) */
4220 fp_do_ucomi_ST0_STi( (UInt)modrm - 0xE8, False );
4221 break;
4222
sewardj37158712004-10-15 21:23:12 +00004223 case 0xF0 ... 0xF7: /* FCOMI %st(0),%st(?) */
4224 fp_do_ucomi_ST0_STi( (UInt)modrm - 0xF0, False );
4225 break;
4226
sewardj8308aad2004-09-12 11:09:54 +00004227 default:
4228 goto decode_fail;
sewardj17442fe2004-09-20 14:54:28 +00004229 }
sewardj89cd0932004-09-08 18:23:25 +00004230 }
sewardjd1725d12004-08-12 20:46:53 +00004231 }
4232
4233 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDC opcodes +-+-+-+-+-+-+-+ */
4234 else
4235 if (first_opcode == 0xDC) {
sewardja58ea662004-08-15 03:12:41 +00004236 if (modrm < 0xC0) {
4237
sewardj89cd0932004-09-08 18:23:25 +00004238 /* bits 5,4,3 are an opcode extension, and the modRM also
sewardjfeeb8a82004-11-30 12:30:11 +00004239 specifies an address. */
sewardja58ea662004-08-15 03:12:41 +00004240 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
4241 delta += len;
4242
4243 switch (gregOfRM(modrm)) {
4244
4245 case 0: /* FADD double-real */
4246 fp_do_op_mem_ST_0 ( addr, "add", dis_buf, Iop_AddF64, True );
4247 break;
4248
sewardjcfded9a2004-09-09 11:44:16 +00004249 case 1: /* FMUL double-real */
4250 fp_do_op_mem_ST_0 ( addr, "mul", dis_buf, Iop_MulF64, True );
4251 break;
4252
sewardje166ed02004-10-25 02:27:01 +00004253 case 2: /* FCOM double-real */
4254 DIP("fcoml %s\n", dis_buf);
4255 /* This forces C1 to zero, which isn't right. */
4256 put_C3210(
4257 binop( Iop_And32,
4258 binop(Iop_Shl32,
4259 binop(Iop_CmpF64,
4260 get_ST(0),
4261 loadLE(Ity_F64,mkexpr(addr))),
4262 mkU8(8)),
4263 mkU32(0x4500)
4264 ));
4265 break;
4266
sewardj883b00b2004-09-11 09:30:24 +00004267 case 3: /* FCOMP double-real */
sewardje166ed02004-10-25 02:27:01 +00004268 DIP("fcompl %s\n", dis_buf);
sewardj883b00b2004-09-11 09:30:24 +00004269 /* This forces C1 to zero, which isn't right. */
4270 put_C3210(
4271 binop( Iop_And32,
4272 binop(Iop_Shl32,
4273 binop(Iop_CmpF64,
4274 get_ST(0),
4275 loadLE(Ity_F64,mkexpr(addr))),
4276 mkU8(8)),
4277 mkU32(0x4500)
4278 ));
4279 fp_pop();
4280 break;
4281
sewardjcfded9a2004-09-09 11:44:16 +00004282 case 4: /* FSUB double-real */
4283 fp_do_op_mem_ST_0 ( addr, "sub", dis_buf, Iop_SubF64, True );
4284 break;
4285
sewardj3fd5e572004-09-09 22:43:51 +00004286 case 5: /* FSUBR double-real */
4287 fp_do_oprev_mem_ST_0 ( addr, "subr", dis_buf, Iop_SubF64, True );
4288 break;
4289
sewardjcfded9a2004-09-09 11:44:16 +00004290 case 6: /* FDIV double-real */
4291 fp_do_op_mem_ST_0 ( addr, "div", dis_buf, Iop_DivF64, True );
4292 break;
4293
sewardj883b00b2004-09-11 09:30:24 +00004294 case 7: /* FDIVR double-real */
4295 fp_do_oprev_mem_ST_0 ( addr, "divr", dis_buf, Iop_DivF64, True );
4296 break;
4297
sewardja58ea662004-08-15 03:12:41 +00004298 default:
4299 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
4300 vex_printf("first_opcode == 0xDC\n");
4301 goto decode_fail;
4302 }
4303
4304 } else {
sewardjbdc7d212004-09-09 02:46:40 +00004305
4306 delta++;
4307 switch (modrm) {
4308
sewardj3fd5e572004-09-09 22:43:51 +00004309 case 0xC0 ... 0xC7: /* FADD %st(0),%st(?) */
4310 fp_do_op_ST_ST ( "add", Iop_AddF64, 0, modrm - 0xC0, False );
4311 break;
4312
sewardjcfded9a2004-09-09 11:44:16 +00004313 case 0xC8 ... 0xCF: /* FMUL %st(0),%st(?) */
4314 fp_do_op_ST_ST ( "mul", Iop_MulF64, 0, modrm - 0xC8, False );
4315 break;
4316
sewardj47341042004-09-19 11:55:46 +00004317 case 0xE0 ... 0xE7: /* FSUBR %st(0),%st(?) */
4318 fp_do_oprev_ST_ST ( "subr", Iop_SubF64, 0, modrm - 0xE0, False );
4319 break;
4320
sewardjcfded9a2004-09-09 11:44:16 +00004321 case 0xE8 ... 0xEF: /* FSUB %st(0),%st(?) */
4322 fp_do_op_ST_ST ( "sub", Iop_SubF64, 0, modrm - 0xE8, False );
4323 break;
4324
sewardja0d48d62004-09-20 21:19:03 +00004325 case 0xF0 ... 0xF7: /* FDIVR %st(0),%st(?) */
4326 fp_do_oprev_ST_ST ( "divr", Iop_DivF64, 0, modrm - 0xF0, False );
4327 break;
4328
sewardjbdc7d212004-09-09 02:46:40 +00004329 case 0xF8 ... 0xFF: /* FDIV %st(0),%st(?) */
4330 fp_do_op_ST_ST ( "div", Iop_DivF64, 0, modrm - 0xF8, False );
4331 break;
4332
4333 default:
4334 goto decode_fail;
sewardj5bd4d162004-11-10 13:02:48 +00004335 }
sewardjbdc7d212004-09-09 02:46:40 +00004336
sewardja58ea662004-08-15 03:12:41 +00004337 }
sewardjd1725d12004-08-12 20:46:53 +00004338 }
4339
4340 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDD opcodes +-+-+-+-+-+-+-+ */
4341 else
4342 if (first_opcode == 0xDD) {
4343
4344 if (modrm < 0xC0) {
4345
sewardjfeeb8a82004-11-30 12:30:11 +00004346 /* bits 5,4,3 are an opcode extension, and the modRM also
sewardjd1725d12004-08-12 20:46:53 +00004347 specifies an address. */
sewardjbb53f8c2004-08-14 11:50:01 +00004348 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
4349 delta += len;
sewardjd1725d12004-08-12 20:46:53 +00004350
4351 switch (gregOfRM(modrm)) {
4352
4353 case 0: /* FLD double-real */
sewardj33dd31b2005-01-08 18:17:32 +00004354 DIP("fldl %s\n", dis_buf);
sewardj207557a2004-08-27 12:00:18 +00004355 fp_push();
sewardjaf1ceca2005-06-30 23:31:27 +00004356 put_ST(0, loadLE(Ity_F64, mkexpr(addr)));
sewardjbb53f8c2004-08-14 11:50:01 +00004357 break;
sewardjd1725d12004-08-12 20:46:53 +00004358
sewardjd1725d12004-08-12 20:46:53 +00004359 case 2: /* FST double-real */
sewardj33dd31b2005-01-08 18:17:32 +00004360 DIP("fstl %s\n", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00004361 storeLE(mkexpr(addr), get_ST(0));
sewardjd1725d12004-08-12 20:46:53 +00004362 break;
sewardj89cd0932004-09-08 18:23:25 +00004363
sewardja58ea662004-08-15 03:12:41 +00004364 case 3: /* FSTP double-real */
sewardj33dd31b2005-01-08 18:17:32 +00004365 DIP("fstpl %s\n", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00004366 storeLE(mkexpr(addr), get_ST(0));
4367 fp_pop();
sewardja58ea662004-08-15 03:12:41 +00004368 break;
sewardjd1725d12004-08-12 20:46:53 +00004369
sewardj9fc9e782004-11-26 17:57:40 +00004370 case 4: { /* FRSTOR m108 */
sewardj893aada2004-11-29 19:57:54 +00004371 /* Uses dirty helper:
4372 VexEmWarn x86g_do_FRSTOR ( VexGuestX86State*, Addr32 ) */
4373 IRTemp ew = newTemp(Ity_I32);
4374 IRDirty* d = unsafeIRDirty_0_N (
4375 0/*regparms*/,
4376 "x86g_dirtyhelper_FRSTOR",
4377 &x86g_dirtyhelper_FRSTOR,
4378 mkIRExprVec_1( mkexpr(addr) )
4379 );
sewardj9fc9e782004-11-26 17:57:40 +00004380 d->needsBBP = True;
sewardj893aada2004-11-29 19:57:54 +00004381 d->tmp = ew;
sewardj9fc9e782004-11-26 17:57:40 +00004382 /* declare we're reading memory */
4383 d->mFx = Ifx_Read;
4384 d->mAddr = mkexpr(addr);
4385 d->mSize = 108;
4386
4387 /* declare we're writing guest state */
sewardj893aada2004-11-29 19:57:54 +00004388 d->nFxState = 5;
sewardj9fc9e782004-11-26 17:57:40 +00004389
4390 d->fxState[0].fx = Ifx_Write;
sewardjc9a43662004-11-30 18:51:59 +00004391 d->fxState[0].offset = OFFB_FTOP;
sewardj9fc9e782004-11-26 17:57:40 +00004392 d->fxState[0].size = sizeof(UInt);
4393
4394 d->fxState[1].fx = Ifx_Write;
sewardjc9a43662004-11-30 18:51:59 +00004395 d->fxState[1].offset = OFFB_FPREGS;
sewardj9fc9e782004-11-26 17:57:40 +00004396 d->fxState[1].size = 8 * sizeof(ULong);
4397
4398 d->fxState[2].fx = Ifx_Write;
sewardjc9a43662004-11-30 18:51:59 +00004399 d->fxState[2].offset = OFFB_FPTAGS;
sewardj9fc9e782004-11-26 17:57:40 +00004400 d->fxState[2].size = 8 * sizeof(UChar);
4401
4402 d->fxState[3].fx = Ifx_Write;
sewardjc9a43662004-11-30 18:51:59 +00004403 d->fxState[3].offset = OFFB_FPROUND;
sewardj9fc9e782004-11-26 17:57:40 +00004404 d->fxState[3].size = sizeof(UInt);
4405
4406 d->fxState[4].fx = Ifx_Write;
sewardjc9a43662004-11-30 18:51:59 +00004407 d->fxState[4].offset = OFFB_FC3210;
sewardj9fc9e782004-11-26 17:57:40 +00004408 d->fxState[4].size = sizeof(UInt);
4409
4410 stmt( IRStmt_Dirty(d) );
4411
sewardj893aada2004-11-29 19:57:54 +00004412 /* ew contains any emulation warning we may need to
4413 issue. If needed, side-exit to the next insn,
4414 reporting the warning, so that Valgrind's dispatcher
4415 sees the warning. */
4416 put_emwarn( mkexpr(ew) );
4417 stmt(
4418 IRStmt_Exit(
4419 binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
4420 Ijk_EmWarn,
sewardj9e6491a2005-07-02 19:24:10 +00004421 IRConst_U32( ((Addr32)guest_EIP_bbstart)+delta)
sewardj893aada2004-11-29 19:57:54 +00004422 )
4423 );
4424
sewardj33dd31b2005-01-08 18:17:32 +00004425 DIP("frstor %s\n", dis_buf);
sewardj9fc9e782004-11-26 17:57:40 +00004426 break;
4427 }
4428
4429 case 6: { /* FNSAVE m108 */
sewardj893aada2004-11-29 19:57:54 +00004430 /* Uses dirty helper:
4431 void x86g_do_FSAVE ( VexGuestX86State*, UInt ) */
sewardj9fc9e782004-11-26 17:57:40 +00004432 IRDirty* d = unsafeIRDirty_0_N (
4433 0/*regparms*/,
4434 "x86g_dirtyhelper_FSAVE",
4435 &x86g_dirtyhelper_FSAVE,
4436 mkIRExprVec_1( mkexpr(addr) )
4437 );
4438 d->needsBBP = True;
4439 /* declare we're writing memory */
4440 d->mFx = Ifx_Write;
4441 d->mAddr = mkexpr(addr);
4442 d->mSize = 108;
4443
4444 /* declare we're reading guest state */
sewardj893aada2004-11-29 19:57:54 +00004445 d->nFxState = 5;
sewardj9fc9e782004-11-26 17:57:40 +00004446
4447 d->fxState[0].fx = Ifx_Read;
sewardjc9a43662004-11-30 18:51:59 +00004448 d->fxState[0].offset = OFFB_FTOP;
sewardj9fc9e782004-11-26 17:57:40 +00004449 d->fxState[0].size = sizeof(UInt);
4450
4451 d->fxState[1].fx = Ifx_Read;
sewardjc9a43662004-11-30 18:51:59 +00004452 d->fxState[1].offset = OFFB_FPREGS;
sewardj9fc9e782004-11-26 17:57:40 +00004453 d->fxState[1].size = 8 * sizeof(ULong);
4454
4455 d->fxState[2].fx = Ifx_Read;
sewardjc9a43662004-11-30 18:51:59 +00004456 d->fxState[2].offset = OFFB_FPTAGS;
sewardj9fc9e782004-11-26 17:57:40 +00004457 d->fxState[2].size = 8 * sizeof(UChar);
4458
4459 d->fxState[3].fx = Ifx_Read;
sewardjc9a43662004-11-30 18:51:59 +00004460 d->fxState[3].offset = OFFB_FPROUND;
sewardj9fc9e782004-11-26 17:57:40 +00004461 d->fxState[3].size = sizeof(UInt);
4462
4463 d->fxState[4].fx = Ifx_Read;
sewardjc9a43662004-11-30 18:51:59 +00004464 d->fxState[4].offset = OFFB_FC3210;
sewardj9fc9e782004-11-26 17:57:40 +00004465 d->fxState[4].size = sizeof(UInt);
4466
4467 stmt( IRStmt_Dirty(d) );
4468
sewardj33dd31b2005-01-08 18:17:32 +00004469 DIP("fnsave %s\n", dis_buf);
sewardj9fc9e782004-11-26 17:57:40 +00004470 break;
4471 }
4472
sewardjd24931d2005-03-20 12:51:39 +00004473 case 7: { /* FNSTSW m16 */
4474 IRExpr* sw = get_FPU_sw();
4475 vassert(typeOfIRExpr(irbb->tyenv, sw) == Ity_I16);
4476 storeLE( mkexpr(addr), sw );
4477 DIP("fnstsw %s\n", dis_buf);
4478 break;
4479 }
4480
sewardjd1725d12004-08-12 20:46:53 +00004481 default:
sewardjbb53f8c2004-08-14 11:50:01 +00004482 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
4483 vex_printf("first_opcode == 0xDD\n");
sewardjd1725d12004-08-12 20:46:53 +00004484 goto decode_fail;
sewardjbb53f8c2004-08-14 11:50:01 +00004485 }
sewardjd1725d12004-08-12 20:46:53 +00004486 } else {
sewardja58ea662004-08-15 03:12:41 +00004487 delta++;
4488 switch (modrm) {
sewardjbdc7d212004-09-09 02:46:40 +00004489
sewardj3ddedc42005-03-25 20:30:00 +00004490 case 0xC0 ... 0xC7: /* FFREE %st(?) */
4491 r_dst = (UInt)modrm - 0xC0;
sewardj4a6f3842005-03-26 11:59:23 +00004492 DIP("ffree %%st(%d)\n", (Int)r_dst);
sewardj3ddedc42005-03-25 20:30:00 +00004493 put_ST_TAG ( r_dst, mkU8(0) );
4494 break;
4495
sewardj06c32a02004-09-12 12:07:34 +00004496 case 0xD0 ... 0xD7: /* FST %st(0),%st(?) */
4497 r_dst = (UInt)modrm - 0xD0;
sewardj2d49b432005-02-01 00:37:06 +00004498 DIP("fst %%st(0),%%st(%d)\n", (Int)r_dst);
sewardj5bd4d162004-11-10 13:02:48 +00004499 /* P4 manual says: "If the destination operand is a
sewardj06c32a02004-09-12 12:07:34 +00004500 non-empty register, the invalid-operation exception
4501 is not generated. Hence put_ST_UNCHECKED. */
4502 put_ST_UNCHECKED(r_dst, get_ST(0));
4503 break;
4504
sewardja58ea662004-08-15 03:12:41 +00004505 case 0xD8 ... 0xDF: /* FSTP %st(0),%st(?) */
4506 r_dst = (UInt)modrm - 0xD8;
sewardj2d49b432005-02-01 00:37:06 +00004507 DIP("fstp %%st(0),%%st(%d)\n", (Int)r_dst);
sewardj5bd4d162004-11-10 13:02:48 +00004508 /* P4 manual says: "If the destination operand is a
sewardj207557a2004-08-27 12:00:18 +00004509 non-empty register, the invalid-operation exception
4510 is not generated. Hence put_ST_UNCHECKED. */
4511 put_ST_UNCHECKED(r_dst, get_ST(0));
4512 fp_pop();
sewardja58ea662004-08-15 03:12:41 +00004513 break;
sewardjbdc7d212004-09-09 02:46:40 +00004514
4515 case 0xE0 ... 0xE7: /* FUCOM %st(0),%st(?) */
4516 r_dst = (UInt)modrm - 0xE0;
sewardj2d49b432005-02-01 00:37:06 +00004517 DIP("fucom %%st(0),%%st(%d)\n", (Int)r_dst);
sewardjc4be80c2004-09-10 16:17:45 +00004518 /* This forces C1 to zero, which isn't right. */
4519 put_C3210(
4520 binop( Iop_And32,
4521 binop(Iop_Shl32,
4522 binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
4523 mkU8(8)),
4524 mkU32(0x4500)
4525 ));
sewardjbdc7d212004-09-09 02:46:40 +00004526 break;
4527
4528 case 0xE8 ... 0xEF: /* FUCOMP %st(0),%st(?) */
4529 r_dst = (UInt)modrm - 0xE8;
sewardj2d49b432005-02-01 00:37:06 +00004530 DIP("fucomp %%st(0),%%st(%d)\n", (Int)r_dst);
sewardjc4be80c2004-09-10 16:17:45 +00004531 /* This forces C1 to zero, which isn't right. */
4532 put_C3210(
4533 binop( Iop_And32,
4534 binop(Iop_Shl32,
4535 binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
4536 mkU8(8)),
4537 mkU32(0x4500)
4538 ));
sewardjbdc7d212004-09-09 02:46:40 +00004539 fp_pop();
4540 break;
4541
sewardj5bd4d162004-11-10 13:02:48 +00004542 default:
sewardja58ea662004-08-15 03:12:41 +00004543 goto decode_fail;
sewardj5bd4d162004-11-10 13:02:48 +00004544 }
sewardjd1725d12004-08-12 20:46:53 +00004545 }
4546 }
4547
4548 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDE opcodes +-+-+-+-+-+-+-+ */
4549 else
4550 if (first_opcode == 0xDE) {
sewardjbdc7d212004-09-09 02:46:40 +00004551
4552 if (modrm < 0xC0) {
sewardjfeeb8a82004-11-30 12:30:11 +00004553
4554 /* bits 5,4,3 are an opcode extension, and the modRM also
4555 specifies an address. */
4556 IROp fop;
4557 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
4558 delta += len;
4559
4560 switch (gregOfRM(modrm)) {
4561
4562 case 0: /* FIADD m16int */ /* ST(0) += m16int */
sewardj33dd31b2005-01-08 18:17:32 +00004563 DIP("fiaddw %s\n", dis_buf);
sewardjfeeb8a82004-11-30 12:30:11 +00004564 fop = Iop_AddF64;
4565 goto do_fop_m16;
4566
4567 case 1: /* FIMUL m16int */ /* ST(0) *= m16int */
sewardj33dd31b2005-01-08 18:17:32 +00004568 DIP("fimulw %s\n", dis_buf);
sewardjfeeb8a82004-11-30 12:30:11 +00004569 fop = Iop_MulF64;
4570 goto do_fop_m16;
4571
4572 case 4: /* FISUB m16int */ /* ST(0) -= m16int */
sewardj33dd31b2005-01-08 18:17:32 +00004573 DIP("fisubw %s\n", dis_buf);
sewardjfeeb8a82004-11-30 12:30:11 +00004574 fop = Iop_SubF64;
4575 goto do_fop_m16;
4576
4577 case 5: /* FISUBR m16int */ /* ST(0) = m16int - ST(0) */
sewardj33dd31b2005-01-08 18:17:32 +00004578 DIP("fisubrw %s\n", dis_buf);
sewardjfeeb8a82004-11-30 12:30:11 +00004579 fop = Iop_SubF64;
4580 goto do_foprev_m16;
4581
4582 case 6: /* FIDIV m16int */ /* ST(0) /= m16int */
sewardj33dd31b2005-01-08 18:17:32 +00004583 DIP("fisubw %s\n", dis_buf);
sewardjfeeb8a82004-11-30 12:30:11 +00004584 fop = Iop_DivF64;
4585 goto do_fop_m16;
4586
4587 case 7: /* FIDIVR m16int */ /* ST(0) = m16int / ST(0) */
sewardj33dd31b2005-01-08 18:17:32 +00004588 DIP("fidivrw %s\n", dis_buf);
sewardjfeeb8a82004-11-30 12:30:11 +00004589 fop = Iop_DivF64;
4590 goto do_foprev_m16;
4591
4592 do_fop_m16:
4593 put_ST_UNCHECKED(0,
4594 binop(fop,
4595 get_ST(0),
4596 unop(Iop_I32toF64,
4597 unop(Iop_16Sto32,
4598 loadLE(Ity_I16, mkexpr(addr))))));
4599 break;
4600
4601 do_foprev_m16:
4602 put_ST_UNCHECKED(0,
4603 binop(fop,
4604 unop(Iop_I32toF64,
4605 unop(Iop_16Sto32,
4606 loadLE(Ity_I16, mkexpr(addr)))),
4607 get_ST(0)));
4608 break;
4609
4610 default:
4611 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
4612 vex_printf("first_opcode == 0xDE\n");
4613 goto decode_fail;
4614 }
sewardjbdc7d212004-09-09 02:46:40 +00004615
4616 } else {
4617
4618 delta++;
sewardj5bd4d162004-11-10 13:02:48 +00004619 switch (modrm) {
sewardjbdc7d212004-09-09 02:46:40 +00004620
sewardjcfded9a2004-09-09 11:44:16 +00004621 case 0xC0 ... 0xC7: /* FADDP %st(0),%st(?) */
4622 fp_do_op_ST_ST ( "add", Iop_AddF64, 0, modrm - 0xC0, True );
4623 break;
4624
sewardjbdc7d212004-09-09 02:46:40 +00004625 case 0xC8 ... 0xCF: /* FMULP %st(0),%st(?) */
4626 fp_do_op_ST_ST ( "mul", Iop_MulF64, 0, modrm - 0xC8, True );
4627 break;
4628
sewardje166ed02004-10-25 02:27:01 +00004629 case 0xD9: /* FCOMPP %st(0),%st(1) */
4630 DIP("fuompp %%st(0),%%st(1)\n");
4631 /* This forces C1 to zero, which isn't right. */
4632 put_C3210(
4633 binop( Iop_And32,
4634 binop(Iop_Shl32,
4635 binop(Iop_CmpF64, get_ST(0), get_ST(1)),
4636 mkU8(8)),
4637 mkU32(0x4500)
4638 ));
4639 fp_pop();
4640 fp_pop();
4641 break;
4642
sewardjcfded9a2004-09-09 11:44:16 +00004643 case 0xE0 ... 0xE7: /* FSUBRP %st(0),%st(?) */
4644 fp_do_oprev_ST_ST ( "subr", Iop_SubF64, 0, modrm - 0xE0, True );
4645 break;
4646
sewardj3fd5e572004-09-09 22:43:51 +00004647 case 0xE8 ... 0xEF: /* FSUBP %st(0),%st(?) */
4648 fp_do_op_ST_ST ( "sub", Iop_SubF64, 0, modrm - 0xE8, True );
4649 break;
4650
sewardjbdc7d212004-09-09 02:46:40 +00004651 case 0xF0 ... 0xF7: /* FDIVRP %st(0),%st(?) */
4652 fp_do_oprev_ST_ST ( "divr", Iop_DivF64, 0, modrm - 0xF0, True );
4653 break;
4654
4655 case 0xF8 ... 0xFF: /* FDIVP %st(0),%st(?) */
4656 fp_do_op_ST_ST ( "div", Iop_DivF64, 0, modrm - 0xF8, True );
4657 break;
4658
4659 default:
4660 goto decode_fail;
sewardj5bd4d162004-11-10 13:02:48 +00004661 }
sewardjbdc7d212004-09-09 02:46:40 +00004662
4663 }
sewardjd1725d12004-08-12 20:46:53 +00004664 }
4665
4666 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDF opcodes +-+-+-+-+-+-+-+ */
4667 else
4668 if (first_opcode == 0xDF) {
sewardj89cd0932004-09-08 18:23:25 +00004669
4670 if (modrm < 0xC0) {
4671
sewardjfeeb8a82004-11-30 12:30:11 +00004672 /* bits 5,4,3 are an opcode extension, and the modRM also
sewardj89cd0932004-09-08 18:23:25 +00004673 specifies an address. */
4674 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
4675 delta += len;
4676
4677 switch (gregOfRM(modrm)) {
4678
sewardj883b00b2004-09-11 09:30:24 +00004679 case 0: /* FILD m16int */
4680 DIP("fildw %s\n", dis_buf);
4681 fp_push();
4682 put_ST(0, unop(Iop_I32toF64,
4683 unop(Iop_16Sto32,
4684 loadLE(Ity_I16, mkexpr(addr)))));
4685 break;
4686
sewardj37158712004-10-15 21:23:12 +00004687 case 2: /* FIST m16 */
sewardj33dd31b2005-01-08 18:17:32 +00004688 DIP("fistp %s\n", dis_buf);
sewardj37158712004-10-15 21:23:12 +00004689 storeLE( mkexpr(addr),
4690 binop(Iop_F64toI16, get_roundingmode(), get_ST(0)) );
4691 break;
4692
sewardj89cd0932004-09-08 18:23:25 +00004693 case 3: /* FISTP m16 */
sewardj33dd31b2005-01-08 18:17:32 +00004694 DIP("fistps %s\n", dis_buf);
sewardj8f3debf2004-09-08 23:42:23 +00004695 storeLE( mkexpr(addr),
4696 binop(Iop_F64toI16, get_roundingmode(), get_ST(0)) );
4697 fp_pop();
sewardj89cd0932004-09-08 18:23:25 +00004698 break;
4699
sewardj89cd0932004-09-08 18:23:25 +00004700 case 5: /* FILD m64 */
4701 DIP("fildll %s\n", dis_buf);
4702 fp_push();
sewardj4cb918d2004-12-03 19:43:31 +00004703 put_ST(0, binop(Iop_I64toF64,
4704 get_roundingmode(),
4705 loadLE(Ity_I64, mkexpr(addr))));
sewardj89cd0932004-09-08 18:23:25 +00004706 break;
sewardj89cd0932004-09-08 18:23:25 +00004707
sewardjcfded9a2004-09-09 11:44:16 +00004708 case 7: /* FISTP m64 */
sewardj33dd31b2005-01-08 18:17:32 +00004709 DIP("fistpll %s\n", dis_buf);
sewardjcfded9a2004-09-09 11:44:16 +00004710 storeLE( mkexpr(addr),
4711 binop(Iop_F64toI64, get_roundingmode(), get_ST(0)) );
4712 fp_pop();
4713 break;
4714
sewardj89cd0932004-09-08 18:23:25 +00004715 default:
4716 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
4717 vex_printf("first_opcode == 0xDF\n");
4718 goto decode_fail;
4719 }
4720
4721 } else {
sewardjbdc7d212004-09-09 02:46:40 +00004722
4723 delta++;
sewardj5bd4d162004-11-10 13:02:48 +00004724 switch (modrm) {
sewardjbdc7d212004-09-09 02:46:40 +00004725
4726 case 0xE0: /* FNSTSW %ax */
4727 DIP("fnstsw %%ax\n");
sewardjd24931d2005-03-20 12:51:39 +00004728 /* Get the FPU status word value and dump it in %AX. */
4729 putIReg(2, R_EAX, get_FPU_sw());
sewardjbdc7d212004-09-09 02:46:40 +00004730 break;
4731
sewardj883b00b2004-09-11 09:30:24 +00004732 case 0xE8 ... 0xEF: /* FUCOMIP %st(0),%st(?) */
sewardj8308aad2004-09-12 11:09:54 +00004733 fp_do_ucomi_ST0_STi( (UInt)modrm - 0xE8, True );
sewardj883b00b2004-09-11 09:30:24 +00004734 break;
4735
sewardjfeeb8a82004-11-30 12:30:11 +00004736 case 0xF0 ... 0xF7: /* FCOMIP %st(0),%st(?) */
4737 /* not really right since COMIP != UCOMIP */
4738 fp_do_ucomi_ST0_STi( (UInt)modrm - 0xF0, True );
4739 break;
4740
sewardjbdc7d212004-09-09 02:46:40 +00004741 default:
4742 goto decode_fail;
sewardj5bd4d162004-11-10 13:02:48 +00004743 }
sewardj89cd0932004-09-08 18:23:25 +00004744 }
4745
sewardjd1725d12004-08-12 20:46:53 +00004746 }
4747
4748 else
4749 vpanic("dis_FPU(x86): invalid primary opcode");
4750
sewardj69d9d662004-10-14 21:58:52 +00004751 *decode_ok = True;
4752 return delta;
4753
sewardjd1725d12004-08-12 20:46:53 +00004754 decode_fail:
4755 *decode_ok = False;
4756 return delta;
4757}
4758
4759
sewardj464efa42004-11-19 22:17:29 +00004760/*------------------------------------------------------------*/
4761/*--- ---*/
4762/*--- MMX INSTRUCTIONS ---*/
4763/*--- ---*/
4764/*------------------------------------------------------------*/
sewardja06e5562004-07-14 13:18:05 +00004765
sewardj464efa42004-11-19 22:17:29 +00004766/* Effect of MMX insns on x87 FPU state (table 11-2 of
4767 IA32 arch manual, volume 3):
4768
4769 Read from, or write to MMX register (viz, any insn except EMMS):
4770 * All tags set to Valid (non-empty) -- FPTAGS[i] := nonzero
4771 * FP stack pointer set to zero
4772
4773 EMMS:
4774 * All tags set to Invalid (empty) -- FPTAGS[i] := zero
4775 * FP stack pointer set to zero
4776*/
4777
sewardj4cb918d2004-12-03 19:43:31 +00004778static void do_MMX_preamble ( void )
sewardj464efa42004-11-19 22:17:29 +00004779{
4780 Int i;
4781 IRArray* descr = mkIRArray( OFFB_FPTAGS, Ity_I8, 8 );
4782 IRExpr* zero = mkU32(0);
4783 IRExpr* tag1 = mkU8(1);
4784 put_ftop(zero);
4785 for (i = 0; i < 8; i++)
4786 stmt( IRStmt_PutI( descr, zero, i, tag1 ) );
4787}
4788
sewardj4cb918d2004-12-03 19:43:31 +00004789static void do_EMMS_preamble ( void )
sewardj464efa42004-11-19 22:17:29 +00004790{
4791 Int i;
4792 IRArray* descr = mkIRArray( OFFB_FPTAGS, Ity_I8, 8 );
4793 IRExpr* zero = mkU32(0);
4794 IRExpr* tag0 = mkU8(0);
4795 put_ftop(zero);
4796 for (i = 0; i < 8; i++)
4797 stmt( IRStmt_PutI( descr, zero, i, tag0 ) );
4798}
4799
4800
4801static IRExpr* getMMXReg ( UInt archreg )
4802{
4803 vassert(archreg < 8);
4804 return IRExpr_Get( OFFB_FPREGS + 8 * archreg, Ity_I64 );
4805}
4806
4807
4808static void putMMXReg ( UInt archreg, IRExpr* e )
4809{
4810 vassert(archreg < 8);
4811 vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_I64);
4812 stmt( IRStmt_Put( OFFB_FPREGS + 8 * archreg, e ) );
4813}
4814
4815
sewardj38a3f862005-01-13 15:06:51 +00004816/* Helper for non-shift MMX insns. Note this is incomplete in the
4817 sense that it does not first call do_MMX_preamble() -- that is the
4818 responsibility of its caller. */
4819
sewardj464efa42004-11-19 22:17:29 +00004820static
sewardj2d49b432005-02-01 00:37:06 +00004821UInt dis_MMXop_regmem_to_reg ( UChar sorb,
sewardj52d04912005-07-03 00:52:48 +00004822 Int delta,
sewardj2d49b432005-02-01 00:37:06 +00004823 UChar opc,
4824 HChar* name,
4825 Bool show_granularity )
sewardj464efa42004-11-19 22:17:29 +00004826{
sewardjc9a43662004-11-30 18:51:59 +00004827 HChar dis_buf[50];
sewardj63ba4092004-11-21 12:30:18 +00004828 UChar modrm = getIByte(delta);
4829 Bool isReg = epartIsReg(modrm);
4830 IRExpr* argL = NULL;
4831 IRExpr* argR = NULL;
sewardj38a3f862005-01-13 15:06:51 +00004832 IRExpr* argG = NULL;
4833 IRExpr* argE = NULL;
sewardj63ba4092004-11-21 12:30:18 +00004834 IRTemp res = newTemp(Ity_I64);
sewardj464efa42004-11-19 22:17:29 +00004835
sewardj38a3f862005-01-13 15:06:51 +00004836 Bool invG = False;
4837 IROp op = Iop_INVALID;
4838 void* hAddr = NULL;
sewardj2d49b432005-02-01 00:37:06 +00004839 HChar* hName = NULL;
sewardj38a3f862005-01-13 15:06:51 +00004840 Bool eLeft = False;
4841
sewardj2b7a9202004-11-26 19:15:38 +00004842# define XXX(_name) do { hAddr = &_name; hName = #_name; } while (0)
sewardj464efa42004-11-19 22:17:29 +00004843
sewardj464efa42004-11-19 22:17:29 +00004844 switch (opc) {
sewardjb5452082004-12-04 20:33:02 +00004845 /* Original MMX ones */
sewardj38a3f862005-01-13 15:06:51 +00004846 case 0xFC: op = Iop_Add8x8; break;
4847 case 0xFD: op = Iop_Add16x4; break;
4848 case 0xFE: op = Iop_Add32x2; break;
sewardj464efa42004-11-19 22:17:29 +00004849
sewardj38a3f862005-01-13 15:06:51 +00004850 case 0xEC: op = Iop_QAdd8Sx8; break;
4851 case 0xED: op = Iop_QAdd16Sx4; break;
sewardj464efa42004-11-19 22:17:29 +00004852
sewardj38a3f862005-01-13 15:06:51 +00004853 case 0xDC: op = Iop_QAdd8Ux8; break;
4854 case 0xDD: op = Iop_QAdd16Ux4; break;
sewardj464efa42004-11-19 22:17:29 +00004855
sewardj38a3f862005-01-13 15:06:51 +00004856 case 0xF8: op = Iop_Sub8x8; break;
4857 case 0xF9: op = Iop_Sub16x4; break;
4858 case 0xFA: op = Iop_Sub32x2; break;
sewardj464efa42004-11-19 22:17:29 +00004859
sewardj38a3f862005-01-13 15:06:51 +00004860 case 0xE8: op = Iop_QSub8Sx8; break;
4861 case 0xE9: op = Iop_QSub16Sx4; break;
sewardj464efa42004-11-19 22:17:29 +00004862
sewardj38a3f862005-01-13 15:06:51 +00004863 case 0xD8: op = Iop_QSub8Ux8; break;
4864 case 0xD9: op = Iop_QSub16Ux4; break;
sewardj464efa42004-11-19 22:17:29 +00004865
sewardj38a3f862005-01-13 15:06:51 +00004866 case 0xE5: op = Iop_MulHi16Sx4; break;
4867 case 0xD5: op = Iop_Mul16x4; break;
4868 case 0xF5: XXX(x86g_calculate_mmx_pmaddwd); break;
sewardj4340dac2004-11-20 13:17:04 +00004869
sewardj38a3f862005-01-13 15:06:51 +00004870 case 0x74: op = Iop_CmpEQ8x8; break;
4871 case 0x75: op = Iop_CmpEQ16x4; break;
4872 case 0x76: op = Iop_CmpEQ32x2; break;
sewardj4340dac2004-11-20 13:17:04 +00004873
sewardj38a3f862005-01-13 15:06:51 +00004874 case 0x64: op = Iop_CmpGT8Sx8; break;
4875 case 0x65: op = Iop_CmpGT16Sx4; break;
4876 case 0x66: op = Iop_CmpGT32Sx2; break;
sewardj63ba4092004-11-21 12:30:18 +00004877
sewardj38a3f862005-01-13 15:06:51 +00004878 case 0x6B: op = Iop_QNarrow32Sx2; eLeft = True; break;
4879 case 0x63: op = Iop_QNarrow16Sx4; eLeft = True; break;
4880 case 0x67: op = Iop_QNarrow16Ux4; eLeft = True; break;
sewardj63ba4092004-11-21 12:30:18 +00004881
sewardj38a3f862005-01-13 15:06:51 +00004882 case 0x68: op = Iop_InterleaveHI8x8; eLeft = True; break;
4883 case 0x69: op = Iop_InterleaveHI16x4; eLeft = True; break;
4884 case 0x6A: op = Iop_InterleaveHI32x2; eLeft = True; break;
sewardj63ba4092004-11-21 12:30:18 +00004885
sewardj38a3f862005-01-13 15:06:51 +00004886 case 0x60: op = Iop_InterleaveLO8x8; eLeft = True; break;
4887 case 0x61: op = Iop_InterleaveLO16x4; eLeft = True; break;
4888 case 0x62: op = Iop_InterleaveLO32x2; eLeft = True; break;
sewardj63ba4092004-11-21 12:30:18 +00004889
sewardj38a3f862005-01-13 15:06:51 +00004890 case 0xDB: op = Iop_And64; break;
4891 case 0xDF: op = Iop_And64; invG = True; break;
4892 case 0xEB: op = Iop_Or64; break;
4893 case 0xEF: /* Possibly do better here if argL and argR are the
4894 same reg */
4895 op = Iop_Xor64; break;
sewardj464efa42004-11-19 22:17:29 +00004896
sewardjb5452082004-12-04 20:33:02 +00004897 /* Introduced in SSE1 */
sewardj38a3f862005-01-13 15:06:51 +00004898 case 0xE0: op = Iop_Avg8Ux8; break;
4899 case 0xE3: op = Iop_Avg16Ux4; break;
4900 case 0xEE: op = Iop_Max16Sx4; break;
4901 case 0xDE: op = Iop_Max8Ux8; break;
4902 case 0xEA: op = Iop_Min16Sx4; break;
4903 case 0xDA: op = Iop_Min8Ux8; break;
4904 case 0xE4: op = Iop_MulHi16Ux4; break;
4905 case 0xF6: XXX(x86g_calculate_mmx_psadbw); break;
sewardjb5452082004-12-04 20:33:02 +00004906
sewardj164f9272004-12-09 00:39:32 +00004907 /* Introduced in SSE2 */
sewardj38a3f862005-01-13 15:06:51 +00004908 case 0xD4: op = Iop_Add64; break;
4909 case 0xFB: op = Iop_Sub64; break;
sewardj164f9272004-12-09 00:39:32 +00004910
sewardj464efa42004-11-19 22:17:29 +00004911 default:
4912 vex_printf("\n0x%x\n", (Int)opc);
4913 vpanic("dis_MMXop_regmem_to_reg");
4914 }
4915
4916# undef XXX
4917
sewardj38a3f862005-01-13 15:06:51 +00004918 argG = getMMXReg(gregOfRM(modrm));
4919 if (invG)
4920 argG = unop(Iop_Not64, argG);
sewardj63ba4092004-11-21 12:30:18 +00004921
sewardj464efa42004-11-19 22:17:29 +00004922 if (isReg) {
sewardj464efa42004-11-19 22:17:29 +00004923 delta++;
sewardj38a3f862005-01-13 15:06:51 +00004924 argE = getMMXReg(eregOfRM(modrm));
sewardj464efa42004-11-19 22:17:29 +00004925 } else {
4926 Int len;
4927 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
4928 delta += len;
sewardj38a3f862005-01-13 15:06:51 +00004929 argE = loadLE(Ity_I64, mkexpr(addr));
sewardj464efa42004-11-19 22:17:29 +00004930 }
4931
sewardj38a3f862005-01-13 15:06:51 +00004932 if (eLeft) {
4933 argL = argE;
4934 argR = argG;
4935 } else {
4936 argL = argG;
4937 argR = argE;
4938 }
4939
4940 if (op != Iop_INVALID) {
4941 vassert(hName == NULL);
4942 vassert(hAddr == NULL);
4943 assign(res, binop(op, argL, argR));
4944 } else {
4945 vassert(hName != NULL);
4946 vassert(hAddr != NULL);
4947 assign( res,
4948 mkIRExprCCall(
4949 Ity_I64,
4950 0/*regparms*/, hName, hAddr,
4951 mkIRExprVec_2( argL, argR )
4952 )
4953 );
sewardj63ba4092004-11-21 12:30:18 +00004954 }
4955
4956 putMMXReg( gregOfRM(modrm), mkexpr(res) );
4957
sewardj464efa42004-11-19 22:17:29 +00004958 DIP("%s%s %s, %s\n",
sewardj2d49b432005-02-01 00:37:06 +00004959 name, show_granularity ? nameMMXGran(opc & 3) : "",
sewardj464efa42004-11-19 22:17:29 +00004960 ( isReg ? nameMMXReg(eregOfRM(modrm)) : dis_buf ),
4961 nameMMXReg(gregOfRM(modrm)) );
4962
4963 return delta;
4964}
4965
4966
sewardj38a3f862005-01-13 15:06:51 +00004967/* Vector by scalar shift of G by the amount specified at the bottom
4968 of E. This is a straight copy of dis_SSE_shiftG_byE. */
4969
sewardj52d04912005-07-03 00:52:48 +00004970static UInt dis_MMX_shiftG_byE ( UChar sorb, Int delta,
sewardj38a3f862005-01-13 15:06:51 +00004971 HChar* opname, IROp op )
4972{
4973 HChar dis_buf[50];
4974 Int alen, size;
4975 IRTemp addr;
4976 Bool shl, shr, sar;
4977 UChar rm = getIByte(delta);
4978 IRTemp g0 = newTemp(Ity_I64);
4979 IRTemp g1 = newTemp(Ity_I64);
4980 IRTemp amt = newTemp(Ity_I32);
4981 IRTemp amt8 = newTemp(Ity_I8);
4982
4983 if (epartIsReg(rm)) {
4984 assign( amt, unop(Iop_64to32, getMMXReg(eregOfRM(rm))) );
4985 DIP("%s %s,%s\n", opname,
4986 nameMMXReg(eregOfRM(rm)),
4987 nameMMXReg(gregOfRM(rm)) );
4988 delta++;
4989 } else {
4990 addr = disAMode ( &alen, sorb, delta, dis_buf );
4991 assign( amt, loadLE(Ity_I32, mkexpr(addr)) );
4992 DIP("%s %s,%s\n", opname,
4993 dis_buf,
4994 nameMMXReg(gregOfRM(rm)) );
4995 delta += alen;
4996 }
4997 assign( g0, getMMXReg(gregOfRM(rm)) );
4998 assign( amt8, unop(Iop_32to8, mkexpr(amt)) );
4999
5000 shl = shr = sar = False;
5001 size = 0;
5002 switch (op) {
5003 case Iop_ShlN16x4: shl = True; size = 32; break;
5004 case Iop_ShlN32x2: shl = True; size = 32; break;
5005 case Iop_Shl64: shl = True; size = 64; break;
5006 case Iop_ShrN16x4: shr = True; size = 16; break;
5007 case Iop_ShrN32x2: shr = True; size = 32; break;
5008 case Iop_Shr64: shr = True; size = 64; break;
5009 case Iop_SarN16x4: sar = True; size = 16; break;
5010 case Iop_SarN32x2: sar = True; size = 32; break;
5011 default: vassert(0);
5012 }
5013
5014 if (shl || shr) {
5015 assign(
5016 g1,
5017 IRExpr_Mux0X(
5018 unop(Iop_1Uto8,binop(Iop_CmpLT32U,mkexpr(amt),mkU32(size))),
5019 mkU64(0),
5020 binop(op, mkexpr(g0), mkexpr(amt8))
5021 )
5022 );
5023 } else
5024 if (sar) {
5025 assign(
5026 g1,
5027 IRExpr_Mux0X(
5028 unop(Iop_1Uto8,binop(Iop_CmpLT32U,mkexpr(amt),mkU32(size))),
5029 binop(op, mkexpr(g0), mkU8(size-1)),
5030 binop(op, mkexpr(g0), mkexpr(amt8))
5031 )
5032 );
5033 } else {
sewardjba89f4c2005-04-07 17:31:27 +00005034 /*NOTREACHED*/
sewardj38a3f862005-01-13 15:06:51 +00005035 vassert(0);
5036 }
5037
5038 putMMXReg( gregOfRM(rm), mkexpr(g1) );
5039 return delta;
5040}
5041
5042
5043/* Vector by scalar shift of E by an immediate byte. This is a
5044 straight copy of dis_SSE_shiftE_imm. */
5045
5046static
sewardj52d04912005-07-03 00:52:48 +00005047UInt dis_MMX_shiftE_imm ( Int delta, HChar* opname, IROp op )
sewardj38a3f862005-01-13 15:06:51 +00005048{
5049 Bool shl, shr, sar;
5050 UChar rm = getIByte(delta);
5051 IRTemp e0 = newTemp(Ity_I64);
5052 IRTemp e1 = newTemp(Ity_I64);
5053 UChar amt, size;
5054 vassert(epartIsReg(rm));
5055 vassert(gregOfRM(rm) == 2
5056 || gregOfRM(rm) == 4 || gregOfRM(rm) == 6);
sewardj2d49b432005-02-01 00:37:06 +00005057 amt = getIByte(delta+1);
sewardj38a3f862005-01-13 15:06:51 +00005058 delta += 2;
5059 DIP("%s $%d,%s\n", opname,
5060 (Int)amt,
5061 nameMMXReg(eregOfRM(rm)) );
5062
5063 assign( e0, getMMXReg(eregOfRM(rm)) );
5064
5065 shl = shr = sar = False;
5066 size = 0;
5067 switch (op) {
5068 case Iop_ShlN16x4: shl = True; size = 16; break;
5069 case Iop_ShlN32x2: shl = True; size = 32; break;
5070 case Iop_Shl64: shl = True; size = 64; break;
5071 case Iop_SarN16x4: sar = True; size = 16; break;
5072 case Iop_SarN32x2: sar = True; size = 32; break;
5073 case Iop_ShrN16x4: shr = True; size = 16; break;
5074 case Iop_ShrN32x2: shr = True; size = 32; break;
5075 case Iop_Shr64: shr = True; size = 64; break;
5076 default: vassert(0);
5077 }
5078
5079 if (shl || shr) {
sewardjba89f4c2005-04-07 17:31:27 +00005080 assign( e1, amt >= size
5081 ? mkU64(0)
5082 : binop(op, mkexpr(e0), mkU8(amt))
5083 );
sewardj38a3f862005-01-13 15:06:51 +00005084 } else
5085 if (sar) {
sewardjba89f4c2005-04-07 17:31:27 +00005086 assign( e1, amt >= size
5087 ? binop(op, mkexpr(e0), mkU8(size-1))
5088 : binop(op, mkexpr(e0), mkU8(amt))
5089 );
sewardj38a3f862005-01-13 15:06:51 +00005090 } else {
sewardjba89f4c2005-04-07 17:31:27 +00005091 /*NOTREACHED*/
sewardj38a3f862005-01-13 15:06:51 +00005092 vassert(0);
5093 }
5094
5095 putMMXReg( eregOfRM(rm), mkexpr(e1) );
5096 return delta;
5097}
5098
5099
5100/* Completely handle all MMX instructions except emms. */
sewardj464efa42004-11-19 22:17:29 +00005101
5102static
sewardj52d04912005-07-03 00:52:48 +00005103UInt dis_MMX ( Bool* decode_ok, UChar sorb, Int sz, Int delta )
sewardj464efa42004-11-19 22:17:29 +00005104{
5105 Int len;
5106 UChar modrm;
sewardjc9a43662004-11-30 18:51:59 +00005107 HChar dis_buf[50];
sewardj464efa42004-11-19 22:17:29 +00005108 UChar opc = getIByte(delta);
5109 delta++;
5110
sewardj4cb918d2004-12-03 19:43:31 +00005111 /* dis_MMX handles all insns except emms. */
5112 do_MMX_preamble();
sewardj464efa42004-11-19 22:17:29 +00005113
5114 switch (opc) {
5115
sewardj2b7a9202004-11-26 19:15:38 +00005116 case 0x6E:
5117 /* MOVD (src)ireg-or-mem (E), (dst)mmxreg (G)*/
sewardj9df271d2004-12-31 22:37:42 +00005118 if (sz != 4)
5119 goto mmx_decode_failure;
sewardj2b7a9202004-11-26 19:15:38 +00005120 modrm = getIByte(delta);
5121 if (epartIsReg(modrm)) {
5122 delta++;
5123 putMMXReg(
5124 gregOfRM(modrm),
5125 binop( Iop_32HLto64,
5126 mkU32(0),
5127 getIReg(4, eregOfRM(modrm)) ) );
5128 DIP("movd %s, %s\n",
5129 nameIReg(4,eregOfRM(modrm)), nameMMXReg(gregOfRM(modrm)));
5130 } else {
5131 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5132 delta += len;
5133 putMMXReg(
5134 gregOfRM(modrm),
5135 binop( Iop_32HLto64,
5136 mkU32(0),
5137 loadLE(Ity_I32, mkexpr(addr)) ) );
5138 DIP("movd %s, %s\n", dis_buf, nameMMXReg(gregOfRM(modrm)));
5139 }
5140 break;
5141
5142 case 0x7E: /* MOVD (src)mmxreg (G), (dst)ireg-or-mem (E) */
sewardj9df271d2004-12-31 22:37:42 +00005143 if (sz != 4)
5144 goto mmx_decode_failure;
sewardj2b7a9202004-11-26 19:15:38 +00005145 modrm = getIByte(delta);
5146 if (epartIsReg(modrm)) {
5147 delta++;
5148 putIReg( 4, eregOfRM(modrm),
5149 unop(Iop_64to32, getMMXReg(gregOfRM(modrm)) ) );
5150 DIP("movd %s, %s\n",
5151 nameMMXReg(gregOfRM(modrm)), nameIReg(4,eregOfRM(modrm)));
5152 } else {
5153 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5154 delta += len;
5155 storeLE( mkexpr(addr),
5156 unop(Iop_64to32, getMMXReg(gregOfRM(modrm)) ) );
5157 DIP("movd %s, %s\n", nameMMXReg(gregOfRM(modrm)), dis_buf);
5158 }
5159 break;
5160
sewardj464efa42004-11-19 22:17:29 +00005161 case 0x6F:
5162 /* MOVQ (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005163 if (sz != 4)
5164 goto mmx_decode_failure;
sewardj464efa42004-11-19 22:17:29 +00005165 modrm = getIByte(delta);
5166 if (epartIsReg(modrm)) {
5167 delta++;
5168 putMMXReg( gregOfRM(modrm), getMMXReg(eregOfRM(modrm)) );
5169 DIP("movq %s, %s\n",
5170 nameMMXReg(eregOfRM(modrm)), nameMMXReg(gregOfRM(modrm)));
5171 } else {
5172 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5173 delta += len;
5174 putMMXReg( gregOfRM(modrm), loadLE(Ity_I64, mkexpr(addr)) );
5175 DIP("movq %s, %s\n",
5176 dis_buf, nameMMXReg(gregOfRM(modrm)));
5177 }
5178 break;
5179
5180 case 0x7F:
5181 /* MOVQ (src)mmxreg, (dst)mmxreg-or-mem */
sewardj9df271d2004-12-31 22:37:42 +00005182 if (sz != 4)
5183 goto mmx_decode_failure;
sewardj464efa42004-11-19 22:17:29 +00005184 modrm = getIByte(delta);
5185 if (epartIsReg(modrm)) {
sewardjc2feffc2004-12-08 12:31:22 +00005186 /* Fall through. The assembler doesn't appear to generate
5187 these. */
5188 goto mmx_decode_failure;
sewardj464efa42004-11-19 22:17:29 +00005189 } else {
5190 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5191 delta += len;
sewardj893aada2004-11-29 19:57:54 +00005192 storeLE( mkexpr(addr), getMMXReg(gregOfRM(modrm)) );
sewardj464efa42004-11-19 22:17:29 +00005193 DIP("mov(nt)q %s, %s\n",
5194 nameMMXReg(gregOfRM(modrm)), dis_buf);
5195 }
5196 break;
5197
sewardj4340dac2004-11-20 13:17:04 +00005198 case 0xFC:
5199 case 0xFD:
5200 case 0xFE: /* PADDgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005201 if (sz != 4)
5202 goto mmx_decode_failure;
sewardj464efa42004-11-19 22:17:29 +00005203 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "padd", True );
5204 break;
5205
sewardj4340dac2004-11-20 13:17:04 +00005206 case 0xEC:
5207 case 0xED: /* PADDSgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005208 if (sz != 4)
5209 goto mmx_decode_failure;
sewardj464efa42004-11-19 22:17:29 +00005210 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "padds", True );
5211 break;
5212
sewardj4340dac2004-11-20 13:17:04 +00005213 case 0xDC:
5214 case 0xDD: /* PADDUSgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005215 if (sz != 4)
5216 goto mmx_decode_failure;
sewardj464efa42004-11-19 22:17:29 +00005217 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "paddus", True );
5218 break;
5219
sewardj4340dac2004-11-20 13:17:04 +00005220 case 0xF8:
5221 case 0xF9:
5222 case 0xFA: /* PSUBgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005223 if (sz != 4)
5224 goto mmx_decode_failure;
sewardj464efa42004-11-19 22:17:29 +00005225 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "psub", True );
5226 break;
5227
sewardj4340dac2004-11-20 13:17:04 +00005228 case 0xE8:
5229 case 0xE9: /* PSUBSgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005230 if (sz != 4)
5231 goto mmx_decode_failure;
sewardj464efa42004-11-19 22:17:29 +00005232 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "psubs", True );
5233 break;
5234
sewardj4340dac2004-11-20 13:17:04 +00005235 case 0xD8:
5236 case 0xD9: /* PSUBUSgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005237 if (sz != 4)
5238 goto mmx_decode_failure;
sewardj464efa42004-11-19 22:17:29 +00005239 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "psubus", True );
5240 break;
5241
5242 case 0xE5: /* PMULHW (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005243 if (sz != 4)
5244 goto mmx_decode_failure;
sewardj464efa42004-11-19 22:17:29 +00005245 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pmulhw", False );
5246 break;
5247
5248 case 0xD5: /* PMULLW (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005249 if (sz != 4)
5250 goto mmx_decode_failure;
sewardj464efa42004-11-19 22:17:29 +00005251 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pmullw", False );
5252 break;
5253
sewardj4340dac2004-11-20 13:17:04 +00005254 case 0xF5: /* PMADDWD (src)mmxreg-or-mem, (dst)mmxreg */
5255 vassert(sz == 4);
5256 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pmaddwd", False );
5257 break;
5258
5259 case 0x74:
5260 case 0x75:
5261 case 0x76: /* PCMPEQgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005262 if (sz != 4)
5263 goto mmx_decode_failure;
sewardj4340dac2004-11-20 13:17:04 +00005264 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pcmpeq", True );
5265 break;
5266
5267 case 0x64:
5268 case 0x65:
5269 case 0x66: /* PCMPGTgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005270 if (sz != 4)
5271 goto mmx_decode_failure;
sewardj4340dac2004-11-20 13:17:04 +00005272 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pcmpgt", True );
5273 break;
5274
sewardj63ba4092004-11-21 12:30:18 +00005275 case 0x6B: /* PACKSSDW (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005276 if (sz != 4)
5277 goto mmx_decode_failure;
sewardj63ba4092004-11-21 12:30:18 +00005278 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "packssdw", False );
5279 break;
5280
5281 case 0x63: /* PACKSSWB (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005282 if (sz != 4)
5283 goto mmx_decode_failure;
sewardj63ba4092004-11-21 12:30:18 +00005284 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "packsswb", False );
5285 break;
5286
5287 case 0x67: /* PACKUSWB (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005288 if (sz != 4)
5289 goto mmx_decode_failure;
sewardj63ba4092004-11-21 12:30:18 +00005290 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "packuswb", False );
5291 break;
5292
5293 case 0x68:
5294 case 0x69:
5295 case 0x6A: /* PUNPCKHgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005296 if (sz != 4)
5297 goto mmx_decode_failure;
sewardj63ba4092004-11-21 12:30:18 +00005298 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "punpckh", True );
5299 break;
5300
5301 case 0x60:
5302 case 0x61:
5303 case 0x62: /* PUNPCKLgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005304 if (sz != 4)
5305 goto mmx_decode_failure;
sewardj63ba4092004-11-21 12:30:18 +00005306 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "punpckl", True );
5307 break;
5308
5309 case 0xDB: /* PAND (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005310 if (sz != 4)
5311 goto mmx_decode_failure;
sewardj63ba4092004-11-21 12:30:18 +00005312 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pand", False );
5313 break;
5314
5315 case 0xDF: /* PANDN (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005316 if (sz != 4)
5317 goto mmx_decode_failure;
sewardj63ba4092004-11-21 12:30:18 +00005318 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pandn", False );
5319 break;
5320
5321 case 0xEB: /* POR (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005322 if (sz != 4)
5323 goto mmx_decode_failure;
sewardj63ba4092004-11-21 12:30:18 +00005324 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "por", False );
5325 break;
5326
5327 case 0xEF: /* PXOR (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005328 if (sz != 4)
5329 goto mmx_decode_failure;
sewardj63ba4092004-11-21 12:30:18 +00005330 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pxor", False );
sewardj38a3f862005-01-13 15:06:51 +00005331 break;
sewardj63ba4092004-11-21 12:30:18 +00005332
sewardj38a3f862005-01-13 15:06:51 +00005333# define SHIFT_BY_REG(_name,_op) \
5334 delta = dis_MMX_shiftG_byE(sorb, delta, _name, _op); \
5335 break;
sewardj8d14a592004-11-21 17:04:50 +00005336
sewardj38a3f862005-01-13 15:06:51 +00005337 /* PSLLgg (src)mmxreg-or-mem, (dst)mmxreg */
5338 case 0xF1: SHIFT_BY_REG("psllw", Iop_ShlN16x4);
5339 case 0xF2: SHIFT_BY_REG("pslld", Iop_ShlN32x2);
5340 case 0xF3: SHIFT_BY_REG("psllq", Iop_Shl64);
sewardj8d14a592004-11-21 17:04:50 +00005341
sewardj38a3f862005-01-13 15:06:51 +00005342 /* PSRLgg (src)mmxreg-or-mem, (dst)mmxreg */
5343 case 0xD1: SHIFT_BY_REG("psrlw", Iop_ShrN16x4);
5344 case 0xD2: SHIFT_BY_REG("psrld", Iop_ShrN32x2);
5345 case 0xD3: SHIFT_BY_REG("psrlq", Iop_Shr64);
5346
5347 /* PSRAgg (src)mmxreg-or-mem, (dst)mmxreg */
5348 case 0xE1: SHIFT_BY_REG("psraw", Iop_SarN16x4);
5349 case 0xE2: SHIFT_BY_REG("psrad", Iop_SarN32x2);
5350
5351# undef SHIFT_BY_REG
sewardj8d14a592004-11-21 17:04:50 +00005352
sewardj2b7a9202004-11-26 19:15:38 +00005353 case 0x71:
5354 case 0x72:
5355 case 0x73: {
5356 /* (sz==4): PSLLgg/PSRAgg/PSRLgg mmxreg by imm8 */
sewardja8415ff2005-01-21 20:55:36 +00005357 UChar byte2, subopc;
sewardj38a3f862005-01-13 15:06:51 +00005358 if (sz != 4)
5359 goto mmx_decode_failure;
sewardj38a3f862005-01-13 15:06:51 +00005360 byte2 = getIByte(delta); /* amode / sub-opcode */
sewardj9b45b482005-02-07 01:42:18 +00005361 subopc = toUChar( (byte2 >> 3) & 7 );
sewardj2b7a9202004-11-26 19:15:38 +00005362
sewardj38a3f862005-01-13 15:06:51 +00005363# define SHIFT_BY_IMM(_name,_op) \
5364 do { delta = dis_MMX_shiftE_imm(delta,_name,_op); \
5365 } while (0)
sewardj2b7a9202004-11-26 19:15:38 +00005366
sewardj2b7a9202004-11-26 19:15:38 +00005367 if (subopc == 2 /*SRL*/ && opc == 0x71)
sewardj38a3f862005-01-13 15:06:51 +00005368 SHIFT_BY_IMM("psrlw", Iop_ShrN16x4);
sewardj2b7a9202004-11-26 19:15:38 +00005369 else if (subopc == 2 /*SRL*/ && opc == 0x72)
sewardj38a3f862005-01-13 15:06:51 +00005370 SHIFT_BY_IMM("psrld", Iop_ShrN32x2);
sewardj2b7a9202004-11-26 19:15:38 +00005371 else if (subopc == 2 /*SRL*/ && opc == 0x73)
sewardj38a3f862005-01-13 15:06:51 +00005372 SHIFT_BY_IMM("psrlq", Iop_Shr64);
sewardj2b7a9202004-11-26 19:15:38 +00005373
5374 else if (subopc == 4 /*SAR*/ && opc == 0x71)
sewardj38a3f862005-01-13 15:06:51 +00005375 SHIFT_BY_IMM("psraw", Iop_SarN16x4);
sewardj2b7a9202004-11-26 19:15:38 +00005376 else if (subopc == 4 /*SAR*/ && opc == 0x72)
sewardj38a3f862005-01-13 15:06:51 +00005377 SHIFT_BY_IMM("psrad", Iop_SarN32x2);
sewardj2b7a9202004-11-26 19:15:38 +00005378
5379 else if (subopc == 6 /*SHL*/ && opc == 0x71)
sewardj38a3f862005-01-13 15:06:51 +00005380 SHIFT_BY_IMM("psllw", Iop_ShlN16x4);
sewardj2b7a9202004-11-26 19:15:38 +00005381 else if (subopc == 6 /*SHL*/ && opc == 0x72)
sewardj38a3f862005-01-13 15:06:51 +00005382 SHIFT_BY_IMM("pslld", Iop_ShlN32x2);
sewardj2b7a9202004-11-26 19:15:38 +00005383 else if (subopc == 6 /*SHL*/ && opc == 0x73)
sewardj38a3f862005-01-13 15:06:51 +00005384 SHIFT_BY_IMM("psllq", Iop_Shl64);
sewardj2b7a9202004-11-26 19:15:38 +00005385
5386 else goto mmx_decode_failure;
5387
sewardj38a3f862005-01-13 15:06:51 +00005388# undef SHIFT_BY_IMM
sewardj2b7a9202004-11-26 19:15:38 +00005389 break;
5390 }
5391
5392 /* --- MMX decode failure --- */
sewardj464efa42004-11-19 22:17:29 +00005393 default:
sewardj2b7a9202004-11-26 19:15:38 +00005394 mmx_decode_failure:
sewardj464efa42004-11-19 22:17:29 +00005395 *decode_ok = False;
5396 return delta; /* ignored */
5397
5398 }
5399
5400 *decode_ok = True;
5401 return delta;
5402}
5403
5404
5405/*------------------------------------------------------------*/
5406/*--- More misc arithmetic and other obscure insns. ---*/
5407/*------------------------------------------------------------*/
sewardja06e5562004-07-14 13:18:05 +00005408
5409/* Double length left and right shifts. Apparently only required in
5410 v-size (no b- variant). */
5411static
5412UInt dis_SHLRD_Gv_Ev ( UChar sorb,
sewardj52d04912005-07-03 00:52:48 +00005413 Int delta, UChar modrm,
sewardja06e5562004-07-14 13:18:05 +00005414 Int sz,
5415 IRExpr* shift_amt,
5416 Bool amt_is_literal,
sewardj2d49b432005-02-01 00:37:06 +00005417 HChar* shift_amt_txt,
sewardja06e5562004-07-14 13:18:05 +00005418 Bool left_shift )
5419{
5420 /* shift_amt :: Ity_I8 is the amount to shift. shift_amt_txt is used
5421 for printing it. And eip on entry points at the modrm byte. */
5422 Int len;
sewardjc9a43662004-11-30 18:51:59 +00005423 HChar dis_buf[50];
sewardja06e5562004-07-14 13:18:05 +00005424
sewardj6d2638e2004-07-15 09:38:27 +00005425 IRType ty = szToITy(sz);
5426 IRTemp gsrc = newTemp(ty);
5427 IRTemp esrc = newTemp(ty);
sewardj92d168d2004-11-15 14:22:12 +00005428 IRTemp addr = IRTemp_INVALID;
sewardj6d2638e2004-07-15 09:38:27 +00005429 IRTemp tmpSH = newTemp(Ity_I8);
sewardj92d168d2004-11-15 14:22:12 +00005430 IRTemp tmpL = IRTemp_INVALID;
5431 IRTemp tmpRes = IRTemp_INVALID;
5432 IRTemp tmpSubSh = IRTemp_INVALID;
sewardja06e5562004-07-14 13:18:05 +00005433 IROp mkpair;
5434 IROp getres;
5435 IROp shift;
sewardja06e5562004-07-14 13:18:05 +00005436 IRExpr* mask = NULL;
5437
5438 vassert(sz == 2 || sz == 4);
5439
5440 /* The E-part is the destination; this is shifted. The G-part
5441 supplies bits to be shifted into the E-part, but is not
5442 changed.
5443
5444 If shifting left, form a double-length word with E at the top
5445 and G at the bottom, and shift this left. The result is then in
5446 the high part.
5447
5448 If shifting right, form a double-length word with G at the top
5449 and E at the bottom, and shift this right. The result is then
5450 at the bottom. */
5451
5452 /* Fetch the operands. */
5453
5454 assign( gsrc, getIReg(sz, gregOfRM(modrm)) );
5455
5456 if (epartIsReg(modrm)) {
5457 delta++;
5458 assign( esrc, getIReg(sz, eregOfRM(modrm)) );
sewardj68511542004-07-28 00:15:44 +00005459 DIP("sh%cd%c %s, %s, %s\n",
sewardja06e5562004-07-14 13:18:05 +00005460 ( left_shift ? 'l' : 'r' ), nameISize(sz),
sewardj68511542004-07-28 00:15:44 +00005461 shift_amt_txt,
sewardja06e5562004-07-14 13:18:05 +00005462 nameIReg(sz, gregOfRM(modrm)), nameIReg(sz, eregOfRM(modrm)));
5463 } else {
5464 addr = disAMode ( &len, sorb, delta, dis_buf );
5465 delta += len;
5466 assign( esrc, loadLE(ty, mkexpr(addr)) );
sewardj68511542004-07-28 00:15:44 +00005467 DIP("sh%cd%c %s, %s, %s\n",
5468 ( left_shift ? 'l' : 'r' ), nameISize(sz),
5469 shift_amt_txt,
5470 nameIReg(sz, gregOfRM(modrm)), dis_buf);
sewardja06e5562004-07-14 13:18:05 +00005471 }
5472
5473 /* Round up the relevant primops. */
5474
5475 if (sz == 4) {
5476 tmpL = newTemp(Ity_I64);
5477 tmpRes = newTemp(Ity_I32);
5478 tmpSubSh = newTemp(Ity_I32);
sewardje539a402004-07-14 18:24:17 +00005479 mkpair = Iop_32HLto64;
sewardj8c7f1ab2004-07-29 20:31:09 +00005480 getres = left_shift ? Iop_64HIto32 : Iop_64to32;
sewardje539a402004-07-14 18:24:17 +00005481 shift = left_shift ? Iop_Shl64 : Iop_Shr64;
5482 mask = mkU8(31);
sewardja06e5562004-07-14 13:18:05 +00005483 } else {
5484 /* sz == 2 */
sewardj8c7f1ab2004-07-29 20:31:09 +00005485 tmpL = newTemp(Ity_I32);
5486 tmpRes = newTemp(Ity_I16);
5487 tmpSubSh = newTemp(Ity_I16);
5488 mkpair = Iop_16HLto32;
5489 getres = left_shift ? Iop_32HIto16 : Iop_32to16;
5490 shift = left_shift ? Iop_Shl32 : Iop_Shr32;
5491 mask = mkU8(15);
sewardja06e5562004-07-14 13:18:05 +00005492 }
5493
5494 /* Do the shift, calculate the subshift value, and set
5495 the flag thunk. */
5496
sewardj8c7f1ab2004-07-29 20:31:09 +00005497 assign( tmpSH, binop(Iop_And8, shift_amt, mask) );
5498
sewardja06e5562004-07-14 13:18:05 +00005499 if (left_shift)
5500 assign( tmpL, binop(mkpair, mkexpr(esrc), mkexpr(gsrc)) );
5501 else
5502 assign( tmpL, binop(mkpair, mkexpr(gsrc), mkexpr(esrc)) );
5503
5504 assign( tmpRes, unop(getres, binop(shift, mkexpr(tmpL), mkexpr(tmpSH)) ) );
5505 assign( tmpSubSh,
5506 unop(getres,
5507 binop(shift,
5508 mkexpr(tmpL),
5509 binop(Iop_And8,
5510 binop(Iop_Sub8, mkexpr(tmpSH), mkU8(1) ),
5511 mask))) );
sewardja06e5562004-07-14 13:18:05 +00005512
sewardj2a2ba8b2004-11-08 13:14:06 +00005513 setFlags_DEP1_DEP2_shift ( left_shift ? Iop_Shl32 : Iop_Sar32,
5514 tmpRes, tmpSubSh, ty, tmpSH );
sewardja06e5562004-07-14 13:18:05 +00005515
5516 /* Put result back. */
5517
5518 if (epartIsReg(modrm)) {
5519 putIReg(sz, eregOfRM(modrm), mkexpr(tmpRes));
5520 } else {
5521 storeLE( mkexpr(addr), mkexpr(tmpRes) );
5522 }
5523
5524 if (amt_is_literal) delta++;
5525 return delta;
5526}
5527
5528
sewardj1c6f9912004-09-07 10:15:24 +00005529/* Handle BT/BTS/BTR/BTC Gv, Ev. Apparently b-size is not
5530 required. */
5531
5532typedef enum { BtOpNone, BtOpSet, BtOpReset, BtOpComp } BtOp;
5533
sewardj2d49b432005-02-01 00:37:06 +00005534static HChar* nameBtOp ( BtOp op )
sewardj1c6f9912004-09-07 10:15:24 +00005535{
5536 switch (op) {
5537 case BtOpNone: return "";
5538 case BtOpSet: return "s";
5539 case BtOpReset: return "r";
5540 case BtOpComp: return "c";
5541 default: vpanic("nameBtOp(x86)");
5542 }
5543}
5544
5545
5546static
sewardj52d04912005-07-03 00:52:48 +00005547UInt dis_bt_G_E ( UChar sorb, Int sz, Int delta, BtOp op )
sewardj1c6f9912004-09-07 10:15:24 +00005548{
sewardjc9a43662004-11-30 18:51:59 +00005549 HChar dis_buf[50];
sewardj1c6f9912004-09-07 10:15:24 +00005550 UChar modrm;
5551 Int len;
5552 IRTemp t_fetched, t_bitno0, t_bitno1, t_bitno2, t_addr0,
5553 t_addr1, t_esp, t_mask;
5554
5555 vassert(sz == 2 || sz == 4);
5556
5557 t_fetched = t_bitno0 = t_bitno1 = t_bitno2
sewardj92d168d2004-11-15 14:22:12 +00005558 = t_addr0 = t_addr1 = t_esp = t_mask = IRTemp_INVALID;
sewardj1c6f9912004-09-07 10:15:24 +00005559
5560 t_fetched = newTemp(Ity_I8);
5561 t_bitno0 = newTemp(Ity_I32);
5562 t_bitno1 = newTemp(Ity_I32);
5563 t_bitno2 = newTemp(Ity_I8);
5564 t_addr1 = newTemp(Ity_I32);
5565 modrm = getIByte(delta);
5566
5567 assign( t_bitno0, widenUto32(getIReg(sz, gregOfRM(modrm))) );
5568
5569 if (epartIsReg(modrm)) {
sewardj1c6f9912004-09-07 10:15:24 +00005570 delta++;
5571 /* Get it onto the client's stack. */
5572 t_esp = newTemp(Ity_I32);
5573 t_addr0 = newTemp(Ity_I32);
5574
5575 assign( t_esp, binop(Iop_Sub32, getIReg(4, R_ESP), mkU32(sz)) );
5576 putIReg(4, R_ESP, mkexpr(t_esp));
5577
5578 storeLE( mkexpr(t_esp), getIReg(sz, eregOfRM(modrm)) );
5579
5580 /* Make t_addr0 point at it. */
5581 assign( t_addr0, mkexpr(t_esp) );
5582
5583 /* Mask out upper bits of the shift amount, since we're doing a
5584 reg. */
5585 assign( t_bitno1, binop(Iop_And32,
5586 mkexpr(t_bitno0),
5587 mkU32(sz == 4 ? 31 : 15)) );
5588
5589 } else {
5590 t_addr0 = disAMode ( &len, sorb, delta, dis_buf );
5591 delta += len;
5592 assign( t_bitno1, mkexpr(t_bitno0) );
5593 }
5594
5595 /* At this point: t_addr0 is the address being operated on. If it
5596 was a reg, we will have pushed it onto the client's stack.
5597 t_bitno1 is the bit number, suitably masked in the case of a
5598 reg. */
5599
5600 /* Now the main sequence. */
5601 assign( t_addr1,
5602 binop(Iop_Add32,
5603 mkexpr(t_addr0),
5604 binop(Iop_Sar32, mkexpr(t_bitno1), mkU8(3))) );
5605
5606 /* t_addr1 now holds effective address */
5607
5608 assign( t_bitno2,
5609 unop(Iop_32to8,
5610 binop(Iop_And32, mkexpr(t_bitno1), mkU32(7))) );
5611
5612 /* t_bitno2 contains offset of bit within byte */
5613
5614 if (op != BtOpNone) {
5615 t_mask = newTemp(Ity_I8);
5616 assign( t_mask, binop(Iop_Shl8, mkU8(1), mkexpr(t_bitno2)) );
5617 }
sewardj4963a422004-10-14 23:34:03 +00005618
sewardj1c6f9912004-09-07 10:15:24 +00005619 /* t_mask is now a suitable byte mask */
5620
5621 assign( t_fetched, loadLE(Ity_I8, mkexpr(t_addr1)) );
5622
5623 if (op != BtOpNone) {
5624 switch (op) {
5625 case BtOpSet:
5626 storeLE( mkexpr(t_addr1),
5627 binop(Iop_Or8, mkexpr(t_fetched),
5628 mkexpr(t_mask)) );
5629 break;
5630 case BtOpComp:
5631 storeLE( mkexpr(t_addr1),
5632 binop(Iop_Xor8, mkexpr(t_fetched),
5633 mkexpr(t_mask)) );
5634 break;
5635 case BtOpReset:
5636 storeLE( mkexpr(t_addr1),
5637 binop(Iop_And8, mkexpr(t_fetched),
5638 unop(Iop_Not8, mkexpr(t_mask))) );
5639 break;
5640 default:
5641 vpanic("dis_bt_G_E(x86)");
5642 }
5643 }
5644
5645 /* Side effect done; now get selected bit into Carry flag */
sewardj2a2ba8b2004-11-08 13:14:06 +00005646 /* Flags: C=selected bit, O,S,Z,A,P undefined, so are set to zero. */
sewardj2a9ad022004-11-25 02:46:58 +00005647 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
sewardj2a2ba8b2004-11-08 13:14:06 +00005648 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
sewardj1c6f9912004-09-07 10:15:24 +00005649 stmt( IRStmt_Put(
sewardj2a2ba8b2004-11-08 13:14:06 +00005650 OFFB_CC_DEP1,
sewardj1c6f9912004-09-07 10:15:24 +00005651 binop(Iop_And32,
5652 binop(Iop_Shr32,
5653 unop(Iop_8Uto32, mkexpr(t_fetched)),
sewardj5bd4d162004-11-10 13:02:48 +00005654 mkexpr(t_bitno2)),
5655 mkU32(1)))
sewardj1c6f9912004-09-07 10:15:24 +00005656 );
sewardja3b7e3a2005-04-05 01:54:19 +00005657 /* Set NDEP even though it isn't used. This makes redundant-PUT
5658 elimination of previous stores to this field work better. */
5659 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardj1c6f9912004-09-07 10:15:24 +00005660
5661 /* Move reg operand from stack back to reg */
5662 if (epartIsReg(modrm)) {
5663 /* t_esp still points at it. */
sewardj4963a422004-10-14 23:34:03 +00005664 putIReg(sz, eregOfRM(modrm), loadLE(szToITy(sz), mkexpr(t_esp)) );
sewardj1c6f9912004-09-07 10:15:24 +00005665 putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t_esp), mkU32(sz)) );
5666 }
5667
5668 DIP("bt%s%c %s, %s\n",
5669 nameBtOp(op), nameISize(sz), nameIReg(sz, gregOfRM(modrm)),
5670 ( epartIsReg(modrm) ? nameIReg(sz, eregOfRM(modrm)) : dis_buf ) );
5671
5672 return delta;
5673}
sewardjce646f22004-08-31 23:55:54 +00005674
5675
5676
5677/* Handle BSF/BSR. Only v-size seems necessary. */
5678static
sewardj52d04912005-07-03 00:52:48 +00005679UInt dis_bs_E_G ( UChar sorb, Int sz, Int delta, Bool fwds )
sewardjce646f22004-08-31 23:55:54 +00005680{
5681 Bool isReg;
5682 UChar modrm;
sewardjc9a43662004-11-30 18:51:59 +00005683 HChar dis_buf[50];
sewardjce646f22004-08-31 23:55:54 +00005684
5685 IRType ty = szToITy(sz);
5686 IRTemp src = newTemp(ty);
5687 IRTemp dst = newTemp(ty);
5688
5689 IRTemp src32 = newTemp(Ity_I32);
5690 IRTemp dst32 = newTemp(Ity_I32);
5691 IRTemp src8 = newTemp(Ity_I8);
5692
5693 vassert(sz == 4 || sz == 2);
sewardjce646f22004-08-31 23:55:54 +00005694
5695 modrm = getIByte(delta);
5696
5697 isReg = epartIsReg(modrm);
5698 if (isReg) {
5699 delta++;
5700 assign( src, getIReg(sz, eregOfRM(modrm)) );
5701 } else {
5702 Int len;
5703 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5704 delta += len;
5705 assign( src, loadLE(ty, mkexpr(addr)) );
5706 }
5707
5708 DIP("bs%c%c %s, %s\n",
5709 fwds ? 'f' : 'r', nameISize(sz),
5710 ( isReg ? nameIReg(sz, eregOfRM(modrm)) : dis_buf ),
5711 nameIReg(sz, gregOfRM(modrm)));
5712
5713 /* Generate an 8-bit expression which is zero iff the
5714 original is zero, and nonzero otherwise */
5715 assign( src8,
5716 unop(Iop_1Uto8, binop(mkSizedOp(ty,Iop_CmpNE8),
5717 mkexpr(src), mkU(ty,0))) );
5718
5719 /* Flags: Z is 1 iff source value is zero. All others
5720 are undefined -- we force them to zero. */
sewardj2a9ad022004-11-25 02:46:58 +00005721 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
sewardj2a2ba8b2004-11-08 13:14:06 +00005722 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
sewardjce646f22004-08-31 23:55:54 +00005723 stmt( IRStmt_Put(
sewardj2a2ba8b2004-11-08 13:14:06 +00005724 OFFB_CC_DEP1,
sewardjce646f22004-08-31 23:55:54 +00005725 IRExpr_Mux0X( mkexpr(src8),
5726 /* src==0 */
sewardj2a9ad022004-11-25 02:46:58 +00005727 mkU32(X86G_CC_MASK_Z),
sewardjce646f22004-08-31 23:55:54 +00005728 /* src!=0 */
5729 mkU32(0)
5730 )
5731 ));
sewardja3b7e3a2005-04-05 01:54:19 +00005732 /* Set NDEP even though it isn't used. This makes redundant-PUT
5733 elimination of previous stores to this field work better. */
5734 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardjce646f22004-08-31 23:55:54 +00005735
5736 /* Result: iff source value is zero, we can't use
5737 Iop_Clz32/Iop_Ctz32 as they have no defined result in that case.
5738 But anyway, Intel x86 semantics say the result is undefined in
5739 such situations. Hence handle the zero case specially. */
5740
5741 /* Bleh. What we compute:
5742
5743 bsf32: if src == 0 then 0 else Ctz32(src)
5744 bsr32: if src == 0 then 0 else 31 - Clz32(src)
5745
5746 bsf16: if src == 0 then 0 else Ctz32(16Uto32(src))
5747 bsr16: if src == 0 then 0 else 31 - Clz32(16Uto32(src))
5748
5749 First, widen src to 32 bits if it is not already.
sewardj37158712004-10-15 21:23:12 +00005750
5751 Postscript 15 Oct 04: it seems that at least VIA Nehemiah leaves the
5752 dst register unchanged when src == 0. Hence change accordingly.
sewardjce646f22004-08-31 23:55:54 +00005753 */
5754 if (sz == 2)
5755 assign( src32, unop(Iop_16Uto32, mkexpr(src)) );
5756 else
5757 assign( src32, mkexpr(src) );
5758
5759 /* The main computation, guarding against zero. */
5760 assign( dst32,
5761 IRExpr_Mux0X(
5762 mkexpr(src8),
sewardj37158712004-10-15 21:23:12 +00005763 /* src == 0 -- leave dst unchanged */
5764 widenUto32( getIReg( sz, gregOfRM(modrm) ) ),
sewardjce646f22004-08-31 23:55:54 +00005765 /* src != 0 */
5766 fwds ? unop(Iop_Ctz32, mkexpr(src32))
5767 : binop(Iop_Sub32,
5768 mkU32(31),
5769 unop(Iop_Clz32, mkexpr(src32)))
5770 )
5771 );
5772
5773 if (sz == 2)
5774 assign( dst, unop(Iop_32to16, mkexpr(dst32)) );
5775 else
5776 assign( dst, mkexpr(dst32) );
5777
5778 /* dump result back */
5779 putIReg( sz, gregOfRM(modrm), mkexpr(dst) );
5780
5781 return delta;
5782}
sewardj64e1d652004-07-12 14:00:46 +00005783
5784
5785static
5786void codegen_xchg_eAX_Reg ( Int sz, Int reg )
5787{
5788 IRType ty = szToITy(sz);
5789 IRTemp t1 = newTemp(ty);
5790 IRTemp t2 = newTemp(ty);
5791 vassert(sz == 2 || sz == 4);
5792 assign( t1, getIReg(sz, R_EAX) );
5793 assign( t2, getIReg(sz, reg) );
5794 putIReg( sz, R_EAX, mkexpr(t2) );
5795 putIReg( sz, reg, mkexpr(t1) );
5796 DIP("xchg%c %s, %s\n",
5797 nameISize(sz), nameIReg(sz, R_EAX), nameIReg(sz, reg));
5798}
5799
5800
sewardjbdc7d212004-09-09 02:46:40 +00005801static
5802void codegen_SAHF ( void )
5803{
5804 /* Set the flags to:
sewardj2a9ad022004-11-25 02:46:58 +00005805 (x86g_calculate_flags_all() & X86G_CC_MASK_O) -- retain the old O flag
5806 | (%AH & (X86G_CC_MASK_S|X86G_CC_MASK_Z|X86G_CC_MASK_A
5807 |X86G_CC_MASK_P|X86G_CC_MASK_C)
sewardjbdc7d212004-09-09 02:46:40 +00005808 */
sewardj2a9ad022004-11-25 02:46:58 +00005809 UInt mask_SZACP = X86G_CC_MASK_S|X86G_CC_MASK_Z|X86G_CC_MASK_A
5810 |X86G_CC_MASK_C|X86G_CC_MASK_P;
sewardjbdc7d212004-09-09 02:46:40 +00005811 IRTemp oldflags = newTemp(Ity_I32);
sewardj2a9ad022004-11-25 02:46:58 +00005812 assign( oldflags, mk_x86g_calculate_eflags_all() );
5813 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
sewardj2a2ba8b2004-11-08 13:14:06 +00005814 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
5815 stmt( IRStmt_Put( OFFB_CC_DEP1,
sewardjbdc7d212004-09-09 02:46:40 +00005816 binop(Iop_Or32,
sewardj2a9ad022004-11-25 02:46:58 +00005817 binop(Iop_And32, mkexpr(oldflags), mkU32(X86G_CC_MASK_O)),
sewardjbdc7d212004-09-09 02:46:40 +00005818 binop(Iop_And32,
5819 binop(Iop_Shr32, getIReg(4, R_EAX), mkU8(8)),
5820 mkU32(mask_SZACP))
5821 )
5822 ));
sewardja3b7e3a2005-04-05 01:54:19 +00005823 /* Set NDEP even though it isn't used. This makes redundant-PUT
5824 elimination of previous stores to this field work better. */
5825 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardjbdc7d212004-09-09 02:46:40 +00005826}
5827
5828
sewardjc9a65702004-07-07 16:32:57 +00005829//-- static
5830//-- void codegen_LAHF ( UCodeBlock* cb )
5831//-- {
5832//-- Int t = newTemp(cb);
5833//--
5834//-- /* Pushed arg is ignored, it just provides somewhere to put the
5835//-- return value. */
5836//-- uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, t);
5837//-- uInstr0(cb, CALLM_S, 0);
5838//-- uInstr1(cb, PUSH, 4, TempReg, t);
5839//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_LAHF));
5840//-- uFlagsRWU(cb, FlagsSZACP, FlagsEmpty, FlagsEmpty);
5841//-- uInstr1(cb, POP, 4, TempReg, t);
5842//-- uInstr0(cb, CALLM_E, 0);
5843//--
5844//-- /* At this point, the %ah sub-register in %eax has been updated,
5845//-- the rest is the same, so do a PUT of the whole thing. */
5846//-- uInstr2(cb, PUT, 4, TempReg, t, ArchReg, R_EAX);
5847//-- }
5848//--
sewardj458a6f82004-08-25 12:46:02 +00005849
5850static
5851UInt dis_cmpxchg_G_E ( UChar sorb,
5852 Int size,
sewardj52d04912005-07-03 00:52:48 +00005853 Int delta0 )
sewardj458a6f82004-08-25 12:46:02 +00005854{
sewardjc9a43662004-11-30 18:51:59 +00005855 HChar dis_buf[50];
sewardj458a6f82004-08-25 12:46:02 +00005856 Int len;
5857
5858 IRType ty = szToITy(size);
5859 IRTemp acc = newTemp(ty);
5860 IRTemp src = newTemp(ty);
sewardj2a2ba8b2004-11-08 13:14:06 +00005861 //IRTemp res = newTemp(ty);
sewardj458a6f82004-08-25 12:46:02 +00005862 IRTemp dest = newTemp(ty);
5863 IRTemp dest2 = newTemp(ty);
5864 IRTemp acc2 = newTemp(ty);
5865 IRTemp cond8 = newTemp(Ity_I8);
sewardj92d168d2004-11-15 14:22:12 +00005866 IRTemp addr = IRTemp_INVALID;
sewardj458a6f82004-08-25 12:46:02 +00005867 UChar rm = getUChar(delta0);
5868
5869 if (epartIsReg(rm)) {
5870 assign( dest, getIReg(size, eregOfRM(rm)) );
5871 delta0++;
5872 DIP("cmpxchg%c %s,%s\n", nameISize(size),
5873 nameIReg(size,gregOfRM(rm)),
5874 nameIReg(size,eregOfRM(rm)) );
sewardj458a6f82004-08-25 12:46:02 +00005875 } else {
5876 addr = disAMode ( &len, sorb, delta0, dis_buf );
5877 assign( dest, loadLE(ty, mkexpr(addr)) );
5878 delta0 += len;
5879 DIP("cmpxchg%c %s,%s\n", nameISize(size),
5880 nameIReg(size,gregOfRM(rm)), dis_buf);
5881 }
5882
5883 assign( src, getIReg(size, gregOfRM(rm)) );
5884 assign( acc, getIReg(size, R_EAX) );
sewardj2a2ba8b2004-11-08 13:14:06 +00005885 //assign( res, binop( mkSizedOp(ty,Iop_Sub8), mkexpr(acc), mkexpr(dest) ));
5886 setFlags_DEP1_DEP2(Iop_Sub8, acc, dest, ty);
sewardj2a9ad022004-11-25 02:46:58 +00005887 assign( cond8, unop(Iop_1Uto8, mk_x86g_calculate_condition(X86CondZ)) );
sewardj458a6f82004-08-25 12:46:02 +00005888 assign( dest2, IRExpr_Mux0X(mkexpr(cond8), mkexpr(dest), mkexpr(src)) );
5889 assign( acc2, IRExpr_Mux0X(mkexpr(cond8), mkexpr(dest), mkexpr(acc)) );
5890 putIReg(size, R_EAX, mkexpr(acc2));
5891
5892 if (epartIsReg(rm)) {
5893 putIReg(size, eregOfRM(rm), mkexpr(dest2));
5894 } else {
5895 storeLE( mkexpr(addr), mkexpr(dest2) );
5896 }
5897
5898 return delta0;
5899}
5900
5901
sewardjc9a65702004-07-07 16:32:57 +00005902//-- static
5903//-- Addr dis_cmpxchg8b ( UCodeBlock* cb,
5904//-- UChar sorb,
5905//-- Addr eip0 )
5906//-- {
5907//-- Int tal, tah, junkl, junkh, destl, desth, srcl, srch, accl, acch;
sewardjc9a43662004-11-30 18:51:59 +00005908//-- HChar dis_buf[50];
sewardjc9a65702004-07-07 16:32:57 +00005909//-- UChar rm;
5910//-- UInt pair;
5911//--
5912//-- rm = getUChar(eip0);
5913//-- accl = newTemp(cb);
5914//-- acch = newTemp(cb);
5915//-- srcl = newTemp(cb);
5916//-- srch = newTemp(cb);
5917//-- destl = newTemp(cb);
5918//-- desth = newTemp(cb);
5919//-- junkl = newTemp(cb);
5920//-- junkh = newTemp(cb);
5921//--
5922//-- vg_assert(!epartIsReg(rm));
5923//--
5924//-- pair = disAMode ( cb, sorb, eip0, dis_buf );
5925//-- tal = LOW24(pair);
5926//-- tah = newTemp(cb);
5927//-- uInstr2(cb, MOV, 4, TempReg, tal, TempReg, tah);
5928//-- uInstr2(cb, ADD, 4, Literal, 0, TempReg, tah);
5929//-- uLiteral(cb, 4);
5930//-- eip0 += HI8(pair);
5931//-- DIP("cmpxchg8b %s\n", dis_buf);
5932//--
5933//-- uInstr0(cb, CALLM_S, 0);
5934//--
5935//-- uInstr2(cb, LOAD, 4, TempReg, tah, TempReg, desth);
5936//-- uInstr1(cb, PUSH, 4, TempReg, desth);
5937//-- uInstr2(cb, LOAD, 4, TempReg, tal, TempReg, destl);
5938//-- uInstr1(cb, PUSH, 4, TempReg, destl);
5939//-- uInstr2(cb, GET, 4, ArchReg, R_ECX, TempReg, srch);
5940//-- uInstr1(cb, PUSH, 4, TempReg, srch);
5941//-- uInstr2(cb, GET, 4, ArchReg, R_EBX, TempReg, srcl);
5942//-- uInstr1(cb, PUSH, 4, TempReg, srcl);
5943//-- uInstr2(cb, GET, 4, ArchReg, R_EDX, TempReg, acch);
5944//-- uInstr1(cb, PUSH, 4, TempReg, acch);
5945//-- uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, accl);
5946//-- uInstr1(cb, PUSH, 4, TempReg, accl);
5947//--
5948//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_cmpxchg8b));
5949//-- uFlagsRWU(cb, FlagsEmpty, FlagZ, FlagsEmpty);
5950//--
5951//-- uInstr1(cb, POP, 4, TempReg, accl);
5952//-- uInstr2(cb, PUT, 4, TempReg, accl, ArchReg, R_EAX);
5953//-- uInstr1(cb, POP, 4, TempReg, acch);
5954//-- uInstr2(cb, PUT, 4, TempReg, acch, ArchReg, R_EDX);
5955//-- uInstr1(cb, POP, 4, TempReg, srcl);
5956//-- uInstr2(cb, PUT, 4, TempReg, srcl, ArchReg, R_EBX);
5957//-- uInstr1(cb, POP, 4, TempReg, srch);
5958//-- uInstr2(cb, PUT, 4, TempReg, srch, ArchReg, R_ECX);
5959//-- uInstr1(cb, POP, 4, TempReg, destl);
5960//-- uInstr2(cb, STORE, 4, TempReg, destl, TempReg, tal);
5961//-- uInstr1(cb, POP, 4, TempReg, desth);
5962//-- uInstr2(cb, STORE, 4, TempReg, desth, TempReg, tah);
5963//--
5964//-- uInstr0(cb, CALLM_E, 0);
5965//--
5966//-- return eip0;
5967//-- }
sewardj458a6f82004-08-25 12:46:02 +00005968
5969
5970/* Handle conditional move instructions of the form
5971 cmovcc E(reg-or-mem), G(reg)
5972
5973 E(src) is reg-or-mem
5974 G(dst) is reg.
5975
5976 If E is reg, --> GET %E, tmps
5977 GET %G, tmpd
5978 CMOVcc tmps, tmpd
5979 PUT tmpd, %G
5980
5981 If E is mem --> (getAddr E) -> tmpa
5982 LD (tmpa), tmps
5983 GET %G, tmpd
5984 CMOVcc tmps, tmpd
5985 PUT tmpd, %G
5986*/
5987static
5988UInt dis_cmov_E_G ( UChar sorb,
5989 Int sz,
sewardj2a9ad022004-11-25 02:46:58 +00005990 X86Condcode cond,
sewardj52d04912005-07-03 00:52:48 +00005991 Int delta0 )
sewardj458a6f82004-08-25 12:46:02 +00005992{
5993 UChar rm = getIByte(delta0);
sewardjc9a43662004-11-30 18:51:59 +00005994 HChar dis_buf[50];
sewardj458a6f82004-08-25 12:46:02 +00005995 Int len;
5996
sewardj883b00b2004-09-11 09:30:24 +00005997 IRType ty = szToITy(sz);
sewardj458a6f82004-08-25 12:46:02 +00005998 IRTemp tmps = newTemp(ty);
5999 IRTemp tmpd = newTemp(ty);
6000
6001 if (epartIsReg(rm)) {
6002 assign( tmps, getIReg(sz, eregOfRM(rm)) );
6003 assign( tmpd, getIReg(sz, gregOfRM(rm)) );
6004
6005 putIReg(sz, gregOfRM(rm),
sewardj2a9ad022004-11-25 02:46:58 +00006006 IRExpr_Mux0X( unop(Iop_1Uto8,
6007 mk_x86g_calculate_condition(cond)),
sewardj458a6f82004-08-25 12:46:02 +00006008 mkexpr(tmpd),
6009 mkexpr(tmps) )
6010 );
6011 DIP("cmov%c%s %s,%s\n", nameISize(sz),
sewardj2a9ad022004-11-25 02:46:58 +00006012 name_X86Condcode(cond),
sewardj458a6f82004-08-25 12:46:02 +00006013 nameIReg(sz,eregOfRM(rm)),
6014 nameIReg(sz,gregOfRM(rm)));
6015 return 1+delta0;
6016 }
6017
6018 /* E refers to memory */
6019 {
6020 IRTemp addr = disAMode ( &len, sorb, delta0, dis_buf );
6021 assign( tmps, loadLE(ty, mkexpr(addr)) );
6022 assign( tmpd, getIReg(sz, gregOfRM(rm)) );
6023
6024 putIReg(sz, gregOfRM(rm),
sewardj2a9ad022004-11-25 02:46:58 +00006025 IRExpr_Mux0X( unop(Iop_1Uto8,
6026 mk_x86g_calculate_condition(cond)),
sewardj458a6f82004-08-25 12:46:02 +00006027 mkexpr(tmpd),
6028 mkexpr(tmps) )
6029 );
6030
6031 DIP("cmov%c%s %s,%s\n", nameISize(sz),
sewardj2a9ad022004-11-25 02:46:58 +00006032 name_X86Condcode(cond),
sewardj458a6f82004-08-25 12:46:02 +00006033 dis_buf,
6034 nameIReg(sz,gregOfRM(rm)));
6035 return len+delta0;
6036 }
6037}
6038
6039
sewardj883b00b2004-09-11 09:30:24 +00006040static
sewardj52d04912005-07-03 00:52:48 +00006041UInt dis_xadd_G_E ( UChar sorb, Int sz, Int delta0 )
sewardj883b00b2004-09-11 09:30:24 +00006042{
6043 Int len;
6044 UChar rm = getIByte(delta0);
sewardjc9a43662004-11-30 18:51:59 +00006045 HChar dis_buf[50];
sewardj883b00b2004-09-11 09:30:24 +00006046
6047 // Int tmpd = newTemp(cb);
6048 //Int tmpt = newTemp(cb);
6049
6050 IRType ty = szToITy(sz);
6051 IRTemp tmpd = newTemp(ty);
6052 IRTemp tmpt0 = newTemp(ty);
6053 IRTemp tmpt1 = newTemp(ty);
6054
6055 if (epartIsReg(rm)) {
sewardja8415ff2005-01-21 20:55:36 +00006056 unimplemented("x86 xadd instruction with register operand");
sewardj883b00b2004-09-11 09:30:24 +00006057#if 0
6058 uInstr2(cb, GET, sz, ArchReg, eregOfRM(rm), TempReg, tmpd);
6059 uInstr2(cb, GET, sz, ArchReg, gregOfRM(rm), TempReg, tmpt);
6060 uInstr2(cb, ADD, sz, TempReg, tmpd, TempReg, tmpt);
6061 setFlagsFromUOpcode(cb, ADD);
6062 uInstr2(cb, PUT, sz, TempReg, tmpd, ArchReg, gregOfRM(rm));
6063 uInstr2(cb, PUT, sz, TempReg, tmpt, ArchReg, eregOfRM(rm));
6064 DIP("xadd%c %s, %s\n",
6065 nameISize(sz), nameIReg(sz,gregOfRM(rm)), nameIReg(sz,eregOfRM(rm)));
6066 return 1+eip0;
6067#endif
6068 } else {
6069 IRTemp addr = disAMode ( &len, sorb, delta0, dis_buf );
6070 assign( tmpd, loadLE(ty, mkexpr(addr)) );
6071 assign( tmpt0, getIReg(sz, gregOfRM(rm)) );
sewardj883b00b2004-09-11 09:30:24 +00006072 assign( tmpt1, binop(mkSizedOp(ty,Iop_Add8), mkexpr(tmpd), mkexpr(tmpt0)) );
sewardj2a2ba8b2004-11-08 13:14:06 +00006073 setFlags_DEP1_DEP2( Iop_Add8, tmpd, tmpt0, ty );
sewardj883b00b2004-09-11 09:30:24 +00006074 storeLE( mkexpr(addr), mkexpr(tmpt1) );
6075 putIReg(sz, gregOfRM(rm), mkexpr(tmpd));
6076 DIP("xadd%c %s, %s\n",
6077 nameISize(sz), nameIReg(sz,gregOfRM(rm)), dis_buf);
6078 return len+delta0;
6079 }
6080}
6081
sewardjb64821b2004-12-14 10:00:16 +00006082/* Move 16 bits from Ew (ireg or mem) to G (a segment register). */
6083
sewardj7df596b2004-12-06 14:29:12 +00006084static
sewardj52d04912005-07-03 00:52:48 +00006085UInt dis_mov_Ew_Sw ( UChar sorb, Int delta0 )
sewardj7df596b2004-12-06 14:29:12 +00006086{
sewardjb64821b2004-12-14 10:00:16 +00006087 Int len;
6088 IRTemp addr;
6089 UChar rm = getIByte(delta0);
6090 HChar dis_buf[50];
sewardj7df596b2004-12-06 14:29:12 +00006091
6092 if (epartIsReg(rm)) {
6093 putSReg( gregOfRM(rm), getIReg(2, eregOfRM(rm)) );
6094 DIP("movw %s,%s\n", nameIReg(2,eregOfRM(rm)), nameSReg(gregOfRM(rm)));
6095 return 1+delta0;
sewardjb64821b2004-12-14 10:00:16 +00006096 } else {
6097 addr = disAMode ( &len, sorb, delta0, dis_buf );
6098 putSReg( gregOfRM(rm), loadLE(Ity_I16, mkexpr(addr)) );
6099 DIP("movw %s,%s\n", dis_buf, nameSReg(gregOfRM(rm)));
6100 return len+delta0;
sewardj7df596b2004-12-06 14:29:12 +00006101 }
6102}
6103
sewardjb64821b2004-12-14 10:00:16 +00006104/* Move 16 bits from G (a segment register) to Ew (ireg or mem). If
6105 dst is ireg and sz==4, zero out top half of it. */
6106
sewardj063f02f2004-10-20 12:36:12 +00006107static
6108UInt dis_mov_Sw_Ew ( UChar sorb,
6109 Int sz,
sewardj52d04912005-07-03 00:52:48 +00006110 Int delta0 )
sewardj063f02f2004-10-20 12:36:12 +00006111{
sewardjb64821b2004-12-14 10:00:16 +00006112 Int len;
6113 IRTemp addr;
6114 UChar rm = getIByte(delta0);
6115 HChar dis_buf[50];
sewardj063f02f2004-10-20 12:36:12 +00006116
6117 vassert(sz == 2 || sz == 4);
6118
6119 if (epartIsReg(rm)) {
6120 if (sz == 4)
6121 putIReg(4, eregOfRM(rm), unop(Iop_16Uto32, getSReg(gregOfRM(rm))));
6122 else
6123 putIReg(2, eregOfRM(rm), getSReg(gregOfRM(rm)));
6124
6125 DIP("mov %s,%s\n", nameSReg(gregOfRM(rm)), nameIReg(sz,eregOfRM(rm)));
6126 return 1+delta0;
sewardjb64821b2004-12-14 10:00:16 +00006127 } else {
6128 addr = disAMode ( &len, sorb, delta0, dis_buf );
6129 storeLE( mkexpr(addr), getSReg(gregOfRM(rm)) );
sewardj063f02f2004-10-20 12:36:12 +00006130 DIP("mov %s,%s\n", nameSReg(gregOfRM(rm)), dis_buf);
sewardjb64821b2004-12-14 10:00:16 +00006131 return len+delta0;
sewardj063f02f2004-10-20 12:36:12 +00006132 }
sewardj063f02f2004-10-20 12:36:12 +00006133}
6134
6135
sewardjb64821b2004-12-14 10:00:16 +00006136static
6137void dis_push_segreg ( UInt sreg, Int sz )
6138{
6139 IRTemp t1 = newTemp(Ity_I16);
6140 IRTemp ta = newTemp(Ity_I32);
6141 vassert(sz == 2 || sz == 4);
6142
6143 assign( t1, getSReg(sreg) );
6144 assign( ta, binop(Iop_Sub32, getIReg(4, R_ESP), mkU32(sz)) );
6145 putIReg(4, R_ESP, mkexpr(ta));
6146 storeLE( mkexpr(ta), mkexpr(t1) );
6147
6148 DIP("pushw %s\n", nameSReg(sreg));
6149}
6150
6151static
6152void dis_pop_segreg ( UInt sreg, Int sz )
6153{
6154 IRTemp t1 = newTemp(Ity_I16);
6155 IRTemp ta = newTemp(Ity_I32);
6156 vassert(sz == 2 || sz == 4);
6157
6158 assign( ta, getIReg(4, R_ESP) );
6159 assign( t1, loadLE(Ity_I16, mkexpr(ta)) );
6160
6161 putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(ta), mkU32(sz)) );
6162 putSReg( sreg, mkexpr(t1) );
6163 DIP("pop %s\n", nameSReg(sreg));
6164}
sewardje05c42c2004-07-08 20:25:10 +00006165
6166static
6167void dis_ret ( UInt d32 )
6168{
6169 IRTemp t1 = newTemp(Ity_I32), t2 = newTemp(Ity_I32);
6170 assign(t1, getIReg(4,R_ESP));
6171 assign(t2, loadLE(Ity_I32,mkexpr(t1)));
6172 putIReg(4, R_ESP,binop(Iop_Add32, mkexpr(t1), mkU32(4+d32)));
sewardj78c19df2004-07-12 22:49:27 +00006173 jmp_treg(Ijk_Ret,t2);
sewardje05c42c2004-07-08 20:25:10 +00006174}
6175
sewardj4cb918d2004-12-03 19:43:31 +00006176/*------------------------------------------------------------*/
6177/*--- SSE/SSE2/SSE3 helpers ---*/
6178/*------------------------------------------------------------*/
sewardjc9a43662004-11-30 18:51:59 +00006179
sewardj129b3d92004-12-05 15:42:05 +00006180/* Worker function; do not call directly.
6181 Handles full width G = G `op` E and G = (not G) `op` E.
6182*/
6183
6184static UInt dis_SSE_E_to_G_all_wrk (
sewardj52d04912005-07-03 00:52:48 +00006185 UChar sorb, Int delta,
sewardj1e6ad742004-12-02 16:16:11 +00006186 HChar* opname, IROp op,
6187 Bool invertG
6188 )
sewardjc9a43662004-11-30 18:51:59 +00006189{
sewardj1e6ad742004-12-02 16:16:11 +00006190 HChar dis_buf[50];
6191 Int alen;
6192 IRTemp addr;
6193 UChar rm = getIByte(delta);
6194 IRExpr* gpart
sewardjf0c1c582005-02-07 23:47:38 +00006195 = invertG ? unop(Iop_NotV128, getXMMReg(gregOfRM(rm)))
sewardj1e6ad742004-12-02 16:16:11 +00006196 : getXMMReg(gregOfRM(rm));
sewardjc9a43662004-11-30 18:51:59 +00006197 if (epartIsReg(rm)) {
6198 putXMMReg( gregOfRM(rm),
sewardj1e6ad742004-12-02 16:16:11 +00006199 binop(op, gpart,
6200 getXMMReg(eregOfRM(rm))) );
sewardjc9a43662004-11-30 18:51:59 +00006201 DIP("%s %s,%s\n", opname,
6202 nameXMMReg(eregOfRM(rm)),
6203 nameXMMReg(gregOfRM(rm)) );
6204 return delta+1;
6205 } else {
sewardj1e6ad742004-12-02 16:16:11 +00006206 addr = disAMode ( &alen, sorb, delta, dis_buf );
6207 putXMMReg( gregOfRM(rm),
6208 binop(op, gpart,
6209 loadLE(Ity_V128, mkexpr(addr))) );
6210 DIP("%s %s,%s\n", opname,
6211 dis_buf,
6212 nameXMMReg(gregOfRM(rm)) );
6213 return delta+alen;
sewardjc9a43662004-11-30 18:51:59 +00006214 }
6215}
6216
sewardj129b3d92004-12-05 15:42:05 +00006217
6218/* All lanes SSE binary operation, G = G `op` E. */
sewardj1e6ad742004-12-02 16:16:11 +00006219
6220static
sewardj52d04912005-07-03 00:52:48 +00006221UInt dis_SSE_E_to_G_all ( UChar sorb, Int delta, HChar* opname, IROp op )
sewardj1e6ad742004-12-02 16:16:11 +00006222{
sewardj129b3d92004-12-05 15:42:05 +00006223 return dis_SSE_E_to_G_all_wrk( sorb, delta, opname, op, False );
sewardj1e6ad742004-12-02 16:16:11 +00006224}
6225
sewardj129b3d92004-12-05 15:42:05 +00006226/* All lanes SSE binary operation, G = (not G) `op` E. */
6227
6228static
sewardj52d04912005-07-03 00:52:48 +00006229UInt dis_SSE_E_to_G_all_invG ( UChar sorb, Int delta,
sewardj129b3d92004-12-05 15:42:05 +00006230 HChar* opname, IROp op )
6231{
6232 return dis_SSE_E_to_G_all_wrk( sorb, delta, opname, op, True );
6233}
6234
sewardj164f9272004-12-09 00:39:32 +00006235
sewardj129b3d92004-12-05 15:42:05 +00006236/* Lowest 32-bit lane only SSE binary operation, G = G `op` E. */
6237
sewardj52d04912005-07-03 00:52:48 +00006238static UInt dis_SSE_E_to_G_lo32 ( UChar sorb, Int delta,
sewardj129b3d92004-12-05 15:42:05 +00006239 HChar* opname, IROp op )
6240{
6241 HChar dis_buf[50];
6242 Int alen;
6243 IRTemp addr;
6244 UChar rm = getIByte(delta);
6245 IRExpr* gpart = getXMMReg(gregOfRM(rm));
6246 if (epartIsReg(rm)) {
6247 putXMMReg( gregOfRM(rm),
6248 binop(op, gpart,
6249 getXMMReg(eregOfRM(rm))) );
6250 DIP("%s %s,%s\n", opname,
6251 nameXMMReg(eregOfRM(rm)),
6252 nameXMMReg(gregOfRM(rm)) );
6253 return delta+1;
6254 } else {
6255 /* We can only do a 32-bit memory read, so the upper 3/4 of the
6256 E operand needs to be made simply of zeroes. */
6257 IRTemp epart = newTemp(Ity_V128);
6258 addr = disAMode ( &alen, sorb, delta, dis_buf );
sewardjf0c1c582005-02-07 23:47:38 +00006259 assign( epart, unop( Iop_32UtoV128,
sewardj129b3d92004-12-05 15:42:05 +00006260 loadLE(Ity_I32, mkexpr(addr))) );
6261 putXMMReg( gregOfRM(rm),
6262 binop(op, gpart, mkexpr(epart)) );
6263 DIP("%s %s,%s\n", opname,
6264 dis_buf,
6265 nameXMMReg(gregOfRM(rm)) );
6266 return delta+alen;
6267 }
6268}
6269
sewardj164f9272004-12-09 00:39:32 +00006270
sewardj636ad762004-12-07 11:16:04 +00006271/* Lower 64-bit lane only SSE binary operation, G = G `op` E. */
6272
sewardj52d04912005-07-03 00:52:48 +00006273static UInt dis_SSE_E_to_G_lo64 ( UChar sorb, Int delta,
sewardj636ad762004-12-07 11:16:04 +00006274 HChar* opname, IROp op )
6275{
6276 HChar dis_buf[50];
6277 Int alen;
6278 IRTemp addr;
6279 UChar rm = getIByte(delta);
6280 IRExpr* gpart = getXMMReg(gregOfRM(rm));
6281 if (epartIsReg(rm)) {
6282 putXMMReg( gregOfRM(rm),
6283 binop(op, gpart,
6284 getXMMReg(eregOfRM(rm))) );
6285 DIP("%s %s,%s\n", opname,
6286 nameXMMReg(eregOfRM(rm)),
6287 nameXMMReg(gregOfRM(rm)) );
6288 return delta+1;
6289 } else {
6290 /* We can only do a 64-bit memory read, so the upper half of the
6291 E operand needs to be made simply of zeroes. */
6292 IRTemp epart = newTemp(Ity_V128);
6293 addr = disAMode ( &alen, sorb, delta, dis_buf );
sewardjf0c1c582005-02-07 23:47:38 +00006294 assign( epart, unop( Iop_64UtoV128,
sewardj636ad762004-12-07 11:16:04 +00006295 loadLE(Ity_I64, mkexpr(addr))) );
6296 putXMMReg( gregOfRM(rm),
6297 binop(op, gpart, mkexpr(epart)) );
6298 DIP("%s %s,%s\n", opname,
6299 dis_buf,
6300 nameXMMReg(gregOfRM(rm)) );
6301 return delta+alen;
6302 }
6303}
6304
sewardj164f9272004-12-09 00:39:32 +00006305
sewardj129b3d92004-12-05 15:42:05 +00006306/* All lanes unary SSE operation, G = op(E). */
6307
6308static UInt dis_SSE_E_to_G_unary_all (
sewardj52d04912005-07-03 00:52:48 +00006309 UChar sorb, Int delta,
sewardj0bd7ce62004-12-05 02:47:40 +00006310 HChar* opname, IROp op
6311 )
6312{
6313 HChar dis_buf[50];
6314 Int alen;
6315 IRTemp addr;
6316 UChar rm = getIByte(delta);
6317 if (epartIsReg(rm)) {
6318 putXMMReg( gregOfRM(rm),
6319 unop(op, getXMMReg(eregOfRM(rm))) );
6320 DIP("%s %s,%s\n", opname,
6321 nameXMMReg(eregOfRM(rm)),
6322 nameXMMReg(gregOfRM(rm)) );
6323 return delta+1;
6324 } else {
6325 addr = disAMode ( &alen, sorb, delta, dis_buf );
6326 putXMMReg( gregOfRM(rm),
6327 unop(op, loadLE(Ity_V128, mkexpr(addr))) );
6328 DIP("%s %s,%s\n", opname,
6329 dis_buf,
6330 nameXMMReg(gregOfRM(rm)) );
6331 return delta+alen;
6332 }
6333}
6334
sewardj164f9272004-12-09 00:39:32 +00006335
sewardj129b3d92004-12-05 15:42:05 +00006336/* Lowest 32-bit lane only unary SSE operation, G = op(E). */
sewardj0bd7ce62004-12-05 02:47:40 +00006337
sewardj129b3d92004-12-05 15:42:05 +00006338static UInt dis_SSE_E_to_G_unary_lo32 (
sewardj52d04912005-07-03 00:52:48 +00006339 UChar sorb, Int delta,
sewardj129b3d92004-12-05 15:42:05 +00006340 HChar* opname, IROp op
6341 )
6342{
6343 /* First we need to get the old G value and patch the low 32 bits
6344 of the E operand into it. Then apply op and write back to G. */
6345 HChar dis_buf[50];
6346 Int alen;
6347 IRTemp addr;
6348 UChar rm = getIByte(delta);
6349 IRTemp oldG0 = newTemp(Ity_V128);
6350 IRTemp oldG1 = newTemp(Ity_V128);
6351
6352 assign( oldG0, getXMMReg(gregOfRM(rm)) );
6353
6354 if (epartIsReg(rm)) {
6355 assign( oldG1,
sewardjf0c1c582005-02-07 23:47:38 +00006356 binop( Iop_SetV128lo32,
sewardj129b3d92004-12-05 15:42:05 +00006357 mkexpr(oldG0),
sewardj35579be2004-12-06 00:36:25 +00006358 getXMMRegLane32(eregOfRM(rm), 0)) );
sewardj129b3d92004-12-05 15:42:05 +00006359 putXMMReg( gregOfRM(rm), unop(op, mkexpr(oldG1)) );
6360 DIP("%s %s,%s\n", opname,
6361 nameXMMReg(eregOfRM(rm)),
6362 nameXMMReg(gregOfRM(rm)) );
6363 return delta+1;
6364 } else {
6365 addr = disAMode ( &alen, sorb, delta, dis_buf );
6366 assign( oldG1,
sewardjf0c1c582005-02-07 23:47:38 +00006367 binop( Iop_SetV128lo32,
sewardj129b3d92004-12-05 15:42:05 +00006368 mkexpr(oldG0),
6369 loadLE(Ity_I32, mkexpr(addr)) ));
6370 putXMMReg( gregOfRM(rm), unop(op, mkexpr(oldG1)) );
6371 DIP("%s %s,%s\n", opname,
6372 dis_buf,
6373 nameXMMReg(gregOfRM(rm)) );
6374 return delta+alen;
6375 }
6376}
6377
sewardj164f9272004-12-09 00:39:32 +00006378
sewardj008754b2004-12-08 14:37:10 +00006379/* Lowest 64-bit lane only unary SSE operation, G = op(E). */
6380
6381static UInt dis_SSE_E_to_G_unary_lo64 (
sewardj52d04912005-07-03 00:52:48 +00006382 UChar sorb, Int delta,
sewardj008754b2004-12-08 14:37:10 +00006383 HChar* opname, IROp op
6384 )
6385{
6386 /* First we need to get the old G value and patch the low 64 bits
6387 of the E operand into it. Then apply op and write back to G. */
6388 HChar dis_buf[50];
6389 Int alen;
6390 IRTemp addr;
6391 UChar rm = getIByte(delta);
6392 IRTemp oldG0 = newTemp(Ity_V128);
6393 IRTemp oldG1 = newTemp(Ity_V128);
6394
6395 assign( oldG0, getXMMReg(gregOfRM(rm)) );
6396
6397 if (epartIsReg(rm)) {
6398 assign( oldG1,
sewardjf0c1c582005-02-07 23:47:38 +00006399 binop( Iop_SetV128lo64,
sewardj008754b2004-12-08 14:37:10 +00006400 mkexpr(oldG0),
6401 getXMMRegLane64(eregOfRM(rm), 0)) );
6402 putXMMReg( gregOfRM(rm), unop(op, mkexpr(oldG1)) );
6403 DIP("%s %s,%s\n", opname,
6404 nameXMMReg(eregOfRM(rm)),
6405 nameXMMReg(gregOfRM(rm)) );
6406 return delta+1;
6407 } else {
6408 addr = disAMode ( &alen, sorb, delta, dis_buf );
6409 assign( oldG1,
sewardjf0c1c582005-02-07 23:47:38 +00006410 binop( Iop_SetV128lo64,
sewardj008754b2004-12-08 14:37:10 +00006411 mkexpr(oldG0),
6412 loadLE(Ity_I64, mkexpr(addr)) ));
6413 putXMMReg( gregOfRM(rm), unop(op, mkexpr(oldG1)) );
6414 DIP("%s %s,%s\n", opname,
6415 dis_buf,
6416 nameXMMReg(gregOfRM(rm)) );
6417 return delta+alen;
6418 }
6419}
6420
sewardj164f9272004-12-09 00:39:32 +00006421
6422/* SSE integer binary operation:
6423 G = G `op` E (eLeft == False)
6424 G = E `op` G (eLeft == True)
6425*/
6426static UInt dis_SSEint_E_to_G(
sewardj52d04912005-07-03 00:52:48 +00006427 UChar sorb, Int delta,
sewardj164f9272004-12-09 00:39:32 +00006428 HChar* opname, IROp op,
6429 Bool eLeft
6430 )
6431{
6432 HChar dis_buf[50];
6433 Int alen;
6434 IRTemp addr;
6435 UChar rm = getIByte(delta);
6436 IRExpr* gpart = getXMMReg(gregOfRM(rm));
6437 IRExpr* epart = NULL;
6438 if (epartIsReg(rm)) {
6439 epart = getXMMReg(eregOfRM(rm));
6440 DIP("%s %s,%s\n", opname,
6441 nameXMMReg(eregOfRM(rm)),
6442 nameXMMReg(gregOfRM(rm)) );
6443 delta += 1;
6444 } else {
6445 addr = disAMode ( &alen, sorb, delta, dis_buf );
6446 epart = loadLE(Ity_V128, mkexpr(addr));
6447 DIP("%s %s,%s\n", opname,
6448 dis_buf,
6449 nameXMMReg(gregOfRM(rm)) );
6450 delta += alen;
6451 }
6452 putXMMReg( gregOfRM(rm),
6453 eLeft ? binop(op, epart, gpart)
6454 : binop(op, gpart, epart) );
6455 return delta;
6456}
6457
6458
sewardjfd226452004-12-07 19:02:18 +00006459/* Helper for doing SSE FP comparisons. */
sewardj0bd7ce62004-12-05 02:47:40 +00006460
sewardj1e6ad742004-12-02 16:16:11 +00006461static void findSSECmpOp ( Bool* needNot, IROp* op,
6462 Int imm8, Bool all_lanes, Int sz )
6463{
6464 imm8 &= 7;
6465 *needNot = False;
6466 *op = Iop_INVALID;
6467 if (imm8 >= 4) {
6468 *needNot = True;
6469 imm8 -= 4;
6470 }
6471
6472 if (sz == 4 && all_lanes) {
6473 switch (imm8) {
6474 case 0: *op = Iop_CmpEQ32Fx4; return;
6475 case 1: *op = Iop_CmpLT32Fx4; return;
6476 case 2: *op = Iop_CmpLE32Fx4; return;
6477 case 3: *op = Iop_CmpUN32Fx4; return;
6478 default: break;
6479 }
6480 }
6481 if (sz == 4 && !all_lanes) {
6482 switch (imm8) {
6483 case 0: *op = Iop_CmpEQ32F0x4; return;
6484 case 1: *op = Iop_CmpLT32F0x4; return;
6485 case 2: *op = Iop_CmpLE32F0x4; return;
6486 case 3: *op = Iop_CmpUN32F0x4; return;
6487 default: break;
6488 }
6489 }
sewardjfd226452004-12-07 19:02:18 +00006490 if (sz == 8 && all_lanes) {
6491 switch (imm8) {
6492 case 0: *op = Iop_CmpEQ64Fx2; return;
6493 case 1: *op = Iop_CmpLT64Fx2; return;
6494 case 2: *op = Iop_CmpLE64Fx2; return;
6495 case 3: *op = Iop_CmpUN64Fx2; return;
6496 default: break;
6497 }
6498 }
6499 if (sz == 8 && !all_lanes) {
6500 switch (imm8) {
6501 case 0: *op = Iop_CmpEQ64F0x2; return;
6502 case 1: *op = Iop_CmpLT64F0x2; return;
6503 case 2: *op = Iop_CmpLE64F0x2; return;
6504 case 3: *op = Iop_CmpUN64F0x2; return;
6505 default: break;
6506 }
sewardj1e6ad742004-12-02 16:16:11 +00006507 }
6508 vpanic("findSSECmpOp(x86,guest)");
6509}
6510
sewardj129b3d92004-12-05 15:42:05 +00006511/* Handles SSE 32F comparisons. */
6512
sewardj52d04912005-07-03 00:52:48 +00006513static UInt dis_SSEcmp_E_to_G ( UChar sorb, Int delta,
sewardj1e6ad742004-12-02 16:16:11 +00006514 HChar* opname, Bool all_lanes, Int sz )
6515{
6516 HChar dis_buf[50];
6517 Int alen, imm8;
6518 IRTemp addr;
6519 Bool needNot = False;
6520 IROp op = Iop_INVALID;
6521 IRTemp plain = newTemp(Ity_V128);
6522 UChar rm = getIByte(delta);
6523 UShort mask = 0;
6524 vassert(sz == 4 || sz == 8);
6525 if (epartIsReg(rm)) {
6526 imm8 = getIByte(delta+1);
6527 findSSECmpOp(&needNot, &op, imm8, all_lanes, sz);
6528 assign( plain, binop(op, getXMMReg(gregOfRM(rm)),
6529 getXMMReg(eregOfRM(rm))) );
6530 delta += 2;
6531 DIP("%s $%d,%s,%s\n", opname,
6532 (Int)imm8,
6533 nameXMMReg(eregOfRM(rm)),
6534 nameXMMReg(gregOfRM(rm)) );
6535 } else {
6536 addr = disAMode ( &alen, sorb, delta, dis_buf );
6537 imm8 = getIByte(delta+alen);
6538 findSSECmpOp(&needNot, &op, imm8, all_lanes, sz);
6539 assign( plain, binop(op, getXMMReg(gregOfRM(rm)),
6540 loadLE(Ity_V128, mkexpr(addr))) );
6541 delta += alen+1;
6542 DIP("%s $%d,%s,%s\n", opname,
6543 (Int)imm8,
6544 dis_buf,
6545 nameXMMReg(gregOfRM(rm)) );
6546 }
6547
sewardj2e383862004-12-12 16:46:47 +00006548 if (needNot && all_lanes) {
6549 putXMMReg( gregOfRM(rm),
sewardjf0c1c582005-02-07 23:47:38 +00006550 unop(Iop_NotV128, mkexpr(plain)) );
sewardj2e383862004-12-12 16:46:47 +00006551 }
6552 else
6553 if (needNot && !all_lanes) {
sewardj9b45b482005-02-07 01:42:18 +00006554 mask = toUShort( sz==4 ? 0x000F : 0x00FF );
sewardj2e383862004-12-12 16:46:47 +00006555 putXMMReg( gregOfRM(rm),
sewardjf0c1c582005-02-07 23:47:38 +00006556 binop(Iop_XorV128, mkexpr(plain), mkV128(mask)) );
sewardj2e383862004-12-12 16:46:47 +00006557 }
6558 else {
6559 putXMMReg( gregOfRM(rm), mkexpr(plain) );
6560 }
sewardj1e6ad742004-12-02 16:16:11 +00006561
sewardj1e6ad742004-12-02 16:16:11 +00006562 return delta;
6563}
6564
sewardjb9fa69b2004-12-09 23:25:14 +00006565
6566/* Vector by scalar shift of G by the amount specified at the bottom
6567 of E. */
6568
sewardj52d04912005-07-03 00:52:48 +00006569static UInt dis_SSE_shiftG_byE ( UChar sorb, Int delta,
sewardjb9fa69b2004-12-09 23:25:14 +00006570 HChar* opname, IROp op )
6571{
6572 HChar dis_buf[50];
6573 Int alen, size;
6574 IRTemp addr;
6575 Bool shl, shr, sar;
6576 UChar rm = getIByte(delta);
6577 IRTemp g0 = newTemp(Ity_V128);
6578 IRTemp g1 = newTemp(Ity_V128);
6579 IRTemp amt = newTemp(Ity_I32);
6580 IRTemp amt8 = newTemp(Ity_I8);
6581 if (epartIsReg(rm)) {
6582 assign( amt, getXMMRegLane32(eregOfRM(rm), 0) );
6583 DIP("%s %s,%s\n", opname,
6584 nameXMMReg(eregOfRM(rm)),
6585 nameXMMReg(gregOfRM(rm)) );
6586 delta++;
6587 } else {
6588 addr = disAMode ( &alen, sorb, delta, dis_buf );
6589 assign( amt, loadLE(Ity_I32, mkexpr(addr)) );
6590 DIP("%s %s,%s\n", opname,
6591 dis_buf,
6592 nameXMMReg(gregOfRM(rm)) );
6593 delta += alen;
6594 }
6595 assign( g0, getXMMReg(gregOfRM(rm)) );
6596 assign( amt8, unop(Iop_32to8, mkexpr(amt)) );
6597
6598 shl = shr = sar = False;
6599 size = 0;
6600 switch (op) {
6601 case Iop_ShlN16x8: shl = True; size = 32; break;
6602 case Iop_ShlN32x4: shl = True; size = 32; break;
6603 case Iop_ShlN64x2: shl = True; size = 64; break;
6604 case Iop_SarN16x8: sar = True; size = 16; break;
6605 case Iop_SarN32x4: sar = True; size = 32; break;
6606 case Iop_ShrN16x8: shr = True; size = 16; break;
6607 case Iop_ShrN32x4: shr = True; size = 32; break;
6608 case Iop_ShrN64x2: shr = True; size = 64; break;
6609 default: vassert(0);
6610 }
6611
6612 if (shl || shr) {
6613 assign(
6614 g1,
6615 IRExpr_Mux0X(
6616 unop(Iop_1Uto8,binop(Iop_CmpLT32U,mkexpr(amt),mkU32(size))),
6617 mkV128(0x0000),
6618 binop(op, mkexpr(g0), mkexpr(amt8))
6619 )
6620 );
6621 } else
6622 if (sar) {
6623 assign(
6624 g1,
6625 IRExpr_Mux0X(
6626 unop(Iop_1Uto8,binop(Iop_CmpLT32U,mkexpr(amt),mkU32(size))),
6627 binop(op, mkexpr(g0), mkU8(size-1)),
6628 binop(op, mkexpr(g0), mkexpr(amt8))
6629 )
6630 );
6631 } else {
sewardjba89f4c2005-04-07 17:31:27 +00006632 /*NOTREACHED*/
sewardjb9fa69b2004-12-09 23:25:14 +00006633 vassert(0);
6634 }
6635
6636 putXMMReg( gregOfRM(rm), mkexpr(g1) );
6637 return delta;
6638}
6639
6640
6641/* Vector by scalar shift of E by an immediate byte. */
6642
sewardj38a3f862005-01-13 15:06:51 +00006643static
sewardj52d04912005-07-03 00:52:48 +00006644UInt dis_SSE_shiftE_imm ( Int delta, HChar* opname, IROp op )
sewardjb9fa69b2004-12-09 23:25:14 +00006645{
6646 Bool shl, shr, sar;
6647 UChar rm = getIByte(delta);
sewardj38a3f862005-01-13 15:06:51 +00006648 IRTemp e0 = newTemp(Ity_V128);
6649 IRTemp e1 = newTemp(Ity_V128);
sewardjb9fa69b2004-12-09 23:25:14 +00006650 UChar amt, size;
6651 vassert(epartIsReg(rm));
6652 vassert(gregOfRM(rm) == 2
6653 || gregOfRM(rm) == 4 || gregOfRM(rm) == 6);
sewardj2d49b432005-02-01 00:37:06 +00006654 amt = getIByte(delta+1);
sewardjb9fa69b2004-12-09 23:25:14 +00006655 delta += 2;
6656 DIP("%s $%d,%s\n", opname,
6657 (Int)amt,
6658 nameXMMReg(eregOfRM(rm)) );
sewardj38a3f862005-01-13 15:06:51 +00006659 assign( e0, getXMMReg(eregOfRM(rm)) );
sewardjb9fa69b2004-12-09 23:25:14 +00006660
6661 shl = shr = sar = False;
6662 size = 0;
6663 switch (op) {
6664 case Iop_ShlN16x8: shl = True; size = 16; break;
6665 case Iop_ShlN32x4: shl = True; size = 32; break;
6666 case Iop_ShlN64x2: shl = True; size = 64; break;
6667 case Iop_SarN16x8: sar = True; size = 16; break;
6668 case Iop_SarN32x4: sar = True; size = 32; break;
6669 case Iop_ShrN16x8: shr = True; size = 16; break;
6670 case Iop_ShrN32x4: shr = True; size = 32; break;
6671 case Iop_ShrN64x2: shr = True; size = 64; break;
6672 default: vassert(0);
6673 }
6674
6675 if (shl || shr) {
sewardjba89f4c2005-04-07 17:31:27 +00006676 assign( e1, amt >= size
6677 ? mkV128(0x0000)
6678 : binop(op, mkexpr(e0), mkU8(amt))
6679 );
sewardjb9fa69b2004-12-09 23:25:14 +00006680 } else
6681 if (sar) {
sewardjba89f4c2005-04-07 17:31:27 +00006682 assign( e1, amt >= size
6683 ? binop(op, mkexpr(e0), mkU8(size-1))
6684 : binop(op, mkexpr(e0), mkU8(amt))
6685 );
sewardjb9fa69b2004-12-09 23:25:14 +00006686 } else {
sewardjba89f4c2005-04-07 17:31:27 +00006687 /*NOTREACHED*/
sewardjb9fa69b2004-12-09 23:25:14 +00006688 vassert(0);
6689 }
6690
sewardj38a3f862005-01-13 15:06:51 +00006691 putXMMReg( eregOfRM(rm), mkexpr(e1) );
sewardjb9fa69b2004-12-09 23:25:14 +00006692 return delta;
6693}
6694
6695
sewardjc1e7dfc2004-12-05 19:29:45 +00006696/* Get the current SSE rounding mode. */
sewardjc9a65702004-07-07 16:32:57 +00006697
sewardj4cb918d2004-12-03 19:43:31 +00006698static IRExpr* /* :: Ity_I32 */ get_sse_roundingmode ( void )
6699{
6700 return binop( Iop_And32,
6701 IRExpr_Get( OFFB_SSEROUND, Ity_I32 ),
6702 mkU32(3) );
6703}
6704
sewardj636ad762004-12-07 11:16:04 +00006705static void put_sse_roundingmode ( IRExpr* sseround )
6706{
6707 vassert(typeOfIRExpr(irbb->tyenv, sseround) == Ity_I32);
6708 stmt( IRStmt_Put( OFFB_SSEROUND, sseround ) );
6709}
6710
sewardjc1e7dfc2004-12-05 19:29:45 +00006711/* Break a 128-bit value up into four 32-bit ints. */
6712
6713static void breakup128to32s ( IRTemp t128,
6714 /*OUTs*/
6715 IRTemp* t3, IRTemp* t2,
6716 IRTemp* t1, IRTemp* t0 )
6717{
6718 IRTemp hi64 = newTemp(Ity_I64);
6719 IRTemp lo64 = newTemp(Ity_I64);
sewardjf0c1c582005-02-07 23:47:38 +00006720 assign( hi64, unop(Iop_V128HIto64, mkexpr(t128)) );
6721 assign( lo64, unop(Iop_V128to64, mkexpr(t128)) );
sewardjc1e7dfc2004-12-05 19:29:45 +00006722
6723 vassert(t0 && *t0 == IRTemp_INVALID);
6724 vassert(t1 && *t1 == IRTemp_INVALID);
6725 vassert(t2 && *t2 == IRTemp_INVALID);
6726 vassert(t3 && *t3 == IRTemp_INVALID);
6727
6728 *t0 = newTemp(Ity_I32);
6729 *t1 = newTemp(Ity_I32);
6730 *t2 = newTemp(Ity_I32);
6731 *t3 = newTemp(Ity_I32);
6732 assign( *t0, unop(Iop_64to32, mkexpr(lo64)) );
6733 assign( *t1, unop(Iop_64HIto32, mkexpr(lo64)) );
6734 assign( *t2, unop(Iop_64to32, mkexpr(hi64)) );
6735 assign( *t3, unop(Iop_64HIto32, mkexpr(hi64)) );
6736}
6737
6738/* Construct a 128-bit value from four 32-bit ints. */
6739
6740static IRExpr* mk128from32s ( IRTemp t3, IRTemp t2,
6741 IRTemp t1, IRTemp t0 )
6742{
6743 return
sewardjf0c1c582005-02-07 23:47:38 +00006744 binop( Iop_64HLtoV128,
sewardjc1e7dfc2004-12-05 19:29:45 +00006745 binop(Iop_32HLto64, mkexpr(t3), mkexpr(t2)),
6746 binop(Iop_32HLto64, mkexpr(t1), mkexpr(t0))
6747 );
6748}
6749
sewardjb9fa69b2004-12-09 23:25:14 +00006750/* Break a 64-bit value up into four 16-bit ints. */
6751
6752static void breakup64to16s ( IRTemp t64,
6753 /*OUTs*/
6754 IRTemp* t3, IRTemp* t2,
6755 IRTemp* t1, IRTemp* t0 )
6756{
6757 IRTemp hi32 = newTemp(Ity_I32);
6758 IRTemp lo32 = newTemp(Ity_I32);
6759 assign( hi32, unop(Iop_64HIto32, mkexpr(t64)) );
6760 assign( lo32, unop(Iop_64to32, mkexpr(t64)) );
6761
6762 vassert(t0 && *t0 == IRTemp_INVALID);
6763 vassert(t1 && *t1 == IRTemp_INVALID);
6764 vassert(t2 && *t2 == IRTemp_INVALID);
6765 vassert(t3 && *t3 == IRTemp_INVALID);
6766
6767 *t0 = newTemp(Ity_I16);
6768 *t1 = newTemp(Ity_I16);
6769 *t2 = newTemp(Ity_I16);
6770 *t3 = newTemp(Ity_I16);
6771 assign( *t0, unop(Iop_32to16, mkexpr(lo32)) );
6772 assign( *t1, unop(Iop_32HIto16, mkexpr(lo32)) );
6773 assign( *t2, unop(Iop_32to16, mkexpr(hi32)) );
6774 assign( *t3, unop(Iop_32HIto16, mkexpr(hi32)) );
6775}
6776
6777/* Construct a 64-bit value from four 16-bit ints. */
6778
6779static IRExpr* mk64from16s ( IRTemp t3, IRTemp t2,
6780 IRTemp t1, IRTemp t0 )
6781{
6782 return
6783 binop( Iop_32HLto64,
6784 binop(Iop_16HLto32, mkexpr(t3), mkexpr(t2)),
6785 binop(Iop_16HLto32, mkexpr(t1), mkexpr(t0))
6786 );
6787}
6788
sewardj4cb918d2004-12-03 19:43:31 +00006789
sewardjc9a65702004-07-07 16:32:57 +00006790/*------------------------------------------------------------*/
sewardjce70a5c2004-10-18 14:09:54 +00006791/*--- Disassemble a single instruction ---*/
sewardjc9a65702004-07-07 16:32:57 +00006792/*------------------------------------------------------------*/
6793
sewardjce70a5c2004-10-18 14:09:54 +00006794/* Disassemble a single instruction into IR. The instruction
sewardj9e6491a2005-07-02 19:24:10 +00006795 is located in host memory at &guest_code[delta]. */
6796
6797static
6798DisResult disInstr_X86_WRK (
6799 Bool put_IP,
6800 Bool (*resteerOkFn) ( Addr64 ),
6801 Long delta64,
6802 VexArchInfo* archinfo
6803 )
sewardjc9a65702004-07-07 16:32:57 +00006804{
sewardjce70a5c2004-10-18 14:09:54 +00006805 IRType ty;
sewardjb5452082004-12-04 20:33:02 +00006806 IRTemp addr, t0, t1, t2, t3, t4, t5, t6;
sewardjce70a5c2004-10-18 14:09:54 +00006807 Int alen;
6808 UChar opc, modrm, abyte;
6809 UInt d32;
sewardjc9a43662004-11-30 18:51:59 +00006810 HChar dis_buf[50];
sewardjce70a5c2004-10-18 14:09:54 +00006811 Int am_sz, d_sz;
sewardj9e6491a2005-07-02 19:24:10 +00006812 DisResult dres;
sewardjc9a43662004-11-30 18:51:59 +00006813 UChar* insn; /* used in SSE decoders */
sewardjce70a5c2004-10-18 14:09:54 +00006814
sewardj9e6491a2005-07-02 19:24:10 +00006815 /* The running delta */
6816 Int delta = (Int)delta64;
6817
sewardjc9a65702004-07-07 16:32:57 +00006818 /* Holds eip at the start of the insn, so that we can print
6819 consistent error messages for unimplemented insns. */
sewardj9e6491a2005-07-02 19:24:10 +00006820 Int delta_start = delta;
sewardjc9a65702004-07-07 16:32:57 +00006821
6822 /* sz denotes the nominal data-op size of the insn; we change it to
6823 2 if an 0x66 prefix is seen */
6824 Int sz = 4;
6825
6826 /* sorb holds the segment-override-prefix byte, if any. Zero if no
6827 prefix has been seen, else one of {0x26, 0x3E, 0x64, 0x65}
6828 indicating the prefix. */
6829 UChar sorb = 0;
6830
sewardj9e6491a2005-07-02 19:24:10 +00006831 /* Set result defaults. */
6832 dres.whatNext = Dis_Continue;
6833 dres.len = 0;
6834 dres.continueAt = 0;
sewardjce70a5c2004-10-18 14:09:54 +00006835
sewardjb5452082004-12-04 20:33:02 +00006836 addr = t0 = t1 = t2 = t3 = t4 = t5 = t6 = IRTemp_INVALID;
sewardjc9a65702004-07-07 16:32:57 +00006837
sewardj9e6491a2005-07-02 19:24:10 +00006838 DIP("\t0x%x: ", guest_EIP_bbstart+delta);
6839
6840 /* We may be asked to update the guest EIP before going further. */
6841 if (put_IP)
6842 stmt( IRStmt_Put( OFFB_EIP, mkU32(guest_EIP_curr_instr)) );
sewardjc9a65702004-07-07 16:32:57 +00006843
sewardj750f4072004-07-26 22:39:11 +00006844 /* Spot the client-request magic sequence. */
6845 {
6846 UChar* code = (UChar*)(guest_code + delta);
6847 /* Spot this:
6848 C1C01D roll $29, %eax
6849 C1C003 roll $3, %eax
6850 C1C81B rorl $27, %eax
6851 C1C805 rorl $5, %eax
6852 C1C00D roll $13, %eax
6853 C1C013 roll $19, %eax
6854 */
6855 if (code[ 0] == 0xC1 && code[ 1] == 0xC0 && code[ 2] == 0x1D &&
6856 code[ 3] == 0xC1 && code[ 4] == 0xC0 && code[ 5] == 0x03 &&
6857 code[ 6] == 0xC1 && code[ 7] == 0xC8 && code[ 8] == 0x1B &&
6858 code[ 9] == 0xC1 && code[10] == 0xC8 && code[11] == 0x05 &&
6859 code[12] == 0xC1 && code[13] == 0xC0 && code[14] == 0x0D &&
6860 code[15] == 0xC1 && code[16] == 0xC0 && code[17] == 0x13
6861 ) {
sewardjce70a5c2004-10-18 14:09:54 +00006862 DIP("%%edx = client_request ( %%eax )\n");
sewardj750f4072004-07-26 22:39:11 +00006863 delta += 18;
sewardj9e6491a2005-07-02 19:24:10 +00006864 jmp_lit(Ijk_ClientReq, guest_EIP_bbstart+delta);
6865 dres.whatNext = Dis_StopHere;
sewardjce70a5c2004-10-18 14:09:54 +00006866 goto decode_success;
sewardj750f4072004-07-26 22:39:11 +00006867 }
6868 }
sewardjc9a65702004-07-07 16:32:57 +00006869
6870 /* Skip a LOCK prefix. */
sewardjce4a2822005-01-07 13:25:28 +00006871 /* 2005 Jan 06: the following insns are observed to sometimes
6872 have a LOCK prefix:
6873 cmpxchgl %ecx,(%edx)
sewardjaade6d42005-01-07 13:36:14 +00006874 cmpxchgl %edx,0x278(%ebx) etc
sewardjce4a2822005-01-07 13:25:28 +00006875 xchgl %eax, (%ecx)
6876 xaddl %eax, (%ecx)
6877 We need to catch any such which appear to be being used as
6878 a memory barrier, for example lock addl $0,0(%esp)
6879 and emit an IR MFence construct.
6880 */
sewardjbb3f52d2005-01-07 14:14:50 +00006881 if (getIByte(delta) == 0xF0) {
6882
6883 UChar* code = (UChar*)(guest_code + delta);
6884
6885 /* Various bits of kernel headers use the following as a memory
6886 barrier. Hence, first emit an MFence and then let the insn
6887 go through as usual. */
6888 /* F08344240000: lock addl $0, 0(%esp) */
6889 if (code[0] == 0xF0 && code[1] == 0x83 && code[2] == 0x44 &&
6890 code[3] == 0x24 && code[4] == 0x00 && code[5] == 0x00) {
6891 stmt( IRStmt_MFence() );
6892 }
6893 else
6894 if (0) {
sewardjce4a2822005-01-07 13:25:28 +00006895 vex_printf("vex x86->IR: ignoring LOCK prefix on: ");
sewardj9e6491a2005-07-02 19:24:10 +00006896 /* insn_verbose = True; */
sewardjce4a2822005-01-07 13:25:28 +00006897 }
sewardjbb3f52d2005-01-07 14:14:50 +00006898
6899 /* In any case, skip the prefix. */
sewardjc9a65702004-07-07 16:32:57 +00006900 delta++;
6901 }
6902
6903 /* Detect operand-size overrides. */
6904 if (getIByte(delta) == 0x66) { sz = 2; delta++; };
6905
6906 /* segment override prefixes come after the operand-size override,
6907 it seems */
6908 switch (getIByte(delta)) {
6909 case 0x3E: /* %DS: */
6910 case 0x26: /* %ES: */
6911 case 0x64: /* %FS: */
6912 case 0x65: /* %GS: */
6913 sorb = getIByte(delta); delta++;
6914 break;
6915 case 0x2E: /* %CS: */
6916 /* 2E prefix on a conditional branch instruction is a
6917 branch-prediction hint, which can safely be ignored. */
6918 {
6919 UChar op1 = getIByte(delta+1);
6920 UChar op2 = getIByte(delta+2);
6921 if ((op1 >= 0x70 && op1 <= 0x7F)
6922 || (op1 == 0xE3)
6923 || (op1 == 0x0F && op2 >= 0x80 && op2 <= 0x8F)) {
sewardj4dfb1992005-03-13 18:56:28 +00006924 if (0) vex_printf("vex x86->IR: ignoring branch hint\n");
sewardjc9a65702004-07-07 16:32:57 +00006925 sorb = getIByte(delta); delta++;
6926 break;
6927 }
6928 }
6929 unimplemented("x86 segment override (SEG=CS) prefix");
6930 /*NOTREACHED*/
6931 break;
6932 case 0x36: /* %SS: */
6933 unimplemented("x86 segment override (SEG=SS) prefix");
6934 /*NOTREACHED*/
6935 break;
6936 default:
6937 break;
6938 }
6939
sewardjc9a43662004-11-30 18:51:59 +00006940 /* ---------------------------------------------------- */
6941 /* --- The SSE decoder. --- */
6942 /* ---------------------------------------------------- */
6943
sewardj4cb918d2004-12-03 19:43:31 +00006944 /* What did I do to deserve SSE ? Perhaps I was really bad in a
6945 previous life? */
6946
sewardj9df271d2004-12-31 22:37:42 +00006947 /* Note, this doesn't handle SSE2 or SSE3. That is handled in a
6948 later section, further on. */
6949
sewardja0e83b02005-01-06 12:36:38 +00006950 insn = (UChar*)&guest_code[delta];
6951
6952 /* Treat fxsave specially. It should be doable even on an SSE0
6953 (Pentium-II class) CPU. Hence be prepared to handle it on
6954 any subarchitecture variant.
6955 */
6956
6957 /* 0F AE /0 = FXSAVE m512 -- write x87 and SSE state to memory */
6958 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xAE
6959 && !epartIsReg(insn[2]) && gregOfRM(insn[2]) == 0) {
sewardj9a036bf2005-03-14 18:19:08 +00006960 IRDirty* d;
sewardja0e83b02005-01-06 12:36:38 +00006961 modrm = getIByte(delta+2);
6962 vassert(sz == 4);
6963 vassert(!epartIsReg(modrm));
6964
6965 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
6966 delta += 2+alen;
6967
sewardj33dd31b2005-01-08 18:17:32 +00006968 DIP("fxsave %s\n", dis_buf);
sewardja0e83b02005-01-06 12:36:38 +00006969
6970 /* Uses dirty helper:
6971 void x86g_do_FXSAVE ( VexGuestX86State*, UInt ) */
sewardj9a036bf2005-03-14 18:19:08 +00006972 d = unsafeIRDirty_0_N (
6973 0/*regparms*/,
6974 "x86g_dirtyhelper_FXSAVE",
6975 &x86g_dirtyhelper_FXSAVE,
6976 mkIRExprVec_1( mkexpr(addr) )
6977 );
sewardja0e83b02005-01-06 12:36:38 +00006978 d->needsBBP = True;
6979
6980 /* declare we're writing memory */
6981 d->mFx = Ifx_Write;
6982 d->mAddr = mkexpr(addr);
6983 d->mSize = 512;
6984
6985 /* declare we're reading guest state */
6986 d->nFxState = 7;
6987
6988 d->fxState[0].fx = Ifx_Read;
6989 d->fxState[0].offset = OFFB_FTOP;
6990 d->fxState[0].size = sizeof(UInt);
6991
6992 d->fxState[1].fx = Ifx_Read;
6993 d->fxState[1].offset = OFFB_FPREGS;
6994 d->fxState[1].size = 8 * sizeof(ULong);
6995
6996 d->fxState[2].fx = Ifx_Read;
6997 d->fxState[2].offset = OFFB_FPTAGS;
6998 d->fxState[2].size = 8 * sizeof(UChar);
6999
7000 d->fxState[3].fx = Ifx_Read;
7001 d->fxState[3].offset = OFFB_FPROUND;
7002 d->fxState[3].size = sizeof(UInt);
7003
7004 d->fxState[4].fx = Ifx_Read;
7005 d->fxState[4].offset = OFFB_FC3210;
7006 d->fxState[4].size = sizeof(UInt);
7007
7008 d->fxState[5].fx = Ifx_Read;
7009 d->fxState[5].offset = OFFB_XMM0;
7010 d->fxState[5].size = 8 * sizeof(U128);
7011
7012 d->fxState[6].fx = Ifx_Read;
7013 d->fxState[6].offset = OFFB_SSEROUND;
7014 d->fxState[6].size = sizeof(UInt);
7015
7016 /* Be paranoid ... this assertion tries to ensure the 8 %xmm
7017 images are packed back-to-back. If not, the value of
7018 d->fxState[5].size is wrong. */
7019 vassert(16 == sizeof(U128));
7020 vassert(OFFB_XMM7 == (OFFB_XMM0 + 7 * 16));
7021
7022 stmt( IRStmt_Dirty(d) );
7023
7024 goto decode_success;
7025 }
7026
7027 /* ------ SSE decoder main ------ */
7028
sewardj9df271d2004-12-31 22:37:42 +00007029 /* Skip parts of the decoder which don't apply given the stated
7030 guest subarchitecture. */
sewardj27e1dd62005-06-30 11:49:14 +00007031 if (archinfo->subarch == VexSubArchX86_sse0)
sewardj9df271d2004-12-31 22:37:42 +00007032 goto after_sse_decoders;
7033
7034 /* Otherwise we must be doing sse1 or sse2, so we can at least try
7035 for SSE1 here. */
sewardjc9a43662004-11-30 18:51:59 +00007036
sewardjc9a43662004-11-30 18:51:59 +00007037 /* 0F 58 = ADDPS -- add 32Fx4 from R/M to R */
sewardj636ad762004-12-07 11:16:04 +00007038 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x58) {
sewardj129b3d92004-12-05 15:42:05 +00007039 delta = dis_SSE_E_to_G_all( sorb, delta+2, "addps", Iop_Add32Fx4 );
sewardjc9a43662004-11-30 18:51:59 +00007040 goto decode_success;
7041 }
7042
sewardj1e6ad742004-12-02 16:16:11 +00007043 /* F3 0F 58 = ADDSS -- add 32F0x4 from R/M to R */
7044 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x58) {
7045 vassert(sz == 4);
sewardj129b3d92004-12-05 15:42:05 +00007046 delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "addss", Iop_Add32F0x4 );
sewardj1e6ad742004-12-02 16:16:11 +00007047 goto decode_success;
7048 }
7049
7050 /* 0F 55 = ANDNPS -- G = (not G) and E */
sewardj636ad762004-12-07 11:16:04 +00007051 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x55) {
sewardjf0c1c582005-02-07 23:47:38 +00007052 delta = dis_SSE_E_to_G_all_invG( sorb, delta+2, "andnps", Iop_AndV128 );
sewardj1e6ad742004-12-02 16:16:11 +00007053 goto decode_success;
7054 }
7055
7056 /* 0F 54 = ANDPS -- G = G and E */
sewardj636ad762004-12-07 11:16:04 +00007057 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x54) {
sewardjf0c1c582005-02-07 23:47:38 +00007058 delta = dis_SSE_E_to_G_all( sorb, delta+2, "andps", Iop_AndV128 );
sewardj1e6ad742004-12-02 16:16:11 +00007059 goto decode_success;
7060 }
7061
7062 /* 0F C2 = CMPPS -- 32Fx4 comparison from R/M to R */
sewardj636ad762004-12-07 11:16:04 +00007063 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xC2) {
sewardj1e6ad742004-12-02 16:16:11 +00007064 delta = dis_SSEcmp_E_to_G( sorb, delta+2, "cmpps", True, 4 );
7065 goto decode_success;
7066 }
7067
7068 /* F3 0F C2 = CMPSS -- 32F0x4 comparison from R/M to R */
7069 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0xC2) {
7070 vassert(sz == 4);
7071 delta = dis_SSEcmp_E_to_G( sorb, delta+3, "cmpss", False, 4 );
7072 goto decode_success;
7073 }
sewardjc9a43662004-11-30 18:51:59 +00007074
sewardjfd226452004-12-07 19:02:18 +00007075 /* 0F 2F = COMISS -- 32F0x4 comparison G,E, and set ZCP */
sewardjc1e7dfc2004-12-05 19:29:45 +00007076 /* 0F 2E = UCOMISS -- 32F0x4 comparison G,E, and set ZCP */
sewardjfd226452004-12-07 19:02:18 +00007077 if (sz == 4 && insn[0] == 0x0F && (insn[1] == 0x2F || insn[1] == 0x2E)) {
sewardj67e002d2004-12-02 18:16:33 +00007078 IRTemp argL = newTemp(Ity_F32);
7079 IRTemp argR = newTemp(Ity_F32);
sewardj67e002d2004-12-02 18:16:33 +00007080 modrm = getIByte(delta+2);
7081 if (epartIsReg(modrm)) {
7082 assign( argR, getXMMRegLane32F( eregOfRM(modrm), 0/*lowest lane*/ ) );
7083 delta += 2+1;
sewardjc1e7dfc2004-12-05 19:29:45 +00007084 DIP("[u]comiss %s,%s\n", nameXMMReg(eregOfRM(modrm)),
7085 nameXMMReg(gregOfRM(modrm)) );
sewardj67e002d2004-12-02 18:16:33 +00007086 } else {
7087 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
7088 assign( argR, loadLE(Ity_F32, mkexpr(addr)) );
7089 delta += 2+alen;
sewardjc1e7dfc2004-12-05 19:29:45 +00007090 DIP("[u]comiss %s,%s\n", dis_buf,
7091 nameXMMReg(gregOfRM(modrm)) );
sewardj67e002d2004-12-02 18:16:33 +00007092 }
7093 assign( argL, getXMMRegLane32F( gregOfRM(modrm), 0/*lowest lane*/ ) );
7094
7095 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
7096 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
7097 stmt( IRStmt_Put(
7098 OFFB_CC_DEP1,
7099 binop( Iop_And32,
7100 binop(Iop_CmpF64,
7101 unop(Iop_F32toF64,mkexpr(argL)),
7102 unop(Iop_F32toF64,mkexpr(argR))),
7103 mkU32(0x45)
7104 )));
sewardja3b7e3a2005-04-05 01:54:19 +00007105 /* Set NDEP even though it isn't used. This makes redundant-PUT
7106 elimination of previous stores to this field work better. */
7107 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardj67e002d2004-12-02 18:16:33 +00007108 goto decode_success;
7109 }
sewardjc9a43662004-11-30 18:51:59 +00007110
sewardj4cb918d2004-12-03 19:43:31 +00007111 /* 0F 2A = CVTPI2PS -- convert 2 x I32 in mem/mmx to 2 x F32 in low
7112 half xmm */
sewardjfd226452004-12-07 19:02:18 +00007113 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x2A) {
sewardj4cb918d2004-12-03 19:43:31 +00007114 IRTemp arg64 = newTemp(Ity_I64);
7115 IRTemp rmode = newTemp(Ity_I32);
7116 vassert(sz == 4);
7117
7118 modrm = getIByte(delta+2);
7119 do_MMX_preamble();
7120 if (epartIsReg(modrm)) {
7121 assign( arg64, getMMXReg(eregOfRM(modrm)) );
7122 delta += 2+1;
7123 DIP("cvtpi2ps %s,%s\n", nameMMXReg(eregOfRM(modrm)),
7124 nameXMMReg(gregOfRM(modrm)));
7125 } else {
7126 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
7127 assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
7128 delta += 2+alen;
7129 DIP("cvtpi2ps %s,%s\n", dis_buf,
7130 nameXMMReg(gregOfRM(modrm)) );
7131 }
7132
7133 assign( rmode, get_sse_roundingmode() );
7134
7135 putXMMRegLane32F(
sewardj3bca9062004-12-04 14:36:09 +00007136 gregOfRM(modrm), 0,
7137 binop(Iop_F64toF32,
sewardj4cb918d2004-12-03 19:43:31 +00007138 mkexpr(rmode),
sewardj3bca9062004-12-04 14:36:09 +00007139 unop(Iop_I32toF64,
7140 unop(Iop_64to32, mkexpr(arg64)) )) );
sewardj4cb918d2004-12-03 19:43:31 +00007141
7142 putXMMRegLane32F(
7143 gregOfRM(modrm), 1,
sewardj3bca9062004-12-04 14:36:09 +00007144 binop(Iop_F64toF32,
sewardj4cb918d2004-12-03 19:43:31 +00007145 mkexpr(rmode),
sewardj3bca9062004-12-04 14:36:09 +00007146 unop(Iop_I32toF64,
7147 unop(Iop_64HIto32, mkexpr(arg64)) )) );
sewardj4cb918d2004-12-03 19:43:31 +00007148
7149 goto decode_success;
7150 }
7151
7152 /* F3 0F 2A = CVTSI2SS -- convert I32 in mem/ireg to F32 in low
7153 quarter xmm */
7154 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x2A) {
7155 IRTemp arg32 = newTemp(Ity_I32);
7156 IRTemp rmode = newTemp(Ity_I32);
7157 vassert(sz == 4);
7158
7159 modrm = getIByte(delta+3);
sewardj4cb918d2004-12-03 19:43:31 +00007160 if (epartIsReg(modrm)) {
7161 assign( arg32, getIReg(4, eregOfRM(modrm)) );
7162 delta += 3+1;
7163 DIP("cvtsi2ss %s,%s\n", nameIReg(4, eregOfRM(modrm)),
7164 nameXMMReg(gregOfRM(modrm)));
7165 } else {
7166 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
7167 assign( arg32, loadLE(Ity_I32, mkexpr(addr)) );
7168 delta += 3+alen;
7169 DIP("cvtsi2ss %s,%s\n", dis_buf,
7170 nameXMMReg(gregOfRM(modrm)) );
7171 }
7172
7173 assign( rmode, get_sse_roundingmode() );
7174
7175 putXMMRegLane32F(
sewardj3bca9062004-12-04 14:36:09 +00007176 gregOfRM(modrm), 0,
7177 binop(Iop_F64toF32,
7178 mkexpr(rmode),
7179 unop(Iop_I32toF64, mkexpr(arg32)) ) );
sewardj4cb918d2004-12-03 19:43:31 +00007180
7181 goto decode_success;
7182 }
7183
7184 /* 0F 2D = CVTPS2PI -- convert 2 x F32 in mem/low half xmm to 2 x
7185 I32 in mmx, according to prevailing SSE rounding mode */
7186 /* 0F 2C = CVTTPS2PI -- convert 2 x F32 in mem/low half xmm to 2 x
7187 I32 in mmx, rounding towards zero */
sewardjfd226452004-12-07 19:02:18 +00007188 if (sz == 4 && insn[0] == 0x0F && (insn[1] == 0x2D || insn[1] == 0x2C)) {
sewardj4cb918d2004-12-03 19:43:31 +00007189 IRTemp dst64 = newTemp(Ity_I64);
7190 IRTemp rmode = newTemp(Ity_I32);
7191 IRTemp f32lo = newTemp(Ity_F32);
7192 IRTemp f32hi = newTemp(Ity_F32);
sewardj2d49b432005-02-01 00:37:06 +00007193 Bool r2zero = toBool(insn[1] == 0x2C);
sewardj4cb918d2004-12-03 19:43:31 +00007194
7195 do_MMX_preamble();
7196 modrm = getIByte(delta+2);
7197
7198 if (epartIsReg(modrm)) {
7199 delta += 2+1;
7200 assign(f32lo, getXMMRegLane32F(eregOfRM(modrm), 0));
7201 assign(f32hi, getXMMRegLane32F(eregOfRM(modrm), 1));
7202 DIP("cvt%sps2pi %s,%s\n", r2zero ? "t" : "",
7203 nameXMMReg(eregOfRM(modrm)),
7204 nameMMXReg(gregOfRM(modrm)));
7205 } else {
7206 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
7207 assign(f32lo, loadLE(Ity_F32, mkexpr(addr)));
7208 assign(f32hi, loadLE(Ity_F32, binop( Iop_Add32,
7209 mkexpr(addr),
7210 mkU32(4) )));
7211 delta += 2+alen;
7212 DIP("cvt%sps2pi %s,%s\n", r2zero ? "t" : "",
7213 dis_buf,
7214 nameMMXReg(gregOfRM(modrm)));
7215 }
7216
7217 if (r2zero) {
7218 assign(rmode, mkU32((UInt)Irrm_ZERO) );
7219 } else {
7220 assign( rmode, get_sse_roundingmode() );
7221 }
7222
7223 assign(
7224 dst64,
7225 binop( Iop_32HLto64,
7226 binop( Iop_F64toI32,
7227 mkexpr(rmode),
7228 unop( Iop_F32toF64, mkexpr(f32hi) ) ),
7229 binop( Iop_F64toI32,
7230 mkexpr(rmode),
7231 unop( Iop_F32toF64, mkexpr(f32lo) ) )
7232 )
7233 );
7234
7235 putMMXReg(gregOfRM(modrm), mkexpr(dst64));
7236 goto decode_success;
7237 }
7238
7239 /* F3 0F 2D = CVTSS2SI -- convert F32 in mem/low quarter xmm to
7240 I32 in ireg, according to prevailing SSE rounding mode */
7241 /* F3 0F 2C = CVTTSS2SI -- convert F32 in mem/low quarter xmm to
sewardj0b210442005-02-23 13:28:27 +00007242 I32 in ireg, rounding towards zero */
sewardj4cb918d2004-12-03 19:43:31 +00007243 if (insn[0] == 0xF3 && insn[1] == 0x0F
7244 && (insn[2] == 0x2D || insn[2] == 0x2C)) {
7245 IRTemp rmode = newTemp(Ity_I32);
7246 IRTemp f32lo = newTemp(Ity_F32);
sewardj2d49b432005-02-01 00:37:06 +00007247 Bool r2zero = toBool(insn[2] == 0x2C);
sewardj4cb918d2004-12-03 19:43:31 +00007248 vassert(sz == 4);
7249
sewardj4cb918d2004-12-03 19:43:31 +00007250 modrm = getIByte(delta+3);
sewardj4cb918d2004-12-03 19:43:31 +00007251 if (epartIsReg(modrm)) {
7252 delta += 3+1;
7253 assign(f32lo, getXMMRegLane32F(eregOfRM(modrm), 0));
7254 DIP("cvt%sss2si %s,%s\n", r2zero ? "t" : "",
7255 nameXMMReg(eregOfRM(modrm)),
7256 nameIReg(4, gregOfRM(modrm)));
7257 } else {
7258 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
7259 assign(f32lo, loadLE(Ity_F32, mkexpr(addr)));
7260 delta += 3+alen;
7261 DIP("cvt%sss2si %s,%s\n", r2zero ? "t" : "",
7262 dis_buf,
7263 nameIReg(4, gregOfRM(modrm)));
7264 }
7265
7266 if (r2zero) {
sewardj7df596b2004-12-06 14:29:12 +00007267 assign( rmode, mkU32((UInt)Irrm_ZERO) );
sewardj4cb918d2004-12-03 19:43:31 +00007268 } else {
7269 assign( rmode, get_sse_roundingmode() );
7270 }
7271
7272 putIReg(4, gregOfRM(modrm),
7273 binop( Iop_F64toI32,
7274 mkexpr(rmode),
7275 unop( Iop_F32toF64, mkexpr(f32lo) ) )
7276 );
7277
7278 goto decode_success;
7279 }
7280
sewardj176a59c2004-12-03 20:08:31 +00007281 /* 0F 5E = DIVPS -- div 32Fx4 from R/M to R */
sewardjfd226452004-12-07 19:02:18 +00007282 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5E) {
sewardj129b3d92004-12-05 15:42:05 +00007283 delta = dis_SSE_E_to_G_all( sorb, delta+2, "divps", Iop_Div32Fx4 );
sewardj176a59c2004-12-03 20:08:31 +00007284 goto decode_success;
7285 }
7286
7287 /* F3 0F 5E = DIVSS -- div 32F0x4 from R/M to R */
7288 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5E) {
7289 vassert(sz == 4);
sewardj129b3d92004-12-05 15:42:05 +00007290 delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "divss", Iop_Div32F0x4 );
sewardj176a59c2004-12-03 20:08:31 +00007291 goto decode_success;
7292 }
7293
sewardj7df596b2004-12-06 14:29:12 +00007294 /* 0F AE /2 = LDMXCSR m32 -- load %mxcsr */
7295 if (insn[0] == 0x0F && insn[1] == 0xAE
7296 && !epartIsReg(insn[2]) && gregOfRM(insn[2]) == 2) {
7297
7298 IRTemp t64 = newTemp(Ity_I64);
7299 IRTemp ew = newTemp(Ity_I32);
7300
7301 modrm = getIByte(delta+2);
7302 vassert(!epartIsReg(modrm));
7303 vassert(sz == 4);
7304
7305 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
7306 delta += 2+alen;
sewardj33dd31b2005-01-08 18:17:32 +00007307 DIP("ldmxcsr %s\n", dis_buf);
sewardj7df596b2004-12-06 14:29:12 +00007308
7309 /* The only thing we observe in %mxcsr is the rounding mode.
7310 Therefore, pass the 32-bit value (SSE native-format control
7311 word) to a clean helper, getting back a 64-bit value, the
7312 lower half of which is the SSEROUND value to store, and the
7313 upper half of which is the emulation-warning token which may
7314 be generated.
7315 */
7316 /* ULong x86h_check_ldmxcsr ( UInt ); */
7317 assign( t64, mkIRExprCCall(
7318 Ity_I64, 0/*regparms*/,
sewardj3bd6f3e2004-12-13 10:48:19 +00007319 "x86g_check_ldmxcsr",
7320 &x86g_check_ldmxcsr,
sewardj7df596b2004-12-06 14:29:12 +00007321 mkIRExprVec_1( loadLE(Ity_I32, mkexpr(addr)) )
7322 )
7323 );
7324
sewardj636ad762004-12-07 11:16:04 +00007325 put_sse_roundingmode( unop(Iop_64to32, mkexpr(t64)) );
sewardj7df596b2004-12-06 14:29:12 +00007326 assign( ew, unop(Iop_64HIto32, mkexpr(t64) ) );
7327 put_emwarn( mkexpr(ew) );
7328 /* Finally, if an emulation warning was reported, side-exit to
7329 the next insn, reporting the warning, so that Valgrind's
7330 dispatcher sees the warning. */
7331 stmt(
7332 IRStmt_Exit(
7333 binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
7334 Ijk_EmWarn,
sewardj9e6491a2005-07-02 19:24:10 +00007335 IRConst_U32( ((Addr32)guest_EIP_bbstart)+delta)
sewardj7df596b2004-12-06 14:29:12 +00007336 )
7337 );
7338 goto decode_success;
7339 }
7340
sewardj176a59c2004-12-03 20:08:31 +00007341 /* 0F 5F = MAXPS -- max 32Fx4 from R/M to R */
sewardjc2feffc2004-12-08 12:31:22 +00007342 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5F) {
sewardj129b3d92004-12-05 15:42:05 +00007343 delta = dis_SSE_E_to_G_all( sorb, delta+2, "maxps", Iop_Max32Fx4 );
sewardj176a59c2004-12-03 20:08:31 +00007344 goto decode_success;
7345 }
7346
7347 /* F3 0F 5F = MAXSS -- max 32F0x4 from R/M to R */
7348 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5F) {
7349 vassert(sz == 4);
sewardj129b3d92004-12-05 15:42:05 +00007350 delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "maxss", Iop_Max32F0x4 );
sewardj176a59c2004-12-03 20:08:31 +00007351 goto decode_success;
7352 }
7353
7354 /* 0F 5D = MINPS -- min 32Fx4 from R/M to R */
sewardjc2feffc2004-12-08 12:31:22 +00007355 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5D) {
sewardj129b3d92004-12-05 15:42:05 +00007356 delta = dis_SSE_E_to_G_all( sorb, delta+2, "minps", Iop_Min32Fx4 );
sewardj176a59c2004-12-03 20:08:31 +00007357 goto decode_success;
7358 }
7359
7360 /* F3 0F 5D = MINSS -- min 32F0x4 from R/M to R */
7361 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5D) {
7362 vassert(sz == 4);
sewardj129b3d92004-12-05 15:42:05 +00007363 delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "minss", Iop_Min32F0x4 );
sewardj176a59c2004-12-03 20:08:31 +00007364 goto decode_success;
7365 }
sewardj4cb918d2004-12-03 19:43:31 +00007366
sewardj9636b442004-12-04 01:38:37 +00007367 /* 0F 28 = MOVAPS -- move from E (mem or xmm) to G (xmm). */
sewardjc2feffc2004-12-08 12:31:22 +00007368 /* 0F 10 = MOVUPS -- move from E (mem or xmm) to G (xmm). */
7369 if (sz == 4 && insn[0] == 0x0F && (insn[1] == 0x28 || insn[1] == 0x10)) {
sewardj9636b442004-12-04 01:38:37 +00007370 modrm = getIByte(delta+2);
sewardj9636b442004-12-04 01:38:37 +00007371 if (epartIsReg(modrm)) {
7372 putXMMReg( gregOfRM(modrm),
7373 getXMMReg( eregOfRM(modrm) ));
7374 DIP("mov[ua]ps %s,%s\n", nameXMMReg(eregOfRM(modrm)),
7375 nameXMMReg(gregOfRM(modrm)));
7376 delta += 2+1;
7377 } else {
7378 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
7379 putXMMReg( gregOfRM(modrm),
7380 loadLE(Ity_V128, mkexpr(addr)) );
7381 DIP("mov[ua]ps %s,%s\n", dis_buf,
7382 nameXMMReg(gregOfRM(modrm)));
7383 delta += 2+alen;
7384 }
7385 goto decode_success;
7386 }
7387
sewardj09f41552004-12-15 12:35:00 +00007388 /* 0F 29 = MOVAPS -- move from G (xmm) to E (mem or xmm). */
7389 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x29) {
7390 modrm = getIByte(delta+2);
sewardj09f41552004-12-15 12:35:00 +00007391 if (epartIsReg(modrm)) {
7392 /* fall through; awaiting test case */
7393 } else {
7394 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
7395 storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) );
7396 DIP("movaps %s,%s\n", nameXMMReg(gregOfRM(modrm)),
7397 dis_buf );
7398 delta += 2+alen;
7399 goto decode_success;
7400 }
7401 }
7402
sewardj0bd7ce62004-12-05 02:47:40 +00007403 /* 0F 16 = MOVHPS -- move from mem to high half of XMM. */
7404 /* 0F 16 = MOVLHPS -- move from lo half to hi half of XMM. */
sewardjc2feffc2004-12-08 12:31:22 +00007405 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x16) {
sewardj0bd7ce62004-12-05 02:47:40 +00007406 modrm = getIByte(delta+2);
7407 if (epartIsReg(modrm)) {
7408 delta += 2+1;
7409 putXMMRegLane64( gregOfRM(modrm), 1/*upper lane*/,
7410 getXMMRegLane64( eregOfRM(modrm), 0 ) );
7411 DIP("movhps %s,%s\n", nameXMMReg(eregOfRM(modrm)),
7412 nameXMMReg(gregOfRM(modrm)));
7413 } else {
7414 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
7415 delta += 2+alen;
7416 putXMMRegLane64( gregOfRM(modrm), 1/*upper lane*/,
7417 loadLE(Ity_I64, mkexpr(addr)) );
7418 DIP("movhps %s,%s\n", dis_buf,
sewardjc2feffc2004-12-08 12:31:22 +00007419 nameXMMReg( gregOfRM(modrm) ));
sewardj0bd7ce62004-12-05 02:47:40 +00007420 }
7421 goto decode_success;
7422 }
7423
7424 /* 0F 17 = MOVHPS -- move from high half of XMM to mem. */
sewardjc2feffc2004-12-08 12:31:22 +00007425 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x17) {
sewardj0bd7ce62004-12-05 02:47:40 +00007426 if (!epartIsReg(insn[2])) {
sewardj0bd7ce62004-12-05 02:47:40 +00007427 delta += 2;
7428 addr = disAMode ( &alen, sorb, delta, dis_buf );
7429 delta += alen;
7430 storeLE( mkexpr(addr),
7431 getXMMRegLane64( gregOfRM(insn[2]),
7432 1/*upper lane*/ ) );
7433 DIP("movhps %s,%s\n", nameXMMReg( gregOfRM(insn[2]) ),
7434 dis_buf);
7435 goto decode_success;
7436 }
7437 /* else fall through */
7438 }
7439
7440 /* 0F 12 = MOVLPS -- move from mem to low half of XMM. */
7441 /* OF 12 = MOVHLPS -- from from hi half to lo half of XMM. */
sewardjc2feffc2004-12-08 12:31:22 +00007442 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x12) {
sewardj0bd7ce62004-12-05 02:47:40 +00007443 modrm = getIByte(delta+2);
7444 if (epartIsReg(modrm)) {
7445 delta += 2+1;
7446 putXMMRegLane64( gregOfRM(modrm),
7447 0/*lower lane*/,
7448 getXMMRegLane64( eregOfRM(modrm), 1 ));
7449 DIP("movhlps %s, %s\n", nameXMMReg(eregOfRM(modrm)),
7450 nameXMMReg(gregOfRM(modrm)));
7451 } else {
7452 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
7453 delta += 2+alen;
7454 putXMMRegLane64( gregOfRM(modrm), 0/*lower lane*/,
7455 loadLE(Ity_I64, mkexpr(addr)) );
7456 DIP("movlps %s, %s\n",
7457 dis_buf, nameXMMReg( gregOfRM(modrm) ));
7458 }
7459 goto decode_success;
7460 }
7461
7462 /* 0F 13 = MOVLPS -- move from low half of XMM to mem. */
sewardjc2feffc2004-12-08 12:31:22 +00007463 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x13) {
sewardj0bd7ce62004-12-05 02:47:40 +00007464 if (!epartIsReg(insn[2])) {
sewardj0bd7ce62004-12-05 02:47:40 +00007465 delta += 2;
7466 addr = disAMode ( &alen, sorb, delta, dis_buf );
7467 delta += alen;
7468 storeLE( mkexpr(addr),
7469 getXMMRegLane64( gregOfRM(insn[2]),
7470 0/*lower lane*/ ) );
7471 DIP("movlps %s, %s\n", nameXMMReg( gregOfRM(insn[2]) ),
7472 dis_buf);
7473 goto decode_success;
7474 }
7475 /* else fall through */
7476 }
7477
sewardj9636b442004-12-04 01:38:37 +00007478 /* 0F 50 = MOVMSKPS - move 4 sign bits from 4 x F32 in xmm(E)
7479 to 4 lowest bits of ireg(G) */
7480 if (insn[0] == 0x0F && insn[1] == 0x50) {
sewardj9636b442004-12-04 01:38:37 +00007481 modrm = getIByte(delta+2);
sewardjc2feffc2004-12-08 12:31:22 +00007482 if (sz == 4 && epartIsReg(modrm)) {
7483 Int src;
7484 t0 = newTemp(Ity_I32);
7485 t1 = newTemp(Ity_I32);
7486 t2 = newTemp(Ity_I32);
7487 t3 = newTemp(Ity_I32);
sewardj129b3d92004-12-05 15:42:05 +00007488 delta += 2+1;
7489 src = eregOfRM(modrm);
7490 assign( t0, binop( Iop_And32,
7491 binop(Iop_Shr32, getXMMRegLane32(src,0), mkU8(31)),
7492 mkU32(1) ));
7493 assign( t1, binop( Iop_And32,
7494 binop(Iop_Shr32, getXMMRegLane32(src,1), mkU8(30)),
7495 mkU32(2) ));
7496 assign( t2, binop( Iop_And32,
7497 binop(Iop_Shr32, getXMMRegLane32(src,2), mkU8(29)),
7498 mkU32(4) ));
7499 assign( t3, binop( Iop_And32,
7500 binop(Iop_Shr32, getXMMRegLane32(src,3), mkU8(28)),
7501 mkU32(8) ));
7502 putIReg(4, gregOfRM(modrm),
7503 binop(Iop_Or32,
7504 binop(Iop_Or32, mkexpr(t0), mkexpr(t1)),
7505 binop(Iop_Or32, mkexpr(t2), mkexpr(t3))
7506 )
7507 );
7508 DIP("movmskps %s,%s\n", nameXMMReg(src),
7509 nameIReg(4, gregOfRM(modrm)));
7510 goto decode_success;
7511 }
7512 /* else fall through */
sewardj9636b442004-12-04 01:38:37 +00007513 }
7514
7515 /* 0F 2B = MOVNTPS -- for us, just a plain SSE store. */
sewardj703d6d62005-05-11 02:55:00 +00007516 /* 66 0F 2B = MOVNTPD -- for us, just a plain SSE store. */
sewardj9636b442004-12-04 01:38:37 +00007517 if (insn[0] == 0x0F && insn[1] == 0x2B) {
7518 modrm = getIByte(delta+2);
7519 if (!epartIsReg(modrm)) {
7520 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
7521 storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) );
sewardj703d6d62005-05-11 02:55:00 +00007522 DIP("movntp%s %s,%s\n", sz==2 ? "d" : "s",
7523 dis_buf,
7524 nameXMMReg(gregOfRM(modrm)));
sewardj9636b442004-12-04 01:38:37 +00007525 delta += 2+alen;
7526 goto decode_success;
7527 }
7528 /* else fall through */
7529 }
7530
sewardjc2feffc2004-12-08 12:31:22 +00007531 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
sewardj9636b442004-12-04 01:38:37 +00007532 /* 0F E7 = MOVNTQ -- for us, just a plain MMX store. Note, the
7533 Intel manual does not say anything about the usual business of
7534 the FP reg tags getting trashed whenever an MMX insn happens.
7535 So we just leave them alone.
7536 */
7537 if (insn[0] == 0x0F && insn[1] == 0xE7) {
7538 modrm = getIByte(delta+2);
sewardjc2feffc2004-12-08 12:31:22 +00007539 if (sz == 4 && !epartIsReg(modrm)) {
sewardj519d66f2004-12-15 11:57:58 +00007540 /* do_MMX_preamble(); Intel docs don't specify this */
sewardj9636b442004-12-04 01:38:37 +00007541 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
7542 storeLE( mkexpr(addr), getMMXReg(gregOfRM(modrm)) );
7543 DIP("movntq %s,%s\n", dis_buf,
7544 nameMMXReg(gregOfRM(modrm)));
7545 delta += 2+alen;
7546 goto decode_success;
7547 }
7548 /* else fall through */
7549 }
7550
7551 /* F3 0F 10 = MOVSS -- move 32 bits from E (mem or lo 1/4 xmm) to G
7552 (lo 1/4 xmm). If E is mem, upper 3/4 of G is zeroed out. */
7553 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x10) {
7554 vassert(sz == 4);
7555 modrm = getIByte(delta+3);
7556 if (epartIsReg(modrm)) {
7557 putXMMRegLane32( gregOfRM(modrm), 0,
7558 getXMMRegLane32( eregOfRM(modrm), 0 ));
7559 DIP("movss %s,%s\n", nameXMMReg(eregOfRM(modrm)),
7560 nameXMMReg(gregOfRM(modrm)));
7561 delta += 3+1;
7562 } else {
7563 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
sewardjad50db02005-04-06 01:45:44 +00007564 /* zero bits 127:64 */
7565 putXMMRegLane64( gregOfRM(modrm), 1, mkU64(0) );
7566 /* zero bits 63:32 */
7567 putXMMRegLane32( gregOfRM(modrm), 1, mkU32(0) );
7568 /* write bits 31:0 */
sewardj9636b442004-12-04 01:38:37 +00007569 putXMMRegLane32( gregOfRM(modrm), 0,
7570 loadLE(Ity_I32, mkexpr(addr)) );
7571 DIP("movss %s,%s\n", dis_buf,
7572 nameXMMReg(gregOfRM(modrm)));
7573 delta += 3+alen;
7574 }
7575 goto decode_success;
7576 }
7577
7578 /* F3 0F 11 = MOVSS -- move 32 bits from G (lo 1/4 xmm) to E (mem
7579 or lo 1/4 xmm). */
7580 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x11) {
7581 vassert(sz == 4);
7582 modrm = getIByte(delta+3);
7583 if (epartIsReg(modrm)) {
7584 /* fall through, we don't yet have a test case */
7585 } else {
7586 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
7587 storeLE( mkexpr(addr),
sewardj519d66f2004-12-15 11:57:58 +00007588 getXMMRegLane32(gregOfRM(modrm), 0) );
7589 DIP("movss %s,%s\n", nameXMMReg(gregOfRM(modrm)),
sewardj9636b442004-12-04 01:38:37 +00007590 dis_buf);
7591 delta += 3+alen;
7592 goto decode_success;
7593 }
7594 }
7595
7596 /* 0F 59 = MULPS -- mul 32Fx4 from R/M to R */
sewardj008754b2004-12-08 14:37:10 +00007597 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x59) {
sewardj129b3d92004-12-05 15:42:05 +00007598 delta = dis_SSE_E_to_G_all( sorb, delta+2, "mulps", Iop_Mul32Fx4 );
sewardj9636b442004-12-04 01:38:37 +00007599 goto decode_success;
7600 }
7601
7602 /* F3 0F 59 = MULSS -- mul 32F0x4 from R/M to R */
7603 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x59) {
7604 vassert(sz == 4);
sewardj129b3d92004-12-05 15:42:05 +00007605 delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "mulss", Iop_Mul32F0x4 );
sewardj9636b442004-12-04 01:38:37 +00007606 goto decode_success;
7607 }
7608
7609 /* 0F 56 = ORPS -- G = G and E */
sewardj008754b2004-12-08 14:37:10 +00007610 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x56) {
sewardjf0c1c582005-02-07 23:47:38 +00007611 delta = dis_SSE_E_to_G_all( sorb, delta+2, "orps", Iop_OrV128 );
sewardj9636b442004-12-04 01:38:37 +00007612 goto decode_success;
7613 }
7614
sewardj3bca9062004-12-04 14:36:09 +00007615 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
7616 /* 0F E0 = PAVGB -- 8x8 unsigned Packed Average, with rounding */
sewardj164f9272004-12-09 00:39:32 +00007617 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xE0) {
sewardjb5452082004-12-04 20:33:02 +00007618 do_MMX_preamble();
7619 delta = dis_MMXop_regmem_to_reg (
7620 sorb, delta+2, insn[1], "pavgb", False );
7621 goto decode_success;
sewardj3bca9062004-12-04 14:36:09 +00007622 }
7623
sewardjb5452082004-12-04 20:33:02 +00007624 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
7625 /* 0F E3 = PAVGW -- 16x4 unsigned Packed Average, with rounding */
sewardj164f9272004-12-09 00:39:32 +00007626 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xE3) {
sewardjb5452082004-12-04 20:33:02 +00007627 do_MMX_preamble();
7628 delta = dis_MMXop_regmem_to_reg (
7629 sorb, delta+2, insn[1], "pavgw", False );
7630 goto decode_success;
7631 }
7632
7633 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
7634 /* 0F C5 = PEXTRW -- extract 16-bit field from mmx(E) and put
7635 zero-extend of it in ireg(G). */
7636 if (insn[0] == 0x0F && insn[1] == 0xC5) {
7637 modrm = insn[2];
7638 if (sz == 4 && epartIsReg(modrm)) {
sewardjb9fa69b2004-12-09 23:25:14 +00007639 IRTemp sV = newTemp(Ity_I64);
7640 t5 = newTemp(Ity_I16);
sewardjb5452082004-12-04 20:33:02 +00007641 do_MMX_preamble();
sewardjb9fa69b2004-12-09 23:25:14 +00007642 assign(sV, getMMXReg(eregOfRM(modrm)));
7643 breakup64to16s( sV, &t3, &t2, &t1, &t0 );
sewardjb5452082004-12-04 20:33:02 +00007644 switch (insn[3] & 3) {
sewardjb9fa69b2004-12-09 23:25:14 +00007645 case 0: assign(t5, mkexpr(t0)); break;
7646 case 1: assign(t5, mkexpr(t1)); break;
7647 case 2: assign(t5, mkexpr(t2)); break;
7648 case 3: assign(t5, mkexpr(t3)); break;
sewardjba89f4c2005-04-07 17:31:27 +00007649 default: vassert(0); /*NOTREACHED*/
sewardjb5452082004-12-04 20:33:02 +00007650 }
sewardjb9fa69b2004-12-09 23:25:14 +00007651 putIReg(4, gregOfRM(modrm), unop(Iop_16Uto32, mkexpr(t5)));
sewardjb5452082004-12-04 20:33:02 +00007652 DIP("pextrw $%d,%s,%s\n",
7653 (Int)insn[3], nameMMXReg(eregOfRM(modrm)),
7654 nameIReg(4,gregOfRM(modrm)));
7655 delta += 4;
7656 goto decode_success;
7657 }
7658 /* else fall through */
7659 }
7660
7661 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
7662 /* 0F C4 = PINSRW -- get 16 bits from E(mem or low half ireg) and
7663 put it into the specified lane of mmx(G). */
sewardje5854d62004-12-09 03:44:34 +00007664 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xC4) {
7665 /* Use t0 .. t3 to hold the 4 original 16-bit lanes of the
7666 mmx reg. t4 is the new lane value. t5 is the original
7667 mmx value. t6 is the new mmx value. */
7668 Int lane;
sewardje5854d62004-12-09 03:44:34 +00007669 t4 = newTemp(Ity_I16);
7670 t5 = newTemp(Ity_I64);
7671 t6 = newTemp(Ity_I64);
7672 modrm = insn[2];
7673 do_MMX_preamble();
sewardjb5452082004-12-04 20:33:02 +00007674
sewardje5854d62004-12-09 03:44:34 +00007675 assign(t5, getMMXReg(gregOfRM(modrm)));
sewardjb9fa69b2004-12-09 23:25:14 +00007676 breakup64to16s( t5, &t3, &t2, &t1, &t0 );
sewardjb5452082004-12-04 20:33:02 +00007677
sewardje5854d62004-12-09 03:44:34 +00007678 if (epartIsReg(modrm)) {
7679 assign(t4, getIReg(2, eregOfRM(modrm)));
sewardjaac7e082005-03-17 14:03:46 +00007680 delta += 3+1;
7681 lane = insn[3+1-1];
sewardje5854d62004-12-09 03:44:34 +00007682 DIP("pinsrw $%d,%s,%s\n", (Int)lane,
7683 nameIReg(2,eregOfRM(modrm)),
7684 nameMMXReg(gregOfRM(modrm)));
7685 } else {
sewardj7420b092005-03-13 20:19:19 +00007686 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
7687 delta += 3+alen;
7688 lane = insn[3+alen-1];
7689 assign(t4, loadLE(Ity_I16, mkexpr(addr)));
7690 DIP("pinsrw $%d,%s,%s\n", (Int)lane,
7691 dis_buf,
7692 nameMMXReg(gregOfRM(modrm)));
sewardjb5452082004-12-04 20:33:02 +00007693 }
sewardje5854d62004-12-09 03:44:34 +00007694
7695 switch (lane & 3) {
sewardjb9fa69b2004-12-09 23:25:14 +00007696 case 0: assign(t6, mk64from16s(t3,t2,t1,t4)); break;
7697 case 1: assign(t6, mk64from16s(t3,t2,t4,t0)); break;
7698 case 2: assign(t6, mk64from16s(t3,t4,t1,t0)); break;
7699 case 3: assign(t6, mk64from16s(t4,t2,t1,t0)); break;
sewardjba89f4c2005-04-07 17:31:27 +00007700 default: vassert(0); /*NOTREACHED*/
sewardje5854d62004-12-09 03:44:34 +00007701 }
7702 putMMXReg(gregOfRM(modrm), mkexpr(t6));
7703 goto decode_success;
sewardjb5452082004-12-04 20:33:02 +00007704 }
7705
7706 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
7707 /* 0F EE = PMAXSW -- 16x4 signed max */
sewardje5854d62004-12-09 03:44:34 +00007708 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xEE) {
sewardjb5452082004-12-04 20:33:02 +00007709 do_MMX_preamble();
7710 delta = dis_MMXop_regmem_to_reg (
7711 sorb, delta+2, insn[1], "pmaxsw", False );
7712 goto decode_success;
7713 }
7714
7715 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
7716 /* 0F DE = PMAXUB -- 8x8 unsigned max */
sewardje5854d62004-12-09 03:44:34 +00007717 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xDE) {
sewardjb5452082004-12-04 20:33:02 +00007718 do_MMX_preamble();
7719 delta = dis_MMXop_regmem_to_reg (
7720 sorb, delta+2, insn[1], "pmaxub", False );
7721 goto decode_success;
7722 }
7723
7724 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
7725 /* 0F EA = PMINSW -- 16x4 signed min */
sewardje5854d62004-12-09 03:44:34 +00007726 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xEA) {
sewardjb5452082004-12-04 20:33:02 +00007727 do_MMX_preamble();
7728 delta = dis_MMXop_regmem_to_reg (
7729 sorb, delta+2, insn[1], "pminsw", False );
7730 goto decode_success;
7731 }
7732
7733 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
7734 /* 0F DA = PMINUB -- 8x8 unsigned min */
sewardje5854d62004-12-09 03:44:34 +00007735 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xDA) {
sewardjb5452082004-12-04 20:33:02 +00007736 do_MMX_preamble();
7737 delta = dis_MMXop_regmem_to_reg (
7738 sorb, delta+2, insn[1], "pminub", False );
7739 goto decode_success;
7740 }
7741
7742 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
7743 /* 0F D7 = PMOVMSKB -- extract sign bits from each of 8 lanes in
7744 mmx(G), turn them into a byte, and put zero-extend of it in
7745 ireg(G). */
sewardje5854d62004-12-09 03:44:34 +00007746 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xD7) {
sewardjb5452082004-12-04 20:33:02 +00007747 modrm = insn[2];
sewardje5854d62004-12-09 03:44:34 +00007748 if (epartIsReg(modrm)) {
sewardjb5452082004-12-04 20:33:02 +00007749 do_MMX_preamble();
7750 t0 = newTemp(Ity_I64);
7751 t1 = newTemp(Ity_I32);
7752 assign(t0, getMMXReg(eregOfRM(modrm)));
7753 assign(t1, mkIRExprCCall(
7754 Ity_I32, 0/*regparms*/,
sewardj38a3f862005-01-13 15:06:51 +00007755 "x86g_calculate_mmx_pmovmskb",
7756 &x86g_calculate_mmx_pmovmskb,
sewardjb5452082004-12-04 20:33:02 +00007757 mkIRExprVec_1(mkexpr(t0))));
7758 putIReg(4, gregOfRM(modrm), mkexpr(t1));
7759 DIP("pmovmskb %s,%s\n", nameMMXReg(eregOfRM(modrm)),
7760 nameIReg(4,gregOfRM(modrm)));
7761 delta += 3;
7762 goto decode_success;
7763 }
7764 /* else fall through */
7765 }
7766
sewardj0bd7ce62004-12-05 02:47:40 +00007767 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
7768 /* 0F E4 = PMULUH -- 16x4 hi-half of unsigned widening multiply */
sewardje5854d62004-12-09 03:44:34 +00007769 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xE4) {
sewardj0bd7ce62004-12-05 02:47:40 +00007770 do_MMX_preamble();
7771 delta = dis_MMXop_regmem_to_reg (
7772 sorb, delta+2, insn[1], "pmuluh", False );
7773 goto decode_success;
7774 }
7775
sewardj7df596b2004-12-06 14:29:12 +00007776 /* 0F 18 /0 = PREFETCHNTA -- prefetch into caches, */
7777 /* 0F 18 /1 = PREFETCH0 -- with various different hints */
7778 /* 0F 18 /2 = PREFETCH1 */
7779 /* 0F 18 /3 = PREFETCH2 */
7780 if (insn[0] == 0x0F && insn[1] == 0x18
7781 && !epartIsReg(insn[2])
7782 && gregOfRM(insn[2]) >= 0 && gregOfRM(insn[2]) <= 3) {
7783 HChar* hintstr = "??";
7784
7785 modrm = getIByte(delta+2);
7786 vassert(!epartIsReg(modrm));
7787
7788 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
7789 delta += 2+alen;
7790
7791 switch (gregOfRM(modrm)) {
7792 case 0: hintstr = "nta"; break;
7793 case 1: hintstr = "t0"; break;
7794 case 2: hintstr = "t1"; break;
7795 case 3: hintstr = "t2"; break;
sewardjba89f4c2005-04-07 17:31:27 +00007796 default: vassert(0); /*NOTREACHED*/
sewardj7df596b2004-12-06 14:29:12 +00007797 }
7798
7799 DIP("prefetch%s %s\n", hintstr, dis_buf);
7800 goto decode_success;
7801 }
7802
sewardj0bd7ce62004-12-05 02:47:40 +00007803 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
7804 /* 0F F6 = PSADBW -- sum of 8Ux8 absolute differences */
7805 if (insn[0] == 0x0F && insn[1] == 0xF6) {
7806 vassert(sz == 4);
7807 do_MMX_preamble();
7808 delta = dis_MMXop_regmem_to_reg (
7809 sorb, delta+2, insn[1], "psadbw", False );
7810 goto decode_success;
7811 }
7812
7813 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
7814 /* 0F 70 = PSHUFW -- rearrange 4x16 from E(mmx or mem) to G(mmx) */
sewardjb9fa69b2004-12-09 23:25:14 +00007815 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x70) {
sewardj0bd7ce62004-12-05 02:47:40 +00007816 Int order;
sewardjb9fa69b2004-12-09 23:25:14 +00007817 IRTemp sV, dV, s3, s2, s1, s0;
7818 s3 = s2 = s1 = s0 = IRTemp_INVALID;
7819 sV = newTemp(Ity_I64);
7820 dV = newTemp(Ity_I64);
sewardj0bd7ce62004-12-05 02:47:40 +00007821 do_MMX_preamble();
7822 modrm = insn[2];
7823 if (epartIsReg(modrm)) {
sewardjb9fa69b2004-12-09 23:25:14 +00007824 assign( sV, getMMXReg(eregOfRM(modrm)) );
sewardj0bd7ce62004-12-05 02:47:40 +00007825 order = (Int)insn[3];
7826 delta += 2+2;
7827 DIP("pshufw $%d,%s,%s\n", order,
7828 nameMMXReg(eregOfRM(modrm)),
7829 nameMMXReg(gregOfRM(modrm)));
7830 } else {
7831 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
sewardjb9fa69b2004-12-09 23:25:14 +00007832 assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
sewardj0bd7ce62004-12-05 02:47:40 +00007833 order = (Int)insn[2+alen];
7834 delta += 3+alen;
7835 DIP("pshufw $%d,%s,%s\n", order,
7836 dis_buf,
7837 nameMMXReg(gregOfRM(modrm)));
7838 }
sewardjb9fa69b2004-12-09 23:25:14 +00007839 breakup64to16s( sV, &s3, &s2, &s1, &s0 );
sewardj0bd7ce62004-12-05 02:47:40 +00007840
sewardjb9fa69b2004-12-09 23:25:14 +00007841# define SEL(n) \
7842 ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
7843 assign(dV,
7844 mk64from16s( SEL((order>>6)&3), SEL((order>>4)&3),
7845 SEL((order>>2)&3), SEL((order>>0)&3) )
sewardj0bd7ce62004-12-05 02:47:40 +00007846 );
sewardjb9fa69b2004-12-09 23:25:14 +00007847 putMMXReg(gregOfRM(modrm), mkexpr(dV));
sewardj0bd7ce62004-12-05 02:47:40 +00007848# undef SEL
sewardj0bd7ce62004-12-05 02:47:40 +00007849 goto decode_success;
7850 }
7851
7852 /* 0F 53 = RCPPS -- approx reciprocal 32Fx4 from R/M to R */
7853 if (insn[0] == 0x0F && insn[1] == 0x53) {
7854 vassert(sz == 4);
sewardj129b3d92004-12-05 15:42:05 +00007855 delta = dis_SSE_E_to_G_unary_all( sorb, delta+2,
7856 "rcpps", Iop_Recip32Fx4 );
sewardj0bd7ce62004-12-05 02:47:40 +00007857 goto decode_success;
7858 }
7859
7860 /* F3 0F 53 = RCPSS -- approx reciprocal 32F0x4 from R/M to R */
7861 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x53) {
7862 vassert(sz == 4);
sewardj129b3d92004-12-05 15:42:05 +00007863 delta = dis_SSE_E_to_G_unary_lo32( sorb, delta+3,
7864 "rcpss", Iop_Recip32F0x4 );
sewardj0bd7ce62004-12-05 02:47:40 +00007865 goto decode_success;
7866 }
sewardjb5452082004-12-04 20:33:02 +00007867
sewardjc1e7dfc2004-12-05 19:29:45 +00007868 /* 0F 52 = RSQRTPS -- approx reciprocal sqrt 32Fx4 from R/M to R */
7869 if (insn[0] == 0x0F && insn[1] == 0x52) {
7870 vassert(sz == 4);
7871 delta = dis_SSE_E_to_G_unary_all( sorb, delta+2,
7872 "rsqrtps", Iop_RSqrt32Fx4 );
7873 goto decode_success;
7874 }
7875
7876 /* F3 0F 52 = RSQRTSS -- approx reciprocal sqrt 32F0x4 from R/M to R */
7877 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x52) {
7878 vassert(sz == 4);
7879 delta = dis_SSE_E_to_G_unary_lo32( sorb, delta+3,
7880 "rsqrtss", Iop_RSqrt32F0x4 );
7881 goto decode_success;
7882 }
7883
7884 /* 0F AE /7 = SFENCE -- flush pending operations to memory */
7885 if (insn[0] == 0x0F && insn[1] == 0xAE
sewardjc2feffc2004-12-08 12:31:22 +00007886 && epartIsReg(insn[2]) && gregOfRM(insn[2]) == 7) {
sewardjc1e7dfc2004-12-05 19:29:45 +00007887 vassert(sz == 4);
7888 delta += 3;
sewardj3e838932005-01-07 12:09:15 +00007889 /* Insert a memory fence. It's sometimes important that these
7890 are carried through to the generated code. */
7891 stmt( IRStmt_MFence() );
sewardjc1e7dfc2004-12-05 19:29:45 +00007892 DIP("sfence\n");
7893 goto decode_success;
7894 }
7895
7896 /* 0F C6 /r ib = SHUFPS -- shuffle packed F32s */
sewardj008754b2004-12-08 14:37:10 +00007897 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xC6) {
sewardjc1e7dfc2004-12-05 19:29:45 +00007898 Int select;
7899 IRTemp sV, dV;
7900 IRTemp s3, s2, s1, s0, d3, d2, d1, d0;
7901 sV = newTemp(Ity_V128);
7902 dV = newTemp(Ity_V128);
7903 s3 = s2 = s1 = s0 = d3 = d2 = d1 = d0 = IRTemp_INVALID;
sewardjc1e7dfc2004-12-05 19:29:45 +00007904 modrm = insn[2];
7905 assign( dV, getXMMReg(gregOfRM(modrm)) );
7906
7907 if (epartIsReg(modrm)) {
7908 assign( sV, getXMMReg(eregOfRM(modrm)) );
7909 select = (Int)insn[3];
7910 delta += 2+2;
7911 DIP("shufps $%d,%s,%s\n", select,
7912 nameXMMReg(eregOfRM(modrm)),
7913 nameXMMReg(gregOfRM(modrm)));
7914 } else {
7915 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
7916 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
7917 select = (Int)insn[2+alen];
7918 delta += 3+alen;
7919 DIP("shufps $%d,%s,%s\n", select,
7920 dis_buf,
7921 nameXMMReg(gregOfRM(modrm)));
7922 }
7923
7924 breakup128to32s( dV, &d3, &d2, &d1, &d0 );
7925 breakup128to32s( sV, &s3, &s2, &s1, &s0 );
7926
7927# define SELD(n) ((n)==0 ? d0 : ((n)==1 ? d1 : ((n)==2 ? d2 : d3)))
7928# define SELS(n) ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
7929
7930 putXMMReg(
7931 gregOfRM(modrm),
7932 mk128from32s( SELS((select>>6)&3), SELS((select>>4)&3),
7933 SELD((select>>2)&3), SELD((select>>0)&3) )
7934 );
7935
7936# undef SELD
7937# undef SELS
7938
7939 goto decode_success;
7940 }
7941
7942 /* 0F 51 = SQRTPS -- approx sqrt 32Fx4 from R/M to R */
sewardj008754b2004-12-08 14:37:10 +00007943 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x51) {
sewardjc1e7dfc2004-12-05 19:29:45 +00007944 delta = dis_SSE_E_to_G_unary_all( sorb, delta+2,
7945 "sqrtps", Iop_Sqrt32Fx4 );
7946 goto decode_success;
7947 }
7948
7949 /* F3 0F 51 = SQRTSS -- approx sqrt 32F0x4 from R/M to R */
7950 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x51) {
7951 vassert(sz == 4);
7952 delta = dis_SSE_E_to_G_unary_lo32( sorb, delta+3,
7953 "sqrtss", Iop_Sqrt32F0x4 );
7954 goto decode_success;
7955 }
7956
sewardja0e83b02005-01-06 12:36:38 +00007957 /* 0F AE /3 = STMXCSR m32 -- store %mxcsr */
sewardj7df596b2004-12-06 14:29:12 +00007958 if (insn[0] == 0x0F && insn[1] == 0xAE
7959 && !epartIsReg(insn[2]) && gregOfRM(insn[2]) == 3) {
7960 modrm = getIByte(delta+2);
7961 vassert(sz == 4);
7962 vassert(!epartIsReg(modrm));
7963
7964 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
7965 delta += 2+alen;
7966
7967 /* Fake up a native SSE mxcsr word. The only thing it depends
7968 on is SSEROUND[1:0], so call a clean helper to cook it up.
7969 */
7970 /* UInt x86h_create_mxcsr ( UInt sseround ) */
sewardj33dd31b2005-01-08 18:17:32 +00007971 DIP("stmxcsr %s\n", dis_buf);
sewardj7df596b2004-12-06 14:29:12 +00007972 storeLE( mkexpr(addr),
7973 mkIRExprCCall(
7974 Ity_I32, 0/*regp*/,
sewardj3bd6f3e2004-12-13 10:48:19 +00007975 "x86g_create_mxcsr", &x86g_create_mxcsr,
sewardja0e83b02005-01-06 12:36:38 +00007976 mkIRExprVec_1( get_sse_roundingmode() )
sewardj7df596b2004-12-06 14:29:12 +00007977 )
7978 );
7979 goto decode_success;
7980 }
7981
sewardjc1e7dfc2004-12-05 19:29:45 +00007982 /* 0F 5C = SUBPS -- sub 32Fx4 from R/M to R */
sewardj008754b2004-12-08 14:37:10 +00007983 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5C) {
sewardjc1e7dfc2004-12-05 19:29:45 +00007984 delta = dis_SSE_E_to_G_all( sorb, delta+2, "subps", Iop_Sub32Fx4 );
7985 goto decode_success;
7986 }
7987
sewardj008754b2004-12-08 14:37:10 +00007988 /* F3 0F 5C = SUBSS -- sub 32F0x4 from R/M to R */
sewardjc1e7dfc2004-12-05 19:29:45 +00007989 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5C) {
7990 vassert(sz == 4);
7991 delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "subss", Iop_Sub32F0x4 );
7992 goto decode_success;
7993 }
7994
7995 /* 0F 15 = UNPCKHPS -- unpack and interleave high part F32s */
7996 /* 0F 14 = UNPCKLPS -- unpack and interleave low part F32s */
7997 /* These just appear to be special cases of SHUFPS */
sewardj008754b2004-12-08 14:37:10 +00007998 if (sz == 4 && insn[0] == 0x0F && (insn[1] == 0x15 || insn[1] == 0x14)) {
sewardjc1e7dfc2004-12-05 19:29:45 +00007999 IRTemp sV, dV;
8000 IRTemp s3, s2, s1, s0, d3, d2, d1, d0;
sewardj2d49b432005-02-01 00:37:06 +00008001 Bool hi = toBool(insn[1] == 0x15);
sewardjc1e7dfc2004-12-05 19:29:45 +00008002 sV = newTemp(Ity_V128);
8003 dV = newTemp(Ity_V128);
8004 s3 = s2 = s1 = s0 = d3 = d2 = d1 = d0 = IRTemp_INVALID;
sewardjc1e7dfc2004-12-05 19:29:45 +00008005 modrm = insn[2];
8006 assign( dV, getXMMReg(gregOfRM(modrm)) );
8007
8008 if (epartIsReg(modrm)) {
8009 assign( sV, getXMMReg(eregOfRM(modrm)) );
8010 delta += 2+1;
8011 DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
8012 nameXMMReg(eregOfRM(modrm)),
8013 nameXMMReg(gregOfRM(modrm)));
8014 } else {
8015 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8016 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
8017 delta += 2+alen;
8018 DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
8019 dis_buf,
8020 nameXMMReg(gregOfRM(modrm)));
8021 }
8022
8023 breakup128to32s( dV, &d3, &d2, &d1, &d0 );
8024 breakup128to32s( sV, &s3, &s2, &s1, &s0 );
8025
8026 if (hi) {
8027 putXMMReg( gregOfRM(modrm), mk128from32s( s3, d3, s2, d2 ) );
8028 } else {
8029 putXMMReg( gregOfRM(modrm), mk128from32s( s1, d1, s0, d0 ) );
8030 }
8031
8032 goto decode_success;
8033 }
8034
8035 /* 0F 57 = XORPS -- G = G and E */
sewardj008754b2004-12-08 14:37:10 +00008036 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x57) {
sewardjf0c1c582005-02-07 23:47:38 +00008037 delta = dis_SSE_E_to_G_all( sorb, delta+2, "xorps", Iop_XorV128 );
sewardjc1e7dfc2004-12-05 19:29:45 +00008038 goto decode_success;
8039 }
8040
sewardj636ad762004-12-07 11:16:04 +00008041 /* ---------------------------------------------------- */
8042 /* --- end of the SSE decoder. --- */
8043 /* ---------------------------------------------------- */
8044
8045 /* ---------------------------------------------------- */
8046 /* --- start of the SSE2 decoder. --- */
8047 /* ---------------------------------------------------- */
8048
sewardj9df271d2004-12-31 22:37:42 +00008049 /* Skip parts of the decoder which don't apply given the stated
8050 guest subarchitecture. */
sewardj27e1dd62005-06-30 11:49:14 +00008051 if (archinfo->subarch == VexSubArchX86_sse0
8052 || archinfo->subarch == VexSubArchX86_sse1)
sewardj9df271d2004-12-31 22:37:42 +00008053 goto after_sse_decoders;
8054
sewardj636ad762004-12-07 11:16:04 +00008055 insn = (UChar*)&guest_code[delta];
8056
8057 /* 66 0F 58 = ADDPD -- add 32Fx4 from R/M to R */
8058 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x58) {
8059 delta = dis_SSE_E_to_G_all( sorb, delta+2, "addpd", Iop_Add64Fx2 );
8060 goto decode_success;
8061 }
8062
8063 /* F2 0F 58 = ADDSD -- add 64F0x2 from R/M to R */
8064 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x58) {
8065 vassert(sz == 4);
8066 delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "addsd", Iop_Add64F0x2 );
8067 goto decode_success;
8068 }
8069
8070 /* 66 0F 55 = ANDNPD -- G = (not G) and E */
8071 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x55) {
sewardjf0c1c582005-02-07 23:47:38 +00008072 delta = dis_SSE_E_to_G_all_invG( sorb, delta+2, "andnpd", Iop_AndV128 );
sewardj636ad762004-12-07 11:16:04 +00008073 goto decode_success;
8074 }
8075
8076 /* 66 0F 54 = ANDPD -- G = G and E */
8077 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x54) {
sewardjf0c1c582005-02-07 23:47:38 +00008078 delta = dis_SSE_E_to_G_all( sorb, delta+2, "andpd", Iop_AndV128 );
sewardj636ad762004-12-07 11:16:04 +00008079 goto decode_success;
8080 }
8081
sewardjfd226452004-12-07 19:02:18 +00008082 /* 66 0F C2 = CMPPD -- 64Fx2 comparison from R/M to R */
8083 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xC2) {
8084 delta = dis_SSEcmp_E_to_G( sorb, delta+2, "cmppd", True, 8 );
8085 goto decode_success;
8086 }
8087
8088 /* F2 0F C2 = CMPSD -- 64F0x2 comparison from R/M to R */
8089 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0xC2) {
8090 vassert(sz == 4);
8091 delta = dis_SSEcmp_E_to_G( sorb, delta+3, "cmpsd", False, 8 );
8092 goto decode_success;
8093 }
8094
8095 /* 66 0F 2F = COMISD -- 64F0x2 comparison G,E, and set ZCP */
8096 /* 66 0F 2E = UCOMISD -- 64F0x2 comparison G,E, and set ZCP */
8097 if (sz == 2 && insn[0] == 0x0F && (insn[1] == 0x2F || insn[1] == 0x2E)) {
8098 IRTemp argL = newTemp(Ity_F64);
8099 IRTemp argR = newTemp(Ity_F64);
8100 modrm = getIByte(delta+2);
8101 if (epartIsReg(modrm)) {
8102 assign( argR, getXMMRegLane64F( eregOfRM(modrm), 0/*lowest lane*/ ) );
8103 delta += 2+1;
8104 DIP("[u]comisd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
8105 nameXMMReg(gregOfRM(modrm)) );
8106 } else {
8107 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8108 assign( argR, loadLE(Ity_F64, mkexpr(addr)) );
8109 delta += 2+alen;
8110 DIP("[u]comisd %s,%s\n", dis_buf,
8111 nameXMMReg(gregOfRM(modrm)) );
8112 }
8113 assign( argL, getXMMRegLane64F( gregOfRM(modrm), 0/*lowest lane*/ ) );
8114
8115 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
8116 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
8117 stmt( IRStmt_Put(
8118 OFFB_CC_DEP1,
8119 binop( Iop_And32,
8120 binop(Iop_CmpF64, mkexpr(argL), mkexpr(argR)),
8121 mkU32(0x45)
8122 )));
sewardja3b7e3a2005-04-05 01:54:19 +00008123 /* Set NDEP even though it isn't used. This makes redundant-PUT
8124 elimination of previous stores to this field work better. */
8125 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardjfd226452004-12-07 19:02:18 +00008126 goto decode_success;
8127 }
8128
8129 /* F3 0F E6 = CVTDQ2PD -- convert 2 x I32 in mem/lo half xmm to 2 x
8130 F64 in xmm(G) */
8131 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0xE6) {
8132 IRTemp arg64 = newTemp(Ity_I64);
8133 vassert(sz == 4);
8134
8135 modrm = getIByte(delta+3);
8136 if (epartIsReg(modrm)) {
8137 assign( arg64, getXMMRegLane64(eregOfRM(modrm), 0) );
8138 delta += 3+1;
8139 DIP("cvtdq2pd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
8140 nameXMMReg(gregOfRM(modrm)));
8141 } else {
8142 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
8143 assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
8144 delta += 3+alen;
8145 DIP("cvtdq2pd %s,%s\n", dis_buf,
8146 nameXMMReg(gregOfRM(modrm)) );
8147 }
8148
8149 putXMMRegLane64F(
8150 gregOfRM(modrm), 0,
8151 unop(Iop_I32toF64, unop(Iop_64to32, mkexpr(arg64)))
8152 );
8153
8154 putXMMRegLane64F(
8155 gregOfRM(modrm), 1,
8156 unop(Iop_I32toF64, unop(Iop_64HIto32, mkexpr(arg64)))
8157 );
8158
8159 goto decode_success;
8160 }
8161
8162 /* 0F 5B = CVTDQ2PS -- convert 4 x I32 in mem/xmm to 4 x F32 in
8163 xmm(G) */
8164 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5B) {
8165 IRTemp argV = newTemp(Ity_V128);
8166 IRTemp rmode = newTemp(Ity_I32);
8167
8168 modrm = getIByte(delta+2);
8169 if (epartIsReg(modrm)) {
8170 assign( argV, getXMMReg(eregOfRM(modrm)) );
8171 delta += 2+1;
8172 DIP("cvtdq2ps %s,%s\n", nameXMMReg(eregOfRM(modrm)),
8173 nameXMMReg(gregOfRM(modrm)));
8174 } else {
8175 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8176 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
8177 delta += 2+alen;
8178 DIP("cvtdq2ps %s,%s\n", dis_buf,
8179 nameXMMReg(gregOfRM(modrm)) );
8180 }
8181
8182 assign( rmode, get_sse_roundingmode() );
8183 breakup128to32s( argV, &t3, &t2, &t1, &t0 );
8184
8185# define CVT(_t) binop( Iop_F64toF32, \
8186 mkexpr(rmode), \
8187 unop(Iop_I32toF64,mkexpr(_t)))
8188
8189 putXMMRegLane32F( gregOfRM(modrm), 3, CVT(t3) );
8190 putXMMRegLane32F( gregOfRM(modrm), 2, CVT(t2) );
8191 putXMMRegLane32F( gregOfRM(modrm), 1, CVT(t1) );
8192 putXMMRegLane32F( gregOfRM(modrm), 0, CVT(t0) );
8193
8194# undef CVT
8195
8196 goto decode_success;
8197 }
8198
8199 /* F2 0F E6 = CVTPD2DQ -- convert 2 x F64 in mem/xmm to 2 x I32 in
8200 lo half xmm(G), and zero upper half */
8201 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0xE6) {
8202 IRTemp argV = newTemp(Ity_V128);
8203 IRTemp rmode = newTemp(Ity_I32);
8204 vassert(sz == 4);
8205
8206 modrm = getIByte(delta+3);
8207 if (epartIsReg(modrm)) {
8208 assign( argV, getXMMReg(eregOfRM(modrm)) );
8209 delta += 3+1;
8210 DIP("cvtpd2dq %s,%s\n", nameXMMReg(eregOfRM(modrm)),
8211 nameXMMReg(gregOfRM(modrm)));
8212 } else {
8213 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
8214 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
8215 delta += 3+alen;
8216 DIP("cvtpd2dq %s,%s\n", dis_buf,
8217 nameXMMReg(gregOfRM(modrm)) );
8218 }
8219
8220 assign( rmode, get_sse_roundingmode() );
8221 t0 = newTemp(Ity_F64);
8222 t1 = newTemp(Ity_F64);
8223 assign( t0, unop(Iop_ReinterpI64asF64,
sewardjf0c1c582005-02-07 23:47:38 +00008224 unop(Iop_V128to64, mkexpr(argV))) );
sewardjfd226452004-12-07 19:02:18 +00008225 assign( t1, unop(Iop_ReinterpI64asF64,
sewardjf0c1c582005-02-07 23:47:38 +00008226 unop(Iop_V128HIto64, mkexpr(argV))) );
sewardjfd226452004-12-07 19:02:18 +00008227
8228# define CVT(_t) binop( Iop_F64toI32, \
8229 mkexpr(rmode), \
8230 mkexpr(_t) )
8231
8232 putXMMRegLane32( gregOfRM(modrm), 3, mkU32(0) );
8233 putXMMRegLane32( gregOfRM(modrm), 2, mkU32(0) );
8234 putXMMRegLane32( gregOfRM(modrm), 1, CVT(t1) );
8235 putXMMRegLane32( gregOfRM(modrm), 0, CVT(t0) );
8236
8237# undef CVT
8238
8239 goto decode_success;
8240 }
8241
8242 /* 66 0F 2D = CVTPD2PI -- convert 2 x F64 in mem/xmm to 2 x
8243 I32 in mmx, according to prevailing SSE rounding mode */
8244 /* 66 0F 2C = CVTTPD2PI -- convert 2 x F64 in mem/xmm to 2 x
8245 I32 in mmx, rounding towards zero */
8246 if (sz == 2 && insn[0] == 0x0F && (insn[1] == 0x2D || insn[1] == 0x2C)) {
8247 IRTemp dst64 = newTemp(Ity_I64);
8248 IRTemp rmode = newTemp(Ity_I32);
8249 IRTemp f64lo = newTemp(Ity_F64);
8250 IRTemp f64hi = newTemp(Ity_F64);
sewardj2d49b432005-02-01 00:37:06 +00008251 Bool r2zero = toBool(insn[1] == 0x2C);
sewardjfd226452004-12-07 19:02:18 +00008252
8253 do_MMX_preamble();
8254 modrm = getIByte(delta+2);
8255
8256 if (epartIsReg(modrm)) {
8257 delta += 2+1;
8258 assign(f64lo, getXMMRegLane64F(eregOfRM(modrm), 0));
8259 assign(f64hi, getXMMRegLane64F(eregOfRM(modrm), 1));
8260 DIP("cvt%spd2pi %s,%s\n", r2zero ? "t" : "",
8261 nameXMMReg(eregOfRM(modrm)),
8262 nameMMXReg(gregOfRM(modrm)));
8263 } else {
8264 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8265 assign(f64lo, loadLE(Ity_F64, mkexpr(addr)));
8266 assign(f64hi, loadLE(Ity_F64, binop( Iop_Add32,
8267 mkexpr(addr),
8268 mkU32(8) )));
8269 delta += 2+alen;
8270 DIP("cvt%spf2pi %s,%s\n", r2zero ? "t" : "",
8271 dis_buf,
8272 nameMMXReg(gregOfRM(modrm)));
8273 }
8274
8275 if (r2zero) {
8276 assign(rmode, mkU32((UInt)Irrm_ZERO) );
8277 } else {
8278 assign( rmode, get_sse_roundingmode() );
8279 }
8280
8281 assign(
8282 dst64,
8283 binop( Iop_32HLto64,
8284 binop( Iop_F64toI32, mkexpr(rmode), mkexpr(f64hi) ),
8285 binop( Iop_F64toI32, mkexpr(rmode), mkexpr(f64lo) )
8286 )
8287 );
8288
8289 putMMXReg(gregOfRM(modrm), mkexpr(dst64));
8290 goto decode_success;
8291 }
8292
8293 /* 66 0F 5A = CVTPD2PS -- convert 2 x F64 in mem/xmm to 2 x F32 in
8294 lo half xmm(G), and zero upper half */
8295 /* Note, this is practically identical to CVTPD2DQ. It would have
8296 been nicer to merge them together, but the insn[] offsets differ
8297 by one. */
8298 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5A) {
8299 IRTemp argV = newTemp(Ity_V128);
8300 IRTemp rmode = newTemp(Ity_I32);
8301
8302 modrm = getIByte(delta+2);
8303 if (epartIsReg(modrm)) {
8304 assign( argV, getXMMReg(eregOfRM(modrm)) );
8305 delta += 2+1;
8306 DIP("cvtpd2ps %s,%s\n", nameXMMReg(eregOfRM(modrm)),
8307 nameXMMReg(gregOfRM(modrm)));
8308 } else {
8309 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8310 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
8311 delta += 2+alen;
8312 DIP("cvtpd2ps %s,%s\n", dis_buf,
8313 nameXMMReg(gregOfRM(modrm)) );
8314 }
8315
8316 assign( rmode, get_sse_roundingmode() );
8317 t0 = newTemp(Ity_F64);
8318 t1 = newTemp(Ity_F64);
8319 assign( t0, unop(Iop_ReinterpI64asF64,
sewardjf0c1c582005-02-07 23:47:38 +00008320 unop(Iop_V128to64, mkexpr(argV))) );
sewardjfd226452004-12-07 19:02:18 +00008321 assign( t1, unop(Iop_ReinterpI64asF64,
sewardjf0c1c582005-02-07 23:47:38 +00008322 unop(Iop_V128HIto64, mkexpr(argV))) );
sewardjfd226452004-12-07 19:02:18 +00008323
8324# define CVT(_t) binop( Iop_F64toF32, \
8325 mkexpr(rmode), \
8326 mkexpr(_t) )
8327
8328 putXMMRegLane32( gregOfRM(modrm), 3, mkU32(0) );
8329 putXMMRegLane32( gregOfRM(modrm), 2, mkU32(0) );
8330 putXMMRegLane32F( gregOfRM(modrm), 1, CVT(t1) );
8331 putXMMRegLane32F( gregOfRM(modrm), 0, CVT(t0) );
8332
8333# undef CVT
8334
8335 goto decode_success;
8336 }
8337
8338 /* 66 0F 2A = CVTPI2PD -- convert 2 x I32 in mem/mmx to 2 x F64 in
8339 xmm(G) */
8340 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x2A) {
8341 IRTemp arg64 = newTemp(Ity_I64);
8342
8343 modrm = getIByte(delta+2);
8344 do_MMX_preamble();
8345 if (epartIsReg(modrm)) {
8346 assign( arg64, getMMXReg(eregOfRM(modrm)) );
8347 delta += 2+1;
8348 DIP("cvtpi2pd %s,%s\n", nameMMXReg(eregOfRM(modrm)),
8349 nameXMMReg(gregOfRM(modrm)));
8350 } else {
8351 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8352 assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
8353 delta += 2+alen;
8354 DIP("cvtpi2pd %s,%s\n", dis_buf,
8355 nameXMMReg(gregOfRM(modrm)) );
8356 }
8357
8358 putXMMRegLane64F(
8359 gregOfRM(modrm), 0,
8360 unop(Iop_I32toF64, unop(Iop_64to32, mkexpr(arg64)) )
8361 );
8362
8363 putXMMRegLane64F(
8364 gregOfRM(modrm), 1,
8365 unop(Iop_I32toF64, unop(Iop_64HIto32, mkexpr(arg64)) )
8366 );
8367
8368 goto decode_success;
8369 }
8370
8371 /* 66 0F 5B = CVTPS2DQ -- convert 4 x F32 in mem/xmm to 4 x I32 in
8372 xmm(G) */
8373 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5B) {
8374 IRTemp argV = newTemp(Ity_V128);
8375 IRTemp rmode = newTemp(Ity_I32);
8376
8377 modrm = getIByte(delta+2);
8378 if (epartIsReg(modrm)) {
8379 assign( argV, getXMMReg(eregOfRM(modrm)) );
8380 delta += 2+1;
8381 DIP("cvtps2dq %s,%s\n", nameXMMReg(eregOfRM(modrm)),
8382 nameXMMReg(gregOfRM(modrm)));
8383 } else {
8384 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8385 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
8386 delta += 2+alen;
8387 DIP("cvtps2dq %s,%s\n", dis_buf,
8388 nameXMMReg(gregOfRM(modrm)) );
8389 }
8390
8391 assign( rmode, get_sse_roundingmode() );
8392 breakup128to32s( argV, &t3, &t2, &t1, &t0 );
8393
8394 /* This is less than ideal. If it turns out to be a performance
8395 bottleneck it can be improved. */
8396# define CVT(_t) \
8397 binop( Iop_F64toI32, \
8398 mkexpr(rmode), \
8399 unop( Iop_F32toF64, \
8400 unop( Iop_ReinterpI32asF32, mkexpr(_t))) )
8401
8402 putXMMRegLane32( gregOfRM(modrm), 3, CVT(t3) );
8403 putXMMRegLane32( gregOfRM(modrm), 2, CVT(t2) );
8404 putXMMRegLane32( gregOfRM(modrm), 1, CVT(t1) );
8405 putXMMRegLane32( gregOfRM(modrm), 0, CVT(t0) );
8406
8407# undef CVT
8408
8409 goto decode_success;
8410 }
8411
8412 /* 0F 5A = CVTPS2PD -- convert 2 x F32 in low half mem/xmm to 2 x
8413 F64 in xmm(G). */
8414 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5A) {
8415 IRTemp f32lo = newTemp(Ity_F32);
8416 IRTemp f32hi = newTemp(Ity_F32);
8417
8418 modrm = getIByte(delta+2);
8419 if (epartIsReg(modrm)) {
8420 assign( f32lo, getXMMRegLane32F(eregOfRM(modrm), 0) );
8421 assign( f32hi, getXMMRegLane32F(eregOfRM(modrm), 1) );
8422 delta += 2+1;
8423 DIP("cvtps2pd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
8424 nameXMMReg(gregOfRM(modrm)));
8425 } else {
8426 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8427 assign( f32lo, loadLE(Ity_F32, mkexpr(addr)) );
8428 assign( f32hi, loadLE(Ity_F32,
8429 binop(Iop_Add32,mkexpr(addr),mkU32(4))) );
8430 delta += 2+alen;
8431 DIP("cvtps2pd %s,%s\n", dis_buf,
8432 nameXMMReg(gregOfRM(modrm)) );
8433 }
8434
8435 putXMMRegLane64F( gregOfRM(modrm), 1,
8436 unop(Iop_F32toF64, mkexpr(f32hi)) );
8437 putXMMRegLane64F( gregOfRM(modrm), 0,
8438 unop(Iop_F32toF64, mkexpr(f32lo)) );
8439
8440 goto decode_success;
8441 }
8442
8443 /* F2 0F 2D = CVTSD2SI -- convert F64 in mem/low half xmm to
8444 I32 in ireg, according to prevailing SSE rounding mode */
8445 /* F2 0F 2C = CVTTSD2SI -- convert F64 in mem/low half xmm to
sewardj0b210442005-02-23 13:28:27 +00008446 I32 in ireg, rounding towards zero */
sewardjfd226452004-12-07 19:02:18 +00008447 if (insn[0] == 0xF2 && insn[1] == 0x0F
8448 && (insn[2] == 0x2D || insn[2] == 0x2C)) {
8449 IRTemp rmode = newTemp(Ity_I32);
8450 IRTemp f64lo = newTemp(Ity_F64);
sewardj2d49b432005-02-01 00:37:06 +00008451 Bool r2zero = toBool(insn[2] == 0x2C);
sewardjfd226452004-12-07 19:02:18 +00008452 vassert(sz == 4);
8453
8454 modrm = getIByte(delta+3);
8455 if (epartIsReg(modrm)) {
8456 delta += 3+1;
8457 assign(f64lo, getXMMRegLane64F(eregOfRM(modrm), 0));
8458 DIP("cvt%ssd2si %s,%s\n", r2zero ? "t" : "",
8459 nameXMMReg(eregOfRM(modrm)),
8460 nameIReg(4, gregOfRM(modrm)));
8461 } else {
8462 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
8463 assign(f64lo, loadLE(Ity_F64, mkexpr(addr)));
8464 delta += 3+alen;
8465 DIP("cvt%ssd2si %s,%s\n", r2zero ? "t" : "",
8466 dis_buf,
8467 nameIReg(4, gregOfRM(modrm)));
8468 }
8469
8470 if (r2zero) {
8471 assign( rmode, mkU32((UInt)Irrm_ZERO) );
8472 } else {
8473 assign( rmode, get_sse_roundingmode() );
8474 }
8475
8476 putIReg(4, gregOfRM(modrm),
8477 binop( Iop_F64toI32, mkexpr(rmode), mkexpr(f64lo)) );
8478
8479 goto decode_success;
8480 }
8481
8482 /* F2 0F 5A = CVTSD2SS -- convert F64 in mem/low half xmm to F32 in
8483 low 1/4 xmm(G), according to prevailing SSE rounding mode */
8484 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x5A) {
8485 IRTemp rmode = newTemp(Ity_I32);
8486 IRTemp f64lo = newTemp(Ity_F64);
8487 vassert(sz == 4);
8488
8489 modrm = getIByte(delta+3);
8490 if (epartIsReg(modrm)) {
8491 delta += 3+1;
8492 assign(f64lo, getXMMRegLane64F(eregOfRM(modrm), 0));
8493 DIP("cvtsd2ss %s,%s\n", nameXMMReg(eregOfRM(modrm)),
8494 nameXMMReg(gregOfRM(modrm)));
8495 } else {
8496 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
8497 assign(f64lo, loadLE(Ity_F64, mkexpr(addr)));
8498 delta += 3+alen;
8499 DIP("cvtsd2ss %s,%s\n", dis_buf,
8500 nameXMMReg(gregOfRM(modrm)));
8501 }
8502
8503 assign( rmode, get_sse_roundingmode() );
8504 putXMMRegLane32F(
8505 gregOfRM(modrm), 0,
8506 binop( Iop_F64toF32, mkexpr(rmode), mkexpr(f64lo) )
8507 );
8508
8509 goto decode_success;
8510 }
8511
8512 /* F2 0F 2A = CVTSI2SD -- convert I32 in mem/ireg to F64 in low
8513 half xmm */
8514 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x2A) {
8515 IRTemp arg32 = newTemp(Ity_I32);
8516 vassert(sz == 4);
8517
8518 modrm = getIByte(delta+3);
sewardjfd226452004-12-07 19:02:18 +00008519 if (epartIsReg(modrm)) {
8520 assign( arg32, getIReg(4, eregOfRM(modrm)) );
8521 delta += 3+1;
8522 DIP("cvtsi2sd %s,%s\n", nameIReg(4, eregOfRM(modrm)),
8523 nameXMMReg(gregOfRM(modrm)));
8524 } else {
8525 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
8526 assign( arg32, loadLE(Ity_I32, mkexpr(addr)) );
8527 delta += 3+alen;
8528 DIP("cvtsi2sd %s,%s\n", dis_buf,
8529 nameXMMReg(gregOfRM(modrm)) );
8530 }
8531
8532 putXMMRegLane64F(
8533 gregOfRM(modrm), 0,
8534 unop(Iop_I32toF64, mkexpr(arg32)) );
8535
8536 goto decode_success;
8537 }
8538
8539 /* F3 0F 5A = CVTSS2SD -- convert F32 in mem/low 1/4 xmm to F64 in
8540 low half xmm(G) */
8541 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5A) {
8542 IRTemp f32lo = newTemp(Ity_F32);
8543 vassert(sz == 4);
8544
8545 modrm = getIByte(delta+3);
8546 if (epartIsReg(modrm)) {
8547 delta += 3+1;
8548 assign(f32lo, getXMMRegLane32F(eregOfRM(modrm), 0));
8549 DIP("cvtss2sd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
8550 nameXMMReg(gregOfRM(modrm)));
8551 } else {
8552 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
8553 assign(f32lo, loadLE(Ity_F32, mkexpr(addr)));
8554 delta += 3+alen;
8555 DIP("cvtss2sd %s,%s\n", dis_buf,
8556 nameXMMReg(gregOfRM(modrm)));
8557 }
8558
8559 putXMMRegLane64F( gregOfRM(modrm), 0,
8560 unop( Iop_F32toF64, mkexpr(f32lo) ) );
8561
8562 goto decode_success;
8563 }
8564
8565 /* 66 0F E6 = CVTTPD2DQ -- convert 2 x F64 in mem/xmm to 2 x I32 in
8566 lo half xmm(G), and zero upper half, rounding towards zero */
8567 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE6) {
8568 IRTemp argV = newTemp(Ity_V128);
8569 IRTemp rmode = newTemp(Ity_I32);
8570
8571 modrm = getIByte(delta+2);
8572 if (epartIsReg(modrm)) {
8573 assign( argV, getXMMReg(eregOfRM(modrm)) );
8574 delta += 2+1;
8575 DIP("cvttpd2dq %s,%s\n", nameXMMReg(eregOfRM(modrm)),
8576 nameXMMReg(gregOfRM(modrm)));
8577 } else {
8578 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8579 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
8580 delta += 2+alen;
8581 DIP("cvttpd2dq %s,%s\n", dis_buf,
8582 nameXMMReg(gregOfRM(modrm)) );
8583 }
8584
8585 assign( rmode, mkU32((UInt)Irrm_ZERO) );
8586
8587 t0 = newTemp(Ity_F64);
8588 t1 = newTemp(Ity_F64);
8589 assign( t0, unop(Iop_ReinterpI64asF64,
sewardjf0c1c582005-02-07 23:47:38 +00008590 unop(Iop_V128to64, mkexpr(argV))) );
sewardjfd226452004-12-07 19:02:18 +00008591 assign( t1, unop(Iop_ReinterpI64asF64,
sewardjf0c1c582005-02-07 23:47:38 +00008592 unop(Iop_V128HIto64, mkexpr(argV))) );
sewardjfd226452004-12-07 19:02:18 +00008593
8594# define CVT(_t) binop( Iop_F64toI32, \
8595 mkexpr(rmode), \
8596 mkexpr(_t) )
8597
8598 putXMMRegLane32( gregOfRM(modrm), 3, mkU32(0) );
8599 putXMMRegLane32( gregOfRM(modrm), 2, mkU32(0) );
8600 putXMMRegLane32( gregOfRM(modrm), 1, CVT(t1) );
8601 putXMMRegLane32( gregOfRM(modrm), 0, CVT(t0) );
8602
8603# undef CVT
8604
8605 goto decode_success;
8606 }
8607
8608 /* F3 0F 5B = CVTTPS2DQ -- convert 4 x F32 in mem/xmm to 4 x I32 in
8609 xmm(G), rounding towards zero */
8610 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5B) {
8611 IRTemp argV = newTemp(Ity_V128);
8612 IRTemp rmode = newTemp(Ity_I32);
8613 vassert(sz == 4);
8614
8615 modrm = getIByte(delta+3);
8616 if (epartIsReg(modrm)) {
8617 assign( argV, getXMMReg(eregOfRM(modrm)) );
8618 delta += 3+1;
8619 DIP("cvttps2dq %s,%s\n", nameXMMReg(eregOfRM(modrm)),
8620 nameXMMReg(gregOfRM(modrm)));
8621 } else {
8622 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
8623 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
8624 delta += 3+alen;
8625 DIP("cvttps2dq %s,%s\n", dis_buf,
8626 nameXMMReg(gregOfRM(modrm)) );
8627 }
8628
8629 assign( rmode, mkU32((UInt)Irrm_ZERO) );
8630 breakup128to32s( argV, &t3, &t2, &t1, &t0 );
8631
8632 /* This is less than ideal. If it turns out to be a performance
8633 bottleneck it can be improved. */
8634# define CVT(_t) \
8635 binop( Iop_F64toI32, \
8636 mkexpr(rmode), \
8637 unop( Iop_F32toF64, \
8638 unop( Iop_ReinterpI32asF32, mkexpr(_t))) )
8639
8640 putXMMRegLane32( gregOfRM(modrm), 3, CVT(t3) );
8641 putXMMRegLane32( gregOfRM(modrm), 2, CVT(t2) );
8642 putXMMRegLane32( gregOfRM(modrm), 1, CVT(t1) );
8643 putXMMRegLane32( gregOfRM(modrm), 0, CVT(t0) );
8644
8645# undef CVT
8646
8647 goto decode_success;
8648 }
8649
8650 /* 66 0F 5E = DIVPD -- div 64Fx2 from R/M to R */
8651 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5E) {
8652 delta = dis_SSE_E_to_G_all( sorb, delta+2, "divpd", Iop_Div64Fx2 );
8653 goto decode_success;
8654 }
8655
sewardjc2feffc2004-12-08 12:31:22 +00008656 /* F2 0F 5E = DIVSD -- div 64F0x2 from R/M to R */
8657 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x5E) {
8658 vassert(sz == 4);
8659 delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "divsd", Iop_Div64F0x2 );
8660 goto decode_success;
8661 }
8662
8663 /* 0F AE /5 = LFENCE -- flush pending operations to memory */
8664 /* 0F AE /6 = MFENCE -- flush pending operations to memory */
8665 if (insn[0] == 0x0F && insn[1] == 0xAE
8666 && epartIsReg(insn[2])
8667 && (gregOfRM(insn[2]) == 5 || gregOfRM(insn[2]) == 6)) {
8668 vassert(sz == 4);
8669 delta += 3;
sewardj3e838932005-01-07 12:09:15 +00008670 /* Insert a memory fence. It's sometimes important that these
8671 are carried through to the generated code. */
8672 stmt( IRStmt_MFence() );
sewardjc2feffc2004-12-08 12:31:22 +00008673 DIP("%sfence\n", gregOfRM(insn[2])==5 ? "l" : "m");
8674 goto decode_success;
8675 }
8676
8677 /* 66 0F 5F = MAXPD -- max 64Fx2 from R/M to R */
8678 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5F) {
8679 delta = dis_SSE_E_to_G_all( sorb, delta+2, "maxpd", Iop_Max64Fx2 );
8680 goto decode_success;
8681 }
8682
8683 /* F2 0F 5F = MAXSD -- max 64F0x2 from R/M to R */
8684 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x5F) {
8685 vassert(sz == 4);
8686 delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "maxsd", Iop_Max64F0x2 );
8687 goto decode_success;
8688 }
8689
8690 /* 66 0F 5D = MINPD -- min 64Fx2 from R/M to R */
8691 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5D) {
8692 delta = dis_SSE_E_to_G_all( sorb, delta+2, "minpd", Iop_Min64Fx2 );
8693 goto decode_success;
8694 }
8695
8696 /* F2 0F 5D = MINSD -- min 64F0x2 from R/M to R */
8697 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x5D) {
8698 vassert(sz == 4);
8699 delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "minsd", Iop_Min64F0x2 );
8700 goto decode_success;
8701 }
8702
8703 /* 66 0F 28 = MOVAPD -- move from E (mem or xmm) to G (xmm). */
8704 /* 66 0F 10 = MOVUPD -- move from E (mem or xmm) to G (xmm). */
8705 /* 66 0F 6F = MOVDQA -- move from E (mem or xmm) to G (xmm). */
8706 if (sz == 2 && insn[0] == 0x0F
8707 && (insn[1] == 0x28 || insn[1] == 0x10 || insn[1] == 0x6F)) {
8708 HChar* wot = insn[1]==0x28 ? "apd" :
8709 insn[1]==0x10 ? "upd" : "dqa";
8710 modrm = getIByte(delta+2);
8711 if (epartIsReg(modrm)) {
8712 putXMMReg( gregOfRM(modrm),
8713 getXMMReg( eregOfRM(modrm) ));
8714 DIP("mov%s %s,%s\n", wot, nameXMMReg(eregOfRM(modrm)),
8715 nameXMMReg(gregOfRM(modrm)));
8716 delta += 2+1;
8717 } else {
8718 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8719 putXMMReg( gregOfRM(modrm),
8720 loadLE(Ity_V128, mkexpr(addr)) );
8721 DIP("mov%s %s,%s\n", wot, dis_buf,
8722 nameXMMReg(gregOfRM(modrm)));
8723 delta += 2+alen;
8724 }
8725 goto decode_success;
8726 }
8727
sewardj95535fe2004-12-15 17:42:58 +00008728 /* 66 0F 29 = MOVAPD -- move from G (xmm) to E (mem or xmm). */
sewardj1c318772005-03-19 14:27:04 +00008729 /* 66 0F 11 = MOVUPD -- move from G (xmm) to E (mem or xmm). */
8730 if (sz == 2 && insn[0] == 0x0F
8731 && (insn[1] == 0x29 || insn[1] == 0x11)) {
8732 HChar* wot = insn[1]==0x29 ? "apd" : "upd";
sewardj95535fe2004-12-15 17:42:58 +00008733 modrm = getIByte(delta+2);
8734 if (epartIsReg(modrm)) {
8735 /* fall through; awaiting test case */
8736 } else {
8737 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8738 storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) );
sewardj1c318772005-03-19 14:27:04 +00008739 DIP("mov%s %s,%s\n", wot, nameXMMReg(gregOfRM(modrm)),
8740 dis_buf );
sewardj95535fe2004-12-15 17:42:58 +00008741 delta += 2+alen;
8742 goto decode_success;
8743 }
8744 }
8745
sewardjc2feffc2004-12-08 12:31:22 +00008746 /* 66 0F 6E = MOVD from r/m32 to xmm, zeroing high 3/4 of xmm. */
8747 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x6E) {
8748 modrm = getIByte(delta+2);
8749 if (epartIsReg(modrm)) {
8750 delta += 2+1;
8751 putXMMReg(
8752 gregOfRM(modrm),
sewardjf0c1c582005-02-07 23:47:38 +00008753 unop( Iop_32UtoV128, getIReg(4, eregOfRM(modrm)) )
sewardjc2feffc2004-12-08 12:31:22 +00008754 );
8755 DIP("movd %s, %s\n",
8756 nameIReg(4,eregOfRM(modrm)), nameXMMReg(gregOfRM(modrm)));
8757 } else {
8758 addr = disAMode( &alen, sorb, delta+2, dis_buf );
8759 delta += 2+alen;
8760 putXMMReg(
8761 gregOfRM(modrm),
sewardjf0c1c582005-02-07 23:47:38 +00008762 unop( Iop_32UtoV128,loadLE(Ity_I32, mkexpr(addr)) )
sewardjc2feffc2004-12-08 12:31:22 +00008763 );
8764 DIP("movd %s, %s\n", dis_buf, nameXMMReg(gregOfRM(modrm)));
8765 }
8766 goto decode_success;
8767 }
8768
8769 /* 66 0F 7E = MOVD from xmm low 1/4 to r/m32. */
8770 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x7E) {
8771 modrm = getIByte(delta+2);
8772 if (epartIsReg(modrm)) {
8773 delta += 2+1;
8774 putIReg( 4, eregOfRM(modrm),
8775 getXMMRegLane32(gregOfRM(modrm), 0) );
8776 DIP("movd %s, %s\n",
8777 nameXMMReg(gregOfRM(modrm)), nameIReg(4,eregOfRM(modrm)));
8778 } else {
8779 addr = disAMode( &alen, sorb, delta+2, dis_buf );
8780 delta += 2+alen;
8781 storeLE( mkexpr(addr),
8782 getXMMRegLane32(gregOfRM(modrm), 0) );
8783 DIP("movd %s, %s\n", nameXMMReg(gregOfRM(modrm)), dis_buf);
8784 }
8785 goto decode_success;
8786 }
8787
8788 /* 66 0F 7F = MOVDQA -- move from G (xmm) to E (mem or xmm). */
8789 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x7F) {
8790 modrm = getIByte(delta+2);
8791 if (epartIsReg(modrm)) {
8792 delta += 2+1;
8793 putXMMReg( eregOfRM(modrm),
8794 getXMMReg(gregOfRM(modrm)) );
8795 DIP("movdqa %s, %s\n", nameXMMReg(gregOfRM(modrm)),
8796 nameXMMReg(eregOfRM(modrm)));
8797 } else {
8798 addr = disAMode( &alen, sorb, delta+2, dis_buf );
8799 delta += 2+alen;
8800 storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) );
8801 DIP("movdqa %s, %s\n", nameXMMReg(gregOfRM(modrm)), dis_buf);
8802 }
8803 goto decode_success;
8804 }
8805
8806 /* F3 0F 6F = MOVDQU -- move from E (mem or xmm) to G (xmm). */
8807 /* Unfortunately can't simply use the MOVDQA case since the
8808 prefix lengths are different (66 vs F3) */
8809 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x6F) {
8810 vassert(sz == 4);
8811 modrm = getIByte(delta+3);
8812 if (epartIsReg(modrm)) {
8813 putXMMReg( gregOfRM(modrm),
8814 getXMMReg( eregOfRM(modrm) ));
8815 DIP("movdqu %s,%s\n", nameXMMReg(eregOfRM(modrm)),
8816 nameXMMReg(gregOfRM(modrm)));
8817 delta += 3+1;
8818 } else {
8819 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
8820 putXMMReg( gregOfRM(modrm),
8821 loadLE(Ity_V128, mkexpr(addr)) );
8822 DIP("movdqu %s,%s\n", dis_buf,
8823 nameXMMReg(gregOfRM(modrm)));
8824 delta += 3+alen;
8825 }
8826 goto decode_success;
8827 }
8828
8829 /* F3 0F 7F = MOVDQU -- move from G (xmm) to E (mem or xmm). */
8830 /* Unfortunately can't simply use the MOVDQA case since the
8831 prefix lengths are different (66 vs F3) */
8832 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x7F) {
8833 vassert(sz == 4);
8834 modrm = getIByte(delta+3);
8835 if (epartIsReg(modrm)) {
8836 delta += 3+1;
8837 putXMMReg( eregOfRM(modrm),
8838 getXMMReg(gregOfRM(modrm)) );
8839 DIP("movdqu %s, %s\n", nameXMMReg(gregOfRM(modrm)),
8840 nameXMMReg(eregOfRM(modrm)));
8841 } else {
8842 addr = disAMode( &alen, sorb, delta+3, dis_buf );
8843 delta += 3+alen;
8844 storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) );
8845 DIP("movdqu %s, %s\n", nameXMMReg(gregOfRM(modrm)), dis_buf);
8846 }
8847 goto decode_success;
8848 }
8849
8850 /* F2 0F D6 = MOVDQ2Q -- move from E (lo half xmm, not mem) to G (mmx). */
8851 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0xD6) {
8852 vassert(sz == 4);
8853 modrm = getIByte(delta+3);
8854 if (epartIsReg(modrm)) {
8855 do_MMX_preamble();
8856 putMMXReg( gregOfRM(modrm),
8857 getXMMRegLane64( eregOfRM(modrm), 0 ));
8858 DIP("movdq2q %s,%s\n", nameXMMReg(eregOfRM(modrm)),
8859 nameMMXReg(gregOfRM(modrm)));
8860 delta += 3+1;
8861 goto decode_success;
8862 } else {
8863 /* fall through, apparently no mem case for this insn */
8864 }
8865 }
8866
8867 /* 66 0F 16 = MOVHPD -- move from mem to high half of XMM. */
8868 /* These seems identical to MOVHPS. This instruction encoding is
8869 completely crazy. */
8870 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x16) {
8871 modrm = getIByte(delta+2);
8872 if (epartIsReg(modrm)) {
8873 /* fall through; apparently reg-reg is not possible */
8874 } else {
8875 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8876 delta += 2+alen;
8877 putXMMRegLane64( gregOfRM(modrm), 1/*upper lane*/,
8878 loadLE(Ity_I64, mkexpr(addr)) );
8879 DIP("movhpd %s,%s\n", dis_buf,
8880 nameXMMReg( gregOfRM(modrm) ));
8881 goto decode_success;
8882 }
8883 }
8884
8885 /* 66 0F 17 = MOVHPD -- move from high half of XMM to mem. */
8886 /* Again, this seems identical to MOVHPS. */
8887 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x17) {
8888 if (!epartIsReg(insn[2])) {
8889 delta += 2;
8890 addr = disAMode ( &alen, sorb, delta, dis_buf );
8891 delta += alen;
8892 storeLE( mkexpr(addr),
8893 getXMMRegLane64( gregOfRM(insn[2]),
8894 1/*upper lane*/ ) );
8895 DIP("movhpd %s,%s\n", nameXMMReg( gregOfRM(insn[2]) ),
8896 dis_buf);
8897 goto decode_success;
8898 }
8899 /* else fall through */
8900 }
8901
8902 /* 66 0F 12 = MOVLPD -- move from mem to low half of XMM. */
8903 /* Identical to MOVLPS ? */
8904 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x12) {
8905 modrm = getIByte(delta+2);
8906 if (epartIsReg(modrm)) {
8907 /* fall through; apparently reg-reg is not possible */
8908 } else {
8909 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8910 delta += 2+alen;
8911 putXMMRegLane64( gregOfRM(modrm), 0/*lower lane*/,
8912 loadLE(Ity_I64, mkexpr(addr)) );
8913 DIP("movlpd %s, %s\n",
8914 dis_buf, nameXMMReg( gregOfRM(modrm) ));
8915 goto decode_success;
8916 }
8917 }
8918
8919 /* 66 0F 13 = MOVLPD -- move from low half of XMM to mem. */
8920 /* Identical to MOVLPS ? */
8921 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x13) {
8922 if (!epartIsReg(insn[2])) {
8923 delta += 2;
8924 addr = disAMode ( &alen, sorb, delta, dis_buf );
8925 delta += alen;
8926 storeLE( mkexpr(addr),
8927 getXMMRegLane64( gregOfRM(insn[2]),
8928 0/*lower lane*/ ) );
8929 DIP("movlpd %s, %s\n", nameXMMReg( gregOfRM(insn[2]) ),
8930 dis_buf);
8931 goto decode_success;
8932 }
8933 /* else fall through */
8934 }
8935
8936 /* 66 0F 50 = MOVMSKPD - move 2 sign bits from 2 x F64 in xmm(E) to
8937 2 lowest bits of ireg(G) */
8938 if (insn[0] == 0x0F && insn[1] == 0x50) {
8939 modrm = getIByte(delta+2);
8940 if (sz == 2 && epartIsReg(modrm)) {
8941 Int src;
8942 t0 = newTemp(Ity_I32);
8943 t1 = newTemp(Ity_I32);
8944 delta += 2+1;
8945 src = eregOfRM(modrm);
8946 assign( t0, binop( Iop_And32,
8947 binop(Iop_Shr32, getXMMRegLane32(src,1), mkU8(31)),
8948 mkU32(1) ));
8949 assign( t1, binop( Iop_And32,
8950 binop(Iop_Shr32, getXMMRegLane32(src,3), mkU8(30)),
8951 mkU32(2) ));
8952 putIReg(4, gregOfRM(modrm),
8953 binop(Iop_Or32, mkexpr(t0), mkexpr(t1))
8954 );
8955 DIP("movmskpd %s,%s\n", nameXMMReg(src),
8956 nameIReg(4, gregOfRM(modrm)));
8957 goto decode_success;
8958 }
8959 /* else fall through */
8960 }
8961
8962 /* 66 0F E7 = MOVNTDQ -- for us, just a plain SSE store. */
8963 if (insn[0] == 0x0F && insn[1] == 0xE7) {
8964 modrm = getIByte(delta+2);
8965 if (sz == 2 && !epartIsReg(modrm)) {
8966 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8967 storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) );
8968 DIP("movntdq %s,%s\n", dis_buf,
8969 nameXMMReg(gregOfRM(modrm)));
8970 delta += 2+alen;
8971 goto decode_success;
8972 }
8973 /* else fall through */
8974 }
8975
8976 /* 0F C3 = MOVNTI -- for us, just a plain ireg store. */
8977 if (insn[0] == 0x0F && insn[1] == 0xC3) {
8978 vassert(sz == 4);
8979 modrm = getIByte(delta+2);
8980 if (!epartIsReg(modrm)) {
8981 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8982 storeLE( mkexpr(addr), getIReg(4, gregOfRM(modrm)) );
8983 DIP("movnti %s,%s\n", dis_buf,
8984 nameIReg(4, gregOfRM(modrm)));
8985 delta += 2+alen;
8986 goto decode_success;
8987 }
8988 /* else fall through */
8989 }
8990
sewardj95535fe2004-12-15 17:42:58 +00008991 /* 66 0F D6 = MOVQ -- move 64 bits from G (lo half xmm) to E (mem
8992 or lo half xmm). */
sewardj9ee82862004-12-14 01:16:59 +00008993 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD6) {
8994 modrm = getIByte(delta+2);
8995 if (epartIsReg(modrm)) {
8996 /* fall through, awaiting test case */
sewardj6d7ccd52005-05-14 02:04:12 +00008997 /* dst: lo half copied, hi half zeroed */
sewardj9ee82862004-12-14 01:16:59 +00008998 } else {
8999 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9000 storeLE( mkexpr(addr),
9001 getXMMRegLane64( gregOfRM(modrm), 0 ));
9002 DIP("movq %s,%s\n", nameXMMReg(gregOfRM(modrm)), dis_buf );
9003 delta += 2+alen;
9004 goto decode_success;
9005 }
9006 }
9007
sewardjc2feffc2004-12-08 12:31:22 +00009008 /* F3 0F D6 = MOVQ2DQ -- move from E (mmx) to G (lo half xmm, zero
9009 hi half). */
9010 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0xD6) {
9011 vassert(sz == 4);
9012 modrm = getIByte(delta+3);
9013 if (epartIsReg(modrm)) {
9014 do_MMX_preamble();
9015 putXMMReg( gregOfRM(modrm),
sewardjf0c1c582005-02-07 23:47:38 +00009016 unop(Iop_64UtoV128, getMMXReg( eregOfRM(modrm) )) );
sewardjc2feffc2004-12-08 12:31:22 +00009017 DIP("movq2dq %s,%s\n", nameMMXReg(eregOfRM(modrm)),
9018 nameXMMReg(gregOfRM(modrm)));
9019 delta += 3+1;
9020 goto decode_success;
9021 } else {
9022 /* fall through, apparently no mem case for this insn */
9023 }
9024 }
9025
sewardj95535fe2004-12-15 17:42:58 +00009026 /* F3 0F 7E = MOVQ -- move 64 bits from E (mem or lo half xmm) to
sewardj6d7ccd52005-05-14 02:04:12 +00009027 G (lo half xmm). Upper half of G is zeroed out. */
sewardj95535fe2004-12-15 17:42:58 +00009028 /* F2 0F 10 = MOVSD -- move 64 bits from E (mem or lo half xmm) to
9029 G (lo half xmm). If E is mem, upper half of G is zeroed out.
sewardj6d7ccd52005-05-14 02:04:12 +00009030 If E is reg, upper half of G is unchanged. */
sewardj95535fe2004-12-15 17:42:58 +00009031 if ((insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x10)
9032 || (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x7E)) {
sewardjc2feffc2004-12-08 12:31:22 +00009033 vassert(sz == 4);
9034 modrm = getIByte(delta+3);
9035 if (epartIsReg(modrm)) {
9036 putXMMRegLane64( gregOfRM(modrm), 0,
9037 getXMMRegLane64( eregOfRM(modrm), 0 ));
sewardj6d7ccd52005-05-14 02:04:12 +00009038 if (insn[0] == 0xF3/*MOVQ*/) {
9039 /* zero bits 127:64 */
9040 putXMMRegLane64( gregOfRM(modrm), 1, mkU64(0) );
9041 }
sewardjc2feffc2004-12-08 12:31:22 +00009042 DIP("movsd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9043 nameXMMReg(gregOfRM(modrm)));
9044 delta += 3+1;
9045 } else {
9046 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
sewardjad50db02005-04-06 01:45:44 +00009047 /* zero bits 127:64 */
sewardj5bf1fd42005-04-06 01:11:08 +00009048 putXMMRegLane64( gregOfRM(modrm), 1, mkU64(0) );
sewardjad50db02005-04-06 01:45:44 +00009049 /* write bits 63:0 */
sewardjc2feffc2004-12-08 12:31:22 +00009050 putXMMRegLane64( gregOfRM(modrm), 0,
9051 loadLE(Ity_I64, mkexpr(addr)) );
9052 DIP("movsd %s,%s\n", dis_buf,
9053 nameXMMReg(gregOfRM(modrm)));
9054 delta += 3+alen;
9055 }
9056 goto decode_success;
9057 }
9058
9059 /* F2 0F 11 = MOVSD -- move 64 bits from G (lo half xmm) to E (mem
9060 or lo half xmm). */
9061 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x11) {
9062 vassert(sz == 4);
9063 modrm = getIByte(delta+3);
9064 if (epartIsReg(modrm)) {
9065 /* fall through, we don't yet have a test case */
9066 } else {
9067 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
9068 storeLE( mkexpr(addr),
sewardj519d66f2004-12-15 11:57:58 +00009069 getXMMRegLane64(gregOfRM(modrm), 0) );
9070 DIP("movsd %s,%s\n", nameXMMReg(gregOfRM(modrm)),
sewardjc2feffc2004-12-08 12:31:22 +00009071 dis_buf);
9072 delta += 3+alen;
9073 goto decode_success;
9074 }
9075 }
sewardjfd226452004-12-07 19:02:18 +00009076
sewardj008754b2004-12-08 14:37:10 +00009077 /* 66 0F 59 = MULPD -- mul 64Fx2 from R/M to R */
9078 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x59) {
9079 delta = dis_SSE_E_to_G_all( sorb, delta+2, "mulpd", Iop_Mul64Fx2 );
9080 goto decode_success;
9081 }
9082
9083 /* F2 0F 59 = MULSD -- mul 64F0x2 from R/M to R */
9084 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x59) {
9085 vassert(sz == 4);
9086 delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "mulsd", Iop_Mul64F0x2 );
9087 goto decode_success;
9088 }
9089
9090 /* 66 0F 56 = ORPD -- G = G and E */
9091 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x56) {
sewardjf0c1c582005-02-07 23:47:38 +00009092 delta = dis_SSE_E_to_G_all( sorb, delta+2, "orpd", Iop_OrV128 );
sewardj008754b2004-12-08 14:37:10 +00009093 goto decode_success;
9094 }
9095
9096 /* 66 0F C6 /r ib = SHUFPD -- shuffle packed F64s */
9097 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xC6) {
9098 Int select;
9099 IRTemp sV = newTemp(Ity_V128);
9100 IRTemp dV = newTemp(Ity_V128);
9101 IRTemp s1 = newTemp(Ity_I64);
9102 IRTemp s0 = newTemp(Ity_I64);
9103 IRTemp d1 = newTemp(Ity_I64);
9104 IRTemp d0 = newTemp(Ity_I64);
9105
9106 modrm = insn[2];
9107 assign( dV, getXMMReg(gregOfRM(modrm)) );
9108
9109 if (epartIsReg(modrm)) {
9110 assign( sV, getXMMReg(eregOfRM(modrm)) );
9111 select = (Int)insn[3];
9112 delta += 2+2;
9113 DIP("shufpd $%d,%s,%s\n", select,
9114 nameXMMReg(eregOfRM(modrm)),
9115 nameXMMReg(gregOfRM(modrm)));
9116 } else {
9117 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9118 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
9119 select = (Int)insn[2+alen];
9120 delta += 3+alen;
9121 DIP("shufpd $%d,%s,%s\n", select,
9122 dis_buf,
9123 nameXMMReg(gregOfRM(modrm)));
9124 }
9125
sewardjf0c1c582005-02-07 23:47:38 +00009126 assign( d1, unop(Iop_V128HIto64, mkexpr(dV)) );
9127 assign( d0, unop(Iop_V128to64, mkexpr(dV)) );
9128 assign( s1, unop(Iop_V128HIto64, mkexpr(sV)) );
9129 assign( s0, unop(Iop_V128to64, mkexpr(sV)) );
sewardj008754b2004-12-08 14:37:10 +00009130
9131# define SELD(n) mkexpr((n)==0 ? d0 : d1)
9132# define SELS(n) mkexpr((n)==0 ? s0 : s1)
9133
9134 putXMMReg(
9135 gregOfRM(modrm),
sewardjf0c1c582005-02-07 23:47:38 +00009136 binop(Iop_64HLtoV128, SELS((select>>1)&1), SELD((select>>0)&1) )
sewardj008754b2004-12-08 14:37:10 +00009137 );
9138
9139# undef SELD
9140# undef SELS
9141
9142 goto decode_success;
9143 }
9144
9145 /* 66 0F 51 = SQRTPD -- approx sqrt 64Fx2 from R/M to R */
9146 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x51) {
9147 delta = dis_SSE_E_to_G_unary_all( sorb, delta+2,
9148 "sqrtpd", Iop_Sqrt64Fx2 );
9149 goto decode_success;
9150 }
9151
9152 /* F2 0F 51 = SQRTSD -- approx sqrt 64F0x2 from R/M to R */
9153 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x51) {
9154 vassert(sz == 4);
9155 delta = dis_SSE_E_to_G_unary_lo64( sorb, delta+3,
9156 "sqrtsd", Iop_Sqrt64F0x2 );
9157 goto decode_success;
9158 }
9159
9160 /* 66 0F 5C = SUBPD -- sub 64Fx2 from R/M to R */
9161 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5C) {
9162 delta = dis_SSE_E_to_G_all( sorb, delta+2, "subpd", Iop_Sub64Fx2 );
9163 goto decode_success;
9164 }
9165
9166 /* F2 0F 5C = SUBSD -- sub 64F0x2 from R/M to R */
9167 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x5C) {
9168 vassert(sz == 4);
9169 delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "subsd", Iop_Sub64F0x2 );
9170 goto decode_success;
9171 }
9172
9173 /* 66 0F 15 = UNPCKHPD -- unpack and interleave high part F64s */
9174 /* 66 0F 14 = UNPCKLPD -- unpack and interleave low part F64s */
9175 /* These just appear to be special cases of SHUFPS */
9176 if (sz == 2 && insn[0] == 0x0F && (insn[1] == 0x15 || insn[1] == 0x14)) {
9177 IRTemp s1 = newTemp(Ity_I64);
9178 IRTemp s0 = newTemp(Ity_I64);
9179 IRTemp d1 = newTemp(Ity_I64);
9180 IRTemp d0 = newTemp(Ity_I64);
9181 IRTemp sV = newTemp(Ity_V128);
9182 IRTemp dV = newTemp(Ity_V128);
sewardj2d49b432005-02-01 00:37:06 +00009183 Bool hi = toBool(insn[1] == 0x15);
sewardj008754b2004-12-08 14:37:10 +00009184
9185 modrm = insn[2];
9186 assign( dV, getXMMReg(gregOfRM(modrm)) );
9187
9188 if (epartIsReg(modrm)) {
9189 assign( sV, getXMMReg(eregOfRM(modrm)) );
9190 delta += 2+1;
9191 DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
9192 nameXMMReg(eregOfRM(modrm)),
9193 nameXMMReg(gregOfRM(modrm)));
9194 } else {
9195 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9196 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
9197 delta += 2+alen;
9198 DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
9199 dis_buf,
9200 nameXMMReg(gregOfRM(modrm)));
9201 }
9202
sewardjf0c1c582005-02-07 23:47:38 +00009203 assign( d1, unop(Iop_V128HIto64, mkexpr(dV)) );
9204 assign( d0, unop(Iop_V128to64, mkexpr(dV)) );
9205 assign( s1, unop(Iop_V128HIto64, mkexpr(sV)) );
9206 assign( s0, unop(Iop_V128to64, mkexpr(sV)) );
sewardj008754b2004-12-08 14:37:10 +00009207
9208 if (hi) {
9209 putXMMReg( gregOfRM(modrm),
sewardjf0c1c582005-02-07 23:47:38 +00009210 binop(Iop_64HLtoV128, mkexpr(s1), mkexpr(d1)) );
sewardj008754b2004-12-08 14:37:10 +00009211 } else {
9212 putXMMReg( gregOfRM(modrm),
sewardjf0c1c582005-02-07 23:47:38 +00009213 binop(Iop_64HLtoV128, mkexpr(s0), mkexpr(d0)) );
sewardj008754b2004-12-08 14:37:10 +00009214 }
9215
9216 goto decode_success;
9217 }
9218
9219 /* 66 0F 57 = XORPD -- G = G and E */
9220 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x57) {
sewardjf0c1c582005-02-07 23:47:38 +00009221 delta = dis_SSE_E_to_G_all( sorb, delta+2, "xorpd", Iop_XorV128 );
sewardj008754b2004-12-08 14:37:10 +00009222 goto decode_success;
9223 }
sewardj636ad762004-12-07 11:16:04 +00009224
sewardj164f9272004-12-09 00:39:32 +00009225 /* 66 0F 6B = PACKSSDW */
9226 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x6B) {
9227 delta = dis_SSEint_E_to_G( sorb, delta+2,
9228 "packssdw", Iop_QNarrow32Sx4, True );
9229 goto decode_success;
9230 }
9231
9232 /* 66 0F 63 = PACKSSWB */
9233 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x63) {
9234 delta = dis_SSEint_E_to_G( sorb, delta+2,
9235 "packsswb", Iop_QNarrow16Sx8, True );
9236 goto decode_success;
9237 }
9238
9239 /* 66 0F 67 = PACKUSWB */
9240 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x67) {
9241 delta = dis_SSEint_E_to_G( sorb, delta+2,
9242 "packuswb", Iop_QNarrow16Ux8, True );
9243 goto decode_success;
9244 }
9245
9246 /* 66 0F FC = PADDB */
9247 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xFC) {
9248 delta = dis_SSEint_E_to_G( sorb, delta+2,
9249 "paddb", Iop_Add8x16, False );
9250 goto decode_success;
9251 }
9252
9253 /* 66 0F FE = PADDD */
9254 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xFE) {
9255 delta = dis_SSEint_E_to_G( sorb, delta+2,
9256 "paddd", Iop_Add32x4, False );
9257 goto decode_success;
9258 }
9259
9260 /* ***--- this is an MMX class insn introduced in SSE2 ---*** */
9261 /* 0F D4 = PADDQ -- add 64x1 */
9262 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xD4) {
9263 do_MMX_preamble();
9264 delta = dis_MMXop_regmem_to_reg (
9265 sorb, delta+2, insn[1], "paddq", False );
9266 goto decode_success;
9267 }
9268
9269 /* 66 0F D4 = PADDQ */
9270 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD4) {
9271 delta = dis_SSEint_E_to_G( sorb, delta+2,
9272 "paddq", Iop_Add64x2, False );
9273 goto decode_success;
9274 }
9275
9276 /* 66 0F FD = PADDW */
9277 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xFD) {
9278 delta = dis_SSEint_E_to_G( sorb, delta+2,
9279 "paddw", Iop_Add16x8, False );
9280 goto decode_success;
9281 }
9282
9283 /* 66 0F EC = PADDSB */
9284 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xEC) {
9285 delta = dis_SSEint_E_to_G( sorb, delta+2,
9286 "paddsb", Iop_QAdd8Sx16, False );
9287 goto decode_success;
9288 }
9289
9290 /* 66 0F ED = PADDSW */
9291 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xED) {
9292 delta = dis_SSEint_E_to_G( sorb, delta+2,
9293 "paddsw", Iop_QAdd16Sx8, False );
9294 goto decode_success;
9295 }
9296
9297 /* 66 0F DC = PADDUSB */
9298 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDC) {
9299 delta = dis_SSEint_E_to_G( sorb, delta+2,
9300 "paddusb", Iop_QAdd8Ux16, False );
9301 goto decode_success;
9302 }
9303
9304 /* 66 0F DD = PADDUSW */
9305 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDD) {
9306 delta = dis_SSEint_E_to_G( sorb, delta+2,
9307 "paddusw", Iop_QAdd16Ux8, False );
9308 goto decode_success;
9309 }
9310
9311 /* 66 0F DB = PAND */
9312 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDB) {
sewardjf0c1c582005-02-07 23:47:38 +00009313 delta = dis_SSE_E_to_G_all( sorb, delta+2, "pand", Iop_AndV128 );
sewardj164f9272004-12-09 00:39:32 +00009314 goto decode_success;
9315 }
9316
9317 /* 66 0F DF = PANDN */
9318 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDF) {
sewardjf0c1c582005-02-07 23:47:38 +00009319 delta = dis_SSE_E_to_G_all_invG( sorb, delta+2, "pandn", Iop_AndV128 );
sewardj164f9272004-12-09 00:39:32 +00009320 goto decode_success;
9321 }
9322
9323 /* 66 0F E0 = PAVGB */
9324 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE0) {
9325 delta = dis_SSEint_E_to_G( sorb, delta+2,
9326 "pavgb", Iop_Avg8Ux16, False );
9327 goto decode_success;
9328 }
9329
9330 /* 66 0F E3 = PAVGW */
9331 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE3) {
9332 delta = dis_SSEint_E_to_G( sorb, delta+2,
9333 "pavgw", Iop_Avg16Ux8, False );
9334 goto decode_success;
9335 }
9336
sewardje5854d62004-12-09 03:44:34 +00009337 /* 66 0F 74 = PCMPEQB */
9338 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x74) {
9339 delta = dis_SSEint_E_to_G( sorb, delta+2,
9340 "pcmpeqb", Iop_CmpEQ8x16, False );
9341 goto decode_success;
9342 }
9343
9344 /* 66 0F 76 = PCMPEQD */
9345 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x76) {
9346 delta = dis_SSEint_E_to_G( sorb, delta+2,
9347 "pcmpeqd", Iop_CmpEQ32x4, False );
9348 goto decode_success;
9349 }
9350
9351 /* 66 0F 75 = PCMPEQW */
9352 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x75) {
9353 delta = dis_SSEint_E_to_G( sorb, delta+2,
9354 "pcmpeqw", Iop_CmpEQ16x8, False );
9355 goto decode_success;
9356 }
9357
9358 /* 66 0F 64 = PCMPGTB */
9359 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x64) {
9360 delta = dis_SSEint_E_to_G( sorb, delta+2,
9361 "pcmpgtb", Iop_CmpGT8Sx16, False );
9362 goto decode_success;
9363 }
9364
9365 /* 66 0F 66 = PCMPGTD */
9366 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x66) {
9367 delta = dis_SSEint_E_to_G( sorb, delta+2,
9368 "pcmpgtd", Iop_CmpGT32Sx4, False );
9369 goto decode_success;
9370 }
9371
9372 /* 66 0F 65 = PCMPGTW */
9373 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x65) {
9374 delta = dis_SSEint_E_to_G( sorb, delta+2,
9375 "pcmpgtw", Iop_CmpGT16Sx8, False );
9376 goto decode_success;
9377 }
9378
9379 /* 66 0F C5 = PEXTRW -- extract 16-bit field from xmm(E) and put
9380 zero-extend of it in ireg(G). */
9381 if (insn[0] == 0x0F && insn[1] == 0xC5) {
9382 modrm = insn[2];
9383 if (sz == 2 && epartIsReg(modrm)) {
9384 t5 = newTemp(Ity_V128);
9385 t4 = newTemp(Ity_I16);
9386 assign(t5, getXMMReg(eregOfRM(modrm)));
9387 breakup128to32s( t5, &t3, &t2, &t1, &t0 );
9388 switch (insn[3] & 7) {
9389 case 0: assign(t4, unop(Iop_32to16, mkexpr(t0))); break;
9390 case 1: assign(t4, unop(Iop_32HIto16, mkexpr(t0))); break;
9391 case 2: assign(t4, unop(Iop_32to16, mkexpr(t1))); break;
9392 case 3: assign(t4, unop(Iop_32HIto16, mkexpr(t1))); break;
9393 case 4: assign(t4, unop(Iop_32to16, mkexpr(t2))); break;
9394 case 5: assign(t4, unop(Iop_32HIto16, mkexpr(t2))); break;
9395 case 6: assign(t4, unop(Iop_32to16, mkexpr(t3))); break;
9396 case 7: assign(t4, unop(Iop_32HIto16, mkexpr(t3))); break;
sewardjba89f4c2005-04-07 17:31:27 +00009397 default: vassert(0); /*NOTREACHED*/
sewardje5854d62004-12-09 03:44:34 +00009398 }
9399 putIReg(4, gregOfRM(modrm), unop(Iop_16Uto32, mkexpr(t4)));
9400 DIP("pextrw $%d,%s,%s\n",
9401 (Int)insn[3], nameXMMReg(eregOfRM(modrm)),
9402 nameIReg(4,gregOfRM(modrm)));
9403 delta += 4;
9404 goto decode_success;
9405 }
9406 /* else fall through */
9407 }
9408
9409 /* 66 0F C4 = PINSRW -- get 16 bits from E(mem or low half ireg) and
9410 put it into the specified lane of xmm(G). */
9411 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xC4) {
9412 Int lane;
9413 t4 = newTemp(Ity_I16);
9414 modrm = insn[2];
9415
9416 if (epartIsReg(modrm)) {
9417 assign(t4, getIReg(2, eregOfRM(modrm)));
sewardjaac7e082005-03-17 14:03:46 +00009418 delta += 3+1;
9419 lane = insn[3+1-1];
sewardje5854d62004-12-09 03:44:34 +00009420 DIP("pinsrw $%d,%s,%s\n", (Int)lane,
9421 nameIReg(2,eregOfRM(modrm)),
9422 nameXMMReg(gregOfRM(modrm)));
9423 } else {
sewardjaac7e082005-03-17 14:03:46 +00009424 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9425 delta += 3+alen;
9426 lane = insn[3+alen-1];
9427 assign(t4, loadLE(Ity_I16, mkexpr(addr)));
9428 DIP("pinsrw $%d,%s,%s\n", (Int)lane,
9429 dis_buf,
9430 nameXMMReg(gregOfRM(modrm)));
sewardje5854d62004-12-09 03:44:34 +00009431 }
9432
9433 putXMMRegLane16( gregOfRM(modrm), lane & 7, mkexpr(t4) );
9434 goto decode_success;
9435 }
9436
9437 /* 66 0F EE = PMAXSW -- 16x8 signed max */
9438 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xEE) {
9439 delta = dis_SSEint_E_to_G( sorb, delta+2,
9440 "pmaxsw", Iop_Max16Sx8, False );
9441 goto decode_success;
9442 }
9443
9444 /* 66 0F DE = PMAXUB -- 8x16 unsigned max */
9445 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDE) {
9446 delta = dis_SSEint_E_to_G( sorb, delta+2,
9447 "pmaxub", Iop_Max8Ux16, False );
9448 goto decode_success;
9449 }
9450
9451 /* 66 0F EA = PMINSW -- 16x8 signed min */
9452 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xEA) {
9453 delta = dis_SSEint_E_to_G( sorb, delta+2,
9454 "pminsw", Iop_Min16Sx8, False );
9455 goto decode_success;
9456 }
9457
9458 /* 66 0F DA = PMINUB -- 8x16 unsigned min */
9459 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDA) {
9460 delta = dis_SSEint_E_to_G( sorb, delta+2,
9461 "pminub", Iop_Min8Ux16, False );
9462 goto decode_success;
9463 }
9464
9465 /* 66 0F D7 = PMOVMSKB -- extract sign bits from each of 16 lanes in
9466 xmm(G), turn them into a byte, and put zero-extend of it in
9467 ireg(G). Doing this directly is just too cumbersome; give up
9468 therefore and call a helper. */
9469 /* UInt x86g_calculate_sse_pmovmskb ( ULong w64hi, ULong w64lo ); */
9470 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD7) {
9471 modrm = insn[2];
9472 if (epartIsReg(modrm)) {
9473 t0 = newTemp(Ity_I64);
9474 t1 = newTemp(Ity_I64);
9475 assign(t0, getXMMRegLane64(eregOfRM(modrm), 0));
9476 assign(t1, getXMMRegLane64(eregOfRM(modrm), 1));
9477 t5 = newTemp(Ity_I32);
9478 assign(t5, mkIRExprCCall(
9479 Ity_I32, 0/*regparms*/,
9480 "x86g_calculate_sse_pmovmskb",
9481 &x86g_calculate_sse_pmovmskb,
sewardj28e5c832004-12-16 11:39:04 +00009482 mkIRExprVec_2( mkexpr(t1), mkexpr(t0) )));
sewardje5854d62004-12-09 03:44:34 +00009483 putIReg(4, gregOfRM(modrm), mkexpr(t5));
9484 DIP("pmovmskb %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9485 nameIReg(4,gregOfRM(modrm)));
9486 delta += 3;
9487 goto decode_success;
9488 }
9489 /* else fall through */
9490 }
9491
9492 /* 66 0F E4 = PMULHUW -- 16x8 hi-half of unsigned widening multiply */
9493 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE4) {
9494 delta = dis_SSEint_E_to_G( sorb, delta+2,
9495 "pmulhuw", Iop_MulHi16Ux8, False );
9496 goto decode_success;
9497 }
9498
9499 /* 66 0F E5 = PMULHW -- 16x8 hi-half of signed widening multiply */
9500 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE5) {
9501 delta = dis_SSEint_E_to_G( sorb, delta+2,
9502 "pmulhw", Iop_MulHi16Sx8, False );
9503 goto decode_success;
9504 }
9505
9506 /* 66 0F D5 = PMULHL -- 16x8 multiply */
9507 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD5) {
9508 delta = dis_SSEint_E_to_G( sorb, delta+2,
9509 "pmullw", Iop_Mul16x8, False );
9510 goto decode_success;
9511 }
9512
9513 /* ***--- this is an MMX class insn introduced in SSE2 ---*** */
9514 /* 0F F4 = PMULUDQ -- unsigned widening multiply of 32-lanes 0 x
9515 0 to form 64-bit result */
9516 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xF4) {
9517 IRTemp sV = newTemp(Ity_I64);
9518 IRTemp dV = newTemp(Ity_I64);
9519 t1 = newTemp(Ity_I32);
9520 t0 = newTemp(Ity_I32);
9521 modrm = insn[2];
9522
9523 do_MMX_preamble();
9524 assign( dV, getMMXReg(gregOfRM(modrm)) );
9525
9526 if (epartIsReg(modrm)) {
9527 assign( sV, getMMXReg(eregOfRM(modrm)) );
9528 delta += 2+1;
9529 DIP("pmuludq %s,%s\n", nameMMXReg(eregOfRM(modrm)),
9530 nameMMXReg(gregOfRM(modrm)));
9531 } else {
9532 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9533 assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
9534 delta += 2+alen;
9535 DIP("pmuludq %s,%s\n", dis_buf,
9536 nameMMXReg(gregOfRM(modrm)));
9537 }
9538
9539 assign( t0, unop(Iop_64to32, mkexpr(dV)) );
9540 assign( t1, unop(Iop_64to32, mkexpr(sV)) );
9541 putMMXReg( gregOfRM(modrm),
9542 binop( Iop_MullU32, mkexpr(t0), mkexpr(t1) ) );
9543 goto decode_success;
9544 }
9545
9546 /* 66 0F F4 = PMULUDQ -- unsigned widening multiply of 32-lanes 0 x
9547 0 to form lower 64-bit half and lanes 2 x 2 to form upper 64-bit
9548 half */
9549 /* This is a really poor translation -- could be improved if
9550 performance critical */
9551 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF4) {
9552 IRTemp sV, dV;
9553 IRTemp s3, s2, s1, s0, d3, d2, d1, d0;
9554 sV = newTemp(Ity_V128);
9555 dV = newTemp(Ity_V128);
9556 s3 = s2 = s1 = s0 = d3 = d2 = d1 = d0 = IRTemp_INVALID;
9557 t1 = newTemp(Ity_I64);
9558 t0 = newTemp(Ity_I64);
9559 modrm = insn[2];
9560 assign( dV, getXMMReg(gregOfRM(modrm)) );
9561
9562 if (epartIsReg(modrm)) {
9563 assign( sV, getXMMReg(eregOfRM(modrm)) );
9564 delta += 2+1;
9565 DIP("pmuludq %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9566 nameXMMReg(gregOfRM(modrm)));
9567 } else {
9568 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9569 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
9570 delta += 2+alen;
9571 DIP("pmuludq %s,%s\n", dis_buf,
9572 nameXMMReg(gregOfRM(modrm)));
9573 }
9574
9575 breakup128to32s( dV, &d3, &d2, &d1, &d0 );
9576 breakup128to32s( sV, &s3, &s2, &s1, &s0 );
9577
9578 assign( t0, binop( Iop_MullU32, mkexpr(d0), mkexpr(s0)) );
9579 putXMMRegLane64( gregOfRM(modrm), 0, mkexpr(t0) );
9580 assign( t1, binop( Iop_MullU32, mkexpr(d2), mkexpr(s2)) );
9581 putXMMRegLane64( gregOfRM(modrm), 1, mkexpr(t1) );
9582 goto decode_success;
9583 }
9584
9585 /* 66 0F EB = POR */
9586 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xEB) {
sewardjf0c1c582005-02-07 23:47:38 +00009587 delta = dis_SSE_E_to_G_all( sorb, delta+2, "por", Iop_OrV128 );
sewardje5854d62004-12-09 03:44:34 +00009588 goto decode_success;
9589 }
9590
sewardjb9fa69b2004-12-09 23:25:14 +00009591 /* 66 0F 70 = PSHUFD -- rearrange 4x32 from E(xmm or mem) to G(xmm) */
9592 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x70) {
9593 Int order;
9594 IRTemp sV, dV, s3, s2, s1, s0;
9595 s3 = s2 = s1 = s0 = IRTemp_INVALID;
9596 sV = newTemp(Ity_V128);
9597 dV = newTemp(Ity_V128);
9598 modrm = insn[2];
9599 if (epartIsReg(modrm)) {
9600 assign( sV, getXMMReg(eregOfRM(modrm)) );
9601 order = (Int)insn[3];
9602 delta += 2+2;
9603 DIP("pshufd $%d,%s,%s\n", order,
9604 nameXMMReg(eregOfRM(modrm)),
9605 nameXMMReg(gregOfRM(modrm)));
9606 } else {
9607 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9608 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
9609 order = (Int)insn[2+alen];
9610 delta += 3+alen;
9611 DIP("pshufd $%d,%s,%s\n", order,
9612 dis_buf,
9613 nameXMMReg(gregOfRM(modrm)));
9614 }
9615 breakup128to32s( sV, &s3, &s2, &s1, &s0 );
9616
9617# define SEL(n) \
9618 ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
9619 assign(dV,
9620 mk128from32s( SEL((order>>6)&3), SEL((order>>4)&3),
9621 SEL((order>>2)&3), SEL((order>>0)&3) )
9622 );
9623 putXMMReg(gregOfRM(modrm), mkexpr(dV));
9624# undef SEL
9625 goto decode_success;
9626 }
9627
9628 /* F3 0F 70 = PSHUFHW -- rearrange upper half 4x16 from E(xmm or
9629 mem) to G(xmm), and copy lower half */
9630 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x70) {
9631 Int order;
9632 IRTemp sVhi, dVhi, sV, dV, s3, s2, s1, s0;
9633 s3 = s2 = s1 = s0 = IRTemp_INVALID;
9634 sV = newTemp(Ity_V128);
9635 dV = newTemp(Ity_V128);
9636 sVhi = newTemp(Ity_I64);
9637 dVhi = newTemp(Ity_I64);
9638 modrm = insn[3];
9639 if (epartIsReg(modrm)) {
9640 assign( sV, getXMMReg(eregOfRM(modrm)) );
9641 order = (Int)insn[4];
9642 delta += 4+1;
9643 DIP("pshufhw $%d,%s,%s\n", order,
9644 nameXMMReg(eregOfRM(modrm)),
9645 nameXMMReg(gregOfRM(modrm)));
9646 } else {
9647 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
9648 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
9649 order = (Int)insn[3+alen];
9650 delta += 4+alen;
9651 DIP("pshufhw $%d,%s,%s\n", order,
9652 dis_buf,
9653 nameXMMReg(gregOfRM(modrm)));
9654 }
sewardjf0c1c582005-02-07 23:47:38 +00009655 assign( sVhi, unop(Iop_V128HIto64, mkexpr(sV)) );
sewardjb9fa69b2004-12-09 23:25:14 +00009656 breakup64to16s( sVhi, &s3, &s2, &s1, &s0 );
9657
9658# define SEL(n) \
9659 ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
9660 assign(dVhi,
9661 mk64from16s( SEL((order>>6)&3), SEL((order>>4)&3),
9662 SEL((order>>2)&3), SEL((order>>0)&3) )
9663 );
sewardjf0c1c582005-02-07 23:47:38 +00009664 assign(dV, binop( Iop_64HLtoV128,
sewardjb9fa69b2004-12-09 23:25:14 +00009665 mkexpr(dVhi),
sewardjf0c1c582005-02-07 23:47:38 +00009666 unop(Iop_V128to64, mkexpr(sV))) );
sewardjb9fa69b2004-12-09 23:25:14 +00009667 putXMMReg(gregOfRM(modrm), mkexpr(dV));
9668# undef SEL
9669 goto decode_success;
9670 }
9671
9672 /* F2 0F 70 = PSHUFLW -- rearrange lower half 4x16 from E(xmm or
9673 mem) to G(xmm), and copy upper half */
9674 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x70) {
9675 Int order;
9676 IRTemp sVlo, dVlo, sV, dV, s3, s2, s1, s0;
9677 s3 = s2 = s1 = s0 = IRTemp_INVALID;
9678 sV = newTemp(Ity_V128);
9679 dV = newTemp(Ity_V128);
9680 sVlo = newTemp(Ity_I64);
9681 dVlo = newTemp(Ity_I64);
9682 modrm = insn[3];
9683 if (epartIsReg(modrm)) {
9684 assign( sV, getXMMReg(eregOfRM(modrm)) );
9685 order = (Int)insn[4];
9686 delta += 4+1;
9687 DIP("pshuflw $%d,%s,%s\n", order,
9688 nameXMMReg(eregOfRM(modrm)),
9689 nameXMMReg(gregOfRM(modrm)));
9690 } else {
9691 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
9692 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
9693 order = (Int)insn[3+alen];
9694 delta += 4+alen;
9695 DIP("pshuflw $%d,%s,%s\n", order,
9696 dis_buf,
9697 nameXMMReg(gregOfRM(modrm)));
9698 }
sewardjf0c1c582005-02-07 23:47:38 +00009699 assign( sVlo, unop(Iop_V128to64, mkexpr(sV)) );
sewardjb9fa69b2004-12-09 23:25:14 +00009700 breakup64to16s( sVlo, &s3, &s2, &s1, &s0 );
9701
9702# define SEL(n) \
9703 ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
9704 assign(dVlo,
9705 mk64from16s( SEL((order>>6)&3), SEL((order>>4)&3),
9706 SEL((order>>2)&3), SEL((order>>0)&3) )
9707 );
sewardjf0c1c582005-02-07 23:47:38 +00009708 assign(dV, binop( Iop_64HLtoV128,
9709 unop(Iop_V128HIto64, mkexpr(sV)),
sewardjb9fa69b2004-12-09 23:25:14 +00009710 mkexpr(dVlo) ) );
9711 putXMMReg(gregOfRM(modrm), mkexpr(dV));
9712# undef SEL
9713 goto decode_success;
9714 }
9715
9716 /* 66 0F 72 /6 ib = PSLLD by immediate */
9717 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x72
9718 && epartIsReg(insn[2])
9719 && gregOfRM(insn[2]) == 6) {
sewardj38a3f862005-01-13 15:06:51 +00009720 delta = dis_SSE_shiftE_imm( delta+2, "pslld", Iop_ShlN32x4 );
sewardjb9fa69b2004-12-09 23:25:14 +00009721 goto decode_success;
9722 }
9723
9724 /* 66 0F F2 = PSLLD by E */
9725 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF2) {
9726 delta = dis_SSE_shiftG_byE( sorb, delta+2, "pslld", Iop_ShlN32x4 );
9727 goto decode_success;
9728 }
9729
sewardjb9fa69b2004-12-09 23:25:14 +00009730 /* 66 0F 73 /7 ib = PSLLDQ by immediate */
9731 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x73
9732 && epartIsReg(insn[2])
9733 && gregOfRM(insn[2]) == 7) {
sewardj0c9907c2005-01-10 20:37:31 +00009734 IRTemp sV, dV, hi64, lo64, hi64r, lo64r;
9735 Int imm = (Int)insn[3];
9736 Int reg = eregOfRM(insn[2]);
9737 DIP("pslldq $%d,%s\n", imm, nameXMMReg(reg));
9738 vassert(imm >= 0 && imm <= 255);
9739 delta += 4;
9740
9741 sV = newTemp(Ity_V128);
9742 dV = newTemp(Ity_V128);
9743 hi64 = newTemp(Ity_I64);
9744 lo64 = newTemp(Ity_I64);
9745 hi64r = newTemp(Ity_I64);
9746 lo64r = newTemp(Ity_I64);
9747
9748 if (imm >= 16) {
sewardj0c9907c2005-01-10 20:37:31 +00009749 putXMMReg(reg, mkV128(0x0000));
9750 goto decode_success;
9751 }
9752
9753 assign( sV, getXMMReg(reg) );
sewardjf0c1c582005-02-07 23:47:38 +00009754 assign( hi64, unop(Iop_V128HIto64, mkexpr(sV)) );
9755 assign( lo64, unop(Iop_V128to64, mkexpr(sV)) );
sewardj0c9907c2005-01-10 20:37:31 +00009756
sewardjba89f4c2005-04-07 17:31:27 +00009757 if (imm == 0) {
9758 assign( lo64r, mkexpr(lo64) );
9759 assign( hi64r, mkexpr(hi64) );
9760 }
9761 else
sewardj0c9907c2005-01-10 20:37:31 +00009762 if (imm == 8) {
9763 assign( lo64r, mkU64(0) );
9764 assign( hi64r, mkexpr(lo64) );
9765 }
sewardjc02043c2005-01-11 15:03:53 +00009766 else
sewardj0c9907c2005-01-10 20:37:31 +00009767 if (imm > 8) {
sewardj0c9907c2005-01-10 20:37:31 +00009768 assign( lo64r, mkU64(0) );
9769 assign( hi64r, binop( Iop_Shl64,
9770 mkexpr(lo64),
9771 mkU8( 8*(imm-8) ) ));
9772 } else {
9773 assign( lo64r, binop( Iop_Shl64,
9774 mkexpr(lo64),
9775 mkU8(8 * imm) ));
9776 assign( hi64r,
9777 binop( Iop_Or64,
9778 binop(Iop_Shl64, mkexpr(hi64),
9779 mkU8(8 * imm)),
9780 binop(Iop_Shr64, mkexpr(lo64),
9781 mkU8(8 * (8 - imm)) )
9782 )
9783 );
9784 }
sewardjf0c1c582005-02-07 23:47:38 +00009785 assign( dV, binop(Iop_64HLtoV128, mkexpr(hi64r), mkexpr(lo64r)) );
sewardj0c9907c2005-01-10 20:37:31 +00009786 putXMMReg(reg, mkexpr(dV));
sewardjb9fa69b2004-12-09 23:25:14 +00009787 goto decode_success;
9788 }
sewardjb9fa69b2004-12-09 23:25:14 +00009789
9790 /* 66 0F 73 /6 ib = PSLLQ by immediate */
9791 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x73
9792 && epartIsReg(insn[2])
9793 && gregOfRM(insn[2]) == 6) {
sewardj38a3f862005-01-13 15:06:51 +00009794 delta = dis_SSE_shiftE_imm( delta+2, "psllq", Iop_ShlN64x2 );
sewardjb9fa69b2004-12-09 23:25:14 +00009795 goto decode_success;
9796 }
9797
9798 /* 66 0F F3 = PSLLQ by E */
9799 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF3) {
9800 delta = dis_SSE_shiftG_byE( sorb, delta+2, "psllq", Iop_ShlN64x2 );
9801 goto decode_success;
9802 }
9803
9804 /* 66 0F 71 /6 ib = PSLLW by immediate */
9805 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x71
9806 && epartIsReg(insn[2])
9807 && gregOfRM(insn[2]) == 6) {
sewardj38a3f862005-01-13 15:06:51 +00009808 delta = dis_SSE_shiftE_imm( delta+2, "psllw", Iop_ShlN16x8 );
sewardjb9fa69b2004-12-09 23:25:14 +00009809 goto decode_success;
9810 }
9811
9812 /* 66 0F F1 = PSLLW by E */
9813 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF1) {
9814 delta = dis_SSE_shiftG_byE( sorb, delta+2, "psllw", Iop_ShlN16x8 );
9815 goto decode_success;
9816 }
9817
9818 /* 66 0F 72 /4 ib = PSRAD by immediate */
9819 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x72
9820 && epartIsReg(insn[2])
9821 && gregOfRM(insn[2]) == 4) {
sewardj38a3f862005-01-13 15:06:51 +00009822 delta = dis_SSE_shiftE_imm( delta+2, "psrad", Iop_SarN32x4 );
sewardjb9fa69b2004-12-09 23:25:14 +00009823 goto decode_success;
9824 }
9825
9826 /* 66 0F E2 = PSRAD by E */
9827 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE2) {
9828 delta = dis_SSE_shiftG_byE( sorb, delta+2, "psrad", Iop_SarN32x4 );
9829 goto decode_success;
9830 }
9831
9832 /* 66 0F 71 /4 ib = PSRAW by immediate */
9833 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x71
9834 && epartIsReg(insn[2])
9835 && gregOfRM(insn[2]) == 4) {
sewardj38a3f862005-01-13 15:06:51 +00009836 delta = dis_SSE_shiftE_imm( delta+2, "psraw", Iop_SarN16x8 );
sewardjb9fa69b2004-12-09 23:25:14 +00009837 goto decode_success;
9838 }
9839
9840 /* 66 0F E1 = PSRAW by E */
9841 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE1) {
9842 delta = dis_SSE_shiftG_byE( sorb, delta+2, "psraw", Iop_SarN16x8 );
9843 goto decode_success;
9844 }
9845
9846 /* 66 0F 72 /2 ib = PSRLD by immediate */
9847 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x72
9848 && epartIsReg(insn[2])
9849 && gregOfRM(insn[2]) == 2) {
sewardj38a3f862005-01-13 15:06:51 +00009850 delta = dis_SSE_shiftE_imm( delta+2, "psrld", Iop_ShrN32x4 );
sewardjb9fa69b2004-12-09 23:25:14 +00009851 goto decode_success;
9852 }
9853
9854 /* 66 0F D2 = PSRLD by E */
9855 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD2) {
9856 delta = dis_SSE_shiftG_byE( sorb, delta+2, "psrld", Iop_ShrN32x4 );
9857 goto decode_success;
9858 }
9859
sewardj9ee82862004-12-14 01:16:59 +00009860 /* 66 0F 73 /3 ib = PSRLDQ by immediate */
9861 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x73
9862 && epartIsReg(insn[2])
sewardj95535fe2004-12-15 17:42:58 +00009863 && gregOfRM(insn[2]) == 3) {
9864 IRTemp sV, dV, hi64, lo64, hi64r, lo64r;
sewardj9ee82862004-12-14 01:16:59 +00009865 Int imm = (Int)insn[3];
9866 Int reg = eregOfRM(insn[2]);
sewardj9ee82862004-12-14 01:16:59 +00009867 DIP("psrldq $%d,%s\n", imm, nameXMMReg(reg));
sewardj95535fe2004-12-15 17:42:58 +00009868 vassert(imm >= 0 && imm <= 255);
9869 delta += 4;
9870
9871 sV = newTemp(Ity_V128);
9872 dV = newTemp(Ity_V128);
9873 hi64 = newTemp(Ity_I64);
9874 lo64 = newTemp(Ity_I64);
9875 hi64r = newTemp(Ity_I64);
9876 lo64r = newTemp(Ity_I64);
9877
9878 if (imm >= 16) {
sewardj95535fe2004-12-15 17:42:58 +00009879 putXMMReg(reg, mkV128(0x0000));
9880 goto decode_success;
9881 }
9882
9883 assign( sV, getXMMReg(reg) );
sewardjf0c1c582005-02-07 23:47:38 +00009884 assign( hi64, unop(Iop_V128HIto64, mkexpr(sV)) );
9885 assign( lo64, unop(Iop_V128to64, mkexpr(sV)) );
sewardj95535fe2004-12-15 17:42:58 +00009886
sewardjba89f4c2005-04-07 17:31:27 +00009887 if (imm == 0) {
9888 assign( lo64r, mkexpr(lo64) );
9889 assign( hi64r, mkexpr(hi64) );
9890 }
9891 else
sewardj95535fe2004-12-15 17:42:58 +00009892 if (imm == 8) {
9893 assign( hi64r, mkU64(0) );
9894 assign( lo64r, mkexpr(hi64) );
9895 }
9896 else
9897 if (imm > 8) {
sewardj95535fe2004-12-15 17:42:58 +00009898 assign( hi64r, mkU64(0) );
9899 assign( lo64r, binop( Iop_Shr64,
9900 mkexpr(hi64),
9901 mkU8( 8*(imm-8) ) ));
9902 } else {
9903 assign( hi64r, binop( Iop_Shr64,
9904 mkexpr(hi64),
9905 mkU8(8 * imm) ));
9906 assign( lo64r,
9907 binop( Iop_Or64,
9908 binop(Iop_Shr64, mkexpr(lo64),
9909 mkU8(8 * imm)),
9910 binop(Iop_Shl64, mkexpr(hi64),
9911 mkU8(8 * (8 - imm)) )
9912 )
9913 );
9914 }
9915
sewardjf0c1c582005-02-07 23:47:38 +00009916 assign( dV, binop(Iop_64HLtoV128, mkexpr(hi64r), mkexpr(lo64r)) );
sewardj95535fe2004-12-15 17:42:58 +00009917 putXMMReg(reg, mkexpr(dV));
sewardj9ee82862004-12-14 01:16:59 +00009918 goto decode_success;
9919 }
9920
sewardjb9fa69b2004-12-09 23:25:14 +00009921 /* 66 0F 73 /2 ib = PSRLQ by immediate */
9922 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x73
9923 && epartIsReg(insn[2])
9924 && gregOfRM(insn[2]) == 2) {
sewardj38a3f862005-01-13 15:06:51 +00009925 delta = dis_SSE_shiftE_imm( delta+2, "psrlq", Iop_ShrN64x2 );
sewardjb9fa69b2004-12-09 23:25:14 +00009926 goto decode_success;
9927 }
9928
9929 /* 66 0F D3 = PSRLQ by E */
9930 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD3) {
9931 delta = dis_SSE_shiftG_byE( sorb, delta+2, "psrlq", Iop_ShrN64x2 );
9932 goto decode_success;
9933 }
9934
9935 /* 66 0F 71 /2 ib = PSRLW by immediate */
9936 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x71
9937 && epartIsReg(insn[2])
9938 && gregOfRM(insn[2]) == 2) {
sewardj38a3f862005-01-13 15:06:51 +00009939 delta = dis_SSE_shiftE_imm( delta+2, "psrlw", Iop_ShrN16x8 );
sewardjb9fa69b2004-12-09 23:25:14 +00009940 goto decode_success;
9941 }
9942
9943 /* 66 0F D1 = PSRLW by E */
9944 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD1) {
9945 delta = dis_SSE_shiftG_byE( sorb, delta+2, "psrlw", Iop_ShrN16x8 );
9946 goto decode_success;
9947 }
9948
9949 /* 66 0F F8 = PSUBB */
9950 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF8) {
9951 delta = dis_SSEint_E_to_G( sorb, delta+2,
9952 "psubb", Iop_Sub8x16, False );
9953 goto decode_success;
9954 }
9955
9956 /* 66 0F FA = PSUBD */
9957 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xFA) {
9958 delta = dis_SSEint_E_to_G( sorb, delta+2,
9959 "psubd", Iop_Sub32x4, False );
9960 goto decode_success;
9961 }
9962
9963 /* ***--- this is an MMX class insn introduced in SSE2 ---*** */
9964 /* 0F FB = PSUBQ -- sub 64x1 */
9965 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xFB) {
9966 do_MMX_preamble();
9967 delta = dis_MMXop_regmem_to_reg (
9968 sorb, delta+2, insn[1], "psubq", False );
9969 goto decode_success;
9970 }
9971
9972 /* 66 0F FB = PSUBQ */
9973 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xFB) {
9974 delta = dis_SSEint_E_to_G( sorb, delta+2,
9975 "psubq", Iop_Sub64x2, False );
9976 goto decode_success;
9977 }
9978
9979 /* 66 0F F9 = PSUBW */
9980 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF9) {
9981 delta = dis_SSEint_E_to_G( sorb, delta+2,
9982 "psubw", Iop_Sub16x8, False );
9983 goto decode_success;
9984 }
9985
9986 /* 66 0F E8 = PSUBSB */
9987 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE8) {
9988 delta = dis_SSEint_E_to_G( sorb, delta+2,
9989 "psubsb", Iop_QSub8Sx16, False );
9990 goto decode_success;
9991 }
9992
9993 /* 66 0F E9 = PSUBSW */
9994 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE9) {
9995 delta = dis_SSEint_E_to_G( sorb, delta+2,
9996 "psubsw", Iop_QSub16Sx8, False );
9997 goto decode_success;
9998 }
9999
10000 /* 66 0F D8 = PSUBSB */
10001 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD8) {
10002 delta = dis_SSEint_E_to_G( sorb, delta+2,
10003 "psubusb", Iop_QSub8Ux16, False );
10004 goto decode_success;
10005 }
10006
10007 /* 66 0F D9 = PSUBSW */
10008 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD9) {
10009 delta = dis_SSEint_E_to_G( sorb, delta+2,
10010 "psubusw", Iop_QSub16Ux8, False );
10011 goto decode_success;
10012 }
10013
sewardj9e203592004-12-10 01:48:18 +000010014 /* 66 0F 68 = PUNPCKHBW */
10015 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x68) {
10016 delta = dis_SSEint_E_to_G( sorb, delta+2,
10017 "punpckhbw",
10018 Iop_InterleaveHI8x16, True );
10019 goto decode_success;
10020 }
10021
10022 /* 66 0F 6A = PUNPCKHDQ */
10023 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x6A) {
10024 delta = dis_SSEint_E_to_G( sorb, delta+2,
10025 "punpckhdq",
10026 Iop_InterleaveHI32x4, True );
10027 goto decode_success;
10028 }
10029
10030 /* 66 0F 6D = PUNPCKHQDQ */
10031 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x6D) {
10032 delta = dis_SSEint_E_to_G( sorb, delta+2,
10033 "punpckhqdq",
10034 Iop_InterleaveHI64x2, True );
10035 goto decode_success;
10036 }
10037
10038 /* 66 0F 69 = PUNPCKHWD */
10039 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x69) {
10040 delta = dis_SSEint_E_to_G( sorb, delta+2,
10041 "punpckhwd",
10042 Iop_InterleaveHI16x8, True );
10043 goto decode_success;
10044 }
10045
10046 /* 66 0F 60 = PUNPCKLBW */
10047 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x60) {
10048 delta = dis_SSEint_E_to_G( sorb, delta+2,
10049 "punpcklbw",
10050 Iop_InterleaveLO8x16, True );
10051 goto decode_success;
10052 }
10053
10054 /* 66 0F 62 = PUNPCKLDQ */
10055 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x62) {
10056 delta = dis_SSEint_E_to_G( sorb, delta+2,
10057 "punpckldq",
10058 Iop_InterleaveLO32x4, True );
10059 goto decode_success;
10060 }
10061
10062 /* 66 0F 6C = PUNPCKLQDQ */
10063 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x6C) {
10064 delta = dis_SSEint_E_to_G( sorb, delta+2,
10065 "punpcklqdq",
10066 Iop_InterleaveLO64x2, True );
10067 goto decode_success;
10068 }
10069
10070 /* 66 0F 61 = PUNPCKLWD */
10071 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x61) {
10072 delta = dis_SSEint_E_to_G( sorb, delta+2,
10073 "punpcklwd",
10074 Iop_InterleaveLO16x8, True );
10075 goto decode_success;
10076 }
10077
10078 /* 66 0F EF = PXOR */
10079 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xEF) {
sewardjf0c1c582005-02-07 23:47:38 +000010080 delta = dis_SSE_E_to_G_all( sorb, delta+2, "pxor", Iop_XorV128 );
sewardj9e203592004-12-10 01:48:18 +000010081 goto decode_success;
10082 }
10083
sewardj164f9272004-12-09 00:39:32 +000010084
sewardjc9a65702004-07-07 16:32:57 +000010085//-- /* FXSAVE/FXRSTOR m32 -- load/store the FPU/MMX/SSE state. */
10086//-- if (insn[0] == 0x0F && insn[1] == 0xAE
10087//-- && (!epartIsReg(insn[2]))
10088//-- && (gregOfRM(insn[2]) == 1 || gregOfRM(insn[2]) == 0) ) {
10089//-- Bool store = gregOfRM(insn[2]) == 0;
10090//-- vg_assert(sz == 4);
10091//-- pair = disAMode ( cb, sorb, eip+2, dis_buf );
10092//-- t1 = LOW24(pair);
10093//-- eip += 2+HI8(pair);
10094//-- uInstr3(cb, store ? SSE2a_MemWr : SSE2a_MemRd, 512,
10095//-- Lit16, (((UShort)insn[0]) << 8) | (UShort)insn[1],
10096//-- Lit16, (UShort)insn[2],
10097//-- TempReg, t1 );
10098//-- DIP("fx%s %s\n", store ? "save" : "rstor", dis_buf );
10099//-- goto decode_success;
10100//-- }
10101//--
sewardjc9a65702004-07-07 16:32:57 +000010102//-- /* CLFLUSH -- flush cache line */
10103//-- if (insn[0] == 0x0F && insn[1] == 0xAE
10104//-- && (!epartIsReg(insn[2]))
10105//-- && (gregOfRM(insn[2]) == 7))
10106//-- {
10107//-- vg_assert(sz == 4);
10108//-- pair = disAMode ( cb, sorb, eip+2, dis_buf );
10109//-- t1 = LOW24(pair);
10110//-- eip += 2+HI8(pair);
10111//-- uInstr3(cb, SSE2a_MemRd, 0, /* ignore sz for internal ops */
10112//-- Lit16, (((UShort)0x0F) << 8) | (UShort)0xAE,
10113//-- Lit16, (UShort)insn[2],
10114//-- TempReg, t1 );
10115//-- DIP("clflush %s\n", dis_buf);
10116//-- goto decode_success;
10117//-- }
sewardjc9a65702004-07-07 16:32:57 +000010118
10119
10120 /* ---------------------------------------------------- */
sewardj9df271d2004-12-31 22:37:42 +000010121 /* --- end of the SSE/SSE2 decoder. --- */
sewardjc9a65702004-07-07 16:32:57 +000010122 /* ---------------------------------------------------- */
10123
sewardj9df271d2004-12-31 22:37:42 +000010124 after_sse_decoders:
10125
sewardjc9a65702004-07-07 16:32:57 +000010126 /* Get the primary opcode. */
10127 opc = getIByte(delta); delta++;
10128
10129 /* We get here if the current insn isn't SSE, or this CPU doesn't
10130 support SSE. */
10131
10132 switch (opc) {
10133
10134 /* ------------------------ Control flow --------------- */
sewardj940e8c92004-07-11 16:53:24 +000010135
10136 case 0xC2: /* RET imm16 */
10137 d32 = getUDisp16(delta);
10138 delta += 2;
10139 dis_ret(d32);
sewardj9e6491a2005-07-02 19:24:10 +000010140 dres.whatNext = Dis_StopHere;
sewardj2d49b432005-02-01 00:37:06 +000010141 DIP("ret %d\n", (Int)d32);
sewardj940e8c92004-07-11 16:53:24 +000010142 break;
sewardje05c42c2004-07-08 20:25:10 +000010143 case 0xC3: /* RET */
10144 dis_ret(0);
sewardj9e6491a2005-07-02 19:24:10 +000010145 dres.whatNext = Dis_StopHere;
sewardje05c42c2004-07-08 20:25:10 +000010146 DIP("ret\n");
10147 break;
sewardjd1061ab2004-07-08 01:45:30 +000010148
10149 case 0xE8: /* CALL J4 */
10150 d32 = getUDisp32(delta); delta += 4;
sewardj9e6491a2005-07-02 19:24:10 +000010151 d32 += (guest_EIP_bbstart+delta);
sewardjce70a5c2004-10-18 14:09:54 +000010152 /* (guest_eip_bbstart+delta) == return-to addr, d32 == call-to addr */
sewardj9e6491a2005-07-02 19:24:10 +000010153 if (d32 == guest_EIP_bbstart+delta && getIByte(delta) >= 0x58
sewardjce70a5c2004-10-18 14:09:54 +000010154 && getIByte(delta) <= 0x5F) {
sewardjd1061ab2004-07-08 01:45:30 +000010155 /* Specially treat the position-independent-code idiom
10156 call X
10157 X: popl %reg
10158 as
10159 movl %eip, %reg.
10160 since this generates better code, but for no other reason. */
10161 Int archReg = getIByte(delta) - 0x58;
sewardjc2ac51e2004-07-12 01:03:26 +000010162 /* vex_printf("-- fPIC thingy\n"); */
sewardj9e6491a2005-07-02 19:24:10 +000010163 putIReg(4, archReg, mkU32(guest_EIP_bbstart+delta));
sewardjd1061ab2004-07-08 01:45:30 +000010164 delta++; /* Step over the POP */
10165 DIP("call 0x%x ; popl %s\n",d32,nameIReg(4,archReg));
sewardjc2ac51e2004-07-12 01:03:26 +000010166 } else {
sewardjd1061ab2004-07-08 01:45:30 +000010167 /* The normal sequence for a call. */
10168 t1 = newTemp(Ity_I32);
sewardj41f43bc2004-07-08 14:23:22 +000010169 assign(t1, binop(Iop_Sub32, getIReg(4,R_ESP), mkU32(4)));
10170 putIReg(4, R_ESP, mkexpr(t1));
sewardj9e6491a2005-07-02 19:24:10 +000010171 storeLE( mkexpr(t1), mkU32(guest_EIP_bbstart+delta));
10172 if (resteerOkFn((Addr64)(Addr32)d32)) {
sewardjce70a5c2004-10-18 14:09:54 +000010173 /* follow into the call target. */
sewardj9e6491a2005-07-02 19:24:10 +000010174 dres.whatNext = Dis_Resteer;
10175 dres.continueAt = (Addr64)(Addr32)d32;
sewardjce70a5c2004-10-18 14:09:54 +000010176 } else {
10177 jmp_lit(Ijk_Call,d32);
sewardj9e6491a2005-07-02 19:24:10 +000010178 dres.whatNext = Dis_StopHere;
sewardjce70a5c2004-10-18 14:09:54 +000010179 }
sewardjd1061ab2004-07-08 01:45:30 +000010180 DIP("call 0x%x\n",d32);
10181 }
10182 break;
10183
sewardjc9a65702004-07-07 16:32:57 +000010184//-- case 0xC8: /* ENTER */
10185//-- d32 = getUDisp16(eip); eip += 2;
10186//-- abyte = getIByte(delta); delta++;
10187//--
10188//-- vg_assert(sz == 4);
10189//-- vg_assert(abyte == 0);
10190//--
10191//-- t1 = newTemp(cb); t2 = newTemp(cb);
10192//-- uInstr2(cb, GET, sz, ArchReg, R_EBP, TempReg, t1);
10193//-- uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t2);
10194//-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
10195//-- uLiteral(cb, sz);
10196//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
10197//-- uInstr2(cb, STORE, 4, TempReg, t1, TempReg, t2);
10198//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_EBP);
10199//-- if (d32) {
10200//-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
sewardj5bd4d162004-11-10 13:02:48 +000010201//-- uLiteral(cb, d32);
10202//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
sewardjc9a65702004-07-07 16:32:57 +000010203//-- }
10204//-- DIP("enter 0x%x, 0x%x", d32, abyte);
10205//-- break;
sewardjc2ac51e2004-07-12 01:03:26 +000010206
10207 case 0xC9: /* LEAVE */
10208 vassert(sz == 4);
10209 t1 = newTemp(Ity_I32); t2 = newTemp(Ity_I32);
10210 assign(t1, getIReg(4,R_EBP));
10211 /* First PUT ESP looks redundant, but need it because ESP must
10212 always be up-to-date for Memcheck to work... */
10213 putIReg(4, R_ESP, mkexpr(t1));
10214 assign(t2, loadLE(Ity_I32,mkexpr(t1)));
10215 putIReg(4, R_EBP, mkexpr(t2));
10216 putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t1), mkU32(4)) );
10217 DIP("leave\n");
10218 break;
10219
sewardjc9a65702004-07-07 16:32:57 +000010220//-- /* ---------------- Misc weird-ass insns --------------- */
10221//--
10222//-- case 0x27: /* DAA */
10223//-- case 0x2F: /* DAS */
10224//-- t1 = newTemp(cb);
10225//-- uInstr2(cb, GET, 1, ArchReg, R_AL, TempReg, t1);
10226//-- /* Widen %AL to 32 bits, so it's all defined when we push it. */
10227//-- uInstr1(cb, WIDEN, 4, TempReg, t1);
10228//-- uWiden(cb, 1, False);
10229//-- uInstr0(cb, CALLM_S, 0);
10230//-- uInstr1(cb, PUSH, 4, TempReg, t1);
10231//-- uInstr1(cb, CALLM, 0, Lit16,
10232//-- opc == 0x27 ? VGOFF_(helper_DAA) : VGOFF_(helper_DAS) );
10233//-- uFlagsRWU(cb, FlagsAC, FlagsSZACP, FlagO);
10234//-- uInstr1(cb, POP, 4, TempReg, t1);
10235//-- uInstr0(cb, CALLM_E, 0);
10236//-- uInstr2(cb, PUT, 1, TempReg, t1, ArchReg, R_AL);
10237//-- DIP(opc == 0x27 ? "daa\n" : "das\n");
10238//-- break;
10239//--
10240//-- case 0x37: /* AAA */
10241//-- case 0x3F: /* AAS */
10242//-- t1 = newTemp(cb);
10243//-- uInstr2(cb, GET, 2, ArchReg, R_EAX, TempReg, t1);
10244//-- /* Widen %AL to 32 bits, so it's all defined when we push it. */
10245//-- uInstr1(cb, WIDEN, 4, TempReg, t1);
10246//-- uWiden(cb, 2, False);
10247//-- uInstr0(cb, CALLM_S, 0);
10248//-- uInstr1(cb, PUSH, 4, TempReg, t1);
10249//-- uInstr1(cb, CALLM, 0, Lit16,
10250//-- opc == 0x37 ? VGOFF_(helper_AAA) : VGOFF_(helper_AAS) );
10251//-- uFlagsRWU(cb, FlagA, FlagsAC, FlagsEmpty);
10252//-- uInstr1(cb, POP, 4, TempReg, t1);
10253//-- uInstr0(cb, CALLM_E, 0);
10254//-- uInstr2(cb, PUT, 2, TempReg, t1, ArchReg, R_EAX);
10255//-- DIP(opc == 0x37 ? "aaa\n" : "aas\n");
10256//-- break;
10257//--
10258//-- case 0xD4: /* AAM */
10259//-- case 0xD5: /* AAD */
10260//-- d32 = getIByte(delta); delta++;
10261//-- if (d32 != 10) VG_(core_panic)("disInstr: AAM/AAD but base not 10 !");
10262//-- t1 = newTemp(cb);
10263//-- uInstr2(cb, GET, 2, ArchReg, R_EAX, TempReg, t1);
10264//-- /* Widen %AX to 32 bits, so it's all defined when we push it. */
10265//-- uInstr1(cb, WIDEN, 4, TempReg, t1);
10266//-- uWiden(cb, 2, False);
10267//-- uInstr0(cb, CALLM_S, 0);
10268//-- uInstr1(cb, PUSH, 4, TempReg, t1);
10269//-- uInstr1(cb, CALLM, 0, Lit16,
10270//-- opc == 0xD4 ? VGOFF_(helper_AAM) : VGOFF_(helper_AAD) );
10271//-- uFlagsRWU(cb, FlagsEmpty, FlagsSZP, FlagsEmpty);
10272//-- uInstr1(cb, POP, 4, TempReg, t1);
10273//-- uInstr0(cb, CALLM_E, 0);
10274//-- uInstr2(cb, PUT, 2, TempReg, t1, ArchReg, R_EAX);
10275//-- DIP(opc == 0xD4 ? "aam\n" : "aad\n");
10276//-- break;
sewardj1c6f9912004-09-07 10:15:24 +000010277
10278 /* ------------------------ CWD/CDQ -------------------- */
10279
10280 case 0x98: /* CBW */
10281 if (sz == 4) {
10282 putIReg(4, R_EAX, unop(Iop_16Sto32, getIReg(2, R_EAX)));
10283 DIP("cwde\n");
10284 } else {
sewardj47341042004-09-19 11:55:46 +000010285 vassert(sz == 2);
10286 putIReg(2, R_EAX, unop(Iop_8Sto16, getIReg(1, R_EAX)));
10287 DIP("cbw\n");
sewardj1c6f9912004-09-07 10:15:24 +000010288 }
10289 break;
sewardj64e1d652004-07-12 14:00:46 +000010290
10291 case 0x99: /* CWD/CDQ */
10292 ty = szToITy(sz);
10293 putIReg(sz, R_EDX,
10294 binop(mkSizedOp(ty,Iop_Sar8),
10295 getIReg(sz, R_EAX),
sewardj9ee82862004-12-14 01:16:59 +000010296 mkU8(sz == 2 ? 15 : 31)) );
sewardj64e1d652004-07-12 14:00:46 +000010297 DIP(sz == 2 ? "cwdq\n" : "cdqq\n");
10298 break;
10299
sewardjbdc7d212004-09-09 02:46:40 +000010300 /* ------------------------ FPU ops -------------------- */
10301
10302 case 0x9E: /* SAHF */
10303 codegen_SAHF();
10304 DIP("sahf\n");
10305 break;
10306
sewardjc9a65702004-07-07 16:32:57 +000010307//-- case 0x9F: /* LAHF */
10308//-- codegen_LAHF ( cb );
10309//-- DIP("lahf\n");
10310//-- break;
10311//--
sewardjbdc7d212004-09-09 02:46:40 +000010312 case 0x9B: /* FWAIT */
10313 /* ignore? */
10314 DIP("fwait\n");
10315 break;
10316
sewardjd1725d12004-08-12 20:46:53 +000010317 case 0xD8:
10318 case 0xD9:
10319 case 0xDA:
10320 case 0xDB:
10321 case 0xDC:
10322 case 0xDD:
10323 case 0xDE:
10324 case 0xDF: {
sewardj52d04912005-07-03 00:52:48 +000010325 Int delta0 = delta;
sewardjd1725d12004-08-12 20:46:53 +000010326 Bool decode_OK = False;
10327 delta = dis_FPU ( &decode_OK, sorb, delta );
10328 if (!decode_OK) {
10329 delta = delta0;
10330 goto decode_failure;
10331 }
10332 break;
10333 }
sewardj0611d802004-07-11 02:37:54 +000010334
10335 /* ------------------------ INC & DEC ------------------ */
10336
10337 case 0x40: /* INC eAX */
10338 case 0x41: /* INC eCX */
10339 case 0x42: /* INC eDX */
10340 case 0x43: /* INC eBX */
10341 case 0x44: /* INC eSP */
10342 case 0x45: /* INC eBP */
10343 case 0x46: /* INC eSI */
10344 case 0x47: /* INC eDI */
10345 vassert(sz == 2 || sz == 4);
10346 ty = szToITy(sz);
10347 t1 = newTemp(ty);
10348 assign( t1, binop(mkSizedOp(ty,Iop_Add8),
10349 getIReg(sz, (UInt)(opc - 0x40)),
10350 mkU(ty,1)) );
10351 setFlags_INC_DEC( True, t1, ty );
10352 putIReg(sz, (UInt)(opc - 0x40), mkexpr(t1));
10353 DIP("inc%c %s\n", nameISize(sz), nameIReg(sz,opc-0x40));
10354 break;
10355
10356 case 0x48: /* DEC eAX */
10357 case 0x49: /* DEC eCX */
10358 case 0x4A: /* DEC eDX */
10359 case 0x4B: /* DEC eBX */
10360 case 0x4C: /* DEC eSP */
10361 case 0x4D: /* DEC eBP */
10362 case 0x4E: /* DEC eSI */
10363 case 0x4F: /* DEC eDI */
10364 vassert(sz == 2 || sz == 4);
10365 ty = szToITy(sz);
10366 t1 = newTemp(ty);
10367 assign( t1, binop(mkSizedOp(ty,Iop_Sub8),
10368 getIReg(sz, (UInt)(opc - 0x48)),
10369 mkU(ty,1)) );
10370 setFlags_INC_DEC( False, t1, ty );
10371 putIReg(sz, (UInt)(opc - 0x48), mkexpr(t1));
10372 DIP("dec%c %s\n", nameISize(sz), nameIReg(sz,opc-0x48));
10373 break;
10374
10375 /* ------------------------ INT ------------------------ */
10376
10377 case 0xCD: /* INT imm8 */
10378 d32 = getIByte(delta); delta++;
10379 if (d32 != 0x80) goto decode_failure;
10380 /* It's important that all ArchRegs carry their up-to-date value
10381 at this point. So we declare an end-of-block here, which
10382 forces any TempRegs caching ArchRegs to be flushed. */
sewardj9e6491a2005-07-02 19:24:10 +000010383 jmp_lit(Ijk_Syscall,((Addr32)guest_EIP_bbstart)+delta);
10384 dres.whatNext = Dis_StopHere;
sewardj0611d802004-07-11 02:37:54 +000010385 DIP("int $0x80\n");
10386 break;
10387
sewardj77b86be2004-07-11 13:28:24 +000010388 /* ------------------------ Jcond, byte offset --------- */
10389
10390 case 0xEB: /* Jb (jump, byte offset) */
sewardj9e6491a2005-07-02 19:24:10 +000010391 d32 = (((Addr32)guest_EIP_bbstart)+delta+1) + getSDisp8(delta);
sewardj77b86be2004-07-11 13:28:24 +000010392 delta++;
sewardj9e6491a2005-07-02 19:24:10 +000010393 if (resteerOkFn((Addr64)(Addr32)d32)) {
10394 dres.whatNext = Dis_Resteer;
10395 dres.continueAt = (Addr64)(Addr32)d32;
sewardjce70a5c2004-10-18 14:09:54 +000010396 } else {
10397 jmp_lit(Ijk_Boring,d32);
sewardj9e6491a2005-07-02 19:24:10 +000010398 dres.whatNext = Dis_StopHere;
sewardjce70a5c2004-10-18 14:09:54 +000010399 }
sewardj77b86be2004-07-11 13:28:24 +000010400 DIP("jmp-8 0x%x\n", d32);
10401 break;
sewardj0611d802004-07-11 02:37:54 +000010402
10403 case 0xE9: /* Jv (jump, 16/32 offset) */
10404 vassert(sz == 4); /* JRS added 2004 July 11 */
sewardj9e6491a2005-07-02 19:24:10 +000010405 d32 = (((Addr32)guest_EIP_bbstart)+delta+sz) + getSDisp(sz,delta);
sewardj0611d802004-07-11 02:37:54 +000010406 delta += sz;
sewardj9e6491a2005-07-02 19:24:10 +000010407 if (resteerOkFn((Addr64)(Addr32)d32)) {
10408 dres.whatNext = Dis_Resteer;
10409 dres.continueAt = (Addr64)(Addr32)d32;
sewardjce70a5c2004-10-18 14:09:54 +000010410 } else {
10411 jmp_lit(Ijk_Boring,d32);
sewardj9e6491a2005-07-02 19:24:10 +000010412 dres.whatNext = Dis_StopHere;
sewardjce70a5c2004-10-18 14:09:54 +000010413 }
sewardj0611d802004-07-11 02:37:54 +000010414 DIP("jmp 0x%x\n", d32);
10415 break;
sewardje87b4842004-07-10 12:23:30 +000010416
10417 case 0x70:
10418 case 0x71:
10419 case 0x72: /* JBb/JNAEb (jump below) */
10420 case 0x73: /* JNBb/JAEb (jump not below) */
10421 case 0x74: /* JZb/JEb (jump zero) */
10422 case 0x75: /* JNZb/JNEb (jump not zero) */
10423 case 0x76: /* JBEb/JNAb (jump below or equal) */
10424 case 0x77: /* JNBEb/JAb (jump not below or equal) */
10425 case 0x78: /* JSb (jump negative) */
10426 case 0x79: /* JSb (jump not negative) */
10427 case 0x7A: /* JP (jump parity even) */
10428 case 0x7B: /* JNP/JPO (jump parity odd) */
10429 case 0x7C: /* JLb/JNGEb (jump less) */
10430 case 0x7D: /* JGEb/JNLb (jump greater or equal) */
10431 case 0x7E: /* JLEb/JNGb (jump less or equal) */
10432 case 0x7F: /* JGb/JNLEb (jump greater) */
sewardj9e6491a2005-07-02 19:24:10 +000010433 d32 = (((Addr32)guest_EIP_bbstart)+delta+1) + getSDisp8(delta);
sewardje87b4842004-07-10 12:23:30 +000010434 delta++;
sewardj9e6491a2005-07-02 19:24:10 +000010435 if (0 && resteerOkFn((Addr64)(Addr32)d32)) {
10436 /* Unused experimental hack: speculatively follow one arm
10437 of a conditional branch. */
sewardjdbf550c2005-01-24 11:54:11 +000010438 /* Assume the branch is taken. So we need to emit a
10439 side-exit to the insn following this one, on the negation
10440 of the condition, and continue at the branch target
10441 address (d32). */
10442 if (0) vex_printf("resteer\n");
10443 stmt( IRStmt_Exit(
10444 mk_x86g_calculate_condition((X86Condcode)(1 ^ (opc - 0x70))),
10445 Ijk_Boring,
sewardj9e6491a2005-07-02 19:24:10 +000010446 IRConst_U32(guest_EIP_bbstart+delta) ) );
10447 dres.whatNext = Dis_Resteer;
10448 dres.continueAt = (Addr64)(Addr32)d32;
sewardjdbf550c2005-01-24 11:54:11 +000010449 } else {
sewardj9e6491a2005-07-02 19:24:10 +000010450 jcc_01((X86Condcode)(opc - 0x70), (Addr32)(guest_EIP_bbstart+delta), d32);
10451 dres.whatNext = Dis_StopHere;
sewardjdbf550c2005-01-24 11:54:11 +000010452 }
sewardj2a9ad022004-11-25 02:46:58 +000010453 DIP("j%s-8 0x%x\n", name_X86Condcode(opc - 0x70), d32);
sewardje87b4842004-07-10 12:23:30 +000010454 break;
10455
sewardj458a6f82004-08-25 12:46:02 +000010456 case 0xE3: /* JECXZ or perhaps JCXZ, depending on OSO ? Intel
10457 manual says it depends on address size override,
10458 which doesn't sound right to me. */
10459 vassert(sz==4); /* possibly also OK for sz==2 */
sewardj9e6491a2005-07-02 19:24:10 +000010460 d32 = (((Addr32)guest_EIP_bbstart)+delta+1) + getSDisp8(delta);
sewardj458a6f82004-08-25 12:46:02 +000010461 delta++;
10462 ty = szToITy(sz);
10463 stmt( IRStmt_Exit(
10464 binop(mkSizedOp(ty,Iop_CmpEQ8),
10465 getIReg(sz,R_ECX),
10466 mkU(ty,0)),
sewardj893aada2004-11-29 19:57:54 +000010467 Ijk_Boring,
sewardj458a6f82004-08-25 12:46:02 +000010468 IRConst_U32(d32))
10469 );
10470
10471 DIP("j%sz 0x%x\n", nameIReg(sz, R_ECX), d32);
10472 break;
10473
sewardjc9a65702004-07-07 16:32:57 +000010474//-- case 0xE0: /* LOOPNE disp8 */
10475//-- case 0xE1: /* LOOPE disp8 */
10476//-- case 0xE2: /* LOOP disp8 */
10477//-- /* Again, the docs say this uses ECX/CX as a count depending on
10478//-- the address size override, not the operand one. Since we
10479//-- don't handle address size overrides, I guess that means
10480//-- ECX. */
10481//-- d32 = (eip+1) + getSDisp8(eip); eip++;
10482//-- t1 = newTemp(cb);
10483//-- uInstr2(cb, GET, 4, ArchReg, R_ECX, TempReg, t1);
10484//-- uInstr1(cb, DEC, 4, TempReg, t1);
10485//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_ECX);
10486//-- uInstr2(cb, JIFZ, 4, TempReg, t1, Literal, 0);
10487//-- uLiteral(cb, eip);
10488//-- if (opc == 0xE0 || opc == 0xE1) { /* LOOPE/LOOPNE */
10489//-- jcc_lit(cb, eip, (opc == 0xE1 ? CondNZ : CondZ));
10490//-- }
10491//-- jmp_lit(cb, d32);
sewardjce70a5c2004-10-18 14:09:54 +000010492//-- whatNext = Dis_StopHere;
sewardjc9a65702004-07-07 16:32:57 +000010493//-- DIP("loop 0x%x\n", d32);
10494//-- break;
sewardj1813dbe2004-07-28 17:09:04 +000010495
10496 /* ------------------------ IMUL ----------------------- */
10497
10498 case 0x69: /* IMUL Iv, Ev, Gv */
10499 delta = dis_imul_I_E_G ( sorb, sz, delta, sz );
10500 break;
10501 case 0x6B: /* IMUL Ib, Ev, Gv */
10502 delta = dis_imul_I_E_G ( sorb, sz, delta, 1 );
10503 break;
sewardj0611d802004-07-11 02:37:54 +000010504
10505 /* ------------------------ MOV ------------------------ */
10506
10507 case 0x88: /* MOV Gb,Eb */
10508 delta = dis_mov_G_E(sorb, 1, delta);
10509 break;
sewardjc9a65702004-07-07 16:32:57 +000010510
10511 case 0x89: /* MOV Gv,Ev */
10512 delta = dis_mov_G_E(sorb, sz, delta);
10513 break;
10514
sewardjc2ac51e2004-07-12 01:03:26 +000010515 case 0x8A: /* MOV Eb,Gb */
10516 delta = dis_mov_E_G(sorb, 1, delta);
10517 break;
sewardje05c42c2004-07-08 20:25:10 +000010518
10519 case 0x8B: /* MOV Ev,Gv */
10520 delta = dis_mov_E_G(sorb, sz, delta);
10521 break;
10522
sewardje87b4842004-07-10 12:23:30 +000010523 case 0x8D: /* LEA M,Gv */
sewardje9460bd2005-01-28 13:45:42 +000010524 if (sz != 4)
10525 goto decode_failure;
sewardje05c42c2004-07-08 20:25:10 +000010526 modrm = getIByte(delta);
10527 if (epartIsReg(modrm))
sewardje9460bd2005-01-28 13:45:42 +000010528 goto decode_failure;
sewardje05c42c2004-07-08 20:25:10 +000010529 /* NOTE! this is the one place where a segment override prefix
10530 has no effect on the address calculation. Therefore we pass
10531 zero instead of sorb here. */
sewardje87b4842004-07-10 12:23:30 +000010532 addr = disAMode ( &alen, /*sorb*/ 0, delta, dis_buf );
10533 delta += alen;
sewardj940e8c92004-07-11 16:53:24 +000010534 putIReg(sz, gregOfRM(modrm), mkexpr(addr));
sewardje05c42c2004-07-08 20:25:10 +000010535 DIP("lea%c %s, %s\n", nameISize(sz), dis_buf,
10536 nameIReg(sz,gregOfRM(modrm)));
10537 break;
sewardje05c42c2004-07-08 20:25:10 +000010538
sewardj063f02f2004-10-20 12:36:12 +000010539 case 0x8C: /* MOV Sw,Ew -- MOV from a SEGMENT REGISTER */
10540 delta = dis_mov_Sw_Ew(sorb, sz, delta);
10541 break;
10542
sewardj7df596b2004-12-06 14:29:12 +000010543 case 0x8E: /* MOV Ew,Sw -- MOV to a SEGMENT REGISTER */
10544 delta = dis_mov_Ew_Sw(sorb, delta);
10545 break;
10546
sewardj43852812004-10-16 23:10:08 +000010547 case 0xA0: /* MOV Ob,AL */
10548 sz = 1;
10549 /* Fall through ... */
sewardj0c12ea82004-07-12 08:18:16 +000010550 case 0xA1: /* MOV Ov,eAX */
10551 d32 = getUDisp32(delta); delta += 4;
10552 ty = szToITy(sz);
10553 addr = newTemp(Ity_I32);
10554 assign( addr, handleSegOverride(sorb, mkU32(d32)) );
10555 putIReg(sz, R_EAX, loadLE(ty, mkexpr(addr)));
10556 DIP("mov%c %s0x%x, %s\n", nameISize(sz), sorbTxt(sorb),
10557 d32, nameIReg(sz,R_EAX));
10558 break;
10559
sewardj180e8b32004-07-29 01:40:11 +000010560 case 0xA2: /* MOV Ob,AL */
10561 sz = 1;
10562 /* Fall through ... */
sewardj750f4072004-07-26 22:39:11 +000010563 case 0xA3: /* MOV eAX,Ov */
10564 d32 = getUDisp32(delta); delta += 4;
10565 ty = szToITy(sz);
10566 addr = newTemp(Ity_I32);
10567 assign( addr, handleSegOverride(sorb, mkU32(d32)) );
10568 storeLE( mkexpr(addr), getIReg(sz,R_EAX) );
10569 DIP("mov%c %s, %s0x%x\n", nameISize(sz), nameIReg(sz,R_EAX),
10570 sorbTxt(sorb), d32);
10571 break;
sewardje87b4842004-07-10 12:23:30 +000010572
sewardjc2ac51e2004-07-12 01:03:26 +000010573 case 0xB0: /* MOV imm,AL */
10574 case 0xB1: /* MOV imm,CL */
10575 case 0xB2: /* MOV imm,DL */
10576 case 0xB3: /* MOV imm,BL */
10577 case 0xB4: /* MOV imm,AH */
10578 case 0xB5: /* MOV imm,CH */
10579 case 0xB6: /* MOV imm,DH */
10580 case 0xB7: /* MOV imm,BH */
10581 d32 = getIByte(delta); delta += 1;
10582 putIReg(1, opc-0xB0, mkU8(d32));
10583 DIP("movb $0x%x,%s\n", d32, nameIReg(1,opc-0xB0));
10584 break;
sewardj7ed22952004-07-29 00:09:58 +000010585
sewardje87b4842004-07-10 12:23:30 +000010586 case 0xB8: /* MOV imm,eAX */
10587 case 0xB9: /* MOV imm,eCX */
10588 case 0xBA: /* MOV imm,eDX */
10589 case 0xBB: /* MOV imm,eBX */
10590 case 0xBC: /* MOV imm,eSP */
10591 case 0xBD: /* MOV imm,eBP */
10592 case 0xBE: /* MOV imm,eSI */
10593 case 0xBF: /* MOV imm,eDI */
10594 d32 = getUDisp(sz,delta); delta += sz;
10595 putIReg(sz, opc-0xB8, mkU(szToITy(sz), d32));
10596 DIP("mov%c $0x%x,%s\n", nameISize(sz), d32, nameIReg(sz,opc-0xB8));
10597 break;
10598
sewardj77b86be2004-07-11 13:28:24 +000010599 case 0xC6: /* MOV Ib,Eb */
10600 sz = 1;
10601 goto do_Mov_I_E;
sewardje87b4842004-07-10 12:23:30 +000010602 case 0xC7: /* MOV Iv,Ev */
10603 goto do_Mov_I_E;
10604
10605 do_Mov_I_E:
10606 modrm = getIByte(delta);
10607 if (epartIsReg(modrm)) {
10608 delta++; /* mod/rm byte */
10609 d32 = getUDisp(sz,delta); delta += sz;
sewardj5bd4d162004-11-10 13:02:48 +000010610 putIReg(sz, eregOfRM(modrm), mkU(szToITy(sz), d32));
sewardje87b4842004-07-10 12:23:30 +000010611 DIP("mov%c $0x%x, %s\n", nameISize(sz), d32,
10612 nameIReg(sz,eregOfRM(modrm)));
sewardje87b4842004-07-10 12:23:30 +000010613 } else {
10614 addr = disAMode ( &alen, sorb, delta, dis_buf );
10615 delta += alen;
10616 d32 = getUDisp(sz,delta); delta += sz;
sewardj5bd4d162004-11-10 13:02:48 +000010617 storeLE(mkexpr(addr), mkU(szToITy(sz), d32));
sewardje87b4842004-07-10 12:23:30 +000010618 DIP("mov%c $0x%x, %s\n", nameISize(sz), d32, dis_buf);
10619 }
10620 break;
10621
sewardj1813dbe2004-07-28 17:09:04 +000010622 /* ------------------------ opl imm, A ----------------- */
10623
10624 case 0x04: /* ADD Ib, AL */
sewardja718d5d2005-04-03 14:59:54 +000010625 delta = dis_op_imm_A( 1, False, Iop_Add8, True, delta, "add" );
sewardj1813dbe2004-07-28 17:09:04 +000010626 break;
sewardj77b86be2004-07-11 13:28:24 +000010627 case 0x05: /* ADD Iv, eAX */
sewardja718d5d2005-04-03 14:59:54 +000010628 delta = dis_op_imm_A( sz, False, Iop_Add8, True, delta, "add" );
sewardj77b86be2004-07-11 13:28:24 +000010629 break;
10630
sewardj940e8c92004-07-11 16:53:24 +000010631 case 0x0C: /* OR Ib, AL */
sewardja718d5d2005-04-03 14:59:54 +000010632 delta = dis_op_imm_A( 1, False, Iop_Or8, True, delta, "or" );
sewardj940e8c92004-07-11 16:53:24 +000010633 break;
sewardj82292882004-07-27 00:15:59 +000010634 case 0x0D: /* OR Iv, eAX */
sewardja718d5d2005-04-03 14:59:54 +000010635 delta = dis_op_imm_A( sz, False, Iop_Or8, True, delta, "or" );
sewardj82292882004-07-27 00:15:59 +000010636 break;
10637
sewardjc9a65702004-07-07 16:32:57 +000010638//-- case 0x14: /* ADC Ib, AL */
sewardj77b86be2004-07-11 13:28:24 +000010639//-- delta = dis_op_imm_A( 1, ADC, True, delta, "adc" );
sewardjc9a65702004-07-07 16:32:57 +000010640//-- break;
sewardja718d5d2005-04-03 14:59:54 +000010641 case 0x15: /* ADC Iv, eAX */
10642 delta = dis_op_imm_A( sz, True, Iop_Add8, True, delta, "adc" );
10643 break;
10644
sewardjc9a65702004-07-07 16:32:57 +000010645//-- case 0x1C: /* SBB Ib, AL */
sewardj77b86be2004-07-11 13:28:24 +000010646//-- delta = dis_op_imm_A( 1, SBB, True, delta, "sbb" );
sewardjc9a65702004-07-07 16:32:57 +000010647//-- break;
10648//-- case 0x1D: /* SBB Iv, eAX */
sewardj77b86be2004-07-11 13:28:24 +000010649//-- delta = dis_op_imm_A( sz, SBB, True, delta, "sbb" );
sewardjc9a65702004-07-07 16:32:57 +000010650//-- break;
10651//--
sewardj940e8c92004-07-11 16:53:24 +000010652 case 0x24: /* AND Ib, AL */
sewardja718d5d2005-04-03 14:59:54 +000010653 delta = dis_op_imm_A( 1, False, Iop_And8, True, delta, "and" );
sewardj940e8c92004-07-11 16:53:24 +000010654 break;
sewardjc2ac51e2004-07-12 01:03:26 +000010655 case 0x25: /* AND Iv, eAX */
sewardja718d5d2005-04-03 14:59:54 +000010656 delta = dis_op_imm_A( sz, False, Iop_And8, True, delta, "and" );
sewardjc2ac51e2004-07-12 01:03:26 +000010657 break;
sewardj0611d802004-07-11 02:37:54 +000010658
10659 case 0x2C: /* SUB Ib, AL */
sewardja718d5d2005-04-03 14:59:54 +000010660 delta = dis_op_imm_A( 1, False, Iop_Sub8, True, delta, "sub" );
sewardj0611d802004-07-11 02:37:54 +000010661 break;
sewardj68511542004-07-28 00:15:44 +000010662 case 0x2D: /* SUB Iv, eAX */
sewardja718d5d2005-04-03 14:59:54 +000010663 delta = dis_op_imm_A( sz, False, Iop_Sub8, True, delta, "sub" );
sewardj68511542004-07-28 00:15:44 +000010664 break;
10665
sewardj1c6f9912004-09-07 10:15:24 +000010666 case 0x34: /* XOR Ib, AL */
sewardja718d5d2005-04-03 14:59:54 +000010667 delta = dis_op_imm_A( 1, False, Iop_Xor8, True, delta, "xor" );
sewardj1c6f9912004-09-07 10:15:24 +000010668 break;
sewardjcaca9d02004-07-28 07:11:32 +000010669 case 0x35: /* XOR Iv, eAX */
sewardja718d5d2005-04-03 14:59:54 +000010670 delta = dis_op_imm_A( sz, False, Iop_Xor8, True, delta, "xor" );
sewardjcaca9d02004-07-28 07:11:32 +000010671 break;
10672
sewardj0611d802004-07-11 02:37:54 +000010673 case 0x3C: /* CMP Ib, AL */
sewardja718d5d2005-04-03 14:59:54 +000010674 delta = dis_op_imm_A( 1, False, Iop_Sub8, False, delta, "cmp" );
sewardj0611d802004-07-11 02:37:54 +000010675 break;
10676 case 0x3D: /* CMP Iv, eAX */
sewardja718d5d2005-04-03 14:59:54 +000010677 delta = dis_op_imm_A( sz, False, Iop_Sub8, False, delta, "cmp" );
sewardj0611d802004-07-11 02:37:54 +000010678 break;
10679
sewardj77b86be2004-07-11 13:28:24 +000010680 case 0xA8: /* TEST Ib, AL */
sewardja718d5d2005-04-03 14:59:54 +000010681 delta = dis_op_imm_A( 1, False, Iop_And8, False, delta, "test" );
sewardj77b86be2004-07-11 13:28:24 +000010682 break;
sewardjc2ac51e2004-07-12 01:03:26 +000010683 case 0xA9: /* TEST Iv, eAX */
sewardja718d5d2005-04-03 14:59:54 +000010684 delta = dis_op_imm_A( sz, False, Iop_And8, False, delta, "test" );
sewardjc2ac51e2004-07-12 01:03:26 +000010685 break;
10686
sewardj1c6f9912004-09-07 10:15:24 +000010687 /* ------------------------ opl Ev, Gv ----------------- */
10688
sewardj89cd0932004-09-08 18:23:25 +000010689 case 0x02: /* ADD Eb,Gb */
10690 delta = dis_op2_E_G ( sorb, False, Iop_Add8, True, 1, delta, "add" );
10691 break;
sewardj9334b0f2004-07-10 22:43:54 +000010692 case 0x03: /* ADD Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +000010693 delta = dis_op2_E_G ( sorb, False, Iop_Add8, True, sz, delta, "add" );
sewardj9334b0f2004-07-10 22:43:54 +000010694 break;
10695
sewardj7ed22952004-07-29 00:09:58 +000010696 case 0x0A: /* OR Eb,Gb */
sewardj180e8b32004-07-29 01:40:11 +000010697 delta = dis_op2_E_G ( sorb, False, Iop_Or8, True, 1, delta, "or" );
sewardj7ed22952004-07-29 00:09:58 +000010698 break;
sewardjc2ac51e2004-07-12 01:03:26 +000010699 case 0x0B: /* OR Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +000010700 delta = dis_op2_E_G ( sorb, False, Iop_Or8, True, sz, delta, "or" );
sewardjc2ac51e2004-07-12 01:03:26 +000010701 break;
sewardjc9a65702004-07-07 16:32:57 +000010702//--
10703//-- case 0x12: /* ADC Eb,Gb */
sewardj180e8b32004-07-29 01:40:11 +000010704//-- delta = dis_op2_E_G ( sorb, True, ADC, True, 1, delta, "adc" );
sewardjc9a65702004-07-07 16:32:57 +000010705//-- break;
sewardjc4eaff32004-09-10 20:25:11 +000010706 case 0x13: /* ADC Ev,Gv */
10707 delta = dis_op2_E_G ( sorb, True, Iop_Add8, True, sz, delta, "adc" );
10708 break;
10709
sewardjc9a65702004-07-07 16:32:57 +000010710//-- case 0x1A: /* SBB Eb,Gb */
sewardj180e8b32004-07-29 01:40:11 +000010711//-- delta = dis_op2_E_G ( sorb, True, SBB, True, 1, delta, "sbb" );
sewardjc9a65702004-07-07 16:32:57 +000010712//-- break;
sewardj180e8b32004-07-29 01:40:11 +000010713 case 0x1B: /* SBB Ev,Gv */
10714 delta = dis_op2_E_G ( sorb, True, Iop_Sub8, True, sz, delta, "sbb" );
sewardj940e8c92004-07-11 16:53:24 +000010715 break;
10716
sewardj1c6f9912004-09-07 10:15:24 +000010717 case 0x22: /* AND Eb,Gb */
10718 delta = dis_op2_E_G ( sorb, False, Iop_And8, True, 1, delta, "and" );
10719 break;
sewardj180e8b32004-07-29 01:40:11 +000010720 case 0x23: /* AND Ev,Gv */
10721 delta = dis_op2_E_G ( sorb, False, Iop_And8, True, sz, delta, "and" );
10722 break;
10723
10724 case 0x2A: /* SUB Eb,Gb */
10725 delta = dis_op2_E_G ( sorb, False, Iop_Sub8, True, 1, delta, "sub" );
10726 break;
sewardj0611d802004-07-11 02:37:54 +000010727 case 0x2B: /* SUB Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +000010728 delta = dis_op2_E_G ( sorb, False, Iop_Sub8, True, sz, delta, "sub" );
sewardj0611d802004-07-11 02:37:54 +000010729 break;
sewardjc2ac51e2004-07-12 01:03:26 +000010730
10731 case 0x32: /* XOR Eb,Gb */
sewardj180e8b32004-07-29 01:40:11 +000010732 delta = dis_op2_E_G ( sorb, False, Iop_Xor8, True, 1, delta, "xor" );
sewardjc2ac51e2004-07-12 01:03:26 +000010733 break;
sewardj1813dbe2004-07-28 17:09:04 +000010734 case 0x33: /* XOR Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +000010735 delta = dis_op2_E_G ( sorb, False, Iop_Xor8, True, sz, delta, "xor" );
sewardj1813dbe2004-07-28 17:09:04 +000010736 break;
10737
sewardjc2ac51e2004-07-12 01:03:26 +000010738 case 0x3A: /* CMP Eb,Gb */
sewardj180e8b32004-07-29 01:40:11 +000010739 delta = dis_op2_E_G ( sorb, False, Iop_Sub8, False, 1, delta, "cmp" );
sewardjc2ac51e2004-07-12 01:03:26 +000010740 break;
sewardje90ad6a2004-07-10 19:02:10 +000010741 case 0x3B: /* CMP Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +000010742 delta = dis_op2_E_G ( sorb, False, Iop_Sub8, False, sz, delta, "cmp" );
sewardje90ad6a2004-07-10 19:02:10 +000010743 break;
10744
sewardj0611d802004-07-11 02:37:54 +000010745 case 0x84: /* TEST Eb,Gb */
sewardj180e8b32004-07-29 01:40:11 +000010746 delta = dis_op2_E_G ( sorb, False, Iop_And8, False, 1, delta, "test" );
sewardj0611d802004-07-11 02:37:54 +000010747 break;
sewardje05c42c2004-07-08 20:25:10 +000010748 case 0x85: /* TEST Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +000010749 delta = dis_op2_E_G ( sorb, False, Iop_And8, False, sz, delta, "test" );
sewardje05c42c2004-07-08 20:25:10 +000010750 break;
10751
sewardj180e8b32004-07-29 01:40:11 +000010752 /* ------------------------ opl Gv, Ev ----------------- */
10753
10754 case 0x00: /* ADD Gb,Eb */
10755 delta = dis_op2_G_E ( sorb, False, Iop_Add8, True, 1, delta, "add" );
10756 break;
sewardje05c42c2004-07-08 20:25:10 +000010757 case 0x01: /* ADD Gv,Ev */
sewardjcaca9d02004-07-28 07:11:32 +000010758 delta = dis_op2_G_E ( sorb, False, Iop_Add8, True, sz, delta, "add" );
sewardje05c42c2004-07-08 20:25:10 +000010759 break;
10760
sewardj940e8c92004-07-11 16:53:24 +000010761 case 0x08: /* OR Gb,Eb */
sewardjcaca9d02004-07-28 07:11:32 +000010762 delta = dis_op2_G_E ( sorb, False, Iop_Or8, True, 1, delta, "or" );
sewardj940e8c92004-07-11 16:53:24 +000010763 break;
sewardj9334b0f2004-07-10 22:43:54 +000010764 case 0x09: /* OR Gv,Ev */
sewardjcaca9d02004-07-28 07:11:32 +000010765 delta = dis_op2_G_E ( sorb, False, Iop_Or8, True, sz, delta, "or" );
sewardj9334b0f2004-07-10 22:43:54 +000010766 break;
10767
sewardja2384712004-07-29 14:36:40 +000010768 case 0x10: /* ADC Gb,Eb */
10769 delta = dis_op2_G_E ( sorb, True, Iop_Add8, True, 1, delta, "adc" );
10770 break;
sewardjcaca9d02004-07-28 07:11:32 +000010771 case 0x11: /* ADC Gv,Ev */
10772 delta = dis_op2_G_E ( sorb, True, Iop_Add8, True, sz, delta, "adc" );
10773 break;
10774
sewardja2384712004-07-29 14:36:40 +000010775 case 0x18: /* SBB Gb,Eb */
10776 delta = dis_op2_G_E ( sorb, True, Iop_Sub8, True, 1, delta, "sbb" );
10777 break;
sewardjcaca9d02004-07-28 07:11:32 +000010778 case 0x19: /* SBB Gv,Ev */
10779 delta = dis_op2_G_E ( sorb, True, Iop_Sub8, True, sz, delta, "sbb" );
10780 break;
10781
sewardja2384712004-07-29 14:36:40 +000010782 case 0x20: /* AND Gb,Eb */
10783 delta = dis_op2_G_E ( sorb, False, Iop_And8, True, 1, delta, "and" );
10784 break;
sewardj0611d802004-07-11 02:37:54 +000010785 case 0x21: /* AND Gv,Ev */
sewardjcaca9d02004-07-28 07:11:32 +000010786 delta = dis_op2_G_E ( sorb, False, Iop_And8, True, sz, delta, "and" );
sewardj0611d802004-07-11 02:37:54 +000010787 break;
10788
sewardj180e8b32004-07-29 01:40:11 +000010789 case 0x28: /* SUB Gb,Eb */
10790 delta = dis_op2_G_E ( sorb, False, Iop_Sub8, True, 1, delta, "sub" );
10791 break;
sewardje05c42c2004-07-08 20:25:10 +000010792 case 0x29: /* SUB Gv,Ev */
sewardjcaca9d02004-07-28 07:11:32 +000010793 delta = dis_op2_G_E ( sorb, False, Iop_Sub8, True, sz, delta, "sub" );
sewardje05c42c2004-07-08 20:25:10 +000010794 break;
10795
sewardjc2ac51e2004-07-12 01:03:26 +000010796 case 0x30: /* XOR Gb,Eb */
sewardjcaca9d02004-07-28 07:11:32 +000010797 delta = dis_op2_G_E ( sorb, False, Iop_Xor8, True, 1, delta, "xor" );
sewardjc2ac51e2004-07-12 01:03:26 +000010798 break;
sewardje87b4842004-07-10 12:23:30 +000010799 case 0x31: /* XOR Gv,Ev */
sewardjcaca9d02004-07-28 07:11:32 +000010800 delta = dis_op2_G_E ( sorb, False, Iop_Xor8, True, sz, delta, "xor" );
sewardje87b4842004-07-10 12:23:30 +000010801 break;
10802
sewardj0611d802004-07-11 02:37:54 +000010803 case 0x38: /* CMP Gb,Eb */
sewardjcaca9d02004-07-28 07:11:32 +000010804 delta = dis_op2_G_E ( sorb, False, Iop_Sub8, False, 1, delta, "cmp" );
sewardj0611d802004-07-11 02:37:54 +000010805 break;
sewardje90ad6a2004-07-10 19:02:10 +000010806 case 0x39: /* CMP Gv,Ev */
sewardjcaca9d02004-07-28 07:11:32 +000010807 delta = dis_op2_G_E ( sorb, False, Iop_Sub8, False, sz, delta, "cmp" );
sewardje90ad6a2004-07-10 19:02:10 +000010808 break;
10809
sewardj9334b0f2004-07-10 22:43:54 +000010810 /* ------------------------ POP ------------------------ */
10811
10812 case 0x58: /* POP eAX */
10813 case 0x59: /* POP eCX */
10814 case 0x5A: /* POP eDX */
10815 case 0x5B: /* POP eBX */
10816 case 0x5D: /* POP eBP */
10817 case 0x5E: /* POP eSI */
10818 case 0x5F: /* POP eDI */
10819 case 0x5C: /* POP eSP */
10820 vassert(sz == 2 || sz == 4);
10821 t1 = newTemp(szToITy(sz)); t2 = newTemp(Ity_I32);
10822 assign(t2, getIReg(4, R_ESP));
10823 assign(t1, loadLE(szToITy(sz),mkexpr(t2)));
10824 putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t2), mkU32(sz)));
10825 putIReg(sz, opc-0x58, mkexpr(t1));
10826 DIP("pop%c %s\n", nameISize(sz), nameIReg(sz,opc-0x58));
10827 break;
10828
sewardja2384712004-07-29 14:36:40 +000010829 case 0x9D: /* POPF */
10830 vassert(sz == 2 || sz == 4);
10831 vassert(sz == 4); // until we know a sz==2 test case exists
10832 t1 = newTemp(Ity_I32); t2 = newTemp(Ity_I32);
10833 assign(t2, getIReg(4, R_ESP));
sewardjc22a6fd2004-07-29 23:41:47 +000010834 assign(t1, widenUto32(loadLE(szToITy(sz),mkexpr(t2))));
sewardja2384712004-07-29 14:36:40 +000010835 putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t2), mkU32(sz)));
sewardj98169c52004-10-24 13:11:39 +000010836 /* t1 is the flag word. Mask out everything except OSZACP and
sewardj2a9ad022004-11-25 02:46:58 +000010837 set the flags thunk to X86G_CC_OP_COPY. */
10838 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
sewardj2a2ba8b2004-11-08 13:14:06 +000010839 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
10840 stmt( IRStmt_Put( OFFB_CC_DEP1,
sewardj5bd4d162004-11-10 13:02:48 +000010841 binop(Iop_And32,
10842 mkexpr(t1),
sewardj2a9ad022004-11-25 02:46:58 +000010843 mkU32( X86G_CC_MASK_C | X86G_CC_MASK_P
10844 | X86G_CC_MASK_A | X86G_CC_MASK_Z
10845 | X86G_CC_MASK_S| X86G_CC_MASK_O )
sewardj5bd4d162004-11-10 13:02:48 +000010846 )
10847 )
10848 );
sewardja3b7e3a2005-04-05 01:54:19 +000010849 /* Set NDEP even though it isn't used. This makes redundant-PUT
10850 elimination of previous stores to this field work better. */
10851 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardja2384712004-07-29 14:36:40 +000010852
10853 /* Also need to set the D flag, which is held in bit 10 of t1.
10854 If zero, put 1 in OFFB_DFLAG, else -1 in OFFB_DFLAG. */
10855 stmt( IRStmt_Put(
10856 OFFB_DFLAG,
10857 IRExpr_Mux0X(
10858 unop(Iop_32to8,
10859 binop(Iop_And32,
10860 binop(Iop_Shr32, mkexpr(t1), mkU8(10)),
10861 mkU32(1))),
10862 mkU32(1),
10863 mkU32(0xFFFFFFFF)))
10864 );
10865
sewardj006a6a22004-10-26 00:50:52 +000010866 /* And set the ID flag */
10867 stmt( IRStmt_Put(
10868 OFFB_IDFLAG,
10869 IRExpr_Mux0X(
10870 unop(Iop_32to8,
10871 binop(Iop_And32,
10872 binop(Iop_Shr32, mkexpr(t1), mkU8(21)),
10873 mkU32(1))),
10874 mkU32(0),
10875 mkU32(1)))
10876 );
10877
sewardja2384712004-07-29 14:36:40 +000010878 DIP("popf%c\n", nameISize(sz));
10879 break;
10880
sewardjbbdc6222004-12-15 18:43:39 +000010881 case 0x61: /* POPA */
10882 /* This is almost certainly wrong for sz==2. So ... */
10883 if (sz != 4) goto decode_failure;
10884
10885 /* t5 is the old %ESP value. */
10886 t5 = newTemp(Ity_I32);
10887 assign( t5, getIReg(4, R_ESP) );
10888
10889 /* Reload all the registers, except %esp. */
10890 putIReg(4,R_EAX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(28)) ));
10891 putIReg(4,R_ECX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(24)) ));
10892 putIReg(4,R_EDX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(20)) ));
10893 putIReg(4,R_EBX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(16)) ));
10894 /* ignore saved %ESP */
10895 putIReg(4,R_EBP, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32( 8)) ));
10896 putIReg(4,R_ESI, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32( 4)) ));
10897 putIReg(4,R_EDI, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32( 0)) ));
10898
10899 /* and move %ESP back up */
10900 putIReg( 4, R_ESP, binop(Iop_Add32, mkexpr(t5), mkU32(8*4)) );
10901
sewardja3d1a662005-03-29 21:33:11 +000010902 DIP("popa%c\n", nameISize(sz));
sewardjbbdc6222004-12-15 18:43:39 +000010903 break;
sewardjfeeb8a82004-11-30 12:30:11 +000010904
10905 case 0x8F: /* POPL/POPW m32 */
10906 { Int len;
10907 UChar rm = getIByte(delta);
10908
10909 /* make sure this instruction is correct POP */
10910 vassert(!epartIsReg(rm) && (gregOfRM(rm) == 0));
10911 /* and has correct size */
10912 vassert(sz == 4);
10913
10914 t1 = newTemp(Ity_I32); t3 = newTemp(Ity_I32);
10915 /* set t1 to ESP: t1 = ESP */
10916 assign( t1, getIReg(4, R_ESP) );
10917 /* load M[ESP] to virtual register t3: t3 = M[t1] */
10918 assign( t3, loadLE(Ity_I32, mkexpr(t1)) );
10919
10920 /* increase ESP; must be done before the STORE. Intel manual says:
10921 If the ESP register is used as a base register for addressing
10922 a destination operand in memory, the POP instruction computes
10923 the effective address of the operand after it increments the
10924 ESP register.
10925 */
10926 putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t1), mkU32(sz)) );
10927
10928 /* resolve MODR/M */
10929 addr = disAMode ( &len, sorb, delta, dis_buf);
10930 storeLE( mkexpr(addr), mkexpr(t3) );
10931
10932 DIP("popl %s\n", dis_buf);
10933
10934 delta += len;
10935 break;
10936 }
10937
sewardjc9a65702004-07-07 16:32:57 +000010938//-- case 0x1F: /* POP %DS */
10939//-- dis_pop_segreg( cb, R_DS, sz ); break;
10940//-- case 0x07: /* POP %ES */
10941//-- dis_pop_segreg( cb, R_ES, sz ); break;
10942//-- case 0x17: /* POP %SS */
10943//-- dis_pop_segreg( cb, R_SS, sz ); break;
sewardjd1061ab2004-07-08 01:45:30 +000010944
10945 /* ------------------------ PUSH ----------------------- */
10946
10947 case 0x50: /* PUSH eAX */
10948 case 0x51: /* PUSH eCX */
10949 case 0x52: /* PUSH eDX */
10950 case 0x53: /* PUSH eBX */
10951 case 0x55: /* PUSH eBP */
10952 case 0x56: /* PUSH eSI */
10953 case 0x57: /* PUSH eDI */
10954 case 0x54: /* PUSH eSP */
10955 /* This is the Right Way, in that the value to be pushed is
10956 established before %esp is changed, so that pushl %esp
10957 correctly pushes the old value. */
10958 vassert(sz == 2 || sz == 4);
10959 ty = sz==2 ? Ity_I16 : Ity_I32;
sewardj883b00b2004-09-11 09:30:24 +000010960 t1 = newTemp(ty); t2 = newTemp(Ity_I32);
sewardj41f43bc2004-07-08 14:23:22 +000010961 assign(t1, getIReg(sz, opc-0x50));
10962 assign(t2, binop(Iop_Sub32, getIReg(4, R_ESP), mkU32(sz)));
10963 putIReg(4, R_ESP, mkexpr(t2) );
10964 storeLE(mkexpr(t2),mkexpr(t1));
sewardjd1061ab2004-07-08 01:45:30 +000010965 DIP("push%c %s\n", nameISize(sz), nameIReg(sz,opc-0x50));
10966 break;
10967
10968
sewardj0c12ea82004-07-12 08:18:16 +000010969 case 0x68: /* PUSH Iv */
10970 d32 = getUDisp(sz,delta); delta += sz;
10971 goto do_push_I;
sewardj741153c2004-07-25 23:39:13 +000010972 case 0x6A: /* PUSH Ib, sign-extended to sz */
10973 d32 = getSDisp8(delta); delta += 1;
10974 goto do_push_I;
sewardj0c12ea82004-07-12 08:18:16 +000010975 do_push_I:
10976 ty = szToITy(sz);
10977 t1 = newTemp(Ity_I32); t2 = newTemp(ty);
10978 assign( t1, binop(Iop_Sub32,getIReg(4,R_ESP),mkU32(sz)) );
10979 putIReg(4, R_ESP, mkexpr(t1) );
10980 storeLE( mkexpr(t1), mkU(ty,d32) );
10981 DIP("push%c $0x%x\n", nameISize(sz), d32);
10982 break;
10983
sewardja2384712004-07-29 14:36:40 +000010984 case 0x9C: /* PUSHF */ {
sewardja2384712004-07-29 14:36:40 +000010985 vassert(sz == 2 || sz == 4);
10986 vassert(sz == 4); // wait for sz==2 test case
10987
10988 t1 = newTemp(Ity_I32);
10989 assign( t1, binop(Iop_Sub32,getIReg(4,R_ESP),mkU32(sz)) );
10990 putIReg(4, R_ESP, mkexpr(t1) );
10991
sewardjbc210942005-07-21 10:07:13 +000010992 /* Calculate OSZACP, and patch in fixed fields as per
10993 Intel docs.
10994 - bit 1 is always 1
10995 - bit 9 is Interrupt Enable (should always be 1 in user mode?)
10996 */
sewardja2384712004-07-29 14:36:40 +000010997 t2 = newTemp(Ity_I32);
sewardjbc210942005-07-21 10:07:13 +000010998 assign( t2, binop(Iop_Or32,
10999 mk_x86g_calculate_eflags_all(),
11000 mkU32( (1<<1)|(1<<9) ) ));
sewardja2384712004-07-29 14:36:40 +000011001
sewardjf9c74fe2004-12-16 02:54:54 +000011002 /* Patch in the D flag. This can simply be a copy of bit 10 of
11003 baseBlock[OFFB_DFLAG]. */
sewardja2384712004-07-29 14:36:40 +000011004 t3 = newTemp(Ity_I32);
11005 assign( t3, binop(Iop_Or32,
11006 mkexpr(t2),
11007 binop(Iop_And32,
sewardjf9c74fe2004-12-16 02:54:54 +000011008 IRExpr_Get(OFFB_DFLAG,Ity_I32),
sewardj5bd4d162004-11-10 13:02:48 +000011009 mkU32(1<<10)))
sewardja2384712004-07-29 14:36:40 +000011010 );
sewardj006a6a22004-10-26 00:50:52 +000011011
11012 /* And patch in the ID flag. */
11013 t4 = newTemp(Ity_I32);
11014 assign( t4, binop(Iop_Or32,
11015 mkexpr(t3),
11016 binop(Iop_And32,
sewardj5bd4d162004-11-10 13:02:48 +000011017 binop(Iop_Shl32, IRExpr_Get(OFFB_IDFLAG,Ity_I32),
sewardj006a6a22004-10-26 00:50:52 +000011018 mkU8(21)),
sewardj5bd4d162004-11-10 13:02:48 +000011019 mkU32(1<<21)))
sewardj006a6a22004-10-26 00:50:52 +000011020 );
11021
sewardja2384712004-07-29 14:36:40 +000011022 /* if sz==2, the stored value needs to be narrowed. */
11023 if (sz == 2)
sewardj5bd4d162004-11-10 13:02:48 +000011024 storeLE( mkexpr(t1), unop(Iop_32to16,mkexpr(t4)) );
sewardja2384712004-07-29 14:36:40 +000011025 else
sewardj5bd4d162004-11-10 13:02:48 +000011026 storeLE( mkexpr(t1), mkexpr(t4) );
sewardja2384712004-07-29 14:36:40 +000011027
11028 DIP("pushf%c\n", nameISize(sz));
11029 break;
11030 }
11031
sewardjbbdc6222004-12-15 18:43:39 +000011032 case 0x60: /* PUSHA */
11033 /* This is almost certainly wrong for sz==2. So ... */
11034 if (sz != 4) goto decode_failure;
11035
11036 /* This is the Right Way, in that the value to be pushed is
11037 established before %esp is changed, so that pusha
11038 correctly pushes the old %esp value. New value of %esp is
11039 pushed at start. */
11040 /* t0 is the %ESP value we're going to push. */
11041 t0 = newTemp(Ity_I32);
11042 assign( t0, getIReg(4, R_ESP) );
11043
11044 /* t5 will be the new %ESP value. */
11045 t5 = newTemp(Ity_I32);
11046 assign( t5, binop(Iop_Sub32, mkexpr(t0), mkU32(8*4)) );
11047
11048 /* Update guest state before prodding memory. */
11049 putIReg(4, R_ESP, mkexpr(t5));
11050
11051 /* Dump all the registers. */
11052 storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(28)), getIReg(4,R_EAX) );
11053 storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(24)), getIReg(4,R_ECX) );
11054 storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(20)), getIReg(4,R_EDX) );
11055 storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(16)), getIReg(4,R_EBX) );
11056 storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(12)), mkexpr(t0) /*esp*/);
11057 storeLE( binop(Iop_Add32,mkexpr(t5),mkU32( 8)), getIReg(4,R_EBP) );
11058 storeLE( binop(Iop_Add32,mkexpr(t5),mkU32( 4)), getIReg(4,R_ESI) );
11059 storeLE( binop(Iop_Add32,mkexpr(t5),mkU32( 0)), getIReg(4,R_EDI) );
11060
11061 DIP("pusha%c\n", nameISize(sz));
11062 break;
11063
11064
sewardjc9a65702004-07-07 16:32:57 +000011065//-- case 0x0E: /* PUSH %CS */
11066//-- dis_push_segreg( cb, R_CS, sz ); break;
11067//-- case 0x1E: /* PUSH %DS */
11068//-- dis_push_segreg( cb, R_DS, sz ); break;
11069//-- case 0x06: /* PUSH %ES */
11070//-- dis_push_segreg( cb, R_ES, sz ); break;
11071//-- case 0x16: /* PUSH %SS */
11072//-- dis_push_segreg( cb, R_SS, sz ); break;
sewardj458a6f82004-08-25 12:46:02 +000011073
11074 /* ------------------------ SCAS et al ----------------- */
11075
11076 case 0xA4: /* MOVS, no REP prefix */
11077 case 0xA5:
11078 dis_string_op( dis_MOVS, ( opc == 0xA4 ? 1 : sz ), "movs", sorb );
11079 break;
11080
sewardj8d4d2232005-01-20 10:47:46 +000011081 case 0xA6: /* CMPSb, no REP prefix */
sewardj33b53542005-03-11 14:00:27 +000011082 case 0xA7:
sewardj8d4d2232005-01-20 10:47:46 +000011083 dis_string_op( dis_CMPS, ( opc == 0xA6 ? 1 : sz ), "cmps", sorb );
11084 break;
sewardj33b53542005-03-11 14:00:27 +000011085
sewardj883b00b2004-09-11 09:30:24 +000011086 case 0xAA: /* STOS, no REP prefix */
sewardj47341042004-09-19 11:55:46 +000011087 case 0xAB:
sewardj883b00b2004-09-11 09:30:24 +000011088 dis_string_op( dis_STOS, ( opc == 0xAA ? 1 : sz ), "stos", sorb );
11089 break;
sewardj33b53542005-03-11 14:00:27 +000011090
sewardj10ca4eb2005-05-30 11:19:54 +000011091 case 0xAC: /* LODS, no REP prefix */
11092 case 0xAD:
11093 dis_string_op( dis_LODS, ( opc == 0xAC ? 1 : sz ), "lods", sorb );
11094 break;
sewardj2d4c3a02004-10-15 00:03:23 +000011095
11096 case 0xAE: /* SCAS, no REP prefix */
11097 case 0xAF:
11098 dis_string_op( dis_SCAS, ( opc == 0xAE ? 1 : sz ), "scas", sorb );
11099 break;
sewardj64e1d652004-07-12 14:00:46 +000011100
11101
11102 case 0xFC: /* CLD */
sewardjeeb9ef82004-07-15 12:39:03 +000011103 stmt( IRStmt_Put( OFFB_DFLAG, mkU32(1)) );
sewardj64e1d652004-07-12 14:00:46 +000011104 DIP("cld\n");
11105 break;
11106
sewardj1813dbe2004-07-28 17:09:04 +000011107 case 0xFD: /* STD */
11108 stmt( IRStmt_Put( OFFB_DFLAG, mkU32(0xFFFFFFFF)) );
11109 DIP("std\n");
11110 break;
11111
sewardjbc210942005-07-21 10:07:13 +000011112 case 0xF8: /* CLC */
11113 case 0xF9: /* STC */
11114 case 0xF5: /* CMC */
11115 t0 = newTemp(Ity_I32);
11116 t1 = newTemp(Ity_I32);
11117 assign( t0, mk_x86g_calculate_eflags_all() );
11118 switch (opc) {
11119 case 0xF8:
11120 assign( t1, binop(Iop_And32, mkexpr(t0),
11121 mkU32(~X86G_CC_MASK_C)));
11122 DIP("clc\n");
11123 break;
11124 case 0xF9:
11125 assign( t1, binop(Iop_Or32, mkexpr(t0),
11126 mkU32(X86G_CC_MASK_C)));
11127 DIP("stc\n");
11128 break;
11129 case 0xF5:
11130 assign( t1, binop(Iop_Xor32, mkexpr(t0),
11131 mkU32(X86G_CC_MASK_C)));
11132 DIP("cmc\n");
11133 break;
11134 default:
11135 vpanic("disInstr(x86)(clc/stc/cmc)");
11136 }
11137 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
11138 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
11139 stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(t1) ));
11140 /* Set NDEP even though it isn't used. This makes redundant-PUT
11141 elimination of previous stores to this field work better. */
11142 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
11143 break;
sewardj82292882004-07-27 00:15:59 +000011144
11145 /* REPNE prefix insn */
11146 case 0xF2: {
sewardj9e6491a2005-07-02 19:24:10 +000011147 Addr32 eip_orig = guest_EIP_bbstart + delta - 1;
sewardj82292882004-07-27 00:15:59 +000011148 vassert(sorb == 0);
11149 abyte = getIByte(delta); delta++;
11150
11151 if (abyte == 0x66) { sz = 2; abyte = getIByte(delta); delta++; }
sewardj9e6491a2005-07-02 19:24:10 +000011152 dres.whatNext = Dis_StopHere;
sewardj82292882004-07-27 00:15:59 +000011153
11154 switch (abyte) {
11155 /* According to the Intel manual, "repne movs" should never occur, but
11156 * in practice it has happened, so allow for it here... */
sewardj180e8b32004-07-29 01:40:11 +000011157 case 0xA4: sz = 1; /* REPNE MOVS<sz> */
sewardjb64821b2004-12-14 10:00:16 +000011158 goto decode_failure;
sewardjc9a65702004-07-07 16:32:57 +000011159//-- case 0xA5:
sewardj5bd4d162004-11-10 13:02:48 +000011160 // dis_REP_op ( CondNZ, dis_MOVS, sz, eip_orig,
11161 // guest_eip_bbstart+delta, "repne movs" );
11162 // break;
sewardjc9a65702004-07-07 16:32:57 +000011163//--
11164//-- case 0xA6: sz = 1; /* REPNE CMPS<sz> */
11165//-- case 0xA7:
11166//-- dis_REP_op ( cb, CondNZ, dis_CMPS, sz, eip_orig, eip, "repne cmps" );
11167//-- break;
11168//--
sewardj82292882004-07-27 00:15:59 +000011169 case 0xAE: sz = 1; /* REPNE SCAS<sz> */
sewardj2d4c3a02004-10-15 00:03:23 +000011170 case 0xAF:
sewardj2a9ad022004-11-25 02:46:58 +000011171 dis_REP_op ( X86CondNZ, dis_SCAS, sz, eip_orig,
sewardj9e6491a2005-07-02 19:24:10 +000011172 guest_EIP_bbstart+delta, "repne scas" );
sewardj82292882004-07-27 00:15:59 +000011173 break;
11174
11175 default:
11176 goto decode_failure;
11177 }
11178 break;
11179 }
sewardj64e1d652004-07-12 14:00:46 +000011180
11181 /* REP/REPE prefix insn (for SCAS and CMPS, 0xF3 means REPE,
11182 for the rest, it means REP) */
11183 case 0xF3: {
sewardj9e6491a2005-07-02 19:24:10 +000011184 Addr32 eip_orig = guest_EIP_bbstart + delta - 1;
sewardj64e1d652004-07-12 14:00:46 +000011185 vassert(sorb == 0);
11186 abyte = getIByte(delta); delta++;
11187
11188 if (abyte == 0x66) { sz = 2; abyte = getIByte(delta); delta++; }
sewardj9e6491a2005-07-02 19:24:10 +000011189 dres.whatNext = Dis_StopHere;
sewardj64e1d652004-07-12 14:00:46 +000011190
11191 switch (abyte) {
11192 case 0xA4: sz = 1; /* REP MOVS<sz> */
11193 case 0xA5:
sewardj2a9ad022004-11-25 02:46:58 +000011194 dis_REP_op ( X86CondAlways, dis_MOVS, sz, eip_orig,
sewardj9e6491a2005-07-02 19:24:10 +000011195 guest_EIP_bbstart+delta, "rep movs" );
sewardj64e1d652004-07-12 14:00:46 +000011196 break;
11197
11198 case 0xA6: sz = 1; /* REPE CMP<sz> */
sewardj2d4c3a02004-10-15 00:03:23 +000011199 case 0xA7:
sewardj2a9ad022004-11-25 02:46:58 +000011200 dis_REP_op ( X86CondZ, dis_CMPS, sz, eip_orig,
sewardj9e6491a2005-07-02 19:24:10 +000011201 guest_EIP_bbstart+delta, "repe cmps" );
sewardj64e1d652004-07-12 14:00:46 +000011202 break;
11203
11204 case 0xAA: sz = 1; /* REP STOS<sz> */
11205 case 0xAB:
sewardj2a9ad022004-11-25 02:46:58 +000011206 dis_REP_op ( X86CondAlways, dis_STOS, sz, eip_orig,
sewardj9e6491a2005-07-02 19:24:10 +000011207 guest_EIP_bbstart+delta, "rep stos" );
sewardj64e1d652004-07-12 14:00:46 +000011208 break;
sewardjc9a65702004-07-07 16:32:57 +000011209//--
11210//-- case 0xAE: sz = 1; /* REPE SCAS<sz> */
11211//-- case 0xAF:
11212//-- dis_REP_op ( cb, CondZ, dis_SCAS, sz, eip_orig, eip, "repe scas" );
11213//-- break;
sewardj43b8df12004-11-26 12:18:51 +000011214
11215 case 0x90: /* REP NOP (PAUSE) */
11216 /* a hint to the P4 re spin-wait loop */
11217 DIP("rep nop (P4 pause)\n");
sewardj7ec59f62005-03-12 16:47:18 +000011218 /* "observe" the hint. The Vex client needs to be careful not
11219 to cause very long delays as a result, though. */
sewardj9e6491a2005-07-02 19:24:10 +000011220 jmp_lit(Ijk_Yield, ((Addr32)guest_EIP_bbstart)+delta);
11221 dres.whatNext = Dis_StopHere;
sewardj43b8df12004-11-26 12:18:51 +000011222 break;
11223
sewardjc9a65702004-07-07 16:32:57 +000011224//-- case 0xC3: /* REP RET */
11225//-- /* AMD K7/K8-specific optimisation; faster than vanilla RET */
11226//-- dis_ret(cb, 0);
11227//-- DIP("rep ret\n");
11228//-- break;
sewardj64e1d652004-07-12 14:00:46 +000011229
11230 default:
11231 goto decode_failure;
11232 }
11233 break;
11234 }
sewardj0611d802004-07-11 02:37:54 +000011235
11236 /* ------------------------ XCHG ----------------------- */
11237
11238 case 0x86: /* XCHG Gb,Eb */
11239 sz = 1;
11240 /* Fall through ... */
11241 case 0x87: /* XCHG Gv,Ev */
11242 modrm = getIByte(delta);
11243 ty = szToITy(sz);
11244 t1 = newTemp(ty); t2 = newTemp(ty);
11245 if (epartIsReg(modrm)) {
sewardj5bd4d162004-11-10 13:02:48 +000011246 assign(t1, getIReg(sz, eregOfRM(modrm)));
11247 assign(t2, getIReg(sz, gregOfRM(modrm)));
11248 putIReg(sz, gregOfRM(modrm), mkexpr(t1));
11249 putIReg(sz, eregOfRM(modrm), mkexpr(t2));
sewardj0611d802004-07-11 02:37:54 +000011250 delta++;
11251 DIP("xchg%c %s, %s\n",
11252 nameISize(sz), nameIReg(sz,gregOfRM(modrm)),
11253 nameIReg(sz,eregOfRM(modrm)));
11254 } else {
sewardj0c12ea82004-07-12 08:18:16 +000011255 addr = disAMode ( &alen, sorb, delta, dis_buf );
sewardj5bd4d162004-11-10 13:02:48 +000011256 assign( t1, loadLE(ty,mkexpr(addr)) );
11257 assign( t2, getIReg(sz,gregOfRM(modrm)) );
11258 storeLE( mkexpr(addr), mkexpr(t2) );
11259 putIReg( sz, gregOfRM(modrm), mkexpr(t1) );
11260 delta += alen;
sewardj0611d802004-07-11 02:37:54 +000011261 DIP("xchg%c %s, %s\n", nameISize(sz),
11262 nameIReg(sz,gregOfRM(modrm)), dis_buf);
sewardj0611d802004-07-11 02:37:54 +000011263 }
11264 break;
sewardje87b4842004-07-10 12:23:30 +000011265
11266 case 0x90: /* XCHG eAX,eAX */
11267 DIP("nop\n");
11268 break;
sewardj64e1d652004-07-12 14:00:46 +000011269 case 0x91: /* XCHG eAX,eCX */
11270 case 0x92: /* XCHG eAX,eDX */
11271 case 0x93: /* XCHG eAX,eBX */
11272 case 0x94: /* XCHG eAX,eSP */
11273 case 0x95: /* XCHG eAX,eBP */
11274 case 0x96: /* XCHG eAX,eSI */
11275 case 0x97: /* XCHG eAX,eDI */
11276 codegen_xchg_eAX_Reg ( sz, opc - 0x90 );
11277 break;
11278
sewardjc9a65702004-07-07 16:32:57 +000011279//-- /* ------------------------ XLAT ----------------------- */
11280//--
11281//-- case 0xD7: /* XLAT */
11282//-- t1 = newTemp(cb); t2 = newTemp(cb);
11283//-- uInstr2(cb, GET, sz, ArchReg, R_EBX, TempReg, t1); /* get eBX */
11284//-- handleSegOverride( cb, sorb, t1 ); /* make t1 DS:eBX */
11285//-- uInstr2(cb, GET, 1, ArchReg, R_AL, TempReg, t2); /* get AL */
11286//-- /* Widen %AL to 32 bits, so it's all defined when we add it. */
11287//-- uInstr1(cb, WIDEN, 4, TempReg, t2);
11288//-- uWiden(cb, 1, False);
11289//-- uInstr2(cb, ADD, sz, TempReg, t2, TempReg, t1); /* add AL to eBX */
11290//-- uInstr2(cb, LOAD, 1, TempReg, t1, TempReg, t2); /* get byte at t1 into t2 */
11291//-- uInstr2(cb, PUT, 1, TempReg, t2, ArchReg, R_AL); /* put byte into AL */
11292//--
11293//-- DIP("xlat%c [ebx]\n", nameISize(sz));
11294//-- break;
11295//--
11296//-- /* ------------------------ IN / OUT ----------------------- */
11297//--
11298//-- case 0xE4: /* IN ib, %al */
11299//-- case 0xE5: /* IN ib, %{e}ax */
11300//-- case 0xEC: /* IN (%dx),%al */
11301//-- case 0xED: /* IN (%dx),%{e}ax */
11302//-- t1 = newTemp(cb);
11303//-- t2 = newTemp(cb);
11304//-- t3 = newTemp(cb);
11305//--
11306//-- uInstr0(cb, CALLM_S, 0);
11307//-- /* operand size? */
11308//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t1);
11309//-- uLiteral(cb, ( opc == 0xE4 || opc == 0xEC ) ? 1 : sz);
11310//-- uInstr1(cb, PUSH, 4, TempReg, t1);
11311//-- /* port number ? */
11312//-- if ( opc == 0xE4 || opc == 0xE5 ) {
11313//-- abyte = getUChar(eip); eip++;
11314//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
11315//-- uLiteral(cb, abyte);
11316//-- }
11317//-- else
11318//-- uInstr2(cb, GET, 4, ArchReg, R_EDX, TempReg, t2);
11319//--
11320//-- uInstr1(cb, PUSH, 4, TempReg, t2);
11321//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_IN));
11322//-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
11323//-- uInstr1(cb, POP, 4, TempReg, t2);
11324//-- uInstr1(cb, CLEAR, 0, Lit16, 4);
11325//-- uInstr0(cb, CALLM_E, 0);
11326//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_EAX);
11327//-- if ( opc == 0xE4 || opc == 0xE5 ) {
11328//-- DIP("in 0x%x, %%eax/%%ax/%%al\n", getUChar(eip-1) );
11329//-- } else {
11330//-- DIP("in (%%dx), %%eax/%%ax/%%al\n");
11331//-- }
11332//-- break;
11333//-- case 0xE6: /* OUT %al,ib */
11334//-- case 0xE7: /* OUT %{e}ax,ib */
11335//-- case 0xEE: /* OUT %al,(%dx) */
11336//-- case 0xEF: /* OUT %{e}ax,(%dx) */
11337//-- t1 = newTemp(cb);
11338//-- t2 = newTemp(cb);
11339//-- t3 = newTemp(cb);
11340//--
11341//-- uInstr0(cb, CALLM_S, 0);
11342//-- /* operand size? */
11343//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t1);
11344//-- uLiteral(cb, ( opc == 0xE6 || opc == 0xEE ) ? 1 : sz);
11345//-- uInstr1(cb, PUSH, 4, TempReg, t1);
11346//-- /* port number ? */
11347//-- if ( opc == 0xE6 || opc == 0xE7 ) {
11348//-- abyte = getUChar(eip); eip++;
11349//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
11350//-- uLiteral(cb, abyte);
11351//-- }
11352//-- else
11353//-- uInstr2(cb, GET, 4, ArchReg, R_EDX, TempReg, t2);
11354//-- uInstr1(cb, PUSH, 4, TempReg, t2);
11355//-- uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, t3);
11356//-- uInstr1(cb, PUSH, 4, TempReg, t3);
11357//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_OUT));
11358//-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
11359//-- uInstr1(cb, CLEAR, 0, Lit16, 12);
11360//-- uInstr0(cb, CALLM_E, 0);
11361//-- if ( opc == 0xE4 || opc == 0xE5 ) {
11362//-- DIP("out %%eax/%%ax/%%al, 0x%x\n", getUChar(eip-1) );
11363//-- } else {
11364//-- DIP("out %%eax/%%ax/%%al, (%%dx)\n");
11365//-- }
11366//-- break;
sewardj0611d802004-07-11 02:37:54 +000011367
11368 /* ------------------------ (Grp1 extensions) ---------- */
11369
11370 case 0x80: /* Grp1 Ib,Eb */
11371 modrm = getIByte(delta);
11372 am_sz = lengthAMode(delta);
11373 sz = 1;
11374 d_sz = 1;
sewardjc2ac51e2004-07-12 01:03:26 +000011375 d32 = getUChar(delta + am_sz);
sewardj0611d802004-07-11 02:37:54 +000011376 delta = dis_Grp1 ( sorb, delta, modrm, am_sz, d_sz, sz, d32 );
11377 break;
sewardje05c42c2004-07-08 20:25:10 +000011378
11379 case 0x81: /* Grp1 Iv,Ev */
11380 modrm = getIByte(delta);
11381 am_sz = lengthAMode(delta);
11382 d_sz = sz;
11383 d32 = getUDisp(d_sz, delta + am_sz);
11384 delta = dis_Grp1 ( sorb, delta, modrm, am_sz, d_sz, sz, d32 );
11385 break;
sewardjd1061ab2004-07-08 01:45:30 +000011386
11387 case 0x83: /* Grp1 Ib,Ev */
11388 modrm = getIByte(delta);
11389 am_sz = lengthAMode(delta);
11390 d_sz = 1;
11391 d32 = getSDisp8(delta + am_sz);
11392 delta = dis_Grp1 ( sorb, delta, modrm, am_sz, d_sz, sz, d32 );
11393 break;
11394
sewardjc2ac51e2004-07-12 01:03:26 +000011395 /* ------------------------ (Grp2 extensions) ---------- */
11396
11397 case 0xC0: /* Grp2 Ib,Eb */
11398 modrm = getIByte(delta);
11399 am_sz = lengthAMode(delta);
11400 d_sz = 1;
sewardj180e8b32004-07-29 01:40:11 +000011401 d32 = getUChar(delta + am_sz);
sewardjc2ac51e2004-07-12 01:03:26 +000011402 sz = 1;
sewardj6d2638e2004-07-15 09:38:27 +000011403 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
11404 mkU8(d32 & 0xFF), NULL );
sewardjc2ac51e2004-07-12 01:03:26 +000011405 break;
sewardje90ad6a2004-07-10 19:02:10 +000011406
11407 case 0xC1: /* Grp2 Ib,Ev */
sewardjc2ac51e2004-07-12 01:03:26 +000011408 modrm = getIByte(delta);
sewardje90ad6a2004-07-10 19:02:10 +000011409 am_sz = lengthAMode(delta);
11410 d_sz = 1;
sewardj180e8b32004-07-29 01:40:11 +000011411 d32 = getUChar(delta + am_sz);
sewardj6d2638e2004-07-15 09:38:27 +000011412 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
11413 mkU8(d32 & 0xFF), NULL );
sewardje90ad6a2004-07-10 19:02:10 +000011414 break;
11415
sewardj180e8b32004-07-29 01:40:11 +000011416 case 0xD0: /* Grp2 1,Eb */
11417 modrm = getIByte(delta);
11418 am_sz = lengthAMode(delta);
11419 d_sz = 0;
11420 d32 = 1;
11421 sz = 1;
11422 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
11423 mkU8(d32), NULL );
11424 break;
sewardjc2ac51e2004-07-12 01:03:26 +000011425
11426 case 0xD1: /* Grp2 1,Ev */
11427 modrm = getUChar(delta);
11428 am_sz = lengthAMode(delta);
11429 d_sz = 0;
11430 d32 = 1;
sewardj6d2638e2004-07-15 09:38:27 +000011431 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
11432 mkU8(d32), NULL );
sewardjc2ac51e2004-07-12 01:03:26 +000011433 break;
11434
sewardj8c7f1ab2004-07-29 20:31:09 +000011435 case 0xD2: /* Grp2 CL,Eb */
11436 modrm = getUChar(delta);
11437 am_sz = lengthAMode(delta);
11438 d_sz = 0;
11439 sz = 1;
11440 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
11441 getIReg(1,R_ECX), "%cl" );
11442 break;
sewardj9334b0f2004-07-10 22:43:54 +000011443
11444 case 0xD3: /* Grp2 CL,Ev */
11445 modrm = getIByte(delta);
11446 am_sz = lengthAMode(delta);
11447 d_sz = 0;
11448 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
sewardj6d2638e2004-07-15 09:38:27 +000011449 getIReg(1,R_ECX), "%cl" );
sewardj9334b0f2004-07-10 22:43:54 +000011450 break;
11451
sewardj940e8c92004-07-11 16:53:24 +000011452 /* ------------------------ (Grp3 extensions) ---------- */
11453
11454 case 0xF6: /* Grp3 Eb */
11455 delta = dis_Grp3 ( sorb, 1, delta );
11456 break;
11457 case 0xF7: /* Grp3 Ev */
11458 delta = dis_Grp3 ( sorb, sz, delta );
11459 break;
11460
sewardjc2ac51e2004-07-12 01:03:26 +000011461 /* ------------------------ (Grp4 extensions) ---------- */
11462
11463 case 0xFE: /* Grp4 Eb */
11464 delta = dis_Grp4 ( sorb, delta );
11465 break;
sewardj0611d802004-07-11 02:37:54 +000011466
11467 /* ------------------------ (Grp5 extensions) ---------- */
11468
11469 case 0xFF: /* Grp5 Ev */
sewardj9e6491a2005-07-02 19:24:10 +000011470 delta = dis_Grp5 ( sorb, sz, delta, &dres );
sewardj0611d802004-07-11 02:37:54 +000011471 break;
sewardje87b4842004-07-10 12:23:30 +000011472
11473 /* ------------------------ Escapes to 2-byte opcodes -- */
11474
11475 case 0x0F: {
11476 opc = getIByte(delta); delta++;
11477 switch (opc) {
11478
sewardj490ad382005-03-13 17:25:53 +000011479 /* =-=-=-=-=-=-=-=-=- Grp8 =-=-=-=-=-=-=-=-=-=-=-= */
11480
11481 case 0xBA: { /* Grp8 Ib,Ev */
11482 Bool decode_OK = False;
11483 modrm = getUChar(delta);
11484 am_sz = lengthAMode(delta);
11485 d32 = getSDisp8(delta + am_sz);
11486 delta = dis_Grp8_Imm ( sorb, delta, modrm, am_sz, sz, d32,
11487 &decode_OK );
11488 if (!decode_OK)
11489 goto decode_failure;
11490 break;
11491 }
sewardjce646f22004-08-31 23:55:54 +000011492
11493 /* =-=-=-=-=-=-=-=-=- BSF/BSR -=-=-=-=-=-=-=-=-=-= */
11494
11495 case 0xBC: /* BSF Gv,Ev */
11496 delta = dis_bs_E_G ( sorb, sz, delta, True );
11497 break;
11498 case 0xBD: /* BSR Gv,Ev */
11499 delta = dis_bs_E_G ( sorb, sz, delta, False );
11500 break;
sewardj1c4208f2004-08-25 13:25:29 +000011501
11502 /* =-=-=-=-=-=-=-=-=- BSWAP -=-=-=-=-=-=-=-=-=-=-= */
11503
11504 case 0xC8: /* BSWAP %eax */
11505 case 0xC9:
11506 case 0xCA:
sewardjb4666cf2004-10-23 00:21:50 +000011507 case 0xCB:
11508 case 0xCC:
11509 case 0xCD:
sewardj1c4208f2004-08-25 13:25:29 +000011510 case 0xCE:
sewardj1c6f9912004-09-07 10:15:24 +000011511 case 0xCF: /* BSWAP %edi */
sewardj1c4208f2004-08-25 13:25:29 +000011512 /* AFAICS from the Intel docs, this only exists at size 4. */
11513 vassert(sz == 4);
11514 t1 = newTemp(Ity_I32);
11515 t2 = newTemp(Ity_I32);
11516 assign( t1, getIReg(4, opc-0xC8) );
11517
11518 assign( t2,
11519 binop(Iop_Or32,
11520 binop(Iop_Shl32, mkexpr(t1), mkU8(24)),
11521 binop(Iop_Or32,
11522 binop(Iop_And32, binop(Iop_Shl32, mkexpr(t1), mkU8(8)),
11523 mkU32(0x00FF0000)),
11524 binop(Iop_Or32,
11525 binop(Iop_And32, binop(Iop_Shr32, mkexpr(t1), mkU8(8)),
11526 mkU32(0x0000FF00)),
11527 binop(Iop_And32, binop(Iop_Shr32, mkexpr(t1), mkU8(24)),
11528 mkU32(0x000000FF) )
11529 )))
11530 );
11531
11532 putIReg(4, opc-0xC8, mkexpr(t2));
sewardj1c4208f2004-08-25 13:25:29 +000011533 DIP("bswapl %s\n", nameIReg(4, opc-0xC8));
11534 break;
11535
sewardj1c6f9912004-09-07 10:15:24 +000011536 /* =-=-=-=-=-=-=-=-=- BT/BTS/BTR/BTC =-=-=-=-=-=-= */
11537
11538 case 0xA3: /* BT Gv,Ev */
11539 delta = dis_bt_G_E ( sorb, sz, delta, BtOpNone );
11540 break;
sewardje6709112004-09-10 18:37:18 +000011541 case 0xB3: /* BTR Gv,Ev */
11542 delta = dis_bt_G_E ( sorb, sz, delta, BtOpReset );
11543 break;
sewardj1c6f9912004-09-07 10:15:24 +000011544 case 0xAB: /* BTS Gv,Ev */
11545 delta = dis_bt_G_E ( sorb, sz, delta, BtOpSet );
11546 break;
sewardj4963a422004-10-14 23:34:03 +000011547 case 0xBB: /* BTC Gv,Ev */
11548 delta = dis_bt_G_E ( sorb, sz, delta, BtOpComp );
11549 break;
sewardj458a6f82004-08-25 12:46:02 +000011550
11551 /* =-=-=-=-=-=-=-=-=- CMOV =-=-=-=-=-=-=-=-=-=-=-= */
11552
sewardj2d4c3a02004-10-15 00:03:23 +000011553 case 0x40:
11554 case 0x41:
sewardj458a6f82004-08-25 12:46:02 +000011555 case 0x42: /* CMOVBb/CMOVNAEb (cmov below) */
11556 case 0x43: /* CMOVNBb/CMOVAEb (cmov not below) */
11557 case 0x44: /* CMOVZb/CMOVEb (cmov zero) */
11558 case 0x45: /* CMOVNZb/CMOVNEb (cmov not zero) */
11559 case 0x46: /* CMOVBEb/CMOVNAb (cmov below or equal) */
11560 case 0x47: /* CMOVNBEb/CMOVAb (cmov not below or equal) */
sewardjce646f22004-08-31 23:55:54 +000011561 case 0x48: /* CMOVSb (cmov negative) */
sewardj458a6f82004-08-25 12:46:02 +000011562 case 0x49: /* CMOVSb (cmov not negative) */
sewardj2d4c3a02004-10-15 00:03:23 +000011563 case 0x4A: /* CMOVP (cmov parity even) */
11564 case 0x4B: /* CMOVNP (cmov parity odd) */
sewardj458a6f82004-08-25 12:46:02 +000011565 case 0x4C: /* CMOVLb/CMOVNGEb (cmov less) */
11566 case 0x4D: /* CMOVGEb/CMOVNLb (cmov greater or equal) */
11567 case 0x4E: /* CMOVLEb/CMOVNGb (cmov less or equal) */
11568 case 0x4F: /* CMOVGb/CMOVNLEb (cmov greater) */
sewardj2a9ad022004-11-25 02:46:58 +000011569 delta = dis_cmov_E_G(sorb, sz, (X86Condcode)(opc - 0x40), delta);
sewardj458a6f82004-08-25 12:46:02 +000011570 break;
11571
11572 /* =-=-=-=-=-=-=-=-=- CMPXCHG -=-=-=-=-=-=-=-=-=-= */
11573
sewardjc744e872004-08-26 11:24:39 +000011574 case 0xB0: /* CMPXCHG Gb,Eb */
11575 delta = dis_cmpxchg_G_E ( sorb, 1, delta );
11576 break;
sewardj458a6f82004-08-25 12:46:02 +000011577 case 0xB1: /* CMPXCHG Gv,Ev */
11578 delta = dis_cmpxchg_G_E ( sorb, sz, delta );
11579 break;
sewardjc9a65702004-07-07 16:32:57 +000011580//-- case 0xC7: /* CMPXCHG8B Gv */
11581//-- eip = dis_cmpxchg8b ( cb, sorb, eip );
11582//-- break;
11583//--
sewardj588ea762004-09-10 18:56:32 +000011584 /* =-=-=-=-=-=-=-=-=- CPUID -=-=-=-=-=-=-=-=-=-=-= */
11585
sewardj7cb49d72004-10-24 22:31:25 +000011586 case 0xA2: { /* CPUID */
11587 /* Uses dirty helper:
sewardj9df271d2004-12-31 22:37:42 +000011588 void dirtyhelper_CPUID_sse[012] ( VexGuestX86State* )
sewardj7cb49d72004-10-24 22:31:25 +000011589 declared to mod eax, wr ebx, ecx, edx
11590 */
sewardj9df271d2004-12-31 22:37:42 +000011591 IRDirty* d = NULL;
11592 HChar* fName = NULL;
11593 void* fAddr = NULL;
sewardj27e1dd62005-06-30 11:49:14 +000011594 switch (archinfo->subarch) {
sewardj9df271d2004-12-31 22:37:42 +000011595 case VexSubArchX86_sse0:
11596 fName = "x86g_dirtyhelper_CPUID_sse0";
11597 fAddr = &x86g_dirtyhelper_CPUID_sse0;
11598 break;
11599 case VexSubArchX86_sse1:
11600 fName = "x86g_dirtyhelper_CPUID_sse1";
11601 fAddr = &x86g_dirtyhelper_CPUID_sse1;
11602 break;
11603 case VexSubArchX86_sse2:
11604 fName = "x86g_dirtyhelper_CPUID_sse2";
11605 fAddr = &x86g_dirtyhelper_CPUID_sse2;
11606 break;
11607 default:
11608 vpanic("disInstr(x86)(cpuid)");
11609 }
11610 vassert(fName); vassert(fAddr);
11611 d = unsafeIRDirty_0_N ( 0/*regparms*/,
11612 fName, fAddr, mkIRExprVec_0() );
sewardj7cb49d72004-10-24 22:31:25 +000011613 /* declare guest state effects */
sewardjc5fc7aa2004-10-27 23:00:55 +000011614 d->needsBBP = True;
sewardj7cb49d72004-10-24 22:31:25 +000011615 d->nFxState = 4;
11616 d->fxState[0].fx = Ifx_Modify;
11617 d->fxState[0].offset = OFFB_EAX;
11618 d->fxState[0].size = 4;
11619 d->fxState[1].fx = Ifx_Write;
11620 d->fxState[1].offset = OFFB_EBX;
11621 d->fxState[1].size = 4;
11622 d->fxState[2].fx = Ifx_Write;
11623 d->fxState[2].offset = OFFB_ECX;
11624 d->fxState[2].size = 4;
11625 d->fxState[3].fx = Ifx_Write;
11626 d->fxState[3].offset = OFFB_EDX;
11627 d->fxState[3].size = 4;
11628 /* execute the dirty call, side-effecting guest state */
11629 stmt( IRStmt_Dirty(d) );
sewardj55860d82005-01-08 18:25:05 +000011630 /* CPUID is a serialising insn. So, just in case someone is
11631 using it as a memory fence ... */
11632 stmt( IRStmt_MFence() );
sewardj517a7d62004-10-25 09:52:18 +000011633 DIP("cpuid\n");
sewardj588ea762004-09-10 18:56:32 +000011634 break;
sewardj7cb49d72004-10-24 22:31:25 +000011635 }
11636
sewardj5bd4d162004-11-10 13:02:48 +000011637//-- if (!VG_(cpu_has_feature)(VG_X86_FEAT_CPUID))
11638//-- goto decode_failure;
sewardjc9a65702004-07-07 16:32:57 +000011639//--
11640//-- t1 = newTemp(cb);
11641//-- t2 = newTemp(cb);
11642//-- t3 = newTemp(cb);
11643//-- t4 = newTemp(cb);
11644//-- uInstr0(cb, CALLM_S, 0);
11645//--
11646//-- uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, t1);
11647//-- uInstr1(cb, PUSH, 4, TempReg, t1);
11648//--
11649//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
11650//-- uLiteral(cb, 0);
11651//-- uInstr1(cb, PUSH, 4, TempReg, t2);
11652//--
11653//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t3);
11654//-- uLiteral(cb, 0);
11655//-- uInstr1(cb, PUSH, 4, TempReg, t3);
11656//--
11657//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t4);
11658//-- uLiteral(cb, 0);
11659//-- uInstr1(cb, PUSH, 4, TempReg, t4);
11660//--
11661//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_CPUID));
11662//-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
11663//--
11664//-- uInstr1(cb, POP, 4, TempReg, t4);
11665//-- uInstr2(cb, PUT, 4, TempReg, t4, ArchReg, R_EDX);
11666//--
11667//-- uInstr1(cb, POP, 4, TempReg, t3);
11668//-- uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_ECX);
11669//--
11670//-- uInstr1(cb, POP, 4, TempReg, t2);
11671//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_EBX);
11672//--
11673//-- uInstr1(cb, POP, 4, TempReg, t1);
11674//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_EAX);
11675//--
11676//-- uInstr0(cb, CALLM_E, 0);
11677//-- DIP("cpuid\n");
11678//-- break;
11679//--
sewardj9334b0f2004-07-10 22:43:54 +000011680 /* =-=-=-=-=-=-=-=-=- MOVZX, MOVSX =-=-=-=-=-=-=-= */
11681
11682 case 0xB6: /* MOVZXb Eb,Gv */
11683 delta = dis_movx_E_G ( sorb, delta, 1, 4, False );
11684 break;
sewardj940e8c92004-07-11 16:53:24 +000011685 case 0xB7: /* MOVZXw Ew,Gv */
11686 delta = dis_movx_E_G ( sorb, delta, 2, 4, False );
11687 break;
11688
sewardj0611d802004-07-11 02:37:54 +000011689 case 0xBE: /* MOVSXb Eb,Gv */
11690 delta = dis_movx_E_G ( sorb, delta, 1, 4, True );
11691 break;
sewardj7ed22952004-07-29 00:09:58 +000011692 case 0xBF: /* MOVSXw Ew,Gv */
11693 delta = dis_movx_E_G ( sorb, delta, 2, 4, True );
11694 break;
11695
sewardjc9a65702004-07-07 16:32:57 +000011696//-- /* =-=-=-=-=-=-=-=-=-=-= MOVNTI -=-=-=-=-=-=-=-=-= */
11697//--
11698//-- case 0xC3: /* MOVNTI Gv,Ev */
11699//-- vg_assert(sz == 4);
11700//-- modrm = getUChar(eip);
11701//-- vg_assert(!epartIsReg(modrm));
11702//-- t1 = newTemp(cb);
11703//-- uInstr2(cb, GET, 4, ArchReg, gregOfRM(modrm), TempReg, t1);
11704//-- pair = disAMode ( cb, sorb, eip, dis_buf );
11705//-- t2 = LOW24(pair);
11706//-- eip += HI8(pair);
11707//-- uInstr2(cb, STORE, 4, TempReg, t1, TempReg, t2);
11708//-- DIP("movnti %s,%s\n", nameIReg(4,gregOfRM(modrm)), dis_buf);
11709//-- break;
sewardjcf780b42004-07-13 18:42:17 +000011710
11711 /* =-=-=-=-=-=-=-=-=- MUL/IMUL =-=-=-=-=-=-=-=-=-= */
11712
11713 case 0xAF: /* IMUL Ev, Gv */
sewardj2a2ba8b2004-11-08 13:14:06 +000011714 delta = dis_mul_E_G ( sorb, sz, delta );
sewardjcf780b42004-07-13 18:42:17 +000011715 break;
sewardje87b4842004-07-10 12:23:30 +000011716
11717 /* =-=-=-=-=-=-=-=-=- Jcond d32 -=-=-=-=-=-=-=-=-= */
11718 case 0x80:
11719 case 0x81:
11720 case 0x82: /* JBb/JNAEb (jump below) */
11721 case 0x83: /* JNBb/JAEb (jump not below) */
11722 case 0x84: /* JZb/JEb (jump zero) */
11723 case 0x85: /* JNZb/JNEb (jump not zero) */
11724 case 0x86: /* JBEb/JNAb (jump below or equal) */
11725 case 0x87: /* JNBEb/JAb (jump not below or equal) */
11726 case 0x88: /* JSb (jump negative) */
11727 case 0x89: /* JSb (jump not negative) */
11728 case 0x8A: /* JP (jump parity even) */
11729 case 0x8B: /* JNP/JPO (jump parity odd) */
11730 case 0x8C: /* JLb/JNGEb (jump less) */
11731 case 0x8D: /* JGEb/JNLb (jump greater or equal) */
11732 case 0x8E: /* JLEb/JNGb (jump less or equal) */
11733 case 0x8F: /* JGb/JNLEb (jump greater) */
sewardj9e6491a2005-07-02 19:24:10 +000011734 d32 = (((Addr32)guest_EIP_bbstart)+delta+4) + getUDisp32(delta);
sewardje87b4842004-07-10 12:23:30 +000011735 delta += 4;
sewardj2a9ad022004-11-25 02:46:58 +000011736 jcc_01( (X86Condcode)(opc - 0x80),
sewardj9e6491a2005-07-02 19:24:10 +000011737 (Addr32)(guest_EIP_bbstart+delta),
sewardj2a9ad022004-11-25 02:46:58 +000011738 d32 );
sewardj9e6491a2005-07-02 19:24:10 +000011739 dres.whatNext = Dis_StopHere;
sewardj2a9ad022004-11-25 02:46:58 +000011740 DIP("j%s-32 0x%x\n", name_X86Condcode(opc - 0x80), d32);
sewardje87b4842004-07-10 12:23:30 +000011741 break;
11742
sewardj89cd0932004-09-08 18:23:25 +000011743 /* =-=-=-=-=-=-=-=-=- RDTSC -=-=-=-=-=-=-=-=-=-=-= */
11744
11745 case 0x31: /* RDTSC */
sewardjcb2c99d2004-12-17 19:14:24 +000011746 if (0) vex_printf("vex x86->IR: kludged rdtsc\n");
sewardj83301962005-03-23 11:35:55 +000011747 putIReg(4, R_EAX, mkU32(1));
sewardj89cd0932004-09-08 18:23:25 +000011748 putIReg(4, R_EDX, mkU32(0));
11749
sewardjc9a65702004-07-07 16:32:57 +000011750//-- t1 = newTemp(cb);
11751//-- t2 = newTemp(cb);
11752//-- t3 = newTemp(cb);
11753//-- uInstr0(cb, CALLM_S, 0);
11754//-- // Nb: even though these args aren't used by RDTSC_helper, need
11755//-- // them to be defined (for Memcheck). The TempRegs pushed must
11756//-- // also be distinct.
11757//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t1);
11758//-- uLiteral(cb, 0);
11759//-- uInstr1(cb, PUSH, 4, TempReg, t1);
11760//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
11761//-- uLiteral(cb, 0);
11762//-- uInstr1(cb, PUSH, 4, TempReg, t2);
11763//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_RDTSC));
11764//-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
11765//-- uInstr1(cb, POP, 4, TempReg, t3);
11766//-- uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_EDX);
11767//-- uInstr1(cb, POP, 4, TempReg, t3);
11768//-- uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_EAX);
11769//-- uInstr0(cb, CALLM_E, 0);
sewardj89cd0932004-09-08 18:23:25 +000011770 DIP("rdtsc\n");
11771 break;
sewardj77b86be2004-07-11 13:28:24 +000011772
sewardjb64821b2004-12-14 10:00:16 +000011773 /* =-=-=-=-=-=-=-=-=- PUSH/POP Sreg =-=-=-=-=-=-=-=-=-= */
11774
11775 case 0xA1: /* POP %FS */
11776 dis_pop_segreg( R_FS, sz ); break;
11777 case 0xA9: /* POP %GS */
11778 dis_pop_segreg( R_GS, sz ); break;
11779
11780 case 0xA0: /* PUSH %FS */
11781 dis_push_segreg( R_FS, sz ); break;
11782 case 0xA8: /* PUSH %GS */
11783 dis_push_segreg( R_GS, sz ); break;
11784
sewardj77b86be2004-07-11 13:28:24 +000011785 /* =-=-=-=-=-=-=-=-=- SETcc Eb =-=-=-=-=-=-=-=-=-= */
11786 case 0x90:
11787 case 0x91:
11788 case 0x92: /* set-Bb/set-NAEb (jump below) */
11789 case 0x93: /* set-NBb/set-AEb (jump not below) */
11790 case 0x94: /* set-Zb/set-Eb (jump zero) */
11791 case 0x95: /* set-NZb/set-NEb (jump not zero) */
11792 case 0x96: /* set-BEb/set-NAb (jump below or equal) */
11793 case 0x97: /* set-NBEb/set-Ab (jump not below or equal) */
11794 case 0x98: /* set-Sb (jump negative) */
11795 case 0x99: /* set-Sb (jump not negative) */
11796 case 0x9A: /* set-P (jump parity even) */
11797 case 0x9B: /* set-NP (jump parity odd) */
11798 case 0x9C: /* set-Lb/set-NGEb (jump less) */
11799 case 0x9D: /* set-GEb/set-NLb (jump greater or equal) */
11800 case 0x9E: /* set-LEb/set-NGb (jump less or equal) */
11801 case 0x9F: /* set-Gb/set-NLEb (jump greater) */
sewardj5bd4d162004-11-10 13:02:48 +000011802 t1 = newTemp(Ity_I8);
sewardj2a9ad022004-11-25 02:46:58 +000011803 assign( t1, unop(Iop_1Uto8,mk_x86g_calculate_condition(opc-0x90)) );
sewardj77b86be2004-07-11 13:28:24 +000011804 modrm = getIByte(delta);
11805 if (epartIsReg(modrm)) {
11806 delta++;
sewardj5bd4d162004-11-10 13:02:48 +000011807 putIReg(1, eregOfRM(modrm), mkexpr(t1));
sewardj2a9ad022004-11-25 02:46:58 +000011808 DIP("set%s %s\n", name_X86Condcode(opc-0x90),
sewardj77b86be2004-07-11 13:28:24 +000011809 nameIReg(1,eregOfRM(modrm)));
11810 } else {
sewardj750f4072004-07-26 22:39:11 +000011811 addr = disAMode ( &alen, sorb, delta, dis_buf );
11812 delta += alen;
11813 storeLE( mkexpr(addr), mkexpr(t1) );
sewardj2a9ad022004-11-25 02:46:58 +000011814 DIP("set%s %s\n", name_X86Condcode(opc-0x90), dis_buf);
sewardj77b86be2004-07-11 13:28:24 +000011815 }
11816 break;
11817
sewardj180e8b32004-07-29 01:40:11 +000011818 /* =-=-=-=-=-=-=-=-=- SHLD/SHRD -=-=-=-=-=-=-=-=-= */
11819
11820 case 0xA4: /* SHLDv imm8,Gv,Ev */
11821 modrm = getIByte(delta);
11822 d32 = delta + lengthAMode(delta);
sewardj2d49b432005-02-01 00:37:06 +000011823 vex_sprintf(dis_buf, "$%d", getIByte(d32));
sewardj180e8b32004-07-29 01:40:11 +000011824 delta = dis_SHLRD_Gv_Ev (
11825 sorb, delta, modrm, sz,
11826 mkU8(getIByte(d32)), True, /* literal */
11827 dis_buf, True );
11828 break;
sewardja06e5562004-07-14 13:18:05 +000011829 case 0xA5: /* SHLDv %cl,Gv,Ev */
11830 modrm = getIByte(delta);
11831 delta = dis_SHLRD_Gv_Ev (
11832 sorb, delta, modrm, sz,
11833 getIReg(1,R_ECX), False, /* not literal */
11834 "%cl", True );
11835 break;
11836
sewardj68511542004-07-28 00:15:44 +000011837 case 0xAC: /* SHRDv imm8,Gv,Ev */
11838 modrm = getIByte(delta);
11839 d32 = delta + lengthAMode(delta);
sewardj2d49b432005-02-01 00:37:06 +000011840 vex_sprintf(dis_buf, "$%d", getIByte(d32));
sewardj68511542004-07-28 00:15:44 +000011841 delta = dis_SHLRD_Gv_Ev (
11842 sorb, delta, modrm, sz,
11843 mkU8(getIByte(d32)), True, /* literal */
11844 dis_buf, False );
11845 break;
sewardja511afc2004-07-29 22:26:03 +000011846 case 0xAD: /* SHRDv %cl,Gv,Ev */
11847 modrm = getIByte(delta);
11848 delta = dis_SHLRD_Gv_Ev (
11849 sorb, delta, modrm, sz,
11850 getIReg(1,R_ECX), False, /* not literal */
11851 "%cl", False );
11852 break;
11853
sewardj464efa42004-11-19 22:17:29 +000011854 /* =-=-=-=-=-=-=-=-=- XADD -=-=-=-=-=-=-=-=-=-= */
11855
sewardjc9a65702004-07-07 16:32:57 +000011856//-- case 0xC0: /* XADD Gb,Eb */
11857//-- eip = dis_xadd_G_E ( cb, sorb, 1, eip );
11858//-- break;
sewardj883b00b2004-09-11 09:30:24 +000011859 case 0xC1: /* XADD Gv,Ev */
11860 delta = dis_xadd_G_E ( sorb, sz, delta );
11861 break;
11862
sewardjf13f37b2004-12-08 17:01:23 +000011863 /* =-=-=-=-=-=-=-=-=- MMXery =-=-=-=-=-=-=-=-=-=-= */
sewardj464efa42004-11-19 22:17:29 +000011864
sewardj2b7a9202004-11-26 19:15:38 +000011865 case 0x71:
11866 case 0x72:
sewardj38a3f862005-01-13 15:06:51 +000011867 case 0x73: /* PSLLgg/PSRAgg/PSRLgg mmxreg by imm8 */
sewardj2b7a9202004-11-26 19:15:38 +000011868
11869 case 0x6E: /* MOVD (src)ireg-or-mem, (dst)mmxreg */
11870 case 0x7E: /* MOVD (src)mmxreg, (dst)ireg-or-mem */
sewardj464efa42004-11-19 22:17:29 +000011871 case 0x7F: /* MOVQ (src)mmxreg, (dst)mmxreg-or-mem */
sewardj2b7a9202004-11-26 19:15:38 +000011872 case 0x6F: /* MOVQ (src)mmxreg-or-mem, (dst)mmxreg */
sewardj464efa42004-11-19 22:17:29 +000011873
11874 case 0xFC:
11875 case 0xFD:
11876 case 0xFE: /* PADDgg (src)mmxreg-or-mem, (dst)mmxreg */
11877
11878 case 0xEC:
11879 case 0xED: /* PADDSgg (src)mmxreg-or-mem, (dst)mmxreg */
11880
11881 case 0xDC:
11882 case 0xDD: /* PADDUSgg (src)mmxreg-or-mem, (dst)mmxreg */
11883
11884 case 0xF8:
11885 case 0xF9:
11886 case 0xFA: /* PSUBgg (src)mmxreg-or-mem, (dst)mmxreg */
11887
11888 case 0xE8:
11889 case 0xE9: /* PSUBSgg (src)mmxreg-or-mem, (dst)mmxreg */
11890
11891 case 0xD8:
11892 case 0xD9: /* PSUBUSgg (src)mmxreg-or-mem, (dst)mmxreg */
11893
11894 case 0xE5: /* PMULHW (src)mmxreg-or-mem, (dst)mmxreg */
11895 case 0xD5: /* PMULLW (src)mmxreg-or-mem, (dst)mmxreg */
11896
sewardj4340dac2004-11-20 13:17:04 +000011897 case 0xF5: /* PMADDWD (src)mmxreg-or-mem, (dst)mmxreg */
11898
11899 case 0x74:
11900 case 0x75:
11901 case 0x76: /* PCMPEQgg (src)mmxreg-or-mem, (dst)mmxreg */
11902
11903 case 0x64:
11904 case 0x65:
11905 case 0x66: /* PCMPGTgg (src)mmxreg-or-mem, (dst)mmxreg */
11906
sewardj63ba4092004-11-21 12:30:18 +000011907 case 0x6B: /* PACKSSDW (src)mmxreg-or-mem, (dst)mmxreg */
11908 case 0x63: /* PACKSSWB (src)mmxreg-or-mem, (dst)mmxreg */
11909 case 0x67: /* PACKUSWB (src)mmxreg-or-mem, (dst)mmxreg */
11910
11911 case 0x68:
11912 case 0x69:
11913 case 0x6A: /* PUNPCKHgg (src)mmxreg-or-mem, (dst)mmxreg */
11914
11915 case 0x60:
11916 case 0x61:
11917 case 0x62: /* PUNPCKLgg (src)mmxreg-or-mem, (dst)mmxreg */
11918
11919 case 0xDB: /* PAND (src)mmxreg-or-mem, (dst)mmxreg */
11920 case 0xDF: /* PANDN (src)mmxreg-or-mem, (dst)mmxreg */
11921 case 0xEB: /* POR (src)mmxreg-or-mem, (dst)mmxreg */
11922 case 0xEF: /* PXOR (src)mmxreg-or-mem, (dst)mmxreg */
11923
sewardj38a3f862005-01-13 15:06:51 +000011924 case 0xF1: /* PSLLgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj8d14a592004-11-21 17:04:50 +000011925 case 0xF2:
sewardj38a3f862005-01-13 15:06:51 +000011926 case 0xF3:
sewardj8d14a592004-11-21 17:04:50 +000011927
sewardj38a3f862005-01-13 15:06:51 +000011928 case 0xD1: /* PSRLgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj8d14a592004-11-21 17:04:50 +000011929 case 0xD2:
sewardj38a3f862005-01-13 15:06:51 +000011930 case 0xD3:
sewardj8d14a592004-11-21 17:04:50 +000011931
sewardj38a3f862005-01-13 15:06:51 +000011932 case 0xE1: /* PSRAgg (src)mmxreg-or-mem, (dst)mmxreg */
11933 case 0xE2:
sewardj464efa42004-11-19 22:17:29 +000011934 {
sewardj52d04912005-07-03 00:52:48 +000011935 Int delta0 = delta-1;
sewardj464efa42004-11-19 22:17:29 +000011936 Bool decode_OK = False;
sewardj38a3f862005-01-13 15:06:51 +000011937
11938 /* If sz==2 this is SSE, and we assume sse idec has
11939 already spotted those cases by now. */
11940 if (sz != 4)
11941 goto decode_failure;
11942
sewardj464efa42004-11-19 22:17:29 +000011943 delta = dis_MMX ( &decode_OK, sorb, sz, delta-1 );
11944 if (!decode_OK) {
11945 delta = delta0;
11946 goto decode_failure;
11947 }
11948 break;
11949 }
11950
sewardj8d14a592004-11-21 17:04:50 +000011951 case 0x77: /* EMMS */
sewardj38a3f862005-01-13 15:06:51 +000011952 if (sz != 4)
11953 goto decode_failure;
sewardj4cb918d2004-12-03 19:43:31 +000011954 do_EMMS_preamble();
sewardj8d14a592004-11-21 17:04:50 +000011955 DIP("emms\n");
11956 break;
11957
sewardje87b4842004-07-10 12:23:30 +000011958 /* =-=-=-=-=-=-=-=-=- unimp2 =-=-=-=-=-=-=-=-=-=-= */
11959
11960 default:
11961 goto decode_failure;
11962 } /* switch (opc) for the 2-byte opcodes */
11963 goto decode_success;
11964 } /* case 0x0F: of primary opcode */
sewardjc9a65702004-07-07 16:32:57 +000011965
11966 /* ------------------------ ??? ------------------------ */
11967
11968 default:
sewardje87b4842004-07-10 12:23:30 +000011969 decode_failure:
sewardjc9a65702004-07-07 16:32:57 +000011970 /* All decode failures end up here. */
sewardj52444cb2004-12-13 14:09:01 +000011971 vex_printf("vex x86->IR: unhandled instruction bytes: "
sewardjc9a65702004-07-07 16:32:57 +000011972 "0x%x 0x%x 0x%x 0x%x\n",
11973 (Int)getIByte(delta_start+0),
11974 (Int)getIByte(delta_start+1),
11975 (Int)getIByte(delta_start+2),
11976 (Int)getIByte(delta_start+3) );
sewardj52444cb2004-12-13 14:09:01 +000011977
sewardjb64821b2004-12-14 10:00:16 +000011978 /* Tell the dispatcher that this insn cannot be decoded, and so has
11979 not been executed, and (is currently) the next to be executed.
11980 EIP should be up-to-date since it made so at the start of each
11981 insn, but nevertheless be paranoid and update it again right
11982 now. */
sewardj9e6491a2005-07-02 19:24:10 +000011983 stmt( IRStmt_Put( OFFB_EIP, mkU32(guest_EIP_curr_instr) ) );
11984 jmp_lit(Ijk_NoDecode, guest_EIP_curr_instr);
11985 dres.whatNext = Dis_StopHere;
11986 dres.len = 0;
11987 return dres;
sewardj52444cb2004-12-13 14:09:01 +000011988
sewardjc9a65702004-07-07 16:32:57 +000011989 } /* switch (opc) for the main (primary) opcode switch. */
11990
sewardje87b4842004-07-10 12:23:30 +000011991 decode_success:
sewardjc9a65702004-07-07 16:32:57 +000011992 /* All decode successes end up here. */
11993 DIP("\n");
sewardjc9a65702004-07-07 16:32:57 +000011994
sewardj9e6491a2005-07-02 19:24:10 +000011995 dres.len = delta - delta_start;
11996 return dres;
sewardjc9a65702004-07-07 16:32:57 +000011997}
11998
11999#undef DIP
12000#undef DIS
12001
sewardj9e6491a2005-07-02 19:24:10 +000012002
12003/*------------------------------------------------------------*/
12004/*--- Top-level fn ---*/
12005/*------------------------------------------------------------*/
12006
12007/* Disassemble a single instruction into IR. The instruction
12008 is located in host memory at &guest_code[delta]. */
12009
12010DisResult disInstr_X86 ( IRBB* irbb_IN,
12011 Bool put_IP,
12012 Bool (*resteerOkFn) ( Addr64 ),
12013 UChar* guest_code_IN,
12014 Long delta,
12015 Addr64 guest_IP,
12016 VexArchInfo* archinfo,
12017 Bool host_bigendian_IN )
12018{
12019 DisResult dres;
12020
12021 /* Set globals (see top of this file) */
12022 guest_code = guest_code_IN;
12023 irbb = irbb_IN;
12024 host_is_bigendian = host_bigendian_IN;
12025 guest_EIP_curr_instr = (Addr32)guest_IP;
12026 guest_EIP_bbstart = (Addr32)toUInt(guest_IP - delta);
12027
12028 dres = disInstr_X86_WRK ( put_IP, resteerOkFn,
12029 delta, archinfo );
12030
12031 return dres;
12032}
12033
12034
sewardjc9a65702004-07-07 16:32:57 +000012035/*--------------------------------------------------------------------*/
sewardjc0ee2ed2004-07-27 10:29:41 +000012036/*--- end guest-x86/toIR.c ---*/
sewardjc9a65702004-07-07 16:32:57 +000012037/*--------------------------------------------------------------------*/