blob: e4bc2131c4a6ae00d0ff6e2850aba14de343636e [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.
sewardje05c42c2004-07-08 20:25:10 +000052*/
53
sewardjc9a65702004-07-07 16:32:57 +000054/* Translates x86 code to IR. */
55
56#include "libvex_basictypes.h"
57#include "libvex_ir.h"
sewardje87b4842004-07-10 12:23:30 +000058#include "libvex.h"
sewardjf6dc3ce2004-10-19 01:03:46 +000059#include "libvex_guest_x86.h"
sewardjc0ee2ed2004-07-27 10:29:41 +000060
61#include "main/vex_util.h"
62#include "main/vex_globals.h"
63#include "guest-x86/gdefs.h"
sewardjc9a65702004-07-07 16:32:57 +000064
65
66/*------------------------------------------------------------*/
67/*--- Globals ---*/
68/*------------------------------------------------------------*/
69
70/* These are set at the start of the translation of a BB, so
71 that we don't have to pass them around endlessly. */
72
73/* We need to know this to do sub-register accesses correctly. */
74/* CONST */
75static Bool host_is_bigendian;
76
sewardjc9a65702004-07-07 16:32:57 +000077/* Pointer to the guest code area. */
78/* CONST */
79static UChar* guest_code;
80
81/* The guest address corresponding to guest_code[0]. */
82/* CONST */
sewardjce70a5c2004-10-18 14:09:54 +000083static Addr32 guest_eip_bbstart;
sewardjc9a65702004-07-07 16:32:57 +000084
sewardjd7cb8532004-08-17 23:59:23 +000085/* The IRBB* into which we're generating code. */
sewardjc9a65702004-07-07 16:32:57 +000086static IRBB* irbb;
87
sewardjc9a65702004-07-07 16:32:57 +000088
sewardjce70a5c2004-10-18 14:09:54 +000089/*------------------------------------------------------------*/
90/*--- Debugging output ---*/
91/*------------------------------------------------------------*/
92
sewardjf48ac192004-10-29 00:41:29 +000093#define DIP(format, args...) \
94 if (vex_traceflags & VEX_TRACE_FE) \
sewardjce70a5c2004-10-18 14:09:54 +000095 vex_printf(format, ## args)
96
sewardjf48ac192004-10-29 00:41:29 +000097#define DIS(buf, format, args...) \
98 if (vex_traceflags & VEX_TRACE_FE) \
sewardjce70a5c2004-10-18 14:09:54 +000099 vex_sprintf(buf, format, ## args)
100
101
102/*------------------------------------------------------------*/
sewardjdcc85fc2004-10-26 13:26:20 +0000103/*--- Offsets of various parts of the x86 guest state. ---*/
104/*------------------------------------------------------------*/
105
sewardjc9a43662004-11-30 18:51:59 +0000106#define OFFB_EAX offsetof(VexGuestX86State,guest_EAX)
107#define OFFB_EBX offsetof(VexGuestX86State,guest_EBX)
108#define OFFB_ECX offsetof(VexGuestX86State,guest_ECX)
109#define OFFB_EDX offsetof(VexGuestX86State,guest_EDX)
110#define OFFB_ESP offsetof(VexGuestX86State,guest_ESP)
111#define OFFB_EBP offsetof(VexGuestX86State,guest_EBP)
112#define OFFB_ESI offsetof(VexGuestX86State,guest_ESI)
113#define OFFB_EDI offsetof(VexGuestX86State,guest_EDI)
sewardj2a2ba8b2004-11-08 13:14:06 +0000114
sewardjc9a43662004-11-30 18:51:59 +0000115#define OFFB_EIP offsetof(VexGuestX86State,guest_EIP)
sewardj2a2ba8b2004-11-08 13:14:06 +0000116
sewardjc9a43662004-11-30 18:51:59 +0000117#define OFFB_CC_OP offsetof(VexGuestX86State,guest_CC_OP)
118#define OFFB_CC_DEP1 offsetof(VexGuestX86State,guest_CC_DEP1)
119#define OFFB_CC_DEP2 offsetof(VexGuestX86State,guest_CC_DEP2)
120#define OFFB_CC_NDEP offsetof(VexGuestX86State,guest_CC_NDEP)
sewardj893aada2004-11-29 19:57:54 +0000121
sewardjc9a43662004-11-30 18:51:59 +0000122#define OFFB_FPREGS offsetof(VexGuestX86State,guest_FPREG[0])
123#define OFFB_FPTAGS offsetof(VexGuestX86State,guest_FPTAG[0])
124#define OFFB_DFLAG offsetof(VexGuestX86State,guest_DFLAG)
125#define OFFB_IDFLAG offsetof(VexGuestX86State,guest_IDFLAG)
126#define OFFB_FTOP offsetof(VexGuestX86State,guest_FTOP)
127#define OFFB_FC3210 offsetof(VexGuestX86State,guest_FC3210)
128#define OFFB_FPROUND offsetof(VexGuestX86State,guest_FPROUND)
129
130#define OFFB_CS offsetof(VexGuestX86State,guest_CS)
131#define OFFB_DS offsetof(VexGuestX86State,guest_DS)
132#define OFFB_ES offsetof(VexGuestX86State,guest_ES)
133#define OFFB_FS offsetof(VexGuestX86State,guest_FS)
134#define OFFB_GS offsetof(VexGuestX86State,guest_GS)
135#define OFFB_SS offsetof(VexGuestX86State,guest_SS)
136
137#define OFFB_SSEROUND offsetof(VexGuestX86State,guest_SSEROUND)
138#define OFFB_XMM0 offsetof(VexGuestX86State,guest_XMM0)
139#define OFFB_XMM1 offsetof(VexGuestX86State,guest_XMM1)
140#define OFFB_XMM2 offsetof(VexGuestX86State,guest_XMM2)
141#define OFFB_XMM3 offsetof(VexGuestX86State,guest_XMM3)
142#define OFFB_XMM4 offsetof(VexGuestX86State,guest_XMM4)
143#define OFFB_XMM5 offsetof(VexGuestX86State,guest_XMM5)
144#define OFFB_XMM6 offsetof(VexGuestX86State,guest_XMM6)
145#define OFFB_XMM7 offsetof(VexGuestX86State,guest_XMM7)
146
147#define OFFB_EMWARN offsetof(VexGuestX86State,guest_EMWARN)
sewardjdcc85fc2004-10-26 13:26:20 +0000148
149
150/*------------------------------------------------------------*/
sewardjce70a5c2004-10-18 14:09:54 +0000151/*--- Disassemble an entire basic block ---*/
152/*------------------------------------------------------------*/
153
154/* The results of disassembling an instruction. There are three
155 possible outcomes. For Dis_Resteer, the disassembler _must_
156 continue at the specified address. For Dis_StopHere, the
157 disassembler _must_ terminate the BB. For Dis_Continue, we may at
158 our option either disassemble the next insn, or terminate the BB;
159 but in the latter case we must set the bb's ->next field to point
160 to the next instruction. */
161
162typedef
163 enum {
164 Dis_StopHere, /* this insn terminates the BB; we must stop. */
165 Dis_Continue, /* we can optionally continue into the next insn */
166 Dis_Resteer /* followed a branch; continue at the spec'd addr */
167 }
168 DisResult;
169
170
171/* forward decls .. */
172static IRExpr* mkU32 ( UInt i );
sewardjdcc85fc2004-10-26 13:26:20 +0000173static void stmt ( IRStmt* st );
174
sewardjce70a5c2004-10-18 14:09:54 +0000175
176/* disInstr disassembles an instruction located at &guest_code[delta],
177 and sets *size to its size. If the returned value is Dis_Resteer,
sewardj5bd4d162004-11-10 13:02:48 +0000178 the next guest address is assigned to *whereNext. disInstr is not
179 permitted to return Dis_Resteer if either (1) resteerOK is False,
180 or (2) resteerOkFn, when applied to the address which it wishes to
181 resteer into, returns False. */
sewardjce70a5c2004-10-18 14:09:54 +0000182
183static DisResult disInstr ( /*IN*/ Bool resteerOK,
sewardj5bd4d162004-11-10 13:02:48 +0000184 /*IN*/ Bool (*resteerOkFn) ( Addr64 ),
sewardjce70a5c2004-10-18 14:09:54 +0000185 /*IN*/ UInt delta,
186 /*OUT*/ UInt* size,
187 /*OUT*/ Addr64* whereNext );
188
189
190/* This is the main (only, in fact) entry point for this module. */
191
192/* Disassemble a complete basic block, starting at eip, and dumping
193 the ucode into cb. Returns the size, in bytes, of the basic
194 block. */
sewardj2a9ad022004-11-25 02:46:58 +0000195IRBB* bbToIR_X86 ( UChar* x86code,
196 Addr64 guest_eip_start,
197 Int* guest_bytes_read,
198 Bool (*byte_accessible)(Addr64),
199 Bool (*chase_into_ok)(Addr64),
200 Bool host_bigendian )
sewardjce70a5c2004-10-18 14:09:54 +0000201{
202 UInt delta;
sewardjdcc85fc2004-10-26 13:26:20 +0000203 Int i, n_instrs, size, first_stmt_idx;
sewardjce70a5c2004-10-18 14:09:54 +0000204 Addr64 guest_next;
205 Bool resteerOK;
206 DisResult dres;
207 static Int n_resteers = 0;
208 Int d_resteers = 0;
sewardj08613742004-10-25 13:01:45 +0000209
210 /* check sanity .. */
211 vassert(vex_control.guest_max_insns >= 1);
212 vassert(vex_control.guest_max_insns < 1000);
213 vassert(vex_control.guest_chase_thresh >= 0);
214 vassert(vex_control.guest_chase_thresh < vex_control.guest_max_insns);
sewardjce70a5c2004-10-18 14:09:54 +0000215
216 /* Set up globals. */
217 host_is_bigendian = host_bigendian;
sewardjce70a5c2004-10-18 14:09:54 +0000218 guest_code = x86code;
219 guest_eip_bbstart = (Addr32)guest_eip_start;
220 irbb = emptyIRBB();
221
sewardjce70a5c2004-10-18 14:09:54 +0000222 vassert((guest_eip_start >> 32) == 0);
sewardjce70a5c2004-10-18 14:09:54 +0000223
sewardjce70a5c2004-10-18 14:09:54 +0000224 /* Delta keeps track of how far along the x86code array we
225 have so far gone. */
226 delta = 0;
227 n_instrs = 0;
228 *guest_bytes_read = 0;
229
230 while (True) {
sewardj08613742004-10-25 13:01:45 +0000231 vassert(n_instrs < vex_control.guest_max_insns);
sewardjce70a5c2004-10-18 14:09:54 +0000232
233 guest_next = 0;
sewardj08613742004-10-25 13:01:45 +0000234 resteerOK = n_instrs < vex_control.guest_chase_thresh;
sewardjdcc85fc2004-10-26 13:26:20 +0000235 first_stmt_idx = irbb->stmts_used;
236
237 if (n_instrs > 0) {
238 /* for the first insn, the dispatch loop will have set
sewardj5bd4d162004-11-10 13:02:48 +0000239 %EIP, but for all the others we have to do it ourselves. */
sewardjdcc85fc2004-10-26 13:26:20 +0000240 stmt( IRStmt_Put( OFFB_EIP, mkU32(guest_eip_bbstart + delta)) );
241 }
242
sewardj5bd4d162004-11-10 13:02:48 +0000243 dres = disInstr( resteerOK, chase_into_ok,
244 delta, &size, &guest_next );
sewardjdcc85fc2004-10-26 13:26:20 +0000245
246 /* Print the resulting IR, if needed. */
sewardjf48ac192004-10-29 00:41:29 +0000247 if (vex_traceflags & VEX_TRACE_FE) {
sewardjdcc85fc2004-10-26 13:26:20 +0000248 for (i = first_stmt_idx; i < irbb->stmts_used; i++) {
249 vex_printf(" ");
250 ppIRStmt(irbb->stmts[i]);
251 vex_printf("\n");
252 }
253 }
254
255 if (dres == Dis_StopHere) {
256 vassert(irbb->next != NULL);
sewardjf48ac192004-10-29 00:41:29 +0000257 if (vex_traceflags & VEX_TRACE_FE) {
sewardjdcc85fc2004-10-26 13:26:20 +0000258 vex_printf(" ");
259 vex_printf( "goto {");
260 ppIRJumpKind(irbb->jumpkind);
261 vex_printf( "} ");
262 ppIRExpr( irbb->next );
263 vex_printf( "\n");
264 }
265 }
266
sewardjce70a5c2004-10-18 14:09:54 +0000267 delta += size;
268 *guest_bytes_read += size;
269 n_instrs++;
270 DIP("\n");
271
272 vassert(size > 0 && size <= 18);
273 if (!resteerOK)
274 vassert(dres != Dis_Resteer);
275 if (dres != Dis_Resteer)
276 vassert(guest_next == 0);
277
278 switch (dres) {
279 case Dis_Continue:
280 vassert(irbb->next == NULL);
sewardj08613742004-10-25 13:01:45 +0000281 if (n_instrs < vex_control.guest_max_insns) {
sewardjce70a5c2004-10-18 14:09:54 +0000282 /* keep going */
283 } else {
284 irbb->next = mkU32(((Addr32)guest_eip_start)+delta);
285 return irbb;
286 }
287 break;
288 case Dis_StopHere:
289 vassert(irbb->next != NULL);
290 return irbb;
291 case Dis_Resteer:
292 vassert(irbb->next == NULL);
293 /* figure out a new delta to continue at. */
sewardj5bd4d162004-11-10 13:02:48 +0000294 vassert(chase_into_ok(guest_next));
sewardjce70a5c2004-10-18 14:09:54 +0000295 delta = (UInt)(guest_next - guest_eip_start);
296 n_resteers++;
297 d_resteers++;
298 if (0 && (n_resteers & 0xFF) == 0)
sewardj5bd4d162004-11-10 13:02:48 +0000299 vex_printf("resteer[%d,%d] to %p (delta = %d)\n",
300 n_resteers, d_resteers,
sewardjce70a5c2004-10-18 14:09:54 +0000301 (void*)(UInt)(guest_next), delta);
302 break;
303 }
304 }
305}
306
307
308/*------------------------------------------------------------*/
309/*--- Helper bits and pieces for deconstructing the ---*/
310/*--- x86 insn stream. ---*/
311/*------------------------------------------------------------*/
312
313/* This is the Intel register encoding -- integer regs. */
314#define R_EAX 0
315#define R_ECX 1
316#define R_EDX 2
317#define R_EBX 3
318#define R_ESP 4
319#define R_EBP 5
320#define R_ESI 6
321#define R_EDI 7
322
323#define R_AL (0+R_EAX)
324#define R_AH (4+R_EAX)
325
sewardj063f02f2004-10-20 12:36:12 +0000326/* This is the Intel register encoding -- segment regs. */
327#define R_ES 0
328#define R_CS 1
329#define R_SS 2
330#define R_DS 3
331#define R_FS 4
332#define R_GS 5
333
sewardjce70a5c2004-10-18 14:09:54 +0000334
sewardjc9a65702004-07-07 16:32:57 +0000335/* Add a statement to the list held by "irbb". */
sewardjd7cb8532004-08-17 23:59:23 +0000336static void stmt ( IRStmt* st )
sewardjc9a65702004-07-07 16:32:57 +0000337{
sewardjd7cb8532004-08-17 23:59:23 +0000338 addStmtToIRBB( irbb, st );
sewardjc9a65702004-07-07 16:32:57 +0000339}
340
341/* Generate a new temporary of the given type. */
342static IRTemp newTemp ( IRType ty )
343{
sewardj6d2638e2004-07-15 09:38:27 +0000344 vassert(isPlausibleType(ty));
sewardje539a402004-07-14 18:24:17 +0000345 return newIRTemp( irbb->tyenv, ty );
sewardjc9a65702004-07-07 16:32:57 +0000346}
347
sewardjc9a65702004-07-07 16:32:57 +0000348/* Bomb out if we can't handle something. */
sewardjd1061ab2004-07-08 01:45:30 +0000349__attribute__ ((noreturn))
sewardjc9a65702004-07-07 16:32:57 +0000350static void unimplemented ( Char* str )
351{
352 vex_printf("x86toIR: unimplemented feature\n");
353 vpanic(str);
354}
355
sewardjce70a5c2004-10-18 14:09:54 +0000356/* Various simple conversions */
sewardjd1061ab2004-07-08 01:45:30 +0000357
sewardje05c42c2004-07-08 20:25:10 +0000358static UInt extend_s_8to32( UInt x )
sewardjd1061ab2004-07-08 01:45:30 +0000359{
360 return (UInt)((((Int)x) << 24) >> 24);
361}
362
sewardj0611d802004-07-11 02:37:54 +0000363static UInt extend_s_16to32 ( UInt x )
364{
365 return (UInt)((((Int)x) << 16) >> 16);
366}
367
sewardjd1061ab2004-07-08 01:45:30 +0000368/* Fetch a byte from the guest insn stream. */
sewardje05c42c2004-07-08 20:25:10 +0000369static UChar getIByte ( UInt delta )
sewardjd1061ab2004-07-08 01:45:30 +0000370{
371 return guest_code[delta];
372}
373
sewardjc9a65702004-07-07 16:32:57 +0000374/* Extract the reg field from a modRM byte. */
sewardje05c42c2004-07-08 20:25:10 +0000375static Int gregOfRM ( UChar mod_reg_rm )
sewardjc9a65702004-07-07 16:32:57 +0000376{
377 return (Int)( (mod_reg_rm >> 3) & 7 );
378}
379
380/* Figure out whether the mod and rm parts of a modRM byte refer to a
381 register or memory. If so, the byte will have the form 11XXXYYY,
382 where YYY is the register number. */
sewardje05c42c2004-07-08 20:25:10 +0000383static Bool epartIsReg ( UChar mod_reg_rm )
sewardjc9a65702004-07-07 16:32:57 +0000384{
385 return (0xC0 == (mod_reg_rm & 0xC0));
386}
387
388/* ... and extract the register number ... */
sewardje05c42c2004-07-08 20:25:10 +0000389static Int eregOfRM ( UChar mod_reg_rm )
sewardjc9a65702004-07-07 16:32:57 +0000390{
391 return (Int)(mod_reg_rm & 0x7);
392}
393
sewardje05c42c2004-07-08 20:25:10 +0000394/* Get a 8/16/32-bit unsigned value out of the insn stream. */
395
396static UInt getUChar ( UInt delta )
397{
398 UInt v = guest_code[delta+0];
399 return v & 0xFF;
400}
401
402static UInt getUDisp16 ( UInt delta )
403{
404 UInt v = guest_code[delta+1]; v <<= 8;
405 v |= guest_code[delta+0];
406 return v & 0xFFFF;
407}
408
409static UInt getUDisp32 ( UInt delta )
sewardjd1061ab2004-07-08 01:45:30 +0000410{
411 UInt v = guest_code[delta+3]; v <<= 8;
412 v |= guest_code[delta+2]; v <<= 8;
413 v |= guest_code[delta+1]; v <<= 8;
414 v |= guest_code[delta+0];
415 return v;
416}
417
sewardje05c42c2004-07-08 20:25:10 +0000418static UInt getUDisp ( Int size, UInt delta )
419{
420 switch (size) {
421 case 4: return getUDisp32(delta);
422 case 2: return getUDisp16(delta);
423 case 1: return getUChar(delta);
424 default: vpanic("getUDisp(x86)");
425 }
426 return 0; /*notreached*/
427}
428
429
sewardjd1061ab2004-07-08 01:45:30 +0000430/* Get a byte value out of the insn stream and sign-extend to 32
431 bits. */
sewardje05c42c2004-07-08 20:25:10 +0000432static UInt getSDisp8 ( UInt delta )
sewardjd1061ab2004-07-08 01:45:30 +0000433{
434 return extend_s_8to32( (UInt) (guest_code[delta]) );
435}
436
sewardj0611d802004-07-11 02:37:54 +0000437static UInt getSDisp16 ( UInt delta0 )
438{
439 UChar* eip = (UChar*)(&guest_code[delta0]);
440 UInt d = *eip++;
441 d |= ((*eip++) << 8);
442 return extend_s_16to32(d);
443}
444
445static UInt getSDisp ( Int size, UInt delta )
446{
447 switch (size) {
448 case 4: return getUDisp32(delta);
449 case 2: return getSDisp16(delta);
450 case 1: return getSDisp8(delta);
451 default: vpanic("getSDisp(x86)");
452 }
453 return 0; /*notreached*/
454}
sewardjd1061ab2004-07-08 01:45:30 +0000455
sewardjc9a65702004-07-07 16:32:57 +0000456
457/*------------------------------------------------------------*/
458/*--- Helpers for constructing IR. ---*/
459/*------------------------------------------------------------*/
460
461/* Create a 1/2/4 byte read of an x86 integer registers. For 16/8 bit
462 register references, we need to take the host endianness into
463 account. Supplied value is 0 .. 7 and in the Intel instruction
464 encoding. */
sewardje05c42c2004-07-08 20:25:10 +0000465
sewardj9334b0f2004-07-10 22:43:54 +0000466static IRType szToITy ( Int n )
467{
468 switch (n) {
469 case 1: return Ity_I8;
470 case 2: return Ity_I16;
471 case 4: return Ity_I32;
472 default: vpanic("szToITy(x86)");
473 }
474}
475
sewardj67e002d2004-12-02 18:16:33 +0000476/* On a little-endian host, less significant bits of the guest
477 registers are at lower addresses. Therefore, if a reference to a
478 register low half has the safe guest state offset as a reference to
479 the full register.
480*/
sewardj9334b0f2004-07-10 22:43:54 +0000481static Int integerGuestRegOffset ( Int sz, UInt archreg )
482{
483 vassert(archreg < 8);
484
sewardj9334b0f2004-07-10 22:43:54 +0000485 /* Correct for little-endian host only. */
sewardj67e002d2004-12-02 18:16:33 +0000486 vassert(!host_is_bigendian);
sewardj063f02f2004-10-20 12:36:12 +0000487
488 if (sz == 4 || sz == 2 || (sz == 1 && archreg < 4)) {
489 switch (archreg) {
sewardjc9a43662004-11-30 18:51:59 +0000490 case R_EAX: return OFFB_EAX;
491 case R_EBX: return OFFB_EBX;
492 case R_ECX: return OFFB_ECX;
493 case R_EDX: return OFFB_EDX;
494 case R_ESI: return OFFB_ESI;
495 case R_EDI: return OFFB_EDI;
496 case R_ESP: return OFFB_ESP;
497 case R_EBP: return OFFB_EBP;
sewardj063f02f2004-10-20 12:36:12 +0000498 default: vpanic("integerGuestRegOffset(x86,le)(4,2)");
499 }
500 }
501
502 vassert(archreg >= 4 && archreg < 8 && sz == 1);
503 switch (archreg-4) {
sewardjc9a43662004-11-30 18:51:59 +0000504 case R_EAX: return 1+ OFFB_EAX;
505 case R_EBX: return 1+ OFFB_EBX;
506 case R_ECX: return 1+ OFFB_ECX;
507 case R_EDX: return 1+ OFFB_EDX;
sewardj063f02f2004-10-20 12:36:12 +0000508 default: vpanic("integerGuestRegOffset(x86,le)(1h)");
509 }
510
511 /* NOTREACHED */
512 vpanic("integerGuestRegOffset(x86,le)");
513}
514
515static Int segmentGuestRegOffset ( UInt sreg )
516{
517 switch (sreg) {
sewardjc9a43662004-11-30 18:51:59 +0000518 case R_ES: return OFFB_ES;
519 case R_CS: return OFFB_CS;
520 case R_SS: return OFFB_SS;
521 case R_DS: return OFFB_DS;
522 case R_FS: return OFFB_FS;
523 case R_GS: return OFFB_GS;
sewardj063f02f2004-10-20 12:36:12 +0000524 default: vpanic("segmentGuestRegOffset(x86)");
sewardj9334b0f2004-07-10 22:43:54 +0000525 }
526}
527
sewardjc9a43662004-11-30 18:51:59 +0000528static Int xmmGuestRegOffset ( UInt xmmreg )
529{
530 switch (xmmreg) {
531 case 0: return OFFB_XMM0;
532 case 1: return OFFB_XMM1;
533 case 2: return OFFB_XMM2;
534 case 3: return OFFB_XMM3;
535 case 4: return OFFB_XMM4;
536 case 5: return OFFB_XMM5;
537 case 6: return OFFB_XMM6;
538 case 7: return OFFB_XMM7;
539 default: vpanic("xmmGuestRegOffset");
540 }
541}
542
sewardj67e002d2004-12-02 18:16:33 +0000543/* Lanes of vector registers are always numbered from zero being the
544 least significant lane (rightmost in the register). */
545
546static Int xmmGuestRegLane32offset ( UInt xmmreg, Int laneno )
547{
548 /* Correct for little-endian host only. */
549 vassert(!host_is_bigendian);
550 vassert(laneno >= 0 && laneno < 4);
551 return xmmGuestRegOffset( xmmreg ) + 4 * laneno;
552}
553
554static Int xmmGuestRegLane64offset ( UInt xmmreg, Int laneno )
555{
556 /* Correct for little-endian host only. */
557 vassert(!host_is_bigendian);
558 vassert(laneno >= 0 && laneno < 2);
559 return xmmGuestRegOffset( xmmreg ) + 8 * laneno;
560}
561
sewardjd1061ab2004-07-08 01:45:30 +0000562static IRExpr* getIReg ( Int sz, UInt archreg )
sewardjc9a65702004-07-07 16:32:57 +0000563{
564 vassert(sz == 1 || sz == 2 || sz == 4);
565 vassert(archreg < 8);
sewardj9334b0f2004-07-10 22:43:54 +0000566 return IRExpr_Get( integerGuestRegOffset(sz,archreg),
sewardj5bd4d162004-11-10 13:02:48 +0000567 szToITy(sz) );
sewardjc9a65702004-07-07 16:32:57 +0000568}
569
570/* Ditto, but write to a reg instead. */
sewardj41f43bc2004-07-08 14:23:22 +0000571static void putIReg ( Int sz, UInt archreg, IRExpr* e )
sewardjc9a65702004-07-07 16:32:57 +0000572{
sewardjc9a43662004-11-30 18:51:59 +0000573 IRType ty = typeOfIRExpr(irbb->tyenv, e);
sewardjc9a65702004-07-07 16:32:57 +0000574 vassert(sz == 1 || sz == 2 || sz == 4);
575 vassert(archreg < 8);
sewardjc9a43662004-11-30 18:51:59 +0000576 vassert(ty == Ity_I32 || ty == Ity_I16 || ty == Ity_I8);
sewardjeeb9ef82004-07-15 12:39:03 +0000577 stmt( IRStmt_Put(integerGuestRegOffset(sz,archreg), e) );
sewardjd1061ab2004-07-08 01:45:30 +0000578}
579
sewardj063f02f2004-10-20 12:36:12 +0000580static IRExpr* getSReg ( UInt sreg )
581{
582 return IRExpr_Get( segmentGuestRegOffset(sreg), Ity_I16 );
583}
584
sewardjf9655262004-10-31 20:02:16 +0000585#if 0
sewardj063f02f2004-10-20 12:36:12 +0000586static void putSReg ( UInt sreg, IRExpr* e )
587{
588 vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_I16);
589 stmt( IRStmt_Put( segmentGuestRegOffset(sreg), e ) );
590}
sewardjf9655262004-10-31 20:02:16 +0000591#endif
sewardj063f02f2004-10-20 12:36:12 +0000592
sewardjc9a43662004-11-30 18:51:59 +0000593static IRExpr* getXMMReg ( UInt xmmreg )
594{
595 return IRExpr_Get( xmmGuestRegOffset(xmmreg), Ity_V128 );
596}
597
sewardj67e002d2004-12-02 18:16:33 +0000598static IRExpr* getXMMRegLane64 ( UInt xmmreg, Int laneno )
599{
600 return IRExpr_Get( xmmGuestRegLane64offset(xmmreg,laneno), Ity_I64 );
601}
602
603static IRExpr* getXMMRegLane32F ( UInt xmmreg, Int laneno )
604{
605 return IRExpr_Get( xmmGuestRegLane32offset(xmmreg,laneno), Ity_F32 );
606}
607
sewardj9636b442004-12-04 01:38:37 +0000608static IRExpr* getXMMRegLane32 ( UInt xmmreg, Int laneno )
609{
610 return IRExpr_Get( xmmGuestRegLane32offset(xmmreg,laneno), Ity_I32 );
611}
612
sewardjc9a43662004-11-30 18:51:59 +0000613static void putXMMReg ( UInt xmmreg, IRExpr* e )
614{
615 vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_V128);
616 stmt( IRStmt_Put( xmmGuestRegOffset(xmmreg), e ) );
617}
618
sewardj67e002d2004-12-02 18:16:33 +0000619static void putXMMRegLane64 ( UInt xmmreg, Int laneno, IRExpr* e )
620{
621 vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_I64);
622 stmt( IRStmt_Put( xmmGuestRegLane64offset(xmmreg,laneno), e ) );
623}
624
sewardj4cb918d2004-12-03 19:43:31 +0000625static void putXMMRegLane32F ( UInt xmmreg, Int laneno, IRExpr* e )
sewardj67e002d2004-12-02 18:16:33 +0000626{
sewardj4cb918d2004-12-03 19:43:31 +0000627 vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_F32);
sewardj67e002d2004-12-02 18:16:33 +0000628 stmt( IRStmt_Put( xmmGuestRegLane32offset(xmmreg,laneno), e ) );
629}
630
sewardj9636b442004-12-04 01:38:37 +0000631static void putXMMRegLane32 ( UInt xmmreg, Int laneno, IRExpr* e )
632{
633 vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_I32);
634 stmt( IRStmt_Put( xmmGuestRegLane32offset(xmmreg,laneno), e ) );
635}
636
sewardj41f43bc2004-07-08 14:23:22 +0000637static void assign ( IRTemp dst, IRExpr* e )
sewardjd1061ab2004-07-08 01:45:30 +0000638{
sewardj41f43bc2004-07-08 14:23:22 +0000639 stmt( IRStmt_Tmp(dst, e) );
sewardjd1061ab2004-07-08 01:45:30 +0000640}
641
sewardj41f43bc2004-07-08 14:23:22 +0000642static void storeLE ( IRExpr* addr, IRExpr* data )
sewardjd1061ab2004-07-08 01:45:30 +0000643{
sewardj41f43bc2004-07-08 14:23:22 +0000644 stmt( IRStmt_STle(addr,data) );
sewardjd1061ab2004-07-08 01:45:30 +0000645}
646
sewardje87b4842004-07-10 12:23:30 +0000647static IRExpr* unop ( IROp op, IRExpr* a )
648{
649 return IRExpr_Unop(op, a);
650}
651
sewardjd1061ab2004-07-08 01:45:30 +0000652static IRExpr* binop ( IROp op, IRExpr* a1, IRExpr* a2 )
653{
654 return IRExpr_Binop(op, a1, a2);
655}
656
657static IRExpr* mkexpr ( IRTemp tmp )
658{
659 return IRExpr_Tmp(tmp);
660}
661
sewardjc2ac51e2004-07-12 01:03:26 +0000662static IRExpr* mkU8 ( UInt i )
663{
664 vassert(i < 256);
665 return IRExpr_Const(IRConst_U8(i));
666}
667
668static IRExpr* mkU16 ( UInt i )
669{
670 vassert(i < 65536);
671 return IRExpr_Const(IRConst_U16(i));
672}
673
sewardjd1061ab2004-07-08 01:45:30 +0000674static IRExpr* mkU32 ( UInt i )
675{
676 return IRExpr_Const(IRConst_U32(i));
sewardjc9a65702004-07-07 16:32:57 +0000677}
678
sewardj41f43bc2004-07-08 14:23:22 +0000679static IRExpr* mkU ( IRType ty, UInt i )
680{
sewardjc2ac51e2004-07-12 01:03:26 +0000681 if (ty == Ity_I8) return mkU8(i);
682 if (ty == Ity_I16) return mkU16(i);
683 if (ty == Ity_I32) return mkU32(i);
sewardje90ad6a2004-07-10 19:02:10 +0000684 /* If this panics, it usually means you passed a size (1,2,4)
685 value as the IRType, rather than a real IRType. */
sewardj41f43bc2004-07-08 14:23:22 +0000686 vpanic("mkU(x86)");
687}
688
sewardj1e6ad742004-12-02 16:16:11 +0000689static IRExpr* mkV128 ( UShort mask )
690{
691 return IRExpr_Const(IRConst_V128(mask));
692}
693
sewardj41f43bc2004-07-08 14:23:22 +0000694static IRExpr* loadLE ( IRType ty, IRExpr* data )
695{
696 return IRExpr_LDle(ty,data);
697}
698
699static IROp mkSizedOp ( IRType ty, IROp op8 )
700{
sewardje05c42c2004-07-08 20:25:10 +0000701 Int adj;
sewardj41f43bc2004-07-08 14:23:22 +0000702 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
703 vassert(op8 == Iop_Add8 || op8 == Iop_Sub8
sewardj41f43bc2004-07-08 14:23:22 +0000704 || op8 == Iop_Mul8
705 || op8 == Iop_Or8 || op8 == Iop_And8 || op8 == Iop_Xor8
sewardj5bd4d162004-11-10 13:02:48 +0000706 || op8 == Iop_Shl8 || op8 == Iop_Shr8 || op8 == Iop_Sar8
sewardje90ad6a2004-07-10 19:02:10 +0000707 || op8 == Iop_CmpEQ8 || op8 == Iop_CmpNE8
sewardj86b133b2004-11-15 13:54:26 +0000708 || op8 == Iop_Not8 );
sewardje05c42c2004-07-08 20:25:10 +0000709 adj = ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
710 return adj + op8;
sewardj41f43bc2004-07-08 14:23:22 +0000711}
712
sewardj9334b0f2004-07-10 22:43:54 +0000713static IROp mkWidenOp ( Int szSmall, Int szBig, Bool signd )
sewardj41f43bc2004-07-08 14:23:22 +0000714{
sewardj9334b0f2004-07-10 22:43:54 +0000715 if (szSmall == 1 && szBig == 4) {
716 return signd ? Iop_8Sto32 : Iop_8Uto32;
sewardj41f43bc2004-07-08 14:23:22 +0000717 }
sewardj9334b0f2004-07-10 22:43:54 +0000718 if (szSmall == 1 && szBig == 2) {
719 return signd ? Iop_8Sto16 : Iop_8Uto16;
720 }
721 if (szSmall == 2 && szBig == 4) {
722 return signd ? Iop_16Sto32 : Iop_16Uto32;
723 }
sewardj948d48b2004-11-05 19:49:09 +0000724 vpanic("mkWidenOp(x86,guest)");
sewardj41f43bc2004-07-08 14:23:22 +0000725}
726
727
728/*------------------------------------------------------------*/
729/*--- Helpers for %eflags. ---*/
730/*------------------------------------------------------------*/
731
sewardj0611d802004-07-11 02:37:54 +0000732/* -------------- Evaluating the flags-thunk. -------------- */
sewardjc9a65702004-07-07 16:32:57 +0000733
sewardje87b4842004-07-10 12:23:30 +0000734/* Build IR to calculate all the eflags from stored
sewardj2a2ba8b2004-11-08 13:14:06 +0000735 CC_OP/CC_DEP1/CC_DEP2/CC_NDEP. Returns an expression ::
736 Ity_I32. */
sewardj2a9ad022004-11-25 02:46:58 +0000737static IRExpr* mk_x86g_calculate_eflags_all ( void )
sewardje87b4842004-07-10 12:23:30 +0000738{
sewardjf9655262004-10-31 20:02:16 +0000739 IRExpr** args
sewardj2a2ba8b2004-11-08 13:14:06 +0000740 = mkIRExprVec_4( IRExpr_Get(OFFB_CC_OP, Ity_I32),
741 IRExpr_Get(OFFB_CC_DEP1, Ity_I32),
742 IRExpr_Get(OFFB_CC_DEP2, Ity_I32),
743 IRExpr_Get(OFFB_CC_NDEP, Ity_I32) );
sewardj43c56462004-11-06 12:17:57 +0000744 IRExpr* call
745 = mkIRExprCCall(
746 Ity_I32,
747 0/*regparm*/,
sewardj2a9ad022004-11-25 02:46:58 +0000748 "x86g_calculate_eflags_all", &x86g_calculate_eflags_all,
sewardj43c56462004-11-06 12:17:57 +0000749 args
750 );
sewardj2a2ba8b2004-11-08 13:14:06 +0000751 /* Exclude OP and NDEP from definedness checking. We're only
752 interested in DEP1 and DEP2. */
753 call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<3);
sewardj43c56462004-11-06 12:17:57 +0000754 return call;
sewardje87b4842004-07-10 12:23:30 +0000755}
756
sewardj84ff0652004-08-23 16:16:08 +0000757/* Build IR to calculate some particular condition from stored
sewardj2a2ba8b2004-11-08 13:14:06 +0000758 CC_OP/CC_DEP1/CC_DEP2/CC_NDEP. Returns an expression ::
759 Ity_Bit. */
sewardj2a9ad022004-11-25 02:46:58 +0000760static IRExpr* mk_x86g_calculate_condition ( X86Condcode cond )
sewardj84ff0652004-08-23 16:16:08 +0000761{
sewardjf9655262004-10-31 20:02:16 +0000762 IRExpr** args
sewardj2a2ba8b2004-11-08 13:14:06 +0000763 = mkIRExprVec_5( mkU32(cond),
sewardjf9655262004-10-31 20:02:16 +0000764 IRExpr_Get(OFFB_CC_OP, Ity_I32),
sewardj2a2ba8b2004-11-08 13:14:06 +0000765 IRExpr_Get(OFFB_CC_DEP1, Ity_I32),
766 IRExpr_Get(OFFB_CC_DEP2, Ity_I32),
767 IRExpr_Get(OFFB_CC_NDEP, Ity_I32) );
sewardj43c56462004-11-06 12:17:57 +0000768 IRExpr* call
769 = mkIRExprCCall(
770 Ity_I32,
771 0/*regparm*/,
sewardj2a9ad022004-11-25 02:46:58 +0000772 "x86g_calculate_condition", &x86g_calculate_condition,
sewardj43c56462004-11-06 12:17:57 +0000773 args
774 );
sewardj2a2ba8b2004-11-08 13:14:06 +0000775 /* Exclude the requested condition, OP and NDEP from definedness
776 checking. We're only interested in DEP1 and DEP2. */
777 call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<1) | (1<<4);
sewardj43c56462004-11-06 12:17:57 +0000778 return unop(Iop_32to1, call);
779}
780
781/* Build IR to calculate just the carry flag from stored
sewardj2a2ba8b2004-11-08 13:14:06 +0000782 CC_OP/CC_DEP1/CC_DEP2/CC_NDEP. Returns an expression :: Ity_I32. */
sewardj2a9ad022004-11-25 02:46:58 +0000783static IRExpr* mk_x86g_calculate_eflags_c ( void )
sewardj43c56462004-11-06 12:17:57 +0000784{
785 IRExpr** args
sewardj2a2ba8b2004-11-08 13:14:06 +0000786 = mkIRExprVec_4( IRExpr_Get(OFFB_CC_OP, Ity_I32),
787 IRExpr_Get(OFFB_CC_DEP1, Ity_I32),
788 IRExpr_Get(OFFB_CC_DEP2, Ity_I32),
789 IRExpr_Get(OFFB_CC_NDEP, Ity_I32) );
sewardj43c56462004-11-06 12:17:57 +0000790 IRExpr* call
791 = mkIRExprCCall(
792 Ity_I32,
793 0/*regparm*/,
sewardj2a9ad022004-11-25 02:46:58 +0000794 "x86g_calculate_eflags_c", &x86g_calculate_eflags_c,
sewardj43c56462004-11-06 12:17:57 +0000795 args
796 );
sewardj2a2ba8b2004-11-08 13:14:06 +0000797 /* Exclude OP and NDEP from definedness checking. We're only
798 interested in DEP1 and DEP2. */
799 call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<3);
sewardj43c56462004-11-06 12:17:57 +0000800 return call;
sewardj84ff0652004-08-23 16:16:08 +0000801}
802
sewardje87b4842004-07-10 12:23:30 +0000803
sewardj0611d802004-07-11 02:37:54 +0000804/* -------------- Building the flags-thunk. -------------- */
805
sewardjb9c5cf62004-08-24 15:10:38 +0000806/* The machinery in this section builds the flag-thunk following a
807 flag-setting operation. Hence the various setFlags_* functions.
sewardjb9c5cf62004-08-24 15:10:38 +0000808*/
809
810static Bool isAddSub ( IROp op8 )
811{
812 return op8 == Iop_Add8 || op8 == Iop_Sub8;
813}
sewardj0611d802004-07-11 02:37:54 +0000814
sewardj2a2ba8b2004-11-08 13:14:06 +0000815static Bool isLogic ( IROp op8 )
816{
817 return op8 == Iop_And8 || op8 == Iop_Or8 || op8 == Iop_Xor8;
818}
819
sewardja2384712004-07-29 14:36:40 +0000820/* U-widen 8/16/32 bit int expr to 32. */
sewardjc22a6fd2004-07-29 23:41:47 +0000821static IRExpr* widenUto32 ( IRExpr* e )
sewardj443cd9d2004-07-18 23:06:45 +0000822{
823 switch (typeOfIRExpr(irbb->tyenv,e)) {
824 case Ity_I32: return e;
825 case Ity_I16: return unop(Iop_16Uto32,e);
826 case Ity_I8: return unop(Iop_8Uto32,e);
827 default: vpanic("widenUto32");
828 }
829}
830
sewardjc22a6fd2004-07-29 23:41:47 +0000831/* S-widen 8/16/32 bit int expr to 32. */
832static IRExpr* widenSto32 ( IRExpr* e )
833{
834 switch (typeOfIRExpr(irbb->tyenv,e)) {
835 case Ity_I32: return e;
836 case Ity_I16: return unop(Iop_16Sto32,e);
837 case Ity_I8: return unop(Iop_8Sto32,e);
838 default: vpanic("widenSto32");
839 }
840}
841
sewardja2384712004-07-29 14:36:40 +0000842/* Narrow 8/16/32 bit int expr to 8/16/32. Clearly only some
843 of these combinations make sense. */
844static IRExpr* narrowTo ( IRType dst_ty, IRExpr* e )
845{
846 IRType src_ty = typeOfIRExpr(irbb->tyenv,e);
847 if (src_ty == dst_ty)
848 return e;
849 if (src_ty == Ity_I32 && dst_ty == Ity_I16)
850 return unop(Iop_32to16, e);
851 if (src_ty == Ity_I32 && dst_ty == Ity_I8)
852 return unop(Iop_32to8, e);
853
854 vex_printf("\nsrc, dst tys are: ");
855 ppIRType(src_ty);
856 vex_printf(", ");
857 ppIRType(dst_ty);
858 vex_printf("\n");
859 vpanic("narrowTo(x86)");
860}
861
sewardj443cd9d2004-07-18 23:06:45 +0000862
sewardj2a2ba8b2004-11-08 13:14:06 +0000863/* Set the flags thunk OP, DEP1 and DEP2 fields. The supplied op is
sewardj948d48b2004-11-05 19:49:09 +0000864 auto-sized up to the real op. */
sewardj0611d802004-07-11 02:37:54 +0000865
sewardj2a2ba8b2004-11-08 13:14:06 +0000866static
867void setFlags_DEP1_DEP2 ( IROp op8, IRTemp dep1, IRTemp dep2, IRType ty )
sewardj0611d802004-07-11 02:37:54 +0000868{
sewardjb9c5cf62004-08-24 15:10:38 +0000869 Int ccOp = ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
870
871 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
872
873 switch (op8) {
sewardj2a9ad022004-11-25 02:46:58 +0000874 case Iop_Add8: ccOp += X86G_CC_OP_ADDB; break;
875 case Iop_Sub8: ccOp += X86G_CC_OP_SUBB; break;
sewardjb9c5cf62004-08-24 15:10:38 +0000876 default: ppIROp(op8);
sewardj2a2ba8b2004-11-08 13:14:06 +0000877 vpanic("setFlags_DEP1_DEP2(x86)");
sewardjb9c5cf62004-08-24 15:10:38 +0000878 }
sewardj2a2ba8b2004-11-08 13:14:06 +0000879 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(ccOp)) );
880 stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto32(mkexpr(dep1))) );
881 stmt( IRStmt_Put( OFFB_CC_DEP2, widenUto32(mkexpr(dep2))) );
sewardjb9c5cf62004-08-24 15:10:38 +0000882}
883
884
sewardj2a2ba8b2004-11-08 13:14:06 +0000885/* Set the OP and DEP1 fields only, and write zero to DEP2. */
sewardjb9c5cf62004-08-24 15:10:38 +0000886
sewardj2a2ba8b2004-11-08 13:14:06 +0000887static
888void setFlags_DEP1 ( IROp op8, IRTemp dep1, IRType ty )
sewardjb9c5cf62004-08-24 15:10:38 +0000889{
890 Int ccOp = ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
sewardj0611d802004-07-11 02:37:54 +0000891
892 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
893
894 switch (op8) {
895 case Iop_Or8:
896 case Iop_And8:
sewardj2a9ad022004-11-25 02:46:58 +0000897 case Iop_Xor8: ccOp += X86G_CC_OP_LOGICB; break;
sewardj0611d802004-07-11 02:37:54 +0000898 default: ppIROp(op8);
sewardj2a2ba8b2004-11-08 13:14:06 +0000899 vpanic("setFlags_DEP1(x86)");
sewardj0611d802004-07-11 02:37:54 +0000900 }
sewardj2a2ba8b2004-11-08 13:14:06 +0000901 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(ccOp)) );
902 stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto32(mkexpr(dep1))) );
903 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0)) );
sewardj0611d802004-07-11 02:37:54 +0000904}
905
906
sewardj948d48b2004-11-05 19:49:09 +0000907/* For shift operations, we put in the result and the undershifted
908 result. Except if the shift amount is zero, the thunk is left
909 unchanged. */
sewardj0611d802004-07-11 02:37:54 +0000910
sewardj2a2ba8b2004-11-08 13:14:06 +0000911static void setFlags_DEP1_DEP2_shift ( IROp op32,
912 IRTemp res,
913 IRTemp resUS,
914 IRType ty,
915 IRTemp guard )
sewardj0611d802004-07-11 02:37:54 +0000916{
sewardjc22a6fd2004-07-29 23:41:47 +0000917 Int ccOp = ty==Ity_I8 ? 2 : (ty==Ity_I16 ? 1 : 0);
sewardj0611d802004-07-11 02:37:54 +0000918
919 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
920 vassert(guard);
921
sewardj2a2ba8b2004-11-08 13:14:06 +0000922 /* Both kinds of right shifts are handled by the same thunk
923 operation. */
sewardjc22a6fd2004-07-29 23:41:47 +0000924 switch (op32) {
925 case Iop_Shr32:
sewardj2a9ad022004-11-25 02:46:58 +0000926 case Iop_Sar32: ccOp = X86G_CC_OP_SHRL - ccOp; break;
927 case Iop_Shl32: ccOp = X86G_CC_OP_SHLL - ccOp; break;
sewardjc22a6fd2004-07-29 23:41:47 +0000928 default: ppIROp(op32);
sewardj2a2ba8b2004-11-08 13:14:06 +0000929 vpanic("setFlags_DEP1_DEP2_shift(x86)");
sewardj0611d802004-07-11 02:37:54 +0000930 }
931
sewardj2a2ba8b2004-11-08 13:14:06 +0000932 /* DEP1 contains the result, DEP2 contains the undershifted value. */
sewardjeeb9ef82004-07-15 12:39:03 +0000933 stmt( IRStmt_Put( OFFB_CC_OP,
sewardj4042c7e2004-07-18 01:28:30 +0000934 IRExpr_Mux0X( mkexpr(guard),
935 IRExpr_Get(OFFB_CC_OP,Ity_I32),
936 mkU32(ccOp))) );
sewardj2a2ba8b2004-11-08 13:14:06 +0000937 stmt( IRStmt_Put( OFFB_CC_DEP1,
sewardj4042c7e2004-07-18 01:28:30 +0000938 IRExpr_Mux0X( mkexpr(guard),
sewardj2a2ba8b2004-11-08 13:14:06 +0000939 IRExpr_Get(OFFB_CC_DEP1,Ity_I32),
sewardj948d48b2004-11-05 19:49:09 +0000940 widenUto32(mkexpr(res)))) );
sewardj2a2ba8b2004-11-08 13:14:06 +0000941 stmt( IRStmt_Put( OFFB_CC_DEP2,
sewardj4042c7e2004-07-18 01:28:30 +0000942 IRExpr_Mux0X( mkexpr(guard),
sewardj2a2ba8b2004-11-08 13:14:06 +0000943 IRExpr_Get(OFFB_CC_DEP2,Ity_I32),
sewardj948d48b2004-11-05 19:49:09 +0000944 widenUto32(mkexpr(resUS)))) );
sewardj0611d802004-07-11 02:37:54 +0000945}
946
947
sewardj2a2ba8b2004-11-08 13:14:06 +0000948/* For the inc/dec case, we store in DEP1 the result value and in NDEP
sewardj948d48b2004-11-05 19:49:09 +0000949 the former value of the carry flag, which unfortunately we have to
950 compute. */
sewardj0611d802004-07-11 02:37:54 +0000951
sewardj948d48b2004-11-05 19:49:09 +0000952static void setFlags_INC_DEC ( Bool inc, IRTemp res, IRType ty )
sewardj0611d802004-07-11 02:37:54 +0000953{
sewardj2a9ad022004-11-25 02:46:58 +0000954 Int ccOp = inc ? X86G_CC_OP_INCB : X86G_CC_OP_DECB;
sewardj0611d802004-07-11 02:37:54 +0000955
956 ccOp += ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
957 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
958
959 /* This has to come first, because calculating the C flag
sewardj2a2ba8b2004-11-08 13:14:06 +0000960 may require reading all four thunk fields. */
sewardj2a9ad022004-11-25 02:46:58 +0000961 stmt( IRStmt_Put( OFFB_CC_NDEP, mk_x86g_calculate_eflags_c()) );
sewardj2a2ba8b2004-11-08 13:14:06 +0000962 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(ccOp)) );
963 stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(res)) );
964 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0)) );
sewardj0611d802004-07-11 02:37:54 +0000965}
966
967
sewardj2a2ba8b2004-11-08 13:14:06 +0000968/* Multiplies are pretty much like add and sub: DEP1 and DEP2 hold the
969 two arguments. */
sewardjcf780b42004-07-13 18:42:17 +0000970
971static
sewardj2a2ba8b2004-11-08 13:14:06 +0000972void setFlags_MUL ( IRType ty, IRTemp arg1, IRTemp arg2, UInt base_op )
sewardjcf780b42004-07-13 18:42:17 +0000973{
974 switch (ty) {
sewardj2a2ba8b2004-11-08 13:14:06 +0000975 case Ity_I8:
976 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(base_op+0) ) );
977 break;
978 case Ity_I16:
979 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(base_op+1) ) );
980 break;
981 case Ity_I32:
982 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(base_op+2) ) );
983 break;
984 default:
985 vpanic("setFlags_MUL(x86)");
sewardjcf780b42004-07-13 18:42:17 +0000986 }
sewardj2a2ba8b2004-11-08 13:14:06 +0000987 stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto32(mkexpr(arg1)) ));
988 stmt( IRStmt_Put( OFFB_CC_DEP2, widenUto32(mkexpr(arg2)) ));
sewardjcf780b42004-07-13 18:42:17 +0000989}
990
991
sewardj3af115f2004-07-14 02:46:52 +0000992/* -------------- Condition codes. -------------- */
993
sewardje87b4842004-07-10 12:23:30 +0000994/* Condition codes, using the Intel encoding. */
sewardj0611d802004-07-11 02:37:54 +0000995
sewardj2a9ad022004-11-25 02:46:58 +0000996static Char* name_X86Condcode ( X86Condcode cond )
sewardje87b4842004-07-10 12:23:30 +0000997{
998 switch (cond) {
sewardj2a9ad022004-11-25 02:46:58 +0000999 case X86CondO: return "o";
1000 case X86CondNO: return "no";
1001 case X86CondB: return "b";
1002 case X86CondNB: return "nb";
1003 case X86CondZ: return "z";
1004 case X86CondNZ: return "nz";
1005 case X86CondBE: return "be";
1006 case X86CondNBE: return "nbe";
1007 case X86CondS: return "s";
1008 case X86CondNS: return "ns";
1009 case X86CondP: return "p";
1010 case X86CondNP: return "np";
1011 case X86CondL: return "l";
1012 case X86CondNL: return "nl";
1013 case X86CondLE: return "le";
1014 case X86CondNLE: return "nle";
1015 case X86CondAlways: return "ALWAYS";
1016 default: vpanic("name_X86Condcode");
sewardje87b4842004-07-10 12:23:30 +00001017 }
1018}
1019
sewardj2a9ad022004-11-25 02:46:58 +00001020static
1021X86Condcode positiveIse_X86Condcode ( X86Condcode cond,
1022 Bool* needInvert )
sewardje87b4842004-07-10 12:23:30 +00001023{
sewardj2a9ad022004-11-25 02:46:58 +00001024 vassert(cond >= X86CondO && cond <= X86CondNLE);
sewardje87b4842004-07-10 12:23:30 +00001025 if (cond & 1) {
1026 *needInvert = True;
1027 return cond-1;
1028 } else {
1029 *needInvert = False;
1030 return cond;
1031 }
1032}
1033
1034
sewardj3af115f2004-07-14 02:46:52 +00001035/* -------------- Helpers for ADD/SUB with carry. -------------- */
1036
sewardj948d48b2004-11-05 19:49:09 +00001037/* Given ta1, ta2 and tres, compute tres = ADC(ta1,ta2) and set flags
sewardj2a2ba8b2004-11-08 13:14:06 +00001038 appropriately.
sewardj3af115f2004-07-14 02:46:52 +00001039*/
1040static void helper_ADC ( Int sz,
sewardj5bd4d162004-11-10 13:02:48 +00001041 IRTemp tres, IRTemp ta1, IRTemp ta2 )
sewardj3af115f2004-07-14 02:46:52 +00001042{
1043 UInt thunkOp;
sewardj2a2ba8b2004-11-08 13:14:06 +00001044 IRType ty = szToITy(sz);
1045 IRTemp oldc = newTemp(Ity_I32);
1046 IRTemp oldcn = newTemp(ty);
1047 IROp plus = mkSizedOp(ty, Iop_Add8);
1048 IROp xor = mkSizedOp(ty, Iop_Xor8);
sewardja2384712004-07-29 14:36:40 +00001049
1050 vassert(sz == 1 || sz == 2 || sz == 4);
sewardj2a9ad022004-11-25 02:46:58 +00001051 thunkOp = sz==4 ? X86G_CC_OP_ADCL
1052 : (sz==2 ? X86G_CC_OP_ADCW : X86G_CC_OP_ADCB);
sewardj3af115f2004-07-14 02:46:52 +00001053
sewardj2a2ba8b2004-11-08 13:14:06 +00001054 /* oldc = old carry flag, 0 or 1 */
1055 assign( oldc, binop(Iop_And32,
sewardj2a9ad022004-11-25 02:46:58 +00001056 mk_x86g_calculate_eflags_c(),
sewardj5bd4d162004-11-10 13:02:48 +00001057 mkU32(1)) );
sewardj3af115f2004-07-14 02:46:52 +00001058
sewardj2a2ba8b2004-11-08 13:14:06 +00001059 assign( oldcn, narrowTo(ty, mkexpr(oldc)) );
1060
1061 assign( tres, binop(plus,
1062 binop(plus,mkexpr(ta1),mkexpr(ta2)),
1063 mkexpr(oldcn)) );
1064
1065 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(thunkOp) ) );
1066 stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(ta1) ) );
sewardj2a9ad022004-11-25 02:46:58 +00001067 stmt( IRStmt_Put( OFFB_CC_DEP2, binop(xor, mkexpr(ta2),
1068 mkexpr(oldcn)) ) );
sewardj2a2ba8b2004-11-08 13:14:06 +00001069 stmt( IRStmt_Put( OFFB_CC_NDEP, mkexpr(oldc) ) );
sewardj3af115f2004-07-14 02:46:52 +00001070}
1071
1072
sewardj948d48b2004-11-05 19:49:09 +00001073/* Given ta1, ta2 and tres, compute tres = SBB(ta1,ta2) and set flags
sewardj2a2ba8b2004-11-08 13:14:06 +00001074 appropriately.
sewardjcaca9d02004-07-28 07:11:32 +00001075*/
1076static void helper_SBB ( Int sz,
sewardj5bd4d162004-11-10 13:02:48 +00001077 IRTemp tres, IRTemp ta1, IRTemp ta2 )
sewardjcaca9d02004-07-28 07:11:32 +00001078{
1079 UInt thunkOp;
sewardj2a2ba8b2004-11-08 13:14:06 +00001080 IRType ty = szToITy(sz);
1081 IRTemp oldc = newTemp(Ity_I32);
1082 IRTemp oldcn = newTemp(ty);
1083 IROp minus = mkSizedOp(ty, Iop_Sub8);
1084 IROp xor = mkSizedOp(ty, Iop_Xor8);
1085
1086 vassert(sz == 1 || sz == 2 || sz == 4);
sewardj2a9ad022004-11-25 02:46:58 +00001087 thunkOp = sz==4 ? X86G_CC_OP_SBBL
1088 : (sz==2 ? X86G_CC_OP_SBBW : X86G_CC_OP_SBBB);
sewardjcaca9d02004-07-28 07:11:32 +00001089
1090 /* oldc = old carry flag, 0 or 1 */
sewardja2384712004-07-29 14:36:40 +00001091 assign( oldc, binop(Iop_And32,
sewardj2a9ad022004-11-25 02:46:58 +00001092 mk_x86g_calculate_eflags_c(),
sewardj5bd4d162004-11-10 13:02:48 +00001093 mkU32(1)) );
sewardjcaca9d02004-07-28 07:11:32 +00001094
sewardj2a2ba8b2004-11-08 13:14:06 +00001095 assign( oldcn, narrowTo(ty, mkexpr(oldc)) );
sewardja2384712004-07-29 14:36:40 +00001096
sewardj2a2ba8b2004-11-08 13:14:06 +00001097 assign( tres, binop(minus,
1098 binop(minus,mkexpr(ta1),mkexpr(ta2)),
1099 mkexpr(oldcn)) );
sewardjcaca9d02004-07-28 07:11:32 +00001100
sewardj2a2ba8b2004-11-08 13:14:06 +00001101 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(thunkOp) ) );
1102 stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(ta1) ) );
sewardj2a9ad022004-11-25 02:46:58 +00001103 stmt( IRStmt_Put( OFFB_CC_DEP2, binop(xor, mkexpr(ta2),
1104 mkexpr(oldcn)) ) );
sewardj2a2ba8b2004-11-08 13:14:06 +00001105 stmt( IRStmt_Put( OFFB_CC_NDEP, mkexpr(oldc) ) );
sewardjcaca9d02004-07-28 07:11:32 +00001106}
1107
1108
sewardjc9a65702004-07-07 16:32:57 +00001109//-- /*------------------------------------------------------------*/
1110//-- /*--- CPU feature set stuff ---*/
1111//-- /*--- This is a little out of place here, but it will do ---*/
1112//-- /*--- for now. ---*/
1113//-- /*------------------------------------------------------------*/
1114//--
sewardje87b4842004-07-10 12:23:30 +00001115//-- #define VG_CPU_VENDOR_GENERIC 0
1116//-- #define VG_CPU_VENDOR_INTEL 1
sewardj5bd4d162004-11-10 13:02:48 +00001117//-- #define VG_CPU_VENDOR_AMD 2
sewardjc9a65702004-07-07 16:32:57 +00001118//--
1119//-- static Int cpu_vendor = VG_CPU_VENDOR_GENERIC;
1120//--
1121//-- static const struct cpu_vendor {
sewardj5bd4d162004-11-10 13:02:48 +00001122//-- const Char *vendorstr;
1123//-- Int vendorid;
sewardjc9a65702004-07-07 16:32:57 +00001124//-- } cpu_vendors[] = {
sewardj5bd4d162004-11-10 13:02:48 +00001125//-- { "GenuineIntel", VG_CPU_VENDOR_INTEL },
1126//-- { "AuthenticAMD", VG_CPU_VENDOR_AMD },
sewardjc9a65702004-07-07 16:32:57 +00001127//-- };
1128//--
sewardj5bd4d162004-11-10 13:02:48 +00001129//-- static Int cpuid_level = -2; /* -2 -> not initialized */
sewardjc9a65702004-07-07 16:32:57 +00001130//-- static UInt cpu_features[VG_N_FEATURE_WORDS];
1131//--
1132//-- /* Standard macro to see if a specific flag is changeable */
1133//-- static inline Bool flag_is_changeable(UInt flag)
1134//-- {
1135//-- UInt f1, f2;
1136//--
1137//-- asm("pushfl\n\t"
1138//-- "pushfl\n\t"
1139//-- "popl %0\n\t"
1140//-- "movl %0,%1\n\t"
1141//-- "xorl %2,%0\n\t"
1142//-- "pushl %0\n\t"
1143//-- "popfl\n\t"
1144//-- "pushfl\n\t"
1145//-- "popl %0\n\t"
1146//-- "popfl\n\t"
1147//-- : "=&r" (f1), "=&r" (f2)
1148//-- : "ir" (flag));
1149//--
1150//-- return ((f1^f2) & flag) != 0;
1151//-- }
1152//--
1153//--
1154//-- /* Probe for the CPUID instruction */
1155//-- static Bool has_cpuid(void)
1156//-- {
1157//-- return flag_is_changeable(EFlagID);
1158//-- }
1159//--
1160//-- static void get_cpu_features(void)
1161//-- {
1162//-- Char vendorstr[13];
1163//-- Int i;
1164//--
1165//-- if (!has_cpuid()) {
1166//-- cpuid_level = -1;
1167//-- return;
1168//-- }
1169//--
1170//-- cpu_features[VG_INT_FEAT] |= (1 << (VG_X86_FEAT_CPUID%32));
1171//--
1172//-- VG_(cpuid)(0, &cpuid_level, (UInt *)&vendorstr[0], (UInt *)&vendorstr[8], (UInt *)&vendorstr[4]);
1173//-- vendorstr[12] = '\0';
1174//--
1175//-- for(i = 0; i < sizeof(cpu_vendors)/sizeof(*cpu_vendors); i++)
1176//-- if (VG_(memcmp)(vendorstr, cpu_vendors[i].vendorstr, 12) == 0) {
sewardj5bd4d162004-11-10 13:02:48 +00001177//-- cpu_vendor = cpu_vendors[i].vendorid;
1178//-- break;
sewardjc9a65702004-07-07 16:32:57 +00001179//-- }
1180//--
1181//-- if (cpuid_level >= 1)
1182//-- VG_(cpuid)(1, NULL, NULL, &cpu_features[VG_EXT_FEAT], &cpu_features[VG_X86_FEAT]);
1183//--
1184//-- switch(cpu_vendor) {
1185//-- case VG_CPU_VENDOR_AMD:
1186//-- /* get AMD-specific flags */
1187//-- VG_(cpuid)(0x80000001, NULL, NULL, NULL, &cpu_features[VG_AMD_FEAT]);
1188//-- break;
1189//--
1190//-- default:
1191//-- break;
1192//-- }
1193//-- }
1194//--
1195//-- Bool VG_(cpu_has_feature)(UInt feature)
1196//-- {
1197//-- UInt word = feature / 32;
1198//-- UInt bit = feature % 32;
1199//--
1200//-- if (cpuid_level == -2)
1201//-- get_cpu_features();
1202//--
1203//-- vg_assert(word >= 0 && word < VG_N_FEATURE_WORDS);
1204//--
1205//-- return !!(cpu_features[word] & (1 << bit));
1206//-- }
1207//--
1208//-- /* The set of features we're willing to support for the client
1209//--
1210//-- This includes supported instruction set extensions, plus any
1211//-- extensions which don't have any user-mode visible effect (but the
1212//-- client may find interesting).
1213//-- */
sewardj5bd4d162004-11-10 13:02:48 +00001214#define VG_X86_SUPPORTED_FEATURES \
1215 ((1 << VG_X86_FEAT_FPU) | \
1216 (1 << VG_X86_FEAT_VME) | \
1217 (1 << VG_X86_FEAT_DE) | \
1218 (1 << VG_X86_FEAT_PSE) | \
1219 (1 << VG_X86_FEAT_TSC) | \
1220 (0 << VG_X86_FEAT_MSR) | \
1221 (1 << VG_X86_FEAT_PAE) | \
1222 (1 << VG_X86_FEAT_MCE) | \
1223 (1 << VG_X86_FEAT_CX8) | \
1224 (1 << VG_X86_FEAT_APIC) | \
1225 (0 << VG_X86_FEAT_SEP) | \
1226 (1 << VG_X86_FEAT_MTRR) | \
1227 (1 << VG_X86_FEAT_PGE) | \
1228 (1 << VG_X86_FEAT_MCA) | \
1229 (1 << VG_X86_FEAT_CMOV) | \
1230 (1 << VG_X86_FEAT_PAT) | \
1231 (1 << VG_X86_FEAT_PSE36) | \
1232 (0 << VG_X86_FEAT_CLFSH) | \
1233 (1 << VG_X86_FEAT_DS) | \
1234 (1 << VG_X86_FEAT_ACPI) | \
1235 (1 << VG_X86_FEAT_MMX) | \
1236 (1 << VG_X86_FEAT_FXSR) | \
1237 (1 << VG_X86_FEAT_SSE) | \
1238 (1 << VG_X86_FEAT_SSE2) | \
1239 (1 << VG_X86_FEAT_SS) | \
1240 (1 << VG_X86_FEAT_HT) | \
1241 (1 << VG_X86_FEAT_TM) | \
1242 (0 << VG_X86_FEAT_IA64) | \
1243 (1 << VG_X86_FEAT_PBE))
sewardjd1061ab2004-07-08 01:45:30 +00001244
sewardj5bd4d162004-11-10 13:02:48 +00001245#define VG_AMD_SUPPORTED_FEATURES \
1246 ((0 << (VG_AMD_FEAT_SYSCALL % 32)) | \
1247 (0 << (VG_AMD_FEAT_NXP % 32)) | \
1248 (1 << (VG_AMD_FEAT_MMXEXT % 32)) | \
1249 (0 << (VG_AMD_FEAT_FFXSR % 32)) | \
1250 (0 << (VG_AMD_FEAT_LONGMODE % 32)) | \
1251 (0 << (VG_AMD_FEAT_3DNOWEXT % 32)) | \
1252 (0 << (VG_AMD_FEAT_3DNOW % 32)) | \
1253 /* Common bits between standard features and AMD features */ \
1254 (1 << VG_X86_FEAT_FPU) | \
1255 (1 << VG_X86_FEAT_VME) | \
1256 (1 << VG_X86_FEAT_DE) | \
1257 (1 << VG_X86_FEAT_PSE) | \
1258 (1 << VG_X86_FEAT_TSC) | \
1259 (0 << VG_X86_FEAT_MSR) | \
1260 (1 << VG_X86_FEAT_PAE) | \
1261 (1 << VG_X86_FEAT_MCE) | \
1262 (1 << VG_X86_FEAT_CX8) | \
1263 (1 << VG_X86_FEAT_APIC) | \
1264 (1 << VG_X86_FEAT_MTRR) | \
1265 (1 << VG_X86_FEAT_PGE) | \
1266 (1 << VG_X86_FEAT_MCA) | \
1267 (1 << VG_X86_FEAT_CMOV) | \
1268 (1 << VG_X86_FEAT_PAT) | \
1269 (1 << VG_X86_FEAT_PSE36) | \
1270 (1 << VG_X86_FEAT_MMX) | \
1271 (1 << VG_X86_FEAT_FXSR))
sewardjd1061ab2004-07-08 01:45:30 +00001272
1273
sewardj5bd4d162004-11-10 13:02:48 +00001274//-- /*
sewardjc9a65702004-07-07 16:32:57 +00001275//-- For simulating the cpuid instruction, we will
1276//-- issue a "real" cpuid instruction and then mask out
1277//-- the bits of the features we do not support currently (3dnow mostly).
1278//-- We also claim to not support most CPUID operations.
sewardj5bd4d162004-11-10 13:02:48 +00001279//--
sewardjc9a65702004-07-07 16:32:57 +00001280//-- Dirk Mueller <mueller@kde.org>
1281//--
1282//-- http://www.sandpile.org/ia32/cpuid.htm
1283//--
1284//-- references:
1285//--
1286//-- pre-MMX pentium:
1287//--
1288//-- <werner> cpuid words (0): 0x1 0x756e6547 0x6c65746e 0x49656e69
1289//-- <werner> cpuid words (1): 0x52b 0x0 0x0 0x1bf
1290//--
1291//-- Updated to be more extensible about future vendor extensions and
1292//-- vendor-specific parts of CPUID.
1293//-- */
1294//-- void VG_(helperc_CPUID)(UInt op, UInt *eax_ret, UInt *ebx_ret, UInt *ecx_ret, UInt *edx_ret)
1295//-- {
1296//-- UInt eax, ebx, ecx, edx;
1297//--
1298//-- if (cpuid_level == -2)
sewardj5bd4d162004-11-10 13:02:48 +00001299//-- get_cpu_features(); /* for cpu_vendor */
sewardjc9a65702004-07-07 16:32:57 +00001300//--
1301//-- VG_(cpuid)(op, &eax, &ebx, &ecx, &edx);
1302//--
1303//-- /* Common mangling */
1304//-- switch(op) {
1305//-- case 1:
1306//-- edx &= VG_X86_SUPPORTED_FEATURES;
1307//-- break;
1308//--
1309//-- case 0xd8000000: {
1310//-- /* Implement some private information at 0xd8000000 */
1311//-- static const Char valgrind_vendor[] = "ValgrindVCPU";
1312//--
sewardj5bd4d162004-11-10 13:02:48 +00001313//-- eax = 0xd8000000; /* max request */
sewardjc9a65702004-07-07 16:32:57 +00001314//-- ebx = *(UInt *)&valgrind_vendor[0];
1315//-- ecx = *(UInt *)&valgrind_vendor[8];
1316//-- edx = *(UInt *)&valgrind_vendor[4];
1317//-- }
1318//-- break;
1319//-- }
1320//--
1321//-- /* Vendor-specific mangling of the results */
1322//-- switch(cpu_vendor) {
1323//-- case VG_CPU_VENDOR_INTEL:
1324//-- switch(op) {
1325//-- case 1:
sewardj5bd4d162004-11-10 13:02:48 +00001326//-- ecx = 0; /* mask out all extended features for now */
1327//-- break;
sewardjc9a65702004-07-07 16:32:57 +00001328//--
1329//-- case 0x80000001:
sewardj5bd4d162004-11-10 13:02:48 +00001330//-- ebx = ecx = edx = 0;
1331//-- break;
sewardjc9a65702004-07-07 16:32:57 +00001332//-- }
1333//-- break;
1334//--
1335//-- case VG_CPU_VENDOR_AMD:
1336//-- switch(op) {
1337//-- case 0x80000001:
sewardj5bd4d162004-11-10 13:02:48 +00001338//-- edx &= VG_AMD_SUPPORTED_FEATURES;
1339//-- break;
sewardjc9a65702004-07-07 16:32:57 +00001340//-- }
1341//-- break;
1342//-- }
1343//--
1344//-- *eax_ret = eax;
1345//-- *ebx_ret = ebx;
1346//-- *ecx_ret = ecx;
1347//-- *edx_ret = edx;
1348//-- }
1349//--
1350//--
1351//-- /*------------------------------------------------------------*/
1352//-- /*--- Here so it can be inlined everywhere. ---*/
1353//-- /*------------------------------------------------------------*/
1354//--
1355//-- /* Allocate a new temp reg number. */
1356//-- __inline__ Int VG_(get_new_temp) ( UCodeBlock* cb )
1357//-- {
1358//-- Int t = cb->nextTemp;
1359//-- cb->nextTemp += 2;
1360//-- return t;
1361//-- }
1362//--
1363//-- Int VG_(get_new_shadow) ( UCodeBlock* cb )
1364//-- {
1365//-- Int t = cb->nextTemp;
1366//-- cb->nextTemp += 2;
1367//-- return SHADOW(t);
1368//-- }
1369
1370
sewardj41f43bc2004-07-08 14:23:22 +00001371
sewardjc9a43662004-11-30 18:51:59 +00001372static HChar* nameGrp1 ( Int opc_aux )
sewardj41f43bc2004-07-08 14:23:22 +00001373{
sewardjc9a43662004-11-30 18:51:59 +00001374 static HChar* grp1_names[8]
sewardj41f43bc2004-07-08 14:23:22 +00001375 = { "add", "or", "adc", "sbb", "and", "sub", "xor", "cmp" };
1376 if (opc_aux < 0 || opc_aux > 7) vpanic("nameGrp1(x86)");
1377 return grp1_names[opc_aux];
1378}
1379
sewardjc9a43662004-11-30 18:51:59 +00001380static HChar* nameGrp2 ( Int opc_aux )
sewardje90ad6a2004-07-10 19:02:10 +00001381{
sewardjc9a43662004-11-30 18:51:59 +00001382 static HChar* grp2_names[8]
sewardje90ad6a2004-07-10 19:02:10 +00001383 = { "rol", "ror", "rcl", "rcr", "shl", "shr", "shl", "sar" };
sewardjc2ac51e2004-07-12 01:03:26 +00001384 if (opc_aux < 0 || opc_aux > 7) vpanic("nameGrp2(x86)");
sewardje90ad6a2004-07-10 19:02:10 +00001385 return grp2_names[opc_aux];
1386}
1387
sewardjc9a43662004-11-30 18:51:59 +00001388static HChar* nameGrp4 ( Int opc_aux )
sewardjc2ac51e2004-07-12 01:03:26 +00001389{
sewardjc9a43662004-11-30 18:51:59 +00001390 static HChar* grp4_names[8]
sewardjc2ac51e2004-07-12 01:03:26 +00001391 = { "inc", "dec", "???", "???", "???", "???", "???", "???" };
1392 if (opc_aux < 0 || opc_aux > 1) vpanic("nameGrp4(x86)");
1393 return grp4_names[opc_aux];
1394}
sewardj0611d802004-07-11 02:37:54 +00001395
sewardjc9a43662004-11-30 18:51:59 +00001396static HChar* nameGrp5 ( Int opc_aux )
sewardj0611d802004-07-11 02:37:54 +00001397{
sewardjc9a43662004-11-30 18:51:59 +00001398 static HChar* grp5_names[8]
sewardj0611d802004-07-11 02:37:54 +00001399 = { "inc", "dec", "call*", "call*", "jmp*", "jmp*", "push", "???" };
1400 if (opc_aux < 0 || opc_aux > 6) vpanic("nameGrp5(x86)");
1401 return grp5_names[opc_aux];
1402}
1403
sewardjc9a65702004-07-07 16:32:57 +00001404//-- static Char* nameGrp8 ( Int opc_aux )
1405//-- {
1406//-- static Char* grp8_names[8]
1407//-- = { "???", "???", "???", "???", "bt", "bts", "btr", "btc" };
1408//-- if (opc_aux < 4 || opc_aux > 7) VG_(core_panic)("nameGrp8");
1409//-- return grp8_names[opc_aux];
1410//-- }
1411
sewardjc9a43662004-11-30 18:51:59 +00001412static HChar* nameIReg ( Int size, Int reg )
sewardjc9a65702004-07-07 16:32:57 +00001413{
sewardjc9a43662004-11-30 18:51:59 +00001414 static HChar* ireg32_names[8]
sewardjc9a65702004-07-07 16:32:57 +00001415 = { "%eax", "%ecx", "%edx", "%ebx",
1416 "%esp", "%ebp", "%esi", "%edi" };
sewardjc9a43662004-11-30 18:51:59 +00001417 static HChar* ireg16_names[8]
sewardjc9a65702004-07-07 16:32:57 +00001418 = { "%ax", "%cx", "%dx", "%bx", "%sp", "%bp", "%si", "%di" };
sewardjc9a43662004-11-30 18:51:59 +00001419 static HChar* ireg8_names[8]
sewardjc9a65702004-07-07 16:32:57 +00001420 = { "%al", "%cl", "%dl", "%bl",
1421 "%ah{sp}", "%ch{bp}", "%dh{si}", "%bh{di}" };
1422 if (reg < 0 || reg > 7) goto bad;
1423 switch (size) {
1424 case 4: return ireg32_names[reg];
1425 case 2: return ireg16_names[reg];
1426 case 1: return ireg8_names[reg];
1427 }
1428 bad:
1429 vpanic("nameIReg(X86)");
1430 return NULL; /*notreached*/
1431}
1432
sewardjc9a43662004-11-30 18:51:59 +00001433static HChar* nameSReg ( UInt sreg )
sewardj063f02f2004-10-20 12:36:12 +00001434{
1435 switch (sreg) {
1436 case R_ES: return "%es";
1437 case R_CS: return "%cs";
1438 case R_SS: return "%ss";
1439 case R_DS: return "%ds";
1440 case R_FS: return "%fs";
1441 case R_GS: return "%gs";
1442 default: vpanic("nameSReg(x86)");
1443 }
1444}
1445
sewardjc9a43662004-11-30 18:51:59 +00001446static HChar* nameMMXReg ( Int mmxreg )
sewardj464efa42004-11-19 22:17:29 +00001447{
sewardjc9a43662004-11-30 18:51:59 +00001448 static HChar* mmx_names[8]
sewardj464efa42004-11-19 22:17:29 +00001449 = { "%mm0", "%mm1", "%mm2", "%mm3", "%mm4", "%mm5", "%mm6", "%mm7" };
1450 if (mmxreg < 0 || mmxreg > 7) vpanic("nameMMXReg(x86,guest)");
1451 return mmx_names[mmxreg];
1452}
1453
sewardjc9a43662004-11-30 18:51:59 +00001454static HChar* nameXMMReg ( Int xmmreg )
1455{
1456 static HChar* xmm_names[8]
1457 = { "%xmm0", "%xmm1", "%xmm2", "%xmm3",
1458 "%xmm4", "%xmm5", "%xmm6", "%xmm7" };
1459 if (xmmreg < 0 || xmmreg > 7) vpanic("name_of_xmm_reg");
1460 return xmm_names[xmmreg];
1461}
sewardj464efa42004-11-19 22:17:29 +00001462
1463static Char* nameMMXGran ( UChar gran )
1464{
1465 switch (gran) {
1466 case 0: return "b";
1467 case 1: return "w";
1468 case 2: return "d";
1469 case 3: return "q";
1470 default: vpanic("nameMMXGran(x86,guest)");
1471 }
1472}
sewardjc9a65702004-07-07 16:32:57 +00001473
sewardj41f43bc2004-07-08 14:23:22 +00001474static Char nameISize ( Int size )
sewardjc9a65702004-07-07 16:32:57 +00001475{
1476 switch (size) {
1477 case 4: return 'l';
1478 case 2: return 'w';
1479 case 1: return 'b';
1480 default: vpanic("nameISize(x86)");
1481 }
1482}
1483
sewardjc9a65702004-07-07 16:32:57 +00001484//-- __inline__ static UInt LOW24 ( UInt x )
1485//-- {
1486//-- return x & 0x00FFFFFF;
1487//-- }
1488//--
1489//-- __inline__ static UInt HI8 ( UInt x )
1490//-- {
1491//-- return x >> 24;
1492//-- }
1493//--
sewardjc9a65702004-07-07 16:32:57 +00001494//-- /*------------------------------------------------------------*/
1495//-- /*--- Flag-related helpers. ---*/
1496//-- /*------------------------------------------------------------*/
1497//--
1498//-- static void setFlagsFromUOpcode ( UCodeBlock* cb, Int uopc )
1499//-- {
1500//-- switch (uopc) {
1501//-- case XOR: case OR: case AND:
1502//-- uFlagsRWU(cb, FlagsEmpty, FlagsOSZCP, FlagA); break;
1503//-- case ADC: case SBB:
1504//-- uFlagsRWU(cb, FlagC, FlagsOSZACP, FlagsEmpty); break;
1505//-- case MUL: case UMUL:
sewardj5bd4d162004-11-10 13:02:48 +00001506//-- uFlagsRWU(cb, FlagsEmpty, FlagsOC, FlagsSZAP); break;
sewardjc9a65702004-07-07 16:32:57 +00001507//-- case ADD: case SUB: case NEG:
1508//-- uFlagsRWU(cb, FlagsEmpty, FlagsOSZACP, FlagsEmpty); break;
1509//-- case INC: case DEC:
1510//-- uFlagsRWU(cb, FlagsEmpty, FlagsOSZAP, FlagsEmpty); break;
1511//-- case SHR: case SAR: case SHL:
1512//-- uFlagsRWU(cb, FlagsEmpty, FlagsOSZCP, FlagA); break;
1513//-- case ROL: case ROR:
1514//-- uFlagsRWU(cb, FlagsEmpty, FlagsOC, FlagsEmpty); break;
1515//-- case RCR: case RCL:
1516//-- uFlagsRWU(cb, FlagC, FlagsOC, FlagsEmpty); break;
1517//-- case NOT:
1518//-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty); break;
1519//-- default:
1520//-- VG_(printf)("unhandled case is %s\n",
1521//-- VG_(name_UOpcode)(True, uopc));
1522//-- VG_(core_panic)("setFlagsFromUOpcode: unhandled case");
1523//-- }
1524//-- }
sewardjd1061ab2004-07-08 01:45:30 +00001525
1526/*------------------------------------------------------------*/
1527/*--- JMP helpers ---*/
1528/*------------------------------------------------------------*/
1529
sewardj78c19df2004-07-12 22:49:27 +00001530static void jmp_lit( IRJumpKind kind, Addr32 d32 )
sewardjd1061ab2004-07-08 01:45:30 +00001531{
sewardje539a402004-07-14 18:24:17 +00001532 irbb->next = mkU32(d32);
1533 irbb->jumpkind = kind;
sewardjd1061ab2004-07-08 01:45:30 +00001534}
1535
sewardj78c19df2004-07-12 22:49:27 +00001536static void jmp_treg( IRJumpKind kind, IRTemp t )
sewardje05c42c2004-07-08 20:25:10 +00001537{
sewardje539a402004-07-14 18:24:17 +00001538 irbb->next = mkexpr(t);
1539 irbb->jumpkind = kind;
sewardje05c42c2004-07-08 20:25:10 +00001540}
sewardje87b4842004-07-10 12:23:30 +00001541
sewardj2a9ad022004-11-25 02:46:58 +00001542static
1543void jcc_01( X86Condcode cond, Addr32 d32_false, Addr32 d32_true )
sewardje87b4842004-07-10 12:23:30 +00001544{
sewardj2a9ad022004-11-25 02:46:58 +00001545 Bool invert;
1546 X86Condcode condPos;
1547 condPos = positiveIse_X86Condcode ( cond, &invert );
sewardje87b4842004-07-10 12:23:30 +00001548 if (invert) {
sewardj2a9ad022004-11-25 02:46:58 +00001549 stmt( IRStmt_Exit( mk_x86g_calculate_condition(condPos),
sewardj893aada2004-11-29 19:57:54 +00001550 Ijk_Boring,
sewardj78c19df2004-07-12 22:49:27 +00001551 IRConst_U32(d32_false) ) );
sewardje539a402004-07-14 18:24:17 +00001552 irbb->next = mkU32(d32_true);
1553 irbb->jumpkind = Ijk_Boring;
sewardje87b4842004-07-10 12:23:30 +00001554 } else {
sewardj2a9ad022004-11-25 02:46:58 +00001555 stmt( IRStmt_Exit( mk_x86g_calculate_condition(condPos),
sewardj893aada2004-11-29 19:57:54 +00001556 Ijk_Boring,
sewardj78c19df2004-07-12 22:49:27 +00001557 IRConst_U32(d32_true) ) );
sewardje539a402004-07-14 18:24:17 +00001558 irbb->next = mkU32(d32_false);
1559 irbb->jumpkind = Ijk_Boring;
sewardje87b4842004-07-10 12:23:30 +00001560 }
1561}
sewardjc9a65702004-07-07 16:32:57 +00001562
1563
sewardjd1061ab2004-07-08 01:45:30 +00001564/*------------------------------------------------------------*/
1565/*--- Disassembling addressing modes ---*/
1566/*------------------------------------------------------------*/
sewardjc9a65702004-07-07 16:32:57 +00001567
sewardjd1061ab2004-07-08 01:45:30 +00001568static
1569UChar* sorbTxt ( UChar sorb )
1570{
1571 switch (sorb) {
1572 case 0: return ""; /* no override */
1573 case 0x3E: return "%ds";
1574 case 0x26: return "%es:";
1575 case 0x64: return "%fs:";
1576 case 0x65: return "%gs:";
1577 default: vpanic("sorbTxt(x86)");
1578 }
1579}
1580
1581
1582/* Tmp is a TempReg holding a virtual address. Convert it to a linear
1583 address by adding any required segment override as indicated by
1584 sorb. */
1585static
1586IRExpr* handleSegOverride ( UChar sorb, IRExpr* virtual )
1587{
1588 //Int sreg, tsreg;
1589
1590 if (sorb == 0)
1591 /* the common case - no override */
1592 return virtual;
1593
1594 unimplemented("segment overrides in new x86->IR phase");
1595#if 0
1596 switch (sorb) {
1597 case 0x3E: sreg = R_DS; break;
1598 case 0x26: sreg = R_ES; break;
1599 case 0x64: sreg = R_FS; break;
1600 case 0x65: sreg = R_GS; break;
1601 default: VG_(core_panic)("handleSegOverride");
1602 }
1603
1604 tsreg = newTemp(cb);
1605
1606 /* sreg -> tsreg */
1607 uInstr2(cb, GETSEG, 2, ArchRegS, sreg, TempReg, tsreg );
1608
1609 /* tmp += segment_base(ldt[tsreg]); also do limit check */
1610 uInstr2(cb, USESEG, 0, TempReg, tsreg, TempReg, tmp );
1611#endif
1612}
1613
1614
1615/* Generate IR to calculate an address indicated by a ModRM and
1616 following SIB bytes. The expression, and the number of bytes in
1617 the address mode, are returned. Note that this fn should not be
1618 called if the R/M part of the address denotes a register instead of
1619 memory. If print_codegen is true, text of the addressing mode is
sewardj940e8c92004-07-11 16:53:24 +00001620 placed in buf.
1621
1622 The computed address is stored in a new tempreg, and the
1623 identity of the tempreg is returned. */
1624
1625static IRTemp disAMode_copy2tmp ( IRExpr* addr32 )
1626{
1627 IRTemp tmp = newTemp(Ity_I32);
1628 assign( tmp, addr32 );
1629 return tmp;
1630}
sewardjd1061ab2004-07-08 01:45:30 +00001631
1632static
sewardj940e8c92004-07-11 16:53:24 +00001633IRTemp disAMode ( Int* len, UChar sorb, UInt delta, UChar* buf )
sewardjd1061ab2004-07-08 01:45:30 +00001634{
1635 UChar mod_reg_rm = getIByte(delta);
1636 delta++;
1637
1638 /* squeeze out the reg field from mod_reg_rm, since a 256-entry
1639 jump table seems a bit excessive.
1640 */
1641 mod_reg_rm &= 0xC7; /* is now XX000YYY */
1642 mod_reg_rm |= (mod_reg_rm >> 3); /* is now XX0XXYYY */
1643 mod_reg_rm &= 0x1F; /* is now 000XXYYY */
1644 switch (mod_reg_rm) {
1645
1646 /* (%eax) .. (%edi), not including (%esp) or (%ebp).
1647 --> GET %reg, t
1648 */
1649 case 0x00: case 0x01: case 0x02: case 0x03:
1650 /* ! 04 */ /* ! 05 */ case 0x06: case 0x07:
1651 { UChar rm = mod_reg_rm;
1652 DIS(buf, "%s(%s)", sorbTxt(sorb), nameIReg(4,rm));
1653 *len = 1;
sewardj5bd4d162004-11-10 13:02:48 +00001654 return disAMode_copy2tmp(
sewardj940e8c92004-07-11 16:53:24 +00001655 handleSegOverride(sorb, getIReg(4,rm)));
sewardjd1061ab2004-07-08 01:45:30 +00001656 }
1657
1658 /* d8(%eax) ... d8(%edi), not including d8(%esp)
1659 --> GET %reg, t ; ADDL d8, t
1660 */
1661 case 0x08: case 0x09: case 0x0A: case 0x0B:
1662 /* ! 0C */ case 0x0D: case 0x0E: case 0x0F:
1663 { UChar rm = mod_reg_rm & 7;
1664 UInt d = getSDisp8(delta);
1665 DIS(buf, "%s%d(%s)", sorbTxt(sorb), d, nameIReg(4,rm));
sewardj5bd4d162004-11-10 13:02:48 +00001666 *len = 2;
1667 return disAMode_copy2tmp(
sewardj940e8c92004-07-11 16:53:24 +00001668 handleSegOverride(sorb,
1669 binop(Iop_Add32,getIReg(4,rm),mkU32(d))));
sewardjd1061ab2004-07-08 01:45:30 +00001670 }
1671
1672 /* d32(%eax) ... d32(%edi), not including d32(%esp)
1673 --> GET %reg, t ; ADDL d8, t
1674 */
1675 case 0x10: case 0x11: case 0x12: case 0x13:
1676 /* ! 14 */ case 0x15: case 0x16: case 0x17:
1677 { UChar rm = mod_reg_rm & 7;
1678 UInt d = getUDisp32(delta);
1679 DIS(buf, "%s0x%x(%s)", sorbTxt(sorb), d, nameIReg(4,rm));
sewardj5bd4d162004-11-10 13:02:48 +00001680 *len = 5;
1681 return disAMode_copy2tmp(
sewardj940e8c92004-07-11 16:53:24 +00001682 handleSegOverride(sorb,
1683 binop(Iop_Add32,getIReg(4,rm),mkU32(d))));
sewardjd1061ab2004-07-08 01:45:30 +00001684 }
1685
1686 /* a register, %eax .. %edi. This shouldn't happen. */
1687 case 0x18: case 0x19: case 0x1A: case 0x1B:
1688 case 0x1C: case 0x1D: case 0x1E: case 0x1F:
1689 vpanic("disAMode(x86): not an addr!");
1690
1691 /* a 32-bit literal address
1692 --> MOV d32, tmp
1693 */
1694 case 0x05:
1695 { UInt d = getUDisp32(delta);
1696 *len = 5;
1697 DIS(buf, "%s(0x%x)", sorbTxt(sorb), d);
sewardj940e8c92004-07-11 16:53:24 +00001698 return disAMode_copy2tmp(
1699 handleSegOverride(sorb, mkU32(d)));
sewardjd1061ab2004-07-08 01:45:30 +00001700 }
1701
1702 case 0x04: {
1703 /* SIB, with no displacement. Special cases:
1704 -- %esp cannot act as an index value.
1705 If index_r indicates %esp, zero is used for the index.
1706 -- when mod is zero and base indicates EBP, base is instead
1707 a 32-bit literal.
1708 It's all madness, I tell you. Extract %index, %base and
1709 scale from the SIB byte. The value denoted is then:
1710 | %index == %ESP && %base == %EBP
1711 = d32 following SIB byte
1712 | %index == %ESP && %base != %EBP
1713 = %base
1714 | %index != %ESP && %base == %EBP
1715 = d32 following SIB byte + (%index << scale)
1716 | %index != %ESP && %base != %ESP
1717 = %base + (%index << scale)
1718
1719 What happens to the souls of CPU architects who dream up such
1720 horrendous schemes, do you suppose?
1721 */
1722 UChar sib = getIByte(delta);
1723 UChar scale = (sib >> 6) & 3;
1724 UChar index_r = (sib >> 3) & 7;
1725 UChar base_r = sib & 7;
sewardj5bd4d162004-11-10 13:02:48 +00001726 delta++;
sewardjd1061ab2004-07-08 01:45:30 +00001727
1728 if (index_r != R_ESP && base_r != R_EBP) {
1729 DIS(buf, "%s(%s,%s,%d)", sorbTxt(sorb),
1730 nameIReg(4,base_r), nameIReg(4,index_r), 1<<scale);
sewardj5bd4d162004-11-10 13:02:48 +00001731 *len = 2;
sewardj940e8c92004-07-11 16:53:24 +00001732 return
1733 disAMode_copy2tmp(
sewardj5bd4d162004-11-10 13:02:48 +00001734 handleSegOverride(sorb,
1735 binop(Iop_Add32,
sewardjd1061ab2004-07-08 01:45:30 +00001736 getIReg(4,base_r),
1737 binop(Iop_Shl32, getIReg(4,index_r),
sewardj6d2638e2004-07-15 09:38:27 +00001738 mkU8(scale)))));
sewardjd1061ab2004-07-08 01:45:30 +00001739 }
1740
1741 if (index_r != R_ESP && base_r == R_EBP) {
1742 UInt d = getUDisp32(delta);
1743 DIS(buf, "%s0x%x(,%s,%d)", sorbTxt(sorb), d,
1744 nameIReg(4,index_r), 1<<scale);
1745 *len = 6;
1746 return
sewardj940e8c92004-07-11 16:53:24 +00001747 disAMode_copy2tmp(
sewardjd1061ab2004-07-08 01:45:30 +00001748 handleSegOverride(sorb,
sewardj5bd4d162004-11-10 13:02:48 +00001749 binop(Iop_Add32,
1750 binop(Iop_Shl32, getIReg(4,index_r), mkU8(scale)),
sewardj940e8c92004-07-11 16:53:24 +00001751 mkU32(d))));
sewardjd1061ab2004-07-08 01:45:30 +00001752 }
1753
1754 if (index_r == R_ESP && base_r != R_EBP) {
1755 DIS(buf, "%s(%s,,)", sorbTxt(sorb), nameIReg(4,base_r));
sewardj5bd4d162004-11-10 13:02:48 +00001756 *len = 2;
1757 return disAMode_copy2tmp(
sewardj940e8c92004-07-11 16:53:24 +00001758 handleSegOverride(sorb, getIReg(4,base_r)));
sewardjd1061ab2004-07-08 01:45:30 +00001759 }
1760
1761 if (index_r == R_ESP && base_r == R_EBP) {
1762 UInt d = getUDisp32(delta);
1763 DIS(buf, "%s0x%x()", sorbTxt(sorb), d);
sewardj5bd4d162004-11-10 13:02:48 +00001764 *len = 6;
1765 vpanic("amode 8");
1766 return disAMode_copy2tmp(
sewardj940e8c92004-07-11 16:53:24 +00001767 handleSegOverride(sorb, mkU32(d)));
sewardjd1061ab2004-07-08 01:45:30 +00001768 }
1769
1770 vassert(0);
1771 }
1772
1773 /* SIB, with 8-bit displacement. Special cases:
1774 -- %esp cannot act as an index value.
1775 If index_r indicates %esp, zero is used for the index.
1776 Denoted value is:
1777 | %index == %ESP
1778 = d8 + %base
1779 | %index != %ESP
1780 = d8 + %base + (%index << scale)
1781 */
1782 case 0x0C: {
1783 UChar sib = getIByte(delta);
1784 UChar scale = (sib >> 6) & 3;
1785 UChar index_r = (sib >> 3) & 7;
1786 UChar base_r = sib & 7;
1787 UInt d = getSDisp8(delta+1);
1788
1789 if (index_r == R_ESP) {
1790 DIS(buf, "%s%d(%s,,)", sorbTxt(sorb), d, nameIReg(4,base_r));
sewardj5bd4d162004-11-10 13:02:48 +00001791 *len = 3;
1792 return disAMode_copy2tmp(
sewardj940e8c92004-07-11 16:53:24 +00001793 handleSegOverride(sorb,
1794 binop(Iop_Add32, getIReg(4,base_r), mkU32(d)) ));
sewardjd1061ab2004-07-08 01:45:30 +00001795 } else {
1796 DIS(buf, "%s%d(%s,%s,%d)", sorbTxt(sorb), d,
1797 nameIReg(4,base_r), nameIReg(4,index_r), 1<<scale);
sewardj5bd4d162004-11-10 13:02:48 +00001798 *len = 3;
1799 return
sewardj940e8c92004-07-11 16:53:24 +00001800 disAMode_copy2tmp(
1801 handleSegOverride(sorb,
sewardj77b86be2004-07-11 13:28:24 +00001802 binop(Iop_Add32,
1803 binop(Iop_Add32,
1804 getIReg(4,base_r),
1805 binop(Iop_Shl32,
sewardj6d2638e2004-07-15 09:38:27 +00001806 getIReg(4,index_r), mkU8(scale))),
sewardj940e8c92004-07-11 16:53:24 +00001807 mkU32(d))));
sewardjd1061ab2004-07-08 01:45:30 +00001808 }
1809 vassert(0);
1810 }
1811
1812 /* SIB, with 32-bit displacement. Special cases:
1813 -- %esp cannot act as an index value.
1814 If index_r indicates %esp, zero is used for the index.
1815 Denoted value is:
1816 | %index == %ESP
1817 = d32 + %base
1818 | %index != %ESP
1819 = d32 + %base + (%index << scale)
1820 */
1821 case 0x14: {
1822 UChar sib = getIByte(delta);
1823 UChar scale = (sib >> 6) & 3;
1824 UChar index_r = (sib >> 3) & 7;
1825 UChar base_r = sib & 7;
1826 UInt d = getUDisp32(delta+1);
1827
1828 if (index_r == R_ESP) {
1829 DIS(buf, "%s%d(%s,,)", sorbTxt(sorb), d, nameIReg(4,base_r));
sewardj5bd4d162004-11-10 13:02:48 +00001830 *len = 6;
1831 return disAMode_copy2tmp(
sewardj940e8c92004-07-11 16:53:24 +00001832 handleSegOverride(sorb,
1833 binop(Iop_Add32, getIReg(4,base_r), mkU32(d)) ));
sewardjd1061ab2004-07-08 01:45:30 +00001834 } else {
1835 DIS(buf, "%s%d(%s,%s,%d)", sorbTxt(sorb), d,
1836 nameIReg(4,base_r), nameIReg(4,index_r), 1<<scale);
sewardj5bd4d162004-11-10 13:02:48 +00001837 *len = 6;
1838 return
sewardj940e8c92004-07-11 16:53:24 +00001839 disAMode_copy2tmp(
1840 handleSegOverride(sorb,
sewardj9334b0f2004-07-10 22:43:54 +00001841 binop(Iop_Add32,
1842 binop(Iop_Add32,
1843 getIReg(4,base_r),
1844 binop(Iop_Shl32,
sewardj6d2638e2004-07-15 09:38:27 +00001845 getIReg(4,index_r), mkU8(scale))),
sewardj940e8c92004-07-11 16:53:24 +00001846 mkU32(d))));
sewardjd1061ab2004-07-08 01:45:30 +00001847 }
1848 vassert(0);
1849 }
1850
1851 default:
1852 vpanic("disAMode(x86)");
1853 return 0; /*notreached*/
1854 }
1855}
1856
1857
1858/* Figure out the number of (insn-stream) bytes constituting the amode
1859 beginning at delta. Is useful for getting hold of literals beyond
1860 the end of the amode before it has been disassembled. */
1861
1862static UInt lengthAMode ( UInt delta )
1863{
1864 UChar mod_reg_rm = getIByte(delta); delta++;
1865
1866 /* squeeze out the reg field from mod_reg_rm, since a 256-entry
1867 jump table seems a bit excessive.
1868 */
1869 mod_reg_rm &= 0xC7; /* is now XX000YYY */
1870 mod_reg_rm |= (mod_reg_rm >> 3); /* is now XX0XXYYY */
1871 mod_reg_rm &= 0x1F; /* is now 000XXYYY */
1872 switch (mod_reg_rm) {
1873
1874 /* (%eax) .. (%edi), not including (%esp) or (%ebp). */
1875 case 0x00: case 0x01: case 0x02: case 0x03:
1876 /* ! 04 */ /* ! 05 */ case 0x06: case 0x07:
1877 return 1;
1878
1879 /* d8(%eax) ... d8(%edi), not including d8(%esp). */
1880 case 0x08: case 0x09: case 0x0A: case 0x0B:
1881 /* ! 0C */ case 0x0D: case 0x0E: case 0x0F:
1882 return 2;
1883
1884 /* d32(%eax) ... d32(%edi), not including d32(%esp). */
1885 case 0x10: case 0x11: case 0x12: case 0x13:
1886 /* ! 14 */ case 0x15: case 0x16: case 0x17:
1887 return 5;
1888
1889 /* a register, %eax .. %edi. (Not an addr, but still handled.) */
1890 case 0x18: case 0x19: case 0x1A: case 0x1B:
1891 case 0x1C: case 0x1D: case 0x1E: case 0x1F:
1892 return 1;
1893
1894 /* a 32-bit literal address. */
1895 case 0x05: return 5;
1896
1897 /* SIB, no displacement. */
1898 case 0x04: {
1899 UChar sib = getIByte(delta);
1900 UChar base_r = sib & 7;
1901 if (base_r == R_EBP) return 6; else return 2;
1902 }
1903 /* SIB, with 8-bit displacement. */
1904 case 0x0C: return 3;
1905
1906 /* SIB, with 32-bit displacement. */
1907 case 0x14: return 6;
1908
1909 default:
1910 vpanic("lengthAMode");
1911 return 0; /*notreached*/
1912 }
1913}
1914
1915/*------------------------------------------------------------*/
1916/*--- Disassembling common idioms ---*/
1917/*------------------------------------------------------------*/
1918
sewardj5df3bfe2004-07-27 09:30:31 +00001919static
1920void codegen_XOR_reg_with_itself ( Int size, Int ge_reg )
1921{
1922 IRType ty = szToITy(size);
1923 /* reg := 0 */
1924 putIReg(size, ge_reg, mkU(ty,0));
1925 /* Flags: C,A,O=0, Z=1, S=0, P=1 */
sewardj2a9ad022004-11-25 02:46:58 +00001926 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
1927 stmt( IRStmt_Put( OFFB_CC_DEP1, mkU32(X86G_CC_MASK_Z|X86G_CC_MASK_P) ));
sewardj2a2ba8b2004-11-08 13:14:06 +00001928 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
sewardj5df3bfe2004-07-27 09:30:31 +00001929 DIP("xor%c %s, %s\n", nameISize(size),
1930 nameIReg(size,ge_reg), nameIReg(size,ge_reg) );
1931}
1932
1933
sewardje87b4842004-07-10 12:23:30 +00001934/* Handle binary integer instructions of the form
1935 op E, G meaning
1936 op reg-or-mem, reg
1937 Is passed the a ptr to the modRM byte, the actual operation, and the
1938 data size. Returns the address advanced completely over this
1939 instruction.
1940
1941 E(src) is reg-or-mem
1942 G(dst) is reg.
1943
1944 If E is reg, --> GET %G, tmp
1945 OP %E, tmp
1946 PUT tmp, %G
1947
1948 If E is mem and OP is not reversible,
1949 --> (getAddr E) -> tmpa
1950 LD (tmpa), tmpa
1951 GET %G, tmp2
1952 OP tmpa, tmp2
1953 PUT tmp2, %G
1954
1955 If E is mem and OP is reversible
1956 --> (getAddr E) -> tmpa
1957 LD (tmpa), tmpa
1958 OP %G, tmpa
1959 PUT tmpa, %G
1960*/
1961static
1962UInt dis_op2_E_G ( UChar sorb,
sewardj180e8b32004-07-29 01:40:11 +00001963 Bool addSubCarry,
sewardje87b4842004-07-10 12:23:30 +00001964 IROp op8,
1965 Bool keep,
1966 Int size,
1967 UInt delta0,
1968 Char* t_x86opc )
1969{
sewardjc9a43662004-11-30 18:51:59 +00001970 HChar dis_buf[50];
sewardj9334b0f2004-07-10 22:43:54 +00001971 Int len;
sewardje87b4842004-07-10 12:23:30 +00001972 IRType ty = szToITy(size);
1973 IRTemp dst1 = newTemp(ty);
1974 IRTemp src = newTemp(ty);
1975 IRTemp dst0 = newTemp(ty);
1976 UChar rm = getUChar(delta0);
sewardj92d168d2004-11-15 14:22:12 +00001977 IRTemp addr = IRTemp_INVALID;
sewardje87b4842004-07-10 12:23:30 +00001978
sewardj180e8b32004-07-29 01:40:11 +00001979 /* addSubCarry == True indicates the intended operation is
1980 add-with-carry or subtract-with-borrow. */
1981 if (addSubCarry) {
1982 vassert(op8 == Iop_Add8 || op8 == Iop_Sub8);
1983 vassert(keep);
1984 }
1985
sewardje87b4842004-07-10 12:23:30 +00001986 if (epartIsReg(rm)) {
sewardje87b4842004-07-10 12:23:30 +00001987 /* Specially handle XOR reg,reg, because that doesn't really
1988 depend on reg, and doing the obvious thing potentially
1989 generates a spurious value check failure due to the bogus
1990 dependency. */
sewardj5df3bfe2004-07-27 09:30:31 +00001991 if (op8 == Iop_Xor8 && gregOfRM(rm) == eregOfRM(rm)) {
1992 codegen_XOR_reg_with_itself ( size, gregOfRM(rm) );
1993 return 1+delta0;
sewardje87b4842004-07-10 12:23:30 +00001994 }
sewardje87b4842004-07-10 12:23:30 +00001995 assign( dst0, getIReg(size,gregOfRM(rm)) );
1996 assign( src, getIReg(size,eregOfRM(rm)) );
sewardje87b4842004-07-10 12:23:30 +00001997
sewardj180e8b32004-07-29 01:40:11 +00001998 if (addSubCarry && op8 == Iop_Add8) {
1999 vassert(0);
2000 helper_ADC( size, dst1, dst0, src );
sewardje87b4842004-07-10 12:23:30 +00002001 putIReg(size, gregOfRM(rm), mkexpr(dst1));
sewardj180e8b32004-07-29 01:40:11 +00002002 } else
2003 if (addSubCarry && op8 == Iop_Sub8) {
sewardj180e8b32004-07-29 01:40:11 +00002004 helper_SBB( size, dst1, dst0, src );
2005 putIReg(size, gregOfRM(rm), mkexpr(dst1));
2006 } else {
2007 assign( dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
sewardj5bd4d162004-11-10 13:02:48 +00002008 if (isAddSub(op8))
sewardj2a2ba8b2004-11-08 13:14:06 +00002009 setFlags_DEP1_DEP2(op8, dst0, src, ty);
sewardjb9c5cf62004-08-24 15:10:38 +00002010 else
sewardj2a2ba8b2004-11-08 13:14:06 +00002011 setFlags_DEP1(op8, dst1, ty);
sewardj180e8b32004-07-29 01:40:11 +00002012 if (keep)
2013 putIReg(size, gregOfRM(rm), mkexpr(dst1));
2014 }
sewardje87b4842004-07-10 12:23:30 +00002015
2016 DIP("%s%c %s,%s\n", t_x86opc, nameISize(size),
2017 nameIReg(size,eregOfRM(rm)),
2018 nameIReg(size,gregOfRM(rm)));
2019 return 1+delta0;
sewardje87b4842004-07-10 12:23:30 +00002020 } else {
sewardj9334b0f2004-07-10 22:43:54 +00002021 /* E refers to memory */
2022 addr = disAMode ( &len, sorb, delta0, dis_buf);
2023 assign( dst0, getIReg(size,gregOfRM(rm)) );
sewardj940e8c92004-07-11 16:53:24 +00002024 assign( src, loadLE(szToITy(size), mkexpr(addr)) );
sewardj9334b0f2004-07-10 22:43:54 +00002025
sewardj180e8b32004-07-29 01:40:11 +00002026 if (addSubCarry && op8 == Iop_Add8) {
sewardj180e8b32004-07-29 01:40:11 +00002027 helper_ADC( size, dst1, dst0, src );
sewardj9334b0f2004-07-10 22:43:54 +00002028 putIReg(size, gregOfRM(rm), mkexpr(dst1));
sewardj180e8b32004-07-29 01:40:11 +00002029 } else
2030 if (addSubCarry && op8 == Iop_Sub8) {
2031 helper_SBB( size, dst1, dst0, src );
2032 putIReg(size, gregOfRM(rm), mkexpr(dst1));
2033 } else {
2034 assign( dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
sewardj5bd4d162004-11-10 13:02:48 +00002035 if (isAddSub(op8))
sewardj2a2ba8b2004-11-08 13:14:06 +00002036 setFlags_DEP1_DEP2(op8, dst0, src, ty);
sewardjb9c5cf62004-08-24 15:10:38 +00002037 else
sewardj2a2ba8b2004-11-08 13:14:06 +00002038 setFlags_DEP1(op8, dst1, ty);
sewardj180e8b32004-07-29 01:40:11 +00002039 if (keep)
2040 putIReg(size, gregOfRM(rm), mkexpr(dst1));
2041 }
sewardj9334b0f2004-07-10 22:43:54 +00002042
sewardje87b4842004-07-10 12:23:30 +00002043 DIP("%s%c %s,%s\n", t_x86opc, nameISize(size),
2044 dis_buf,nameIReg(size,gregOfRM(rm)));
sewardj9334b0f2004-07-10 22:43:54 +00002045 return len+delta0;
sewardje87b4842004-07-10 12:23:30 +00002046 }
sewardje87b4842004-07-10 12:23:30 +00002047}
sewardje05c42c2004-07-08 20:25:10 +00002048
2049
2050
2051/* Handle binary integer instructions of the form
2052 op G, E meaning
2053 op reg, reg-or-mem
2054 Is passed the a ptr to the modRM byte, the actual operation, and the
2055 data size. Returns the address advanced completely over this
2056 instruction.
2057
2058 G(src) is reg.
2059 E(dst) is reg-or-mem
2060
2061 If E is reg, --> GET %E, tmp
2062 OP %G, tmp
2063 PUT tmp, %E
2064
2065 If E is mem, --> (getAddr E) -> tmpa
2066 LD (tmpa), tmpv
2067 OP %G, tmpv
2068 ST tmpv, (tmpa)
2069*/
2070static
2071UInt dis_op2_G_E ( UChar sorb,
sewardjcaca9d02004-07-28 07:11:32 +00002072 Bool addSubCarry,
sewardje05c42c2004-07-08 20:25:10 +00002073 IROp op8,
2074 Bool keep,
2075 Int size,
2076 UInt delta0,
2077 Char* t_x86opc )
2078{
sewardjc9a43662004-11-30 18:51:59 +00002079 HChar dis_buf[50];
sewardje87b4842004-07-10 12:23:30 +00002080 Int len;
sewardje05c42c2004-07-08 20:25:10 +00002081 IRType ty = szToITy(size);
2082 IRTemp dst1 = newTemp(ty);
2083 IRTemp src = newTemp(ty);
2084 IRTemp dst0 = newTemp(ty);
2085 UChar rm = getIByte(delta0);
sewardj92d168d2004-11-15 14:22:12 +00002086 IRTemp addr = IRTemp_INVALID;
sewardje05c42c2004-07-08 20:25:10 +00002087
sewardjcaca9d02004-07-28 07:11:32 +00002088 /* addSubCarry == True indicates the intended operation is
2089 add-with-carry or subtract-with-borrow. */
2090 if (addSubCarry) {
2091 vassert(op8 == Iop_Add8 || op8 == Iop_Sub8);
2092 vassert(keep);
2093 }
2094
sewardje05c42c2004-07-08 20:25:10 +00002095 if (epartIsReg(rm)) {
sewardje05c42c2004-07-08 20:25:10 +00002096 /* Specially handle XOR reg,reg, because that doesn't really
2097 depend on reg, and doing the obvious thing potentially
2098 generates a spurious value check failure due to the bogus
2099 dependency. */
sewardj5df3bfe2004-07-27 09:30:31 +00002100 if (op8 == Iop_Xor8 && gregOfRM(rm) == eregOfRM(rm)) {
2101 codegen_XOR_reg_with_itself ( size, gregOfRM(rm) );
2102 return 1+delta0;
sewardje05c42c2004-07-08 20:25:10 +00002103 }
sewardje05c42c2004-07-08 20:25:10 +00002104 assign(dst0, getIReg(size,eregOfRM(rm)));
2105 assign(src, getIReg(size,gregOfRM(rm)));
sewardje05c42c2004-07-08 20:25:10 +00002106
sewardjcaca9d02004-07-28 07:11:32 +00002107 if (addSubCarry && op8 == Iop_Add8) {
sewardj1813dbe2004-07-28 17:09:04 +00002108 helper_ADC( size, dst1, dst0, src );
2109 putIReg(size, eregOfRM(rm), mkexpr(dst1));
sewardjcaca9d02004-07-28 07:11:32 +00002110 } else
2111 if (addSubCarry && op8 == Iop_Sub8) {
2112 helper_SBB( size, dst1, dst0, src );
sewardje05c42c2004-07-08 20:25:10 +00002113 putIReg(size, eregOfRM(rm), mkexpr(dst1));
sewardjcaca9d02004-07-28 07:11:32 +00002114 } else {
2115 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
sewardj5bd4d162004-11-10 13:02:48 +00002116 if (isAddSub(op8))
sewardj2a2ba8b2004-11-08 13:14:06 +00002117 setFlags_DEP1_DEP2(op8, dst0, src, ty);
sewardjb9c5cf62004-08-24 15:10:38 +00002118 else
sewardj2a2ba8b2004-11-08 13:14:06 +00002119 setFlags_DEP1(op8, dst1, ty);
sewardjcaca9d02004-07-28 07:11:32 +00002120 if (keep)
2121 putIReg(size, eregOfRM(rm), mkexpr(dst1));
2122 }
sewardje05c42c2004-07-08 20:25:10 +00002123
2124 DIP("%s%c %s,%s\n", t_x86opc, nameISize(size),
2125 nameIReg(size,gregOfRM(rm)),
2126 nameIReg(size,eregOfRM(rm)));
2127 return 1+delta0;
2128 }
2129
2130 /* E refers to memory */
2131 {
sewardje87b4842004-07-10 12:23:30 +00002132 addr = disAMode ( &len, sorb, delta0, dis_buf);
sewardj940e8c92004-07-11 16:53:24 +00002133 assign(dst0, loadLE(ty,mkexpr(addr)));
sewardje87b4842004-07-10 12:23:30 +00002134 assign(src, getIReg(size,gregOfRM(rm)));
sewardje05c42c2004-07-08 20:25:10 +00002135
sewardjcaca9d02004-07-28 07:11:32 +00002136 if (addSubCarry && op8 == Iop_Add8) {
2137 helper_ADC( size, dst1, dst0, src );
2138 storeLE(mkexpr(addr), mkexpr(dst1));
2139 } else
2140 if (addSubCarry && op8 == Iop_Sub8) {
2141 helper_SBB( size, dst1, dst0, src );
2142 storeLE(mkexpr(addr), mkexpr(dst1));
2143 } else {
2144 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
sewardj5bd4d162004-11-10 13:02:48 +00002145 if (isAddSub(op8))
sewardj2a2ba8b2004-11-08 13:14:06 +00002146 setFlags_DEP1_DEP2(op8, dst0, src, ty);
sewardjb9c5cf62004-08-24 15:10:38 +00002147 else
sewardj2a2ba8b2004-11-08 13:14:06 +00002148 setFlags_DEP1(op8, dst1, ty);
sewardjcaca9d02004-07-28 07:11:32 +00002149 if (keep)
2150 storeLE(mkexpr(addr), mkexpr(dst1));
2151 }
sewardje87b4842004-07-10 12:23:30 +00002152
sewardje05c42c2004-07-08 20:25:10 +00002153 DIP("%s%c %s,%s\n", t_x86opc, nameISize(size),
2154 nameIReg(size,gregOfRM(rm)), dis_buf);
sewardje87b4842004-07-10 12:23:30 +00002155 return len+delta0;
sewardje05c42c2004-07-08 20:25:10 +00002156 }
2157}
2158
2159
2160/* Handle move instructions of the form
2161 mov E, G meaning
2162 mov reg-or-mem, reg
2163 Is passed the a ptr to the modRM byte, and the data size. Returns
2164 the address advanced completely over this instruction.
2165
2166 E(src) is reg-or-mem
2167 G(dst) is reg.
2168
2169 If E is reg, --> GET %E, tmpv
2170 PUT tmpv, %G
2171
2172 If E is mem --> (getAddr E) -> tmpa
2173 LD (tmpa), tmpb
2174 PUT tmpb, %G
2175*/
2176static
2177UInt dis_mov_E_G ( UChar sorb,
2178 Int size,
2179 UInt delta0 )
2180{
2181 Int len;
2182 UChar rm = getIByte(delta0);
sewardjc9a43662004-11-30 18:51:59 +00002183 HChar dis_buf[50];
sewardje05c42c2004-07-08 20:25:10 +00002184
2185 if (epartIsReg(rm)) {
sewardj7ca37d92004-10-25 02:58:30 +00002186 putIReg(size, gregOfRM(rm), getIReg(size, eregOfRM(rm)));
sewardje05c42c2004-07-08 20:25:10 +00002187 DIP("mov%c %s,%s\n", nameISize(size),
2188 nameIReg(size,eregOfRM(rm)),
2189 nameIReg(size,gregOfRM(rm)));
sewardj7ca37d92004-10-25 02:58:30 +00002190 return 1+delta0;
sewardje05c42c2004-07-08 20:25:10 +00002191 }
2192
2193 /* E refers to memory */
2194 {
sewardj940e8c92004-07-11 16:53:24 +00002195 IRTemp addr = disAMode ( &len, sorb, delta0, dis_buf );
2196 putIReg(size, gregOfRM(rm), loadLE(szToITy(size), mkexpr(addr)));
sewardje05c42c2004-07-08 20:25:10 +00002197 DIP("mov%c %s,%s\n", nameISize(size),
2198 dis_buf,nameIReg(size,gregOfRM(rm)));
2199 return delta0+len;
2200 }
2201}
2202
2203
2204/* Handle move instructions of the form
2205 mov G, E meaning
2206 mov reg, reg-or-mem
2207 Is passed the a ptr to the modRM byte, and the data size. Returns
2208 the address advanced completely over this instruction.
2209
2210 G(src) is reg.
2211 E(dst) is reg-or-mem
2212
2213 If E is reg, --> GET %G, tmp
2214 PUT tmp, %E
2215
2216 If E is mem, --> (getAddr E) -> tmpa
2217 GET %G, tmpv
2218 ST tmpv, (tmpa)
2219*/
sewardjc9a65702004-07-07 16:32:57 +00002220static
2221UInt dis_mov_G_E ( UChar sorb,
2222 Int size,
2223 UInt delta0 )
2224{
sewardje05c42c2004-07-08 20:25:10 +00002225 Int len;
sewardjc9a65702004-07-07 16:32:57 +00002226 UChar rm = getIByte(delta0);
sewardjc9a43662004-11-30 18:51:59 +00002227 HChar dis_buf[50];
sewardjc9a65702004-07-07 16:32:57 +00002228
2229 if (epartIsReg(rm)) {
sewardj41f43bc2004-07-08 14:23:22 +00002230 putIReg(size, eregOfRM(rm), getIReg(size, gregOfRM(rm)));
sewardjc9a65702004-07-07 16:32:57 +00002231 DIP("mov%c %s,%s\n", nameISize(size),
2232 nameIReg(size,gregOfRM(rm)),
2233 nameIReg(size,eregOfRM(rm)));
2234 return 1+delta0;
2235 }
2236
sewardjc9a65702004-07-07 16:32:57 +00002237 /* E refers to memory */
2238 {
sewardj940e8c92004-07-11 16:53:24 +00002239 IRTemp addr = disAMode ( &len, sorb, delta0, dis_buf);
2240 storeLE( mkexpr(addr), getIReg(size, gregOfRM(rm)) );
sewardjc9a65702004-07-07 16:32:57 +00002241 DIP("mov%c %s,%s\n", nameISize(size),
2242 nameIReg(size,gregOfRM(rm)), dis_buf);
sewardje05c42c2004-07-08 20:25:10 +00002243 return len+delta0;
sewardjc9a65702004-07-07 16:32:57 +00002244 }
sewardjc9a65702004-07-07 16:32:57 +00002245}
2246
2247
sewardj0611d802004-07-11 02:37:54 +00002248/* op $immediate, AL/AX/EAX. */
2249static
2250UInt dis_op_imm_A ( Int size,
2251 IROp op8,
2252 Bool keep,
2253 UInt delta,
2254 Char* t_x86opc )
2255{
2256 IRType ty = szToITy(size);
2257 IRTemp dst0 = newTemp(ty);
2258 IRTemp src = newTemp(ty);
2259 IRTemp dst1 = newTemp(ty);
2260 UInt lit = getUDisp(size,delta);
2261 assign(dst0, getIReg(size,R_EAX));
2262 assign(src, mkU(ty,lit));
2263 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
sewardjb9c5cf62004-08-24 15:10:38 +00002264 if (isAddSub(op8))
sewardj2a2ba8b2004-11-08 13:14:06 +00002265 setFlags_DEP1_DEP2(op8, dst0, src, ty);
sewardjb9c5cf62004-08-24 15:10:38 +00002266 else
sewardj2a2ba8b2004-11-08 13:14:06 +00002267 if (isLogic(op8))
2268 setFlags_DEP1(op8, dst1, ty);
2269 else
2270 vpanic("dis_op_imm_A(x86,guest)");
sewardj0611d802004-07-11 02:37:54 +00002271
2272 if (keep)
2273 putIReg(size, R_EAX, mkexpr(dst1));
2274
2275 DIP("%s%c $0x%x, %s\n", t_x86opc, nameISize(size),
2276 lit, nameIReg(size,R_EAX));
2277 return delta+size;
2278}
sewardj9334b0f2004-07-10 22:43:54 +00002279
2280
2281/* Sign- and Zero-extending moves. */
2282static
2283UInt dis_movx_E_G ( UChar sorb,
2284 UInt delta, Int szs, Int szd, Bool sign_extend )
2285{
sewardj9334b0f2004-07-10 22:43:54 +00002286 UChar rm = getIByte(delta);
2287 if (epartIsReg(rm)) {
2288 putIReg(szd, gregOfRM(rm),
sewardj5bd4d162004-11-10 13:02:48 +00002289 unop(mkWidenOp(szs,szd,sign_extend),
2290 getIReg(szs,eregOfRM(rm))));
sewardj9334b0f2004-07-10 22:43:54 +00002291 DIP("mov%c%c%c %s,%s\n", sign_extend ? 's' : 'z',
2292 nameISize(szs), nameISize(szd),
2293 nameIReg(szs,eregOfRM(rm)),
2294 nameIReg(szd,gregOfRM(rm)));
2295 return 1+delta;
2296 }
2297
2298 /* E refers to memory */
2299 {
sewardj940e8c92004-07-11 16:53:24 +00002300 Int len;
sewardjc9a43662004-11-30 18:51:59 +00002301 HChar dis_buf[50];
sewardj940e8c92004-07-11 16:53:24 +00002302 IRTemp addr = disAMode ( &len, sorb, delta, dis_buf );
sewardj0611d802004-07-11 02:37:54 +00002303
2304 putIReg(szd, gregOfRM(rm),
sewardj5bd4d162004-11-10 13:02:48 +00002305 unop(mkWidenOp(szs,szd,sign_extend),
sewardj940e8c92004-07-11 16:53:24 +00002306 loadLE(szToITy(szs),mkexpr(addr))));
sewardj9334b0f2004-07-10 22:43:54 +00002307 DIP("mov%c%c%c %s,%s\n", sign_extend ? 's' : 'z',
2308 nameISize(szs), nameISize(szd),
2309 dis_buf, nameIReg(szd,gregOfRM(rm)));
sewardj0611d802004-07-11 02:37:54 +00002310 return len+delta;
sewardj9334b0f2004-07-10 22:43:54 +00002311 }
2312}
2313
sewardj9690d922004-07-14 01:39:17 +00002314
2315/* Generate code to divide ArchRegs EDX:EAX / DX:AX / AX by the 32 /
2316 16 / 8 bit quantity in the given IRTemp. */
2317static
2318void codegen_div ( Int sz, IRTemp t, Bool signed_divide )
2319{
sewardje5427e82004-09-11 19:43:51 +00002320 IROp op = signed_divide ? Iop_DivModS64to32 : Iop_DivModU64to32;
2321 IRTemp src64 = newTemp(Ity_I64);
2322 IRTemp dst64 = newTemp(Ity_I64);
sewardj9690d922004-07-14 01:39:17 +00002323 switch (sz) {
sewardje5427e82004-09-11 19:43:51 +00002324 case 4:
sewardj9690d922004-07-14 01:39:17 +00002325 assign( src64, binop(Iop_32HLto64,
sewardje5427e82004-09-11 19:43:51 +00002326 getIReg(4,R_EDX), getIReg(4,R_EAX)) );
sewardj9690d922004-07-14 01:39:17 +00002327 assign( dst64, binop(op, mkexpr(src64), mkexpr(t)) );
sewardj8c7f1ab2004-07-29 20:31:09 +00002328 putIReg( 4, R_EAX, unop(Iop_64to32,mkexpr(dst64)) );
sewardj9690d922004-07-14 01:39:17 +00002329 putIReg( 4, R_EDX, unop(Iop_64HIto32,mkexpr(dst64)) );
2330 break;
sewardje5427e82004-09-11 19:43:51 +00002331 case 2: {
2332 IROp widen3264 = signed_divide ? Iop_32Sto64 : Iop_32Uto64;
2333 IROp widen1632 = signed_divide ? Iop_16Sto32 : Iop_16Uto32;
2334 assign( src64, unop(widen3264,
2335 binop(Iop_16HLto32,
2336 getIReg(2,R_EDX), getIReg(2,R_EAX))) );
2337 assign( dst64, binop(op, mkexpr(src64), unop(widen1632,mkexpr(t))) );
2338 putIReg( 2, R_EAX, unop(Iop_32to16,unop(Iop_64to32,mkexpr(dst64))) );
2339 putIReg( 2, R_EDX, unop(Iop_32to16,unop(Iop_64HIto32,mkexpr(dst64))) );
2340 break;
sewardj9690d922004-07-14 01:39:17 +00002341 }
sewardj4e82db72004-10-16 11:32:15 +00002342 case 1: {
2343 IROp widen3264 = signed_divide ? Iop_32Sto64 : Iop_32Uto64;
2344 IROp widen1632 = signed_divide ? Iop_16Sto32 : Iop_16Uto32;
2345 IROp widen816 = signed_divide ? Iop_8Sto16 : Iop_8Uto16;
2346 assign( src64, unop(widen3264, unop(widen1632, getIReg(2,R_EAX))) );
2347 assign( dst64,
2348 binop(op, mkexpr(src64),
2349 unop(widen1632, unop(widen816, mkexpr(t)))) );
2350 putIReg( 1, R_AL, unop(Iop_16to8, unop(Iop_32to16,
2351 unop(Iop_64to32,mkexpr(dst64)))) );
2352 putIReg( 1, R_AH, unop(Iop_16to8, unop(Iop_32to16,
2353 unop(Iop_64HIto32,mkexpr(dst64)))) );
2354 break;
2355 }
sewardj9690d922004-07-14 01:39:17 +00002356 default: vpanic("codegen_div(x86)");
2357 }
2358}
sewardjc9a65702004-07-07 16:32:57 +00002359//-- Int helper;
2360//-- Int ta = newTemp(cb);
2361//-- Int td = newTemp(cb);
2362//--
2363//-- switch (sz) {
2364//-- case 4: helper = (signed_divide ? VGOFF_(helper_idiv_64_32)
2365//-- : VGOFF_(helper_div_64_32));
2366//-- break;
2367//-- case 2: helper = (signed_divide ? VGOFF_(helper_idiv_32_16)
2368//-- : VGOFF_(helper_div_32_16));
2369//-- break;
2370//-- case 1: helper = (signed_divide ? VGOFF_(helper_idiv_16_8)
2371//-- : VGOFF_(helper_div_16_8));
2372//-- break;
2373//-- default: VG_(core_panic)("codegen_div");
2374//-- }
2375//-- uInstr0(cb, CALLM_S, 0);
2376//-- if (sz == 4 || sz == 2) {
2377//-- uInstr1(cb, PUSH, sz, TempReg, t);
2378//-- uInstr2(cb, GET, sz, ArchReg, R_EAX, TempReg, ta);
2379//-- uInstr1(cb, PUSH, sz, TempReg, ta);
2380//-- uInstr2(cb, GET, sz, ArchReg, R_EDX, TempReg, td);
2381//-- uInstr1(cb, PUSH, sz, TempReg, td);
2382//-- uInstr1(cb, CALLM, 0, Lit16, helper);
2383//-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsOSZACP);
2384//-- uInstr1(cb, POP, sz, TempReg, t);
2385//-- uInstr2(cb, PUT, sz, TempReg, t, ArchReg, R_EDX);
2386//-- uInstr1(cb, POP, sz, TempReg, t);
2387//-- uInstr2(cb, PUT, sz, TempReg, t, ArchReg, R_EAX);
2388//-- uInstr1(cb, CLEAR, 0, Lit16, 4);
2389//-- } else {
2390//-- uInstr1(cb, PUSH, 1, TempReg, t);
2391//-- uInstr2(cb, GET, 2, ArchReg, R_EAX, TempReg, ta);
2392//-- uInstr1(cb, PUSH, 2, TempReg, ta);
2393//-- uInstr2(cb, MOV, 1, Literal, 0, TempReg, td);
2394//-- uLiteral(cb, 0);
2395//-- uInstr1(cb, PUSH, 1, TempReg, td);
2396//-- uInstr1(cb, CALLM, 0, Lit16, helper);
2397//-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsOSZACP);
2398//-- uInstr1(cb, POP, 1, TempReg, t);
2399//-- uInstr2(cb, PUT, 1, TempReg, t, ArchReg, R_AL);
2400//-- uInstr1(cb, POP, 1, TempReg, t);
2401//-- uInstr2(cb, PUT, 1, TempReg, t, ArchReg, R_AH);
2402//-- uInstr1(cb, CLEAR, 0, Lit16, 4);
2403//-- }
2404//-- uInstr0(cb, CALLM_E, 0);
2405//-- }
sewardj41f43bc2004-07-08 14:23:22 +00002406
2407
2408static
sewardje90ad6a2004-07-10 19:02:10 +00002409UInt dis_Grp1 ( UChar sorb,
sewardj41f43bc2004-07-08 14:23:22 +00002410 UInt delta, UChar modrm,
2411 Int am_sz, Int d_sz, Int sz, UInt d32 )
2412{
sewardj41f43bc2004-07-08 14:23:22 +00002413 Int len;
sewardjc9a43662004-11-30 18:51:59 +00002414 HChar dis_buf[50];
sewardje05c42c2004-07-08 20:25:10 +00002415 IRType ty = szToITy(sz);
2416 IRTemp dst1 = newTemp(ty);
2417 IRTemp src = newTemp(ty);
2418 IRTemp dst0 = newTemp(ty);
sewardj92d168d2004-11-15 14:22:12 +00002419 IRTemp addr = IRTemp_INVALID;
sewardj66de2272004-07-16 21:19:05 +00002420 IROp op8 = Iop_INVALID;
sewardj180e8b32004-07-29 01:40:11 +00002421 UInt mask = sz==1 ? 0xFF : (sz==2 ? 0xFFFF : 0xFFFFFFFF);
sewardj41f43bc2004-07-08 14:23:22 +00002422
2423 switch (gregOfRM(modrm)) {
sewardje05c42c2004-07-08 20:25:10 +00002424 case 0: op8 = Iop_Add8; break; case 1: op8 = Iop_Or8; break;
sewardj66de2272004-07-16 21:19:05 +00002425 case 2: break; // ADC
2426 case 3: break; // SBB
sewardje05c42c2004-07-08 20:25:10 +00002427 case 4: op8 = Iop_And8; break; case 5: op8 = Iop_Sub8; break;
2428 case 6: op8 = Iop_Xor8; break; case 7: op8 = Iop_Sub8; break;
sewardj41f43bc2004-07-08 14:23:22 +00002429 default: vpanic("dis_Grp1: unhandled case");
2430 }
sewardj41f43bc2004-07-08 14:23:22 +00002431
2432 if (epartIsReg(modrm)) {
2433 vassert(am_sz == 1);
2434
2435 assign(dst0, getIReg(sz,eregOfRM(modrm)));
sewardj180e8b32004-07-29 01:40:11 +00002436 assign(src, mkU(ty,d32 & mask));
sewardj41f43bc2004-07-08 14:23:22 +00002437
sewardj180e8b32004-07-29 01:40:11 +00002438 if (gregOfRM(modrm) == 2 /* ADC */) {
2439 helper_ADC( sz, dst1, dst0, src );
2440 } else
2441 if (gregOfRM(modrm) == 3 /* SBB */) {
2442 helper_SBB( sz, dst1, dst0, src );
2443 } else {
2444 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
sewardj5bd4d162004-11-10 13:02:48 +00002445 if (isAddSub(op8))
sewardj2a2ba8b2004-11-08 13:14:06 +00002446 setFlags_DEP1_DEP2(op8, dst0, src, ty);
sewardjb9c5cf62004-08-24 15:10:38 +00002447 else
sewardj2a2ba8b2004-11-08 13:14:06 +00002448 setFlags_DEP1(op8, dst1, ty);
sewardj180e8b32004-07-29 01:40:11 +00002449 }
sewardj41f43bc2004-07-08 14:23:22 +00002450
2451 if (gregOfRM(modrm) < 7)
sewardje05c42c2004-07-08 20:25:10 +00002452 putIReg(sz, eregOfRM(modrm), mkexpr(dst1));
sewardj41f43bc2004-07-08 14:23:22 +00002453
2454 delta += (am_sz + d_sz);
2455 DIP("%s%c $0x%x, %s\n", nameGrp1(gregOfRM(modrm)), nameISize(sz), d32,
2456 nameIReg(sz,eregOfRM(modrm)));
2457 } else {
sewardje87b4842004-07-10 12:23:30 +00002458 addr = disAMode ( &len, sorb, delta, dis_buf);
sewardj41f43bc2004-07-08 14:23:22 +00002459
sewardj940e8c92004-07-11 16:53:24 +00002460 assign(dst0, loadLE(ty,mkexpr(addr)));
sewardj180e8b32004-07-29 01:40:11 +00002461 assign(src, mkU(ty,d32 & mask));
sewardj41f43bc2004-07-08 14:23:22 +00002462
sewardj66de2272004-07-16 21:19:05 +00002463 if (gregOfRM(modrm) == 2 /* ADC */) {
sewardj3af115f2004-07-14 02:46:52 +00002464 helper_ADC( sz, dst1, dst0, src );
2465 } else
sewardj66de2272004-07-16 21:19:05 +00002466 if (gregOfRM(modrm) == 3 /* SBB */) {
sewardje166ed02004-10-25 02:27:01 +00002467 helper_SBB( sz, dst1, dst0, src );
sewardj3af115f2004-07-14 02:46:52 +00002468 } else {
2469 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
sewardj5bd4d162004-11-10 13:02:48 +00002470 if (isAddSub(op8))
sewardj2a2ba8b2004-11-08 13:14:06 +00002471 setFlags_DEP1_DEP2(op8, dst0, src, ty);
sewardjb9c5cf62004-08-24 15:10:38 +00002472 else
sewardj2a2ba8b2004-11-08 13:14:06 +00002473 setFlags_DEP1(op8, dst1, ty);
sewardj3af115f2004-07-14 02:46:52 +00002474 }
sewardj41f43bc2004-07-08 14:23:22 +00002475
2476 if (gregOfRM(modrm) < 7)
sewardj940e8c92004-07-11 16:53:24 +00002477 storeLE(mkexpr(addr), mkexpr(dst1));
sewardj41f43bc2004-07-08 14:23:22 +00002478
2479 delta += (len+d_sz);
2480 DIP("%s%c $0x%x, %s\n", nameGrp1(gregOfRM(modrm)), nameISize(sz),
2481 d32, dis_buf);
2482 }
2483 return delta;
2484}
2485
2486
sewardj6d2638e2004-07-15 09:38:27 +00002487/* Group 2 extended opcodes. shift_expr must be an 8-bit typed
2488 expression. */
2489
sewardje90ad6a2004-07-10 19:02:10 +00002490static
2491UInt dis_Grp2 ( UChar sorb,
2492 UInt delta, UChar modrm,
sewardj6d2638e2004-07-15 09:38:27 +00002493 Int am_sz, Int d_sz, Int sz, IRExpr* shift_expr,
2494 Char* shift_expr_txt )
sewardje90ad6a2004-07-10 19:02:10 +00002495{
2496 /* delta on entry points at the modrm byte. */
sewardjc9a43662004-11-30 18:51:59 +00002497 HChar dis_buf[50];
sewardj6d2638e2004-07-15 09:38:27 +00002498 Int len;
sewardj9aebb0c2004-10-24 19:20:43 +00002499 Bool isShift, isRotate, isRotateRC;
sewardj6d2638e2004-07-15 09:38:27 +00002500 IRType ty = szToITy(sz);
2501 IRTemp dst0 = newTemp(ty);
2502 IRTemp dst1 = newTemp(ty);
sewardj92d168d2004-11-15 14:22:12 +00002503 IRTemp addr = IRTemp_INVALID;
sewardje90ad6a2004-07-10 19:02:10 +00002504
2505 vassert(sz == 1 || sz == 2 || sz == 4);
2506
sewardje90ad6a2004-07-10 19:02:10 +00002507 /* Put value to shift/rotate in dst0. */
2508 if (epartIsReg(modrm)) {
2509 assign(dst0, getIReg(sz, eregOfRM(modrm)));
sewardj940e8c92004-07-11 16:53:24 +00002510 delta += (am_sz + d_sz);
sewardje90ad6a2004-07-10 19:02:10 +00002511 } else {
sewardj940e8c92004-07-11 16:53:24 +00002512 addr = disAMode ( &len, sorb, delta, dis_buf);
2513 assign(dst0, loadLE(ty,mkexpr(addr)));
2514 delta += len + d_sz;
sewardje90ad6a2004-07-10 19:02:10 +00002515 }
2516
2517 isShift = False;
2518 switch (gregOfRM(modrm)) { case 4: case 5: case 7: isShift = True; }
2519
sewardj750f4072004-07-26 22:39:11 +00002520 isRotate = False;
2521 switch (gregOfRM(modrm)) { case 0: case 1: isRotate = True; }
2522
sewardj9aebb0c2004-10-24 19:20:43 +00002523 isRotateRC = gregOfRM(modrm) == 3;
2524
2525 if (!isShift && !isRotate && !isRotateRC) {
sewardj8c7f1ab2004-07-29 20:31:09 +00002526 vex_printf("\ncase %d\n", gregOfRM(modrm));
2527 vpanic("dis_Grp2(Reg): unhandled case(x86)");
2528 }
2529
sewardj9aebb0c2004-10-24 19:20:43 +00002530 if (isRotateRC) {
2531 /* call a helper; this insn is so ridiculous it does not deserve
2532 better */
2533 IRTemp r64 = newTemp(Ity_I64);
sewardjf9655262004-10-31 20:02:16 +00002534 IRExpr** args
2535 = mkIRExprVec_4( widenUto32(mkexpr(dst0)), /* thing to rotate */
2536 widenUto32(shift_expr), /* rotate amount */
sewardj2a9ad022004-11-25 02:46:58 +00002537 widenUto32(mk_x86g_calculate_eflags_all()),
sewardjf9655262004-10-31 20:02:16 +00002538 mkU32(sz) );
2539 assign( r64, mkIRExprCCall(
sewardj8ea867b2004-10-30 19:03:02 +00002540 Ity_I64,
sewardjf9655262004-10-31 20:02:16 +00002541 0/*regparm*/,
sewardj2a9ad022004-11-25 02:46:58 +00002542 "x86g_calculate_RCR", &x86g_calculate_RCR,
sewardj8ea867b2004-10-30 19:03:02 +00002543 args
sewardjf9655262004-10-31 20:02:16 +00002544 )
2545 );
sewardj9aebb0c2004-10-24 19:20:43 +00002546 /* new eflags in hi half r64; new value in lo half r64 */
2547 assign( dst1, narrowTo(ty, unop(Iop_64to32, mkexpr(r64))) );
sewardj2a9ad022004-11-25 02:46:58 +00002548 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
sewardj2a2ba8b2004-11-08 13:14:06 +00002549 stmt( IRStmt_Put( OFFB_CC_DEP1, unop(Iop_64HIto32, mkexpr(r64)) ));
2550 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
sewardj9aebb0c2004-10-24 19:20:43 +00002551 }
2552
sewardje90ad6a2004-07-10 19:02:10 +00002553 if (isShift) {
2554
sewardjc22a6fd2004-07-29 23:41:47 +00002555 IRTemp pre32 = newTemp(Ity_I32);
2556 IRTemp res32 = newTemp(Ity_I32);
2557 IRTemp res32ss = newTemp(Ity_I32);
sewardj6d2638e2004-07-15 09:38:27 +00002558 IRTemp shift_amt = newTemp(Ity_I8);
sewardjc22a6fd2004-07-29 23:41:47 +00002559 IROp op32;
sewardje90ad6a2004-07-10 19:02:10 +00002560
2561 switch (gregOfRM(modrm)) {
sewardjc22a6fd2004-07-29 23:41:47 +00002562 case 4: op32 = Iop_Shl32; break;
2563 case 5: op32 = Iop_Shr32; break;
2564 case 7: op32 = Iop_Sar32; break;
sewardje90ad6a2004-07-10 19:02:10 +00002565 default: vpanic("dis_Grp2:shift"); break;
2566 }
2567
sewardjc22a6fd2004-07-29 23:41:47 +00002568 /* Widen the value to be shifted to 32 bits, do the shift, and
2569 narrow back down. This seems surprisingly long-winded, but
2570 unfortunately the Intel semantics requires that 8/16-bit
2571 shifts give defined results for shift values all the way up
2572 to 31, and this seems the simplest way to do it. It has the
2573 advantage that the only IR level shifts generated are of 32
2574 bit values, and the shift amount is guaranteed to be in the
2575 range 0 .. 31, thereby observing the IR semantics requiring
2576 all shift values to be in the range 0 .. 2^word_size-1. */
2577
2578 /* shift_amt = shift_expr & 31, regardless of operation size */
2579 assign( shift_amt, binop(Iop_And8, shift_expr, mkU8(31)) );
2580
2581 /* suitably widen the value to be shifted to 32 bits. */
2582 assign( pre32, op32==Iop_Sar32 ? widenSto32(mkexpr(dst0))
2583 : widenUto32(mkexpr(dst0)) );
2584
2585 /* res32 = pre32 `shift` shift_amt */
2586 assign( res32, binop(op32, mkexpr(pre32), mkexpr(shift_amt)) );
2587
2588 /* res32ss = pre32 `shift` ((shift_amt - 1) & 31) */
2589 assign( res32ss,
2590 binop(op32,
2591 mkexpr(pre32),
2592 binop(Iop_And8,
2593 binop(Iop_Sub8,
2594 mkexpr(shift_amt), mkU8(1)),
2595 mkU8(31))) );
sewardje90ad6a2004-07-10 19:02:10 +00002596
2597 /* Build the flags thunk. */
sewardj2a2ba8b2004-11-08 13:14:06 +00002598 setFlags_DEP1_DEP2_shift(op32, res32, res32ss, ty, shift_amt);
sewardjc22a6fd2004-07-29 23:41:47 +00002599
2600 /* Narrow the result back down. */
2601 assign( dst1, narrowTo(ty, mkexpr(res32)) );
sewardj750f4072004-07-26 22:39:11 +00002602
sewardj1813dbe2004-07-28 17:09:04 +00002603 } /* if (isShift) */
2604
2605 else
sewardj750f4072004-07-26 22:39:11 +00002606 if (isRotate) {
sewardj7ebbdae2004-08-26 12:30:48 +00002607 Int ccOp = ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
2608 Bool left = gregOfRM(modrm) == 0;
2609 IRTemp rot_amt = newTemp(Ity_I8);
2610 IRTemp rot_amt32 = newTemp(Ity_I8);
2611 IRTemp oldFlags = newTemp(Ity_I32);
sewardj750f4072004-07-26 22:39:11 +00002612
2613 /* rot_amt = shift_expr & mask */
sewardjc22a6fd2004-07-29 23:41:47 +00002614 /* By masking the rotate amount thusly, the IR-level Shl/Shr
2615 expressions never shift beyond the word size and thus remain
2616 well defined. */
sewardj7ebbdae2004-08-26 12:30:48 +00002617 assign(rot_amt32, binop(Iop_And8, shift_expr, mkU8(31)));
2618
2619 if (ty == Ity_I32)
2620 assign(rot_amt, mkexpr(rot_amt32));
2621 else
2622 assign(rot_amt, binop(Iop_And8, mkexpr(rot_amt32), mkU8(8*sz-1)));
sewardj750f4072004-07-26 22:39:11 +00002623
2624 if (left) {
sewardj1813dbe2004-07-28 17:09:04 +00002625
sewardj750f4072004-07-26 22:39:11 +00002626 /* dst1 = (dst0 << rot_amt) | (dst0 >>u (wordsize-rot_amt)) */
2627 assign(dst1,
2628 binop( mkSizedOp(ty,Iop_Or8),
2629 binop( mkSizedOp(ty,Iop_Shl8),
2630 mkexpr(dst0),
2631 mkexpr(rot_amt)
2632 ),
2633 binop( mkSizedOp(ty,Iop_Shr8),
2634 mkexpr(dst0),
2635 binop(Iop_Sub8,mkU8(8*sz), mkexpr(rot_amt))
2636 )
2637 )
2638 );
sewardj2a9ad022004-11-25 02:46:58 +00002639 ccOp += X86G_CC_OP_ROLB;
sewardj750f4072004-07-26 22:39:11 +00002640
sewardj1813dbe2004-07-28 17:09:04 +00002641 } else { /* right */
sewardj750f4072004-07-26 22:39:11 +00002642
sewardj1813dbe2004-07-28 17:09:04 +00002643 /* dst1 = (dst0 >>u rot_amt) | (dst0 << (wordsize-rot_amt)) */
2644 assign(dst1,
2645 binop( mkSizedOp(ty,Iop_Or8),
2646 binop( mkSizedOp(ty,Iop_Shr8),
2647 mkexpr(dst0),
2648 mkexpr(rot_amt)
2649 ),
2650 binop( mkSizedOp(ty,Iop_Shl8),
2651 mkexpr(dst0),
2652 binop(Iop_Sub8,mkU8(8*sz), mkexpr(rot_amt))
sewardj750f4072004-07-26 22:39:11 +00002653 )
2654 )
2655 );
sewardj2a9ad022004-11-25 02:46:58 +00002656 ccOp += X86G_CC_OP_RORB;
sewardjc22a6fd2004-07-29 23:41:47 +00002657
sewardj750f4072004-07-26 22:39:11 +00002658 }
sewardjc22a6fd2004-07-29 23:41:47 +00002659
sewardj1813dbe2004-07-28 17:09:04 +00002660 /* dst1 now holds the rotated value. Build flag thunk. We
2661 need the resulting value for this, and the previous flags.
2662 Except don't set it if the rotate count is zero. */
2663
sewardj2a9ad022004-11-25 02:46:58 +00002664 assign(oldFlags, mk_x86g_calculate_eflags_all());
sewardj1813dbe2004-07-28 17:09:04 +00002665
sewardj2a2ba8b2004-11-08 13:14:06 +00002666 /* CC_DEP1 is the rotated value. CC_NDEP is flags before. */
sewardj1813dbe2004-07-28 17:09:04 +00002667 stmt( IRStmt_Put( OFFB_CC_OP,
sewardj7ebbdae2004-08-26 12:30:48 +00002668 IRExpr_Mux0X( mkexpr(rot_amt32),
sewardj1813dbe2004-07-28 17:09:04 +00002669 IRExpr_Get(OFFB_CC_OP,Ity_I32),
2670 mkU32(ccOp))) );
sewardj2a2ba8b2004-11-08 13:14:06 +00002671 stmt( IRStmt_Put( OFFB_CC_DEP1,
sewardj7ebbdae2004-08-26 12:30:48 +00002672 IRExpr_Mux0X( mkexpr(rot_amt32),
sewardj2a2ba8b2004-11-08 13:14:06 +00002673 IRExpr_Get(OFFB_CC_DEP1,Ity_I32),
sewardjc22a6fd2004-07-29 23:41:47 +00002674 widenUto32(mkexpr(dst1)))) );
sewardj2a2ba8b2004-11-08 13:14:06 +00002675 stmt( IRStmt_Put( OFFB_CC_DEP2,
sewardj7ebbdae2004-08-26 12:30:48 +00002676 IRExpr_Mux0X( mkexpr(rot_amt32),
sewardj2a2ba8b2004-11-08 13:14:06 +00002677 IRExpr_Get(OFFB_CC_DEP2,Ity_I32),
2678 mkU32(0))) );
2679 stmt( IRStmt_Put( OFFB_CC_NDEP,
2680 IRExpr_Mux0X( mkexpr(rot_amt32),
2681 IRExpr_Get(OFFB_CC_NDEP,Ity_I32),
sewardj1813dbe2004-07-28 17:09:04 +00002682 mkexpr(oldFlags))) );
2683 } /* if (isRotate) */
sewardje90ad6a2004-07-10 19:02:10 +00002684
2685 /* Save result, and finish up. */
2686 if (epartIsReg(modrm)) {
2687 putIReg(sz, eregOfRM(modrm), mkexpr(dst1));
sewardjf48ac192004-10-29 00:41:29 +00002688 if (vex_traceflags & VEX_TRACE_FE) {
sewardje90ad6a2004-07-10 19:02:10 +00002689 vex_printf("%s%c ",
2690 nameGrp2(gregOfRM(modrm)), nameISize(sz) );
sewardj6d2638e2004-07-15 09:38:27 +00002691 if (shift_expr_txt)
2692 vex_printf("%s", shift_expr_txt);
2693 else
2694 ppIRExpr(shift_expr);
sewardje90ad6a2004-07-10 19:02:10 +00002695 vex_printf(", %s\n", nameIReg(sz,eregOfRM(modrm)));
2696 }
sewardje90ad6a2004-07-10 19:02:10 +00002697 } else {
sewardj940e8c92004-07-11 16:53:24 +00002698 storeLE(mkexpr(addr), mkexpr(dst1));
sewardjf48ac192004-10-29 00:41:29 +00002699 if (vex_traceflags & VEX_TRACE_FE) {
sewardj940e8c92004-07-11 16:53:24 +00002700 vex_printf("%s%c ",
2701 nameGrp2(gregOfRM(modrm)), nameISize(sz) );
sewardj6d2638e2004-07-15 09:38:27 +00002702 if (shift_expr_txt)
2703 vex_printf("%s", shift_expr_txt);
2704 else
2705 ppIRExpr(shift_expr);
sewardj940e8c92004-07-11 16:53:24 +00002706 vex_printf(", %s\n", dis_buf);
2707 }
sewardje90ad6a2004-07-10 19:02:10 +00002708 }
sewardje90ad6a2004-07-10 19:02:10 +00002709 return delta;
2710}
2711
2712
2713
sewardjc9a65702004-07-07 16:32:57 +00002714//-- /* Group 8 extended opcodes (but BT/BTS/BTC/BTR only). */
2715//-- static
2716//-- Addr dis_Grp8_BT ( UCodeBlock* cb,
2717//-- UChar sorb,
2718//-- Addr eip, UChar modrm,
2719//-- Int am_sz, Int sz, UInt src_val )
2720//-- {
sewardj5bd4d162004-11-10 13:02:48 +00002721# define MODIFY_t2_AND_SET_CARRY_FLAG \
2722 /* t2 is the value to be op'd on. Copy to t_fetched, then \
2723 modify t2, if non-BT. */ \
2724 uInstr2(cb, MOV, 4, TempReg, t2, TempReg, t_fetched); \
2725 uInstr2(cb, MOV, sz, Literal, 0, TempReg, t_mask); \
2726 uLiteral(cb, v_mask); \
2727 switch (gregOfRM(modrm)) { \
2728 case 4: /* BT */ break; \
2729 case 5: /* BTS */ \
2730 uInstr2(cb, OR, sz, TempReg, t_mask, TempReg, t2); break; \
2731 case 6: /* BTR */ \
2732 uInstr2(cb, AND, sz, TempReg, t_mask, TempReg, t2); break; \
2733 case 7: /* BTC */ \
2734 uInstr2(cb, XOR, sz, TempReg, t_mask, TempReg, t2); break; \
2735 } \
2736 /* Copy relevant bit from t_fetched into carry flag. */ \
2737 uInstr2(cb, SHR, sz, Literal, 0, TempReg, t_fetched); \
2738 uLiteral(cb, src_val); \
2739 uInstr2(cb, MOV, sz, Literal, 0, TempReg, t_mask); \
2740 uLiteral(cb, 1); \
2741 uInstr2(cb, AND, sz, TempReg, t_mask, TempReg, t_fetched); \
2742 uInstr1(cb, NEG, sz, TempReg, t_fetched); \
sewardjd1061ab2004-07-08 01:45:30 +00002743 setFlagsFromUOpcode(cb, NEG);
2744
2745
sewardjc9a65702004-07-07 16:32:57 +00002746//-- /* src_val denotes a d8.
2747//-- And eip on entry points at the modrm byte. */
2748//-- Int t1, t2, t_fetched, t_mask;
2749//-- UInt pair;
sewardjc9a43662004-11-30 18:51:59 +00002750//-- HChar dis_buf[50];
sewardjc9a65702004-07-07 16:32:57 +00002751//-- UInt v_mask;
2752//--
2753//-- /* There is no 1-byte form of this instruction, AFAICS. */
2754//-- vg_assert(sz == 2 || sz == 4);
2755//--
2756//-- /* Limit src_val -- the bit offset -- to something within a word.
2757//-- The Intel docs say that literal offsets larger than a word are
2758//-- masked in this way. */
2759//-- switch (sz) {
2760//-- case 2: src_val &= 15; break;
2761//-- case 4: src_val &= 31; break;
2762//-- default: VG_(core_panic)("dis_Grp8_BT: invalid size");
2763//-- }
2764//--
2765//-- /* Invent a mask suitable for the operation. */
2766//--
2767//-- switch (gregOfRM(modrm)) {
2768//-- case 4: /* BT */ v_mask = 0; break;
2769//-- case 5: /* BTS */ v_mask = 1 << src_val; break;
2770//-- case 6: /* BTR */ v_mask = ~(1 << src_val); break;
2771//-- case 7: /* BTC */ v_mask = 1 << src_val; break;
2772//-- /* If this needs to be extended, probably simplest to make a
2773//-- new function to handle the other cases (0 .. 3). The
2774//-- Intel docs do however not indicate any use for 0 .. 3, so
2775//-- we don't expect this to happen. */
2776//-- default: VG_(core_panic)("dis_Grp8_BT");
2777//-- }
2778//-- /* Probably excessively paranoid. */
2779//-- if (sz == 2)
2780//-- v_mask &= 0x0000FFFF;
2781//--
2782//-- t1 = INVALID_TEMPREG;
2783//-- t_fetched = newTemp(cb);
2784//-- t_mask = newTemp(cb);
2785//--
2786//-- if (epartIsReg(modrm)) {
2787//-- vg_assert(am_sz == 1);
2788//-- t2 = newTemp(cb);
2789//--
2790//-- /* Fetch the value to be tested and modified. */
2791//-- uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t2);
2792//-- /* Do it! */
2793//-- MODIFY_t2_AND_SET_CARRY_FLAG;
2794//-- /* Dump the result back, if non-BT. */
2795//-- if (gregOfRM(modrm) != 4 /* BT */)
2796//-- uInstr2(cb, PUT, sz, TempReg, t2, ArchReg, eregOfRM(modrm));
2797//--
2798//-- eip += (am_sz + 1);
2799//-- DIP("%s%c $0x%x, %s\n", nameGrp8(gregOfRM(modrm)), nameISize(sz),
2800//-- src_val, nameIReg(sz,eregOfRM(modrm)));
2801//-- } else {
2802//-- pair = disAMode ( cb, sorb, eip, dis_buf);
2803//-- t1 = LOW24(pair);
2804//-- t2 = newTemp(cb);
2805//-- eip += HI8(pair);
2806//-- eip += 1;
2807//--
2808//-- /* Fetch the value to be tested and modified. */
2809//-- uInstr2(cb, LOAD, sz, TempReg, t1, TempReg, t2);
2810//-- /* Do it! */
2811//-- MODIFY_t2_AND_SET_CARRY_FLAG;
2812//-- /* Dump the result back, if non-BT. */
2813//-- if (gregOfRM(modrm) != 4 /* BT */) {
2814//-- uInstr2(cb, STORE, sz, TempReg, t2, TempReg, t1);
2815//-- }
2816//-- DIP("%s%c $0x%x, %s\n", nameGrp8(gregOfRM(modrm)), nameISize(sz),
2817//-- src_val, dis_buf);
2818//-- }
2819//-- return eip;
2820//--
2821//-- # undef MODIFY_t2_AND_SET_CARRY_FLAG
2822//-- }
sewardjcf780b42004-07-13 18:42:17 +00002823
2824
2825
sewardj1813dbe2004-07-28 17:09:04 +00002826/* Signed/unsigned widening multiply. Generate IR to multiply the
2827 value in EAX/AX/AL by the given IRTemp, and park the result in
2828 EDX:EAX/DX:AX/AX.
sewardjcf780b42004-07-13 18:42:17 +00002829*/
sewardj1813dbe2004-07-28 17:09:04 +00002830static void codegen_mulL_A_D ( Int sz, Bool syned,
2831 IRTemp tmp, Char* tmp_txt )
sewardjcf780b42004-07-13 18:42:17 +00002832{
sewardjcf780b42004-07-13 18:42:17 +00002833 IRType ty = szToITy(sz);
2834 IRTemp t1 = newTemp(ty);
sewardjcf780b42004-07-13 18:42:17 +00002835
sewardj1813dbe2004-07-28 17:09:04 +00002836 assign( t1, getIReg(sz, R_EAX) );
sewardjcf780b42004-07-13 18:42:17 +00002837
2838 switch (ty) {
sewardjb81f8b32004-07-30 10:17:50 +00002839 case Ity_I32: {
2840 IRTemp res64 = newTemp(Ity_I64);
sewardj948d48b2004-11-05 19:49:09 +00002841 IRTemp resHi = newTemp(Ity_I32);
2842 IRTemp resLo = newTemp(Ity_I32);
sewardjb81f8b32004-07-30 10:17:50 +00002843 IROp mulOp = syned ? Iop_MullS32 : Iop_MullU32;
sewardj2a9ad022004-11-25 02:46:58 +00002844 UInt tBaseOp = syned ? X86G_CC_OP_SMULB : X86G_CC_OP_UMULB;
sewardj2a2ba8b2004-11-08 13:14:06 +00002845 setFlags_MUL ( Ity_I32, t1, tmp, tBaseOp );
sewardjb81f8b32004-07-30 10:17:50 +00002846 assign( res64, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
sewardj948d48b2004-11-05 19:49:09 +00002847 assign( resHi, unop(Iop_64HIto32,mkexpr(res64)));
2848 assign( resLo, unop(Iop_64to32,mkexpr(res64)));
sewardj948d48b2004-11-05 19:49:09 +00002849 putIReg(4, R_EDX, mkexpr(resHi));
2850 putIReg(4, R_EAX, mkexpr(resLo));
sewardjb81f8b32004-07-30 10:17:50 +00002851 break;
2852 }
2853 case Ity_I16: {
2854 IRTemp res32 = newTemp(Ity_I32);
sewardj948d48b2004-11-05 19:49:09 +00002855 IRTemp resHi = newTemp(Ity_I16);
2856 IRTemp resLo = newTemp(Ity_I16);
sewardjb81f8b32004-07-30 10:17:50 +00002857 IROp mulOp = syned ? Iop_MullS16 : Iop_MullU16;
sewardj2a9ad022004-11-25 02:46:58 +00002858 UInt tBaseOp = syned ? X86G_CC_OP_SMULB : X86G_CC_OP_UMULB;
sewardj2a2ba8b2004-11-08 13:14:06 +00002859 setFlags_MUL ( Ity_I16, t1, tmp, tBaseOp );
sewardjb81f8b32004-07-30 10:17:50 +00002860 assign( res32, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
sewardj948d48b2004-11-05 19:49:09 +00002861 assign( resHi, unop(Iop_32HIto16,mkexpr(res32)));
2862 assign( resLo, unop(Iop_32to16,mkexpr(res32)));
sewardj948d48b2004-11-05 19:49:09 +00002863 putIReg(2, R_EDX, mkexpr(resHi));
2864 putIReg(2, R_EAX, mkexpr(resLo));
sewardjb81f8b32004-07-30 10:17:50 +00002865 break;
2866 }
2867 case Ity_I8: {
2868 IRTemp res16 = newTemp(Ity_I16);
sewardj948d48b2004-11-05 19:49:09 +00002869 IRTemp resHi = newTemp(Ity_I8);
2870 IRTemp resLo = newTemp(Ity_I8);
sewardjb81f8b32004-07-30 10:17:50 +00002871 IROp mulOp = syned ? Iop_MullS8 : Iop_MullU8;
sewardj2a9ad022004-11-25 02:46:58 +00002872 UInt tBaseOp = syned ? X86G_CC_OP_SMULB : X86G_CC_OP_UMULB;
sewardj2a2ba8b2004-11-08 13:14:06 +00002873 setFlags_MUL ( Ity_I8, t1, tmp, tBaseOp );
sewardjb81f8b32004-07-30 10:17:50 +00002874 assign( res16, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
sewardj948d48b2004-11-05 19:49:09 +00002875 assign( resHi, unop(Iop_16HIto8,mkexpr(res16)));
2876 assign( resLo, unop(Iop_16to8,mkexpr(res16)));
sewardjb81f8b32004-07-30 10:17:50 +00002877 putIReg(2, R_EAX, mkexpr(res16));
2878 break;
2879 }
2880 default:
2881 vpanic("codegen_mulL_A_D(x86)");
sewardjcf780b42004-07-13 18:42:17 +00002882 }
sewardj1813dbe2004-07-28 17:09:04 +00002883 DIP("%s%c %s\n", syned ? "imul" : "mul", nameISize(sz), tmp_txt);
sewardjcf780b42004-07-13 18:42:17 +00002884}
2885
sewardj940e8c92004-07-11 16:53:24 +00002886
2887/* Group 3 extended opcodes. */
2888static
2889UInt dis_Grp3 ( UChar sorb, Int sz, UInt delta )
2890{
sewardjc9a43662004-11-30 18:51:59 +00002891 UInt d32;
2892 UChar modrm;
2893 HChar dis_buf[50];
2894 Int len;
sewardjc2ac51e2004-07-12 01:03:26 +00002895 IRTemp addr;
sewardj940e8c92004-07-11 16:53:24 +00002896 IRType ty = szToITy(sz);
2897 IRTemp t1 = newTemp(ty);
sewardj92d168d2004-11-15 14:22:12 +00002898 // IRTemp t2 = IRTemp_INVALID;
sewardj940e8c92004-07-11 16:53:24 +00002899 IRTemp dst1, src, dst0;
2900 modrm = getIByte(delta);
2901 if (epartIsReg(modrm)) {
2902 switch (gregOfRM(modrm)) {
sewardjc2ac51e2004-07-12 01:03:26 +00002903 case 0: { /* TEST */
2904 delta++; d32 = getUDisp(sz, delta); delta += sz;
sewardj5bd4d162004-11-10 13:02:48 +00002905 dst1 = newTemp(ty);
2906 assign(dst1, binop(mkSizedOp(ty,Iop_And8),
2907 getIReg(sz,eregOfRM(modrm)),
sewardjc2ac51e2004-07-12 01:03:26 +00002908 mkU(ty,d32)));
sewardj5bd4d162004-11-10 13:02:48 +00002909 setFlags_DEP1( Iop_And8, dst1, ty );
sewardjc2ac51e2004-07-12 01:03:26 +00002910 DIP("test%c $0x%x, %s\n", nameISize(sz), d32,
2911 nameIReg(sz, eregOfRM(modrm)));
2912 break;
2913 }
sewardj940e8c92004-07-11 16:53:24 +00002914 case 2: /* NOT */
2915 delta++;
2916 putIReg(sz, eregOfRM(modrm),
2917 unop(mkSizedOp(ty,Iop_Not8),
2918 getIReg(sz, eregOfRM(modrm))));
2919 DIP("not%c %s\n", nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
2920 break;
2921 case 3: /* NEG */
2922 delta++;
2923 dst0 = newTemp(ty);
2924 src = newTemp(ty);
2925 dst1 = newTemp(ty);
sewardj5bd4d162004-11-10 13:02:48 +00002926 assign(dst0, mkU(ty,0));
sewardja511afc2004-07-29 22:26:03 +00002927 assign(src, getIReg(sz,eregOfRM(modrm)));
sewardj5bd4d162004-11-10 13:02:48 +00002928 assign(dst1, binop(mkSizedOp(ty,Iop_Sub8), mkexpr(dst0), mkexpr(src)));
sewardj2a2ba8b2004-11-08 13:14:06 +00002929 setFlags_DEP1_DEP2(Iop_Sub8, dst0, src, ty);
sewardj5bd4d162004-11-10 13:02:48 +00002930 putIReg(sz, eregOfRM(modrm), mkexpr(dst1));
sewardj940e8c92004-07-11 16:53:24 +00002931 DIP("neg%c %s\n", nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
2932 break;
sewardjcf780b42004-07-13 18:42:17 +00002933 case 4: /* MUL (unsigned widening) */
2934 delta++;
sewardj1813dbe2004-07-28 17:09:04 +00002935 src = newTemp(ty);
sewardj5bd4d162004-11-10 13:02:48 +00002936 assign(src, getIReg(sz,eregOfRM(modrm)));
sewardj1813dbe2004-07-28 17:09:04 +00002937 codegen_mulL_A_D ( sz, False, src, nameIReg(sz,eregOfRM(modrm)) );
sewardjcf780b42004-07-13 18:42:17 +00002938 break;
sewardjcaca9d02004-07-28 07:11:32 +00002939 case 5: /* IMUL (signed widening) */
2940 delta++;
sewardj1813dbe2004-07-28 17:09:04 +00002941 src = newTemp(ty);
sewardj5bd4d162004-11-10 13:02:48 +00002942 assign(src, getIReg(sz,eregOfRM(modrm)));
sewardj1813dbe2004-07-28 17:09:04 +00002943 codegen_mulL_A_D ( sz, True, src, nameIReg(sz,eregOfRM(modrm)) );
sewardjcaca9d02004-07-28 07:11:32 +00002944 break;
sewardj68511542004-07-28 00:15:44 +00002945 case 6: /* DIV */
2946 delta++;
2947 assign( t1, getIReg(sz, eregOfRM(modrm)) );
2948 codegen_div ( sz, t1, False );
2949 DIP("div%c %s\n", nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
2950 break;
sewardjcaca9d02004-07-28 07:11:32 +00002951 case 7: /* IDIV */
2952 delta++;
2953 assign( t1, getIReg(sz, eregOfRM(modrm)) );
2954 codegen_div ( sz, t1, True );
2955 DIP("idiv%c %s\n", nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
2956 break;
sewardj940e8c92004-07-11 16:53:24 +00002957 default:
2958 vex_printf(
2959 "unhandled Grp3(R) case %d\n", (UInt)gregOfRM(modrm));
2960 vpanic("Grp3(x86)");
2961 }
2962 } else {
sewardjc2ac51e2004-07-12 01:03:26 +00002963 addr = disAMode ( &len, sorb, delta, dis_buf );
2964 t1 = newTemp(ty);
2965 delta += len;
2966 assign(t1, loadLE(ty,mkexpr(addr)));
2967 switch (gregOfRM(modrm)) {
2968 case 0: { /* TEST */
2969 d32 = getUDisp(sz, delta); delta += sz;
sewardj5bd4d162004-11-10 13:02:48 +00002970 dst1 = newTemp(ty);
2971 assign(dst1, binop(mkSizedOp(ty,Iop_And8),
2972 mkexpr(t1), mkU(ty,d32)));
2973 setFlags_DEP1( Iop_And8, dst1, ty );
sewardjc2ac51e2004-07-12 01:03:26 +00002974 DIP("test%c $0x%x, %s\n", nameISize(sz), d32, dis_buf);
2975 break;
2976 }
sewardj78fe7912004-08-20 23:38:07 +00002977 /* probably OK, but awaiting test case */
2978 case 2: /* NOT */
2979 storeLE( mkexpr(addr), unop(mkSizedOp(ty,Iop_Not8), mkexpr(t1)));
2980 DIP("not%c %s\n", nameISize(sz), dis_buf);
2981 break;
sewardj0c12ea82004-07-12 08:18:16 +00002982 case 3: /* NEG */
2983 dst0 = newTemp(ty);
2984 src = newTemp(ty);
2985 dst1 = newTemp(ty);
sewardj5bd4d162004-11-10 13:02:48 +00002986 assign(dst0, mkU(ty,0));
sewardja511afc2004-07-29 22:26:03 +00002987 assign(src, mkexpr(t1));
sewardj5bd4d162004-11-10 13:02:48 +00002988 assign(dst1, binop(mkSizedOp(ty,Iop_Sub8), mkexpr(dst0), mkexpr(src)));
sewardj2a2ba8b2004-11-08 13:14:06 +00002989 setFlags_DEP1_DEP2(Iop_Sub8, dst0, src, ty);
sewardj5bd4d162004-11-10 13:02:48 +00002990 storeLE( mkexpr(addr), mkexpr(dst1) );
sewardj0c12ea82004-07-12 08:18:16 +00002991 DIP("neg%c %s\n", nameISize(sz), dis_buf);
2992 break;
sewardj1813dbe2004-07-28 17:09:04 +00002993 case 4: /* MUL */
2994 codegen_mulL_A_D ( sz, False, t1, dis_buf );
2995 break;
2996 case 5: /* IMUL */
2997 codegen_mulL_A_D ( sz, True, t1, dis_buf );
2998 break;
sewardj9690d922004-07-14 01:39:17 +00002999 case 6: /* DIV */
3000 codegen_div ( sz, t1, False );
3001 DIP("div%c %s\n", nameISize(sz), dis_buf);
3002 break;
sewardj1813dbe2004-07-28 17:09:04 +00003003 case 7: /* IDIV */
3004 codegen_div ( sz, t1, True );
3005 DIP("idiv%c %s\n", nameISize(sz), dis_buf);
3006 break;
sewardjc2ac51e2004-07-12 01:03:26 +00003007 default:
3008 vex_printf(
3009 "unhandled Grp3(M) case %d\n", (UInt)gregOfRM(modrm));
3010 vpanic("Grp3(x86)");
3011 }
sewardj940e8c92004-07-11 16:53:24 +00003012 }
3013 return delta;
3014}
3015
3016
sewardjc2ac51e2004-07-12 01:03:26 +00003017/* Group 4 extended opcodes. */
3018static
3019UInt dis_Grp4 ( UChar sorb, UInt delta )
3020{
sewardjc9a43662004-11-30 18:51:59 +00003021 Int alen;
sewardjc2ac51e2004-07-12 01:03:26 +00003022 UChar modrm;
sewardjc9a43662004-11-30 18:51:59 +00003023 HChar dis_buf[50];
sewardjc2ac51e2004-07-12 01:03:26 +00003024 IRType ty = Ity_I8;
sewardj7ed22952004-07-29 00:09:58 +00003025 IRTemp t1 = newTemp(ty);
3026 IRTemp t2 = newTemp(ty);
sewardjc2ac51e2004-07-12 01:03:26 +00003027
3028 modrm = getIByte(delta);
3029 if (epartIsReg(modrm)) {
sewardjc2ac51e2004-07-12 01:03:26 +00003030 assign(t1, getIReg(1, eregOfRM(modrm)));
3031 switch (gregOfRM(modrm)) {
sewardj7ed22952004-07-29 00:09:58 +00003032 case 0: /* INC */
3033 assign(t2, binop(Iop_Add8, mkexpr(t1), mkU8(1)));
3034 putIReg(1, eregOfRM(modrm), mkexpr(t2));
3035 setFlags_INC_DEC( True, t2, ty );
3036 break;
sewardjc2ac51e2004-07-12 01:03:26 +00003037 case 1: /* DEC */
sewardjc2ac51e2004-07-12 01:03:26 +00003038 assign(t2, binop(Iop_Sub8, mkexpr(t1), mkU8(1)));
3039 putIReg(1, eregOfRM(modrm), mkexpr(t2));
3040 setFlags_INC_DEC( False, t2, ty );
3041 break;
3042 default:
3043 vex_printf(
3044 "unhandled Grp4(R) case %d\n", (UInt)gregOfRM(modrm));
sewardj7ed22952004-07-29 00:09:58 +00003045 vpanic("Grp4(x86,R)");
sewardjc2ac51e2004-07-12 01:03:26 +00003046 }
3047 delta++;
3048 DIP("%sb %s\n", nameGrp4(gregOfRM(modrm)),
3049 nameIReg(1, eregOfRM(modrm)));
3050 } else {
sewardj7ed22952004-07-29 00:09:58 +00003051 IRTemp addr = disAMode ( &alen, sorb, delta, dis_buf );
3052 assign( t1, loadLE(ty, mkexpr(addr)) );
3053 switch (gregOfRM(modrm)) {
sewardj588ea762004-09-10 18:56:32 +00003054 case 0: /* INC */
3055 assign(t2, binop(Iop_Add8, mkexpr(t1), mkU8(1)));
3056 storeLE( mkexpr(addr), mkexpr(t2) );
3057 setFlags_INC_DEC( True, t2, ty );
3058 break;
sewardj7ed22952004-07-29 00:09:58 +00003059 case 1: /* DEC */
3060 assign(t2, binop(Iop_Sub8, mkexpr(t1), mkU8(1)));
3061 storeLE( mkexpr(addr), mkexpr(t2) );
3062 setFlags_INC_DEC( False, t2, ty );
3063 break;
3064 default:
3065 vex_printf(
3066 "unhandled Grp4(M) case %d\n", (UInt)gregOfRM(modrm));
3067 vpanic("Grp4(x86,M)");
3068 }
3069 delta += alen;
3070 DIP("%sb %s\n", nameGrp4(gregOfRM(modrm)), dis_buf);
sewardjc2ac51e2004-07-12 01:03:26 +00003071 }
3072 return delta;
3073}
sewardj0611d802004-07-11 02:37:54 +00003074
3075
3076/* Group 5 extended opcodes. */
3077static
sewardjce70a5c2004-10-18 14:09:54 +00003078UInt dis_Grp5 ( UChar sorb, Int sz, UInt delta, DisResult* whatNext )
sewardj0611d802004-07-11 02:37:54 +00003079{
3080 Int len;
3081 UChar modrm;
sewardjc9a43662004-11-30 18:51:59 +00003082 HChar dis_buf[50];
sewardj92d168d2004-11-15 14:22:12 +00003083 IRTemp addr = IRTemp_INVALID;
sewardj0611d802004-07-11 02:37:54 +00003084 IRType ty = szToITy(sz);
3085 IRTemp t1 = newTemp(ty);
sewardj92d168d2004-11-15 14:22:12 +00003086 IRTemp t2 = IRTemp_INVALID;
sewardj0611d802004-07-11 02:37:54 +00003087
3088 modrm = getIByte(delta);
3089 if (epartIsReg(modrm)) {
sewardj940e8c92004-07-11 16:53:24 +00003090 assign(t1, getIReg(sz,eregOfRM(modrm)));
sewardj0611d802004-07-11 02:37:54 +00003091 switch (gregOfRM(modrm)) {
sewardjc9a65702004-07-07 16:32:57 +00003092//-- case 0: /* INC */
3093//-- uInstr1(cb, INC, sz, TempReg, t1);
3094//-- setFlagsFromUOpcode(cb, INC);
3095//-- uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, eregOfRM(modrm));
3096//-- break;
3097//-- case 1: /* DEC */
3098//-- uInstr1(cb, DEC, sz, TempReg, t1);
3099//-- setFlagsFromUOpcode(cb, DEC);
3100//-- uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, eregOfRM(modrm));
3101//-- break;
sewardjc2ac51e2004-07-12 01:03:26 +00003102 case 2: /* call Ev */
3103 vassert(sz == 4);
3104 t2 = newTemp(Ity_I32);
3105 assign(t2, binop(Iop_Sub32, getIReg(4,R_ESP), mkU32(4)));
3106 putIReg(4, R_ESP, mkexpr(t2));
sewardj5bd4d162004-11-10 13:02:48 +00003107 storeLE( mkexpr(t2), mkU32(guest_eip_bbstart+delta+1));
3108 jmp_treg(Ijk_Call,t1);
sewardjce70a5c2004-10-18 14:09:54 +00003109 *whatNext = Dis_StopHere;
sewardjc2ac51e2004-07-12 01:03:26 +00003110 break;
sewardj0611d802004-07-11 02:37:54 +00003111 case 4: /* jmp Ev */
3112 vassert(sz == 4);
sewardj78c19df2004-07-12 22:49:27 +00003113 jmp_treg(Ijk_Boring,t1);
sewardjce70a5c2004-10-18 14:09:54 +00003114 *whatNext = Dis_StopHere;
sewardj0611d802004-07-11 02:37:54 +00003115 break;
3116 default:
3117 vex_printf(
3118 "unhandled Grp5(R) case %d\n", (UInt)gregOfRM(modrm));
3119 vpanic("Grp5(x86)");
3120 }
3121 delta++;
3122 DIP("%s%c %s\n", nameGrp5(gregOfRM(modrm)),
3123 nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
3124 } else {
3125 addr = disAMode ( &len, sorb, delta, dis_buf );
sewardj940e8c92004-07-11 16:53:24 +00003126 assign(t1, loadLE(ty,mkexpr(addr)));
sewardj0611d802004-07-11 02:37:54 +00003127 switch (gregOfRM(modrm)) {
3128 case 0: /* INC */
3129 t2 = newTemp(ty);
3130 assign(t2, binop(mkSizedOp(ty,Iop_Add8),
3131 mkexpr(t1), mkU(ty,1)));
3132 setFlags_INC_DEC( True, t2, ty );
sewardj940e8c92004-07-11 16:53:24 +00003133 storeLE(mkexpr(addr),mkexpr(t2));
sewardj0611d802004-07-11 02:37:54 +00003134 break;
sewardjc2ac51e2004-07-12 01:03:26 +00003135 case 1: /* DEC */
3136 t2 = newTemp(ty);
3137 assign(t2, binop(mkSizedOp(ty,Iop_Sub8),
3138 mkexpr(t1), mkU(ty,1)));
3139 setFlags_INC_DEC( False, t2, ty );
3140 storeLE(mkexpr(addr),mkexpr(t2));
3141 break;
sewardj77b86be2004-07-11 13:28:24 +00003142 case 2: /* call Ev */
3143 vassert(sz == 4);
3144 t2 = newTemp(Ity_I32);
3145 assign(t2, binop(Iop_Sub32, getIReg(4,R_ESP), mkU32(4)));
3146 putIReg(4, R_ESP, mkexpr(t2));
sewardj5bd4d162004-11-10 13:02:48 +00003147 storeLE( mkexpr(t2), mkU32(guest_eip_bbstart+delta+len));
3148 jmp_treg(Ijk_Call,t1);
sewardjce70a5c2004-10-18 14:09:54 +00003149 *whatNext = Dis_StopHere;
sewardj77b86be2004-07-11 13:28:24 +00003150 break;
3151 case 4: /* JMP Ev */
3152 vassert(sz == 4);
sewardj78c19df2004-07-12 22:49:27 +00003153 jmp_treg(Ijk_Boring,t1);
sewardjce70a5c2004-10-18 14:09:54 +00003154 *whatNext = Dis_StopHere;
sewardj77b86be2004-07-11 13:28:24 +00003155 break;
sewardj0c12ea82004-07-12 08:18:16 +00003156 case 6: /* PUSH Ev */
3157 vassert(sz == 4 || sz == 2);
3158 t2 = newTemp(Ity_I32);
3159 assign( t2, binop(Iop_Sub32,getIReg(4,R_ESP),mkU32(sz)) );
3160 putIReg(4, R_ESP, mkexpr(t2) );
sewardj5bd4d162004-11-10 13:02:48 +00003161 storeLE( mkexpr(t2), mkexpr(t1) );
sewardj0c12ea82004-07-12 08:18:16 +00003162 break;
sewardj0611d802004-07-11 02:37:54 +00003163 default:
3164 vex_printf(
3165 "unhandled Grp5(M) case %d\n", (UInt)gregOfRM(modrm));
3166 vpanic("Grp5(x86)");
3167 }
3168 delta += len;
3169 DIP("%s%c %s\n", nameGrp5(gregOfRM(modrm)),
3170 nameISize(sz), dis_buf);
3171 }
3172 return delta;
3173}
3174
sewardj464efa42004-11-19 22:17:29 +00003175
sewardj64e1d652004-07-12 14:00:46 +00003176/*------------------------------------------------------------*/
3177/*--- Disassembling string ops (including REP prefixes) ---*/
3178/*------------------------------------------------------------*/
3179
3180/* Code shared by all the string ops */
3181static
3182void dis_string_op_increment(Int sz, Int t_inc)
3183{
3184 if (sz == 4 || sz == 2) {
3185 assign( t_inc,
3186 binop(Iop_Shl32, IRExpr_Get( OFFB_DFLAG, Ity_I32 ),
sewardj6d2638e2004-07-15 09:38:27 +00003187 mkU8(sz/2) ) );
sewardj64e1d652004-07-12 14:00:46 +00003188 } else {
3189 assign( t_inc,
3190 IRExpr_Get( OFFB_DFLAG, Ity_I32 ) );
3191 }
3192}
3193
sewardj64e1d652004-07-12 14:00:46 +00003194static
3195void dis_string_op( void (*dis_OP)( Int, IRTemp ),
3196 Int sz, Char* name, UChar sorb )
3197{
3198 IRTemp t_inc = newTemp(Ity_I32);
3199 vassert(sorb == 0);
3200 dis_string_op_increment(sz, t_inc);
3201 dis_OP( sz, t_inc );
3202 DIP("%s%c\n", name, nameISize(sz));
3203}
sewardj64e1d652004-07-12 14:00:46 +00003204
3205static
3206void dis_MOVS ( Int sz, IRTemp t_inc )
3207{
3208 IRType ty = szToITy(sz);
3209 //IRTemp tv = newTemp(ty); /* value being copied */
3210 IRTemp td = newTemp(Ity_I32); /* EDI */
3211 IRTemp ts = newTemp(Ity_I32); /* ESI */
3212
3213 //uInstr2(cb, GET, 4, ArchReg, R_EDI, TempReg, td);
3214 //uInstr2(cb, GET, 4, ArchReg, R_ESI, TempReg, ts);
3215 assign( td, getIReg(4, R_EDI) );
3216 assign( ts, getIReg(4, R_ESI) );
3217
3218 //uInstr2(cb, LOAD, sz, TempReg, ts, TempReg, tv);
3219 //uInstr2(cb, STORE,sz, TempReg, tv, TempReg, td);
3220 storeLE( mkexpr(td), loadLE(ty,mkexpr(ts)) );
3221
3222 //uInstr2(cb, ADD, 4, TempReg, t_inc, TempReg, td);
3223 //uInstr2(cb, ADD, 4, TempReg, t_inc, TempReg, ts);
3224
3225 //uInstr2(cb, PUT, 4, TempReg, td, ArchReg, R_EDI);
3226 //uInstr2(cb, PUT, 4, TempReg, ts, ArchReg, R_ESI);
3227 putIReg( 4, R_EDI, binop(Iop_Add32, mkexpr(td), mkexpr(t_inc)) );
3228 putIReg( 4, R_ESI, binop(Iop_Add32, mkexpr(ts), mkexpr(t_inc)) );
3229}
3230
sewardjc9a65702004-07-07 16:32:57 +00003231//-- static
3232//-- void dis_LODS ( UCodeBlock* cb, Int sz, Int t_inc )
3233//-- {
3234//-- Int ta = newTemp(cb); /* EAX */
3235//-- Int ts = newTemp(cb); /* ESI */
3236//--
3237//-- uInstr2(cb, GET, 4, ArchReg, R_ESI, TempReg, ts);
3238//-- uInstr2(cb, LOAD, sz, TempReg, ts, TempReg, ta);
3239//-- uInstr2(cb, PUT, sz, TempReg, ta, ArchReg, R_EAX);
3240//--
3241//-- uInstr2(cb, ADD, 4, TempReg, t_inc, TempReg, ts);
3242//-- uInstr2(cb, PUT, 4, TempReg, ts, ArchReg, R_ESI);
3243//-- }
sewardj64e1d652004-07-12 14:00:46 +00003244
3245static
3246void dis_STOS ( Int sz, IRTemp t_inc )
3247{
3248 IRType ty = szToITy(sz);
3249 IRTemp ta = newTemp(ty); /* EAX */
3250 IRTemp td = newTemp(Ity_I32); /* EDI */
3251
3252 //uInstr2(cb, GET, sz, ArchReg, R_EAX, TempReg, ta);
3253 assign( ta, getIReg(sz, R_EAX) );
3254
3255 //uInstr2(cb, GET, 4, ArchReg, R_EDI, TempReg, td);
3256 assign( td, getIReg(4, R_EDI) );
3257
3258 //uInstr2(cb, STORE, sz, TempReg, ta, TempReg, td);
sewardj6d2638e2004-07-15 09:38:27 +00003259 storeLE( mkexpr(td), mkexpr(ta) );
sewardj64e1d652004-07-12 14:00:46 +00003260
3261 //uInstr2(cb, ADD, 4, TempReg, t_inc, TempReg, td);
3262 //uInstr2(cb, PUT, 4, TempReg, td, ArchReg, R_EDI);
3263 putIReg( 4, R_EDI, binop(Iop_Add32, mkexpr(td), mkexpr(t_inc)) );
3264}
3265
3266static
3267void dis_CMPS ( Int sz, IRTemp t_inc )
3268{
3269 IRType ty = szToITy(sz);
sewardj6d2638e2004-07-15 09:38:27 +00003270 IRTemp tdv = newTemp(ty); /* (EDI) */
3271 IRTemp tsv = newTemp(ty); /* (ESI) */
sewardj2a2ba8b2004-11-08 13:14:06 +00003272 //IRTemp res = newTemp(ty);
sewardj64e1d652004-07-12 14:00:46 +00003273 IRTemp td = newTemp(Ity_I32); /* EDI */
3274 IRTemp ts = newTemp(Ity_I32); /* ESI */
3275
3276 //uInstr2(cb, GET, 4, ArchReg, R_EDI, TempReg, td);
3277 assign( td, getIReg(4, R_EDI) );
3278
3279 //uInstr2(cb, GET, 4, ArchReg, R_ESI, TempReg, ts);
3280 assign( ts, getIReg(4, R_ESI) );
3281
3282 //uInstr2(cb, LOAD, sz, TempReg, td, TempReg, tdv);
3283 assign( tdv, loadLE(ty,mkexpr(td)) );
3284
3285 //uInstr2(cb, LOAD, sz, TempReg, ts, TempReg, tsv);
sewardjb9c5cf62004-08-24 15:10:38 +00003286 assign( tsv, loadLE(ty,mkexpr(ts)) );
sewardj64e1d652004-07-12 14:00:46 +00003287
3288 //uInstr2(cb, SUB, sz, TempReg, tdv, TempReg, tsv);
3289 //setFlagsFromUOpcode(cb, SUB);
sewardj2a2ba8b2004-11-08 13:14:06 +00003290 //assign( res, binop(mkSizedOp(ty, Iop_Sub8), mkexpr(tsv), mkexpr(tdv)) );
3291 setFlags_DEP1_DEP2 ( Iop_Sub8, tsv, tdv, ty );
sewardj64e1d652004-07-12 14:00:46 +00003292
3293 //uInstr2(cb, ADD, 4, TempReg, t_inc, TempReg, td);
3294 //uInstr2(cb, ADD, 4, TempReg, t_inc, TempReg, ts);
3295
3296 //uInstr2(cb, PUT, 4, TempReg, td, ArchReg, R_EDI);
3297 putIReg(4, R_EDI, binop(Iop_Add32, mkexpr(td), mkexpr(t_inc)) );
3298
3299 //uInstr2(cb, PUT, 4, TempReg, ts, ArchReg, R_ESI);
3300 putIReg(4, R_ESI, binop(Iop_Add32, mkexpr(ts), mkexpr(t_inc)) );
3301}
3302
sewardj64e1d652004-07-12 14:00:46 +00003303static
3304void dis_SCAS ( Int sz, IRTemp t_inc )
3305{
3306 IRType ty = szToITy(sz);
sewardj82292882004-07-27 00:15:59 +00003307 IRTemp ta = newTemp(ty); /* EAX */
sewardj64e1d652004-07-12 14:00:46 +00003308 IRTemp td = newTemp(Ity_I32); /* EDI */
3309 IRTemp tdv = newTemp(ty); /* (EDI) */
sewardj2a2ba8b2004-11-08 13:14:06 +00003310 //IRTemp res = newTemp(ty);
sewardj64e1d652004-07-12 14:00:46 +00003311
3312 //uInstr2(cb, GET, sz, ArchReg, R_EAX, TempReg, ta);
sewardjb9c5cf62004-08-24 15:10:38 +00003313 assign( ta, getIReg(sz, R_EAX) );
sewardj64e1d652004-07-12 14:00:46 +00003314
3315 //uInstr2(cb, GET, 4, ArchReg, R_EDI, TempReg, td);
3316 assign( td, getIReg(4, R_EDI) );
3317
3318 //uInstr2(cb, LOAD, sz, TempReg, td, TempReg, tdv);
3319 assign( tdv, loadLE(ty,mkexpr(td)) );
3320
sewardj64e1d652004-07-12 14:00:46 +00003321 //uInstr2(cb, SUB, sz, TempReg, tdv, TempReg, ta);
3322 //setFlagsFromUOpcode(cb, SUB);
sewardj2a2ba8b2004-11-08 13:14:06 +00003323 //assign( res, binop(mkSizedOp(ty, Iop_Sub8), mkexpr(ta), mkexpr(tdv)) );
3324 setFlags_DEP1_DEP2 ( Iop_Sub8, ta, tdv, ty );
sewardj64e1d652004-07-12 14:00:46 +00003325
3326 //uInstr2(cb, ADD, 4, TempReg, t_inc, TempReg, td);
3327 //uInstr2(cb, PUT, 4, TempReg, td, ArchReg, R_EDI);
3328 putIReg(4, R_EDI, binop(Iop_Add32, mkexpr(td), mkexpr(t_inc)) );
3329}
sewardj82292882004-07-27 00:15:59 +00003330
sewardj64e1d652004-07-12 14:00:46 +00003331
3332/* Wrap the appropriate string op inside a REP/REPE/REPNE.
3333 We assume the insn is the last one in the basic block, and so emit a jump
3334 to the next insn, rather than just falling through. */
3335static
sewardj2a9ad022004-11-25 02:46:58 +00003336void dis_REP_op ( X86Condcode cond,
sewardj64e1d652004-07-12 14:00:46 +00003337 void (*dis_OP)(Int, IRTemp),
3338 Int sz, Addr32 eip, Addr32 eip_next, Char* name )
3339{
3340 IRTemp t_inc = newTemp(Ity_I32);
3341 IRTemp tc = newTemp(Ity_I32); /* ECX */
3342
3343 //uInstr2 (cb, GET, 4, ArchReg, R_ECX, TempReg, tc);
3344 assign( tc, getIReg(4,R_ECX) );
3345
3346 //uInstr2 (cb, JIFZ, 4, TempReg, tc, Literal, 0);
3347 //uLiteral(cb, eip_next);
3348 stmt( IRStmt_Exit( binop(Iop_CmpEQ32,mkexpr(tc),mkU32(0)),
sewardj893aada2004-11-29 19:57:54 +00003349 Ijk_Boring,
sewardj64e1d652004-07-12 14:00:46 +00003350 IRConst_U32(eip_next) ) );
3351
3352 //uInstr1 (cb, DEC, 4, TempReg, tc);
3353 //uInstr2 (cb, PUT, 4, TempReg, tc, ArchReg, R_ECX);
3354 putIReg(4, R_ECX, binop(Iop_Sub32, mkexpr(tc), mkU32(1)) );
3355
3356 dis_string_op_increment(sz, t_inc);
3357 dis_OP (sz, t_inc);
3358
sewardj2a9ad022004-11-25 02:46:58 +00003359 if (cond == X86CondAlways) {
sewardj78c19df2004-07-12 22:49:27 +00003360 jmp_lit(Ijk_Boring,eip);
sewardj64e1d652004-07-12 14:00:46 +00003361 } else {
sewardj2a9ad022004-11-25 02:46:58 +00003362 stmt( IRStmt_Exit( mk_x86g_calculate_condition(cond),
sewardj893aada2004-11-29 19:57:54 +00003363 Ijk_Boring,
sewardj5bd4d162004-11-10 13:02:48 +00003364 IRConst_U32(eip) ) );
sewardj78c19df2004-07-12 22:49:27 +00003365 jmp_lit(Ijk_Boring,eip_next);
sewardj64e1d652004-07-12 14:00:46 +00003366 }
3367 DIP("%s%c\n", name, nameISize(sz));
3368}
3369
sewardj464efa42004-11-19 22:17:29 +00003370
sewardj64e1d652004-07-12 14:00:46 +00003371/*------------------------------------------------------------*/
3372/*--- Arithmetic, etc. ---*/
3373/*------------------------------------------------------------*/
3374
sewardj2a2ba8b2004-11-08 13:14:06 +00003375/* IMUL E, G. Supplied eip points to the modR/M byte. */
sewardjcf780b42004-07-13 18:42:17 +00003376static
3377UInt dis_mul_E_G ( UChar sorb,
3378 Int size,
sewardj2a2ba8b2004-11-08 13:14:06 +00003379 UInt delta0 )
sewardjcf780b42004-07-13 18:42:17 +00003380{
sewardj71a65362004-07-28 01:48:34 +00003381 Int alen;
sewardjc9a43662004-11-30 18:51:59 +00003382 HChar dis_buf[50];
sewardjcf780b42004-07-13 18:42:17 +00003383 UChar rm = getIByte(delta0);
3384 IRType ty = szToITy(size);
sewardj6d2638e2004-07-15 09:38:27 +00003385 IRTemp te = newTemp(ty);
3386 IRTemp tg = newTemp(ty);
sewardj948d48b2004-11-05 19:49:09 +00003387 IRTemp resLo = newTemp(ty);
sewardj71a65362004-07-28 01:48:34 +00003388
sewardj948d48b2004-11-05 19:49:09 +00003389 assign( tg, getIReg(size, gregOfRM(rm)) );
sewardjcf780b42004-07-13 18:42:17 +00003390 if (epartIsReg(rm)) {
sewardjcf780b42004-07-13 18:42:17 +00003391 assign( te, getIReg(size, eregOfRM(rm)) );
sewardj948d48b2004-11-05 19:49:09 +00003392 } else {
3393 IRTemp addr = disAMode( &alen, sorb, delta0, dis_buf );
3394 assign( te, loadLE(ty,mkexpr(addr)) );
3395 }
sewardjcf780b42004-07-13 18:42:17 +00003396
sewardj2a9ad022004-11-25 02:46:58 +00003397 setFlags_MUL ( ty, te, tg, X86G_CC_OP_SMULB );
sewardj948d48b2004-11-05 19:49:09 +00003398
sewardj2a2ba8b2004-11-08 13:14:06 +00003399 assign( resLo, binop( mkSizedOp(ty, Iop_Mul8), mkexpr(te), mkexpr(tg) ) );
sewardj948d48b2004-11-05 19:49:09 +00003400
3401 putIReg(size, gregOfRM(rm), mkexpr(resLo) );
3402
3403 if (epartIsReg(rm)) {
sewardj2a2ba8b2004-11-08 13:14:06 +00003404 DIP("imul%c %s, %s\n", nameISize(size),
3405 nameIReg(size,eregOfRM(rm)),
3406 nameIReg(size,gregOfRM(rm)));
sewardjcf780b42004-07-13 18:42:17 +00003407 return 1+delta0;
3408 } else {
sewardj2a2ba8b2004-11-08 13:14:06 +00003409 DIP("imul%c %s, %s\n", nameISize(size),
3410 dis_buf, nameIReg(size,gregOfRM(rm)));
sewardj71a65362004-07-28 01:48:34 +00003411 return alen+delta0;
sewardjcf780b42004-07-13 18:42:17 +00003412 }
3413}
3414
3415
sewardj1813dbe2004-07-28 17:09:04 +00003416/* IMUL I * E -> G. Supplied eip points to the modR/M byte. */
3417static
3418UInt dis_imul_I_E_G ( UChar sorb,
3419 Int size,
3420 UInt delta,
3421 Int litsize )
3422{
sewardj883b00b2004-09-11 09:30:24 +00003423 Int d32, alen;
sewardjc9a43662004-11-30 18:51:59 +00003424 HChar dis_buf[50];
sewardjb81f8b32004-07-30 10:17:50 +00003425 UChar rm = getIByte(delta);
sewardj1813dbe2004-07-28 17:09:04 +00003426 IRType ty = szToITy(size);
3427 IRTemp te = newTemp(ty);
3428 IRTemp tl = newTemp(ty);
sewardj948d48b2004-11-05 19:49:09 +00003429 IRTemp resLo = newTemp(ty);
sewardj1813dbe2004-07-28 17:09:04 +00003430
sewardjb81f8b32004-07-30 10:17:50 +00003431 vassert(size == 1 || size == 2 || size == 4);
3432
sewardj1813dbe2004-07-28 17:09:04 +00003433 if (epartIsReg(rm)) {
3434 assign(te, getIReg(size, eregOfRM(rm)));
3435 delta++;
3436 } else {
sewardj883b00b2004-09-11 09:30:24 +00003437 IRTemp addr = disAMode( &alen, sorb, delta, dis_buf );
3438 assign(te, loadLE(ty, mkexpr(addr)));
3439 delta += alen;
sewardj1813dbe2004-07-28 17:09:04 +00003440 }
3441 d32 = getSDisp(litsize,delta);
3442 delta += litsize;
3443
sewardjb81f8b32004-07-30 10:17:50 +00003444 if (size == 1) d32 &= 0xFF;
3445 if (size == 2) d32 &= 0xFFFF;
3446
sewardj1813dbe2004-07-28 17:09:04 +00003447 assign(tl, mkU(ty,d32));
sewardj948d48b2004-11-05 19:49:09 +00003448
sewardj2a2ba8b2004-11-08 13:14:06 +00003449 assign( resLo, binop( mkSizedOp(ty, Iop_Mul8), mkexpr(te), mkexpr(tl) ));
sewardj948d48b2004-11-05 19:49:09 +00003450
sewardj2a9ad022004-11-25 02:46:58 +00003451 setFlags_MUL ( ty, te, tl, X86G_CC_OP_SMULB );
sewardj948d48b2004-11-05 19:49:09 +00003452
3453 putIReg(size, gregOfRM(rm), mkexpr(resLo));
sewardj1813dbe2004-07-28 17:09:04 +00003454
3455 DIP("imul %d, %s, %s\n", d32,
3456 ( epartIsReg(rm) ? nameIReg(size,eregOfRM(rm)) : dis_buf ),
3457 nameIReg(size,gregOfRM(rm)) );
3458 return delta;
sewardj948d48b2004-11-05 19:49:09 +00003459}
sewardj1813dbe2004-07-28 17:09:04 +00003460
3461
sewardjd1725d12004-08-12 20:46:53 +00003462/*------------------------------------------------------------*/
sewardj464efa42004-11-19 22:17:29 +00003463/*--- ---*/
3464/*--- x87 FLOATING POINT INSTRUCTIONS ---*/
3465/*--- ---*/
sewardjd1725d12004-08-12 20:46:53 +00003466/*------------------------------------------------------------*/
3467
sewardj207557a2004-08-27 12:00:18 +00003468/* --- Helper functions for dealing with the register stack. --- */
3469
sewardj893aada2004-11-29 19:57:54 +00003470/* --- Set the emulation-warning pseudo-register. --- */
3471
3472static void put_emwarn ( IRExpr* e /* :: Ity_I32 */ )
3473{
3474 stmt( IRStmt_Put( OFFB_EMWARN, e ) );
3475}
3476
sewardj17442fe2004-09-20 14:54:28 +00003477/* --- Produce an IRExpr* denoting a 64-bit QNaN. --- */
sewardj207557a2004-08-27 12:00:18 +00003478
sewardj17442fe2004-09-20 14:54:28 +00003479static IRExpr* mkQNaN64 ( void )
sewardj207557a2004-08-27 12:00:18 +00003480{
sewardj17442fe2004-09-20 14:54:28 +00003481 /* QNaN is 0 2047 1 0(51times)
3482 == 0b 11111111111b 1 0(51times)
3483 == 0x7FF8 0000 0000 0000
3484 */
3485 return IRExpr_Const(IRConst_F64i(0x7FF8000000000000ULL));
sewardj207557a2004-08-27 12:00:18 +00003486}
3487
sewardj893aada2004-11-29 19:57:54 +00003488/* --------- Get/put the top-of-stack pointer. --------- */
sewardjd1725d12004-08-12 20:46:53 +00003489
3490static IRExpr* get_ftop ( void )
3491{
3492 return IRExpr_Get( OFFB_FTOP, Ity_I32 );
3493}
3494
sewardj207557a2004-08-27 12:00:18 +00003495static void put_ftop ( IRExpr* e )
sewardjd1725d12004-08-12 20:46:53 +00003496{
sewardj207557a2004-08-27 12:00:18 +00003497 stmt( IRStmt_Put( OFFB_FTOP, e ) );
sewardjd1725d12004-08-12 20:46:53 +00003498}
3499
sewardj893aada2004-11-29 19:57:54 +00003500/* --------- Get/put the C3210 bits. --------- */
sewardjbdc7d212004-09-09 02:46:40 +00003501
sewardjc4be80c2004-09-10 16:17:45 +00003502static IRExpr* get_C3210 ( void )
sewardjbdc7d212004-09-09 02:46:40 +00003503{
sewardjc4be80c2004-09-10 16:17:45 +00003504 return IRExpr_Get( OFFB_FC3210, Ity_I32 );
sewardjbdc7d212004-09-09 02:46:40 +00003505}
3506
sewardjc4be80c2004-09-10 16:17:45 +00003507static void put_C3210 ( IRExpr* e )
sewardjbdc7d212004-09-09 02:46:40 +00003508{
sewardjc4be80c2004-09-10 16:17:45 +00003509 stmt( IRStmt_Put( OFFB_FC3210, e ) );
sewardjbdc7d212004-09-09 02:46:40 +00003510}
sewardjd1725d12004-08-12 20:46:53 +00003511
sewardj893aada2004-11-29 19:57:54 +00003512/* --------- Get/put the FPU rounding mode. --------- */
sewardjd01a9632004-11-30 13:18:37 +00003513static IRExpr* /* :: Ity_I32 */ get_fpround ( void )
sewardj8f3debf2004-09-08 23:42:23 +00003514{
sewardjd01a9632004-11-30 13:18:37 +00003515 return IRExpr_Get( OFFB_FPROUND, Ity_I32 );
sewardj8f3debf2004-09-08 23:42:23 +00003516}
3517
sewardjd01a9632004-11-30 13:18:37 +00003518static void put_fpround ( IRExpr* /* :: Ity_I32 */ e )
sewardj8f3debf2004-09-08 23:42:23 +00003519{
sewardjd01a9632004-11-30 13:18:37 +00003520 stmt( IRStmt_Put( OFFB_FPROUND, e ) );
sewardj8f3debf2004-09-08 23:42:23 +00003521}
3522
3523
sewardj893aada2004-11-29 19:57:54 +00003524/* --------- Synthesise a 2-bit FPU rounding mode. --------- */
sewardj8f3debf2004-09-08 23:42:23 +00003525/* Produces a value in 0 .. 3, which is encoded as per the type
sewardjd01a9632004-11-30 13:18:37 +00003526 IRRoundingMode. Since the guest_FPROUND value is also encoded as
3527 per IRRoundingMode, we merely need to get it and mask it for
3528 safety.
sewardj8f3debf2004-09-08 23:42:23 +00003529*/
3530static IRExpr* /* :: Ity_I32 */ get_roundingmode ( void )
3531{
sewardjd01a9632004-11-30 13:18:37 +00003532 return binop( Iop_And32, get_fpround(), mkU32(3) );
sewardj8f3debf2004-09-08 23:42:23 +00003533}
3534
3535
sewardj207557a2004-08-27 12:00:18 +00003536/* --------- Get/set FP register tag bytes. --------- */
3537
sewardj207557a2004-08-27 12:00:18 +00003538/* Given i, and some expression e, generate 'ST_TAG(i) = e'. */
3539
3540static void put_ST_TAG ( Int i, IRExpr* value )
3541{
sewardj2d3f77c2004-09-22 23:49:09 +00003542 IRArray* descr;
sewardj207557a2004-08-27 12:00:18 +00003543 vassert(typeOfIRExpr(irbb->tyenv, value) == Ity_I8);
sewardjf6dc3ce2004-10-19 01:03:46 +00003544 descr = mkIRArray( OFFB_FPTAGS, Ity_I8, 8 );
sewardj2d3f77c2004-09-22 23:49:09 +00003545 stmt( IRStmt_PutI( descr, get_ftop(), i, value ) );
sewardj207557a2004-08-27 12:00:18 +00003546}
3547
3548/* Given i, generate an expression yielding 'ST_TAG(i)'. This will be
sewardjdb199622004-09-06 23:19:03 +00003549 zero to indicate "Empty" and nonzero to indicate "NonEmpty". */
sewardj207557a2004-08-27 12:00:18 +00003550
3551static IRExpr* get_ST_TAG ( Int i )
3552{
sewardjf6dc3ce2004-10-19 01:03:46 +00003553 IRArray* descr = mkIRArray( OFFB_FPTAGS, Ity_I8, 8 );
sewardj2d3f77c2004-09-22 23:49:09 +00003554 return IRExpr_GetI( descr, get_ftop(), i );
sewardj207557a2004-08-27 12:00:18 +00003555}
3556
3557
3558/* --------- Get/set FP registers. --------- */
3559
sewardj2d3f77c2004-09-22 23:49:09 +00003560/* Given i, and some expression e, emit 'ST(i) = e' and set the
3561 register's tag to indicate the register is full. The previous
3562 state of the register is not checked. */
sewardj207557a2004-08-27 12:00:18 +00003563
3564static void put_ST_UNCHECKED ( Int i, IRExpr* value )
sewardjd1725d12004-08-12 20:46:53 +00003565{
sewardj2d3f77c2004-09-22 23:49:09 +00003566 IRArray* descr;
sewardjdb199622004-09-06 23:19:03 +00003567 vassert(typeOfIRExpr(irbb->tyenv, value) == Ity_F64);
sewardjf6dc3ce2004-10-19 01:03:46 +00003568 descr = mkIRArray( OFFB_FPREGS, Ity_F64, 8 );
sewardj2d3f77c2004-09-22 23:49:09 +00003569 stmt( IRStmt_PutI( descr, get_ftop(), i, value ) );
sewardj207557a2004-08-27 12:00:18 +00003570 /* Mark the register as in-use. */
3571 put_ST_TAG(i, mkU8(1));
sewardjd1725d12004-08-12 20:46:53 +00003572}
3573
sewardj207557a2004-08-27 12:00:18 +00003574/* Given i, and some expression e, emit
3575 ST(i) = is_full(i) ? NaN : e
3576 and set the tag accordingly.
3577*/
3578
3579static void put_ST ( Int i, IRExpr* value )
3580{
3581 put_ST_UNCHECKED( i,
sewardjdb199622004-09-06 23:19:03 +00003582 IRExpr_Mux0X( get_ST_TAG(i),
3583 /* 0 means empty */
3584 value,
3585 /* non-0 means full */
sewardj17442fe2004-09-20 14:54:28 +00003586 mkQNaN64()
sewardj207557a2004-08-27 12:00:18 +00003587 )
3588 );
3589}
3590
3591
sewardjd1725d12004-08-12 20:46:53 +00003592/* Given i, generate an expression yielding 'ST(i)'. */
3593
sewardj207557a2004-08-27 12:00:18 +00003594static IRExpr* get_ST_UNCHECKED ( Int i )
sewardjd1725d12004-08-12 20:46:53 +00003595{
sewardjf6dc3ce2004-10-19 01:03:46 +00003596 IRArray* descr = mkIRArray( OFFB_FPREGS, Ity_F64, 8 );
sewardj2d3f77c2004-09-22 23:49:09 +00003597 return IRExpr_GetI( descr, get_ftop(), i );
sewardjd1725d12004-08-12 20:46:53 +00003598}
3599
sewardjc4be80c2004-09-10 16:17:45 +00003600
sewardj207557a2004-08-27 12:00:18 +00003601/* Given i, generate an expression yielding
3602 is_full(i) ? ST(i) : NaN
3603*/
3604
3605static IRExpr* get_ST ( Int i )
3606{
3607 return
3608 IRExpr_Mux0X( get_ST_TAG(i),
3609 /* 0 means empty */
sewardj17442fe2004-09-20 14:54:28 +00003610 mkQNaN64(),
sewardj207557a2004-08-27 12:00:18 +00003611 /* non-0 means full */
3612 get_ST_UNCHECKED(i));
3613}
3614
3615
sewardjd1725d12004-08-12 20:46:53 +00003616/* Adjust FTOP downwards by one register. */
3617
sewardj207557a2004-08-27 12:00:18 +00003618static void fp_push ( void )
sewardjd1725d12004-08-12 20:46:53 +00003619{
sewardj2d3f77c2004-09-22 23:49:09 +00003620 put_ftop( binop(Iop_Sub32, get_ftop(), mkU32(1)) );
sewardjd1725d12004-08-12 20:46:53 +00003621}
3622
sewardj207557a2004-08-27 12:00:18 +00003623/* Adjust FTOP upwards by one register, and mark the vacated register
3624 as empty. */
sewardja58ea662004-08-15 03:12:41 +00003625
sewardj207557a2004-08-27 12:00:18 +00003626static void fp_pop ( void )
sewardja58ea662004-08-15 03:12:41 +00003627{
sewardjdb199622004-09-06 23:19:03 +00003628 put_ST_TAG(0, mkU8(0));
sewardj2d3f77c2004-09-22 23:49:09 +00003629 put_ftop( binop(Iop_Add32, get_ftop(), mkU32(1)) );
sewardja58ea662004-08-15 03:12:41 +00003630}
3631
sewardj3f61ddb2004-10-16 20:51:05 +00003632/* Clear the C2 bit of the FPU status register, for
3633 sin/cos/tan/sincos. */
3634
3635static void clear_C2 ( void )
3636{
sewardj67e002d2004-12-02 18:16:33 +00003637 put_C3210( binop(Iop_And32, get_C3210(), mkU32(~X86G_FC_MASK_C2)) );
sewardj3f61ddb2004-10-16 20:51:05 +00003638}
3639
3640
sewardj207557a2004-08-27 12:00:18 +00003641/* ------------------------------------------------------- */
3642/* Given all that stack-mangling junk, we can now go ahead
3643 and describe FP instructions.
3644*/
3645
sewardj3fd5e572004-09-09 22:43:51 +00003646/* ST(0) = ST(0) `op` mem64/32(addr)
sewardj207557a2004-08-27 12:00:18 +00003647 Need to check ST(0)'s tag on read, but not on write.
3648*/
sewardja58ea662004-08-15 03:12:41 +00003649static
3650void fp_do_op_mem_ST_0 ( IRTemp addr, UChar* op_txt, UChar* dis_buf,
3651 IROp op, Bool dbl )
3652{
3653 DIP("f%s%c %s", op_txt, dbl?'l':'s', dis_buf);
3654 if (dbl) {
sewardj3fd5e572004-09-09 22:43:51 +00003655 put_ST_UNCHECKED(0,
3656 binop( op,
3657 get_ST(0),
3658 loadLE(Ity_F64,mkexpr(addr))
3659 ));
sewardja58ea662004-08-15 03:12:41 +00003660 } else {
sewardj3fd5e572004-09-09 22:43:51 +00003661 put_ST_UNCHECKED(0,
3662 binop( op,
3663 get_ST(0),
3664 unop(Iop_F32toF64, loadLE(Ity_F32,mkexpr(addr)))
3665 ));
3666 }
3667}
3668
3669
3670/* ST(0) = mem64/32(addr) `op` ST(0)
3671 Need to check ST(0)'s tag on read, but not on write.
3672*/
3673static
3674void fp_do_oprev_mem_ST_0 ( IRTemp addr, UChar* op_txt, UChar* dis_buf,
sewardj883b00b2004-09-11 09:30:24 +00003675 IROp op, Bool dbl )
sewardj3fd5e572004-09-09 22:43:51 +00003676{
3677 DIP("f%s%c %s", op_txt, dbl?'l':'s', dis_buf);
3678 if (dbl) {
3679 put_ST_UNCHECKED(0,
3680 binop( op,
3681 loadLE(Ity_F64,mkexpr(addr)),
3682 get_ST(0)
3683 ));
3684 } else {
3685 put_ST_UNCHECKED(0,
3686 binop( op,
3687 unop(Iop_F32toF64, loadLE(Ity_F32,mkexpr(addr))),
3688 get_ST(0)
3689 ));
sewardja58ea662004-08-15 03:12:41 +00003690 }
3691}
3692
sewardjd1725d12004-08-12 20:46:53 +00003693
sewardjdb199622004-09-06 23:19:03 +00003694/* ST(dst) = ST(dst) `op` ST(src).
3695 Check dst and src tags when reading but not on write.
3696*/
3697static
sewardjbdc7d212004-09-09 02:46:40 +00003698void fp_do_op_ST_ST ( UChar* op_txt, IROp op, UInt st_src, UInt st_dst,
3699 Bool pop_after )
sewardjdb199622004-09-06 23:19:03 +00003700{
sewardjbdc7d212004-09-09 02:46:40 +00003701 DIP("f%s%s st(%d), st(%d)\n", op_txt, pop_after?"p":"", st_src, st_dst );
sewardjdb199622004-09-06 23:19:03 +00003702 put_ST_UNCHECKED(
3703 st_dst,
3704 binop(op, get_ST(st_dst), get_ST(st_src) )
3705 );
sewardjbdc7d212004-09-09 02:46:40 +00003706 if (pop_after)
3707 fp_pop();
3708}
3709
3710/* ST(dst) = ST(src) `op` ST(dst).
3711 Check dst and src tags when reading but not on write.
3712*/
3713static
3714void fp_do_oprev_ST_ST ( UChar* op_txt, IROp op, UInt st_src, UInt st_dst,
sewardj883b00b2004-09-11 09:30:24 +00003715 Bool pop_after )
sewardjbdc7d212004-09-09 02:46:40 +00003716{
3717 DIP("f%s%s st(%d), st(%d)\n", op_txt, pop_after?"p":"", st_src, st_dst );
3718 put_ST_UNCHECKED(
3719 st_dst,
3720 binop(op, get_ST(st_src), get_ST(st_dst) )
3721 );
3722 if (pop_after)
3723 fp_pop();
sewardjdb199622004-09-06 23:19:03 +00003724}
3725
sewardj8308aad2004-09-12 11:09:54 +00003726/* %eflags(Z,P,C) = UCOMI( st(0), st(i) ) */
3727static void fp_do_ucomi_ST0_STi ( UInt i, Bool pop_after )
3728{
3729 DIP("fucomi%s %%st(0),%%st(%d)\n", pop_after ? "p" : "", i);
3730 /* This is a bit of a hack (and isn't really right). It sets
3731 Z,P,C,O correctly, but forces A and S to zero, whereas the Intel
3732 documentation implies A and S are unchanged.
3733 */
sewardjfeeb8a82004-11-30 12:30:11 +00003734 /* It's also fishy in that it is used both for COMIP and
3735 UCOMIP, and they aren't the same (although similar). */
sewardj2a9ad022004-11-25 02:46:58 +00003736 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
sewardj2a2ba8b2004-11-08 13:14:06 +00003737 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
3738 stmt( IRStmt_Put( OFFB_CC_DEP1,
sewardj8308aad2004-09-12 11:09:54 +00003739 binop( Iop_And32,
3740 binop(Iop_CmpF64, get_ST(0), get_ST(i)),
3741 mkU32(0x45)
3742 )));
3743 if (pop_after)
3744 fp_pop();
3745}
3746
sewardjdb199622004-09-06 23:19:03 +00003747
sewardjd1725d12004-08-12 20:46:53 +00003748static
3749UInt dis_FPU ( Bool* decode_ok, UChar sorb, UInt delta )
3750{
sewardja58ea662004-08-15 03:12:41 +00003751 Int len;
3752 UInt r_src, r_dst;
sewardjc9a43662004-11-30 18:51:59 +00003753 HChar dis_buf[50];
sewardj89cd0932004-09-08 18:23:25 +00003754 IRTemp t1, t2;
sewardjd1725d12004-08-12 20:46:53 +00003755
3756 /* On entry, delta points at the second byte of the insn (the modrm
3757 byte).*/
3758 UChar first_opcode = getIByte(delta-1);
3759 UChar modrm = getIByte(delta+0);
3760
3761 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xD8 opcodes +-+-+-+-+-+-+-+ */
3762
3763 if (first_opcode == 0xD8) {
sewardjdb199622004-09-06 23:19:03 +00003764 if (modrm < 0xC0) {
sewardj89cd0932004-09-08 18:23:25 +00003765
3766 /* bits 5,4,3 are an opcode extension, and the modRM also
3767 specifies an address. */
3768 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
3769 delta += len;
3770
3771 switch (gregOfRM(modrm)) {
3772
sewardj3fd5e572004-09-09 22:43:51 +00003773 case 0: /* FADD single-real */
3774 fp_do_op_mem_ST_0 ( addr, "add", dis_buf, Iop_AddF64, False );
3775 break;
3776
sewardj89cd0932004-09-08 18:23:25 +00003777 case 1: /* FMUL single-real */
3778 fp_do_op_mem_ST_0 ( addr, "mul", dis_buf, Iop_MulF64, False );
3779 break;
3780
sewardj7ca37d92004-10-25 02:58:30 +00003781 case 2: /* FCOM single-real */
3782 DIP("fcoms %s\n", dis_buf);
3783 /* This forces C1 to zero, which isn't right. */
3784 put_C3210(
3785 binop( Iop_And32,
3786 binop(Iop_Shl32,
3787 binop(Iop_CmpF64,
3788 get_ST(0),
3789 unop(Iop_F32toF64,
3790 loadLE(Ity_F32,mkexpr(addr)))),
3791 mkU8(8)),
3792 mkU32(0x4500)
3793 ));
3794 break;
3795
3796 case 3: /* FCOMP single-real */
sewardje166ed02004-10-25 02:27:01 +00003797 DIP("fcomps %s\n", dis_buf);
3798 /* This forces C1 to zero, which isn't right. */
3799 put_C3210(
3800 binop( Iop_And32,
3801 binop(Iop_Shl32,
3802 binop(Iop_CmpF64,
3803 get_ST(0),
3804 unop(Iop_F32toF64,
3805 loadLE(Ity_F32,mkexpr(addr)))),
3806 mkU8(8)),
3807 mkU32(0x4500)
3808 ));
3809 fp_pop();
3810 break;
3811
sewardj588ea762004-09-10 18:56:32 +00003812 case 4: /* FSUB single-real */
3813 fp_do_op_mem_ST_0 ( addr, "sub", dis_buf, Iop_SubF64, False );
3814 break;
3815
3816 case 5: /* FSUBR single-real */
3817 fp_do_oprev_mem_ST_0 ( addr, "subr", dis_buf, Iop_SubF64, False );
3818 break;
3819
sewardjbdc7d212004-09-09 02:46:40 +00003820 case 6: /* FDIV single-real */
3821 fp_do_op_mem_ST_0 ( addr, "div", dis_buf, Iop_DivF64, False );
3822 break;
3823
sewardj8308aad2004-09-12 11:09:54 +00003824 case 7: /* FDIVR single-real */
3825 fp_do_oprev_mem_ST_0 ( addr, "divr", dis_buf, Iop_DivF64, False );
3826 break;
3827
sewardj89cd0932004-09-08 18:23:25 +00003828 default:
3829 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
3830 vex_printf("first_opcode == 0xD8\n");
3831 goto decode_fail;
3832 }
sewardjdb199622004-09-06 23:19:03 +00003833 } else {
3834 delta++;
3835 switch (modrm) {
sewardj89cd0932004-09-08 18:23:25 +00003836
sewardjdb199622004-09-06 23:19:03 +00003837 case 0xC0 ... 0xC7: /* FADD %st(?),%st(0) */
sewardjbdc7d212004-09-09 02:46:40 +00003838 fp_do_op_ST_ST ( "add", Iop_AddF64, modrm - 0xC0, 0, False );
sewardjdb199622004-09-06 23:19:03 +00003839 break;
sewardj89cd0932004-09-08 18:23:25 +00003840
sewardj3fd5e572004-09-09 22:43:51 +00003841 case 0xC8 ... 0xCF: /* FMUL %st(?),%st(0) */
3842 fp_do_op_ST_ST ( "mul", Iop_MulF64, modrm - 0xC8, 0, False );
3843 break;
3844
sewardje166ed02004-10-25 02:27:01 +00003845#if 1
3846 /* Dunno if this is right */
3847 case 0xD0 ... 0xD7: /* FCOM %st(?),%st(0) */
3848 r_dst = (UInt)modrm - 0xD0;
3849 DIP("fcom %%st(0),%%st(%d)\n", r_dst);
3850 /* This forces C1 to zero, which isn't right. */
3851 put_C3210(
3852 binop( Iop_And32,
3853 binop(Iop_Shl32,
3854 binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
3855 mkU8(8)),
3856 mkU32(0x4500)
3857 ));
3858 break;
3859#endif
3860#if 1
sewardj98169c52004-10-24 13:11:39 +00003861 /* Dunno if this is right */
3862 case 0xD8 ... 0xDF: /* FCOMP %st(?),%st(0) */
3863 r_dst = (UInt)modrm - 0xD8;
3864 DIP("fcomp %%st(0),%%st(%d)\n", r_dst);
3865 /* This forces C1 to zero, which isn't right. */
3866 put_C3210(
3867 binop( Iop_And32,
3868 binop(Iop_Shl32,
3869 binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
3870 mkU8(8)),
3871 mkU32(0x4500)
3872 ));
3873 fp_pop();
3874 break;
3875#endif
sewardj89cd0932004-09-08 18:23:25 +00003876 case 0xE0 ... 0xE7: /* FSUB %st(?),%st(0) */
sewardjbdc7d212004-09-09 02:46:40 +00003877 fp_do_op_ST_ST ( "sub", Iop_SubF64, modrm - 0xE0, 0, False );
sewardj89cd0932004-09-08 18:23:25 +00003878 break;
3879
sewardj8308aad2004-09-12 11:09:54 +00003880 case 0xE8 ... 0xEF: /* FSUBR %st(?),%st(0) */
3881 fp_do_oprev_ST_ST ( "subr", Iop_SubF64, modrm - 0xE8, 0, False );
3882 break;
3883
sewardj3fd5e572004-09-09 22:43:51 +00003884 case 0xF0 ... 0xF7: /* FDIV %st(?),%st(0) */
3885 fp_do_op_ST_ST ( "div", Iop_DivF64, modrm - 0xF0, 0, False );
3886 break;
3887
3888 case 0xF8 ... 0xFF: /* FDIVR %st(?),%st(0) */
3889 fp_do_oprev_ST_ST ( "divr", Iop_DivF64, modrm - 0xF8, 0, False );
3890 break;
3891
sewardjdb199622004-09-06 23:19:03 +00003892 default:
3893 goto decode_fail;
3894 }
3895 }
sewardjd1725d12004-08-12 20:46:53 +00003896 }
3897
3898 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xD9 opcodes +-+-+-+-+-+-+-+ */
3899 else
3900 if (first_opcode == 0xD9) {
sewardjbb53f8c2004-08-14 11:50:01 +00003901 if (modrm < 0xC0) {
sewardj89cd0932004-09-08 18:23:25 +00003902
3903 /* bits 5,4,3 are an opcode extension, and the modRM also
sewardjfeeb8a82004-11-30 12:30:11 +00003904 specifies an address. */
sewardj89cd0932004-09-08 18:23:25 +00003905 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
3906 delta += len;
3907
3908 switch (gregOfRM(modrm)) {
3909
3910 case 0: /* FLD single-real */
3911 DIP("fldF %s\n", dis_buf);
3912 fp_push();
3913 put_ST(0, unop(Iop_F32toF64,
sewardj8f3debf2004-09-08 23:42:23 +00003914 loadLE(Ity_F32, mkexpr(addr))));
sewardj89cd0932004-09-08 18:23:25 +00003915 break;
3916
sewardj588ea762004-09-10 18:56:32 +00003917 case 2: /* FST single-real */
3918 DIP("fstS %s", dis_buf);
sewardj3bca9062004-12-04 14:36:09 +00003919 storeLE(mkexpr(addr),
3920 binop(Iop_F64toF32, get_roundingmode(), get_ST(0)));
sewardj588ea762004-09-10 18:56:32 +00003921 break;
3922
sewardj89cd0932004-09-08 18:23:25 +00003923 case 3: /* FSTP single-real */
3924 DIP("fstpS %s", dis_buf);
sewardj3bca9062004-12-04 14:36:09 +00003925 storeLE(mkexpr(addr),
3926 binop(Iop_F64toF32, get_roundingmode(), get_ST(0)));
sewardj5bd4d162004-11-10 13:02:48 +00003927 fp_pop();
sewardj89cd0932004-09-08 18:23:25 +00003928 break;
3929
sewardj893aada2004-11-29 19:57:54 +00003930 case 5: {/* FLDCW */
3931 /* The only thing we observe in the control word is the
sewardjd01a9632004-11-30 13:18:37 +00003932 rounding mode. Therefore, pass the 16-bit value
3933 (x87 native-format control word) to a clean helper,
3934 getting back a 64-bit value, the lower half of which
3935 is the FPROUND value to store, and the upper half of
3936 which is the emulation-warning token which may be
3937 generated.
sewardj893aada2004-11-29 19:57:54 +00003938 */
3939 /* ULong x86h_check_fldcw ( UInt ); */
3940 IRTemp t64 = newTemp(Ity_I64);
3941 IRTemp ew = newTemp(Ity_I32);
sewardj8f3debf2004-09-08 23:42:23 +00003942 DIP("fldcw %s", dis_buf);
sewardj893aada2004-11-29 19:57:54 +00003943 assign( t64, mkIRExprCCall(
3944 Ity_I64, 0/*regparms*/,
3945 "x86h_check_fldcw",
3946 &x86h_check_fldcw,
3947 mkIRExprVec_1(
3948 unop( Iop_16Uto32,
3949 loadLE(Ity_I16, mkexpr(addr)))
3950 )
3951 )
3952 );
3953
sewardjd01a9632004-11-30 13:18:37 +00003954 put_fpround( unop(Iop_64to32, mkexpr(t64)) );
sewardj893aada2004-11-29 19:57:54 +00003955 assign( ew, unop(Iop_64HIto32, mkexpr(t64) ) );
3956 put_emwarn( mkexpr(ew) );
3957 /* Finally, if an emulation warning was reported,
3958 side-exit to the next insn, reporting the warning,
3959 so that Valgrind's dispatcher sees the warning. */
3960 stmt(
3961 IRStmt_Exit(
3962 binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
3963 Ijk_EmWarn,
3964 IRConst_U32( ((Addr32)guest_eip_bbstart)+delta)
3965 )
3966 );
sewardj89cd0932004-09-08 18:23:25 +00003967 break;
sewardj893aada2004-11-29 19:57:54 +00003968 }
sewardj89cd0932004-09-08 18:23:25 +00003969
sewardj588ea762004-09-10 18:56:32 +00003970 case 7: /* FNSTCW */
sewardj893aada2004-11-29 19:57:54 +00003971 /* Fake up a native x87 FPU control word. The only
sewardjd01a9632004-11-30 13:18:37 +00003972 thing it depends on is FPROUND[1:0], so call a clean
sewardj893aada2004-11-29 19:57:54 +00003973 helper to cook it up. */
sewardjd01a9632004-11-30 13:18:37 +00003974 /* UInt x86h_create_fpucw ( UInt fpround ) */
sewardj588ea762004-09-10 18:56:32 +00003975 DIP("fnstcw %s", dis_buf);
sewardj893aada2004-11-29 19:57:54 +00003976 storeLE(
3977 mkexpr(addr),
3978 unop( Iop_32to16,
3979 mkIRExprCCall(
3980 Ity_I32, 0/*regp*/,
3981 "x86h_create_fpucw", &x86h_create_fpucw,
sewardjd01a9632004-11-30 13:18:37 +00003982 mkIRExprVec_1( get_fpround() )
sewardj893aada2004-11-29 19:57:54 +00003983 )
3984 )
3985 );
sewardj89cd0932004-09-08 18:23:25 +00003986 break;
3987
3988 default:
3989 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
3990 vex_printf("first_opcode == 0xD9\n");
3991 goto decode_fail;
3992 }
3993
sewardjbb53f8c2004-08-14 11:50:01 +00003994 } else {
3995 delta++;
3996 switch (modrm) {
sewardj89cd0932004-09-08 18:23:25 +00003997
sewardjbb53f8c2004-08-14 11:50:01 +00003998 case 0xC0 ... 0xC7: /* FLD %st(?) */
sewardja58ea662004-08-15 03:12:41 +00003999 r_src = (UInt)modrm - 0xC0;
4000 DIP("fld %%st(%d)\n", r_src);
sewardj5bd4d162004-11-10 13:02:48 +00004001 t1 = newTemp(Ity_F64);
4002 assign(t1, get_ST(r_src));
4003 fp_push();
4004 put_ST(0, mkexpr(t1));
sewardjbb53f8c2004-08-14 11:50:01 +00004005 break;
4006
sewardj89cd0932004-09-08 18:23:25 +00004007 case 0xC8 ... 0xCF: /* FXCH %st(?) */
4008 r_src = (UInt)modrm - 0xC8;
4009 DIP("fxch %%st(%d)\n", r_src);
4010 t1 = newTemp(Ity_F64);
4011 t2 = newTemp(Ity_F64);
4012 assign(t1, get_ST(0));
4013 assign(t2, get_ST(r_src));
4014 put_ST_UNCHECKED(0, mkexpr(t2));
4015 put_ST_UNCHECKED(r_src, mkexpr(t1));
4016 break;
4017
sewardjcfded9a2004-09-09 11:44:16 +00004018 case 0xE0: /* FCHS */
4019 DIP("fchs\n");
4020 put_ST_UNCHECKED(0, unop(Iop_NegF64, get_ST(0)));
4021 break;
4022
sewardj883b00b2004-09-11 09:30:24 +00004023 case 0xE1: /* FABS */
4024 DIP("fabs\n");
4025 put_ST_UNCHECKED(0, unop(Iop_AbsF64, get_ST(0)));
4026 break;
sewardjc4be80c2004-09-10 16:17:45 +00004027
sewardj883b00b2004-09-11 09:30:24 +00004028 case 0xE5: { /* FXAM */
4029 /* This is an interesting one. It examines %st(0),
4030 regardless of whether the tag says it's empty or not.
4031 Here, just pass both the tag (in our format) and the
4032 value (as a double, actually a ULong) to a helper
4033 function. */
sewardjf9655262004-10-31 20:02:16 +00004034 IRExpr** args
4035 = mkIRExprVec_2( unop(Iop_8Uto32, get_ST_TAG(0)),
4036 unop(Iop_ReinterpF64asI64,
4037 get_ST_UNCHECKED(0)) );
4038 put_C3210(mkIRExprCCall(
sewardj8ea867b2004-10-30 19:03:02 +00004039 Ity_I32,
sewardjf9655262004-10-31 20:02:16 +00004040 0/*regparm*/,
sewardj2a9ad022004-11-25 02:46:58 +00004041 "x86g_calculate_FXAM", &x86g_calculate_FXAM,
sewardj8ea867b2004-10-30 19:03:02 +00004042 args
4043 ));
sewardjf9655262004-10-31 20:02:16 +00004044 DIP("fxam");
sewardj883b00b2004-09-11 09:30:24 +00004045 break;
4046 }
4047
4048 case 0xE8: /* FLD1 */
sewardjdb199622004-09-06 23:19:03 +00004049 DIP("fld1");
sewardjce646f22004-08-31 23:55:54 +00004050 fp_push();
4051 put_ST(0, IRExpr_Const(IRConst_F64(1.0)));
4052 break;
4053
sewardj37158712004-10-15 21:23:12 +00004054 case 0xE9: /* FLDL2T */
4055 DIP("fldl2t");
4056 fp_push();
4057 put_ST(0, IRExpr_Const(IRConst_F64(3.32192809488736234781)));
4058 break;
4059
sewardj8308aad2004-09-12 11:09:54 +00004060 case 0xEA: /* FLDL2E */
4061 DIP("fldl2e");
4062 fp_push();
4063 put_ST(0, IRExpr_Const(IRConst_F64(1.44269504088896340739)));
4064 break;
4065
sewardja0d48d62004-09-20 21:19:03 +00004066 case 0xEB: /* FLDPI */
4067 DIP("fldpi");
4068 fp_push();
4069 put_ST(0, IRExpr_Const(IRConst_F64(3.14159265358979323851)));
4070 break;
4071
sewardjdb199622004-09-06 23:19:03 +00004072 case 0xEC: /* FLDLG2 */
4073 DIP("fldlg2");
4074 fp_push();
4075 put_ST(0, IRExpr_Const(IRConst_F64(0.301029995663981143)));
4076 break;
4077
4078 case 0xED: /* FLDLN2 */
4079 DIP("fldln2");
4080 fp_push();
4081 put_ST(0, IRExpr_Const(IRConst_F64(0.69314718055994530942)));
4082 break;
4083
sewardja58ea662004-08-15 03:12:41 +00004084 case 0xEE: /* FLDZ */
4085 DIP("fldz");
sewardj207557a2004-08-27 12:00:18 +00004086 fp_push();
4087 put_ST(0, IRExpr_Const(IRConst_F64(0.0)));
sewardja58ea662004-08-15 03:12:41 +00004088 break;
4089
sewardj06c32a02004-09-12 12:07:34 +00004090 case 0xF0: /* F2XM1 */
4091 DIP("f2xm1\n");
4092 put_ST_UNCHECKED(0, unop(Iop_2xm1F64, get_ST(0)));
4093 break;
4094
sewardj52ace3e2004-09-11 17:10:08 +00004095 case 0xF1: /* FYL2X */
4096 DIP("fyl2x\n");
4097 put_ST_UNCHECKED(1, binop(Iop_Yl2xF64,
4098 get_ST(1), get_ST(0)));
4099 fp_pop();
4100 break;
4101
sewardj99016a72004-10-15 22:09:17 +00004102 case 0xF2: /* FPTAN */
4103 DIP("ftan\n");
4104 put_ST_UNCHECKED(0, unop(Iop_TanF64, get_ST(0)));
4105 fp_push();
4106 put_ST(0, IRExpr_Const(IRConst_F64(1.0)));
sewardj3f61ddb2004-10-16 20:51:05 +00004107 clear_C2(); /* HACK */
sewardj99016a72004-10-15 22:09:17 +00004108 break;
4109
sewardjcfded9a2004-09-09 11:44:16 +00004110 case 0xF3: /* FPATAN */
4111 DIP("fpatan\n");
sewardj52ace3e2004-09-11 17:10:08 +00004112 put_ST_UNCHECKED(1, binop(Iop_AtanF64,
sewardjcfded9a2004-09-09 11:44:16 +00004113 get_ST(1), get_ST(0)));
4114 fp_pop();
4115 break;
4116
sewardj442d0be2004-10-15 22:57:13 +00004117 case 0xF5: { /* FPREM1 -- IEEE compliant */
4118 IRTemp a1 = newTemp(Ity_F64);
4119 IRTemp a2 = newTemp(Ity_F64);
4120 DIP("fprem1\n");
4121 /* Do FPREM1 twice, once to get the remainder, and once
4122 to get the C3210 flag values. */
4123 assign( a1, get_ST(0) );
4124 assign( a2, get_ST(1) );
4125 put_ST_UNCHECKED(0, binop(Iop_PRem1F64,
4126 mkexpr(a1), mkexpr(a2)));
4127 put_C3210( binop(Iop_PRem1C3210F64, mkexpr(a1), mkexpr(a2)) );
4128 break;
4129 }
4130
sewardjfeeb8a82004-11-30 12:30:11 +00004131 case 0xF7: /* FINCSTP */
4132 DIP("fprem\n");
4133 put_ftop( binop(Iop_Add32, get_ftop(), mkU32(1)) );
4134 break;
4135
sewardj46de4072004-09-11 19:23:24 +00004136 case 0xF8: { /* FPREM -- not IEEE compliant */
4137 IRTemp a1 = newTemp(Ity_F64);
4138 IRTemp a2 = newTemp(Ity_F64);
4139 DIP("fprem\n");
4140 /* Do FPREM twice, once to get the remainder, and once
4141 to get the C3210 flag values. */
4142 assign( a1, get_ST(0) );
4143 assign( a2, get_ST(1) );
4144 put_ST_UNCHECKED(0, binop(Iop_PRemF64,
4145 mkexpr(a1), mkexpr(a2)));
4146 put_C3210( binop(Iop_PRemC3210F64, mkexpr(a1), mkexpr(a2)) );
4147 break;
4148 }
4149
sewardj8308aad2004-09-12 11:09:54 +00004150 case 0xF9: /* FYL2XP1 */
4151 DIP("fyl2xp1\n");
4152 put_ST_UNCHECKED(1, binop(Iop_Yl2xp1F64,
4153 get_ST(1), get_ST(0)));
4154 fp_pop();
4155 break;
4156
sewardjc4be80c2004-09-10 16:17:45 +00004157 case 0xFA: /* FSQRT */
4158 DIP("fsqrt\n");
4159 put_ST_UNCHECKED(0, unop(Iop_SqrtF64, get_ST(0)));
4160 break;
4161
sewardje6709112004-09-10 18:37:18 +00004162 case 0xFC: /* FRNDINT */
4163 DIP("frndint\n");
4164 put_ST_UNCHECKED(0,
4165 binop(Iop_RoundF64, get_roundingmode(), get_ST(0)) );
4166 break;
4167
sewardj06c32a02004-09-12 12:07:34 +00004168 case 0xFD: /* FSCALE */
4169 DIP("fscale\n");
4170 put_ST_UNCHECKED(0, binop(Iop_ScaleF64,
4171 get_ST(0), get_ST(1)));
4172 break;
4173
sewardjcfded9a2004-09-09 11:44:16 +00004174 case 0xFE: /* FSIN */
4175 DIP("fsin\n");
4176 put_ST_UNCHECKED(0, unop(Iop_SinF64, get_ST(0)));
sewardj3f61ddb2004-10-16 20:51:05 +00004177 clear_C2(); /* HACK */
sewardjcfded9a2004-09-09 11:44:16 +00004178 break;
4179
4180 case 0xFF: /* FCOS */
4181 DIP("fcos\n");
4182 put_ST_UNCHECKED(0, unop(Iop_CosF64, get_ST(0)));
sewardj3f61ddb2004-10-16 20:51:05 +00004183 clear_C2(); /* HACK */
sewardjcfded9a2004-09-09 11:44:16 +00004184 break;
4185
sewardjbb53f8c2004-08-14 11:50:01 +00004186 default:
4187 goto decode_fail;
4188 }
4189 }
sewardjd1725d12004-08-12 20:46:53 +00004190 }
4191
4192 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDA opcodes +-+-+-+-+-+-+-+ */
4193 else
4194 if (first_opcode == 0xDA) {
sewardjbb53f8c2004-08-14 11:50:01 +00004195
4196 if (modrm < 0xC0) {
4197
sewardjfeeb8a82004-11-30 12:30:11 +00004198 /* bits 5,4,3 are an opcode extension, and the modRM also
sewardjbb53f8c2004-08-14 11:50:01 +00004199 specifies an address. */
sewardjce646f22004-08-31 23:55:54 +00004200 IROp fop;
sewardjbb53f8c2004-08-14 11:50:01 +00004201 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
4202 delta += len;
sewardjbb53f8c2004-08-14 11:50:01 +00004203 switch (gregOfRM(modrm)) {
sewardjce646f22004-08-31 23:55:54 +00004204
sewardjdb199622004-09-06 23:19:03 +00004205 case 0: /* FIADD m32int */ /* ST(0) += m32int */
4206 DIP("fiaddl %s", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00004207 fop = Iop_AddF64;
4208 goto do_fop_m32;
sewardjdb199622004-09-06 23:19:03 +00004209
sewardj207557a2004-08-27 12:00:18 +00004210 case 1: /* FIMUL m32int */ /* ST(0) *= m32int */
sewardjbb53f8c2004-08-14 11:50:01 +00004211 DIP("fimull %s", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00004212 fop = Iop_MulF64;
4213 goto do_fop_m32;
sewardjce646f22004-08-31 23:55:54 +00004214
4215 case 4: /* FISUB m32int */ /* ST(0) -= m32int */
4216 DIP("fisubl %s", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00004217 fop = Iop_SubF64;
4218 goto do_fop_m32;
sewardjce646f22004-08-31 23:55:54 +00004219
sewardj8308aad2004-09-12 11:09:54 +00004220 case 5: /* FISUBR m32int */ /* ST(0) = m32int - ST(0) */
4221 DIP("fisubrl %s", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00004222 fop = Iop_SubF64;
4223 goto do_foprev_m32;
sewardj8308aad2004-09-12 11:09:54 +00004224
sewardjce646f22004-08-31 23:55:54 +00004225 case 6: /* FIDIV m32int */ /* ST(0) /= m32int */
4226 DIP("fisubl %s", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00004227 fop = Iop_DivF64;
4228 goto do_fop_m32;
sewardjce646f22004-08-31 23:55:54 +00004229
sewardjc4eaff32004-09-10 20:25:11 +00004230 case 7: /* FIDIVR m32int */ /* ST(0) = m32int / ST(0) */
sewardj8308aad2004-09-12 11:09:54 +00004231 DIP("fidivrl %s", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00004232 fop = Iop_DivF64;
4233 goto do_foprev_m32;
sewardjc4eaff32004-09-10 20:25:11 +00004234
sewardjce646f22004-08-31 23:55:54 +00004235 do_fop_m32:
sewardj207557a2004-08-27 12:00:18 +00004236 put_ST_UNCHECKED(0,
sewardjce646f22004-08-31 23:55:54 +00004237 binop(fop,
sewardj207557a2004-08-27 12:00:18 +00004238 get_ST(0),
sewardj89cd0932004-09-08 18:23:25 +00004239 unop(Iop_I32toF64,
4240 loadLE(Ity_I32, mkexpr(addr)))));
sewardjbb53f8c2004-08-14 11:50:01 +00004241 break;
4242
sewardjc4eaff32004-09-10 20:25:11 +00004243 do_foprev_m32:
4244 put_ST_UNCHECKED(0,
4245 binop(fop,
4246 unop(Iop_I32toF64,
4247 loadLE(Ity_I32, mkexpr(addr))),
4248 get_ST(0)));
4249 break;
4250
sewardjbb53f8c2004-08-14 11:50:01 +00004251 default:
4252 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
4253 vex_printf("first_opcode == 0xDA\n");
4254 goto decode_fail;
4255 }
sewardj4cb918d2004-12-03 19:43:31 +00004256
sewardjbb53f8c2004-08-14 11:50:01 +00004257 } else {
sewardjbdc7d212004-09-09 02:46:40 +00004258
4259 delta++;
4260 switch (modrm) {
4261
sewardj3fd5e572004-09-09 22:43:51 +00004262 case 0xC8 ... 0xCF: /* FCMOVE(Z) ST(i), ST(0) */
4263 r_src = (UInt)modrm - 0xC8;
sewardj5bd4d162004-11-10 13:02:48 +00004264 DIP("fcmovz %%st(%d), %%st(0)", r_src);
4265 put_ST_UNCHECKED(0,
sewardj3fd5e572004-09-09 22:43:51 +00004266 IRExpr_Mux0X(
sewardj2a9ad022004-11-25 02:46:58 +00004267 unop(Iop_1Uto8,
4268 mk_x86g_calculate_condition(X86CondZ)),
sewardj3fd5e572004-09-09 22:43:51 +00004269 get_ST(0), get_ST(r_src)) );
4270 break;
4271
sewardjbdc7d212004-09-09 02:46:40 +00004272 case 0xE9: /* FUCOMPP %st(0),%st(1) */
4273 DIP("fucompp %%st(0),%%st(1)\n");
sewardjc4be80c2004-09-10 16:17:45 +00004274 /* This forces C1 to zero, which isn't right. */
4275 put_C3210(
4276 binop( Iop_And32,
4277 binop(Iop_Shl32,
4278 binop(Iop_CmpF64, get_ST(0), get_ST(1)),
4279 mkU8(8)),
4280 mkU32(0x4500)
4281 ));
sewardjbdc7d212004-09-09 02:46:40 +00004282 fp_pop();
4283 fp_pop();
4284 break;
4285
sewardj5bd4d162004-11-10 13:02:48 +00004286 default:
sewardjbdc7d212004-09-09 02:46:40 +00004287 goto decode_fail;
sewardj5bd4d162004-11-10 13:02:48 +00004288 }
sewardjbdc7d212004-09-09 02:46:40 +00004289
sewardjbb53f8c2004-08-14 11:50:01 +00004290 }
sewardjd1725d12004-08-12 20:46:53 +00004291 }
4292
4293 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDB opcodes +-+-+-+-+-+-+-+ */
4294 else
4295 if (first_opcode == 0xDB) {
sewardj89cd0932004-09-08 18:23:25 +00004296 if (modrm < 0xC0) {
4297
sewardjfeeb8a82004-11-30 12:30:11 +00004298 /* bits 5,4,3 are an opcode extension, and the modRM also
sewardj89cd0932004-09-08 18:23:25 +00004299 specifies an address. */
4300 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
4301 delta += len;
4302
4303 switch (gregOfRM(modrm)) {
4304
4305 case 0: /* FILD m32int */
4306 DIP("fildl %s\n", dis_buf);
4307 fp_push();
4308 put_ST(0, unop(Iop_I32toF64,
4309 loadLE(Ity_I32, mkexpr(addr))));
4310 break;
4311
sewardj8f3debf2004-09-08 23:42:23 +00004312 case 2: /* FIST m32 */
4313 DIP("fistl %s", dis_buf);
4314 storeLE( mkexpr(addr),
4315 binop(Iop_F64toI32, get_roundingmode(), get_ST(0)) );
4316 break;
4317
sewardj89cd0932004-09-08 18:23:25 +00004318 case 3: /* FISTP m32 */
4319 DIP("fistpl %s", dis_buf);
sewardj8f3debf2004-09-08 23:42:23 +00004320 storeLE( mkexpr(addr),
4321 binop(Iop_F64toI32, get_roundingmode(), get_ST(0)) );
sewardj5bd4d162004-11-10 13:02:48 +00004322 fp_pop();
sewardj89cd0932004-09-08 18:23:25 +00004323 break;
sewardj17442fe2004-09-20 14:54:28 +00004324
sewardjb3bce0e2004-09-14 23:20:10 +00004325 case 5: { /* FLD extended-real */
sewardj7cb49d72004-10-24 22:31:25 +00004326 /* Uses dirty helper:
4327 ULong loadF80le ( VexGuestX86State*, UInt )
4328 addr holds the address. First, do a dirty call to
sewardjb3bce0e2004-09-14 23:20:10 +00004329 get hold of the data. */
sewardjc5fc7aa2004-10-27 23:00:55 +00004330 IRTemp val = newTemp(Ity_I64);
4331 IRExpr** args = mkIRExprVec_1 ( mkexpr(addr) );
4332
sewardj8ea867b2004-10-30 19:03:02 +00004333 IRDirty* d = unsafeIRDirty_1_N (
4334 val,
sewardj2a9ad022004-11-25 02:46:58 +00004335 0/*regparms*/,
4336 "x86g_loadF80le", &x86g_loadF80le,
sewardj8ea867b2004-10-30 19:03:02 +00004337 args
4338 );
sewardjb3bce0e2004-09-14 23:20:10 +00004339 /* declare that we're reading memory */
4340 d->mFx = Ifx_Read;
sewardj17442fe2004-09-20 14:54:28 +00004341 d->mAddr = mkexpr(addr);
sewardjb3bce0e2004-09-14 23:20:10 +00004342 d->mSize = 10;
sewardjc5fc7aa2004-10-27 23:00:55 +00004343
4344 /* execute the dirty call, dumping the result in val. */
sewardjb3bce0e2004-09-14 23:20:10 +00004345 stmt( IRStmt_Dirty(d) );
4346 fp_push();
sewardjc5fc7aa2004-10-27 23:00:55 +00004347 put_ST(0, unop(Iop_ReinterpI64asF64, mkexpr(val)));
4348
4349 DIP("fldt %s", dis_buf);
sewardjb3bce0e2004-09-14 23:20:10 +00004350 break;
4351 }
sewardj17442fe2004-09-20 14:54:28 +00004352
4353 case 7: { /* FSTP extended-real */
sewardj9fc9e782004-11-26 17:57:40 +00004354 /* Uses dirty helper: void x86g_storeF80le ( UInt, ULong ) */
sewardjc5fc7aa2004-10-27 23:00:55 +00004355 IRExpr** args
4356 = mkIRExprVec_2( mkexpr(addr),
4357 unop(Iop_ReinterpF64asI64, get_ST(0)) );
4358
sewardj8ea867b2004-10-30 19:03:02 +00004359 IRDirty* d = unsafeIRDirty_0_N (
sewardjf9655262004-10-31 20:02:16 +00004360 0/*regparms*/,
sewardj2a9ad022004-11-25 02:46:58 +00004361 "x86g_storeF80le", &x86g_storeF80le,
sewardj8ea867b2004-10-30 19:03:02 +00004362 args
4363 );
sewardj17442fe2004-09-20 14:54:28 +00004364 /* declare we're writing memory */
4365 d->mFx = Ifx_Write;
4366 d->mAddr = mkexpr(addr);
4367 d->mSize = 10;
sewardjc5fc7aa2004-10-27 23:00:55 +00004368
sewardj17442fe2004-09-20 14:54:28 +00004369 /* execute the dirty call. */
4370 stmt( IRStmt_Dirty(d) );
4371 fp_pop();
sewardjc5fc7aa2004-10-27 23:00:55 +00004372
4373 DIP("fstpt %s", dis_buf);
sewardj17442fe2004-09-20 14:54:28 +00004374 break;
4375 }
4376
sewardjb3bce0e2004-09-14 23:20:10 +00004377 default:
sewardj89cd0932004-09-08 18:23:25 +00004378 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
4379 vex_printf("first_opcode == 0xDB\n");
4380 goto decode_fail;
4381 }
4382
4383 } else {
sewardj8308aad2004-09-12 11:09:54 +00004384
4385 delta++;
4386 switch (modrm) {
4387
sewardj4e82db72004-10-16 11:32:15 +00004388 case 0xC8 ... 0xCF: /* FCMOVNE(NZ) ST(i), ST(0) */
4389 r_src = (UInt)modrm - 0xC8;
sewardj5bd4d162004-11-10 13:02:48 +00004390 DIP("fcmovnz %%st(%d), %%st(0)", r_src);
4391 put_ST_UNCHECKED(0,
sewardj4e82db72004-10-16 11:32:15 +00004392 IRExpr_Mux0X(
sewardj2a9ad022004-11-25 02:46:58 +00004393 unop(Iop_1Uto8,
4394 mk_x86g_calculate_condition(X86CondNZ)),
sewardj4e82db72004-10-16 11:32:15 +00004395 get_ST(0), get_ST(r_src)) );
4396 break;
4397
sewardj8308aad2004-09-12 11:09:54 +00004398 case 0xE8 ... 0xEF: /* FUCOMI %st(0),%st(?) */
4399 fp_do_ucomi_ST0_STi( (UInt)modrm - 0xE8, False );
4400 break;
4401
sewardj37158712004-10-15 21:23:12 +00004402 case 0xF0 ... 0xF7: /* FCOMI %st(0),%st(?) */
4403 fp_do_ucomi_ST0_STi( (UInt)modrm - 0xF0, False );
4404 break;
4405
sewardj8308aad2004-09-12 11:09:54 +00004406 default:
4407 goto decode_fail;
sewardj17442fe2004-09-20 14:54:28 +00004408 }
sewardj89cd0932004-09-08 18:23:25 +00004409 }
sewardjd1725d12004-08-12 20:46:53 +00004410 }
4411
4412 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDC opcodes +-+-+-+-+-+-+-+ */
4413 else
4414 if (first_opcode == 0xDC) {
sewardja58ea662004-08-15 03:12:41 +00004415 if (modrm < 0xC0) {
4416
sewardj89cd0932004-09-08 18:23:25 +00004417 /* bits 5,4,3 are an opcode extension, and the modRM also
sewardjfeeb8a82004-11-30 12:30:11 +00004418 specifies an address. */
sewardja58ea662004-08-15 03:12:41 +00004419 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
4420 delta += len;
4421
4422 switch (gregOfRM(modrm)) {
4423
4424 case 0: /* FADD double-real */
4425 fp_do_op_mem_ST_0 ( addr, "add", dis_buf, Iop_AddF64, True );
4426 break;
4427
sewardjcfded9a2004-09-09 11:44:16 +00004428 case 1: /* FMUL double-real */
4429 fp_do_op_mem_ST_0 ( addr, "mul", dis_buf, Iop_MulF64, True );
4430 break;
4431
sewardje166ed02004-10-25 02:27:01 +00004432 case 2: /* FCOM double-real */
4433 DIP("fcoml %s\n", dis_buf);
4434 /* This forces C1 to zero, which isn't right. */
4435 put_C3210(
4436 binop( Iop_And32,
4437 binop(Iop_Shl32,
4438 binop(Iop_CmpF64,
4439 get_ST(0),
4440 loadLE(Ity_F64,mkexpr(addr))),
4441 mkU8(8)),
4442 mkU32(0x4500)
4443 ));
4444 break;
4445
sewardj883b00b2004-09-11 09:30:24 +00004446 case 3: /* FCOMP double-real */
sewardje166ed02004-10-25 02:27:01 +00004447 DIP("fcompl %s\n", dis_buf);
sewardj883b00b2004-09-11 09:30:24 +00004448 /* This forces C1 to zero, which isn't right. */
4449 put_C3210(
4450 binop( Iop_And32,
4451 binop(Iop_Shl32,
4452 binop(Iop_CmpF64,
4453 get_ST(0),
4454 loadLE(Ity_F64,mkexpr(addr))),
4455 mkU8(8)),
4456 mkU32(0x4500)
4457 ));
4458 fp_pop();
4459 break;
4460
sewardjcfded9a2004-09-09 11:44:16 +00004461 case 4: /* FSUB double-real */
4462 fp_do_op_mem_ST_0 ( addr, "sub", dis_buf, Iop_SubF64, True );
4463 break;
4464
sewardj3fd5e572004-09-09 22:43:51 +00004465 case 5: /* FSUBR double-real */
4466 fp_do_oprev_mem_ST_0 ( addr, "subr", dis_buf, Iop_SubF64, True );
4467 break;
4468
sewardjcfded9a2004-09-09 11:44:16 +00004469 case 6: /* FDIV double-real */
4470 fp_do_op_mem_ST_0 ( addr, "div", dis_buf, Iop_DivF64, True );
4471 break;
4472
sewardj883b00b2004-09-11 09:30:24 +00004473 case 7: /* FDIVR double-real */
4474 fp_do_oprev_mem_ST_0 ( addr, "divr", dis_buf, Iop_DivF64, True );
4475 break;
4476
sewardja58ea662004-08-15 03:12:41 +00004477 default:
4478 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
4479 vex_printf("first_opcode == 0xDC\n");
4480 goto decode_fail;
4481 }
4482
4483 } else {
sewardjbdc7d212004-09-09 02:46:40 +00004484
4485 delta++;
4486 switch (modrm) {
4487
sewardj3fd5e572004-09-09 22:43:51 +00004488 case 0xC0 ... 0xC7: /* FADD %st(0),%st(?) */
4489 fp_do_op_ST_ST ( "add", Iop_AddF64, 0, modrm - 0xC0, False );
4490 break;
4491
sewardjcfded9a2004-09-09 11:44:16 +00004492 case 0xC8 ... 0xCF: /* FMUL %st(0),%st(?) */
4493 fp_do_op_ST_ST ( "mul", Iop_MulF64, 0, modrm - 0xC8, False );
4494 break;
4495
sewardj47341042004-09-19 11:55:46 +00004496 case 0xE0 ... 0xE7: /* FSUBR %st(0),%st(?) */
4497 fp_do_oprev_ST_ST ( "subr", Iop_SubF64, 0, modrm - 0xE0, False );
4498 break;
4499
sewardjcfded9a2004-09-09 11:44:16 +00004500 case 0xE8 ... 0xEF: /* FSUB %st(0),%st(?) */
4501 fp_do_op_ST_ST ( "sub", Iop_SubF64, 0, modrm - 0xE8, False );
4502 break;
4503
sewardja0d48d62004-09-20 21:19:03 +00004504 case 0xF0 ... 0xF7: /* FDIVR %st(0),%st(?) */
4505 fp_do_oprev_ST_ST ( "divr", Iop_DivF64, 0, modrm - 0xF0, False );
4506 break;
4507
sewardjbdc7d212004-09-09 02:46:40 +00004508 case 0xF8 ... 0xFF: /* FDIV %st(0),%st(?) */
4509 fp_do_op_ST_ST ( "div", Iop_DivF64, 0, modrm - 0xF8, False );
4510 break;
4511
4512 default:
4513 goto decode_fail;
sewardj5bd4d162004-11-10 13:02:48 +00004514 }
sewardjbdc7d212004-09-09 02:46:40 +00004515
sewardja58ea662004-08-15 03:12:41 +00004516 }
sewardjd1725d12004-08-12 20:46:53 +00004517 }
4518
4519 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDD opcodes +-+-+-+-+-+-+-+ */
4520 else
4521 if (first_opcode == 0xDD) {
4522
4523 if (modrm < 0xC0) {
4524
sewardjfeeb8a82004-11-30 12:30:11 +00004525 /* bits 5,4,3 are an opcode extension, and the modRM also
sewardjd1725d12004-08-12 20:46:53 +00004526 specifies an address. */
sewardjbb53f8c2004-08-14 11:50:01 +00004527 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
4528 delta += len;
sewardjd1725d12004-08-12 20:46:53 +00004529
4530 switch (gregOfRM(modrm)) {
4531
4532 case 0: /* FLD double-real */
4533 DIP("fldD %s\n", dis_buf);
sewardj207557a2004-08-27 12:00:18 +00004534 fp_push();
4535 put_ST(0, IRExpr_LDle(Ity_F64, mkexpr(addr)));
sewardjbb53f8c2004-08-14 11:50:01 +00004536 break;
sewardjd1725d12004-08-12 20:46:53 +00004537
sewardjd1725d12004-08-12 20:46:53 +00004538 case 2: /* FST double-real */
sewardj89cd0932004-09-08 18:23:25 +00004539 DIP("fstD %s", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00004540 storeLE(mkexpr(addr), get_ST(0));
sewardjd1725d12004-08-12 20:46:53 +00004541 break;
sewardj89cd0932004-09-08 18:23:25 +00004542
sewardja58ea662004-08-15 03:12:41 +00004543 case 3: /* FSTP double-real */
4544 DIP("fstpD %s", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00004545 storeLE(mkexpr(addr), get_ST(0));
4546 fp_pop();
sewardja58ea662004-08-15 03:12:41 +00004547 break;
sewardjd1725d12004-08-12 20:46:53 +00004548
sewardj9fc9e782004-11-26 17:57:40 +00004549 case 4: { /* FRSTOR m108 */
sewardj893aada2004-11-29 19:57:54 +00004550 /* Uses dirty helper:
4551 VexEmWarn x86g_do_FRSTOR ( VexGuestX86State*, Addr32 ) */
4552 IRTemp ew = newTemp(Ity_I32);
4553 IRDirty* d = unsafeIRDirty_0_N (
4554 0/*regparms*/,
4555 "x86g_dirtyhelper_FRSTOR",
4556 &x86g_dirtyhelper_FRSTOR,
4557 mkIRExprVec_1( mkexpr(addr) )
4558 );
sewardj9fc9e782004-11-26 17:57:40 +00004559 d->needsBBP = True;
sewardj893aada2004-11-29 19:57:54 +00004560 d->tmp = ew;
sewardj9fc9e782004-11-26 17:57:40 +00004561 /* declare we're reading memory */
4562 d->mFx = Ifx_Read;
4563 d->mAddr = mkexpr(addr);
4564 d->mSize = 108;
4565
4566 /* declare we're writing guest state */
sewardj893aada2004-11-29 19:57:54 +00004567 d->nFxState = 5;
sewardj9fc9e782004-11-26 17:57:40 +00004568
4569 d->fxState[0].fx = Ifx_Write;
sewardjc9a43662004-11-30 18:51:59 +00004570 d->fxState[0].offset = OFFB_FTOP;
sewardj9fc9e782004-11-26 17:57:40 +00004571 d->fxState[0].size = sizeof(UInt);
4572
4573 d->fxState[1].fx = Ifx_Write;
sewardjc9a43662004-11-30 18:51:59 +00004574 d->fxState[1].offset = OFFB_FPREGS;
sewardj9fc9e782004-11-26 17:57:40 +00004575 d->fxState[1].size = 8 * sizeof(ULong);
4576
4577 d->fxState[2].fx = Ifx_Write;
sewardjc9a43662004-11-30 18:51:59 +00004578 d->fxState[2].offset = OFFB_FPTAGS;
sewardj9fc9e782004-11-26 17:57:40 +00004579 d->fxState[2].size = 8 * sizeof(UChar);
4580
4581 d->fxState[3].fx = Ifx_Write;
sewardjc9a43662004-11-30 18:51:59 +00004582 d->fxState[3].offset = OFFB_FPROUND;
sewardj9fc9e782004-11-26 17:57:40 +00004583 d->fxState[3].size = sizeof(UInt);
4584
4585 d->fxState[4].fx = Ifx_Write;
sewardjc9a43662004-11-30 18:51:59 +00004586 d->fxState[4].offset = OFFB_FC3210;
sewardj9fc9e782004-11-26 17:57:40 +00004587 d->fxState[4].size = sizeof(UInt);
4588
4589 stmt( IRStmt_Dirty(d) );
4590
sewardj893aada2004-11-29 19:57:54 +00004591 /* ew contains any emulation warning we may need to
4592 issue. If needed, side-exit to the next insn,
4593 reporting the warning, so that Valgrind's dispatcher
4594 sees the warning. */
4595 put_emwarn( mkexpr(ew) );
4596 stmt(
4597 IRStmt_Exit(
4598 binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
4599 Ijk_EmWarn,
4600 IRConst_U32( ((Addr32)guest_eip_bbstart)+delta)
4601 )
4602 );
4603
sewardj9fc9e782004-11-26 17:57:40 +00004604 DIP("frstor %s", dis_buf);
4605 break;
4606 }
4607
4608 case 6: { /* FNSAVE m108 */
sewardj893aada2004-11-29 19:57:54 +00004609 /* Uses dirty helper:
4610 void x86g_do_FSAVE ( VexGuestX86State*, UInt ) */
sewardj9fc9e782004-11-26 17:57:40 +00004611 IRDirty* d = unsafeIRDirty_0_N (
4612 0/*regparms*/,
4613 "x86g_dirtyhelper_FSAVE",
4614 &x86g_dirtyhelper_FSAVE,
4615 mkIRExprVec_1( mkexpr(addr) )
4616 );
4617 d->needsBBP = True;
4618 /* declare we're writing memory */
4619 d->mFx = Ifx_Write;
4620 d->mAddr = mkexpr(addr);
4621 d->mSize = 108;
4622
4623 /* declare we're reading guest state */
sewardj893aada2004-11-29 19:57:54 +00004624 d->nFxState = 5;
sewardj9fc9e782004-11-26 17:57:40 +00004625
4626 d->fxState[0].fx = Ifx_Read;
sewardjc9a43662004-11-30 18:51:59 +00004627 d->fxState[0].offset = OFFB_FTOP;
sewardj9fc9e782004-11-26 17:57:40 +00004628 d->fxState[0].size = sizeof(UInt);
4629
4630 d->fxState[1].fx = Ifx_Read;
sewardjc9a43662004-11-30 18:51:59 +00004631 d->fxState[1].offset = OFFB_FPREGS;
sewardj9fc9e782004-11-26 17:57:40 +00004632 d->fxState[1].size = 8 * sizeof(ULong);
4633
4634 d->fxState[2].fx = Ifx_Read;
sewardjc9a43662004-11-30 18:51:59 +00004635 d->fxState[2].offset = OFFB_FPTAGS;
sewardj9fc9e782004-11-26 17:57:40 +00004636 d->fxState[2].size = 8 * sizeof(UChar);
4637
4638 d->fxState[3].fx = Ifx_Read;
sewardjc9a43662004-11-30 18:51:59 +00004639 d->fxState[3].offset = OFFB_FPROUND;
sewardj9fc9e782004-11-26 17:57:40 +00004640 d->fxState[3].size = sizeof(UInt);
4641
4642 d->fxState[4].fx = Ifx_Read;
sewardjc9a43662004-11-30 18:51:59 +00004643 d->fxState[4].offset = OFFB_FC3210;
sewardj9fc9e782004-11-26 17:57:40 +00004644 d->fxState[4].size = sizeof(UInt);
4645
4646 stmt( IRStmt_Dirty(d) );
4647
4648 DIP("fnsave %s", dis_buf);
4649 break;
4650 }
4651
sewardjd1725d12004-08-12 20:46:53 +00004652 default:
sewardjbb53f8c2004-08-14 11:50:01 +00004653 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
4654 vex_printf("first_opcode == 0xDD\n");
sewardjd1725d12004-08-12 20:46:53 +00004655 goto decode_fail;
sewardjbb53f8c2004-08-14 11:50:01 +00004656 }
sewardjd1725d12004-08-12 20:46:53 +00004657 } else {
sewardja58ea662004-08-15 03:12:41 +00004658 delta++;
4659 switch (modrm) {
sewardjbdc7d212004-09-09 02:46:40 +00004660
sewardj06c32a02004-09-12 12:07:34 +00004661 case 0xD0 ... 0xD7: /* FST %st(0),%st(?) */
4662 r_dst = (UInt)modrm - 0xD0;
4663 DIP("fst %%st(0),%%st(%d)\n", r_dst);
sewardj5bd4d162004-11-10 13:02:48 +00004664 /* P4 manual says: "If the destination operand is a
sewardj06c32a02004-09-12 12:07:34 +00004665 non-empty register, the invalid-operation exception
4666 is not generated. Hence put_ST_UNCHECKED. */
4667 put_ST_UNCHECKED(r_dst, get_ST(0));
4668 break;
4669
sewardja58ea662004-08-15 03:12:41 +00004670 case 0xD8 ... 0xDF: /* FSTP %st(0),%st(?) */
4671 r_dst = (UInt)modrm - 0xD8;
4672 DIP("fstp %%st(0),%%st(%d)\n", r_dst);
sewardj5bd4d162004-11-10 13:02:48 +00004673 /* P4 manual says: "If the destination operand is a
sewardj207557a2004-08-27 12:00:18 +00004674 non-empty register, the invalid-operation exception
4675 is not generated. Hence put_ST_UNCHECKED. */
4676 put_ST_UNCHECKED(r_dst, get_ST(0));
4677 fp_pop();
sewardja58ea662004-08-15 03:12:41 +00004678 break;
sewardjbdc7d212004-09-09 02:46:40 +00004679
4680 case 0xE0 ... 0xE7: /* FUCOM %st(0),%st(?) */
4681 r_dst = (UInt)modrm - 0xE0;
4682 DIP("fucom %%st(0),%%st(%d)\n", r_dst);
sewardjc4be80c2004-09-10 16:17:45 +00004683 /* This forces C1 to zero, which isn't right. */
4684 put_C3210(
4685 binop( Iop_And32,
4686 binop(Iop_Shl32,
4687 binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
4688 mkU8(8)),
4689 mkU32(0x4500)
4690 ));
sewardjbdc7d212004-09-09 02:46:40 +00004691 break;
4692
4693 case 0xE8 ... 0xEF: /* FUCOMP %st(0),%st(?) */
4694 r_dst = (UInt)modrm - 0xE8;
4695 DIP("fucomp %%st(0),%%st(%d)\n", r_dst);
sewardjc4be80c2004-09-10 16:17:45 +00004696 /* This forces C1 to zero, which isn't right. */
4697 put_C3210(
4698 binop( Iop_And32,
4699 binop(Iop_Shl32,
4700 binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
4701 mkU8(8)),
4702 mkU32(0x4500)
4703 ));
sewardjbdc7d212004-09-09 02:46:40 +00004704 fp_pop();
4705 break;
4706
sewardj5bd4d162004-11-10 13:02:48 +00004707 default:
sewardja58ea662004-08-15 03:12:41 +00004708 goto decode_fail;
sewardj5bd4d162004-11-10 13:02:48 +00004709 }
sewardjd1725d12004-08-12 20:46:53 +00004710 }
4711 }
4712
4713 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDE opcodes +-+-+-+-+-+-+-+ */
4714 else
4715 if (first_opcode == 0xDE) {
sewardjbdc7d212004-09-09 02:46:40 +00004716
4717 if (modrm < 0xC0) {
sewardjfeeb8a82004-11-30 12:30:11 +00004718
4719 /* bits 5,4,3 are an opcode extension, and the modRM also
4720 specifies an address. */
4721 IROp fop;
4722 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
4723 delta += len;
4724
4725 switch (gregOfRM(modrm)) {
4726
4727 case 0: /* FIADD m16int */ /* ST(0) += m16int */
4728 DIP("fiaddw %s", dis_buf);
4729 fop = Iop_AddF64;
4730 goto do_fop_m16;
4731
4732 case 1: /* FIMUL m16int */ /* ST(0) *= m16int */
4733 DIP("fimulw %s", dis_buf);
4734 fop = Iop_MulF64;
4735 goto do_fop_m16;
4736
4737 case 4: /* FISUB m16int */ /* ST(0) -= m16int */
4738 DIP("fisubw %s", dis_buf);
4739 fop = Iop_SubF64;
4740 goto do_fop_m16;
4741
4742 case 5: /* FISUBR m16int */ /* ST(0) = m16int - ST(0) */
4743 DIP("fisubrw %s", dis_buf);
4744 fop = Iop_SubF64;
4745 goto do_foprev_m16;
4746
4747 case 6: /* FIDIV m16int */ /* ST(0) /= m16int */
4748 DIP("fisubw %s", dis_buf);
4749 fop = Iop_DivF64;
4750 goto do_fop_m16;
4751
4752 case 7: /* FIDIVR m16int */ /* ST(0) = m16int / ST(0) */
4753 DIP("fidivrw %s", dis_buf);
4754 fop = Iop_DivF64;
4755 goto do_foprev_m16;
4756
4757 do_fop_m16:
4758 put_ST_UNCHECKED(0,
4759 binop(fop,
4760 get_ST(0),
4761 unop(Iop_I32toF64,
4762 unop(Iop_16Sto32,
4763 loadLE(Ity_I16, mkexpr(addr))))));
4764 break;
4765
4766 do_foprev_m16:
4767 put_ST_UNCHECKED(0,
4768 binop(fop,
4769 unop(Iop_I32toF64,
4770 unop(Iop_16Sto32,
4771 loadLE(Ity_I16, mkexpr(addr)))),
4772 get_ST(0)));
4773 break;
4774
4775 default:
4776 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
4777 vex_printf("first_opcode == 0xDE\n");
4778 goto decode_fail;
4779 }
sewardjbdc7d212004-09-09 02:46:40 +00004780
4781 } else {
4782
4783 delta++;
sewardj5bd4d162004-11-10 13:02:48 +00004784 switch (modrm) {
sewardjbdc7d212004-09-09 02:46:40 +00004785
sewardjcfded9a2004-09-09 11:44:16 +00004786 case 0xC0 ... 0xC7: /* FADDP %st(0),%st(?) */
4787 fp_do_op_ST_ST ( "add", Iop_AddF64, 0, modrm - 0xC0, True );
4788 break;
4789
sewardjbdc7d212004-09-09 02:46:40 +00004790 case 0xC8 ... 0xCF: /* FMULP %st(0),%st(?) */
4791 fp_do_op_ST_ST ( "mul", Iop_MulF64, 0, modrm - 0xC8, True );
4792 break;
4793
sewardje166ed02004-10-25 02:27:01 +00004794 case 0xD9: /* FCOMPP %st(0),%st(1) */
4795 DIP("fuompp %%st(0),%%st(1)\n");
4796 /* This forces C1 to zero, which isn't right. */
4797 put_C3210(
4798 binop( Iop_And32,
4799 binop(Iop_Shl32,
4800 binop(Iop_CmpF64, get_ST(0), get_ST(1)),
4801 mkU8(8)),
4802 mkU32(0x4500)
4803 ));
4804 fp_pop();
4805 fp_pop();
4806 break;
4807
sewardjcfded9a2004-09-09 11:44:16 +00004808 case 0xE0 ... 0xE7: /* FSUBRP %st(0),%st(?) */
4809 fp_do_oprev_ST_ST ( "subr", Iop_SubF64, 0, modrm - 0xE0, True );
4810 break;
4811
sewardj3fd5e572004-09-09 22:43:51 +00004812 case 0xE8 ... 0xEF: /* FSUBP %st(0),%st(?) */
4813 fp_do_op_ST_ST ( "sub", Iop_SubF64, 0, modrm - 0xE8, True );
4814 break;
4815
sewardjbdc7d212004-09-09 02:46:40 +00004816 case 0xF0 ... 0xF7: /* FDIVRP %st(0),%st(?) */
4817 fp_do_oprev_ST_ST ( "divr", Iop_DivF64, 0, modrm - 0xF0, True );
4818 break;
4819
4820 case 0xF8 ... 0xFF: /* FDIVP %st(0),%st(?) */
4821 fp_do_op_ST_ST ( "div", Iop_DivF64, 0, modrm - 0xF8, True );
4822 break;
4823
4824 default:
4825 goto decode_fail;
sewardj5bd4d162004-11-10 13:02:48 +00004826 }
sewardjbdc7d212004-09-09 02:46:40 +00004827
4828 }
sewardjd1725d12004-08-12 20:46:53 +00004829 }
4830
4831 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDF opcodes +-+-+-+-+-+-+-+ */
4832 else
4833 if (first_opcode == 0xDF) {
sewardj89cd0932004-09-08 18:23:25 +00004834
4835 if (modrm < 0xC0) {
4836
sewardjfeeb8a82004-11-30 12:30:11 +00004837 /* bits 5,4,3 are an opcode extension, and the modRM also
sewardj89cd0932004-09-08 18:23:25 +00004838 specifies an address. */
4839 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
4840 delta += len;
4841
4842 switch (gregOfRM(modrm)) {
4843
sewardj883b00b2004-09-11 09:30:24 +00004844 case 0: /* FILD m16int */
4845 DIP("fildw %s\n", dis_buf);
4846 fp_push();
4847 put_ST(0, unop(Iop_I32toF64,
4848 unop(Iop_16Sto32,
4849 loadLE(Ity_I16, mkexpr(addr)))));
4850 break;
4851
sewardj37158712004-10-15 21:23:12 +00004852 case 2: /* FIST m16 */
4853 DIP("fistp %s", dis_buf);
4854 storeLE( mkexpr(addr),
4855 binop(Iop_F64toI16, get_roundingmode(), get_ST(0)) );
4856 break;
4857
sewardj89cd0932004-09-08 18:23:25 +00004858 case 3: /* FISTP m16 */
4859 DIP("fistps %s", dis_buf);
sewardj8f3debf2004-09-08 23:42:23 +00004860 storeLE( mkexpr(addr),
4861 binop(Iop_F64toI16, get_roundingmode(), get_ST(0)) );
4862 fp_pop();
sewardj89cd0932004-09-08 18:23:25 +00004863 break;
4864
sewardj89cd0932004-09-08 18:23:25 +00004865 case 5: /* FILD m64 */
4866 DIP("fildll %s\n", dis_buf);
4867 fp_push();
sewardj4cb918d2004-12-03 19:43:31 +00004868 put_ST(0, binop(Iop_I64toF64,
4869 get_roundingmode(),
4870 loadLE(Ity_I64, mkexpr(addr))));
sewardj89cd0932004-09-08 18:23:25 +00004871 break;
sewardj89cd0932004-09-08 18:23:25 +00004872
sewardjcfded9a2004-09-09 11:44:16 +00004873 case 7: /* FISTP m64 */
4874 DIP("fistpll %s", dis_buf);
4875 storeLE( mkexpr(addr),
4876 binop(Iop_F64toI64, get_roundingmode(), get_ST(0)) );
4877 fp_pop();
4878 break;
4879
sewardj89cd0932004-09-08 18:23:25 +00004880 default:
4881 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
4882 vex_printf("first_opcode == 0xDF\n");
4883 goto decode_fail;
4884 }
4885
4886 } else {
sewardjbdc7d212004-09-09 02:46:40 +00004887
4888 delta++;
sewardj5bd4d162004-11-10 13:02:48 +00004889 switch (modrm) {
sewardjbdc7d212004-09-09 02:46:40 +00004890
4891 case 0xE0: /* FNSTSW %ax */
4892 DIP("fnstsw %%ax\n");
4893 /* Invent a plausible-looking FPU status word value and
4894 dump it in %AX:
sewardjc4be80c2004-09-10 16:17:45 +00004895 ((ftop & 7) << 11) | (c3210 & 0x4700)
sewardjbdc7d212004-09-09 02:46:40 +00004896 */
4897 putIReg(2, R_EAX,
4898 unop(Iop_32to16,
4899 binop(Iop_Or32,
4900 binop(Iop_Shl32,
4901 binop(Iop_And32, get_ftop(), mkU32(7)),
4902 mkU8(11)),
sewardjc4be80c2004-09-10 16:17:45 +00004903 binop(Iop_And32, get_C3210(), mkU32(0x4700))
sewardjbdc7d212004-09-09 02:46:40 +00004904 )));
4905 break;
4906
sewardj883b00b2004-09-11 09:30:24 +00004907 case 0xE8 ... 0xEF: /* FUCOMIP %st(0),%st(?) */
sewardj8308aad2004-09-12 11:09:54 +00004908 fp_do_ucomi_ST0_STi( (UInt)modrm - 0xE8, True );
sewardj883b00b2004-09-11 09:30:24 +00004909 break;
4910
sewardjfeeb8a82004-11-30 12:30:11 +00004911 case 0xF0 ... 0xF7: /* FCOMIP %st(0),%st(?) */
4912 /* not really right since COMIP != UCOMIP */
4913 fp_do_ucomi_ST0_STi( (UInt)modrm - 0xF0, True );
4914 break;
4915
sewardjbdc7d212004-09-09 02:46:40 +00004916 default:
4917 goto decode_fail;
sewardj5bd4d162004-11-10 13:02:48 +00004918 }
sewardj89cd0932004-09-08 18:23:25 +00004919 }
4920
sewardjd1725d12004-08-12 20:46:53 +00004921 }
4922
4923 else
4924 vpanic("dis_FPU(x86): invalid primary opcode");
4925
sewardj69d9d662004-10-14 21:58:52 +00004926 *decode_ok = True;
4927 return delta;
4928
sewardjd1725d12004-08-12 20:46:53 +00004929 decode_fail:
4930 *decode_ok = False;
4931 return delta;
4932}
4933
4934
sewardj464efa42004-11-19 22:17:29 +00004935/*------------------------------------------------------------*/
4936/*--- ---*/
4937/*--- MMX INSTRUCTIONS ---*/
4938/*--- ---*/
4939/*------------------------------------------------------------*/
sewardja06e5562004-07-14 13:18:05 +00004940
sewardj464efa42004-11-19 22:17:29 +00004941/* Effect of MMX insns on x87 FPU state (table 11-2 of
4942 IA32 arch manual, volume 3):
4943
4944 Read from, or write to MMX register (viz, any insn except EMMS):
4945 * All tags set to Valid (non-empty) -- FPTAGS[i] := nonzero
4946 * FP stack pointer set to zero
4947
4948 EMMS:
4949 * All tags set to Invalid (empty) -- FPTAGS[i] := zero
4950 * FP stack pointer set to zero
4951*/
4952
sewardj4cb918d2004-12-03 19:43:31 +00004953static void do_MMX_preamble ( void )
sewardj464efa42004-11-19 22:17:29 +00004954{
4955 Int i;
4956 IRArray* descr = mkIRArray( OFFB_FPTAGS, Ity_I8, 8 );
4957 IRExpr* zero = mkU32(0);
4958 IRExpr* tag1 = mkU8(1);
4959 put_ftop(zero);
4960 for (i = 0; i < 8; i++)
4961 stmt( IRStmt_PutI( descr, zero, i, tag1 ) );
4962}
4963
sewardj4cb918d2004-12-03 19:43:31 +00004964static void do_EMMS_preamble ( void )
sewardj464efa42004-11-19 22:17:29 +00004965{
4966 Int i;
4967 IRArray* descr = mkIRArray( OFFB_FPTAGS, Ity_I8, 8 );
4968 IRExpr* zero = mkU32(0);
4969 IRExpr* tag0 = mkU8(0);
4970 put_ftop(zero);
4971 for (i = 0; i < 8; i++)
4972 stmt( IRStmt_PutI( descr, zero, i, tag0 ) );
4973}
4974
4975
4976static IRExpr* getMMXReg ( UInt archreg )
4977{
4978 vassert(archreg < 8);
4979 return IRExpr_Get( OFFB_FPREGS + 8 * archreg, Ity_I64 );
4980}
4981
4982
4983static void putMMXReg ( UInt archreg, IRExpr* e )
4984{
4985 vassert(archreg < 8);
4986 vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_I64);
4987 stmt( IRStmt_Put( OFFB_FPREGS + 8 * archreg, e ) );
4988}
4989
4990
4991static
4992UInt dis_MMXop_regmem_to_reg ( UChar sorb,
4993 UInt delta,
4994 UChar opc,
4995 Char* name,
4996 Bool show_granularity )
4997{
sewardjc9a43662004-11-30 18:51:59 +00004998 HChar dis_buf[50];
sewardj63ba4092004-11-21 12:30:18 +00004999 UChar modrm = getIByte(delta);
5000 Bool isReg = epartIsReg(modrm);
5001 IRExpr* argL = NULL;
5002 IRExpr* argR = NULL;
5003 IRTemp res = newTemp(Ity_I64);
sewardj464efa42004-11-19 22:17:29 +00005004
sewardj2b7a9202004-11-26 19:15:38 +00005005# define XXX(_name) do { hAddr = &_name; hName = #_name; } while (0)
sewardj464efa42004-11-19 22:17:29 +00005006
5007 void* hAddr = NULL;
5008 Char* hName = NULL;
5009 switch (opc) {
sewardjb5452082004-12-04 20:33:02 +00005010 /* Original MMX ones */
sewardj2a9ad022004-11-25 02:46:58 +00005011 case 0xFC: XXX(x86g_calculate_add8x8); break;
5012 case 0xFD: XXX(x86g_calculate_add16x4); break;
5013 case 0xFE: XXX(x86g_calculate_add32x2); break;
sewardj464efa42004-11-19 22:17:29 +00005014
sewardj2a9ad022004-11-25 02:46:58 +00005015 case 0xEC: XXX(x86g_calculate_qadd8Sx8); break;
5016 case 0xED: XXX(x86g_calculate_qadd16Sx4); break;
sewardj464efa42004-11-19 22:17:29 +00005017
sewardj2a9ad022004-11-25 02:46:58 +00005018 case 0xDC: XXX(x86g_calculate_qadd8Ux8); break;
5019 case 0xDD: XXX(x86g_calculate_qadd16Ux4); break;
sewardj464efa42004-11-19 22:17:29 +00005020
sewardj2a9ad022004-11-25 02:46:58 +00005021 case 0xF8: XXX(x86g_calculate_sub8x8); break;
5022 case 0xF9: XXX(x86g_calculate_sub16x4); break;
5023 case 0xFA: XXX(x86g_calculate_sub32x2); break;
sewardj464efa42004-11-19 22:17:29 +00005024
sewardj2a9ad022004-11-25 02:46:58 +00005025 case 0xE8: XXX(x86g_calculate_qsub8Sx8); break;
5026 case 0xE9: XXX(x86g_calculate_qsub16Sx4); break;
sewardj464efa42004-11-19 22:17:29 +00005027
sewardj2a9ad022004-11-25 02:46:58 +00005028 case 0xD8: XXX(x86g_calculate_qsub8Ux8); break;
5029 case 0xD9: XXX(x86g_calculate_qsub16Ux4); break;
sewardj464efa42004-11-19 22:17:29 +00005030
sewardj2a9ad022004-11-25 02:46:58 +00005031 case 0xE5: XXX(x86g_calculate_mulhi16x4); break;
5032 case 0xD5: XXX(x86g_calculate_mullo16x4); break;
5033 case 0xF5: XXX(x86g_calculate_pmaddwd); break;
sewardj4340dac2004-11-20 13:17:04 +00005034
sewardj2a9ad022004-11-25 02:46:58 +00005035 case 0x74: XXX(x86g_calculate_cmpeq8x8); break;
5036 case 0x75: XXX(x86g_calculate_cmpeq16x4); break;
5037 case 0x76: XXX(x86g_calculate_cmpeq32x2); break;
sewardj4340dac2004-11-20 13:17:04 +00005038
sewardj2a9ad022004-11-25 02:46:58 +00005039 case 0x64: XXX(x86g_calculate_cmpge8Sx8); break;
5040 case 0x65: XXX(x86g_calculate_cmpge16Sx4); break;
5041 case 0x66: XXX(x86g_calculate_cmpge32Sx2); break;
sewardj63ba4092004-11-21 12:30:18 +00005042
sewardj2a9ad022004-11-25 02:46:58 +00005043 case 0x6B: XXX(x86g_calculate_packssdw); break;
5044 case 0x63: XXX(x86g_calculate_packsswb); break;
5045 case 0x67: XXX(x86g_calculate_packuswb); break;
sewardj63ba4092004-11-21 12:30:18 +00005046
sewardj2a9ad022004-11-25 02:46:58 +00005047 case 0x68: XXX(x86g_calculate_punpckhbw); break;
5048 case 0x69: XXX(x86g_calculate_punpckhwd); break;
5049 case 0x6A: XXX(x86g_calculate_punpckhdq); break;
sewardj63ba4092004-11-21 12:30:18 +00005050
sewardj2a9ad022004-11-25 02:46:58 +00005051 case 0x60: XXX(x86g_calculate_punpcklbw); break;
5052 case 0x61: XXX(x86g_calculate_punpcklwd); break;
5053 case 0x62: XXX(x86g_calculate_punpckldq); break;
sewardj63ba4092004-11-21 12:30:18 +00005054
sewardj2a9ad022004-11-25 02:46:58 +00005055 case 0xF1: XXX(x86g_calculate_shl16x4); break;
5056 case 0xF2: XXX(x86g_calculate_shl32x2); break;
5057 case 0xF3: XXX(x86g_calculate_shl64x1); break;
sewardj8d14a592004-11-21 17:04:50 +00005058
sewardj2a9ad022004-11-25 02:46:58 +00005059 case 0xD1: XXX(x86g_calculate_shr16Ux4); break;
5060 case 0xD2: XXX(x86g_calculate_shr32Ux2); break;
5061 case 0xD3: XXX(x86g_calculate_shr64Ux1); break;
sewardj8d14a592004-11-21 17:04:50 +00005062
sewardj2a9ad022004-11-25 02:46:58 +00005063 case 0xE1: XXX(x86g_calculate_shr16Sx4); break;
5064 case 0xE2: XXX(x86g_calculate_shr32Sx2); break;
sewardj8d14a592004-11-21 17:04:50 +00005065
sewardj63ba4092004-11-21 12:30:18 +00005066 case 0xDB: break; /* AND */
5067 case 0xDF: break; /* ANDN */
5068 case 0xEB: break; /* OR */
5069 case 0xEF: break; /* XOR */
sewardj464efa42004-11-19 22:17:29 +00005070
sewardjb5452082004-12-04 20:33:02 +00005071 /* Introduced in SSE1 */
5072 case 0xE0: XXX(x86g_calculate_avg8Ux8); break;
5073 case 0xE3: XXX(x86g_calculate_avg16Ux4); break;
5074 case 0xEE: XXX(x86g_calculate_max16Sx4); break;
5075 case 0xDE: XXX(x86g_calculate_max8Ux8); break;
5076 case 0xEA: XXX(x86g_calculate_min16Sx4); break;
5077 case 0xDA: XXX(x86g_calculate_min8Ux8); break;
sewardj0bd7ce62004-12-05 02:47:40 +00005078 case 0xE4: XXX(x86g_calculate_mull16uHIx4); break;
5079 case 0xF6: XXX(x86g_calculate_psadbw); break;
sewardjb5452082004-12-04 20:33:02 +00005080
sewardj464efa42004-11-19 22:17:29 +00005081 default:
5082 vex_printf("\n0x%x\n", (Int)opc);
5083 vpanic("dis_MMXop_regmem_to_reg");
5084 }
5085
5086# undef XXX
5087
sewardj63ba4092004-11-21 12:30:18 +00005088 argL = getMMXReg(gregOfRM(modrm));
5089
sewardj464efa42004-11-19 22:17:29 +00005090 if (isReg) {
sewardj464efa42004-11-19 22:17:29 +00005091 delta++;
sewardj63ba4092004-11-21 12:30:18 +00005092 argR = getMMXReg(eregOfRM(modrm));
sewardj464efa42004-11-19 22:17:29 +00005093 } else {
5094 Int len;
5095 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5096 delta += len;
sewardj63ba4092004-11-21 12:30:18 +00005097 argR = loadLE(Ity_I64, mkexpr(addr));
sewardj464efa42004-11-19 22:17:29 +00005098 }
5099
sewardj63ba4092004-11-21 12:30:18 +00005100 switch (opc) {
5101 case 0xDB:
5102 assign(res, binop(Iop_And64, argL, argR) );
5103 break;
5104 case 0xDF:
sewardjb4acca52004-11-21 13:45:05 +00005105 assign(res, binop(Iop_And64, unop(Iop_Not64, argL), argR) );
sewardj63ba4092004-11-21 12:30:18 +00005106 break;
5107 case 0xEB:
5108 assign(res, binop(Iop_Or64, argL, argR) );
5109 break;
5110 case 0xEF:
5111 /* Possibly do better here if argL and argR are the same reg */
5112 assign(res, binop(Iop_Xor64, argL, argR) );
5113 break;
5114 default:
5115 vassert(hAddr);
5116 vassert(hName);
5117 assign( res,
5118 mkIRExprCCall(
5119 Ity_I64,
5120 0/*regparms*/, hName, hAddr,
5121 mkIRExprVec_2( argL, argR )
5122 )
5123 );
5124 break;
5125 }
5126
5127 putMMXReg( gregOfRM(modrm), mkexpr(res) );
5128
sewardj464efa42004-11-19 22:17:29 +00005129 DIP("%s%s %s, %s\n",
5130 name, show_granularity ? nameMMXGran(opc & 3) : (Char*)"",
5131 ( isReg ? nameMMXReg(eregOfRM(modrm)) : dis_buf ),
5132 nameMMXReg(gregOfRM(modrm)) );
5133
5134 return delta;
5135}
5136
5137
5138
5139static
5140UInt dis_MMX ( Bool* decode_ok, UChar sorb, Int sz, UInt delta )
5141{
5142 Int len;
5143 UChar modrm;
sewardjc9a43662004-11-30 18:51:59 +00005144 HChar dis_buf[50];
sewardj464efa42004-11-19 22:17:29 +00005145 UChar opc = getIByte(delta);
5146 delta++;
5147
sewardj4cb918d2004-12-03 19:43:31 +00005148 /* dis_MMX handles all insns except emms. */
5149 do_MMX_preamble();
sewardj464efa42004-11-19 22:17:29 +00005150
5151 switch (opc) {
5152
sewardj2b7a9202004-11-26 19:15:38 +00005153 case 0x6E:
5154 /* MOVD (src)ireg-or-mem (E), (dst)mmxreg (G)*/
5155 vassert(sz == 4);
5156 modrm = getIByte(delta);
5157 if (epartIsReg(modrm)) {
5158 delta++;
5159 putMMXReg(
5160 gregOfRM(modrm),
5161 binop( Iop_32HLto64,
5162 mkU32(0),
5163 getIReg(4, eregOfRM(modrm)) ) );
5164 DIP("movd %s, %s\n",
5165 nameIReg(4,eregOfRM(modrm)), nameMMXReg(gregOfRM(modrm)));
5166 } else {
5167 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5168 delta += len;
5169 putMMXReg(
5170 gregOfRM(modrm),
5171 binop( Iop_32HLto64,
5172 mkU32(0),
5173 loadLE(Ity_I32, mkexpr(addr)) ) );
5174 DIP("movd %s, %s\n", dis_buf, nameMMXReg(gregOfRM(modrm)));
5175 }
5176 break;
5177
5178 case 0x7E: /* MOVD (src)mmxreg (G), (dst)ireg-or-mem (E) */
5179 vassert(sz == 4);
5180 modrm = getIByte(delta);
5181 if (epartIsReg(modrm)) {
5182 delta++;
5183 putIReg( 4, eregOfRM(modrm),
5184 unop(Iop_64to32, getMMXReg(gregOfRM(modrm)) ) );
5185 DIP("movd %s, %s\n",
5186 nameMMXReg(gregOfRM(modrm)), nameIReg(4,eregOfRM(modrm)));
5187 } else {
5188 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5189 delta += len;
5190 storeLE( mkexpr(addr),
5191 unop(Iop_64to32, getMMXReg(gregOfRM(modrm)) ) );
5192 DIP("movd %s, %s\n", nameMMXReg(gregOfRM(modrm)), dis_buf);
5193 }
5194 break;
5195
sewardj464efa42004-11-19 22:17:29 +00005196 case 0x6F:
5197 /* MOVQ (src)mmxreg-or-mem, (dst)mmxreg */
5198 vassert(sz == 4);
5199 modrm = getIByte(delta);
5200 if (epartIsReg(modrm)) {
5201 delta++;
5202 putMMXReg( gregOfRM(modrm), getMMXReg(eregOfRM(modrm)) );
5203 DIP("movq %s, %s\n",
5204 nameMMXReg(eregOfRM(modrm)), nameMMXReg(gregOfRM(modrm)));
5205 } else {
5206 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5207 delta += len;
5208 putMMXReg( gregOfRM(modrm), loadLE(Ity_I64, mkexpr(addr)) );
5209 DIP("movq %s, %s\n",
5210 dis_buf, nameMMXReg(gregOfRM(modrm)));
5211 }
5212 break;
5213
5214 case 0x7F:
5215 /* MOVQ (src)mmxreg, (dst)mmxreg-or-mem */
5216 vassert(sz == 4);
5217 modrm = getIByte(delta);
5218 if (epartIsReg(modrm)) {
sewardj63ba4092004-11-21 12:30:18 +00005219 vassert(0);
sewardj464efa42004-11-19 22:17:29 +00005220#if 0
5221 eip++;
5222 uInstr1(cb, MMX2, 0,
5223 Lit16,
5224 (((UShort)(opc)) << 8) | ((UShort)modrm) );
5225 DIP("movq %s, %s\n",
5226 nameMMXReg(gregOfRM(modrm)), nameMMXReg(eregOfRM(modrm)));
5227#endif
5228 } else {
5229 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5230 delta += len;
sewardj893aada2004-11-29 19:57:54 +00005231 storeLE( mkexpr(addr), getMMXReg(gregOfRM(modrm)) );
sewardj464efa42004-11-19 22:17:29 +00005232 DIP("mov(nt)q %s, %s\n",
5233 nameMMXReg(gregOfRM(modrm)), dis_buf);
5234 }
5235 break;
5236
sewardj4340dac2004-11-20 13:17:04 +00005237 case 0xFC:
5238 case 0xFD:
5239 case 0xFE: /* PADDgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj464efa42004-11-19 22:17:29 +00005240 vassert(sz == 4);
5241 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "padd", True );
5242 break;
5243
sewardj4340dac2004-11-20 13:17:04 +00005244 case 0xEC:
5245 case 0xED: /* PADDSgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj464efa42004-11-19 22:17:29 +00005246 vassert(sz == 4);
5247 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "padds", True );
5248 break;
5249
sewardj4340dac2004-11-20 13:17:04 +00005250 case 0xDC:
5251 case 0xDD: /* PADDUSgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj464efa42004-11-19 22:17:29 +00005252 vassert(sz == 4);
5253 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "paddus", True );
5254 break;
5255
sewardj4340dac2004-11-20 13:17:04 +00005256 case 0xF8:
5257 case 0xF9:
5258 case 0xFA: /* PSUBgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj464efa42004-11-19 22:17:29 +00005259 vassert(sz == 4);
5260 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "psub", True );
5261 break;
5262
sewardj4340dac2004-11-20 13:17:04 +00005263 case 0xE8:
5264 case 0xE9: /* PSUBSgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj464efa42004-11-19 22:17:29 +00005265 vassert(sz == 4);
5266 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "psubs", True );
5267 break;
5268
sewardj4340dac2004-11-20 13:17:04 +00005269 case 0xD8:
5270 case 0xD9: /* PSUBUSgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj464efa42004-11-19 22:17:29 +00005271 vassert(sz == 4);
5272 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "psubus", True );
5273 break;
5274
5275 case 0xE5: /* PMULHW (src)mmxreg-or-mem, (dst)mmxreg */
5276 vassert(sz == 4);
5277 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pmulhw", False );
5278 break;
5279
5280 case 0xD5: /* PMULLW (src)mmxreg-or-mem, (dst)mmxreg */
5281 vassert(sz == 4);
5282 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pmullw", False );
5283 break;
5284
sewardj4340dac2004-11-20 13:17:04 +00005285 case 0xF5: /* PMADDWD (src)mmxreg-or-mem, (dst)mmxreg */
5286 vassert(sz == 4);
5287 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pmaddwd", False );
5288 break;
5289
5290 case 0x74:
5291 case 0x75:
5292 case 0x76: /* PCMPEQgg (src)mmxreg-or-mem, (dst)mmxreg */
5293 vassert(sz == 4);
5294 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pcmpeq", True );
5295 break;
5296
5297 case 0x64:
5298 case 0x65:
5299 case 0x66: /* PCMPGTgg (src)mmxreg-or-mem, (dst)mmxreg */
5300 vassert(sz == 4);
5301 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pcmpgt", True );
5302 break;
5303
sewardj63ba4092004-11-21 12:30:18 +00005304 case 0x6B: /* PACKSSDW (src)mmxreg-or-mem, (dst)mmxreg */
5305 vassert(sz == 4);
5306 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "packssdw", False );
5307 break;
5308
5309 case 0x63: /* PACKSSWB (src)mmxreg-or-mem, (dst)mmxreg */
5310 vassert(sz == 4);
5311 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "packsswb", False );
5312 break;
5313
5314 case 0x67: /* PACKUSWB (src)mmxreg-or-mem, (dst)mmxreg */
5315 vassert(sz == 4);
5316 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "packuswb", False );
5317 break;
5318
5319 case 0x68:
5320 case 0x69:
5321 case 0x6A: /* PUNPCKHgg (src)mmxreg-or-mem, (dst)mmxreg */
5322 vassert(sz == 4);
5323 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "punpckh", True );
5324 break;
5325
5326 case 0x60:
5327 case 0x61:
5328 case 0x62: /* PUNPCKLgg (src)mmxreg-or-mem, (dst)mmxreg */
5329 vassert(sz == 4);
5330 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "punpckl", True );
5331 break;
5332
5333 case 0xDB: /* PAND (src)mmxreg-or-mem, (dst)mmxreg */
5334 vassert(sz == 4);
5335 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pand", False );
5336 break;
5337
5338 case 0xDF: /* PANDN (src)mmxreg-or-mem, (dst)mmxreg */
5339 vassert(sz == 4);
5340 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pandn", False );
5341 break;
5342
5343 case 0xEB: /* POR (src)mmxreg-or-mem, (dst)mmxreg */
5344 vassert(sz == 4);
5345 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "por", False );
5346 break;
5347
5348 case 0xEF: /* PXOR (src)mmxreg-or-mem, (dst)mmxreg */
5349 vassert(sz == 4);
5350 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pxor", False );
5351 break;
5352
sewardj8d14a592004-11-21 17:04:50 +00005353 case 0xF1:
5354 case 0xF2:
5355 case 0xF3: /* PSLLgg (src)mmxreg-or-mem, (dst)mmxreg */
5356 vassert(sz == 4);
5357 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "psll", True );
5358 break;
5359
5360 case 0xD1:
5361 case 0xD2:
5362 case 0xD3: /* PSRLgg (src)mmxreg-or-mem, (dst)mmxreg */
5363 vassert(sz == 4);
5364 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "psrl", True );
5365 break;
5366
5367 case 0xE1:
5368 case 0xE2: /* PSRAgg (src)mmxreg-or-mem, (dst)mmxreg */
5369 vassert(sz == 4);
5370 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "psra", True );
5371 break;
5372
sewardj2b7a9202004-11-26 19:15:38 +00005373 case 0x71:
5374 case 0x72:
5375 case 0x73: {
5376 /* (sz==4): PSLLgg/PSRAgg/PSRLgg mmxreg by imm8 */
5377 UChar byte1, byte2, byte3, subopc, mmreg;
5378 void* hAddr;
5379 Char* hName;
5380 vassert(sz == 4);
5381 byte1 = opc; /* 0x71/72/73 */
5382 byte2 = getIByte(delta); delta++; /* amode / sub-opcode */
5383 byte3 = getIByte(delta); delta++; /* imm8 */
5384 mmreg = byte2 & 7;
5385 subopc = (byte2 >> 3) & 7;
5386
5387# define XXX(_name) do { hAddr = &_name; hName = #_name; } while (0)
5388
5389 hAddr = NULL;
5390 hName = NULL;
5391
5392 if (subopc == 2 /*SRL*/ && opc == 0x71)
5393 XXX(x86g_calculate_shr16Ux4);
5394 else if (subopc == 2 /*SRL*/ && opc == 0x72)
5395 XXX(x86g_calculate_shr32Ux2);
5396 else if (subopc == 2 /*SRL*/ && opc == 0x73)
5397 XXX(x86g_calculate_shr64Ux1);
5398
5399 else if (subopc == 4 /*SAR*/ && opc == 0x71)
5400 XXX(x86g_calculate_shr16Sx4);
5401 else if (subopc == 4 /*SAR*/ && opc == 0x72)
5402 XXX(x86g_calculate_shr32Sx2);
5403
5404 else if (subopc == 6 /*SHL*/ && opc == 0x71)
5405 XXX(x86g_calculate_shl16x4);
5406 else if (subopc == 6 /*SHL*/ && opc == 0x72)
5407 XXX(x86g_calculate_shl32x2);
5408 else if (subopc == 6 /*SHL*/ && opc == 0x73)
5409 XXX(x86g_calculate_shl64x1);
5410
5411 else goto mmx_decode_failure;
5412
5413# undef XXX
5414
5415 putMMXReg(
5416 mmreg,
5417 mkIRExprCCall(
5418 Ity_I64,
5419 0/*regparms*/, hName, hAddr,
5420 mkIRExprVec_2( getMMXReg(mmreg),
5421 IRExpr_Const(IRConst_U64( (ULong)byte3 ) ) )
5422 )
5423 );
5424
5425 DIP("ps%s%s $%d, %s\n",
5426 ( subopc == 2 ? "rl"
5427 : subopc == 6 ? "ll"
5428 : subopc == 4 ? "ra"
5429 : "??" ),
5430 nameMMXGran(opc & 3), (Int)byte3, nameMMXReg(mmreg) );
5431 break;
5432 }
5433
5434 /* --- MMX decode failure --- */
sewardj464efa42004-11-19 22:17:29 +00005435 default:
sewardj2b7a9202004-11-26 19:15:38 +00005436 mmx_decode_failure:
sewardj464efa42004-11-19 22:17:29 +00005437 *decode_ok = False;
5438 return delta; /* ignored */
5439
5440 }
5441
5442 *decode_ok = True;
5443 return delta;
5444}
5445
5446
5447/*------------------------------------------------------------*/
5448/*--- More misc arithmetic and other obscure insns. ---*/
5449/*------------------------------------------------------------*/
sewardja06e5562004-07-14 13:18:05 +00005450
5451/* Double length left and right shifts. Apparently only required in
5452 v-size (no b- variant). */
5453static
5454UInt dis_SHLRD_Gv_Ev ( UChar sorb,
5455 UInt delta, UChar modrm,
5456 Int sz,
5457 IRExpr* shift_amt,
5458 Bool amt_is_literal,
5459 Char* shift_amt_txt,
5460 Bool left_shift )
5461{
5462 /* shift_amt :: Ity_I8 is the amount to shift. shift_amt_txt is used
5463 for printing it. And eip on entry points at the modrm byte. */
5464 Int len;
sewardjc9a43662004-11-30 18:51:59 +00005465 HChar dis_buf[50];
sewardja06e5562004-07-14 13:18:05 +00005466
sewardj6d2638e2004-07-15 09:38:27 +00005467 IRType ty = szToITy(sz);
5468 IRTemp gsrc = newTemp(ty);
5469 IRTemp esrc = newTemp(ty);
sewardj92d168d2004-11-15 14:22:12 +00005470 IRTemp addr = IRTemp_INVALID;
sewardj6d2638e2004-07-15 09:38:27 +00005471 IRTemp tmpSH = newTemp(Ity_I8);
sewardj92d168d2004-11-15 14:22:12 +00005472 IRTemp tmpL = IRTemp_INVALID;
5473 IRTemp tmpRes = IRTemp_INVALID;
5474 IRTemp tmpSubSh = IRTemp_INVALID;
sewardja06e5562004-07-14 13:18:05 +00005475 IROp mkpair;
5476 IROp getres;
5477 IROp shift;
sewardja06e5562004-07-14 13:18:05 +00005478 IRExpr* mask = NULL;
5479
5480 vassert(sz == 2 || sz == 4);
5481
5482 /* The E-part is the destination; this is shifted. The G-part
5483 supplies bits to be shifted into the E-part, but is not
5484 changed.
5485
5486 If shifting left, form a double-length word with E at the top
5487 and G at the bottom, and shift this left. The result is then in
5488 the high part.
5489
5490 If shifting right, form a double-length word with G at the top
5491 and E at the bottom, and shift this right. The result is then
5492 at the bottom. */
5493
5494 /* Fetch the operands. */
5495
5496 assign( gsrc, getIReg(sz, gregOfRM(modrm)) );
5497
5498 if (epartIsReg(modrm)) {
5499 delta++;
5500 assign( esrc, getIReg(sz, eregOfRM(modrm)) );
sewardj68511542004-07-28 00:15:44 +00005501 DIP("sh%cd%c %s, %s, %s\n",
sewardja06e5562004-07-14 13:18:05 +00005502 ( left_shift ? 'l' : 'r' ), nameISize(sz),
sewardj68511542004-07-28 00:15:44 +00005503 shift_amt_txt,
sewardja06e5562004-07-14 13:18:05 +00005504 nameIReg(sz, gregOfRM(modrm)), nameIReg(sz, eregOfRM(modrm)));
5505 } else {
5506 addr = disAMode ( &len, sorb, delta, dis_buf );
5507 delta += len;
5508 assign( esrc, loadLE(ty, mkexpr(addr)) );
sewardj68511542004-07-28 00:15:44 +00005509 DIP("sh%cd%c %s, %s, %s\n",
5510 ( left_shift ? 'l' : 'r' ), nameISize(sz),
5511 shift_amt_txt,
5512 nameIReg(sz, gregOfRM(modrm)), dis_buf);
sewardja06e5562004-07-14 13:18:05 +00005513 }
5514
5515 /* Round up the relevant primops. */
5516
5517 if (sz == 4) {
5518 tmpL = newTemp(Ity_I64);
5519 tmpRes = newTemp(Ity_I32);
5520 tmpSubSh = newTemp(Ity_I32);
sewardje539a402004-07-14 18:24:17 +00005521 mkpair = Iop_32HLto64;
sewardj8c7f1ab2004-07-29 20:31:09 +00005522 getres = left_shift ? Iop_64HIto32 : Iop_64to32;
sewardje539a402004-07-14 18:24:17 +00005523 shift = left_shift ? Iop_Shl64 : Iop_Shr64;
5524 mask = mkU8(31);
sewardja06e5562004-07-14 13:18:05 +00005525 } else {
5526 /* sz == 2 */
sewardj8c7f1ab2004-07-29 20:31:09 +00005527 tmpL = newTemp(Ity_I32);
5528 tmpRes = newTemp(Ity_I16);
5529 tmpSubSh = newTemp(Ity_I16);
5530 mkpair = Iop_16HLto32;
5531 getres = left_shift ? Iop_32HIto16 : Iop_32to16;
5532 shift = left_shift ? Iop_Shl32 : Iop_Shr32;
5533 mask = mkU8(15);
sewardja06e5562004-07-14 13:18:05 +00005534 }
5535
5536 /* Do the shift, calculate the subshift value, and set
5537 the flag thunk. */
5538
sewardj8c7f1ab2004-07-29 20:31:09 +00005539 assign( tmpSH, binop(Iop_And8, shift_amt, mask) );
5540
sewardja06e5562004-07-14 13:18:05 +00005541 if (left_shift)
5542 assign( tmpL, binop(mkpair, mkexpr(esrc), mkexpr(gsrc)) );
5543 else
5544 assign( tmpL, binop(mkpair, mkexpr(gsrc), mkexpr(esrc)) );
5545
5546 assign( tmpRes, unop(getres, binop(shift, mkexpr(tmpL), mkexpr(tmpSH)) ) );
5547 assign( tmpSubSh,
5548 unop(getres,
5549 binop(shift,
5550 mkexpr(tmpL),
5551 binop(Iop_And8,
5552 binop(Iop_Sub8, mkexpr(tmpSH), mkU8(1) ),
5553 mask))) );
sewardja06e5562004-07-14 13:18:05 +00005554
sewardj2a2ba8b2004-11-08 13:14:06 +00005555 setFlags_DEP1_DEP2_shift ( left_shift ? Iop_Shl32 : Iop_Sar32,
5556 tmpRes, tmpSubSh, ty, tmpSH );
sewardja06e5562004-07-14 13:18:05 +00005557
5558 /* Put result back. */
5559
5560 if (epartIsReg(modrm)) {
5561 putIReg(sz, eregOfRM(modrm), mkexpr(tmpRes));
5562 } else {
5563 storeLE( mkexpr(addr), mkexpr(tmpRes) );
5564 }
5565
5566 if (amt_is_literal) delta++;
5567 return delta;
5568}
5569
5570
sewardj1c6f9912004-09-07 10:15:24 +00005571/* Handle BT/BTS/BTR/BTC Gv, Ev. Apparently b-size is not
5572 required. */
5573
5574typedef enum { BtOpNone, BtOpSet, BtOpReset, BtOpComp } BtOp;
5575
5576static Char* nameBtOp ( BtOp op )
5577{
5578 switch (op) {
5579 case BtOpNone: return "";
5580 case BtOpSet: return "s";
5581 case BtOpReset: return "r";
5582 case BtOpComp: return "c";
5583 default: vpanic("nameBtOp(x86)");
5584 }
5585}
5586
5587
5588static
5589UInt dis_bt_G_E ( UChar sorb, Int sz, UInt delta, BtOp op )
5590{
sewardjc9a43662004-11-30 18:51:59 +00005591 HChar dis_buf[50];
sewardj1c6f9912004-09-07 10:15:24 +00005592 UChar modrm;
5593 Int len;
5594 IRTemp t_fetched, t_bitno0, t_bitno1, t_bitno2, t_addr0,
5595 t_addr1, t_esp, t_mask;
5596
5597 vassert(sz == 2 || sz == 4);
5598
5599 t_fetched = t_bitno0 = t_bitno1 = t_bitno2
sewardj92d168d2004-11-15 14:22:12 +00005600 = t_addr0 = t_addr1 = t_esp = t_mask = IRTemp_INVALID;
sewardj1c6f9912004-09-07 10:15:24 +00005601
5602 t_fetched = newTemp(Ity_I8);
5603 t_bitno0 = newTemp(Ity_I32);
5604 t_bitno1 = newTemp(Ity_I32);
5605 t_bitno2 = newTemp(Ity_I8);
5606 t_addr1 = newTemp(Ity_I32);
5607 modrm = getIByte(delta);
5608
5609 assign( t_bitno0, widenUto32(getIReg(sz, gregOfRM(modrm))) );
5610
5611 if (epartIsReg(modrm)) {
sewardj1c6f9912004-09-07 10:15:24 +00005612 delta++;
5613 /* Get it onto the client's stack. */
5614 t_esp = newTemp(Ity_I32);
5615 t_addr0 = newTemp(Ity_I32);
5616
5617 assign( t_esp, binop(Iop_Sub32, getIReg(4, R_ESP), mkU32(sz)) );
5618 putIReg(4, R_ESP, mkexpr(t_esp));
5619
5620 storeLE( mkexpr(t_esp), getIReg(sz, eregOfRM(modrm)) );
5621
5622 /* Make t_addr0 point at it. */
5623 assign( t_addr0, mkexpr(t_esp) );
5624
5625 /* Mask out upper bits of the shift amount, since we're doing a
5626 reg. */
5627 assign( t_bitno1, binop(Iop_And32,
5628 mkexpr(t_bitno0),
5629 mkU32(sz == 4 ? 31 : 15)) );
5630
5631 } else {
5632 t_addr0 = disAMode ( &len, sorb, delta, dis_buf );
5633 delta += len;
5634 assign( t_bitno1, mkexpr(t_bitno0) );
5635 }
5636
5637 /* At this point: t_addr0 is the address being operated on. If it
5638 was a reg, we will have pushed it onto the client's stack.
5639 t_bitno1 is the bit number, suitably masked in the case of a
5640 reg. */
5641
5642 /* Now the main sequence. */
5643 assign( t_addr1,
5644 binop(Iop_Add32,
5645 mkexpr(t_addr0),
5646 binop(Iop_Sar32, mkexpr(t_bitno1), mkU8(3))) );
5647
5648 /* t_addr1 now holds effective address */
5649
5650 assign( t_bitno2,
5651 unop(Iop_32to8,
5652 binop(Iop_And32, mkexpr(t_bitno1), mkU32(7))) );
5653
5654 /* t_bitno2 contains offset of bit within byte */
5655
5656 if (op != BtOpNone) {
5657 t_mask = newTemp(Ity_I8);
5658 assign( t_mask, binop(Iop_Shl8, mkU8(1), mkexpr(t_bitno2)) );
5659 }
sewardj4963a422004-10-14 23:34:03 +00005660
sewardj1c6f9912004-09-07 10:15:24 +00005661 /* t_mask is now a suitable byte mask */
5662
5663 assign( t_fetched, loadLE(Ity_I8, mkexpr(t_addr1)) );
5664
5665 if (op != BtOpNone) {
5666 switch (op) {
5667 case BtOpSet:
5668 storeLE( mkexpr(t_addr1),
5669 binop(Iop_Or8, mkexpr(t_fetched),
5670 mkexpr(t_mask)) );
5671 break;
5672 case BtOpComp:
5673 storeLE( mkexpr(t_addr1),
5674 binop(Iop_Xor8, mkexpr(t_fetched),
5675 mkexpr(t_mask)) );
5676 break;
5677 case BtOpReset:
5678 storeLE( mkexpr(t_addr1),
5679 binop(Iop_And8, mkexpr(t_fetched),
5680 unop(Iop_Not8, mkexpr(t_mask))) );
5681 break;
5682 default:
5683 vpanic("dis_bt_G_E(x86)");
5684 }
5685 }
5686
5687 /* Side effect done; now get selected bit into Carry flag */
sewardj2a2ba8b2004-11-08 13:14:06 +00005688 /* Flags: C=selected bit, O,S,Z,A,P undefined, so are set to zero. */
sewardj2a9ad022004-11-25 02:46:58 +00005689 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
sewardj2a2ba8b2004-11-08 13:14:06 +00005690 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
sewardj1c6f9912004-09-07 10:15:24 +00005691 stmt( IRStmt_Put(
sewardj2a2ba8b2004-11-08 13:14:06 +00005692 OFFB_CC_DEP1,
sewardj1c6f9912004-09-07 10:15:24 +00005693 binop(Iop_And32,
5694 binop(Iop_Shr32,
5695 unop(Iop_8Uto32, mkexpr(t_fetched)),
sewardj5bd4d162004-11-10 13:02:48 +00005696 mkexpr(t_bitno2)),
5697 mkU32(1)))
sewardj1c6f9912004-09-07 10:15:24 +00005698 );
5699
5700 /* Move reg operand from stack back to reg */
5701 if (epartIsReg(modrm)) {
5702 /* t_esp still points at it. */
sewardj4963a422004-10-14 23:34:03 +00005703 putIReg(sz, eregOfRM(modrm), loadLE(szToITy(sz), mkexpr(t_esp)) );
sewardj1c6f9912004-09-07 10:15:24 +00005704 putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t_esp), mkU32(sz)) );
5705 }
5706
5707 DIP("bt%s%c %s, %s\n",
5708 nameBtOp(op), nameISize(sz), nameIReg(sz, gregOfRM(modrm)),
5709 ( epartIsReg(modrm) ? nameIReg(sz, eregOfRM(modrm)) : dis_buf ) );
5710
5711 return delta;
5712}
sewardjce646f22004-08-31 23:55:54 +00005713
5714
5715
5716/* Handle BSF/BSR. Only v-size seems necessary. */
5717static
5718UInt dis_bs_E_G ( UChar sorb, Int sz, UInt delta, Bool fwds )
5719{
5720 Bool isReg;
5721 UChar modrm;
sewardjc9a43662004-11-30 18:51:59 +00005722 HChar dis_buf[50];
sewardjce646f22004-08-31 23:55:54 +00005723
5724 IRType ty = szToITy(sz);
5725 IRTemp src = newTemp(ty);
5726 IRTemp dst = newTemp(ty);
5727
5728 IRTemp src32 = newTemp(Ity_I32);
5729 IRTemp dst32 = newTemp(Ity_I32);
5730 IRTemp src8 = newTemp(Ity_I8);
5731
5732 vassert(sz == 4 || sz == 2);
sewardjce646f22004-08-31 23:55:54 +00005733
5734 modrm = getIByte(delta);
5735
5736 isReg = epartIsReg(modrm);
5737 if (isReg) {
5738 delta++;
5739 assign( src, getIReg(sz, eregOfRM(modrm)) );
5740 } else {
5741 Int len;
5742 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5743 delta += len;
5744 assign( src, loadLE(ty, mkexpr(addr)) );
5745 }
5746
5747 DIP("bs%c%c %s, %s\n",
5748 fwds ? 'f' : 'r', nameISize(sz),
5749 ( isReg ? nameIReg(sz, eregOfRM(modrm)) : dis_buf ),
5750 nameIReg(sz, gregOfRM(modrm)));
5751
5752 /* Generate an 8-bit expression which is zero iff the
5753 original is zero, and nonzero otherwise */
5754 assign( src8,
5755 unop(Iop_1Uto8, binop(mkSizedOp(ty,Iop_CmpNE8),
5756 mkexpr(src), mkU(ty,0))) );
5757
5758 /* Flags: Z is 1 iff source value is zero. All others
5759 are undefined -- we force them to zero. */
sewardj2a9ad022004-11-25 02:46:58 +00005760 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
sewardj2a2ba8b2004-11-08 13:14:06 +00005761 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
sewardjce646f22004-08-31 23:55:54 +00005762 stmt( IRStmt_Put(
sewardj2a2ba8b2004-11-08 13:14:06 +00005763 OFFB_CC_DEP1,
sewardjce646f22004-08-31 23:55:54 +00005764 IRExpr_Mux0X( mkexpr(src8),
5765 /* src==0 */
sewardj2a9ad022004-11-25 02:46:58 +00005766 mkU32(X86G_CC_MASK_Z),
sewardjce646f22004-08-31 23:55:54 +00005767 /* src!=0 */
5768 mkU32(0)
5769 )
5770 ));
5771
5772 /* Result: iff source value is zero, we can't use
5773 Iop_Clz32/Iop_Ctz32 as they have no defined result in that case.
5774 But anyway, Intel x86 semantics say the result is undefined in
5775 such situations. Hence handle the zero case specially. */
5776
5777 /* Bleh. What we compute:
5778
5779 bsf32: if src == 0 then 0 else Ctz32(src)
5780 bsr32: if src == 0 then 0 else 31 - Clz32(src)
5781
5782 bsf16: if src == 0 then 0 else Ctz32(16Uto32(src))
5783 bsr16: if src == 0 then 0 else 31 - Clz32(16Uto32(src))
5784
5785 First, widen src to 32 bits if it is not already.
sewardj37158712004-10-15 21:23:12 +00005786
5787 Postscript 15 Oct 04: it seems that at least VIA Nehemiah leaves the
5788 dst register unchanged when src == 0. Hence change accordingly.
sewardjce646f22004-08-31 23:55:54 +00005789 */
5790 if (sz == 2)
5791 assign( src32, unop(Iop_16Uto32, mkexpr(src)) );
5792 else
5793 assign( src32, mkexpr(src) );
5794
5795 /* The main computation, guarding against zero. */
5796 assign( dst32,
5797 IRExpr_Mux0X(
5798 mkexpr(src8),
sewardj37158712004-10-15 21:23:12 +00005799 /* src == 0 -- leave dst unchanged */
5800 widenUto32( getIReg( sz, gregOfRM(modrm) ) ),
sewardjce646f22004-08-31 23:55:54 +00005801 /* src != 0 */
5802 fwds ? unop(Iop_Ctz32, mkexpr(src32))
5803 : binop(Iop_Sub32,
5804 mkU32(31),
5805 unop(Iop_Clz32, mkexpr(src32)))
5806 )
5807 );
5808
5809 if (sz == 2)
5810 assign( dst, unop(Iop_32to16, mkexpr(dst32)) );
5811 else
5812 assign( dst, mkexpr(dst32) );
5813
5814 /* dump result back */
5815 putIReg( sz, gregOfRM(modrm), mkexpr(dst) );
5816
5817 return delta;
5818}
sewardj64e1d652004-07-12 14:00:46 +00005819
5820
5821static
5822void codegen_xchg_eAX_Reg ( Int sz, Int reg )
5823{
5824 IRType ty = szToITy(sz);
5825 IRTemp t1 = newTemp(ty);
5826 IRTemp t2 = newTemp(ty);
5827 vassert(sz == 2 || sz == 4);
5828 assign( t1, getIReg(sz, R_EAX) );
5829 assign( t2, getIReg(sz, reg) );
5830 putIReg( sz, R_EAX, mkexpr(t2) );
5831 putIReg( sz, reg, mkexpr(t1) );
5832 DIP("xchg%c %s, %s\n",
5833 nameISize(sz), nameIReg(sz, R_EAX), nameIReg(sz, reg));
5834}
5835
5836
sewardjbdc7d212004-09-09 02:46:40 +00005837static
5838void codegen_SAHF ( void )
5839{
5840 /* Set the flags to:
sewardj2a9ad022004-11-25 02:46:58 +00005841 (x86g_calculate_flags_all() & X86G_CC_MASK_O) -- retain the old O flag
5842 | (%AH & (X86G_CC_MASK_S|X86G_CC_MASK_Z|X86G_CC_MASK_A
5843 |X86G_CC_MASK_P|X86G_CC_MASK_C)
sewardjbdc7d212004-09-09 02:46:40 +00005844 */
sewardj2a9ad022004-11-25 02:46:58 +00005845 UInt mask_SZACP = X86G_CC_MASK_S|X86G_CC_MASK_Z|X86G_CC_MASK_A
5846 |X86G_CC_MASK_C|X86G_CC_MASK_P;
sewardjbdc7d212004-09-09 02:46:40 +00005847 IRTemp oldflags = newTemp(Ity_I32);
sewardj2a9ad022004-11-25 02:46:58 +00005848 assign( oldflags, mk_x86g_calculate_eflags_all() );
5849 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
sewardj2a2ba8b2004-11-08 13:14:06 +00005850 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
5851 stmt( IRStmt_Put( OFFB_CC_DEP1,
sewardjbdc7d212004-09-09 02:46:40 +00005852 binop(Iop_Or32,
sewardj2a9ad022004-11-25 02:46:58 +00005853 binop(Iop_And32, mkexpr(oldflags), mkU32(X86G_CC_MASK_O)),
sewardjbdc7d212004-09-09 02:46:40 +00005854 binop(Iop_And32,
5855 binop(Iop_Shr32, getIReg(4, R_EAX), mkU8(8)),
5856 mkU32(mask_SZACP))
5857 )
5858 ));
5859}
5860
5861
sewardjc9a65702004-07-07 16:32:57 +00005862//-- static
5863//-- void codegen_LAHF ( UCodeBlock* cb )
5864//-- {
5865//-- Int t = newTemp(cb);
5866//--
5867//-- /* Pushed arg is ignored, it just provides somewhere to put the
5868//-- return value. */
5869//-- uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, t);
5870//-- uInstr0(cb, CALLM_S, 0);
5871//-- uInstr1(cb, PUSH, 4, TempReg, t);
5872//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_LAHF));
5873//-- uFlagsRWU(cb, FlagsSZACP, FlagsEmpty, FlagsEmpty);
5874//-- uInstr1(cb, POP, 4, TempReg, t);
5875//-- uInstr0(cb, CALLM_E, 0);
5876//--
5877//-- /* At this point, the %ah sub-register in %eax has been updated,
5878//-- the rest is the same, so do a PUT of the whole thing. */
5879//-- uInstr2(cb, PUT, 4, TempReg, t, ArchReg, R_EAX);
5880//-- }
5881//--
sewardj458a6f82004-08-25 12:46:02 +00005882
5883static
5884UInt dis_cmpxchg_G_E ( UChar sorb,
5885 Int size,
5886 UInt delta0 )
5887{
sewardjc9a43662004-11-30 18:51:59 +00005888 HChar dis_buf[50];
sewardj458a6f82004-08-25 12:46:02 +00005889 Int len;
5890
5891 IRType ty = szToITy(size);
5892 IRTemp acc = newTemp(ty);
5893 IRTemp src = newTemp(ty);
sewardj2a2ba8b2004-11-08 13:14:06 +00005894 //IRTemp res = newTemp(ty);
sewardj458a6f82004-08-25 12:46:02 +00005895 IRTemp dest = newTemp(ty);
5896 IRTemp dest2 = newTemp(ty);
5897 IRTemp acc2 = newTemp(ty);
5898 IRTemp cond8 = newTemp(Ity_I8);
sewardj92d168d2004-11-15 14:22:12 +00005899 IRTemp addr = IRTemp_INVALID;
sewardj458a6f82004-08-25 12:46:02 +00005900 UChar rm = getUChar(delta0);
5901
5902 if (epartIsReg(rm)) {
5903 assign( dest, getIReg(size, eregOfRM(rm)) );
5904 delta0++;
5905 DIP("cmpxchg%c %s,%s\n", nameISize(size),
5906 nameIReg(size,gregOfRM(rm)),
5907 nameIReg(size,eregOfRM(rm)) );
sewardj458a6f82004-08-25 12:46:02 +00005908 } else {
5909 addr = disAMode ( &len, sorb, delta0, dis_buf );
5910 assign( dest, loadLE(ty, mkexpr(addr)) );
5911 delta0 += len;
5912 DIP("cmpxchg%c %s,%s\n", nameISize(size),
5913 nameIReg(size,gregOfRM(rm)), dis_buf);
5914 }
5915
5916 assign( src, getIReg(size, gregOfRM(rm)) );
5917 assign( acc, getIReg(size, R_EAX) );
sewardj2a2ba8b2004-11-08 13:14:06 +00005918 //assign( res, binop( mkSizedOp(ty,Iop_Sub8), mkexpr(acc), mkexpr(dest) ));
5919 setFlags_DEP1_DEP2(Iop_Sub8, acc, dest, ty);
sewardj2a9ad022004-11-25 02:46:58 +00005920 assign( cond8, unop(Iop_1Uto8, mk_x86g_calculate_condition(X86CondZ)) );
sewardj458a6f82004-08-25 12:46:02 +00005921 assign( dest2, IRExpr_Mux0X(mkexpr(cond8), mkexpr(dest), mkexpr(src)) );
5922 assign( acc2, IRExpr_Mux0X(mkexpr(cond8), mkexpr(dest), mkexpr(acc)) );
5923 putIReg(size, R_EAX, mkexpr(acc2));
5924
5925 if (epartIsReg(rm)) {
5926 putIReg(size, eregOfRM(rm), mkexpr(dest2));
5927 } else {
5928 storeLE( mkexpr(addr), mkexpr(dest2) );
5929 }
5930
5931 return delta0;
5932}
5933
5934
sewardjc9a65702004-07-07 16:32:57 +00005935//-- static
5936//-- Addr dis_cmpxchg8b ( UCodeBlock* cb,
5937//-- UChar sorb,
5938//-- Addr eip0 )
5939//-- {
5940//-- Int tal, tah, junkl, junkh, destl, desth, srcl, srch, accl, acch;
sewardjc9a43662004-11-30 18:51:59 +00005941//-- HChar dis_buf[50];
sewardjc9a65702004-07-07 16:32:57 +00005942//-- UChar rm;
5943//-- UInt pair;
5944//--
5945//-- rm = getUChar(eip0);
5946//-- accl = newTemp(cb);
5947//-- acch = newTemp(cb);
5948//-- srcl = newTemp(cb);
5949//-- srch = newTemp(cb);
5950//-- destl = newTemp(cb);
5951//-- desth = newTemp(cb);
5952//-- junkl = newTemp(cb);
5953//-- junkh = newTemp(cb);
5954//--
5955//-- vg_assert(!epartIsReg(rm));
5956//--
5957//-- pair = disAMode ( cb, sorb, eip0, dis_buf );
5958//-- tal = LOW24(pair);
5959//-- tah = newTemp(cb);
5960//-- uInstr2(cb, MOV, 4, TempReg, tal, TempReg, tah);
5961//-- uInstr2(cb, ADD, 4, Literal, 0, TempReg, tah);
5962//-- uLiteral(cb, 4);
5963//-- eip0 += HI8(pair);
5964//-- DIP("cmpxchg8b %s\n", dis_buf);
5965//--
5966//-- uInstr0(cb, CALLM_S, 0);
5967//--
5968//-- uInstr2(cb, LOAD, 4, TempReg, tah, TempReg, desth);
5969//-- uInstr1(cb, PUSH, 4, TempReg, desth);
5970//-- uInstr2(cb, LOAD, 4, TempReg, tal, TempReg, destl);
5971//-- uInstr1(cb, PUSH, 4, TempReg, destl);
5972//-- uInstr2(cb, GET, 4, ArchReg, R_ECX, TempReg, srch);
5973//-- uInstr1(cb, PUSH, 4, TempReg, srch);
5974//-- uInstr2(cb, GET, 4, ArchReg, R_EBX, TempReg, srcl);
5975//-- uInstr1(cb, PUSH, 4, TempReg, srcl);
5976//-- uInstr2(cb, GET, 4, ArchReg, R_EDX, TempReg, acch);
5977//-- uInstr1(cb, PUSH, 4, TempReg, acch);
5978//-- uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, accl);
5979//-- uInstr1(cb, PUSH, 4, TempReg, accl);
5980//--
5981//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_cmpxchg8b));
5982//-- uFlagsRWU(cb, FlagsEmpty, FlagZ, FlagsEmpty);
5983//--
5984//-- uInstr1(cb, POP, 4, TempReg, accl);
5985//-- uInstr2(cb, PUT, 4, TempReg, accl, ArchReg, R_EAX);
5986//-- uInstr1(cb, POP, 4, TempReg, acch);
5987//-- uInstr2(cb, PUT, 4, TempReg, acch, ArchReg, R_EDX);
5988//-- uInstr1(cb, POP, 4, TempReg, srcl);
5989//-- uInstr2(cb, PUT, 4, TempReg, srcl, ArchReg, R_EBX);
5990//-- uInstr1(cb, POP, 4, TempReg, srch);
5991//-- uInstr2(cb, PUT, 4, TempReg, srch, ArchReg, R_ECX);
5992//-- uInstr1(cb, POP, 4, TempReg, destl);
5993//-- uInstr2(cb, STORE, 4, TempReg, destl, TempReg, tal);
5994//-- uInstr1(cb, POP, 4, TempReg, desth);
5995//-- uInstr2(cb, STORE, 4, TempReg, desth, TempReg, tah);
5996//--
5997//-- uInstr0(cb, CALLM_E, 0);
5998//--
5999//-- return eip0;
6000//-- }
sewardj458a6f82004-08-25 12:46:02 +00006001
6002
6003/* Handle conditional move instructions of the form
6004 cmovcc E(reg-or-mem), G(reg)
6005
6006 E(src) is reg-or-mem
6007 G(dst) is reg.
6008
6009 If E is reg, --> GET %E, tmps
6010 GET %G, tmpd
6011 CMOVcc tmps, tmpd
6012 PUT tmpd, %G
6013
6014 If E is mem --> (getAddr E) -> tmpa
6015 LD (tmpa), tmps
6016 GET %G, tmpd
6017 CMOVcc tmps, tmpd
6018 PUT tmpd, %G
6019*/
6020static
6021UInt dis_cmov_E_G ( UChar sorb,
6022 Int sz,
sewardj2a9ad022004-11-25 02:46:58 +00006023 X86Condcode cond,
sewardj458a6f82004-08-25 12:46:02 +00006024 UInt delta0 )
6025{
6026 UChar rm = getIByte(delta0);
sewardjc9a43662004-11-30 18:51:59 +00006027 HChar dis_buf[50];
sewardj458a6f82004-08-25 12:46:02 +00006028 Int len;
6029
sewardj883b00b2004-09-11 09:30:24 +00006030 IRType ty = szToITy(sz);
sewardj458a6f82004-08-25 12:46:02 +00006031 IRTemp tmps = newTemp(ty);
6032 IRTemp tmpd = newTemp(ty);
6033
6034 if (epartIsReg(rm)) {
6035 assign( tmps, getIReg(sz, eregOfRM(rm)) );
6036 assign( tmpd, getIReg(sz, gregOfRM(rm)) );
6037
6038 putIReg(sz, gregOfRM(rm),
sewardj2a9ad022004-11-25 02:46:58 +00006039 IRExpr_Mux0X( unop(Iop_1Uto8,
6040 mk_x86g_calculate_condition(cond)),
sewardj458a6f82004-08-25 12:46:02 +00006041 mkexpr(tmpd),
6042 mkexpr(tmps) )
6043 );
6044 DIP("cmov%c%s %s,%s\n", nameISize(sz),
sewardj2a9ad022004-11-25 02:46:58 +00006045 name_X86Condcode(cond),
sewardj458a6f82004-08-25 12:46:02 +00006046 nameIReg(sz,eregOfRM(rm)),
6047 nameIReg(sz,gregOfRM(rm)));
6048 return 1+delta0;
6049 }
6050
6051 /* E refers to memory */
6052 {
6053 IRTemp addr = disAMode ( &len, sorb, delta0, dis_buf );
6054 assign( tmps, loadLE(ty, mkexpr(addr)) );
6055 assign( tmpd, getIReg(sz, gregOfRM(rm)) );
6056
6057 putIReg(sz, gregOfRM(rm),
sewardj2a9ad022004-11-25 02:46:58 +00006058 IRExpr_Mux0X( unop(Iop_1Uto8,
6059 mk_x86g_calculate_condition(cond)),
sewardj458a6f82004-08-25 12:46:02 +00006060 mkexpr(tmpd),
6061 mkexpr(tmps) )
6062 );
6063
6064 DIP("cmov%c%s %s,%s\n", nameISize(sz),
sewardj2a9ad022004-11-25 02:46:58 +00006065 name_X86Condcode(cond),
sewardj458a6f82004-08-25 12:46:02 +00006066 dis_buf,
6067 nameIReg(sz,gregOfRM(rm)));
6068 return len+delta0;
6069 }
6070}
6071
6072
sewardj883b00b2004-09-11 09:30:24 +00006073static
6074UInt dis_xadd_G_E ( UChar sorb, Int sz, UInt delta0 )
6075{
6076 Int len;
6077 UChar rm = getIByte(delta0);
sewardjc9a43662004-11-30 18:51:59 +00006078 HChar dis_buf[50];
sewardj883b00b2004-09-11 09:30:24 +00006079
6080 // Int tmpd = newTemp(cb);
6081 //Int tmpt = newTemp(cb);
6082
6083 IRType ty = szToITy(sz);
6084 IRTemp tmpd = newTemp(ty);
6085 IRTemp tmpt0 = newTemp(ty);
6086 IRTemp tmpt1 = newTemp(ty);
6087
6088 if (epartIsReg(rm)) {
6089 vassert(0);
6090#if 0
6091 uInstr2(cb, GET, sz, ArchReg, eregOfRM(rm), TempReg, tmpd);
6092 uInstr2(cb, GET, sz, ArchReg, gregOfRM(rm), TempReg, tmpt);
6093 uInstr2(cb, ADD, sz, TempReg, tmpd, TempReg, tmpt);
6094 setFlagsFromUOpcode(cb, ADD);
6095 uInstr2(cb, PUT, sz, TempReg, tmpd, ArchReg, gregOfRM(rm));
6096 uInstr2(cb, PUT, sz, TempReg, tmpt, ArchReg, eregOfRM(rm));
6097 DIP("xadd%c %s, %s\n",
6098 nameISize(sz), nameIReg(sz,gregOfRM(rm)), nameIReg(sz,eregOfRM(rm)));
6099 return 1+eip0;
6100#endif
6101 } else {
6102 IRTemp addr = disAMode ( &len, sorb, delta0, dis_buf );
6103 assign( tmpd, loadLE(ty, mkexpr(addr)) );
6104 assign( tmpt0, getIReg(sz, gregOfRM(rm)) );
sewardj883b00b2004-09-11 09:30:24 +00006105 assign( tmpt1, binop(mkSizedOp(ty,Iop_Add8), mkexpr(tmpd), mkexpr(tmpt0)) );
sewardj2a2ba8b2004-11-08 13:14:06 +00006106 setFlags_DEP1_DEP2( Iop_Add8, tmpd, tmpt0, ty );
sewardj883b00b2004-09-11 09:30:24 +00006107 storeLE( mkexpr(addr), mkexpr(tmpt1) );
6108 putIReg(sz, gregOfRM(rm), mkexpr(tmpd));
6109 DIP("xadd%c %s, %s\n",
6110 nameISize(sz), nameIReg(sz,gregOfRM(rm)), dis_buf);
6111 return len+delta0;
6112 }
6113}
6114
sewardjc9a65702004-07-07 16:32:57 +00006115//-- /* Moves of Ew into a segment register.
6116//-- mov Ew, Sw meaning
6117//-- mov reg-or-mem, reg
6118//-- Is passed the a ptr to the modRM byte, and the data size. Returns
6119//-- the address advanced completely over this instruction.
6120//--
6121//-- Ew(src) is reg-or-mem
6122//-- Sw(dst) is seg reg.
6123//--
6124//-- If E is reg, --> GETw %Ew, tmpv
6125//-- PUTSEG tmpv, %Sw
6126//--
6127//-- If E is mem --> (getAddr E) -> tmpa
6128//-- LDw (tmpa), tmpb
6129//-- PUTSEG tmpb, %Sw
6130//-- */
6131//-- static
6132//-- Addr dis_mov_Ew_Sw ( UCodeBlock* cb,
6133//-- UChar sorb,
6134//-- Addr eip0 )
6135//-- {
6136//-- UChar rm = getUChar(eip0);
sewardjc9a43662004-11-30 18:51:59 +00006137//-- HChar dis_buf[50];
sewardjc9a65702004-07-07 16:32:57 +00006138//--
6139//-- if (epartIsReg(rm)) {
6140//-- Int tmpv = newTemp(cb);
6141//-- uInstr2(cb, GET, 2, ArchReg, eregOfRM(rm), TempReg, tmpv);
6142//-- uInstr2(cb, PUTSEG, 2, TempReg, tmpv, ArchRegS, gregOfRM(rm));
6143//-- DIP("movw %s,%s\n", nameIReg(2,eregOfRM(rm)), nameSReg(gregOfRM(rm)));
6144//-- return 1+eip0;
6145//-- }
6146//--
6147//-- /* E refers to memory */
6148//-- {
6149//-- UInt pair = disAMode ( cb, sorb, eip0, dis_buf );
6150//-- Int tmpa = LOW24(pair);
6151//-- Int tmpb = newTemp(cb);
6152//-- uInstr2(cb, LOAD, 2, TempReg, tmpa, TempReg, tmpb);
6153//-- uInstr2(cb, PUTSEG, 2, TempReg, tmpb, ArchRegS, gregOfRM(rm));
6154//-- DIP("movw %s,%s\n", dis_buf,nameSReg(gregOfRM(rm)));
6155//-- return HI8(pair)+eip0;
6156//-- }
6157//-- }
6158//--
6159//--
6160//-- /* Moves of a segment register to Ew.
6161//-- mov Sw, Ew meaning
6162//-- mov reg, reg-or-mem
6163//-- Is passed the a ptr to the modRM byte, and the data size. Returns
6164//-- the address advanced completely over this instruction.
6165//--
6166//-- Sw(src) is seg reg.
6167//-- Ew(dst) is reg-or-mem
6168//--
6169//-- If E is reg, --> GETSEG %Sw, tmp
6170//-- PUTW tmp, %Ew
6171//--
6172//-- If E is mem, --> (getAddr E) -> tmpa
6173//-- GETSEG %Sw, tmpv
6174//-- STW tmpv, (tmpa)
6175//-- */
sewardj063f02f2004-10-20 12:36:12 +00006176static
6177UInt dis_mov_Sw_Ew ( UChar sorb,
6178 Int sz,
6179 UInt delta0 )
6180{
6181 UChar rm = getIByte(delta0);
sewardjc9a43662004-11-30 18:51:59 +00006182 //HChar dis_buf[50];
sewardj063f02f2004-10-20 12:36:12 +00006183
6184 vassert(sz == 2 || sz == 4);
6185
6186 if (epartIsReg(rm)) {
6187 if (sz == 4)
6188 putIReg(4, eregOfRM(rm), unop(Iop_16Uto32, getSReg(gregOfRM(rm))));
6189 else
6190 putIReg(2, eregOfRM(rm), getSReg(gregOfRM(rm)));
6191
6192 DIP("mov %s,%s\n", nameSReg(gregOfRM(rm)), nameIReg(sz,eregOfRM(rm)));
6193 return 1+delta0;
6194 }
6195
6196 vassert(0);
6197#if 0
6198 /* E refers to memory */
6199 {
6200 UInt pair = disAMode ( cb, sorb, eip0, dis_buf );
6201 Int tmpa = LOW24(pair);
6202 Int tmpv = newTemp(cb);
6203 uInstr2(cb, GETSEG, 2, ArchRegS, gregOfRM(rm), TempReg, tmpv);
6204 uInstr2(cb, STORE, 2, TempReg, tmpv, TempReg, tmpa);
6205 DIP("mov %s,%s\n", nameSReg(gregOfRM(rm)), dis_buf);
6206 return HI8(pair)+eip0;
6207 }
6208#endif
6209}
6210
6211
6212
sewardjc9a65702004-07-07 16:32:57 +00006213//-- /* Simple MMX operations, either
6214//-- op (src)mmxreg, (dst)mmxreg
6215//-- or
6216//-- op (src)address, (dst)mmxreg
6217//-- opc is the byte following the 0x0F prefix.
6218//-- */
6219//-- static
6220//-- Addr dis_MMXop_regmem_to_reg ( UCodeBlock* cb,
6221//-- UChar sorb,
6222//-- Addr eip,
6223//-- UChar opc,
6224//-- Char* name,
6225//-- Bool show_granularity )
6226//-- {
sewardjc9a43662004-11-30 18:51:59 +00006227//-- HChar dis_buf[50];
sewardjc9a65702004-07-07 16:32:57 +00006228//-- UChar modrm = getUChar(eip);
6229//-- Bool isReg = epartIsReg(modrm);
6230//--
6231//-- if (isReg) {
6232//-- eip++;
6233//-- uInstr1(cb, MMX2, 0,
6234//-- Lit16,
6235//-- (((UShort)(opc)) << 8) | ((UShort)modrm) );
6236//-- } else {
6237//-- UInt pair = disAMode ( cb, sorb, eip, dis_buf );
6238//-- Int tmpa = LOW24(pair);
6239//-- eip += HI8(pair);
6240//-- uInstr2(cb, MMX2_MemRd, 8,
6241//-- Lit16,
6242//-- (((UShort)(opc)) << 8) | ((UShort)modrm),
6243//-- TempReg, tmpa);
6244//-- }
6245//--
6246//-- DIP("%s%s %s, %s\n",
6247//-- name, show_granularity ? nameMMXGran(opc & 3) : (Char*)"",
6248//-- ( isReg ? nameMMXReg(eregOfRM(modrm)) : dis_buf ),
6249//-- nameMMXReg(gregOfRM(modrm)) );
6250//--
6251//-- return eip;
6252//-- }
6253//--
6254//--
6255//-- /* Simple MMX operations, either
6256//-- op (src)mmxreg, (dst)mmxreg
6257//-- or
6258//-- op (src)address, (dst)mmxreg
6259//-- opc is the byte following the 0x0F prefix.
6260//-- */
6261//-- static
6262//-- Addr dis_MMXop_regmem_to_reg_Imm8 ( UCodeBlock* cb,
6263//-- UChar sorb,
6264//-- Addr eip,
6265//-- UChar opc,
6266//-- Char* name,
6267//-- Bool show_granularity )
6268//-- {
sewardjc9a43662004-11-30 18:51:59 +00006269//-- HChar dis_buf[50];
sewardjc9a65702004-07-07 16:32:57 +00006270//-- UChar modrm = getUChar(eip);
6271//-- UChar imm8;
6272//-- Bool isReg = epartIsReg(modrm);
6273//--
6274//-- if (isReg) {
6275//-- eip++;
6276//-- imm8 = getUChar(eip);
6277//-- eip++;
6278//-- uInstr2(cb, MMX3, 0,
6279//-- Lit16,
6280//-- (((UShort)(opc)) << 8) | ((UShort)modrm),
6281//-- Lit16,
6282//-- ((UShort)imm8));
6283//-- } else {
6284//-- UInt pair = disAMode ( cb, sorb, eip, dis_buf );
6285//-- Int tmpa = LOW24(pair);
6286//-- eip += HI8(pair);
6287//-- imm8 = getUChar(eip);
6288//-- eip++;
6289//-- uInstr3(cb, MMX2a1_MemRd, 8,
6290//-- Lit16,
6291//-- (((UShort)(opc)) << 8) | ((UShort)modrm),
6292//-- Lit16,
6293//-- ((UShort)imm8),
6294//-- TempReg, tmpa);
6295//-- }
6296//--
6297//-- DIP("%s%s %s, %s, $%d\n",
6298//-- name, show_granularity ? nameMMXGran(opc & 3) : (Char*)"",
6299//-- ( isReg ? nameMMXReg(eregOfRM(modrm)) : dis_buf ),
6300//-- nameMMXReg(gregOfRM(modrm)), (Int)imm8 );
6301//--
6302//-- return eip;
6303//-- }
6304//--
6305//--
6306//--
6307//-- /* Simple SSE operations, either
6308//-- op (src)xmmreg, (dst)xmmreg
6309//-- or
6310//-- op (src)address, (dst)xmmreg
6311//-- 3 opcode bytes.
6312//-- Supplied eip points to the first address mode byte.
6313//-- */
6314//-- static
6315//-- Addr dis_SSE3_reg_or_mem ( UCodeBlock* cb,
6316//-- UChar sorb,
sewardj5bd4d162004-11-10 13:02:48 +00006317//-- Addr eip,
6318//-- Int sz,
sewardjc9a65702004-07-07 16:32:57 +00006319//-- Char* name,
6320//-- UChar opc1,
6321//-- UChar opc2,
6322//-- UChar opc3 )
6323//-- {
sewardjc9a43662004-11-30 18:51:59 +00006324//-- HChar dis_buf[50];
sewardjc9a65702004-07-07 16:32:57 +00006325//-- UChar modrm = getUChar(eip);
6326//-- Bool isReg = epartIsReg(modrm);
6327//--
6328//-- if (isReg) {
6329//-- /* Completely internal SSE insn. */
6330//-- uInstr2(cb, SSE4, 0, /* ignore sz for internal ops */
6331//-- Lit16, (((UShort)opc1) << 8) | (UShort)opc2,
6332//-- Lit16, (((UShort)opc3) << 8) | (UShort)modrm );
6333//-- eip++;
6334//-- } else {
6335//-- UInt pair = disAMode ( cb, sorb, eip, dis_buf );
6336//-- Int tmpa = LOW24(pair);
6337//-- eip += HI8(pair);
6338//-- uInstr3(cb, SSE3a_MemRd, sz,
6339//-- Lit16, (((UShort)(opc1)) << 8) | ((UShort)opc2),
6340//-- Lit16, (((UShort)(opc3)) << 8) | ((UShort)modrm),
6341//-- TempReg, tmpa);
6342//-- }
6343//--
6344//-- DIP("%s %s, %s\n",
6345//-- name,
6346//-- ( isReg ? nameXMMReg(eregOfRM(modrm)) : dis_buf ),
6347//-- nameXMMReg(gregOfRM(modrm)) );
6348//--
6349//-- return eip;
6350//-- }
6351//--
6352//--
6353//-- /* Simple SSE operations, either
6354//-- op (src)xmmreg, (dst)xmmreg
6355//-- or
6356//-- op (src)address, (dst)xmmreg
6357//-- 2 opcode bytes.
6358//-- Supplied eip points to the first address mode byte.
6359//-- */
6360//-- static
6361//-- Addr dis_SSE2_reg_or_mem ( UCodeBlock* cb,
6362//-- UChar sorb,
6363//-- Addr eip,
6364//-- Int sz,
6365//-- Char* name,
6366//-- UChar opc1,
6367//-- UChar opc2 )
6368//-- {
sewardjc9a43662004-11-30 18:51:59 +00006369//-- HChar dis_buf[50];
sewardjc9a65702004-07-07 16:32:57 +00006370//-- UChar modrm = getUChar(eip);
6371//-- Bool isReg = epartIsReg(modrm);
6372//--
6373//-- if (isReg) {
6374//-- /* Completely internal SSE insn. */
6375//-- uInstr2(cb, SSE3, 0, /* ignore sz for internal ops */
6376//-- Lit16, (((UShort)opc1) << 8) | (UShort)opc2,
6377//-- Lit16, (UShort)modrm );
6378//-- eip++;
6379//-- } else {
6380//-- UInt pair = disAMode ( cb, sorb, eip, dis_buf );
6381//-- Int tmpa = LOW24(pair);
6382//-- eip += HI8(pair);
6383//-- uInstr3(cb, SSE2a_MemRd, sz,
6384//-- Lit16, (((UShort)(opc1)) << 8) | ((UShort)opc2),
6385//-- Lit16, (UShort)modrm,
6386//-- TempReg, tmpa);
6387//-- }
6388//-- DIP("%s %s, %s\n",
6389//-- name,
6390//-- ( isReg ? nameXMMReg(eregOfRM(modrm)) : dis_buf ),
6391//-- nameXMMReg(gregOfRM(modrm)) );
6392//--
6393//-- return eip;
6394//-- }
6395//--
6396//--
6397//-- /* Simple SSE operations, either
6398//-- op (src)xmmreg, (dst)xmmreg
6399//-- or
6400//-- op (src)address, (dst)xmmreg
6401//-- 2 opcode bytes and an 8-bit immediate after the amode.
6402//-- Supplied eip points to the first address mode byte.
6403//-- */
6404//-- static
6405//-- Addr dis_SSE2_reg_or_mem_Imm8 ( UCodeBlock* cb,
6406//-- UChar sorb,
sewardj5bd4d162004-11-10 13:02:48 +00006407//-- Addr eip,
sewardjc9a65702004-07-07 16:32:57 +00006408//-- Int sz,
6409//-- Char* name,
sewardj5bd4d162004-11-10 13:02:48 +00006410//-- UChar opc1,
6411//-- UChar opc2 )
sewardjc9a65702004-07-07 16:32:57 +00006412//-- {
sewardjc9a43662004-11-30 18:51:59 +00006413//-- HChar dis_buf[50];
sewardjc9a65702004-07-07 16:32:57 +00006414//-- UChar modrm = getUChar(eip);
6415//-- UChar imm8;
6416//-- Bool isReg = epartIsReg(modrm);
6417//--
6418//-- if (isReg) {
6419//-- /* Completely internal SSE insn. */
6420//-- eip++;
6421//-- imm8 = getUChar(eip);
6422//-- uInstr2(cb, SSE4, 0, /* ignore sz for internal ops */
6423//-- Lit16, (((UShort)opc1) << 8) | (UShort)opc2,
6424//-- Lit16, (((UShort)modrm) << 8) | (UShort)imm8 );
6425//-- eip++;
6426//-- } else {
6427//-- UInt pair = disAMode ( cb, sorb, eip, dis_buf );
6428//-- Int tmpa = LOW24(pair);
6429//-- eip += HI8(pair);
6430//-- imm8 = getUChar(eip);
6431//-- eip++;
6432//-- uInstr3(cb, SSE2a1_MemRd, sz,
6433//-- Lit16, (((UShort)(opc1)) << 8) | ((UShort)opc2),
6434//-- Lit16, (((UShort)(modrm)) << 8) | ((UShort)imm8),
6435//-- TempReg, tmpa);
6436//-- }
6437//-- DIP("%s %s, %s, $%d\n",
6438//-- name, ( isReg ? nameXMMReg(eregOfRM(modrm)) : dis_buf ),
6439//-- nameXMMReg(gregOfRM(modrm)), (Int)imm8 );
6440//-- return eip;
6441//-- }
6442//--
6443//--
6444//-- /* Simple SSE operations, either
6445//-- op (src)xmmreg, (dst)xmmreg
6446//-- or
6447//-- op (src)address, (dst)xmmreg
6448//-- 3 opcode bytes and an 8-bit immediate after the amode.
6449//-- Supplied eip points to the first address mode byte.
6450//-- */
6451//-- static
6452//-- Addr dis_SSE3_reg_or_mem_Imm8 ( UCodeBlock* cb,
6453//-- UChar sorb,
sewardj5bd4d162004-11-10 13:02:48 +00006454//-- Addr eip,
sewardjc9a65702004-07-07 16:32:57 +00006455//-- Int sz,
6456//-- Char* name,
sewardj5bd4d162004-11-10 13:02:48 +00006457//-- UChar opc1,
6458//-- UChar opc2,
sewardjc9a65702004-07-07 16:32:57 +00006459//-- UChar opc3 )
6460//-- {
sewardjc9a43662004-11-30 18:51:59 +00006461//-- HChar dis_buf[50];
sewardjc9a65702004-07-07 16:32:57 +00006462//-- UChar modrm = getUChar(eip);
6463//-- UChar imm8;
6464//-- Bool isReg = epartIsReg(modrm);
6465//--
6466//-- if (isReg) {
6467//-- /* Completely internal SSE insn. */
6468//-- eip++;
6469//-- imm8 = getUChar(eip);
6470//-- uInstr3(cb, SSE5, 0, /* ignore sz for internal ops */
6471//-- Lit16, (((UShort)opc1) << 8) | (UShort)opc2,
6472//-- Lit16, (((UShort)opc3) << 8) | (UShort)modrm,
6473//-- Lit16, (UShort)imm8 );
6474//-- eip++;
6475//-- } else {
6476//-- UInt pair = disAMode ( cb, sorb, eip, dis_buf );
6477//-- Int tmpa = LOW24(pair);
6478//-- eip += HI8(pair);
6479//-- imm8 = getUChar(eip);
6480//-- eip++;
6481//-- uInstr3(cb, SSE3a1_MemRd, sz,
6482//-- Lit16, (((UShort)(opc1)) << 8) | ((UShort)opc2),
6483//-- Lit16, (((UShort)(opc3)) << 8) | ((UShort)modrm),
6484//-- TempReg, tmpa);
6485//-- uLiteral(cb, imm8);
6486//-- }
6487//-- DIP("%s %s, %s, $%d\n",
6488//-- name, ( isReg ? nameXMMReg(eregOfRM(modrm)) : dis_buf ),
6489//-- nameXMMReg(gregOfRM(modrm)), (Int)imm8 );
6490//-- return eip;
6491//-- }
6492//--
6493//--
6494//-- /* Disassemble an SSE insn which is either a simple reg-reg move or a
6495//-- move between registers and memory. Supplied eip points to the
6496//-- first address mode byte.
6497//-- */
6498//-- static
6499//-- Addr dis_SSE3_load_store_or_mov ( UCodeBlock* cb,
6500//-- UChar sorb,
6501//-- Addr eip,
6502//-- Int sz,
sewardj5bd4d162004-11-10 13:02:48 +00006503//-- Bool is_store,
sewardjc9a65702004-07-07 16:32:57 +00006504//-- Char* name,
6505//-- UChar insn0,
6506//-- UChar insn1,
6507//-- UChar insn2 )
6508//-- {
sewardjc9a43662004-11-30 18:51:59 +00006509//-- HChar dis_buf[50];
sewardjc9a65702004-07-07 16:32:57 +00006510//-- UChar modrm = getUChar(eip);
6511//-- Bool isReg = epartIsReg(modrm);
6512//-- UInt pair;
6513//-- Int t1;
6514//--
6515//-- if (isReg) {
6516//-- /* Completely internal; we can issue SSE4. */
6517//-- eip++;
6518//-- uInstr2(cb, SSE4, 0, /* ignore sz for internal ops */
6519//-- Lit16, (((UShort)insn0) << 8) | (UShort)insn1,
6520//-- Lit16, (((UShort)insn2) << 8) | (UShort)modrm );
6521//-- } else {
6522//-- pair = disAMode ( cb, sorb, eip, dis_buf );
6523//-- t1 = LOW24(pair);
6524//-- eip += HI8(pair);
6525//-- uInstr3(cb, is_store ? SSE3a_MemWr : SSE3a_MemRd, sz,
6526//-- Lit16, (((UShort)insn0) << 8) | (UShort)insn1,
6527//-- Lit16, (((UShort)insn2) << 8) | (UShort)modrm,
6528//-- TempReg, t1 );
6529//-- }
6530//--
6531//-- if (is_store) {
6532//-- DIP("%s %s, %s\n",
6533//-- name,
6534//-- nameXMMReg(gregOfRM(modrm)),
6535//-- ( isReg ? nameXMMReg(eregOfRM(modrm)) : dis_buf ) );
6536//-- } else {
6537//-- DIP("%s %s, %s\n",
6538//-- name,
6539//-- ( isReg ? nameXMMReg(eregOfRM(modrm)) : dis_buf ),
6540//-- nameXMMReg(gregOfRM(modrm)) );
6541//-- }
6542//-- return eip;
6543//-- }
6544//--
6545//--
6546//-- /* Disassemble an SSE insn which is either a simple reg-reg move or a
6547//-- move between registers and memory. Supplied eip points to the
6548//-- first address mode byte. */
6549//-- static
6550//-- Addr dis_SSE2_load_store_or_mov ( UCodeBlock* cb,
6551//-- UChar sorb,
6552//-- Addr eip,
6553//-- Int sz,
sewardj5bd4d162004-11-10 13:02:48 +00006554//-- Bool is_store,
sewardjc9a65702004-07-07 16:32:57 +00006555//-- Char* name,
6556//-- UChar insn0,
6557//-- UChar insn1 )
6558//-- {
sewardjc9a43662004-11-30 18:51:59 +00006559//-- HChar dis_buf[50];
sewardjc9a65702004-07-07 16:32:57 +00006560//-- UChar modrm = getUChar(eip);
6561//-- Bool isReg = epartIsReg(modrm);
6562//-- UInt pair;
6563//-- Int t1;
6564//--
6565//-- if (isReg) {
6566//-- /* Completely internal; we can issue SSE3. */
6567//-- eip++;
6568//-- uInstr2(cb, SSE3, 0, /* ignore sz for internal ops */
6569//-- Lit16, (((UShort)insn0) << 8) | (UShort)insn1,
6570//-- Lit16, (UShort)modrm );
6571//-- } else {
6572//-- pair = disAMode ( cb, sorb, eip, dis_buf );
6573//-- t1 = LOW24(pair);
6574//-- eip += HI8(pair);
6575//-- uInstr3(cb, is_store ? SSE2a_MemWr : SSE2a_MemRd, sz,
6576//-- Lit16, (((UShort)insn0) << 8) | (UShort)insn1,
6577//-- Lit16, (UShort)modrm,
6578//-- TempReg, t1 );
6579//-- }
6580//--
6581//-- if (is_store) {
6582//-- DIP("%s %s, %s\n",
6583//-- name,
6584//-- nameXMMReg(gregOfRM(modrm)),
6585//-- ( isReg ? nameXMMReg(eregOfRM(modrm)) : dis_buf ) );
6586//-- } else {
6587//-- DIP("%s %s, %s\n",
6588//-- name,
6589//-- ( isReg ? nameXMMReg(eregOfRM(modrm)) : dis_buf ),
6590//-- nameXMMReg(gregOfRM(modrm)) );
6591//-- }
6592//-- return eip;
6593//-- }
6594//--
6595//--
6596//-- /* Simple SSE operations, either
6597//-- op (src)xmmreg, (dst)mmxreg
6598//-- or
6599//-- op (src)address, (dst)mmxreg
6600//-- 2 opcode bytes.
6601//-- Supplied eip points to the first address mode byte.
6602//-- */
6603//-- static
6604//-- Addr dis_SSE2_to_MMX ( UCodeBlock *cb,
6605//-- UChar sorb,
6606//-- Addr eip,
6607//-- Int sz,
6608//-- Char* name,
6609//-- UChar opc1,
6610//-- UChar opc2 )
6611//-- {
sewardjc9a43662004-11-30 18:51:59 +00006612//-- HChar dis_buf[50];
sewardjc9a65702004-07-07 16:32:57 +00006613//-- UChar modrm = getUChar(eip);
6614//-- if (epartIsReg(modrm)) {
6615//-- /* Completely internal SSE insn. */
6616//-- uInstr2(cb, SSE3, 0, /* ignore sz for internal ops */
6617//-- Lit16, (((UShort)opc1) << 8) | (UShort)opc2,
6618//-- Lit16, (UShort)modrm );
6619//-- DIP("%s %s, %s\n",
6620//-- name, nameXMMReg(eregOfRM(modrm)), nameMMXReg(gregOfRM(modrm)) );
6621//-- eip++;
6622//-- } else {
6623//-- UInt pair = disAMode ( cb, sorb, eip, dis_buf );
6624//-- Int tmpa = LOW24(pair);
6625//-- eip += HI8(pair);
6626//-- uInstr3(cb, SSE2a_MemRd, sz,
6627//-- Lit16, (((UShort)(opc1)) << 8) | ((UShort)opc2),
6628//-- Lit16, ((UShort)modrm),
6629//-- TempReg, tmpa);
6630//-- DIP("%s %s, %s\n", name, dis_buf, nameMMXReg(gregOfRM(modrm)));
6631//-- }
6632//-- return eip;
6633//-- }
6634//--
6635//--
6636//-- /* Simple SSE operations, either
6637//-- op (src)mmxreg, (dst)xmmreg
6638//-- or
6639//-- op (src)address, (dst)xmmreg
6640//-- 2 opcode bytes.
6641//-- Supplied eip points to the first address mode byte.
6642//-- */
6643//-- static
6644//-- Addr dis_SSE2_from_MMX ( UCodeBlock *cb,
6645//-- UChar sorb,
6646//-- Addr eip,
6647//-- Int sz,
6648//-- Char* name,
6649//-- UChar opc1,
6650//-- UChar opc2 )
6651//-- {
sewardjc9a43662004-11-30 18:51:59 +00006652//-- HChar dis_buf[50];
sewardjc9a65702004-07-07 16:32:57 +00006653//-- UChar modrm = getUChar(eip);
6654//-- if (epartIsReg(modrm)) {
6655//-- /* Completely internal SSE insn. */
6656//-- uInstr2(cb, SSE3, 0, /* ignore sz for internal ops */
6657//-- Lit16, (((UShort)opc1) << 8) | (UShort)opc2,
6658//-- Lit16, (UShort)modrm );
6659//-- DIP("%s %s, %s\n",
6660//-- name, nameMMXReg(eregOfRM(modrm)), nameXMMReg(gregOfRM(modrm)) );
6661//-- eip++;
6662//-- } else {
6663//-- UInt pair = disAMode ( cb, sorb, eip, dis_buf );
6664//-- Int tmpa = LOW24(pair);
6665//-- eip += HI8(pair);
6666//-- uInstr3(cb, SSE2a_MemRd, sz,
6667//-- Lit16, (((UShort)(opc1)) << 8) | ((UShort)opc2),
6668//-- Lit16, ((UShort)modrm),
6669//-- TempReg, tmpa);
6670//-- DIP("%s %s, %s\n", name, dis_buf, nameXMMReg(gregOfRM(modrm)));
6671//-- }
6672//-- return eip;
6673//-- }
6674//--
6675//--
6676//-- /* Simple SSE operations, either
6677//-- op (src)xmmreg, (dst)mmxreg
6678//-- or
6679//-- op (src)address, (dst)mmxreg
6680//-- 3 opcode bytes.
6681//-- Supplied eip points to the first address mode byte.
6682//-- */
6683//-- static
6684//-- Addr dis_SSE3_to_MMX ( UCodeBlock *cb,
6685//-- UChar sorb,
6686//-- Addr eip,
6687//-- Int sz,
6688//-- Char* name,
6689//-- UChar opc1,
6690//-- UChar opc2,
6691//-- UChar opc3 )
6692//-- {
sewardjc9a43662004-11-30 18:51:59 +00006693//-- HChar dis_buf[50];
sewardjc9a65702004-07-07 16:32:57 +00006694//-- UChar modrm = getUChar(eip);
6695//-- if (epartIsReg(modrm)) {
6696//-- /* Completely internal SSE insn. */
6697//-- uInstr2(cb, SSE4, 0, /* ignore sz for internal ops */
6698//-- Lit16, (((UShort)opc1) << 8) | (UShort)opc2,
6699//-- Lit16, (((UShort)opc3) << 8) | (UShort)modrm );
6700//-- DIP("%s %s, %s\n",
6701//-- name, nameXMMReg(eregOfRM(modrm)), nameMMXReg(gregOfRM(modrm)) );
6702//-- eip++;
6703//-- } else {
6704//-- UInt pair = disAMode ( cb, sorb, eip, dis_buf );
6705//-- Int tmpa = LOW24(pair);
6706//-- eip += HI8(pair);
6707//-- uInstr3(cb, SSE3a_MemRd, sz,
6708//-- Lit16, (((UShort)(opc1)) << 8) | ((UShort)opc2),
6709//-- Lit16, (((UShort)(opc3)) << 8) | ((UShort)modrm),
6710//-- TempReg, tmpa);
6711//-- DIP("%s %s, %s\n", name, dis_buf, nameMMXReg(gregOfRM(modrm)));
6712//-- }
6713//-- return eip;
6714//-- }
6715//--
6716//--
6717//-- /* Simple SSE operations, either
6718//-- op (src)mmxreg, (dst)xmmreg
6719//-- or
6720//-- op (src)address, (dst)xmmreg
6721//-- 3 opcode bytes.
6722//-- Supplied eip points to the first address mode byte.
6723//-- */
6724//-- static
6725//-- Addr dis_SSE3_from_MMX ( UCodeBlock *cb,
6726//-- UChar sorb,
6727//-- Addr eip,
6728//-- Int sz,
6729//-- Char* name,
6730//-- UChar opc1,
6731//-- UChar opc2,
6732//-- UChar opc3 )
6733//-- {
sewardjc9a43662004-11-30 18:51:59 +00006734//-- HChar dis_buf[50];
sewardjc9a65702004-07-07 16:32:57 +00006735//-- UChar modrm = getUChar(eip);
6736//-- if (epartIsReg(modrm)) {
6737//-- /* Completely internal SSE insn. */
6738//-- uInstr2(cb, SSE4, 0, /* ignore sz for internal ops */
6739//-- Lit16, (((UShort)opc1) << 8) | (UShort)opc2,
6740//-- Lit16, (((UShort)opc3) << 8) | (UShort)modrm );
6741//-- DIP("%s %s, %s\n",
6742//-- name, nameMMXReg(eregOfRM(modrm)), nameXMMReg(gregOfRM(modrm)) );
6743//-- eip++;
6744//-- } else {
6745//-- UInt pair = disAMode ( cb, sorb, eip, dis_buf );
6746//-- Int tmpa = LOW24(pair);
6747//-- eip += HI8(pair);
6748//-- uInstr3(cb, SSE3a_MemRd, sz,
6749//-- Lit16, (((UShort)(opc1)) << 8) | ((UShort)opc2),
6750//-- Lit16, (((UShort)(opc3)) << 8) | ((UShort)modrm),
6751//-- TempReg, tmpa);
6752//-- DIP("%s %s, %s\n", name, dis_buf, nameXMMReg(gregOfRM(modrm)));
6753//-- }
6754//-- return eip;
6755//-- }
6756//--
6757//--
6758//-- static
6759//-- void dis_push_segreg ( UCodeBlock* cb, UInt sreg, Int sz )
6760//-- {
6761//-- Int t1 = newTemp(cb), t2 = newTemp(cb);
6762//-- vg_assert(sz == 2 || sz == 4);
6763//-- uInstr2(cb, GETSEG, 2, ArchRegS, sreg, TempReg, t1);
6764//-- uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t2);
6765//-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
6766//-- uLiteral(cb, sz);
6767//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
6768//-- uInstr2(cb, STORE, 2, TempReg, t1, TempReg, t2);
6769//-- DIP("push %s\n", VG_(name_of_seg_reg)(sreg));
6770//-- }
6771//--
6772//-- static
6773//-- void dis_pop_segreg ( UCodeBlock* cb, UInt sreg, Int sz )
6774//-- {
6775//-- Int t1 = newTemp(cb), t2 = newTemp(cb);
6776//-- vg_assert(sz == 2 || sz == 4);
6777//-- uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t2);
6778//-- uInstr2(cb, LOAD, 2, TempReg, t2, TempReg, t1);
6779//-- uInstr2(cb, ADD, 4, Literal, 0, TempReg, t2);
6780//-- uLiteral(cb, sz);
6781//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
6782//-- uInstr2(cb, PUTSEG, 2, TempReg, t1, ArchRegS, sreg);
6783//-- DIP("pop %s\n", VG_(name_of_seg_reg)(sreg));
6784//-- }
sewardje05c42c2004-07-08 20:25:10 +00006785
6786static
6787void dis_ret ( UInt d32 )
6788{
6789 IRTemp t1 = newTemp(Ity_I32), t2 = newTemp(Ity_I32);
6790 assign(t1, getIReg(4,R_ESP));
6791 assign(t2, loadLE(Ity_I32,mkexpr(t1)));
6792 putIReg(4, R_ESP,binop(Iop_Add32, mkexpr(t1), mkU32(4+d32)));
sewardj78c19df2004-07-12 22:49:27 +00006793 jmp_treg(Ijk_Ret,t2);
sewardje05c42c2004-07-08 20:25:10 +00006794}
6795
sewardj4cb918d2004-12-03 19:43:31 +00006796/*------------------------------------------------------------*/
6797/*--- SSE/SSE2/SSE3 helpers ---*/
6798/*------------------------------------------------------------*/
sewardjc9a43662004-11-30 18:51:59 +00006799
sewardj129b3d92004-12-05 15:42:05 +00006800/* Worker function; do not call directly.
6801 Handles full width G = G `op` E and G = (not G) `op` E.
6802*/
6803
6804static UInt dis_SSE_E_to_G_all_wrk (
sewardj1e6ad742004-12-02 16:16:11 +00006805 UChar sorb, UInt delta,
6806 HChar* opname, IROp op,
6807 Bool invertG
6808 )
sewardjc9a43662004-11-30 18:51:59 +00006809{
sewardj1e6ad742004-12-02 16:16:11 +00006810 HChar dis_buf[50];
6811 Int alen;
6812 IRTemp addr;
6813 UChar rm = getIByte(delta);
6814 IRExpr* gpart
6815 = invertG ? binop( Iop_Xor128,
6816 getXMMReg(gregOfRM(rm)),
6817 mkV128(0xFFFF) )
6818 : getXMMReg(gregOfRM(rm));
sewardjc9a43662004-11-30 18:51:59 +00006819 if (epartIsReg(rm)) {
6820 putXMMReg( gregOfRM(rm),
sewardj1e6ad742004-12-02 16:16:11 +00006821 binop(op, gpart,
6822 getXMMReg(eregOfRM(rm))) );
sewardjc9a43662004-11-30 18:51:59 +00006823 DIP("%s %s,%s\n", opname,
6824 nameXMMReg(eregOfRM(rm)),
6825 nameXMMReg(gregOfRM(rm)) );
6826 return delta+1;
6827 } else {
sewardj1e6ad742004-12-02 16:16:11 +00006828 addr = disAMode ( &alen, sorb, delta, dis_buf );
6829 putXMMReg( gregOfRM(rm),
6830 binop(op, gpart,
6831 loadLE(Ity_V128, mkexpr(addr))) );
6832 DIP("%s %s,%s\n", opname,
6833 dis_buf,
6834 nameXMMReg(gregOfRM(rm)) );
6835 return delta+alen;
sewardjc9a43662004-11-30 18:51:59 +00006836 }
6837}
6838
sewardj129b3d92004-12-05 15:42:05 +00006839
6840/* All lanes SSE binary operation, G = G `op` E. */
sewardj1e6ad742004-12-02 16:16:11 +00006841
6842static
sewardj129b3d92004-12-05 15:42:05 +00006843UInt dis_SSE_E_to_G_all ( UChar sorb, UInt delta, HChar* opname, IROp op )
sewardj1e6ad742004-12-02 16:16:11 +00006844{
sewardj129b3d92004-12-05 15:42:05 +00006845 return dis_SSE_E_to_G_all_wrk( sorb, delta, opname, op, False );
sewardj1e6ad742004-12-02 16:16:11 +00006846}
6847
sewardj129b3d92004-12-05 15:42:05 +00006848/* All lanes SSE binary operation, G = (not G) `op` E. */
6849
6850static
6851UInt dis_SSE_E_to_G_all_invG ( UChar sorb, UInt delta,
6852 HChar* opname, IROp op )
6853{
6854 return dis_SSE_E_to_G_all_wrk( sorb, delta, opname, op, True );
6855}
6856
6857/* Lowest 32-bit lane only SSE binary operation, G = G `op` E. */
6858
6859static UInt dis_SSE_E_to_G_lo32 ( UChar sorb, UInt delta,
6860 HChar* opname, IROp op )
6861{
6862 HChar dis_buf[50];
6863 Int alen;
6864 IRTemp addr;
6865 UChar rm = getIByte(delta);
6866 IRExpr* gpart = getXMMReg(gregOfRM(rm));
6867 if (epartIsReg(rm)) {
6868 putXMMReg( gregOfRM(rm),
6869 binop(op, gpart,
6870 getXMMReg(eregOfRM(rm))) );
6871 DIP("%s %s,%s\n", opname,
6872 nameXMMReg(eregOfRM(rm)),
6873 nameXMMReg(gregOfRM(rm)) );
6874 return delta+1;
6875 } else {
6876 /* We can only do a 32-bit memory read, so the upper 3/4 of the
6877 E operand needs to be made simply of zeroes. */
6878 IRTemp epart = newTemp(Ity_V128);
6879 addr = disAMode ( &alen, sorb, delta, dis_buf );
6880 assign( epart, unop( Iop_32Uto128,
6881 loadLE(Ity_I32, mkexpr(addr))) );
6882 putXMMReg( gregOfRM(rm),
6883 binop(op, gpart, mkexpr(epart)) );
6884 DIP("%s %s,%s\n", opname,
6885 dis_buf,
6886 nameXMMReg(gregOfRM(rm)) );
6887 return delta+alen;
6888 }
6889}
6890
6891/* All lanes unary SSE operation, G = op(E). */
6892
6893static UInt dis_SSE_E_to_G_unary_all (
sewardj0bd7ce62004-12-05 02:47:40 +00006894 UChar sorb, UInt delta,
6895 HChar* opname, IROp op
6896 )
6897{
6898 HChar dis_buf[50];
6899 Int alen;
6900 IRTemp addr;
6901 UChar rm = getIByte(delta);
6902 if (epartIsReg(rm)) {
6903 putXMMReg( gregOfRM(rm),
6904 unop(op, getXMMReg(eregOfRM(rm))) );
6905 DIP("%s %s,%s\n", opname,
6906 nameXMMReg(eregOfRM(rm)),
6907 nameXMMReg(gregOfRM(rm)) );
6908 return delta+1;
6909 } else {
6910 addr = disAMode ( &alen, sorb, delta, dis_buf );
6911 putXMMReg( gregOfRM(rm),
6912 unop(op, loadLE(Ity_V128, mkexpr(addr))) );
6913 DIP("%s %s,%s\n", opname,
6914 dis_buf,
6915 nameXMMReg(gregOfRM(rm)) );
6916 return delta+alen;
6917 }
6918}
6919
sewardj129b3d92004-12-05 15:42:05 +00006920/* Lowest 32-bit lane only unary SSE operation, G = op(E). */
sewardj0bd7ce62004-12-05 02:47:40 +00006921
sewardj129b3d92004-12-05 15:42:05 +00006922static UInt dis_SSE_E_to_G_unary_lo32 (
6923 UChar sorb, UInt delta,
6924 HChar* opname, IROp op
6925 )
6926{
6927 /* First we need to get the old G value and patch the low 32 bits
6928 of the E operand into it. Then apply op and write back to G. */
6929 HChar dis_buf[50];
6930 Int alen;
6931 IRTemp addr;
6932 UChar rm = getIByte(delta);
6933 IRTemp oldG0 = newTemp(Ity_V128);
6934 IRTemp oldG1 = newTemp(Ity_V128);
6935
6936 assign( oldG0, getXMMReg(gregOfRM(rm)) );
6937
6938 if (epartIsReg(rm)) {
6939 assign( oldG1,
6940 binop( Iop_Set128lo32,
6941 mkexpr(oldG0),
6942 getXMMRegLane32(0, eregOfRM(rm))) );
6943 putXMMReg( gregOfRM(rm), unop(op, mkexpr(oldG1)) );
6944 DIP("%s %s,%s\n", opname,
6945 nameXMMReg(eregOfRM(rm)),
6946 nameXMMReg(gregOfRM(rm)) );
6947 return delta+1;
6948 } else {
6949 addr = disAMode ( &alen, sorb, delta, dis_buf );
6950 assign( oldG1,
6951 binop( Iop_Set128lo32,
6952 mkexpr(oldG0),
6953 loadLE(Ity_I32, mkexpr(addr)) ));
6954 putXMMReg( gregOfRM(rm), unop(op, mkexpr(oldG1)) );
6955 DIP("%s %s,%s\n", opname,
6956 dis_buf,
6957 nameXMMReg(gregOfRM(rm)) );
6958 return delta+alen;
6959 }
6960}
6961
6962/* Helper for doing SSE 32Fx4 comparisons. */
sewardj0bd7ce62004-12-05 02:47:40 +00006963
sewardj1e6ad742004-12-02 16:16:11 +00006964static void findSSECmpOp ( Bool* needNot, IROp* op,
6965 Int imm8, Bool all_lanes, Int sz )
6966{
6967 imm8 &= 7;
6968 *needNot = False;
6969 *op = Iop_INVALID;
6970 if (imm8 >= 4) {
6971 *needNot = True;
6972 imm8 -= 4;
6973 }
6974
6975 if (sz == 4 && all_lanes) {
6976 switch (imm8) {
6977 case 0: *op = Iop_CmpEQ32Fx4; return;
6978 case 1: *op = Iop_CmpLT32Fx4; return;
6979 case 2: *op = Iop_CmpLE32Fx4; return;
6980 case 3: *op = Iop_CmpUN32Fx4; return;
6981 default: break;
6982 }
6983 }
6984 if (sz == 4 && !all_lanes) {
6985 switch (imm8) {
6986 case 0: *op = Iop_CmpEQ32F0x4; return;
6987 case 1: *op = Iop_CmpLT32F0x4; return;
6988 case 2: *op = Iop_CmpLE32F0x4; return;
6989 case 3: *op = Iop_CmpUN32F0x4; return;
6990 default: break;
6991 }
6992 }
6993 if (sz == 8) {
6994 }
6995 vpanic("findSSECmpOp(x86,guest)");
6996}
6997
sewardj129b3d92004-12-05 15:42:05 +00006998/* Handles SSE 32F comparisons. */
6999
sewardj1e6ad742004-12-02 16:16:11 +00007000static UInt dis_SSEcmp_E_to_G ( UChar sorb, UInt delta,
7001 HChar* opname, Bool all_lanes, Int sz )
7002{
7003 HChar dis_buf[50];
7004 Int alen, imm8;
7005 IRTemp addr;
7006 Bool needNot = False;
7007 IROp op = Iop_INVALID;
7008 IRTemp plain = newTemp(Ity_V128);
7009 UChar rm = getIByte(delta);
7010 UShort mask = 0;
7011 vassert(sz == 4 || sz == 8);
7012 if (epartIsReg(rm)) {
7013 imm8 = getIByte(delta+1);
7014 findSSECmpOp(&needNot, &op, imm8, all_lanes, sz);
7015 assign( plain, binop(op, getXMMReg(gregOfRM(rm)),
7016 getXMMReg(eregOfRM(rm))) );
7017 delta += 2;
7018 DIP("%s $%d,%s,%s\n", opname,
7019 (Int)imm8,
7020 nameXMMReg(eregOfRM(rm)),
7021 nameXMMReg(gregOfRM(rm)) );
7022 } else {
7023 addr = disAMode ( &alen, sorb, delta, dis_buf );
7024 imm8 = getIByte(delta+alen);
7025 findSSECmpOp(&needNot, &op, imm8, all_lanes, sz);
7026 assign( plain, binop(op, getXMMReg(gregOfRM(rm)),
7027 loadLE(Ity_V128, mkexpr(addr))) );
7028 delta += alen+1;
7029 DIP("%s $%d,%s,%s\n", opname,
7030 (Int)imm8,
7031 dis_buf,
7032 nameXMMReg(gregOfRM(rm)) );
7033 }
7034
7035 if (needNot && all_lanes)
7036 mask = 0xFFFF;
7037 if (needNot && !all_lanes)
7038 mask = 0x000F;
7039
7040 putXMMReg( gregOfRM(rm),
7041 needNot ? binop(Iop_Xor128, mkexpr(plain), mkV128(mask))
7042 : mkexpr(plain) );
7043 return delta;
7044}
7045
sewardjc9a65702004-07-07 16:32:57 +00007046
sewardj4cb918d2004-12-03 19:43:31 +00007047static IRExpr* /* :: Ity_I32 */ get_sse_roundingmode ( void )
7048{
7049 return binop( Iop_And32,
7050 IRExpr_Get( OFFB_SSEROUND, Ity_I32 ),
7051 mkU32(3) );
7052}
7053
7054
sewardjc9a65702004-07-07 16:32:57 +00007055/*------------------------------------------------------------*/
sewardjce70a5c2004-10-18 14:09:54 +00007056/*--- Disassemble a single instruction ---*/
sewardjc9a65702004-07-07 16:32:57 +00007057/*------------------------------------------------------------*/
7058
sewardjce70a5c2004-10-18 14:09:54 +00007059/* Disassemble a single instruction into IR. The instruction
7060 is located in host memory at &guest_code[delta].
7061 Set *size to be the size of the instruction.
7062 If the returned value is Dis_Resteer,
7063 the next guest address is assigned to *whereNext. If resteerOK
7064 is False, disInstr may not return Dis_Resteer. */
7065
7066static DisResult disInstr ( /*IN*/ Bool resteerOK,
sewardj5bd4d162004-11-10 13:02:48 +00007067 /*IN*/ Bool (*resteerOkFn) ( Addr64 ),
sewardjce70a5c2004-10-18 14:09:54 +00007068 /*IN*/ UInt delta,
7069 /*OUT*/ UInt* size,
7070 /*OUT*/ Addr64* whereNext )
sewardjc9a65702004-07-07 16:32:57 +00007071{
sewardjce70a5c2004-10-18 14:09:54 +00007072 IRType ty;
sewardjb5452082004-12-04 20:33:02 +00007073 IRTemp addr, t0, t1, t2, t3, t4, t5, t6;
sewardjce70a5c2004-10-18 14:09:54 +00007074 Int alen;
7075 UChar opc, modrm, abyte;
7076 UInt d32;
sewardjc9a43662004-11-30 18:51:59 +00007077 HChar dis_buf[50];
sewardjce70a5c2004-10-18 14:09:54 +00007078 Int am_sz, d_sz;
7079 DisResult whatNext = Dis_Continue;
sewardjc9a43662004-11-30 18:51:59 +00007080 UChar* insn; /* used in SSE decoders */
sewardjce70a5c2004-10-18 14:09:54 +00007081
sewardjc9a65702004-07-07 16:32:57 +00007082 //Char loc_buf[M_VG_ERRTXT];
7083
7084 /* Holds eip at the start of the insn, so that we can print
7085 consistent error messages for unimplemented insns. */
7086 UInt delta_start = delta;
7087
7088 /* sz denotes the nominal data-op size of the insn; we change it to
7089 2 if an 0x66 prefix is seen */
7090 Int sz = 4;
7091
7092 /* sorb holds the segment-override-prefix byte, if any. Zero if no
7093 prefix has been seen, else one of {0x26, 0x3E, 0x64, 0x65}
7094 indicating the prefix. */
7095 UChar sorb = 0;
7096
sewardjce70a5c2004-10-18 14:09:54 +00007097 /* If we don't set *size properly, this causes bbToIR_X86Instr to
7098 assert. */
7099 *size = 0;
7100
sewardjb5452082004-12-04 20:33:02 +00007101 addr = t0 = t1 = t2 = t3 = t4 = t5 = t6 = IRTemp_INVALID;
sewardjc9a65702004-07-07 16:32:57 +00007102
sewardjce70a5c2004-10-18 14:09:54 +00007103 DIP("\t0x%x: ", guest_eip_bbstart+delta);
sewardjc9a65702004-07-07 16:32:57 +00007104
sewardj750f4072004-07-26 22:39:11 +00007105 /* Spot the client-request magic sequence. */
7106 {
7107 UChar* code = (UChar*)(guest_code + delta);
7108 /* Spot this:
7109 C1C01D roll $29, %eax
7110 C1C003 roll $3, %eax
7111 C1C81B rorl $27, %eax
7112 C1C805 rorl $5, %eax
7113 C1C00D roll $13, %eax
7114 C1C013 roll $19, %eax
7115 */
7116 if (code[ 0] == 0xC1 && code[ 1] == 0xC0 && code[ 2] == 0x1D &&
7117 code[ 3] == 0xC1 && code[ 4] == 0xC0 && code[ 5] == 0x03 &&
7118 code[ 6] == 0xC1 && code[ 7] == 0xC8 && code[ 8] == 0x1B &&
7119 code[ 9] == 0xC1 && code[10] == 0xC8 && code[11] == 0x05 &&
7120 code[12] == 0xC1 && code[13] == 0xC0 && code[14] == 0x0D &&
7121 code[15] == 0xC1 && code[16] == 0xC0 && code[17] == 0x13
7122 ) {
sewardjce70a5c2004-10-18 14:09:54 +00007123 DIP("%%edx = client_request ( %%eax )\n");
sewardj750f4072004-07-26 22:39:11 +00007124 delta += 18;
sewardjce70a5c2004-10-18 14:09:54 +00007125 jmp_lit(Ijk_ClientReq, guest_eip_bbstart+delta);
7126 whatNext = Dis_StopHere;
7127 goto decode_success;
sewardj750f4072004-07-26 22:39:11 +00007128 }
7129 }
sewardjc9a65702004-07-07 16:32:57 +00007130
7131 /* Skip a LOCK prefix. */
7132 if (getIByte(delta) == 0xF0) {
njn285f22c2004-11-23 17:11:49 +00007133 if (0) vex_printf("vex x86->IR: ignoring LOCK prefix\n");
sewardjc9a65702004-07-07 16:32:57 +00007134 delta++;
7135 }
7136
7137 /* Detect operand-size overrides. */
7138 if (getIByte(delta) == 0x66) { sz = 2; delta++; };
7139
7140 /* segment override prefixes come after the operand-size override,
7141 it seems */
7142 switch (getIByte(delta)) {
7143 case 0x3E: /* %DS: */
7144 case 0x26: /* %ES: */
7145 case 0x64: /* %FS: */
7146 case 0x65: /* %GS: */
7147 sorb = getIByte(delta); delta++;
7148 break;
7149 case 0x2E: /* %CS: */
7150 /* 2E prefix on a conditional branch instruction is a
7151 branch-prediction hint, which can safely be ignored. */
7152 {
7153 UChar op1 = getIByte(delta+1);
7154 UChar op2 = getIByte(delta+2);
7155 if ((op1 >= 0x70 && op1 <= 0x7F)
7156 || (op1 == 0xE3)
7157 || (op1 == 0x0F && op2 >= 0x80 && op2 <= 0x8F)) {
sewardjce70a5c2004-10-18 14:09:54 +00007158 vex_printf("vex x86->IR: ignoring branch hint\n");
sewardjc9a65702004-07-07 16:32:57 +00007159 sorb = getIByte(delta); delta++;
7160 break;
7161 }
7162 }
7163 unimplemented("x86 segment override (SEG=CS) prefix");
7164 /*NOTREACHED*/
7165 break;
7166 case 0x36: /* %SS: */
7167 unimplemented("x86 segment override (SEG=SS) prefix");
7168 /*NOTREACHED*/
7169 break;
7170 default:
7171 break;
7172 }
7173
sewardjc9a43662004-11-30 18:51:59 +00007174 /* ---------------------------------------------------- */
7175 /* --- The SSE decoder. --- */
7176 /* ---------------------------------------------------- */
7177
sewardj4cb918d2004-12-03 19:43:31 +00007178 /* What did I do to deserve SSE ? Perhaps I was really bad in a
7179 previous life? */
7180
sewardjc9a43662004-11-30 18:51:59 +00007181 /* Note, this doesn't handle SSE2 or SSE3. */
7182
7183 insn = (UChar*)&guest_code[delta];
7184
sewardjc9a43662004-11-30 18:51:59 +00007185 /* 0F 58 = ADDPS -- add 32Fx4 from R/M to R */
7186 if (insn[0] == 0x0F && insn[1] == 0x58) {
7187 vassert(sz == 4);
sewardj129b3d92004-12-05 15:42:05 +00007188 delta = dis_SSE_E_to_G_all( sorb, delta+2, "addps", Iop_Add32Fx4 );
sewardjc9a43662004-11-30 18:51:59 +00007189 goto decode_success;
7190 }
7191
sewardj1e6ad742004-12-02 16:16:11 +00007192 /* F3 0F 58 = ADDSS -- add 32F0x4 from R/M to R */
7193 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x58) {
7194 vassert(sz == 4);
sewardj129b3d92004-12-05 15:42:05 +00007195 delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "addss", Iop_Add32F0x4 );
sewardj1e6ad742004-12-02 16:16:11 +00007196 goto decode_success;
7197 }
7198
7199 /* 0F 55 = ANDNPS -- G = (not G) and E */
7200 if (insn[0] == 0x0F && insn[1] == 0x55) {
7201 vassert(sz == 4);
sewardj129b3d92004-12-05 15:42:05 +00007202 delta = dis_SSE_E_to_G_all_invG( sorb, delta+2, "andnps", Iop_And128 );
sewardj1e6ad742004-12-02 16:16:11 +00007203 goto decode_success;
7204 }
7205
7206 /* 0F 54 = ANDPS -- G = G and E */
7207 if (insn[0] == 0x0F && insn[1] == 0x54) {
7208 vassert(sz == 4);
sewardj129b3d92004-12-05 15:42:05 +00007209 delta = dis_SSE_E_to_G_all( sorb, delta+2, "andps", Iop_And128 );
sewardj1e6ad742004-12-02 16:16:11 +00007210 goto decode_success;
7211 }
7212
7213 /* 0F C2 = CMPPS -- 32Fx4 comparison from R/M to R */
7214 if (insn[0] == 0x0F && insn[1] == 0xC2) {
7215 vassert(sz == 4);
7216 delta = dis_SSEcmp_E_to_G( sorb, delta+2, "cmpps", True, 4 );
7217 goto decode_success;
7218 }
7219
7220 /* F3 0F C2 = CMPSS -- 32F0x4 comparison from R/M to R */
7221 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0xC2) {
7222 vassert(sz == 4);
7223 delta = dis_SSEcmp_E_to_G( sorb, delta+3, "cmpss", False, 4 );
7224 goto decode_success;
7225 }
sewardjc9a43662004-11-30 18:51:59 +00007226
sewardj67e002d2004-12-02 18:16:33 +00007227 /* 0F 2F = COMISS -- 32F0x4 comparison G,E, and set ZCP */
7228 if (insn[0] == 0x0F && insn[1] == 0x2F) {
7229 IRTemp argL = newTemp(Ity_F32);
7230 IRTemp argR = newTemp(Ity_F32);
7231 vassert(sz == 4);
7232 modrm = getIByte(delta+2);
7233 if (epartIsReg(modrm)) {
7234 assign( argR, getXMMRegLane32F( eregOfRM(modrm), 0/*lowest lane*/ ) );
7235 delta += 2+1;
7236 DIP("comiss %s,%s\n", nameXMMReg(eregOfRM(modrm)),
7237 nameXMMReg(gregOfRM(modrm)) );
7238 } else {
7239 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
7240 assign( argR, loadLE(Ity_F32, mkexpr(addr)) );
7241 delta += 2+alen;
7242 DIP("comiss %s,%s\n", dis_buf,
7243 nameXMMReg(gregOfRM(modrm)) );
7244 }
7245 assign( argL, getXMMRegLane32F( gregOfRM(modrm), 0/*lowest lane*/ ) );
7246
7247 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
7248 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
7249 stmt( IRStmt_Put(
7250 OFFB_CC_DEP1,
7251 binop( Iop_And32,
7252 binop(Iop_CmpF64,
7253 unop(Iop_F32toF64,mkexpr(argL)),
7254 unop(Iop_F32toF64,mkexpr(argR))),
7255 mkU32(0x45)
7256 )));
7257
7258 goto decode_success;
7259 }
sewardjc9a43662004-11-30 18:51:59 +00007260
sewardj4cb918d2004-12-03 19:43:31 +00007261 /* 0F 2A = CVTPI2PS -- convert 2 x I32 in mem/mmx to 2 x F32 in low
7262 half xmm */
7263 if (insn[0] == 0x0F && insn[1] == 0x2A) {
7264 IRTemp arg64 = newTemp(Ity_I64);
7265 IRTemp rmode = newTemp(Ity_I32);
7266 vassert(sz == 4);
7267
7268 modrm = getIByte(delta+2);
7269 do_MMX_preamble();
7270 if (epartIsReg(modrm)) {
7271 assign( arg64, getMMXReg(eregOfRM(modrm)) );
7272 delta += 2+1;
7273 DIP("cvtpi2ps %s,%s\n", nameMMXReg(eregOfRM(modrm)),
7274 nameXMMReg(gregOfRM(modrm)));
7275 } else {
7276 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
7277 assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
7278 delta += 2+alen;
7279 DIP("cvtpi2ps %s,%s\n", dis_buf,
7280 nameXMMReg(gregOfRM(modrm)) );
7281 }
7282
7283 assign( rmode, get_sse_roundingmode() );
7284
7285 putXMMRegLane32F(
sewardj3bca9062004-12-04 14:36:09 +00007286 gregOfRM(modrm), 0,
7287 binop(Iop_F64toF32,
sewardj4cb918d2004-12-03 19:43:31 +00007288 mkexpr(rmode),
sewardj3bca9062004-12-04 14:36:09 +00007289 unop(Iop_I32toF64,
7290 unop(Iop_64to32, mkexpr(arg64)) )) );
sewardj4cb918d2004-12-03 19:43:31 +00007291
7292 putXMMRegLane32F(
7293 gregOfRM(modrm), 1,
sewardj3bca9062004-12-04 14:36:09 +00007294 binop(Iop_F64toF32,
sewardj4cb918d2004-12-03 19:43:31 +00007295 mkexpr(rmode),
sewardj3bca9062004-12-04 14:36:09 +00007296 unop(Iop_I32toF64,
7297 unop(Iop_64HIto32, mkexpr(arg64)) )) );
sewardj4cb918d2004-12-03 19:43:31 +00007298
7299 goto decode_success;
7300 }
7301
7302 /* F3 0F 2A = CVTSI2SS -- convert I32 in mem/ireg to F32 in low
7303 quarter xmm */
7304 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x2A) {
7305 IRTemp arg32 = newTemp(Ity_I32);
7306 IRTemp rmode = newTemp(Ity_I32);
7307 vassert(sz == 4);
7308
7309 modrm = getIByte(delta+3);
7310 do_MMX_preamble();
7311 if (epartIsReg(modrm)) {
7312 assign( arg32, getIReg(4, eregOfRM(modrm)) );
7313 delta += 3+1;
7314 DIP("cvtsi2ss %s,%s\n", nameIReg(4, eregOfRM(modrm)),
7315 nameXMMReg(gregOfRM(modrm)));
7316 } else {
7317 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
7318 assign( arg32, loadLE(Ity_I32, mkexpr(addr)) );
7319 delta += 3+alen;
7320 DIP("cvtsi2ss %s,%s\n", dis_buf,
7321 nameXMMReg(gregOfRM(modrm)) );
7322 }
7323
7324 assign( rmode, get_sse_roundingmode() );
7325
7326 putXMMRegLane32F(
sewardj3bca9062004-12-04 14:36:09 +00007327 gregOfRM(modrm), 0,
7328 binop(Iop_F64toF32,
7329 mkexpr(rmode),
7330 unop(Iop_I32toF64, mkexpr(arg32)) ) );
sewardj4cb918d2004-12-03 19:43:31 +00007331
7332 goto decode_success;
7333 }
7334
7335 /* 0F 2D = CVTPS2PI -- convert 2 x F32 in mem/low half xmm to 2 x
7336 I32 in mmx, according to prevailing SSE rounding mode */
7337 /* 0F 2C = CVTTPS2PI -- convert 2 x F32 in mem/low half xmm to 2 x
7338 I32 in mmx, rounding towards zero */
7339 if (insn[0] == 0x0F && (insn[1] == 0x2D || insn[1] == 0x2C)) {
7340 IRTemp dst64 = newTemp(Ity_I64);
7341 IRTemp rmode = newTemp(Ity_I32);
7342 IRTemp f32lo = newTemp(Ity_F32);
7343 IRTemp f32hi = newTemp(Ity_F32);
7344 Bool r2zero = insn[1] == 0x2C;
7345 vassert(sz == 4);
7346
7347 do_MMX_preamble();
7348 modrm = getIByte(delta+2);
7349
7350 if (epartIsReg(modrm)) {
7351 delta += 2+1;
7352 assign(f32lo, getXMMRegLane32F(eregOfRM(modrm), 0));
7353 assign(f32hi, getXMMRegLane32F(eregOfRM(modrm), 1));
7354 DIP("cvt%sps2pi %s,%s\n", r2zero ? "t" : "",
7355 nameXMMReg(eregOfRM(modrm)),
7356 nameMMXReg(gregOfRM(modrm)));
7357 } else {
7358 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
7359 assign(f32lo, loadLE(Ity_F32, mkexpr(addr)));
7360 assign(f32hi, loadLE(Ity_F32, binop( Iop_Add32,
7361 mkexpr(addr),
7362 mkU32(4) )));
7363 delta += 2+alen;
7364 DIP("cvt%sps2pi %s,%s\n", r2zero ? "t" : "",
7365 dis_buf,
7366 nameMMXReg(gregOfRM(modrm)));
7367 }
7368
7369 if (r2zero) {
7370 assign(rmode, mkU32((UInt)Irrm_ZERO) );
7371 } else {
7372 assign( rmode, get_sse_roundingmode() );
7373 }
7374
7375 assign(
7376 dst64,
7377 binop( Iop_32HLto64,
7378 binop( Iop_F64toI32,
7379 mkexpr(rmode),
7380 unop( Iop_F32toF64, mkexpr(f32hi) ) ),
7381 binop( Iop_F64toI32,
7382 mkexpr(rmode),
7383 unop( Iop_F32toF64, mkexpr(f32lo) ) )
7384 )
7385 );
7386
7387 putMMXReg(gregOfRM(modrm), mkexpr(dst64));
7388 goto decode_success;
7389 }
7390
7391 /* F3 0F 2D = CVTSS2SI -- convert F32 in mem/low quarter xmm to
7392 I32 in ireg, according to prevailing SSE rounding mode */
7393 /* F3 0F 2C = CVTTSS2SI -- convert F32 in mem/low quarter xmm to
7394 I32 in ireg, according to prevailing SSE rounding mode */
7395 if (insn[0] == 0xF3 && insn[1] == 0x0F
7396 && (insn[2] == 0x2D || insn[2] == 0x2C)) {
7397 IRTemp rmode = newTemp(Ity_I32);
7398 IRTemp f32lo = newTemp(Ity_F32);
7399 Bool r2zero = insn[2] == 0x2C;
7400 vassert(sz == 4);
7401
7402 do_MMX_preamble();
7403 modrm = getIByte(delta+3);
7404
7405 if (epartIsReg(modrm)) {
7406 delta += 3+1;
7407 assign(f32lo, getXMMRegLane32F(eregOfRM(modrm), 0));
7408 DIP("cvt%sss2si %s,%s\n", r2zero ? "t" : "",
7409 nameXMMReg(eregOfRM(modrm)),
7410 nameIReg(4, gregOfRM(modrm)));
7411 } else {
7412 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
7413 assign(f32lo, loadLE(Ity_F32, mkexpr(addr)));
7414 delta += 3+alen;
7415 DIP("cvt%sss2si %s,%s\n", r2zero ? "t" : "",
7416 dis_buf,
7417 nameIReg(4, gregOfRM(modrm)));
7418 }
7419
7420 if (r2zero) {
7421 assign(rmode, mkU32((UInt)Irrm_ZERO) );
7422 } else {
7423 assign( rmode, get_sse_roundingmode() );
7424 }
7425
7426 putIReg(4, gregOfRM(modrm),
7427 binop( Iop_F64toI32,
7428 mkexpr(rmode),
7429 unop( Iop_F32toF64, mkexpr(f32lo) ) )
7430 );
7431
7432 goto decode_success;
7433 }
7434
sewardj176a59c2004-12-03 20:08:31 +00007435 /* 0F 5E = DIVPS -- div 32Fx4 from R/M to R */
7436 if (insn[0] == 0x0F && insn[1] == 0x5E) {
7437 vassert(sz == 4);
sewardj129b3d92004-12-05 15:42:05 +00007438 delta = dis_SSE_E_to_G_all( sorb, delta+2, "divps", Iop_Div32Fx4 );
sewardj176a59c2004-12-03 20:08:31 +00007439 goto decode_success;
7440 }
7441
7442 /* F3 0F 5E = DIVSS -- div 32F0x4 from R/M to R */
7443 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5E) {
7444 vassert(sz == 4);
sewardj129b3d92004-12-05 15:42:05 +00007445 delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "divss", Iop_Div32F0x4 );
sewardj176a59c2004-12-03 20:08:31 +00007446 goto decode_success;
7447 }
7448
7449 /* 0F 5F = MAXPS -- max 32Fx4 from R/M to R */
7450 if (insn[0] == 0x0F && insn[1] == 0x5F) {
7451 vassert(sz == 4);
sewardj129b3d92004-12-05 15:42:05 +00007452 delta = dis_SSE_E_to_G_all( sorb, delta+2, "maxps", Iop_Max32Fx4 );
sewardj176a59c2004-12-03 20:08:31 +00007453 goto decode_success;
7454 }
7455
7456 /* F3 0F 5F = MAXSS -- max 32F0x4 from R/M to R */
7457 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5F) {
7458 vassert(sz == 4);
sewardj129b3d92004-12-05 15:42:05 +00007459 delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "maxss", Iop_Max32F0x4 );
sewardj176a59c2004-12-03 20:08:31 +00007460 goto decode_success;
7461 }
7462
7463 /* 0F 5D = MINPS -- min 32Fx4 from R/M to R */
7464 if (insn[0] == 0x0F && insn[1] == 0x5D) {
7465 vassert(sz == 4);
sewardj129b3d92004-12-05 15:42:05 +00007466 delta = dis_SSE_E_to_G_all( sorb, delta+2, "minps", Iop_Min32Fx4 );
sewardj176a59c2004-12-03 20:08:31 +00007467 goto decode_success;
7468 }
7469
7470 /* F3 0F 5D = MINSS -- min 32F0x4 from R/M to R */
7471 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5D) {
7472 vassert(sz == 4);
sewardj129b3d92004-12-05 15:42:05 +00007473 delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "minss", Iop_Min32F0x4 );
sewardj176a59c2004-12-03 20:08:31 +00007474 goto decode_success;
7475 }
sewardj4cb918d2004-12-03 19:43:31 +00007476
sewardj9636b442004-12-04 01:38:37 +00007477 /* 0F 28 = MOVAPS -- move from E (mem or xmm) to G (xmm). */
7478 /* 0F 10 = MOVAPS -- move from E (mem or xmm) to G (xmm). */
7479 if (insn[0] == 0x0F && (insn[1] == 0x28 || insn[1] == 0x10)) {
7480 vassert(sz == 4);
7481 modrm = getIByte(delta+2);
7482
7483 if (epartIsReg(modrm)) {
7484 putXMMReg( gregOfRM(modrm),
7485 getXMMReg( eregOfRM(modrm) ));
7486 DIP("mov[ua]ps %s,%s\n", nameXMMReg(eregOfRM(modrm)),
7487 nameXMMReg(gregOfRM(modrm)));
7488 delta += 2+1;
7489 } else {
7490 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
7491 putXMMReg( gregOfRM(modrm),
7492 loadLE(Ity_V128, mkexpr(addr)) );
7493 DIP("mov[ua]ps %s,%s\n", dis_buf,
7494 nameXMMReg(gregOfRM(modrm)));
7495 delta += 2+alen;
7496 }
7497 goto decode_success;
7498 }
7499
sewardj0bd7ce62004-12-05 02:47:40 +00007500 /* 0F 16 = MOVHPS -- move from mem to high half of XMM. */
7501 /* 0F 16 = MOVLHPS -- move from lo half to hi half of XMM. */
7502 if (insn[0] == 0x0F && insn[1] == 0x16) {
7503 vassert(sz == 4);
7504 modrm = getIByte(delta+2);
7505 if (epartIsReg(modrm)) {
7506 delta += 2+1;
7507 putXMMRegLane64( gregOfRM(modrm), 1/*upper lane*/,
7508 getXMMRegLane64( eregOfRM(modrm), 0 ) );
7509 DIP("movhps %s,%s\n", nameXMMReg(eregOfRM(modrm)),
7510 nameXMMReg(gregOfRM(modrm)));
7511 } else {
7512 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
7513 delta += 2+alen;
7514 putXMMRegLane64( gregOfRM(modrm), 1/*upper lane*/,
7515 loadLE(Ity_I64, mkexpr(addr)) );
7516 DIP("movhps %s,%s\n", dis_buf,
7517 nameXMMReg( gregOfRM(insn[2]) ));
7518 }
7519 goto decode_success;
7520 }
7521
7522 /* 0F 17 = MOVHPS -- move from high half of XMM to mem. */
7523 if (insn[0] == 0x0F && insn[1] == 0x17) {
7524 if (!epartIsReg(insn[2])) {
7525 vassert(sz == 4);
7526 delta += 2;
7527 addr = disAMode ( &alen, sorb, delta, dis_buf );
7528 delta += alen;
7529 storeLE( mkexpr(addr),
7530 getXMMRegLane64( gregOfRM(insn[2]),
7531 1/*upper lane*/ ) );
7532 DIP("movhps %s,%s\n", nameXMMReg( gregOfRM(insn[2]) ),
7533 dis_buf);
7534 goto decode_success;
7535 }
7536 /* else fall through */
7537 }
7538
7539 /* 0F 12 = MOVLPS -- move from mem to low half of XMM. */
7540 /* OF 12 = MOVHLPS -- from from hi half to lo half of XMM. */
7541 if (insn[0] == 0x0F && insn[1] == 0x12) {
7542 vassert(sz == 4);
7543 modrm = getIByte(delta+2);
7544 if (epartIsReg(modrm)) {
7545 delta += 2+1;
7546 putXMMRegLane64( gregOfRM(modrm),
7547 0/*lower lane*/,
7548 getXMMRegLane64( eregOfRM(modrm), 1 ));
7549 DIP("movhlps %s, %s\n", nameXMMReg(eregOfRM(modrm)),
7550 nameXMMReg(gregOfRM(modrm)));
7551 } else {
7552 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
7553 delta += 2+alen;
7554 putXMMRegLane64( gregOfRM(modrm), 0/*lower lane*/,
7555 loadLE(Ity_I64, mkexpr(addr)) );
7556 DIP("movlps %s, %s\n",
7557 dis_buf, nameXMMReg( gregOfRM(modrm) ));
7558 }
7559 goto decode_success;
7560 }
7561
7562 /* 0F 13 = MOVLPS -- move from low half of XMM to mem. */
7563 if (insn[0] == 0x0F && insn[1] == 0x13) {
7564 if (!epartIsReg(insn[2])) {
7565 vassert(sz == 4);
7566 delta += 2;
7567 addr = disAMode ( &alen, sorb, delta, dis_buf );
7568 delta += alen;
7569 storeLE( mkexpr(addr),
7570 getXMMRegLane64( gregOfRM(insn[2]),
7571 0/*lower lane*/ ) );
7572 DIP("movlps %s, %s\n", nameXMMReg( gregOfRM(insn[2]) ),
7573 dis_buf);
7574 goto decode_success;
7575 }
7576 /* else fall through */
7577 }
7578
sewardj9636b442004-12-04 01:38:37 +00007579 /* 0F 50 = MOVMSKPS - move 4 sign bits from 4 x F32 in xmm(E)
7580 to 4 lowest bits of ireg(G) */
7581 if (insn[0] == 0x0F && insn[1] == 0x50) {
7582 t0 = newTemp(Ity_I32);
7583 t1 = newTemp(Ity_I32);
7584 t2 = newTemp(Ity_I32);
7585 t3 = newTemp(Ity_I32);
7586 Int src;
sewardj9636b442004-12-04 01:38:37 +00007587 modrm = getIByte(delta+2);
sewardj129b3d92004-12-05 15:42:05 +00007588 if (epartIsReg(modrm)) {
7589 vassert(sz == 4);
7590 delta += 2+1;
7591 src = eregOfRM(modrm);
7592 assign( t0, binop( Iop_And32,
7593 binop(Iop_Shr32, getXMMRegLane32(src,0), mkU8(31)),
7594 mkU32(1) ));
7595 assign( t1, binop( Iop_And32,
7596 binop(Iop_Shr32, getXMMRegLane32(src,1), mkU8(30)),
7597 mkU32(2) ));
7598 assign( t2, binop( Iop_And32,
7599 binop(Iop_Shr32, getXMMRegLane32(src,2), mkU8(29)),
7600 mkU32(4) ));
7601 assign( t3, binop( Iop_And32,
7602 binop(Iop_Shr32, getXMMRegLane32(src,3), mkU8(28)),
7603 mkU32(8) ));
7604 putIReg(4, gregOfRM(modrm),
7605 binop(Iop_Or32,
7606 binop(Iop_Or32, mkexpr(t0), mkexpr(t1)),
7607 binop(Iop_Or32, mkexpr(t2), mkexpr(t3))
7608 )
7609 );
7610 DIP("movmskps %s,%s\n", nameXMMReg(src),
7611 nameIReg(4, gregOfRM(modrm)));
7612 goto decode_success;
7613 }
7614 /* else fall through */
sewardj9636b442004-12-04 01:38:37 +00007615 }
7616
7617 /* 0F 2B = MOVNTPS -- for us, just a plain SSE store. */
7618 if (insn[0] == 0x0F && insn[1] == 0x2B) {
7619 modrm = getIByte(delta+2);
7620 if (!epartIsReg(modrm)) {
7621 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
7622 storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) );
7623 DIP("movntps %s,%s\n", dis_buf,
7624 nameXMMReg(gregOfRM(modrm)));
7625 delta += 2+alen;
7626 goto decode_success;
7627 }
7628 /* else fall through */
7629 }
7630
7631 /* 0F E7 = MOVNTQ -- for us, just a plain MMX store. Note, the
7632 Intel manual does not say anything about the usual business of
7633 the FP reg tags getting trashed whenever an MMX insn happens.
7634 So we just leave them alone.
7635 */
7636 if (insn[0] == 0x0F && insn[1] == 0xE7) {
7637 modrm = getIByte(delta+2);
7638 if (!epartIsReg(modrm)) {
7639 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
7640 storeLE( mkexpr(addr), getMMXReg(gregOfRM(modrm)) );
7641 DIP("movntq %s,%s\n", dis_buf,
7642 nameMMXReg(gregOfRM(modrm)));
7643 delta += 2+alen;
7644 goto decode_success;
7645 }
7646 /* else fall through */
7647 }
7648
7649 /* F3 0F 10 = MOVSS -- move 32 bits from E (mem or lo 1/4 xmm) to G
7650 (lo 1/4 xmm). If E is mem, upper 3/4 of G is zeroed out. */
7651 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x10) {
7652 vassert(sz == 4);
7653 modrm = getIByte(delta+3);
7654 if (epartIsReg(modrm)) {
7655 putXMMRegLane32( gregOfRM(modrm), 0,
7656 getXMMRegLane32( eregOfRM(modrm), 0 ));
7657 DIP("movss %s,%s\n", nameXMMReg(eregOfRM(modrm)),
7658 nameXMMReg(gregOfRM(modrm)));
7659 delta += 3+1;
7660 } else {
7661 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
7662 putXMMReg( gregOfRM(modrm), mkV128(0) );
7663 putXMMRegLane32( gregOfRM(modrm), 0,
7664 loadLE(Ity_I32, mkexpr(addr)) );
7665 DIP("movss %s,%s\n", dis_buf,
7666 nameXMMReg(gregOfRM(modrm)));
7667 delta += 3+alen;
7668 }
7669 goto decode_success;
7670 }
7671
7672 /* F3 0F 11 = MOVSS -- move 32 bits from G (lo 1/4 xmm) to E (mem
7673 or lo 1/4 xmm). */
7674 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x11) {
7675 vassert(sz == 4);
7676 modrm = getIByte(delta+3);
7677 if (epartIsReg(modrm)) {
7678 /* fall through, we don't yet have a test case */
7679 } else {
7680 addr = disAMode ( &alen, sorb, delta+3, dis_buf );
7681 storeLE( mkexpr(addr),
7682 getXMMRegLane32(eregOfRM(modrm), 0) );
7683 DIP("movss %s,%s\n", nameXMMReg(eregOfRM(modrm)),
7684 dis_buf);
7685 delta += 3+alen;
7686 goto decode_success;
7687 }
7688 }
7689
7690 /* 0F 59 = MULPS -- mul 32Fx4 from R/M to R */
7691 if (insn[0] == 0x0F && insn[1] == 0x59) {
7692 vassert(sz == 4);
sewardj129b3d92004-12-05 15:42:05 +00007693 delta = dis_SSE_E_to_G_all( sorb, delta+2, "mulps", Iop_Mul32Fx4 );
sewardj9636b442004-12-04 01:38:37 +00007694 goto decode_success;
7695 }
7696
7697 /* F3 0F 59 = MULSS -- mul 32F0x4 from R/M to R */
7698 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x59) {
7699 vassert(sz == 4);
sewardj129b3d92004-12-05 15:42:05 +00007700 delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "mulss", Iop_Mul32F0x4 );
sewardj9636b442004-12-04 01:38:37 +00007701 goto decode_success;
7702 }
7703
7704 /* 0F 56 = ORPS -- G = G and E */
7705 if (insn[0] == 0x0F && insn[1] == 0x56) {
7706 vassert(sz == 4);
sewardj129b3d92004-12-05 15:42:05 +00007707 delta = dis_SSE_E_to_G_all( sorb, delta+2, "orps", Iop_Or128 );
sewardj9636b442004-12-04 01:38:37 +00007708 goto decode_success;
7709 }
7710
sewardj3bca9062004-12-04 14:36:09 +00007711 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
7712 /* 0F E0 = PAVGB -- 8x8 unsigned Packed Average, with rounding */
sewardjb5452082004-12-04 20:33:02 +00007713 if (insn[0] == 0x0F && insn[1] == 0xE0) {
7714 vassert(sz == 4);
7715 do_MMX_preamble();
7716 delta = dis_MMXop_regmem_to_reg (
7717 sorb, delta+2, insn[1], "pavgb", False );
7718 goto decode_success;
sewardj3bca9062004-12-04 14:36:09 +00007719 }
7720
sewardjb5452082004-12-04 20:33:02 +00007721 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
7722 /* 0F E3 = PAVGW -- 16x4 unsigned Packed Average, with rounding */
7723 if (insn[0] == 0x0F && insn[1] == 0xE3) {
7724 vassert(sz == 4);
7725 do_MMX_preamble();
7726 delta = dis_MMXop_regmem_to_reg (
7727 sorb, delta+2, insn[1], "pavgw", False );
7728 goto decode_success;
7729 }
7730
7731 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
7732 /* 0F C5 = PEXTRW -- extract 16-bit field from mmx(E) and put
7733 zero-extend of it in ireg(G). */
7734 if (insn[0] == 0x0F && insn[1] == 0xC5) {
7735 modrm = insn[2];
7736 if (sz == 4 && epartIsReg(modrm)) {
7737 do_MMX_preamble();
7738 t0 = newTemp(Ity_I64);
7739 t1 = newTemp(Ity_I16);
7740 assign(t0, getMMXReg(eregOfRM(modrm)));
7741 switch (insn[3] & 3) {
7742 case 0:
7743 assign(t1, unop(Iop_32to16,
7744 unop(Iop_64to32, mkexpr(t0)))); break;
7745 case 1:
7746 assign(t1, unop(Iop_32HIto16,
7747 unop(Iop_64to32, mkexpr(t0)))); break;
7748 case 2:
7749 assign(t1, unop(Iop_32to16,
7750 unop(Iop_64HIto32, mkexpr(t0)))); break;
7751 case 3:
7752 assign(t1, unop(Iop_32HIto16,
7753 unop(Iop_64HIto32, mkexpr(t0)))); break;
7754 default:
7755 vassert(0);
7756 }
7757 putIReg(4, gregOfRM(modrm), unop(Iop_16Uto32, mkexpr(t1)));
7758 DIP("pextrw $%d,%s,%s\n",
7759 (Int)insn[3], nameMMXReg(eregOfRM(modrm)),
7760 nameIReg(4,gregOfRM(modrm)));
7761 delta += 4;
7762 goto decode_success;
7763 }
7764 /* else fall through */
7765 }
7766
7767 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
7768 /* 0F C4 = PINSRW -- get 16 bits from E(mem or low half ireg) and
7769 put it into the specified lane of mmx(G). */
7770 if (insn[0] == 0x0F && insn[1] == 0xC4) {
7771 if (sz == 4) {
7772 /* Use t0 .. t3 to hold the 4 original 16-bit lanes of the
7773 mmx reg. t4 is the new lane value. t5 is the original
7774 mmx value. t6 is the new mmx value. */
7775 Int lane;
7776 t0 = newTemp(Ity_I16);
7777 t1 = newTemp(Ity_I16);
7778 t2 = newTemp(Ity_I16);
7779 t3 = newTemp(Ity_I16);
7780 t4 = newTemp(Ity_I16);
7781 t5 = newTemp(Ity_I64);
7782 t6 = newTemp(Ity_I64);
7783 modrm = insn[2];
7784 do_MMX_preamble();
7785
7786 assign(t5, getMMXReg(gregOfRM(modrm)));
7787
7788 assign(t0, unop(Iop_32to16, unop(Iop_64to32, mkexpr(t5))));
7789 assign(t1, unop(Iop_32HIto16, unop(Iop_64to32, mkexpr(t5))));
7790 assign(t2, unop(Iop_32to16, unop(Iop_64HIto32, mkexpr(t5))));
7791 assign(t3, unop(Iop_32HIto16, unop(Iop_64HIto32, mkexpr(t5))));
7792
7793 if (epartIsReg(modrm)) {
7794 assign(t4, getIReg(2, eregOfRM(modrm)));
7795 lane = insn[3];
7796 delta += 2+2;
7797 DIP("pinsrw $%d,%s,%s\n", (Int)lane,
7798 nameIReg(2,eregOfRM(modrm)),
7799 nameMMXReg(gregOfRM(modrm)));
7800 } else {
7801 /* awaiting test case */
7802 goto decode_failure;
7803 }
7804
7805 switch (lane & 3) {
7806 case 0:
7807 assign(t6, binop(Iop_32HLto64,
7808 binop(Iop_16HLto32, mkexpr(t3), mkexpr(t2)),
7809 binop(Iop_16HLto32, mkexpr(t1), mkexpr(t4))
7810 )
7811 );
7812 break;
7813 case 1:
7814 assign(t6, binop(Iop_32HLto64,
7815 binop(Iop_16HLto32, mkexpr(t3), mkexpr(t2)),
7816 binop(Iop_16HLto32, mkexpr(t4), mkexpr(t0))
7817 )
7818 );
7819 break;
7820 case 2:
7821 assign(t6, binop(Iop_32HLto64,
7822 binop(Iop_16HLto32, mkexpr(t3), mkexpr(t4)),
7823 binop(Iop_16HLto32, mkexpr(t1), mkexpr(t0))
7824 )
7825 );
7826 break;
7827 case 3:
7828 assign(t6, binop(Iop_32HLto64,
7829 binop(Iop_16HLto32, mkexpr(t4), mkexpr(t2)),
7830 binop(Iop_16HLto32, mkexpr(t1), mkexpr(t0))
7831 )
7832 );
7833 break;
7834 default:
7835 vassert(0);
7836 }
7837 putMMXReg(gregOfRM(modrm), mkexpr(t6));
7838 goto decode_success;
7839
7840 }
7841 /* else fall through */
7842 }
7843
7844 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
7845 /* 0F EE = PMAXSW -- 16x4 signed max */
7846 if (insn[0] == 0x0F && insn[1] == 0xEE) {
7847 vassert(sz == 4);
7848 do_MMX_preamble();
7849 delta = dis_MMXop_regmem_to_reg (
7850 sorb, delta+2, insn[1], "pmaxsw", False );
7851 goto decode_success;
7852 }
7853
7854 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
7855 /* 0F DE = PMAXUB -- 8x8 unsigned max */
7856 if (insn[0] == 0x0F && insn[1] == 0xDE) {
7857 vassert(sz == 4);
7858 do_MMX_preamble();
7859 delta = dis_MMXop_regmem_to_reg (
7860 sorb, delta+2, insn[1], "pmaxub", False );
7861 goto decode_success;
7862 }
7863
7864 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
7865 /* 0F EA = PMINSW -- 16x4 signed min */
7866 if (insn[0] == 0x0F && insn[1] == 0xEA) {
7867 vassert(sz == 4);
7868 do_MMX_preamble();
7869 delta = dis_MMXop_regmem_to_reg (
7870 sorb, delta+2, insn[1], "pminsw", False );
7871 goto decode_success;
7872 }
7873
7874 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
7875 /* 0F DA = PMINUB -- 8x8 unsigned min */
7876 if (insn[0] == 0x0F && insn[1] == 0xDA) {
7877 vassert(sz == 4);
7878 do_MMX_preamble();
7879 delta = dis_MMXop_regmem_to_reg (
7880 sorb, delta+2, insn[1], "pminub", False );
7881 goto decode_success;
7882 }
7883
7884 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
7885 /* 0F D7 = PMOVMSKB -- extract sign bits from each of 8 lanes in
7886 mmx(G), turn them into a byte, and put zero-extend of it in
7887 ireg(G). */
7888 if (insn[0] == 0x0F && insn[1] == 0xD7) {
7889 modrm = insn[2];
7890 if (sz == 4 && epartIsReg(modrm)) {
7891 do_MMX_preamble();
7892 t0 = newTemp(Ity_I64);
7893 t1 = newTemp(Ity_I32);
7894 assign(t0, getMMXReg(eregOfRM(modrm)));
7895 assign(t1, mkIRExprCCall(
7896 Ity_I32, 0/*regparms*/,
7897 "x86g_calculate_pmovmskb",
7898 &x86g_calculate_pmovmskb,
7899 mkIRExprVec_1(mkexpr(t0))));
7900 putIReg(4, gregOfRM(modrm), mkexpr(t1));
7901 DIP("pmovmskb %s,%s\n", nameMMXReg(eregOfRM(modrm)),
7902 nameIReg(4,gregOfRM(modrm)));
7903 delta += 3;
7904 goto decode_success;
7905 }
7906 /* else fall through */
7907 }
7908
sewardj0bd7ce62004-12-05 02:47:40 +00007909 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
7910 /* 0F E4 = PMULUH -- 16x4 hi-half of unsigned widening multiply */
7911 if (insn[0] == 0x0F && insn[1] == 0xE4) {
7912 vassert(sz == 4);
7913 do_MMX_preamble();
7914 delta = dis_MMXop_regmem_to_reg (
7915 sorb, delta+2, insn[1], "pmuluh", False );
7916 goto decode_success;
7917 }
7918
7919 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
7920 /* 0F F6 = PSADBW -- sum of 8Ux8 absolute differences */
7921 if (insn[0] == 0x0F && insn[1] == 0xF6) {
7922 vassert(sz == 4);
7923 do_MMX_preamble();
7924 delta = dis_MMXop_regmem_to_reg (
7925 sorb, delta+2, insn[1], "psadbw", False );
7926 goto decode_success;
7927 }
7928
7929 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
7930 /* 0F 70 = PSHUFW -- rearrange 4x16 from E(mmx or mem) to G(mmx) */
7931 if (insn[0] == 0x0F && insn[1] == 0x70) {
7932 Int order;
7933 vassert(sz == 4);
7934 t0 = newTemp(Ity_I64);
7935 t1 = newTemp(Ity_I64);
7936 do_MMX_preamble();
7937 modrm = insn[2];
7938 if (epartIsReg(modrm)) {
7939 assign( t0, getMMXReg(eregOfRM(modrm)) );
7940 order = (Int)insn[3];
7941 delta += 2+2;
7942 DIP("pshufw $%d,%s,%s\n", order,
7943 nameMMXReg(eregOfRM(modrm)),
7944 nameMMXReg(gregOfRM(modrm)));
7945 } else {
7946 addr = disAMode ( &alen, sorb, delta+2, dis_buf );
7947 assign( t0, loadLE(Ity_I64, mkexpr(addr)) );
7948 order = (Int)insn[2+alen];
7949 delta += 3+alen;
7950 DIP("pshufw $%d,%s,%s\n", order,
7951 dis_buf,
7952 nameMMXReg(gregOfRM(modrm)));
7953 }
7954
7955# define WORD0 unop(Iop_32to16,unop(Iop_64to32,mkexpr(t0)))
7956# define WORD1 unop(Iop_32HIto16,unop(Iop_64to32,mkexpr(t0)))
7957# define WORD2 unop(Iop_32to16,unop(Iop_64HIto32,mkexpr(t0)))
7958# define WORD3 unop(Iop_32HIto16,unop(Iop_64HIto32,mkexpr(t0)))
7959# define SEL(n) ((n)==0 ? WORD0 \
7960 : ((n)==1 ? WORD1 \
7961 : ((n)==2 ? WORD2 : WORD3)))
7962 assign(t1,
7963 binop(Iop_32HLto64,
7964 binop(Iop_16HLto32,SEL((order>>6)&3),SEL((order>>4)&3)),
7965 binop(Iop_16HLto32,SEL((order>>2)&3),SEL((order>>0)&3))
7966 )
7967 );
7968 putMMXReg(gregOfRM(modrm), mkexpr(t1));
7969
7970# undef SEL
7971# undef WORD0
7972# undef WORD1
7973# undef WORD2
7974# undef WORD3
7975 goto decode_success;
7976 }
7977
7978 /* 0F 53 = RCPPS -- approx reciprocal 32Fx4 from R/M to R */
7979 if (insn[0] == 0x0F && insn[1] == 0x53) {
7980 vassert(sz == 4);
sewardj129b3d92004-12-05 15:42:05 +00007981 delta = dis_SSE_E_to_G_unary_all( sorb, delta+2,
7982 "rcpps", Iop_Recip32Fx4 );
sewardj0bd7ce62004-12-05 02:47:40 +00007983 goto decode_success;
7984 }
7985
7986 /* F3 0F 53 = RCPSS -- approx reciprocal 32F0x4 from R/M to R */
7987 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x53) {
7988 vassert(sz == 4);
sewardj129b3d92004-12-05 15:42:05 +00007989 delta = dis_SSE_E_to_G_unary_lo32( sorb, delta+3,
7990 "rcpss", Iop_Recip32F0x4 );
sewardj0bd7ce62004-12-05 02:47:40 +00007991 goto decode_success;
7992 }
sewardjb5452082004-12-04 20:33:02 +00007993
sewardjc9a65702004-07-07 16:32:57 +00007994//--
7995//-- /* FXSAVE/FXRSTOR m32 -- load/store the FPU/MMX/SSE state. */
7996//-- if (insn[0] == 0x0F && insn[1] == 0xAE
7997//-- && (!epartIsReg(insn[2]))
7998//-- && (gregOfRM(insn[2]) == 1 || gregOfRM(insn[2]) == 0) ) {
7999//-- Bool store = gregOfRM(insn[2]) == 0;
8000//-- vg_assert(sz == 4);
8001//-- pair = disAMode ( cb, sorb, eip+2, dis_buf );
8002//-- t1 = LOW24(pair);
8003//-- eip += 2+HI8(pair);
8004//-- uInstr3(cb, store ? SSE2a_MemWr : SSE2a_MemRd, 512,
8005//-- Lit16, (((UShort)insn[0]) << 8) | (UShort)insn[1],
8006//-- Lit16, (UShort)insn[2],
8007//-- TempReg, t1 );
8008//-- DIP("fx%s %s\n", store ? "save" : "rstor", dis_buf );
8009//-- goto decode_success;
8010//-- }
8011//--
8012//-- /* STMXCSR/LDMXCSR m32 -- load/store the MXCSR register. */
8013//-- if (insn[0] == 0x0F && insn[1] == 0xAE
8014//-- && (!epartIsReg(insn[2]))
8015//-- && (gregOfRM(insn[2]) == 3 || gregOfRM(insn[2]) == 2) ) {
8016//-- Bool store = gregOfRM(insn[2]) == 3;
8017//-- vg_assert(sz == 4);
8018//-- pair = disAMode ( cb, sorb, eip+2, dis_buf );
8019//-- t1 = LOW24(pair);
8020//-- eip += 2+HI8(pair);
8021//-- uInstr3(cb, store ? SSE2a_MemWr : SSE2a_MemRd, 4,
8022//-- Lit16, (((UShort)insn[0]) << 8) | (UShort)insn[1],
8023//-- Lit16, (UShort)insn[2],
8024//-- TempReg, t1 );
8025//-- DIP("%smxcsr %s\n", store ? "st" : "ld", dis_buf );
8026//-- goto decode_success;
8027//-- }
8028//--
8029//-- /* LFENCE/MFENCE/SFENCE -- flush pending operations to memory */
8030//-- if (insn[0] == 0x0F && insn[1] == 0xAE
8031//-- && (epartIsReg(insn[2]))
8032//-- && (gregOfRM(insn[2]) >= 5 && gregOfRM(insn[2]) <= 7))
8033//-- {
8034//-- vg_assert(sz == 4);
8035//-- eip += 3;
8036//-- uInstr2(cb, SSE3, 0, /* ignore sz for internal ops */
8037//-- Lit16, (((UShort)0x0F) << 8) | (UShort)0xAE,
8038//-- Lit16, (UShort)insn[2] );
8039//-- DIP("sfence\n");
8040//-- goto decode_success;
8041//-- }
8042//--
8043//-- /* CLFLUSH -- flush cache line */
8044//-- if (insn[0] == 0x0F && insn[1] == 0xAE
8045//-- && (!epartIsReg(insn[2]))
8046//-- && (gregOfRM(insn[2]) == 7))
8047//-- {
8048//-- vg_assert(sz == 4);
8049//-- pair = disAMode ( cb, sorb, eip+2, dis_buf );
8050//-- t1 = LOW24(pair);
8051//-- eip += 2+HI8(pair);
8052//-- uInstr3(cb, SSE2a_MemRd, 0, /* ignore sz for internal ops */
8053//-- Lit16, (((UShort)0x0F) << 8) | (UShort)0xAE,
8054//-- Lit16, (UShort)insn[2],
8055//-- TempReg, t1 );
8056//-- DIP("clflush %s\n", dis_buf);
8057//-- goto decode_success;
8058//-- }
8059//--
8060//-- /* CVTPI2PS (0x0F,0x2A) -- mm/m64, xmm */
8061//-- /* CVTPI2PD (0x66,0x0F,0x2A) -- mm/m64, xmm */
8062//-- if (insn[0] == 0x0F && insn[1] == 0x2A) {
8063//-- if (sz == 4) {
8064//-- eip = dis_SSE2_from_MMX
8065//-- ( cb, sorb, eip+2, 8, "cvtpi2ps",
8066//-- insn[0], insn[1] );
8067//-- } else {
8068//-- eip = dis_SSE3_from_MMX
8069//-- ( cb, sorb, eip+2, 8, "cvtpi2pd",
8070//-- 0x66, insn[0], insn[1] );
8071//-- }
8072//-- goto decode_success;
8073//-- }
8074//--
8075//-- /* CVTTPS2PI (0x0F,0x2C) -- xmm/m64, mm */
8076//-- /* CVTPS2PI (0x0F,0x2D) -- xmm/m64, mm */
8077//-- /* CVTTPD2PI (0x66,0x0F,0x2C) -- xmm/m128, mm */
8078//-- /* CVTPD2PI (0x66,0x0F,0x2D) -- xmm/m128, mm */
8079//-- if (insn[0] == 0x0F
8080//-- && (insn[1] == 0x2C || insn[1] == 0x2D)) {
8081//-- if (sz == 4) {
8082//-- eip = dis_SSE2_to_MMX
8083//-- ( cb, sorb, eip+2, 8, "cvt{t}ps2pi",
8084//-- insn[0], insn[1] );
8085//-- } else {
8086//-- eip = dis_SSE3_to_MMX
8087//-- ( cb, sorb, eip+2, 16, "cvt{t}pd2pi",
8088//-- 0x66, insn[0], insn[1] );
8089//-- }
8090//-- goto decode_success;
8091//-- }
8092//--
8093//-- /* CVTTSD2SI (0xF2,0x0F,0x2C) -- convert a double-precision float
8094//-- value in memory or xmm reg to int and put it in an ireg.
8095//-- Truncate. */
8096//-- /* CVTTSS2SI (0xF3,0x0F,0x2C) -- convert a single-precision float
8097//-- value in memory or xmm reg to int and put it in an ireg.
8098//-- Truncate. */
8099//-- /* CVTSD2SI (0xF2,0x0F,0x2D) -- convert a double-precision float
8100//-- value in memory or xmm reg to int and put it in an ireg. Round
8101//-- as per MXCSR. */
8102//-- /* CVTSS2SI (0xF3,0x0F,0x2D) -- convert a single-precision float
8103//-- value in memory or xmm reg to int and put it in an ireg. Round
8104//-- as per MXCSR. */
8105//-- if ((insn[0] == 0xF2 || insn[0] == 0xF3)
8106//-- && insn[1] == 0x0F
8107//-- && (insn[2] == 0x2C || insn[2] == 0x2D)) {
8108//-- vg_assert(sz == 4);
8109//-- modrm = insn[3];
8110//-- if (epartIsReg(modrm)) {
8111//-- /* We're moving a value in an xmm reg to an ireg. */
8112//-- eip += 4;
sewardj5bd4d162004-11-10 13:02:48 +00008113//-- t1 = newTemp(cb);
sewardjc9a65702004-07-07 16:32:57 +00008114//-- /* sz is 4 for all 4 insns. */
8115//-- vg_assert(epartIsReg(modrm));
8116//-- uInstr3(cb, SSE3g_RegWr, 4,
8117//-- Lit16, (((UShort)insn[0]) << 8) | (UShort)insn[1],
8118//-- Lit16, (((UShort)insn[2]) << 8) | (UShort)modrm,
8119//-- TempReg, t1 );
8120//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, gregOfRM(modrm));
8121//-- DIP("cvt{t}s{s,d}2si %s, %s\n",
8122//-- nameXMMReg(eregOfRM(modrm)), nameIReg(4,gregOfRM(modrm)) );
8123//-- } else {
8124//-- /* So, we're reading memory and writing an ireg. This calls
8125//-- for the ultra-horrible SSE3ag_MemRd_RegWr uinstr. We
8126//-- can't do it in a roundabout route because it does some
8127//-- kind of conversion on the way, which we need to have
8128//-- happen too. So our only choice is to re-emit a suitably
8129//-- rehashed version of the instruction. */
sewardj5bd4d162004-11-10 13:02:48 +00008130//-- /* Destination ireg is GREG. Address goes as EREG as
8131//-- usual. */
sewardjc9a65702004-07-07 16:32:57 +00008132//-- t1 = newTemp(cb); /* t1 holds value on its way to ireg */
8133//-- pair = disAMode ( cb, sorb, eip+3, dis_buf );
8134//-- t2 = LOW24(pair); /* t2 holds addr */
8135//-- eip += 3+HI8(pair);
8136//-- uInstr2(cb, SSE3ag_MemRd_RegWr, insn[0]==0xF2 ? 8 : 4,
8137//-- TempReg, t2, /* address */
8138//-- TempReg, t1 /* dest */);
8139//-- uLiteral(cb , (((UInt)insn[0]) << 24)
8140//-- | (((UInt)insn[1]) << 16)
8141//-- | (((UInt)insn[2]) << 8)
8142//-- | ((UInt)modrm) );
8143//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, gregOfRM(modrm));
8144//-- DIP("cvt{t}s{s,d}2si %s, %s\n",
8145//-- dis_buf, nameIReg(4,gregOfRM(modrm)) );
8146//-- }
8147//-- goto decode_success;
8148//-- }
8149//--
8150//-- /* CVTSI2SS -- convert int reg, or int value in memory, to low 4
8151//-- bytes of XMM reg. */
8152//-- /* CVTSI2SD -- convert int reg, or int value in memory, to low 8
8153//-- bytes of XMM reg. */
8154//-- if ((insn[0] == 0xF3 /*CVTSI2SS*/ || insn[0] == 0xF2 /* CVTSI2SD*/)
8155//-- && insn[1] == 0x0F && insn[2] == 0x2A) {
8156//-- Char* s_or_d = insn[0]==0xF3 ? "s" : "d";
8157//-- vg_assert(sz == 4);
8158//-- modrm = insn[3];
8159//-- t1 = newTemp(cb);
8160//-- if (epartIsReg(modrm)) {
8161//-- uInstr2(cb, GET, 4, ArchReg, eregOfRM(modrm), TempReg, t1);
8162//-- vg_assert(epartIsReg(modrm));
8163//-- uInstr3(cb, SSE3e_RegRd, 4,
8164//-- Lit16, (((UShort)insn[0]) << 8) | (UShort)insn[1],
8165//-- Lit16, (((UShort)insn[2]) << 8) | (UShort)modrm,
8166//-- TempReg, t1 );
8167//-- eip += 4;
8168//-- DIP("cvtsi2s%s %s, %s\n", s_or_d,
8169//-- nameIReg(4,eregOfRM(modrm)), nameXMMReg(gregOfRM(modrm)));
8170//-- } else {
8171//-- pair = disAMode ( cb, sorb, eip+3, dis_buf );
8172//-- t2 = LOW24(pair);
8173//-- eip += 3+HI8(pair);
sewardj5bd4d162004-11-10 13:02:48 +00008174//-- uInstr3(cb, SSE3a_MemRd, 4,
sewardjc9a65702004-07-07 16:32:57 +00008175//-- Lit16, (((UShort)insn[0]) << 8) | (UShort)insn[1],
8176//-- Lit16, (((UShort)insn[2]) << 8) | (UShort)modrm,
8177//-- TempReg, t2 );
8178//-- DIP("cvtsi2s%s %s, %s\n",
8179//-- s_or_d, dis_buf, nameXMMReg(gregOfRM(modrm)));
8180//-- }
8181//-- goto decode_success;
8182//-- }
8183//--
8184//-- /* CVTPS2PD -- convert two packed floats to two packed doubles. */
8185//-- /* 0x66: CVTPD2PS -- convert two packed doubles to two packed floats. */
8186//-- if (insn[0] == 0x0F && insn[1] == 0x5A) {
8187//-- vg_assert(sz == 2 || sz == 4);
8188//-- if (sz == 4) {
8189//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 8, "cvtps2pd",
8190//-- insn[0], insn[1] );
8191//-- } else {
8192//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "cvtpd2ps",
8193//-- 0x66, insn[0], insn[1] );
8194//-- }
8195//-- goto decode_success;
8196//-- }
8197//--
8198//-- /* CVTSS2SD -- convert one single float to double. */
8199//-- if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5A) {
8200//-- vg_assert(sz == 4);
8201//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, 4, "cvtss2sd",
8202//-- insn[0], insn[1], insn[2] );
8203//-- goto decode_success;
8204//-- }
8205//--
8206//-- /* CVTSD2SS -- convert one single double. to float. */
8207//-- if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x5A) {
8208//-- vg_assert(sz == 4);
8209//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, 8, "cvtsd2ss",
8210//-- insn[0], insn[1], insn[2] );
8211//-- goto decode_success;
8212//-- }
8213//--
8214//-- /* CVTDQ2PS -- convert four ints to four packed floats. */
8215//-- /* 0x66: CVTPS2DQ -- convert four packed floats to four ints. */
8216//-- if (insn[0] == 0x0F && insn[1] == 0x5B) {
8217//-- vg_assert(sz == 2 || sz == 4);
8218//-- if (sz == 4) {
8219//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "cvtdq2ps",
8220//-- insn[0], insn[1] );
8221//-- } else {
8222//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "cvtps2dq",
8223//-- 0x66, insn[0], insn[1] );
8224//-- }
8225//-- goto decode_success;
8226//-- }
8227//--
8228//-- /* CVTPD2DQ -- convert two packed doubles to two ints. */
8229//-- if (sz == 2
8230//-- && insn[0] == 0x0F && insn[1] == 0xE6) {
8231//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 8, "cvtpd2dq",
8232//-- 0x66, insn[0], insn[1] );
8233//-- goto decode_success;
8234//-- }
8235//--
8236//-- /* CVTTPD2DQ -- convert two packed doubles to two ints with truncation. */
8237//-- if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0xE6) {
8238//-- vg_assert(sz == 4);
8239//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, 8, "cvttpd2dq",
8240//-- insn[0], insn[1], insn[2] );
8241//-- goto decode_success;
8242//-- }
8243//--
8244//-- /* CVTDQ2PD -- convert two ints to two packed doubles. */
8245//-- if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0xE6) {
8246//-- vg_assert(sz == 4);
8247//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, 8, "cvtdq2pd",
8248//-- insn[0], insn[1], insn[2] );
8249//-- goto decode_success;
8250//-- }
8251//--
8252//-- /* CVTTPS2DQ -- convert four packed floats to four ints with truncation. */
8253//-- if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5B) {
8254//-- vg_assert(sz == 4);
8255//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, 16, "cvttps2dq",
8256//-- insn[0], insn[1], insn[2] );
8257//-- goto decode_success;
8258//-- }
8259//--
8260//-- /* CMPSS -- compare scalar floats. */
8261//-- if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0xC2) {
8262//-- vg_assert(sz == 4);
8263//-- eip = dis_SSE3_reg_or_mem_Imm8 ( cb, sorb, eip+3, 8, "cmpss",
8264//-- insn[0], insn[1], insn[2] );
8265//-- goto decode_success;
8266//-- }
8267//--
8268//-- /* CMPSD -- compare scalar doubles. */
8269//-- if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0xC2) {
8270//-- vg_assert(sz == 4);
8271//-- eip = dis_SSE3_reg_or_mem_Imm8 ( cb, sorb, eip+3, 8, "cmpsd",
8272//-- insn[0], insn[1], insn[2] );
8273//-- goto decode_success;
8274//-- }
8275//--
8276//-- /* sz==4: CMPPS -- compare packed floats */
8277//-- /* sz==2: CMPPD -- compare packed doubles */
8278//-- if (insn[0] == 0x0F && insn[1] == 0xC2) {
8279//-- vg_assert(sz == 4 || sz == 2);
8280//-- if (sz == 4) {
8281//-- eip = dis_SSE2_reg_or_mem_Imm8 ( cb, sorb, eip+2, 16, "cmpps",
8282//-- insn[0], insn[1] );
8283//-- } else {
8284//-- eip = dis_SSE3_reg_or_mem_Imm8 ( cb, sorb, eip+2, 16, "cmppd",
8285//-- 0x66, insn[0], insn[1] );
8286//-- }
8287//-- goto decode_success;
8288//-- }
8289//--
8290//-- /* PSHUFD */
8291//-- if (sz == 2
8292//-- && insn[0] == 0x0F && insn[1] == 0x70) {
8293//-- eip = dis_SSE3_reg_or_mem_Imm8 ( cb, sorb, eip+2, 16,
8294//-- "pshufd",
8295//-- 0x66, insn[0], insn[1] );
8296//-- goto decode_success;
8297//-- }
8298//--
8299//-- /* PSHUFLW */
8300//-- if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x70) {
8301//-- eip = dis_SSE3_reg_or_mem_Imm8 ( cb, sorb, eip+3, 16,
8302//-- "pshuflw",
8303//-- insn[0], insn[1], insn[2] );
8304//-- goto decode_success;
8305//-- }
8306//--
8307//-- /* PSHUFHW */
8308//-- if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x70) {
8309//-- eip = dis_SSE3_reg_or_mem_Imm8 ( cb, sorb, eip+3, 16,
8310//-- "pshufhw",
8311//-- insn[0], insn[1], insn[2] );
8312//-- goto decode_success;
8313//-- }
8314//--
8315//-- /* SHUFPD */
8316//-- if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xC6) {
8317//-- eip = dis_SSE3_reg_or_mem_Imm8 ( cb, sorb, eip+2, 16, "shufpd",
8318//-- 0x66, insn[0], insn[1] );
8319//-- goto decode_success;
8320//-- }
8321//--
8322//-- /* SHUFPS */
8323//-- if (insn[0] == 0x0F && insn[1] == 0xC6) {
8324//-- vg_assert(sz == 4);
8325//-- eip = dis_SSE2_reg_or_mem_Imm8 ( cb, sorb, eip+2, 16, "shufps",
8326//-- insn[0], insn[1] );
8327//-- goto decode_success;
8328//-- }
8329//--
8330//-- /* 0xF2: MULSD */
8331//-- /* 0xF3: MULSS -- multiply low 4 bytes of XMM reg. */
8332//-- if ((insn[0] == 0xF2 || insn[0] == 0xF3)
8333//-- && insn[1] == 0x0F && insn[2] == 0x59) {
8334//-- Bool sz8 = insn[0] == 0xF2;
8335//-- vg_assert(sz == 4);
8336//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, sz8 ? 8 : 4,
8337//-- sz8 ? "mulss" : "mulsd",
8338//-- insn[0], insn[1], insn[2] );
8339//-- goto decode_success;
8340//-- }
8341//--
8342//-- /* MULPS */
8343//-- /* 0x66: MULPD */
8344//-- if (insn[0] == 0x0F && insn[1] == 0x59) {
8345//-- vg_assert(sz == 4 || sz == 2);
8346//-- if (sz == 4) {
8347//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "mulps",
8348//-- insn[0], insn[1] );
8349//-- } else {
8350//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "mulpd",
8351//-- 0x66, insn[0], insn[1] );
8352//-- }
8353//-- goto decode_success;
8354//-- }
8355//--
8356//-- /* 0xF2: DIVSD */
8357//-- /* 0xF3: DIVSS -- divide low 4 bytes of XMM reg. */
8358//-- if ((insn[0] == 0xF2 || insn[0] == 0xF3)
8359//-- && insn[1] == 0x0F && insn[2] == 0x5E) {
8360//-- Bool sz8 = insn[0] == 0xF2;
8361//-- vg_assert(sz == 4);
8362//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, sz8 ? 8 : 4,
8363//-- sz8 ? "divsd" : "divss",
8364//-- insn[0], insn[1], insn[2] );
8365//-- goto decode_success;
8366//-- }
8367//--
8368//-- /* DIVPS */
8369//-- /* 0x66: DIVPD */
8370//-- if (insn[0] == 0x0F && insn[1] == 0x5E) {
8371//-- vg_assert(sz == 4 || sz == 2);
8372//-- if (sz == 4) {
8373//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "divps",
8374//-- insn[0], insn[1] );
8375//-- } else {
8376//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "divpd",
8377//-- 0x66, insn[0], insn[1] );
8378//-- }
8379//-- goto decode_success;
8380//-- }
8381//--
8382//-- /* 0xF2: SUBSD */
8383//-- /* 0xF3: SUBSS */
8384//-- if ((insn[0] == 0xF2 || insn[0] == 0xF3)
8385//-- && insn[1] == 0x0F && insn[2] == 0x5C) {
8386//-- Bool sz8 = insn[0] == 0xF2;
8387//-- vg_assert(sz == 4);
8388//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, sz8 ? 8 : 4,
8389//-- sz8 ? "subsd" : "subss",
8390//-- insn[0], insn[1], insn[2] );
8391//-- goto decode_success;
8392//-- }
8393//--
8394//-- /* SUBPS */
8395//-- /* 0x66: SUBPD */
8396//-- if (insn[0] == 0x0F && insn[1] == 0x5C) {
8397//-- vg_assert(sz == 4 || sz == 2);
8398//-- if (sz == 4) {
8399//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "subps",
8400//-- insn[0], insn[1] );
8401//-- } else {
8402//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "subpd",
8403//-- 0x66, insn[0], insn[1] );
8404//-- }
8405//-- goto decode_success;
8406//-- }
8407//--
8408//-- /* 0xF2: ADDSD */
8409//-- /* 0xF3: ADDSS */
8410//-- if ((insn[0] == 0xF2 || insn[0] == 0xF3)
8411//-- && insn[1] == 0x0F && insn[2] == 0x58) {
8412//-- Bool sz8 = insn[0] == 0xF2;
8413//-- vg_assert(sz == 4);
8414//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, sz8 ? 8 : 4,
8415//-- sz8 ? "addsd" : "addss",
8416//-- insn[0], insn[1], insn[2] );
8417//-- goto decode_success;
8418//-- }
8419//--
8420//-- /* ADDPS */
8421//-- /* 0x66: ADDPD */
8422//-- if (insn[0] == 0x0F && insn[1] == 0x58) {
8423//-- vg_assert(sz == 4 || sz == 2);
8424//-- if (sz == 4) {
8425//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "addps",
8426//-- insn[0], insn[1] );
8427//-- } else {
8428//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "addpd",
8429//-- 0x66, insn[0], insn[1] );
8430//-- }
8431//-- goto decode_success;
8432//-- }
8433//--
8434//-- /* 0xF2: MINSD */
8435//-- /* 0xF3: MINSS */
8436//-- if ((insn[0] == 0xF2 || insn[0] == 0xF3)
8437//-- && insn[1] == 0x0F && insn[2] == 0x5D) {
8438//-- Bool sz8 = insn[0] == 0xF2;
8439//-- vg_assert(sz == 4);
8440//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, sz8 ? 8 : 4,
8441//-- sz8 ? "minsd" : "minss",
8442//-- insn[0], insn[1], insn[2] );
8443//-- goto decode_success;
8444//-- }
8445//--
8446//-- /* MINPS */
8447//-- /* 0x66: MINPD */
8448//-- if (insn[0] == 0x0F && insn[1] == 0x5D) {
8449//-- vg_assert(sz == 4 || sz == 2);
8450//-- if (sz == 4) {
8451//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "minps",
8452//-- insn[0], insn[1] );
8453//-- } else {
8454//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "minpd",
8455//-- 0x66, insn[0], insn[1] );
8456//-- }
8457//-- goto decode_success;
8458//-- }
8459//--
8460//-- /* 0xF3: MAXSD */
8461//-- /* 0xF3: MAXSS */
8462//-- if ((insn[0] == 0xF2 || insn[0] == 0xF3)
8463//-- && insn[1] == 0x0F && insn[2] == 0x5F) {
8464//-- Bool sz8 = insn[0] == 0xF2;
8465//-- vg_assert(sz == 4);
8466//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, sz8 ? 8 : 4,
8467//-- sz8 ? "maxsd" : "maxss",
8468//-- insn[0], insn[1], insn[2] );
8469//-- goto decode_success;
8470//-- }
8471//--
8472//-- /* MAXPS */
8473//-- /* 0x66: MAXPD */
8474//-- if (insn[0] == 0x0F && insn[1] == 0x5F) {
8475//-- vg_assert(sz == 4 || sz == 2);
8476//-- if (sz == 4) {
8477//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "maxps",
8478//-- insn[0], insn[1] );
8479//-- } else {
8480//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "maxpd",
8481//-- 0x66, insn[0], insn[1] );
8482//-- }
8483//-- goto decode_success;
8484//-- }
8485//--
8486//-- /* RCPPS -- reciprocal of packed floats */
8487//-- if (insn[0] == 0x0F && insn[1] == 0x53) {
8488//-- vg_assert(sz == 4);
8489//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "rcpps",
8490//-- insn[0], insn[1] );
8491//-- goto decode_success;
8492//-- }
8493//--
8494//-- /* XORPS */
8495//-- /* 0x66: XORPD (src)xmmreg-or-mem, (dst)xmmreg */
8496//-- if (insn[0] == 0x0F && insn[1] == 0x57) {
8497//-- vg_assert(sz == 4 || sz == 2);
8498//-- if (sz == 4) {
8499//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "xorps",
8500//-- insn[0], insn[1] );
8501//-- } else {
8502//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "xorpd",
8503//-- 0x66, insn[0], insn[1] );
8504//-- }
8505//-- goto decode_success;
8506//-- }
8507//--
8508//-- /* ANDPS */
8509//-- /* 0x66: ANDPD (src)xmmreg-or-mem, (dst)xmmreg */
8510//-- if (insn[0] == 0x0F && insn[1] == 0x54) {
8511//-- vg_assert(sz == 4 || sz == 2);
8512//-- if (sz == 4) {
8513//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "andps",
8514//-- insn[0], insn[1] );
8515//-- } else {
8516//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "andpd",
8517//-- 0x66, insn[0], insn[1] );
8518//-- }
8519//-- goto decode_success;
8520//-- }
8521//--
8522//-- /* ORPS */
8523//-- /* 0x66: ORPD (src)xmmreg-or-mem, (dst)xmmreg */
8524//-- if (insn[0] == 0x0F && insn[1] == 0x56) {
8525//-- vg_assert(sz == 4 || sz == 2);
8526//-- if (sz == 4) {
8527//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "orps",
8528//-- insn[0], insn[1] );
8529//-- } else {
8530//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "orpd",
8531//-- 0x66, insn[0], insn[1] );
8532//-- }
8533//-- goto decode_success;
8534//-- }
8535//--
8536//-- /* PXOR (src)xmmreg-or-mem, (dst)xmmreg */
8537//-- if (sz == 2
8538//-- && insn[0] == 0x0F && insn[1] == 0xEF) {
8539//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pxor",
8540//-- 0x66, insn[0], insn[1] );
8541//-- goto decode_success;
8542//-- }
8543//--
8544//-- /* PAND (src)xmmreg-or-mem, (dst)xmmreg */
8545//-- if (sz == 2
8546//-- && insn[0] == 0x0F && insn[1] == 0xDB) {
8547//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pand",
8548//-- 0x66, insn[0], insn[1] );
8549//-- goto decode_success;
8550//-- }
8551//--
8552//-- /* PANDN (src)xmmreg-or-mem, (dst)xmmreg */
8553//-- if (sz == 2
8554//-- && insn[0] == 0x0F && insn[1] == 0xDF) {
8555//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pandn",
8556//-- 0x66, insn[0], insn[1] );
8557//-- goto decode_success;
8558//-- }
8559//--
8560//-- /* POR (src)xmmreg-or-mem, (dst)xmmreg */
8561//-- if (sz == 2
8562//-- && insn[0] == 0x0F && insn[1] == 0xEB) {
8563//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "por",
8564//-- 0x66, insn[0], insn[1] );
8565//-- goto decode_success;
8566//-- }
8567//--
8568//-- /* 0xDA: PMINUB(src)xmmreg-or-mem, (dst)xmmreg */
8569//-- /* 0xEA: PMINSW(src)xmmreg-or-mem, (dst)xmmreg */
8570//-- if (sz == 2
8571//-- && insn[0] == 0x0F
8572//-- && (insn[1] == 0xDA || insn[1] == 0xEA)) {
8573//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pmin{ub,sw}",
8574//-- 0x66, insn[0], insn[1] );
8575//-- goto decode_success;
8576//-- }
8577//--
8578//-- /* 0xDE: PMAXUB(src)xmmreg-or-mem, (dst)xmmreg */
8579//-- /* 0xEE: PMAXSW(src)xmmreg-or-mem, (dst)xmmreg */
8580//-- if (sz == 2
8581//-- && insn[0] == 0x0F
8582//-- && (insn[1] == 0xDE || insn[1] == 0xEE)) {
8583//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pmax{ub,sw}",
8584//-- 0x66, insn[0], insn[1] );
8585//-- goto decode_success;
8586//-- }
8587//--
8588//-- /* 0xE0: PAVGB(src)xmmreg-or-mem, (dst)xmmreg */
8589//-- /* 0xE3: PAVGW(src)xmmreg-or-mem, (dst)xmmreg */
8590//-- if (sz == 2
8591//-- && insn[0] == 0x0F
8592//-- && (insn[1] == 0xE0 || insn[1] == 0xE3)) {
8593//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pavg{b,w}",
8594//-- 0x66, insn[0], insn[1] );
8595//-- goto decode_success;
8596//-- }
8597//--
8598//-- /* 0xF6: PSADBW(src)xmmreg-or-mem, (dst)xmmreg */
8599//-- if (sz == 2
8600//-- && insn[0] == 0x0F && insn[1] == 0xF6) {
8601//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "psadbw",
8602//-- 0x66, insn[0], insn[1] );
8603//-- goto decode_success;
8604//-- }
8605//--
8606//-- /* 0x60: PUNPCKLBW (src)xmmreg-or-mem, (dst)xmmreg */
8607//-- /* 0x61: PUNPCKLWD (src)xmmreg-or-mem, (dst)xmmreg */
8608//-- /* 0x62: PUNPCKLDQ (src)xmmreg-or-mem, (dst)xmmreg */
8609//-- /* 0x6C: PUNPCKQLQDQ (src)xmmreg-or-mem, (dst)xmmreg */
8610//-- if (sz == 2
8611//-- && insn[0] == 0x0F
8612//-- && (insn[1] == 0x60 || insn[1] == 0x61
8613//-- || insn[1] == 0x62 || insn[1] == 0x6C)) {
8614//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16,
8615//-- "punpckl{bw,wd,dq,qdq}",
8616//-- 0x66, insn[0], insn[1] );
8617//-- goto decode_success;
8618//-- }
8619//--
8620//-- /* 0x68: PUNPCKHBW (src)xmmreg-or-mem, (dst)xmmreg */
8621//-- /* 0x69: PUNPCKHWD (src)xmmreg-or-mem, (dst)xmmreg */
8622//-- /* 0x6A: PUNPCKHDQ (src)xmmreg-or-mem, (dst)xmmreg */
8623//-- /* 0x6D: PUNPCKHQDQ (src)xmmreg-or-mem, (dst)xmmreg */
8624//-- if (sz == 2
8625//-- && insn[0] == 0x0F
8626//-- && (insn[1] == 0x68 || insn[1] == 0x69
8627//-- || insn[1] == 0x6A || insn[1] == 0x6D)) {
8628//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16,
8629//-- "punpckh{bw,wd,dq,qdq}",
8630//-- 0x66, insn[0], insn[1] );
8631//-- goto decode_success;
8632//-- }
8633//--
8634//-- /* 0x14: UNPCKLPD (src)xmmreg-or-mem, (dst)xmmreg. Reads a+0
8635//-- .. a+7, so we can say size 8 */
8636//-- /* 0x15: UNPCKHPD (src)xmmreg-or-mem, (dst)xmmreg. Reads a+8
8637//-- .. a+15, but we have no way to express this, so better say size
8638//-- 16. Sigh. */
8639//-- if (sz == 2
8640//-- && insn[0] == 0x0F
8641//-- && (insn[1] == 0x14 || insn[1] == 0x15)) {
8642//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2,
8643//-- insn[1]==0x14 ? 8 : 16,
8644//-- "unpck{l,h}pd",
8645//-- 0x66, insn[0], insn[1] );
8646//-- goto decode_success;
8647//-- }
8648//--
8649//-- /* 0x14: UNPCKLPS (src)xmmreg-or-mem, (dst)xmmreg Reads a+0
8650//-- .. a+7, so we can say size 8 */
8651//-- /* 0x15: UNPCKHPS (src)xmmreg-or-mem, (dst)xmmreg Reads a+8
8652//-- .. a+15, but we have no way to express this, so better say size
8653//-- 16. Sigh. */
8654//-- if (sz == 4
8655//-- && insn[0] == 0x0F
8656//-- && (insn[1] == 0x14 || insn[1] == 0x15)) {
8657//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2,
8658//-- insn[1]==0x14 ? 8 : 16,
8659//-- "unpck{l,h}ps",
8660//-- insn[0], insn[1] );
8661//-- goto decode_success;
8662//-- }
8663//--
8664//-- /* 0xFC: PADDB (src)xmmreg-or-mem, (dst)xmmreg */
8665//-- /* 0xFD: PADDW (src)xmmreg-or-mem, (dst)xmmreg */
8666//-- /* 0xFE: PADDD (src)xmmreg-or-mem, (dst)xmmreg */
8667//-- /* 0xD4: PADDQ (src)xmmreg-or-mem, (dst)xmmreg */
8668//-- if (sz == 2
8669//-- && insn[0] == 0x0F
8670//-- && (insn[1] == 0xFC || insn[1] == 0xFD
8671//-- || insn[1] == 0xFE || insn[1] == 0xD4)) {
8672//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "padd{b,w,d,q}",
8673//-- 0x66, insn[0], insn[1] );
8674//-- goto decode_success;
8675//-- }
8676//--
8677//-- /* 0xEC: PADDSB (src)xmmreg-or-mem, (dst)xmmreg */
8678//-- /* 0xED: PADDSW (src)xmmreg-or-mem, (dst)xmmreg */
8679//-- if (sz == 2
8680//-- && insn[0] == 0x0F
8681//-- && (insn[1] == 0xEC || insn[1] == 0xED)) {
8682//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "padds{b,w}",
8683//-- 0x66, insn[0], insn[1] );
8684//-- goto decode_success;
8685//-- }
8686//--
8687//-- /* 0xDC: PADDUSB (src)xmmreg-or-mem, (dst)xmmreg */
8688//-- /* 0xDD: PADDUSW (src)xmmreg-or-mem, (dst)xmmreg */
8689//-- if (sz == 2
8690//-- && insn[0] == 0x0F
8691//-- && (insn[1] == 0xDC || insn[1] == 0xDD)) {
8692//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "paddus{b,w}",
8693//-- 0x66, insn[0], insn[1] );
8694//-- goto decode_success;
8695//-- }
8696//--
8697//-- /* 0xF8: PSUBB (src)xmmreg-or-mem, (dst)xmmreg */
8698//-- /* 0xF9: PSUBW (src)xmmreg-or-mem, (dst)xmmreg */
8699//-- /* 0xFA: PSUBD (src)xmmreg-or-mem, (dst)xmmreg */
8700//-- /* 0xFB: PSUBQ (src)xmmreg-or-mem, (dst)xmmreg */
8701//-- if (sz == 2
8702//-- && insn[0] == 0x0F
8703//-- && (insn[1] == 0xF8 || insn[1] == 0xF9
8704//-- || insn[1] == 0xFA || insn[1] == 0xFB)) {
8705//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "psub{b,w,d,q}",
8706//-- 0x66, insn[0], insn[1] );
8707//-- goto decode_success;
8708//-- }
8709//--
8710//-- /* 0xE8: PSUBSB (src)xmmreg-or-mem, (dst)xmmreg */
8711//-- /* 0xE9: PSUBSW (src)xmmreg-or-mem, (dst)xmmreg */
8712//-- if (sz == 2
8713//-- && insn[0] == 0x0F
8714//-- && (insn[1] == 0xE8 || insn[1] == 0xE9)) {
8715//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "psubs{b,w}",
8716//-- 0x66, insn[0], insn[1] );
8717//-- goto decode_success;
8718//-- }
8719//--
8720//-- /* 0xD8: PSUBUSB (src)xmmreg-or-mem, (dst)xmmreg */
8721//-- /* 0xD9: PSUBUSW (src)xmmreg-or-mem, (dst)xmmreg */
8722//-- if (sz == 2
8723//-- && insn[0] == 0x0F
8724//-- && (insn[1] == 0xD8 || insn[1] == 0xD9)) {
8725//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "psubus{b,w}",
8726//-- 0x66, insn[0], insn[1] );
8727//-- goto decode_success;
8728//-- }
8729//--
8730//-- /* 0xE4: PMULHUW(src)xmmreg-or-mem, (dst)xmmreg */
8731//-- /* 0xE5: PMULHW(src)xmmreg-or-mem, (dst)xmmreg */
8732//-- /* 0xD5: PMULLW(src)xmmreg-or-mem, (dst)xmmreg */
8733//-- if (sz == 2
8734//-- && insn[0] == 0x0F
8735//-- && (insn[1] == 0xE4 || insn[1] == 0xE5 || insn[1] == 0xD5)) {
8736//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pmul{hu,h,l}w",
8737//-- 0x66, insn[0], insn[1] );
8738//-- goto decode_success;
8739//-- }
8740//--
8741//-- /* 0xD5: PMULUDQ(src)xmmreg-or-mem, (dst)xmmreg */
8742//-- if (sz == 2
8743//-- && insn[0] == 0x0F && insn[1] == 0xF4) {
8744//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pmuludq",
8745//-- 0x66, insn[0], insn[1] );
8746//-- goto decode_success;
8747//-- }
8748//--
8749//-- /* 0xF5: PMADDWD(src)xmmreg-or-mem, (dst)xmmreg */
8750//-- if (sz == 2
8751//-- && insn[0] == 0x0F
8752//-- && insn[1] == 0xF5) {
8753//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pmaddwd",
8754//-- 0x66, insn[0], insn[1] );
8755//-- goto decode_success;
8756//-- }
8757//--
8758//-- /* 0x74: PCMPEQB (src)xmmreg-or-mem, (dst)xmmreg */
8759//-- /* 0x75: PCMPEQW (src)xmmreg-or-mem, (dst)xmmreg */
8760//-- /* 0x76: PCMPEQD (src)xmmreg-or-mem, (dst)xmmreg */
8761//-- if (sz == 2
8762//-- && insn[0] == 0x0F
8763//-- && (insn[1] == 0x74 || insn[1] == 0x75 || insn[1] == 0x76)) {
8764//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pcmpeq{b,w,d}",
8765//-- 0x66, insn[0], insn[1] );
8766//-- goto decode_success;
8767//-- }
8768//--
8769//-- /* 0x64: PCMPGTB (src)xmmreg-or-mem, (dst)xmmreg */
8770//-- /* 0x65: PCMPGTW (src)xmmreg-or-mem, (dst)xmmreg */
8771//-- /* 0x66: PCMPGTD (src)xmmreg-or-mem, (dst)xmmreg */
8772//-- if (sz == 2
8773//-- && insn[0] == 0x0F
8774//-- && (insn[1] == 0x64 || insn[1] == 0x65 || insn[1] == 0x66)) {
8775//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pcmpgt{b,w,d}",
8776//-- 0x66, insn[0], insn[1] );
8777//-- goto decode_success;
8778//-- }
8779//--
8780//-- /* 0x63: PACKSSWB (src)xmmreg-or-mem, (dst)xmmreg */
8781//-- /* 0x6B: PACKSSDW (src)xmmreg-or-mem, (dst)xmmreg */
8782//-- if (sz == 2
8783//-- && insn[0] == 0x0F
8784//-- && (insn[1] == 0x63 || insn[1] == 0x6B)) {
8785//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "packss{wb,dw}",
8786//-- 0x66, insn[0], insn[1] );
8787//-- goto decode_success;
8788//-- }
8789//--
8790//-- /* 0x67: PACKUSWB (src)xmmreg-or-mem, (dst)xmmreg */
8791//-- if (sz == 2
8792//-- && insn[0] == 0x0F
8793//-- && insn[1] == 0x67) {
8794//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "packuswb",
8795//-- 0x66, insn[0], insn[1] );
8796//-- goto decode_success;
8797//-- }
8798//--
8799//-- /* 0xF1: PSLLW (src)xmmreg-or-mem, (dst)xmmreg */
8800//-- /* 0xF2: PSLLD (src)xmmreg-or-mem, (dst)xmmreg */
8801//-- /* 0xF3: PSLLQ (src)xmmreg-or-mem, (dst)xmmreg */
8802//-- if (sz == 2
8803//-- && insn[0] == 0x0F
8804//-- && (insn[1] == 0xF1 || insn[1] == 0xF2 || insn[1] == 0xF3)) {
8805//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "psll{b,w,d}",
8806//-- 0x66, insn[0], insn[1] );
8807//-- goto decode_success;
8808//-- }
8809//--
8810//-- /* 0xD1: PSRLW (src)xmmreg-or-mem, (dst)xmmreg */
8811//-- /* 0xD2: PSRLD (src)xmmreg-or-mem, (dst)xmmreg */
8812//-- /* 0xD3: PSRLQ (src)xmmreg-or-mem, (dst)xmmreg */
8813//-- if (sz == 2
8814//-- && insn[0] == 0x0F
8815//-- && (insn[1] == 0xD1 || insn[1] == 0xD2 || insn[1] == 0xD3)) {
8816//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "psrl{b,w,d}",
8817//-- 0x66, insn[0], insn[1] );
8818//-- goto decode_success;
8819//-- }
8820//--
8821//-- /* 0xE1: PSRAW (src)xmmreg-or-mem, (dst)xmmreg */
8822//-- /* 0xE2: PSRAD (src)xmmreg-or-mem, (dst)xmmreg */
8823//-- if (sz == 2
8824//-- && insn[0] == 0x0F
8825//-- && (insn[1] == 0xE1 || insn[1] == 0xE2)) {
8826//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "psra{w,d}",
8827//-- 0x66, insn[0], insn[1] );
8828//-- goto decode_success;
8829//-- }
8830//--
8831//-- /* (U)COMISD (src)xmmreg-or-mem, (dst)xmmreg */
8832//-- if (sz == 2
8833//-- && insn[0] == 0x0F
8834//-- && ( insn[1] == 0x2E || insn[1] == 0x2F ) ) {
8835//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 8, "{u}comisd",
8836//-- 0x66, insn[0], insn[1] );
8837//-- vg_assert(LAST_UINSTR(cb).opcode == SSE3a_MemRd
8838//-- || LAST_UINSTR(cb).opcode == SSE4);
8839//-- uFlagsRWU(cb, FlagsEmpty, FlagsOSZACP, FlagsEmpty);
8840//-- goto decode_success;
8841//-- }
8842//--
8843//-- /* (U)COMISS (src)xmmreg-or-mem, (dst)xmmreg */
8844//-- if (sz == 4
8845//-- && insn[0] == 0x0F
8846//-- && ( insn[1] == 0x2E || insn[ 1 ] == 0x2F )) {
8847//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 4, "{u}comiss",
8848//-- insn[0], insn[1] );
8849//-- vg_assert(LAST_UINSTR(cb).opcode == SSE2a_MemRd
8850//-- || LAST_UINSTR(cb).opcode == SSE3);
8851//-- uFlagsRWU(cb, FlagsEmpty, FlagsOSZACP, FlagsEmpty);
8852//-- goto decode_success;
8853//-- }
8854//--
8855//-- /* MOVSD -- move 8 bytes of XMM reg to/from XMM reg or mem. */
8856//-- if (insn[0] == 0xF2
8857//-- && insn[1] == 0x0F
8858//-- && (insn[2] == 0x11 || insn[2] == 0x10)) {
8859//-- vg_assert(sz == 4);
8860//-- eip = dis_SSE3_load_store_or_mov
8861//-- ( cb, sorb, eip+3, 8, insn[2]==0x11, "movsd",
sewardj5bd4d162004-11-10 13:02:48 +00008862//-- insn[0], insn[1], insn[2] );
sewardjc9a65702004-07-07 16:32:57 +00008863//-- goto decode_success;
8864//-- }
8865//--
8866//-- /* MOVQ -- move 8 bytes of XMM reg to XMM reg or mem. How
8867//-- does this differ from MOVSD ?? */
8868//-- if (sz == 2
8869//-- && insn[0] == 0x0F
8870//-- && insn[1] == 0xD6) {
8871//-- eip = dis_SSE3_load_store_or_mov
8872//-- ( cb, sorb, eip+2, 8, True /*store*/, "movq",
8873//-- 0x66, insn[0], insn[1] );
8874//-- goto decode_success;
8875//-- }
8876//--
8877//-- /* MOVQ -- move 8 bytes of XMM reg or mem to XMM reg. How
8878//-- does this differ from MOVSD ?? */
8879//-- if (insn[0] == 0xF3
8880//-- && insn[1] == 0x0F
8881//-- && insn[2] == 0x7E) {
8882//-- eip = dis_SSE3_load_store_or_mov
8883//-- ( cb, sorb, eip+3, 8, False /*load*/, "movq",
8884//-- insn[0], insn[1], insn[2] );
8885//-- goto decode_success;
8886//-- }
8887//--
8888//-- /* MOVDQ2Q -- move low 4 bytes of XMM reg to MMX reg. */
8889//-- if (insn[0] == 0xF2
8890//-- && insn[1] == 0x0F
8891//-- && insn[2] == 0xD6) {
8892//-- eip = dis_SSE3_to_MMX
8893//-- ( cb, sorb, eip+3, 8, "movdq2q",
8894//-- insn[0], insn[1], insn[2] );
8895//-- goto decode_success;
8896//-- }
8897//--
8898//-- /* MOVQ2DQ -- move MMX reg to low 4 bytes of XMM reg. */
8899//-- if (insn[0] == 0xF3
8900//-- && insn[1] == 0x0F
8901//-- && insn[2] == 0xD6) {
8902//-- eip = dis_SSE3_from_MMX
8903//-- ( cb, sorb, eip+3, 8, "movq2dq",
8904//-- insn[0], insn[1], insn[2] );
8905//-- goto decode_success;
8906//-- }
8907//--
8908//-- /* MOVSS -- move 4 bytes of XMM reg to/from XMM reg or mem. */
8909//-- if (insn[0] == 0xF3
8910//-- && insn[1] == 0x0F
8911//-- && (insn[2] == 0x11 || insn[2] == 0x10)) {
8912//-- vg_assert(sz == 4);
8913//-- eip = dis_SSE3_load_store_or_mov
8914//-- ( cb, sorb, eip+3, 4, insn[2]==0x11, "movss",
8915//-- insn[0], insn[1], insn[2] );
8916//-- goto decode_success;
8917//-- }
8918//--
8919//-- /* I don't understand how MOVAPD differs from MOVAPS. */
8920//-- /* MOVAPD (28,29) -- aligned load/store of xmm reg, or xmm-xmm reg
8921//-- move */
8922//-- if (sz == 2
8923//-- && insn[0] == 0x0F && insn[1] == 0x28) {
8924//-- UChar* name = "movapd";
8925//-- //(insn[1] == 0x10 || insn[1] == 0x11)
8926//-- // ? "movups" : "movaps";
8927//-- Bool store = False; //insn[1] == 0x29 || insn[1] == 11;
8928//-- eip = dis_SSE3_load_store_or_mov
8929//-- ( cb, sorb, eip+2, 16, store, name,
8930//-- 0x66, insn[0], insn[1] );
8931//-- goto decode_success;
8932//-- }
8933//--
8934//-- /* sz==4: MOVAPS (28,29) -- aligned load/store of xmm reg, or
8935//-- xmm-xmm reg move */
8936//-- /* sz==4: MOVUPS (10,11) -- unaligned load/store of xmm reg, or
8937//-- xmm-xmm reg move */
8938//-- /* sz==2: MOVAPD (28,29) -- aligned load/store of xmm reg, or
8939//-- xmm-xmm reg move */
8940//-- /* sz==2: MOVUPD (10,11) -- unaligned load/store of xmm reg, or
8941//-- xmm-xmm reg move */
8942//-- if (insn[0] == 0x0F && (insn[1] == 0x28
8943//-- || insn[1] == 0x29
8944//-- || insn[1] == 0x10
8945//-- || insn[1] == 0x11)) {
8946//-- UChar* name = (insn[1] == 0x10 || insn[1] == 0x11)
8947//-- ? "movups" : "movaps";
8948//-- Bool store = insn[1] == 0x29 || insn[1] == 11;
8949//-- vg_assert(sz == 2 || sz == 4);
8950//-- if (sz == 4) {
8951//-- eip = dis_SSE2_load_store_or_mov
8952//-- ( cb, sorb, eip+2, 16, store, name,
8953//-- insn[0], insn[1] );
8954//-- } else {
8955//-- eip = dis_SSE3_load_store_or_mov
8956//-- ( cb, sorb, eip+2, 16, store, name,
8957//-- 0x66, insn[0], insn[1] );
8958//-- }
8959//-- goto decode_success;
8960//-- }
8961//--
8962//-- /* MOVDQA -- aligned 16-byte load/store. */
8963//-- if (sz == 2
8964//-- && insn[0] == 0x0F
8965//-- && (insn[1] == 0x6F || insn[1] == 0x7F)) {
8966//-- Bool is_store = insn[1]==0x7F;
8967//-- eip = dis_SSE3_load_store_or_mov
8968//-- (cb, sorb, eip+2, 16, is_store, "movdqa",
8969//-- 0x66, insn[0], insn[1] );
8970//-- goto decode_success;
8971//-- }
8972//--
8973//-- /* MOVDQU -- unaligned 16-byte load/store. */
8974//-- if (insn[0] == 0xF3
8975//-- && insn[1] == 0x0F
8976//-- && (insn[2] == 0x6F || insn[2] == 0x7F)) {
8977//-- Bool is_store = insn[2]==0x7F;
8978//-- eip = dis_SSE3_load_store_or_mov
8979//-- (cb, sorb, eip+3, 16, is_store, "movdqu",
8980//-- insn[0], insn[1], insn[2] );
8981//-- goto decode_success;
8982//-- }
8983//--
8984//-- /* MOVNTDQ -- 16-byte store with temporal hint (which we
8985//-- ignore). */
8986//-- if (sz == 2
8987//-- && insn[0] == 0x0F
8988//-- && insn[1] == 0xE7) {
8989//-- eip = dis_SSE3_load_store_or_mov
8990//-- (cb, sorb, eip+2, 16, True /* is_store */, "movntdq",
8991//-- 0x66, insn[0], insn[1] );
8992//-- goto decode_success;
8993//-- }
8994//--
8995//-- /* MOVNTPS -- 16-byte store with temporal hint (which we
8996//-- ignore). */
8997//-- if (insn[0] == 0x0F
8998//-- && insn[1] == 0x2B) {
8999//-- eip = dis_SSE2_load_store_or_mov
9000//-- (cb, sorb, eip+2, 16, True /* is_store */, "movntps",
9001//-- insn[0], insn[1] );
9002//-- goto decode_success;
9003//-- }
9004//--
9005//-- /* MOVNTPD -- 16-byte store with temporal hint (which we
9006//-- ignore). */
9007//-- if (sz == 2
9008//-- && insn[0] == 0x0F
9009//-- && insn[1] == 0x2B) {
9010//-- eip = dis_SSE3_load_store_or_mov
9011//-- (cb, sorb, eip+2, 16, True /* is_store */, "movntpd",
9012//-- 0x66, insn[0], insn[1] );
9013//-- goto decode_success;
9014//-- }
9015//--
9016//-- /* MOVD -- 4-byte move between xmmregs and (ireg or memory). */
9017//-- if (sz == 2
9018//-- && insn[0] == 0x0F
9019//-- && (insn[1] == 0x6E || insn[1] == 0x7E)) {
9020//-- Bool is_store = insn[1]==0x7E;
9021//-- modrm = insn[2];
9022//-- if (epartIsReg(modrm) && is_store) {
9023//-- t1 = newTemp(cb);
9024//-- uInstr3(cb, SSE3e_RegWr, 4,
9025//-- Lit16, (((UShort)0x66) << 8) | (UShort)insn[0],
9026//-- Lit16, (((UShort)insn[1]) << 8) | (UShort)modrm,
9027//-- TempReg, t1 );
sewardj5bd4d162004-11-10 13:02:48 +00009028//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, eregOfRM(modrm));
9029//-- DIP("movd %s, %s\n",
sewardjc9a65702004-07-07 16:32:57 +00009030//-- nameXMMReg(gregOfRM(modrm)), nameIReg(4,eregOfRM(modrm)));
9031//-- eip += 3;
9032//-- } else
9033//-- if (epartIsReg(modrm) && !is_store) {
9034//-- t1 = newTemp(cb);
sewardj5bd4d162004-11-10 13:02:48 +00009035//-- uInstr2(cb, GET, 4, ArchReg, eregOfRM(modrm), TempReg, t1);
sewardjc9a65702004-07-07 16:32:57 +00009036//-- uInstr3(cb, SSE3e_RegRd, 4,
9037//-- Lit16, (((UShort)0x66) << 8) | (UShort)insn[0],
9038//-- Lit16, (((UShort)insn[1]) << 8) | (UShort)modrm,
9039//-- TempReg, t1 );
sewardj5bd4d162004-11-10 13:02:48 +00009040//-- DIP("movd %s, %s\n",
sewardjc9a65702004-07-07 16:32:57 +00009041//-- nameIReg(4,eregOfRM(modrm)), nameXMMReg(gregOfRM(modrm)));
9042//-- eip += 3;
9043//-- } else {
9044//-- eip = dis_SSE3_load_store_or_mov
9045//-- (cb, sorb, eip+2, 4, is_store, "movd",
9046//-- 0x66, insn[0], insn[1] );
9047//-- }
9048//-- goto decode_success;
9049//-- }
9050//--
9051//-- /* PEXTRW from SSE register; writes ireg */
9052//-- if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xC5) {
9053//-- t1 = newTemp(cb);
9054//-- modrm = insn[2];
9055//-- vg_assert(epartIsReg(modrm));
9056//-- vg_assert((modrm & 0xC0) == 0xC0);
9057//-- uInstr3(cb, SSE3g1_RegWr, 4,
9058//-- Lit16, (((UShort)0x66) << 8) | (UShort)insn[0],
9059//-- Lit16, (((UShort)insn[1]) << 8) | (UShort)modrm,
9060//-- TempReg, t1 );
9061//-- uLiteral(cb, insn[3]);
9062//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, gregOfRM(modrm));
9063//-- DIP("pextrw %s, %d, %s\n",
9064//-- nameXMMReg(eregOfRM(modrm)), (Int)insn[3],
9065//-- nameIReg(4, gregOfRM(modrm)));
9066//-- eip += 4;
9067//-- goto decode_success;
9068//-- }
9069//--
9070//-- /* PINSRW to SSE register; reads mem or ireg */
9071//-- if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xC4) {
9072//-- t1 = newTemp(cb);
9073//-- modrm = insn[2];
9074//-- if (epartIsReg(modrm)) {
9075//-- uInstr2(cb, GET, 2, ArchReg, eregOfRM(modrm), TempReg, t1);
9076//-- vg_assert(epartIsReg(modrm));
9077//-- uInstr3(cb, SSE3e1_RegRd, 2,
9078//-- Lit16, (((UShort)0x66) << 8) | (UShort)insn[0],
9079//-- Lit16, (((UShort)insn[1]) << 8) | (UShort)modrm,
9080//-- TempReg, t1 );
9081//-- uLiteral(cb, insn[3]);
9082//-- DIP("pinsrw %s, %d, %s\n",
9083//-- nameIReg(2, eregOfRM(modrm)), (Int)insn[3],
9084//-- nameXMMReg(gregOfRM(modrm)));
9085//-- eip += 4;
9086//-- } else {
sewardj5bd4d162004-11-10 13:02:48 +00009087//-- VG_(core_panic)("PINSRW mem");
sewardjc9a65702004-07-07 16:32:57 +00009088//-- }
9089//-- goto decode_success;
9090//-- }
9091//--
9092//-- /* SQRTSD: square root of scalar double. */
9093//-- if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x51) {
9094//-- vg_assert(sz == 4);
9095//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, 8,
9096//-- "sqrtsd",
9097//-- insn[0], insn[1], insn[2] );
9098//-- goto decode_success;
9099//-- }
9100//--
9101//-- /* SQRTSS: square root of scalar float. */
9102//-- if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x51) {
9103//-- vg_assert(sz == 4);
9104//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, 4,
9105//-- "sqrtss",
9106//-- insn[0], insn[1], insn[2] );
9107//-- goto decode_success;
9108//-- }
9109//--
9110//-- /* RSQRTSS: square root reciprocal of scalar float. */
9111//-- if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x52) {
9112//-- vg_assert(sz == 4);
9113//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, 4,
9114//-- "sqrtss",
9115//-- insn[0], insn[1], insn[2] );
9116//-- goto decode_success;
9117//-- }
9118//--
9119//-- /* 0xF3: RCPSS -- reciprocal of scalar float */
9120//-- if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x53) {
9121//-- vg_assert(sz == 4);
9122//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, 4,
9123//-- "rcpss",
9124//-- insn[0], insn[1], insn[2] );
9125//-- goto decode_success;
9126//-- }
9127//--
9128//-- /* MOVMSKPD -- extract 2 sign bits from a xmm reg and copy them to
9129//-- an ireg. Top 30 bits of ireg are set to zero. */
9130//-- /* MOVMSKPS -- extract 4 sign bits from a xmm reg and copy them to
9131//-- an ireg. Top 28 bits of ireg are set to zero. */
9132//-- if (insn[0] == 0x0F && insn[1] == 0x50) {
9133//-- vg_assert(sz == 4 || sz == 2);
9134//-- modrm = insn[2];
9135//-- /* Intel docs don't say anything about a memory source being
sewardj5bd4d162004-11-10 13:02:48 +00009136//-- allowed here. */
sewardjc9a65702004-07-07 16:32:57 +00009137//-- vg_assert(epartIsReg(modrm));
9138//-- t1 = newTemp(cb);
9139//-- if (sz == 4) {
9140//-- uInstr3(cb, SSE2g_RegWr, 4,
9141//-- Lit16, (((UShort)insn[0]) << 8) | (UShort)insn[1],
9142//-- Lit16, (UShort)modrm,
9143//-- TempReg, t1 );
9144//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, gregOfRM(modrm));
9145//-- } else {
9146//-- uInstr3(cb, SSE3g_RegWr, 4,
9147//-- Lit16, (((UShort)0x66) << 8) | (UShort)insn[0],
9148//-- Lit16, (((UShort)insn[1]) << 8) | (UShort)modrm,
9149//-- TempReg, t1 );
9150//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, gregOfRM(modrm));
9151//-- }
9152//-- DIP("movmskp%c %s, %s\n", sz == 4 ? 's' : 'd',
9153//-- nameXMMReg(eregOfRM(modrm)), nameIReg(4,gregOfRM(modrm)));
9154//-- eip += 3;
9155//-- goto decode_success;
9156//-- }
9157//--
9158//-- /* ANDNPS */
9159//-- /* 0x66: ANDNPD (src)xmmreg-or-mem, (dst)xmmreg */
9160//-- if (insn[0] == 0x0F && insn[1] == 0x55) {
9161//-- vg_assert(sz == 4 || sz == 2);
9162//-- if (sz == 4) {
9163//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "andnps",
9164//-- insn[0], insn[1] );
9165//-- } else {
9166//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "andnpd",
9167//-- 0x66, insn[0], insn[1] );
9168//-- }
9169//-- goto decode_success;
9170//-- }
9171//--
9172//-- /* MOVHLPS -- move two packed floats from high quadword to low quadword */
9173//-- /* MOVLPS -- load/store two packed floats to/from low quadword. */
9174//-- /* MOVLPD -- load/store packed double to/from low quadword. */
9175//-- if (insn[0] == 0x0F
9176//-- && (insn[1] == 0x12 || insn[1] == 0x13)) {
9177//-- Bool is_store = insn[1]==0x13;
9178//-- vg_assert(sz == 4 || sz == 2);
9179//-- if (sz == 4) {
9180//-- if (epartIsReg(insn[2])) {
9181//-- vg_assert(insn[1]==0x12);
9182//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "movhlps",
9183//-- insn[0], insn[1] );
9184//-- } else {
9185//-- eip = dis_SSE2_load_store_or_mov
9186//-- (cb, sorb, eip+2, 8, is_store, "movlps",
9187//-- insn[0], insn[1] );
9188//-- }
9189//-- } else {
9190//-- vg_assert(!epartIsReg(insn[2]));
9191//-- eip = dis_SSE3_load_store_or_mov
9192//-- (cb, sorb, eip+2, 8, is_store, "movlpd",
9193//-- 0x66, insn[0], insn[1] );
9194//-- }
9195//-- goto decode_success;
9196//-- }
9197//--
9198//-- /* MOVLHPS -- move two packed floats from low quadword to high quadword */
9199//-- /* MOVHPS -- load/store two packed floats to/from high quadword. */
9200//-- /* MOVHPD -- load/store packed double to/from high quadword. */
9201//-- if (insn[0] == 0x0F
9202//-- && (insn[1] == 0x16 || insn[1] == 0x17)) {
9203//-- Bool is_store = insn[1]==0x17;
9204//-- vg_assert(sz == 4 || sz == 2);
9205//-- if (sz == 4) {
9206//-- if (epartIsReg(insn[2])) {
9207//-- vg_assert(insn[1]==0x16);
9208//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "movlhps",
9209//-- insn[0], insn[1] );
9210//-- } else {
9211//-- eip = dis_SSE2_load_store_or_mov
9212//-- (cb, sorb, eip+2, 8, is_store, "movhps",
9213//-- insn[0], insn[1] );
9214//-- }
9215//-- } else {
9216//-- vg_assert(!epartIsReg(insn[2]));
9217//-- eip = dis_SSE3_load_store_or_mov
9218//-- (cb, sorb, eip+2, 8, is_store, "movhpd",
9219//-- 0x66, insn[0], insn[1] );
9220//-- }
9221//-- goto decode_success;
9222//-- }
9223//--
9224//-- /* PMOVMSKB -- extract 16 sign bits from a xmm reg and copy them to
9225//-- an ireg. Top 16 bits of ireg are set to zero. */
9226//-- if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD7) {
9227//-- modrm = insn[2];
9228//-- /* Intel docs don't say anything about a memory source being
sewardj5bd4d162004-11-10 13:02:48 +00009229//-- allowed here. */
sewardjc9a65702004-07-07 16:32:57 +00009230//-- vg_assert(epartIsReg(modrm));
9231//-- t1 = newTemp(cb);
9232//-- uInstr3(cb, SSE3g_RegWr, 4,
9233//-- Lit16, (((UShort)0x66) << 8) | (UShort)insn[0],
9234//-- Lit16, (((UShort)insn[1]) << 8) | (UShort)modrm,
9235//-- TempReg, t1 );
9236//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, gregOfRM(modrm));
9237//-- DIP("pmovmskb %s, %s\n",
9238//-- nameXMMReg(eregOfRM(modrm)), nameIReg(4,gregOfRM(modrm)));
9239//-- eip += 3;
9240//-- goto decode_success;
9241//-- }
9242//--
9243//-- /* sz==4: SQRTPS: square root of packed float. */
9244//-- /* sz==2: SQRTPD: square root of packed double. */
9245//-- if (insn[0] == 0x0F && insn[1] == 0x51) {
9246//-- vg_assert(sz == 2 || sz == 4);
9247//-- if (sz == 4) {
9248//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16,
9249//-- "sqrtps",
9250//-- insn[0], insn[1] );
9251//-- } else {
9252//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16,
9253//-- "sqrtpd",
9254//-- 0x66, insn[0], insn[1] );
9255//-- }
9256//-- goto decode_success;
9257//-- }
9258//--
9259//-- /* RSQRTPS: square root reciprocal of packed float. */
9260//-- if (insn[0] == 0x0F && insn[1] == 0x52) {
9261//-- vg_assert(sz == 4);
9262//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16,
9263//-- "rsqrtps",
9264//-- insn[0], insn[1] );
9265//-- goto decode_success;
9266//-- }
9267//--
9268//-- /* Fall through into the non-SSE decoder. */
9269//--
9270//-- } /* if (VG_(have_ssestate)) */
9271
9272
9273 /* ---------------------------------------------------- */
sewardjb5452082004-12-04 20:33:02 +00009274 /* --- end of the SSE decoder. --- */
sewardjc9a65702004-07-07 16:32:57 +00009275 /* ---------------------------------------------------- */
9276
9277 /* Get the primary opcode. */
9278 opc = getIByte(delta); delta++;
9279
9280 /* We get here if the current insn isn't SSE, or this CPU doesn't
9281 support SSE. */
9282
9283 switch (opc) {
9284
9285 /* ------------------------ Control flow --------------- */
sewardj940e8c92004-07-11 16:53:24 +00009286
9287 case 0xC2: /* RET imm16 */
9288 d32 = getUDisp16(delta);
9289 delta += 2;
9290 dis_ret(d32);
sewardjce70a5c2004-10-18 14:09:54 +00009291 whatNext = Dis_StopHere;
sewardj940e8c92004-07-11 16:53:24 +00009292 DIP("ret %d\n", d32);
9293 break;
sewardje05c42c2004-07-08 20:25:10 +00009294 case 0xC3: /* RET */
9295 dis_ret(0);
sewardjce70a5c2004-10-18 14:09:54 +00009296 whatNext = Dis_StopHere;
sewardje05c42c2004-07-08 20:25:10 +00009297 DIP("ret\n");
9298 break;
sewardjd1061ab2004-07-08 01:45:30 +00009299
9300 case 0xE8: /* CALL J4 */
9301 d32 = getUDisp32(delta); delta += 4;
sewardjce70a5c2004-10-18 14:09:54 +00009302 d32 += (guest_eip_bbstart+delta);
9303 /* (guest_eip_bbstart+delta) == return-to addr, d32 == call-to addr */
9304 if (d32 == guest_eip_bbstart+delta && getIByte(delta) >= 0x58
9305 && getIByte(delta) <= 0x5F) {
sewardjd1061ab2004-07-08 01:45:30 +00009306 /* Specially treat the position-independent-code idiom
9307 call X
9308 X: popl %reg
9309 as
9310 movl %eip, %reg.
9311 since this generates better code, but for no other reason. */
9312 Int archReg = getIByte(delta) - 0x58;
sewardjc2ac51e2004-07-12 01:03:26 +00009313 /* vex_printf("-- fPIC thingy\n"); */
sewardjce70a5c2004-10-18 14:09:54 +00009314 putIReg(4, archReg, mkU32(guest_eip_bbstart+delta));
sewardjd1061ab2004-07-08 01:45:30 +00009315 delta++; /* Step over the POP */
9316 DIP("call 0x%x ; popl %s\n",d32,nameIReg(4,archReg));
sewardjc2ac51e2004-07-12 01:03:26 +00009317 } else {
sewardjd1061ab2004-07-08 01:45:30 +00009318 /* The normal sequence for a call. */
9319 t1 = newTemp(Ity_I32);
sewardj41f43bc2004-07-08 14:23:22 +00009320 assign(t1, binop(Iop_Sub32, getIReg(4,R_ESP), mkU32(4)));
9321 putIReg(4, R_ESP, mkexpr(t1));
sewardj5bd4d162004-11-10 13:02:48 +00009322 storeLE( mkexpr(t1), mkU32(guest_eip_bbstart+delta));
9323 if (resteerOK && resteerOkFn((Addr64)(Addr32)d32)) {
sewardjce70a5c2004-10-18 14:09:54 +00009324 /* follow into the call target. */
9325 whatNext = Dis_Resteer;
9326 *whereNext = d32;
9327 } else {
9328 jmp_lit(Ijk_Call,d32);
9329 whatNext = Dis_StopHere;
9330 }
sewardjd1061ab2004-07-08 01:45:30 +00009331 DIP("call 0x%x\n",d32);
9332 }
9333 break;
9334
sewardjc9a65702004-07-07 16:32:57 +00009335//-- case 0xC8: /* ENTER */
9336//-- d32 = getUDisp16(eip); eip += 2;
9337//-- abyte = getIByte(delta); delta++;
9338//--
9339//-- vg_assert(sz == 4);
9340//-- vg_assert(abyte == 0);
9341//--
9342//-- t1 = newTemp(cb); t2 = newTemp(cb);
9343//-- uInstr2(cb, GET, sz, ArchReg, R_EBP, TempReg, t1);
9344//-- uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t2);
9345//-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
9346//-- uLiteral(cb, sz);
9347//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
9348//-- uInstr2(cb, STORE, 4, TempReg, t1, TempReg, t2);
9349//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_EBP);
9350//-- if (d32) {
9351//-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
sewardj5bd4d162004-11-10 13:02:48 +00009352//-- uLiteral(cb, d32);
9353//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
sewardjc9a65702004-07-07 16:32:57 +00009354//-- }
9355//-- DIP("enter 0x%x, 0x%x", d32, abyte);
9356//-- break;
sewardjc2ac51e2004-07-12 01:03:26 +00009357
9358 case 0xC9: /* LEAVE */
9359 vassert(sz == 4);
9360 t1 = newTemp(Ity_I32); t2 = newTemp(Ity_I32);
9361 assign(t1, getIReg(4,R_EBP));
9362 /* First PUT ESP looks redundant, but need it because ESP must
9363 always be up-to-date for Memcheck to work... */
9364 putIReg(4, R_ESP, mkexpr(t1));
9365 assign(t2, loadLE(Ity_I32,mkexpr(t1)));
9366 putIReg(4, R_EBP, mkexpr(t2));
9367 putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t1), mkU32(4)) );
9368 DIP("leave\n");
9369 break;
9370
sewardjc9a65702004-07-07 16:32:57 +00009371//-- /* ---------------- Misc weird-ass insns --------------- */
9372//--
9373//-- case 0x27: /* DAA */
9374//-- case 0x2F: /* DAS */
9375//-- t1 = newTemp(cb);
9376//-- uInstr2(cb, GET, 1, ArchReg, R_AL, TempReg, t1);
9377//-- /* Widen %AL to 32 bits, so it's all defined when we push it. */
9378//-- uInstr1(cb, WIDEN, 4, TempReg, t1);
9379//-- uWiden(cb, 1, False);
9380//-- uInstr0(cb, CALLM_S, 0);
9381//-- uInstr1(cb, PUSH, 4, TempReg, t1);
9382//-- uInstr1(cb, CALLM, 0, Lit16,
9383//-- opc == 0x27 ? VGOFF_(helper_DAA) : VGOFF_(helper_DAS) );
9384//-- uFlagsRWU(cb, FlagsAC, FlagsSZACP, FlagO);
9385//-- uInstr1(cb, POP, 4, TempReg, t1);
9386//-- uInstr0(cb, CALLM_E, 0);
9387//-- uInstr2(cb, PUT, 1, TempReg, t1, ArchReg, R_AL);
9388//-- DIP(opc == 0x27 ? "daa\n" : "das\n");
9389//-- break;
9390//--
9391//-- case 0x37: /* AAA */
9392//-- case 0x3F: /* AAS */
9393//-- t1 = newTemp(cb);
9394//-- uInstr2(cb, GET, 2, ArchReg, R_EAX, TempReg, t1);
9395//-- /* Widen %AL to 32 bits, so it's all defined when we push it. */
9396//-- uInstr1(cb, WIDEN, 4, TempReg, t1);
9397//-- uWiden(cb, 2, False);
9398//-- uInstr0(cb, CALLM_S, 0);
9399//-- uInstr1(cb, PUSH, 4, TempReg, t1);
9400//-- uInstr1(cb, CALLM, 0, Lit16,
9401//-- opc == 0x37 ? VGOFF_(helper_AAA) : VGOFF_(helper_AAS) );
9402//-- uFlagsRWU(cb, FlagA, FlagsAC, FlagsEmpty);
9403//-- uInstr1(cb, POP, 4, TempReg, t1);
9404//-- uInstr0(cb, CALLM_E, 0);
9405//-- uInstr2(cb, PUT, 2, TempReg, t1, ArchReg, R_EAX);
9406//-- DIP(opc == 0x37 ? "aaa\n" : "aas\n");
9407//-- break;
9408//--
9409//-- case 0xD4: /* AAM */
9410//-- case 0xD5: /* AAD */
9411//-- d32 = getIByte(delta); delta++;
9412//-- if (d32 != 10) VG_(core_panic)("disInstr: AAM/AAD but base not 10 !");
9413//-- t1 = newTemp(cb);
9414//-- uInstr2(cb, GET, 2, ArchReg, R_EAX, TempReg, t1);
9415//-- /* Widen %AX to 32 bits, so it's all defined when we push it. */
9416//-- uInstr1(cb, WIDEN, 4, TempReg, t1);
9417//-- uWiden(cb, 2, False);
9418//-- uInstr0(cb, CALLM_S, 0);
9419//-- uInstr1(cb, PUSH, 4, TempReg, t1);
9420//-- uInstr1(cb, CALLM, 0, Lit16,
9421//-- opc == 0xD4 ? VGOFF_(helper_AAM) : VGOFF_(helper_AAD) );
9422//-- uFlagsRWU(cb, FlagsEmpty, FlagsSZP, FlagsEmpty);
9423//-- uInstr1(cb, POP, 4, TempReg, t1);
9424//-- uInstr0(cb, CALLM_E, 0);
9425//-- uInstr2(cb, PUT, 2, TempReg, t1, ArchReg, R_EAX);
9426//-- DIP(opc == 0xD4 ? "aam\n" : "aad\n");
9427//-- break;
sewardj1c6f9912004-09-07 10:15:24 +00009428
9429 /* ------------------------ CWD/CDQ -------------------- */
9430
9431 case 0x98: /* CBW */
9432 if (sz == 4) {
9433 putIReg(4, R_EAX, unop(Iop_16Sto32, getIReg(2, R_EAX)));
9434 DIP("cwde\n");
9435 } else {
sewardj47341042004-09-19 11:55:46 +00009436 vassert(sz == 2);
9437 putIReg(2, R_EAX, unop(Iop_8Sto16, getIReg(1, R_EAX)));
9438 DIP("cbw\n");
sewardj1c6f9912004-09-07 10:15:24 +00009439 }
9440 break;
sewardj64e1d652004-07-12 14:00:46 +00009441
9442 case 0x99: /* CWD/CDQ */
9443 ty = szToITy(sz);
9444 putIReg(sz, R_EDX,
9445 binop(mkSizedOp(ty,Iop_Sar8),
9446 getIReg(sz, R_EAX),
sewardj5bd4d162004-11-10 13:02:48 +00009447 mkU8(sz == 2 ? 15 : 31)) );
sewardj64e1d652004-07-12 14:00:46 +00009448 DIP(sz == 2 ? "cwdq\n" : "cdqq\n");
9449 break;
9450
sewardjbdc7d212004-09-09 02:46:40 +00009451 /* ------------------------ FPU ops -------------------- */
9452
9453 case 0x9E: /* SAHF */
9454 codegen_SAHF();
9455 DIP("sahf\n");
9456 break;
9457
sewardjc9a65702004-07-07 16:32:57 +00009458//-- case 0x9F: /* LAHF */
9459//-- codegen_LAHF ( cb );
9460//-- DIP("lahf\n");
9461//-- break;
9462//--
sewardjbdc7d212004-09-09 02:46:40 +00009463 case 0x9B: /* FWAIT */
9464 /* ignore? */
9465 DIP("fwait\n");
9466 break;
9467
sewardjd1725d12004-08-12 20:46:53 +00009468 case 0xD8:
9469 case 0xD9:
9470 case 0xDA:
9471 case 0xDB:
9472 case 0xDC:
9473 case 0xDD:
9474 case 0xDE:
9475 case 0xDF: {
9476 UInt delta0 = delta;
9477 Bool decode_OK = False;
9478 delta = dis_FPU ( &decode_OK, sorb, delta );
9479 if (!decode_OK) {
9480 delta = delta0;
9481 goto decode_failure;
9482 }
9483 break;
9484 }
sewardj0611d802004-07-11 02:37:54 +00009485
9486 /* ------------------------ INC & DEC ------------------ */
9487
9488 case 0x40: /* INC eAX */
9489 case 0x41: /* INC eCX */
9490 case 0x42: /* INC eDX */
9491 case 0x43: /* INC eBX */
9492 case 0x44: /* INC eSP */
9493 case 0x45: /* INC eBP */
9494 case 0x46: /* INC eSI */
9495 case 0x47: /* INC eDI */
9496 vassert(sz == 2 || sz == 4);
9497 ty = szToITy(sz);
9498 t1 = newTemp(ty);
9499 assign( t1, binop(mkSizedOp(ty,Iop_Add8),
9500 getIReg(sz, (UInt)(opc - 0x40)),
9501 mkU(ty,1)) );
9502 setFlags_INC_DEC( True, t1, ty );
9503 putIReg(sz, (UInt)(opc - 0x40), mkexpr(t1));
9504 DIP("inc%c %s\n", nameISize(sz), nameIReg(sz,opc-0x40));
9505 break;
9506
9507 case 0x48: /* DEC eAX */
9508 case 0x49: /* DEC eCX */
9509 case 0x4A: /* DEC eDX */
9510 case 0x4B: /* DEC eBX */
9511 case 0x4C: /* DEC eSP */
9512 case 0x4D: /* DEC eBP */
9513 case 0x4E: /* DEC eSI */
9514 case 0x4F: /* DEC eDI */
9515 vassert(sz == 2 || sz == 4);
9516 ty = szToITy(sz);
9517 t1 = newTemp(ty);
9518 assign( t1, binop(mkSizedOp(ty,Iop_Sub8),
9519 getIReg(sz, (UInt)(opc - 0x48)),
9520 mkU(ty,1)) );
9521 setFlags_INC_DEC( False, t1, ty );
9522 putIReg(sz, (UInt)(opc - 0x48), mkexpr(t1));
9523 DIP("dec%c %s\n", nameISize(sz), nameIReg(sz,opc-0x48));
9524 break;
9525
9526 /* ------------------------ INT ------------------------ */
9527
9528 case 0xCD: /* INT imm8 */
9529 d32 = getIByte(delta); delta++;
9530 if (d32 != 0x80) goto decode_failure;
9531 /* It's important that all ArchRegs carry their up-to-date value
9532 at this point. So we declare an end-of-block here, which
9533 forces any TempRegs caching ArchRegs to be flushed. */
sewardj4fd30f22004-10-25 00:42:16 +00009534 jmp_lit(Ijk_Syscall,((Addr32)guest_eip_bbstart)+delta);
sewardjce70a5c2004-10-18 14:09:54 +00009535 whatNext = Dis_StopHere;
sewardj0611d802004-07-11 02:37:54 +00009536 DIP("int $0x80\n");
9537 break;
9538
sewardj77b86be2004-07-11 13:28:24 +00009539 /* ------------------------ Jcond, byte offset --------- */
9540
9541 case 0xEB: /* Jb (jump, byte offset) */
sewardj4fd30f22004-10-25 00:42:16 +00009542 d32 = (((Addr32)guest_eip_bbstart)+delta+1) + getSDisp8(delta);
sewardj77b86be2004-07-11 13:28:24 +00009543 delta++;
sewardj5bd4d162004-11-10 13:02:48 +00009544 if (resteerOK && resteerOkFn((Addr64)(Addr32)d32)) {
sewardjce70a5c2004-10-18 14:09:54 +00009545 whatNext = Dis_Resteer;
9546 *whereNext = d32;
9547 } else {
9548 jmp_lit(Ijk_Boring,d32);
9549 whatNext = Dis_StopHere;
9550 }
sewardj77b86be2004-07-11 13:28:24 +00009551 DIP("jmp-8 0x%x\n", d32);
9552 break;
sewardj0611d802004-07-11 02:37:54 +00009553
9554 case 0xE9: /* Jv (jump, 16/32 offset) */
9555 vassert(sz == 4); /* JRS added 2004 July 11 */
sewardj4fd30f22004-10-25 00:42:16 +00009556 d32 = (((Addr32)guest_eip_bbstart)+delta+sz) + getSDisp(sz,delta);
sewardj0611d802004-07-11 02:37:54 +00009557 delta += sz;
sewardj5bd4d162004-11-10 13:02:48 +00009558 if (resteerOK && resteerOkFn((Addr64)(Addr32)d32)) {
sewardjce70a5c2004-10-18 14:09:54 +00009559 whatNext = Dis_Resteer;
9560 *whereNext = d32;
9561 } else {
9562 jmp_lit(Ijk_Boring,d32);
9563 whatNext = Dis_StopHere;
9564 }
sewardj0611d802004-07-11 02:37:54 +00009565 DIP("jmp 0x%x\n", d32);
9566 break;
sewardje87b4842004-07-10 12:23:30 +00009567
9568 case 0x70:
9569 case 0x71:
9570 case 0x72: /* JBb/JNAEb (jump below) */
9571 case 0x73: /* JNBb/JAEb (jump not below) */
9572 case 0x74: /* JZb/JEb (jump zero) */
9573 case 0x75: /* JNZb/JNEb (jump not zero) */
9574 case 0x76: /* JBEb/JNAb (jump below or equal) */
9575 case 0x77: /* JNBEb/JAb (jump not below or equal) */
9576 case 0x78: /* JSb (jump negative) */
9577 case 0x79: /* JSb (jump not negative) */
9578 case 0x7A: /* JP (jump parity even) */
9579 case 0x7B: /* JNP/JPO (jump parity odd) */
9580 case 0x7C: /* JLb/JNGEb (jump less) */
9581 case 0x7D: /* JGEb/JNLb (jump greater or equal) */
9582 case 0x7E: /* JLEb/JNGb (jump less or equal) */
9583 case 0x7F: /* JGb/JNLEb (jump greater) */
sewardj4fd30f22004-10-25 00:42:16 +00009584 d32 = (((Addr32)guest_eip_bbstart)+delta+1) + getSDisp8(delta);
sewardje87b4842004-07-10 12:23:30 +00009585 delta++;
sewardj2a9ad022004-11-25 02:46:58 +00009586 jcc_01((X86Condcode)(opc - 0x70), (Addr32)(guest_eip_bbstart+delta), d32);
sewardjce70a5c2004-10-18 14:09:54 +00009587 whatNext = Dis_StopHere;
sewardj2a9ad022004-11-25 02:46:58 +00009588 DIP("j%s-8 0x%x\n", name_X86Condcode(opc - 0x70), d32);
sewardje87b4842004-07-10 12:23:30 +00009589 break;
9590
sewardj458a6f82004-08-25 12:46:02 +00009591 case 0xE3: /* JECXZ or perhaps JCXZ, depending on OSO ? Intel
9592 manual says it depends on address size override,
9593 which doesn't sound right to me. */
9594 vassert(sz==4); /* possibly also OK for sz==2 */
sewardj4fd30f22004-10-25 00:42:16 +00009595 d32 = (((Addr32)guest_eip_bbstart)+delta+1) + getSDisp8(delta);
sewardj458a6f82004-08-25 12:46:02 +00009596 delta++;
9597 ty = szToITy(sz);
9598 stmt( IRStmt_Exit(
9599 binop(mkSizedOp(ty,Iop_CmpEQ8),
9600 getIReg(sz,R_ECX),
9601 mkU(ty,0)),
sewardj893aada2004-11-29 19:57:54 +00009602 Ijk_Boring,
sewardj458a6f82004-08-25 12:46:02 +00009603 IRConst_U32(d32))
9604 );
9605
9606 DIP("j%sz 0x%x\n", nameIReg(sz, R_ECX), d32);
9607 break;
9608
sewardjc9a65702004-07-07 16:32:57 +00009609//-- case 0xE0: /* LOOPNE disp8 */
9610//-- case 0xE1: /* LOOPE disp8 */
9611//-- case 0xE2: /* LOOP disp8 */
9612//-- /* Again, the docs say this uses ECX/CX as a count depending on
9613//-- the address size override, not the operand one. Since we
9614//-- don't handle address size overrides, I guess that means
9615//-- ECX. */
9616//-- d32 = (eip+1) + getSDisp8(eip); eip++;
9617//-- t1 = newTemp(cb);
9618//-- uInstr2(cb, GET, 4, ArchReg, R_ECX, TempReg, t1);
9619//-- uInstr1(cb, DEC, 4, TempReg, t1);
9620//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_ECX);
9621//-- uInstr2(cb, JIFZ, 4, TempReg, t1, Literal, 0);
9622//-- uLiteral(cb, eip);
9623//-- if (opc == 0xE0 || opc == 0xE1) { /* LOOPE/LOOPNE */
9624//-- jcc_lit(cb, eip, (opc == 0xE1 ? CondNZ : CondZ));
9625//-- }
9626//-- jmp_lit(cb, d32);
sewardjce70a5c2004-10-18 14:09:54 +00009627//-- whatNext = Dis_StopHere;
sewardjc9a65702004-07-07 16:32:57 +00009628//-- DIP("loop 0x%x\n", d32);
9629//-- break;
sewardj1813dbe2004-07-28 17:09:04 +00009630
9631 /* ------------------------ IMUL ----------------------- */
9632
9633 case 0x69: /* IMUL Iv, Ev, Gv */
9634 delta = dis_imul_I_E_G ( sorb, sz, delta, sz );
9635 break;
9636 case 0x6B: /* IMUL Ib, Ev, Gv */
9637 delta = dis_imul_I_E_G ( sorb, sz, delta, 1 );
9638 break;
sewardj0611d802004-07-11 02:37:54 +00009639
9640 /* ------------------------ MOV ------------------------ */
9641
9642 case 0x88: /* MOV Gb,Eb */
9643 delta = dis_mov_G_E(sorb, 1, delta);
9644 break;
sewardjc9a65702004-07-07 16:32:57 +00009645
9646 case 0x89: /* MOV Gv,Ev */
9647 delta = dis_mov_G_E(sorb, sz, delta);
9648 break;
9649
sewardjc2ac51e2004-07-12 01:03:26 +00009650 case 0x8A: /* MOV Eb,Gb */
9651 delta = dis_mov_E_G(sorb, 1, delta);
9652 break;
sewardje05c42c2004-07-08 20:25:10 +00009653
9654 case 0x8B: /* MOV Ev,Gv */
9655 delta = dis_mov_E_G(sorb, sz, delta);
9656 break;
9657
sewardje87b4842004-07-10 12:23:30 +00009658 case 0x8D: /* LEA M,Gv */
sewardje05c42c2004-07-08 20:25:10 +00009659 vassert(sz == 4);
9660 modrm = getIByte(delta);
9661 if (epartIsReg(modrm))
9662 vpanic("LEA M,Gv: modRM refers to register (x86)");
9663 /* NOTE! this is the one place where a segment override prefix
9664 has no effect on the address calculation. Therefore we pass
9665 zero instead of sorb here. */
sewardje87b4842004-07-10 12:23:30 +00009666 addr = disAMode ( &alen, /*sorb*/ 0, delta, dis_buf );
9667 delta += alen;
sewardj940e8c92004-07-11 16:53:24 +00009668 putIReg(sz, gregOfRM(modrm), mkexpr(addr));
sewardje05c42c2004-07-08 20:25:10 +00009669 DIP("lea%c %s, %s\n", nameISize(sz), dis_buf,
9670 nameIReg(sz,gregOfRM(modrm)));
9671 break;
sewardje05c42c2004-07-08 20:25:10 +00009672
sewardj063f02f2004-10-20 12:36:12 +00009673 case 0x8C: /* MOV Sw,Ew -- MOV from a SEGMENT REGISTER */
9674 delta = dis_mov_Sw_Ew(sorb, sz, delta);
9675 break;
9676
sewardjc9a65702004-07-07 16:32:57 +00009677//-- case 0x8E: /* MOV Ew,Sw -- MOV to a SEGMENT REGISTER */
9678//-- eip = dis_mov_Ew_Sw(cb, sorb, eip);
9679//-- break;
9680//--
sewardj43852812004-10-16 23:10:08 +00009681 case 0xA0: /* MOV Ob,AL */
9682 sz = 1;
9683 /* Fall through ... */
sewardj0c12ea82004-07-12 08:18:16 +00009684 case 0xA1: /* MOV Ov,eAX */
9685 d32 = getUDisp32(delta); delta += 4;
9686 ty = szToITy(sz);
9687 addr = newTemp(Ity_I32);
9688 assign( addr, handleSegOverride(sorb, mkU32(d32)) );
9689 putIReg(sz, R_EAX, loadLE(ty, mkexpr(addr)));
9690 DIP("mov%c %s0x%x, %s\n", nameISize(sz), sorbTxt(sorb),
9691 d32, nameIReg(sz,R_EAX));
9692 break;
9693
sewardj180e8b32004-07-29 01:40:11 +00009694 case 0xA2: /* MOV Ob,AL */
9695 sz = 1;
9696 /* Fall through ... */
sewardj750f4072004-07-26 22:39:11 +00009697 case 0xA3: /* MOV eAX,Ov */
9698 d32 = getUDisp32(delta); delta += 4;
9699 ty = szToITy(sz);
9700 addr = newTemp(Ity_I32);
9701 assign( addr, handleSegOverride(sorb, mkU32(d32)) );
9702 storeLE( mkexpr(addr), getIReg(sz,R_EAX) );
9703 DIP("mov%c %s, %s0x%x\n", nameISize(sz), nameIReg(sz,R_EAX),
9704 sorbTxt(sorb), d32);
9705 break;
sewardje87b4842004-07-10 12:23:30 +00009706
sewardjc2ac51e2004-07-12 01:03:26 +00009707 case 0xB0: /* MOV imm,AL */
9708 case 0xB1: /* MOV imm,CL */
9709 case 0xB2: /* MOV imm,DL */
9710 case 0xB3: /* MOV imm,BL */
9711 case 0xB4: /* MOV imm,AH */
9712 case 0xB5: /* MOV imm,CH */
9713 case 0xB6: /* MOV imm,DH */
9714 case 0xB7: /* MOV imm,BH */
9715 d32 = getIByte(delta); delta += 1;
9716 putIReg(1, opc-0xB0, mkU8(d32));
9717 DIP("movb $0x%x,%s\n", d32, nameIReg(1,opc-0xB0));
9718 break;
sewardj7ed22952004-07-29 00:09:58 +00009719
sewardje87b4842004-07-10 12:23:30 +00009720 case 0xB8: /* MOV imm,eAX */
9721 case 0xB9: /* MOV imm,eCX */
9722 case 0xBA: /* MOV imm,eDX */
9723 case 0xBB: /* MOV imm,eBX */
9724 case 0xBC: /* MOV imm,eSP */
9725 case 0xBD: /* MOV imm,eBP */
9726 case 0xBE: /* MOV imm,eSI */
9727 case 0xBF: /* MOV imm,eDI */
9728 d32 = getUDisp(sz,delta); delta += sz;
9729 putIReg(sz, opc-0xB8, mkU(szToITy(sz), d32));
9730 DIP("mov%c $0x%x,%s\n", nameISize(sz), d32, nameIReg(sz,opc-0xB8));
9731 break;
9732
sewardj77b86be2004-07-11 13:28:24 +00009733 case 0xC6: /* MOV Ib,Eb */
9734 sz = 1;
9735 goto do_Mov_I_E;
sewardje87b4842004-07-10 12:23:30 +00009736 case 0xC7: /* MOV Iv,Ev */
9737 goto do_Mov_I_E;
9738
9739 do_Mov_I_E:
9740 modrm = getIByte(delta);
9741 if (epartIsReg(modrm)) {
9742 delta++; /* mod/rm byte */
9743 d32 = getUDisp(sz,delta); delta += sz;
sewardj5bd4d162004-11-10 13:02:48 +00009744 putIReg(sz, eregOfRM(modrm), mkU(szToITy(sz), d32));
sewardje87b4842004-07-10 12:23:30 +00009745 DIP("mov%c $0x%x, %s\n", nameISize(sz), d32,
9746 nameIReg(sz,eregOfRM(modrm)));
sewardj5bd4d162004-11-10 13:02:48 +00009747 vassert(0);
sewardje87b4842004-07-10 12:23:30 +00009748 } else {
9749 addr = disAMode ( &alen, sorb, delta, dis_buf );
9750 delta += alen;
9751 d32 = getUDisp(sz,delta); delta += sz;
sewardj5bd4d162004-11-10 13:02:48 +00009752 storeLE(mkexpr(addr), mkU(szToITy(sz), d32));
sewardje87b4842004-07-10 12:23:30 +00009753 DIP("mov%c $0x%x, %s\n", nameISize(sz), d32, dis_buf);
9754 }
9755 break;
9756
sewardj1813dbe2004-07-28 17:09:04 +00009757 /* ------------------------ opl imm, A ----------------- */
9758
9759 case 0x04: /* ADD Ib, AL */
9760 delta = dis_op_imm_A( 1, Iop_Add8, True, delta, "add" );
9761 break;
sewardj77b86be2004-07-11 13:28:24 +00009762 case 0x05: /* ADD Iv, eAX */
9763 delta = dis_op_imm_A(sz, Iop_Add8, True, delta, "add" );
9764 break;
9765
sewardj940e8c92004-07-11 16:53:24 +00009766 case 0x0C: /* OR Ib, AL */
9767 delta = dis_op_imm_A( 1, Iop_Or8, True, delta, "or" );
9768 break;
sewardj82292882004-07-27 00:15:59 +00009769 case 0x0D: /* OR Iv, eAX */
9770 delta = dis_op_imm_A( sz, Iop_Or8, True, delta, "or" );
9771 break;
9772
sewardjc9a65702004-07-07 16:32:57 +00009773//-- case 0x14: /* ADC Ib, AL */
sewardj77b86be2004-07-11 13:28:24 +00009774//-- delta = dis_op_imm_A( 1, ADC, True, delta, "adc" );
sewardjc9a65702004-07-07 16:32:57 +00009775//-- break;
9776//-- case 0x15: /* ADC Iv, eAX */
sewardj77b86be2004-07-11 13:28:24 +00009777//-- delta = dis_op_imm_A( sz, ADC, True, delta, "adc" );
sewardjc9a65702004-07-07 16:32:57 +00009778//-- break;
9779//--
9780//-- case 0x1C: /* SBB Ib, AL */
sewardj77b86be2004-07-11 13:28:24 +00009781//-- delta = dis_op_imm_A( 1, SBB, True, delta, "sbb" );
sewardjc9a65702004-07-07 16:32:57 +00009782//-- break;
9783//-- case 0x1D: /* SBB Iv, eAX */
sewardj77b86be2004-07-11 13:28:24 +00009784//-- delta = dis_op_imm_A( sz, SBB, True, delta, "sbb" );
sewardjc9a65702004-07-07 16:32:57 +00009785//-- break;
9786//--
sewardj940e8c92004-07-11 16:53:24 +00009787 case 0x24: /* AND Ib, AL */
9788 delta = dis_op_imm_A( 1, Iop_And8, True, delta, "and" );
9789 break;
sewardjc2ac51e2004-07-12 01:03:26 +00009790 case 0x25: /* AND Iv, eAX */
9791 delta = dis_op_imm_A( sz, Iop_And8, True, delta, "and" );
9792 break;
sewardj0611d802004-07-11 02:37:54 +00009793
9794 case 0x2C: /* SUB Ib, AL */
9795 delta = dis_op_imm_A(1, Iop_Sub8, True, delta, "sub" );
9796 break;
sewardj68511542004-07-28 00:15:44 +00009797 case 0x2D: /* SUB Iv, eAX */
9798 delta = dis_op_imm_A( sz, Iop_Sub8, True, delta, "sub" );
9799 break;
9800
sewardj1c6f9912004-09-07 10:15:24 +00009801 case 0x34: /* XOR Ib, AL */
9802 delta = dis_op_imm_A( 1, Iop_Xor8, True, delta, "xor" );
9803 break;
sewardjcaca9d02004-07-28 07:11:32 +00009804 case 0x35: /* XOR Iv, eAX */
9805 delta = dis_op_imm_A( sz, Iop_Xor8, True, delta, "xor" );
9806 break;
9807
sewardj0611d802004-07-11 02:37:54 +00009808 case 0x3C: /* CMP Ib, AL */
sewardj77b86be2004-07-11 13:28:24 +00009809 delta = dis_op_imm_A( 1, Iop_Sub8, False, delta, "cmp" );
sewardj0611d802004-07-11 02:37:54 +00009810 break;
9811 case 0x3D: /* CMP Iv, eAX */
sewardj77b86be2004-07-11 13:28:24 +00009812 delta = dis_op_imm_A( sz, Iop_Sub8, False, delta, "cmp" );
sewardj0611d802004-07-11 02:37:54 +00009813 break;
9814
sewardj77b86be2004-07-11 13:28:24 +00009815 case 0xA8: /* TEST Ib, AL */
9816 delta = dis_op_imm_A( 1, Iop_And8, False, delta, "test" );
9817 break;
sewardjc2ac51e2004-07-12 01:03:26 +00009818 case 0xA9: /* TEST Iv, eAX */
9819 delta = dis_op_imm_A( sz, Iop_And8, False, delta, "test" );
9820 break;
9821
sewardj1c6f9912004-09-07 10:15:24 +00009822 /* ------------------------ opl Ev, Gv ----------------- */
9823
sewardj89cd0932004-09-08 18:23:25 +00009824 case 0x02: /* ADD Eb,Gb */
9825 delta = dis_op2_E_G ( sorb, False, Iop_Add8, True, 1, delta, "add" );
9826 break;
sewardj9334b0f2004-07-10 22:43:54 +00009827 case 0x03: /* ADD Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +00009828 delta = dis_op2_E_G ( sorb, False, Iop_Add8, True, sz, delta, "add" );
sewardj9334b0f2004-07-10 22:43:54 +00009829 break;
9830
sewardj7ed22952004-07-29 00:09:58 +00009831 case 0x0A: /* OR Eb,Gb */
sewardj180e8b32004-07-29 01:40:11 +00009832 delta = dis_op2_E_G ( sorb, False, Iop_Or8, True, 1, delta, "or" );
sewardj7ed22952004-07-29 00:09:58 +00009833 break;
sewardjc2ac51e2004-07-12 01:03:26 +00009834 case 0x0B: /* OR Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +00009835 delta = dis_op2_E_G ( sorb, False, Iop_Or8, True, sz, delta, "or" );
sewardjc2ac51e2004-07-12 01:03:26 +00009836 break;
sewardjc9a65702004-07-07 16:32:57 +00009837//--
9838//-- case 0x12: /* ADC Eb,Gb */
sewardj180e8b32004-07-29 01:40:11 +00009839//-- delta = dis_op2_E_G ( sorb, True, ADC, True, 1, delta, "adc" );
sewardjc9a65702004-07-07 16:32:57 +00009840//-- break;
sewardjc4eaff32004-09-10 20:25:11 +00009841 case 0x13: /* ADC Ev,Gv */
9842 delta = dis_op2_E_G ( sorb, True, Iop_Add8, True, sz, delta, "adc" );
9843 break;
9844
sewardjc9a65702004-07-07 16:32:57 +00009845//-- case 0x1A: /* SBB Eb,Gb */
sewardj180e8b32004-07-29 01:40:11 +00009846//-- delta = dis_op2_E_G ( sorb, True, SBB, True, 1, delta, "sbb" );
sewardjc9a65702004-07-07 16:32:57 +00009847//-- break;
sewardj180e8b32004-07-29 01:40:11 +00009848 case 0x1B: /* SBB Ev,Gv */
9849 delta = dis_op2_E_G ( sorb, True, Iop_Sub8, True, sz, delta, "sbb" );
sewardj940e8c92004-07-11 16:53:24 +00009850 break;
9851
sewardj1c6f9912004-09-07 10:15:24 +00009852 case 0x22: /* AND Eb,Gb */
9853 delta = dis_op2_E_G ( sorb, False, Iop_And8, True, 1, delta, "and" );
9854 break;
sewardj180e8b32004-07-29 01:40:11 +00009855 case 0x23: /* AND Ev,Gv */
9856 delta = dis_op2_E_G ( sorb, False, Iop_And8, True, sz, delta, "and" );
9857 break;
9858
9859 case 0x2A: /* SUB Eb,Gb */
9860 delta = dis_op2_E_G ( sorb, False, Iop_Sub8, True, 1, delta, "sub" );
9861 break;
sewardj0611d802004-07-11 02:37:54 +00009862 case 0x2B: /* SUB Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +00009863 delta = dis_op2_E_G ( sorb, False, Iop_Sub8, True, sz, delta, "sub" );
sewardj0611d802004-07-11 02:37:54 +00009864 break;
sewardjc2ac51e2004-07-12 01:03:26 +00009865
9866 case 0x32: /* XOR Eb,Gb */
sewardj180e8b32004-07-29 01:40:11 +00009867 delta = dis_op2_E_G ( sorb, False, Iop_Xor8, True, 1, delta, "xor" );
sewardjc2ac51e2004-07-12 01:03:26 +00009868 break;
sewardj1813dbe2004-07-28 17:09:04 +00009869 case 0x33: /* XOR Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +00009870 delta = dis_op2_E_G ( sorb, False, Iop_Xor8, True, sz, delta, "xor" );
sewardj1813dbe2004-07-28 17:09:04 +00009871 break;
9872
sewardjc2ac51e2004-07-12 01:03:26 +00009873 case 0x3A: /* CMP Eb,Gb */
sewardj180e8b32004-07-29 01:40:11 +00009874 delta = dis_op2_E_G ( sorb, False, Iop_Sub8, False, 1, delta, "cmp" );
sewardjc2ac51e2004-07-12 01:03:26 +00009875 break;
sewardje90ad6a2004-07-10 19:02:10 +00009876 case 0x3B: /* CMP Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +00009877 delta = dis_op2_E_G ( sorb, False, Iop_Sub8, False, sz, delta, "cmp" );
sewardje90ad6a2004-07-10 19:02:10 +00009878 break;
9879
sewardj0611d802004-07-11 02:37:54 +00009880 case 0x84: /* TEST Eb,Gb */
sewardj180e8b32004-07-29 01:40:11 +00009881 delta = dis_op2_E_G ( sorb, False, Iop_And8, False, 1, delta, "test" );
sewardj0611d802004-07-11 02:37:54 +00009882 break;
sewardje05c42c2004-07-08 20:25:10 +00009883 case 0x85: /* TEST Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +00009884 delta = dis_op2_E_G ( sorb, False, Iop_And8, False, sz, delta, "test" );
sewardje05c42c2004-07-08 20:25:10 +00009885 break;
9886
sewardj180e8b32004-07-29 01:40:11 +00009887 /* ------------------------ opl Gv, Ev ----------------- */
9888
9889 case 0x00: /* ADD Gb,Eb */
9890 delta = dis_op2_G_E ( sorb, False, Iop_Add8, True, 1, delta, "add" );
9891 break;
sewardje05c42c2004-07-08 20:25:10 +00009892 case 0x01: /* ADD Gv,Ev */
sewardjcaca9d02004-07-28 07:11:32 +00009893 delta = dis_op2_G_E ( sorb, False, Iop_Add8, True, sz, delta, "add" );
sewardje05c42c2004-07-08 20:25:10 +00009894 break;
9895
sewardj940e8c92004-07-11 16:53:24 +00009896 case 0x08: /* OR Gb,Eb */
sewardjcaca9d02004-07-28 07:11:32 +00009897 delta = dis_op2_G_E ( sorb, False, Iop_Or8, True, 1, delta, "or" );
sewardj940e8c92004-07-11 16:53:24 +00009898 break;
sewardj9334b0f2004-07-10 22:43:54 +00009899 case 0x09: /* OR Gv,Ev */
sewardjcaca9d02004-07-28 07:11:32 +00009900 delta = dis_op2_G_E ( sorb, False, Iop_Or8, True, sz, delta, "or" );
sewardj9334b0f2004-07-10 22:43:54 +00009901 break;
9902
sewardja2384712004-07-29 14:36:40 +00009903 case 0x10: /* ADC Gb,Eb */
9904 delta = dis_op2_G_E ( sorb, True, Iop_Add8, True, 1, delta, "adc" );
9905 break;
sewardjcaca9d02004-07-28 07:11:32 +00009906 case 0x11: /* ADC Gv,Ev */
9907 delta = dis_op2_G_E ( sorb, True, Iop_Add8, True, sz, delta, "adc" );
9908 break;
9909
sewardja2384712004-07-29 14:36:40 +00009910 case 0x18: /* SBB Gb,Eb */
9911 delta = dis_op2_G_E ( sorb, True, Iop_Sub8, True, 1, delta, "sbb" );
9912 break;
sewardjcaca9d02004-07-28 07:11:32 +00009913 case 0x19: /* SBB Gv,Ev */
9914 delta = dis_op2_G_E ( sorb, True, Iop_Sub8, True, sz, delta, "sbb" );
9915 break;
9916
sewardja2384712004-07-29 14:36:40 +00009917 case 0x20: /* AND Gb,Eb */
9918 delta = dis_op2_G_E ( sorb, False, Iop_And8, True, 1, delta, "and" );
9919 break;
sewardj0611d802004-07-11 02:37:54 +00009920 case 0x21: /* AND Gv,Ev */
sewardjcaca9d02004-07-28 07:11:32 +00009921 delta = dis_op2_G_E ( sorb, False, Iop_And8, True, sz, delta, "and" );
sewardj0611d802004-07-11 02:37:54 +00009922 break;
9923
sewardj180e8b32004-07-29 01:40:11 +00009924 case 0x28: /* SUB Gb,Eb */
9925 delta = dis_op2_G_E ( sorb, False, Iop_Sub8, True, 1, delta, "sub" );
9926 break;
sewardje05c42c2004-07-08 20:25:10 +00009927 case 0x29: /* SUB Gv,Ev */
sewardjcaca9d02004-07-28 07:11:32 +00009928 delta = dis_op2_G_E ( sorb, False, Iop_Sub8, True, sz, delta, "sub" );
sewardje05c42c2004-07-08 20:25:10 +00009929 break;
9930
sewardjc2ac51e2004-07-12 01:03:26 +00009931 case 0x30: /* XOR Gb,Eb */
sewardjcaca9d02004-07-28 07:11:32 +00009932 delta = dis_op2_G_E ( sorb, False, Iop_Xor8, True, 1, delta, "xor" );
sewardjc2ac51e2004-07-12 01:03:26 +00009933 break;
sewardje87b4842004-07-10 12:23:30 +00009934 case 0x31: /* XOR Gv,Ev */
sewardjcaca9d02004-07-28 07:11:32 +00009935 delta = dis_op2_G_E ( sorb, False, Iop_Xor8, True, sz, delta, "xor" );
sewardje87b4842004-07-10 12:23:30 +00009936 break;
9937
sewardj0611d802004-07-11 02:37:54 +00009938 case 0x38: /* CMP Gb,Eb */
sewardjcaca9d02004-07-28 07:11:32 +00009939 delta = dis_op2_G_E ( sorb, False, Iop_Sub8, False, 1, delta, "cmp" );
sewardj0611d802004-07-11 02:37:54 +00009940 break;
sewardje90ad6a2004-07-10 19:02:10 +00009941 case 0x39: /* CMP Gv,Ev */
sewardjcaca9d02004-07-28 07:11:32 +00009942 delta = dis_op2_G_E ( sorb, False, Iop_Sub8, False, sz, delta, "cmp" );
sewardje90ad6a2004-07-10 19:02:10 +00009943 break;
9944
sewardj9334b0f2004-07-10 22:43:54 +00009945 /* ------------------------ POP ------------------------ */
9946
9947 case 0x58: /* POP eAX */
9948 case 0x59: /* POP eCX */
9949 case 0x5A: /* POP eDX */
9950 case 0x5B: /* POP eBX */
9951 case 0x5D: /* POP eBP */
9952 case 0x5E: /* POP eSI */
9953 case 0x5F: /* POP eDI */
9954 case 0x5C: /* POP eSP */
9955 vassert(sz == 2 || sz == 4);
9956 t1 = newTemp(szToITy(sz)); t2 = newTemp(Ity_I32);
9957 assign(t2, getIReg(4, R_ESP));
9958 assign(t1, loadLE(szToITy(sz),mkexpr(t2)));
9959 putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t2), mkU32(sz)));
9960 putIReg(sz, opc-0x58, mkexpr(t1));
9961 DIP("pop%c %s\n", nameISize(sz), nameIReg(sz,opc-0x58));
9962 break;
9963
sewardja2384712004-07-29 14:36:40 +00009964 case 0x9D: /* POPF */
9965 vassert(sz == 2 || sz == 4);
9966 vassert(sz == 4); // until we know a sz==2 test case exists
9967 t1 = newTemp(Ity_I32); t2 = newTemp(Ity_I32);
9968 assign(t2, getIReg(4, R_ESP));
sewardjc22a6fd2004-07-29 23:41:47 +00009969 assign(t1, widenUto32(loadLE(szToITy(sz),mkexpr(t2))));
sewardja2384712004-07-29 14:36:40 +00009970 putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t2), mkU32(sz)));
sewardj98169c52004-10-24 13:11:39 +00009971 /* t1 is the flag word. Mask out everything except OSZACP and
sewardj2a9ad022004-11-25 02:46:58 +00009972 set the flags thunk to X86G_CC_OP_COPY. */
9973 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
sewardj2a2ba8b2004-11-08 13:14:06 +00009974 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
9975 stmt( IRStmt_Put( OFFB_CC_DEP1,
sewardj5bd4d162004-11-10 13:02:48 +00009976 binop(Iop_And32,
9977 mkexpr(t1),
sewardj2a9ad022004-11-25 02:46:58 +00009978 mkU32( X86G_CC_MASK_C | X86G_CC_MASK_P
9979 | X86G_CC_MASK_A | X86G_CC_MASK_Z
9980 | X86G_CC_MASK_S| X86G_CC_MASK_O )
sewardj5bd4d162004-11-10 13:02:48 +00009981 )
9982 )
9983 );
sewardja2384712004-07-29 14:36:40 +00009984
9985 /* Also need to set the D flag, which is held in bit 10 of t1.
9986 If zero, put 1 in OFFB_DFLAG, else -1 in OFFB_DFLAG. */
9987 stmt( IRStmt_Put(
9988 OFFB_DFLAG,
9989 IRExpr_Mux0X(
9990 unop(Iop_32to8,
9991 binop(Iop_And32,
9992 binop(Iop_Shr32, mkexpr(t1), mkU8(10)),
9993 mkU32(1))),
9994 mkU32(1),
9995 mkU32(0xFFFFFFFF)))
9996 );
9997
sewardj006a6a22004-10-26 00:50:52 +00009998 /* And set the ID flag */
9999 stmt( IRStmt_Put(
10000 OFFB_IDFLAG,
10001 IRExpr_Mux0X(
10002 unop(Iop_32to8,
10003 binop(Iop_And32,
10004 binop(Iop_Shr32, mkexpr(t1), mkU8(21)),
10005 mkU32(1))),
10006 mkU32(0),
10007 mkU32(1)))
10008 );
10009
sewardja2384712004-07-29 14:36:40 +000010010 DIP("popf%c\n", nameISize(sz));
10011 break;
10012
sewardjc9a65702004-07-07 16:32:57 +000010013//-- case 0x61: /* POPA */
10014//-- { Int reg;
10015//-- /* Just to keep things sane, we assert for a size 4. It's
10016//-- probably OK for size 2 as well, but I'd like to find a test
10017//-- case; ie, have the assertion fail, before committing to it.
10018//-- If it fails for you, uncomment the sz == 2 bit, try again,
10019//-- and let me know whether or not it works. (jseward@acm.org). */
10020//-- vg_assert(sz == 4 /* || sz == 2 */);
10021//--
10022//-- /* Eight values are popped, one per register, but the value of
10023//-- %esp on the stack is ignored and instead incremented (in one
10024//-- hit at the end) for each of the values. */
10025//-- t1 = newTemp(cb); t2 = newTemp(cb); t3 = newTemp(cb);
10026//-- uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t2);
10027//-- uInstr2(cb, MOV, 4, TempReg, t2, TempReg, t3);
10028//--
10029//-- /* Do %edi, %esi, %ebp */
10030//-- for (reg = 7; reg >= 5; reg--) {
10031//-- uInstr2(cb, LOAD, sz, TempReg, t2, TempReg, t1);
10032//-- uInstr2(cb, ADD, 4, Literal, 0, TempReg, t2);
10033//-- uLiteral(cb, sz);
10034//-- uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, reg);
10035//-- }
10036//-- /* Ignore (skip) value of %esp on stack. */
10037//-- uInstr2(cb, ADD, 4, Literal, 0, TempReg, t2);
10038//-- uLiteral(cb, sz);
10039//-- /* Do %ebx, %edx, %ecx, %eax */
10040//-- for (reg = 3; reg >= 0; reg--) {
10041//-- uInstr2(cb, LOAD, sz, TempReg, t2, TempReg, t1);
10042//-- uInstr2(cb, ADD, 4, Literal, 0, TempReg, t2);
10043//-- uLiteral(cb, sz);
10044//-- uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, reg);
10045//-- }
10046//-- uInstr2(cb, ADD, 4, Literal, 0, TempReg, t3);
10047//-- uLiteral(cb, sz * 8); /* One 'sz' per register */
10048//-- uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_ESP);
10049//-- DIP("popa%c\n", nameISize(sz));
10050//-- break;
10051//-- }
sewardjfeeb8a82004-11-30 12:30:11 +000010052
10053 case 0x8F: /* POPL/POPW m32 */
10054 { Int len;
10055 UChar rm = getIByte(delta);
10056
10057 /* make sure this instruction is correct POP */
10058 vassert(!epartIsReg(rm) && (gregOfRM(rm) == 0));
10059 /* and has correct size */
10060 vassert(sz == 4);
10061
10062 t1 = newTemp(Ity_I32); t3 = newTemp(Ity_I32);
10063 /* set t1 to ESP: t1 = ESP */
10064 assign( t1, getIReg(4, R_ESP) );
10065 /* load M[ESP] to virtual register t3: t3 = M[t1] */
10066 assign( t3, loadLE(Ity_I32, mkexpr(t1)) );
10067
10068 /* increase ESP; must be done before the STORE. Intel manual says:
10069 If the ESP register is used as a base register for addressing
10070 a destination operand in memory, the POP instruction computes
10071 the effective address of the operand after it increments the
10072 ESP register.
10073 */
10074 putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t1), mkU32(sz)) );
10075
10076 /* resolve MODR/M */
10077 addr = disAMode ( &len, sorb, delta, dis_buf);
10078 storeLE( mkexpr(addr), mkexpr(t3) );
10079
10080 DIP("popl %s\n", dis_buf);
10081
10082 delta += len;
10083 break;
10084 }
10085
sewardjc9a65702004-07-07 16:32:57 +000010086//-- case 0x1F: /* POP %DS */
10087//-- dis_pop_segreg( cb, R_DS, sz ); break;
10088//-- case 0x07: /* POP %ES */
10089//-- dis_pop_segreg( cb, R_ES, sz ); break;
10090//-- case 0x17: /* POP %SS */
10091//-- dis_pop_segreg( cb, R_SS, sz ); break;
sewardjd1061ab2004-07-08 01:45:30 +000010092
10093 /* ------------------------ PUSH ----------------------- */
10094
10095 case 0x50: /* PUSH eAX */
10096 case 0x51: /* PUSH eCX */
10097 case 0x52: /* PUSH eDX */
10098 case 0x53: /* PUSH eBX */
10099 case 0x55: /* PUSH eBP */
10100 case 0x56: /* PUSH eSI */
10101 case 0x57: /* PUSH eDI */
10102 case 0x54: /* PUSH eSP */
10103 /* This is the Right Way, in that the value to be pushed is
10104 established before %esp is changed, so that pushl %esp
10105 correctly pushes the old value. */
10106 vassert(sz == 2 || sz == 4);
10107 ty = sz==2 ? Ity_I16 : Ity_I32;
sewardj883b00b2004-09-11 09:30:24 +000010108 t1 = newTemp(ty); t2 = newTemp(Ity_I32);
sewardj41f43bc2004-07-08 14:23:22 +000010109 assign(t1, getIReg(sz, opc-0x50));
10110 assign(t2, binop(Iop_Sub32, getIReg(4, R_ESP), mkU32(sz)));
10111 putIReg(4, R_ESP, mkexpr(t2) );
10112 storeLE(mkexpr(t2),mkexpr(t1));
sewardjd1061ab2004-07-08 01:45:30 +000010113 DIP("push%c %s\n", nameISize(sz), nameIReg(sz,opc-0x50));
10114 break;
10115
10116
sewardj0c12ea82004-07-12 08:18:16 +000010117 case 0x68: /* PUSH Iv */
10118 d32 = getUDisp(sz,delta); delta += sz;
10119 goto do_push_I;
sewardj741153c2004-07-25 23:39:13 +000010120 case 0x6A: /* PUSH Ib, sign-extended to sz */
10121 d32 = getSDisp8(delta); delta += 1;
10122 goto do_push_I;
sewardj0c12ea82004-07-12 08:18:16 +000010123 do_push_I:
10124 ty = szToITy(sz);
10125 t1 = newTemp(Ity_I32); t2 = newTemp(ty);
10126 assign( t1, binop(Iop_Sub32,getIReg(4,R_ESP),mkU32(sz)) );
10127 putIReg(4, R_ESP, mkexpr(t1) );
10128 storeLE( mkexpr(t1), mkU(ty,d32) );
10129 DIP("push%c $0x%x\n", nameISize(sz), d32);
10130 break;
10131
sewardja2384712004-07-29 14:36:40 +000010132 case 0x9C: /* PUSHF */ {
sewardja2384712004-07-29 14:36:40 +000010133 vassert(sz == 2 || sz == 4);
10134 vassert(sz == 4); // wait for sz==2 test case
10135
10136 t1 = newTemp(Ity_I32);
10137 assign( t1, binop(Iop_Sub32,getIReg(4,R_ESP),mkU32(sz)) );
10138 putIReg(4, R_ESP, mkexpr(t1) );
10139
10140 t2 = newTemp(Ity_I32);
sewardj2a9ad022004-11-25 02:46:58 +000010141 assign( t2, mk_x86g_calculate_eflags_all() );
sewardja2384712004-07-29 14:36:40 +000010142
10143 /* Patch in the D flag. This can simply be the inversion
sewardj5bd4d162004-11-10 13:02:48 +000010144 of bit 10 of baseBlock[OFFB_DFLAG]. */
sewardja2384712004-07-29 14:36:40 +000010145 t3 = newTemp(Ity_I32);
10146 assign( t3, binop(Iop_Or32,
10147 mkexpr(t2),
10148 binop(Iop_And32,
sewardj5bd4d162004-11-10 13:02:48 +000010149 unop(Iop_Not32, IRExpr_Get(OFFB_DFLAG,Ity_I32)),
10150 mkU32(1<<10)))
sewardja2384712004-07-29 14:36:40 +000010151 );
sewardj006a6a22004-10-26 00:50:52 +000010152
10153 /* And patch in the ID flag. */
10154 t4 = newTemp(Ity_I32);
10155 assign( t4, binop(Iop_Or32,
10156 mkexpr(t3),
10157 binop(Iop_And32,
sewardj5bd4d162004-11-10 13:02:48 +000010158 binop(Iop_Shl32, IRExpr_Get(OFFB_IDFLAG,Ity_I32),
sewardj006a6a22004-10-26 00:50:52 +000010159 mkU8(21)),
sewardj5bd4d162004-11-10 13:02:48 +000010160 mkU32(1<<21)))
sewardj006a6a22004-10-26 00:50:52 +000010161 );
10162
sewardja2384712004-07-29 14:36:40 +000010163 /* if sz==2, the stored value needs to be narrowed. */
10164 if (sz == 2)
sewardj5bd4d162004-11-10 13:02:48 +000010165 storeLE( mkexpr(t1), unop(Iop_32to16,mkexpr(t4)) );
sewardja2384712004-07-29 14:36:40 +000010166 else
sewardj5bd4d162004-11-10 13:02:48 +000010167 storeLE( mkexpr(t1), mkexpr(t4) );
sewardja2384712004-07-29 14:36:40 +000010168
10169 DIP("pushf%c\n", nameISize(sz));
10170 break;
10171 }
10172
sewardjc9a65702004-07-07 16:32:57 +000010173//-- case 0x60: /* PUSHA */
10174//-- { Int reg;
10175//-- /* Just to keep things sane, we assert for a size 4. It's
10176//-- probably OK for size 2 as well, but I'd like to find a test
10177//-- case; ie, have the assertion fail, before committing to it.
10178//-- If it fails for you, uncomment the sz == 2 bit, try again,
10179//-- and let me know whether or not it works. (jseward@acm.org). */
10180//-- vg_assert(sz == 4 /* || sz == 2 */);
10181//--
10182//-- /* This is the Right Way, in that the value to be pushed is
10183//-- established before %esp is changed, so that pusha
10184//-- correctly pushes the old %esp value. New value of %esp is
10185//-- pushed at start. */
10186//-- t1 = newTemp(cb); t2 = newTemp(cb); t3 = newTemp(cb);
10187//-- t4 = newTemp(cb);
10188//-- uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t3);
10189//-- uInstr2(cb, MOV, 4, TempReg, t3, TempReg, t2);
10190//-- uInstr2(cb, MOV, 4, TempReg, t3, TempReg, t4);
10191//-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t4);
10192//-- uLiteral(cb, sz * 8); /* One 'sz' per register. */
10193//-- uInstr2(cb, PUT, 4, TempReg, t4, ArchReg, R_ESP);
10194//-- /* Do %eax, %ecx, %edx, %ebx */
10195//-- for (reg = 0; reg <= 3; reg++) {
10196//-- uInstr2(cb, GET, sz, ArchReg, reg, TempReg, t1);
10197//-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
10198//-- uLiteral(cb, sz);
10199//-- uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t2);
10200//-- }
10201//-- /* Push old value of %esp */
10202//-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
10203//-- uLiteral(cb, sz);
10204//-- uInstr2(cb, STORE, sz, TempReg, t3, TempReg, t2);
10205//-- /* Do %ebp, %esi, %edi */
10206//-- for (reg = 5; reg <= 7; reg++) {
10207//-- uInstr2(cb, GET, sz, ArchReg, reg, TempReg, t1);
10208//-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
10209//-- uLiteral(cb, sz);
10210//-- uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t2);
10211//-- }
10212//-- DIP("pusha%c\n", nameISize(sz));
10213//-- break;
10214//-- }
10215//--
10216//-- case 0x0E: /* PUSH %CS */
10217//-- dis_push_segreg( cb, R_CS, sz ); break;
10218//-- case 0x1E: /* PUSH %DS */
10219//-- dis_push_segreg( cb, R_DS, sz ); break;
10220//-- case 0x06: /* PUSH %ES */
10221//-- dis_push_segreg( cb, R_ES, sz ); break;
10222//-- case 0x16: /* PUSH %SS */
10223//-- dis_push_segreg( cb, R_SS, sz ); break;
sewardj458a6f82004-08-25 12:46:02 +000010224
10225 /* ------------------------ SCAS et al ----------------- */
10226
10227 case 0xA4: /* MOVS, no REP prefix */
10228 case 0xA5:
10229 dis_string_op( dis_MOVS, ( opc == 0xA4 ? 1 : sz ), "movs", sorb );
10230 break;
10231
sewardjc9a65702004-07-07 16:32:57 +000010232//-- case 0xA6: /* CMPSb, no REP prefix */
10233//-- case 0xA7:
10234//-- dis_string_op( cb, dis_CMPS, ( opc == 0xA6 ? 1 : sz ), "cmps", sorb );
10235//-- break;
10236//--
sewardj883b00b2004-09-11 09:30:24 +000010237 case 0xAA: /* STOS, no REP prefix */
sewardj47341042004-09-19 11:55:46 +000010238 case 0xAB:
sewardj883b00b2004-09-11 09:30:24 +000010239 dis_string_op( dis_STOS, ( opc == 0xAA ? 1 : sz ), "stos", sorb );
10240 break;
sewardjc9a65702004-07-07 16:32:57 +000010241//--
10242//-- case 0xAC: /* LODS, no REP prefix */
10243//-- case 0xAD:
10244//-- dis_string_op( cb, dis_LODS, ( opc == 0xAC ? 1 : sz ), "lods", sorb );
10245//-- break;
sewardj2d4c3a02004-10-15 00:03:23 +000010246
10247 case 0xAE: /* SCAS, no REP prefix */
10248 case 0xAF:
10249 dis_string_op( dis_SCAS, ( opc == 0xAE ? 1 : sz ), "scas", sorb );
10250 break;
sewardj64e1d652004-07-12 14:00:46 +000010251
10252
10253 case 0xFC: /* CLD */
sewardjeeb9ef82004-07-15 12:39:03 +000010254 stmt( IRStmt_Put( OFFB_DFLAG, mkU32(1)) );
sewardj64e1d652004-07-12 14:00:46 +000010255 DIP("cld\n");
10256 break;
10257
sewardj1813dbe2004-07-28 17:09:04 +000010258 case 0xFD: /* STD */
10259 stmt( IRStmt_Put( OFFB_DFLAG, mkU32(0xFFFFFFFF)) );
10260 DIP("std\n");
10261 break;
10262
sewardjc9a65702004-07-07 16:32:57 +000010263//-- case 0xF8: /* CLC */
10264//-- uInstr0(cb, CALLM_S, 0);
10265//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_CLC));
10266//-- uFlagsRWU(cb, FlagsEmpty, FlagC, FlagsOSZAP);
10267//-- uInstr0(cb, CALLM_E, 0);
10268//-- DIP("clc\n");
10269//-- break;
10270//--
10271//-- case 0xF9: /* STC */
10272//-- uInstr0(cb, CALLM_S, 0);
10273//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_STC));
10274//-- uFlagsRWU(cb, FlagsEmpty, FlagC, FlagsOSZAP);
10275//-- uInstr0(cb, CALLM_E, 0);
10276//-- DIP("stc\n");
10277//-- break;
10278//--
10279//-- case 0xF5: /* CMC */
10280//-- uInstr0(cb, CALLM_S, 0);
10281//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_CMC));
10282//-- uFlagsRWU(cb, FlagC, FlagC, FlagsOSZAP);
10283//-- uInstr0(cb, CALLM_E, 0);
10284//-- DIP("cmc\n");
10285//-- break;
sewardj82292882004-07-27 00:15:59 +000010286
10287 /* REPNE prefix insn */
10288 case 0xF2: {
sewardjce70a5c2004-10-18 14:09:54 +000010289 Addr32 eip_orig = guest_eip_bbstart + delta - 1;
sewardj82292882004-07-27 00:15:59 +000010290 vassert(sorb == 0);
10291 abyte = getIByte(delta); delta++;
10292
10293 if (abyte == 0x66) { sz = 2; abyte = getIByte(delta); delta++; }
sewardjce70a5c2004-10-18 14:09:54 +000010294 whatNext = Dis_StopHere;
sewardj82292882004-07-27 00:15:59 +000010295
10296 switch (abyte) {
10297 /* According to the Intel manual, "repne movs" should never occur, but
10298 * in practice it has happened, so allow for it here... */
sewardj180e8b32004-07-29 01:40:11 +000010299 case 0xA4: sz = 1; /* REPNE MOVS<sz> */
sewardj5bd4d162004-11-10 13:02:48 +000010300 vassert(0);
sewardjc9a65702004-07-07 16:32:57 +000010301//-- case 0xA5:
sewardj5bd4d162004-11-10 13:02:48 +000010302 // dis_REP_op ( CondNZ, dis_MOVS, sz, eip_orig,
10303 // guest_eip_bbstart+delta, "repne movs" );
10304 // break;
sewardjc9a65702004-07-07 16:32:57 +000010305//--
10306//-- case 0xA6: sz = 1; /* REPNE CMPS<sz> */
10307//-- case 0xA7:
10308//-- dis_REP_op ( cb, CondNZ, dis_CMPS, sz, eip_orig, eip, "repne cmps" );
10309//-- break;
10310//--
sewardj82292882004-07-27 00:15:59 +000010311 case 0xAE: sz = 1; /* REPNE SCAS<sz> */
sewardj2d4c3a02004-10-15 00:03:23 +000010312 case 0xAF:
sewardj2a9ad022004-11-25 02:46:58 +000010313 dis_REP_op ( X86CondNZ, dis_SCAS, sz, eip_orig,
10314 guest_eip_bbstart+delta, "repne scas" );
sewardj82292882004-07-27 00:15:59 +000010315 break;
10316
10317 default:
10318 goto decode_failure;
10319 }
10320 break;
10321 }
sewardj64e1d652004-07-12 14:00:46 +000010322
10323 /* REP/REPE prefix insn (for SCAS and CMPS, 0xF3 means REPE,
10324 for the rest, it means REP) */
10325 case 0xF3: {
sewardjce70a5c2004-10-18 14:09:54 +000010326 Addr32 eip_orig = guest_eip_bbstart + delta - 1;
sewardj64e1d652004-07-12 14:00:46 +000010327 vassert(sorb == 0);
10328 abyte = getIByte(delta); delta++;
10329
10330 if (abyte == 0x66) { sz = 2; abyte = getIByte(delta); delta++; }
sewardjce70a5c2004-10-18 14:09:54 +000010331 whatNext = Dis_StopHere;
sewardj64e1d652004-07-12 14:00:46 +000010332
10333 switch (abyte) {
10334 case 0xA4: sz = 1; /* REP MOVS<sz> */
10335 case 0xA5:
sewardj2a9ad022004-11-25 02:46:58 +000010336 dis_REP_op ( X86CondAlways, dis_MOVS, sz, eip_orig,
10337 guest_eip_bbstart+delta, "rep movs" );
sewardj64e1d652004-07-12 14:00:46 +000010338 break;
10339
10340 case 0xA6: sz = 1; /* REPE CMP<sz> */
sewardj2d4c3a02004-10-15 00:03:23 +000010341 case 0xA7:
sewardj2a9ad022004-11-25 02:46:58 +000010342 dis_REP_op ( X86CondZ, dis_CMPS, sz, eip_orig,
10343 guest_eip_bbstart+delta, "repe cmps" );
sewardj64e1d652004-07-12 14:00:46 +000010344 break;
10345
10346 case 0xAA: sz = 1; /* REP STOS<sz> */
10347 case 0xAB:
sewardj2a9ad022004-11-25 02:46:58 +000010348 dis_REP_op ( X86CondAlways, dis_STOS, sz, eip_orig,
10349 guest_eip_bbstart+delta, "rep stos" );
sewardj64e1d652004-07-12 14:00:46 +000010350 break;
sewardjc9a65702004-07-07 16:32:57 +000010351//--
10352//-- case 0xAE: sz = 1; /* REPE SCAS<sz> */
10353//-- case 0xAF:
10354//-- dis_REP_op ( cb, CondZ, dis_SCAS, sz, eip_orig, eip, "repe scas" );
10355//-- break;
sewardj43b8df12004-11-26 12:18:51 +000010356
10357 case 0x90: /* REP NOP (PAUSE) */
10358 /* a hint to the P4 re spin-wait loop */
10359 DIP("rep nop (P4 pause)\n");
10360 jmp_lit(Ijk_Yield, ((Addr32)guest_eip_bbstart)+delta);
10361 whatNext = Dis_StopHere;
10362 break;
10363
sewardjc9a65702004-07-07 16:32:57 +000010364//-- case 0xC3: /* REP RET */
10365//-- /* AMD K7/K8-specific optimisation; faster than vanilla RET */
10366//-- dis_ret(cb, 0);
10367//-- DIP("rep ret\n");
10368//-- break;
sewardj64e1d652004-07-12 14:00:46 +000010369
10370 default:
10371 goto decode_failure;
10372 }
10373 break;
10374 }
sewardj0611d802004-07-11 02:37:54 +000010375
10376 /* ------------------------ XCHG ----------------------- */
10377
10378 case 0x86: /* XCHG Gb,Eb */
10379 sz = 1;
10380 /* Fall through ... */
10381 case 0x87: /* XCHG Gv,Ev */
10382 modrm = getIByte(delta);
10383 ty = szToITy(sz);
10384 t1 = newTemp(ty); t2 = newTemp(ty);
10385 if (epartIsReg(modrm)) {
sewardj5bd4d162004-11-10 13:02:48 +000010386 assign(t1, getIReg(sz, eregOfRM(modrm)));
10387 assign(t2, getIReg(sz, gregOfRM(modrm)));
10388 putIReg(sz, gregOfRM(modrm), mkexpr(t1));
10389 putIReg(sz, eregOfRM(modrm), mkexpr(t2));
sewardj0611d802004-07-11 02:37:54 +000010390 delta++;
10391 DIP("xchg%c %s, %s\n",
10392 nameISize(sz), nameIReg(sz,gregOfRM(modrm)),
10393 nameIReg(sz,eregOfRM(modrm)));
10394 } else {
sewardj0c12ea82004-07-12 08:18:16 +000010395 addr = disAMode ( &alen, sorb, delta, dis_buf );
sewardj5bd4d162004-11-10 13:02:48 +000010396 assign( t1, loadLE(ty,mkexpr(addr)) );
10397 assign( t2, getIReg(sz,gregOfRM(modrm)) );
10398 storeLE( mkexpr(addr), mkexpr(t2) );
10399 putIReg( sz, gregOfRM(modrm), mkexpr(t1) );
10400 delta += alen;
sewardj0611d802004-07-11 02:37:54 +000010401 DIP("xchg%c %s, %s\n", nameISize(sz),
10402 nameIReg(sz,gregOfRM(modrm)), dis_buf);
sewardj0611d802004-07-11 02:37:54 +000010403 }
10404 break;
sewardje87b4842004-07-10 12:23:30 +000010405
10406 case 0x90: /* XCHG eAX,eAX */
10407 DIP("nop\n");
10408 break;
sewardj64e1d652004-07-12 14:00:46 +000010409 case 0x91: /* XCHG eAX,eCX */
10410 case 0x92: /* XCHG eAX,eDX */
10411 case 0x93: /* XCHG eAX,eBX */
10412 case 0x94: /* XCHG eAX,eSP */
10413 case 0x95: /* XCHG eAX,eBP */
10414 case 0x96: /* XCHG eAX,eSI */
10415 case 0x97: /* XCHG eAX,eDI */
10416 codegen_xchg_eAX_Reg ( sz, opc - 0x90 );
10417 break;
10418
sewardjc9a65702004-07-07 16:32:57 +000010419//-- /* ------------------------ XLAT ----------------------- */
10420//--
10421//-- case 0xD7: /* XLAT */
10422//-- t1 = newTemp(cb); t2 = newTemp(cb);
10423//-- uInstr2(cb, GET, sz, ArchReg, R_EBX, TempReg, t1); /* get eBX */
10424//-- handleSegOverride( cb, sorb, t1 ); /* make t1 DS:eBX */
10425//-- uInstr2(cb, GET, 1, ArchReg, R_AL, TempReg, t2); /* get AL */
10426//-- /* Widen %AL to 32 bits, so it's all defined when we add it. */
10427//-- uInstr1(cb, WIDEN, 4, TempReg, t2);
10428//-- uWiden(cb, 1, False);
10429//-- uInstr2(cb, ADD, sz, TempReg, t2, TempReg, t1); /* add AL to eBX */
10430//-- uInstr2(cb, LOAD, 1, TempReg, t1, TempReg, t2); /* get byte at t1 into t2 */
10431//-- uInstr2(cb, PUT, 1, TempReg, t2, ArchReg, R_AL); /* put byte into AL */
10432//--
10433//-- DIP("xlat%c [ebx]\n", nameISize(sz));
10434//-- break;
10435//--
10436//-- /* ------------------------ IN / OUT ----------------------- */
10437//--
10438//-- case 0xE4: /* IN ib, %al */
10439//-- case 0xE5: /* IN ib, %{e}ax */
10440//-- case 0xEC: /* IN (%dx),%al */
10441//-- case 0xED: /* IN (%dx),%{e}ax */
10442//-- t1 = newTemp(cb);
10443//-- t2 = newTemp(cb);
10444//-- t3 = newTemp(cb);
10445//--
10446//-- uInstr0(cb, CALLM_S, 0);
10447//-- /* operand size? */
10448//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t1);
10449//-- uLiteral(cb, ( opc == 0xE4 || opc == 0xEC ) ? 1 : sz);
10450//-- uInstr1(cb, PUSH, 4, TempReg, t1);
10451//-- /* port number ? */
10452//-- if ( opc == 0xE4 || opc == 0xE5 ) {
10453//-- abyte = getUChar(eip); eip++;
10454//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
10455//-- uLiteral(cb, abyte);
10456//-- }
10457//-- else
10458//-- uInstr2(cb, GET, 4, ArchReg, R_EDX, TempReg, t2);
10459//--
10460//-- uInstr1(cb, PUSH, 4, TempReg, t2);
10461//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_IN));
10462//-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
10463//-- uInstr1(cb, POP, 4, TempReg, t2);
10464//-- uInstr1(cb, CLEAR, 0, Lit16, 4);
10465//-- uInstr0(cb, CALLM_E, 0);
10466//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_EAX);
10467//-- if ( opc == 0xE4 || opc == 0xE5 ) {
10468//-- DIP("in 0x%x, %%eax/%%ax/%%al\n", getUChar(eip-1) );
10469//-- } else {
10470//-- DIP("in (%%dx), %%eax/%%ax/%%al\n");
10471//-- }
10472//-- break;
10473//-- case 0xE6: /* OUT %al,ib */
10474//-- case 0xE7: /* OUT %{e}ax,ib */
10475//-- case 0xEE: /* OUT %al,(%dx) */
10476//-- case 0xEF: /* OUT %{e}ax,(%dx) */
10477//-- t1 = newTemp(cb);
10478//-- t2 = newTemp(cb);
10479//-- t3 = newTemp(cb);
10480//--
10481//-- uInstr0(cb, CALLM_S, 0);
10482//-- /* operand size? */
10483//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t1);
10484//-- uLiteral(cb, ( opc == 0xE6 || opc == 0xEE ) ? 1 : sz);
10485//-- uInstr1(cb, PUSH, 4, TempReg, t1);
10486//-- /* port number ? */
10487//-- if ( opc == 0xE6 || opc == 0xE7 ) {
10488//-- abyte = getUChar(eip); eip++;
10489//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
10490//-- uLiteral(cb, abyte);
10491//-- }
10492//-- else
10493//-- uInstr2(cb, GET, 4, ArchReg, R_EDX, TempReg, t2);
10494//-- uInstr1(cb, PUSH, 4, TempReg, t2);
10495//-- uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, t3);
10496//-- uInstr1(cb, PUSH, 4, TempReg, t3);
10497//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_OUT));
10498//-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
10499//-- uInstr1(cb, CLEAR, 0, Lit16, 12);
10500//-- uInstr0(cb, CALLM_E, 0);
10501//-- if ( opc == 0xE4 || opc == 0xE5 ) {
10502//-- DIP("out %%eax/%%ax/%%al, 0x%x\n", getUChar(eip-1) );
10503//-- } else {
10504//-- DIP("out %%eax/%%ax/%%al, (%%dx)\n");
10505//-- }
10506//-- break;
sewardj0611d802004-07-11 02:37:54 +000010507
10508 /* ------------------------ (Grp1 extensions) ---------- */
10509
10510 case 0x80: /* Grp1 Ib,Eb */
10511 modrm = getIByte(delta);
10512 am_sz = lengthAMode(delta);
10513 sz = 1;
10514 d_sz = 1;
sewardjc2ac51e2004-07-12 01:03:26 +000010515 d32 = getUChar(delta + am_sz);
sewardj0611d802004-07-11 02:37:54 +000010516 delta = dis_Grp1 ( sorb, delta, modrm, am_sz, d_sz, sz, d32 );
10517 break;
sewardje05c42c2004-07-08 20:25:10 +000010518
10519 case 0x81: /* Grp1 Iv,Ev */
10520 modrm = getIByte(delta);
10521 am_sz = lengthAMode(delta);
10522 d_sz = sz;
10523 d32 = getUDisp(d_sz, delta + am_sz);
10524 delta = dis_Grp1 ( sorb, delta, modrm, am_sz, d_sz, sz, d32 );
10525 break;
sewardjd1061ab2004-07-08 01:45:30 +000010526
10527 case 0x83: /* Grp1 Ib,Ev */
10528 modrm = getIByte(delta);
10529 am_sz = lengthAMode(delta);
10530 d_sz = 1;
10531 d32 = getSDisp8(delta + am_sz);
10532 delta = dis_Grp1 ( sorb, delta, modrm, am_sz, d_sz, sz, d32 );
10533 break;
10534
sewardjc2ac51e2004-07-12 01:03:26 +000010535 /* ------------------------ (Grp2 extensions) ---------- */
10536
10537 case 0xC0: /* Grp2 Ib,Eb */
10538 modrm = getIByte(delta);
10539 am_sz = lengthAMode(delta);
10540 d_sz = 1;
sewardj180e8b32004-07-29 01:40:11 +000010541 d32 = getUChar(delta + am_sz);
sewardjc2ac51e2004-07-12 01:03:26 +000010542 sz = 1;
sewardj6d2638e2004-07-15 09:38:27 +000010543 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
10544 mkU8(d32 & 0xFF), NULL );
sewardjc2ac51e2004-07-12 01:03:26 +000010545 break;
sewardje90ad6a2004-07-10 19:02:10 +000010546
10547 case 0xC1: /* Grp2 Ib,Ev */
sewardjc2ac51e2004-07-12 01:03:26 +000010548 modrm = getIByte(delta);
sewardje90ad6a2004-07-10 19:02:10 +000010549 am_sz = lengthAMode(delta);
10550 d_sz = 1;
sewardj180e8b32004-07-29 01:40:11 +000010551 d32 = getUChar(delta + am_sz);
sewardj6d2638e2004-07-15 09:38:27 +000010552 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
10553 mkU8(d32 & 0xFF), NULL );
sewardje90ad6a2004-07-10 19:02:10 +000010554 break;
10555
sewardj180e8b32004-07-29 01:40:11 +000010556 case 0xD0: /* Grp2 1,Eb */
10557 modrm = getIByte(delta);
10558 am_sz = lengthAMode(delta);
10559 d_sz = 0;
10560 d32 = 1;
10561 sz = 1;
10562 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
10563 mkU8(d32), NULL );
10564 break;
sewardjc2ac51e2004-07-12 01:03:26 +000010565
10566 case 0xD1: /* Grp2 1,Ev */
10567 modrm = getUChar(delta);
10568 am_sz = lengthAMode(delta);
10569 d_sz = 0;
10570 d32 = 1;
sewardj6d2638e2004-07-15 09:38:27 +000010571 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
10572 mkU8(d32), NULL );
sewardjc2ac51e2004-07-12 01:03:26 +000010573 break;
10574
sewardj8c7f1ab2004-07-29 20:31:09 +000010575 case 0xD2: /* Grp2 CL,Eb */
10576 modrm = getUChar(delta);
10577 am_sz = lengthAMode(delta);
10578 d_sz = 0;
10579 sz = 1;
10580 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
10581 getIReg(1,R_ECX), "%cl" );
10582 break;
sewardj9334b0f2004-07-10 22:43:54 +000010583
10584 case 0xD3: /* Grp2 CL,Ev */
10585 modrm = getIByte(delta);
10586 am_sz = lengthAMode(delta);
10587 d_sz = 0;
10588 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
sewardj6d2638e2004-07-15 09:38:27 +000010589 getIReg(1,R_ECX), "%cl" );
sewardj9334b0f2004-07-10 22:43:54 +000010590 break;
10591
sewardj940e8c92004-07-11 16:53:24 +000010592 /* ------------------------ (Grp3 extensions) ---------- */
10593
10594 case 0xF6: /* Grp3 Eb */
10595 delta = dis_Grp3 ( sorb, 1, delta );
10596 break;
10597 case 0xF7: /* Grp3 Ev */
10598 delta = dis_Grp3 ( sorb, sz, delta );
10599 break;
10600
sewardjc2ac51e2004-07-12 01:03:26 +000010601 /* ------------------------ (Grp4 extensions) ---------- */
10602
10603 case 0xFE: /* Grp4 Eb */
10604 delta = dis_Grp4 ( sorb, delta );
10605 break;
sewardj0611d802004-07-11 02:37:54 +000010606
10607 /* ------------------------ (Grp5 extensions) ---------- */
10608
10609 case 0xFF: /* Grp5 Ev */
sewardjce70a5c2004-10-18 14:09:54 +000010610 delta = dis_Grp5 ( sorb, sz, delta, &whatNext );
sewardj0611d802004-07-11 02:37:54 +000010611 break;
sewardje87b4842004-07-10 12:23:30 +000010612
10613 /* ------------------------ Escapes to 2-byte opcodes -- */
10614
10615 case 0x0F: {
10616 opc = getIByte(delta); delta++;
10617 switch (opc) {
10618
sewardjc9a65702004-07-07 16:32:57 +000010619//-- /* =-=-=-=-=-=-=-=-=- Grp8 =-=-=-=-=-=-=-=-=-=-=-= */
10620//--
10621//-- case 0xBA: /* Grp8 Ib,Ev */
10622//-- modrm = getUChar(eip);
10623//-- am_sz = lengthAMode(eip);
10624//-- d32 = getSDisp8(eip + am_sz);
10625//-- eip = dis_Grp8_BT ( cb, sorb, eip, modrm, am_sz, sz, d32 );
10626//-- break;
sewardjce646f22004-08-31 23:55:54 +000010627
10628 /* =-=-=-=-=-=-=-=-=- BSF/BSR -=-=-=-=-=-=-=-=-=-= */
10629
10630 case 0xBC: /* BSF Gv,Ev */
10631 delta = dis_bs_E_G ( sorb, sz, delta, True );
10632 break;
10633 case 0xBD: /* BSR Gv,Ev */
10634 delta = dis_bs_E_G ( sorb, sz, delta, False );
10635 break;
sewardj1c4208f2004-08-25 13:25:29 +000010636
10637 /* =-=-=-=-=-=-=-=-=- BSWAP -=-=-=-=-=-=-=-=-=-=-= */
10638
10639 case 0xC8: /* BSWAP %eax */
10640 case 0xC9:
10641 case 0xCA:
sewardjb4666cf2004-10-23 00:21:50 +000010642 case 0xCB:
10643 case 0xCC:
10644 case 0xCD:
sewardj1c4208f2004-08-25 13:25:29 +000010645 case 0xCE:
sewardj1c6f9912004-09-07 10:15:24 +000010646 case 0xCF: /* BSWAP %edi */
sewardj1c4208f2004-08-25 13:25:29 +000010647 /* AFAICS from the Intel docs, this only exists at size 4. */
10648 vassert(sz == 4);
10649 t1 = newTemp(Ity_I32);
10650 t2 = newTemp(Ity_I32);
10651 assign( t1, getIReg(4, opc-0xC8) );
10652
10653 assign( t2,
10654 binop(Iop_Or32,
10655 binop(Iop_Shl32, mkexpr(t1), mkU8(24)),
10656 binop(Iop_Or32,
10657 binop(Iop_And32, binop(Iop_Shl32, mkexpr(t1), mkU8(8)),
10658 mkU32(0x00FF0000)),
10659 binop(Iop_Or32,
10660 binop(Iop_And32, binop(Iop_Shr32, mkexpr(t1), mkU8(8)),
10661 mkU32(0x0000FF00)),
10662 binop(Iop_And32, binop(Iop_Shr32, mkexpr(t1), mkU8(24)),
10663 mkU32(0x000000FF) )
10664 )))
10665 );
10666
10667 putIReg(4, opc-0xC8, mkexpr(t2));
sewardj1c4208f2004-08-25 13:25:29 +000010668 DIP("bswapl %s\n", nameIReg(4, opc-0xC8));
10669 break;
10670
sewardj1c6f9912004-09-07 10:15:24 +000010671 /* =-=-=-=-=-=-=-=-=- BT/BTS/BTR/BTC =-=-=-=-=-=-= */
10672
10673 case 0xA3: /* BT Gv,Ev */
10674 delta = dis_bt_G_E ( sorb, sz, delta, BtOpNone );
10675 break;
sewardje6709112004-09-10 18:37:18 +000010676 case 0xB3: /* BTR Gv,Ev */
10677 delta = dis_bt_G_E ( sorb, sz, delta, BtOpReset );
10678 break;
sewardj1c6f9912004-09-07 10:15:24 +000010679 case 0xAB: /* BTS Gv,Ev */
10680 delta = dis_bt_G_E ( sorb, sz, delta, BtOpSet );
10681 break;
sewardj4963a422004-10-14 23:34:03 +000010682 case 0xBB: /* BTC Gv,Ev */
10683 delta = dis_bt_G_E ( sorb, sz, delta, BtOpComp );
10684 break;
sewardj458a6f82004-08-25 12:46:02 +000010685
10686 /* =-=-=-=-=-=-=-=-=- CMOV =-=-=-=-=-=-=-=-=-=-=-= */
10687
sewardj2d4c3a02004-10-15 00:03:23 +000010688 case 0x40:
10689 case 0x41:
sewardj458a6f82004-08-25 12:46:02 +000010690 case 0x42: /* CMOVBb/CMOVNAEb (cmov below) */
10691 case 0x43: /* CMOVNBb/CMOVAEb (cmov not below) */
10692 case 0x44: /* CMOVZb/CMOVEb (cmov zero) */
10693 case 0x45: /* CMOVNZb/CMOVNEb (cmov not zero) */
10694 case 0x46: /* CMOVBEb/CMOVNAb (cmov below or equal) */
10695 case 0x47: /* CMOVNBEb/CMOVAb (cmov not below or equal) */
sewardjce646f22004-08-31 23:55:54 +000010696 case 0x48: /* CMOVSb (cmov negative) */
sewardj458a6f82004-08-25 12:46:02 +000010697 case 0x49: /* CMOVSb (cmov not negative) */
sewardj2d4c3a02004-10-15 00:03:23 +000010698 case 0x4A: /* CMOVP (cmov parity even) */
10699 case 0x4B: /* CMOVNP (cmov parity odd) */
sewardj458a6f82004-08-25 12:46:02 +000010700 case 0x4C: /* CMOVLb/CMOVNGEb (cmov less) */
10701 case 0x4D: /* CMOVGEb/CMOVNLb (cmov greater or equal) */
10702 case 0x4E: /* CMOVLEb/CMOVNGb (cmov less or equal) */
10703 case 0x4F: /* CMOVGb/CMOVNLEb (cmov greater) */
sewardj2a9ad022004-11-25 02:46:58 +000010704 delta = dis_cmov_E_G(sorb, sz, (X86Condcode)(opc - 0x40), delta);
sewardj458a6f82004-08-25 12:46:02 +000010705 break;
10706
10707 /* =-=-=-=-=-=-=-=-=- CMPXCHG -=-=-=-=-=-=-=-=-=-= */
10708
sewardjc744e872004-08-26 11:24:39 +000010709 case 0xB0: /* CMPXCHG Gb,Eb */
10710 delta = dis_cmpxchg_G_E ( sorb, 1, delta );
10711 break;
sewardj458a6f82004-08-25 12:46:02 +000010712 case 0xB1: /* CMPXCHG Gv,Ev */
10713 delta = dis_cmpxchg_G_E ( sorb, sz, delta );
10714 break;
sewardjc9a65702004-07-07 16:32:57 +000010715//-- case 0xC7: /* CMPXCHG8B Gv */
10716//-- eip = dis_cmpxchg8b ( cb, sorb, eip );
10717//-- break;
10718//--
sewardj588ea762004-09-10 18:56:32 +000010719 /* =-=-=-=-=-=-=-=-=- CPUID -=-=-=-=-=-=-=-=-=-=-= */
10720
sewardj7cb49d72004-10-24 22:31:25 +000010721 case 0xA2: { /* CPUID */
10722 /* Uses dirty helper:
10723 void dirtyhelper_CPUID ( VexGuestX86State* )
10724 declared to mod eax, wr ebx, ecx, edx
10725 */
sewardjf9655262004-10-31 20:02:16 +000010726 IRDirty* d = unsafeIRDirty_0_N (
10727 0/*regparms*/,
sewardj2a9ad022004-11-25 02:46:58 +000010728 "x86g_dirtyhelper_CPUID",
10729 &x86g_dirtyhelper_CPUID,
sewardjf9655262004-10-31 20:02:16 +000010730 mkIRExprVec_0()
10731 );
sewardj7cb49d72004-10-24 22:31:25 +000010732 /* declare guest state effects */
sewardjc5fc7aa2004-10-27 23:00:55 +000010733 d->needsBBP = True;
sewardj7cb49d72004-10-24 22:31:25 +000010734 d->nFxState = 4;
10735 d->fxState[0].fx = Ifx_Modify;
10736 d->fxState[0].offset = OFFB_EAX;
10737 d->fxState[0].size = 4;
10738 d->fxState[1].fx = Ifx_Write;
10739 d->fxState[1].offset = OFFB_EBX;
10740 d->fxState[1].size = 4;
10741 d->fxState[2].fx = Ifx_Write;
10742 d->fxState[2].offset = OFFB_ECX;
10743 d->fxState[2].size = 4;
10744 d->fxState[3].fx = Ifx_Write;
10745 d->fxState[3].offset = OFFB_EDX;
10746 d->fxState[3].size = 4;
10747 /* execute the dirty call, side-effecting guest state */
10748 stmt( IRStmt_Dirty(d) );
sewardj517a7d62004-10-25 09:52:18 +000010749 DIP("cpuid\n");
sewardj588ea762004-09-10 18:56:32 +000010750 break;
sewardj7cb49d72004-10-24 22:31:25 +000010751 }
10752
sewardj5bd4d162004-11-10 13:02:48 +000010753//-- if (!VG_(cpu_has_feature)(VG_X86_FEAT_CPUID))
10754//-- goto decode_failure;
sewardjc9a65702004-07-07 16:32:57 +000010755//--
10756//-- t1 = newTemp(cb);
10757//-- t2 = newTemp(cb);
10758//-- t3 = newTemp(cb);
10759//-- t4 = newTemp(cb);
10760//-- uInstr0(cb, CALLM_S, 0);
10761//--
10762//-- uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, t1);
10763//-- uInstr1(cb, PUSH, 4, TempReg, t1);
10764//--
10765//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
10766//-- uLiteral(cb, 0);
10767//-- uInstr1(cb, PUSH, 4, TempReg, t2);
10768//--
10769//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t3);
10770//-- uLiteral(cb, 0);
10771//-- uInstr1(cb, PUSH, 4, TempReg, t3);
10772//--
10773//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t4);
10774//-- uLiteral(cb, 0);
10775//-- uInstr1(cb, PUSH, 4, TempReg, t4);
10776//--
10777//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_CPUID));
10778//-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
10779//--
10780//-- uInstr1(cb, POP, 4, TempReg, t4);
10781//-- uInstr2(cb, PUT, 4, TempReg, t4, ArchReg, R_EDX);
10782//--
10783//-- uInstr1(cb, POP, 4, TempReg, t3);
10784//-- uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_ECX);
10785//--
10786//-- uInstr1(cb, POP, 4, TempReg, t2);
10787//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_EBX);
10788//--
10789//-- uInstr1(cb, POP, 4, TempReg, t1);
10790//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_EAX);
10791//--
10792//-- uInstr0(cb, CALLM_E, 0);
10793//-- DIP("cpuid\n");
10794//-- break;
10795//--
sewardj9334b0f2004-07-10 22:43:54 +000010796 /* =-=-=-=-=-=-=-=-=- MOVZX, MOVSX =-=-=-=-=-=-=-= */
10797
10798 case 0xB6: /* MOVZXb Eb,Gv */
10799 delta = dis_movx_E_G ( sorb, delta, 1, 4, False );
10800 break;
sewardj940e8c92004-07-11 16:53:24 +000010801 case 0xB7: /* MOVZXw Ew,Gv */
10802 delta = dis_movx_E_G ( sorb, delta, 2, 4, False );
10803 break;
10804
sewardj0611d802004-07-11 02:37:54 +000010805 case 0xBE: /* MOVSXb Eb,Gv */
10806 delta = dis_movx_E_G ( sorb, delta, 1, 4, True );
10807 break;
sewardj7ed22952004-07-29 00:09:58 +000010808 case 0xBF: /* MOVSXw Ew,Gv */
10809 delta = dis_movx_E_G ( sorb, delta, 2, 4, True );
10810 break;
10811
sewardjc9a65702004-07-07 16:32:57 +000010812//-- /* =-=-=-=-=-=-=-=-=-=-= MOVNTI -=-=-=-=-=-=-=-=-= */
10813//--
10814//-- case 0xC3: /* MOVNTI Gv,Ev */
10815//-- vg_assert(sz == 4);
10816//-- modrm = getUChar(eip);
10817//-- vg_assert(!epartIsReg(modrm));
10818//-- t1 = newTemp(cb);
10819//-- uInstr2(cb, GET, 4, ArchReg, gregOfRM(modrm), TempReg, t1);
10820//-- pair = disAMode ( cb, sorb, eip, dis_buf );
10821//-- t2 = LOW24(pair);
10822//-- eip += HI8(pair);
10823//-- uInstr2(cb, STORE, 4, TempReg, t1, TempReg, t2);
10824//-- DIP("movnti %s,%s\n", nameIReg(4,gregOfRM(modrm)), dis_buf);
10825//-- break;
sewardjcf780b42004-07-13 18:42:17 +000010826
10827 /* =-=-=-=-=-=-=-=-=- MUL/IMUL =-=-=-=-=-=-=-=-=-= */
10828
10829 case 0xAF: /* IMUL Ev, Gv */
sewardj2a2ba8b2004-11-08 13:14:06 +000010830 delta = dis_mul_E_G ( sorb, sz, delta );
sewardjcf780b42004-07-13 18:42:17 +000010831 break;
sewardje87b4842004-07-10 12:23:30 +000010832
10833 /* =-=-=-=-=-=-=-=-=- Jcond d32 -=-=-=-=-=-=-=-=-= */
10834 case 0x80:
10835 case 0x81:
10836 case 0x82: /* JBb/JNAEb (jump below) */
10837 case 0x83: /* JNBb/JAEb (jump not below) */
10838 case 0x84: /* JZb/JEb (jump zero) */
10839 case 0x85: /* JNZb/JNEb (jump not zero) */
10840 case 0x86: /* JBEb/JNAb (jump below or equal) */
10841 case 0x87: /* JNBEb/JAb (jump not below or equal) */
10842 case 0x88: /* JSb (jump negative) */
10843 case 0x89: /* JSb (jump not negative) */
10844 case 0x8A: /* JP (jump parity even) */
10845 case 0x8B: /* JNP/JPO (jump parity odd) */
10846 case 0x8C: /* JLb/JNGEb (jump less) */
10847 case 0x8D: /* JGEb/JNLb (jump greater or equal) */
10848 case 0x8E: /* JLEb/JNGb (jump less or equal) */
10849 case 0x8F: /* JGb/JNLEb (jump greater) */
sewardj4fd30f22004-10-25 00:42:16 +000010850 d32 = (((Addr32)guest_eip_bbstart)+delta+4) + getUDisp32(delta);
sewardje87b4842004-07-10 12:23:30 +000010851 delta += 4;
sewardj2a9ad022004-11-25 02:46:58 +000010852 jcc_01( (X86Condcode)(opc - 0x80),
10853 (Addr32)(guest_eip_bbstart+delta),
10854 d32 );
sewardjce70a5c2004-10-18 14:09:54 +000010855 whatNext = Dis_StopHere;
sewardj2a9ad022004-11-25 02:46:58 +000010856 DIP("j%s-32 0x%x\n", name_X86Condcode(opc - 0x80), d32);
sewardje87b4842004-07-10 12:23:30 +000010857 break;
10858
sewardj89cd0932004-09-08 18:23:25 +000010859
10860 /* =-=-=-=-=-=-=-=-=- RDTSC -=-=-=-=-=-=-=-=-=-=-= */
10861
10862 case 0x31: /* RDTSC */
10863 vex_printf("vex x86->IR: kludged rdtsc\n");
10864 putIReg(4, R_EAX, mkU32(0));
10865 putIReg(4, R_EDX, mkU32(0));
10866
sewardjc9a65702004-07-07 16:32:57 +000010867//-- t1 = newTemp(cb);
10868//-- t2 = newTemp(cb);
10869//-- t3 = newTemp(cb);
10870//-- uInstr0(cb, CALLM_S, 0);
10871//-- // Nb: even though these args aren't used by RDTSC_helper, need
10872//-- // them to be defined (for Memcheck). The TempRegs pushed must
10873//-- // also be distinct.
10874//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t1);
10875//-- uLiteral(cb, 0);
10876//-- uInstr1(cb, PUSH, 4, TempReg, t1);
10877//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
10878//-- uLiteral(cb, 0);
10879//-- uInstr1(cb, PUSH, 4, TempReg, t2);
10880//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_RDTSC));
10881//-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
10882//-- uInstr1(cb, POP, 4, TempReg, t3);
10883//-- uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_EDX);
10884//-- uInstr1(cb, POP, 4, TempReg, t3);
10885//-- uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_EAX);
10886//-- uInstr0(cb, CALLM_E, 0);
sewardj89cd0932004-09-08 18:23:25 +000010887 DIP("rdtsc\n");
10888 break;
sewardj77b86be2004-07-11 13:28:24 +000010889
10890 /* =-=-=-=-=-=-=-=-=- SETcc Eb =-=-=-=-=-=-=-=-=-= */
10891 case 0x90:
10892 case 0x91:
10893 case 0x92: /* set-Bb/set-NAEb (jump below) */
10894 case 0x93: /* set-NBb/set-AEb (jump not below) */
10895 case 0x94: /* set-Zb/set-Eb (jump zero) */
10896 case 0x95: /* set-NZb/set-NEb (jump not zero) */
10897 case 0x96: /* set-BEb/set-NAb (jump below or equal) */
10898 case 0x97: /* set-NBEb/set-Ab (jump not below or equal) */
10899 case 0x98: /* set-Sb (jump negative) */
10900 case 0x99: /* set-Sb (jump not negative) */
10901 case 0x9A: /* set-P (jump parity even) */
10902 case 0x9B: /* set-NP (jump parity odd) */
10903 case 0x9C: /* set-Lb/set-NGEb (jump less) */
10904 case 0x9D: /* set-GEb/set-NLb (jump greater or equal) */
10905 case 0x9E: /* set-LEb/set-NGb (jump less or equal) */
10906 case 0x9F: /* set-Gb/set-NLEb (jump greater) */
sewardj5bd4d162004-11-10 13:02:48 +000010907 t1 = newTemp(Ity_I8);
sewardj2a9ad022004-11-25 02:46:58 +000010908 assign( t1, unop(Iop_1Uto8,mk_x86g_calculate_condition(opc-0x90)) );
sewardj77b86be2004-07-11 13:28:24 +000010909 modrm = getIByte(delta);
10910 if (epartIsReg(modrm)) {
10911 delta++;
sewardj5bd4d162004-11-10 13:02:48 +000010912 putIReg(1, eregOfRM(modrm), mkexpr(t1));
sewardj2a9ad022004-11-25 02:46:58 +000010913 DIP("set%s %s\n", name_X86Condcode(opc-0x90),
sewardj77b86be2004-07-11 13:28:24 +000010914 nameIReg(1,eregOfRM(modrm)));
10915 } else {
sewardj750f4072004-07-26 22:39:11 +000010916 addr = disAMode ( &alen, sorb, delta, dis_buf );
10917 delta += alen;
10918 storeLE( mkexpr(addr), mkexpr(t1) );
sewardj2a9ad022004-11-25 02:46:58 +000010919 DIP("set%s %s\n", name_X86Condcode(opc-0x90), dis_buf);
sewardj77b86be2004-07-11 13:28:24 +000010920 }
10921 break;
10922
sewardj180e8b32004-07-29 01:40:11 +000010923 /* =-=-=-=-=-=-=-=-=- SHLD/SHRD -=-=-=-=-=-=-=-=-= */
10924
10925 case 0xA4: /* SHLDv imm8,Gv,Ev */
10926 modrm = getIByte(delta);
10927 d32 = delta + lengthAMode(delta);
10928 vex_sprintf(dis_buf, "$%d", delta);
10929 delta = dis_SHLRD_Gv_Ev (
10930 sorb, delta, modrm, sz,
10931 mkU8(getIByte(d32)), True, /* literal */
10932 dis_buf, True );
10933 break;
sewardja06e5562004-07-14 13:18:05 +000010934 case 0xA5: /* SHLDv %cl,Gv,Ev */
10935 modrm = getIByte(delta);
10936 delta = dis_SHLRD_Gv_Ev (
10937 sorb, delta, modrm, sz,
10938 getIReg(1,R_ECX), False, /* not literal */
10939 "%cl", True );
10940 break;
10941
sewardj68511542004-07-28 00:15:44 +000010942 case 0xAC: /* SHRDv imm8,Gv,Ev */
10943 modrm = getIByte(delta);
10944 d32 = delta + lengthAMode(delta);
10945 vex_sprintf(dis_buf, "$%d", delta);
10946 delta = dis_SHLRD_Gv_Ev (
10947 sorb, delta, modrm, sz,
10948 mkU8(getIByte(d32)), True, /* literal */
10949 dis_buf, False );
10950 break;
sewardja511afc2004-07-29 22:26:03 +000010951 case 0xAD: /* SHRDv %cl,Gv,Ev */
10952 modrm = getIByte(delta);
10953 delta = dis_SHLRD_Gv_Ev (
10954 sorb, delta, modrm, sz,
10955 getIReg(1,R_ECX), False, /* not literal */
10956 "%cl", False );
10957 break;
10958
sewardj464efa42004-11-19 22:17:29 +000010959 /* =-=-=-=-=-=-=-=-=- XADD -=-=-=-=-=-=-=-=-=-= */
10960
sewardjc9a65702004-07-07 16:32:57 +000010961//-- case 0xC0: /* XADD Gb,Eb */
10962//-- eip = dis_xadd_G_E ( cb, sorb, 1, eip );
10963//-- break;
sewardj883b00b2004-09-11 09:30:24 +000010964 case 0xC1: /* XADD Gv,Ev */
10965 delta = dis_xadd_G_E ( sorb, sz, delta );
10966 break;
10967
sewardjc9a65702004-07-07 16:32:57 +000010968//-- /* =-=-=-=-=-=-=-=-=- MMXery =-=-=-=-=-=-=-=-=-=-= */
10969//--
10970//-- case 0x0D: /* PREFETCH / PREFETCHW - 3Dnow!ery*/
10971//-- case 0x18: /* PREFETCHT0/PREFETCHT1/PREFETCHT2/PREFETCHNTA */
10972//--
10973//-- vg_assert(sz == 4);
10974//-- modrm = getUChar(eip);
10975//-- if (epartIsReg(modrm)) {
10976//-- goto decode_failure;
10977//-- }
10978//-- if (gregOfRM(modrm) > 3) {
10979//-- goto decode_failure;
10980//-- }
10981//-- eip += lengthAMode(eip);
10982//-- if (VG_(print_codegen)) {
10983//-- UChar* hintstr;
10984//-- if (opc == 0x0D) {
10985//-- switch (gregOfRM(modrm)) {
10986//-- case 0: hintstr = ""; break;
10987//-- case 1: hintstr = "w"; break;
10988//-- default: goto decode_failure;
10989//-- }
10990//-- }
10991//-- else {
10992//-- switch (gregOfRM(modrm)) {
10993//-- case 0: hintstr = "nta"; break;
10994//-- case 1: hintstr = "t0"; break;
10995//-- case 2: hintstr = "t1"; break;
10996//-- case 3: hintstr = "t2"; break;
10997//-- default: goto decode_failure;
10998//-- }
10999//-- }
11000//-- VG_(printf)("prefetch%s ...\n", hintstr);
11001//-- }
11002//-- break;
11003//--
11004//-- case 0x71: case 0x72: case 0x73: {
11005//-- /* (sz==4): PSLL/PSRA/PSRL mmxreg by imm8 */
11006//-- /* (sz==2): PSLL/PSRA/PSRL xmmreg by imm8 */
11007//-- UChar byte1, byte2, byte3, subopc, mmreg;
11008//-- vg_assert(sz == 4 || sz == 2);
11009//-- byte1 = opc; /* 0x71/72/73 */
11010//-- byte2 = getUChar(eip); eip++; /* amode / sub-opcode */
11011//-- byte3 = getUChar(eip); eip++; /* imm8 */
11012//-- mmreg = byte2 & 7;
11013//-- subopc = (byte2 >> 3) & 7;
11014//-- if (subopc == 2 || subopc == 6 || subopc == 4) {
11015//-- /* 2 == 010 == SRL, 6 == 110 == SLL, 4 == 100 == SRA */
11016//-- /* ok */
11017//-- } else
11018//-- if (sz == 2 && opc == 0x73 && (subopc == 7 || subopc == 3)) {
11019//-- /* 3 == PSRLDQ, 7 == PSLLDQ */
11020//-- /* This is allowable in SSE. Because sz==2 we fall thru to
11021//-- SSE5 below. */
11022//-- } else {
11023//-- eip -= (sz==2 ? 3 : 2);
11024//-- goto decode_failure;
11025//-- }
11026//-- if (sz == 4) {
11027//-- /* The leading 0x0F is implied for MMX*, so we don't
sewardj5bd4d162004-11-10 13:02:48 +000011028//-- include it. */
sewardjc9a65702004-07-07 16:32:57 +000011029//-- uInstr2(cb, MMX3, 0,
11030//-- Lit16, (((UShort)byte1) << 8) | ((UShort)byte2),
11031//-- Lit16, ((UShort)byte3) );
11032//-- DIP("ps%s%s $%d, %s\n",
11033//-- ( subopc == 2 ? "rl"
11034//-- : subopc == 6 ? "ll"
11035//-- : subopc == 4 ? "ra"
11036//-- : "??"),
11037//-- nameMMXGran(opc & 3), (Int)byte3, nameMMXReg(mmreg) );
sewardj5bd4d162004-11-10 13:02:48 +000011038//-- } else {
sewardjc9a65702004-07-07 16:32:57 +000011039//-- /* Whereas we have to include it for SSE. */
11040//-- uInstr3(cb, SSE5, 0,
11041//-- Lit16, (((UShort)0x66) << 8) | ((UShort)0x0F),
11042//-- Lit16, (((UShort)byte1) << 8) | ((UShort)byte2),
11043//-- Lit16, ((UShort)byte3) );
11044//-- DIP("ps%s%s $%d, %s\n",
11045//-- ( subopc == 2 ? "rl"
11046//-- : subopc == 6 ? "ll"
11047//-- : subopc == 4 ? "ra"
11048//-- : subopc == 3 ? "(PSRLDQ)"
11049//-- : subopc == 7 ? "(PSLLDQ)"
11050//-- : "??"),
11051//-- nameMMXGran(opc & 3), (Int)byte3, nameXMMReg(mmreg) );
sewardj5bd4d162004-11-10 13:02:48 +000011052//-- }
sewardjc9a65702004-07-07 16:32:57 +000011053//-- break;
11054//-- }
11055//--
sewardjc9a65702004-07-07 16:32:57 +000011056//-- case 0x7E: /* MOVD (src)mmxreg, (dst)ireg-or-mem */
11057//-- vg_assert(sz == 4);
11058//-- modrm = getUChar(eip);
11059//-- if (epartIsReg(modrm)) {
11060//-- eip++;
11061//-- t1 = newTemp(cb);
11062//-- uInstr2(cb, MMX2_ERegWr, 4,
11063//-- Lit16,
11064//-- (((UShort)(opc)) << 8) | ((UShort)modrm),
11065//-- TempReg, t1 );
11066//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, eregOfRM(modrm));
11067//-- DIP("movd %s, %s\n",
11068//-- nameMMXReg(gregOfRM(modrm)), nameIReg(4,eregOfRM(modrm)));
11069//-- } else {
11070//-- Int tmpa;
11071//-- pair = disAMode ( cb, sorb, eip, dis_buf );
11072//-- tmpa = LOW24(pair);
11073//-- eip += HI8(pair);
11074//-- uInstr2(cb, MMX2_MemWr, 4,
11075//-- Lit16,
11076//-- (((UShort)(opc)) << 8) | ((UShort)modrm),
11077//-- TempReg, tmpa);
11078//-- DIP("movd %s, %s\n", nameMMXReg(gregOfRM(modrm)), dis_buf);
11079//-- }
11080//-- break;
11081//--
11082//-- case 0x6E: /* MOVD (src)ireg-or-mem, (dst)mmxreg */
11083//-- vg_assert(sz == 4);
11084//-- modrm = getUChar(eip);
11085//-- if (epartIsReg(modrm)) {
11086//-- eip++;
11087//-- t1 = newTemp(cb);
11088//-- uInstr2(cb, GET, 4, ArchReg, eregOfRM(modrm), TempReg, t1);
11089//-- uInstr2(cb, MMX2_ERegRd, 4,
11090//-- Lit16,
11091//-- (((UShort)(opc)) << 8) | ((UShort)modrm),
11092//-- TempReg, t1 );
11093//-- DIP("movd %s, %s\n",
11094//-- nameIReg(4,eregOfRM(modrm)), nameMMXReg(gregOfRM(modrm)));
11095//-- } else {
11096//-- Int tmpa;
11097//-- pair = disAMode ( cb, sorb, eip, dis_buf );
11098//-- tmpa = LOW24(pair);
11099//-- eip += HI8(pair);
11100//-- uInstr2(cb, MMX2_MemRd, 4,
11101//-- Lit16,
11102//-- (((UShort)(opc)) << 8) | ((UShort)modrm),
11103//-- TempReg, tmpa);
11104//-- DIP("movd %s, %s\n", dis_buf, nameMMXReg(gregOfRM(modrm)));
11105//-- }
11106//-- break;
11107//--
sewardj464efa42004-11-19 22:17:29 +000011108
sewardj2b7a9202004-11-26 19:15:38 +000011109 case 0x71:
11110 case 0x72:
11111 case 0x73: /* (sz==4): PSLLgg/PSRAgg/PSRLgg mmxreg by imm8 */
11112 /* If sz==2 this is SSE, and we assume sse idec has
11113 already spotted those cases by now. */
11114 vassert(sz == 4);
11115
11116 case 0x6E: /* MOVD (src)ireg-or-mem, (dst)mmxreg */
11117 case 0x7E: /* MOVD (src)mmxreg, (dst)ireg-or-mem */
sewardj464efa42004-11-19 22:17:29 +000011118 case 0x7F: /* MOVQ (src)mmxreg, (dst)mmxreg-or-mem */
sewardj2b7a9202004-11-26 19:15:38 +000011119 case 0x6F: /* MOVQ (src)mmxreg-or-mem, (dst)mmxreg */
sewardj464efa42004-11-19 22:17:29 +000011120
11121 case 0xFC:
11122 case 0xFD:
11123 case 0xFE: /* PADDgg (src)mmxreg-or-mem, (dst)mmxreg */
11124
11125 case 0xEC:
11126 case 0xED: /* PADDSgg (src)mmxreg-or-mem, (dst)mmxreg */
11127
11128 case 0xDC:
11129 case 0xDD: /* PADDUSgg (src)mmxreg-or-mem, (dst)mmxreg */
11130
11131 case 0xF8:
11132 case 0xF9:
11133 case 0xFA: /* PSUBgg (src)mmxreg-or-mem, (dst)mmxreg */
11134
11135 case 0xE8:
11136 case 0xE9: /* PSUBSgg (src)mmxreg-or-mem, (dst)mmxreg */
11137
11138 case 0xD8:
11139 case 0xD9: /* PSUBUSgg (src)mmxreg-or-mem, (dst)mmxreg */
11140
11141 case 0xE5: /* PMULHW (src)mmxreg-or-mem, (dst)mmxreg */
11142 case 0xD5: /* PMULLW (src)mmxreg-or-mem, (dst)mmxreg */
11143
sewardj4340dac2004-11-20 13:17:04 +000011144 case 0xF5: /* PMADDWD (src)mmxreg-or-mem, (dst)mmxreg */
11145
11146 case 0x74:
11147 case 0x75:
11148 case 0x76: /* PCMPEQgg (src)mmxreg-or-mem, (dst)mmxreg */
11149
11150 case 0x64:
11151 case 0x65:
11152 case 0x66: /* PCMPGTgg (src)mmxreg-or-mem, (dst)mmxreg */
11153
sewardj63ba4092004-11-21 12:30:18 +000011154 case 0x6B: /* PACKSSDW (src)mmxreg-or-mem, (dst)mmxreg */
11155 case 0x63: /* PACKSSWB (src)mmxreg-or-mem, (dst)mmxreg */
11156 case 0x67: /* PACKUSWB (src)mmxreg-or-mem, (dst)mmxreg */
11157
11158 case 0x68:
11159 case 0x69:
11160 case 0x6A: /* PUNPCKHgg (src)mmxreg-or-mem, (dst)mmxreg */
11161
11162 case 0x60:
11163 case 0x61:
11164 case 0x62: /* PUNPCKLgg (src)mmxreg-or-mem, (dst)mmxreg */
11165
11166 case 0xDB: /* PAND (src)mmxreg-or-mem, (dst)mmxreg */
11167 case 0xDF: /* PANDN (src)mmxreg-or-mem, (dst)mmxreg */
11168 case 0xEB: /* POR (src)mmxreg-or-mem, (dst)mmxreg */
11169 case 0xEF: /* PXOR (src)mmxreg-or-mem, (dst)mmxreg */
11170
sewardj8d14a592004-11-21 17:04:50 +000011171 case 0xF1:
11172 case 0xF2:
11173 case 0xF3: /* PSLLgg (src)mmxreg-or-mem, (dst)mmxreg */
11174
11175 case 0xD1:
11176 case 0xD2:
11177 case 0xD3: /* PSRLgg (src)mmxreg-or-mem, (dst)mmxreg */
11178
11179 case 0xE1:
11180 case 0xE2: /* PSRAgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj464efa42004-11-19 22:17:29 +000011181 {
11182 UInt delta0 = delta-1;
11183 Bool decode_OK = False;
11184 delta = dis_MMX ( &decode_OK, sorb, sz, delta-1 );
11185 if (!decode_OK) {
11186 delta = delta0;
11187 goto decode_failure;
11188 }
11189 break;
11190 }
11191
sewardj8d14a592004-11-21 17:04:50 +000011192 case 0x77: /* EMMS */
11193 vassert(sz == 4);
sewardj4cb918d2004-12-03 19:43:31 +000011194 do_EMMS_preamble();
sewardj8d14a592004-11-21 17:04:50 +000011195 DIP("emms\n");
11196 break;
11197
sewardjc9a65702004-07-07 16:32:57 +000011198//-- case 0x7F: /* MOVQ (src)mmxreg, (dst)mmxreg-or-mem */
11199//-- case 0xE7: /* MOVNTQ (src)mmxreg, (dst)mmxreg-or-mem */
11200//-- vg_assert(sz == 4);
11201//-- modrm = getUChar(eip);
11202//-- if (epartIsReg(modrm)) {
11203//-- eip++;
11204//-- uInstr1(cb, MMX2, 0,
11205//-- Lit16,
11206//-- (((UShort)(opc)) << 8) | ((UShort)modrm) );
11207//-- DIP("movq %s, %s\n",
11208//-- nameMMXReg(gregOfRM(modrm)), nameMMXReg(eregOfRM(modrm)));
11209//-- } else {
11210//-- Int tmpa;
11211//-- pair = disAMode ( cb, sorb, eip, dis_buf );
11212//-- tmpa = LOW24(pair);
11213//-- eip += HI8(pair);
11214//-- uInstr2(cb, MMX2_MemWr, 8,
11215//-- Lit16,
11216//-- (((UShort)(opc)) << 8) | ((UShort)modrm),
11217//-- TempReg, tmpa);
11218//-- DIP("mov(nt)q %s, %s\n",
11219//-- nameMMXReg(gregOfRM(modrm)), dis_buf);
11220//-- }
11221//-- break;
11222//--
11223//-- case 0xFC: case 0xFD: case 0xFE:
11224//-- /* PADDgg (src)mmxreg-or-mem, (dst)mmxreg */
11225//-- vg_assert(sz == 4);
11226//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "padd", True );
11227//-- break;
11228//--
11229//-- case 0xD4:
11230//-- /* PADDQ (src)mmxreg-or-mem, (dst)mmxreg */
11231//-- vg_assert(sz == 4);
11232//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "paddq", False );
11233//-- break;
11234//--
11235//-- case 0xEC: case 0xED:
11236//-- /* PADDSgg (src)mmxreg-or-mem, (dst)mmxreg */
11237//-- vg_assert(sz == 4);
11238//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "padds", True );
11239//-- break;
11240//--
11241//-- case 0xDC: case 0xDD:
11242//-- /* PADDUSgg (src)mmxreg-or-mem, (dst)mmxreg */
11243//-- vg_assert(sz == 4);
11244//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "paddus", True );
11245//-- break;
11246//--
11247//-- case 0xF8: case 0xF9: case 0xFA: case 0xFB:
11248//-- /* PSUBgg (src)mmxreg-or-mem, (dst)mmxreg */
11249//-- vg_assert(sz == 4);
11250//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "psub", True );
11251//-- break;
11252//--
11253//-- case 0xE8: case 0xE9:
11254//-- /* PSUBSgg (src)mmxreg-or-mem, (dst)mmxreg */
11255//-- vg_assert(sz == 4);
11256//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "psubs", True );
11257//-- break;
11258//--
11259//-- case 0xD8: case 0xD9:
11260//-- /* PSUBUSgg (src)mmxreg-or-mem, (dst)mmxreg */
11261//-- vg_assert(sz == 4);
11262//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "psubus", True );
11263//-- break;
11264//--
11265//-- case 0xE4: /* PMULHUW (src)mmxreg-or-mem, (dst)mmxreg */
11266//-- vg_assert(sz == 4);
11267//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pmulhuw", False );
11268//-- break;
11269//--
11270//-- case 0xE5: /* PMULHW (src)mmxreg-or-mem, (dst)mmxreg */
11271//-- vg_assert(sz == 4);
11272//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pmulhw", False );
11273//-- break;
11274//--
11275//-- case 0xD5: /* PMULLW (src)mmxreg-or-mem, (dst)mmxreg */
11276//-- vg_assert(sz == 4);
11277//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pmullw", False );
11278//-- break;
11279//--
11280//-- case 0xF4: /* PMULUDQ (src)mmxreg-or-mem, (dst)mmxreg */
11281//-- vg_assert(sz == 4);
11282//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pmuludq", False );
11283//-- break;
11284//--
11285//-- case 0xF5: /* PMADDWD (src)mmxreg-or-mem, (dst)mmxreg */
11286//-- vg_assert(sz == 4);
11287//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pmaddwd", False );
11288//-- break;
11289//--
11290//-- case 0x74: case 0x75: case 0x76:
11291//-- /* PCMPEQgg (src)mmxreg-or-mem, (dst)mmxreg */
11292//-- vg_assert(sz == 4);
11293//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pcmpeq", True );
11294//-- break;
11295//--
11296//-- case 0x64: case 0x65: case 0x66:
11297//-- /* PCMPGTgg (src)mmxreg-or-mem, (dst)mmxreg */
11298//-- vg_assert(sz == 4);
11299//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pcmpgt", True );
11300//-- break;
11301//--
11302//-- case 0x6B: /* PACKSSDW (src)mmxreg-or-mem, (dst)mmxreg */
11303//-- vg_assert(sz == 4);
11304//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "packssdw", False );
11305//-- break;
11306//--
11307//-- case 0x63: /* PACKSSWB (src)mmxreg-or-mem, (dst)mmxreg */
11308//-- vg_assert(sz == 4);
11309//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "packsswb", False );
11310//-- break;
11311//--
11312//-- case 0x67: /* PACKUSWB (src)mmxreg-or-mem, (dst)mmxreg */
11313//-- vg_assert(sz == 4);
11314//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "packuswb", False );
11315//-- break;
11316//--
11317//-- case 0x68: case 0x69: case 0x6A:
11318//-- /* PUNPCKHgg (src)mmxreg-or-mem, (dst)mmxreg */
11319//-- vg_assert(sz == 4);
11320//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "punpckh", True );
11321//-- break;
11322//--
11323//-- case 0x60: case 0x61: case 0x62:
11324//-- /* PUNPCKLgg (src)mmxreg-or-mem, (dst)mmxreg */
11325//-- vg_assert(sz == 4);
11326//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "punpckl", True );
11327//-- break;
11328//--
11329//-- case 0xDB: /* PAND (src)mmxreg-or-mem, (dst)mmxreg */
11330//-- vg_assert(sz == 4);
11331//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pand", False );
11332//-- break;
11333//--
11334//-- case 0xDF: /* PANDN (src)mmxreg-or-mem, (dst)mmxreg */
11335//-- vg_assert(sz == 4);
11336//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pandn", False );
11337//-- break;
11338//--
11339//-- case 0xEB: /* POR (src)mmxreg-or-mem, (dst)mmxreg */
11340//-- vg_assert(sz == 4);
11341//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "por", False );
11342//-- break;
11343//--
11344//-- case 0xEF: /* PXOR (src)mmxreg-or-mem, (dst)mmxreg */
11345//-- vg_assert(sz == 4);
11346//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pxor", False );
11347//-- break;
11348//--
11349//-- case 0xF1: case 0xF2: case 0xF3:
11350//-- /* PSLLgg (src)mmxreg-or-mem, (dst)mmxreg */
11351//-- vg_assert(sz == 4);
11352//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "psll", True );
11353//-- break;
11354//--
11355//-- case 0xD1: case 0xD2: case 0xD3:
11356//-- /* PSRLgg (src)mmxreg-or-mem, (dst)mmxreg */
11357//-- vg_assert(sz == 4);
11358//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "psrl", True );
11359//-- break;
11360//--
11361//-- case 0xE1: case 0xE2:
11362//-- /* PSRAgg (src)mmxreg-or-mem, (dst)mmxreg */
11363//-- vg_assert(sz == 4);
11364//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "psra", True );
11365//-- break;
11366//--
11367//-- case 0xDA:
11368//-- /* PMINUB (src)mmxreg-or-mem, (dst)mmxreg */
11369//-- vg_assert(sz == 4);
11370//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pminub", False );
11371//-- break;
11372//--
11373//-- case 0xDE:
11374//-- /* PMAXUB (src)mmxreg-or-mem, (dst)mmxreg */
11375//-- vg_assert(sz == 4);
11376//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pmaxub", False );
11377//-- break;
11378//--
11379//-- case 0xEA:
11380//-- /* PMINSW (src)mmxreg-or-mem, (dst)mmxreg */
11381//-- vg_assert(sz == 4);
11382//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pminsw", False );
11383//-- break;
11384//--
11385//-- case 0xEE:
11386//-- /* PMAXSW (src)mmxreg-or-mem, (dst)mmxreg */
11387//-- vg_assert(sz == 4);
11388//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pmaxsw", False );
11389//-- break;
11390//--
11391//-- case 0xE0:
11392//-- /* PAVGB (src)mmxreg-or-mem, (dst)mmxreg */
11393//-- vg_assert(sz == 4);
11394//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pavgb", False );
11395//-- break;
11396//--
11397//-- case 0xE3:
11398//-- /* PAVGW (src)mmxreg-or-mem, (dst)mmxreg */
11399//-- vg_assert(sz == 4);
11400//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pavgw", False );
11401//-- break;
11402//--
11403//-- case 0xF6:
11404//-- /* PSADBW (src)mmxreg-or-mem, (dst)mmxreg */
11405//-- vg_assert(sz == 4);
11406//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "psadbw", False );
11407//-- break;
11408//--
11409//-- case 0x70:
11410//-- /* PSHUFW imm8, (src)mmxreg-or-mem, (dst)mmxreg */
11411//-- vg_assert(sz == 4);
11412//-- eip = dis_MMXop_regmem_to_reg_Imm8 ( cb, sorb, eip, opc, "pshufw", False );
11413//-- break;
11414//--
11415//-- case 0xD7:
11416//-- /* PMOVMSKB (src)mmxreg, (dst)ireg */
11417//-- vg_assert(sz == 4);
11418//-- modrm = getUChar(eip);
11419//-- vg_assert(epartIsReg(modrm));
11420//-- t1 = newTemp(cb);
11421//-- uInstr3(cb, SSE2g_RegWr, 4,
11422//-- Lit16, (((UShort)(0x0F)) << 8) | (UShort)(opc),
11423//-- Lit16, (UShort)modrm,
11424//-- TempReg, t1 );
11425//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, gregOfRM(modrm));
11426//-- DIP("pmovmskb %s, %s\n",
11427//-- nameMMXReg(eregOfRM(modrm)), nameIReg(4,gregOfRM(modrm)));
11428//-- eip++;
11429//-- break;
11430//--
11431//-- case 0xC5:
11432//-- /* PEXTRW (src)mmxreg, (dst)ireg */
11433//-- vg_assert(sz == 4);
11434//-- t1 = newTemp(cb);
11435//-- modrm = getUChar(eip); eip++;
11436//-- abyte = getUChar(eip); eip++;
11437//-- vg_assert(epartIsReg(modrm));
11438//-- uInstr3(cb, SSE2g1_RegWr, 4,
11439//-- Lit16, (((UShort)(0x0F)) << 8) | (UShort)(opc),
11440//-- Lit16, (UShort)modrm,
11441//-- TempReg, t1 );
11442//-- uLiteral(cb, abyte);
11443//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, gregOfRM(modrm));
11444//-- DIP("pextrw %s, %d, %s\n",
11445//-- nameMMXReg(eregOfRM(modrm)), (Int)abyte,
11446//-- nameIReg(4, gregOfRM(modrm)));
11447//-- break;
11448//--
11449//-- case 0xC4:
11450//-- /* PINSRW (src)ireg, (dst)mmxreg */
11451//-- vg_assert(sz == 4);
11452//-- t1 = newTemp(cb);
11453//-- modrm = getUChar(eip); eip++;
11454//-- abyte = getUChar(eip); eip++;
11455//-- vg_assert(epartIsReg(modrm));
11456//-- uInstr2(cb, GET, 2, ArchReg, eregOfRM(modrm), TempReg, t1);
11457//-- uInstr3(cb, SSE2e1_RegRd, 2,
11458//-- Lit16, (((UShort)(0x0F)) << 8) | (UShort)(opc),
11459//-- Lit16, (UShort)modrm,
11460//-- TempReg, t1 );
11461//-- uLiteral(cb, abyte);
11462//-- DIP("pinsrw %s, %d, %s\n", nameIReg(2, eregOfRM(modrm)),
11463//-- (Int)abyte, nameMMXReg(gregOfRM(modrm)));
11464//-- break;
11465//--
11466//-- case 0xA1: /* POP %FS */
11467//-- dis_pop_segreg( cb, R_FS, sz ); break;
11468//-- case 0xA9: /* POP %GS */
11469//-- dis_pop_segreg( cb, R_GS, sz ); break;
11470//--
11471//-- case 0xA0: /* PUSH %FS */
11472//-- dis_push_segreg( cb, R_FS, sz ); break;
11473//-- case 0xA8: /* PUSH %GS */
11474//-- dis_push_segreg( cb, R_GS, sz ); break;
sewardje87b4842004-07-10 12:23:30 +000011475
11476 /* =-=-=-=-=-=-=-=-=- unimp2 =-=-=-=-=-=-=-=-=-=-= */
11477
11478 default:
11479 goto decode_failure;
11480 } /* switch (opc) for the 2-byte opcodes */
11481 goto decode_success;
11482 } /* case 0x0F: of primary opcode */
sewardjc9a65702004-07-07 16:32:57 +000011483
11484 /* ------------------------ ??? ------------------------ */
11485
11486 default:
sewardje87b4842004-07-10 12:23:30 +000011487 decode_failure:
sewardjc9a65702004-07-07 16:32:57 +000011488 /* All decode failures end up here. */
11489 vex_printf("disInstr(x86): unhandled instruction bytes: "
11490 "0x%x 0x%x 0x%x 0x%x\n",
11491 (Int)getIByte(delta_start+0),
11492 (Int)getIByte(delta_start+1),
11493 (Int)getIByte(delta_start+2),
11494 (Int)getIByte(delta_start+3) );
11495 vpanic("x86toIR: unimplemented insn");
11496 /* Print address of failing instruction. */
11497 //VG_(describe_eip)((Addr)eip_start, loc_buf, M_VG_ERRTXT);
11498 //VG_(printf)(" at %s\n", loc_buf);
11499
11500 //uInstr0(cb, CALLM_S, 0);
11501 //uInstr1(cb, CALLM, 0, Lit16,
11502 // VGOFF_(helper_undefined_instruction));
11503 //uInstr0(cb, CALLM_E, 0);
11504
11505 /* just because everything else insists the last instruction of
11506 a BB is a jmp */
11507 //jmp_lit(cb, eip);
sewardjce70a5c2004-10-18 14:09:54 +000011508 //whatNext = Dis_StopHere;
sewardjc9a65702004-07-07 16:32:57 +000011509 //break;
11510 //return eip;
11511
11512 } /* switch (opc) for the main (primary) opcode switch. */
11513
sewardje87b4842004-07-10 12:23:30 +000011514 decode_success:
sewardjc9a65702004-07-07 16:32:57 +000011515 /* All decode successes end up here. */
11516 DIP("\n");
sewardjc9a65702004-07-07 16:32:57 +000011517
sewardjce70a5c2004-10-18 14:09:54 +000011518 *size = delta - delta_start;
11519 return whatNext;
sewardjc9a65702004-07-07 16:32:57 +000011520}
11521
11522#undef DIP
11523#undef DIS
11524
11525/*--------------------------------------------------------------------*/
sewardjc0ee2ed2004-07-27 10:29:41 +000011526/*--- end guest-x86/toIR.c ---*/
sewardjc9a65702004-07-07 16:32:57 +000011527/*--------------------------------------------------------------------*/