blob: b3dd3fb6ebc0f1a3f286b0ca901675249ea29313 [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 ---*/
sewardjc9a65702004-07-07 16:32:57 +00005/*--- Copyright (c) 2004 OpenWorks LLP. All rights reserved. ---*/
6/*--- ---*/
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
13 Copyright (C) 2004 OpenWorks, LLP.
14
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:
sewardj1f40a0a2004-07-21 12:28:07 +000037 SBB reg with itself
sewardj1f40a0a2004-07-21 12:28:07 +000038 MOVAPS fix (vg_to_ucode rev 1.143)
sewardj458a6f82004-08-25 12:46:02 +000039 check flag settings for cmpxchg
sewardj883b00b2004-09-11 09:30:24 +000040 FUCOMI(P): what happens to A and S flags? Currently are forced
41 to zero.
sewardje166ed02004-10-25 02:27:01 +000042 Fix CPUID, or more precisely, eflags bit 21 so it is changeable.
sewardj3f61ddb2004-10-16 20:51:05 +000043
sewardjce70a5c2004-10-18 14:09:54 +000044 x87 FP Limitations:
sewardj3f61ddb2004-10-16 20:51:05 +000045 * no FP exceptions, except for handling stack over/underflow
46 * FP rounding mode observed only for float->int conversions
47 * FP sin/cos/tan/sincos: C2 flag is always cleared. IOW the
48 simulation claims the argument is in-range (-2^63 <= arg <= 2^63)
49 even when it isn't.
sewardje166ed02004-10-25 02:27:01 +000050 * some of the FCOM cases could do with testing -- not convinced
51 that the args are the right way round.
sewardj52444cb2004-12-13 14:09:01 +000052
53 This module uses global variables and so is not MT-safe (if that
54 should ever become relevant).
sewardje05c42c2004-07-08 20:25:10 +000055*/
56
sewardjc9a65702004-07-07 16:32:57 +000057/* Translates x86 code to IR. */
58
59#include "libvex_basictypes.h"
60#include "libvex_ir.h"
sewardje87b4842004-07-10 12:23:30 +000061#include "libvex.h"
sewardjf6dc3ce2004-10-19 01:03:46 +000062#include "libvex_guest_x86.h"
sewardjc0ee2ed2004-07-27 10:29:41 +000063
64#include "main/vex_util.h"
65#include "main/vex_globals.h"
66#include "guest-x86/gdefs.h"
sewardjc9a65702004-07-07 16:32:57 +000067
68
69/*------------------------------------------------------------*/
70/*--- Globals ---*/
71/*------------------------------------------------------------*/
72
73/* These are set at the start of the translation of a BB, so
74 that we don't have to pass them around endlessly. */
75
76/* We need to know this to do sub-register accesses correctly. */
77/* CONST */
78static Bool host_is_bigendian;
79
sewardjc9a65702004-07-07 16:32:57 +000080/* Pointer to the guest code area. */
81/* CONST */
82static UChar* guest_code;
83
84/* The guest address corresponding to guest_code[0]. */
85/* CONST */
sewardjce70a5c2004-10-18 14:09:54 +000086static Addr32 guest_eip_bbstart;
sewardjc9a65702004-07-07 16:32:57 +000087
sewardj52444cb2004-12-13 14:09:01 +000088/* The guest address for the instruction currently being
89 translated. */
90/* CONST for any specific insn, not for the entire BB */
91static Addr32 guest_eip_curr_instr;
92
sewardjd7cb8532004-08-17 23:59:23 +000093/* The IRBB* into which we're generating code. */
sewardjc9a65702004-07-07 16:32:57 +000094static IRBB* irbb;
95
sewardjc9a65702004-07-07 16:32:57 +000096
sewardjce70a5c2004-10-18 14:09:54 +000097/*------------------------------------------------------------*/
98/*--- Debugging output ---*/
99/*------------------------------------------------------------*/
100
sewardjf48ac192004-10-29 00:41:29 +0000101#define DIP(format, args...) \
102 if (vex_traceflags & VEX_TRACE_FE) \
sewardjce70a5c2004-10-18 14:09:54 +0000103 vex_printf(format, ## args)
104
sewardjf48ac192004-10-29 00:41:29 +0000105#define DIS(buf, format, args...) \
106 if (vex_traceflags & VEX_TRACE_FE) \
sewardjce70a5c2004-10-18 14:09:54 +0000107 vex_sprintf(buf, format, ## args)
108
109
110/*------------------------------------------------------------*/
sewardjdcc85fc2004-10-26 13:26:20 +0000111/*--- Offsets of various parts of the x86 guest state. ---*/
112/*------------------------------------------------------------*/
113
sewardjc9a43662004-11-30 18:51:59 +0000114#define OFFB_EAX offsetof(VexGuestX86State,guest_EAX)
115#define OFFB_EBX offsetof(VexGuestX86State,guest_EBX)
116#define OFFB_ECX offsetof(VexGuestX86State,guest_ECX)
117#define OFFB_EDX offsetof(VexGuestX86State,guest_EDX)
118#define OFFB_ESP offsetof(VexGuestX86State,guest_ESP)
119#define OFFB_EBP offsetof(VexGuestX86State,guest_EBP)
120#define OFFB_ESI offsetof(VexGuestX86State,guest_ESI)
121#define OFFB_EDI offsetof(VexGuestX86State,guest_EDI)
sewardj2a2ba8b2004-11-08 13:14:06 +0000122
sewardjc9a43662004-11-30 18:51:59 +0000123#define OFFB_EIP offsetof(VexGuestX86State,guest_EIP)
sewardj2a2ba8b2004-11-08 13:14:06 +0000124
sewardjc9a43662004-11-30 18:51:59 +0000125#define OFFB_CC_OP offsetof(VexGuestX86State,guest_CC_OP)
126#define OFFB_CC_DEP1 offsetof(VexGuestX86State,guest_CC_DEP1)
127#define OFFB_CC_DEP2 offsetof(VexGuestX86State,guest_CC_DEP2)
128#define OFFB_CC_NDEP offsetof(VexGuestX86State,guest_CC_NDEP)
sewardj893aada2004-11-29 19:57:54 +0000129
sewardjc9a43662004-11-30 18:51:59 +0000130#define OFFB_FPREGS offsetof(VexGuestX86State,guest_FPREG[0])
131#define OFFB_FPTAGS offsetof(VexGuestX86State,guest_FPTAG[0])
132#define OFFB_DFLAG offsetof(VexGuestX86State,guest_DFLAG)
133#define OFFB_IDFLAG offsetof(VexGuestX86State,guest_IDFLAG)
134#define OFFB_FTOP offsetof(VexGuestX86State,guest_FTOP)
135#define OFFB_FC3210 offsetof(VexGuestX86State,guest_FC3210)
136#define OFFB_FPROUND offsetof(VexGuestX86State,guest_FPROUND)
137
138#define OFFB_CS offsetof(VexGuestX86State,guest_CS)
139#define OFFB_DS offsetof(VexGuestX86State,guest_DS)
140#define OFFB_ES offsetof(VexGuestX86State,guest_ES)
141#define OFFB_FS offsetof(VexGuestX86State,guest_FS)
142#define OFFB_GS offsetof(VexGuestX86State,guest_GS)
143#define OFFB_SS offsetof(VexGuestX86State,guest_SS)
sewardj3bd6f3e2004-12-13 10:48:19 +0000144#define OFFB_LDT offsetof(VexGuestX86State,guest_LDT)
145#define OFFB_GDT offsetof(VexGuestX86State,guest_GDT)
sewardjc9a43662004-11-30 18:51:59 +0000146
147#define OFFB_SSEROUND offsetof(VexGuestX86State,guest_SSEROUND)
148#define OFFB_XMM0 offsetof(VexGuestX86State,guest_XMM0)
149#define OFFB_XMM1 offsetof(VexGuestX86State,guest_XMM1)
150#define OFFB_XMM2 offsetof(VexGuestX86State,guest_XMM2)
151#define OFFB_XMM3 offsetof(VexGuestX86State,guest_XMM3)
152#define OFFB_XMM4 offsetof(VexGuestX86State,guest_XMM4)
153#define OFFB_XMM5 offsetof(VexGuestX86State,guest_XMM5)
154#define OFFB_XMM6 offsetof(VexGuestX86State,guest_XMM6)
155#define OFFB_XMM7 offsetof(VexGuestX86State,guest_XMM7)
156
157#define OFFB_EMWARN offsetof(VexGuestX86State,guest_EMWARN)
sewardjdcc85fc2004-10-26 13:26:20 +0000158
159
160/*------------------------------------------------------------*/
sewardjce70a5c2004-10-18 14:09:54 +0000161/*--- Disassemble an entire basic block ---*/
162/*------------------------------------------------------------*/
163
164/* The results of disassembling an instruction. There are three
165 possible outcomes. For Dis_Resteer, the disassembler _must_
166 continue at the specified address. For Dis_StopHere, the
167 disassembler _must_ terminate the BB. For Dis_Continue, we may at
168 our option either disassemble the next insn, or terminate the BB;
169 but in the latter case we must set the bb's ->next field to point
170 to the next instruction. */
171
172typedef
173 enum {
174 Dis_StopHere, /* this insn terminates the BB; we must stop. */
175 Dis_Continue, /* we can optionally continue into the next insn */
176 Dis_Resteer /* followed a branch; continue at the spec'd addr */
177 }
178 DisResult;
179
180
181/* forward decls .. */
182static IRExpr* mkU32 ( UInt i );
sewardjdcc85fc2004-10-26 13:26:20 +0000183static void stmt ( IRStmt* st );
184
sewardjce70a5c2004-10-18 14:09:54 +0000185
186/* disInstr disassembles an instruction located at &guest_code[delta],
187 and sets *size to its size. If the returned value is Dis_Resteer,
sewardj5bd4d162004-11-10 13:02:48 +0000188 the next guest address is assigned to *whereNext. disInstr is not
189 permitted to return Dis_Resteer if either (1) resteerOK is False,
190 or (2) resteerOkFn, when applied to the address which it wishes to
191 resteer into, returns False. */
sewardjce70a5c2004-10-18 14:09:54 +0000192
193static DisResult disInstr ( /*IN*/ Bool resteerOK,
sewardj5bd4d162004-11-10 13:02:48 +0000194 /*IN*/ Bool (*resteerOkFn) ( Addr64 ),
sewardjce70a5c2004-10-18 14:09:54 +0000195 /*IN*/ UInt delta,
196 /*OUT*/ UInt* size,
197 /*OUT*/ Addr64* whereNext );
198
199
200/* This is the main (only, in fact) entry point for this module. */
201
202/* Disassemble a complete basic block, starting at eip, and dumping
203 the ucode into cb. Returns the size, in bytes, of the basic
204 block. */
sewardj2a9ad022004-11-25 02:46:58 +0000205IRBB* bbToIR_X86 ( UChar* x86code,
206 Addr64 guest_eip_start,
207 Int* guest_bytes_read,
208 Bool (*byte_accessible)(Addr64),
209 Bool (*chase_into_ok)(Addr64),
210 Bool host_bigendian )
sewardjce70a5c2004-10-18 14:09:54 +0000211{
212 UInt delta;
sewardjdcc85fc2004-10-26 13:26:20 +0000213 Int i, n_instrs, size, first_stmt_idx;
sewardjce70a5c2004-10-18 14:09:54 +0000214 Addr64 guest_next;
215 Bool resteerOK;
216 DisResult dres;
217 static Int n_resteers = 0;
218 Int d_resteers = 0;
sewardj08613742004-10-25 13:01:45 +0000219
220 /* check sanity .. */
221 vassert(vex_control.guest_max_insns >= 1);
222 vassert(vex_control.guest_max_insns < 1000);
223 vassert(vex_control.guest_chase_thresh >= 0);
224 vassert(vex_control.guest_chase_thresh < vex_control.guest_max_insns);
sewardjce70a5c2004-10-18 14:09:54 +0000225
226 /* Set up globals. */
227 host_is_bigendian = host_bigendian;
sewardjce70a5c2004-10-18 14:09:54 +0000228 guest_code = x86code;
229 guest_eip_bbstart = (Addr32)guest_eip_start;
230 irbb = emptyIRBB();
231
sewardjce70a5c2004-10-18 14:09:54 +0000232 vassert((guest_eip_start >> 32) == 0);
sewardjce70a5c2004-10-18 14:09:54 +0000233
sewardjce70a5c2004-10-18 14:09:54 +0000234 /* Delta keeps track of how far along the x86code array we
235 have so far gone. */
236 delta = 0;
237 n_instrs = 0;
238 *guest_bytes_read = 0;
239
240 while (True) {
sewardj08613742004-10-25 13:01:45 +0000241 vassert(n_instrs < vex_control.guest_max_insns);
sewardjce70a5c2004-10-18 14:09:54 +0000242
243 guest_next = 0;
sewardj08613742004-10-25 13:01:45 +0000244 resteerOK = n_instrs < vex_control.guest_chase_thresh;
sewardjdcc85fc2004-10-26 13:26:20 +0000245 first_stmt_idx = irbb->stmts_used;
246
247 if (n_instrs > 0) {
248 /* for the first insn, the dispatch loop will have set
sewardj5bd4d162004-11-10 13:02:48 +0000249 %EIP, but for all the others we have to do it ourselves. */
sewardjdcc85fc2004-10-26 13:26:20 +0000250 stmt( IRStmt_Put( OFFB_EIP, mkU32(guest_eip_bbstart + delta)) );
251 }
252
sewardj52444cb2004-12-13 14:09:01 +0000253 guest_eip_curr_instr = guest_eip_bbstart + delta;
254
sewardj5bd4d162004-11-10 13:02:48 +0000255 dres = disInstr( resteerOK, chase_into_ok,
256 delta, &size, &guest_next );
sewardjdcc85fc2004-10-26 13:26:20 +0000257
258 /* Print the resulting IR, if needed. */
sewardjf48ac192004-10-29 00:41:29 +0000259 if (vex_traceflags & VEX_TRACE_FE) {
sewardjdcc85fc2004-10-26 13:26:20 +0000260 for (i = first_stmt_idx; i < irbb->stmts_used; i++) {
261 vex_printf(" ");
262 ppIRStmt(irbb->stmts[i]);
263 vex_printf("\n");
264 }
265 }
266
267 if (dres == Dis_StopHere) {
268 vassert(irbb->next != NULL);
sewardjf48ac192004-10-29 00:41:29 +0000269 if (vex_traceflags & VEX_TRACE_FE) {
sewardjdcc85fc2004-10-26 13:26:20 +0000270 vex_printf(" ");
271 vex_printf( "goto {");
272 ppIRJumpKind(irbb->jumpkind);
273 vex_printf( "} ");
274 ppIRExpr( irbb->next );
275 vex_printf( "\n");
276 }
277 }
278
sewardjce70a5c2004-10-18 14:09:54 +0000279 delta += size;
280 *guest_bytes_read += size;
281 n_instrs++;
282 DIP("\n");
283
sewardj52444cb2004-12-13 14:09:01 +0000284 vassert(size >= 0 && size <= 18);
sewardjce70a5c2004-10-18 14:09:54 +0000285 if (!resteerOK)
286 vassert(dres != Dis_Resteer);
287 if (dres != Dis_Resteer)
288 vassert(guest_next == 0);
289
290 switch (dres) {
291 case Dis_Continue:
292 vassert(irbb->next == NULL);
sewardj08613742004-10-25 13:01:45 +0000293 if (n_instrs < vex_control.guest_max_insns) {
sewardjce70a5c2004-10-18 14:09:54 +0000294 /* keep going */
295 } else {
296 irbb->next = mkU32(((Addr32)guest_eip_start)+delta);
297 return irbb;
298 }
299 break;
300 case Dis_StopHere:
301 vassert(irbb->next != NULL);
302 return irbb;
303 case Dis_Resteer:
304 vassert(irbb->next == NULL);
305 /* figure out a new delta to continue at. */
sewardj5bd4d162004-11-10 13:02:48 +0000306 vassert(chase_into_ok(guest_next));
sewardjce70a5c2004-10-18 14:09:54 +0000307 delta = (UInt)(guest_next - guest_eip_start);
308 n_resteers++;
309 d_resteers++;
310 if (0 && (n_resteers & 0xFF) == 0)
sewardj5bd4d162004-11-10 13:02:48 +0000311 vex_printf("resteer[%d,%d] to %p (delta = %d)\n",
312 n_resteers, d_resteers,
sewardjce70a5c2004-10-18 14:09:54 +0000313 (void*)(UInt)(guest_next), delta);
314 break;
315 }
316 }
317}
318
319
320/*------------------------------------------------------------*/
321/*--- Helper bits and pieces for deconstructing the ---*/
322/*--- x86 insn stream. ---*/
323/*------------------------------------------------------------*/
324
325/* This is the Intel register encoding -- integer regs. */
326#define R_EAX 0
327#define R_ECX 1
328#define R_EDX 2
329#define R_EBX 3
330#define R_ESP 4
331#define R_EBP 5
332#define R_ESI 6
333#define R_EDI 7
334
335#define R_AL (0+R_EAX)
336#define R_AH (4+R_EAX)
337
sewardj063f02f2004-10-20 12:36:12 +0000338/* This is the Intel register encoding -- segment regs. */
339#define R_ES 0
340#define R_CS 1
341#define R_SS 2
342#define R_DS 3
343#define R_FS 4
344#define R_GS 5
345
sewardjce70a5c2004-10-18 14:09:54 +0000346
sewardjc9a65702004-07-07 16:32:57 +0000347/* Add a statement to the list held by "irbb". */
sewardjd7cb8532004-08-17 23:59:23 +0000348static void stmt ( IRStmt* st )
sewardjc9a65702004-07-07 16:32:57 +0000349{
sewardjd7cb8532004-08-17 23:59:23 +0000350 addStmtToIRBB( irbb, st );
sewardjc9a65702004-07-07 16:32:57 +0000351}
352
353/* Generate a new temporary of the given type. */
354static IRTemp newTemp ( IRType ty )
355{
sewardj6d2638e2004-07-15 09:38:27 +0000356 vassert(isPlausibleType(ty));
sewardje539a402004-07-14 18:24:17 +0000357 return newIRTemp( irbb->tyenv, ty );
sewardjc9a65702004-07-07 16:32:57 +0000358}
359
sewardjc9a65702004-07-07 16:32:57 +0000360/* Bomb out if we can't handle something. */
sewardjd1061ab2004-07-08 01:45:30 +0000361__attribute__ ((noreturn))
sewardjc9a65702004-07-07 16:32:57 +0000362static void unimplemented ( Char* str )
363{
364 vex_printf("x86toIR: unimplemented feature\n");
365 vpanic(str);
366}
367
sewardjce70a5c2004-10-18 14:09:54 +0000368/* Various simple conversions */
sewardjd1061ab2004-07-08 01:45:30 +0000369
sewardje05c42c2004-07-08 20:25:10 +0000370static UInt extend_s_8to32( UInt x )
sewardjd1061ab2004-07-08 01:45:30 +0000371{
372 return (UInt)((((Int)x) << 24) >> 24);
373}
374
sewardj0611d802004-07-11 02:37:54 +0000375static UInt extend_s_16to32 ( UInt x )
376{
377 return (UInt)((((Int)x) << 16) >> 16);
378}
379
sewardjd1061ab2004-07-08 01:45:30 +0000380/* Fetch a byte from the guest insn stream. */
sewardje05c42c2004-07-08 20:25:10 +0000381static UChar getIByte ( UInt delta )
sewardjd1061ab2004-07-08 01:45:30 +0000382{
383 return guest_code[delta];
384}
385
sewardjc9a65702004-07-07 16:32:57 +0000386/* Extract the reg field from a modRM byte. */
sewardje05c42c2004-07-08 20:25:10 +0000387static Int gregOfRM ( UChar mod_reg_rm )
sewardjc9a65702004-07-07 16:32:57 +0000388{
389 return (Int)( (mod_reg_rm >> 3) & 7 );
390}
391
392/* Figure out whether the mod and rm parts of a modRM byte refer to a
393 register or memory. If so, the byte will have the form 11XXXYYY,
394 where YYY is the register number. */
sewardje05c42c2004-07-08 20:25:10 +0000395static Bool epartIsReg ( UChar mod_reg_rm )
sewardjc9a65702004-07-07 16:32:57 +0000396{
397 return (0xC0 == (mod_reg_rm & 0xC0));
398}
399
400/* ... and extract the register number ... */
sewardje05c42c2004-07-08 20:25:10 +0000401static Int eregOfRM ( UChar mod_reg_rm )
sewardjc9a65702004-07-07 16:32:57 +0000402{
403 return (Int)(mod_reg_rm & 0x7);
404}
405
sewardje05c42c2004-07-08 20:25:10 +0000406/* Get a 8/16/32-bit unsigned value out of the insn stream. */
407
408static UInt getUChar ( UInt delta )
409{
410 UInt v = guest_code[delta+0];
411 return v & 0xFF;
412}
413
414static UInt getUDisp16 ( UInt delta )
415{
416 UInt v = guest_code[delta+1]; v <<= 8;
417 v |= guest_code[delta+0];
418 return v & 0xFFFF;
419}
420
421static UInt getUDisp32 ( UInt delta )
sewardjd1061ab2004-07-08 01:45:30 +0000422{
423 UInt v = guest_code[delta+3]; v <<= 8;
424 v |= guest_code[delta+2]; v <<= 8;
425 v |= guest_code[delta+1]; v <<= 8;
426 v |= guest_code[delta+0];
427 return v;
428}
429
sewardje05c42c2004-07-08 20:25:10 +0000430static UInt getUDisp ( Int size, UInt delta )
431{
432 switch (size) {
433 case 4: return getUDisp32(delta);
434 case 2: return getUDisp16(delta);
435 case 1: return getUChar(delta);
436 default: vpanic("getUDisp(x86)");
437 }
438 return 0; /*notreached*/
439}
440
441
sewardjd1061ab2004-07-08 01:45:30 +0000442/* Get a byte value out of the insn stream and sign-extend to 32
443 bits. */
sewardje05c42c2004-07-08 20:25:10 +0000444static UInt getSDisp8 ( UInt delta )
sewardjd1061ab2004-07-08 01:45:30 +0000445{
446 return extend_s_8to32( (UInt) (guest_code[delta]) );
447}
448
sewardj0611d802004-07-11 02:37:54 +0000449static UInt getSDisp16 ( UInt delta0 )
450{
451 UChar* eip = (UChar*)(&guest_code[delta0]);
452 UInt d = *eip++;
453 d |= ((*eip++) << 8);
454 return extend_s_16to32(d);
455}
456
457static UInt getSDisp ( Int size, UInt delta )
458{
459 switch (size) {
460 case 4: return getUDisp32(delta);
461 case 2: return getSDisp16(delta);
462 case 1: return getSDisp8(delta);
463 default: vpanic("getSDisp(x86)");
464 }
465 return 0; /*notreached*/
466}
sewardjd1061ab2004-07-08 01:45:30 +0000467
sewardjc9a65702004-07-07 16:32:57 +0000468
469/*------------------------------------------------------------*/
470/*--- Helpers for constructing IR. ---*/
471/*------------------------------------------------------------*/
472
473/* Create a 1/2/4 byte read of an x86 integer registers. For 16/8 bit
474 register references, we need to take the host endianness into
475 account. Supplied value is 0 .. 7 and in the Intel instruction
476 encoding. */
sewardje05c42c2004-07-08 20:25:10 +0000477
sewardj9334b0f2004-07-10 22:43:54 +0000478static IRType szToITy ( Int n )
479{
480 switch (n) {
481 case 1: return Ity_I8;
482 case 2: return Ity_I16;
483 case 4: return Ity_I32;
484 default: vpanic("szToITy(x86)");
485 }
486}
487
sewardj67e002d2004-12-02 18:16:33 +0000488/* On a little-endian host, less significant bits of the guest
489 registers are at lower addresses. Therefore, if a reference to a
490 register low half has the safe guest state offset as a reference to
491 the full register.
492*/
sewardj9334b0f2004-07-10 22:43:54 +0000493static Int integerGuestRegOffset ( Int sz, UInt archreg )
494{
495 vassert(archreg < 8);
496
sewardj9334b0f2004-07-10 22:43:54 +0000497 /* Correct for little-endian host only. */
sewardj67e002d2004-12-02 18:16:33 +0000498 vassert(!host_is_bigendian);
sewardj063f02f2004-10-20 12:36:12 +0000499
500 if (sz == 4 || sz == 2 || (sz == 1 && archreg < 4)) {
501 switch (archreg) {
sewardjc9a43662004-11-30 18:51:59 +0000502 case R_EAX: return OFFB_EAX;
503 case R_EBX: return OFFB_EBX;
504 case R_ECX: return OFFB_ECX;
505 case R_EDX: return OFFB_EDX;
506 case R_ESI: return OFFB_ESI;
507 case R_EDI: return OFFB_EDI;
508 case R_ESP: return OFFB_ESP;
509 case R_EBP: return OFFB_EBP;
sewardj063f02f2004-10-20 12:36:12 +0000510 default: vpanic("integerGuestRegOffset(x86,le)(4,2)");
511 }
512 }
513
514 vassert(archreg >= 4 && archreg < 8 && sz == 1);
515 switch (archreg-4) {
sewardjc9a43662004-11-30 18:51:59 +0000516 case R_EAX: return 1+ OFFB_EAX;
517 case R_EBX: return 1+ OFFB_EBX;
518 case R_ECX: return 1+ OFFB_ECX;
519 case R_EDX: return 1+ OFFB_EDX;
sewardj063f02f2004-10-20 12:36:12 +0000520 default: vpanic("integerGuestRegOffset(x86,le)(1h)");
521 }
522
523 /* NOTREACHED */
524 vpanic("integerGuestRegOffset(x86,le)");
525}
526
527static Int segmentGuestRegOffset ( UInt sreg )
528{
529 switch (sreg) {
sewardjc9a43662004-11-30 18:51:59 +0000530 case R_ES: return OFFB_ES;
531 case R_CS: return OFFB_CS;
532 case R_SS: return OFFB_SS;
533 case R_DS: return OFFB_DS;
534 case R_FS: return OFFB_FS;
535 case R_GS: return OFFB_GS;
sewardj063f02f2004-10-20 12:36:12 +0000536 default: vpanic("segmentGuestRegOffset(x86)");
sewardj9334b0f2004-07-10 22:43:54 +0000537 }
538}
539
sewardjc9a43662004-11-30 18:51:59 +0000540static Int xmmGuestRegOffset ( UInt xmmreg )
541{
542 switch (xmmreg) {
543 case 0: return OFFB_XMM0;
544 case 1: return OFFB_XMM1;
545 case 2: return OFFB_XMM2;
546 case 3: return OFFB_XMM3;
547 case 4: return OFFB_XMM4;
548 case 5: return OFFB_XMM5;
549 case 6: return OFFB_XMM6;
550 case 7: return OFFB_XMM7;
551 default: vpanic("xmmGuestRegOffset");
552 }
553}
554
sewardj67e002d2004-12-02 18:16:33 +0000555/* Lanes of vector registers are always numbered from zero being the
556 least significant lane (rightmost in the register). */
557
sewardje5854d62004-12-09 03:44:34 +0000558static Int xmmGuestRegLane16offset ( UInt xmmreg, Int laneno )
559{
560 /* Correct for little-endian host only. */
561 vassert(!host_is_bigendian);
562 vassert(laneno >= 0 && laneno < 8);
563 return xmmGuestRegOffset( xmmreg ) + 2 * laneno;
564}
565
sewardj67e002d2004-12-02 18:16:33 +0000566static Int xmmGuestRegLane32offset ( UInt xmmreg, Int laneno )
567{
568 /* Correct for little-endian host only. */
569 vassert(!host_is_bigendian);
570 vassert(laneno >= 0 && laneno < 4);
571 return xmmGuestRegOffset( xmmreg ) + 4 * laneno;
572}
573
574static Int xmmGuestRegLane64offset ( UInt xmmreg, Int laneno )
575{
576 /* Correct for little-endian host only. */
577 vassert(!host_is_bigendian);
578 vassert(laneno >= 0 && laneno < 2);
579 return xmmGuestRegOffset( xmmreg ) + 8 * laneno;
580}
581
sewardjd1061ab2004-07-08 01:45:30 +0000582static IRExpr* getIReg ( Int sz, UInt archreg )
sewardjc9a65702004-07-07 16:32:57 +0000583{
584 vassert(sz == 1 || sz == 2 || sz == 4);
585 vassert(archreg < 8);
sewardj9334b0f2004-07-10 22:43:54 +0000586 return IRExpr_Get( integerGuestRegOffset(sz,archreg),
sewardj5bd4d162004-11-10 13:02:48 +0000587 szToITy(sz) );
sewardjc9a65702004-07-07 16:32:57 +0000588}
589
590/* Ditto, but write to a reg instead. */
sewardj41f43bc2004-07-08 14:23:22 +0000591static void putIReg ( Int sz, UInt archreg, IRExpr* e )
sewardjc9a65702004-07-07 16:32:57 +0000592{
sewardjc9a43662004-11-30 18:51:59 +0000593 IRType ty = typeOfIRExpr(irbb->tyenv, e);
sewardjc9a65702004-07-07 16:32:57 +0000594 vassert(sz == 1 || sz == 2 || sz == 4);
595 vassert(archreg < 8);
sewardjc9a43662004-11-30 18:51:59 +0000596 vassert(ty == Ity_I32 || ty == Ity_I16 || ty == Ity_I8);
sewardjeeb9ef82004-07-15 12:39:03 +0000597 stmt( IRStmt_Put(integerGuestRegOffset(sz,archreg), e) );
sewardjd1061ab2004-07-08 01:45:30 +0000598}
599
sewardj063f02f2004-10-20 12:36:12 +0000600static IRExpr* getSReg ( UInt sreg )
601{
602 return IRExpr_Get( segmentGuestRegOffset(sreg), Ity_I16 );
603}
604
605static void putSReg ( UInt sreg, IRExpr* e )
606{
607 vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_I16);
608 stmt( IRStmt_Put( segmentGuestRegOffset(sreg), e ) );
609}
610
sewardjc9a43662004-11-30 18:51:59 +0000611static IRExpr* getXMMReg ( UInt xmmreg )
612{
613 return IRExpr_Get( xmmGuestRegOffset(xmmreg), Ity_V128 );
614}
615
sewardj67e002d2004-12-02 18:16:33 +0000616static IRExpr* getXMMRegLane64 ( UInt xmmreg, Int laneno )
617{
618 return IRExpr_Get( xmmGuestRegLane64offset(xmmreg,laneno), Ity_I64 );
619}
620
sewardjfd226452004-12-07 19:02:18 +0000621static IRExpr* getXMMRegLane64F ( UInt xmmreg, Int laneno )
sewardj67e002d2004-12-02 18:16:33 +0000622{
sewardjfd226452004-12-07 19:02:18 +0000623 return IRExpr_Get( xmmGuestRegLane64offset(xmmreg,laneno), Ity_F64 );
sewardj67e002d2004-12-02 18:16:33 +0000624}
625
sewardj9636b442004-12-04 01:38:37 +0000626static IRExpr* getXMMRegLane32 ( UInt xmmreg, Int laneno )
627{
628 return IRExpr_Get( xmmGuestRegLane32offset(xmmreg,laneno), Ity_I32 );
629}
630
sewardjfd226452004-12-07 19:02:18 +0000631static IRExpr* getXMMRegLane32F ( UInt xmmreg, Int laneno )
632{
633 return IRExpr_Get( xmmGuestRegLane32offset(xmmreg,laneno), Ity_F32 );
634}
635
sewardjc9a43662004-11-30 18:51:59 +0000636static void putXMMReg ( UInt xmmreg, IRExpr* e )
637{
638 vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_V128);
639 stmt( IRStmt_Put( xmmGuestRegOffset(xmmreg), e ) );
640}
641
sewardj67e002d2004-12-02 18:16:33 +0000642static void putXMMRegLane64 ( UInt xmmreg, Int laneno, IRExpr* e )
643{
644 vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_I64);
645 stmt( IRStmt_Put( xmmGuestRegLane64offset(xmmreg,laneno), e ) );
646}
647
sewardjfd226452004-12-07 19:02:18 +0000648static void putXMMRegLane64F ( UInt xmmreg, Int laneno, IRExpr* e )
649{
650 vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_F64);
651 stmt( IRStmt_Put( xmmGuestRegLane64offset(xmmreg,laneno), e ) );
652}
653
sewardj4cb918d2004-12-03 19:43:31 +0000654static void putXMMRegLane32F ( UInt xmmreg, Int laneno, IRExpr* e )
sewardj67e002d2004-12-02 18:16:33 +0000655{
sewardj4cb918d2004-12-03 19:43:31 +0000656 vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_F32);
sewardj67e002d2004-12-02 18:16:33 +0000657 stmt( IRStmt_Put( xmmGuestRegLane32offset(xmmreg,laneno), e ) );
658}
659
sewardj9636b442004-12-04 01:38:37 +0000660static void putXMMRegLane32 ( UInt xmmreg, Int laneno, IRExpr* e )
661{
662 vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_I32);
663 stmt( IRStmt_Put( xmmGuestRegLane32offset(xmmreg,laneno), e ) );
664}
665
sewardje5854d62004-12-09 03:44:34 +0000666static void putXMMRegLane16 ( UInt xmmreg, Int laneno, IRExpr* e )
667{
668 vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_I16);
669 stmt( IRStmt_Put( xmmGuestRegLane16offset(xmmreg,laneno), e ) );
670}
671
sewardj41f43bc2004-07-08 14:23:22 +0000672static void assign ( IRTemp dst, IRExpr* e )
sewardjd1061ab2004-07-08 01:45:30 +0000673{
sewardj41f43bc2004-07-08 14:23:22 +0000674 stmt( IRStmt_Tmp(dst, e) );
sewardjd1061ab2004-07-08 01:45:30 +0000675}
676
sewardj41f43bc2004-07-08 14:23:22 +0000677static void storeLE ( IRExpr* addr, IRExpr* data )
sewardjd1061ab2004-07-08 01:45:30 +0000678{
sewardj41f43bc2004-07-08 14:23:22 +0000679 stmt( IRStmt_STle(addr,data) );
sewardjd1061ab2004-07-08 01:45:30 +0000680}
681
sewardje87b4842004-07-10 12:23:30 +0000682static IRExpr* unop ( IROp op, IRExpr* a )
683{
684 return IRExpr_Unop(op, a);
685}
686
sewardjd1061ab2004-07-08 01:45:30 +0000687static IRExpr* binop ( IROp op, IRExpr* a1, IRExpr* a2 )
688{
689 return IRExpr_Binop(op, a1, a2);
690}
691
692static IRExpr* mkexpr ( IRTemp tmp )
693{
694 return IRExpr_Tmp(tmp);
695}
696
sewardjc2ac51e2004-07-12 01:03:26 +0000697static IRExpr* mkU8 ( UInt i )
698{
699 vassert(i < 256);
700 return IRExpr_Const(IRConst_U8(i));
701}
702
703static IRExpr* mkU16 ( UInt i )
704{
705 vassert(i < 65536);
706 return IRExpr_Const(IRConst_U16(i));
707}
708
sewardjd1061ab2004-07-08 01:45:30 +0000709static IRExpr* mkU32 ( UInt i )
710{
711 return IRExpr_Const(IRConst_U32(i));
sewardjc9a65702004-07-07 16:32:57 +0000712}
713
sewardj41f43bc2004-07-08 14:23:22 +0000714static IRExpr* mkU ( IRType ty, UInt i )
715{
sewardjc2ac51e2004-07-12 01:03:26 +0000716 if (ty == Ity_I8) return mkU8(i);
717 if (ty == Ity_I16) return mkU16(i);
718 if (ty == Ity_I32) return mkU32(i);
sewardje90ad6a2004-07-10 19:02:10 +0000719 /* If this panics, it usually means you passed a size (1,2,4)
720 value as the IRType, rather than a real IRType. */
sewardj41f43bc2004-07-08 14:23:22 +0000721 vpanic("mkU(x86)");
722}
723
sewardj1e6ad742004-12-02 16:16:11 +0000724static IRExpr* mkV128 ( UShort mask )
725{
726 return IRExpr_Const(IRConst_V128(mask));
727}
728
sewardj41f43bc2004-07-08 14:23:22 +0000729static IRExpr* loadLE ( IRType ty, IRExpr* data )
730{
731 return IRExpr_LDle(ty,data);
732}
733
734static IROp mkSizedOp ( IRType ty, IROp op8 )
735{
sewardje05c42c2004-07-08 20:25:10 +0000736 Int adj;
sewardj41f43bc2004-07-08 14:23:22 +0000737 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
738 vassert(op8 == Iop_Add8 || op8 == Iop_Sub8
sewardj41f43bc2004-07-08 14:23:22 +0000739 || op8 == Iop_Mul8
740 || op8 == Iop_Or8 || op8 == Iop_And8 || op8 == Iop_Xor8
sewardj5bd4d162004-11-10 13:02:48 +0000741 || op8 == Iop_Shl8 || op8 == Iop_Shr8 || op8 == Iop_Sar8
sewardje90ad6a2004-07-10 19:02:10 +0000742 || op8 == Iop_CmpEQ8 || op8 == Iop_CmpNE8
sewardj86b133b2004-11-15 13:54:26 +0000743 || op8 == Iop_Not8 );
sewardje05c42c2004-07-08 20:25:10 +0000744 adj = ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
745 return adj + op8;
sewardj41f43bc2004-07-08 14:23:22 +0000746}
747
sewardj9334b0f2004-07-10 22:43:54 +0000748static IROp mkWidenOp ( Int szSmall, Int szBig, Bool signd )
sewardj41f43bc2004-07-08 14:23:22 +0000749{
sewardj9334b0f2004-07-10 22:43:54 +0000750 if (szSmall == 1 && szBig == 4) {
751 return signd ? Iop_8Sto32 : Iop_8Uto32;
sewardj41f43bc2004-07-08 14:23:22 +0000752 }
sewardj9334b0f2004-07-10 22:43:54 +0000753 if (szSmall == 1 && szBig == 2) {
754 return signd ? Iop_8Sto16 : Iop_8Uto16;
755 }
756 if (szSmall == 2 && szBig == 4) {
757 return signd ? Iop_16Sto32 : Iop_16Uto32;
758 }
sewardj948d48b2004-11-05 19:49:09 +0000759 vpanic("mkWidenOp(x86,guest)");
sewardj41f43bc2004-07-08 14:23:22 +0000760}
761
762
763/*------------------------------------------------------------*/
764/*--- Helpers for %eflags. ---*/
765/*------------------------------------------------------------*/
766
sewardj0611d802004-07-11 02:37:54 +0000767/* -------------- Evaluating the flags-thunk. -------------- */
sewardjc9a65702004-07-07 16:32:57 +0000768
sewardje87b4842004-07-10 12:23:30 +0000769/* Build IR to calculate all the eflags from stored
sewardj2a2ba8b2004-11-08 13:14:06 +0000770 CC_OP/CC_DEP1/CC_DEP2/CC_NDEP. Returns an expression ::
771 Ity_I32. */
sewardj2a9ad022004-11-25 02:46:58 +0000772static IRExpr* mk_x86g_calculate_eflags_all ( void )
sewardje87b4842004-07-10 12:23:30 +0000773{
sewardjf9655262004-10-31 20:02:16 +0000774 IRExpr** args
sewardj2a2ba8b2004-11-08 13:14:06 +0000775 = mkIRExprVec_4( IRExpr_Get(OFFB_CC_OP, Ity_I32),
776 IRExpr_Get(OFFB_CC_DEP1, Ity_I32),
777 IRExpr_Get(OFFB_CC_DEP2, Ity_I32),
778 IRExpr_Get(OFFB_CC_NDEP, Ity_I32) );
sewardj43c56462004-11-06 12:17:57 +0000779 IRExpr* call
780 = mkIRExprCCall(
781 Ity_I32,
782 0/*regparm*/,
sewardj2a9ad022004-11-25 02:46:58 +0000783 "x86g_calculate_eflags_all", &x86g_calculate_eflags_all,
sewardj43c56462004-11-06 12:17:57 +0000784 args
785 );
sewardj2a2ba8b2004-11-08 13:14:06 +0000786 /* Exclude OP and NDEP from definedness checking. We're only
787 interested in DEP1 and DEP2. */
788 call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<3);
sewardj43c56462004-11-06 12:17:57 +0000789 return call;
sewardje87b4842004-07-10 12:23:30 +0000790}
791
sewardj84ff0652004-08-23 16:16:08 +0000792/* Build IR to calculate some particular condition from stored
sewardj2a2ba8b2004-11-08 13:14:06 +0000793 CC_OP/CC_DEP1/CC_DEP2/CC_NDEP. Returns an expression ::
794 Ity_Bit. */
sewardj2a9ad022004-11-25 02:46:58 +0000795static IRExpr* mk_x86g_calculate_condition ( X86Condcode cond )
sewardj84ff0652004-08-23 16:16:08 +0000796{
sewardjf9655262004-10-31 20:02:16 +0000797 IRExpr** args
sewardj2a2ba8b2004-11-08 13:14:06 +0000798 = mkIRExprVec_5( mkU32(cond),
sewardjf9655262004-10-31 20:02:16 +0000799 IRExpr_Get(OFFB_CC_OP, Ity_I32),
sewardj2a2ba8b2004-11-08 13:14:06 +0000800 IRExpr_Get(OFFB_CC_DEP1, Ity_I32),
801 IRExpr_Get(OFFB_CC_DEP2, Ity_I32),
802 IRExpr_Get(OFFB_CC_NDEP, Ity_I32) );
sewardj43c56462004-11-06 12:17:57 +0000803 IRExpr* call
804 = mkIRExprCCall(
805 Ity_I32,
806 0/*regparm*/,
sewardj2a9ad022004-11-25 02:46:58 +0000807 "x86g_calculate_condition", &x86g_calculate_condition,
sewardj43c56462004-11-06 12:17:57 +0000808 args
809 );
sewardj2a2ba8b2004-11-08 13:14:06 +0000810 /* Exclude the requested condition, OP and NDEP from definedness
811 checking. We're only interested in DEP1 and DEP2. */
812 call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<1) | (1<<4);
sewardj43c56462004-11-06 12:17:57 +0000813 return unop(Iop_32to1, call);
814}
815
816/* Build IR to calculate just the carry flag from stored
sewardj2a2ba8b2004-11-08 13:14:06 +0000817 CC_OP/CC_DEP1/CC_DEP2/CC_NDEP. Returns an expression :: Ity_I32. */
sewardj2a9ad022004-11-25 02:46:58 +0000818static IRExpr* mk_x86g_calculate_eflags_c ( void )
sewardj43c56462004-11-06 12:17:57 +0000819{
820 IRExpr** args
sewardj2a2ba8b2004-11-08 13:14:06 +0000821 = mkIRExprVec_4( IRExpr_Get(OFFB_CC_OP, Ity_I32),
822 IRExpr_Get(OFFB_CC_DEP1, Ity_I32),
823 IRExpr_Get(OFFB_CC_DEP2, Ity_I32),
824 IRExpr_Get(OFFB_CC_NDEP, Ity_I32) );
sewardj43c56462004-11-06 12:17:57 +0000825 IRExpr* call
826 = mkIRExprCCall(
827 Ity_I32,
828 0/*regparm*/,
sewardj2a9ad022004-11-25 02:46:58 +0000829 "x86g_calculate_eflags_c", &x86g_calculate_eflags_c,
sewardj43c56462004-11-06 12:17:57 +0000830 args
831 );
sewardj2a2ba8b2004-11-08 13:14:06 +0000832 /* Exclude OP and NDEP from definedness checking. We're only
833 interested in DEP1 and DEP2. */
834 call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<3);
sewardj43c56462004-11-06 12:17:57 +0000835 return call;
sewardj84ff0652004-08-23 16:16:08 +0000836}
837
sewardje87b4842004-07-10 12:23:30 +0000838
sewardj0611d802004-07-11 02:37:54 +0000839/* -------------- Building the flags-thunk. -------------- */
840
sewardjb9c5cf62004-08-24 15:10:38 +0000841/* The machinery in this section builds the flag-thunk following a
842 flag-setting operation. Hence the various setFlags_* functions.
sewardjb9c5cf62004-08-24 15:10:38 +0000843*/
844
845static Bool isAddSub ( IROp op8 )
846{
847 return op8 == Iop_Add8 || op8 == Iop_Sub8;
848}
sewardj0611d802004-07-11 02:37:54 +0000849
sewardj2a2ba8b2004-11-08 13:14:06 +0000850static Bool isLogic ( IROp op8 )
851{
852 return op8 == Iop_And8 || op8 == Iop_Or8 || op8 == Iop_Xor8;
853}
854
sewardja2384712004-07-29 14:36:40 +0000855/* U-widen 8/16/32 bit int expr to 32. */
sewardjc22a6fd2004-07-29 23:41:47 +0000856static IRExpr* widenUto32 ( IRExpr* e )
sewardj443cd9d2004-07-18 23:06:45 +0000857{
858 switch (typeOfIRExpr(irbb->tyenv,e)) {
859 case Ity_I32: return e;
860 case Ity_I16: return unop(Iop_16Uto32,e);
861 case Ity_I8: return unop(Iop_8Uto32,e);
862 default: vpanic("widenUto32");
863 }
864}
865
sewardjc22a6fd2004-07-29 23:41:47 +0000866/* S-widen 8/16/32 bit int expr to 32. */
867static IRExpr* widenSto32 ( IRExpr* e )
868{
869 switch (typeOfIRExpr(irbb->tyenv,e)) {
870 case Ity_I32: return e;
871 case Ity_I16: return unop(Iop_16Sto32,e);
872 case Ity_I8: return unop(Iop_8Sto32,e);
873 default: vpanic("widenSto32");
874 }
875}
876
sewardja2384712004-07-29 14:36:40 +0000877/* Narrow 8/16/32 bit int expr to 8/16/32. Clearly only some
878 of these combinations make sense. */
879static IRExpr* narrowTo ( IRType dst_ty, IRExpr* e )
880{
881 IRType src_ty = typeOfIRExpr(irbb->tyenv,e);
882 if (src_ty == dst_ty)
883 return e;
884 if (src_ty == Ity_I32 && dst_ty == Ity_I16)
885 return unop(Iop_32to16, e);
886 if (src_ty == Ity_I32 && dst_ty == Ity_I8)
887 return unop(Iop_32to8, e);
888
889 vex_printf("\nsrc, dst tys are: ");
890 ppIRType(src_ty);
891 vex_printf(", ");
892 ppIRType(dst_ty);
893 vex_printf("\n");
894 vpanic("narrowTo(x86)");
895}
896
sewardj443cd9d2004-07-18 23:06:45 +0000897
sewardj2a2ba8b2004-11-08 13:14:06 +0000898/* Set the flags thunk OP, DEP1 and DEP2 fields. The supplied op is
sewardj948d48b2004-11-05 19:49:09 +0000899 auto-sized up to the real op. */
sewardj0611d802004-07-11 02:37:54 +0000900
sewardj2a2ba8b2004-11-08 13:14:06 +0000901static
902void setFlags_DEP1_DEP2 ( IROp op8, IRTemp dep1, IRTemp dep2, IRType ty )
sewardj0611d802004-07-11 02:37:54 +0000903{
sewardjb9c5cf62004-08-24 15:10:38 +0000904 Int ccOp = ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
905
906 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
907
908 switch (op8) {
sewardj2a9ad022004-11-25 02:46:58 +0000909 case Iop_Add8: ccOp += X86G_CC_OP_ADDB; break;
910 case Iop_Sub8: ccOp += X86G_CC_OP_SUBB; break;
sewardjb9c5cf62004-08-24 15:10:38 +0000911 default: ppIROp(op8);
sewardj2a2ba8b2004-11-08 13:14:06 +0000912 vpanic("setFlags_DEP1_DEP2(x86)");
sewardjb9c5cf62004-08-24 15:10:38 +0000913 }
sewardj2a2ba8b2004-11-08 13:14:06 +0000914 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(ccOp)) );
915 stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto32(mkexpr(dep1))) );
916 stmt( IRStmt_Put( OFFB_CC_DEP2, widenUto32(mkexpr(dep2))) );
sewardjb9c5cf62004-08-24 15:10:38 +0000917}
918
919
sewardj2a2ba8b2004-11-08 13:14:06 +0000920/* Set the OP and DEP1 fields only, and write zero to DEP2. */
sewardjb9c5cf62004-08-24 15:10:38 +0000921
sewardj2a2ba8b2004-11-08 13:14:06 +0000922static
923void setFlags_DEP1 ( IROp op8, IRTemp dep1, IRType ty )
sewardjb9c5cf62004-08-24 15:10:38 +0000924{
925 Int ccOp = ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
sewardj0611d802004-07-11 02:37:54 +0000926
927 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
928
929 switch (op8) {
930 case Iop_Or8:
931 case Iop_And8:
sewardj2a9ad022004-11-25 02:46:58 +0000932 case Iop_Xor8: ccOp += X86G_CC_OP_LOGICB; break;
sewardj0611d802004-07-11 02:37:54 +0000933 default: ppIROp(op8);
sewardj2a2ba8b2004-11-08 13:14:06 +0000934 vpanic("setFlags_DEP1(x86)");
sewardj0611d802004-07-11 02:37:54 +0000935 }
sewardj2a2ba8b2004-11-08 13:14:06 +0000936 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(ccOp)) );
937 stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto32(mkexpr(dep1))) );
938 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0)) );
sewardj0611d802004-07-11 02:37:54 +0000939}
940
941
sewardj948d48b2004-11-05 19:49:09 +0000942/* For shift operations, we put in the result and the undershifted
943 result. Except if the shift amount is zero, the thunk is left
944 unchanged. */
sewardj0611d802004-07-11 02:37:54 +0000945
sewardj2a2ba8b2004-11-08 13:14:06 +0000946static void setFlags_DEP1_DEP2_shift ( IROp op32,
947 IRTemp res,
948 IRTemp resUS,
949 IRType ty,
950 IRTemp guard )
sewardj0611d802004-07-11 02:37:54 +0000951{
sewardjc22a6fd2004-07-29 23:41:47 +0000952 Int ccOp = ty==Ity_I8 ? 2 : (ty==Ity_I16 ? 1 : 0);
sewardj0611d802004-07-11 02:37:54 +0000953
954 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
955 vassert(guard);
956
sewardj2a2ba8b2004-11-08 13:14:06 +0000957 /* Both kinds of right shifts are handled by the same thunk
958 operation. */
sewardjc22a6fd2004-07-29 23:41:47 +0000959 switch (op32) {
960 case Iop_Shr32:
sewardj2a9ad022004-11-25 02:46:58 +0000961 case Iop_Sar32: ccOp = X86G_CC_OP_SHRL - ccOp; break;
962 case Iop_Shl32: ccOp = X86G_CC_OP_SHLL - ccOp; break;
sewardjc22a6fd2004-07-29 23:41:47 +0000963 default: ppIROp(op32);
sewardj2a2ba8b2004-11-08 13:14:06 +0000964 vpanic("setFlags_DEP1_DEP2_shift(x86)");
sewardj0611d802004-07-11 02:37:54 +0000965 }
966
sewardj2a2ba8b2004-11-08 13:14:06 +0000967 /* DEP1 contains the result, DEP2 contains the undershifted value. */
sewardjeeb9ef82004-07-15 12:39:03 +0000968 stmt( IRStmt_Put( OFFB_CC_OP,
sewardj4042c7e2004-07-18 01:28:30 +0000969 IRExpr_Mux0X( mkexpr(guard),
970 IRExpr_Get(OFFB_CC_OP,Ity_I32),
971 mkU32(ccOp))) );
sewardj2a2ba8b2004-11-08 13:14:06 +0000972 stmt( IRStmt_Put( OFFB_CC_DEP1,
sewardj4042c7e2004-07-18 01:28:30 +0000973 IRExpr_Mux0X( mkexpr(guard),
sewardj2a2ba8b2004-11-08 13:14:06 +0000974 IRExpr_Get(OFFB_CC_DEP1,Ity_I32),
sewardj948d48b2004-11-05 19:49:09 +0000975 widenUto32(mkexpr(res)))) );
sewardj2a2ba8b2004-11-08 13:14:06 +0000976 stmt( IRStmt_Put( OFFB_CC_DEP2,
sewardj4042c7e2004-07-18 01:28:30 +0000977 IRExpr_Mux0X( mkexpr(guard),
sewardj2a2ba8b2004-11-08 13:14:06 +0000978 IRExpr_Get(OFFB_CC_DEP2,Ity_I32),
sewardj948d48b2004-11-05 19:49:09 +0000979 widenUto32(mkexpr(resUS)))) );
sewardj0611d802004-07-11 02:37:54 +0000980}
981
982
sewardj2a2ba8b2004-11-08 13:14:06 +0000983/* For the inc/dec case, we store in DEP1 the result value and in NDEP
sewardj948d48b2004-11-05 19:49:09 +0000984 the former value of the carry flag, which unfortunately we have to
985 compute. */
sewardj0611d802004-07-11 02:37:54 +0000986
sewardj948d48b2004-11-05 19:49:09 +0000987static void setFlags_INC_DEC ( Bool inc, IRTemp res, IRType ty )
sewardj0611d802004-07-11 02:37:54 +0000988{
sewardj2a9ad022004-11-25 02:46:58 +0000989 Int ccOp = inc ? X86G_CC_OP_INCB : X86G_CC_OP_DECB;
sewardj0611d802004-07-11 02:37:54 +0000990
991 ccOp += ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
992 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
993
994 /* This has to come first, because calculating the C flag
sewardj2a2ba8b2004-11-08 13:14:06 +0000995 may require reading all four thunk fields. */
sewardj2a9ad022004-11-25 02:46:58 +0000996 stmt( IRStmt_Put( OFFB_CC_NDEP, mk_x86g_calculate_eflags_c()) );
sewardj2a2ba8b2004-11-08 13:14:06 +0000997 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(ccOp)) );
998 stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(res)) );
999 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0)) );
sewardj0611d802004-07-11 02:37:54 +00001000}
1001
1002
sewardj2a2ba8b2004-11-08 13:14:06 +00001003/* Multiplies are pretty much like add and sub: DEP1 and DEP2 hold the
1004 two arguments. */
sewardjcf780b42004-07-13 18:42:17 +00001005
1006static
sewardj2a2ba8b2004-11-08 13:14:06 +00001007void setFlags_MUL ( IRType ty, IRTemp arg1, IRTemp arg2, UInt base_op )
sewardjcf780b42004-07-13 18:42:17 +00001008{
1009 switch (ty) {
sewardj2a2ba8b2004-11-08 13:14:06 +00001010 case Ity_I8:
1011 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(base_op+0) ) );
1012 break;
1013 case Ity_I16:
1014 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(base_op+1) ) );
1015 break;
1016 case Ity_I32:
1017 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(base_op+2) ) );
1018 break;
1019 default:
1020 vpanic("setFlags_MUL(x86)");
sewardjcf780b42004-07-13 18:42:17 +00001021 }
sewardj2a2ba8b2004-11-08 13:14:06 +00001022 stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto32(mkexpr(arg1)) ));
1023 stmt( IRStmt_Put( OFFB_CC_DEP2, widenUto32(mkexpr(arg2)) ));
sewardjcf780b42004-07-13 18:42:17 +00001024}
1025
1026
sewardj3af115f2004-07-14 02:46:52 +00001027/* -------------- Condition codes. -------------- */
1028
sewardje87b4842004-07-10 12:23:30 +00001029/* Condition codes, using the Intel encoding. */
sewardj0611d802004-07-11 02:37:54 +00001030
sewardj2a9ad022004-11-25 02:46:58 +00001031static Char* name_X86Condcode ( X86Condcode cond )
sewardje87b4842004-07-10 12:23:30 +00001032{
1033 switch (cond) {
sewardj2a9ad022004-11-25 02:46:58 +00001034 case X86CondO: return "o";
1035 case X86CondNO: return "no";
1036 case X86CondB: return "b";
1037 case X86CondNB: return "nb";
1038 case X86CondZ: return "z";
1039 case X86CondNZ: return "nz";
1040 case X86CondBE: return "be";
1041 case X86CondNBE: return "nbe";
1042 case X86CondS: return "s";
1043 case X86CondNS: return "ns";
1044 case X86CondP: return "p";
1045 case X86CondNP: return "np";
1046 case X86CondL: return "l";
1047 case X86CondNL: return "nl";
1048 case X86CondLE: return "le";
1049 case X86CondNLE: return "nle";
1050 case X86CondAlways: return "ALWAYS";
1051 default: vpanic("name_X86Condcode");
sewardje87b4842004-07-10 12:23:30 +00001052 }
1053}
1054
sewardj2a9ad022004-11-25 02:46:58 +00001055static
1056X86Condcode positiveIse_X86Condcode ( X86Condcode cond,
1057 Bool* needInvert )
sewardje87b4842004-07-10 12:23:30 +00001058{
sewardj2a9ad022004-11-25 02:46:58 +00001059 vassert(cond >= X86CondO && cond <= X86CondNLE);
sewardje87b4842004-07-10 12:23:30 +00001060 if (cond & 1) {
1061 *needInvert = True;
1062 return cond-1;
1063 } else {
1064 *needInvert = False;
1065 return cond;
1066 }
1067}
1068
1069
sewardj3af115f2004-07-14 02:46:52 +00001070/* -------------- Helpers for ADD/SUB with carry. -------------- */
1071
sewardj948d48b2004-11-05 19:49:09 +00001072/* Given ta1, ta2 and tres, compute tres = ADC(ta1,ta2) and set flags
sewardj2a2ba8b2004-11-08 13:14:06 +00001073 appropriately.
sewardj3af115f2004-07-14 02:46:52 +00001074*/
1075static void helper_ADC ( Int sz,
sewardj5bd4d162004-11-10 13:02:48 +00001076 IRTemp tres, IRTemp ta1, IRTemp ta2 )
sewardj3af115f2004-07-14 02:46:52 +00001077{
1078 UInt thunkOp;
sewardj2a2ba8b2004-11-08 13:14:06 +00001079 IRType ty = szToITy(sz);
1080 IRTemp oldc = newTemp(Ity_I32);
1081 IRTemp oldcn = newTemp(ty);
1082 IROp plus = mkSizedOp(ty, Iop_Add8);
1083 IROp xor = mkSizedOp(ty, Iop_Xor8);
sewardja2384712004-07-29 14:36:40 +00001084
1085 vassert(sz == 1 || sz == 2 || sz == 4);
sewardj2a9ad022004-11-25 02:46:58 +00001086 thunkOp = sz==4 ? X86G_CC_OP_ADCL
1087 : (sz==2 ? X86G_CC_OP_ADCW : X86G_CC_OP_ADCB);
sewardj3af115f2004-07-14 02:46:52 +00001088
sewardj2a2ba8b2004-11-08 13:14:06 +00001089 /* oldc = old carry flag, 0 or 1 */
1090 assign( oldc, binop(Iop_And32,
sewardj2a9ad022004-11-25 02:46:58 +00001091 mk_x86g_calculate_eflags_c(),
sewardj5bd4d162004-11-10 13:02:48 +00001092 mkU32(1)) );
sewardj3af115f2004-07-14 02:46:52 +00001093
sewardj2a2ba8b2004-11-08 13:14:06 +00001094 assign( oldcn, narrowTo(ty, mkexpr(oldc)) );
1095
1096 assign( tres, binop(plus,
1097 binop(plus,mkexpr(ta1),mkexpr(ta2)),
1098 mkexpr(oldcn)) );
1099
1100 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(thunkOp) ) );
1101 stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(ta1) ) );
sewardj2a9ad022004-11-25 02:46:58 +00001102 stmt( IRStmt_Put( OFFB_CC_DEP2, binop(xor, mkexpr(ta2),
1103 mkexpr(oldcn)) ) );
sewardj2a2ba8b2004-11-08 13:14:06 +00001104 stmt( IRStmt_Put( OFFB_CC_NDEP, mkexpr(oldc) ) );
sewardj3af115f2004-07-14 02:46:52 +00001105}
1106
1107
sewardj948d48b2004-11-05 19:49:09 +00001108/* Given ta1, ta2 and tres, compute tres = SBB(ta1,ta2) and set flags
sewardj2a2ba8b2004-11-08 13:14:06 +00001109 appropriately.
sewardjcaca9d02004-07-28 07:11:32 +00001110*/
1111static void helper_SBB ( Int sz,
sewardj5bd4d162004-11-10 13:02:48 +00001112 IRTemp tres, IRTemp ta1, IRTemp ta2 )
sewardjcaca9d02004-07-28 07:11:32 +00001113{
1114 UInt thunkOp;
sewardj2a2ba8b2004-11-08 13:14:06 +00001115 IRType ty = szToITy(sz);
1116 IRTemp oldc = newTemp(Ity_I32);
1117 IRTemp oldcn = newTemp(ty);
1118 IROp minus = mkSizedOp(ty, Iop_Sub8);
1119 IROp xor = mkSizedOp(ty, Iop_Xor8);
1120
1121 vassert(sz == 1 || sz == 2 || sz == 4);
sewardj2a9ad022004-11-25 02:46:58 +00001122 thunkOp = sz==4 ? X86G_CC_OP_SBBL
1123 : (sz==2 ? X86G_CC_OP_SBBW : X86G_CC_OP_SBBB);
sewardjcaca9d02004-07-28 07:11:32 +00001124
1125 /* oldc = old carry flag, 0 or 1 */
sewardja2384712004-07-29 14:36:40 +00001126 assign( oldc, binop(Iop_And32,
sewardj2a9ad022004-11-25 02:46:58 +00001127 mk_x86g_calculate_eflags_c(),
sewardj5bd4d162004-11-10 13:02:48 +00001128 mkU32(1)) );
sewardjcaca9d02004-07-28 07:11:32 +00001129
sewardj2a2ba8b2004-11-08 13:14:06 +00001130 assign( oldcn, narrowTo(ty, mkexpr(oldc)) );
sewardja2384712004-07-29 14:36:40 +00001131
sewardj2a2ba8b2004-11-08 13:14:06 +00001132 assign( tres, binop(minus,
1133 binop(minus,mkexpr(ta1),mkexpr(ta2)),
1134 mkexpr(oldcn)) );
sewardjcaca9d02004-07-28 07:11:32 +00001135
sewardj2a2ba8b2004-11-08 13:14:06 +00001136 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(thunkOp) ) );
1137 stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(ta1) ) );
sewardj2a9ad022004-11-25 02:46:58 +00001138 stmt( IRStmt_Put( OFFB_CC_DEP2, binop(xor, mkexpr(ta2),
1139 mkexpr(oldcn)) ) );
sewardj2a2ba8b2004-11-08 13:14:06 +00001140 stmt( IRStmt_Put( OFFB_CC_NDEP, mkexpr(oldc) ) );
sewardjcaca9d02004-07-28 07:11:32 +00001141}
1142
1143
sewardjc9a65702004-07-07 16:32:57 +00001144//-- /*------------------------------------------------------------*/
1145//-- /*--- CPU feature set stuff ---*/
1146//-- /*--- This is a little out of place here, but it will do ---*/
1147//-- /*--- for now. ---*/
1148//-- /*------------------------------------------------------------*/
1149//--
sewardje87b4842004-07-10 12:23:30 +00001150//-- #define VG_CPU_VENDOR_GENERIC 0
1151//-- #define VG_CPU_VENDOR_INTEL 1
sewardj5bd4d162004-11-10 13:02:48 +00001152//-- #define VG_CPU_VENDOR_AMD 2
sewardjc9a65702004-07-07 16:32:57 +00001153//--
1154//-- static Int cpu_vendor = VG_CPU_VENDOR_GENERIC;
1155//--
1156//-- static const struct cpu_vendor {
sewardj5bd4d162004-11-10 13:02:48 +00001157//-- const Char *vendorstr;
1158//-- Int vendorid;
sewardjc9a65702004-07-07 16:32:57 +00001159//-- } cpu_vendors[] = {
sewardj5bd4d162004-11-10 13:02:48 +00001160//-- { "GenuineIntel", VG_CPU_VENDOR_INTEL },
1161//-- { "AuthenticAMD", VG_CPU_VENDOR_AMD },
sewardjc9a65702004-07-07 16:32:57 +00001162//-- };
1163//--
sewardj5bd4d162004-11-10 13:02:48 +00001164//-- static Int cpuid_level = -2; /* -2 -> not initialized */
sewardjc9a65702004-07-07 16:32:57 +00001165//-- static UInt cpu_features[VG_N_FEATURE_WORDS];
1166//--
1167//-- /* Standard macro to see if a specific flag is changeable */
1168//-- static inline Bool flag_is_changeable(UInt flag)
1169//-- {
1170//-- UInt f1, f2;
1171//--
1172//-- asm("pushfl\n\t"
1173//-- "pushfl\n\t"
1174//-- "popl %0\n\t"
1175//-- "movl %0,%1\n\t"
1176//-- "xorl %2,%0\n\t"
1177//-- "pushl %0\n\t"
1178//-- "popfl\n\t"
1179//-- "pushfl\n\t"
1180//-- "popl %0\n\t"
1181//-- "popfl\n\t"
1182//-- : "=&r" (f1), "=&r" (f2)
1183//-- : "ir" (flag));
1184//--
1185//-- return ((f1^f2) & flag) != 0;
1186//-- }
1187//--
1188//--
1189//-- /* Probe for the CPUID instruction */
1190//-- static Bool has_cpuid(void)
1191//-- {
1192//-- return flag_is_changeable(EFlagID);
1193//-- }
1194//--
1195//-- static void get_cpu_features(void)
1196//-- {
1197//-- Char vendorstr[13];
1198//-- Int i;
1199//--
1200//-- if (!has_cpuid()) {
1201//-- cpuid_level = -1;
1202//-- return;
1203//-- }
1204//--
1205//-- cpu_features[VG_INT_FEAT] |= (1 << (VG_X86_FEAT_CPUID%32));
1206//--
1207//-- VG_(cpuid)(0, &cpuid_level, (UInt *)&vendorstr[0], (UInt *)&vendorstr[8], (UInt *)&vendorstr[4]);
1208//-- vendorstr[12] = '\0';
1209//--
1210//-- for(i = 0; i < sizeof(cpu_vendors)/sizeof(*cpu_vendors); i++)
1211//-- if (VG_(memcmp)(vendorstr, cpu_vendors[i].vendorstr, 12) == 0) {
sewardj5bd4d162004-11-10 13:02:48 +00001212//-- cpu_vendor = cpu_vendors[i].vendorid;
1213//-- break;
sewardjc9a65702004-07-07 16:32:57 +00001214//-- }
1215//--
1216//-- if (cpuid_level >= 1)
1217//-- VG_(cpuid)(1, NULL, NULL, &cpu_features[VG_EXT_FEAT], &cpu_features[VG_X86_FEAT]);
1218//--
1219//-- switch(cpu_vendor) {
1220//-- case VG_CPU_VENDOR_AMD:
1221//-- /* get AMD-specific flags */
1222//-- VG_(cpuid)(0x80000001, NULL, NULL, NULL, &cpu_features[VG_AMD_FEAT]);
1223//-- break;
1224//--
1225//-- default:
1226//-- break;
1227//-- }
1228//-- }
1229//--
1230//-- Bool VG_(cpu_has_feature)(UInt feature)
1231//-- {
1232//-- UInt word = feature / 32;
1233//-- UInt bit = feature % 32;
1234//--
1235//-- if (cpuid_level == -2)
1236//-- get_cpu_features();
1237//--
1238//-- vg_assert(word >= 0 && word < VG_N_FEATURE_WORDS);
1239//--
1240//-- return !!(cpu_features[word] & (1 << bit));
1241//-- }
1242//--
1243//-- /* The set of features we're willing to support for the client
1244//--
1245//-- This includes supported instruction set extensions, plus any
1246//-- extensions which don't have any user-mode visible effect (but the
1247//-- client may find interesting).
1248//-- */
sewardj5bd4d162004-11-10 13:02:48 +00001249#define VG_X86_SUPPORTED_FEATURES \
1250 ((1 << VG_X86_FEAT_FPU) | \
1251 (1 << VG_X86_FEAT_VME) | \
1252 (1 << VG_X86_FEAT_DE) | \
1253 (1 << VG_X86_FEAT_PSE) | \
1254 (1 << VG_X86_FEAT_TSC) | \
1255 (0 << VG_X86_FEAT_MSR) | \
1256 (1 << VG_X86_FEAT_PAE) | \
1257 (1 << VG_X86_FEAT_MCE) | \
1258 (1 << VG_X86_FEAT_CX8) | \
1259 (1 << VG_X86_FEAT_APIC) | \
1260 (0 << VG_X86_FEAT_SEP) | \
1261 (1 << VG_X86_FEAT_MTRR) | \
1262 (1 << VG_X86_FEAT_PGE) | \
1263 (1 << VG_X86_FEAT_MCA) | \
1264 (1 << VG_X86_FEAT_CMOV) | \
1265 (1 << VG_X86_FEAT_PAT) | \
1266 (1 << VG_X86_FEAT_PSE36) | \
1267 (0 << VG_X86_FEAT_CLFSH) | \
1268 (1 << VG_X86_FEAT_DS) | \
1269 (1 << VG_X86_FEAT_ACPI) | \
1270 (1 << VG_X86_FEAT_MMX) | \
1271 (1 << VG_X86_FEAT_FXSR) | \
1272 (1 << VG_X86_FEAT_SSE) | \
1273 (1 << VG_X86_FEAT_SSE2) | \
1274 (1 << VG_X86_FEAT_SS) | \
1275 (1 << VG_X86_FEAT_HT) | \
1276 (1 << VG_X86_FEAT_TM) | \
1277 (0 << VG_X86_FEAT_IA64) | \
1278 (1 << VG_X86_FEAT_PBE))
sewardjd1061ab2004-07-08 01:45:30 +00001279
sewardj5bd4d162004-11-10 13:02:48 +00001280#define VG_AMD_SUPPORTED_FEATURES \
1281 ((0 << (VG_AMD_FEAT_SYSCALL % 32)) | \
1282 (0 << (VG_AMD_FEAT_NXP % 32)) | \
1283 (1 << (VG_AMD_FEAT_MMXEXT % 32)) | \
1284 (0 << (VG_AMD_FEAT_FFXSR % 32)) | \
1285 (0 << (VG_AMD_FEAT_LONGMODE % 32)) | \
1286 (0 << (VG_AMD_FEAT_3DNOWEXT % 32)) | \
1287 (0 << (VG_AMD_FEAT_3DNOW % 32)) | \
1288 /* Common bits between standard features and AMD features */ \
1289 (1 << VG_X86_FEAT_FPU) | \
1290 (1 << VG_X86_FEAT_VME) | \
1291 (1 << VG_X86_FEAT_DE) | \
1292 (1 << VG_X86_FEAT_PSE) | \
1293 (1 << VG_X86_FEAT_TSC) | \
1294 (0 << VG_X86_FEAT_MSR) | \
1295 (1 << VG_X86_FEAT_PAE) | \
1296 (1 << VG_X86_FEAT_MCE) | \
1297 (1 << VG_X86_FEAT_CX8) | \
1298 (1 << VG_X86_FEAT_APIC) | \
1299 (1 << VG_X86_FEAT_MTRR) | \
1300 (1 << VG_X86_FEAT_PGE) | \
1301 (1 << VG_X86_FEAT_MCA) | \
1302 (1 << VG_X86_FEAT_CMOV) | \
1303 (1 << VG_X86_FEAT_PAT) | \
1304 (1 << VG_X86_FEAT_PSE36) | \
1305 (1 << VG_X86_FEAT_MMX) | \
1306 (1 << VG_X86_FEAT_FXSR))
sewardjd1061ab2004-07-08 01:45:30 +00001307
1308
sewardj5bd4d162004-11-10 13:02:48 +00001309//-- /*
sewardjc9a65702004-07-07 16:32:57 +00001310//-- For simulating the cpuid instruction, we will
1311//-- issue a "real" cpuid instruction and then mask out
1312//-- the bits of the features we do not support currently (3dnow mostly).
1313//-- We also claim to not support most CPUID operations.
sewardj5bd4d162004-11-10 13:02:48 +00001314//--
sewardjc9a65702004-07-07 16:32:57 +00001315//-- Dirk Mueller <mueller@kde.org>
1316//--
1317//-- http://www.sandpile.org/ia32/cpuid.htm
1318//--
1319//-- references:
1320//--
1321//-- pre-MMX pentium:
1322//--
1323//-- <werner> cpuid words (0): 0x1 0x756e6547 0x6c65746e 0x49656e69
1324//-- <werner> cpuid words (1): 0x52b 0x0 0x0 0x1bf
1325//--
1326//-- Updated to be more extensible about future vendor extensions and
1327//-- vendor-specific parts of CPUID.
1328//-- */
1329//-- void VG_(helperc_CPUID)(UInt op, UInt *eax_ret, UInt *ebx_ret, UInt *ecx_ret, UInt *edx_ret)
1330//-- {
1331//-- UInt eax, ebx, ecx, edx;
1332//--
1333//-- if (cpuid_level == -2)
sewardj5bd4d162004-11-10 13:02:48 +00001334//-- get_cpu_features(); /* for cpu_vendor */
sewardjc9a65702004-07-07 16:32:57 +00001335//--
1336//-- VG_(cpuid)(op, &eax, &ebx, &ecx, &edx);
1337//--
1338//-- /* Common mangling */
1339//-- switch(op) {
1340//-- case 1:
1341//-- edx &= VG_X86_SUPPORTED_FEATURES;
1342//-- break;
1343//--
1344//-- case 0xd8000000: {
1345//-- /* Implement some private information at 0xd8000000 */
1346//-- static const Char valgrind_vendor[] = "ValgrindVCPU";
1347//--
sewardj5bd4d162004-11-10 13:02:48 +00001348//-- eax = 0xd8000000; /* max request */
sewardjc9a65702004-07-07 16:32:57 +00001349//-- ebx = *(UInt *)&valgrind_vendor[0];
1350//-- ecx = *(UInt *)&valgrind_vendor[8];
1351//-- edx = *(UInt *)&valgrind_vendor[4];
1352//-- }
1353//-- break;
1354//-- }
1355//--
1356//-- /* Vendor-specific mangling of the results */
1357//-- switch(cpu_vendor) {
1358//-- case VG_CPU_VENDOR_INTEL:
1359//-- switch(op) {
1360//-- case 1:
sewardj5bd4d162004-11-10 13:02:48 +00001361//-- ecx = 0; /* mask out all extended features for now */
1362//-- break;
sewardjc9a65702004-07-07 16:32:57 +00001363//--
1364//-- case 0x80000001:
sewardj5bd4d162004-11-10 13:02:48 +00001365//-- ebx = ecx = edx = 0;
1366//-- break;
sewardjc9a65702004-07-07 16:32:57 +00001367//-- }
1368//-- break;
1369//--
1370//-- case VG_CPU_VENDOR_AMD:
1371//-- switch(op) {
1372//-- case 0x80000001:
sewardj5bd4d162004-11-10 13:02:48 +00001373//-- edx &= VG_AMD_SUPPORTED_FEATURES;
1374//-- break;
sewardjc9a65702004-07-07 16:32:57 +00001375//-- }
1376//-- break;
1377//-- }
1378//--
1379//-- *eax_ret = eax;
1380//-- *ebx_ret = ebx;
1381//-- *ecx_ret = ecx;
1382//-- *edx_ret = edx;
1383//-- }
sewardjc9a65702004-07-07 16:32:57 +00001384
sewardj41f43bc2004-07-08 14:23:22 +00001385
sewardjc9a43662004-11-30 18:51:59 +00001386static HChar* nameGrp1 ( Int opc_aux )
sewardj41f43bc2004-07-08 14:23:22 +00001387{
sewardjc9a43662004-11-30 18:51:59 +00001388 static HChar* grp1_names[8]
sewardj41f43bc2004-07-08 14:23:22 +00001389 = { "add", "or", "adc", "sbb", "and", "sub", "xor", "cmp" };
1390 if (opc_aux < 0 || opc_aux > 7) vpanic("nameGrp1(x86)");
1391 return grp1_names[opc_aux];
1392}
1393
sewardjc9a43662004-11-30 18:51:59 +00001394static HChar* nameGrp2 ( Int opc_aux )
sewardje90ad6a2004-07-10 19:02:10 +00001395{
sewardjc9a43662004-11-30 18:51:59 +00001396 static HChar* grp2_names[8]
sewardje90ad6a2004-07-10 19:02:10 +00001397 = { "rol", "ror", "rcl", "rcr", "shl", "shr", "shl", "sar" };
sewardjc2ac51e2004-07-12 01:03:26 +00001398 if (opc_aux < 0 || opc_aux > 7) vpanic("nameGrp2(x86)");
sewardje90ad6a2004-07-10 19:02:10 +00001399 return grp2_names[opc_aux];
1400}
1401
sewardjc9a43662004-11-30 18:51:59 +00001402static HChar* nameGrp4 ( Int opc_aux )
sewardjc2ac51e2004-07-12 01:03:26 +00001403{
sewardjc9a43662004-11-30 18:51:59 +00001404 static HChar* grp4_names[8]
sewardjc2ac51e2004-07-12 01:03:26 +00001405 = { "inc", "dec", "???", "???", "???", "???", "???", "???" };
1406 if (opc_aux < 0 || opc_aux > 1) vpanic("nameGrp4(x86)");
1407 return grp4_names[opc_aux];
1408}
sewardj0611d802004-07-11 02:37:54 +00001409
sewardjc9a43662004-11-30 18:51:59 +00001410static HChar* nameGrp5 ( Int opc_aux )
sewardj0611d802004-07-11 02:37:54 +00001411{
sewardjc9a43662004-11-30 18:51:59 +00001412 static HChar* grp5_names[8]
sewardj0611d802004-07-11 02:37:54 +00001413 = { "inc", "dec", "call*", "call*", "jmp*", "jmp*", "push", "???" };
1414 if (opc_aux < 0 || opc_aux > 6) vpanic("nameGrp5(x86)");
1415 return grp5_names[opc_aux];
1416}
1417
sewardjc9a65702004-07-07 16:32:57 +00001418//-- static Char* nameGrp8 ( Int opc_aux )
1419//-- {
1420//-- static Char* grp8_names[8]
1421//-- = { "???", "???", "???", "???", "bt", "bts", "btr", "btc" };
1422//-- if (opc_aux < 4 || opc_aux > 7) VG_(core_panic)("nameGrp8");
1423//-- return grp8_names[opc_aux];
1424//-- }
1425
sewardjc9a43662004-11-30 18:51:59 +00001426static HChar* nameIReg ( Int size, Int reg )
sewardjc9a65702004-07-07 16:32:57 +00001427{
sewardjc9a43662004-11-30 18:51:59 +00001428 static HChar* ireg32_names[8]
sewardjc9a65702004-07-07 16:32:57 +00001429 = { "%eax", "%ecx", "%edx", "%ebx",
1430 "%esp", "%ebp", "%esi", "%edi" };
sewardjc9a43662004-11-30 18:51:59 +00001431 static HChar* ireg16_names[8]
sewardjc9a65702004-07-07 16:32:57 +00001432 = { "%ax", "%cx", "%dx", "%bx", "%sp", "%bp", "%si", "%di" };
sewardjc9a43662004-11-30 18:51:59 +00001433 static HChar* ireg8_names[8]
sewardjc9a65702004-07-07 16:32:57 +00001434 = { "%al", "%cl", "%dl", "%bl",
1435 "%ah{sp}", "%ch{bp}", "%dh{si}", "%bh{di}" };
1436 if (reg < 0 || reg > 7) goto bad;
1437 switch (size) {
1438 case 4: return ireg32_names[reg];
1439 case 2: return ireg16_names[reg];
1440 case 1: return ireg8_names[reg];
1441 }
1442 bad:
1443 vpanic("nameIReg(X86)");
1444 return NULL; /*notreached*/
1445}
1446
sewardjc9a43662004-11-30 18:51:59 +00001447static HChar* nameSReg ( UInt sreg )
sewardj063f02f2004-10-20 12:36:12 +00001448{
1449 switch (sreg) {
1450 case R_ES: return "%es";
1451 case R_CS: return "%cs";
1452 case R_SS: return "%ss";
1453 case R_DS: return "%ds";
1454 case R_FS: return "%fs";
1455 case R_GS: return "%gs";
1456 default: vpanic("nameSReg(x86)");
1457 }
1458}
1459
sewardjc9a43662004-11-30 18:51:59 +00001460static HChar* nameMMXReg ( Int mmxreg )
sewardj464efa42004-11-19 22:17:29 +00001461{
sewardjc9a43662004-11-30 18:51:59 +00001462 static HChar* mmx_names[8]
sewardj464efa42004-11-19 22:17:29 +00001463 = { "%mm0", "%mm1", "%mm2", "%mm3", "%mm4", "%mm5", "%mm6", "%mm7" };
1464 if (mmxreg < 0 || mmxreg > 7) vpanic("nameMMXReg(x86,guest)");
1465 return mmx_names[mmxreg];
1466}
1467
sewardjc9a43662004-11-30 18:51:59 +00001468static HChar* nameXMMReg ( Int xmmreg )
1469{
1470 static HChar* xmm_names[8]
1471 = { "%xmm0", "%xmm1", "%xmm2", "%xmm3",
1472 "%xmm4", "%xmm5", "%xmm6", "%xmm7" };
1473 if (xmmreg < 0 || xmmreg > 7) vpanic("name_of_xmm_reg");
1474 return xmm_names[xmmreg];
1475}
sewardj464efa42004-11-19 22:17:29 +00001476
1477static Char* nameMMXGran ( UChar gran )
1478{
1479 switch (gran) {
1480 case 0: return "b";
1481 case 1: return "w";
1482 case 2: return "d";
1483 case 3: return "q";
1484 default: vpanic("nameMMXGran(x86,guest)");
1485 }
1486}
sewardjc9a65702004-07-07 16:32:57 +00001487
sewardj41f43bc2004-07-08 14:23:22 +00001488static Char nameISize ( Int size )
sewardjc9a65702004-07-07 16:32:57 +00001489{
1490 switch (size) {
1491 case 4: return 'l';
1492 case 2: return 'w';
1493 case 1: return 'b';
1494 default: vpanic("nameISize(x86)");
1495 }
1496}
1497
sewardjd1061ab2004-07-08 01:45:30 +00001498
1499/*------------------------------------------------------------*/
1500/*--- JMP helpers ---*/
1501/*------------------------------------------------------------*/
1502
sewardj78c19df2004-07-12 22:49:27 +00001503static void jmp_lit( IRJumpKind kind, Addr32 d32 )
sewardjd1061ab2004-07-08 01:45:30 +00001504{
sewardje539a402004-07-14 18:24:17 +00001505 irbb->next = mkU32(d32);
1506 irbb->jumpkind = kind;
sewardjd1061ab2004-07-08 01:45:30 +00001507}
1508
sewardj78c19df2004-07-12 22:49:27 +00001509static void jmp_treg( IRJumpKind kind, IRTemp t )
sewardje05c42c2004-07-08 20:25:10 +00001510{
sewardje539a402004-07-14 18:24:17 +00001511 irbb->next = mkexpr(t);
1512 irbb->jumpkind = kind;
sewardje05c42c2004-07-08 20:25:10 +00001513}
sewardje87b4842004-07-10 12:23:30 +00001514
sewardj2a9ad022004-11-25 02:46:58 +00001515static
1516void jcc_01( X86Condcode cond, Addr32 d32_false, Addr32 d32_true )
sewardje87b4842004-07-10 12:23:30 +00001517{
sewardj2a9ad022004-11-25 02:46:58 +00001518 Bool invert;
1519 X86Condcode condPos;
1520 condPos = positiveIse_X86Condcode ( cond, &invert );
sewardje87b4842004-07-10 12:23:30 +00001521 if (invert) {
sewardj2a9ad022004-11-25 02:46:58 +00001522 stmt( IRStmt_Exit( mk_x86g_calculate_condition(condPos),
sewardj893aada2004-11-29 19:57:54 +00001523 Ijk_Boring,
sewardj78c19df2004-07-12 22:49:27 +00001524 IRConst_U32(d32_false) ) );
sewardje539a402004-07-14 18:24:17 +00001525 irbb->next = mkU32(d32_true);
1526 irbb->jumpkind = Ijk_Boring;
sewardje87b4842004-07-10 12:23:30 +00001527 } else {
sewardj2a9ad022004-11-25 02:46:58 +00001528 stmt( IRStmt_Exit( mk_x86g_calculate_condition(condPos),
sewardj893aada2004-11-29 19:57:54 +00001529 Ijk_Boring,
sewardj78c19df2004-07-12 22:49:27 +00001530 IRConst_U32(d32_true) ) );
sewardje539a402004-07-14 18:24:17 +00001531 irbb->next = mkU32(d32_false);
1532 irbb->jumpkind = Ijk_Boring;
sewardje87b4842004-07-10 12:23:30 +00001533 }
1534}
sewardjc9a65702004-07-07 16:32:57 +00001535
1536
sewardjd1061ab2004-07-08 01:45:30 +00001537/*------------------------------------------------------------*/
1538/*--- Disassembling addressing modes ---*/
1539/*------------------------------------------------------------*/
sewardjc9a65702004-07-07 16:32:57 +00001540
sewardjd1061ab2004-07-08 01:45:30 +00001541static
1542UChar* sorbTxt ( UChar sorb )
1543{
1544 switch (sorb) {
1545 case 0: return ""; /* no override */
1546 case 0x3E: return "%ds";
1547 case 0x26: return "%es:";
1548 case 0x64: return "%fs:";
1549 case 0x65: return "%gs:";
sewardj7df596b2004-12-06 14:29:12 +00001550 default: vpanic("sorbTxt(x86,guest)");
sewardjd1061ab2004-07-08 01:45:30 +00001551 }
1552}
1553
1554
sewardj7df596b2004-12-06 14:29:12 +00001555/* 'virtual' is an IRExpr* holding a virtual address. Convert it to a
1556 linear address by adding any required segment override as indicated
1557 by sorb. */
sewardjd1061ab2004-07-08 01:45:30 +00001558static
1559IRExpr* handleSegOverride ( UChar sorb, IRExpr* virtual )
1560{
sewardj3bd6f3e2004-12-13 10:48:19 +00001561 Int sreg;
1562 IRType hWordTy;
1563 IRTemp ldt_ptr, gdt_ptr, seg_selector, r64;
sewardjd1061ab2004-07-08 01:45:30 +00001564
1565 if (sorb == 0)
1566 /* the common case - no override */
1567 return virtual;
1568
sewardjd1061ab2004-07-08 01:45:30 +00001569 switch (sorb) {
1570 case 0x3E: sreg = R_DS; break;
1571 case 0x26: sreg = R_ES; break;
1572 case 0x64: sreg = R_FS; break;
1573 case 0x65: sreg = R_GS; break;
sewardj7df596b2004-12-06 14:29:12 +00001574 default: vpanic("handleSegOverride(x86,guest)");
sewardjd1061ab2004-07-08 01:45:30 +00001575 }
1576
sewardj3bd6f3e2004-12-13 10:48:19 +00001577 hWordTy = sizeof(HWord)==4 ? Ity_I32 : Ity_I64;
sewardjd1061ab2004-07-08 01:45:30 +00001578
sewardj3bd6f3e2004-12-13 10:48:19 +00001579 seg_selector = newTemp(Ity_I32);
1580 ldt_ptr = newTemp(hWordTy);
1581 gdt_ptr = newTemp(hWordTy);
1582 r64 = newTemp(Ity_I64);
sewardjd1061ab2004-07-08 01:45:30 +00001583
sewardj3bd6f3e2004-12-13 10:48:19 +00001584 assign( seg_selector, unop(Iop_16Uto32, getSReg(sreg)) );
1585 assign( ldt_ptr, IRExpr_Get( OFFB_LDT, hWordTy ));
1586 assign( gdt_ptr, IRExpr_Get( OFFB_GDT, hWordTy ));
sewardj7df596b2004-12-06 14:29:12 +00001587
sewardj3bd6f3e2004-12-13 10:48:19 +00001588 /*
1589 Call this to do the translation and limit checks:
1590 ULong x86g_use_seg_selector ( HWord ldt, HWord gdt,
1591 UInt seg_selector, UInt virtual_addr )
1592 */
1593 assign(
1594 r64,
1595 mkIRExprCCall(
1596 Ity_I64,
1597 0/*regparms*/,
1598 "x86g_use_seg_selector",
1599 &x86g_use_seg_selector,
1600 mkIRExprVec_4( mkexpr(ldt_ptr), mkexpr(gdt_ptr),
1601 mkexpr(seg_selector), virtual)
1602 )
1603 );
sewardj7df596b2004-12-06 14:29:12 +00001604
sewardj52444cb2004-12-13 14:09:01 +00001605 /* If the high 32 of the result are non-zero, there was a
1606 failure in address translation. In which case, make a
1607 quick exit.
1608 */
1609 stmt(
1610 IRStmt_Exit(
1611 binop(Iop_CmpNE32, unop(Iop_64HIto32, mkexpr(r64)), mkU32(0)),
1612 Ijk_MapFail,
1613 IRConst_U32( guest_eip_curr_instr )
1614 )
1615 );
1616
1617 /* otherwise, here's the translated result. */
sewardj3bd6f3e2004-12-13 10:48:19 +00001618 return unop(Iop_64to32, mkexpr(r64));
sewardjd1061ab2004-07-08 01:45:30 +00001619}
1620
1621
1622/* Generate IR to calculate an address indicated by a ModRM and
1623 following SIB bytes. The expression, and the number of bytes in
1624 the address mode, are returned. Note that this fn should not be
1625 called if the R/M part of the address denotes a register instead of
1626 memory. If print_codegen is true, text of the addressing mode is
sewardj940e8c92004-07-11 16:53:24 +00001627 placed in buf.
1628
1629 The computed address is stored in a new tempreg, and the
1630 identity of the tempreg is returned. */
1631
1632static IRTemp disAMode_copy2tmp ( IRExpr* addr32 )
1633{
1634 IRTemp tmp = newTemp(Ity_I32);
1635 assign( tmp, addr32 );
1636 return tmp;
1637}
sewardjd1061ab2004-07-08 01:45:30 +00001638
1639static
sewardj940e8c92004-07-11 16:53:24 +00001640IRTemp disAMode ( Int* len, UChar sorb, UInt delta, UChar* buf )
sewardjd1061ab2004-07-08 01:45:30 +00001641{
1642 UChar mod_reg_rm = getIByte(delta);
1643 delta++;
1644
sewardj9ee82862004-12-14 01:16:59 +00001645 buf[0] = (UChar)0;
1646
sewardjd1061ab2004-07-08 01:45:30 +00001647 /* squeeze out the reg field from mod_reg_rm, since a 256-entry
1648 jump table seems a bit excessive.
1649 */
1650 mod_reg_rm &= 0xC7; /* is now XX000YYY */
1651 mod_reg_rm |= (mod_reg_rm >> 3); /* is now XX0XXYYY */
1652 mod_reg_rm &= 0x1F; /* is now 000XXYYY */
1653 switch (mod_reg_rm) {
1654
1655 /* (%eax) .. (%edi), not including (%esp) or (%ebp).
1656 --> GET %reg, t
1657 */
1658 case 0x00: case 0x01: case 0x02: case 0x03:
1659 /* ! 04 */ /* ! 05 */ case 0x06: case 0x07:
1660 { UChar rm = mod_reg_rm;
1661 DIS(buf, "%s(%s)", sorbTxt(sorb), nameIReg(4,rm));
1662 *len = 1;
sewardj5bd4d162004-11-10 13:02:48 +00001663 return disAMode_copy2tmp(
sewardj940e8c92004-07-11 16:53:24 +00001664 handleSegOverride(sorb, getIReg(4,rm)));
sewardjd1061ab2004-07-08 01:45:30 +00001665 }
1666
1667 /* d8(%eax) ... d8(%edi), not including d8(%esp)
1668 --> GET %reg, t ; ADDL d8, t
1669 */
1670 case 0x08: case 0x09: case 0x0A: case 0x0B:
1671 /* ! 0C */ case 0x0D: case 0x0E: case 0x0F:
1672 { UChar rm = mod_reg_rm & 7;
1673 UInt d = getSDisp8(delta);
1674 DIS(buf, "%s%d(%s)", sorbTxt(sorb), d, nameIReg(4,rm));
sewardj5bd4d162004-11-10 13:02:48 +00001675 *len = 2;
1676 return disAMode_copy2tmp(
sewardj940e8c92004-07-11 16:53:24 +00001677 handleSegOverride(sorb,
1678 binop(Iop_Add32,getIReg(4,rm),mkU32(d))));
sewardjd1061ab2004-07-08 01:45:30 +00001679 }
1680
1681 /* d32(%eax) ... d32(%edi), not including d32(%esp)
1682 --> GET %reg, t ; ADDL d8, t
1683 */
1684 case 0x10: case 0x11: case 0x12: case 0x13:
1685 /* ! 14 */ case 0x15: case 0x16: case 0x17:
1686 { UChar rm = mod_reg_rm & 7;
1687 UInt d = getUDisp32(delta);
1688 DIS(buf, "%s0x%x(%s)", sorbTxt(sorb), d, nameIReg(4,rm));
sewardj5bd4d162004-11-10 13:02:48 +00001689 *len = 5;
1690 return disAMode_copy2tmp(
sewardj940e8c92004-07-11 16:53:24 +00001691 handleSegOverride(sorb,
1692 binop(Iop_Add32,getIReg(4,rm),mkU32(d))));
sewardjd1061ab2004-07-08 01:45:30 +00001693 }
1694
1695 /* a register, %eax .. %edi. This shouldn't happen. */
1696 case 0x18: case 0x19: case 0x1A: case 0x1B:
1697 case 0x1C: case 0x1D: case 0x1E: case 0x1F:
1698 vpanic("disAMode(x86): not an addr!");
1699
1700 /* a 32-bit literal address
1701 --> MOV d32, tmp
1702 */
1703 case 0x05:
1704 { UInt d = getUDisp32(delta);
1705 *len = 5;
1706 DIS(buf, "%s(0x%x)", sorbTxt(sorb), d);
sewardj940e8c92004-07-11 16:53:24 +00001707 return disAMode_copy2tmp(
1708 handleSegOverride(sorb, mkU32(d)));
sewardjd1061ab2004-07-08 01:45:30 +00001709 }
1710
1711 case 0x04: {
1712 /* SIB, with no displacement. Special cases:
1713 -- %esp cannot act as an index value.
1714 If index_r indicates %esp, zero is used for the index.
1715 -- when mod is zero and base indicates EBP, base is instead
1716 a 32-bit literal.
1717 It's all madness, I tell you. Extract %index, %base and
1718 scale from the SIB byte. The value denoted is then:
1719 | %index == %ESP && %base == %EBP
1720 = d32 following SIB byte
1721 | %index == %ESP && %base != %EBP
1722 = %base
1723 | %index != %ESP && %base == %EBP
1724 = d32 following SIB byte + (%index << scale)
1725 | %index != %ESP && %base != %ESP
1726 = %base + (%index << scale)
1727
1728 What happens to the souls of CPU architects who dream up such
1729 horrendous schemes, do you suppose?
1730 */
1731 UChar sib = getIByte(delta);
1732 UChar scale = (sib >> 6) & 3;
1733 UChar index_r = (sib >> 3) & 7;
1734 UChar base_r = sib & 7;
sewardj5bd4d162004-11-10 13:02:48 +00001735 delta++;
sewardjd1061ab2004-07-08 01:45:30 +00001736
1737 if (index_r != R_ESP && base_r != R_EBP) {
1738 DIS(buf, "%s(%s,%s,%d)", sorbTxt(sorb),
1739 nameIReg(4,base_r), nameIReg(4,index_r), 1<<scale);
sewardj5bd4d162004-11-10 13:02:48 +00001740 *len = 2;
sewardj940e8c92004-07-11 16:53:24 +00001741 return
1742 disAMode_copy2tmp(
sewardj5bd4d162004-11-10 13:02:48 +00001743 handleSegOverride(sorb,
1744 binop(Iop_Add32,
sewardjd1061ab2004-07-08 01:45:30 +00001745 getIReg(4,base_r),
1746 binop(Iop_Shl32, getIReg(4,index_r),
sewardj6d2638e2004-07-15 09:38:27 +00001747 mkU8(scale)))));
sewardjd1061ab2004-07-08 01:45:30 +00001748 }
1749
1750 if (index_r != R_ESP && base_r == R_EBP) {
1751 UInt d = getUDisp32(delta);
1752 DIS(buf, "%s0x%x(,%s,%d)", sorbTxt(sorb), d,
1753 nameIReg(4,index_r), 1<<scale);
1754 *len = 6;
1755 return
sewardj940e8c92004-07-11 16:53:24 +00001756 disAMode_copy2tmp(
sewardjd1061ab2004-07-08 01:45:30 +00001757 handleSegOverride(sorb,
sewardj5bd4d162004-11-10 13:02:48 +00001758 binop(Iop_Add32,
1759 binop(Iop_Shl32, getIReg(4,index_r), mkU8(scale)),
sewardj940e8c92004-07-11 16:53:24 +00001760 mkU32(d))));
sewardjd1061ab2004-07-08 01:45:30 +00001761 }
1762
1763 if (index_r == R_ESP && base_r != R_EBP) {
1764 DIS(buf, "%s(%s,,)", sorbTxt(sorb), nameIReg(4,base_r));
sewardj5bd4d162004-11-10 13:02:48 +00001765 *len = 2;
1766 return disAMode_copy2tmp(
sewardj940e8c92004-07-11 16:53:24 +00001767 handleSegOverride(sorb, getIReg(4,base_r)));
sewardjd1061ab2004-07-08 01:45:30 +00001768 }
1769
1770 if (index_r == R_ESP && base_r == R_EBP) {
1771 UInt d = getUDisp32(delta);
1772 DIS(buf, "%s0x%x()", sorbTxt(sorb), d);
sewardj5bd4d162004-11-10 13:02:48 +00001773 *len = 6;
1774 vpanic("amode 8");
1775 return disAMode_copy2tmp(
sewardj940e8c92004-07-11 16:53:24 +00001776 handleSegOverride(sorb, mkU32(d)));
sewardjd1061ab2004-07-08 01:45:30 +00001777 }
1778
1779 vassert(0);
1780 }
1781
1782 /* SIB, with 8-bit displacement. Special cases:
1783 -- %esp cannot act as an index value.
1784 If index_r indicates %esp, zero is used for the index.
1785 Denoted value is:
1786 | %index == %ESP
1787 = d8 + %base
1788 | %index != %ESP
1789 = d8 + %base + (%index << scale)
1790 */
1791 case 0x0C: {
1792 UChar sib = getIByte(delta);
1793 UChar scale = (sib >> 6) & 3;
1794 UChar index_r = (sib >> 3) & 7;
1795 UChar base_r = sib & 7;
1796 UInt d = getSDisp8(delta+1);
1797
1798 if (index_r == R_ESP) {
1799 DIS(buf, "%s%d(%s,,)", sorbTxt(sorb), d, nameIReg(4,base_r));
sewardj5bd4d162004-11-10 13:02:48 +00001800 *len = 3;
1801 return disAMode_copy2tmp(
sewardj940e8c92004-07-11 16:53:24 +00001802 handleSegOverride(sorb,
1803 binop(Iop_Add32, getIReg(4,base_r), mkU32(d)) ));
sewardjd1061ab2004-07-08 01:45:30 +00001804 } else {
1805 DIS(buf, "%s%d(%s,%s,%d)", sorbTxt(sorb), d,
1806 nameIReg(4,base_r), nameIReg(4,index_r), 1<<scale);
sewardj5bd4d162004-11-10 13:02:48 +00001807 *len = 3;
1808 return
sewardj940e8c92004-07-11 16:53:24 +00001809 disAMode_copy2tmp(
1810 handleSegOverride(sorb,
sewardj77b86be2004-07-11 13:28:24 +00001811 binop(Iop_Add32,
1812 binop(Iop_Add32,
1813 getIReg(4,base_r),
1814 binop(Iop_Shl32,
sewardj6d2638e2004-07-15 09:38:27 +00001815 getIReg(4,index_r), mkU8(scale))),
sewardj940e8c92004-07-11 16:53:24 +00001816 mkU32(d))));
sewardjd1061ab2004-07-08 01:45:30 +00001817 }
1818 vassert(0);
1819 }
1820
1821 /* SIB, with 32-bit displacement. Special cases:
1822 -- %esp cannot act as an index value.
1823 If index_r indicates %esp, zero is used for the index.
1824 Denoted value is:
1825 | %index == %ESP
1826 = d32 + %base
1827 | %index != %ESP
1828 = d32 + %base + (%index << scale)
1829 */
1830 case 0x14: {
1831 UChar sib = getIByte(delta);
1832 UChar scale = (sib >> 6) & 3;
1833 UChar index_r = (sib >> 3) & 7;
1834 UChar base_r = sib & 7;
1835 UInt d = getUDisp32(delta+1);
1836
1837 if (index_r == R_ESP) {
1838 DIS(buf, "%s%d(%s,,)", sorbTxt(sorb), d, nameIReg(4,base_r));
sewardj5bd4d162004-11-10 13:02:48 +00001839 *len = 6;
1840 return disAMode_copy2tmp(
sewardj940e8c92004-07-11 16:53:24 +00001841 handleSegOverride(sorb,
1842 binop(Iop_Add32, getIReg(4,base_r), mkU32(d)) ));
sewardjd1061ab2004-07-08 01:45:30 +00001843 } else {
1844 DIS(buf, "%s%d(%s,%s,%d)", sorbTxt(sorb), d,
1845 nameIReg(4,base_r), nameIReg(4,index_r), 1<<scale);
sewardj5bd4d162004-11-10 13:02:48 +00001846 *len = 6;
1847 return
sewardj940e8c92004-07-11 16:53:24 +00001848 disAMode_copy2tmp(
1849 handleSegOverride(sorb,
sewardj9334b0f2004-07-10 22:43:54 +00001850 binop(Iop_Add32,
1851 binop(Iop_Add32,
1852 getIReg(4,base_r),
1853 binop(Iop_Shl32,
sewardj6d2638e2004-07-15 09:38:27 +00001854 getIReg(4,index_r), mkU8(scale))),
sewardj940e8c92004-07-11 16:53:24 +00001855 mkU32(d))));
sewardjd1061ab2004-07-08 01:45:30 +00001856 }
1857 vassert(0);
1858 }
1859
1860 default:
1861 vpanic("disAMode(x86)");
1862 return 0; /*notreached*/
1863 }
1864}
1865
1866
1867/* Figure out the number of (insn-stream) bytes constituting the amode
1868 beginning at delta. Is useful for getting hold of literals beyond
1869 the end of the amode before it has been disassembled. */
1870
1871static UInt lengthAMode ( UInt delta )
1872{
1873 UChar mod_reg_rm = getIByte(delta); delta++;
1874
1875 /* squeeze out the reg field from mod_reg_rm, since a 256-entry
1876 jump table seems a bit excessive.
1877 */
1878 mod_reg_rm &= 0xC7; /* is now XX000YYY */
1879 mod_reg_rm |= (mod_reg_rm >> 3); /* is now XX0XXYYY */
1880 mod_reg_rm &= 0x1F; /* is now 000XXYYY */
1881 switch (mod_reg_rm) {
1882
1883 /* (%eax) .. (%edi), not including (%esp) or (%ebp). */
1884 case 0x00: case 0x01: case 0x02: case 0x03:
1885 /* ! 04 */ /* ! 05 */ case 0x06: case 0x07:
1886 return 1;
1887
1888 /* d8(%eax) ... d8(%edi), not including d8(%esp). */
1889 case 0x08: case 0x09: case 0x0A: case 0x0B:
1890 /* ! 0C */ case 0x0D: case 0x0E: case 0x0F:
1891 return 2;
1892
1893 /* d32(%eax) ... d32(%edi), not including d32(%esp). */
1894 case 0x10: case 0x11: case 0x12: case 0x13:
1895 /* ! 14 */ case 0x15: case 0x16: case 0x17:
1896 return 5;
1897
1898 /* a register, %eax .. %edi. (Not an addr, but still handled.) */
1899 case 0x18: case 0x19: case 0x1A: case 0x1B:
1900 case 0x1C: case 0x1D: case 0x1E: case 0x1F:
1901 return 1;
1902
1903 /* a 32-bit literal address. */
1904 case 0x05: return 5;
1905
1906 /* SIB, no displacement. */
1907 case 0x04: {
1908 UChar sib = getIByte(delta);
1909 UChar base_r = sib & 7;
1910 if (base_r == R_EBP) return 6; else return 2;
1911 }
1912 /* SIB, with 8-bit displacement. */
1913 case 0x0C: return 3;
1914
1915 /* SIB, with 32-bit displacement. */
1916 case 0x14: return 6;
1917
1918 default:
1919 vpanic("lengthAMode");
1920 return 0; /*notreached*/
1921 }
1922}
1923
1924/*------------------------------------------------------------*/
1925/*--- Disassembling common idioms ---*/
1926/*------------------------------------------------------------*/
1927
sewardj5df3bfe2004-07-27 09:30:31 +00001928static
1929void codegen_XOR_reg_with_itself ( Int size, Int ge_reg )
1930{
1931 IRType ty = szToITy(size);
1932 /* reg := 0 */
1933 putIReg(size, ge_reg, mkU(ty,0));
1934 /* Flags: C,A,O=0, Z=1, S=0, P=1 */
sewardj2a9ad022004-11-25 02:46:58 +00001935 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
1936 stmt( IRStmt_Put( OFFB_CC_DEP1, mkU32(X86G_CC_MASK_Z|X86G_CC_MASK_P) ));
sewardj2a2ba8b2004-11-08 13:14:06 +00001937 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
sewardj5df3bfe2004-07-27 09:30:31 +00001938 DIP("xor%c %s, %s\n", nameISize(size),
1939 nameIReg(size,ge_reg), nameIReg(size,ge_reg) );
1940}
1941
1942
sewardje87b4842004-07-10 12:23:30 +00001943/* Handle binary integer instructions of the form
1944 op E, G meaning
1945 op reg-or-mem, reg
1946 Is passed the a ptr to the modRM byte, the actual operation, and the
1947 data size. Returns the address advanced completely over this
1948 instruction.
1949
1950 E(src) is reg-or-mem
1951 G(dst) is reg.
1952
1953 If E is reg, --> GET %G, tmp
1954 OP %E, tmp
1955 PUT tmp, %G
1956
1957 If E is mem and OP is not reversible,
1958 --> (getAddr E) -> tmpa
1959 LD (tmpa), tmpa
1960 GET %G, tmp2
1961 OP tmpa, tmp2
1962 PUT tmp2, %G
1963
1964 If E is mem and OP is reversible
1965 --> (getAddr E) -> tmpa
1966 LD (tmpa), tmpa
1967 OP %G, tmpa
1968 PUT tmpa, %G
1969*/
1970static
1971UInt dis_op2_E_G ( UChar sorb,
sewardj180e8b32004-07-29 01:40:11 +00001972 Bool addSubCarry,
sewardje87b4842004-07-10 12:23:30 +00001973 IROp op8,
1974 Bool keep,
1975 Int size,
1976 UInt delta0,
1977 Char* t_x86opc )
1978{
sewardjc9a43662004-11-30 18:51:59 +00001979 HChar dis_buf[50];
sewardj9334b0f2004-07-10 22:43:54 +00001980 Int len;
sewardje87b4842004-07-10 12:23:30 +00001981 IRType ty = szToITy(size);
1982 IRTemp dst1 = newTemp(ty);
1983 IRTemp src = newTemp(ty);
1984 IRTemp dst0 = newTemp(ty);
1985 UChar rm = getUChar(delta0);
sewardj92d168d2004-11-15 14:22:12 +00001986 IRTemp addr = IRTemp_INVALID;
sewardje87b4842004-07-10 12:23:30 +00001987
sewardj180e8b32004-07-29 01:40:11 +00001988 /* addSubCarry == True indicates the intended operation is
1989 add-with-carry or subtract-with-borrow. */
1990 if (addSubCarry) {
1991 vassert(op8 == Iop_Add8 || op8 == Iop_Sub8);
1992 vassert(keep);
1993 }
1994
sewardje87b4842004-07-10 12:23:30 +00001995 if (epartIsReg(rm)) {
sewardje87b4842004-07-10 12:23:30 +00001996 /* Specially handle XOR reg,reg, because that doesn't really
1997 depend on reg, and doing the obvious thing potentially
1998 generates a spurious value check failure due to the bogus
1999 dependency. */
sewardj5df3bfe2004-07-27 09:30:31 +00002000 if (op8 == Iop_Xor8 && gregOfRM(rm) == eregOfRM(rm)) {
2001 codegen_XOR_reg_with_itself ( size, gregOfRM(rm) );
2002 return 1+delta0;
sewardje87b4842004-07-10 12:23:30 +00002003 }
sewardje87b4842004-07-10 12:23:30 +00002004 assign( dst0, getIReg(size,gregOfRM(rm)) );
2005 assign( src, getIReg(size,eregOfRM(rm)) );
sewardje87b4842004-07-10 12:23:30 +00002006
sewardj180e8b32004-07-29 01:40:11 +00002007 if (addSubCarry && op8 == Iop_Add8) {
sewardj180e8b32004-07-29 01:40:11 +00002008 helper_ADC( size, dst1, dst0, src );
sewardje87b4842004-07-10 12:23:30 +00002009 putIReg(size, gregOfRM(rm), mkexpr(dst1));
sewardj180e8b32004-07-29 01:40:11 +00002010 } else
2011 if (addSubCarry && op8 == Iop_Sub8) {
sewardj180e8b32004-07-29 01:40:11 +00002012 helper_SBB( size, dst1, dst0, src );
2013 putIReg(size, gregOfRM(rm), mkexpr(dst1));
2014 } else {
2015 assign( dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
sewardj5bd4d162004-11-10 13:02:48 +00002016 if (isAddSub(op8))
sewardj2a2ba8b2004-11-08 13:14:06 +00002017 setFlags_DEP1_DEP2(op8, dst0, src, ty);
sewardjb9c5cf62004-08-24 15:10:38 +00002018 else
sewardj2a2ba8b2004-11-08 13:14:06 +00002019 setFlags_DEP1(op8, dst1, ty);
sewardj180e8b32004-07-29 01:40:11 +00002020 if (keep)
2021 putIReg(size, gregOfRM(rm), mkexpr(dst1));
2022 }
sewardje87b4842004-07-10 12:23:30 +00002023
2024 DIP("%s%c %s,%s\n", t_x86opc, nameISize(size),
2025 nameIReg(size,eregOfRM(rm)),
2026 nameIReg(size,gregOfRM(rm)));
2027 return 1+delta0;
sewardje87b4842004-07-10 12:23:30 +00002028 } else {
sewardj9334b0f2004-07-10 22:43:54 +00002029 /* E refers to memory */
2030 addr = disAMode ( &len, sorb, delta0, dis_buf);
2031 assign( dst0, getIReg(size,gregOfRM(rm)) );
sewardj940e8c92004-07-11 16:53:24 +00002032 assign( src, loadLE(szToITy(size), mkexpr(addr)) );
sewardj9334b0f2004-07-10 22:43:54 +00002033
sewardj180e8b32004-07-29 01:40:11 +00002034 if (addSubCarry && op8 == Iop_Add8) {
sewardj180e8b32004-07-29 01:40:11 +00002035 helper_ADC( size, dst1, dst0, src );
sewardj9334b0f2004-07-10 22:43:54 +00002036 putIReg(size, gregOfRM(rm), mkexpr(dst1));
sewardj180e8b32004-07-29 01:40:11 +00002037 } else
2038 if (addSubCarry && op8 == Iop_Sub8) {
2039 helper_SBB( size, dst1, dst0, src );
2040 putIReg(size, gregOfRM(rm), mkexpr(dst1));
2041 } else {
2042 assign( dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
sewardj5bd4d162004-11-10 13:02:48 +00002043 if (isAddSub(op8))
sewardj2a2ba8b2004-11-08 13:14:06 +00002044 setFlags_DEP1_DEP2(op8, dst0, src, ty);
sewardjb9c5cf62004-08-24 15:10:38 +00002045 else
sewardj2a2ba8b2004-11-08 13:14:06 +00002046 setFlags_DEP1(op8, dst1, ty);
sewardj180e8b32004-07-29 01:40:11 +00002047 if (keep)
2048 putIReg(size, gregOfRM(rm), mkexpr(dst1));
2049 }
sewardj9334b0f2004-07-10 22:43:54 +00002050
sewardje87b4842004-07-10 12:23:30 +00002051 DIP("%s%c %s,%s\n", t_x86opc, nameISize(size),
2052 dis_buf,nameIReg(size,gregOfRM(rm)));
sewardj9334b0f2004-07-10 22:43:54 +00002053 return len+delta0;
sewardje87b4842004-07-10 12:23:30 +00002054 }
sewardje87b4842004-07-10 12:23:30 +00002055}
sewardje05c42c2004-07-08 20:25:10 +00002056
2057
2058
2059/* Handle binary integer instructions of the form
2060 op G, E meaning
2061 op reg, reg-or-mem
2062 Is passed the a ptr to the modRM byte, the actual operation, and the
2063 data size. Returns the address advanced completely over this
2064 instruction.
2065
2066 G(src) is reg.
2067 E(dst) is reg-or-mem
2068
2069 If E is reg, --> GET %E, tmp
2070 OP %G, tmp
2071 PUT tmp, %E
2072
2073 If E is mem, --> (getAddr E) -> tmpa
2074 LD (tmpa), tmpv
2075 OP %G, tmpv
2076 ST tmpv, (tmpa)
2077*/
2078static
2079UInt dis_op2_G_E ( UChar sorb,
sewardjcaca9d02004-07-28 07:11:32 +00002080 Bool addSubCarry,
sewardje05c42c2004-07-08 20:25:10 +00002081 IROp op8,
2082 Bool keep,
2083 Int size,
2084 UInt delta0,
2085 Char* t_x86opc )
2086{
sewardjc9a43662004-11-30 18:51:59 +00002087 HChar dis_buf[50];
sewardje87b4842004-07-10 12:23:30 +00002088 Int len;
sewardje05c42c2004-07-08 20:25:10 +00002089 IRType ty = szToITy(size);
2090 IRTemp dst1 = newTemp(ty);
2091 IRTemp src = newTemp(ty);
2092 IRTemp dst0 = newTemp(ty);
2093 UChar rm = getIByte(delta0);
sewardj92d168d2004-11-15 14:22:12 +00002094 IRTemp addr = IRTemp_INVALID;
sewardje05c42c2004-07-08 20:25:10 +00002095
sewardjcaca9d02004-07-28 07:11:32 +00002096 /* addSubCarry == True indicates the intended operation is
2097 add-with-carry or subtract-with-borrow. */
2098 if (addSubCarry) {
2099 vassert(op8 == Iop_Add8 || op8 == Iop_Sub8);
2100 vassert(keep);
2101 }
2102
sewardje05c42c2004-07-08 20:25:10 +00002103 if (epartIsReg(rm)) {
sewardje05c42c2004-07-08 20:25:10 +00002104 /* Specially handle XOR reg,reg, because that doesn't really
2105 depend on reg, and doing the obvious thing potentially
2106 generates a spurious value check failure due to the bogus
2107 dependency. */
sewardj5df3bfe2004-07-27 09:30:31 +00002108 if (op8 == Iop_Xor8 && gregOfRM(rm) == eregOfRM(rm)) {
2109 codegen_XOR_reg_with_itself ( size, gregOfRM(rm) );
2110 return 1+delta0;
sewardje05c42c2004-07-08 20:25:10 +00002111 }
sewardje05c42c2004-07-08 20:25:10 +00002112 assign(dst0, getIReg(size,eregOfRM(rm)));
2113 assign(src, getIReg(size,gregOfRM(rm)));
sewardje05c42c2004-07-08 20:25:10 +00002114
sewardjcaca9d02004-07-28 07:11:32 +00002115 if (addSubCarry && op8 == Iop_Add8) {
sewardj1813dbe2004-07-28 17:09:04 +00002116 helper_ADC( size, dst1, dst0, src );
2117 putIReg(size, eregOfRM(rm), mkexpr(dst1));
sewardjcaca9d02004-07-28 07:11:32 +00002118 } else
2119 if (addSubCarry && op8 == Iop_Sub8) {
2120 helper_SBB( size, dst1, dst0, src );
sewardje05c42c2004-07-08 20:25:10 +00002121 putIReg(size, eregOfRM(rm), mkexpr(dst1));
sewardjcaca9d02004-07-28 07:11:32 +00002122 } else {
2123 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
sewardj5bd4d162004-11-10 13:02:48 +00002124 if (isAddSub(op8))
sewardj2a2ba8b2004-11-08 13:14:06 +00002125 setFlags_DEP1_DEP2(op8, dst0, src, ty);
sewardjb9c5cf62004-08-24 15:10:38 +00002126 else
sewardj2a2ba8b2004-11-08 13:14:06 +00002127 setFlags_DEP1(op8, dst1, ty);
sewardjcaca9d02004-07-28 07:11:32 +00002128 if (keep)
2129 putIReg(size, eregOfRM(rm), mkexpr(dst1));
2130 }
sewardje05c42c2004-07-08 20:25:10 +00002131
2132 DIP("%s%c %s,%s\n", t_x86opc, nameISize(size),
2133 nameIReg(size,gregOfRM(rm)),
2134 nameIReg(size,eregOfRM(rm)));
2135 return 1+delta0;
2136 }
2137
2138 /* E refers to memory */
2139 {
sewardje87b4842004-07-10 12:23:30 +00002140 addr = disAMode ( &len, sorb, delta0, dis_buf);
sewardj940e8c92004-07-11 16:53:24 +00002141 assign(dst0, loadLE(ty,mkexpr(addr)));
sewardje87b4842004-07-10 12:23:30 +00002142 assign(src, getIReg(size,gregOfRM(rm)));
sewardje05c42c2004-07-08 20:25:10 +00002143
sewardjcaca9d02004-07-28 07:11:32 +00002144 if (addSubCarry && op8 == Iop_Add8) {
2145 helper_ADC( size, dst1, dst0, src );
2146 storeLE(mkexpr(addr), mkexpr(dst1));
2147 } else
2148 if (addSubCarry && op8 == Iop_Sub8) {
2149 helper_SBB( size, dst1, dst0, src );
2150 storeLE(mkexpr(addr), mkexpr(dst1));
2151 } else {
2152 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
sewardj5bd4d162004-11-10 13:02:48 +00002153 if (isAddSub(op8))
sewardj2a2ba8b2004-11-08 13:14:06 +00002154 setFlags_DEP1_DEP2(op8, dst0, src, ty);
sewardjb9c5cf62004-08-24 15:10:38 +00002155 else
sewardj2a2ba8b2004-11-08 13:14:06 +00002156 setFlags_DEP1(op8, dst1, ty);
sewardjcaca9d02004-07-28 07:11:32 +00002157 if (keep)
2158 storeLE(mkexpr(addr), mkexpr(dst1));
2159 }
sewardje87b4842004-07-10 12:23:30 +00002160
sewardje05c42c2004-07-08 20:25:10 +00002161 DIP("%s%c %s,%s\n", t_x86opc, nameISize(size),
2162 nameIReg(size,gregOfRM(rm)), dis_buf);
sewardje87b4842004-07-10 12:23:30 +00002163 return len+delta0;
sewardje05c42c2004-07-08 20:25:10 +00002164 }
2165}
2166
2167
2168/* Handle move instructions of the form
2169 mov E, G meaning
2170 mov reg-or-mem, reg
2171 Is passed the a ptr to the modRM byte, and the data size. Returns
2172 the address advanced completely over this instruction.
2173
2174 E(src) is reg-or-mem
2175 G(dst) is reg.
2176
2177 If E is reg, --> GET %E, tmpv
2178 PUT tmpv, %G
2179
2180 If E is mem --> (getAddr E) -> tmpa
2181 LD (tmpa), tmpb
2182 PUT tmpb, %G
2183*/
2184static
2185UInt dis_mov_E_G ( UChar sorb,
2186 Int size,
2187 UInt delta0 )
2188{
2189 Int len;
2190 UChar rm = getIByte(delta0);
sewardjc9a43662004-11-30 18:51:59 +00002191 HChar dis_buf[50];
sewardje05c42c2004-07-08 20:25:10 +00002192
2193 if (epartIsReg(rm)) {
sewardj7ca37d92004-10-25 02:58:30 +00002194 putIReg(size, gregOfRM(rm), getIReg(size, eregOfRM(rm)));
sewardje05c42c2004-07-08 20:25:10 +00002195 DIP("mov%c %s,%s\n", nameISize(size),
2196 nameIReg(size,eregOfRM(rm)),
2197 nameIReg(size,gregOfRM(rm)));
sewardj7ca37d92004-10-25 02:58:30 +00002198 return 1+delta0;
sewardje05c42c2004-07-08 20:25:10 +00002199 }
2200
2201 /* E refers to memory */
2202 {
sewardj940e8c92004-07-11 16:53:24 +00002203 IRTemp addr = disAMode ( &len, sorb, delta0, dis_buf );
2204 putIReg(size, gregOfRM(rm), loadLE(szToITy(size), mkexpr(addr)));
sewardje05c42c2004-07-08 20:25:10 +00002205 DIP("mov%c %s,%s\n", nameISize(size),
2206 dis_buf,nameIReg(size,gregOfRM(rm)));
2207 return delta0+len;
2208 }
2209}
2210
2211
2212/* Handle move instructions of the form
2213 mov G, E meaning
2214 mov reg, reg-or-mem
2215 Is passed the a ptr to the modRM byte, and the data size. Returns
2216 the address advanced completely over this instruction.
2217
2218 G(src) is reg.
2219 E(dst) is reg-or-mem
2220
2221 If E is reg, --> GET %G, tmp
2222 PUT tmp, %E
2223
2224 If E is mem, --> (getAddr E) -> tmpa
2225 GET %G, tmpv
2226 ST tmpv, (tmpa)
2227*/
sewardjc9a65702004-07-07 16:32:57 +00002228static
2229UInt dis_mov_G_E ( UChar sorb,
2230 Int size,
2231 UInt delta0 )
2232{
sewardje05c42c2004-07-08 20:25:10 +00002233 Int len;
sewardjc9a65702004-07-07 16:32:57 +00002234 UChar rm = getIByte(delta0);
sewardjc9a43662004-11-30 18:51:59 +00002235 HChar dis_buf[50];
sewardjc9a65702004-07-07 16:32:57 +00002236
2237 if (epartIsReg(rm)) {
sewardj41f43bc2004-07-08 14:23:22 +00002238 putIReg(size, eregOfRM(rm), getIReg(size, gregOfRM(rm)));
sewardjc9a65702004-07-07 16:32:57 +00002239 DIP("mov%c %s,%s\n", nameISize(size),
2240 nameIReg(size,gregOfRM(rm)),
2241 nameIReg(size,eregOfRM(rm)));
2242 return 1+delta0;
2243 }
2244
sewardjc9a65702004-07-07 16:32:57 +00002245 /* E refers to memory */
2246 {
sewardj940e8c92004-07-11 16:53:24 +00002247 IRTemp addr = disAMode ( &len, sorb, delta0, dis_buf);
2248 storeLE( mkexpr(addr), getIReg(size, gregOfRM(rm)) );
sewardjc9a65702004-07-07 16:32:57 +00002249 DIP("mov%c %s,%s\n", nameISize(size),
2250 nameIReg(size,gregOfRM(rm)), dis_buf);
sewardje05c42c2004-07-08 20:25:10 +00002251 return len+delta0;
sewardjc9a65702004-07-07 16:32:57 +00002252 }
sewardjc9a65702004-07-07 16:32:57 +00002253}
2254
2255
sewardj0611d802004-07-11 02:37:54 +00002256/* op $immediate, AL/AX/EAX. */
2257static
2258UInt dis_op_imm_A ( Int size,
2259 IROp op8,
2260 Bool keep,
2261 UInt delta,
2262 Char* t_x86opc )
2263{
2264 IRType ty = szToITy(size);
2265 IRTemp dst0 = newTemp(ty);
2266 IRTemp src = newTemp(ty);
2267 IRTemp dst1 = newTemp(ty);
2268 UInt lit = getUDisp(size,delta);
2269 assign(dst0, getIReg(size,R_EAX));
2270 assign(src, mkU(ty,lit));
2271 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
sewardjb9c5cf62004-08-24 15:10:38 +00002272 if (isAddSub(op8))
sewardj2a2ba8b2004-11-08 13:14:06 +00002273 setFlags_DEP1_DEP2(op8, dst0, src, ty);
sewardjb9c5cf62004-08-24 15:10:38 +00002274 else
sewardj2a2ba8b2004-11-08 13:14:06 +00002275 if (isLogic(op8))
2276 setFlags_DEP1(op8, dst1, ty);
2277 else
2278 vpanic("dis_op_imm_A(x86,guest)");
sewardj0611d802004-07-11 02:37:54 +00002279
2280 if (keep)
2281 putIReg(size, R_EAX, mkexpr(dst1));
2282
2283 DIP("%s%c $0x%x, %s\n", t_x86opc, nameISize(size),
2284 lit, nameIReg(size,R_EAX));
2285 return delta+size;
2286}
sewardj9334b0f2004-07-10 22:43:54 +00002287
2288
2289/* Sign- and Zero-extending moves. */
2290static
2291UInt dis_movx_E_G ( UChar sorb,
2292 UInt delta, Int szs, Int szd, Bool sign_extend )
2293{
sewardj9334b0f2004-07-10 22:43:54 +00002294 UChar rm = getIByte(delta);
2295 if (epartIsReg(rm)) {
2296 putIReg(szd, gregOfRM(rm),
sewardj5bd4d162004-11-10 13:02:48 +00002297 unop(mkWidenOp(szs,szd,sign_extend),
2298 getIReg(szs,eregOfRM(rm))));
sewardj9334b0f2004-07-10 22:43:54 +00002299 DIP("mov%c%c%c %s,%s\n", sign_extend ? 's' : 'z',
2300 nameISize(szs), nameISize(szd),
2301 nameIReg(szs,eregOfRM(rm)),
2302 nameIReg(szd,gregOfRM(rm)));
2303 return 1+delta;
2304 }
2305
2306 /* E refers to memory */
2307 {
sewardj940e8c92004-07-11 16:53:24 +00002308 Int len;
sewardjc9a43662004-11-30 18:51:59 +00002309 HChar dis_buf[50];
sewardj940e8c92004-07-11 16:53:24 +00002310 IRTemp addr = disAMode ( &len, sorb, delta, dis_buf );
sewardj0611d802004-07-11 02:37:54 +00002311
2312 putIReg(szd, gregOfRM(rm),
sewardj5bd4d162004-11-10 13:02:48 +00002313 unop(mkWidenOp(szs,szd,sign_extend),
sewardj940e8c92004-07-11 16:53:24 +00002314 loadLE(szToITy(szs),mkexpr(addr))));
sewardj9334b0f2004-07-10 22:43:54 +00002315 DIP("mov%c%c%c %s,%s\n", sign_extend ? 's' : 'z',
2316 nameISize(szs), nameISize(szd),
2317 dis_buf, nameIReg(szd,gregOfRM(rm)));
sewardj0611d802004-07-11 02:37:54 +00002318 return len+delta;
sewardj9334b0f2004-07-10 22:43:54 +00002319 }
2320}
2321
sewardj9690d922004-07-14 01:39:17 +00002322
2323/* Generate code to divide ArchRegs EDX:EAX / DX:AX / AX by the 32 /
2324 16 / 8 bit quantity in the given IRTemp. */
2325static
2326void codegen_div ( Int sz, IRTemp t, Bool signed_divide )
2327{
sewardje5427e82004-09-11 19:43:51 +00002328 IROp op = signed_divide ? Iop_DivModS64to32 : Iop_DivModU64to32;
2329 IRTemp src64 = newTemp(Ity_I64);
2330 IRTemp dst64 = newTemp(Ity_I64);
sewardj9690d922004-07-14 01:39:17 +00002331 switch (sz) {
sewardje5427e82004-09-11 19:43:51 +00002332 case 4:
sewardj9690d922004-07-14 01:39:17 +00002333 assign( src64, binop(Iop_32HLto64,
sewardje5427e82004-09-11 19:43:51 +00002334 getIReg(4,R_EDX), getIReg(4,R_EAX)) );
sewardj9690d922004-07-14 01:39:17 +00002335 assign( dst64, binop(op, mkexpr(src64), mkexpr(t)) );
sewardj8c7f1ab2004-07-29 20:31:09 +00002336 putIReg( 4, R_EAX, unop(Iop_64to32,mkexpr(dst64)) );
sewardj9690d922004-07-14 01:39:17 +00002337 putIReg( 4, R_EDX, unop(Iop_64HIto32,mkexpr(dst64)) );
2338 break;
sewardje5427e82004-09-11 19:43:51 +00002339 case 2: {
2340 IROp widen3264 = signed_divide ? Iop_32Sto64 : Iop_32Uto64;
2341 IROp widen1632 = signed_divide ? Iop_16Sto32 : Iop_16Uto32;
2342 assign( src64, unop(widen3264,
2343 binop(Iop_16HLto32,
2344 getIReg(2,R_EDX), getIReg(2,R_EAX))) );
2345 assign( dst64, binop(op, mkexpr(src64), unop(widen1632,mkexpr(t))) );
2346 putIReg( 2, R_EAX, unop(Iop_32to16,unop(Iop_64to32,mkexpr(dst64))) );
2347 putIReg( 2, R_EDX, unop(Iop_32to16,unop(Iop_64HIto32,mkexpr(dst64))) );
2348 break;
sewardj9690d922004-07-14 01:39:17 +00002349 }
sewardj4e82db72004-10-16 11:32:15 +00002350 case 1: {
2351 IROp widen3264 = signed_divide ? Iop_32Sto64 : Iop_32Uto64;
2352 IROp widen1632 = signed_divide ? Iop_16Sto32 : Iop_16Uto32;
2353 IROp widen816 = signed_divide ? Iop_8Sto16 : Iop_8Uto16;
2354 assign( src64, unop(widen3264, unop(widen1632, getIReg(2,R_EAX))) );
2355 assign( dst64,
2356 binop(op, mkexpr(src64),
2357 unop(widen1632, unop(widen816, mkexpr(t)))) );
2358 putIReg( 1, R_AL, unop(Iop_16to8, unop(Iop_32to16,
2359 unop(Iop_64to32,mkexpr(dst64)))) );
2360 putIReg( 1, R_AH, unop(Iop_16to8, unop(Iop_32to16,
2361 unop(Iop_64HIto32,mkexpr(dst64)))) );
2362 break;
2363 }
sewardj9690d922004-07-14 01:39:17 +00002364 default: vpanic("codegen_div(x86)");
2365 }
2366}
sewardj41f43bc2004-07-08 14:23:22 +00002367
2368
2369static
sewardje90ad6a2004-07-10 19:02:10 +00002370UInt dis_Grp1 ( UChar sorb,
sewardj41f43bc2004-07-08 14:23:22 +00002371 UInt delta, UChar modrm,
2372 Int am_sz, Int d_sz, Int sz, UInt d32 )
2373{
sewardj41f43bc2004-07-08 14:23:22 +00002374 Int len;
sewardjc9a43662004-11-30 18:51:59 +00002375 HChar dis_buf[50];
sewardje05c42c2004-07-08 20:25:10 +00002376 IRType ty = szToITy(sz);
2377 IRTemp dst1 = newTemp(ty);
2378 IRTemp src = newTemp(ty);
2379 IRTemp dst0 = newTemp(ty);
sewardj92d168d2004-11-15 14:22:12 +00002380 IRTemp addr = IRTemp_INVALID;
sewardj66de2272004-07-16 21:19:05 +00002381 IROp op8 = Iop_INVALID;
sewardj180e8b32004-07-29 01:40:11 +00002382 UInt mask = sz==1 ? 0xFF : (sz==2 ? 0xFFFF : 0xFFFFFFFF);
sewardj41f43bc2004-07-08 14:23:22 +00002383
2384 switch (gregOfRM(modrm)) {
sewardje05c42c2004-07-08 20:25:10 +00002385 case 0: op8 = Iop_Add8; break; case 1: op8 = Iop_Or8; break;
sewardj66de2272004-07-16 21:19:05 +00002386 case 2: break; // ADC
2387 case 3: break; // SBB
sewardje05c42c2004-07-08 20:25:10 +00002388 case 4: op8 = Iop_And8; break; case 5: op8 = Iop_Sub8; break;
2389 case 6: op8 = Iop_Xor8; break; case 7: op8 = Iop_Sub8; break;
sewardj41f43bc2004-07-08 14:23:22 +00002390 default: vpanic("dis_Grp1: unhandled case");
2391 }
sewardj41f43bc2004-07-08 14:23:22 +00002392
2393 if (epartIsReg(modrm)) {
2394 vassert(am_sz == 1);
2395
2396 assign(dst0, getIReg(sz,eregOfRM(modrm)));
sewardj180e8b32004-07-29 01:40:11 +00002397 assign(src, mkU(ty,d32 & mask));
sewardj41f43bc2004-07-08 14:23:22 +00002398
sewardj180e8b32004-07-29 01:40:11 +00002399 if (gregOfRM(modrm) == 2 /* ADC */) {
2400 helper_ADC( sz, dst1, dst0, src );
2401 } else
2402 if (gregOfRM(modrm) == 3 /* SBB */) {
2403 helper_SBB( sz, dst1, dst0, src );
2404 } else {
2405 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
sewardj5bd4d162004-11-10 13:02:48 +00002406 if (isAddSub(op8))
sewardj2a2ba8b2004-11-08 13:14:06 +00002407 setFlags_DEP1_DEP2(op8, dst0, src, ty);
sewardjb9c5cf62004-08-24 15:10:38 +00002408 else
sewardj2a2ba8b2004-11-08 13:14:06 +00002409 setFlags_DEP1(op8, dst1, ty);
sewardj180e8b32004-07-29 01:40:11 +00002410 }
sewardj41f43bc2004-07-08 14:23:22 +00002411
2412 if (gregOfRM(modrm) < 7)
sewardje05c42c2004-07-08 20:25:10 +00002413 putIReg(sz, eregOfRM(modrm), mkexpr(dst1));
sewardj41f43bc2004-07-08 14:23:22 +00002414
2415 delta += (am_sz + d_sz);
2416 DIP("%s%c $0x%x, %s\n", nameGrp1(gregOfRM(modrm)), nameISize(sz), d32,
2417 nameIReg(sz,eregOfRM(modrm)));
2418 } else {
sewardje87b4842004-07-10 12:23:30 +00002419 addr = disAMode ( &len, sorb, delta, dis_buf);
sewardj41f43bc2004-07-08 14:23:22 +00002420
sewardj940e8c92004-07-11 16:53:24 +00002421 assign(dst0, loadLE(ty,mkexpr(addr)));
sewardj180e8b32004-07-29 01:40:11 +00002422 assign(src, mkU(ty,d32 & mask));
sewardj41f43bc2004-07-08 14:23:22 +00002423
sewardj66de2272004-07-16 21:19:05 +00002424 if (gregOfRM(modrm) == 2 /* ADC */) {
sewardj3af115f2004-07-14 02:46:52 +00002425 helper_ADC( sz, dst1, dst0, src );
2426 } else
sewardj66de2272004-07-16 21:19:05 +00002427 if (gregOfRM(modrm) == 3 /* SBB */) {
sewardje166ed02004-10-25 02:27:01 +00002428 helper_SBB( sz, dst1, dst0, src );
sewardj3af115f2004-07-14 02:46:52 +00002429 } else {
2430 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
sewardj5bd4d162004-11-10 13:02:48 +00002431 if (isAddSub(op8))
sewardj2a2ba8b2004-11-08 13:14:06 +00002432 setFlags_DEP1_DEP2(op8, dst0, src, ty);
sewardjb9c5cf62004-08-24 15:10:38 +00002433 else
sewardj2a2ba8b2004-11-08 13:14:06 +00002434 setFlags_DEP1(op8, dst1, ty);
sewardj3af115f2004-07-14 02:46:52 +00002435 }
sewardj41f43bc2004-07-08 14:23:22 +00002436
2437 if (gregOfRM(modrm) < 7)
sewardj940e8c92004-07-11 16:53:24 +00002438 storeLE(mkexpr(addr), mkexpr(dst1));
sewardj41f43bc2004-07-08 14:23:22 +00002439
2440 delta += (len+d_sz);
2441 DIP("%s%c $0x%x, %s\n", nameGrp1(gregOfRM(modrm)), nameISize(sz),
2442 d32, dis_buf);
2443 }
2444 return delta;
2445}
2446
2447
sewardj6d2638e2004-07-15 09:38:27 +00002448/* Group 2 extended opcodes. shift_expr must be an 8-bit typed
2449 expression. */
2450
sewardje90ad6a2004-07-10 19:02:10 +00002451static
2452UInt dis_Grp2 ( UChar sorb,
2453 UInt delta, UChar modrm,
sewardj6d2638e2004-07-15 09:38:27 +00002454 Int am_sz, Int d_sz, Int sz, IRExpr* shift_expr,
2455 Char* shift_expr_txt )
sewardje90ad6a2004-07-10 19:02:10 +00002456{
2457 /* delta on entry points at the modrm byte. */
sewardjc9a43662004-11-30 18:51:59 +00002458 HChar dis_buf[50];
sewardj6d2638e2004-07-15 09:38:27 +00002459 Int len;
sewardj9aebb0c2004-10-24 19:20:43 +00002460 Bool isShift, isRotate, isRotateRC;
sewardj6d2638e2004-07-15 09:38:27 +00002461 IRType ty = szToITy(sz);
2462 IRTemp dst0 = newTemp(ty);
2463 IRTemp dst1 = newTemp(ty);
sewardj92d168d2004-11-15 14:22:12 +00002464 IRTemp addr = IRTemp_INVALID;
sewardje90ad6a2004-07-10 19:02:10 +00002465
2466 vassert(sz == 1 || sz == 2 || sz == 4);
2467
sewardje90ad6a2004-07-10 19:02:10 +00002468 /* Put value to shift/rotate in dst0. */
2469 if (epartIsReg(modrm)) {
2470 assign(dst0, getIReg(sz, eregOfRM(modrm)));
sewardj940e8c92004-07-11 16:53:24 +00002471 delta += (am_sz + d_sz);
sewardje90ad6a2004-07-10 19:02:10 +00002472 } else {
sewardj940e8c92004-07-11 16:53:24 +00002473 addr = disAMode ( &len, sorb, delta, dis_buf);
2474 assign(dst0, loadLE(ty,mkexpr(addr)));
2475 delta += len + d_sz;
sewardje90ad6a2004-07-10 19:02:10 +00002476 }
2477
2478 isShift = False;
2479 switch (gregOfRM(modrm)) { case 4: case 5: case 7: isShift = True; }
2480
sewardj750f4072004-07-26 22:39:11 +00002481 isRotate = False;
2482 switch (gregOfRM(modrm)) { case 0: case 1: isRotate = True; }
2483
sewardj9aebb0c2004-10-24 19:20:43 +00002484 isRotateRC = gregOfRM(modrm) == 3;
2485
2486 if (!isShift && !isRotate && !isRotateRC) {
sewardj8c7f1ab2004-07-29 20:31:09 +00002487 vex_printf("\ncase %d\n", gregOfRM(modrm));
2488 vpanic("dis_Grp2(Reg): unhandled case(x86)");
2489 }
2490
sewardj9aebb0c2004-10-24 19:20:43 +00002491 if (isRotateRC) {
2492 /* call a helper; this insn is so ridiculous it does not deserve
2493 better */
2494 IRTemp r64 = newTemp(Ity_I64);
sewardjf9655262004-10-31 20:02:16 +00002495 IRExpr** args
2496 = mkIRExprVec_4( widenUto32(mkexpr(dst0)), /* thing to rotate */
2497 widenUto32(shift_expr), /* rotate amount */
sewardj2a9ad022004-11-25 02:46:58 +00002498 widenUto32(mk_x86g_calculate_eflags_all()),
sewardjf9655262004-10-31 20:02:16 +00002499 mkU32(sz) );
2500 assign( r64, mkIRExprCCall(
sewardj8ea867b2004-10-30 19:03:02 +00002501 Ity_I64,
sewardjf9655262004-10-31 20:02:16 +00002502 0/*regparm*/,
sewardj2a9ad022004-11-25 02:46:58 +00002503 "x86g_calculate_RCR", &x86g_calculate_RCR,
sewardj8ea867b2004-10-30 19:03:02 +00002504 args
sewardjf9655262004-10-31 20:02:16 +00002505 )
2506 );
sewardj9aebb0c2004-10-24 19:20:43 +00002507 /* new eflags in hi half r64; new value in lo half r64 */
2508 assign( dst1, narrowTo(ty, unop(Iop_64to32, mkexpr(r64))) );
sewardj2a9ad022004-11-25 02:46:58 +00002509 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
sewardj2a2ba8b2004-11-08 13:14:06 +00002510 stmt( IRStmt_Put( OFFB_CC_DEP1, unop(Iop_64HIto32, mkexpr(r64)) ));
2511 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
sewardj9aebb0c2004-10-24 19:20:43 +00002512 }
2513
sewardje90ad6a2004-07-10 19:02:10 +00002514 if (isShift) {
2515
sewardjc22a6fd2004-07-29 23:41:47 +00002516 IRTemp pre32 = newTemp(Ity_I32);
2517 IRTemp res32 = newTemp(Ity_I32);
2518 IRTemp res32ss = newTemp(Ity_I32);
sewardj6d2638e2004-07-15 09:38:27 +00002519 IRTemp shift_amt = newTemp(Ity_I8);
sewardjc22a6fd2004-07-29 23:41:47 +00002520 IROp op32;
sewardje90ad6a2004-07-10 19:02:10 +00002521
2522 switch (gregOfRM(modrm)) {
sewardjc22a6fd2004-07-29 23:41:47 +00002523 case 4: op32 = Iop_Shl32; break;
2524 case 5: op32 = Iop_Shr32; break;
2525 case 7: op32 = Iop_Sar32; break;
sewardje90ad6a2004-07-10 19:02:10 +00002526 default: vpanic("dis_Grp2:shift"); break;
2527 }
2528
sewardjc22a6fd2004-07-29 23:41:47 +00002529 /* Widen the value to be shifted to 32 bits, do the shift, and
2530 narrow back down. This seems surprisingly long-winded, but
2531 unfortunately the Intel semantics requires that 8/16-bit
2532 shifts give defined results for shift values all the way up
2533 to 31, and this seems the simplest way to do it. It has the
2534 advantage that the only IR level shifts generated are of 32
2535 bit values, and the shift amount is guaranteed to be in the
2536 range 0 .. 31, thereby observing the IR semantics requiring
2537 all shift values to be in the range 0 .. 2^word_size-1. */
2538
2539 /* shift_amt = shift_expr & 31, regardless of operation size */
2540 assign( shift_amt, binop(Iop_And8, shift_expr, mkU8(31)) );
2541
2542 /* suitably widen the value to be shifted to 32 bits. */
2543 assign( pre32, op32==Iop_Sar32 ? widenSto32(mkexpr(dst0))
2544 : widenUto32(mkexpr(dst0)) );
2545
2546 /* res32 = pre32 `shift` shift_amt */
2547 assign( res32, binop(op32, mkexpr(pre32), mkexpr(shift_amt)) );
2548
2549 /* res32ss = pre32 `shift` ((shift_amt - 1) & 31) */
2550 assign( res32ss,
2551 binop(op32,
2552 mkexpr(pre32),
2553 binop(Iop_And8,
2554 binop(Iop_Sub8,
2555 mkexpr(shift_amt), mkU8(1)),
2556 mkU8(31))) );
sewardje90ad6a2004-07-10 19:02:10 +00002557
2558 /* Build the flags thunk. */
sewardj2a2ba8b2004-11-08 13:14:06 +00002559 setFlags_DEP1_DEP2_shift(op32, res32, res32ss, ty, shift_amt);
sewardjc22a6fd2004-07-29 23:41:47 +00002560
2561 /* Narrow the result back down. */
2562 assign( dst1, narrowTo(ty, mkexpr(res32)) );
sewardj750f4072004-07-26 22:39:11 +00002563
sewardj1813dbe2004-07-28 17:09:04 +00002564 } /* if (isShift) */
2565
2566 else
sewardj750f4072004-07-26 22:39:11 +00002567 if (isRotate) {
sewardj7ebbdae2004-08-26 12:30:48 +00002568 Int ccOp = ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
2569 Bool left = gregOfRM(modrm) == 0;
2570 IRTemp rot_amt = newTemp(Ity_I8);
2571 IRTemp rot_amt32 = newTemp(Ity_I8);
2572 IRTemp oldFlags = newTemp(Ity_I32);
sewardj750f4072004-07-26 22:39:11 +00002573
2574 /* rot_amt = shift_expr & mask */
sewardjc22a6fd2004-07-29 23:41:47 +00002575 /* By masking the rotate amount thusly, the IR-level Shl/Shr
2576 expressions never shift beyond the word size and thus remain
2577 well defined. */
sewardj7ebbdae2004-08-26 12:30:48 +00002578 assign(rot_amt32, binop(Iop_And8, shift_expr, mkU8(31)));
2579
2580 if (ty == Ity_I32)
2581 assign(rot_amt, mkexpr(rot_amt32));
2582 else
2583 assign(rot_amt, binop(Iop_And8, mkexpr(rot_amt32), mkU8(8*sz-1)));
sewardj750f4072004-07-26 22:39:11 +00002584
2585 if (left) {
sewardj1813dbe2004-07-28 17:09:04 +00002586
sewardj750f4072004-07-26 22:39:11 +00002587 /* dst1 = (dst0 << rot_amt) | (dst0 >>u (wordsize-rot_amt)) */
2588 assign(dst1,
2589 binop( mkSizedOp(ty,Iop_Or8),
2590 binop( mkSizedOp(ty,Iop_Shl8),
2591 mkexpr(dst0),
2592 mkexpr(rot_amt)
2593 ),
2594 binop( mkSizedOp(ty,Iop_Shr8),
2595 mkexpr(dst0),
2596 binop(Iop_Sub8,mkU8(8*sz), mkexpr(rot_amt))
2597 )
2598 )
2599 );
sewardj2a9ad022004-11-25 02:46:58 +00002600 ccOp += X86G_CC_OP_ROLB;
sewardj750f4072004-07-26 22:39:11 +00002601
sewardj1813dbe2004-07-28 17:09:04 +00002602 } else { /* right */
sewardj750f4072004-07-26 22:39:11 +00002603
sewardj1813dbe2004-07-28 17:09:04 +00002604 /* dst1 = (dst0 >>u rot_amt) | (dst0 << (wordsize-rot_amt)) */
2605 assign(dst1,
2606 binop( mkSizedOp(ty,Iop_Or8),
2607 binop( mkSizedOp(ty,Iop_Shr8),
2608 mkexpr(dst0),
2609 mkexpr(rot_amt)
2610 ),
2611 binop( mkSizedOp(ty,Iop_Shl8),
2612 mkexpr(dst0),
2613 binop(Iop_Sub8,mkU8(8*sz), mkexpr(rot_amt))
sewardj750f4072004-07-26 22:39:11 +00002614 )
2615 )
2616 );
sewardj2a9ad022004-11-25 02:46:58 +00002617 ccOp += X86G_CC_OP_RORB;
sewardjc22a6fd2004-07-29 23:41:47 +00002618
sewardj750f4072004-07-26 22:39:11 +00002619 }
sewardjc22a6fd2004-07-29 23:41:47 +00002620
sewardj1813dbe2004-07-28 17:09:04 +00002621 /* dst1 now holds the rotated value. Build flag thunk. We
2622 need the resulting value for this, and the previous flags.
2623 Except don't set it if the rotate count is zero. */
2624
sewardj2a9ad022004-11-25 02:46:58 +00002625 assign(oldFlags, mk_x86g_calculate_eflags_all());
sewardj1813dbe2004-07-28 17:09:04 +00002626
sewardj2a2ba8b2004-11-08 13:14:06 +00002627 /* CC_DEP1 is the rotated value. CC_NDEP is flags before. */
sewardj1813dbe2004-07-28 17:09:04 +00002628 stmt( IRStmt_Put( OFFB_CC_OP,
sewardj7ebbdae2004-08-26 12:30:48 +00002629 IRExpr_Mux0X( mkexpr(rot_amt32),
sewardj1813dbe2004-07-28 17:09:04 +00002630 IRExpr_Get(OFFB_CC_OP,Ity_I32),
2631 mkU32(ccOp))) );
sewardj2a2ba8b2004-11-08 13:14:06 +00002632 stmt( IRStmt_Put( OFFB_CC_DEP1,
sewardj7ebbdae2004-08-26 12:30:48 +00002633 IRExpr_Mux0X( mkexpr(rot_amt32),
sewardj2a2ba8b2004-11-08 13:14:06 +00002634 IRExpr_Get(OFFB_CC_DEP1,Ity_I32),
sewardjc22a6fd2004-07-29 23:41:47 +00002635 widenUto32(mkexpr(dst1)))) );
sewardj2a2ba8b2004-11-08 13:14:06 +00002636 stmt( IRStmt_Put( OFFB_CC_DEP2,
sewardj7ebbdae2004-08-26 12:30:48 +00002637 IRExpr_Mux0X( mkexpr(rot_amt32),
sewardj2a2ba8b2004-11-08 13:14:06 +00002638 IRExpr_Get(OFFB_CC_DEP2,Ity_I32),
2639 mkU32(0))) );
2640 stmt( IRStmt_Put( OFFB_CC_NDEP,
2641 IRExpr_Mux0X( mkexpr(rot_amt32),
2642 IRExpr_Get(OFFB_CC_NDEP,Ity_I32),
sewardj1813dbe2004-07-28 17:09:04 +00002643 mkexpr(oldFlags))) );
2644 } /* if (isRotate) */
sewardje90ad6a2004-07-10 19:02:10 +00002645
2646 /* Save result, and finish up. */
2647 if (epartIsReg(modrm)) {
2648 putIReg(sz, eregOfRM(modrm), mkexpr(dst1));
sewardjf48ac192004-10-29 00:41:29 +00002649 if (vex_traceflags & VEX_TRACE_FE) {
sewardje90ad6a2004-07-10 19:02:10 +00002650 vex_printf("%s%c ",
2651 nameGrp2(gregOfRM(modrm)), nameISize(sz) );
sewardj6d2638e2004-07-15 09:38:27 +00002652 if (shift_expr_txt)
2653 vex_printf("%s", shift_expr_txt);
2654 else
2655 ppIRExpr(shift_expr);
sewardje90ad6a2004-07-10 19:02:10 +00002656 vex_printf(", %s\n", nameIReg(sz,eregOfRM(modrm)));
2657 }
sewardje90ad6a2004-07-10 19:02:10 +00002658 } else {
sewardj940e8c92004-07-11 16:53:24 +00002659 storeLE(mkexpr(addr), mkexpr(dst1));
sewardjf48ac192004-10-29 00:41:29 +00002660 if (vex_traceflags & VEX_TRACE_FE) {
sewardj940e8c92004-07-11 16:53:24 +00002661 vex_printf("%s%c ",
2662 nameGrp2(gregOfRM(modrm)), nameISize(sz) );
sewardj6d2638e2004-07-15 09:38:27 +00002663 if (shift_expr_txt)
2664 vex_printf("%s", shift_expr_txt);
2665 else
2666 ppIRExpr(shift_expr);
sewardj940e8c92004-07-11 16:53:24 +00002667 vex_printf(", %s\n", dis_buf);
2668 }
sewardje90ad6a2004-07-10 19:02:10 +00002669 }
sewardje90ad6a2004-07-10 19:02:10 +00002670 return delta;
2671}
2672
2673
2674
sewardjc9a65702004-07-07 16:32:57 +00002675//-- /* Group 8 extended opcodes (but BT/BTS/BTC/BTR only). */
2676//-- static
2677//-- Addr dis_Grp8_BT ( UCodeBlock* cb,
2678//-- UChar sorb,
2679//-- Addr eip, UChar modrm,
2680//-- Int am_sz, Int sz, UInt src_val )
2681//-- {
sewardj5bd4d162004-11-10 13:02:48 +00002682# define MODIFY_t2_AND_SET_CARRY_FLAG \
2683 /* t2 is the value to be op'd on. Copy to t_fetched, then \
2684 modify t2, if non-BT. */ \
2685 uInstr2(cb, MOV, 4, TempReg, t2, TempReg, t_fetched); \
2686 uInstr2(cb, MOV, sz, Literal, 0, TempReg, t_mask); \
2687 uLiteral(cb, v_mask); \
2688 switch (gregOfRM(modrm)) { \
2689 case 4: /* BT */ break; \
2690 case 5: /* BTS */ \
2691 uInstr2(cb, OR, sz, TempReg, t_mask, TempReg, t2); break; \
2692 case 6: /* BTR */ \
2693 uInstr2(cb, AND, sz, TempReg, t_mask, TempReg, t2); break; \
2694 case 7: /* BTC */ \
2695 uInstr2(cb, XOR, sz, TempReg, t_mask, TempReg, t2); break; \
2696 } \
2697 /* Copy relevant bit from t_fetched into carry flag. */ \
2698 uInstr2(cb, SHR, sz, Literal, 0, TempReg, t_fetched); \
2699 uLiteral(cb, src_val); \
2700 uInstr2(cb, MOV, sz, Literal, 0, TempReg, t_mask); \
2701 uLiteral(cb, 1); \
2702 uInstr2(cb, AND, sz, TempReg, t_mask, TempReg, t_fetched); \
2703 uInstr1(cb, NEG, sz, TempReg, t_fetched); \
sewardjd1061ab2004-07-08 01:45:30 +00002704 setFlagsFromUOpcode(cb, NEG);
2705
2706
sewardjc9a65702004-07-07 16:32:57 +00002707//-- /* src_val denotes a d8.
2708//-- And eip on entry points at the modrm byte. */
2709//-- Int t1, t2, t_fetched, t_mask;
2710//-- UInt pair;
sewardjc9a43662004-11-30 18:51:59 +00002711//-- HChar dis_buf[50];
sewardjc9a65702004-07-07 16:32:57 +00002712//-- UInt v_mask;
2713//--
2714//-- /* There is no 1-byte form of this instruction, AFAICS. */
2715//-- vg_assert(sz == 2 || sz == 4);
2716//--
2717//-- /* Limit src_val -- the bit offset -- to something within a word.
2718//-- The Intel docs say that literal offsets larger than a word are
2719//-- masked in this way. */
2720//-- switch (sz) {
2721//-- case 2: src_val &= 15; break;
2722//-- case 4: src_val &= 31; break;
2723//-- default: VG_(core_panic)("dis_Grp8_BT: invalid size");
2724//-- }
2725//--
2726//-- /* Invent a mask suitable for the operation. */
2727//--
2728//-- switch (gregOfRM(modrm)) {
2729//-- case 4: /* BT */ v_mask = 0; break;
2730//-- case 5: /* BTS */ v_mask = 1 << src_val; break;
2731//-- case 6: /* BTR */ v_mask = ~(1 << src_val); break;
2732//-- case 7: /* BTC */ v_mask = 1 << src_val; break;
2733//-- /* If this needs to be extended, probably simplest to make a
2734//-- new function to handle the other cases (0 .. 3). The
2735//-- Intel docs do however not indicate any use for 0 .. 3, so
2736//-- we don't expect this to happen. */
2737//-- default: VG_(core_panic)("dis_Grp8_BT");
2738//-- }
2739//-- /* Probably excessively paranoid. */
2740//-- if (sz == 2)
2741//-- v_mask &= 0x0000FFFF;
2742//--
2743//-- t1 = INVALID_TEMPREG;
2744//-- t_fetched = newTemp(cb);
2745//-- t_mask = newTemp(cb);
2746//--
2747//-- if (epartIsReg(modrm)) {
2748//-- vg_assert(am_sz == 1);
2749//-- t2 = newTemp(cb);
2750//--
2751//-- /* Fetch the value to be tested and modified. */
2752//-- uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t2);
2753//-- /* Do it! */
2754//-- MODIFY_t2_AND_SET_CARRY_FLAG;
2755//-- /* Dump the result back, if non-BT. */
2756//-- if (gregOfRM(modrm) != 4 /* BT */)
2757//-- uInstr2(cb, PUT, sz, TempReg, t2, ArchReg, eregOfRM(modrm));
2758//--
2759//-- eip += (am_sz + 1);
2760//-- DIP("%s%c $0x%x, %s\n", nameGrp8(gregOfRM(modrm)), nameISize(sz),
2761//-- src_val, nameIReg(sz,eregOfRM(modrm)));
2762//-- } else {
2763//-- pair = disAMode ( cb, sorb, eip, dis_buf);
2764//-- t1 = LOW24(pair);
2765//-- t2 = newTemp(cb);
2766//-- eip += HI8(pair);
2767//-- eip += 1;
2768//--
2769//-- /* Fetch the value to be tested and modified. */
2770//-- uInstr2(cb, LOAD, sz, TempReg, t1, TempReg, t2);
2771//-- /* Do it! */
2772//-- MODIFY_t2_AND_SET_CARRY_FLAG;
2773//-- /* Dump the result back, if non-BT. */
2774//-- if (gregOfRM(modrm) != 4 /* BT */) {
2775//-- uInstr2(cb, STORE, sz, TempReg, t2, TempReg, t1);
2776//-- }
2777//-- DIP("%s%c $0x%x, %s\n", nameGrp8(gregOfRM(modrm)), nameISize(sz),
2778//-- src_val, dis_buf);
2779//-- }
2780//-- return eip;
2781//--
2782//-- # undef MODIFY_t2_AND_SET_CARRY_FLAG
2783//-- }
sewardjcf780b42004-07-13 18:42:17 +00002784
2785
2786
sewardj1813dbe2004-07-28 17:09:04 +00002787/* Signed/unsigned widening multiply. Generate IR to multiply the
2788 value in EAX/AX/AL by the given IRTemp, and park the result in
2789 EDX:EAX/DX:AX/AX.
sewardjcf780b42004-07-13 18:42:17 +00002790*/
sewardj1813dbe2004-07-28 17:09:04 +00002791static void codegen_mulL_A_D ( Int sz, Bool syned,
2792 IRTemp tmp, Char* tmp_txt )
sewardjcf780b42004-07-13 18:42:17 +00002793{
sewardjcf780b42004-07-13 18:42:17 +00002794 IRType ty = szToITy(sz);
2795 IRTemp t1 = newTemp(ty);
sewardjcf780b42004-07-13 18:42:17 +00002796
sewardj1813dbe2004-07-28 17:09:04 +00002797 assign( t1, getIReg(sz, R_EAX) );
sewardjcf780b42004-07-13 18:42:17 +00002798
2799 switch (ty) {
sewardjb81f8b32004-07-30 10:17:50 +00002800 case Ity_I32: {
2801 IRTemp res64 = newTemp(Ity_I64);
sewardj948d48b2004-11-05 19:49:09 +00002802 IRTemp resHi = newTemp(Ity_I32);
2803 IRTemp resLo = newTemp(Ity_I32);
sewardjb81f8b32004-07-30 10:17:50 +00002804 IROp mulOp = syned ? Iop_MullS32 : Iop_MullU32;
sewardj2a9ad022004-11-25 02:46:58 +00002805 UInt tBaseOp = syned ? X86G_CC_OP_SMULB : X86G_CC_OP_UMULB;
sewardj2a2ba8b2004-11-08 13:14:06 +00002806 setFlags_MUL ( Ity_I32, t1, tmp, tBaseOp );
sewardjb81f8b32004-07-30 10:17:50 +00002807 assign( res64, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
sewardj948d48b2004-11-05 19:49:09 +00002808 assign( resHi, unop(Iop_64HIto32,mkexpr(res64)));
2809 assign( resLo, unop(Iop_64to32,mkexpr(res64)));
sewardj948d48b2004-11-05 19:49:09 +00002810 putIReg(4, R_EDX, mkexpr(resHi));
2811 putIReg(4, R_EAX, mkexpr(resLo));
sewardjb81f8b32004-07-30 10:17:50 +00002812 break;
2813 }
2814 case Ity_I16: {
2815 IRTemp res32 = newTemp(Ity_I32);
sewardj948d48b2004-11-05 19:49:09 +00002816 IRTemp resHi = newTemp(Ity_I16);
2817 IRTemp resLo = newTemp(Ity_I16);
sewardjb81f8b32004-07-30 10:17:50 +00002818 IROp mulOp = syned ? Iop_MullS16 : Iop_MullU16;
sewardj2a9ad022004-11-25 02:46:58 +00002819 UInt tBaseOp = syned ? X86G_CC_OP_SMULB : X86G_CC_OP_UMULB;
sewardj2a2ba8b2004-11-08 13:14:06 +00002820 setFlags_MUL ( Ity_I16, t1, tmp, tBaseOp );
sewardjb81f8b32004-07-30 10:17:50 +00002821 assign( res32, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
sewardj948d48b2004-11-05 19:49:09 +00002822 assign( resHi, unop(Iop_32HIto16,mkexpr(res32)));
2823 assign( resLo, unop(Iop_32to16,mkexpr(res32)));
sewardj948d48b2004-11-05 19:49:09 +00002824 putIReg(2, R_EDX, mkexpr(resHi));
2825 putIReg(2, R_EAX, mkexpr(resLo));
sewardjb81f8b32004-07-30 10:17:50 +00002826 break;
2827 }
2828 case Ity_I8: {
2829 IRTemp res16 = newTemp(Ity_I16);
sewardj948d48b2004-11-05 19:49:09 +00002830 IRTemp resHi = newTemp(Ity_I8);
2831 IRTemp resLo = newTemp(Ity_I8);
sewardjb81f8b32004-07-30 10:17:50 +00002832 IROp mulOp = syned ? Iop_MullS8 : Iop_MullU8;
sewardj2a9ad022004-11-25 02:46:58 +00002833 UInt tBaseOp = syned ? X86G_CC_OP_SMULB : X86G_CC_OP_UMULB;
sewardj2a2ba8b2004-11-08 13:14:06 +00002834 setFlags_MUL ( Ity_I8, t1, tmp, tBaseOp );
sewardjb81f8b32004-07-30 10:17:50 +00002835 assign( res16, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
sewardj948d48b2004-11-05 19:49:09 +00002836 assign( resHi, unop(Iop_16HIto8,mkexpr(res16)));
2837 assign( resLo, unop(Iop_16to8,mkexpr(res16)));
sewardjb81f8b32004-07-30 10:17:50 +00002838 putIReg(2, R_EAX, mkexpr(res16));
2839 break;
2840 }
2841 default:
2842 vpanic("codegen_mulL_A_D(x86)");
sewardjcf780b42004-07-13 18:42:17 +00002843 }
sewardj1813dbe2004-07-28 17:09:04 +00002844 DIP("%s%c %s\n", syned ? "imul" : "mul", nameISize(sz), tmp_txt);
sewardjcf780b42004-07-13 18:42:17 +00002845}
2846
sewardj940e8c92004-07-11 16:53:24 +00002847
2848/* Group 3 extended opcodes. */
2849static
2850UInt dis_Grp3 ( UChar sorb, Int sz, UInt delta )
2851{
sewardjc9a43662004-11-30 18:51:59 +00002852 UInt d32;
2853 UChar modrm;
2854 HChar dis_buf[50];
2855 Int len;
sewardjc2ac51e2004-07-12 01:03:26 +00002856 IRTemp addr;
sewardj940e8c92004-07-11 16:53:24 +00002857 IRType ty = szToITy(sz);
2858 IRTemp t1 = newTemp(ty);
sewardj92d168d2004-11-15 14:22:12 +00002859 // IRTemp t2 = IRTemp_INVALID;
sewardj940e8c92004-07-11 16:53:24 +00002860 IRTemp dst1, src, dst0;
2861 modrm = getIByte(delta);
2862 if (epartIsReg(modrm)) {
2863 switch (gregOfRM(modrm)) {
sewardjc2ac51e2004-07-12 01:03:26 +00002864 case 0: { /* TEST */
2865 delta++; d32 = getUDisp(sz, delta); delta += sz;
sewardj5bd4d162004-11-10 13:02:48 +00002866 dst1 = newTemp(ty);
2867 assign(dst1, binop(mkSizedOp(ty,Iop_And8),
2868 getIReg(sz,eregOfRM(modrm)),
sewardjc2ac51e2004-07-12 01:03:26 +00002869 mkU(ty,d32)));
sewardj5bd4d162004-11-10 13:02:48 +00002870 setFlags_DEP1( Iop_And8, dst1, ty );
sewardjc2ac51e2004-07-12 01:03:26 +00002871 DIP("test%c $0x%x, %s\n", nameISize(sz), d32,
2872 nameIReg(sz, eregOfRM(modrm)));
2873 break;
2874 }
sewardj940e8c92004-07-11 16:53:24 +00002875 case 2: /* NOT */
2876 delta++;
2877 putIReg(sz, eregOfRM(modrm),
2878 unop(mkSizedOp(ty,Iop_Not8),
2879 getIReg(sz, eregOfRM(modrm))));
2880 DIP("not%c %s\n", nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
2881 break;
2882 case 3: /* NEG */
2883 delta++;
2884 dst0 = newTemp(ty);
2885 src = newTemp(ty);
2886 dst1 = newTemp(ty);
sewardj5bd4d162004-11-10 13:02:48 +00002887 assign(dst0, mkU(ty,0));
sewardja511afc2004-07-29 22:26:03 +00002888 assign(src, getIReg(sz,eregOfRM(modrm)));
sewardj5bd4d162004-11-10 13:02:48 +00002889 assign(dst1, binop(mkSizedOp(ty,Iop_Sub8), mkexpr(dst0), mkexpr(src)));
sewardj2a2ba8b2004-11-08 13:14:06 +00002890 setFlags_DEP1_DEP2(Iop_Sub8, dst0, src, ty);
sewardj5bd4d162004-11-10 13:02:48 +00002891 putIReg(sz, eregOfRM(modrm), mkexpr(dst1));
sewardj940e8c92004-07-11 16:53:24 +00002892 DIP("neg%c %s\n", nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
2893 break;
sewardjcf780b42004-07-13 18:42:17 +00002894 case 4: /* MUL (unsigned widening) */
2895 delta++;
sewardj1813dbe2004-07-28 17:09:04 +00002896 src = newTemp(ty);
sewardj5bd4d162004-11-10 13:02:48 +00002897 assign(src, getIReg(sz,eregOfRM(modrm)));
sewardj1813dbe2004-07-28 17:09:04 +00002898 codegen_mulL_A_D ( sz, False, src, nameIReg(sz,eregOfRM(modrm)) );
sewardjcf780b42004-07-13 18:42:17 +00002899 break;
sewardjcaca9d02004-07-28 07:11:32 +00002900 case 5: /* IMUL (signed widening) */
2901 delta++;
sewardj1813dbe2004-07-28 17:09:04 +00002902 src = newTemp(ty);
sewardj5bd4d162004-11-10 13:02:48 +00002903 assign(src, getIReg(sz,eregOfRM(modrm)));
sewardj1813dbe2004-07-28 17:09:04 +00002904 codegen_mulL_A_D ( sz, True, src, nameIReg(sz,eregOfRM(modrm)) );
sewardjcaca9d02004-07-28 07:11:32 +00002905 break;
sewardj68511542004-07-28 00:15:44 +00002906 case 6: /* DIV */
2907 delta++;
2908 assign( t1, getIReg(sz, eregOfRM(modrm)) );
2909 codegen_div ( sz, t1, False );
2910 DIP("div%c %s\n", nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
2911 break;
sewardjcaca9d02004-07-28 07:11:32 +00002912 case 7: /* IDIV */
2913 delta++;
2914 assign( t1, getIReg(sz, eregOfRM(modrm)) );
2915 codegen_div ( sz, t1, True );
2916 DIP("idiv%c %s\n", nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
2917 break;
sewardj940e8c92004-07-11 16:53:24 +00002918 default:
2919 vex_printf(
2920 "unhandled Grp3(R) case %d\n", (UInt)gregOfRM(modrm));
2921 vpanic("Grp3(x86)");
2922 }
2923 } else {
sewardjc2ac51e2004-07-12 01:03:26 +00002924 addr = disAMode ( &len, sorb, delta, dis_buf );
2925 t1 = newTemp(ty);
2926 delta += len;
2927 assign(t1, loadLE(ty,mkexpr(addr)));
2928 switch (gregOfRM(modrm)) {
2929 case 0: { /* TEST */
2930 d32 = getUDisp(sz, delta); delta += sz;
sewardj5bd4d162004-11-10 13:02:48 +00002931 dst1 = newTemp(ty);
2932 assign(dst1, binop(mkSizedOp(ty,Iop_And8),
2933 mkexpr(t1), mkU(ty,d32)));
2934 setFlags_DEP1( Iop_And8, dst1, ty );
sewardjc2ac51e2004-07-12 01:03:26 +00002935 DIP("test%c $0x%x, %s\n", nameISize(sz), d32, dis_buf);
2936 break;
2937 }
sewardj78fe7912004-08-20 23:38:07 +00002938 /* probably OK, but awaiting test case */
2939 case 2: /* NOT */
2940 storeLE( mkexpr(addr), unop(mkSizedOp(ty,Iop_Not8), mkexpr(t1)));
2941 DIP("not%c %s\n", nameISize(sz), dis_buf);
2942 break;
sewardj0c12ea82004-07-12 08:18:16 +00002943 case 3: /* NEG */
2944 dst0 = newTemp(ty);
2945 src = newTemp(ty);
2946 dst1 = newTemp(ty);
sewardj5bd4d162004-11-10 13:02:48 +00002947 assign(dst0, mkU(ty,0));
sewardja511afc2004-07-29 22:26:03 +00002948 assign(src, mkexpr(t1));
sewardj5bd4d162004-11-10 13:02:48 +00002949 assign(dst1, binop(mkSizedOp(ty,Iop_Sub8), mkexpr(dst0), mkexpr(src)));
sewardj2a2ba8b2004-11-08 13:14:06 +00002950 setFlags_DEP1_DEP2(Iop_Sub8, dst0, src, ty);
sewardj5bd4d162004-11-10 13:02:48 +00002951 storeLE( mkexpr(addr), mkexpr(dst1) );
sewardj0c12ea82004-07-12 08:18:16 +00002952 DIP("neg%c %s\n", nameISize(sz), dis_buf);
2953 break;
sewardj1813dbe2004-07-28 17:09:04 +00002954 case 4: /* MUL */
2955 codegen_mulL_A_D ( sz, False, t1, dis_buf );
2956 break;
2957 case 5: /* IMUL */
2958 codegen_mulL_A_D ( sz, True, t1, dis_buf );
2959 break;
sewardj9690d922004-07-14 01:39:17 +00002960 case 6: /* DIV */
2961 codegen_div ( sz, t1, False );
2962 DIP("div%c %s\n", nameISize(sz), dis_buf);
2963 break;
sewardj1813dbe2004-07-28 17:09:04 +00002964 case 7: /* IDIV */
2965 codegen_div ( sz, t1, True );
2966 DIP("idiv%c %s\n", nameISize(sz), dis_buf);
2967 break;
sewardjc2ac51e2004-07-12 01:03:26 +00002968 default:
2969 vex_printf(
2970 "unhandled Grp3(M) case %d\n", (UInt)gregOfRM(modrm));
2971 vpanic("Grp3(x86)");
2972 }
sewardj940e8c92004-07-11 16:53:24 +00002973 }
2974 return delta;
2975}
2976
2977
sewardjc2ac51e2004-07-12 01:03:26 +00002978/* Group 4 extended opcodes. */
2979static
2980UInt dis_Grp4 ( UChar sorb, UInt delta )
2981{
sewardjc9a43662004-11-30 18:51:59 +00002982 Int alen;
sewardjc2ac51e2004-07-12 01:03:26 +00002983 UChar modrm;
sewardjc9a43662004-11-30 18:51:59 +00002984 HChar dis_buf[50];
sewardjc2ac51e2004-07-12 01:03:26 +00002985 IRType ty = Ity_I8;
sewardj7ed22952004-07-29 00:09:58 +00002986 IRTemp t1 = newTemp(ty);
2987 IRTemp t2 = newTemp(ty);
sewardjc2ac51e2004-07-12 01:03:26 +00002988
2989 modrm = getIByte(delta);
2990 if (epartIsReg(modrm)) {
sewardjc2ac51e2004-07-12 01:03:26 +00002991 assign(t1, getIReg(1, eregOfRM(modrm)));
2992 switch (gregOfRM(modrm)) {
sewardj7ed22952004-07-29 00:09:58 +00002993 case 0: /* INC */
2994 assign(t2, binop(Iop_Add8, mkexpr(t1), mkU8(1)));
2995 putIReg(1, eregOfRM(modrm), mkexpr(t2));
2996 setFlags_INC_DEC( True, t2, ty );
2997 break;
sewardjc2ac51e2004-07-12 01:03:26 +00002998 case 1: /* DEC */
sewardjc2ac51e2004-07-12 01:03:26 +00002999 assign(t2, binop(Iop_Sub8, mkexpr(t1), mkU8(1)));
3000 putIReg(1, eregOfRM(modrm), mkexpr(t2));
3001 setFlags_INC_DEC( False, t2, ty );
3002 break;
3003 default:
3004 vex_printf(
3005 "unhandled Grp4(R) case %d\n", (UInt)gregOfRM(modrm));
sewardj7ed22952004-07-29 00:09:58 +00003006 vpanic("Grp4(x86,R)");
sewardjc2ac51e2004-07-12 01:03:26 +00003007 }
3008 delta++;
3009 DIP("%sb %s\n", nameGrp4(gregOfRM(modrm)),
3010 nameIReg(1, eregOfRM(modrm)));
3011 } else {
sewardj7ed22952004-07-29 00:09:58 +00003012 IRTemp addr = disAMode ( &alen, sorb, delta, dis_buf );
3013 assign( t1, loadLE(ty, mkexpr(addr)) );
3014 switch (gregOfRM(modrm)) {
sewardj588ea762004-09-10 18:56:32 +00003015 case 0: /* INC */
3016 assign(t2, binop(Iop_Add8, mkexpr(t1), mkU8(1)));
3017 storeLE( mkexpr(addr), mkexpr(t2) );
3018 setFlags_INC_DEC( True, t2, ty );
3019 break;
sewardj7ed22952004-07-29 00:09:58 +00003020 case 1: /* DEC */
3021 assign(t2, binop(Iop_Sub8, mkexpr(t1), mkU8(1)));
3022 storeLE( mkexpr(addr), mkexpr(t2) );
3023 setFlags_INC_DEC( False, t2, ty );
3024 break;
3025 default:
3026 vex_printf(
3027 "unhandled Grp4(M) case %d\n", (UInt)gregOfRM(modrm));
3028 vpanic("Grp4(x86,M)");
3029 }
3030 delta += alen;
3031 DIP("%sb %s\n", nameGrp4(gregOfRM(modrm)), dis_buf);
sewardjc2ac51e2004-07-12 01:03:26 +00003032 }
3033 return delta;
3034}
sewardj0611d802004-07-11 02:37:54 +00003035
3036
3037/* Group 5 extended opcodes. */
3038static
sewardjce70a5c2004-10-18 14:09:54 +00003039UInt dis_Grp5 ( UChar sorb, Int sz, UInt delta, DisResult* whatNext )
sewardj0611d802004-07-11 02:37:54 +00003040{
3041 Int len;
3042 UChar modrm;
sewardjc9a43662004-11-30 18:51:59 +00003043 HChar dis_buf[50];
sewardj92d168d2004-11-15 14:22:12 +00003044 IRTemp addr = IRTemp_INVALID;
sewardj0611d802004-07-11 02:37:54 +00003045 IRType ty = szToITy(sz);
3046 IRTemp t1 = newTemp(ty);
sewardj92d168d2004-11-15 14:22:12 +00003047 IRTemp t2 = IRTemp_INVALID;
sewardj0611d802004-07-11 02:37:54 +00003048
3049 modrm = getIByte(delta);
3050 if (epartIsReg(modrm)) {
sewardj940e8c92004-07-11 16:53:24 +00003051 assign(t1, getIReg(sz,eregOfRM(modrm)));
sewardj0611d802004-07-11 02:37:54 +00003052 switch (gregOfRM(modrm)) {
sewardjc9a65702004-07-07 16:32:57 +00003053//-- case 0: /* INC */
3054//-- uInstr1(cb, INC, sz, TempReg, t1);
3055//-- setFlagsFromUOpcode(cb, INC);
3056//-- uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, eregOfRM(modrm));
3057//-- break;
3058//-- case 1: /* DEC */
3059//-- uInstr1(cb, DEC, sz, TempReg, t1);
3060//-- setFlagsFromUOpcode(cb, DEC);
3061//-- uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, eregOfRM(modrm));
3062//-- break;
sewardjc2ac51e2004-07-12 01:03:26 +00003063 case 2: /* call Ev */
3064 vassert(sz == 4);
3065 t2 = newTemp(Ity_I32);
3066 assign(t2, binop(Iop_Sub32, getIReg(4,R_ESP), mkU32(4)));
3067 putIReg(4, R_ESP, mkexpr(t2));
sewardj5bd4d162004-11-10 13:02:48 +00003068 storeLE( mkexpr(t2), mkU32(guest_eip_bbstart+delta+1));
3069 jmp_treg(Ijk_Call,t1);
sewardjce70a5c2004-10-18 14:09:54 +00003070 *whatNext = Dis_StopHere;
sewardjc2ac51e2004-07-12 01:03:26 +00003071 break;
sewardj0611d802004-07-11 02:37:54 +00003072 case 4: /* jmp Ev */
3073 vassert(sz == 4);
sewardj78c19df2004-07-12 22:49:27 +00003074 jmp_treg(Ijk_Boring,t1);
sewardjce70a5c2004-10-18 14:09:54 +00003075 *whatNext = Dis_StopHere;
sewardj0611d802004-07-11 02:37:54 +00003076 break;
3077 default:
3078 vex_printf(
3079 "unhandled Grp5(R) case %d\n", (UInt)gregOfRM(modrm));
3080 vpanic("Grp5(x86)");
3081 }
3082 delta++;
3083 DIP("%s%c %s\n", nameGrp5(gregOfRM(modrm)),
3084 nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
3085 } else {
3086 addr = disAMode ( &len, sorb, delta, dis_buf );
sewardj940e8c92004-07-11 16:53:24 +00003087 assign(t1, loadLE(ty,mkexpr(addr)));
sewardj0611d802004-07-11 02:37:54 +00003088 switch (gregOfRM(modrm)) {
3089 case 0: /* INC */
3090 t2 = newTemp(ty);
3091 assign(t2, binop(mkSizedOp(ty,Iop_Add8),
3092 mkexpr(t1), mkU(ty,1)));
3093 setFlags_INC_DEC( True, t2, ty );
sewardj940e8c92004-07-11 16:53:24 +00003094 storeLE(mkexpr(addr),mkexpr(t2));
sewardj0611d802004-07-11 02:37:54 +00003095 break;
sewardjc2ac51e2004-07-12 01:03:26 +00003096 case 1: /* DEC */
3097 t2 = newTemp(ty);
3098 assign(t2, binop(mkSizedOp(ty,Iop_Sub8),
3099 mkexpr(t1), mkU(ty,1)));
3100 setFlags_INC_DEC( False, t2, ty );
3101 storeLE(mkexpr(addr),mkexpr(t2));
3102 break;
sewardj77b86be2004-07-11 13:28:24 +00003103 case 2: /* call Ev */
3104 vassert(sz == 4);
3105 t2 = newTemp(Ity_I32);
3106 assign(t2, binop(Iop_Sub32, getIReg(4,R_ESP), mkU32(4)));
3107 putIReg(4, R_ESP, mkexpr(t2));
sewardj5bd4d162004-11-10 13:02:48 +00003108 storeLE( mkexpr(t2), mkU32(guest_eip_bbstart+delta+len));
3109 jmp_treg(Ijk_Call,t1);
sewardjce70a5c2004-10-18 14:09:54 +00003110 *whatNext = Dis_StopHere;
sewardj77b86be2004-07-11 13:28:24 +00003111 break;
3112 case 4: /* JMP Ev */
3113 vassert(sz == 4);
sewardj78c19df2004-07-12 22:49:27 +00003114 jmp_treg(Ijk_Boring,t1);
sewardjce70a5c2004-10-18 14:09:54 +00003115 *whatNext = Dis_StopHere;
sewardj77b86be2004-07-11 13:28:24 +00003116 break;
sewardj0c12ea82004-07-12 08:18:16 +00003117 case 6: /* PUSH Ev */
3118 vassert(sz == 4 || sz == 2);
3119 t2 = newTemp(Ity_I32);
3120 assign( t2, binop(Iop_Sub32,getIReg(4,R_ESP),mkU32(sz)) );
3121 putIReg(4, R_ESP, mkexpr(t2) );
sewardj5bd4d162004-11-10 13:02:48 +00003122 storeLE( mkexpr(t2), mkexpr(t1) );
sewardj0c12ea82004-07-12 08:18:16 +00003123 break;
sewardj0611d802004-07-11 02:37:54 +00003124 default:
3125 vex_printf(
3126 "unhandled Grp5(M) case %d\n", (UInt)gregOfRM(modrm));
3127 vpanic("Grp5(x86)");
3128 }
3129 delta += len;
3130 DIP("%s%c %s\n", nameGrp5(gregOfRM(modrm)),
3131 nameISize(sz), dis_buf);
3132 }
3133 return delta;
3134}
3135
sewardj464efa42004-11-19 22:17:29 +00003136
sewardj64e1d652004-07-12 14:00:46 +00003137/*------------------------------------------------------------*/
3138/*--- Disassembling string ops (including REP prefixes) ---*/
3139/*------------------------------------------------------------*/
3140
3141/* Code shared by all the string ops */
3142static
3143void dis_string_op_increment(Int sz, Int t_inc)
3144{
3145 if (sz == 4 || sz == 2) {
3146 assign( t_inc,
3147 binop(Iop_Shl32, IRExpr_Get( OFFB_DFLAG, Ity_I32 ),
sewardj6d2638e2004-07-15 09:38:27 +00003148 mkU8(sz/2) ) );
sewardj64e1d652004-07-12 14:00:46 +00003149 } else {
3150 assign( t_inc,
3151 IRExpr_Get( OFFB_DFLAG, Ity_I32 ) );
3152 }
3153}
3154
sewardj64e1d652004-07-12 14:00:46 +00003155static
3156void dis_string_op( void (*dis_OP)( Int, IRTemp ),
3157 Int sz, Char* name, UChar sorb )
3158{
3159 IRTemp t_inc = newTemp(Ity_I32);
3160 vassert(sorb == 0);
3161 dis_string_op_increment(sz, t_inc);
3162 dis_OP( sz, t_inc );
3163 DIP("%s%c\n", name, nameISize(sz));
3164}
sewardj64e1d652004-07-12 14:00:46 +00003165
3166static
3167void dis_MOVS ( Int sz, IRTemp t_inc )
3168{
3169 IRType ty = szToITy(sz);
3170 //IRTemp tv = newTemp(ty); /* value being copied */
3171 IRTemp td = newTemp(Ity_I32); /* EDI */
3172 IRTemp ts = newTemp(Ity_I32); /* ESI */
3173
3174 //uInstr2(cb, GET, 4, ArchReg, R_EDI, TempReg, td);
3175 //uInstr2(cb, GET, 4, ArchReg, R_ESI, TempReg, ts);
3176 assign( td, getIReg(4, R_EDI) );
3177 assign( ts, getIReg(4, R_ESI) );
3178
3179 //uInstr2(cb, LOAD, sz, TempReg, ts, TempReg, tv);
3180 //uInstr2(cb, STORE,sz, TempReg, tv, TempReg, td);
3181 storeLE( mkexpr(td), loadLE(ty,mkexpr(ts)) );
3182
3183 //uInstr2(cb, ADD, 4, TempReg, t_inc, TempReg, td);
3184 //uInstr2(cb, ADD, 4, TempReg, t_inc, TempReg, ts);
3185
3186 //uInstr2(cb, PUT, 4, TempReg, td, ArchReg, R_EDI);
3187 //uInstr2(cb, PUT, 4, TempReg, ts, ArchReg, R_ESI);
3188 putIReg( 4, R_EDI, binop(Iop_Add32, mkexpr(td), mkexpr(t_inc)) );
3189 putIReg( 4, R_ESI, binop(Iop_Add32, mkexpr(ts), mkexpr(t_inc)) );
3190}
3191
sewardjc9a65702004-07-07 16:32:57 +00003192//-- static
3193//-- void dis_LODS ( UCodeBlock* cb, Int sz, Int t_inc )
3194//-- {
3195//-- Int ta = newTemp(cb); /* EAX */
3196//-- Int ts = newTemp(cb); /* ESI */
3197//--
3198//-- uInstr2(cb, GET, 4, ArchReg, R_ESI, TempReg, ts);
3199//-- uInstr2(cb, LOAD, sz, TempReg, ts, TempReg, ta);
3200//-- uInstr2(cb, PUT, sz, TempReg, ta, ArchReg, R_EAX);
3201//--
3202//-- uInstr2(cb, ADD, 4, TempReg, t_inc, TempReg, ts);
3203//-- uInstr2(cb, PUT, 4, TempReg, ts, ArchReg, R_ESI);
3204//-- }
sewardj64e1d652004-07-12 14:00:46 +00003205
3206static
3207void dis_STOS ( Int sz, IRTemp t_inc )
3208{
3209 IRType ty = szToITy(sz);
3210 IRTemp ta = newTemp(ty); /* EAX */
3211 IRTemp td = newTemp(Ity_I32); /* EDI */
3212
3213 //uInstr2(cb, GET, sz, ArchReg, R_EAX, TempReg, ta);
3214 assign( ta, getIReg(sz, R_EAX) );
3215
3216 //uInstr2(cb, GET, 4, ArchReg, R_EDI, TempReg, td);
3217 assign( td, getIReg(4, R_EDI) );
3218
3219 //uInstr2(cb, STORE, sz, TempReg, ta, TempReg, td);
sewardj6d2638e2004-07-15 09:38:27 +00003220 storeLE( mkexpr(td), mkexpr(ta) );
sewardj64e1d652004-07-12 14:00:46 +00003221
3222 //uInstr2(cb, ADD, 4, TempReg, t_inc, TempReg, td);
3223 //uInstr2(cb, PUT, 4, TempReg, td, ArchReg, R_EDI);
3224 putIReg( 4, R_EDI, binop(Iop_Add32, mkexpr(td), mkexpr(t_inc)) );
3225}
3226
3227static
3228void dis_CMPS ( Int sz, IRTemp t_inc )
3229{
3230 IRType ty = szToITy(sz);
sewardj6d2638e2004-07-15 09:38:27 +00003231 IRTemp tdv = newTemp(ty); /* (EDI) */
3232 IRTemp tsv = newTemp(ty); /* (ESI) */
sewardj2a2ba8b2004-11-08 13:14:06 +00003233 //IRTemp res = newTemp(ty);
sewardj64e1d652004-07-12 14:00:46 +00003234 IRTemp td = newTemp(Ity_I32); /* EDI */
3235 IRTemp ts = newTemp(Ity_I32); /* ESI */
3236
3237 //uInstr2(cb, GET, 4, ArchReg, R_EDI, TempReg, td);
3238 assign( td, getIReg(4, R_EDI) );
3239
3240 //uInstr2(cb, GET, 4, ArchReg, R_ESI, TempReg, ts);
3241 assign( ts, getIReg(4, R_ESI) );
3242
3243 //uInstr2(cb, LOAD, sz, TempReg, td, TempReg, tdv);
3244 assign( tdv, loadLE(ty,mkexpr(td)) );
3245
3246 //uInstr2(cb, LOAD, sz, TempReg, ts, TempReg, tsv);
sewardjb9c5cf62004-08-24 15:10:38 +00003247 assign( tsv, loadLE(ty,mkexpr(ts)) );
sewardj64e1d652004-07-12 14:00:46 +00003248
3249 //uInstr2(cb, SUB, sz, TempReg, tdv, TempReg, tsv);
3250 //setFlagsFromUOpcode(cb, SUB);
sewardj2a2ba8b2004-11-08 13:14:06 +00003251 //assign( res, binop(mkSizedOp(ty, Iop_Sub8), mkexpr(tsv), mkexpr(tdv)) );
3252 setFlags_DEP1_DEP2 ( Iop_Sub8, tsv, tdv, ty );
sewardj64e1d652004-07-12 14:00:46 +00003253
3254 //uInstr2(cb, ADD, 4, TempReg, t_inc, TempReg, td);
3255 //uInstr2(cb, ADD, 4, TempReg, t_inc, TempReg, ts);
3256
3257 //uInstr2(cb, PUT, 4, TempReg, td, ArchReg, R_EDI);
3258 putIReg(4, R_EDI, binop(Iop_Add32, mkexpr(td), mkexpr(t_inc)) );
3259
3260 //uInstr2(cb, PUT, 4, TempReg, ts, ArchReg, R_ESI);
3261 putIReg(4, R_ESI, binop(Iop_Add32, mkexpr(ts), mkexpr(t_inc)) );
3262}
3263
sewardj64e1d652004-07-12 14:00:46 +00003264static
3265void dis_SCAS ( Int sz, IRTemp t_inc )
3266{
3267 IRType ty = szToITy(sz);
sewardj82292882004-07-27 00:15:59 +00003268 IRTemp ta = newTemp(ty); /* EAX */
sewardj64e1d652004-07-12 14:00:46 +00003269 IRTemp td = newTemp(Ity_I32); /* EDI */
3270 IRTemp tdv = newTemp(ty); /* (EDI) */
sewardj2a2ba8b2004-11-08 13:14:06 +00003271 //IRTemp res = newTemp(ty);
sewardj64e1d652004-07-12 14:00:46 +00003272
3273 //uInstr2(cb, GET, sz, ArchReg, R_EAX, TempReg, ta);
sewardjb9c5cf62004-08-24 15:10:38 +00003274 assign( ta, getIReg(sz, R_EAX) );
sewardj64e1d652004-07-12 14:00:46 +00003275
3276 //uInstr2(cb, GET, 4, ArchReg, R_EDI, TempReg, td);
3277 assign( td, getIReg(4, R_EDI) );
3278
3279 //uInstr2(cb, LOAD, sz, TempReg, td, TempReg, tdv);
3280 assign( tdv, loadLE(ty,mkexpr(td)) );
3281
sewardj64e1d652004-07-12 14:00:46 +00003282 //uInstr2(cb, SUB, sz, TempReg, tdv, TempReg, ta);
3283 //setFlagsFromUOpcode(cb, SUB);
sewardj2a2ba8b2004-11-08 13:14:06 +00003284 //assign( res, binop(mkSizedOp(ty, Iop_Sub8), mkexpr(ta), mkexpr(tdv)) );
3285 setFlags_DEP1_DEP2 ( Iop_Sub8, ta, tdv, ty );
sewardj64e1d652004-07-12 14:00:46 +00003286
3287 //uInstr2(cb, ADD, 4, TempReg, t_inc, TempReg, td);
3288 //uInstr2(cb, PUT, 4, TempReg, td, ArchReg, R_EDI);
3289 putIReg(4, R_EDI, binop(Iop_Add32, mkexpr(td), mkexpr(t_inc)) );
3290}
sewardj82292882004-07-27 00:15:59 +00003291
sewardj64e1d652004-07-12 14:00:46 +00003292
3293/* Wrap the appropriate string op inside a REP/REPE/REPNE.
3294 We assume the insn is the last one in the basic block, and so emit a jump
3295 to the next insn, rather than just falling through. */
3296static
sewardj2a9ad022004-11-25 02:46:58 +00003297void dis_REP_op ( X86Condcode cond,
sewardj64e1d652004-07-12 14:00:46 +00003298 void (*dis_OP)(Int, IRTemp),
3299 Int sz, Addr32 eip, Addr32 eip_next, Char* name )
3300{
3301 IRTemp t_inc = newTemp(Ity_I32);
3302 IRTemp tc = newTemp(Ity_I32); /* ECX */
3303
3304 //uInstr2 (cb, GET, 4, ArchReg, R_ECX, TempReg, tc);
3305 assign( tc, getIReg(4,R_ECX) );
3306
3307 //uInstr2 (cb, JIFZ, 4, TempReg, tc, Literal, 0);
3308 //uLiteral(cb, eip_next);
3309 stmt( IRStmt_Exit( binop(Iop_CmpEQ32,mkexpr(tc),mkU32(0)),
sewardj893aada2004-11-29 19:57:54 +00003310 Ijk_Boring,
sewardj64e1d652004-07-12 14:00:46 +00003311 IRConst_U32(eip_next) ) );
3312
3313 //uInstr1 (cb, DEC, 4, TempReg, tc);
3314 //uInstr2 (cb, PUT, 4, TempReg, tc, ArchReg, R_ECX);
3315 putIReg(4, R_ECX, binop(Iop_Sub32, mkexpr(tc), mkU32(1)) );
3316
3317 dis_string_op_increment(sz, t_inc);
3318 dis_OP (sz, t_inc);
3319
sewardj2a9ad022004-11-25 02:46:58 +00003320 if (cond == X86CondAlways) {
sewardj78c19df2004-07-12 22:49:27 +00003321 jmp_lit(Ijk_Boring,eip);
sewardj64e1d652004-07-12 14:00:46 +00003322 } else {
sewardj2a9ad022004-11-25 02:46:58 +00003323 stmt( IRStmt_Exit( mk_x86g_calculate_condition(cond),
sewardj893aada2004-11-29 19:57:54 +00003324 Ijk_Boring,
sewardj5bd4d162004-11-10 13:02:48 +00003325 IRConst_U32(eip) ) );
sewardj78c19df2004-07-12 22:49:27 +00003326 jmp_lit(Ijk_Boring,eip_next);
sewardj64e1d652004-07-12 14:00:46 +00003327 }
3328 DIP("%s%c\n", name, nameISize(sz));
3329}
3330
sewardj464efa42004-11-19 22:17:29 +00003331
sewardj64e1d652004-07-12 14:00:46 +00003332/*------------------------------------------------------------*/
3333/*--- Arithmetic, etc. ---*/
3334/*------------------------------------------------------------*/
3335
sewardj2a2ba8b2004-11-08 13:14:06 +00003336/* IMUL E, G. Supplied eip points to the modR/M byte. */
sewardjcf780b42004-07-13 18:42:17 +00003337static
3338UInt dis_mul_E_G ( UChar sorb,
3339 Int size,
sewardj2a2ba8b2004-11-08 13:14:06 +00003340 UInt delta0 )
sewardjcf780b42004-07-13 18:42:17 +00003341{
sewardj71a65362004-07-28 01:48:34 +00003342 Int alen;
sewardjc9a43662004-11-30 18:51:59 +00003343 HChar dis_buf[50];
sewardjcf780b42004-07-13 18:42:17 +00003344 UChar rm = getIByte(delta0);
3345 IRType ty = szToITy(size);
sewardj6d2638e2004-07-15 09:38:27 +00003346 IRTemp te = newTemp(ty);
3347 IRTemp tg = newTemp(ty);
sewardj948d48b2004-11-05 19:49:09 +00003348 IRTemp resLo = newTemp(ty);
sewardj71a65362004-07-28 01:48:34 +00003349
sewardj948d48b2004-11-05 19:49:09 +00003350 assign( tg, getIReg(size, gregOfRM(rm)) );
sewardjcf780b42004-07-13 18:42:17 +00003351 if (epartIsReg(rm)) {
sewardjcf780b42004-07-13 18:42:17 +00003352 assign( te, getIReg(size, eregOfRM(rm)) );
sewardj948d48b2004-11-05 19:49:09 +00003353 } else {
3354 IRTemp addr = disAMode( &alen, sorb, delta0, dis_buf );
3355 assign( te, loadLE(ty,mkexpr(addr)) );
3356 }
sewardjcf780b42004-07-13 18:42:17 +00003357
sewardj2a9ad022004-11-25 02:46:58 +00003358 setFlags_MUL ( ty, te, tg, X86G_CC_OP_SMULB );
sewardj948d48b2004-11-05 19:49:09 +00003359
sewardj2a2ba8b2004-11-08 13:14:06 +00003360 assign( resLo, binop( mkSizedOp(ty, Iop_Mul8), mkexpr(te), mkexpr(tg) ) );
sewardj948d48b2004-11-05 19:49:09 +00003361
3362 putIReg(size, gregOfRM(rm), mkexpr(resLo) );
3363
3364 if (epartIsReg(rm)) {
sewardj2a2ba8b2004-11-08 13:14:06 +00003365 DIP("imul%c %s, %s\n", nameISize(size),
3366 nameIReg(size,eregOfRM(rm)),
3367 nameIReg(size,gregOfRM(rm)));
sewardjcf780b42004-07-13 18:42:17 +00003368 return 1+delta0;
3369 } else {
sewardj2a2ba8b2004-11-08 13:14:06 +00003370 DIP("imul%c %s, %s\n", nameISize(size),
3371 dis_buf, nameIReg(size,gregOfRM(rm)));
sewardj71a65362004-07-28 01:48:34 +00003372 return alen+delta0;
sewardjcf780b42004-07-13 18:42:17 +00003373 }
3374}
3375
3376
sewardj1813dbe2004-07-28 17:09:04 +00003377/* IMUL I * E -> G. Supplied eip points to the modR/M byte. */
3378static
3379UInt dis_imul_I_E_G ( UChar sorb,
3380 Int size,
3381 UInt delta,
3382 Int litsize )
3383{
sewardj883b00b2004-09-11 09:30:24 +00003384 Int d32, alen;
sewardjc9a43662004-11-30 18:51:59 +00003385 HChar dis_buf[50];
sewardjb81f8b32004-07-30 10:17:50 +00003386 UChar rm = getIByte(delta);
sewardj1813dbe2004-07-28 17:09:04 +00003387 IRType ty = szToITy(size);
3388 IRTemp te = newTemp(ty);
3389 IRTemp tl = newTemp(ty);
sewardj948d48b2004-11-05 19:49:09 +00003390 IRTemp resLo = newTemp(ty);
sewardj1813dbe2004-07-28 17:09:04 +00003391
sewardjb81f8b32004-07-30 10:17:50 +00003392 vassert(size == 1 || size == 2 || size == 4);
3393
sewardj1813dbe2004-07-28 17:09:04 +00003394 if (epartIsReg(rm)) {
3395 assign(te, getIReg(size, eregOfRM(rm)));
3396 delta++;
3397 } else {
sewardj883b00b2004-09-11 09:30:24 +00003398 IRTemp addr = disAMode( &alen, sorb, delta, dis_buf );
3399 assign(te, loadLE(ty, mkexpr(addr)));
3400 delta += alen;
sewardj1813dbe2004-07-28 17:09:04 +00003401 }
3402 d32 = getSDisp(litsize,delta);
3403 delta += litsize;
3404
sewardjb81f8b32004-07-30 10:17:50 +00003405 if (size == 1) d32 &= 0xFF;
3406 if (size == 2) d32 &= 0xFFFF;
3407
sewardj1813dbe2004-07-28 17:09:04 +00003408 assign(tl, mkU(ty,d32));
sewardj948d48b2004-11-05 19:49:09 +00003409
sewardj2a2ba8b2004-11-08 13:14:06 +00003410 assign( resLo, binop( mkSizedOp(ty, Iop_Mul8), mkexpr(te), mkexpr(tl) ));
sewardj948d48b2004-11-05 19:49:09 +00003411
sewardj2a9ad022004-11-25 02:46:58 +00003412 setFlags_MUL ( ty, te, tl, X86G_CC_OP_SMULB );
sewardj948d48b2004-11-05 19:49:09 +00003413
3414 putIReg(size, gregOfRM(rm), mkexpr(resLo));
sewardj1813dbe2004-07-28 17:09:04 +00003415
3416 DIP("imul %d, %s, %s\n", d32,
3417 ( epartIsReg(rm) ? nameIReg(size,eregOfRM(rm)) : dis_buf ),
3418 nameIReg(size,gregOfRM(rm)) );
3419 return delta;
sewardj948d48b2004-11-05 19:49:09 +00003420}
sewardj1813dbe2004-07-28 17:09:04 +00003421
3422
sewardjd1725d12004-08-12 20:46:53 +00003423/*------------------------------------------------------------*/
sewardj464efa42004-11-19 22:17:29 +00003424/*--- ---*/
3425/*--- x87 FLOATING POINT INSTRUCTIONS ---*/
3426/*--- ---*/
sewardjd1725d12004-08-12 20:46:53 +00003427/*------------------------------------------------------------*/
3428
sewardj207557a2004-08-27 12:00:18 +00003429/* --- Helper functions for dealing with the register stack. --- */
3430
sewardj893aada2004-11-29 19:57:54 +00003431/* --- Set the emulation-warning pseudo-register. --- */
3432
3433static void put_emwarn ( IRExpr* e /* :: Ity_I32 */ )
3434{
3435 stmt( IRStmt_Put( OFFB_EMWARN, e ) );
3436}
3437
sewardj17442fe2004-09-20 14:54:28 +00003438/* --- Produce an IRExpr* denoting a 64-bit QNaN. --- */
sewardj207557a2004-08-27 12:00:18 +00003439
sewardj17442fe2004-09-20 14:54:28 +00003440static IRExpr* mkQNaN64 ( void )
sewardj207557a2004-08-27 12:00:18 +00003441{
sewardj17442fe2004-09-20 14:54:28 +00003442 /* QNaN is 0 2047 1 0(51times)
3443 == 0b 11111111111b 1 0(51times)
3444 == 0x7FF8 0000 0000 0000
3445 */
3446 return IRExpr_Const(IRConst_F64i(0x7FF8000000000000ULL));
sewardj207557a2004-08-27 12:00:18 +00003447}
3448
sewardj893aada2004-11-29 19:57:54 +00003449/* --------- Get/put the top-of-stack pointer. --------- */
sewardjd1725d12004-08-12 20:46:53 +00003450
3451static IRExpr* get_ftop ( void )
3452{
3453 return IRExpr_Get( OFFB_FTOP, Ity_I32 );
3454}
3455
sewardj207557a2004-08-27 12:00:18 +00003456static void put_ftop ( IRExpr* e )
sewardjd1725d12004-08-12 20:46:53 +00003457{
sewardj207557a2004-08-27 12:00:18 +00003458 stmt( IRStmt_Put( OFFB_FTOP, e ) );
sewardjd1725d12004-08-12 20:46:53 +00003459}
3460
sewardj893aada2004-11-29 19:57:54 +00003461/* --------- Get/put the C3210 bits. --------- */
sewardjbdc7d212004-09-09 02:46:40 +00003462
sewardjc4be80c2004-09-10 16:17:45 +00003463static IRExpr* get_C3210 ( void )
sewardjbdc7d212004-09-09 02:46:40 +00003464{
sewardjc4be80c2004-09-10 16:17:45 +00003465 return IRExpr_Get( OFFB_FC3210, Ity_I32 );
sewardjbdc7d212004-09-09 02:46:40 +00003466}
3467
sewardjc4be80c2004-09-10 16:17:45 +00003468static void put_C3210 ( IRExpr* e )
sewardjbdc7d212004-09-09 02:46:40 +00003469{
sewardjc4be80c2004-09-10 16:17:45 +00003470 stmt( IRStmt_Put( OFFB_FC3210, e ) );
sewardjbdc7d212004-09-09 02:46:40 +00003471}
sewardjd1725d12004-08-12 20:46:53 +00003472
sewardj893aada2004-11-29 19:57:54 +00003473/* --------- Get/put the FPU rounding mode. --------- */
sewardjd01a9632004-11-30 13:18:37 +00003474static IRExpr* /* :: Ity_I32 */ get_fpround ( void )
sewardj8f3debf2004-09-08 23:42:23 +00003475{
sewardjd01a9632004-11-30 13:18:37 +00003476 return IRExpr_Get( OFFB_FPROUND, Ity_I32 );
sewardj8f3debf2004-09-08 23:42:23 +00003477}
3478
sewardjd01a9632004-11-30 13:18:37 +00003479static void put_fpround ( IRExpr* /* :: Ity_I32 */ e )
sewardj8f3debf2004-09-08 23:42:23 +00003480{
sewardjd01a9632004-11-30 13:18:37 +00003481 stmt( IRStmt_Put( OFFB_FPROUND, e ) );
sewardj8f3debf2004-09-08 23:42:23 +00003482}
3483
3484
sewardj893aada2004-11-29 19:57:54 +00003485/* --------- Synthesise a 2-bit FPU rounding mode. --------- */
sewardj8f3debf2004-09-08 23:42:23 +00003486/* Produces a value in 0 .. 3, which is encoded as per the type
sewardjd01a9632004-11-30 13:18:37 +00003487 IRRoundingMode. Since the guest_FPROUND value is also encoded as
3488 per IRRoundingMode, we merely need to get it and mask it for
3489 safety.
sewardj8f3debf2004-09-08 23:42:23 +00003490*/
3491static IRExpr* /* :: Ity_I32 */ get_roundingmode ( void )
3492{
sewardjd01a9632004-11-30 13:18:37 +00003493 return binop( Iop_And32, get_fpround(), mkU32(3) );
sewardj8f3debf2004-09-08 23:42:23 +00003494}
3495
3496
sewardj207557a2004-08-27 12:00:18 +00003497/* --------- Get/set FP register tag bytes. --------- */
3498
sewardj207557a2004-08-27 12:00:18 +00003499/* Given i, and some expression e, generate 'ST_TAG(i) = e'. */
3500
3501static void put_ST_TAG ( Int i, IRExpr* value )
3502{
sewardj2d3f77c2004-09-22 23:49:09 +00003503 IRArray* descr;
sewardj207557a2004-08-27 12:00:18 +00003504 vassert(typeOfIRExpr(irbb->tyenv, value) == Ity_I8);
sewardjf6dc3ce2004-10-19 01:03:46 +00003505 descr = mkIRArray( OFFB_FPTAGS, Ity_I8, 8 );
sewardj2d3f77c2004-09-22 23:49:09 +00003506 stmt( IRStmt_PutI( descr, get_ftop(), i, value ) );
sewardj207557a2004-08-27 12:00:18 +00003507}
3508
3509/* Given i, generate an expression yielding 'ST_TAG(i)'. This will be
sewardjdb199622004-09-06 23:19:03 +00003510 zero to indicate "Empty" and nonzero to indicate "NonEmpty". */
sewardj207557a2004-08-27 12:00:18 +00003511
3512static IRExpr* get_ST_TAG ( Int i )
3513{
sewardjf6dc3ce2004-10-19 01:03:46 +00003514 IRArray* descr = mkIRArray( OFFB_FPTAGS, Ity_I8, 8 );
sewardj2d3f77c2004-09-22 23:49:09 +00003515 return IRExpr_GetI( descr, get_ftop(), i );
sewardj207557a2004-08-27 12:00:18 +00003516}
3517
3518
3519/* --------- Get/set FP registers. --------- */
3520
sewardj2d3f77c2004-09-22 23:49:09 +00003521/* Given i, and some expression e, emit 'ST(i) = e' and set the
3522 register's tag to indicate the register is full. The previous
3523 state of the register is not checked. */
sewardj207557a2004-08-27 12:00:18 +00003524
3525static void put_ST_UNCHECKED ( Int i, IRExpr* value )
sewardjd1725d12004-08-12 20:46:53 +00003526{
sewardj2d3f77c2004-09-22 23:49:09 +00003527 IRArray* descr;
sewardjdb199622004-09-06 23:19:03 +00003528 vassert(typeOfIRExpr(irbb->tyenv, value) == Ity_F64);
sewardjf6dc3ce2004-10-19 01:03:46 +00003529 descr = mkIRArray( OFFB_FPREGS, Ity_F64, 8 );
sewardj2d3f77c2004-09-22 23:49:09 +00003530 stmt( IRStmt_PutI( descr, get_ftop(), i, value ) );
sewardj207557a2004-08-27 12:00:18 +00003531 /* Mark the register as in-use. */
3532 put_ST_TAG(i, mkU8(1));
sewardjd1725d12004-08-12 20:46:53 +00003533}
3534
sewardj207557a2004-08-27 12:00:18 +00003535/* Given i, and some expression e, emit
3536 ST(i) = is_full(i) ? NaN : e
3537 and set the tag accordingly.
3538*/
3539
3540static void put_ST ( Int i, IRExpr* value )
3541{
3542 put_ST_UNCHECKED( i,
sewardjdb199622004-09-06 23:19:03 +00003543 IRExpr_Mux0X( get_ST_TAG(i),
3544 /* 0 means empty */
3545 value,
3546 /* non-0 means full */
sewardj17442fe2004-09-20 14:54:28 +00003547 mkQNaN64()
sewardj207557a2004-08-27 12:00:18 +00003548 )
3549 );
3550}
3551
3552
sewardjd1725d12004-08-12 20:46:53 +00003553/* Given i, generate an expression yielding 'ST(i)'. */
3554
sewardj207557a2004-08-27 12:00:18 +00003555static IRExpr* get_ST_UNCHECKED ( Int i )
sewardjd1725d12004-08-12 20:46:53 +00003556{
sewardjf6dc3ce2004-10-19 01:03:46 +00003557 IRArray* descr = mkIRArray( OFFB_FPREGS, Ity_F64, 8 );
sewardj2d3f77c2004-09-22 23:49:09 +00003558 return IRExpr_GetI( descr, get_ftop(), i );
sewardjd1725d12004-08-12 20:46:53 +00003559}
3560
sewardjc4be80c2004-09-10 16:17:45 +00003561
sewardj207557a2004-08-27 12:00:18 +00003562/* Given i, generate an expression yielding
3563 is_full(i) ? ST(i) : NaN
3564*/
3565
3566static IRExpr* get_ST ( Int i )
3567{
3568 return
3569 IRExpr_Mux0X( get_ST_TAG(i),
3570 /* 0 means empty */
sewardj17442fe2004-09-20 14:54:28 +00003571 mkQNaN64(),
sewardj207557a2004-08-27 12:00:18 +00003572 /* non-0 means full */
3573 get_ST_UNCHECKED(i));
3574}
3575
3576
sewardjd1725d12004-08-12 20:46:53 +00003577/* Adjust FTOP downwards by one register. */
3578
sewardj207557a2004-08-27 12:00:18 +00003579static void fp_push ( void )
sewardjd1725d12004-08-12 20:46:53 +00003580{
sewardj2d3f77c2004-09-22 23:49:09 +00003581 put_ftop( binop(Iop_Sub32, get_ftop(), mkU32(1)) );
sewardjd1725d12004-08-12 20:46:53 +00003582}
3583
sewardj207557a2004-08-27 12:00:18 +00003584/* Adjust FTOP upwards by one register, and mark the vacated register
3585 as empty. */
sewardja58ea662004-08-15 03:12:41 +00003586
sewardj207557a2004-08-27 12:00:18 +00003587static void fp_pop ( void )
sewardja58ea662004-08-15 03:12:41 +00003588{
sewardjdb199622004-09-06 23:19:03 +00003589 put_ST_TAG(0, mkU8(0));
sewardj2d3f77c2004-09-22 23:49:09 +00003590 put_ftop( binop(Iop_Add32, get_ftop(), mkU32(1)) );
sewardja58ea662004-08-15 03:12:41 +00003591}
3592
sewardj3f61ddb2004-10-16 20:51:05 +00003593/* Clear the C2 bit of the FPU status register, for
3594 sin/cos/tan/sincos. */
3595
3596static void clear_C2 ( void )
3597{
sewardj67e002d2004-12-02 18:16:33 +00003598 put_C3210( binop(Iop_And32, get_C3210(), mkU32(~X86G_FC_MASK_C2)) );
sewardj3f61ddb2004-10-16 20:51:05 +00003599}
3600
3601
sewardj207557a2004-08-27 12:00:18 +00003602/* ------------------------------------------------------- */
3603/* Given all that stack-mangling junk, we can now go ahead
3604 and describe FP instructions.
3605*/
3606
sewardj3fd5e572004-09-09 22:43:51 +00003607/* ST(0) = ST(0) `op` mem64/32(addr)
sewardj207557a2004-08-27 12:00:18 +00003608 Need to check ST(0)'s tag on read, but not on write.
3609*/
sewardja58ea662004-08-15 03:12:41 +00003610static
3611void fp_do_op_mem_ST_0 ( IRTemp addr, UChar* op_txt, UChar* dis_buf,
3612 IROp op, Bool dbl )
3613{
3614 DIP("f%s%c %s", op_txt, dbl?'l':'s', dis_buf);
3615 if (dbl) {
sewardj3fd5e572004-09-09 22:43:51 +00003616 put_ST_UNCHECKED(0,
3617 binop( op,
3618 get_ST(0),
3619 loadLE(Ity_F64,mkexpr(addr))
3620 ));
sewardja58ea662004-08-15 03:12:41 +00003621 } else {
sewardj3fd5e572004-09-09 22:43:51 +00003622 put_ST_UNCHECKED(0,
3623 binop( op,
3624 get_ST(0),
3625 unop(Iop_F32toF64, loadLE(Ity_F32,mkexpr(addr)))
3626 ));
3627 }
3628}
3629
3630
3631/* ST(0) = mem64/32(addr) `op` ST(0)
3632 Need to check ST(0)'s tag on read, but not on write.
3633*/
3634static
3635void fp_do_oprev_mem_ST_0 ( IRTemp addr, UChar* op_txt, UChar* dis_buf,
sewardj883b00b2004-09-11 09:30:24 +00003636 IROp op, Bool dbl )
sewardj3fd5e572004-09-09 22:43:51 +00003637{
3638 DIP("f%s%c %s", op_txt, dbl?'l':'s', dis_buf);
3639 if (dbl) {
3640 put_ST_UNCHECKED(0,
3641 binop( op,
3642 loadLE(Ity_F64,mkexpr(addr)),
3643 get_ST(0)
3644 ));
3645 } else {
3646 put_ST_UNCHECKED(0,
3647 binop( op,
3648 unop(Iop_F32toF64, loadLE(Ity_F32,mkexpr(addr))),
3649 get_ST(0)
3650 ));
sewardja58ea662004-08-15 03:12:41 +00003651 }
3652}
3653
sewardjd1725d12004-08-12 20:46:53 +00003654
sewardjdb199622004-09-06 23:19:03 +00003655/* ST(dst) = ST(dst) `op` ST(src).
3656 Check dst and src tags when reading but not on write.
3657*/
3658static
sewardjbdc7d212004-09-09 02:46:40 +00003659void fp_do_op_ST_ST ( UChar* op_txt, IROp op, UInt st_src, UInt st_dst,
3660 Bool pop_after )
sewardjdb199622004-09-06 23:19:03 +00003661{
sewardjbdc7d212004-09-09 02:46:40 +00003662 DIP("f%s%s st(%d), st(%d)\n", op_txt, pop_after?"p":"", st_src, st_dst );
sewardjdb199622004-09-06 23:19:03 +00003663 put_ST_UNCHECKED(
3664 st_dst,
3665 binop(op, get_ST(st_dst), get_ST(st_src) )
3666 );
sewardjbdc7d212004-09-09 02:46:40 +00003667 if (pop_after)
3668 fp_pop();
3669}
3670
3671/* ST(dst) = ST(src) `op` ST(dst).
3672 Check dst and src tags when reading but not on write.
3673*/
3674static
3675void fp_do_oprev_ST_ST ( UChar* op_txt, IROp op, UInt st_src, UInt st_dst,
sewardj883b00b2004-09-11 09:30:24 +00003676 Bool pop_after )
sewardjbdc7d212004-09-09 02:46:40 +00003677{
3678 DIP("f%s%s st(%d), st(%d)\n", op_txt, pop_after?"p":"", st_src, st_dst );
3679 put_ST_UNCHECKED(
3680 st_dst,
3681 binop(op, get_ST(st_src), get_ST(st_dst) )
3682 );
3683 if (pop_after)
3684 fp_pop();
sewardjdb199622004-09-06 23:19:03 +00003685}
3686
sewardj8308aad2004-09-12 11:09:54 +00003687/* %eflags(Z,P,C) = UCOMI( st(0), st(i) ) */
3688static void fp_do_ucomi_ST0_STi ( UInt i, Bool pop_after )
3689{
3690 DIP("fucomi%s %%st(0),%%st(%d)\n", pop_after ? "p" : "", i);
3691 /* This is a bit of a hack (and isn't really right). It sets
3692 Z,P,C,O correctly, but forces A and S to zero, whereas the Intel
3693 documentation implies A and S are unchanged.
3694 */
sewardjfeeb8a82004-11-30 12:30:11 +00003695 /* It's also fishy in that it is used both for COMIP and
3696 UCOMIP, and they aren't the same (although similar). */
sewardj2a9ad022004-11-25 02:46:58 +00003697 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
sewardj2a2ba8b2004-11-08 13:14:06 +00003698 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
3699 stmt( IRStmt_Put( OFFB_CC_DEP1,
sewardj8308aad2004-09-12 11:09:54 +00003700 binop( Iop_And32,
3701 binop(Iop_CmpF64, get_ST(0), get_ST(i)),
3702 mkU32(0x45)
3703 )));
3704 if (pop_after)
3705 fp_pop();
3706}
3707
sewardjdb199622004-09-06 23:19:03 +00003708
sewardjd1725d12004-08-12 20:46:53 +00003709static
3710UInt dis_FPU ( Bool* decode_ok, UChar sorb, UInt delta )
3711{
sewardja58ea662004-08-15 03:12:41 +00003712 Int len;
3713 UInt r_src, r_dst;
sewardjc9a43662004-11-30 18:51:59 +00003714 HChar dis_buf[50];
sewardj89cd0932004-09-08 18:23:25 +00003715 IRTemp t1, t2;
sewardjd1725d12004-08-12 20:46:53 +00003716
3717 /* On entry, delta points at the second byte of the insn (the modrm
3718 byte).*/
3719 UChar first_opcode = getIByte(delta-1);
3720 UChar modrm = getIByte(delta+0);
3721
3722 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xD8 opcodes +-+-+-+-+-+-+-+ */
3723
3724 if (first_opcode == 0xD8) {
sewardjdb199622004-09-06 23:19:03 +00003725 if (modrm < 0xC0) {
sewardj89cd0932004-09-08 18:23:25 +00003726
3727 /* bits 5,4,3 are an opcode extension, and the modRM also
3728 specifies an address. */
3729 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
3730 delta += len;
3731
3732 switch (gregOfRM(modrm)) {
3733
sewardj3fd5e572004-09-09 22:43:51 +00003734 case 0: /* FADD single-real */
3735 fp_do_op_mem_ST_0 ( addr, "add", dis_buf, Iop_AddF64, False );
3736 break;
3737
sewardj89cd0932004-09-08 18:23:25 +00003738 case 1: /* FMUL single-real */
3739 fp_do_op_mem_ST_0 ( addr, "mul", dis_buf, Iop_MulF64, False );
3740 break;
3741
sewardj7ca37d92004-10-25 02:58:30 +00003742 case 2: /* FCOM single-real */
3743 DIP("fcoms %s\n", dis_buf);
3744 /* This forces C1 to zero, which isn't right. */
3745 put_C3210(
3746 binop( Iop_And32,
3747 binop(Iop_Shl32,
3748 binop(Iop_CmpF64,
3749 get_ST(0),
3750 unop(Iop_F32toF64,
3751 loadLE(Ity_F32,mkexpr(addr)))),
3752 mkU8(8)),
3753 mkU32(0x4500)
3754 ));
3755 break;
3756
3757 case 3: /* FCOMP single-real */
sewardje166ed02004-10-25 02:27:01 +00003758 DIP("fcomps %s\n", dis_buf);
3759 /* This forces C1 to zero, which isn't right. */
3760 put_C3210(
3761 binop( Iop_And32,
3762 binop(Iop_Shl32,
3763 binop(Iop_CmpF64,
3764 get_ST(0),
3765 unop(Iop_F32toF64,
3766 loadLE(Ity_F32,mkexpr(addr)))),
3767 mkU8(8)),
3768 mkU32(0x4500)
3769 ));
3770 fp_pop();
3771 break;
3772
sewardj588ea762004-09-10 18:56:32 +00003773 case 4: /* FSUB single-real */
3774 fp_do_op_mem_ST_0 ( addr, "sub", dis_buf, Iop_SubF64, False );
3775 break;
3776
3777 case 5: /* FSUBR single-real */
3778 fp_do_oprev_mem_ST_0 ( addr, "subr", dis_buf, Iop_SubF64, False );
3779 break;
3780
sewardjbdc7d212004-09-09 02:46:40 +00003781 case 6: /* FDIV single-real */
3782 fp_do_op_mem_ST_0 ( addr, "div", dis_buf, Iop_DivF64, False );
3783 break;
3784
sewardj8308aad2004-09-12 11:09:54 +00003785 case 7: /* FDIVR single-real */
3786 fp_do_oprev_mem_ST_0 ( addr, "divr", dis_buf, Iop_DivF64, False );
3787 break;
3788
sewardj89cd0932004-09-08 18:23:25 +00003789 default:
3790 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
3791 vex_printf("first_opcode == 0xD8\n");
3792 goto decode_fail;
3793 }
sewardjdb199622004-09-06 23:19:03 +00003794 } else {
3795 delta++;
3796 switch (modrm) {
sewardj89cd0932004-09-08 18:23:25 +00003797
sewardjdb199622004-09-06 23:19:03 +00003798 case 0xC0 ... 0xC7: /* FADD %st(?),%st(0) */
sewardjbdc7d212004-09-09 02:46:40 +00003799 fp_do_op_ST_ST ( "add", Iop_AddF64, modrm - 0xC0, 0, False );
sewardjdb199622004-09-06 23:19:03 +00003800 break;
sewardj89cd0932004-09-08 18:23:25 +00003801
sewardj3fd5e572004-09-09 22:43:51 +00003802 case 0xC8 ... 0xCF: /* FMUL %st(?),%st(0) */
3803 fp_do_op_ST_ST ( "mul", Iop_MulF64, modrm - 0xC8, 0, False );
3804 break;
3805
sewardje166ed02004-10-25 02:27:01 +00003806#if 1
3807 /* Dunno if this is right */
3808 case 0xD0 ... 0xD7: /* FCOM %st(?),%st(0) */
3809 r_dst = (UInt)modrm - 0xD0;
3810 DIP("fcom %%st(0),%%st(%d)\n", r_dst);
3811 /* This forces C1 to zero, which isn't right. */
3812 put_C3210(
3813 binop( Iop_And32,
3814 binop(Iop_Shl32,
3815 binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
3816 mkU8(8)),
3817 mkU32(0x4500)
3818 ));
3819 break;
3820#endif
3821#if 1
sewardj98169c52004-10-24 13:11:39 +00003822 /* Dunno if this is right */
3823 case 0xD8 ... 0xDF: /* FCOMP %st(?),%st(0) */
3824 r_dst = (UInt)modrm - 0xD8;
3825 DIP("fcomp %%st(0),%%st(%d)\n", r_dst);
3826 /* This forces C1 to zero, which isn't right. */
3827 put_C3210(
3828 binop( Iop_And32,
3829 binop(Iop_Shl32,
3830 binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
3831 mkU8(8)),
3832 mkU32(0x4500)
3833 ));
3834 fp_pop();
3835 break;
3836#endif
sewardj89cd0932004-09-08 18:23:25 +00003837 case 0xE0 ... 0xE7: /* FSUB %st(?),%st(0) */
sewardjbdc7d212004-09-09 02:46:40 +00003838 fp_do_op_ST_ST ( "sub", Iop_SubF64, modrm - 0xE0, 0, False );
sewardj89cd0932004-09-08 18:23:25 +00003839 break;
3840
sewardj8308aad2004-09-12 11:09:54 +00003841 case 0xE8 ... 0xEF: /* FSUBR %st(?),%st(0) */
3842 fp_do_oprev_ST_ST ( "subr", Iop_SubF64, modrm - 0xE8, 0, False );
3843 break;
3844
sewardj3fd5e572004-09-09 22:43:51 +00003845 case 0xF0 ... 0xF7: /* FDIV %st(?),%st(0) */
3846 fp_do_op_ST_ST ( "div", Iop_DivF64, modrm - 0xF0, 0, False );
3847 break;
3848
3849 case 0xF8 ... 0xFF: /* FDIVR %st(?),%st(0) */
3850 fp_do_oprev_ST_ST ( "divr", Iop_DivF64, modrm - 0xF8, 0, False );
3851 break;
3852
sewardjdb199622004-09-06 23:19:03 +00003853 default:
3854 goto decode_fail;
3855 }
3856 }
sewardjd1725d12004-08-12 20:46:53 +00003857 }
3858
3859 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xD9 opcodes +-+-+-+-+-+-+-+ */
3860 else
3861 if (first_opcode == 0xD9) {
sewardjbb53f8c2004-08-14 11:50:01 +00003862 if (modrm < 0xC0) {
sewardj89cd0932004-09-08 18:23:25 +00003863
3864 /* bits 5,4,3 are an opcode extension, and the modRM also
sewardjfeeb8a82004-11-30 12:30:11 +00003865 specifies an address. */
sewardj89cd0932004-09-08 18:23:25 +00003866 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
3867 delta += len;
3868
3869 switch (gregOfRM(modrm)) {
3870
3871 case 0: /* FLD single-real */
3872 DIP("fldF %s\n", dis_buf);
3873 fp_push();
3874 put_ST(0, unop(Iop_F32toF64,
sewardj8f3debf2004-09-08 23:42:23 +00003875 loadLE(Ity_F32, mkexpr(addr))));
sewardj89cd0932004-09-08 18:23:25 +00003876 break;
3877
sewardj588ea762004-09-10 18:56:32 +00003878 case 2: /* FST single-real */
3879 DIP("fstS %s", dis_buf);
sewardj3bca9062004-12-04 14:36:09 +00003880 storeLE(mkexpr(addr),
3881 binop(Iop_F64toF32, get_roundingmode(), get_ST(0)));
sewardj588ea762004-09-10 18:56:32 +00003882 break;
3883
sewardj89cd0932004-09-08 18:23:25 +00003884 case 3: /* FSTP single-real */
3885 DIP("fstpS %s", dis_buf);
sewardj3bca9062004-12-04 14:36:09 +00003886 storeLE(mkexpr(addr),
3887 binop(Iop_F64toF32, get_roundingmode(), get_ST(0)));
sewardj5bd4d162004-11-10 13:02:48 +00003888 fp_pop();
sewardj89cd0932004-09-08 18:23:25 +00003889 break;
3890
sewardj7df596b2004-12-06 14:29:12 +00003891 case 4: { /* FLDENV m108 */
3892 /* Uses dirty helper:
3893 VexEmWarn x86g_do_FLDENV ( VexGuestX86State*, Addr32 ) */
3894 IRTemp ew = newTemp(Ity_I32);
3895 IRDirty* d = unsafeIRDirty_0_N (
3896 0/*regparms*/,
3897 "x86g_dirtyhelper_FLDENV",
3898 &x86g_dirtyhelper_FLDENV,
3899 mkIRExprVec_1( mkexpr(addr) )
3900 );
3901 d->needsBBP = True;
3902 d->tmp = ew;
3903 /* declare we're reading memory */
3904 d->mFx = Ifx_Read;
3905 d->mAddr = mkexpr(addr);
3906 d->mSize = 28;
3907
3908 /* declare we're writing guest state */
3909 d->nFxState = 5;
3910
3911 d->fxState[0].fx = Ifx_Write;
3912 d->fxState[0].offset = OFFB_FTOP;
3913 d->fxState[0].size = sizeof(UInt);
3914
3915 d->fxState[1].fx = Ifx_Write;
3916 d->fxState[1].offset = OFFB_FPREGS;
3917 d->fxState[1].size = 8 * sizeof(ULong);
3918
3919 d->fxState[2].fx = Ifx_Write;
3920 d->fxState[2].offset = OFFB_FPTAGS;
3921 d->fxState[2].size = 8 * sizeof(UChar);
3922
3923 d->fxState[3].fx = Ifx_Write;
3924 d->fxState[3].offset = OFFB_FPROUND;
3925 d->fxState[3].size = sizeof(UInt);
3926
3927 d->fxState[4].fx = Ifx_Write;
3928 d->fxState[4].offset = OFFB_FC3210;
3929 d->fxState[4].size = sizeof(UInt);
3930
3931 stmt( IRStmt_Dirty(d) );
3932
3933 /* ew contains any emulation warning we may need to
3934 issue. If needed, side-exit to the next insn,
3935 reporting the warning, so that Valgrind's dispatcher
3936 sees the warning. */
3937 put_emwarn( mkexpr(ew) );
3938 stmt(
3939 IRStmt_Exit(
3940 binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
3941 Ijk_EmWarn,
3942 IRConst_U32( ((Addr32)guest_eip_bbstart)+delta)
3943 )
3944 );
3945
3946 DIP("fldenv %s", dis_buf);
3947 break;
3948 }
3949
sewardj893aada2004-11-29 19:57:54 +00003950 case 5: {/* FLDCW */
3951 /* The only thing we observe in the control word is the
sewardjd01a9632004-11-30 13:18:37 +00003952 rounding mode. Therefore, pass the 16-bit value
3953 (x87 native-format control word) to a clean helper,
3954 getting back a 64-bit value, the lower half of which
3955 is the FPROUND value to store, and the upper half of
3956 which is the emulation-warning token which may be
3957 generated.
sewardj893aada2004-11-29 19:57:54 +00003958 */
3959 /* ULong x86h_check_fldcw ( UInt ); */
3960 IRTemp t64 = newTemp(Ity_I64);
3961 IRTemp ew = newTemp(Ity_I32);
sewardj8f3debf2004-09-08 23:42:23 +00003962 DIP("fldcw %s", dis_buf);
sewardj893aada2004-11-29 19:57:54 +00003963 assign( t64, mkIRExprCCall(
3964 Ity_I64, 0/*regparms*/,
sewardj3bd6f3e2004-12-13 10:48:19 +00003965 "x86g_check_fldcw",
3966 &x86g_check_fldcw,
sewardj893aada2004-11-29 19:57:54 +00003967 mkIRExprVec_1(
3968 unop( Iop_16Uto32,
3969 loadLE(Ity_I16, mkexpr(addr)))
3970 )
3971 )
3972 );
3973
sewardjd01a9632004-11-30 13:18:37 +00003974 put_fpround( unop(Iop_64to32, mkexpr(t64)) );
sewardj893aada2004-11-29 19:57:54 +00003975 assign( ew, unop(Iop_64HIto32, mkexpr(t64) ) );
3976 put_emwarn( mkexpr(ew) );
3977 /* Finally, if an emulation warning was reported,
3978 side-exit to the next insn, reporting the warning,
3979 so that Valgrind's dispatcher sees the warning. */
3980 stmt(
3981 IRStmt_Exit(
3982 binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
3983 Ijk_EmWarn,
3984 IRConst_U32( ((Addr32)guest_eip_bbstart)+delta)
3985 )
3986 );
sewardj89cd0932004-09-08 18:23:25 +00003987 break;
sewardj893aada2004-11-29 19:57:54 +00003988 }
sewardj89cd0932004-09-08 18:23:25 +00003989
sewardj7df596b2004-12-06 14:29:12 +00003990 case 6: { /* FNSTENV m28 */
3991 /* Uses dirty helper:
3992 void x86g_do_FSTENV ( VexGuestX86State*, UInt ) */
3993 IRDirty* d = unsafeIRDirty_0_N (
3994 0/*regparms*/,
3995 "x86g_dirtyhelper_FSTENV",
3996 &x86g_dirtyhelper_FSTENV,
3997 mkIRExprVec_1( mkexpr(addr) )
3998 );
3999 d->needsBBP = True;
4000 /* declare we're writing memory */
4001 d->mFx = Ifx_Write;
4002 d->mAddr = mkexpr(addr);
4003 d->mSize = 28;
4004
4005 /* declare we're reading guest state */
4006 d->nFxState = 4;
4007
4008 d->fxState[0].fx = Ifx_Read;
4009 d->fxState[0].offset = OFFB_FTOP;
4010 d->fxState[0].size = sizeof(UInt);
4011
4012 d->fxState[1].fx = Ifx_Read;
4013 d->fxState[1].offset = OFFB_FPTAGS;
4014 d->fxState[1].size = 8 * sizeof(UChar);
4015
4016 d->fxState[2].fx = Ifx_Read;
4017 d->fxState[2].offset = OFFB_FPROUND;
4018 d->fxState[2].size = sizeof(UInt);
4019
4020 d->fxState[3].fx = Ifx_Read;
4021 d->fxState[3].offset = OFFB_FC3210;
4022 d->fxState[3].size = sizeof(UInt);
4023
4024 stmt( IRStmt_Dirty(d) );
4025
4026 DIP("fnstenv %s", dis_buf);
4027 break;
4028 }
4029
sewardj588ea762004-09-10 18:56:32 +00004030 case 7: /* FNSTCW */
sewardj893aada2004-11-29 19:57:54 +00004031 /* Fake up a native x87 FPU control word. The only
sewardjd01a9632004-11-30 13:18:37 +00004032 thing it depends on is FPROUND[1:0], so call a clean
sewardj893aada2004-11-29 19:57:54 +00004033 helper to cook it up. */
sewardjd01a9632004-11-30 13:18:37 +00004034 /* UInt x86h_create_fpucw ( UInt fpround ) */
sewardj588ea762004-09-10 18:56:32 +00004035 DIP("fnstcw %s", dis_buf);
sewardj893aada2004-11-29 19:57:54 +00004036 storeLE(
4037 mkexpr(addr),
4038 unop( Iop_32to16,
4039 mkIRExprCCall(
4040 Ity_I32, 0/*regp*/,
sewardj3bd6f3e2004-12-13 10:48:19 +00004041 "x86g_create_fpucw", &x86g_create_fpucw,
sewardjd01a9632004-11-30 13:18:37 +00004042 mkIRExprVec_1( get_fpround() )
sewardj893aada2004-11-29 19:57:54 +00004043 )
4044 )
4045 );
sewardj89cd0932004-09-08 18:23:25 +00004046 break;
4047
4048 default:
4049 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
4050 vex_printf("first_opcode == 0xD9\n");
4051 goto decode_fail;
4052 }
4053
sewardjbb53f8c2004-08-14 11:50:01 +00004054 } else {
4055 delta++;
4056 switch (modrm) {
sewardj89cd0932004-09-08 18:23:25 +00004057
sewardjbb53f8c2004-08-14 11:50:01 +00004058 case 0xC0 ... 0xC7: /* FLD %st(?) */
sewardja58ea662004-08-15 03:12:41 +00004059 r_src = (UInt)modrm - 0xC0;
4060 DIP("fld %%st(%d)\n", r_src);
sewardj5bd4d162004-11-10 13:02:48 +00004061 t1 = newTemp(Ity_F64);
4062 assign(t1, get_ST(r_src));
4063 fp_push();
4064 put_ST(0, mkexpr(t1));
sewardjbb53f8c2004-08-14 11:50:01 +00004065 break;
4066
sewardj89cd0932004-09-08 18:23:25 +00004067 case 0xC8 ... 0xCF: /* FXCH %st(?) */
4068 r_src = (UInt)modrm - 0xC8;
4069 DIP("fxch %%st(%d)\n", r_src);
4070 t1 = newTemp(Ity_F64);
4071 t2 = newTemp(Ity_F64);
4072 assign(t1, get_ST(0));
4073 assign(t2, get_ST(r_src));
4074 put_ST_UNCHECKED(0, mkexpr(t2));
4075 put_ST_UNCHECKED(r_src, mkexpr(t1));
4076 break;
4077
sewardjcfded9a2004-09-09 11:44:16 +00004078 case 0xE0: /* FCHS */
4079 DIP("fchs\n");
4080 put_ST_UNCHECKED(0, unop(Iop_NegF64, get_ST(0)));
4081 break;
4082
sewardj883b00b2004-09-11 09:30:24 +00004083 case 0xE1: /* FABS */
4084 DIP("fabs\n");
4085 put_ST_UNCHECKED(0, unop(Iop_AbsF64, get_ST(0)));
4086 break;
sewardjc4be80c2004-09-10 16:17:45 +00004087
sewardj883b00b2004-09-11 09:30:24 +00004088 case 0xE5: { /* FXAM */
4089 /* This is an interesting one. It examines %st(0),
4090 regardless of whether the tag says it's empty or not.
4091 Here, just pass both the tag (in our format) and the
4092 value (as a double, actually a ULong) to a helper
4093 function. */
sewardjf9655262004-10-31 20:02:16 +00004094 IRExpr** args
4095 = mkIRExprVec_2( unop(Iop_8Uto32, get_ST_TAG(0)),
4096 unop(Iop_ReinterpF64asI64,
4097 get_ST_UNCHECKED(0)) );
4098 put_C3210(mkIRExprCCall(
sewardj8ea867b2004-10-30 19:03:02 +00004099 Ity_I32,
sewardjf9655262004-10-31 20:02:16 +00004100 0/*regparm*/,
sewardj2a9ad022004-11-25 02:46:58 +00004101 "x86g_calculate_FXAM", &x86g_calculate_FXAM,
sewardj8ea867b2004-10-30 19:03:02 +00004102 args
4103 ));
sewardjf9655262004-10-31 20:02:16 +00004104 DIP("fxam");
sewardj883b00b2004-09-11 09:30:24 +00004105 break;
4106 }
4107
4108 case 0xE8: /* FLD1 */
sewardjdb199622004-09-06 23:19:03 +00004109 DIP("fld1");
sewardjce646f22004-08-31 23:55:54 +00004110 fp_push();
4111 put_ST(0, IRExpr_Const(IRConst_F64(1.0)));
4112 break;
4113
sewardj37158712004-10-15 21:23:12 +00004114 case 0xE9: /* FLDL2T */
4115 DIP("fldl2t");
4116 fp_push();
4117 put_ST(0, IRExpr_Const(IRConst_F64(3.32192809488736234781)));
4118 break;
4119
sewardj8308aad2004-09-12 11:09:54 +00004120 case 0xEA: /* FLDL2E */
4121 DIP("fldl2e");
4122 fp_push();
4123 put_ST(0, IRExpr_Const(IRConst_F64(1.44269504088896340739)));
4124 break;
4125
sewardja0d48d62004-09-20 21:19:03 +00004126 case 0xEB: /* FLDPI */
4127 DIP("fldpi");
4128 fp_push();
4129 put_ST(0, IRExpr_Const(IRConst_F64(3.14159265358979323851)));
4130 break;
4131
sewardjdb199622004-09-06 23:19:03 +00004132 case 0xEC: /* FLDLG2 */
4133 DIP("fldlg2");
4134 fp_push();
4135 put_ST(0, IRExpr_Const(IRConst_F64(0.301029995663981143)));
4136 break;
4137
4138 case 0xED: /* FLDLN2 */
4139 DIP("fldln2");
4140 fp_push();
4141 put_ST(0, IRExpr_Const(IRConst_F64(0.69314718055994530942)));
4142 break;
4143
sewardja58ea662004-08-15 03:12:41 +00004144 case 0xEE: /* FLDZ */
4145 DIP("fldz");
sewardj207557a2004-08-27 12:00:18 +00004146 fp_push();
4147 put_ST(0, IRExpr_Const(IRConst_F64(0.0)));
sewardja58ea662004-08-15 03:12:41 +00004148 break;
4149
sewardj06c32a02004-09-12 12:07:34 +00004150 case 0xF0: /* F2XM1 */
4151 DIP("f2xm1\n");
4152 put_ST_UNCHECKED(0, unop(Iop_2xm1F64, get_ST(0)));
4153 break;
4154
sewardj52ace3e2004-09-11 17:10:08 +00004155 case 0xF1: /* FYL2X */
4156 DIP("fyl2x\n");
4157 put_ST_UNCHECKED(1, binop(Iop_Yl2xF64,
4158 get_ST(1), get_ST(0)));
4159 fp_pop();
4160 break;
4161
sewardj99016a72004-10-15 22:09:17 +00004162 case 0xF2: /* FPTAN */
4163 DIP("ftan\n");
4164 put_ST_UNCHECKED(0, unop(Iop_TanF64, get_ST(0)));
4165 fp_push();
4166 put_ST(0, IRExpr_Const(IRConst_F64(1.0)));
sewardj3f61ddb2004-10-16 20:51:05 +00004167 clear_C2(); /* HACK */
sewardj99016a72004-10-15 22:09:17 +00004168 break;
4169
sewardjcfded9a2004-09-09 11:44:16 +00004170 case 0xF3: /* FPATAN */
4171 DIP("fpatan\n");
sewardj52ace3e2004-09-11 17:10:08 +00004172 put_ST_UNCHECKED(1, binop(Iop_AtanF64,
sewardjcfded9a2004-09-09 11:44:16 +00004173 get_ST(1), get_ST(0)));
4174 fp_pop();
4175 break;
4176
sewardj442d0be2004-10-15 22:57:13 +00004177 case 0xF5: { /* FPREM1 -- IEEE compliant */
4178 IRTemp a1 = newTemp(Ity_F64);
4179 IRTemp a2 = newTemp(Ity_F64);
4180 DIP("fprem1\n");
4181 /* Do FPREM1 twice, once to get the remainder, and once
4182 to get the C3210 flag values. */
4183 assign( a1, get_ST(0) );
4184 assign( a2, get_ST(1) );
4185 put_ST_UNCHECKED(0, binop(Iop_PRem1F64,
4186 mkexpr(a1), mkexpr(a2)));
4187 put_C3210( binop(Iop_PRem1C3210F64, mkexpr(a1), mkexpr(a2)) );
4188 break;
4189 }
4190
sewardjfeeb8a82004-11-30 12:30:11 +00004191 case 0xF7: /* FINCSTP */
4192 DIP("fprem\n");
4193 put_ftop( binop(Iop_Add32, get_ftop(), mkU32(1)) );
4194 break;
4195
sewardj46de4072004-09-11 19:23:24 +00004196 case 0xF8: { /* FPREM -- not IEEE compliant */
4197 IRTemp a1 = newTemp(Ity_F64);
4198 IRTemp a2 = newTemp(Ity_F64);
4199 DIP("fprem\n");
4200 /* Do FPREM twice, once to get the remainder, and once
4201 to get the C3210 flag values. */
4202 assign( a1, get_ST(0) );
4203 assign( a2, get_ST(1) );
4204 put_ST_UNCHECKED(0, binop(Iop_PRemF64,
4205 mkexpr(a1), mkexpr(a2)));
4206 put_C3210( binop(Iop_PRemC3210F64, mkexpr(a1), mkexpr(a2)) );
4207 break;
4208 }
4209
sewardj8308aad2004-09-12 11:09:54 +00004210 case 0xF9: /* FYL2XP1 */
4211 DIP("fyl2xp1\n");
4212 put_ST_UNCHECKED(1, binop(Iop_Yl2xp1F64,
4213 get_ST(1), get_ST(0)));
4214 fp_pop();
4215 break;
4216
sewardjc4be80c2004-09-10 16:17:45 +00004217 case 0xFA: /* FSQRT */
4218 DIP("fsqrt\n");
4219 put_ST_UNCHECKED(0, unop(Iop_SqrtF64, get_ST(0)));
4220 break;
4221
sewardj519d66f2004-12-15 11:57:58 +00004222 case 0xFB: { /* FSINCOS */
4223 IRTemp a1 = newTemp(Ity_F64);
4224 assign( a1, get_ST(0) );
4225 DIP("fsincos\n");
4226 put_ST_UNCHECKED(0, unop(Iop_SinF64, mkexpr(a1)));
4227 fp_push();
4228 put_ST(0, unop(Iop_CosF64, mkexpr(a1)));
4229 break;
4230 }
4231
sewardje6709112004-09-10 18:37:18 +00004232 case 0xFC: /* FRNDINT */
4233 DIP("frndint\n");
4234 put_ST_UNCHECKED(0,
4235 binop(Iop_RoundF64, get_roundingmode(), get_ST(0)) );
4236 break;
4237
sewardj06c32a02004-09-12 12:07:34 +00004238 case 0xFD: /* FSCALE */
4239 DIP("fscale\n");
4240 put_ST_UNCHECKED(0, binop(Iop_ScaleF64,
4241 get_ST(0), get_ST(1)));
4242 break;
4243
sewardjcfded9a2004-09-09 11:44:16 +00004244 case 0xFE: /* FSIN */
4245 DIP("fsin\n");
4246 put_ST_UNCHECKED(0, unop(Iop_SinF64, get_ST(0)));
sewardj3f61ddb2004-10-16 20:51:05 +00004247 clear_C2(); /* HACK */
sewardjcfded9a2004-09-09 11:44:16 +00004248 break;
4249
4250 case 0xFF: /* FCOS */
4251 DIP("fcos\n");
4252 put_ST_UNCHECKED(0, unop(Iop_CosF64, get_ST(0)));
sewardj3f61ddb2004-10-16 20:51:05 +00004253 clear_C2(); /* HACK */
sewardjcfded9a2004-09-09 11:44:16 +00004254 break;
4255
sewardjbb53f8c2004-08-14 11:50:01 +00004256 default:
4257 goto decode_fail;
4258 }
4259 }
sewardjd1725d12004-08-12 20:46:53 +00004260 }
4261
4262 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDA opcodes +-+-+-+-+-+-+-+ */
4263 else
4264 if (first_opcode == 0xDA) {
sewardjbb53f8c2004-08-14 11:50:01 +00004265
4266 if (modrm < 0xC0) {
4267
sewardjfeeb8a82004-11-30 12:30:11 +00004268 /* bits 5,4,3 are an opcode extension, and the modRM also
sewardjbb53f8c2004-08-14 11:50:01 +00004269 specifies an address. */
sewardjce646f22004-08-31 23:55:54 +00004270 IROp fop;
sewardjbb53f8c2004-08-14 11:50:01 +00004271 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
4272 delta += len;
sewardjbb53f8c2004-08-14 11:50:01 +00004273 switch (gregOfRM(modrm)) {
sewardjce646f22004-08-31 23:55:54 +00004274
sewardjdb199622004-09-06 23:19:03 +00004275 case 0: /* FIADD m32int */ /* ST(0) += m32int */
4276 DIP("fiaddl %s", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00004277 fop = Iop_AddF64;
4278 goto do_fop_m32;
sewardjdb199622004-09-06 23:19:03 +00004279
sewardj207557a2004-08-27 12:00:18 +00004280 case 1: /* FIMUL m32int */ /* ST(0) *= m32int */
sewardjbb53f8c2004-08-14 11:50:01 +00004281 DIP("fimull %s", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00004282 fop = Iop_MulF64;
4283 goto do_fop_m32;
sewardjce646f22004-08-31 23:55:54 +00004284
4285 case 4: /* FISUB m32int */ /* ST(0) -= m32int */
4286 DIP("fisubl %s", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00004287 fop = Iop_SubF64;
4288 goto do_fop_m32;
sewardjce646f22004-08-31 23:55:54 +00004289
sewardj8308aad2004-09-12 11:09:54 +00004290 case 5: /* FISUBR m32int */ /* ST(0) = m32int - ST(0) */
4291 DIP("fisubrl %s", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00004292 fop = Iop_SubF64;
4293 goto do_foprev_m32;
sewardj8308aad2004-09-12 11:09:54 +00004294
sewardjce646f22004-08-31 23:55:54 +00004295 case 6: /* FIDIV m32int */ /* ST(0) /= m32int */
4296 DIP("fisubl %s", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00004297 fop = Iop_DivF64;
4298 goto do_fop_m32;
sewardjce646f22004-08-31 23:55:54 +00004299
sewardjc4eaff32004-09-10 20:25:11 +00004300 case 7: /* FIDIVR m32int */ /* ST(0) = m32int / ST(0) */
sewardj8308aad2004-09-12 11:09:54 +00004301 DIP("fidivrl %s", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00004302 fop = Iop_DivF64;
4303 goto do_foprev_m32;
sewardjc4eaff32004-09-10 20:25:11 +00004304
sewardjce646f22004-08-31 23:55:54 +00004305 do_fop_m32:
sewardj207557a2004-08-27 12:00:18 +00004306 put_ST_UNCHECKED(0,
sewardjce646f22004-08-31 23:55:54 +00004307 binop(fop,
sewardj207557a2004-08-27 12:00:18 +00004308 get_ST(0),
sewardj89cd0932004-09-08 18:23:25 +00004309 unop(Iop_I32toF64,
4310 loadLE(Ity_I32, mkexpr(addr)))));
sewardjbb53f8c2004-08-14 11:50:01 +00004311 break;
4312
sewardjc4eaff32004-09-10 20:25:11 +00004313 do_foprev_m32:
4314 put_ST_UNCHECKED(0,
4315 binop(fop,
4316 unop(Iop_I32toF64,
4317 loadLE(Ity_I32, mkexpr(addr))),
4318 get_ST(0)));
4319 break;
4320
sewardjbb53f8c2004-08-14 11:50:01 +00004321 default:
4322 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
4323 vex_printf("first_opcode == 0xDA\n");
4324 goto decode_fail;
4325 }
sewardj4cb918d2004-12-03 19:43:31 +00004326
sewardjbb53f8c2004-08-14 11:50:01 +00004327 } else {
sewardjbdc7d212004-09-09 02:46:40 +00004328
4329 delta++;
4330 switch (modrm) {
4331
sewardj519d66f2004-12-15 11:57:58 +00004332 case 0xC0 ... 0xC7: /* FCMOVB ST(i), ST(0) */
4333 r_src = (UInt)modrm - 0xC0;
4334 DIP("fcmovb %%st(%d), %%st(0)", r_src);
4335 put_ST_UNCHECKED(0,
4336 IRExpr_Mux0X(
4337 unop(Iop_1Uto8,
4338 mk_x86g_calculate_condition(X86CondB)),
4339 get_ST(0), get_ST(r_src)) );
4340 break;
4341
sewardj3fd5e572004-09-09 22:43:51 +00004342 case 0xC8 ... 0xCF: /* FCMOVE(Z) ST(i), ST(0) */
4343 r_src = (UInt)modrm - 0xC8;
sewardj5bd4d162004-11-10 13:02:48 +00004344 DIP("fcmovz %%st(%d), %%st(0)", r_src);
4345 put_ST_UNCHECKED(0,
sewardj3fd5e572004-09-09 22:43:51 +00004346 IRExpr_Mux0X(
sewardj2a9ad022004-11-25 02:46:58 +00004347 unop(Iop_1Uto8,
4348 mk_x86g_calculate_condition(X86CondZ)),
sewardj3fd5e572004-09-09 22:43:51 +00004349 get_ST(0), get_ST(r_src)) );
4350 break;
4351
sewardj519d66f2004-12-15 11:57:58 +00004352 case 0xD0 ... 0xD7: /* FCMOVBE ST(i), ST(0) */
4353 r_src = (UInt)modrm - 0xD0;
4354 DIP("fcmovbe %%st(%d), %%st(0)", r_src);
4355 put_ST_UNCHECKED(0,
4356 IRExpr_Mux0X(
4357 unop(Iop_1Uto8,
4358 mk_x86g_calculate_condition(X86CondBE)),
4359 get_ST(0), get_ST(r_src)) );
4360 break;
4361
sewardjbdc7d212004-09-09 02:46:40 +00004362 case 0xE9: /* FUCOMPP %st(0),%st(1) */
4363 DIP("fucompp %%st(0),%%st(1)\n");
sewardjc4be80c2004-09-10 16:17:45 +00004364 /* This forces C1 to zero, which isn't right. */
4365 put_C3210(
4366 binop( Iop_And32,
4367 binop(Iop_Shl32,
4368 binop(Iop_CmpF64, get_ST(0), get_ST(1)),
4369 mkU8(8)),
4370 mkU32(0x4500)
4371 ));
sewardjbdc7d212004-09-09 02:46:40 +00004372 fp_pop();
4373 fp_pop();
4374 break;
4375
sewardj5bd4d162004-11-10 13:02:48 +00004376 default:
sewardjbdc7d212004-09-09 02:46:40 +00004377 goto decode_fail;
sewardj5bd4d162004-11-10 13:02:48 +00004378 }
sewardjbdc7d212004-09-09 02:46:40 +00004379
sewardjbb53f8c2004-08-14 11:50:01 +00004380 }
sewardjd1725d12004-08-12 20:46:53 +00004381 }
4382
4383 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDB opcodes +-+-+-+-+-+-+-+ */
4384 else
4385 if (first_opcode == 0xDB) {
sewardj89cd0932004-09-08 18:23:25 +00004386 if (modrm < 0xC0) {
4387
sewardjfeeb8a82004-11-30 12:30:11 +00004388 /* bits 5,4,3 are an opcode extension, and the modRM also
sewardj89cd0932004-09-08 18:23:25 +00004389 specifies an address. */
4390 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
4391 delta += len;
4392
4393 switch (gregOfRM(modrm)) {
4394
4395 case 0: /* FILD m32int */
4396 DIP("fildl %s\n", dis_buf);
4397 fp_push();
4398 put_ST(0, unop(Iop_I32toF64,
4399 loadLE(Ity_I32, mkexpr(addr))));
4400 break;
4401
sewardj8f3debf2004-09-08 23:42:23 +00004402 case 2: /* FIST m32 */
4403 DIP("fistl %s", dis_buf);
4404 storeLE( mkexpr(addr),
4405 binop(Iop_F64toI32, get_roundingmode(), get_ST(0)) );
4406 break;
4407
sewardj89cd0932004-09-08 18:23:25 +00004408 case 3: /* FISTP m32 */
4409 DIP("fistpl %s", dis_buf);
sewardj8f3debf2004-09-08 23:42:23 +00004410 storeLE( mkexpr(addr),
4411 binop(Iop_F64toI32, get_roundingmode(), get_ST(0)) );
sewardj5bd4d162004-11-10 13:02:48 +00004412 fp_pop();
sewardj89cd0932004-09-08 18:23:25 +00004413 break;
sewardj17442fe2004-09-20 14:54:28 +00004414
sewardjb3bce0e2004-09-14 23:20:10 +00004415 case 5: { /* FLD extended-real */
sewardj7cb49d72004-10-24 22:31:25 +00004416 /* Uses dirty helper:
4417 ULong loadF80le ( VexGuestX86State*, UInt )
4418 addr holds the address. First, do a dirty call to
sewardjb3bce0e2004-09-14 23:20:10 +00004419 get hold of the data. */
sewardjc5fc7aa2004-10-27 23:00:55 +00004420 IRTemp val = newTemp(Ity_I64);
4421 IRExpr** args = mkIRExprVec_1 ( mkexpr(addr) );
4422
sewardj8ea867b2004-10-30 19:03:02 +00004423 IRDirty* d = unsafeIRDirty_1_N (
4424 val,
sewardj2a9ad022004-11-25 02:46:58 +00004425 0/*regparms*/,
4426 "x86g_loadF80le", &x86g_loadF80le,
sewardj8ea867b2004-10-30 19:03:02 +00004427 args
4428 );
sewardjb3bce0e2004-09-14 23:20:10 +00004429 /* declare that we're reading memory */
4430 d->mFx = Ifx_Read;
sewardj17442fe2004-09-20 14:54:28 +00004431 d->mAddr = mkexpr(addr);
sewardjb3bce0e2004-09-14 23:20:10 +00004432 d->mSize = 10;
sewardjc5fc7aa2004-10-27 23:00:55 +00004433
4434 /* execute the dirty call, dumping the result in val. */
sewardjb3bce0e2004-09-14 23:20:10 +00004435 stmt( IRStmt_Dirty(d) );
4436 fp_push();
sewardjc5fc7aa2004-10-27 23:00:55 +00004437 put_ST(0, unop(Iop_ReinterpI64asF64, mkexpr(val)));
4438
4439 DIP("fldt %s", dis_buf);
sewardjb3bce0e2004-09-14 23:20:10 +00004440 break;
4441 }
sewardj17442fe2004-09-20 14:54:28 +00004442
4443 case 7: { /* FSTP extended-real */
sewardj9fc9e782004-11-26 17:57:40 +00004444 /* Uses dirty helper: void x86g_storeF80le ( UInt, ULong ) */
sewardjc5fc7aa2004-10-27 23:00:55 +00004445 IRExpr** args
4446 = mkIRExprVec_2( mkexpr(addr),
4447 unop(Iop_ReinterpF64asI64, get_ST(0)) );
4448
sewardj8ea867b2004-10-30 19:03:02 +00004449 IRDirty* d = unsafeIRDirty_0_N (
sewardjf9655262004-10-31 20:02:16 +00004450 0/*regparms*/,
sewardj2a9ad022004-11-25 02:46:58 +00004451 "x86g_storeF80le", &x86g_storeF80le,
sewardj8ea867b2004-10-30 19:03:02 +00004452 args
4453 );
sewardj17442fe2004-09-20 14:54:28 +00004454 /* declare we're writing memory */
4455 d->mFx = Ifx_Write;
4456 d->mAddr = mkexpr(addr);
4457 d->mSize = 10;
sewardjc5fc7aa2004-10-27 23:00:55 +00004458
sewardj17442fe2004-09-20 14:54:28 +00004459 /* execute the dirty call. */
4460 stmt( IRStmt_Dirty(d) );
4461 fp_pop();
sewardjc5fc7aa2004-10-27 23:00:55 +00004462
4463 DIP("fstpt %s", dis_buf);
sewardj17442fe2004-09-20 14:54:28 +00004464 break;
4465 }
4466
sewardjb3bce0e2004-09-14 23:20:10 +00004467 default:
sewardj89cd0932004-09-08 18:23:25 +00004468 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
4469 vex_printf("first_opcode == 0xDB\n");
4470 goto decode_fail;
4471 }
4472
4473 } else {
sewardj8308aad2004-09-12 11:09:54 +00004474
4475 delta++;
4476 switch (modrm) {
4477
sewardj519d66f2004-12-15 11:57:58 +00004478 case 0xC0 ... 0xC7: /* FCMOVNB ST(i), ST(0) */
4479 r_src = (UInt)modrm - 0xC0;
4480 DIP("fcmovnb %%st(%d), %%st(0)", r_src);
4481 put_ST_UNCHECKED(0,
4482 IRExpr_Mux0X(
4483 unop(Iop_1Uto8,
4484 mk_x86g_calculate_condition(X86CondNB)),
4485 get_ST(0), get_ST(r_src)) );
4486 break;
4487
sewardj4e82db72004-10-16 11:32:15 +00004488 case 0xC8 ... 0xCF: /* FCMOVNE(NZ) ST(i), ST(0) */
4489 r_src = (UInt)modrm - 0xC8;
sewardj5bd4d162004-11-10 13:02:48 +00004490 DIP("fcmovnz %%st(%d), %%st(0)", r_src);
4491 put_ST_UNCHECKED(0,
sewardj4e82db72004-10-16 11:32:15 +00004492 IRExpr_Mux0X(
sewardj2a9ad022004-11-25 02:46:58 +00004493 unop(Iop_1Uto8,
4494 mk_x86g_calculate_condition(X86CondNZ)),
sewardj4e82db72004-10-16 11:32:15 +00004495 get_ST(0), get_ST(r_src)) );
4496 break;
4497
sewardj519d66f2004-12-15 11:57:58 +00004498 case 0xD0 ... 0xD7: /* FCMOVNBE ST(i), ST(0) */
4499 r_src = (UInt)modrm - 0xD0;
4500 DIP("fcmovnbe %%st(%d), %%st(0)", r_src);
4501 put_ST_UNCHECKED(0,
4502 IRExpr_Mux0X(
4503 unop(Iop_1Uto8,
4504 mk_x86g_calculate_condition(X86CondNBE)),
4505 get_ST(0), get_ST(r_src)) );
4506 break;
4507
sewardj7df596b2004-12-06 14:29:12 +00004508 case 0xE2:
4509 DIP("fnclex\n");
4510 break;
4511
sewardj8308aad2004-09-12 11:09:54 +00004512 case 0xE8 ... 0xEF: /* FUCOMI %st(0),%st(?) */
4513 fp_do_ucomi_ST0_STi( (UInt)modrm - 0xE8, False );
4514 break;
4515
sewardj37158712004-10-15 21:23:12 +00004516 case 0xF0 ... 0xF7: /* FCOMI %st(0),%st(?) */
4517 fp_do_ucomi_ST0_STi( (UInt)modrm - 0xF0, False );
4518 break;
4519
sewardj8308aad2004-09-12 11:09:54 +00004520 default:
4521 goto decode_fail;
sewardj17442fe2004-09-20 14:54:28 +00004522 }
sewardj89cd0932004-09-08 18:23:25 +00004523 }
sewardjd1725d12004-08-12 20:46:53 +00004524 }
4525
4526 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDC opcodes +-+-+-+-+-+-+-+ */
4527 else
4528 if (first_opcode == 0xDC) {
sewardja58ea662004-08-15 03:12:41 +00004529 if (modrm < 0xC0) {
4530
sewardj89cd0932004-09-08 18:23:25 +00004531 /* bits 5,4,3 are an opcode extension, and the modRM also
sewardjfeeb8a82004-11-30 12:30:11 +00004532 specifies an address. */
sewardja58ea662004-08-15 03:12:41 +00004533 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
4534 delta += len;
4535
4536 switch (gregOfRM(modrm)) {
4537
4538 case 0: /* FADD double-real */
4539 fp_do_op_mem_ST_0 ( addr, "add", dis_buf, Iop_AddF64, True );
4540 break;
4541
sewardjcfded9a2004-09-09 11:44:16 +00004542 case 1: /* FMUL double-real */
4543 fp_do_op_mem_ST_0 ( addr, "mul", dis_buf, Iop_MulF64, True );
4544 break;
4545
sewardje166ed02004-10-25 02:27:01 +00004546 case 2: /* FCOM double-real */
4547 DIP("fcoml %s\n", dis_buf);
4548 /* This forces C1 to zero, which isn't right. */
4549 put_C3210(
4550 binop( Iop_And32,
4551 binop(Iop_Shl32,
4552 binop(Iop_CmpF64,
4553 get_ST(0),
4554 loadLE(Ity_F64,mkexpr(addr))),
4555 mkU8(8)),
4556 mkU32(0x4500)
4557 ));
4558 break;
4559
sewardj883b00b2004-09-11 09:30:24 +00004560 case 3: /* FCOMP double-real */
sewardje166ed02004-10-25 02:27:01 +00004561 DIP("fcompl %s\n", dis_buf);
sewardj883b00b2004-09-11 09:30:24 +00004562 /* This forces C1 to zero, which isn't right. */
4563 put_C3210(
4564 binop( Iop_And32,
4565 binop(Iop_Shl32,
4566 binop(Iop_CmpF64,
4567 get_ST(0),
4568 loadLE(Ity_F64,mkexpr(addr))),
4569 mkU8(8)),
4570 mkU32(0x4500)
4571 ));
4572 fp_pop();
4573 break;
4574
sewardjcfded9a2004-09-09 11:44:16 +00004575 case 4: /* FSUB double-real */
4576 fp_do_op_mem_ST_0 ( addr, "sub", dis_buf, Iop_SubF64, True );
4577 break;
4578
sewardj3fd5e572004-09-09 22:43:51 +00004579 case 5: /* FSUBR double-real */
4580 fp_do_oprev_mem_ST_0 ( addr, "subr", dis_buf, Iop_SubF64, True );
4581 break;
4582
sewardjcfded9a2004-09-09 11:44:16 +00004583 case 6: /* FDIV double-real */
4584 fp_do_op_mem_ST_0 ( addr, "div", dis_buf, Iop_DivF64, True );
4585 break;
4586
sewardj883b00b2004-09-11 09:30:24 +00004587 case 7: /* FDIVR double-real */
4588 fp_do_oprev_mem_ST_0 ( addr, "divr", dis_buf, Iop_DivF64, True );
4589 break;
4590
sewardja58ea662004-08-15 03:12:41 +00004591 default:
4592 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
4593 vex_printf("first_opcode == 0xDC\n");
4594 goto decode_fail;
4595 }
4596
4597 } else {
sewardjbdc7d212004-09-09 02:46:40 +00004598
4599 delta++;
4600 switch (modrm) {
4601
sewardj3fd5e572004-09-09 22:43:51 +00004602 case 0xC0 ... 0xC7: /* FADD %st(0),%st(?) */
4603 fp_do_op_ST_ST ( "add", Iop_AddF64, 0, modrm - 0xC0, False );
4604 break;
4605
sewardjcfded9a2004-09-09 11:44:16 +00004606 case 0xC8 ... 0xCF: /* FMUL %st(0),%st(?) */
4607 fp_do_op_ST_ST ( "mul", Iop_MulF64, 0, modrm - 0xC8, False );
4608 break;
4609
sewardj47341042004-09-19 11:55:46 +00004610 case 0xE0 ... 0xE7: /* FSUBR %st(0),%st(?) */
4611 fp_do_oprev_ST_ST ( "subr", Iop_SubF64, 0, modrm - 0xE0, False );
4612 break;
4613
sewardjcfded9a2004-09-09 11:44:16 +00004614 case 0xE8 ... 0xEF: /* FSUB %st(0),%st(?) */
4615 fp_do_op_ST_ST ( "sub", Iop_SubF64, 0, modrm - 0xE8, False );
4616 break;
4617
sewardja0d48d62004-09-20 21:19:03 +00004618 case 0xF0 ... 0xF7: /* FDIVR %st(0),%st(?) */
4619 fp_do_oprev_ST_ST ( "divr", Iop_DivF64, 0, modrm - 0xF0, False );
4620 break;
4621
sewardjbdc7d212004-09-09 02:46:40 +00004622 case 0xF8 ... 0xFF: /* FDIV %st(0),%st(?) */
4623 fp_do_op_ST_ST ( "div", Iop_DivF64, 0, modrm - 0xF8, False );
4624 break;
4625
4626 default:
4627 goto decode_fail;
sewardj5bd4d162004-11-10 13:02:48 +00004628 }
sewardjbdc7d212004-09-09 02:46:40 +00004629
sewardja58ea662004-08-15 03:12:41 +00004630 }
sewardjd1725d12004-08-12 20:46:53 +00004631 }
4632
4633 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDD opcodes +-+-+-+-+-+-+-+ */
4634 else
4635 if (first_opcode == 0xDD) {
4636
4637 if (modrm < 0xC0) {
4638
sewardjfeeb8a82004-11-30 12:30:11 +00004639 /* bits 5,4,3 are an opcode extension, and the modRM also
sewardjd1725d12004-08-12 20:46:53 +00004640 specifies an address. */
sewardjbb53f8c2004-08-14 11:50:01 +00004641 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
4642 delta += len;
sewardjd1725d12004-08-12 20:46:53 +00004643
4644 switch (gregOfRM(modrm)) {
4645
4646 case 0: /* FLD double-real */
4647 DIP("fldD %s\n", dis_buf);
sewardj207557a2004-08-27 12:00:18 +00004648 fp_push();
4649 put_ST(0, IRExpr_LDle(Ity_F64, mkexpr(addr)));
sewardjbb53f8c2004-08-14 11:50:01 +00004650 break;
sewardjd1725d12004-08-12 20:46:53 +00004651
sewardjd1725d12004-08-12 20:46:53 +00004652 case 2: /* FST double-real */
sewardj89cd0932004-09-08 18:23:25 +00004653 DIP("fstD %s", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00004654 storeLE(mkexpr(addr), get_ST(0));
sewardjd1725d12004-08-12 20:46:53 +00004655 break;
sewardj89cd0932004-09-08 18:23:25 +00004656
sewardja58ea662004-08-15 03:12:41 +00004657 case 3: /* FSTP double-real */
4658 DIP("fstpD %s", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00004659 storeLE(mkexpr(addr), get_ST(0));
4660 fp_pop();
sewardja58ea662004-08-15 03:12:41 +00004661 break;
sewardjd1725d12004-08-12 20:46:53 +00004662
sewardj9fc9e782004-11-26 17:57:40 +00004663 case 4: { /* FRSTOR m108 */
sewardj893aada2004-11-29 19:57:54 +00004664 /* Uses dirty helper:
4665 VexEmWarn x86g_do_FRSTOR ( VexGuestX86State*, Addr32 ) */
4666 IRTemp ew = newTemp(Ity_I32);
4667 IRDirty* d = unsafeIRDirty_0_N (
4668 0/*regparms*/,
4669 "x86g_dirtyhelper_FRSTOR",
4670 &x86g_dirtyhelper_FRSTOR,
4671 mkIRExprVec_1( mkexpr(addr) )
4672 );
sewardj9fc9e782004-11-26 17:57:40 +00004673 d->needsBBP = True;
sewardj893aada2004-11-29 19:57:54 +00004674 d->tmp = ew;
sewardj9fc9e782004-11-26 17:57:40 +00004675 /* declare we're reading memory */
4676 d->mFx = Ifx_Read;
4677 d->mAddr = mkexpr(addr);
4678 d->mSize = 108;
4679
4680 /* declare we're writing guest state */
sewardj893aada2004-11-29 19:57:54 +00004681 d->nFxState = 5;
sewardj9fc9e782004-11-26 17:57:40 +00004682
4683 d->fxState[0].fx = Ifx_Write;
sewardjc9a43662004-11-30 18:51:59 +00004684 d->fxState[0].offset = OFFB_FTOP;
sewardj9fc9e782004-11-26 17:57:40 +00004685 d->fxState[0].size = sizeof(UInt);
4686
4687 d->fxState[1].fx = Ifx_Write;
sewardjc9a43662004-11-30 18:51:59 +00004688 d->fxState[1].offset = OFFB_FPREGS;
sewardj9fc9e782004-11-26 17:57:40 +00004689 d->fxState[1].size = 8 * sizeof(ULong);
4690
4691 d->fxState[2].fx = Ifx_Write;
sewardjc9a43662004-11-30 18:51:59 +00004692 d->fxState[2].offset = OFFB_FPTAGS;
sewardj9fc9e782004-11-26 17:57:40 +00004693 d->fxState[2].size = 8 * sizeof(UChar);
4694
4695 d->fxState[3].fx = Ifx_Write;
sewardjc9a43662004-11-30 18:51:59 +00004696 d->fxState[3].offset = OFFB_FPROUND;
sewardj9fc9e782004-11-26 17:57:40 +00004697 d->fxState[3].size = sizeof(UInt);
4698
4699 d->fxState[4].fx = Ifx_Write;
sewardjc9a43662004-11-30 18:51:59 +00004700 d->fxState[4].offset = OFFB_FC3210;
sewardj9fc9e782004-11-26 17:57:40 +00004701 d->fxState[4].size = sizeof(UInt);
4702
4703 stmt( IRStmt_Dirty(d) );
4704
sewardj893aada2004-11-29 19:57:54 +00004705 /* ew contains any emulation warning we may need to
4706 issue. If needed, side-exit to the next insn,
4707 reporting the warning, so that Valgrind's dispatcher
4708 sees the warning. */
4709 put_emwarn( mkexpr(ew) );
4710 stmt(
4711 IRStmt_Exit(
4712 binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
4713 Ijk_EmWarn,
4714 IRConst_U32( ((Addr32)guest_eip_bbstart)+delta)
4715 )
4716 );
4717
sewardj9fc9e782004-11-26 17:57:40 +00004718 DIP("frstor %s", dis_buf);
4719 break;
4720 }
4721
4722 case 6: { /* FNSAVE m108 */
sewardj893aada2004-11-29 19:57:54 +00004723 /* Uses dirty helper:
4724 void x86g_do_FSAVE ( VexGuestX86State*, UInt ) */
sewardj9fc9e782004-11-26 17:57:40 +00004725 IRDirty* d = unsafeIRDirty_0_N (
4726 0/*regparms*/,
4727 "x86g_dirtyhelper_FSAVE",
4728 &x86g_dirtyhelper_FSAVE,
4729 mkIRExprVec_1( mkexpr(addr) )
4730 );
4731 d->needsBBP = True;
4732 /* declare we're writing memory */
4733 d->mFx = Ifx_Write;
4734 d->mAddr = mkexpr(addr);
4735 d->mSize = 108;
4736
4737 /* declare we're reading guest state */
sewardj893aada2004-11-29 19:57:54 +00004738 d->nFxState = 5;
sewardj9fc9e782004-11-26 17:57:40 +00004739
4740 d->fxState[0].fx = Ifx_Read;
sewardjc9a43662004-11-30 18:51:59 +00004741 d->fxState[0].offset = OFFB_FTOP;
sewardj9fc9e782004-11-26 17:57:40 +00004742 d->fxState[0].size = sizeof(UInt);
4743
4744 d->fxState[1].fx = Ifx_Read;
sewardjc9a43662004-11-30 18:51:59 +00004745 d->fxState[1].offset = OFFB_FPREGS;
sewardj9fc9e782004-11-26 17:57:40 +00004746 d->fxState[1].size = 8 * sizeof(ULong);
4747
4748 d->fxState[2].fx = Ifx_Read;
sewardjc9a43662004-11-30 18:51:59 +00004749 d->fxState[2].offset = OFFB_FPTAGS;
sewardj9fc9e782004-11-26 17:57:40 +00004750 d->fxState[2].size = 8 * sizeof(UChar);
4751
4752 d->fxState[3].fx = Ifx_Read;
sewardjc9a43662004-11-30 18:51:59 +00004753 d->fxState[3].offset = OFFB_FPROUND;
sewardj9fc9e782004-11-26 17:57:40 +00004754 d->fxState[3].size = sizeof(UInt);
4755
4756 d->fxState[4].fx = Ifx_Read;
sewardjc9a43662004-11-30 18:51:59 +00004757 d->fxState[4].offset = OFFB_FC3210;
sewardj9fc9e782004-11-26 17:57:40 +00004758 d->fxState[4].size = sizeof(UInt);
4759
4760 stmt( IRStmt_Dirty(d) );
4761
4762 DIP("fnsave %s", dis_buf);
4763 break;
4764 }
4765
sewardjd1725d12004-08-12 20:46:53 +00004766 default:
sewardjbb53f8c2004-08-14 11:50:01 +00004767 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
4768 vex_printf("first_opcode == 0xDD\n");
sewardjd1725d12004-08-12 20:46:53 +00004769 goto decode_fail;
sewardjbb53f8c2004-08-14 11:50:01 +00004770 }
sewardjd1725d12004-08-12 20:46:53 +00004771 } else {
sewardja58ea662004-08-15 03:12:41 +00004772 delta++;
4773 switch (modrm) {
sewardjbdc7d212004-09-09 02:46:40 +00004774
sewardj06c32a02004-09-12 12:07:34 +00004775 case 0xD0 ... 0xD7: /* FST %st(0),%st(?) */
4776 r_dst = (UInt)modrm - 0xD0;
4777 DIP("fst %%st(0),%%st(%d)\n", r_dst);
sewardj5bd4d162004-11-10 13:02:48 +00004778 /* P4 manual says: "If the destination operand is a
sewardj06c32a02004-09-12 12:07:34 +00004779 non-empty register, the invalid-operation exception
4780 is not generated. Hence put_ST_UNCHECKED. */
4781 put_ST_UNCHECKED(r_dst, get_ST(0));
4782 break;
4783
sewardja58ea662004-08-15 03:12:41 +00004784 case 0xD8 ... 0xDF: /* FSTP %st(0),%st(?) */
4785 r_dst = (UInt)modrm - 0xD8;
4786 DIP("fstp %%st(0),%%st(%d)\n", r_dst);
sewardj5bd4d162004-11-10 13:02:48 +00004787 /* P4 manual says: "If the destination operand is a
sewardj207557a2004-08-27 12:00:18 +00004788 non-empty register, the invalid-operation exception
4789 is not generated. Hence put_ST_UNCHECKED. */
4790 put_ST_UNCHECKED(r_dst, get_ST(0));
4791 fp_pop();
sewardja58ea662004-08-15 03:12:41 +00004792 break;
sewardjbdc7d212004-09-09 02:46:40 +00004793
4794 case 0xE0 ... 0xE7: /* FUCOM %st(0),%st(?) */
4795 r_dst = (UInt)modrm - 0xE0;
4796 DIP("fucom %%st(0),%%st(%d)\n", r_dst);
sewardjc4be80c2004-09-10 16:17:45 +00004797 /* This forces C1 to zero, which isn't right. */
4798 put_C3210(
4799 binop( Iop_And32,
4800 binop(Iop_Shl32,
4801 binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
4802 mkU8(8)),
4803 mkU32(0x4500)
4804 ));
sewardjbdc7d212004-09-09 02:46:40 +00004805 break;
4806
4807 case 0xE8 ... 0xEF: /* FUCOMP %st(0),%st(?) */
4808 r_dst = (UInt)modrm - 0xE8;
4809 DIP("fucomp %%st(0),%%st(%d)\n", r_dst);
sewardjc4be80c2004-09-10 16:17:45 +00004810 /* This forces C1 to zero, which isn't right. */
4811 put_C3210(
4812 binop( Iop_And32,
4813 binop(Iop_Shl32,
4814 binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
4815 mkU8(8)),
4816 mkU32(0x4500)
4817 ));
sewardjbdc7d212004-09-09 02:46:40 +00004818 fp_pop();
4819 break;
4820
sewardj5bd4d162004-11-10 13:02:48 +00004821 default:
sewardja58ea662004-08-15 03:12:41 +00004822 goto decode_fail;
sewardj5bd4d162004-11-10 13:02:48 +00004823 }
sewardjd1725d12004-08-12 20:46:53 +00004824 }
4825 }
4826
4827 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDE opcodes +-+-+-+-+-+-+-+ */
4828 else
4829 if (first_opcode == 0xDE) {
sewardjbdc7d212004-09-09 02:46:40 +00004830
4831 if (modrm < 0xC0) {
sewardjfeeb8a82004-11-30 12:30:11 +00004832
4833 /* bits 5,4,3 are an opcode extension, and the modRM also
4834 specifies an address. */
4835 IROp fop;
4836 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
4837 delta += len;
4838
4839 switch (gregOfRM(modrm)) {
4840
4841 case 0: /* FIADD m16int */ /* ST(0) += m16int */
4842 DIP("fiaddw %s", dis_buf);
4843 fop = Iop_AddF64;
4844 goto do_fop_m16;
4845
4846 case 1: /* FIMUL m16int */ /* ST(0) *= m16int */
4847 DIP("fimulw %s", dis_buf);
4848 fop = Iop_MulF64;
4849 goto do_fop_m16;
4850
4851 case 4: /* FISUB m16int */ /* ST(0) -= m16int */
4852 DIP("fisubw %s", dis_buf);
4853 fop = Iop_SubF64;
4854 goto do_fop_m16;
4855
4856 case 5: /* FISUBR m16int */ /* ST(0) = m16int - ST(0) */
4857 DIP("fisubrw %s", dis_buf);
4858 fop = Iop_SubF64;
4859 goto do_foprev_m16;
4860
4861 case 6: /* FIDIV m16int */ /* ST(0) /= m16int */
4862 DIP("fisubw %s", dis_buf);
4863 fop = Iop_DivF64;
4864 goto do_fop_m16;
4865
4866 case 7: /* FIDIVR m16int */ /* ST(0) = m16int / ST(0) */
4867 DIP("fidivrw %s", dis_buf);
4868 fop = Iop_DivF64;
4869 goto do_foprev_m16;
4870
4871 do_fop_m16:
4872 put_ST_UNCHECKED(0,
4873 binop(fop,
4874 get_ST(0),
4875 unop(Iop_I32toF64,
4876 unop(Iop_16Sto32,
4877 loadLE(Ity_I16, mkexpr(addr))))));
4878 break;
4879
4880 do_foprev_m16:
4881 put_ST_UNCHECKED(0,
4882 binop(fop,
4883 unop(Iop_I32toF64,
4884 unop(Iop_16Sto32,
4885 loadLE(Ity_I16, mkexpr(addr)))),
4886 get_ST(0)));
4887 break;
4888
4889 default:
4890 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
4891 vex_printf("first_opcode == 0xDE\n");
4892 goto decode_fail;
4893 }
sewardjbdc7d212004-09-09 02:46:40 +00004894
4895 } else {
4896
4897 delta++;
sewardj5bd4d162004-11-10 13:02:48 +00004898 switch (modrm) {
sewardjbdc7d212004-09-09 02:46:40 +00004899
sewardjcfded9a2004-09-09 11:44:16 +00004900 case 0xC0 ... 0xC7: /* FADDP %st(0),%st(?) */
4901 fp_do_op_ST_ST ( "add", Iop_AddF64, 0, modrm - 0xC0, True );
4902 break;
4903
sewardjbdc7d212004-09-09 02:46:40 +00004904 case 0xC8 ... 0xCF: /* FMULP %st(0),%st(?) */
4905 fp_do_op_ST_ST ( "mul", Iop_MulF64, 0, modrm - 0xC8, True );
4906 break;
4907
sewardje166ed02004-10-25 02:27:01 +00004908 case 0xD9: /* FCOMPP %st(0),%st(1) */
4909 DIP("fuompp %%st(0),%%st(1)\n");
4910 /* This forces C1 to zero, which isn't right. */
4911 put_C3210(
4912 binop( Iop_And32,
4913 binop(Iop_Shl32,
4914 binop(Iop_CmpF64, get_ST(0), get_ST(1)),
4915 mkU8(8)),
4916 mkU32(0x4500)
4917 ));
4918 fp_pop();
4919 fp_pop();
4920 break;
4921
sewardjcfded9a2004-09-09 11:44:16 +00004922 case 0xE0 ... 0xE7: /* FSUBRP %st(0),%st(?) */
4923 fp_do_oprev_ST_ST ( "subr", Iop_SubF64, 0, modrm - 0xE0, True );
4924 break;
4925
sewardj3fd5e572004-09-09 22:43:51 +00004926 case 0xE8 ... 0xEF: /* FSUBP %st(0),%st(?) */
4927 fp_do_op_ST_ST ( "sub", Iop_SubF64, 0, modrm - 0xE8, True );
4928 break;
4929
sewardjbdc7d212004-09-09 02:46:40 +00004930 case 0xF0 ... 0xF7: /* FDIVRP %st(0),%st(?) */
4931 fp_do_oprev_ST_ST ( "divr", Iop_DivF64, 0, modrm - 0xF0, True );
4932 break;
4933
4934 case 0xF8 ... 0xFF: /* FDIVP %st(0),%st(?) */
4935 fp_do_op_ST_ST ( "div", Iop_DivF64, 0, modrm - 0xF8, True );
4936 break;
4937
4938 default:
4939 goto decode_fail;
sewardj5bd4d162004-11-10 13:02:48 +00004940 }
sewardjbdc7d212004-09-09 02:46:40 +00004941
4942 }
sewardjd1725d12004-08-12 20:46:53 +00004943 }
4944
4945 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDF opcodes +-+-+-+-+-+-+-+ */
4946 else
4947 if (first_opcode == 0xDF) {
sewardj89cd0932004-09-08 18:23:25 +00004948
4949 if (modrm < 0xC0) {
4950
sewardjfeeb8a82004-11-30 12:30:11 +00004951 /* bits 5,4,3 are an opcode extension, and the modRM also
sewardj89cd0932004-09-08 18:23:25 +00004952 specifies an address. */
4953 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
4954 delta += len;
4955
4956 switch (gregOfRM(modrm)) {
4957
sewardj883b00b2004-09-11 09:30:24 +00004958 case 0: /* FILD m16int */
4959 DIP("fildw %s\n", dis_buf);
4960 fp_push();
4961 put_ST(0, unop(Iop_I32toF64,
4962 unop(Iop_16Sto32,
4963 loadLE(Ity_I16, mkexpr(addr)))));
4964 break;
4965
sewardj37158712004-10-15 21:23:12 +00004966 case 2: /* FIST m16 */
4967 DIP("fistp %s", dis_buf);
4968 storeLE( mkexpr(addr),
4969 binop(Iop_F64toI16, get_roundingmode(), get_ST(0)) );
4970 break;
4971
sewardj89cd0932004-09-08 18:23:25 +00004972 case 3: /* FISTP m16 */
4973 DIP("fistps %s", dis_buf);
sewardj8f3debf2004-09-08 23:42:23 +00004974 storeLE( mkexpr(addr),
4975 binop(Iop_F64toI16, get_roundingmode(), get_ST(0)) );
4976 fp_pop();
sewardj89cd0932004-09-08 18:23:25 +00004977 break;
4978
sewardj89cd0932004-09-08 18:23:25 +00004979 case 5: /* FILD m64 */
4980 DIP("fildll %s\n", dis_buf);
4981 fp_push();
sewardj4cb918d2004-12-03 19:43:31 +00004982 put_ST(0, binop(Iop_I64toF64,
4983 get_roundingmode(),
4984 loadLE(Ity_I64, mkexpr(addr))));
sewardj89cd0932004-09-08 18:23:25 +00004985 break;
sewardj89cd0932004-09-08 18:23:25 +00004986
sewardjcfded9a2004-09-09 11:44:16 +00004987 case 7: /* FISTP m64 */
4988 DIP("fistpll %s", dis_buf);
4989 storeLE( mkexpr(addr),
4990 binop(Iop_F64toI64, get_roundingmode(), get_ST(0)) );
4991 fp_pop();
4992 break;
4993
sewardj89cd0932004-09-08 18:23:25 +00004994 default:
4995 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
4996 vex_printf("first_opcode == 0xDF\n");
4997 goto decode_fail;
4998 }
4999
5000 } else {
sewardjbdc7d212004-09-09 02:46:40 +00005001
5002 delta++;
sewardj5bd4d162004-11-10 13:02:48 +00005003 switch (modrm) {
sewardjbdc7d212004-09-09 02:46:40 +00005004
5005 case 0xE0: /* FNSTSW %ax */
5006 DIP("fnstsw %%ax\n");
5007 /* Invent a plausible-looking FPU status word value and
5008 dump it in %AX:
sewardjc4be80c2004-09-10 16:17:45 +00005009 ((ftop & 7) << 11) | (c3210 & 0x4700)
sewardjbdc7d212004-09-09 02:46:40 +00005010 */
5011 putIReg(2, R_EAX,
5012 unop(Iop_32to16,
5013 binop(Iop_Or32,
5014 binop(Iop_Shl32,
5015 binop(Iop_And32, get_ftop(), mkU32(7)),
5016 mkU8(11)),
sewardjc4be80c2004-09-10 16:17:45 +00005017 binop(Iop_And32, get_C3210(), mkU32(0x4700))
sewardjbdc7d212004-09-09 02:46:40 +00005018 )));
5019 break;
5020
sewardj883b00b2004-09-11 09:30:24 +00005021 case 0xE8 ... 0xEF: /* FUCOMIP %st(0),%st(?) */
sewardj8308aad2004-09-12 11:09:54 +00005022 fp_do_ucomi_ST0_STi( (UInt)modrm - 0xE8, True );
sewardj883b00b2004-09-11 09:30:24 +00005023 break;
5024
sewardjfeeb8a82004-11-30 12:30:11 +00005025 case 0xF0 ... 0xF7: /* FCOMIP %st(0),%st(?) */
5026 /* not really right since COMIP != UCOMIP */
5027 fp_do_ucomi_ST0_STi( (UInt)modrm - 0xF0, True );
5028 break;
5029
sewardjbdc7d212004-09-09 02:46:40 +00005030 default:
5031 goto decode_fail;
sewardj5bd4d162004-11-10 13:02:48 +00005032 }
sewardj89cd0932004-09-08 18:23:25 +00005033 }
5034
sewardjd1725d12004-08-12 20:46:53 +00005035 }
5036
5037 else
5038 vpanic("dis_FPU(x86): invalid primary opcode");
5039
sewardj69d9d662004-10-14 21:58:52 +00005040 *decode_ok = True;
5041 return delta;
5042
sewardjd1725d12004-08-12 20:46:53 +00005043 decode_fail:
5044 *decode_ok = False;
5045 return delta;
5046}
5047
5048
sewardj464efa42004-11-19 22:17:29 +00005049/*------------------------------------------------------------*/
5050/*--- ---*/
5051/*--- MMX INSTRUCTIONS ---*/
5052/*--- ---*/
5053/*------------------------------------------------------------*/
sewardja06e5562004-07-14 13:18:05 +00005054
sewardj464efa42004-11-19 22:17:29 +00005055/* Effect of MMX insns on x87 FPU state (table 11-2 of
5056 IA32 arch manual, volume 3):
5057
5058 Read from, or write to MMX register (viz, any insn except EMMS):
5059 * All tags set to Valid (non-empty) -- FPTAGS[i] := nonzero
5060 * FP stack pointer set to zero
5061
5062 EMMS:
5063 * All tags set to Invalid (empty) -- FPTAGS[i] := zero
5064 * FP stack pointer set to zero
5065*/
5066
sewardj4cb918d2004-12-03 19:43:31 +00005067static void do_MMX_preamble ( void )
sewardj464efa42004-11-19 22:17:29 +00005068{
5069 Int i;
5070 IRArray* descr = mkIRArray( OFFB_FPTAGS, Ity_I8, 8 );
5071 IRExpr* zero = mkU32(0);
5072 IRExpr* tag1 = mkU8(1);
5073 put_ftop(zero);
5074 for (i = 0; i < 8; i++)
5075 stmt( IRStmt_PutI( descr, zero, i, tag1 ) );
5076}
5077
sewardj4cb918d2004-12-03 19:43:31 +00005078static void do_EMMS_preamble ( void )
sewardj464efa42004-11-19 22:17:29 +00005079{
5080 Int i;
5081 IRArray* descr = mkIRArray( OFFB_FPTAGS, Ity_I8, 8 );
5082 IRExpr* zero = mkU32(0);
5083 IRExpr* tag0 = mkU8(0);
5084 put_ftop(zero);
5085 for (i = 0; i < 8; i++)
5086 stmt( IRStmt_PutI( descr, zero, i, tag0 ) );
5087}
5088
5089
5090static IRExpr* getMMXReg ( UInt archreg )
5091{
5092 vassert(archreg < 8);
5093 return IRExpr_Get( OFFB_FPREGS + 8 * archreg, Ity_I64 );
5094}
5095
5096
5097static void putMMXReg ( UInt archreg, IRExpr* e )
5098{
5099 vassert(archreg < 8);
5100 vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_I64);
5101 stmt( IRStmt_Put( OFFB_FPREGS + 8 * archreg, e ) );
5102}
5103
5104
5105static
5106UInt dis_MMXop_regmem_to_reg ( UChar sorb,
5107 UInt delta,
5108 UChar opc,
5109 Char* name,
5110 Bool show_granularity )
5111{
sewardjc9a43662004-11-30 18:51:59 +00005112 HChar dis_buf[50];
sewardj63ba4092004-11-21 12:30:18 +00005113 UChar modrm = getIByte(delta);
5114 Bool isReg = epartIsReg(modrm);
5115 IRExpr* argL = NULL;
5116 IRExpr* argR = NULL;
5117 IRTemp res = newTemp(Ity_I64);
sewardj464efa42004-11-19 22:17:29 +00005118
sewardj2b7a9202004-11-26 19:15:38 +00005119# define XXX(_name) do { hAddr = &_name; hName = #_name; } while (0)
sewardj464efa42004-11-19 22:17:29 +00005120
5121 void* hAddr = NULL;
5122 Char* hName = NULL;
5123 switch (opc) {
sewardjb5452082004-12-04 20:33:02 +00005124 /* Original MMX ones */
sewardj2a9ad022004-11-25 02:46:58 +00005125 case 0xFC: XXX(x86g_calculate_add8x8); break;
5126 case 0xFD: XXX(x86g_calculate_add16x4); break;
5127 case 0xFE: XXX(x86g_calculate_add32x2); break;
sewardj464efa42004-11-19 22:17:29 +00005128
sewardj2a9ad022004-11-25 02:46:58 +00005129 case 0xEC: XXX(x86g_calculate_qadd8Sx8); break;
5130 case 0xED: XXX(x86g_calculate_qadd16Sx4); break;
sewardj464efa42004-11-19 22:17:29 +00005131
sewardj2a9ad022004-11-25 02:46:58 +00005132 case 0xDC: XXX(x86g_calculate_qadd8Ux8); break;
5133 case 0xDD: XXX(x86g_calculate_qadd16Ux4); break;
sewardj464efa42004-11-19 22:17:29 +00005134
sewardj2a9ad022004-11-25 02:46:58 +00005135 case 0xF8: XXX(x86g_calculate_sub8x8); break;
5136 case 0xF9: XXX(x86g_calculate_sub16x4); break;
5137 case 0xFA: XXX(x86g_calculate_sub32x2); break;
sewardj464efa42004-11-19 22:17:29 +00005138
sewardj2a9ad022004-11-25 02:46:58 +00005139 case 0xE8: XXX(x86g_calculate_qsub8Sx8); break;
5140 case 0xE9: XXX(x86g_calculate_qsub16Sx4); break;
sewardj464efa42004-11-19 22:17:29 +00005141
sewardj2a9ad022004-11-25 02:46:58 +00005142 case 0xD8: XXX(x86g_calculate_qsub8Ux8); break;
5143 case 0xD9: XXX(x86g_calculate_qsub16Ux4); break;
sewardj464efa42004-11-19 22:17:29 +00005144
sewardj2a9ad022004-11-25 02:46:58 +00005145 case 0xE5: XXX(x86g_calculate_mulhi16x4); break;
5146 case 0xD5: XXX(x86g_calculate_mullo16x4); break;
5147 case 0xF5: XXX(x86g_calculate_pmaddwd); break;
sewardj4340dac2004-11-20 13:17:04 +00005148
sewardj2a9ad022004-11-25 02:46:58 +00005149 case 0x74: XXX(x86g_calculate_cmpeq8x8); break;
5150 case 0x75: XXX(x86g_calculate_cmpeq16x4); break;
5151 case 0x76: XXX(x86g_calculate_cmpeq32x2); break;
sewardj4340dac2004-11-20 13:17:04 +00005152
sewardj2a9ad022004-11-25 02:46:58 +00005153 case 0x64: XXX(x86g_calculate_cmpge8Sx8); break;
5154 case 0x65: XXX(x86g_calculate_cmpge16Sx4); break;
5155 case 0x66: XXX(x86g_calculate_cmpge32Sx2); break;
sewardj63ba4092004-11-21 12:30:18 +00005156
sewardj2a9ad022004-11-25 02:46:58 +00005157 case 0x6B: XXX(x86g_calculate_packssdw); break;
5158 case 0x63: XXX(x86g_calculate_packsswb); break;
5159 case 0x67: XXX(x86g_calculate_packuswb); break;
sewardj63ba4092004-11-21 12:30:18 +00005160
sewardj2a9ad022004-11-25 02:46:58 +00005161 case 0x68: XXX(x86g_calculate_punpckhbw); break;
5162 case 0x69: XXX(x86g_calculate_punpckhwd); break;
5163 case 0x6A: XXX(x86g_calculate_punpckhdq); break;
sewardj63ba4092004-11-21 12:30:18 +00005164
sewardj2a9ad022004-11-25 02:46:58 +00005165 case 0x60: XXX(x86g_calculate_punpcklbw); break;
5166 case 0x61: XXX(x86g_calculate_punpcklwd); break;
5167 case 0x62: XXX(x86g_calculate_punpckldq); break;
sewardj63ba4092004-11-21 12:30:18 +00005168
sewardj2a9ad022004-11-25 02:46:58 +00005169 case 0xF1: XXX(x86g_calculate_shl16x4); break;
5170 case 0xF2: XXX(x86g_calculate_shl32x2); break;
5171 case 0xF3: XXX(x86g_calculate_shl64x1); break;
sewardj8d14a592004-11-21 17:04:50 +00005172
sewardj2a9ad022004-11-25 02:46:58 +00005173 case 0xD1: XXX(x86g_calculate_shr16Ux4); break;
5174 case 0xD2: XXX(x86g_calculate_shr32Ux2); break;
5175 case 0xD3: XXX(x86g_calculate_shr64Ux1); break;
sewardj8d14a592004-11-21 17:04:50 +00005176
sewardj2a9ad022004-11-25 02:46:58 +00005177 case 0xE1: XXX(x86g_calculate_shr16Sx4); break;
5178 case 0xE2: XXX(x86g_calculate_shr32Sx2); break;
sewardj8d14a592004-11-21 17:04:50 +00005179
sewardj63ba4092004-11-21 12:30:18 +00005180 case 0xDB: break; /* AND */
5181 case 0xDF: break; /* ANDN */
5182 case 0xEB: break; /* OR */
5183 case 0xEF: break; /* XOR */
sewardj464efa42004-11-19 22:17:29 +00005184
sewardjb5452082004-12-04 20:33:02 +00005185 /* Introduced in SSE1 */
5186 case 0xE0: XXX(x86g_calculate_avg8Ux8); break;
5187 case 0xE3: XXX(x86g_calculate_avg16Ux4); break;
5188 case 0xEE: XXX(x86g_calculate_max16Sx4); break;
5189 case 0xDE: XXX(x86g_calculate_max8Ux8); break;
5190 case 0xEA: XXX(x86g_calculate_min16Sx4); break;
5191 case 0xDA: XXX(x86g_calculate_min8Ux8); break;
sewardj0bd7ce62004-12-05 02:47:40 +00005192 case 0xE4: XXX(x86g_calculate_mull16uHIx4); break;
5193 case 0xF6: XXX(x86g_calculate_psadbw); break;
sewardjb5452082004-12-04 20:33:02 +00005194
sewardj164f9272004-12-09 00:39:32 +00005195 /* Introduced in SSE2 */
5196 case 0xD4: XXX(x86g_calculate_add64x1); break;
sewardjb9fa69b2004-12-09 23:25:14 +00005197 case 0xFB: XXX(x86g_calculate_sub64x1); break;
sewardj164f9272004-12-09 00:39:32 +00005198
sewardj464efa42004-11-19 22:17:29 +00005199 default:
5200 vex_printf("\n0x%x\n", (Int)opc);
5201 vpanic("dis_MMXop_regmem_to_reg");
5202 }
5203
5204# undef XXX
5205
sewardj63ba4092004-11-21 12:30:18 +00005206 argL = getMMXReg(gregOfRM(modrm));
5207
sewardj464efa42004-11-19 22:17:29 +00005208 if (isReg) {
sewardj464efa42004-11-19 22:17:29 +00005209 delta++;
sewardj63ba4092004-11-21 12:30:18 +00005210 argR = getMMXReg(eregOfRM(modrm));
sewardj464efa42004-11-19 22:17:29 +00005211 } else {
5212 Int len;
5213 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5214 delta += len;
sewardj63ba4092004-11-21 12:30:18 +00005215 argR = loadLE(Ity_I64, mkexpr(addr));
sewardj464efa42004-11-19 22:17:29 +00005216 }
5217
sewardj63ba4092004-11-21 12:30:18 +00005218 switch (opc) {
5219 case 0xDB:
5220 assign(res, binop(Iop_And64, argL, argR) );
5221 break;
5222 case 0xDF:
sewardjb4acca52004-11-21 13:45:05 +00005223 assign(res, binop(Iop_And64, unop(Iop_Not64, argL), argR) );
sewardj63ba4092004-11-21 12:30:18 +00005224 break;
5225 case 0xEB:
5226 assign(res, binop(Iop_Or64, argL, argR) );
5227 break;
5228 case 0xEF:
5229 /* Possibly do better here if argL and argR are the same reg */
5230 assign(res, binop(Iop_Xor64, argL, argR) );
5231 break;
5232 default:
5233 vassert(hAddr);
5234 vassert(hName);
5235 assign( res,
5236 mkIRExprCCall(
5237 Ity_I64,
5238 0/*regparms*/, hName, hAddr,
5239 mkIRExprVec_2( argL, argR )
5240 )
5241 );
5242 break;
5243 }
5244
5245 putMMXReg( gregOfRM(modrm), mkexpr(res) );
5246
sewardj464efa42004-11-19 22:17:29 +00005247 DIP("%s%s %s, %s\n",
5248 name, show_granularity ? nameMMXGran(opc & 3) : (Char*)"",
5249 ( isReg ? nameMMXReg(eregOfRM(modrm)) : dis_buf ),
5250 nameMMXReg(gregOfRM(modrm)) );
5251
5252 return delta;
5253}
5254
5255
5256
5257static
5258UInt dis_MMX ( Bool* decode_ok, UChar sorb, Int sz, UInt delta )
5259{
5260 Int len;
5261 UChar modrm;
sewardjc9a43662004-11-30 18:51:59 +00005262 HChar dis_buf[50];
sewardj464efa42004-11-19 22:17:29 +00005263 UChar opc = getIByte(delta);
5264 delta++;
5265
sewardj4cb918d2004-12-03 19:43:31 +00005266 /* dis_MMX handles all insns except emms. */
5267 do_MMX_preamble();
sewardj464efa42004-11-19 22:17:29 +00005268
5269 switch (opc) {
5270
sewardj2b7a9202004-11-26 19:15:38 +00005271 case 0x6E:
5272 /* MOVD (src)ireg-or-mem (E), (dst)mmxreg (G)*/
5273 vassert(sz == 4);
5274 modrm = getIByte(delta);
5275 if (epartIsReg(modrm)) {
5276 delta++;
5277 putMMXReg(
5278 gregOfRM(modrm),
5279 binop( Iop_32HLto64,
5280 mkU32(0),
5281 getIReg(4, eregOfRM(modrm)) ) );
5282 DIP("movd %s, %s\n",
5283 nameIReg(4,eregOfRM(modrm)), nameMMXReg(gregOfRM(modrm)));
5284 } else {
5285 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5286 delta += len;
5287 putMMXReg(
5288 gregOfRM(modrm),
5289 binop( Iop_32HLto64,
5290 mkU32(0),
5291 loadLE(Ity_I32, mkexpr(addr)) ) );
5292 DIP("movd %s, %s\n", dis_buf, nameMMXReg(gregOfRM(modrm)));
5293 }
5294 break;
5295
5296 case 0x7E: /* MOVD (src)mmxreg (G), (dst)ireg-or-mem (E) */
5297 vassert(sz == 4);
5298 modrm = getIByte(delta);
5299 if (epartIsReg(modrm)) {
5300 delta++;
5301 putIReg( 4, eregOfRM(modrm),
5302 unop(Iop_64to32, getMMXReg(gregOfRM(modrm)) ) );
5303 DIP("movd %s, %s\n",
5304 nameMMXReg(gregOfRM(modrm)), nameIReg(4,eregOfRM(modrm)));
5305 } else {
5306 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5307 delta += len;
5308 storeLE( mkexpr(addr),
5309 unop(Iop_64to32, getMMXReg(gregOfRM(modrm)) ) );
5310 DIP("movd %s, %s\n", nameMMXReg(gregOfRM(modrm)), dis_buf);
5311 }
5312 break;
5313
sewardj464efa42004-11-19 22:17:29 +00005314 case 0x6F:
5315 /* MOVQ (src)mmxreg-or-mem, (dst)mmxreg */
5316 vassert(sz == 4);
5317 modrm = getIByte(delta);
5318 if (epartIsReg(modrm)) {
5319 delta++;
5320 putMMXReg( gregOfRM(modrm), getMMXReg(eregOfRM(modrm)) );
5321 DIP("movq %s, %s\n",
5322 nameMMXReg(eregOfRM(modrm)), nameMMXReg(gregOfRM(modrm)));
5323 } else {
5324 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5325 delta += len;
5326 putMMXReg( gregOfRM(modrm), loadLE(Ity_I64, mkexpr(addr)) );
5327 DIP("movq %s, %s\n",
5328 dis_buf, nameMMXReg(gregOfRM(modrm)));
5329 }
5330 break;
5331
5332 case 0x7F:
5333 /* MOVQ (src)mmxreg, (dst)mmxreg-or-mem */
5334 vassert(sz == 4);
5335 modrm = getIByte(delta);
5336 if (epartIsReg(modrm)) {
sewardjc2feffc2004-12-08 12:31:22 +00005337 /* Fall through. The assembler doesn't appear to generate
5338 these. */
5339 goto mmx_decode_failure;
sewardj464efa42004-11-19 22:17:29 +00005340 } else {
5341 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5342 delta += len;
sewardj893aada2004-11-29 19:57:54 +00005343 storeLE( mkexpr(addr), getMMXReg(gregOfRM(modrm)) );
sewardj464efa42004-11-19 22:17:29 +00005344 DIP("mov(nt)q %s, %s\n",
5345 nameMMXReg(gregOfRM(modrm)), dis_buf);
5346 }
5347 break;
5348
sewardj4340dac2004-11-20 13:17:04 +00005349 case 0xFC:
5350 case 0xFD:
5351 case 0xFE: /* PADDgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj464efa42004-11-19 22:17:29 +00005352 vassert(sz == 4);
5353 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "padd", True );
5354 break;
5355
sewardj4340dac2004-11-20 13:17:04 +00005356 case 0xEC:
5357 case 0xED: /* PADDSgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj464efa42004-11-19 22:17:29 +00005358 vassert(sz == 4);
5359 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "padds", True );
5360 break;
5361
sewardj4340dac2004-11-20 13:17:04 +00005362 case 0xDC:
5363 case 0xDD: /* PADDUSgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj464efa42004-11-19 22:17:29 +00005364 vassert(sz == 4);
5365 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "paddus", True );
5366 break;
5367
sewardj4340dac2004-11-20 13:17:04 +00005368 case 0xF8:
5369 case 0xF9:
5370 case 0xFA: /* PSUBgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj464efa42004-11-19 22:17:29 +00005371 vassert(sz == 4);
5372 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "psub", True );
5373 break;
5374
sewardj4340dac2004-11-20 13:17:04 +00005375 case 0xE8:
5376 case 0xE9: /* PSUBSgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj464efa42004-11-19 22:17:29 +00005377 vassert(sz == 4);
5378 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "psubs", True );
5379 break;
5380
sewardj4340dac2004-11-20 13:17:04 +00005381 case 0xD8:
5382 case 0xD9: /* PSUBUSgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj464efa42004-11-19 22:17:29 +00005383 vassert(sz == 4);
5384 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "psubus", True );
5385 break;
5386
5387 case 0xE5: /* PMULHW (src)mmxreg-or-mem, (dst)mmxreg */
5388 vassert(sz == 4);
5389 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pmulhw", False );
5390 break;
5391
5392 case 0xD5: /* PMULLW (src)mmxreg-or-mem, (dst)mmxreg */
5393 vassert(sz == 4);
5394 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pmullw", False );
5395 break;
5396
sewardj4340dac2004-11-20 13:17:04 +00005397 case 0xF5: /* PMADDWD (src)mmxreg-or-mem, (dst)mmxreg */
5398 vassert(sz == 4);
5399 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pmaddwd", False );
5400 break;
5401
5402 case 0x74:
5403 case 0x75:
5404 case 0x76: /* PCMPEQgg (src)mmxreg-or-mem, (dst)mmxreg */
5405 vassert(sz == 4);
5406 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pcmpeq", True );
5407 break;
5408
5409 case 0x64:
5410 case 0x65:
5411 case 0x66: /* PCMPGTgg (src)mmxreg-or-mem, (dst)mmxreg */
5412 vassert(sz == 4);
5413 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pcmpgt", True );
5414 break;
5415
sewardj63ba4092004-11-21 12:30:18 +00005416 case 0x6B: /* PACKSSDW (src)mmxreg-or-mem, (dst)mmxreg */
5417 vassert(sz == 4);
5418 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "packssdw", False );
5419 break;
5420
5421 case 0x63: /* PACKSSWB (src)mmxreg-or-mem, (dst)mmxreg */
5422 vassert(sz == 4);
5423 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "packsswb", False );
5424 break;
5425
5426 case 0x67: /* PACKUSWB (src)mmxreg-or-mem, (dst)mmxreg */
5427 vassert(sz == 4);
5428 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "packuswb", False );
5429 break;
5430
5431 case 0x68:
5432 case 0x69:
5433 case 0x6A: /* PUNPCKHgg (src)mmxreg-or-mem, (dst)mmxreg */
5434 vassert(sz == 4);
5435 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "punpckh", True );
5436 break;
5437
5438 case 0x60:
5439 case 0x61:
5440 case 0x62: /* PUNPCKLgg (src)mmxreg-or-mem, (dst)mmxreg */
5441 vassert(sz == 4);
5442 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "punpckl", True );
5443 break;
5444
5445 case 0xDB: /* PAND (src)mmxreg-or-mem, (dst)mmxreg */
5446 vassert(sz == 4);
5447 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pand", False );
5448 break;
5449
5450 case 0xDF: /* PANDN (src)mmxreg-or-mem, (dst)mmxreg */
5451 vassert(sz == 4);
5452 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pandn", False );
5453 break;
5454
5455 case 0xEB: /* POR (src)mmxreg-or-mem, (dst)mmxreg */
5456 vassert(sz == 4);
5457 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "por", False );
5458 break;
5459
5460 case 0xEF: /* PXOR (src)mmxreg-or-mem, (dst)mmxreg */
5461 vassert(sz == 4);
5462 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pxor", False );
5463 break;
5464
sewardj8d14a592004-11-21 17:04:50 +00005465 case 0xF1:
5466 case 0xF2:
5467 case 0xF3: /* PSLLgg (src)mmxreg-or-mem, (dst)mmxreg */
5468 vassert(sz == 4);
5469 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "psll", True );
5470 break;
5471
5472 case 0xD1:
5473 case 0xD2:
5474 case 0xD3: /* PSRLgg (src)mmxreg-or-mem, (dst)mmxreg */
5475 vassert(sz == 4);
5476 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "psrl", True );
5477 break;
5478
5479 case 0xE1:
5480 case 0xE2: /* PSRAgg (src)mmxreg-or-mem, (dst)mmxreg */
5481 vassert(sz == 4);
5482 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "psra", True );
5483 break;
5484
sewardj2b7a9202004-11-26 19:15:38 +00005485 case 0x71:
5486 case 0x72:
5487 case 0x73: {
5488 /* (sz==4): PSLLgg/PSRAgg/PSRLgg mmxreg by imm8 */
5489 UChar byte1, byte2, byte3, subopc, mmreg;
5490 void* hAddr;
5491 Char* hName;
5492 vassert(sz == 4);
5493 byte1 = opc; /* 0x71/72/73 */
5494 byte2 = getIByte(delta); delta++; /* amode / sub-opcode */
5495 byte3 = getIByte(delta); delta++; /* imm8 */
5496 mmreg = byte2 & 7;
5497 subopc = (byte2 >> 3) & 7;
5498
5499# define XXX(_name) do { hAddr = &_name; hName = #_name; } while (0)
5500
5501 hAddr = NULL;
5502 hName = NULL;
5503
5504 if (subopc == 2 /*SRL*/ && opc == 0x71)
5505 XXX(x86g_calculate_shr16Ux4);
5506 else if (subopc == 2 /*SRL*/ && opc == 0x72)
5507 XXX(x86g_calculate_shr32Ux2);
5508 else if (subopc == 2 /*SRL*/ && opc == 0x73)
5509 XXX(x86g_calculate_shr64Ux1);
5510
5511 else if (subopc == 4 /*SAR*/ && opc == 0x71)
5512 XXX(x86g_calculate_shr16Sx4);
5513 else if (subopc == 4 /*SAR*/ && opc == 0x72)
5514 XXX(x86g_calculate_shr32Sx2);
5515
5516 else if (subopc == 6 /*SHL*/ && opc == 0x71)
5517 XXX(x86g_calculate_shl16x4);
5518 else if (subopc == 6 /*SHL*/ && opc == 0x72)
5519 XXX(x86g_calculate_shl32x2);
5520 else if (subopc == 6 /*SHL*/ && opc == 0x73)
5521 XXX(x86g_calculate_shl64x1);
5522
5523 else goto mmx_decode_failure;
5524
5525# undef XXX
5526
5527 putMMXReg(
5528 mmreg,
5529 mkIRExprCCall(
5530 Ity_I64,
5531 0/*regparms*/, hName, hAddr,
5532 mkIRExprVec_2( getMMXReg(mmreg),
5533 IRExpr_Const(IRConst_U64( (ULong)byte3 ) ) )
5534 )
5535 );
5536
5537 DIP("ps%s%s $%d, %s\n",
5538 ( subopc == 2 ? "rl"
5539 : subopc == 6 ? "ll"
5540 : subopc == 4 ? "ra"
5541 : "??" ),
5542 nameMMXGran(opc & 3), (Int)byte3, nameMMXReg(mmreg) );
5543 break;
5544 }
5545
5546 /* --- MMX decode failure --- */
sewardj464efa42004-11-19 22:17:29 +00005547 default:
sewardj2b7a9202004-11-26 19:15:38 +00005548 mmx_decode_failure:
sewardj464efa42004-11-19 22:17:29 +00005549 *decode_ok = False;
5550 return delta; /* ignored */
5551
5552 }
5553
5554 *decode_ok = True;
5555 return delta;
5556}
5557
5558
5559/*------------------------------------------------------------*/
5560/*--- More misc arithmetic and other obscure insns. ---*/
5561/*------------------------------------------------------------*/
sewardja06e5562004-07-14 13:18:05 +00005562
5563/* Double length left and right shifts. Apparently only required in
5564 v-size (no b- variant). */
5565static
5566UInt dis_SHLRD_Gv_Ev ( UChar sorb,
5567 UInt delta, UChar modrm,
5568 Int sz,
5569 IRExpr* shift_amt,
5570 Bool amt_is_literal,
5571 Char* shift_amt_txt,
5572 Bool left_shift )
5573{
5574 /* shift_amt :: Ity_I8 is the amount to shift. shift_amt_txt is used
5575 for printing it. And eip on entry points at the modrm byte. */
5576 Int len;
sewardjc9a43662004-11-30 18:51:59 +00005577 HChar dis_buf[50];
sewardja06e5562004-07-14 13:18:05 +00005578
sewardj6d2638e2004-07-15 09:38:27 +00005579 IRType ty = szToITy(sz);
5580 IRTemp gsrc = newTemp(ty);
5581 IRTemp esrc = newTemp(ty);
sewardj92d168d2004-11-15 14:22:12 +00005582 IRTemp addr = IRTemp_INVALID;
sewardj6d2638e2004-07-15 09:38:27 +00005583 IRTemp tmpSH = newTemp(Ity_I8);
sewardj92d168d2004-11-15 14:22:12 +00005584 IRTemp tmpL = IRTemp_INVALID;
5585 IRTemp tmpRes = IRTemp_INVALID;
5586 IRTemp tmpSubSh = IRTemp_INVALID;
sewardja06e5562004-07-14 13:18:05 +00005587 IROp mkpair;
5588 IROp getres;
5589 IROp shift;
sewardja06e5562004-07-14 13:18:05 +00005590 IRExpr* mask = NULL;
5591
5592 vassert(sz == 2 || sz == 4);
5593
5594 /* The E-part is the destination; this is shifted. The G-part
5595 supplies bits to be shifted into the E-part, but is not
5596 changed.
5597
5598 If shifting left, form a double-length word with E at the top
5599 and G at the bottom, and shift this left. The result is then in
5600 the high part.
5601
5602 If shifting right, form a double-length word with G at the top
5603 and E at the bottom, and shift this right. The result is then
5604 at the bottom. */
5605
5606 /* Fetch the operands. */
5607
5608 assign( gsrc, getIReg(sz, gregOfRM(modrm)) );
5609
5610 if (epartIsReg(modrm)) {
5611 delta++;
5612 assign( esrc, getIReg(sz, eregOfRM(modrm)) );
sewardj68511542004-07-28 00:15:44 +00005613 DIP("sh%cd%c %s, %s, %s\n",
sewardja06e5562004-07-14 13:18:05 +00005614 ( left_shift ? 'l' : 'r' ), nameISize(sz),
sewardj68511542004-07-28 00:15:44 +00005615 shift_amt_txt,
sewardja06e5562004-07-14 13:18:05 +00005616 nameIReg(sz, gregOfRM(modrm)), nameIReg(sz, eregOfRM(modrm)));
5617 } else {
5618 addr = disAMode ( &len, sorb, delta, dis_buf );
5619 delta += len;
5620 assign( esrc, loadLE(ty, mkexpr(addr)) );
sewardj68511542004-07-28 00:15:44 +00005621 DIP("sh%cd%c %s, %s, %s\n",
5622 ( left_shift ? 'l' : 'r' ), nameISize(sz),
5623 shift_amt_txt,
5624 nameIReg(sz, gregOfRM(modrm)), dis_buf);
sewardja06e5562004-07-14 13:18:05 +00005625 }
5626
5627 /* Round up the relevant primops. */
5628
5629 if (sz == 4) {
5630 tmpL = newTemp(Ity_I64);
5631 tmpRes = newTemp(Ity_I32);
5632 tmpSubSh = newTemp(Ity_I32);
sewardje539a402004-07-14 18:24:17 +00005633 mkpair = Iop_32HLto64;
sewardj8c7f1ab2004-07-29 20:31:09 +00005634 getres = left_shift ? Iop_64HIto32 : Iop_64to32;
sewardje539a402004-07-14 18:24:17 +00005635 shift = left_shift ? Iop_Shl64 : Iop_Shr64;
5636 mask = mkU8(31);
sewardja06e5562004-07-14 13:18:05 +00005637 } else {
5638 /* sz == 2 */
sewardj8c7f1ab2004-07-29 20:31:09 +00005639 tmpL = newTemp(Ity_I32);
5640 tmpRes = newTemp(Ity_I16);
5641 tmpSubSh = newTemp(Ity_I16);
5642 mkpair = Iop_16HLto32;
5643 getres = left_shift ? Iop_32HIto16 : Iop_32to16;
5644 shift = left_shift ? Iop_Shl32 : Iop_Shr32;
5645 mask = mkU8(15);
sewardja06e5562004-07-14 13:18:05 +00005646 }
5647
5648 /* Do the shift, calculate the subshift value, and set
5649 the flag thunk. */
5650
sewardj8c7f1ab2004-07-29 20:31:09 +00005651 assign( tmpSH, binop(Iop_And8, shift_amt, mask) );
5652
sewardja06e5562004-07-14 13:18:05 +00005653 if (left_shift)
5654 assign( tmpL, binop(mkpair, mkexpr(esrc), mkexpr(gsrc)) );
5655 else
5656 assign( tmpL, binop(mkpair, mkexpr(gsrc), mkexpr(esrc)) );
5657
5658 assign( tmpRes, unop(getres, binop(shift, mkexpr(tmpL), mkexpr(tmpSH)) ) );
5659 assign( tmpSubSh,
5660 unop(getres,
5661 binop(shift,
5662 mkexpr(tmpL),
5663 binop(Iop_And8,
5664 binop(Iop_Sub8, mkexpr(tmpSH), mkU8(1) ),
5665 mask))) );
sewardja06e5562004-07-14 13:18:05 +00005666
sewardj2a2ba8b2004-11-08 13:14:06 +00005667 setFlags_DEP1_DEP2_shift ( left_shift ? Iop_Shl32 : Iop_Sar32,
5668 tmpRes, tmpSubSh, ty, tmpSH );
sewardja06e5562004-07-14 13:18:05 +00005669
5670 /* Put result back. */
5671
5672 if (epartIsReg(modrm)) {
5673 putIReg(sz, eregOfRM(modrm), mkexpr(tmpRes));
5674 } else {
5675 storeLE( mkexpr(addr), mkexpr(tmpRes) );
5676 }
5677
5678 if (amt_is_literal) delta++;
5679 return delta;
5680}
5681
5682
sewardj1c6f9912004-09-07 10:15:24 +00005683/* Handle BT/BTS/BTR/BTC Gv, Ev. Apparently b-size is not
5684 required. */
5685
5686typedef enum { BtOpNone, BtOpSet, BtOpReset, BtOpComp } BtOp;
5687
5688static Char* nameBtOp ( BtOp op )
5689{
5690 switch (op) {
5691 case BtOpNone: return "";
5692 case BtOpSet: return "s";
5693 case BtOpReset: return "r";
5694 case BtOpComp: return "c";
5695 default: vpanic("nameBtOp(x86)");
5696 }
5697}
5698
5699
5700static
5701UInt dis_bt_G_E ( UChar sorb, Int sz, UInt delta, BtOp op )
5702{
sewardjc9a43662004-11-30 18:51:59 +00005703 HChar dis_buf[50];
sewardj1c6f9912004-09-07 10:15:24 +00005704 UChar modrm;
5705 Int len;
5706 IRTemp t_fetched, t_bitno0, t_bitno1, t_bitno2, t_addr0,
5707 t_addr1, t_esp, t_mask;
5708
5709 vassert(sz == 2 || sz == 4);
5710
5711 t_fetched = t_bitno0 = t_bitno1 = t_bitno2
sewardj92d168d2004-11-15 14:22:12 +00005712 = t_addr0 = t_addr1 = t_esp = t_mask = IRTemp_INVALID;
sewardj1c6f9912004-09-07 10:15:24 +00005713
5714 t_fetched = newTemp(Ity_I8);
5715 t_bitno0 = newTemp(Ity_I32);
5716 t_bitno1 = newTemp(Ity_I32);
5717 t_bitno2 = newTemp(Ity_I8);
5718 t_addr1 = newTemp(Ity_I32);
5719 modrm = getIByte(delta);
5720
5721 assign( t_bitno0, widenUto32(getIReg(sz, gregOfRM(modrm))) );
5722
5723 if (epartIsReg(modrm)) {
sewardj1c6f9912004-09-07 10:15:24 +00005724 delta++;
5725 /* Get it onto the client's stack. */
5726 t_esp = newTemp(Ity_I32);
5727 t_addr0 = newTemp(Ity_I32);
5728
5729 assign( t_esp, binop(Iop_Sub32, getIReg(4, R_ESP), mkU32(sz)) );
5730 putIReg(4, R_ESP, mkexpr(t_esp));
5731
5732 storeLE( mkexpr(t_esp), getIReg(sz, eregOfRM(modrm)) );
5733
5734 /* Make t_addr0 point at it. */
5735 assign( t_addr0, mkexpr(t_esp) );
5736
5737 /* Mask out upper bits of the shift amount, since we're doing a
5738 reg. */
5739 assign( t_bitno1, binop(Iop_And32,
5740 mkexpr(t_bitno0),
5741 mkU32(sz == 4 ? 31 : 15)) );
5742
5743 } else {
5744 t_addr0 = disAMode ( &len, sorb, delta, dis_buf );
5745 delta += len;
5746 assign( t_bitno1, mkexpr(t_bitno0) );
5747 }
5748
5749 /* At this point: t_addr0 is the address being operated on. If it
5750 was a reg, we will have pushed it onto the client's stack.
5751 t_bitno1 is the bit number, suitably masked in the case of a
5752 reg. */
5753
5754 /* Now the main sequence. */
5755 assign( t_addr1,
5756 binop(Iop_Add32,
5757 mkexpr(t_addr0),
5758 binop(Iop_Sar32, mkexpr(t_bitno1), mkU8(3))) );
5759
5760 /* t_addr1 now holds effective address */
5761
5762 assign( t_bitno2,
5763 unop(Iop_32to8,
5764 binop(Iop_And32, mkexpr(t_bitno1), mkU32(7))) );
5765
5766 /* t_bitno2 contains offset of bit within byte */
5767
5768 if (op != BtOpNone) {
5769 t_mask = newTemp(Ity_I8);
5770 assign( t_mask, binop(Iop_Shl8, mkU8(1), mkexpr(t_bitno2)) );
5771 }
sewardj4963a422004-10-14 23:34:03 +00005772
sewardj1c6f9912004-09-07 10:15:24 +00005773 /* t_mask is now a suitable byte mask */
5774
5775 assign( t_fetched, loadLE(Ity_I8, mkexpr(t_addr1)) );
5776
5777 if (op != BtOpNone) {
5778 switch (op) {
5779 case BtOpSet:
5780 storeLE( mkexpr(t_addr1),
5781 binop(Iop_Or8, mkexpr(t_fetched),
5782 mkexpr(t_mask)) );
5783 break;
5784 case BtOpComp:
5785 storeLE( mkexpr(t_addr1),
5786 binop(Iop_Xor8, mkexpr(t_fetched),
5787 mkexpr(t_mask)) );
5788 break;
5789 case BtOpReset:
5790 storeLE( mkexpr(t_addr1),
5791 binop(Iop_And8, mkexpr(t_fetched),
5792 unop(Iop_Not8, mkexpr(t_mask))) );
5793 break;
5794 default:
5795 vpanic("dis_bt_G_E(x86)");
5796 }
5797 }
5798
5799 /* Side effect done; now get selected bit into Carry flag */
sewardj2a2ba8b2004-11-08 13:14:06 +00005800 /* Flags: C=selected bit, O,S,Z,A,P undefined, so are set to zero. */
sewardj2a9ad022004-11-25 02:46:58 +00005801 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
sewardj2a2ba8b2004-11-08 13:14:06 +00005802 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
sewardj1c6f9912004-09-07 10:15:24 +00005803 stmt( IRStmt_Put(
sewardj2a2ba8b2004-11-08 13:14:06 +00005804 OFFB_CC_DEP1,
sewardj1c6f9912004-09-07 10:15:24 +00005805 binop(Iop_And32,
5806 binop(Iop_Shr32,
5807 unop(Iop_8Uto32, mkexpr(t_fetched)),
sewardj5bd4d162004-11-10 13:02:48 +00005808 mkexpr(t_bitno2)),
5809 mkU32(1)))
sewardj1c6f9912004-09-07 10:15:24 +00005810 );
5811
5812 /* Move reg operand from stack back to reg */
5813 if (epartIsReg(modrm)) {
5814 /* t_esp still points at it. */
sewardj4963a422004-10-14 23:34:03 +00005815 putIReg(sz, eregOfRM(modrm), loadLE(szToITy(sz), mkexpr(t_esp)) );
sewardj1c6f9912004-09-07 10:15:24 +00005816 putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t_esp), mkU32(sz)) );
5817 }
5818
5819 DIP("bt%s%c %s, %s\n",
5820 nameBtOp(op), nameISize(sz), nameIReg(sz, gregOfRM(modrm)),
5821 ( epartIsReg(modrm) ? nameIReg(sz, eregOfRM(modrm)) : dis_buf ) );
5822
5823 return delta;
5824}
sewardjce646f22004-08-31 23:55:54 +00005825
5826
5827
5828/* Handle BSF/BSR. Only v-size seems necessary. */
5829static
5830UInt dis_bs_E_G ( UChar sorb, Int sz, UInt delta, Bool fwds )
5831{
5832 Bool isReg;
5833 UChar modrm;
sewardjc9a43662004-11-30 18:51:59 +00005834 HChar dis_buf[50];
sewardjce646f22004-08-31 23:55:54 +00005835
5836 IRType ty = szToITy(sz);
5837 IRTemp src = newTemp(ty);
5838 IRTemp dst = newTemp(ty);
5839
5840 IRTemp src32 = newTemp(Ity_I32);
5841 IRTemp dst32 = newTemp(Ity_I32);
5842 IRTemp src8 = newTemp(Ity_I8);
5843
5844 vassert(sz == 4 || sz == 2);
sewardjce646f22004-08-31 23:55:54 +00005845
5846 modrm = getIByte(delta);
5847
5848 isReg = epartIsReg(modrm);
5849 if (isReg) {
5850 delta++;
5851 assign( src, getIReg(sz, eregOfRM(modrm)) );
5852 } else {
5853 Int len;
5854 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5855 delta += len;
5856 assign( src, loadLE(ty, mkexpr(addr)) );
5857 }
5858
5859 DIP("bs%c%c %s, %s\n",
5860 fwds ? 'f' : 'r', nameISize(sz),
5861 ( isReg ? nameIReg(sz, eregOfRM(modrm)) : dis_buf ),
5862 nameIReg(sz, gregOfRM(modrm)));
5863
5864 /* Generate an 8-bit expression which is zero iff the
5865 original is zero, and nonzero otherwise */
5866 assign( src8,
5867 unop(Iop_1Uto8, binop(mkSizedOp(ty,Iop_CmpNE8),
5868 mkexpr(src), mkU(ty,0))) );
5869
5870 /* Flags: Z is 1 iff source value is zero. All others
5871 are undefined -- we force them to zero. */
sewardj2a9ad022004-11-25 02:46:58 +00005872 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
sewardj2a2ba8b2004-11-08 13:14:06 +00005873 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
sewardjce646f22004-08-31 23:55:54 +00005874 stmt( IRStmt_Put(
sewardj2a2ba8b2004-11-08 13:14:06 +00005875 OFFB_CC_DEP1,
sewardjce646f22004-08-31 23:55:54 +00005876 IRExpr_Mux0X( mkexpr(src8),
5877 /* src==0 */
sewardj2a9ad022004-11-25 02:46:58 +00005878 mkU32(X86G_CC_MASK_Z),
sewardjce646f22004-08-31 23:55:54 +00005879 /* src!=0 */
5880 mkU32(0)
5881 )
5882 ));
5883
5884 /* Result: iff source value is zero, we can't use
5885 Iop_Clz32/Iop_Ctz32 as they have no defined result in that case.
5886 But anyway, Intel x86 semantics say the result is undefined in
5887 such situations. Hence handle the zero case specially. */
5888
5889 /* Bleh. What we compute:
5890
5891 bsf32: if src == 0 then 0 else Ctz32(src)
5892 bsr32: if src == 0 then 0 else 31 - Clz32(src)
5893
5894 bsf16: if src == 0 then 0 else Ctz32(16Uto32(src))
5895 bsr16: if src == 0 then 0 else 31 - Clz32(16Uto32(src))
5896
5897 First, widen src to 32 bits if it is not already.
sewardj37158712004-10-15 21:23:12 +00005898
5899 Postscript 15 Oct 04: it seems that at least VIA Nehemiah leaves the
5900 dst register unchanged when src == 0. Hence change accordingly.
sewardjce646f22004-08-31 23:55:54 +00005901 */
5902 if (sz == 2)
5903 assign( src32, unop(Iop_16Uto32, mkexpr(src)) );
5904 else
5905 assign( src32, mkexpr(src) );
5906
5907 /* The main computation, guarding against zero. */
5908 assign( dst32,
5909 IRExpr_Mux0X(
5910 mkexpr(src8),
sewardj37158712004-10-15 21:23:12 +00005911 /* src == 0 -- leave dst unchanged */
5912 widenUto32( getIReg( sz, gregOfRM(modrm) ) ),
sewardjce646f22004-08-31 23:55:54 +00005913 /* src != 0 */
5914 fwds ? unop(Iop_Ctz32, mkexpr(src32))
5915 : binop(Iop_Sub32,
5916 mkU32(31),
5917 unop(Iop_Clz32, mkexpr(src32)))
5918 )
5919 );
5920
5921 if (sz == 2)
5922 assign( dst, unop(Iop_32to16, mkexpr(dst32)) );
5923 else
5924 assign( dst, mkexpr(dst32) );
5925
5926 /* dump result back */
5927 putIReg( sz, gregOfRM(modrm), mkexpr(dst) );
5928
5929 return delta;
5930}
sewardj64e1d652004-07-12 14:00:46 +00005931
5932
5933static
5934void codegen_xchg_eAX_Reg ( Int sz, Int reg )
5935{
5936 IRType ty = szToITy(sz);
5937 IRTemp t1 = newTemp(ty);
5938 IRTemp t2 = newTemp(ty);
5939 vassert(sz == 2 || sz == 4);
5940 assign( t1, getIReg(sz, R_EAX) );
5941 assign( t2, getIReg(sz, reg) );
5942 putIReg( sz, R_EAX, mkexpr(t2) );
5943 putIReg( sz, reg, mkexpr(t1) );
5944 DIP("xchg%c %s, %s\n",
5945 nameISize(sz), nameIReg(sz, R_EAX), nameIReg(sz, reg));
5946}
5947
5948
sewardjbdc7d212004-09-09 02:46:40 +00005949static
5950void codegen_SAHF ( void )
5951{
5952 /* Set the flags to:
sewardj2a9ad022004-11-25 02:46:58 +00005953 (x86g_calculate_flags_all() & X86G_CC_MASK_O) -- retain the old O flag
5954 | (%AH & (X86G_CC_MASK_S|X86G_CC_MASK_Z|X86G_CC_MASK_A
5955 |X86G_CC_MASK_P|X86G_CC_MASK_C)
sewardjbdc7d212004-09-09 02:46:40 +00005956 */
sewardj2a9ad022004-11-25 02:46:58 +00005957 UInt mask_SZACP = X86G_CC_MASK_S|X86G_CC_MASK_Z|X86G_CC_MASK_A
5958 |X86G_CC_MASK_C|X86G_CC_MASK_P;
sewardjbdc7d212004-09-09 02:46:40 +00005959 IRTemp oldflags = newTemp(Ity_I32);
sewardj2a9ad022004-11-25 02:46:58 +00005960 assign( oldflags, mk_x86g_calculate_eflags_all() );
5961 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
sewardj2a2ba8b2004-11-08 13:14:06 +00005962 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
5963 stmt( IRStmt_Put( OFFB_CC_DEP1,
sewardjbdc7d212004-09-09 02:46:40 +00005964 binop(Iop_Or32,
sewardj2a9ad022004-11-25 02:46:58 +00005965 binop(Iop_And32, mkexpr(oldflags), mkU32(X86G_CC_MASK_O)),
sewardjbdc7d212004-09-09 02:46:40 +00005966 binop(Iop_And32,
5967 binop(Iop_Shr32, getIReg(4, R_EAX), mkU8(8)),
5968 mkU32(mask_SZACP))
5969 )
5970 ));
5971}
5972
5973
sewardjc9a65702004-07-07 16:32:57 +00005974//-- static
5975//-- void codegen_LAHF ( UCodeBlock* cb )
5976//-- {
5977//-- Int t = newTemp(cb);
5978//--
5979//-- /* Pushed arg is ignored, it just provides somewhere to put the
5980//-- return value. */
5981//-- uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, t);
5982//-- uInstr0(cb, CALLM_S, 0);
5983//-- uInstr1(cb, PUSH, 4, TempReg, t);
5984//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_LAHF));
5985//-- uFlagsRWU(cb, FlagsSZACP, FlagsEmpty, FlagsEmpty);
5986//-- uInstr1(cb, POP, 4, TempReg, t);
5987//-- uInstr0(cb, CALLM_E, 0);
5988//--
5989//-- /* At this point, the %ah sub-register in %eax has been updated,
5990//-- the rest is the same, so do a PUT of the whole thing. */
5991//-- uInstr2(cb, PUT, 4, TempReg, t, ArchReg, R_EAX);
5992//-- }
5993//--
sewardj458a6f82004-08-25 12:46:02 +00005994
5995static
5996UInt dis_cmpxchg_G_E ( UChar sorb,
5997 Int size,
5998 UInt delta0 )
5999{
sewardjc9a43662004-11-30 18:51:59 +00006000 HChar dis_buf[50];
sewardj458a6f82004-08-25 12:46:02 +00006001 Int len;
6002
6003 IRType ty = szToITy(size);
6004 IRTemp acc = newTemp(ty);
6005 IRTemp src = newTemp(ty);
sewardj2a2ba8b2004-11-08 13:14:06 +00006006 //IRTemp res = newTemp(ty);
sewardj458a6f82004-08-25 12:46:02 +00006007 IRTemp dest = newTemp(ty);
6008 IRTemp dest2 = newTemp(ty);
6009 IRTemp acc2 = newTemp(ty);
6010 IRTemp cond8 = newTemp(Ity_I8);
sewardj92d168d2004-11-15 14:22:12 +00006011 IRTemp addr = IRTemp_INVALID;
sewardj458a6f82004-08-25 12:46:02 +00006012 UChar rm = getUChar(delta0);
6013
6014 if (epartIsReg(rm)) {
6015 assign( dest, getIReg(size, eregOfRM(rm)) );
6016 delta0++;
6017 DIP("cmpxchg%c %s,%s\n", nameISize(size),
6018 nameIReg(size,gregOfRM(rm)),
6019 nameIReg(size,eregOfRM(rm)) );
sewardj458a6f82004-08-25 12:46:02 +00006020 } else {
6021 addr = disAMode ( &len, sorb, delta0, dis_buf );
6022 assign( dest, loadLE(ty, mkexpr(addr)) );
6023 delta0 += len;
6024 DIP("cmpxchg%c %s,%s\n", nameISize(size),
6025 nameIReg(size,gregOfRM(rm)), dis_buf);
6026 }
6027
6028 assign( src, getIReg(size, gregOfRM(rm)) );
6029 assign( acc, getIReg(size, R_EAX) );
sewardj2a2ba8b2004-11-08 13:14:06 +00006030 //assign( res, binop( mkSizedOp(ty,Iop_Sub8), mkexpr(acc), mkexpr(dest) ));
6031 setFlags_DEP1_DEP2(Iop_Sub8, acc, dest, ty);
sewardj2a9ad022004-11-25 02:46:58 +00006032 assign( cond8, unop(Iop_1Uto8, mk_x86g_calculate_condition(X86CondZ)) );
sewardj458a6f82004-08-25 12:46:02 +00006033 assign( dest2, IRExpr_Mux0X(mkexpr(cond8), mkexpr(dest), mkexpr(src)) );
6034 assign( acc2, IRExpr_Mux0X(mkexpr(cond8), mkexpr(dest), mkexpr(acc)) );
6035 putIReg(size, R_EAX, mkexpr(acc2));
6036
6037 if (epartIsReg(rm)) {
6038 putIReg(size, eregOfRM(rm), mkexpr(dest2));
6039 } else {
6040 storeLE( mkexpr(addr), mkexpr(dest2) );
6041 }
6042
6043 return delta0;
6044}
6045
6046
sewardjc9a65702004-07-07 16:32:57 +00006047//-- static
6048//-- Addr dis_cmpxchg8b ( UCodeBlock* cb,
6049//-- UChar sorb,
6050//-- Addr eip0 )
6051//-- {
6052//-- Int tal, tah, junkl, junkh, destl, desth, srcl, srch, accl, acch;
sewardjc9a43662004-11-30 18:51:59 +00006053//-- HChar dis_buf[50];
sewardjc9a65702004-07-07 16:32:57 +00006054//-- UChar rm;
6055//-- UInt pair;
6056//--
6057//-- rm = getUChar(eip0);
6058//-- accl = newTemp(cb);
6059//-- acch = newTemp(cb);
6060//-- srcl = newTemp(cb);
6061//-- srch = newTemp(cb);
6062//-- destl = newTemp(cb);
6063//-- desth = newTemp(cb);
6064//-- junkl = newTemp(cb);
6065//-- junkh = newTemp(cb);
6066//--
6067//-- vg_assert(!epartIsReg(rm));
6068//--
6069//-- pair = disAMode ( cb, sorb, eip0, dis_buf );
6070//-- tal = LOW24(pair);
6071//-- tah = newTemp(cb);
6072//-- uInstr2(cb, MOV, 4, TempReg, tal, TempReg, tah);
6073//-- uInstr2(cb, ADD, 4, Literal, 0, TempReg, tah);
6074//-- uLiteral(cb, 4);
6075//-- eip0 += HI8(pair);
6076//-- DIP("cmpxchg8b %s\n", dis_buf);
6077//--
6078//-- uInstr0(cb, CALLM_S, 0);
6079//--
6080//-- uInstr2(cb, LOAD, 4, TempReg, tah, TempReg, desth);
6081//-- uInstr1(cb, PUSH, 4, TempReg, desth);
6082//-- uInstr2(cb, LOAD, 4, TempReg, tal, TempReg, destl);
6083//-- uInstr1(cb, PUSH, 4, TempReg, destl);
6084//-- uInstr2(cb, GET, 4, ArchReg, R_ECX, TempReg, srch);
6085//-- uInstr1(cb, PUSH, 4, TempReg, srch);
6086//-- uInstr2(cb, GET, 4, ArchReg, R_EBX, TempReg, srcl);
6087//-- uInstr1(cb, PUSH, 4, TempReg, srcl);
6088//-- uInstr2(cb, GET, 4, ArchReg, R_EDX, TempReg, acch);
6089//-- uInstr1(cb, PUSH, 4, TempReg, acch);
6090//-- uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, accl);
6091//-- uInstr1(cb, PUSH, 4, TempReg, accl);
6092//--
6093//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_cmpxchg8b));
6094//-- uFlagsRWU(cb, FlagsEmpty, FlagZ, FlagsEmpty);
6095//--
6096//-- uInstr1(cb, POP, 4, TempReg, accl);
6097//-- uInstr2(cb, PUT, 4, TempReg, accl, ArchReg, R_EAX);
6098//-- uInstr1(cb, POP, 4, TempReg, acch);
6099//-- uInstr2(cb, PUT, 4, TempReg, acch, ArchReg, R_EDX);
6100//-- uInstr1(cb, POP, 4, TempReg, srcl);
6101//-- uInstr2(cb, PUT, 4, TempReg, srcl, ArchReg, R_EBX);
6102//-- uInstr1(cb, POP, 4, TempReg, srch);
6103//-- uInstr2(cb, PUT, 4, TempReg, srch, ArchReg, R_ECX);
6104//-- uInstr1(cb, POP, 4, TempReg, destl);
6105//-- uInstr2(cb, STORE, 4, TempReg, destl, TempReg, tal);
6106//-- uInstr1(cb, POP, 4, TempReg, desth);
6107//-- uInstr2(cb, STORE, 4, TempReg, desth, TempReg, tah);
6108//--
6109//-- uInstr0(cb, CALLM_E, 0);
6110//--
6111//-- return eip0;
6112//-- }
sewardj458a6f82004-08-25 12:46:02 +00006113
6114
6115/* Handle conditional move instructions of the form
6116 cmovcc E(reg-or-mem), G(reg)
6117
6118 E(src) is reg-or-mem
6119 G(dst) is reg.
6120
6121 If E is reg, --> GET %E, tmps
6122 GET %G, tmpd
6123 CMOVcc tmps, tmpd
6124 PUT tmpd, %G
6125
6126 If E is mem --> (getAddr E) -> tmpa
6127 LD (tmpa), tmps
6128 GET %G, tmpd
6129 CMOVcc tmps, tmpd
6130 PUT tmpd, %G
6131*/
6132static
6133UInt dis_cmov_E_G ( UChar sorb,
6134 Int sz,
sewardj2a9ad022004-11-25 02:46:58 +00006135 X86Condcode cond,
sewardj458a6f82004-08-25 12:46:02 +00006136 UInt delta0 )
6137{
6138 UChar rm = getIByte(delta0);
sewardjc9a43662004-11-30 18:51:59 +00006139 HChar dis_buf[50];
sewardj458a6f82004-08-25 12:46:02 +00006140 Int len;
6141
sewardj883b00b2004-09-11 09:30:24 +00006142 IRType ty = szToITy(sz);
sewardj458a6f82004-08-25 12:46:02 +00006143 IRTemp tmps = newTemp(ty);
6144 IRTemp tmpd = newTemp(ty);
6145
6146 if (epartIsReg(rm)) {
6147 assign( tmps, getIReg(sz, eregOfRM(rm)) );
6148 assign( tmpd, getIReg(sz, gregOfRM(rm)) );
6149
6150 putIReg(sz, gregOfRM(rm),
sewardj2a9ad022004-11-25 02:46:58 +00006151 IRExpr_Mux0X( unop(Iop_1Uto8,
6152 mk_x86g_calculate_condition(cond)),
sewardj458a6f82004-08-25 12:46:02 +00006153 mkexpr(tmpd),
6154 mkexpr(tmps) )
6155 );
6156 DIP("cmov%c%s %s,%s\n", nameISize(sz),
sewardj2a9ad022004-11-25 02:46:58 +00006157 name_X86Condcode(cond),
sewardj458a6f82004-08-25 12:46:02 +00006158 nameIReg(sz,eregOfRM(rm)),
6159 nameIReg(sz,gregOfRM(rm)));
6160 return 1+delta0;
6161 }
6162
6163 /* E refers to memory */
6164 {
6165 IRTemp addr = disAMode ( &len, sorb, delta0, dis_buf );
6166 assign( tmps, loadLE(ty, mkexpr(addr)) );
6167 assign( tmpd, getIReg(sz, gregOfRM(rm)) );
6168
6169 putIReg(sz, gregOfRM(rm),
sewardj2a9ad022004-11-25 02:46:58 +00006170 IRExpr_Mux0X( unop(Iop_1Uto8,
6171 mk_x86g_calculate_condition(cond)),
sewardj458a6f82004-08-25 12:46:02 +00006172 mkexpr(tmpd),
6173 mkexpr(tmps) )
6174 );
6175
6176 DIP("cmov%c%s %s,%s\n", nameISize(sz),
sewardj2a9ad022004-11-25 02:46:58 +00006177 name_X86Condcode(cond),
sewardj458a6f82004-08-25 12:46:02 +00006178 dis_buf,
6179 nameIReg(sz,gregOfRM(rm)));
6180 return len+delta0;
6181 }
6182}
6183
6184
sewardj883b00b2004-09-11 09:30:24 +00006185static
6186UInt dis_xadd_G_E ( UChar sorb, Int sz, UInt delta0 )
6187{
6188 Int len;
6189 UChar rm = getIByte(delta0);
sewardjc9a43662004-11-30 18:51:59 +00006190 HChar dis_buf[50];
sewardj883b00b2004-09-11 09:30:24 +00006191
6192 // Int tmpd = newTemp(cb);
6193 //Int tmpt = newTemp(cb);
6194
6195 IRType ty = szToITy(sz);
6196 IRTemp tmpd = newTemp(ty);
6197 IRTemp tmpt0 = newTemp(ty);
6198 IRTemp tmpt1 = newTemp(ty);
6199
6200 if (epartIsReg(rm)) {
6201 vassert(0);
6202#if 0
6203 uInstr2(cb, GET, sz, ArchReg, eregOfRM(rm), TempReg, tmpd);
6204 uInstr2(cb, GET, sz, ArchReg, gregOfRM(rm), TempReg, tmpt);
6205 uInstr2(cb, ADD, sz, TempReg, tmpd, TempReg, tmpt);
6206 setFlagsFromUOpcode(cb, ADD);
6207 uInstr2(cb, PUT, sz, TempReg, tmpd, ArchReg, gregOfRM(rm));
6208 uInstr2(cb, PUT, sz, TempReg, tmpt, ArchReg, eregOfRM(rm));
6209 DIP("xadd%c %s, %s\n",
6210 nameISize(sz), nameIReg(sz,gregOfRM(rm)), nameIReg(sz,eregOfRM(rm)));
6211 return 1+eip0;
6212#endif
6213 } else {
6214 IRTemp addr = disAMode ( &len, sorb, delta0, dis_buf );
6215 assign( tmpd, loadLE(ty, mkexpr(addr)) );
6216 assign( tmpt0, getIReg(sz, gregOfRM(rm)) );
sewardj883b00b2004-09-11 09:30:24 +00006217 assign( tmpt1, binop(mkSizedOp(ty,Iop_Add8), mkexpr(tmpd), mkexpr(tmpt0)) );
sewardj2a2ba8b2004-11-08 13:14:06 +00006218 setFlags_DEP1_DEP2( Iop_Add8, tmpd, tmpt0, ty );
sewardj883b00b2004-09-11 09:30:24 +00006219 storeLE( mkexpr(addr), mkexpr(tmpt1) );
6220 putIReg(sz, gregOfRM(rm), mkexpr(tmpd));
6221 DIP("xadd%c %s, %s\n",
6222 nameISize(sz), nameIReg(sz,gregOfRM(rm)), dis_buf);
6223 return len+delta0;
6224 }
6225}
6226
sewardjb64821b2004-12-14 10:00:16 +00006227/* Move 16 bits from Ew (ireg or mem) to G (a segment register). */
6228
sewardj7df596b2004-12-06 14:29:12 +00006229static
6230UInt dis_mov_Ew_Sw ( UChar sorb, UInt delta0 )
6231{
sewardjb64821b2004-12-14 10:00:16 +00006232 Int len;
6233 IRTemp addr;
6234 UChar rm = getIByte(delta0);
6235 HChar dis_buf[50];
sewardj7df596b2004-12-06 14:29:12 +00006236
6237 if (epartIsReg(rm)) {
6238 putSReg( gregOfRM(rm), getIReg(2, eregOfRM(rm)) );
6239 DIP("movw %s,%s\n", nameIReg(2,eregOfRM(rm)), nameSReg(gregOfRM(rm)));
6240 return 1+delta0;
sewardjb64821b2004-12-14 10:00:16 +00006241 } else {
6242 addr = disAMode ( &len, sorb, delta0, dis_buf );
6243 putSReg( gregOfRM(rm), loadLE(Ity_I16, mkexpr(addr)) );
6244 DIP("movw %s,%s\n", dis_buf, nameSReg(gregOfRM(rm)));
6245 return len+delta0;
sewardj7df596b2004-12-06 14:29:12 +00006246 }
6247}
6248
sewardjb64821b2004-12-14 10:00:16 +00006249/* Move 16 bits from G (a segment register) to Ew (ireg or mem). If
6250 dst is ireg and sz==4, zero out top half of it. */
6251
sewardj063f02f2004-10-20 12:36:12 +00006252static
6253UInt dis_mov_Sw_Ew ( UChar sorb,
6254 Int sz,
6255 UInt delta0 )
6256{
sewardjb64821b2004-12-14 10:00:16 +00006257 Int len;
6258 IRTemp addr;
6259 UChar rm = getIByte(delta0);
6260 HChar dis_buf[50];
sewardj063f02f2004-10-20 12:36:12 +00006261
6262 vassert(sz == 2 || sz == 4);
6263
6264 if (epartIsReg(rm)) {
6265 if (sz == 4)
6266 putIReg(4, eregOfRM(rm), unop(Iop_16Uto32, getSReg(gregOfRM(rm))));
6267 else
6268 putIReg(2, eregOfRM(rm), getSReg(gregOfRM(rm)));
6269
6270 DIP("mov %s,%s\n", nameSReg(gregOfRM(rm)), nameIReg(sz,eregOfRM(rm)));
6271 return 1+delta0;
sewardjb64821b2004-12-14 10:00:16 +00006272 } else {
6273 addr = disAMode ( &len, sorb, delta0, dis_buf );
6274 storeLE( mkexpr(addr), getSReg(gregOfRM(rm)) );
sewardj063f02f2004-10-20 12:36:12 +00006275 DIP("mov %s,%s\n", nameSReg(gregOfRM(rm)), dis_buf);
sewardjb64821b2004-12-14 10:00:16 +00006276 return len+delta0;
sewardj063f02f2004-10-20 12:36:12 +00006277 }
sewardj063f02f2004-10-20 12:36:12 +00006278}
6279
6280
sewardjb64821b2004-12-14 10:00:16 +00006281static
6282void dis_push_segreg ( UInt sreg, Int sz )
6283{
6284 IRTemp t1 = newTemp(Ity_I16);
6285 IRTemp ta = newTemp(Ity_I32);
6286 vassert(sz == 2 || sz == 4);
6287
6288 assign( t1, getSReg(sreg) );
6289 assign( ta, binop(Iop_Sub32, getIReg(4, R_ESP), mkU32(sz)) );
6290 putIReg(4, R_ESP, mkexpr(ta));
6291 storeLE( mkexpr(ta), mkexpr(t1) );
6292
6293 DIP("pushw %s\n", nameSReg(sreg));
6294}
6295
6296static
6297void dis_pop_segreg ( UInt sreg, Int sz )
6298{
6299 IRTemp t1 = newTemp(Ity_I16);
6300 IRTemp ta = newTemp(Ity_I32);
6301 vassert(sz == 2 || sz == 4);
6302
6303 assign( ta, getIReg(4, R_ESP) );
6304 assign( t1, loadLE(Ity_I16, mkexpr(ta)) );
6305
6306 putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(ta), mkU32(sz)) );
6307 putSReg( sreg, mkexpr(t1) );
6308 DIP("pop %s\n", nameSReg(sreg));
6309}
sewardje05c42c2004-07-08 20:25:10 +00006310
6311static
6312void dis_ret ( UInt d32 )
6313{
6314 IRTemp t1 = newTemp(Ity_I32), t2 = newTemp(Ity_I32);
6315 assign(t1, getIReg(4,R_ESP));
6316 assign(t2, loadLE(Ity_I32,mkexpr(t1)));
6317 putIReg(4, R_ESP,binop(Iop_Add32, mkexpr(t1), mkU32(4+d32)));
sewardj78c19df2004-07-12 22:49:27 +00006318 jmp_treg(Ijk_Ret,t2);
sewardje05c42c2004-07-08 20:25:10 +00006319}
6320
sewardj4cb918d2004-12-03 19:43:31 +00006321/*------------------------------------------------------------*/
6322/*--- SSE/SSE2/SSE3 helpers ---*/
6323/*------------------------------------------------------------*/
sewardjc9a43662004-11-30 18:51:59 +00006324
sewardj129b3d92004-12-05 15:42:05 +00006325/* Worker function; do not call directly.
6326 Handles full width G = G `op` E and G = (not G) `op` E.
6327*/
6328
6329static UInt dis_SSE_E_to_G_all_wrk (
sewardj1e6ad742004-12-02 16:16:11 +00006330 UChar sorb, UInt delta,
6331 HChar* opname, IROp op,
6332 Bool invertG
6333 )
sewardjc9a43662004-11-30 18:51:59 +00006334{
sewardj1e6ad742004-12-02 16:16:11 +00006335 HChar dis_buf[50];
6336 Int alen;
6337 IRTemp addr;
6338 UChar rm = getIByte(delta);
6339 IRExpr* gpart
sewardj2e383862004-12-12 16:46:47 +00006340 = invertG ? unop(Iop_Not128, getXMMReg(gregOfRM(rm)))
sewardj1e6ad742004-12-02 16:16:11 +00006341 : getXMMReg(gregOfRM(rm));
sewardjc9a43662004-11-30 18:51:59 +00006342 if (epartIsReg(rm)) {
6343 putXMMReg( gregOfRM(rm),
sewardj1e6ad742004-12-02 16:16:11 +00006344 binop(op, gpart,
6345 getXMMReg(eregOfRM(rm))) );
sewardjc9a43662004-11-30 18:51:59 +00006346 DIP("%s %s,%s\n", opname,
6347 nameXMMReg(eregOfRM(rm)),
6348 nameXMMReg(gregOfRM(rm)) );
6349 return delta+1;
6350 } else {
sewardj1e6ad742004-12-02 16:16:11 +00006351 addr = disAMode ( &alen, sorb, delta, dis_buf );
6352 putXMMReg( gregOfRM(rm),
6353 binop(op, gpart,
6354 loadLE(Ity_V128, mkexpr(addr))) );
6355 DIP("%s %s,%s\n", opname,
6356 dis_buf,
6357 nameXMMReg(gregOfRM(rm)) );
6358 return delta+alen;
sewardjc9a43662004-11-30 18:51:59 +00006359 }
6360}
6361
sewardj129b3d92004-12-05 15:42:05 +00006362
6363/* All lanes SSE binary operation, G = G `op` E. */
sewardj1e6ad742004-12-02 16:16:11 +00006364
6365static
sewardj129b3d92004-12-05 15:42:05 +00006366UInt dis_SSE_E_to_G_all ( UChar sorb, UInt delta, HChar* opname, IROp op )
sewardj1e6ad742004-12-02 16:16:11 +00006367{
sewardj129b3d92004-12-05 15:42:05 +00006368 return dis_SSE_E_to_G_all_wrk( sorb, delta, opname, op, False );
sewardj1e6ad742004-12-02 16:16:11 +00006369}
6370
sewardj129b3d92004-12-05 15:42:05 +00006371/* All lanes SSE binary operation, G = (not G) `op` E. */
6372
6373static
6374UInt dis_SSE_E_to_G_all_invG ( UChar sorb, UInt delta,
6375 HChar* opname, IROp op )
6376{
6377 return dis_SSE_E_to_G_all_wrk( sorb, delta, opname, op, True );
6378}
6379
sewardj164f9272004-12-09 00:39:32 +00006380
sewardj129b3d92004-12-05 15:42:05 +00006381/* Lowest 32-bit lane only SSE binary operation, G = G `op` E. */
6382
6383static UInt dis_SSE_E_to_G_lo32 ( UChar sorb, UInt delta,
6384 HChar* opname, IROp op )
6385{
6386 HChar dis_buf[50];
6387 Int alen;
6388 IRTemp addr;
6389 UChar rm = getIByte(delta);
6390 IRExpr* gpart = getXMMReg(gregOfRM(rm));
6391 if (epartIsReg(rm)) {
6392 putXMMReg( gregOfRM(rm),
6393 binop(op, gpart,
6394 getXMMReg(eregOfRM(rm))) );
6395 DIP("%s %s,%s\n", opname,
6396 nameXMMReg(eregOfRM(rm)),
6397 nameXMMReg(gregOfRM(rm)) );
6398 return delta+1;
6399 } else {
6400 /* We can only do a 32-bit memory read, so the upper 3/4 of the
6401 E operand needs to be made simply of zeroes. */
6402 IRTemp epart = newTemp(Ity_V128);
6403 addr = disAMode ( &alen, sorb, delta, dis_buf );
6404 assign( epart, unop( Iop_32Uto128,
6405 loadLE(Ity_I32, mkexpr(addr))) );
6406 putXMMReg( gregOfRM(rm),
6407 binop(op, gpart, mkexpr(epart)) );
6408 DIP("%s %s,%s\n", opname,
6409 dis_buf,
6410 nameXMMReg(gregOfRM(rm)) );
6411 return delta+alen;
6412 }
6413}
6414
sewardj164f9272004-12-09 00:39:32 +00006415
sewardj636ad762004-12-07 11:16:04 +00006416/* Lower 64-bit lane only SSE binary operation, G = G `op` E. */
6417
6418static UInt dis_SSE_E_to_G_lo64 ( UChar sorb, UInt delta,
6419 HChar* opname, IROp op )
6420{
6421 HChar dis_buf[50];
6422 Int alen;
6423 IRTemp addr;
6424 UChar rm = getIByte(delta);
6425 IRExpr* gpart = getXMMReg(gregOfRM(rm));
6426 if (epartIsReg(rm)) {
6427 putXMMReg( gregOfRM(rm),
6428 binop(op, gpart,
6429 getXMMReg(eregOfRM(rm))) );
6430 DIP("%s %s,%s\n", opname,
6431 nameXMMReg(eregOfRM(rm)),
6432 nameXMMReg(gregOfRM(rm)) );
6433 return delta+1;
6434 } else {
6435 /* We can only do a 64-bit memory read, so the upper half of the
6436 E operand needs to be made simply of zeroes. */
6437 IRTemp epart = newTemp(Ity_V128);
6438 addr = disAMode ( &alen, sorb, delta, dis_buf );
6439 assign( epart, unop( Iop_64Uto128,
6440 loadLE(Ity_I64, mkexpr(addr))) );
6441 putXMMReg( gregOfRM(rm),
6442 binop(op, gpart, mkexpr(epart)) );
6443 DIP("%s %s,%s\n", opname,
6444 dis_buf,
6445 nameXMMReg(gregOfRM(rm)) );
6446 return delta+alen;
6447 }
6448}
6449
sewardj164f9272004-12-09 00:39:32 +00006450
sewardj129b3d92004-12-05 15:42:05 +00006451/* All lanes unary SSE operation, G = op(E). */
6452
6453static UInt dis_SSE_E_to_G_unary_all (
sewardj0bd7ce62004-12-05 02:47:40 +00006454 UChar sorb, UInt delta,
6455 HChar* opname, IROp op
6456 )
6457{
6458 HChar dis_buf[50];
6459 Int alen;
6460 IRTemp addr;
6461 UChar rm = getIByte(delta);
6462 if (epartIsReg(rm)) {
6463 putXMMReg( gregOfRM(rm),
6464 unop(op, getXMMReg(eregOfRM(rm))) );
6465 DIP("%s %s,%s\n", opname,
6466 nameXMMReg(eregOfRM(rm)),
6467 nameXMMReg(gregOfRM(rm)) );
6468 return delta+1;
6469 } else {
6470 addr = disAMode ( &alen, sorb, delta, dis_buf );
6471 putXMMReg( gregOfRM(rm),
6472 unop(op, loadLE(Ity_V128, mkexpr(addr))) );
6473 DIP("%s %s,%s\n", opname,
6474 dis_buf,
6475 nameXMMReg(gregOfRM(rm)) );
6476 return delta+alen;
6477 }
6478}
6479
sewardj164f9272004-12-09 00:39:32 +00006480
sewardj129b3d92004-12-05 15:42:05 +00006481/* Lowest 32-bit lane only unary SSE operation, G = op(E). */
sewardj0bd7ce62004-12-05 02:47:40 +00006482
sewardj129b3d92004-12-05 15:42:05 +00006483static UInt dis_SSE_E_to_G_unary_lo32 (
6484 UChar sorb, UInt delta,
6485 HChar* opname, IROp op
6486 )
6487{
6488 /* First we need to get the old G value and patch the low 32 bits
6489 of the E operand into it. Then apply op and write back to G. */
6490 HChar dis_buf[50];
6491 Int alen;
6492 IRTemp addr;
6493 UChar rm = getIByte(delta);
6494 IRTemp oldG0 = newTemp(Ity_V128);
6495 IRTemp oldG1 = newTemp(Ity_V128);
6496
6497 assign( oldG0, getXMMReg(gregOfRM(rm)) );
6498
6499 if (epartIsReg(rm)) {
6500 assign( oldG1,
6501 binop( Iop_Set128lo32,
6502 mkexpr(oldG0),
sewardj35579be2004-12-06 00:36:25 +00006503 getXMMRegLane32(eregOfRM(rm), 0)) );
sewardj129b3d92004-12-05 15:42:05 +00006504 putXMMReg( gregOfRM(rm), unop(op, mkexpr(oldG1)) );
6505 DIP("%s %s,%s\n", opname,
6506 nameXMMReg(eregOfRM(rm)),
6507 nameXMMReg(gregOfRM(rm)) );
6508 return delta+1;
6509 } else {
6510 addr = disAMode ( &alen, sorb, delta, dis_buf );
6511 assign( oldG1,
6512 binop( Iop_Set128lo32,
6513 mkexpr(oldG0),
6514 loadLE(Ity_I32, mkexpr(addr)) ));
6515 putXMMReg( gregOfRM(rm), unop(op, mkexpr(oldG1)) );
6516 DIP("%s %s,%s\n", opname,
6517 dis_buf,
6518 nameXMMReg(gregOfRM(rm)) );
6519 return delta+alen;
6520 }
6521}
6522
sewardj164f9272004-12-09 00:39:32 +00006523
sewardj008754b2004-12-08 14:37:10 +00006524/* Lowest 64-bit lane only unary SSE operation, G = op(E). */
6525
6526static UInt dis_SSE_E_to_G_unary_lo64 (
6527 UChar sorb, UInt delta,
6528 HChar* opname, IROp op
6529 )
6530{
6531 /* First we need to get the old G value and patch the low 64 bits
6532 of the E operand into it. Then apply op and write back to G. */
6533 HChar dis_buf[50];
6534 Int alen;
6535 IRTemp addr;
6536 UChar rm = getIByte(delta);
6537 IRTemp oldG0 = newTemp(Ity_V128);
6538 IRTemp oldG1 = newTemp(Ity_V128);
6539
6540 assign( oldG0, getXMMReg(gregOfRM(rm)) );
6541
6542 if (epartIsReg(rm)) {
6543 assign( oldG1,
6544 binop( Iop_Set128lo64,
6545 mkexpr(oldG0),
6546 getXMMRegLane64(eregOfRM(rm), 0)) );
6547 putXMMReg( gregOfRM(rm), unop(op, mkexpr(oldG1)) );
6548 DIP("%s %s,%s\n", opname,
6549 nameXMMReg(eregOfRM(rm)),
6550 nameXMMReg(gregOfRM(rm)) );
6551 return delta+1;
6552 } else {
6553 addr = disAMode ( &alen, sorb, delta, dis_buf );
6554 assign( oldG1,
6555 binop( Iop_Set128lo64,
6556 mkexpr(oldG0),
6557 loadLE(Ity_I64, mkexpr(addr)) ));
6558 putXMMReg( gregOfRM(rm), unop(op, mkexpr(oldG1)) );
6559 DIP("%s %s,%s\n", opname,
6560 dis_buf,
6561 nameXMMReg(gregOfRM(rm)) );
6562 return delta+alen;
6563 }
6564}
6565
sewardj164f9272004-12-09 00:39:32 +00006566
6567/* SSE integer binary operation:
6568 G = G `op` E (eLeft == False)
6569 G = E `op` G (eLeft == True)
6570*/
6571static UInt dis_SSEint_E_to_G(
6572 UChar sorb, UInt delta,
6573 HChar* opname, IROp op,
6574 Bool eLeft
6575 )
6576{
6577 HChar dis_buf[50];
6578 Int alen;
6579 IRTemp addr;
6580 UChar rm = getIByte(delta);
6581 IRExpr* gpart = getXMMReg(gregOfRM(rm));
6582 IRExpr* epart = NULL;
6583 if (epartIsReg(rm)) {
6584 epart = getXMMReg(eregOfRM(rm));
6585 DIP("%s %s,%s\n", opname,
6586 nameXMMReg(eregOfRM(rm)),
6587 nameXMMReg(gregOfRM(rm)) );
6588 delta += 1;
6589 } else {
6590 addr = disAMode ( &alen, sorb, delta, dis_buf );
6591 epart = loadLE(Ity_V128, mkexpr(addr));
6592 DIP("%s %s,%s\n", opname,
6593 dis_buf,
6594 nameXMMReg(gregOfRM(rm)) );
6595 delta += alen;
6596 }
6597 putXMMReg( gregOfRM(rm),
6598 eLeft ? binop(op, epart, gpart)
6599 : binop(op, gpart, epart) );
6600 return delta;
6601}
6602
6603
sewardjfd226452004-12-07 19:02:18 +00006604/* Helper for doing SSE FP comparisons. */
sewardj0bd7ce62004-12-05 02:47:40 +00006605
sewardj1e6ad742004-12-02 16:16:11 +00006606static void findSSECmpOp ( Bool* needNot, IROp* op,
6607 Int imm8, Bool all_lanes, Int sz )
6608{
6609 imm8 &= 7;
6610 *needNot = False;
6611 *op = Iop_INVALID;
6612 if (imm8 >= 4) {
6613 *needNot = True;
6614 imm8 -= 4;
6615 }
6616
6617 if (sz == 4 && all_lanes) {
6618 switch (imm8) {
6619 case 0: *op = Iop_CmpEQ32Fx4; return;
6620 case 1: *op = Iop_CmpLT32Fx4; return;
6621 case 2: *op = Iop_CmpLE32Fx4; return;
6622 case 3: *op = Iop_CmpUN32Fx4; return;
6623 default: break;
6624 }
6625 }
6626 if (sz == 4 && !all_lanes) {
6627 switch (imm8) {
6628 case 0: *op = Iop_CmpEQ32F0x4; return;
6629 case 1: *op = Iop_CmpLT32F0x4; return;
6630 case 2: *op = Iop_CmpLE32F0x4; return;
6631 case 3: *op = Iop_CmpUN32F0x4; return;
6632 default: break;
6633 }
6634 }
sewardjfd226452004-12-07 19:02:18 +00006635 if (sz == 8 && all_lanes) {
6636 switch (imm8) {
6637 case 0: *op = Iop_CmpEQ64Fx2; return;
6638 case 1: *op = Iop_CmpLT64Fx2; return;
6639 case 2: *op = Iop_CmpLE64Fx2; return;
6640 case 3: *op = Iop_CmpUN64Fx2; return;
6641 default: break;
6642 }
6643 }
6644 if (sz == 8 && !all_lanes) {
6645 switch (imm8) {
6646 case 0: *op = Iop_CmpEQ64F0x2; return;
6647 case 1: *op = Iop_CmpLT64F0x2; return;
6648 case 2: *op = Iop_CmpLE64F0x2; return;
6649 case 3: *op = Iop_CmpUN64F0x2; return;
6650 default: break;
6651 }
sewardj1e6ad742004-12-02 16:16:11 +00006652 }
6653 vpanic("findSSECmpOp(x86,guest)");
6654}
6655
sewardj129b3d92004-12-05 15:42:05 +00006656/* Handles SSE 32F comparisons. */
6657
sewardj1e6ad742004-12-02 16:16:11 +00006658static UInt dis_SSEcmp_E_to_G ( UChar sorb, UInt delta,
6659 HChar* opname, Bool all_lanes, Int sz )
6660{
6661 HChar dis_buf[50];
6662 Int alen, imm8;
6663 IRTemp addr;
6664 Bool needNot = False;
6665 IROp op = Iop_INVALID;
6666 IRTemp plain = newTemp(Ity_V128);
6667 UChar rm = getIByte(delta);
6668 UShort mask = 0;
6669 vassert(sz == 4 || sz == 8);
6670 if (epartIsReg(rm)) {
6671 imm8 = getIByte(delta+1);
6672 findSSECmpOp(&needNot, &op, imm8, all_lanes, sz);
6673 assign( plain, binop(op, getXMMReg(gregOfRM(rm)),
6674 getXMMReg(eregOfRM(rm))) );
6675 delta += 2;
6676 DIP("%s $%d,%s,%s\n", opname,
6677 (Int)imm8,
6678 nameXMMReg(eregOfRM(rm)),
6679 nameXMMReg(gregOfRM(rm)) );
6680 } else {
6681 addr = disAMode ( &alen, sorb, delta, dis_buf );
6682 imm8 = getIByte(delta+alen);
6683 findSSECmpOp(&needNot, &op, imm8, all_lanes, sz);
6684 assign( plain, binop(op, getXMMReg(gregOfRM(rm)),
6685 loadLE(Ity_V128, mkexpr(addr))) );
6686 delta += alen+1;
6687 DIP("%s $%d,%s,%s\n", opname,
6688 (Int)imm8,
6689 dis_buf,
6690 nameXMMReg(gregOfRM(rm)) );
6691 }
6692
sewardj2e383862004-12-12 16:46:47 +00006693 if (needNot && all_lanes) {
6694 putXMMReg( gregOfRM(rm),
6695 unop(Iop_Not128, mkexpr(plain)) );
6696 }
6697 else
6698 if (needNot && !all_lanes) {
sewardjfd226452004-12-07 19:02:18 +00006699 mask = sz==4 ? 0x000F : 0x00FF;
sewardj2e383862004-12-12 16:46:47 +00006700 putXMMReg( gregOfRM(rm),
6701 binop(Iop_Xor128, mkexpr(plain), mkV128(mask)) );
6702 }
6703 else {
6704 putXMMReg( gregOfRM(rm), mkexpr(plain) );
6705 }
sewardj1e6ad742004-12-02 16:16:11 +00006706
sewardj1e6ad742004-12-02 16:16:11 +00006707 return delta;
6708}
6709
sewardjb9fa69b2004-12-09 23:25:14 +00006710
6711/* Vector by scalar shift of G by the amount specified at the bottom
6712 of E. */
6713
6714static UInt dis_SSE_shiftG_byE ( UChar sorb, UInt delta,
6715 HChar* opname, IROp op )
6716{
6717 HChar dis_buf[50];
6718 Int alen, size;
6719 IRTemp addr;
6720 Bool shl, shr, sar;
6721 UChar rm = getIByte(delta);
6722 IRTemp g0 = newTemp(Ity_V128);
6723 IRTemp g1 = newTemp(Ity_V128);
6724 IRTemp amt = newTemp(Ity_I32);
6725 IRTemp amt8 = newTemp(Ity_I8);
6726 if (epartIsReg(rm)) {
6727 assign( amt, getXMMRegLane32(eregOfRM(rm), 0) );
6728 DIP("%s %s,%s\n", opname,
6729 nameXMMReg(eregOfRM(rm)),
6730 nameXMMReg(gregOfRM(rm)) );
6731 delta++;
6732 } else {
6733 addr = disAMode ( &alen, sorb, delta, dis_buf );
6734 assign( amt, loadLE(Ity_I32, mkexpr(addr)) );
6735 DIP("%s %s,%s\n", opname,
6736 dis_buf,
6737 nameXMMReg(gregOfRM(rm)) );
6738 delta += alen;
6739 }
6740 assign( g0, getXMMReg(gregOfRM(rm)) );
6741 assign( amt8, unop(Iop_32to8, mkexpr(amt)) );
6742
6743 shl = shr = sar = False;
6744 size = 0;
6745 switch (op) {
6746 case Iop_ShlN16x8: shl = True; size = 32; break;
6747 case Iop_ShlN32x4: shl = True; size = 32; break;
6748 case Iop_ShlN64x2: shl = True; size = 64; break;
6749 case Iop_SarN16x8: sar = True; size = 16; break;
6750 case Iop_SarN32x4: sar = True; size = 32; break;
6751 case Iop_ShrN16x8: shr = True; size = 16; break;
6752 case Iop_ShrN32x4: shr = True; size = 32; break;
6753 case Iop_ShrN64x2: shr = True; size = 64; break;
6754 default: vassert(0);
6755 }
6756
6757 if (shl || shr) {
6758 assign(
6759 g1,
6760 IRExpr_Mux0X(
6761 unop(Iop_1Uto8,binop(Iop_CmpLT32U,mkexpr(amt),mkU32(size))),
6762 mkV128(0x0000),
6763 binop(op, mkexpr(g0), mkexpr(amt8))
6764 )
6765 );
6766 } else
6767 if (sar) {
6768 assign(
6769 g1,
6770 IRExpr_Mux0X(
6771 unop(Iop_1Uto8,binop(Iop_CmpLT32U,mkexpr(amt),mkU32(size))),
6772 binop(op, mkexpr(g0), mkU8(size-1)),
6773 binop(op, mkexpr(g0), mkexpr(amt8))
6774 )
6775 );
6776 } else {
6777 vassert(0);
6778 }
6779
6780 putXMMReg( gregOfRM(rm), mkexpr(g1) );
6781 return delta;
6782}
6783
6784
6785/* Vector by scalar shift of E by an immediate byte. */
6786
6787static UInt dis_SSE_shiftE_imm ( UChar sorb, UInt delta,
6788 HChar* opname, IROp op )
6789{
6790 Bool shl, shr, sar;
6791 UChar rm = getIByte(delta);
6792 IRTemp g0 = newTemp(Ity_V128);
6793 IRTemp g1 = newTemp(Ity_V128);
6794 UChar amt, size;
6795 vassert(epartIsReg(rm));
6796 vassert(gregOfRM(rm) == 2
6797 || gregOfRM(rm) == 4 || gregOfRM(rm) == 6);
6798 amt = (Int)(getIByte(delta+1));
6799 delta += 2;
6800 DIP("%s $%d,%s\n", opname,
6801 (Int)amt,
6802 nameXMMReg(eregOfRM(rm)) );
6803 assign( g0, getXMMReg(eregOfRM(rm)) );
6804
6805 shl = shr = sar = False;
6806 size = 0;
6807 switch (op) {
6808 case Iop_ShlN16x8: shl = True; size = 16; break;
6809 case Iop_ShlN32x4: shl = True; size = 32; break;
6810 case Iop_ShlN64x2: shl = True; size = 64; break;
6811 case Iop_SarN16x8: sar = True; size = 16; break;
6812 case Iop_SarN32x4: sar = True; size = 32; break;
6813 case Iop_ShrN16x8: shr = True; size = 16; break;
6814 case Iop_ShrN32x4: shr = True; size = 32; break;
6815 case Iop_ShrN64x2: shr = True; size = 64; break;
6816 default: vassert(0);
6817 }
6818
6819 if (shl || shr) {
6820 assign( g1, amt >= size
6821 ? mkV128(0x0000)
6822 : binop(op, mkexpr(g0), mkU8(amt))
6823 );
6824 } else
6825 if (sar) {
6826 assign( g1, amt >= size
6827 ? binop(op, mkexpr(g0), mkU8(size-1))
6828 : binop(op, mkexpr(g0), mkU8(amt))
6829 );
6830 } else {
6831 vassert(0);
6832 }
6833
6834 putXMMReg( eregOfRM(rm), mkexpr(g1) );
6835 return delta;
6836}
6837
6838
sewardjc1e7dfc2004-12-05 19:29:45 +00006839/* Get the current SSE rounding mode. */
sewardjc9a65702004-07-07 16:32:57 +00006840
sewardj4cb918d2004-12-03 19:43:31 +00006841static IRExpr* /* :: Ity_I32 */ get_sse_roundingmode ( void )
6842{
6843 return binop( Iop_And32,
6844 IRExpr_Get( OFFB_SSEROUND, Ity_I32 ),
6845 mkU32(3) );
6846}
6847
sewardj636ad762004-12-07 11:16:04 +00006848static void put_sse_roundingmode ( IRExpr* sseround )
6849{
6850 vassert(typeOfIRExpr(irbb->tyenv, sseround) == Ity_I32);
6851 stmt( IRStmt_Put( OFFB_SSEROUND, sseround ) );
6852}
6853
sewardjc1e7dfc2004-12-05 19:29:45 +00006854/* Break a 128-bit value up into four 32-bit ints. */
6855
6856static void breakup128to32s ( IRTemp t128,
6857 /*OUTs*/
6858 IRTemp* t3, IRTemp* t2,
6859 IRTemp* t1, IRTemp* t0 )
6860{
6861 IRTemp hi64 = newTemp(Ity_I64);
6862 IRTemp lo64 = newTemp(Ity_I64);
6863 assign( hi64, unop(Iop_128HIto64, mkexpr(t128)) );
6864 assign( lo64, unop(Iop_128to64, mkexpr(t128)) );
6865
6866 vassert(t0 && *t0 == IRTemp_INVALID);
6867 vassert(t1 && *t1 == IRTemp_INVALID);
6868 vassert(t2 && *t2 == IRTemp_INVALID);
6869 vassert(t3 && *t3 == IRTemp_INVALID);
6870
6871 *t0 = newTemp(Ity_I32);
6872 *t1 = newTemp(Ity_I32);
6873 *t2 = newTemp(Ity_I32);
6874 *t3 = newTemp(Ity_I32);
6875 assign( *t0, unop(Iop_64to32, mkexpr(lo64)) );
6876 assign( *t1, unop(Iop_64HIto32, mkexpr(lo64)) );
6877 assign( *t2, unop(Iop_64to32, mkexpr(hi64)) );
6878 assign( *t3, unop(Iop_64HIto32, mkexpr(hi64)) );
6879}
6880
6881/* Construct a 128-bit value from four 32-bit ints. */
6882
6883static IRExpr* mk128from32s ( IRTemp t3, IRTemp t2,
6884 IRTemp t1, IRTemp t0 )
6885{
6886 return
6887 binop( Iop_64HLto128,
6888 binop(Iop_32HLto64, mkexpr(t3), mkexpr(t2)),
6889 binop(Iop_32HLto64, mkexpr(t1), mkexpr(t0))
6890 );
6891}
6892
sewardjb9fa69b2004-12-09 23:25:14 +00006893/* Break a 64-bit value up into four 16-bit ints. */
6894
6895static void breakup64to16s ( IRTemp t64,
6896 /*OUTs*/
6897 IRTemp* t3, IRTemp* t2,
6898 IRTemp* t1, IRTemp* t0 )
6899{
6900 IRTemp hi32 = newTemp(Ity_I32);
6901 IRTemp lo32 = newTemp(Ity_I32);
6902 assign( hi32, unop(Iop_64HIto32, mkexpr(t64)) );
6903 assign( lo32, unop(Iop_64to32, mkexpr(t64)) );
6904
6905 vassert(t0 && *t0 == IRTemp_INVALID);
6906 vassert(t1 && *t1 == IRTemp_INVALID);
6907 vassert(t2 && *t2 == IRTemp_INVALID);
6908 vassert(t3 && *t3 == IRTemp_INVALID);
6909
6910 *t0 = newTemp(Ity_I16);
6911 *t1 = newTemp(Ity_I16);
6912 *t2 = newTemp(Ity_I16);
6913 *t3 = newTemp(Ity_I16);
6914 assign( *t0, unop(Iop_32to16, mkexpr(lo32)) );
6915 assign( *t1, unop(Iop_32HIto16, mkexpr(lo32)) );
6916 assign( *t2, unop(Iop_32to16, mkexpr(hi32)) );
6917 assign( *t3, unop(Iop_32HIto16, mkexpr(hi32)) );
6918}
6919
6920/* Construct a 64-bit value from four 16-bit ints. */
6921
6922static IRExpr* mk64from16s ( IRTemp t3, IRTemp t2,
6923 IRTemp t1, IRTemp t0 )
6924{
6925 return
6926 binop( Iop_32HLto64,
6927 binop(Iop_16HLto32, mkexpr(t3), mkexpr(t2)),
6928 binop(Iop_16HLto32, mkexpr(t1), mkexpr(t0))
6929 );
6930}
6931
sewardj4cb918d2004-12-03 19:43:31 +00006932
sewardjc9a65702004-07-07 16:32:57 +00006933/*------------------------------------------------------------*/
sewardjce70a5c2004-10-18 14:09:54 +00006934/*--- Disassemble a single instruction ---*/
sewardjc9a65702004-07-07 16:32:57 +00006935/*------------------------------------------------------------*/
6936
sewardjce70a5c2004-10-18 14:09:54 +00006937/* Disassemble a single instruction into IR. The instruction
6938 is located in host memory at &guest_code[delta].
6939 Set *size to be the size of the instruction.
6940 If the returned value is Dis_Resteer,
6941 the next guest address is assigned to *whereNext. If resteerOK
6942 is False, disInstr may not return Dis_Resteer. */
6943
6944static DisResult disInstr ( /*IN*/ Bool resteerOK,
sewardj5bd4d162004-11-10 13:02:48 +00006945 /*IN*/ Bool (*resteerOkFn) ( Addr64 ),
sewardjce70a5c2004-10-18 14:09:54 +00006946 /*IN*/ UInt delta,
6947 /*OUT*/ UInt* size,
6948 /*OUT*/ Addr64* whereNext )
sewardjc9a65702004-07-07 16:32:57 +00006949{
sewardjce70a5c2004-10-18 14:09:54 +00006950 IRType ty;
sewardjb5452082004-12-04 20:33:02 +00006951 IRTemp addr, t0, t1, t2, t3, t4, t5, t6;
sewardjce70a5c2004-10-18 14:09:54 +00006952 Int alen;
6953 UChar opc, modrm, abyte;
6954 UInt d32;
sewardjc9a43662004-11-30 18:51:59 +00006955 HChar dis_buf[50];
sewardjce70a5c2004-10-18 14:09:54 +00006956 Int am_sz, d_sz;
6957 DisResult whatNext = Dis_Continue;
sewardjc9a43662004-11-30 18:51:59 +00006958 UChar* insn; /* used in SSE decoders */
sewardjce70a5c2004-10-18 14:09:54 +00006959
sewardjc9a65702004-07-07 16:32:57 +00006960 //Char loc_buf[M_VG_ERRTXT];
6961
6962 /* Holds eip at the start of the insn, so that we can print
6963 consistent error messages for unimplemented insns. */
6964 UInt delta_start = delta;
6965
6966 /* sz denotes the nominal data-op size of the insn; we change it to
6967 2 if an 0x66 prefix is seen */
6968 Int sz = 4;
6969
6970 /* sorb holds the segment-override-prefix byte, if any. Zero if no
6971 prefix has been seen, else one of {0x26, 0x3E, 0x64, 0x65}
6972 indicating the prefix. */
6973 UChar sorb = 0;
6974
sewardjce70a5c2004-10-18 14:09:54 +00006975 /* If we don't set *size properly, this causes bbToIR_X86Instr to
6976 assert. */
6977 *size = 0;
6978
sewardjb5452082004-12-04 20:33:02 +00006979 addr = t0 = t1 = t2 = t3 = t4 = t5 = t6 = IRTemp_INVALID;
sewardjc9a65702004-07-07 16:32:57 +00006980
sewardjce70a5c2004-10-18 14:09:54 +00006981 DIP("\t0x%x: ", guest_eip_bbstart+delta);
sewardjc9a65702004-07-07 16:32:57 +00006982
sewardj750f4072004-07-26 22:39:11 +00006983 /* Spot the client-request magic sequence. */
6984 {
6985 UChar* code = (UChar*)(guest_code + delta);
6986 /* Spot this:
6987 C1C01D roll $29, %eax
6988 C1C003 roll $3, %eax
6989 C1C81B rorl $27, %eax
6990 C1C805 rorl $5, %eax
6991 C1C00D roll $13, %eax
6992 C1C013 roll $19, %eax
6993 */
6994 if (code[ 0] == 0xC1 && code[ 1] == 0xC0 && code[ 2] == 0x1D &&
6995 code[ 3] == 0xC1 && code[ 4] == 0xC0 && code[ 5] == 0x03 &&
6996 code[ 6] == 0xC1 && code[ 7] == 0xC8 && code[ 8] == 0x1B &&
6997 code[ 9] == 0xC1 && code[10] == 0xC8 && code[11] == 0x05 &&
6998 code[12] == 0xC1 && code[13] == 0xC0 && code[14] == 0x0D &&
6999 code[15] == 0xC1 && code[16] == 0xC0 && code[17] == 0x13
7000 ) {
sewardjce70a5c2004-10-18 14:09:54 +00007001 DIP("%%edx = client_request ( %%eax )\n");
sewardj750f4072004-07-26 22:39:11 +00007002 delta += 18;
sewardjce70a5c2004-10-18 14:09:54 +00007003 jmp_lit(Ijk_ClientReq, guest_eip_bbstart+delta);
7004 whatNext = Dis_StopHere;
7005 goto decode_success;
sewardj750f4072004-07-26 22:39:11 +00007006 }
7007 }
sewardjc9a65702004-07-07 16:32:57 +00007008
7009 /* Skip a LOCK prefix. */
7010 if (getIByte(delta) == 0xF0) {
njn285f22c2004-11-23 17:11:49 +00007011 if (0) vex_printf("vex x86->IR: ignoring LOCK prefix\n");
sewardjc9a65702004-07-07 16:32:57 +00007012 delta++;
7013 }
7014
7015 /* Detect operand-size overrides. */
7016 if (getIByte(delta) == 0x66) { sz = 2; delta++; };
7017
7018 /* segment override prefixes come after the operand-size override,
7019 it seems */
7020 switch (getIByte(delta)) {
7021 case 0x3E: /* %DS: */
7022 case 0x26: /* %ES: */
7023 case 0x64: /* %FS: */
7024 case 0x65: /* %GS: */
7025 sorb = getIByte(delta); delta++;
7026 break;
7027 case 0x2E: /* %CS: */
7028 /* 2E prefix on a conditional branch instruction is a
7029 branch-prediction hint, which can safely be ignored. */
7030 {
7031 UChar op1 = getIByte(delta+1);
7032 UChar op2 = getIByte(delta+2);
7033 if ((op1 >= 0x70 && op1 <= 0x7F)
7034 || (op1 == 0xE3)
7035 || (op1 == 0x0F && op2 >= 0x80 && op2 <= 0x8F)) {
sewardjce70a5c2004-10-18 14:09:54 +00007036 vex_printf("vex x86->IR: ignoring branch hint\n");
sewardjc9a65702004-07-07 16:32:57 +00007037 sorb = getIByte(delta); delta++;
7038 break;
7039 }
7040 }
7041 unimplemented("x86 segment override (SEG=CS) prefix");
7042 /*NOTREACHED*/
7043 break;
7044 case 0x36: /* %SS: */
7045 unimplemented("x86 segment override (SEG=SS) prefix");
7046 /*NOTREACHED*/
7047 break;
7048 default:
7049 break;
7050 }
7051
sewardjc9a43662004-11-30 18:51:59 +00007052 /* ---------------------------------------------------- */
7053 /* --- The SSE decoder. --- */
7054 /* ---------------------------------------------------- */
7055
sewardj4cb918d2004-12-03 19:43:31 +00007056 /* What did I do to deserve SSE ? Perhaps I was really bad in a
7057 previous life? */
7058
sewardjc9a43662004-11-30 18:51:59 +00007059 /* Note, this doesn't handle SSE2 or SSE3. */
7060
7061 insn = (UChar*)&guest_code[delta];
7062
sewardjc9a43662004-11-30 18:51:59 +00007063 /* 0F 58 = ADDPS -- add 32Fx4 from R/M to R */
sewardj636ad762004-12-07 11:16:04 +00007064 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x58) {
sewardj129b3d92004-12-05 15:42:05 +00007065 delta = dis_SSE_E_to_G_all( sorb, delta+2, "addps", Iop_Add32Fx4 );
sewardjc9a43662004-11-30 18:51:59 +00007066 goto decode_success;
7067 }
7068
sewardj1e6ad742004-12-02 16:16:11 +00007069 /* F3 0F 58 = ADDSS -- add 32F0x4 from R/M to R */
7070 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x58) {
7071 vassert(sz == 4);
sewardj129b3d92004-12-05 15:42:05 +00007072 delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "addss", Iop_Add32F0x4 );
sewardj1e6ad742004-12-02 16:16:11 +00007073 goto decode_success;
7074 }
7075
7076 /* 0F 55 = ANDNPS -- G = (not G) and E */
sewardj636ad762004-12-07 11:16:04 +00007077 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x55) {
sewardj129b3d92004-12-05 15:42:05 +00007078 delta = dis_SSE_E_to_G_all_invG( sorb, delta+2, "andnps", Iop_And128 );
sewardj1e6ad742004-12-02 16:16:11 +00007079 goto decode_success;
7080 }
7081
7082 /* 0F 54 = ANDPS -- G = G and E */
sewardj636ad762004-12-07 11:16:04 +00007083 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x54) {
sewardj129b3d92004-12-05 15:42:05 +00007084 delta = dis_SSE_E_to_G_all( sorb, delta+2, "andps", Iop_And128 );
sewardj1e6ad742004-12-02 16:16:11 +00007085 goto decode_success;
7086 }
7087
7088 /* 0F C2 = CMPPS -- 32Fx4 comparison from R/M to R */
sewardj636ad762004-12-07 11:16:04 +00007089 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xC2) {
sewardj1e6ad742004-12-02 16:16:11 +00007090 delta = dis_SSEcmp_E_to_G( sorb, delta+2, "cmpps", True, 4 );
7091 goto decode_success;
7092 }
7093
7094 /* F3 0F C2 = CMPSS -- 32F0x4 comparison from R/M to R */
7095 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0xC2) {
7096 vassert(sz == 4);
7097 delta = dis_SSEcmp_E_to_G( sorb, delta+3, "cmpss", False, 4 );
7098 goto decode_success;
7099 }
sewardjc9a43662004-11-30 18:51:59 +00007100
sewardjfd226452004-12-07 19:02:18 +00007101 /* 0F 2F = COMISS -- 32F0x4 comparison G,E, and set ZCP */
sewardjc1e7dfc2004-12-05 19:29:45 +00007102 /* 0F 2E = UCOMISS -- 32F0x4 comparison G,E, and set ZCP */
sewardjfd226452004-12-07 19:02:18 +00007103 if (sz == 4 && insn[0] == 0x0F && (insn[1] == 0x2F || insn[1] == 0x2E)) {
sewardj67e002d2004-12-02 18:16:33 +00007104 IRTemp argL = newTemp(Ity_F32);
7105 IRTemp argR = newTemp(Ity_F32);
sewardj67e002d2004-12-02 18:16:33 +00007106 modrm = getIByte(delta+2);
7107 if (epartIsReg(modrm)) {
7108 assign( argR, getXMMRegLane32F( eregOfRM(modrm), 0/*lowest lane*/ ) );
7109 delta += 2+1;
sewardjc1e7dfc2004-12-05 19:29:45 +00007110 DIP("[u]comiss %s,%s\n", nameXMMReg(eregOfRM(modrm)),
7111 nameXMMReg(gregOfRM(modrm)) );
sewardj67e002d2004-12-02 18:16:33 +00007112 } else {
7113 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
7114 assign( argR, loadLE(Ity_F32, mkexpr(addr)) );
7115 delta += 2+alen;
sewardjc1e7dfc2004-12-05 19:29:45 +00007116 DIP("[u]comiss %s,%s\n", dis_buf,
7117 nameXMMReg(gregOfRM(modrm)) );
sewardj67e002d2004-12-02 18:16:33 +00007118 }
7119 assign( argL, getXMMRegLane32F( gregOfRM(modrm), 0/*lowest lane*/ ) );
7120
7121 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
7122 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
7123 stmt( IRStmt_Put(
7124 OFFB_CC_DEP1,
7125 binop( Iop_And32,
7126 binop(Iop_CmpF64,
7127 unop(Iop_F32toF64,mkexpr(argL)),
7128 unop(Iop_F32toF64,mkexpr(argR))),
7129 mkU32(0x45)
7130 )));
7131
7132 goto decode_success;
7133 }
sewardjc9a43662004-11-30 18:51:59 +00007134
sewardj4cb918d2004-12-03 19:43:31 +00007135 /* 0F 2A = CVTPI2PS -- convert 2 x I32 in mem/mmx to 2 x F32 in low
7136 half xmm */
sewardjfd226452004-12-07 19:02:18 +00007137 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x2A) {
sewardj4cb918d2004-12-03 19:43:31 +00007138 IRTemp arg64 = newTemp(Ity_I64);
7139 IRTemp rmode = newTemp(Ity_I32);
7140 vassert(sz == 4);
7141
7142 modrm = getIByte(delta+2);
7143 do_MMX_preamble();
7144 if (epartIsReg(modrm)) {
7145 assign( arg64, getMMXReg(eregOfRM(modrm)) );
7146 delta += 2+1;
7147 DIP("cvtpi2ps %s,%s\n", nameMMXReg(eregOfRM(modrm)),
7148 nameXMMReg(gregOfRM(modrm)));
7149 } else {
7150 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
7151 assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
7152 delta += 2+alen;
7153 DIP("cvtpi2ps %s,%s\n", dis_buf,
7154 nameXMMReg(gregOfRM(modrm)) );
7155 }
7156
7157 assign( rmode, get_sse_roundingmode() );
7158
7159 putXMMRegLane32F(
sewardj3bca9062004-12-04 14:36:09 +00007160 gregOfRM(modrm), 0,
7161 binop(Iop_F64toF32,
sewardj4cb918d2004-12-03 19:43:31 +00007162 mkexpr(rmode),
sewardj3bca9062004-12-04 14:36:09 +00007163 unop(Iop_I32toF64,
7164 unop(Iop_64to32, mkexpr(arg64)) )) );
sewardj4cb918d2004-12-03 19:43:31 +00007165
7166 putXMMRegLane32F(
7167 gregOfRM(modrm), 1,
sewardj3bca9062004-12-04 14:36:09 +00007168 binop(Iop_F64toF32,
sewardj4cb918d2004-12-03 19:43:31 +00007169 mkexpr(rmode),
sewardj3bca9062004-12-04 14:36:09 +00007170 unop(Iop_I32toF64,
7171 unop(Iop_64HIto32, mkexpr(arg64)) )) );
sewardj4cb918d2004-12-03 19:43:31 +00007172
7173 goto decode_success;
7174 }
7175
7176 /* F3 0F 2A = CVTSI2SS -- convert I32 in mem/ireg to F32 in low
7177 quarter xmm */
7178 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x2A) {
7179 IRTemp arg32 = newTemp(Ity_I32);
7180 IRTemp rmode = newTemp(Ity_I32);
7181 vassert(sz == 4);
7182
7183 modrm = getIByte(delta+3);
sewardj4cb918d2004-12-03 19:43:31 +00007184 if (epartIsReg(modrm)) {
7185 assign( arg32, getIReg(4, eregOfRM(modrm)) );
7186 delta += 3+1;
7187 DIP("cvtsi2ss %s,%s\n", nameIReg(4, eregOfRM(modrm)),
7188 nameXMMReg(gregOfRM(modrm)));
7189 } else {
7190 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
7191 assign( arg32, loadLE(Ity_I32, mkexpr(addr)) );
7192 delta += 3+alen;
7193 DIP("cvtsi2ss %s,%s\n", dis_buf,
7194 nameXMMReg(gregOfRM(modrm)) );
7195 }
7196
7197 assign( rmode, get_sse_roundingmode() );
7198
7199 putXMMRegLane32F(
sewardj3bca9062004-12-04 14:36:09 +00007200 gregOfRM(modrm), 0,
7201 binop(Iop_F64toF32,
7202 mkexpr(rmode),
7203 unop(Iop_I32toF64, mkexpr(arg32)) ) );
sewardj4cb918d2004-12-03 19:43:31 +00007204
7205 goto decode_success;
7206 }
7207
7208 /* 0F 2D = CVTPS2PI -- convert 2 x F32 in mem/low half xmm to 2 x
7209 I32 in mmx, according to prevailing SSE rounding mode */
7210 /* 0F 2C = CVTTPS2PI -- convert 2 x F32 in mem/low half xmm to 2 x
7211 I32 in mmx, rounding towards zero */
sewardjfd226452004-12-07 19:02:18 +00007212 if (sz == 4 && insn[0] == 0x0F && (insn[1] == 0x2D || insn[1] == 0x2C)) {
sewardj4cb918d2004-12-03 19:43:31 +00007213 IRTemp dst64 = newTemp(Ity_I64);
7214 IRTemp rmode = newTemp(Ity_I32);
7215 IRTemp f32lo = newTemp(Ity_F32);
7216 IRTemp f32hi = newTemp(Ity_F32);
7217 Bool r2zero = insn[1] == 0x2C;
sewardj4cb918d2004-12-03 19:43:31 +00007218
7219 do_MMX_preamble();
7220 modrm = getIByte(delta+2);
7221
7222 if (epartIsReg(modrm)) {
7223 delta += 2+1;
7224 assign(f32lo, getXMMRegLane32F(eregOfRM(modrm), 0));
7225 assign(f32hi, getXMMRegLane32F(eregOfRM(modrm), 1));
7226 DIP("cvt%sps2pi %s,%s\n", r2zero ? "t" : "",
7227 nameXMMReg(eregOfRM(modrm)),
7228 nameMMXReg(gregOfRM(modrm)));
7229 } else {
7230 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
7231 assign(f32lo, loadLE(Ity_F32, mkexpr(addr)));
7232 assign(f32hi, loadLE(Ity_F32, binop( Iop_Add32,
7233 mkexpr(addr),
7234 mkU32(4) )));
7235 delta += 2+alen;
7236 DIP("cvt%sps2pi %s,%s\n", r2zero ? "t" : "",
7237 dis_buf,
7238 nameMMXReg(gregOfRM(modrm)));
7239 }
7240
7241 if (r2zero) {
7242 assign(rmode, mkU32((UInt)Irrm_ZERO) );
7243 } else {
7244 assign( rmode, get_sse_roundingmode() );
7245 }
7246
7247 assign(
7248 dst64,
7249 binop( Iop_32HLto64,
7250 binop( Iop_F64toI32,
7251 mkexpr(rmode),
7252 unop( Iop_F32toF64, mkexpr(f32hi) ) ),
7253 binop( Iop_F64toI32,
7254 mkexpr(rmode),
7255 unop( Iop_F32toF64, mkexpr(f32lo) ) )
7256 )
7257 );
7258
7259 putMMXReg(gregOfRM(modrm), mkexpr(dst64));
7260 goto decode_success;
7261 }
7262
7263 /* F3 0F 2D = CVTSS2SI -- convert F32 in mem/low quarter xmm to
7264 I32 in ireg, according to prevailing SSE rounding mode */
7265 /* F3 0F 2C = CVTTSS2SI -- convert F32 in mem/low quarter xmm to
7266 I32 in ireg, according to prevailing SSE rounding mode */
7267 if (insn[0] == 0xF3 && insn[1] == 0x0F
7268 && (insn[2] == 0x2D || insn[2] == 0x2C)) {
7269 IRTemp rmode = newTemp(Ity_I32);
7270 IRTemp f32lo = newTemp(Ity_F32);
7271 Bool r2zero = insn[2] == 0x2C;
7272 vassert(sz == 4);
7273
sewardj4cb918d2004-12-03 19:43:31 +00007274 modrm = getIByte(delta+3);
sewardj4cb918d2004-12-03 19:43:31 +00007275 if (epartIsReg(modrm)) {
7276 delta += 3+1;
7277 assign(f32lo, getXMMRegLane32F(eregOfRM(modrm), 0));
7278 DIP("cvt%sss2si %s,%s\n", r2zero ? "t" : "",
7279 nameXMMReg(eregOfRM(modrm)),
7280 nameIReg(4, gregOfRM(modrm)));
7281 } else {
7282 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
7283 assign(f32lo, loadLE(Ity_F32, mkexpr(addr)));
7284 delta += 3+alen;
7285 DIP("cvt%sss2si %s,%s\n", r2zero ? "t" : "",
7286 dis_buf,
7287 nameIReg(4, gregOfRM(modrm)));
7288 }
7289
7290 if (r2zero) {
sewardj7df596b2004-12-06 14:29:12 +00007291 assign( rmode, mkU32((UInt)Irrm_ZERO) );
sewardj4cb918d2004-12-03 19:43:31 +00007292 } else {
7293 assign( rmode, get_sse_roundingmode() );
7294 }
7295
7296 putIReg(4, gregOfRM(modrm),
7297 binop( Iop_F64toI32,
7298 mkexpr(rmode),
7299 unop( Iop_F32toF64, mkexpr(f32lo) ) )
7300 );
7301
7302 goto decode_success;
7303 }
7304
sewardj176a59c2004-12-03 20:08:31 +00007305 /* 0F 5E = DIVPS -- div 32Fx4 from R/M to R */
sewardjfd226452004-12-07 19:02:18 +00007306 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5E) {
sewardj129b3d92004-12-05 15:42:05 +00007307 delta = dis_SSE_E_to_G_all( sorb, delta+2, "divps", Iop_Div32Fx4 );
sewardj176a59c2004-12-03 20:08:31 +00007308 goto decode_success;
7309 }
7310
7311 /* F3 0F 5E = DIVSS -- div 32F0x4 from R/M to R */
7312 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5E) {
7313 vassert(sz == 4);
sewardj129b3d92004-12-05 15:42:05 +00007314 delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "divss", Iop_Div32F0x4 );
sewardj176a59c2004-12-03 20:08:31 +00007315 goto decode_success;
7316 }
7317
sewardj7df596b2004-12-06 14:29:12 +00007318 /* 0F AE /2 = LDMXCSR m32 -- load %mxcsr */
7319 if (insn[0] == 0x0F && insn[1] == 0xAE
7320 && !epartIsReg(insn[2]) && gregOfRM(insn[2]) == 2) {
7321
7322 IRTemp t64 = newTemp(Ity_I64);
7323 IRTemp ew = newTemp(Ity_I32);
7324
7325 modrm = getIByte(delta+2);
7326 vassert(!epartIsReg(modrm));
7327 vassert(sz == 4);
7328
7329 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
7330 delta += 2+alen;
7331 DIP("ldmxcsr %s", dis_buf);
7332
7333 /* The only thing we observe in %mxcsr is the rounding mode.
7334 Therefore, pass the 32-bit value (SSE native-format control
7335 word) to a clean helper, getting back a 64-bit value, the
7336 lower half of which is the SSEROUND value to store, and the
7337 upper half of which is the emulation-warning token which may
7338 be generated.
7339 */
7340 /* ULong x86h_check_ldmxcsr ( UInt ); */
7341 assign( t64, mkIRExprCCall(
7342 Ity_I64, 0/*regparms*/,
sewardj3bd6f3e2004-12-13 10:48:19 +00007343 "x86g_check_ldmxcsr",
7344 &x86g_check_ldmxcsr,
sewardj7df596b2004-12-06 14:29:12 +00007345 mkIRExprVec_1( loadLE(Ity_I32, mkexpr(addr)) )
7346 )
7347 );
7348
sewardj636ad762004-12-07 11:16:04 +00007349 put_sse_roundingmode( unop(Iop_64to32, mkexpr(t64)) );
sewardj7df596b2004-12-06 14:29:12 +00007350 assign( ew, unop(Iop_64HIto32, mkexpr(t64) ) );
7351 put_emwarn( mkexpr(ew) );
7352 /* Finally, if an emulation warning was reported, side-exit to
7353 the next insn, reporting the warning, so that Valgrind's
7354 dispatcher sees the warning. */
7355 stmt(
7356 IRStmt_Exit(
7357 binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
7358 Ijk_EmWarn,
7359 IRConst_U32( ((Addr32)guest_eip_bbstart)+delta)
7360 )
7361 );
7362 goto decode_success;
7363 }
7364
sewardj176a59c2004-12-03 20:08:31 +00007365 /* 0F 5F = MAXPS -- max 32Fx4 from R/M to R */
sewardjc2feffc2004-12-08 12:31:22 +00007366 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5F) {
sewardj129b3d92004-12-05 15:42:05 +00007367 delta = dis_SSE_E_to_G_all( sorb, delta+2, "maxps", Iop_Max32Fx4 );
sewardj176a59c2004-12-03 20:08:31 +00007368 goto decode_success;
7369 }
7370
7371 /* F3 0F 5F = MAXSS -- max 32F0x4 from R/M to R */
7372 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5F) {
7373 vassert(sz == 4);
sewardj129b3d92004-12-05 15:42:05 +00007374 delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "maxss", Iop_Max32F0x4 );
sewardj176a59c2004-12-03 20:08:31 +00007375 goto decode_success;
7376 }
7377
7378 /* 0F 5D = MINPS -- min 32Fx4 from R/M to R */
sewardjc2feffc2004-12-08 12:31:22 +00007379 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5D) {
sewardj129b3d92004-12-05 15:42:05 +00007380 delta = dis_SSE_E_to_G_all( sorb, delta+2, "minps", Iop_Min32Fx4 );
sewardj176a59c2004-12-03 20:08:31 +00007381 goto decode_success;
7382 }
7383
7384 /* F3 0F 5D = MINSS -- min 32F0x4 from R/M to R */
7385 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5D) {
7386 vassert(sz == 4);
sewardj129b3d92004-12-05 15:42:05 +00007387 delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "minss", Iop_Min32F0x4 );
sewardj176a59c2004-12-03 20:08:31 +00007388 goto decode_success;
7389 }
sewardj4cb918d2004-12-03 19:43:31 +00007390
sewardj9636b442004-12-04 01:38:37 +00007391 /* 0F 28 = MOVAPS -- move from E (mem or xmm) to G (xmm). */
sewardjc2feffc2004-12-08 12:31:22 +00007392 /* 0F 10 = MOVUPS -- move from E (mem or xmm) to G (xmm). */
7393 if (sz == 4 && insn[0] == 0x0F && (insn[1] == 0x28 || insn[1] == 0x10)) {
sewardj9636b442004-12-04 01:38:37 +00007394 modrm = getIByte(delta+2);
7395
7396 if (epartIsReg(modrm)) {
7397 putXMMReg( gregOfRM(modrm),
7398 getXMMReg( eregOfRM(modrm) ));
7399 DIP("mov[ua]ps %s,%s\n", nameXMMReg(eregOfRM(modrm)),
7400 nameXMMReg(gregOfRM(modrm)));
7401 delta += 2+1;
7402 } else {
7403 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
7404 putXMMReg( gregOfRM(modrm),
7405 loadLE(Ity_V128, mkexpr(addr)) );
7406 DIP("mov[ua]ps %s,%s\n", dis_buf,
7407 nameXMMReg(gregOfRM(modrm)));
7408 delta += 2+alen;
7409 }
7410 goto decode_success;
7411 }
7412
sewardj09f41552004-12-15 12:35:00 +00007413 /* 0F 29 = MOVAPS -- move from G (xmm) to E (mem or xmm). */
7414 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x29) {
7415 modrm = getIByte(delta+2);
7416
7417 if (epartIsReg(modrm)) {
7418 /* fall through; awaiting test case */
7419 } else {
7420 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
7421 storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) );
7422 DIP("movaps %s,%s\n", nameXMMReg(gregOfRM(modrm)),
7423 dis_buf );
7424 delta += 2+alen;
7425 goto decode_success;
7426 }
7427 }
7428
sewardj0bd7ce62004-12-05 02:47:40 +00007429 /* 0F 16 = MOVHPS -- move from mem to high half of XMM. */
7430 /* 0F 16 = MOVLHPS -- move from lo half to hi half of XMM. */
sewardjc2feffc2004-12-08 12:31:22 +00007431 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x16) {
sewardj0bd7ce62004-12-05 02:47:40 +00007432 modrm = getIByte(delta+2);
7433 if (epartIsReg(modrm)) {
7434 delta += 2+1;
7435 putXMMRegLane64( gregOfRM(modrm), 1/*upper lane*/,
7436 getXMMRegLane64( eregOfRM(modrm), 0 ) );
7437 DIP("movhps %s,%s\n", nameXMMReg(eregOfRM(modrm)),
7438 nameXMMReg(gregOfRM(modrm)));
7439 } else {
7440 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
7441 delta += 2+alen;
7442 putXMMRegLane64( gregOfRM(modrm), 1/*upper lane*/,
7443 loadLE(Ity_I64, mkexpr(addr)) );
7444 DIP("movhps %s,%s\n", dis_buf,
sewardjc2feffc2004-12-08 12:31:22 +00007445 nameXMMReg( gregOfRM(modrm) ));
sewardj0bd7ce62004-12-05 02:47:40 +00007446 }
7447 goto decode_success;
7448 }
7449
7450 /* 0F 17 = MOVHPS -- move from high half of XMM to mem. */
sewardjc2feffc2004-12-08 12:31:22 +00007451 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x17) {
sewardj0bd7ce62004-12-05 02:47:40 +00007452 if (!epartIsReg(insn[2])) {
sewardj0bd7ce62004-12-05 02:47:40 +00007453 delta += 2;
7454 addr = disAMode ( &alen, sorb, delta, dis_buf );
7455 delta += alen;
7456 storeLE( mkexpr(addr),
7457 getXMMRegLane64( gregOfRM(insn[2]),
7458 1/*upper lane*/ ) );
7459 DIP("movhps %s,%s\n", nameXMMReg( gregOfRM(insn[2]) ),
7460 dis_buf);
7461 goto decode_success;
7462 }
7463 /* else fall through */
7464 }
7465
7466 /* 0F 12 = MOVLPS -- move from mem to low half of XMM. */
7467 /* OF 12 = MOVHLPS -- from from hi half to lo half of XMM. */
sewardjc2feffc2004-12-08 12:31:22 +00007468 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x12) {
sewardj0bd7ce62004-12-05 02:47:40 +00007469 modrm = getIByte(delta+2);
7470 if (epartIsReg(modrm)) {
7471 delta += 2+1;
7472 putXMMRegLane64( gregOfRM(modrm),
7473 0/*lower lane*/,
7474 getXMMRegLane64( eregOfRM(modrm), 1 ));
7475 DIP("movhlps %s, %s\n", nameXMMReg(eregOfRM(modrm)),
7476 nameXMMReg(gregOfRM(modrm)));
7477 } else {
7478 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
7479 delta += 2+alen;
7480 putXMMRegLane64( gregOfRM(modrm), 0/*lower lane*/,
7481 loadLE(Ity_I64, mkexpr(addr)) );
7482 DIP("movlps %s, %s\n",
7483 dis_buf, nameXMMReg( gregOfRM(modrm) ));
7484 }
7485 goto decode_success;
7486 }
7487
7488 /* 0F 13 = MOVLPS -- move from low half of XMM to mem. */
sewardjc2feffc2004-12-08 12:31:22 +00007489 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x13) {
sewardj0bd7ce62004-12-05 02:47:40 +00007490 if (!epartIsReg(insn[2])) {
sewardj0bd7ce62004-12-05 02:47:40 +00007491 delta += 2;
7492 addr = disAMode ( &alen, sorb, delta, dis_buf );
7493 delta += alen;
7494 storeLE( mkexpr(addr),
7495 getXMMRegLane64( gregOfRM(insn[2]),
7496 0/*lower lane*/ ) );
7497 DIP("movlps %s, %s\n", nameXMMReg( gregOfRM(insn[2]) ),
7498 dis_buf);
7499 goto decode_success;
7500 }
7501 /* else fall through */
7502 }
7503
sewardj9636b442004-12-04 01:38:37 +00007504 /* 0F 50 = MOVMSKPS - move 4 sign bits from 4 x F32 in xmm(E)
7505 to 4 lowest bits of ireg(G) */
7506 if (insn[0] == 0x0F && insn[1] == 0x50) {
sewardj9636b442004-12-04 01:38:37 +00007507 modrm = getIByte(delta+2);
sewardjc2feffc2004-12-08 12:31:22 +00007508 if (sz == 4 && epartIsReg(modrm)) {
7509 Int src;
7510 t0 = newTemp(Ity_I32);
7511 t1 = newTemp(Ity_I32);
7512 t2 = newTemp(Ity_I32);
7513 t3 = newTemp(Ity_I32);
sewardj129b3d92004-12-05 15:42:05 +00007514 delta += 2+1;
7515 src = eregOfRM(modrm);
7516 assign( t0, binop( Iop_And32,
7517 binop(Iop_Shr32, getXMMRegLane32(src,0), mkU8(31)),
7518 mkU32(1) ));
7519 assign( t1, binop( Iop_And32,
7520 binop(Iop_Shr32, getXMMRegLane32(src,1), mkU8(30)),
7521 mkU32(2) ));
7522 assign( t2, binop( Iop_And32,
7523 binop(Iop_Shr32, getXMMRegLane32(src,2), mkU8(29)),
7524 mkU32(4) ));
7525 assign( t3, binop( Iop_And32,
7526 binop(Iop_Shr32, getXMMRegLane32(src,3), mkU8(28)),
7527 mkU32(8) ));
7528 putIReg(4, gregOfRM(modrm),
7529 binop(Iop_Or32,
7530 binop(Iop_Or32, mkexpr(t0), mkexpr(t1)),
7531 binop(Iop_Or32, mkexpr(t2), mkexpr(t3))
7532 )
7533 );
7534 DIP("movmskps %s,%s\n", nameXMMReg(src),
7535 nameIReg(4, gregOfRM(modrm)));
7536 goto decode_success;
7537 }
7538 /* else fall through */
sewardj9636b442004-12-04 01:38:37 +00007539 }
7540
7541 /* 0F 2B = MOVNTPS -- for us, just a plain SSE store. */
7542 if (insn[0] == 0x0F && insn[1] == 0x2B) {
7543 modrm = getIByte(delta+2);
7544 if (!epartIsReg(modrm)) {
7545 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
7546 storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) );
7547 DIP("movntps %s,%s\n", dis_buf,
7548 nameXMMReg(gregOfRM(modrm)));
7549 delta += 2+alen;
7550 goto decode_success;
7551 }
7552 /* else fall through */
7553 }
7554
sewardjc2feffc2004-12-08 12:31:22 +00007555 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
sewardj9636b442004-12-04 01:38:37 +00007556 /* 0F E7 = MOVNTQ -- for us, just a plain MMX store. Note, the
7557 Intel manual does not say anything about the usual business of
7558 the FP reg tags getting trashed whenever an MMX insn happens.
7559 So we just leave them alone.
7560 */
7561 if (insn[0] == 0x0F && insn[1] == 0xE7) {
7562 modrm = getIByte(delta+2);
sewardjc2feffc2004-12-08 12:31:22 +00007563 if (sz == 4 && !epartIsReg(modrm)) {
sewardj519d66f2004-12-15 11:57:58 +00007564 /* do_MMX_preamble(); Intel docs don't specify this */
sewardj9636b442004-12-04 01:38:37 +00007565 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
7566 storeLE( mkexpr(addr), getMMXReg(gregOfRM(modrm)) );
7567 DIP("movntq %s,%s\n", dis_buf,
7568 nameMMXReg(gregOfRM(modrm)));
7569 delta += 2+alen;
7570 goto decode_success;
7571 }
7572 /* else fall through */
7573 }
7574
7575 /* F3 0F 10 = MOVSS -- move 32 bits from E (mem or lo 1/4 xmm) to G
7576 (lo 1/4 xmm). If E is mem, upper 3/4 of G is zeroed out. */
7577 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x10) {
7578 vassert(sz == 4);
7579 modrm = getIByte(delta+3);
7580 if (epartIsReg(modrm)) {
7581 putXMMRegLane32( gregOfRM(modrm), 0,
7582 getXMMRegLane32( eregOfRM(modrm), 0 ));
7583 DIP("movss %s,%s\n", nameXMMReg(eregOfRM(modrm)),
7584 nameXMMReg(gregOfRM(modrm)));
7585 delta += 3+1;
7586 } else {
7587 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
7588 putXMMReg( gregOfRM(modrm), mkV128(0) );
7589 putXMMRegLane32( gregOfRM(modrm), 0,
7590 loadLE(Ity_I32, mkexpr(addr)) );
7591 DIP("movss %s,%s\n", dis_buf,
7592 nameXMMReg(gregOfRM(modrm)));
7593 delta += 3+alen;
7594 }
7595 goto decode_success;
7596 }
7597
7598 /* F3 0F 11 = MOVSS -- move 32 bits from G (lo 1/4 xmm) to E (mem
7599 or lo 1/4 xmm). */
7600 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x11) {
7601 vassert(sz == 4);
7602 modrm = getIByte(delta+3);
7603 if (epartIsReg(modrm)) {
7604 /* fall through, we don't yet have a test case */
7605 } else {
7606 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
7607 storeLE( mkexpr(addr),
sewardj519d66f2004-12-15 11:57:58 +00007608 getXMMRegLane32(gregOfRM(modrm), 0) );
7609 DIP("movss %s,%s\n", nameXMMReg(gregOfRM(modrm)),
sewardj9636b442004-12-04 01:38:37 +00007610 dis_buf);
7611 delta += 3+alen;
7612 goto decode_success;
7613 }
7614 }
7615
7616 /* 0F 59 = MULPS -- mul 32Fx4 from R/M to R */
sewardj008754b2004-12-08 14:37:10 +00007617 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x59) {
sewardj129b3d92004-12-05 15:42:05 +00007618 delta = dis_SSE_E_to_G_all( sorb, delta+2, "mulps", Iop_Mul32Fx4 );
sewardj9636b442004-12-04 01:38:37 +00007619 goto decode_success;
7620 }
7621
7622 /* F3 0F 59 = MULSS -- mul 32F0x4 from R/M to R */
7623 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x59) {
7624 vassert(sz == 4);
sewardj129b3d92004-12-05 15:42:05 +00007625 delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "mulss", Iop_Mul32F0x4 );
sewardj9636b442004-12-04 01:38:37 +00007626 goto decode_success;
7627 }
7628
7629 /* 0F 56 = ORPS -- G = G and E */
sewardj008754b2004-12-08 14:37:10 +00007630 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x56) {
sewardj129b3d92004-12-05 15:42:05 +00007631 delta = dis_SSE_E_to_G_all( sorb, delta+2, "orps", Iop_Or128 );
sewardj9636b442004-12-04 01:38:37 +00007632 goto decode_success;
7633 }
7634
sewardj3bca9062004-12-04 14:36:09 +00007635 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
7636 /* 0F E0 = PAVGB -- 8x8 unsigned Packed Average, with rounding */
sewardj164f9272004-12-09 00:39:32 +00007637 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xE0) {
sewardjb5452082004-12-04 20:33:02 +00007638 do_MMX_preamble();
7639 delta = dis_MMXop_regmem_to_reg (
7640 sorb, delta+2, insn[1], "pavgb", False );
7641 goto decode_success;
sewardj3bca9062004-12-04 14:36:09 +00007642 }
7643
sewardjb5452082004-12-04 20:33:02 +00007644 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
7645 /* 0F E3 = PAVGW -- 16x4 unsigned Packed Average, with rounding */
sewardj164f9272004-12-09 00:39:32 +00007646 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xE3) {
sewardjb5452082004-12-04 20:33:02 +00007647 do_MMX_preamble();
7648 delta = dis_MMXop_regmem_to_reg (
7649 sorb, delta+2, insn[1], "pavgw", False );
7650 goto decode_success;
7651 }
7652
7653 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
7654 /* 0F C5 = PEXTRW -- extract 16-bit field from mmx(E) and put
7655 zero-extend of it in ireg(G). */
7656 if (insn[0] == 0x0F && insn[1] == 0xC5) {
7657 modrm = insn[2];
7658 if (sz == 4 && epartIsReg(modrm)) {
sewardjb9fa69b2004-12-09 23:25:14 +00007659 IRTemp sV = newTemp(Ity_I64);
7660 t5 = newTemp(Ity_I16);
sewardjb5452082004-12-04 20:33:02 +00007661 do_MMX_preamble();
sewardjb9fa69b2004-12-09 23:25:14 +00007662 assign(sV, getMMXReg(eregOfRM(modrm)));
7663 breakup64to16s( sV, &t3, &t2, &t1, &t0 );
sewardjb5452082004-12-04 20:33:02 +00007664 switch (insn[3] & 3) {
sewardjb9fa69b2004-12-09 23:25:14 +00007665 case 0: assign(t5, mkexpr(t0)); break;
7666 case 1: assign(t5, mkexpr(t1)); break;
7667 case 2: assign(t5, mkexpr(t2)); break;
7668 case 3: assign(t5, mkexpr(t3)); break;
7669 default: vassert(0);
sewardjb5452082004-12-04 20:33:02 +00007670 }
sewardjb9fa69b2004-12-09 23:25:14 +00007671 putIReg(4, gregOfRM(modrm), unop(Iop_16Uto32, mkexpr(t5)));
sewardjb5452082004-12-04 20:33:02 +00007672 DIP("pextrw $%d,%s,%s\n",
7673 (Int)insn[3], nameMMXReg(eregOfRM(modrm)),
7674 nameIReg(4,gregOfRM(modrm)));
7675 delta += 4;
7676 goto decode_success;
7677 }
7678 /* else fall through */
7679 }
7680
7681 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
7682 /* 0F C4 = PINSRW -- get 16 bits from E(mem or low half ireg) and
7683 put it into the specified lane of mmx(G). */
sewardje5854d62004-12-09 03:44:34 +00007684 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xC4) {
7685 /* Use t0 .. t3 to hold the 4 original 16-bit lanes of the
7686 mmx reg. t4 is the new lane value. t5 is the original
7687 mmx value. t6 is the new mmx value. */
7688 Int lane;
sewardje5854d62004-12-09 03:44:34 +00007689 t4 = newTemp(Ity_I16);
7690 t5 = newTemp(Ity_I64);
7691 t6 = newTemp(Ity_I64);
7692 modrm = insn[2];
7693 do_MMX_preamble();
sewardjb5452082004-12-04 20:33:02 +00007694
sewardje5854d62004-12-09 03:44:34 +00007695 assign(t5, getMMXReg(gregOfRM(modrm)));
sewardjb9fa69b2004-12-09 23:25:14 +00007696 breakup64to16s( t5, &t3, &t2, &t1, &t0 );
sewardjb5452082004-12-04 20:33:02 +00007697
sewardje5854d62004-12-09 03:44:34 +00007698 if (epartIsReg(modrm)) {
7699 assign(t4, getIReg(2, eregOfRM(modrm)));
7700 lane = insn[3];
7701 delta += 2+2;
7702 DIP("pinsrw $%d,%s,%s\n", (Int)lane,
7703 nameIReg(2,eregOfRM(modrm)),
7704 nameMMXReg(gregOfRM(modrm)));
7705 } else {
7706 /* awaiting test case */
7707 goto decode_failure;
sewardjb5452082004-12-04 20:33:02 +00007708 }
sewardje5854d62004-12-09 03:44:34 +00007709
7710 switch (lane & 3) {
sewardjb9fa69b2004-12-09 23:25:14 +00007711 case 0: assign(t6, mk64from16s(t3,t2,t1,t4)); break;
7712 case 1: assign(t6, mk64from16s(t3,t2,t4,t0)); break;
7713 case 2: assign(t6, mk64from16s(t3,t4,t1,t0)); break;
7714 case 3: assign(t6, mk64from16s(t4,t2,t1,t0)); break;
7715 default: vassert(0);
sewardje5854d62004-12-09 03:44:34 +00007716 }
7717 putMMXReg(gregOfRM(modrm), mkexpr(t6));
7718 goto decode_success;
sewardjb5452082004-12-04 20:33:02 +00007719 }
7720
7721 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
7722 /* 0F EE = PMAXSW -- 16x4 signed max */
sewardje5854d62004-12-09 03:44:34 +00007723 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xEE) {
sewardjb5452082004-12-04 20:33:02 +00007724 do_MMX_preamble();
7725 delta = dis_MMXop_regmem_to_reg (
7726 sorb, delta+2, insn[1], "pmaxsw", False );
7727 goto decode_success;
7728 }
7729
7730 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
7731 /* 0F DE = PMAXUB -- 8x8 unsigned max */
sewardje5854d62004-12-09 03:44:34 +00007732 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xDE) {
sewardjb5452082004-12-04 20:33:02 +00007733 do_MMX_preamble();
7734 delta = dis_MMXop_regmem_to_reg (
7735 sorb, delta+2, insn[1], "pmaxub", False );
7736 goto decode_success;
7737 }
7738
7739 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
7740 /* 0F EA = PMINSW -- 16x4 signed min */
sewardje5854d62004-12-09 03:44:34 +00007741 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xEA) {
sewardjb5452082004-12-04 20:33:02 +00007742 do_MMX_preamble();
7743 delta = dis_MMXop_regmem_to_reg (
7744 sorb, delta+2, insn[1], "pminsw", False );
7745 goto decode_success;
7746 }
7747
7748 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
7749 /* 0F DA = PMINUB -- 8x8 unsigned min */
sewardje5854d62004-12-09 03:44:34 +00007750 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xDA) {
sewardjb5452082004-12-04 20:33:02 +00007751 do_MMX_preamble();
7752 delta = dis_MMXop_regmem_to_reg (
7753 sorb, delta+2, insn[1], "pminub", False );
7754 goto decode_success;
7755 }
7756
7757 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
7758 /* 0F D7 = PMOVMSKB -- extract sign bits from each of 8 lanes in
7759 mmx(G), turn them into a byte, and put zero-extend of it in
7760 ireg(G). */
sewardje5854d62004-12-09 03:44:34 +00007761 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xD7) {
sewardjb5452082004-12-04 20:33:02 +00007762 modrm = insn[2];
sewardje5854d62004-12-09 03:44:34 +00007763 if (epartIsReg(modrm)) {
sewardjb5452082004-12-04 20:33:02 +00007764 do_MMX_preamble();
7765 t0 = newTemp(Ity_I64);
7766 t1 = newTemp(Ity_I32);
7767 assign(t0, getMMXReg(eregOfRM(modrm)));
7768 assign(t1, mkIRExprCCall(
7769 Ity_I32, 0/*regparms*/,
7770 "x86g_calculate_pmovmskb",
7771 &x86g_calculate_pmovmskb,
7772 mkIRExprVec_1(mkexpr(t0))));
7773 putIReg(4, gregOfRM(modrm), mkexpr(t1));
7774 DIP("pmovmskb %s,%s\n", nameMMXReg(eregOfRM(modrm)),
7775 nameIReg(4,gregOfRM(modrm)));
7776 delta += 3;
7777 goto decode_success;
7778 }
7779 /* else fall through */
7780 }
7781
sewardj0bd7ce62004-12-05 02:47:40 +00007782 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
7783 /* 0F E4 = PMULUH -- 16x4 hi-half of unsigned widening multiply */
sewardje5854d62004-12-09 03:44:34 +00007784 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xE4) {
sewardj0bd7ce62004-12-05 02:47:40 +00007785 do_MMX_preamble();
7786 delta = dis_MMXop_regmem_to_reg (
7787 sorb, delta+2, insn[1], "pmuluh", False );
7788 goto decode_success;
7789 }
7790
sewardj7df596b2004-12-06 14:29:12 +00007791 /* 0F 18 /0 = PREFETCHNTA -- prefetch into caches, */
7792 /* 0F 18 /1 = PREFETCH0 -- with various different hints */
7793 /* 0F 18 /2 = PREFETCH1 */
7794 /* 0F 18 /3 = PREFETCH2 */
7795 if (insn[0] == 0x0F && insn[1] == 0x18
7796 && !epartIsReg(insn[2])
7797 && gregOfRM(insn[2]) >= 0 && gregOfRM(insn[2]) <= 3) {
7798 HChar* hintstr = "??";
7799
7800 modrm = getIByte(delta+2);
7801 vassert(!epartIsReg(modrm));
7802
7803 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
7804 delta += 2+alen;
7805
7806 switch (gregOfRM(modrm)) {
7807 case 0: hintstr = "nta"; break;
7808 case 1: hintstr = "t0"; break;
7809 case 2: hintstr = "t1"; break;
7810 case 3: hintstr = "t2"; break;
7811 default: vassert(0);
7812 }
7813
7814 DIP("prefetch%s %s\n", hintstr, dis_buf);
7815 goto decode_success;
7816 }
7817
sewardj0bd7ce62004-12-05 02:47:40 +00007818 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
7819 /* 0F F6 = PSADBW -- sum of 8Ux8 absolute differences */
7820 if (insn[0] == 0x0F && insn[1] == 0xF6) {
7821 vassert(sz == 4);
7822 do_MMX_preamble();
7823 delta = dis_MMXop_regmem_to_reg (
7824 sorb, delta+2, insn[1], "psadbw", False );
7825 goto decode_success;
7826 }
7827
7828 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
7829 /* 0F 70 = PSHUFW -- rearrange 4x16 from E(mmx or mem) to G(mmx) */
sewardjb9fa69b2004-12-09 23:25:14 +00007830 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x70) {
sewardj0bd7ce62004-12-05 02:47:40 +00007831 Int order;
sewardjb9fa69b2004-12-09 23:25:14 +00007832 IRTemp sV, dV, s3, s2, s1, s0;
7833 s3 = s2 = s1 = s0 = IRTemp_INVALID;
7834 sV = newTemp(Ity_I64);
7835 dV = newTemp(Ity_I64);
sewardj0bd7ce62004-12-05 02:47:40 +00007836 do_MMX_preamble();
7837 modrm = insn[2];
7838 if (epartIsReg(modrm)) {
sewardjb9fa69b2004-12-09 23:25:14 +00007839 assign( sV, getMMXReg(eregOfRM(modrm)) );
sewardj0bd7ce62004-12-05 02:47:40 +00007840 order = (Int)insn[3];
7841 delta += 2+2;
7842 DIP("pshufw $%d,%s,%s\n", order,
7843 nameMMXReg(eregOfRM(modrm)),
7844 nameMMXReg(gregOfRM(modrm)));
7845 } else {
7846 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
sewardjb9fa69b2004-12-09 23:25:14 +00007847 assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
sewardj0bd7ce62004-12-05 02:47:40 +00007848 order = (Int)insn[2+alen];
7849 delta += 3+alen;
7850 DIP("pshufw $%d,%s,%s\n", order,
7851 dis_buf,
7852 nameMMXReg(gregOfRM(modrm)));
7853 }
sewardjb9fa69b2004-12-09 23:25:14 +00007854 breakup64to16s( sV, &s3, &s2, &s1, &s0 );
sewardj0bd7ce62004-12-05 02:47:40 +00007855
sewardjb9fa69b2004-12-09 23:25:14 +00007856# define SEL(n) \
7857 ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
7858 assign(dV,
7859 mk64from16s( SEL((order>>6)&3), SEL((order>>4)&3),
7860 SEL((order>>2)&3), SEL((order>>0)&3) )
sewardj0bd7ce62004-12-05 02:47:40 +00007861 );
sewardjb9fa69b2004-12-09 23:25:14 +00007862 putMMXReg(gregOfRM(modrm), mkexpr(dV));
sewardj0bd7ce62004-12-05 02:47:40 +00007863# undef SEL
sewardj0bd7ce62004-12-05 02:47:40 +00007864 goto decode_success;
7865 }
7866
7867 /* 0F 53 = RCPPS -- approx reciprocal 32Fx4 from R/M to R */
7868 if (insn[0] == 0x0F && insn[1] == 0x53) {
7869 vassert(sz == 4);
sewardj129b3d92004-12-05 15:42:05 +00007870 delta = dis_SSE_E_to_G_unary_all( sorb, delta+2,
7871 "rcpps", Iop_Recip32Fx4 );
sewardj0bd7ce62004-12-05 02:47:40 +00007872 goto decode_success;
7873 }
7874
7875 /* F3 0F 53 = RCPSS -- approx reciprocal 32F0x4 from R/M to R */
7876 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x53) {
7877 vassert(sz == 4);
sewardj129b3d92004-12-05 15:42:05 +00007878 delta = dis_SSE_E_to_G_unary_lo32( sorb, delta+3,
7879 "rcpss", Iop_Recip32F0x4 );
sewardj0bd7ce62004-12-05 02:47:40 +00007880 goto decode_success;
7881 }
sewardjb5452082004-12-04 20:33:02 +00007882
sewardjc1e7dfc2004-12-05 19:29:45 +00007883 /* 0F 52 = RSQRTPS -- approx reciprocal sqrt 32Fx4 from R/M to R */
7884 if (insn[0] == 0x0F && insn[1] == 0x52) {
7885 vassert(sz == 4);
7886 delta = dis_SSE_E_to_G_unary_all( sorb, delta+2,
7887 "rsqrtps", Iop_RSqrt32Fx4 );
7888 goto decode_success;
7889 }
7890
7891 /* F3 0F 52 = RSQRTSS -- approx reciprocal sqrt 32F0x4 from R/M to R */
7892 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x52) {
7893 vassert(sz == 4);
7894 delta = dis_SSE_E_to_G_unary_lo32( sorb, delta+3,
7895 "rsqrtss", Iop_RSqrt32F0x4 );
7896 goto decode_success;
7897 }
7898
7899 /* 0F AE /7 = SFENCE -- flush pending operations to memory */
7900 if (insn[0] == 0x0F && insn[1] == 0xAE
sewardjc2feffc2004-12-08 12:31:22 +00007901 && epartIsReg(insn[2]) && gregOfRM(insn[2]) == 7) {
sewardjc1e7dfc2004-12-05 19:29:45 +00007902 vassert(sz == 4);
7903 delta += 3;
7904 /* nothing to do */
7905 DIP("sfence\n");
7906 goto decode_success;
7907 }
7908
7909 /* 0F C6 /r ib = SHUFPS -- shuffle packed F32s */
sewardj008754b2004-12-08 14:37:10 +00007910 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xC6) {
sewardjc1e7dfc2004-12-05 19:29:45 +00007911 Int select;
7912 IRTemp sV, dV;
7913 IRTemp s3, s2, s1, s0, d3, d2, d1, d0;
7914 sV = newTemp(Ity_V128);
7915 dV = newTemp(Ity_V128);
7916 s3 = s2 = s1 = s0 = d3 = d2 = d1 = d0 = IRTemp_INVALID;
sewardjc1e7dfc2004-12-05 19:29:45 +00007917 modrm = insn[2];
7918 assign( dV, getXMMReg(gregOfRM(modrm)) );
7919
7920 if (epartIsReg(modrm)) {
7921 assign( sV, getXMMReg(eregOfRM(modrm)) );
7922 select = (Int)insn[3];
7923 delta += 2+2;
7924 DIP("shufps $%d,%s,%s\n", select,
7925 nameXMMReg(eregOfRM(modrm)),
7926 nameXMMReg(gregOfRM(modrm)));
7927 } else {
7928 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
7929 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
7930 select = (Int)insn[2+alen];
7931 delta += 3+alen;
7932 DIP("shufps $%d,%s,%s\n", select,
7933 dis_buf,
7934 nameXMMReg(gregOfRM(modrm)));
7935 }
7936
7937 breakup128to32s( dV, &d3, &d2, &d1, &d0 );
7938 breakup128to32s( sV, &s3, &s2, &s1, &s0 );
7939
7940# define SELD(n) ((n)==0 ? d0 : ((n)==1 ? d1 : ((n)==2 ? d2 : d3)))
7941# define SELS(n) ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
7942
7943 putXMMReg(
7944 gregOfRM(modrm),
7945 mk128from32s( SELS((select>>6)&3), SELS((select>>4)&3),
7946 SELD((select>>2)&3), SELD((select>>0)&3) )
7947 );
7948
7949# undef SELD
7950# undef SELS
7951
7952 goto decode_success;
7953 }
7954
7955 /* 0F 51 = SQRTPS -- approx sqrt 32Fx4 from R/M to R */
sewardj008754b2004-12-08 14:37:10 +00007956 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x51) {
sewardjc1e7dfc2004-12-05 19:29:45 +00007957 delta = dis_SSE_E_to_G_unary_all( sorb, delta+2,
7958 "sqrtps", Iop_Sqrt32Fx4 );
7959 goto decode_success;
7960 }
7961
7962 /* F3 0F 51 = SQRTSS -- approx sqrt 32F0x4 from R/M to R */
7963 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x51) {
7964 vassert(sz == 4);
7965 delta = dis_SSE_E_to_G_unary_lo32( sorb, delta+3,
7966 "sqrtss", Iop_Sqrt32F0x4 );
7967 goto decode_success;
7968 }
7969
sewardj7df596b2004-12-06 14:29:12 +00007970 /* 0F AE /3 = STMXCSR m32 -- load %mxcsr */
7971 if (insn[0] == 0x0F && insn[1] == 0xAE
7972 && !epartIsReg(insn[2]) && gregOfRM(insn[2]) == 3) {
7973 modrm = getIByte(delta+2);
7974 vassert(sz == 4);
7975 vassert(!epartIsReg(modrm));
7976
7977 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
7978 delta += 2+alen;
7979
7980 /* Fake up a native SSE mxcsr word. The only thing it depends
7981 on is SSEROUND[1:0], so call a clean helper to cook it up.
7982 */
7983 /* UInt x86h_create_mxcsr ( UInt sseround ) */
7984 DIP("stmxcsr %s", dis_buf);
7985 storeLE( mkexpr(addr),
7986 mkIRExprCCall(
7987 Ity_I32, 0/*regp*/,
sewardj3bd6f3e2004-12-13 10:48:19 +00007988 "x86g_create_mxcsr", &x86g_create_mxcsr,
sewardj7df596b2004-12-06 14:29:12 +00007989 mkIRExprVec_1( get_fpround() )
7990 )
7991 );
7992 goto decode_success;
7993 }
7994
sewardjc1e7dfc2004-12-05 19:29:45 +00007995 /* 0F 5C = SUBPS -- sub 32Fx4 from R/M to R */
sewardj008754b2004-12-08 14:37:10 +00007996 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5C) {
sewardjc1e7dfc2004-12-05 19:29:45 +00007997 delta = dis_SSE_E_to_G_all( sorb, delta+2, "subps", Iop_Sub32Fx4 );
7998 goto decode_success;
7999 }
8000
sewardj008754b2004-12-08 14:37:10 +00008001 /* F3 0F 5C = SUBSS -- sub 32F0x4 from R/M to R */
sewardjc1e7dfc2004-12-05 19:29:45 +00008002 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5C) {
8003 vassert(sz == 4);
8004 delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "subss", Iop_Sub32F0x4 );
8005 goto decode_success;
8006 }
8007
8008 /* 0F 15 = UNPCKHPS -- unpack and interleave high part F32s */
8009 /* 0F 14 = UNPCKLPS -- unpack and interleave low part F32s */
8010 /* These just appear to be special cases of SHUFPS */
sewardj008754b2004-12-08 14:37:10 +00008011 if (sz == 4 && insn[0] == 0x0F && (insn[1] == 0x15 || insn[1] == 0x14)) {
sewardjc1e7dfc2004-12-05 19:29:45 +00008012 IRTemp sV, dV;
8013 IRTemp s3, s2, s1, s0, d3, d2, d1, d0;
8014 Bool hi = insn[1] == 0x15;
8015 sV = newTemp(Ity_V128);
8016 dV = newTemp(Ity_V128);
8017 s3 = s2 = s1 = s0 = d3 = d2 = d1 = d0 = IRTemp_INVALID;
sewardjc1e7dfc2004-12-05 19:29:45 +00008018 modrm = insn[2];
8019 assign( dV, getXMMReg(gregOfRM(modrm)) );
8020
8021 if (epartIsReg(modrm)) {
8022 assign( sV, getXMMReg(eregOfRM(modrm)) );
8023 delta += 2+1;
8024 DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
8025 nameXMMReg(eregOfRM(modrm)),
8026 nameXMMReg(gregOfRM(modrm)));
8027 } else {
8028 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8029 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
8030 delta += 2+alen;
8031 DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
8032 dis_buf,
8033 nameXMMReg(gregOfRM(modrm)));
8034 }
8035
8036 breakup128to32s( dV, &d3, &d2, &d1, &d0 );
8037 breakup128to32s( sV, &s3, &s2, &s1, &s0 );
8038
8039 if (hi) {
8040 putXMMReg( gregOfRM(modrm), mk128from32s( s3, d3, s2, d2 ) );
8041 } else {
8042 putXMMReg( gregOfRM(modrm), mk128from32s( s1, d1, s0, d0 ) );
8043 }
8044
8045 goto decode_success;
8046 }
8047
8048 /* 0F 57 = XORPS -- G = G and E */
sewardj008754b2004-12-08 14:37:10 +00008049 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x57) {
sewardjc1e7dfc2004-12-05 19:29:45 +00008050 delta = dis_SSE_E_to_G_all( sorb, delta+2, "xorps", Iop_Xor128 );
8051 goto decode_success;
8052 }
8053
sewardj636ad762004-12-07 11:16:04 +00008054 /* ---------------------------------------------------- */
8055 /* --- end of the SSE decoder. --- */
8056 /* ---------------------------------------------------- */
8057
8058 /* ---------------------------------------------------- */
8059 /* --- start of the SSE2 decoder. --- */
8060 /* ---------------------------------------------------- */
8061
8062 insn = (UChar*)&guest_code[delta];
8063
8064 /* 66 0F 58 = ADDPD -- add 32Fx4 from R/M to R */
8065 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x58) {
8066 delta = dis_SSE_E_to_G_all( sorb, delta+2, "addpd", Iop_Add64Fx2 );
8067 goto decode_success;
8068 }
8069
8070 /* F2 0F 58 = ADDSD -- add 64F0x2 from R/M to R */
8071 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x58) {
8072 vassert(sz == 4);
8073 delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "addsd", Iop_Add64F0x2 );
8074 goto decode_success;
8075 }
8076
8077 /* 66 0F 55 = ANDNPD -- G = (not G) and E */
8078 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x55) {
8079 delta = dis_SSE_E_to_G_all_invG( sorb, delta+2, "andnpd", Iop_And128 );
8080 goto decode_success;
8081 }
8082
8083 /* 66 0F 54 = ANDPD -- G = G and E */
8084 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x54) {
8085 delta = dis_SSE_E_to_G_all( sorb, delta+2, "andpd", Iop_And128 );
8086 goto decode_success;
8087 }
8088
sewardjfd226452004-12-07 19:02:18 +00008089 /* 66 0F C2 = CMPPD -- 64Fx2 comparison from R/M to R */
8090 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xC2) {
8091 delta = dis_SSEcmp_E_to_G( sorb, delta+2, "cmppd", True, 8 );
8092 goto decode_success;
8093 }
8094
8095 /* F2 0F C2 = CMPSD -- 64F0x2 comparison from R/M to R */
8096 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0xC2) {
8097 vassert(sz == 4);
8098 delta = dis_SSEcmp_E_to_G( sorb, delta+3, "cmpsd", False, 8 );
8099 goto decode_success;
8100 }
8101
8102 /* 66 0F 2F = COMISD -- 64F0x2 comparison G,E, and set ZCP */
8103 /* 66 0F 2E = UCOMISD -- 64F0x2 comparison G,E, and set ZCP */
8104 if (sz == 2 && insn[0] == 0x0F && (insn[1] == 0x2F || insn[1] == 0x2E)) {
8105 IRTemp argL = newTemp(Ity_F64);
8106 IRTemp argR = newTemp(Ity_F64);
8107 modrm = getIByte(delta+2);
8108 if (epartIsReg(modrm)) {
8109 assign( argR, getXMMRegLane64F( eregOfRM(modrm), 0/*lowest lane*/ ) );
8110 delta += 2+1;
8111 DIP("[u]comisd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
8112 nameXMMReg(gregOfRM(modrm)) );
8113 } else {
8114 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8115 assign( argR, loadLE(Ity_F64, mkexpr(addr)) );
8116 delta += 2+alen;
8117 DIP("[u]comisd %s,%s\n", dis_buf,
8118 nameXMMReg(gregOfRM(modrm)) );
8119 }
8120 assign( argL, getXMMRegLane64F( gregOfRM(modrm), 0/*lowest lane*/ ) );
8121
8122 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
8123 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
8124 stmt( IRStmt_Put(
8125 OFFB_CC_DEP1,
8126 binop( Iop_And32,
8127 binop(Iop_CmpF64, mkexpr(argL), mkexpr(argR)),
8128 mkU32(0x45)
8129 )));
8130
8131 goto decode_success;
8132 }
8133
8134 /* F3 0F E6 = CVTDQ2PD -- convert 2 x I32 in mem/lo half xmm to 2 x
8135 F64 in xmm(G) */
8136 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0xE6) {
8137 IRTemp arg64 = newTemp(Ity_I64);
8138 vassert(sz == 4);
8139
8140 modrm = getIByte(delta+3);
8141 if (epartIsReg(modrm)) {
8142 assign( arg64, getXMMRegLane64(eregOfRM(modrm), 0) );
8143 delta += 3+1;
8144 DIP("cvtdq2pd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
8145 nameXMMReg(gregOfRM(modrm)));
8146 } else {
8147 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
8148 assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
8149 delta += 3+alen;
8150 DIP("cvtdq2pd %s,%s\n", dis_buf,
8151 nameXMMReg(gregOfRM(modrm)) );
8152 }
8153
8154 putXMMRegLane64F(
8155 gregOfRM(modrm), 0,
8156 unop(Iop_I32toF64, unop(Iop_64to32, mkexpr(arg64)))
8157 );
8158
8159 putXMMRegLane64F(
8160 gregOfRM(modrm), 1,
8161 unop(Iop_I32toF64, unop(Iop_64HIto32, mkexpr(arg64)))
8162 );
8163
8164 goto decode_success;
8165 }
8166
8167 /* 0F 5B = CVTDQ2PS -- convert 4 x I32 in mem/xmm to 4 x F32 in
8168 xmm(G) */
8169 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5B) {
8170 IRTemp argV = newTemp(Ity_V128);
8171 IRTemp rmode = newTemp(Ity_I32);
8172
8173 modrm = getIByte(delta+2);
8174 if (epartIsReg(modrm)) {
8175 assign( argV, getXMMReg(eregOfRM(modrm)) );
8176 delta += 2+1;
8177 DIP("cvtdq2ps %s,%s\n", nameXMMReg(eregOfRM(modrm)),
8178 nameXMMReg(gregOfRM(modrm)));
8179 } else {
8180 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8181 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
8182 delta += 2+alen;
8183 DIP("cvtdq2ps %s,%s\n", dis_buf,
8184 nameXMMReg(gregOfRM(modrm)) );
8185 }
8186
8187 assign( rmode, get_sse_roundingmode() );
8188 breakup128to32s( argV, &t3, &t2, &t1, &t0 );
8189
8190# define CVT(_t) binop( Iop_F64toF32, \
8191 mkexpr(rmode), \
8192 unop(Iop_I32toF64,mkexpr(_t)))
8193
8194 putXMMRegLane32F( gregOfRM(modrm), 3, CVT(t3) );
8195 putXMMRegLane32F( gregOfRM(modrm), 2, CVT(t2) );
8196 putXMMRegLane32F( gregOfRM(modrm), 1, CVT(t1) );
8197 putXMMRegLane32F( gregOfRM(modrm), 0, CVT(t0) );
8198
8199# undef CVT
8200
8201 goto decode_success;
8202 }
8203
8204 /* F2 0F E6 = CVTPD2DQ -- convert 2 x F64 in mem/xmm to 2 x I32 in
8205 lo half xmm(G), and zero upper half */
8206 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0xE6) {
8207 IRTemp argV = newTemp(Ity_V128);
8208 IRTemp rmode = newTemp(Ity_I32);
8209 vassert(sz == 4);
8210
8211 modrm = getIByte(delta+3);
8212 if (epartIsReg(modrm)) {
8213 assign( argV, getXMMReg(eregOfRM(modrm)) );
8214 delta += 3+1;
8215 DIP("cvtpd2dq %s,%s\n", nameXMMReg(eregOfRM(modrm)),
8216 nameXMMReg(gregOfRM(modrm)));
8217 } else {
8218 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
8219 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
8220 delta += 3+alen;
8221 DIP("cvtpd2dq %s,%s\n", dis_buf,
8222 nameXMMReg(gregOfRM(modrm)) );
8223 }
8224
8225 assign( rmode, get_sse_roundingmode() );
8226 t0 = newTemp(Ity_F64);
8227 t1 = newTemp(Ity_F64);
8228 assign( t0, unop(Iop_ReinterpI64asF64,
8229 unop(Iop_128to64, mkexpr(argV))) );
8230 assign( t1, unop(Iop_ReinterpI64asF64,
8231 unop(Iop_128HIto64, mkexpr(argV))) );
8232
8233# define CVT(_t) binop( Iop_F64toI32, \
8234 mkexpr(rmode), \
8235 mkexpr(_t) )
8236
8237 putXMMRegLane32( gregOfRM(modrm), 3, mkU32(0) );
8238 putXMMRegLane32( gregOfRM(modrm), 2, mkU32(0) );
8239 putXMMRegLane32( gregOfRM(modrm), 1, CVT(t1) );
8240 putXMMRegLane32( gregOfRM(modrm), 0, CVT(t0) );
8241
8242# undef CVT
8243
8244 goto decode_success;
8245 }
8246
8247 /* 66 0F 2D = CVTPD2PI -- convert 2 x F64 in mem/xmm to 2 x
8248 I32 in mmx, according to prevailing SSE rounding mode */
8249 /* 66 0F 2C = CVTTPD2PI -- convert 2 x F64 in mem/xmm to 2 x
8250 I32 in mmx, rounding towards zero */
8251 if (sz == 2 && insn[0] == 0x0F && (insn[1] == 0x2D || insn[1] == 0x2C)) {
8252 IRTemp dst64 = newTemp(Ity_I64);
8253 IRTemp rmode = newTemp(Ity_I32);
8254 IRTemp f64lo = newTemp(Ity_F64);
8255 IRTemp f64hi = newTemp(Ity_F64);
8256 Bool r2zero = insn[1] == 0x2C;
8257
8258 do_MMX_preamble();
8259 modrm = getIByte(delta+2);
8260
8261 if (epartIsReg(modrm)) {
8262 delta += 2+1;
8263 assign(f64lo, getXMMRegLane64F(eregOfRM(modrm), 0));
8264 assign(f64hi, getXMMRegLane64F(eregOfRM(modrm), 1));
8265 DIP("cvt%spd2pi %s,%s\n", r2zero ? "t" : "",
8266 nameXMMReg(eregOfRM(modrm)),
8267 nameMMXReg(gregOfRM(modrm)));
8268 } else {
8269 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8270 assign(f64lo, loadLE(Ity_F64, mkexpr(addr)));
8271 assign(f64hi, loadLE(Ity_F64, binop( Iop_Add32,
8272 mkexpr(addr),
8273 mkU32(8) )));
8274 delta += 2+alen;
8275 DIP("cvt%spf2pi %s,%s\n", r2zero ? "t" : "",
8276 dis_buf,
8277 nameMMXReg(gregOfRM(modrm)));
8278 }
8279
8280 if (r2zero) {
8281 assign(rmode, mkU32((UInt)Irrm_ZERO) );
8282 } else {
8283 assign( rmode, get_sse_roundingmode() );
8284 }
8285
8286 assign(
8287 dst64,
8288 binop( Iop_32HLto64,
8289 binop( Iop_F64toI32, mkexpr(rmode), mkexpr(f64hi) ),
8290 binop( Iop_F64toI32, mkexpr(rmode), mkexpr(f64lo) )
8291 )
8292 );
8293
8294 putMMXReg(gregOfRM(modrm), mkexpr(dst64));
8295 goto decode_success;
8296 }
8297
8298 /* 66 0F 5A = CVTPD2PS -- convert 2 x F64 in mem/xmm to 2 x F32 in
8299 lo half xmm(G), and zero upper half */
8300 /* Note, this is practically identical to CVTPD2DQ. It would have
8301 been nicer to merge them together, but the insn[] offsets differ
8302 by one. */
8303 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5A) {
8304 IRTemp argV = newTemp(Ity_V128);
8305 IRTemp rmode = newTemp(Ity_I32);
8306
8307 modrm = getIByte(delta+2);
8308 if (epartIsReg(modrm)) {
8309 assign( argV, getXMMReg(eregOfRM(modrm)) );
8310 delta += 2+1;
8311 DIP("cvtpd2ps %s,%s\n", nameXMMReg(eregOfRM(modrm)),
8312 nameXMMReg(gregOfRM(modrm)));
8313 } else {
8314 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8315 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
8316 delta += 2+alen;
8317 DIP("cvtpd2ps %s,%s\n", dis_buf,
8318 nameXMMReg(gregOfRM(modrm)) );
8319 }
8320
8321 assign( rmode, get_sse_roundingmode() );
8322 t0 = newTemp(Ity_F64);
8323 t1 = newTemp(Ity_F64);
8324 assign( t0, unop(Iop_ReinterpI64asF64,
8325 unop(Iop_128to64, mkexpr(argV))) );
8326 assign( t1, unop(Iop_ReinterpI64asF64,
8327 unop(Iop_128HIto64, mkexpr(argV))) );
8328
8329# define CVT(_t) binop( Iop_F64toF32, \
8330 mkexpr(rmode), \
8331 mkexpr(_t) )
8332
8333 putXMMRegLane32( gregOfRM(modrm), 3, mkU32(0) );
8334 putXMMRegLane32( gregOfRM(modrm), 2, mkU32(0) );
8335 putXMMRegLane32F( gregOfRM(modrm), 1, CVT(t1) );
8336 putXMMRegLane32F( gregOfRM(modrm), 0, CVT(t0) );
8337
8338# undef CVT
8339
8340 goto decode_success;
8341 }
8342
8343 /* 66 0F 2A = CVTPI2PD -- convert 2 x I32 in mem/mmx to 2 x F64 in
8344 xmm(G) */
8345 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x2A) {
8346 IRTemp arg64 = newTemp(Ity_I64);
8347
8348 modrm = getIByte(delta+2);
8349 do_MMX_preamble();
8350 if (epartIsReg(modrm)) {
8351 assign( arg64, getMMXReg(eregOfRM(modrm)) );
8352 delta += 2+1;
8353 DIP("cvtpi2pd %s,%s\n", nameMMXReg(eregOfRM(modrm)),
8354 nameXMMReg(gregOfRM(modrm)));
8355 } else {
8356 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8357 assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
8358 delta += 2+alen;
8359 DIP("cvtpi2pd %s,%s\n", dis_buf,
8360 nameXMMReg(gregOfRM(modrm)) );
8361 }
8362
8363 putXMMRegLane64F(
8364 gregOfRM(modrm), 0,
8365 unop(Iop_I32toF64, unop(Iop_64to32, mkexpr(arg64)) )
8366 );
8367
8368 putXMMRegLane64F(
8369 gregOfRM(modrm), 1,
8370 unop(Iop_I32toF64, unop(Iop_64HIto32, mkexpr(arg64)) )
8371 );
8372
8373 goto decode_success;
8374 }
8375
8376 /* 66 0F 5B = CVTPS2DQ -- convert 4 x F32 in mem/xmm to 4 x I32 in
8377 xmm(G) */
8378 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5B) {
8379 IRTemp argV = newTemp(Ity_V128);
8380 IRTemp rmode = newTemp(Ity_I32);
8381
8382 modrm = getIByte(delta+2);
8383 if (epartIsReg(modrm)) {
8384 assign( argV, getXMMReg(eregOfRM(modrm)) );
8385 delta += 2+1;
8386 DIP("cvtps2dq %s,%s\n", nameXMMReg(eregOfRM(modrm)),
8387 nameXMMReg(gregOfRM(modrm)));
8388 } else {
8389 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8390 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
8391 delta += 2+alen;
8392 DIP("cvtps2dq %s,%s\n", dis_buf,
8393 nameXMMReg(gregOfRM(modrm)) );
8394 }
8395
8396 assign( rmode, get_sse_roundingmode() );
8397 breakup128to32s( argV, &t3, &t2, &t1, &t0 );
8398
8399 /* This is less than ideal. If it turns out to be a performance
8400 bottleneck it can be improved. */
8401# define CVT(_t) \
8402 binop( Iop_F64toI32, \
8403 mkexpr(rmode), \
8404 unop( Iop_F32toF64, \
8405 unop( Iop_ReinterpI32asF32, mkexpr(_t))) )
8406
8407 putXMMRegLane32( gregOfRM(modrm), 3, CVT(t3) );
8408 putXMMRegLane32( gregOfRM(modrm), 2, CVT(t2) );
8409 putXMMRegLane32( gregOfRM(modrm), 1, CVT(t1) );
8410 putXMMRegLane32( gregOfRM(modrm), 0, CVT(t0) );
8411
8412# undef CVT
8413
8414 goto decode_success;
8415 }
8416
8417 /* 0F 5A = CVTPS2PD -- convert 2 x F32 in low half mem/xmm to 2 x
8418 F64 in xmm(G). */
8419 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5A) {
8420 IRTemp f32lo = newTemp(Ity_F32);
8421 IRTemp f32hi = newTemp(Ity_F32);
8422
8423 modrm = getIByte(delta+2);
8424 if (epartIsReg(modrm)) {
8425 assign( f32lo, getXMMRegLane32F(eregOfRM(modrm), 0) );
8426 assign( f32hi, getXMMRegLane32F(eregOfRM(modrm), 1) );
8427 delta += 2+1;
8428 DIP("cvtps2pd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
8429 nameXMMReg(gregOfRM(modrm)));
8430 } else {
8431 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8432 assign( f32lo, loadLE(Ity_F32, mkexpr(addr)) );
8433 assign( f32hi, loadLE(Ity_F32,
8434 binop(Iop_Add32,mkexpr(addr),mkU32(4))) );
8435 delta += 2+alen;
8436 DIP("cvtps2pd %s,%s\n", dis_buf,
8437 nameXMMReg(gregOfRM(modrm)) );
8438 }
8439
8440 putXMMRegLane64F( gregOfRM(modrm), 1,
8441 unop(Iop_F32toF64, mkexpr(f32hi)) );
8442 putXMMRegLane64F( gregOfRM(modrm), 0,
8443 unop(Iop_F32toF64, mkexpr(f32lo)) );
8444
8445 goto decode_success;
8446 }
8447
8448 /* F2 0F 2D = CVTSD2SI -- convert F64 in mem/low half xmm to
8449 I32 in ireg, according to prevailing SSE rounding mode */
8450 /* F2 0F 2C = CVTTSD2SI -- convert F64 in mem/low half xmm to
8451 I32 in ireg, according to prevailing SSE rounding mode */
8452 if (insn[0] == 0xF2 && insn[1] == 0x0F
8453 && (insn[2] == 0x2D || insn[2] == 0x2C)) {
8454 IRTemp rmode = newTemp(Ity_I32);
8455 IRTemp f64lo = newTemp(Ity_F64);
8456 Bool r2zero = insn[2] == 0x2C;
8457 vassert(sz == 4);
8458
8459 modrm = getIByte(delta+3);
8460 if (epartIsReg(modrm)) {
8461 delta += 3+1;
8462 assign(f64lo, getXMMRegLane64F(eregOfRM(modrm), 0));
8463 DIP("cvt%ssd2si %s,%s\n", r2zero ? "t" : "",
8464 nameXMMReg(eregOfRM(modrm)),
8465 nameIReg(4, gregOfRM(modrm)));
8466 } else {
8467 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
8468 assign(f64lo, loadLE(Ity_F64, mkexpr(addr)));
8469 delta += 3+alen;
8470 DIP("cvt%ssd2si %s,%s\n", r2zero ? "t" : "",
8471 dis_buf,
8472 nameIReg(4, gregOfRM(modrm)));
8473 }
8474
8475 if (r2zero) {
8476 assign( rmode, mkU32((UInt)Irrm_ZERO) );
8477 } else {
8478 assign( rmode, get_sse_roundingmode() );
8479 }
8480
8481 putIReg(4, gregOfRM(modrm),
8482 binop( Iop_F64toI32, mkexpr(rmode), mkexpr(f64lo)) );
8483
8484 goto decode_success;
8485 }
8486
8487 /* F2 0F 5A = CVTSD2SS -- convert F64 in mem/low half xmm to F32 in
8488 low 1/4 xmm(G), according to prevailing SSE rounding mode */
8489 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x5A) {
8490 IRTemp rmode = newTemp(Ity_I32);
8491 IRTemp f64lo = newTemp(Ity_F64);
8492 vassert(sz == 4);
8493
8494 modrm = getIByte(delta+3);
8495 if (epartIsReg(modrm)) {
8496 delta += 3+1;
8497 assign(f64lo, getXMMRegLane64F(eregOfRM(modrm), 0));
8498 DIP("cvtsd2ss %s,%s\n", nameXMMReg(eregOfRM(modrm)),
8499 nameXMMReg(gregOfRM(modrm)));
8500 } else {
8501 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
8502 assign(f64lo, loadLE(Ity_F64, mkexpr(addr)));
8503 delta += 3+alen;
8504 DIP("cvtsd2ss %s,%s\n", dis_buf,
8505 nameXMMReg(gregOfRM(modrm)));
8506 }
8507
8508 assign( rmode, get_sse_roundingmode() );
8509 putXMMRegLane32F(
8510 gregOfRM(modrm), 0,
8511 binop( Iop_F64toF32, mkexpr(rmode), mkexpr(f64lo) )
8512 );
8513
8514 goto decode_success;
8515 }
8516
8517 /* F2 0F 2A = CVTSI2SD -- convert I32 in mem/ireg to F64 in low
8518 half xmm */
8519 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x2A) {
8520 IRTemp arg32 = newTemp(Ity_I32);
8521 vassert(sz == 4);
8522
8523 modrm = getIByte(delta+3);
sewardjfd226452004-12-07 19:02:18 +00008524 if (epartIsReg(modrm)) {
8525 assign( arg32, getIReg(4, eregOfRM(modrm)) );
8526 delta += 3+1;
8527 DIP("cvtsi2sd %s,%s\n", nameIReg(4, eregOfRM(modrm)),
8528 nameXMMReg(gregOfRM(modrm)));
8529 } else {
8530 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
8531 assign( arg32, loadLE(Ity_I32, mkexpr(addr)) );
8532 delta += 3+alen;
8533 DIP("cvtsi2sd %s,%s\n", dis_buf,
8534 nameXMMReg(gregOfRM(modrm)) );
8535 }
8536
8537 putXMMRegLane64F(
8538 gregOfRM(modrm), 0,
8539 unop(Iop_I32toF64, mkexpr(arg32)) );
8540
8541 goto decode_success;
8542 }
8543
8544 /* F3 0F 5A = CVTSS2SD -- convert F32 in mem/low 1/4 xmm to F64 in
8545 low half xmm(G) */
8546 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5A) {
8547 IRTemp f32lo = newTemp(Ity_F32);
8548 vassert(sz == 4);
8549
8550 modrm = getIByte(delta+3);
8551 if (epartIsReg(modrm)) {
8552 delta += 3+1;
8553 assign(f32lo, getXMMRegLane32F(eregOfRM(modrm), 0));
8554 DIP("cvtss2sd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
8555 nameXMMReg(gregOfRM(modrm)));
8556 } else {
8557 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
8558 assign(f32lo, loadLE(Ity_F32, mkexpr(addr)));
8559 delta += 3+alen;
8560 DIP("cvtss2sd %s,%s\n", dis_buf,
8561 nameXMMReg(gregOfRM(modrm)));
8562 }
8563
8564 putXMMRegLane64F( gregOfRM(modrm), 0,
8565 unop( Iop_F32toF64, mkexpr(f32lo) ) );
8566
8567 goto decode_success;
8568 }
8569
8570 /* 66 0F E6 = CVTTPD2DQ -- convert 2 x F64 in mem/xmm to 2 x I32 in
8571 lo half xmm(G), and zero upper half, rounding towards zero */
8572 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE6) {
8573 IRTemp argV = newTemp(Ity_V128);
8574 IRTemp rmode = newTemp(Ity_I32);
8575
8576 modrm = getIByte(delta+2);
8577 if (epartIsReg(modrm)) {
8578 assign( argV, getXMMReg(eregOfRM(modrm)) );
8579 delta += 2+1;
8580 DIP("cvttpd2dq %s,%s\n", nameXMMReg(eregOfRM(modrm)),
8581 nameXMMReg(gregOfRM(modrm)));
8582 } else {
8583 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8584 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
8585 delta += 2+alen;
8586 DIP("cvttpd2dq %s,%s\n", dis_buf,
8587 nameXMMReg(gregOfRM(modrm)) );
8588 }
8589
8590 assign( rmode, mkU32((UInt)Irrm_ZERO) );
8591
8592 t0 = newTemp(Ity_F64);
8593 t1 = newTemp(Ity_F64);
8594 assign( t0, unop(Iop_ReinterpI64asF64,
8595 unop(Iop_128to64, mkexpr(argV))) );
8596 assign( t1, unop(Iop_ReinterpI64asF64,
8597 unop(Iop_128HIto64, mkexpr(argV))) );
8598
8599# define CVT(_t) binop( Iop_F64toI32, \
8600 mkexpr(rmode), \
8601 mkexpr(_t) )
8602
8603 putXMMRegLane32( gregOfRM(modrm), 3, mkU32(0) );
8604 putXMMRegLane32( gregOfRM(modrm), 2, mkU32(0) );
8605 putXMMRegLane32( gregOfRM(modrm), 1, CVT(t1) );
8606 putXMMRegLane32( gregOfRM(modrm), 0, CVT(t0) );
8607
8608# undef CVT
8609
8610 goto decode_success;
8611 }
8612
8613 /* F3 0F 5B = CVTTPS2DQ -- convert 4 x F32 in mem/xmm to 4 x I32 in
8614 xmm(G), rounding towards zero */
8615 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5B) {
8616 IRTemp argV = newTemp(Ity_V128);
8617 IRTemp rmode = newTemp(Ity_I32);
8618 vassert(sz == 4);
8619
8620 modrm = getIByte(delta+3);
8621 if (epartIsReg(modrm)) {
8622 assign( argV, getXMMReg(eregOfRM(modrm)) );
8623 delta += 3+1;
8624 DIP("cvttps2dq %s,%s\n", nameXMMReg(eregOfRM(modrm)),
8625 nameXMMReg(gregOfRM(modrm)));
8626 } else {
8627 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
8628 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
8629 delta += 3+alen;
8630 DIP("cvttps2dq %s,%s\n", dis_buf,
8631 nameXMMReg(gregOfRM(modrm)) );
8632 }
8633
8634 assign( rmode, mkU32((UInt)Irrm_ZERO) );
8635 breakup128to32s( argV, &t3, &t2, &t1, &t0 );
8636
8637 /* This is less than ideal. If it turns out to be a performance
8638 bottleneck it can be improved. */
8639# define CVT(_t) \
8640 binop( Iop_F64toI32, \
8641 mkexpr(rmode), \
8642 unop( Iop_F32toF64, \
8643 unop( Iop_ReinterpI32asF32, mkexpr(_t))) )
8644
8645 putXMMRegLane32( gregOfRM(modrm), 3, CVT(t3) );
8646 putXMMRegLane32( gregOfRM(modrm), 2, CVT(t2) );
8647 putXMMRegLane32( gregOfRM(modrm), 1, CVT(t1) );
8648 putXMMRegLane32( gregOfRM(modrm), 0, CVT(t0) );
8649
8650# undef CVT
8651
8652 goto decode_success;
8653 }
8654
8655 /* 66 0F 5E = DIVPD -- div 64Fx2 from R/M to R */
8656 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5E) {
8657 delta = dis_SSE_E_to_G_all( sorb, delta+2, "divpd", Iop_Div64Fx2 );
8658 goto decode_success;
8659 }
8660
sewardjc2feffc2004-12-08 12:31:22 +00008661 /* F2 0F 5E = DIVSD -- div 64F0x2 from R/M to R */
8662 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x5E) {
8663 vassert(sz == 4);
8664 delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "divsd", Iop_Div64F0x2 );
8665 goto decode_success;
8666 }
8667
8668 /* 0F AE /5 = LFENCE -- flush pending operations to memory */
8669 /* 0F AE /6 = MFENCE -- flush pending operations to memory */
8670 if (insn[0] == 0x0F && insn[1] == 0xAE
8671 && epartIsReg(insn[2])
8672 && (gregOfRM(insn[2]) == 5 || gregOfRM(insn[2]) == 6)) {
8673 vassert(sz == 4);
8674 delta += 3;
8675 /* nothing to do */
8676 DIP("%sfence\n", gregOfRM(insn[2])==5 ? "l" : "m");
8677 goto decode_success;
8678 }
8679
8680 /* 66 0F 5F = MAXPD -- max 64Fx2 from R/M to R */
8681 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5F) {
8682 delta = dis_SSE_E_to_G_all( sorb, delta+2, "maxpd", Iop_Max64Fx2 );
8683 goto decode_success;
8684 }
8685
8686 /* F2 0F 5F = MAXSD -- max 64F0x2 from R/M to R */
8687 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x5F) {
8688 vassert(sz == 4);
8689 delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "maxsd", Iop_Max64F0x2 );
8690 goto decode_success;
8691 }
8692
8693 /* 66 0F 5D = MINPD -- min 64Fx2 from R/M to R */
8694 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5D) {
8695 delta = dis_SSE_E_to_G_all( sorb, delta+2, "minpd", Iop_Min64Fx2 );
8696 goto decode_success;
8697 }
8698
8699 /* F2 0F 5D = MINSD -- min 64F0x2 from R/M to R */
8700 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x5D) {
8701 vassert(sz == 4);
8702 delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "minsd", Iop_Min64F0x2 );
8703 goto decode_success;
8704 }
8705
8706 /* 66 0F 28 = MOVAPD -- move from E (mem or xmm) to G (xmm). */
8707 /* 66 0F 10 = MOVUPD -- move from E (mem or xmm) to G (xmm). */
8708 /* 66 0F 6F = MOVDQA -- move from E (mem or xmm) to G (xmm). */
8709 if (sz == 2 && insn[0] == 0x0F
8710 && (insn[1] == 0x28 || insn[1] == 0x10 || insn[1] == 0x6F)) {
8711 HChar* wot = insn[1]==0x28 ? "apd" :
8712 insn[1]==0x10 ? "upd" : "dqa";
8713 modrm = getIByte(delta+2);
8714 if (epartIsReg(modrm)) {
8715 putXMMReg( gregOfRM(modrm),
8716 getXMMReg( eregOfRM(modrm) ));
8717 DIP("mov%s %s,%s\n", wot, nameXMMReg(eregOfRM(modrm)),
8718 nameXMMReg(gregOfRM(modrm)));
8719 delta += 2+1;
8720 } else {
8721 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8722 putXMMReg( gregOfRM(modrm),
8723 loadLE(Ity_V128, mkexpr(addr)) );
8724 DIP("mov%s %s,%s\n", wot, dis_buf,
8725 nameXMMReg(gregOfRM(modrm)));
8726 delta += 2+alen;
8727 }
8728 goto decode_success;
8729 }
8730
8731 /* 66 0F 6E = MOVD from r/m32 to xmm, zeroing high 3/4 of xmm. */
8732 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x6E) {
8733 modrm = getIByte(delta+2);
8734 if (epartIsReg(modrm)) {
8735 delta += 2+1;
8736 putXMMReg(
8737 gregOfRM(modrm),
8738 unop( Iop_32Uto128, getIReg(4, eregOfRM(modrm)) )
8739 );
8740 DIP("movd %s, %s\n",
8741 nameIReg(4,eregOfRM(modrm)), nameXMMReg(gregOfRM(modrm)));
8742 } else {
8743 addr = disAMode( &alen, sorb, delta+2, dis_buf );
8744 delta += 2+alen;
8745 putXMMReg(
8746 gregOfRM(modrm),
8747 unop( Iop_32Uto128,loadLE(Ity_I32, mkexpr(addr)) )
8748 );
8749 DIP("movd %s, %s\n", dis_buf, nameXMMReg(gregOfRM(modrm)));
8750 }
8751 goto decode_success;
8752 }
8753
8754 /* 66 0F 7E = MOVD from xmm low 1/4 to r/m32. */
8755 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x7E) {
8756 modrm = getIByte(delta+2);
8757 if (epartIsReg(modrm)) {
8758 delta += 2+1;
8759 putIReg( 4, eregOfRM(modrm),
8760 getXMMRegLane32(gregOfRM(modrm), 0) );
8761 DIP("movd %s, %s\n",
8762 nameXMMReg(gregOfRM(modrm)), nameIReg(4,eregOfRM(modrm)));
8763 } else {
8764 addr = disAMode( &alen, sorb, delta+2, dis_buf );
8765 delta += 2+alen;
8766 storeLE( mkexpr(addr),
8767 getXMMRegLane32(gregOfRM(modrm), 0) );
8768 DIP("movd %s, %s\n", nameXMMReg(gregOfRM(modrm)), dis_buf);
8769 }
8770 goto decode_success;
8771 }
8772
8773 /* 66 0F 7F = MOVDQA -- move from G (xmm) to E (mem or xmm). */
8774 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x7F) {
8775 modrm = getIByte(delta+2);
8776 if (epartIsReg(modrm)) {
8777 delta += 2+1;
8778 putXMMReg( eregOfRM(modrm),
8779 getXMMReg(gregOfRM(modrm)) );
8780 DIP("movdqa %s, %s\n", nameXMMReg(gregOfRM(modrm)),
8781 nameXMMReg(eregOfRM(modrm)));
8782 } else {
8783 addr = disAMode( &alen, sorb, delta+2, dis_buf );
8784 delta += 2+alen;
8785 storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) );
8786 DIP("movdqa %s, %s\n", nameXMMReg(gregOfRM(modrm)), dis_buf);
8787 }
8788 goto decode_success;
8789 }
8790
8791 /* F3 0F 6F = MOVDQU -- move from E (mem or xmm) to G (xmm). */
8792 /* Unfortunately can't simply use the MOVDQA case since the
8793 prefix lengths are different (66 vs F3) */
8794 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x6F) {
8795 vassert(sz == 4);
8796 modrm = getIByte(delta+3);
8797 if (epartIsReg(modrm)) {
8798 putXMMReg( gregOfRM(modrm),
8799 getXMMReg( eregOfRM(modrm) ));
8800 DIP("movdqu %s,%s\n", nameXMMReg(eregOfRM(modrm)),
8801 nameXMMReg(gregOfRM(modrm)));
8802 delta += 3+1;
8803 } else {
8804 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
8805 putXMMReg( gregOfRM(modrm),
8806 loadLE(Ity_V128, mkexpr(addr)) );
8807 DIP("movdqu %s,%s\n", dis_buf,
8808 nameXMMReg(gregOfRM(modrm)));
8809 delta += 3+alen;
8810 }
8811 goto decode_success;
8812 }
8813
8814 /* F3 0F 7F = MOVDQU -- move from G (xmm) to E (mem or xmm). */
8815 /* Unfortunately can't simply use the MOVDQA case since the
8816 prefix lengths are different (66 vs F3) */
8817 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x7F) {
8818 vassert(sz == 4);
8819 modrm = getIByte(delta+3);
8820 if (epartIsReg(modrm)) {
8821 delta += 3+1;
8822 putXMMReg( eregOfRM(modrm),
8823 getXMMReg(gregOfRM(modrm)) );
8824 DIP("movdqu %s, %s\n", nameXMMReg(gregOfRM(modrm)),
8825 nameXMMReg(eregOfRM(modrm)));
8826 } else {
8827 addr = disAMode( &alen, sorb, delta+3, dis_buf );
8828 delta += 3+alen;
8829 storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) );
8830 DIP("movdqu %s, %s\n", nameXMMReg(gregOfRM(modrm)), dis_buf);
8831 }
8832 goto decode_success;
8833 }
8834
8835 /* F2 0F D6 = MOVDQ2Q -- move from E (lo half xmm, not mem) to G (mmx). */
8836 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0xD6) {
8837 vassert(sz == 4);
8838 modrm = getIByte(delta+3);
8839 if (epartIsReg(modrm)) {
8840 do_MMX_preamble();
8841 putMMXReg( gregOfRM(modrm),
8842 getXMMRegLane64( eregOfRM(modrm), 0 ));
8843 DIP("movdq2q %s,%s\n", nameXMMReg(eregOfRM(modrm)),
8844 nameMMXReg(gregOfRM(modrm)));
8845 delta += 3+1;
8846 goto decode_success;
8847 } else {
8848 /* fall through, apparently no mem case for this insn */
8849 }
8850 }
8851
8852 /* 66 0F 16 = MOVHPD -- move from mem to high half of XMM. */
8853 /* These seems identical to MOVHPS. This instruction encoding is
8854 completely crazy. */
8855 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x16) {
8856 modrm = getIByte(delta+2);
8857 if (epartIsReg(modrm)) {
8858 /* fall through; apparently reg-reg is not possible */
8859 } else {
8860 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8861 delta += 2+alen;
8862 putXMMRegLane64( gregOfRM(modrm), 1/*upper lane*/,
8863 loadLE(Ity_I64, mkexpr(addr)) );
8864 DIP("movhpd %s,%s\n", dis_buf,
8865 nameXMMReg( gregOfRM(modrm) ));
8866 goto decode_success;
8867 }
8868 }
8869
8870 /* 66 0F 17 = MOVHPD -- move from high half of XMM to mem. */
8871 /* Again, this seems identical to MOVHPS. */
8872 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x17) {
8873 if (!epartIsReg(insn[2])) {
8874 delta += 2;
8875 addr = disAMode ( &alen, sorb, delta, dis_buf );
8876 delta += alen;
8877 storeLE( mkexpr(addr),
8878 getXMMRegLane64( gregOfRM(insn[2]),
8879 1/*upper lane*/ ) );
8880 DIP("movhpd %s,%s\n", nameXMMReg( gregOfRM(insn[2]) ),
8881 dis_buf);
8882 goto decode_success;
8883 }
8884 /* else fall through */
8885 }
8886
8887 /* 66 0F 12 = MOVLPD -- move from mem to low half of XMM. */
8888 /* Identical to MOVLPS ? */
8889 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x12) {
8890 modrm = getIByte(delta+2);
8891 if (epartIsReg(modrm)) {
8892 /* fall through; apparently reg-reg is not possible */
8893 } else {
8894 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8895 delta += 2+alen;
8896 putXMMRegLane64( gregOfRM(modrm), 0/*lower lane*/,
8897 loadLE(Ity_I64, mkexpr(addr)) );
8898 DIP("movlpd %s, %s\n",
8899 dis_buf, nameXMMReg( gregOfRM(modrm) ));
8900 goto decode_success;
8901 }
8902 }
8903
8904 /* 66 0F 13 = MOVLPD -- move from low half of XMM to mem. */
8905 /* Identical to MOVLPS ? */
8906 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x13) {
8907 if (!epartIsReg(insn[2])) {
8908 delta += 2;
8909 addr = disAMode ( &alen, sorb, delta, dis_buf );
8910 delta += alen;
8911 storeLE( mkexpr(addr),
8912 getXMMRegLane64( gregOfRM(insn[2]),
8913 0/*lower lane*/ ) );
8914 DIP("movlpd %s, %s\n", nameXMMReg( gregOfRM(insn[2]) ),
8915 dis_buf);
8916 goto decode_success;
8917 }
8918 /* else fall through */
8919 }
8920
8921 /* 66 0F 50 = MOVMSKPD - move 2 sign bits from 2 x F64 in xmm(E) to
8922 2 lowest bits of ireg(G) */
8923 if (insn[0] == 0x0F && insn[1] == 0x50) {
8924 modrm = getIByte(delta+2);
8925 if (sz == 2 && epartIsReg(modrm)) {
8926 Int src;
8927 t0 = newTemp(Ity_I32);
8928 t1 = newTemp(Ity_I32);
8929 delta += 2+1;
8930 src = eregOfRM(modrm);
8931 assign( t0, binop( Iop_And32,
8932 binop(Iop_Shr32, getXMMRegLane32(src,1), mkU8(31)),
8933 mkU32(1) ));
8934 assign( t1, binop( Iop_And32,
8935 binop(Iop_Shr32, getXMMRegLane32(src,3), mkU8(30)),
8936 mkU32(2) ));
8937 putIReg(4, gregOfRM(modrm),
8938 binop(Iop_Or32, mkexpr(t0), mkexpr(t1))
8939 );
8940 DIP("movmskpd %s,%s\n", nameXMMReg(src),
8941 nameIReg(4, gregOfRM(modrm)));
8942 goto decode_success;
8943 }
8944 /* else fall through */
8945 }
8946
8947 /* 66 0F E7 = MOVNTDQ -- for us, just a plain SSE store. */
8948 if (insn[0] == 0x0F && insn[1] == 0xE7) {
8949 modrm = getIByte(delta+2);
8950 if (sz == 2 && !epartIsReg(modrm)) {
8951 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8952 storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) );
8953 DIP("movntdq %s,%s\n", dis_buf,
8954 nameXMMReg(gregOfRM(modrm)));
8955 delta += 2+alen;
8956 goto decode_success;
8957 }
8958 /* else fall through */
8959 }
8960
8961 /* 0F C3 = MOVNTI -- for us, just a plain ireg store. */
8962 if (insn[0] == 0x0F && insn[1] == 0xC3) {
8963 vassert(sz == 4);
8964 modrm = getIByte(delta+2);
8965 if (!epartIsReg(modrm)) {
8966 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8967 storeLE( mkexpr(addr), getIReg(4, gregOfRM(modrm)) );
8968 DIP("movnti %s,%s\n", dis_buf,
8969 nameIReg(4, gregOfRM(modrm)));
8970 delta += 2+alen;
8971 goto decode_success;
8972 }
8973 /* else fall through */
8974 }
8975
sewardj9ee82862004-12-14 01:16:59 +00008976 /* 66 0F D6 = MOVQ -- move 64 bits from E (mem or lo half xmm) to G
8977 (lo half xmm). */
8978 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD6) {
8979 modrm = getIByte(delta+2);
8980 if (epartIsReg(modrm)) {
8981 /* fall through, awaiting test case */
8982 } else {
8983 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8984 storeLE( mkexpr(addr),
8985 getXMMRegLane64( gregOfRM(modrm), 0 ));
8986 DIP("movq %s,%s\n", nameXMMReg(gregOfRM(modrm)), dis_buf );
8987 delta += 2+alen;
8988 goto decode_success;
8989 }
8990 }
8991
sewardjc2feffc2004-12-08 12:31:22 +00008992 /* F3 0F D6 = MOVQ2DQ -- move from E (mmx) to G (lo half xmm, zero
8993 hi half). */
8994 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0xD6) {
8995 vassert(sz == 4);
8996 modrm = getIByte(delta+3);
8997 if (epartIsReg(modrm)) {
8998 do_MMX_preamble();
8999 putXMMReg( gregOfRM(modrm),
9000 unop(Iop_64Uto128, getMMXReg( eregOfRM(modrm) )) );
9001 DIP("movq2dq %s,%s\n", nameMMXReg(eregOfRM(modrm)),
9002 nameXMMReg(gregOfRM(modrm)));
9003 delta += 3+1;
9004 goto decode_success;
9005 } else {
9006 /* fall through, apparently no mem case for this insn */
9007 }
9008 }
9009
9010 /* F2 0F 10 = MOVSD -- move 64 bits from E (mem or lo half xmm) to
9011 G (lo half xmm). If E is mem, upper half of G is zeroed out. */
9012 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x10) {
9013 vassert(sz == 4);
9014 modrm = getIByte(delta+3);
9015 if (epartIsReg(modrm)) {
9016 putXMMRegLane64( gregOfRM(modrm), 0,
9017 getXMMRegLane64( eregOfRM(modrm), 0 ));
9018 DIP("movsd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9019 nameXMMReg(gregOfRM(modrm)));
9020 delta += 3+1;
9021 } else {
9022 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
9023 putXMMReg( gregOfRM(modrm), mkV128(0) );
9024 putXMMRegLane64( gregOfRM(modrm), 0,
9025 loadLE(Ity_I64, mkexpr(addr)) );
9026 DIP("movsd %s,%s\n", dis_buf,
9027 nameXMMReg(gregOfRM(modrm)));
9028 delta += 3+alen;
9029 }
9030 goto decode_success;
9031 }
9032
9033 /* F2 0F 11 = MOVSD -- move 64 bits from G (lo half xmm) to E (mem
9034 or lo half xmm). */
9035 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x11) {
9036 vassert(sz == 4);
9037 modrm = getIByte(delta+3);
9038 if (epartIsReg(modrm)) {
9039 /* fall through, we don't yet have a test case */
9040 } else {
9041 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
9042 storeLE( mkexpr(addr),
sewardj519d66f2004-12-15 11:57:58 +00009043 getXMMRegLane64(gregOfRM(modrm), 0) );
9044 DIP("movsd %s,%s\n", nameXMMReg(gregOfRM(modrm)),
sewardjc2feffc2004-12-08 12:31:22 +00009045 dis_buf);
9046 delta += 3+alen;
9047 goto decode_success;
9048 }
9049 }
sewardjfd226452004-12-07 19:02:18 +00009050
sewardj008754b2004-12-08 14:37:10 +00009051 /* 66 0F 59 = MULPD -- mul 64Fx2 from R/M to R */
9052 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x59) {
9053 delta = dis_SSE_E_to_G_all( sorb, delta+2, "mulpd", Iop_Mul64Fx2 );
9054 goto decode_success;
9055 }
9056
9057 /* F2 0F 59 = MULSD -- mul 64F0x2 from R/M to R */
9058 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x59) {
9059 vassert(sz == 4);
9060 delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "mulsd", Iop_Mul64F0x2 );
9061 goto decode_success;
9062 }
9063
9064 /* 66 0F 56 = ORPD -- G = G and E */
9065 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x56) {
9066 delta = dis_SSE_E_to_G_all( sorb, delta+2, "orpd", Iop_Or128 );
9067 goto decode_success;
9068 }
9069
9070 /* 66 0F C6 /r ib = SHUFPD -- shuffle packed F64s */
9071 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xC6) {
9072 Int select;
9073 IRTemp sV = newTemp(Ity_V128);
9074 IRTemp dV = newTemp(Ity_V128);
9075 IRTemp s1 = newTemp(Ity_I64);
9076 IRTemp s0 = newTemp(Ity_I64);
9077 IRTemp d1 = newTemp(Ity_I64);
9078 IRTemp d0 = newTemp(Ity_I64);
9079
9080 modrm = insn[2];
9081 assign( dV, getXMMReg(gregOfRM(modrm)) );
9082
9083 if (epartIsReg(modrm)) {
9084 assign( sV, getXMMReg(eregOfRM(modrm)) );
9085 select = (Int)insn[3];
9086 delta += 2+2;
9087 DIP("shufpd $%d,%s,%s\n", select,
9088 nameXMMReg(eregOfRM(modrm)),
9089 nameXMMReg(gregOfRM(modrm)));
9090 } else {
9091 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9092 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
9093 select = (Int)insn[2+alen];
9094 delta += 3+alen;
9095 DIP("shufpd $%d,%s,%s\n", select,
9096 dis_buf,
9097 nameXMMReg(gregOfRM(modrm)));
9098 }
9099
9100 assign( d1, unop(Iop_128HIto64, mkexpr(dV)) );
9101 assign( d0, unop(Iop_128to64, mkexpr(dV)) );
9102 assign( s1, unop(Iop_128HIto64, mkexpr(sV)) );
9103 assign( s0, unop(Iop_128to64, mkexpr(sV)) );
9104
9105# define SELD(n) mkexpr((n)==0 ? d0 : d1)
9106# define SELS(n) mkexpr((n)==0 ? s0 : s1)
9107
9108 putXMMReg(
9109 gregOfRM(modrm),
9110 binop(Iop_64HLto128, SELS((select>>1)&1), SELD((select>>0)&1) )
9111 );
9112
9113# undef SELD
9114# undef SELS
9115
9116 goto decode_success;
9117 }
9118
9119 /* 66 0F 51 = SQRTPD -- approx sqrt 64Fx2 from R/M to R */
9120 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x51) {
9121 delta = dis_SSE_E_to_G_unary_all( sorb, delta+2,
9122 "sqrtpd", Iop_Sqrt64Fx2 );
9123 goto decode_success;
9124 }
9125
9126 /* F2 0F 51 = SQRTSD -- approx sqrt 64F0x2 from R/M to R */
9127 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x51) {
9128 vassert(sz == 4);
9129 delta = dis_SSE_E_to_G_unary_lo64( sorb, delta+3,
9130 "sqrtsd", Iop_Sqrt64F0x2 );
9131 goto decode_success;
9132 }
9133
9134 /* 66 0F 5C = SUBPD -- sub 64Fx2 from R/M to R */
9135 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5C) {
9136 delta = dis_SSE_E_to_G_all( sorb, delta+2, "subpd", Iop_Sub64Fx2 );
9137 goto decode_success;
9138 }
9139
9140 /* F2 0F 5C = SUBSD -- sub 64F0x2 from R/M to R */
9141 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x5C) {
9142 vassert(sz == 4);
9143 delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "subsd", Iop_Sub64F0x2 );
9144 goto decode_success;
9145 }
9146
9147 /* 66 0F 15 = UNPCKHPD -- unpack and interleave high part F64s */
9148 /* 66 0F 14 = UNPCKLPD -- unpack and interleave low part F64s */
9149 /* These just appear to be special cases of SHUFPS */
9150 if (sz == 2 && insn[0] == 0x0F && (insn[1] == 0x15 || insn[1] == 0x14)) {
9151 IRTemp s1 = newTemp(Ity_I64);
9152 IRTemp s0 = newTemp(Ity_I64);
9153 IRTemp d1 = newTemp(Ity_I64);
9154 IRTemp d0 = newTemp(Ity_I64);
9155 IRTemp sV = newTemp(Ity_V128);
9156 IRTemp dV = newTemp(Ity_V128);
9157 Bool hi = insn[1] == 0x15;
9158
9159 modrm = insn[2];
9160 assign( dV, getXMMReg(gregOfRM(modrm)) );
9161
9162 if (epartIsReg(modrm)) {
9163 assign( sV, getXMMReg(eregOfRM(modrm)) );
9164 delta += 2+1;
9165 DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
9166 nameXMMReg(eregOfRM(modrm)),
9167 nameXMMReg(gregOfRM(modrm)));
9168 } else {
9169 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9170 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
9171 delta += 2+alen;
9172 DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
9173 dis_buf,
9174 nameXMMReg(gregOfRM(modrm)));
9175 }
9176
9177 assign( d1, unop(Iop_128HIto64, mkexpr(dV)) );
9178 assign( d0, unop(Iop_128to64, mkexpr(dV)) );
9179 assign( s1, unop(Iop_128HIto64, mkexpr(sV)) );
9180 assign( s0, unop(Iop_128to64, mkexpr(sV)) );
9181
9182 if (hi) {
9183 putXMMReg( gregOfRM(modrm),
9184 binop(Iop_64HLto128, mkexpr(s1), mkexpr(d1)) );
9185 } else {
9186 putXMMReg( gregOfRM(modrm),
9187 binop(Iop_64HLto128, mkexpr(s0), mkexpr(d0)) );
9188 }
9189
9190 goto decode_success;
9191 }
9192
9193 /* 66 0F 57 = XORPD -- G = G and E */
9194 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x57) {
9195 delta = dis_SSE_E_to_G_all( sorb, delta+2, "xorpd", Iop_Xor128 );
9196 goto decode_success;
9197 }
sewardj636ad762004-12-07 11:16:04 +00009198
sewardj164f9272004-12-09 00:39:32 +00009199 ///////////////////////////////////////////////////////////////////
9200
9201 /* 66 0F 6B = PACKSSDW */
9202 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x6B) {
9203 delta = dis_SSEint_E_to_G( sorb, delta+2,
9204 "packssdw", Iop_QNarrow32Sx4, True );
9205 goto decode_success;
9206 }
9207
9208 /* 66 0F 63 = PACKSSWB */
9209 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x63) {
9210 delta = dis_SSEint_E_to_G( sorb, delta+2,
9211 "packsswb", Iop_QNarrow16Sx8, True );
9212 goto decode_success;
9213 }
9214
9215 /* 66 0F 67 = PACKUSWB */
9216 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x67) {
9217 delta = dis_SSEint_E_to_G( sorb, delta+2,
9218 "packuswb", Iop_QNarrow16Ux8, True );
9219 goto decode_success;
9220 }
9221
9222 /* 66 0F FC = PADDB */
9223 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xFC) {
9224 delta = dis_SSEint_E_to_G( sorb, delta+2,
9225 "paddb", Iop_Add8x16, False );
9226 goto decode_success;
9227 }
9228
9229 /* 66 0F FE = PADDD */
9230 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xFE) {
9231 delta = dis_SSEint_E_to_G( sorb, delta+2,
9232 "paddd", Iop_Add32x4, False );
9233 goto decode_success;
9234 }
9235
9236 /* ***--- this is an MMX class insn introduced in SSE2 ---*** */
9237 /* 0F D4 = PADDQ -- add 64x1 */
9238 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xD4) {
9239 do_MMX_preamble();
9240 delta = dis_MMXop_regmem_to_reg (
9241 sorb, delta+2, insn[1], "paddq", False );
9242 goto decode_success;
9243 }
9244
9245 /* 66 0F D4 = PADDQ */
9246 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD4) {
9247 delta = dis_SSEint_E_to_G( sorb, delta+2,
9248 "paddq", Iop_Add64x2, False );
9249 goto decode_success;
9250 }
9251
9252 /* 66 0F FD = PADDW */
9253 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xFD) {
9254 delta = dis_SSEint_E_to_G( sorb, delta+2,
9255 "paddw", Iop_Add16x8, False );
9256 goto decode_success;
9257 }
9258
9259 /* 66 0F EC = PADDSB */
9260 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xEC) {
9261 delta = dis_SSEint_E_to_G( sorb, delta+2,
9262 "paddsb", Iop_QAdd8Sx16, False );
9263 goto decode_success;
9264 }
9265
9266 /* 66 0F ED = PADDSW */
9267 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xED) {
9268 delta = dis_SSEint_E_to_G( sorb, delta+2,
9269 "paddsw", Iop_QAdd16Sx8, False );
9270 goto decode_success;
9271 }
9272
9273 /* 66 0F DC = PADDUSB */
9274 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDC) {
9275 delta = dis_SSEint_E_to_G( sorb, delta+2,
9276 "paddusb", Iop_QAdd8Ux16, False );
9277 goto decode_success;
9278 }
9279
9280 /* 66 0F DD = PADDUSW */
9281 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDD) {
9282 delta = dis_SSEint_E_to_G( sorb, delta+2,
9283 "paddusw", Iop_QAdd16Ux8, False );
9284 goto decode_success;
9285 }
9286
9287 /* 66 0F DB = PAND */
9288 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDB) {
9289 delta = dis_SSE_E_to_G_all( sorb, delta+2, "pand", Iop_And128 );
9290 goto decode_success;
9291 }
9292
9293 /* 66 0F DF = PANDN */
9294 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDF) {
9295 delta = dis_SSE_E_to_G_all_invG( sorb, delta+2, "pandn", Iop_And128 );
9296 goto decode_success;
9297 }
9298
9299 /* 66 0F E0 = PAVGB */
9300 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE0) {
9301 delta = dis_SSEint_E_to_G( sorb, delta+2,
9302 "pavgb", Iop_Avg8Ux16, False );
9303 goto decode_success;
9304 }
9305
9306 /* 66 0F E3 = PAVGW */
9307 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE3) {
9308 delta = dis_SSEint_E_to_G( sorb, delta+2,
9309 "pavgw", Iop_Avg16Ux8, False );
9310 goto decode_success;
9311 }
9312
sewardje5854d62004-12-09 03:44:34 +00009313 /* 66 0F 74 = PCMPEQB */
9314 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x74) {
9315 delta = dis_SSEint_E_to_G( sorb, delta+2,
9316 "pcmpeqb", Iop_CmpEQ8x16, False );
9317 goto decode_success;
9318 }
9319
9320 /* 66 0F 76 = PCMPEQD */
9321 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x76) {
9322 delta = dis_SSEint_E_to_G( sorb, delta+2,
9323 "pcmpeqd", Iop_CmpEQ32x4, False );
9324 goto decode_success;
9325 }
9326
9327 /* 66 0F 75 = PCMPEQW */
9328 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x75) {
9329 delta = dis_SSEint_E_to_G( sorb, delta+2,
9330 "pcmpeqw", Iop_CmpEQ16x8, False );
9331 goto decode_success;
9332 }
9333
9334 /* 66 0F 64 = PCMPGTB */
9335 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x64) {
9336 delta = dis_SSEint_E_to_G( sorb, delta+2,
9337 "pcmpgtb", Iop_CmpGT8Sx16, False );
9338 goto decode_success;
9339 }
9340
9341 /* 66 0F 66 = PCMPGTD */
9342 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x66) {
9343 delta = dis_SSEint_E_to_G( sorb, delta+2,
9344 "pcmpgtd", Iop_CmpGT32Sx4, False );
9345 goto decode_success;
9346 }
9347
9348 /* 66 0F 65 = PCMPGTW */
9349 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x65) {
9350 delta = dis_SSEint_E_to_G( sorb, delta+2,
9351 "pcmpgtw", Iop_CmpGT16Sx8, False );
9352 goto decode_success;
9353 }
9354
9355 /* 66 0F C5 = PEXTRW -- extract 16-bit field from xmm(E) and put
9356 zero-extend of it in ireg(G). */
9357 if (insn[0] == 0x0F && insn[1] == 0xC5) {
9358 modrm = insn[2];
9359 if (sz == 2 && epartIsReg(modrm)) {
9360 t5 = newTemp(Ity_V128);
9361 t4 = newTemp(Ity_I16);
9362 assign(t5, getXMMReg(eregOfRM(modrm)));
9363 breakup128to32s( t5, &t3, &t2, &t1, &t0 );
9364 switch (insn[3] & 7) {
9365 case 0: assign(t4, unop(Iop_32to16, mkexpr(t0))); break;
9366 case 1: assign(t4, unop(Iop_32HIto16, mkexpr(t0))); break;
9367 case 2: assign(t4, unop(Iop_32to16, mkexpr(t1))); break;
9368 case 3: assign(t4, unop(Iop_32HIto16, mkexpr(t1))); break;
9369 case 4: assign(t4, unop(Iop_32to16, mkexpr(t2))); break;
9370 case 5: assign(t4, unop(Iop_32HIto16, mkexpr(t2))); break;
9371 case 6: assign(t4, unop(Iop_32to16, mkexpr(t3))); break;
9372 case 7: assign(t4, unop(Iop_32HIto16, mkexpr(t3))); break;
9373 default: vassert(0);
9374 }
9375 putIReg(4, gregOfRM(modrm), unop(Iop_16Uto32, mkexpr(t4)));
9376 DIP("pextrw $%d,%s,%s\n",
9377 (Int)insn[3], nameXMMReg(eregOfRM(modrm)),
9378 nameIReg(4,gregOfRM(modrm)));
9379 delta += 4;
9380 goto decode_success;
9381 }
9382 /* else fall through */
9383 }
9384
9385 /* 66 0F C4 = PINSRW -- get 16 bits from E(mem or low half ireg) and
9386 put it into the specified lane of xmm(G). */
9387 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xC4) {
9388 Int lane;
9389 t4 = newTemp(Ity_I16);
9390 modrm = insn[2];
9391
9392 if (epartIsReg(modrm)) {
9393 assign(t4, getIReg(2, eregOfRM(modrm)));
9394 lane = insn[3];
9395 delta += 2+2;
9396 DIP("pinsrw $%d,%s,%s\n", (Int)lane,
9397 nameIReg(2,eregOfRM(modrm)),
9398 nameXMMReg(gregOfRM(modrm)));
9399 } else {
9400 /* awaiting test case */
9401 goto decode_failure;
9402 }
9403
9404 putXMMRegLane16( gregOfRM(modrm), lane & 7, mkexpr(t4) );
9405 goto decode_success;
9406 }
9407
9408 /* 66 0F EE = PMAXSW -- 16x8 signed max */
9409 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xEE) {
9410 delta = dis_SSEint_E_to_G( sorb, delta+2,
9411 "pmaxsw", Iop_Max16Sx8, False );
9412 goto decode_success;
9413 }
9414
9415 /* 66 0F DE = PMAXUB -- 8x16 unsigned max */
9416 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDE) {
9417 delta = dis_SSEint_E_to_G( sorb, delta+2,
9418 "pmaxub", Iop_Max8Ux16, False );
9419 goto decode_success;
9420 }
9421
9422 /* 66 0F EA = PMINSW -- 16x8 signed min */
9423 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xEA) {
9424 delta = dis_SSEint_E_to_G( sorb, delta+2,
9425 "pminsw", Iop_Min16Sx8, False );
9426 goto decode_success;
9427 }
9428
9429 /* 66 0F DA = PMINUB -- 8x16 unsigned min */
9430 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDA) {
9431 delta = dis_SSEint_E_to_G( sorb, delta+2,
9432 "pminub", Iop_Min8Ux16, False );
9433 goto decode_success;
9434 }
9435
9436 /* 66 0F D7 = PMOVMSKB -- extract sign bits from each of 16 lanes in
9437 xmm(G), turn them into a byte, and put zero-extend of it in
9438 ireg(G). Doing this directly is just too cumbersome; give up
9439 therefore and call a helper. */
9440 /* UInt x86g_calculate_sse_pmovmskb ( ULong w64hi, ULong w64lo ); */
9441 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD7) {
9442 modrm = insn[2];
9443 if (epartIsReg(modrm)) {
9444 t0 = newTemp(Ity_I64);
9445 t1 = newTemp(Ity_I64);
9446 assign(t0, getXMMRegLane64(eregOfRM(modrm), 0));
9447 assign(t1, getXMMRegLane64(eregOfRM(modrm), 1));
9448 t5 = newTemp(Ity_I32);
9449 assign(t5, mkIRExprCCall(
9450 Ity_I32, 0/*regparms*/,
9451 "x86g_calculate_sse_pmovmskb",
9452 &x86g_calculate_sse_pmovmskb,
9453 mkIRExprVec_2( mkexpr(t0), mkexpr(t1) )));
9454 putIReg(4, gregOfRM(modrm), mkexpr(t5));
9455 DIP("pmovmskb %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9456 nameIReg(4,gregOfRM(modrm)));
9457 delta += 3;
9458 goto decode_success;
9459 }
9460 /* else fall through */
9461 }
9462
9463 /* 66 0F E4 = PMULHUW -- 16x8 hi-half of unsigned widening multiply */
9464 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE4) {
9465 delta = dis_SSEint_E_to_G( sorb, delta+2,
9466 "pmulhuw", Iop_MulHi16Ux8, False );
9467 goto decode_success;
9468 }
9469
9470 /* 66 0F E5 = PMULHW -- 16x8 hi-half of signed widening multiply */
9471 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE5) {
9472 delta = dis_SSEint_E_to_G( sorb, delta+2,
9473 "pmulhw", Iop_MulHi16Sx8, False );
9474 goto decode_success;
9475 }
9476
9477 /* 66 0F D5 = PMULHL -- 16x8 multiply */
9478 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD5) {
9479 delta = dis_SSEint_E_to_G( sorb, delta+2,
9480 "pmullw", Iop_Mul16x8, False );
9481 goto decode_success;
9482 }
9483
9484 /* ***--- this is an MMX class insn introduced in SSE2 ---*** */
9485 /* 0F F4 = PMULUDQ -- unsigned widening multiply of 32-lanes 0 x
9486 0 to form 64-bit result */
9487 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xF4) {
9488 IRTemp sV = newTemp(Ity_I64);
9489 IRTemp dV = newTemp(Ity_I64);
9490 t1 = newTemp(Ity_I32);
9491 t0 = newTemp(Ity_I32);
9492 modrm = insn[2];
9493
9494 do_MMX_preamble();
9495 assign( dV, getMMXReg(gregOfRM(modrm)) );
9496
9497 if (epartIsReg(modrm)) {
9498 assign( sV, getMMXReg(eregOfRM(modrm)) );
9499 delta += 2+1;
9500 DIP("pmuludq %s,%s\n", nameMMXReg(eregOfRM(modrm)),
9501 nameMMXReg(gregOfRM(modrm)));
9502 } else {
9503 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9504 assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
9505 delta += 2+alen;
9506 DIP("pmuludq %s,%s\n", dis_buf,
9507 nameMMXReg(gregOfRM(modrm)));
9508 }
9509
9510 assign( t0, unop(Iop_64to32, mkexpr(dV)) );
9511 assign( t1, unop(Iop_64to32, mkexpr(sV)) );
9512 putMMXReg( gregOfRM(modrm),
9513 binop( Iop_MullU32, mkexpr(t0), mkexpr(t1) ) );
9514 goto decode_success;
9515 }
9516
9517 /* 66 0F F4 = PMULUDQ -- unsigned widening multiply of 32-lanes 0 x
9518 0 to form lower 64-bit half and lanes 2 x 2 to form upper 64-bit
9519 half */
9520 /* This is a really poor translation -- could be improved if
9521 performance critical */
9522 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF4) {
9523 IRTemp sV, dV;
9524 IRTemp s3, s2, s1, s0, d3, d2, d1, d0;
9525 sV = newTemp(Ity_V128);
9526 dV = newTemp(Ity_V128);
9527 s3 = s2 = s1 = s0 = d3 = d2 = d1 = d0 = IRTemp_INVALID;
9528 t1 = newTemp(Ity_I64);
9529 t0 = newTemp(Ity_I64);
9530 modrm = insn[2];
9531 assign( dV, getXMMReg(gregOfRM(modrm)) );
9532
9533 if (epartIsReg(modrm)) {
9534 assign( sV, getXMMReg(eregOfRM(modrm)) );
9535 delta += 2+1;
9536 DIP("pmuludq %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9537 nameXMMReg(gregOfRM(modrm)));
9538 } else {
9539 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9540 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
9541 delta += 2+alen;
9542 DIP("pmuludq %s,%s\n", dis_buf,
9543 nameXMMReg(gregOfRM(modrm)));
9544 }
9545
9546 breakup128to32s( dV, &d3, &d2, &d1, &d0 );
9547 breakup128to32s( sV, &s3, &s2, &s1, &s0 );
9548
9549 assign( t0, binop( Iop_MullU32, mkexpr(d0), mkexpr(s0)) );
9550 putXMMRegLane64( gregOfRM(modrm), 0, mkexpr(t0) );
9551 assign( t1, binop( Iop_MullU32, mkexpr(d2), mkexpr(s2)) );
9552 putXMMRegLane64( gregOfRM(modrm), 1, mkexpr(t1) );
9553 goto decode_success;
9554 }
9555
9556 /* 66 0F EB = POR */
9557 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xEB) {
9558 delta = dis_SSE_E_to_G_all( sorb, delta+2, "por", Iop_Or128 );
9559 goto decode_success;
9560 }
9561
sewardjb9fa69b2004-12-09 23:25:14 +00009562 /* 66 0F 70 = PSHUFD -- rearrange 4x32 from E(xmm or mem) to G(xmm) */
9563 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x70) {
9564 Int order;
9565 IRTemp sV, dV, s3, s2, s1, s0;
9566 s3 = s2 = s1 = s0 = IRTemp_INVALID;
9567 sV = newTemp(Ity_V128);
9568 dV = newTemp(Ity_V128);
9569 modrm = insn[2];
9570 if (epartIsReg(modrm)) {
9571 assign( sV, getXMMReg(eregOfRM(modrm)) );
9572 order = (Int)insn[3];
9573 delta += 2+2;
9574 DIP("pshufd $%d,%s,%s\n", order,
9575 nameXMMReg(eregOfRM(modrm)),
9576 nameXMMReg(gregOfRM(modrm)));
9577 } else {
9578 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9579 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
9580 order = (Int)insn[2+alen];
9581 delta += 3+alen;
9582 DIP("pshufd $%d,%s,%s\n", order,
9583 dis_buf,
9584 nameXMMReg(gregOfRM(modrm)));
9585 }
9586 breakup128to32s( sV, &s3, &s2, &s1, &s0 );
9587
9588# define SEL(n) \
9589 ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
9590 assign(dV,
9591 mk128from32s( SEL((order>>6)&3), SEL((order>>4)&3),
9592 SEL((order>>2)&3), SEL((order>>0)&3) )
9593 );
9594 putXMMReg(gregOfRM(modrm), mkexpr(dV));
9595# undef SEL
9596 goto decode_success;
9597 }
9598
9599 /* F3 0F 70 = PSHUFHW -- rearrange upper half 4x16 from E(xmm or
9600 mem) to G(xmm), and copy lower half */
9601 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x70) {
9602 Int order;
9603 IRTemp sVhi, dVhi, sV, dV, s3, s2, s1, s0;
9604 s3 = s2 = s1 = s0 = IRTemp_INVALID;
9605 sV = newTemp(Ity_V128);
9606 dV = newTemp(Ity_V128);
9607 sVhi = newTemp(Ity_I64);
9608 dVhi = newTemp(Ity_I64);
9609 modrm = insn[3];
9610 if (epartIsReg(modrm)) {
9611 assign( sV, getXMMReg(eregOfRM(modrm)) );
9612 order = (Int)insn[4];
9613 delta += 4+1;
9614 DIP("pshufhw $%d,%s,%s\n", order,
9615 nameXMMReg(eregOfRM(modrm)),
9616 nameXMMReg(gregOfRM(modrm)));
9617 } else {
9618 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
9619 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
9620 order = (Int)insn[3+alen];
9621 delta += 4+alen;
9622 DIP("pshufhw $%d,%s,%s\n", order,
9623 dis_buf,
9624 nameXMMReg(gregOfRM(modrm)));
9625 }
9626 assign( sVhi, unop(Iop_128HIto64, mkexpr(sV)) );
9627 breakup64to16s( sVhi, &s3, &s2, &s1, &s0 );
9628
9629# define SEL(n) \
9630 ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
9631 assign(dVhi,
9632 mk64from16s( SEL((order>>6)&3), SEL((order>>4)&3),
9633 SEL((order>>2)&3), SEL((order>>0)&3) )
9634 );
9635 assign(dV, binop( Iop_64HLto128,
9636 mkexpr(dVhi),
9637 unop(Iop_128to64, mkexpr(sV))) );
9638 putXMMReg(gregOfRM(modrm), mkexpr(dV));
9639# undef SEL
9640 goto decode_success;
9641 }
9642
9643 /* F2 0F 70 = PSHUFLW -- rearrange lower half 4x16 from E(xmm or
9644 mem) to G(xmm), and copy upper half */
9645 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x70) {
9646 Int order;
9647 IRTemp sVlo, dVlo, sV, dV, s3, s2, s1, s0;
9648 s3 = s2 = s1 = s0 = IRTemp_INVALID;
9649 sV = newTemp(Ity_V128);
9650 dV = newTemp(Ity_V128);
9651 sVlo = newTemp(Ity_I64);
9652 dVlo = newTemp(Ity_I64);
9653 modrm = insn[3];
9654 if (epartIsReg(modrm)) {
9655 assign( sV, getXMMReg(eregOfRM(modrm)) );
9656 order = (Int)insn[4];
9657 delta += 4+1;
9658 DIP("pshuflw $%d,%s,%s\n", order,
9659 nameXMMReg(eregOfRM(modrm)),
9660 nameXMMReg(gregOfRM(modrm)));
9661 } else {
9662 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
9663 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
9664 order = (Int)insn[3+alen];
9665 delta += 4+alen;
9666 DIP("pshuflw $%d,%s,%s\n", order,
9667 dis_buf,
9668 nameXMMReg(gregOfRM(modrm)));
9669 }
9670 assign( sVlo, unop(Iop_128to64, mkexpr(sV)) );
9671 breakup64to16s( sVlo, &s3, &s2, &s1, &s0 );
9672
9673# define SEL(n) \
9674 ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
9675 assign(dVlo,
9676 mk64from16s( SEL((order>>6)&3), SEL((order>>4)&3),
9677 SEL((order>>2)&3), SEL((order>>0)&3) )
9678 );
9679 assign(dV, binop( Iop_64HLto128,
9680 unop(Iop_128HIto64, mkexpr(sV)),
9681 mkexpr(dVlo) ) );
9682 putXMMReg(gregOfRM(modrm), mkexpr(dV));
9683# undef SEL
9684 goto decode_success;
9685 }
9686
9687 /* 66 0F 72 /6 ib = PSLLD by immediate */
9688 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x72
9689 && epartIsReg(insn[2])
9690 && gregOfRM(insn[2]) == 6) {
9691 delta = dis_SSE_shiftE_imm( sorb, delta+2, "pslld", Iop_ShlN32x4 );
9692 goto decode_success;
9693 }
9694
9695 /* 66 0F F2 = PSLLD by E */
9696 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF2) {
9697 delta = dis_SSE_shiftG_byE( sorb, delta+2, "pslld", Iop_ShlN32x4 );
9698 goto decode_success;
9699 }
9700
9701#if 0
9702 /* 66 0F 73 /7 ib = PSLLDQ by immediate */
9703 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x73
9704 && epartIsReg(insn[2])
9705 && gregOfRM(insn[2]) == 7) {
9706 delta = dis_SSE_shiftE_imm( sorb, delta+2, "pslldq", Iop_ShlN64x2 );
9707 goto decode_success;
9708 }
9709#endif
9710
9711 /* 66 0F 73 /6 ib = PSLLQ by immediate */
9712 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x73
9713 && epartIsReg(insn[2])
9714 && gregOfRM(insn[2]) == 6) {
9715 delta = dis_SSE_shiftE_imm( sorb, delta+2, "psllq", Iop_ShlN64x2 );
9716 goto decode_success;
9717 }
9718
9719 /* 66 0F F3 = PSLLQ by E */
9720 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF3) {
9721 delta = dis_SSE_shiftG_byE( sorb, delta+2, "psllq", Iop_ShlN64x2 );
9722 goto decode_success;
9723 }
9724
9725 /* 66 0F 71 /6 ib = PSLLW by immediate */
9726 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x71
9727 && epartIsReg(insn[2])
9728 && gregOfRM(insn[2]) == 6) {
9729 delta = dis_SSE_shiftE_imm( sorb, delta+2, "psllw", Iop_ShlN16x8 );
9730 goto decode_success;
9731 }
9732
9733 /* 66 0F F1 = PSLLW by E */
9734 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF1) {
9735 delta = dis_SSE_shiftG_byE( sorb, delta+2, "psllw", Iop_ShlN16x8 );
9736 goto decode_success;
9737 }
9738
9739 /* 66 0F 72 /4 ib = PSRAD by immediate */
9740 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x72
9741 && epartIsReg(insn[2])
9742 && gregOfRM(insn[2]) == 4) {
9743 delta = dis_SSE_shiftE_imm( sorb, delta+2, "psrad", Iop_SarN32x4 );
9744 goto decode_success;
9745 }
9746
9747 /* 66 0F E2 = PSRAD by E */
9748 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE2) {
9749 delta = dis_SSE_shiftG_byE( sorb, delta+2, "psrad", Iop_SarN32x4 );
9750 goto decode_success;
9751 }
9752
9753 /* 66 0F 71 /4 ib = PSRAW by immediate */
9754 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x71
9755 && epartIsReg(insn[2])
9756 && gregOfRM(insn[2]) == 4) {
9757 delta = dis_SSE_shiftE_imm( sorb, delta+2, "psraw", Iop_SarN16x8 );
9758 goto decode_success;
9759 }
9760
9761 /* 66 0F E1 = PSRAW by E */
9762 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE1) {
9763 delta = dis_SSE_shiftG_byE( sorb, delta+2, "psraw", Iop_SarN16x8 );
9764 goto decode_success;
9765 }
9766
9767 /* 66 0F 72 /2 ib = PSRLD by immediate */
9768 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x72
9769 && epartIsReg(insn[2])
9770 && gregOfRM(insn[2]) == 2) {
9771 delta = dis_SSE_shiftE_imm( sorb, delta+2, "psrld", Iop_ShrN32x4 );
9772 goto decode_success;
9773 }
9774
9775 /* 66 0F D2 = PSRLD by E */
9776 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD2) {
9777 delta = dis_SSE_shiftG_byE( sorb, delta+2, "psrld", Iop_ShrN32x4 );
9778 goto decode_success;
9779 }
9780
sewardj9ee82862004-12-14 01:16:59 +00009781 /* 66 0F 73 /3 ib = PSRLDQ by immediate */
9782 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x73
9783 && epartIsReg(insn[2])
9784 && gregOfRM(insn[2]) == 3
9785 /* hack; only deal with specific shift amounts */
9786 && (insn[3] == 4 || insn[3] == 8)) {
9787 Int imm = (Int)insn[3];
9788 Int reg = eregOfRM(insn[2]);
9789 IRTemp sV = newTemp(Ity_V128);
9790 IRTemp dV = newTemp(Ity_V128);
9791 delta += 4;
9792 t5 = newTemp(Ity_I32);
9793 assign( t5, mkU32(0) );
9794 assign( sV, getXMMReg(reg) );
9795 breakup128to32s( sV, &t3, &t2, &t1, &t0 );
9796 switch (imm) {
9797 case 8: assign( dV, mk128from32s(t5,t5,t3,t2) ); break;
9798 case 4: assign( dV, mk128from32s(t5,t3,t2,t1) ); break;
9799 default: vassert(0); /* can't get here */
9800 }
9801 putXMMReg(reg, mkexpr(dV));
9802 DIP("psrldq $%d,%s\n", imm, nameXMMReg(reg));
9803 goto decode_success;
9804 }
9805
sewardjb9fa69b2004-12-09 23:25:14 +00009806 /* 66 0F 73 /2 ib = PSRLQ by immediate */
9807 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x73
9808 && epartIsReg(insn[2])
9809 && gregOfRM(insn[2]) == 2) {
9810 delta = dis_SSE_shiftE_imm( sorb, delta+2, "psrlq", Iop_ShrN64x2 );
9811 goto decode_success;
9812 }
9813
9814 /* 66 0F D3 = PSRLQ by E */
9815 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD3) {
9816 delta = dis_SSE_shiftG_byE( sorb, delta+2, "psrlq", Iop_ShrN64x2 );
9817 goto decode_success;
9818 }
9819
9820 /* 66 0F 71 /2 ib = PSRLW by immediate */
9821 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x71
9822 && epartIsReg(insn[2])
9823 && gregOfRM(insn[2]) == 2) {
9824 delta = dis_SSE_shiftE_imm( sorb, delta+2, "psrlw", Iop_ShrN16x8 );
9825 goto decode_success;
9826 }
9827
9828 /* 66 0F D1 = PSRLW by E */
9829 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD1) {
9830 delta = dis_SSE_shiftG_byE( sorb, delta+2, "psrlw", Iop_ShrN16x8 );
9831 goto decode_success;
9832 }
9833
9834 /* 66 0F F8 = PSUBB */
9835 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF8) {
9836 delta = dis_SSEint_E_to_G( sorb, delta+2,
9837 "psubb", Iop_Sub8x16, False );
9838 goto decode_success;
9839 }
9840
9841 /* 66 0F FA = PSUBD */
9842 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xFA) {
9843 delta = dis_SSEint_E_to_G( sorb, delta+2,
9844 "psubd", Iop_Sub32x4, False );
9845 goto decode_success;
9846 }
9847
9848 /* ***--- this is an MMX class insn introduced in SSE2 ---*** */
9849 /* 0F FB = PSUBQ -- sub 64x1 */
9850 if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xFB) {
9851 do_MMX_preamble();
9852 delta = dis_MMXop_regmem_to_reg (
9853 sorb, delta+2, insn[1], "psubq", False );
9854 goto decode_success;
9855 }
9856
9857 /* 66 0F FB = PSUBQ */
9858 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xFB) {
9859 delta = dis_SSEint_E_to_G( sorb, delta+2,
9860 "psubq", Iop_Sub64x2, False );
9861 goto decode_success;
9862 }
9863
9864 /* 66 0F F9 = PSUBW */
9865 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF9) {
9866 delta = dis_SSEint_E_to_G( sorb, delta+2,
9867 "psubw", Iop_Sub16x8, False );
9868 goto decode_success;
9869 }
9870
9871 /* 66 0F E8 = PSUBSB */
9872 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE8) {
9873 delta = dis_SSEint_E_to_G( sorb, delta+2,
9874 "psubsb", Iop_QSub8Sx16, False );
9875 goto decode_success;
9876 }
9877
9878 /* 66 0F E9 = PSUBSW */
9879 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE9) {
9880 delta = dis_SSEint_E_to_G( sorb, delta+2,
9881 "psubsw", Iop_QSub16Sx8, False );
9882 goto decode_success;
9883 }
9884
9885 /* 66 0F D8 = PSUBSB */
9886 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD8) {
9887 delta = dis_SSEint_E_to_G( sorb, delta+2,
9888 "psubusb", Iop_QSub8Ux16, False );
9889 goto decode_success;
9890 }
9891
9892 /* 66 0F D9 = PSUBSW */
9893 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD9) {
9894 delta = dis_SSEint_E_to_G( sorb, delta+2,
9895 "psubusw", Iop_QSub16Ux8, False );
9896 goto decode_success;
9897 }
9898
sewardj9e203592004-12-10 01:48:18 +00009899 /* 66 0F 68 = PUNPCKHBW */
9900 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x68) {
9901 delta = dis_SSEint_E_to_G( sorb, delta+2,
9902 "punpckhbw",
9903 Iop_InterleaveHI8x16, True );
9904 goto decode_success;
9905 }
9906
9907 /* 66 0F 6A = PUNPCKHDQ */
9908 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x6A) {
9909 delta = dis_SSEint_E_to_G( sorb, delta+2,
9910 "punpckhdq",
9911 Iop_InterleaveHI32x4, True );
9912 goto decode_success;
9913 }
9914
9915 /* 66 0F 6D = PUNPCKHQDQ */
9916 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x6D) {
9917 delta = dis_SSEint_E_to_G( sorb, delta+2,
9918 "punpckhqdq",
9919 Iop_InterleaveHI64x2, True );
9920 goto decode_success;
9921 }
9922
9923 /* 66 0F 69 = PUNPCKHWD */
9924 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x69) {
9925 delta = dis_SSEint_E_to_G( sorb, delta+2,
9926 "punpckhwd",
9927 Iop_InterleaveHI16x8, True );
9928 goto decode_success;
9929 }
9930
9931 /* 66 0F 60 = PUNPCKLBW */
9932 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x60) {
9933 delta = dis_SSEint_E_to_G( sorb, delta+2,
9934 "punpcklbw",
9935 Iop_InterleaveLO8x16, True );
9936 goto decode_success;
9937 }
9938
9939 /* 66 0F 62 = PUNPCKLDQ */
9940 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x62) {
9941 delta = dis_SSEint_E_to_G( sorb, delta+2,
9942 "punpckldq",
9943 Iop_InterleaveLO32x4, True );
9944 goto decode_success;
9945 }
9946
9947 /* 66 0F 6C = PUNPCKLQDQ */
9948 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x6C) {
9949 delta = dis_SSEint_E_to_G( sorb, delta+2,
9950 "punpcklqdq",
9951 Iop_InterleaveLO64x2, True );
9952 goto decode_success;
9953 }
9954
9955 /* 66 0F 61 = PUNPCKLWD */
9956 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x61) {
9957 delta = dis_SSEint_E_to_G( sorb, delta+2,
9958 "punpcklwd",
9959 Iop_InterleaveLO16x8, True );
9960 goto decode_success;
9961 }
9962
9963 /* 66 0F EF = PXOR */
9964 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xEF) {
9965 delta = dis_SSE_E_to_G_all( sorb, delta+2, "pxor", Iop_Xor128 );
9966 goto decode_success;
9967 }
9968
sewardj164f9272004-12-09 00:39:32 +00009969
sewardjc9a65702004-07-07 16:32:57 +00009970//--
9971//-- /* FXSAVE/FXRSTOR m32 -- load/store the FPU/MMX/SSE state. */
9972//-- if (insn[0] == 0x0F && insn[1] == 0xAE
9973//-- && (!epartIsReg(insn[2]))
9974//-- && (gregOfRM(insn[2]) == 1 || gregOfRM(insn[2]) == 0) ) {
9975//-- Bool store = gregOfRM(insn[2]) == 0;
9976//-- vg_assert(sz == 4);
9977//-- pair = disAMode ( cb, sorb, eip+2, dis_buf );
9978//-- t1 = LOW24(pair);
9979//-- eip += 2+HI8(pair);
9980//-- uInstr3(cb, store ? SSE2a_MemWr : SSE2a_MemRd, 512,
9981//-- Lit16, (((UShort)insn[0]) << 8) | (UShort)insn[1],
9982//-- Lit16, (UShort)insn[2],
9983//-- TempReg, t1 );
9984//-- DIP("fx%s %s\n", store ? "save" : "rstor", dis_buf );
9985//-- goto decode_success;
9986//-- }
9987//--
9988//-- /* STMXCSR/LDMXCSR m32 -- load/store the MXCSR register. */
9989//-- if (insn[0] == 0x0F && insn[1] == 0xAE
9990//-- && (!epartIsReg(insn[2]))
9991//-- && (gregOfRM(insn[2]) == 3 || gregOfRM(insn[2]) == 2) ) {
9992//-- Bool store = gregOfRM(insn[2]) == 3;
9993//-- vg_assert(sz == 4);
9994//-- pair = disAMode ( cb, sorb, eip+2, dis_buf );
9995//-- t1 = LOW24(pair);
9996//-- eip += 2+HI8(pair);
9997//-- uInstr3(cb, store ? SSE2a_MemWr : SSE2a_MemRd, 4,
9998//-- Lit16, (((UShort)insn[0]) << 8) | (UShort)insn[1],
9999//-- Lit16, (UShort)insn[2],
10000//-- TempReg, t1 );
10001//-- DIP("%smxcsr %s\n", store ? "st" : "ld", dis_buf );
10002//-- goto decode_success;
10003//-- }
10004//--
10005//-- /* LFENCE/MFENCE/SFENCE -- flush pending operations to memory */
10006//-- if (insn[0] == 0x0F && insn[1] == 0xAE
10007//-- && (epartIsReg(insn[2]))
10008//-- && (gregOfRM(insn[2]) >= 5 && gregOfRM(insn[2]) <= 7))
10009//-- {
10010//-- vg_assert(sz == 4);
10011//-- eip += 3;
10012//-- uInstr2(cb, SSE3, 0, /* ignore sz for internal ops */
10013//-- Lit16, (((UShort)0x0F) << 8) | (UShort)0xAE,
10014//-- Lit16, (UShort)insn[2] );
10015//-- DIP("sfence\n");
10016//-- goto decode_success;
10017//-- }
10018//--
10019//-- /* CLFLUSH -- flush cache line */
10020//-- if (insn[0] == 0x0F && insn[1] == 0xAE
10021//-- && (!epartIsReg(insn[2]))
10022//-- && (gregOfRM(insn[2]) == 7))
10023//-- {
10024//-- vg_assert(sz == 4);
10025//-- pair = disAMode ( cb, sorb, eip+2, dis_buf );
10026//-- t1 = LOW24(pair);
10027//-- eip += 2+HI8(pair);
10028//-- uInstr3(cb, SSE2a_MemRd, 0, /* ignore sz for internal ops */
10029//-- Lit16, (((UShort)0x0F) << 8) | (UShort)0xAE,
10030//-- Lit16, (UShort)insn[2],
10031//-- TempReg, t1 );
10032//-- DIP("clflush %s\n", dis_buf);
10033//-- goto decode_success;
10034//-- }
10035//--
10036//-- /* CVTPI2PS (0x0F,0x2A) -- mm/m64, xmm */
10037//-- /* CVTPI2PD (0x66,0x0F,0x2A) -- mm/m64, xmm */
10038//-- if (insn[0] == 0x0F && insn[1] == 0x2A) {
10039//-- if (sz == 4) {
10040//-- eip = dis_SSE2_from_MMX
10041//-- ( cb, sorb, eip+2, 8, "cvtpi2ps",
10042//-- insn[0], insn[1] );
10043//-- } else {
10044//-- eip = dis_SSE3_from_MMX
10045//-- ( cb, sorb, eip+2, 8, "cvtpi2pd",
10046//-- 0x66, insn[0], insn[1] );
10047//-- }
10048//-- goto decode_success;
10049//-- }
10050//--
10051//-- /* CVTTPS2PI (0x0F,0x2C) -- xmm/m64, mm */
10052//-- /* CVTPS2PI (0x0F,0x2D) -- xmm/m64, mm */
10053//-- /* CVTTPD2PI (0x66,0x0F,0x2C) -- xmm/m128, mm */
10054//-- /* CVTPD2PI (0x66,0x0F,0x2D) -- xmm/m128, mm */
10055//-- if (insn[0] == 0x0F
10056//-- && (insn[1] == 0x2C || insn[1] == 0x2D)) {
10057//-- if (sz == 4) {
10058//-- eip = dis_SSE2_to_MMX
10059//-- ( cb, sorb, eip+2, 8, "cvt{t}ps2pi",
10060//-- insn[0], insn[1] );
10061//-- } else {
10062//-- eip = dis_SSE3_to_MMX
10063//-- ( cb, sorb, eip+2, 16, "cvt{t}pd2pi",
10064//-- 0x66, insn[0], insn[1] );
10065//-- }
10066//-- goto decode_success;
10067//-- }
10068//--
10069//-- /* CVTTSD2SI (0xF2,0x0F,0x2C) -- convert a double-precision float
10070//-- value in memory or xmm reg to int and put it in an ireg.
10071//-- Truncate. */
10072//-- /* CVTTSS2SI (0xF3,0x0F,0x2C) -- convert a single-precision float
10073//-- value in memory or xmm reg to int and put it in an ireg.
10074//-- Truncate. */
10075//-- /* CVTSD2SI (0xF2,0x0F,0x2D) -- convert a double-precision float
10076//-- value in memory or xmm reg to int and put it in an ireg. Round
10077//-- as per MXCSR. */
10078//-- /* CVTSS2SI (0xF3,0x0F,0x2D) -- convert a single-precision float
10079//-- value in memory or xmm reg to int and put it in an ireg. Round
10080//-- as per MXCSR. */
10081//-- if ((insn[0] == 0xF2 || insn[0] == 0xF3)
10082//-- && insn[1] == 0x0F
10083//-- && (insn[2] == 0x2C || insn[2] == 0x2D)) {
10084//-- vg_assert(sz == 4);
10085//-- modrm = insn[3];
10086//-- if (epartIsReg(modrm)) {
10087//-- /* We're moving a value in an xmm reg to an ireg. */
10088//-- eip += 4;
sewardj5bd4d162004-11-10 13:02:48 +000010089//-- t1 = newTemp(cb);
sewardjc9a65702004-07-07 16:32:57 +000010090//-- /* sz is 4 for all 4 insns. */
10091//-- vg_assert(epartIsReg(modrm));
10092//-- uInstr3(cb, SSE3g_RegWr, 4,
10093//-- Lit16, (((UShort)insn[0]) << 8) | (UShort)insn[1],
10094//-- Lit16, (((UShort)insn[2]) << 8) | (UShort)modrm,
10095//-- TempReg, t1 );
10096//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, gregOfRM(modrm));
10097//-- DIP("cvt{t}s{s,d}2si %s, %s\n",
10098//-- nameXMMReg(eregOfRM(modrm)), nameIReg(4,gregOfRM(modrm)) );
10099//-- } else {
10100//-- /* So, we're reading memory and writing an ireg. This calls
10101//-- for the ultra-horrible SSE3ag_MemRd_RegWr uinstr. We
10102//-- can't do it in a roundabout route because it does some
10103//-- kind of conversion on the way, which we need to have
10104//-- happen too. So our only choice is to re-emit a suitably
10105//-- rehashed version of the instruction. */
sewardj5bd4d162004-11-10 13:02:48 +000010106//-- /* Destination ireg is GREG. Address goes as EREG as
10107//-- usual. */
sewardjc9a65702004-07-07 16:32:57 +000010108//-- t1 = newTemp(cb); /* t1 holds value on its way to ireg */
10109//-- pair = disAMode ( cb, sorb, eip+3, dis_buf );
10110//-- t2 = LOW24(pair); /* t2 holds addr */
10111//-- eip += 3+HI8(pair);
10112//-- uInstr2(cb, SSE3ag_MemRd_RegWr, insn[0]==0xF2 ? 8 : 4,
10113//-- TempReg, t2, /* address */
10114//-- TempReg, t1 /* dest */);
10115//-- uLiteral(cb , (((UInt)insn[0]) << 24)
10116//-- | (((UInt)insn[1]) << 16)
10117//-- | (((UInt)insn[2]) << 8)
10118//-- | ((UInt)modrm) );
10119//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, gregOfRM(modrm));
10120//-- DIP("cvt{t}s{s,d}2si %s, %s\n",
10121//-- dis_buf, nameIReg(4,gregOfRM(modrm)) );
10122//-- }
10123//-- goto decode_success;
10124//-- }
10125//--
10126//-- /* CVTSI2SS -- convert int reg, or int value in memory, to low 4
10127//-- bytes of XMM reg. */
10128//-- /* CVTSI2SD -- convert int reg, or int value in memory, to low 8
10129//-- bytes of XMM reg. */
10130//-- if ((insn[0] == 0xF3 /*CVTSI2SS*/ || insn[0] == 0xF2 /* CVTSI2SD*/)
10131//-- && insn[1] == 0x0F && insn[2] == 0x2A) {
10132//-- Char* s_or_d = insn[0]==0xF3 ? "s" : "d";
10133//-- vg_assert(sz == 4);
10134//-- modrm = insn[3];
10135//-- t1 = newTemp(cb);
10136//-- if (epartIsReg(modrm)) {
10137//-- uInstr2(cb, GET, 4, ArchReg, eregOfRM(modrm), TempReg, t1);
10138//-- vg_assert(epartIsReg(modrm));
10139//-- uInstr3(cb, SSE3e_RegRd, 4,
10140//-- Lit16, (((UShort)insn[0]) << 8) | (UShort)insn[1],
10141//-- Lit16, (((UShort)insn[2]) << 8) | (UShort)modrm,
10142//-- TempReg, t1 );
10143//-- eip += 4;
10144//-- DIP("cvtsi2s%s %s, %s\n", s_or_d,
10145//-- nameIReg(4,eregOfRM(modrm)), nameXMMReg(gregOfRM(modrm)));
10146//-- } else {
10147//-- pair = disAMode ( cb, sorb, eip+3, dis_buf );
10148//-- t2 = LOW24(pair);
10149//-- eip += 3+HI8(pair);
sewardj5bd4d162004-11-10 13:02:48 +000010150//-- uInstr3(cb, SSE3a_MemRd, 4,
sewardjc9a65702004-07-07 16:32:57 +000010151//-- Lit16, (((UShort)insn[0]) << 8) | (UShort)insn[1],
10152//-- Lit16, (((UShort)insn[2]) << 8) | (UShort)modrm,
10153//-- TempReg, t2 );
10154//-- DIP("cvtsi2s%s %s, %s\n",
10155//-- s_or_d, dis_buf, nameXMMReg(gregOfRM(modrm)));
10156//-- }
10157//-- goto decode_success;
10158//-- }
10159//--
10160//-- /* CVTPS2PD -- convert two packed floats to two packed doubles. */
10161//-- /* 0x66: CVTPD2PS -- convert two packed doubles to two packed floats. */
10162//-- if (insn[0] == 0x0F && insn[1] == 0x5A) {
10163//-- vg_assert(sz == 2 || sz == 4);
10164//-- if (sz == 4) {
10165//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 8, "cvtps2pd",
10166//-- insn[0], insn[1] );
10167//-- } else {
10168//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "cvtpd2ps",
10169//-- 0x66, insn[0], insn[1] );
10170//-- }
10171//-- goto decode_success;
10172//-- }
10173//--
10174//-- /* CVTSS2SD -- convert one single float to double. */
10175//-- if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5A) {
10176//-- vg_assert(sz == 4);
10177//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, 4, "cvtss2sd",
10178//-- insn[0], insn[1], insn[2] );
10179//-- goto decode_success;
10180//-- }
10181//--
10182//-- /* CVTSD2SS -- convert one single double. to float. */
10183//-- if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x5A) {
10184//-- vg_assert(sz == 4);
10185//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, 8, "cvtsd2ss",
10186//-- insn[0], insn[1], insn[2] );
10187//-- goto decode_success;
10188//-- }
10189//--
10190//-- /* CVTDQ2PS -- convert four ints to four packed floats. */
10191//-- /* 0x66: CVTPS2DQ -- convert four packed floats to four ints. */
10192//-- if (insn[0] == 0x0F && insn[1] == 0x5B) {
10193//-- vg_assert(sz == 2 || sz == 4);
10194//-- if (sz == 4) {
10195//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "cvtdq2ps",
10196//-- insn[0], insn[1] );
10197//-- } else {
10198//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "cvtps2dq",
10199//-- 0x66, insn[0], insn[1] );
10200//-- }
10201//-- goto decode_success;
10202//-- }
10203//--
10204//-- /* CVTPD2DQ -- convert two packed doubles to two ints. */
10205//-- if (sz == 2
10206//-- && insn[0] == 0x0F && insn[1] == 0xE6) {
10207//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 8, "cvtpd2dq",
10208//-- 0x66, insn[0], insn[1] );
10209//-- goto decode_success;
10210//-- }
10211//--
10212//-- /* CVTTPD2DQ -- convert two packed doubles to two ints with truncation. */
10213//-- if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0xE6) {
10214//-- vg_assert(sz == 4);
10215//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, 8, "cvttpd2dq",
10216//-- insn[0], insn[1], insn[2] );
10217//-- goto decode_success;
10218//-- }
10219//--
10220//-- /* CVTDQ2PD -- convert two ints to two packed doubles. */
10221//-- if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0xE6) {
10222//-- vg_assert(sz == 4);
10223//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, 8, "cvtdq2pd",
10224//-- insn[0], insn[1], insn[2] );
10225//-- goto decode_success;
10226//-- }
10227//--
10228//-- /* CVTTPS2DQ -- convert four packed floats to four ints with truncation. */
10229//-- if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5B) {
10230//-- vg_assert(sz == 4);
10231//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, 16, "cvttps2dq",
10232//-- insn[0], insn[1], insn[2] );
10233//-- goto decode_success;
10234//-- }
10235//--
10236//-- /* CMPSS -- compare scalar floats. */
10237//-- if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0xC2) {
10238//-- vg_assert(sz == 4);
10239//-- eip = dis_SSE3_reg_or_mem_Imm8 ( cb, sorb, eip+3, 8, "cmpss",
10240//-- insn[0], insn[1], insn[2] );
10241//-- goto decode_success;
10242//-- }
10243//--
10244//-- /* CMPSD -- compare scalar doubles. */
10245//-- if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0xC2) {
10246//-- vg_assert(sz == 4);
10247//-- eip = dis_SSE3_reg_or_mem_Imm8 ( cb, sorb, eip+3, 8, "cmpsd",
10248//-- insn[0], insn[1], insn[2] );
10249//-- goto decode_success;
10250//-- }
10251//--
10252//-- /* sz==4: CMPPS -- compare packed floats */
10253//-- /* sz==2: CMPPD -- compare packed doubles */
10254//-- if (insn[0] == 0x0F && insn[1] == 0xC2) {
10255//-- vg_assert(sz == 4 || sz == 2);
10256//-- if (sz == 4) {
10257//-- eip = dis_SSE2_reg_or_mem_Imm8 ( cb, sorb, eip+2, 16, "cmpps",
10258//-- insn[0], insn[1] );
10259//-- } else {
10260//-- eip = dis_SSE3_reg_or_mem_Imm8 ( cb, sorb, eip+2, 16, "cmppd",
10261//-- 0x66, insn[0], insn[1] );
10262//-- }
10263//-- goto decode_success;
10264//-- }
10265//--
10266//-- /* PSHUFD */
10267//-- if (sz == 2
10268//-- && insn[0] == 0x0F && insn[1] == 0x70) {
10269//-- eip = dis_SSE3_reg_or_mem_Imm8 ( cb, sorb, eip+2, 16,
10270//-- "pshufd",
10271//-- 0x66, insn[0], insn[1] );
10272//-- goto decode_success;
10273//-- }
10274//--
10275//-- /* PSHUFLW */
10276//-- if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x70) {
10277//-- eip = dis_SSE3_reg_or_mem_Imm8 ( cb, sorb, eip+3, 16,
10278//-- "pshuflw",
10279//-- insn[0], insn[1], insn[2] );
10280//-- goto decode_success;
10281//-- }
10282//--
10283//-- /* PSHUFHW */
10284//-- if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x70) {
10285//-- eip = dis_SSE3_reg_or_mem_Imm8 ( cb, sorb, eip+3, 16,
10286//-- "pshufhw",
10287//-- insn[0], insn[1], insn[2] );
10288//-- goto decode_success;
10289//-- }
10290//--
10291//-- /* SHUFPD */
10292//-- if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xC6) {
10293//-- eip = dis_SSE3_reg_or_mem_Imm8 ( cb, sorb, eip+2, 16, "shufpd",
10294//-- 0x66, insn[0], insn[1] );
10295//-- goto decode_success;
10296//-- }
10297//--
10298//-- /* SHUFPS */
10299//-- if (insn[0] == 0x0F && insn[1] == 0xC6) {
10300//-- vg_assert(sz == 4);
10301//-- eip = dis_SSE2_reg_or_mem_Imm8 ( cb, sorb, eip+2, 16, "shufps",
10302//-- insn[0], insn[1] );
10303//-- goto decode_success;
10304//-- }
10305//--
10306//-- /* 0xF2: MULSD */
10307//-- /* 0xF3: MULSS -- multiply low 4 bytes of XMM reg. */
10308//-- if ((insn[0] == 0xF2 || insn[0] == 0xF3)
10309//-- && insn[1] == 0x0F && insn[2] == 0x59) {
10310//-- Bool sz8 = insn[0] == 0xF2;
10311//-- vg_assert(sz == 4);
10312//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, sz8 ? 8 : 4,
10313//-- sz8 ? "mulss" : "mulsd",
10314//-- insn[0], insn[1], insn[2] );
10315//-- goto decode_success;
10316//-- }
10317//--
10318//-- /* MULPS */
10319//-- /* 0x66: MULPD */
10320//-- if (insn[0] == 0x0F && insn[1] == 0x59) {
10321//-- vg_assert(sz == 4 || sz == 2);
10322//-- if (sz == 4) {
10323//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "mulps",
10324//-- insn[0], insn[1] );
10325//-- } else {
10326//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "mulpd",
10327//-- 0x66, insn[0], insn[1] );
10328//-- }
10329//-- goto decode_success;
10330//-- }
10331//--
10332//-- /* 0xF2: DIVSD */
10333//-- /* 0xF3: DIVSS -- divide low 4 bytes of XMM reg. */
10334//-- if ((insn[0] == 0xF2 || insn[0] == 0xF3)
10335//-- && insn[1] == 0x0F && insn[2] == 0x5E) {
10336//-- Bool sz8 = insn[0] == 0xF2;
10337//-- vg_assert(sz == 4);
10338//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, sz8 ? 8 : 4,
10339//-- sz8 ? "divsd" : "divss",
10340//-- insn[0], insn[1], insn[2] );
10341//-- goto decode_success;
10342//-- }
10343//--
10344//-- /* DIVPS */
10345//-- /* 0x66: DIVPD */
10346//-- if (insn[0] == 0x0F && insn[1] == 0x5E) {
10347//-- vg_assert(sz == 4 || sz == 2);
10348//-- if (sz == 4) {
10349//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "divps",
10350//-- insn[0], insn[1] );
10351//-- } else {
10352//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "divpd",
10353//-- 0x66, insn[0], insn[1] );
10354//-- }
10355//-- goto decode_success;
10356//-- }
10357//--
10358//-- /* 0xF2: SUBSD */
10359//-- /* 0xF3: SUBSS */
10360//-- if ((insn[0] == 0xF2 || insn[0] == 0xF3)
10361//-- && insn[1] == 0x0F && insn[2] == 0x5C) {
10362//-- Bool sz8 = insn[0] == 0xF2;
10363//-- vg_assert(sz == 4);
10364//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, sz8 ? 8 : 4,
10365//-- sz8 ? "subsd" : "subss",
10366//-- insn[0], insn[1], insn[2] );
10367//-- goto decode_success;
10368//-- }
10369//--
10370//-- /* SUBPS */
10371//-- /* 0x66: SUBPD */
10372//-- if (insn[0] == 0x0F && insn[1] == 0x5C) {
10373//-- vg_assert(sz == 4 || sz == 2);
10374//-- if (sz == 4) {
10375//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "subps",
10376//-- insn[0], insn[1] );
10377//-- } else {
10378//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "subpd",
10379//-- 0x66, insn[0], insn[1] );
10380//-- }
10381//-- goto decode_success;
10382//-- }
10383//--
10384//-- /* 0xF2: ADDSD */
10385//-- /* 0xF3: ADDSS */
10386//-- if ((insn[0] == 0xF2 || insn[0] == 0xF3)
10387//-- && insn[1] == 0x0F && insn[2] == 0x58) {
10388//-- Bool sz8 = insn[0] == 0xF2;
10389//-- vg_assert(sz == 4);
10390//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, sz8 ? 8 : 4,
10391//-- sz8 ? "addsd" : "addss",
10392//-- insn[0], insn[1], insn[2] );
10393//-- goto decode_success;
10394//-- }
10395//--
10396//-- /* ADDPS */
10397//-- /* 0x66: ADDPD */
10398//-- if (insn[0] == 0x0F && insn[1] == 0x58) {
10399//-- vg_assert(sz == 4 || sz == 2);
10400//-- if (sz == 4) {
10401//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "addps",
10402//-- insn[0], insn[1] );
10403//-- } else {
10404//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "addpd",
10405//-- 0x66, insn[0], insn[1] );
10406//-- }
10407//-- goto decode_success;
10408//-- }
10409//--
10410//-- /* 0xF2: MINSD */
10411//-- /* 0xF3: MINSS */
10412//-- if ((insn[0] == 0xF2 || insn[0] == 0xF3)
10413//-- && insn[1] == 0x0F && insn[2] == 0x5D) {
10414//-- Bool sz8 = insn[0] == 0xF2;
10415//-- vg_assert(sz == 4);
10416//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, sz8 ? 8 : 4,
10417//-- sz8 ? "minsd" : "minss",
10418//-- insn[0], insn[1], insn[2] );
10419//-- goto decode_success;
10420//-- }
10421//--
10422//-- /* MINPS */
10423//-- /* 0x66: MINPD */
10424//-- if (insn[0] == 0x0F && insn[1] == 0x5D) {
10425//-- vg_assert(sz == 4 || sz == 2);
10426//-- if (sz == 4) {
10427//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "minps",
10428//-- insn[0], insn[1] );
10429//-- } else {
10430//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "minpd",
10431//-- 0x66, insn[0], insn[1] );
10432//-- }
10433//-- goto decode_success;
10434//-- }
10435//--
10436//-- /* 0xF3: MAXSD */
10437//-- /* 0xF3: MAXSS */
10438//-- if ((insn[0] == 0xF2 || insn[0] == 0xF3)
10439//-- && insn[1] == 0x0F && insn[2] == 0x5F) {
10440//-- Bool sz8 = insn[0] == 0xF2;
10441//-- vg_assert(sz == 4);
10442//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, sz8 ? 8 : 4,
10443//-- sz8 ? "maxsd" : "maxss",
10444//-- insn[0], insn[1], insn[2] );
10445//-- goto decode_success;
10446//-- }
10447//--
10448//-- /* MAXPS */
10449//-- /* 0x66: MAXPD */
10450//-- if (insn[0] == 0x0F && insn[1] == 0x5F) {
10451//-- vg_assert(sz == 4 || sz == 2);
10452//-- if (sz == 4) {
10453//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "maxps",
10454//-- insn[0], insn[1] );
10455//-- } else {
10456//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "maxpd",
10457//-- 0x66, insn[0], insn[1] );
10458//-- }
10459//-- goto decode_success;
10460//-- }
10461//--
10462//-- /* RCPPS -- reciprocal of packed floats */
10463//-- if (insn[0] == 0x0F && insn[1] == 0x53) {
10464//-- vg_assert(sz == 4);
10465//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "rcpps",
10466//-- insn[0], insn[1] );
10467//-- goto decode_success;
10468//-- }
10469//--
10470//-- /* XORPS */
10471//-- /* 0x66: XORPD (src)xmmreg-or-mem, (dst)xmmreg */
10472//-- if (insn[0] == 0x0F && insn[1] == 0x57) {
10473//-- vg_assert(sz == 4 || sz == 2);
10474//-- if (sz == 4) {
10475//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "xorps",
10476//-- insn[0], insn[1] );
10477//-- } else {
10478//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "xorpd",
10479//-- 0x66, insn[0], insn[1] );
10480//-- }
10481//-- goto decode_success;
10482//-- }
10483//--
10484//-- /* ANDPS */
10485//-- /* 0x66: ANDPD (src)xmmreg-or-mem, (dst)xmmreg */
10486//-- if (insn[0] == 0x0F && insn[1] == 0x54) {
10487//-- vg_assert(sz == 4 || sz == 2);
10488//-- if (sz == 4) {
10489//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "andps",
10490//-- insn[0], insn[1] );
10491//-- } else {
10492//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "andpd",
10493//-- 0x66, insn[0], insn[1] );
10494//-- }
10495//-- goto decode_success;
10496//-- }
10497//--
10498//-- /* ORPS */
10499//-- /* 0x66: ORPD (src)xmmreg-or-mem, (dst)xmmreg */
10500//-- if (insn[0] == 0x0F && insn[1] == 0x56) {
10501//-- vg_assert(sz == 4 || sz == 2);
10502//-- if (sz == 4) {
10503//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "orps",
10504//-- insn[0], insn[1] );
10505//-- } else {
10506//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "orpd",
10507//-- 0x66, insn[0], insn[1] );
10508//-- }
10509//-- goto decode_success;
10510//-- }
10511//--
10512//-- /* PXOR (src)xmmreg-or-mem, (dst)xmmreg */
10513//-- if (sz == 2
10514//-- && insn[0] == 0x0F && insn[1] == 0xEF) {
10515//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pxor",
10516//-- 0x66, insn[0], insn[1] );
10517//-- goto decode_success;
10518//-- }
10519//--
10520//-- /* PAND (src)xmmreg-or-mem, (dst)xmmreg */
10521//-- if (sz == 2
10522//-- && insn[0] == 0x0F && insn[1] == 0xDB) {
10523//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pand",
10524//-- 0x66, insn[0], insn[1] );
10525//-- goto decode_success;
10526//-- }
10527//--
10528//-- /* PANDN (src)xmmreg-or-mem, (dst)xmmreg */
10529//-- if (sz == 2
10530//-- && insn[0] == 0x0F && insn[1] == 0xDF) {
10531//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pandn",
10532//-- 0x66, insn[0], insn[1] );
10533//-- goto decode_success;
10534//-- }
10535//--
10536//-- /* POR (src)xmmreg-or-mem, (dst)xmmreg */
10537//-- if (sz == 2
10538//-- && insn[0] == 0x0F && insn[1] == 0xEB) {
10539//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "por",
10540//-- 0x66, insn[0], insn[1] );
10541//-- goto decode_success;
10542//-- }
10543//--
10544//-- /* 0xDA: PMINUB(src)xmmreg-or-mem, (dst)xmmreg */
10545//-- /* 0xEA: PMINSW(src)xmmreg-or-mem, (dst)xmmreg */
10546//-- if (sz == 2
10547//-- && insn[0] == 0x0F
10548//-- && (insn[1] == 0xDA || insn[1] == 0xEA)) {
10549//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pmin{ub,sw}",
10550//-- 0x66, insn[0], insn[1] );
10551//-- goto decode_success;
10552//-- }
10553//--
10554//-- /* 0xDE: PMAXUB(src)xmmreg-or-mem, (dst)xmmreg */
10555//-- /* 0xEE: PMAXSW(src)xmmreg-or-mem, (dst)xmmreg */
10556//-- if (sz == 2
10557//-- && insn[0] == 0x0F
10558//-- && (insn[1] == 0xDE || insn[1] == 0xEE)) {
10559//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pmax{ub,sw}",
10560//-- 0x66, insn[0], insn[1] );
10561//-- goto decode_success;
10562//-- }
10563//--
10564//-- /* 0xE0: PAVGB(src)xmmreg-or-mem, (dst)xmmreg */
10565//-- /* 0xE3: PAVGW(src)xmmreg-or-mem, (dst)xmmreg */
10566//-- if (sz == 2
10567//-- && insn[0] == 0x0F
10568//-- && (insn[1] == 0xE0 || insn[1] == 0xE3)) {
10569//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pavg{b,w}",
10570//-- 0x66, insn[0], insn[1] );
10571//-- goto decode_success;
10572//-- }
10573//--
10574//-- /* 0xF6: PSADBW(src)xmmreg-or-mem, (dst)xmmreg */
10575//-- if (sz == 2
10576//-- && insn[0] == 0x0F && insn[1] == 0xF6) {
10577//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "psadbw",
10578//-- 0x66, insn[0], insn[1] );
10579//-- goto decode_success;
10580//-- }
10581//--
10582//-- /* 0x60: PUNPCKLBW (src)xmmreg-or-mem, (dst)xmmreg */
10583//-- /* 0x61: PUNPCKLWD (src)xmmreg-or-mem, (dst)xmmreg */
10584//-- /* 0x62: PUNPCKLDQ (src)xmmreg-or-mem, (dst)xmmreg */
10585//-- /* 0x6C: PUNPCKQLQDQ (src)xmmreg-or-mem, (dst)xmmreg */
10586//-- if (sz == 2
10587//-- && insn[0] == 0x0F
10588//-- && (insn[1] == 0x60 || insn[1] == 0x61
10589//-- || insn[1] == 0x62 || insn[1] == 0x6C)) {
10590//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16,
10591//-- "punpckl{bw,wd,dq,qdq}",
10592//-- 0x66, insn[0], insn[1] );
10593//-- goto decode_success;
10594//-- }
10595//--
10596//-- /* 0x68: PUNPCKHBW (src)xmmreg-or-mem, (dst)xmmreg */
10597//-- /* 0x69: PUNPCKHWD (src)xmmreg-or-mem, (dst)xmmreg */
10598//-- /* 0x6A: PUNPCKHDQ (src)xmmreg-or-mem, (dst)xmmreg */
10599//-- /* 0x6D: PUNPCKHQDQ (src)xmmreg-or-mem, (dst)xmmreg */
10600//-- if (sz == 2
10601//-- && insn[0] == 0x0F
10602//-- && (insn[1] == 0x68 || insn[1] == 0x69
10603//-- || insn[1] == 0x6A || insn[1] == 0x6D)) {
10604//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16,
10605//-- "punpckh{bw,wd,dq,qdq}",
10606//-- 0x66, insn[0], insn[1] );
10607//-- goto decode_success;
10608//-- }
10609//--
10610//-- /* 0x14: UNPCKLPD (src)xmmreg-or-mem, (dst)xmmreg. Reads a+0
10611//-- .. a+7, so we can say size 8 */
10612//-- /* 0x15: UNPCKHPD (src)xmmreg-or-mem, (dst)xmmreg. Reads a+8
10613//-- .. a+15, but we have no way to express this, so better say size
10614//-- 16. Sigh. */
10615//-- if (sz == 2
10616//-- && insn[0] == 0x0F
10617//-- && (insn[1] == 0x14 || insn[1] == 0x15)) {
10618//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2,
10619//-- insn[1]==0x14 ? 8 : 16,
10620//-- "unpck{l,h}pd",
10621//-- 0x66, insn[0], insn[1] );
10622//-- goto decode_success;
10623//-- }
10624//--
10625//-- /* 0x14: UNPCKLPS (src)xmmreg-or-mem, (dst)xmmreg Reads a+0
10626//-- .. a+7, so we can say size 8 */
10627//-- /* 0x15: UNPCKHPS (src)xmmreg-or-mem, (dst)xmmreg Reads a+8
10628//-- .. a+15, but we have no way to express this, so better say size
10629//-- 16. Sigh. */
10630//-- if (sz == 4
10631//-- && insn[0] == 0x0F
10632//-- && (insn[1] == 0x14 || insn[1] == 0x15)) {
10633//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2,
10634//-- insn[1]==0x14 ? 8 : 16,
10635//-- "unpck{l,h}ps",
10636//-- insn[0], insn[1] );
10637//-- goto decode_success;
10638//-- }
10639//--
10640//-- /* 0xFC: PADDB (src)xmmreg-or-mem, (dst)xmmreg */
10641//-- /* 0xFD: PADDW (src)xmmreg-or-mem, (dst)xmmreg */
10642//-- /* 0xFE: PADDD (src)xmmreg-or-mem, (dst)xmmreg */
10643//-- /* 0xD4: PADDQ (src)xmmreg-or-mem, (dst)xmmreg */
10644//-- if (sz == 2
10645//-- && insn[0] == 0x0F
10646//-- && (insn[1] == 0xFC || insn[1] == 0xFD
10647//-- || insn[1] == 0xFE || insn[1] == 0xD4)) {
10648//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "padd{b,w,d,q}",
10649//-- 0x66, insn[0], insn[1] );
10650//-- goto decode_success;
10651//-- }
10652//--
10653//-- /* 0xEC: PADDSB (src)xmmreg-or-mem, (dst)xmmreg */
10654//-- /* 0xED: PADDSW (src)xmmreg-or-mem, (dst)xmmreg */
10655//-- if (sz == 2
10656//-- && insn[0] == 0x0F
10657//-- && (insn[1] == 0xEC || insn[1] == 0xED)) {
10658//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "padds{b,w}",
10659//-- 0x66, insn[0], insn[1] );
10660//-- goto decode_success;
10661//-- }
10662//--
10663//-- /* 0xDC: PADDUSB (src)xmmreg-or-mem, (dst)xmmreg */
10664//-- /* 0xDD: PADDUSW (src)xmmreg-or-mem, (dst)xmmreg */
10665//-- if (sz == 2
10666//-- && insn[0] == 0x0F
10667//-- && (insn[1] == 0xDC || insn[1] == 0xDD)) {
10668//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "paddus{b,w}",
10669//-- 0x66, insn[0], insn[1] );
10670//-- goto decode_success;
10671//-- }
10672//--
10673//-- /* 0xF8: PSUBB (src)xmmreg-or-mem, (dst)xmmreg */
10674//-- /* 0xF9: PSUBW (src)xmmreg-or-mem, (dst)xmmreg */
10675//-- /* 0xFA: PSUBD (src)xmmreg-or-mem, (dst)xmmreg */
10676//-- /* 0xFB: PSUBQ (src)xmmreg-or-mem, (dst)xmmreg */
10677//-- if (sz == 2
10678//-- && insn[0] == 0x0F
10679//-- && (insn[1] == 0xF8 || insn[1] == 0xF9
10680//-- || insn[1] == 0xFA || insn[1] == 0xFB)) {
10681//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "psub{b,w,d,q}",
10682//-- 0x66, insn[0], insn[1] );
10683//-- goto decode_success;
10684//-- }
10685//--
10686//-- /* 0xE8: PSUBSB (src)xmmreg-or-mem, (dst)xmmreg */
10687//-- /* 0xE9: PSUBSW (src)xmmreg-or-mem, (dst)xmmreg */
10688//-- if (sz == 2
10689//-- && insn[0] == 0x0F
10690//-- && (insn[1] == 0xE8 || insn[1] == 0xE9)) {
10691//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "psubs{b,w}",
10692//-- 0x66, insn[0], insn[1] );
10693//-- goto decode_success;
10694//-- }
10695//--
10696//-- /* 0xD8: PSUBUSB (src)xmmreg-or-mem, (dst)xmmreg */
10697//-- /* 0xD9: PSUBUSW (src)xmmreg-or-mem, (dst)xmmreg */
10698//-- if (sz == 2
10699//-- && insn[0] == 0x0F
10700//-- && (insn[1] == 0xD8 || insn[1] == 0xD9)) {
10701//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "psubus{b,w}",
10702//-- 0x66, insn[0], insn[1] );
10703//-- goto decode_success;
10704//-- }
10705//--
10706//-- /* 0xE4: PMULHUW(src)xmmreg-or-mem, (dst)xmmreg */
10707//-- /* 0xE5: PMULHW(src)xmmreg-or-mem, (dst)xmmreg */
10708//-- /* 0xD5: PMULLW(src)xmmreg-or-mem, (dst)xmmreg */
10709//-- if (sz == 2
10710//-- && insn[0] == 0x0F
10711//-- && (insn[1] == 0xE4 || insn[1] == 0xE5 || insn[1] == 0xD5)) {
10712//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pmul{hu,h,l}w",
10713//-- 0x66, insn[0], insn[1] );
10714//-- goto decode_success;
10715//-- }
10716//--
10717//-- /* 0xD5: PMULUDQ(src)xmmreg-or-mem, (dst)xmmreg */
10718//-- if (sz == 2
10719//-- && insn[0] == 0x0F && insn[1] == 0xF4) {
10720//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pmuludq",
10721//-- 0x66, insn[0], insn[1] );
10722//-- goto decode_success;
10723//-- }
10724//--
10725//-- /* 0xF5: PMADDWD(src)xmmreg-or-mem, (dst)xmmreg */
10726//-- if (sz == 2
10727//-- && insn[0] == 0x0F
10728//-- && insn[1] == 0xF5) {
10729//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pmaddwd",
10730//-- 0x66, insn[0], insn[1] );
10731//-- goto decode_success;
10732//-- }
10733//--
10734//-- /* 0x74: PCMPEQB (src)xmmreg-or-mem, (dst)xmmreg */
10735//-- /* 0x75: PCMPEQW (src)xmmreg-or-mem, (dst)xmmreg */
10736//-- /* 0x76: PCMPEQD (src)xmmreg-or-mem, (dst)xmmreg */
10737//-- if (sz == 2
10738//-- && insn[0] == 0x0F
10739//-- && (insn[1] == 0x74 || insn[1] == 0x75 || insn[1] == 0x76)) {
10740//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pcmpeq{b,w,d}",
10741//-- 0x66, insn[0], insn[1] );
10742//-- goto decode_success;
10743//-- }
10744//--
10745//-- /* 0x64: PCMPGTB (src)xmmreg-or-mem, (dst)xmmreg */
10746//-- /* 0x65: PCMPGTW (src)xmmreg-or-mem, (dst)xmmreg */
10747//-- /* 0x66: PCMPGTD (src)xmmreg-or-mem, (dst)xmmreg */
10748//-- if (sz == 2
10749//-- && insn[0] == 0x0F
10750//-- && (insn[1] == 0x64 || insn[1] == 0x65 || insn[1] == 0x66)) {
10751//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pcmpgt{b,w,d}",
10752//-- 0x66, insn[0], insn[1] );
10753//-- goto decode_success;
10754//-- }
10755//--
10756//-- /* 0x63: PACKSSWB (src)xmmreg-or-mem, (dst)xmmreg */
10757//-- /* 0x6B: PACKSSDW (src)xmmreg-or-mem, (dst)xmmreg */
10758//-- if (sz == 2
10759//-- && insn[0] == 0x0F
10760//-- && (insn[1] == 0x63 || insn[1] == 0x6B)) {
10761//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "packss{wb,dw}",
10762//-- 0x66, insn[0], insn[1] );
10763//-- goto decode_success;
10764//-- }
10765//--
10766//-- /* 0x67: PACKUSWB (src)xmmreg-or-mem, (dst)xmmreg */
10767//-- if (sz == 2
10768//-- && insn[0] == 0x0F
10769//-- && insn[1] == 0x67) {
10770//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "packuswb",
10771//-- 0x66, insn[0], insn[1] );
10772//-- goto decode_success;
10773//-- }
10774//--
10775//-- /* 0xF1: PSLLW (src)xmmreg-or-mem, (dst)xmmreg */
10776//-- /* 0xF2: PSLLD (src)xmmreg-or-mem, (dst)xmmreg */
10777//-- /* 0xF3: PSLLQ (src)xmmreg-or-mem, (dst)xmmreg */
10778//-- if (sz == 2
10779//-- && insn[0] == 0x0F
10780//-- && (insn[1] == 0xF1 || insn[1] == 0xF2 || insn[1] == 0xF3)) {
10781//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "psll{b,w,d}",
10782//-- 0x66, insn[0], insn[1] );
10783//-- goto decode_success;
10784//-- }
10785//--
10786//-- /* 0xD1: PSRLW (src)xmmreg-or-mem, (dst)xmmreg */
10787//-- /* 0xD2: PSRLD (src)xmmreg-or-mem, (dst)xmmreg */
10788//-- /* 0xD3: PSRLQ (src)xmmreg-or-mem, (dst)xmmreg */
10789//-- if (sz == 2
10790//-- && insn[0] == 0x0F
10791//-- && (insn[1] == 0xD1 || insn[1] == 0xD2 || insn[1] == 0xD3)) {
10792//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "psrl{b,w,d}",
10793//-- 0x66, insn[0], insn[1] );
10794//-- goto decode_success;
10795//-- }
10796//--
10797//-- /* 0xE1: PSRAW (src)xmmreg-or-mem, (dst)xmmreg */
10798//-- /* 0xE2: PSRAD (src)xmmreg-or-mem, (dst)xmmreg */
10799//-- if (sz == 2
10800//-- && insn[0] == 0x0F
10801//-- && (insn[1] == 0xE1 || insn[1] == 0xE2)) {
10802//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "psra{w,d}",
10803//-- 0x66, insn[0], insn[1] );
10804//-- goto decode_success;
10805//-- }
10806//--
10807//-- /* (U)COMISD (src)xmmreg-or-mem, (dst)xmmreg */
10808//-- if (sz == 2
10809//-- && insn[0] == 0x0F
10810//-- && ( insn[1] == 0x2E || insn[1] == 0x2F ) ) {
10811//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 8, "{u}comisd",
10812//-- 0x66, insn[0], insn[1] );
10813//-- vg_assert(LAST_UINSTR(cb).opcode == SSE3a_MemRd
10814//-- || LAST_UINSTR(cb).opcode == SSE4);
10815//-- uFlagsRWU(cb, FlagsEmpty, FlagsOSZACP, FlagsEmpty);
10816//-- goto decode_success;
10817//-- }
10818//--
10819//-- /* (U)COMISS (src)xmmreg-or-mem, (dst)xmmreg */
10820//-- if (sz == 4
10821//-- && insn[0] == 0x0F
10822//-- && ( insn[1] == 0x2E || insn[ 1 ] == 0x2F )) {
10823//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 4, "{u}comiss",
10824//-- insn[0], insn[1] );
10825//-- vg_assert(LAST_UINSTR(cb).opcode == SSE2a_MemRd
10826//-- || LAST_UINSTR(cb).opcode == SSE3);
10827//-- uFlagsRWU(cb, FlagsEmpty, FlagsOSZACP, FlagsEmpty);
10828//-- goto decode_success;
10829//-- }
10830//--
10831//-- /* MOVSD -- move 8 bytes of XMM reg to/from XMM reg or mem. */
10832//-- if (insn[0] == 0xF2
10833//-- && insn[1] == 0x0F
10834//-- && (insn[2] == 0x11 || insn[2] == 0x10)) {
10835//-- vg_assert(sz == 4);
10836//-- eip = dis_SSE3_load_store_or_mov
10837//-- ( cb, sorb, eip+3, 8, insn[2]==0x11, "movsd",
sewardj5bd4d162004-11-10 13:02:48 +000010838//-- insn[0], insn[1], insn[2] );
sewardjc9a65702004-07-07 16:32:57 +000010839//-- goto decode_success;
10840//-- }
10841//--
10842//-- /* MOVQ -- move 8 bytes of XMM reg to XMM reg or mem. How
10843//-- does this differ from MOVSD ?? */
10844//-- if (sz == 2
10845//-- && insn[0] == 0x0F
10846//-- && insn[1] == 0xD6) {
10847//-- eip = dis_SSE3_load_store_or_mov
10848//-- ( cb, sorb, eip+2, 8, True /*store*/, "movq",
10849//-- 0x66, insn[0], insn[1] );
10850//-- goto decode_success;
10851//-- }
10852//--
10853//-- /* MOVQ -- move 8 bytes of XMM reg or mem to XMM reg. How
10854//-- does this differ from MOVSD ?? */
10855//-- if (insn[0] == 0xF3
10856//-- && insn[1] == 0x0F
10857//-- && insn[2] == 0x7E) {
10858//-- eip = dis_SSE3_load_store_or_mov
10859//-- ( cb, sorb, eip+3, 8, False /*load*/, "movq",
10860//-- insn[0], insn[1], insn[2] );
10861//-- goto decode_success;
10862//-- }
10863//--
10864//-- /* MOVDQ2Q -- move low 4 bytes of XMM reg to MMX reg. */
10865//-- if (insn[0] == 0xF2
10866//-- && insn[1] == 0x0F
10867//-- && insn[2] == 0xD6) {
10868//-- eip = dis_SSE3_to_MMX
10869//-- ( cb, sorb, eip+3, 8, "movdq2q",
10870//-- insn[0], insn[1], insn[2] );
10871//-- goto decode_success;
10872//-- }
10873//--
10874//-- /* MOVQ2DQ -- move MMX reg to low 4 bytes of XMM reg. */
10875//-- if (insn[0] == 0xF3
10876//-- && insn[1] == 0x0F
10877//-- && insn[2] == 0xD6) {
10878//-- eip = dis_SSE3_from_MMX
10879//-- ( cb, sorb, eip+3, 8, "movq2dq",
10880//-- insn[0], insn[1], insn[2] );
10881//-- goto decode_success;
10882//-- }
10883//--
10884//-- /* MOVSS -- move 4 bytes of XMM reg to/from XMM reg or mem. */
10885//-- if (insn[0] == 0xF3
10886//-- && insn[1] == 0x0F
10887//-- && (insn[2] == 0x11 || insn[2] == 0x10)) {
10888//-- vg_assert(sz == 4);
10889//-- eip = dis_SSE3_load_store_or_mov
10890//-- ( cb, sorb, eip+3, 4, insn[2]==0x11, "movss",
10891//-- insn[0], insn[1], insn[2] );
10892//-- goto decode_success;
10893//-- }
10894//--
10895//-- /* I don't understand how MOVAPD differs from MOVAPS. */
10896//-- /* MOVAPD (28,29) -- aligned load/store of xmm reg, or xmm-xmm reg
10897//-- move */
10898//-- if (sz == 2
10899//-- && insn[0] == 0x0F && insn[1] == 0x28) {
10900//-- UChar* name = "movapd";
10901//-- //(insn[1] == 0x10 || insn[1] == 0x11)
10902//-- // ? "movups" : "movaps";
10903//-- Bool store = False; //insn[1] == 0x29 || insn[1] == 11;
10904//-- eip = dis_SSE3_load_store_or_mov
10905//-- ( cb, sorb, eip+2, 16, store, name,
10906//-- 0x66, insn[0], insn[1] );
10907//-- goto decode_success;
10908//-- }
10909//--
10910//-- /* sz==4: MOVAPS (28,29) -- aligned load/store of xmm reg, or
10911//-- xmm-xmm reg move */
10912//-- /* sz==4: MOVUPS (10,11) -- unaligned load/store of xmm reg, or
10913//-- xmm-xmm reg move */
10914//-- /* sz==2: MOVAPD (28,29) -- aligned load/store of xmm reg, or
10915//-- xmm-xmm reg move */
10916//-- /* sz==2: MOVUPD (10,11) -- unaligned load/store of xmm reg, or
10917//-- xmm-xmm reg move */
10918//-- if (insn[0] == 0x0F && (insn[1] == 0x28
10919//-- || insn[1] == 0x29
10920//-- || insn[1] == 0x10
10921//-- || insn[1] == 0x11)) {
10922//-- UChar* name = (insn[1] == 0x10 || insn[1] == 0x11)
10923//-- ? "movups" : "movaps";
10924//-- Bool store = insn[1] == 0x29 || insn[1] == 11;
10925//-- vg_assert(sz == 2 || sz == 4);
10926//-- if (sz == 4) {
10927//-- eip = dis_SSE2_load_store_or_mov
10928//-- ( cb, sorb, eip+2, 16, store, name,
10929//-- insn[0], insn[1] );
10930//-- } else {
10931//-- eip = dis_SSE3_load_store_or_mov
10932//-- ( cb, sorb, eip+2, 16, store, name,
10933//-- 0x66, insn[0], insn[1] );
10934//-- }
10935//-- goto decode_success;
10936//-- }
10937//--
10938//-- /* MOVDQA -- aligned 16-byte load/store. */
10939//-- if (sz == 2
10940//-- && insn[0] == 0x0F
10941//-- && (insn[1] == 0x6F || insn[1] == 0x7F)) {
10942//-- Bool is_store = insn[1]==0x7F;
10943//-- eip = dis_SSE3_load_store_or_mov
10944//-- (cb, sorb, eip+2, 16, is_store, "movdqa",
10945//-- 0x66, insn[0], insn[1] );
10946//-- goto decode_success;
10947//-- }
10948//--
10949//-- /* MOVDQU -- unaligned 16-byte load/store. */
10950//-- if (insn[0] == 0xF3
10951//-- && insn[1] == 0x0F
10952//-- && (insn[2] == 0x6F || insn[2] == 0x7F)) {
10953//-- Bool is_store = insn[2]==0x7F;
10954//-- eip = dis_SSE3_load_store_or_mov
10955//-- (cb, sorb, eip+3, 16, is_store, "movdqu",
10956//-- insn[0], insn[1], insn[2] );
10957//-- goto decode_success;
10958//-- }
10959//--
10960//-- /* MOVNTDQ -- 16-byte store with temporal hint (which we
10961//-- ignore). */
10962//-- if (sz == 2
10963//-- && insn[0] == 0x0F
10964//-- && insn[1] == 0xE7) {
10965//-- eip = dis_SSE3_load_store_or_mov
10966//-- (cb, sorb, eip+2, 16, True /* is_store */, "movntdq",
10967//-- 0x66, insn[0], insn[1] );
10968//-- goto decode_success;
10969//-- }
10970//--
10971//-- /* MOVNTPS -- 16-byte store with temporal hint (which we
10972//-- ignore). */
10973//-- if (insn[0] == 0x0F
10974//-- && insn[1] == 0x2B) {
10975//-- eip = dis_SSE2_load_store_or_mov
10976//-- (cb, sorb, eip+2, 16, True /* is_store */, "movntps",
10977//-- insn[0], insn[1] );
10978//-- goto decode_success;
10979//-- }
10980//--
10981//-- /* MOVNTPD -- 16-byte store with temporal hint (which we
10982//-- ignore). */
10983//-- if (sz == 2
10984//-- && insn[0] == 0x0F
10985//-- && insn[1] == 0x2B) {
10986//-- eip = dis_SSE3_load_store_or_mov
10987//-- (cb, sorb, eip+2, 16, True /* is_store */, "movntpd",
10988//-- 0x66, insn[0], insn[1] );
10989//-- goto decode_success;
10990//-- }
10991//--
10992//-- /* MOVD -- 4-byte move between xmmregs and (ireg or memory). */
10993//-- if (sz == 2
10994//-- && insn[0] == 0x0F
10995//-- && (insn[1] == 0x6E || insn[1] == 0x7E)) {
10996//-- Bool is_store = insn[1]==0x7E;
10997//-- modrm = insn[2];
10998//-- if (epartIsReg(modrm) && is_store) {
10999//-- t1 = newTemp(cb);
11000//-- uInstr3(cb, SSE3e_RegWr, 4,
11001//-- Lit16, (((UShort)0x66) << 8) | (UShort)insn[0],
11002//-- Lit16, (((UShort)insn[1]) << 8) | (UShort)modrm,
11003//-- TempReg, t1 );
sewardj5bd4d162004-11-10 13:02:48 +000011004//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, eregOfRM(modrm));
11005//-- DIP("movd %s, %s\n",
sewardjc9a65702004-07-07 16:32:57 +000011006//-- nameXMMReg(gregOfRM(modrm)), nameIReg(4,eregOfRM(modrm)));
11007//-- eip += 3;
11008//-- } else
11009//-- if (epartIsReg(modrm) && !is_store) {
11010//-- t1 = newTemp(cb);
sewardj5bd4d162004-11-10 13:02:48 +000011011//-- uInstr2(cb, GET, 4, ArchReg, eregOfRM(modrm), TempReg, t1);
sewardjc9a65702004-07-07 16:32:57 +000011012//-- uInstr3(cb, SSE3e_RegRd, 4,
11013//-- Lit16, (((UShort)0x66) << 8) | (UShort)insn[0],
11014//-- Lit16, (((UShort)insn[1]) << 8) | (UShort)modrm,
11015//-- TempReg, t1 );
sewardj5bd4d162004-11-10 13:02:48 +000011016//-- DIP("movd %s, %s\n",
sewardjc9a65702004-07-07 16:32:57 +000011017//-- nameIReg(4,eregOfRM(modrm)), nameXMMReg(gregOfRM(modrm)));
11018//-- eip += 3;
11019//-- } else {
11020//-- eip = dis_SSE3_load_store_or_mov
11021//-- (cb, sorb, eip+2, 4, is_store, "movd",
11022//-- 0x66, insn[0], insn[1] );
11023//-- }
11024//-- goto decode_success;
11025//-- }
11026//--
11027//-- /* PEXTRW from SSE register; writes ireg */
11028//-- if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xC5) {
11029//-- t1 = newTemp(cb);
11030//-- modrm = insn[2];
11031//-- vg_assert(epartIsReg(modrm));
11032//-- vg_assert((modrm & 0xC0) == 0xC0);
11033//-- uInstr3(cb, SSE3g1_RegWr, 4,
11034//-- Lit16, (((UShort)0x66) << 8) | (UShort)insn[0],
11035//-- Lit16, (((UShort)insn[1]) << 8) | (UShort)modrm,
11036//-- TempReg, t1 );
11037//-- uLiteral(cb, insn[3]);
11038//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, gregOfRM(modrm));
11039//-- DIP("pextrw %s, %d, %s\n",
11040//-- nameXMMReg(eregOfRM(modrm)), (Int)insn[3],
11041//-- nameIReg(4, gregOfRM(modrm)));
11042//-- eip += 4;
11043//-- goto decode_success;
11044//-- }
11045//--
11046//-- /* PINSRW to SSE register; reads mem or ireg */
11047//-- if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xC4) {
11048//-- t1 = newTemp(cb);
11049//-- modrm = insn[2];
11050//-- if (epartIsReg(modrm)) {
11051//-- uInstr2(cb, GET, 2, ArchReg, eregOfRM(modrm), TempReg, t1);
11052//-- vg_assert(epartIsReg(modrm));
11053//-- uInstr3(cb, SSE3e1_RegRd, 2,
11054//-- Lit16, (((UShort)0x66) << 8) | (UShort)insn[0],
11055//-- Lit16, (((UShort)insn[1]) << 8) | (UShort)modrm,
11056//-- TempReg, t1 );
11057//-- uLiteral(cb, insn[3]);
11058//-- DIP("pinsrw %s, %d, %s\n",
11059//-- nameIReg(2, eregOfRM(modrm)), (Int)insn[3],
11060//-- nameXMMReg(gregOfRM(modrm)));
11061//-- eip += 4;
11062//-- } else {
sewardj5bd4d162004-11-10 13:02:48 +000011063//-- VG_(core_panic)("PINSRW mem");
sewardjc9a65702004-07-07 16:32:57 +000011064//-- }
11065//-- goto decode_success;
11066//-- }
11067//--
11068//-- /* SQRTSD: square root of scalar double. */
11069//-- if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x51) {
11070//-- vg_assert(sz == 4);
11071//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, 8,
11072//-- "sqrtsd",
11073//-- insn[0], insn[1], insn[2] );
11074//-- goto decode_success;
11075//-- }
11076//--
11077//-- /* SQRTSS: square root of scalar float. */
11078//-- if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x51) {
11079//-- vg_assert(sz == 4);
11080//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, 4,
11081//-- "sqrtss",
11082//-- insn[0], insn[1], insn[2] );
11083//-- goto decode_success;
11084//-- }
11085//--
11086//-- /* RSQRTSS: square root reciprocal of scalar float. */
11087//-- if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x52) {
11088//-- vg_assert(sz == 4);
11089//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, 4,
11090//-- "sqrtss",
11091//-- insn[0], insn[1], insn[2] );
11092//-- goto decode_success;
11093//-- }
11094//--
11095//-- /* 0xF3: RCPSS -- reciprocal of scalar float */
11096//-- if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x53) {
11097//-- vg_assert(sz == 4);
11098//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, 4,
11099//-- "rcpss",
11100//-- insn[0], insn[1], insn[2] );
11101//-- goto decode_success;
11102//-- }
11103//--
11104//-- /* MOVMSKPD -- extract 2 sign bits from a xmm reg and copy them to
11105//-- an ireg. Top 30 bits of ireg are set to zero. */
11106//-- /* MOVMSKPS -- extract 4 sign bits from a xmm reg and copy them to
11107//-- an ireg. Top 28 bits of ireg are set to zero. */
11108//-- if (insn[0] == 0x0F && insn[1] == 0x50) {
11109//-- vg_assert(sz == 4 || sz == 2);
11110//-- modrm = insn[2];
11111//-- /* Intel docs don't say anything about a memory source being
sewardj5bd4d162004-11-10 13:02:48 +000011112//-- allowed here. */
sewardjc9a65702004-07-07 16:32:57 +000011113//-- vg_assert(epartIsReg(modrm));
11114//-- t1 = newTemp(cb);
11115//-- if (sz == 4) {
11116//-- uInstr3(cb, SSE2g_RegWr, 4,
11117//-- Lit16, (((UShort)insn[0]) << 8) | (UShort)insn[1],
11118//-- Lit16, (UShort)modrm,
11119//-- TempReg, t1 );
11120//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, gregOfRM(modrm));
11121//-- } else {
11122//-- uInstr3(cb, SSE3g_RegWr, 4,
11123//-- Lit16, (((UShort)0x66) << 8) | (UShort)insn[0],
11124//-- Lit16, (((UShort)insn[1]) << 8) | (UShort)modrm,
11125//-- TempReg, t1 );
11126//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, gregOfRM(modrm));
11127//-- }
11128//-- DIP("movmskp%c %s, %s\n", sz == 4 ? 's' : 'd',
11129//-- nameXMMReg(eregOfRM(modrm)), nameIReg(4,gregOfRM(modrm)));
11130//-- eip += 3;
11131//-- goto decode_success;
11132//-- }
11133//--
11134//-- /* ANDNPS */
11135//-- /* 0x66: ANDNPD (src)xmmreg-or-mem, (dst)xmmreg */
11136//-- if (insn[0] == 0x0F && insn[1] == 0x55) {
11137//-- vg_assert(sz == 4 || sz == 2);
11138//-- if (sz == 4) {
11139//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "andnps",
11140//-- insn[0], insn[1] );
11141//-- } else {
11142//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "andnpd",
11143//-- 0x66, insn[0], insn[1] );
11144//-- }
11145//-- goto decode_success;
11146//-- }
11147//--
11148//-- /* MOVHLPS -- move two packed floats from high quadword to low quadword */
11149//-- /* MOVLPS -- load/store two packed floats to/from low quadword. */
11150//-- /* MOVLPD -- load/store packed double to/from low quadword. */
11151//-- if (insn[0] == 0x0F
11152//-- && (insn[1] == 0x12 || insn[1] == 0x13)) {
11153//-- Bool is_store = insn[1]==0x13;
11154//-- vg_assert(sz == 4 || sz == 2);
11155//-- if (sz == 4) {
11156//-- if (epartIsReg(insn[2])) {
11157//-- vg_assert(insn[1]==0x12);
11158//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "movhlps",
11159//-- insn[0], insn[1] );
11160//-- } else {
11161//-- eip = dis_SSE2_load_store_or_mov
11162//-- (cb, sorb, eip+2, 8, is_store, "movlps",
11163//-- insn[0], insn[1] );
11164//-- }
11165//-- } else {
11166//-- vg_assert(!epartIsReg(insn[2]));
11167//-- eip = dis_SSE3_load_store_or_mov
11168//-- (cb, sorb, eip+2, 8, is_store, "movlpd",
11169//-- 0x66, insn[0], insn[1] );
11170//-- }
11171//-- goto decode_success;
11172//-- }
11173//--
11174//-- /* MOVLHPS -- move two packed floats from low quadword to high quadword */
11175//-- /* MOVHPS -- load/store two packed floats to/from high quadword. */
11176//-- /* MOVHPD -- load/store packed double to/from high quadword. */
11177//-- if (insn[0] == 0x0F
11178//-- && (insn[1] == 0x16 || insn[1] == 0x17)) {
11179//-- Bool is_store = insn[1]==0x17;
11180//-- vg_assert(sz == 4 || sz == 2);
11181//-- if (sz == 4) {
11182//-- if (epartIsReg(insn[2])) {
11183//-- vg_assert(insn[1]==0x16);
11184//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "movlhps",
11185//-- insn[0], insn[1] );
11186//-- } else {
11187//-- eip = dis_SSE2_load_store_or_mov
11188//-- (cb, sorb, eip+2, 8, is_store, "movhps",
11189//-- insn[0], insn[1] );
11190//-- }
11191//-- } else {
11192//-- vg_assert(!epartIsReg(insn[2]));
11193//-- eip = dis_SSE3_load_store_or_mov
11194//-- (cb, sorb, eip+2, 8, is_store, "movhpd",
11195//-- 0x66, insn[0], insn[1] );
11196//-- }
11197//-- goto decode_success;
11198//-- }
11199//--
11200//-- /* PMOVMSKB -- extract 16 sign bits from a xmm reg and copy them to
11201//-- an ireg. Top 16 bits of ireg are set to zero. */
11202//-- if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD7) {
11203//-- modrm = insn[2];
11204//-- /* Intel docs don't say anything about a memory source being
sewardj5bd4d162004-11-10 13:02:48 +000011205//-- allowed here. */
sewardjc9a65702004-07-07 16:32:57 +000011206//-- vg_assert(epartIsReg(modrm));
11207//-- t1 = newTemp(cb);
11208//-- uInstr3(cb, SSE3g_RegWr, 4,
11209//-- Lit16, (((UShort)0x66) << 8) | (UShort)insn[0],
11210//-- Lit16, (((UShort)insn[1]) << 8) | (UShort)modrm,
11211//-- TempReg, t1 );
11212//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, gregOfRM(modrm));
11213//-- DIP("pmovmskb %s, %s\n",
11214//-- nameXMMReg(eregOfRM(modrm)), nameIReg(4,gregOfRM(modrm)));
11215//-- eip += 3;
11216//-- goto decode_success;
11217//-- }
11218//--
11219//-- /* sz==4: SQRTPS: square root of packed float. */
11220//-- /* sz==2: SQRTPD: square root of packed double. */
11221//-- if (insn[0] == 0x0F && insn[1] == 0x51) {
11222//-- vg_assert(sz == 2 || sz == 4);
11223//-- if (sz == 4) {
11224//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16,
11225//-- "sqrtps",
11226//-- insn[0], insn[1] );
11227//-- } else {
11228//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16,
11229//-- "sqrtpd",
11230//-- 0x66, insn[0], insn[1] );
11231//-- }
11232//-- goto decode_success;
11233//-- }
11234//--
11235//-- /* RSQRTPS: square root reciprocal of packed float. */
11236//-- if (insn[0] == 0x0F && insn[1] == 0x52) {
11237//-- vg_assert(sz == 4);
11238//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16,
11239//-- "rsqrtps",
11240//-- insn[0], insn[1] );
11241//-- goto decode_success;
11242//-- }
11243//--
11244//-- /* Fall through into the non-SSE decoder. */
11245//--
11246//-- } /* if (VG_(have_ssestate)) */
11247
11248
11249 /* ---------------------------------------------------- */
sewardjb5452082004-12-04 20:33:02 +000011250 /* --- end of the SSE decoder. --- */
sewardjc9a65702004-07-07 16:32:57 +000011251 /* ---------------------------------------------------- */
11252
11253 /* Get the primary opcode. */
11254 opc = getIByte(delta); delta++;
11255
11256 /* We get here if the current insn isn't SSE, or this CPU doesn't
11257 support SSE. */
11258
11259 switch (opc) {
11260
11261 /* ------------------------ Control flow --------------- */
sewardj940e8c92004-07-11 16:53:24 +000011262
11263 case 0xC2: /* RET imm16 */
11264 d32 = getUDisp16(delta);
11265 delta += 2;
11266 dis_ret(d32);
sewardjce70a5c2004-10-18 14:09:54 +000011267 whatNext = Dis_StopHere;
sewardj940e8c92004-07-11 16:53:24 +000011268 DIP("ret %d\n", d32);
11269 break;
sewardje05c42c2004-07-08 20:25:10 +000011270 case 0xC3: /* RET */
11271 dis_ret(0);
sewardjce70a5c2004-10-18 14:09:54 +000011272 whatNext = Dis_StopHere;
sewardje05c42c2004-07-08 20:25:10 +000011273 DIP("ret\n");
11274 break;
sewardjd1061ab2004-07-08 01:45:30 +000011275
11276 case 0xE8: /* CALL J4 */
11277 d32 = getUDisp32(delta); delta += 4;
sewardjce70a5c2004-10-18 14:09:54 +000011278 d32 += (guest_eip_bbstart+delta);
11279 /* (guest_eip_bbstart+delta) == return-to addr, d32 == call-to addr */
11280 if (d32 == guest_eip_bbstart+delta && getIByte(delta) >= 0x58
11281 && getIByte(delta) <= 0x5F) {
sewardjd1061ab2004-07-08 01:45:30 +000011282 /* Specially treat the position-independent-code idiom
11283 call X
11284 X: popl %reg
11285 as
11286 movl %eip, %reg.
11287 since this generates better code, but for no other reason. */
11288 Int archReg = getIByte(delta) - 0x58;
sewardjc2ac51e2004-07-12 01:03:26 +000011289 /* vex_printf("-- fPIC thingy\n"); */
sewardjce70a5c2004-10-18 14:09:54 +000011290 putIReg(4, archReg, mkU32(guest_eip_bbstart+delta));
sewardjd1061ab2004-07-08 01:45:30 +000011291 delta++; /* Step over the POP */
11292 DIP("call 0x%x ; popl %s\n",d32,nameIReg(4,archReg));
sewardjc2ac51e2004-07-12 01:03:26 +000011293 } else {
sewardjd1061ab2004-07-08 01:45:30 +000011294 /* The normal sequence for a call. */
11295 t1 = newTemp(Ity_I32);
sewardj41f43bc2004-07-08 14:23:22 +000011296 assign(t1, binop(Iop_Sub32, getIReg(4,R_ESP), mkU32(4)));
11297 putIReg(4, R_ESP, mkexpr(t1));
sewardj5bd4d162004-11-10 13:02:48 +000011298 storeLE( mkexpr(t1), mkU32(guest_eip_bbstart+delta));
11299 if (resteerOK && resteerOkFn((Addr64)(Addr32)d32)) {
sewardjce70a5c2004-10-18 14:09:54 +000011300 /* follow into the call target. */
11301 whatNext = Dis_Resteer;
11302 *whereNext = d32;
11303 } else {
11304 jmp_lit(Ijk_Call,d32);
11305 whatNext = Dis_StopHere;
11306 }
sewardjd1061ab2004-07-08 01:45:30 +000011307 DIP("call 0x%x\n",d32);
11308 }
11309 break;
11310
sewardjc9a65702004-07-07 16:32:57 +000011311//-- case 0xC8: /* ENTER */
11312//-- d32 = getUDisp16(eip); eip += 2;
11313//-- abyte = getIByte(delta); delta++;
11314//--
11315//-- vg_assert(sz == 4);
11316//-- vg_assert(abyte == 0);
11317//--
11318//-- t1 = newTemp(cb); t2 = newTemp(cb);
11319//-- uInstr2(cb, GET, sz, ArchReg, R_EBP, TempReg, t1);
11320//-- uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t2);
11321//-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
11322//-- uLiteral(cb, sz);
11323//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
11324//-- uInstr2(cb, STORE, 4, TempReg, t1, TempReg, t2);
11325//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_EBP);
11326//-- if (d32) {
11327//-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
sewardj5bd4d162004-11-10 13:02:48 +000011328//-- uLiteral(cb, d32);
11329//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
sewardjc9a65702004-07-07 16:32:57 +000011330//-- }
11331//-- DIP("enter 0x%x, 0x%x", d32, abyte);
11332//-- break;
sewardjc2ac51e2004-07-12 01:03:26 +000011333
11334 case 0xC9: /* LEAVE */
11335 vassert(sz == 4);
11336 t1 = newTemp(Ity_I32); t2 = newTemp(Ity_I32);
11337 assign(t1, getIReg(4,R_EBP));
11338 /* First PUT ESP looks redundant, but need it because ESP must
11339 always be up-to-date for Memcheck to work... */
11340 putIReg(4, R_ESP, mkexpr(t1));
11341 assign(t2, loadLE(Ity_I32,mkexpr(t1)));
11342 putIReg(4, R_EBP, mkexpr(t2));
11343 putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t1), mkU32(4)) );
11344 DIP("leave\n");
11345 break;
11346
sewardjc9a65702004-07-07 16:32:57 +000011347//-- /* ---------------- Misc weird-ass insns --------------- */
11348//--
11349//-- case 0x27: /* DAA */
11350//-- case 0x2F: /* DAS */
11351//-- t1 = newTemp(cb);
11352//-- uInstr2(cb, GET, 1, ArchReg, R_AL, TempReg, t1);
11353//-- /* Widen %AL to 32 bits, so it's all defined when we push it. */
11354//-- uInstr1(cb, WIDEN, 4, TempReg, t1);
11355//-- uWiden(cb, 1, False);
11356//-- uInstr0(cb, CALLM_S, 0);
11357//-- uInstr1(cb, PUSH, 4, TempReg, t1);
11358//-- uInstr1(cb, CALLM, 0, Lit16,
11359//-- opc == 0x27 ? VGOFF_(helper_DAA) : VGOFF_(helper_DAS) );
11360//-- uFlagsRWU(cb, FlagsAC, FlagsSZACP, FlagO);
11361//-- uInstr1(cb, POP, 4, TempReg, t1);
11362//-- uInstr0(cb, CALLM_E, 0);
11363//-- uInstr2(cb, PUT, 1, TempReg, t1, ArchReg, R_AL);
11364//-- DIP(opc == 0x27 ? "daa\n" : "das\n");
11365//-- break;
11366//--
11367//-- case 0x37: /* AAA */
11368//-- case 0x3F: /* AAS */
11369//-- t1 = newTemp(cb);
11370//-- uInstr2(cb, GET, 2, ArchReg, R_EAX, TempReg, t1);
11371//-- /* Widen %AL to 32 bits, so it's all defined when we push it. */
11372//-- uInstr1(cb, WIDEN, 4, TempReg, t1);
11373//-- uWiden(cb, 2, False);
11374//-- uInstr0(cb, CALLM_S, 0);
11375//-- uInstr1(cb, PUSH, 4, TempReg, t1);
11376//-- uInstr1(cb, CALLM, 0, Lit16,
11377//-- opc == 0x37 ? VGOFF_(helper_AAA) : VGOFF_(helper_AAS) );
11378//-- uFlagsRWU(cb, FlagA, FlagsAC, FlagsEmpty);
11379//-- uInstr1(cb, POP, 4, TempReg, t1);
11380//-- uInstr0(cb, CALLM_E, 0);
11381//-- uInstr2(cb, PUT, 2, TempReg, t1, ArchReg, R_EAX);
11382//-- DIP(opc == 0x37 ? "aaa\n" : "aas\n");
11383//-- break;
11384//--
11385//-- case 0xD4: /* AAM */
11386//-- case 0xD5: /* AAD */
11387//-- d32 = getIByte(delta); delta++;
11388//-- if (d32 != 10) VG_(core_panic)("disInstr: AAM/AAD but base not 10 !");
11389//-- t1 = newTemp(cb);
11390//-- uInstr2(cb, GET, 2, ArchReg, R_EAX, TempReg, t1);
11391//-- /* Widen %AX to 32 bits, so it's all defined when we push it. */
11392//-- uInstr1(cb, WIDEN, 4, TempReg, t1);
11393//-- uWiden(cb, 2, False);
11394//-- uInstr0(cb, CALLM_S, 0);
11395//-- uInstr1(cb, PUSH, 4, TempReg, t1);
11396//-- uInstr1(cb, CALLM, 0, Lit16,
11397//-- opc == 0xD4 ? VGOFF_(helper_AAM) : VGOFF_(helper_AAD) );
11398//-- uFlagsRWU(cb, FlagsEmpty, FlagsSZP, FlagsEmpty);
11399//-- uInstr1(cb, POP, 4, TempReg, t1);
11400//-- uInstr0(cb, CALLM_E, 0);
11401//-- uInstr2(cb, PUT, 2, TempReg, t1, ArchReg, R_EAX);
11402//-- DIP(opc == 0xD4 ? "aam\n" : "aad\n");
11403//-- break;
sewardj1c6f9912004-09-07 10:15:24 +000011404
11405 /* ------------------------ CWD/CDQ -------------------- */
11406
11407 case 0x98: /* CBW */
11408 if (sz == 4) {
11409 putIReg(4, R_EAX, unop(Iop_16Sto32, getIReg(2, R_EAX)));
11410 DIP("cwde\n");
11411 } else {
sewardj47341042004-09-19 11:55:46 +000011412 vassert(sz == 2);
11413 putIReg(2, R_EAX, unop(Iop_8Sto16, getIReg(1, R_EAX)));
11414 DIP("cbw\n");
sewardj1c6f9912004-09-07 10:15:24 +000011415 }
11416 break;
sewardj64e1d652004-07-12 14:00:46 +000011417
11418 case 0x99: /* CWD/CDQ */
11419 ty = szToITy(sz);
11420 putIReg(sz, R_EDX,
11421 binop(mkSizedOp(ty,Iop_Sar8),
11422 getIReg(sz, R_EAX),
sewardj9ee82862004-12-14 01:16:59 +000011423 mkU8(sz == 2 ? 15 : 31)) );
sewardj64e1d652004-07-12 14:00:46 +000011424 DIP(sz == 2 ? "cwdq\n" : "cdqq\n");
11425 break;
11426
sewardjbdc7d212004-09-09 02:46:40 +000011427 /* ------------------------ FPU ops -------------------- */
11428
11429 case 0x9E: /* SAHF */
11430 codegen_SAHF();
11431 DIP("sahf\n");
11432 break;
11433
sewardjc9a65702004-07-07 16:32:57 +000011434//-- case 0x9F: /* LAHF */
11435//-- codegen_LAHF ( cb );
11436//-- DIP("lahf\n");
11437//-- break;
11438//--
sewardjbdc7d212004-09-09 02:46:40 +000011439 case 0x9B: /* FWAIT */
11440 /* ignore? */
11441 DIP("fwait\n");
11442 break;
11443
sewardjd1725d12004-08-12 20:46:53 +000011444 case 0xD8:
11445 case 0xD9:
11446 case 0xDA:
11447 case 0xDB:
11448 case 0xDC:
11449 case 0xDD:
11450 case 0xDE:
11451 case 0xDF: {
11452 UInt delta0 = delta;
11453 Bool decode_OK = False;
11454 delta = dis_FPU ( &decode_OK, sorb, delta );
11455 if (!decode_OK) {
11456 delta = delta0;
11457 goto decode_failure;
11458 }
11459 break;
11460 }
sewardj0611d802004-07-11 02:37:54 +000011461
11462 /* ------------------------ INC & DEC ------------------ */
11463
11464 case 0x40: /* INC eAX */
11465 case 0x41: /* INC eCX */
11466 case 0x42: /* INC eDX */
11467 case 0x43: /* INC eBX */
11468 case 0x44: /* INC eSP */
11469 case 0x45: /* INC eBP */
11470 case 0x46: /* INC eSI */
11471 case 0x47: /* INC eDI */
11472 vassert(sz == 2 || sz == 4);
11473 ty = szToITy(sz);
11474 t1 = newTemp(ty);
11475 assign( t1, binop(mkSizedOp(ty,Iop_Add8),
11476 getIReg(sz, (UInt)(opc - 0x40)),
11477 mkU(ty,1)) );
11478 setFlags_INC_DEC( True, t1, ty );
11479 putIReg(sz, (UInt)(opc - 0x40), mkexpr(t1));
11480 DIP("inc%c %s\n", nameISize(sz), nameIReg(sz,opc-0x40));
11481 break;
11482
11483 case 0x48: /* DEC eAX */
11484 case 0x49: /* DEC eCX */
11485 case 0x4A: /* DEC eDX */
11486 case 0x4B: /* DEC eBX */
11487 case 0x4C: /* DEC eSP */
11488 case 0x4D: /* DEC eBP */
11489 case 0x4E: /* DEC eSI */
11490 case 0x4F: /* DEC eDI */
11491 vassert(sz == 2 || sz == 4);
11492 ty = szToITy(sz);
11493 t1 = newTemp(ty);
11494 assign( t1, binop(mkSizedOp(ty,Iop_Sub8),
11495 getIReg(sz, (UInt)(opc - 0x48)),
11496 mkU(ty,1)) );
11497 setFlags_INC_DEC( False, t1, ty );
11498 putIReg(sz, (UInt)(opc - 0x48), mkexpr(t1));
11499 DIP("dec%c %s\n", nameISize(sz), nameIReg(sz,opc-0x48));
11500 break;
11501
11502 /* ------------------------ INT ------------------------ */
11503
11504 case 0xCD: /* INT imm8 */
11505 d32 = getIByte(delta); delta++;
11506 if (d32 != 0x80) goto decode_failure;
11507 /* It's important that all ArchRegs carry their up-to-date value
11508 at this point. So we declare an end-of-block here, which
11509 forces any TempRegs caching ArchRegs to be flushed. */
sewardj4fd30f22004-10-25 00:42:16 +000011510 jmp_lit(Ijk_Syscall,((Addr32)guest_eip_bbstart)+delta);
sewardjce70a5c2004-10-18 14:09:54 +000011511 whatNext = Dis_StopHere;
sewardj0611d802004-07-11 02:37:54 +000011512 DIP("int $0x80\n");
11513 break;
11514
sewardj77b86be2004-07-11 13:28:24 +000011515 /* ------------------------ Jcond, byte offset --------- */
11516
11517 case 0xEB: /* Jb (jump, byte offset) */
sewardj4fd30f22004-10-25 00:42:16 +000011518 d32 = (((Addr32)guest_eip_bbstart)+delta+1) + getSDisp8(delta);
sewardj77b86be2004-07-11 13:28:24 +000011519 delta++;
sewardj5bd4d162004-11-10 13:02:48 +000011520 if (resteerOK && resteerOkFn((Addr64)(Addr32)d32)) {
sewardjce70a5c2004-10-18 14:09:54 +000011521 whatNext = Dis_Resteer;
11522 *whereNext = d32;
11523 } else {
11524 jmp_lit(Ijk_Boring,d32);
11525 whatNext = Dis_StopHere;
11526 }
sewardj77b86be2004-07-11 13:28:24 +000011527 DIP("jmp-8 0x%x\n", d32);
11528 break;
sewardj0611d802004-07-11 02:37:54 +000011529
11530 case 0xE9: /* Jv (jump, 16/32 offset) */
11531 vassert(sz == 4); /* JRS added 2004 July 11 */
sewardj4fd30f22004-10-25 00:42:16 +000011532 d32 = (((Addr32)guest_eip_bbstart)+delta+sz) + getSDisp(sz,delta);
sewardj0611d802004-07-11 02:37:54 +000011533 delta += sz;
sewardj5bd4d162004-11-10 13:02:48 +000011534 if (resteerOK && resteerOkFn((Addr64)(Addr32)d32)) {
sewardjce70a5c2004-10-18 14:09:54 +000011535 whatNext = Dis_Resteer;
11536 *whereNext = d32;
11537 } else {
11538 jmp_lit(Ijk_Boring,d32);
11539 whatNext = Dis_StopHere;
11540 }
sewardj0611d802004-07-11 02:37:54 +000011541 DIP("jmp 0x%x\n", d32);
11542 break;
sewardje87b4842004-07-10 12:23:30 +000011543
11544 case 0x70:
11545 case 0x71:
11546 case 0x72: /* JBb/JNAEb (jump below) */
11547 case 0x73: /* JNBb/JAEb (jump not below) */
11548 case 0x74: /* JZb/JEb (jump zero) */
11549 case 0x75: /* JNZb/JNEb (jump not zero) */
11550 case 0x76: /* JBEb/JNAb (jump below or equal) */
11551 case 0x77: /* JNBEb/JAb (jump not below or equal) */
11552 case 0x78: /* JSb (jump negative) */
11553 case 0x79: /* JSb (jump not negative) */
11554 case 0x7A: /* JP (jump parity even) */
11555 case 0x7B: /* JNP/JPO (jump parity odd) */
11556 case 0x7C: /* JLb/JNGEb (jump less) */
11557 case 0x7D: /* JGEb/JNLb (jump greater or equal) */
11558 case 0x7E: /* JLEb/JNGb (jump less or equal) */
11559 case 0x7F: /* JGb/JNLEb (jump greater) */
sewardj4fd30f22004-10-25 00:42:16 +000011560 d32 = (((Addr32)guest_eip_bbstart)+delta+1) + getSDisp8(delta);
sewardje87b4842004-07-10 12:23:30 +000011561 delta++;
sewardj2a9ad022004-11-25 02:46:58 +000011562 jcc_01((X86Condcode)(opc - 0x70), (Addr32)(guest_eip_bbstart+delta), d32);
sewardjce70a5c2004-10-18 14:09:54 +000011563 whatNext = Dis_StopHere;
sewardj2a9ad022004-11-25 02:46:58 +000011564 DIP("j%s-8 0x%x\n", name_X86Condcode(opc - 0x70), d32);
sewardje87b4842004-07-10 12:23:30 +000011565 break;
11566
sewardj458a6f82004-08-25 12:46:02 +000011567 case 0xE3: /* JECXZ or perhaps JCXZ, depending on OSO ? Intel
11568 manual says it depends on address size override,
11569 which doesn't sound right to me. */
11570 vassert(sz==4); /* possibly also OK for sz==2 */
sewardj4fd30f22004-10-25 00:42:16 +000011571 d32 = (((Addr32)guest_eip_bbstart)+delta+1) + getSDisp8(delta);
sewardj458a6f82004-08-25 12:46:02 +000011572 delta++;
11573 ty = szToITy(sz);
11574 stmt( IRStmt_Exit(
11575 binop(mkSizedOp(ty,Iop_CmpEQ8),
11576 getIReg(sz,R_ECX),
11577 mkU(ty,0)),
sewardj893aada2004-11-29 19:57:54 +000011578 Ijk_Boring,
sewardj458a6f82004-08-25 12:46:02 +000011579 IRConst_U32(d32))
11580 );
11581
11582 DIP("j%sz 0x%x\n", nameIReg(sz, R_ECX), d32);
11583 break;
11584
sewardjc9a65702004-07-07 16:32:57 +000011585//-- case 0xE0: /* LOOPNE disp8 */
11586//-- case 0xE1: /* LOOPE disp8 */
11587//-- case 0xE2: /* LOOP disp8 */
11588//-- /* Again, the docs say this uses ECX/CX as a count depending on
11589//-- the address size override, not the operand one. Since we
11590//-- don't handle address size overrides, I guess that means
11591//-- ECX. */
11592//-- d32 = (eip+1) + getSDisp8(eip); eip++;
11593//-- t1 = newTemp(cb);
11594//-- uInstr2(cb, GET, 4, ArchReg, R_ECX, TempReg, t1);
11595//-- uInstr1(cb, DEC, 4, TempReg, t1);
11596//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_ECX);
11597//-- uInstr2(cb, JIFZ, 4, TempReg, t1, Literal, 0);
11598//-- uLiteral(cb, eip);
11599//-- if (opc == 0xE0 || opc == 0xE1) { /* LOOPE/LOOPNE */
11600//-- jcc_lit(cb, eip, (opc == 0xE1 ? CondNZ : CondZ));
11601//-- }
11602//-- jmp_lit(cb, d32);
sewardjce70a5c2004-10-18 14:09:54 +000011603//-- whatNext = Dis_StopHere;
sewardjc9a65702004-07-07 16:32:57 +000011604//-- DIP("loop 0x%x\n", d32);
11605//-- break;
sewardj1813dbe2004-07-28 17:09:04 +000011606
11607 /* ------------------------ IMUL ----------------------- */
11608
11609 case 0x69: /* IMUL Iv, Ev, Gv */
11610 delta = dis_imul_I_E_G ( sorb, sz, delta, sz );
11611 break;
11612 case 0x6B: /* IMUL Ib, Ev, Gv */
11613 delta = dis_imul_I_E_G ( sorb, sz, delta, 1 );
11614 break;
sewardj0611d802004-07-11 02:37:54 +000011615
11616 /* ------------------------ MOV ------------------------ */
11617
11618 case 0x88: /* MOV Gb,Eb */
11619 delta = dis_mov_G_E(sorb, 1, delta);
11620 break;
sewardjc9a65702004-07-07 16:32:57 +000011621
11622 case 0x89: /* MOV Gv,Ev */
11623 delta = dis_mov_G_E(sorb, sz, delta);
11624 break;
11625
sewardjc2ac51e2004-07-12 01:03:26 +000011626 case 0x8A: /* MOV Eb,Gb */
11627 delta = dis_mov_E_G(sorb, 1, delta);
11628 break;
sewardje05c42c2004-07-08 20:25:10 +000011629
11630 case 0x8B: /* MOV Ev,Gv */
11631 delta = dis_mov_E_G(sorb, sz, delta);
11632 break;
11633
sewardje87b4842004-07-10 12:23:30 +000011634 case 0x8D: /* LEA M,Gv */
sewardje05c42c2004-07-08 20:25:10 +000011635 vassert(sz == 4);
11636 modrm = getIByte(delta);
11637 if (epartIsReg(modrm))
11638 vpanic("LEA M,Gv: modRM refers to register (x86)");
11639 /* NOTE! this is the one place where a segment override prefix
11640 has no effect on the address calculation. Therefore we pass
11641 zero instead of sorb here. */
sewardje87b4842004-07-10 12:23:30 +000011642 addr = disAMode ( &alen, /*sorb*/ 0, delta, dis_buf );
11643 delta += alen;
sewardj940e8c92004-07-11 16:53:24 +000011644 putIReg(sz, gregOfRM(modrm), mkexpr(addr));
sewardje05c42c2004-07-08 20:25:10 +000011645 DIP("lea%c %s, %s\n", nameISize(sz), dis_buf,
11646 nameIReg(sz,gregOfRM(modrm)));
11647 break;
sewardje05c42c2004-07-08 20:25:10 +000011648
sewardj063f02f2004-10-20 12:36:12 +000011649 case 0x8C: /* MOV Sw,Ew -- MOV from a SEGMENT REGISTER */
11650 delta = dis_mov_Sw_Ew(sorb, sz, delta);
11651 break;
11652
sewardj7df596b2004-12-06 14:29:12 +000011653 case 0x8E: /* MOV Ew,Sw -- MOV to a SEGMENT REGISTER */
11654 delta = dis_mov_Ew_Sw(sorb, delta);
11655 break;
11656
sewardj43852812004-10-16 23:10:08 +000011657 case 0xA0: /* MOV Ob,AL */
11658 sz = 1;
11659 /* Fall through ... */
sewardj0c12ea82004-07-12 08:18:16 +000011660 case 0xA1: /* MOV Ov,eAX */
11661 d32 = getUDisp32(delta); delta += 4;
11662 ty = szToITy(sz);
11663 addr = newTemp(Ity_I32);
11664 assign( addr, handleSegOverride(sorb, mkU32(d32)) );
11665 putIReg(sz, R_EAX, loadLE(ty, mkexpr(addr)));
11666 DIP("mov%c %s0x%x, %s\n", nameISize(sz), sorbTxt(sorb),
11667 d32, nameIReg(sz,R_EAX));
11668 break;
11669
sewardj180e8b32004-07-29 01:40:11 +000011670 case 0xA2: /* MOV Ob,AL */
11671 sz = 1;
11672 /* Fall through ... */
sewardj750f4072004-07-26 22:39:11 +000011673 case 0xA3: /* MOV eAX,Ov */
11674 d32 = getUDisp32(delta); delta += 4;
11675 ty = szToITy(sz);
11676 addr = newTemp(Ity_I32);
11677 assign( addr, handleSegOverride(sorb, mkU32(d32)) );
11678 storeLE( mkexpr(addr), getIReg(sz,R_EAX) );
11679 DIP("mov%c %s, %s0x%x\n", nameISize(sz), nameIReg(sz,R_EAX),
11680 sorbTxt(sorb), d32);
11681 break;
sewardje87b4842004-07-10 12:23:30 +000011682
sewardjc2ac51e2004-07-12 01:03:26 +000011683 case 0xB0: /* MOV imm,AL */
11684 case 0xB1: /* MOV imm,CL */
11685 case 0xB2: /* MOV imm,DL */
11686 case 0xB3: /* MOV imm,BL */
11687 case 0xB4: /* MOV imm,AH */
11688 case 0xB5: /* MOV imm,CH */
11689 case 0xB6: /* MOV imm,DH */
11690 case 0xB7: /* MOV imm,BH */
11691 d32 = getIByte(delta); delta += 1;
11692 putIReg(1, opc-0xB0, mkU8(d32));
11693 DIP("movb $0x%x,%s\n", d32, nameIReg(1,opc-0xB0));
11694 break;
sewardj7ed22952004-07-29 00:09:58 +000011695
sewardje87b4842004-07-10 12:23:30 +000011696 case 0xB8: /* MOV imm,eAX */
11697 case 0xB9: /* MOV imm,eCX */
11698 case 0xBA: /* MOV imm,eDX */
11699 case 0xBB: /* MOV imm,eBX */
11700 case 0xBC: /* MOV imm,eSP */
11701 case 0xBD: /* MOV imm,eBP */
11702 case 0xBE: /* MOV imm,eSI */
11703 case 0xBF: /* MOV imm,eDI */
11704 d32 = getUDisp(sz,delta); delta += sz;
11705 putIReg(sz, opc-0xB8, mkU(szToITy(sz), d32));
11706 DIP("mov%c $0x%x,%s\n", nameISize(sz), d32, nameIReg(sz,opc-0xB8));
11707 break;
11708
sewardj77b86be2004-07-11 13:28:24 +000011709 case 0xC6: /* MOV Ib,Eb */
11710 sz = 1;
11711 goto do_Mov_I_E;
sewardje87b4842004-07-10 12:23:30 +000011712 case 0xC7: /* MOV Iv,Ev */
11713 goto do_Mov_I_E;
11714
11715 do_Mov_I_E:
11716 modrm = getIByte(delta);
11717 if (epartIsReg(modrm)) {
11718 delta++; /* mod/rm byte */
11719 d32 = getUDisp(sz,delta); delta += sz;
sewardj5bd4d162004-11-10 13:02:48 +000011720 putIReg(sz, eregOfRM(modrm), mkU(szToITy(sz), d32));
sewardje87b4842004-07-10 12:23:30 +000011721 DIP("mov%c $0x%x, %s\n", nameISize(sz), d32,
11722 nameIReg(sz,eregOfRM(modrm)));
sewardj5bd4d162004-11-10 13:02:48 +000011723 vassert(0);
sewardje87b4842004-07-10 12:23:30 +000011724 } else {
11725 addr = disAMode ( &alen, sorb, delta, dis_buf );
11726 delta += alen;
11727 d32 = getUDisp(sz,delta); delta += sz;
sewardj5bd4d162004-11-10 13:02:48 +000011728 storeLE(mkexpr(addr), mkU(szToITy(sz), d32));
sewardje87b4842004-07-10 12:23:30 +000011729 DIP("mov%c $0x%x, %s\n", nameISize(sz), d32, dis_buf);
11730 }
11731 break;
11732
sewardj1813dbe2004-07-28 17:09:04 +000011733 /* ------------------------ opl imm, A ----------------- */
11734
11735 case 0x04: /* ADD Ib, AL */
11736 delta = dis_op_imm_A( 1, Iop_Add8, True, delta, "add" );
11737 break;
sewardj77b86be2004-07-11 13:28:24 +000011738 case 0x05: /* ADD Iv, eAX */
11739 delta = dis_op_imm_A(sz, Iop_Add8, True, delta, "add" );
11740 break;
11741
sewardj940e8c92004-07-11 16:53:24 +000011742 case 0x0C: /* OR Ib, AL */
11743 delta = dis_op_imm_A( 1, Iop_Or8, True, delta, "or" );
11744 break;
sewardj82292882004-07-27 00:15:59 +000011745 case 0x0D: /* OR Iv, eAX */
11746 delta = dis_op_imm_A( sz, Iop_Or8, True, delta, "or" );
11747 break;
11748
sewardjc9a65702004-07-07 16:32:57 +000011749//-- case 0x14: /* ADC Ib, AL */
sewardj77b86be2004-07-11 13:28:24 +000011750//-- delta = dis_op_imm_A( 1, ADC, True, delta, "adc" );
sewardjc9a65702004-07-07 16:32:57 +000011751//-- break;
11752//-- case 0x15: /* ADC Iv, eAX */
sewardj77b86be2004-07-11 13:28:24 +000011753//-- delta = dis_op_imm_A( sz, ADC, True, delta, "adc" );
sewardjc9a65702004-07-07 16:32:57 +000011754//-- break;
11755//--
11756//-- case 0x1C: /* SBB Ib, AL */
sewardj77b86be2004-07-11 13:28:24 +000011757//-- delta = dis_op_imm_A( 1, SBB, True, delta, "sbb" );
sewardjc9a65702004-07-07 16:32:57 +000011758//-- break;
11759//-- case 0x1D: /* SBB Iv, eAX */
sewardj77b86be2004-07-11 13:28:24 +000011760//-- delta = dis_op_imm_A( sz, SBB, True, delta, "sbb" );
sewardjc9a65702004-07-07 16:32:57 +000011761//-- break;
11762//--
sewardj940e8c92004-07-11 16:53:24 +000011763 case 0x24: /* AND Ib, AL */
11764 delta = dis_op_imm_A( 1, Iop_And8, True, delta, "and" );
11765 break;
sewardjc2ac51e2004-07-12 01:03:26 +000011766 case 0x25: /* AND Iv, eAX */
11767 delta = dis_op_imm_A( sz, Iop_And8, True, delta, "and" );
11768 break;
sewardj0611d802004-07-11 02:37:54 +000011769
11770 case 0x2C: /* SUB Ib, AL */
11771 delta = dis_op_imm_A(1, Iop_Sub8, True, delta, "sub" );
11772 break;
sewardj68511542004-07-28 00:15:44 +000011773 case 0x2D: /* SUB Iv, eAX */
11774 delta = dis_op_imm_A( sz, Iop_Sub8, True, delta, "sub" );
11775 break;
11776
sewardj1c6f9912004-09-07 10:15:24 +000011777 case 0x34: /* XOR Ib, AL */
11778 delta = dis_op_imm_A( 1, Iop_Xor8, True, delta, "xor" );
11779 break;
sewardjcaca9d02004-07-28 07:11:32 +000011780 case 0x35: /* XOR Iv, eAX */
11781 delta = dis_op_imm_A( sz, Iop_Xor8, True, delta, "xor" );
11782 break;
11783
sewardj0611d802004-07-11 02:37:54 +000011784 case 0x3C: /* CMP Ib, AL */
sewardj77b86be2004-07-11 13:28:24 +000011785 delta = dis_op_imm_A( 1, Iop_Sub8, False, delta, "cmp" );
sewardj0611d802004-07-11 02:37:54 +000011786 break;
11787 case 0x3D: /* CMP Iv, eAX */
sewardj77b86be2004-07-11 13:28:24 +000011788 delta = dis_op_imm_A( sz, Iop_Sub8, False, delta, "cmp" );
sewardj0611d802004-07-11 02:37:54 +000011789 break;
11790
sewardj77b86be2004-07-11 13:28:24 +000011791 case 0xA8: /* TEST Ib, AL */
11792 delta = dis_op_imm_A( 1, Iop_And8, False, delta, "test" );
11793 break;
sewardjc2ac51e2004-07-12 01:03:26 +000011794 case 0xA9: /* TEST Iv, eAX */
11795 delta = dis_op_imm_A( sz, Iop_And8, False, delta, "test" );
11796 break;
11797
sewardj1c6f9912004-09-07 10:15:24 +000011798 /* ------------------------ opl Ev, Gv ----------------- */
11799
sewardj89cd0932004-09-08 18:23:25 +000011800 case 0x02: /* ADD Eb,Gb */
11801 delta = dis_op2_E_G ( sorb, False, Iop_Add8, True, 1, delta, "add" );
11802 break;
sewardj9334b0f2004-07-10 22:43:54 +000011803 case 0x03: /* ADD Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +000011804 delta = dis_op2_E_G ( sorb, False, Iop_Add8, True, sz, delta, "add" );
sewardj9334b0f2004-07-10 22:43:54 +000011805 break;
11806
sewardj7ed22952004-07-29 00:09:58 +000011807 case 0x0A: /* OR Eb,Gb */
sewardj180e8b32004-07-29 01:40:11 +000011808 delta = dis_op2_E_G ( sorb, False, Iop_Or8, True, 1, delta, "or" );
sewardj7ed22952004-07-29 00:09:58 +000011809 break;
sewardjc2ac51e2004-07-12 01:03:26 +000011810 case 0x0B: /* OR Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +000011811 delta = dis_op2_E_G ( sorb, False, Iop_Or8, True, sz, delta, "or" );
sewardjc2ac51e2004-07-12 01:03:26 +000011812 break;
sewardjc9a65702004-07-07 16:32:57 +000011813//--
11814//-- case 0x12: /* ADC Eb,Gb */
sewardj180e8b32004-07-29 01:40:11 +000011815//-- delta = dis_op2_E_G ( sorb, True, ADC, True, 1, delta, "adc" );
sewardjc9a65702004-07-07 16:32:57 +000011816//-- break;
sewardjc4eaff32004-09-10 20:25:11 +000011817 case 0x13: /* ADC Ev,Gv */
11818 delta = dis_op2_E_G ( sorb, True, Iop_Add8, True, sz, delta, "adc" );
11819 break;
11820
sewardjc9a65702004-07-07 16:32:57 +000011821//-- case 0x1A: /* SBB Eb,Gb */
sewardj180e8b32004-07-29 01:40:11 +000011822//-- delta = dis_op2_E_G ( sorb, True, SBB, True, 1, delta, "sbb" );
sewardjc9a65702004-07-07 16:32:57 +000011823//-- break;
sewardj180e8b32004-07-29 01:40:11 +000011824 case 0x1B: /* SBB Ev,Gv */
11825 delta = dis_op2_E_G ( sorb, True, Iop_Sub8, True, sz, delta, "sbb" );
sewardj940e8c92004-07-11 16:53:24 +000011826 break;
11827
sewardj1c6f9912004-09-07 10:15:24 +000011828 case 0x22: /* AND Eb,Gb */
11829 delta = dis_op2_E_G ( sorb, False, Iop_And8, True, 1, delta, "and" );
11830 break;
sewardj180e8b32004-07-29 01:40:11 +000011831 case 0x23: /* AND Ev,Gv */
11832 delta = dis_op2_E_G ( sorb, False, Iop_And8, True, sz, delta, "and" );
11833 break;
11834
11835 case 0x2A: /* SUB Eb,Gb */
11836 delta = dis_op2_E_G ( sorb, False, Iop_Sub8, True, 1, delta, "sub" );
11837 break;
sewardj0611d802004-07-11 02:37:54 +000011838 case 0x2B: /* SUB Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +000011839 delta = dis_op2_E_G ( sorb, False, Iop_Sub8, True, sz, delta, "sub" );
sewardj0611d802004-07-11 02:37:54 +000011840 break;
sewardjc2ac51e2004-07-12 01:03:26 +000011841
11842 case 0x32: /* XOR Eb,Gb */
sewardj180e8b32004-07-29 01:40:11 +000011843 delta = dis_op2_E_G ( sorb, False, Iop_Xor8, True, 1, delta, "xor" );
sewardjc2ac51e2004-07-12 01:03:26 +000011844 break;
sewardj1813dbe2004-07-28 17:09:04 +000011845 case 0x33: /* XOR Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +000011846 delta = dis_op2_E_G ( sorb, False, Iop_Xor8, True, sz, delta, "xor" );
sewardj1813dbe2004-07-28 17:09:04 +000011847 break;
11848
sewardjc2ac51e2004-07-12 01:03:26 +000011849 case 0x3A: /* CMP Eb,Gb */
sewardj180e8b32004-07-29 01:40:11 +000011850 delta = dis_op2_E_G ( sorb, False, Iop_Sub8, False, 1, delta, "cmp" );
sewardjc2ac51e2004-07-12 01:03:26 +000011851 break;
sewardje90ad6a2004-07-10 19:02:10 +000011852 case 0x3B: /* CMP Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +000011853 delta = dis_op2_E_G ( sorb, False, Iop_Sub8, False, sz, delta, "cmp" );
sewardje90ad6a2004-07-10 19:02:10 +000011854 break;
11855
sewardj0611d802004-07-11 02:37:54 +000011856 case 0x84: /* TEST Eb,Gb */
sewardj180e8b32004-07-29 01:40:11 +000011857 delta = dis_op2_E_G ( sorb, False, Iop_And8, False, 1, delta, "test" );
sewardj0611d802004-07-11 02:37:54 +000011858 break;
sewardje05c42c2004-07-08 20:25:10 +000011859 case 0x85: /* TEST Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +000011860 delta = dis_op2_E_G ( sorb, False, Iop_And8, False, sz, delta, "test" );
sewardje05c42c2004-07-08 20:25:10 +000011861 break;
11862
sewardj180e8b32004-07-29 01:40:11 +000011863 /* ------------------------ opl Gv, Ev ----------------- */
11864
11865 case 0x00: /* ADD Gb,Eb */
11866 delta = dis_op2_G_E ( sorb, False, Iop_Add8, True, 1, delta, "add" );
11867 break;
sewardje05c42c2004-07-08 20:25:10 +000011868 case 0x01: /* ADD Gv,Ev */
sewardjcaca9d02004-07-28 07:11:32 +000011869 delta = dis_op2_G_E ( sorb, False, Iop_Add8, True, sz, delta, "add" );
sewardje05c42c2004-07-08 20:25:10 +000011870 break;
11871
sewardj940e8c92004-07-11 16:53:24 +000011872 case 0x08: /* OR Gb,Eb */
sewardjcaca9d02004-07-28 07:11:32 +000011873 delta = dis_op2_G_E ( sorb, False, Iop_Or8, True, 1, delta, "or" );
sewardj940e8c92004-07-11 16:53:24 +000011874 break;
sewardj9334b0f2004-07-10 22:43:54 +000011875 case 0x09: /* OR Gv,Ev */
sewardjcaca9d02004-07-28 07:11:32 +000011876 delta = dis_op2_G_E ( sorb, False, Iop_Or8, True, sz, delta, "or" );
sewardj9334b0f2004-07-10 22:43:54 +000011877 break;
11878
sewardja2384712004-07-29 14:36:40 +000011879 case 0x10: /* ADC Gb,Eb */
11880 delta = dis_op2_G_E ( sorb, True, Iop_Add8, True, 1, delta, "adc" );
11881 break;
sewardjcaca9d02004-07-28 07:11:32 +000011882 case 0x11: /* ADC Gv,Ev */
11883 delta = dis_op2_G_E ( sorb, True, Iop_Add8, True, sz, delta, "adc" );
11884 break;
11885
sewardja2384712004-07-29 14:36:40 +000011886 case 0x18: /* SBB Gb,Eb */
11887 delta = dis_op2_G_E ( sorb, True, Iop_Sub8, True, 1, delta, "sbb" );
11888 break;
sewardjcaca9d02004-07-28 07:11:32 +000011889 case 0x19: /* SBB Gv,Ev */
11890 delta = dis_op2_G_E ( sorb, True, Iop_Sub8, True, sz, delta, "sbb" );
11891 break;
11892
sewardja2384712004-07-29 14:36:40 +000011893 case 0x20: /* AND Gb,Eb */
11894 delta = dis_op2_G_E ( sorb, False, Iop_And8, True, 1, delta, "and" );
11895 break;
sewardj0611d802004-07-11 02:37:54 +000011896 case 0x21: /* AND Gv,Ev */
sewardjcaca9d02004-07-28 07:11:32 +000011897 delta = dis_op2_G_E ( sorb, False, Iop_And8, True, sz, delta, "and" );
sewardj0611d802004-07-11 02:37:54 +000011898 break;
11899
sewardj180e8b32004-07-29 01:40:11 +000011900 case 0x28: /* SUB Gb,Eb */
11901 delta = dis_op2_G_E ( sorb, False, Iop_Sub8, True, 1, delta, "sub" );
11902 break;
sewardje05c42c2004-07-08 20:25:10 +000011903 case 0x29: /* SUB Gv,Ev */
sewardjcaca9d02004-07-28 07:11:32 +000011904 delta = dis_op2_G_E ( sorb, False, Iop_Sub8, True, sz, delta, "sub" );
sewardje05c42c2004-07-08 20:25:10 +000011905 break;
11906
sewardjc2ac51e2004-07-12 01:03:26 +000011907 case 0x30: /* XOR Gb,Eb */
sewardjcaca9d02004-07-28 07:11:32 +000011908 delta = dis_op2_G_E ( sorb, False, Iop_Xor8, True, 1, delta, "xor" );
sewardjc2ac51e2004-07-12 01:03:26 +000011909 break;
sewardje87b4842004-07-10 12:23:30 +000011910 case 0x31: /* XOR Gv,Ev */
sewardjcaca9d02004-07-28 07:11:32 +000011911 delta = dis_op2_G_E ( sorb, False, Iop_Xor8, True, sz, delta, "xor" );
sewardje87b4842004-07-10 12:23:30 +000011912 break;
11913
sewardj0611d802004-07-11 02:37:54 +000011914 case 0x38: /* CMP Gb,Eb */
sewardjcaca9d02004-07-28 07:11:32 +000011915 delta = dis_op2_G_E ( sorb, False, Iop_Sub8, False, 1, delta, "cmp" );
sewardj0611d802004-07-11 02:37:54 +000011916 break;
sewardje90ad6a2004-07-10 19:02:10 +000011917 case 0x39: /* CMP Gv,Ev */
sewardjcaca9d02004-07-28 07:11:32 +000011918 delta = dis_op2_G_E ( sorb, False, Iop_Sub8, False, sz, delta, "cmp" );
sewardje90ad6a2004-07-10 19:02:10 +000011919 break;
11920
sewardj9334b0f2004-07-10 22:43:54 +000011921 /* ------------------------ POP ------------------------ */
11922
11923 case 0x58: /* POP eAX */
11924 case 0x59: /* POP eCX */
11925 case 0x5A: /* POP eDX */
11926 case 0x5B: /* POP eBX */
11927 case 0x5D: /* POP eBP */
11928 case 0x5E: /* POP eSI */
11929 case 0x5F: /* POP eDI */
11930 case 0x5C: /* POP eSP */
11931 vassert(sz == 2 || sz == 4);
11932 t1 = newTemp(szToITy(sz)); t2 = newTemp(Ity_I32);
11933 assign(t2, getIReg(4, R_ESP));
11934 assign(t1, loadLE(szToITy(sz),mkexpr(t2)));
11935 putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t2), mkU32(sz)));
11936 putIReg(sz, opc-0x58, mkexpr(t1));
11937 DIP("pop%c %s\n", nameISize(sz), nameIReg(sz,opc-0x58));
11938 break;
11939
sewardja2384712004-07-29 14:36:40 +000011940 case 0x9D: /* POPF */
11941 vassert(sz == 2 || sz == 4);
11942 vassert(sz == 4); // until we know a sz==2 test case exists
11943 t1 = newTemp(Ity_I32); t2 = newTemp(Ity_I32);
11944 assign(t2, getIReg(4, R_ESP));
sewardjc22a6fd2004-07-29 23:41:47 +000011945 assign(t1, widenUto32(loadLE(szToITy(sz),mkexpr(t2))));
sewardja2384712004-07-29 14:36:40 +000011946 putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t2), mkU32(sz)));
sewardj98169c52004-10-24 13:11:39 +000011947 /* t1 is the flag word. Mask out everything except OSZACP and
sewardj2a9ad022004-11-25 02:46:58 +000011948 set the flags thunk to X86G_CC_OP_COPY. */
11949 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
sewardj2a2ba8b2004-11-08 13:14:06 +000011950 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
11951 stmt( IRStmt_Put( OFFB_CC_DEP1,
sewardj5bd4d162004-11-10 13:02:48 +000011952 binop(Iop_And32,
11953 mkexpr(t1),
sewardj2a9ad022004-11-25 02:46:58 +000011954 mkU32( X86G_CC_MASK_C | X86G_CC_MASK_P
11955 | X86G_CC_MASK_A | X86G_CC_MASK_Z
11956 | X86G_CC_MASK_S| X86G_CC_MASK_O )
sewardj5bd4d162004-11-10 13:02:48 +000011957 )
11958 )
11959 );
sewardja2384712004-07-29 14:36:40 +000011960
11961 /* Also need to set the D flag, which is held in bit 10 of t1.
11962 If zero, put 1 in OFFB_DFLAG, else -1 in OFFB_DFLAG. */
11963 stmt( IRStmt_Put(
11964 OFFB_DFLAG,
11965 IRExpr_Mux0X(
11966 unop(Iop_32to8,
11967 binop(Iop_And32,
11968 binop(Iop_Shr32, mkexpr(t1), mkU8(10)),
11969 mkU32(1))),
11970 mkU32(1),
11971 mkU32(0xFFFFFFFF)))
11972 );
11973
sewardj006a6a22004-10-26 00:50:52 +000011974 /* And set the ID flag */
11975 stmt( IRStmt_Put(
11976 OFFB_IDFLAG,
11977 IRExpr_Mux0X(
11978 unop(Iop_32to8,
11979 binop(Iop_And32,
11980 binop(Iop_Shr32, mkexpr(t1), mkU8(21)),
11981 mkU32(1))),
11982 mkU32(0),
11983 mkU32(1)))
11984 );
11985
sewardja2384712004-07-29 14:36:40 +000011986 DIP("popf%c\n", nameISize(sz));
11987 break;
11988
sewardjc9a65702004-07-07 16:32:57 +000011989//-- case 0x61: /* POPA */
11990//-- { Int reg;
11991//-- /* Just to keep things sane, we assert for a size 4. It's
11992//-- probably OK for size 2 as well, but I'd like to find a test
11993//-- case; ie, have the assertion fail, before committing to it.
11994//-- If it fails for you, uncomment the sz == 2 bit, try again,
11995//-- and let me know whether or not it works. (jseward@acm.org). */
11996//-- vg_assert(sz == 4 /* || sz == 2 */);
11997//--
11998//-- /* Eight values are popped, one per register, but the value of
11999//-- %esp on the stack is ignored and instead incremented (in one
12000//-- hit at the end) for each of the values. */
12001//-- t1 = newTemp(cb); t2 = newTemp(cb); t3 = newTemp(cb);
12002//-- uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t2);
12003//-- uInstr2(cb, MOV, 4, TempReg, t2, TempReg, t3);
12004//--
12005//-- /* Do %edi, %esi, %ebp */
12006//-- for (reg = 7; reg >= 5; reg--) {
12007//-- uInstr2(cb, LOAD, sz, TempReg, t2, TempReg, t1);
12008//-- uInstr2(cb, ADD, 4, Literal, 0, TempReg, t2);
12009//-- uLiteral(cb, sz);
12010//-- uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, reg);
12011//-- }
12012//-- /* Ignore (skip) value of %esp on stack. */
12013//-- uInstr2(cb, ADD, 4, Literal, 0, TempReg, t2);
12014//-- uLiteral(cb, sz);
12015//-- /* Do %ebx, %edx, %ecx, %eax */
12016//-- for (reg = 3; reg >= 0; reg--) {
12017//-- uInstr2(cb, LOAD, sz, TempReg, t2, TempReg, t1);
12018//-- uInstr2(cb, ADD, 4, Literal, 0, TempReg, t2);
12019//-- uLiteral(cb, sz);
12020//-- uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, reg);
12021//-- }
12022//-- uInstr2(cb, ADD, 4, Literal, 0, TempReg, t3);
12023//-- uLiteral(cb, sz * 8); /* One 'sz' per register */
12024//-- uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_ESP);
12025//-- DIP("popa%c\n", nameISize(sz));
12026//-- break;
12027//-- }
sewardjfeeb8a82004-11-30 12:30:11 +000012028
12029 case 0x8F: /* POPL/POPW m32 */
12030 { Int len;
12031 UChar rm = getIByte(delta);
12032
12033 /* make sure this instruction is correct POP */
12034 vassert(!epartIsReg(rm) && (gregOfRM(rm) == 0));
12035 /* and has correct size */
12036 vassert(sz == 4);
12037
12038 t1 = newTemp(Ity_I32); t3 = newTemp(Ity_I32);
12039 /* set t1 to ESP: t1 = ESP */
12040 assign( t1, getIReg(4, R_ESP) );
12041 /* load M[ESP] to virtual register t3: t3 = M[t1] */
12042 assign( t3, loadLE(Ity_I32, mkexpr(t1)) );
12043
12044 /* increase ESP; must be done before the STORE. Intel manual says:
12045 If the ESP register is used as a base register for addressing
12046 a destination operand in memory, the POP instruction computes
12047 the effective address of the operand after it increments the
12048 ESP register.
12049 */
12050 putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t1), mkU32(sz)) );
12051
12052 /* resolve MODR/M */
12053 addr = disAMode ( &len, sorb, delta, dis_buf);
12054 storeLE( mkexpr(addr), mkexpr(t3) );
12055
12056 DIP("popl %s\n", dis_buf);
12057
12058 delta += len;
12059 break;
12060 }
12061
sewardjc9a65702004-07-07 16:32:57 +000012062//-- case 0x1F: /* POP %DS */
12063//-- dis_pop_segreg( cb, R_DS, sz ); break;
12064//-- case 0x07: /* POP %ES */
12065//-- dis_pop_segreg( cb, R_ES, sz ); break;
12066//-- case 0x17: /* POP %SS */
12067//-- dis_pop_segreg( cb, R_SS, sz ); break;
sewardjd1061ab2004-07-08 01:45:30 +000012068
12069 /* ------------------------ PUSH ----------------------- */
12070
12071 case 0x50: /* PUSH eAX */
12072 case 0x51: /* PUSH eCX */
12073 case 0x52: /* PUSH eDX */
12074 case 0x53: /* PUSH eBX */
12075 case 0x55: /* PUSH eBP */
12076 case 0x56: /* PUSH eSI */
12077 case 0x57: /* PUSH eDI */
12078 case 0x54: /* PUSH eSP */
12079 /* This is the Right Way, in that the value to be pushed is
12080 established before %esp is changed, so that pushl %esp
12081 correctly pushes the old value. */
12082 vassert(sz == 2 || sz == 4);
12083 ty = sz==2 ? Ity_I16 : Ity_I32;
sewardj883b00b2004-09-11 09:30:24 +000012084 t1 = newTemp(ty); t2 = newTemp(Ity_I32);
sewardj41f43bc2004-07-08 14:23:22 +000012085 assign(t1, getIReg(sz, opc-0x50));
12086 assign(t2, binop(Iop_Sub32, getIReg(4, R_ESP), mkU32(sz)));
12087 putIReg(4, R_ESP, mkexpr(t2) );
12088 storeLE(mkexpr(t2),mkexpr(t1));
sewardjd1061ab2004-07-08 01:45:30 +000012089 DIP("push%c %s\n", nameISize(sz), nameIReg(sz,opc-0x50));
12090 break;
12091
12092
sewardj0c12ea82004-07-12 08:18:16 +000012093 case 0x68: /* PUSH Iv */
12094 d32 = getUDisp(sz,delta); delta += sz;
12095 goto do_push_I;
sewardj741153c2004-07-25 23:39:13 +000012096 case 0x6A: /* PUSH Ib, sign-extended to sz */
12097 d32 = getSDisp8(delta); delta += 1;
12098 goto do_push_I;
sewardj0c12ea82004-07-12 08:18:16 +000012099 do_push_I:
12100 ty = szToITy(sz);
12101 t1 = newTemp(Ity_I32); t2 = newTemp(ty);
12102 assign( t1, binop(Iop_Sub32,getIReg(4,R_ESP),mkU32(sz)) );
12103 putIReg(4, R_ESP, mkexpr(t1) );
12104 storeLE( mkexpr(t1), mkU(ty,d32) );
12105 DIP("push%c $0x%x\n", nameISize(sz), d32);
12106 break;
12107
sewardja2384712004-07-29 14:36:40 +000012108 case 0x9C: /* PUSHF */ {
sewardja2384712004-07-29 14:36:40 +000012109 vassert(sz == 2 || sz == 4);
12110 vassert(sz == 4); // wait for sz==2 test case
12111
12112 t1 = newTemp(Ity_I32);
12113 assign( t1, binop(Iop_Sub32,getIReg(4,R_ESP),mkU32(sz)) );
12114 putIReg(4, R_ESP, mkexpr(t1) );
12115
12116 t2 = newTemp(Ity_I32);
sewardj2a9ad022004-11-25 02:46:58 +000012117 assign( t2, mk_x86g_calculate_eflags_all() );
sewardja2384712004-07-29 14:36:40 +000012118
12119 /* Patch in the D flag. This can simply be the inversion
sewardj5bd4d162004-11-10 13:02:48 +000012120 of bit 10 of baseBlock[OFFB_DFLAG]. */
sewardja2384712004-07-29 14:36:40 +000012121 t3 = newTemp(Ity_I32);
12122 assign( t3, binop(Iop_Or32,
12123 mkexpr(t2),
12124 binop(Iop_And32,
sewardj5bd4d162004-11-10 13:02:48 +000012125 unop(Iop_Not32, IRExpr_Get(OFFB_DFLAG,Ity_I32)),
12126 mkU32(1<<10)))
sewardja2384712004-07-29 14:36:40 +000012127 );
sewardj006a6a22004-10-26 00:50:52 +000012128
12129 /* And patch in the ID flag. */
12130 t4 = newTemp(Ity_I32);
12131 assign( t4, binop(Iop_Or32,
12132 mkexpr(t3),
12133 binop(Iop_And32,
sewardj5bd4d162004-11-10 13:02:48 +000012134 binop(Iop_Shl32, IRExpr_Get(OFFB_IDFLAG,Ity_I32),
sewardj006a6a22004-10-26 00:50:52 +000012135 mkU8(21)),
sewardj5bd4d162004-11-10 13:02:48 +000012136 mkU32(1<<21)))
sewardj006a6a22004-10-26 00:50:52 +000012137 );
12138
sewardja2384712004-07-29 14:36:40 +000012139 /* if sz==2, the stored value needs to be narrowed. */
12140 if (sz == 2)
sewardj5bd4d162004-11-10 13:02:48 +000012141 storeLE( mkexpr(t1), unop(Iop_32to16,mkexpr(t4)) );
sewardja2384712004-07-29 14:36:40 +000012142 else
sewardj5bd4d162004-11-10 13:02:48 +000012143 storeLE( mkexpr(t1), mkexpr(t4) );
sewardja2384712004-07-29 14:36:40 +000012144
12145 DIP("pushf%c\n", nameISize(sz));
12146 break;
12147 }
12148
sewardjc9a65702004-07-07 16:32:57 +000012149//-- case 0x60: /* PUSHA */
12150//-- { Int reg;
12151//-- /* Just to keep things sane, we assert for a size 4. It's
12152//-- probably OK for size 2 as well, but I'd like to find a test
12153//-- case; ie, have the assertion fail, before committing to it.
12154//-- If it fails for you, uncomment the sz == 2 bit, try again,
12155//-- and let me know whether or not it works. (jseward@acm.org). */
12156//-- vg_assert(sz == 4 /* || sz == 2 */);
12157//--
12158//-- /* This is the Right Way, in that the value to be pushed is
12159//-- established before %esp is changed, so that pusha
12160//-- correctly pushes the old %esp value. New value of %esp is
12161//-- pushed at start. */
12162//-- t1 = newTemp(cb); t2 = newTemp(cb); t3 = newTemp(cb);
12163//-- t4 = newTemp(cb);
12164//-- uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t3);
12165//-- uInstr2(cb, MOV, 4, TempReg, t3, TempReg, t2);
12166//-- uInstr2(cb, MOV, 4, TempReg, t3, TempReg, t4);
12167//-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t4);
12168//-- uLiteral(cb, sz * 8); /* One 'sz' per register. */
12169//-- uInstr2(cb, PUT, 4, TempReg, t4, ArchReg, R_ESP);
12170//-- /* Do %eax, %ecx, %edx, %ebx */
12171//-- for (reg = 0; reg <= 3; reg++) {
12172//-- uInstr2(cb, GET, sz, ArchReg, reg, TempReg, t1);
12173//-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
12174//-- uLiteral(cb, sz);
12175//-- uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t2);
12176//-- }
12177//-- /* Push old value of %esp */
12178//-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
12179//-- uLiteral(cb, sz);
12180//-- uInstr2(cb, STORE, sz, TempReg, t3, TempReg, t2);
12181//-- /* Do %ebp, %esi, %edi */
12182//-- for (reg = 5; reg <= 7; reg++) {
12183//-- uInstr2(cb, GET, sz, ArchReg, reg, TempReg, t1);
12184//-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
12185//-- uLiteral(cb, sz);
12186//-- uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t2);
12187//-- }
12188//-- DIP("pusha%c\n", nameISize(sz));
12189//-- break;
12190//-- }
12191//--
12192//-- case 0x0E: /* PUSH %CS */
12193//-- dis_push_segreg( cb, R_CS, sz ); break;
12194//-- case 0x1E: /* PUSH %DS */
12195//-- dis_push_segreg( cb, R_DS, sz ); break;
12196//-- case 0x06: /* PUSH %ES */
12197//-- dis_push_segreg( cb, R_ES, sz ); break;
12198//-- case 0x16: /* PUSH %SS */
12199//-- dis_push_segreg( cb, R_SS, sz ); break;
sewardj458a6f82004-08-25 12:46:02 +000012200
12201 /* ------------------------ SCAS et al ----------------- */
12202
12203 case 0xA4: /* MOVS, no REP prefix */
12204 case 0xA5:
12205 dis_string_op( dis_MOVS, ( opc == 0xA4 ? 1 : sz ), "movs", sorb );
12206 break;
12207
sewardjc9a65702004-07-07 16:32:57 +000012208//-- case 0xA6: /* CMPSb, no REP prefix */
12209//-- case 0xA7:
12210//-- dis_string_op( cb, dis_CMPS, ( opc == 0xA6 ? 1 : sz ), "cmps", sorb );
12211//-- break;
12212//--
sewardj883b00b2004-09-11 09:30:24 +000012213 case 0xAA: /* STOS, no REP prefix */
sewardj47341042004-09-19 11:55:46 +000012214 case 0xAB:
sewardj883b00b2004-09-11 09:30:24 +000012215 dis_string_op( dis_STOS, ( opc == 0xAA ? 1 : sz ), "stos", sorb );
12216 break;
sewardjc9a65702004-07-07 16:32:57 +000012217//--
12218//-- case 0xAC: /* LODS, no REP prefix */
12219//-- case 0xAD:
12220//-- dis_string_op( cb, dis_LODS, ( opc == 0xAC ? 1 : sz ), "lods", sorb );
12221//-- break;
sewardj2d4c3a02004-10-15 00:03:23 +000012222
12223 case 0xAE: /* SCAS, no REP prefix */
12224 case 0xAF:
12225 dis_string_op( dis_SCAS, ( opc == 0xAE ? 1 : sz ), "scas", sorb );
12226 break;
sewardj64e1d652004-07-12 14:00:46 +000012227
12228
12229 case 0xFC: /* CLD */
sewardjeeb9ef82004-07-15 12:39:03 +000012230 stmt( IRStmt_Put( OFFB_DFLAG, mkU32(1)) );
sewardj64e1d652004-07-12 14:00:46 +000012231 DIP("cld\n");
12232 break;
12233
sewardj1813dbe2004-07-28 17:09:04 +000012234 case 0xFD: /* STD */
12235 stmt( IRStmt_Put( OFFB_DFLAG, mkU32(0xFFFFFFFF)) );
12236 DIP("std\n");
12237 break;
12238
sewardjc9a65702004-07-07 16:32:57 +000012239//-- case 0xF8: /* CLC */
12240//-- uInstr0(cb, CALLM_S, 0);
12241//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_CLC));
12242//-- uFlagsRWU(cb, FlagsEmpty, FlagC, FlagsOSZAP);
12243//-- uInstr0(cb, CALLM_E, 0);
12244//-- DIP("clc\n");
12245//-- break;
12246//--
12247//-- case 0xF9: /* STC */
12248//-- uInstr0(cb, CALLM_S, 0);
12249//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_STC));
12250//-- uFlagsRWU(cb, FlagsEmpty, FlagC, FlagsOSZAP);
12251//-- uInstr0(cb, CALLM_E, 0);
12252//-- DIP("stc\n");
12253//-- break;
12254//--
12255//-- case 0xF5: /* CMC */
12256//-- uInstr0(cb, CALLM_S, 0);
12257//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_CMC));
12258//-- uFlagsRWU(cb, FlagC, FlagC, FlagsOSZAP);
12259//-- uInstr0(cb, CALLM_E, 0);
12260//-- DIP("cmc\n");
12261//-- break;
sewardj82292882004-07-27 00:15:59 +000012262
12263 /* REPNE prefix insn */
12264 case 0xF2: {
sewardjce70a5c2004-10-18 14:09:54 +000012265 Addr32 eip_orig = guest_eip_bbstart + delta - 1;
sewardj82292882004-07-27 00:15:59 +000012266 vassert(sorb == 0);
12267 abyte = getIByte(delta); delta++;
12268
12269 if (abyte == 0x66) { sz = 2; abyte = getIByte(delta); delta++; }
sewardjce70a5c2004-10-18 14:09:54 +000012270 whatNext = Dis_StopHere;
sewardj82292882004-07-27 00:15:59 +000012271
12272 switch (abyte) {
12273 /* According to the Intel manual, "repne movs" should never occur, but
12274 * in practice it has happened, so allow for it here... */
sewardj180e8b32004-07-29 01:40:11 +000012275 case 0xA4: sz = 1; /* REPNE MOVS<sz> */
sewardjb64821b2004-12-14 10:00:16 +000012276 goto decode_failure;
sewardjc9a65702004-07-07 16:32:57 +000012277//-- case 0xA5:
sewardj5bd4d162004-11-10 13:02:48 +000012278 // dis_REP_op ( CondNZ, dis_MOVS, sz, eip_orig,
12279 // guest_eip_bbstart+delta, "repne movs" );
12280 // break;
sewardjc9a65702004-07-07 16:32:57 +000012281//--
12282//-- case 0xA6: sz = 1; /* REPNE CMPS<sz> */
12283//-- case 0xA7:
12284//-- dis_REP_op ( cb, CondNZ, dis_CMPS, sz, eip_orig, eip, "repne cmps" );
12285//-- break;
12286//--
sewardj82292882004-07-27 00:15:59 +000012287 case 0xAE: sz = 1; /* REPNE SCAS<sz> */
sewardj2d4c3a02004-10-15 00:03:23 +000012288 case 0xAF:
sewardj2a9ad022004-11-25 02:46:58 +000012289 dis_REP_op ( X86CondNZ, dis_SCAS, sz, eip_orig,
12290 guest_eip_bbstart+delta, "repne scas" );
sewardj82292882004-07-27 00:15:59 +000012291 break;
12292
12293 default:
12294 goto decode_failure;
12295 }
12296 break;
12297 }
sewardj64e1d652004-07-12 14:00:46 +000012298
12299 /* REP/REPE prefix insn (for SCAS and CMPS, 0xF3 means REPE,
12300 for the rest, it means REP) */
12301 case 0xF3: {
sewardjce70a5c2004-10-18 14:09:54 +000012302 Addr32 eip_orig = guest_eip_bbstart + delta - 1;
sewardj64e1d652004-07-12 14:00:46 +000012303 vassert(sorb == 0);
12304 abyte = getIByte(delta); delta++;
12305
12306 if (abyte == 0x66) { sz = 2; abyte = getIByte(delta); delta++; }
sewardjce70a5c2004-10-18 14:09:54 +000012307 whatNext = Dis_StopHere;
sewardj64e1d652004-07-12 14:00:46 +000012308
12309 switch (abyte) {
12310 case 0xA4: sz = 1; /* REP MOVS<sz> */
12311 case 0xA5:
sewardj2a9ad022004-11-25 02:46:58 +000012312 dis_REP_op ( X86CondAlways, dis_MOVS, sz, eip_orig,
12313 guest_eip_bbstart+delta, "rep movs" );
sewardj64e1d652004-07-12 14:00:46 +000012314 break;
12315
12316 case 0xA6: sz = 1; /* REPE CMP<sz> */
sewardj2d4c3a02004-10-15 00:03:23 +000012317 case 0xA7:
sewardj2a9ad022004-11-25 02:46:58 +000012318 dis_REP_op ( X86CondZ, dis_CMPS, sz, eip_orig,
12319 guest_eip_bbstart+delta, "repe cmps" );
sewardj64e1d652004-07-12 14:00:46 +000012320 break;
12321
12322 case 0xAA: sz = 1; /* REP STOS<sz> */
12323 case 0xAB:
sewardj2a9ad022004-11-25 02:46:58 +000012324 dis_REP_op ( X86CondAlways, dis_STOS, sz, eip_orig,
12325 guest_eip_bbstart+delta, "rep stos" );
sewardj64e1d652004-07-12 14:00:46 +000012326 break;
sewardjc9a65702004-07-07 16:32:57 +000012327//--
12328//-- case 0xAE: sz = 1; /* REPE SCAS<sz> */
12329//-- case 0xAF:
12330//-- dis_REP_op ( cb, CondZ, dis_SCAS, sz, eip_orig, eip, "repe scas" );
12331//-- break;
sewardj43b8df12004-11-26 12:18:51 +000012332
12333 case 0x90: /* REP NOP (PAUSE) */
12334 /* a hint to the P4 re spin-wait loop */
12335 DIP("rep nop (P4 pause)\n");
12336 jmp_lit(Ijk_Yield, ((Addr32)guest_eip_bbstart)+delta);
12337 whatNext = Dis_StopHere;
12338 break;
12339
sewardjc9a65702004-07-07 16:32:57 +000012340//-- case 0xC3: /* REP RET */
12341//-- /* AMD K7/K8-specific optimisation; faster than vanilla RET */
12342//-- dis_ret(cb, 0);
12343//-- DIP("rep ret\n");
12344//-- break;
sewardj64e1d652004-07-12 14:00:46 +000012345
12346 default:
12347 goto decode_failure;
12348 }
12349 break;
12350 }
sewardj0611d802004-07-11 02:37:54 +000012351
12352 /* ------------------------ XCHG ----------------------- */
12353
12354 case 0x86: /* XCHG Gb,Eb */
12355 sz = 1;
12356 /* Fall through ... */
12357 case 0x87: /* XCHG Gv,Ev */
12358 modrm = getIByte(delta);
12359 ty = szToITy(sz);
12360 t1 = newTemp(ty); t2 = newTemp(ty);
12361 if (epartIsReg(modrm)) {
sewardj5bd4d162004-11-10 13:02:48 +000012362 assign(t1, getIReg(sz, eregOfRM(modrm)));
12363 assign(t2, getIReg(sz, gregOfRM(modrm)));
12364 putIReg(sz, gregOfRM(modrm), mkexpr(t1));
12365 putIReg(sz, eregOfRM(modrm), mkexpr(t2));
sewardj0611d802004-07-11 02:37:54 +000012366 delta++;
12367 DIP("xchg%c %s, %s\n",
12368 nameISize(sz), nameIReg(sz,gregOfRM(modrm)),
12369 nameIReg(sz,eregOfRM(modrm)));
12370 } else {
sewardj0c12ea82004-07-12 08:18:16 +000012371 addr = disAMode ( &alen, sorb, delta, dis_buf );
sewardj5bd4d162004-11-10 13:02:48 +000012372 assign( t1, loadLE(ty,mkexpr(addr)) );
12373 assign( t2, getIReg(sz,gregOfRM(modrm)) );
12374 storeLE( mkexpr(addr), mkexpr(t2) );
12375 putIReg( sz, gregOfRM(modrm), mkexpr(t1) );
12376 delta += alen;
sewardj0611d802004-07-11 02:37:54 +000012377 DIP("xchg%c %s, %s\n", nameISize(sz),
12378 nameIReg(sz,gregOfRM(modrm)), dis_buf);
sewardj0611d802004-07-11 02:37:54 +000012379 }
12380 break;
sewardje87b4842004-07-10 12:23:30 +000012381
12382 case 0x90: /* XCHG eAX,eAX */
12383 DIP("nop\n");
12384 break;
sewardj64e1d652004-07-12 14:00:46 +000012385 case 0x91: /* XCHG eAX,eCX */
12386 case 0x92: /* XCHG eAX,eDX */
12387 case 0x93: /* XCHG eAX,eBX */
12388 case 0x94: /* XCHG eAX,eSP */
12389 case 0x95: /* XCHG eAX,eBP */
12390 case 0x96: /* XCHG eAX,eSI */
12391 case 0x97: /* XCHG eAX,eDI */
12392 codegen_xchg_eAX_Reg ( sz, opc - 0x90 );
12393 break;
12394
sewardjc9a65702004-07-07 16:32:57 +000012395//-- /* ------------------------ XLAT ----------------------- */
12396//--
12397//-- case 0xD7: /* XLAT */
12398//-- t1 = newTemp(cb); t2 = newTemp(cb);
12399//-- uInstr2(cb, GET, sz, ArchReg, R_EBX, TempReg, t1); /* get eBX */
12400//-- handleSegOverride( cb, sorb, t1 ); /* make t1 DS:eBX */
12401//-- uInstr2(cb, GET, 1, ArchReg, R_AL, TempReg, t2); /* get AL */
12402//-- /* Widen %AL to 32 bits, so it's all defined when we add it. */
12403//-- uInstr1(cb, WIDEN, 4, TempReg, t2);
12404//-- uWiden(cb, 1, False);
12405//-- uInstr2(cb, ADD, sz, TempReg, t2, TempReg, t1); /* add AL to eBX */
12406//-- uInstr2(cb, LOAD, 1, TempReg, t1, TempReg, t2); /* get byte at t1 into t2 */
12407//-- uInstr2(cb, PUT, 1, TempReg, t2, ArchReg, R_AL); /* put byte into AL */
12408//--
12409//-- DIP("xlat%c [ebx]\n", nameISize(sz));
12410//-- break;
12411//--
12412//-- /* ------------------------ IN / OUT ----------------------- */
12413//--
12414//-- case 0xE4: /* IN ib, %al */
12415//-- case 0xE5: /* IN ib, %{e}ax */
12416//-- case 0xEC: /* IN (%dx),%al */
12417//-- case 0xED: /* IN (%dx),%{e}ax */
12418//-- t1 = newTemp(cb);
12419//-- t2 = newTemp(cb);
12420//-- t3 = newTemp(cb);
12421//--
12422//-- uInstr0(cb, CALLM_S, 0);
12423//-- /* operand size? */
12424//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t1);
12425//-- uLiteral(cb, ( opc == 0xE4 || opc == 0xEC ) ? 1 : sz);
12426//-- uInstr1(cb, PUSH, 4, TempReg, t1);
12427//-- /* port number ? */
12428//-- if ( opc == 0xE4 || opc == 0xE5 ) {
12429//-- abyte = getUChar(eip); eip++;
12430//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
12431//-- uLiteral(cb, abyte);
12432//-- }
12433//-- else
12434//-- uInstr2(cb, GET, 4, ArchReg, R_EDX, TempReg, t2);
12435//--
12436//-- uInstr1(cb, PUSH, 4, TempReg, t2);
12437//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_IN));
12438//-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
12439//-- uInstr1(cb, POP, 4, TempReg, t2);
12440//-- uInstr1(cb, CLEAR, 0, Lit16, 4);
12441//-- uInstr0(cb, CALLM_E, 0);
12442//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_EAX);
12443//-- if ( opc == 0xE4 || opc == 0xE5 ) {
12444//-- DIP("in 0x%x, %%eax/%%ax/%%al\n", getUChar(eip-1) );
12445//-- } else {
12446//-- DIP("in (%%dx), %%eax/%%ax/%%al\n");
12447//-- }
12448//-- break;
12449//-- case 0xE6: /* OUT %al,ib */
12450//-- case 0xE7: /* OUT %{e}ax,ib */
12451//-- case 0xEE: /* OUT %al,(%dx) */
12452//-- case 0xEF: /* OUT %{e}ax,(%dx) */
12453//-- t1 = newTemp(cb);
12454//-- t2 = newTemp(cb);
12455//-- t3 = newTemp(cb);
12456//--
12457//-- uInstr0(cb, CALLM_S, 0);
12458//-- /* operand size? */
12459//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t1);
12460//-- uLiteral(cb, ( opc == 0xE6 || opc == 0xEE ) ? 1 : sz);
12461//-- uInstr1(cb, PUSH, 4, TempReg, t1);
12462//-- /* port number ? */
12463//-- if ( opc == 0xE6 || opc == 0xE7 ) {
12464//-- abyte = getUChar(eip); eip++;
12465//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
12466//-- uLiteral(cb, abyte);
12467//-- }
12468//-- else
12469//-- uInstr2(cb, GET, 4, ArchReg, R_EDX, TempReg, t2);
12470//-- uInstr1(cb, PUSH, 4, TempReg, t2);
12471//-- uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, t3);
12472//-- uInstr1(cb, PUSH, 4, TempReg, t3);
12473//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_OUT));
12474//-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
12475//-- uInstr1(cb, CLEAR, 0, Lit16, 12);
12476//-- uInstr0(cb, CALLM_E, 0);
12477//-- if ( opc == 0xE4 || opc == 0xE5 ) {
12478//-- DIP("out %%eax/%%ax/%%al, 0x%x\n", getUChar(eip-1) );
12479//-- } else {
12480//-- DIP("out %%eax/%%ax/%%al, (%%dx)\n");
12481//-- }
12482//-- break;
sewardj0611d802004-07-11 02:37:54 +000012483
12484 /* ------------------------ (Grp1 extensions) ---------- */
12485
12486 case 0x80: /* Grp1 Ib,Eb */
12487 modrm = getIByte(delta);
12488 am_sz = lengthAMode(delta);
12489 sz = 1;
12490 d_sz = 1;
sewardjc2ac51e2004-07-12 01:03:26 +000012491 d32 = getUChar(delta + am_sz);
sewardj0611d802004-07-11 02:37:54 +000012492 delta = dis_Grp1 ( sorb, delta, modrm, am_sz, d_sz, sz, d32 );
12493 break;
sewardje05c42c2004-07-08 20:25:10 +000012494
12495 case 0x81: /* Grp1 Iv,Ev */
12496 modrm = getIByte(delta);
12497 am_sz = lengthAMode(delta);
12498 d_sz = sz;
12499 d32 = getUDisp(d_sz, delta + am_sz);
12500 delta = dis_Grp1 ( sorb, delta, modrm, am_sz, d_sz, sz, d32 );
12501 break;
sewardjd1061ab2004-07-08 01:45:30 +000012502
12503 case 0x83: /* Grp1 Ib,Ev */
12504 modrm = getIByte(delta);
12505 am_sz = lengthAMode(delta);
12506 d_sz = 1;
12507 d32 = getSDisp8(delta + am_sz);
12508 delta = dis_Grp1 ( sorb, delta, modrm, am_sz, d_sz, sz, d32 );
12509 break;
12510
sewardjc2ac51e2004-07-12 01:03:26 +000012511 /* ------------------------ (Grp2 extensions) ---------- */
12512
12513 case 0xC0: /* Grp2 Ib,Eb */
12514 modrm = getIByte(delta);
12515 am_sz = lengthAMode(delta);
12516 d_sz = 1;
sewardj180e8b32004-07-29 01:40:11 +000012517 d32 = getUChar(delta + am_sz);
sewardjc2ac51e2004-07-12 01:03:26 +000012518 sz = 1;
sewardj6d2638e2004-07-15 09:38:27 +000012519 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
12520 mkU8(d32 & 0xFF), NULL );
sewardjc2ac51e2004-07-12 01:03:26 +000012521 break;
sewardje90ad6a2004-07-10 19:02:10 +000012522
12523 case 0xC1: /* Grp2 Ib,Ev */
sewardjc2ac51e2004-07-12 01:03:26 +000012524 modrm = getIByte(delta);
sewardje90ad6a2004-07-10 19:02:10 +000012525 am_sz = lengthAMode(delta);
12526 d_sz = 1;
sewardj180e8b32004-07-29 01:40:11 +000012527 d32 = getUChar(delta + am_sz);
sewardj6d2638e2004-07-15 09:38:27 +000012528 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
12529 mkU8(d32 & 0xFF), NULL );
sewardje90ad6a2004-07-10 19:02:10 +000012530 break;
12531
sewardj180e8b32004-07-29 01:40:11 +000012532 case 0xD0: /* Grp2 1,Eb */
12533 modrm = getIByte(delta);
12534 am_sz = lengthAMode(delta);
12535 d_sz = 0;
12536 d32 = 1;
12537 sz = 1;
12538 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
12539 mkU8(d32), NULL );
12540 break;
sewardjc2ac51e2004-07-12 01:03:26 +000012541
12542 case 0xD1: /* Grp2 1,Ev */
12543 modrm = getUChar(delta);
12544 am_sz = lengthAMode(delta);
12545 d_sz = 0;
12546 d32 = 1;
sewardj6d2638e2004-07-15 09:38:27 +000012547 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
12548 mkU8(d32), NULL );
sewardjc2ac51e2004-07-12 01:03:26 +000012549 break;
12550
sewardj8c7f1ab2004-07-29 20:31:09 +000012551 case 0xD2: /* Grp2 CL,Eb */
12552 modrm = getUChar(delta);
12553 am_sz = lengthAMode(delta);
12554 d_sz = 0;
12555 sz = 1;
12556 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
12557 getIReg(1,R_ECX), "%cl" );
12558 break;
sewardj9334b0f2004-07-10 22:43:54 +000012559
12560 case 0xD3: /* Grp2 CL,Ev */
12561 modrm = getIByte(delta);
12562 am_sz = lengthAMode(delta);
12563 d_sz = 0;
12564 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
sewardj6d2638e2004-07-15 09:38:27 +000012565 getIReg(1,R_ECX), "%cl" );
sewardj9334b0f2004-07-10 22:43:54 +000012566 break;
12567
sewardj940e8c92004-07-11 16:53:24 +000012568 /* ------------------------ (Grp3 extensions) ---------- */
12569
12570 case 0xF6: /* Grp3 Eb */
12571 delta = dis_Grp3 ( sorb, 1, delta );
12572 break;
12573 case 0xF7: /* Grp3 Ev */
12574 delta = dis_Grp3 ( sorb, sz, delta );
12575 break;
12576
sewardjc2ac51e2004-07-12 01:03:26 +000012577 /* ------------------------ (Grp4 extensions) ---------- */
12578
12579 case 0xFE: /* Grp4 Eb */
12580 delta = dis_Grp4 ( sorb, delta );
12581 break;
sewardj0611d802004-07-11 02:37:54 +000012582
12583 /* ------------------------ (Grp5 extensions) ---------- */
12584
12585 case 0xFF: /* Grp5 Ev */
sewardjce70a5c2004-10-18 14:09:54 +000012586 delta = dis_Grp5 ( sorb, sz, delta, &whatNext );
sewardj0611d802004-07-11 02:37:54 +000012587 break;
sewardje87b4842004-07-10 12:23:30 +000012588
12589 /* ------------------------ Escapes to 2-byte opcodes -- */
12590
12591 case 0x0F: {
12592 opc = getIByte(delta); delta++;
12593 switch (opc) {
12594
sewardjc9a65702004-07-07 16:32:57 +000012595//-- /* =-=-=-=-=-=-=-=-=- Grp8 =-=-=-=-=-=-=-=-=-=-=-= */
12596//--
12597//-- case 0xBA: /* Grp8 Ib,Ev */
12598//-- modrm = getUChar(eip);
12599//-- am_sz = lengthAMode(eip);
12600//-- d32 = getSDisp8(eip + am_sz);
12601//-- eip = dis_Grp8_BT ( cb, sorb, eip, modrm, am_sz, sz, d32 );
12602//-- break;
sewardjce646f22004-08-31 23:55:54 +000012603
12604 /* =-=-=-=-=-=-=-=-=- BSF/BSR -=-=-=-=-=-=-=-=-=-= */
12605
12606 case 0xBC: /* BSF Gv,Ev */
12607 delta = dis_bs_E_G ( sorb, sz, delta, True );
12608 break;
12609 case 0xBD: /* BSR Gv,Ev */
12610 delta = dis_bs_E_G ( sorb, sz, delta, False );
12611 break;
sewardj1c4208f2004-08-25 13:25:29 +000012612
12613 /* =-=-=-=-=-=-=-=-=- BSWAP -=-=-=-=-=-=-=-=-=-=-= */
12614
12615 case 0xC8: /* BSWAP %eax */
12616 case 0xC9:
12617 case 0xCA:
sewardjb4666cf2004-10-23 00:21:50 +000012618 case 0xCB:
12619 case 0xCC:
12620 case 0xCD:
sewardj1c4208f2004-08-25 13:25:29 +000012621 case 0xCE:
sewardj1c6f9912004-09-07 10:15:24 +000012622 case 0xCF: /* BSWAP %edi */
sewardj1c4208f2004-08-25 13:25:29 +000012623 /* AFAICS from the Intel docs, this only exists at size 4. */
12624 vassert(sz == 4);
12625 t1 = newTemp(Ity_I32);
12626 t2 = newTemp(Ity_I32);
12627 assign( t1, getIReg(4, opc-0xC8) );
12628
12629 assign( t2,
12630 binop(Iop_Or32,
12631 binop(Iop_Shl32, mkexpr(t1), mkU8(24)),
12632 binop(Iop_Or32,
12633 binop(Iop_And32, binop(Iop_Shl32, mkexpr(t1), mkU8(8)),
12634 mkU32(0x00FF0000)),
12635 binop(Iop_Or32,
12636 binop(Iop_And32, binop(Iop_Shr32, mkexpr(t1), mkU8(8)),
12637 mkU32(0x0000FF00)),
12638 binop(Iop_And32, binop(Iop_Shr32, mkexpr(t1), mkU8(24)),
12639 mkU32(0x000000FF) )
12640 )))
12641 );
12642
12643 putIReg(4, opc-0xC8, mkexpr(t2));
sewardj1c4208f2004-08-25 13:25:29 +000012644 DIP("bswapl %s\n", nameIReg(4, opc-0xC8));
12645 break;
12646
sewardj1c6f9912004-09-07 10:15:24 +000012647 /* =-=-=-=-=-=-=-=-=- BT/BTS/BTR/BTC =-=-=-=-=-=-= */
12648
12649 case 0xA3: /* BT Gv,Ev */
12650 delta = dis_bt_G_E ( sorb, sz, delta, BtOpNone );
12651 break;
sewardje6709112004-09-10 18:37:18 +000012652 case 0xB3: /* BTR Gv,Ev */
12653 delta = dis_bt_G_E ( sorb, sz, delta, BtOpReset );
12654 break;
sewardj1c6f9912004-09-07 10:15:24 +000012655 case 0xAB: /* BTS Gv,Ev */
12656 delta = dis_bt_G_E ( sorb, sz, delta, BtOpSet );
12657 break;
sewardj4963a422004-10-14 23:34:03 +000012658 case 0xBB: /* BTC Gv,Ev */
12659 delta = dis_bt_G_E ( sorb, sz, delta, BtOpComp );
12660 break;
sewardj458a6f82004-08-25 12:46:02 +000012661
12662 /* =-=-=-=-=-=-=-=-=- CMOV =-=-=-=-=-=-=-=-=-=-=-= */
12663
sewardj2d4c3a02004-10-15 00:03:23 +000012664 case 0x40:
12665 case 0x41:
sewardj458a6f82004-08-25 12:46:02 +000012666 case 0x42: /* CMOVBb/CMOVNAEb (cmov below) */
12667 case 0x43: /* CMOVNBb/CMOVAEb (cmov not below) */
12668 case 0x44: /* CMOVZb/CMOVEb (cmov zero) */
12669 case 0x45: /* CMOVNZb/CMOVNEb (cmov not zero) */
12670 case 0x46: /* CMOVBEb/CMOVNAb (cmov below or equal) */
12671 case 0x47: /* CMOVNBEb/CMOVAb (cmov not below or equal) */
sewardjce646f22004-08-31 23:55:54 +000012672 case 0x48: /* CMOVSb (cmov negative) */
sewardj458a6f82004-08-25 12:46:02 +000012673 case 0x49: /* CMOVSb (cmov not negative) */
sewardj2d4c3a02004-10-15 00:03:23 +000012674 case 0x4A: /* CMOVP (cmov parity even) */
12675 case 0x4B: /* CMOVNP (cmov parity odd) */
sewardj458a6f82004-08-25 12:46:02 +000012676 case 0x4C: /* CMOVLb/CMOVNGEb (cmov less) */
12677 case 0x4D: /* CMOVGEb/CMOVNLb (cmov greater or equal) */
12678 case 0x4E: /* CMOVLEb/CMOVNGb (cmov less or equal) */
12679 case 0x4F: /* CMOVGb/CMOVNLEb (cmov greater) */
sewardj2a9ad022004-11-25 02:46:58 +000012680 delta = dis_cmov_E_G(sorb, sz, (X86Condcode)(opc - 0x40), delta);
sewardj458a6f82004-08-25 12:46:02 +000012681 break;
12682
12683 /* =-=-=-=-=-=-=-=-=- CMPXCHG -=-=-=-=-=-=-=-=-=-= */
12684
sewardjc744e872004-08-26 11:24:39 +000012685 case 0xB0: /* CMPXCHG Gb,Eb */
12686 delta = dis_cmpxchg_G_E ( sorb, 1, delta );
12687 break;
sewardj458a6f82004-08-25 12:46:02 +000012688 case 0xB1: /* CMPXCHG Gv,Ev */
12689 delta = dis_cmpxchg_G_E ( sorb, sz, delta );
12690 break;
sewardjc9a65702004-07-07 16:32:57 +000012691//-- case 0xC7: /* CMPXCHG8B Gv */
12692//-- eip = dis_cmpxchg8b ( cb, sorb, eip );
12693//-- break;
12694//--
sewardj588ea762004-09-10 18:56:32 +000012695 /* =-=-=-=-=-=-=-=-=- CPUID -=-=-=-=-=-=-=-=-=-=-= */
12696
sewardj7cb49d72004-10-24 22:31:25 +000012697 case 0xA2: { /* CPUID */
12698 /* Uses dirty helper:
12699 void dirtyhelper_CPUID ( VexGuestX86State* )
12700 declared to mod eax, wr ebx, ecx, edx
12701 */
sewardjf9655262004-10-31 20:02:16 +000012702 IRDirty* d = unsafeIRDirty_0_N (
12703 0/*regparms*/,
sewardj2a9ad022004-11-25 02:46:58 +000012704 "x86g_dirtyhelper_CPUID",
12705 &x86g_dirtyhelper_CPUID,
sewardjf9655262004-10-31 20:02:16 +000012706 mkIRExprVec_0()
12707 );
sewardj7cb49d72004-10-24 22:31:25 +000012708 /* declare guest state effects */
sewardjc5fc7aa2004-10-27 23:00:55 +000012709 d->needsBBP = True;
sewardj7cb49d72004-10-24 22:31:25 +000012710 d->nFxState = 4;
12711 d->fxState[0].fx = Ifx_Modify;
12712 d->fxState[0].offset = OFFB_EAX;
12713 d->fxState[0].size = 4;
12714 d->fxState[1].fx = Ifx_Write;
12715 d->fxState[1].offset = OFFB_EBX;
12716 d->fxState[1].size = 4;
12717 d->fxState[2].fx = Ifx_Write;
12718 d->fxState[2].offset = OFFB_ECX;
12719 d->fxState[2].size = 4;
12720 d->fxState[3].fx = Ifx_Write;
12721 d->fxState[3].offset = OFFB_EDX;
12722 d->fxState[3].size = 4;
12723 /* execute the dirty call, side-effecting guest state */
12724 stmt( IRStmt_Dirty(d) );
sewardj517a7d62004-10-25 09:52:18 +000012725 DIP("cpuid\n");
sewardj588ea762004-09-10 18:56:32 +000012726 break;
sewardj7cb49d72004-10-24 22:31:25 +000012727 }
12728
sewardj5bd4d162004-11-10 13:02:48 +000012729//-- if (!VG_(cpu_has_feature)(VG_X86_FEAT_CPUID))
12730//-- goto decode_failure;
sewardjc9a65702004-07-07 16:32:57 +000012731//--
12732//-- t1 = newTemp(cb);
12733//-- t2 = newTemp(cb);
12734//-- t3 = newTemp(cb);
12735//-- t4 = newTemp(cb);
12736//-- uInstr0(cb, CALLM_S, 0);
12737//--
12738//-- uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, t1);
12739//-- uInstr1(cb, PUSH, 4, TempReg, t1);
12740//--
12741//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
12742//-- uLiteral(cb, 0);
12743//-- uInstr1(cb, PUSH, 4, TempReg, t2);
12744//--
12745//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t3);
12746//-- uLiteral(cb, 0);
12747//-- uInstr1(cb, PUSH, 4, TempReg, t3);
12748//--
12749//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t4);
12750//-- uLiteral(cb, 0);
12751//-- uInstr1(cb, PUSH, 4, TempReg, t4);
12752//--
12753//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_CPUID));
12754//-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
12755//--
12756//-- uInstr1(cb, POP, 4, TempReg, t4);
12757//-- uInstr2(cb, PUT, 4, TempReg, t4, ArchReg, R_EDX);
12758//--
12759//-- uInstr1(cb, POP, 4, TempReg, t3);
12760//-- uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_ECX);
12761//--
12762//-- uInstr1(cb, POP, 4, TempReg, t2);
12763//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_EBX);
12764//--
12765//-- uInstr1(cb, POP, 4, TempReg, t1);
12766//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_EAX);
12767//--
12768//-- uInstr0(cb, CALLM_E, 0);
12769//-- DIP("cpuid\n");
12770//-- break;
12771//--
sewardj9334b0f2004-07-10 22:43:54 +000012772 /* =-=-=-=-=-=-=-=-=- MOVZX, MOVSX =-=-=-=-=-=-=-= */
12773
12774 case 0xB6: /* MOVZXb Eb,Gv */
12775 delta = dis_movx_E_G ( sorb, delta, 1, 4, False );
12776 break;
sewardj940e8c92004-07-11 16:53:24 +000012777 case 0xB7: /* MOVZXw Ew,Gv */
12778 delta = dis_movx_E_G ( sorb, delta, 2, 4, False );
12779 break;
12780
sewardj0611d802004-07-11 02:37:54 +000012781 case 0xBE: /* MOVSXb Eb,Gv */
12782 delta = dis_movx_E_G ( sorb, delta, 1, 4, True );
12783 break;
sewardj7ed22952004-07-29 00:09:58 +000012784 case 0xBF: /* MOVSXw Ew,Gv */
12785 delta = dis_movx_E_G ( sorb, delta, 2, 4, True );
12786 break;
12787
sewardjc9a65702004-07-07 16:32:57 +000012788//-- /* =-=-=-=-=-=-=-=-=-=-= MOVNTI -=-=-=-=-=-=-=-=-= */
12789//--
12790//-- case 0xC3: /* MOVNTI Gv,Ev */
12791//-- vg_assert(sz == 4);
12792//-- modrm = getUChar(eip);
12793//-- vg_assert(!epartIsReg(modrm));
12794//-- t1 = newTemp(cb);
12795//-- uInstr2(cb, GET, 4, ArchReg, gregOfRM(modrm), TempReg, t1);
12796//-- pair = disAMode ( cb, sorb, eip, dis_buf );
12797//-- t2 = LOW24(pair);
12798//-- eip += HI8(pair);
12799//-- uInstr2(cb, STORE, 4, TempReg, t1, TempReg, t2);
12800//-- DIP("movnti %s,%s\n", nameIReg(4,gregOfRM(modrm)), dis_buf);
12801//-- break;
sewardjcf780b42004-07-13 18:42:17 +000012802
12803 /* =-=-=-=-=-=-=-=-=- MUL/IMUL =-=-=-=-=-=-=-=-=-= */
12804
12805 case 0xAF: /* IMUL Ev, Gv */
sewardj2a2ba8b2004-11-08 13:14:06 +000012806 delta = dis_mul_E_G ( sorb, sz, delta );
sewardjcf780b42004-07-13 18:42:17 +000012807 break;
sewardje87b4842004-07-10 12:23:30 +000012808
12809 /* =-=-=-=-=-=-=-=-=- Jcond d32 -=-=-=-=-=-=-=-=-= */
12810 case 0x80:
12811 case 0x81:
12812 case 0x82: /* JBb/JNAEb (jump below) */
12813 case 0x83: /* JNBb/JAEb (jump not below) */
12814 case 0x84: /* JZb/JEb (jump zero) */
12815 case 0x85: /* JNZb/JNEb (jump not zero) */
12816 case 0x86: /* JBEb/JNAb (jump below or equal) */
12817 case 0x87: /* JNBEb/JAb (jump not below or equal) */
12818 case 0x88: /* JSb (jump negative) */
12819 case 0x89: /* JSb (jump not negative) */
12820 case 0x8A: /* JP (jump parity even) */
12821 case 0x8B: /* JNP/JPO (jump parity odd) */
12822 case 0x8C: /* JLb/JNGEb (jump less) */
12823 case 0x8D: /* JGEb/JNLb (jump greater or equal) */
12824 case 0x8E: /* JLEb/JNGb (jump less or equal) */
12825 case 0x8F: /* JGb/JNLEb (jump greater) */
sewardj4fd30f22004-10-25 00:42:16 +000012826 d32 = (((Addr32)guest_eip_bbstart)+delta+4) + getUDisp32(delta);
sewardje87b4842004-07-10 12:23:30 +000012827 delta += 4;
sewardj2a9ad022004-11-25 02:46:58 +000012828 jcc_01( (X86Condcode)(opc - 0x80),
12829 (Addr32)(guest_eip_bbstart+delta),
12830 d32 );
sewardjce70a5c2004-10-18 14:09:54 +000012831 whatNext = Dis_StopHere;
sewardj2a9ad022004-11-25 02:46:58 +000012832 DIP("j%s-32 0x%x\n", name_X86Condcode(opc - 0x80), d32);
sewardje87b4842004-07-10 12:23:30 +000012833 break;
12834
sewardj89cd0932004-09-08 18:23:25 +000012835 /* =-=-=-=-=-=-=-=-=- RDTSC -=-=-=-=-=-=-=-=-=-=-= */
12836
12837 case 0x31: /* RDTSC */
12838 vex_printf("vex x86->IR: kludged rdtsc\n");
12839 putIReg(4, R_EAX, mkU32(0));
12840 putIReg(4, R_EDX, mkU32(0));
12841
sewardjc9a65702004-07-07 16:32:57 +000012842//-- t1 = newTemp(cb);
12843//-- t2 = newTemp(cb);
12844//-- t3 = newTemp(cb);
12845//-- uInstr0(cb, CALLM_S, 0);
12846//-- // Nb: even though these args aren't used by RDTSC_helper, need
12847//-- // them to be defined (for Memcheck). The TempRegs pushed must
12848//-- // also be distinct.
12849//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t1);
12850//-- uLiteral(cb, 0);
12851//-- uInstr1(cb, PUSH, 4, TempReg, t1);
12852//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
12853//-- uLiteral(cb, 0);
12854//-- uInstr1(cb, PUSH, 4, TempReg, t2);
12855//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_RDTSC));
12856//-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
12857//-- uInstr1(cb, POP, 4, TempReg, t3);
12858//-- uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_EDX);
12859//-- uInstr1(cb, POP, 4, TempReg, t3);
12860//-- uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_EAX);
12861//-- uInstr0(cb, CALLM_E, 0);
sewardj89cd0932004-09-08 18:23:25 +000012862 DIP("rdtsc\n");
12863 break;
sewardj77b86be2004-07-11 13:28:24 +000012864
sewardjb64821b2004-12-14 10:00:16 +000012865 /* =-=-=-=-=-=-=-=-=- PUSH/POP Sreg =-=-=-=-=-=-=-=-=-= */
12866
12867 case 0xA1: /* POP %FS */
12868 dis_pop_segreg( R_FS, sz ); break;
12869 case 0xA9: /* POP %GS */
12870 dis_pop_segreg( R_GS, sz ); break;
12871
12872 case 0xA0: /* PUSH %FS */
12873 dis_push_segreg( R_FS, sz ); break;
12874 case 0xA8: /* PUSH %GS */
12875 dis_push_segreg( R_GS, sz ); break;
12876
sewardj77b86be2004-07-11 13:28:24 +000012877 /* =-=-=-=-=-=-=-=-=- SETcc Eb =-=-=-=-=-=-=-=-=-= */
12878 case 0x90:
12879 case 0x91:
12880 case 0x92: /* set-Bb/set-NAEb (jump below) */
12881 case 0x93: /* set-NBb/set-AEb (jump not below) */
12882 case 0x94: /* set-Zb/set-Eb (jump zero) */
12883 case 0x95: /* set-NZb/set-NEb (jump not zero) */
12884 case 0x96: /* set-BEb/set-NAb (jump below or equal) */
12885 case 0x97: /* set-NBEb/set-Ab (jump not below or equal) */
12886 case 0x98: /* set-Sb (jump negative) */
12887 case 0x99: /* set-Sb (jump not negative) */
12888 case 0x9A: /* set-P (jump parity even) */
12889 case 0x9B: /* set-NP (jump parity odd) */
12890 case 0x9C: /* set-Lb/set-NGEb (jump less) */
12891 case 0x9D: /* set-GEb/set-NLb (jump greater or equal) */
12892 case 0x9E: /* set-LEb/set-NGb (jump less or equal) */
12893 case 0x9F: /* set-Gb/set-NLEb (jump greater) */
sewardj5bd4d162004-11-10 13:02:48 +000012894 t1 = newTemp(Ity_I8);
sewardj2a9ad022004-11-25 02:46:58 +000012895 assign( t1, unop(Iop_1Uto8,mk_x86g_calculate_condition(opc-0x90)) );
sewardj77b86be2004-07-11 13:28:24 +000012896 modrm = getIByte(delta);
12897 if (epartIsReg(modrm)) {
12898 delta++;
sewardj5bd4d162004-11-10 13:02:48 +000012899 putIReg(1, eregOfRM(modrm), mkexpr(t1));
sewardj2a9ad022004-11-25 02:46:58 +000012900 DIP("set%s %s\n", name_X86Condcode(opc-0x90),
sewardj77b86be2004-07-11 13:28:24 +000012901 nameIReg(1,eregOfRM(modrm)));
12902 } else {
sewardj750f4072004-07-26 22:39:11 +000012903 addr = disAMode ( &alen, sorb, delta, dis_buf );
12904 delta += alen;
12905 storeLE( mkexpr(addr), mkexpr(t1) );
sewardj2a9ad022004-11-25 02:46:58 +000012906 DIP("set%s %s\n", name_X86Condcode(opc-0x90), dis_buf);
sewardj77b86be2004-07-11 13:28:24 +000012907 }
12908 break;
12909
sewardj180e8b32004-07-29 01:40:11 +000012910 /* =-=-=-=-=-=-=-=-=- SHLD/SHRD -=-=-=-=-=-=-=-=-= */
12911
12912 case 0xA4: /* SHLDv imm8,Gv,Ev */
12913 modrm = getIByte(delta);
12914 d32 = delta + lengthAMode(delta);
12915 vex_sprintf(dis_buf, "$%d", delta);
12916 delta = dis_SHLRD_Gv_Ev (
12917 sorb, delta, modrm, sz,
12918 mkU8(getIByte(d32)), True, /* literal */
12919 dis_buf, True );
12920 break;
sewardja06e5562004-07-14 13:18:05 +000012921 case 0xA5: /* SHLDv %cl,Gv,Ev */
12922 modrm = getIByte(delta);
12923 delta = dis_SHLRD_Gv_Ev (
12924 sorb, delta, modrm, sz,
12925 getIReg(1,R_ECX), False, /* not literal */
12926 "%cl", True );
12927 break;
12928
sewardj68511542004-07-28 00:15:44 +000012929 case 0xAC: /* SHRDv imm8,Gv,Ev */
12930 modrm = getIByte(delta);
12931 d32 = delta + lengthAMode(delta);
12932 vex_sprintf(dis_buf, "$%d", delta);
12933 delta = dis_SHLRD_Gv_Ev (
12934 sorb, delta, modrm, sz,
12935 mkU8(getIByte(d32)), True, /* literal */
12936 dis_buf, False );
12937 break;
sewardja511afc2004-07-29 22:26:03 +000012938 case 0xAD: /* SHRDv %cl,Gv,Ev */
12939 modrm = getIByte(delta);
12940 delta = dis_SHLRD_Gv_Ev (
12941 sorb, delta, modrm, sz,
12942 getIReg(1,R_ECX), False, /* not literal */
12943 "%cl", False );
12944 break;
12945
sewardj464efa42004-11-19 22:17:29 +000012946 /* =-=-=-=-=-=-=-=-=- XADD -=-=-=-=-=-=-=-=-=-= */
12947
sewardjc9a65702004-07-07 16:32:57 +000012948//-- case 0xC0: /* XADD Gb,Eb */
12949//-- eip = dis_xadd_G_E ( cb, sorb, 1, eip );
12950//-- break;
sewardj883b00b2004-09-11 09:30:24 +000012951 case 0xC1: /* XADD Gv,Ev */
12952 delta = dis_xadd_G_E ( sorb, sz, delta );
12953 break;
12954
sewardjf13f37b2004-12-08 17:01:23 +000012955 /* =-=-=-=-=-=-=-=-=- MMXery =-=-=-=-=-=-=-=-=-=-= */
sewardj464efa42004-11-19 22:17:29 +000012956
sewardj2b7a9202004-11-26 19:15:38 +000012957 case 0x71:
12958 case 0x72:
12959 case 0x73: /* (sz==4): PSLLgg/PSRAgg/PSRLgg mmxreg by imm8 */
12960 /* If sz==2 this is SSE, and we assume sse idec has
12961 already spotted those cases by now. */
sewardjb9fa69b2004-12-09 23:25:14 +000012962 if (sz == 2)
12963 goto decode_failure;
sewardj2b7a9202004-11-26 19:15:38 +000012964
12965 case 0x6E: /* MOVD (src)ireg-or-mem, (dst)mmxreg */
12966 case 0x7E: /* MOVD (src)mmxreg, (dst)ireg-or-mem */
sewardj464efa42004-11-19 22:17:29 +000012967 case 0x7F: /* MOVQ (src)mmxreg, (dst)mmxreg-or-mem */
sewardj2b7a9202004-11-26 19:15:38 +000012968 case 0x6F: /* MOVQ (src)mmxreg-or-mem, (dst)mmxreg */
sewardj464efa42004-11-19 22:17:29 +000012969
12970 case 0xFC:
12971 case 0xFD:
12972 case 0xFE: /* PADDgg (src)mmxreg-or-mem, (dst)mmxreg */
12973
12974 case 0xEC:
12975 case 0xED: /* PADDSgg (src)mmxreg-or-mem, (dst)mmxreg */
12976
12977 case 0xDC:
12978 case 0xDD: /* PADDUSgg (src)mmxreg-or-mem, (dst)mmxreg */
12979
12980 case 0xF8:
12981 case 0xF9:
12982 case 0xFA: /* PSUBgg (src)mmxreg-or-mem, (dst)mmxreg */
12983
12984 case 0xE8:
12985 case 0xE9: /* PSUBSgg (src)mmxreg-or-mem, (dst)mmxreg */
12986
12987 case 0xD8:
12988 case 0xD9: /* PSUBUSgg (src)mmxreg-or-mem, (dst)mmxreg */
12989
12990 case 0xE5: /* PMULHW (src)mmxreg-or-mem, (dst)mmxreg */
12991 case 0xD5: /* PMULLW (src)mmxreg-or-mem, (dst)mmxreg */
12992
sewardj4340dac2004-11-20 13:17:04 +000012993 case 0xF5: /* PMADDWD (src)mmxreg-or-mem, (dst)mmxreg */
12994
12995 case 0x74:
12996 case 0x75:
12997 case 0x76: /* PCMPEQgg (src)mmxreg-or-mem, (dst)mmxreg */
12998
12999 case 0x64:
13000 case 0x65:
13001 case 0x66: /* PCMPGTgg (src)mmxreg-or-mem, (dst)mmxreg */
13002
sewardj63ba4092004-11-21 12:30:18 +000013003 case 0x6B: /* PACKSSDW (src)mmxreg-or-mem, (dst)mmxreg */
13004 case 0x63: /* PACKSSWB (src)mmxreg-or-mem, (dst)mmxreg */
13005 case 0x67: /* PACKUSWB (src)mmxreg-or-mem, (dst)mmxreg */
13006
13007 case 0x68:
13008 case 0x69:
13009 case 0x6A: /* PUNPCKHgg (src)mmxreg-or-mem, (dst)mmxreg */
13010
13011 case 0x60:
13012 case 0x61:
13013 case 0x62: /* PUNPCKLgg (src)mmxreg-or-mem, (dst)mmxreg */
13014
13015 case 0xDB: /* PAND (src)mmxreg-or-mem, (dst)mmxreg */
13016 case 0xDF: /* PANDN (src)mmxreg-or-mem, (dst)mmxreg */
13017 case 0xEB: /* POR (src)mmxreg-or-mem, (dst)mmxreg */
13018 case 0xEF: /* PXOR (src)mmxreg-or-mem, (dst)mmxreg */
13019
sewardj8d14a592004-11-21 17:04:50 +000013020 case 0xF1:
13021 case 0xF2:
13022 case 0xF3: /* PSLLgg (src)mmxreg-or-mem, (dst)mmxreg */
13023
13024 case 0xD1:
13025 case 0xD2:
13026 case 0xD3: /* PSRLgg (src)mmxreg-or-mem, (dst)mmxreg */
13027
13028 case 0xE1:
13029 case 0xE2: /* PSRAgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj464efa42004-11-19 22:17:29 +000013030 {
13031 UInt delta0 = delta-1;
13032 Bool decode_OK = False;
13033 delta = dis_MMX ( &decode_OK, sorb, sz, delta-1 );
13034 if (!decode_OK) {
13035 delta = delta0;
13036 goto decode_failure;
13037 }
13038 break;
13039 }
13040
sewardj8d14a592004-11-21 17:04:50 +000013041 case 0x77: /* EMMS */
13042 vassert(sz == 4);
sewardj4cb918d2004-12-03 19:43:31 +000013043 do_EMMS_preamble();
sewardj8d14a592004-11-21 17:04:50 +000013044 DIP("emms\n");
13045 break;
13046
sewardje87b4842004-07-10 12:23:30 +000013047 /* =-=-=-=-=-=-=-=-=- unimp2 =-=-=-=-=-=-=-=-=-=-= */
13048
13049 default:
13050 goto decode_failure;
13051 } /* switch (opc) for the 2-byte opcodes */
13052 goto decode_success;
13053 } /* case 0x0F: of primary opcode */
sewardjc9a65702004-07-07 16:32:57 +000013054
13055 /* ------------------------ ??? ------------------------ */
13056
13057 default:
sewardje87b4842004-07-10 12:23:30 +000013058 decode_failure:
sewardjc9a65702004-07-07 16:32:57 +000013059 /* All decode failures end up here. */
sewardj52444cb2004-12-13 14:09:01 +000013060 vex_printf("vex x86->IR: unhandled instruction bytes: "
sewardjc9a65702004-07-07 16:32:57 +000013061 "0x%x 0x%x 0x%x 0x%x\n",
13062 (Int)getIByte(delta_start+0),
13063 (Int)getIByte(delta_start+1),
13064 (Int)getIByte(delta_start+2),
13065 (Int)getIByte(delta_start+3) );
sewardj52444cb2004-12-13 14:09:01 +000013066
sewardjb64821b2004-12-14 10:00:16 +000013067 /* Tell the dispatcher that this insn cannot be decoded, and so has
13068 not been executed, and (is currently) the next to be executed.
13069 EIP should be up-to-date since it made so at the start of each
13070 insn, but nevertheless be paranoid and update it again right
13071 now. */
sewardj52444cb2004-12-13 14:09:01 +000013072 stmt( IRStmt_Put( OFFB_EIP, mkU32(guest_eip_curr_instr) ) );
13073 jmp_lit(Ijk_NoDecode, guest_eip_curr_instr);
13074 whatNext = Dis_StopHere;
13075 *size = 0;
13076 return whatNext;
13077
sewardjc9a65702004-07-07 16:32:57 +000013078 /* Print address of failing instruction. */
13079 //VG_(describe_eip)((Addr)eip_start, loc_buf, M_VG_ERRTXT);
13080 //VG_(printf)(" at %s\n", loc_buf);
13081
13082 //uInstr0(cb, CALLM_S, 0);
13083 //uInstr1(cb, CALLM, 0, Lit16,
13084 // VGOFF_(helper_undefined_instruction));
13085 //uInstr0(cb, CALLM_E, 0);
13086
13087 /* just because everything else insists the last instruction of
13088 a BB is a jmp */
13089 //jmp_lit(cb, eip);
sewardjce70a5c2004-10-18 14:09:54 +000013090 //whatNext = Dis_StopHere;
sewardjc9a65702004-07-07 16:32:57 +000013091 //break;
13092 //return eip;
13093
13094 } /* switch (opc) for the main (primary) opcode switch. */
13095
sewardje87b4842004-07-10 12:23:30 +000013096 decode_success:
sewardjc9a65702004-07-07 16:32:57 +000013097 /* All decode successes end up here. */
13098 DIP("\n");
sewardjc9a65702004-07-07 16:32:57 +000013099
sewardjce70a5c2004-10-18 14:09:54 +000013100 *size = delta - delta_start;
13101 return whatNext;
sewardjc9a65702004-07-07 16:32:57 +000013102}
13103
13104#undef DIP
13105#undef DIS
13106
13107/*--------------------------------------------------------------------*/
sewardjc0ee2ed2004-07-27 10:29:41 +000013108/*--- end guest-x86/toIR.c ---*/
sewardjc9a65702004-07-07 16:32:57 +000013109/*--------------------------------------------------------------------*/