blob: cb0cfbe0e77f4d7b324fa2ba74c29f8ef95d2c90 [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"
105#include "guest-x86/gdefs.h"
sewardjc9a65702004-07-07 16:32:57 +0000106
107
108/*------------------------------------------------------------*/
109/*--- Globals ---*/
110/*------------------------------------------------------------*/
111
112/* These are set at the start of the translation of a BB, so
113 that we don't have to pass them around endlessly. */
114
115/* We need to know this to do sub-register accesses correctly. */
116/* CONST */
117static Bool host_is_bigendian;
118
sewardjc9a65702004-07-07 16:32:57 +0000119/* Pointer to the guest code area. */
120/* CONST */
121static UChar* guest_code;
122
123/* The guest address corresponding to guest_code[0]. */
124/* CONST */
sewardjce70a5c2004-10-18 14:09:54 +0000125static Addr32 guest_eip_bbstart;
sewardjc9a65702004-07-07 16:32:57 +0000126
sewardj52444cb2004-12-13 14:09:01 +0000127/* The guest address for the instruction currently being
128 translated. */
129/* CONST for any specific insn, not for the entire BB */
130static Addr32 guest_eip_curr_instr;
131
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
sewardjce4a2822005-01-07 13:25:28 +0000135/* Emergency verboseness just for this insn? DEBUG ONLY */
136static Bool insn_verbose = False;
137
sewardjc9a65702004-07-07 16:32:57 +0000138
sewardjce70a5c2004-10-18 14:09:54 +0000139/*------------------------------------------------------------*/
140/*--- Debugging output ---*/
141/*------------------------------------------------------------*/
142
sewardjf48ac192004-10-29 00:41:29 +0000143#define DIP(format, args...) \
sewardjce4a2822005-01-07 13:25:28 +0000144 if (insn_verbose || (vex_traceflags & VEX_TRACE_FE)) \
sewardjce70a5c2004-10-18 14:09:54 +0000145 vex_printf(format, ## args)
146
sewardjf48ac192004-10-29 00:41:29 +0000147#define DIS(buf, format, args...) \
sewardjce4a2822005-01-07 13:25:28 +0000148 if (insn_verbose || (vex_traceflags & VEX_TRACE_FE)) \
sewardjce70a5c2004-10-18 14:09:54 +0000149 vex_sprintf(buf, format, ## args)
150
151
152/*------------------------------------------------------------*/
sewardjdcc85fc2004-10-26 13:26:20 +0000153/*--- Offsets of various parts of the x86 guest state. ---*/
154/*------------------------------------------------------------*/
155
sewardjc9a43662004-11-30 18:51:59 +0000156#define OFFB_EAX offsetof(VexGuestX86State,guest_EAX)
157#define OFFB_EBX offsetof(VexGuestX86State,guest_EBX)
158#define OFFB_ECX offsetof(VexGuestX86State,guest_ECX)
159#define OFFB_EDX offsetof(VexGuestX86State,guest_EDX)
160#define OFFB_ESP offsetof(VexGuestX86State,guest_ESP)
161#define OFFB_EBP offsetof(VexGuestX86State,guest_EBP)
162#define OFFB_ESI offsetof(VexGuestX86State,guest_ESI)
163#define OFFB_EDI offsetof(VexGuestX86State,guest_EDI)
sewardj2a2ba8b2004-11-08 13:14:06 +0000164
sewardjc9a43662004-11-30 18:51:59 +0000165#define OFFB_EIP offsetof(VexGuestX86State,guest_EIP)
sewardj2a2ba8b2004-11-08 13:14:06 +0000166
sewardjc9a43662004-11-30 18:51:59 +0000167#define OFFB_CC_OP offsetof(VexGuestX86State,guest_CC_OP)
168#define OFFB_CC_DEP1 offsetof(VexGuestX86State,guest_CC_DEP1)
169#define OFFB_CC_DEP2 offsetof(VexGuestX86State,guest_CC_DEP2)
170#define OFFB_CC_NDEP offsetof(VexGuestX86State,guest_CC_NDEP)
sewardj893aada2004-11-29 19:57:54 +0000171
sewardjc9a43662004-11-30 18:51:59 +0000172#define OFFB_FPREGS offsetof(VexGuestX86State,guest_FPREG[0])
173#define OFFB_FPTAGS offsetof(VexGuestX86State,guest_FPTAG[0])
174#define OFFB_DFLAG offsetof(VexGuestX86State,guest_DFLAG)
175#define OFFB_IDFLAG offsetof(VexGuestX86State,guest_IDFLAG)
176#define OFFB_FTOP offsetof(VexGuestX86State,guest_FTOP)
177#define OFFB_FC3210 offsetof(VexGuestX86State,guest_FC3210)
178#define OFFB_FPROUND offsetof(VexGuestX86State,guest_FPROUND)
179
180#define OFFB_CS offsetof(VexGuestX86State,guest_CS)
181#define OFFB_DS offsetof(VexGuestX86State,guest_DS)
182#define OFFB_ES offsetof(VexGuestX86State,guest_ES)
183#define OFFB_FS offsetof(VexGuestX86State,guest_FS)
184#define OFFB_GS offsetof(VexGuestX86State,guest_GS)
185#define OFFB_SS offsetof(VexGuestX86State,guest_SS)
sewardj3bd6f3e2004-12-13 10:48:19 +0000186#define OFFB_LDT offsetof(VexGuestX86State,guest_LDT)
187#define OFFB_GDT offsetof(VexGuestX86State,guest_GDT)
sewardjc9a43662004-11-30 18:51:59 +0000188
189#define OFFB_SSEROUND offsetof(VexGuestX86State,guest_SSEROUND)
190#define OFFB_XMM0 offsetof(VexGuestX86State,guest_XMM0)
191#define OFFB_XMM1 offsetof(VexGuestX86State,guest_XMM1)
192#define OFFB_XMM2 offsetof(VexGuestX86State,guest_XMM2)
193#define OFFB_XMM3 offsetof(VexGuestX86State,guest_XMM3)
194#define OFFB_XMM4 offsetof(VexGuestX86State,guest_XMM4)
195#define OFFB_XMM5 offsetof(VexGuestX86State,guest_XMM5)
196#define OFFB_XMM6 offsetof(VexGuestX86State,guest_XMM6)
197#define OFFB_XMM7 offsetof(VexGuestX86State,guest_XMM7)
198
199#define OFFB_EMWARN offsetof(VexGuestX86State,guest_EMWARN)
sewardjdcc85fc2004-10-26 13:26:20 +0000200
201
202/*------------------------------------------------------------*/
sewardjce70a5c2004-10-18 14:09:54 +0000203/*--- Disassemble an entire basic block ---*/
204/*------------------------------------------------------------*/
205
206/* The results of disassembling an instruction. There are three
207 possible outcomes. For Dis_Resteer, the disassembler _must_
208 continue at the specified address. For Dis_StopHere, the
209 disassembler _must_ terminate the BB. For Dis_Continue, we may at
210 our option either disassemble the next insn, or terminate the BB;
211 but in the latter case we must set the bb's ->next field to point
212 to the next instruction. */
213
214typedef
215 enum {
216 Dis_StopHere, /* this insn terminates the BB; we must stop. */
217 Dis_Continue, /* we can optionally continue into the next insn */
218 Dis_Resteer /* followed a branch; continue at the spec'd addr */
219 }
220 DisResult;
221
222
223/* forward decls .. */
224static IRExpr* mkU32 ( UInt i );
sewardjdcc85fc2004-10-26 13:26:20 +0000225static void stmt ( IRStmt* st );
226
sewardjce70a5c2004-10-18 14:09:54 +0000227
228/* disInstr disassembles an instruction located at &guest_code[delta],
229 and sets *size to its size. If the returned value is Dis_Resteer,
sewardj5bd4d162004-11-10 13:02:48 +0000230 the next guest address is assigned to *whereNext. disInstr is not
231 permitted to return Dis_Resteer if either (1) resteerOK is False,
232 or (2) resteerOkFn, when applied to the address which it wishes to
233 resteer into, returns False. */
sewardjce70a5c2004-10-18 14:09:54 +0000234
sewardj9df271d2004-12-31 22:37:42 +0000235static
236DisResult disInstr ( /*IN*/ Bool resteerOK,
237 /*IN*/ Bool (*resteerOkFn) ( Addr64 ),
238 /*IN*/ UInt delta,
239 /*IN*/ VexSubArch subarch,
sewardj9b45b482005-02-07 01:42:18 +0000240 /*OUT*/ Int* size,
sewardj9df271d2004-12-31 22:37:42 +0000241 /*OUT*/ Addr64* whereNext );
sewardjce70a5c2004-10-18 14:09:54 +0000242
243
244/* This is the main (only, in fact) entry point for this module. */
245
246/* Disassemble a complete basic block, starting at eip, and dumping
247 the ucode into cb. Returns the size, in bytes, of the basic
248 block. */
sewardj72c72812005-01-19 11:49:45 +0000249IRBB* bbToIR_X86 ( UChar* x86code,
250 Addr64 guest_eip_start,
251 VexGuestExtents* vge,
252 Bool (*byte_accessible)(Addr64),
253 Bool (*chase_into_ok)(Addr64),
254 Bool host_bigendian,
255 VexSubArch subarch_guest )
sewardjce70a5c2004-10-18 14:09:54 +0000256{
257 UInt delta;
sewardjdcc85fc2004-10-26 13:26:20 +0000258 Int i, n_instrs, size, first_stmt_idx;
sewardjce70a5c2004-10-18 14:09:54 +0000259 Addr64 guest_next;
260 Bool resteerOK;
261 DisResult dres;
sewardjf1689312005-03-16 18:19:10 +0000262 IRStmt* imark;
sewardjce70a5c2004-10-18 14:09:54 +0000263 static Int n_resteers = 0;
264 Int d_resteers = 0;
sewardj08613742004-10-25 13:01:45 +0000265
266 /* check sanity .. */
267 vassert(vex_control.guest_max_insns >= 1);
sewardj72c72812005-01-19 11:49:45 +0000268 vassert(vex_control.guest_max_insns < 500);
sewardj08613742004-10-25 13:01:45 +0000269 vassert(vex_control.guest_chase_thresh >= 0);
270 vassert(vex_control.guest_chase_thresh < vex_control.guest_max_insns);
sewardjce70a5c2004-10-18 14:09:54 +0000271
sewardj9df271d2004-12-31 22:37:42 +0000272 vassert(subarch_guest == VexSubArchX86_sse0
273 || subarch_guest == VexSubArchX86_sse1
274 || subarch_guest == VexSubArchX86_sse2);
275
sewardjce4a2822005-01-07 13:25:28 +0000276 vassert((guest_eip_start >> 32) == 0);
277
sewardj72c72812005-01-19 11:49:45 +0000278 /* Start a new, empty extent. */
279 vge->n_used = 1;
280 vge->base[0] = guest_eip_start;
281 vge->len[0] = 0;
282
sewardjce70a5c2004-10-18 14:09:54 +0000283 /* Set up globals. */
284 host_is_bigendian = host_bigendian;
sewardjce70a5c2004-10-18 14:09:54 +0000285 guest_code = x86code;
286 guest_eip_bbstart = (Addr32)guest_eip_start;
287 irbb = emptyIRBB();
sewardjce4a2822005-01-07 13:25:28 +0000288 insn_verbose = False;
sewardjce70a5c2004-10-18 14:09:54 +0000289
sewardjce70a5c2004-10-18 14:09:54 +0000290 /* Delta keeps track of how far along the x86code array we
291 have so far gone. */
292 delta = 0;
293 n_instrs = 0;
sewardjce70a5c2004-10-18 14:09:54 +0000294
295 while (True) {
sewardj08613742004-10-25 13:01:45 +0000296 vassert(n_instrs < vex_control.guest_max_insns);
sewardjce70a5c2004-10-18 14:09:54 +0000297
298 guest_next = 0;
sewardj72c72812005-01-19 11:49:45 +0000299 resteerOK
sewardj2d49b432005-02-01 00:37:06 +0000300 = toBool(
301 n_instrs < vex_control.guest_chase_thresh
302 /* we can't afford to have a resteer once we're on the
303 last extent slot. */
304 && vge->n_used < 3
305 );
sewardj72c72812005-01-19 11:49:45 +0000306
sewardjf1689312005-03-16 18:19:10 +0000307 /* This is the %EIP of the instruction we're just about to deal
308 with. */
309 guest_eip_curr_instr = guest_eip_bbstart + delta;
310
311 /* This is the irbb statement array index of the first stmt in
312 this insn. That will always be the instruction-mark
313 descriptor. */
sewardjdcc85fc2004-10-26 13:26:20 +0000314 first_stmt_idx = irbb->stmts_used;
315
sewardjf1689312005-03-16 18:19:10 +0000316 /* Add an instruction-mark statement. We won't know until after
317 disInstr how long the instruction is, so just put in a zero
318 length and we'll fix it up later. */
319 stmt( IRStmt_IMark( (Addr64)guest_eip_curr_instr, 0 ));
320
sewardjdcc85fc2004-10-26 13:26:20 +0000321 if (n_instrs > 0) {
322 /* for the first insn, the dispatch loop will have set
sewardj5bd4d162004-11-10 13:02:48 +0000323 %EIP, but for all the others we have to do it ourselves. */
sewardjf1689312005-03-16 18:19:10 +0000324 stmt( IRStmt_Put( OFFB_EIP, mkU32(guest_eip_curr_instr)) );
sewardjdcc85fc2004-10-26 13:26:20 +0000325 }
326
sewardjf1689312005-03-16 18:19:10 +0000327 /* Do the instruction. This may set insn_verbose to True, which
328 needs to be annulled. */
329 size = 0; /* just in case disInstr doesn't set it */
sewardj5bd4d162004-11-10 13:02:48 +0000330 dres = disInstr( resteerOK, chase_into_ok,
sewardj9df271d2004-12-31 22:37:42 +0000331 delta, subarch_guest, &size, &guest_next );
sewardjce4a2822005-01-07 13:25:28 +0000332 insn_verbose = False;
sewardjdcc85fc2004-10-26 13:26:20 +0000333
sewardjbde709b2005-03-26 13:14:54 +0000334 /* stay sane ... */
335 vassert(size >= 0 && size <= 18);
336
sewardjf1689312005-03-16 18:19:10 +0000337 /* Fill in the insn-mark length field. */
338 vassert(first_stmt_idx >= 0 && first_stmt_idx < irbb->stmts_used);
339 imark = irbb->stmts[first_stmt_idx];
340 vassert(imark);
341 vassert(imark->tag == Ist_IMark);
342 vassert(imark->Ist.IMark.len == 0);
343 imark->Ist.IMark.len = size;
344
sewardjdcc85fc2004-10-26 13:26:20 +0000345 /* Print the resulting IR, if needed. */
sewardjf48ac192004-10-29 00:41:29 +0000346 if (vex_traceflags & VEX_TRACE_FE) {
sewardjdcc85fc2004-10-26 13:26:20 +0000347 for (i = first_stmt_idx; i < irbb->stmts_used; i++) {
348 vex_printf(" ");
349 ppIRStmt(irbb->stmts[i]);
350 vex_printf("\n");
351 }
352 }
353
354 if (dres == Dis_StopHere) {
355 vassert(irbb->next != NULL);
sewardjf48ac192004-10-29 00:41:29 +0000356 if (vex_traceflags & VEX_TRACE_FE) {
sewardjdcc85fc2004-10-26 13:26:20 +0000357 vex_printf(" ");
358 vex_printf( "goto {");
359 ppIRJumpKind(irbb->jumpkind);
360 vex_printf( "} ");
361 ppIRExpr( irbb->next );
362 vex_printf( "\n");
363 }
364 }
365
sewardjce70a5c2004-10-18 14:09:54 +0000366 delta += size;
sewardje395ae82005-02-26 02:00:50 +0000367 /* If vex_control.guest_max_insns is required to be < 500 and
368 each insn is at max 15 bytes long, this limit of 10000 then
369 seems reasonable since the max possible extent length will be
370 500 * 15 == 7500. */
371 vassert(vge->len[vge->n_used-1] < 10000);
372 vge->len[vge->n_used-1]
373 = toUShort(toUInt( vge->len[vge->n_used-1] + size ));
sewardjce70a5c2004-10-18 14:09:54 +0000374 n_instrs++;
375 DIP("\n");
376
sewardjce70a5c2004-10-18 14:09:54 +0000377 if (!resteerOK)
378 vassert(dres != Dis_Resteer);
379 if (dres != Dis_Resteer)
380 vassert(guest_next == 0);
381
382 switch (dres) {
383 case Dis_Continue:
384 vassert(irbb->next == NULL);
sewardj08613742004-10-25 13:01:45 +0000385 if (n_instrs < vex_control.guest_max_insns) {
sewardjce70a5c2004-10-18 14:09:54 +0000386 /* keep going */
387 } else {
388 irbb->next = mkU32(((Addr32)guest_eip_start)+delta);
389 return irbb;
390 }
391 break;
392 case Dis_StopHere:
393 vassert(irbb->next != NULL);
394 return irbb;
395 case Dis_Resteer:
396 vassert(irbb->next == NULL);
397 /* figure out a new delta to continue at. */
sewardj5bd4d162004-11-10 13:02:48 +0000398 vassert(chase_into_ok(guest_next));
sewardje395ae82005-02-26 02:00:50 +0000399 delta = toUInt(guest_next - guest_eip_start);
sewardj72c72812005-01-19 11:49:45 +0000400 /* we now have to start a new extent slot. */
401 vge->n_used++;
402 vassert(vge->n_used <= 3);
403 vge->base[vge->n_used-1] = guest_next;
404 vge->len[vge->n_used-1] = 0;
sewardjce70a5c2004-10-18 14:09:54 +0000405 n_resteers++;
406 d_resteers++;
407 if (0 && (n_resteers & 0xFF) == 0)
sewardj5bd4d162004-11-10 13:02:48 +0000408 vex_printf("resteer[%d,%d] to %p (delta = %d)\n",
409 n_resteers, d_resteers,
sewardj9b45b482005-02-07 01:42:18 +0000410 ULong_to_Ptr(guest_next), (Int)delta);
sewardjce70a5c2004-10-18 14:09:54 +0000411 break;
412 }
413 }
414}
415
416
417/*------------------------------------------------------------*/
418/*--- Helper bits and pieces for deconstructing the ---*/
419/*--- x86 insn stream. ---*/
420/*------------------------------------------------------------*/
421
422/* This is the Intel register encoding -- integer regs. */
423#define R_EAX 0
424#define R_ECX 1
425#define R_EDX 2
426#define R_EBX 3
427#define R_ESP 4
428#define R_EBP 5
429#define R_ESI 6
430#define R_EDI 7
431
432#define R_AL (0+R_EAX)
433#define R_AH (4+R_EAX)
434
sewardj063f02f2004-10-20 12:36:12 +0000435/* This is the Intel register encoding -- segment regs. */
436#define R_ES 0
437#define R_CS 1
438#define R_SS 2
439#define R_DS 3
440#define R_FS 4
441#define R_GS 5
442
sewardjce70a5c2004-10-18 14:09:54 +0000443
sewardjc9a65702004-07-07 16:32:57 +0000444/* Add a statement to the list held by "irbb". */
sewardjd7cb8532004-08-17 23:59:23 +0000445static void stmt ( IRStmt* st )
sewardjc9a65702004-07-07 16:32:57 +0000446{
sewardjd7cb8532004-08-17 23:59:23 +0000447 addStmtToIRBB( irbb, st );
sewardjc9a65702004-07-07 16:32:57 +0000448}
449
450/* Generate a new temporary of the given type. */
451static IRTemp newTemp ( IRType ty )
452{
sewardj496a58d2005-03-20 18:44:44 +0000453 vassert(isPlausibleIRType(ty));
sewardje539a402004-07-14 18:24:17 +0000454 return newIRTemp( irbb->tyenv, ty );
sewardjc9a65702004-07-07 16:32:57 +0000455}
456
sewardjc9a65702004-07-07 16:32:57 +0000457/* Bomb out if we can't handle something. */
sewardjd1061ab2004-07-08 01:45:30 +0000458__attribute__ ((noreturn))
sewardj2d49b432005-02-01 00:37:06 +0000459static void unimplemented ( HChar* str )
sewardjc9a65702004-07-07 16:32:57 +0000460{
461 vex_printf("x86toIR: unimplemented feature\n");
462 vpanic(str);
463}
464
sewardjce70a5c2004-10-18 14:09:54 +0000465/* Various simple conversions */
sewardjd1061ab2004-07-08 01:45:30 +0000466
sewardje05c42c2004-07-08 20:25:10 +0000467static UInt extend_s_8to32( UInt x )
sewardjd1061ab2004-07-08 01:45:30 +0000468{
469 return (UInt)((((Int)x) << 24) >> 24);
470}
471
sewardj0611d802004-07-11 02:37:54 +0000472static UInt extend_s_16to32 ( UInt x )
473{
474 return (UInt)((((Int)x) << 16) >> 16);
475}
476
sewardjd1061ab2004-07-08 01:45:30 +0000477/* Fetch a byte from the guest insn stream. */
sewardje05c42c2004-07-08 20:25:10 +0000478static UChar getIByte ( UInt delta )
sewardjd1061ab2004-07-08 01:45:30 +0000479{
480 return guest_code[delta];
481}
482
sewardjc9a65702004-07-07 16:32:57 +0000483/* Extract the reg field from a modRM byte. */
sewardje05c42c2004-07-08 20:25:10 +0000484static Int gregOfRM ( UChar mod_reg_rm )
sewardjc9a65702004-07-07 16:32:57 +0000485{
486 return (Int)( (mod_reg_rm >> 3) & 7 );
487}
488
489/* Figure out whether the mod and rm parts of a modRM byte refer to a
490 register or memory. If so, the byte will have the form 11XXXYYY,
491 where YYY is the register number. */
sewardje05c42c2004-07-08 20:25:10 +0000492static Bool epartIsReg ( UChar mod_reg_rm )
sewardjc9a65702004-07-07 16:32:57 +0000493{
sewardj2d49b432005-02-01 00:37:06 +0000494 return toBool(0xC0 == (mod_reg_rm & 0xC0));
sewardjc9a65702004-07-07 16:32:57 +0000495}
496
497/* ... and extract the register number ... */
sewardje05c42c2004-07-08 20:25:10 +0000498static Int eregOfRM ( UChar mod_reg_rm )
sewardjc9a65702004-07-07 16:32:57 +0000499{
500 return (Int)(mod_reg_rm & 0x7);
501}
502
sewardje05c42c2004-07-08 20:25:10 +0000503/* Get a 8/16/32-bit unsigned value out of the insn stream. */
504
sewardj2d49b432005-02-01 00:37:06 +0000505static UChar getUChar ( UInt delta )
sewardje05c42c2004-07-08 20:25:10 +0000506{
sewardj2d49b432005-02-01 00:37:06 +0000507 UChar v = guest_code[delta+0];
sewardj9b45b482005-02-07 01:42:18 +0000508 return toUChar(v);
sewardje05c42c2004-07-08 20:25:10 +0000509}
510
511static UInt getUDisp16 ( UInt delta )
512{
513 UInt v = guest_code[delta+1]; v <<= 8;
514 v |= guest_code[delta+0];
515 return v & 0xFFFF;
516}
517
518static UInt getUDisp32 ( UInt delta )
sewardjd1061ab2004-07-08 01:45:30 +0000519{
520 UInt v = guest_code[delta+3]; v <<= 8;
521 v |= guest_code[delta+2]; v <<= 8;
522 v |= guest_code[delta+1]; v <<= 8;
523 v |= guest_code[delta+0];
524 return v;
525}
526
sewardje05c42c2004-07-08 20:25:10 +0000527static UInt getUDisp ( Int size, UInt delta )
528{
529 switch (size) {
530 case 4: return getUDisp32(delta);
531 case 2: return getUDisp16(delta);
sewardj2d49b432005-02-01 00:37:06 +0000532 case 1: return (UInt)getUChar(delta);
sewardje05c42c2004-07-08 20:25:10 +0000533 default: vpanic("getUDisp(x86)");
534 }
535 return 0; /*notreached*/
536}
537
538
sewardjd1061ab2004-07-08 01:45:30 +0000539/* Get a byte value out of the insn stream and sign-extend to 32
540 bits. */
sewardje05c42c2004-07-08 20:25:10 +0000541static UInt getSDisp8 ( UInt delta )
sewardjd1061ab2004-07-08 01:45:30 +0000542{
543 return extend_s_8to32( (UInt) (guest_code[delta]) );
544}
545
sewardj0611d802004-07-11 02:37:54 +0000546static UInt getSDisp16 ( UInt delta0 )
547{
548 UChar* eip = (UChar*)(&guest_code[delta0]);
549 UInt d = *eip++;
550 d |= ((*eip++) << 8);
551 return extend_s_16to32(d);
552}
553
554static UInt getSDisp ( Int size, UInt delta )
555{
556 switch (size) {
557 case 4: return getUDisp32(delta);
558 case 2: return getSDisp16(delta);
559 case 1: return getSDisp8(delta);
560 default: vpanic("getSDisp(x86)");
561 }
562 return 0; /*notreached*/
563}
sewardjd1061ab2004-07-08 01:45:30 +0000564
sewardjc9a65702004-07-07 16:32:57 +0000565
566/*------------------------------------------------------------*/
567/*--- Helpers for constructing IR. ---*/
568/*------------------------------------------------------------*/
569
570/* Create a 1/2/4 byte read of an x86 integer registers. For 16/8 bit
571 register references, we need to take the host endianness into
572 account. Supplied value is 0 .. 7 and in the Intel instruction
573 encoding. */
sewardje05c42c2004-07-08 20:25:10 +0000574
sewardj9334b0f2004-07-10 22:43:54 +0000575static IRType szToITy ( Int n )
576{
577 switch (n) {
578 case 1: return Ity_I8;
579 case 2: return Ity_I16;
580 case 4: return Ity_I32;
581 default: vpanic("szToITy(x86)");
582 }
583}
584
sewardj67e002d2004-12-02 18:16:33 +0000585/* On a little-endian host, less significant bits of the guest
586 registers are at lower addresses. Therefore, if a reference to a
587 register low half has the safe guest state offset as a reference to
588 the full register.
589*/
sewardj9334b0f2004-07-10 22:43:54 +0000590static Int integerGuestRegOffset ( Int sz, UInt archreg )
591{
592 vassert(archreg < 8);
593
sewardj9334b0f2004-07-10 22:43:54 +0000594 /* Correct for little-endian host only. */
sewardj67e002d2004-12-02 18:16:33 +0000595 vassert(!host_is_bigendian);
sewardj063f02f2004-10-20 12:36:12 +0000596
597 if (sz == 4 || sz == 2 || (sz == 1 && archreg < 4)) {
598 switch (archreg) {
sewardjc9a43662004-11-30 18:51:59 +0000599 case R_EAX: return OFFB_EAX;
600 case R_EBX: return OFFB_EBX;
601 case R_ECX: return OFFB_ECX;
602 case R_EDX: return OFFB_EDX;
603 case R_ESI: return OFFB_ESI;
604 case R_EDI: return OFFB_EDI;
605 case R_ESP: return OFFB_ESP;
606 case R_EBP: return OFFB_EBP;
sewardj063f02f2004-10-20 12:36:12 +0000607 default: vpanic("integerGuestRegOffset(x86,le)(4,2)");
608 }
609 }
610
611 vassert(archreg >= 4 && archreg < 8 && sz == 1);
612 switch (archreg-4) {
sewardjc9a43662004-11-30 18:51:59 +0000613 case R_EAX: return 1+ OFFB_EAX;
614 case R_EBX: return 1+ OFFB_EBX;
615 case R_ECX: return 1+ OFFB_ECX;
616 case R_EDX: return 1+ OFFB_EDX;
sewardj063f02f2004-10-20 12:36:12 +0000617 default: vpanic("integerGuestRegOffset(x86,le)(1h)");
618 }
619
620 /* NOTREACHED */
621 vpanic("integerGuestRegOffset(x86,le)");
622}
623
624static Int segmentGuestRegOffset ( UInt sreg )
625{
626 switch (sreg) {
sewardjc9a43662004-11-30 18:51:59 +0000627 case R_ES: return OFFB_ES;
628 case R_CS: return OFFB_CS;
629 case R_SS: return OFFB_SS;
630 case R_DS: return OFFB_DS;
631 case R_FS: return OFFB_FS;
632 case R_GS: return OFFB_GS;
sewardj063f02f2004-10-20 12:36:12 +0000633 default: vpanic("segmentGuestRegOffset(x86)");
sewardj9334b0f2004-07-10 22:43:54 +0000634 }
635}
636
sewardjc9a43662004-11-30 18:51:59 +0000637static Int xmmGuestRegOffset ( UInt xmmreg )
638{
639 switch (xmmreg) {
640 case 0: return OFFB_XMM0;
641 case 1: return OFFB_XMM1;
642 case 2: return OFFB_XMM2;
643 case 3: return OFFB_XMM3;
644 case 4: return OFFB_XMM4;
645 case 5: return OFFB_XMM5;
646 case 6: return OFFB_XMM6;
647 case 7: return OFFB_XMM7;
648 default: vpanic("xmmGuestRegOffset");
649 }
650}
651
sewardj67e002d2004-12-02 18:16:33 +0000652/* Lanes of vector registers are always numbered from zero being the
653 least significant lane (rightmost in the register). */
654
sewardje5854d62004-12-09 03:44:34 +0000655static Int xmmGuestRegLane16offset ( UInt xmmreg, Int laneno )
656{
657 /* Correct for little-endian host only. */
658 vassert(!host_is_bigendian);
659 vassert(laneno >= 0 && laneno < 8);
660 return xmmGuestRegOffset( xmmreg ) + 2 * laneno;
661}
662
sewardj67e002d2004-12-02 18:16:33 +0000663static Int xmmGuestRegLane32offset ( UInt xmmreg, Int laneno )
664{
665 /* Correct for little-endian host only. */
666 vassert(!host_is_bigendian);
667 vassert(laneno >= 0 && laneno < 4);
668 return xmmGuestRegOffset( xmmreg ) + 4 * laneno;
669}
670
671static Int xmmGuestRegLane64offset ( UInt xmmreg, Int laneno )
672{
673 /* Correct for little-endian host only. */
674 vassert(!host_is_bigendian);
675 vassert(laneno >= 0 && laneno < 2);
676 return xmmGuestRegOffset( xmmreg ) + 8 * laneno;
677}
678
sewardjd1061ab2004-07-08 01:45:30 +0000679static IRExpr* getIReg ( Int sz, UInt archreg )
sewardjc9a65702004-07-07 16:32:57 +0000680{
681 vassert(sz == 1 || sz == 2 || sz == 4);
682 vassert(archreg < 8);
sewardj9334b0f2004-07-10 22:43:54 +0000683 return IRExpr_Get( integerGuestRegOffset(sz,archreg),
sewardj5bd4d162004-11-10 13:02:48 +0000684 szToITy(sz) );
sewardjc9a65702004-07-07 16:32:57 +0000685}
686
687/* Ditto, but write to a reg instead. */
sewardj41f43bc2004-07-08 14:23:22 +0000688static void putIReg ( Int sz, UInt archreg, IRExpr* e )
sewardjc9a65702004-07-07 16:32:57 +0000689{
sewardjc9a43662004-11-30 18:51:59 +0000690 IRType ty = typeOfIRExpr(irbb->tyenv, e);
sewardjd24931d2005-03-20 12:51:39 +0000691 switch (sz) {
692 case 1: vassert(ty == Ity_I8); break;
693 case 2: vassert(ty == Ity_I16); break;
694 case 4: vassert(ty == Ity_I32); break;
695 default: vpanic("putIReg(x86)");
696 }
sewardjc9a65702004-07-07 16:32:57 +0000697 vassert(archreg < 8);
sewardjeeb9ef82004-07-15 12:39:03 +0000698 stmt( IRStmt_Put(integerGuestRegOffset(sz,archreg), e) );
sewardjd1061ab2004-07-08 01:45:30 +0000699}
700
sewardj063f02f2004-10-20 12:36:12 +0000701static IRExpr* getSReg ( UInt sreg )
702{
703 return IRExpr_Get( segmentGuestRegOffset(sreg), Ity_I16 );
704}
705
706static void putSReg ( UInt sreg, IRExpr* e )
707{
708 vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_I16);
709 stmt( IRStmt_Put( segmentGuestRegOffset(sreg), e ) );
710}
711
sewardjc9a43662004-11-30 18:51:59 +0000712static IRExpr* getXMMReg ( UInt xmmreg )
713{
714 return IRExpr_Get( xmmGuestRegOffset(xmmreg), Ity_V128 );
715}
716
sewardj67e002d2004-12-02 18:16:33 +0000717static IRExpr* getXMMRegLane64 ( UInt xmmreg, Int laneno )
718{
719 return IRExpr_Get( xmmGuestRegLane64offset(xmmreg,laneno), Ity_I64 );
720}
721
sewardjfd226452004-12-07 19:02:18 +0000722static IRExpr* getXMMRegLane64F ( UInt xmmreg, Int laneno )
sewardj67e002d2004-12-02 18:16:33 +0000723{
sewardjfd226452004-12-07 19:02:18 +0000724 return IRExpr_Get( xmmGuestRegLane64offset(xmmreg,laneno), Ity_F64 );
sewardj67e002d2004-12-02 18:16:33 +0000725}
726
sewardj9636b442004-12-04 01:38:37 +0000727static IRExpr* getXMMRegLane32 ( UInt xmmreg, Int laneno )
728{
729 return IRExpr_Get( xmmGuestRegLane32offset(xmmreg,laneno), Ity_I32 );
730}
731
sewardjfd226452004-12-07 19:02:18 +0000732static IRExpr* getXMMRegLane32F ( UInt xmmreg, Int laneno )
733{
734 return IRExpr_Get( xmmGuestRegLane32offset(xmmreg,laneno), Ity_F32 );
735}
736
sewardjc9a43662004-11-30 18:51:59 +0000737static void putXMMReg ( UInt xmmreg, IRExpr* e )
738{
739 vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_V128);
740 stmt( IRStmt_Put( xmmGuestRegOffset(xmmreg), e ) );
741}
742
sewardj67e002d2004-12-02 18:16:33 +0000743static void putXMMRegLane64 ( UInt xmmreg, Int laneno, IRExpr* e )
744{
745 vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_I64);
746 stmt( IRStmt_Put( xmmGuestRegLane64offset(xmmreg,laneno), e ) );
747}
748
sewardjfd226452004-12-07 19:02:18 +0000749static void putXMMRegLane64F ( UInt xmmreg, Int laneno, IRExpr* e )
750{
751 vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_F64);
752 stmt( IRStmt_Put( xmmGuestRegLane64offset(xmmreg,laneno), e ) );
753}
754
sewardj4cb918d2004-12-03 19:43:31 +0000755static void putXMMRegLane32F ( UInt xmmreg, Int laneno, IRExpr* e )
sewardj67e002d2004-12-02 18:16:33 +0000756{
sewardj4cb918d2004-12-03 19:43:31 +0000757 vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_F32);
sewardj67e002d2004-12-02 18:16:33 +0000758 stmt( IRStmt_Put( xmmGuestRegLane32offset(xmmreg,laneno), e ) );
759}
760
sewardj9636b442004-12-04 01:38:37 +0000761static void putXMMRegLane32 ( UInt xmmreg, Int laneno, IRExpr* e )
762{
763 vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_I32);
764 stmt( IRStmt_Put( xmmGuestRegLane32offset(xmmreg,laneno), e ) );
765}
766
sewardje5854d62004-12-09 03:44:34 +0000767static void putXMMRegLane16 ( UInt xmmreg, Int laneno, IRExpr* e )
768{
769 vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_I16);
770 stmt( IRStmt_Put( xmmGuestRegLane16offset(xmmreg,laneno), e ) );
771}
772
sewardj41f43bc2004-07-08 14:23:22 +0000773static void assign ( IRTemp dst, IRExpr* e )
sewardjd1061ab2004-07-08 01:45:30 +0000774{
sewardj41f43bc2004-07-08 14:23:22 +0000775 stmt( IRStmt_Tmp(dst, e) );
sewardjd1061ab2004-07-08 01:45:30 +0000776}
777
sewardj41f43bc2004-07-08 14:23:22 +0000778static void storeLE ( IRExpr* addr, IRExpr* data )
sewardjd1061ab2004-07-08 01:45:30 +0000779{
sewardj41f43bc2004-07-08 14:23:22 +0000780 stmt( IRStmt_STle(addr,data) );
sewardjd1061ab2004-07-08 01:45:30 +0000781}
782
sewardje87b4842004-07-10 12:23:30 +0000783static IRExpr* unop ( IROp op, IRExpr* a )
784{
785 return IRExpr_Unop(op, a);
786}
787
sewardjd1061ab2004-07-08 01:45:30 +0000788static IRExpr* binop ( IROp op, IRExpr* a1, IRExpr* a2 )
789{
790 return IRExpr_Binop(op, a1, a2);
791}
792
793static IRExpr* mkexpr ( IRTemp tmp )
794{
795 return IRExpr_Tmp(tmp);
796}
797
sewardjc2ac51e2004-07-12 01:03:26 +0000798static IRExpr* mkU8 ( UInt i )
799{
800 vassert(i < 256);
sewardj2d49b432005-02-01 00:37:06 +0000801 return IRExpr_Const(IRConst_U8( (UChar)i ));
sewardjc2ac51e2004-07-12 01:03:26 +0000802}
803
804static IRExpr* mkU16 ( UInt i )
805{
806 vassert(i < 65536);
sewardj2d49b432005-02-01 00:37:06 +0000807 return IRExpr_Const(IRConst_U16( (UShort)i ));
sewardjc2ac51e2004-07-12 01:03:26 +0000808}
809
sewardjd1061ab2004-07-08 01:45:30 +0000810static IRExpr* mkU32 ( UInt i )
811{
812 return IRExpr_Const(IRConst_U32(i));
sewardjc9a65702004-07-07 16:32:57 +0000813}
814
sewardj95535fe2004-12-15 17:42:58 +0000815static IRExpr* mkU64 ( ULong i )
816{
817 return IRExpr_Const(IRConst_U64(i));
818}
819
sewardj41f43bc2004-07-08 14:23:22 +0000820static IRExpr* mkU ( IRType ty, UInt i )
821{
sewardjc2ac51e2004-07-12 01:03:26 +0000822 if (ty == Ity_I8) return mkU8(i);
823 if (ty == Ity_I16) return mkU16(i);
824 if (ty == Ity_I32) return mkU32(i);
sewardje90ad6a2004-07-10 19:02:10 +0000825 /* If this panics, it usually means you passed a size (1,2,4)
826 value as the IRType, rather than a real IRType. */
sewardj41f43bc2004-07-08 14:23:22 +0000827 vpanic("mkU(x86)");
828}
829
sewardj1e6ad742004-12-02 16:16:11 +0000830static IRExpr* mkV128 ( UShort mask )
831{
832 return IRExpr_Const(IRConst_V128(mask));
833}
834
sewardj41f43bc2004-07-08 14:23:22 +0000835static IRExpr* loadLE ( IRType ty, IRExpr* data )
836{
837 return IRExpr_LDle(ty,data);
838}
839
840static IROp mkSizedOp ( IRType ty, IROp op8 )
841{
sewardje05c42c2004-07-08 20:25:10 +0000842 Int adj;
sewardj41f43bc2004-07-08 14:23:22 +0000843 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
844 vassert(op8 == Iop_Add8 || op8 == Iop_Sub8
sewardj41f43bc2004-07-08 14:23:22 +0000845 || op8 == Iop_Mul8
846 || op8 == Iop_Or8 || op8 == Iop_And8 || op8 == Iop_Xor8
sewardj5bd4d162004-11-10 13:02:48 +0000847 || op8 == Iop_Shl8 || op8 == Iop_Shr8 || op8 == Iop_Sar8
sewardje90ad6a2004-07-10 19:02:10 +0000848 || op8 == Iop_CmpEQ8 || op8 == Iop_CmpNE8
sewardj71a35e72005-05-03 12:20:15 +0000849 || op8 == Iop_Not8 || op8 == Iop_Neg8);
sewardje05c42c2004-07-08 20:25:10 +0000850 adj = ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
851 return adj + op8;
sewardj41f43bc2004-07-08 14:23:22 +0000852}
853
sewardj9334b0f2004-07-10 22:43:54 +0000854static IROp mkWidenOp ( Int szSmall, Int szBig, Bool signd )
sewardj41f43bc2004-07-08 14:23:22 +0000855{
sewardj9334b0f2004-07-10 22:43:54 +0000856 if (szSmall == 1 && szBig == 4) {
857 return signd ? Iop_8Sto32 : Iop_8Uto32;
sewardj41f43bc2004-07-08 14:23:22 +0000858 }
sewardj9334b0f2004-07-10 22:43:54 +0000859 if (szSmall == 1 && szBig == 2) {
860 return signd ? Iop_8Sto16 : Iop_8Uto16;
861 }
862 if (szSmall == 2 && szBig == 4) {
863 return signd ? Iop_16Sto32 : Iop_16Uto32;
864 }
sewardj948d48b2004-11-05 19:49:09 +0000865 vpanic("mkWidenOp(x86,guest)");
sewardj41f43bc2004-07-08 14:23:22 +0000866}
867
868
869/*------------------------------------------------------------*/
870/*--- Helpers for %eflags. ---*/
871/*------------------------------------------------------------*/
872
sewardj0611d802004-07-11 02:37:54 +0000873/* -------------- Evaluating the flags-thunk. -------------- */
sewardjc9a65702004-07-07 16:32:57 +0000874
sewardje87b4842004-07-10 12:23:30 +0000875/* Build IR to calculate all the eflags from stored
sewardj2a2ba8b2004-11-08 13:14:06 +0000876 CC_OP/CC_DEP1/CC_DEP2/CC_NDEP. Returns an expression ::
877 Ity_I32. */
sewardj2a9ad022004-11-25 02:46:58 +0000878static IRExpr* mk_x86g_calculate_eflags_all ( void )
sewardje87b4842004-07-10 12:23:30 +0000879{
sewardjf9655262004-10-31 20:02:16 +0000880 IRExpr** args
sewardj2a2ba8b2004-11-08 13:14:06 +0000881 = mkIRExprVec_4( IRExpr_Get(OFFB_CC_OP, Ity_I32),
882 IRExpr_Get(OFFB_CC_DEP1, Ity_I32),
883 IRExpr_Get(OFFB_CC_DEP2, Ity_I32),
884 IRExpr_Get(OFFB_CC_NDEP, Ity_I32) );
sewardj43c56462004-11-06 12:17:57 +0000885 IRExpr* call
886 = mkIRExprCCall(
887 Ity_I32,
888 0/*regparm*/,
sewardj2a9ad022004-11-25 02:46:58 +0000889 "x86g_calculate_eflags_all", &x86g_calculate_eflags_all,
sewardj43c56462004-11-06 12:17:57 +0000890 args
891 );
sewardj2a2ba8b2004-11-08 13:14:06 +0000892 /* Exclude OP and NDEP from definedness checking. We're only
893 interested in DEP1 and DEP2. */
894 call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<3);
sewardj43c56462004-11-06 12:17:57 +0000895 return call;
sewardje87b4842004-07-10 12:23:30 +0000896}
897
sewardj84ff0652004-08-23 16:16:08 +0000898/* Build IR to calculate some particular condition from stored
sewardj2a2ba8b2004-11-08 13:14:06 +0000899 CC_OP/CC_DEP1/CC_DEP2/CC_NDEP. Returns an expression ::
900 Ity_Bit. */
sewardj2a9ad022004-11-25 02:46:58 +0000901static IRExpr* mk_x86g_calculate_condition ( X86Condcode cond )
sewardj84ff0652004-08-23 16:16:08 +0000902{
sewardjf9655262004-10-31 20:02:16 +0000903 IRExpr** args
sewardj2a2ba8b2004-11-08 13:14:06 +0000904 = mkIRExprVec_5( mkU32(cond),
sewardjf9655262004-10-31 20:02:16 +0000905 IRExpr_Get(OFFB_CC_OP, Ity_I32),
sewardj2a2ba8b2004-11-08 13:14:06 +0000906 IRExpr_Get(OFFB_CC_DEP1, Ity_I32),
907 IRExpr_Get(OFFB_CC_DEP2, Ity_I32),
908 IRExpr_Get(OFFB_CC_NDEP, Ity_I32) );
sewardj43c56462004-11-06 12:17:57 +0000909 IRExpr* call
910 = mkIRExprCCall(
911 Ity_I32,
912 0/*regparm*/,
sewardj2a9ad022004-11-25 02:46:58 +0000913 "x86g_calculate_condition", &x86g_calculate_condition,
sewardj43c56462004-11-06 12:17:57 +0000914 args
915 );
sewardj2a2ba8b2004-11-08 13:14:06 +0000916 /* Exclude the requested condition, OP and NDEP from definedness
917 checking. We're only interested in DEP1 and DEP2. */
918 call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<1) | (1<<4);
sewardj43c56462004-11-06 12:17:57 +0000919 return unop(Iop_32to1, call);
920}
921
922/* Build IR to calculate just the carry flag from stored
sewardj2a2ba8b2004-11-08 13:14:06 +0000923 CC_OP/CC_DEP1/CC_DEP2/CC_NDEP. Returns an expression :: Ity_I32. */
sewardj2a9ad022004-11-25 02:46:58 +0000924static IRExpr* mk_x86g_calculate_eflags_c ( void )
sewardj43c56462004-11-06 12:17:57 +0000925{
926 IRExpr** args
sewardj2a2ba8b2004-11-08 13:14:06 +0000927 = mkIRExprVec_4( IRExpr_Get(OFFB_CC_OP, Ity_I32),
928 IRExpr_Get(OFFB_CC_DEP1, Ity_I32),
929 IRExpr_Get(OFFB_CC_DEP2, Ity_I32),
930 IRExpr_Get(OFFB_CC_NDEP, Ity_I32) );
sewardj43c56462004-11-06 12:17:57 +0000931 IRExpr* call
932 = mkIRExprCCall(
933 Ity_I32,
sewardj893a3302005-01-24 10:49:02 +0000934 3/*regparm*/,
sewardj2a9ad022004-11-25 02:46:58 +0000935 "x86g_calculate_eflags_c", &x86g_calculate_eflags_c,
sewardj43c56462004-11-06 12:17:57 +0000936 args
937 );
sewardj2a2ba8b2004-11-08 13:14:06 +0000938 /* Exclude OP and NDEP from definedness checking. We're only
939 interested in DEP1 and DEP2. */
940 call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<3);
sewardj43c56462004-11-06 12:17:57 +0000941 return call;
sewardj84ff0652004-08-23 16:16:08 +0000942}
943
sewardje87b4842004-07-10 12:23:30 +0000944
sewardj0611d802004-07-11 02:37:54 +0000945/* -------------- Building the flags-thunk. -------------- */
946
sewardjb9c5cf62004-08-24 15:10:38 +0000947/* The machinery in this section builds the flag-thunk following a
948 flag-setting operation. Hence the various setFlags_* functions.
sewardjb9c5cf62004-08-24 15:10:38 +0000949*/
950
951static Bool isAddSub ( IROp op8 )
952{
sewardj2d49b432005-02-01 00:37:06 +0000953 return toBool(op8 == Iop_Add8 || op8 == Iop_Sub8);
sewardjb9c5cf62004-08-24 15:10:38 +0000954}
sewardj0611d802004-07-11 02:37:54 +0000955
sewardj2a2ba8b2004-11-08 13:14:06 +0000956static Bool isLogic ( IROp op8 )
957{
sewardj2d49b432005-02-01 00:37:06 +0000958 return toBool(op8 == Iop_And8 || op8 == Iop_Or8 || op8 == Iop_Xor8);
sewardj2a2ba8b2004-11-08 13:14:06 +0000959}
960
sewardja2384712004-07-29 14:36:40 +0000961/* U-widen 8/16/32 bit int expr to 32. */
sewardjc22a6fd2004-07-29 23:41:47 +0000962static IRExpr* widenUto32 ( IRExpr* e )
sewardj443cd9d2004-07-18 23:06:45 +0000963{
964 switch (typeOfIRExpr(irbb->tyenv,e)) {
965 case Ity_I32: return e;
966 case Ity_I16: return unop(Iop_16Uto32,e);
967 case Ity_I8: return unop(Iop_8Uto32,e);
968 default: vpanic("widenUto32");
969 }
970}
971
sewardjc22a6fd2004-07-29 23:41:47 +0000972/* S-widen 8/16/32 bit int expr to 32. */
973static IRExpr* widenSto32 ( IRExpr* e )
974{
975 switch (typeOfIRExpr(irbb->tyenv,e)) {
976 case Ity_I32: return e;
977 case Ity_I16: return unop(Iop_16Sto32,e);
978 case Ity_I8: return unop(Iop_8Sto32,e);
979 default: vpanic("widenSto32");
980 }
981}
982
sewardja2384712004-07-29 14:36:40 +0000983/* Narrow 8/16/32 bit int expr to 8/16/32. Clearly only some
984 of these combinations make sense. */
985static IRExpr* narrowTo ( IRType dst_ty, IRExpr* e )
986{
987 IRType src_ty = typeOfIRExpr(irbb->tyenv,e);
988 if (src_ty == dst_ty)
989 return e;
990 if (src_ty == Ity_I32 && dst_ty == Ity_I16)
991 return unop(Iop_32to16, e);
992 if (src_ty == Ity_I32 && dst_ty == Ity_I8)
993 return unop(Iop_32to8, e);
994
995 vex_printf("\nsrc, dst tys are: ");
996 ppIRType(src_ty);
997 vex_printf(", ");
998 ppIRType(dst_ty);
999 vex_printf("\n");
1000 vpanic("narrowTo(x86)");
1001}
1002
sewardj443cd9d2004-07-18 23:06:45 +00001003
sewardj2a2ba8b2004-11-08 13:14:06 +00001004/* Set the flags thunk OP, DEP1 and DEP2 fields. The supplied op is
sewardj948d48b2004-11-05 19:49:09 +00001005 auto-sized up to the real op. */
sewardj0611d802004-07-11 02:37:54 +00001006
sewardj2a2ba8b2004-11-08 13:14:06 +00001007static
1008void setFlags_DEP1_DEP2 ( IROp op8, IRTemp dep1, IRTemp dep2, IRType ty )
sewardj0611d802004-07-11 02:37:54 +00001009{
sewardjb9c5cf62004-08-24 15:10:38 +00001010 Int ccOp = ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
1011
1012 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
1013
1014 switch (op8) {
sewardj2a9ad022004-11-25 02:46:58 +00001015 case Iop_Add8: ccOp += X86G_CC_OP_ADDB; break;
1016 case Iop_Sub8: ccOp += X86G_CC_OP_SUBB; break;
sewardjb9c5cf62004-08-24 15:10:38 +00001017 default: ppIROp(op8);
sewardj2a2ba8b2004-11-08 13:14:06 +00001018 vpanic("setFlags_DEP1_DEP2(x86)");
sewardjb9c5cf62004-08-24 15:10:38 +00001019 }
sewardj2a2ba8b2004-11-08 13:14:06 +00001020 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(ccOp)) );
1021 stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto32(mkexpr(dep1))) );
1022 stmt( IRStmt_Put( OFFB_CC_DEP2, widenUto32(mkexpr(dep2))) );
sewardja3b7e3a2005-04-05 01:54:19 +00001023 /* Set NDEP even though it isn't used. This makes redundant-PUT
1024 elimination of previous stores to this field work better. */
1025 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardjb9c5cf62004-08-24 15:10:38 +00001026}
1027
1028
sewardj2a2ba8b2004-11-08 13:14:06 +00001029/* Set the OP and DEP1 fields only, and write zero to DEP2. */
sewardjb9c5cf62004-08-24 15:10:38 +00001030
sewardj2a2ba8b2004-11-08 13:14:06 +00001031static
1032void setFlags_DEP1 ( IROp op8, IRTemp dep1, IRType ty )
sewardjb9c5cf62004-08-24 15:10:38 +00001033{
1034 Int ccOp = ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
sewardj0611d802004-07-11 02:37:54 +00001035
1036 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
1037
1038 switch (op8) {
1039 case Iop_Or8:
1040 case Iop_And8:
sewardj2a9ad022004-11-25 02:46:58 +00001041 case Iop_Xor8: ccOp += X86G_CC_OP_LOGICB; break;
sewardj0611d802004-07-11 02:37:54 +00001042 default: ppIROp(op8);
sewardj2a2ba8b2004-11-08 13:14:06 +00001043 vpanic("setFlags_DEP1(x86)");
sewardj0611d802004-07-11 02:37:54 +00001044 }
sewardj2a2ba8b2004-11-08 13:14:06 +00001045 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(ccOp)) );
1046 stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto32(mkexpr(dep1))) );
1047 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0)) );
sewardja3b7e3a2005-04-05 01:54:19 +00001048 /* Set NDEP even though it isn't used. This makes redundant-PUT
1049 elimination of previous stores to this field work better. */
1050 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardj0611d802004-07-11 02:37:54 +00001051}
1052
1053
sewardj948d48b2004-11-05 19:49:09 +00001054/* For shift operations, we put in the result and the undershifted
1055 result. Except if the shift amount is zero, the thunk is left
1056 unchanged. */
sewardj0611d802004-07-11 02:37:54 +00001057
sewardj2a2ba8b2004-11-08 13:14:06 +00001058static void setFlags_DEP1_DEP2_shift ( IROp op32,
1059 IRTemp res,
1060 IRTemp resUS,
1061 IRType ty,
1062 IRTemp guard )
sewardj0611d802004-07-11 02:37:54 +00001063{
sewardjc22a6fd2004-07-29 23:41:47 +00001064 Int ccOp = ty==Ity_I8 ? 2 : (ty==Ity_I16 ? 1 : 0);
sewardj0611d802004-07-11 02:37:54 +00001065
1066 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
1067 vassert(guard);
1068
sewardj2a2ba8b2004-11-08 13:14:06 +00001069 /* Both kinds of right shifts are handled by the same thunk
1070 operation. */
sewardjc22a6fd2004-07-29 23:41:47 +00001071 switch (op32) {
1072 case Iop_Shr32:
sewardj2a9ad022004-11-25 02:46:58 +00001073 case Iop_Sar32: ccOp = X86G_CC_OP_SHRL - ccOp; break;
1074 case Iop_Shl32: ccOp = X86G_CC_OP_SHLL - ccOp; break;
sewardjc22a6fd2004-07-29 23:41:47 +00001075 default: ppIROp(op32);
sewardj2a2ba8b2004-11-08 13:14:06 +00001076 vpanic("setFlags_DEP1_DEP2_shift(x86)");
sewardj0611d802004-07-11 02:37:54 +00001077 }
1078
sewardj2a2ba8b2004-11-08 13:14:06 +00001079 /* DEP1 contains the result, DEP2 contains the undershifted value. */
sewardjeeb9ef82004-07-15 12:39:03 +00001080 stmt( IRStmt_Put( OFFB_CC_OP,
sewardj4042c7e2004-07-18 01:28:30 +00001081 IRExpr_Mux0X( mkexpr(guard),
1082 IRExpr_Get(OFFB_CC_OP,Ity_I32),
1083 mkU32(ccOp))) );
sewardj2a2ba8b2004-11-08 13:14:06 +00001084 stmt( IRStmt_Put( OFFB_CC_DEP1,
sewardj4042c7e2004-07-18 01:28:30 +00001085 IRExpr_Mux0X( mkexpr(guard),
sewardj2a2ba8b2004-11-08 13:14:06 +00001086 IRExpr_Get(OFFB_CC_DEP1,Ity_I32),
sewardj948d48b2004-11-05 19:49:09 +00001087 widenUto32(mkexpr(res)))) );
sewardj2a2ba8b2004-11-08 13:14:06 +00001088 stmt( IRStmt_Put( OFFB_CC_DEP2,
sewardj4042c7e2004-07-18 01:28:30 +00001089 IRExpr_Mux0X( mkexpr(guard),
sewardj2a2ba8b2004-11-08 13:14:06 +00001090 IRExpr_Get(OFFB_CC_DEP2,Ity_I32),
sewardj948d48b2004-11-05 19:49:09 +00001091 widenUto32(mkexpr(resUS)))) );
sewardja3b7e3a2005-04-05 01:54:19 +00001092 /* Set NDEP even though it isn't used. This makes redundant-PUT
1093 elimination of previous stores to this field work better. */
1094 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardj0611d802004-07-11 02:37:54 +00001095}
1096
1097
sewardj2a2ba8b2004-11-08 13:14:06 +00001098/* For the inc/dec case, we store in DEP1 the result value and in NDEP
sewardj948d48b2004-11-05 19:49:09 +00001099 the former value of the carry flag, which unfortunately we have to
1100 compute. */
sewardj0611d802004-07-11 02:37:54 +00001101
sewardj948d48b2004-11-05 19:49:09 +00001102static void setFlags_INC_DEC ( Bool inc, IRTemp res, IRType ty )
sewardj0611d802004-07-11 02:37:54 +00001103{
sewardj2a9ad022004-11-25 02:46:58 +00001104 Int ccOp = inc ? X86G_CC_OP_INCB : X86G_CC_OP_DECB;
sewardj0611d802004-07-11 02:37:54 +00001105
1106 ccOp += ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
1107 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
1108
1109 /* This has to come first, because calculating the C flag
sewardj2a2ba8b2004-11-08 13:14:06 +00001110 may require reading all four thunk fields. */
sewardj2a9ad022004-11-25 02:46:58 +00001111 stmt( IRStmt_Put( OFFB_CC_NDEP, mk_x86g_calculate_eflags_c()) );
sewardj2a2ba8b2004-11-08 13:14:06 +00001112 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(ccOp)) );
1113 stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(res)) );
1114 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0)) );
sewardj0611d802004-07-11 02:37:54 +00001115}
1116
1117
sewardj2a2ba8b2004-11-08 13:14:06 +00001118/* Multiplies are pretty much like add and sub: DEP1 and DEP2 hold the
1119 two arguments. */
sewardjcf780b42004-07-13 18:42:17 +00001120
1121static
sewardj2a2ba8b2004-11-08 13:14:06 +00001122void setFlags_MUL ( IRType ty, IRTemp arg1, IRTemp arg2, UInt base_op )
sewardjcf780b42004-07-13 18:42:17 +00001123{
1124 switch (ty) {
sewardj2a2ba8b2004-11-08 13:14:06 +00001125 case Ity_I8:
1126 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(base_op+0) ) );
1127 break;
1128 case Ity_I16:
1129 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(base_op+1) ) );
1130 break;
1131 case Ity_I32:
1132 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(base_op+2) ) );
1133 break;
1134 default:
1135 vpanic("setFlags_MUL(x86)");
sewardjcf780b42004-07-13 18:42:17 +00001136 }
sewardj2a2ba8b2004-11-08 13:14:06 +00001137 stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto32(mkexpr(arg1)) ));
1138 stmt( IRStmt_Put( OFFB_CC_DEP2, widenUto32(mkexpr(arg2)) ));
sewardja3b7e3a2005-04-05 01:54:19 +00001139 /* Set NDEP even though it isn't used. This makes redundant-PUT
1140 elimination of previous stores to this field work better. */
1141 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardjcf780b42004-07-13 18:42:17 +00001142}
1143
1144
sewardj3af115f2004-07-14 02:46:52 +00001145/* -------------- Condition codes. -------------- */
1146
sewardje87b4842004-07-10 12:23:30 +00001147/* Condition codes, using the Intel encoding. */
sewardj0611d802004-07-11 02:37:54 +00001148
sewardj2d49b432005-02-01 00:37:06 +00001149static HChar* name_X86Condcode ( X86Condcode cond )
sewardje87b4842004-07-10 12:23:30 +00001150{
1151 switch (cond) {
sewardj2a9ad022004-11-25 02:46:58 +00001152 case X86CondO: return "o";
1153 case X86CondNO: return "no";
1154 case X86CondB: return "b";
1155 case X86CondNB: return "nb";
1156 case X86CondZ: return "z";
1157 case X86CondNZ: return "nz";
1158 case X86CondBE: return "be";
1159 case X86CondNBE: return "nbe";
1160 case X86CondS: return "s";
1161 case X86CondNS: return "ns";
1162 case X86CondP: return "p";
1163 case X86CondNP: return "np";
1164 case X86CondL: return "l";
1165 case X86CondNL: return "nl";
1166 case X86CondLE: return "le";
1167 case X86CondNLE: return "nle";
1168 case X86CondAlways: return "ALWAYS";
1169 default: vpanic("name_X86Condcode");
sewardje87b4842004-07-10 12:23:30 +00001170 }
1171}
1172
sewardj2a9ad022004-11-25 02:46:58 +00001173static
1174X86Condcode positiveIse_X86Condcode ( X86Condcode cond,
sewardjdbf550c2005-01-24 11:54:11 +00001175 Bool* needInvert )
sewardje87b4842004-07-10 12:23:30 +00001176{
sewardj2a9ad022004-11-25 02:46:58 +00001177 vassert(cond >= X86CondO && cond <= X86CondNLE);
sewardje87b4842004-07-10 12:23:30 +00001178 if (cond & 1) {
1179 *needInvert = True;
1180 return cond-1;
1181 } else {
1182 *needInvert = False;
1183 return cond;
1184 }
1185}
1186
1187
sewardj3af115f2004-07-14 02:46:52 +00001188/* -------------- Helpers for ADD/SUB with carry. -------------- */
1189
sewardj948d48b2004-11-05 19:49:09 +00001190/* Given ta1, ta2 and tres, compute tres = ADC(ta1,ta2) and set flags
sewardj2a2ba8b2004-11-08 13:14:06 +00001191 appropriately.
sewardj3af115f2004-07-14 02:46:52 +00001192*/
1193static void helper_ADC ( Int sz,
sewardj5bd4d162004-11-10 13:02:48 +00001194 IRTemp tres, IRTemp ta1, IRTemp ta2 )
sewardj3af115f2004-07-14 02:46:52 +00001195{
1196 UInt thunkOp;
sewardj2a2ba8b2004-11-08 13:14:06 +00001197 IRType ty = szToITy(sz);
1198 IRTemp oldc = newTemp(Ity_I32);
1199 IRTemp oldcn = newTemp(ty);
1200 IROp plus = mkSizedOp(ty, Iop_Add8);
1201 IROp xor = mkSizedOp(ty, Iop_Xor8);
sewardja2384712004-07-29 14:36:40 +00001202
1203 vassert(sz == 1 || sz == 2 || sz == 4);
sewardj2a9ad022004-11-25 02:46:58 +00001204 thunkOp = sz==4 ? X86G_CC_OP_ADCL
1205 : (sz==2 ? X86G_CC_OP_ADCW : X86G_CC_OP_ADCB);
sewardj3af115f2004-07-14 02:46:52 +00001206
sewardj2a2ba8b2004-11-08 13:14:06 +00001207 /* oldc = old carry flag, 0 or 1 */
1208 assign( oldc, binop(Iop_And32,
sewardj2a9ad022004-11-25 02:46:58 +00001209 mk_x86g_calculate_eflags_c(),
sewardj5bd4d162004-11-10 13:02:48 +00001210 mkU32(1)) );
sewardj3af115f2004-07-14 02:46:52 +00001211
sewardj2a2ba8b2004-11-08 13:14:06 +00001212 assign( oldcn, narrowTo(ty, mkexpr(oldc)) );
1213
1214 assign( tres, binop(plus,
1215 binop(plus,mkexpr(ta1),mkexpr(ta2)),
1216 mkexpr(oldcn)) );
1217
1218 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(thunkOp) ) );
1219 stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(ta1) ) );
sewardj2a9ad022004-11-25 02:46:58 +00001220 stmt( IRStmt_Put( OFFB_CC_DEP2, binop(xor, mkexpr(ta2),
1221 mkexpr(oldcn)) ) );
sewardj2a2ba8b2004-11-08 13:14:06 +00001222 stmt( IRStmt_Put( OFFB_CC_NDEP, mkexpr(oldc) ) );
sewardj3af115f2004-07-14 02:46:52 +00001223}
1224
1225
sewardj948d48b2004-11-05 19:49:09 +00001226/* Given ta1, ta2 and tres, compute tres = SBB(ta1,ta2) and set flags
sewardj2a2ba8b2004-11-08 13:14:06 +00001227 appropriately.
sewardjcaca9d02004-07-28 07:11:32 +00001228*/
1229static void helper_SBB ( Int sz,
sewardj5bd4d162004-11-10 13:02:48 +00001230 IRTemp tres, IRTemp ta1, IRTemp ta2 )
sewardjcaca9d02004-07-28 07:11:32 +00001231{
1232 UInt thunkOp;
sewardj2a2ba8b2004-11-08 13:14:06 +00001233 IRType ty = szToITy(sz);
1234 IRTemp oldc = newTemp(Ity_I32);
1235 IRTemp oldcn = newTemp(ty);
1236 IROp minus = mkSizedOp(ty, Iop_Sub8);
1237 IROp xor = mkSizedOp(ty, Iop_Xor8);
1238
1239 vassert(sz == 1 || sz == 2 || sz == 4);
sewardj2a9ad022004-11-25 02:46:58 +00001240 thunkOp = sz==4 ? X86G_CC_OP_SBBL
1241 : (sz==2 ? X86G_CC_OP_SBBW : X86G_CC_OP_SBBB);
sewardjcaca9d02004-07-28 07:11:32 +00001242
1243 /* oldc = old carry flag, 0 or 1 */
sewardja2384712004-07-29 14:36:40 +00001244 assign( oldc, binop(Iop_And32,
sewardj2a9ad022004-11-25 02:46:58 +00001245 mk_x86g_calculate_eflags_c(),
sewardj5bd4d162004-11-10 13:02:48 +00001246 mkU32(1)) );
sewardjcaca9d02004-07-28 07:11:32 +00001247
sewardj2a2ba8b2004-11-08 13:14:06 +00001248 assign( oldcn, narrowTo(ty, mkexpr(oldc)) );
sewardja2384712004-07-29 14:36:40 +00001249
sewardj2a2ba8b2004-11-08 13:14:06 +00001250 assign( tres, binop(minus,
1251 binop(minus,mkexpr(ta1),mkexpr(ta2)),
1252 mkexpr(oldcn)) );
sewardjcaca9d02004-07-28 07:11:32 +00001253
sewardj2a2ba8b2004-11-08 13:14:06 +00001254 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(thunkOp) ) );
1255 stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(ta1) ) );
sewardj2a9ad022004-11-25 02:46:58 +00001256 stmt( IRStmt_Put( OFFB_CC_DEP2, binop(xor, mkexpr(ta2),
1257 mkexpr(oldcn)) ) );
sewardj2a2ba8b2004-11-08 13:14:06 +00001258 stmt( IRStmt_Put( OFFB_CC_NDEP, mkexpr(oldc) ) );
sewardjcaca9d02004-07-28 07:11:32 +00001259}
1260
1261
sewardj7dd2eb22005-01-05 10:38:54 +00001262/* -------------- Helpers for disassembly printing. -------------- */
sewardj41f43bc2004-07-08 14:23:22 +00001263
sewardjc9a43662004-11-30 18:51:59 +00001264static HChar* nameGrp1 ( Int opc_aux )
sewardj41f43bc2004-07-08 14:23:22 +00001265{
sewardjc9a43662004-11-30 18:51:59 +00001266 static HChar* grp1_names[8]
sewardj41f43bc2004-07-08 14:23:22 +00001267 = { "add", "or", "adc", "sbb", "and", "sub", "xor", "cmp" };
1268 if (opc_aux < 0 || opc_aux > 7) vpanic("nameGrp1(x86)");
1269 return grp1_names[opc_aux];
1270}
1271
sewardjc9a43662004-11-30 18:51:59 +00001272static HChar* nameGrp2 ( Int opc_aux )
sewardje90ad6a2004-07-10 19:02:10 +00001273{
sewardjc9a43662004-11-30 18:51:59 +00001274 static HChar* grp2_names[8]
sewardje90ad6a2004-07-10 19:02:10 +00001275 = { "rol", "ror", "rcl", "rcr", "shl", "shr", "shl", "sar" };
sewardjc2ac51e2004-07-12 01:03:26 +00001276 if (opc_aux < 0 || opc_aux > 7) vpanic("nameGrp2(x86)");
sewardje90ad6a2004-07-10 19:02:10 +00001277 return grp2_names[opc_aux];
1278}
1279
sewardjc9a43662004-11-30 18:51:59 +00001280static HChar* nameGrp4 ( Int opc_aux )
sewardjc2ac51e2004-07-12 01:03:26 +00001281{
sewardjc9a43662004-11-30 18:51:59 +00001282 static HChar* grp4_names[8]
sewardjc2ac51e2004-07-12 01:03:26 +00001283 = { "inc", "dec", "???", "???", "???", "???", "???", "???" };
1284 if (opc_aux < 0 || opc_aux > 1) vpanic("nameGrp4(x86)");
1285 return grp4_names[opc_aux];
1286}
sewardj0611d802004-07-11 02:37:54 +00001287
sewardjc9a43662004-11-30 18:51:59 +00001288static HChar* nameGrp5 ( Int opc_aux )
sewardj0611d802004-07-11 02:37:54 +00001289{
sewardjc9a43662004-11-30 18:51:59 +00001290 static HChar* grp5_names[8]
sewardj0611d802004-07-11 02:37:54 +00001291 = { "inc", "dec", "call*", "call*", "jmp*", "jmp*", "push", "???" };
1292 if (opc_aux < 0 || opc_aux > 6) vpanic("nameGrp5(x86)");
1293 return grp5_names[opc_aux];
1294}
1295
sewardj490ad382005-03-13 17:25:53 +00001296static HChar* nameGrp8 ( Int opc_aux )
1297{
1298 static HChar* grp8_names[8]
1299 = { "???", "???", "???", "???", "bt", "bts", "btr", "btc" };
1300 if (opc_aux < 4 || opc_aux > 7) vpanic("nameGrp8(x86)");
1301 return grp8_names[opc_aux];
1302}
sewardjc9a65702004-07-07 16:32:57 +00001303
sewardjc9a43662004-11-30 18:51:59 +00001304static HChar* nameIReg ( Int size, Int reg )
sewardjc9a65702004-07-07 16:32:57 +00001305{
sewardjc9a43662004-11-30 18:51:59 +00001306 static HChar* ireg32_names[8]
sewardjc9a65702004-07-07 16:32:57 +00001307 = { "%eax", "%ecx", "%edx", "%ebx",
1308 "%esp", "%ebp", "%esi", "%edi" };
sewardjc9a43662004-11-30 18:51:59 +00001309 static HChar* ireg16_names[8]
sewardjc9a65702004-07-07 16:32:57 +00001310 = { "%ax", "%cx", "%dx", "%bx", "%sp", "%bp", "%si", "%di" };
sewardjc9a43662004-11-30 18:51:59 +00001311 static HChar* ireg8_names[8]
sewardjc9a65702004-07-07 16:32:57 +00001312 = { "%al", "%cl", "%dl", "%bl",
1313 "%ah{sp}", "%ch{bp}", "%dh{si}", "%bh{di}" };
1314 if (reg < 0 || reg > 7) goto bad;
1315 switch (size) {
1316 case 4: return ireg32_names[reg];
1317 case 2: return ireg16_names[reg];
1318 case 1: return ireg8_names[reg];
1319 }
1320 bad:
1321 vpanic("nameIReg(X86)");
1322 return NULL; /*notreached*/
1323}
1324
sewardjc9a43662004-11-30 18:51:59 +00001325static HChar* nameSReg ( UInt sreg )
sewardj063f02f2004-10-20 12:36:12 +00001326{
1327 switch (sreg) {
1328 case R_ES: return "%es";
1329 case R_CS: return "%cs";
1330 case R_SS: return "%ss";
1331 case R_DS: return "%ds";
1332 case R_FS: return "%fs";
1333 case R_GS: return "%gs";
1334 default: vpanic("nameSReg(x86)");
1335 }
1336}
1337
sewardjc9a43662004-11-30 18:51:59 +00001338static HChar* nameMMXReg ( Int mmxreg )
sewardj464efa42004-11-19 22:17:29 +00001339{
sewardjc9a43662004-11-30 18:51:59 +00001340 static HChar* mmx_names[8]
sewardj464efa42004-11-19 22:17:29 +00001341 = { "%mm0", "%mm1", "%mm2", "%mm3", "%mm4", "%mm5", "%mm6", "%mm7" };
1342 if (mmxreg < 0 || mmxreg > 7) vpanic("nameMMXReg(x86,guest)");
1343 return mmx_names[mmxreg];
1344}
1345
sewardjc9a43662004-11-30 18:51:59 +00001346static HChar* nameXMMReg ( Int xmmreg )
1347{
1348 static HChar* xmm_names[8]
1349 = { "%xmm0", "%xmm1", "%xmm2", "%xmm3",
1350 "%xmm4", "%xmm5", "%xmm6", "%xmm7" };
1351 if (xmmreg < 0 || xmmreg > 7) vpanic("name_of_xmm_reg");
1352 return xmm_names[xmmreg];
1353}
sewardj464efa42004-11-19 22:17:29 +00001354
sewardj2d49b432005-02-01 00:37:06 +00001355static HChar* nameMMXGran ( Int gran )
sewardj464efa42004-11-19 22:17:29 +00001356{
1357 switch (gran) {
1358 case 0: return "b";
1359 case 1: return "w";
1360 case 2: return "d";
1361 case 3: return "q";
1362 default: vpanic("nameMMXGran(x86,guest)");
1363 }
1364}
sewardjc9a65702004-07-07 16:32:57 +00001365
sewardj2d49b432005-02-01 00:37:06 +00001366static HChar nameISize ( Int size )
sewardjc9a65702004-07-07 16:32:57 +00001367{
1368 switch (size) {
1369 case 4: return 'l';
1370 case 2: return 'w';
1371 case 1: return 'b';
1372 default: vpanic("nameISize(x86)");
1373 }
1374}
1375
sewardjd1061ab2004-07-08 01:45:30 +00001376
1377/*------------------------------------------------------------*/
1378/*--- JMP helpers ---*/
1379/*------------------------------------------------------------*/
1380
sewardj78c19df2004-07-12 22:49:27 +00001381static void jmp_lit( IRJumpKind kind, Addr32 d32 )
sewardjd1061ab2004-07-08 01:45:30 +00001382{
sewardje539a402004-07-14 18:24:17 +00001383 irbb->next = mkU32(d32);
1384 irbb->jumpkind = kind;
sewardjd1061ab2004-07-08 01:45:30 +00001385}
1386
sewardj78c19df2004-07-12 22:49:27 +00001387static void jmp_treg( IRJumpKind kind, IRTemp t )
sewardje05c42c2004-07-08 20:25:10 +00001388{
sewardje539a402004-07-14 18:24:17 +00001389 irbb->next = mkexpr(t);
1390 irbb->jumpkind = kind;
sewardje05c42c2004-07-08 20:25:10 +00001391}
sewardje87b4842004-07-10 12:23:30 +00001392
sewardj2a9ad022004-11-25 02:46:58 +00001393static
1394void jcc_01( X86Condcode cond, Addr32 d32_false, Addr32 d32_true )
sewardje87b4842004-07-10 12:23:30 +00001395{
sewardj2a9ad022004-11-25 02:46:58 +00001396 Bool invert;
1397 X86Condcode condPos;
1398 condPos = positiveIse_X86Condcode ( cond, &invert );
sewardje87b4842004-07-10 12:23:30 +00001399 if (invert) {
sewardj2a9ad022004-11-25 02:46:58 +00001400 stmt( IRStmt_Exit( mk_x86g_calculate_condition(condPos),
sewardj893aada2004-11-29 19:57:54 +00001401 Ijk_Boring,
sewardj78c19df2004-07-12 22:49:27 +00001402 IRConst_U32(d32_false) ) );
sewardje539a402004-07-14 18:24:17 +00001403 irbb->next = mkU32(d32_true);
1404 irbb->jumpkind = Ijk_Boring;
sewardje87b4842004-07-10 12:23:30 +00001405 } else {
sewardj2a9ad022004-11-25 02:46:58 +00001406 stmt( IRStmt_Exit( mk_x86g_calculate_condition(condPos),
sewardj893aada2004-11-29 19:57:54 +00001407 Ijk_Boring,
sewardj78c19df2004-07-12 22:49:27 +00001408 IRConst_U32(d32_true) ) );
sewardje539a402004-07-14 18:24:17 +00001409 irbb->next = mkU32(d32_false);
1410 irbb->jumpkind = Ijk_Boring;
sewardje87b4842004-07-10 12:23:30 +00001411 }
1412}
sewardjc9a65702004-07-07 16:32:57 +00001413
1414
sewardjd1061ab2004-07-08 01:45:30 +00001415/*------------------------------------------------------------*/
1416/*--- Disassembling addressing modes ---*/
1417/*------------------------------------------------------------*/
sewardjc9a65702004-07-07 16:32:57 +00001418
sewardjd1061ab2004-07-08 01:45:30 +00001419static
sewardj2d49b432005-02-01 00:37:06 +00001420HChar* sorbTxt ( UChar sorb )
sewardjd1061ab2004-07-08 01:45:30 +00001421{
1422 switch (sorb) {
1423 case 0: return ""; /* no override */
1424 case 0x3E: return "%ds";
1425 case 0x26: return "%es:";
1426 case 0x64: return "%fs:";
1427 case 0x65: return "%gs:";
sewardj7df596b2004-12-06 14:29:12 +00001428 default: vpanic("sorbTxt(x86,guest)");
sewardjd1061ab2004-07-08 01:45:30 +00001429 }
1430}
1431
1432
sewardj7df596b2004-12-06 14:29:12 +00001433/* 'virtual' is an IRExpr* holding a virtual address. Convert it to a
1434 linear address by adding any required segment override as indicated
1435 by sorb. */
sewardjd1061ab2004-07-08 01:45:30 +00001436static
1437IRExpr* handleSegOverride ( UChar sorb, IRExpr* virtual )
1438{
sewardj3bd6f3e2004-12-13 10:48:19 +00001439 Int sreg;
1440 IRType hWordTy;
1441 IRTemp ldt_ptr, gdt_ptr, seg_selector, r64;
sewardjd1061ab2004-07-08 01:45:30 +00001442
1443 if (sorb == 0)
1444 /* the common case - no override */
1445 return virtual;
1446
sewardjd1061ab2004-07-08 01:45:30 +00001447 switch (sorb) {
1448 case 0x3E: sreg = R_DS; break;
1449 case 0x26: sreg = R_ES; break;
1450 case 0x64: sreg = R_FS; break;
1451 case 0x65: sreg = R_GS; break;
sewardj7df596b2004-12-06 14:29:12 +00001452 default: vpanic("handleSegOverride(x86,guest)");
sewardjd1061ab2004-07-08 01:45:30 +00001453 }
1454
sewardj3bd6f3e2004-12-13 10:48:19 +00001455 hWordTy = sizeof(HWord)==4 ? Ity_I32 : Ity_I64;
sewardjd1061ab2004-07-08 01:45:30 +00001456
sewardj3bd6f3e2004-12-13 10:48:19 +00001457 seg_selector = newTemp(Ity_I32);
1458 ldt_ptr = newTemp(hWordTy);
1459 gdt_ptr = newTemp(hWordTy);
1460 r64 = newTemp(Ity_I64);
sewardjd1061ab2004-07-08 01:45:30 +00001461
sewardj3bd6f3e2004-12-13 10:48:19 +00001462 assign( seg_selector, unop(Iop_16Uto32, getSReg(sreg)) );
1463 assign( ldt_ptr, IRExpr_Get( OFFB_LDT, hWordTy ));
1464 assign( gdt_ptr, IRExpr_Get( OFFB_GDT, hWordTy ));
sewardj7df596b2004-12-06 14:29:12 +00001465
sewardj3bd6f3e2004-12-13 10:48:19 +00001466 /*
1467 Call this to do the translation and limit checks:
1468 ULong x86g_use_seg_selector ( HWord ldt, HWord gdt,
1469 UInt seg_selector, UInt virtual_addr )
1470 */
1471 assign(
1472 r64,
1473 mkIRExprCCall(
1474 Ity_I64,
1475 0/*regparms*/,
1476 "x86g_use_seg_selector",
1477 &x86g_use_seg_selector,
1478 mkIRExprVec_4( mkexpr(ldt_ptr), mkexpr(gdt_ptr),
1479 mkexpr(seg_selector), virtual)
1480 )
1481 );
sewardj7df596b2004-12-06 14:29:12 +00001482
sewardj52444cb2004-12-13 14:09:01 +00001483 /* If the high 32 of the result are non-zero, there was a
1484 failure in address translation. In which case, make a
1485 quick exit.
1486 */
1487 stmt(
1488 IRStmt_Exit(
1489 binop(Iop_CmpNE32, unop(Iop_64HIto32, mkexpr(r64)), mkU32(0)),
1490 Ijk_MapFail,
1491 IRConst_U32( guest_eip_curr_instr )
1492 )
1493 );
1494
1495 /* otherwise, here's the translated result. */
sewardj3bd6f3e2004-12-13 10:48:19 +00001496 return unop(Iop_64to32, mkexpr(r64));
sewardjd1061ab2004-07-08 01:45:30 +00001497}
1498
1499
1500/* Generate IR to calculate an address indicated by a ModRM and
1501 following SIB bytes. The expression, and the number of bytes in
1502 the address mode, are returned. Note that this fn should not be
1503 called if the R/M part of the address denotes a register instead of
1504 memory. If print_codegen is true, text of the addressing mode is
sewardj940e8c92004-07-11 16:53:24 +00001505 placed in buf.
1506
1507 The computed address is stored in a new tempreg, and the
1508 identity of the tempreg is returned. */
1509
1510static IRTemp disAMode_copy2tmp ( IRExpr* addr32 )
1511{
1512 IRTemp tmp = newTemp(Ity_I32);
1513 assign( tmp, addr32 );
1514 return tmp;
1515}
sewardjd1061ab2004-07-08 01:45:30 +00001516
1517static
sewardj2d49b432005-02-01 00:37:06 +00001518IRTemp disAMode ( Int* len, UChar sorb, UInt delta, HChar* buf )
sewardjd1061ab2004-07-08 01:45:30 +00001519{
1520 UChar mod_reg_rm = getIByte(delta);
1521 delta++;
1522
sewardj9ee82862004-12-14 01:16:59 +00001523 buf[0] = (UChar)0;
1524
sewardjd1061ab2004-07-08 01:45:30 +00001525 /* squeeze out the reg field from mod_reg_rm, since a 256-entry
1526 jump table seems a bit excessive.
1527 */
sewardj9b45b482005-02-07 01:42:18 +00001528 mod_reg_rm &= 0xC7; /* is now XX000YYY */
1529 mod_reg_rm = toUChar(mod_reg_rm | (mod_reg_rm >> 3));
1530 /* is now XX0XXYYY */
1531 mod_reg_rm &= 0x1F; /* is now 000XXYYY */
sewardjd1061ab2004-07-08 01:45:30 +00001532 switch (mod_reg_rm) {
1533
1534 /* (%eax) .. (%edi), not including (%esp) or (%ebp).
1535 --> GET %reg, t
1536 */
1537 case 0x00: case 0x01: case 0x02: case 0x03:
1538 /* ! 04 */ /* ! 05 */ case 0x06: case 0x07:
1539 { UChar rm = mod_reg_rm;
1540 DIS(buf, "%s(%s)", sorbTxt(sorb), nameIReg(4,rm));
1541 *len = 1;
sewardj5bd4d162004-11-10 13:02:48 +00001542 return disAMode_copy2tmp(
sewardj940e8c92004-07-11 16:53:24 +00001543 handleSegOverride(sorb, getIReg(4,rm)));
sewardjd1061ab2004-07-08 01:45:30 +00001544 }
1545
1546 /* d8(%eax) ... d8(%edi), not including d8(%esp)
1547 --> GET %reg, t ; ADDL d8, t
1548 */
1549 case 0x08: case 0x09: case 0x0A: case 0x0B:
1550 /* ! 0C */ case 0x0D: case 0x0E: case 0x0F:
sewardj9b45b482005-02-07 01:42:18 +00001551 { UChar rm = toUChar(mod_reg_rm & 7);
sewardjd1061ab2004-07-08 01:45:30 +00001552 UInt d = getSDisp8(delta);
sewardj2d49b432005-02-01 00:37:06 +00001553 DIS(buf, "%s%d(%s)", sorbTxt(sorb), (Int)d, nameIReg(4,rm));
sewardj5bd4d162004-11-10 13:02:48 +00001554 *len = 2;
1555 return disAMode_copy2tmp(
sewardj940e8c92004-07-11 16:53:24 +00001556 handleSegOverride(sorb,
1557 binop(Iop_Add32,getIReg(4,rm),mkU32(d))));
sewardjd1061ab2004-07-08 01:45:30 +00001558 }
1559
1560 /* d32(%eax) ... d32(%edi), not including d32(%esp)
1561 --> GET %reg, t ; ADDL d8, t
1562 */
1563 case 0x10: case 0x11: case 0x12: case 0x13:
1564 /* ! 14 */ case 0x15: case 0x16: case 0x17:
sewardj9b45b482005-02-07 01:42:18 +00001565 { UChar rm = toUChar(mod_reg_rm & 7);
sewardjd1061ab2004-07-08 01:45:30 +00001566 UInt d = getUDisp32(delta);
sewardj2d49b432005-02-01 00:37:06 +00001567 DIS(buf, "%s0x%x(%s)", sorbTxt(sorb), (Int)d, nameIReg(4,rm));
sewardj5bd4d162004-11-10 13:02:48 +00001568 *len = 5;
1569 return disAMode_copy2tmp(
sewardj940e8c92004-07-11 16:53:24 +00001570 handleSegOverride(sorb,
1571 binop(Iop_Add32,getIReg(4,rm),mkU32(d))));
sewardjd1061ab2004-07-08 01:45:30 +00001572 }
1573
1574 /* a register, %eax .. %edi. This shouldn't happen. */
1575 case 0x18: case 0x19: case 0x1A: case 0x1B:
1576 case 0x1C: case 0x1D: case 0x1E: case 0x1F:
1577 vpanic("disAMode(x86): not an addr!");
1578
1579 /* a 32-bit literal address
1580 --> MOV d32, tmp
1581 */
1582 case 0x05:
1583 { UInt d = getUDisp32(delta);
1584 *len = 5;
1585 DIS(buf, "%s(0x%x)", sorbTxt(sorb), d);
sewardj940e8c92004-07-11 16:53:24 +00001586 return disAMode_copy2tmp(
1587 handleSegOverride(sorb, mkU32(d)));
sewardjd1061ab2004-07-08 01:45:30 +00001588 }
1589
1590 case 0x04: {
1591 /* SIB, with no displacement. Special cases:
1592 -- %esp cannot act as an index value.
1593 If index_r indicates %esp, zero is used for the index.
1594 -- when mod is zero and base indicates EBP, base is instead
1595 a 32-bit literal.
1596 It's all madness, I tell you. Extract %index, %base and
1597 scale from the SIB byte. The value denoted is then:
1598 | %index == %ESP && %base == %EBP
1599 = d32 following SIB byte
1600 | %index == %ESP && %base != %EBP
1601 = %base
1602 | %index != %ESP && %base == %EBP
1603 = d32 following SIB byte + (%index << scale)
1604 | %index != %ESP && %base != %ESP
1605 = %base + (%index << scale)
1606
1607 What happens to the souls of CPU architects who dream up such
1608 horrendous schemes, do you suppose?
1609 */
1610 UChar sib = getIByte(delta);
sewardj9b45b482005-02-07 01:42:18 +00001611 UChar scale = toUChar((sib >> 6) & 3);
1612 UChar index_r = toUChar((sib >> 3) & 7);
1613 UChar base_r = toUChar(sib & 7);
sewardj5bd4d162004-11-10 13:02:48 +00001614 delta++;
sewardjd1061ab2004-07-08 01:45:30 +00001615
1616 if (index_r != R_ESP && base_r != R_EBP) {
1617 DIS(buf, "%s(%s,%s,%d)", sorbTxt(sorb),
1618 nameIReg(4,base_r), nameIReg(4,index_r), 1<<scale);
sewardj5bd4d162004-11-10 13:02:48 +00001619 *len = 2;
sewardj940e8c92004-07-11 16:53:24 +00001620 return
1621 disAMode_copy2tmp(
sewardj5bd4d162004-11-10 13:02:48 +00001622 handleSegOverride(sorb,
1623 binop(Iop_Add32,
sewardjd1061ab2004-07-08 01:45:30 +00001624 getIReg(4,base_r),
1625 binop(Iop_Shl32, getIReg(4,index_r),
sewardj6d2638e2004-07-15 09:38:27 +00001626 mkU8(scale)))));
sewardjd1061ab2004-07-08 01:45:30 +00001627 }
1628
1629 if (index_r != R_ESP && base_r == R_EBP) {
1630 UInt d = getUDisp32(delta);
1631 DIS(buf, "%s0x%x(,%s,%d)", sorbTxt(sorb), d,
1632 nameIReg(4,index_r), 1<<scale);
1633 *len = 6;
1634 return
sewardj940e8c92004-07-11 16:53:24 +00001635 disAMode_copy2tmp(
sewardjd1061ab2004-07-08 01:45:30 +00001636 handleSegOverride(sorb,
sewardj5bd4d162004-11-10 13:02:48 +00001637 binop(Iop_Add32,
1638 binop(Iop_Shl32, getIReg(4,index_r), mkU8(scale)),
sewardj940e8c92004-07-11 16:53:24 +00001639 mkU32(d))));
sewardjd1061ab2004-07-08 01:45:30 +00001640 }
1641
1642 if (index_r == R_ESP && base_r != R_EBP) {
1643 DIS(buf, "%s(%s,,)", sorbTxt(sorb), nameIReg(4,base_r));
sewardj5bd4d162004-11-10 13:02:48 +00001644 *len = 2;
1645 return disAMode_copy2tmp(
sewardj940e8c92004-07-11 16:53:24 +00001646 handleSegOverride(sorb, getIReg(4,base_r)));
sewardjd1061ab2004-07-08 01:45:30 +00001647 }
1648
1649 if (index_r == R_ESP && base_r == R_EBP) {
1650 UInt d = getUDisp32(delta);
1651 DIS(buf, "%s0x%x()", sorbTxt(sorb), d);
sewardj5bd4d162004-11-10 13:02:48 +00001652 *len = 6;
sewardja340ee82005-01-26 01:24:34 +00001653 vpanic("disAMode(x86):untested amode: 8");
sewardj5bd4d162004-11-10 13:02:48 +00001654 return disAMode_copy2tmp(
sewardj940e8c92004-07-11 16:53:24 +00001655 handleSegOverride(sorb, mkU32(d)));
sewardjd1061ab2004-07-08 01:45:30 +00001656 }
sewardjba89f4c2005-04-07 17:31:27 +00001657 /*NOTREACHED*/
sewardjd1061ab2004-07-08 01:45:30 +00001658 vassert(0);
1659 }
1660
1661 /* SIB, with 8-bit displacement. Special cases:
1662 -- %esp cannot act as an index value.
1663 If index_r indicates %esp, zero is used for the index.
1664 Denoted value is:
1665 | %index == %ESP
1666 = d8 + %base
1667 | %index != %ESP
1668 = d8 + %base + (%index << scale)
1669 */
1670 case 0x0C: {
1671 UChar sib = getIByte(delta);
sewardj9b45b482005-02-07 01:42:18 +00001672 UChar scale = toUChar((sib >> 6) & 3);
1673 UChar index_r = toUChar((sib >> 3) & 7);
1674 UChar base_r = toUChar(sib & 7);
sewardjd1061ab2004-07-08 01:45:30 +00001675 UInt d = getSDisp8(delta+1);
1676
1677 if (index_r == R_ESP) {
sewardj2d49b432005-02-01 00:37:06 +00001678 DIS(buf, "%s%d(%s,,)", sorbTxt(sorb),
1679 (Int)d, nameIReg(4,base_r));
sewardj5bd4d162004-11-10 13:02:48 +00001680 *len = 3;
1681 return disAMode_copy2tmp(
sewardj940e8c92004-07-11 16:53:24 +00001682 handleSegOverride(sorb,
1683 binop(Iop_Add32, getIReg(4,base_r), mkU32(d)) ));
sewardjd1061ab2004-07-08 01:45:30 +00001684 } else {
sewardj2d49b432005-02-01 00:37:06 +00001685 DIS(buf, "%s%d(%s,%s,%d)", sorbTxt(sorb), (Int)d,
sewardjd1061ab2004-07-08 01:45:30 +00001686 nameIReg(4,base_r), nameIReg(4,index_r), 1<<scale);
sewardj5bd4d162004-11-10 13:02:48 +00001687 *len = 3;
1688 return
sewardj940e8c92004-07-11 16:53:24 +00001689 disAMode_copy2tmp(
1690 handleSegOverride(sorb,
sewardj77b86be2004-07-11 13:28:24 +00001691 binop(Iop_Add32,
1692 binop(Iop_Add32,
1693 getIReg(4,base_r),
1694 binop(Iop_Shl32,
sewardj6d2638e2004-07-15 09:38:27 +00001695 getIReg(4,index_r), mkU8(scale))),
sewardj940e8c92004-07-11 16:53:24 +00001696 mkU32(d))));
sewardjd1061ab2004-07-08 01:45:30 +00001697 }
sewardjba89f4c2005-04-07 17:31:27 +00001698 /*NOTREACHED*/
sewardjd1061ab2004-07-08 01:45:30 +00001699 vassert(0);
1700 }
1701
1702 /* SIB, with 32-bit displacement. Special cases:
1703 -- %esp cannot act as an index value.
1704 If index_r indicates %esp, zero is used for the index.
1705 Denoted value is:
1706 | %index == %ESP
1707 = d32 + %base
1708 | %index != %ESP
1709 = d32 + %base + (%index << scale)
1710 */
1711 case 0x14: {
1712 UChar sib = getIByte(delta);
sewardj9b45b482005-02-07 01:42:18 +00001713 UChar scale = toUChar((sib >> 6) & 3);
1714 UChar index_r = toUChar((sib >> 3) & 7);
1715 UChar base_r = toUChar(sib & 7);
sewardjd1061ab2004-07-08 01:45:30 +00001716 UInt d = getUDisp32(delta+1);
1717
1718 if (index_r == R_ESP) {
sewardj2d49b432005-02-01 00:37:06 +00001719 DIS(buf, "%s%d(%s,,)", sorbTxt(sorb),
1720 (Int)d, nameIReg(4,base_r));
sewardj5bd4d162004-11-10 13:02:48 +00001721 *len = 6;
1722 return disAMode_copy2tmp(
sewardj940e8c92004-07-11 16:53:24 +00001723 handleSegOverride(sorb,
1724 binop(Iop_Add32, getIReg(4,base_r), mkU32(d)) ));
sewardjd1061ab2004-07-08 01:45:30 +00001725 } else {
sewardj2d49b432005-02-01 00:37:06 +00001726 DIS(buf, "%s%d(%s,%s,%d)", sorbTxt(sorb), (Int)d,
1727 nameIReg(4,base_r), nameIReg(4,index_r), 1<<scale);
sewardj5bd4d162004-11-10 13:02:48 +00001728 *len = 6;
1729 return
sewardj940e8c92004-07-11 16:53:24 +00001730 disAMode_copy2tmp(
1731 handleSegOverride(sorb,
sewardj9334b0f2004-07-10 22:43:54 +00001732 binop(Iop_Add32,
1733 binop(Iop_Add32,
1734 getIReg(4,base_r),
1735 binop(Iop_Shl32,
sewardj6d2638e2004-07-15 09:38:27 +00001736 getIReg(4,index_r), mkU8(scale))),
sewardj940e8c92004-07-11 16:53:24 +00001737 mkU32(d))));
sewardjd1061ab2004-07-08 01:45:30 +00001738 }
sewardjba89f4c2005-04-07 17:31:27 +00001739 /*NOTREACHED*/
sewardjd1061ab2004-07-08 01:45:30 +00001740 vassert(0);
1741 }
1742
1743 default:
1744 vpanic("disAMode(x86)");
1745 return 0; /*notreached*/
1746 }
1747}
1748
1749
1750/* Figure out the number of (insn-stream) bytes constituting the amode
1751 beginning at delta. Is useful for getting hold of literals beyond
1752 the end of the amode before it has been disassembled. */
1753
1754static UInt lengthAMode ( UInt delta )
1755{
1756 UChar mod_reg_rm = getIByte(delta); delta++;
1757
1758 /* squeeze out the reg field from mod_reg_rm, since a 256-entry
1759 jump table seems a bit excessive.
1760 */
1761 mod_reg_rm &= 0xC7; /* is now XX000YYY */
sewardj9b45b482005-02-07 01:42:18 +00001762 mod_reg_rm = toUChar(mod_reg_rm | (mod_reg_rm >> 3));
1763 /* is now XX0XXYYY */
sewardjd1061ab2004-07-08 01:45:30 +00001764 mod_reg_rm &= 0x1F; /* is now 000XXYYY */
1765 switch (mod_reg_rm) {
1766
1767 /* (%eax) .. (%edi), not including (%esp) or (%ebp). */
1768 case 0x00: case 0x01: case 0x02: case 0x03:
1769 /* ! 04 */ /* ! 05 */ case 0x06: case 0x07:
1770 return 1;
1771
1772 /* d8(%eax) ... d8(%edi), not including d8(%esp). */
1773 case 0x08: case 0x09: case 0x0A: case 0x0B:
1774 /* ! 0C */ case 0x0D: case 0x0E: case 0x0F:
1775 return 2;
1776
1777 /* d32(%eax) ... d32(%edi), not including d32(%esp). */
1778 case 0x10: case 0x11: case 0x12: case 0x13:
1779 /* ! 14 */ case 0x15: case 0x16: case 0x17:
1780 return 5;
1781
1782 /* a register, %eax .. %edi. (Not an addr, but still handled.) */
1783 case 0x18: case 0x19: case 0x1A: case 0x1B:
1784 case 0x1C: case 0x1D: case 0x1E: case 0x1F:
1785 return 1;
1786
1787 /* a 32-bit literal address. */
1788 case 0x05: return 5;
1789
1790 /* SIB, no displacement. */
1791 case 0x04: {
1792 UChar sib = getIByte(delta);
sewardj9b45b482005-02-07 01:42:18 +00001793 UChar base_r = toUChar(sib & 7);
sewardjd1061ab2004-07-08 01:45:30 +00001794 if (base_r == R_EBP) return 6; else return 2;
1795 }
1796 /* SIB, with 8-bit displacement. */
1797 case 0x0C: return 3;
1798
1799 /* SIB, with 32-bit displacement. */
1800 case 0x14: return 6;
1801
1802 default:
1803 vpanic("lengthAMode");
1804 return 0; /*notreached*/
1805 }
1806}
1807
1808/*------------------------------------------------------------*/
1809/*--- Disassembling common idioms ---*/
1810/*------------------------------------------------------------*/
1811
sewardje87b4842004-07-10 12:23:30 +00001812/* Handle binary integer instructions of the form
1813 op E, G meaning
1814 op reg-or-mem, reg
1815 Is passed the a ptr to the modRM byte, the actual operation, and the
1816 data size. Returns the address advanced completely over this
1817 instruction.
1818
1819 E(src) is reg-or-mem
1820 G(dst) is reg.
1821
1822 If E is reg, --> GET %G, tmp
1823 OP %E, tmp
1824 PUT tmp, %G
1825
1826 If E is mem and OP is not reversible,
1827 --> (getAddr E) -> tmpa
1828 LD (tmpa), tmpa
1829 GET %G, tmp2
1830 OP tmpa, tmp2
1831 PUT tmp2, %G
1832
1833 If E is mem and OP is reversible
1834 --> (getAddr E) -> tmpa
1835 LD (tmpa), tmpa
1836 OP %G, tmpa
1837 PUT tmpa, %G
1838*/
1839static
1840UInt dis_op2_E_G ( UChar sorb,
sewardj180e8b32004-07-29 01:40:11 +00001841 Bool addSubCarry,
sewardje87b4842004-07-10 12:23:30 +00001842 IROp op8,
1843 Bool keep,
1844 Int size,
1845 UInt delta0,
sewardj2d49b432005-02-01 00:37:06 +00001846 HChar* t_x86opc )
sewardje87b4842004-07-10 12:23:30 +00001847{
sewardjc9a43662004-11-30 18:51:59 +00001848 HChar dis_buf[50];
sewardj9334b0f2004-07-10 22:43:54 +00001849 Int len;
sewardje87b4842004-07-10 12:23:30 +00001850 IRType ty = szToITy(size);
1851 IRTemp dst1 = newTemp(ty);
1852 IRTemp src = newTemp(ty);
1853 IRTemp dst0 = newTemp(ty);
1854 UChar rm = getUChar(delta0);
sewardj92d168d2004-11-15 14:22:12 +00001855 IRTemp addr = IRTemp_INVALID;
sewardje87b4842004-07-10 12:23:30 +00001856
sewardj180e8b32004-07-29 01:40:11 +00001857 /* addSubCarry == True indicates the intended operation is
1858 add-with-carry or subtract-with-borrow. */
1859 if (addSubCarry) {
1860 vassert(op8 == Iop_Add8 || op8 == Iop_Sub8);
1861 vassert(keep);
1862 }
1863
sewardje87b4842004-07-10 12:23:30 +00001864 if (epartIsReg(rm)) {
sewardje87b4842004-07-10 12:23:30 +00001865 /* Specially handle XOR reg,reg, because that doesn't really
1866 depend on reg, and doing the obvious thing potentially
1867 generates a spurious value check failure due to the bogus
sewardj55efbdf2005-05-02 17:07:02 +00001868 dependency. Ditto SBB reg,reg. */
1869 if ((op8 == Iop_Xor8 || (op8 == Iop_Sub8 && addSubCarry))
1870 && gregOfRM(rm) == eregOfRM(rm)) {
1871 putIReg(size, gregOfRM(rm), mkU(ty,0));
sewardje87b4842004-07-10 12:23:30 +00001872 }
sewardje87b4842004-07-10 12:23:30 +00001873 assign( dst0, getIReg(size,gregOfRM(rm)) );
1874 assign( src, getIReg(size,eregOfRM(rm)) );
sewardje87b4842004-07-10 12:23:30 +00001875
sewardj180e8b32004-07-29 01:40:11 +00001876 if (addSubCarry && op8 == Iop_Add8) {
sewardj180e8b32004-07-29 01:40:11 +00001877 helper_ADC( size, dst1, dst0, src );
sewardje87b4842004-07-10 12:23:30 +00001878 putIReg(size, gregOfRM(rm), mkexpr(dst1));
sewardj180e8b32004-07-29 01:40:11 +00001879 } else
1880 if (addSubCarry && op8 == Iop_Sub8) {
sewardj180e8b32004-07-29 01:40:11 +00001881 helper_SBB( size, dst1, dst0, src );
1882 putIReg(size, gregOfRM(rm), mkexpr(dst1));
1883 } else {
1884 assign( dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
sewardj5bd4d162004-11-10 13:02:48 +00001885 if (isAddSub(op8))
sewardj2a2ba8b2004-11-08 13:14:06 +00001886 setFlags_DEP1_DEP2(op8, dst0, src, ty);
sewardjb9c5cf62004-08-24 15:10:38 +00001887 else
sewardj2a2ba8b2004-11-08 13:14:06 +00001888 setFlags_DEP1(op8, dst1, ty);
sewardj180e8b32004-07-29 01:40:11 +00001889 if (keep)
1890 putIReg(size, gregOfRM(rm), mkexpr(dst1));
1891 }
sewardje87b4842004-07-10 12:23:30 +00001892
1893 DIP("%s%c %s,%s\n", t_x86opc, nameISize(size),
1894 nameIReg(size,eregOfRM(rm)),
1895 nameIReg(size,gregOfRM(rm)));
1896 return 1+delta0;
sewardje87b4842004-07-10 12:23:30 +00001897 } else {
sewardj9334b0f2004-07-10 22:43:54 +00001898 /* E refers to memory */
1899 addr = disAMode ( &len, sorb, delta0, dis_buf);
1900 assign( dst0, getIReg(size,gregOfRM(rm)) );
sewardj940e8c92004-07-11 16:53:24 +00001901 assign( src, loadLE(szToITy(size), mkexpr(addr)) );
sewardj9334b0f2004-07-10 22:43:54 +00001902
sewardj180e8b32004-07-29 01:40:11 +00001903 if (addSubCarry && op8 == Iop_Add8) {
sewardj180e8b32004-07-29 01:40:11 +00001904 helper_ADC( size, dst1, dst0, src );
sewardj9334b0f2004-07-10 22:43:54 +00001905 putIReg(size, gregOfRM(rm), mkexpr(dst1));
sewardj180e8b32004-07-29 01:40:11 +00001906 } else
1907 if (addSubCarry && op8 == Iop_Sub8) {
1908 helper_SBB( size, dst1, dst0, src );
1909 putIReg(size, gregOfRM(rm), mkexpr(dst1));
1910 } else {
1911 assign( dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
sewardj5bd4d162004-11-10 13:02:48 +00001912 if (isAddSub(op8))
sewardj2a2ba8b2004-11-08 13:14:06 +00001913 setFlags_DEP1_DEP2(op8, dst0, src, ty);
sewardjb9c5cf62004-08-24 15:10:38 +00001914 else
sewardj2a2ba8b2004-11-08 13:14:06 +00001915 setFlags_DEP1(op8, dst1, ty);
sewardj180e8b32004-07-29 01:40:11 +00001916 if (keep)
1917 putIReg(size, gregOfRM(rm), mkexpr(dst1));
1918 }
sewardj9334b0f2004-07-10 22:43:54 +00001919
sewardje87b4842004-07-10 12:23:30 +00001920 DIP("%s%c %s,%s\n", t_x86opc, nameISize(size),
1921 dis_buf,nameIReg(size,gregOfRM(rm)));
sewardj9334b0f2004-07-10 22:43:54 +00001922 return len+delta0;
sewardje87b4842004-07-10 12:23:30 +00001923 }
sewardje87b4842004-07-10 12:23:30 +00001924}
sewardje05c42c2004-07-08 20:25:10 +00001925
1926
1927
1928/* Handle binary integer instructions of the form
1929 op G, E meaning
1930 op reg, reg-or-mem
1931 Is passed the a ptr to the modRM byte, the actual operation, and the
1932 data size. Returns the address advanced completely over this
1933 instruction.
1934
1935 G(src) is reg.
1936 E(dst) is reg-or-mem
1937
1938 If E is reg, --> GET %E, tmp
1939 OP %G, tmp
1940 PUT tmp, %E
1941
1942 If E is mem, --> (getAddr E) -> tmpa
1943 LD (tmpa), tmpv
1944 OP %G, tmpv
1945 ST tmpv, (tmpa)
1946*/
1947static
1948UInt dis_op2_G_E ( UChar sorb,
sewardjcaca9d02004-07-28 07:11:32 +00001949 Bool addSubCarry,
sewardje05c42c2004-07-08 20:25:10 +00001950 IROp op8,
1951 Bool keep,
1952 Int size,
1953 UInt delta0,
sewardj2d49b432005-02-01 00:37:06 +00001954 HChar* t_x86opc )
sewardje05c42c2004-07-08 20:25:10 +00001955{
sewardjc9a43662004-11-30 18:51:59 +00001956 HChar dis_buf[50];
sewardje87b4842004-07-10 12:23:30 +00001957 Int len;
sewardje05c42c2004-07-08 20:25:10 +00001958 IRType ty = szToITy(size);
1959 IRTemp dst1 = newTemp(ty);
1960 IRTemp src = newTemp(ty);
1961 IRTemp dst0 = newTemp(ty);
1962 UChar rm = getIByte(delta0);
sewardj92d168d2004-11-15 14:22:12 +00001963 IRTemp addr = IRTemp_INVALID;
sewardje05c42c2004-07-08 20:25:10 +00001964
sewardjcaca9d02004-07-28 07:11:32 +00001965 /* addSubCarry == True indicates the intended operation is
1966 add-with-carry or subtract-with-borrow. */
1967 if (addSubCarry) {
1968 vassert(op8 == Iop_Add8 || op8 == Iop_Sub8);
1969 vassert(keep);
1970 }
1971
sewardje05c42c2004-07-08 20:25:10 +00001972 if (epartIsReg(rm)) {
sewardje05c42c2004-07-08 20:25:10 +00001973 /* Specially handle XOR reg,reg, because that doesn't really
1974 depend on reg, and doing the obvious thing potentially
1975 generates a spurious value check failure due to the bogus
sewardj55efbdf2005-05-02 17:07:02 +00001976 dependency. Ditto SBB reg,reg.*/
1977 if ((op8 == Iop_Xor8 || (op8 == Iop_Sub8 && addSubCarry))
1978 && gregOfRM(rm) == eregOfRM(rm)) {
1979 putIReg(size, eregOfRM(rm), mkU(ty,0));
sewardje05c42c2004-07-08 20:25:10 +00001980 }
sewardje05c42c2004-07-08 20:25:10 +00001981 assign(dst0, getIReg(size,eregOfRM(rm)));
1982 assign(src, getIReg(size,gregOfRM(rm)));
sewardje05c42c2004-07-08 20:25:10 +00001983
sewardjcaca9d02004-07-28 07:11:32 +00001984 if (addSubCarry && op8 == Iop_Add8) {
sewardj1813dbe2004-07-28 17:09:04 +00001985 helper_ADC( size, dst1, dst0, src );
1986 putIReg(size, eregOfRM(rm), mkexpr(dst1));
sewardjcaca9d02004-07-28 07:11:32 +00001987 } else
1988 if (addSubCarry && op8 == Iop_Sub8) {
1989 helper_SBB( size, dst1, dst0, src );
sewardje05c42c2004-07-08 20:25:10 +00001990 putIReg(size, eregOfRM(rm), mkexpr(dst1));
sewardjcaca9d02004-07-28 07:11:32 +00001991 } else {
1992 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
sewardj5bd4d162004-11-10 13:02:48 +00001993 if (isAddSub(op8))
sewardj2a2ba8b2004-11-08 13:14:06 +00001994 setFlags_DEP1_DEP2(op8, dst0, src, ty);
sewardjb9c5cf62004-08-24 15:10:38 +00001995 else
sewardj2a2ba8b2004-11-08 13:14:06 +00001996 setFlags_DEP1(op8, dst1, ty);
sewardjcaca9d02004-07-28 07:11:32 +00001997 if (keep)
1998 putIReg(size, eregOfRM(rm), mkexpr(dst1));
1999 }
sewardje05c42c2004-07-08 20:25:10 +00002000
2001 DIP("%s%c %s,%s\n", t_x86opc, nameISize(size),
2002 nameIReg(size,gregOfRM(rm)),
2003 nameIReg(size,eregOfRM(rm)));
2004 return 1+delta0;
2005 }
2006
2007 /* E refers to memory */
2008 {
sewardje87b4842004-07-10 12:23:30 +00002009 addr = disAMode ( &len, sorb, delta0, dis_buf);
sewardj940e8c92004-07-11 16:53:24 +00002010 assign(dst0, loadLE(ty,mkexpr(addr)));
sewardje87b4842004-07-10 12:23:30 +00002011 assign(src, getIReg(size,gregOfRM(rm)));
sewardje05c42c2004-07-08 20:25:10 +00002012
sewardjcaca9d02004-07-28 07:11:32 +00002013 if (addSubCarry && op8 == Iop_Add8) {
2014 helper_ADC( size, dst1, dst0, src );
2015 storeLE(mkexpr(addr), mkexpr(dst1));
2016 } else
2017 if (addSubCarry && op8 == Iop_Sub8) {
2018 helper_SBB( size, dst1, dst0, src );
2019 storeLE(mkexpr(addr), mkexpr(dst1));
2020 } else {
2021 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
sewardj5bd4d162004-11-10 13:02:48 +00002022 if (isAddSub(op8))
sewardj2a2ba8b2004-11-08 13:14:06 +00002023 setFlags_DEP1_DEP2(op8, dst0, src, ty);
sewardjb9c5cf62004-08-24 15:10:38 +00002024 else
sewardj2a2ba8b2004-11-08 13:14:06 +00002025 setFlags_DEP1(op8, dst1, ty);
sewardjcaca9d02004-07-28 07:11:32 +00002026 if (keep)
2027 storeLE(mkexpr(addr), mkexpr(dst1));
2028 }
sewardje87b4842004-07-10 12:23:30 +00002029
sewardje05c42c2004-07-08 20:25:10 +00002030 DIP("%s%c %s,%s\n", t_x86opc, nameISize(size),
2031 nameIReg(size,gregOfRM(rm)), dis_buf);
sewardje87b4842004-07-10 12:23:30 +00002032 return len+delta0;
sewardje05c42c2004-07-08 20:25:10 +00002033 }
2034}
2035
2036
2037/* Handle move instructions of the form
2038 mov E, G meaning
2039 mov reg-or-mem, reg
2040 Is passed the a ptr to the modRM byte, and the data size. Returns
2041 the address advanced completely over this instruction.
2042
2043 E(src) is reg-or-mem
2044 G(dst) is reg.
2045
2046 If E is reg, --> GET %E, tmpv
2047 PUT tmpv, %G
2048
2049 If E is mem --> (getAddr E) -> tmpa
2050 LD (tmpa), tmpb
2051 PUT tmpb, %G
2052*/
2053static
2054UInt dis_mov_E_G ( UChar sorb,
2055 Int size,
2056 UInt delta0 )
2057{
2058 Int len;
2059 UChar rm = getIByte(delta0);
sewardjc9a43662004-11-30 18:51:59 +00002060 HChar dis_buf[50];
sewardje05c42c2004-07-08 20:25:10 +00002061
2062 if (epartIsReg(rm)) {
sewardj7ca37d92004-10-25 02:58:30 +00002063 putIReg(size, gregOfRM(rm), getIReg(size, eregOfRM(rm)));
sewardje05c42c2004-07-08 20:25:10 +00002064 DIP("mov%c %s,%s\n", nameISize(size),
2065 nameIReg(size,eregOfRM(rm)),
2066 nameIReg(size,gregOfRM(rm)));
sewardj7ca37d92004-10-25 02:58:30 +00002067 return 1+delta0;
sewardje05c42c2004-07-08 20:25:10 +00002068 }
2069
2070 /* E refers to memory */
2071 {
sewardj940e8c92004-07-11 16:53:24 +00002072 IRTemp addr = disAMode ( &len, sorb, delta0, dis_buf );
2073 putIReg(size, gregOfRM(rm), loadLE(szToITy(size), mkexpr(addr)));
sewardje05c42c2004-07-08 20:25:10 +00002074 DIP("mov%c %s,%s\n", nameISize(size),
2075 dis_buf,nameIReg(size,gregOfRM(rm)));
2076 return delta0+len;
2077 }
2078}
2079
2080
2081/* Handle move instructions of the form
2082 mov G, E meaning
2083 mov reg, reg-or-mem
2084 Is passed the a ptr to the modRM byte, and the data size. Returns
2085 the address advanced completely over this instruction.
2086
2087 G(src) is reg.
2088 E(dst) is reg-or-mem
2089
2090 If E is reg, --> GET %G, tmp
2091 PUT tmp, %E
2092
2093 If E is mem, --> (getAddr E) -> tmpa
2094 GET %G, tmpv
2095 ST tmpv, (tmpa)
2096*/
sewardjc9a65702004-07-07 16:32:57 +00002097static
2098UInt dis_mov_G_E ( UChar sorb,
2099 Int size,
2100 UInt delta0 )
2101{
sewardje05c42c2004-07-08 20:25:10 +00002102 Int len;
sewardjc9a65702004-07-07 16:32:57 +00002103 UChar rm = getIByte(delta0);
sewardjc9a43662004-11-30 18:51:59 +00002104 HChar dis_buf[50];
sewardjc9a65702004-07-07 16:32:57 +00002105
2106 if (epartIsReg(rm)) {
sewardj41f43bc2004-07-08 14:23:22 +00002107 putIReg(size, eregOfRM(rm), getIReg(size, gregOfRM(rm)));
sewardjc9a65702004-07-07 16:32:57 +00002108 DIP("mov%c %s,%s\n", nameISize(size),
2109 nameIReg(size,gregOfRM(rm)),
2110 nameIReg(size,eregOfRM(rm)));
2111 return 1+delta0;
2112 }
2113
sewardjc9a65702004-07-07 16:32:57 +00002114 /* E refers to memory */
2115 {
sewardj940e8c92004-07-11 16:53:24 +00002116 IRTemp addr = disAMode ( &len, sorb, delta0, dis_buf);
2117 storeLE( mkexpr(addr), getIReg(size, gregOfRM(rm)) );
sewardjc9a65702004-07-07 16:32:57 +00002118 DIP("mov%c %s,%s\n", nameISize(size),
2119 nameIReg(size,gregOfRM(rm)), dis_buf);
sewardje05c42c2004-07-08 20:25:10 +00002120 return len+delta0;
sewardjc9a65702004-07-07 16:32:57 +00002121 }
sewardjc9a65702004-07-07 16:32:57 +00002122}
2123
2124
sewardj0611d802004-07-11 02:37:54 +00002125/* op $immediate, AL/AX/EAX. */
2126static
2127UInt dis_op_imm_A ( Int size,
sewardja718d5d2005-04-03 14:59:54 +00002128 Bool carrying,
sewardj0611d802004-07-11 02:37:54 +00002129 IROp op8,
2130 Bool keep,
2131 UInt delta,
sewardj2d49b432005-02-01 00:37:06 +00002132 HChar* t_x86opc )
sewardj0611d802004-07-11 02:37:54 +00002133{
2134 IRType ty = szToITy(size);
2135 IRTemp dst0 = newTemp(ty);
2136 IRTemp src = newTemp(ty);
2137 IRTemp dst1 = newTemp(ty);
2138 UInt lit = getUDisp(size,delta);
2139 assign(dst0, getIReg(size,R_EAX));
2140 assign(src, mkU(ty,lit));
sewardja718d5d2005-04-03 14:59:54 +00002141
2142 if (isAddSub(op8) && !carrying) {
2143 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
sewardj2a2ba8b2004-11-08 13:14:06 +00002144 setFlags_DEP1_DEP2(op8, dst0, src, ty);
sewardja718d5d2005-04-03 14:59:54 +00002145 }
sewardjb9c5cf62004-08-24 15:10:38 +00002146 else
sewardja718d5d2005-04-03 14:59:54 +00002147 if (isLogic(op8)) {
2148 vassert(!carrying);
2149 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
sewardj2a2ba8b2004-11-08 13:14:06 +00002150 setFlags_DEP1(op8, dst1, ty);
sewardja718d5d2005-04-03 14:59:54 +00002151 }
2152 else
2153 if (op8 == Iop_Add8 && carrying) {
2154 helper_ADC( size, dst1, dst0, src );
2155 }
sewardj2a2ba8b2004-11-08 13:14:06 +00002156 else
2157 vpanic("dis_op_imm_A(x86,guest)");
sewardj0611d802004-07-11 02:37:54 +00002158
2159 if (keep)
2160 putIReg(size, R_EAX, mkexpr(dst1));
2161
2162 DIP("%s%c $0x%x, %s\n", t_x86opc, nameISize(size),
2163 lit, nameIReg(size,R_EAX));
2164 return delta+size;
2165}
sewardj9334b0f2004-07-10 22:43:54 +00002166
2167
2168/* Sign- and Zero-extending moves. */
2169static
2170UInt dis_movx_E_G ( UChar sorb,
2171 UInt delta, Int szs, Int szd, Bool sign_extend )
2172{
sewardj9334b0f2004-07-10 22:43:54 +00002173 UChar rm = getIByte(delta);
2174 if (epartIsReg(rm)) {
2175 putIReg(szd, gregOfRM(rm),
sewardj5bd4d162004-11-10 13:02:48 +00002176 unop(mkWidenOp(szs,szd,sign_extend),
2177 getIReg(szs,eregOfRM(rm))));
sewardj9334b0f2004-07-10 22:43:54 +00002178 DIP("mov%c%c%c %s,%s\n", sign_extend ? 's' : 'z',
2179 nameISize(szs), nameISize(szd),
2180 nameIReg(szs,eregOfRM(rm)),
2181 nameIReg(szd,gregOfRM(rm)));
2182 return 1+delta;
2183 }
2184
2185 /* E refers to memory */
2186 {
sewardj940e8c92004-07-11 16:53:24 +00002187 Int len;
sewardjc9a43662004-11-30 18:51:59 +00002188 HChar dis_buf[50];
sewardj940e8c92004-07-11 16:53:24 +00002189 IRTemp addr = disAMode ( &len, sorb, delta, dis_buf );
sewardj0611d802004-07-11 02:37:54 +00002190
2191 putIReg(szd, gregOfRM(rm),
sewardj5bd4d162004-11-10 13:02:48 +00002192 unop(mkWidenOp(szs,szd,sign_extend),
sewardj940e8c92004-07-11 16:53:24 +00002193 loadLE(szToITy(szs),mkexpr(addr))));
sewardj9334b0f2004-07-10 22:43:54 +00002194 DIP("mov%c%c%c %s,%s\n", sign_extend ? 's' : 'z',
2195 nameISize(szs), nameISize(szd),
2196 dis_buf, nameIReg(szd,gregOfRM(rm)));
sewardj0611d802004-07-11 02:37:54 +00002197 return len+delta;
sewardj9334b0f2004-07-10 22:43:54 +00002198 }
2199}
2200
sewardj9690d922004-07-14 01:39:17 +00002201
2202/* Generate code to divide ArchRegs EDX:EAX / DX:AX / AX by the 32 /
2203 16 / 8 bit quantity in the given IRTemp. */
2204static
2205void codegen_div ( Int sz, IRTemp t, Bool signed_divide )
2206{
sewardje5427e82004-09-11 19:43:51 +00002207 IROp op = signed_divide ? Iop_DivModS64to32 : Iop_DivModU64to32;
2208 IRTemp src64 = newTemp(Ity_I64);
2209 IRTemp dst64 = newTemp(Ity_I64);
sewardj9690d922004-07-14 01:39:17 +00002210 switch (sz) {
sewardje5427e82004-09-11 19:43:51 +00002211 case 4:
sewardj9690d922004-07-14 01:39:17 +00002212 assign( src64, binop(Iop_32HLto64,
sewardje5427e82004-09-11 19:43:51 +00002213 getIReg(4,R_EDX), getIReg(4,R_EAX)) );
sewardj9690d922004-07-14 01:39:17 +00002214 assign( dst64, binop(op, mkexpr(src64), mkexpr(t)) );
sewardj8c7f1ab2004-07-29 20:31:09 +00002215 putIReg( 4, R_EAX, unop(Iop_64to32,mkexpr(dst64)) );
sewardj9690d922004-07-14 01:39:17 +00002216 putIReg( 4, R_EDX, unop(Iop_64HIto32,mkexpr(dst64)) );
2217 break;
sewardje5427e82004-09-11 19:43:51 +00002218 case 2: {
2219 IROp widen3264 = signed_divide ? Iop_32Sto64 : Iop_32Uto64;
2220 IROp widen1632 = signed_divide ? Iop_16Sto32 : Iop_16Uto32;
2221 assign( src64, unop(widen3264,
2222 binop(Iop_16HLto32,
2223 getIReg(2,R_EDX), getIReg(2,R_EAX))) );
2224 assign( dst64, binop(op, mkexpr(src64), unop(widen1632,mkexpr(t))) );
2225 putIReg( 2, R_EAX, unop(Iop_32to16,unop(Iop_64to32,mkexpr(dst64))) );
2226 putIReg( 2, R_EDX, unop(Iop_32to16,unop(Iop_64HIto32,mkexpr(dst64))) );
2227 break;
sewardj9690d922004-07-14 01:39:17 +00002228 }
sewardj4e82db72004-10-16 11:32:15 +00002229 case 1: {
2230 IROp widen3264 = signed_divide ? Iop_32Sto64 : Iop_32Uto64;
2231 IROp widen1632 = signed_divide ? Iop_16Sto32 : Iop_16Uto32;
2232 IROp widen816 = signed_divide ? Iop_8Sto16 : Iop_8Uto16;
2233 assign( src64, unop(widen3264, unop(widen1632, getIReg(2,R_EAX))) );
2234 assign( dst64,
2235 binop(op, mkexpr(src64),
2236 unop(widen1632, unop(widen816, mkexpr(t)))) );
2237 putIReg( 1, R_AL, unop(Iop_16to8, unop(Iop_32to16,
2238 unop(Iop_64to32,mkexpr(dst64)))) );
2239 putIReg( 1, R_AH, unop(Iop_16to8, unop(Iop_32to16,
2240 unop(Iop_64HIto32,mkexpr(dst64)))) );
2241 break;
2242 }
sewardj9690d922004-07-14 01:39:17 +00002243 default: vpanic("codegen_div(x86)");
2244 }
2245}
sewardj41f43bc2004-07-08 14:23:22 +00002246
2247
2248static
sewardje90ad6a2004-07-10 19:02:10 +00002249UInt dis_Grp1 ( UChar sorb,
sewardj41f43bc2004-07-08 14:23:22 +00002250 UInt delta, UChar modrm,
2251 Int am_sz, Int d_sz, Int sz, UInt d32 )
2252{
sewardj41f43bc2004-07-08 14:23:22 +00002253 Int len;
sewardjc9a43662004-11-30 18:51:59 +00002254 HChar dis_buf[50];
sewardje05c42c2004-07-08 20:25:10 +00002255 IRType ty = szToITy(sz);
2256 IRTemp dst1 = newTemp(ty);
2257 IRTemp src = newTemp(ty);
2258 IRTemp dst0 = newTemp(ty);
sewardj92d168d2004-11-15 14:22:12 +00002259 IRTemp addr = IRTemp_INVALID;
sewardj66de2272004-07-16 21:19:05 +00002260 IROp op8 = Iop_INVALID;
sewardj180e8b32004-07-29 01:40:11 +00002261 UInt mask = sz==1 ? 0xFF : (sz==2 ? 0xFFFF : 0xFFFFFFFF);
sewardj41f43bc2004-07-08 14:23:22 +00002262
2263 switch (gregOfRM(modrm)) {
sewardje05c42c2004-07-08 20:25:10 +00002264 case 0: op8 = Iop_Add8; break; case 1: op8 = Iop_Or8; break;
sewardj66de2272004-07-16 21:19:05 +00002265 case 2: break; // ADC
2266 case 3: break; // SBB
sewardje05c42c2004-07-08 20:25:10 +00002267 case 4: op8 = Iop_And8; break; case 5: op8 = Iop_Sub8; break;
2268 case 6: op8 = Iop_Xor8; break; case 7: op8 = Iop_Sub8; break;
sewardj41f43bc2004-07-08 14:23:22 +00002269 default: vpanic("dis_Grp1: unhandled case");
2270 }
sewardj41f43bc2004-07-08 14:23:22 +00002271
2272 if (epartIsReg(modrm)) {
2273 vassert(am_sz == 1);
2274
2275 assign(dst0, getIReg(sz,eregOfRM(modrm)));
sewardj180e8b32004-07-29 01:40:11 +00002276 assign(src, mkU(ty,d32 & mask));
sewardj41f43bc2004-07-08 14:23:22 +00002277
sewardj180e8b32004-07-29 01:40:11 +00002278 if (gregOfRM(modrm) == 2 /* ADC */) {
2279 helper_ADC( sz, dst1, dst0, src );
2280 } else
2281 if (gregOfRM(modrm) == 3 /* SBB */) {
2282 helper_SBB( sz, dst1, dst0, src );
2283 } else {
2284 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
sewardj5bd4d162004-11-10 13:02:48 +00002285 if (isAddSub(op8))
sewardj2a2ba8b2004-11-08 13:14:06 +00002286 setFlags_DEP1_DEP2(op8, dst0, src, ty);
sewardjb9c5cf62004-08-24 15:10:38 +00002287 else
sewardj2a2ba8b2004-11-08 13:14:06 +00002288 setFlags_DEP1(op8, dst1, ty);
sewardj180e8b32004-07-29 01:40:11 +00002289 }
sewardj41f43bc2004-07-08 14:23:22 +00002290
2291 if (gregOfRM(modrm) < 7)
sewardje05c42c2004-07-08 20:25:10 +00002292 putIReg(sz, eregOfRM(modrm), mkexpr(dst1));
sewardj41f43bc2004-07-08 14:23:22 +00002293
2294 delta += (am_sz + d_sz);
2295 DIP("%s%c $0x%x, %s\n", nameGrp1(gregOfRM(modrm)), nameISize(sz), d32,
2296 nameIReg(sz,eregOfRM(modrm)));
2297 } else {
sewardje87b4842004-07-10 12:23:30 +00002298 addr = disAMode ( &len, sorb, delta, dis_buf);
sewardj41f43bc2004-07-08 14:23:22 +00002299
sewardj940e8c92004-07-11 16:53:24 +00002300 assign(dst0, loadLE(ty,mkexpr(addr)));
sewardj180e8b32004-07-29 01:40:11 +00002301 assign(src, mkU(ty,d32 & mask));
sewardj41f43bc2004-07-08 14:23:22 +00002302
sewardj66de2272004-07-16 21:19:05 +00002303 if (gregOfRM(modrm) == 2 /* ADC */) {
sewardj3af115f2004-07-14 02:46:52 +00002304 helper_ADC( sz, dst1, dst0, src );
2305 } else
sewardj66de2272004-07-16 21:19:05 +00002306 if (gregOfRM(modrm) == 3 /* SBB */) {
sewardje166ed02004-10-25 02:27:01 +00002307 helper_SBB( sz, dst1, dst0, src );
sewardj3af115f2004-07-14 02:46:52 +00002308 } else {
2309 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
sewardj5bd4d162004-11-10 13:02:48 +00002310 if (isAddSub(op8))
sewardj2a2ba8b2004-11-08 13:14:06 +00002311 setFlags_DEP1_DEP2(op8, dst0, src, ty);
sewardjb9c5cf62004-08-24 15:10:38 +00002312 else
sewardj2a2ba8b2004-11-08 13:14:06 +00002313 setFlags_DEP1(op8, dst1, ty);
sewardj3af115f2004-07-14 02:46:52 +00002314 }
sewardj41f43bc2004-07-08 14:23:22 +00002315
2316 if (gregOfRM(modrm) < 7)
sewardj940e8c92004-07-11 16:53:24 +00002317 storeLE(mkexpr(addr), mkexpr(dst1));
sewardj41f43bc2004-07-08 14:23:22 +00002318
2319 delta += (len+d_sz);
2320 DIP("%s%c $0x%x, %s\n", nameGrp1(gregOfRM(modrm)), nameISize(sz),
2321 d32, dis_buf);
2322 }
2323 return delta;
2324}
2325
2326
sewardj6d2638e2004-07-15 09:38:27 +00002327/* Group 2 extended opcodes. shift_expr must be an 8-bit typed
2328 expression. */
2329
sewardje90ad6a2004-07-10 19:02:10 +00002330static
2331UInt dis_Grp2 ( UChar sorb,
2332 UInt delta, UChar modrm,
sewardj6d2638e2004-07-15 09:38:27 +00002333 Int am_sz, Int d_sz, Int sz, IRExpr* shift_expr,
sewardj2d49b432005-02-01 00:37:06 +00002334 HChar* shift_expr_txt )
sewardje90ad6a2004-07-10 19:02:10 +00002335{
2336 /* delta on entry points at the modrm byte. */
sewardjc9a43662004-11-30 18:51:59 +00002337 HChar dis_buf[50];
sewardj6d2638e2004-07-15 09:38:27 +00002338 Int len;
sewardj9aebb0c2004-10-24 19:20:43 +00002339 Bool isShift, isRotate, isRotateRC;
sewardj6d2638e2004-07-15 09:38:27 +00002340 IRType ty = szToITy(sz);
2341 IRTemp dst0 = newTemp(ty);
2342 IRTemp dst1 = newTemp(ty);
sewardj92d168d2004-11-15 14:22:12 +00002343 IRTemp addr = IRTemp_INVALID;
sewardje90ad6a2004-07-10 19:02:10 +00002344
2345 vassert(sz == 1 || sz == 2 || sz == 4);
2346
sewardje90ad6a2004-07-10 19:02:10 +00002347 /* Put value to shift/rotate in dst0. */
2348 if (epartIsReg(modrm)) {
2349 assign(dst0, getIReg(sz, eregOfRM(modrm)));
sewardj940e8c92004-07-11 16:53:24 +00002350 delta += (am_sz + d_sz);
sewardje90ad6a2004-07-10 19:02:10 +00002351 } else {
sewardj940e8c92004-07-11 16:53:24 +00002352 addr = disAMode ( &len, sorb, delta, dis_buf);
2353 assign(dst0, loadLE(ty,mkexpr(addr)));
2354 delta += len + d_sz;
sewardje90ad6a2004-07-10 19:02:10 +00002355 }
2356
2357 isShift = False;
2358 switch (gregOfRM(modrm)) { case 4: case 5: case 7: isShift = True; }
2359
sewardj750f4072004-07-26 22:39:11 +00002360 isRotate = False;
2361 switch (gregOfRM(modrm)) { case 0: case 1: isRotate = True; }
2362
sewardj2d49b432005-02-01 00:37:06 +00002363 isRotateRC = toBool(gregOfRM(modrm) == 3);
sewardj9aebb0c2004-10-24 19:20:43 +00002364
2365 if (!isShift && !isRotate && !isRotateRC) {
sewardj8c7f1ab2004-07-29 20:31:09 +00002366 vex_printf("\ncase %d\n", gregOfRM(modrm));
2367 vpanic("dis_Grp2(Reg): unhandled case(x86)");
2368 }
2369
sewardj9aebb0c2004-10-24 19:20:43 +00002370 if (isRotateRC) {
2371 /* call a helper; this insn is so ridiculous it does not deserve
2372 better */
2373 IRTemp r64 = newTemp(Ity_I64);
sewardjf9655262004-10-31 20:02:16 +00002374 IRExpr** args
2375 = mkIRExprVec_4( widenUto32(mkexpr(dst0)), /* thing to rotate */
2376 widenUto32(shift_expr), /* rotate amount */
sewardj2a9ad022004-11-25 02:46:58 +00002377 widenUto32(mk_x86g_calculate_eflags_all()),
sewardjf9655262004-10-31 20:02:16 +00002378 mkU32(sz) );
2379 assign( r64, mkIRExprCCall(
sewardj8ea867b2004-10-30 19:03:02 +00002380 Ity_I64,
sewardjf9655262004-10-31 20:02:16 +00002381 0/*regparm*/,
sewardj2a9ad022004-11-25 02:46:58 +00002382 "x86g_calculate_RCR", &x86g_calculate_RCR,
sewardj8ea867b2004-10-30 19:03:02 +00002383 args
sewardjf9655262004-10-31 20:02:16 +00002384 )
2385 );
sewardj9aebb0c2004-10-24 19:20:43 +00002386 /* new eflags in hi half r64; new value in lo half r64 */
2387 assign( dst1, narrowTo(ty, unop(Iop_64to32, mkexpr(r64))) );
sewardj2a9ad022004-11-25 02:46:58 +00002388 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
sewardj2a2ba8b2004-11-08 13:14:06 +00002389 stmt( IRStmt_Put( OFFB_CC_DEP1, unop(Iop_64HIto32, mkexpr(r64)) ));
2390 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
sewardja3b7e3a2005-04-05 01:54:19 +00002391 /* Set NDEP even though it isn't used. This makes redundant-PUT
2392 elimination of previous stores to this field work better. */
2393 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardj9aebb0c2004-10-24 19:20:43 +00002394 }
2395
sewardje90ad6a2004-07-10 19:02:10 +00002396 if (isShift) {
2397
sewardjc22a6fd2004-07-29 23:41:47 +00002398 IRTemp pre32 = newTemp(Ity_I32);
2399 IRTemp res32 = newTemp(Ity_I32);
2400 IRTemp res32ss = newTemp(Ity_I32);
sewardj6d2638e2004-07-15 09:38:27 +00002401 IRTemp shift_amt = newTemp(Ity_I8);
sewardjc22a6fd2004-07-29 23:41:47 +00002402 IROp op32;
sewardje90ad6a2004-07-10 19:02:10 +00002403
2404 switch (gregOfRM(modrm)) {
sewardjc22a6fd2004-07-29 23:41:47 +00002405 case 4: op32 = Iop_Shl32; break;
2406 case 5: op32 = Iop_Shr32; break;
2407 case 7: op32 = Iop_Sar32; break;
sewardje90ad6a2004-07-10 19:02:10 +00002408 default: vpanic("dis_Grp2:shift"); break;
2409 }
2410
sewardjc22a6fd2004-07-29 23:41:47 +00002411 /* Widen the value to be shifted to 32 bits, do the shift, and
2412 narrow back down. This seems surprisingly long-winded, but
2413 unfortunately the Intel semantics requires that 8/16-bit
2414 shifts give defined results for shift values all the way up
2415 to 31, and this seems the simplest way to do it. It has the
2416 advantage that the only IR level shifts generated are of 32
2417 bit values, and the shift amount is guaranteed to be in the
2418 range 0 .. 31, thereby observing the IR semantics requiring
2419 all shift values to be in the range 0 .. 2^word_size-1. */
2420
2421 /* shift_amt = shift_expr & 31, regardless of operation size */
2422 assign( shift_amt, binop(Iop_And8, shift_expr, mkU8(31)) );
2423
2424 /* suitably widen the value to be shifted to 32 bits. */
2425 assign( pre32, op32==Iop_Sar32 ? widenSto32(mkexpr(dst0))
2426 : widenUto32(mkexpr(dst0)) );
2427
2428 /* res32 = pre32 `shift` shift_amt */
2429 assign( res32, binop(op32, mkexpr(pre32), mkexpr(shift_amt)) );
2430
2431 /* res32ss = pre32 `shift` ((shift_amt - 1) & 31) */
2432 assign( res32ss,
2433 binop(op32,
2434 mkexpr(pre32),
2435 binop(Iop_And8,
2436 binop(Iop_Sub8,
2437 mkexpr(shift_amt), mkU8(1)),
2438 mkU8(31))) );
sewardje90ad6a2004-07-10 19:02:10 +00002439
2440 /* Build the flags thunk. */
sewardj2a2ba8b2004-11-08 13:14:06 +00002441 setFlags_DEP1_DEP2_shift(op32, res32, res32ss, ty, shift_amt);
sewardjc22a6fd2004-07-29 23:41:47 +00002442
2443 /* Narrow the result back down. */
2444 assign( dst1, narrowTo(ty, mkexpr(res32)) );
sewardj750f4072004-07-26 22:39:11 +00002445
sewardj1813dbe2004-07-28 17:09:04 +00002446 } /* if (isShift) */
2447
2448 else
sewardj750f4072004-07-26 22:39:11 +00002449 if (isRotate) {
sewardj7ebbdae2004-08-26 12:30:48 +00002450 Int ccOp = ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
sewardj2d49b432005-02-01 00:37:06 +00002451 Bool left = toBool(gregOfRM(modrm) == 0);
sewardj7ebbdae2004-08-26 12:30:48 +00002452 IRTemp rot_amt = newTemp(Ity_I8);
2453 IRTemp rot_amt32 = newTemp(Ity_I8);
2454 IRTemp oldFlags = newTemp(Ity_I32);
sewardj750f4072004-07-26 22:39:11 +00002455
2456 /* rot_amt = shift_expr & mask */
sewardjc22a6fd2004-07-29 23:41:47 +00002457 /* By masking the rotate amount thusly, the IR-level Shl/Shr
2458 expressions never shift beyond the word size and thus remain
2459 well defined. */
sewardj7ebbdae2004-08-26 12:30:48 +00002460 assign(rot_amt32, binop(Iop_And8, shift_expr, mkU8(31)));
2461
2462 if (ty == Ity_I32)
2463 assign(rot_amt, mkexpr(rot_amt32));
2464 else
2465 assign(rot_amt, binop(Iop_And8, mkexpr(rot_amt32), mkU8(8*sz-1)));
sewardj750f4072004-07-26 22:39:11 +00002466
2467 if (left) {
sewardj1813dbe2004-07-28 17:09:04 +00002468
sewardj750f4072004-07-26 22:39:11 +00002469 /* dst1 = (dst0 << rot_amt) | (dst0 >>u (wordsize-rot_amt)) */
2470 assign(dst1,
2471 binop( mkSizedOp(ty,Iop_Or8),
2472 binop( mkSizedOp(ty,Iop_Shl8),
2473 mkexpr(dst0),
2474 mkexpr(rot_amt)
2475 ),
2476 binop( mkSizedOp(ty,Iop_Shr8),
2477 mkexpr(dst0),
2478 binop(Iop_Sub8,mkU8(8*sz), mkexpr(rot_amt))
2479 )
2480 )
2481 );
sewardj2a9ad022004-11-25 02:46:58 +00002482 ccOp += X86G_CC_OP_ROLB;
sewardj750f4072004-07-26 22:39:11 +00002483
sewardj1813dbe2004-07-28 17:09:04 +00002484 } else { /* right */
sewardj750f4072004-07-26 22:39:11 +00002485
sewardj1813dbe2004-07-28 17:09:04 +00002486 /* dst1 = (dst0 >>u rot_amt) | (dst0 << (wordsize-rot_amt)) */
2487 assign(dst1,
2488 binop( mkSizedOp(ty,Iop_Or8),
2489 binop( mkSizedOp(ty,Iop_Shr8),
2490 mkexpr(dst0),
2491 mkexpr(rot_amt)
2492 ),
2493 binop( mkSizedOp(ty,Iop_Shl8),
2494 mkexpr(dst0),
2495 binop(Iop_Sub8,mkU8(8*sz), mkexpr(rot_amt))
sewardj750f4072004-07-26 22:39:11 +00002496 )
2497 )
2498 );
sewardj2a9ad022004-11-25 02:46:58 +00002499 ccOp += X86G_CC_OP_RORB;
sewardjc22a6fd2004-07-29 23:41:47 +00002500
sewardj750f4072004-07-26 22:39:11 +00002501 }
sewardjc22a6fd2004-07-29 23:41:47 +00002502
sewardj1813dbe2004-07-28 17:09:04 +00002503 /* dst1 now holds the rotated value. Build flag thunk. We
2504 need the resulting value for this, and the previous flags.
2505 Except don't set it if the rotate count is zero. */
2506
sewardj2a9ad022004-11-25 02:46:58 +00002507 assign(oldFlags, mk_x86g_calculate_eflags_all());
sewardj1813dbe2004-07-28 17:09:04 +00002508
sewardj2a2ba8b2004-11-08 13:14:06 +00002509 /* CC_DEP1 is the rotated value. CC_NDEP is flags before. */
sewardj1813dbe2004-07-28 17:09:04 +00002510 stmt( IRStmt_Put( OFFB_CC_OP,
sewardj7ebbdae2004-08-26 12:30:48 +00002511 IRExpr_Mux0X( mkexpr(rot_amt32),
sewardj1813dbe2004-07-28 17:09:04 +00002512 IRExpr_Get(OFFB_CC_OP,Ity_I32),
2513 mkU32(ccOp))) );
sewardj2a2ba8b2004-11-08 13:14:06 +00002514 stmt( IRStmt_Put( OFFB_CC_DEP1,
sewardj7ebbdae2004-08-26 12:30:48 +00002515 IRExpr_Mux0X( mkexpr(rot_amt32),
sewardj2a2ba8b2004-11-08 13:14:06 +00002516 IRExpr_Get(OFFB_CC_DEP1,Ity_I32),
sewardjc22a6fd2004-07-29 23:41:47 +00002517 widenUto32(mkexpr(dst1)))) );
sewardj2a2ba8b2004-11-08 13:14:06 +00002518 stmt( IRStmt_Put( OFFB_CC_DEP2,
sewardj7ebbdae2004-08-26 12:30:48 +00002519 IRExpr_Mux0X( mkexpr(rot_amt32),
sewardj2a2ba8b2004-11-08 13:14:06 +00002520 IRExpr_Get(OFFB_CC_DEP2,Ity_I32),
2521 mkU32(0))) );
2522 stmt( IRStmt_Put( OFFB_CC_NDEP,
2523 IRExpr_Mux0X( mkexpr(rot_amt32),
2524 IRExpr_Get(OFFB_CC_NDEP,Ity_I32),
sewardj1813dbe2004-07-28 17:09:04 +00002525 mkexpr(oldFlags))) );
2526 } /* if (isRotate) */
sewardje90ad6a2004-07-10 19:02:10 +00002527
2528 /* Save result, and finish up. */
2529 if (epartIsReg(modrm)) {
2530 putIReg(sz, eregOfRM(modrm), mkexpr(dst1));
sewardjf48ac192004-10-29 00:41:29 +00002531 if (vex_traceflags & VEX_TRACE_FE) {
sewardje90ad6a2004-07-10 19:02:10 +00002532 vex_printf("%s%c ",
2533 nameGrp2(gregOfRM(modrm)), nameISize(sz) );
sewardj6d2638e2004-07-15 09:38:27 +00002534 if (shift_expr_txt)
2535 vex_printf("%s", shift_expr_txt);
2536 else
2537 ppIRExpr(shift_expr);
sewardje90ad6a2004-07-10 19:02:10 +00002538 vex_printf(", %s\n", nameIReg(sz,eregOfRM(modrm)));
2539 }
sewardje90ad6a2004-07-10 19:02:10 +00002540 } else {
sewardj940e8c92004-07-11 16:53:24 +00002541 storeLE(mkexpr(addr), mkexpr(dst1));
sewardjf48ac192004-10-29 00:41:29 +00002542 if (vex_traceflags & VEX_TRACE_FE) {
sewardj940e8c92004-07-11 16:53:24 +00002543 vex_printf("%s%c ",
2544 nameGrp2(gregOfRM(modrm)), nameISize(sz) );
sewardj6d2638e2004-07-15 09:38:27 +00002545 if (shift_expr_txt)
2546 vex_printf("%s", shift_expr_txt);
2547 else
2548 ppIRExpr(shift_expr);
sewardj940e8c92004-07-11 16:53:24 +00002549 vex_printf(", %s\n", dis_buf);
2550 }
sewardje90ad6a2004-07-10 19:02:10 +00002551 }
sewardje90ad6a2004-07-10 19:02:10 +00002552 return delta;
2553}
2554
2555
sewardj490ad382005-03-13 17:25:53 +00002556/* Group 8 extended opcodes (but BT/BTS/BTC/BTR only). */
2557static
2558UInt dis_Grp8_Imm ( UChar sorb,
2559 UInt delta, UChar modrm,
2560 Int am_sz, Int sz, UInt src_val,
2561 Bool* decode_OK )
2562{
2563 /* src_val denotes a d8.
2564 And delta on entry points at the modrm byte. */
sewardje90ad6a2004-07-10 19:02:10 +00002565
sewardj490ad382005-03-13 17:25:53 +00002566 IRType ty = szToITy(sz);
2567 IRTemp t2 = newTemp(Ity_I32);
2568 IRTemp t2m = newTemp(Ity_I32);
2569 IRTemp t_addr = IRTemp_INVALID;
2570 HChar dis_buf[50];
2571 UInt mask;
sewardjd1061ab2004-07-08 01:45:30 +00002572
sewardj490ad382005-03-13 17:25:53 +00002573 /* we're optimists :-) */
2574 *decode_OK = True;
sewardjd1061ab2004-07-08 01:45:30 +00002575
sewardj490ad382005-03-13 17:25:53 +00002576 /* Limit src_val -- the bit offset -- to something within a word.
2577 The Intel docs say that literal offsets larger than a word are
2578 masked in this way. */
2579 switch (sz) {
2580 case 2: src_val &= 15; break;
2581 case 4: src_val &= 31; break;
2582 default: *decode_OK = False; return delta;
2583 }
sewardjcf780b42004-07-13 18:42:17 +00002584
sewardj490ad382005-03-13 17:25:53 +00002585 /* Invent a mask suitable for the operation. */
2586 switch (gregOfRM(modrm)) {
2587 case 4: /* BT */ mask = 0; break;
2588 case 5: /* BTS */ mask = 1 << src_val; break;
2589 case 6: /* BTR */ mask = ~(1 << src_val); break;
2590 case 7: /* BTC */ mask = 1 << src_val; break;
2591 /* If this needs to be extended, probably simplest to make a
2592 new function to handle the other cases (0 .. 3). The
2593 Intel docs do however not indicate any use for 0 .. 3, so
2594 we don't expect this to happen. */
2595 default: *decode_OK = False; return delta;
2596 }
2597
2598 /* Fetch the value to be tested and modified into t2, which is
2599 32-bits wide regardless of sz. */
2600 if (epartIsReg(modrm)) {
2601 vassert(am_sz == 1);
sewardj5a8334e2005-03-13 19:52:45 +00002602 assign( t2, widenUto32(getIReg(sz, eregOfRM(modrm))) );
sewardj490ad382005-03-13 17:25:53 +00002603 delta += (am_sz + 1);
2604 DIP("%s%c $0x%x, %s\n", nameGrp8(gregOfRM(modrm)), nameISize(sz),
2605 src_val, nameIReg(sz,eregOfRM(modrm)));
2606 } else {
2607 Int len;
2608 t_addr = disAMode ( &len, sorb, delta, dis_buf);
2609 delta += (len+1);
2610 assign( t2, widenUto32(loadLE(ty, mkexpr(t_addr))) );
2611 DIP("%s%c $0x%x, %s\n", nameGrp8(gregOfRM(modrm)), nameISize(sz),
2612 src_val, dis_buf);
2613 }
2614
2615 /* Copy relevant bit from t2 into the carry flag. */
2616 /* Flags: C=selected bit, O,S,Z,A,P undefined, so are set to zero. */
2617 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
2618 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
2619 stmt( IRStmt_Put(
2620 OFFB_CC_DEP1,
2621 binop(Iop_And32,
2622 binop(Iop_Shr32, mkexpr(t2), mkU8(src_val)),
2623 mkU32(1))
2624 ));
sewardja3b7e3a2005-04-05 01:54:19 +00002625 /* Set NDEP even though it isn't used. This makes redundant-PUT
2626 elimination of previous stores to this field work better. */
2627 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardj490ad382005-03-13 17:25:53 +00002628
2629 /* Compute the new value into t2m, if non-BT. */
2630 switch (gregOfRM(modrm)) {
2631 case 4: /* BT */
2632 break;
2633 case 5: /* BTS */
2634 assign( t2m, binop(Iop_Or32, mkU32(mask), mkexpr(t2)) );
2635 break;
2636 case 6: /* BTR */
2637 assign( t2m, binop(Iop_And32, mkU32(mask), mkexpr(t2)) );
2638 break;
2639 case 7: /* BTC */
2640 assign( t2m, binop(Iop_Xor32, mkU32(mask), mkexpr(t2)) );
2641 break;
sewardjba89f4c2005-04-07 17:31:27 +00002642 default:
2643 /*NOTREACHED*/ /*the previous switch guards this*/
sewardj490ad382005-03-13 17:25:53 +00002644 vassert(0);
2645 }
2646
2647 /* Write the result back, if non-BT. */
2648 if (gregOfRM(modrm) != 4 /* BT */) {
2649 if (epartIsReg(modrm)) {
2650 putIReg(sz, eregOfRM(modrm), narrowTo(ty, mkexpr(t2m)));
2651 } else {
2652 storeLE(mkexpr(t_addr), narrowTo(ty, mkexpr(t2m)));
2653 }
2654 }
2655
2656 return delta;
2657}
sewardjcf780b42004-07-13 18:42:17 +00002658
2659
sewardj1813dbe2004-07-28 17:09:04 +00002660/* Signed/unsigned widening multiply. Generate IR to multiply the
2661 value in EAX/AX/AL by the given IRTemp, and park the result in
2662 EDX:EAX/DX:AX/AX.
sewardjcf780b42004-07-13 18:42:17 +00002663*/
sewardj1813dbe2004-07-28 17:09:04 +00002664static void codegen_mulL_A_D ( Int sz, Bool syned,
sewardj2d49b432005-02-01 00:37:06 +00002665 IRTemp tmp, HChar* tmp_txt )
sewardjcf780b42004-07-13 18:42:17 +00002666{
sewardjcf780b42004-07-13 18:42:17 +00002667 IRType ty = szToITy(sz);
2668 IRTemp t1 = newTemp(ty);
sewardjcf780b42004-07-13 18:42:17 +00002669
sewardj1813dbe2004-07-28 17:09:04 +00002670 assign( t1, getIReg(sz, R_EAX) );
sewardjcf780b42004-07-13 18:42:17 +00002671
2672 switch (ty) {
sewardjb81f8b32004-07-30 10:17:50 +00002673 case Ity_I32: {
2674 IRTemp res64 = newTemp(Ity_I64);
sewardj948d48b2004-11-05 19:49:09 +00002675 IRTemp resHi = newTemp(Ity_I32);
2676 IRTemp resLo = newTemp(Ity_I32);
sewardjb81f8b32004-07-30 10:17:50 +00002677 IROp mulOp = syned ? Iop_MullS32 : Iop_MullU32;
sewardj2a9ad022004-11-25 02:46:58 +00002678 UInt tBaseOp = syned ? X86G_CC_OP_SMULB : X86G_CC_OP_UMULB;
sewardj2a2ba8b2004-11-08 13:14:06 +00002679 setFlags_MUL ( Ity_I32, t1, tmp, tBaseOp );
sewardjb81f8b32004-07-30 10:17:50 +00002680 assign( res64, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
sewardj948d48b2004-11-05 19:49:09 +00002681 assign( resHi, unop(Iop_64HIto32,mkexpr(res64)));
2682 assign( resLo, unop(Iop_64to32,mkexpr(res64)));
sewardj948d48b2004-11-05 19:49:09 +00002683 putIReg(4, R_EDX, mkexpr(resHi));
2684 putIReg(4, R_EAX, mkexpr(resLo));
sewardjb81f8b32004-07-30 10:17:50 +00002685 break;
2686 }
2687 case Ity_I16: {
2688 IRTemp res32 = newTemp(Ity_I32);
sewardj948d48b2004-11-05 19:49:09 +00002689 IRTemp resHi = newTemp(Ity_I16);
2690 IRTemp resLo = newTemp(Ity_I16);
sewardjb81f8b32004-07-30 10:17:50 +00002691 IROp mulOp = syned ? Iop_MullS16 : Iop_MullU16;
sewardj2a9ad022004-11-25 02:46:58 +00002692 UInt tBaseOp = syned ? X86G_CC_OP_SMULB : X86G_CC_OP_UMULB;
sewardj2a2ba8b2004-11-08 13:14:06 +00002693 setFlags_MUL ( Ity_I16, t1, tmp, tBaseOp );
sewardjb81f8b32004-07-30 10:17:50 +00002694 assign( res32, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
sewardj948d48b2004-11-05 19:49:09 +00002695 assign( resHi, unop(Iop_32HIto16,mkexpr(res32)));
2696 assign( resLo, unop(Iop_32to16,mkexpr(res32)));
sewardj948d48b2004-11-05 19:49:09 +00002697 putIReg(2, R_EDX, mkexpr(resHi));
2698 putIReg(2, R_EAX, mkexpr(resLo));
sewardjb81f8b32004-07-30 10:17:50 +00002699 break;
2700 }
2701 case Ity_I8: {
2702 IRTemp res16 = newTemp(Ity_I16);
sewardj948d48b2004-11-05 19:49:09 +00002703 IRTemp resHi = newTemp(Ity_I8);
2704 IRTemp resLo = newTemp(Ity_I8);
sewardjb81f8b32004-07-30 10:17:50 +00002705 IROp mulOp = syned ? Iop_MullS8 : Iop_MullU8;
sewardj2a9ad022004-11-25 02:46:58 +00002706 UInt tBaseOp = syned ? X86G_CC_OP_SMULB : X86G_CC_OP_UMULB;
sewardj2a2ba8b2004-11-08 13:14:06 +00002707 setFlags_MUL ( Ity_I8, t1, tmp, tBaseOp );
sewardjb81f8b32004-07-30 10:17:50 +00002708 assign( res16, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
sewardj948d48b2004-11-05 19:49:09 +00002709 assign( resHi, unop(Iop_16HIto8,mkexpr(res16)));
2710 assign( resLo, unop(Iop_16to8,mkexpr(res16)));
sewardjb81f8b32004-07-30 10:17:50 +00002711 putIReg(2, R_EAX, mkexpr(res16));
2712 break;
2713 }
2714 default:
2715 vpanic("codegen_mulL_A_D(x86)");
sewardjcf780b42004-07-13 18:42:17 +00002716 }
sewardj1813dbe2004-07-28 17:09:04 +00002717 DIP("%s%c %s\n", syned ? "imul" : "mul", nameISize(sz), tmp_txt);
sewardjcf780b42004-07-13 18:42:17 +00002718}
2719
sewardj940e8c92004-07-11 16:53:24 +00002720
2721/* Group 3 extended opcodes. */
2722static
2723UInt dis_Grp3 ( UChar sorb, Int sz, UInt delta )
2724{
sewardjc9a43662004-11-30 18:51:59 +00002725 UInt d32;
2726 UChar modrm;
2727 HChar dis_buf[50];
2728 Int len;
sewardjc2ac51e2004-07-12 01:03:26 +00002729 IRTemp addr;
sewardj940e8c92004-07-11 16:53:24 +00002730 IRType ty = szToITy(sz);
2731 IRTemp t1 = newTemp(ty);
sewardj92d168d2004-11-15 14:22:12 +00002732 // IRTemp t2 = IRTemp_INVALID;
sewardj940e8c92004-07-11 16:53:24 +00002733 IRTemp dst1, src, dst0;
2734 modrm = getIByte(delta);
2735 if (epartIsReg(modrm)) {
2736 switch (gregOfRM(modrm)) {
sewardjc2ac51e2004-07-12 01:03:26 +00002737 case 0: { /* TEST */
2738 delta++; d32 = getUDisp(sz, delta); delta += sz;
sewardj5bd4d162004-11-10 13:02:48 +00002739 dst1 = newTemp(ty);
2740 assign(dst1, binop(mkSizedOp(ty,Iop_And8),
2741 getIReg(sz,eregOfRM(modrm)),
sewardjc2ac51e2004-07-12 01:03:26 +00002742 mkU(ty,d32)));
sewardj5bd4d162004-11-10 13:02:48 +00002743 setFlags_DEP1( Iop_And8, dst1, ty );
sewardjc2ac51e2004-07-12 01:03:26 +00002744 DIP("test%c $0x%x, %s\n", nameISize(sz), d32,
2745 nameIReg(sz, eregOfRM(modrm)));
2746 break;
2747 }
sewardj940e8c92004-07-11 16:53:24 +00002748 case 2: /* NOT */
2749 delta++;
2750 putIReg(sz, eregOfRM(modrm),
2751 unop(mkSizedOp(ty,Iop_Not8),
2752 getIReg(sz, eregOfRM(modrm))));
2753 DIP("not%c %s\n", nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
2754 break;
2755 case 3: /* NEG */
2756 delta++;
2757 dst0 = newTemp(ty);
2758 src = newTemp(ty);
2759 dst1 = newTemp(ty);
sewardj5bd4d162004-11-10 13:02:48 +00002760 assign(dst0, mkU(ty,0));
sewardja511afc2004-07-29 22:26:03 +00002761 assign(src, getIReg(sz,eregOfRM(modrm)));
sewardj71a35e72005-05-03 12:20:15 +00002762 assign(dst1, unop(mkSizedOp(ty,Iop_Neg8), mkexpr(src)));
sewardj2a2ba8b2004-11-08 13:14:06 +00002763 setFlags_DEP1_DEP2(Iop_Sub8, dst0, src, ty);
sewardj5bd4d162004-11-10 13:02:48 +00002764 putIReg(sz, eregOfRM(modrm), mkexpr(dst1));
sewardj940e8c92004-07-11 16:53:24 +00002765 DIP("neg%c %s\n", nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
2766 break;
sewardjcf780b42004-07-13 18:42:17 +00002767 case 4: /* MUL (unsigned widening) */
2768 delta++;
sewardj1813dbe2004-07-28 17:09:04 +00002769 src = newTemp(ty);
sewardj5bd4d162004-11-10 13:02:48 +00002770 assign(src, getIReg(sz,eregOfRM(modrm)));
sewardj1813dbe2004-07-28 17:09:04 +00002771 codegen_mulL_A_D ( sz, False, src, nameIReg(sz,eregOfRM(modrm)) );
sewardjcf780b42004-07-13 18:42:17 +00002772 break;
sewardjcaca9d02004-07-28 07:11:32 +00002773 case 5: /* IMUL (signed widening) */
2774 delta++;
sewardj1813dbe2004-07-28 17:09:04 +00002775 src = newTemp(ty);
sewardj5bd4d162004-11-10 13:02:48 +00002776 assign(src, getIReg(sz,eregOfRM(modrm)));
sewardj1813dbe2004-07-28 17:09:04 +00002777 codegen_mulL_A_D ( sz, True, src, nameIReg(sz,eregOfRM(modrm)) );
sewardjcaca9d02004-07-28 07:11:32 +00002778 break;
sewardj68511542004-07-28 00:15:44 +00002779 case 6: /* DIV */
2780 delta++;
2781 assign( t1, getIReg(sz, eregOfRM(modrm)) );
2782 codegen_div ( sz, t1, False );
2783 DIP("div%c %s\n", nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
2784 break;
sewardjcaca9d02004-07-28 07:11:32 +00002785 case 7: /* IDIV */
2786 delta++;
2787 assign( t1, getIReg(sz, eregOfRM(modrm)) );
2788 codegen_div ( sz, t1, True );
2789 DIP("idiv%c %s\n", nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
2790 break;
sewardj940e8c92004-07-11 16:53:24 +00002791 default:
2792 vex_printf(
sewardj2d49b432005-02-01 00:37:06 +00002793 "unhandled Grp3(R) case %d\n", (Int)gregOfRM(modrm));
sewardj940e8c92004-07-11 16:53:24 +00002794 vpanic("Grp3(x86)");
2795 }
2796 } else {
sewardjc2ac51e2004-07-12 01:03:26 +00002797 addr = disAMode ( &len, sorb, delta, dis_buf );
2798 t1 = newTemp(ty);
2799 delta += len;
2800 assign(t1, loadLE(ty,mkexpr(addr)));
2801 switch (gregOfRM(modrm)) {
2802 case 0: { /* TEST */
2803 d32 = getUDisp(sz, delta); delta += sz;
sewardj5bd4d162004-11-10 13:02:48 +00002804 dst1 = newTemp(ty);
2805 assign(dst1, binop(mkSizedOp(ty,Iop_And8),
2806 mkexpr(t1), mkU(ty,d32)));
2807 setFlags_DEP1( Iop_And8, dst1, ty );
sewardjc2ac51e2004-07-12 01:03:26 +00002808 DIP("test%c $0x%x, %s\n", nameISize(sz), d32, dis_buf);
2809 break;
2810 }
sewardj78fe7912004-08-20 23:38:07 +00002811 case 2: /* NOT */
2812 storeLE( mkexpr(addr), unop(mkSizedOp(ty,Iop_Not8), mkexpr(t1)));
2813 DIP("not%c %s\n", nameISize(sz), dis_buf);
2814 break;
sewardj0c12ea82004-07-12 08:18:16 +00002815 case 3: /* NEG */
2816 dst0 = newTemp(ty);
2817 src = newTemp(ty);
2818 dst1 = newTemp(ty);
sewardj5bd4d162004-11-10 13:02:48 +00002819 assign(dst0, mkU(ty,0));
sewardja511afc2004-07-29 22:26:03 +00002820 assign(src, mkexpr(t1));
sewardj71a35e72005-05-03 12:20:15 +00002821 assign(dst1, unop(mkSizedOp(ty,Iop_Neg8), mkexpr(src)));
sewardj2a2ba8b2004-11-08 13:14:06 +00002822 setFlags_DEP1_DEP2(Iop_Sub8, dst0, src, ty);
sewardj5bd4d162004-11-10 13:02:48 +00002823 storeLE( mkexpr(addr), mkexpr(dst1) );
sewardj0c12ea82004-07-12 08:18:16 +00002824 DIP("neg%c %s\n", nameISize(sz), dis_buf);
2825 break;
sewardj1813dbe2004-07-28 17:09:04 +00002826 case 4: /* MUL */
2827 codegen_mulL_A_D ( sz, False, t1, dis_buf );
2828 break;
2829 case 5: /* IMUL */
2830 codegen_mulL_A_D ( sz, True, t1, dis_buf );
2831 break;
sewardj9690d922004-07-14 01:39:17 +00002832 case 6: /* DIV */
2833 codegen_div ( sz, t1, False );
2834 DIP("div%c %s\n", nameISize(sz), dis_buf);
2835 break;
sewardj1813dbe2004-07-28 17:09:04 +00002836 case 7: /* IDIV */
2837 codegen_div ( sz, t1, True );
2838 DIP("idiv%c %s\n", nameISize(sz), dis_buf);
2839 break;
sewardjc2ac51e2004-07-12 01:03:26 +00002840 default:
2841 vex_printf(
sewardj2d49b432005-02-01 00:37:06 +00002842 "unhandled Grp3(M) case %d\n", (Int)gregOfRM(modrm));
sewardjc2ac51e2004-07-12 01:03:26 +00002843 vpanic("Grp3(x86)");
2844 }
sewardj940e8c92004-07-11 16:53:24 +00002845 }
2846 return delta;
2847}
2848
2849
sewardjc2ac51e2004-07-12 01:03:26 +00002850/* Group 4 extended opcodes. */
2851static
2852UInt dis_Grp4 ( UChar sorb, UInt delta )
2853{
sewardjc9a43662004-11-30 18:51:59 +00002854 Int alen;
sewardjc2ac51e2004-07-12 01:03:26 +00002855 UChar modrm;
sewardjc9a43662004-11-30 18:51:59 +00002856 HChar dis_buf[50];
sewardjc2ac51e2004-07-12 01:03:26 +00002857 IRType ty = Ity_I8;
sewardj7ed22952004-07-29 00:09:58 +00002858 IRTemp t1 = newTemp(ty);
2859 IRTemp t2 = newTemp(ty);
sewardjc2ac51e2004-07-12 01:03:26 +00002860
2861 modrm = getIByte(delta);
2862 if (epartIsReg(modrm)) {
sewardjc2ac51e2004-07-12 01:03:26 +00002863 assign(t1, getIReg(1, eregOfRM(modrm)));
2864 switch (gregOfRM(modrm)) {
sewardj7ed22952004-07-29 00:09:58 +00002865 case 0: /* INC */
2866 assign(t2, binop(Iop_Add8, mkexpr(t1), mkU8(1)));
2867 putIReg(1, eregOfRM(modrm), mkexpr(t2));
2868 setFlags_INC_DEC( True, t2, ty );
2869 break;
sewardjc2ac51e2004-07-12 01:03:26 +00002870 case 1: /* DEC */
sewardjc2ac51e2004-07-12 01:03:26 +00002871 assign(t2, binop(Iop_Sub8, mkexpr(t1), mkU8(1)));
2872 putIReg(1, eregOfRM(modrm), mkexpr(t2));
2873 setFlags_INC_DEC( False, t2, ty );
2874 break;
2875 default:
2876 vex_printf(
sewardj2d49b432005-02-01 00:37:06 +00002877 "unhandled Grp4(R) case %d\n", (Int)gregOfRM(modrm));
sewardj7ed22952004-07-29 00:09:58 +00002878 vpanic("Grp4(x86,R)");
sewardjc2ac51e2004-07-12 01:03:26 +00002879 }
2880 delta++;
2881 DIP("%sb %s\n", nameGrp4(gregOfRM(modrm)),
2882 nameIReg(1, eregOfRM(modrm)));
2883 } else {
sewardj7ed22952004-07-29 00:09:58 +00002884 IRTemp addr = disAMode ( &alen, sorb, delta, dis_buf );
2885 assign( t1, loadLE(ty, mkexpr(addr)) );
2886 switch (gregOfRM(modrm)) {
sewardj588ea762004-09-10 18:56:32 +00002887 case 0: /* INC */
2888 assign(t2, binop(Iop_Add8, mkexpr(t1), mkU8(1)));
2889 storeLE( mkexpr(addr), mkexpr(t2) );
2890 setFlags_INC_DEC( True, t2, ty );
2891 break;
sewardj7ed22952004-07-29 00:09:58 +00002892 case 1: /* DEC */
2893 assign(t2, binop(Iop_Sub8, mkexpr(t1), mkU8(1)));
2894 storeLE( mkexpr(addr), mkexpr(t2) );
2895 setFlags_INC_DEC( False, t2, ty );
2896 break;
2897 default:
2898 vex_printf(
sewardj2d49b432005-02-01 00:37:06 +00002899 "unhandled Grp4(M) case %d\n", (Int)gregOfRM(modrm));
sewardj7ed22952004-07-29 00:09:58 +00002900 vpanic("Grp4(x86,M)");
2901 }
2902 delta += alen;
2903 DIP("%sb %s\n", nameGrp4(gregOfRM(modrm)), dis_buf);
sewardjc2ac51e2004-07-12 01:03:26 +00002904 }
2905 return delta;
2906}
sewardj0611d802004-07-11 02:37:54 +00002907
2908
2909/* Group 5 extended opcodes. */
2910static
sewardjce70a5c2004-10-18 14:09:54 +00002911UInt dis_Grp5 ( UChar sorb, Int sz, UInt delta, DisResult* whatNext )
sewardj0611d802004-07-11 02:37:54 +00002912{
2913 Int len;
2914 UChar modrm;
sewardjc9a43662004-11-30 18:51:59 +00002915 HChar dis_buf[50];
sewardj92d168d2004-11-15 14:22:12 +00002916 IRTemp addr = IRTemp_INVALID;
sewardj0611d802004-07-11 02:37:54 +00002917 IRType ty = szToITy(sz);
2918 IRTemp t1 = newTemp(ty);
sewardj92d168d2004-11-15 14:22:12 +00002919 IRTemp t2 = IRTemp_INVALID;
sewardj0611d802004-07-11 02:37:54 +00002920
2921 modrm = getIByte(delta);
2922 if (epartIsReg(modrm)) {
sewardj940e8c92004-07-11 16:53:24 +00002923 assign(t1, getIReg(sz,eregOfRM(modrm)));
sewardj0611d802004-07-11 02:37:54 +00002924 switch (gregOfRM(modrm)) {
sewardjc9a65702004-07-07 16:32:57 +00002925//-- case 0: /* INC */
2926//-- uInstr1(cb, INC, sz, TempReg, t1);
2927//-- setFlagsFromUOpcode(cb, INC);
2928//-- uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, eregOfRM(modrm));
2929//-- break;
2930//-- case 1: /* DEC */
2931//-- uInstr1(cb, DEC, sz, TempReg, t1);
2932//-- setFlagsFromUOpcode(cb, DEC);
2933//-- uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, eregOfRM(modrm));
2934//-- break;
sewardjc2ac51e2004-07-12 01:03:26 +00002935 case 2: /* call Ev */
2936 vassert(sz == 4);
2937 t2 = newTemp(Ity_I32);
2938 assign(t2, binop(Iop_Sub32, getIReg(4,R_ESP), mkU32(4)));
2939 putIReg(4, R_ESP, mkexpr(t2));
sewardj5bd4d162004-11-10 13:02:48 +00002940 storeLE( mkexpr(t2), mkU32(guest_eip_bbstart+delta+1));
2941 jmp_treg(Ijk_Call,t1);
sewardjce70a5c2004-10-18 14:09:54 +00002942 *whatNext = Dis_StopHere;
sewardjc2ac51e2004-07-12 01:03:26 +00002943 break;
sewardj0611d802004-07-11 02:37:54 +00002944 case 4: /* jmp Ev */
2945 vassert(sz == 4);
sewardj78c19df2004-07-12 22:49:27 +00002946 jmp_treg(Ijk_Boring,t1);
sewardjce70a5c2004-10-18 14:09:54 +00002947 *whatNext = Dis_StopHere;
sewardj0611d802004-07-11 02:37:54 +00002948 break;
2949 default:
2950 vex_printf(
sewardj2d49b432005-02-01 00:37:06 +00002951 "unhandled Grp5(R) case %d\n", (Int)gregOfRM(modrm));
sewardj0611d802004-07-11 02:37:54 +00002952 vpanic("Grp5(x86)");
2953 }
2954 delta++;
2955 DIP("%s%c %s\n", nameGrp5(gregOfRM(modrm)),
2956 nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
2957 } else {
2958 addr = disAMode ( &len, sorb, delta, dis_buf );
sewardj940e8c92004-07-11 16:53:24 +00002959 assign(t1, loadLE(ty,mkexpr(addr)));
sewardj0611d802004-07-11 02:37:54 +00002960 switch (gregOfRM(modrm)) {
2961 case 0: /* INC */
2962 t2 = newTemp(ty);
2963 assign(t2, binop(mkSizedOp(ty,Iop_Add8),
2964 mkexpr(t1), mkU(ty,1)));
2965 setFlags_INC_DEC( True, t2, ty );
sewardj940e8c92004-07-11 16:53:24 +00002966 storeLE(mkexpr(addr),mkexpr(t2));
sewardj0611d802004-07-11 02:37:54 +00002967 break;
sewardjc2ac51e2004-07-12 01:03:26 +00002968 case 1: /* DEC */
2969 t2 = newTemp(ty);
2970 assign(t2, binop(mkSizedOp(ty,Iop_Sub8),
2971 mkexpr(t1), mkU(ty,1)));
2972 setFlags_INC_DEC( False, t2, ty );
2973 storeLE(mkexpr(addr),mkexpr(t2));
2974 break;
sewardj77b86be2004-07-11 13:28:24 +00002975 case 2: /* call Ev */
2976 vassert(sz == 4);
2977 t2 = newTemp(Ity_I32);
2978 assign(t2, binop(Iop_Sub32, getIReg(4,R_ESP), mkU32(4)));
2979 putIReg(4, R_ESP, mkexpr(t2));
sewardj5bd4d162004-11-10 13:02:48 +00002980 storeLE( mkexpr(t2), mkU32(guest_eip_bbstart+delta+len));
2981 jmp_treg(Ijk_Call,t1);
sewardjce70a5c2004-10-18 14:09:54 +00002982 *whatNext = Dis_StopHere;
sewardj77b86be2004-07-11 13:28:24 +00002983 break;
2984 case 4: /* JMP Ev */
2985 vassert(sz == 4);
sewardj78c19df2004-07-12 22:49:27 +00002986 jmp_treg(Ijk_Boring,t1);
sewardjce70a5c2004-10-18 14:09:54 +00002987 *whatNext = Dis_StopHere;
sewardj77b86be2004-07-11 13:28:24 +00002988 break;
sewardj0c12ea82004-07-12 08:18:16 +00002989 case 6: /* PUSH Ev */
2990 vassert(sz == 4 || sz == 2);
2991 t2 = newTemp(Ity_I32);
2992 assign( t2, binop(Iop_Sub32,getIReg(4,R_ESP),mkU32(sz)) );
2993 putIReg(4, R_ESP, mkexpr(t2) );
sewardj5bd4d162004-11-10 13:02:48 +00002994 storeLE( mkexpr(t2), mkexpr(t1) );
sewardj0c12ea82004-07-12 08:18:16 +00002995 break;
sewardj0611d802004-07-11 02:37:54 +00002996 default:
2997 vex_printf(
sewardj2d49b432005-02-01 00:37:06 +00002998 "unhandled Grp5(M) case %d\n", (Int)gregOfRM(modrm));
sewardj0611d802004-07-11 02:37:54 +00002999 vpanic("Grp5(x86)");
3000 }
3001 delta += len;
3002 DIP("%s%c %s\n", nameGrp5(gregOfRM(modrm)),
3003 nameISize(sz), dis_buf);
3004 }
3005 return delta;
3006}
3007
sewardj464efa42004-11-19 22:17:29 +00003008
sewardj64e1d652004-07-12 14:00:46 +00003009/*------------------------------------------------------------*/
3010/*--- Disassembling string ops (including REP prefixes) ---*/
3011/*------------------------------------------------------------*/
3012
3013/* Code shared by all the string ops */
3014static
3015void dis_string_op_increment(Int sz, Int t_inc)
3016{
3017 if (sz == 4 || sz == 2) {
3018 assign( t_inc,
3019 binop(Iop_Shl32, IRExpr_Get( OFFB_DFLAG, Ity_I32 ),
sewardj6d2638e2004-07-15 09:38:27 +00003020 mkU8(sz/2) ) );
sewardj64e1d652004-07-12 14:00:46 +00003021 } else {
3022 assign( t_inc,
3023 IRExpr_Get( OFFB_DFLAG, Ity_I32 ) );
3024 }
3025}
3026
sewardj64e1d652004-07-12 14:00:46 +00003027static
3028void dis_string_op( void (*dis_OP)( Int, IRTemp ),
sewardj2d49b432005-02-01 00:37:06 +00003029 Int sz, HChar* name, UChar sorb )
sewardj64e1d652004-07-12 14:00:46 +00003030{
3031 IRTemp t_inc = newTemp(Ity_I32);
3032 vassert(sorb == 0);
3033 dis_string_op_increment(sz, t_inc);
3034 dis_OP( sz, t_inc );
3035 DIP("%s%c\n", name, nameISize(sz));
3036}
sewardj64e1d652004-07-12 14:00:46 +00003037
3038static
3039void dis_MOVS ( Int sz, IRTemp t_inc )
3040{
3041 IRType ty = szToITy(sz);
sewardj64e1d652004-07-12 14:00:46 +00003042 IRTemp td = newTemp(Ity_I32); /* EDI */
3043 IRTemp ts = newTemp(Ity_I32); /* ESI */
3044
sewardj64e1d652004-07-12 14:00:46 +00003045 assign( td, getIReg(4, R_EDI) );
3046 assign( ts, getIReg(4, R_ESI) );
3047
sewardj64e1d652004-07-12 14:00:46 +00003048 storeLE( mkexpr(td), loadLE(ty,mkexpr(ts)) );
3049
sewardj64e1d652004-07-12 14:00:46 +00003050 putIReg( 4, R_EDI, binop(Iop_Add32, mkexpr(td), mkexpr(t_inc)) );
3051 putIReg( 4, R_ESI, binop(Iop_Add32, mkexpr(ts), mkexpr(t_inc)) );
3052}
3053
sewardj10ca4eb2005-05-30 11:19:54 +00003054static
3055void dis_LODS ( Int sz, IRTemp t_inc )
3056{
3057 IRType ty = szToITy(sz);
3058 IRTemp ts = newTemp(Ity_I32); /* ESI */
3059
3060 assign( ts, getIReg(4, R_ESI) );
3061
3062 putIReg( sz, R_EAX, loadLE(ty, mkexpr(ts)) );
3063
3064 putIReg( 4, R_ESI, binop(Iop_Add32, mkexpr(ts), mkexpr(t_inc)) );
3065}
sewardj64e1d652004-07-12 14:00:46 +00003066
3067static
3068void dis_STOS ( Int sz, IRTemp t_inc )
3069{
3070 IRType ty = szToITy(sz);
3071 IRTemp ta = newTemp(ty); /* EAX */
3072 IRTemp td = newTemp(Ity_I32); /* EDI */
3073
sewardj64e1d652004-07-12 14:00:46 +00003074 assign( ta, getIReg(sz, R_EAX) );
sewardj64e1d652004-07-12 14:00:46 +00003075 assign( td, getIReg(4, R_EDI) );
3076
sewardj6d2638e2004-07-15 09:38:27 +00003077 storeLE( mkexpr(td), mkexpr(ta) );
sewardj64e1d652004-07-12 14:00:46 +00003078
sewardj64e1d652004-07-12 14:00:46 +00003079 putIReg( 4, R_EDI, binop(Iop_Add32, mkexpr(td), mkexpr(t_inc)) );
3080}
3081
3082static
3083void dis_CMPS ( Int sz, IRTemp t_inc )
3084{
3085 IRType ty = szToITy(sz);
sewardj6d2638e2004-07-15 09:38:27 +00003086 IRTemp tdv = newTemp(ty); /* (EDI) */
3087 IRTemp tsv = newTemp(ty); /* (ESI) */
sewardj64e1d652004-07-12 14:00:46 +00003088 IRTemp td = newTemp(Ity_I32); /* EDI */
3089 IRTemp ts = newTemp(Ity_I32); /* ESI */
3090
sewardj64e1d652004-07-12 14:00:46 +00003091 assign( td, getIReg(4, R_EDI) );
sewardj64e1d652004-07-12 14:00:46 +00003092 assign( ts, getIReg(4, R_ESI) );
3093
sewardj64e1d652004-07-12 14:00:46 +00003094 assign( tdv, loadLE(ty,mkexpr(td)) );
sewardjb9c5cf62004-08-24 15:10:38 +00003095 assign( tsv, loadLE(ty,mkexpr(ts)) );
sewardj64e1d652004-07-12 14:00:46 +00003096
sewardj2a2ba8b2004-11-08 13:14:06 +00003097 setFlags_DEP1_DEP2 ( Iop_Sub8, tsv, tdv, ty );
sewardj64e1d652004-07-12 14:00:46 +00003098
sewardj64e1d652004-07-12 14:00:46 +00003099 putIReg(4, R_EDI, binop(Iop_Add32, mkexpr(td), mkexpr(t_inc)) );
sewardj64e1d652004-07-12 14:00:46 +00003100 putIReg(4, R_ESI, binop(Iop_Add32, mkexpr(ts), mkexpr(t_inc)) );
3101}
3102
sewardj64e1d652004-07-12 14:00:46 +00003103static
3104void dis_SCAS ( Int sz, IRTemp t_inc )
3105{
3106 IRType ty = szToITy(sz);
sewardj82292882004-07-27 00:15:59 +00003107 IRTemp ta = newTemp(ty); /* EAX */
sewardj64e1d652004-07-12 14:00:46 +00003108 IRTemp td = newTemp(Ity_I32); /* EDI */
3109 IRTemp tdv = newTemp(ty); /* (EDI) */
3110
sewardjb9c5cf62004-08-24 15:10:38 +00003111 assign( ta, getIReg(sz, R_EAX) );
sewardj64e1d652004-07-12 14:00:46 +00003112 assign( td, getIReg(4, R_EDI) );
3113
sewardj64e1d652004-07-12 14:00:46 +00003114 assign( tdv, loadLE(ty,mkexpr(td)) );
sewardj2a2ba8b2004-11-08 13:14:06 +00003115 setFlags_DEP1_DEP2 ( Iop_Sub8, ta, tdv, ty );
sewardj64e1d652004-07-12 14:00:46 +00003116
sewardj64e1d652004-07-12 14:00:46 +00003117 putIReg(4, R_EDI, binop(Iop_Add32, mkexpr(td), mkexpr(t_inc)) );
3118}
sewardj82292882004-07-27 00:15:59 +00003119
sewardj64e1d652004-07-12 14:00:46 +00003120
3121/* Wrap the appropriate string op inside a REP/REPE/REPNE.
3122 We assume the insn is the last one in the basic block, and so emit a jump
3123 to the next insn, rather than just falling through. */
3124static
sewardj2a9ad022004-11-25 02:46:58 +00003125void dis_REP_op ( X86Condcode cond,
sewardj64e1d652004-07-12 14:00:46 +00003126 void (*dis_OP)(Int, IRTemp),
sewardj2d49b432005-02-01 00:37:06 +00003127 Int sz, Addr32 eip, Addr32 eip_next, HChar* name )
sewardj64e1d652004-07-12 14:00:46 +00003128{
3129 IRTemp t_inc = newTemp(Ity_I32);
3130 IRTemp tc = newTemp(Ity_I32); /* ECX */
3131
sewardj64e1d652004-07-12 14:00:46 +00003132 assign( tc, getIReg(4,R_ECX) );
3133
sewardj64e1d652004-07-12 14:00:46 +00003134 stmt( IRStmt_Exit( binop(Iop_CmpEQ32,mkexpr(tc),mkU32(0)),
sewardj893aada2004-11-29 19:57:54 +00003135 Ijk_Boring,
sewardj64e1d652004-07-12 14:00:46 +00003136 IRConst_U32(eip_next) ) );
3137
sewardj64e1d652004-07-12 14:00:46 +00003138 putIReg(4, R_ECX, binop(Iop_Sub32, mkexpr(tc), mkU32(1)) );
3139
3140 dis_string_op_increment(sz, t_inc);
3141 dis_OP (sz, t_inc);
3142
sewardj2a9ad022004-11-25 02:46:58 +00003143 if (cond == X86CondAlways) {
sewardj78c19df2004-07-12 22:49:27 +00003144 jmp_lit(Ijk_Boring,eip);
sewardj64e1d652004-07-12 14:00:46 +00003145 } else {
sewardj2a9ad022004-11-25 02:46:58 +00003146 stmt( IRStmt_Exit( mk_x86g_calculate_condition(cond),
sewardj893aada2004-11-29 19:57:54 +00003147 Ijk_Boring,
sewardj5bd4d162004-11-10 13:02:48 +00003148 IRConst_U32(eip) ) );
sewardj78c19df2004-07-12 22:49:27 +00003149 jmp_lit(Ijk_Boring,eip_next);
sewardj64e1d652004-07-12 14:00:46 +00003150 }
3151 DIP("%s%c\n", name, nameISize(sz));
3152}
3153
sewardj464efa42004-11-19 22:17:29 +00003154
sewardj64e1d652004-07-12 14:00:46 +00003155/*------------------------------------------------------------*/
3156/*--- Arithmetic, etc. ---*/
3157/*------------------------------------------------------------*/
3158
sewardj2a2ba8b2004-11-08 13:14:06 +00003159/* IMUL E, G. Supplied eip points to the modR/M byte. */
sewardjcf780b42004-07-13 18:42:17 +00003160static
3161UInt dis_mul_E_G ( UChar sorb,
3162 Int size,
sewardj2a2ba8b2004-11-08 13:14:06 +00003163 UInt delta0 )
sewardjcf780b42004-07-13 18:42:17 +00003164{
sewardj71a65362004-07-28 01:48:34 +00003165 Int alen;
sewardjc9a43662004-11-30 18:51:59 +00003166 HChar dis_buf[50];
sewardjcf780b42004-07-13 18:42:17 +00003167 UChar rm = getIByte(delta0);
3168 IRType ty = szToITy(size);
sewardj6d2638e2004-07-15 09:38:27 +00003169 IRTemp te = newTemp(ty);
3170 IRTemp tg = newTemp(ty);
sewardj948d48b2004-11-05 19:49:09 +00003171 IRTemp resLo = newTemp(ty);
sewardj71a65362004-07-28 01:48:34 +00003172
sewardj948d48b2004-11-05 19:49:09 +00003173 assign( tg, getIReg(size, gregOfRM(rm)) );
sewardjcf780b42004-07-13 18:42:17 +00003174 if (epartIsReg(rm)) {
sewardjcf780b42004-07-13 18:42:17 +00003175 assign( te, getIReg(size, eregOfRM(rm)) );
sewardj948d48b2004-11-05 19:49:09 +00003176 } else {
3177 IRTemp addr = disAMode( &alen, sorb, delta0, dis_buf );
3178 assign( te, loadLE(ty,mkexpr(addr)) );
3179 }
sewardjcf780b42004-07-13 18:42:17 +00003180
sewardj2a9ad022004-11-25 02:46:58 +00003181 setFlags_MUL ( ty, te, tg, X86G_CC_OP_SMULB );
sewardj948d48b2004-11-05 19:49:09 +00003182
sewardj2a2ba8b2004-11-08 13:14:06 +00003183 assign( resLo, binop( mkSizedOp(ty, Iop_Mul8), mkexpr(te), mkexpr(tg) ) );
sewardj948d48b2004-11-05 19:49:09 +00003184
3185 putIReg(size, gregOfRM(rm), mkexpr(resLo) );
3186
3187 if (epartIsReg(rm)) {
sewardj2a2ba8b2004-11-08 13:14:06 +00003188 DIP("imul%c %s, %s\n", nameISize(size),
3189 nameIReg(size,eregOfRM(rm)),
3190 nameIReg(size,gregOfRM(rm)));
sewardjcf780b42004-07-13 18:42:17 +00003191 return 1+delta0;
3192 } else {
sewardj2a2ba8b2004-11-08 13:14:06 +00003193 DIP("imul%c %s, %s\n", nameISize(size),
3194 dis_buf, nameIReg(size,gregOfRM(rm)));
sewardj71a65362004-07-28 01:48:34 +00003195 return alen+delta0;
sewardjcf780b42004-07-13 18:42:17 +00003196 }
3197}
3198
3199
sewardj1813dbe2004-07-28 17:09:04 +00003200/* IMUL I * E -> G. Supplied eip points to the modR/M byte. */
3201static
3202UInt dis_imul_I_E_G ( UChar sorb,
3203 Int size,
3204 UInt delta,
3205 Int litsize )
3206{
sewardj883b00b2004-09-11 09:30:24 +00003207 Int d32, alen;
sewardjc9a43662004-11-30 18:51:59 +00003208 HChar dis_buf[50];
sewardjb81f8b32004-07-30 10:17:50 +00003209 UChar rm = getIByte(delta);
sewardj1813dbe2004-07-28 17:09:04 +00003210 IRType ty = szToITy(size);
3211 IRTemp te = newTemp(ty);
3212 IRTemp tl = newTemp(ty);
sewardj948d48b2004-11-05 19:49:09 +00003213 IRTemp resLo = newTemp(ty);
sewardj1813dbe2004-07-28 17:09:04 +00003214
sewardjb81f8b32004-07-30 10:17:50 +00003215 vassert(size == 1 || size == 2 || size == 4);
3216
sewardj1813dbe2004-07-28 17:09:04 +00003217 if (epartIsReg(rm)) {
3218 assign(te, getIReg(size, eregOfRM(rm)));
3219 delta++;
3220 } else {
sewardj883b00b2004-09-11 09:30:24 +00003221 IRTemp addr = disAMode( &alen, sorb, delta, dis_buf );
3222 assign(te, loadLE(ty, mkexpr(addr)));
3223 delta += alen;
sewardj1813dbe2004-07-28 17:09:04 +00003224 }
3225 d32 = getSDisp(litsize,delta);
3226 delta += litsize;
3227
sewardjb81f8b32004-07-30 10:17:50 +00003228 if (size == 1) d32 &= 0xFF;
3229 if (size == 2) d32 &= 0xFFFF;
3230
sewardj1813dbe2004-07-28 17:09:04 +00003231 assign(tl, mkU(ty,d32));
sewardj948d48b2004-11-05 19:49:09 +00003232
sewardj2a2ba8b2004-11-08 13:14:06 +00003233 assign( resLo, binop( mkSizedOp(ty, Iop_Mul8), mkexpr(te), mkexpr(tl) ));
sewardj948d48b2004-11-05 19:49:09 +00003234
sewardj2a9ad022004-11-25 02:46:58 +00003235 setFlags_MUL ( ty, te, tl, X86G_CC_OP_SMULB );
sewardj948d48b2004-11-05 19:49:09 +00003236
3237 putIReg(size, gregOfRM(rm), mkexpr(resLo));
sewardj1813dbe2004-07-28 17:09:04 +00003238
3239 DIP("imul %d, %s, %s\n", d32,
3240 ( epartIsReg(rm) ? nameIReg(size,eregOfRM(rm)) : dis_buf ),
3241 nameIReg(size,gregOfRM(rm)) );
3242 return delta;
sewardj948d48b2004-11-05 19:49:09 +00003243}
sewardj1813dbe2004-07-28 17:09:04 +00003244
3245
sewardjd1725d12004-08-12 20:46:53 +00003246/*------------------------------------------------------------*/
sewardj464efa42004-11-19 22:17:29 +00003247/*--- ---*/
3248/*--- x87 FLOATING POINT INSTRUCTIONS ---*/
3249/*--- ---*/
sewardjd1725d12004-08-12 20:46:53 +00003250/*------------------------------------------------------------*/
3251
sewardj207557a2004-08-27 12:00:18 +00003252/* --- Helper functions for dealing with the register stack. --- */
3253
sewardj893aada2004-11-29 19:57:54 +00003254/* --- Set the emulation-warning pseudo-register. --- */
3255
3256static void put_emwarn ( IRExpr* e /* :: Ity_I32 */ )
3257{
sewardj86ed7622005-03-27 02:20:56 +00003258 vassert(typeOfIRExpr(irbb->tyenv, e) == Ity_I32);
sewardj893aada2004-11-29 19:57:54 +00003259 stmt( IRStmt_Put( OFFB_EMWARN, e ) );
3260}
3261
sewardj17442fe2004-09-20 14:54:28 +00003262/* --- Produce an IRExpr* denoting a 64-bit QNaN. --- */
sewardj207557a2004-08-27 12:00:18 +00003263
sewardj17442fe2004-09-20 14:54:28 +00003264static IRExpr* mkQNaN64 ( void )
sewardj207557a2004-08-27 12:00:18 +00003265{
sewardj17442fe2004-09-20 14:54:28 +00003266 /* QNaN is 0 2047 1 0(51times)
3267 == 0b 11111111111b 1 0(51times)
3268 == 0x7FF8 0000 0000 0000
3269 */
3270 return IRExpr_Const(IRConst_F64i(0x7FF8000000000000ULL));
sewardj207557a2004-08-27 12:00:18 +00003271}
3272
sewardj893aada2004-11-29 19:57:54 +00003273/* --------- Get/put the top-of-stack pointer. --------- */
sewardjd1725d12004-08-12 20:46:53 +00003274
3275static IRExpr* get_ftop ( void )
3276{
3277 return IRExpr_Get( OFFB_FTOP, Ity_I32 );
3278}
3279
sewardj207557a2004-08-27 12:00:18 +00003280static void put_ftop ( IRExpr* e )
sewardjd1725d12004-08-12 20:46:53 +00003281{
sewardj86ed7622005-03-27 02:20:56 +00003282 vassert(typeOfIRExpr(irbb->tyenv, e) == Ity_I32);
sewardj207557a2004-08-27 12:00:18 +00003283 stmt( IRStmt_Put( OFFB_FTOP, e ) );
sewardjd1725d12004-08-12 20:46:53 +00003284}
3285
sewardj893aada2004-11-29 19:57:54 +00003286/* --------- Get/put the C3210 bits. --------- */
sewardjbdc7d212004-09-09 02:46:40 +00003287
sewardjc4be80c2004-09-10 16:17:45 +00003288static IRExpr* get_C3210 ( void )
sewardjbdc7d212004-09-09 02:46:40 +00003289{
sewardjc4be80c2004-09-10 16:17:45 +00003290 return IRExpr_Get( OFFB_FC3210, Ity_I32 );
sewardjbdc7d212004-09-09 02:46:40 +00003291}
3292
sewardjc4be80c2004-09-10 16:17:45 +00003293static void put_C3210 ( IRExpr* e )
sewardjbdc7d212004-09-09 02:46:40 +00003294{
sewardjc4be80c2004-09-10 16:17:45 +00003295 stmt( IRStmt_Put( OFFB_FC3210, e ) );
sewardjbdc7d212004-09-09 02:46:40 +00003296}
sewardjd1725d12004-08-12 20:46:53 +00003297
sewardj893aada2004-11-29 19:57:54 +00003298/* --------- Get/put the FPU rounding mode. --------- */
sewardjd01a9632004-11-30 13:18:37 +00003299static IRExpr* /* :: Ity_I32 */ get_fpround ( void )
sewardj8f3debf2004-09-08 23:42:23 +00003300{
sewardjd01a9632004-11-30 13:18:37 +00003301 return IRExpr_Get( OFFB_FPROUND, Ity_I32 );
sewardj8f3debf2004-09-08 23:42:23 +00003302}
3303
sewardjd01a9632004-11-30 13:18:37 +00003304static void put_fpround ( IRExpr* /* :: Ity_I32 */ e )
sewardj8f3debf2004-09-08 23:42:23 +00003305{
sewardjd01a9632004-11-30 13:18:37 +00003306 stmt( IRStmt_Put( OFFB_FPROUND, e ) );
sewardj8f3debf2004-09-08 23:42:23 +00003307}
3308
3309
sewardj893aada2004-11-29 19:57:54 +00003310/* --------- Synthesise a 2-bit FPU rounding mode. --------- */
sewardj8f3debf2004-09-08 23:42:23 +00003311/* Produces a value in 0 .. 3, which is encoded as per the type
sewardjd01a9632004-11-30 13:18:37 +00003312 IRRoundingMode. Since the guest_FPROUND value is also encoded as
3313 per IRRoundingMode, we merely need to get it and mask it for
3314 safety.
sewardj8f3debf2004-09-08 23:42:23 +00003315*/
3316static IRExpr* /* :: Ity_I32 */ get_roundingmode ( void )
3317{
sewardjd01a9632004-11-30 13:18:37 +00003318 return binop( Iop_And32, get_fpround(), mkU32(3) );
sewardj8f3debf2004-09-08 23:42:23 +00003319}
3320
3321
sewardj207557a2004-08-27 12:00:18 +00003322/* --------- Get/set FP register tag bytes. --------- */
3323
sewardj207557a2004-08-27 12:00:18 +00003324/* Given i, and some expression e, generate 'ST_TAG(i) = e'. */
3325
3326static void put_ST_TAG ( Int i, IRExpr* value )
3327{
sewardj2d3f77c2004-09-22 23:49:09 +00003328 IRArray* descr;
sewardj207557a2004-08-27 12:00:18 +00003329 vassert(typeOfIRExpr(irbb->tyenv, value) == Ity_I8);
sewardjf6dc3ce2004-10-19 01:03:46 +00003330 descr = mkIRArray( OFFB_FPTAGS, Ity_I8, 8 );
sewardj2d3f77c2004-09-22 23:49:09 +00003331 stmt( IRStmt_PutI( descr, get_ftop(), i, value ) );
sewardj207557a2004-08-27 12:00:18 +00003332}
3333
3334/* Given i, generate an expression yielding 'ST_TAG(i)'. This will be
sewardjdb199622004-09-06 23:19:03 +00003335 zero to indicate "Empty" and nonzero to indicate "NonEmpty". */
sewardj207557a2004-08-27 12:00:18 +00003336
3337static IRExpr* get_ST_TAG ( Int i )
3338{
sewardjf6dc3ce2004-10-19 01:03:46 +00003339 IRArray* descr = mkIRArray( OFFB_FPTAGS, Ity_I8, 8 );
sewardj2d3f77c2004-09-22 23:49:09 +00003340 return IRExpr_GetI( descr, get_ftop(), i );
sewardj207557a2004-08-27 12:00:18 +00003341}
3342
3343
3344/* --------- Get/set FP registers. --------- */
3345
sewardj2d3f77c2004-09-22 23:49:09 +00003346/* Given i, and some expression e, emit 'ST(i) = e' and set the
3347 register's tag to indicate the register is full. The previous
3348 state of the register is not checked. */
sewardj207557a2004-08-27 12:00:18 +00003349
3350static void put_ST_UNCHECKED ( Int i, IRExpr* value )
sewardjd1725d12004-08-12 20:46:53 +00003351{
sewardj2d3f77c2004-09-22 23:49:09 +00003352 IRArray* descr;
sewardjdb199622004-09-06 23:19:03 +00003353 vassert(typeOfIRExpr(irbb->tyenv, value) == Ity_F64);
sewardjf6dc3ce2004-10-19 01:03:46 +00003354 descr = mkIRArray( OFFB_FPREGS, Ity_F64, 8 );
sewardj2d3f77c2004-09-22 23:49:09 +00003355 stmt( IRStmt_PutI( descr, get_ftop(), i, value ) );
sewardj207557a2004-08-27 12:00:18 +00003356 /* Mark the register as in-use. */
3357 put_ST_TAG(i, mkU8(1));
sewardjd1725d12004-08-12 20:46:53 +00003358}
3359
sewardj207557a2004-08-27 12:00:18 +00003360/* Given i, and some expression e, emit
3361 ST(i) = is_full(i) ? NaN : e
3362 and set the tag accordingly.
3363*/
3364
3365static void put_ST ( Int i, IRExpr* value )
3366{
3367 put_ST_UNCHECKED( i,
sewardjdb199622004-09-06 23:19:03 +00003368 IRExpr_Mux0X( get_ST_TAG(i),
3369 /* 0 means empty */
3370 value,
3371 /* non-0 means full */
sewardj17442fe2004-09-20 14:54:28 +00003372 mkQNaN64()
sewardj207557a2004-08-27 12:00:18 +00003373 )
3374 );
3375}
3376
3377
sewardjd1725d12004-08-12 20:46:53 +00003378/* Given i, generate an expression yielding 'ST(i)'. */
3379
sewardj207557a2004-08-27 12:00:18 +00003380static IRExpr* get_ST_UNCHECKED ( Int i )
sewardjd1725d12004-08-12 20:46:53 +00003381{
sewardjf6dc3ce2004-10-19 01:03:46 +00003382 IRArray* descr = mkIRArray( OFFB_FPREGS, Ity_F64, 8 );
sewardj2d3f77c2004-09-22 23:49:09 +00003383 return IRExpr_GetI( descr, get_ftop(), i );
sewardjd1725d12004-08-12 20:46:53 +00003384}
3385
sewardjc4be80c2004-09-10 16:17:45 +00003386
sewardj207557a2004-08-27 12:00:18 +00003387/* Given i, generate an expression yielding
3388 is_full(i) ? ST(i) : NaN
3389*/
3390
3391static IRExpr* get_ST ( Int i )
3392{
3393 return
3394 IRExpr_Mux0X( get_ST_TAG(i),
3395 /* 0 means empty */
sewardj17442fe2004-09-20 14:54:28 +00003396 mkQNaN64(),
sewardj207557a2004-08-27 12:00:18 +00003397 /* non-0 means full */
3398 get_ST_UNCHECKED(i));
3399}
3400
3401
sewardjd1725d12004-08-12 20:46:53 +00003402/* Adjust FTOP downwards by one register. */
3403
sewardj207557a2004-08-27 12:00:18 +00003404static void fp_push ( void )
sewardjd1725d12004-08-12 20:46:53 +00003405{
sewardj2d3f77c2004-09-22 23:49:09 +00003406 put_ftop( binop(Iop_Sub32, get_ftop(), mkU32(1)) );
sewardjd1725d12004-08-12 20:46:53 +00003407}
3408
sewardj207557a2004-08-27 12:00:18 +00003409/* Adjust FTOP upwards by one register, and mark the vacated register
3410 as empty. */
sewardja58ea662004-08-15 03:12:41 +00003411
sewardj207557a2004-08-27 12:00:18 +00003412static void fp_pop ( void )
sewardja58ea662004-08-15 03:12:41 +00003413{
sewardjdb199622004-09-06 23:19:03 +00003414 put_ST_TAG(0, mkU8(0));
sewardj2d3f77c2004-09-22 23:49:09 +00003415 put_ftop( binop(Iop_Add32, get_ftop(), mkU32(1)) );
sewardja58ea662004-08-15 03:12:41 +00003416}
3417
sewardj3f61ddb2004-10-16 20:51:05 +00003418/* Clear the C2 bit of the FPU status register, for
3419 sin/cos/tan/sincos. */
3420
3421static void clear_C2 ( void )
3422{
sewardj67e002d2004-12-02 18:16:33 +00003423 put_C3210( binop(Iop_And32, get_C3210(), mkU32(~X86G_FC_MASK_C2)) );
sewardj3f61ddb2004-10-16 20:51:05 +00003424}
3425
sewardjd24931d2005-03-20 12:51:39 +00003426/* Invent a plausible-looking FPU status word value:
3427 ((ftop & 7) << 11) | (c3210 & 0x4700)
3428 */
3429static IRExpr* get_FPU_sw ( void )
3430{
3431 return
3432 unop(Iop_32to16,
3433 binop(Iop_Or32,
3434 binop(Iop_Shl32,
3435 binop(Iop_And32, get_ftop(), mkU32(7)),
3436 mkU8(11)),
3437 binop(Iop_And32, get_C3210(), mkU32(0x4700))
3438 ));
3439}
3440
sewardj3f61ddb2004-10-16 20:51:05 +00003441
sewardj207557a2004-08-27 12:00:18 +00003442/* ------------------------------------------------------- */
3443/* Given all that stack-mangling junk, we can now go ahead
3444 and describe FP instructions.
3445*/
3446
sewardj3fd5e572004-09-09 22:43:51 +00003447/* ST(0) = ST(0) `op` mem64/32(addr)
sewardj207557a2004-08-27 12:00:18 +00003448 Need to check ST(0)'s tag on read, but not on write.
3449*/
sewardja58ea662004-08-15 03:12:41 +00003450static
sewardj2d49b432005-02-01 00:37:06 +00003451void fp_do_op_mem_ST_0 ( IRTemp addr, HChar* op_txt, HChar* dis_buf,
sewardja58ea662004-08-15 03:12:41 +00003452 IROp op, Bool dbl )
3453{
sewardj33dd31b2005-01-08 18:17:32 +00003454 DIP("f%s%c %s\n", op_txt, dbl?'l':'s', dis_buf);
sewardja58ea662004-08-15 03:12:41 +00003455 if (dbl) {
sewardj3fd5e572004-09-09 22:43:51 +00003456 put_ST_UNCHECKED(0,
3457 binop( op,
3458 get_ST(0),
3459 loadLE(Ity_F64,mkexpr(addr))
3460 ));
sewardja58ea662004-08-15 03:12:41 +00003461 } else {
sewardj3fd5e572004-09-09 22:43:51 +00003462 put_ST_UNCHECKED(0,
3463 binop( op,
3464 get_ST(0),
3465 unop(Iop_F32toF64, loadLE(Ity_F32,mkexpr(addr)))
3466 ));
3467 }
3468}
3469
3470
3471/* ST(0) = mem64/32(addr) `op` ST(0)
3472 Need to check ST(0)'s tag on read, but not on write.
3473*/
3474static
sewardj2d49b432005-02-01 00:37:06 +00003475void fp_do_oprev_mem_ST_0 ( IRTemp addr, HChar* op_txt, HChar* dis_buf,
sewardj883b00b2004-09-11 09:30:24 +00003476 IROp op, Bool dbl )
sewardj3fd5e572004-09-09 22:43:51 +00003477{
sewardj33dd31b2005-01-08 18:17:32 +00003478 DIP("f%s%c %s\n", op_txt, dbl?'l':'s', dis_buf);
sewardj3fd5e572004-09-09 22:43:51 +00003479 if (dbl) {
3480 put_ST_UNCHECKED(0,
3481 binop( op,
3482 loadLE(Ity_F64,mkexpr(addr)),
3483 get_ST(0)
3484 ));
3485 } else {
3486 put_ST_UNCHECKED(0,
3487 binop( op,
3488 unop(Iop_F32toF64, loadLE(Ity_F32,mkexpr(addr))),
3489 get_ST(0)
3490 ));
sewardja58ea662004-08-15 03:12:41 +00003491 }
3492}
3493
sewardjd1725d12004-08-12 20:46:53 +00003494
sewardjdb199622004-09-06 23:19:03 +00003495/* ST(dst) = ST(dst) `op` ST(src).
3496 Check dst and src tags when reading but not on write.
3497*/
3498static
sewardj2d49b432005-02-01 00:37:06 +00003499void fp_do_op_ST_ST ( HChar* op_txt, IROp op, UInt st_src, UInt st_dst,
sewardjbdc7d212004-09-09 02:46:40 +00003500 Bool pop_after )
sewardjdb199622004-09-06 23:19:03 +00003501{
sewardj2d49b432005-02-01 00:37:06 +00003502 DIP("f%s%s st(%d), st(%d)\n", op_txt, pop_after?"p":"",
3503 (Int)st_src, (Int)st_dst );
sewardjdb199622004-09-06 23:19:03 +00003504 put_ST_UNCHECKED(
3505 st_dst,
3506 binop(op, get_ST(st_dst), get_ST(st_src) )
3507 );
sewardjbdc7d212004-09-09 02:46:40 +00003508 if (pop_after)
3509 fp_pop();
3510}
3511
3512/* ST(dst) = ST(src) `op` ST(dst).
3513 Check dst and src tags when reading but not on write.
3514*/
3515static
sewardj2d49b432005-02-01 00:37:06 +00003516void fp_do_oprev_ST_ST ( HChar* op_txt, IROp op, UInt st_src, UInt st_dst,
sewardj883b00b2004-09-11 09:30:24 +00003517 Bool pop_after )
sewardjbdc7d212004-09-09 02:46:40 +00003518{
sewardj2d49b432005-02-01 00:37:06 +00003519 DIP("f%s%s st(%d), st(%d)\n", op_txt, pop_after?"p":"",
3520 (Int)st_src, (Int)st_dst );
sewardjbdc7d212004-09-09 02:46:40 +00003521 put_ST_UNCHECKED(
3522 st_dst,
3523 binop(op, get_ST(st_src), get_ST(st_dst) )
3524 );
3525 if (pop_after)
3526 fp_pop();
sewardjdb199622004-09-06 23:19:03 +00003527}
3528
sewardj8308aad2004-09-12 11:09:54 +00003529/* %eflags(Z,P,C) = UCOMI( st(0), st(i) ) */
3530static void fp_do_ucomi_ST0_STi ( UInt i, Bool pop_after )
3531{
sewardj2d49b432005-02-01 00:37:06 +00003532 DIP("fucomi%s %%st(0),%%st(%d)\n", pop_after ? "p" : "", (Int)i );
sewardj8308aad2004-09-12 11:09:54 +00003533 /* This is a bit of a hack (and isn't really right). It sets
3534 Z,P,C,O correctly, but forces A and S to zero, whereas the Intel
3535 documentation implies A and S are unchanged.
3536 */
sewardjfeeb8a82004-11-30 12:30:11 +00003537 /* It's also fishy in that it is used both for COMIP and
3538 UCOMIP, and they aren't the same (although similar). */
sewardj2a9ad022004-11-25 02:46:58 +00003539 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
sewardj2a2ba8b2004-11-08 13:14:06 +00003540 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
3541 stmt( IRStmt_Put( OFFB_CC_DEP1,
sewardj8308aad2004-09-12 11:09:54 +00003542 binop( Iop_And32,
3543 binop(Iop_CmpF64, get_ST(0), get_ST(i)),
3544 mkU32(0x45)
3545 )));
sewardja3b7e3a2005-04-05 01:54:19 +00003546 /* Set NDEP even though it isn't used. This makes redundant-PUT
3547 elimination of previous stores to this field work better. */
3548 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardj8308aad2004-09-12 11:09:54 +00003549 if (pop_after)
3550 fp_pop();
3551}
3552
sewardjdb199622004-09-06 23:19:03 +00003553
sewardjd1725d12004-08-12 20:46:53 +00003554static
3555UInt dis_FPU ( Bool* decode_ok, UChar sorb, UInt delta )
3556{
sewardja58ea662004-08-15 03:12:41 +00003557 Int len;
3558 UInt r_src, r_dst;
sewardjc9a43662004-11-30 18:51:59 +00003559 HChar dis_buf[50];
sewardj89cd0932004-09-08 18:23:25 +00003560 IRTemp t1, t2;
sewardjd1725d12004-08-12 20:46:53 +00003561
3562 /* On entry, delta points at the second byte of the insn (the modrm
3563 byte).*/
3564 UChar first_opcode = getIByte(delta-1);
3565 UChar modrm = getIByte(delta+0);
3566
3567 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xD8 opcodes +-+-+-+-+-+-+-+ */
3568
3569 if (first_opcode == 0xD8) {
sewardjdb199622004-09-06 23:19:03 +00003570 if (modrm < 0xC0) {
sewardj89cd0932004-09-08 18:23:25 +00003571
3572 /* bits 5,4,3 are an opcode extension, and the modRM also
3573 specifies an address. */
3574 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
3575 delta += len;
3576
3577 switch (gregOfRM(modrm)) {
3578
sewardj3fd5e572004-09-09 22:43:51 +00003579 case 0: /* FADD single-real */
3580 fp_do_op_mem_ST_0 ( addr, "add", dis_buf, Iop_AddF64, False );
3581 break;
3582
sewardj89cd0932004-09-08 18:23:25 +00003583 case 1: /* FMUL single-real */
3584 fp_do_op_mem_ST_0 ( addr, "mul", dis_buf, Iop_MulF64, False );
3585 break;
3586
sewardj7ca37d92004-10-25 02:58:30 +00003587 case 2: /* FCOM single-real */
3588 DIP("fcoms %s\n", dis_buf);
3589 /* This forces C1 to zero, which isn't right. */
3590 put_C3210(
3591 binop( Iop_And32,
3592 binop(Iop_Shl32,
3593 binop(Iop_CmpF64,
3594 get_ST(0),
3595 unop(Iop_F32toF64,
3596 loadLE(Ity_F32,mkexpr(addr)))),
3597 mkU8(8)),
3598 mkU32(0x4500)
3599 ));
3600 break;
3601
3602 case 3: /* FCOMP single-real */
sewardje166ed02004-10-25 02:27:01 +00003603 DIP("fcomps %s\n", dis_buf);
3604 /* This forces C1 to zero, which isn't right. */
3605 put_C3210(
3606 binop( Iop_And32,
3607 binop(Iop_Shl32,
3608 binop(Iop_CmpF64,
3609 get_ST(0),
3610 unop(Iop_F32toF64,
3611 loadLE(Ity_F32,mkexpr(addr)))),
3612 mkU8(8)),
3613 mkU32(0x4500)
3614 ));
3615 fp_pop();
3616 break;
3617
sewardj588ea762004-09-10 18:56:32 +00003618 case 4: /* FSUB single-real */
3619 fp_do_op_mem_ST_0 ( addr, "sub", dis_buf, Iop_SubF64, False );
3620 break;
3621
3622 case 5: /* FSUBR single-real */
3623 fp_do_oprev_mem_ST_0 ( addr, "subr", dis_buf, Iop_SubF64, False );
3624 break;
3625
sewardjbdc7d212004-09-09 02:46:40 +00003626 case 6: /* FDIV single-real */
3627 fp_do_op_mem_ST_0 ( addr, "div", dis_buf, Iop_DivF64, False );
3628 break;
3629
sewardj8308aad2004-09-12 11:09:54 +00003630 case 7: /* FDIVR single-real */
3631 fp_do_oprev_mem_ST_0 ( addr, "divr", dis_buf, Iop_DivF64, False );
3632 break;
3633
sewardj89cd0932004-09-08 18:23:25 +00003634 default:
3635 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
3636 vex_printf("first_opcode == 0xD8\n");
3637 goto decode_fail;
3638 }
sewardjdb199622004-09-06 23:19:03 +00003639 } else {
3640 delta++;
3641 switch (modrm) {
sewardj89cd0932004-09-08 18:23:25 +00003642
sewardjdb199622004-09-06 23:19:03 +00003643 case 0xC0 ... 0xC7: /* FADD %st(?),%st(0) */
sewardjbdc7d212004-09-09 02:46:40 +00003644 fp_do_op_ST_ST ( "add", Iop_AddF64, modrm - 0xC0, 0, False );
sewardjdb199622004-09-06 23:19:03 +00003645 break;
sewardj89cd0932004-09-08 18:23:25 +00003646
sewardj3fd5e572004-09-09 22:43:51 +00003647 case 0xC8 ... 0xCF: /* FMUL %st(?),%st(0) */
3648 fp_do_op_ST_ST ( "mul", Iop_MulF64, modrm - 0xC8, 0, False );
3649 break;
3650
sewardje166ed02004-10-25 02:27:01 +00003651 /* Dunno if this is right */
3652 case 0xD0 ... 0xD7: /* FCOM %st(?),%st(0) */
3653 r_dst = (UInt)modrm - 0xD0;
sewardj2d49b432005-02-01 00:37:06 +00003654 DIP("fcom %%st(0),%%st(%d)\n", (Int)r_dst);
sewardje166ed02004-10-25 02:27:01 +00003655 /* This forces C1 to zero, which isn't right. */
3656 put_C3210(
3657 binop( Iop_And32,
3658 binop(Iop_Shl32,
3659 binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
3660 mkU8(8)),
3661 mkU32(0x4500)
3662 ));
3663 break;
sewardj2d49b432005-02-01 00:37:06 +00003664
sewardj98169c52004-10-24 13:11:39 +00003665 /* Dunno if this is right */
3666 case 0xD8 ... 0xDF: /* FCOMP %st(?),%st(0) */
3667 r_dst = (UInt)modrm - 0xD8;
sewardj2d49b432005-02-01 00:37:06 +00003668 DIP("fcomp %%st(0),%%st(%d)\n", (Int)r_dst);
sewardj98169c52004-10-24 13:11:39 +00003669 /* This forces C1 to zero, which isn't right. */
3670 put_C3210(
3671 binop( Iop_And32,
3672 binop(Iop_Shl32,
3673 binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
3674 mkU8(8)),
3675 mkU32(0x4500)
3676 ));
3677 fp_pop();
3678 break;
sewardj2d49b432005-02-01 00:37:06 +00003679
sewardj89cd0932004-09-08 18:23:25 +00003680 case 0xE0 ... 0xE7: /* FSUB %st(?),%st(0) */
sewardjbdc7d212004-09-09 02:46:40 +00003681 fp_do_op_ST_ST ( "sub", Iop_SubF64, modrm - 0xE0, 0, False );
sewardj89cd0932004-09-08 18:23:25 +00003682 break;
3683
sewardj8308aad2004-09-12 11:09:54 +00003684 case 0xE8 ... 0xEF: /* FSUBR %st(?),%st(0) */
3685 fp_do_oprev_ST_ST ( "subr", Iop_SubF64, modrm - 0xE8, 0, False );
3686 break;
3687
sewardj3fd5e572004-09-09 22:43:51 +00003688 case 0xF0 ... 0xF7: /* FDIV %st(?),%st(0) */
3689 fp_do_op_ST_ST ( "div", Iop_DivF64, modrm - 0xF0, 0, False );
3690 break;
3691
3692 case 0xF8 ... 0xFF: /* FDIVR %st(?),%st(0) */
3693 fp_do_oprev_ST_ST ( "divr", Iop_DivF64, modrm - 0xF8, 0, False );
3694 break;
3695
sewardjdb199622004-09-06 23:19:03 +00003696 default:
3697 goto decode_fail;
3698 }
3699 }
sewardjd1725d12004-08-12 20:46:53 +00003700 }
3701
3702 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xD9 opcodes +-+-+-+-+-+-+-+ */
3703 else
3704 if (first_opcode == 0xD9) {
sewardjbb53f8c2004-08-14 11:50:01 +00003705 if (modrm < 0xC0) {
sewardj89cd0932004-09-08 18:23:25 +00003706
3707 /* bits 5,4,3 are an opcode extension, and the modRM also
sewardjfeeb8a82004-11-30 12:30:11 +00003708 specifies an address. */
sewardj89cd0932004-09-08 18:23:25 +00003709 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
3710 delta += len;
3711
3712 switch (gregOfRM(modrm)) {
3713
3714 case 0: /* FLD single-real */
sewardj33dd31b2005-01-08 18:17:32 +00003715 DIP("flds %s\n", dis_buf);
sewardj89cd0932004-09-08 18:23:25 +00003716 fp_push();
3717 put_ST(0, unop(Iop_F32toF64,
sewardj8f3debf2004-09-08 23:42:23 +00003718 loadLE(Ity_F32, mkexpr(addr))));
sewardj89cd0932004-09-08 18:23:25 +00003719 break;
3720
sewardj588ea762004-09-10 18:56:32 +00003721 case 2: /* FST single-real */
sewardj33dd31b2005-01-08 18:17:32 +00003722 DIP("fsts %s\n", dis_buf);
sewardj3bca9062004-12-04 14:36:09 +00003723 storeLE(mkexpr(addr),
3724 binop(Iop_F64toF32, get_roundingmode(), get_ST(0)));
sewardj588ea762004-09-10 18:56:32 +00003725 break;
3726
sewardj89cd0932004-09-08 18:23:25 +00003727 case 3: /* FSTP single-real */
sewardj33dd31b2005-01-08 18:17:32 +00003728 DIP("fstps %s\n", dis_buf);
sewardj3bca9062004-12-04 14:36:09 +00003729 storeLE(mkexpr(addr),
3730 binop(Iop_F64toF32, get_roundingmode(), get_ST(0)));
sewardj5bd4d162004-11-10 13:02:48 +00003731 fp_pop();
sewardj89cd0932004-09-08 18:23:25 +00003732 break;
3733
sewardjd24931d2005-03-20 12:51:39 +00003734 case 4: { /* FLDENV m28 */
sewardj7df596b2004-12-06 14:29:12 +00003735 /* Uses dirty helper:
3736 VexEmWarn x86g_do_FLDENV ( VexGuestX86State*, Addr32 ) */
3737 IRTemp ew = newTemp(Ity_I32);
3738 IRDirty* d = unsafeIRDirty_0_N (
3739 0/*regparms*/,
3740 "x86g_dirtyhelper_FLDENV",
3741 &x86g_dirtyhelper_FLDENV,
3742 mkIRExprVec_1( mkexpr(addr) )
3743 );
3744 d->needsBBP = True;
3745 d->tmp = ew;
3746 /* declare we're reading memory */
3747 d->mFx = Ifx_Read;
3748 d->mAddr = mkexpr(addr);
3749 d->mSize = 28;
3750
3751 /* declare we're writing guest state */
3752 d->nFxState = 5;
3753
3754 d->fxState[0].fx = Ifx_Write;
3755 d->fxState[0].offset = OFFB_FTOP;
3756 d->fxState[0].size = sizeof(UInt);
3757
3758 d->fxState[1].fx = Ifx_Write;
3759 d->fxState[1].offset = OFFB_FPREGS;
3760 d->fxState[1].size = 8 * sizeof(ULong);
3761
3762 d->fxState[2].fx = Ifx_Write;
3763 d->fxState[2].offset = OFFB_FPTAGS;
3764 d->fxState[2].size = 8 * sizeof(UChar);
3765
3766 d->fxState[3].fx = Ifx_Write;
3767 d->fxState[3].offset = OFFB_FPROUND;
3768 d->fxState[3].size = sizeof(UInt);
3769
3770 d->fxState[4].fx = Ifx_Write;
3771 d->fxState[4].offset = OFFB_FC3210;
3772 d->fxState[4].size = sizeof(UInt);
3773
3774 stmt( IRStmt_Dirty(d) );
3775
3776 /* ew contains any emulation warning we may need to
3777 issue. If needed, side-exit to the next insn,
3778 reporting the warning, so that Valgrind's dispatcher
3779 sees the warning. */
3780 put_emwarn( mkexpr(ew) );
3781 stmt(
3782 IRStmt_Exit(
3783 binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
3784 Ijk_EmWarn,
3785 IRConst_U32( ((Addr32)guest_eip_bbstart)+delta)
3786 )
3787 );
3788
sewardj33dd31b2005-01-08 18:17:32 +00003789 DIP("fldenv %s\n", dis_buf);
sewardj7df596b2004-12-06 14:29:12 +00003790 break;
3791 }
3792
sewardj893aada2004-11-29 19:57:54 +00003793 case 5: {/* FLDCW */
3794 /* The only thing we observe in the control word is the
sewardjd01a9632004-11-30 13:18:37 +00003795 rounding mode. Therefore, pass the 16-bit value
3796 (x87 native-format control word) to a clean helper,
3797 getting back a 64-bit value, the lower half of which
3798 is the FPROUND value to store, and the upper half of
3799 which is the emulation-warning token which may be
3800 generated.
sewardj893aada2004-11-29 19:57:54 +00003801 */
3802 /* ULong x86h_check_fldcw ( UInt ); */
3803 IRTemp t64 = newTemp(Ity_I64);
3804 IRTemp ew = newTemp(Ity_I32);
sewardj33dd31b2005-01-08 18:17:32 +00003805 DIP("fldcw %s\n", dis_buf);
sewardj893aada2004-11-29 19:57:54 +00003806 assign( t64, mkIRExprCCall(
3807 Ity_I64, 0/*regparms*/,
sewardj3bd6f3e2004-12-13 10:48:19 +00003808 "x86g_check_fldcw",
3809 &x86g_check_fldcw,
sewardj893aada2004-11-29 19:57:54 +00003810 mkIRExprVec_1(
3811 unop( Iop_16Uto32,
3812 loadLE(Ity_I16, mkexpr(addr)))
3813 )
3814 )
3815 );
3816
sewardjd01a9632004-11-30 13:18:37 +00003817 put_fpround( unop(Iop_64to32, mkexpr(t64)) );
sewardj893aada2004-11-29 19:57:54 +00003818 assign( ew, unop(Iop_64HIto32, mkexpr(t64) ) );
3819 put_emwarn( mkexpr(ew) );
3820 /* Finally, if an emulation warning was reported,
3821 side-exit to the next insn, reporting the warning,
3822 so that Valgrind's dispatcher sees the warning. */
3823 stmt(
3824 IRStmt_Exit(
3825 binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
3826 Ijk_EmWarn,
3827 IRConst_U32( ((Addr32)guest_eip_bbstart)+delta)
3828 )
3829 );
sewardj89cd0932004-09-08 18:23:25 +00003830 break;
sewardj893aada2004-11-29 19:57:54 +00003831 }
sewardj89cd0932004-09-08 18:23:25 +00003832
sewardj7df596b2004-12-06 14:29:12 +00003833 case 6: { /* FNSTENV m28 */
3834 /* Uses dirty helper:
3835 void x86g_do_FSTENV ( VexGuestX86State*, UInt ) */
3836 IRDirty* d = unsafeIRDirty_0_N (
3837 0/*regparms*/,
3838 "x86g_dirtyhelper_FSTENV",
3839 &x86g_dirtyhelper_FSTENV,
3840 mkIRExprVec_1( mkexpr(addr) )
3841 );
3842 d->needsBBP = True;
3843 /* declare we're writing memory */
3844 d->mFx = Ifx_Write;
3845 d->mAddr = mkexpr(addr);
3846 d->mSize = 28;
3847
3848 /* declare we're reading guest state */
3849 d->nFxState = 4;
3850
3851 d->fxState[0].fx = Ifx_Read;
3852 d->fxState[0].offset = OFFB_FTOP;
3853 d->fxState[0].size = sizeof(UInt);
3854
3855 d->fxState[1].fx = Ifx_Read;
3856 d->fxState[1].offset = OFFB_FPTAGS;
3857 d->fxState[1].size = 8 * sizeof(UChar);
3858
3859 d->fxState[2].fx = Ifx_Read;
3860 d->fxState[2].offset = OFFB_FPROUND;
3861 d->fxState[2].size = sizeof(UInt);
3862
3863 d->fxState[3].fx = Ifx_Read;
3864 d->fxState[3].offset = OFFB_FC3210;
3865 d->fxState[3].size = sizeof(UInt);
3866
3867 stmt( IRStmt_Dirty(d) );
3868
sewardj33dd31b2005-01-08 18:17:32 +00003869 DIP("fnstenv %s\n", dis_buf);
sewardj7df596b2004-12-06 14:29:12 +00003870 break;
3871 }
3872
sewardj588ea762004-09-10 18:56:32 +00003873 case 7: /* FNSTCW */
sewardj893aada2004-11-29 19:57:54 +00003874 /* Fake up a native x87 FPU control word. The only
sewardjd01a9632004-11-30 13:18:37 +00003875 thing it depends on is FPROUND[1:0], so call a clean
sewardj893aada2004-11-29 19:57:54 +00003876 helper to cook it up. */
sewardjd01a9632004-11-30 13:18:37 +00003877 /* UInt x86h_create_fpucw ( UInt fpround ) */
sewardj33dd31b2005-01-08 18:17:32 +00003878 DIP("fnstcw %s\n", dis_buf);
sewardj893aada2004-11-29 19:57:54 +00003879 storeLE(
3880 mkexpr(addr),
3881 unop( Iop_32to16,
3882 mkIRExprCCall(
3883 Ity_I32, 0/*regp*/,
sewardj3bd6f3e2004-12-13 10:48:19 +00003884 "x86g_create_fpucw", &x86g_create_fpucw,
sewardjd01a9632004-11-30 13:18:37 +00003885 mkIRExprVec_1( get_fpround() )
sewardj893aada2004-11-29 19:57:54 +00003886 )
3887 )
3888 );
sewardj89cd0932004-09-08 18:23:25 +00003889 break;
3890
3891 default:
3892 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
3893 vex_printf("first_opcode == 0xD9\n");
3894 goto decode_fail;
3895 }
3896
sewardjbb53f8c2004-08-14 11:50:01 +00003897 } else {
3898 delta++;
3899 switch (modrm) {
sewardj89cd0932004-09-08 18:23:25 +00003900
sewardjbb53f8c2004-08-14 11:50:01 +00003901 case 0xC0 ... 0xC7: /* FLD %st(?) */
sewardja58ea662004-08-15 03:12:41 +00003902 r_src = (UInt)modrm - 0xC0;
sewardj2d49b432005-02-01 00:37:06 +00003903 DIP("fld %%st(%d)\n", (Int)r_src);
sewardj5bd4d162004-11-10 13:02:48 +00003904 t1 = newTemp(Ity_F64);
3905 assign(t1, get_ST(r_src));
3906 fp_push();
3907 put_ST(0, mkexpr(t1));
sewardjbb53f8c2004-08-14 11:50:01 +00003908 break;
3909
sewardj89cd0932004-09-08 18:23:25 +00003910 case 0xC8 ... 0xCF: /* FXCH %st(?) */
3911 r_src = (UInt)modrm - 0xC8;
sewardj2d49b432005-02-01 00:37:06 +00003912 DIP("fxch %%st(%d)\n", (Int)r_src);
sewardj89cd0932004-09-08 18:23:25 +00003913 t1 = newTemp(Ity_F64);
3914 t2 = newTemp(Ity_F64);
3915 assign(t1, get_ST(0));
3916 assign(t2, get_ST(r_src));
3917 put_ST_UNCHECKED(0, mkexpr(t2));
3918 put_ST_UNCHECKED(r_src, mkexpr(t1));
3919 break;
3920
sewardjcfded9a2004-09-09 11:44:16 +00003921 case 0xE0: /* FCHS */
3922 DIP("fchs\n");
3923 put_ST_UNCHECKED(0, unop(Iop_NegF64, get_ST(0)));
3924 break;
3925
sewardj883b00b2004-09-11 09:30:24 +00003926 case 0xE1: /* FABS */
3927 DIP("fabs\n");
3928 put_ST_UNCHECKED(0, unop(Iop_AbsF64, get_ST(0)));
3929 break;
sewardjc4be80c2004-09-10 16:17:45 +00003930
sewardj1c318772005-03-19 14:27:04 +00003931 case 0xE4: /* FTST */
3932 DIP("ftst\n");
3933 /* This forces C1 to zero, which isn't right. */
3934 /* Well, in fact the Intel docs say (bizarrely): "C1 is
3935 set to 0 if stack underflow occurred; otherwise, set
3936 to 0" which is pretty nonsensical. I guess it's a
3937 typo. */
3938 put_C3210(
3939 binop( Iop_And32,
3940 binop(Iop_Shl32,
3941 binop(Iop_CmpF64,
3942 get_ST(0),
3943 IRExpr_Const(IRConst_F64i(0x0ULL))),
3944 mkU8(8)),
3945 mkU32(0x4500)
3946 ));
3947 break;
3948
sewardj883b00b2004-09-11 09:30:24 +00003949 case 0xE5: { /* FXAM */
3950 /* This is an interesting one. It examines %st(0),
3951 regardless of whether the tag says it's empty or not.
3952 Here, just pass both the tag (in our format) and the
3953 value (as a double, actually a ULong) to a helper
3954 function. */
sewardjf9655262004-10-31 20:02:16 +00003955 IRExpr** args
3956 = mkIRExprVec_2( unop(Iop_8Uto32, get_ST_TAG(0)),
3957 unop(Iop_ReinterpF64asI64,
3958 get_ST_UNCHECKED(0)) );
3959 put_C3210(mkIRExprCCall(
sewardj8ea867b2004-10-30 19:03:02 +00003960 Ity_I32,
sewardjf9655262004-10-31 20:02:16 +00003961 0/*regparm*/,
sewardj2a9ad022004-11-25 02:46:58 +00003962 "x86g_calculate_FXAM", &x86g_calculate_FXAM,
sewardj8ea867b2004-10-30 19:03:02 +00003963 args
3964 ));
sewardj33dd31b2005-01-08 18:17:32 +00003965 DIP("fxam\n");
sewardj883b00b2004-09-11 09:30:24 +00003966 break;
3967 }
3968
3969 case 0xE8: /* FLD1 */
sewardj33dd31b2005-01-08 18:17:32 +00003970 DIP("fld1\n");
sewardjce646f22004-08-31 23:55:54 +00003971 fp_push();
sewardj9c323762005-01-10 16:49:19 +00003972 /* put_ST(0, IRExpr_Const(IRConst_F64(1.0))); */
3973 put_ST(0, IRExpr_Const(IRConst_F64i(0x3ff0000000000000ULL)));
sewardjce646f22004-08-31 23:55:54 +00003974 break;
3975
sewardj37158712004-10-15 21:23:12 +00003976 case 0xE9: /* FLDL2T */
sewardj33dd31b2005-01-08 18:17:32 +00003977 DIP("fldl2t\n");
sewardj37158712004-10-15 21:23:12 +00003978 fp_push();
sewardj9c323762005-01-10 16:49:19 +00003979 /* put_ST(0, IRExpr_Const(IRConst_F64(3.32192809488736234781))); */
3980 put_ST(0, IRExpr_Const(IRConst_F64i(0x400a934f0979a371ULL)));
sewardj37158712004-10-15 21:23:12 +00003981 break;
3982
sewardj8308aad2004-09-12 11:09:54 +00003983 case 0xEA: /* FLDL2E */
sewardj33dd31b2005-01-08 18:17:32 +00003984 DIP("fldl2e\n");
sewardj8308aad2004-09-12 11:09:54 +00003985 fp_push();
sewardj9c323762005-01-10 16:49:19 +00003986 /* put_ST(0, IRExpr_Const(IRConst_F64(1.44269504088896340739))); */
3987 put_ST(0, IRExpr_Const(IRConst_F64i(0x3ff71547652b82feULL)));
sewardj8308aad2004-09-12 11:09:54 +00003988 break;
3989
sewardja0d48d62004-09-20 21:19:03 +00003990 case 0xEB: /* FLDPI */
sewardj33dd31b2005-01-08 18:17:32 +00003991 DIP("fldpi\n");
sewardja0d48d62004-09-20 21:19:03 +00003992 fp_push();
sewardj9c323762005-01-10 16:49:19 +00003993 /* put_ST(0, IRExpr_Const(IRConst_F64(3.14159265358979323851))); */
3994 put_ST(0, IRExpr_Const(IRConst_F64i(0x400921fb54442d18ULL)));
sewardja0d48d62004-09-20 21:19:03 +00003995 break;
3996
sewardjdb199622004-09-06 23:19:03 +00003997 case 0xEC: /* FLDLG2 */
sewardj33dd31b2005-01-08 18:17:32 +00003998 DIP("fldlg2\n");
sewardjdb199622004-09-06 23:19:03 +00003999 fp_push();
sewardj9c323762005-01-10 16:49:19 +00004000 /* put_ST(0, IRExpr_Const(IRConst_F64(0.301029995663981143))); */
4001 put_ST(0, IRExpr_Const(IRConst_F64i(0x3fd34413509f79ffULL)));
sewardjdb199622004-09-06 23:19:03 +00004002 break;
4003
4004 case 0xED: /* FLDLN2 */
sewardj33dd31b2005-01-08 18:17:32 +00004005 DIP("fldln2\n");
sewardjdb199622004-09-06 23:19:03 +00004006 fp_push();
sewardj9c323762005-01-10 16:49:19 +00004007 /* put_ST(0, IRExpr_Const(IRConst_F64(0.69314718055994530942))); */
4008 put_ST(0, IRExpr_Const(IRConst_F64i(0x3fe62e42fefa39efULL)));
sewardjdb199622004-09-06 23:19:03 +00004009 break;
4010
sewardja58ea662004-08-15 03:12:41 +00004011 case 0xEE: /* FLDZ */
sewardj33dd31b2005-01-08 18:17:32 +00004012 DIP("fldz\n");
sewardj207557a2004-08-27 12:00:18 +00004013 fp_push();
sewardj9c323762005-01-10 16:49:19 +00004014 /* put_ST(0, IRExpr_Const(IRConst_F64(0.0))); */
4015 put_ST(0, IRExpr_Const(IRConst_F64i(0x0000000000000000ULL)));
sewardja58ea662004-08-15 03:12:41 +00004016 break;
4017
sewardj06c32a02004-09-12 12:07:34 +00004018 case 0xF0: /* F2XM1 */
4019 DIP("f2xm1\n");
4020 put_ST_UNCHECKED(0, unop(Iop_2xm1F64, get_ST(0)));
4021 break;
4022
sewardj52ace3e2004-09-11 17:10:08 +00004023 case 0xF1: /* FYL2X */
4024 DIP("fyl2x\n");
4025 put_ST_UNCHECKED(1, binop(Iop_Yl2xF64,
4026 get_ST(1), get_ST(0)));
4027 fp_pop();
4028 break;
4029
sewardj99016a72004-10-15 22:09:17 +00004030 case 0xF2: /* FPTAN */
4031 DIP("ftan\n");
4032 put_ST_UNCHECKED(0, unop(Iop_TanF64, get_ST(0)));
4033 fp_push();
4034 put_ST(0, IRExpr_Const(IRConst_F64(1.0)));
sewardj3f61ddb2004-10-16 20:51:05 +00004035 clear_C2(); /* HACK */
sewardj99016a72004-10-15 22:09:17 +00004036 break;
4037
sewardjcfded9a2004-09-09 11:44:16 +00004038 case 0xF3: /* FPATAN */
4039 DIP("fpatan\n");
sewardj52ace3e2004-09-11 17:10:08 +00004040 put_ST_UNCHECKED(1, binop(Iop_AtanF64,
sewardjcfded9a2004-09-09 11:44:16 +00004041 get_ST(1), get_ST(0)));
4042 fp_pop();
4043 break;
4044
sewardj442d0be2004-10-15 22:57:13 +00004045 case 0xF5: { /* FPREM1 -- IEEE compliant */
4046 IRTemp a1 = newTemp(Ity_F64);
4047 IRTemp a2 = newTemp(Ity_F64);
4048 DIP("fprem1\n");
4049 /* Do FPREM1 twice, once to get the remainder, and once
4050 to get the C3210 flag values. */
4051 assign( a1, get_ST(0) );
4052 assign( a2, get_ST(1) );
4053 put_ST_UNCHECKED(0, binop(Iop_PRem1F64,
4054 mkexpr(a1), mkexpr(a2)));
4055 put_C3210( binop(Iop_PRem1C3210F64, mkexpr(a1), mkexpr(a2)) );
4056 break;
4057 }
4058
sewardjfeeb8a82004-11-30 12:30:11 +00004059 case 0xF7: /* FINCSTP */
4060 DIP("fprem\n");
4061 put_ftop( binop(Iop_Add32, get_ftop(), mkU32(1)) );
4062 break;
4063
sewardj46de4072004-09-11 19:23:24 +00004064 case 0xF8: { /* FPREM -- not IEEE compliant */
4065 IRTemp a1 = newTemp(Ity_F64);
4066 IRTemp a2 = newTemp(Ity_F64);
4067 DIP("fprem\n");
4068 /* Do FPREM twice, once to get the remainder, and once
4069 to get the C3210 flag values. */
4070 assign( a1, get_ST(0) );
4071 assign( a2, get_ST(1) );
4072 put_ST_UNCHECKED(0, binop(Iop_PRemF64,
4073 mkexpr(a1), mkexpr(a2)));
4074 put_C3210( binop(Iop_PRemC3210F64, mkexpr(a1), mkexpr(a2)) );
4075 break;
4076 }
4077
sewardj8308aad2004-09-12 11:09:54 +00004078 case 0xF9: /* FYL2XP1 */
4079 DIP("fyl2xp1\n");
4080 put_ST_UNCHECKED(1, binop(Iop_Yl2xp1F64,
4081 get_ST(1), get_ST(0)));
4082 fp_pop();
4083 break;
4084
sewardjc4be80c2004-09-10 16:17:45 +00004085 case 0xFA: /* FSQRT */
4086 DIP("fsqrt\n");
4087 put_ST_UNCHECKED(0, unop(Iop_SqrtF64, get_ST(0)));
4088 break;
4089
sewardj519d66f2004-12-15 11:57:58 +00004090 case 0xFB: { /* FSINCOS */
4091 IRTemp a1 = newTemp(Ity_F64);
4092 assign( a1, get_ST(0) );
4093 DIP("fsincos\n");
4094 put_ST_UNCHECKED(0, unop(Iop_SinF64, mkexpr(a1)));
4095 fp_push();
4096 put_ST(0, unop(Iop_CosF64, mkexpr(a1)));
sewardj88a69242005-04-01 20:19:20 +00004097 clear_C2(); /* HACK */
sewardj519d66f2004-12-15 11:57:58 +00004098 break;
4099 }
4100
sewardje6709112004-09-10 18:37:18 +00004101 case 0xFC: /* FRNDINT */
4102 DIP("frndint\n");
4103 put_ST_UNCHECKED(0,
4104 binop(Iop_RoundF64, get_roundingmode(), get_ST(0)) );
4105 break;
4106
sewardj06c32a02004-09-12 12:07:34 +00004107 case 0xFD: /* FSCALE */
4108 DIP("fscale\n");
4109 put_ST_UNCHECKED(0, binop(Iop_ScaleF64,
4110 get_ST(0), get_ST(1)));
4111 break;
4112
sewardjcfded9a2004-09-09 11:44:16 +00004113 case 0xFE: /* FSIN */
4114 DIP("fsin\n");
4115 put_ST_UNCHECKED(0, unop(Iop_SinF64, get_ST(0)));
sewardj3f61ddb2004-10-16 20:51:05 +00004116 clear_C2(); /* HACK */
sewardjcfded9a2004-09-09 11:44:16 +00004117 break;
4118
4119 case 0xFF: /* FCOS */
4120 DIP("fcos\n");
4121 put_ST_UNCHECKED(0, unop(Iop_CosF64, get_ST(0)));
sewardj3f61ddb2004-10-16 20:51:05 +00004122 clear_C2(); /* HACK */
sewardjcfded9a2004-09-09 11:44:16 +00004123 break;
4124
sewardjbb53f8c2004-08-14 11:50:01 +00004125 default:
4126 goto decode_fail;
4127 }
4128 }
sewardjd1725d12004-08-12 20:46:53 +00004129 }
4130
4131 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDA opcodes +-+-+-+-+-+-+-+ */
4132 else
4133 if (first_opcode == 0xDA) {
sewardjbb53f8c2004-08-14 11:50:01 +00004134
4135 if (modrm < 0xC0) {
4136
sewardjfeeb8a82004-11-30 12:30:11 +00004137 /* bits 5,4,3 are an opcode extension, and the modRM also
sewardjbb53f8c2004-08-14 11:50:01 +00004138 specifies an address. */
sewardjce646f22004-08-31 23:55:54 +00004139 IROp fop;
sewardjbb53f8c2004-08-14 11:50:01 +00004140 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
4141 delta += len;
sewardjbb53f8c2004-08-14 11:50:01 +00004142 switch (gregOfRM(modrm)) {
sewardjce646f22004-08-31 23:55:54 +00004143
sewardjdb199622004-09-06 23:19:03 +00004144 case 0: /* FIADD m32int */ /* ST(0) += m32int */
sewardj33dd31b2005-01-08 18:17:32 +00004145 DIP("fiaddl %s\n", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00004146 fop = Iop_AddF64;
4147 goto do_fop_m32;
sewardjdb199622004-09-06 23:19:03 +00004148
sewardj207557a2004-08-27 12:00:18 +00004149 case 1: /* FIMUL m32int */ /* ST(0) *= m32int */
sewardj33dd31b2005-01-08 18:17:32 +00004150 DIP("fimull %s\n", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00004151 fop = Iop_MulF64;
4152 goto do_fop_m32;
sewardjce646f22004-08-31 23:55:54 +00004153
4154 case 4: /* FISUB m32int */ /* ST(0) -= m32int */
sewardj33dd31b2005-01-08 18:17:32 +00004155 DIP("fisubl %s\n", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00004156 fop = Iop_SubF64;
4157 goto do_fop_m32;
sewardjce646f22004-08-31 23:55:54 +00004158
sewardj8308aad2004-09-12 11:09:54 +00004159 case 5: /* FISUBR m32int */ /* ST(0) = m32int - ST(0) */
sewardj33dd31b2005-01-08 18:17:32 +00004160 DIP("fisubrl %s\n", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00004161 fop = Iop_SubF64;
4162 goto do_foprev_m32;
sewardj8308aad2004-09-12 11:09:54 +00004163
sewardjce646f22004-08-31 23:55:54 +00004164 case 6: /* FIDIV m32int */ /* ST(0) /= m32int */
sewardj36917e92005-03-21 00:12:15 +00004165 DIP("fidivl %s\n", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00004166 fop = Iop_DivF64;
4167 goto do_fop_m32;
sewardjce646f22004-08-31 23:55:54 +00004168
sewardjc4eaff32004-09-10 20:25:11 +00004169 case 7: /* FIDIVR m32int */ /* ST(0) = m32int / ST(0) */
sewardj33dd31b2005-01-08 18:17:32 +00004170 DIP("fidivrl %s\n", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00004171 fop = Iop_DivF64;
4172 goto do_foprev_m32;
sewardjc4eaff32004-09-10 20:25:11 +00004173
sewardjce646f22004-08-31 23:55:54 +00004174 do_fop_m32:
sewardj207557a2004-08-27 12:00:18 +00004175 put_ST_UNCHECKED(0,
sewardjce646f22004-08-31 23:55:54 +00004176 binop(fop,
sewardj207557a2004-08-27 12:00:18 +00004177 get_ST(0),
sewardj89cd0932004-09-08 18:23:25 +00004178 unop(Iop_I32toF64,
4179 loadLE(Ity_I32, mkexpr(addr)))));
sewardjbb53f8c2004-08-14 11:50:01 +00004180 break;
4181
sewardjc4eaff32004-09-10 20:25:11 +00004182 do_foprev_m32:
4183 put_ST_UNCHECKED(0,
4184 binop(fop,
4185 unop(Iop_I32toF64,
4186 loadLE(Ity_I32, mkexpr(addr))),
4187 get_ST(0)));
4188 break;
4189
sewardjbb53f8c2004-08-14 11:50:01 +00004190 default:
4191 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
4192 vex_printf("first_opcode == 0xDA\n");
4193 goto decode_fail;
4194 }
sewardj4cb918d2004-12-03 19:43:31 +00004195
sewardjbb53f8c2004-08-14 11:50:01 +00004196 } else {
sewardjbdc7d212004-09-09 02:46:40 +00004197
4198 delta++;
4199 switch (modrm) {
4200
sewardj519d66f2004-12-15 11:57:58 +00004201 case 0xC0 ... 0xC7: /* FCMOVB ST(i), ST(0) */
4202 r_src = (UInt)modrm - 0xC0;
sewardj2d49b432005-02-01 00:37:06 +00004203 DIP("fcmovb %%st(%d), %%st(0)\n", (Int)r_src);
sewardj519d66f2004-12-15 11:57:58 +00004204 put_ST_UNCHECKED(0,
4205 IRExpr_Mux0X(
4206 unop(Iop_1Uto8,
4207 mk_x86g_calculate_condition(X86CondB)),
4208 get_ST(0), get_ST(r_src)) );
4209 break;
4210
sewardj3fd5e572004-09-09 22:43:51 +00004211 case 0xC8 ... 0xCF: /* FCMOVE(Z) ST(i), ST(0) */
4212 r_src = (UInt)modrm - 0xC8;
sewardj2d49b432005-02-01 00:37:06 +00004213 DIP("fcmovz %%st(%d), %%st(0)\n", (Int)r_src);
sewardj5bd4d162004-11-10 13:02:48 +00004214 put_ST_UNCHECKED(0,
sewardj3fd5e572004-09-09 22:43:51 +00004215 IRExpr_Mux0X(
sewardj2a9ad022004-11-25 02:46:58 +00004216 unop(Iop_1Uto8,
4217 mk_x86g_calculate_condition(X86CondZ)),
sewardj3fd5e572004-09-09 22:43:51 +00004218 get_ST(0), get_ST(r_src)) );
4219 break;
4220
sewardj519d66f2004-12-15 11:57:58 +00004221 case 0xD0 ... 0xD7: /* FCMOVBE ST(i), ST(0) */
4222 r_src = (UInt)modrm - 0xD0;
sewardj2d49b432005-02-01 00:37:06 +00004223 DIP("fcmovbe %%st(%d), %%st(0)\n", (Int)r_src);
sewardj519d66f2004-12-15 11:57:58 +00004224 put_ST_UNCHECKED(0,
4225 IRExpr_Mux0X(
4226 unop(Iop_1Uto8,
4227 mk_x86g_calculate_condition(X86CondBE)),
4228 get_ST(0), get_ST(r_src)) );
4229 break;
4230
sewardjbdc7d212004-09-09 02:46:40 +00004231 case 0xE9: /* FUCOMPP %st(0),%st(1) */
4232 DIP("fucompp %%st(0),%%st(1)\n");
sewardjc4be80c2004-09-10 16:17:45 +00004233 /* This forces C1 to zero, which isn't right. */
4234 put_C3210(
4235 binop( Iop_And32,
4236 binop(Iop_Shl32,
4237 binop(Iop_CmpF64, get_ST(0), get_ST(1)),
4238 mkU8(8)),
4239 mkU32(0x4500)
4240 ));
sewardjbdc7d212004-09-09 02:46:40 +00004241 fp_pop();
4242 fp_pop();
4243 break;
4244
sewardj5bd4d162004-11-10 13:02:48 +00004245 default:
sewardjbdc7d212004-09-09 02:46:40 +00004246 goto decode_fail;
sewardj5bd4d162004-11-10 13:02:48 +00004247 }
sewardjbdc7d212004-09-09 02:46:40 +00004248
sewardjbb53f8c2004-08-14 11:50:01 +00004249 }
sewardjd1725d12004-08-12 20:46:53 +00004250 }
4251
4252 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDB opcodes +-+-+-+-+-+-+-+ */
4253 else
4254 if (first_opcode == 0xDB) {
sewardj89cd0932004-09-08 18:23:25 +00004255 if (modrm < 0xC0) {
4256
sewardjfeeb8a82004-11-30 12:30:11 +00004257 /* bits 5,4,3 are an opcode extension, and the modRM also
sewardj89cd0932004-09-08 18:23:25 +00004258 specifies an address. */
4259 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
4260 delta += len;
4261
4262 switch (gregOfRM(modrm)) {
4263
4264 case 0: /* FILD m32int */
4265 DIP("fildl %s\n", dis_buf);
4266 fp_push();
4267 put_ST(0, unop(Iop_I32toF64,
4268 loadLE(Ity_I32, mkexpr(addr))));
4269 break;
4270
sewardj8f3debf2004-09-08 23:42:23 +00004271 case 2: /* FIST m32 */
sewardj33dd31b2005-01-08 18:17:32 +00004272 DIP("fistl %s\n", dis_buf);
sewardj8f3debf2004-09-08 23:42:23 +00004273 storeLE( mkexpr(addr),
4274 binop(Iop_F64toI32, get_roundingmode(), get_ST(0)) );
4275 break;
4276
sewardj89cd0932004-09-08 18:23:25 +00004277 case 3: /* FISTP m32 */
sewardj33dd31b2005-01-08 18:17:32 +00004278 DIP("fistpl %s\n", dis_buf);
sewardj8f3debf2004-09-08 23:42:23 +00004279 storeLE( mkexpr(addr),
4280 binop(Iop_F64toI32, get_roundingmode(), get_ST(0)) );
sewardj5bd4d162004-11-10 13:02:48 +00004281 fp_pop();
sewardj89cd0932004-09-08 18:23:25 +00004282 break;
sewardj17442fe2004-09-20 14:54:28 +00004283
sewardjb3bce0e2004-09-14 23:20:10 +00004284 case 5: { /* FLD extended-real */
sewardj7cb49d72004-10-24 22:31:25 +00004285 /* Uses dirty helper:
sewardj56579232005-03-26 21:49:42 +00004286 ULong x86g_loadF80le ( UInt )
sewardj7cb49d72004-10-24 22:31:25 +00004287 addr holds the address. First, do a dirty call to
sewardjb3bce0e2004-09-14 23:20:10 +00004288 get hold of the data. */
sewardjc5fc7aa2004-10-27 23:00:55 +00004289 IRTemp val = newTemp(Ity_I64);
4290 IRExpr** args = mkIRExprVec_1 ( mkexpr(addr) );
4291
sewardj8ea867b2004-10-30 19:03:02 +00004292 IRDirty* d = unsafeIRDirty_1_N (
4293 val,
sewardj2a9ad022004-11-25 02:46:58 +00004294 0/*regparms*/,
4295 "x86g_loadF80le", &x86g_loadF80le,
sewardj8ea867b2004-10-30 19:03:02 +00004296 args
4297 );
sewardjb3bce0e2004-09-14 23:20:10 +00004298 /* declare that we're reading memory */
4299 d->mFx = Ifx_Read;
sewardj17442fe2004-09-20 14:54:28 +00004300 d->mAddr = mkexpr(addr);
sewardjb3bce0e2004-09-14 23:20:10 +00004301 d->mSize = 10;
sewardjc5fc7aa2004-10-27 23:00:55 +00004302
4303 /* execute the dirty call, dumping the result in val. */
sewardjb3bce0e2004-09-14 23:20:10 +00004304 stmt( IRStmt_Dirty(d) );
4305 fp_push();
sewardjc5fc7aa2004-10-27 23:00:55 +00004306 put_ST(0, unop(Iop_ReinterpI64asF64, mkexpr(val)));
4307
sewardj33dd31b2005-01-08 18:17:32 +00004308 DIP("fldt %s\n", dis_buf);
sewardjb3bce0e2004-09-14 23:20:10 +00004309 break;
4310 }
sewardj17442fe2004-09-20 14:54:28 +00004311
4312 case 7: { /* FSTP extended-real */
sewardj9fc9e782004-11-26 17:57:40 +00004313 /* Uses dirty helper: void x86g_storeF80le ( UInt, ULong ) */
sewardjc5fc7aa2004-10-27 23:00:55 +00004314 IRExpr** args
4315 = mkIRExprVec_2( mkexpr(addr),
4316 unop(Iop_ReinterpF64asI64, get_ST(0)) );
4317
sewardj8ea867b2004-10-30 19:03:02 +00004318 IRDirty* d = unsafeIRDirty_0_N (
sewardjf9655262004-10-31 20:02:16 +00004319 0/*regparms*/,
sewardj2a9ad022004-11-25 02:46:58 +00004320 "x86g_storeF80le", &x86g_storeF80le,
sewardj8ea867b2004-10-30 19:03:02 +00004321 args
4322 );
sewardj17442fe2004-09-20 14:54:28 +00004323 /* declare we're writing memory */
4324 d->mFx = Ifx_Write;
4325 d->mAddr = mkexpr(addr);
4326 d->mSize = 10;
sewardjc5fc7aa2004-10-27 23:00:55 +00004327
sewardj17442fe2004-09-20 14:54:28 +00004328 /* execute the dirty call. */
4329 stmt( IRStmt_Dirty(d) );
4330 fp_pop();
sewardjc5fc7aa2004-10-27 23:00:55 +00004331
sewardj33dd31b2005-01-08 18:17:32 +00004332 DIP("fstpt\n %s", dis_buf);
sewardj17442fe2004-09-20 14:54:28 +00004333 break;
4334 }
4335
sewardjb3bce0e2004-09-14 23:20:10 +00004336 default:
sewardj89cd0932004-09-08 18:23:25 +00004337 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
4338 vex_printf("first_opcode == 0xDB\n");
4339 goto decode_fail;
4340 }
4341
4342 } else {
sewardj8308aad2004-09-12 11:09:54 +00004343
4344 delta++;
4345 switch (modrm) {
4346
sewardj519d66f2004-12-15 11:57:58 +00004347 case 0xC0 ... 0xC7: /* FCMOVNB ST(i), ST(0) */
4348 r_src = (UInt)modrm - 0xC0;
sewardj2d49b432005-02-01 00:37:06 +00004349 DIP("fcmovnb %%st(%d), %%st(0)\n", (Int)r_src);
sewardj519d66f2004-12-15 11:57:58 +00004350 put_ST_UNCHECKED(0,
4351 IRExpr_Mux0X(
4352 unop(Iop_1Uto8,
4353 mk_x86g_calculate_condition(X86CondNB)),
4354 get_ST(0), get_ST(r_src)) );
4355 break;
4356
sewardj4e82db72004-10-16 11:32:15 +00004357 case 0xC8 ... 0xCF: /* FCMOVNE(NZ) ST(i), ST(0) */
4358 r_src = (UInt)modrm - 0xC8;
sewardj2d49b432005-02-01 00:37:06 +00004359 DIP("fcmovnz %%st(%d), %%st(0)\n", (Int)r_src);
sewardj5bd4d162004-11-10 13:02:48 +00004360 put_ST_UNCHECKED(0,
sewardj4e82db72004-10-16 11:32:15 +00004361 IRExpr_Mux0X(
sewardj2a9ad022004-11-25 02:46:58 +00004362 unop(Iop_1Uto8,
4363 mk_x86g_calculate_condition(X86CondNZ)),
sewardj4e82db72004-10-16 11:32:15 +00004364 get_ST(0), get_ST(r_src)) );
4365 break;
4366
sewardj519d66f2004-12-15 11:57:58 +00004367 case 0xD0 ... 0xD7: /* FCMOVNBE ST(i), ST(0) */
4368 r_src = (UInt)modrm - 0xD0;
sewardj2d49b432005-02-01 00:37:06 +00004369 DIP("fcmovnbe %%st(%d), %%st(0)\n", (Int)r_src);
sewardj519d66f2004-12-15 11:57:58 +00004370 put_ST_UNCHECKED(0,
4371 IRExpr_Mux0X(
4372 unop(Iop_1Uto8,
4373 mk_x86g_calculate_condition(X86CondNBE)),
4374 get_ST(0), get_ST(r_src)) );
4375 break;
4376
sewardj7df596b2004-12-06 14:29:12 +00004377 case 0xE2:
4378 DIP("fnclex\n");
4379 break;
4380
sewardja0e83b02005-01-06 12:36:38 +00004381 case 0xE3: {
4382 /* Uses dirty helper:
4383 void x86g_do_FINIT ( VexGuestX86State* ) */
4384 IRDirty* d = unsafeIRDirty_0_N (
4385 0/*regparms*/,
4386 "x86g_dirtyhelper_FINIT",
4387 &x86g_dirtyhelper_FINIT,
4388 mkIRExprVec_0()
4389 );
4390 d->needsBBP = True;
4391
4392 /* declare we're writing guest state */
4393 d->nFxState = 5;
4394
4395 d->fxState[0].fx = Ifx_Write;
4396 d->fxState[0].offset = OFFB_FTOP;
4397 d->fxState[0].size = sizeof(UInt);
4398
4399 d->fxState[1].fx = Ifx_Write;
4400 d->fxState[1].offset = OFFB_FPREGS;
4401 d->fxState[1].size = 8 * sizeof(ULong);
4402
4403 d->fxState[2].fx = Ifx_Write;
4404 d->fxState[2].offset = OFFB_FPTAGS;
4405 d->fxState[2].size = 8 * sizeof(UChar);
4406
4407 d->fxState[3].fx = Ifx_Write;
4408 d->fxState[3].offset = OFFB_FPROUND;
4409 d->fxState[3].size = sizeof(UInt);
4410
4411 d->fxState[4].fx = Ifx_Write;
4412 d->fxState[4].offset = OFFB_FC3210;
4413 d->fxState[4].size = sizeof(UInt);
4414
4415 stmt( IRStmt_Dirty(d) );
4416
sewardj33dd31b2005-01-08 18:17:32 +00004417 DIP("fninit\n");
sewardja0e83b02005-01-06 12:36:38 +00004418 break;
4419 }
4420
sewardj8308aad2004-09-12 11:09:54 +00004421 case 0xE8 ... 0xEF: /* FUCOMI %st(0),%st(?) */
4422 fp_do_ucomi_ST0_STi( (UInt)modrm - 0xE8, False );
4423 break;
4424
sewardj37158712004-10-15 21:23:12 +00004425 case 0xF0 ... 0xF7: /* FCOMI %st(0),%st(?) */
4426 fp_do_ucomi_ST0_STi( (UInt)modrm - 0xF0, False );
4427 break;
4428
sewardj8308aad2004-09-12 11:09:54 +00004429 default:
4430 goto decode_fail;
sewardj17442fe2004-09-20 14:54:28 +00004431 }
sewardj89cd0932004-09-08 18:23:25 +00004432 }
sewardjd1725d12004-08-12 20:46:53 +00004433 }
4434
4435 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDC opcodes +-+-+-+-+-+-+-+ */
4436 else
4437 if (first_opcode == 0xDC) {
sewardja58ea662004-08-15 03:12:41 +00004438 if (modrm < 0xC0) {
4439
sewardj89cd0932004-09-08 18:23:25 +00004440 /* bits 5,4,3 are an opcode extension, and the modRM also
sewardjfeeb8a82004-11-30 12:30:11 +00004441 specifies an address. */
sewardja58ea662004-08-15 03:12:41 +00004442 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
4443 delta += len;
4444
4445 switch (gregOfRM(modrm)) {
4446
4447 case 0: /* FADD double-real */
4448 fp_do_op_mem_ST_0 ( addr, "add", dis_buf, Iop_AddF64, True );
4449 break;
4450
sewardjcfded9a2004-09-09 11:44:16 +00004451 case 1: /* FMUL double-real */
4452 fp_do_op_mem_ST_0 ( addr, "mul", dis_buf, Iop_MulF64, True );
4453 break;
4454
sewardje166ed02004-10-25 02:27:01 +00004455 case 2: /* FCOM double-real */
4456 DIP("fcoml %s\n", dis_buf);
4457 /* This forces C1 to zero, which isn't right. */
4458 put_C3210(
4459 binop( Iop_And32,
4460 binop(Iop_Shl32,
4461 binop(Iop_CmpF64,
4462 get_ST(0),
4463 loadLE(Ity_F64,mkexpr(addr))),
4464 mkU8(8)),
4465 mkU32(0x4500)
4466 ));
4467 break;
4468
sewardj883b00b2004-09-11 09:30:24 +00004469 case 3: /* FCOMP double-real */
sewardje166ed02004-10-25 02:27:01 +00004470 DIP("fcompl %s\n", dis_buf);
sewardj883b00b2004-09-11 09:30:24 +00004471 /* This forces C1 to zero, which isn't right. */
4472 put_C3210(
4473 binop( Iop_And32,
4474 binop(Iop_Shl32,
4475 binop(Iop_CmpF64,
4476 get_ST(0),
4477 loadLE(Ity_F64,mkexpr(addr))),
4478 mkU8(8)),
4479 mkU32(0x4500)
4480 ));
4481 fp_pop();
4482 break;
4483
sewardjcfded9a2004-09-09 11:44:16 +00004484 case 4: /* FSUB double-real */
4485 fp_do_op_mem_ST_0 ( addr, "sub", dis_buf, Iop_SubF64, True );
4486 break;
4487
sewardj3fd5e572004-09-09 22:43:51 +00004488 case 5: /* FSUBR double-real */
4489 fp_do_oprev_mem_ST_0 ( addr, "subr", dis_buf, Iop_SubF64, True );
4490 break;
4491
sewardjcfded9a2004-09-09 11:44:16 +00004492 case 6: /* FDIV double-real */
4493 fp_do_op_mem_ST_0 ( addr, "div", dis_buf, Iop_DivF64, True );
4494 break;
4495
sewardj883b00b2004-09-11 09:30:24 +00004496 case 7: /* FDIVR double-real */
4497 fp_do_oprev_mem_ST_0 ( addr, "divr", dis_buf, Iop_DivF64, True );
4498 break;
4499
sewardja58ea662004-08-15 03:12:41 +00004500 default:
4501 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
4502 vex_printf("first_opcode == 0xDC\n");
4503 goto decode_fail;
4504 }
4505
4506 } else {
sewardjbdc7d212004-09-09 02:46:40 +00004507
4508 delta++;
4509 switch (modrm) {
4510
sewardj3fd5e572004-09-09 22:43:51 +00004511 case 0xC0 ... 0xC7: /* FADD %st(0),%st(?) */
4512 fp_do_op_ST_ST ( "add", Iop_AddF64, 0, modrm - 0xC0, False );
4513 break;
4514
sewardjcfded9a2004-09-09 11:44:16 +00004515 case 0xC8 ... 0xCF: /* FMUL %st(0),%st(?) */
4516 fp_do_op_ST_ST ( "mul", Iop_MulF64, 0, modrm - 0xC8, False );
4517 break;
4518
sewardj47341042004-09-19 11:55:46 +00004519 case 0xE0 ... 0xE7: /* FSUBR %st(0),%st(?) */
4520 fp_do_oprev_ST_ST ( "subr", Iop_SubF64, 0, modrm - 0xE0, False );
4521 break;
4522
sewardjcfded9a2004-09-09 11:44:16 +00004523 case 0xE8 ... 0xEF: /* FSUB %st(0),%st(?) */
4524 fp_do_op_ST_ST ( "sub", Iop_SubF64, 0, modrm - 0xE8, False );
4525 break;
4526
sewardja0d48d62004-09-20 21:19:03 +00004527 case 0xF0 ... 0xF7: /* FDIVR %st(0),%st(?) */
4528 fp_do_oprev_ST_ST ( "divr", Iop_DivF64, 0, modrm - 0xF0, False );
4529 break;
4530
sewardjbdc7d212004-09-09 02:46:40 +00004531 case 0xF8 ... 0xFF: /* FDIV %st(0),%st(?) */
4532 fp_do_op_ST_ST ( "div", Iop_DivF64, 0, modrm - 0xF8, False );
4533 break;
4534
4535 default:
4536 goto decode_fail;
sewardj5bd4d162004-11-10 13:02:48 +00004537 }
sewardjbdc7d212004-09-09 02:46:40 +00004538
sewardja58ea662004-08-15 03:12:41 +00004539 }
sewardjd1725d12004-08-12 20:46:53 +00004540 }
4541
4542 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDD opcodes +-+-+-+-+-+-+-+ */
4543 else
4544 if (first_opcode == 0xDD) {
4545
4546 if (modrm < 0xC0) {
4547
sewardjfeeb8a82004-11-30 12:30:11 +00004548 /* bits 5,4,3 are an opcode extension, and the modRM also
sewardjd1725d12004-08-12 20:46:53 +00004549 specifies an address. */
sewardjbb53f8c2004-08-14 11:50:01 +00004550 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
4551 delta += len;
sewardjd1725d12004-08-12 20:46:53 +00004552
4553 switch (gregOfRM(modrm)) {
4554
4555 case 0: /* FLD double-real */
sewardj33dd31b2005-01-08 18:17:32 +00004556 DIP("fldl %s\n", dis_buf);
sewardj207557a2004-08-27 12:00:18 +00004557 fp_push();
4558 put_ST(0, IRExpr_LDle(Ity_F64, mkexpr(addr)));
sewardjbb53f8c2004-08-14 11:50:01 +00004559 break;
sewardjd1725d12004-08-12 20:46:53 +00004560
sewardjd1725d12004-08-12 20:46:53 +00004561 case 2: /* FST double-real */
sewardj33dd31b2005-01-08 18:17:32 +00004562 DIP("fstl %s\n", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00004563 storeLE(mkexpr(addr), get_ST(0));
sewardjd1725d12004-08-12 20:46:53 +00004564 break;
sewardj89cd0932004-09-08 18:23:25 +00004565
sewardja58ea662004-08-15 03:12:41 +00004566 case 3: /* FSTP double-real */
sewardj33dd31b2005-01-08 18:17:32 +00004567 DIP("fstpl %s\n", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00004568 storeLE(mkexpr(addr), get_ST(0));
4569 fp_pop();
sewardja58ea662004-08-15 03:12:41 +00004570 break;
sewardjd1725d12004-08-12 20:46:53 +00004571
sewardj9fc9e782004-11-26 17:57:40 +00004572 case 4: { /* FRSTOR m108 */
sewardj893aada2004-11-29 19:57:54 +00004573 /* Uses dirty helper:
4574 VexEmWarn x86g_do_FRSTOR ( VexGuestX86State*, Addr32 ) */
4575 IRTemp ew = newTemp(Ity_I32);
4576 IRDirty* d = unsafeIRDirty_0_N (
4577 0/*regparms*/,
4578 "x86g_dirtyhelper_FRSTOR",
4579 &x86g_dirtyhelper_FRSTOR,
4580 mkIRExprVec_1( mkexpr(addr) )
4581 );
sewardj9fc9e782004-11-26 17:57:40 +00004582 d->needsBBP = True;
sewardj893aada2004-11-29 19:57:54 +00004583 d->tmp = ew;
sewardj9fc9e782004-11-26 17:57:40 +00004584 /* declare we're reading memory */
4585 d->mFx = Ifx_Read;
4586 d->mAddr = mkexpr(addr);
4587 d->mSize = 108;
4588
4589 /* declare we're writing guest state */
sewardj893aada2004-11-29 19:57:54 +00004590 d->nFxState = 5;
sewardj9fc9e782004-11-26 17:57:40 +00004591
4592 d->fxState[0].fx = Ifx_Write;
sewardjc9a43662004-11-30 18:51:59 +00004593 d->fxState[0].offset = OFFB_FTOP;
sewardj9fc9e782004-11-26 17:57:40 +00004594 d->fxState[0].size = sizeof(UInt);
4595
4596 d->fxState[1].fx = Ifx_Write;
sewardjc9a43662004-11-30 18:51:59 +00004597 d->fxState[1].offset = OFFB_FPREGS;
sewardj9fc9e782004-11-26 17:57:40 +00004598 d->fxState[1].size = 8 * sizeof(ULong);
4599
4600 d->fxState[2].fx = Ifx_Write;
sewardjc9a43662004-11-30 18:51:59 +00004601 d->fxState[2].offset = OFFB_FPTAGS;
sewardj9fc9e782004-11-26 17:57:40 +00004602 d->fxState[2].size = 8 * sizeof(UChar);
4603
4604 d->fxState[3].fx = Ifx_Write;
sewardjc9a43662004-11-30 18:51:59 +00004605 d->fxState[3].offset = OFFB_FPROUND;
sewardj9fc9e782004-11-26 17:57:40 +00004606 d->fxState[3].size = sizeof(UInt);
4607
4608 d->fxState[4].fx = Ifx_Write;
sewardjc9a43662004-11-30 18:51:59 +00004609 d->fxState[4].offset = OFFB_FC3210;
sewardj9fc9e782004-11-26 17:57:40 +00004610 d->fxState[4].size = sizeof(UInt);
4611
4612 stmt( IRStmt_Dirty(d) );
4613
sewardj893aada2004-11-29 19:57:54 +00004614 /* ew contains any emulation warning we may need to
4615 issue. If needed, side-exit to the next insn,
4616 reporting the warning, so that Valgrind's dispatcher
4617 sees the warning. */
4618 put_emwarn( mkexpr(ew) );
4619 stmt(
4620 IRStmt_Exit(
4621 binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
4622 Ijk_EmWarn,
4623 IRConst_U32( ((Addr32)guest_eip_bbstart)+delta)
4624 )
4625 );
4626
sewardj33dd31b2005-01-08 18:17:32 +00004627 DIP("frstor %s\n", dis_buf);
sewardj9fc9e782004-11-26 17:57:40 +00004628 break;
4629 }
4630
4631 case 6: { /* FNSAVE m108 */
sewardj893aada2004-11-29 19:57:54 +00004632 /* Uses dirty helper:
4633 void x86g_do_FSAVE ( VexGuestX86State*, UInt ) */
sewardj9fc9e782004-11-26 17:57:40 +00004634 IRDirty* d = unsafeIRDirty_0_N (
4635 0/*regparms*/,
4636 "x86g_dirtyhelper_FSAVE",
4637 &x86g_dirtyhelper_FSAVE,
4638 mkIRExprVec_1( mkexpr(addr) )
4639 );
4640 d->needsBBP = True;
4641 /* declare we're writing memory */
4642 d->mFx = Ifx_Write;
4643 d->mAddr = mkexpr(addr);
4644 d->mSize = 108;
4645
4646 /* declare we're reading guest state */
sewardj893aada2004-11-29 19:57:54 +00004647 d->nFxState = 5;
sewardj9fc9e782004-11-26 17:57:40 +00004648
4649 d->fxState[0].fx = Ifx_Read;
sewardjc9a43662004-11-30 18:51:59 +00004650 d->fxState[0].offset = OFFB_FTOP;
sewardj9fc9e782004-11-26 17:57:40 +00004651 d->fxState[0].size = sizeof(UInt);
4652
4653 d->fxState[1].fx = Ifx_Read;
sewardjc9a43662004-11-30 18:51:59 +00004654 d->fxState[1].offset = OFFB_FPREGS;
sewardj9fc9e782004-11-26 17:57:40 +00004655 d->fxState[1].size = 8 * sizeof(ULong);
4656
4657 d->fxState[2].fx = Ifx_Read;
sewardjc9a43662004-11-30 18:51:59 +00004658 d->fxState[2].offset = OFFB_FPTAGS;
sewardj9fc9e782004-11-26 17:57:40 +00004659 d->fxState[2].size = 8 * sizeof(UChar);
4660
4661 d->fxState[3].fx = Ifx_Read;
sewardjc9a43662004-11-30 18:51:59 +00004662 d->fxState[3].offset = OFFB_FPROUND;
sewardj9fc9e782004-11-26 17:57:40 +00004663 d->fxState[3].size = sizeof(UInt);
4664
4665 d->fxState[4].fx = Ifx_Read;
sewardjc9a43662004-11-30 18:51:59 +00004666 d->fxState[4].offset = OFFB_FC3210;
sewardj9fc9e782004-11-26 17:57:40 +00004667 d->fxState[4].size = sizeof(UInt);
4668
4669 stmt( IRStmt_Dirty(d) );
4670
sewardj33dd31b2005-01-08 18:17:32 +00004671 DIP("fnsave %s\n", dis_buf);
sewardj9fc9e782004-11-26 17:57:40 +00004672 break;
4673 }
4674
sewardjd24931d2005-03-20 12:51:39 +00004675 case 7: { /* FNSTSW m16 */
4676 IRExpr* sw = get_FPU_sw();
4677 vassert(typeOfIRExpr(irbb->tyenv, sw) == Ity_I16);
4678 storeLE( mkexpr(addr), sw );
4679 DIP("fnstsw %s\n", dis_buf);
4680 break;
4681 }
4682
sewardjd1725d12004-08-12 20:46:53 +00004683 default:
sewardjbb53f8c2004-08-14 11:50:01 +00004684 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
4685 vex_printf("first_opcode == 0xDD\n");
sewardjd1725d12004-08-12 20:46:53 +00004686 goto decode_fail;
sewardjbb53f8c2004-08-14 11:50:01 +00004687 }
sewardjd1725d12004-08-12 20:46:53 +00004688 } else {
sewardja58ea662004-08-15 03:12:41 +00004689 delta++;
4690 switch (modrm) {
sewardjbdc7d212004-09-09 02:46:40 +00004691
sewardj3ddedc42005-03-25 20:30:00 +00004692 case 0xC0 ... 0xC7: /* FFREE %st(?) */
4693 r_dst = (UInt)modrm - 0xC0;
sewardj4a6f3842005-03-26 11:59:23 +00004694 DIP("ffree %%st(%d)\n", (Int)r_dst);
sewardj3ddedc42005-03-25 20:30:00 +00004695 put_ST_TAG ( r_dst, mkU8(0) );
4696 break;
4697
sewardj06c32a02004-09-12 12:07:34 +00004698 case 0xD0 ... 0xD7: /* FST %st(0),%st(?) */
4699 r_dst = (UInt)modrm - 0xD0;
sewardj2d49b432005-02-01 00:37:06 +00004700 DIP("fst %%st(0),%%st(%d)\n", (Int)r_dst);
sewardj5bd4d162004-11-10 13:02:48 +00004701 /* P4 manual says: "If the destination operand is a
sewardj06c32a02004-09-12 12:07:34 +00004702 non-empty register, the invalid-operation exception
4703 is not generated. Hence put_ST_UNCHECKED. */
4704 put_ST_UNCHECKED(r_dst, get_ST(0));
4705 break;
4706
sewardja58ea662004-08-15 03:12:41 +00004707 case 0xD8 ... 0xDF: /* FSTP %st(0),%st(?) */
4708 r_dst = (UInt)modrm - 0xD8;
sewardj2d49b432005-02-01 00:37:06 +00004709 DIP("fstp %%st(0),%%st(%d)\n", (Int)r_dst);
sewardj5bd4d162004-11-10 13:02:48 +00004710 /* P4 manual says: "If the destination operand is a
sewardj207557a2004-08-27 12:00:18 +00004711 non-empty register, the invalid-operation exception
4712 is not generated. Hence put_ST_UNCHECKED. */
4713 put_ST_UNCHECKED(r_dst, get_ST(0));
4714 fp_pop();
sewardja58ea662004-08-15 03:12:41 +00004715 break;
sewardjbdc7d212004-09-09 02:46:40 +00004716
4717 case 0xE0 ... 0xE7: /* FUCOM %st(0),%st(?) */
4718 r_dst = (UInt)modrm - 0xE0;
sewardj2d49b432005-02-01 00:37:06 +00004719 DIP("fucom %%st(0),%%st(%d)\n", (Int)r_dst);
sewardjc4be80c2004-09-10 16:17:45 +00004720 /* This forces C1 to zero, which isn't right. */
4721 put_C3210(
4722 binop( Iop_And32,
4723 binop(Iop_Shl32,
4724 binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
4725 mkU8(8)),
4726 mkU32(0x4500)
4727 ));
sewardjbdc7d212004-09-09 02:46:40 +00004728 break;
4729
4730 case 0xE8 ... 0xEF: /* FUCOMP %st(0),%st(?) */
4731 r_dst = (UInt)modrm - 0xE8;
sewardj2d49b432005-02-01 00:37:06 +00004732 DIP("fucomp %%st(0),%%st(%d)\n", (Int)r_dst);
sewardjc4be80c2004-09-10 16:17:45 +00004733 /* This forces C1 to zero, which isn't right. */
4734 put_C3210(
4735 binop( Iop_And32,
4736 binop(Iop_Shl32,
4737 binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
4738 mkU8(8)),
4739 mkU32(0x4500)
4740 ));
sewardjbdc7d212004-09-09 02:46:40 +00004741 fp_pop();
4742 break;
4743
sewardj5bd4d162004-11-10 13:02:48 +00004744 default:
sewardja58ea662004-08-15 03:12:41 +00004745 goto decode_fail;
sewardj5bd4d162004-11-10 13:02:48 +00004746 }
sewardjd1725d12004-08-12 20:46:53 +00004747 }
4748 }
4749
4750 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDE opcodes +-+-+-+-+-+-+-+ */
4751 else
4752 if (first_opcode == 0xDE) {
sewardjbdc7d212004-09-09 02:46:40 +00004753
4754 if (modrm < 0xC0) {
sewardjfeeb8a82004-11-30 12:30:11 +00004755
4756 /* bits 5,4,3 are an opcode extension, and the modRM also
4757 specifies an address. */
4758 IROp fop;
4759 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
4760 delta += len;
4761
4762 switch (gregOfRM(modrm)) {
4763
4764 case 0: /* FIADD m16int */ /* ST(0) += m16int */
sewardj33dd31b2005-01-08 18:17:32 +00004765 DIP("fiaddw %s\n", dis_buf);
sewardjfeeb8a82004-11-30 12:30:11 +00004766 fop = Iop_AddF64;
4767 goto do_fop_m16;
4768
4769 case 1: /* FIMUL m16int */ /* ST(0) *= m16int */
sewardj33dd31b2005-01-08 18:17:32 +00004770 DIP("fimulw %s\n", dis_buf);
sewardjfeeb8a82004-11-30 12:30:11 +00004771 fop = Iop_MulF64;
4772 goto do_fop_m16;
4773
4774 case 4: /* FISUB m16int */ /* ST(0) -= m16int */
sewardj33dd31b2005-01-08 18:17:32 +00004775 DIP("fisubw %s\n", dis_buf);
sewardjfeeb8a82004-11-30 12:30:11 +00004776 fop = Iop_SubF64;
4777 goto do_fop_m16;
4778
4779 case 5: /* FISUBR m16int */ /* ST(0) = m16int - ST(0) */
sewardj33dd31b2005-01-08 18:17:32 +00004780 DIP("fisubrw %s\n", dis_buf);
sewardjfeeb8a82004-11-30 12:30:11 +00004781 fop = Iop_SubF64;
4782 goto do_foprev_m16;
4783
4784 case 6: /* FIDIV m16int */ /* ST(0) /= m16int */
sewardj33dd31b2005-01-08 18:17:32 +00004785 DIP("fisubw %s\n", dis_buf);
sewardjfeeb8a82004-11-30 12:30:11 +00004786 fop = Iop_DivF64;
4787 goto do_fop_m16;
4788
4789 case 7: /* FIDIVR m16int */ /* ST(0) = m16int / ST(0) */
sewardj33dd31b2005-01-08 18:17:32 +00004790 DIP("fidivrw %s\n", dis_buf);
sewardjfeeb8a82004-11-30 12:30:11 +00004791 fop = Iop_DivF64;
4792 goto do_foprev_m16;
4793
4794 do_fop_m16:
4795 put_ST_UNCHECKED(0,
4796 binop(fop,
4797 get_ST(0),
4798 unop(Iop_I32toF64,
4799 unop(Iop_16Sto32,
4800 loadLE(Ity_I16, mkexpr(addr))))));
4801 break;
4802
4803 do_foprev_m16:
4804 put_ST_UNCHECKED(0,
4805 binop(fop,
4806 unop(Iop_I32toF64,
4807 unop(Iop_16Sto32,
4808 loadLE(Ity_I16, mkexpr(addr)))),
4809 get_ST(0)));
4810 break;
4811
4812 default:
4813 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
4814 vex_printf("first_opcode == 0xDE\n");
4815 goto decode_fail;
4816 }
sewardjbdc7d212004-09-09 02:46:40 +00004817
4818 } else {
4819
4820 delta++;
sewardj5bd4d162004-11-10 13:02:48 +00004821 switch (modrm) {
sewardjbdc7d212004-09-09 02:46:40 +00004822
sewardjcfded9a2004-09-09 11:44:16 +00004823 case 0xC0 ... 0xC7: /* FADDP %st(0),%st(?) */
4824 fp_do_op_ST_ST ( "add", Iop_AddF64, 0, modrm - 0xC0, True );
4825 break;
4826
sewardjbdc7d212004-09-09 02:46:40 +00004827 case 0xC8 ... 0xCF: /* FMULP %st(0),%st(?) */
4828 fp_do_op_ST_ST ( "mul", Iop_MulF64, 0, modrm - 0xC8, True );
4829 break;
4830
sewardje166ed02004-10-25 02:27:01 +00004831 case 0xD9: /* FCOMPP %st(0),%st(1) */
4832 DIP("fuompp %%st(0),%%st(1)\n");
4833 /* This forces C1 to zero, which isn't right. */
4834 put_C3210(
4835 binop( Iop_And32,
4836 binop(Iop_Shl32,
4837 binop(Iop_CmpF64, get_ST(0), get_ST(1)),
4838 mkU8(8)),
4839 mkU32(0x4500)
4840 ));
4841 fp_pop();
4842 fp_pop();
4843 break;
4844
sewardjcfded9a2004-09-09 11:44:16 +00004845 case 0xE0 ... 0xE7: /* FSUBRP %st(0),%st(?) */
4846 fp_do_oprev_ST_ST ( "subr", Iop_SubF64, 0, modrm - 0xE0, True );
4847 break;
4848
sewardj3fd5e572004-09-09 22:43:51 +00004849 case 0xE8 ... 0xEF: /* FSUBP %st(0),%st(?) */
4850 fp_do_op_ST_ST ( "sub", Iop_SubF64, 0, modrm - 0xE8, True );
4851 break;
4852
sewardjbdc7d212004-09-09 02:46:40 +00004853 case 0xF0 ... 0xF7: /* FDIVRP %st(0),%st(?) */
4854 fp_do_oprev_ST_ST ( "divr", Iop_DivF64, 0, modrm - 0xF0, True );
4855 break;
4856
4857 case 0xF8 ... 0xFF: /* FDIVP %st(0),%st(?) */
4858 fp_do_op_ST_ST ( "div", Iop_DivF64, 0, modrm - 0xF8, True );
4859 break;
4860
4861 default:
4862 goto decode_fail;
sewardj5bd4d162004-11-10 13:02:48 +00004863 }
sewardjbdc7d212004-09-09 02:46:40 +00004864
4865 }
sewardjd1725d12004-08-12 20:46:53 +00004866 }
4867
4868 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDF opcodes +-+-+-+-+-+-+-+ */
4869 else
4870 if (first_opcode == 0xDF) {
sewardj89cd0932004-09-08 18:23:25 +00004871
4872 if (modrm < 0xC0) {
4873
sewardjfeeb8a82004-11-30 12:30:11 +00004874 /* bits 5,4,3 are an opcode extension, and the modRM also
sewardj89cd0932004-09-08 18:23:25 +00004875 specifies an address. */
4876 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
4877 delta += len;
4878
4879 switch (gregOfRM(modrm)) {
4880
sewardj883b00b2004-09-11 09:30:24 +00004881 case 0: /* FILD m16int */
4882 DIP("fildw %s\n", dis_buf);
4883 fp_push();
4884 put_ST(0, unop(Iop_I32toF64,
4885 unop(Iop_16Sto32,
4886 loadLE(Ity_I16, mkexpr(addr)))));
4887 break;
4888
sewardj37158712004-10-15 21:23:12 +00004889 case 2: /* FIST m16 */
sewardj33dd31b2005-01-08 18:17:32 +00004890 DIP("fistp %s\n", dis_buf);
sewardj37158712004-10-15 21:23:12 +00004891 storeLE( mkexpr(addr),
4892 binop(Iop_F64toI16, get_roundingmode(), get_ST(0)) );
4893 break;
4894
sewardj89cd0932004-09-08 18:23:25 +00004895 case 3: /* FISTP m16 */
sewardj33dd31b2005-01-08 18:17:32 +00004896 DIP("fistps %s\n", dis_buf);
sewardj8f3debf2004-09-08 23:42:23 +00004897 storeLE( mkexpr(addr),
4898 binop(Iop_F64toI16, get_roundingmode(), get_ST(0)) );
4899 fp_pop();
sewardj89cd0932004-09-08 18:23:25 +00004900 break;
4901
sewardj89cd0932004-09-08 18:23:25 +00004902 case 5: /* FILD m64 */
4903 DIP("fildll %s\n", dis_buf);
4904 fp_push();
sewardj4cb918d2004-12-03 19:43:31 +00004905 put_ST(0, binop(Iop_I64toF64,
4906 get_roundingmode(),
4907 loadLE(Ity_I64, mkexpr(addr))));
sewardj89cd0932004-09-08 18:23:25 +00004908 break;
sewardj89cd0932004-09-08 18:23:25 +00004909
sewardjcfded9a2004-09-09 11:44:16 +00004910 case 7: /* FISTP m64 */
sewardj33dd31b2005-01-08 18:17:32 +00004911 DIP("fistpll %s\n", dis_buf);
sewardjcfded9a2004-09-09 11:44:16 +00004912 storeLE( mkexpr(addr),
4913 binop(Iop_F64toI64, get_roundingmode(), get_ST(0)) );
4914 fp_pop();
4915 break;
4916
sewardj89cd0932004-09-08 18:23:25 +00004917 default:
4918 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
4919 vex_printf("first_opcode == 0xDF\n");
4920 goto decode_fail;
4921 }
4922
4923 } else {
sewardjbdc7d212004-09-09 02:46:40 +00004924
4925 delta++;
sewardj5bd4d162004-11-10 13:02:48 +00004926 switch (modrm) {
sewardjbdc7d212004-09-09 02:46:40 +00004927
4928 case 0xE0: /* FNSTSW %ax */
4929 DIP("fnstsw %%ax\n");
sewardjd24931d2005-03-20 12:51:39 +00004930 /* Get the FPU status word value and dump it in %AX. */
4931 putIReg(2, R_EAX, get_FPU_sw());
sewardjbdc7d212004-09-09 02:46:40 +00004932 break;
4933
sewardj883b00b2004-09-11 09:30:24 +00004934 case 0xE8 ... 0xEF: /* FUCOMIP %st(0),%st(?) */
sewardj8308aad2004-09-12 11:09:54 +00004935 fp_do_ucomi_ST0_STi( (UInt)modrm - 0xE8, True );
sewardj883b00b2004-09-11 09:30:24 +00004936 break;
4937
sewardjfeeb8a82004-11-30 12:30:11 +00004938 case 0xF0 ... 0xF7: /* FCOMIP %st(0),%st(?) */
4939 /* not really right since COMIP != UCOMIP */
4940 fp_do_ucomi_ST0_STi( (UInt)modrm - 0xF0, True );
4941 break;
4942
sewardjbdc7d212004-09-09 02:46:40 +00004943 default:
4944 goto decode_fail;
sewardj5bd4d162004-11-10 13:02:48 +00004945 }
sewardj89cd0932004-09-08 18:23:25 +00004946 }
4947
sewardjd1725d12004-08-12 20:46:53 +00004948 }
4949
4950 else
4951 vpanic("dis_FPU(x86): invalid primary opcode");
4952
sewardj69d9d662004-10-14 21:58:52 +00004953 *decode_ok = True;
4954 return delta;
4955
sewardjd1725d12004-08-12 20:46:53 +00004956 decode_fail:
4957 *decode_ok = False;
4958 return delta;
4959}
4960
4961
sewardj464efa42004-11-19 22:17:29 +00004962/*------------------------------------------------------------*/
4963/*--- ---*/
4964/*--- MMX INSTRUCTIONS ---*/
4965/*--- ---*/
4966/*------------------------------------------------------------*/
sewardja06e5562004-07-14 13:18:05 +00004967
sewardj464efa42004-11-19 22:17:29 +00004968/* Effect of MMX insns on x87 FPU state (table 11-2 of
4969 IA32 arch manual, volume 3):
4970
4971 Read from, or write to MMX register (viz, any insn except EMMS):
4972 * All tags set to Valid (non-empty) -- FPTAGS[i] := nonzero
4973 * FP stack pointer set to zero
4974
4975 EMMS:
4976 * All tags set to Invalid (empty) -- FPTAGS[i] := zero
4977 * FP stack pointer set to zero
4978*/
4979
sewardj4cb918d2004-12-03 19:43:31 +00004980static void do_MMX_preamble ( void )
sewardj464efa42004-11-19 22:17:29 +00004981{
4982 Int i;
4983 IRArray* descr = mkIRArray( OFFB_FPTAGS, Ity_I8, 8 );
4984 IRExpr* zero = mkU32(0);
4985 IRExpr* tag1 = mkU8(1);
4986 put_ftop(zero);
4987 for (i = 0; i < 8; i++)
4988 stmt( IRStmt_PutI( descr, zero, i, tag1 ) );
4989}
4990
sewardj4cb918d2004-12-03 19:43:31 +00004991static void do_EMMS_preamble ( void )
sewardj464efa42004-11-19 22:17:29 +00004992{
4993 Int i;
4994 IRArray* descr = mkIRArray( OFFB_FPTAGS, Ity_I8, 8 );
4995 IRExpr* zero = mkU32(0);
4996 IRExpr* tag0 = mkU8(0);
4997 put_ftop(zero);
4998 for (i = 0; i < 8; i++)
4999 stmt( IRStmt_PutI( descr, zero, i, tag0 ) );
5000}
5001
5002
5003static IRExpr* getMMXReg ( UInt archreg )
5004{
5005 vassert(archreg < 8);
5006 return IRExpr_Get( OFFB_FPREGS + 8 * archreg, Ity_I64 );
5007}
5008
5009
5010static void putMMXReg ( UInt archreg, IRExpr* e )
5011{
5012 vassert(archreg < 8);
5013 vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_I64);
5014 stmt( IRStmt_Put( OFFB_FPREGS + 8 * archreg, e ) );
5015}
5016
5017
sewardj38a3f862005-01-13 15:06:51 +00005018/* Helper for non-shift MMX insns. Note this is incomplete in the
5019 sense that it does not first call do_MMX_preamble() -- that is the
5020 responsibility of its caller. */
5021
sewardj464efa42004-11-19 22:17:29 +00005022static
sewardj2d49b432005-02-01 00:37:06 +00005023UInt dis_MMXop_regmem_to_reg ( UChar sorb,
5024 UInt delta,
5025 UChar opc,
5026 HChar* name,
5027 Bool show_granularity )
sewardj464efa42004-11-19 22:17:29 +00005028{
sewardjc9a43662004-11-30 18:51:59 +00005029 HChar dis_buf[50];
sewardj63ba4092004-11-21 12:30:18 +00005030 UChar modrm = getIByte(delta);
5031 Bool isReg = epartIsReg(modrm);
5032 IRExpr* argL = NULL;
5033 IRExpr* argR = NULL;
sewardj38a3f862005-01-13 15:06:51 +00005034 IRExpr* argG = NULL;
5035 IRExpr* argE = NULL;
sewardj63ba4092004-11-21 12:30:18 +00005036 IRTemp res = newTemp(Ity_I64);
sewardj464efa42004-11-19 22:17:29 +00005037
sewardj38a3f862005-01-13 15:06:51 +00005038 Bool invG = False;
5039 IROp op = Iop_INVALID;
5040 void* hAddr = NULL;
sewardj2d49b432005-02-01 00:37:06 +00005041 HChar* hName = NULL;
sewardj38a3f862005-01-13 15:06:51 +00005042 Bool eLeft = False;
5043
sewardj2b7a9202004-11-26 19:15:38 +00005044# define XXX(_name) do { hAddr = &_name; hName = #_name; } while (0)
sewardj464efa42004-11-19 22:17:29 +00005045
sewardj464efa42004-11-19 22:17:29 +00005046 switch (opc) {
sewardjb5452082004-12-04 20:33:02 +00005047 /* Original MMX ones */
sewardj38a3f862005-01-13 15:06:51 +00005048 case 0xFC: op = Iop_Add8x8; break;
5049 case 0xFD: op = Iop_Add16x4; break;
5050 case 0xFE: op = Iop_Add32x2; break;
sewardj464efa42004-11-19 22:17:29 +00005051
sewardj38a3f862005-01-13 15:06:51 +00005052 case 0xEC: op = Iop_QAdd8Sx8; break;
5053 case 0xED: op = Iop_QAdd16Sx4; break;
sewardj464efa42004-11-19 22:17:29 +00005054
sewardj38a3f862005-01-13 15:06:51 +00005055 case 0xDC: op = Iop_QAdd8Ux8; break;
5056 case 0xDD: op = Iop_QAdd16Ux4; break;
sewardj464efa42004-11-19 22:17:29 +00005057
sewardj38a3f862005-01-13 15:06:51 +00005058 case 0xF8: op = Iop_Sub8x8; break;
5059 case 0xF9: op = Iop_Sub16x4; break;
5060 case 0xFA: op = Iop_Sub32x2; break;
sewardj464efa42004-11-19 22:17:29 +00005061
sewardj38a3f862005-01-13 15:06:51 +00005062 case 0xE8: op = Iop_QSub8Sx8; break;
5063 case 0xE9: op = Iop_QSub16Sx4; break;
sewardj464efa42004-11-19 22:17:29 +00005064
sewardj38a3f862005-01-13 15:06:51 +00005065 case 0xD8: op = Iop_QSub8Ux8; break;
5066 case 0xD9: op = Iop_QSub16Ux4; break;
sewardj464efa42004-11-19 22:17:29 +00005067
sewardj38a3f862005-01-13 15:06:51 +00005068 case 0xE5: op = Iop_MulHi16Sx4; break;
5069 case 0xD5: op = Iop_Mul16x4; break;
5070 case 0xF5: XXX(x86g_calculate_mmx_pmaddwd); break;
sewardj4340dac2004-11-20 13:17:04 +00005071
sewardj38a3f862005-01-13 15:06:51 +00005072 case 0x74: op = Iop_CmpEQ8x8; break;
5073 case 0x75: op = Iop_CmpEQ16x4; break;
5074 case 0x76: op = Iop_CmpEQ32x2; break;
sewardj4340dac2004-11-20 13:17:04 +00005075
sewardj38a3f862005-01-13 15:06:51 +00005076 case 0x64: op = Iop_CmpGT8Sx8; break;
5077 case 0x65: op = Iop_CmpGT16Sx4; break;
5078 case 0x66: op = Iop_CmpGT32Sx2; break;
sewardj63ba4092004-11-21 12:30:18 +00005079
sewardj38a3f862005-01-13 15:06:51 +00005080 case 0x6B: op = Iop_QNarrow32Sx2; eLeft = True; break;
5081 case 0x63: op = Iop_QNarrow16Sx4; eLeft = True; break;
5082 case 0x67: op = Iop_QNarrow16Ux4; eLeft = True; break;
sewardj63ba4092004-11-21 12:30:18 +00005083
sewardj38a3f862005-01-13 15:06:51 +00005084 case 0x68: op = Iop_InterleaveHI8x8; eLeft = True; break;
5085 case 0x69: op = Iop_InterleaveHI16x4; eLeft = True; break;
5086 case 0x6A: op = Iop_InterleaveHI32x2; eLeft = True; break;
sewardj63ba4092004-11-21 12:30:18 +00005087
sewardj38a3f862005-01-13 15:06:51 +00005088 case 0x60: op = Iop_InterleaveLO8x8; eLeft = True; break;
5089 case 0x61: op = Iop_InterleaveLO16x4; eLeft = True; break;
5090 case 0x62: op = Iop_InterleaveLO32x2; eLeft = True; break;
sewardj63ba4092004-11-21 12:30:18 +00005091
sewardj38a3f862005-01-13 15:06:51 +00005092 case 0xDB: op = Iop_And64; break;
5093 case 0xDF: op = Iop_And64; invG = True; break;
5094 case 0xEB: op = Iop_Or64; break;
5095 case 0xEF: /* Possibly do better here if argL and argR are the
5096 same reg */
5097 op = Iop_Xor64; break;
sewardj464efa42004-11-19 22:17:29 +00005098
sewardjb5452082004-12-04 20:33:02 +00005099 /* Introduced in SSE1 */
sewardj38a3f862005-01-13 15:06:51 +00005100 case 0xE0: op = Iop_Avg8Ux8; break;
5101 case 0xE3: op = Iop_Avg16Ux4; break;
5102 case 0xEE: op = Iop_Max16Sx4; break;
5103 case 0xDE: op = Iop_Max8Ux8; break;
5104 case 0xEA: op = Iop_Min16Sx4; break;
5105 case 0xDA: op = Iop_Min8Ux8; break;
5106 case 0xE4: op = Iop_MulHi16Ux4; break;
5107 case 0xF6: XXX(x86g_calculate_mmx_psadbw); break;
sewardjb5452082004-12-04 20:33:02 +00005108
sewardj164f9272004-12-09 00:39:32 +00005109 /* Introduced in SSE2 */
sewardj38a3f862005-01-13 15:06:51 +00005110 case 0xD4: op = Iop_Add64; break;
5111 case 0xFB: op = Iop_Sub64; break;
sewardj164f9272004-12-09 00:39:32 +00005112
sewardj464efa42004-11-19 22:17:29 +00005113 default:
5114 vex_printf("\n0x%x\n", (Int)opc);
5115 vpanic("dis_MMXop_regmem_to_reg");
5116 }
5117
5118# undef XXX
5119
sewardj38a3f862005-01-13 15:06:51 +00005120 argG = getMMXReg(gregOfRM(modrm));
5121 if (invG)
5122 argG = unop(Iop_Not64, argG);
sewardj63ba4092004-11-21 12:30:18 +00005123
sewardj464efa42004-11-19 22:17:29 +00005124 if (isReg) {
sewardj464efa42004-11-19 22:17:29 +00005125 delta++;
sewardj38a3f862005-01-13 15:06:51 +00005126 argE = getMMXReg(eregOfRM(modrm));
sewardj464efa42004-11-19 22:17:29 +00005127 } else {
5128 Int len;
5129 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5130 delta += len;
sewardj38a3f862005-01-13 15:06:51 +00005131 argE = loadLE(Ity_I64, mkexpr(addr));
sewardj464efa42004-11-19 22:17:29 +00005132 }
5133
sewardj38a3f862005-01-13 15:06:51 +00005134 if (eLeft) {
5135 argL = argE;
5136 argR = argG;
5137 } else {
5138 argL = argG;
5139 argR = argE;
5140 }
5141
5142 if (op != Iop_INVALID) {
5143 vassert(hName == NULL);
5144 vassert(hAddr == NULL);
5145 assign(res, binop(op, argL, argR));
5146 } else {
5147 vassert(hName != NULL);
5148 vassert(hAddr != NULL);
5149 assign( res,
5150 mkIRExprCCall(
5151 Ity_I64,
5152 0/*regparms*/, hName, hAddr,
5153 mkIRExprVec_2( argL, argR )
5154 )
5155 );
sewardj63ba4092004-11-21 12:30:18 +00005156 }
5157
5158 putMMXReg( gregOfRM(modrm), mkexpr(res) );
5159
sewardj464efa42004-11-19 22:17:29 +00005160 DIP("%s%s %s, %s\n",
sewardj2d49b432005-02-01 00:37:06 +00005161 name, show_granularity ? nameMMXGran(opc & 3) : "",
sewardj464efa42004-11-19 22:17:29 +00005162 ( isReg ? nameMMXReg(eregOfRM(modrm)) : dis_buf ),
5163 nameMMXReg(gregOfRM(modrm)) );
5164
5165 return delta;
5166}
5167
5168
sewardj38a3f862005-01-13 15:06:51 +00005169/* Vector by scalar shift of G by the amount specified at the bottom
5170 of E. This is a straight copy of dis_SSE_shiftG_byE. */
5171
5172static UInt dis_MMX_shiftG_byE ( UChar sorb, UInt delta,
5173 HChar* opname, IROp op )
5174{
5175 HChar dis_buf[50];
5176 Int alen, size;
5177 IRTemp addr;
5178 Bool shl, shr, sar;
5179 UChar rm = getIByte(delta);
5180 IRTemp g0 = newTemp(Ity_I64);
5181 IRTemp g1 = newTemp(Ity_I64);
5182 IRTemp amt = newTemp(Ity_I32);
5183 IRTemp amt8 = newTemp(Ity_I8);
5184
5185 if (epartIsReg(rm)) {
5186 assign( amt, unop(Iop_64to32, getMMXReg(eregOfRM(rm))) );
5187 DIP("%s %s,%s\n", opname,
5188 nameMMXReg(eregOfRM(rm)),
5189 nameMMXReg(gregOfRM(rm)) );
5190 delta++;
5191 } else {
5192 addr = disAMode ( &alen, sorb, delta, dis_buf );
5193 assign( amt, loadLE(Ity_I32, mkexpr(addr)) );
5194 DIP("%s %s,%s\n", opname,
5195 dis_buf,
5196 nameMMXReg(gregOfRM(rm)) );
5197 delta += alen;
5198 }
5199 assign( g0, getMMXReg(gregOfRM(rm)) );
5200 assign( amt8, unop(Iop_32to8, mkexpr(amt)) );
5201
5202 shl = shr = sar = False;
5203 size = 0;
5204 switch (op) {
5205 case Iop_ShlN16x4: shl = True; size = 32; break;
5206 case Iop_ShlN32x2: shl = True; size = 32; break;
5207 case Iop_Shl64: shl = True; size = 64; break;
5208 case Iop_ShrN16x4: shr = True; size = 16; break;
5209 case Iop_ShrN32x2: shr = True; size = 32; break;
5210 case Iop_Shr64: shr = True; size = 64; break;
5211 case Iop_SarN16x4: sar = True; size = 16; break;
5212 case Iop_SarN32x2: sar = True; size = 32; break;
5213 default: vassert(0);
5214 }
5215
5216 if (shl || shr) {
5217 assign(
5218 g1,
5219 IRExpr_Mux0X(
5220 unop(Iop_1Uto8,binop(Iop_CmpLT32U,mkexpr(amt),mkU32(size))),
5221 mkU64(0),
5222 binop(op, mkexpr(g0), mkexpr(amt8))
5223 )
5224 );
5225 } else
5226 if (sar) {
5227 assign(
5228 g1,
5229 IRExpr_Mux0X(
5230 unop(Iop_1Uto8,binop(Iop_CmpLT32U,mkexpr(amt),mkU32(size))),
5231 binop(op, mkexpr(g0), mkU8(size-1)),
5232 binop(op, mkexpr(g0), mkexpr(amt8))
5233 )
5234 );
5235 } else {
sewardjba89f4c2005-04-07 17:31:27 +00005236 /*NOTREACHED*/
sewardj38a3f862005-01-13 15:06:51 +00005237 vassert(0);
5238 }
5239
5240 putMMXReg( gregOfRM(rm), mkexpr(g1) );
5241 return delta;
5242}
5243
5244
5245/* Vector by scalar shift of E by an immediate byte. This is a
5246 straight copy of dis_SSE_shiftE_imm. */
5247
5248static
5249UInt dis_MMX_shiftE_imm ( UInt delta, HChar* opname, IROp op )
5250{
5251 Bool shl, shr, sar;
5252 UChar rm = getIByte(delta);
5253 IRTemp e0 = newTemp(Ity_I64);
5254 IRTemp e1 = newTemp(Ity_I64);
5255 UChar amt, size;
5256 vassert(epartIsReg(rm));
5257 vassert(gregOfRM(rm) == 2
5258 || gregOfRM(rm) == 4 || gregOfRM(rm) == 6);
sewardj2d49b432005-02-01 00:37:06 +00005259 amt = getIByte(delta+1);
sewardj38a3f862005-01-13 15:06:51 +00005260 delta += 2;
5261 DIP("%s $%d,%s\n", opname,
5262 (Int)amt,
5263 nameMMXReg(eregOfRM(rm)) );
5264
5265 assign( e0, getMMXReg(eregOfRM(rm)) );
5266
5267 shl = shr = sar = False;
5268 size = 0;
5269 switch (op) {
5270 case Iop_ShlN16x4: shl = True; size = 16; break;
5271 case Iop_ShlN32x2: shl = True; size = 32; break;
5272 case Iop_Shl64: shl = True; size = 64; break;
5273 case Iop_SarN16x4: sar = True; size = 16; break;
5274 case Iop_SarN32x2: sar = True; size = 32; break;
5275 case Iop_ShrN16x4: shr = True; size = 16; break;
5276 case Iop_ShrN32x2: shr = True; size = 32; break;
5277 case Iop_Shr64: shr = True; size = 64; break;
5278 default: vassert(0);
5279 }
5280
5281 if (shl || shr) {
sewardjba89f4c2005-04-07 17:31:27 +00005282 assign( e1, amt >= size
5283 ? mkU64(0)
5284 : binop(op, mkexpr(e0), mkU8(amt))
5285 );
sewardj38a3f862005-01-13 15:06:51 +00005286 } else
5287 if (sar) {
sewardjba89f4c2005-04-07 17:31:27 +00005288 assign( e1, amt >= size
5289 ? binop(op, mkexpr(e0), mkU8(size-1))
5290 : binop(op, mkexpr(e0), mkU8(amt))
5291 );
sewardj38a3f862005-01-13 15:06:51 +00005292 } else {
sewardjba89f4c2005-04-07 17:31:27 +00005293 /*NOTREACHED*/
sewardj38a3f862005-01-13 15:06:51 +00005294 vassert(0);
5295 }
5296
5297 putMMXReg( eregOfRM(rm), mkexpr(e1) );
5298 return delta;
5299}
5300
5301
5302/* Completely handle all MMX instructions except emms. */
sewardj464efa42004-11-19 22:17:29 +00005303
5304static
5305UInt dis_MMX ( Bool* decode_ok, UChar sorb, Int sz, UInt delta )
5306{
5307 Int len;
5308 UChar modrm;
sewardjc9a43662004-11-30 18:51:59 +00005309 HChar dis_buf[50];
sewardj464efa42004-11-19 22:17:29 +00005310 UChar opc = getIByte(delta);
5311 delta++;
5312
sewardj4cb918d2004-12-03 19:43:31 +00005313 /* dis_MMX handles all insns except emms. */
5314 do_MMX_preamble();
sewardj464efa42004-11-19 22:17:29 +00005315
5316 switch (opc) {
5317
sewardj2b7a9202004-11-26 19:15:38 +00005318 case 0x6E:
5319 /* MOVD (src)ireg-or-mem (E), (dst)mmxreg (G)*/
sewardj9df271d2004-12-31 22:37:42 +00005320 if (sz != 4)
5321 goto mmx_decode_failure;
sewardj2b7a9202004-11-26 19:15:38 +00005322 modrm = getIByte(delta);
5323 if (epartIsReg(modrm)) {
5324 delta++;
5325 putMMXReg(
5326 gregOfRM(modrm),
5327 binop( Iop_32HLto64,
5328 mkU32(0),
5329 getIReg(4, eregOfRM(modrm)) ) );
5330 DIP("movd %s, %s\n",
5331 nameIReg(4,eregOfRM(modrm)), nameMMXReg(gregOfRM(modrm)));
5332 } else {
5333 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5334 delta += len;
5335 putMMXReg(
5336 gregOfRM(modrm),
5337 binop( Iop_32HLto64,
5338 mkU32(0),
5339 loadLE(Ity_I32, mkexpr(addr)) ) );
5340 DIP("movd %s, %s\n", dis_buf, nameMMXReg(gregOfRM(modrm)));
5341 }
5342 break;
5343
5344 case 0x7E: /* MOVD (src)mmxreg (G), (dst)ireg-or-mem (E) */
sewardj9df271d2004-12-31 22:37:42 +00005345 if (sz != 4)
5346 goto mmx_decode_failure;
sewardj2b7a9202004-11-26 19:15:38 +00005347 modrm = getIByte(delta);
5348 if (epartIsReg(modrm)) {
5349 delta++;
5350 putIReg( 4, eregOfRM(modrm),
5351 unop(Iop_64to32, getMMXReg(gregOfRM(modrm)) ) );
5352 DIP("movd %s, %s\n",
5353 nameMMXReg(gregOfRM(modrm)), nameIReg(4,eregOfRM(modrm)));
5354 } else {
5355 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5356 delta += len;
5357 storeLE( mkexpr(addr),
5358 unop(Iop_64to32, getMMXReg(gregOfRM(modrm)) ) );
5359 DIP("movd %s, %s\n", nameMMXReg(gregOfRM(modrm)), dis_buf);
5360 }
5361 break;
5362
sewardj464efa42004-11-19 22:17:29 +00005363 case 0x6F:
5364 /* MOVQ (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005365 if (sz != 4)
5366 goto mmx_decode_failure;
sewardj464efa42004-11-19 22:17:29 +00005367 modrm = getIByte(delta);
5368 if (epartIsReg(modrm)) {
5369 delta++;
5370 putMMXReg( gregOfRM(modrm), getMMXReg(eregOfRM(modrm)) );
5371 DIP("movq %s, %s\n",
5372 nameMMXReg(eregOfRM(modrm)), nameMMXReg(gregOfRM(modrm)));
5373 } else {
5374 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5375 delta += len;
5376 putMMXReg( gregOfRM(modrm), loadLE(Ity_I64, mkexpr(addr)) );
5377 DIP("movq %s, %s\n",
5378 dis_buf, nameMMXReg(gregOfRM(modrm)));
5379 }
5380 break;
5381
5382 case 0x7F:
5383 /* MOVQ (src)mmxreg, (dst)mmxreg-or-mem */
sewardj9df271d2004-12-31 22:37:42 +00005384 if (sz != 4)
5385 goto mmx_decode_failure;
sewardj464efa42004-11-19 22:17:29 +00005386 modrm = getIByte(delta);
5387 if (epartIsReg(modrm)) {
sewardjc2feffc2004-12-08 12:31:22 +00005388 /* Fall through. The assembler doesn't appear to generate
5389 these. */
5390 goto mmx_decode_failure;
sewardj464efa42004-11-19 22:17:29 +00005391 } else {
5392 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5393 delta += len;
sewardj893aada2004-11-29 19:57:54 +00005394 storeLE( mkexpr(addr), getMMXReg(gregOfRM(modrm)) );
sewardj464efa42004-11-19 22:17:29 +00005395 DIP("mov(nt)q %s, %s\n",
5396 nameMMXReg(gregOfRM(modrm)), dis_buf);
5397 }
5398 break;
5399
sewardj4340dac2004-11-20 13:17:04 +00005400 case 0xFC:
5401 case 0xFD:
5402 case 0xFE: /* PADDgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005403 if (sz != 4)
5404 goto mmx_decode_failure;
sewardj464efa42004-11-19 22:17:29 +00005405 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "padd", True );
5406 break;
5407
sewardj4340dac2004-11-20 13:17:04 +00005408 case 0xEC:
5409 case 0xED: /* PADDSgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005410 if (sz != 4)
5411 goto mmx_decode_failure;
sewardj464efa42004-11-19 22:17:29 +00005412 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "padds", True );
5413 break;
5414
sewardj4340dac2004-11-20 13:17:04 +00005415 case 0xDC:
5416 case 0xDD: /* PADDUSgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005417 if (sz != 4)
5418 goto mmx_decode_failure;
sewardj464efa42004-11-19 22:17:29 +00005419 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "paddus", True );
5420 break;
5421
sewardj4340dac2004-11-20 13:17:04 +00005422 case 0xF8:
5423 case 0xF9:
5424 case 0xFA: /* PSUBgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005425 if (sz != 4)
5426 goto mmx_decode_failure;
sewardj464efa42004-11-19 22:17:29 +00005427 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "psub", True );
5428 break;
5429
sewardj4340dac2004-11-20 13:17:04 +00005430 case 0xE8:
5431 case 0xE9: /* PSUBSgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005432 if (sz != 4)
5433 goto mmx_decode_failure;
sewardj464efa42004-11-19 22:17:29 +00005434 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "psubs", True );
5435 break;
5436
sewardj4340dac2004-11-20 13:17:04 +00005437 case 0xD8:
5438 case 0xD9: /* PSUBUSgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005439 if (sz != 4)
5440 goto mmx_decode_failure;
sewardj464efa42004-11-19 22:17:29 +00005441 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "psubus", True );
5442 break;
5443
5444 case 0xE5: /* PMULHW (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005445 if (sz != 4)
5446 goto mmx_decode_failure;
sewardj464efa42004-11-19 22:17:29 +00005447 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pmulhw", False );
5448 break;
5449
5450 case 0xD5: /* PMULLW (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005451 if (sz != 4)
5452 goto mmx_decode_failure;
sewardj464efa42004-11-19 22:17:29 +00005453 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pmullw", False );
5454 break;
5455
sewardj4340dac2004-11-20 13:17:04 +00005456 case 0xF5: /* PMADDWD (src)mmxreg-or-mem, (dst)mmxreg */
5457 vassert(sz == 4);
5458 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pmaddwd", False );
5459 break;
5460
5461 case 0x74:
5462 case 0x75:
5463 case 0x76: /* PCMPEQgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005464 if (sz != 4)
5465 goto mmx_decode_failure;
sewardj4340dac2004-11-20 13:17:04 +00005466 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pcmpeq", True );
5467 break;
5468
5469 case 0x64:
5470 case 0x65:
5471 case 0x66: /* PCMPGTgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005472 if (sz != 4)
5473 goto mmx_decode_failure;
sewardj4340dac2004-11-20 13:17:04 +00005474 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pcmpgt", True );
5475 break;
5476
sewardj63ba4092004-11-21 12:30:18 +00005477 case 0x6B: /* PACKSSDW (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005478 if (sz != 4)
5479 goto mmx_decode_failure;
sewardj63ba4092004-11-21 12:30:18 +00005480 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "packssdw", False );
5481 break;
5482
5483 case 0x63: /* PACKSSWB (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005484 if (sz != 4)
5485 goto mmx_decode_failure;
sewardj63ba4092004-11-21 12:30:18 +00005486 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "packsswb", False );
5487 break;
5488
5489 case 0x67: /* PACKUSWB (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005490 if (sz != 4)
5491 goto mmx_decode_failure;
sewardj63ba4092004-11-21 12:30:18 +00005492 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "packuswb", False );
5493 break;
5494
5495 case 0x68:
5496 case 0x69:
5497 case 0x6A: /* PUNPCKHgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005498 if (sz != 4)
5499 goto mmx_decode_failure;
sewardj63ba4092004-11-21 12:30:18 +00005500 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "punpckh", True );
5501 break;
5502
5503 case 0x60:
5504 case 0x61:
5505 case 0x62: /* PUNPCKLgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005506 if (sz != 4)
5507 goto mmx_decode_failure;
sewardj63ba4092004-11-21 12:30:18 +00005508 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "punpckl", True );
5509 break;
5510
5511 case 0xDB: /* PAND (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005512 if (sz != 4)
5513 goto mmx_decode_failure;
sewardj63ba4092004-11-21 12:30:18 +00005514 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pand", False );
5515 break;
5516
5517 case 0xDF: /* PANDN (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005518 if (sz != 4)
5519 goto mmx_decode_failure;
sewardj63ba4092004-11-21 12:30:18 +00005520 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pandn", False );
5521 break;
5522
5523 case 0xEB: /* POR (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005524 if (sz != 4)
5525 goto mmx_decode_failure;
sewardj63ba4092004-11-21 12:30:18 +00005526 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "por", False );
5527 break;
5528
5529 case 0xEF: /* PXOR (src)mmxreg-or-mem, (dst)mmxreg */
sewardj9df271d2004-12-31 22:37:42 +00005530 if (sz != 4)
5531 goto mmx_decode_failure;
sewardj63ba4092004-11-21 12:30:18 +00005532 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pxor", False );
sewardj38a3f862005-01-13 15:06:51 +00005533 break;
sewardj63ba4092004-11-21 12:30:18 +00005534
sewardj38a3f862005-01-13 15:06:51 +00005535# define SHIFT_BY_REG(_name,_op) \
5536 delta = dis_MMX_shiftG_byE(sorb, delta, _name, _op); \
5537 break;
sewardj8d14a592004-11-21 17:04:50 +00005538
sewardj38a3f862005-01-13 15:06:51 +00005539 /* PSLLgg (src)mmxreg-or-mem, (dst)mmxreg */
5540 case 0xF1: SHIFT_BY_REG("psllw", Iop_ShlN16x4);
5541 case 0xF2: SHIFT_BY_REG("pslld", Iop_ShlN32x2);
5542 case 0xF3: SHIFT_BY_REG("psllq", Iop_Shl64);
sewardj8d14a592004-11-21 17:04:50 +00005543
sewardj38a3f862005-01-13 15:06:51 +00005544 /* PSRLgg (src)mmxreg-or-mem, (dst)mmxreg */
5545 case 0xD1: SHIFT_BY_REG("psrlw", Iop_ShrN16x4);
5546 case 0xD2: SHIFT_BY_REG("psrld", Iop_ShrN32x2);
5547 case 0xD3: SHIFT_BY_REG("psrlq", Iop_Shr64);
5548
5549 /* PSRAgg (src)mmxreg-or-mem, (dst)mmxreg */
5550 case 0xE1: SHIFT_BY_REG("psraw", Iop_SarN16x4);
5551 case 0xE2: SHIFT_BY_REG("psrad", Iop_SarN32x2);
5552
5553# undef SHIFT_BY_REG
sewardj8d14a592004-11-21 17:04:50 +00005554
sewardj2b7a9202004-11-26 19:15:38 +00005555 case 0x71:
5556 case 0x72:
5557 case 0x73: {
5558 /* (sz==4): PSLLgg/PSRAgg/PSRLgg mmxreg by imm8 */
sewardja8415ff2005-01-21 20:55:36 +00005559 UChar byte2, subopc;
sewardj38a3f862005-01-13 15:06:51 +00005560 if (sz != 4)
5561 goto mmx_decode_failure;
sewardj38a3f862005-01-13 15:06:51 +00005562 byte2 = getIByte(delta); /* amode / sub-opcode */
sewardj9b45b482005-02-07 01:42:18 +00005563 subopc = toUChar( (byte2 >> 3) & 7 );
sewardj2b7a9202004-11-26 19:15:38 +00005564
sewardj38a3f862005-01-13 15:06:51 +00005565# define SHIFT_BY_IMM(_name,_op) \
5566 do { delta = dis_MMX_shiftE_imm(delta,_name,_op); \
5567 } while (0)
sewardj2b7a9202004-11-26 19:15:38 +00005568
sewardj2b7a9202004-11-26 19:15:38 +00005569 if (subopc == 2 /*SRL*/ && opc == 0x71)
sewardj38a3f862005-01-13 15:06:51 +00005570 SHIFT_BY_IMM("psrlw", Iop_ShrN16x4);
sewardj2b7a9202004-11-26 19:15:38 +00005571 else if (subopc == 2 /*SRL*/ && opc == 0x72)
sewardj38a3f862005-01-13 15:06:51 +00005572 SHIFT_BY_IMM("psrld", Iop_ShrN32x2);
sewardj2b7a9202004-11-26 19:15:38 +00005573 else if (subopc == 2 /*SRL*/ && opc == 0x73)
sewardj38a3f862005-01-13 15:06:51 +00005574 SHIFT_BY_IMM("psrlq", Iop_Shr64);
sewardj2b7a9202004-11-26 19:15:38 +00005575
5576 else if (subopc == 4 /*SAR*/ && opc == 0x71)
sewardj38a3f862005-01-13 15:06:51 +00005577 SHIFT_BY_IMM("psraw", Iop_SarN16x4);
sewardj2b7a9202004-11-26 19:15:38 +00005578 else if (subopc == 4 /*SAR*/ && opc == 0x72)
sewardj38a3f862005-01-13 15:06:51 +00005579 SHIFT_BY_IMM("psrad", Iop_SarN32x2);
sewardj2b7a9202004-11-26 19:15:38 +00005580
5581 else if (subopc == 6 /*SHL*/ && opc == 0x71)
sewardj38a3f862005-01-13 15:06:51 +00005582 SHIFT_BY_IMM("psllw", Iop_ShlN16x4);
sewardj2b7a9202004-11-26 19:15:38 +00005583 else if (subopc == 6 /*SHL*/ && opc == 0x72)
sewardj38a3f862005-01-13 15:06:51 +00005584 SHIFT_BY_IMM("pslld", Iop_ShlN32x2);
sewardj2b7a9202004-11-26 19:15:38 +00005585 else if (subopc == 6 /*SHL*/ && opc == 0x73)
sewardj38a3f862005-01-13 15:06:51 +00005586 SHIFT_BY_IMM("psllq", Iop_Shl64);
sewardj2b7a9202004-11-26 19:15:38 +00005587
5588 else goto mmx_decode_failure;
5589
sewardj38a3f862005-01-13 15:06:51 +00005590# undef SHIFT_BY_IMM
sewardj2b7a9202004-11-26 19:15:38 +00005591 break;
5592 }
5593
5594 /* --- MMX decode failure --- */
sewardj464efa42004-11-19 22:17:29 +00005595 default:
sewardj2b7a9202004-11-26 19:15:38 +00005596 mmx_decode_failure:
sewardj464efa42004-11-19 22:17:29 +00005597 *decode_ok = False;
5598 return delta; /* ignored */
5599
5600 }
5601
5602 *decode_ok = True;
5603 return delta;
5604}
5605
5606
5607/*------------------------------------------------------------*/
5608/*--- More misc arithmetic and other obscure insns. ---*/
5609/*------------------------------------------------------------*/
sewardja06e5562004-07-14 13:18:05 +00005610
5611/* Double length left and right shifts. Apparently only required in
5612 v-size (no b- variant). */
5613static
5614UInt dis_SHLRD_Gv_Ev ( UChar sorb,
5615 UInt delta, UChar modrm,
5616 Int sz,
5617 IRExpr* shift_amt,
5618 Bool amt_is_literal,
sewardj2d49b432005-02-01 00:37:06 +00005619 HChar* shift_amt_txt,
sewardja06e5562004-07-14 13:18:05 +00005620 Bool left_shift )
5621{
5622 /* shift_amt :: Ity_I8 is the amount to shift. shift_amt_txt is used
5623 for printing it. And eip on entry points at the modrm byte. */
5624 Int len;
sewardjc9a43662004-11-30 18:51:59 +00005625 HChar dis_buf[50];
sewardja06e5562004-07-14 13:18:05 +00005626
sewardj6d2638e2004-07-15 09:38:27 +00005627 IRType ty = szToITy(sz);
5628 IRTemp gsrc = newTemp(ty);
5629 IRTemp esrc = newTemp(ty);
sewardj92d168d2004-11-15 14:22:12 +00005630 IRTemp addr = IRTemp_INVALID;
sewardj6d2638e2004-07-15 09:38:27 +00005631 IRTemp tmpSH = newTemp(Ity_I8);
sewardj92d168d2004-11-15 14:22:12 +00005632 IRTemp tmpL = IRTemp_INVALID;
5633 IRTemp tmpRes = IRTemp_INVALID;
5634 IRTemp tmpSubSh = IRTemp_INVALID;
sewardja06e5562004-07-14 13:18:05 +00005635 IROp mkpair;
5636 IROp getres;
5637 IROp shift;
sewardja06e5562004-07-14 13:18:05 +00005638 IRExpr* mask = NULL;
5639
5640 vassert(sz == 2 || sz == 4);
5641
5642 /* The E-part is the destination; this is shifted. The G-part
5643 supplies bits to be shifted into the E-part, but is not
5644 changed.
5645
5646 If shifting left, form a double-length word with E at the top
5647 and G at the bottom, and shift this left. The result is then in
5648 the high part.
5649
5650 If shifting right, form a double-length word with G at the top
5651 and E at the bottom, and shift this right. The result is then
5652 at the bottom. */
5653
5654 /* Fetch the operands. */
5655
5656 assign( gsrc, getIReg(sz, gregOfRM(modrm)) );
5657
5658 if (epartIsReg(modrm)) {
5659 delta++;
5660 assign( esrc, getIReg(sz, eregOfRM(modrm)) );
sewardj68511542004-07-28 00:15:44 +00005661 DIP("sh%cd%c %s, %s, %s\n",
sewardja06e5562004-07-14 13:18:05 +00005662 ( left_shift ? 'l' : 'r' ), nameISize(sz),
sewardj68511542004-07-28 00:15:44 +00005663 shift_amt_txt,
sewardja06e5562004-07-14 13:18:05 +00005664 nameIReg(sz, gregOfRM(modrm)), nameIReg(sz, eregOfRM(modrm)));
5665 } else {
5666 addr = disAMode ( &len, sorb, delta, dis_buf );
5667 delta += len;
5668 assign( esrc, loadLE(ty, mkexpr(addr)) );
sewardj68511542004-07-28 00:15:44 +00005669 DIP("sh%cd%c %s, %s, %s\n",
5670 ( left_shift ? 'l' : 'r' ), nameISize(sz),
5671 shift_amt_txt,
5672 nameIReg(sz, gregOfRM(modrm)), dis_buf);
sewardja06e5562004-07-14 13:18:05 +00005673 }
5674
5675 /* Round up the relevant primops. */
5676
5677 if (sz == 4) {
5678 tmpL = newTemp(Ity_I64);
5679 tmpRes = newTemp(Ity_I32);
5680 tmpSubSh = newTemp(Ity_I32);
sewardje539a402004-07-14 18:24:17 +00005681 mkpair = Iop_32HLto64;
sewardj8c7f1ab2004-07-29 20:31:09 +00005682 getres = left_shift ? Iop_64HIto32 : Iop_64to32;
sewardje539a402004-07-14 18:24:17 +00005683 shift = left_shift ? Iop_Shl64 : Iop_Shr64;
5684 mask = mkU8(31);
sewardja06e5562004-07-14 13:18:05 +00005685 } else {
5686 /* sz == 2 */
sewardj8c7f1ab2004-07-29 20:31:09 +00005687 tmpL = newTemp(Ity_I32);
5688 tmpRes = newTemp(Ity_I16);
5689 tmpSubSh = newTemp(Ity_I16);
5690 mkpair = Iop_16HLto32;
5691 getres = left_shift ? Iop_32HIto16 : Iop_32to16;
5692 shift = left_shift ? Iop_Shl32 : Iop_Shr32;
5693 mask = mkU8(15);
sewardja06e5562004-07-14 13:18:05 +00005694 }
5695
5696 /* Do the shift, calculate the subshift value, and set
5697 the flag thunk. */
5698
sewardj8c7f1ab2004-07-29 20:31:09 +00005699 assign( tmpSH, binop(Iop_And8, shift_amt, mask) );
5700
sewardja06e5562004-07-14 13:18:05 +00005701 if (left_shift)
5702 assign( tmpL, binop(mkpair, mkexpr(esrc), mkexpr(gsrc)) );
5703 else
5704 assign( tmpL, binop(mkpair, mkexpr(gsrc), mkexpr(esrc)) );
5705
5706 assign( tmpRes, unop(getres, binop(shift, mkexpr(tmpL), mkexpr(tmpSH)) ) );
5707 assign( tmpSubSh,
5708 unop(getres,
5709 binop(shift,
5710 mkexpr(tmpL),
5711 binop(Iop_And8,
5712 binop(Iop_Sub8, mkexpr(tmpSH), mkU8(1) ),
5713 mask))) );
sewardja06e5562004-07-14 13:18:05 +00005714
sewardj2a2ba8b2004-11-08 13:14:06 +00005715 setFlags_DEP1_DEP2_shift ( left_shift ? Iop_Shl32 : Iop_Sar32,
5716 tmpRes, tmpSubSh, ty, tmpSH );
sewardja06e5562004-07-14 13:18:05 +00005717
5718 /* Put result back. */
5719
5720 if (epartIsReg(modrm)) {
5721 putIReg(sz, eregOfRM(modrm), mkexpr(tmpRes));
5722 } else {
5723 storeLE( mkexpr(addr), mkexpr(tmpRes) );
5724 }
5725
5726 if (amt_is_literal) delta++;
5727 return delta;
5728}
5729
5730
sewardj1c6f9912004-09-07 10:15:24 +00005731/* Handle BT/BTS/BTR/BTC Gv, Ev. Apparently b-size is not
5732 required. */
5733
5734typedef enum { BtOpNone, BtOpSet, BtOpReset, BtOpComp } BtOp;
5735
sewardj2d49b432005-02-01 00:37:06 +00005736static HChar* nameBtOp ( BtOp op )
sewardj1c6f9912004-09-07 10:15:24 +00005737{
5738 switch (op) {
5739 case BtOpNone: return "";
5740 case BtOpSet: return "s";
5741 case BtOpReset: return "r";
5742 case BtOpComp: return "c";
5743 default: vpanic("nameBtOp(x86)");
5744 }
5745}
5746
5747
5748static
5749UInt dis_bt_G_E ( UChar sorb, Int sz, UInt delta, BtOp op )
5750{
sewardjc9a43662004-11-30 18:51:59 +00005751 HChar dis_buf[50];
sewardj1c6f9912004-09-07 10:15:24 +00005752 UChar modrm;
5753 Int len;
5754 IRTemp t_fetched, t_bitno0, t_bitno1, t_bitno2, t_addr0,
5755 t_addr1, t_esp, t_mask;
5756
5757 vassert(sz == 2 || sz == 4);
5758
5759 t_fetched = t_bitno0 = t_bitno1 = t_bitno2
sewardj92d168d2004-11-15 14:22:12 +00005760 = t_addr0 = t_addr1 = t_esp = t_mask = IRTemp_INVALID;
sewardj1c6f9912004-09-07 10:15:24 +00005761
5762 t_fetched = newTemp(Ity_I8);
5763 t_bitno0 = newTemp(Ity_I32);
5764 t_bitno1 = newTemp(Ity_I32);
5765 t_bitno2 = newTemp(Ity_I8);
5766 t_addr1 = newTemp(Ity_I32);
5767 modrm = getIByte(delta);
5768
5769 assign( t_bitno0, widenUto32(getIReg(sz, gregOfRM(modrm))) );
5770
5771 if (epartIsReg(modrm)) {
sewardj1c6f9912004-09-07 10:15:24 +00005772 delta++;
5773 /* Get it onto the client's stack. */
5774 t_esp = newTemp(Ity_I32);
5775 t_addr0 = newTemp(Ity_I32);
5776
5777 assign( t_esp, binop(Iop_Sub32, getIReg(4, R_ESP), mkU32(sz)) );
5778 putIReg(4, R_ESP, mkexpr(t_esp));
5779
5780 storeLE( mkexpr(t_esp), getIReg(sz, eregOfRM(modrm)) );
5781
5782 /* Make t_addr0 point at it. */
5783 assign( t_addr0, mkexpr(t_esp) );
5784
5785 /* Mask out upper bits of the shift amount, since we're doing a
5786 reg. */
5787 assign( t_bitno1, binop(Iop_And32,
5788 mkexpr(t_bitno0),
5789 mkU32(sz == 4 ? 31 : 15)) );
5790
5791 } else {
5792 t_addr0 = disAMode ( &len, sorb, delta, dis_buf );
5793 delta += len;
5794 assign( t_bitno1, mkexpr(t_bitno0) );
5795 }
5796
5797 /* At this point: t_addr0 is the address being operated on. If it
5798 was a reg, we will have pushed it onto the client's stack.
5799 t_bitno1 is the bit number, suitably masked in the case of a
5800 reg. */
5801
5802 /* Now the main sequence. */
5803 assign( t_addr1,
5804 binop(Iop_Add32,
5805 mkexpr(t_addr0),
5806 binop(Iop_Sar32, mkexpr(t_bitno1), mkU8(3))) );
5807
5808 /* t_addr1 now holds effective address */
5809
5810 assign( t_bitno2,
5811 unop(Iop_32to8,
5812 binop(Iop_And32, mkexpr(t_bitno1), mkU32(7))) );
5813
5814 /* t_bitno2 contains offset of bit within byte */
5815
5816 if (op != BtOpNone) {
5817 t_mask = newTemp(Ity_I8);
5818 assign( t_mask, binop(Iop_Shl8, mkU8(1), mkexpr(t_bitno2)) );
5819 }
sewardj4963a422004-10-14 23:34:03 +00005820
sewardj1c6f9912004-09-07 10:15:24 +00005821 /* t_mask is now a suitable byte mask */
5822
5823 assign( t_fetched, loadLE(Ity_I8, mkexpr(t_addr1)) );
5824
5825 if (op != BtOpNone) {
5826 switch (op) {
5827 case BtOpSet:
5828 storeLE( mkexpr(t_addr1),
5829 binop(Iop_Or8, mkexpr(t_fetched),
5830 mkexpr(t_mask)) );
5831 break;
5832 case BtOpComp:
5833 storeLE( mkexpr(t_addr1),
5834 binop(Iop_Xor8, mkexpr(t_fetched),
5835 mkexpr(t_mask)) );
5836 break;
5837 case BtOpReset:
5838 storeLE( mkexpr(t_addr1),
5839 binop(Iop_And8, mkexpr(t_fetched),
5840 unop(Iop_Not8, mkexpr(t_mask))) );
5841 break;
5842 default:
5843 vpanic("dis_bt_G_E(x86)");
5844 }
5845 }
5846
5847 /* Side effect done; now get selected bit into Carry flag */
sewardj2a2ba8b2004-11-08 13:14:06 +00005848 /* Flags: C=selected bit, O,S,Z,A,P undefined, so are set to zero. */
sewardj2a9ad022004-11-25 02:46:58 +00005849 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
sewardj2a2ba8b2004-11-08 13:14:06 +00005850 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
sewardj1c6f9912004-09-07 10:15:24 +00005851 stmt( IRStmt_Put(
sewardj2a2ba8b2004-11-08 13:14:06 +00005852 OFFB_CC_DEP1,
sewardj1c6f9912004-09-07 10:15:24 +00005853 binop(Iop_And32,
5854 binop(Iop_Shr32,
5855 unop(Iop_8Uto32, mkexpr(t_fetched)),
sewardj5bd4d162004-11-10 13:02:48 +00005856 mkexpr(t_bitno2)),
5857 mkU32(1)))
sewardj1c6f9912004-09-07 10:15:24 +00005858 );
sewardja3b7e3a2005-04-05 01:54:19 +00005859 /* Set NDEP even though it isn't used. This makes redundant-PUT
5860 elimination of previous stores to this field work better. */
5861 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardj1c6f9912004-09-07 10:15:24 +00005862
5863 /* Move reg operand from stack back to reg */
5864 if (epartIsReg(modrm)) {
5865 /* t_esp still points at it. */
sewardj4963a422004-10-14 23:34:03 +00005866 putIReg(sz, eregOfRM(modrm), loadLE(szToITy(sz), mkexpr(t_esp)) );
sewardj1c6f9912004-09-07 10:15:24 +00005867 putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t_esp), mkU32(sz)) );
5868 }
5869
5870 DIP("bt%s%c %s, %s\n",
5871 nameBtOp(op), nameISize(sz), nameIReg(sz, gregOfRM(modrm)),
5872 ( epartIsReg(modrm) ? nameIReg(sz, eregOfRM(modrm)) : dis_buf ) );
5873
5874 return delta;
5875}
sewardjce646f22004-08-31 23:55:54 +00005876
5877
5878
5879/* Handle BSF/BSR. Only v-size seems necessary. */
5880static
5881UInt dis_bs_E_G ( UChar sorb, Int sz, UInt delta, Bool fwds )
5882{
5883 Bool isReg;
5884 UChar modrm;
sewardjc9a43662004-11-30 18:51:59 +00005885 HChar dis_buf[50];
sewardjce646f22004-08-31 23:55:54 +00005886
5887 IRType ty = szToITy(sz);
5888 IRTemp src = newTemp(ty);
5889 IRTemp dst = newTemp(ty);
5890
5891 IRTemp src32 = newTemp(Ity_I32);
5892 IRTemp dst32 = newTemp(Ity_I32);
5893 IRTemp src8 = newTemp(Ity_I8);
5894
5895 vassert(sz == 4 || sz == 2);
sewardjce646f22004-08-31 23:55:54 +00005896
5897 modrm = getIByte(delta);
5898
5899 isReg = epartIsReg(modrm);
5900 if (isReg) {
5901 delta++;
5902 assign( src, getIReg(sz, eregOfRM(modrm)) );
5903 } else {
5904 Int len;
5905 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5906 delta += len;
5907 assign( src, loadLE(ty, mkexpr(addr)) );
5908 }
5909
5910 DIP("bs%c%c %s, %s\n",
5911 fwds ? 'f' : 'r', nameISize(sz),
5912 ( isReg ? nameIReg(sz, eregOfRM(modrm)) : dis_buf ),
5913 nameIReg(sz, gregOfRM(modrm)));
5914
5915 /* Generate an 8-bit expression which is zero iff the
5916 original is zero, and nonzero otherwise */
5917 assign( src8,
5918 unop(Iop_1Uto8, binop(mkSizedOp(ty,Iop_CmpNE8),
5919 mkexpr(src), mkU(ty,0))) );
5920
5921 /* Flags: Z is 1 iff source value is zero. All others
5922 are undefined -- we force them to zero. */
sewardj2a9ad022004-11-25 02:46:58 +00005923 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
sewardj2a2ba8b2004-11-08 13:14:06 +00005924 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
sewardjce646f22004-08-31 23:55:54 +00005925 stmt( IRStmt_Put(
sewardj2a2ba8b2004-11-08 13:14:06 +00005926 OFFB_CC_DEP1,
sewardjce646f22004-08-31 23:55:54 +00005927 IRExpr_Mux0X( mkexpr(src8),
5928 /* src==0 */
sewardj2a9ad022004-11-25 02:46:58 +00005929 mkU32(X86G_CC_MASK_Z),
sewardjce646f22004-08-31 23:55:54 +00005930 /* src!=0 */
5931 mkU32(0)
5932 )
5933 ));
sewardja3b7e3a2005-04-05 01:54:19 +00005934 /* Set NDEP even though it isn't used. This makes redundant-PUT
5935 elimination of previous stores to this field work better. */
5936 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardjce646f22004-08-31 23:55:54 +00005937
5938 /* Result: iff source value is zero, we can't use
5939 Iop_Clz32/Iop_Ctz32 as they have no defined result in that case.
5940 But anyway, Intel x86 semantics say the result is undefined in
5941 such situations. Hence handle the zero case specially. */
5942
5943 /* Bleh. What we compute:
5944
5945 bsf32: if src == 0 then 0 else Ctz32(src)
5946 bsr32: if src == 0 then 0 else 31 - Clz32(src)
5947
5948 bsf16: if src == 0 then 0 else Ctz32(16Uto32(src))
5949 bsr16: if src == 0 then 0 else 31 - Clz32(16Uto32(src))
5950
5951 First, widen src to 32 bits if it is not already.
sewardj37158712004-10-15 21:23:12 +00005952
5953 Postscript 15 Oct 04: it seems that at least VIA Nehemiah leaves the
5954 dst register unchanged when src == 0. Hence change accordingly.
sewardjce646f22004-08-31 23:55:54 +00005955 */
5956 if (sz == 2)
5957 assign( src32, unop(Iop_16Uto32, mkexpr(src)) );
5958 else
5959 assign( src32, mkexpr(src) );
5960
5961 /* The main computation, guarding against zero. */
5962 assign( dst32,
5963 IRExpr_Mux0X(
5964 mkexpr(src8),
sewardj37158712004-10-15 21:23:12 +00005965 /* src == 0 -- leave dst unchanged */
5966 widenUto32( getIReg( sz, gregOfRM(modrm) ) ),
sewardjce646f22004-08-31 23:55:54 +00005967 /* src != 0 */
5968 fwds ? unop(Iop_Ctz32, mkexpr(src32))
5969 : binop(Iop_Sub32,
5970 mkU32(31),
5971 unop(Iop_Clz32, mkexpr(src32)))
5972 )
5973 );
5974
5975 if (sz == 2)
5976 assign( dst, unop(Iop_32to16, mkexpr(dst32)) );
5977 else
5978 assign( dst, mkexpr(dst32) );
5979
5980 /* dump result back */
5981 putIReg( sz, gregOfRM(modrm), mkexpr(dst) );
5982
5983 return delta;
5984}
sewardj64e1d652004-07-12 14:00:46 +00005985
5986
5987static
5988void codegen_xchg_eAX_Reg ( Int sz, Int reg )
5989{
5990 IRType ty = szToITy(sz);
5991 IRTemp t1 = newTemp(ty);
5992 IRTemp t2 = newTemp(ty);
5993 vassert(sz == 2 || sz == 4);
5994 assign( t1, getIReg(sz, R_EAX) );
5995 assign( t2, getIReg(sz, reg) );
5996 putIReg( sz, R_EAX, mkexpr(t2) );
5997 putIReg( sz, reg, mkexpr(t1) );
5998 DIP("xchg%c %s, %s\n",
5999 nameISize(sz), nameIReg(sz, R_EAX), nameIReg(sz, reg));
6000}
6001
6002
sewardjbdc7d212004-09-09 02:46:40 +00006003static
6004void codegen_SAHF ( void )
6005{
6006 /* Set the flags to:
sewardj2a9ad022004-11-25 02:46:58 +00006007 (x86g_calculate_flags_all() & X86G_CC_MASK_O) -- retain the old O flag
6008 | (%AH & (X86G_CC_MASK_S|X86G_CC_MASK_Z|X86G_CC_MASK_A
6009 |X86G_CC_MASK_P|X86G_CC_MASK_C)
sewardjbdc7d212004-09-09 02:46:40 +00006010 */
sewardj2a9ad022004-11-25 02:46:58 +00006011 UInt mask_SZACP = X86G_CC_MASK_S|X86G_CC_MASK_Z|X86G_CC_MASK_A
6012 |X86G_CC_MASK_C|X86G_CC_MASK_P;
sewardjbdc7d212004-09-09 02:46:40 +00006013 IRTemp oldflags = newTemp(Ity_I32);
sewardj2a9ad022004-11-25 02:46:58 +00006014 assign( oldflags, mk_x86g_calculate_eflags_all() );
6015 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
sewardj2a2ba8b2004-11-08 13:14:06 +00006016 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
6017 stmt( IRStmt_Put( OFFB_CC_DEP1,
sewardjbdc7d212004-09-09 02:46:40 +00006018 binop(Iop_Or32,
sewardj2a9ad022004-11-25 02:46:58 +00006019 binop(Iop_And32, mkexpr(oldflags), mkU32(X86G_CC_MASK_O)),
sewardjbdc7d212004-09-09 02:46:40 +00006020 binop(Iop_And32,
6021 binop(Iop_Shr32, getIReg(4, R_EAX), mkU8(8)),
6022 mkU32(mask_SZACP))
6023 )
6024 ));
sewardja3b7e3a2005-04-05 01:54:19 +00006025 /* Set NDEP even though it isn't used. This makes redundant-PUT
6026 elimination of previous stores to this field work better. */
6027 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardjbdc7d212004-09-09 02:46:40 +00006028}
6029
6030
sewardjc9a65702004-07-07 16:32:57 +00006031//-- static
6032//-- void codegen_LAHF ( UCodeBlock* cb )
6033//-- {
6034//-- Int t = newTemp(cb);
6035//--
6036//-- /* Pushed arg is ignored, it just provides somewhere to put the
6037//-- return value. */
6038//-- uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, t);
6039//-- uInstr0(cb, CALLM_S, 0);
6040//-- uInstr1(cb, PUSH, 4, TempReg, t);
6041//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_LAHF));
6042//-- uFlagsRWU(cb, FlagsSZACP, FlagsEmpty, FlagsEmpty);
6043//-- uInstr1(cb, POP, 4, TempReg, t);
6044//-- uInstr0(cb, CALLM_E, 0);
6045//--
6046//-- /* At this point, the %ah sub-register in %eax has been updated,
6047//-- the rest is the same, so do a PUT of the whole thing. */
6048//-- uInstr2(cb, PUT, 4, TempReg, t, ArchReg, R_EAX);
6049//-- }
6050//--
sewardj458a6f82004-08-25 12:46:02 +00006051
6052static
6053UInt dis_cmpxchg_G_E ( UChar sorb,
6054 Int size,
6055 UInt delta0 )
6056{
sewardjc9a43662004-11-30 18:51:59 +00006057 HChar dis_buf[50];
sewardj458a6f82004-08-25 12:46:02 +00006058 Int len;
6059
6060 IRType ty = szToITy(size);
6061 IRTemp acc = newTemp(ty);
6062 IRTemp src = newTemp(ty);
sewardj2a2ba8b2004-11-08 13:14:06 +00006063 //IRTemp res = newTemp(ty);
sewardj458a6f82004-08-25 12:46:02 +00006064 IRTemp dest = newTemp(ty);
6065 IRTemp dest2 = newTemp(ty);
6066 IRTemp acc2 = newTemp(ty);
6067 IRTemp cond8 = newTemp(Ity_I8);
sewardj92d168d2004-11-15 14:22:12 +00006068 IRTemp addr = IRTemp_INVALID;
sewardj458a6f82004-08-25 12:46:02 +00006069 UChar rm = getUChar(delta0);
6070
6071 if (epartIsReg(rm)) {
6072 assign( dest, getIReg(size, eregOfRM(rm)) );
6073 delta0++;
6074 DIP("cmpxchg%c %s,%s\n", nameISize(size),
6075 nameIReg(size,gregOfRM(rm)),
6076 nameIReg(size,eregOfRM(rm)) );
sewardj458a6f82004-08-25 12:46:02 +00006077 } else {
6078 addr = disAMode ( &len, sorb, delta0, dis_buf );
6079 assign( dest, loadLE(ty, mkexpr(addr)) );
6080 delta0 += len;
6081 DIP("cmpxchg%c %s,%s\n", nameISize(size),
6082 nameIReg(size,gregOfRM(rm)), dis_buf);
6083 }
6084
6085 assign( src, getIReg(size, gregOfRM(rm)) );
6086 assign( acc, getIReg(size, R_EAX) );
sewardj2a2ba8b2004-11-08 13:14:06 +00006087 //assign( res, binop( mkSizedOp(ty,Iop_Sub8), mkexpr(acc), mkexpr(dest) ));
6088 setFlags_DEP1_DEP2(Iop_Sub8, acc, dest, ty);
sewardj2a9ad022004-11-25 02:46:58 +00006089 assign( cond8, unop(Iop_1Uto8, mk_x86g_calculate_condition(X86CondZ)) );
sewardj458a6f82004-08-25 12:46:02 +00006090 assign( dest2, IRExpr_Mux0X(mkexpr(cond8), mkexpr(dest), mkexpr(src)) );
6091 assign( acc2, IRExpr_Mux0X(mkexpr(cond8), mkexpr(dest), mkexpr(acc)) );
6092 putIReg(size, R_EAX, mkexpr(acc2));
6093
6094 if (epartIsReg(rm)) {
6095 putIReg(size, eregOfRM(rm), mkexpr(dest2));
6096 } else {
6097 storeLE( mkexpr(addr), mkexpr(dest2) );
6098 }
6099
6100 return delta0;
6101}
6102
6103
sewardjc9a65702004-07-07 16:32:57 +00006104//-- static
6105//-- Addr dis_cmpxchg8b ( UCodeBlock* cb,
6106//-- UChar sorb,
6107//-- Addr eip0 )
6108//-- {
6109//-- Int tal, tah, junkl, junkh, destl, desth, srcl, srch, accl, acch;
sewardjc9a43662004-11-30 18:51:59 +00006110//-- HChar dis_buf[50];
sewardjc9a65702004-07-07 16:32:57 +00006111//-- UChar rm;
6112//-- UInt pair;
6113//--
6114//-- rm = getUChar(eip0);
6115//-- accl = newTemp(cb);
6116//-- acch = newTemp(cb);
6117//-- srcl = newTemp(cb);
6118//-- srch = newTemp(cb);
6119//-- destl = newTemp(cb);
6120//-- desth = newTemp(cb);
6121//-- junkl = newTemp(cb);
6122//-- junkh = newTemp(cb);
6123//--
6124//-- vg_assert(!epartIsReg(rm));
6125//--
6126//-- pair = disAMode ( cb, sorb, eip0, dis_buf );
6127//-- tal = LOW24(pair);
6128//-- tah = newTemp(cb);
6129//-- uInstr2(cb, MOV, 4, TempReg, tal, TempReg, tah);
6130//-- uInstr2(cb, ADD, 4, Literal, 0, TempReg, tah);
6131//-- uLiteral(cb, 4);
6132//-- eip0 += HI8(pair);
6133//-- DIP("cmpxchg8b %s\n", dis_buf);
6134//--
6135//-- uInstr0(cb, CALLM_S, 0);
6136//--
6137//-- uInstr2(cb, LOAD, 4, TempReg, tah, TempReg, desth);
6138//-- uInstr1(cb, PUSH, 4, TempReg, desth);
6139//-- uInstr2(cb, LOAD, 4, TempReg, tal, TempReg, destl);
6140//-- uInstr1(cb, PUSH, 4, TempReg, destl);
6141//-- uInstr2(cb, GET, 4, ArchReg, R_ECX, TempReg, srch);
6142//-- uInstr1(cb, PUSH, 4, TempReg, srch);
6143//-- uInstr2(cb, GET, 4, ArchReg, R_EBX, TempReg, srcl);
6144//-- uInstr1(cb, PUSH, 4, TempReg, srcl);
6145//-- uInstr2(cb, GET, 4, ArchReg, R_EDX, TempReg, acch);
6146//-- uInstr1(cb, PUSH, 4, TempReg, acch);
6147//-- uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, accl);
6148//-- uInstr1(cb, PUSH, 4, TempReg, accl);
6149//--
6150//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_cmpxchg8b));
6151//-- uFlagsRWU(cb, FlagsEmpty, FlagZ, FlagsEmpty);
6152//--
6153//-- uInstr1(cb, POP, 4, TempReg, accl);
6154//-- uInstr2(cb, PUT, 4, TempReg, accl, ArchReg, R_EAX);
6155//-- uInstr1(cb, POP, 4, TempReg, acch);
6156//-- uInstr2(cb, PUT, 4, TempReg, acch, ArchReg, R_EDX);
6157//-- uInstr1(cb, POP, 4, TempReg, srcl);
6158//-- uInstr2(cb, PUT, 4, TempReg, srcl, ArchReg, R_EBX);
6159//-- uInstr1(cb, POP, 4, TempReg, srch);
6160//-- uInstr2(cb, PUT, 4, TempReg, srch, ArchReg, R_ECX);
6161//-- uInstr1(cb, POP, 4, TempReg, destl);
6162//-- uInstr2(cb, STORE, 4, TempReg, destl, TempReg, tal);
6163//-- uInstr1(cb, POP, 4, TempReg, desth);
6164//-- uInstr2(cb, STORE, 4, TempReg, desth, TempReg, tah);
6165//--
6166//-- uInstr0(cb, CALLM_E, 0);
6167//--
6168//-- return eip0;
6169//-- }
sewardj458a6f82004-08-25 12:46:02 +00006170
6171
6172/* Handle conditional move instructions of the form
6173 cmovcc E(reg-or-mem), G(reg)
6174
6175 E(src) is reg-or-mem
6176 G(dst) is reg.
6177
6178 If E is reg, --> GET %E, tmps
6179 GET %G, tmpd
6180 CMOVcc tmps, tmpd
6181 PUT tmpd, %G
6182
6183 If E is mem --> (getAddr E) -> tmpa
6184 LD (tmpa), tmps
6185 GET %G, tmpd
6186 CMOVcc tmps, tmpd
6187 PUT tmpd, %G
6188*/
6189static
6190UInt dis_cmov_E_G ( UChar sorb,
6191 Int sz,
sewardj2a9ad022004-11-25 02:46:58 +00006192 X86Condcode cond,
sewardj458a6f82004-08-25 12:46:02 +00006193 UInt delta0 )
6194{
6195 UChar rm = getIByte(delta0);
sewardjc9a43662004-11-30 18:51:59 +00006196 HChar dis_buf[50];
sewardj458a6f82004-08-25 12:46:02 +00006197 Int len;
6198
sewardj883b00b2004-09-11 09:30:24 +00006199 IRType ty = szToITy(sz);
sewardj458a6f82004-08-25 12:46:02 +00006200 IRTemp tmps = newTemp(ty);
6201 IRTemp tmpd = newTemp(ty);
6202
6203 if (epartIsReg(rm)) {
6204 assign( tmps, getIReg(sz, eregOfRM(rm)) );
6205 assign( tmpd, getIReg(sz, gregOfRM(rm)) );
6206
6207 putIReg(sz, gregOfRM(rm),
sewardj2a9ad022004-11-25 02:46:58 +00006208 IRExpr_Mux0X( unop(Iop_1Uto8,
6209 mk_x86g_calculate_condition(cond)),
sewardj458a6f82004-08-25 12:46:02 +00006210 mkexpr(tmpd),
6211 mkexpr(tmps) )
6212 );
6213 DIP("cmov%c%s %s,%s\n", nameISize(sz),
sewardj2a9ad022004-11-25 02:46:58 +00006214 name_X86Condcode(cond),
sewardj458a6f82004-08-25 12:46:02 +00006215 nameIReg(sz,eregOfRM(rm)),
6216 nameIReg(sz,gregOfRM(rm)));
6217 return 1+delta0;
6218 }
6219
6220 /* E refers to memory */
6221 {
6222 IRTemp addr = disAMode ( &len, sorb, delta0, dis_buf );
6223 assign( tmps, loadLE(ty, mkexpr(addr)) );
6224 assign( tmpd, getIReg(sz, gregOfRM(rm)) );
6225
6226 putIReg(sz, gregOfRM(rm),
sewardj2a9ad022004-11-25 02:46:58 +00006227 IRExpr_Mux0X( unop(Iop_1Uto8,
6228 mk_x86g_calculate_condition(cond)),
sewardj458a6f82004-08-25 12:46:02 +00006229 mkexpr(tmpd),
6230 mkexpr(tmps) )
6231 );
6232
6233 DIP("cmov%c%s %s,%s\n", nameISize(sz),
sewardj2a9ad022004-11-25 02:46:58 +00006234 name_X86Condcode(cond),
sewardj458a6f82004-08-25 12:46:02 +00006235 dis_buf,
6236 nameIReg(sz,gregOfRM(rm)));
6237 return len+delta0;
6238 }
6239}
6240
6241
sewardj883b00b2004-09-11 09:30:24 +00006242static
6243UInt dis_xadd_G_E ( UChar sorb, Int sz, UInt delta0 )
6244{
6245 Int len;
6246 UChar rm = getIByte(delta0);
sewardjc9a43662004-11-30 18:51:59 +00006247 HChar dis_buf[50];
sewardj883b00b2004-09-11 09:30:24 +00006248
6249 // Int tmpd = newTemp(cb);
6250 //Int tmpt = newTemp(cb);
6251
6252 IRType ty = szToITy(sz);
6253 IRTemp tmpd = newTemp(ty);
6254 IRTemp tmpt0 = newTemp(ty);
6255 IRTemp tmpt1 = newTemp(ty);
6256
6257 if (epartIsReg(rm)) {
sewardja8415ff2005-01-21 20:55:36 +00006258 unimplemented("x86 xadd instruction with register operand");
sewardj883b00b2004-09-11 09:30:24 +00006259#if 0
6260 uInstr2(cb, GET, sz, ArchReg, eregOfRM(rm), TempReg, tmpd);
6261 uInstr2(cb, GET, sz, ArchReg, gregOfRM(rm), TempReg, tmpt);
6262 uInstr2(cb, ADD, sz, TempReg, tmpd, TempReg, tmpt);
6263 setFlagsFromUOpcode(cb, ADD);
6264 uInstr2(cb, PUT, sz, TempReg, tmpd, ArchReg, gregOfRM(rm));
6265 uInstr2(cb, PUT, sz, TempReg, tmpt, ArchReg, eregOfRM(rm));
6266 DIP("xadd%c %s, %s\n",
6267 nameISize(sz), nameIReg(sz,gregOfRM(rm)), nameIReg(sz,eregOfRM(rm)));
6268 return 1+eip0;
6269#endif
6270 } else {
6271 IRTemp addr = disAMode ( &len, sorb, delta0, dis_buf );
6272 assign( tmpd, loadLE(ty, mkexpr(addr)) );
6273 assign( tmpt0, getIReg(sz, gregOfRM(rm)) );
sewardj883b00b2004-09-11 09:30:24 +00006274 assign( tmpt1, binop(mkSizedOp(ty,Iop_Add8), mkexpr(tmpd), mkexpr(tmpt0)) );
sewardj2a2ba8b2004-11-08 13:14:06 +00006275 setFlags_DEP1_DEP2( Iop_Add8, tmpd, tmpt0, ty );
sewardj883b00b2004-09-11 09:30:24 +00006276 storeLE( mkexpr(addr), mkexpr(tmpt1) );
6277 putIReg(sz, gregOfRM(rm), mkexpr(tmpd));
6278 DIP("xadd%c %s, %s\n",
6279 nameISize(sz), nameIReg(sz,gregOfRM(rm)), dis_buf);
6280 return len+delta0;
6281 }
6282}
6283
sewardjb64821b2004-12-14 10:00:16 +00006284/* Move 16 bits from Ew (ireg or mem) to G (a segment register). */
6285
sewardj7df596b2004-12-06 14:29:12 +00006286static
6287UInt dis_mov_Ew_Sw ( UChar sorb, UInt delta0 )
6288{
sewardjb64821b2004-12-14 10:00:16 +00006289 Int len;
6290 IRTemp addr;
6291 UChar rm = getIByte(delta0);
6292 HChar dis_buf[50];
sewardj7df596b2004-12-06 14:29:12 +00006293
6294 if (epartIsReg(rm)) {
6295 putSReg( gregOfRM(rm), getIReg(2, eregOfRM(rm)) );
6296 DIP("movw %s,%s\n", nameIReg(2,eregOfRM(rm)), nameSReg(gregOfRM(rm)));
6297 return 1+delta0;
sewardjb64821b2004-12-14 10:00:16 +00006298 } else {
6299 addr = disAMode ( &len, sorb, delta0, dis_buf );
6300 putSReg( gregOfRM(rm), loadLE(Ity_I16, mkexpr(addr)) );
6301 DIP("movw %s,%s\n", dis_buf, nameSReg(gregOfRM(rm)));
6302 return len+delta0;
sewardj7df596b2004-12-06 14:29:12 +00006303 }
6304}
6305
sewardjb64821b2004-12-14 10:00:16 +00006306/* Move 16 bits from G (a segment register) to Ew (ireg or mem). If
6307 dst is ireg and sz==4, zero out top half of it. */
6308
sewardj063f02f2004-10-20 12:36:12 +00006309static
6310UInt dis_mov_Sw_Ew ( UChar sorb,
6311 Int sz,
6312 UInt delta0 )
6313{
sewardjb64821b2004-12-14 10:00:16 +00006314 Int len;
6315 IRTemp addr;
6316 UChar rm = getIByte(delta0);
6317 HChar dis_buf[50];
sewardj063f02f2004-10-20 12:36:12 +00006318
6319 vassert(sz == 2 || sz == 4);
6320
6321 if (epartIsReg(rm)) {
6322 if (sz == 4)
6323 putIReg(4, eregOfRM(rm), unop(Iop_16Uto32, getSReg(gregOfRM(rm))));
6324 else
6325 putIReg(2, eregOfRM(rm), getSReg(gregOfRM(rm)));
6326
6327 DIP("mov %s,%s\n", nameSReg(gregOfRM(rm)), nameIReg(sz,eregOfRM(rm)));
6328 return 1+delta0;
sewardjb64821b2004-12-14 10:00:16 +00006329 } else {
6330 addr = disAMode ( &len, sorb, delta0, dis_buf );
6331 storeLE( mkexpr(addr), getSReg(gregOfRM(rm)) );
sewardj063f02f2004-10-20 12:36:12 +00006332 DIP("mov %s,%s\n", nameSReg(gregOfRM(rm)), dis_buf);
sewardjb64821b2004-12-14 10:00:16 +00006333 return len+delta0;
sewardj063f02f2004-10-20 12:36:12 +00006334 }
sewardj063f02f2004-10-20 12:36:12 +00006335}
6336
6337
sewardjb64821b2004-12-14 10:00:16 +00006338static
6339void dis_push_segreg ( UInt sreg, Int sz )
6340{
6341 IRTemp t1 = newTemp(Ity_I16);
6342 IRTemp ta = newTemp(Ity_I32);
6343 vassert(sz == 2 || sz == 4);
6344
6345 assign( t1, getSReg(sreg) );
6346 assign( ta, binop(Iop_Sub32, getIReg(4, R_ESP), mkU32(sz)) );
6347 putIReg(4, R_ESP, mkexpr(ta));
6348 storeLE( mkexpr(ta), mkexpr(t1) );
6349
6350 DIP("pushw %s\n", nameSReg(sreg));
6351}
6352
6353static
6354void dis_pop_segreg ( UInt sreg, Int sz )
6355{
6356 IRTemp t1 = newTemp(Ity_I16);
6357 IRTemp ta = newTemp(Ity_I32);
6358 vassert(sz == 2 || sz == 4);
6359
6360 assign( ta, getIReg(4, R_ESP) );
6361 assign( t1, loadLE(Ity_I16, mkexpr(ta)) );
6362
6363 putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(ta), mkU32(sz)) );
6364 putSReg( sreg, mkexpr(t1) );
6365 DIP("pop %s\n", nameSReg(sreg));
6366}
sewardje05c42c2004-07-08 20:25:10 +00006367
6368static
6369void dis_ret ( UInt d32 )
6370{
6371 IRTemp t1 = newTemp(Ity_I32), t2 = newTemp(Ity_I32);
6372 assign(t1, getIReg(4,R_ESP));
6373 assign(t2, loadLE(Ity_I32,mkexpr(t1)));
6374 putIReg(4, R_ESP,binop(Iop_Add32, mkexpr(t1), mkU32(4+d32)));
sewardj78c19df2004-07-12 22:49:27 +00006375 jmp_treg(Ijk_Ret,t2);
sewardje05c42c2004-07-08 20:25:10 +00006376}
6377
sewardj4cb918d2004-12-03 19:43:31 +00006378/*------------------------------------------------------------*/
6379/*--- SSE/SSE2/SSE3 helpers ---*/
6380/*------------------------------------------------------------*/
sewardjc9a43662004-11-30 18:51:59 +00006381
sewardj129b3d92004-12-05 15:42:05 +00006382/* Worker function; do not call directly.
6383 Handles full width G = G `op` E and G = (not G) `op` E.
6384*/
6385
6386static UInt dis_SSE_E_to_G_all_wrk (
sewardj1e6ad742004-12-02 16:16:11 +00006387 UChar sorb, UInt delta,
6388 HChar* opname, IROp op,
6389 Bool invertG
6390 )
sewardjc9a43662004-11-30 18:51:59 +00006391{
sewardj1e6ad742004-12-02 16:16:11 +00006392 HChar dis_buf[50];
6393 Int alen;
6394 IRTemp addr;
6395 UChar rm = getIByte(delta);
6396 IRExpr* gpart
sewardjf0c1c582005-02-07 23:47:38 +00006397 = invertG ? unop(Iop_NotV128, getXMMReg(gregOfRM(rm)))
sewardj1e6ad742004-12-02 16:16:11 +00006398 : getXMMReg(gregOfRM(rm));
sewardjc9a43662004-11-30 18:51:59 +00006399 if (epartIsReg(rm)) {
6400 putXMMReg( gregOfRM(rm),
sewardj1e6ad742004-12-02 16:16:11 +00006401 binop(op, gpart,
6402 getXMMReg(eregOfRM(rm))) );
sewardjc9a43662004-11-30 18:51:59 +00006403 DIP("%s %s,%s\n", opname,
6404 nameXMMReg(eregOfRM(rm)),
6405 nameXMMReg(gregOfRM(rm)) );
6406 return delta+1;
6407 } else {
sewardj1e6ad742004-12-02 16:16:11 +00006408 addr = disAMode ( &alen, sorb, delta, dis_buf );
6409 putXMMReg( gregOfRM(rm),
6410 binop(op, gpart,
6411 loadLE(Ity_V128, mkexpr(addr))) );
6412 DIP("%s %s,%s\n", opname,
6413 dis_buf,
6414 nameXMMReg(gregOfRM(rm)) );
6415 return delta+alen;
sewardjc9a43662004-11-30 18:51:59 +00006416 }
6417}
6418
sewardj129b3d92004-12-05 15:42:05 +00006419
6420/* All lanes SSE binary operation, G = G `op` E. */
sewardj1e6ad742004-12-02 16:16:11 +00006421
6422static
sewardj129b3d92004-12-05 15:42:05 +00006423UInt dis_SSE_E_to_G_all ( UChar sorb, UInt delta, HChar* opname, IROp op )
sewardj1e6ad742004-12-02 16:16:11 +00006424{
sewardj129b3d92004-12-05 15:42:05 +00006425 return dis_SSE_E_to_G_all_wrk( sorb, delta, opname, op, False );
sewardj1e6ad742004-12-02 16:16:11 +00006426}
6427
sewardj129b3d92004-12-05 15:42:05 +00006428/* All lanes SSE binary operation, G = (not G) `op` E. */
6429
6430static
6431UInt dis_SSE_E_to_G_all_invG ( UChar sorb, UInt delta,
6432 HChar* opname, IROp op )
6433{
6434 return dis_SSE_E_to_G_all_wrk( sorb, delta, opname, op, True );
6435}
6436
sewardj164f9272004-12-09 00:39:32 +00006437
sewardj129b3d92004-12-05 15:42:05 +00006438/* Lowest 32-bit lane only SSE binary operation, G = G `op` E. */
6439
6440static UInt dis_SSE_E_to_G_lo32 ( UChar sorb, UInt delta,
6441 HChar* opname, IROp op )
6442{
6443 HChar dis_buf[50];
6444 Int alen;
6445 IRTemp addr;
6446 UChar rm = getIByte(delta);
6447 IRExpr* gpart = getXMMReg(gregOfRM(rm));
6448 if (epartIsReg(rm)) {
6449 putXMMReg( gregOfRM(rm),
6450 binop(op, gpart,
6451 getXMMReg(eregOfRM(rm))) );
6452 DIP("%s %s,%s\n", opname,
6453 nameXMMReg(eregOfRM(rm)),
6454 nameXMMReg(gregOfRM(rm)) );
6455 return delta+1;
6456 } else {
6457 /* We can only do a 32-bit memory read, so the upper 3/4 of the
6458 E operand needs to be made simply of zeroes. */
6459 IRTemp epart = newTemp(Ity_V128);
6460 addr = disAMode ( &alen, sorb, delta, dis_buf );
sewardjf0c1c582005-02-07 23:47:38 +00006461 assign( epart, unop( Iop_32UtoV128,
sewardj129b3d92004-12-05 15:42:05 +00006462 loadLE(Ity_I32, mkexpr(addr))) );
6463 putXMMReg( gregOfRM(rm),
6464 binop(op, gpart, mkexpr(epart)) );
6465 DIP("%s %s,%s\n", opname,
6466 dis_buf,
6467 nameXMMReg(gregOfRM(rm)) );
6468 return delta+alen;
6469 }
6470}
6471
sewardj164f9272004-12-09 00:39:32 +00006472
sewardj636ad762004-12-07 11:16:04 +00006473/* Lower 64-bit lane only SSE binary operation, G = G `op` E. */
6474
6475static UInt dis_SSE_E_to_G_lo64 ( UChar sorb, UInt delta,
6476 HChar* opname, IROp op )
6477{
6478 HChar dis_buf[50];
6479 Int alen;
6480 IRTemp addr;
6481 UChar rm = getIByte(delta);
6482 IRExpr* gpart = getXMMReg(gregOfRM(rm));
6483 if (epartIsReg(rm)) {
6484 putXMMReg( gregOfRM(rm),
6485 binop(op, gpart,
6486 getXMMReg(eregOfRM(rm))) );
6487 DIP("%s %s,%s\n", opname,
6488 nameXMMReg(eregOfRM(rm)),
6489 nameXMMReg(gregOfRM(rm)) );
6490 return delta+1;
6491 } else {
6492 /* We can only do a 64-bit memory read, so the upper half of the
6493 E operand needs to be made simply of zeroes. */
6494 IRTemp epart = newTemp(Ity_V128);
6495 addr = disAMode ( &alen, sorb, delta, dis_buf );
sewardjf0c1c582005-02-07 23:47:38 +00006496 assign( epart, unop( Iop_64UtoV128,
sewardj636ad762004-12-07 11:16:04 +00006497 loadLE(Ity_I64, mkexpr(addr))) );
6498 putXMMReg( gregOfRM(rm),
6499 binop(op, gpart, mkexpr(epart)) );
6500 DIP("%s %s,%s\n", opname,
6501 dis_buf,
6502 nameXMMReg(gregOfRM(rm)) );
6503 return delta+alen;
6504 }
6505}
6506
sewardj164f9272004-12-09 00:39:32 +00006507
sewardj129b3d92004-12-05 15:42:05 +00006508/* All lanes unary SSE operation, G = op(E). */
6509
6510static UInt dis_SSE_E_to_G_unary_all (
sewardj0bd7ce62004-12-05 02:47:40 +00006511 UChar sorb, UInt delta,
6512 HChar* opname, IROp op
6513 )
6514{
6515 HChar dis_buf[50];
6516 Int alen;
6517 IRTemp addr;
6518 UChar rm = getIByte(delta);
6519 if (epartIsReg(rm)) {
6520 putXMMReg( gregOfRM(rm),
6521 unop(op, getXMMReg(eregOfRM(rm))) );
6522 DIP("%s %s,%s\n", opname,
6523 nameXMMReg(eregOfRM(rm)),
6524 nameXMMReg(gregOfRM(rm)) );
6525 return delta+1;
6526 } else {
6527 addr = disAMode ( &alen, sorb, delta, dis_buf );
6528 putXMMReg( gregOfRM(rm),
6529 unop(op, loadLE(Ity_V128, mkexpr(addr))) );
6530 DIP("%s %s,%s\n", opname,
6531 dis_buf,
6532 nameXMMReg(gregOfRM(rm)) );
6533 return delta+alen;
6534 }
6535}
6536
sewardj164f9272004-12-09 00:39:32 +00006537
sewardj129b3d92004-12-05 15:42:05 +00006538/* Lowest 32-bit lane only unary SSE operation, G = op(E). */
sewardj0bd7ce62004-12-05 02:47:40 +00006539
sewardj129b3d92004-12-05 15:42:05 +00006540static UInt dis_SSE_E_to_G_unary_lo32 (
6541 UChar sorb, UInt delta,
6542 HChar* opname, IROp op
6543 )
6544{
6545 /* First we need to get the old G value and patch the low 32 bits
6546 of the E operand into it. Then apply op and write back to G. */
6547 HChar dis_buf[50];
6548 Int alen;
6549 IRTemp addr;
6550 UChar rm = getIByte(delta);
6551 IRTemp oldG0 = newTemp(Ity_V128);
6552 IRTemp oldG1 = newTemp(Ity_V128);
6553
6554 assign( oldG0, getXMMReg(gregOfRM(rm)) );
6555
6556 if (epartIsReg(rm)) {
6557 assign( oldG1,
sewardjf0c1c582005-02-07 23:47:38 +00006558 binop( Iop_SetV128lo32,
sewardj129b3d92004-12-05 15:42:05 +00006559 mkexpr(oldG0),
sewardj35579be2004-12-06 00:36:25 +00006560 getXMMRegLane32(eregOfRM(rm), 0)) );
sewardj129b3d92004-12-05 15:42:05 +00006561 putXMMReg( gregOfRM(rm), unop(op, mkexpr(oldG1)) );
6562 DIP("%s %s,%s\n", opname,
6563 nameXMMReg(eregOfRM(rm)),
6564 nameXMMReg(gregOfRM(rm)) );
6565 return delta+1;
6566 } else {
6567 addr = disAMode ( &alen, sorb, delta, dis_buf );
6568 assign( oldG1,
sewardjf0c1c582005-02-07 23:47:38 +00006569 binop( Iop_SetV128lo32,
sewardj129b3d92004-12-05 15:42:05 +00006570 mkexpr(oldG0),
6571 loadLE(Ity_I32, mkexpr(addr)) ));
6572 putXMMReg( gregOfRM(rm), unop(op, mkexpr(oldG1)) );
6573 DIP("%s %s,%s\n", opname,
6574 dis_buf,
6575 nameXMMReg(gregOfRM(rm)) );
6576 return delta+alen;
6577 }
6578}
6579
sewardj164f9272004-12-09 00:39:32 +00006580
sewardj008754b2004-12-08 14:37:10 +00006581/* Lowest 64-bit lane only unary SSE operation, G = op(E). */
6582
6583static UInt dis_SSE_E_to_G_unary_lo64 (
6584 UChar sorb, UInt delta,
6585 HChar* opname, IROp op
6586 )
6587{
6588 /* First we need to get the old G value and patch the low 64 bits
6589 of the E operand into it. Then apply op and write back to G. */
6590 HChar dis_buf[50];
6591 Int alen;
6592 IRTemp addr;
6593 UChar rm = getIByte(delta);
6594 IRTemp oldG0 = newTemp(Ity_V128);
6595 IRTemp oldG1 = newTemp(Ity_V128);
6596
6597 assign( oldG0, getXMMReg(gregOfRM(rm)) );
6598
6599 if (epartIsReg(rm)) {
6600 assign( oldG1,
sewardjf0c1c582005-02-07 23:47:38 +00006601 binop( Iop_SetV128lo64,
sewardj008754b2004-12-08 14:37:10 +00006602 mkexpr(oldG0),
6603 getXMMRegLane64(eregOfRM(rm), 0)) );
6604 putXMMReg( gregOfRM(rm), unop(op, mkexpr(oldG1)) );
6605 DIP("%s %s,%s\n", opname,
6606 nameXMMReg(eregOfRM(rm)),
6607 nameXMMReg(gregOfRM(rm)) );
6608 return delta+1;
6609 } else {
6610 addr = disAMode ( &alen, sorb, delta, dis_buf );
6611 assign( oldG1,
sewardjf0c1c582005-02-07 23:47:38 +00006612 binop( Iop_SetV128lo64,
sewardj008754b2004-12-08 14:37:10 +00006613 mkexpr(oldG0),
6614 loadLE(Ity_I64, mkexpr(addr)) ));
6615 putXMMReg( gregOfRM(rm), unop(op, mkexpr(oldG1)) );
6616 DIP("%s %s,%s\n", opname,
6617 dis_buf,
6618 nameXMMReg(gregOfRM(rm)) );
6619 return delta+alen;
6620 }
6621}
6622
sewardj164f9272004-12-09 00:39:32 +00006623
6624/* SSE integer binary operation:
6625 G = G `op` E (eLeft == False)
6626 G = E `op` G (eLeft == True)
6627*/
6628static UInt dis_SSEint_E_to_G(
6629 UChar sorb, UInt delta,
6630 HChar* opname, IROp op,
6631 Bool eLeft
6632 )
6633{
6634 HChar dis_buf[50];
6635 Int alen;
6636 IRTemp addr;
6637 UChar rm = getIByte(delta);
6638 IRExpr* gpart = getXMMReg(gregOfRM(rm));
6639 IRExpr* epart = NULL;
6640 if (epartIsReg(rm)) {
6641 epart = getXMMReg(eregOfRM(rm));
6642 DIP("%s %s,%s\n", opname,
6643 nameXMMReg(eregOfRM(rm)),
6644 nameXMMReg(gregOfRM(rm)) );
6645 delta += 1;
6646 } else {
6647 addr = disAMode ( &alen, sorb, delta, dis_buf );
6648 epart = loadLE(Ity_V128, mkexpr(addr));
6649 DIP("%s %s,%s\n", opname,
6650 dis_buf,
6651 nameXMMReg(gregOfRM(rm)) );
6652 delta += alen;
6653 }
6654 putXMMReg( gregOfRM(rm),
6655 eLeft ? binop(op, epart, gpart)
6656 : binop(op, gpart, epart) );
6657 return delta;
6658}
6659
6660
sewardjfd226452004-12-07 19:02:18 +00006661/* Helper for doing SSE FP comparisons. */
sewardj0bd7ce62004-12-05 02:47:40 +00006662
sewardj1e6ad742004-12-02 16:16:11 +00006663static void findSSECmpOp ( Bool* needNot, IROp* op,
6664 Int imm8, Bool all_lanes, Int sz )
6665{
6666 imm8 &= 7;
6667 *needNot = False;
6668 *op = Iop_INVALID;
6669 if (imm8 >= 4) {
6670 *needNot = True;
6671 imm8 -= 4;
6672 }
6673
6674 if (sz == 4 && all_lanes) {
6675 switch (imm8) {
6676 case 0: *op = Iop_CmpEQ32Fx4; return;
6677 case 1: *op = Iop_CmpLT32Fx4; return;
6678 case 2: *op = Iop_CmpLE32Fx4; return;
6679 case 3: *op = Iop_CmpUN32Fx4; return;
6680 default: break;
6681 }
6682 }
6683 if (sz == 4 && !all_lanes) {
6684 switch (imm8) {
6685 case 0: *op = Iop_CmpEQ32F0x4; return;
6686 case 1: *op = Iop_CmpLT32F0x4; return;
6687 case 2: *op = Iop_CmpLE32F0x4; return;
6688 case 3: *op = Iop_CmpUN32F0x4; return;
6689 default: break;
6690 }
6691 }
sewardjfd226452004-12-07 19:02:18 +00006692 if (sz == 8 && all_lanes) {
6693 switch (imm8) {
6694 case 0: *op = Iop_CmpEQ64Fx2; return;
6695 case 1: *op = Iop_CmpLT64Fx2; return;
6696 case 2: *op = Iop_CmpLE64Fx2; return;
6697 case 3: *op = Iop_CmpUN64Fx2; return;
6698 default: break;
6699 }
6700 }
6701 if (sz == 8 && !all_lanes) {
6702 switch (imm8) {
6703 case 0: *op = Iop_CmpEQ64F0x2; return;
6704 case 1: *op = Iop_CmpLT64F0x2; return;
6705 case 2: *op = Iop_CmpLE64F0x2; return;
6706 case 3: *op = Iop_CmpUN64F0x2; return;
6707 default: break;
6708 }
sewardj1e6ad742004-12-02 16:16:11 +00006709 }
6710 vpanic("findSSECmpOp(x86,guest)");
6711}
6712
sewardj129b3d92004-12-05 15:42:05 +00006713/* Handles SSE 32F comparisons. */
6714
sewardj1e6ad742004-12-02 16:16:11 +00006715static UInt dis_SSEcmp_E_to_G ( UChar sorb, UInt delta,
6716 HChar* opname, Bool all_lanes, Int sz )
6717{
6718 HChar dis_buf[50];
6719 Int alen, imm8;
6720 IRTemp addr;
6721 Bool needNot = False;
6722 IROp op = Iop_INVALID;
6723 IRTemp plain = newTemp(Ity_V128);
6724 UChar rm = getIByte(delta);
6725 UShort mask = 0;
6726 vassert(sz == 4 || sz == 8);
6727 if (epartIsReg(rm)) {
6728 imm8 = getIByte(delta+1);
6729 findSSECmpOp(&needNot, &op, imm8, all_lanes, sz);
6730 assign( plain, binop(op, getXMMReg(gregOfRM(rm)),
6731 getXMMReg(eregOfRM(rm))) );
6732 delta += 2;
6733 DIP("%s $%d,%s,%s\n", opname,
6734 (Int)imm8,
6735 nameXMMReg(eregOfRM(rm)),
6736 nameXMMReg(gregOfRM(rm)) );
6737 } else {
6738 addr = disAMode ( &alen, sorb, delta, dis_buf );
6739 imm8 = getIByte(delta+alen);
6740 findSSECmpOp(&needNot, &op, imm8, all_lanes, sz);
6741 assign( plain, binop(op, getXMMReg(gregOfRM(rm)),
6742 loadLE(Ity_V128, mkexpr(addr))) );
6743 delta += alen+1;
6744 DIP("%s $%d,%s,%s\n", opname,
6745 (Int)imm8,
6746 dis_buf,
6747 nameXMMReg(gregOfRM(rm)) );
6748 }
6749
sewardj2e383862004-12-12 16:46:47 +00006750 if (needNot && all_lanes) {
6751 putXMMReg( gregOfRM(rm),
sewardjf0c1c582005-02-07 23:47:38 +00006752 unop(Iop_NotV128, mkexpr(plain)) );
sewardj2e383862004-12-12 16:46:47 +00006753 }
6754 else
6755 if (needNot && !all_lanes) {
sewardj9b45b482005-02-07 01:42:18 +00006756 mask = toUShort( sz==4 ? 0x000F : 0x00FF );
sewardj2e383862004-12-12 16:46:47 +00006757 putXMMReg( gregOfRM(rm),
sewardjf0c1c582005-02-07 23:47:38 +00006758 binop(Iop_XorV128, mkexpr(plain), mkV128(mask)) );
sewardj2e383862004-12-12 16:46:47 +00006759 }
6760 else {
6761 putXMMReg( gregOfRM(rm), mkexpr(plain) );
6762 }
sewardj1e6ad742004-12-02 16:16:11 +00006763
sewardj1e6ad742004-12-02 16:16:11 +00006764 return delta;
6765}
6766
sewardjb9fa69b2004-12-09 23:25:14 +00006767
6768/* Vector by scalar shift of G by the amount specified at the bottom
6769 of E. */
6770
6771static UInt dis_SSE_shiftG_byE ( UChar sorb, UInt delta,
6772 HChar* opname, IROp op )
6773{
6774 HChar dis_buf[50];
6775 Int alen, size;
6776 IRTemp addr;
6777 Bool shl, shr, sar;
6778 UChar rm = getIByte(delta);
6779 IRTemp g0 = newTemp(Ity_V128);
6780 IRTemp g1 = newTemp(Ity_V128);
6781 IRTemp amt = newTemp(Ity_I32);
6782 IRTemp amt8 = newTemp(Ity_I8);
6783 if (epartIsReg(rm)) {
6784 assign( amt, getXMMRegLane32(eregOfRM(rm), 0) );
6785 DIP("%s %s,%s\n", opname,
6786 nameXMMReg(eregOfRM(rm)),
6787 nameXMMReg(gregOfRM(rm)) );
6788 delta++;
6789 } else {
6790 addr = disAMode ( &alen, sorb, delta, dis_buf );
6791 assign( amt, loadLE(Ity_I32, mkexpr(addr)) );
6792 DIP("%s %s,%s\n", opname,
6793 dis_buf,
6794 nameXMMReg(gregOfRM(rm)) );
6795 delta += alen;
6796 }
6797 assign( g0, getXMMReg(gregOfRM(rm)) );
6798 assign( amt8, unop(Iop_32to8, mkexpr(amt)) );
6799
6800 shl = shr = sar = False;
6801 size = 0;
6802 switch (op) {
6803 case Iop_ShlN16x8: shl = True; size = 32; break;
6804 case Iop_ShlN32x4: shl = True; size = 32; break;
6805 case Iop_ShlN64x2: shl = True; size = 64; break;
6806 case Iop_SarN16x8: sar = True; size = 16; break;
6807 case Iop_SarN32x4: sar = True; size = 32; break;
6808 case Iop_ShrN16x8: shr = True; size = 16; break;
6809 case Iop_ShrN32x4: shr = True; size = 32; break;
6810 case Iop_ShrN64x2: shr = True; size = 64; break;
6811 default: vassert(0);
6812 }
6813
6814 if (shl || shr) {
6815 assign(
6816 g1,
6817 IRExpr_Mux0X(
6818 unop(Iop_1Uto8,binop(Iop_CmpLT32U,mkexpr(amt),mkU32(size))),
6819 mkV128(0x0000),
6820 binop(op, mkexpr(g0), mkexpr(amt8))
6821 )
6822 );
6823 } else
6824 if (sar) {
6825 assign(
6826 g1,
6827 IRExpr_Mux0X(
6828 unop(Iop_1Uto8,binop(Iop_CmpLT32U,mkexpr(amt),mkU32(size))),
6829 binop(op, mkexpr(g0), mkU8(size-1)),
6830 binop(op, mkexpr(g0), mkexpr(amt8))
6831 )
6832 );
6833 } else {
sewardjba89f4c2005-04-07 17:31:27 +00006834 /*NOTREACHED*/
sewardjb9fa69b2004-12-09 23:25:14 +00006835 vassert(0);
6836 }
6837
6838 putXMMReg( gregOfRM(rm), mkexpr(g1) );
6839 return delta;
6840}
6841
6842
6843/* Vector by scalar shift of E by an immediate byte. */
6844
sewardj38a3f862005-01-13 15:06:51 +00006845static
6846UInt dis_SSE_shiftE_imm ( UInt delta, HChar* opname, IROp op )
sewardjb9fa69b2004-12-09 23:25:14 +00006847{
6848 Bool shl, shr, sar;
6849 UChar rm = getIByte(delta);
sewardj38a3f862005-01-13 15:06:51 +00006850 IRTemp e0 = newTemp(Ity_V128);
6851 IRTemp e1 = newTemp(Ity_V128);
sewardjb9fa69b2004-12-09 23:25:14 +00006852 UChar amt, size;
6853 vassert(epartIsReg(rm));
6854 vassert(gregOfRM(rm) == 2
6855 || gregOfRM(rm) == 4 || gregOfRM(rm) == 6);
sewardj2d49b432005-02-01 00:37:06 +00006856 amt = getIByte(delta+1);
sewardjb9fa69b2004-12-09 23:25:14 +00006857 delta += 2;
6858 DIP("%s $%d,%s\n", opname,
6859 (Int)amt,
6860 nameXMMReg(eregOfRM(rm)) );
sewardj38a3f862005-01-13 15:06:51 +00006861 assign( e0, getXMMReg(eregOfRM(rm)) );
sewardjb9fa69b2004-12-09 23:25:14 +00006862
6863 shl = shr = sar = False;
6864 size = 0;
6865 switch (op) {
6866 case Iop_ShlN16x8: shl = True; size = 16; break;
6867 case Iop_ShlN32x4: shl = True; size = 32; break;
6868 case Iop_ShlN64x2: shl = True; size = 64; break;
6869 case Iop_SarN16x8: sar = True; size = 16; break;
6870 case Iop_SarN32x4: sar = True; size = 32; break;
6871 case Iop_ShrN16x8: shr = True; size = 16; break;
6872 case Iop_ShrN32x4: shr = True; size = 32; break;
6873 case Iop_ShrN64x2: shr = True; size = 64; break;
6874 default: vassert(0);
6875 }
6876
6877 if (shl || shr) {
sewardjba89f4c2005-04-07 17:31:27 +00006878 assign( e1, amt >= size
6879 ? mkV128(0x0000)
6880 : binop(op, mkexpr(e0), mkU8(amt))
6881 );
sewardjb9fa69b2004-12-09 23:25:14 +00006882 } else
6883 if (sar) {
sewardjba89f4c2005-04-07 17:31:27 +00006884 assign( e1, amt >= size
6885 ? binop(op, mkexpr(e0), mkU8(size-1))
6886 : binop(op, mkexpr(e0), mkU8(amt))
6887 );
sewardjb9fa69b2004-12-09 23:25:14 +00006888 } else {
sewardjba89f4c2005-04-07 17:31:27 +00006889 /*NOTREACHED*/
sewardjb9fa69b2004-12-09 23:25:14 +00006890 vassert(0);
6891 }
6892
sewardj38a3f862005-01-13 15:06:51 +00006893 putXMMReg( eregOfRM(rm), mkexpr(e1) );
sewardjb9fa69b2004-12-09 23:25:14 +00006894 return delta;
6895}
6896
6897
sewardjc1e7dfc2004-12-05 19:29:45 +00006898/* Get the current SSE rounding mode. */
sewardjc9a65702004-07-07 16:32:57 +00006899
sewardj4cb918d2004-12-03 19:43:31 +00006900static IRExpr* /* :: Ity_I32 */ get_sse_roundingmode ( void )
6901{
6902 return binop( Iop_And32,
6903 IRExpr_Get( OFFB_SSEROUND, Ity_I32 ),
6904 mkU32(3) );
6905}
6906
sewardj636ad762004-12-07 11:16:04 +00006907static void put_sse_roundingmode ( IRExpr* sseround )
6908{
6909 vassert(typeOfIRExpr(irbb->tyenv, sseround) == Ity_I32);
6910 stmt( IRStmt_Put( OFFB_SSEROUND, sseround ) );
6911}
6912
sewardjc1e7dfc2004-12-05 19:29:45 +00006913/* Break a 128-bit value up into four 32-bit ints. */
6914
6915static void breakup128to32s ( IRTemp t128,
6916 /*OUTs*/
6917 IRTemp* t3, IRTemp* t2,
6918 IRTemp* t1, IRTemp* t0 )
6919{
6920 IRTemp hi64 = newTemp(Ity_I64);
6921 IRTemp lo64 = newTemp(Ity_I64);
sewardjf0c1c582005-02-07 23:47:38 +00006922 assign( hi64, unop(Iop_V128HIto64, mkexpr(t128)) );
6923 assign( lo64, unop(Iop_V128to64, mkexpr(t128)) );
sewardjc1e7dfc2004-12-05 19:29:45 +00006924
6925 vassert(t0 && *t0 == IRTemp_INVALID);
6926 vassert(t1 && *t1 == IRTemp_INVALID);
6927 vassert(t2 && *t2 == IRTemp_INVALID);
6928 vassert(t3 && *t3 == IRTemp_INVALID);
6929
6930 *t0 = newTemp(Ity_I32);
6931 *t1 = newTemp(Ity_I32);
6932 *t2 = newTemp(Ity_I32);
6933 *t3 = newTemp(Ity_I32);
6934 assign( *t0, unop(Iop_64to32, mkexpr(lo64)) );
6935 assign( *t1, unop(Iop_64HIto32, mkexpr(lo64)) );
6936 assign( *t2, unop(Iop_64to32, mkexpr(hi64)) );
6937 assign( *t3, unop(Iop_64HIto32, mkexpr(hi64)) );
6938}
6939
6940/* Construct a 128-bit value from four 32-bit ints. */
6941
6942static IRExpr* mk128from32s ( IRTemp t3, IRTemp t2,
6943 IRTemp t1, IRTemp t0 )
6944{
6945 return
sewardjf0c1c582005-02-07 23:47:38 +00006946 binop( Iop_64HLtoV128,
sewardjc1e7dfc2004-12-05 19:29:45 +00006947 binop(Iop_32HLto64, mkexpr(t3), mkexpr(t2)),
6948 binop(Iop_32HLto64, mkexpr(t1), mkexpr(t0))
6949 );
6950}
6951
sewardjb9fa69b2004-12-09 23:25:14 +00006952/* Break a 64-bit value up into four 16-bit ints. */
6953
6954static void breakup64to16s ( IRTemp t64,
6955 /*OUTs*/
6956 IRTemp* t3, IRTemp* t2,
6957 IRTemp* t1, IRTemp* t0 )
6958{
6959 IRTemp hi32 = newTemp(Ity_I32);
6960 IRTemp lo32 = newTemp(Ity_I32);
6961 assign( hi32, unop(Iop_64HIto32, mkexpr(t64)) );
6962 assign( lo32, unop(Iop_64to32, mkexpr(t64)) );
6963
6964 vassert(t0 && *t0 == IRTemp_INVALID);
6965 vassert(t1 && *t1 == IRTemp_INVALID);
6966 vassert(t2 && *t2 == IRTemp_INVALID);
6967 vassert(t3 && *t3 == IRTemp_INVALID);
6968
6969 *t0 = newTemp(Ity_I16);
6970 *t1 = newTemp(Ity_I16);
6971 *t2 = newTemp(Ity_I16);
6972 *t3 = newTemp(Ity_I16);
6973 assign( *t0, unop(Iop_32to16, mkexpr(lo32)) );
6974 assign( *t1, unop(Iop_32HIto16, mkexpr(lo32)) );
6975 assign( *t2, unop(Iop_32to16, mkexpr(hi32)) );
6976 assign( *t3, unop(Iop_32HIto16, mkexpr(hi32)) );
6977}
6978
6979/* Construct a 64-bit value from four 16-bit ints. */
6980
6981static IRExpr* mk64from16s ( IRTemp t3, IRTemp t2,
6982 IRTemp t1, IRTemp t0 )
6983{
6984 return
6985 binop( Iop_32HLto64,
6986 binop(Iop_16HLto32, mkexpr(t3), mkexpr(t2)),
6987 binop(Iop_16HLto32, mkexpr(t1), mkexpr(t0))
6988 );
6989}
6990
sewardj4cb918d2004-12-03 19:43:31 +00006991
sewardjc9a65702004-07-07 16:32:57 +00006992/*------------------------------------------------------------*/
sewardjce70a5c2004-10-18 14:09:54 +00006993/*--- Disassemble a single instruction ---*/
sewardjc9a65702004-07-07 16:32:57 +00006994/*------------------------------------------------------------*/
6995
sewardjce70a5c2004-10-18 14:09:54 +00006996/* Disassemble a single instruction into IR. The instruction
6997 is located in host memory at &guest_code[delta].
6998 Set *size to be the size of the instruction.
6999 If the returned value is Dis_Resteer,
7000 the next guest address is assigned to *whereNext. If resteerOK
7001 is False, disInstr may not return Dis_Resteer. */
7002
sewardj9df271d2004-12-31 22:37:42 +00007003static
7004DisResult disInstr ( /*IN*/ Bool resteerOK,
7005 /*IN*/ Bool (*resteerOkFn) ( Addr64 ),
7006 /*IN*/ UInt delta,
7007 /*IN*/ VexSubArch subarch,
sewardj9b45b482005-02-07 01:42:18 +00007008 /*OUT*/ Int* size,
sewardj9df271d2004-12-31 22:37:42 +00007009 /*OUT*/ Addr64* whereNext )
sewardjc9a65702004-07-07 16:32:57 +00007010{
sewardjce70a5c2004-10-18 14:09:54 +00007011 IRType ty;
sewardjb5452082004-12-04 20:33:02 +00007012 IRTemp addr, t0, t1, t2, t3, t4, t5, t6;
sewardjce70a5c2004-10-18 14:09:54 +00007013 Int alen;
7014 UChar opc, modrm, abyte;
7015 UInt d32;
sewardjc9a43662004-11-30 18:51:59 +00007016 HChar dis_buf[50];
sewardjce70a5c2004-10-18 14:09:54 +00007017 Int am_sz, d_sz;
7018 DisResult whatNext = Dis_Continue;
sewardjc9a43662004-11-30 18:51:59 +00007019 UChar* insn; /* used in SSE decoders */
sewardjce70a5c2004-10-18 14:09:54 +00007020
sewardjc9a65702004-07-07 16:32:57 +00007021 /* Holds eip at the start of the insn, so that we can print
7022 consistent error messages for unimplemented insns. */
7023 UInt delta_start = delta;
7024
7025 /* sz denotes the nominal data-op size of the insn; we change it to
7026 2 if an 0x66 prefix is seen */
7027 Int sz = 4;
7028
7029 /* sorb holds the segment-override-prefix byte, if any. Zero if no
7030 prefix has been seen, else one of {0x26, 0x3E, 0x64, 0x65}
7031 indicating the prefix. */
7032 UChar sorb = 0;
7033
sewardjce70a5c2004-10-18 14:09:54 +00007034 /* If we don't set *size properly, this causes bbToIR_X86Instr to
7035 assert. */
7036 *size = 0;
7037
sewardjb5452082004-12-04 20:33:02 +00007038 addr = t0 = t1 = t2 = t3 = t4 = t5 = t6 = IRTemp_INVALID;
sewardjc9a65702004-07-07 16:32:57 +00007039
sewardjce70a5c2004-10-18 14:09:54 +00007040 DIP("\t0x%x: ", guest_eip_bbstart+delta);
sewardjc9a65702004-07-07 16:32:57 +00007041
sewardj750f4072004-07-26 22:39:11 +00007042 /* Spot the client-request magic sequence. */
7043 {
7044 UChar* code = (UChar*)(guest_code + delta);
7045 /* Spot this:
7046 C1C01D roll $29, %eax
7047 C1C003 roll $3, %eax
7048 C1C81B rorl $27, %eax
7049 C1C805 rorl $5, %eax
7050 C1C00D roll $13, %eax
7051 C1C013 roll $19, %eax
7052 */
7053 if (code[ 0] == 0xC1 && code[ 1] == 0xC0 && code[ 2] == 0x1D &&
7054 code[ 3] == 0xC1 && code[ 4] == 0xC0 && code[ 5] == 0x03 &&
7055 code[ 6] == 0xC1 && code[ 7] == 0xC8 && code[ 8] == 0x1B &&
7056 code[ 9] == 0xC1 && code[10] == 0xC8 && code[11] == 0x05 &&
7057 code[12] == 0xC1 && code[13] == 0xC0 && code[14] == 0x0D &&
7058 code[15] == 0xC1 && code[16] == 0xC0 && code[17] == 0x13
7059 ) {
sewardjce70a5c2004-10-18 14:09:54 +00007060 DIP("%%edx = client_request ( %%eax )\n");
sewardj750f4072004-07-26 22:39:11 +00007061 delta += 18;
sewardjce70a5c2004-10-18 14:09:54 +00007062 jmp_lit(Ijk_ClientReq, guest_eip_bbstart+delta);
7063 whatNext = Dis_StopHere;
7064 goto decode_success;
sewardj750f4072004-07-26 22:39:11 +00007065 }
7066 }
sewardjc9a65702004-07-07 16:32:57 +00007067
7068 /* Skip a LOCK prefix. */
sewardjce4a2822005-01-07 13:25:28 +00007069 /* 2005 Jan 06: the following insns are observed to sometimes
7070 have a LOCK prefix:
7071 cmpxchgl %ecx,(%edx)
sewardjaade6d42005-01-07 13:36:14 +00007072 cmpxchgl %edx,0x278(%ebx) etc
sewardjce4a2822005-01-07 13:25:28 +00007073 xchgl %eax, (%ecx)
7074 xaddl %eax, (%ecx)
7075 We need to catch any such which appear to be being used as
7076 a memory barrier, for example lock addl $0,0(%esp)
7077 and emit an IR MFence construct.
7078 */
sewardjbb3f52d2005-01-07 14:14:50 +00007079 if (getIByte(delta) == 0xF0) {
7080
7081 UChar* code = (UChar*)(guest_code + delta);
7082
7083 /* Various bits of kernel headers use the following as a memory
7084 barrier. Hence, first emit an MFence and then let the insn
7085 go through as usual. */
7086 /* F08344240000: lock addl $0, 0(%esp) */
7087 if (code[0] == 0xF0 && code[1] == 0x83 && code[2] == 0x44 &&
7088 code[3] == 0x24 && code[4] == 0x00 && code[5] == 0x00) {
7089 stmt( IRStmt_MFence() );
7090 }
7091 else
7092 if (0) {
sewardjce4a2822005-01-07 13:25:28 +00007093 vex_printf("vex x86->IR: ignoring LOCK prefix on: ");
7094 insn_verbose = True;
7095 }
sewardjbb3f52d2005-01-07 14:14:50 +00007096
7097 /* In any case, skip the prefix. */
sewardjc9a65702004-07-07 16:32:57 +00007098 delta++;
7099 }
7100
7101 /* Detect operand-size overrides. */
7102 if (getIByte(delta) == 0x66) { sz = 2; delta++; };
7103
7104 /* segment override prefixes come after the operand-size override,
7105 it seems */
7106 switch (getIByte(delta)) {
7107 case 0x3E: /* %DS: */
7108 case 0x26: /* %ES: */
7109 case 0x64: /* %FS: */
7110 case 0x65: /* %GS: */
7111 sorb = getIByte(delta); delta++;
7112 break;
7113 case 0x2E: /* %CS: */
7114 /* 2E prefix on a conditional branch instruction is a
7115 branch-prediction hint, which can safely be ignored. */
7116 {
7117 UChar op1 = getIByte(delta+1);
7118 UChar op2 = getIByte(delta+2);
7119 if ((op1 >= 0x70 && op1 <= 0x7F)
7120 || (op1 == 0xE3)
7121 || (op1 == 0x0F && op2 >= 0x80 && op2 <= 0x8F)) {
sewardj4dfb1992005-03-13 18:56:28 +00007122 if (0) vex_printf("vex x86->IR: ignoring branch hint\n");
sewardjc9a65702004-07-07 16:32:57 +00007123 sorb = getIByte(delta); delta++;
7124 break;
7125 }
7126 }
7127 unimplemented("x86 segment override (SEG=CS) prefix");
7128 /*NOTREACHED*/
7129 break;
7130 case 0x36: /* %SS: */
7131 unimplemented("x86 segment override (SEG=SS) prefix");
7132 /*NOTREACHED*/
7133 break;
7134 default:
7135 break;
7136 }
7137
sewardjc9a43662004-11-30 18:51:59 +00007138 /* ---------------------------------------------------- */
7139 /* --- The SSE decoder. --- */
7140 /* ---------------------------------------------------- */
7141
sewardj4cb918d2004-12-03 19:43:31 +00007142 /* What did I do to deserve SSE ? Perhaps I was really bad in a
7143 previous life? */
7144
sewardj9df271d2004-12-31 22:37:42 +00007145 /* Note, this doesn't handle SSE2 or SSE3. That is handled in a
7146 later section, further on. */
7147
sewardja0e83b02005-01-06 12:36:38 +00007148 insn = (UChar*)&guest_code[delta];
7149
7150 /* Treat fxsave specially. It should be doable even on an SSE0
7151 (Pentium-II class) CPU. Hence be prepared to handle it on
7152 any subarchitecture variant.
7153 */
7154
7155 /* 0F AE /0 = FXSAVE m512 -- write x87 and SSE state to memory */
7156 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xAE
7157 && !epartIsReg(insn[2]) && gregOfRM(insn[2]) == 0) {
sewardj9a036bf2005-03-14 18:19:08 +00007158 IRDirty* d;
sewardja0e83b02005-01-06 12:36:38 +00007159 modrm = getIByte(delta+2);
7160 vassert(sz == 4);
7161 vassert(!epartIsReg(modrm));
7162
7163 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
7164 delta += 2+alen;
7165
sewardj33dd31b2005-01-08 18:17:32 +00007166 DIP("fxsave %s\n", dis_buf);
sewardja0e83b02005-01-06 12:36:38 +00007167
7168 /* Uses dirty helper:
7169 void x86g_do_FXSAVE ( VexGuestX86State*, UInt ) */
sewardj9a036bf2005-03-14 18:19:08 +00007170 d = unsafeIRDirty_0_N (
7171 0/*regparms*/,
7172 "x86g_dirtyhelper_FXSAVE",
7173 &x86g_dirtyhelper_FXSAVE,
7174 mkIRExprVec_1( mkexpr(addr) )
7175 );
sewardja0e83b02005-01-06 12:36:38 +00007176 d->needsBBP = True;
7177
7178 /* declare we're writing memory */
7179 d->mFx = Ifx_Write;
7180 d->mAddr = mkexpr(addr);
7181 d->mSize = 512;
7182
7183 /* declare we're reading guest state */
7184 d->nFxState = 7;
7185
7186 d->fxState[0].fx = Ifx_Read;
7187 d->fxState[0].offset = OFFB_FTOP;
7188 d->fxState[0].size = sizeof(UInt);
7189
7190 d->fxState[1].fx = Ifx_Read;
7191 d->fxState[1].offset = OFFB_FPREGS;
7192 d->fxState[1].size = 8 * sizeof(ULong);
7193
7194 d->fxState[2].fx = Ifx_Read;
7195 d->fxState[2].offset = OFFB_FPTAGS;
7196 d->fxState[2].size = 8 * sizeof(UChar);
7197
7198 d->fxState[3].fx = Ifx_Read;
7199 d->fxState[3].offset = OFFB_FPROUND;
7200 d->fxState[3].size = sizeof(UInt);
7201
7202 d->fxState[4].fx = Ifx_Read;
7203 d->fxState[4].offset = OFFB_FC3210;
7204 d->fxState[4].size = sizeof(UInt);
7205
7206 d->fxState[5].fx = Ifx_Read;
7207 d->fxState[5].offset = OFFB_XMM0;
7208 d->fxState[5].size = 8 * sizeof(U128);
7209
7210 d->fxState[6].fx = Ifx_Read;
7211 d->fxState[6].offset = OFFB_SSEROUND;
7212 d->fxState[6].size = sizeof(UInt);
7213
7214 /* Be paranoid ... this assertion tries to ensure the 8 %xmm
7215 images are packed back-to-back. If not, the value of
7216 d->fxState[5].size is wrong. */
7217 vassert(16 == sizeof(U128));
7218 vassert(OFFB_XMM7 == (OFFB_XMM0 + 7 * 16));
7219
7220 stmt( IRStmt_Dirty(d) );
7221
7222 goto decode_success;
7223 }
7224
7225 /* ------ SSE decoder main ------ */
7226
sewardj9df271d2004-12-31 22:37:42 +00007227 /* Skip parts of the decoder which don't apply given the stated
7228 guest subarchitecture. */
7229 if (subarch == VexSubArchX86_sse0)
7230 goto after_sse_decoders;
7231
7232 /* Otherwise we must be doing sse1 or sse2, so we can at least try
7233 for SSE1 here. */
sewardjc9a43662004-11-30 18:51:59 +00007234
sewardjc9a43662004-11-30 18:51:59 +00007235 /* 0F 58 = ADDPS -- add 32Fx4 from R/M to R */
sewardj636ad762004-12-07 11:16:04 +00007236 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x58) {
sewardj129b3d92004-12-05 15:42:05 +00007237 delta = dis_SSE_E_to_G_all( sorb, delta+2, "addps", Iop_Add32Fx4 );
sewardjc9a43662004-11-30 18:51:59 +00007238 goto decode_success;
7239 }
7240
sewardj1e6ad742004-12-02 16:16:11 +00007241 /* F3 0F 58 = ADDSS -- add 32F0x4 from R/M to R */
7242 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x58) {
7243 vassert(sz == 4);
sewardj129b3d92004-12-05 15:42:05 +00007244 delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "addss", Iop_Add32F0x4 );
sewardj1e6ad742004-12-02 16:16:11 +00007245 goto decode_success;
7246 }
7247
7248 /* 0F 55 = ANDNPS -- G = (not G) and E */
sewardj636ad762004-12-07 11:16:04 +00007249 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x55) {
sewardjf0c1c582005-02-07 23:47:38 +00007250 delta = dis_SSE_E_to_G_all_invG( sorb, delta+2, "andnps", Iop_AndV128 );
sewardj1e6ad742004-12-02 16:16:11 +00007251 goto decode_success;
7252 }
7253
7254 /* 0F 54 = ANDPS -- G = G and E */
sewardj636ad762004-12-07 11:16:04 +00007255 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x54) {
sewardjf0c1c582005-02-07 23:47:38 +00007256 delta = dis_SSE_E_to_G_all( sorb, delta+2, "andps", Iop_AndV128 );
sewardj1e6ad742004-12-02 16:16:11 +00007257 goto decode_success;
7258 }
7259
7260 /* 0F C2 = CMPPS -- 32Fx4 comparison from R/M to R */
sewardj636ad762004-12-07 11:16:04 +00007261 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xC2) {
sewardj1e6ad742004-12-02 16:16:11 +00007262 delta = dis_SSEcmp_E_to_G( sorb, delta+2, "cmpps", True, 4 );
7263 goto decode_success;
7264 }
7265
7266 /* F3 0F C2 = CMPSS -- 32F0x4 comparison from R/M to R */
7267 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0xC2) {
7268 vassert(sz == 4);
7269 delta = dis_SSEcmp_E_to_G( sorb, delta+3, "cmpss", False, 4 );
7270 goto decode_success;
7271 }
sewardjc9a43662004-11-30 18:51:59 +00007272
sewardjfd226452004-12-07 19:02:18 +00007273 /* 0F 2F = COMISS -- 32F0x4 comparison G,E, and set ZCP */
sewardjc1e7dfc2004-12-05 19:29:45 +00007274 /* 0F 2E = UCOMISS -- 32F0x4 comparison G,E, and set ZCP */
sewardjfd226452004-12-07 19:02:18 +00007275 if (sz == 4 && insn[0] == 0x0F && (insn[1] == 0x2F || insn[1] == 0x2E)) {
sewardj67e002d2004-12-02 18:16:33 +00007276 IRTemp argL = newTemp(Ity_F32);
7277 IRTemp argR = newTemp(Ity_F32);
sewardj67e002d2004-12-02 18:16:33 +00007278 modrm = getIByte(delta+2);
7279 if (epartIsReg(modrm)) {
7280 assign( argR, getXMMRegLane32F( eregOfRM(modrm), 0/*lowest lane*/ ) );
7281 delta += 2+1;
sewardjc1e7dfc2004-12-05 19:29:45 +00007282 DIP("[u]comiss %s,%s\n", nameXMMReg(eregOfRM(modrm)),
7283 nameXMMReg(gregOfRM(modrm)) );
sewardj67e002d2004-12-02 18:16:33 +00007284 } else {
7285 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
7286 assign( argR, loadLE(Ity_F32, mkexpr(addr)) );
7287 delta += 2+alen;
sewardjc1e7dfc2004-12-05 19:29:45 +00007288 DIP("[u]comiss %s,%s\n", dis_buf,
7289 nameXMMReg(gregOfRM(modrm)) );
sewardj67e002d2004-12-02 18:16:33 +00007290 }
7291 assign( argL, getXMMRegLane32F( gregOfRM(modrm), 0/*lowest lane*/ ) );
7292
7293 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
7294 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
7295 stmt( IRStmt_Put(
7296 OFFB_CC_DEP1,
7297 binop( Iop_And32,
7298 binop(Iop_CmpF64,
7299 unop(Iop_F32toF64,mkexpr(argL)),
7300 unop(Iop_F32toF64,mkexpr(argR))),
7301 mkU32(0x45)
7302 )));
sewardja3b7e3a2005-04-05 01:54:19 +00007303 /* Set NDEP even though it isn't used. This makes redundant-PUT
7304 elimination of previous stores to this field work better. */
7305 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardj67e002d2004-12-02 18:16:33 +00007306 goto decode_success;
7307 }
sewardjc9a43662004-11-30 18:51:59 +00007308
sewardj4cb918d2004-12-03 19:43:31 +00007309 /* 0F 2A = CVTPI2PS -- convert 2 x I32 in mem/mmx to 2 x F32 in low
7310 half xmm */
sewardjfd226452004-12-07 19:02:18 +00007311 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x2A) {
sewardj4cb918d2004-12-03 19:43:31 +00007312 IRTemp arg64 = newTemp(Ity_I64);
7313 IRTemp rmode = newTemp(Ity_I32);
7314 vassert(sz == 4);
7315
7316 modrm = getIByte(delta+2);
7317 do_MMX_preamble();
7318 if (epartIsReg(modrm)) {
7319 assign( arg64, getMMXReg(eregOfRM(modrm)) );
7320 delta += 2+1;
7321 DIP("cvtpi2ps %s,%s\n", nameMMXReg(eregOfRM(modrm)),
7322 nameXMMReg(gregOfRM(modrm)));
7323 } else {
7324 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
7325 assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
7326 delta += 2+alen;
7327 DIP("cvtpi2ps %s,%s\n", dis_buf,
7328 nameXMMReg(gregOfRM(modrm)) );
7329 }
7330
7331 assign( rmode, get_sse_roundingmode() );
7332
7333 putXMMRegLane32F(
sewardj3bca9062004-12-04 14:36:09 +00007334 gregOfRM(modrm), 0,
7335 binop(Iop_F64toF32,
sewardj4cb918d2004-12-03 19:43:31 +00007336 mkexpr(rmode),
sewardj3bca9062004-12-04 14:36:09 +00007337 unop(Iop_I32toF64,
7338 unop(Iop_64to32, mkexpr(arg64)) )) );
sewardj4cb918d2004-12-03 19:43:31 +00007339
7340 putXMMRegLane32F(
7341 gregOfRM(modrm), 1,
sewardj3bca9062004-12-04 14:36:09 +00007342 binop(Iop_F64toF32,
sewardj4cb918d2004-12-03 19:43:31 +00007343 mkexpr(rmode),
sewardj3bca9062004-12-04 14:36:09 +00007344 unop(Iop_I32toF64,
7345 unop(Iop_64HIto32, mkexpr(arg64)) )) );
sewardj4cb918d2004-12-03 19:43:31 +00007346
7347 goto decode_success;
7348 }
7349
7350 /* F3 0F 2A = CVTSI2SS -- convert I32 in mem/ireg to F32 in low
7351 quarter xmm */
7352 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x2A) {
7353 IRTemp arg32 = newTemp(Ity_I32);
7354 IRTemp rmode = newTemp(Ity_I32);
7355 vassert(sz == 4);
7356
7357 modrm = getIByte(delta+3);
sewardj4cb918d2004-12-03 19:43:31 +00007358 if (epartIsReg(modrm)) {
7359 assign( arg32, getIReg(4, eregOfRM(modrm)) );
7360 delta += 3+1;
7361 DIP("cvtsi2ss %s,%s\n", nameIReg(4, eregOfRM(modrm)),
7362 nameXMMReg(gregOfRM(modrm)));
7363 } else {
7364 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
7365 assign( arg32, loadLE(Ity_I32, mkexpr(addr)) );
7366 delta += 3+alen;
7367 DIP("cvtsi2ss %s,%s\n", dis_buf,
7368 nameXMMReg(gregOfRM(modrm)) );
7369 }
7370
7371 assign( rmode, get_sse_roundingmode() );
7372
7373 putXMMRegLane32F(
sewardj3bca9062004-12-04 14:36:09 +00007374 gregOfRM(modrm), 0,
7375 binop(Iop_F64toF32,
7376 mkexpr(rmode),
7377 unop(Iop_I32toF64, mkexpr(arg32)) ) );
sewardj4cb918d2004-12-03 19:43:31 +00007378
7379 goto decode_success;
7380 }
7381
7382 /* 0F 2D = CVTPS2PI -- convert 2 x F32 in mem/low half xmm to 2 x
7383 I32 in mmx, according to prevailing SSE rounding mode */
7384 /* 0F 2C = CVTTPS2PI -- convert 2 x F32 in mem/low half xmm to 2 x
7385 I32 in mmx, rounding towards zero */
sewardjfd226452004-12-07 19:02:18 +00007386 if (sz == 4 && insn[0] == 0x0F && (insn[1] == 0x2D || insn[1] == 0x2C)) {
sewardj4cb918d2004-12-03 19:43:31 +00007387 IRTemp dst64 = newTemp(Ity_I64);
7388 IRTemp rmode = newTemp(Ity_I32);
7389 IRTemp f32lo = newTemp(Ity_F32);
7390 IRTemp f32hi = newTemp(Ity_F32);
sewardj2d49b432005-02-01 00:37:06 +00007391 Bool r2zero = toBool(insn[1] == 0x2C);
sewardj4cb918d2004-12-03 19:43:31 +00007392
7393 do_MMX_preamble();
7394 modrm = getIByte(delta+2);
7395
7396 if (epartIsReg(modrm)) {
7397 delta += 2+1;
7398 assign(f32lo, getXMMRegLane32F(eregOfRM(modrm), 0));
7399 assign(f32hi, getXMMRegLane32F(eregOfRM(modrm), 1));
7400 DIP("cvt%sps2pi %s,%s\n", r2zero ? "t" : "",
7401 nameXMMReg(eregOfRM(modrm)),
7402 nameMMXReg(gregOfRM(modrm)));
7403 } else {
7404 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
7405 assign(f32lo, loadLE(Ity_F32, mkexpr(addr)));
7406 assign(f32hi, loadLE(Ity_F32, binop( Iop_Add32,
7407 mkexpr(addr),
7408 mkU32(4) )));
7409 delta += 2+alen;
7410 DIP("cvt%sps2pi %s,%s\n", r2zero ? "t" : "",
7411 dis_buf,
7412 nameMMXReg(gregOfRM(modrm)));
7413 }
7414
7415 if (r2zero) {
7416 assign(rmode, mkU32((UInt)Irrm_ZERO) );
7417 } else {
7418 assign( rmode, get_sse_roundingmode() );
7419 }
7420
7421 assign(
7422 dst64,
7423 binop( Iop_32HLto64,
7424 binop( Iop_F64toI32,
7425 mkexpr(rmode),
7426 unop( Iop_F32toF64, mkexpr(f32hi) ) ),
7427 binop( Iop_F64toI32,
7428 mkexpr(rmode),
7429 unop( Iop_F32toF64, mkexpr(f32lo) ) )
7430 )
7431 );
7432
7433 putMMXReg(gregOfRM(modrm), mkexpr(dst64));
7434 goto decode_success;
7435 }
7436
7437 /* F3 0F 2D = CVTSS2SI -- convert F32 in mem/low quarter xmm to
7438 I32 in ireg, according to prevailing SSE rounding mode */
7439 /* F3 0F 2C = CVTTSS2SI -- convert F32 in mem/low quarter xmm to
sewardj0b210442005-02-23 13:28:27 +00007440 I32 in ireg, rounding towards zero */
sewardj4cb918d2004-12-03 19:43:31 +00007441 if (insn[0] == 0xF3 && insn[1] == 0x0F
7442 && (insn[2] == 0x2D || insn[2] == 0x2C)) {
7443 IRTemp rmode = newTemp(Ity_I32);
7444 IRTemp f32lo = newTemp(Ity_F32);
sewardj2d49b432005-02-01 00:37:06 +00007445 Bool r2zero = toBool(insn[2] == 0x2C);
sewardj4cb918d2004-12-03 19:43:31 +00007446 vassert(sz == 4);
7447
sewardj4cb918d2004-12-03 19:43:31 +00007448 modrm = getIByte(delta+3);
sewardj4cb918d2004-12-03 19:43:31 +00007449 if (epartIsReg(modrm)) {
7450 delta += 3+1;
7451 assign(f32lo, getXMMRegLane32F(eregOfRM(modrm), 0));
7452 DIP("cvt%sss2si %s,%s\n", r2zero ? "t" : "",
7453 nameXMMReg(eregOfRM(modrm)),
7454 nameIReg(4, gregOfRM(modrm)));
7455 } else {
7456 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
7457 assign(f32lo, loadLE(Ity_F32, mkexpr(addr)));
7458 delta += 3+alen;
7459 DIP("cvt%sss2si %s,%s\n", r2zero ? "t" : "",
7460 dis_buf,
7461 nameIReg(4, gregOfRM(modrm)));
7462 }
7463
7464 if (r2zero) {
sewardj7df596b2004-12-06 14:29:12 +00007465 assign( rmode, mkU32((UInt)Irrm_ZERO) );
sewardj4cb918d2004-12-03 19:43:31 +00007466 } else {
7467 assign( rmode, get_sse_roundingmode() );
7468 }
7469
7470 putIReg(4, gregOfRM(modrm),
7471 binop( Iop_F64toI32,
7472 mkexpr(rmode),
7473 unop( Iop_F32toF64, mkexpr(f32lo) ) )
7474 );
7475
7476 goto decode_success;
7477 }
7478
sewardj176a59c2004-12-03 20:08:31 +00007479 /* 0F 5E = DIVPS -- div 32Fx4 from R/M to R */
sewardjfd226452004-12-07 19:02:18 +00007480 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5E) {
sewardj129b3d92004-12-05 15:42:05 +00007481 delta = dis_SSE_E_to_G_all( sorb, delta+2, "divps", Iop_Div32Fx4 );
sewardj176a59c2004-12-03 20:08:31 +00007482 goto decode_success;
7483 }
7484
7485 /* F3 0F 5E = DIVSS -- div 32F0x4 from R/M to R */
7486 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5E) {
7487 vassert(sz == 4);
sewardj129b3d92004-12-05 15:42:05 +00007488 delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "divss", Iop_Div32F0x4 );
sewardj176a59c2004-12-03 20:08:31 +00007489 goto decode_success;
7490 }
7491
sewardj7df596b2004-12-06 14:29:12 +00007492 /* 0F AE /2 = LDMXCSR m32 -- load %mxcsr */
7493 if (insn[0] == 0x0F && insn[1] == 0xAE
7494 && !epartIsReg(insn[2]) && gregOfRM(insn[2]) == 2) {
7495
7496 IRTemp t64 = newTemp(Ity_I64);
7497 IRTemp ew = newTemp(Ity_I32);
7498
7499 modrm = getIByte(delta+2);
7500 vassert(!epartIsReg(modrm));
7501 vassert(sz == 4);
7502
7503 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
7504 delta += 2+alen;
sewardj33dd31b2005-01-08 18:17:32 +00007505 DIP("ldmxcsr %s\n", dis_buf);
sewardj7df596b2004-12-06 14:29:12 +00007506
7507 /* The only thing we observe in %mxcsr is the rounding mode.
7508 Therefore, pass the 32-bit value (SSE native-format control
7509 word) to a clean helper, getting back a 64-bit value, the
7510 lower half of which is the SSEROUND value to store, and the
7511 upper half of which is the emulation-warning token which may
7512 be generated.
7513 */
7514 /* ULong x86h_check_ldmxcsr ( UInt ); */
7515 assign( t64, mkIRExprCCall(
7516 Ity_I64, 0/*regparms*/,
sewardj3bd6f3e2004-12-13 10:48:19 +00007517 "x86g_check_ldmxcsr",
7518 &x86g_check_ldmxcsr,
sewardj7df596b2004-12-06 14:29:12 +00007519 mkIRExprVec_1( loadLE(Ity_I32, mkexpr(addr)) )
7520 )
7521 );
7522
sewardj636ad762004-12-07 11:16:04 +00007523 put_sse_roundingmode( unop(Iop_64to32, mkexpr(t64)) );
sewardj7df596b2004-12-06 14:29:12 +00007524 assign( ew, unop(Iop_64HIto32, mkexpr(t64) ) );
7525 put_emwarn( mkexpr(ew) );
7526 /* Finally, if an emulation warning was reported, side-exit to
7527 the next insn, reporting the warning, so that Valgrind's
7528 dispatcher sees the warning. */
7529 stmt(
7530 IRStmt_Exit(
7531 binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
7532 Ijk_EmWarn,
7533 IRConst_U32( ((Addr32)guest_eip_bbstart)+delta)
7534 )
7535 );
7536 goto decode_success;
7537 }
7538
sewardj176a59c2004-12-03 20:08:31 +00007539 /* 0F 5F = MAXPS -- max 32Fx4 from R/M to R */
sewardjc2feffc2004-12-08 12:31:22 +00007540 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5F) {
sewardj129b3d92004-12-05 15:42:05 +00007541 delta = dis_SSE_E_to_G_all( sorb, delta+2, "maxps", Iop_Max32Fx4 );
sewardj176a59c2004-12-03 20:08:31 +00007542 goto decode_success;
7543 }
7544
7545 /* F3 0F 5F = MAXSS -- max 32F0x4 from R/M to R */
7546 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5F) {
7547 vassert(sz == 4);
sewardj129b3d92004-12-05 15:42:05 +00007548 delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "maxss", Iop_Max32F0x4 );
sewardj176a59c2004-12-03 20:08:31 +00007549 goto decode_success;
7550 }
7551
7552 /* 0F 5D = MINPS -- min 32Fx4 from R/M to R */
sewardjc2feffc2004-12-08 12:31:22 +00007553 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5D) {
sewardj129b3d92004-12-05 15:42:05 +00007554 delta = dis_SSE_E_to_G_all( sorb, delta+2, "minps", Iop_Min32Fx4 );
sewardj176a59c2004-12-03 20:08:31 +00007555 goto decode_success;
7556 }
7557
7558 /* F3 0F 5D = MINSS -- min 32F0x4 from R/M to R */
7559 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5D) {
7560 vassert(sz == 4);
sewardj129b3d92004-12-05 15:42:05 +00007561 delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "minss", Iop_Min32F0x4 );
sewardj176a59c2004-12-03 20:08:31 +00007562 goto decode_success;
7563 }
sewardj4cb918d2004-12-03 19:43:31 +00007564
sewardj9636b442004-12-04 01:38:37 +00007565 /* 0F 28 = MOVAPS -- move from E (mem or xmm) to G (xmm). */
sewardjc2feffc2004-12-08 12:31:22 +00007566 /* 0F 10 = MOVUPS -- move from E (mem or xmm) to G (xmm). */
7567 if (sz == 4 && insn[0] == 0x0F && (insn[1] == 0x28 || insn[1] == 0x10)) {
sewardj9636b442004-12-04 01:38:37 +00007568 modrm = getIByte(delta+2);
sewardj9636b442004-12-04 01:38:37 +00007569 if (epartIsReg(modrm)) {
7570 putXMMReg( gregOfRM(modrm),
7571 getXMMReg( eregOfRM(modrm) ));
7572 DIP("mov[ua]ps %s,%s\n", nameXMMReg(eregOfRM(modrm)),
7573 nameXMMReg(gregOfRM(modrm)));
7574 delta += 2+1;
7575 } else {
7576 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
7577 putXMMReg( gregOfRM(modrm),
7578 loadLE(Ity_V128, mkexpr(addr)) );
7579 DIP("mov[ua]ps %s,%s\n", dis_buf,
7580 nameXMMReg(gregOfRM(modrm)));
7581 delta += 2+alen;
7582 }
7583 goto decode_success;
7584 }
7585
sewardj09f41552004-12-15 12:35:00 +00007586 /* 0F 29 = MOVAPS -- move from G (xmm) to E (mem or xmm). */
7587 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x29) {
7588 modrm = getIByte(delta+2);
sewardj09f41552004-12-15 12:35:00 +00007589 if (epartIsReg(modrm)) {
7590 /* fall through; awaiting test case */
7591 } else {
7592 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
7593 storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) );
7594 DIP("movaps %s,%s\n", nameXMMReg(gregOfRM(modrm)),
7595 dis_buf );
7596 delta += 2+alen;
7597 goto decode_success;
7598 }
7599 }
7600
sewardj0bd7ce62004-12-05 02:47:40 +00007601 /* 0F 16 = MOVHPS -- move from mem to high half of XMM. */
7602 /* 0F 16 = MOVLHPS -- move from lo half to hi half of XMM. */
sewardjc2feffc2004-12-08 12:31:22 +00007603 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x16) {
sewardj0bd7ce62004-12-05 02:47:40 +00007604 modrm = getIByte(delta+2);
7605 if (epartIsReg(modrm)) {
7606 delta += 2+1;
7607 putXMMRegLane64( gregOfRM(modrm), 1/*upper lane*/,
7608 getXMMRegLane64( eregOfRM(modrm), 0 ) );
7609 DIP("movhps %s,%s\n", nameXMMReg(eregOfRM(modrm)),
7610 nameXMMReg(gregOfRM(modrm)));
7611 } else {
7612 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
7613 delta += 2+alen;
7614 putXMMRegLane64( gregOfRM(modrm), 1/*upper lane*/,
7615 loadLE(Ity_I64, mkexpr(addr)) );
7616 DIP("movhps %s,%s\n", dis_buf,
sewardjc2feffc2004-12-08 12:31:22 +00007617 nameXMMReg( gregOfRM(modrm) ));
sewardj0bd7ce62004-12-05 02:47:40 +00007618 }
7619 goto decode_success;
7620 }
7621
7622 /* 0F 17 = MOVHPS -- move from high half of XMM to mem. */
sewardjc2feffc2004-12-08 12:31:22 +00007623 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x17) {
sewardj0bd7ce62004-12-05 02:47:40 +00007624 if (!epartIsReg(insn[2])) {
sewardj0bd7ce62004-12-05 02:47:40 +00007625 delta += 2;
7626 addr = disAMode ( &alen, sorb, delta, dis_buf );
7627 delta += alen;
7628 storeLE( mkexpr(addr),
7629 getXMMRegLane64( gregOfRM(insn[2]),
7630 1/*upper lane*/ ) );
7631 DIP("movhps %s,%s\n", nameXMMReg( gregOfRM(insn[2]) ),
7632 dis_buf);
7633 goto decode_success;
7634 }
7635 /* else fall through */
7636 }
7637
7638 /* 0F 12 = MOVLPS -- move from mem to low half of XMM. */
7639 /* OF 12 = MOVHLPS -- from from hi half to lo half of XMM. */
sewardjc2feffc2004-12-08 12:31:22 +00007640 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x12) {
sewardj0bd7ce62004-12-05 02:47:40 +00007641 modrm = getIByte(delta+2);
7642 if (epartIsReg(modrm)) {
7643 delta += 2+1;
7644 putXMMRegLane64( gregOfRM(modrm),
7645 0/*lower lane*/,
7646 getXMMRegLane64( eregOfRM(modrm), 1 ));
7647 DIP("movhlps %s, %s\n", nameXMMReg(eregOfRM(modrm)),
7648 nameXMMReg(gregOfRM(modrm)));
7649 } else {
7650 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
7651 delta += 2+alen;
7652 putXMMRegLane64( gregOfRM(modrm), 0/*lower lane*/,
7653 loadLE(Ity_I64, mkexpr(addr)) );
7654 DIP("movlps %s, %s\n",
7655 dis_buf, nameXMMReg( gregOfRM(modrm) ));
7656 }
7657 goto decode_success;
7658 }
7659
7660 /* 0F 13 = MOVLPS -- move from low half of XMM to mem. */
sewardjc2feffc2004-12-08 12:31:22 +00007661 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x13) {
sewardj0bd7ce62004-12-05 02:47:40 +00007662 if (!epartIsReg(insn[2])) {
sewardj0bd7ce62004-12-05 02:47:40 +00007663 delta += 2;
7664 addr = disAMode ( &alen, sorb, delta, dis_buf );
7665 delta += alen;
7666 storeLE( mkexpr(addr),
7667 getXMMRegLane64( gregOfRM(insn[2]),
7668 0/*lower lane*/ ) );
7669 DIP("movlps %s, %s\n", nameXMMReg( gregOfRM(insn[2]) ),
7670 dis_buf);
7671 goto decode_success;
7672 }
7673 /* else fall through */
7674 }
7675
sewardj9636b442004-12-04 01:38:37 +00007676 /* 0F 50 = MOVMSKPS - move 4 sign bits from 4 x F32 in xmm(E)
7677 to 4 lowest bits of ireg(G) */
7678 if (insn[0] == 0x0F && insn[1] == 0x50) {
sewardj9636b442004-12-04 01:38:37 +00007679 modrm = getIByte(delta+2);
sewardjc2feffc2004-12-08 12:31:22 +00007680 if (sz == 4 && epartIsReg(modrm)) {
7681 Int src;
7682 t0 = newTemp(Ity_I32);
7683 t1 = newTemp(Ity_I32);
7684 t2 = newTemp(Ity_I32);
7685 t3 = newTemp(Ity_I32);
sewardj129b3d92004-12-05 15:42:05 +00007686 delta += 2+1;
7687 src = eregOfRM(modrm);
7688 assign( t0, binop( Iop_And32,
7689 binop(Iop_Shr32, getXMMRegLane32(src,0), mkU8(31)),
7690 mkU32(1) ));
7691 assign( t1, binop( Iop_And32,
7692 binop(Iop_Shr32, getXMMRegLane32(src,1), mkU8(30)),
7693 mkU32(2) ));
7694 assign( t2, binop( Iop_And32,
7695 binop(Iop_Shr32, getXMMRegLane32(src,2), mkU8(29)),
7696 mkU32(4) ));
7697 assign( t3, binop( Iop_And32,
7698 binop(Iop_Shr32, getXMMRegLane32(src,3), mkU8(28)),
7699 mkU32(8) ));
7700 putIReg(4, gregOfRM(modrm),
7701 binop(Iop_Or32,
7702 binop(Iop_Or32, mkexpr(t0), mkexpr(t1)),
7703 binop(Iop_Or32, mkexpr(t2), mkexpr(t3))
7704 )
7705 );
7706 DIP("movmskps %s,%s\n", nameXMMReg(src),
7707 nameIReg(4, gregOfRM(modrm)));
7708 goto decode_success;
7709 }
7710 /* else fall through */
sewardj9636b442004-12-04 01:38:37 +00007711 }
7712
7713 /* 0F 2B = MOVNTPS -- for us, just a plain SSE store. */
sewardj703d6d62005-05-11 02:55:00 +00007714 /* 66 0F 2B = MOVNTPD -- for us, just a plain SSE store. */
sewardj9636b442004-12-04 01:38:37 +00007715 if (insn[0] == 0x0F && insn[1] == 0x2B) {
7716 modrm = getIByte(delta+2);
7717 if (!epartIsReg(modrm)) {
7718 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
7719 storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) );
sewardj703d6d62005-05-11 02:55:00 +00007720 DIP("movntp%s %s,%s\n", sz==2 ? "d" : "s",
7721 dis_buf,
7722 nameXMMReg(gregOfRM(modrm)));
sewardj9636b442004-12-04 01:38:37 +00007723 delta += 2+alen;
7724 goto decode_success;
7725 }
7726 /* else fall through */
7727 }
7728
sewardjc2feffc2004-12-08 12:31:22 +00007729 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
sewardj9636b442004-12-04 01:38:37 +00007730 /* 0F E7 = MOVNTQ -- for us, just a plain MMX store. Note, the
7731 Intel manual does not say anything about the usual business of
7732 the FP reg tags getting trashed whenever an MMX insn happens.
7733 So we just leave them alone.
7734 */
7735 if (insn[0] == 0x0F && insn[1] == 0xE7) {
7736 modrm = getIByte(delta+2);
sewardjc2feffc2004-12-08 12:31:22 +00007737 if (sz == 4 && !epartIsReg(modrm)) {
sewardj519d66f2004-12-15 11:57:58 +00007738 /* do_MMX_preamble(); Intel docs don't specify this */
sewardj9636b442004-12-04 01:38:37 +00007739 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
7740 storeLE( mkexpr(addr), getMMXReg(gregOfRM(modrm)) );
7741 DIP("movntq %s,%s\n", dis_buf,
7742 nameMMXReg(gregOfRM(modrm)));
7743 delta += 2+alen;
7744 goto decode_success;
7745 }
7746 /* else fall through */
7747 }
7748
7749 /* F3 0F 10 = MOVSS -- move 32 bits from E (mem or lo 1/4 xmm) to G
7750 (lo 1/4 xmm). If E is mem, upper 3/4 of G is zeroed out. */
7751 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x10) {
7752 vassert(sz == 4);
7753 modrm = getIByte(delta+3);
7754 if (epartIsReg(modrm)) {
7755 putXMMRegLane32( gregOfRM(modrm), 0,
7756 getXMMRegLane32( eregOfRM(modrm), 0 ));
7757 DIP("movss %s,%s\n", nameXMMReg(eregOfRM(modrm)),
7758 nameXMMReg(gregOfRM(modrm)));
7759 delta += 3+1;
7760 } else {
7761 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
sewardjad50db02005-04-06 01:45:44 +00007762 /* zero bits 127:64 */
7763 putXMMRegLane64( gregOfRM(modrm), 1, mkU64(0) );
7764 /* zero bits 63:32 */
7765 putXMMRegLane32( gregOfRM(modrm), 1, mkU32(0) );
7766 /* write bits 31:0 */
sewardj9636b442004-12-04 01:38:37 +00007767 putXMMRegLane32( gregOfRM(modrm), 0,
7768 loadLE(Ity_I32, mkexpr(addr)) );
7769 DIP("movss %s,%s\n", dis_buf,
7770 nameXMMReg(gregOfRM(modrm)));
7771 delta += 3+alen;
7772 }
7773 goto decode_success;
7774 }
7775
7776 /* F3 0F 11 = MOVSS -- move 32 bits from G (lo 1/4 xmm) to E (mem
7777 or lo 1/4 xmm). */
7778 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x11) {
7779 vassert(sz == 4);
7780 modrm = getIByte(delta+3);
7781 if (epartIsReg(modrm)) {
7782 /* fall through, we don't yet have a test case */
7783 } else {
7784 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
7785 storeLE( mkexpr(addr),
sewardj519d66f2004-12-15 11:57:58 +00007786 getXMMRegLane32(gregOfRM(modrm), 0) );
7787 DIP("movss %s,%s\n", nameXMMReg(gregOfRM(modrm)),
sewardj9636b442004-12-04 01:38:37 +00007788 dis_buf);
7789 delta += 3+alen;
7790 goto decode_success;
7791 }
7792 }
7793
7794 /* 0F 59 = MULPS -- mul 32Fx4 from R/M to R */
sewardj008754b2004-12-08 14:37:10 +00007795 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x59) {
sewardj129b3d92004-12-05 15:42:05 +00007796 delta = dis_SSE_E_to_G_all( sorb, delta+2, "mulps", Iop_Mul32Fx4 );
sewardj9636b442004-12-04 01:38:37 +00007797 goto decode_success;
7798 }
7799
7800 /* F3 0F 59 = MULSS -- mul 32F0x4 from R/M to R */
7801 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x59) {
7802 vassert(sz == 4);
sewardj129b3d92004-12-05 15:42:05 +00007803 delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "mulss", Iop_Mul32F0x4 );
sewardj9636b442004-12-04 01:38:37 +00007804 goto decode_success;
7805 }
7806
7807 /* 0F 56 = ORPS -- G = G and E */
sewardj008754b2004-12-08 14:37:10 +00007808 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x56) {
sewardjf0c1c582005-02-07 23:47:38 +00007809 delta = dis_SSE_E_to_G_all( sorb, delta+2, "orps", Iop_OrV128 );
sewardj9636b442004-12-04 01:38:37 +00007810 goto decode_success;
7811 }
7812
sewardj3bca9062004-12-04 14:36:09 +00007813 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
7814 /* 0F E0 = PAVGB -- 8x8 unsigned Packed Average, with rounding */
sewardj164f9272004-12-09 00:39:32 +00007815 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xE0) {
sewardjb5452082004-12-04 20:33:02 +00007816 do_MMX_preamble();
7817 delta = dis_MMXop_regmem_to_reg (
7818 sorb, delta+2, insn[1], "pavgb", False );
7819 goto decode_success;
sewardj3bca9062004-12-04 14:36:09 +00007820 }
7821
sewardjb5452082004-12-04 20:33:02 +00007822 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
7823 /* 0F E3 = PAVGW -- 16x4 unsigned Packed Average, with rounding */
sewardj164f9272004-12-09 00:39:32 +00007824 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xE3) {
sewardjb5452082004-12-04 20:33:02 +00007825 do_MMX_preamble();
7826 delta = dis_MMXop_regmem_to_reg (
7827 sorb, delta+2, insn[1], "pavgw", False );
7828 goto decode_success;
7829 }
7830
7831 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
7832 /* 0F C5 = PEXTRW -- extract 16-bit field from mmx(E) and put
7833 zero-extend of it in ireg(G). */
7834 if (insn[0] == 0x0F && insn[1] == 0xC5) {
7835 modrm = insn[2];
7836 if (sz == 4 && epartIsReg(modrm)) {
sewardjb9fa69b2004-12-09 23:25:14 +00007837 IRTemp sV = newTemp(Ity_I64);
7838 t5 = newTemp(Ity_I16);
sewardjb5452082004-12-04 20:33:02 +00007839 do_MMX_preamble();
sewardjb9fa69b2004-12-09 23:25:14 +00007840 assign(sV, getMMXReg(eregOfRM(modrm)));
7841 breakup64to16s( sV, &t3, &t2, &t1, &t0 );
sewardjb5452082004-12-04 20:33:02 +00007842 switch (insn[3] & 3) {
sewardjb9fa69b2004-12-09 23:25:14 +00007843 case 0: assign(t5, mkexpr(t0)); break;
7844 case 1: assign(t5, mkexpr(t1)); break;
7845 case 2: assign(t5, mkexpr(t2)); break;
7846 case 3: assign(t5, mkexpr(t3)); break;
sewardjba89f4c2005-04-07 17:31:27 +00007847 default: vassert(0); /*NOTREACHED*/
sewardjb5452082004-12-04 20:33:02 +00007848 }
sewardjb9fa69b2004-12-09 23:25:14 +00007849 putIReg(4, gregOfRM(modrm), unop(Iop_16Uto32, mkexpr(t5)));
sewardjb5452082004-12-04 20:33:02 +00007850 DIP("pextrw $%d,%s,%s\n",
7851 (Int)insn[3], nameMMXReg(eregOfRM(modrm)),
7852 nameIReg(4,gregOfRM(modrm)));
7853 delta += 4;
7854 goto decode_success;
7855 }
7856 /* else fall through */
7857 }
7858
7859 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
7860 /* 0F C4 = PINSRW -- get 16 bits from E(mem or low half ireg) and
7861 put it into the specified lane of mmx(G). */
sewardje5854d62004-12-09 03:44:34 +00007862 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xC4) {
7863 /* Use t0 .. t3 to hold the 4 original 16-bit lanes of the
7864 mmx reg. t4 is the new lane value. t5 is the original
7865 mmx value. t6 is the new mmx value. */
7866 Int lane;
sewardje5854d62004-12-09 03:44:34 +00007867 t4 = newTemp(Ity_I16);
7868 t5 = newTemp(Ity_I64);
7869 t6 = newTemp(Ity_I64);
7870 modrm = insn[2];
7871 do_MMX_preamble();
sewardjb5452082004-12-04 20:33:02 +00007872
sewardje5854d62004-12-09 03:44:34 +00007873 assign(t5, getMMXReg(gregOfRM(modrm)));
sewardjb9fa69b2004-12-09 23:25:14 +00007874 breakup64to16s( t5, &t3, &t2, &t1, &t0 );
sewardjb5452082004-12-04 20:33:02 +00007875
sewardje5854d62004-12-09 03:44:34 +00007876 if (epartIsReg(modrm)) {
7877 assign(t4, getIReg(2, eregOfRM(modrm)));
sewardjaac7e082005-03-17 14:03:46 +00007878 delta += 3+1;
7879 lane = insn[3+1-1];
sewardje5854d62004-12-09 03:44:34 +00007880 DIP("pinsrw $%d,%s,%s\n", (Int)lane,
7881 nameIReg(2,eregOfRM(modrm)),
7882 nameMMXReg(gregOfRM(modrm)));
7883 } else {
sewardj7420b092005-03-13 20:19:19 +00007884 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
7885 delta += 3+alen;
7886 lane = insn[3+alen-1];
7887 assign(t4, loadLE(Ity_I16, mkexpr(addr)));
7888 DIP("pinsrw $%d,%s,%s\n", (Int)lane,
7889 dis_buf,
7890 nameMMXReg(gregOfRM(modrm)));
sewardjb5452082004-12-04 20:33:02 +00007891 }
sewardje5854d62004-12-09 03:44:34 +00007892
7893 switch (lane & 3) {
sewardjb9fa69b2004-12-09 23:25:14 +00007894 case 0: assign(t6, mk64from16s(t3,t2,t1,t4)); break;
7895 case 1: assign(t6, mk64from16s(t3,t2,t4,t0)); break;
7896 case 2: assign(t6, mk64from16s(t3,t4,t1,t0)); break;
7897 case 3: assign(t6, mk64from16s(t4,t2,t1,t0)); break;
sewardjba89f4c2005-04-07 17:31:27 +00007898 default: vassert(0); /*NOTREACHED*/
sewardje5854d62004-12-09 03:44:34 +00007899 }
7900 putMMXReg(gregOfRM(modrm), mkexpr(t6));
7901 goto decode_success;
sewardjb5452082004-12-04 20:33:02 +00007902 }
7903
7904 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
7905 /* 0F EE = PMAXSW -- 16x4 signed max */
sewardje5854d62004-12-09 03:44:34 +00007906 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xEE) {
sewardjb5452082004-12-04 20:33:02 +00007907 do_MMX_preamble();
7908 delta = dis_MMXop_regmem_to_reg (
7909 sorb, delta+2, insn[1], "pmaxsw", False );
7910 goto decode_success;
7911 }
7912
7913 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
7914 /* 0F DE = PMAXUB -- 8x8 unsigned max */
sewardje5854d62004-12-09 03:44:34 +00007915 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xDE) {
sewardjb5452082004-12-04 20:33:02 +00007916 do_MMX_preamble();
7917 delta = dis_MMXop_regmem_to_reg (
7918 sorb, delta+2, insn[1], "pmaxub", False );
7919 goto decode_success;
7920 }
7921
7922 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
7923 /* 0F EA = PMINSW -- 16x4 signed min */
sewardje5854d62004-12-09 03:44:34 +00007924 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xEA) {
sewardjb5452082004-12-04 20:33:02 +00007925 do_MMX_preamble();
7926 delta = dis_MMXop_regmem_to_reg (
7927 sorb, delta+2, insn[1], "pminsw", False );
7928 goto decode_success;
7929 }
7930
7931 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
7932 /* 0F DA = PMINUB -- 8x8 unsigned min */
sewardje5854d62004-12-09 03:44:34 +00007933 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xDA) {
sewardjb5452082004-12-04 20:33:02 +00007934 do_MMX_preamble();
7935 delta = dis_MMXop_regmem_to_reg (
7936 sorb, delta+2, insn[1], "pminub", False );
7937 goto decode_success;
7938 }
7939
7940 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
7941 /* 0F D7 = PMOVMSKB -- extract sign bits from each of 8 lanes in
7942 mmx(G), turn them into a byte, and put zero-extend of it in
7943 ireg(G). */
sewardje5854d62004-12-09 03:44:34 +00007944 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xD7) {
sewardjb5452082004-12-04 20:33:02 +00007945 modrm = insn[2];
sewardje5854d62004-12-09 03:44:34 +00007946 if (epartIsReg(modrm)) {
sewardjb5452082004-12-04 20:33:02 +00007947 do_MMX_preamble();
7948 t0 = newTemp(Ity_I64);
7949 t1 = newTemp(Ity_I32);
7950 assign(t0, getMMXReg(eregOfRM(modrm)));
7951 assign(t1, mkIRExprCCall(
7952 Ity_I32, 0/*regparms*/,
sewardj38a3f862005-01-13 15:06:51 +00007953 "x86g_calculate_mmx_pmovmskb",
7954 &x86g_calculate_mmx_pmovmskb,
sewardjb5452082004-12-04 20:33:02 +00007955 mkIRExprVec_1(mkexpr(t0))));
7956 putIReg(4, gregOfRM(modrm), mkexpr(t1));
7957 DIP("pmovmskb %s,%s\n", nameMMXReg(eregOfRM(modrm)),
7958 nameIReg(4,gregOfRM(modrm)));
7959 delta += 3;
7960 goto decode_success;
7961 }
7962 /* else fall through */
7963 }
7964
sewardj0bd7ce62004-12-05 02:47:40 +00007965 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
7966 /* 0F E4 = PMULUH -- 16x4 hi-half of unsigned widening multiply */
sewardje5854d62004-12-09 03:44:34 +00007967 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xE4) {
sewardj0bd7ce62004-12-05 02:47:40 +00007968 do_MMX_preamble();
7969 delta = dis_MMXop_regmem_to_reg (
7970 sorb, delta+2, insn[1], "pmuluh", False );
7971 goto decode_success;
7972 }
7973
sewardj7df596b2004-12-06 14:29:12 +00007974 /* 0F 18 /0 = PREFETCHNTA -- prefetch into caches, */
7975 /* 0F 18 /1 = PREFETCH0 -- with various different hints */
7976 /* 0F 18 /2 = PREFETCH1 */
7977 /* 0F 18 /3 = PREFETCH2 */
7978 if (insn[0] == 0x0F && insn[1] == 0x18
7979 && !epartIsReg(insn[2])
7980 && gregOfRM(insn[2]) >= 0 && gregOfRM(insn[2]) <= 3) {
7981 HChar* hintstr = "??";
7982
7983 modrm = getIByte(delta+2);
7984 vassert(!epartIsReg(modrm));
7985
7986 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
7987 delta += 2+alen;
7988
7989 switch (gregOfRM(modrm)) {
7990 case 0: hintstr = "nta"; break;
7991 case 1: hintstr = "t0"; break;
7992 case 2: hintstr = "t1"; break;
7993 case 3: hintstr = "t2"; break;
sewardjba89f4c2005-04-07 17:31:27 +00007994 default: vassert(0); /*NOTREACHED*/
sewardj7df596b2004-12-06 14:29:12 +00007995 }
7996
7997 DIP("prefetch%s %s\n", hintstr, dis_buf);
7998 goto decode_success;
7999 }
8000
sewardj0bd7ce62004-12-05 02:47:40 +00008001 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8002 /* 0F F6 = PSADBW -- sum of 8Ux8 absolute differences */
8003 if (insn[0] == 0x0F && insn[1] == 0xF6) {
8004 vassert(sz == 4);
8005 do_MMX_preamble();
8006 delta = dis_MMXop_regmem_to_reg (
8007 sorb, delta+2, insn[1], "psadbw", False );
8008 goto decode_success;
8009 }
8010
8011 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8012 /* 0F 70 = PSHUFW -- rearrange 4x16 from E(mmx or mem) to G(mmx) */
sewardjb9fa69b2004-12-09 23:25:14 +00008013 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x70) {
sewardj0bd7ce62004-12-05 02:47:40 +00008014 Int order;
sewardjb9fa69b2004-12-09 23:25:14 +00008015 IRTemp sV, dV, s3, s2, s1, s0;
8016 s3 = s2 = s1 = s0 = IRTemp_INVALID;
8017 sV = newTemp(Ity_I64);
8018 dV = newTemp(Ity_I64);
sewardj0bd7ce62004-12-05 02:47:40 +00008019 do_MMX_preamble();
8020 modrm = insn[2];
8021 if (epartIsReg(modrm)) {
sewardjb9fa69b2004-12-09 23:25:14 +00008022 assign( sV, getMMXReg(eregOfRM(modrm)) );
sewardj0bd7ce62004-12-05 02:47:40 +00008023 order = (Int)insn[3];
8024 delta += 2+2;
8025 DIP("pshufw $%d,%s,%s\n", order,
8026 nameMMXReg(eregOfRM(modrm)),
8027 nameMMXReg(gregOfRM(modrm)));
8028 } else {
8029 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
sewardjb9fa69b2004-12-09 23:25:14 +00008030 assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
sewardj0bd7ce62004-12-05 02:47:40 +00008031 order = (Int)insn[2+alen];
8032 delta += 3+alen;
8033 DIP("pshufw $%d,%s,%s\n", order,
8034 dis_buf,
8035 nameMMXReg(gregOfRM(modrm)));
8036 }
sewardjb9fa69b2004-12-09 23:25:14 +00008037 breakup64to16s( sV, &s3, &s2, &s1, &s0 );
sewardj0bd7ce62004-12-05 02:47:40 +00008038
sewardjb9fa69b2004-12-09 23:25:14 +00008039# define SEL(n) \
8040 ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
8041 assign(dV,
8042 mk64from16s( SEL((order>>6)&3), SEL((order>>4)&3),
8043 SEL((order>>2)&3), SEL((order>>0)&3) )
sewardj0bd7ce62004-12-05 02:47:40 +00008044 );
sewardjb9fa69b2004-12-09 23:25:14 +00008045 putMMXReg(gregOfRM(modrm), mkexpr(dV));
sewardj0bd7ce62004-12-05 02:47:40 +00008046# undef SEL
sewardj0bd7ce62004-12-05 02:47:40 +00008047 goto decode_success;
8048 }
8049
8050 /* 0F 53 = RCPPS -- approx reciprocal 32Fx4 from R/M to R */
8051 if (insn[0] == 0x0F && insn[1] == 0x53) {
8052 vassert(sz == 4);
sewardj129b3d92004-12-05 15:42:05 +00008053 delta = dis_SSE_E_to_G_unary_all( sorb, delta+2,
8054 "rcpps", Iop_Recip32Fx4 );
sewardj0bd7ce62004-12-05 02:47:40 +00008055 goto decode_success;
8056 }
8057
8058 /* F3 0F 53 = RCPSS -- approx reciprocal 32F0x4 from R/M to R */
8059 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x53) {
8060 vassert(sz == 4);
sewardj129b3d92004-12-05 15:42:05 +00008061 delta = dis_SSE_E_to_G_unary_lo32( sorb, delta+3,
8062 "rcpss", Iop_Recip32F0x4 );
sewardj0bd7ce62004-12-05 02:47:40 +00008063 goto decode_success;
8064 }
sewardjb5452082004-12-04 20:33:02 +00008065
sewardjc1e7dfc2004-12-05 19:29:45 +00008066 /* 0F 52 = RSQRTPS -- approx reciprocal sqrt 32Fx4 from R/M to R */
8067 if (insn[0] == 0x0F && insn[1] == 0x52) {
8068 vassert(sz == 4);
8069 delta = dis_SSE_E_to_G_unary_all( sorb, delta+2,
8070 "rsqrtps", Iop_RSqrt32Fx4 );
8071 goto decode_success;
8072 }
8073
8074 /* F3 0F 52 = RSQRTSS -- approx reciprocal sqrt 32F0x4 from R/M to R */
8075 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x52) {
8076 vassert(sz == 4);
8077 delta = dis_SSE_E_to_G_unary_lo32( sorb, delta+3,
8078 "rsqrtss", Iop_RSqrt32F0x4 );
8079 goto decode_success;
8080 }
8081
8082 /* 0F AE /7 = SFENCE -- flush pending operations to memory */
8083 if (insn[0] == 0x0F && insn[1] == 0xAE
sewardjc2feffc2004-12-08 12:31:22 +00008084 && epartIsReg(insn[2]) && gregOfRM(insn[2]) == 7) {
sewardjc1e7dfc2004-12-05 19:29:45 +00008085 vassert(sz == 4);
8086 delta += 3;
sewardj3e838932005-01-07 12:09:15 +00008087 /* Insert a memory fence. It's sometimes important that these
8088 are carried through to the generated code. */
8089 stmt( IRStmt_MFence() );
sewardjc1e7dfc2004-12-05 19:29:45 +00008090 DIP("sfence\n");
8091 goto decode_success;
8092 }
8093
8094 /* 0F C6 /r ib = SHUFPS -- shuffle packed F32s */
sewardj008754b2004-12-08 14:37:10 +00008095 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xC6) {
sewardjc1e7dfc2004-12-05 19:29:45 +00008096 Int select;
8097 IRTemp sV, dV;
8098 IRTemp s3, s2, s1, s0, d3, d2, d1, d0;
8099 sV = newTemp(Ity_V128);
8100 dV = newTemp(Ity_V128);
8101 s3 = s2 = s1 = s0 = d3 = d2 = d1 = d0 = IRTemp_INVALID;
sewardjc1e7dfc2004-12-05 19:29:45 +00008102 modrm = insn[2];
8103 assign( dV, getXMMReg(gregOfRM(modrm)) );
8104
8105 if (epartIsReg(modrm)) {
8106 assign( sV, getXMMReg(eregOfRM(modrm)) );
8107 select = (Int)insn[3];
8108 delta += 2+2;
8109 DIP("shufps $%d,%s,%s\n", select,
8110 nameXMMReg(eregOfRM(modrm)),
8111 nameXMMReg(gregOfRM(modrm)));
8112 } else {
8113 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8114 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
8115 select = (Int)insn[2+alen];
8116 delta += 3+alen;
8117 DIP("shufps $%d,%s,%s\n", select,
8118 dis_buf,
8119 nameXMMReg(gregOfRM(modrm)));
8120 }
8121
8122 breakup128to32s( dV, &d3, &d2, &d1, &d0 );
8123 breakup128to32s( sV, &s3, &s2, &s1, &s0 );
8124
8125# define SELD(n) ((n)==0 ? d0 : ((n)==1 ? d1 : ((n)==2 ? d2 : d3)))
8126# define SELS(n) ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
8127
8128 putXMMReg(
8129 gregOfRM(modrm),
8130 mk128from32s( SELS((select>>6)&3), SELS((select>>4)&3),
8131 SELD((select>>2)&3), SELD((select>>0)&3) )
8132 );
8133
8134# undef SELD
8135# undef SELS
8136
8137 goto decode_success;
8138 }
8139
8140 /* 0F 51 = SQRTPS -- approx sqrt 32Fx4 from R/M to R */
sewardj008754b2004-12-08 14:37:10 +00008141 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x51) {
sewardjc1e7dfc2004-12-05 19:29:45 +00008142 delta = dis_SSE_E_to_G_unary_all( sorb, delta+2,
8143 "sqrtps", Iop_Sqrt32Fx4 );
8144 goto decode_success;
8145 }
8146
8147 /* F3 0F 51 = SQRTSS -- approx sqrt 32F0x4 from R/M to R */
8148 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x51) {
8149 vassert(sz == 4);
8150 delta = dis_SSE_E_to_G_unary_lo32( sorb, delta+3,
8151 "sqrtss", Iop_Sqrt32F0x4 );
8152 goto decode_success;
8153 }
8154
sewardja0e83b02005-01-06 12:36:38 +00008155 /* 0F AE /3 = STMXCSR m32 -- store %mxcsr */
sewardj7df596b2004-12-06 14:29:12 +00008156 if (insn[0] == 0x0F && insn[1] == 0xAE
8157 && !epartIsReg(insn[2]) && gregOfRM(insn[2]) == 3) {
8158 modrm = getIByte(delta+2);
8159 vassert(sz == 4);
8160 vassert(!epartIsReg(modrm));
8161
8162 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8163 delta += 2+alen;
8164
8165 /* Fake up a native SSE mxcsr word. The only thing it depends
8166 on is SSEROUND[1:0], so call a clean helper to cook it up.
8167 */
8168 /* UInt x86h_create_mxcsr ( UInt sseround ) */
sewardj33dd31b2005-01-08 18:17:32 +00008169 DIP("stmxcsr %s\n", dis_buf);
sewardj7df596b2004-12-06 14:29:12 +00008170 storeLE( mkexpr(addr),
8171 mkIRExprCCall(
8172 Ity_I32, 0/*regp*/,
sewardj3bd6f3e2004-12-13 10:48:19 +00008173 "x86g_create_mxcsr", &x86g_create_mxcsr,
sewardja0e83b02005-01-06 12:36:38 +00008174 mkIRExprVec_1( get_sse_roundingmode() )
sewardj7df596b2004-12-06 14:29:12 +00008175 )
8176 );
8177 goto decode_success;
8178 }
8179
sewardjc1e7dfc2004-12-05 19:29:45 +00008180 /* 0F 5C = SUBPS -- sub 32Fx4 from R/M to R */
sewardj008754b2004-12-08 14:37:10 +00008181 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5C) {
sewardjc1e7dfc2004-12-05 19:29:45 +00008182 delta = dis_SSE_E_to_G_all( sorb, delta+2, "subps", Iop_Sub32Fx4 );
8183 goto decode_success;
8184 }
8185
sewardj008754b2004-12-08 14:37:10 +00008186 /* F3 0F 5C = SUBSS -- sub 32F0x4 from R/M to R */
sewardjc1e7dfc2004-12-05 19:29:45 +00008187 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5C) {
8188 vassert(sz == 4);
8189 delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "subss", Iop_Sub32F0x4 );
8190 goto decode_success;
8191 }
8192
8193 /* 0F 15 = UNPCKHPS -- unpack and interleave high part F32s */
8194 /* 0F 14 = UNPCKLPS -- unpack and interleave low part F32s */
8195 /* These just appear to be special cases of SHUFPS */
sewardj008754b2004-12-08 14:37:10 +00008196 if (sz == 4 && insn[0] == 0x0F && (insn[1] == 0x15 || insn[1] == 0x14)) {
sewardjc1e7dfc2004-12-05 19:29:45 +00008197 IRTemp sV, dV;
8198 IRTemp s3, s2, s1, s0, d3, d2, d1, d0;
sewardj2d49b432005-02-01 00:37:06 +00008199 Bool hi = toBool(insn[1] == 0x15);
sewardjc1e7dfc2004-12-05 19:29:45 +00008200 sV = newTemp(Ity_V128);
8201 dV = newTemp(Ity_V128);
8202 s3 = s2 = s1 = s0 = d3 = d2 = d1 = d0 = IRTemp_INVALID;
sewardjc1e7dfc2004-12-05 19:29:45 +00008203 modrm = insn[2];
8204 assign( dV, getXMMReg(gregOfRM(modrm)) );
8205
8206 if (epartIsReg(modrm)) {
8207 assign( sV, getXMMReg(eregOfRM(modrm)) );
8208 delta += 2+1;
8209 DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
8210 nameXMMReg(eregOfRM(modrm)),
8211 nameXMMReg(gregOfRM(modrm)));
8212 } else {
8213 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8214 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
8215 delta += 2+alen;
8216 DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
8217 dis_buf,
8218 nameXMMReg(gregOfRM(modrm)));
8219 }
8220
8221 breakup128to32s( dV, &d3, &d2, &d1, &d0 );
8222 breakup128to32s( sV, &s3, &s2, &s1, &s0 );
8223
8224 if (hi) {
8225 putXMMReg( gregOfRM(modrm), mk128from32s( s3, d3, s2, d2 ) );
8226 } else {
8227 putXMMReg( gregOfRM(modrm), mk128from32s( s1, d1, s0, d0 ) );
8228 }
8229
8230 goto decode_success;
8231 }
8232
8233 /* 0F 57 = XORPS -- G = G and E */
sewardj008754b2004-12-08 14:37:10 +00008234 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x57) {
sewardjf0c1c582005-02-07 23:47:38 +00008235 delta = dis_SSE_E_to_G_all( sorb, delta+2, "xorps", Iop_XorV128 );
sewardjc1e7dfc2004-12-05 19:29:45 +00008236 goto decode_success;
8237 }
8238
sewardj636ad762004-12-07 11:16:04 +00008239 /* ---------------------------------------------------- */
8240 /* --- end of the SSE decoder. --- */
8241 /* ---------------------------------------------------- */
8242
8243 /* ---------------------------------------------------- */
8244 /* --- start of the SSE2 decoder. --- */
8245 /* ---------------------------------------------------- */
8246
sewardj9df271d2004-12-31 22:37:42 +00008247 /* Skip parts of the decoder which don't apply given the stated
8248 guest subarchitecture. */
8249 if (subarch == VexSubArchX86_sse0 || subarch == VexSubArchX86_sse1)
8250 goto after_sse_decoders;
8251
sewardj636ad762004-12-07 11:16:04 +00008252 insn = (UChar*)&guest_code[delta];
8253
8254 /* 66 0F 58 = ADDPD -- add 32Fx4 from R/M to R */
8255 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x58) {
8256 delta = dis_SSE_E_to_G_all( sorb, delta+2, "addpd", Iop_Add64Fx2 );
8257 goto decode_success;
8258 }
8259
8260 /* F2 0F 58 = ADDSD -- add 64F0x2 from R/M to R */
8261 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x58) {
8262 vassert(sz == 4);
8263 delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "addsd", Iop_Add64F0x2 );
8264 goto decode_success;
8265 }
8266
8267 /* 66 0F 55 = ANDNPD -- G = (not G) and E */
8268 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x55) {
sewardjf0c1c582005-02-07 23:47:38 +00008269 delta = dis_SSE_E_to_G_all_invG( sorb, delta+2, "andnpd", Iop_AndV128 );
sewardj636ad762004-12-07 11:16:04 +00008270 goto decode_success;
8271 }
8272
8273 /* 66 0F 54 = ANDPD -- G = G and E */
8274 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x54) {
sewardjf0c1c582005-02-07 23:47:38 +00008275 delta = dis_SSE_E_to_G_all( sorb, delta+2, "andpd", Iop_AndV128 );
sewardj636ad762004-12-07 11:16:04 +00008276 goto decode_success;
8277 }
8278
sewardjfd226452004-12-07 19:02:18 +00008279 /* 66 0F C2 = CMPPD -- 64Fx2 comparison from R/M to R */
8280 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xC2) {
8281 delta = dis_SSEcmp_E_to_G( sorb, delta+2, "cmppd", True, 8 );
8282 goto decode_success;
8283 }
8284
8285 /* F2 0F C2 = CMPSD -- 64F0x2 comparison from R/M to R */
8286 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0xC2) {
8287 vassert(sz == 4);
8288 delta = dis_SSEcmp_E_to_G( sorb, delta+3, "cmpsd", False, 8 );
8289 goto decode_success;
8290 }
8291
8292 /* 66 0F 2F = COMISD -- 64F0x2 comparison G,E, and set ZCP */
8293 /* 66 0F 2E = UCOMISD -- 64F0x2 comparison G,E, and set ZCP */
8294 if (sz == 2 && insn[0] == 0x0F && (insn[1] == 0x2F || insn[1] == 0x2E)) {
8295 IRTemp argL = newTemp(Ity_F64);
8296 IRTemp argR = newTemp(Ity_F64);
8297 modrm = getIByte(delta+2);
8298 if (epartIsReg(modrm)) {
8299 assign( argR, getXMMRegLane64F( eregOfRM(modrm), 0/*lowest lane*/ ) );
8300 delta += 2+1;
8301 DIP("[u]comisd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
8302 nameXMMReg(gregOfRM(modrm)) );
8303 } else {
8304 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8305 assign( argR, loadLE(Ity_F64, mkexpr(addr)) );
8306 delta += 2+alen;
8307 DIP("[u]comisd %s,%s\n", dis_buf,
8308 nameXMMReg(gregOfRM(modrm)) );
8309 }
8310 assign( argL, getXMMRegLane64F( gregOfRM(modrm), 0/*lowest lane*/ ) );
8311
8312 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
8313 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
8314 stmt( IRStmt_Put(
8315 OFFB_CC_DEP1,
8316 binop( Iop_And32,
8317 binop(Iop_CmpF64, mkexpr(argL), mkexpr(argR)),
8318 mkU32(0x45)
8319 )));
sewardja3b7e3a2005-04-05 01:54:19 +00008320 /* Set NDEP even though it isn't used. This makes redundant-PUT
8321 elimination of previous stores to this field work better. */
8322 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardjfd226452004-12-07 19:02:18 +00008323 goto decode_success;
8324 }
8325
8326 /* F3 0F E6 = CVTDQ2PD -- convert 2 x I32 in mem/lo half xmm to 2 x
8327 F64 in xmm(G) */
8328 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0xE6) {
8329 IRTemp arg64 = newTemp(Ity_I64);
8330 vassert(sz == 4);
8331
8332 modrm = getIByte(delta+3);
8333 if (epartIsReg(modrm)) {
8334 assign( arg64, getXMMRegLane64(eregOfRM(modrm), 0) );
8335 delta += 3+1;
8336 DIP("cvtdq2pd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
8337 nameXMMReg(gregOfRM(modrm)));
8338 } else {
8339 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
8340 assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
8341 delta += 3+alen;
8342 DIP("cvtdq2pd %s,%s\n", dis_buf,
8343 nameXMMReg(gregOfRM(modrm)) );
8344 }
8345
8346 putXMMRegLane64F(
8347 gregOfRM(modrm), 0,
8348 unop(Iop_I32toF64, unop(Iop_64to32, mkexpr(arg64)))
8349 );
8350
8351 putXMMRegLane64F(
8352 gregOfRM(modrm), 1,
8353 unop(Iop_I32toF64, unop(Iop_64HIto32, mkexpr(arg64)))
8354 );
8355
8356 goto decode_success;
8357 }
8358
8359 /* 0F 5B = CVTDQ2PS -- convert 4 x I32 in mem/xmm to 4 x F32 in
8360 xmm(G) */
8361 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5B) {
8362 IRTemp argV = newTemp(Ity_V128);
8363 IRTemp rmode = newTemp(Ity_I32);
8364
8365 modrm = getIByte(delta+2);
8366 if (epartIsReg(modrm)) {
8367 assign( argV, getXMMReg(eregOfRM(modrm)) );
8368 delta += 2+1;
8369 DIP("cvtdq2ps %s,%s\n", nameXMMReg(eregOfRM(modrm)),
8370 nameXMMReg(gregOfRM(modrm)));
8371 } else {
8372 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8373 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
8374 delta += 2+alen;
8375 DIP("cvtdq2ps %s,%s\n", dis_buf,
8376 nameXMMReg(gregOfRM(modrm)) );
8377 }
8378
8379 assign( rmode, get_sse_roundingmode() );
8380 breakup128to32s( argV, &t3, &t2, &t1, &t0 );
8381
8382# define CVT(_t) binop( Iop_F64toF32, \
8383 mkexpr(rmode), \
8384 unop(Iop_I32toF64,mkexpr(_t)))
8385
8386 putXMMRegLane32F( gregOfRM(modrm), 3, CVT(t3) );
8387 putXMMRegLane32F( gregOfRM(modrm), 2, CVT(t2) );
8388 putXMMRegLane32F( gregOfRM(modrm), 1, CVT(t1) );
8389 putXMMRegLane32F( gregOfRM(modrm), 0, CVT(t0) );
8390
8391# undef CVT
8392
8393 goto decode_success;
8394 }
8395
8396 /* F2 0F E6 = CVTPD2DQ -- convert 2 x F64 in mem/xmm to 2 x I32 in
8397 lo half xmm(G), and zero upper half */
8398 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0xE6) {
8399 IRTemp argV = newTemp(Ity_V128);
8400 IRTemp rmode = newTemp(Ity_I32);
8401 vassert(sz == 4);
8402
8403 modrm = getIByte(delta+3);
8404 if (epartIsReg(modrm)) {
8405 assign( argV, getXMMReg(eregOfRM(modrm)) );
8406 delta += 3+1;
8407 DIP("cvtpd2dq %s,%s\n", nameXMMReg(eregOfRM(modrm)),
8408 nameXMMReg(gregOfRM(modrm)));
8409 } else {
8410 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
8411 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
8412 delta += 3+alen;
8413 DIP("cvtpd2dq %s,%s\n", dis_buf,
8414 nameXMMReg(gregOfRM(modrm)) );
8415 }
8416
8417 assign( rmode, get_sse_roundingmode() );
8418 t0 = newTemp(Ity_F64);
8419 t1 = newTemp(Ity_F64);
8420 assign( t0, unop(Iop_ReinterpI64asF64,
sewardjf0c1c582005-02-07 23:47:38 +00008421 unop(Iop_V128to64, mkexpr(argV))) );
sewardjfd226452004-12-07 19:02:18 +00008422 assign( t1, unop(Iop_ReinterpI64asF64,
sewardjf0c1c582005-02-07 23:47:38 +00008423 unop(Iop_V128HIto64, mkexpr(argV))) );
sewardjfd226452004-12-07 19:02:18 +00008424
8425# define CVT(_t) binop( Iop_F64toI32, \
8426 mkexpr(rmode), \
8427 mkexpr(_t) )
8428
8429 putXMMRegLane32( gregOfRM(modrm), 3, mkU32(0) );
8430 putXMMRegLane32( gregOfRM(modrm), 2, mkU32(0) );
8431 putXMMRegLane32( gregOfRM(modrm), 1, CVT(t1) );
8432 putXMMRegLane32( gregOfRM(modrm), 0, CVT(t0) );
8433
8434# undef CVT
8435
8436 goto decode_success;
8437 }
8438
8439 /* 66 0F 2D = CVTPD2PI -- convert 2 x F64 in mem/xmm to 2 x
8440 I32 in mmx, according to prevailing SSE rounding mode */
8441 /* 66 0F 2C = CVTTPD2PI -- convert 2 x F64 in mem/xmm to 2 x
8442 I32 in mmx, rounding towards zero */
8443 if (sz == 2 && insn[0] == 0x0F && (insn[1] == 0x2D || insn[1] == 0x2C)) {
8444 IRTemp dst64 = newTemp(Ity_I64);
8445 IRTemp rmode = newTemp(Ity_I32);
8446 IRTemp f64lo = newTemp(Ity_F64);
8447 IRTemp f64hi = newTemp(Ity_F64);
sewardj2d49b432005-02-01 00:37:06 +00008448 Bool r2zero = toBool(insn[1] == 0x2C);
sewardjfd226452004-12-07 19:02:18 +00008449
8450 do_MMX_preamble();
8451 modrm = getIByte(delta+2);
8452
8453 if (epartIsReg(modrm)) {
8454 delta += 2+1;
8455 assign(f64lo, getXMMRegLane64F(eregOfRM(modrm), 0));
8456 assign(f64hi, getXMMRegLane64F(eregOfRM(modrm), 1));
8457 DIP("cvt%spd2pi %s,%s\n", r2zero ? "t" : "",
8458 nameXMMReg(eregOfRM(modrm)),
8459 nameMMXReg(gregOfRM(modrm)));
8460 } else {
8461 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8462 assign(f64lo, loadLE(Ity_F64, mkexpr(addr)));
8463 assign(f64hi, loadLE(Ity_F64, binop( Iop_Add32,
8464 mkexpr(addr),
8465 mkU32(8) )));
8466 delta += 2+alen;
8467 DIP("cvt%spf2pi %s,%s\n", r2zero ? "t" : "",
8468 dis_buf,
8469 nameMMXReg(gregOfRM(modrm)));
8470 }
8471
8472 if (r2zero) {
8473 assign(rmode, mkU32((UInt)Irrm_ZERO) );
8474 } else {
8475 assign( rmode, get_sse_roundingmode() );
8476 }
8477
8478 assign(
8479 dst64,
8480 binop( Iop_32HLto64,
8481 binop( Iop_F64toI32, mkexpr(rmode), mkexpr(f64hi) ),
8482 binop( Iop_F64toI32, mkexpr(rmode), mkexpr(f64lo) )
8483 )
8484 );
8485
8486 putMMXReg(gregOfRM(modrm), mkexpr(dst64));
8487 goto decode_success;
8488 }
8489
8490 /* 66 0F 5A = CVTPD2PS -- convert 2 x F64 in mem/xmm to 2 x F32 in
8491 lo half xmm(G), and zero upper half */
8492 /* Note, this is practically identical to CVTPD2DQ. It would have
8493 been nicer to merge them together, but the insn[] offsets differ
8494 by one. */
8495 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5A) {
8496 IRTemp argV = newTemp(Ity_V128);
8497 IRTemp rmode = newTemp(Ity_I32);
8498
8499 modrm = getIByte(delta+2);
8500 if (epartIsReg(modrm)) {
8501 assign( argV, getXMMReg(eregOfRM(modrm)) );
8502 delta += 2+1;
8503 DIP("cvtpd2ps %s,%s\n", nameXMMReg(eregOfRM(modrm)),
8504 nameXMMReg(gregOfRM(modrm)));
8505 } else {
8506 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8507 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
8508 delta += 2+alen;
8509 DIP("cvtpd2ps %s,%s\n", dis_buf,
8510 nameXMMReg(gregOfRM(modrm)) );
8511 }
8512
8513 assign( rmode, get_sse_roundingmode() );
8514 t0 = newTemp(Ity_F64);
8515 t1 = newTemp(Ity_F64);
8516 assign( t0, unop(Iop_ReinterpI64asF64,
sewardjf0c1c582005-02-07 23:47:38 +00008517 unop(Iop_V128to64, mkexpr(argV))) );
sewardjfd226452004-12-07 19:02:18 +00008518 assign( t1, unop(Iop_ReinterpI64asF64,
sewardjf0c1c582005-02-07 23:47:38 +00008519 unop(Iop_V128HIto64, mkexpr(argV))) );
sewardjfd226452004-12-07 19:02:18 +00008520
8521# define CVT(_t) binop( Iop_F64toF32, \
8522 mkexpr(rmode), \
8523 mkexpr(_t) )
8524
8525 putXMMRegLane32( gregOfRM(modrm), 3, mkU32(0) );
8526 putXMMRegLane32( gregOfRM(modrm), 2, mkU32(0) );
8527 putXMMRegLane32F( gregOfRM(modrm), 1, CVT(t1) );
8528 putXMMRegLane32F( gregOfRM(modrm), 0, CVT(t0) );
8529
8530# undef CVT
8531
8532 goto decode_success;
8533 }
8534
8535 /* 66 0F 2A = CVTPI2PD -- convert 2 x I32 in mem/mmx to 2 x F64 in
8536 xmm(G) */
8537 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x2A) {
8538 IRTemp arg64 = newTemp(Ity_I64);
8539
8540 modrm = getIByte(delta+2);
8541 do_MMX_preamble();
8542 if (epartIsReg(modrm)) {
8543 assign( arg64, getMMXReg(eregOfRM(modrm)) );
8544 delta += 2+1;
8545 DIP("cvtpi2pd %s,%s\n", nameMMXReg(eregOfRM(modrm)),
8546 nameXMMReg(gregOfRM(modrm)));
8547 } else {
8548 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8549 assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
8550 delta += 2+alen;
8551 DIP("cvtpi2pd %s,%s\n", dis_buf,
8552 nameXMMReg(gregOfRM(modrm)) );
8553 }
8554
8555 putXMMRegLane64F(
8556 gregOfRM(modrm), 0,
8557 unop(Iop_I32toF64, unop(Iop_64to32, mkexpr(arg64)) )
8558 );
8559
8560 putXMMRegLane64F(
8561 gregOfRM(modrm), 1,
8562 unop(Iop_I32toF64, unop(Iop_64HIto32, mkexpr(arg64)) )
8563 );
8564
8565 goto decode_success;
8566 }
8567
8568 /* 66 0F 5B = CVTPS2DQ -- convert 4 x F32 in mem/xmm to 4 x I32 in
8569 xmm(G) */
8570 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5B) {
8571 IRTemp argV = newTemp(Ity_V128);
8572 IRTemp rmode = newTemp(Ity_I32);
8573
8574 modrm = getIByte(delta+2);
8575 if (epartIsReg(modrm)) {
8576 assign( argV, getXMMReg(eregOfRM(modrm)) );
8577 delta += 2+1;
8578 DIP("cvtps2dq %s,%s\n", nameXMMReg(eregOfRM(modrm)),
8579 nameXMMReg(gregOfRM(modrm)));
8580 } else {
8581 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8582 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
8583 delta += 2+alen;
8584 DIP("cvtps2dq %s,%s\n", dis_buf,
8585 nameXMMReg(gregOfRM(modrm)) );
8586 }
8587
8588 assign( rmode, get_sse_roundingmode() );
8589 breakup128to32s( argV, &t3, &t2, &t1, &t0 );
8590
8591 /* This is less than ideal. If it turns out to be a performance
8592 bottleneck it can be improved. */
8593# define CVT(_t) \
8594 binop( Iop_F64toI32, \
8595 mkexpr(rmode), \
8596 unop( Iop_F32toF64, \
8597 unop( Iop_ReinterpI32asF32, mkexpr(_t))) )
8598
8599 putXMMRegLane32( gregOfRM(modrm), 3, CVT(t3) );
8600 putXMMRegLane32( gregOfRM(modrm), 2, CVT(t2) );
8601 putXMMRegLane32( gregOfRM(modrm), 1, CVT(t1) );
8602 putXMMRegLane32( gregOfRM(modrm), 0, CVT(t0) );
8603
8604# undef CVT
8605
8606 goto decode_success;
8607 }
8608
8609 /* 0F 5A = CVTPS2PD -- convert 2 x F32 in low half mem/xmm to 2 x
8610 F64 in xmm(G). */
8611 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5A) {
8612 IRTemp f32lo = newTemp(Ity_F32);
8613 IRTemp f32hi = newTemp(Ity_F32);
8614
8615 modrm = getIByte(delta+2);
8616 if (epartIsReg(modrm)) {
8617 assign( f32lo, getXMMRegLane32F(eregOfRM(modrm), 0) );
8618 assign( f32hi, getXMMRegLane32F(eregOfRM(modrm), 1) );
8619 delta += 2+1;
8620 DIP("cvtps2pd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
8621 nameXMMReg(gregOfRM(modrm)));
8622 } else {
8623 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8624 assign( f32lo, loadLE(Ity_F32, mkexpr(addr)) );
8625 assign( f32hi, loadLE(Ity_F32,
8626 binop(Iop_Add32,mkexpr(addr),mkU32(4))) );
8627 delta += 2+alen;
8628 DIP("cvtps2pd %s,%s\n", dis_buf,
8629 nameXMMReg(gregOfRM(modrm)) );
8630 }
8631
8632 putXMMRegLane64F( gregOfRM(modrm), 1,
8633 unop(Iop_F32toF64, mkexpr(f32hi)) );
8634 putXMMRegLane64F( gregOfRM(modrm), 0,
8635 unop(Iop_F32toF64, mkexpr(f32lo)) );
8636
8637 goto decode_success;
8638 }
8639
8640 /* F2 0F 2D = CVTSD2SI -- convert F64 in mem/low half xmm to
8641 I32 in ireg, according to prevailing SSE rounding mode */
8642 /* F2 0F 2C = CVTTSD2SI -- convert F64 in mem/low half xmm to
sewardj0b210442005-02-23 13:28:27 +00008643 I32 in ireg, rounding towards zero */
sewardjfd226452004-12-07 19:02:18 +00008644 if (insn[0] == 0xF2 && insn[1] == 0x0F
8645 && (insn[2] == 0x2D || insn[2] == 0x2C)) {
8646 IRTemp rmode = newTemp(Ity_I32);
8647 IRTemp f64lo = newTemp(Ity_F64);
sewardj2d49b432005-02-01 00:37:06 +00008648 Bool r2zero = toBool(insn[2] == 0x2C);
sewardjfd226452004-12-07 19:02:18 +00008649 vassert(sz == 4);
8650
8651 modrm = getIByte(delta+3);
8652 if (epartIsReg(modrm)) {
8653 delta += 3+1;
8654 assign(f64lo, getXMMRegLane64F(eregOfRM(modrm), 0));
8655 DIP("cvt%ssd2si %s,%s\n", r2zero ? "t" : "",
8656 nameXMMReg(eregOfRM(modrm)),
8657 nameIReg(4, gregOfRM(modrm)));
8658 } else {
8659 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
8660 assign(f64lo, loadLE(Ity_F64, mkexpr(addr)));
8661 delta += 3+alen;
8662 DIP("cvt%ssd2si %s,%s\n", r2zero ? "t" : "",
8663 dis_buf,
8664 nameIReg(4, gregOfRM(modrm)));
8665 }
8666
8667 if (r2zero) {
8668 assign( rmode, mkU32((UInt)Irrm_ZERO) );
8669 } else {
8670 assign( rmode, get_sse_roundingmode() );
8671 }
8672
8673 putIReg(4, gregOfRM(modrm),
8674 binop( Iop_F64toI32, mkexpr(rmode), mkexpr(f64lo)) );
8675
8676 goto decode_success;
8677 }
8678
8679 /* F2 0F 5A = CVTSD2SS -- convert F64 in mem/low half xmm to F32 in
8680 low 1/4 xmm(G), according to prevailing SSE rounding mode */
8681 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x5A) {
8682 IRTemp rmode = newTemp(Ity_I32);
8683 IRTemp f64lo = newTemp(Ity_F64);
8684 vassert(sz == 4);
8685
8686 modrm = getIByte(delta+3);
8687 if (epartIsReg(modrm)) {
8688 delta += 3+1;
8689 assign(f64lo, getXMMRegLane64F(eregOfRM(modrm), 0));
8690 DIP("cvtsd2ss %s,%s\n", nameXMMReg(eregOfRM(modrm)),
8691 nameXMMReg(gregOfRM(modrm)));
8692 } else {
8693 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
8694 assign(f64lo, loadLE(Ity_F64, mkexpr(addr)));
8695 delta += 3+alen;
8696 DIP("cvtsd2ss %s,%s\n", dis_buf,
8697 nameXMMReg(gregOfRM(modrm)));
8698 }
8699
8700 assign( rmode, get_sse_roundingmode() );
8701 putXMMRegLane32F(
8702 gregOfRM(modrm), 0,
8703 binop( Iop_F64toF32, mkexpr(rmode), mkexpr(f64lo) )
8704 );
8705
8706 goto decode_success;
8707 }
8708
8709 /* F2 0F 2A = CVTSI2SD -- convert I32 in mem/ireg to F64 in low
8710 half xmm */
8711 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x2A) {
8712 IRTemp arg32 = newTemp(Ity_I32);
8713 vassert(sz == 4);
8714
8715 modrm = getIByte(delta+3);
sewardjfd226452004-12-07 19:02:18 +00008716 if (epartIsReg(modrm)) {
8717 assign( arg32, getIReg(4, eregOfRM(modrm)) );
8718 delta += 3+1;
8719 DIP("cvtsi2sd %s,%s\n", nameIReg(4, eregOfRM(modrm)),
8720 nameXMMReg(gregOfRM(modrm)));
8721 } else {
8722 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
8723 assign( arg32, loadLE(Ity_I32, mkexpr(addr)) );
8724 delta += 3+alen;
8725 DIP("cvtsi2sd %s,%s\n", dis_buf,
8726 nameXMMReg(gregOfRM(modrm)) );
8727 }
8728
8729 putXMMRegLane64F(
8730 gregOfRM(modrm), 0,
8731 unop(Iop_I32toF64, mkexpr(arg32)) );
8732
8733 goto decode_success;
8734 }
8735
8736 /* F3 0F 5A = CVTSS2SD -- convert F32 in mem/low 1/4 xmm to F64 in
8737 low half xmm(G) */
8738 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5A) {
8739 IRTemp f32lo = newTemp(Ity_F32);
8740 vassert(sz == 4);
8741
8742 modrm = getIByte(delta+3);
8743 if (epartIsReg(modrm)) {
8744 delta += 3+1;
8745 assign(f32lo, getXMMRegLane32F(eregOfRM(modrm), 0));
8746 DIP("cvtss2sd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
8747 nameXMMReg(gregOfRM(modrm)));
8748 } else {
8749 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
8750 assign(f32lo, loadLE(Ity_F32, mkexpr(addr)));
8751 delta += 3+alen;
8752 DIP("cvtss2sd %s,%s\n", dis_buf,
8753 nameXMMReg(gregOfRM(modrm)));
8754 }
8755
8756 putXMMRegLane64F( gregOfRM(modrm), 0,
8757 unop( Iop_F32toF64, mkexpr(f32lo) ) );
8758
8759 goto decode_success;
8760 }
8761
8762 /* 66 0F E6 = CVTTPD2DQ -- convert 2 x F64 in mem/xmm to 2 x I32 in
8763 lo half xmm(G), and zero upper half, rounding towards zero */
8764 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE6) {
8765 IRTemp argV = newTemp(Ity_V128);
8766 IRTemp rmode = newTemp(Ity_I32);
8767
8768 modrm = getIByte(delta+2);
8769 if (epartIsReg(modrm)) {
8770 assign( argV, getXMMReg(eregOfRM(modrm)) );
8771 delta += 2+1;
8772 DIP("cvttpd2dq %s,%s\n", nameXMMReg(eregOfRM(modrm)),
8773 nameXMMReg(gregOfRM(modrm)));
8774 } else {
8775 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8776 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
8777 delta += 2+alen;
8778 DIP("cvttpd2dq %s,%s\n", dis_buf,
8779 nameXMMReg(gregOfRM(modrm)) );
8780 }
8781
8782 assign( rmode, mkU32((UInt)Irrm_ZERO) );
8783
8784 t0 = newTemp(Ity_F64);
8785 t1 = newTemp(Ity_F64);
8786 assign( t0, unop(Iop_ReinterpI64asF64,
sewardjf0c1c582005-02-07 23:47:38 +00008787 unop(Iop_V128to64, mkexpr(argV))) );
sewardjfd226452004-12-07 19:02:18 +00008788 assign( t1, unop(Iop_ReinterpI64asF64,
sewardjf0c1c582005-02-07 23:47:38 +00008789 unop(Iop_V128HIto64, mkexpr(argV))) );
sewardjfd226452004-12-07 19:02:18 +00008790
8791# define CVT(_t) binop( Iop_F64toI32, \
8792 mkexpr(rmode), \
8793 mkexpr(_t) )
8794
8795 putXMMRegLane32( gregOfRM(modrm), 3, mkU32(0) );
8796 putXMMRegLane32( gregOfRM(modrm), 2, mkU32(0) );
8797 putXMMRegLane32( gregOfRM(modrm), 1, CVT(t1) );
8798 putXMMRegLane32( gregOfRM(modrm), 0, CVT(t0) );
8799
8800# undef CVT
8801
8802 goto decode_success;
8803 }
8804
8805 /* F3 0F 5B = CVTTPS2DQ -- convert 4 x F32 in mem/xmm to 4 x I32 in
8806 xmm(G), rounding towards zero */
8807 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5B) {
8808 IRTemp argV = newTemp(Ity_V128);
8809 IRTemp rmode = newTemp(Ity_I32);
8810 vassert(sz == 4);
8811
8812 modrm = getIByte(delta+3);
8813 if (epartIsReg(modrm)) {
8814 assign( argV, getXMMReg(eregOfRM(modrm)) );
8815 delta += 3+1;
8816 DIP("cvttps2dq %s,%s\n", nameXMMReg(eregOfRM(modrm)),
8817 nameXMMReg(gregOfRM(modrm)));
8818 } else {
8819 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
8820 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
8821 delta += 3+alen;
8822 DIP("cvttps2dq %s,%s\n", dis_buf,
8823 nameXMMReg(gregOfRM(modrm)) );
8824 }
8825
8826 assign( rmode, mkU32((UInt)Irrm_ZERO) );
8827 breakup128to32s( argV, &t3, &t2, &t1, &t0 );
8828
8829 /* This is less than ideal. If it turns out to be a performance
8830 bottleneck it can be improved. */
8831# define CVT(_t) \
8832 binop( Iop_F64toI32, \
8833 mkexpr(rmode), \
8834 unop( Iop_F32toF64, \
8835 unop( Iop_ReinterpI32asF32, mkexpr(_t))) )
8836
8837 putXMMRegLane32( gregOfRM(modrm), 3, CVT(t3) );
8838 putXMMRegLane32( gregOfRM(modrm), 2, CVT(t2) );
8839 putXMMRegLane32( gregOfRM(modrm), 1, CVT(t1) );
8840 putXMMRegLane32( gregOfRM(modrm), 0, CVT(t0) );
8841
8842# undef CVT
8843
8844 goto decode_success;
8845 }
8846
8847 /* 66 0F 5E = DIVPD -- div 64Fx2 from R/M to R */
8848 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5E) {
8849 delta = dis_SSE_E_to_G_all( sorb, delta+2, "divpd", Iop_Div64Fx2 );
8850 goto decode_success;
8851 }
8852
sewardjc2feffc2004-12-08 12:31:22 +00008853 /* F2 0F 5E = DIVSD -- div 64F0x2 from R/M to R */
8854 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x5E) {
8855 vassert(sz == 4);
8856 delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "divsd", Iop_Div64F0x2 );
8857 goto decode_success;
8858 }
8859
8860 /* 0F AE /5 = LFENCE -- flush pending operations to memory */
8861 /* 0F AE /6 = MFENCE -- flush pending operations to memory */
8862 if (insn[0] == 0x0F && insn[1] == 0xAE
8863 && epartIsReg(insn[2])
8864 && (gregOfRM(insn[2]) == 5 || gregOfRM(insn[2]) == 6)) {
8865 vassert(sz == 4);
8866 delta += 3;
sewardj3e838932005-01-07 12:09:15 +00008867 /* Insert a memory fence. It's sometimes important that these
8868 are carried through to the generated code. */
8869 stmt( IRStmt_MFence() );
sewardjc2feffc2004-12-08 12:31:22 +00008870 DIP("%sfence\n", gregOfRM(insn[2])==5 ? "l" : "m");
8871 goto decode_success;
8872 }
8873
8874 /* 66 0F 5F = MAXPD -- max 64Fx2 from R/M to R */
8875 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5F) {
8876 delta = dis_SSE_E_to_G_all( sorb, delta+2, "maxpd", Iop_Max64Fx2 );
8877 goto decode_success;
8878 }
8879
8880 /* F2 0F 5F = MAXSD -- max 64F0x2 from R/M to R */
8881 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x5F) {
8882 vassert(sz == 4);
8883 delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "maxsd", Iop_Max64F0x2 );
8884 goto decode_success;
8885 }
8886
8887 /* 66 0F 5D = MINPD -- min 64Fx2 from R/M to R */
8888 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5D) {
8889 delta = dis_SSE_E_to_G_all( sorb, delta+2, "minpd", Iop_Min64Fx2 );
8890 goto decode_success;
8891 }
8892
8893 /* F2 0F 5D = MINSD -- min 64F0x2 from R/M to R */
8894 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x5D) {
8895 vassert(sz == 4);
8896 delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "minsd", Iop_Min64F0x2 );
8897 goto decode_success;
8898 }
8899
8900 /* 66 0F 28 = MOVAPD -- move from E (mem or xmm) to G (xmm). */
8901 /* 66 0F 10 = MOVUPD -- move from E (mem or xmm) to G (xmm). */
8902 /* 66 0F 6F = MOVDQA -- move from E (mem or xmm) to G (xmm). */
8903 if (sz == 2 && insn[0] == 0x0F
8904 && (insn[1] == 0x28 || insn[1] == 0x10 || insn[1] == 0x6F)) {
8905 HChar* wot = insn[1]==0x28 ? "apd" :
8906 insn[1]==0x10 ? "upd" : "dqa";
8907 modrm = getIByte(delta+2);
8908 if (epartIsReg(modrm)) {
8909 putXMMReg( gregOfRM(modrm),
8910 getXMMReg( eregOfRM(modrm) ));
8911 DIP("mov%s %s,%s\n", wot, nameXMMReg(eregOfRM(modrm)),
8912 nameXMMReg(gregOfRM(modrm)));
8913 delta += 2+1;
8914 } else {
8915 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8916 putXMMReg( gregOfRM(modrm),
8917 loadLE(Ity_V128, mkexpr(addr)) );
8918 DIP("mov%s %s,%s\n", wot, dis_buf,
8919 nameXMMReg(gregOfRM(modrm)));
8920 delta += 2+alen;
8921 }
8922 goto decode_success;
8923 }
8924
sewardj95535fe2004-12-15 17:42:58 +00008925 /* 66 0F 29 = MOVAPD -- move from G (xmm) to E (mem or xmm). */
sewardj1c318772005-03-19 14:27:04 +00008926 /* 66 0F 11 = MOVUPD -- move from G (xmm) to E (mem or xmm). */
8927 if (sz == 2 && insn[0] == 0x0F
8928 && (insn[1] == 0x29 || insn[1] == 0x11)) {
8929 HChar* wot = insn[1]==0x29 ? "apd" : "upd";
sewardj95535fe2004-12-15 17:42:58 +00008930 modrm = getIByte(delta+2);
8931 if (epartIsReg(modrm)) {
8932 /* fall through; awaiting test case */
8933 } else {
8934 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8935 storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) );
sewardj1c318772005-03-19 14:27:04 +00008936 DIP("mov%s %s,%s\n", wot, nameXMMReg(gregOfRM(modrm)),
8937 dis_buf );
sewardj95535fe2004-12-15 17:42:58 +00008938 delta += 2+alen;
8939 goto decode_success;
8940 }
8941 }
8942
sewardjc2feffc2004-12-08 12:31:22 +00008943 /* 66 0F 6E = MOVD from r/m32 to xmm, zeroing high 3/4 of xmm. */
8944 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x6E) {
8945 modrm = getIByte(delta+2);
8946 if (epartIsReg(modrm)) {
8947 delta += 2+1;
8948 putXMMReg(
8949 gregOfRM(modrm),
sewardjf0c1c582005-02-07 23:47:38 +00008950 unop( Iop_32UtoV128, getIReg(4, eregOfRM(modrm)) )
sewardjc2feffc2004-12-08 12:31:22 +00008951 );
8952 DIP("movd %s, %s\n",
8953 nameIReg(4,eregOfRM(modrm)), nameXMMReg(gregOfRM(modrm)));
8954 } else {
8955 addr = disAMode( &alen, sorb, delta+2, dis_buf );
8956 delta += 2+alen;
8957 putXMMReg(
8958 gregOfRM(modrm),
sewardjf0c1c582005-02-07 23:47:38 +00008959 unop( Iop_32UtoV128,loadLE(Ity_I32, mkexpr(addr)) )
sewardjc2feffc2004-12-08 12:31:22 +00008960 );
8961 DIP("movd %s, %s\n", dis_buf, nameXMMReg(gregOfRM(modrm)));
8962 }
8963 goto decode_success;
8964 }
8965
8966 /* 66 0F 7E = MOVD from xmm low 1/4 to r/m32. */
8967 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x7E) {
8968 modrm = getIByte(delta+2);
8969 if (epartIsReg(modrm)) {
8970 delta += 2+1;
8971 putIReg( 4, eregOfRM(modrm),
8972 getXMMRegLane32(gregOfRM(modrm), 0) );
8973 DIP("movd %s, %s\n",
8974 nameXMMReg(gregOfRM(modrm)), nameIReg(4,eregOfRM(modrm)));
8975 } else {
8976 addr = disAMode( &alen, sorb, delta+2, dis_buf );
8977 delta += 2+alen;
8978 storeLE( mkexpr(addr),
8979 getXMMRegLane32(gregOfRM(modrm), 0) );
8980 DIP("movd %s, %s\n", nameXMMReg(gregOfRM(modrm)), dis_buf);
8981 }
8982 goto decode_success;
8983 }
8984
8985 /* 66 0F 7F = MOVDQA -- move from G (xmm) to E (mem or xmm). */
8986 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x7F) {
8987 modrm = getIByte(delta+2);
8988 if (epartIsReg(modrm)) {
8989 delta += 2+1;
8990 putXMMReg( eregOfRM(modrm),
8991 getXMMReg(gregOfRM(modrm)) );
8992 DIP("movdqa %s, %s\n", nameXMMReg(gregOfRM(modrm)),
8993 nameXMMReg(eregOfRM(modrm)));
8994 } else {
8995 addr = disAMode( &alen, sorb, delta+2, dis_buf );
8996 delta += 2+alen;
8997 storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) );
8998 DIP("movdqa %s, %s\n", nameXMMReg(gregOfRM(modrm)), dis_buf);
8999 }
9000 goto decode_success;
9001 }
9002
9003 /* F3 0F 6F = MOVDQU -- move from E (mem or xmm) to G (xmm). */
9004 /* Unfortunately can't simply use the MOVDQA case since the
9005 prefix lengths are different (66 vs F3) */
9006 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x6F) {
9007 vassert(sz == 4);
9008 modrm = getIByte(delta+3);
9009 if (epartIsReg(modrm)) {
9010 putXMMReg( gregOfRM(modrm),
9011 getXMMReg( eregOfRM(modrm) ));
9012 DIP("movdqu %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9013 nameXMMReg(gregOfRM(modrm)));
9014 delta += 3+1;
9015 } else {
9016 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
9017 putXMMReg( gregOfRM(modrm),
9018 loadLE(Ity_V128, mkexpr(addr)) );
9019 DIP("movdqu %s,%s\n", dis_buf,
9020 nameXMMReg(gregOfRM(modrm)));
9021 delta += 3+alen;
9022 }
9023 goto decode_success;
9024 }
9025
9026 /* F3 0F 7F = MOVDQU -- move from G (xmm) to E (mem or xmm). */
9027 /* Unfortunately can't simply use the MOVDQA case since the
9028 prefix lengths are different (66 vs F3) */
9029 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x7F) {
9030 vassert(sz == 4);
9031 modrm = getIByte(delta+3);
9032 if (epartIsReg(modrm)) {
9033 delta += 3+1;
9034 putXMMReg( eregOfRM(modrm),
9035 getXMMReg(gregOfRM(modrm)) );
9036 DIP("movdqu %s, %s\n", nameXMMReg(gregOfRM(modrm)),
9037 nameXMMReg(eregOfRM(modrm)));
9038 } else {
9039 addr = disAMode( &alen, sorb, delta+3, dis_buf );
9040 delta += 3+alen;
9041 storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) );
9042 DIP("movdqu %s, %s\n", nameXMMReg(gregOfRM(modrm)), dis_buf);
9043 }
9044 goto decode_success;
9045 }
9046
9047 /* F2 0F D6 = MOVDQ2Q -- move from E (lo half xmm, not mem) to G (mmx). */
9048 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0xD6) {
9049 vassert(sz == 4);
9050 modrm = getIByte(delta+3);
9051 if (epartIsReg(modrm)) {
9052 do_MMX_preamble();
9053 putMMXReg( gregOfRM(modrm),
9054 getXMMRegLane64( eregOfRM(modrm), 0 ));
9055 DIP("movdq2q %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9056 nameMMXReg(gregOfRM(modrm)));
9057 delta += 3+1;
9058 goto decode_success;
9059 } else {
9060 /* fall through, apparently no mem case for this insn */
9061 }
9062 }
9063
9064 /* 66 0F 16 = MOVHPD -- move from mem to high half of XMM. */
9065 /* These seems identical to MOVHPS. This instruction encoding is
9066 completely crazy. */
9067 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x16) {
9068 modrm = getIByte(delta+2);
9069 if (epartIsReg(modrm)) {
9070 /* fall through; apparently reg-reg is not possible */
9071 } else {
9072 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9073 delta += 2+alen;
9074 putXMMRegLane64( gregOfRM(modrm), 1/*upper lane*/,
9075 loadLE(Ity_I64, mkexpr(addr)) );
9076 DIP("movhpd %s,%s\n", dis_buf,
9077 nameXMMReg( gregOfRM(modrm) ));
9078 goto decode_success;
9079 }
9080 }
9081
9082 /* 66 0F 17 = MOVHPD -- move from high half of XMM to mem. */
9083 /* Again, this seems identical to MOVHPS. */
9084 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x17) {
9085 if (!epartIsReg(insn[2])) {
9086 delta += 2;
9087 addr = disAMode ( &alen, sorb, delta, dis_buf );
9088 delta += alen;
9089 storeLE( mkexpr(addr),
9090 getXMMRegLane64( gregOfRM(insn[2]),
9091 1/*upper lane*/ ) );
9092 DIP("movhpd %s,%s\n", nameXMMReg( gregOfRM(insn[2]) ),
9093 dis_buf);
9094 goto decode_success;
9095 }
9096 /* else fall through */
9097 }
9098
9099 /* 66 0F 12 = MOVLPD -- move from mem to low half of XMM. */
9100 /* Identical to MOVLPS ? */
9101 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x12) {
9102 modrm = getIByte(delta+2);
9103 if (epartIsReg(modrm)) {
9104 /* fall through; apparently reg-reg is not possible */
9105 } else {
9106 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9107 delta += 2+alen;
9108 putXMMRegLane64( gregOfRM(modrm), 0/*lower lane*/,
9109 loadLE(Ity_I64, mkexpr(addr)) );
9110 DIP("movlpd %s, %s\n",
9111 dis_buf, nameXMMReg( gregOfRM(modrm) ));
9112 goto decode_success;
9113 }
9114 }
9115
9116 /* 66 0F 13 = MOVLPD -- move from low half of XMM to mem. */
9117 /* Identical to MOVLPS ? */
9118 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x13) {
9119 if (!epartIsReg(insn[2])) {
9120 delta += 2;
9121 addr = disAMode ( &alen, sorb, delta, dis_buf );
9122 delta += alen;
9123 storeLE( mkexpr(addr),
9124 getXMMRegLane64( gregOfRM(insn[2]),
9125 0/*lower lane*/ ) );
9126 DIP("movlpd %s, %s\n", nameXMMReg( gregOfRM(insn[2]) ),
9127 dis_buf);
9128 goto decode_success;
9129 }
9130 /* else fall through */
9131 }
9132
9133 /* 66 0F 50 = MOVMSKPD - move 2 sign bits from 2 x F64 in xmm(E) to
9134 2 lowest bits of ireg(G) */
9135 if (insn[0] == 0x0F && insn[1] == 0x50) {
9136 modrm = getIByte(delta+2);
9137 if (sz == 2 && epartIsReg(modrm)) {
9138 Int src;
9139 t0 = newTemp(Ity_I32);
9140 t1 = newTemp(Ity_I32);
9141 delta += 2+1;
9142 src = eregOfRM(modrm);
9143 assign( t0, binop( Iop_And32,
9144 binop(Iop_Shr32, getXMMRegLane32(src,1), mkU8(31)),
9145 mkU32(1) ));
9146 assign( t1, binop( Iop_And32,
9147 binop(Iop_Shr32, getXMMRegLane32(src,3), mkU8(30)),
9148 mkU32(2) ));
9149 putIReg(4, gregOfRM(modrm),
9150 binop(Iop_Or32, mkexpr(t0), mkexpr(t1))
9151 );
9152 DIP("movmskpd %s,%s\n", nameXMMReg(src),
9153 nameIReg(4, gregOfRM(modrm)));
9154 goto decode_success;
9155 }
9156 /* else fall through */
9157 }
9158
9159 /* 66 0F E7 = MOVNTDQ -- for us, just a plain SSE store. */
9160 if (insn[0] == 0x0F && insn[1] == 0xE7) {
9161 modrm = getIByte(delta+2);
9162 if (sz == 2 && !epartIsReg(modrm)) {
9163 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9164 storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) );
9165 DIP("movntdq %s,%s\n", dis_buf,
9166 nameXMMReg(gregOfRM(modrm)));
9167 delta += 2+alen;
9168 goto decode_success;
9169 }
9170 /* else fall through */
9171 }
9172
9173 /* 0F C3 = MOVNTI -- for us, just a plain ireg store. */
9174 if (insn[0] == 0x0F && insn[1] == 0xC3) {
9175 vassert(sz == 4);
9176 modrm = getIByte(delta+2);
9177 if (!epartIsReg(modrm)) {
9178 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9179 storeLE( mkexpr(addr), getIReg(4, gregOfRM(modrm)) );
9180 DIP("movnti %s,%s\n", dis_buf,
9181 nameIReg(4, gregOfRM(modrm)));
9182 delta += 2+alen;
9183 goto decode_success;
9184 }
9185 /* else fall through */
9186 }
9187
sewardj95535fe2004-12-15 17:42:58 +00009188 /* 66 0F D6 = MOVQ -- move 64 bits from G (lo half xmm) to E (mem
9189 or lo half xmm). */
sewardj9ee82862004-12-14 01:16:59 +00009190 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD6) {
9191 modrm = getIByte(delta+2);
9192 if (epartIsReg(modrm)) {
9193 /* fall through, awaiting test case */
sewardj6d7ccd52005-05-14 02:04:12 +00009194 /* dst: lo half copied, hi half zeroed */
sewardj9ee82862004-12-14 01:16:59 +00009195 } else {
9196 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9197 storeLE( mkexpr(addr),
9198 getXMMRegLane64( gregOfRM(modrm), 0 ));
9199 DIP("movq %s,%s\n", nameXMMReg(gregOfRM(modrm)), dis_buf );
9200 delta += 2+alen;
9201 goto decode_success;
9202 }
9203 }
9204
sewardjc2feffc2004-12-08 12:31:22 +00009205 /* F3 0F D6 = MOVQ2DQ -- move from E (mmx) to G (lo half xmm, zero
9206 hi half). */
9207 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0xD6) {
9208 vassert(sz == 4);
9209 modrm = getIByte(delta+3);
9210 if (epartIsReg(modrm)) {
9211 do_MMX_preamble();
9212 putXMMReg( gregOfRM(modrm),
sewardjf0c1c582005-02-07 23:47:38 +00009213 unop(Iop_64UtoV128, getMMXReg( eregOfRM(modrm) )) );
sewardjc2feffc2004-12-08 12:31:22 +00009214 DIP("movq2dq %s,%s\n", nameMMXReg(eregOfRM(modrm)),
9215 nameXMMReg(gregOfRM(modrm)));
9216 delta += 3+1;
9217 goto decode_success;
9218 } else {
9219 /* fall through, apparently no mem case for this insn */
9220 }
9221 }
9222
sewardj95535fe2004-12-15 17:42:58 +00009223 /* F3 0F 7E = MOVQ -- move 64 bits from E (mem or lo half xmm) to
sewardj6d7ccd52005-05-14 02:04:12 +00009224 G (lo half xmm). Upper half of G is zeroed out. */
sewardj95535fe2004-12-15 17:42:58 +00009225 /* F2 0F 10 = MOVSD -- move 64 bits from E (mem or lo half xmm) to
9226 G (lo half xmm). If E is mem, upper half of G is zeroed out.
sewardj6d7ccd52005-05-14 02:04:12 +00009227 If E is reg, upper half of G is unchanged. */
sewardj95535fe2004-12-15 17:42:58 +00009228 if ((insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x10)
9229 || (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x7E)) {
sewardjc2feffc2004-12-08 12:31:22 +00009230 vassert(sz == 4);
9231 modrm = getIByte(delta+3);
9232 if (epartIsReg(modrm)) {
9233 putXMMRegLane64( gregOfRM(modrm), 0,
9234 getXMMRegLane64( eregOfRM(modrm), 0 ));
sewardj6d7ccd52005-05-14 02:04:12 +00009235 if (insn[0] == 0xF3/*MOVQ*/) {
9236 /* zero bits 127:64 */
9237 putXMMRegLane64( gregOfRM(modrm), 1, mkU64(0) );
9238 }
sewardjc2feffc2004-12-08 12:31:22 +00009239 DIP("movsd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9240 nameXMMReg(gregOfRM(modrm)));
9241 delta += 3+1;
9242 } else {
9243 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
sewardjad50db02005-04-06 01:45:44 +00009244 /* zero bits 127:64 */
sewardj5bf1fd42005-04-06 01:11:08 +00009245 putXMMRegLane64( gregOfRM(modrm), 1, mkU64(0) );
sewardjad50db02005-04-06 01:45:44 +00009246 /* write bits 63:0 */
sewardjc2feffc2004-12-08 12:31:22 +00009247 putXMMRegLane64( gregOfRM(modrm), 0,
9248 loadLE(Ity_I64, mkexpr(addr)) );
9249 DIP("movsd %s,%s\n", dis_buf,
9250 nameXMMReg(gregOfRM(modrm)));
9251 delta += 3+alen;
9252 }
9253 goto decode_success;
9254 }
9255
9256 /* F2 0F 11 = MOVSD -- move 64 bits from G (lo half xmm) to E (mem
9257 or lo half xmm). */
9258 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x11) {
9259 vassert(sz == 4);
9260 modrm = getIByte(delta+3);
9261 if (epartIsReg(modrm)) {
9262 /* fall through, we don't yet have a test case */
9263 } else {
9264 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
9265 storeLE( mkexpr(addr),
sewardj519d66f2004-12-15 11:57:58 +00009266 getXMMRegLane64(gregOfRM(modrm), 0) );
9267 DIP("movsd %s,%s\n", nameXMMReg(gregOfRM(modrm)),
sewardjc2feffc2004-12-08 12:31:22 +00009268 dis_buf);
9269 delta += 3+alen;
9270 goto decode_success;
9271 }
9272 }
sewardjfd226452004-12-07 19:02:18 +00009273
sewardj008754b2004-12-08 14:37:10 +00009274 /* 66 0F 59 = MULPD -- mul 64Fx2 from R/M to R */
9275 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x59) {
9276 delta = dis_SSE_E_to_G_all( sorb, delta+2, "mulpd", Iop_Mul64Fx2 );
9277 goto decode_success;
9278 }
9279
9280 /* F2 0F 59 = MULSD -- mul 64F0x2 from R/M to R */
9281 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x59) {
9282 vassert(sz == 4);
9283 delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "mulsd", Iop_Mul64F0x2 );
9284 goto decode_success;
9285 }
9286
9287 /* 66 0F 56 = ORPD -- G = G and E */
9288 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x56) {
sewardjf0c1c582005-02-07 23:47:38 +00009289 delta = dis_SSE_E_to_G_all( sorb, delta+2, "orpd", Iop_OrV128 );
sewardj008754b2004-12-08 14:37:10 +00009290 goto decode_success;
9291 }
9292
9293 /* 66 0F C6 /r ib = SHUFPD -- shuffle packed F64s */
9294 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xC6) {
9295 Int select;
9296 IRTemp sV = newTemp(Ity_V128);
9297 IRTemp dV = newTemp(Ity_V128);
9298 IRTemp s1 = newTemp(Ity_I64);
9299 IRTemp s0 = newTemp(Ity_I64);
9300 IRTemp d1 = newTemp(Ity_I64);
9301 IRTemp d0 = newTemp(Ity_I64);
9302
9303 modrm = insn[2];
9304 assign( dV, getXMMReg(gregOfRM(modrm)) );
9305
9306 if (epartIsReg(modrm)) {
9307 assign( sV, getXMMReg(eregOfRM(modrm)) );
9308 select = (Int)insn[3];
9309 delta += 2+2;
9310 DIP("shufpd $%d,%s,%s\n", select,
9311 nameXMMReg(eregOfRM(modrm)),
9312 nameXMMReg(gregOfRM(modrm)));
9313 } else {
9314 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9315 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
9316 select = (Int)insn[2+alen];
9317 delta += 3+alen;
9318 DIP("shufpd $%d,%s,%s\n", select,
9319 dis_buf,
9320 nameXMMReg(gregOfRM(modrm)));
9321 }
9322
sewardjf0c1c582005-02-07 23:47:38 +00009323 assign( d1, unop(Iop_V128HIto64, mkexpr(dV)) );
9324 assign( d0, unop(Iop_V128to64, mkexpr(dV)) );
9325 assign( s1, unop(Iop_V128HIto64, mkexpr(sV)) );
9326 assign( s0, unop(Iop_V128to64, mkexpr(sV)) );
sewardj008754b2004-12-08 14:37:10 +00009327
9328# define SELD(n) mkexpr((n)==0 ? d0 : d1)
9329# define SELS(n) mkexpr((n)==0 ? s0 : s1)
9330
9331 putXMMReg(
9332 gregOfRM(modrm),
sewardjf0c1c582005-02-07 23:47:38 +00009333 binop(Iop_64HLtoV128, SELS((select>>1)&1), SELD((select>>0)&1) )
sewardj008754b2004-12-08 14:37:10 +00009334 );
9335
9336# undef SELD
9337# undef SELS
9338
9339 goto decode_success;
9340 }
9341
9342 /* 66 0F 51 = SQRTPD -- approx sqrt 64Fx2 from R/M to R */
9343 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x51) {
9344 delta = dis_SSE_E_to_G_unary_all( sorb, delta+2,
9345 "sqrtpd", Iop_Sqrt64Fx2 );
9346 goto decode_success;
9347 }
9348
9349 /* F2 0F 51 = SQRTSD -- approx sqrt 64F0x2 from R/M to R */
9350 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x51) {
9351 vassert(sz == 4);
9352 delta = dis_SSE_E_to_G_unary_lo64( sorb, delta+3,
9353 "sqrtsd", Iop_Sqrt64F0x2 );
9354 goto decode_success;
9355 }
9356
9357 /* 66 0F 5C = SUBPD -- sub 64Fx2 from R/M to R */
9358 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5C) {
9359 delta = dis_SSE_E_to_G_all( sorb, delta+2, "subpd", Iop_Sub64Fx2 );
9360 goto decode_success;
9361 }
9362
9363 /* F2 0F 5C = SUBSD -- sub 64F0x2 from R/M to R */
9364 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x5C) {
9365 vassert(sz == 4);
9366 delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "subsd", Iop_Sub64F0x2 );
9367 goto decode_success;
9368 }
9369
9370 /* 66 0F 15 = UNPCKHPD -- unpack and interleave high part F64s */
9371 /* 66 0F 14 = UNPCKLPD -- unpack and interleave low part F64s */
9372 /* These just appear to be special cases of SHUFPS */
9373 if (sz == 2 && insn[0] == 0x0F && (insn[1] == 0x15 || insn[1] == 0x14)) {
9374 IRTemp s1 = newTemp(Ity_I64);
9375 IRTemp s0 = newTemp(Ity_I64);
9376 IRTemp d1 = newTemp(Ity_I64);
9377 IRTemp d0 = newTemp(Ity_I64);
9378 IRTemp sV = newTemp(Ity_V128);
9379 IRTemp dV = newTemp(Ity_V128);
sewardj2d49b432005-02-01 00:37:06 +00009380 Bool hi = toBool(insn[1] == 0x15);
sewardj008754b2004-12-08 14:37:10 +00009381
9382 modrm = insn[2];
9383 assign( dV, getXMMReg(gregOfRM(modrm)) );
9384
9385 if (epartIsReg(modrm)) {
9386 assign( sV, getXMMReg(eregOfRM(modrm)) );
9387 delta += 2+1;
9388 DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
9389 nameXMMReg(eregOfRM(modrm)),
9390 nameXMMReg(gregOfRM(modrm)));
9391 } else {
9392 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9393 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
9394 delta += 2+alen;
9395 DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
9396 dis_buf,
9397 nameXMMReg(gregOfRM(modrm)));
9398 }
9399
sewardjf0c1c582005-02-07 23:47:38 +00009400 assign( d1, unop(Iop_V128HIto64, mkexpr(dV)) );
9401 assign( d0, unop(Iop_V128to64, mkexpr(dV)) );
9402 assign( s1, unop(Iop_V128HIto64, mkexpr(sV)) );
9403 assign( s0, unop(Iop_V128to64, mkexpr(sV)) );
sewardj008754b2004-12-08 14:37:10 +00009404
9405 if (hi) {
9406 putXMMReg( gregOfRM(modrm),
sewardjf0c1c582005-02-07 23:47:38 +00009407 binop(Iop_64HLtoV128, mkexpr(s1), mkexpr(d1)) );
sewardj008754b2004-12-08 14:37:10 +00009408 } else {
9409 putXMMReg( gregOfRM(modrm),
sewardjf0c1c582005-02-07 23:47:38 +00009410 binop(Iop_64HLtoV128, mkexpr(s0), mkexpr(d0)) );
sewardj008754b2004-12-08 14:37:10 +00009411 }
9412
9413 goto decode_success;
9414 }
9415
9416 /* 66 0F 57 = XORPD -- G = G and E */
9417 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x57) {
sewardjf0c1c582005-02-07 23:47:38 +00009418 delta = dis_SSE_E_to_G_all( sorb, delta+2, "xorpd", Iop_XorV128 );
sewardj008754b2004-12-08 14:37:10 +00009419 goto decode_success;
9420 }
sewardj636ad762004-12-07 11:16:04 +00009421
sewardj164f9272004-12-09 00:39:32 +00009422 /* 66 0F 6B = PACKSSDW */
9423 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x6B) {
9424 delta = dis_SSEint_E_to_G( sorb, delta+2,
9425 "packssdw", Iop_QNarrow32Sx4, True );
9426 goto decode_success;
9427 }
9428
9429 /* 66 0F 63 = PACKSSWB */
9430 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x63) {
9431 delta = dis_SSEint_E_to_G( sorb, delta+2,
9432 "packsswb", Iop_QNarrow16Sx8, True );
9433 goto decode_success;
9434 }
9435
9436 /* 66 0F 67 = PACKUSWB */
9437 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x67) {
9438 delta = dis_SSEint_E_to_G( sorb, delta+2,
9439 "packuswb", Iop_QNarrow16Ux8, True );
9440 goto decode_success;
9441 }
9442
9443 /* 66 0F FC = PADDB */
9444 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xFC) {
9445 delta = dis_SSEint_E_to_G( sorb, delta+2,
9446 "paddb", Iop_Add8x16, False );
9447 goto decode_success;
9448 }
9449
9450 /* 66 0F FE = PADDD */
9451 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xFE) {
9452 delta = dis_SSEint_E_to_G( sorb, delta+2,
9453 "paddd", Iop_Add32x4, False );
9454 goto decode_success;
9455 }
9456
9457 /* ***--- this is an MMX class insn introduced in SSE2 ---*** */
9458 /* 0F D4 = PADDQ -- add 64x1 */
9459 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xD4) {
9460 do_MMX_preamble();
9461 delta = dis_MMXop_regmem_to_reg (
9462 sorb, delta+2, insn[1], "paddq", False );
9463 goto decode_success;
9464 }
9465
9466 /* 66 0F D4 = PADDQ */
9467 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD4) {
9468 delta = dis_SSEint_E_to_G( sorb, delta+2,
9469 "paddq", Iop_Add64x2, False );
9470 goto decode_success;
9471 }
9472
9473 /* 66 0F FD = PADDW */
9474 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xFD) {
9475 delta = dis_SSEint_E_to_G( sorb, delta+2,
9476 "paddw", Iop_Add16x8, False );
9477 goto decode_success;
9478 }
9479
9480 /* 66 0F EC = PADDSB */
9481 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xEC) {
9482 delta = dis_SSEint_E_to_G( sorb, delta+2,
9483 "paddsb", Iop_QAdd8Sx16, False );
9484 goto decode_success;
9485 }
9486
9487 /* 66 0F ED = PADDSW */
9488 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xED) {
9489 delta = dis_SSEint_E_to_G( sorb, delta+2,
9490 "paddsw", Iop_QAdd16Sx8, False );
9491 goto decode_success;
9492 }
9493
9494 /* 66 0F DC = PADDUSB */
9495 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDC) {
9496 delta = dis_SSEint_E_to_G( sorb, delta+2,
9497 "paddusb", Iop_QAdd8Ux16, False );
9498 goto decode_success;
9499 }
9500
9501 /* 66 0F DD = PADDUSW */
9502 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDD) {
9503 delta = dis_SSEint_E_to_G( sorb, delta+2,
9504 "paddusw", Iop_QAdd16Ux8, False );
9505 goto decode_success;
9506 }
9507
9508 /* 66 0F DB = PAND */
9509 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDB) {
sewardjf0c1c582005-02-07 23:47:38 +00009510 delta = dis_SSE_E_to_G_all( sorb, delta+2, "pand", Iop_AndV128 );
sewardj164f9272004-12-09 00:39:32 +00009511 goto decode_success;
9512 }
9513
9514 /* 66 0F DF = PANDN */
9515 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDF) {
sewardjf0c1c582005-02-07 23:47:38 +00009516 delta = dis_SSE_E_to_G_all_invG( sorb, delta+2, "pandn", Iop_AndV128 );
sewardj164f9272004-12-09 00:39:32 +00009517 goto decode_success;
9518 }
9519
9520 /* 66 0F E0 = PAVGB */
9521 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE0) {
9522 delta = dis_SSEint_E_to_G( sorb, delta+2,
9523 "pavgb", Iop_Avg8Ux16, False );
9524 goto decode_success;
9525 }
9526
9527 /* 66 0F E3 = PAVGW */
9528 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE3) {
9529 delta = dis_SSEint_E_to_G( sorb, delta+2,
9530 "pavgw", Iop_Avg16Ux8, False );
9531 goto decode_success;
9532 }
9533
sewardje5854d62004-12-09 03:44:34 +00009534 /* 66 0F 74 = PCMPEQB */
9535 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x74) {
9536 delta = dis_SSEint_E_to_G( sorb, delta+2,
9537 "pcmpeqb", Iop_CmpEQ8x16, False );
9538 goto decode_success;
9539 }
9540
9541 /* 66 0F 76 = PCMPEQD */
9542 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x76) {
9543 delta = dis_SSEint_E_to_G( sorb, delta+2,
9544 "pcmpeqd", Iop_CmpEQ32x4, False );
9545 goto decode_success;
9546 }
9547
9548 /* 66 0F 75 = PCMPEQW */
9549 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x75) {
9550 delta = dis_SSEint_E_to_G( sorb, delta+2,
9551 "pcmpeqw", Iop_CmpEQ16x8, False );
9552 goto decode_success;
9553 }
9554
9555 /* 66 0F 64 = PCMPGTB */
9556 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x64) {
9557 delta = dis_SSEint_E_to_G( sorb, delta+2,
9558 "pcmpgtb", Iop_CmpGT8Sx16, False );
9559 goto decode_success;
9560 }
9561
9562 /* 66 0F 66 = PCMPGTD */
9563 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x66) {
9564 delta = dis_SSEint_E_to_G( sorb, delta+2,
9565 "pcmpgtd", Iop_CmpGT32Sx4, False );
9566 goto decode_success;
9567 }
9568
9569 /* 66 0F 65 = PCMPGTW */
9570 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x65) {
9571 delta = dis_SSEint_E_to_G( sorb, delta+2,
9572 "pcmpgtw", Iop_CmpGT16Sx8, False );
9573 goto decode_success;
9574 }
9575
9576 /* 66 0F C5 = PEXTRW -- extract 16-bit field from xmm(E) and put
9577 zero-extend of it in ireg(G). */
9578 if (insn[0] == 0x0F && insn[1] == 0xC5) {
9579 modrm = insn[2];
9580 if (sz == 2 && epartIsReg(modrm)) {
9581 t5 = newTemp(Ity_V128);
9582 t4 = newTemp(Ity_I16);
9583 assign(t5, getXMMReg(eregOfRM(modrm)));
9584 breakup128to32s( t5, &t3, &t2, &t1, &t0 );
9585 switch (insn[3] & 7) {
9586 case 0: assign(t4, unop(Iop_32to16, mkexpr(t0))); break;
9587 case 1: assign(t4, unop(Iop_32HIto16, mkexpr(t0))); break;
9588 case 2: assign(t4, unop(Iop_32to16, mkexpr(t1))); break;
9589 case 3: assign(t4, unop(Iop_32HIto16, mkexpr(t1))); break;
9590 case 4: assign(t4, unop(Iop_32to16, mkexpr(t2))); break;
9591 case 5: assign(t4, unop(Iop_32HIto16, mkexpr(t2))); break;
9592 case 6: assign(t4, unop(Iop_32to16, mkexpr(t3))); break;
9593 case 7: assign(t4, unop(Iop_32HIto16, mkexpr(t3))); break;
sewardjba89f4c2005-04-07 17:31:27 +00009594 default: vassert(0); /*NOTREACHED*/
sewardje5854d62004-12-09 03:44:34 +00009595 }
9596 putIReg(4, gregOfRM(modrm), unop(Iop_16Uto32, mkexpr(t4)));
9597 DIP("pextrw $%d,%s,%s\n",
9598 (Int)insn[3], nameXMMReg(eregOfRM(modrm)),
9599 nameIReg(4,gregOfRM(modrm)));
9600 delta += 4;
9601 goto decode_success;
9602 }
9603 /* else fall through */
9604 }
9605
9606 /* 66 0F C4 = PINSRW -- get 16 bits from E(mem or low half ireg) and
9607 put it into the specified lane of xmm(G). */
9608 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xC4) {
9609 Int lane;
9610 t4 = newTemp(Ity_I16);
9611 modrm = insn[2];
9612
9613 if (epartIsReg(modrm)) {
9614 assign(t4, getIReg(2, eregOfRM(modrm)));
sewardjaac7e082005-03-17 14:03:46 +00009615 delta += 3+1;
9616 lane = insn[3+1-1];
sewardje5854d62004-12-09 03:44:34 +00009617 DIP("pinsrw $%d,%s,%s\n", (Int)lane,
9618 nameIReg(2,eregOfRM(modrm)),
9619 nameXMMReg(gregOfRM(modrm)));
9620 } else {
sewardjaac7e082005-03-17 14:03:46 +00009621 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9622 delta += 3+alen;
9623 lane = insn[3+alen-1];
9624 assign(t4, loadLE(Ity_I16, mkexpr(addr)));
9625 DIP("pinsrw $%d,%s,%s\n", (Int)lane,
9626 dis_buf,
9627 nameXMMReg(gregOfRM(modrm)));
sewardje5854d62004-12-09 03:44:34 +00009628 }
9629
9630 putXMMRegLane16( gregOfRM(modrm), lane & 7, mkexpr(t4) );
9631 goto decode_success;
9632 }
9633
9634 /* 66 0F EE = PMAXSW -- 16x8 signed max */
9635 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xEE) {
9636 delta = dis_SSEint_E_to_G( sorb, delta+2,
9637 "pmaxsw", Iop_Max16Sx8, False );
9638 goto decode_success;
9639 }
9640
9641 /* 66 0F DE = PMAXUB -- 8x16 unsigned max */
9642 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDE) {
9643 delta = dis_SSEint_E_to_G( sorb, delta+2,
9644 "pmaxub", Iop_Max8Ux16, False );
9645 goto decode_success;
9646 }
9647
9648 /* 66 0F EA = PMINSW -- 16x8 signed min */
9649 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xEA) {
9650 delta = dis_SSEint_E_to_G( sorb, delta+2,
9651 "pminsw", Iop_Min16Sx8, False );
9652 goto decode_success;
9653 }
9654
9655 /* 66 0F DA = PMINUB -- 8x16 unsigned min */
9656 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDA) {
9657 delta = dis_SSEint_E_to_G( sorb, delta+2,
9658 "pminub", Iop_Min8Ux16, False );
9659 goto decode_success;
9660 }
9661
9662 /* 66 0F D7 = PMOVMSKB -- extract sign bits from each of 16 lanes in
9663 xmm(G), turn them into a byte, and put zero-extend of it in
9664 ireg(G). Doing this directly is just too cumbersome; give up
9665 therefore and call a helper. */
9666 /* UInt x86g_calculate_sse_pmovmskb ( ULong w64hi, ULong w64lo ); */
9667 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD7) {
9668 modrm = insn[2];
9669 if (epartIsReg(modrm)) {
9670 t0 = newTemp(Ity_I64);
9671 t1 = newTemp(Ity_I64);
9672 assign(t0, getXMMRegLane64(eregOfRM(modrm), 0));
9673 assign(t1, getXMMRegLane64(eregOfRM(modrm), 1));
9674 t5 = newTemp(Ity_I32);
9675 assign(t5, mkIRExprCCall(
9676 Ity_I32, 0/*regparms*/,
9677 "x86g_calculate_sse_pmovmskb",
9678 &x86g_calculate_sse_pmovmskb,
sewardj28e5c832004-12-16 11:39:04 +00009679 mkIRExprVec_2( mkexpr(t1), mkexpr(t0) )));
sewardje5854d62004-12-09 03:44:34 +00009680 putIReg(4, gregOfRM(modrm), mkexpr(t5));
9681 DIP("pmovmskb %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9682 nameIReg(4,gregOfRM(modrm)));
9683 delta += 3;
9684 goto decode_success;
9685 }
9686 /* else fall through */
9687 }
9688
9689 /* 66 0F E4 = PMULHUW -- 16x8 hi-half of unsigned widening multiply */
9690 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE4) {
9691 delta = dis_SSEint_E_to_G( sorb, delta+2,
9692 "pmulhuw", Iop_MulHi16Ux8, False );
9693 goto decode_success;
9694 }
9695
9696 /* 66 0F E5 = PMULHW -- 16x8 hi-half of signed widening multiply */
9697 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE5) {
9698 delta = dis_SSEint_E_to_G( sorb, delta+2,
9699 "pmulhw", Iop_MulHi16Sx8, False );
9700 goto decode_success;
9701 }
9702
9703 /* 66 0F D5 = PMULHL -- 16x8 multiply */
9704 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD5) {
9705 delta = dis_SSEint_E_to_G( sorb, delta+2,
9706 "pmullw", Iop_Mul16x8, False );
9707 goto decode_success;
9708 }
9709
9710 /* ***--- this is an MMX class insn introduced in SSE2 ---*** */
9711 /* 0F F4 = PMULUDQ -- unsigned widening multiply of 32-lanes 0 x
9712 0 to form 64-bit result */
9713 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xF4) {
9714 IRTemp sV = newTemp(Ity_I64);
9715 IRTemp dV = newTemp(Ity_I64);
9716 t1 = newTemp(Ity_I32);
9717 t0 = newTemp(Ity_I32);
9718 modrm = insn[2];
9719
9720 do_MMX_preamble();
9721 assign( dV, getMMXReg(gregOfRM(modrm)) );
9722
9723 if (epartIsReg(modrm)) {
9724 assign( sV, getMMXReg(eregOfRM(modrm)) );
9725 delta += 2+1;
9726 DIP("pmuludq %s,%s\n", nameMMXReg(eregOfRM(modrm)),
9727 nameMMXReg(gregOfRM(modrm)));
9728 } else {
9729 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9730 assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
9731 delta += 2+alen;
9732 DIP("pmuludq %s,%s\n", dis_buf,
9733 nameMMXReg(gregOfRM(modrm)));
9734 }
9735
9736 assign( t0, unop(Iop_64to32, mkexpr(dV)) );
9737 assign( t1, unop(Iop_64to32, mkexpr(sV)) );
9738 putMMXReg( gregOfRM(modrm),
9739 binop( Iop_MullU32, mkexpr(t0), mkexpr(t1) ) );
9740 goto decode_success;
9741 }
9742
9743 /* 66 0F F4 = PMULUDQ -- unsigned widening multiply of 32-lanes 0 x
9744 0 to form lower 64-bit half and lanes 2 x 2 to form upper 64-bit
9745 half */
9746 /* This is a really poor translation -- could be improved if
9747 performance critical */
9748 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF4) {
9749 IRTemp sV, dV;
9750 IRTemp s3, s2, s1, s0, d3, d2, d1, d0;
9751 sV = newTemp(Ity_V128);
9752 dV = newTemp(Ity_V128);
9753 s3 = s2 = s1 = s0 = d3 = d2 = d1 = d0 = IRTemp_INVALID;
9754 t1 = newTemp(Ity_I64);
9755 t0 = newTemp(Ity_I64);
9756 modrm = insn[2];
9757 assign( dV, getXMMReg(gregOfRM(modrm)) );
9758
9759 if (epartIsReg(modrm)) {
9760 assign( sV, getXMMReg(eregOfRM(modrm)) );
9761 delta += 2+1;
9762 DIP("pmuludq %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9763 nameXMMReg(gregOfRM(modrm)));
9764 } else {
9765 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9766 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
9767 delta += 2+alen;
9768 DIP("pmuludq %s,%s\n", dis_buf,
9769 nameXMMReg(gregOfRM(modrm)));
9770 }
9771
9772 breakup128to32s( dV, &d3, &d2, &d1, &d0 );
9773 breakup128to32s( sV, &s3, &s2, &s1, &s0 );
9774
9775 assign( t0, binop( Iop_MullU32, mkexpr(d0), mkexpr(s0)) );
9776 putXMMRegLane64( gregOfRM(modrm), 0, mkexpr(t0) );
9777 assign( t1, binop( Iop_MullU32, mkexpr(d2), mkexpr(s2)) );
9778 putXMMRegLane64( gregOfRM(modrm), 1, mkexpr(t1) );
9779 goto decode_success;
9780 }
9781
9782 /* 66 0F EB = POR */
9783 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xEB) {
sewardjf0c1c582005-02-07 23:47:38 +00009784 delta = dis_SSE_E_to_G_all( sorb, delta+2, "por", Iop_OrV128 );
sewardje5854d62004-12-09 03:44:34 +00009785 goto decode_success;
9786 }
9787
sewardjb9fa69b2004-12-09 23:25:14 +00009788 /* 66 0F 70 = PSHUFD -- rearrange 4x32 from E(xmm or mem) to G(xmm) */
9789 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x70) {
9790 Int order;
9791 IRTemp sV, dV, s3, s2, s1, s0;
9792 s3 = s2 = s1 = s0 = IRTemp_INVALID;
9793 sV = newTemp(Ity_V128);
9794 dV = newTemp(Ity_V128);
9795 modrm = insn[2];
9796 if (epartIsReg(modrm)) {
9797 assign( sV, getXMMReg(eregOfRM(modrm)) );
9798 order = (Int)insn[3];
9799 delta += 2+2;
9800 DIP("pshufd $%d,%s,%s\n", order,
9801 nameXMMReg(eregOfRM(modrm)),
9802 nameXMMReg(gregOfRM(modrm)));
9803 } else {
9804 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9805 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
9806 order = (Int)insn[2+alen];
9807 delta += 3+alen;
9808 DIP("pshufd $%d,%s,%s\n", order,
9809 dis_buf,
9810 nameXMMReg(gregOfRM(modrm)));
9811 }
9812 breakup128to32s( sV, &s3, &s2, &s1, &s0 );
9813
9814# define SEL(n) \
9815 ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
9816 assign(dV,
9817 mk128from32s( SEL((order>>6)&3), SEL((order>>4)&3),
9818 SEL((order>>2)&3), SEL((order>>0)&3) )
9819 );
9820 putXMMReg(gregOfRM(modrm), mkexpr(dV));
9821# undef SEL
9822 goto decode_success;
9823 }
9824
9825 /* F3 0F 70 = PSHUFHW -- rearrange upper half 4x16 from E(xmm or
9826 mem) to G(xmm), and copy lower half */
9827 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x70) {
9828 Int order;
9829 IRTemp sVhi, dVhi, sV, dV, s3, s2, s1, s0;
9830 s3 = s2 = s1 = s0 = IRTemp_INVALID;
9831 sV = newTemp(Ity_V128);
9832 dV = newTemp(Ity_V128);
9833 sVhi = newTemp(Ity_I64);
9834 dVhi = newTemp(Ity_I64);
9835 modrm = insn[3];
9836 if (epartIsReg(modrm)) {
9837 assign( sV, getXMMReg(eregOfRM(modrm)) );
9838 order = (Int)insn[4];
9839 delta += 4+1;
9840 DIP("pshufhw $%d,%s,%s\n", order,
9841 nameXMMReg(eregOfRM(modrm)),
9842 nameXMMReg(gregOfRM(modrm)));
9843 } else {
9844 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
9845 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
9846 order = (Int)insn[3+alen];
9847 delta += 4+alen;
9848 DIP("pshufhw $%d,%s,%s\n", order,
9849 dis_buf,
9850 nameXMMReg(gregOfRM(modrm)));
9851 }
sewardjf0c1c582005-02-07 23:47:38 +00009852 assign( sVhi, unop(Iop_V128HIto64, mkexpr(sV)) );
sewardjb9fa69b2004-12-09 23:25:14 +00009853 breakup64to16s( sVhi, &s3, &s2, &s1, &s0 );
9854
9855# define SEL(n) \
9856 ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
9857 assign(dVhi,
9858 mk64from16s( SEL((order>>6)&3), SEL((order>>4)&3),
9859 SEL((order>>2)&3), SEL((order>>0)&3) )
9860 );
sewardjf0c1c582005-02-07 23:47:38 +00009861 assign(dV, binop( Iop_64HLtoV128,
sewardjb9fa69b2004-12-09 23:25:14 +00009862 mkexpr(dVhi),
sewardjf0c1c582005-02-07 23:47:38 +00009863 unop(Iop_V128to64, mkexpr(sV))) );
sewardjb9fa69b2004-12-09 23:25:14 +00009864 putXMMReg(gregOfRM(modrm), mkexpr(dV));
9865# undef SEL
9866 goto decode_success;
9867 }
9868
9869 /* F2 0F 70 = PSHUFLW -- rearrange lower half 4x16 from E(xmm or
9870 mem) to G(xmm), and copy upper half */
9871 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x70) {
9872 Int order;
9873 IRTemp sVlo, dVlo, sV, dV, s3, s2, s1, s0;
9874 s3 = s2 = s1 = s0 = IRTemp_INVALID;
9875 sV = newTemp(Ity_V128);
9876 dV = newTemp(Ity_V128);
9877 sVlo = newTemp(Ity_I64);
9878 dVlo = newTemp(Ity_I64);
9879 modrm = insn[3];
9880 if (epartIsReg(modrm)) {
9881 assign( sV, getXMMReg(eregOfRM(modrm)) );
9882 order = (Int)insn[4];
9883 delta += 4+1;
9884 DIP("pshuflw $%d,%s,%s\n", order,
9885 nameXMMReg(eregOfRM(modrm)),
9886 nameXMMReg(gregOfRM(modrm)));
9887 } else {
9888 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
9889 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
9890 order = (Int)insn[3+alen];
9891 delta += 4+alen;
9892 DIP("pshuflw $%d,%s,%s\n", order,
9893 dis_buf,
9894 nameXMMReg(gregOfRM(modrm)));
9895 }
sewardjf0c1c582005-02-07 23:47:38 +00009896 assign( sVlo, unop(Iop_V128to64, mkexpr(sV)) );
sewardjb9fa69b2004-12-09 23:25:14 +00009897 breakup64to16s( sVlo, &s3, &s2, &s1, &s0 );
9898
9899# define SEL(n) \
9900 ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
9901 assign(dVlo,
9902 mk64from16s( SEL((order>>6)&3), SEL((order>>4)&3),
9903 SEL((order>>2)&3), SEL((order>>0)&3) )
9904 );
sewardjf0c1c582005-02-07 23:47:38 +00009905 assign(dV, binop( Iop_64HLtoV128,
9906 unop(Iop_V128HIto64, mkexpr(sV)),
sewardjb9fa69b2004-12-09 23:25:14 +00009907 mkexpr(dVlo) ) );
9908 putXMMReg(gregOfRM(modrm), mkexpr(dV));
9909# undef SEL
9910 goto decode_success;
9911 }
9912
9913 /* 66 0F 72 /6 ib = PSLLD by immediate */
9914 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x72
9915 && epartIsReg(insn[2])
9916 && gregOfRM(insn[2]) == 6) {
sewardj38a3f862005-01-13 15:06:51 +00009917 delta = dis_SSE_shiftE_imm( delta+2, "pslld", Iop_ShlN32x4 );
sewardjb9fa69b2004-12-09 23:25:14 +00009918 goto decode_success;
9919 }
9920
9921 /* 66 0F F2 = PSLLD by E */
9922 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF2) {
9923 delta = dis_SSE_shiftG_byE( sorb, delta+2, "pslld", Iop_ShlN32x4 );
9924 goto decode_success;
9925 }
9926
sewardjb9fa69b2004-12-09 23:25:14 +00009927 /* 66 0F 73 /7 ib = PSLLDQ by immediate */
9928 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x73
9929 && epartIsReg(insn[2])
9930 && gregOfRM(insn[2]) == 7) {
sewardj0c9907c2005-01-10 20:37:31 +00009931 IRTemp sV, dV, hi64, lo64, hi64r, lo64r;
9932 Int imm = (Int)insn[3];
9933 Int reg = eregOfRM(insn[2]);
9934 DIP("pslldq $%d,%s\n", imm, nameXMMReg(reg));
9935 vassert(imm >= 0 && imm <= 255);
9936 delta += 4;
9937
9938 sV = newTemp(Ity_V128);
9939 dV = newTemp(Ity_V128);
9940 hi64 = newTemp(Ity_I64);
9941 lo64 = newTemp(Ity_I64);
9942 hi64r = newTemp(Ity_I64);
9943 lo64r = newTemp(Ity_I64);
9944
9945 if (imm >= 16) {
sewardj0c9907c2005-01-10 20:37:31 +00009946 putXMMReg(reg, mkV128(0x0000));
9947 goto decode_success;
9948 }
9949
9950 assign( sV, getXMMReg(reg) );
sewardjf0c1c582005-02-07 23:47:38 +00009951 assign( hi64, unop(Iop_V128HIto64, mkexpr(sV)) );
9952 assign( lo64, unop(Iop_V128to64, mkexpr(sV)) );
sewardj0c9907c2005-01-10 20:37:31 +00009953
sewardjba89f4c2005-04-07 17:31:27 +00009954 if (imm == 0) {
9955 assign( lo64r, mkexpr(lo64) );
9956 assign( hi64r, mkexpr(hi64) );
9957 }
9958 else
sewardj0c9907c2005-01-10 20:37:31 +00009959 if (imm == 8) {
9960 assign( lo64r, mkU64(0) );
9961 assign( hi64r, mkexpr(lo64) );
9962 }
sewardjc02043c2005-01-11 15:03:53 +00009963 else
sewardj0c9907c2005-01-10 20:37:31 +00009964 if (imm > 8) {
sewardj0c9907c2005-01-10 20:37:31 +00009965 assign( lo64r, mkU64(0) );
9966 assign( hi64r, binop( Iop_Shl64,
9967 mkexpr(lo64),
9968 mkU8( 8*(imm-8) ) ));
9969 } else {
9970 assign( lo64r, binop( Iop_Shl64,
9971 mkexpr(lo64),
9972 mkU8(8 * imm) ));
9973 assign( hi64r,
9974 binop( Iop_Or64,
9975 binop(Iop_Shl64, mkexpr(hi64),
9976 mkU8(8 * imm)),
9977 binop(Iop_Shr64, mkexpr(lo64),
9978 mkU8(8 * (8 - imm)) )
9979 )
9980 );
9981 }
sewardjf0c1c582005-02-07 23:47:38 +00009982 assign( dV, binop(Iop_64HLtoV128, mkexpr(hi64r), mkexpr(lo64r)) );
sewardj0c9907c2005-01-10 20:37:31 +00009983 putXMMReg(reg, mkexpr(dV));
sewardjb9fa69b2004-12-09 23:25:14 +00009984 goto decode_success;
9985 }
sewardjb9fa69b2004-12-09 23:25:14 +00009986
9987 /* 66 0F 73 /6 ib = PSLLQ by immediate */
9988 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x73
9989 && epartIsReg(insn[2])
9990 && gregOfRM(insn[2]) == 6) {
sewardj38a3f862005-01-13 15:06:51 +00009991 delta = dis_SSE_shiftE_imm( delta+2, "psllq", Iop_ShlN64x2 );
sewardjb9fa69b2004-12-09 23:25:14 +00009992 goto decode_success;
9993 }
9994
9995 /* 66 0F F3 = PSLLQ by E */
9996 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF3) {
9997 delta = dis_SSE_shiftG_byE( sorb, delta+2, "psllq", Iop_ShlN64x2 );
9998 goto decode_success;
9999 }
10000
10001 /* 66 0F 71 /6 ib = PSLLW by immediate */
10002 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x71
10003 && epartIsReg(insn[2])
10004 && gregOfRM(insn[2]) == 6) {
sewardj38a3f862005-01-13 15:06:51 +000010005 delta = dis_SSE_shiftE_imm( delta+2, "psllw", Iop_ShlN16x8 );
sewardjb9fa69b2004-12-09 23:25:14 +000010006 goto decode_success;
10007 }
10008
10009 /* 66 0F F1 = PSLLW by E */
10010 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF1) {
10011 delta = dis_SSE_shiftG_byE( sorb, delta+2, "psllw", Iop_ShlN16x8 );
10012 goto decode_success;
10013 }
10014
10015 /* 66 0F 72 /4 ib = PSRAD by immediate */
10016 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x72
10017 && epartIsReg(insn[2])
10018 && gregOfRM(insn[2]) == 4) {
sewardj38a3f862005-01-13 15:06:51 +000010019 delta = dis_SSE_shiftE_imm( delta+2, "psrad", Iop_SarN32x4 );
sewardjb9fa69b2004-12-09 23:25:14 +000010020 goto decode_success;
10021 }
10022
10023 /* 66 0F E2 = PSRAD by E */
10024 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE2) {
10025 delta = dis_SSE_shiftG_byE( sorb, delta+2, "psrad", Iop_SarN32x4 );
10026 goto decode_success;
10027 }
10028
10029 /* 66 0F 71 /4 ib = PSRAW by immediate */
10030 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x71
10031 && epartIsReg(insn[2])
10032 && gregOfRM(insn[2]) == 4) {
sewardj38a3f862005-01-13 15:06:51 +000010033 delta = dis_SSE_shiftE_imm( delta+2, "psraw", Iop_SarN16x8 );
sewardjb9fa69b2004-12-09 23:25:14 +000010034 goto decode_success;
10035 }
10036
10037 /* 66 0F E1 = PSRAW by E */
10038 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE1) {
10039 delta = dis_SSE_shiftG_byE( sorb, delta+2, "psraw", Iop_SarN16x8 );
10040 goto decode_success;
10041 }
10042
10043 /* 66 0F 72 /2 ib = PSRLD by immediate */
10044 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x72
10045 && epartIsReg(insn[2])
10046 && gregOfRM(insn[2]) == 2) {
sewardj38a3f862005-01-13 15:06:51 +000010047 delta = dis_SSE_shiftE_imm( delta+2, "psrld", Iop_ShrN32x4 );
sewardjb9fa69b2004-12-09 23:25:14 +000010048 goto decode_success;
10049 }
10050
10051 /* 66 0F D2 = PSRLD by E */
10052 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD2) {
10053 delta = dis_SSE_shiftG_byE( sorb, delta+2, "psrld", Iop_ShrN32x4 );
10054 goto decode_success;
10055 }
10056
sewardj9ee82862004-12-14 01:16:59 +000010057 /* 66 0F 73 /3 ib = PSRLDQ by immediate */
10058 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x73
10059 && epartIsReg(insn[2])
sewardj95535fe2004-12-15 17:42:58 +000010060 && gregOfRM(insn[2]) == 3) {
10061 IRTemp sV, dV, hi64, lo64, hi64r, lo64r;
sewardj9ee82862004-12-14 01:16:59 +000010062 Int imm = (Int)insn[3];
10063 Int reg = eregOfRM(insn[2]);
sewardj9ee82862004-12-14 01:16:59 +000010064 DIP("psrldq $%d,%s\n", imm, nameXMMReg(reg));
sewardj95535fe2004-12-15 17:42:58 +000010065 vassert(imm >= 0 && imm <= 255);
10066 delta += 4;
10067
10068 sV = newTemp(Ity_V128);
10069 dV = newTemp(Ity_V128);
10070 hi64 = newTemp(Ity_I64);
10071 lo64 = newTemp(Ity_I64);
10072 hi64r = newTemp(Ity_I64);
10073 lo64r = newTemp(Ity_I64);
10074
10075 if (imm >= 16) {
sewardj95535fe2004-12-15 17:42:58 +000010076 putXMMReg(reg, mkV128(0x0000));
10077 goto decode_success;
10078 }
10079
10080 assign( sV, getXMMReg(reg) );
sewardjf0c1c582005-02-07 23:47:38 +000010081 assign( hi64, unop(Iop_V128HIto64, mkexpr(sV)) );
10082 assign( lo64, unop(Iop_V128to64, mkexpr(sV)) );
sewardj95535fe2004-12-15 17:42:58 +000010083
sewardjba89f4c2005-04-07 17:31:27 +000010084 if (imm == 0) {
10085 assign( lo64r, mkexpr(lo64) );
10086 assign( hi64r, mkexpr(hi64) );
10087 }
10088 else
sewardj95535fe2004-12-15 17:42:58 +000010089 if (imm == 8) {
10090 assign( hi64r, mkU64(0) );
10091 assign( lo64r, mkexpr(hi64) );
10092 }
10093 else
10094 if (imm > 8) {
sewardj95535fe2004-12-15 17:42:58 +000010095 assign( hi64r, mkU64(0) );
10096 assign( lo64r, binop( Iop_Shr64,
10097 mkexpr(hi64),
10098 mkU8( 8*(imm-8) ) ));
10099 } else {
10100 assign( hi64r, binop( Iop_Shr64,
10101 mkexpr(hi64),
10102 mkU8(8 * imm) ));
10103 assign( lo64r,
10104 binop( Iop_Or64,
10105 binop(Iop_Shr64, mkexpr(lo64),
10106 mkU8(8 * imm)),
10107 binop(Iop_Shl64, mkexpr(hi64),
10108 mkU8(8 * (8 - imm)) )
10109 )
10110 );
10111 }
10112
sewardjf0c1c582005-02-07 23:47:38 +000010113 assign( dV, binop(Iop_64HLtoV128, mkexpr(hi64r), mkexpr(lo64r)) );
sewardj95535fe2004-12-15 17:42:58 +000010114 putXMMReg(reg, mkexpr(dV));
sewardj9ee82862004-12-14 01:16:59 +000010115 goto decode_success;
10116 }
10117
sewardjb9fa69b2004-12-09 23:25:14 +000010118 /* 66 0F 73 /2 ib = PSRLQ by immediate */
10119 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x73
10120 && epartIsReg(insn[2])
10121 && gregOfRM(insn[2]) == 2) {
sewardj38a3f862005-01-13 15:06:51 +000010122 delta = dis_SSE_shiftE_imm( delta+2, "psrlq", Iop_ShrN64x2 );
sewardjb9fa69b2004-12-09 23:25:14 +000010123 goto decode_success;
10124 }
10125
10126 /* 66 0F D3 = PSRLQ by E */
10127 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD3) {
10128 delta = dis_SSE_shiftG_byE( sorb, delta+2, "psrlq", Iop_ShrN64x2 );
10129 goto decode_success;
10130 }
10131
10132 /* 66 0F 71 /2 ib = PSRLW by immediate */
10133 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x71
10134 && epartIsReg(insn[2])
10135 && gregOfRM(insn[2]) == 2) {
sewardj38a3f862005-01-13 15:06:51 +000010136 delta = dis_SSE_shiftE_imm( delta+2, "psrlw", Iop_ShrN16x8 );
sewardjb9fa69b2004-12-09 23:25:14 +000010137 goto decode_success;
10138 }
10139
10140 /* 66 0F D1 = PSRLW by E */
10141 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD1) {
10142 delta = dis_SSE_shiftG_byE( sorb, delta+2, "psrlw", Iop_ShrN16x8 );
10143 goto decode_success;
10144 }
10145
10146 /* 66 0F F8 = PSUBB */
10147 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF8) {
10148 delta = dis_SSEint_E_to_G( sorb, delta+2,
10149 "psubb", Iop_Sub8x16, False );
10150 goto decode_success;
10151 }
10152
10153 /* 66 0F FA = PSUBD */
10154 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xFA) {
10155 delta = dis_SSEint_E_to_G( sorb, delta+2,
10156 "psubd", Iop_Sub32x4, False );
10157 goto decode_success;
10158 }
10159
10160 /* ***--- this is an MMX class insn introduced in SSE2 ---*** */
10161 /* 0F FB = PSUBQ -- sub 64x1 */
10162 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xFB) {
10163 do_MMX_preamble();
10164 delta = dis_MMXop_regmem_to_reg (
10165 sorb, delta+2, insn[1], "psubq", False );
10166 goto decode_success;
10167 }
10168
10169 /* 66 0F FB = PSUBQ */
10170 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xFB) {
10171 delta = dis_SSEint_E_to_G( sorb, delta+2,
10172 "psubq", Iop_Sub64x2, False );
10173 goto decode_success;
10174 }
10175
10176 /* 66 0F F9 = PSUBW */
10177 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF9) {
10178 delta = dis_SSEint_E_to_G( sorb, delta+2,
10179 "psubw", Iop_Sub16x8, False );
10180 goto decode_success;
10181 }
10182
10183 /* 66 0F E8 = PSUBSB */
10184 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE8) {
10185 delta = dis_SSEint_E_to_G( sorb, delta+2,
10186 "psubsb", Iop_QSub8Sx16, False );
10187 goto decode_success;
10188 }
10189
10190 /* 66 0F E9 = PSUBSW */
10191 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE9) {
10192 delta = dis_SSEint_E_to_G( sorb, delta+2,
10193 "psubsw", Iop_QSub16Sx8, False );
10194 goto decode_success;
10195 }
10196
10197 /* 66 0F D8 = PSUBSB */
10198 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD8) {
10199 delta = dis_SSEint_E_to_G( sorb, delta+2,
10200 "psubusb", Iop_QSub8Ux16, False );
10201 goto decode_success;
10202 }
10203
10204 /* 66 0F D9 = PSUBSW */
10205 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD9) {
10206 delta = dis_SSEint_E_to_G( sorb, delta+2,
10207 "psubusw", Iop_QSub16Ux8, False );
10208 goto decode_success;
10209 }
10210
sewardj9e203592004-12-10 01:48:18 +000010211 /* 66 0F 68 = PUNPCKHBW */
10212 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x68) {
10213 delta = dis_SSEint_E_to_G( sorb, delta+2,
10214 "punpckhbw",
10215 Iop_InterleaveHI8x16, True );
10216 goto decode_success;
10217 }
10218
10219 /* 66 0F 6A = PUNPCKHDQ */
10220 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x6A) {
10221 delta = dis_SSEint_E_to_G( sorb, delta+2,
10222 "punpckhdq",
10223 Iop_InterleaveHI32x4, True );
10224 goto decode_success;
10225 }
10226
10227 /* 66 0F 6D = PUNPCKHQDQ */
10228 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x6D) {
10229 delta = dis_SSEint_E_to_G( sorb, delta+2,
10230 "punpckhqdq",
10231 Iop_InterleaveHI64x2, True );
10232 goto decode_success;
10233 }
10234
10235 /* 66 0F 69 = PUNPCKHWD */
10236 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x69) {
10237 delta = dis_SSEint_E_to_G( sorb, delta+2,
10238 "punpckhwd",
10239 Iop_InterleaveHI16x8, True );
10240 goto decode_success;
10241 }
10242
10243 /* 66 0F 60 = PUNPCKLBW */
10244 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x60) {
10245 delta = dis_SSEint_E_to_G( sorb, delta+2,
10246 "punpcklbw",
10247 Iop_InterleaveLO8x16, True );
10248 goto decode_success;
10249 }
10250
10251 /* 66 0F 62 = PUNPCKLDQ */
10252 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x62) {
10253 delta = dis_SSEint_E_to_G( sorb, delta+2,
10254 "punpckldq",
10255 Iop_InterleaveLO32x4, True );
10256 goto decode_success;
10257 }
10258
10259 /* 66 0F 6C = PUNPCKLQDQ */
10260 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x6C) {
10261 delta = dis_SSEint_E_to_G( sorb, delta+2,
10262 "punpcklqdq",
10263 Iop_InterleaveLO64x2, True );
10264 goto decode_success;
10265 }
10266
10267 /* 66 0F 61 = PUNPCKLWD */
10268 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x61) {
10269 delta = dis_SSEint_E_to_G( sorb, delta+2,
10270 "punpcklwd",
10271 Iop_InterleaveLO16x8, True );
10272 goto decode_success;
10273 }
10274
10275 /* 66 0F EF = PXOR */
10276 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xEF) {
sewardjf0c1c582005-02-07 23:47:38 +000010277 delta = dis_SSE_E_to_G_all( sorb, delta+2, "pxor", Iop_XorV128 );
sewardj9e203592004-12-10 01:48:18 +000010278 goto decode_success;
10279 }
10280
sewardj164f9272004-12-09 00:39:32 +000010281
sewardjc9a65702004-07-07 16:32:57 +000010282//-- /* FXSAVE/FXRSTOR m32 -- load/store the FPU/MMX/SSE state. */
10283//-- if (insn[0] == 0x0F && insn[1] == 0xAE
10284//-- && (!epartIsReg(insn[2]))
10285//-- && (gregOfRM(insn[2]) == 1 || gregOfRM(insn[2]) == 0) ) {
10286//-- Bool store = gregOfRM(insn[2]) == 0;
10287//-- vg_assert(sz == 4);
10288//-- pair = disAMode ( cb, sorb, eip+2, dis_buf );
10289//-- t1 = LOW24(pair);
10290//-- eip += 2+HI8(pair);
10291//-- uInstr3(cb, store ? SSE2a_MemWr : SSE2a_MemRd, 512,
10292//-- Lit16, (((UShort)insn[0]) << 8) | (UShort)insn[1],
10293//-- Lit16, (UShort)insn[2],
10294//-- TempReg, t1 );
10295//-- DIP("fx%s %s\n", store ? "save" : "rstor", dis_buf );
10296//-- goto decode_success;
10297//-- }
10298//--
sewardjc9a65702004-07-07 16:32:57 +000010299//-- /* CLFLUSH -- flush cache line */
10300//-- if (insn[0] == 0x0F && insn[1] == 0xAE
10301//-- && (!epartIsReg(insn[2]))
10302//-- && (gregOfRM(insn[2]) == 7))
10303//-- {
10304//-- vg_assert(sz == 4);
10305//-- pair = disAMode ( cb, sorb, eip+2, dis_buf );
10306//-- t1 = LOW24(pair);
10307//-- eip += 2+HI8(pair);
10308//-- uInstr3(cb, SSE2a_MemRd, 0, /* ignore sz for internal ops */
10309//-- Lit16, (((UShort)0x0F) << 8) | (UShort)0xAE,
10310//-- Lit16, (UShort)insn[2],
10311//-- TempReg, t1 );
10312//-- DIP("clflush %s\n", dis_buf);
10313//-- goto decode_success;
10314//-- }
sewardjc9a65702004-07-07 16:32:57 +000010315
10316
10317 /* ---------------------------------------------------- */
sewardj9df271d2004-12-31 22:37:42 +000010318 /* --- end of the SSE/SSE2 decoder. --- */
sewardjc9a65702004-07-07 16:32:57 +000010319 /* ---------------------------------------------------- */
10320
sewardj9df271d2004-12-31 22:37:42 +000010321 after_sse_decoders:
10322
sewardjc9a65702004-07-07 16:32:57 +000010323 /* Get the primary opcode. */
10324 opc = getIByte(delta); delta++;
10325
10326 /* We get here if the current insn isn't SSE, or this CPU doesn't
10327 support SSE. */
10328
10329 switch (opc) {
10330
10331 /* ------------------------ Control flow --------------- */
sewardj940e8c92004-07-11 16:53:24 +000010332
10333 case 0xC2: /* RET imm16 */
10334 d32 = getUDisp16(delta);
10335 delta += 2;
10336 dis_ret(d32);
sewardjce70a5c2004-10-18 14:09:54 +000010337 whatNext = Dis_StopHere;
sewardj2d49b432005-02-01 00:37:06 +000010338 DIP("ret %d\n", (Int)d32);
sewardj940e8c92004-07-11 16:53:24 +000010339 break;
sewardje05c42c2004-07-08 20:25:10 +000010340 case 0xC3: /* RET */
10341 dis_ret(0);
sewardjce70a5c2004-10-18 14:09:54 +000010342 whatNext = Dis_StopHere;
sewardje05c42c2004-07-08 20:25:10 +000010343 DIP("ret\n");
10344 break;
sewardjd1061ab2004-07-08 01:45:30 +000010345
10346 case 0xE8: /* CALL J4 */
10347 d32 = getUDisp32(delta); delta += 4;
sewardjce70a5c2004-10-18 14:09:54 +000010348 d32 += (guest_eip_bbstart+delta);
10349 /* (guest_eip_bbstart+delta) == return-to addr, d32 == call-to addr */
10350 if (d32 == guest_eip_bbstart+delta && getIByte(delta) >= 0x58
10351 && getIByte(delta) <= 0x5F) {
sewardjd1061ab2004-07-08 01:45:30 +000010352 /* Specially treat the position-independent-code idiom
10353 call X
10354 X: popl %reg
10355 as
10356 movl %eip, %reg.
10357 since this generates better code, but for no other reason. */
10358 Int archReg = getIByte(delta) - 0x58;
sewardjc2ac51e2004-07-12 01:03:26 +000010359 /* vex_printf("-- fPIC thingy\n"); */
sewardjce70a5c2004-10-18 14:09:54 +000010360 putIReg(4, archReg, mkU32(guest_eip_bbstart+delta));
sewardjd1061ab2004-07-08 01:45:30 +000010361 delta++; /* Step over the POP */
10362 DIP("call 0x%x ; popl %s\n",d32,nameIReg(4,archReg));
sewardjc2ac51e2004-07-12 01:03:26 +000010363 } else {
sewardjd1061ab2004-07-08 01:45:30 +000010364 /* The normal sequence for a call. */
10365 t1 = newTemp(Ity_I32);
sewardj41f43bc2004-07-08 14:23:22 +000010366 assign(t1, binop(Iop_Sub32, getIReg(4,R_ESP), mkU32(4)));
10367 putIReg(4, R_ESP, mkexpr(t1));
sewardj5bd4d162004-11-10 13:02:48 +000010368 storeLE( mkexpr(t1), mkU32(guest_eip_bbstart+delta));
10369 if (resteerOK && resteerOkFn((Addr64)(Addr32)d32)) {
sewardjce70a5c2004-10-18 14:09:54 +000010370 /* follow into the call target. */
10371 whatNext = Dis_Resteer;
10372 *whereNext = d32;
10373 } else {
10374 jmp_lit(Ijk_Call,d32);
10375 whatNext = Dis_StopHere;
10376 }
sewardjd1061ab2004-07-08 01:45:30 +000010377 DIP("call 0x%x\n",d32);
10378 }
10379 break;
10380
sewardjc9a65702004-07-07 16:32:57 +000010381//-- case 0xC8: /* ENTER */
10382//-- d32 = getUDisp16(eip); eip += 2;
10383//-- abyte = getIByte(delta); delta++;
10384//--
10385//-- vg_assert(sz == 4);
10386//-- vg_assert(abyte == 0);
10387//--
10388//-- t1 = newTemp(cb); t2 = newTemp(cb);
10389//-- uInstr2(cb, GET, sz, ArchReg, R_EBP, TempReg, t1);
10390//-- uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t2);
10391//-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
10392//-- uLiteral(cb, sz);
10393//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
10394//-- uInstr2(cb, STORE, 4, TempReg, t1, TempReg, t2);
10395//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_EBP);
10396//-- if (d32) {
10397//-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
sewardj5bd4d162004-11-10 13:02:48 +000010398//-- uLiteral(cb, d32);
10399//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
sewardjc9a65702004-07-07 16:32:57 +000010400//-- }
10401//-- DIP("enter 0x%x, 0x%x", d32, abyte);
10402//-- break;
sewardjc2ac51e2004-07-12 01:03:26 +000010403
10404 case 0xC9: /* LEAVE */
10405 vassert(sz == 4);
10406 t1 = newTemp(Ity_I32); t2 = newTemp(Ity_I32);
10407 assign(t1, getIReg(4,R_EBP));
10408 /* First PUT ESP looks redundant, but need it because ESP must
10409 always be up-to-date for Memcheck to work... */
10410 putIReg(4, R_ESP, mkexpr(t1));
10411 assign(t2, loadLE(Ity_I32,mkexpr(t1)));
10412 putIReg(4, R_EBP, mkexpr(t2));
10413 putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t1), mkU32(4)) );
10414 DIP("leave\n");
10415 break;
10416
sewardjc9a65702004-07-07 16:32:57 +000010417//-- /* ---------------- Misc weird-ass insns --------------- */
10418//--
10419//-- case 0x27: /* DAA */
10420//-- case 0x2F: /* DAS */
10421//-- t1 = newTemp(cb);
10422//-- uInstr2(cb, GET, 1, ArchReg, R_AL, TempReg, t1);
10423//-- /* Widen %AL to 32 bits, so it's all defined when we push it. */
10424//-- uInstr1(cb, WIDEN, 4, TempReg, t1);
10425//-- uWiden(cb, 1, False);
10426//-- uInstr0(cb, CALLM_S, 0);
10427//-- uInstr1(cb, PUSH, 4, TempReg, t1);
10428//-- uInstr1(cb, CALLM, 0, Lit16,
10429//-- opc == 0x27 ? VGOFF_(helper_DAA) : VGOFF_(helper_DAS) );
10430//-- uFlagsRWU(cb, FlagsAC, FlagsSZACP, FlagO);
10431//-- uInstr1(cb, POP, 4, TempReg, t1);
10432//-- uInstr0(cb, CALLM_E, 0);
10433//-- uInstr2(cb, PUT, 1, TempReg, t1, ArchReg, R_AL);
10434//-- DIP(opc == 0x27 ? "daa\n" : "das\n");
10435//-- break;
10436//--
10437//-- case 0x37: /* AAA */
10438//-- case 0x3F: /* AAS */
10439//-- t1 = newTemp(cb);
10440//-- uInstr2(cb, GET, 2, ArchReg, R_EAX, TempReg, t1);
10441//-- /* Widen %AL to 32 bits, so it's all defined when we push it. */
10442//-- uInstr1(cb, WIDEN, 4, TempReg, t1);
10443//-- uWiden(cb, 2, False);
10444//-- uInstr0(cb, CALLM_S, 0);
10445//-- uInstr1(cb, PUSH, 4, TempReg, t1);
10446//-- uInstr1(cb, CALLM, 0, Lit16,
10447//-- opc == 0x37 ? VGOFF_(helper_AAA) : VGOFF_(helper_AAS) );
10448//-- uFlagsRWU(cb, FlagA, FlagsAC, FlagsEmpty);
10449//-- uInstr1(cb, POP, 4, TempReg, t1);
10450//-- uInstr0(cb, CALLM_E, 0);
10451//-- uInstr2(cb, PUT, 2, TempReg, t1, ArchReg, R_EAX);
10452//-- DIP(opc == 0x37 ? "aaa\n" : "aas\n");
10453//-- break;
10454//--
10455//-- case 0xD4: /* AAM */
10456//-- case 0xD5: /* AAD */
10457//-- d32 = getIByte(delta); delta++;
10458//-- if (d32 != 10) VG_(core_panic)("disInstr: AAM/AAD but base not 10 !");
10459//-- t1 = newTemp(cb);
10460//-- uInstr2(cb, GET, 2, ArchReg, R_EAX, TempReg, t1);
10461//-- /* Widen %AX to 32 bits, so it's all defined when we push it. */
10462//-- uInstr1(cb, WIDEN, 4, TempReg, t1);
10463//-- uWiden(cb, 2, False);
10464//-- uInstr0(cb, CALLM_S, 0);
10465//-- uInstr1(cb, PUSH, 4, TempReg, t1);
10466//-- uInstr1(cb, CALLM, 0, Lit16,
10467//-- opc == 0xD4 ? VGOFF_(helper_AAM) : VGOFF_(helper_AAD) );
10468//-- uFlagsRWU(cb, FlagsEmpty, FlagsSZP, FlagsEmpty);
10469//-- uInstr1(cb, POP, 4, TempReg, t1);
10470//-- uInstr0(cb, CALLM_E, 0);
10471//-- uInstr2(cb, PUT, 2, TempReg, t1, ArchReg, R_EAX);
10472//-- DIP(opc == 0xD4 ? "aam\n" : "aad\n");
10473//-- break;
sewardj1c6f9912004-09-07 10:15:24 +000010474
10475 /* ------------------------ CWD/CDQ -------------------- */
10476
10477 case 0x98: /* CBW */
10478 if (sz == 4) {
10479 putIReg(4, R_EAX, unop(Iop_16Sto32, getIReg(2, R_EAX)));
10480 DIP("cwde\n");
10481 } else {
sewardj47341042004-09-19 11:55:46 +000010482 vassert(sz == 2);
10483 putIReg(2, R_EAX, unop(Iop_8Sto16, getIReg(1, R_EAX)));
10484 DIP("cbw\n");
sewardj1c6f9912004-09-07 10:15:24 +000010485 }
10486 break;
sewardj64e1d652004-07-12 14:00:46 +000010487
10488 case 0x99: /* CWD/CDQ */
10489 ty = szToITy(sz);
10490 putIReg(sz, R_EDX,
10491 binop(mkSizedOp(ty,Iop_Sar8),
10492 getIReg(sz, R_EAX),
sewardj9ee82862004-12-14 01:16:59 +000010493 mkU8(sz == 2 ? 15 : 31)) );
sewardj64e1d652004-07-12 14:00:46 +000010494 DIP(sz == 2 ? "cwdq\n" : "cdqq\n");
10495 break;
10496
sewardjbdc7d212004-09-09 02:46:40 +000010497 /* ------------------------ FPU ops -------------------- */
10498
10499 case 0x9E: /* SAHF */
10500 codegen_SAHF();
10501 DIP("sahf\n");
10502 break;
10503
sewardjc9a65702004-07-07 16:32:57 +000010504//-- case 0x9F: /* LAHF */
10505//-- codegen_LAHF ( cb );
10506//-- DIP("lahf\n");
10507//-- break;
10508//--
sewardjbdc7d212004-09-09 02:46:40 +000010509 case 0x9B: /* FWAIT */
10510 /* ignore? */
10511 DIP("fwait\n");
10512 break;
10513
sewardjd1725d12004-08-12 20:46:53 +000010514 case 0xD8:
10515 case 0xD9:
10516 case 0xDA:
10517 case 0xDB:
10518 case 0xDC:
10519 case 0xDD:
10520 case 0xDE:
10521 case 0xDF: {
10522 UInt delta0 = delta;
10523 Bool decode_OK = False;
10524 delta = dis_FPU ( &decode_OK, sorb, delta );
10525 if (!decode_OK) {
10526 delta = delta0;
10527 goto decode_failure;
10528 }
10529 break;
10530 }
sewardj0611d802004-07-11 02:37:54 +000010531
10532 /* ------------------------ INC & DEC ------------------ */
10533
10534 case 0x40: /* INC eAX */
10535 case 0x41: /* INC eCX */
10536 case 0x42: /* INC eDX */
10537 case 0x43: /* INC eBX */
10538 case 0x44: /* INC eSP */
10539 case 0x45: /* INC eBP */
10540 case 0x46: /* INC eSI */
10541 case 0x47: /* INC eDI */
10542 vassert(sz == 2 || sz == 4);
10543 ty = szToITy(sz);
10544 t1 = newTemp(ty);
10545 assign( t1, binop(mkSizedOp(ty,Iop_Add8),
10546 getIReg(sz, (UInt)(opc - 0x40)),
10547 mkU(ty,1)) );
10548 setFlags_INC_DEC( True, t1, ty );
10549 putIReg(sz, (UInt)(opc - 0x40), mkexpr(t1));
10550 DIP("inc%c %s\n", nameISize(sz), nameIReg(sz,opc-0x40));
10551 break;
10552
10553 case 0x48: /* DEC eAX */
10554 case 0x49: /* DEC eCX */
10555 case 0x4A: /* DEC eDX */
10556 case 0x4B: /* DEC eBX */
10557 case 0x4C: /* DEC eSP */
10558 case 0x4D: /* DEC eBP */
10559 case 0x4E: /* DEC eSI */
10560 case 0x4F: /* DEC eDI */
10561 vassert(sz == 2 || sz == 4);
10562 ty = szToITy(sz);
10563 t1 = newTemp(ty);
10564 assign( t1, binop(mkSizedOp(ty,Iop_Sub8),
10565 getIReg(sz, (UInt)(opc - 0x48)),
10566 mkU(ty,1)) );
10567 setFlags_INC_DEC( False, t1, ty );
10568 putIReg(sz, (UInt)(opc - 0x48), mkexpr(t1));
10569 DIP("dec%c %s\n", nameISize(sz), nameIReg(sz,opc-0x48));
10570 break;
10571
10572 /* ------------------------ INT ------------------------ */
10573
10574 case 0xCD: /* INT imm8 */
10575 d32 = getIByte(delta); delta++;
10576 if (d32 != 0x80) goto decode_failure;
10577 /* It's important that all ArchRegs carry their up-to-date value
10578 at this point. So we declare an end-of-block here, which
10579 forces any TempRegs caching ArchRegs to be flushed. */
sewardj4fd30f22004-10-25 00:42:16 +000010580 jmp_lit(Ijk_Syscall,((Addr32)guest_eip_bbstart)+delta);
sewardjce70a5c2004-10-18 14:09:54 +000010581 whatNext = Dis_StopHere;
sewardj0611d802004-07-11 02:37:54 +000010582 DIP("int $0x80\n");
10583 break;
10584
sewardj77b86be2004-07-11 13:28:24 +000010585 /* ------------------------ Jcond, byte offset --------- */
10586
10587 case 0xEB: /* Jb (jump, byte offset) */
sewardj4fd30f22004-10-25 00:42:16 +000010588 d32 = (((Addr32)guest_eip_bbstart)+delta+1) + getSDisp8(delta);
sewardj77b86be2004-07-11 13:28:24 +000010589 delta++;
sewardj5bd4d162004-11-10 13:02:48 +000010590 if (resteerOK && resteerOkFn((Addr64)(Addr32)d32)) {
sewardjce70a5c2004-10-18 14:09:54 +000010591 whatNext = Dis_Resteer;
10592 *whereNext = d32;
10593 } else {
10594 jmp_lit(Ijk_Boring,d32);
10595 whatNext = Dis_StopHere;
10596 }
sewardj77b86be2004-07-11 13:28:24 +000010597 DIP("jmp-8 0x%x\n", d32);
10598 break;
sewardj0611d802004-07-11 02:37:54 +000010599
10600 case 0xE9: /* Jv (jump, 16/32 offset) */
10601 vassert(sz == 4); /* JRS added 2004 July 11 */
sewardj4fd30f22004-10-25 00:42:16 +000010602 d32 = (((Addr32)guest_eip_bbstart)+delta+sz) + getSDisp(sz,delta);
sewardj0611d802004-07-11 02:37:54 +000010603 delta += sz;
sewardj5bd4d162004-11-10 13:02:48 +000010604 if (resteerOK && resteerOkFn((Addr64)(Addr32)d32)) {
sewardjce70a5c2004-10-18 14:09:54 +000010605 whatNext = Dis_Resteer;
10606 *whereNext = d32;
10607 } else {
10608 jmp_lit(Ijk_Boring,d32);
10609 whatNext = Dis_StopHere;
10610 }
sewardj0611d802004-07-11 02:37:54 +000010611 DIP("jmp 0x%x\n", d32);
10612 break;
sewardje87b4842004-07-10 12:23:30 +000010613
10614 case 0x70:
10615 case 0x71:
10616 case 0x72: /* JBb/JNAEb (jump below) */
10617 case 0x73: /* JNBb/JAEb (jump not below) */
10618 case 0x74: /* JZb/JEb (jump zero) */
10619 case 0x75: /* JNZb/JNEb (jump not zero) */
10620 case 0x76: /* JBEb/JNAb (jump below or equal) */
10621 case 0x77: /* JNBEb/JAb (jump not below or equal) */
10622 case 0x78: /* JSb (jump negative) */
10623 case 0x79: /* JSb (jump not negative) */
10624 case 0x7A: /* JP (jump parity even) */
10625 case 0x7B: /* JNP/JPO (jump parity odd) */
10626 case 0x7C: /* JLb/JNGEb (jump less) */
10627 case 0x7D: /* JGEb/JNLb (jump greater or equal) */
10628 case 0x7E: /* JLEb/JNGb (jump less or equal) */
10629 case 0x7F: /* JGb/JNLEb (jump greater) */
sewardj4fd30f22004-10-25 00:42:16 +000010630 d32 = (((Addr32)guest_eip_bbstart)+delta+1) + getSDisp8(delta);
sewardje87b4842004-07-10 12:23:30 +000010631 delta++;
sewardjdbf550c2005-01-24 11:54:11 +000010632 if (0 && resteerOK && resteerOkFn((Addr64)(Addr32)d32)) {
10633 /* Assume the branch is taken. So we need to emit a
10634 side-exit to the insn following this one, on the negation
10635 of the condition, and continue at the branch target
10636 address (d32). */
10637 if (0) vex_printf("resteer\n");
10638 stmt( IRStmt_Exit(
10639 mk_x86g_calculate_condition((X86Condcode)(1 ^ (opc - 0x70))),
10640 Ijk_Boring,
10641 IRConst_U32(guest_eip_bbstart+delta) ) );
10642 whatNext = Dis_Resteer;
10643 *whereNext = d32;
10644 } else {
10645 jcc_01((X86Condcode)(opc - 0x70), (Addr32)(guest_eip_bbstart+delta), d32);
10646 whatNext = Dis_StopHere;
10647 }
sewardj2a9ad022004-11-25 02:46:58 +000010648 DIP("j%s-8 0x%x\n", name_X86Condcode(opc - 0x70), d32);
sewardje87b4842004-07-10 12:23:30 +000010649 break;
10650
sewardj458a6f82004-08-25 12:46:02 +000010651 case 0xE3: /* JECXZ or perhaps JCXZ, depending on OSO ? Intel
10652 manual says it depends on address size override,
10653 which doesn't sound right to me. */
10654 vassert(sz==4); /* possibly also OK for sz==2 */
sewardj4fd30f22004-10-25 00:42:16 +000010655 d32 = (((Addr32)guest_eip_bbstart)+delta+1) + getSDisp8(delta);
sewardj458a6f82004-08-25 12:46:02 +000010656 delta++;
10657 ty = szToITy(sz);
10658 stmt( IRStmt_Exit(
10659 binop(mkSizedOp(ty,Iop_CmpEQ8),
10660 getIReg(sz,R_ECX),
10661 mkU(ty,0)),
sewardj893aada2004-11-29 19:57:54 +000010662 Ijk_Boring,
sewardj458a6f82004-08-25 12:46:02 +000010663 IRConst_U32(d32))
10664 );
10665
10666 DIP("j%sz 0x%x\n", nameIReg(sz, R_ECX), d32);
10667 break;
10668
sewardjc9a65702004-07-07 16:32:57 +000010669//-- case 0xE0: /* LOOPNE disp8 */
10670//-- case 0xE1: /* LOOPE disp8 */
10671//-- case 0xE2: /* LOOP disp8 */
10672//-- /* Again, the docs say this uses ECX/CX as a count depending on
10673//-- the address size override, not the operand one. Since we
10674//-- don't handle address size overrides, I guess that means
10675//-- ECX. */
10676//-- d32 = (eip+1) + getSDisp8(eip); eip++;
10677//-- t1 = newTemp(cb);
10678//-- uInstr2(cb, GET, 4, ArchReg, R_ECX, TempReg, t1);
10679//-- uInstr1(cb, DEC, 4, TempReg, t1);
10680//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_ECX);
10681//-- uInstr2(cb, JIFZ, 4, TempReg, t1, Literal, 0);
10682//-- uLiteral(cb, eip);
10683//-- if (opc == 0xE0 || opc == 0xE1) { /* LOOPE/LOOPNE */
10684//-- jcc_lit(cb, eip, (opc == 0xE1 ? CondNZ : CondZ));
10685//-- }
10686//-- jmp_lit(cb, d32);
sewardjce70a5c2004-10-18 14:09:54 +000010687//-- whatNext = Dis_StopHere;
sewardjc9a65702004-07-07 16:32:57 +000010688//-- DIP("loop 0x%x\n", d32);
10689//-- break;
sewardj1813dbe2004-07-28 17:09:04 +000010690
10691 /* ------------------------ IMUL ----------------------- */
10692
10693 case 0x69: /* IMUL Iv, Ev, Gv */
10694 delta = dis_imul_I_E_G ( sorb, sz, delta, sz );
10695 break;
10696 case 0x6B: /* IMUL Ib, Ev, Gv */
10697 delta = dis_imul_I_E_G ( sorb, sz, delta, 1 );
10698 break;
sewardj0611d802004-07-11 02:37:54 +000010699
10700 /* ------------------------ MOV ------------------------ */
10701
10702 case 0x88: /* MOV Gb,Eb */
10703 delta = dis_mov_G_E(sorb, 1, delta);
10704 break;
sewardjc9a65702004-07-07 16:32:57 +000010705
10706 case 0x89: /* MOV Gv,Ev */
10707 delta = dis_mov_G_E(sorb, sz, delta);
10708 break;
10709
sewardjc2ac51e2004-07-12 01:03:26 +000010710 case 0x8A: /* MOV Eb,Gb */
10711 delta = dis_mov_E_G(sorb, 1, delta);
10712 break;
sewardje05c42c2004-07-08 20:25:10 +000010713
10714 case 0x8B: /* MOV Ev,Gv */
10715 delta = dis_mov_E_G(sorb, sz, delta);
10716 break;
10717
sewardje87b4842004-07-10 12:23:30 +000010718 case 0x8D: /* LEA M,Gv */
sewardje9460bd2005-01-28 13:45:42 +000010719 if (sz != 4)
10720 goto decode_failure;
sewardje05c42c2004-07-08 20:25:10 +000010721 modrm = getIByte(delta);
10722 if (epartIsReg(modrm))
sewardje9460bd2005-01-28 13:45:42 +000010723 goto decode_failure;
sewardje05c42c2004-07-08 20:25:10 +000010724 /* NOTE! this is the one place where a segment override prefix
10725 has no effect on the address calculation. Therefore we pass
10726 zero instead of sorb here. */
sewardje87b4842004-07-10 12:23:30 +000010727 addr = disAMode ( &alen, /*sorb*/ 0, delta, dis_buf );
10728 delta += alen;
sewardj940e8c92004-07-11 16:53:24 +000010729 putIReg(sz, gregOfRM(modrm), mkexpr(addr));
sewardje05c42c2004-07-08 20:25:10 +000010730 DIP("lea%c %s, %s\n", nameISize(sz), dis_buf,
10731 nameIReg(sz,gregOfRM(modrm)));
10732 break;
sewardje05c42c2004-07-08 20:25:10 +000010733
sewardj063f02f2004-10-20 12:36:12 +000010734 case 0x8C: /* MOV Sw,Ew -- MOV from a SEGMENT REGISTER */
10735 delta = dis_mov_Sw_Ew(sorb, sz, delta);
10736 break;
10737
sewardj7df596b2004-12-06 14:29:12 +000010738 case 0x8E: /* MOV Ew,Sw -- MOV to a SEGMENT REGISTER */
10739 delta = dis_mov_Ew_Sw(sorb, delta);
10740 break;
10741
sewardj43852812004-10-16 23:10:08 +000010742 case 0xA0: /* MOV Ob,AL */
10743 sz = 1;
10744 /* Fall through ... */
sewardj0c12ea82004-07-12 08:18:16 +000010745 case 0xA1: /* MOV Ov,eAX */
10746 d32 = getUDisp32(delta); delta += 4;
10747 ty = szToITy(sz);
10748 addr = newTemp(Ity_I32);
10749 assign( addr, handleSegOverride(sorb, mkU32(d32)) );
10750 putIReg(sz, R_EAX, loadLE(ty, mkexpr(addr)));
10751 DIP("mov%c %s0x%x, %s\n", nameISize(sz), sorbTxt(sorb),
10752 d32, nameIReg(sz,R_EAX));
10753 break;
10754
sewardj180e8b32004-07-29 01:40:11 +000010755 case 0xA2: /* MOV Ob,AL */
10756 sz = 1;
10757 /* Fall through ... */
sewardj750f4072004-07-26 22:39:11 +000010758 case 0xA3: /* MOV eAX,Ov */
10759 d32 = getUDisp32(delta); delta += 4;
10760 ty = szToITy(sz);
10761 addr = newTemp(Ity_I32);
10762 assign( addr, handleSegOverride(sorb, mkU32(d32)) );
10763 storeLE( mkexpr(addr), getIReg(sz,R_EAX) );
10764 DIP("mov%c %s, %s0x%x\n", nameISize(sz), nameIReg(sz,R_EAX),
10765 sorbTxt(sorb), d32);
10766 break;
sewardje87b4842004-07-10 12:23:30 +000010767
sewardjc2ac51e2004-07-12 01:03:26 +000010768 case 0xB0: /* MOV imm,AL */
10769 case 0xB1: /* MOV imm,CL */
10770 case 0xB2: /* MOV imm,DL */
10771 case 0xB3: /* MOV imm,BL */
10772 case 0xB4: /* MOV imm,AH */
10773 case 0xB5: /* MOV imm,CH */
10774 case 0xB6: /* MOV imm,DH */
10775 case 0xB7: /* MOV imm,BH */
10776 d32 = getIByte(delta); delta += 1;
10777 putIReg(1, opc-0xB0, mkU8(d32));
10778 DIP("movb $0x%x,%s\n", d32, nameIReg(1,opc-0xB0));
10779 break;
sewardj7ed22952004-07-29 00:09:58 +000010780
sewardje87b4842004-07-10 12:23:30 +000010781 case 0xB8: /* MOV imm,eAX */
10782 case 0xB9: /* MOV imm,eCX */
10783 case 0xBA: /* MOV imm,eDX */
10784 case 0xBB: /* MOV imm,eBX */
10785 case 0xBC: /* MOV imm,eSP */
10786 case 0xBD: /* MOV imm,eBP */
10787 case 0xBE: /* MOV imm,eSI */
10788 case 0xBF: /* MOV imm,eDI */
10789 d32 = getUDisp(sz,delta); delta += sz;
10790 putIReg(sz, opc-0xB8, mkU(szToITy(sz), d32));
10791 DIP("mov%c $0x%x,%s\n", nameISize(sz), d32, nameIReg(sz,opc-0xB8));
10792 break;
10793
sewardj77b86be2004-07-11 13:28:24 +000010794 case 0xC6: /* MOV Ib,Eb */
10795 sz = 1;
10796 goto do_Mov_I_E;
sewardje87b4842004-07-10 12:23:30 +000010797 case 0xC7: /* MOV Iv,Ev */
10798 goto do_Mov_I_E;
10799
10800 do_Mov_I_E:
10801 modrm = getIByte(delta);
10802 if (epartIsReg(modrm)) {
10803 delta++; /* mod/rm byte */
10804 d32 = getUDisp(sz,delta); delta += sz;
sewardj5bd4d162004-11-10 13:02:48 +000010805 putIReg(sz, eregOfRM(modrm), mkU(szToITy(sz), d32));
sewardje87b4842004-07-10 12:23:30 +000010806 DIP("mov%c $0x%x, %s\n", nameISize(sz), d32,
10807 nameIReg(sz,eregOfRM(modrm)));
sewardje87b4842004-07-10 12:23:30 +000010808 } else {
10809 addr = disAMode ( &alen, sorb, delta, dis_buf );
10810 delta += alen;
10811 d32 = getUDisp(sz,delta); delta += sz;
sewardj5bd4d162004-11-10 13:02:48 +000010812 storeLE(mkexpr(addr), mkU(szToITy(sz), d32));
sewardje87b4842004-07-10 12:23:30 +000010813 DIP("mov%c $0x%x, %s\n", nameISize(sz), d32, dis_buf);
10814 }
10815 break;
10816
sewardj1813dbe2004-07-28 17:09:04 +000010817 /* ------------------------ opl imm, A ----------------- */
10818
10819 case 0x04: /* ADD Ib, AL */
sewardja718d5d2005-04-03 14:59:54 +000010820 delta = dis_op_imm_A( 1, False, Iop_Add8, True, delta, "add" );
sewardj1813dbe2004-07-28 17:09:04 +000010821 break;
sewardj77b86be2004-07-11 13:28:24 +000010822 case 0x05: /* ADD Iv, eAX */
sewardja718d5d2005-04-03 14:59:54 +000010823 delta = dis_op_imm_A( sz, False, Iop_Add8, True, delta, "add" );
sewardj77b86be2004-07-11 13:28:24 +000010824 break;
10825
sewardj940e8c92004-07-11 16:53:24 +000010826 case 0x0C: /* OR Ib, AL */
sewardja718d5d2005-04-03 14:59:54 +000010827 delta = dis_op_imm_A( 1, False, Iop_Or8, True, delta, "or" );
sewardj940e8c92004-07-11 16:53:24 +000010828 break;
sewardj82292882004-07-27 00:15:59 +000010829 case 0x0D: /* OR Iv, eAX */
sewardja718d5d2005-04-03 14:59:54 +000010830 delta = dis_op_imm_A( sz, False, Iop_Or8, True, delta, "or" );
sewardj82292882004-07-27 00:15:59 +000010831 break;
10832
sewardjc9a65702004-07-07 16:32:57 +000010833//-- case 0x14: /* ADC Ib, AL */
sewardj77b86be2004-07-11 13:28:24 +000010834//-- delta = dis_op_imm_A( 1, ADC, True, delta, "adc" );
sewardjc9a65702004-07-07 16:32:57 +000010835//-- break;
sewardja718d5d2005-04-03 14:59:54 +000010836 case 0x15: /* ADC Iv, eAX */
10837 delta = dis_op_imm_A( sz, True, Iop_Add8, True, delta, "adc" );
10838 break;
10839
sewardjc9a65702004-07-07 16:32:57 +000010840//-- case 0x1C: /* SBB Ib, AL */
sewardj77b86be2004-07-11 13:28:24 +000010841//-- delta = dis_op_imm_A( 1, SBB, True, delta, "sbb" );
sewardjc9a65702004-07-07 16:32:57 +000010842//-- break;
10843//-- case 0x1D: /* SBB Iv, eAX */
sewardj77b86be2004-07-11 13:28:24 +000010844//-- delta = dis_op_imm_A( sz, SBB, True, delta, "sbb" );
sewardjc9a65702004-07-07 16:32:57 +000010845//-- break;
10846//--
sewardj940e8c92004-07-11 16:53:24 +000010847 case 0x24: /* AND Ib, AL */
sewardja718d5d2005-04-03 14:59:54 +000010848 delta = dis_op_imm_A( 1, False, Iop_And8, True, delta, "and" );
sewardj940e8c92004-07-11 16:53:24 +000010849 break;
sewardjc2ac51e2004-07-12 01:03:26 +000010850 case 0x25: /* AND Iv, eAX */
sewardja718d5d2005-04-03 14:59:54 +000010851 delta = dis_op_imm_A( sz, False, Iop_And8, True, delta, "and" );
sewardjc2ac51e2004-07-12 01:03:26 +000010852 break;
sewardj0611d802004-07-11 02:37:54 +000010853
10854 case 0x2C: /* SUB Ib, AL */
sewardja718d5d2005-04-03 14:59:54 +000010855 delta = dis_op_imm_A( 1, False, Iop_Sub8, True, delta, "sub" );
sewardj0611d802004-07-11 02:37:54 +000010856 break;
sewardj68511542004-07-28 00:15:44 +000010857 case 0x2D: /* SUB Iv, eAX */
sewardja718d5d2005-04-03 14:59:54 +000010858 delta = dis_op_imm_A( sz, False, Iop_Sub8, True, delta, "sub" );
sewardj68511542004-07-28 00:15:44 +000010859 break;
10860
sewardj1c6f9912004-09-07 10:15:24 +000010861 case 0x34: /* XOR Ib, AL */
sewardja718d5d2005-04-03 14:59:54 +000010862 delta = dis_op_imm_A( 1, False, Iop_Xor8, True, delta, "xor" );
sewardj1c6f9912004-09-07 10:15:24 +000010863 break;
sewardjcaca9d02004-07-28 07:11:32 +000010864 case 0x35: /* XOR Iv, eAX */
sewardja718d5d2005-04-03 14:59:54 +000010865 delta = dis_op_imm_A( sz, False, Iop_Xor8, True, delta, "xor" );
sewardjcaca9d02004-07-28 07:11:32 +000010866 break;
10867
sewardj0611d802004-07-11 02:37:54 +000010868 case 0x3C: /* CMP Ib, AL */
sewardja718d5d2005-04-03 14:59:54 +000010869 delta = dis_op_imm_A( 1, False, Iop_Sub8, False, delta, "cmp" );
sewardj0611d802004-07-11 02:37:54 +000010870 break;
10871 case 0x3D: /* CMP Iv, eAX */
sewardja718d5d2005-04-03 14:59:54 +000010872 delta = dis_op_imm_A( sz, False, Iop_Sub8, False, delta, "cmp" );
sewardj0611d802004-07-11 02:37:54 +000010873 break;
10874
sewardj77b86be2004-07-11 13:28:24 +000010875 case 0xA8: /* TEST Ib, AL */
sewardja718d5d2005-04-03 14:59:54 +000010876 delta = dis_op_imm_A( 1, False, Iop_And8, False, delta, "test" );
sewardj77b86be2004-07-11 13:28:24 +000010877 break;
sewardjc2ac51e2004-07-12 01:03:26 +000010878 case 0xA9: /* TEST Iv, eAX */
sewardja718d5d2005-04-03 14:59:54 +000010879 delta = dis_op_imm_A( sz, False, Iop_And8, False, delta, "test" );
sewardjc2ac51e2004-07-12 01:03:26 +000010880 break;
10881
sewardj1c6f9912004-09-07 10:15:24 +000010882 /* ------------------------ opl Ev, Gv ----------------- */
10883
sewardj89cd0932004-09-08 18:23:25 +000010884 case 0x02: /* ADD Eb,Gb */
10885 delta = dis_op2_E_G ( sorb, False, Iop_Add8, True, 1, delta, "add" );
10886 break;
sewardj9334b0f2004-07-10 22:43:54 +000010887 case 0x03: /* ADD Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +000010888 delta = dis_op2_E_G ( sorb, False, Iop_Add8, True, sz, delta, "add" );
sewardj9334b0f2004-07-10 22:43:54 +000010889 break;
10890
sewardj7ed22952004-07-29 00:09:58 +000010891 case 0x0A: /* OR Eb,Gb */
sewardj180e8b32004-07-29 01:40:11 +000010892 delta = dis_op2_E_G ( sorb, False, Iop_Or8, True, 1, delta, "or" );
sewardj7ed22952004-07-29 00:09:58 +000010893 break;
sewardjc2ac51e2004-07-12 01:03:26 +000010894 case 0x0B: /* OR Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +000010895 delta = dis_op2_E_G ( sorb, False, Iop_Or8, True, sz, delta, "or" );
sewardjc2ac51e2004-07-12 01:03:26 +000010896 break;
sewardjc9a65702004-07-07 16:32:57 +000010897//--
10898//-- case 0x12: /* ADC Eb,Gb */
sewardj180e8b32004-07-29 01:40:11 +000010899//-- delta = dis_op2_E_G ( sorb, True, ADC, True, 1, delta, "adc" );
sewardjc9a65702004-07-07 16:32:57 +000010900//-- break;
sewardjc4eaff32004-09-10 20:25:11 +000010901 case 0x13: /* ADC Ev,Gv */
10902 delta = dis_op2_E_G ( sorb, True, Iop_Add8, True, sz, delta, "adc" );
10903 break;
10904
sewardjc9a65702004-07-07 16:32:57 +000010905//-- case 0x1A: /* SBB Eb,Gb */
sewardj180e8b32004-07-29 01:40:11 +000010906//-- delta = dis_op2_E_G ( sorb, True, SBB, True, 1, delta, "sbb" );
sewardjc9a65702004-07-07 16:32:57 +000010907//-- break;
sewardj180e8b32004-07-29 01:40:11 +000010908 case 0x1B: /* SBB Ev,Gv */
10909 delta = dis_op2_E_G ( sorb, True, Iop_Sub8, True, sz, delta, "sbb" );
sewardj940e8c92004-07-11 16:53:24 +000010910 break;
10911
sewardj1c6f9912004-09-07 10:15:24 +000010912 case 0x22: /* AND Eb,Gb */
10913 delta = dis_op2_E_G ( sorb, False, Iop_And8, True, 1, delta, "and" );
10914 break;
sewardj180e8b32004-07-29 01:40:11 +000010915 case 0x23: /* AND Ev,Gv */
10916 delta = dis_op2_E_G ( sorb, False, Iop_And8, True, sz, delta, "and" );
10917 break;
10918
10919 case 0x2A: /* SUB Eb,Gb */
10920 delta = dis_op2_E_G ( sorb, False, Iop_Sub8, True, 1, delta, "sub" );
10921 break;
sewardj0611d802004-07-11 02:37:54 +000010922 case 0x2B: /* SUB Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +000010923 delta = dis_op2_E_G ( sorb, False, Iop_Sub8, True, sz, delta, "sub" );
sewardj0611d802004-07-11 02:37:54 +000010924 break;
sewardjc2ac51e2004-07-12 01:03:26 +000010925
10926 case 0x32: /* XOR Eb,Gb */
sewardj180e8b32004-07-29 01:40:11 +000010927 delta = dis_op2_E_G ( sorb, False, Iop_Xor8, True, 1, delta, "xor" );
sewardjc2ac51e2004-07-12 01:03:26 +000010928 break;
sewardj1813dbe2004-07-28 17:09:04 +000010929 case 0x33: /* XOR Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +000010930 delta = dis_op2_E_G ( sorb, False, Iop_Xor8, True, sz, delta, "xor" );
sewardj1813dbe2004-07-28 17:09:04 +000010931 break;
10932
sewardjc2ac51e2004-07-12 01:03:26 +000010933 case 0x3A: /* CMP Eb,Gb */
sewardj180e8b32004-07-29 01:40:11 +000010934 delta = dis_op2_E_G ( sorb, False, Iop_Sub8, False, 1, delta, "cmp" );
sewardjc2ac51e2004-07-12 01:03:26 +000010935 break;
sewardje90ad6a2004-07-10 19:02:10 +000010936 case 0x3B: /* CMP Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +000010937 delta = dis_op2_E_G ( sorb, False, Iop_Sub8, False, sz, delta, "cmp" );
sewardje90ad6a2004-07-10 19:02:10 +000010938 break;
10939
sewardj0611d802004-07-11 02:37:54 +000010940 case 0x84: /* TEST Eb,Gb */
sewardj180e8b32004-07-29 01:40:11 +000010941 delta = dis_op2_E_G ( sorb, False, Iop_And8, False, 1, delta, "test" );
sewardj0611d802004-07-11 02:37:54 +000010942 break;
sewardje05c42c2004-07-08 20:25:10 +000010943 case 0x85: /* TEST Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +000010944 delta = dis_op2_E_G ( sorb, False, Iop_And8, False, sz, delta, "test" );
sewardje05c42c2004-07-08 20:25:10 +000010945 break;
10946
sewardj180e8b32004-07-29 01:40:11 +000010947 /* ------------------------ opl Gv, Ev ----------------- */
10948
10949 case 0x00: /* ADD Gb,Eb */
10950 delta = dis_op2_G_E ( sorb, False, Iop_Add8, True, 1, delta, "add" );
10951 break;
sewardje05c42c2004-07-08 20:25:10 +000010952 case 0x01: /* ADD Gv,Ev */
sewardjcaca9d02004-07-28 07:11:32 +000010953 delta = dis_op2_G_E ( sorb, False, Iop_Add8, True, sz, delta, "add" );
sewardje05c42c2004-07-08 20:25:10 +000010954 break;
10955
sewardj940e8c92004-07-11 16:53:24 +000010956 case 0x08: /* OR Gb,Eb */
sewardjcaca9d02004-07-28 07:11:32 +000010957 delta = dis_op2_G_E ( sorb, False, Iop_Or8, True, 1, delta, "or" );
sewardj940e8c92004-07-11 16:53:24 +000010958 break;
sewardj9334b0f2004-07-10 22:43:54 +000010959 case 0x09: /* OR Gv,Ev */
sewardjcaca9d02004-07-28 07:11:32 +000010960 delta = dis_op2_G_E ( sorb, False, Iop_Or8, True, sz, delta, "or" );
sewardj9334b0f2004-07-10 22:43:54 +000010961 break;
10962
sewardja2384712004-07-29 14:36:40 +000010963 case 0x10: /* ADC Gb,Eb */
10964 delta = dis_op2_G_E ( sorb, True, Iop_Add8, True, 1, delta, "adc" );
10965 break;
sewardjcaca9d02004-07-28 07:11:32 +000010966 case 0x11: /* ADC Gv,Ev */
10967 delta = dis_op2_G_E ( sorb, True, Iop_Add8, True, sz, delta, "adc" );
10968 break;
10969
sewardja2384712004-07-29 14:36:40 +000010970 case 0x18: /* SBB Gb,Eb */
10971 delta = dis_op2_G_E ( sorb, True, Iop_Sub8, True, 1, delta, "sbb" );
10972 break;
sewardjcaca9d02004-07-28 07:11:32 +000010973 case 0x19: /* SBB Gv,Ev */
10974 delta = dis_op2_G_E ( sorb, True, Iop_Sub8, True, sz, delta, "sbb" );
10975 break;
10976
sewardja2384712004-07-29 14:36:40 +000010977 case 0x20: /* AND Gb,Eb */
10978 delta = dis_op2_G_E ( sorb, False, Iop_And8, True, 1, delta, "and" );
10979 break;
sewardj0611d802004-07-11 02:37:54 +000010980 case 0x21: /* AND Gv,Ev */
sewardjcaca9d02004-07-28 07:11:32 +000010981 delta = dis_op2_G_E ( sorb, False, Iop_And8, True, sz, delta, "and" );
sewardj0611d802004-07-11 02:37:54 +000010982 break;
10983
sewardj180e8b32004-07-29 01:40:11 +000010984 case 0x28: /* SUB Gb,Eb */
10985 delta = dis_op2_G_E ( sorb, False, Iop_Sub8, True, 1, delta, "sub" );
10986 break;
sewardje05c42c2004-07-08 20:25:10 +000010987 case 0x29: /* SUB Gv,Ev */
sewardjcaca9d02004-07-28 07:11:32 +000010988 delta = dis_op2_G_E ( sorb, False, Iop_Sub8, True, sz, delta, "sub" );
sewardje05c42c2004-07-08 20:25:10 +000010989 break;
10990
sewardjc2ac51e2004-07-12 01:03:26 +000010991 case 0x30: /* XOR Gb,Eb */
sewardjcaca9d02004-07-28 07:11:32 +000010992 delta = dis_op2_G_E ( sorb, False, Iop_Xor8, True, 1, delta, "xor" );
sewardjc2ac51e2004-07-12 01:03:26 +000010993 break;
sewardje87b4842004-07-10 12:23:30 +000010994 case 0x31: /* XOR Gv,Ev */
sewardjcaca9d02004-07-28 07:11:32 +000010995 delta = dis_op2_G_E ( sorb, False, Iop_Xor8, True, sz, delta, "xor" );
sewardje87b4842004-07-10 12:23:30 +000010996 break;
10997
sewardj0611d802004-07-11 02:37:54 +000010998 case 0x38: /* CMP Gb,Eb */
sewardjcaca9d02004-07-28 07:11:32 +000010999 delta = dis_op2_G_E ( sorb, False, Iop_Sub8, False, 1, delta, "cmp" );
sewardj0611d802004-07-11 02:37:54 +000011000 break;
sewardje90ad6a2004-07-10 19:02:10 +000011001 case 0x39: /* CMP Gv,Ev */
sewardjcaca9d02004-07-28 07:11:32 +000011002 delta = dis_op2_G_E ( sorb, False, Iop_Sub8, False, sz, delta, "cmp" );
sewardje90ad6a2004-07-10 19:02:10 +000011003 break;
11004
sewardj9334b0f2004-07-10 22:43:54 +000011005 /* ------------------------ POP ------------------------ */
11006
11007 case 0x58: /* POP eAX */
11008 case 0x59: /* POP eCX */
11009 case 0x5A: /* POP eDX */
11010 case 0x5B: /* POP eBX */
11011 case 0x5D: /* POP eBP */
11012 case 0x5E: /* POP eSI */
11013 case 0x5F: /* POP eDI */
11014 case 0x5C: /* POP eSP */
11015 vassert(sz == 2 || sz == 4);
11016 t1 = newTemp(szToITy(sz)); t2 = newTemp(Ity_I32);
11017 assign(t2, getIReg(4, R_ESP));
11018 assign(t1, loadLE(szToITy(sz),mkexpr(t2)));
11019 putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t2), mkU32(sz)));
11020 putIReg(sz, opc-0x58, mkexpr(t1));
11021 DIP("pop%c %s\n", nameISize(sz), nameIReg(sz,opc-0x58));
11022 break;
11023
sewardja2384712004-07-29 14:36:40 +000011024 case 0x9D: /* POPF */
11025 vassert(sz == 2 || sz == 4);
11026 vassert(sz == 4); // until we know a sz==2 test case exists
11027 t1 = newTemp(Ity_I32); t2 = newTemp(Ity_I32);
11028 assign(t2, getIReg(4, R_ESP));
sewardjc22a6fd2004-07-29 23:41:47 +000011029 assign(t1, widenUto32(loadLE(szToITy(sz),mkexpr(t2))));
sewardja2384712004-07-29 14:36:40 +000011030 putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t2), mkU32(sz)));
sewardj98169c52004-10-24 13:11:39 +000011031 /* t1 is the flag word. Mask out everything except OSZACP and
sewardj2a9ad022004-11-25 02:46:58 +000011032 set the flags thunk to X86G_CC_OP_COPY. */
11033 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
sewardj2a2ba8b2004-11-08 13:14:06 +000011034 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
11035 stmt( IRStmt_Put( OFFB_CC_DEP1,
sewardj5bd4d162004-11-10 13:02:48 +000011036 binop(Iop_And32,
11037 mkexpr(t1),
sewardj2a9ad022004-11-25 02:46:58 +000011038 mkU32( X86G_CC_MASK_C | X86G_CC_MASK_P
11039 | X86G_CC_MASK_A | X86G_CC_MASK_Z
11040 | X86G_CC_MASK_S| X86G_CC_MASK_O )
sewardj5bd4d162004-11-10 13:02:48 +000011041 )
11042 )
11043 );
sewardja3b7e3a2005-04-05 01:54:19 +000011044 /* Set NDEP even though it isn't used. This makes redundant-PUT
11045 elimination of previous stores to this field work better. */
11046 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU32(0) ));
sewardja2384712004-07-29 14:36:40 +000011047
11048 /* Also need to set the D flag, which is held in bit 10 of t1.
11049 If zero, put 1 in OFFB_DFLAG, else -1 in OFFB_DFLAG. */
11050 stmt( IRStmt_Put(
11051 OFFB_DFLAG,
11052 IRExpr_Mux0X(
11053 unop(Iop_32to8,
11054 binop(Iop_And32,
11055 binop(Iop_Shr32, mkexpr(t1), mkU8(10)),
11056 mkU32(1))),
11057 mkU32(1),
11058 mkU32(0xFFFFFFFF)))
11059 );
11060
sewardj006a6a22004-10-26 00:50:52 +000011061 /* And set the ID flag */
11062 stmt( IRStmt_Put(
11063 OFFB_IDFLAG,
11064 IRExpr_Mux0X(
11065 unop(Iop_32to8,
11066 binop(Iop_And32,
11067 binop(Iop_Shr32, mkexpr(t1), mkU8(21)),
11068 mkU32(1))),
11069 mkU32(0),
11070 mkU32(1)))
11071 );
11072
sewardja2384712004-07-29 14:36:40 +000011073 DIP("popf%c\n", nameISize(sz));
11074 break;
11075
sewardjbbdc6222004-12-15 18:43:39 +000011076 case 0x61: /* POPA */
11077 /* This is almost certainly wrong for sz==2. So ... */
11078 if (sz != 4) goto decode_failure;
11079
11080 /* t5 is the old %ESP value. */
11081 t5 = newTemp(Ity_I32);
11082 assign( t5, getIReg(4, R_ESP) );
11083
11084 /* Reload all the registers, except %esp. */
11085 putIReg(4,R_EAX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(28)) ));
11086 putIReg(4,R_ECX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(24)) ));
11087 putIReg(4,R_EDX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(20)) ));
11088 putIReg(4,R_EBX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(16)) ));
11089 /* ignore saved %ESP */
11090 putIReg(4,R_EBP, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32( 8)) ));
11091 putIReg(4,R_ESI, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32( 4)) ));
11092 putIReg(4,R_EDI, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32( 0)) ));
11093
11094 /* and move %ESP back up */
11095 putIReg( 4, R_ESP, binop(Iop_Add32, mkexpr(t5), mkU32(8*4)) );
11096
sewardja3d1a662005-03-29 21:33:11 +000011097 DIP("popa%c\n", nameISize(sz));
sewardjbbdc6222004-12-15 18:43:39 +000011098 break;
sewardjfeeb8a82004-11-30 12:30:11 +000011099
11100 case 0x8F: /* POPL/POPW m32 */
11101 { Int len;
11102 UChar rm = getIByte(delta);
11103
11104 /* make sure this instruction is correct POP */
11105 vassert(!epartIsReg(rm) && (gregOfRM(rm) == 0));
11106 /* and has correct size */
11107 vassert(sz == 4);
11108
11109 t1 = newTemp(Ity_I32); t3 = newTemp(Ity_I32);
11110 /* set t1 to ESP: t1 = ESP */
11111 assign( t1, getIReg(4, R_ESP) );
11112 /* load M[ESP] to virtual register t3: t3 = M[t1] */
11113 assign( t3, loadLE(Ity_I32, mkexpr(t1)) );
11114
11115 /* increase ESP; must be done before the STORE. Intel manual says:
11116 If the ESP register is used as a base register for addressing
11117 a destination operand in memory, the POP instruction computes
11118 the effective address of the operand after it increments the
11119 ESP register.
11120 */
11121 putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t1), mkU32(sz)) );
11122
11123 /* resolve MODR/M */
11124 addr = disAMode ( &len, sorb, delta, dis_buf);
11125 storeLE( mkexpr(addr), mkexpr(t3) );
11126
11127 DIP("popl %s\n", dis_buf);
11128
11129 delta += len;
11130 break;
11131 }
11132
sewardjc9a65702004-07-07 16:32:57 +000011133//-- case 0x1F: /* POP %DS */
11134//-- dis_pop_segreg( cb, R_DS, sz ); break;
11135//-- case 0x07: /* POP %ES */
11136//-- dis_pop_segreg( cb, R_ES, sz ); break;
11137//-- case 0x17: /* POP %SS */
11138//-- dis_pop_segreg( cb, R_SS, sz ); break;
sewardjd1061ab2004-07-08 01:45:30 +000011139
11140 /* ------------------------ PUSH ----------------------- */
11141
11142 case 0x50: /* PUSH eAX */
11143 case 0x51: /* PUSH eCX */
11144 case 0x52: /* PUSH eDX */
11145 case 0x53: /* PUSH eBX */
11146 case 0x55: /* PUSH eBP */
11147 case 0x56: /* PUSH eSI */
11148 case 0x57: /* PUSH eDI */
11149 case 0x54: /* PUSH eSP */
11150 /* This is the Right Way, in that the value to be pushed is
11151 established before %esp is changed, so that pushl %esp
11152 correctly pushes the old value. */
11153 vassert(sz == 2 || sz == 4);
11154 ty = sz==2 ? Ity_I16 : Ity_I32;
sewardj883b00b2004-09-11 09:30:24 +000011155 t1 = newTemp(ty); t2 = newTemp(Ity_I32);
sewardj41f43bc2004-07-08 14:23:22 +000011156 assign(t1, getIReg(sz, opc-0x50));
11157 assign(t2, binop(Iop_Sub32, getIReg(4, R_ESP), mkU32(sz)));
11158 putIReg(4, R_ESP, mkexpr(t2) );
11159 storeLE(mkexpr(t2),mkexpr(t1));
sewardjd1061ab2004-07-08 01:45:30 +000011160 DIP("push%c %s\n", nameISize(sz), nameIReg(sz,opc-0x50));
11161 break;
11162
11163
sewardj0c12ea82004-07-12 08:18:16 +000011164 case 0x68: /* PUSH Iv */
11165 d32 = getUDisp(sz,delta); delta += sz;
11166 goto do_push_I;
sewardj741153c2004-07-25 23:39:13 +000011167 case 0x6A: /* PUSH Ib, sign-extended to sz */
11168 d32 = getSDisp8(delta); delta += 1;
11169 goto do_push_I;
sewardj0c12ea82004-07-12 08:18:16 +000011170 do_push_I:
11171 ty = szToITy(sz);
11172 t1 = newTemp(Ity_I32); t2 = newTemp(ty);
11173 assign( t1, binop(Iop_Sub32,getIReg(4,R_ESP),mkU32(sz)) );
11174 putIReg(4, R_ESP, mkexpr(t1) );
11175 storeLE( mkexpr(t1), mkU(ty,d32) );
11176 DIP("push%c $0x%x\n", nameISize(sz), d32);
11177 break;
11178
sewardja2384712004-07-29 14:36:40 +000011179 case 0x9C: /* PUSHF */ {
sewardja2384712004-07-29 14:36:40 +000011180 vassert(sz == 2 || sz == 4);
11181 vassert(sz == 4); // wait for sz==2 test case
11182
11183 t1 = newTemp(Ity_I32);
11184 assign( t1, binop(Iop_Sub32,getIReg(4,R_ESP),mkU32(sz)) );
11185 putIReg(4, R_ESP, mkexpr(t1) );
11186
11187 t2 = newTemp(Ity_I32);
sewardj2a9ad022004-11-25 02:46:58 +000011188 assign( t2, mk_x86g_calculate_eflags_all() );
sewardja2384712004-07-29 14:36:40 +000011189
sewardjf9c74fe2004-12-16 02:54:54 +000011190 /* Patch in the D flag. This can simply be a copy of bit 10 of
11191 baseBlock[OFFB_DFLAG]. */
sewardja2384712004-07-29 14:36:40 +000011192 t3 = newTemp(Ity_I32);
11193 assign( t3, binop(Iop_Or32,
11194 mkexpr(t2),
11195 binop(Iop_And32,
sewardjf9c74fe2004-12-16 02:54:54 +000011196 IRExpr_Get(OFFB_DFLAG,Ity_I32),
sewardj5bd4d162004-11-10 13:02:48 +000011197 mkU32(1<<10)))
sewardja2384712004-07-29 14:36:40 +000011198 );
sewardj006a6a22004-10-26 00:50:52 +000011199
11200 /* And patch in the ID flag. */
11201 t4 = newTemp(Ity_I32);
11202 assign( t4, binop(Iop_Or32,
11203 mkexpr(t3),
11204 binop(Iop_And32,
sewardj5bd4d162004-11-10 13:02:48 +000011205 binop(Iop_Shl32, IRExpr_Get(OFFB_IDFLAG,Ity_I32),
sewardj006a6a22004-10-26 00:50:52 +000011206 mkU8(21)),
sewardj5bd4d162004-11-10 13:02:48 +000011207 mkU32(1<<21)))
sewardj006a6a22004-10-26 00:50:52 +000011208 );
11209
sewardja2384712004-07-29 14:36:40 +000011210 /* if sz==2, the stored value needs to be narrowed. */
11211 if (sz == 2)
sewardj5bd4d162004-11-10 13:02:48 +000011212 storeLE( mkexpr(t1), unop(Iop_32to16,mkexpr(t4)) );
sewardja2384712004-07-29 14:36:40 +000011213 else
sewardj5bd4d162004-11-10 13:02:48 +000011214 storeLE( mkexpr(t1), mkexpr(t4) );
sewardja2384712004-07-29 14:36:40 +000011215
11216 DIP("pushf%c\n", nameISize(sz));
11217 break;
11218 }
11219
sewardjbbdc6222004-12-15 18:43:39 +000011220 case 0x60: /* PUSHA */
11221 /* This is almost certainly wrong for sz==2. So ... */
11222 if (sz != 4) goto decode_failure;
11223
11224 /* This is the Right Way, in that the value to be pushed is
11225 established before %esp is changed, so that pusha
11226 correctly pushes the old %esp value. New value of %esp is
11227 pushed at start. */
11228 /* t0 is the %ESP value we're going to push. */
11229 t0 = newTemp(Ity_I32);
11230 assign( t0, getIReg(4, R_ESP) );
11231
11232 /* t5 will be the new %ESP value. */
11233 t5 = newTemp(Ity_I32);
11234 assign( t5, binop(Iop_Sub32, mkexpr(t0), mkU32(8*4)) );
11235
11236 /* Update guest state before prodding memory. */
11237 putIReg(4, R_ESP, mkexpr(t5));
11238
11239 /* Dump all the registers. */
11240 storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(28)), getIReg(4,R_EAX) );
11241 storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(24)), getIReg(4,R_ECX) );
11242 storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(20)), getIReg(4,R_EDX) );
11243 storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(16)), getIReg(4,R_EBX) );
11244 storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(12)), mkexpr(t0) /*esp*/);
11245 storeLE( binop(Iop_Add32,mkexpr(t5),mkU32( 8)), getIReg(4,R_EBP) );
11246 storeLE( binop(Iop_Add32,mkexpr(t5),mkU32( 4)), getIReg(4,R_ESI) );
11247 storeLE( binop(Iop_Add32,mkexpr(t5),mkU32( 0)), getIReg(4,R_EDI) );
11248
11249 DIP("pusha%c\n", nameISize(sz));
11250 break;
11251
11252
sewardjc9a65702004-07-07 16:32:57 +000011253//-- case 0x0E: /* PUSH %CS */
11254//-- dis_push_segreg( cb, R_CS, sz ); break;
11255//-- case 0x1E: /* PUSH %DS */
11256//-- dis_push_segreg( cb, R_DS, sz ); break;
11257//-- case 0x06: /* PUSH %ES */
11258//-- dis_push_segreg( cb, R_ES, sz ); break;
11259//-- case 0x16: /* PUSH %SS */
11260//-- dis_push_segreg( cb, R_SS, sz ); break;
sewardj458a6f82004-08-25 12:46:02 +000011261
11262 /* ------------------------ SCAS et al ----------------- */
11263
11264 case 0xA4: /* MOVS, no REP prefix */
11265 case 0xA5:
11266 dis_string_op( dis_MOVS, ( opc == 0xA4 ? 1 : sz ), "movs", sorb );
11267 break;
11268
sewardj8d4d2232005-01-20 10:47:46 +000011269 case 0xA6: /* CMPSb, no REP prefix */
sewardj33b53542005-03-11 14:00:27 +000011270 case 0xA7:
sewardj8d4d2232005-01-20 10:47:46 +000011271 dis_string_op( dis_CMPS, ( opc == 0xA6 ? 1 : sz ), "cmps", sorb );
11272 break;
sewardj33b53542005-03-11 14:00:27 +000011273
sewardj883b00b2004-09-11 09:30:24 +000011274 case 0xAA: /* STOS, no REP prefix */
sewardj47341042004-09-19 11:55:46 +000011275 case 0xAB:
sewardj883b00b2004-09-11 09:30:24 +000011276 dis_string_op( dis_STOS, ( opc == 0xAA ? 1 : sz ), "stos", sorb );
11277 break;
sewardj33b53542005-03-11 14:00:27 +000011278
sewardj10ca4eb2005-05-30 11:19:54 +000011279 case 0xAC: /* LODS, no REP prefix */
11280 case 0xAD:
11281 dis_string_op( dis_LODS, ( opc == 0xAC ? 1 : sz ), "lods", sorb );
11282 break;
sewardj2d4c3a02004-10-15 00:03:23 +000011283
11284 case 0xAE: /* SCAS, no REP prefix */
11285 case 0xAF:
11286 dis_string_op( dis_SCAS, ( opc == 0xAE ? 1 : sz ), "scas", sorb );
11287 break;
sewardj64e1d652004-07-12 14:00:46 +000011288
11289
11290 case 0xFC: /* CLD */
sewardjeeb9ef82004-07-15 12:39:03 +000011291 stmt( IRStmt_Put( OFFB_DFLAG, mkU32(1)) );
sewardj64e1d652004-07-12 14:00:46 +000011292 DIP("cld\n");
11293 break;
11294
sewardj1813dbe2004-07-28 17:09:04 +000011295 case 0xFD: /* STD */
11296 stmt( IRStmt_Put( OFFB_DFLAG, mkU32(0xFFFFFFFF)) );
11297 DIP("std\n");
11298 break;
11299
sewardjc9a65702004-07-07 16:32:57 +000011300//-- case 0xF8: /* CLC */
11301//-- uInstr0(cb, CALLM_S, 0);
11302//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_CLC));
11303//-- uFlagsRWU(cb, FlagsEmpty, FlagC, FlagsOSZAP);
11304//-- uInstr0(cb, CALLM_E, 0);
11305//-- DIP("clc\n");
11306//-- break;
11307//--
11308//-- case 0xF9: /* STC */
11309//-- uInstr0(cb, CALLM_S, 0);
11310//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_STC));
11311//-- uFlagsRWU(cb, FlagsEmpty, FlagC, FlagsOSZAP);
11312//-- uInstr0(cb, CALLM_E, 0);
11313//-- DIP("stc\n");
11314//-- break;
11315//--
11316//-- case 0xF5: /* CMC */
11317//-- uInstr0(cb, CALLM_S, 0);
11318//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_CMC));
11319//-- uFlagsRWU(cb, FlagC, FlagC, FlagsOSZAP);
11320//-- uInstr0(cb, CALLM_E, 0);
11321//-- DIP("cmc\n");
11322//-- break;
sewardj82292882004-07-27 00:15:59 +000011323
11324 /* REPNE prefix insn */
11325 case 0xF2: {
sewardjce70a5c2004-10-18 14:09:54 +000011326 Addr32 eip_orig = guest_eip_bbstart + delta - 1;
sewardj82292882004-07-27 00:15:59 +000011327 vassert(sorb == 0);
11328 abyte = getIByte(delta); delta++;
11329
11330 if (abyte == 0x66) { sz = 2; abyte = getIByte(delta); delta++; }
sewardjce70a5c2004-10-18 14:09:54 +000011331 whatNext = Dis_StopHere;
sewardj82292882004-07-27 00:15:59 +000011332
11333 switch (abyte) {
11334 /* According to the Intel manual, "repne movs" should never occur, but
11335 * in practice it has happened, so allow for it here... */
sewardj180e8b32004-07-29 01:40:11 +000011336 case 0xA4: sz = 1; /* REPNE MOVS<sz> */
sewardjb64821b2004-12-14 10:00:16 +000011337 goto decode_failure;
sewardjc9a65702004-07-07 16:32:57 +000011338//-- case 0xA5:
sewardj5bd4d162004-11-10 13:02:48 +000011339 // dis_REP_op ( CondNZ, dis_MOVS, sz, eip_orig,
11340 // guest_eip_bbstart+delta, "repne movs" );
11341 // break;
sewardjc9a65702004-07-07 16:32:57 +000011342//--
11343//-- case 0xA6: sz = 1; /* REPNE CMPS<sz> */
11344//-- case 0xA7:
11345//-- dis_REP_op ( cb, CondNZ, dis_CMPS, sz, eip_orig, eip, "repne cmps" );
11346//-- break;
11347//--
sewardj82292882004-07-27 00:15:59 +000011348 case 0xAE: sz = 1; /* REPNE SCAS<sz> */
sewardj2d4c3a02004-10-15 00:03:23 +000011349 case 0xAF:
sewardj2a9ad022004-11-25 02:46:58 +000011350 dis_REP_op ( X86CondNZ, dis_SCAS, sz, eip_orig,
11351 guest_eip_bbstart+delta, "repne scas" );
sewardj82292882004-07-27 00:15:59 +000011352 break;
11353
11354 default:
11355 goto decode_failure;
11356 }
11357 break;
11358 }
sewardj64e1d652004-07-12 14:00:46 +000011359
11360 /* REP/REPE prefix insn (for SCAS and CMPS, 0xF3 means REPE,
11361 for the rest, it means REP) */
11362 case 0xF3: {
sewardjce70a5c2004-10-18 14:09:54 +000011363 Addr32 eip_orig = guest_eip_bbstart + delta - 1;
sewardj64e1d652004-07-12 14:00:46 +000011364 vassert(sorb == 0);
11365 abyte = getIByte(delta); delta++;
11366
11367 if (abyte == 0x66) { sz = 2; abyte = getIByte(delta); delta++; }
sewardjce70a5c2004-10-18 14:09:54 +000011368 whatNext = Dis_StopHere;
sewardj64e1d652004-07-12 14:00:46 +000011369
11370 switch (abyte) {
11371 case 0xA4: sz = 1; /* REP MOVS<sz> */
11372 case 0xA5:
sewardj2a9ad022004-11-25 02:46:58 +000011373 dis_REP_op ( X86CondAlways, dis_MOVS, sz, eip_orig,
11374 guest_eip_bbstart+delta, "rep movs" );
sewardj64e1d652004-07-12 14:00:46 +000011375 break;
11376
11377 case 0xA6: sz = 1; /* REPE CMP<sz> */
sewardj2d4c3a02004-10-15 00:03:23 +000011378 case 0xA7:
sewardj2a9ad022004-11-25 02:46:58 +000011379 dis_REP_op ( X86CondZ, dis_CMPS, sz, eip_orig,
11380 guest_eip_bbstart+delta, "repe cmps" );
sewardj64e1d652004-07-12 14:00:46 +000011381 break;
11382
11383 case 0xAA: sz = 1; /* REP STOS<sz> */
11384 case 0xAB:
sewardj2a9ad022004-11-25 02:46:58 +000011385 dis_REP_op ( X86CondAlways, dis_STOS, sz, eip_orig,
11386 guest_eip_bbstart+delta, "rep stos" );
sewardj64e1d652004-07-12 14:00:46 +000011387 break;
sewardjc9a65702004-07-07 16:32:57 +000011388//--
11389//-- case 0xAE: sz = 1; /* REPE SCAS<sz> */
11390//-- case 0xAF:
11391//-- dis_REP_op ( cb, CondZ, dis_SCAS, sz, eip_orig, eip, "repe scas" );
11392//-- break;
sewardj43b8df12004-11-26 12:18:51 +000011393
11394 case 0x90: /* REP NOP (PAUSE) */
11395 /* a hint to the P4 re spin-wait loop */
11396 DIP("rep nop (P4 pause)\n");
sewardj7ec59f62005-03-12 16:47:18 +000011397 /* "observe" the hint. The Vex client needs to be careful not
11398 to cause very long delays as a result, though. */
sewardj43b8df12004-11-26 12:18:51 +000011399 jmp_lit(Ijk_Yield, ((Addr32)guest_eip_bbstart)+delta);
11400 whatNext = Dis_StopHere;
11401 break;
11402
sewardjc9a65702004-07-07 16:32:57 +000011403//-- case 0xC3: /* REP RET */
11404//-- /* AMD K7/K8-specific optimisation; faster than vanilla RET */
11405//-- dis_ret(cb, 0);
11406//-- DIP("rep ret\n");
11407//-- break;
sewardj64e1d652004-07-12 14:00:46 +000011408
11409 default:
11410 goto decode_failure;
11411 }
11412 break;
11413 }
sewardj0611d802004-07-11 02:37:54 +000011414
11415 /* ------------------------ XCHG ----------------------- */
11416
11417 case 0x86: /* XCHG Gb,Eb */
11418 sz = 1;
11419 /* Fall through ... */
11420 case 0x87: /* XCHG Gv,Ev */
11421 modrm = getIByte(delta);
11422 ty = szToITy(sz);
11423 t1 = newTemp(ty); t2 = newTemp(ty);
11424 if (epartIsReg(modrm)) {
sewardj5bd4d162004-11-10 13:02:48 +000011425 assign(t1, getIReg(sz, eregOfRM(modrm)));
11426 assign(t2, getIReg(sz, gregOfRM(modrm)));
11427 putIReg(sz, gregOfRM(modrm), mkexpr(t1));
11428 putIReg(sz, eregOfRM(modrm), mkexpr(t2));
sewardj0611d802004-07-11 02:37:54 +000011429 delta++;
11430 DIP("xchg%c %s, %s\n",
11431 nameISize(sz), nameIReg(sz,gregOfRM(modrm)),
11432 nameIReg(sz,eregOfRM(modrm)));
11433 } else {
sewardj0c12ea82004-07-12 08:18:16 +000011434 addr = disAMode ( &alen, sorb, delta, dis_buf );
sewardj5bd4d162004-11-10 13:02:48 +000011435 assign( t1, loadLE(ty,mkexpr(addr)) );
11436 assign( t2, getIReg(sz,gregOfRM(modrm)) );
11437 storeLE( mkexpr(addr), mkexpr(t2) );
11438 putIReg( sz, gregOfRM(modrm), mkexpr(t1) );
11439 delta += alen;
sewardj0611d802004-07-11 02:37:54 +000011440 DIP("xchg%c %s, %s\n", nameISize(sz),
11441 nameIReg(sz,gregOfRM(modrm)), dis_buf);
sewardj0611d802004-07-11 02:37:54 +000011442 }
11443 break;
sewardje87b4842004-07-10 12:23:30 +000011444
11445 case 0x90: /* XCHG eAX,eAX */
11446 DIP("nop\n");
11447 break;
sewardj64e1d652004-07-12 14:00:46 +000011448 case 0x91: /* XCHG eAX,eCX */
11449 case 0x92: /* XCHG eAX,eDX */
11450 case 0x93: /* XCHG eAX,eBX */
11451 case 0x94: /* XCHG eAX,eSP */
11452 case 0x95: /* XCHG eAX,eBP */
11453 case 0x96: /* XCHG eAX,eSI */
11454 case 0x97: /* XCHG eAX,eDI */
11455 codegen_xchg_eAX_Reg ( sz, opc - 0x90 );
11456 break;
11457
sewardjc9a65702004-07-07 16:32:57 +000011458//-- /* ------------------------ XLAT ----------------------- */
11459//--
11460//-- case 0xD7: /* XLAT */
11461//-- t1 = newTemp(cb); t2 = newTemp(cb);
11462//-- uInstr2(cb, GET, sz, ArchReg, R_EBX, TempReg, t1); /* get eBX */
11463//-- handleSegOverride( cb, sorb, t1 ); /* make t1 DS:eBX */
11464//-- uInstr2(cb, GET, 1, ArchReg, R_AL, TempReg, t2); /* get AL */
11465//-- /* Widen %AL to 32 bits, so it's all defined when we add it. */
11466//-- uInstr1(cb, WIDEN, 4, TempReg, t2);
11467//-- uWiden(cb, 1, False);
11468//-- uInstr2(cb, ADD, sz, TempReg, t2, TempReg, t1); /* add AL to eBX */
11469//-- uInstr2(cb, LOAD, 1, TempReg, t1, TempReg, t2); /* get byte at t1 into t2 */
11470//-- uInstr2(cb, PUT, 1, TempReg, t2, ArchReg, R_AL); /* put byte into AL */
11471//--
11472//-- DIP("xlat%c [ebx]\n", nameISize(sz));
11473//-- break;
11474//--
11475//-- /* ------------------------ IN / OUT ----------------------- */
11476//--
11477//-- case 0xE4: /* IN ib, %al */
11478//-- case 0xE5: /* IN ib, %{e}ax */
11479//-- case 0xEC: /* IN (%dx),%al */
11480//-- case 0xED: /* IN (%dx),%{e}ax */
11481//-- t1 = newTemp(cb);
11482//-- t2 = newTemp(cb);
11483//-- t3 = newTemp(cb);
11484//--
11485//-- uInstr0(cb, CALLM_S, 0);
11486//-- /* operand size? */
11487//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t1);
11488//-- uLiteral(cb, ( opc == 0xE4 || opc == 0xEC ) ? 1 : sz);
11489//-- uInstr1(cb, PUSH, 4, TempReg, t1);
11490//-- /* port number ? */
11491//-- if ( opc == 0xE4 || opc == 0xE5 ) {
11492//-- abyte = getUChar(eip); eip++;
11493//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
11494//-- uLiteral(cb, abyte);
11495//-- }
11496//-- else
11497//-- uInstr2(cb, GET, 4, ArchReg, R_EDX, TempReg, t2);
11498//--
11499//-- uInstr1(cb, PUSH, 4, TempReg, t2);
11500//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_IN));
11501//-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
11502//-- uInstr1(cb, POP, 4, TempReg, t2);
11503//-- uInstr1(cb, CLEAR, 0, Lit16, 4);
11504//-- uInstr0(cb, CALLM_E, 0);
11505//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_EAX);
11506//-- if ( opc == 0xE4 || opc == 0xE5 ) {
11507//-- DIP("in 0x%x, %%eax/%%ax/%%al\n", getUChar(eip-1) );
11508//-- } else {
11509//-- DIP("in (%%dx), %%eax/%%ax/%%al\n");
11510//-- }
11511//-- break;
11512//-- case 0xE6: /* OUT %al,ib */
11513//-- case 0xE7: /* OUT %{e}ax,ib */
11514//-- case 0xEE: /* OUT %al,(%dx) */
11515//-- case 0xEF: /* OUT %{e}ax,(%dx) */
11516//-- t1 = newTemp(cb);
11517//-- t2 = newTemp(cb);
11518//-- t3 = newTemp(cb);
11519//--
11520//-- uInstr0(cb, CALLM_S, 0);
11521//-- /* operand size? */
11522//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t1);
11523//-- uLiteral(cb, ( opc == 0xE6 || opc == 0xEE ) ? 1 : sz);
11524//-- uInstr1(cb, PUSH, 4, TempReg, t1);
11525//-- /* port number ? */
11526//-- if ( opc == 0xE6 || opc == 0xE7 ) {
11527//-- abyte = getUChar(eip); eip++;
11528//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
11529//-- uLiteral(cb, abyte);
11530//-- }
11531//-- else
11532//-- uInstr2(cb, GET, 4, ArchReg, R_EDX, TempReg, t2);
11533//-- uInstr1(cb, PUSH, 4, TempReg, t2);
11534//-- uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, t3);
11535//-- uInstr1(cb, PUSH, 4, TempReg, t3);
11536//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_OUT));
11537//-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
11538//-- uInstr1(cb, CLEAR, 0, Lit16, 12);
11539//-- uInstr0(cb, CALLM_E, 0);
11540//-- if ( opc == 0xE4 || opc == 0xE5 ) {
11541//-- DIP("out %%eax/%%ax/%%al, 0x%x\n", getUChar(eip-1) );
11542//-- } else {
11543//-- DIP("out %%eax/%%ax/%%al, (%%dx)\n");
11544//-- }
11545//-- break;
sewardj0611d802004-07-11 02:37:54 +000011546
11547 /* ------------------------ (Grp1 extensions) ---------- */
11548
11549 case 0x80: /* Grp1 Ib,Eb */
11550 modrm = getIByte(delta);
11551 am_sz = lengthAMode(delta);
11552 sz = 1;
11553 d_sz = 1;
sewardjc2ac51e2004-07-12 01:03:26 +000011554 d32 = getUChar(delta + am_sz);
sewardj0611d802004-07-11 02:37:54 +000011555 delta = dis_Grp1 ( sorb, delta, modrm, am_sz, d_sz, sz, d32 );
11556 break;
sewardje05c42c2004-07-08 20:25:10 +000011557
11558 case 0x81: /* Grp1 Iv,Ev */
11559 modrm = getIByte(delta);
11560 am_sz = lengthAMode(delta);
11561 d_sz = sz;
11562 d32 = getUDisp(d_sz, delta + am_sz);
11563 delta = dis_Grp1 ( sorb, delta, modrm, am_sz, d_sz, sz, d32 );
11564 break;
sewardjd1061ab2004-07-08 01:45:30 +000011565
11566 case 0x83: /* Grp1 Ib,Ev */
11567 modrm = getIByte(delta);
11568 am_sz = lengthAMode(delta);
11569 d_sz = 1;
11570 d32 = getSDisp8(delta + am_sz);
11571 delta = dis_Grp1 ( sorb, delta, modrm, am_sz, d_sz, sz, d32 );
11572 break;
11573
sewardjc2ac51e2004-07-12 01:03:26 +000011574 /* ------------------------ (Grp2 extensions) ---------- */
11575
11576 case 0xC0: /* Grp2 Ib,Eb */
11577 modrm = getIByte(delta);
11578 am_sz = lengthAMode(delta);
11579 d_sz = 1;
sewardj180e8b32004-07-29 01:40:11 +000011580 d32 = getUChar(delta + am_sz);
sewardjc2ac51e2004-07-12 01:03:26 +000011581 sz = 1;
sewardj6d2638e2004-07-15 09:38:27 +000011582 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
11583 mkU8(d32 & 0xFF), NULL );
sewardjc2ac51e2004-07-12 01:03:26 +000011584 break;
sewardje90ad6a2004-07-10 19:02:10 +000011585
11586 case 0xC1: /* Grp2 Ib,Ev */
sewardjc2ac51e2004-07-12 01:03:26 +000011587 modrm = getIByte(delta);
sewardje90ad6a2004-07-10 19:02:10 +000011588 am_sz = lengthAMode(delta);
11589 d_sz = 1;
sewardj180e8b32004-07-29 01:40:11 +000011590 d32 = getUChar(delta + am_sz);
sewardj6d2638e2004-07-15 09:38:27 +000011591 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
11592 mkU8(d32 & 0xFF), NULL );
sewardje90ad6a2004-07-10 19:02:10 +000011593 break;
11594
sewardj180e8b32004-07-29 01:40:11 +000011595 case 0xD0: /* Grp2 1,Eb */
11596 modrm = getIByte(delta);
11597 am_sz = lengthAMode(delta);
11598 d_sz = 0;
11599 d32 = 1;
11600 sz = 1;
11601 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
11602 mkU8(d32), NULL );
11603 break;
sewardjc2ac51e2004-07-12 01:03:26 +000011604
11605 case 0xD1: /* Grp2 1,Ev */
11606 modrm = getUChar(delta);
11607 am_sz = lengthAMode(delta);
11608 d_sz = 0;
11609 d32 = 1;
sewardj6d2638e2004-07-15 09:38:27 +000011610 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
11611 mkU8(d32), NULL );
sewardjc2ac51e2004-07-12 01:03:26 +000011612 break;
11613
sewardj8c7f1ab2004-07-29 20:31:09 +000011614 case 0xD2: /* Grp2 CL,Eb */
11615 modrm = getUChar(delta);
11616 am_sz = lengthAMode(delta);
11617 d_sz = 0;
11618 sz = 1;
11619 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
11620 getIReg(1,R_ECX), "%cl" );
11621 break;
sewardj9334b0f2004-07-10 22:43:54 +000011622
11623 case 0xD3: /* Grp2 CL,Ev */
11624 modrm = getIByte(delta);
11625 am_sz = lengthAMode(delta);
11626 d_sz = 0;
11627 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
sewardj6d2638e2004-07-15 09:38:27 +000011628 getIReg(1,R_ECX), "%cl" );
sewardj9334b0f2004-07-10 22:43:54 +000011629 break;
11630
sewardj940e8c92004-07-11 16:53:24 +000011631 /* ------------------------ (Grp3 extensions) ---------- */
11632
11633 case 0xF6: /* Grp3 Eb */
11634 delta = dis_Grp3 ( sorb, 1, delta );
11635 break;
11636 case 0xF7: /* Grp3 Ev */
11637 delta = dis_Grp3 ( sorb, sz, delta );
11638 break;
11639
sewardjc2ac51e2004-07-12 01:03:26 +000011640 /* ------------------------ (Grp4 extensions) ---------- */
11641
11642 case 0xFE: /* Grp4 Eb */
11643 delta = dis_Grp4 ( sorb, delta );
11644 break;
sewardj0611d802004-07-11 02:37:54 +000011645
11646 /* ------------------------ (Grp5 extensions) ---------- */
11647
11648 case 0xFF: /* Grp5 Ev */
sewardjce70a5c2004-10-18 14:09:54 +000011649 delta = dis_Grp5 ( sorb, sz, delta, &whatNext );
sewardj0611d802004-07-11 02:37:54 +000011650 break;
sewardje87b4842004-07-10 12:23:30 +000011651
11652 /* ------------------------ Escapes to 2-byte opcodes -- */
11653
11654 case 0x0F: {
11655 opc = getIByte(delta); delta++;
11656 switch (opc) {
11657
sewardj490ad382005-03-13 17:25:53 +000011658 /* =-=-=-=-=-=-=-=-=- Grp8 =-=-=-=-=-=-=-=-=-=-=-= */
11659
11660 case 0xBA: { /* Grp8 Ib,Ev */
11661 Bool decode_OK = False;
11662 modrm = getUChar(delta);
11663 am_sz = lengthAMode(delta);
11664 d32 = getSDisp8(delta + am_sz);
11665 delta = dis_Grp8_Imm ( sorb, delta, modrm, am_sz, sz, d32,
11666 &decode_OK );
11667 if (!decode_OK)
11668 goto decode_failure;
11669 break;
11670 }
sewardjce646f22004-08-31 23:55:54 +000011671
11672 /* =-=-=-=-=-=-=-=-=- BSF/BSR -=-=-=-=-=-=-=-=-=-= */
11673
11674 case 0xBC: /* BSF Gv,Ev */
11675 delta = dis_bs_E_G ( sorb, sz, delta, True );
11676 break;
11677 case 0xBD: /* BSR Gv,Ev */
11678 delta = dis_bs_E_G ( sorb, sz, delta, False );
11679 break;
sewardj1c4208f2004-08-25 13:25:29 +000011680
11681 /* =-=-=-=-=-=-=-=-=- BSWAP -=-=-=-=-=-=-=-=-=-=-= */
11682
11683 case 0xC8: /* BSWAP %eax */
11684 case 0xC9:
11685 case 0xCA:
sewardjb4666cf2004-10-23 00:21:50 +000011686 case 0xCB:
11687 case 0xCC:
11688 case 0xCD:
sewardj1c4208f2004-08-25 13:25:29 +000011689 case 0xCE:
sewardj1c6f9912004-09-07 10:15:24 +000011690 case 0xCF: /* BSWAP %edi */
sewardj1c4208f2004-08-25 13:25:29 +000011691 /* AFAICS from the Intel docs, this only exists at size 4. */
11692 vassert(sz == 4);
11693 t1 = newTemp(Ity_I32);
11694 t2 = newTemp(Ity_I32);
11695 assign( t1, getIReg(4, opc-0xC8) );
11696
11697 assign( t2,
11698 binop(Iop_Or32,
11699 binop(Iop_Shl32, mkexpr(t1), mkU8(24)),
11700 binop(Iop_Or32,
11701 binop(Iop_And32, binop(Iop_Shl32, mkexpr(t1), mkU8(8)),
11702 mkU32(0x00FF0000)),
11703 binop(Iop_Or32,
11704 binop(Iop_And32, binop(Iop_Shr32, mkexpr(t1), mkU8(8)),
11705 mkU32(0x0000FF00)),
11706 binop(Iop_And32, binop(Iop_Shr32, mkexpr(t1), mkU8(24)),
11707 mkU32(0x000000FF) )
11708 )))
11709 );
11710
11711 putIReg(4, opc-0xC8, mkexpr(t2));
sewardj1c4208f2004-08-25 13:25:29 +000011712 DIP("bswapl %s\n", nameIReg(4, opc-0xC8));
11713 break;
11714
sewardj1c6f9912004-09-07 10:15:24 +000011715 /* =-=-=-=-=-=-=-=-=- BT/BTS/BTR/BTC =-=-=-=-=-=-= */
11716
11717 case 0xA3: /* BT Gv,Ev */
11718 delta = dis_bt_G_E ( sorb, sz, delta, BtOpNone );
11719 break;
sewardje6709112004-09-10 18:37:18 +000011720 case 0xB3: /* BTR Gv,Ev */
11721 delta = dis_bt_G_E ( sorb, sz, delta, BtOpReset );
11722 break;
sewardj1c6f9912004-09-07 10:15:24 +000011723 case 0xAB: /* BTS Gv,Ev */
11724 delta = dis_bt_G_E ( sorb, sz, delta, BtOpSet );
11725 break;
sewardj4963a422004-10-14 23:34:03 +000011726 case 0xBB: /* BTC Gv,Ev */
11727 delta = dis_bt_G_E ( sorb, sz, delta, BtOpComp );
11728 break;
sewardj458a6f82004-08-25 12:46:02 +000011729
11730 /* =-=-=-=-=-=-=-=-=- CMOV =-=-=-=-=-=-=-=-=-=-=-= */
11731
sewardj2d4c3a02004-10-15 00:03:23 +000011732 case 0x40:
11733 case 0x41:
sewardj458a6f82004-08-25 12:46:02 +000011734 case 0x42: /* CMOVBb/CMOVNAEb (cmov below) */
11735 case 0x43: /* CMOVNBb/CMOVAEb (cmov not below) */
11736 case 0x44: /* CMOVZb/CMOVEb (cmov zero) */
11737 case 0x45: /* CMOVNZb/CMOVNEb (cmov not zero) */
11738 case 0x46: /* CMOVBEb/CMOVNAb (cmov below or equal) */
11739 case 0x47: /* CMOVNBEb/CMOVAb (cmov not below or equal) */
sewardjce646f22004-08-31 23:55:54 +000011740 case 0x48: /* CMOVSb (cmov negative) */
sewardj458a6f82004-08-25 12:46:02 +000011741 case 0x49: /* CMOVSb (cmov not negative) */
sewardj2d4c3a02004-10-15 00:03:23 +000011742 case 0x4A: /* CMOVP (cmov parity even) */
11743 case 0x4B: /* CMOVNP (cmov parity odd) */
sewardj458a6f82004-08-25 12:46:02 +000011744 case 0x4C: /* CMOVLb/CMOVNGEb (cmov less) */
11745 case 0x4D: /* CMOVGEb/CMOVNLb (cmov greater or equal) */
11746 case 0x4E: /* CMOVLEb/CMOVNGb (cmov less or equal) */
11747 case 0x4F: /* CMOVGb/CMOVNLEb (cmov greater) */
sewardj2a9ad022004-11-25 02:46:58 +000011748 delta = dis_cmov_E_G(sorb, sz, (X86Condcode)(opc - 0x40), delta);
sewardj458a6f82004-08-25 12:46:02 +000011749 break;
11750
11751 /* =-=-=-=-=-=-=-=-=- CMPXCHG -=-=-=-=-=-=-=-=-=-= */
11752
sewardjc744e872004-08-26 11:24:39 +000011753 case 0xB0: /* CMPXCHG Gb,Eb */
11754 delta = dis_cmpxchg_G_E ( sorb, 1, delta );
11755 break;
sewardj458a6f82004-08-25 12:46:02 +000011756 case 0xB1: /* CMPXCHG Gv,Ev */
11757 delta = dis_cmpxchg_G_E ( sorb, sz, delta );
11758 break;
sewardjc9a65702004-07-07 16:32:57 +000011759//-- case 0xC7: /* CMPXCHG8B Gv */
11760//-- eip = dis_cmpxchg8b ( cb, sorb, eip );
11761//-- break;
11762//--
sewardj588ea762004-09-10 18:56:32 +000011763 /* =-=-=-=-=-=-=-=-=- CPUID -=-=-=-=-=-=-=-=-=-=-= */
11764
sewardj7cb49d72004-10-24 22:31:25 +000011765 case 0xA2: { /* CPUID */
11766 /* Uses dirty helper:
sewardj9df271d2004-12-31 22:37:42 +000011767 void dirtyhelper_CPUID_sse[012] ( VexGuestX86State* )
sewardj7cb49d72004-10-24 22:31:25 +000011768 declared to mod eax, wr ebx, ecx, edx
11769 */
sewardj9df271d2004-12-31 22:37:42 +000011770 IRDirty* d = NULL;
11771 HChar* fName = NULL;
11772 void* fAddr = NULL;
11773 switch (subarch) {
11774 case VexSubArchX86_sse0:
11775 fName = "x86g_dirtyhelper_CPUID_sse0";
11776 fAddr = &x86g_dirtyhelper_CPUID_sse0;
11777 break;
11778 case VexSubArchX86_sse1:
11779 fName = "x86g_dirtyhelper_CPUID_sse1";
11780 fAddr = &x86g_dirtyhelper_CPUID_sse1;
11781 break;
11782 case VexSubArchX86_sse2:
11783 fName = "x86g_dirtyhelper_CPUID_sse2";
11784 fAddr = &x86g_dirtyhelper_CPUID_sse2;
11785 break;
11786 default:
11787 vpanic("disInstr(x86)(cpuid)");
11788 }
11789 vassert(fName); vassert(fAddr);
11790 d = unsafeIRDirty_0_N ( 0/*regparms*/,
11791 fName, fAddr, mkIRExprVec_0() );
sewardj7cb49d72004-10-24 22:31:25 +000011792 /* declare guest state effects */
sewardjc5fc7aa2004-10-27 23:00:55 +000011793 d->needsBBP = True;
sewardj7cb49d72004-10-24 22:31:25 +000011794 d->nFxState = 4;
11795 d->fxState[0].fx = Ifx_Modify;
11796 d->fxState[0].offset = OFFB_EAX;
11797 d->fxState[0].size = 4;
11798 d->fxState[1].fx = Ifx_Write;
11799 d->fxState[1].offset = OFFB_EBX;
11800 d->fxState[1].size = 4;
11801 d->fxState[2].fx = Ifx_Write;
11802 d->fxState[2].offset = OFFB_ECX;
11803 d->fxState[2].size = 4;
11804 d->fxState[3].fx = Ifx_Write;
11805 d->fxState[3].offset = OFFB_EDX;
11806 d->fxState[3].size = 4;
11807 /* execute the dirty call, side-effecting guest state */
11808 stmt( IRStmt_Dirty(d) );
sewardj55860d82005-01-08 18:25:05 +000011809 /* CPUID is a serialising insn. So, just in case someone is
11810 using it as a memory fence ... */
11811 stmt( IRStmt_MFence() );
sewardj517a7d62004-10-25 09:52:18 +000011812 DIP("cpuid\n");
sewardj588ea762004-09-10 18:56:32 +000011813 break;
sewardj7cb49d72004-10-24 22:31:25 +000011814 }
11815
sewardj5bd4d162004-11-10 13:02:48 +000011816//-- if (!VG_(cpu_has_feature)(VG_X86_FEAT_CPUID))
11817//-- goto decode_failure;
sewardjc9a65702004-07-07 16:32:57 +000011818//--
11819//-- t1 = newTemp(cb);
11820//-- t2 = newTemp(cb);
11821//-- t3 = newTemp(cb);
11822//-- t4 = newTemp(cb);
11823//-- uInstr0(cb, CALLM_S, 0);
11824//--
11825//-- uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, t1);
11826//-- uInstr1(cb, PUSH, 4, TempReg, t1);
11827//--
11828//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
11829//-- uLiteral(cb, 0);
11830//-- uInstr1(cb, PUSH, 4, TempReg, t2);
11831//--
11832//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t3);
11833//-- uLiteral(cb, 0);
11834//-- uInstr1(cb, PUSH, 4, TempReg, t3);
11835//--
11836//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t4);
11837//-- uLiteral(cb, 0);
11838//-- uInstr1(cb, PUSH, 4, TempReg, t4);
11839//--
11840//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_CPUID));
11841//-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
11842//--
11843//-- uInstr1(cb, POP, 4, TempReg, t4);
11844//-- uInstr2(cb, PUT, 4, TempReg, t4, ArchReg, R_EDX);
11845//--
11846//-- uInstr1(cb, POP, 4, TempReg, t3);
11847//-- uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_ECX);
11848//--
11849//-- uInstr1(cb, POP, 4, TempReg, t2);
11850//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_EBX);
11851//--
11852//-- uInstr1(cb, POP, 4, TempReg, t1);
11853//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_EAX);
11854//--
11855//-- uInstr0(cb, CALLM_E, 0);
11856//-- DIP("cpuid\n");
11857//-- break;
11858//--
sewardj9334b0f2004-07-10 22:43:54 +000011859 /* =-=-=-=-=-=-=-=-=- MOVZX, MOVSX =-=-=-=-=-=-=-= */
11860
11861 case 0xB6: /* MOVZXb Eb,Gv */
11862 delta = dis_movx_E_G ( sorb, delta, 1, 4, False );
11863 break;
sewardj940e8c92004-07-11 16:53:24 +000011864 case 0xB7: /* MOVZXw Ew,Gv */
11865 delta = dis_movx_E_G ( sorb, delta, 2, 4, False );
11866 break;
11867
sewardj0611d802004-07-11 02:37:54 +000011868 case 0xBE: /* MOVSXb Eb,Gv */
11869 delta = dis_movx_E_G ( sorb, delta, 1, 4, True );
11870 break;
sewardj7ed22952004-07-29 00:09:58 +000011871 case 0xBF: /* MOVSXw Ew,Gv */
11872 delta = dis_movx_E_G ( sorb, delta, 2, 4, True );
11873 break;
11874
sewardjc9a65702004-07-07 16:32:57 +000011875//-- /* =-=-=-=-=-=-=-=-=-=-= MOVNTI -=-=-=-=-=-=-=-=-= */
11876//--
11877//-- case 0xC3: /* MOVNTI Gv,Ev */
11878//-- vg_assert(sz == 4);
11879//-- modrm = getUChar(eip);
11880//-- vg_assert(!epartIsReg(modrm));
11881//-- t1 = newTemp(cb);
11882//-- uInstr2(cb, GET, 4, ArchReg, gregOfRM(modrm), TempReg, t1);
11883//-- pair = disAMode ( cb, sorb, eip, dis_buf );
11884//-- t2 = LOW24(pair);
11885//-- eip += HI8(pair);
11886//-- uInstr2(cb, STORE, 4, TempReg, t1, TempReg, t2);
11887//-- DIP("movnti %s,%s\n", nameIReg(4,gregOfRM(modrm)), dis_buf);
11888//-- break;
sewardjcf780b42004-07-13 18:42:17 +000011889
11890 /* =-=-=-=-=-=-=-=-=- MUL/IMUL =-=-=-=-=-=-=-=-=-= */
11891
11892 case 0xAF: /* IMUL Ev, Gv */
sewardj2a2ba8b2004-11-08 13:14:06 +000011893 delta = dis_mul_E_G ( sorb, sz, delta );
sewardjcf780b42004-07-13 18:42:17 +000011894 break;
sewardje87b4842004-07-10 12:23:30 +000011895
11896 /* =-=-=-=-=-=-=-=-=- Jcond d32 -=-=-=-=-=-=-=-=-= */
11897 case 0x80:
11898 case 0x81:
11899 case 0x82: /* JBb/JNAEb (jump below) */
11900 case 0x83: /* JNBb/JAEb (jump not below) */
11901 case 0x84: /* JZb/JEb (jump zero) */
11902 case 0x85: /* JNZb/JNEb (jump not zero) */
11903 case 0x86: /* JBEb/JNAb (jump below or equal) */
11904 case 0x87: /* JNBEb/JAb (jump not below or equal) */
11905 case 0x88: /* JSb (jump negative) */
11906 case 0x89: /* JSb (jump not negative) */
11907 case 0x8A: /* JP (jump parity even) */
11908 case 0x8B: /* JNP/JPO (jump parity odd) */
11909 case 0x8C: /* JLb/JNGEb (jump less) */
11910 case 0x8D: /* JGEb/JNLb (jump greater or equal) */
11911 case 0x8E: /* JLEb/JNGb (jump less or equal) */
11912 case 0x8F: /* JGb/JNLEb (jump greater) */
sewardj4fd30f22004-10-25 00:42:16 +000011913 d32 = (((Addr32)guest_eip_bbstart)+delta+4) + getUDisp32(delta);
sewardje87b4842004-07-10 12:23:30 +000011914 delta += 4;
sewardj2a9ad022004-11-25 02:46:58 +000011915 jcc_01( (X86Condcode)(opc - 0x80),
11916 (Addr32)(guest_eip_bbstart+delta),
11917 d32 );
sewardjce70a5c2004-10-18 14:09:54 +000011918 whatNext = Dis_StopHere;
sewardj2a9ad022004-11-25 02:46:58 +000011919 DIP("j%s-32 0x%x\n", name_X86Condcode(opc - 0x80), d32);
sewardje87b4842004-07-10 12:23:30 +000011920 break;
11921
sewardj89cd0932004-09-08 18:23:25 +000011922 /* =-=-=-=-=-=-=-=-=- RDTSC -=-=-=-=-=-=-=-=-=-=-= */
11923
11924 case 0x31: /* RDTSC */
sewardjcb2c99d2004-12-17 19:14:24 +000011925 if (0) vex_printf("vex x86->IR: kludged rdtsc\n");
sewardj83301962005-03-23 11:35:55 +000011926 putIReg(4, R_EAX, mkU32(1));
sewardj89cd0932004-09-08 18:23:25 +000011927 putIReg(4, R_EDX, mkU32(0));
11928
sewardjc9a65702004-07-07 16:32:57 +000011929//-- t1 = newTemp(cb);
11930//-- t2 = newTemp(cb);
11931//-- t3 = newTemp(cb);
11932//-- uInstr0(cb, CALLM_S, 0);
11933//-- // Nb: even though these args aren't used by RDTSC_helper, need
11934//-- // them to be defined (for Memcheck). The TempRegs pushed must
11935//-- // also be distinct.
11936//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t1);
11937//-- uLiteral(cb, 0);
11938//-- uInstr1(cb, PUSH, 4, TempReg, t1);
11939//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
11940//-- uLiteral(cb, 0);
11941//-- uInstr1(cb, PUSH, 4, TempReg, t2);
11942//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_RDTSC));
11943//-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
11944//-- uInstr1(cb, POP, 4, TempReg, t3);
11945//-- uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_EDX);
11946//-- uInstr1(cb, POP, 4, TempReg, t3);
11947//-- uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_EAX);
11948//-- uInstr0(cb, CALLM_E, 0);
sewardj89cd0932004-09-08 18:23:25 +000011949 DIP("rdtsc\n");
11950 break;
sewardj77b86be2004-07-11 13:28:24 +000011951
sewardjb64821b2004-12-14 10:00:16 +000011952 /* =-=-=-=-=-=-=-=-=- PUSH/POP Sreg =-=-=-=-=-=-=-=-=-= */
11953
11954 case 0xA1: /* POP %FS */
11955 dis_pop_segreg( R_FS, sz ); break;
11956 case 0xA9: /* POP %GS */
11957 dis_pop_segreg( R_GS, sz ); break;
11958
11959 case 0xA0: /* PUSH %FS */
11960 dis_push_segreg( R_FS, sz ); break;
11961 case 0xA8: /* PUSH %GS */
11962 dis_push_segreg( R_GS, sz ); break;
11963
sewardj77b86be2004-07-11 13:28:24 +000011964 /* =-=-=-=-=-=-=-=-=- SETcc Eb =-=-=-=-=-=-=-=-=-= */
11965 case 0x90:
11966 case 0x91:
11967 case 0x92: /* set-Bb/set-NAEb (jump below) */
11968 case 0x93: /* set-NBb/set-AEb (jump not below) */
11969 case 0x94: /* set-Zb/set-Eb (jump zero) */
11970 case 0x95: /* set-NZb/set-NEb (jump not zero) */
11971 case 0x96: /* set-BEb/set-NAb (jump below or equal) */
11972 case 0x97: /* set-NBEb/set-Ab (jump not below or equal) */
11973 case 0x98: /* set-Sb (jump negative) */
11974 case 0x99: /* set-Sb (jump not negative) */
11975 case 0x9A: /* set-P (jump parity even) */
11976 case 0x9B: /* set-NP (jump parity odd) */
11977 case 0x9C: /* set-Lb/set-NGEb (jump less) */
11978 case 0x9D: /* set-GEb/set-NLb (jump greater or equal) */
11979 case 0x9E: /* set-LEb/set-NGb (jump less or equal) */
11980 case 0x9F: /* set-Gb/set-NLEb (jump greater) */
sewardj5bd4d162004-11-10 13:02:48 +000011981 t1 = newTemp(Ity_I8);
sewardj2a9ad022004-11-25 02:46:58 +000011982 assign( t1, unop(Iop_1Uto8,mk_x86g_calculate_condition(opc-0x90)) );
sewardj77b86be2004-07-11 13:28:24 +000011983 modrm = getIByte(delta);
11984 if (epartIsReg(modrm)) {
11985 delta++;
sewardj5bd4d162004-11-10 13:02:48 +000011986 putIReg(1, eregOfRM(modrm), mkexpr(t1));
sewardj2a9ad022004-11-25 02:46:58 +000011987 DIP("set%s %s\n", name_X86Condcode(opc-0x90),
sewardj77b86be2004-07-11 13:28:24 +000011988 nameIReg(1,eregOfRM(modrm)));
11989 } else {
sewardj750f4072004-07-26 22:39:11 +000011990 addr = disAMode ( &alen, sorb, delta, dis_buf );
11991 delta += alen;
11992 storeLE( mkexpr(addr), mkexpr(t1) );
sewardj2a9ad022004-11-25 02:46:58 +000011993 DIP("set%s %s\n", name_X86Condcode(opc-0x90), dis_buf);
sewardj77b86be2004-07-11 13:28:24 +000011994 }
11995 break;
11996
sewardj180e8b32004-07-29 01:40:11 +000011997 /* =-=-=-=-=-=-=-=-=- SHLD/SHRD -=-=-=-=-=-=-=-=-= */
11998
11999 case 0xA4: /* SHLDv imm8,Gv,Ev */
12000 modrm = getIByte(delta);
12001 d32 = delta + lengthAMode(delta);
sewardj2d49b432005-02-01 00:37:06 +000012002 vex_sprintf(dis_buf, "$%d", getIByte(d32));
sewardj180e8b32004-07-29 01:40:11 +000012003 delta = dis_SHLRD_Gv_Ev (
12004 sorb, delta, modrm, sz,
12005 mkU8(getIByte(d32)), True, /* literal */
12006 dis_buf, True );
12007 break;
sewardja06e5562004-07-14 13:18:05 +000012008 case 0xA5: /* SHLDv %cl,Gv,Ev */
12009 modrm = getIByte(delta);
12010 delta = dis_SHLRD_Gv_Ev (
12011 sorb, delta, modrm, sz,
12012 getIReg(1,R_ECX), False, /* not literal */
12013 "%cl", True );
12014 break;
12015
sewardj68511542004-07-28 00:15:44 +000012016 case 0xAC: /* SHRDv imm8,Gv,Ev */
12017 modrm = getIByte(delta);
12018 d32 = delta + lengthAMode(delta);
sewardj2d49b432005-02-01 00:37:06 +000012019 vex_sprintf(dis_buf, "$%d", getIByte(d32));
sewardj68511542004-07-28 00:15:44 +000012020 delta = dis_SHLRD_Gv_Ev (
12021 sorb, delta, modrm, sz,
12022 mkU8(getIByte(d32)), True, /* literal */
12023 dis_buf, False );
12024 break;
sewardja511afc2004-07-29 22:26:03 +000012025 case 0xAD: /* SHRDv %cl,Gv,Ev */
12026 modrm = getIByte(delta);
12027 delta = dis_SHLRD_Gv_Ev (
12028 sorb, delta, modrm, sz,
12029 getIReg(1,R_ECX), False, /* not literal */
12030 "%cl", False );
12031 break;
12032
sewardj464efa42004-11-19 22:17:29 +000012033 /* =-=-=-=-=-=-=-=-=- XADD -=-=-=-=-=-=-=-=-=-= */
12034
sewardjc9a65702004-07-07 16:32:57 +000012035//-- case 0xC0: /* XADD Gb,Eb */
12036//-- eip = dis_xadd_G_E ( cb, sorb, 1, eip );
12037//-- break;
sewardj883b00b2004-09-11 09:30:24 +000012038 case 0xC1: /* XADD Gv,Ev */
12039 delta = dis_xadd_G_E ( sorb, sz, delta );
12040 break;
12041
sewardjf13f37b2004-12-08 17:01:23 +000012042 /* =-=-=-=-=-=-=-=-=- MMXery =-=-=-=-=-=-=-=-=-=-= */
sewardj464efa42004-11-19 22:17:29 +000012043
sewardj2b7a9202004-11-26 19:15:38 +000012044 case 0x71:
12045 case 0x72:
sewardj38a3f862005-01-13 15:06:51 +000012046 case 0x73: /* PSLLgg/PSRAgg/PSRLgg mmxreg by imm8 */
sewardj2b7a9202004-11-26 19:15:38 +000012047
12048 case 0x6E: /* MOVD (src)ireg-or-mem, (dst)mmxreg */
12049 case 0x7E: /* MOVD (src)mmxreg, (dst)ireg-or-mem */
sewardj464efa42004-11-19 22:17:29 +000012050 case 0x7F: /* MOVQ (src)mmxreg, (dst)mmxreg-or-mem */
sewardj2b7a9202004-11-26 19:15:38 +000012051 case 0x6F: /* MOVQ (src)mmxreg-or-mem, (dst)mmxreg */
sewardj464efa42004-11-19 22:17:29 +000012052
12053 case 0xFC:
12054 case 0xFD:
12055 case 0xFE: /* PADDgg (src)mmxreg-or-mem, (dst)mmxreg */
12056
12057 case 0xEC:
12058 case 0xED: /* PADDSgg (src)mmxreg-or-mem, (dst)mmxreg */
12059
12060 case 0xDC:
12061 case 0xDD: /* PADDUSgg (src)mmxreg-or-mem, (dst)mmxreg */
12062
12063 case 0xF8:
12064 case 0xF9:
12065 case 0xFA: /* PSUBgg (src)mmxreg-or-mem, (dst)mmxreg */
12066
12067 case 0xE8:
12068 case 0xE9: /* PSUBSgg (src)mmxreg-or-mem, (dst)mmxreg */
12069
12070 case 0xD8:
12071 case 0xD9: /* PSUBUSgg (src)mmxreg-or-mem, (dst)mmxreg */
12072
12073 case 0xE5: /* PMULHW (src)mmxreg-or-mem, (dst)mmxreg */
12074 case 0xD5: /* PMULLW (src)mmxreg-or-mem, (dst)mmxreg */
12075
sewardj4340dac2004-11-20 13:17:04 +000012076 case 0xF5: /* PMADDWD (src)mmxreg-or-mem, (dst)mmxreg */
12077
12078 case 0x74:
12079 case 0x75:
12080 case 0x76: /* PCMPEQgg (src)mmxreg-or-mem, (dst)mmxreg */
12081
12082 case 0x64:
12083 case 0x65:
12084 case 0x66: /* PCMPGTgg (src)mmxreg-or-mem, (dst)mmxreg */
12085
sewardj63ba4092004-11-21 12:30:18 +000012086 case 0x6B: /* PACKSSDW (src)mmxreg-or-mem, (dst)mmxreg */
12087 case 0x63: /* PACKSSWB (src)mmxreg-or-mem, (dst)mmxreg */
12088 case 0x67: /* PACKUSWB (src)mmxreg-or-mem, (dst)mmxreg */
12089
12090 case 0x68:
12091 case 0x69:
12092 case 0x6A: /* PUNPCKHgg (src)mmxreg-or-mem, (dst)mmxreg */
12093
12094 case 0x60:
12095 case 0x61:
12096 case 0x62: /* PUNPCKLgg (src)mmxreg-or-mem, (dst)mmxreg */
12097
12098 case 0xDB: /* PAND (src)mmxreg-or-mem, (dst)mmxreg */
12099 case 0xDF: /* PANDN (src)mmxreg-or-mem, (dst)mmxreg */
12100 case 0xEB: /* POR (src)mmxreg-or-mem, (dst)mmxreg */
12101 case 0xEF: /* PXOR (src)mmxreg-or-mem, (dst)mmxreg */
12102
sewardj38a3f862005-01-13 15:06:51 +000012103 case 0xF1: /* PSLLgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj8d14a592004-11-21 17:04:50 +000012104 case 0xF2:
sewardj38a3f862005-01-13 15:06:51 +000012105 case 0xF3:
sewardj8d14a592004-11-21 17:04:50 +000012106
sewardj38a3f862005-01-13 15:06:51 +000012107 case 0xD1: /* PSRLgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj8d14a592004-11-21 17:04:50 +000012108 case 0xD2:
sewardj38a3f862005-01-13 15:06:51 +000012109 case 0xD3:
sewardj8d14a592004-11-21 17:04:50 +000012110
sewardj38a3f862005-01-13 15:06:51 +000012111 case 0xE1: /* PSRAgg (src)mmxreg-or-mem, (dst)mmxreg */
12112 case 0xE2:
sewardj464efa42004-11-19 22:17:29 +000012113 {
12114 UInt delta0 = delta-1;
12115 Bool decode_OK = False;
sewardj38a3f862005-01-13 15:06:51 +000012116
12117 /* If sz==2 this is SSE, and we assume sse idec has
12118 already spotted those cases by now. */
12119 if (sz != 4)
12120 goto decode_failure;
12121
sewardj464efa42004-11-19 22:17:29 +000012122 delta = dis_MMX ( &decode_OK, sorb, sz, delta-1 );
12123 if (!decode_OK) {
12124 delta = delta0;
12125 goto decode_failure;
12126 }
12127 break;
12128 }
12129
sewardj8d14a592004-11-21 17:04:50 +000012130 case 0x77: /* EMMS */
sewardj38a3f862005-01-13 15:06:51 +000012131 if (sz != 4)
12132 goto decode_failure;
sewardj4cb918d2004-12-03 19:43:31 +000012133 do_EMMS_preamble();
sewardj8d14a592004-11-21 17:04:50 +000012134 DIP("emms\n");
12135 break;
12136
sewardje87b4842004-07-10 12:23:30 +000012137 /* =-=-=-=-=-=-=-=-=- unimp2 =-=-=-=-=-=-=-=-=-=-= */
12138
12139 default:
12140 goto decode_failure;
12141 } /* switch (opc) for the 2-byte opcodes */
12142 goto decode_success;
12143 } /* case 0x0F: of primary opcode */
sewardjc9a65702004-07-07 16:32:57 +000012144
12145 /* ------------------------ ??? ------------------------ */
12146
12147 default:
sewardje87b4842004-07-10 12:23:30 +000012148 decode_failure:
sewardjc9a65702004-07-07 16:32:57 +000012149 /* All decode failures end up here. */
sewardj52444cb2004-12-13 14:09:01 +000012150 vex_printf("vex x86->IR: unhandled instruction bytes: "
sewardjc9a65702004-07-07 16:32:57 +000012151 "0x%x 0x%x 0x%x 0x%x\n",
12152 (Int)getIByte(delta_start+0),
12153 (Int)getIByte(delta_start+1),
12154 (Int)getIByte(delta_start+2),
12155 (Int)getIByte(delta_start+3) );
sewardj52444cb2004-12-13 14:09:01 +000012156
sewardjb64821b2004-12-14 10:00:16 +000012157 /* Tell the dispatcher that this insn cannot be decoded, and so has
12158 not been executed, and (is currently) the next to be executed.
12159 EIP should be up-to-date since it made so at the start of each
12160 insn, but nevertheless be paranoid and update it again right
12161 now. */
sewardj52444cb2004-12-13 14:09:01 +000012162 stmt( IRStmt_Put( OFFB_EIP, mkU32(guest_eip_curr_instr) ) );
12163 jmp_lit(Ijk_NoDecode, guest_eip_curr_instr);
12164 whatNext = Dis_StopHere;
12165 *size = 0;
12166 return whatNext;
12167
sewardjc9a65702004-07-07 16:32:57 +000012168 } /* switch (opc) for the main (primary) opcode switch. */
12169
sewardje87b4842004-07-10 12:23:30 +000012170 decode_success:
sewardjc9a65702004-07-07 16:32:57 +000012171 /* All decode successes end up here. */
12172 DIP("\n");
sewardjc9a65702004-07-07 16:32:57 +000012173
sewardjce70a5c2004-10-18 14:09:54 +000012174 *size = delta - delta_start;
12175 return whatNext;
sewardjc9a65702004-07-07 16:32:57 +000012176}
12177
12178#undef DIP
12179#undef DIS
12180
12181/*--------------------------------------------------------------------*/
sewardjc0ee2ed2004-07-27 10:29:41 +000012182/*--- end guest-x86/toIR.c ---*/
sewardjc9a65702004-07-07 16:32:57 +000012183/*--------------------------------------------------------------------*/