blob: 679ccf5c1809454013e8da1154edf3a898ba7695 [file] [log] [blame]
sewardjd20c8852005-01-20 20:04:07 +00001
2/*--------------------------------------------------------------------*/
3/*--- ---*/
4/*--- This file (guest-amd64/toIR.c) is ---*/
5/*--- Copyright (c) 2004 OpenWorks LLP. All rights reserved. ---*/
6/*--- ---*/
7/*--------------------------------------------------------------------*/
8
9/*
10 This file is part of LibVEX, a library for dynamic binary
11 instrumentation and translation.
12
13 Copyright (C) 2004-2005 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
sewardjf8c37f72005-02-07 18:55:29 +000036/* EFLAGS after multiply-Q is wrong because there is no way to do
37 a 128-bit multiply in C (directly). */
38
sewardjd20c8852005-01-20 20:04:07 +000039//.. /* TODO:
40//.. SBB reg with itself
41//..
42//.. check flag settings for cmpxchg
43//.. FUCOMI(P): what happens to A and S flags? Currently are forced
44//.. to zero.
45//..
46//.. x87 FP Limitations:
47//..
48//.. * all arithmetic done at 64 bits
49//..
50//.. * no FP exceptions, except for handling stack over/underflow
51//..
52//.. * FP rounding mode observed only for float->int conversions
53//.. and int->float conversions which could lose accuracy, and
54//.. for float-to-float rounding. For all other operations,
55//.. round-to-nearest is used, regardless.
56//..
57//.. * FP sin/cos/tan/sincos: C2 flag is always cleared. IOW the
58//.. simulation claims the argument is in-range (-2^63 <= arg <= 2^63)
59//.. even when it isn't.
60//..
61//.. * some of the FCOM cases could do with testing -- not convinced
62//.. that the args are the right way round.
63//..
64//.. * FSAVE does not re-initialise the FPU; it should do
65//..
66//.. * FINIT not only initialises the FPU environment, it also
67//.. zeroes all the FP registers. It should leave the registers
68//.. unchanged.
69//..
70//.. RDTSC returns zero, always.
71//..
72//.. SAHF should cause eflags[1] == 1, and in fact it produces 0. As
73//.. per Intel docs this bit has no meaning anyway. Since PUSHF is the
74//.. only way to observe eflags[1], a proper fix would be to make that
75//.. bit be set by PUSHF.
76//..
77//.. This module uses global variables and so is not MT-safe (if that
78//.. should ever become relevant). */
sewardj44d494d2005-01-20 20:26:33 +000079
80/* Translates AMD64 code to IR. */
81
82#include "libvex_basictypes.h"
83#include "libvex_ir.h"
84#include "libvex.h"
85#include "libvex_guest_amd64.h"
86
87#include "main/vex_util.h"
88#include "main/vex_globals.h"
89#include "guest-amd64/gdefs.h"
90
91
sewardjecb94892005-01-21 14:26:37 +000092/*------------------------------------------------------------*/
93/*--- Globals ---*/
94/*------------------------------------------------------------*/
95
sewardj4b744762005-02-07 15:02:25 +000096/* ------ CONST for entire BB ------ */
97
sewardjecb94892005-01-21 14:26:37 +000098/* These are set at the start of the translation of a BB, so
99 that we don't have to pass them around endlessly. */
100
101/* We need to know this to do sub-register accesses correctly. */
sewardj4b744762005-02-07 15:02:25 +0000102/* CONST for entire BB */
sewardjecb94892005-01-21 14:26:37 +0000103static Bool host_is_bigendian;
104
sewardjb3a04292005-01-21 20:33:44 +0000105/* Pointer to the guest code area. */
sewardj4b744762005-02-07 15:02:25 +0000106/* CONST for entire BB */
sewardjb3a04292005-01-21 20:33:44 +0000107static UChar* guest_code;
108
sewardjdf0e0022005-01-25 15:48:43 +0000109/* The guest address corresponding to guest_code[0]. */
sewardj4b744762005-02-07 15:02:25 +0000110/* CONST for entire BB */
sewardjdf0e0022005-01-25 15:48:43 +0000111static Addr64 guest_rip_bbstart;
sewardjb3a04292005-01-21 20:33:44 +0000112
sewardj4b744762005-02-07 15:02:25 +0000113/* The IRBB* into which we're generating code. */
114/* CONST for entire BB */
115static IRBB* irbb;
116
117
118/* ------ CONST for each instruction ------ */
119
sewardjb3a04292005-01-21 20:33:44 +0000120/* The guest address for the instruction currently being
121 translated. */
122/* CONST for any specific insn, not for the entire BB */
sewardjdf0e0022005-01-25 15:48:43 +0000123static Addr64 guest_rip_curr_instr;
sewardjecb94892005-01-21 14:26:37 +0000124
sewardjb3a04292005-01-21 20:33:44 +0000125/* Emergency verboseness just for this insn? DEBUG ONLY */
126static Bool insn_verbose = False;
sewardjecb94892005-01-21 14:26:37 +0000127
128
sewardj4b744762005-02-07 15:02:25 +0000129/* For ensuring that %rip-relative addressing is done right. A read
130 of %rip generates the address of the next instruction. It may be
131 that we don't conveniently know that inside disAMode(). For sanity
132 checking, if the next insn %rip is needed, we make a guess at what
133 it is, record that guess here, and set the accompanying Bool to
134 indicate that -- after this insn's decode is finished -- that guess
135 needs to be checked. */
136
137/* At the start of each insn decode, is set to (0, False).
138 After the decode, if _mustcheck is now True, _assumed is
139 checked. */
140
141static Addr64 guest_rip_next_assumed;
142static Bool guest_rip_next_mustcheck;
143
144
sewardjecb94892005-01-21 14:26:37 +0000145/*------------------------------------------------------------*/
146/*--- Helpers for constructing IR. ---*/
147/*------------------------------------------------------------*/
148
sewardjb3a04292005-01-21 20:33:44 +0000149/* Generate a new temporary of the given type. */
150static IRTemp newTemp ( IRType ty )
151{
152 vassert(isPlausibleType(ty));
153 return newIRTemp( irbb->tyenv, ty );
154}
155
sewardjecb94892005-01-21 14:26:37 +0000156/* Add a statement to the list held by "irbb". */
157static void stmt ( IRStmt* st )
158{
159 addStmtToIRBB( irbb, st );
160}
sewardjb3a04292005-01-21 20:33:44 +0000161
162/* Generate a statement "dst := e". */
163static void assign ( IRTemp dst, IRExpr* e )
164{
165 stmt( IRStmt_Tmp(dst, e) );
166}
167
sewardjecb94892005-01-21 14:26:37 +0000168static IRExpr* unop ( IROp op, IRExpr* a )
169{
170 return IRExpr_Unop(op, a);
171}
172
sewardjb3a04292005-01-21 20:33:44 +0000173static IRExpr* binop ( IROp op, IRExpr* a1, IRExpr* a2 )
174{
175 return IRExpr_Binop(op, a1, a2);
176}
177
sewardjdf0e0022005-01-25 15:48:43 +0000178static IRExpr* mkexpr ( IRTemp tmp )
179{
180 return IRExpr_Tmp(tmp);
181}
sewardjb3a04292005-01-21 20:33:44 +0000182
sewardj3ca55a12005-01-27 16:06:23 +0000183static IRExpr* mkU8 ( ULong i )
sewardjb3a04292005-01-21 20:33:44 +0000184{
185 vassert(i < 256);
sewardj3ca55a12005-01-27 16:06:23 +0000186 return IRExpr_Const(IRConst_U8( (UChar)i ));
sewardjb3a04292005-01-21 20:33:44 +0000187}
188
sewardj5e525292005-01-28 15:13:10 +0000189static IRExpr* mkU16 ( ULong i )
190{
191 vassert(i < 0x10000ULL);
192 return IRExpr_Const(IRConst_U16( (UShort)i ));
193}
sewardj3ca55a12005-01-27 16:06:23 +0000194
195static IRExpr* mkU32 ( ULong i )
196{
197 vassert(i < 0x100000000ULL);
198 return IRExpr_Const(IRConst_U32( (UInt)i ));
199}
sewardjb3a04292005-01-21 20:33:44 +0000200
201static IRExpr* mkU64 ( ULong i )
202{
203 return IRExpr_Const(IRConst_U64(i));
204}
sewardjecb94892005-01-21 14:26:37 +0000205
sewardj3ca55a12005-01-27 16:06:23 +0000206static IRExpr* mkU ( IRType ty, ULong i )
207{
208 switch (ty) {
209 case Ity_I8: return mkU8(i);
sewardj5e525292005-01-28 15:13:10 +0000210 case Ity_I16: return mkU16(i);
sewardj3ca55a12005-01-27 16:06:23 +0000211 case Ity_I32: return mkU32(i);
212 case Ity_I64: return mkU64(i);
213 default: vpanic("mkU(amd64)");
214 }
215}
216
sewardj5e525292005-01-28 15:13:10 +0000217static void storeLE ( IRExpr* addr, IRExpr* data )
218{
219 stmt( IRStmt_STle(addr,data) );
220}
221
222static IRExpr* loadLE ( IRType ty, IRExpr* data )
223{
224 return IRExpr_LDle(ty,data);
225}
226
227static IROp mkSizedOp ( IRType ty, IROp op8 )
228{
229 vassert(op8 == Iop_Add8 || op8 == Iop_Sub8
230 || op8 == Iop_Mul8
231 || op8 == Iop_Or8 || op8 == Iop_And8 || op8 == Iop_Xor8
232 || op8 == Iop_Shl8 || op8 == Iop_Shr8 || op8 == Iop_Sar8
233 || op8 == Iop_CmpEQ8 || op8 == Iop_CmpNE8
234 || op8 == Iop_Not8 );
235 switch (ty) {
236 case Ity_I8: return 0 +op8;
237 case Ity_I16: return 1 +op8;
238 case Ity_I32: return 2 +op8;
239 case Ity_I64: return 3 +op8;
240 default: vpanic("mkSizedOp(amd64)");
241 }
242}
243
244static
245IRExpr* doScalarWidening ( Int szSmall, Int szBig, Bool signd, IRExpr* src )
246{
247 if (szSmall == 1 && szBig == 4) {
248 return unop(signd ? Iop_8Sto32 : Iop_8Uto32, src);
249 }
250 if (szSmall == 1 && szBig == 2) {
251 return unop(signd ? Iop_8Sto16 : Iop_8Uto16, src);
252 }
253 if (szSmall == 2 && szBig == 4) {
254 return unop(signd ? Iop_16Sto32 : Iop_16Uto32, src);
255 }
256 if (szSmall == 1 && szBig == 8 && !signd) {
257 return unop(Iop_32Uto64, unop(Iop_8Uto32, src));
258 }
sewardj03b07cc2005-01-31 18:09:43 +0000259 if (szSmall == 1 && szBig == 8 && signd) {
260 return unop(Iop_32Sto64, unop(Iop_8Sto32, src));
261 }
sewardj5e525292005-01-28 15:13:10 +0000262 if (szSmall == 2 && szBig == 8 && !signd) {
263 return unop(Iop_32Uto64, unop(Iop_16Uto32, src));
264 }
sewardj03b07cc2005-01-31 18:09:43 +0000265 if (szSmall == 2 && szBig == 8 && signd) {
266 return unop(Iop_32Sto64, unop(Iop_16Sto32, src));
267 }
sewardj5e525292005-01-28 15:13:10 +0000268 vpanic("doScalarWidening(amd64)");
269}
270
271
sewardjecb94892005-01-21 14:26:37 +0000272
273/*------------------------------------------------------------*/
274/*--- Debugging output ---*/
275/*------------------------------------------------------------*/
276
sewardjb3a04292005-01-21 20:33:44 +0000277/* Bomb out if we can't handle something. */
278__attribute__ ((noreturn))
279static void unimplemented ( HChar* str )
280{
281 vex_printf("amd64toIR: unimplemented feature\n");
282 vpanic(str);
283}
284
sewardjecb94892005-01-21 14:26:37 +0000285#define DIP(format, args...) \
286 if (insn_verbose || (vex_traceflags & VEX_TRACE_FE)) \
287 vex_printf(format, ## args)
288
289#define DIS(buf, format, args...) \
290 if (insn_verbose || (vex_traceflags & VEX_TRACE_FE)) \
291 vex_sprintf(buf, format, ## args)
292
293
294/*------------------------------------------------------------*/
295/*--- Offsets of various parts of the amd64 guest state. ---*/
296/*------------------------------------------------------------*/
297
298#define OFFB_RAX offsetof(VexGuestAMD64State,guest_RAX)
299#define OFFB_RBX offsetof(VexGuestAMD64State,guest_RBX)
300#define OFFB_RCX offsetof(VexGuestAMD64State,guest_RCX)
301#define OFFB_RDX offsetof(VexGuestAMD64State,guest_RDX)
302#define OFFB_RSP offsetof(VexGuestAMD64State,guest_RSP)
303#define OFFB_RBP offsetof(VexGuestAMD64State,guest_RBP)
304#define OFFB_RSI offsetof(VexGuestAMD64State,guest_RSI)
305#define OFFB_RDI offsetof(VexGuestAMD64State,guest_RDI)
306#define OFFB_R8 offsetof(VexGuestAMD64State,guest_R8)
307#define OFFB_R9 offsetof(VexGuestAMD64State,guest_R9)
308#define OFFB_R10 offsetof(VexGuestAMD64State,guest_R10)
309#define OFFB_R11 offsetof(VexGuestAMD64State,guest_R11)
310#define OFFB_R12 offsetof(VexGuestAMD64State,guest_R12)
311#define OFFB_R13 offsetof(VexGuestAMD64State,guest_R13)
312#define OFFB_R14 offsetof(VexGuestAMD64State,guest_R14)
313#define OFFB_R15 offsetof(VexGuestAMD64State,guest_R15)
314
315#define OFFB_RIP offsetof(VexGuestAMD64State,guest_RIP)
316
sewardja6b93d12005-02-17 09:28:28 +0000317#define OFFB_FS_ZERO offsetof(VexGuestAMD64State,guest_FS_ZERO)
318
sewardjecb94892005-01-21 14:26:37 +0000319#define OFFB_CC_OP offsetof(VexGuestAMD64State,guest_CC_OP)
320#define OFFB_CC_DEP1 offsetof(VexGuestAMD64State,guest_CC_DEP1)
321#define OFFB_CC_DEP2 offsetof(VexGuestAMD64State,guest_CC_DEP2)
322#define OFFB_CC_NDEP offsetof(VexGuestAMD64State,guest_CC_NDEP)
323
sewardj8d965312005-02-25 02:48:47 +0000324#define OFFB_FPREGS offsetof(VexGuestAMD64State,guest_FPREG[0])
325#define OFFB_FPTAGS offsetof(VexGuestAMD64State,guest_FPTAG[0])
sewardjd0a12df2005-02-10 02:07:43 +0000326#define OFFB_DFLAG offsetof(VexGuestAMD64State,guest_DFLAG)
sewardj85520e42005-02-19 15:22:38 +0000327#define OFFB_IDFLAG offsetof(VexGuestAMD64State,guest_IDFLAG)
sewardj8d965312005-02-25 02:48:47 +0000328#define OFFB_FTOP offsetof(VexGuestAMD64State,guest_FTOP)
sewardjd20c8852005-01-20 20:04:07 +0000329//.. #define OFFB_FC3210 offsetof(VexGuestX86State,guest_FC3210)
sewardjc49ce232005-02-25 13:03:03 +0000330#define OFFB_FPROUND offsetof(VexGuestAMD64State,guest_FPROUND)
sewardjd20c8852005-01-20 20:04:07 +0000331//..
332//.. #define OFFB_CS offsetof(VexGuestX86State,guest_CS)
333//.. #define OFFB_DS offsetof(VexGuestX86State,guest_DS)
334//.. #define OFFB_ES offsetof(VexGuestX86State,guest_ES)
335//.. #define OFFB_FS offsetof(VexGuestX86State,guest_FS)
336//.. #define OFFB_GS offsetof(VexGuestX86State,guest_GS)
337//.. #define OFFB_SS offsetof(VexGuestX86State,guest_SS)
338//.. #define OFFB_LDT offsetof(VexGuestX86State,guest_LDT)
339//.. #define OFFB_GDT offsetof(VexGuestX86State,guest_GDT)
sewardj1001dc42005-02-21 08:25:55 +0000340
341#define OFFB_SSEROUND offsetof(VexGuestAMD64State,guest_SSEROUND)
342#define OFFB_XMM0 offsetof(VexGuestAMD64State,guest_XMM0)
343#define OFFB_XMM1 offsetof(VexGuestAMD64State,guest_XMM1)
344#define OFFB_XMM2 offsetof(VexGuestAMD64State,guest_XMM2)
345#define OFFB_XMM3 offsetof(VexGuestAMD64State,guest_XMM3)
346#define OFFB_XMM4 offsetof(VexGuestAMD64State,guest_XMM4)
347#define OFFB_XMM5 offsetof(VexGuestAMD64State,guest_XMM5)
348#define OFFB_XMM6 offsetof(VexGuestAMD64State,guest_XMM6)
349#define OFFB_XMM7 offsetof(VexGuestAMD64State,guest_XMM7)
350#define OFFB_XMM8 offsetof(VexGuestAMD64State,guest_XMM8)
351#define OFFB_XMM9 offsetof(VexGuestAMD64State,guest_XMM9)
352#define OFFB_XMM10 offsetof(VexGuestAMD64State,guest_XMM10)
353#define OFFB_XMM11 offsetof(VexGuestAMD64State,guest_XMM11)
354#define OFFB_XMM12 offsetof(VexGuestAMD64State,guest_XMM12)
355#define OFFB_XMM13 offsetof(VexGuestAMD64State,guest_XMM13)
356#define OFFB_XMM14 offsetof(VexGuestAMD64State,guest_XMM14)
357#define OFFB_XMM15 offsetof(VexGuestAMD64State,guest_XMM15)
358
sewardjd20c8852005-01-20 20:04:07 +0000359//.. #define OFFB_EMWARN offsetof(VexGuestX86State,guest_EMWARN)
sewardjdf0e0022005-01-25 15:48:43 +0000360
361
362/*------------------------------------------------------------*/
363/*--- Disassemble an entire basic block ---*/
364/*------------------------------------------------------------*/
365
366/* The results of disassembling an instruction. There are three
367 possible outcomes. For Dis_Resteer, the disassembler _must_
368 continue at the specified address. For Dis_StopHere, the
369 disassembler _must_ terminate the BB. For Dis_Continue, we may at
370 our option either disassemble the next insn, or terminate the BB;
371 but in the latter case we must set the bb's ->next field to point
372 to the next instruction. */
373
374typedef
375 enum {
376 Dis_StopHere, /* this insn terminates the BB; we must stop. */
377 Dis_Continue, /* we can optionally continue into the next insn */
378 Dis_Resteer /* followed a branch; continue at the spec'd addr */
379 }
380 DisResult;
381
382
383/* forward decls .. */
sewardjd20c8852005-01-20 20:04:07 +0000384//.. static IRExpr* mkU32 ( UInt i );
385//.. static void stmt ( IRStmt* st );
386//..
387//..
sewardjdf0e0022005-01-25 15:48:43 +0000388/* disInstr disassembles an instruction located at &guest_code[delta],
389 and sets *size to its size. If the returned value is Dis_Resteer,
390 the next guest address is assigned to *whereNext. disInstr is not
391 permitted to return Dis_Resteer if either (1) resteerOK is False,
392 or (2) resteerOkFn, when applied to the address which it wishes to
393 resteer into, returns False. */
394
395static
396DisResult disInstr ( /*IN*/ Bool resteerOK,
397 /*IN*/ Bool (*resteerOkFn) ( Addr64 ),
398 /*IN*/ ULong delta,
399 /*IN*/ VexSubArch subarch,
sewardj1027dc22005-02-26 01:55:02 +0000400 /*OUT*/ Long* size,
sewardjdf0e0022005-01-25 15:48:43 +0000401 /*OUT*/ Addr64* whereNext );
sewardj44d494d2005-01-20 20:26:33 +0000402
403
404/* This is the main (only, in fact) entry point for this module. */
405
406/* Disassemble a complete basic block, starting at eip, and dumping
407 the ucode into cb. Returns the size, in bytes, of the basic
408 block. */
409IRBB* bbToIR_AMD64 ( UChar* amd64code,
410 Addr64 guest_rip_start,
411 VexGuestExtents* vge,
412 Bool (*byte_accessible)(Addr64),
413 Bool (*chase_into_ok)(Addr64),
414 Bool host_bigendian,
415 VexSubArch subarch_guest )
416{
sewardj1027dc22005-02-26 01:55:02 +0000417 Long delta, size;
418 Int i, n_instrs, first_stmt_idx;
sewardjdf0e0022005-01-25 15:48:43 +0000419 Addr64 guest_next;
420 Bool resteerOK;
421 DisResult dres;
422 static Int n_resteers = 0;
423 Int d_resteers = 0;
424
425 /* check sanity .. */
426 vassert(vex_control.guest_max_insns >= 1);
427 vassert(vex_control.guest_max_insns < 500);
428 vassert(vex_control.guest_chase_thresh >= 0);
429 vassert(vex_control.guest_chase_thresh < vex_control.guest_max_insns);
430
431 vassert(subarch_guest == VexSubArch_NONE);
432
433 /* Start a new, empty extent. */
434 vge->n_used = 1;
435 vge->base[0] = guest_rip_start;
436 vge->len[0] = 0;
437
438 /* Set up globals. */
439 host_is_bigendian = host_bigendian;
440 guest_code = amd64code;
441 guest_rip_bbstart = guest_rip_start;
442 irbb = emptyIRBB();
443 insn_verbose = False;
444
445 /* Delta keeps track of how far along the amd64code array we
446 have so far gone. */
447 delta = 0;
448 n_instrs = 0;
449
450 while (True) {
451 vassert(n_instrs < vex_control.guest_max_insns);
452
453 guest_next = 0;
454 resteerOK
sewardj7a240552005-01-28 21:37:12 +0000455 = toBool(
456 n_instrs < vex_control.guest_chase_thresh
457 /* we can't afford to have a resteer once we're on the
458 last extent slot. */
459 && vge->n_used < 3
460 );
sewardjdf0e0022005-01-25 15:48:43 +0000461
462 first_stmt_idx = irbb->stmts_used;
463
sewardjc77afb12005-02-02 02:15:10 +0000464 guest_rip_curr_instr = guest_rip_bbstart + delta;
465
sewardjdf0e0022005-01-25 15:48:43 +0000466 if (n_instrs > 0) {
467 /* for the first insn, the dispatch loop will have set
sewardjc77afb12005-02-02 02:15:10 +0000468 %RIP, but for all the others we have to do it ourselves. */
469 stmt( IRStmt_Put( OFFB_RIP, mkU64(guest_rip_curr_instr)) );
sewardjdf0e0022005-01-25 15:48:43 +0000470 }
471
sewardj4b744762005-02-07 15:02:25 +0000472 guest_rip_next_assumed = 0;
473 guest_rip_next_mustcheck = False;
sewardjdf0e0022005-01-25 15:48:43 +0000474 dres = disInstr( resteerOK, chase_into_ok,
475 delta, subarch_guest, &size, &guest_next );
476 insn_verbose = False;
477
478 /* Print the resulting IR, if needed. */
479 if (vex_traceflags & VEX_TRACE_FE) {
480 for (i = first_stmt_idx; i < irbb->stmts_used; i++) {
481 vex_printf(" ");
482 ppIRStmt(irbb->stmts[i]);
483 vex_printf("\n");
484 }
485 }
sewardj4b744762005-02-07 15:02:25 +0000486
487 /* If disInstr tried to figure out the next rip, check it got it
488 right. Failure of this assertion is serious and denotes a
489 bug in disInstr. */
490 if (guest_rip_next_mustcheck
491 && guest_rip_next_assumed != guest_rip_curr_instr+size) {
sewardje1698952005-02-08 15:02:39 +0000492 vex_printf("\n");
493 vex_printf("assumed next %%rip = 0x%llx\n",
494 guest_rip_next_assumed );
495 vex_printf(" actual next %%rip = 0x%llx\n",
496 guest_rip_curr_instr+size );
sewardj4b744762005-02-07 15:02:25 +0000497 vpanic("bbToIR_AMD64: disInstr miscalculated next %rip");
498 }
499
sewardjdf0e0022005-01-25 15:48:43 +0000500 if (dres == Dis_StopHere) {
501 vassert(irbb->next != NULL);
502 if (vex_traceflags & VEX_TRACE_FE) {
503 vex_printf(" ");
504 vex_printf( "goto {");
505 ppIRJumpKind(irbb->jumpkind);
506 vex_printf( "} ");
507 ppIRExpr( irbb->next );
508 vex_printf( "\n");
509 }
510 }
511
512 delta += size;
sewardj1027dc22005-02-26 01:55:02 +0000513 /* If vex_control.guest_max_insns is required to be < 500 and
514 each insn is at max 15 bytes long, this limit of 10000 then
515 seems reasonable since the max possible extent length will be
516 500 * 15 == 7500. */
517 vassert(vge->len[vge->n_used-1] < 10000);
518 vge->len[vge->n_used-1]
519 = toUShort(toUInt( vge->len[vge->n_used-1] + size ));
sewardjdf0e0022005-01-25 15:48:43 +0000520 n_instrs++;
521 DIP("\n");
522
523 vassert(size >= 0 && size <= 18);
524 if (!resteerOK)
525 vassert(dres != Dis_Resteer);
526 if (dres != Dis_Resteer)
527 vassert(guest_next == 0);
528
529 switch (dres) {
530 case Dis_Continue:
531 vassert(irbb->next == NULL);
532 if (n_instrs < vex_control.guest_max_insns) {
533 /* keep going */
534 } else {
535 irbb->next = mkU64(guest_rip_start+delta);
536 return irbb;
537 }
538 break;
539 case Dis_StopHere:
540 vassert(irbb->next != NULL);
541 return irbb;
542 case Dis_Resteer:
543 vassert(irbb->next == NULL);
544 /* figure out a new delta to continue at. */
545 vassert(chase_into_ok(guest_next));
sewardj1027dc22005-02-26 01:55:02 +0000546 delta = guest_next - guest_rip_start;
sewardjdf0e0022005-01-25 15:48:43 +0000547 /* we now have to start a new extent slot. */
548 vge->n_used++;
549 vassert(vge->n_used <= 3);
550 vge->base[vge->n_used-1] = guest_next;
551 vge->len[vge->n_used-1] = 0;
552 n_resteers++;
553 d_resteers++;
554 if (0 && (n_resteers & 0xFF) == 0)
sewardj8c332e22005-01-28 01:36:56 +0000555 vex_printf("resteer[%d,%d] to 0x%llx (delta = %lld)\n",
sewardjdf0e0022005-01-25 15:48:43 +0000556 n_resteers, d_resteers,
sewardj8c332e22005-01-28 01:36:56 +0000557 guest_next, delta);
sewardjdf0e0022005-01-25 15:48:43 +0000558 break;
559 }
560 }
sewardj44d494d2005-01-20 20:26:33 +0000561}
sewardjecb94892005-01-21 14:26:37 +0000562
563
564/*------------------------------------------------------------*/
565/*--- Helper bits and pieces for deconstructing the ---*/
566/*--- amd64 insn stream. ---*/
567/*------------------------------------------------------------*/
568
569/* This is the AMD64 register encoding -- integer regs. */
570#define R_RAX 0
571#define R_RCX 1
572#define R_RDX 2
573#define R_RBX 3
574#define R_RSP 4
575#define R_RBP 5
576#define R_RSI 6
577#define R_RDI 7
578#define R_R8 8
579#define R_R9 9
580#define R_R10 10
581#define R_R11 11
582#define R_R12 12
583#define R_R13 13
584#define R_R14 14
585#define R_R15 15
586
sewardjd20c8852005-01-20 20:04:07 +0000587//.. #define R_AL (0+R_EAX)
588//.. #define R_AH (4+R_EAX)
sewardjecb94892005-01-21 14:26:37 +0000589
590/* This is the Intel register encoding -- segment regs. */
591#define R_ES 0
592#define R_CS 1
593#define R_SS 2
594#define R_DS 3
595#define R_FS 4
596#define R_GS 5
597
598
sewardjb3a04292005-01-21 20:33:44 +0000599/* Various simple conversions */
600
601static ULong extend_s_8to64 ( UChar x )
602{
603 return (ULong)((((Long)x) << 56) >> 56);
604}
605
606static ULong extend_s_16to64 ( UShort x )
607{
608 return (ULong)((((Long)x) << 48) >> 48);
609}
610
611static ULong extend_s_32to64 ( UInt x )
612{
613 return (ULong)((((Long)x) << 32) >> 32);
614}
615
sewardjdf0e0022005-01-25 15:48:43 +0000616/* Figure out whether the mod and rm parts of a modRM byte refer to a
617 register or memory. If so, the byte will have the form 11XXXYYY,
618 where YYY is the register number. */
sewardj5b470602005-02-27 13:10:48 +0000619inline
sewardjdf0e0022005-01-25 15:48:43 +0000620static Bool epartIsReg ( UChar mod_reg_rm )
621{
sewardj7a240552005-01-28 21:37:12 +0000622 return toBool(0xC0 == (mod_reg_rm & 0xC0));
sewardjdf0e0022005-01-25 15:48:43 +0000623}
624
sewardj901ed122005-02-27 13:25:31 +0000625/* Extract the 'g' field from a modRM byte. This only produces 3
626 bits, which is not a complete register number. You should avoid
627 this function if at all possible. */
628inline
629static Int gregLO3ofRM ( UChar mod_reg_rm )
sewardjdf0e0022005-01-25 15:48:43 +0000630{
631 return (Int)( (mod_reg_rm >> 3) & 7 );
632}
633
634/* Get a 8/16/32-bit unsigned value out of the insn stream. */
635
sewardj8c332e22005-01-28 01:36:56 +0000636static UChar getUChar ( ULong delta )
sewardjdf0e0022005-01-25 15:48:43 +0000637{
sewardj8c332e22005-01-28 01:36:56 +0000638 UChar v = guest_code[delta+0];
639 return v;
sewardjdf0e0022005-01-25 15:48:43 +0000640}
641
sewardj9da16972005-02-21 13:58:26 +0000642//.. static UInt getUDisp16 ( ULong delta )
sewardjd20c8852005-01-20 20:04:07 +0000643//.. {
644//.. UInt v = guest_code[delta+1]; v <<= 8;
645//.. v |= guest_code[delta+0];
646//.. return v & 0xFFFF;
647//.. }
648//..
sewardj9da16972005-02-21 13:58:26 +0000649//.. static UInt getUDisp ( Int size, ULong delta )
sewardjd20c8852005-01-20 20:04:07 +0000650//.. {
651//.. switch (size) {
652//.. case 4: return getUDisp32(delta);
653//.. case 2: return getUDisp16(delta);
654//.. case 1: return getUChar(delta);
655//.. default: vpanic("getUDisp(x86)");
656//.. }
657//.. return 0; /*notreached*/
658//.. }
sewardjb3a04292005-01-21 20:33:44 +0000659
660
661/* Get a byte value out of the insn stream and sign-extend to 64
662 bits. */
sewardj1027dc22005-02-26 01:55:02 +0000663static Long getSDisp8 ( ULong delta )
sewardjb3a04292005-01-21 20:33:44 +0000664{
665 return extend_s_8to64( guest_code[delta] );
666}
667
sewardj5e525292005-01-28 15:13:10 +0000668/* Get a 16-bit value out of the insn stream and sign-extend to 64
669 bits. */
sewardj1027dc22005-02-26 01:55:02 +0000670static Long getSDisp16 ( ULong delta )
sewardj5e525292005-01-28 15:13:10 +0000671{
sewardj118b23e2005-01-29 02:14:44 +0000672 UInt v = guest_code[delta+1]; v <<= 8;
sewardj5e525292005-01-28 15:13:10 +0000673 v |= guest_code[delta+0];
sewardj118b23e2005-01-29 02:14:44 +0000674 return extend_s_16to64( (UShort)v );
sewardj5e525292005-01-28 15:13:10 +0000675}
676
sewardjb3a04292005-01-21 20:33:44 +0000677/* Get a 32-bit value out of the insn stream and sign-extend to 64
678 bits. */
sewardj1027dc22005-02-26 01:55:02 +0000679static Long getSDisp32 ( ULong delta )
sewardjb3a04292005-01-21 20:33:44 +0000680{
681 UInt v = guest_code[delta+3]; v <<= 8;
682 v |= guest_code[delta+2]; v <<= 8;
683 v |= guest_code[delta+1]; v <<= 8;
684 v |= guest_code[delta+0];
685 return extend_s_32to64( v );
686}
687
sewardj03b07cc2005-01-31 18:09:43 +0000688/* Get a 64-bit value out of the insn stream. */
sewardj1027dc22005-02-26 01:55:02 +0000689static Long getDisp64 ( ULong delta )
sewardj03b07cc2005-01-31 18:09:43 +0000690{
sewardj7eaa7cf2005-01-31 18:55:22 +0000691 ULong v = 0;
sewardj03b07cc2005-01-31 18:09:43 +0000692 v |= guest_code[delta+7]; v <<= 8;
693 v |= guest_code[delta+6]; v <<= 8;
694 v |= guest_code[delta+5]; v <<= 8;
695 v |= guest_code[delta+4]; v <<= 8;
696 v |= guest_code[delta+3]; v <<= 8;
697 v |= guest_code[delta+2]; v <<= 8;
698 v |= guest_code[delta+1]; v <<= 8;
699 v |= guest_code[delta+0];
700 return v;
701}
702
sewardj3ca55a12005-01-27 16:06:23 +0000703/* Note: because AMD64 doesn't allow 64-bit literals, it is an error
704 if this is called with size==8. Should not happen. */
sewardj1027dc22005-02-26 01:55:02 +0000705static Long getSDisp ( Int size, ULong delta )
sewardj3ca55a12005-01-27 16:06:23 +0000706{
707 switch (size) {
708 case 4: return getSDisp32(delta);
sewardj5e525292005-01-28 15:13:10 +0000709 case 2: return getSDisp16(delta);
sewardj3ca55a12005-01-27 16:06:23 +0000710 case 1: return getSDisp8(delta);
711 default: vpanic("getSDisp(amd64)");
712 }
713}
714
sewardj1389d4d2005-01-28 13:46:29 +0000715static ULong mkSizeMask ( Int sz )
sewardj3ca55a12005-01-27 16:06:23 +0000716{
717 switch (sz) {
sewardj1389d4d2005-01-28 13:46:29 +0000718 case 1: return 0x00000000000000FFULL;
719 case 2: return 0x000000000000FFFFULL;
720 case 4: return 0x00000000FFFFFFFFULL;
sewardj3ca55a12005-01-27 16:06:23 +0000721 case 8: return 0xFFFFFFFFFFFFFFFFULL;
722 default: vpanic("mkSzMask(amd64)");
723 }
724}
725
726static Int imin ( Int a, Int b )
727{
728 return (a < b) ? a : b;
729}
sewardjecb94892005-01-21 14:26:37 +0000730
sewardj5b470602005-02-27 13:10:48 +0000731static IRType szToITy ( Int n )
732{
733 switch (n) {
734 case 1: return Ity_I8;
735 case 2: return Ity_I16;
736 case 4: return Ity_I32;
737 case 8: return Ity_I64;
738 default: vpanic("szToITy(amd64)");
739 }
740}
741
sewardjecb94892005-01-21 14:26:37 +0000742
743/*------------------------------------------------------------*/
744/*--- For dealing with prefixes. ---*/
745/*------------------------------------------------------------*/
746
747/* The idea is to pass around an int holding a bitmask summarising
748 info from the prefixes seen on the current instruction, including
749 info from the REX byte. This info is used in various places, but
750 most especially when making sense of register fields in
751 instructions.
752
753 The top 16 bits of the prefix are 0x3141, just as a hacky way
754 to ensure it really is a valid prefix.
sewardjdf0e0022005-01-25 15:48:43 +0000755
756 Things you can safely assume about a well-formed prefix:
757 * at most one segment-override bit (CS,DS,ES,FS,GS,SS) is set.
sewardj5b470602005-02-27 13:10:48 +0000758 * if REX is not present then REXW,REXR,REXX,REXB will read
759 as zero.
sewardjdf0e0022005-01-25 15:48:43 +0000760 * F2 and F3 will not both be 1.
sewardjecb94892005-01-21 14:26:37 +0000761*/
762
763typedef UInt Prefix;
764
sewardj3ca55a12005-01-27 16:06:23 +0000765#define PFX_ASO (1<<0) /* address-size override present (0x67) */
766#define PFX_66 (1<<1) /* operand-size override-to-16 present (0x66) */
767#define PFX_REX (1<<2) /* REX byte present (0x40 to 0x4F) */
768#define PFX_REXW (1<<3) /* REX W bit, if REX present, else 0 */
769#define PFX_REXR (1<<4) /* REX R bit, if REX present, else 0 */
770#define PFX_REXX (1<<5) /* REX X bit, if REX present, else 0 */
771#define PFX_REXB (1<<6) /* REX B bit, if REX present, else 0 */
772#define PFX_LOCK (1<<7) /* bus LOCK prefix present (0xF0) */
773#define PFX_F2 (1<<8) /* REP/REPE/REPZ prefix present (0xF2) */
774#define PFX_F3 (1<<9) /* REPNE/REPNZ prefix present (0xF3) */
775#define PFX_CS (1<<10) /* CS segment prefix present (0x2E) */
776#define PFX_DS (1<<11) /* DS segment prefix present (0x3E) */
777#define PFX_ES (1<<12) /* ES segment prefix present (0x26) */
778#define PFX_FS (1<<13) /* FS segment prefix present (0x64) */
779#define PFX_GS (1<<14) /* GS segment prefix present (0x65) */
780#define PFX_SS (1<<15) /* SS segment prefix present (0x36) */
781
782#define PFX_EMPTY 0x31410000
sewardjecb94892005-01-21 14:26:37 +0000783
sewardjb3a04292005-01-21 20:33:44 +0000784static Bool IS_VALID_PFX ( Prefix pfx ) {
sewardj7a240552005-01-28 21:37:12 +0000785 return toBool((pfx & 0xFFFF0000) == PFX_EMPTY);
sewardjecb94892005-01-21 14:26:37 +0000786}
787
sewardjb3a04292005-01-21 20:33:44 +0000788static Bool haveREX ( Prefix pfx ) {
sewardj7a240552005-01-28 21:37:12 +0000789 return toBool(pfx & PFX_REX);
sewardjecb94892005-01-21 14:26:37 +0000790}
791
sewardj5e525292005-01-28 15:13:10 +0000792static Int getRexW ( Prefix pfx ) {
793 return (pfx & PFX_REXW) ? 1 : 0;
794}
sewardj901ed122005-02-27 13:25:31 +0000795/* Apparently unused.
sewardjdf0e0022005-01-25 15:48:43 +0000796static Int getRexR ( Prefix pfx ) {
797 return (pfx & PFX_REXR) ? 1 : 0;
798}
sewardj901ed122005-02-27 13:25:31 +0000799*/
sewardj5b470602005-02-27 13:10:48 +0000800static Int getRexX ( Prefix pfx ) {
801 return (pfx & PFX_REXX) ? 1 : 0;
802}
sewardjdf0e0022005-01-25 15:48:43 +0000803static Int getRexB ( Prefix pfx ) {
804 return (pfx & PFX_REXB) ? 1 : 0;
805}
806
sewardj3ca55a12005-01-27 16:06:23 +0000807/* Check a prefix doesn't have F2 or F3 set in it, since usually that
808 completely changes what instruction it really is. */
809static Bool haveF2orF3 ( Prefix pfx ) {
sewardj7a240552005-01-28 21:37:12 +0000810 return toBool((pfx & (PFX_F2|PFX_F3)) > 0);
sewardj3ca55a12005-01-27 16:06:23 +0000811}
sewardj55dbb262005-01-28 16:36:51 +0000812static Bool haveF2 ( Prefix pfx ) {
sewardj7a240552005-01-28 21:37:12 +0000813 return toBool((pfx & PFX_F2) > 0);
sewardj55dbb262005-01-28 16:36:51 +0000814}
815static Bool haveF3 ( Prefix pfx ) {
sewardj7a240552005-01-28 21:37:12 +0000816 return toBool((pfx & PFX_F3) > 0);
sewardj55dbb262005-01-28 16:36:51 +0000817}
sewardjecb94892005-01-21 14:26:37 +0000818
sewardj1001dc42005-02-21 08:25:55 +0000819/* Return True iff pfx has 66 set and F2 and F3 clear */
820static Bool have66noF2noF3 ( Prefix pfx )
821{
822 return
sewardj8d965312005-02-25 02:48:47 +0000823 toBool((pfx & (PFX_66|PFX_F2|PFX_F3)) == PFX_66);
sewardj1001dc42005-02-21 08:25:55 +0000824}
825
826/* Return True iff pfx has F2 set and 66 and F3 clear */
827static Bool haveF2no66noF3 ( Prefix pfx )
828{
829 return
sewardj8d965312005-02-25 02:48:47 +0000830 toBool((pfx & (PFX_66|PFX_F2|PFX_F3)) == PFX_F2);
831}
832
833/* Return True iff pfx has F3 set and 66 and F2 clear */
834static Bool haveF3no66noF2 ( Prefix pfx )
835{
836 return
837 toBool((pfx & (PFX_66|PFX_F2|PFX_F3)) == PFX_F3);
sewardj1001dc42005-02-21 08:25:55 +0000838}
839
840/* Return True iff pfx has 66, F2 and F3 clear */
841static Bool haveNo66noF2noF3 ( Prefix pfx )
842{
843 return
sewardj8d965312005-02-25 02:48:47 +0000844 toBool((pfx & (PFX_66|PFX_F2|PFX_F3)) == 0);
sewardj1001dc42005-02-21 08:25:55 +0000845}
846
sewardj1389d4d2005-01-28 13:46:29 +0000847/* Clear all the segment-override bits in a prefix. */
848static Prefix clearSegBits ( Prefix p )
849{
sewardj1001dc42005-02-21 08:25:55 +0000850 return
851 p & ~(PFX_CS | PFX_DS | PFX_ES | PFX_FS | PFX_GS | PFX_SS);
852}
853
sewardj1389d4d2005-01-28 13:46:29 +0000854
sewardjecb94892005-01-21 14:26:37 +0000855/*------------------------------------------------------------*/
sewardj5b470602005-02-27 13:10:48 +0000856/*--- For dealing with integer registers ---*/
sewardjecb94892005-01-21 14:26:37 +0000857/*------------------------------------------------------------*/
858
sewardj5b470602005-02-27 13:10:48 +0000859/* This is somewhat complex. The rules are:
860
861 For 64, 32 and 16 bit register references, the e or g fields in the
862 modrm bytes supply the low 3 bits of the register number. The
863 fourth (most-significant) bit of the register number is supplied by
864 the REX byte, if it is present; else that bit is taken to be zero.
865
866 The REX.R bit supplies the high bit corresponding to the g register
867 field, and the REX.B bit supplies the high bit corresponding to the
868 e register field (when the mod part of modrm indicates that modrm's
869 e component refers to a register and not to memory).
870
871 The REX.X bit supplies a high register bit for certain registers
872 in SIB address modes, and is generally rarely used.
873
874 For 8 bit register references, the presence of the REX byte itself
875 has significance. If there is no REX present, then the 3-bit
876 number extracted from the modrm e or g field is treated as an index
877 into the sequence %al %cl %dl %bl %ah %ch %dh %bh -- that is, the
878 old x86 encoding scheme.
879
880 But if there is a REX present, the register reference is
881 interpreted in the same way as for 64/32/16-bit references: a high
882 bit is extracted from REX, giving a 4-bit number, and the denoted
883 register is the lowest 8 bits of the 16 integer registers denoted
884 by the number. In particular, values 3 through 7 of this sequence
885 do not refer to %ah %ch %dh %bh but instead to the lowest 8 bits of
886 %rsp %rbp %rsi %rdi.
887
888 The REX.W bit has no bearing at all on register numbers. Instead
889 its presence indicates that the operand size is to be overridden
890 from its default value (32 bits) to 64 bits instead. This is in
891 the same fashion that an 0x66 prefix indicates the operand size is
892 to be overridden from 32 bits down to 16 bits. When both REX.W and
893 0x66 are present there is a conflict, and REX.W takes precedence.
894
895 Rather than try to handle this complexity using a single huge
896 function, several smaller ones are provided. The aim is to make it
897 as difficult as possible to screw up register decoding in a subtle
898 and hard-to-track-down way.
899
900 Because these routines fish around in the host's memory (that is,
901 in the guest state area) for sub-parts of guest registers, their
902 correctness depends on the host's endianness. So far these
903 routines only work for little-endian hosts. Those for which
904 endianness is important have assertions to ensure sanity.
905*/
sewardjecb94892005-01-21 14:26:37 +0000906
907
sewardj5b470602005-02-27 13:10:48 +0000908/* About the simplest question you can ask: where do the 64-bit
909 integer registers live (in the guest state) ? */
sewardjecb94892005-01-21 14:26:37 +0000910
sewardj3ca55a12005-01-27 16:06:23 +0000911static Int integerGuestReg64Offset ( UInt reg )
sewardjb3a04292005-01-21 20:33:44 +0000912{
913 switch (reg) {
914 case R_RAX: return OFFB_RAX;
915 case R_RCX: return OFFB_RCX;
916 case R_RDX: return OFFB_RDX;
917 case R_RBX: return OFFB_RBX;
918 case R_RSP: return OFFB_RSP;
919 case R_RBP: return OFFB_RBP;
920 case R_RSI: return OFFB_RSI;
921 case R_RDI: return OFFB_RDI;
922 case R_R8: return OFFB_R8;
923 case R_R9: return OFFB_R9;
924 case R_R10: return OFFB_R10;
925 case R_R11: return OFFB_R11;
926 case R_R12: return OFFB_R12;
927 case R_R13: return OFFB_R13;
928 case R_R14: return OFFB_R14;
929 case R_R15: return OFFB_R15;
930 default: vpanic("integerGuestReg64Offset(amd64)");
931 }
932}
933
934
sewardj5b470602005-02-27 13:10:48 +0000935/* Produce the name of an integer register, for printing purposes.
936 reg is a number in the range 0 .. 15 that has been generated from a
937 3-bit reg-field number and a REX extension bit. irregular denotes
938 the case where sz==1 and no REX byte is present. */
sewardjecb94892005-01-21 14:26:37 +0000939
940static
sewardj5b470602005-02-27 13:10:48 +0000941HChar* nameIReg ( Int sz, UInt reg, Bool irregular )
sewardjecb94892005-01-21 14:26:37 +0000942{
sewardjecb94892005-01-21 14:26:37 +0000943 static HChar* ireg64_names[16]
944 = { "%rax", "%rcx", "%rdx", "%rbx", "%rsp", "%rbp", "%rsi", "%rdi",
945 "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15" };
946 static HChar* ireg32_names[16]
947 = { "%eax", "%ecx", "%edx", "%ebx", "%esp", "%ebp", "%esi", "%edi",
948 "%r8d", "%r9d", "%r10d","%r11d","%r12d","%r13d","%r14d","%r15d" };
949 static HChar* ireg16_names[16]
950 = { "%ax", "%cx", "%dx", "%bx", "%sp", "%bp", "%si", "%di",
951 "%r8w", "%r9w", "%r10w","%r11w","%r12w","%r13w","%r14w","%r15w" };
952 static HChar* ireg8_names[16]
953 = { "%al", "%cl", "%dl", "%bl", "%spl", "%bpl", "%sil", "%dil",
954 "%r8b", "%r9b", "%r10b","%r11b","%r12b","%r13b","%r14b","%r15b" };
sewardj5b470602005-02-27 13:10:48 +0000955 static HChar* ireg8_irregular[8]
sewardjecb94892005-01-21 14:26:37 +0000956 = { "%al", "%cl", "%dl", "%bl", "%ah", "%ch", "%dh", "%bh" };
957
sewardj5b470602005-02-27 13:10:48 +0000958 vassert(reg < 16);
959 if (sz == 1) {
960 if (irregular)
961 vassert(reg < 8);
962 } else {
963 vassert(irregular == False);
964 }
sewardjecb94892005-01-21 14:26:37 +0000965
966 switch (sz) {
sewardj5b470602005-02-27 13:10:48 +0000967 case 8: return ireg64_names[reg];
968 case 4: return ireg32_names[reg];
969 case 2: return ireg16_names[reg];
970 case 1: if (irregular) {
971 return ireg8_irregular[reg];
972 } else {
973 return ireg8_names[reg];
974 }
975 default: vpanic("nameIReg(amd64)");
sewardjecb94892005-01-21 14:26:37 +0000976 }
sewardjecb94892005-01-21 14:26:37 +0000977}
978
sewardj5b470602005-02-27 13:10:48 +0000979/* Using the same argument conventions as nameIReg, produce the
980 guest state offset of an integer register. */
sewardjb3a04292005-01-21 20:33:44 +0000981
sewardjecb94892005-01-21 14:26:37 +0000982static
sewardj5b470602005-02-27 13:10:48 +0000983Int offsetIReg ( Int sz, UInt reg, Bool irregular )
sewardjecb94892005-01-21 14:26:37 +0000984{
sewardj5b470602005-02-27 13:10:48 +0000985 vassert(reg < 16);
986 if (sz == 1) {
987 if (irregular)
988 vassert(reg < 8);
989 } else {
990 vassert(irregular == False);
sewardjecb94892005-01-21 14:26:37 +0000991 }
sewardj5b470602005-02-27 13:10:48 +0000992
993 /* Deal with irregular case -- sz==1 and no REX present */
994 if (sz == 1 && irregular) {
995 switch (reg) {
996 case R_RSP: return 1+ OFFB_RAX;
997 case R_RBP: return 1+ OFFB_RCX;
998 case R_RSI: return 1+ OFFB_RDX;
999 case R_RDI: return 1+ OFFB_RBX;
1000 default: break; /* use the normal case */
1001 }
sewardjecb94892005-01-21 14:26:37 +00001002 }
sewardj5b470602005-02-27 13:10:48 +00001003
1004 /* Normal case */
1005 return integerGuestReg64Offset(reg);
sewardjecb94892005-01-21 14:26:37 +00001006}
1007
1008
sewardj5b470602005-02-27 13:10:48 +00001009/* Read the %CL register :: Ity_I8, for shift/rotate operations. */
1010
1011static IRExpr* getIRegCL ( void )
1012{
1013 vassert(!host_is_bigendian);
1014 return IRExpr_Get( OFFB_RCX, Ity_I8 );
1015}
1016
1017
1018/* Write to the %AH register. */
1019
1020static void putIRegAH ( IRExpr* e )
1021{
1022 vassert(!host_is_bigendian);
1023 vassert(typeOfIRExpr(irbb->tyenv, e) == Ity_I8);
1024 stmt( IRStmt_Put( OFFB_RAX+1, e ) );
1025}
1026
1027
1028/* Read/write various widths of %RAX, as it has various
1029 special-purpose uses. */
1030
1031static HChar* nameIRegRAX ( Int sz )
1032{
1033 switch (sz) {
1034 case 1: return "%al";
1035 case 2: return "%ax";
1036 case 4: return "%eax";
1037 case 8: return "%rax";
1038 default: vpanic("nameIRegRAX(amd64)");
1039 }
1040}
1041
1042static IRExpr* getIRegRAX ( Int sz )
1043{
1044 vassert(!host_is_bigendian);
1045 switch (sz) {
1046 case 1: return IRExpr_Get( OFFB_RAX, Ity_I8 );
1047 case 2: return IRExpr_Get( OFFB_RAX, Ity_I16 );
1048 case 4: return IRExpr_Get( OFFB_RAX, Ity_I32 );
1049 case 8: return IRExpr_Get( OFFB_RAX, Ity_I64 );
1050 default: vpanic("getIRegRAX(amd64)");
1051 }
1052}
1053
1054static void putIRegRAX ( Int sz, IRExpr* e )
1055{
1056 IRType ty = typeOfIRExpr(irbb->tyenv, e);
1057 vassert(!host_is_bigendian);
1058 switch (sz) {
1059 case 8: vassert(ty == Ity_I64);
1060 stmt( IRStmt_Put( OFFB_RAX, e ));
1061 break;
1062 case 4: vassert(ty == Ity_I32);
1063 stmt( IRStmt_Put( OFFB_RAX, unop(Iop_32Uto64,e) ));
1064 break;
1065 case 2: vassert(ty == Ity_I16);
1066 stmt( IRStmt_Put( OFFB_RAX, e ));
1067 break;
1068 case 1: vassert(ty == Ity_I8);
1069 stmt( IRStmt_Put( OFFB_RAX, e ));
1070 break;
1071 default: vpanic("putIRegRAX(amd64)");
1072 }
1073}
1074
1075
1076/* Read/write various widths of %RDX, as it has various
1077 special-purpose uses. */
1078
1079static IRExpr* getIRegRDX ( Int sz )
1080{
1081 vassert(!host_is_bigendian);
1082 switch (sz) {
1083 case 1: return IRExpr_Get( OFFB_RDX, Ity_I8 );
1084 case 2: return IRExpr_Get( OFFB_RDX, Ity_I16 );
1085 case 4: return IRExpr_Get( OFFB_RDX, Ity_I32 );
1086 case 8: return IRExpr_Get( OFFB_RDX, Ity_I64 );
1087 default: vpanic("getIRegRDX(amd64)");
1088 }
1089}
1090
1091static void putIRegRDX ( Int sz, IRExpr* e )
1092{
1093 vassert(!host_is_bigendian);
1094 vassert(typeOfIRExpr(irbb->tyenv, e) == szToITy(sz));
1095 switch (sz) {
1096 case 8: stmt( IRStmt_Put( OFFB_RDX, e ));
1097 break;
1098 case 4: stmt( IRStmt_Put( OFFB_RDX, unop(Iop_32Uto64,e) ));
1099 break;
1100 case 2: stmt( IRStmt_Put( OFFB_RDX, e ));
1101 break;
1102 case 1: stmt( IRStmt_Put( OFFB_RDX, e ));
1103 break;
1104 default: vpanic("putIRegRDX(amd64)");
1105 }
1106}
1107
1108
1109/* Simplistic functions to deal with the integer registers as a
1110 straightforward bank of 16 64-bit regs. */
sewardjb3a04292005-01-21 20:33:44 +00001111
1112static IRExpr* getIReg64 ( UInt regno )
1113{
1114 return IRExpr_Get( integerGuestReg64Offset(regno),
1115 Ity_I64 );
1116}
1117
sewardj2f959cc2005-01-26 01:19:35 +00001118static void putIReg64 ( UInt regno, IRExpr* e )
1119{
1120 vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_I64);
1121 stmt( IRStmt_Put( integerGuestReg64Offset(regno), e ) );
1122}
1123
sewardjb3a04292005-01-21 20:33:44 +00001124static HChar* nameIReg64 ( UInt regno )
1125{
sewardj5b470602005-02-27 13:10:48 +00001126 return nameIReg( 8, regno, False );
sewardjb3a04292005-01-21 20:33:44 +00001127}
sewardj5b470602005-02-27 13:10:48 +00001128
1129
1130/* Simplistic functions to deal with the lower halves of integer
1131 registers as a straightforward bank of 16 32-bit regs. */
1132
1133static IRExpr* getIReg32 ( UInt regno )
1134{
1135 vassert(!host_is_bigendian);
1136 return IRExpr_Get( integerGuestReg64Offset(regno),
1137 Ity_I32 );
1138}
1139
1140static void putIReg32 ( UInt regno, IRExpr* e )
1141{
1142 vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_I32);
1143 stmt( IRStmt_Put( integerGuestReg64Offset(regno),
1144 unop(Iop_32Uto64,e) ) );
1145}
1146
1147static HChar* nameIReg32 ( UInt regno )
1148{
1149 return nameIReg( 4, regno, False );
1150}
1151
1152
1153/* Sometimes what we know is a 3-bit register number, a REX byte, and
1154 which field of the REX byte is to be used to extend to a 4-bit
1155 number. These functions cater for that situation.
1156*/
1157static IRExpr* getIReg64rexX ( Prefix pfx, UInt lo3bits )
1158{
1159 vassert(lo3bits < 8);
1160 vassert(IS_VALID_PFX(pfx));
1161 return getIReg64( lo3bits | (getRexX(pfx) << 3) );
1162}
1163
1164static HChar* nameIReg64rexX ( Prefix pfx, UInt lo3bits )
1165{
1166 vassert(lo3bits < 8);
1167 vassert(IS_VALID_PFX(pfx));
1168 return nameIReg( 8, lo3bits | (getRexX(pfx) << 3), False );
1169}
1170
1171static HChar* nameIRegRexB ( Int sz, Prefix pfx, UInt lo3bits )
1172{
1173 vassert(lo3bits < 8);
1174 vassert(IS_VALID_PFX(pfx));
1175 vassert(sz == 8 || sz == 4 || sz == 2 || sz == 1);
1176 return nameIReg( sz, lo3bits | (getRexB(pfx) << 3),
1177 sz==1 && !haveREX(pfx) );
1178}
1179
1180static IRExpr* getIRegRexB ( Int sz, Prefix pfx, UInt lo3bits )
1181{
1182 vassert(lo3bits < 8);
1183 vassert(IS_VALID_PFX(pfx));
1184 vassert(sz == 8 || sz == 4 || sz == 2 || sz == 1);
1185 return IRExpr_Get(
1186 offsetIReg( sz, lo3bits | (getRexB(pfx) << 3),
1187 sz==1 && !haveREX(pfx) ),
1188 szToITy(sz)
1189 );
1190}
1191
1192static void putIRegRexB ( Int sz, Prefix pfx, UInt lo3bits, IRExpr* e )
1193{
1194 vassert(lo3bits < 8);
1195 vassert(IS_VALID_PFX(pfx));
1196 vassert(typeOfIRExpr(irbb->tyenv, e) == szToITy(sz));
1197 stmt( IRStmt_Put(
1198 offsetIReg( sz, lo3bits | (getRexB(pfx) << 3),
1199 sz==1 && !haveREX(pfx) ),
1200 sz==4 ? unop(Iop_32Uto64,e) : e
1201 ));
1202}
1203
1204
1205/* Functions for getting register numbers from modrm bytes and REX
1206 when we don't have to consider the complexities of integer subreg
1207 accesses.
1208*/
1209/* Extract the g reg field from a modRM byte, and augment it using the
1210 REX.R bit from the supplied REX byte. The R bit usually is
1211 associated with the g register field.
1212*/
1213static UInt gregOfRexRM ( Prefix pfx, UChar mod_reg_rm )
1214{
1215 Int reg = (Int)( (mod_reg_rm >> 3) & 7 );
1216 reg += (pfx & PFX_REXR) ? 8 : 0;
1217 return reg;
1218}
1219
1220/* Extract the e reg field from a modRM byte, and augment it using the
1221 REX.B bit from the supplied REX byte. The B bit usually is
1222 associated with the e register field (when modrm indicates e is a
1223 register, that is).
1224*/
1225static UInt eregOfRexRM ( Prefix pfx, UChar mod_reg_rm )
1226{
1227 Int rm;
1228 vassert(epartIsReg(mod_reg_rm));
1229 rm = (Int)(mod_reg_rm & 0x7);
1230 rm += (pfx & PFX_REXB) ? 8 : 0;
1231 return rm;
1232}
1233
1234
1235/* General functions for dealing with integer register access. */
1236
1237/* Produce the guest state offset for a reference to the 'g' register
1238 field in a modrm byte, taking into account REX (or its absence),
1239 and the size of the access.
1240*/
1241static UInt offsetIRegG ( Int sz, Prefix pfx, UChar mod_reg_rm )
1242{
1243 UInt reg;
1244 vassert(!host_is_bigendian);
1245 vassert(IS_VALID_PFX(pfx));
1246 vassert(sz == 8 || sz == 4 || sz == 2 || sz == 1);
1247 reg = gregOfRexRM( pfx, mod_reg_rm );
1248 return offsetIReg( sz, reg, sz == 1 && !haveREX(pfx) );
1249}
1250
1251static
1252IRExpr* getIRegG ( Int sz, Prefix pfx, UChar mod_reg_rm )
1253{
1254 return IRExpr_Get( offsetIRegG( sz, pfx, mod_reg_rm ),
1255 szToITy(sz) );
1256}
1257
1258static
1259void putIRegG ( Int sz, Prefix pfx, UChar mod_reg_rm, IRExpr* e )
1260{
1261 vassert(typeOfIRExpr(irbb->tyenv,e) == szToITy(sz));
1262 if (sz == 4) {
1263 e = unop(Iop_32Uto64,e);
1264 }
1265 stmt( IRStmt_Put( offsetIRegG( sz, pfx, mod_reg_rm ), e ) );
1266}
1267
1268static
1269HChar* nameIRegG ( Int sz, Prefix pfx, UChar mod_reg_rm )
1270{
1271 return nameIReg( sz, gregOfRexRM(pfx,mod_reg_rm),
1272 sz==1 && !haveREX(pfx) );
1273}
1274
1275
1276/* Produce the guest state offset for a reference to the 'e' register
1277 field in a modrm byte, taking into account REX (or its absence),
1278 and the size of the access. eregOfRexRM will assert if mod_reg_rm
1279 denotes a memory access rather than a register access.
1280*/
1281static UInt offsetIRegE ( Int sz, Prefix pfx, UChar mod_reg_rm )
1282{
1283 UInt reg;
1284 vassert(!host_is_bigendian);
1285 vassert(IS_VALID_PFX(pfx));
1286 vassert(sz == 8 || sz == 4 || sz == 2 || sz == 1);
1287 reg = eregOfRexRM( pfx, mod_reg_rm );
1288 return offsetIReg( sz, reg, sz == 1 && !haveREX(pfx) );
1289}
1290
1291static
1292IRExpr* getIRegE ( Int sz, Prefix pfx, UChar mod_reg_rm )
1293{
1294 return IRExpr_Get( offsetIRegE( sz, pfx, mod_reg_rm ),
1295 szToITy(sz) );
1296}
1297
1298static
1299void putIRegE ( Int sz, Prefix pfx, UChar mod_reg_rm, IRExpr* e )
1300{
1301 vassert(typeOfIRExpr(irbb->tyenv,e) == szToITy(sz));
1302 if (sz == 4) {
1303 e = unop(Iop_32Uto64,e);
1304 }
1305 stmt( IRStmt_Put( offsetIRegE( sz, pfx, mod_reg_rm ), e ) );
1306}
1307
1308static
1309HChar* nameIRegE ( Int sz, Prefix pfx, UChar mod_reg_rm )
1310{
1311 return nameIReg( sz, eregOfRexRM(pfx,mod_reg_rm),
1312 sz==1 && !haveREX(pfx) );
1313}
1314
1315
1316/*------------------------------------------------------------*/
1317/*--- For dealing with XMM registers ---*/
1318/*------------------------------------------------------------*/
sewardjecb94892005-01-21 14:26:37 +00001319
sewardjd20c8852005-01-20 20:04:07 +00001320//.. static Int segmentGuestRegOffset ( UInt sreg )
1321//.. {
1322//.. switch (sreg) {
1323//.. case R_ES: return OFFB_ES;
1324//.. case R_CS: return OFFB_CS;
1325//.. case R_SS: return OFFB_SS;
1326//.. case R_DS: return OFFB_DS;
1327//.. case R_FS: return OFFB_FS;
1328//.. case R_GS: return OFFB_GS;
1329//.. default: vpanic("segmentGuestRegOffset(x86)");
1330//.. }
1331//.. }
sewardj1001dc42005-02-21 08:25:55 +00001332
1333static Int xmmGuestRegOffset ( UInt xmmreg )
1334{
1335 switch (xmmreg) {
1336 case 0: return OFFB_XMM0;
1337 case 1: return OFFB_XMM1;
1338 case 2: return OFFB_XMM2;
1339 case 3: return OFFB_XMM3;
1340 case 4: return OFFB_XMM4;
1341 case 5: return OFFB_XMM5;
1342 case 6: return OFFB_XMM6;
1343 case 7: return OFFB_XMM7;
1344 case 8: return OFFB_XMM8;
1345 case 9: return OFFB_XMM9;
1346 case 10: return OFFB_XMM10;
1347 case 11: return OFFB_XMM11;
1348 case 12: return OFFB_XMM12;
1349 case 13: return OFFB_XMM13;
1350 case 14: return OFFB_XMM14;
1351 case 15: return OFFB_XMM15;
1352 default: vpanic("xmmGuestRegOffset(amd64)");
1353 }
1354}
1355
sewardjd20c8852005-01-20 20:04:07 +00001356//.. /* Lanes of vector registers are always numbered from zero being the
1357//.. least significant lane (rightmost in the register). */
1358//..
1359//.. static Int xmmGuestRegLane16offset ( UInt xmmreg, Int laneno )
1360//.. {
1361//.. /* Correct for little-endian host only. */
1362//.. vassert(!host_is_bigendian);
1363//.. vassert(laneno >= 0 && laneno < 8);
1364//.. return xmmGuestRegOffset( xmmreg ) + 2 * laneno;
1365//.. }
sewardj8d965312005-02-25 02:48:47 +00001366
1367static Int xmmGuestRegLane32offset ( UInt xmmreg, Int laneno )
1368{
1369 /* Correct for little-endian host only. */
1370 vassert(!host_is_bigendian);
1371 vassert(laneno >= 0 && laneno < 4);
1372 return xmmGuestRegOffset( xmmreg ) + 4 * laneno;
1373}
sewardj1001dc42005-02-21 08:25:55 +00001374
1375static Int xmmGuestRegLane64offset ( UInt xmmreg, Int laneno )
1376{
1377 /* Correct for little-endian host only. */
1378 vassert(!host_is_bigendian);
1379 vassert(laneno >= 0 && laneno < 2);
1380 return xmmGuestRegOffset( xmmreg ) + 8 * laneno;
1381}
1382
sewardjd20c8852005-01-20 20:04:07 +00001383//.. static IRExpr* getSReg ( UInt sreg )
1384//.. {
1385//.. return IRExpr_Get( segmentGuestRegOffset(sreg), Ity_I16 );
1386//.. }
1387//..
1388//.. static void putSReg ( UInt sreg, IRExpr* e )
1389//.. {
1390//.. vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_I16);
1391//.. stmt( IRStmt_Put( segmentGuestRegOffset(sreg), e ) );
1392//.. }
sewardj1001dc42005-02-21 08:25:55 +00001393
1394static IRExpr* getXMMReg ( UInt xmmreg )
1395{
1396 return IRExpr_Get( xmmGuestRegOffset(xmmreg), Ity_V128 );
1397}
1398
1399static IRExpr* getXMMRegLane64 ( UInt xmmreg, Int laneno )
1400{
1401 return IRExpr_Get( xmmGuestRegLane64offset(xmmreg,laneno), Ity_I64 );
1402}
1403
sewardj18303862005-02-21 12:36:54 +00001404static IRExpr* getXMMRegLane64F ( UInt xmmreg, Int laneno )
1405{
1406 return IRExpr_Get( xmmGuestRegLane64offset(xmmreg,laneno), Ity_F64 );
1407}
1408
sewardj8d965312005-02-25 02:48:47 +00001409static IRExpr* getXMMRegLane32 ( UInt xmmreg, Int laneno )
1410{
1411 return IRExpr_Get( xmmGuestRegLane32offset(xmmreg,laneno), Ity_I32 );
1412}
1413
sewardjc49ce232005-02-25 13:03:03 +00001414static IRExpr* getXMMRegLane32F ( UInt xmmreg, Int laneno )
1415{
1416 return IRExpr_Get( xmmGuestRegLane32offset(xmmreg,laneno), Ity_F32 );
1417}
sewardj1001dc42005-02-21 08:25:55 +00001418
1419static void putXMMReg ( UInt xmmreg, IRExpr* e )
1420{
1421 vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_V128);
1422 stmt( IRStmt_Put( xmmGuestRegOffset(xmmreg), e ) );
1423}
1424
1425static void putXMMRegLane64 ( UInt xmmreg, Int laneno, IRExpr* e )
1426{
1427 vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_I64);
1428 stmt( IRStmt_Put( xmmGuestRegLane64offset(xmmreg,laneno), e ) );
1429}
1430
sewardj1a01e652005-02-23 11:39:21 +00001431static void putXMMRegLane64F ( UInt xmmreg, Int laneno, IRExpr* e )
1432{
1433 vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_F64);
1434 stmt( IRStmt_Put( xmmGuestRegLane64offset(xmmreg,laneno), e ) );
1435}
1436
sewardj8d965312005-02-25 02:48:47 +00001437static void putXMMRegLane32F ( UInt xmmreg, Int laneno, IRExpr* e )
1438{
1439 vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_F32);
1440 stmt( IRStmt_Put( xmmGuestRegLane32offset(xmmreg,laneno), e ) );
1441}
1442
1443static void putXMMRegLane32 ( UInt xmmreg, Int laneno, IRExpr* e )
1444{
1445 vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_I32);
1446 stmt( IRStmt_Put( xmmGuestRegLane32offset(xmmreg,laneno), e ) );
1447}
1448
sewardjd20c8852005-01-20 20:04:07 +00001449//.. static void putXMMRegLane16 ( UInt xmmreg, Int laneno, IRExpr* e )
1450//.. {
1451//.. vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_I16);
1452//.. stmt( IRStmt_Put( xmmGuestRegLane16offset(xmmreg,laneno), e ) );
1453//.. }
sewardj3ca55a12005-01-27 16:06:23 +00001454
sewardj1001dc42005-02-21 08:25:55 +00001455static IRExpr* mkV128 ( UShort mask )
1456{
1457 return IRExpr_Const(IRConst_V128(mask));
1458}
sewardjdf0e0022005-01-25 15:48:43 +00001459
sewardj5b470602005-02-27 13:10:48 +00001460
sewardj118b23e2005-01-29 02:14:44 +00001461/*------------------------------------------------------------*/
1462/*--- Helpers for %eflags. ---*/
1463/*------------------------------------------------------------*/
1464
1465/* -------------- Evaluating the flags-thunk. -------------- */
1466
1467/* Build IR to calculate all the eflags from stored
1468 CC_OP/CC_DEP1/CC_DEP2/CC_NDEP. Returns an expression ::
1469 Ity_I64. */
1470static IRExpr* mk_amd64g_calculate_rflags_all ( void )
1471{
1472 IRExpr** args
1473 = mkIRExprVec_4( IRExpr_Get(OFFB_CC_OP, Ity_I64),
1474 IRExpr_Get(OFFB_CC_DEP1, Ity_I64),
1475 IRExpr_Get(OFFB_CC_DEP2, Ity_I64),
1476 IRExpr_Get(OFFB_CC_NDEP, Ity_I64) );
1477 IRExpr* call
1478 = mkIRExprCCall(
1479 Ity_I64,
1480 0/*regparm*/,
1481 "amd64g_calculate_rflags_all", &amd64g_calculate_rflags_all,
1482 args
1483 );
1484 /* Exclude OP and NDEP from definedness checking. We're only
1485 interested in DEP1 and DEP2. */
1486 call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<3);
1487 return call;
1488}
sewardj3ca55a12005-01-27 16:06:23 +00001489
1490/* Build IR to calculate some particular condition from stored
1491 CC_OP/CC_DEP1/CC_DEP2/CC_NDEP. Returns an expression ::
1492 Ity_Bit. */
1493static IRExpr* mk_amd64g_calculate_condition ( AMD64Condcode cond )
1494{
1495 IRExpr** args
1496 = mkIRExprVec_5( mkU64(cond),
1497 IRExpr_Get(OFFB_CC_OP, Ity_I64),
1498 IRExpr_Get(OFFB_CC_DEP1, Ity_I64),
1499 IRExpr_Get(OFFB_CC_DEP2, Ity_I64),
1500 IRExpr_Get(OFFB_CC_NDEP, Ity_I64) );
1501 IRExpr* call
1502 = mkIRExprCCall(
1503 Ity_I64,
1504 0/*regparm*/,
1505 "amd64g_calculate_condition", &amd64g_calculate_condition,
1506 args
1507 );
1508 /* Exclude the requested condition, OP and NDEP from definedness
1509 checking. We're only interested in DEP1 and DEP2. */
1510 call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<1) | (1<<4);
1511 return unop(Iop_32to1, unop(Iop_64to32, call));
1512}
sewardjdf0e0022005-01-25 15:48:43 +00001513
1514/* Build IR to calculate just the carry flag from stored
1515 CC_OP/CC_DEP1/CC_DEP2/CC_NDEP. Returns an expression :: Ity_I64. */
1516static IRExpr* mk_amd64g_calculate_rflags_c ( void )
1517{
1518 IRExpr** args
1519 = mkIRExprVec_4( IRExpr_Get(OFFB_CC_OP, Ity_I64),
1520 IRExpr_Get(OFFB_CC_DEP1, Ity_I64),
1521 IRExpr_Get(OFFB_CC_DEP2, Ity_I64),
1522 IRExpr_Get(OFFB_CC_NDEP, Ity_I64) );
1523 IRExpr* call
1524 = mkIRExprCCall(
1525 Ity_I64,
1526 0/*regparm*/,
1527 "amd64g_calculate_rflags_c", &amd64g_calculate_rflags_c,
1528 args
1529 );
1530 /* Exclude OP and NDEP from definedness checking. We're only
1531 interested in DEP1 and DEP2. */
1532 call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<3);
1533 return call;
1534}
1535
1536
1537/* -------------- Building the flags-thunk. -------------- */
1538
1539/* The machinery in this section builds the flag-thunk following a
1540 flag-setting operation. Hence the various setFlags_* functions.
1541*/
1542
1543static Bool isAddSub ( IROp op8 )
1544{
sewardj7a240552005-01-28 21:37:12 +00001545 return toBool(op8 == Iop_Add8 || op8 == Iop_Sub8);
sewardjdf0e0022005-01-25 15:48:43 +00001546}
1547
sewardj3ca55a12005-01-27 16:06:23 +00001548static Bool isLogic ( IROp op8 )
1549{
sewardj7a240552005-01-28 21:37:12 +00001550 return toBool(op8 == Iop_And8 || op8 == Iop_Or8 || op8 == Iop_Xor8);
sewardj3ca55a12005-01-27 16:06:23 +00001551}
sewardjdf0e0022005-01-25 15:48:43 +00001552
1553/* U-widen 8/16/32/64 bit int expr to 64. */
1554static IRExpr* widenUto64 ( IRExpr* e )
1555{
1556 switch (typeOfIRExpr(irbb->tyenv,e)) {
1557 case Ity_I64: return e;
1558 case Ity_I32: return unop(Iop_32Uto64, e);
1559 case Ity_I16: return unop(Iop_32Uto64, unop(Iop_16Uto32,e));
1560 case Ity_I8: return unop(Iop_32Uto64, unop(Iop_8Uto32,e));
sewardj118b23e2005-01-29 02:14:44 +00001561 default: vpanic("widenUto64");
sewardjdf0e0022005-01-25 15:48:43 +00001562 }
1563}
1564
sewardj118b23e2005-01-29 02:14:44 +00001565/* S-widen 8/16/32/64 bit int expr to 32. */
1566static IRExpr* widenSto64 ( IRExpr* e )
1567{
1568 switch (typeOfIRExpr(irbb->tyenv,e)) {
1569 case Ity_I64: return e;
1570 case Ity_I32: return unop(Iop_32Sto64, e);
1571 case Ity_I16: return unop(Iop_32Sto64, unop(Iop_16Sto32,e));
1572 case Ity_I8: return unop(Iop_32Sto64, unop(Iop_8Sto32,e));
1573 default: vpanic("widenSto64");
1574 }
1575}
sewardjdf0e0022005-01-25 15:48:43 +00001576
1577/* Narrow 8/16/32/64 bit int expr to 8/16/32/64. Clearly only some
1578 of these combinations make sense. */
1579static IRExpr* narrowTo ( IRType dst_ty, IRExpr* e )
1580{
1581 IRType src_ty = typeOfIRExpr(irbb->tyenv,e);
1582 if (src_ty == dst_ty)
1583 return e;
1584 if (src_ty == Ity_I32 && dst_ty == Ity_I16)
1585 return unop(Iop_32to16, e);
1586 if (src_ty == Ity_I32 && dst_ty == Ity_I8)
1587 return unop(Iop_32to8, e);
sewardj118b23e2005-01-29 02:14:44 +00001588 if (src_ty == Ity_I64 && dst_ty == Ity_I32)
1589 return unop(Iop_64to32, e);
1590 if (src_ty == Ity_I64 && dst_ty == Ity_I16)
1591 return unop(Iop_32to16, unop(Iop_64to32, e));
sewardj03b07cc2005-01-31 18:09:43 +00001592 if (src_ty == Ity_I64 && dst_ty == Ity_I8)
1593 return unop(Iop_32to8, unop(Iop_64to32, e));
sewardjdf0e0022005-01-25 15:48:43 +00001594
1595 vex_printf("\nsrc, dst tys are: ");
1596 ppIRType(src_ty);
1597 vex_printf(", ");
1598 ppIRType(dst_ty);
1599 vex_printf("\n");
1600 vpanic("narrowTo(amd64)");
1601}
1602
1603
1604/* Set the flags thunk OP, DEP1 and DEP2 fields. The supplied op is
1605 auto-sized up to the real op. */
1606
1607static
1608void setFlags_DEP1_DEP2 ( IROp op8, IRTemp dep1, IRTemp dep2, IRType ty )
1609{
1610 Int ccOp = 0;
1611 switch (ty) {
1612 case Ity_I8: ccOp = 0; break;
1613 case Ity_I16: ccOp = 1; break;
1614 case Ity_I32: ccOp = 2; break;
1615 case Ity_I64: ccOp = 3; break;
1616 default: vassert(0);
1617 }
1618 switch (op8) {
1619 case Iop_Add8: ccOp += AMD64G_CC_OP_ADDB; break;
1620 case Iop_Sub8: ccOp += AMD64G_CC_OP_SUBB; break;
1621 default: ppIROp(op8);
1622 vpanic("setFlags_DEP1_DEP2(amd64)");
1623 }
1624 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(ccOp)) );
1625 stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto64(mkexpr(dep1))) );
1626 stmt( IRStmt_Put( OFFB_CC_DEP2, widenUto64(mkexpr(dep2))) );
1627}
1628
1629
1630/* Set the OP and DEP1 fields only, and write zero to DEP2. */
1631
1632static
1633void setFlags_DEP1 ( IROp op8, IRTemp dep1, IRType ty )
1634{
1635 Int ccOp = 0;
1636 switch (ty) {
1637 case Ity_I8: ccOp = 0; break;
1638 case Ity_I16: ccOp = 1; break;
1639 case Ity_I32: ccOp = 2; break;
1640 case Ity_I64: ccOp = 3; break;
1641 default: vassert(0);
1642 }
1643 switch (op8) {
1644 case Iop_Or8:
1645 case Iop_And8:
1646 case Iop_Xor8: ccOp += AMD64G_CC_OP_LOGICB; break;
1647 default: ppIROp(op8);
1648 vpanic("setFlags_DEP1(amd64)");
1649 }
1650 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(ccOp)) );
1651 stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto64(mkexpr(dep1))) );
1652 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0)) );
1653}
1654
1655
sewardj118b23e2005-01-29 02:14:44 +00001656/* For shift operations, we put in the result and the undershifted
1657 result. Except if the shift amount is zero, the thunk is left
1658 unchanged. */
1659
1660static void setFlags_DEP1_DEP2_shift ( IROp op64,
1661 IRTemp res,
1662 IRTemp resUS,
1663 IRType ty,
1664 IRTemp guard )
1665{
1666 Int ccOp = 0;
1667 switch (ty) {
1668 case Ity_I8: ccOp = 0; break;
1669 case Ity_I16: ccOp = 1; break;
1670 case Ity_I32: ccOp = 2; break;
1671 case Ity_I64: ccOp = 3; break;
1672 default: vassert(0);
1673 }
1674
1675 vassert(guard);
1676
1677 /* Both kinds of right shifts are handled by the same thunk
1678 operation. */
1679 switch (op64) {
1680 case Iop_Shr64:
1681 case Iop_Sar64: ccOp += AMD64G_CC_OP_SHRB; break;
1682 case Iop_Shl64: ccOp += AMD64G_CC_OP_SHLB; break;
1683 default: ppIROp(op64);
1684 vpanic("setFlags_DEP1_DEP2_shift(amd64)");
1685 }
1686
1687 /* DEP1 contains the result, DEP2 contains the undershifted value. */
1688 stmt( IRStmt_Put( OFFB_CC_OP,
1689 IRExpr_Mux0X( mkexpr(guard),
1690 IRExpr_Get(OFFB_CC_OP,Ity_I64),
1691 mkU64(ccOp))) );
1692 stmt( IRStmt_Put( OFFB_CC_DEP1,
1693 IRExpr_Mux0X( mkexpr(guard),
1694 IRExpr_Get(OFFB_CC_DEP1,Ity_I64),
1695 widenUto64(mkexpr(res)))) );
1696 stmt( IRStmt_Put( OFFB_CC_DEP2,
1697 IRExpr_Mux0X( mkexpr(guard),
1698 IRExpr_Get(OFFB_CC_DEP2,Ity_I64),
1699 widenUto64(mkexpr(resUS)))) );
1700}
sewardj354e5c62005-01-27 20:12:52 +00001701
1702
1703/* For the inc/dec case, we store in DEP1 the result value and in NDEP
1704 the former value of the carry flag, which unfortunately we have to
1705 compute. */
1706
1707static void setFlags_INC_DEC ( Bool inc, IRTemp res, IRType ty )
1708{
1709 Int ccOp = inc ? AMD64G_CC_OP_INCB : AMD64G_CC_OP_DECB;
1710
1711 switch (ty) {
1712 case Ity_I8: ccOp += 0; break;
1713 case Ity_I16: ccOp += 1; break;
1714 case Ity_I32: ccOp += 2; break;
1715 case Ity_I64: ccOp += 3; break;
1716 default: vassert(0);
1717 }
1718
1719 /* This has to come first, because calculating the C flag
1720 may require reading all four thunk fields. */
1721 stmt( IRStmt_Put( OFFB_CC_NDEP, mk_amd64g_calculate_rflags_c()) );
1722 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(ccOp)) );
1723 stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(res)) );
1724 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0)) );
1725}
1726
1727
sewardj32b2bbe2005-01-28 00:50:10 +00001728/* Multiplies are pretty much like add and sub: DEP1 and DEP2 hold the
1729 two arguments. */
1730
1731static
1732void setFlags_MUL ( IRType ty, IRTemp arg1, IRTemp arg2, ULong base_op )
1733{
1734 switch (ty) {
1735 case Ity_I8:
1736 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(base_op+0) ) );
1737 break;
1738 case Ity_I16:
1739 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(base_op+1) ) );
1740 break;
1741 case Ity_I32:
1742 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(base_op+2) ) );
1743 break;
1744 case Ity_I64:
1745 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(base_op+3) ) );
1746 break;
1747 default:
1748 vpanic("setFlags_MUL(amd64)");
1749 }
1750 stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto64(mkexpr(arg1)) ));
1751 stmt( IRStmt_Put( OFFB_CC_DEP2, widenUto64(mkexpr(arg2)) ));
1752}
sewardj3ca55a12005-01-27 16:06:23 +00001753
1754
1755/* -------------- Condition codes. -------------- */
1756
1757/* Condition codes, using the AMD encoding. */
1758
sewardj8c332e22005-01-28 01:36:56 +00001759static HChar* name_AMD64Condcode ( AMD64Condcode cond )
sewardj3ca55a12005-01-27 16:06:23 +00001760{
1761 switch (cond) {
1762 case AMD64CondO: return "o";
1763 case AMD64CondNO: return "no";
1764 case AMD64CondB: return "b";
sewardje941eea2005-01-30 19:52:28 +00001765 case AMD64CondNB: return "ae"; /*"nb";*/
1766 case AMD64CondZ: return "e"; /*"z";*/
1767 case AMD64CondNZ: return "ne"; /*"nz";*/
sewardj3ca55a12005-01-27 16:06:23 +00001768 case AMD64CondBE: return "be";
sewardje941eea2005-01-30 19:52:28 +00001769 case AMD64CondNBE: return "a"; /*"nbe";*/
sewardj3ca55a12005-01-27 16:06:23 +00001770 case AMD64CondS: return "s";
1771 case AMD64CondNS: return "ns";
1772 case AMD64CondP: return "p";
1773 case AMD64CondNP: return "np";
1774 case AMD64CondL: return "l";
sewardje941eea2005-01-30 19:52:28 +00001775 case AMD64CondNL: return "ge"; /*"nl";*/
sewardj3ca55a12005-01-27 16:06:23 +00001776 case AMD64CondLE: return "le";
sewardje941eea2005-01-30 19:52:28 +00001777 case AMD64CondNLE: return "g"; /*"nle";*/
sewardj3ca55a12005-01-27 16:06:23 +00001778 case AMD64CondAlways: return "ALWAYS";
1779 default: vpanic("name_AMD64Condcode");
1780 }
1781}
1782
sewardj1389d4d2005-01-28 13:46:29 +00001783static
1784AMD64Condcode positiveIse_AMD64Condcode ( AMD64Condcode cond,
1785 /*OUT*/Bool* needInvert )
1786{
1787 vassert(cond >= AMD64CondO && cond <= AMD64CondNLE);
1788 if (cond & 1) {
1789 *needInvert = True;
1790 return cond-1;
1791 } else {
1792 *needInvert = False;
1793 return cond;
1794 }
1795}
sewardjdf0e0022005-01-25 15:48:43 +00001796
1797
1798/* -------------- Helpers for ADD/SUB with carry. -------------- */
1799
1800/* Given ta1, ta2 and tres, compute tres = ADC(ta1,ta2) and set flags
1801 appropriately.
1802*/
1803static void helper_ADC ( Int sz,
1804 IRTemp tres, IRTemp ta1, IRTemp ta2 )
1805{
1806 UInt thunkOp;
1807 IRType ty = szToITy(sz);
1808 IRTemp oldc = newTemp(Ity_I64);
1809 IRTemp oldcn = newTemp(ty);
1810 IROp plus = mkSizedOp(ty, Iop_Add8);
1811 IROp xor = mkSizedOp(ty, Iop_Xor8);
1812
1813 switch (sz) {
1814 case 8: thunkOp = AMD64G_CC_OP_ADCQ; break;
1815 case 4: thunkOp = AMD64G_CC_OP_ADCL; break;
1816 case 2: thunkOp = AMD64G_CC_OP_ADCW; break;
1817 case 1: thunkOp = AMD64G_CC_OP_ADCB; break;
1818 default: vassert(0);
1819 }
1820
1821 /* oldc = old carry flag, 0 or 1 */
1822 assign( oldc, binop(Iop_And64,
1823 mk_amd64g_calculate_rflags_c(),
1824 mkU64(1)) );
1825
1826 assign( oldcn, narrowTo(ty, mkexpr(oldc)) );
1827
1828 assign( tres, binop(plus,
1829 binop(plus,mkexpr(ta1),mkexpr(ta2)),
1830 mkexpr(oldcn)) );
1831
1832 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(thunkOp) ) );
1833 stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(ta1) ) );
1834 stmt( IRStmt_Put( OFFB_CC_DEP2, binop(xor, mkexpr(ta2),
1835 mkexpr(oldcn)) ) );
1836 stmt( IRStmt_Put( OFFB_CC_NDEP, mkexpr(oldc) ) );
1837}
1838
1839
1840/* Given ta1, ta2 and tres, compute tres = SBB(ta1,ta2) and set flags
1841 appropriately.
1842*/
1843static void helper_SBB ( Int sz,
1844 IRTemp tres, IRTemp ta1, IRTemp ta2 )
1845{
1846 UInt thunkOp;
1847 IRType ty = szToITy(sz);
1848 IRTemp oldc = newTemp(Ity_I64);
1849 IRTemp oldcn = newTemp(ty);
1850 IROp minus = mkSizedOp(ty, Iop_Sub8);
1851 IROp xor = mkSizedOp(ty, Iop_Xor8);
1852
1853 switch (sz) {
1854 case 8: thunkOp = AMD64G_CC_OP_SBBQ; break;
1855 case 4: thunkOp = AMD64G_CC_OP_SBBL; break;
1856 case 2: thunkOp = AMD64G_CC_OP_SBBW; break;
1857 case 1: thunkOp = AMD64G_CC_OP_SBBB; break;
1858 default: vassert(0);
1859 }
1860
1861 /* oldc = old carry flag, 0 or 1 */
1862 assign( oldc, binop(Iop_And64,
1863 mk_amd64g_calculate_rflags_c(),
1864 mkU64(1)) );
1865
1866 assign( oldcn, narrowTo(ty, mkexpr(oldc)) );
1867
1868 assign( tres, binop(minus,
1869 binop(minus,mkexpr(ta1),mkexpr(ta2)),
1870 mkexpr(oldcn)) );
1871
1872 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(thunkOp) ) );
1873 stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(ta1) ) );
1874 stmt( IRStmt_Put( OFFB_CC_DEP2, binop(xor, mkexpr(ta2),
1875 mkexpr(oldcn)) ) );
1876 stmt( IRStmt_Put( OFFB_CC_NDEP, mkexpr(oldc) ) );
1877}
1878
1879
sewardj3ca55a12005-01-27 16:06:23 +00001880/* -------------- Helpers for disassembly printing. -------------- */
1881
1882static HChar* nameGrp1 ( Int opc_aux )
1883{
1884 static HChar* grp1_names[8]
1885 = { "add", "or", "adc", "sbb", "and", "sub", "xor", "cmp" };
1886 if (opc_aux < 0 || opc_aux > 7) vpanic("nameGrp1(amd64)");
1887 return grp1_names[opc_aux];
1888}
1889
sewardj118b23e2005-01-29 02:14:44 +00001890static HChar* nameGrp2 ( Int opc_aux )
1891{
1892 static HChar* grp2_names[8]
1893 = { "rol", "ror", "rcl", "rcr", "shl", "shr", "shl", "sar" };
sewardje941eea2005-01-30 19:52:28 +00001894 if (opc_aux < 0 || opc_aux > 7) vpanic("nameGrp2(amd64)");
sewardj118b23e2005-01-29 02:14:44 +00001895 return grp2_names[opc_aux];
1896}
1897
sewardj03b07cc2005-01-31 18:09:43 +00001898static HChar* nameGrp4 ( Int opc_aux )
1899{
1900 static HChar* grp4_names[8]
1901 = { "inc", "dec", "???", "???", "???", "???", "???", "???" };
1902 if (opc_aux < 0 || opc_aux > 1) vpanic("nameGrp4(amd64)");
1903 return grp4_names[opc_aux];
1904}
sewardj354e5c62005-01-27 20:12:52 +00001905
1906static HChar* nameGrp5 ( Int opc_aux )
1907{
1908 static HChar* grp5_names[8]
1909 = { "inc", "dec", "call*", "call*", "jmp*", "jmp*", "push", "???" };
1910 if (opc_aux < 0 || opc_aux > 6) vpanic("nameGrp5(amd64)");
1911 return grp5_names[opc_aux];
1912}
1913
sewardjd20c8852005-01-20 20:04:07 +00001914//.. //-- static Char* nameGrp8 ( Int opc_aux )
1915//.. //-- {
1916//.. //-- static Char* grp8_names[8]
1917//.. //-- = { "???", "???", "???", "???", "bt", "bts", "btr", "btc" };
1918//.. //-- if (opc_aux < 4 || opc_aux > 7) VG_(core_panic)("nameGrp8");
1919//.. //-- return grp8_names[opc_aux];
1920//.. //-- }
1921//..
sewardjd20c8852005-01-20 20:04:07 +00001922//.. static HChar* nameSReg ( UInt sreg )
1923//.. {
1924//.. switch (sreg) {
1925//.. case R_ES: return "%es";
1926//.. case R_CS: return "%cs";
1927//.. case R_SS: return "%ss";
1928//.. case R_DS: return "%ds";
1929//.. case R_FS: return "%fs";
1930//.. case R_GS: return "%gs";
1931//.. default: vpanic("nameSReg(x86)");
1932//.. }
1933//.. }
1934//..
1935//.. static HChar* nameMMXReg ( Int mmxreg )
1936//.. {
1937//.. static HChar* mmx_names[8]
1938//.. = { "%mm0", "%mm1", "%mm2", "%mm3", "%mm4", "%mm5", "%mm6", "%mm7" };
1939//.. if (mmxreg < 0 || mmxreg > 7) vpanic("nameMMXReg(x86,guest)");
1940//.. return mmx_names[mmxreg];
1941//.. }
sewardj1001dc42005-02-21 08:25:55 +00001942
1943static HChar* nameXMMReg ( Int xmmreg )
1944{
1945 static HChar* xmm_names[16]
1946 = { "%xmm0", "%xmm1", "%xmm2", "%xmm3",
1947 "%xmm4", "%xmm5", "%xmm6", "%xmm7",
1948 "%xmm8", "%xmm9", "%xmm10", "%xmm11",
1949 "%xmm12", "%xmm13", "%xmm14", "%xmm15" };
1950 if (xmmreg < 0 || xmmreg > 15) vpanic("nameXMMReg(amd64)");
1951 return xmm_names[xmmreg];
1952}
1953
sewardjd20c8852005-01-20 20:04:07 +00001954//.. static Char* nameMMXGran ( UChar gran )
1955//.. {
1956//.. switch (gran) {
1957//.. case 0: return "b";
1958//.. case 1: return "w";
1959//.. case 2: return "d";
1960//.. case 3: return "q";
1961//.. default: vpanic("nameMMXGran(x86,guest)");
1962//.. }
1963//.. }
sewardjdf0e0022005-01-25 15:48:43 +00001964
sewardj8c332e22005-01-28 01:36:56 +00001965static HChar nameISize ( Int size )
sewardjdf0e0022005-01-25 15:48:43 +00001966{
1967 switch (size) {
1968 case 8: return 'q';
1969 case 4: return 'l';
1970 case 2: return 'w';
1971 case 1: return 'b';
1972 default: vpanic("nameISize(amd64)");
1973 }
1974}
1975
1976
1977/*------------------------------------------------------------*/
1978/*--- JMP helpers ---*/
1979/*------------------------------------------------------------*/
1980
1981static void jmp_lit( IRJumpKind kind, Addr64 d64 )
1982{
1983 irbb->next = mkU64(d64);
1984 irbb->jumpkind = kind;
1985}
1986
sewardj2f959cc2005-01-26 01:19:35 +00001987static void jmp_treg( IRJumpKind kind, IRTemp t )
1988{
sewardj3ca55a12005-01-27 16:06:23 +00001989 irbb->next = mkexpr(t);
sewardj2f959cc2005-01-26 01:19:35 +00001990 irbb->jumpkind = kind;
1991}
1992
sewardj1389d4d2005-01-28 13:46:29 +00001993static
1994void jcc_01 ( AMD64Condcode cond, Addr64 d64_false, Addr64 d64_true )
1995{
1996 Bool invert;
1997 AMD64Condcode condPos;
1998 condPos = positiveIse_AMD64Condcode ( cond, &invert );
1999 if (invert) {
2000 stmt( IRStmt_Exit( mk_amd64g_calculate_condition(condPos),
2001 Ijk_Boring,
2002 IRConst_U64(d64_false) ) );
2003 irbb->next = mkU64(d64_true);
2004 irbb->jumpkind = Ijk_Boring;
2005 } else {
2006 stmt( IRStmt_Exit( mk_amd64g_calculate_condition(condPos),
2007 Ijk_Boring,
2008 IRConst_U64(d64_true) ) );
2009 irbb->next = mkU64(d64_false);
2010 irbb->jumpkind = Ijk_Boring;
2011 }
2012}
sewardjb3a04292005-01-21 20:33:44 +00002013
2014
2015/*------------------------------------------------------------*/
2016/*--- Disassembling addressing modes ---*/
2017/*------------------------------------------------------------*/
2018
2019static
sewardj8c332e22005-01-28 01:36:56 +00002020HChar* sorbTxt ( Prefix pfx )
sewardjb3a04292005-01-21 20:33:44 +00002021{
2022 if (pfx & PFX_CS) return "%cs:";
2023 if (pfx & PFX_DS) return "%ds:";
2024 if (pfx & PFX_ES) return "%es:";
2025 if (pfx & PFX_FS) return "%fs:";
2026 if (pfx & PFX_GS) return "%gs:";
2027 if (pfx & PFX_SS) return "%ss:";
2028 return ""; /* no override */
2029}
2030
2031
2032/* 'virtual' is an IRExpr* holding a virtual address. Convert it to a
2033 linear address by adding any required segment override as indicated
2034 by sorb. */
2035static
2036IRExpr* handleSegOverride ( Prefix pfx, IRExpr* virtual )
2037{
sewardja6b93d12005-02-17 09:28:28 +00002038 if (pfx & PFX_FS) {
2039 /* Note that this is a linux-kernel specific hack that relies
2040 on the assumption that %fs is always zero. */
2041 /* return virtual + guest_FS_ZERO. */
2042 return binop(Iop_Add64, virtual, IRExpr_Get(OFFB_FS_ZERO, Ity_I64));
2043 }
sewardjb3a04292005-01-21 20:33:44 +00002044
sewardja6b93d12005-02-17 09:28:28 +00002045 if (pfx & PFX_GS) {
2046 unimplemented("amd64 %gs segment override");
2047 }
2048
2049 /* cs, ds, es and ss are simply ignored in 64-bit mode. */
2050 return virtual;
sewardjb3a04292005-01-21 20:33:44 +00002051}
sewardja6b93d12005-02-17 09:28:28 +00002052
sewardjd20c8852005-01-20 20:04:07 +00002053//.. {
2054//.. Int sreg;
2055//.. IRType hWordTy;
2056//.. IRTemp ldt_ptr, gdt_ptr, seg_selector, r64;
2057//..
2058//.. if (sorb == 0)
2059//.. /* the common case - no override */
2060//.. return virtual;
2061//..
2062//.. switch (sorb) {
2063//.. case 0x3E: sreg = R_DS; break;
2064//.. case 0x26: sreg = R_ES; break;
2065//.. case 0x64: sreg = R_FS; break;
2066//.. case 0x65: sreg = R_GS; break;
2067//.. default: vpanic("handleSegOverride(x86,guest)");
2068//.. }
2069//..
2070//.. hWordTy = sizeof(HWord)==4 ? Ity_I32 : Ity_I64;
2071//..
2072//.. seg_selector = newTemp(Ity_I32);
2073//.. ldt_ptr = newTemp(hWordTy);
2074//.. gdt_ptr = newTemp(hWordTy);
2075//.. r64 = newTemp(Ity_I64);
2076//..
2077//.. assign( seg_selector, unop(Iop_16Uto32, getSReg(sreg)) );
2078//.. assign( ldt_ptr, IRExpr_Get( OFFB_LDT, hWordTy ));
2079//.. assign( gdt_ptr, IRExpr_Get( OFFB_GDT, hWordTy ));
2080//..
2081//.. /*
2082//.. Call this to do the translation and limit checks:
2083//.. ULong x86g_use_seg_selector ( HWord ldt, HWord gdt,
2084//.. UInt seg_selector, UInt virtual_addr )
2085//.. */
2086//.. assign(
2087//.. r64,
2088//.. mkIRExprCCall(
2089//.. Ity_I64,
2090//.. 0/*regparms*/,
2091//.. "x86g_use_seg_selector",
2092//.. &x86g_use_seg_selector,
2093//.. mkIRExprVec_4( mkexpr(ldt_ptr), mkexpr(gdt_ptr),
2094//.. mkexpr(seg_selector), virtual)
2095//.. )
2096//.. );
2097//..
2098//.. /* If the high 32 of the result are non-zero, there was a
2099//.. failure in address translation. In which case, make a
2100//.. quick exit.
2101//.. */
2102//.. stmt(
2103//.. IRStmt_Exit(
2104//.. binop(Iop_CmpNE32, unop(Iop_64HIto32, mkexpr(r64)), mkU32(0)),
2105//.. Ijk_MapFail,
2106//.. IRConst_U32( guest_eip_curr_instr )
2107//.. )
2108//.. );
2109//..
2110//.. /* otherwise, here's the translated result. */
2111//.. return unop(Iop_64to32, mkexpr(r64));
2112//.. }
sewardjb3a04292005-01-21 20:33:44 +00002113
2114
2115/* Generate IR to calculate an address indicated by a ModRM and
2116 following SIB bytes. The expression, and the number of bytes in
2117 the address mode, are returned (the latter in *len). Note that
2118 this fn should not be called if the R/M part of the address denotes
2119 a register instead of memory. If print_codegen is true, text of
2120 the addressing mode is placed in buf.
2121
2122 The computed address is stored in a new tempreg, and the
sewardje1698952005-02-08 15:02:39 +00002123 identity of the tempreg is returned.
2124
2125 extra_bytes holds the number of bytes after the amode, as supplied
2126 by the caller. This is needed to make sense of %rip-relative
2127 addresses. Note that the value that *len is set to is only the
2128 length of the amode itself and does not include the value supplied
2129 in xtra_bytes.
2130 */
sewardjb3a04292005-01-21 20:33:44 +00002131
2132static IRTemp disAMode_copy2tmp ( IRExpr* addr64 )
2133{
2134 IRTemp tmp = newTemp(Ity_I64);
2135 assign( tmp, addr64 );
2136 return tmp;
2137}
2138
2139static
sewardje1698952005-02-08 15:02:39 +00002140IRTemp disAMode ( Int* len, Prefix pfx, ULong delta,
2141 HChar* buf, Int extra_bytes )
sewardjb3a04292005-01-21 20:33:44 +00002142{
sewardj8c332e22005-01-28 01:36:56 +00002143 UChar mod_reg_rm = getUChar(delta);
sewardjb3a04292005-01-21 20:33:44 +00002144 delta++;
2145
2146 buf[0] = (UChar)0;
sewardje1698952005-02-08 15:02:39 +00002147 vassert(extra_bytes >= 0 && extra_bytes < 10);
sewardjb3a04292005-01-21 20:33:44 +00002148
2149 /* squeeze out the reg field from mod_reg_rm, since a 256-entry
2150 jump table seems a bit excessive.
2151 */
sewardj7a240552005-01-28 21:37:12 +00002152 mod_reg_rm &= 0xC7; /* is now XX000YYY */
sewardj1027dc22005-02-26 01:55:02 +00002153 mod_reg_rm = toUChar(mod_reg_rm | (mod_reg_rm >> 3));
2154 /* is now XX0XXYYY */
sewardj7a240552005-01-28 21:37:12 +00002155 mod_reg_rm &= 0x1F; /* is now 000XXYYY */
sewardjb3a04292005-01-21 20:33:44 +00002156 switch (mod_reg_rm) {
2157
2158 /* REX.B==0: (%rax) .. (%rdi), not including (%rsp) or (%rbp).
2159 REX.B==1: (%r8) .. (%r15), not including (%r12) or (%r13).
2160 */
2161 case 0x00: case 0x01: case 0x02: case 0x03:
2162 /* ! 04 */ /* ! 05 */ case 0x06: case 0x07:
sewardj1027dc22005-02-26 01:55:02 +00002163 { UChar rm = toUChar(mod_reg_rm & 7);
sewardj5b470602005-02-27 13:10:48 +00002164 DIS(buf, "%s(%s)", sorbTxt(pfx), nameIRegRexB(8,pfx,rm));
sewardjb3a04292005-01-21 20:33:44 +00002165 *len = 1;
2166 return disAMode_copy2tmp(
sewardj5b470602005-02-27 13:10:48 +00002167 handleSegOverride(pfx, getIRegRexB(8,pfx,rm)));
sewardjb3a04292005-01-21 20:33:44 +00002168 }
2169
2170 /* REX.B==0: d8(%rax) ... d8(%rdi), not including d8(%rsp)
2171 REX.B==1: d8(%r8) ... d8(%r15), not including d8(%r12)
2172 */
2173 case 0x08: case 0x09: case 0x0A: case 0x0B:
2174 /* ! 0C */ case 0x0D: case 0x0E: case 0x0F:
sewardj1027dc22005-02-26 01:55:02 +00002175 { UChar rm = toUChar(mod_reg_rm & 7);
sewardj8c332e22005-01-28 01:36:56 +00002176 Long d = getSDisp8(delta);
sewardj7eaa7cf2005-01-31 18:55:22 +00002177 if (d == 0) {
sewardj5b470602005-02-27 13:10:48 +00002178 DIS(buf, "%s(%s)", sorbTxt(pfx), nameIRegRexB(8,pfx,rm));
sewardj7eaa7cf2005-01-31 18:55:22 +00002179 } else {
sewardj5b470602005-02-27 13:10:48 +00002180 DIS(buf, "%s%lld(%s)", sorbTxt(pfx), d, nameIRegRexB(8,pfx,rm));
sewardj7eaa7cf2005-01-31 18:55:22 +00002181 }
sewardjb3a04292005-01-21 20:33:44 +00002182 *len = 2;
2183 return disAMode_copy2tmp(
2184 handleSegOverride(pfx,
sewardj5b470602005-02-27 13:10:48 +00002185 binop(Iop_Add64,getIRegRexB(8,pfx,rm),mkU64(d))));
sewardjb3a04292005-01-21 20:33:44 +00002186 }
2187
2188 /* REX.B==0: d32(%rax) ... d32(%rdi), not including d32(%rsp)
2189 REX.B==1: d32(%r8) ... d32(%r15), not including d32(%r12)
2190 */
2191 case 0x10: case 0x11: case 0x12: case 0x13:
2192 /* ! 14 */ case 0x15: case 0x16: case 0x17:
sewardj1027dc22005-02-26 01:55:02 +00002193 { UChar rm = toUChar(mod_reg_rm & 7);
sewardj227458e2005-01-31 19:04:50 +00002194 Long d = getSDisp32(delta);
sewardj5b470602005-02-27 13:10:48 +00002195 DIS(buf, "%s%lld(%s)", sorbTxt(pfx), d, nameIRegRexB(8,pfx,rm));
sewardjb3a04292005-01-21 20:33:44 +00002196 *len = 5;
2197 return disAMode_copy2tmp(
2198 handleSegOverride(pfx,
sewardj5b470602005-02-27 13:10:48 +00002199 binop(Iop_Add64,getIRegRexB(8,pfx,rm),mkU64(d))));
sewardjb3a04292005-01-21 20:33:44 +00002200 }
2201
2202 /* REX.B==0: a register, %rax .. %rdi. This shouldn't happen. */
2203 /* REX.B==1: a register, %r8 .. %r16. This shouldn't happen. */
2204 case 0x18: case 0x19: case 0x1A: case 0x1B:
2205 case 0x1C: case 0x1D: case 0x1E: case 0x1F:
sewardj354e5c62005-01-27 20:12:52 +00002206 vpanic("disAMode(amd64): not an addr!");
sewardjb3a04292005-01-21 20:33:44 +00002207
sewardjdf0e0022005-01-25 15:48:43 +00002208 /* RIP + disp32. This assumes that guest_rip_curr_instr is set
sewardjb3a04292005-01-21 20:33:44 +00002209 correctly at the start of handling each instruction. */
2210 case 0x05:
sewardj227458e2005-01-31 19:04:50 +00002211 { Long d = getSDisp32(delta);
sewardjb3a04292005-01-21 20:33:44 +00002212 *len = 5;
sewardj7eaa7cf2005-01-31 18:55:22 +00002213 DIS(buf, "%s%lld(%%rip)", sorbTxt(pfx), d);
sewardj4b744762005-02-07 15:02:25 +00002214 /* We need to know the next instruction's start address.
2215 Try and figure out what it is, record the guess, and ask
2216 the top-level driver logic (bbToIR_AMD64) to check we
2217 guessed right, after the instruction is completely
2218 decoded. */
2219 guest_rip_next_mustcheck = True;
sewardje1698952005-02-08 15:02:39 +00002220 guest_rip_next_assumed = guest_rip_bbstart
2221 + delta+4 + extra_bytes;
sewardjb3a04292005-01-21 20:33:44 +00002222 return disAMode_copy2tmp(
2223 handleSegOverride(pfx,
sewardj4b744762005-02-07 15:02:25 +00002224 binop(Iop_Add64, mkU64(guest_rip_next_assumed),
sewardjb3a04292005-01-21 20:33:44 +00002225 mkU64(d))));
2226 }
sewardj3ca55a12005-01-27 16:06:23 +00002227
sewardj2f959cc2005-01-26 01:19:35 +00002228 case 0x04: {
2229 /* SIB, with no displacement. Special cases:
sewardj3ca55a12005-01-27 16:06:23 +00002230 -- %rsp cannot act as an index value.
2231 If index_r indicates %rsp, zero is used for the index.
2232 -- when mod is zero and base indicates RBP or R13, base is
2233 instead a 32-bit sign-extended literal.
sewardj2f959cc2005-01-26 01:19:35 +00002234 It's all madness, I tell you. Extract %index, %base and
2235 scale from the SIB byte. The value denoted is then:
sewardj3ca55a12005-01-27 16:06:23 +00002236 | %index == %RSP && (%base == %RBP || %base == %R13)
sewardj2f959cc2005-01-26 01:19:35 +00002237 = d32 following SIB byte
sewardj3ca55a12005-01-27 16:06:23 +00002238 | %index == %RSP && !(%base == %RBP || %base == %R13)
sewardj2f959cc2005-01-26 01:19:35 +00002239 = %base
sewardj3ca55a12005-01-27 16:06:23 +00002240 | %index != %RSP && (%base == %RBP || %base == %R13)
sewardj2f959cc2005-01-26 01:19:35 +00002241 = d32 following SIB byte + (%index << scale)
sewardj3ca55a12005-01-27 16:06:23 +00002242 | %index != %RSP && !(%base == %RBP || %base == %R13)
sewardj2f959cc2005-01-26 01:19:35 +00002243 = %base + (%index << scale)
2244 */
sewardj8c332e22005-01-28 01:36:56 +00002245 UChar sib = getUChar(delta);
sewardj1027dc22005-02-26 01:55:02 +00002246 UChar scale = toUChar((sib >> 6) & 3);
2247 UChar index_r = toUChar((sib >> 3) & 7);
2248 UChar base_r = toUChar(sib & 7);
sewardj3ca55a12005-01-27 16:06:23 +00002249 /* correct since #(R13) == 8 + #(RBP) */
sewardj7a240552005-01-28 21:37:12 +00002250 Bool base_is_BPor13 = toBool(base_r == R_RBP);
2251 Bool index_is_SP = toBool(index_r == R_RSP && 0==getRexX(pfx));
sewardj2f959cc2005-01-26 01:19:35 +00002252 delta++;
sewardjb3a04292005-01-21 20:33:44 +00002253
sewardj3ca55a12005-01-27 16:06:23 +00002254 if ((!index_is_SP) && (!base_is_BPor13)) {
sewardje941eea2005-01-30 19:52:28 +00002255 if (scale == 0) {
2256 DIS(buf, "%s(%s,%s)", sorbTxt(pfx),
sewardj5b470602005-02-27 13:10:48 +00002257 nameIRegRexB(8,pfx,base_r),
2258 nameIReg64rexX(pfx,index_r));
sewardje941eea2005-01-30 19:52:28 +00002259 } else {
2260 DIS(buf, "%s(%s,%s,%d)", sorbTxt(pfx),
sewardj5b470602005-02-27 13:10:48 +00002261 nameIRegRexB(8,pfx,base_r),
2262 nameIReg64rexX(pfx,index_r), 1<<scale);
sewardje941eea2005-01-30 19:52:28 +00002263 }
sewardj2f959cc2005-01-26 01:19:35 +00002264 *len = 2;
sewardj2f959cc2005-01-26 01:19:35 +00002265 return
2266 disAMode_copy2tmp(
sewardj3ca55a12005-01-27 16:06:23 +00002267 handleSegOverride(pfx,
2268 binop(Iop_Add64,
sewardj5b470602005-02-27 13:10:48 +00002269 getIRegRexB(8,pfx,base_r),
2270 binop(Iop_Shl64, getIReg64rexX(pfx,index_r),
sewardj2f959cc2005-01-26 01:19:35 +00002271 mkU8(scale)))));
2272 }
2273
sewardj3ca55a12005-01-27 16:06:23 +00002274 if ((!index_is_SP) && base_is_BPor13) {
sewardj227458e2005-01-31 19:04:50 +00002275 Long d = getSDisp32(delta);
sewardj7eaa7cf2005-01-31 18:55:22 +00002276 DIS(buf, "%s%lld(,%s,%d)", sorbTxt(pfx), d,
sewardj5b470602005-02-27 13:10:48 +00002277 nameIReg64rexX(pfx,index_r), 1<<scale);
sewardj2f959cc2005-01-26 01:19:35 +00002278 *len = 6;
sewardj2f959cc2005-01-26 01:19:35 +00002279 return
2280 disAMode_copy2tmp(
sewardj3ca55a12005-01-27 16:06:23 +00002281 handleSegOverride(pfx,
2282 binop(Iop_Add64,
sewardj5b470602005-02-27 13:10:48 +00002283 binop(Iop_Shl64, getIReg64rexX(pfx,index_r),
sewardj3ca55a12005-01-27 16:06:23 +00002284 mkU8(scale)),
2285 mkU64(d))));
sewardj2f959cc2005-01-26 01:19:35 +00002286 }
2287
sewardj3ca55a12005-01-27 16:06:23 +00002288 if (index_is_SP && (!base_is_BPor13)) {
sewardj5b470602005-02-27 13:10:48 +00002289 DIS(buf, "%s(%s)", sorbTxt(pfx), nameIRegRexB(8,pfx,base_r));
sewardj2f959cc2005-01-26 01:19:35 +00002290 *len = 2;
sewardj2f959cc2005-01-26 01:19:35 +00002291 return disAMode_copy2tmp(
sewardj5b470602005-02-27 13:10:48 +00002292 handleSegOverride(pfx, getIRegRexB(8,pfx,base_r)));
sewardj2f959cc2005-01-26 01:19:35 +00002293 }
2294
sewardj3ca55a12005-01-27 16:06:23 +00002295 if (index_is_SP && base_is_BPor13) {
sewardj227458e2005-01-31 19:04:50 +00002296 Long d = getSDisp32(delta);
sewardj7eaa7cf2005-01-31 18:55:22 +00002297 DIS(buf, "%s%lld", sorbTxt(pfx), d);
sewardj2f959cc2005-01-26 01:19:35 +00002298 *len = 6;
sewardj2f959cc2005-01-26 01:19:35 +00002299 return disAMode_copy2tmp(
sewardj3ca55a12005-01-27 16:06:23 +00002300 handleSegOverride(pfx, mkU64(d)));
sewardj2f959cc2005-01-26 01:19:35 +00002301 }
2302
2303 vassert(0);
2304 }
sewardj3ca55a12005-01-27 16:06:23 +00002305
sewardj2f959cc2005-01-26 01:19:35 +00002306 /* SIB, with 8-bit displacement. Special cases:
2307 -- %esp cannot act as an index value.
2308 If index_r indicates %esp, zero is used for the index.
2309 Denoted value is:
2310 | %index == %ESP
2311 = d8 + %base
2312 | %index != %ESP
2313 = d8 + %base + (%index << scale)
2314 */
2315 case 0x0C: {
sewardj8c332e22005-01-28 01:36:56 +00002316 UChar sib = getUChar(delta);
sewardj1027dc22005-02-26 01:55:02 +00002317 UChar scale = toUChar((sib >> 6) & 3);
2318 UChar index_r = toUChar((sib >> 3) & 7);
2319 UChar base_r = toUChar(sib & 7);
sewardj8c332e22005-01-28 01:36:56 +00002320 Long d = getSDisp8(delta+1);
sewardj2f959cc2005-01-26 01:19:35 +00002321
sewardj3ca55a12005-01-27 16:06:23 +00002322 if (index_r == R_RSP && 0==getRexX(pfx)) {
sewardje941eea2005-01-30 19:52:28 +00002323 DIS(buf, "%s%lld(%s)", sorbTxt(pfx),
sewardj5b470602005-02-27 13:10:48 +00002324 d, nameIRegRexB(8,pfx,base_r));
sewardj2f959cc2005-01-26 01:19:35 +00002325 *len = 3;
sewardj2f959cc2005-01-26 01:19:35 +00002326 return disAMode_copy2tmp(
sewardj3ca55a12005-01-27 16:06:23 +00002327 handleSegOverride(pfx,
sewardj5b470602005-02-27 13:10:48 +00002328 binop(Iop_Add64, getIRegRexB(8,pfx,base_r), mkU64(d)) ));
sewardj2f959cc2005-01-26 01:19:35 +00002329 } else {
sewardje941eea2005-01-30 19:52:28 +00002330 if (scale == 0) {
2331 DIS(buf, "%s%lld(%s,%s)", sorbTxt(pfx), d,
sewardj5b470602005-02-27 13:10:48 +00002332 nameIRegRexB(8,pfx,base_r),
2333 nameIReg64rexX(pfx,index_r));
sewardje941eea2005-01-30 19:52:28 +00002334 } else {
2335 DIS(buf, "%s%lld(%s,%s,%d)", sorbTxt(pfx), d,
sewardj5b470602005-02-27 13:10:48 +00002336 nameIRegRexB(8,pfx,base_r),
2337 nameIReg64rexX(pfx,index_r), 1<<scale);
sewardje941eea2005-01-30 19:52:28 +00002338 }
sewardj2f959cc2005-01-26 01:19:35 +00002339 *len = 3;
sewardj2f959cc2005-01-26 01:19:35 +00002340 return
2341 disAMode_copy2tmp(
sewardj3ca55a12005-01-27 16:06:23 +00002342 handleSegOverride(pfx,
2343 binop(Iop_Add64,
2344 binop(Iop_Add64,
sewardj5b470602005-02-27 13:10:48 +00002345 getIRegRexB(8,pfx,base_r),
sewardj3ca55a12005-01-27 16:06:23 +00002346 binop(Iop_Shl64,
sewardj5b470602005-02-27 13:10:48 +00002347 getIReg64rexX(pfx,index_r), mkU8(scale))),
sewardj3ca55a12005-01-27 16:06:23 +00002348 mkU64(d))));
sewardj2f959cc2005-01-26 01:19:35 +00002349 }
sewardj3ca55a12005-01-27 16:06:23 +00002350 vassert(0); /*NOTREACHED*/
sewardj2f959cc2005-01-26 01:19:35 +00002351 }
sewardj3ca55a12005-01-27 16:06:23 +00002352
sewardj2f959cc2005-01-26 01:19:35 +00002353 /* SIB, with 32-bit displacement. Special cases:
2354 -- %rsp cannot act as an index value.
2355 If index_r indicates %rsp, zero is used for the index.
2356 Denoted value is:
2357 | %index == %RSP
2358 = d32 + %base
2359 | %index != %RSP
2360 = d32 + %base + (%index << scale)
2361 */
2362 case 0x14: {
sewardj8c332e22005-01-28 01:36:56 +00002363 UChar sib = getUChar(delta);
sewardj1027dc22005-02-26 01:55:02 +00002364 UChar scale = toUChar((sib >> 6) & 3);
2365 UChar index_r = toUChar((sib >> 3) & 7);
2366 UChar base_r = toUChar(sib & 7);
sewardj8c332e22005-01-28 01:36:56 +00002367 Long d = getSDisp32(delta+1);
sewardj2f959cc2005-01-26 01:19:35 +00002368
2369 if (index_r == R_RSP && 0==getRexX(pfx)) {
sewardje941eea2005-01-30 19:52:28 +00002370 DIS(buf, "%s%lld(%s)", sorbTxt(pfx),
sewardj5b470602005-02-27 13:10:48 +00002371 d, nameIRegRexB(8,pfx,base_r));
sewardj2f959cc2005-01-26 01:19:35 +00002372 *len = 6;
sewardj2f959cc2005-01-26 01:19:35 +00002373 return disAMode_copy2tmp(
2374 handleSegOverride(pfx,
sewardj5b470602005-02-27 13:10:48 +00002375 binop(Iop_Add64, getIRegRexB(8,pfx,base_r), mkU64(d)) ));
sewardj2f959cc2005-01-26 01:19:35 +00002376 } else {
sewardje941eea2005-01-30 19:52:28 +00002377 if (scale == 0) {
2378 DIS(buf, "%s%lld(%s,%s)", sorbTxt(pfx), d,
sewardj5b470602005-02-27 13:10:48 +00002379 nameIRegRexB(8,pfx,base_r),
2380 nameIReg64rexX(pfx,index_r));
sewardje941eea2005-01-30 19:52:28 +00002381 } else {
2382 DIS(buf, "%s%lld(%s,%s,%d)", sorbTxt(pfx), d,
sewardj5b470602005-02-27 13:10:48 +00002383 nameIRegRexB(8,pfx,base_r),
2384 nameIReg64rexX(pfx,index_r), 1<<scale);
sewardje941eea2005-01-30 19:52:28 +00002385 }
sewardj2f959cc2005-01-26 01:19:35 +00002386 *len = 6;
2387 return
2388 disAMode_copy2tmp(
2389 handleSegOverride(pfx,
2390 binop(Iop_Add64,
2391 binop(Iop_Add64,
sewardj5b470602005-02-27 13:10:48 +00002392 getIRegRexB(8,pfx,base_r),
sewardj2f959cc2005-01-26 01:19:35 +00002393 binop(Iop_Shl64,
sewardj5b470602005-02-27 13:10:48 +00002394 getIReg64rexX(pfx,index_r), mkU8(scale))),
sewardj2f959cc2005-01-26 01:19:35 +00002395 mkU64(d))));
2396 }
sewardj3ca55a12005-01-27 16:06:23 +00002397 vassert(0); /*NOTREACHED*/
sewardj2f959cc2005-01-26 01:19:35 +00002398 }
2399
sewardjb3a04292005-01-21 20:33:44 +00002400 default:
2401 vpanic("disAMode(amd64)");
2402 return 0; /*notreached*/
2403 }
2404}
2405
2406
sewardj3ca55a12005-01-27 16:06:23 +00002407/* Figure out the number of (insn-stream) bytes constituting the amode
2408 beginning at delta. Is useful for getting hold of literals beyond
2409 the end of the amode before it has been disassembled. */
2410
sewardj8c332e22005-01-28 01:36:56 +00002411static UInt lengthAMode ( Prefix pfx, ULong delta )
sewardj3ca55a12005-01-27 16:06:23 +00002412{
sewardj8c332e22005-01-28 01:36:56 +00002413 UChar mod_reg_rm = getUChar(delta);
sewardj3ca55a12005-01-27 16:06:23 +00002414 delta++;
2415
2416 /* squeeze out the reg field from mod_reg_rm, since a 256-entry
2417 jump table seems a bit excessive.
2418 */
sewardj7a240552005-01-28 21:37:12 +00002419 mod_reg_rm &= 0xC7; /* is now XX000YYY */
sewardj1027dc22005-02-26 01:55:02 +00002420 mod_reg_rm = toUChar(mod_reg_rm | (mod_reg_rm >> 3));
2421 /* is now XX0XXYYY */
sewardj7a240552005-01-28 21:37:12 +00002422 mod_reg_rm &= 0x1F; /* is now 000XXYYY */
sewardj3ca55a12005-01-27 16:06:23 +00002423 switch (mod_reg_rm) {
2424
2425 /* REX.B==0: (%rax) .. (%rdi), not including (%rsp) or (%rbp).
2426 REX.B==1: (%r8) .. (%r15), not including (%r12) or (%r13).
2427 */
2428 case 0x00: case 0x01: case 0x02: case 0x03:
2429 /* ! 04 */ /* ! 05 */ case 0x06: case 0x07:
sewardj3ca55a12005-01-27 16:06:23 +00002430 return 1;
2431
2432 /* REX.B==0: d8(%rax) ... d8(%rdi), not including d8(%rsp)
2433 REX.B==1: d8(%r8) ... d8(%r15), not including d8(%r12)
2434 */
2435 case 0x08: case 0x09: case 0x0A: case 0x0B:
2436 /* ! 0C */ case 0x0D: case 0x0E: case 0x0F:
sewardj3ca55a12005-01-27 16:06:23 +00002437 return 2;
2438
2439 /* REX.B==0: d32(%rax) ... d32(%rdi), not including d32(%rsp)
2440 REX.B==1: d32(%r8) ... d32(%r15), not including d32(%r12)
2441 */
2442 case 0x10: case 0x11: case 0x12: case 0x13:
2443 /* ! 14 */ case 0x15: case 0x16: case 0x17:
sewardj3ca55a12005-01-27 16:06:23 +00002444 return 5;
2445
2446 /* REX.B==0: a register, %rax .. %rdi. This shouldn't happen. */
2447 /* REX.B==1: a register, %r8 .. %r16. This shouldn't happen. */
2448 /* Not an address, but still handled. */
2449 case 0x18: case 0x19: case 0x1A: case 0x1B:
2450 case 0x1C: case 0x1D: case 0x1E: case 0x1F:
2451 return 1;
2452
2453 /* RIP + disp32. */
2454 case 0x05:
sewardj3ca55a12005-01-27 16:06:23 +00002455 return 5;
2456
2457 case 0x04: {
2458 /* SIB, with no displacement. */
sewardj8c332e22005-01-28 01:36:56 +00002459 UChar sib = getUChar(delta);
sewardj1027dc22005-02-26 01:55:02 +00002460 UChar base_r = toUChar(sib & 7);
sewardj3ca55a12005-01-27 16:06:23 +00002461 /* correct since #(R13) == 8 + #(RBP) */
sewardj7a240552005-01-28 21:37:12 +00002462 Bool base_is_BPor13 = toBool(base_r == R_RBP);
sewardj3ca55a12005-01-27 16:06:23 +00002463
2464 if (base_is_BPor13) {
sewardj3ca55a12005-01-27 16:06:23 +00002465 return 6;
2466 } else {
sewardj3ca55a12005-01-27 16:06:23 +00002467 return 2;
2468 }
2469 }
2470
2471 /* SIB, with 8-bit displacement. */
2472 case 0x0C:
2473 return 3;
2474
2475 /* SIB, with 32-bit displacement. */
2476 case 0x14:
2477 return 6;
2478
2479 default:
2480 vpanic("lengthAMode(amd64)");
2481 return 0; /*notreached*/
2482 }
2483}
2484
2485
sewardjdf0e0022005-01-25 15:48:43 +00002486/*------------------------------------------------------------*/
2487/*--- Disassembling common idioms ---*/
2488/*------------------------------------------------------------*/
2489
sewardjdf0e0022005-01-25 15:48:43 +00002490/* Handle binary integer instructions of the form
2491 op E, G meaning
2492 op reg-or-mem, reg
2493 Is passed the a ptr to the modRM byte, the actual operation, and the
2494 data size. Returns the address advanced completely over this
2495 instruction.
2496
2497 E(src) is reg-or-mem
2498 G(dst) is reg.
2499
2500 If E is reg, --> GET %G, tmp
2501 OP %E, tmp
2502 PUT tmp, %G
2503
2504 If E is mem and OP is not reversible,
2505 --> (getAddr E) -> tmpa
2506 LD (tmpa), tmpa
2507 GET %G, tmp2
2508 OP tmpa, tmp2
2509 PUT tmp2, %G
2510
2511 If E is mem and OP is reversible
2512 --> (getAddr E) -> tmpa
2513 LD (tmpa), tmpa
2514 OP %G, tmpa
2515 PUT tmpa, %G
2516*/
2517static
2518ULong dis_op2_E_G ( Prefix pfx,
2519 Bool addSubCarry,
2520 IROp op8,
2521 Bool keep,
2522 Int size,
2523 ULong delta0,
sewardj8c332e22005-01-28 01:36:56 +00002524 HChar* t_amd64opc )
sewardjdf0e0022005-01-25 15:48:43 +00002525{
2526 HChar dis_buf[50];
2527 Int len;
2528 IRType ty = szToITy(size);
2529 IRTemp dst1 = newTemp(ty);
2530 IRTemp src = newTemp(ty);
2531 IRTemp dst0 = newTemp(ty);
2532 UChar rm = getUChar(delta0);
2533 IRTemp addr = IRTemp_INVALID;
2534
2535 /* addSubCarry == True indicates the intended operation is
2536 add-with-carry or subtract-with-borrow. */
2537 if (addSubCarry) {
2538 vassert(op8 == Iop_Add8 || op8 == Iop_Sub8);
2539 vassert(keep);
2540 }
2541
2542 if (epartIsReg(rm)) {
sewardjdf0e0022005-01-25 15:48:43 +00002543 /* Specially handle XOR reg,reg, because that doesn't really
2544 depend on reg, and doing the obvious thing potentially
2545 generates a spurious value check failure due to the bogus
2546 dependency. */
sewardj5b470602005-02-27 13:10:48 +00002547 if ((op8 == Iop_Xor8 || (op8 == Iop_Sub8 && addSubCarry))
2548 && offsetIRegG(size,pfx,rm) == offsetIRegE(size,pfx,rm)) {
sewardj118b23e2005-01-29 02:14:44 +00002549 vassert(0); /* awaiting test case */
sewardj5b470602005-02-27 13:10:48 +00002550 if (op8 == Iop_Sub8)
2551 vex_printf("vex amd64->IR: sbb %%r,%%r optimisation(1)\n");
2552 putIRegG(size,pfx,rm, mkU(ty,0));
sewardjdf0e0022005-01-25 15:48:43 +00002553 }
sewardj5b470602005-02-27 13:10:48 +00002554
2555 assign( dst0, getIRegG(size,pfx,rm) );
2556 assign( src, getIRegE(size,pfx,rm) );
sewardjdf0e0022005-01-25 15:48:43 +00002557
2558 if (addSubCarry && op8 == Iop_Add8) {
sewardj3ca55a12005-01-27 16:06:23 +00002559 vassert(0); /* awaiting test case */
sewardjdf0e0022005-01-25 15:48:43 +00002560 helper_ADC( size, dst1, dst0, src );
sewardj5b470602005-02-27 13:10:48 +00002561 putIRegG(size, pfx, rm, mkexpr(dst1));
sewardjdf0e0022005-01-25 15:48:43 +00002562 } else
2563 if (addSubCarry && op8 == Iop_Sub8) {
sewardj3ca55a12005-01-27 16:06:23 +00002564 vassert(0); /* awaiting test case */
sewardjdf0e0022005-01-25 15:48:43 +00002565 helper_SBB( size, dst1, dst0, src );
sewardj5b470602005-02-27 13:10:48 +00002566 putIRegG(size, pfx, rm, mkexpr(dst1));
sewardjdf0e0022005-01-25 15:48:43 +00002567 } else {
2568 assign( dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
2569 if (isAddSub(op8))
2570 setFlags_DEP1_DEP2(op8, dst0, src, ty);
2571 else
2572 setFlags_DEP1(op8, dst1, ty);
2573 if (keep)
sewardj5b470602005-02-27 13:10:48 +00002574 putIRegG(size, pfx, rm, mkexpr(dst1));
sewardjdf0e0022005-01-25 15:48:43 +00002575 }
2576
2577 DIP("%s%c %s,%s\n", t_amd64opc, nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00002578 nameIRegE(size,pfx,rm),
2579 nameIRegG(size,pfx,rm));
sewardjdf0e0022005-01-25 15:48:43 +00002580 return 1+delta0;
2581 } else {
2582 /* E refers to memory */
sewardje1698952005-02-08 15:02:39 +00002583 addr = disAMode ( &len, pfx, delta0, dis_buf, 0 );
sewardj5b470602005-02-27 13:10:48 +00002584 assign( dst0, getIRegG(size,pfx,rm) );
sewardjdf0e0022005-01-25 15:48:43 +00002585 assign( src, loadLE(szToITy(size), mkexpr(addr)) );
2586
2587 if (addSubCarry && op8 == Iop_Add8) {
sewardj3ca55a12005-01-27 16:06:23 +00002588 vassert(0); /* awaiting test case */
sewardjdf0e0022005-01-25 15:48:43 +00002589 helper_ADC( size, dst1, dst0, src );
sewardj5b470602005-02-27 13:10:48 +00002590 putIRegG(size, pfx, rm, mkexpr(dst1));
sewardjdf0e0022005-01-25 15:48:43 +00002591 } else
2592 if (addSubCarry && op8 == Iop_Sub8) {
sewardj3ca55a12005-01-27 16:06:23 +00002593 vassert(0); /* awaiting test case */
sewardjdf0e0022005-01-25 15:48:43 +00002594 helper_SBB( size, dst1, dst0, src );
sewardj5b470602005-02-27 13:10:48 +00002595 putIRegG(size, pfx, rm, mkexpr(dst1));
sewardjdf0e0022005-01-25 15:48:43 +00002596 } else {
2597 assign( dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
2598 if (isAddSub(op8))
2599 setFlags_DEP1_DEP2(op8, dst0, src, ty);
2600 else
2601 setFlags_DEP1(op8, dst1, ty);
2602 if (keep)
sewardj5b470602005-02-27 13:10:48 +00002603 putIRegG(size, pfx, rm, mkexpr(dst1));
sewardjdf0e0022005-01-25 15:48:43 +00002604 }
2605
2606 DIP("%s%c %s,%s\n", t_amd64opc, nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00002607 dis_buf, nameIRegG(size, pfx, rm));
sewardjdf0e0022005-01-25 15:48:43 +00002608 return len+delta0;
2609 }
2610}
2611
2612
2613
sewardj3ca55a12005-01-27 16:06:23 +00002614/* Handle binary integer instructions of the form
2615 op G, E meaning
2616 op reg, reg-or-mem
2617 Is passed the a ptr to the modRM byte, the actual operation, and the
2618 data size. Returns the address advanced completely over this
2619 instruction.
2620
2621 G(src) is reg.
2622 E(dst) is reg-or-mem
2623
2624 If E is reg, --> GET %E, tmp
2625 OP %G, tmp
2626 PUT tmp, %E
2627
2628 If E is mem, --> (getAddr E) -> tmpa
2629 LD (tmpa), tmpv
2630 OP %G, tmpv
2631 ST tmpv, (tmpa)
2632*/
2633static
sewardj8c332e22005-01-28 01:36:56 +00002634ULong dis_op2_G_E ( Prefix pfx,
2635 Bool addSubCarry,
2636 IROp op8,
2637 Bool keep,
2638 Int size,
2639 ULong delta0,
2640 HChar* t_amd64opc )
sewardj3ca55a12005-01-27 16:06:23 +00002641{
2642 HChar dis_buf[50];
2643 Int len;
2644 IRType ty = szToITy(size);
2645 IRTemp dst1 = newTemp(ty);
2646 IRTemp src = newTemp(ty);
2647 IRTemp dst0 = newTemp(ty);
sewardj8c332e22005-01-28 01:36:56 +00002648 UChar rm = getUChar(delta0);
sewardj3ca55a12005-01-27 16:06:23 +00002649 IRTemp addr = IRTemp_INVALID;
2650
2651 /* addSubCarry == True indicates the intended operation is
2652 add-with-carry or subtract-with-borrow. */
2653 if (addSubCarry) {
2654 vassert(op8 == Iop_Add8 || op8 == Iop_Sub8);
2655 vassert(keep);
2656 }
2657
2658 if (epartIsReg(rm)) {
2659 /* Specially handle XOR reg,reg, because that doesn't really
2660 depend on reg, and doing the obvious thing potentially
2661 generates a spurious value check failure due to the bogus
sewardj5b470602005-02-27 13:10:48 +00002662 dependency. Ditto SBB reg,reg. */
2663 if ((op8 == Iop_Xor8 || (op8 == Iop_Sub8 && addSubCarry))
2664 && offsetIRegG(size,pfx,rm) == offsetIRegE(size,pfx,rm)) {
2665 putIRegE(size,pfx,rm, mkU(ty,0));
sewardj3ca55a12005-01-27 16:06:23 +00002666 }
sewardj5b470602005-02-27 13:10:48 +00002667
2668 assign(dst0, getIRegE(size,pfx,rm));
2669 assign(src, getIRegG(size,pfx,rm));
sewardj3ca55a12005-01-27 16:06:23 +00002670
2671 if (addSubCarry && op8 == Iop_Add8) {
sewardj3ca55a12005-01-27 16:06:23 +00002672 helper_ADC( size, dst1, dst0, src );
sewardj5b470602005-02-27 13:10:48 +00002673 putIRegE(size, pfx, rm, mkexpr(dst1));
sewardj3ca55a12005-01-27 16:06:23 +00002674 } else
2675 if (addSubCarry && op8 == Iop_Sub8) {
sewardj3ca55a12005-01-27 16:06:23 +00002676 helper_SBB( size, dst1, dst0, src );
sewardj5b470602005-02-27 13:10:48 +00002677 putIRegE(size, pfx, rm, mkexpr(dst1));
sewardj3ca55a12005-01-27 16:06:23 +00002678 } else {
2679 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
2680 if (isAddSub(op8))
2681 setFlags_DEP1_DEP2(op8, dst0, src, ty);
2682 else
2683 setFlags_DEP1(op8, dst1, ty);
2684 if (keep)
sewardj5b470602005-02-27 13:10:48 +00002685 putIRegE(size, pfx, rm, mkexpr(dst1));
sewardj3ca55a12005-01-27 16:06:23 +00002686 }
2687
2688 DIP("%s%c %s,%s\n", t_amd64opc, nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00002689 nameIRegG(size,pfx,rm),
2690 nameIRegE(size,pfx,rm));
sewardj3ca55a12005-01-27 16:06:23 +00002691 return 1+delta0;
2692 }
2693
2694 /* E refers to memory */
2695 {
sewardje1698952005-02-08 15:02:39 +00002696 addr = disAMode ( &len, pfx, delta0, dis_buf, 0 );
sewardj3ca55a12005-01-27 16:06:23 +00002697 assign(dst0, loadLE(ty,mkexpr(addr)));
sewardj5b470602005-02-27 13:10:48 +00002698 assign(src, getIRegG(size,pfx,rm));
sewardj3ca55a12005-01-27 16:06:23 +00002699
2700 if (addSubCarry && op8 == Iop_Add8) {
2701 vassert(0); /* awaiting test case */
2702 helper_ADC( size, dst1, dst0, src );
2703 storeLE(mkexpr(addr), mkexpr(dst1));
2704 } else
2705 if (addSubCarry && op8 == Iop_Sub8) {
2706 vassert(0); /* awaiting test case */
2707 helper_SBB( size, dst1, dst0, src );
2708 storeLE(mkexpr(addr), mkexpr(dst1));
2709 } else {
2710 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
2711 if (isAddSub(op8))
2712 setFlags_DEP1_DEP2(op8, dst0, src, ty);
2713 else
2714 setFlags_DEP1(op8, dst1, ty);
2715 if (keep)
2716 storeLE(mkexpr(addr), mkexpr(dst1));
2717 }
2718
2719 DIP("%s%c %s,%s\n", t_amd64opc, nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00002720 nameIRegG(size,pfx,rm), dis_buf);
sewardj3ca55a12005-01-27 16:06:23 +00002721 return len+delta0;
2722 }
2723}
2724
2725
sewardj1389d4d2005-01-28 13:46:29 +00002726/* Handle move instructions of the form
2727 mov E, G meaning
2728 mov reg-or-mem, reg
2729 Is passed the a ptr to the modRM byte, and the data size. Returns
2730 the address advanced completely over this instruction.
2731
2732 E(src) is reg-or-mem
2733 G(dst) is reg.
2734
2735 If E is reg, --> GET %E, tmpv
2736 PUT tmpv, %G
2737
2738 If E is mem --> (getAddr E) -> tmpa
2739 LD (tmpa), tmpb
2740 PUT tmpb, %G
2741*/
2742static
2743ULong dis_mov_E_G ( Prefix pfx,
2744 Int size,
2745 ULong delta0 )
2746{
2747 Int len;
2748 UChar rm = getUChar(delta0);
2749 HChar dis_buf[50];
2750
2751 if (epartIsReg(rm)) {
sewardj5b470602005-02-27 13:10:48 +00002752 putIRegG(size, pfx, rm, getIRegE(size, pfx, rm));
sewardje941eea2005-01-30 19:52:28 +00002753 DIP("mov%c %s,%s\n", nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00002754 nameIRegE(size,pfx,rm),
2755 nameIRegG(size,pfx,rm));
sewardj1389d4d2005-01-28 13:46:29 +00002756 return 1+delta0;
2757 }
2758
2759 /* E refers to memory */
2760 {
sewardje1698952005-02-08 15:02:39 +00002761 IRTemp addr = disAMode ( &len, pfx, delta0, dis_buf, 0 );
sewardj5b470602005-02-27 13:10:48 +00002762 putIRegG(size, pfx, rm, loadLE(szToITy(size), mkexpr(addr)));
sewardj1389d4d2005-01-28 13:46:29 +00002763 DIP("mov%c %s,%s\n", nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00002764 dis_buf,
2765 nameIRegG(size,pfx,rm));
sewardj1389d4d2005-01-28 13:46:29 +00002766 return delta0+len;
2767 }
2768}
2769
2770
2771/* Handle move instructions of the form
2772 mov G, E meaning
2773 mov reg, reg-or-mem
2774 Is passed the a ptr to the modRM byte, and the data size. Returns
2775 the address advanced completely over this instruction.
2776
2777 G(src) is reg.
2778 E(dst) is reg-or-mem
2779
2780 If E is reg, --> GET %G, tmp
2781 PUT tmp, %E
2782
2783 If E is mem, --> (getAddr E) -> tmpa
2784 GET %G, tmpv
2785 ST tmpv, (tmpa)
2786*/
2787static
2788ULong dis_mov_G_E ( Prefix pfx,
2789 Int size,
2790 ULong delta0 )
2791{
2792 Int len;
2793 UChar rm = getUChar(delta0);
2794 HChar dis_buf[50];
2795
2796 if (epartIsReg(rm)) {
sewardj5b470602005-02-27 13:10:48 +00002797 putIRegE(size, pfx, rm, getIRegG(size, pfx, rm));
sewardje941eea2005-01-30 19:52:28 +00002798 DIP("mov%c %s,%s\n", nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00002799 nameIRegG(size,pfx,rm),
2800 nameIRegE(size,pfx,rm));
sewardj1389d4d2005-01-28 13:46:29 +00002801 return 1+delta0;
2802 }
2803
2804 /* E refers to memory */
2805 {
sewardje1698952005-02-08 15:02:39 +00002806 IRTemp addr = disAMode ( &len, pfx, delta0, dis_buf, 0 );
sewardj5b470602005-02-27 13:10:48 +00002807 storeLE( mkexpr(addr), getIRegG(size, pfx, rm) );
sewardj1389d4d2005-01-28 13:46:29 +00002808 DIP("mov%c %s,%s\n", nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00002809 nameIRegG(size,pfx,rm),
2810 dis_buf);
sewardj1389d4d2005-01-28 13:46:29 +00002811 return len+delta0;
2812 }
2813}
sewardj3ca55a12005-01-27 16:06:23 +00002814
2815
2816/* op $immediate, AL/AX/EAX/RAX. */
2817static
sewardj8c332e22005-01-28 01:36:56 +00002818ULong dis_op_imm_A ( Int size,
2819 IROp op8,
2820 Bool keep,
2821 ULong delta,
2822 HChar* t_amd64opc )
sewardj3ca55a12005-01-27 16:06:23 +00002823{
2824 Int size4 = imin(size,4);
2825 IRType ty = szToITy(size);
2826 IRTemp dst0 = newTemp(ty);
2827 IRTemp src = newTemp(ty);
2828 IRTemp dst1 = newTemp(ty);
sewardj8c332e22005-01-28 01:36:56 +00002829 Long lit = getSDisp(size4,delta);
sewardj5b470602005-02-27 13:10:48 +00002830 assign(dst0, getIRegRAX(size));
sewardj1389d4d2005-01-28 13:46:29 +00002831 assign(src, mkU(ty,lit & mkSizeMask(size)));
sewardj3ca55a12005-01-27 16:06:23 +00002832 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
2833 if (isAddSub(op8))
2834 setFlags_DEP1_DEP2(op8, dst0, src, ty);
2835 else
2836 if (isLogic(op8))
2837 setFlags_DEP1(op8, dst1, ty);
2838 else
2839 vpanic("dis_op_imm_A(amd64)");
2840
2841 if (keep)
sewardj5b470602005-02-27 13:10:48 +00002842 putIRegRAX(size, mkexpr(dst1));
sewardj3ca55a12005-01-27 16:06:23 +00002843
2844 DIP("%s%c $%lld, %s\n", t_amd64opc, nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00002845 lit, nameIRegRAX(size));
sewardj3ca55a12005-01-27 16:06:23 +00002846 return delta+size4;
2847}
2848
2849
sewardj5e525292005-01-28 15:13:10 +00002850/* Sign- and Zero-extending moves. */
2851static
2852ULong dis_movx_E_G ( Prefix pfx,
2853 ULong delta, Int szs, Int szd, Bool sign_extend )
2854{
2855 UChar rm = getUChar(delta);
2856 if (epartIsReg(rm)) {
sewardj5b470602005-02-27 13:10:48 +00002857 putIRegG(szd, pfx, rm,
sewardj5e525292005-01-28 15:13:10 +00002858 doScalarWidening(
2859 szs,szd,sign_extend,
sewardj5b470602005-02-27 13:10:48 +00002860 getIRegE(szs,pfx,rm)));
sewardj5e525292005-01-28 15:13:10 +00002861 DIP("mov%c%c%c %s,%s\n", sign_extend ? 's' : 'z',
2862 nameISize(szs),
2863 nameISize(szd),
sewardj5b470602005-02-27 13:10:48 +00002864 nameIRegE(szs,pfx,rm),
2865 nameIRegG(szd,pfx,rm));
sewardj5e525292005-01-28 15:13:10 +00002866 return 1+delta;
2867 }
2868
2869 /* E refers to memory */
2870 {
2871 Int len;
2872 HChar dis_buf[50];
sewardje1698952005-02-08 15:02:39 +00002873 IRTemp addr = disAMode ( &len, pfx, delta, dis_buf, 0 );
sewardj5b470602005-02-27 13:10:48 +00002874 putIRegG(szd, pfx, rm,
sewardj5e525292005-01-28 15:13:10 +00002875 doScalarWidening(
2876 szs,szd,sign_extend,
2877 loadLE(szToITy(szs),mkexpr(addr))));
2878 DIP("mov%c%c%c %s,%s\n", sign_extend ? 's' : 'z',
2879 nameISize(szs),
2880 nameISize(szd),
2881 dis_buf,
sewardj5b470602005-02-27 13:10:48 +00002882 nameIRegG(szd,pfx,rm));
sewardj5e525292005-01-28 15:13:10 +00002883 return len+delta;
2884 }
2885}
sewardj32b2bbe2005-01-28 00:50:10 +00002886
2887
sewardj03b07cc2005-01-31 18:09:43 +00002888/* Generate code to divide ArchRegs RDX:RAX / EDX:EAX / DX:AX / AX by
2889 the 64 / 32 / 16 / 8 bit quantity in the given IRTemp. */
sewardj32b2bbe2005-01-28 00:50:10 +00002890static
2891void codegen_div ( Int sz, IRTemp t, Bool signed_divide )
2892{
sewardj03b07cc2005-01-31 18:09:43 +00002893 /* special-case the 64-bit case */
2894 if (sz == 8) {
2895 IROp op = signed_divide ? Iop_DivModS128to64
2896 : Iop_DivModU128to64;
sewardja6b93d12005-02-17 09:28:28 +00002897 IRTemp src128 = newTemp(Ity_I128);
2898 IRTemp dst128 = newTemp(Ity_I128);
sewardj03b07cc2005-01-31 18:09:43 +00002899 assign( src128, binop(Iop_64HLto128,
sewardja6b93d12005-02-17 09:28:28 +00002900 getIReg64(R_RDX),
2901 getIReg64(R_RAX)) );
sewardj03b07cc2005-01-31 18:09:43 +00002902 assign( dst128, binop(op, mkexpr(src128), mkexpr(t)) );
sewardja6b93d12005-02-17 09:28:28 +00002903 putIReg64( R_RAX, unop(Iop_128to64,mkexpr(dst128)) );
2904 putIReg64( R_RDX, unop(Iop_128HIto64,mkexpr(dst128)) );
sewardj03b07cc2005-01-31 18:09:43 +00002905 } else {
2906 IROp op = signed_divide ? Iop_DivModS64to32
2907 : Iop_DivModU64to32;
2908 IRTemp src64 = newTemp(Ity_I64);
2909 IRTemp dst64 = newTemp(Ity_I64);
2910 switch (sz) {
sewardj85520e42005-02-19 15:22:38 +00002911 case 4:
sewardj5b470602005-02-27 13:10:48 +00002912 assign( src64,
2913 binop(Iop_32HLto64, getIRegRDX(4), getIRegRAX(4)) );
2914 assign( dst64,
2915 binop(op, mkexpr(src64), mkexpr(t)) );
2916 putIRegRAX( 4, unop(Iop_64to32,mkexpr(dst64)) );
2917 putIRegRDX( 4, unop(Iop_64HIto32,mkexpr(dst64)) );
sewardj85520e42005-02-19 15:22:38 +00002918 break;
2919 case 2: {
2920 IROp widen3264 = signed_divide ? Iop_32Sto64 : Iop_32Uto64;
2921 IROp widen1632 = signed_divide ? Iop_16Sto32 : Iop_16Uto32;
2922 assign( src64, unop(widen3264,
2923 binop(Iop_16HLto32,
sewardj5b470602005-02-27 13:10:48 +00002924 getIRegRDX(2),
2925 getIRegRAX(2))) );
sewardj85520e42005-02-19 15:22:38 +00002926 assign( dst64, binop(op, mkexpr(src64), unop(widen1632,mkexpr(t))) );
sewardj5b470602005-02-27 13:10:48 +00002927 putIRegRAX( 2, unop(Iop_32to16,unop(Iop_64to32,mkexpr(dst64))) );
2928 putIRegRDX( 2, unop(Iop_32to16,unop(Iop_64HIto32,mkexpr(dst64))) );
sewardj85520e42005-02-19 15:22:38 +00002929 break;
2930 }
2931 case 1: {
2932 IROp widen3264 = signed_divide ? Iop_32Sto64 : Iop_32Uto64;
2933 IROp widen1632 = signed_divide ? Iop_16Sto32 : Iop_16Uto32;
2934 IROp widen816 = signed_divide ? Iop_8Sto16 : Iop_8Uto16;
2935 assign( src64, unop(widen3264,
sewardj5b470602005-02-27 13:10:48 +00002936 unop(widen1632, getIRegRAX(2))) );
sewardj85520e42005-02-19 15:22:38 +00002937 assign( dst64,
2938 binop(op, mkexpr(src64),
2939 unop(widen1632, unop(widen816, mkexpr(t)))) );
sewardj5b470602005-02-27 13:10:48 +00002940 putIRegRAX( 1, unop(Iop_16to8,
2941 unop(Iop_32to16,
2942 unop(Iop_64to32,mkexpr(dst64)))) );
2943 putIRegAH( unop(Iop_16to8,
2944 unop(Iop_32to16,
2945 unop(Iop_64HIto32,mkexpr(dst64)))) );
sewardj85520e42005-02-19 15:22:38 +00002946 break;
2947 }
2948 default:
2949 vpanic("codegen_div(amd64)");
sewardj03b07cc2005-01-31 18:09:43 +00002950 }
sewardj32b2bbe2005-01-28 00:50:10 +00002951 }
2952}
sewardj3ca55a12005-01-27 16:06:23 +00002953
2954static
sewardj8c332e22005-01-28 01:36:56 +00002955ULong dis_Grp1 ( Prefix pfx,
2956 ULong delta, UChar modrm,
sewardj227458e2005-01-31 19:04:50 +00002957 Int am_sz, Int d_sz, Int sz, Long d64 )
sewardj3ca55a12005-01-27 16:06:23 +00002958{
2959 Int len;
2960 HChar dis_buf[50];
2961 IRType ty = szToITy(sz);
2962 IRTemp dst1 = newTemp(ty);
2963 IRTemp src = newTemp(ty);
2964 IRTemp dst0 = newTemp(ty);
2965 IRTemp addr = IRTemp_INVALID;
2966 IROp op8 = Iop_INVALID;
sewardj1389d4d2005-01-28 13:46:29 +00002967 ULong mask = mkSizeMask(sz);
sewardj3ca55a12005-01-27 16:06:23 +00002968
sewardj901ed122005-02-27 13:25:31 +00002969 switch (gregLO3ofRM(modrm)) {
sewardj3ca55a12005-01-27 16:06:23 +00002970 case 0: op8 = Iop_Add8; break; case 1: op8 = Iop_Or8; break;
2971 case 2: break; // ADC
2972 case 3: break; // SBB
2973 case 4: op8 = Iop_And8; break; case 5: op8 = Iop_Sub8; break;
2974 case 6: op8 = Iop_Xor8; break; case 7: op8 = Iop_Sub8; break;
2975 default: vpanic("dis_Grp1(amd64): unhandled case");
2976 }
2977
2978 if (epartIsReg(modrm)) {
2979 vassert(am_sz == 1);
2980
sewardj5b470602005-02-27 13:10:48 +00002981 assign(dst0, getIRegE(sz,pfx,modrm));
sewardj227458e2005-01-31 19:04:50 +00002982 assign(src, mkU(ty,d64 & mask));
sewardj3ca55a12005-01-27 16:06:23 +00002983
sewardj901ed122005-02-27 13:25:31 +00002984 if (gregLO3ofRM(modrm) == 2 /* ADC */) {
sewardj3ca55a12005-01-27 16:06:23 +00002985 vassert(0); /* awaiting test case */
2986 helper_ADC( sz, dst1, dst0, src );
2987 } else
sewardj901ed122005-02-27 13:25:31 +00002988 if (gregLO3ofRM(modrm) == 3 /* SBB */) {
sewardj3ca55a12005-01-27 16:06:23 +00002989 helper_SBB( sz, dst1, dst0, src );
2990 } else {
2991 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
2992 if (isAddSub(op8))
2993 setFlags_DEP1_DEP2(op8, dst0, src, ty);
2994 else
2995 setFlags_DEP1(op8, dst1, ty);
2996 }
2997
sewardj901ed122005-02-27 13:25:31 +00002998 if (gregLO3ofRM(modrm) < 7)
sewardj5b470602005-02-27 13:10:48 +00002999 putIRegE(sz, pfx, modrm, mkexpr(dst1));
sewardj3ca55a12005-01-27 16:06:23 +00003000
3001 delta += (am_sz + d_sz);
sewardje941eea2005-01-30 19:52:28 +00003002 DIP("%s%c $%lld, %s\n",
sewardj901ed122005-02-27 13:25:31 +00003003 nameGrp1(gregLO3ofRM(modrm)), nameISize(sz), d64,
sewardj5b470602005-02-27 13:10:48 +00003004 nameIRegE(sz,pfx,modrm));
sewardj3ca55a12005-01-27 16:06:23 +00003005 } else {
sewardje1698952005-02-08 15:02:39 +00003006 addr = disAMode ( &len, pfx, delta, dis_buf, /*xtra*/d_sz );
sewardj3ca55a12005-01-27 16:06:23 +00003007
3008 assign(dst0, loadLE(ty,mkexpr(addr)));
sewardj227458e2005-01-31 19:04:50 +00003009 assign(src, mkU(ty,d64 & mask));
sewardj3ca55a12005-01-27 16:06:23 +00003010
sewardj901ed122005-02-27 13:25:31 +00003011 if (gregLO3ofRM(modrm) == 2 /* ADC */) {
sewardj3ca55a12005-01-27 16:06:23 +00003012 vassert(0); /* awaiting test case */
3013 helper_ADC( sz, dst1, dst0, src );
3014 } else
sewardj901ed122005-02-27 13:25:31 +00003015 if (gregLO3ofRM(modrm) == 3 /* SBB */) {
sewardj3ca55a12005-01-27 16:06:23 +00003016 vassert(0); /* awaiting test case */
3017 helper_SBB( sz, dst1, dst0, src );
3018 } else {
3019 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
3020 if (isAddSub(op8))
3021 setFlags_DEP1_DEP2(op8, dst0, src, ty);
3022 else
3023 setFlags_DEP1(op8, dst1, ty);
3024 }
3025
sewardj901ed122005-02-27 13:25:31 +00003026 if (gregLO3ofRM(modrm) < 7)
sewardj3ca55a12005-01-27 16:06:23 +00003027 storeLE(mkexpr(addr), mkexpr(dst1));
3028
3029 delta += (len+d_sz);
sewardje941eea2005-01-30 19:52:28 +00003030 DIP("%s%c $%lld, %s\n",
sewardj901ed122005-02-27 13:25:31 +00003031 nameGrp1(gregLO3ofRM(modrm)), nameISize(sz),
sewardj227458e2005-01-31 19:04:50 +00003032 d64, dis_buf);
sewardj3ca55a12005-01-27 16:06:23 +00003033 }
3034 return delta;
3035}
3036
3037
sewardj118b23e2005-01-29 02:14:44 +00003038/* Group 2 extended opcodes. shift_expr must be an 8-bit typed
3039 expression. */
3040
3041static
3042ULong dis_Grp2 ( Prefix pfx,
3043 ULong delta, UChar modrm,
3044 Int am_sz, Int d_sz, Int sz, IRExpr* shift_expr,
3045 HChar* shift_expr_txt )
3046{
3047 /* delta on entry points at the modrm byte. */
3048 HChar dis_buf[50];
3049 Int len;
3050 Bool isShift, isRotate, isRotateRC;
3051 IRType ty = szToITy(sz);
3052 IRTemp dst0 = newTemp(ty);
3053 IRTemp dst1 = newTemp(ty);
3054 IRTemp addr = IRTemp_INVALID;
3055
3056 vassert(sz == 1 || sz == 2 || sz == 4 || sz == 8);
3057
3058 /* Put value to shift/rotate in dst0. */
3059 if (epartIsReg(modrm)) {
sewardj5b470602005-02-27 13:10:48 +00003060 assign(dst0, getIRegE(sz, pfx, modrm));
sewardj118b23e2005-01-29 02:14:44 +00003061 delta += (am_sz + d_sz);
3062 } else {
sewardje1698952005-02-08 15:02:39 +00003063 addr = disAMode ( &len, pfx, delta, dis_buf, 0 );
sewardj118b23e2005-01-29 02:14:44 +00003064 assign(dst0, loadLE(ty,mkexpr(addr)));
3065 delta += len + d_sz;
3066 }
3067
3068 isShift = False;
sewardj901ed122005-02-27 13:25:31 +00003069 switch (gregLO3ofRM(modrm)) { case 4: case 5: case 7: isShift = True; }
sewardj118b23e2005-01-29 02:14:44 +00003070
3071 isRotate = False;
sewardj901ed122005-02-27 13:25:31 +00003072 switch (gregLO3ofRM(modrm)) { case 0: case 1: isRotate = True; }
sewardj118b23e2005-01-29 02:14:44 +00003073
sewardj901ed122005-02-27 13:25:31 +00003074 isRotateRC = toBool(gregLO3ofRM(modrm) == 3);
sewardj118b23e2005-01-29 02:14:44 +00003075
3076 if (!isShift && !isRotate && !isRotateRC) {
sewardj901ed122005-02-27 13:25:31 +00003077 vex_printf("\ncase %d\n", gregLO3ofRM(modrm));
sewardj118b23e2005-01-29 02:14:44 +00003078 vpanic("dis_Grp2(Reg): unhandled case(amd64)");
3079 }
3080
3081 if (isRotateRC) {
sewardj85520e42005-02-19 15:22:38 +00003082 vpanic("dis_Grp2(Reg,amd64): unhandled case(RotateRC)");
sewardj118b23e2005-01-29 02:14:44 +00003083 vassert(0);
sewardjd20c8852005-01-20 20:04:07 +00003084//.. /* call a helper; this insn is so ridiculous it does not deserve
3085//.. better */
3086//.. IRTemp r64 = newTemp(Ity_I64);
3087//.. IRExpr** args
3088//.. = mkIRExprVec_4( widenUto32(mkexpr(dst0)), /* thing to rotate */
3089//.. widenUto32(shift_expr), /* rotate amount */
3090//.. widenUto32(mk_x86g_calculate_eflags_all()),
3091//.. mkU32(sz) );
3092//.. assign( r64, mkIRExprCCall(
3093//.. Ity_I64,
3094//.. 0/*regparm*/,
3095//.. "x86g_calculate_RCR", &x86g_calculate_RCR,
3096//.. args
3097//.. )
3098//.. );
3099//.. /* new eflags in hi half r64; new value in lo half r64 */
3100//.. assign( dst1, narrowTo(ty, unop(Iop_64to32, mkexpr(r64))) );
3101//.. stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
3102//.. stmt( IRStmt_Put( OFFB_CC_DEP1, unop(Iop_64HIto32, mkexpr(r64)) ));
3103//.. stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
sewardj118b23e2005-01-29 02:14:44 +00003104 }
3105
3106 if (isShift) {
3107
3108 IRTemp pre64 = newTemp(Ity_I64);
3109 IRTemp res64 = newTemp(Ity_I64);
3110 IRTemp res64ss = newTemp(Ity_I64);
3111 IRTemp shift_amt = newTemp(Ity_I8);
sewardj1027dc22005-02-26 01:55:02 +00003112 UChar mask = toUChar(sz==8 ? 63 : 31);
sewardj118b23e2005-01-29 02:14:44 +00003113 IROp op64;
3114
sewardj901ed122005-02-27 13:25:31 +00003115 switch (gregLO3ofRM(modrm)) {
sewardj118b23e2005-01-29 02:14:44 +00003116 case 4: op64 = Iop_Shl64; break;
3117 case 5: op64 = Iop_Shr64; break;
3118 case 7: op64 = Iop_Sar64; break;
3119 default: vpanic("dis_Grp2:shift"); break;
3120 }
3121
3122 /* Widen the value to be shifted to 64 bits, do the shift, and
3123 narrow back down. This seems surprisingly long-winded, but
3124 unfortunately the AMD semantics requires that 8/16/32-bit
3125 shifts give defined results for shift values all the way up
sewardj03c96e82005-02-19 18:12:45 +00003126 to 32, and this seems the simplest way to do it. It has the
sewardj118b23e2005-01-29 02:14:44 +00003127 advantage that the only IR level shifts generated are of 64
3128 bit values, and the shift amount is guaranteed to be in the
3129 range 0 .. 63, thereby observing the IR semantics requiring
sewardj03c96e82005-02-19 18:12:45 +00003130 all shift values to be in the range 0 .. 2^word_size-1.
sewardj118b23e2005-01-29 02:14:44 +00003131
sewardj03c96e82005-02-19 18:12:45 +00003132 Therefore the shift amount is masked with 63 for 64-bit shifts
3133 and 31 for all others.
3134 */
3135 /* shift_amt = shift_expr & MASK, regardless of operation size */
3136 assign( shift_amt, binop(Iop_And8, shift_expr, mkU8(mask)) );
sewardj118b23e2005-01-29 02:14:44 +00003137
sewardj03c96e82005-02-19 18:12:45 +00003138 /* suitably widen the value to be shifted to 64 bits. */
sewardj118b23e2005-01-29 02:14:44 +00003139 assign( pre64, op64==Iop_Sar64 ? widenSto64(mkexpr(dst0))
3140 : widenUto64(mkexpr(dst0)) );
3141
3142 /* res64 = pre64 `shift` shift_amt */
3143 assign( res64, binop(op64, mkexpr(pre64), mkexpr(shift_amt)) );
3144
sewardj03c96e82005-02-19 18:12:45 +00003145 /* res64ss = pre64 `shift` ((shift_amt - 1) & MASK) */
sewardj118b23e2005-01-29 02:14:44 +00003146 assign( res64ss,
3147 binop(op64,
3148 mkexpr(pre64),
3149 binop(Iop_And8,
3150 binop(Iop_Sub8,
3151 mkexpr(shift_amt), mkU8(1)),
sewardj03c96e82005-02-19 18:12:45 +00003152 mkU8(mask))) );
sewardj118b23e2005-01-29 02:14:44 +00003153
3154 /* Build the flags thunk. */
3155 setFlags_DEP1_DEP2_shift(op64, res64, res64ss, ty, shift_amt);
3156
3157 /* Narrow the result back down. */
3158 assign( dst1, narrowTo(ty, mkexpr(res64)) );
3159
3160 } /* if (isShift) */
3161
3162 else
3163 if (isRotate) {
3164 Int ccOp = ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1
3165 : (ty==Ity_I32 ? 2 : 3));
sewardj901ed122005-02-27 13:25:31 +00003166 Bool left = toBool(gregLO3ofRM(modrm) == 0);
sewardj118b23e2005-01-29 02:14:44 +00003167 IRTemp rot_amt = newTemp(Ity_I8);
3168 IRTemp rot_amt64 = newTemp(Ity_I8);
3169 IRTemp oldFlags = newTemp(Ity_I64);
sewardj1027dc22005-02-26 01:55:02 +00003170 UChar mask = toUChar(sz==8 ? 63 : 31);
sewardj118b23e2005-01-29 02:14:44 +00003171
3172 /* rot_amt = shift_expr & mask */
3173 /* By masking the rotate amount thusly, the IR-level Shl/Shr
3174 expressions never shift beyond the word size and thus remain
3175 well defined. */
sewardj03c96e82005-02-19 18:12:45 +00003176 assign(rot_amt64, binop(Iop_And8, shift_expr, mkU8(mask)));
sewardj118b23e2005-01-29 02:14:44 +00003177
3178 if (ty == Ity_I64)
3179 assign(rot_amt, mkexpr(rot_amt64));
3180 else
3181 assign(rot_amt, binop(Iop_And8, mkexpr(rot_amt64), mkU8(8*sz-1)));
3182
3183 if (left) {
3184
3185 /* dst1 = (dst0 << rot_amt) | (dst0 >>u (wordsize-rot_amt)) */
3186 assign(dst1,
3187 binop( mkSizedOp(ty,Iop_Or8),
3188 binop( mkSizedOp(ty,Iop_Shl8),
3189 mkexpr(dst0),
3190 mkexpr(rot_amt)
3191 ),
3192 binop( mkSizedOp(ty,Iop_Shr8),
3193 mkexpr(dst0),
3194 binop(Iop_Sub8,mkU8(8*sz), mkexpr(rot_amt))
3195 )
3196 )
3197 );
3198 ccOp += AMD64G_CC_OP_ROLB;
3199
3200 } else { /* right */
3201
3202 /* dst1 = (dst0 >>u rot_amt) | (dst0 << (wordsize-rot_amt)) */
3203 assign(dst1,
3204 binop( mkSizedOp(ty,Iop_Or8),
3205 binop( mkSizedOp(ty,Iop_Shr8),
3206 mkexpr(dst0),
3207 mkexpr(rot_amt)
3208 ),
3209 binop( mkSizedOp(ty,Iop_Shl8),
3210 mkexpr(dst0),
3211 binop(Iop_Sub8,mkU8(8*sz), mkexpr(rot_amt))
3212 )
3213 )
3214 );
3215 ccOp += AMD64G_CC_OP_RORB;
3216
3217 }
3218
3219 /* dst1 now holds the rotated value. Build flag thunk. We
3220 need the resulting value for this, and the previous flags.
3221 Except don't set it if the rotate count is zero. */
3222
3223 assign(oldFlags, mk_amd64g_calculate_rflags_all());
3224
3225 /* CC_DEP1 is the rotated value. CC_NDEP is flags before. */
3226 stmt( IRStmt_Put( OFFB_CC_OP,
3227 IRExpr_Mux0X( mkexpr(rot_amt64),
3228 IRExpr_Get(OFFB_CC_OP,Ity_I64),
3229 mkU64(ccOp))) );
3230 stmt( IRStmt_Put( OFFB_CC_DEP1,
3231 IRExpr_Mux0X( mkexpr(rot_amt64),
3232 IRExpr_Get(OFFB_CC_DEP1,Ity_I64),
3233 widenUto64(mkexpr(dst1)))) );
3234 stmt( IRStmt_Put( OFFB_CC_DEP2,
3235 IRExpr_Mux0X( mkexpr(rot_amt64),
3236 IRExpr_Get(OFFB_CC_DEP2,Ity_I64),
3237 mkU64(0))) );
3238 stmt( IRStmt_Put( OFFB_CC_NDEP,
3239 IRExpr_Mux0X( mkexpr(rot_amt64),
3240 IRExpr_Get(OFFB_CC_NDEP,Ity_I64),
3241 mkexpr(oldFlags))) );
3242 } /* if (isRotate) */
3243
3244 /* Save result, and finish up. */
3245 if (epartIsReg(modrm)) {
sewardj5b470602005-02-27 13:10:48 +00003246 putIRegE(sz, pfx, modrm, mkexpr(dst1));
sewardj118b23e2005-01-29 02:14:44 +00003247 if (vex_traceflags & VEX_TRACE_FE) {
3248 vex_printf("%s%c ",
sewardj901ed122005-02-27 13:25:31 +00003249 nameGrp2(gregLO3ofRM(modrm)), nameISize(sz) );
sewardj118b23e2005-01-29 02:14:44 +00003250 if (shift_expr_txt)
3251 vex_printf("%s", shift_expr_txt);
3252 else
3253 ppIRExpr(shift_expr);
sewardj5b470602005-02-27 13:10:48 +00003254 vex_printf(", %s\n", nameIRegE(sz,pfx,modrm));
sewardj118b23e2005-01-29 02:14:44 +00003255 }
3256 } else {
3257 storeLE(mkexpr(addr), mkexpr(dst1));
3258 if (vex_traceflags & VEX_TRACE_FE) {
3259 vex_printf("%s%c ",
sewardj901ed122005-02-27 13:25:31 +00003260 nameGrp2(gregLO3ofRM(modrm)), nameISize(sz) );
sewardj118b23e2005-01-29 02:14:44 +00003261 if (shift_expr_txt)
3262 vex_printf("%s", shift_expr_txt);
3263 else
3264 ppIRExpr(shift_expr);
3265 vex_printf(", %s\n", dis_buf);
3266 }
3267 }
3268 return delta;
3269}
3270
3271
3272
sewardjd20c8852005-01-20 20:04:07 +00003273//.. //-- /* Group 8 extended opcodes (but BT/BTS/BTC/BTR only). */
3274//.. //-- static
3275//.. //-- Addr dis_Grp8_BT ( UCodeBlock* cb,
3276//.. //-- UChar sorb,
3277//.. //-- Addr eip, UChar modrm,
3278//.. //-- Int am_sz, Int sz, UInt src_val )
3279//.. //-- {
3280//.. # define MODIFY_t2_AND_SET_CARRY_FLAG \
3281//.. /* t2 is the value to be op'd on. Copy to t_fetched, then \
3282//.. modify t2, if non-BT. */ \
3283//.. uInstr2(cb, MOV, 4, TempReg, t2, TempReg, t_fetched); \
3284//.. uInstr2(cb, MOV, sz, Literal, 0, TempReg, t_mask); \
3285//.. uLiteral(cb, v_mask); \
3286//.. switch (gregOfRM(modrm)) { \
3287//.. case 4: /* BT */ break; \
3288//.. case 5: /* BTS */ \
3289//.. uInstr2(cb, OR, sz, TempReg, t_mask, TempReg, t2); break; \
3290//.. case 6: /* BTR */ \
3291//.. uInstr2(cb, AND, sz, TempReg, t_mask, TempReg, t2); break; \
3292//.. case 7: /* BTC */ \
3293//.. uInstr2(cb, XOR, sz, TempReg, t_mask, TempReg, t2); break; \
3294//.. } \
3295//.. /* Copy relevant bit from t_fetched into carry flag. */ \
3296//.. uInstr2(cb, SHR, sz, Literal, 0, TempReg, t_fetched); \
3297//.. uLiteral(cb, src_val); \
3298//.. uInstr2(cb, MOV, sz, Literal, 0, TempReg, t_mask); \
3299//.. uLiteral(cb, 1); \
3300//.. uInstr2(cb, AND, sz, TempReg, t_mask, TempReg, t_fetched); \
3301//.. uInstr1(cb, NEG, sz, TempReg, t_fetched); \
3302//.. setFlagsFromUOpcode(cb, NEG);
3303//..
3304//..
3305//-- /* src_val denotes a d8.
3306//-- And eip on entry points at the modrm byte. */
3307//-- Int t1, t2, t_fetched, t_mask;
3308//-- UInt pair;
3309//-- HChar dis_buf[50];
3310//-- UInt v_mask;
3311//--
3312//-- /* There is no 1-byte form of this instruction, AFAICS. */
3313//-- vg_assert(sz == 2 || sz == 4);
3314//--
3315//-- /* Limit src_val -- the bit offset -- to something within a word.
3316//-- The Intel docs say that literal offsets larger than a word are
3317//-- masked in this way. */
3318//-- switch (sz) {
3319//-- case 2: src_val &= 15; break;
3320//-- case 4: src_val &= 31; break;
3321//-- default: VG_(core_panic)("dis_Grp8_BT: invalid size");
3322//-- }
3323//--
3324//-- /* Invent a mask suitable for the operation. */
3325//--
3326//-- switch (gregOfRM(modrm)) {
3327//-- case 4: /* BT */ v_mask = 0; break;
3328//-- case 5: /* BTS */ v_mask = 1 << src_val; break;
3329//-- case 6: /* BTR */ v_mask = ~(1 << src_val); break;
3330//-- case 7: /* BTC */ v_mask = 1 << src_val; break;
3331//-- /* If this needs to be extended, probably simplest to make a
3332//-- new function to handle the other cases (0 .. 3). The
3333//-- Intel docs do however not indicate any use for 0 .. 3, so
3334//-- we don't expect this to happen. */
3335//-- default: VG_(core_panic)("dis_Grp8_BT");
3336//-- }
3337//-- /* Probably excessively paranoid. */
3338//-- if (sz == 2)
3339//-- v_mask &= 0x0000FFFF;
3340//--
3341//-- t1 = INVALID_TEMPREG;
3342//-- t_fetched = newTemp(cb);
3343//-- t_mask = newTemp(cb);
3344//--
3345//-- if (epartIsReg(modrm)) {
3346//-- vg_assert(am_sz == 1);
3347//-- t2 = newTemp(cb);
3348//--
3349//-- /* Fetch the value to be tested and modified. */
3350//-- uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t2);
3351//-- /* Do it! */
3352//-- MODIFY_t2_AND_SET_CARRY_FLAG;
3353//-- /* Dump the result back, if non-BT. */
3354//-- if (gregOfRM(modrm) != 4 /* BT */)
3355//-- uInstr2(cb, PUT, sz, TempReg, t2, ArchReg, eregOfRM(modrm));
3356//--
3357//-- eip += (am_sz + 1);
3358//-- DIP("%s%c $0x%x, %s\n", nameGrp8(gregOfRM(modrm)), nameISize(sz),
3359//-- src_val, nameIReg(sz,eregOfRM(modrm)));
3360//-- } else {
3361//-- pair = disAMode ( cb, sorb, eip, dis_buf);
3362//-- t1 = LOW24(pair);
3363//-- t2 = newTemp(cb);
3364//-- eip += HI8(pair);
3365//-- eip += 1;
3366//--
3367//-- /* Fetch the value to be tested and modified. */
3368//-- uInstr2(cb, LOAD, sz, TempReg, t1, TempReg, t2);
3369//-- /* Do it! */
3370//-- MODIFY_t2_AND_SET_CARRY_FLAG;
3371//-- /* Dump the result back, if non-BT. */
3372//-- if (gregOfRM(modrm) != 4 /* BT */) {
3373//-- uInstr2(cb, STORE, sz, TempReg, t2, TempReg, t1);
3374//-- }
3375//-- DIP("%s%c $0x%x, %s\n", nameGrp8(gregOfRM(modrm)), nameISize(sz),
3376//-- src_val, dis_buf);
3377//-- }
3378//-- return eip;
3379//--
3380//-- # undef MODIFY_t2_AND_SET_CARRY_FLAG
3381//-- }
sewardj9b967672005-02-08 11:13:09 +00003382
3383
3384
3385/* Signed/unsigned widening multiply. Generate IR to multiply the
3386 value in RAX/EAX/AX/AL by the given IRTemp, and park the result in
3387 RDX:RAX/EDX:EAX/DX:AX/AX.
3388*/
3389static void codegen_mulL_A_D ( Int sz, Bool syned,
sewardj1027dc22005-02-26 01:55:02 +00003390 IRTemp tmp, HChar* tmp_txt )
sewardj9b967672005-02-08 11:13:09 +00003391{
3392 IRType ty = szToITy(sz);
3393 IRTemp t1 = newTemp(ty);
3394
sewardj5b470602005-02-27 13:10:48 +00003395 assign( t1, getIRegRAX(sz) );
sewardj9b967672005-02-08 11:13:09 +00003396
3397 switch (ty) {
3398 case Ity_I64: {
3399 IRTemp res128 = newTemp(Ity_I128);
3400 IRTemp resHi = newTemp(Ity_I64);
3401 IRTemp resLo = newTemp(Ity_I64);
3402 IROp mulOp = syned ? Iop_MullS64 : Iop_MullU64;
3403 UInt tBaseOp = syned ? AMD64G_CC_OP_SMULQ : AMD64G_CC_OP_UMULQ;
3404 setFlags_MUL ( Ity_I64, t1, tmp, tBaseOp );
3405 assign( res128, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
3406 assign( resHi, unop(Iop_128HIto64,mkexpr(res128)));
3407 assign( resLo, unop(Iop_128to64,mkexpr(res128)));
sewardj5b470602005-02-27 13:10:48 +00003408 putIReg64(R_RDX, mkexpr(resHi));
3409 putIReg64(R_RAX, mkexpr(resLo));
sewardj9b967672005-02-08 11:13:09 +00003410 break;
3411 }
sewardj85520e42005-02-19 15:22:38 +00003412 case Ity_I32: {
3413 IRTemp res64 = newTemp(Ity_I64);
3414 IRTemp resHi = newTemp(Ity_I32);
3415 IRTemp resLo = newTemp(Ity_I32);
3416 IROp mulOp = syned ? Iop_MullS32 : Iop_MullU32;
3417 UInt tBaseOp = syned ? AMD64G_CC_OP_SMULB : AMD64G_CC_OP_UMULB;
3418 setFlags_MUL ( Ity_I32, t1, tmp, tBaseOp );
3419 assign( res64, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
3420 assign( resHi, unop(Iop_64HIto32,mkexpr(res64)));
3421 assign( resLo, unop(Iop_64to32,mkexpr(res64)));
sewardj5b470602005-02-27 13:10:48 +00003422 putIRegRDX(4, mkexpr(resHi));
3423 putIRegRAX(4, mkexpr(resLo));
sewardj85520e42005-02-19 15:22:38 +00003424 break;
3425 }
3426 case Ity_I16: {
3427 IRTemp res32 = newTemp(Ity_I32);
3428 IRTemp resHi = newTemp(Ity_I16);
3429 IRTemp resLo = newTemp(Ity_I16);
3430 IROp mulOp = syned ? Iop_MullS16 : Iop_MullU16;
3431 UInt tBaseOp = syned ? AMD64G_CC_OP_SMULB : AMD64G_CC_OP_UMULB;
3432 setFlags_MUL ( Ity_I16, t1, tmp, tBaseOp );
3433 assign( res32, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
3434 assign( resHi, unop(Iop_32HIto16,mkexpr(res32)));
3435 assign( resLo, unop(Iop_32to16,mkexpr(res32)));
sewardj5b470602005-02-27 13:10:48 +00003436 putIRegRDX(2, mkexpr(resHi));
3437 putIRegRAX(2, mkexpr(resLo));
sewardj85520e42005-02-19 15:22:38 +00003438 break;
3439 }
3440 case Ity_I8: {
3441 IRTemp res16 = newTemp(Ity_I16);
3442 IRTemp resHi = newTemp(Ity_I8);
3443 IRTemp resLo = newTemp(Ity_I8);
3444 IROp mulOp = syned ? Iop_MullS8 : Iop_MullU8;
3445 UInt tBaseOp = syned ? AMD64G_CC_OP_SMULB : AMD64G_CC_OP_UMULB;
3446 setFlags_MUL ( Ity_I8, t1, tmp, tBaseOp );
3447 assign( res16, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
3448 assign( resHi, unop(Iop_16HIto8,mkexpr(res16)));
3449 assign( resLo, unop(Iop_16to8,mkexpr(res16)));
sewardj5b470602005-02-27 13:10:48 +00003450 putIRegRAX(2, mkexpr(res16));
sewardj85520e42005-02-19 15:22:38 +00003451 break;
3452 }
sewardj9b967672005-02-08 11:13:09 +00003453 default:
sewardj85520e42005-02-19 15:22:38 +00003454 ppIRType(ty);
sewardj9b967672005-02-08 11:13:09 +00003455 vpanic("codegen_mulL_A_D(amd64)");
3456 }
3457 DIP("%s%c %s\n", syned ? "imul" : "mul", nameISize(sz), tmp_txt);
3458}
sewardj32b2bbe2005-01-28 00:50:10 +00003459
3460
3461/* Group 3 extended opcodes. */
3462static
3463ULong dis_Grp3 ( Prefix pfx, Int sz, ULong delta )
3464{
sewardj227458e2005-01-31 19:04:50 +00003465 Long d64;
sewardj32b2bbe2005-01-28 00:50:10 +00003466 UChar modrm;
3467 HChar dis_buf[50];
3468 Int len;
3469 IRTemp addr;
3470 IRType ty = szToITy(sz);
3471 IRTemp t1 = newTemp(ty);
sewardj55dbb262005-01-28 16:36:51 +00003472 IRTemp dst1, src, dst0;
sewardj8c332e22005-01-28 01:36:56 +00003473 modrm = getUChar(delta);
sewardj32b2bbe2005-01-28 00:50:10 +00003474 if (epartIsReg(modrm)) {
sewardj901ed122005-02-27 13:25:31 +00003475 switch (gregLO3ofRM(modrm)) {
sewardj118b23e2005-01-29 02:14:44 +00003476 case 0: { /* TEST */
3477 delta++;
3478 d64 = getSDisp(imin(4,sz), delta);
3479 delta += imin(4,sz);
3480 dst1 = newTemp(ty);
3481 assign(dst1, binop(mkSizedOp(ty,Iop_And8),
sewardj5b470602005-02-27 13:10:48 +00003482 getIRegE(sz,pfx,modrm),
sewardj03b07cc2005-01-31 18:09:43 +00003483 mkU(ty, d64 & mkSizeMask(sz))));
sewardj118b23e2005-01-29 02:14:44 +00003484 setFlags_DEP1( Iop_And8, dst1, ty );
sewardj7eaa7cf2005-01-31 18:55:22 +00003485 DIP("test%c $%lld, %s\n",
sewardj118b23e2005-01-29 02:14:44 +00003486 nameISize(sz), d64,
sewardj5b470602005-02-27 13:10:48 +00003487 nameIRegE(sz, pfx, modrm));
sewardj118b23e2005-01-29 02:14:44 +00003488 break;
3489 }
sewardj55dbb262005-01-28 16:36:51 +00003490 case 2: /* NOT */
3491 delta++;
sewardj5b470602005-02-27 13:10:48 +00003492 putIRegE(sz, pfx, modrm,
3493 unop(mkSizedOp(ty,Iop_Not8),
3494 getIRegE(sz, pfx, modrm)));
sewardj55dbb262005-01-28 16:36:51 +00003495 DIP("not%c %s\n", nameISize(sz),
sewardj5b470602005-02-27 13:10:48 +00003496 nameIRegE(sz, pfx, modrm));
sewardj55dbb262005-01-28 16:36:51 +00003497 break;
3498 case 3: /* NEG */
3499 delta++;
3500 dst0 = newTemp(ty);
3501 src = newTemp(ty);
3502 dst1 = newTemp(ty);
3503 assign(dst0, mkU(ty,0));
sewardj5b470602005-02-27 13:10:48 +00003504 assign(src, getIRegE(sz, pfx, modrm));
sewardj55dbb262005-01-28 16:36:51 +00003505 assign(dst1, binop(mkSizedOp(ty,Iop_Sub8), mkexpr(dst0), mkexpr(src)));
3506 setFlags_DEP1_DEP2(Iop_Sub8, dst0, src, ty);
sewardj5b470602005-02-27 13:10:48 +00003507 putIRegE(sz, pfx, modrm, mkexpr(dst1));
3508 DIP("neg%c %s\n", nameISize(sz), nameIRegE(sz, pfx, modrm));
sewardj55dbb262005-01-28 16:36:51 +00003509 break;
sewardj9b967672005-02-08 11:13:09 +00003510 case 4: /* MUL (unsigned widening) */
3511 delta++;
3512 src = newTemp(ty);
sewardj5b470602005-02-27 13:10:48 +00003513 assign(src, getIRegE(sz,pfx,modrm));
sewardj9b967672005-02-08 11:13:09 +00003514 codegen_mulL_A_D ( sz, False, src,
sewardj5b470602005-02-27 13:10:48 +00003515 nameIRegE(sz,pfx,modrm) );
sewardj9b967672005-02-08 11:13:09 +00003516 break;
sewardj85520e42005-02-19 15:22:38 +00003517 case 5: /* IMUL (signed widening) */
3518 delta++;
3519 src = newTemp(ty);
sewardj5b470602005-02-27 13:10:48 +00003520 assign(src, getIRegE(sz,pfx,modrm));
sewardj85520e42005-02-19 15:22:38 +00003521 codegen_mulL_A_D ( sz, True, src,
sewardj5b470602005-02-27 13:10:48 +00003522 nameIRegE(sz,pfx,modrm) );
sewardj85520e42005-02-19 15:22:38 +00003523 break;
sewardj03b07cc2005-01-31 18:09:43 +00003524 case 6: /* DIV */
3525 delta++;
sewardj5b470602005-02-27 13:10:48 +00003526 assign( t1, getIRegE(sz, pfx, modrm) );
sewardj03b07cc2005-01-31 18:09:43 +00003527 codegen_div ( sz, t1, False );
3528 DIP("div%c %s\n", nameISize(sz),
sewardj5b470602005-02-27 13:10:48 +00003529 nameIRegE(sz, pfx, modrm));
sewardj03b07cc2005-01-31 18:09:43 +00003530 break;
sewardj32b2bbe2005-01-28 00:50:10 +00003531 case 7: /* IDIV */
3532 delta++;
sewardj5b470602005-02-27 13:10:48 +00003533 assign( t1, getIRegE(sz, pfx, modrm) );
sewardj32b2bbe2005-01-28 00:50:10 +00003534 codegen_div ( sz, t1, True );
3535 DIP("idiv%c %s\n", nameISize(sz),
sewardj5b470602005-02-27 13:10:48 +00003536 nameIRegE(sz, pfx, modrm));
sewardj32b2bbe2005-01-28 00:50:10 +00003537 break;
3538 default:
3539 vex_printf(
sewardj901ed122005-02-27 13:25:31 +00003540 "unhandled Grp3(R) case %d\n", (Int)gregLO3ofRM(modrm));
sewardj32b2bbe2005-01-28 00:50:10 +00003541 vpanic("Grp3(amd64)");
3542 }
3543 } else {
sewardj7de0d3c2005-02-13 02:26:41 +00003544 addr = disAMode ( &len, pfx, delta, dis_buf,
3545 /* we have to inform disAMode of any immediate
3546 bytes used */
sewardj901ed122005-02-27 13:25:31 +00003547 gregLO3ofRM(modrm)==0/*TEST*/
sewardj7de0d3c2005-02-13 02:26:41 +00003548 ? imin(4,sz)
3549 : 0
3550 );
sewardj32b2bbe2005-01-28 00:50:10 +00003551 t1 = newTemp(ty);
3552 delta += len;
3553 assign(t1, loadLE(ty,mkexpr(addr)));
sewardj901ed122005-02-27 13:25:31 +00003554 switch (gregLO3ofRM(modrm)) {
sewardj03b07cc2005-01-31 18:09:43 +00003555 case 0: { /* TEST */
3556 d64 = getSDisp(imin(4,sz), delta);
3557 delta += imin(4,sz);
3558 dst1 = newTemp(ty);
3559 assign(dst1, binop(mkSizedOp(ty,Iop_And8),
3560 mkexpr(t1),
3561 mkU(ty, d64 & mkSizeMask(sz))));
3562 setFlags_DEP1( Iop_And8, dst1, ty );
3563 DIP("test%c $%lld, %s\n", nameISize(sz), d64, dis_buf);
3564 break;
3565 }
sewardjd20c8852005-01-20 20:04:07 +00003566//.. /* probably OK, but awaiting test case */
3567//.. case 2: /* NOT */
3568//.. storeLE( mkexpr(addr), unop(mkSizedOp(ty,Iop_Not8), mkexpr(t1)));
3569//.. DIP("not%c %s\n", nameISize(sz), dis_buf);
3570//.. break;
sewardj7de0d3c2005-02-13 02:26:41 +00003571 case 3: /* NEG */
3572 dst0 = newTemp(ty);
3573 src = newTemp(ty);
3574 dst1 = newTemp(ty);
3575 assign(dst0, mkU(ty,0));
3576 assign(src, mkexpr(t1));
3577 assign(dst1, binop(mkSizedOp(ty,Iop_Sub8), mkexpr(dst0), mkexpr(src)));
3578 setFlags_DEP1_DEP2(Iop_Sub8, dst0, src, ty);
3579 storeLE( mkexpr(addr), mkexpr(dst1) );
3580 DIP("neg%c %s\n", nameISize(sz), dis_buf);
3581 break;
sewardjd20c8852005-01-20 20:04:07 +00003582//.. case 4: /* MUL */
3583//.. codegen_mulL_A_D ( sz, False, t1, dis_buf );
3584//.. break;
3585//.. case 5: /* IMUL */
3586//.. codegen_mulL_A_D ( sz, True, t1, dis_buf );
3587//.. break;
sewardj1001dc42005-02-21 08:25:55 +00003588 case 6: /* DIV */
3589 codegen_div ( sz, t1, False );
3590 DIP("div%c %s\n", nameISize(sz), dis_buf);
3591 break;
sewardjd20c8852005-01-20 20:04:07 +00003592//.. case 7: /* IDIV */
3593//.. codegen_div ( sz, t1, True );
3594//.. DIP("idiv%c %s\n", nameISize(sz), dis_buf);
3595//.. break;
sewardj32b2bbe2005-01-28 00:50:10 +00003596 default:
3597 vex_printf(
sewardj901ed122005-02-27 13:25:31 +00003598 "unhandled Grp3(M) case %d\n", (Int)gregLO3ofRM(modrm));
sewardj32b2bbe2005-01-28 00:50:10 +00003599 vpanic("Grp3(amd64)");
3600 }
3601 }
3602 return delta;
3603}
3604
3605
sewardj03b07cc2005-01-31 18:09:43 +00003606/* Group 4 extended opcodes. */
3607static
3608ULong dis_Grp4 ( Prefix pfx, ULong delta )
3609{
3610 Int alen;
3611 UChar modrm;
3612 HChar dis_buf[50];
3613 IRType ty = Ity_I8;
3614 IRTemp t1 = newTemp(ty);
3615 IRTemp t2 = newTemp(ty);
3616
3617 modrm = getUChar(delta);
3618 if (epartIsReg(modrm)) {
sewardj5b470602005-02-27 13:10:48 +00003619 assign(t1, getIRegE(1, pfx, modrm));
sewardj901ed122005-02-27 13:25:31 +00003620 switch (gregLO3ofRM(modrm)) {
sewardj85520e42005-02-19 15:22:38 +00003621 case 0: /* INC */
3622 assign(t2, binop(Iop_Add8, mkexpr(t1), mkU8(1)));
sewardj5b470602005-02-27 13:10:48 +00003623 putIRegE(1, pfx, modrm, mkexpr(t2));
sewardj85520e42005-02-19 15:22:38 +00003624 setFlags_INC_DEC( True, t2, ty );
3625 break;
sewardj03b07cc2005-01-31 18:09:43 +00003626 case 1: /* DEC */
3627 assign(t2, binop(Iop_Sub8, mkexpr(t1), mkU8(1)));
sewardj5b470602005-02-27 13:10:48 +00003628 putIRegE(1, pfx, modrm, mkexpr(t2));
sewardj03b07cc2005-01-31 18:09:43 +00003629 setFlags_INC_DEC( False, t2, ty );
3630 break;
3631 default:
3632 vex_printf(
sewardj901ed122005-02-27 13:25:31 +00003633 "unhandled Grp4(R) case %d\n", (Int)gregLO3ofRM(modrm));
sewardj03b07cc2005-01-31 18:09:43 +00003634 vpanic("Grp4(amd64,R)");
3635 }
3636 delta++;
sewardj901ed122005-02-27 13:25:31 +00003637 DIP("%sb %s\n", nameGrp4(gregLO3ofRM(modrm)),
sewardj5b470602005-02-27 13:10:48 +00003638 nameIRegE(1, pfx, modrm));
sewardj03b07cc2005-01-31 18:09:43 +00003639 } else {
sewardje1698952005-02-08 15:02:39 +00003640 IRTemp addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
sewardj03b07cc2005-01-31 18:09:43 +00003641 assign( t1, loadLE(ty, mkexpr(addr)) );
sewardj901ed122005-02-27 13:25:31 +00003642 switch (gregLO3ofRM(modrm)) {
sewardjd20c8852005-01-20 20:04:07 +00003643//.. case 0: /* INC */
3644//.. assign(t2, binop(Iop_Add8, mkexpr(t1), mkU8(1)));
3645//.. storeLE( mkexpr(addr), mkexpr(t2) );
3646//.. setFlags_INC_DEC( True, t2, ty );
3647//.. break;
3648//.. case 1: /* DEC */
3649//.. assign(t2, binop(Iop_Sub8, mkexpr(t1), mkU8(1)));
3650//.. storeLE( mkexpr(addr), mkexpr(t2) );
3651//.. setFlags_INC_DEC( False, t2, ty );
3652//.. break;
sewardj03b07cc2005-01-31 18:09:43 +00003653 default:
3654 vex_printf(
sewardj901ed122005-02-27 13:25:31 +00003655 "unhandled Grp4(M) case %d\n", (Int)gregLO3ofRM(modrm));
sewardj03b07cc2005-01-31 18:09:43 +00003656 vpanic("Grp4(amd64,M)");
3657 }
3658 delta += alen;
sewardj901ed122005-02-27 13:25:31 +00003659 DIP("%sb %s\n", nameGrp4(gregLO3ofRM(modrm)), dis_buf);
sewardj03b07cc2005-01-31 18:09:43 +00003660 }
3661 return delta;
3662}
sewardj354e5c62005-01-27 20:12:52 +00003663
3664
3665/* Group 5 extended opcodes. */
3666static
3667ULong dis_Grp5 ( Prefix pfx, Int sz, ULong delta, DisResult* whatNext )
3668{
3669 Int len;
3670 UChar modrm;
3671 HChar dis_buf[50];
3672 IRTemp addr = IRTemp_INVALID;
3673 IRType ty = szToITy(sz);
3674 IRTemp t1 = newTemp(ty);
3675 IRTemp t2 = IRTemp_INVALID;
sewardj03b07cc2005-01-31 18:09:43 +00003676 IRTemp t3 = IRTemp_INVALID;
sewardj7eaa7cf2005-01-31 18:55:22 +00003677 Bool showSz = True;
sewardj354e5c62005-01-27 20:12:52 +00003678
sewardj8c332e22005-01-28 01:36:56 +00003679 modrm = getUChar(delta);
sewardj354e5c62005-01-27 20:12:52 +00003680 if (epartIsReg(modrm)) {
sewardj5b470602005-02-27 13:10:48 +00003681 assign(t1, getIRegE(sz,pfx,modrm));
sewardj901ed122005-02-27 13:25:31 +00003682 switch (gregLO3ofRM(modrm)) {
sewardj32b2bbe2005-01-28 00:50:10 +00003683 case 0: /* INC */
3684 t2 = newTemp(ty);
3685 assign(t2, binop(mkSizedOp(ty,Iop_Add8),
3686 mkexpr(t1), mkU(ty,1)));
3687 setFlags_INC_DEC( True, t2, ty );
sewardj5b470602005-02-27 13:10:48 +00003688 putIRegE(sz,pfx,modrm, mkexpr(t2));
sewardj32b2bbe2005-01-28 00:50:10 +00003689 break;
3690 case 1: /* DEC */
3691 t2 = newTemp(ty);
3692 assign(t2, binop(mkSizedOp(ty,Iop_Sub8),
3693 mkexpr(t1), mkU(ty,1)));
3694 setFlags_INC_DEC( False, t2, ty );
sewardj5b470602005-02-27 13:10:48 +00003695 putIRegE(sz,pfx,modrm, mkexpr(t2));
sewardj32b2bbe2005-01-28 00:50:10 +00003696 break;
sewardj354e5c62005-01-27 20:12:52 +00003697 case 2: /* call Ev */
sewardj03b07cc2005-01-31 18:09:43 +00003698 /* Ignore any sz value and operate as if sz==8. */
sewardj354e5c62005-01-27 20:12:52 +00003699 vassert(sz == 4);
sewardj03b07cc2005-01-31 18:09:43 +00003700 sz = 8;
3701 t3 = newTemp(Ity_I64);
sewardj5b470602005-02-27 13:10:48 +00003702 assign(t3, getIRegE(sz,pfx,modrm));
sewardj03b07cc2005-01-31 18:09:43 +00003703 t2 = newTemp(Ity_I64);
3704 assign(t2, binop(Iop_Sub64, getIReg64(R_RSP), mkU64(8)));
3705 putIReg64(R_RSP, mkexpr(t2));
3706 storeLE( mkexpr(t2), mkU64(guest_rip_bbstart+delta+1));
3707 jmp_treg(Ijk_Call,t3);
sewardj354e5c62005-01-27 20:12:52 +00003708 *whatNext = Dis_StopHere;
sewardj7eaa7cf2005-01-31 18:55:22 +00003709 showSz = False;
sewardj354e5c62005-01-27 20:12:52 +00003710 break;
sewardj354e5c62005-01-27 20:12:52 +00003711 case 4: /* jmp Ev */
sewardj03b07cc2005-01-31 18:09:43 +00003712 /* Ignore any sz value and operate as if sz==8. */
sewardj354e5c62005-01-27 20:12:52 +00003713 vassert(sz == 4);
sewardj03b07cc2005-01-31 18:09:43 +00003714 sz = 8;
3715 t3 = newTemp(Ity_I64);
sewardj5b470602005-02-27 13:10:48 +00003716 assign(t3, getIRegE(sz,pfx,modrm));
sewardj03b07cc2005-01-31 18:09:43 +00003717 jmp_treg(Ijk_Boring,t3);
sewardj354e5c62005-01-27 20:12:52 +00003718 *whatNext = Dis_StopHere;
sewardj7eaa7cf2005-01-31 18:55:22 +00003719 showSz = False;
sewardj354e5c62005-01-27 20:12:52 +00003720 break;
sewardj354e5c62005-01-27 20:12:52 +00003721 default:
3722 vex_printf(
sewardj901ed122005-02-27 13:25:31 +00003723 "unhandled Grp5(R) case %d\n", (Int)gregLO3ofRM(modrm));
sewardj354e5c62005-01-27 20:12:52 +00003724 vpanic("Grp5(amd64)");
3725 }
3726 delta++;
sewardj901ed122005-02-27 13:25:31 +00003727 DIP("%s%c %s\n", nameGrp5(gregLO3ofRM(modrm)),
sewardj7eaa7cf2005-01-31 18:55:22 +00003728 showSz ? nameISize(sz) : ' ',
sewardj5b470602005-02-27 13:10:48 +00003729 nameIRegE(sz, pfx, modrm));
sewardj354e5c62005-01-27 20:12:52 +00003730 } else {
sewardje1698952005-02-08 15:02:39 +00003731 addr = disAMode ( &len, pfx, delta, dis_buf, 0 );
sewardj901ed122005-02-27 13:25:31 +00003732 if (gregLO3ofRM(modrm) != 2 && gregLO3ofRM(modrm) != 4
3733 && gregLO3ofRM(modrm) != 6) {
sewardj03b07cc2005-01-31 18:09:43 +00003734 assign(t1, loadLE(ty,mkexpr(addr)));
sewardj909c06d2005-02-19 22:47:41 +00003735 }
sewardj901ed122005-02-27 13:25:31 +00003736 switch (gregLO3ofRM(modrm)) {
sewardj354e5c62005-01-27 20:12:52 +00003737 case 0: /* INC */
sewardj354e5c62005-01-27 20:12:52 +00003738 t2 = newTemp(ty);
3739 assign(t2, binop(mkSizedOp(ty,Iop_Add8),
3740 mkexpr(t1), mkU(ty,1)));
3741 setFlags_INC_DEC( True, t2, ty );
3742 storeLE(mkexpr(addr),mkexpr(t2));
3743 break;
sewardj354e5c62005-01-27 20:12:52 +00003744 case 1: /* DEC */
3745 t2 = newTemp(ty);
3746 assign(t2, binop(mkSizedOp(ty,Iop_Sub8),
3747 mkexpr(t1), mkU(ty,1)));
3748 setFlags_INC_DEC( False, t2, ty );
3749 storeLE(mkexpr(addr),mkexpr(t2));
3750 break;
3751 case 2: /* call Ev */
sewardj03b07cc2005-01-31 18:09:43 +00003752 /* Ignore any sz value and operate as if sz==8. */
sewardj354e5c62005-01-27 20:12:52 +00003753 vassert(sz == 4);
sewardj7eaa7cf2005-01-31 18:55:22 +00003754 sz = 8;
sewardj03b07cc2005-01-31 18:09:43 +00003755 t3 = newTemp(Ity_I64);
3756 assign(t3, loadLE(Ity_I64,mkexpr(addr)));
3757 t2 = newTemp(Ity_I64);
3758 assign(t2, binop(Iop_Sub64, getIReg64(R_RSP), mkU64(8)));
3759 putIReg64(R_RSP, mkexpr(t2));
3760 storeLE( mkexpr(t2), mkU64(guest_rip_bbstart+delta+len));
3761 jmp_treg(Ijk_Call,t3);
sewardj354e5c62005-01-27 20:12:52 +00003762 *whatNext = Dis_StopHere;
sewardj7eaa7cf2005-01-31 18:55:22 +00003763 showSz = False;
sewardj354e5c62005-01-27 20:12:52 +00003764 break;
sewardj354e5c62005-01-27 20:12:52 +00003765 case 4: /* JMP Ev */
sewardj03b07cc2005-01-31 18:09:43 +00003766 /* Ignore any sz value and operate as if sz==8. */
sewardj354e5c62005-01-27 20:12:52 +00003767 vassert(sz == 4);
sewardj7eaa7cf2005-01-31 18:55:22 +00003768 sz = 8;
sewardj03b07cc2005-01-31 18:09:43 +00003769 t3 = newTemp(Ity_I64);
3770 assign(t3, loadLE(Ity_I64,mkexpr(addr)));
3771 jmp_treg(Ijk_Boring,t3);
sewardj354e5c62005-01-27 20:12:52 +00003772 *whatNext = Dis_StopHere;
sewardj7eaa7cf2005-01-31 18:55:22 +00003773 showSz = False;
sewardj354e5c62005-01-27 20:12:52 +00003774 break;
sewardj354e5c62005-01-27 20:12:52 +00003775 case 6: /* PUSH Ev */
sewardja6b93d12005-02-17 09:28:28 +00003776 /* There is no encoding for 32-bit operand size; hence ... */
3777 if (sz == 4) sz = 8;
3778 vassert(sz == 8 || sz == 2);
sewardj909c06d2005-02-19 22:47:41 +00003779 if (sz == 8) {
3780 t3 = newTemp(Ity_I64);
3781 assign(t3, loadLE(Ity_I64,mkexpr(addr)));
3782 t2 = newTemp(Ity_I64);
3783 assign( t2, binop(Iop_Sub64,getIReg64(R_RSP),mkU64(sz)) );
3784 putIReg64(R_RSP, mkexpr(t2) );
3785 storeLE( mkexpr(t2), mkexpr(t3) );
3786 break;
3787 } else {
3788 goto unhandled; /* awaiting test case */
3789 }
sewardj354e5c62005-01-27 20:12:52 +00003790 default:
sewardja6b93d12005-02-17 09:28:28 +00003791 unhandled:
sewardj354e5c62005-01-27 20:12:52 +00003792 vex_printf(
sewardj901ed122005-02-27 13:25:31 +00003793 "unhandled Grp5(M) case %d\n", (Int)gregLO3ofRM(modrm));
sewardj354e5c62005-01-27 20:12:52 +00003794 vpanic("Grp5(amd64)");
3795 }
3796 delta += len;
sewardj901ed122005-02-27 13:25:31 +00003797 DIP("%s%c %s\n", nameGrp5(gregLO3ofRM(modrm)),
sewardj7eaa7cf2005-01-31 18:55:22 +00003798 showSz ? nameISize(sz) : ' ',
3799 dis_buf);
sewardj354e5c62005-01-27 20:12:52 +00003800 }
3801 return delta;
3802}
3803
3804
sewardjd0a12df2005-02-10 02:07:43 +00003805/*------------------------------------------------------------*/
3806/*--- Disassembling string ops (including REP prefixes) ---*/
3807/*------------------------------------------------------------*/
3808
3809/* Code shared by all the string ops */
3810static
3811void dis_string_op_increment ( Int sz, IRTemp t_inc )
3812{
3813 UChar logSz;
3814 if (sz == 8 || sz == 4 || sz == 2) {
3815 logSz = 1;
3816 if (sz == 4) logSz = 2;
3817 if (sz == 8) logSz = 3;
3818 assign( t_inc,
3819 binop(Iop_Shl64, IRExpr_Get( OFFB_DFLAG, Ity_I64 ),
3820 mkU8(logSz) ) );
3821 } else {
3822 assign( t_inc,
3823 IRExpr_Get( OFFB_DFLAG, Ity_I64 ) );
3824 }
3825}
3826
sewardj909c06d2005-02-19 22:47:41 +00003827static
3828void dis_string_op( void (*dis_OP)( Int, IRTemp ),
3829 Int sz, HChar* name, Prefix pfx )
3830{
3831 IRTemp t_inc = newTemp(Ity_I64);
3832 /* Really we ought to inspect the override prefixes, but we don't.
3833 The following assertion catches any resulting sillyness. */
3834 vassert(pfx == clearSegBits(pfx));
3835 dis_string_op_increment(sz, t_inc);
3836 dis_OP( sz, t_inc );
3837 DIP("%s%c\n", name, nameISize(sz));
3838}
3839
3840static
3841void dis_MOVS ( Int sz, IRTemp t_inc )
3842{
3843 IRType ty = szToITy(sz);
3844 IRTemp td = newTemp(Ity_I64); /* RDI */
3845 IRTemp ts = newTemp(Ity_I64); /* RSI */
3846
3847 assign( td, getIReg64(R_RDI) );
3848 assign( ts, getIReg64(R_RSI) );
3849
3850 storeLE( mkexpr(td), loadLE(ty,mkexpr(ts)) );
3851
3852 putIReg64( R_RDI, binop(Iop_Add64, mkexpr(td), mkexpr(t_inc)) );
3853 putIReg64( R_RSI, binop(Iop_Add64, mkexpr(ts), mkexpr(t_inc)) );
3854}
3855
sewardjd20c8852005-01-20 20:04:07 +00003856//.. //-- static
3857//.. //-- void dis_LODS ( UCodeBlock* cb, Int sz, Int t_inc )
3858//.. //-- {
3859//.. //-- Int ta = newTemp(cb); /* EAX */
3860//.. //-- Int ts = newTemp(cb); /* ESI */
3861//.. //--
3862//.. //-- uInstr2(cb, GET, 4, ArchReg, R_ESI, TempReg, ts);
3863//.. //-- uInstr2(cb, LOAD, sz, TempReg, ts, TempReg, ta);
3864//.. //-- uInstr2(cb, PUT, sz, TempReg, ta, ArchReg, R_EAX);
3865//.. //--
3866//.. //-- uInstr2(cb, ADD, 4, TempReg, t_inc, TempReg, ts);
3867//.. //-- uInstr2(cb, PUT, 4, TempReg, ts, ArchReg, R_ESI);
3868//.. //-- }
sewardja6b93d12005-02-17 09:28:28 +00003869
3870static
3871void dis_STOS ( Int sz, IRTemp t_inc )
3872{
3873 IRType ty = szToITy(sz);
3874 IRTemp ta = newTemp(ty); /* rAX */
3875 IRTemp td = newTemp(Ity_I64); /* RDI */
3876
sewardj5b470602005-02-27 13:10:48 +00003877 assign( ta, getIRegRAX(sz) );
sewardja6b93d12005-02-17 09:28:28 +00003878
3879 assign( td, getIReg64(R_RDI) );
3880
3881 storeLE( mkexpr(td), mkexpr(ta) );
3882
3883 putIReg64( R_RDI, binop(Iop_Add64, mkexpr(td), mkexpr(t_inc)) );
3884}
sewardjd0a12df2005-02-10 02:07:43 +00003885
3886static
3887void dis_CMPS ( Int sz, IRTemp t_inc )
3888{
3889 IRType ty = szToITy(sz);
3890 IRTemp tdv = newTemp(ty); /* (RDI) */
3891 IRTemp tsv = newTemp(ty); /* (RSI) */
3892 IRTemp td = newTemp(Ity_I64); /* RDI */
3893 IRTemp ts = newTemp(Ity_I64); /* RSI */
3894
3895 assign( td, getIReg64(R_RDI) );
3896
3897 assign( ts, getIReg64(R_RSI) );
3898
3899 assign( tdv, loadLE(ty,mkexpr(td)) );
3900
3901 assign( tsv, loadLE(ty,mkexpr(ts)) );
3902
3903 setFlags_DEP1_DEP2 ( Iop_Sub8, tsv, tdv, ty );
3904
3905 putIReg64(R_RDI, binop(Iop_Add64, mkexpr(td), mkexpr(t_inc)) );
3906
3907 putIReg64(R_RSI, binop(Iop_Add64, mkexpr(ts), mkexpr(t_inc)) );
3908}
3909
sewardj85520e42005-02-19 15:22:38 +00003910static
3911void dis_SCAS ( Int sz, IRTemp t_inc )
3912{
3913 IRType ty = szToITy(sz);
3914 IRTemp ta = newTemp(ty); /* rAX */
3915 IRTemp td = newTemp(Ity_I64); /* RDI */
3916 IRTemp tdv = newTemp(ty); /* (RDI) */
3917
sewardj5b470602005-02-27 13:10:48 +00003918 assign( ta, getIRegRAX(sz) );
sewardj85520e42005-02-19 15:22:38 +00003919
3920 assign( td, getIReg64(R_RDI) );
3921
3922 assign( tdv, loadLE(ty,mkexpr(td)) );
3923
3924 setFlags_DEP1_DEP2 ( Iop_Sub8, ta, tdv, ty );
3925
3926 putIReg64(R_RDI, binop(Iop_Add64, mkexpr(td), mkexpr(t_inc)) );
3927}
sewardjd0a12df2005-02-10 02:07:43 +00003928
3929
3930/* Wrap the appropriate string op inside a REP/REPE/REPNE. We assume
3931 the insn is the last one in the basic block, and so emit a jump to
3932 the next insn, rather than just falling through. */
3933static
3934void dis_REP_op ( AMD64Condcode cond,
3935 void (*dis_OP)(Int, IRTemp),
sewardj909c06d2005-02-19 22:47:41 +00003936 Int sz, Addr64 rip, Addr64 rip_next, HChar* name,
3937 Prefix pfx )
sewardjd0a12df2005-02-10 02:07:43 +00003938{
3939 IRTemp t_inc = newTemp(Ity_I64);
3940 IRTemp tc = newTemp(Ity_I64); /* RCX */
3941
sewardj909c06d2005-02-19 22:47:41 +00003942 /* Really we ought to inspect the override prefixes, but we don't.
3943 The following assertion catches any resulting sillyness. */
3944 vassert(pfx == clearSegBits(pfx));
3945
sewardjd0a12df2005-02-10 02:07:43 +00003946 assign( tc, getIReg64(R_RCX) );
3947
3948 stmt( IRStmt_Exit( binop(Iop_CmpEQ64,mkexpr(tc),mkU64(0)),
3949 Ijk_Boring,
3950 IRConst_U64(rip_next) ) );
3951
3952 putIReg64(R_RCX, binop(Iop_Sub64, mkexpr(tc), mkU64(1)) );
3953
3954 dis_string_op_increment(sz, t_inc);
3955 dis_OP (sz, t_inc);
3956
3957 if (cond == AMD64CondAlways) {
3958 jmp_lit(Ijk_Boring,rip);
3959 } else {
3960 stmt( IRStmt_Exit( mk_amd64g_calculate_condition(cond),
3961 Ijk_Boring,
3962 IRConst_U64(rip) ) );
3963 jmp_lit(Ijk_Boring,rip_next);
3964 }
3965 DIP("%s%c\n", name, nameISize(sz));
3966}
sewardj32b2bbe2005-01-28 00:50:10 +00003967
3968
3969/*------------------------------------------------------------*/
3970/*--- Arithmetic, etc. ---*/
3971/*------------------------------------------------------------*/
3972
3973/* IMUL E, G. Supplied eip points to the modR/M byte. */
3974static
3975ULong dis_mul_E_G ( Prefix pfx,
3976 Int size,
3977 ULong delta0 )
3978{
3979 Int alen;
3980 HChar dis_buf[50];
sewardj8c332e22005-01-28 01:36:56 +00003981 UChar rm = getUChar(delta0);
sewardj32b2bbe2005-01-28 00:50:10 +00003982 IRType ty = szToITy(size);
3983 IRTemp te = newTemp(ty);
3984 IRTemp tg = newTemp(ty);
3985 IRTemp resLo = newTemp(ty);
3986
sewardj5b470602005-02-27 13:10:48 +00003987 assign( tg, getIRegG(size, pfx, rm) );
sewardj32b2bbe2005-01-28 00:50:10 +00003988 if (epartIsReg(rm)) {
sewardj5b470602005-02-27 13:10:48 +00003989 assign( te, getIRegE(size, pfx, rm) );
sewardj32b2bbe2005-01-28 00:50:10 +00003990 } else {
sewardje1698952005-02-08 15:02:39 +00003991 IRTemp addr = disAMode( &alen, pfx, delta0, dis_buf, 0 );
sewardj32b2bbe2005-01-28 00:50:10 +00003992 assign( te, loadLE(ty,mkexpr(addr)) );
3993 }
3994
3995 setFlags_MUL ( ty, te, tg, AMD64G_CC_OP_SMULB );
3996
3997 assign( resLo, binop( mkSizedOp(ty, Iop_Mul8), mkexpr(te), mkexpr(tg) ) );
3998
sewardj5b470602005-02-27 13:10:48 +00003999 putIRegG(size, pfx, rm, mkexpr(resLo) );
sewardj32b2bbe2005-01-28 00:50:10 +00004000
4001 if (epartIsReg(rm)) {
4002 DIP("imul%c %s, %s\n", nameISize(size),
sewardj901ed122005-02-27 13:25:31 +00004003 nameIRegE(size,pfx,rm),
4004 nameIRegG(size,pfx,rm));
sewardj32b2bbe2005-01-28 00:50:10 +00004005 return 1+delta0;
4006 } else {
4007 DIP("imul%c %s, %s\n", nameISize(size),
4008 dis_buf,
sewardj901ed122005-02-27 13:25:31 +00004009 nameIRegG(size,pfx,rm));
sewardj32b2bbe2005-01-28 00:50:10 +00004010 return alen+delta0;
4011 }
4012}
4013
4014
4015/* IMUL I * E -> G. Supplied rip points to the modR/M byte. */
4016static
4017ULong dis_imul_I_E_G ( Prefix pfx,
4018 Int size,
4019 ULong delta,
4020 Int litsize )
4021{
4022 Long d64;
4023 Int alen;
4024 HChar dis_buf[50];
sewardj8c332e22005-01-28 01:36:56 +00004025 UChar rm = getUChar(delta);
sewardj32b2bbe2005-01-28 00:50:10 +00004026 IRType ty = szToITy(size);
4027 IRTemp te = newTemp(ty);
4028 IRTemp tl = newTemp(ty);
4029 IRTemp resLo = newTemp(ty);
4030
sewardj85520e42005-02-19 15:22:38 +00004031 vassert(/*size == 1 ||*/ size == 2 || size == 4 || size == 8);
sewardj32b2bbe2005-01-28 00:50:10 +00004032
4033 if (epartIsReg(rm)) {
sewardj5b470602005-02-27 13:10:48 +00004034 assign(te, getIRegE(size, pfx, rm));
sewardj32b2bbe2005-01-28 00:50:10 +00004035 delta++;
4036 } else {
sewardj7de0d3c2005-02-13 02:26:41 +00004037 IRTemp addr = disAMode( &alen, pfx, delta, dis_buf,
4038 imin(4,litsize) );
sewardj32b2bbe2005-01-28 00:50:10 +00004039 assign(te, loadLE(ty, mkexpr(addr)));
4040 delta += alen;
4041 }
4042 d64 = getSDisp(imin(4,litsize),delta);
4043 delta += imin(4,litsize);
4044
sewardj1389d4d2005-01-28 13:46:29 +00004045 d64 &= mkSizeMask(size);
sewardj32b2bbe2005-01-28 00:50:10 +00004046 assign(tl, mkU(ty,d64));
4047
4048 assign( resLo, binop( mkSizedOp(ty, Iop_Mul8), mkexpr(te), mkexpr(tl) ));
4049
4050 setFlags_MUL ( ty, te, tl, AMD64G_CC_OP_SMULB );
4051
sewardj5b470602005-02-27 13:10:48 +00004052 putIRegG(size, pfx, rm, mkexpr(resLo));
sewardj32b2bbe2005-01-28 00:50:10 +00004053
4054 DIP("imul%c $%lld, %s, %s\n",
4055 nameISize(size), d64,
sewardj5b470602005-02-27 13:10:48 +00004056 ( epartIsReg(rm) ? nameIRegE(size,pfx,rm) : dis_buf ),
4057 nameIRegG(size,pfx,rm) );
sewardj32b2bbe2005-01-28 00:50:10 +00004058 return delta;
4059}
4060
4061
sewardjd20c8852005-01-20 20:04:07 +00004062//.. /*------------------------------------------------------------*/
4063//.. /*--- ---*/
4064//.. /*--- x87 FLOATING POINT INSTRUCTIONS ---*/
4065//.. /*--- ---*/
4066//.. /*------------------------------------------------------------*/
4067//..
4068//.. /* --- Helper functions for dealing with the register stack. --- */
4069//..
4070//.. /* --- Set the emulation-warning pseudo-register. --- */
4071//..
4072//.. static void put_emwarn ( IRExpr* e /* :: Ity_I32 */ )
4073//.. {
4074//.. stmt( IRStmt_Put( OFFB_EMWARN, e ) );
4075//.. }
sewardj8d965312005-02-25 02:48:47 +00004076
4077/* --- Produce an IRExpr* denoting a 64-bit QNaN. --- */
4078
4079static IRExpr* mkQNaN64 ( void )
4080{
4081 /* QNaN is 0 2047 1 0(51times)
4082 == 0b 11111111111b 1 0(51times)
4083 == 0x7FF8 0000 0000 0000
4084 */
4085 return IRExpr_Const(IRConst_F64i(0x7FF8000000000000ULL));
4086}
4087
4088/* --------- Get/put the top-of-stack pointer :: Ity_I32 --------- */
4089
4090static IRExpr* get_ftop ( void )
4091{
4092 return IRExpr_Get( OFFB_FTOP, Ity_I32 );
4093}
4094
4095static void put_ftop ( IRExpr* e )
4096{
4097 vassert(typeOfIRExpr(irbb->tyenv, e) == Ity_I32);
4098 stmt( IRStmt_Put( OFFB_FTOP, e ) );
4099}
4100
sewardjd20c8852005-01-20 20:04:07 +00004101//.. /* --------- Get/put the C3210 bits. --------- */
4102//..
4103//.. static IRExpr* get_C3210 ( void )
4104//.. {
4105//.. return IRExpr_Get( OFFB_FC3210, Ity_I32 );
4106//.. }
4107//..
4108//.. static void put_C3210 ( IRExpr* e )
4109//.. {
4110//.. stmt( IRStmt_Put( OFFB_FC3210, e ) );
4111//.. }
sewardjc49ce232005-02-25 13:03:03 +00004112
4113/* --------- Get/put the FPU rounding mode. --------- */
4114static IRExpr* /* :: Ity_I32 */ get_fpround ( void )
4115{
4116 return unop(Iop_64to32, IRExpr_Get( OFFB_FPROUND, Ity_I64 ));
4117}
4118
sewardjd20c8852005-01-20 20:04:07 +00004119//.. static void put_fpround ( IRExpr* /* :: Ity_I32 */ e )
4120//.. {
sewardjc49ce232005-02-25 13:03:03 +00004121//.. vassert(typeOfIRExpr(irbb->tyenv, e) == Ity_I32);
4122//.. stmt( IRStmt_Put( OFFB_FPROUND, unop(Iop_32Uto64,e) ) );
sewardjd20c8852005-01-20 20:04:07 +00004123//.. }
sewardjc49ce232005-02-25 13:03:03 +00004124
4125
4126/* --------- Synthesise a 2-bit FPU rounding mode. --------- */
4127/* Produces a value in 0 .. 3, which is encoded as per the type
4128 IRRoundingMode. Since the guest_FPROUND value is also encoded as
4129 per IRRoundingMode, we merely need to get it and mask it for
4130 safety.
4131*/
4132static IRExpr* /* :: Ity_I32 */ get_roundingmode ( void )
4133{
4134 return binop( Iop_And32, get_fpround(), mkU32(3) );
4135}
sewardj8d965312005-02-25 02:48:47 +00004136
4137
4138/* --------- Get/set FP register tag bytes. --------- */
4139
4140/* Given i, and some expression e, generate 'ST_TAG(i) = e'. */
4141
4142static void put_ST_TAG ( Int i, IRExpr* value )
4143{
4144 IRArray* descr;
4145 vassert(typeOfIRExpr(irbb->tyenv, value) == Ity_I8);
4146 descr = mkIRArray( OFFB_FPTAGS, Ity_I8, 8 );
4147 stmt( IRStmt_PutI( descr, get_ftop(), i, value ) );
4148}
4149
4150/* Given i, generate an expression yielding 'ST_TAG(i)'. This will be
4151 zero to indicate "Empty" and nonzero to indicate "NonEmpty". */
4152
4153static IRExpr* get_ST_TAG ( Int i )
4154{
4155 IRArray* descr = mkIRArray( OFFB_FPTAGS, Ity_I8, 8 );
4156 return IRExpr_GetI( descr, get_ftop(), i );
4157}
4158
4159
4160/* --------- Get/set FP registers. --------- */
4161
4162/* Given i, and some expression e, emit 'ST(i) = e' and set the
4163 register's tag to indicate the register is full. The previous
4164 state of the register is not checked. */
4165
4166static void put_ST_UNCHECKED ( Int i, IRExpr* value )
4167{
4168 IRArray* descr;
4169 vassert(typeOfIRExpr(irbb->tyenv, value) == Ity_F64);
4170 descr = mkIRArray( OFFB_FPREGS, Ity_F64, 8 );
4171 stmt( IRStmt_PutI( descr, get_ftop(), i, value ) );
4172 /* Mark the register as in-use. */
4173 put_ST_TAG(i, mkU8(1));
4174}
4175
4176/* Given i, and some expression e, emit
4177 ST(i) = is_full(i) ? NaN : e
4178 and set the tag accordingly.
4179*/
4180
4181static void put_ST ( Int i, IRExpr* value )
4182{
4183 put_ST_UNCHECKED( i,
4184 IRExpr_Mux0X( get_ST_TAG(i),
4185 /* 0 means empty */
4186 value,
4187 /* non-0 means full */
4188 mkQNaN64()
4189 )
4190 );
4191}
4192
4193
4194/* Given i, generate an expression yielding 'ST(i)'. */
4195
4196static IRExpr* get_ST_UNCHECKED ( Int i )
4197{
4198 IRArray* descr = mkIRArray( OFFB_FPREGS, Ity_F64, 8 );
4199 return IRExpr_GetI( descr, get_ftop(), i );
4200}
4201
4202
4203/* Given i, generate an expression yielding
4204 is_full(i) ? ST(i) : NaN
4205*/
4206
4207static IRExpr* get_ST ( Int i )
4208{
4209 return
4210 IRExpr_Mux0X( get_ST_TAG(i),
4211 /* 0 means empty */
4212 mkQNaN64(),
4213 /* non-0 means full */
4214 get_ST_UNCHECKED(i));
4215}
4216
4217
4218/* Adjust FTOP downwards by one register. */
4219
4220static void fp_push ( void )
4221{
4222 put_ftop( binop(Iop_Sub32, get_ftop(), mkU32(1)) );
4223}
4224
4225/* Adjust FTOP upwards by one register, and mark the vacated register
4226 as empty. */
4227
4228static void fp_pop ( void )
4229{
4230 put_ST_TAG(0, mkU8(0));
4231 put_ftop( binop(Iop_Add32, get_ftop(), mkU32(1)) );
4232}
4233
sewardjd20c8852005-01-20 20:04:07 +00004234//.. /* Clear the C2 bit of the FPU status register, for
4235//.. sin/cos/tan/sincos. */
4236//..
4237//.. static void clear_C2 ( void )
4238//.. {
4239//.. put_C3210( binop(Iop_And32, get_C3210(), mkU32(~X86G_FC_MASK_C2)) );
4240//.. }
4241//..
4242//..
4243//.. /* ------------------------------------------------------- */
4244//.. /* Given all that stack-mangling junk, we can now go ahead
4245//.. and describe FP instructions.
4246//.. */
4247//..
4248//.. /* ST(0) = ST(0) `op` mem64/32(addr)
4249//.. Need to check ST(0)'s tag on read, but not on write.
4250//.. */
4251//.. static
4252//.. void fp_do_op_mem_ST_0 ( IRTemp addr, UChar* op_txt, UChar* dis_buf,
4253//.. IROp op, Bool dbl )
4254//.. {
4255//.. DIP("f%s%c %s\n", op_txt, dbl?'l':'s', dis_buf);
4256//.. if (dbl) {
4257//.. put_ST_UNCHECKED(0,
4258//.. binop( op,
4259//.. get_ST(0),
4260//.. loadLE(Ity_F64,mkexpr(addr))
4261//.. ));
4262//.. } else {
4263//.. put_ST_UNCHECKED(0,
4264//.. binop( op,
4265//.. get_ST(0),
4266//.. unop(Iop_F32toF64, loadLE(Ity_F32,mkexpr(addr)))
4267//.. ));
4268//.. }
4269//.. }
4270//..
4271//..
4272//.. /* ST(0) = mem64/32(addr) `op` ST(0)
4273//.. Need to check ST(0)'s tag on read, but not on write.
4274//.. */
4275//.. static
4276//.. void fp_do_oprev_mem_ST_0 ( IRTemp addr, UChar* op_txt, UChar* dis_buf,
4277//.. IROp op, Bool dbl )
4278//.. {
4279//.. DIP("f%s%c %s\n", op_txt, dbl?'l':'s', dis_buf);
4280//.. if (dbl) {
4281//.. put_ST_UNCHECKED(0,
4282//.. binop( op,
4283//.. loadLE(Ity_F64,mkexpr(addr)),
4284//.. get_ST(0)
4285//.. ));
4286//.. } else {
4287//.. put_ST_UNCHECKED(0,
4288//.. binop( op,
4289//.. unop(Iop_F32toF64, loadLE(Ity_F32,mkexpr(addr))),
4290//.. get_ST(0)
4291//.. ));
4292//.. }
4293//.. }
sewardj37d52572005-02-25 14:22:12 +00004294
4295
4296/* ST(dst) = ST(dst) `op` ST(src).
4297 Check dst and src tags when reading but not on write.
4298*/
4299static
4300void fp_do_op_ST_ST ( HChar* op_txt, IROp op, UInt st_src, UInt st_dst,
4301 Bool pop_after )
4302{
sewardj1027dc22005-02-26 01:55:02 +00004303 DIP("f%s%s st(%u), st(%u)\n", op_txt, pop_after?"p":"", st_src, st_dst );
sewardj37d52572005-02-25 14:22:12 +00004304 put_ST_UNCHECKED(
4305 st_dst,
4306 binop(op, get_ST(st_dst), get_ST(st_src) )
4307 );
4308 if (pop_after)
4309 fp_pop();
4310}
4311
sewardjd20c8852005-01-20 20:04:07 +00004312//.. /* ST(dst) = ST(src) `op` ST(dst).
4313//.. Check dst and src tags when reading but not on write.
4314//.. */
4315//.. static
4316//.. void fp_do_oprev_ST_ST ( UChar* op_txt, IROp op, UInt st_src, UInt st_dst,
4317//.. Bool pop_after )
4318//.. {
4319//.. DIP("f%s%s st(%d), st(%d)\n", op_txt, pop_after?"p":"", st_src, st_dst );
4320//.. put_ST_UNCHECKED(
4321//.. st_dst,
4322//.. binop(op, get_ST(st_src), get_ST(st_dst) )
4323//.. );
4324//.. if (pop_after)
4325//.. fp_pop();
4326//.. }
sewardjc49ce232005-02-25 13:03:03 +00004327
4328/* %rflags(Z,P,C) = UCOMI( st(0), st(i) ) */
4329static void fp_do_ucomi_ST0_STi ( UInt i, Bool pop_after )
4330{
sewardj1027dc22005-02-26 01:55:02 +00004331 DIP("fucomi%s %%st(0),%%st(%u)\n", pop_after ? "p" : "", i);
sewardjc49ce232005-02-25 13:03:03 +00004332 /* This is a bit of a hack (and isn't really right). It sets
4333 Z,P,C,O correctly, but forces A and S to zero, whereas the Intel
4334 documentation implies A and S are unchanged.
4335 */
4336 /* It's also fishy in that it is used both for COMIP and
4337 UCOMIP, and they aren't the same (although similar). */
4338 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(AMD64G_CC_OP_COPY) ));
4339 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
4340 stmt( IRStmt_Put(
4341 OFFB_CC_DEP1,
4342 binop( Iop_And64,
4343 unop( Iop_32Uto64,
4344 binop(Iop_CmpF64, get_ST(0), get_ST(i))),
4345 mkU64(0x45)
4346 )));
4347 if (pop_after)
4348 fp_pop();
4349}
sewardj8d965312005-02-25 02:48:47 +00004350
4351
4352static
4353ULong dis_FPU ( Bool* decode_ok, Prefix pfx, ULong delta )
4354{
4355 Int len;
4356 UInt r_src, r_dst;
4357 HChar dis_buf[50];
4358 IRTemp t1, t2;
4359
4360 /* On entry, delta points at the second byte of the insn (the modrm
4361 byte).*/
4362 UChar first_opcode = getUChar(delta-1);
4363 UChar modrm = getUChar(delta+0);
4364
sewardj37d52572005-02-25 14:22:12 +00004365 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xD8 opcodes +-+-+-+-+-+-+-+ */
4366
4367 if (first_opcode == 0xD8) {
4368 if (modrm < 0xC0) {
4369
4370 /* bits 5,4,3 are an opcode extension, and the modRM also
4371 specifies an address. */
sewardj1027dc22005-02-26 01:55:02 +00004372 //IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
4373 //delta += len;
sewardj37d52572005-02-25 14:22:12 +00004374
sewardj901ed122005-02-27 13:25:31 +00004375 switch (gregLO3ofRM(modrm)) {
sewardj37d52572005-02-25 14:22:12 +00004376
sewardjd20c8852005-01-20 20:04:07 +00004377//.. case 0: /* FADD single-real */
4378//.. fp_do_op_mem_ST_0 ( addr, "add", dis_buf, Iop_AddF64, False );
4379//.. break;
4380//..
4381//.. case 1: /* FMUL single-real */
4382//.. fp_do_op_mem_ST_0 ( addr, "mul", dis_buf, Iop_MulF64, False );
4383//.. break;
4384//..
4385//.. case 2: /* FCOM single-real */
4386//.. DIP("fcoms %s\n", dis_buf);
4387//.. /* This forces C1 to zero, which isn't right. */
4388//.. put_C3210(
4389//.. binop( Iop_And32,
4390//.. binop(Iop_Shl32,
4391//.. binop(Iop_CmpF64,
4392//.. get_ST(0),
4393//.. unop(Iop_F32toF64,
4394//.. loadLE(Ity_F32,mkexpr(addr)))),
4395//.. mkU8(8)),
4396//.. mkU32(0x4500)
4397//.. ));
4398//.. break;
4399//..
4400//.. case 3: /* FCOMP single-real */
4401//.. DIP("fcomps %s\n", dis_buf);
4402//.. /* This forces C1 to zero, which isn't right. */
4403//.. put_C3210(
4404//.. binop( Iop_And32,
4405//.. binop(Iop_Shl32,
4406//.. binop(Iop_CmpF64,
4407//.. get_ST(0),
4408//.. unop(Iop_F32toF64,
4409//.. loadLE(Ity_F32,mkexpr(addr)))),
4410//.. mkU8(8)),
4411//.. mkU32(0x4500)
4412//.. ));
4413//.. fp_pop();
4414//.. break;
4415//..
4416//.. case 4: /* FSUB single-real */
4417//.. fp_do_op_mem_ST_0 ( addr, "sub", dis_buf, Iop_SubF64, False );
4418//.. break;
4419//..
4420//.. case 5: /* FSUBR single-real */
4421//.. fp_do_oprev_mem_ST_0 ( addr, "subr", dis_buf, Iop_SubF64, False );
4422//.. break;
4423//..
4424//.. case 6: /* FDIV single-real */
4425//.. fp_do_op_mem_ST_0 ( addr, "div", dis_buf, Iop_DivF64, False );
4426//.. break;
4427//..
4428//.. case 7: /* FDIVR single-real */
4429//.. fp_do_oprev_mem_ST_0 ( addr, "divr", dis_buf, Iop_DivF64, False );
4430//.. break;
sewardj37d52572005-02-25 14:22:12 +00004431
4432 default:
sewardj901ed122005-02-27 13:25:31 +00004433 vex_printf("unhandled opc_aux = 0x%2x\n", gregLO3ofRM(modrm));
sewardj37d52572005-02-25 14:22:12 +00004434 vex_printf("first_opcode == 0xD8\n");
4435 goto decode_fail;
4436 }
4437 } else {
4438 delta++;
4439 switch (modrm) {
4440
4441 case 0xC0 ... 0xC7: /* FADD %st(?),%st(0) */
4442 fp_do_op_ST_ST ( "add", Iop_AddF64, modrm - 0xC0, 0, False );
4443 break;
4444
sewardjd20c8852005-01-20 20:04:07 +00004445//.. case 0xC8 ... 0xCF: /* FMUL %st(?),%st(0) */
4446//.. fp_do_op_ST_ST ( "mul", Iop_MulF64, modrm - 0xC8, 0, False );
4447//.. break;
4448//..
4449//.. #if 1
4450//.. /* Dunno if this is right */
4451//.. case 0xD0 ... 0xD7: /* FCOM %st(?),%st(0) */
4452//.. r_dst = (UInt)modrm - 0xD0;
4453//.. DIP("fcom %%st(0),%%st(%d)\n", r_dst);
4454//.. /* This forces C1 to zero, which isn't right. */
4455//.. put_C3210(
4456//.. binop( Iop_And32,
4457//.. binop(Iop_Shl32,
4458//.. binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
4459//.. mkU8(8)),
4460//.. mkU32(0x4500)
4461//.. ));
4462//.. break;
4463//.. #endif
4464//.. #if 1
4465//.. /* Dunno if this is right */
4466//.. case 0xD8 ... 0xDF: /* FCOMP %st(?),%st(0) */
4467//.. r_dst = (UInt)modrm - 0xD8;
4468//.. DIP("fcomp %%st(0),%%st(%d)\n", r_dst);
4469//.. /* This forces C1 to zero, which isn't right. */
4470//.. put_C3210(
4471//.. binop( Iop_And32,
4472//.. binop(Iop_Shl32,
4473//.. binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
4474//.. mkU8(8)),
4475//.. mkU32(0x4500)
4476//.. ));
4477//.. fp_pop();
4478//.. break;
4479//.. #endif
4480//.. case 0xE0 ... 0xE7: /* FSUB %st(?),%st(0) */
4481//.. fp_do_op_ST_ST ( "sub", Iop_SubF64, modrm - 0xE0, 0, False );
4482//.. break;
4483//..
4484//.. case 0xE8 ... 0xEF: /* FSUBR %st(?),%st(0) */
4485//.. fp_do_oprev_ST_ST ( "subr", Iop_SubF64, modrm - 0xE8, 0, False );
4486//.. break;
4487//..
4488//.. case 0xF0 ... 0xF7: /* FDIV %st(?),%st(0) */
4489//.. fp_do_op_ST_ST ( "div", Iop_DivF64, modrm - 0xF0, 0, False );
4490//.. break;
4491//..
4492//.. case 0xF8 ... 0xFF: /* FDIVR %st(?),%st(0) */
4493//.. fp_do_oprev_ST_ST ( "divr", Iop_DivF64, modrm - 0xF8, 0, False );
4494//.. break;
sewardj37d52572005-02-25 14:22:12 +00004495
4496 default:
4497 goto decode_fail;
4498 }
4499 }
4500 }
sewardj8d965312005-02-25 02:48:47 +00004501
4502 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xD9 opcodes +-+-+-+-+-+-+-+ */
sewardj37d52572005-02-25 14:22:12 +00004503 else
sewardj8d965312005-02-25 02:48:47 +00004504 if (first_opcode == 0xD9) {
4505 if (modrm < 0xC0) {
4506
4507 /* bits 5,4,3 are an opcode extension, and the modRM also
4508 specifies an address. */
4509 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
4510 delta += len;
4511
sewardj901ed122005-02-27 13:25:31 +00004512 switch (gregLO3ofRM(modrm)) {
sewardj8d965312005-02-25 02:48:47 +00004513
sewardjc49ce232005-02-25 13:03:03 +00004514 case 0: /* FLD single-real */
4515 DIP("flds %s\n", dis_buf);
4516 fp_push();
4517 put_ST(0, unop(Iop_F32toF64,
4518 loadLE(Ity_F32, mkexpr(addr))));
4519 break;
4520
4521 case 2: /* FST single-real */
4522 DIP("fsts %s\n", dis_buf);
4523 storeLE(mkexpr(addr),
4524 binop(Iop_F64toF32, get_roundingmode(), get_ST(0)));
4525 break;
4526
4527 case 3: /* FSTP single-real */
4528 DIP("fstps %s\n", dis_buf);
4529 storeLE(mkexpr(addr),
4530 binop(Iop_F64toF32, get_roundingmode(), get_ST(0)));
4531 fp_pop();
4532 break;
4533
sewardjd20c8852005-01-20 20:04:07 +00004534//.. case 4: { /* FLDENV m108 */
4535//.. /* Uses dirty helper:
4536//.. VexEmWarn x86g_do_FLDENV ( VexGuestX86State*, Addr32 ) */
4537//.. IRTemp ew = newTemp(Ity_I32);
4538//.. IRDirty* d = unsafeIRDirty_0_N (
4539//.. 0/*regparms*/,
4540//.. "x86g_dirtyhelper_FLDENV",
4541//.. &x86g_dirtyhelper_FLDENV,
4542//.. mkIRExprVec_1( mkexpr(addr) )
4543//.. );
4544//.. d->needsBBP = True;
4545//.. d->tmp = ew;
4546//.. /* declare we're reading memory */
4547//.. d->mFx = Ifx_Read;
4548//.. d->mAddr = mkexpr(addr);
4549//.. d->mSize = 28;
4550//..
4551//.. /* declare we're writing guest state */
4552//.. d->nFxState = 5;
4553//..
4554//.. d->fxState[0].fx = Ifx_Write;
4555//.. d->fxState[0].offset = OFFB_FTOP;
4556//.. d->fxState[0].size = sizeof(UInt);
4557//..
4558//.. d->fxState[1].fx = Ifx_Write;
4559//.. d->fxState[1].offset = OFFB_FPREGS;
4560//.. d->fxState[1].size = 8 * sizeof(ULong);
4561//..
4562//.. d->fxState[2].fx = Ifx_Write;
4563//.. d->fxState[2].offset = OFFB_FPTAGS;
4564//.. d->fxState[2].size = 8 * sizeof(UChar);
4565//..
4566//.. d->fxState[3].fx = Ifx_Write;
4567//.. d->fxState[3].offset = OFFB_FPROUND;
4568//.. d->fxState[3].size = sizeof(UInt);
4569//..
4570//.. d->fxState[4].fx = Ifx_Write;
4571//.. d->fxState[4].offset = OFFB_FC3210;
4572//.. d->fxState[4].size = sizeof(UInt);
4573//..
4574//.. stmt( IRStmt_Dirty(d) );
4575//..
4576//.. /* ew contains any emulation warning we may need to
4577//.. issue. If needed, side-exit to the next insn,
4578//.. reporting the warning, so that Valgrind's dispatcher
4579//.. sees the warning. */
4580//.. put_emwarn( mkexpr(ew) );
4581//.. stmt(
4582//.. IRStmt_Exit(
4583//.. binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
4584//.. Ijk_EmWarn,
4585//.. IRConst_U32( ((Addr32)guest_eip_bbstart)+delta)
4586//.. )
4587//.. );
4588//..
4589//.. DIP("fldenv %s\n", dis_buf);
4590//.. break;
4591//.. }
4592//..
4593//.. case 5: {/* FLDCW */
4594//.. /* The only thing we observe in the control word is the
4595//.. rounding mode. Therefore, pass the 16-bit value
4596//.. (x87 native-format control word) to a clean helper,
4597//.. getting back a 64-bit value, the lower half of which
4598//.. is the FPROUND value to store, and the upper half of
4599//.. which is the emulation-warning token which may be
4600//.. generated.
4601//.. */
4602//.. /* ULong x86h_check_fldcw ( UInt ); */
4603//.. IRTemp t64 = newTemp(Ity_I64);
4604//.. IRTemp ew = newTemp(Ity_I32);
4605//.. DIP("fldcw %s\n", dis_buf);
4606//.. assign( t64, mkIRExprCCall(
4607//.. Ity_I64, 0/*regparms*/,
4608//.. "x86g_check_fldcw",
4609//.. &x86g_check_fldcw,
4610//.. mkIRExprVec_1(
4611//.. unop( Iop_16Uto32,
4612//.. loadLE(Ity_I16, mkexpr(addr)))
4613//.. )
4614//.. )
4615//.. );
4616//..
4617//.. put_fpround( unop(Iop_64to32, mkexpr(t64)) );
4618//.. assign( ew, unop(Iop_64HIto32, mkexpr(t64) ) );
4619//.. put_emwarn( mkexpr(ew) );
4620//.. /* Finally, if an emulation warning was reported,
4621//.. side-exit to the next insn, reporting the warning,
4622//.. so that Valgrind's dispatcher sees the warning. */
4623//.. stmt(
4624//.. IRStmt_Exit(
4625//.. binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
4626//.. Ijk_EmWarn,
4627//.. IRConst_U32( ((Addr32)guest_eip_bbstart)+delta)
4628//.. )
4629//.. );
4630//.. break;
4631//.. }
4632//..
4633//.. case 6: { /* FNSTENV m28 */
4634//.. /* Uses dirty helper:
4635//.. void x86g_do_FSTENV ( VexGuestX86State*, UInt ) */
4636//.. IRDirty* d = unsafeIRDirty_0_N (
4637//.. 0/*regparms*/,
4638//.. "x86g_dirtyhelper_FSTENV",
4639//.. &x86g_dirtyhelper_FSTENV,
4640//.. mkIRExprVec_1( mkexpr(addr) )
4641//.. );
4642//.. d->needsBBP = True;
4643//.. /* declare we're writing memory */
4644//.. d->mFx = Ifx_Write;
4645//.. d->mAddr = mkexpr(addr);
4646//.. d->mSize = 28;
4647//..
4648//.. /* declare we're reading guest state */
4649//.. d->nFxState = 4;
4650//..
4651//.. d->fxState[0].fx = Ifx_Read;
4652//.. d->fxState[0].offset = OFFB_FTOP;
4653//.. d->fxState[0].size = sizeof(UInt);
4654//..
4655//.. d->fxState[1].fx = Ifx_Read;
4656//.. d->fxState[1].offset = OFFB_FPTAGS;
4657//.. d->fxState[1].size = 8 * sizeof(UChar);
4658//..
4659//.. d->fxState[2].fx = Ifx_Read;
4660//.. d->fxState[2].offset = OFFB_FPROUND;
4661//.. d->fxState[2].size = sizeof(UInt);
4662//..
4663//.. d->fxState[3].fx = Ifx_Read;
4664//.. d->fxState[3].offset = OFFB_FC3210;
4665//.. d->fxState[3].size = sizeof(UInt);
4666//..
4667//.. stmt( IRStmt_Dirty(d) );
4668//..
4669//.. DIP("fnstenv %s\n", dis_buf);
4670//.. break;
4671//.. }
4672//..
4673//.. case 7: /* FNSTCW */
4674//.. /* Fake up a native x87 FPU control word. The only
4675//.. thing it depends on is FPROUND[1:0], so call a clean
4676//.. helper to cook it up. */
4677//.. /* UInt x86h_create_fpucw ( UInt fpround ) */
4678//.. DIP("fnstcw %s\n", dis_buf);
4679//.. storeLE(
4680//.. mkexpr(addr),
4681//.. unop( Iop_32to16,
4682//.. mkIRExprCCall(
4683//.. Ity_I32, 0/*regp*/,
4684//.. "x86g_create_fpucw", &x86g_create_fpucw,
4685//.. mkIRExprVec_1( get_fpround() )
4686//.. )
4687//.. )
4688//.. );
4689//.. break;
sewardj8d965312005-02-25 02:48:47 +00004690
4691 default:
sewardj901ed122005-02-27 13:25:31 +00004692 vex_printf("unhandled opc_aux = 0x%2x\n", gregLO3ofRM(modrm));
sewardj8d965312005-02-25 02:48:47 +00004693 vex_printf("first_opcode == 0xD9\n");
4694 goto decode_fail;
4695 }
4696
4697 } else {
4698 delta++;
4699 switch (modrm) {
4700
sewardjc49ce232005-02-25 13:03:03 +00004701 case 0xC0 ... 0xC7: /* FLD %st(?) */
4702 r_src = (UInt)modrm - 0xC0;
sewardj1027dc22005-02-26 01:55:02 +00004703 DIP("fld %%st(%u)\n", r_src);
sewardjc49ce232005-02-25 13:03:03 +00004704 t1 = newTemp(Ity_F64);
4705 assign(t1, get_ST(r_src));
4706 fp_push();
4707 put_ST(0, mkexpr(t1));
4708 break;
sewardj8d965312005-02-25 02:48:47 +00004709
4710 case 0xC8 ... 0xCF: /* FXCH %st(?) */
4711 r_src = (UInt)modrm - 0xC8;
sewardj1027dc22005-02-26 01:55:02 +00004712 DIP("fxch %%st(%u)\n", r_src);
sewardj8d965312005-02-25 02:48:47 +00004713 t1 = newTemp(Ity_F64);
4714 t2 = newTemp(Ity_F64);
4715 assign(t1, get_ST(0));
4716 assign(t2, get_ST(r_src));
4717 put_ST_UNCHECKED(0, mkexpr(t2));
4718 put_ST_UNCHECKED(r_src, mkexpr(t1));
4719 break;
4720
4721 case 0xE0: /* FCHS */
4722 DIP("fchs\n");
4723 put_ST_UNCHECKED(0, unop(Iop_NegF64, get_ST(0)));
4724 break;
4725
sewardjd20c8852005-01-20 20:04:07 +00004726//.. case 0xE1: /* FABS */
4727//.. DIP("fabs\n");
4728//.. put_ST_UNCHECKED(0, unop(Iop_AbsF64, get_ST(0)));
4729//.. break;
4730//..
4731//.. case 0xE5: { /* FXAM */
4732//.. /* This is an interesting one. It examines %st(0),
4733//.. regardless of whether the tag says it's empty or not.
4734//.. Here, just pass both the tag (in our format) and the
4735//.. value (as a double, actually a ULong) to a helper
4736//.. function. */
4737//.. IRExpr** args
4738//.. = mkIRExprVec_2( unop(Iop_8Uto32, get_ST_TAG(0)),
4739//.. unop(Iop_ReinterpF64asI64,
4740//.. get_ST_UNCHECKED(0)) );
4741//.. put_C3210(mkIRExprCCall(
4742//.. Ity_I32,
4743//.. 0/*regparm*/,
4744//.. "x86g_calculate_FXAM", &x86g_calculate_FXAM,
4745//.. args
4746//.. ));
4747//.. DIP("fxam\n");
4748//.. break;
4749//.. }
sewardjc49ce232005-02-25 13:03:03 +00004750
4751 case 0xE8: /* FLD1 */
4752 DIP("fld1\n");
4753 fp_push();
4754 /* put_ST(0, IRExpr_Const(IRConst_F64(1.0))); */
4755 put_ST(0, IRExpr_Const(IRConst_F64i(0x3ff0000000000000ULL)));
4756 break;
4757
sewardjd20c8852005-01-20 20:04:07 +00004758//.. case 0xE9: /* FLDL2T */
4759//.. DIP("fldl2t\n");
4760//.. fp_push();
4761//.. /* put_ST(0, IRExpr_Const(IRConst_F64(3.32192809488736234781))); */
4762//.. put_ST(0, IRExpr_Const(IRConst_F64i(0x400a934f0979a371ULL)));
4763//.. break;
4764//..
4765//.. case 0xEA: /* FLDL2E */
4766//.. DIP("fldl2e\n");
4767//.. fp_push();
4768//.. /* put_ST(0, IRExpr_Const(IRConst_F64(1.44269504088896340739))); */
4769//.. put_ST(0, IRExpr_Const(IRConst_F64i(0x3ff71547652b82feULL)));
4770//.. break;
4771//..
4772//.. case 0xEB: /* FLDPI */
4773//.. DIP("fldpi\n");
4774//.. fp_push();
4775//.. /* put_ST(0, IRExpr_Const(IRConst_F64(3.14159265358979323851))); */
4776//.. put_ST(0, IRExpr_Const(IRConst_F64i(0x400921fb54442d18ULL)));
4777//.. break;
4778//..
4779//.. case 0xEC: /* FLDLG2 */
4780//.. DIP("fldlg2\n");
4781//.. fp_push();
4782//.. /* put_ST(0, IRExpr_Const(IRConst_F64(0.301029995663981143))); */
4783//.. put_ST(0, IRExpr_Const(IRConst_F64i(0x3fd34413509f79ffULL)));
4784//.. break;
4785//..
4786//.. case 0xED: /* FLDLN2 */
4787//.. DIP("fldln2\n");
4788//.. fp_push();
4789//.. /* put_ST(0, IRExpr_Const(IRConst_F64(0.69314718055994530942))); */
4790//.. put_ST(0, IRExpr_Const(IRConst_F64i(0x3fe62e42fefa39efULL)));
4791//.. break;
sewardjc49ce232005-02-25 13:03:03 +00004792
4793 case 0xEE: /* FLDZ */
4794 DIP("fldz\n");
4795 fp_push();
4796 /* put_ST(0, IRExpr_Const(IRConst_F64(0.0))); */
4797 put_ST(0, IRExpr_Const(IRConst_F64i(0x0000000000000000ULL)));
4798 break;
4799
sewardjd20c8852005-01-20 20:04:07 +00004800//.. case 0xF0: /* F2XM1 */
4801//.. DIP("f2xm1\n");
4802//.. put_ST_UNCHECKED(0, unop(Iop_2xm1F64, get_ST(0)));
4803//.. break;
4804//..
4805//.. case 0xF1: /* FYL2X */
4806//.. DIP("fyl2x\n");
4807//.. put_ST_UNCHECKED(1, binop(Iop_Yl2xF64,
4808//.. get_ST(1), get_ST(0)));
4809//.. fp_pop();
4810//.. break;
4811//..
4812//.. case 0xF2: /* FPTAN */
4813//.. DIP("ftan\n");
4814//.. put_ST_UNCHECKED(0, unop(Iop_TanF64, get_ST(0)));
4815//.. fp_push();
4816//.. put_ST(0, IRExpr_Const(IRConst_F64(1.0)));
4817//.. clear_C2(); /* HACK */
4818//.. break;
4819//..
4820//.. case 0xF3: /* FPATAN */
4821//.. DIP("fpatan\n");
4822//.. put_ST_UNCHECKED(1, binop(Iop_AtanF64,
4823//.. get_ST(1), get_ST(0)));
4824//.. fp_pop();
4825//.. break;
4826//..
4827//.. case 0xF5: { /* FPREM1 -- IEEE compliant */
4828//.. IRTemp a1 = newTemp(Ity_F64);
4829//.. IRTemp a2 = newTemp(Ity_F64);
4830//.. DIP("fprem1\n");
4831//.. /* Do FPREM1 twice, once to get the remainder, and once
4832//.. to get the C3210 flag values. */
4833//.. assign( a1, get_ST(0) );
4834//.. assign( a2, get_ST(1) );
4835//.. put_ST_UNCHECKED(0, binop(Iop_PRem1F64,
4836//.. mkexpr(a1), mkexpr(a2)));
4837//.. put_C3210( binop(Iop_PRem1C3210F64, mkexpr(a1), mkexpr(a2)) );
4838//.. break;
4839//.. }
4840//..
4841//.. case 0xF7: /* FINCSTP */
4842//.. DIP("fprem\n");
4843//.. put_ftop( binop(Iop_Add32, get_ftop(), mkU32(1)) );
4844//.. break;
4845//..
4846//.. case 0xF8: { /* FPREM -- not IEEE compliant */
4847//.. IRTemp a1 = newTemp(Ity_F64);
4848//.. IRTemp a2 = newTemp(Ity_F64);
4849//.. DIP("fprem\n");
4850//.. /* Do FPREM twice, once to get the remainder, and once
4851//.. to get the C3210 flag values. */
4852//.. assign( a1, get_ST(0) );
4853//.. assign( a2, get_ST(1) );
4854//.. put_ST_UNCHECKED(0, binop(Iop_PRemF64,
4855//.. mkexpr(a1), mkexpr(a2)));
4856//.. put_C3210( binop(Iop_PRemC3210F64, mkexpr(a1), mkexpr(a2)) );
4857//.. break;
4858//.. }
4859//..
4860//.. case 0xF9: /* FYL2XP1 */
4861//.. DIP("fyl2xp1\n");
4862//.. put_ST_UNCHECKED(1, binop(Iop_Yl2xp1F64,
4863//.. get_ST(1), get_ST(0)));
4864//.. fp_pop();
4865//.. break;
4866//..
4867//.. case 0xFA: /* FSQRT */
4868//.. DIP("fsqrt\n");
4869//.. put_ST_UNCHECKED(0, unop(Iop_SqrtF64, get_ST(0)));
4870//.. break;
4871//..
4872//.. case 0xFB: { /* FSINCOS */
4873//.. IRTemp a1 = newTemp(Ity_F64);
4874//.. assign( a1, get_ST(0) );
4875//.. DIP("fsincos\n");
4876//.. put_ST_UNCHECKED(0, unop(Iop_SinF64, mkexpr(a1)));
4877//.. fp_push();
4878//.. put_ST(0, unop(Iop_CosF64, mkexpr(a1)));
4879//.. break;
4880//.. }
4881//..
4882//.. case 0xFC: /* FRNDINT */
4883//.. DIP("frndint\n");
4884//.. put_ST_UNCHECKED(0,
4885//.. binop(Iop_RoundF64, get_roundingmode(), get_ST(0)) );
4886//.. break;
4887//..
4888//.. case 0xFD: /* FSCALE */
4889//.. DIP("fscale\n");
4890//.. put_ST_UNCHECKED(0, binop(Iop_ScaleF64,
4891//.. get_ST(0), get_ST(1)));
4892//.. break;
4893//..
4894//.. case 0xFE: /* FSIN */
4895//.. DIP("fsin\n");
4896//.. put_ST_UNCHECKED(0, unop(Iop_SinF64, get_ST(0)));
4897//.. clear_C2(); /* HACK */
4898//.. break;
4899//..
4900//.. case 0xFF: /* FCOS */
4901//.. DIP("fcos\n");
4902//.. put_ST_UNCHECKED(0, unop(Iop_CosF64, get_ST(0)));
4903//.. clear_C2(); /* HACK */
4904//.. break;
sewardj8d965312005-02-25 02:48:47 +00004905
4906 default:
4907 goto decode_fail;
4908 }
4909 }
4910 }
4911
4912 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDA opcodes +-+-+-+-+-+-+-+ */
4913 else
4914 if (first_opcode == 0xDA) {
4915
4916 if (modrm < 0xC0) {
4917
4918 /* bits 5,4,3 are an opcode extension, and the modRM also
4919 specifies an address. */
sewardj1027dc22005-02-26 01:55:02 +00004920 //IROp fop;
4921 //IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
sewardj8d965312005-02-25 02:48:47 +00004922 delta += len;
sewardj901ed122005-02-27 13:25:31 +00004923 switch (gregLO3ofRM(modrm)) {
sewardj8d965312005-02-25 02:48:47 +00004924
sewardjd20c8852005-01-20 20:04:07 +00004925//.. case 0: /* FIADD m32int */ /* ST(0) += m32int */
4926//.. DIP("fiaddl %s\n", dis_buf);
4927//.. fop = Iop_AddF64;
4928//.. goto do_fop_m32;
4929//..
4930//.. case 1: /* FIMUL m32int */ /* ST(0) *= m32int */
4931//.. DIP("fimull %s\n", dis_buf);
4932//.. fop = Iop_MulF64;
4933//.. goto do_fop_m32;
4934//..
4935//.. case 4: /* FISUB m32int */ /* ST(0) -= m32int */
4936//.. DIP("fisubl %s\n", dis_buf);
4937//.. fop = Iop_SubF64;
4938//.. goto do_fop_m32;
4939//..
4940//.. case 5: /* FISUBR m32int */ /* ST(0) = m32int - ST(0) */
4941//.. DIP("fisubrl %s\n", dis_buf);
4942//.. fop = Iop_SubF64;
4943//.. goto do_foprev_m32;
4944//..
4945//.. case 6: /* FIDIV m32int */ /* ST(0) /= m32int */
4946//.. DIP("fisubl %s\n", dis_buf);
4947//.. fop = Iop_DivF64;
4948//.. goto do_fop_m32;
4949//..
4950//.. case 7: /* FIDIVR m32int */ /* ST(0) = m32int / ST(0) */
4951//.. DIP("fidivrl %s\n", dis_buf);
4952//.. fop = Iop_DivF64;
4953//.. goto do_foprev_m32;
4954//..
4955//.. do_fop_m32:
4956//.. put_ST_UNCHECKED(0,
4957//.. binop(fop,
4958//.. get_ST(0),
4959//.. unop(Iop_I32toF64,
4960//.. loadLE(Ity_I32, mkexpr(addr)))));
4961//.. break;
4962//..
4963//.. do_foprev_m32:
4964//.. put_ST_UNCHECKED(0,
4965//.. binop(fop,
4966//.. unop(Iop_I32toF64,
4967//.. loadLE(Ity_I32, mkexpr(addr))),
4968//.. get_ST(0)));
4969//.. break;
sewardj8d965312005-02-25 02:48:47 +00004970
4971 default:
sewardj901ed122005-02-27 13:25:31 +00004972 vex_printf("unhandled opc_aux = 0x%2x\n", gregLO3ofRM(modrm));
sewardj8d965312005-02-25 02:48:47 +00004973 vex_printf("first_opcode == 0xDA\n");
4974 goto decode_fail;
4975 }
4976
4977 } else {
4978
4979 delta++;
4980 switch (modrm) {
4981
sewardjd20c8852005-01-20 20:04:07 +00004982//.. case 0xC0 ... 0xC7: /* FCMOVB ST(i), ST(0) */
4983//.. r_src = (UInt)modrm - 0xC0;
4984//.. DIP("fcmovb %%st(%d), %%st(0)\n", r_src);
4985//.. put_ST_UNCHECKED(0,
4986//.. IRExpr_Mux0X(
4987//.. unop(Iop_1Uto8,
4988//.. mk_x86g_calculate_condition(X86CondB)),
4989//.. get_ST(0), get_ST(r_src)) );
4990//.. break;
sewardj8d965312005-02-25 02:48:47 +00004991
4992 case 0xC8 ... 0xCF: /* FCMOVE(Z) ST(i), ST(0) */
4993 r_src = (UInt)modrm - 0xC8;
sewardj1027dc22005-02-26 01:55:02 +00004994 DIP("fcmovz %%st(%u), %%st(0)\n", r_src);
sewardj8d965312005-02-25 02:48:47 +00004995 put_ST_UNCHECKED(0,
4996 IRExpr_Mux0X(
4997 unop(Iop_1Uto8,
4998 mk_amd64g_calculate_condition(AMD64CondZ)),
4999 get_ST(0), get_ST(r_src)) );
5000 break;
5001
sewardj37d52572005-02-25 14:22:12 +00005002 case 0xD0 ... 0xD7: /* FCMOVBE ST(i), ST(0) */
5003 r_src = (UInt)modrm - 0xD0;
sewardj1027dc22005-02-26 01:55:02 +00005004 DIP("fcmovbe %%st(%u), %%st(0)\n", r_src);
sewardj37d52572005-02-25 14:22:12 +00005005 put_ST_UNCHECKED(0,
5006 IRExpr_Mux0X(
5007 unop(Iop_1Uto8,
5008 mk_amd64g_calculate_condition(AMD64CondBE)),
5009 get_ST(0), get_ST(r_src)) );
5010 break;
5011
sewardjd20c8852005-01-20 20:04:07 +00005012//.. case 0xE9: /* FUCOMPP %st(0),%st(1) */
5013//.. DIP("fucompp %%st(0),%%st(1)\n");
5014//.. /* This forces C1 to zero, which isn't right. */
5015//.. put_C3210(
5016//.. binop( Iop_And32,
5017//.. binop(Iop_Shl32,
5018//.. binop(Iop_CmpF64, get_ST(0), get_ST(1)),
5019//.. mkU8(8)),
5020//.. mkU32(0x4500)
5021//.. ));
5022//.. fp_pop();
5023//.. fp_pop();
5024//.. break;
sewardj8d965312005-02-25 02:48:47 +00005025
5026 default:
5027 goto decode_fail;
5028 }
5029
5030 }
5031 }
5032
sewardjc49ce232005-02-25 13:03:03 +00005033 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDB opcodes +-+-+-+-+-+-+-+ */
5034 else
5035 if (first_opcode == 0xDB) {
5036 if (modrm < 0xC0) {
5037
5038 /* bits 5,4,3 are an opcode extension, and the modRM also
5039 specifies an address. */
5040 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
5041 delta += len;
5042
sewardj901ed122005-02-27 13:25:31 +00005043 switch (gregLO3ofRM(modrm)) {
sewardjc49ce232005-02-25 13:03:03 +00005044
sewardjd20c8852005-01-20 20:04:07 +00005045//.. case 0: /* FILD m32int */
5046//.. DIP("fildl %s\n", dis_buf);
5047//.. fp_push();
5048//.. put_ST(0, unop(Iop_I32toF64,
5049//.. loadLE(Ity_I32, mkexpr(addr))));
5050//.. break;
5051//..
5052//.. case 2: /* FIST m32 */
5053//.. DIP("fistl %s\n", dis_buf);
5054//.. storeLE( mkexpr(addr),
5055//.. binop(Iop_F64toI32, get_roundingmode(), get_ST(0)) );
5056//.. break;
sewardj37d52572005-02-25 14:22:12 +00005057
5058 case 3: /* FISTP m32 */
5059 DIP("fistpl %s\n", dis_buf);
5060 storeLE( mkexpr(addr),
5061 binop(Iop_F64toI32, get_roundingmode(), get_ST(0)) );
5062 fp_pop();
5063 break;
5064
sewardjd20c8852005-01-20 20:04:07 +00005065//.. case 5: { /* FLD extended-real */
5066//.. /* Uses dirty helper:
5067//.. ULong loadF80le ( VexGuestX86State*, UInt )
5068//.. addr holds the address. First, do a dirty call to
5069//.. get hold of the data. */
5070//.. IRTemp val = newTemp(Ity_I64);
5071//.. IRExpr** args = mkIRExprVec_1 ( mkexpr(addr) );
5072//..
5073//.. IRDirty* d = unsafeIRDirty_1_N (
5074//.. val,
5075//.. 0/*regparms*/,
5076//.. "x86g_loadF80le", &x86g_loadF80le,
5077//.. args
5078//.. );
5079//.. /* declare that we're reading memory */
5080//.. d->mFx = Ifx_Read;
5081//.. d->mAddr = mkexpr(addr);
5082//.. d->mSize = 10;
5083//..
5084//.. /* execute the dirty call, dumping the result in val. */
5085//.. stmt( IRStmt_Dirty(d) );
5086//.. fp_push();
5087//.. put_ST(0, unop(Iop_ReinterpI64asF64, mkexpr(val)));
5088//..
5089//.. DIP("fldt %s\n", dis_buf);
5090//.. break;
5091//.. }
5092//..
5093//.. case 7: { /* FSTP extended-real */
5094//.. /* Uses dirty helper: void x86g_storeF80le ( UInt, ULong ) */
5095//.. IRExpr** args
5096//.. = mkIRExprVec_2( mkexpr(addr),
5097//.. unop(Iop_ReinterpF64asI64, get_ST(0)) );
5098//..
5099//.. IRDirty* d = unsafeIRDirty_0_N (
5100//.. 0/*regparms*/,
5101//.. "x86g_storeF80le", &x86g_storeF80le,
5102//.. args
5103//.. );
5104//.. /* declare we're writing memory */
5105//.. d->mFx = Ifx_Write;
5106//.. d->mAddr = mkexpr(addr);
5107//.. d->mSize = 10;
5108//..
5109//.. /* execute the dirty call. */
5110//.. stmt( IRStmt_Dirty(d) );
5111//.. fp_pop();
5112//..
5113//.. DIP("fstpt\n %s", dis_buf);
5114//.. break;
5115//.. }
sewardjc49ce232005-02-25 13:03:03 +00005116
5117 default:
sewardj901ed122005-02-27 13:25:31 +00005118 vex_printf("unhandled opc_aux = 0x%2x\n", gregLO3ofRM(modrm));
sewardjc49ce232005-02-25 13:03:03 +00005119 vex_printf("first_opcode == 0xDB\n");
5120 goto decode_fail;
5121 }
5122
5123 } else {
5124
5125 delta++;
5126 switch (modrm) {
5127
sewardjd20c8852005-01-20 20:04:07 +00005128//.. case 0xC0 ... 0xC7: /* FCMOVNB ST(i), ST(0) */
5129//.. r_src = (UInt)modrm - 0xC0;
5130//.. DIP("fcmovnb %%st(%d), %%st(0)\n", r_src);
5131//.. put_ST_UNCHECKED(0,
5132//.. IRExpr_Mux0X(
5133//.. unop(Iop_1Uto8,
5134//.. mk_x86g_calculate_condition(X86CondNB)),
5135//.. get_ST(0), get_ST(r_src)) );
5136//.. break;
5137//..
5138//.. case 0xC8 ... 0xCF: /* FCMOVNE(NZ) ST(i), ST(0) */
5139//.. r_src = (UInt)modrm - 0xC8;
5140//.. DIP("fcmovnz %%st(%d), %%st(0)\n", r_src);
5141//.. put_ST_UNCHECKED(0,
5142//.. IRExpr_Mux0X(
5143//.. unop(Iop_1Uto8,
5144//.. mk_x86g_calculate_condition(X86CondNZ)),
5145//.. get_ST(0), get_ST(r_src)) );
5146//.. break;
5147//..
5148//.. case 0xD0 ... 0xD7: /* FCMOVNBE ST(i), ST(0) */
5149//.. r_src = (UInt)modrm - 0xD0;
5150//.. DIP("fcmovnbe %%st(%d), %%st(0)\n", r_src);
5151//.. put_ST_UNCHECKED(0,
5152//.. IRExpr_Mux0X(
5153//.. unop(Iop_1Uto8,
5154//.. mk_x86g_calculate_condition(X86CondNBE)),
5155//.. get_ST(0), get_ST(r_src)) );
5156//.. break;
5157//..
5158//.. case 0xE2:
5159//.. DIP("fnclex\n");
5160//.. break;
5161//..
5162//.. case 0xE3: {
5163//.. /* Uses dirty helper:
5164//.. void x86g_do_FINIT ( VexGuestX86State* ) */
5165//.. IRDirty* d = unsafeIRDirty_0_N (
5166//.. 0/*regparms*/,
5167//.. "x86g_dirtyhelper_FINIT",
5168//.. &x86g_dirtyhelper_FINIT,
5169//.. mkIRExprVec_0()
5170//.. );
5171//.. d->needsBBP = True;
5172//..
5173//.. /* declare we're writing guest state */
5174//.. d->nFxState = 5;
5175//..
5176//.. d->fxState[0].fx = Ifx_Write;
5177//.. d->fxState[0].offset = OFFB_FTOP;
5178//.. d->fxState[0].size = sizeof(UInt);
5179//..
5180//.. d->fxState[1].fx = Ifx_Write;
5181//.. d->fxState[1].offset = OFFB_FPREGS;
5182//.. d->fxState[1].size = 8 * sizeof(ULong);
5183//..
5184//.. d->fxState[2].fx = Ifx_Write;
5185//.. d->fxState[2].offset = OFFB_FPTAGS;
5186//.. d->fxState[2].size = 8 * sizeof(UChar);
5187//..
5188//.. d->fxState[3].fx = Ifx_Write;
5189//.. d->fxState[3].offset = OFFB_FPROUND;
5190//.. d->fxState[3].size = sizeof(UInt);
5191//..
5192//.. d->fxState[4].fx = Ifx_Write;
5193//.. d->fxState[4].offset = OFFB_FC3210;
5194//.. d->fxState[4].size = sizeof(UInt);
5195//..
5196//.. stmt( IRStmt_Dirty(d) );
5197//..
5198//.. DIP("fninit\n");
5199//.. break;
5200//.. }
sewardjc49ce232005-02-25 13:03:03 +00005201
5202 case 0xE8 ... 0xEF: /* FUCOMI %st(0),%st(?) */
5203 fp_do_ucomi_ST0_STi( (UInt)modrm - 0xE8, False );
5204 break;
5205
sewardjd20c8852005-01-20 20:04:07 +00005206//.. case 0xF0 ... 0xF7: /* FCOMI %st(0),%st(?) */
5207//.. fp_do_ucomi_ST0_STi( (UInt)modrm - 0xF0, False );
5208//.. break;
sewardjc49ce232005-02-25 13:03:03 +00005209
5210 default:
5211 goto decode_fail;
5212 }
5213 }
5214 }
5215
sewardjd20c8852005-01-20 20:04:07 +00005216//.. /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDC opcodes +-+-+-+-+-+-+-+ */
5217//.. else
5218//.. if (first_opcode == 0xDC) {
5219//.. if (modrm < 0xC0) {
5220//..
5221//.. /* bits 5,4,3 are an opcode extension, and the modRM also
5222//.. specifies an address. */
5223//.. IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5224//.. delta += len;
5225//..
5226//.. switch (gregOfRM(modrm)) {
5227//..
5228//.. case 0: /* FADD double-real */
5229//.. fp_do_op_mem_ST_0 ( addr, "add", dis_buf, Iop_AddF64, True );
5230//.. break;
5231//..
5232//.. case 1: /* FMUL double-real */
5233//.. fp_do_op_mem_ST_0 ( addr, "mul", dis_buf, Iop_MulF64, True );
5234//.. break;
5235//..
5236//.. case 2: /* FCOM double-real */
5237//.. DIP("fcoml %s\n", dis_buf);
5238//.. /* This forces C1 to zero, which isn't right. */
5239//.. put_C3210(
5240//.. binop( Iop_And32,
5241//.. binop(Iop_Shl32,
5242//.. binop(Iop_CmpF64,
5243//.. get_ST(0),
5244//.. loadLE(Ity_F64,mkexpr(addr))),
5245//.. mkU8(8)),
5246//.. mkU32(0x4500)
5247//.. ));
5248//.. break;
5249//..
5250//.. case 3: /* FCOMP double-real */
5251//.. DIP("fcompl %s\n", dis_buf);
5252//.. /* This forces C1 to zero, which isn't right. */
5253//.. put_C3210(
5254//.. binop( Iop_And32,
5255//.. binop(Iop_Shl32,
5256//.. binop(Iop_CmpF64,
5257//.. get_ST(0),
5258//.. loadLE(Ity_F64,mkexpr(addr))),
5259//.. mkU8(8)),
5260//.. mkU32(0x4500)
5261//.. ));
5262//.. fp_pop();
5263//.. break;
5264//..
5265//.. case 4: /* FSUB double-real */
5266//.. fp_do_op_mem_ST_0 ( addr, "sub", dis_buf, Iop_SubF64, True );
5267//.. break;
5268//..
5269//.. case 5: /* FSUBR double-real */
5270//.. fp_do_oprev_mem_ST_0 ( addr, "subr", dis_buf, Iop_SubF64, True );
5271//.. break;
5272//..
5273//.. case 6: /* FDIV double-real */
5274//.. fp_do_op_mem_ST_0 ( addr, "div", dis_buf, Iop_DivF64, True );
5275//.. break;
5276//..
5277//.. case 7: /* FDIVR double-real */
5278//.. fp_do_oprev_mem_ST_0 ( addr, "divr", dis_buf, Iop_DivF64, True );
5279//.. break;
5280//..
5281//.. default:
5282//.. vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
5283//.. vex_printf("first_opcode == 0xDC\n");
5284//.. goto decode_fail;
5285//.. }
5286//..
5287//.. } else {
5288//..
5289//.. delta++;
5290//.. switch (modrm) {
5291//..
5292//.. case 0xC0 ... 0xC7: /* FADD %st(0),%st(?) */
5293//.. fp_do_op_ST_ST ( "add", Iop_AddF64, 0, modrm - 0xC0, False );
5294//.. break;
5295//..
5296//.. case 0xC8 ... 0xCF: /* FMUL %st(0),%st(?) */
5297//.. fp_do_op_ST_ST ( "mul", Iop_MulF64, 0, modrm - 0xC8, False );
5298//.. break;
5299//..
5300//.. case 0xE0 ... 0xE7: /* FSUBR %st(0),%st(?) */
5301//.. fp_do_oprev_ST_ST ( "subr", Iop_SubF64, 0, modrm - 0xE0, False );
5302//.. break;
5303//..
5304//.. case 0xE8 ... 0xEF: /* FSUB %st(0),%st(?) */
5305//.. fp_do_op_ST_ST ( "sub", Iop_SubF64, 0, modrm - 0xE8, False );
5306//.. break;
5307//..
5308//.. case 0xF0 ... 0xF7: /* FDIVR %st(0),%st(?) */
5309//.. fp_do_oprev_ST_ST ( "divr", Iop_DivF64, 0, modrm - 0xF0, False );
5310//.. break;
5311//..
5312//.. case 0xF8 ... 0xFF: /* FDIV %st(0),%st(?) */
5313//.. fp_do_op_ST_ST ( "div", Iop_DivF64, 0, modrm - 0xF8, False );
5314//.. break;
5315//..
5316//.. default:
5317//.. goto decode_fail;
5318//.. }
5319//..
5320//.. }
5321//.. }
sewardj8d965312005-02-25 02:48:47 +00005322
5323 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDD opcodes +-+-+-+-+-+-+-+ */
5324 else
5325 if (first_opcode == 0xDD) {
5326
5327 if (modrm < 0xC0) {
5328
5329 /* bits 5,4,3 are an opcode extension, and the modRM also
5330 specifies an address. */
5331 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
5332 delta += len;
5333
sewardj901ed122005-02-27 13:25:31 +00005334 switch (gregLO3ofRM(modrm)) {
sewardj8d965312005-02-25 02:48:47 +00005335
5336 case 0: /* FLD double-real */
5337 DIP("fldl %s\n", dis_buf);
5338 fp_push();
5339 put_ST(0, IRExpr_LDle(Ity_F64, mkexpr(addr)));
5340 break;
5341
sewardjc49ce232005-02-25 13:03:03 +00005342 case 2: /* FST double-real */
5343 DIP("fstl %s\n", dis_buf);
5344 storeLE(mkexpr(addr), get_ST(0));
5345 break;
sewardj8d965312005-02-25 02:48:47 +00005346
5347 case 3: /* FSTP double-real */
5348 DIP("fstpl %s\n", dis_buf);
5349 storeLE(mkexpr(addr), get_ST(0));
5350 fp_pop();
5351 break;
5352
sewardjd20c8852005-01-20 20:04:07 +00005353//.. case 4: { /* FRSTOR m108 */
5354//.. /* Uses dirty helper:
5355//.. VexEmWarn x86g_do_FRSTOR ( VexGuestX86State*, Addr32 ) */
5356//.. IRTemp ew = newTemp(Ity_I32);
5357//.. IRDirty* d = unsafeIRDirty_0_N (
5358//.. 0/*regparms*/,
5359//.. "x86g_dirtyhelper_FRSTOR",
5360//.. &x86g_dirtyhelper_FRSTOR,
5361//.. mkIRExprVec_1( mkexpr(addr) )
5362//.. );
5363//.. d->needsBBP = True;
5364//.. d->tmp = ew;
5365//.. /* declare we're reading memory */
5366//.. d->mFx = Ifx_Read;
5367//.. d->mAddr = mkexpr(addr);
5368//.. d->mSize = 108;
5369//..
5370//.. /* declare we're writing guest state */
5371//.. d->nFxState = 5;
5372//..
5373//.. d->fxState[0].fx = Ifx_Write;
5374//.. d->fxState[0].offset = OFFB_FTOP;
5375//.. d->fxState[0].size = sizeof(UInt);
5376//..
5377//.. d->fxState[1].fx = Ifx_Write;
5378//.. d->fxState[1].offset = OFFB_FPREGS;
5379//.. d->fxState[1].size = 8 * sizeof(ULong);
5380//..
5381//.. d->fxState[2].fx = Ifx_Write;
5382//.. d->fxState[2].offset = OFFB_FPTAGS;
5383//.. d->fxState[2].size = 8 * sizeof(UChar);
5384//..
5385//.. d->fxState[3].fx = Ifx_Write;
5386//.. d->fxState[3].offset = OFFB_FPROUND;
5387//.. d->fxState[3].size = sizeof(UInt);
5388//..
5389//.. d->fxState[4].fx = Ifx_Write;
5390//.. d->fxState[4].offset = OFFB_FC3210;
5391//.. d->fxState[4].size = sizeof(UInt);
5392//..
5393//.. stmt( IRStmt_Dirty(d) );
5394//..
5395//.. /* ew contains any emulation warning we may need to
5396//.. issue. If needed, side-exit to the next insn,
5397//.. reporting the warning, so that Valgrind's dispatcher
5398//.. sees the warning. */
5399//.. put_emwarn( mkexpr(ew) );
5400//.. stmt(
5401//.. IRStmt_Exit(
5402//.. binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
5403//.. Ijk_EmWarn,
5404//.. IRConst_U32( ((Addr32)guest_eip_bbstart)+delta)
5405//.. )
5406//.. );
5407//..
5408//.. DIP("frstor %s\n", dis_buf);
5409//.. break;
5410//.. }
5411//..
5412//.. case 6: { /* FNSAVE m108 */
5413//.. /* Uses dirty helper:
5414//.. void x86g_do_FSAVE ( VexGuestX86State*, UInt ) */
5415//.. IRDirty* d = unsafeIRDirty_0_N (
5416//.. 0/*regparms*/,
5417//.. "x86g_dirtyhelper_FSAVE",
5418//.. &x86g_dirtyhelper_FSAVE,
5419//.. mkIRExprVec_1( mkexpr(addr) )
5420//.. );
5421//.. d->needsBBP = True;
5422//.. /* declare we're writing memory */
5423//.. d->mFx = Ifx_Write;
5424//.. d->mAddr = mkexpr(addr);
5425//.. d->mSize = 108;
5426//..
5427//.. /* declare we're reading guest state */
5428//.. d->nFxState = 5;
5429//..
5430//.. d->fxState[0].fx = Ifx_Read;
5431//.. d->fxState[0].offset = OFFB_FTOP;
5432//.. d->fxState[0].size = sizeof(UInt);
5433//..
5434//.. d->fxState[1].fx = Ifx_Read;
5435//.. d->fxState[1].offset = OFFB_FPREGS;
5436//.. d->fxState[1].size = 8 * sizeof(ULong);
5437//..
5438//.. d->fxState[2].fx = Ifx_Read;
5439//.. d->fxState[2].offset = OFFB_FPTAGS;
5440//.. d->fxState[2].size = 8 * sizeof(UChar);
5441//..
5442//.. d->fxState[3].fx = Ifx_Read;
5443//.. d->fxState[3].offset = OFFB_FPROUND;
5444//.. d->fxState[3].size = sizeof(UInt);
5445//..
5446//.. d->fxState[4].fx = Ifx_Read;
5447//.. d->fxState[4].offset = OFFB_FC3210;
5448//.. d->fxState[4].size = sizeof(UInt);
5449//..
5450//.. stmt( IRStmt_Dirty(d) );
5451//..
5452//.. DIP("fnsave %s\n", dis_buf);
5453//.. break;
5454//.. }
sewardj8d965312005-02-25 02:48:47 +00005455
5456 default:
sewardj901ed122005-02-27 13:25:31 +00005457 vex_printf("unhandled opc_aux = 0x%2x\n", gregLO3ofRM(modrm));
sewardj8d965312005-02-25 02:48:47 +00005458 vex_printf("first_opcode == 0xDD\n");
5459 goto decode_fail;
5460 }
5461 } else {
5462 delta++;
5463 switch (modrm) {
5464
sewardjd20c8852005-01-20 20:04:07 +00005465//.. case 0xD0 ... 0xD7: /* FST %st(0),%st(?) */
5466//.. r_dst = (UInt)modrm - 0xD0;
5467//.. DIP("fst %%st(0),%%st(%d)\n", r_dst);
5468//.. /* P4 manual says: "If the destination operand is a
5469//.. non-empty register, the invalid-operation exception
5470//.. is not generated. Hence put_ST_UNCHECKED. */
5471//.. put_ST_UNCHECKED(r_dst, get_ST(0));
5472//.. break;
sewardj8d965312005-02-25 02:48:47 +00005473
5474 case 0xD8 ... 0xDF: /* FSTP %st(0),%st(?) */
5475 r_dst = (UInt)modrm - 0xD8;
sewardj1027dc22005-02-26 01:55:02 +00005476 DIP("fstp %%st(0),%%st(%u)\n", r_dst);
sewardj8d965312005-02-25 02:48:47 +00005477 /* P4 manual says: "If the destination operand is a
5478 non-empty register, the invalid-operation exception
5479 is not generated. Hence put_ST_UNCHECKED. */
5480 put_ST_UNCHECKED(r_dst, get_ST(0));
5481 fp_pop();
5482 break;
5483
sewardjd20c8852005-01-20 20:04:07 +00005484//.. case 0xE0 ... 0xE7: /* FUCOM %st(0),%st(?) */
5485//.. r_dst = (UInt)modrm - 0xE0;
5486//.. DIP("fucom %%st(0),%%st(%d)\n", r_dst);
5487//.. /* This forces C1 to zero, which isn't right. */
5488//.. put_C3210(
5489//.. binop( Iop_And32,
5490//.. binop(Iop_Shl32,
5491//.. binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
5492//.. mkU8(8)),
5493//.. mkU32(0x4500)
5494//.. ));
5495//.. break;
5496//..
5497//.. case 0xE8 ... 0xEF: /* FUCOMP %st(0),%st(?) */
5498//.. r_dst = (UInt)modrm - 0xE8;
5499//.. DIP("fucomp %%st(0),%%st(%d)\n", r_dst);
5500//.. /* This forces C1 to zero, which isn't right. */
5501//.. put_C3210(
5502//.. binop( Iop_And32,
5503//.. binop(Iop_Shl32,
5504//.. binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
5505//.. mkU8(8)),
5506//.. mkU32(0x4500)
5507//.. ));
5508//.. fp_pop();
5509//.. break;
sewardj8d965312005-02-25 02:48:47 +00005510
5511 default:
5512 goto decode_fail;
5513 }
5514 }
5515 }
5516
sewardjd20c8852005-01-20 20:04:07 +00005517//.. /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDE opcodes +-+-+-+-+-+-+-+ */
5518//.. else
5519//.. if (first_opcode == 0xDE) {
5520//..
5521//.. if (modrm < 0xC0) {
5522//..
5523//.. /* bits 5,4,3 are an opcode extension, and the modRM also
5524//.. specifies an address. */
5525//.. IROp fop;
5526//.. IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5527//.. delta += len;
5528//..
5529//.. switch (gregOfRM(modrm)) {
5530//..
5531//.. case 0: /* FIADD m16int */ /* ST(0) += m16int */
5532//.. DIP("fiaddw %s\n", dis_buf);
5533//.. fop = Iop_AddF64;
5534//.. goto do_fop_m16;
5535//..
5536//.. case 1: /* FIMUL m16int */ /* ST(0) *= m16int */
5537//.. DIP("fimulw %s\n", dis_buf);
5538//.. fop = Iop_MulF64;
5539//.. goto do_fop_m16;
5540//..
5541//.. case 4: /* FISUB m16int */ /* ST(0) -= m16int */
5542//.. DIP("fisubw %s\n", dis_buf);
5543//.. fop = Iop_SubF64;
5544//.. goto do_fop_m16;
5545//..
5546//.. case 5: /* FISUBR m16int */ /* ST(0) = m16int - ST(0) */
5547//.. DIP("fisubrw %s\n", dis_buf);
5548//.. fop = Iop_SubF64;
5549//.. goto do_foprev_m16;
5550//..
5551//.. case 6: /* FIDIV m16int */ /* ST(0) /= m16int */
5552//.. DIP("fisubw %s\n", dis_buf);
5553//.. fop = Iop_DivF64;
5554//.. goto do_fop_m16;
5555//..
5556//.. case 7: /* FIDIVR m16int */ /* ST(0) = m16int / ST(0) */
5557//.. DIP("fidivrw %s\n", dis_buf);
5558//.. fop = Iop_DivF64;
5559//.. goto do_foprev_m16;
5560//..
5561//.. do_fop_m16:
5562//.. put_ST_UNCHECKED(0,
5563//.. binop(fop,
5564//.. get_ST(0),
5565//.. unop(Iop_I32toF64,
5566//.. unop(Iop_16Sto32,
5567//.. loadLE(Ity_I16, mkexpr(addr))))));
5568//.. break;
5569//..
5570//.. do_foprev_m16:
5571//.. put_ST_UNCHECKED(0,
5572//.. binop(fop,
5573//.. unop(Iop_I32toF64,
5574//.. unop(Iop_16Sto32,
5575//.. loadLE(Ity_I16, mkexpr(addr)))),
5576//.. get_ST(0)));
5577//.. break;
5578//..
5579//.. default:
5580//.. vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
5581//.. vex_printf("first_opcode == 0xDE\n");
5582//.. goto decode_fail;
5583//.. }
5584//..
5585//.. } else {
5586//..
5587//.. delta++;
5588//.. switch (modrm) {
5589//..
5590//.. case 0xC0 ... 0xC7: /* FADDP %st(0),%st(?) */
5591//.. fp_do_op_ST_ST ( "add", Iop_AddF64, 0, modrm - 0xC0, True );
5592//.. break;
5593//..
5594//.. case 0xC8 ... 0xCF: /* FMULP %st(0),%st(?) */
5595//.. fp_do_op_ST_ST ( "mul", Iop_MulF64, 0, modrm - 0xC8, True );
5596//.. break;
5597//..
5598//.. case 0xD9: /* FCOMPP %st(0),%st(1) */
5599//.. DIP("fuompp %%st(0),%%st(1)\n");
5600//.. /* This forces C1 to zero, which isn't right. */
5601//.. put_C3210(
5602//.. binop( Iop_And32,
5603//.. binop(Iop_Shl32,
5604//.. binop(Iop_CmpF64, get_ST(0), get_ST(1)),
5605//.. mkU8(8)),
5606//.. mkU32(0x4500)
5607//.. ));
5608//.. fp_pop();
5609//.. fp_pop();
5610//.. break;
5611//..
5612//.. case 0xE0 ... 0xE7: /* FSUBRP %st(0),%st(?) */
5613//.. fp_do_oprev_ST_ST ( "subr", Iop_SubF64, 0, modrm - 0xE0, True );
5614//.. break;
5615//..
5616//.. case 0xE8 ... 0xEF: /* FSUBP %st(0),%st(?) */
5617//.. fp_do_op_ST_ST ( "sub", Iop_SubF64, 0, modrm - 0xE8, True );
5618//.. break;
5619//..
5620//.. case 0xF0 ... 0xF7: /* FDIVRP %st(0),%st(?) */
5621//.. fp_do_oprev_ST_ST ( "divr", Iop_DivF64, 0, modrm - 0xF0, True );
5622//.. break;
5623//..
5624//.. case 0xF8 ... 0xFF: /* FDIVP %st(0),%st(?) */
5625//.. fp_do_op_ST_ST ( "div", Iop_DivF64, 0, modrm - 0xF8, True );
5626//.. break;
5627//..
5628//.. default:
5629//.. goto decode_fail;
5630//.. }
5631//..
5632//.. }
5633//.. }
sewardjc49ce232005-02-25 13:03:03 +00005634
5635 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDF opcodes +-+-+-+-+-+-+-+ */
5636 else
5637 if (first_opcode == 0xDF) {
5638
5639 if (modrm < 0xC0) {
5640
5641 /* bits 5,4,3 are an opcode extension, and the modRM also
5642 specifies an address. */
5643 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
5644 delta += len;
5645
sewardj901ed122005-02-27 13:25:31 +00005646 switch (gregLO3ofRM(modrm)) {
sewardjc49ce232005-02-25 13:03:03 +00005647
sewardjd20c8852005-01-20 20:04:07 +00005648//.. case 0: /* FILD m16int */
5649//.. DIP("fildw %s\n", dis_buf);
5650//.. fp_push();
5651//.. put_ST(0, unop(Iop_I32toF64,
5652//.. unop(Iop_16Sto32,
5653//.. loadLE(Ity_I16, mkexpr(addr)))));
5654//.. break;
5655//..
5656//.. case 2: /* FIST m16 */
5657//.. DIP("fistp %s\n", dis_buf);
5658//.. storeLE( mkexpr(addr),
5659//.. binop(Iop_F64toI16, get_roundingmode(), get_ST(0)) );
5660//.. break;
5661//..
5662//.. case 3: /* FISTP m16 */
5663//.. DIP("fistps %s\n", dis_buf);
5664//.. storeLE( mkexpr(addr),
5665//.. binop(Iop_F64toI16, get_roundingmode(), get_ST(0)) );
5666//.. fp_pop();
5667//.. break;
sewardj37d52572005-02-25 14:22:12 +00005668
5669 case 5: /* FILD m64 */
5670 DIP("fildll %s\n", dis_buf);
5671 fp_push();
5672 put_ST(0, binop(Iop_I64toF64,
5673 get_roundingmode(),
5674 loadLE(Ity_I64, mkexpr(addr))));
5675 break;
5676
sewardjd20c8852005-01-20 20:04:07 +00005677//.. case 7: /* FISTP m64 */
5678//.. DIP("fistpll %s\n", dis_buf);
5679//.. storeLE( mkexpr(addr),
5680//.. binop(Iop_F64toI64, get_roundingmode(), get_ST(0)) );
5681//.. fp_pop();
5682//.. break;
sewardjc49ce232005-02-25 13:03:03 +00005683
5684 default:
sewardj901ed122005-02-27 13:25:31 +00005685 vex_printf("unhandled opc_aux = 0x%2x\n", gregLO3ofRM(modrm));
sewardjc49ce232005-02-25 13:03:03 +00005686 vex_printf("first_opcode == 0xDF\n");
5687 goto decode_fail;
5688 }
5689
5690 } else {
5691
5692 delta++;
5693 switch (modrm) {
5694
5695 case 0xC0: /* FFREEP %st(0) */
5696 DIP("ffreep %%st(%d)\n", 0);
5697 put_ST_TAG ( 0, mkU8(0) );
5698 fp_pop();
5699 break;
5700
sewardjd20c8852005-01-20 20:04:07 +00005701//.. case 0xE0: /* FNSTSW %ax */
5702//.. DIP("fnstsw %%ax\n");
5703//.. /* Invent a plausible-looking FPU status word value and
5704//.. dump it in %AX:
5705//.. ((ftop & 7) << 11) | (c3210 & 0x4700)
5706//.. */
5707//.. putIReg(2, R_EAX,
5708//.. unop(Iop_32to16,
5709//.. binop(Iop_Or32,
5710//.. binop(Iop_Shl32,
5711//.. binop(Iop_And32, get_ftop(), mkU32(7)),
5712//.. mkU8(11)),
5713//.. binop(Iop_And32, get_C3210(), mkU32(0x4700))
5714//.. )));
5715//.. break;
5716//..
5717//.. case 0xE8 ... 0xEF: /* FUCOMIP %st(0),%st(?) */
5718//.. fp_do_ucomi_ST0_STi( (UInt)modrm - 0xE8, True );
5719//.. break;
5720//..
5721//.. case 0xF0 ... 0xF7: /* FCOMIP %st(0),%st(?) */
5722//.. /* not really right since COMIP != UCOMIP */
5723//.. fp_do_ucomi_ST0_STi( (UInt)modrm - 0xF0, True );
5724//.. break;
sewardjc49ce232005-02-25 13:03:03 +00005725
5726 default:
5727 goto decode_fail;
5728 }
5729 }
5730
5731 }
sewardj8d965312005-02-25 02:48:47 +00005732
5733 else
5734 goto decode_fail; //vpanic("dis_FPU(amd64): invalid primary opcode");
5735
5736 *decode_ok = True;
5737 return delta;
5738
5739 decode_fail:
5740 *decode_ok = False;
5741 return delta;
5742}
5743
5744
sewardjd20c8852005-01-20 20:04:07 +00005745//.. /*------------------------------------------------------------*/
5746//.. /*--- ---*/
5747//.. /*--- MMX INSTRUCTIONS ---*/
5748//.. /*--- ---*/
5749//.. /*------------------------------------------------------------*/
5750//..
5751//.. /* Effect of MMX insns on x87 FPU state (table 11-2 of
5752//.. IA32 arch manual, volume 3):
5753//..
5754//.. Read from, or write to MMX register (viz, any insn except EMMS):
5755//.. * All tags set to Valid (non-empty) -- FPTAGS[i] := nonzero
5756//.. * FP stack pointer set to zero
5757//..
5758//.. EMMS:
5759//.. * All tags set to Invalid (empty) -- FPTAGS[i] := zero
5760//.. * FP stack pointer set to zero
5761//.. */
5762//..
5763//.. static void do_MMX_preamble ( void )
5764//.. {
5765//.. Int i;
5766//.. IRArray* descr = mkIRArray( OFFB_FPTAGS, Ity_I8, 8 );
5767//.. IRExpr* zero = mkU32(0);
5768//.. IRExpr* tag1 = mkU8(1);
5769//.. put_ftop(zero);
5770//.. for (i = 0; i < 8; i++)
5771//.. stmt( IRStmt_PutI( descr, zero, i, tag1 ) );
5772//.. }
5773//..
5774//.. static void do_EMMS_preamble ( void )
5775//.. {
5776//.. Int i;
5777//.. IRArray* descr = mkIRArray( OFFB_FPTAGS, Ity_I8, 8 );
5778//.. IRExpr* zero = mkU32(0);
5779//.. IRExpr* tag0 = mkU8(0);
5780//.. put_ftop(zero);
5781//.. for (i = 0; i < 8; i++)
5782//.. stmt( IRStmt_PutI( descr, zero, i, tag0 ) );
5783//.. }
5784//..
5785//..
5786//.. static IRExpr* getMMXReg ( UInt archreg )
5787//.. {
5788//.. vassert(archreg < 8);
5789//.. return IRExpr_Get( OFFB_FPREGS + 8 * archreg, Ity_I64 );
5790//.. }
5791//..
5792//..
5793//.. static void putMMXReg ( UInt archreg, IRExpr* e )
5794//.. {
5795//.. vassert(archreg < 8);
5796//.. vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_I64);
5797//.. stmt( IRStmt_Put( OFFB_FPREGS + 8 * archreg, e ) );
5798//.. }
5799//..
5800//..
5801//.. /* Helper for non-shift MMX insns. Note this is incomplete in the
5802//.. sense that it does not first call do_MMX_preamble() -- that is the
5803//.. responsibility of its caller. */
5804//..
5805//.. static
5806//.. UInt dis_MMXop_regmem_to_reg ( UChar sorb,
5807//.. UInt delta,
5808//.. UChar opc,
5809//.. Char* name,
5810//.. Bool show_granularity )
5811//.. {
5812//.. HChar dis_buf[50];
sewardj8c332e22005-01-28 01:36:56 +00005813//.. UChar modrm = getUChar(delta);
sewardjd20c8852005-01-20 20:04:07 +00005814//.. Bool isReg = epartIsReg(modrm);
5815//.. IRExpr* argL = NULL;
5816//.. IRExpr* argR = NULL;
5817//.. IRExpr* argG = NULL;
5818//.. IRExpr* argE = NULL;
5819//.. IRTemp res = newTemp(Ity_I64);
5820//..
5821//.. Bool invG = False;
5822//.. IROp op = Iop_INVALID;
5823//.. void* hAddr = NULL;
5824//.. Char* hName = NULL;
5825//.. Bool eLeft = False;
5826//..
5827//.. # define XXX(_name) do { hAddr = &_name; hName = #_name; } while (0)
5828//..
5829//.. switch (opc) {
5830//.. /* Original MMX ones */
5831//.. case 0xFC: op = Iop_Add8x8; break;
5832//.. case 0xFD: op = Iop_Add16x4; break;
5833//.. case 0xFE: op = Iop_Add32x2; break;
5834//..
5835//.. case 0xEC: op = Iop_QAdd8Sx8; break;
5836//.. case 0xED: op = Iop_QAdd16Sx4; break;
5837//..
5838//.. case 0xDC: op = Iop_QAdd8Ux8; break;
5839//.. case 0xDD: op = Iop_QAdd16Ux4; break;
5840//..
5841//.. case 0xF8: op = Iop_Sub8x8; break;
5842//.. case 0xF9: op = Iop_Sub16x4; break;
5843//.. case 0xFA: op = Iop_Sub32x2; break;
5844//..
5845//.. case 0xE8: op = Iop_QSub8Sx8; break;
5846//.. case 0xE9: op = Iop_QSub16Sx4; break;
5847//..
5848//.. case 0xD8: op = Iop_QSub8Ux8; break;
5849//.. case 0xD9: op = Iop_QSub16Ux4; break;
5850//..
5851//.. case 0xE5: op = Iop_MulHi16Sx4; break;
5852//.. case 0xD5: op = Iop_Mul16x4; break;
5853//.. case 0xF5: XXX(x86g_calculate_mmx_pmaddwd); break;
5854//..
5855//.. case 0x74: op = Iop_CmpEQ8x8; break;
5856//.. case 0x75: op = Iop_CmpEQ16x4; break;
5857//.. case 0x76: op = Iop_CmpEQ32x2; break;
5858//..
5859//.. case 0x64: op = Iop_CmpGT8Sx8; break;
5860//.. case 0x65: op = Iop_CmpGT16Sx4; break;
5861//.. case 0x66: op = Iop_CmpGT32Sx2; break;
5862//..
5863//.. case 0x6B: op = Iop_QNarrow32Sx2; eLeft = True; break;
5864//.. case 0x63: op = Iop_QNarrow16Sx4; eLeft = True; break;
5865//.. case 0x67: op = Iop_QNarrow16Ux4; eLeft = True; break;
5866//..
5867//.. case 0x68: op = Iop_InterleaveHI8x8; eLeft = True; break;
5868//.. case 0x69: op = Iop_InterleaveHI16x4; eLeft = True; break;
5869//.. case 0x6A: op = Iop_InterleaveHI32x2; eLeft = True; break;
5870//..
5871//.. case 0x60: op = Iop_InterleaveLO8x8; eLeft = True; break;
5872//.. case 0x61: op = Iop_InterleaveLO16x4; eLeft = True; break;
5873//.. case 0x62: op = Iop_InterleaveLO32x2; eLeft = True; break;
5874//..
5875//.. case 0xDB: op = Iop_And64; break;
5876//.. case 0xDF: op = Iop_And64; invG = True; break;
5877//.. case 0xEB: op = Iop_Or64; break;
5878//.. case 0xEF: /* Possibly do better here if argL and argR are the
5879//.. same reg */
5880//.. op = Iop_Xor64; break;
5881//..
5882//.. /* Introduced in SSE1 */
5883//.. case 0xE0: op = Iop_Avg8Ux8; break;
5884//.. case 0xE3: op = Iop_Avg16Ux4; break;
5885//.. case 0xEE: op = Iop_Max16Sx4; break;
5886//.. case 0xDE: op = Iop_Max8Ux8; break;
5887//.. case 0xEA: op = Iop_Min16Sx4; break;
5888//.. case 0xDA: op = Iop_Min8Ux8; break;
5889//.. case 0xE4: op = Iop_MulHi16Ux4; break;
5890//.. case 0xF6: XXX(x86g_calculate_mmx_psadbw); break;
5891//..
5892//.. /* Introduced in SSE2 */
5893//.. case 0xD4: op = Iop_Add64; break;
5894//.. case 0xFB: op = Iop_Sub64; break;
5895//..
5896//.. default:
5897//.. vex_printf("\n0x%x\n", (Int)opc);
5898//.. vpanic("dis_MMXop_regmem_to_reg");
5899//.. }
5900//..
5901//.. # undef XXX
5902//..
5903//.. argG = getMMXReg(gregOfRM(modrm));
5904//.. if (invG)
5905//.. argG = unop(Iop_Not64, argG);
5906//..
5907//.. if (isReg) {
5908//.. delta++;
5909//.. argE = getMMXReg(eregOfRM(modrm));
5910//.. } else {
5911//.. Int len;
5912//.. IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5913//.. delta += len;
5914//.. argE = loadLE(Ity_I64, mkexpr(addr));
5915//.. }
5916//..
5917//.. if (eLeft) {
5918//.. argL = argE;
5919//.. argR = argG;
5920//.. } else {
5921//.. argL = argG;
5922//.. argR = argE;
5923//.. }
5924//..
5925//.. if (op != Iop_INVALID) {
5926//.. vassert(hName == NULL);
5927//.. vassert(hAddr == NULL);
5928//.. assign(res, binop(op, argL, argR));
5929//.. } else {
5930//.. vassert(hName != NULL);
5931//.. vassert(hAddr != NULL);
5932//.. assign( res,
5933//.. mkIRExprCCall(
5934//.. Ity_I64,
5935//.. 0/*regparms*/, hName, hAddr,
5936//.. mkIRExprVec_2( argL, argR )
5937//.. )
5938//.. );
5939//.. }
5940//..
5941//.. putMMXReg( gregOfRM(modrm), mkexpr(res) );
5942//..
5943//.. DIP("%s%s %s, %s\n",
5944//.. name, show_granularity ? nameMMXGran(opc & 3) : (Char*)"",
5945//.. ( isReg ? nameMMXReg(eregOfRM(modrm)) : dis_buf ),
5946//.. nameMMXReg(gregOfRM(modrm)) );
5947//..
5948//.. return delta;
5949//.. }
5950//..
5951//..
5952//.. /* Vector by scalar shift of G by the amount specified at the bottom
5953//.. of E. This is a straight copy of dis_SSE_shiftG_byE. */
5954//..
sewardj9da16972005-02-21 13:58:26 +00005955//.. static UInt dis_MMX_shiftG_byE ( UChar sorb, ULong delta,
sewardjd20c8852005-01-20 20:04:07 +00005956//.. HChar* opname, IROp op )
5957//.. {
5958//.. HChar dis_buf[50];
5959//.. Int alen, size;
5960//.. IRTemp addr;
5961//.. Bool shl, shr, sar;
sewardj8c332e22005-01-28 01:36:56 +00005962//.. UChar rm = getUChar(delta);
sewardjd20c8852005-01-20 20:04:07 +00005963//.. IRTemp g0 = newTemp(Ity_I64);
5964//.. IRTemp g1 = newTemp(Ity_I64);
5965//.. IRTemp amt = newTemp(Ity_I32);
5966//.. IRTemp amt8 = newTemp(Ity_I8);
5967//..
5968//.. if (epartIsReg(rm)) {
5969//.. assign( amt, unop(Iop_64to32, getMMXReg(eregOfRM(rm))) );
5970//.. DIP("%s %s,%s\n", opname,
5971//.. nameMMXReg(eregOfRM(rm)),
5972//.. nameMMXReg(gregOfRM(rm)) );
5973//.. delta++;
5974//.. } else {
5975//.. addr = disAMode ( &alen, sorb, delta, dis_buf );
5976//.. assign( amt, loadLE(Ity_I32, mkexpr(addr)) );
5977//.. DIP("%s %s,%s\n", opname,
5978//.. dis_buf,
5979//.. nameMMXReg(gregOfRM(rm)) );
5980//.. delta += alen;
5981//.. }
5982//.. assign( g0, getMMXReg(gregOfRM(rm)) );
5983//.. assign( amt8, unop(Iop_32to8, mkexpr(amt)) );
5984//..
5985//.. shl = shr = sar = False;
5986//.. size = 0;
5987//.. switch (op) {
5988//.. case Iop_ShlN16x4: shl = True; size = 32; break;
5989//.. case Iop_ShlN32x2: shl = True; size = 32; break;
5990//.. case Iop_Shl64: shl = True; size = 64; break;
5991//.. case Iop_ShrN16x4: shr = True; size = 16; break;
5992//.. case Iop_ShrN32x2: shr = True; size = 32; break;
5993//.. case Iop_Shr64: shr = True; size = 64; break;
5994//.. case Iop_SarN16x4: sar = True; size = 16; break;
5995//.. case Iop_SarN32x2: sar = True; size = 32; break;
5996//.. default: vassert(0);
5997//.. }
5998//..
5999//.. if (shl || shr) {
6000//.. assign(
6001//.. g1,
6002//.. IRExpr_Mux0X(
6003//.. unop(Iop_1Uto8,binop(Iop_CmpLT32U,mkexpr(amt),mkU32(size))),
6004//.. mkU64(0),
6005//.. binop(op, mkexpr(g0), mkexpr(amt8))
6006//.. )
6007//.. );
6008//.. } else
6009//.. if (sar) {
6010//.. assign(
6011//.. g1,
6012//.. IRExpr_Mux0X(
6013//.. unop(Iop_1Uto8,binop(Iop_CmpLT32U,mkexpr(amt),mkU32(size))),
6014//.. binop(op, mkexpr(g0), mkU8(size-1)),
6015//.. binop(op, mkexpr(g0), mkexpr(amt8))
6016//.. )
6017//.. );
6018//.. } else {
6019//.. vassert(0);
6020//.. }
6021//..
6022//.. putMMXReg( gregOfRM(rm), mkexpr(g1) );
6023//.. return delta;
6024//.. }
6025//..
6026//..
6027//.. /* Vector by scalar shift of E by an immediate byte. This is a
6028//.. straight copy of dis_SSE_shiftE_imm. */
6029//..
6030//.. static
sewardj9da16972005-02-21 13:58:26 +00006031//.. UInt dis_MMX_shiftE_imm ( ULong delta, HChar* opname, IROp op )
sewardjd20c8852005-01-20 20:04:07 +00006032//.. {
6033//.. Bool shl, shr, sar;
sewardj8c332e22005-01-28 01:36:56 +00006034//.. UChar rm = getUChar(delta);
sewardjd20c8852005-01-20 20:04:07 +00006035//.. IRTemp e0 = newTemp(Ity_I64);
6036//.. IRTemp e1 = newTemp(Ity_I64);
6037//.. UChar amt, size;
6038//.. vassert(epartIsReg(rm));
6039//.. vassert(gregOfRM(rm) == 2
6040//.. || gregOfRM(rm) == 4 || gregOfRM(rm) == 6);
sewardj8c332e22005-01-28 01:36:56 +00006041//.. amt = (Int)(getUChar(delta+1));
sewardjd20c8852005-01-20 20:04:07 +00006042//.. delta += 2;
6043//.. DIP("%s $%d,%s\n", opname,
6044//.. (Int)amt,
6045//.. nameMMXReg(eregOfRM(rm)) );
6046//..
6047//.. assign( e0, getMMXReg(eregOfRM(rm)) );
6048//..
6049//.. shl = shr = sar = False;
6050//.. size = 0;
6051//.. switch (op) {
6052//.. case Iop_ShlN16x4: shl = True; size = 16; break;
6053//.. case Iop_ShlN32x2: shl = True; size = 32; break;
6054//.. case Iop_Shl64: shl = True; size = 64; break;
6055//.. case Iop_SarN16x4: sar = True; size = 16; break;
6056//.. case Iop_SarN32x2: sar = True; size = 32; break;
6057//.. case Iop_ShrN16x4: shr = True; size = 16; break;
6058//.. case Iop_ShrN32x2: shr = True; size = 32; break;
6059//.. case Iop_Shr64: shr = True; size = 64; break;
6060//.. default: vassert(0);
6061//.. }
6062//..
6063//.. if (shl || shr) {
6064//.. assign( e1, amt >= size
6065//.. ? mkU64(0)
6066//.. : binop(op, mkexpr(e0), mkU8(amt))
6067//.. );
6068//.. } else
6069//.. if (sar) {
6070//.. assign( e1, amt >= size
6071//.. ? binop(op, mkexpr(e0), mkU8(size-1))
6072//.. : binop(op, mkexpr(e0), mkU8(amt))
6073//.. );
6074//.. } else {
6075//.. vassert(0);
6076//.. }
6077//..
6078//.. putMMXReg( eregOfRM(rm), mkexpr(e1) );
6079//.. return delta;
6080//.. }
6081//..
6082//..
6083//.. /* Completely handle all MMX instructions except emms. */
6084//..
6085//.. static
sewardj9da16972005-02-21 13:58:26 +00006086//.. UInt dis_MMX ( Bool* decode_ok, UChar sorb, Int sz, ULong delta )
sewardjd20c8852005-01-20 20:04:07 +00006087//.. {
6088//.. Int len;
6089//.. UChar modrm;
6090//.. HChar dis_buf[50];
sewardj8c332e22005-01-28 01:36:56 +00006091//.. UChar opc = getUChar(delta);
sewardjd20c8852005-01-20 20:04:07 +00006092//.. delta++;
6093//..
6094//.. /* dis_MMX handles all insns except emms. */
6095//.. do_MMX_preamble();
6096//..
6097//.. switch (opc) {
6098//..
6099//.. case 0x6E:
6100//.. /* MOVD (src)ireg-or-mem (E), (dst)mmxreg (G)*/
6101//.. if (sz != 4)
6102//.. goto mmx_decode_failure;
sewardj8c332e22005-01-28 01:36:56 +00006103//.. modrm = getUChar(delta);
sewardjd20c8852005-01-20 20:04:07 +00006104//.. if (epartIsReg(modrm)) {
6105//.. delta++;
6106//.. putMMXReg(
6107//.. gregOfRM(modrm),
6108//.. binop( Iop_32HLto64,
6109//.. mkU32(0),
6110//.. getIReg(4, eregOfRM(modrm)) ) );
6111//.. DIP("movd %s, %s\n",
6112//.. nameIReg(4,eregOfRM(modrm)), nameMMXReg(gregOfRM(modrm)));
6113//.. } else {
6114//.. IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
6115//.. delta += len;
6116//.. putMMXReg(
6117//.. gregOfRM(modrm),
6118//.. binop( Iop_32HLto64,
6119//.. mkU32(0),
6120//.. loadLE(Ity_I32, mkexpr(addr)) ) );
6121//.. DIP("movd %s, %s\n", dis_buf, nameMMXReg(gregOfRM(modrm)));
6122//.. }
6123//.. break;
6124//..
6125//.. case 0x7E: /* MOVD (src)mmxreg (G), (dst)ireg-or-mem (E) */
6126//.. if (sz != 4)
6127//.. goto mmx_decode_failure;
sewardj8c332e22005-01-28 01:36:56 +00006128//.. modrm = getUChar(delta);
sewardjd20c8852005-01-20 20:04:07 +00006129//.. if (epartIsReg(modrm)) {
6130//.. delta++;
6131//.. putIReg( 4, eregOfRM(modrm),
6132//.. unop(Iop_64to32, getMMXReg(gregOfRM(modrm)) ) );
6133//.. DIP("movd %s, %s\n",
6134//.. nameMMXReg(gregOfRM(modrm)), nameIReg(4,eregOfRM(modrm)));
6135//.. } else {
6136//.. IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
6137//.. delta += len;
6138//.. storeLE( mkexpr(addr),
6139//.. unop(Iop_64to32, getMMXReg(gregOfRM(modrm)) ) );
6140//.. DIP("movd %s, %s\n", nameMMXReg(gregOfRM(modrm)), dis_buf);
6141//.. }
6142//.. break;
6143//..
6144//.. case 0x6F:
6145//.. /* MOVQ (src)mmxreg-or-mem, (dst)mmxreg */
6146//.. if (sz != 4)
6147//.. goto mmx_decode_failure;
sewardj8c332e22005-01-28 01:36:56 +00006148//.. modrm = getUChar(delta);
sewardjd20c8852005-01-20 20:04:07 +00006149//.. if (epartIsReg(modrm)) {
6150//.. delta++;
6151//.. putMMXReg( gregOfRM(modrm), getMMXReg(eregOfRM(modrm)) );
6152//.. DIP("movq %s, %s\n",
6153//.. nameMMXReg(eregOfRM(modrm)), nameMMXReg(gregOfRM(modrm)));
6154//.. } else {
6155//.. IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
6156//.. delta += len;
6157//.. putMMXReg( gregOfRM(modrm), loadLE(Ity_I64, mkexpr(addr)) );
6158//.. DIP("movq %s, %s\n",
6159//.. dis_buf, nameMMXReg(gregOfRM(modrm)));
6160//.. }
6161//.. break;
6162//..
6163//.. case 0x7F:
6164//.. /* MOVQ (src)mmxreg, (dst)mmxreg-or-mem */
6165//.. if (sz != 4)
6166//.. goto mmx_decode_failure;
sewardj8c332e22005-01-28 01:36:56 +00006167//.. modrm = getUChar(delta);
sewardjd20c8852005-01-20 20:04:07 +00006168//.. if (epartIsReg(modrm)) {
6169//.. /* Fall through. The assembler doesn't appear to generate
6170//.. these. */
6171//.. goto mmx_decode_failure;
6172//.. } else {
6173//.. IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
6174//.. delta += len;
6175//.. storeLE( mkexpr(addr), getMMXReg(gregOfRM(modrm)) );
6176//.. DIP("mov(nt)q %s, %s\n",
6177//.. nameMMXReg(gregOfRM(modrm)), dis_buf);
6178//.. }
6179//.. break;
6180//..
6181//.. case 0xFC:
6182//.. case 0xFD:
6183//.. case 0xFE: /* PADDgg (src)mmxreg-or-mem, (dst)mmxreg */
6184//.. if (sz != 4)
6185//.. goto mmx_decode_failure;
6186//.. delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "padd", True );
6187//.. break;
6188//..
6189//.. case 0xEC:
6190//.. case 0xED: /* PADDSgg (src)mmxreg-or-mem, (dst)mmxreg */
6191//.. if (sz != 4)
6192//.. goto mmx_decode_failure;
6193//.. delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "padds", True );
6194//.. break;
6195//..
6196//.. case 0xDC:
6197//.. case 0xDD: /* PADDUSgg (src)mmxreg-or-mem, (dst)mmxreg */
6198//.. if (sz != 4)
6199//.. goto mmx_decode_failure;
6200//.. delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "paddus", True );
6201//.. break;
6202//..
6203//.. case 0xF8:
6204//.. case 0xF9:
6205//.. case 0xFA: /* PSUBgg (src)mmxreg-or-mem, (dst)mmxreg */
6206//.. if (sz != 4)
6207//.. goto mmx_decode_failure;
6208//.. delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "psub", True );
6209//.. break;
6210//..
6211//.. case 0xE8:
6212//.. case 0xE9: /* PSUBSgg (src)mmxreg-or-mem, (dst)mmxreg */
6213//.. if (sz != 4)
6214//.. goto mmx_decode_failure;
6215//.. delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "psubs", True );
6216//.. break;
6217//..
6218//.. case 0xD8:
6219//.. case 0xD9: /* PSUBUSgg (src)mmxreg-or-mem, (dst)mmxreg */
6220//.. if (sz != 4)
6221//.. goto mmx_decode_failure;
6222//.. delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "psubus", True );
6223//.. break;
6224//..
6225//.. case 0xE5: /* PMULHW (src)mmxreg-or-mem, (dst)mmxreg */
6226//.. if (sz != 4)
6227//.. goto mmx_decode_failure;
6228//.. delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pmulhw", False );
6229//.. break;
6230//..
6231//.. case 0xD5: /* PMULLW (src)mmxreg-or-mem, (dst)mmxreg */
6232//.. if (sz != 4)
6233//.. goto mmx_decode_failure;
6234//.. delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pmullw", False );
6235//.. break;
6236//..
6237//.. case 0xF5: /* PMADDWD (src)mmxreg-or-mem, (dst)mmxreg */
6238//.. vassert(sz == 4);
6239//.. delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pmaddwd", False );
6240//.. break;
6241//..
6242//.. case 0x74:
6243//.. case 0x75:
6244//.. case 0x76: /* PCMPEQgg (src)mmxreg-or-mem, (dst)mmxreg */
6245//.. if (sz != 4)
6246//.. goto mmx_decode_failure;
6247//.. delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pcmpeq", True );
6248//.. break;
6249//..
6250//.. case 0x64:
6251//.. case 0x65:
6252//.. case 0x66: /* PCMPGTgg (src)mmxreg-or-mem, (dst)mmxreg */
6253//.. if (sz != 4)
6254//.. goto mmx_decode_failure;
6255//.. delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pcmpgt", True );
6256//.. break;
6257//..
6258//.. case 0x6B: /* PACKSSDW (src)mmxreg-or-mem, (dst)mmxreg */
6259//.. if (sz != 4)
6260//.. goto mmx_decode_failure;
6261//.. delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "packssdw", False );
6262//.. break;
6263//..
6264//.. case 0x63: /* PACKSSWB (src)mmxreg-or-mem, (dst)mmxreg */
6265//.. if (sz != 4)
6266//.. goto mmx_decode_failure;
6267//.. delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "packsswb", False );
6268//.. break;
6269//..
6270//.. case 0x67: /* PACKUSWB (src)mmxreg-or-mem, (dst)mmxreg */
6271//.. if (sz != 4)
6272//.. goto mmx_decode_failure;
6273//.. delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "packuswb", False );
6274//.. break;
6275//..
6276//.. case 0x68:
6277//.. case 0x69:
6278//.. case 0x6A: /* PUNPCKHgg (src)mmxreg-or-mem, (dst)mmxreg */
6279//.. if (sz != 4)
6280//.. goto mmx_decode_failure;
6281//.. delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "punpckh", True );
6282//.. break;
6283//..
6284//.. case 0x60:
6285//.. case 0x61:
6286//.. case 0x62: /* PUNPCKLgg (src)mmxreg-or-mem, (dst)mmxreg */
6287//.. if (sz != 4)
6288//.. goto mmx_decode_failure;
6289//.. delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "punpckl", True );
6290//.. break;
6291//..
6292//.. case 0xDB: /* PAND (src)mmxreg-or-mem, (dst)mmxreg */
6293//.. if (sz != 4)
6294//.. goto mmx_decode_failure;
6295//.. delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pand", False );
6296//.. break;
6297//..
6298//.. case 0xDF: /* PANDN (src)mmxreg-or-mem, (dst)mmxreg */
6299//.. if (sz != 4)
6300//.. goto mmx_decode_failure;
6301//.. delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pandn", False );
6302//.. break;
6303//..
6304//.. case 0xEB: /* POR (src)mmxreg-or-mem, (dst)mmxreg */
6305//.. if (sz != 4)
6306//.. goto mmx_decode_failure;
6307//.. delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "por", False );
6308//.. break;
6309//..
6310//.. case 0xEF: /* PXOR (src)mmxreg-or-mem, (dst)mmxreg */
6311//.. if (sz != 4)
6312//.. goto mmx_decode_failure;
6313//.. delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pxor", False );
6314//.. break;
6315//..
6316//.. # define SHIFT_BY_REG(_name,_op) \
6317//.. delta = dis_MMX_shiftG_byE(sorb, delta, _name, _op); \
6318//.. break;
6319//..
6320//.. /* PSLLgg (src)mmxreg-or-mem, (dst)mmxreg */
6321//.. case 0xF1: SHIFT_BY_REG("psllw", Iop_ShlN16x4);
6322//.. case 0xF2: SHIFT_BY_REG("pslld", Iop_ShlN32x2);
6323//.. case 0xF3: SHIFT_BY_REG("psllq", Iop_Shl64);
6324//..
6325//.. /* PSRLgg (src)mmxreg-or-mem, (dst)mmxreg */
6326//.. case 0xD1: SHIFT_BY_REG("psrlw", Iop_ShrN16x4);
6327//.. case 0xD2: SHIFT_BY_REG("psrld", Iop_ShrN32x2);
6328//.. case 0xD3: SHIFT_BY_REG("psrlq", Iop_Shr64);
6329//..
6330//.. /* PSRAgg (src)mmxreg-or-mem, (dst)mmxreg */
6331//.. case 0xE1: SHIFT_BY_REG("psraw", Iop_SarN16x4);
6332//.. case 0xE2: SHIFT_BY_REG("psrad", Iop_SarN32x2);
6333//..
6334//.. # undef SHIFT_BY_REG
6335//..
6336//.. case 0x71:
6337//.. case 0x72:
6338//.. case 0x73: {
6339//.. /* (sz==4): PSLLgg/PSRAgg/PSRLgg mmxreg by imm8 */
6340//.. UChar byte1, byte2, subopc;
6341//.. void* hAddr;
6342//.. Char* hName;
6343//.. if (sz != 4)
6344//.. goto mmx_decode_failure;
6345//.. byte1 = opc; /* 0x71/72/73 */
sewardj8c332e22005-01-28 01:36:56 +00006346//.. byte2 = getUChar(delta); /* amode / sub-opcode */
sewardjd20c8852005-01-20 20:04:07 +00006347//.. subopc = (byte2 >> 3) & 7;
6348//..
6349//.. # define SHIFT_BY_IMM(_name,_op) \
6350//.. do { delta = dis_MMX_shiftE_imm(delta,_name,_op); \
6351//.. } while (0)
6352//..
6353//.. hAddr = NULL;
6354//.. hName = NULL;
6355//..
6356//.. if (subopc == 2 /*SRL*/ && opc == 0x71)
6357//.. SHIFT_BY_IMM("psrlw", Iop_ShrN16x4);
6358//.. else if (subopc == 2 /*SRL*/ && opc == 0x72)
6359//.. SHIFT_BY_IMM("psrld", Iop_ShrN32x2);
6360//.. else if (subopc == 2 /*SRL*/ && opc == 0x73)
6361//.. SHIFT_BY_IMM("psrlq", Iop_Shr64);
6362//..
6363//.. else if (subopc == 4 /*SAR*/ && opc == 0x71)
6364//.. SHIFT_BY_IMM("psraw", Iop_SarN16x4);
6365//.. else if (subopc == 4 /*SAR*/ && opc == 0x72)
6366//.. SHIFT_BY_IMM("psrad", Iop_SarN32x2);
6367//..
6368//.. else if (subopc == 6 /*SHL*/ && opc == 0x71)
6369//.. SHIFT_BY_IMM("psllw", Iop_ShlN16x4);
6370//.. else if (subopc == 6 /*SHL*/ && opc == 0x72)
6371//.. SHIFT_BY_IMM("pslld", Iop_ShlN32x2);
6372//.. else if (subopc == 6 /*SHL*/ && opc == 0x73)
6373//.. SHIFT_BY_IMM("psllq", Iop_Shl64);
6374//..
6375//.. else goto mmx_decode_failure;
6376//..
6377//.. # undef SHIFT_BY_IMM
6378//.. break;
6379//.. }
6380//..
6381//.. /* --- MMX decode failure --- */
6382//.. default:
6383//.. mmx_decode_failure:
6384//.. *decode_ok = False;
6385//.. return delta; /* ignored */
6386//..
6387//.. }
6388//..
6389//.. *decode_ok = True;
6390//.. return delta;
6391//.. }
6392//..
6393//..
6394//.. /*------------------------------------------------------------*/
6395//.. /*--- More misc arithmetic and other obscure insns. ---*/
6396//.. /*------------------------------------------------------------*/
6397//..
6398//.. /* Double length left and right shifts. Apparently only required in
6399//.. v-size (no b- variant). */
6400//.. static
6401//.. UInt dis_SHLRD_Gv_Ev ( UChar sorb,
sewardj9da16972005-02-21 13:58:26 +00006402//.. ULong delta, UChar modrm,
sewardjd20c8852005-01-20 20:04:07 +00006403//.. Int sz,
6404//.. IRExpr* shift_amt,
6405//.. Bool amt_is_literal,
6406//.. Char* shift_amt_txt,
6407//.. Bool left_shift )
6408//.. {
6409//.. /* shift_amt :: Ity_I8 is the amount to shift. shift_amt_txt is used
6410//.. for printing it. And eip on entry points at the modrm byte. */
6411//.. Int len;
6412//.. HChar dis_buf[50];
6413//..
6414//.. IRType ty = szToITy(sz);
6415//.. IRTemp gsrc = newTemp(ty);
6416//.. IRTemp esrc = newTemp(ty);
6417//.. IRTemp addr = IRTemp_INVALID;
6418//.. IRTemp tmpSH = newTemp(Ity_I8);
6419//.. IRTemp tmpL = IRTemp_INVALID;
6420//.. IRTemp tmpRes = IRTemp_INVALID;
6421//.. IRTemp tmpSubSh = IRTemp_INVALID;
6422//.. IROp mkpair;
6423//.. IROp getres;
6424//.. IROp shift;
6425//.. IRExpr* mask = NULL;
6426//..
6427//.. vassert(sz == 2 || sz == 4);
6428//..
6429//.. /* The E-part is the destination; this is shifted. The G-part
6430//.. supplies bits to be shifted into the E-part, but is not
6431//.. changed.
6432//..
6433//.. If shifting left, form a double-length word with E at the top
6434//.. and G at the bottom, and shift this left. The result is then in
6435//.. the high part.
6436//..
6437//.. If shifting right, form a double-length word with G at the top
6438//.. and E at the bottom, and shift this right. The result is then
6439//.. at the bottom. */
6440//..
6441//.. /* Fetch the operands. */
6442//..
6443//.. assign( gsrc, getIReg(sz, gregOfRM(modrm)) );
6444//..
6445//.. if (epartIsReg(modrm)) {
6446//.. delta++;
6447//.. assign( esrc, getIReg(sz, eregOfRM(modrm)) );
6448//.. DIP("sh%cd%c %s, %s, %s\n",
6449//.. ( left_shift ? 'l' : 'r' ), nameISize(sz),
6450//.. shift_amt_txt,
6451//.. nameIReg(sz, gregOfRM(modrm)), nameIReg(sz, eregOfRM(modrm)));
6452//.. } else {
6453//.. addr = disAMode ( &len, sorb, delta, dis_buf );
6454//.. delta += len;
6455//.. assign( esrc, loadLE(ty, mkexpr(addr)) );
6456//.. DIP("sh%cd%c %s, %s, %s\n",
6457//.. ( left_shift ? 'l' : 'r' ), nameISize(sz),
6458//.. shift_amt_txt,
6459//.. nameIReg(sz, gregOfRM(modrm)), dis_buf);
6460//.. }
6461//..
6462//.. /* Round up the relevant primops. */
6463//..
6464//.. if (sz == 4) {
6465//.. tmpL = newTemp(Ity_I64);
6466//.. tmpRes = newTemp(Ity_I32);
6467//.. tmpSubSh = newTemp(Ity_I32);
6468//.. mkpair = Iop_32HLto64;
6469//.. getres = left_shift ? Iop_64HIto32 : Iop_64to32;
6470//.. shift = left_shift ? Iop_Shl64 : Iop_Shr64;
6471//.. mask = mkU8(31);
6472//.. } else {
6473//.. /* sz == 2 */
6474//.. tmpL = newTemp(Ity_I32);
6475//.. tmpRes = newTemp(Ity_I16);
6476//.. tmpSubSh = newTemp(Ity_I16);
6477//.. mkpair = Iop_16HLto32;
6478//.. getres = left_shift ? Iop_32HIto16 : Iop_32to16;
6479//.. shift = left_shift ? Iop_Shl32 : Iop_Shr32;
6480//.. mask = mkU8(15);
6481//.. }
6482//..
6483//.. /* Do the shift, calculate the subshift value, and set
6484//.. the flag thunk. */
6485//..
6486//.. assign( tmpSH, binop(Iop_And8, shift_amt, mask) );
6487//..
6488//.. if (left_shift)
6489//.. assign( tmpL, binop(mkpair, mkexpr(esrc), mkexpr(gsrc)) );
6490//.. else
6491//.. assign( tmpL, binop(mkpair, mkexpr(gsrc), mkexpr(esrc)) );
6492//..
6493//.. assign( tmpRes, unop(getres, binop(shift, mkexpr(tmpL), mkexpr(tmpSH)) ) );
6494//.. assign( tmpSubSh,
6495//.. unop(getres,
6496//.. binop(shift,
6497//.. mkexpr(tmpL),
6498//.. binop(Iop_And8,
6499//.. binop(Iop_Sub8, mkexpr(tmpSH), mkU8(1) ),
6500//.. mask))) );
6501//..
6502//.. setFlags_DEP1_DEP2_shift ( left_shift ? Iop_Shl32 : Iop_Sar32,
6503//.. tmpRes, tmpSubSh, ty, tmpSH );
6504//..
6505//.. /* Put result back. */
6506//..
6507//.. if (epartIsReg(modrm)) {
6508//.. putIReg(sz, eregOfRM(modrm), mkexpr(tmpRes));
6509//.. } else {
6510//.. storeLE( mkexpr(addr), mkexpr(tmpRes) );
6511//.. }
6512//..
6513//.. if (amt_is_literal) delta++;
6514//.. return delta;
6515//.. }
6516//..
6517//..
6518//.. /* Handle BT/BTS/BTR/BTC Gv, Ev. Apparently b-size is not
6519//.. required. */
6520//..
6521//.. typedef enum { BtOpNone, BtOpSet, BtOpReset, BtOpComp } BtOp;
6522//..
6523//.. static Char* nameBtOp ( BtOp op )
6524//.. {
6525//.. switch (op) {
6526//.. case BtOpNone: return "";
6527//.. case BtOpSet: return "s";
6528//.. case BtOpReset: return "r";
6529//.. case BtOpComp: return "c";
6530//.. default: vpanic("nameBtOp(x86)");
6531//.. }
6532//.. }
6533//..
6534//..
6535//.. static
sewardj9da16972005-02-21 13:58:26 +00006536//.. UInt dis_bt_G_E ( UChar sorb, Int sz, ULong delta, BtOp op )
sewardjd20c8852005-01-20 20:04:07 +00006537//.. {
6538//.. HChar dis_buf[50];
6539//.. UChar modrm;
6540//.. Int len;
6541//.. IRTemp t_fetched, t_bitno0, t_bitno1, t_bitno2, t_addr0,
6542//.. t_addr1, t_esp, t_mask;
6543//..
6544//.. vassert(sz == 2 || sz == 4);
6545//..
6546//.. t_fetched = t_bitno0 = t_bitno1 = t_bitno2
6547//.. = t_addr0 = t_addr1 = t_esp = t_mask = IRTemp_INVALID;
6548//..
6549//.. t_fetched = newTemp(Ity_I8);
6550//.. t_bitno0 = newTemp(Ity_I32);
6551//.. t_bitno1 = newTemp(Ity_I32);
6552//.. t_bitno2 = newTemp(Ity_I8);
6553//.. t_addr1 = newTemp(Ity_I32);
sewardj8c332e22005-01-28 01:36:56 +00006554//.. modrm = getUChar(delta);
sewardjd20c8852005-01-20 20:04:07 +00006555//..
6556//.. assign( t_bitno0, widenUto32(getIReg(sz, gregOfRM(modrm))) );
6557//..
6558//.. if (epartIsReg(modrm)) {
6559//.. delta++;
6560//.. /* Get it onto the client's stack. */
6561//.. t_esp = newTemp(Ity_I32);
6562//.. t_addr0 = newTemp(Ity_I32);
6563//..
6564//.. assign( t_esp, binop(Iop_Sub32, getIReg(4, R_ESP), mkU32(sz)) );
6565//.. putIReg(4, R_ESP, mkexpr(t_esp));
6566//..
6567//.. storeLE( mkexpr(t_esp), getIReg(sz, eregOfRM(modrm)) );
6568//..
6569//.. /* Make t_addr0 point at it. */
6570//.. assign( t_addr0, mkexpr(t_esp) );
6571//..
6572//.. /* Mask out upper bits of the shift amount, since we're doing a
6573//.. reg. */
6574//.. assign( t_bitno1, binop(Iop_And32,
6575//.. mkexpr(t_bitno0),
6576//.. mkU32(sz == 4 ? 31 : 15)) );
6577//..
6578//.. } else {
6579//.. t_addr0 = disAMode ( &len, sorb, delta, dis_buf );
6580//.. delta += len;
6581//.. assign( t_bitno1, mkexpr(t_bitno0) );
6582//.. }
6583//..
6584//.. /* At this point: t_addr0 is the address being operated on. If it
6585//.. was a reg, we will have pushed it onto the client's stack.
6586//.. t_bitno1 is the bit number, suitably masked in the case of a
6587//.. reg. */
6588//..
6589//.. /* Now the main sequence. */
6590//.. assign( t_addr1,
6591//.. binop(Iop_Add32,
6592//.. mkexpr(t_addr0),
6593//.. binop(Iop_Sar32, mkexpr(t_bitno1), mkU8(3))) );
6594//..
6595//.. /* t_addr1 now holds effective address */
6596//..
6597//.. assign( t_bitno2,
6598//.. unop(Iop_32to8,
6599//.. binop(Iop_And32, mkexpr(t_bitno1), mkU32(7))) );
6600//..
6601//.. /* t_bitno2 contains offset of bit within byte */
6602//..
6603//.. if (op != BtOpNone) {
6604//.. t_mask = newTemp(Ity_I8);
6605//.. assign( t_mask, binop(Iop_Shl8, mkU8(1), mkexpr(t_bitno2)) );
6606//.. }
6607//..
6608//.. /* t_mask is now a suitable byte mask */
6609//..
6610//.. assign( t_fetched, loadLE(Ity_I8, mkexpr(t_addr1)) );
6611//..
6612//.. if (op != BtOpNone) {
6613//.. switch (op) {
6614//.. case BtOpSet:
6615//.. storeLE( mkexpr(t_addr1),
6616//.. binop(Iop_Or8, mkexpr(t_fetched),
6617//.. mkexpr(t_mask)) );
6618//.. break;
6619//.. case BtOpComp:
6620//.. storeLE( mkexpr(t_addr1),
6621//.. binop(Iop_Xor8, mkexpr(t_fetched),
6622//.. mkexpr(t_mask)) );
6623//.. break;
6624//.. case BtOpReset:
6625//.. storeLE( mkexpr(t_addr1),
6626//.. binop(Iop_And8, mkexpr(t_fetched),
6627//.. unop(Iop_Not8, mkexpr(t_mask))) );
6628//.. break;
6629//.. default:
6630//.. vpanic("dis_bt_G_E(x86)");
6631//.. }
6632//.. }
6633//..
6634//.. /* Side effect done; now get selected bit into Carry flag */
6635//.. /* Flags: C=selected bit, O,S,Z,A,P undefined, so are set to zero. */
6636//.. stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
6637//.. stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
6638//.. stmt( IRStmt_Put(
6639//.. OFFB_CC_DEP1,
6640//.. binop(Iop_And32,
6641//.. binop(Iop_Shr32,
6642//.. unop(Iop_8Uto32, mkexpr(t_fetched)),
6643//.. mkexpr(t_bitno2)),
6644//.. mkU32(1)))
6645//.. );
6646//..
6647//.. /* Move reg operand from stack back to reg */
6648//.. if (epartIsReg(modrm)) {
6649//.. /* t_esp still points at it. */
6650//.. putIReg(sz, eregOfRM(modrm), loadLE(szToITy(sz), mkexpr(t_esp)) );
6651//.. putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t_esp), mkU32(sz)) );
6652//.. }
6653//..
6654//.. DIP("bt%s%c %s, %s\n",
6655//.. nameBtOp(op), nameISize(sz), nameIReg(sz, gregOfRM(modrm)),
6656//.. ( epartIsReg(modrm) ? nameIReg(sz, eregOfRM(modrm)) : dis_buf ) );
6657//..
6658//.. return delta;
6659//.. }
6660//..
6661//..
6662//..
6663//.. /* Handle BSF/BSR. Only v-size seems necessary. */
6664//.. static
sewardj9da16972005-02-21 13:58:26 +00006665//.. UInt dis_bs_E_G ( UChar sorb, Int sz, ULong delta, Bool fwds )
sewardjd20c8852005-01-20 20:04:07 +00006666//.. {
6667//.. Bool isReg;
6668//.. UChar modrm;
6669//.. HChar dis_buf[50];
6670//..
6671//.. IRType ty = szToITy(sz);
6672//.. IRTemp src = newTemp(ty);
6673//.. IRTemp dst = newTemp(ty);
6674//..
6675//.. IRTemp src32 = newTemp(Ity_I32);
6676//.. IRTemp dst32 = newTemp(Ity_I32);
6677//.. IRTemp src8 = newTemp(Ity_I8);
6678//..
6679//.. vassert(sz == 4 || sz == 2);
6680//..
sewardj8c332e22005-01-28 01:36:56 +00006681//.. modrm = getUChar(delta);
sewardjd20c8852005-01-20 20:04:07 +00006682//..
6683//.. isReg = epartIsReg(modrm);
6684//.. if (isReg) {
6685//.. delta++;
6686//.. assign( src, getIReg(sz, eregOfRM(modrm)) );
6687//.. } else {
6688//.. Int len;
6689//.. IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
6690//.. delta += len;
6691//.. assign( src, loadLE(ty, mkexpr(addr)) );
6692//.. }
6693//..
6694//.. DIP("bs%c%c %s, %s\n",
6695//.. fwds ? 'f' : 'r', nameISize(sz),
6696//.. ( isReg ? nameIReg(sz, eregOfRM(modrm)) : dis_buf ),
6697//.. nameIReg(sz, gregOfRM(modrm)));
6698//..
6699//.. /* Generate an 8-bit expression which is zero iff the
6700//.. original is zero, and nonzero otherwise */
6701//.. assign( src8,
6702//.. unop(Iop_1Uto8, binop(mkSizedOp(ty,Iop_CmpNE8),
6703//.. mkexpr(src), mkU(ty,0))) );
6704//..
6705//.. /* Flags: Z is 1 iff source value is zero. All others
6706//.. are undefined -- we force them to zero. */
6707//.. stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
6708//.. stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
6709//.. stmt( IRStmt_Put(
6710//.. OFFB_CC_DEP1,
6711//.. IRExpr_Mux0X( mkexpr(src8),
6712//.. /* src==0 */
6713//.. mkU32(X86G_CC_MASK_Z),
6714//.. /* src!=0 */
6715//.. mkU32(0)
6716//.. )
6717//.. ));
6718//..
6719//.. /* Result: iff source value is zero, we can't use
6720//.. Iop_Clz32/Iop_Ctz32 as they have no defined result in that case.
6721//.. But anyway, Intel x86 semantics say the result is undefined in
6722//.. such situations. Hence handle the zero case specially. */
6723//..
6724//.. /* Bleh. What we compute:
6725//..
6726//.. bsf32: if src == 0 then 0 else Ctz32(src)
6727//.. bsr32: if src == 0 then 0 else 31 - Clz32(src)
6728//..
6729//.. bsf16: if src == 0 then 0 else Ctz32(16Uto32(src))
6730//.. bsr16: if src == 0 then 0 else 31 - Clz32(16Uto32(src))
6731//..
6732//.. First, widen src to 32 bits if it is not already.
6733//..
6734//.. Postscript 15 Oct 04: it seems that at least VIA Nehemiah leaves the
6735//.. dst register unchanged when src == 0. Hence change accordingly.
6736//.. */
6737//.. if (sz == 2)
6738//.. assign( src32, unop(Iop_16Uto32, mkexpr(src)) );
6739//.. else
6740//.. assign( src32, mkexpr(src) );
6741//..
6742//.. /* The main computation, guarding against zero. */
6743//.. assign( dst32,
6744//.. IRExpr_Mux0X(
6745//.. mkexpr(src8),
6746//.. /* src == 0 -- leave dst unchanged */
6747//.. widenUto32( getIReg( sz, gregOfRM(modrm) ) ),
6748//.. /* src != 0 */
6749//.. fwds ? unop(Iop_Ctz32, mkexpr(src32))
6750//.. : binop(Iop_Sub32,
6751//.. mkU32(31),
6752//.. unop(Iop_Clz32, mkexpr(src32)))
6753//.. )
6754//.. );
6755//..
6756//.. if (sz == 2)
6757//.. assign( dst, unop(Iop_32to16, mkexpr(dst32)) );
6758//.. else
6759//.. assign( dst, mkexpr(dst32) );
6760//..
6761//.. /* dump result back */
6762//.. putIReg( sz, gregOfRM(modrm), mkexpr(dst) );
6763//..
6764//.. return delta;
6765//.. }
sewardja6b93d12005-02-17 09:28:28 +00006766
6767
6768/* swap rAX with the reg specified by reg and REX.B */
6769static
sewardj5b470602005-02-27 13:10:48 +00006770void codegen_xchg_rAX_Reg ( Prefix pfx, Int sz, UInt regLo3 )
sewardja6b93d12005-02-17 09:28:28 +00006771{
6772 IRType ty = szToITy(sz);
6773 IRTemp t1 = newTemp(ty);
6774 IRTemp t2 = newTemp(ty);
6775 vassert(sz == 8);
sewardj5b470602005-02-27 13:10:48 +00006776 vassert(regLo3 < 8);
sewardja6b93d12005-02-17 09:28:28 +00006777 assign( t1, getIReg64(R_RAX) );
sewardj5b470602005-02-27 13:10:48 +00006778 assign( t2, getIRegRexB(8,pfx, regLo3) );
sewardja6b93d12005-02-17 09:28:28 +00006779 putIReg64( R_RAX, mkexpr(t2) );
sewardj5b470602005-02-27 13:10:48 +00006780 putIRegRexB(8, pfx, regLo3, mkexpr(t1) );
sewardja6b93d12005-02-17 09:28:28 +00006781 DIP("xchg%c %s, %s\n",
sewardj5b470602005-02-27 13:10:48 +00006782 nameISize(sz), nameIRegRAX(sz),
6783 nameIRegRexB(8,pfx, regLo3));
sewardja6b93d12005-02-17 09:28:28 +00006784}
6785
6786
sewardjd20c8852005-01-20 20:04:07 +00006787//.. static
6788//.. void codegen_SAHF ( void )
6789//.. {
6790//.. /* Set the flags to:
6791//.. (x86g_calculate_flags_all() & X86G_CC_MASK_O) -- retain the old O flag
6792//.. | (%AH & (X86G_CC_MASK_S|X86G_CC_MASK_Z|X86G_CC_MASK_A
6793//.. |X86G_CC_MASK_P|X86G_CC_MASK_C)
6794//.. */
6795//.. UInt mask_SZACP = X86G_CC_MASK_S|X86G_CC_MASK_Z|X86G_CC_MASK_A
6796//.. |X86G_CC_MASK_C|X86G_CC_MASK_P;
6797//.. IRTemp oldflags = newTemp(Ity_I32);
6798//.. assign( oldflags, mk_x86g_calculate_eflags_all() );
6799//.. stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
6800//.. stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
6801//.. stmt( IRStmt_Put( OFFB_CC_DEP1,
6802//.. binop(Iop_Or32,
6803//.. binop(Iop_And32, mkexpr(oldflags), mkU32(X86G_CC_MASK_O)),
6804//.. binop(Iop_And32,
6805//.. binop(Iop_Shr32, getIReg(4, R_EAX), mkU8(8)),
6806//.. mkU32(mask_SZACP))
6807//.. )
6808//.. ));
6809//.. }
6810//..
6811//..
6812//.. //-- static
6813//.. //-- void codegen_LAHF ( UCodeBlock* cb )
6814//.. //-- {
6815//.. //-- Int t = newTemp(cb);
6816//.. //--
6817//.. //-- /* Pushed arg is ignored, it just provides somewhere to put the
6818//.. //-- return value. */
6819//.. //-- uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, t);
6820//.. //-- uInstr0(cb, CALLM_S, 0);
6821//.. //-- uInstr1(cb, PUSH, 4, TempReg, t);
6822//.. //-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_LAHF));
6823//.. //-- uFlagsRWU(cb, FlagsSZACP, FlagsEmpty, FlagsEmpty);
6824//.. //-- uInstr1(cb, POP, 4, TempReg, t);
6825//.. //-- uInstr0(cb, CALLM_E, 0);
6826//.. //--
6827//.. //-- /* At this point, the %ah sub-register in %eax has been updated,
6828//.. //-- the rest is the same, so do a PUT of the whole thing. */
6829//.. //-- uInstr2(cb, PUT, 4, TempReg, t, ArchReg, R_EAX);
6830//.. //-- }
6831//.. //--
sewardja6b93d12005-02-17 09:28:28 +00006832
6833static
6834ULong dis_cmpxchg_G_E ( Prefix pfx,
6835 Int size,
6836 ULong delta0 )
6837{
6838 HChar dis_buf[50];
6839 Int len;
6840
6841 IRType ty = szToITy(size);
6842 IRTemp acc = newTemp(ty);
6843 IRTemp src = newTemp(ty);
6844 IRTemp dest = newTemp(ty);
6845 IRTemp dest2 = newTemp(ty);
6846 IRTemp acc2 = newTemp(ty);
6847 IRTemp cond8 = newTemp(Ity_I8);
6848 IRTemp addr = IRTemp_INVALID;
6849 UChar rm = getUChar(delta0);
6850
6851 if (epartIsReg(rm)) {
sewardj5b470602005-02-27 13:10:48 +00006852 vassert(0); /* awaiting test case */
6853 assign( dest, getIRegE(size, pfx, rm) );
sewardja6b93d12005-02-17 09:28:28 +00006854 delta0++;
6855 DIP("cmpxchg%c %s,%s\n", nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00006856 nameIRegG(size,pfx,rm),
6857 nameIRegE(size,pfx,rm) );
sewardja6b93d12005-02-17 09:28:28 +00006858 } else {
6859 addr = disAMode ( &len, pfx, delta0, dis_buf, 0 );
6860 assign( dest, loadLE(ty, mkexpr(addr)) );
6861 delta0 += len;
6862 DIP("cmpxchg%c %s,%s\n", nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00006863 nameIRegG(size,pfx,rm), dis_buf);
sewardja6b93d12005-02-17 09:28:28 +00006864 }
6865
sewardj5b470602005-02-27 13:10:48 +00006866 assign( src, getIRegG(size, pfx, rm) );
6867 assign( acc, getIRegRAX(size) );
sewardja6b93d12005-02-17 09:28:28 +00006868 setFlags_DEP1_DEP2(Iop_Sub8, acc, dest, ty);
6869 assign( cond8, unop(Iop_1Uto8, mk_amd64g_calculate_condition(AMD64CondZ)) );
6870 assign( dest2, IRExpr_Mux0X(mkexpr(cond8), mkexpr(dest), mkexpr(src)) );
6871 assign( acc2, IRExpr_Mux0X(mkexpr(cond8), mkexpr(dest), mkexpr(acc)) );
sewardj5b470602005-02-27 13:10:48 +00006872 putIRegRAX(size, mkexpr(acc2));
sewardja6b93d12005-02-17 09:28:28 +00006873
6874 if (epartIsReg(rm)) {
sewardj5b470602005-02-27 13:10:48 +00006875 putIRegE(size, pfx, rm, mkexpr(dest2));
sewardja6b93d12005-02-17 09:28:28 +00006876 } else {
6877 storeLE( mkexpr(addr), mkexpr(dest2) );
6878 }
6879
6880 return delta0;
6881}
6882
6883
sewardjd20c8852005-01-20 20:04:07 +00006884//.. //-- static
6885//.. //-- Addr dis_cmpxchg8b ( UCodeBlock* cb,
6886//.. //-- UChar sorb,
6887//.. //-- Addr eip0 )
6888//.. //-- {
6889//.. //-- Int tal, tah, junkl, junkh, destl, desth, srcl, srch, accl, acch;
6890//.. //-- HChar dis_buf[50];
6891//.. //-- UChar rm;
6892//.. //-- UInt pair;
6893//.. //--
6894//.. //-- rm = getUChar(eip0);
6895//.. //-- accl = newTemp(cb);
6896//.. //-- acch = newTemp(cb);
6897//.. //-- srcl = newTemp(cb);
6898//.. //-- srch = newTemp(cb);
6899//.. //-- destl = newTemp(cb);
6900//.. //-- desth = newTemp(cb);
6901//.. //-- junkl = newTemp(cb);
6902//.. //-- junkh = newTemp(cb);
6903//.. //--
6904//.. //-- vg_assert(!epartIsReg(rm));
6905//.. //--
6906//.. //-- pair = disAMode ( cb, sorb, eip0, dis_buf );
6907//.. //-- tal = LOW24(pair);
6908//.. //-- tah = newTemp(cb);
6909//.. //-- uInstr2(cb, MOV, 4, TempReg, tal, TempReg, tah);
6910//.. //-- uInstr2(cb, ADD, 4, Literal, 0, TempReg, tah);
6911//.. //-- uLiteral(cb, 4);
6912//.. //-- eip0 += HI8(pair);
6913//.. //-- DIP("cmpxchg8b %s\n", dis_buf);
6914//.. //--
6915//.. //-- uInstr0(cb, CALLM_S, 0);
6916//.. //--
6917//.. //-- uInstr2(cb, LOAD, 4, TempReg, tah, TempReg, desth);
6918//.. //-- uInstr1(cb, PUSH, 4, TempReg, desth);
6919//.. //-- uInstr2(cb, LOAD, 4, TempReg, tal, TempReg, destl);
6920//.. //-- uInstr1(cb, PUSH, 4, TempReg, destl);
6921//.. //-- uInstr2(cb, GET, 4, ArchReg, R_ECX, TempReg, srch);
6922//.. //-- uInstr1(cb, PUSH, 4, TempReg, srch);
6923//.. //-- uInstr2(cb, GET, 4, ArchReg, R_EBX, TempReg, srcl);
6924//.. //-- uInstr1(cb, PUSH, 4, TempReg, srcl);
6925//.. //-- uInstr2(cb, GET, 4, ArchReg, R_EDX, TempReg, acch);
6926//.. //-- uInstr1(cb, PUSH, 4, TempReg, acch);
6927//.. //-- uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, accl);
6928//.. //-- uInstr1(cb, PUSH, 4, TempReg, accl);
6929//.. //--
6930//.. //-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_cmpxchg8b));
6931//.. //-- uFlagsRWU(cb, FlagsEmpty, FlagZ, FlagsEmpty);
6932//.. //--
6933//.. //-- uInstr1(cb, POP, 4, TempReg, accl);
6934//.. //-- uInstr2(cb, PUT, 4, TempReg, accl, ArchReg, R_EAX);
6935//.. //-- uInstr1(cb, POP, 4, TempReg, acch);
6936//.. //-- uInstr2(cb, PUT, 4, TempReg, acch, ArchReg, R_EDX);
6937//.. //-- uInstr1(cb, POP, 4, TempReg, srcl);
6938//.. //-- uInstr2(cb, PUT, 4, TempReg, srcl, ArchReg, R_EBX);
6939//.. //-- uInstr1(cb, POP, 4, TempReg, srch);
6940//.. //-- uInstr2(cb, PUT, 4, TempReg, srch, ArchReg, R_ECX);
6941//.. //-- uInstr1(cb, POP, 4, TempReg, destl);
6942//.. //-- uInstr2(cb, STORE, 4, TempReg, destl, TempReg, tal);
6943//.. //-- uInstr1(cb, POP, 4, TempReg, desth);
6944//.. //-- uInstr2(cb, STORE, 4, TempReg, desth, TempReg, tah);
6945//.. //--
6946//.. //-- uInstr0(cb, CALLM_E, 0);
6947//.. //--
6948//.. //-- return eip0;
6949//.. //-- }
sewardj3ca55a12005-01-27 16:06:23 +00006950
6951
6952/* Handle conditional move instructions of the form
6953 cmovcc E(reg-or-mem), G(reg)
6954
6955 E(src) is reg-or-mem
6956 G(dst) is reg.
6957
6958 If E is reg, --> GET %E, tmps
6959 GET %G, tmpd
6960 CMOVcc tmps, tmpd
6961 PUT tmpd, %G
6962
6963 If E is mem --> (getAddr E) -> tmpa
6964 LD (tmpa), tmps
6965 GET %G, tmpd
6966 CMOVcc tmps, tmpd
6967 PUT tmpd, %G
6968*/
6969static
6970ULong dis_cmov_E_G ( Prefix pfx,
6971 Int sz,
6972 AMD64Condcode cond,
6973 ULong delta0 )
6974{
sewardj8c332e22005-01-28 01:36:56 +00006975 UChar rm = getUChar(delta0);
sewardj3ca55a12005-01-27 16:06:23 +00006976 HChar dis_buf[50];
6977 Int len;
6978
6979 IRType ty = szToITy(sz);
6980 IRTemp tmps = newTemp(ty);
6981 IRTemp tmpd = newTemp(ty);
6982
6983 if (epartIsReg(rm)) {
sewardj5b470602005-02-27 13:10:48 +00006984 assign( tmps, getIRegE(sz, pfx, rm) );
6985 assign( tmpd, getIRegG(sz, pfx, rm) );
sewardj3ca55a12005-01-27 16:06:23 +00006986
sewardj5b470602005-02-27 13:10:48 +00006987 putIRegG( sz, pfx, rm,
sewardj3ca55a12005-01-27 16:06:23 +00006988 IRExpr_Mux0X( unop(Iop_1Uto8,
6989 mk_amd64g_calculate_condition(cond)),
6990 mkexpr(tmpd),
6991 mkexpr(tmps) )
6992 );
sewardje941eea2005-01-30 19:52:28 +00006993 DIP("cmov%s %s,%s\n", name_AMD64Condcode(cond),
sewardj5b470602005-02-27 13:10:48 +00006994 nameIRegE(sz,pfx,rm),
6995 nameIRegG(sz,pfx,rm));
sewardj3ca55a12005-01-27 16:06:23 +00006996 return 1+delta0;
6997 }
6998
6999 /* E refers to memory */
7000 {
sewardje1698952005-02-08 15:02:39 +00007001 IRTemp addr = disAMode ( &len, pfx, delta0, dis_buf, 0 );
sewardj3ca55a12005-01-27 16:06:23 +00007002 assign( tmps, loadLE(ty, mkexpr(addr)) );
sewardj5b470602005-02-27 13:10:48 +00007003 assign( tmpd, getIRegG(sz, pfx, rm) );
sewardj3ca55a12005-01-27 16:06:23 +00007004
sewardj5b470602005-02-27 13:10:48 +00007005 putIRegG( sz, pfx, rm,
sewardj3ca55a12005-01-27 16:06:23 +00007006 IRExpr_Mux0X( unop(Iop_1Uto8,
7007 mk_amd64g_calculate_condition(cond)),
7008 mkexpr(tmpd),
7009 mkexpr(tmps) )
7010 );
7011
sewardj7eaa7cf2005-01-31 18:55:22 +00007012 DIP("cmov%s %s,%s\n", name_AMD64Condcode(cond),
7013 dis_buf,
sewardj5b470602005-02-27 13:10:48 +00007014 nameIRegG(sz,pfx,rm));
sewardj3ca55a12005-01-27 16:06:23 +00007015 return len+delta0;
7016 }
7017}
7018
7019
sewardjd20c8852005-01-20 20:04:07 +00007020//.. static
sewardj9da16972005-02-21 13:58:26 +00007021//.. UInt dis_xadd_G_E ( UChar sorb, Int sz, ULong delta0 )
sewardjd20c8852005-01-20 20:04:07 +00007022//.. {
7023//.. Int len;
sewardj8c332e22005-01-28 01:36:56 +00007024//.. UChar rm = getUChar(delta0);
sewardjd20c8852005-01-20 20:04:07 +00007025//.. HChar dis_buf[50];
7026//..
7027//.. // Int tmpd = newTemp(cb);
7028//.. //Int tmpt = newTemp(cb);
7029//..
7030//.. IRType ty = szToITy(sz);
7031//.. IRTemp tmpd = newTemp(ty);
7032//.. IRTemp tmpt0 = newTemp(ty);
7033//.. IRTemp tmpt1 = newTemp(ty);
7034//..
7035//.. if (epartIsReg(rm)) {
7036//.. vassert(0);
7037//.. #if 0
7038//.. uInstr2(cb, GET, sz, ArchReg, eregOfRM(rm), TempReg, tmpd);
7039//.. uInstr2(cb, GET, sz, ArchReg, gregOfRM(rm), TempReg, tmpt);
7040//.. uInstr2(cb, ADD, sz, TempReg, tmpd, TempReg, tmpt);
7041//.. setFlagsFromUOpcode(cb, ADD);
7042//.. uInstr2(cb, PUT, sz, TempReg, tmpd, ArchReg, gregOfRM(rm));
7043//.. uInstr2(cb, PUT, sz, TempReg, tmpt, ArchReg, eregOfRM(rm));
7044//.. DIP("xadd%c %s, %s\n",
7045//.. nameISize(sz), nameIReg(sz,gregOfRM(rm)), nameIReg(sz,eregOfRM(rm)));
7046//.. return 1+eip0;
7047//.. #endif
7048//.. } else {
7049//.. IRTemp addr = disAMode ( &len, sorb, delta0, dis_buf );
7050//.. assign( tmpd, loadLE(ty, mkexpr(addr)) );
7051//.. assign( tmpt0, getIReg(sz, gregOfRM(rm)) );
7052//.. assign( tmpt1, binop(mkSizedOp(ty,Iop_Add8), mkexpr(tmpd), mkexpr(tmpt0)) );
7053//.. setFlags_DEP1_DEP2( Iop_Add8, tmpd, tmpt0, ty );
7054//.. storeLE( mkexpr(addr), mkexpr(tmpt1) );
7055//.. putIReg(sz, gregOfRM(rm), mkexpr(tmpd));
7056//.. DIP("xadd%c %s, %s\n",
7057//.. nameISize(sz), nameIReg(sz,gregOfRM(rm)), dis_buf);
7058//.. return len+delta0;
7059//.. }
7060//.. }
7061//..
7062//.. /* Move 16 bits from Ew (ireg or mem) to G (a segment register). */
7063//..
7064//.. static
sewardj9da16972005-02-21 13:58:26 +00007065//.. UInt dis_mov_Ew_Sw ( UChar sorb, ULong delta0 )
sewardjd20c8852005-01-20 20:04:07 +00007066//.. {
7067//.. Int len;
7068//.. IRTemp addr;
sewardj8c332e22005-01-28 01:36:56 +00007069//.. UChar rm = getUChar(delta0);
sewardjd20c8852005-01-20 20:04:07 +00007070//.. HChar dis_buf[50];
7071//..
7072//.. if (epartIsReg(rm)) {
7073//.. putSReg( gregOfRM(rm), getIReg(2, eregOfRM(rm)) );
7074//.. DIP("movw %s,%s\n", nameIReg(2,eregOfRM(rm)), nameSReg(gregOfRM(rm)));
7075//.. return 1+delta0;
7076//.. } else {
7077//.. addr = disAMode ( &len, sorb, delta0, dis_buf );
7078//.. putSReg( gregOfRM(rm), loadLE(Ity_I16, mkexpr(addr)) );
7079//.. DIP("movw %s,%s\n", dis_buf, nameSReg(gregOfRM(rm)));
7080//.. return len+delta0;
7081//.. }
7082//.. }
7083//..
7084//.. /* Move 16 bits from G (a segment register) to Ew (ireg or mem). If
7085//.. dst is ireg and sz==4, zero out top half of it. */
7086//..
7087//.. static
7088//.. UInt dis_mov_Sw_Ew ( UChar sorb,
7089//.. Int sz,
7090//.. UInt delta0 )
7091//.. {
7092//.. Int len;
7093//.. IRTemp addr;
sewardj8c332e22005-01-28 01:36:56 +00007094//.. UChar rm = getUChar(delta0);
sewardjd20c8852005-01-20 20:04:07 +00007095//.. HChar dis_buf[50];
7096//..
7097//.. vassert(sz == 2 || sz == 4);
7098//..
7099//.. if (epartIsReg(rm)) {
7100//.. if (sz == 4)
7101//.. putIReg(4, eregOfRM(rm), unop(Iop_16Uto32, getSReg(gregOfRM(rm))));
7102//.. else
7103//.. putIReg(2, eregOfRM(rm), getSReg(gregOfRM(rm)));
7104//..
7105//.. DIP("mov %s,%s\n", nameSReg(gregOfRM(rm)), nameIReg(sz,eregOfRM(rm)));
7106//.. return 1+delta0;
7107//.. } else {
7108//.. addr = disAMode ( &len, sorb, delta0, dis_buf );
7109//.. storeLE( mkexpr(addr), getSReg(gregOfRM(rm)) );
7110//.. DIP("mov %s,%s\n", nameSReg(gregOfRM(rm)), dis_buf);
7111//.. return len+delta0;
7112//.. }
7113//.. }
7114//..
7115//..
7116//.. static
7117//.. void dis_push_segreg ( UInt sreg, Int sz )
7118//.. {
7119//.. IRTemp t1 = newTemp(Ity_I16);
7120//.. IRTemp ta = newTemp(Ity_I32);
7121//.. vassert(sz == 2 || sz == 4);
7122//..
7123//.. assign( t1, getSReg(sreg) );
7124//.. assign( ta, binop(Iop_Sub32, getIReg(4, R_ESP), mkU32(sz)) );
7125//.. putIReg(4, R_ESP, mkexpr(ta));
7126//.. storeLE( mkexpr(ta), mkexpr(t1) );
7127//..
7128//.. DIP("pushw %s\n", nameSReg(sreg));
7129//.. }
7130//..
7131//.. static
7132//.. void dis_pop_segreg ( UInt sreg, Int sz )
7133//.. {
7134//.. IRTemp t1 = newTemp(Ity_I16);
7135//.. IRTemp ta = newTemp(Ity_I32);
7136//.. vassert(sz == 2 || sz == 4);
7137//..
7138//.. assign( ta, getIReg(4, R_ESP) );
7139//.. assign( t1, loadLE(Ity_I16, mkexpr(ta)) );
7140//..
7141//.. putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(ta), mkU32(sz)) );
7142//.. putSReg( sreg, mkexpr(t1) );
7143//.. DIP("pop %s\n", nameSReg(sreg));
7144//.. }
sewardj2f959cc2005-01-26 01:19:35 +00007145
7146static
7147void dis_ret ( ULong d64 )
7148{
7149 IRTemp t1 = newTemp(Ity_I64);
7150 IRTemp t2 = newTemp(Ity_I64);
7151 assign(t1, getIReg64(R_RSP));
7152 assign(t2, loadLE(Ity_I64,mkexpr(t1)));
7153 putIReg64(R_RSP, binop(Iop_Add64, mkexpr(t1), mkU64(8+d64)));
7154 jmp_treg(Ijk_Ret,t2);
7155}
7156
sewardj5b470602005-02-27 13:10:48 +00007157
sewardj1001dc42005-02-21 08:25:55 +00007158/*------------------------------------------------------------*/
7159/*--- SSE/SSE2/SSE3 helpers ---*/
7160/*------------------------------------------------------------*/
7161
7162/* Worker function; do not call directly.
7163 Handles full width G = G `op` E and G = (not G) `op` E.
7164*/
7165
sewardj8d965312005-02-25 02:48:47 +00007166static ULong dis_SSE_E_to_G_all_wrk (
7167 Prefix pfx, ULong delta,
7168 HChar* opname, IROp op,
7169 Bool invertG
7170 )
sewardj9da16972005-02-21 13:58:26 +00007171{
7172 HChar dis_buf[50];
7173 Int alen;
7174 IRTemp addr;
7175 UChar rm = getUChar(delta);
7176 IRExpr* gpart
7177 = invertG ? unop(Iop_NotV128, getXMMReg(gregOfRexRM(pfx,rm)))
7178 : getXMMReg(gregOfRexRM(pfx,rm));
7179 if (epartIsReg(rm)) {
7180 putXMMReg( gregOfRexRM(pfx,rm),
7181 binop(op, gpart,
7182 getXMMReg(eregOfRexRM(pfx,rm))) );
7183 DIP("%s %s,%s\n", opname,
7184 nameXMMReg(eregOfRexRM(pfx,rm)),
7185 nameXMMReg(gregOfRexRM(pfx,rm)) );
7186 return delta+1;
7187 } else {
7188 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
7189 putXMMReg( gregOfRexRM(pfx,rm),
7190 binop(op, gpart,
7191 loadLE(Ity_V128, mkexpr(addr))) );
7192 DIP("%s %s,%s\n", opname,
7193 dis_buf,
7194 nameXMMReg(gregOfRexRM(pfx,rm)) );
7195 return delta+alen;
7196 }
7197}
7198
7199
7200/* All lanes SSE binary operation, G = G `op` E. */
7201
7202static
sewardj8d965312005-02-25 02:48:47 +00007203ULong dis_SSE_E_to_G_all ( Prefix pfx, ULong delta,
7204 HChar* opname, IROp op )
sewardj9da16972005-02-21 13:58:26 +00007205{
7206 return dis_SSE_E_to_G_all_wrk( pfx, delta, opname, op, False );
7207}
7208
sewardj8d965312005-02-25 02:48:47 +00007209/* All lanes SSE binary operation, G = (not G) `op` E. */
7210
7211static
7212ULong dis_SSE_E_to_G_all_invG ( Prefix pfx, ULong delta,
7213 HChar* opname, IROp op )
7214{
7215 return dis_SSE_E_to_G_all_wrk( pfx, delta, opname, op, True );
7216}
7217
7218
7219/* Lowest 32-bit lane only SSE binary operation, G = G `op` E. */
7220
7221static ULong dis_SSE_E_to_G_lo32 ( Prefix pfx, ULong delta,
7222 HChar* opname, IROp op )
7223{
7224 HChar dis_buf[50];
7225 Int alen;
7226 IRTemp addr;
7227 UChar rm = getUChar(delta);
sewardj9c9ee3d2005-02-26 01:17:42 +00007228 IRExpr* gpart = getXMMReg(gregOfRexRM(pfx,rm));
sewardj8d965312005-02-25 02:48:47 +00007229 if (epartIsReg(rm)) {
sewardj9c9ee3d2005-02-26 01:17:42 +00007230 putXMMReg( gregOfRexRM(pfx,rm),
sewardj8d965312005-02-25 02:48:47 +00007231 binop(op, gpart,
7232 getXMMReg(eregOfRexRM(pfx,rm))) );
7233 DIP("%s %s,%s\n", opname,
7234 nameXMMReg(eregOfRexRM(pfx,rm)),
7235 nameXMMReg(gregOfRexRM(pfx,rm)) );
7236 return delta+1;
7237 } else {
7238 /* We can only do a 32-bit memory read, so the upper 3/4 of the
7239 E operand needs to be made simply of zeroes. */
7240 IRTemp epart = newTemp(Ity_V128);
7241 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
7242 assign( epart, unop( Iop_32UtoV128,
7243 loadLE(Ity_I32, mkexpr(addr))) );
7244 putXMMReg( gregOfRexRM(pfx,rm),
7245 binop(op, gpart, mkexpr(epart)) );
7246 DIP("%s %s,%s\n", opname,
7247 dis_buf,
7248 nameXMMReg(gregOfRexRM(pfx,rm)) );
7249 return delta+alen;
7250 }
7251}
sewardj1001dc42005-02-21 08:25:55 +00007252
7253
7254/* Lower 64-bit lane only SSE binary operation, G = G `op` E. */
7255
sewardj8d965312005-02-25 02:48:47 +00007256static ULong dis_SSE_E_to_G_lo64 ( Prefix pfx, ULong delta,
7257 HChar* opname, IROp op )
sewardj1001dc42005-02-21 08:25:55 +00007258{
7259 HChar dis_buf[50];
7260 Int alen;
7261 IRTemp addr;
7262 UChar rm = getUChar(delta);
7263 IRExpr* gpart = getXMMReg(gregOfRexRM(pfx,rm));
7264 if (epartIsReg(rm)) {
7265 putXMMReg( gregOfRexRM(pfx,rm),
7266 binop(op, gpart,
7267 getXMMReg(eregOfRexRM(pfx,rm))) );
7268 DIP("%s %s,%s\n", opname,
7269 nameXMMReg(eregOfRexRM(pfx,rm)),
7270 nameXMMReg(gregOfRexRM(pfx,rm)) );
7271 return delta+1;
7272 } else {
7273 /* We can only do a 64-bit memory read, so the upper half of the
7274 E operand needs to be made simply of zeroes. */
7275 IRTemp epart = newTemp(Ity_V128);
7276 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
7277 assign( epart, unop( Iop_64UtoV128,
7278 loadLE(Ity_I64, mkexpr(addr))) );
7279 putXMMReg( gregOfRexRM(pfx,rm),
7280 binop(op, gpart, mkexpr(epart)) );
7281 DIP("%s %s,%s\n", opname,
7282 dis_buf,
7283 nameXMMReg(gregOfRexRM(pfx,rm)) );
7284 return delta+alen;
7285 }
7286}
7287
7288
sewardjd20c8852005-01-20 20:04:07 +00007289//.. /* All lanes unary SSE operation, G = op(E). */
7290//..
7291//.. static UInt dis_SSE_E_to_G_unary_all (
sewardj9da16972005-02-21 13:58:26 +00007292//.. UChar sorb, ULong delta,
sewardjd20c8852005-01-20 20:04:07 +00007293//.. HChar* opname, IROp op
7294//.. )
7295//.. {
7296//.. HChar dis_buf[50];
7297//.. Int alen;
7298//.. IRTemp addr;
sewardj8c332e22005-01-28 01:36:56 +00007299//.. UChar rm = getUChar(delta);
sewardjd20c8852005-01-20 20:04:07 +00007300//.. if (epartIsReg(rm)) {
7301//.. putXMMReg( gregOfRM(rm),
7302//.. unop(op, getXMMReg(eregOfRM(rm))) );
7303//.. DIP("%s %s,%s\n", opname,
7304//.. nameXMMReg(eregOfRM(rm)),
7305//.. nameXMMReg(gregOfRM(rm)) );
7306//.. return delta+1;
7307//.. } else {
7308//.. addr = disAMode ( &alen, sorb, delta, dis_buf );
7309//.. putXMMReg( gregOfRM(rm),
7310//.. unop(op, loadLE(Ity_V128, mkexpr(addr))) );
7311//.. DIP("%s %s,%s\n", opname,
7312//.. dis_buf,
7313//.. nameXMMReg(gregOfRM(rm)) );
7314//.. return delta+alen;
7315//.. }
7316//.. }
7317//..
7318//..
7319//.. /* Lowest 32-bit lane only unary SSE operation, G = op(E). */
7320//..
7321//.. static UInt dis_SSE_E_to_G_unary_lo32 (
sewardj9da16972005-02-21 13:58:26 +00007322//.. UChar sorb, ULong delta,
sewardjd20c8852005-01-20 20:04:07 +00007323//.. HChar* opname, IROp op
7324//.. )
7325//.. {
7326//.. /* First we need to get the old G value and patch the low 32 bits
7327//.. of the E operand into it. Then apply op and write back to G. */
7328//.. HChar dis_buf[50];
7329//.. Int alen;
7330//.. IRTemp addr;
sewardj8c332e22005-01-28 01:36:56 +00007331//.. UChar rm = getUChar(delta);
sewardjd20c8852005-01-20 20:04:07 +00007332//.. IRTemp oldG0 = newTemp(Ity_V128);
7333//.. IRTemp oldG1 = newTemp(Ity_V128);
7334//..
7335//.. assign( oldG0, getXMMReg(gregOfRM(rm)) );
7336//..
7337//.. if (epartIsReg(rm)) {
7338//.. assign( oldG1,
7339//.. binop( Iop_Set128lo32,
7340//.. mkexpr(oldG0),
7341//.. getXMMRegLane32(eregOfRM(rm), 0)) );
7342//.. putXMMReg( gregOfRM(rm), unop(op, mkexpr(oldG1)) );
7343//.. DIP("%s %s,%s\n", opname,
7344//.. nameXMMReg(eregOfRM(rm)),
7345//.. nameXMMReg(gregOfRM(rm)) );
7346//.. return delta+1;
7347//.. } else {
7348//.. addr = disAMode ( &alen, sorb, delta, dis_buf );
7349//.. assign( oldG1,
7350//.. binop( Iop_Set128lo32,
7351//.. mkexpr(oldG0),
7352//.. loadLE(Ity_I32, mkexpr(addr)) ));
7353//.. putXMMReg( gregOfRM(rm), unop(op, mkexpr(oldG1)) );
7354//.. DIP("%s %s,%s\n", opname,
7355//.. dis_buf,
7356//.. nameXMMReg(gregOfRM(rm)) );
7357//.. return delta+alen;
7358//.. }
7359//.. }
sewardj1001dc42005-02-21 08:25:55 +00007360
7361
7362/* Lowest 64-bit lane only unary SSE operation, G = op(E). */
7363
sewardj8d965312005-02-25 02:48:47 +00007364static ULong dis_SSE_E_to_G_unary_lo64 (
7365 Prefix pfx, ULong delta,
7366 HChar* opname, IROp op
7367 )
sewardj1001dc42005-02-21 08:25:55 +00007368{
7369 /* First we need to get the old G value and patch the low 64 bits
7370 of the E operand into it. Then apply op and write back to G. */
7371 HChar dis_buf[50];
7372 Int alen;
7373 IRTemp addr;
7374 UChar rm = getUChar(delta);
7375 IRTemp oldG0 = newTemp(Ity_V128);
7376 IRTemp oldG1 = newTemp(Ity_V128);
7377
7378 assign( oldG0, getXMMReg(gregOfRexRM(pfx,rm)) );
7379
7380 if (epartIsReg(rm)) {
7381 assign( oldG1,
7382 binop( Iop_SetV128lo64,
7383 mkexpr(oldG0),
7384 getXMMRegLane64(eregOfRexRM(pfx,rm), 0)) );
7385 putXMMReg( gregOfRexRM(pfx,rm), unop(op, mkexpr(oldG1)) );
7386 DIP("%s %s,%s\n", opname,
7387 nameXMMReg(eregOfRexRM(pfx,rm)),
7388 nameXMMReg(gregOfRexRM(pfx,rm)) );
7389 return delta+1;
7390 } else {
7391 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
7392 assign( oldG1,
7393 binop( Iop_SetV128lo64,
7394 mkexpr(oldG0),
7395 loadLE(Ity_I64, mkexpr(addr)) ));
7396 putXMMReg( gregOfRexRM(pfx,rm), unop(op, mkexpr(oldG1)) );
7397 DIP("%s %s,%s\n", opname,
7398 dis_buf,
7399 nameXMMReg(gregOfRexRM(pfx,rm)) );
7400 return delta+alen;
7401 }
7402}
7403
7404
sewardjd20c8852005-01-20 20:04:07 +00007405//.. /* SSE integer binary operation:
7406//.. G = G `op` E (eLeft == False)
7407//.. G = E `op` G (eLeft == True)
7408//.. */
7409//.. static UInt dis_SSEint_E_to_G(
sewardj9da16972005-02-21 13:58:26 +00007410//.. UChar sorb, ULong delta,
sewardjd20c8852005-01-20 20:04:07 +00007411//.. HChar* opname, IROp op,
7412//.. Bool eLeft
7413//.. )
7414//.. {
7415//.. HChar dis_buf[50];
7416//.. Int alen;
7417//.. IRTemp addr;
sewardj8c332e22005-01-28 01:36:56 +00007418//.. UChar rm = getUChar(delta);
sewardjd20c8852005-01-20 20:04:07 +00007419//.. IRExpr* gpart = getXMMReg(gregOfRM(rm));
7420//.. IRExpr* epart = NULL;
7421//.. if (epartIsReg(rm)) {
7422//.. epart = getXMMReg(eregOfRM(rm));
7423//.. DIP("%s %s,%s\n", opname,
7424//.. nameXMMReg(eregOfRM(rm)),
7425//.. nameXMMReg(gregOfRM(rm)) );
7426//.. delta += 1;
7427//.. } else {
7428//.. addr = disAMode ( &alen, sorb, delta, dis_buf );
7429//.. epart = loadLE(Ity_V128, mkexpr(addr));
7430//.. DIP("%s %s,%s\n", opname,
7431//.. dis_buf,
7432//.. nameXMMReg(gregOfRM(rm)) );
7433//.. delta += alen;
7434//.. }
7435//.. putXMMReg( gregOfRM(rm),
7436//.. eLeft ? binop(op, epart, gpart)
7437//.. : binop(op, gpart, epart) );
7438//.. return delta;
7439//.. }
sewardj8d965312005-02-25 02:48:47 +00007440
7441
7442/* Helper for doing SSE FP comparisons. */
7443
7444static void findSSECmpOp ( Bool* needNot, IROp* op,
7445 Int imm8, Bool all_lanes, Int sz )
7446{
7447 imm8 &= 7;
7448 *needNot = False;
7449 *op = Iop_INVALID;
7450 if (imm8 >= 4) {
7451 *needNot = True;
7452 imm8 -= 4;
7453 }
7454
7455 if (sz == 4 && all_lanes) {
7456 switch (imm8) {
7457 case 0: *op = Iop_CmpEQ32Fx4; return;
7458 case 1: *op = Iop_CmpLT32Fx4; return;
7459 case 2: *op = Iop_CmpLE32Fx4; return;
7460 case 3: *op = Iop_CmpUN32Fx4; return;
7461 default: break;
7462 }
7463 }
7464 if (sz == 4 && !all_lanes) {
7465 switch (imm8) {
7466 case 0: *op = Iop_CmpEQ32F0x4; return;
7467 case 1: *op = Iop_CmpLT32F0x4; return;
7468 case 2: *op = Iop_CmpLE32F0x4; return;
7469 case 3: *op = Iop_CmpUN32F0x4; return;
7470 default: break;
7471 }
7472 }
7473 if (sz == 8 && all_lanes) {
7474 switch (imm8) {
7475 case 0: *op = Iop_CmpEQ64Fx2; return;
7476 case 1: *op = Iop_CmpLT64Fx2; return;
7477 case 2: *op = Iop_CmpLE64Fx2; return;
7478 case 3: *op = Iop_CmpUN64Fx2; return;
7479 default: break;
7480 }
7481 }
7482 if (sz == 8 && !all_lanes) {
7483 switch (imm8) {
7484 case 0: *op = Iop_CmpEQ64F0x2; return;
7485 case 1: *op = Iop_CmpLT64F0x2; return;
7486 case 2: *op = Iop_CmpLE64F0x2; return;
7487 case 3: *op = Iop_CmpUN64F0x2; return;
7488 default: break;
7489 }
7490 }
7491 vpanic("findSSECmpOp(amd64,guest)");
7492}
7493
7494/* Handles SSE 32F comparisons. */
7495
7496static ULong dis_SSEcmp_E_to_G ( Prefix pfx, ULong delta,
7497 HChar* opname, Bool all_lanes, Int sz )
7498{
7499 HChar dis_buf[50];
7500 Int alen, imm8;
7501 IRTemp addr;
7502 Bool needNot = False;
7503 IROp op = Iop_INVALID;
7504 IRTemp plain = newTemp(Ity_V128);
7505 UChar rm = getUChar(delta);
7506 UShort mask = 0;
7507 vassert(sz == 4 || sz == 8);
7508 if (epartIsReg(rm)) {
7509 imm8 = getUChar(delta+1);
7510 findSSECmpOp(&needNot, &op, imm8, all_lanes, sz);
7511 assign( plain, binop(op, getXMMReg(gregOfRexRM(pfx,rm)),
7512 getXMMReg(eregOfRexRM(pfx,rm))) );
7513 delta += 2;
7514 DIP("%s $%d,%s,%s\n", opname,
7515 (Int)imm8,
7516 nameXMMReg(eregOfRexRM(pfx,rm)),
7517 nameXMMReg(gregOfRexRM(pfx,rm)) );
7518 } else {
7519 addr = disAMode ( &alen, pfx, delta, dis_buf, 1 );
7520 imm8 = getUChar(delta+alen);
7521 findSSECmpOp(&needNot, &op, imm8, all_lanes, sz);
7522 assign( plain, binop(op, getXMMReg(gregOfRexRM(pfx,rm)),
7523 loadLE(Ity_V128, mkexpr(addr))) );
7524 delta += alen+1;
7525 DIP("%s $%d,%s,%s\n", opname,
7526 (Int)imm8,
7527 dis_buf,
7528 nameXMMReg(gregOfRexRM(pfx,rm)) );
7529 }
7530
7531 if (needNot && all_lanes) {
sewardj9c9ee3d2005-02-26 01:17:42 +00007532 putXMMReg( gregOfRexRM(pfx,rm),
sewardj8d965312005-02-25 02:48:47 +00007533 unop(Iop_NotV128, mkexpr(plain)) );
7534 }
7535 else
7536 if (needNot && !all_lanes) {
sewardj1027dc22005-02-26 01:55:02 +00007537 mask = toUShort(sz==4 ? 0x000F : 0x00FF);
sewardj8d965312005-02-25 02:48:47 +00007538 putXMMReg( gregOfRexRM(pfx,rm),
7539 binop(Iop_XorV128, mkexpr(plain), mkV128(mask)) );
7540 }
7541 else {
7542 putXMMReg( gregOfRexRM(pfx,rm), mkexpr(plain) );
7543 }
7544
7545 return delta;
7546}
7547
7548
sewardjd20c8852005-01-20 20:04:07 +00007549//.. /* Vector by scalar shift of G by the amount specified at the bottom
7550//.. of E. */
7551//..
sewardj9da16972005-02-21 13:58:26 +00007552//.. static UInt dis_SSE_shiftG_byE ( UChar sorb, ULong delta,
sewardjd20c8852005-01-20 20:04:07 +00007553//.. HChar* opname, IROp op )
7554//.. {
7555//.. HChar dis_buf[50];
7556//.. Int alen, size;
7557//.. IRTemp addr;
7558//.. Bool shl, shr, sar;
sewardj8c332e22005-01-28 01:36:56 +00007559//.. UChar rm = getUChar(delta);
sewardjd20c8852005-01-20 20:04:07 +00007560//.. IRTemp g0 = newTemp(Ity_V128);
7561//.. IRTemp g1 = newTemp(Ity_V128);
7562//.. IRTemp amt = newTemp(Ity_I32);
7563//.. IRTemp amt8 = newTemp(Ity_I8);
7564//.. if (epartIsReg(rm)) {
7565//.. assign( amt, getXMMRegLane32(eregOfRM(rm), 0) );
7566//.. DIP("%s %s,%s\n", opname,
7567//.. nameXMMReg(eregOfRM(rm)),
7568//.. nameXMMReg(gregOfRM(rm)) );
7569//.. delta++;
7570//.. } else {
7571//.. addr = disAMode ( &alen, sorb, delta, dis_buf );
7572//.. assign( amt, loadLE(Ity_I32, mkexpr(addr)) );
7573//.. DIP("%s %s,%s\n", opname,
7574//.. dis_buf,
7575//.. nameXMMReg(gregOfRM(rm)) );
7576//.. delta += alen;
7577//.. }
7578//.. assign( g0, getXMMReg(gregOfRM(rm)) );
7579//.. assign( amt8, unop(Iop_32to8, mkexpr(amt)) );
7580//..
7581//.. shl = shr = sar = False;
7582//.. size = 0;
7583//.. switch (op) {
7584//.. case Iop_ShlN16x8: shl = True; size = 32; break;
7585//.. case Iop_ShlN32x4: shl = True; size = 32; break;
7586//.. case Iop_ShlN64x2: shl = True; size = 64; break;
7587//.. case Iop_SarN16x8: sar = True; size = 16; break;
7588//.. case Iop_SarN32x4: sar = True; size = 32; break;
7589//.. case Iop_ShrN16x8: shr = True; size = 16; break;
7590//.. case Iop_ShrN32x4: shr = True; size = 32; break;
7591//.. case Iop_ShrN64x2: shr = True; size = 64; break;
7592//.. default: vassert(0);
7593//.. }
7594//..
7595//.. if (shl || shr) {
7596//.. assign(
7597//.. g1,
7598//.. IRExpr_Mux0X(
7599//.. unop(Iop_1Uto8,binop(Iop_CmpLT32U,mkexpr(amt),mkU32(size))),
7600//.. mkV128(0x0000),
7601//.. binop(op, mkexpr(g0), mkexpr(amt8))
7602//.. )
7603//.. );
7604//.. } else
7605//.. if (sar) {
7606//.. assign(
7607//.. g1,
7608//.. IRExpr_Mux0X(
7609//.. unop(Iop_1Uto8,binop(Iop_CmpLT32U,mkexpr(amt),mkU32(size))),
7610//.. binop(op, mkexpr(g0), mkU8(size-1)),
7611//.. binop(op, mkexpr(g0), mkexpr(amt8))
7612//.. )
7613//.. );
7614//.. } else {
7615//.. vassert(0);
7616//.. }
7617//..
7618//.. putXMMReg( gregOfRM(rm), mkexpr(g1) );
7619//.. return delta;
7620//.. }
7621//..
7622//..
7623//.. /* Vector by scalar shift of E by an immediate byte. */
7624//..
7625//.. static
sewardj9da16972005-02-21 13:58:26 +00007626//.. UInt dis_SSE_shiftE_imm ( ULong delta, HChar* opname, IROp op )
sewardjd20c8852005-01-20 20:04:07 +00007627//.. {
7628//.. Bool shl, shr, sar;
sewardj8c332e22005-01-28 01:36:56 +00007629//.. UChar rm = getUChar(delta);
sewardjd20c8852005-01-20 20:04:07 +00007630//.. IRTemp e0 = newTemp(Ity_V128);
7631//.. IRTemp e1 = newTemp(Ity_V128);
7632//.. UChar amt, size;
7633//.. vassert(epartIsReg(rm));
7634//.. vassert(gregOfRM(rm) == 2
7635//.. || gregOfRM(rm) == 4 || gregOfRM(rm) == 6);
sewardj8c332e22005-01-28 01:36:56 +00007636//.. amt = (Int)(getUChar(delta+1));
sewardjd20c8852005-01-20 20:04:07 +00007637//.. delta += 2;
7638//.. DIP("%s $%d,%s\n", opname,
7639//.. (Int)amt,
7640//.. nameXMMReg(eregOfRM(rm)) );
7641//.. assign( e0, getXMMReg(eregOfRM(rm)) );
7642//..
7643//.. shl = shr = sar = False;
7644//.. size = 0;
7645//.. switch (op) {
7646//.. case Iop_ShlN16x8: shl = True; size = 16; break;
7647//.. case Iop_ShlN32x4: shl = True; size = 32; break;
7648//.. case Iop_ShlN64x2: shl = True; size = 64; break;
7649//.. case Iop_SarN16x8: sar = True; size = 16; break;
7650//.. case Iop_SarN32x4: sar = True; size = 32; break;
7651//.. case Iop_ShrN16x8: shr = True; size = 16; break;
7652//.. case Iop_ShrN32x4: shr = True; size = 32; break;
7653//.. case Iop_ShrN64x2: shr = True; size = 64; break;
7654//.. default: vassert(0);
7655//.. }
7656//..
7657//.. if (shl || shr) {
7658//.. assign( e1, amt >= size
7659//.. ? mkV128(0x0000)
7660//.. : binop(op, mkexpr(e0), mkU8(amt))
7661//.. );
7662//.. } else
7663//.. if (sar) {
7664//.. assign( e1, amt >= size
7665//.. ? binop(op, mkexpr(e0), mkU8(size-1))
7666//.. : binop(op, mkexpr(e0), mkU8(amt))
7667//.. );
7668//.. } else {
7669//.. vassert(0);
7670//.. }
7671//..
7672//.. putXMMReg( eregOfRM(rm), mkexpr(e1) );
7673//.. return delta;
7674//.. }
sewardj1a01e652005-02-23 11:39:21 +00007675
7676
7677/* Get the current SSE rounding mode. */
7678
7679static IRExpr* /* :: Ity_I32 */ get_sse_roundingmode ( void )
7680{
7681 return
7682 unop( Iop_64to32,
7683 binop( Iop_And64,
7684 IRExpr_Get( OFFB_SSEROUND, Ity_I64 ),
7685 mkU64(3) ));
7686}
7687
sewardjd20c8852005-01-20 20:04:07 +00007688//.. static void put_sse_roundingmode ( IRExpr* sseround )
7689//.. {
7690//.. vassert(typeOfIRExpr(irbb->tyenv, sseround) == Ity_I32);
7691//.. stmt( IRStmt_Put( OFFB_SSEROUND, sseround ) );
7692//.. }
7693//..
7694//.. /* Break a 128-bit value up into four 32-bit ints. */
7695//..
7696//.. static void breakup128to32s ( IRTemp t128,
7697//.. /*OUTs*/
7698//.. IRTemp* t3, IRTemp* t2,
7699//.. IRTemp* t1, IRTemp* t0 )
7700//.. {
7701//.. IRTemp hi64 = newTemp(Ity_I64);
7702//.. IRTemp lo64 = newTemp(Ity_I64);
7703//.. assign( hi64, unop(Iop_128HIto64, mkexpr(t128)) );
7704//.. assign( lo64, unop(Iop_128to64, mkexpr(t128)) );
7705//..
7706//.. vassert(t0 && *t0 == IRTemp_INVALID);
7707//.. vassert(t1 && *t1 == IRTemp_INVALID);
7708//.. vassert(t2 && *t2 == IRTemp_INVALID);
7709//.. vassert(t3 && *t3 == IRTemp_INVALID);
7710//..
7711//.. *t0 = newTemp(Ity_I32);
7712//.. *t1 = newTemp(Ity_I32);
7713//.. *t2 = newTemp(Ity_I32);
7714//.. *t3 = newTemp(Ity_I32);
7715//.. assign( *t0, unop(Iop_64to32, mkexpr(lo64)) );
7716//.. assign( *t1, unop(Iop_64HIto32, mkexpr(lo64)) );
7717//.. assign( *t2, unop(Iop_64to32, mkexpr(hi64)) );
7718//.. assign( *t3, unop(Iop_64HIto32, mkexpr(hi64)) );
7719//.. }
7720//..
7721//.. /* Construct a 128-bit value from four 32-bit ints. */
7722//..
7723//.. static IRExpr* mk128from32s ( IRTemp t3, IRTemp t2,
7724//.. IRTemp t1, IRTemp t0 )
7725//.. {
7726//.. return
7727//.. binop( Iop_64HLto128,
7728//.. binop(Iop_32HLto64, mkexpr(t3), mkexpr(t2)),
7729//.. binop(Iop_32HLto64, mkexpr(t1), mkexpr(t0))
7730//.. );
7731//.. }
7732//..
7733//.. /* Break a 64-bit value up into four 16-bit ints. */
7734//..
7735//.. static void breakup64to16s ( IRTemp t64,
7736//.. /*OUTs*/
7737//.. IRTemp* t3, IRTemp* t2,
7738//.. IRTemp* t1, IRTemp* t0 )
7739//.. {
7740//.. IRTemp hi32 = newTemp(Ity_I32);
7741//.. IRTemp lo32 = newTemp(Ity_I32);
7742//.. assign( hi32, unop(Iop_64HIto32, mkexpr(t64)) );
7743//.. assign( lo32, unop(Iop_64to32, mkexpr(t64)) );
7744//..
7745//.. vassert(t0 && *t0 == IRTemp_INVALID);
7746//.. vassert(t1 && *t1 == IRTemp_INVALID);
7747//.. vassert(t2 && *t2 == IRTemp_INVALID);
7748//.. vassert(t3 && *t3 == IRTemp_INVALID);
7749//..
7750//.. *t0 = newTemp(Ity_I16);
7751//.. *t1 = newTemp(Ity_I16);
7752//.. *t2 = newTemp(Ity_I16);
7753//.. *t3 = newTemp(Ity_I16);
7754//.. assign( *t0, unop(Iop_32to16, mkexpr(lo32)) );
7755//.. assign( *t1, unop(Iop_32HIto16, mkexpr(lo32)) );
7756//.. assign( *t2, unop(Iop_32to16, mkexpr(hi32)) );
7757//.. assign( *t3, unop(Iop_32HIto16, mkexpr(hi32)) );
7758//.. }
7759//..
7760//.. /* Construct a 64-bit value from four 16-bit ints. */
7761//..
7762//.. static IRExpr* mk64from16s ( IRTemp t3, IRTemp t2,
7763//.. IRTemp t1, IRTemp t0 )
7764//.. {
7765//.. return
7766//.. binop( Iop_32HLto64,
7767//.. binop(Iop_16HLto32, mkexpr(t3), mkexpr(t2)),
7768//.. binop(Iop_16HLto32, mkexpr(t1), mkexpr(t0))
7769//.. );
7770//.. }
sewardjdf0e0022005-01-25 15:48:43 +00007771
7772
7773/*------------------------------------------------------------*/
7774/*--- Disassemble a single instruction ---*/
7775/*------------------------------------------------------------*/
7776
7777/* Disassemble a single instruction into IR. The instruction
7778 is located in host memory at &guest_code[delta].
7779 Set *size to be the size of the instruction.
7780 If the returned value is Dis_Resteer,
7781 the next guest address is assigned to *whereNext. If resteerOK
7782 is False, disInstr may not return Dis_Resteer. */
7783
7784static
7785DisResult disInstr ( /*IN*/ Bool resteerOK,
7786 /*IN*/ Bool (*resteerOkFn) ( Addr64 ),
7787 /*IN*/ ULong delta,
7788 /*IN*/ VexSubArch subarch,
sewardj1027dc22005-02-26 01:55:02 +00007789 /*OUT*/ Long* size,
sewardjdf0e0022005-01-25 15:48:43 +00007790 /*OUT*/ Addr64* whereNext )
7791{
7792 IRType ty;
sewardj85520e42005-02-19 15:22:38 +00007793 IRTemp addr, /* t0, */ t1, t2, t3, t4 /*, t5, t6 */;
sewardjdf0e0022005-01-25 15:48:43 +00007794 Int alen;
sewardj7a240552005-01-28 21:37:12 +00007795 UChar opc, modrm, /*abyte,*/ pre;
sewardj1027dc22005-02-26 01:55:02 +00007796 Long d64;
sewardjdf0e0022005-01-25 15:48:43 +00007797 HChar dis_buf[50];
7798 Int am_sz, d_sz, n, n_prefixes;
7799 DisResult whatNext = Dis_Continue;
sewardja6b93d12005-02-17 09:28:28 +00007800 UChar* insn; /* used in SSE decoders */
sewardjdf0e0022005-01-25 15:48:43 +00007801
7802 /* Holds eip at the start of the insn, so that we can print
7803 consistent error messages for unimplemented insns. */
7804 ULong delta_start = delta;
7805
7806 /* sz denotes the nominal data-op size of the insn; we change it to
7807 2 if an 0x66 prefix is seen and 8 if REX.W is 1. In case of
7808 conflict REX.W takes precedence. */
7809 Int sz = 4;
7810
sewardj3ca55a12005-01-27 16:06:23 +00007811 /* pfx holds the summary of prefixes. */
7812 Prefix pfx = PFX_EMPTY;
sewardjdf0e0022005-01-25 15:48:43 +00007813
sewardj4b744762005-02-07 15:02:25 +00007814 /* If we don't set *size properly, this causes bbToIR_AMD64Instr to
sewardjdf0e0022005-01-25 15:48:43 +00007815 assert. */
7816 *size = 0;
7817
sewardj4b744762005-02-07 15:02:25 +00007818 vassert(guest_rip_next_assumed == 0);
7819 vassert(guest_rip_next_mustcheck == False);
7820
sewardj85520e42005-02-19 15:22:38 +00007821 addr = /* t0 = */ t1 = t2 = t3 = t4 = /* t5 = t6 = */ IRTemp_INVALID;
sewardjdf0e0022005-01-25 15:48:43 +00007822
7823 DIP("\t0x%llx: ", guest_rip_bbstart+delta);
7824
7825 /* Spot the client-request magic sequence. */
7826 {
7827 UChar* code = (UChar*)(guest_code + delta);
7828 /* Spot this:
7829 C1C01D roll $29, %eax
7830 C1C003 roll $3, %eax
7831 C1C81B rorl $27, %eax
7832 C1C805 rorl $5, %eax
7833 C1C00D roll $13, %eax
7834 C1C013 roll $19, %eax
7835 */
7836 if (code[ 0] == 0xC1 && code[ 1] == 0xC0 && code[ 2] == 0x1D &&
7837 code[ 3] == 0xC1 && code[ 4] == 0xC0 && code[ 5] == 0x03 &&
7838 code[ 6] == 0xC1 && code[ 7] == 0xC8 && code[ 8] == 0x1B &&
7839 code[ 9] == 0xC1 && code[10] == 0xC8 && code[11] == 0x05 &&
7840 code[12] == 0xC1 && code[13] == 0xC0 && code[14] == 0x0D &&
7841 code[15] == 0xC1 && code[16] == 0xC0 && code[17] == 0x13
7842 ) {
7843 DIP("%%edx = client_request ( %%eax )\n");
7844 delta += 18;
7845 jmp_lit(Ijk_ClientReq, guest_rip_bbstart+delta);
7846 whatNext = Dis_StopHere;
7847 goto decode_success;
7848 }
7849 }
7850
7851 /* Eat prefixes, summarising the result in pfx and sz, and rejecting
7852 as many invalid combinations as possible. */
7853 n_prefixes = 0;
7854 while (True) {
7855 if (n_prefixes > 5) goto decode_failure;
sewardj8c332e22005-01-28 01:36:56 +00007856 pre = getUChar(delta);
sewardjdf0e0022005-01-25 15:48:43 +00007857 switch (pre) {
7858 case 0x66: pfx |= PFX_66; break;
7859 case 0x67: pfx |= PFX_ASO; break;
7860 case 0xF2: pfx |= PFX_F2; break;
7861 case 0xF3: pfx |= PFX_F3; break;
7862 case 0xF0: pfx |= PFX_LOCK; break;
7863 case 0x2E: pfx |= PFX_CS; break;
7864 case 0x3E: pfx |= PFX_DS; break;
7865 case 0x26: pfx |= PFX_ES; break;
7866 case 0x64: pfx |= PFX_FS; break;
7867 case 0x65: pfx |= PFX_GS; break;
7868 case 0x36: pfx |= PFX_SS; break;
7869 case 0x40 ... 0x4F:
7870 pfx |= PFX_REX;
7871 if (pre & (1<<3)) pfx |= PFX_REXW;
7872 if (pre & (1<<2)) pfx |= PFX_REXR;
7873 if (pre & (1<<1)) pfx |= PFX_REXX;
7874 if (pre & (1<<0)) pfx |= PFX_REXB;
7875 break;
7876 default:
7877 goto not_a_prefix;
7878 }
7879 n_prefixes++;
7880 delta++;
7881 }
7882
7883 not_a_prefix:
7884 /* Dump invalid combinations */
sewardj3ca55a12005-01-27 16:06:23 +00007885 if (pfx & PFX_ASO)
7886 goto decode_failure; /* don't support address-size override */
sewardjdf0e0022005-01-25 15:48:43 +00007887
7888 n = 0;
7889 if (pfx & PFX_F2) n++;
7890 if (pfx & PFX_F3) n++;
sewardj3ca55a12005-01-27 16:06:23 +00007891 if (n > 1)
7892 goto decode_failure; /* can't have both */
sewardjdf0e0022005-01-25 15:48:43 +00007893
7894 n = 0;
7895 if (pfx & PFX_CS) n++;
7896 if (pfx & PFX_DS) n++;
7897 if (pfx & PFX_ES) n++;
7898 if (pfx & PFX_FS) n++;
7899 if (pfx & PFX_GS) n++;
7900 if (pfx & PFX_SS) n++;
sewardj3ca55a12005-01-27 16:06:23 +00007901 if (n > 1)
7902 goto decode_failure; /* multiple seg overrides == illegal */
sewardjdf0e0022005-01-25 15:48:43 +00007903
7904 /* Set up sz. */
7905 sz = 4;
7906 if (pfx & PFX_66) sz = 2;
7907 if ((pfx & PFX_REX) && (pfx & PFX_REXW)) sz = 8;
7908
7909 /* temp hack re LOCK */
7910 if (1 && (pfx & PFX_LOCK)) {
7911 vex_printf("vex amd64->IR: ignoring LOCK prefix on: ");
7912 insn_verbose = True;
7913 }
7914
sewardjd20c8852005-01-20 20:04:07 +00007915//.. /* Skip a LOCK prefix. */
7916//.. /* 2005 Jan 06: the following insns are observed to sometimes
7917//.. have a LOCK prefix:
7918//.. cmpxchgl %ecx,(%edx)
7919//.. cmpxchgl %edx,0x278(%ebx) etc
7920//.. xchgl %eax, (%ecx)
7921//.. xaddl %eax, (%ecx)
7922//.. We need to catch any such which appear to be being used as
7923//.. a memory barrier, for example lock addl $0,0(%esp)
7924//.. and emit an IR MFence construct.
7925//.. */
sewardj8c332e22005-01-28 01:36:56 +00007926//.. if (getUChar(delta) == 0xF0) {
sewardjd20c8852005-01-20 20:04:07 +00007927//..
7928//.. UChar* code = (UChar*)(guest_code + delta);
7929//..
7930//.. /* Various bits of kernel headers use the following as a memory
7931//.. barrier. Hence, first emit an MFence and then let the insn
7932//.. go through as usual. */
7933//.. /* F08344240000: lock addl $0, 0(%esp) */
7934//.. if (code[0] == 0xF0 && code[1] == 0x83 && code[2] == 0x44 &&
7935//.. code[3] == 0x24 && code[4] == 0x00 && code[5] == 0x00) {
7936//.. stmt( IRStmt_MFence() );
7937//.. }
7938//.. else
7939//.. if (0) {
7940//.. vex_printf("vex x86->IR: ignoring LOCK prefix on: ");
7941//.. insn_verbose = True;
7942//.. }
7943//..
7944//.. /* In any case, skip the prefix. */
7945//.. delta++;
7946//.. }
7947//..
7948//.. /* Detect operand-size overrides. */
sewardj8c332e22005-01-28 01:36:56 +00007949//.. if (getUChar(delta) == 0x66) { sz = 2; delta++; };
sewardjd20c8852005-01-20 20:04:07 +00007950//..
7951//.. /* segment override prefixes come after the operand-size override,
7952//.. it seems */
sewardj8c332e22005-01-28 01:36:56 +00007953//.. switch (getUChar(delta)) {
sewardjd20c8852005-01-20 20:04:07 +00007954//.. case 0x3E: /* %DS: */
7955//.. case 0x26: /* %ES: */
7956//.. case 0x64: /* %FS: */
7957//.. case 0x65: /* %GS: */
sewardj8c332e22005-01-28 01:36:56 +00007958//.. sorb = getUChar(delta); delta++;
sewardjd20c8852005-01-20 20:04:07 +00007959//.. break;
7960//.. case 0x2E: /* %CS: */
7961//.. /* 2E prefix on a conditional branch instruction is a
7962//.. branch-prediction hint, which can safely be ignored. */
7963//.. {
sewardj8c332e22005-01-28 01:36:56 +00007964//.. UChar op1 = getUChar(delta+1);
7965//.. UChar op2 = getUChar(delta+2);
sewardjd20c8852005-01-20 20:04:07 +00007966//.. if ((op1 >= 0x70 && op1 <= 0x7F)
7967//.. || (op1 == 0xE3)
7968//.. || (op1 == 0x0F && op2 >= 0x80 && op2 <= 0x8F)) {
7969//.. vex_printf("vex x86->IR: ignoring branch hint\n");
sewardj8c332e22005-01-28 01:36:56 +00007970//.. sorb = getUChar(delta); delta++;
sewardjd20c8852005-01-20 20:04:07 +00007971//.. break;
7972//.. }
7973//.. }
7974//.. unimplemented("x86 segment override (SEG=CS) prefix");
7975//.. /*NOTREACHED*/
7976//.. break;
7977//.. case 0x36: /* %SS: */
7978//.. unimplemented("x86 segment override (SEG=SS) prefix");
7979//.. /*NOTREACHED*/
7980//.. break;
7981//.. default:
7982//.. break;
7983//.. }
sewardja6b93d12005-02-17 09:28:28 +00007984
7985 /* ---------------------------------------------------- */
7986 /* --- The SSE decoder. --- */
7987 /* ---------------------------------------------------- */
7988
7989 /* What did I do to deserve SSE ? Perhaps I was really bad in a
7990 previous life? */
7991
7992 /* Note, this doesn't handle SSE2 or SSE3. That is handled in a
7993 later section, further on. */
7994
7995 insn = (UChar*)&guest_code[delta];
7996
sewardjd20c8852005-01-20 20:04:07 +00007997//.. /* Treat fxsave specially. It should be doable even on an SSE0
7998//.. (Pentium-II class) CPU. Hence be prepared to handle it on
7999//.. any subarchitecture variant.
8000//.. */
8001//..
8002//.. /* 0F AE /0 = FXSAVE m512 -- write x87 and SSE state to memory */
8003//.. if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xAE
8004//.. && !epartIsReg(insn[2]) && gregOfRM(insn[2]) == 0) {
sewardj8c332e22005-01-28 01:36:56 +00008005//.. modrm = getUChar(delta+2);
sewardjd20c8852005-01-20 20:04:07 +00008006//.. vassert(sz == 4);
8007//.. vassert(!epartIsReg(modrm));
8008//..
8009//.. addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8010//.. delta += 2+alen;
8011//..
8012//.. DIP("fxsave %s\n", dis_buf);
8013//..
8014//.. /* Uses dirty helper:
8015//.. void x86g_do_FXSAVE ( VexGuestX86State*, UInt ) */
8016//.. IRDirty* d = unsafeIRDirty_0_N (
8017//.. 0/*regparms*/,
8018//.. "x86g_dirtyhelper_FXSAVE",
8019//.. &x86g_dirtyhelper_FXSAVE,
8020//.. mkIRExprVec_1( mkexpr(addr) )
8021//.. );
8022//.. d->needsBBP = True;
8023//..
8024//.. /* declare we're writing memory */
8025//.. d->mFx = Ifx_Write;
8026//.. d->mAddr = mkexpr(addr);
8027//.. d->mSize = 512;
8028//..
8029//.. /* declare we're reading guest state */
8030//.. d->nFxState = 7;
8031//..
8032//.. d->fxState[0].fx = Ifx_Read;
8033//.. d->fxState[0].offset = OFFB_FTOP;
8034//.. d->fxState[0].size = sizeof(UInt);
8035//..
8036//.. d->fxState[1].fx = Ifx_Read;
8037//.. d->fxState[1].offset = OFFB_FPREGS;
8038//.. d->fxState[1].size = 8 * sizeof(ULong);
8039//..
8040//.. d->fxState[2].fx = Ifx_Read;
8041//.. d->fxState[2].offset = OFFB_FPTAGS;
8042//.. d->fxState[2].size = 8 * sizeof(UChar);
8043//..
8044//.. d->fxState[3].fx = Ifx_Read;
8045//.. d->fxState[3].offset = OFFB_FPROUND;
8046//.. d->fxState[3].size = sizeof(UInt);
8047//..
8048//.. d->fxState[4].fx = Ifx_Read;
8049//.. d->fxState[4].offset = OFFB_FC3210;
8050//.. d->fxState[4].size = sizeof(UInt);
8051//..
8052//.. d->fxState[5].fx = Ifx_Read;
8053//.. d->fxState[5].offset = OFFB_XMM0;
8054//.. d->fxState[5].size = 8 * sizeof(U128);
8055//..
8056//.. d->fxState[6].fx = Ifx_Read;
8057//.. d->fxState[6].offset = OFFB_SSEROUND;
8058//.. d->fxState[6].size = sizeof(UInt);
8059//..
8060//.. /* Be paranoid ... this assertion tries to ensure the 8 %xmm
8061//.. images are packed back-to-back. If not, the value of
8062//.. d->fxState[5].size is wrong. */
8063//.. vassert(16 == sizeof(U128));
8064//.. vassert(OFFB_XMM7 == (OFFB_XMM0 + 7 * 16));
8065//..
8066//.. stmt( IRStmt_Dirty(d) );
8067//..
8068//.. goto decode_success;
8069//.. }
8070//..
8071//.. /* ------ SSE decoder main ------ */
8072//..
8073//.. /* Skip parts of the decoder which don't apply given the stated
8074//.. guest subarchitecture. */
8075//.. if (subarch == VexSubArchX86_sse0)
8076//.. goto after_sse_decoders;
8077//..
8078//.. /* Otherwise we must be doing sse1 or sse2, so we can at least try
8079//.. for SSE1 here. */
8080//..
8081//.. /* 0F 58 = ADDPS -- add 32Fx4 from R/M to R */
8082//.. if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x58) {
8083//.. delta = dis_SSE_E_to_G_all( sorb, delta+2, "addps", Iop_Add32Fx4 );
8084//.. goto decode_success;
8085//.. }
sewardj8d965312005-02-25 02:48:47 +00008086
8087 /* F3 0F 58 = ADDSS -- add 32F0x4 from R/M to R */
8088 if (haveF3no66noF2(pfx) && sz == 4
8089 && insn[0] == 0x0F && insn[1] == 0x58) {
8090 delta = dis_SSE_E_to_G_lo32( pfx, delta+2, "addss", Iop_Add32F0x4 );
8091 goto decode_success;
8092 }
8093
sewardjd20c8852005-01-20 20:04:07 +00008094//.. /* 0F 55 = ANDNPS -- G = (not G) and E */
8095//.. if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x55) {
8096//.. delta = dis_SSE_E_to_G_all_invG( sorb, delta+2, "andnps", Iop_And128 );
8097//.. goto decode_success;
8098//.. }
sewardj37d52572005-02-25 14:22:12 +00008099
8100 /* 0F 54 = ANDPS -- G = G and E */
8101 if (haveNo66noF2noF3(pfx) && sz == 4
8102 && insn[0] == 0x0F && insn[1] == 0x54) {
8103 delta = dis_SSE_E_to_G_all( pfx, delta+2, "andps", Iop_AndV128 );
8104 goto decode_success;
8105 }
8106
sewardjd20c8852005-01-20 20:04:07 +00008107//.. /* 0F C2 = CMPPS -- 32Fx4 comparison from R/M to R */
8108//.. if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xC2) {
8109//.. delta = dis_SSEcmp_E_to_G( sorb, delta+2, "cmpps", True, 4 );
8110//.. goto decode_success;
8111//.. }
8112//..
8113//.. /* F3 0F C2 = CMPSS -- 32F0x4 comparison from R/M to R */
8114//.. if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0xC2) {
8115//.. vassert(sz == 4);
8116//.. delta = dis_SSEcmp_E_to_G( sorb, delta+3, "cmpss", False, 4 );
8117//.. goto decode_success;
8118//.. }
sewardjc49ce232005-02-25 13:03:03 +00008119
8120 /* 0F 2F = COMISS -- 32F0x4 comparison G,E, and set ZCP */
8121 /* 0F 2E = UCOMISS -- 32F0x4 comparison G,E, and set ZCP */
8122 if (haveNo66noF2noF3(pfx) && sz == 4
8123 && insn[0] == 0x0F && (insn[1] == 0x2F || insn[1] == 0x2E)) {
8124 IRTemp argL = newTemp(Ity_F32);
8125 IRTemp argR = newTemp(Ity_F32);
8126 modrm = getUChar(delta+2);
8127 if (epartIsReg(modrm)) {
8128 assign( argR, getXMMRegLane32F( eregOfRexRM(pfx,modrm),
8129 0/*lowest lane*/ ) );
8130 delta += 2+1;
8131 DIP("%scomiss %s,%s\n", insn[1]==0x2E ? "u" : "",
8132 nameXMMReg(eregOfRexRM(pfx,modrm)),
8133 nameXMMReg(gregOfRexRM(pfx,modrm)) );
8134 } else {
8135 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8136 assign( argR, loadLE(Ity_F32, mkexpr(addr)) );
8137 delta += 2+alen;
8138 DIP("%scomiss %s,%s\n", insn[1]==0x2E ? "u" : "",
8139 dis_buf,
8140 nameXMMReg(gregOfRexRM(pfx,modrm)) );
8141 }
8142 assign( argL, getXMMRegLane32F( gregOfRexRM(pfx,modrm),
8143 0/*lowest lane*/ ) );
8144
8145 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(AMD64G_CC_OP_COPY) ));
8146 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
8147 stmt( IRStmt_Put(
8148 OFFB_CC_DEP1,
8149 binop( Iop_And64,
8150 unop( Iop_32Uto64,
8151 binop(Iop_CmpF64,
8152 unop(Iop_F32toF64,mkexpr(argL)),
8153 unop(Iop_F32toF64,mkexpr(argR)))),
8154 mkU64(0x45)
8155 )));
8156
8157 goto decode_success;
8158 }
8159
sewardjd20c8852005-01-20 20:04:07 +00008160//.. /* 0F 2A = CVTPI2PS -- convert 2 x I32 in mem/mmx to 2 x F32 in low
8161//.. half xmm */
8162//.. if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x2A) {
8163//.. IRTemp arg64 = newTemp(Ity_I64);
8164//.. IRTemp rmode = newTemp(Ity_I32);
8165//.. vassert(sz == 4);
8166//..
sewardj8c332e22005-01-28 01:36:56 +00008167//.. modrm = getUChar(delta+2);
sewardjd20c8852005-01-20 20:04:07 +00008168//.. do_MMX_preamble();
8169//.. if (epartIsReg(modrm)) {
8170//.. assign( arg64, getMMXReg(eregOfRM(modrm)) );
8171//.. delta += 2+1;
8172//.. DIP("cvtpi2ps %s,%s\n", nameMMXReg(eregOfRM(modrm)),
8173//.. nameXMMReg(gregOfRM(modrm)));
8174//.. } else {
8175//.. addr = disAMode ( &alen, sorb, delta+2, dis_buf );
sewardj8d965312005-02-25 02:48:47 +00008176//.. assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
sewardjd20c8852005-01-20 20:04:07 +00008177//.. delta += 2+alen;
8178//.. DIP("cvtpi2ps %s,%s\n", dis_buf,
8179//.. nameXMMReg(gregOfRM(modrm)) );
8180//.. }
8181//..
8182//.. assign( rmode, get_sse_roundingmode() );
8183//..
8184//.. putXMMRegLane32F(
8185//.. gregOfRM(modrm), 0,
8186//.. binop(Iop_F64toF32,
8187//.. mkexpr(rmode),
8188//.. unop(Iop_I32toF64,
8189//.. unop(Iop_64to32, mkexpr(arg64)) )) );
8190//..
8191//.. putXMMRegLane32F(
8192//.. gregOfRM(modrm), 1,
8193//.. binop(Iop_F64toF32,
8194//.. mkexpr(rmode),
8195//.. unop(Iop_I32toF64,
8196//.. unop(Iop_64HIto32, mkexpr(arg64)) )) );
8197//..
8198//.. goto decode_success;
8199//.. }
sewardj8d965312005-02-25 02:48:47 +00008200
8201 /* F3 0F 2A = CVTSI2SS
8202 -- sz==4: convert I32 in mem/ireg to F32 in low quarter xmm
8203 -- sz==8: convert I64 in mem/ireg to F32 in low quarter xmm */
8204 if (haveF3no66noF2(pfx) && (sz == 4 || sz == 8)
8205 && insn[0] == 0x0F && insn[1] == 0x2A) {
8206
8207 IRTemp rmode = newTemp(Ity_I32);
8208 assign( rmode, get_sse_roundingmode() );
8209 modrm = getUChar(delta+2);
8210
8211 if (sz == 4) {
8212 IRTemp arg32 = newTemp(Ity_I32);
8213 if (epartIsReg(modrm)) {
sewardj5b470602005-02-27 13:10:48 +00008214 assign( arg32, getIReg32(eregOfRexRM(pfx,modrm)) );
sewardj8d965312005-02-25 02:48:47 +00008215 delta += 2+1;
sewardj5b470602005-02-27 13:10:48 +00008216 DIP("cvtsi2ss %s,%s\n", nameIReg32(eregOfRexRM(pfx,modrm)),
sewardj8d965312005-02-25 02:48:47 +00008217 nameXMMReg(gregOfRexRM(pfx,modrm)));
8218 } else {
sewardj8d965312005-02-25 02:48:47 +00008219 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8220 assign( arg32, loadLE(Ity_I32, mkexpr(addr)) );
8221 delta += 2+alen;
8222 DIP("cvtsi2ss %s,%s\n", dis_buf,
8223 nameXMMReg(gregOfRexRM(pfx,modrm)) );
8224 }
8225 putXMMRegLane32F(
8226 gregOfRexRM(pfx,modrm), 0,
8227 binop(Iop_F64toF32,
8228 mkexpr(rmode),
8229 unop(Iop_I32toF64, mkexpr(arg32)) ) );
8230 } else {
8231 /* sz == 8 */
8232 IRTemp arg64 = newTemp(Ity_I64);
8233 if (epartIsReg(modrm)) {
sewardj5b470602005-02-27 13:10:48 +00008234 assign( arg64, getIReg64(eregOfRexRM(pfx,modrm)) );
sewardj8d965312005-02-25 02:48:47 +00008235 delta += 2+1;
sewardj5b470602005-02-27 13:10:48 +00008236 DIP("cvtsi2ssq %s,%s\n", nameIReg64(eregOfRexRM(pfx,modrm)),
sewardj8d965312005-02-25 02:48:47 +00008237 nameXMMReg(gregOfRexRM(pfx,modrm)));
8238 } else {
8239 goto decode_failure; /* awaiting test case */
8240 }
8241 putXMMRegLane32F(
8242 gregOfRexRM(pfx,modrm), 0,
8243 binop(Iop_F64toF32,
8244 mkexpr(rmode),
8245 binop(Iop_I64toF64, mkexpr(rmode), mkexpr(arg64)) ) );
8246 }
8247
8248 goto decode_success;
8249 }
8250
sewardjd20c8852005-01-20 20:04:07 +00008251//.. /* 0F 2D = CVTPS2PI -- convert 2 x F32 in mem/low half xmm to 2 x
8252//.. I32 in mmx, according to prevailing SSE rounding mode */
8253//.. /* 0F 2C = CVTTPS2PI -- convert 2 x F32 in mem/low half xmm to 2 x
8254//.. I32 in mmx, rounding towards zero */
8255//.. if (sz == 4 && insn[0] == 0x0F && (insn[1] == 0x2D || insn[1] == 0x2C)) {
8256//.. IRTemp dst64 = newTemp(Ity_I64);
8257//.. IRTemp rmode = newTemp(Ity_I32);
8258//.. IRTemp f32lo = newTemp(Ity_F32);
8259//.. IRTemp f32hi = newTemp(Ity_F32);
8260//.. Bool r2zero = insn[1] == 0x2C;
8261//..
8262//.. do_MMX_preamble();
sewardj8c332e22005-01-28 01:36:56 +00008263//.. modrm = getUChar(delta+2);
sewardjd20c8852005-01-20 20:04:07 +00008264//..
8265//.. if (epartIsReg(modrm)) {
8266//.. delta += 2+1;
8267//.. assign(f32lo, getXMMRegLane32F(eregOfRM(modrm), 0));
8268//.. assign(f32hi, getXMMRegLane32F(eregOfRM(modrm), 1));
8269//.. DIP("cvt%sps2pi %s,%s\n", r2zero ? "t" : "",
8270//.. nameXMMReg(eregOfRM(modrm)),
8271//.. nameMMXReg(gregOfRM(modrm)));
8272//.. } else {
8273//.. addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8274//.. assign(f32lo, loadLE(Ity_F32, mkexpr(addr)));
8275//.. assign(f32hi, loadLE(Ity_F32, binop( Iop_Add32,
8276//.. mkexpr(addr),
8277//.. mkU32(4) )));
8278//.. delta += 2+alen;
8279//.. DIP("cvt%sps2pi %s,%s\n", r2zero ? "t" : "",
8280//.. dis_buf,
8281//.. nameMMXReg(gregOfRM(modrm)));
8282//.. }
8283//..
8284//.. if (r2zero) {
8285//.. assign(rmode, mkU32((UInt)Irrm_ZERO) );
8286//.. } else {
8287//.. assign( rmode, get_sse_roundingmode() );
8288//.. }
8289//..
8290//.. assign(
8291//.. dst64,
8292//.. binop( Iop_32HLto64,
8293//.. binop( Iop_F64toI32,
8294//.. mkexpr(rmode),
8295//.. unop( Iop_F32toF64, mkexpr(f32hi) ) ),
8296//.. binop( Iop_F64toI32,
8297//.. mkexpr(rmode),
8298//.. unop( Iop_F32toF64, mkexpr(f32lo) ) )
8299//.. )
8300//.. );
8301//..
8302//.. putMMXReg(gregOfRM(modrm), mkexpr(dst64));
8303//.. goto decode_success;
8304//.. }
8305//..
8306//.. /* F3 0F 2D = CVTSS2SI -- convert F32 in mem/low quarter xmm to
8307//.. I32 in ireg, according to prevailing SSE rounding mode */
8308//.. /* F3 0F 2C = CVTTSS2SI -- convert F32 in mem/low quarter xmm to
8309//.. I32 in ireg, according to prevailing SSE rounding mode */
8310//.. if (insn[0] == 0xF3 && insn[1] == 0x0F
8311//.. && (insn[2] == 0x2D || insn[2] == 0x2C)) {
8312//.. IRTemp rmode = newTemp(Ity_I32);
8313//.. IRTemp f32lo = newTemp(Ity_F32);
8314//.. Bool r2zero = insn[2] == 0x2C;
8315//.. vassert(sz == 4);
8316//..
sewardj8c332e22005-01-28 01:36:56 +00008317//.. modrm = getUChar(delta+3);
sewardjd20c8852005-01-20 20:04:07 +00008318//.. if (epartIsReg(modrm)) {
8319//.. delta += 3+1;
8320//.. assign(f32lo, getXMMRegLane32F(eregOfRM(modrm), 0));
8321//.. DIP("cvt%sss2si %s,%s\n", r2zero ? "t" : "",
8322//.. nameXMMReg(eregOfRM(modrm)),
8323//.. nameIReg(4, gregOfRM(modrm)));
8324//.. } else {
8325//.. addr = disAMode ( &alen, sorb, delta+3, dis_buf );
8326//.. assign(f32lo, loadLE(Ity_F32, mkexpr(addr)));
8327//.. delta += 3+alen;
8328//.. DIP("cvt%sss2si %s,%s\n", r2zero ? "t" : "",
8329//.. dis_buf,
8330//.. nameIReg(4, gregOfRM(modrm)));
8331//.. }
8332//..
8333//.. if (r2zero) {
8334//.. assign( rmode, mkU32((UInt)Irrm_ZERO) );
8335//.. } else {
8336//.. assign( rmode, get_sse_roundingmode() );
8337//.. }
8338//..
8339//.. putIReg(4, gregOfRM(modrm),
8340//.. binop( Iop_F64toI32,
8341//.. mkexpr(rmode),
8342//.. unop( Iop_F32toF64, mkexpr(f32lo) ) )
8343//.. );
8344//..
8345//.. goto decode_success;
8346//.. }
8347//..
8348//.. /* 0F 5E = DIVPS -- div 32Fx4 from R/M to R */
8349//.. if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5E) {
8350//.. delta = dis_SSE_E_to_G_all( sorb, delta+2, "divps", Iop_Div32Fx4 );
8351//.. goto decode_success;
8352//.. }
sewardjc49ce232005-02-25 13:03:03 +00008353
8354 /* F3 0F 5E = DIVSS -- div 32F0x4 from R/M to R */
8355 if (haveF3no66noF2(pfx) && sz == 4
8356 && insn[0] == 0x0F && insn[1] == 0x5E) {
8357 delta = dis_SSE_E_to_G_lo32( pfx, delta+2, "divss", Iop_Div32F0x4 );
8358 goto decode_success;
8359 }
8360
sewardjd20c8852005-01-20 20:04:07 +00008361//.. /* 0F AE /2 = LDMXCSR m32 -- load %mxcsr */
8362//.. if (insn[0] == 0x0F && insn[1] == 0xAE
8363//.. && !epartIsReg(insn[2]) && gregOfRM(insn[2]) == 2) {
8364//..
8365//.. IRTemp t64 = newTemp(Ity_I64);
8366//.. IRTemp ew = newTemp(Ity_I32);
8367//..
sewardj8c332e22005-01-28 01:36:56 +00008368//.. modrm = getUChar(delta+2);
sewardjd20c8852005-01-20 20:04:07 +00008369//.. vassert(!epartIsReg(modrm));
8370//.. vassert(sz == 4);
8371//..
8372//.. addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8373//.. delta += 2+alen;
8374//.. DIP("ldmxcsr %s\n", dis_buf);
8375//..
8376//.. /* The only thing we observe in %mxcsr is the rounding mode.
8377//.. Therefore, pass the 32-bit value (SSE native-format control
8378//.. word) to a clean helper, getting back a 64-bit value, the
8379//.. lower half of which is the SSEROUND value to store, and the
8380//.. upper half of which is the emulation-warning token which may
8381//.. be generated.
8382//.. */
8383//.. /* ULong x86h_check_ldmxcsr ( UInt ); */
8384//.. assign( t64, mkIRExprCCall(
8385//.. Ity_I64, 0/*regparms*/,
8386//.. "x86g_check_ldmxcsr",
8387//.. &x86g_check_ldmxcsr,
8388//.. mkIRExprVec_1( loadLE(Ity_I32, mkexpr(addr)) )
8389//.. )
8390//.. );
8391//..
8392//.. put_sse_roundingmode( unop(Iop_64to32, mkexpr(t64)) );
8393//.. assign( ew, unop(Iop_64HIto32, mkexpr(t64) ) );
8394//.. put_emwarn( mkexpr(ew) );
8395//.. /* Finally, if an emulation warning was reported, side-exit to
8396//.. the next insn, reporting the warning, so that Valgrind's
8397//.. dispatcher sees the warning. */
8398//.. stmt(
8399//.. IRStmt_Exit(
8400//.. binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
8401//.. Ijk_EmWarn,
8402//.. IRConst_U32( ((Addr32)guest_eip_bbstart)+delta)
8403//.. )
8404//.. );
8405//.. goto decode_success;
8406//.. }
8407//..
8408//.. /* 0F 5F = MAXPS -- max 32Fx4 from R/M to R */
8409//.. if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5F) {
8410//.. delta = dis_SSE_E_to_G_all( sorb, delta+2, "maxps", Iop_Max32Fx4 );
8411//.. goto decode_success;
8412//.. }
sewardj37d52572005-02-25 14:22:12 +00008413
8414 /* F3 0F 5F = MAXSS -- max 32F0x4 from R/M to R */
8415 if (haveF3no66noF2(pfx) && sz == 4
8416 && insn[0] == 0x0F && insn[1] == 0x5F) {
8417 delta = dis_SSE_E_to_G_lo32( pfx, delta+2, "maxss", Iop_Max32F0x4 );
8418 goto decode_success;
8419 }
8420
sewardjd20c8852005-01-20 20:04:07 +00008421//.. /* 0F 5D = MINPS -- min 32Fx4 from R/M to R */
8422//.. if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5D) {
8423//.. delta = dis_SSE_E_to_G_all( sorb, delta+2, "minps", Iop_Min32Fx4 );
8424//.. goto decode_success;
8425//.. }
sewardj37d52572005-02-25 14:22:12 +00008426
8427 /* F3 0F 5D = MINSS -- min 32F0x4 from R/M to R */
8428 if (haveF3no66noF2(pfx) && sz == 4
8429 && insn[0] == 0x0F && insn[1] == 0x5D) {
8430 delta = dis_SSE_E_to_G_lo32( pfx, delta+2, "minss", Iop_Min32F0x4 );
8431 goto decode_success;
8432 }
sewardj8d965312005-02-25 02:48:47 +00008433
8434 /* 0F 28 = MOVAPS -- move from E (mem or xmm) to G (xmm). */
8435 /* 0F 10 = MOVUPS -- move from E (mem or xmm) to G (xmm). */
8436 if (haveNo66noF2noF3(pfx) && sz == 4
8437 && insn[0] == 0x0F && (insn[1] == 0x28 || insn[1] == 0x10)) {
8438 modrm = getUChar(delta+2);
8439 if (epartIsReg(modrm)) {
8440 putXMMReg( gregOfRexRM(pfx,modrm),
8441 getXMMReg( eregOfRexRM(pfx,modrm) ));
8442 DIP("mov[ua]ps %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
8443 nameXMMReg(gregOfRexRM(pfx,modrm)));
8444 delta += 2+1;
8445 } else {
8446 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8447 putXMMReg( gregOfRexRM(pfx,modrm),
8448 loadLE(Ity_V128, mkexpr(addr)) );
8449 DIP("mov[ua]ps %s,%s\n", dis_buf,
8450 nameXMMReg(gregOfRexRM(pfx,modrm)));
8451 delta += 2+alen;
8452 }
8453 goto decode_success;
8454 }
sewardj1001dc42005-02-21 08:25:55 +00008455
8456 /* 0F 29 = MOVAPS -- move from G (xmm) to E (mem or xmm). */
sewardj8d965312005-02-25 02:48:47 +00008457 if (haveNo66noF2noF3(pfx) && sz == 4
8458 && insn[0] == 0x0F && insn[1] == 0x29) {
sewardj1001dc42005-02-21 08:25:55 +00008459 modrm = getUChar(delta+2);
8460 if (epartIsReg(modrm)) {
8461 /* fall through; awaiting test case */
8462 } else {
8463 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8464 storeLE( mkexpr(addr), getXMMReg(gregOfRexRM(pfx,modrm)) );
8465 DIP("movaps %s,%s\n", nameXMMReg(gregOfRexRM(pfx,modrm)),
8466 dis_buf );
8467 delta += 2+alen;
8468 goto decode_success;
8469 }
8470 }
8471
sewardjd20c8852005-01-20 20:04:07 +00008472//.. /* 0F 16 = MOVHPS -- move from mem to high half of XMM. */
8473//.. /* 0F 16 = MOVLHPS -- move from lo half to hi half of XMM. */
8474//.. if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x16) {
sewardj8c332e22005-01-28 01:36:56 +00008475//.. modrm = getUChar(delta+2);
sewardjd20c8852005-01-20 20:04:07 +00008476//.. if (epartIsReg(modrm)) {
8477//.. delta += 2+1;
8478//.. putXMMRegLane64( gregOfRM(modrm), 1/*upper lane*/,
8479//.. getXMMRegLane64( eregOfRM(modrm), 0 ) );
8480//.. DIP("movhps %s,%s\n", nameXMMReg(eregOfRM(modrm)),
8481//.. nameXMMReg(gregOfRM(modrm)));
8482//.. } else {
8483//.. addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8484//.. delta += 2+alen;
8485//.. putXMMRegLane64( gregOfRM(modrm), 1/*upper lane*/,
8486//.. loadLE(Ity_I64, mkexpr(addr)) );
8487//.. DIP("movhps %s,%s\n", dis_buf,
8488//.. nameXMMReg( gregOfRM(modrm) ));
8489//.. }
8490//.. goto decode_success;
8491//.. }
8492//..
8493//.. /* 0F 17 = MOVHPS -- move from high half of XMM to mem. */
8494//.. if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x17) {
8495//.. if (!epartIsReg(insn[2])) {
8496//.. delta += 2;
8497//.. addr = disAMode ( &alen, sorb, delta, dis_buf );
8498//.. delta += alen;
8499//.. storeLE( mkexpr(addr),
8500//.. getXMMRegLane64( gregOfRM(insn[2]),
8501//.. 1/*upper lane*/ ) );
8502//.. DIP("movhps %s,%s\n", nameXMMReg( gregOfRM(insn[2]) ),
8503//.. dis_buf);
8504//.. goto decode_success;
8505//.. }
8506//.. /* else fall through */
8507//.. }
8508//..
8509//.. /* 0F 12 = MOVLPS -- move from mem to low half of XMM. */
8510//.. /* OF 12 = MOVHLPS -- from from hi half to lo half of XMM. */
8511//.. if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x12) {
sewardj8c332e22005-01-28 01:36:56 +00008512//.. modrm = getUChar(delta+2);
sewardjd20c8852005-01-20 20:04:07 +00008513//.. if (epartIsReg(modrm)) {
8514//.. delta += 2+1;
8515//.. putXMMRegLane64( gregOfRM(modrm),
8516//.. 0/*lower lane*/,
8517//.. getXMMRegLane64( eregOfRM(modrm), 1 ));
8518//.. DIP("movhlps %s, %s\n", nameXMMReg(eregOfRM(modrm)),
8519//.. nameXMMReg(gregOfRM(modrm)));
8520//.. } else {
8521//.. addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8522//.. delta += 2+alen;
8523//.. putXMMRegLane64( gregOfRM(modrm), 0/*lower lane*/,
8524//.. loadLE(Ity_I64, mkexpr(addr)) );
8525//.. DIP("movlps %s, %s\n",
8526//.. dis_buf, nameXMMReg( gregOfRM(modrm) ));
8527//.. }
8528//.. goto decode_success;
8529//.. }
8530//..
8531//.. /* 0F 13 = MOVLPS -- move from low half of XMM to mem. */
8532//.. if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x13) {
8533//.. if (!epartIsReg(insn[2])) {
8534//.. delta += 2;
8535//.. addr = disAMode ( &alen, sorb, delta, dis_buf );
8536//.. delta += alen;
8537//.. storeLE( mkexpr(addr),
8538//.. getXMMRegLane64( gregOfRM(insn[2]),
8539//.. 0/*lower lane*/ ) );
8540//.. DIP("movlps %s, %s\n", nameXMMReg( gregOfRM(insn[2]) ),
8541//.. dis_buf);
8542//.. goto decode_success;
8543//.. }
8544//.. /* else fall through */
8545//.. }
8546//..
8547//.. /* 0F 50 = MOVMSKPS - move 4 sign bits from 4 x F32 in xmm(E)
8548//.. to 4 lowest bits of ireg(G) */
8549//.. if (insn[0] == 0x0F && insn[1] == 0x50) {
sewardj8c332e22005-01-28 01:36:56 +00008550//.. modrm = getUChar(delta+2);
sewardjd20c8852005-01-20 20:04:07 +00008551//.. if (sz == 4 && epartIsReg(modrm)) {
8552//.. Int src;
8553//.. t0 = newTemp(Ity_I32);
8554//.. t1 = newTemp(Ity_I32);
8555//.. t2 = newTemp(Ity_I32);
8556//.. t3 = newTemp(Ity_I32);
8557//.. delta += 2+1;
8558//.. src = eregOfRM(modrm);
8559//.. assign( t0, binop( Iop_And32,
8560//.. binop(Iop_Shr32, getXMMRegLane32(src,0), mkU8(31)),
8561//.. mkU32(1) ));
8562//.. assign( t1, binop( Iop_And32,
8563//.. binop(Iop_Shr32, getXMMRegLane32(src,1), mkU8(30)),
8564//.. mkU32(2) ));
8565//.. assign( t2, binop( Iop_And32,
8566//.. binop(Iop_Shr32, getXMMRegLane32(src,2), mkU8(29)),
8567//.. mkU32(4) ));
8568//.. assign( t3, binop( Iop_And32,
8569//.. binop(Iop_Shr32, getXMMRegLane32(src,3), mkU8(28)),
8570//.. mkU32(8) ));
8571//.. putIReg(4, gregOfRM(modrm),
8572//.. binop(Iop_Or32,
8573//.. binop(Iop_Or32, mkexpr(t0), mkexpr(t1)),
8574//.. binop(Iop_Or32, mkexpr(t2), mkexpr(t3))
8575//.. )
8576//.. );
8577//.. DIP("movmskps %s,%s\n", nameXMMReg(src),
8578//.. nameIReg(4, gregOfRM(modrm)));
8579//.. goto decode_success;
8580//.. }
8581//.. /* else fall through */
8582//.. }
8583//..
8584//.. /* 0F 2B = MOVNTPS -- for us, just a plain SSE store. */
8585//.. if (insn[0] == 0x0F && insn[1] == 0x2B) {
sewardj8c332e22005-01-28 01:36:56 +00008586//.. modrm = getUChar(delta+2);
sewardjd20c8852005-01-20 20:04:07 +00008587//.. if (!epartIsReg(modrm)) {
8588//.. addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8589//.. storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) );
8590//.. DIP("movntps %s,%s\n", dis_buf,
8591//.. nameXMMReg(gregOfRM(modrm)));
8592//.. delta += 2+alen;
8593//.. goto decode_success;
8594//.. }
8595//.. /* else fall through */
8596//.. }
8597//..
8598//.. /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8599//.. /* 0F E7 = MOVNTQ -- for us, just a plain MMX store. Note, the
8600//.. Intel manual does not say anything about the usual business of
8601//.. the FP reg tags getting trashed whenever an MMX insn happens.
8602//.. So we just leave them alone.
8603//.. */
8604//.. if (insn[0] == 0x0F && insn[1] == 0xE7) {
sewardj8c332e22005-01-28 01:36:56 +00008605//.. modrm = getUChar(delta+2);
sewardjd20c8852005-01-20 20:04:07 +00008606//.. if (sz == 4 && !epartIsReg(modrm)) {
8607//.. /* do_MMX_preamble(); Intel docs don't specify this */
8608//.. addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8609//.. storeLE( mkexpr(addr), getMMXReg(gregOfRM(modrm)) );
8610//.. DIP("movntq %s,%s\n", dis_buf,
8611//.. nameMMXReg(gregOfRM(modrm)));
8612//.. delta += 2+alen;
8613//.. goto decode_success;
8614//.. }
8615//.. /* else fall through */
8616//.. }
sewardj8d965312005-02-25 02:48:47 +00008617
8618 /* F3 0F 10 = MOVSS -- move 32 bits from E (mem or lo 1/4 xmm) to G
8619 (lo 1/4 xmm). If E is mem, upper 3/4 of G is zeroed out. */
8620 if (haveF3no66noF2(pfx) && sz == 4
8621 && insn[0] == 0x0F && insn[1] == 0x10) {
8622 modrm = getUChar(delta+2);
8623 if (epartIsReg(modrm)) {
8624 putXMMRegLane32( gregOfRexRM(pfx,modrm), 0,
8625 getXMMRegLane32( eregOfRexRM(pfx,modrm), 0 ));
8626 DIP("movss %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
8627 nameXMMReg(gregOfRexRM(pfx,modrm)));
8628 delta += 2+1;
8629 } else {
8630 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8631 putXMMReg( gregOfRexRM(pfx,modrm), mkV128(0) );
8632 putXMMRegLane32( gregOfRexRM(pfx,modrm), 0,
8633 loadLE(Ity_I32, mkexpr(addr)) );
8634 DIP("movss %s,%s\n", dis_buf,
8635 nameXMMReg(gregOfRexRM(pfx,modrm)));
8636 delta += 2+alen;
8637 }
8638 goto decode_success;
8639 }
8640
8641 /* F3 0F 11 = MOVSS -- move 32 bits from G (lo 1/4 xmm) to E (mem
8642 or lo 1/4 xmm). */
8643 if (haveF3no66noF2(pfx) && sz == 4
8644 && insn[0] == 0x0F && insn[1] == 0x11) {
8645 modrm = getUChar(delta+2);
8646 if (epartIsReg(modrm)) {
8647 /* fall through, we don't yet have a test case */
8648 } else {
8649 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8650 storeLE( mkexpr(addr),
8651 getXMMRegLane32(gregOfRexRM(pfx,modrm), 0) );
8652 DIP("movss %s,%s\n", nameXMMReg(gregOfRexRM(pfx,modrm)),
8653 dis_buf);
8654 delta += 2+alen;
8655 goto decode_success;
8656 }
8657 }
8658
sewardjd20c8852005-01-20 20:04:07 +00008659//.. /* 0F 59 = MULPS -- mul 32Fx4 from R/M to R */
8660//.. if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x59) {
8661//.. delta = dis_SSE_E_to_G_all( sorb, delta+2, "mulps", Iop_Mul32Fx4 );
8662//.. goto decode_success;
8663//.. }
sewardj8d965312005-02-25 02:48:47 +00008664
8665 /* F3 0F 59 = MULSS -- mul 32F0x4 from R/M to R */
8666 if (haveF3no66noF2(pfx) && sz == 4
8667 && insn[0] == 0x0F && insn[1] == 0x59) {
8668 delta = dis_SSE_E_to_G_lo32( pfx, delta+2, "mulss", Iop_Mul32F0x4 );
8669 goto decode_success;
8670 }
8671
sewardjd20c8852005-01-20 20:04:07 +00008672//.. /* 0F 56 = ORPS -- G = G and E */
8673//.. if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x56) {
8674//.. delta = dis_SSE_E_to_G_all( sorb, delta+2, "orps", Iop_Or128 );
8675//.. goto decode_success;
8676//.. }
8677//..
8678//.. /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8679//.. /* 0F E0 = PAVGB -- 8x8 unsigned Packed Average, with rounding */
8680//.. if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xE0) {
8681//.. do_MMX_preamble();
8682//.. delta = dis_MMXop_regmem_to_reg (
8683//.. sorb, delta+2, insn[1], "pavgb", False );
8684//.. goto decode_success;
8685//.. }
8686//..
8687//.. /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8688//.. /* 0F E3 = PAVGW -- 16x4 unsigned Packed Average, with rounding */
8689//.. if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xE3) {
8690//.. do_MMX_preamble();
8691//.. delta = dis_MMXop_regmem_to_reg (
8692//.. sorb, delta+2, insn[1], "pavgw", False );
8693//.. goto decode_success;
8694//.. }
8695//..
8696//.. /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8697//.. /* 0F C5 = PEXTRW -- extract 16-bit field from mmx(E) and put
8698//.. zero-extend of it in ireg(G). */
8699//.. if (insn[0] == 0x0F && insn[1] == 0xC5) {
8700//.. modrm = insn[2];
8701//.. if (sz == 4 && epartIsReg(modrm)) {
8702//.. IRTemp sV = newTemp(Ity_I64);
8703//.. t5 = newTemp(Ity_I16);
8704//.. do_MMX_preamble();
8705//.. assign(sV, getMMXReg(eregOfRM(modrm)));
8706//.. breakup64to16s( sV, &t3, &t2, &t1, &t0 );
8707//.. switch (insn[3] & 3) {
8708//.. case 0: assign(t5, mkexpr(t0)); break;
8709//.. case 1: assign(t5, mkexpr(t1)); break;
8710//.. case 2: assign(t5, mkexpr(t2)); break;
8711//.. case 3: assign(t5, mkexpr(t3)); break;
8712//.. default: vassert(0);
8713//.. }
8714//.. putIReg(4, gregOfRM(modrm), unop(Iop_16Uto32, mkexpr(t5)));
8715//.. DIP("pextrw $%d,%s,%s\n",
8716//.. (Int)insn[3], nameMMXReg(eregOfRM(modrm)),
8717//.. nameIReg(4,gregOfRM(modrm)));
8718//.. delta += 4;
8719//.. goto decode_success;
8720//.. }
8721//.. /* else fall through */
8722//.. }
8723//..
8724//.. /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8725//.. /* 0F C4 = PINSRW -- get 16 bits from E(mem or low half ireg) and
8726//.. put it into the specified lane of mmx(G). */
8727//.. if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xC4) {
8728//.. /* Use t0 .. t3 to hold the 4 original 16-bit lanes of the
8729//.. mmx reg. t4 is the new lane value. t5 is the original
8730//.. mmx value. t6 is the new mmx value. */
8731//.. Int lane;
8732//.. t4 = newTemp(Ity_I16);
8733//.. t5 = newTemp(Ity_I64);
8734//.. t6 = newTemp(Ity_I64);
8735//.. modrm = insn[2];
8736//.. do_MMX_preamble();
8737//..
8738//.. assign(t5, getMMXReg(gregOfRM(modrm)));
8739//.. breakup64to16s( t5, &t3, &t2, &t1, &t0 );
8740//..
8741//.. if (epartIsReg(modrm)) {
8742//.. assign(t4, getIReg(2, eregOfRM(modrm)));
8743//.. lane = insn[3];
8744//.. delta += 2+2;
8745//.. DIP("pinsrw $%d,%s,%s\n", (Int)lane,
8746//.. nameIReg(2,eregOfRM(modrm)),
8747//.. nameMMXReg(gregOfRM(modrm)));
8748//.. } else {
8749//.. /* awaiting test case */
8750//.. goto decode_failure;
8751//.. }
8752//..
8753//.. switch (lane & 3) {
8754//.. case 0: assign(t6, mk64from16s(t3,t2,t1,t4)); break;
8755//.. case 1: assign(t6, mk64from16s(t3,t2,t4,t0)); break;
8756//.. case 2: assign(t6, mk64from16s(t3,t4,t1,t0)); break;
8757//.. case 3: assign(t6, mk64from16s(t4,t2,t1,t0)); break;
8758//.. default: vassert(0);
8759//.. }
8760//.. putMMXReg(gregOfRM(modrm), mkexpr(t6));
8761//.. goto decode_success;
8762//.. }
8763//..
8764//.. /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8765//.. /* 0F EE = PMAXSW -- 16x4 signed max */
8766//.. if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xEE) {
8767//.. do_MMX_preamble();
8768//.. delta = dis_MMXop_regmem_to_reg (
8769//.. sorb, delta+2, insn[1], "pmaxsw", False );
8770//.. goto decode_success;
8771//.. }
8772//..
8773//.. /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8774//.. /* 0F DE = PMAXUB -- 8x8 unsigned max */
8775//.. if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xDE) {
8776//.. do_MMX_preamble();
8777//.. delta = dis_MMXop_regmem_to_reg (
8778//.. sorb, delta+2, insn[1], "pmaxub", False );
8779//.. goto decode_success;
8780//.. }
8781//..
8782//.. /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8783//.. /* 0F EA = PMINSW -- 16x4 signed min */
8784//.. if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xEA) {
8785//.. do_MMX_preamble();
8786//.. delta = dis_MMXop_regmem_to_reg (
8787//.. sorb, delta+2, insn[1], "pminsw", False );
8788//.. goto decode_success;
8789//.. }
8790//..
8791//.. /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8792//.. /* 0F DA = PMINUB -- 8x8 unsigned min */
8793//.. if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xDA) {
8794//.. do_MMX_preamble();
8795//.. delta = dis_MMXop_regmem_to_reg (
8796//.. sorb, delta+2, insn[1], "pminub", False );
8797//.. goto decode_success;
8798//.. }
8799//..
8800//.. /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8801//.. /* 0F D7 = PMOVMSKB -- extract sign bits from each of 8 lanes in
8802//.. mmx(G), turn them into a byte, and put zero-extend of it in
8803//.. ireg(G). */
8804//.. if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xD7) {
8805//.. modrm = insn[2];
8806//.. if (epartIsReg(modrm)) {
8807//.. do_MMX_preamble();
8808//.. t0 = newTemp(Ity_I64);
8809//.. t1 = newTemp(Ity_I32);
8810//.. assign(t0, getMMXReg(eregOfRM(modrm)));
8811//.. assign(t1, mkIRExprCCall(
8812//.. Ity_I32, 0/*regparms*/,
8813//.. "x86g_calculate_mmx_pmovmskb",
8814//.. &x86g_calculate_mmx_pmovmskb,
8815//.. mkIRExprVec_1(mkexpr(t0))));
8816//.. putIReg(4, gregOfRM(modrm), mkexpr(t1));
8817//.. DIP("pmovmskb %s,%s\n", nameMMXReg(eregOfRM(modrm)),
8818//.. nameIReg(4,gregOfRM(modrm)));
8819//.. delta += 3;
8820//.. goto decode_success;
8821//.. }
8822//.. /* else fall through */
8823//.. }
8824//..
8825//.. /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8826//.. /* 0F E4 = PMULUH -- 16x4 hi-half of unsigned widening multiply */
8827//.. if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xE4) {
8828//.. do_MMX_preamble();
8829//.. delta = dis_MMXop_regmem_to_reg (
8830//.. sorb, delta+2, insn[1], "pmuluh", False );
8831//.. goto decode_success;
8832//.. }
sewardja6b93d12005-02-17 09:28:28 +00008833
8834 /* 0F 18 /0 = PREFETCHNTA -- prefetch into caches, */
8835 /* 0F 18 /1 = PREFETCH0 -- with various different hints */
8836 /* 0F 18 /2 = PREFETCH1 */
8837 /* 0F 18 /3 = PREFETCH2 */
8838 if (insn[0] == 0x0F && insn[1] == 0x18
8839 && !haveF2orF3(pfx)
8840 && !epartIsReg(insn[2])
sewardj901ed122005-02-27 13:25:31 +00008841 && gregLO3ofRM(insn[2]) >= 0 && gregLO3ofRM(insn[2]) <= 3) {
sewardja6b93d12005-02-17 09:28:28 +00008842 HChar* hintstr = "??";
8843
8844 modrm = getUChar(delta+2);
8845 vassert(!epartIsReg(modrm));
8846
8847 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8848 delta += 2+alen;
8849
sewardj901ed122005-02-27 13:25:31 +00008850 switch (gregLO3ofRM(modrm)) {
sewardja6b93d12005-02-17 09:28:28 +00008851 case 0: hintstr = "nta"; break;
8852 case 1: hintstr = "t0"; break;
8853 case 2: hintstr = "t1"; break;
8854 case 3: hintstr = "t2"; break;
8855 default: vassert(0);
8856 }
8857
8858 DIP("prefetch%s %s\n", hintstr, dis_buf);
8859 goto decode_success;
8860 }
8861
sewardjd20c8852005-01-20 20:04:07 +00008862//.. /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8863//.. /* 0F F6 = PSADBW -- sum of 8Ux8 absolute differences */
8864//.. if (insn[0] == 0x0F && insn[1] == 0xF6) {
8865//.. vassert(sz == 4);
8866//.. do_MMX_preamble();
8867//.. delta = dis_MMXop_regmem_to_reg (
8868//.. sorb, delta+2, insn[1], "psadbw", False );
8869//.. goto decode_success;
8870//.. }
8871//..
8872//.. /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8873//.. /* 0F 70 = PSHUFW -- rearrange 4x16 from E(mmx or mem) to G(mmx) */
8874//.. if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x70) {
8875//.. Int order;
8876//.. IRTemp sV, dV, s3, s2, s1, s0;
8877//.. s3 = s2 = s1 = s0 = IRTemp_INVALID;
8878//.. sV = newTemp(Ity_I64);
8879//.. dV = newTemp(Ity_I64);
8880//.. do_MMX_preamble();
8881//.. modrm = insn[2];
8882//.. if (epartIsReg(modrm)) {
8883//.. assign( sV, getMMXReg(eregOfRM(modrm)) );
8884//.. order = (Int)insn[3];
8885//.. delta += 2+2;
8886//.. DIP("pshufw $%d,%s,%s\n", order,
8887//.. nameMMXReg(eregOfRM(modrm)),
8888//.. nameMMXReg(gregOfRM(modrm)));
8889//.. } else {
8890//.. addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8891//.. assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
sewardj8d965312005-02-25 02:48:47 +00008892//.. order = (Int)insn[2+alen];
sewardjd20c8852005-01-20 20:04:07 +00008893//.. delta += 3+alen;
8894//.. DIP("pshufw $%d,%s,%s\n", order,
8895//.. dis_buf,
8896//.. nameMMXReg(gregOfRM(modrm)));
8897//.. }
8898//.. breakup64to16s( sV, &s3, &s2, &s1, &s0 );
8899//..
8900//.. # define SEL(n) \
8901//.. ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
8902//.. assign(dV,
8903//.. mk64from16s( SEL((order>>6)&3), SEL((order>>4)&3),
8904//.. SEL((order>>2)&3), SEL((order>>0)&3) )
8905//.. );
8906//.. putMMXReg(gregOfRM(modrm), mkexpr(dV));
8907//.. # undef SEL
8908//.. goto decode_success;
8909//.. }
8910//..
8911//.. /* 0F 53 = RCPPS -- approx reciprocal 32Fx4 from R/M to R */
8912//.. if (insn[0] == 0x0F && insn[1] == 0x53) {
8913//.. vassert(sz == 4);
8914//.. delta = dis_SSE_E_to_G_unary_all( sorb, delta+2,
8915//.. "rcpps", Iop_Recip32Fx4 );
8916//.. goto decode_success;
8917//.. }
8918//..
8919//.. /* F3 0F 53 = RCPSS -- approx reciprocal 32F0x4 from R/M to R */
8920//.. if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x53) {
8921//.. vassert(sz == 4);
8922//.. delta = dis_SSE_E_to_G_unary_lo32( sorb, delta+3,
8923//.. "rcpss", Iop_Recip32F0x4 );
8924//.. goto decode_success;
8925//.. }
8926//..
8927//.. /* 0F 52 = RSQRTPS -- approx reciprocal sqrt 32Fx4 from R/M to R */
8928//.. if (insn[0] == 0x0F && insn[1] == 0x52) {
8929//.. vassert(sz == 4);
8930//.. delta = dis_SSE_E_to_G_unary_all( sorb, delta+2,
8931//.. "rsqrtps", Iop_RSqrt32Fx4 );
8932//.. goto decode_success;
8933//.. }
8934//..
8935//.. /* F3 0F 52 = RSQRTSS -- approx reciprocal sqrt 32F0x4 from R/M to R */
8936//.. if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x52) {
8937//.. vassert(sz == 4);
8938//.. delta = dis_SSE_E_to_G_unary_lo32( sorb, delta+3,
8939//.. "rsqrtss", Iop_RSqrt32F0x4 );
8940//.. goto decode_success;
8941//.. }
8942//..
8943//.. /* 0F AE /7 = SFENCE -- flush pending operations to memory */
8944//.. if (insn[0] == 0x0F && insn[1] == 0xAE
8945//.. && epartIsReg(insn[2]) && gregOfRM(insn[2]) == 7) {
8946//.. vassert(sz == 4);
8947//.. delta += 3;
8948//.. /* Insert a memory fence. It's sometimes important that these
8949//.. are carried through to the generated code. */
8950//.. stmt( IRStmt_MFence() );
8951//.. DIP("sfence\n");
8952//.. goto decode_success;
8953//.. }
8954//..
8955//.. /* 0F C6 /r ib = SHUFPS -- shuffle packed F32s */
8956//.. if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xC6) {
8957//.. Int select;
8958//.. IRTemp sV, dV;
8959//.. IRTemp s3, s2, s1, s0, d3, d2, d1, d0;
8960//.. sV = newTemp(Ity_V128);
8961//.. dV = newTemp(Ity_V128);
8962//.. s3 = s2 = s1 = s0 = d3 = d2 = d1 = d0 = IRTemp_INVALID;
8963//.. modrm = insn[2];
8964//.. assign( dV, getXMMReg(gregOfRM(modrm)) );
8965//..
8966//.. if (epartIsReg(modrm)) {
8967//.. assign( sV, getXMMReg(eregOfRM(modrm)) );
8968//.. select = (Int)insn[3];
8969//.. delta += 2+2;
8970//.. DIP("shufps $%d,%s,%s\n", select,
8971//.. nameXMMReg(eregOfRM(modrm)),
8972//.. nameXMMReg(gregOfRM(modrm)));
8973//.. } else {
8974//.. addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8975//.. assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
8976//.. select = (Int)insn[2+alen];
8977//.. delta += 3+alen;
8978//.. DIP("shufps $%d,%s,%s\n", select,
8979//.. dis_buf,
8980//.. nameXMMReg(gregOfRM(modrm)));
8981//.. }
8982//..
8983//.. breakup128to32s( dV, &d3, &d2, &d1, &d0 );
8984//.. breakup128to32s( sV, &s3, &s2, &s1, &s0 );
8985//..
8986//.. # define SELD(n) ((n)==0 ? d0 : ((n)==1 ? d1 : ((n)==2 ? d2 : d3)))
8987//.. # define SELS(n) ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
8988//..
8989//.. putXMMReg(
8990//.. gregOfRM(modrm),
8991//.. mk128from32s( SELS((select>>6)&3), SELS((select>>4)&3),
8992//.. SELD((select>>2)&3), SELD((select>>0)&3) )
8993//.. );
8994//..
8995//.. # undef SELD
8996//.. # undef SELS
8997//..
8998//.. goto decode_success;
8999//.. }
9000//..
9001//.. /* 0F 51 = SQRTPS -- approx sqrt 32Fx4 from R/M to R */
9002//.. if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x51) {
9003//.. delta = dis_SSE_E_to_G_unary_all( sorb, delta+2,
9004//.. "sqrtps", Iop_Sqrt32Fx4 );
9005//.. goto decode_success;
9006//.. }
9007//..
9008//.. /* F3 0F 51 = SQRTSS -- approx sqrt 32F0x4 from R/M to R */
9009//.. if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x51) {
9010//.. vassert(sz == 4);
9011//.. delta = dis_SSE_E_to_G_unary_lo32( sorb, delta+3,
9012//.. "sqrtss", Iop_Sqrt32F0x4 );
9013//.. goto decode_success;
9014//.. }
9015//..
9016//.. /* 0F AE /3 = STMXCSR m32 -- store %mxcsr */
9017//.. if (insn[0] == 0x0F && insn[1] == 0xAE
9018//.. && !epartIsReg(insn[2]) && gregOfRM(insn[2]) == 3) {
sewardj8c332e22005-01-28 01:36:56 +00009019//.. modrm = getUChar(delta+2);
sewardjd20c8852005-01-20 20:04:07 +00009020//.. vassert(sz == 4);
9021//.. vassert(!epartIsReg(modrm));
9022//..
9023//.. addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9024//.. delta += 2+alen;
9025//..
9026//.. /* Fake up a native SSE mxcsr word. The only thing it depends
9027//.. on is SSEROUND[1:0], so call a clean helper to cook it up.
9028//.. */
9029//.. /* UInt x86h_create_mxcsr ( UInt sseround ) */
9030//.. DIP("stmxcsr %s\n", dis_buf);
9031//.. storeLE( mkexpr(addr),
9032//.. mkIRExprCCall(
9033//.. Ity_I32, 0/*regp*/,
9034//.. "x86g_create_mxcsr", &x86g_create_mxcsr,
9035//.. mkIRExprVec_1( get_sse_roundingmode() )
9036//.. )
9037//.. );
9038//.. goto decode_success;
9039//.. }
9040//..
9041//.. /* 0F 5C = SUBPS -- sub 32Fx4 from R/M to R */
9042//.. if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5C) {
9043//.. delta = dis_SSE_E_to_G_all( sorb, delta+2, "subps", Iop_Sub32Fx4 );
9044//.. goto decode_success;
9045//.. }
sewardj8d965312005-02-25 02:48:47 +00009046
9047 /* F3 0F 5C = SUBSS -- sub 32F0x4 from R/M to R */
9048 if (haveF3no66noF2(pfx) && sz == 4
9049 && insn[0] == 0x0F && insn[1] == 0x5C) {
9050 delta = dis_SSE_E_to_G_lo32( pfx, delta+2, "subss", Iop_Sub32F0x4 );
9051 goto decode_success;
9052 }
9053
sewardjd20c8852005-01-20 20:04:07 +00009054//.. /* 0F 15 = UNPCKHPS -- unpack and interleave high part F32s */
9055//.. /* 0F 14 = UNPCKLPS -- unpack and interleave low part F32s */
9056//.. /* These just appear to be special cases of SHUFPS */
9057//.. if (sz == 4 && insn[0] == 0x0F && (insn[1] == 0x15 || insn[1] == 0x14)) {
9058//.. IRTemp sV, dV;
9059//.. IRTemp s3, s2, s1, s0, d3, d2, d1, d0;
9060//.. Bool hi = insn[1] == 0x15;
9061//.. sV = newTemp(Ity_V128);
9062//.. dV = newTemp(Ity_V128);
9063//.. s3 = s2 = s1 = s0 = d3 = d2 = d1 = d0 = IRTemp_INVALID;
9064//.. modrm = insn[2];
9065//.. assign( dV, getXMMReg(gregOfRM(modrm)) );
9066//..
9067//.. if (epartIsReg(modrm)) {
9068//.. assign( sV, getXMMReg(eregOfRM(modrm)) );
9069//.. delta += 2+1;
9070//.. DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
9071//.. nameXMMReg(eregOfRM(modrm)),
9072//.. nameXMMReg(gregOfRM(modrm)));
9073//.. } else {
9074//.. addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9075//.. assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
9076//.. delta += 2+alen;
9077//.. DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
9078//.. dis_buf,
9079//.. nameXMMReg(gregOfRM(modrm)));
9080//.. }
9081//..
9082//.. breakup128to32s( dV, &d3, &d2, &d1, &d0 );
9083//.. breakup128to32s( sV, &s3, &s2, &s1, &s0 );
9084//..
9085//.. if (hi) {
9086//.. putXMMReg( gregOfRM(modrm), mk128from32s( s3, d3, s2, d2 ) );
9087//.. } else {
9088//.. putXMMReg( gregOfRM(modrm), mk128from32s( s1, d1, s0, d0 ) );
9089//.. }
9090//..
9091//.. goto decode_success;
9092//.. }
sewardj8d965312005-02-25 02:48:47 +00009093
9094 /* 0F 57 = XORPS -- G = G and E */
9095 if (haveNo66noF2noF3(pfx) && sz == 4
9096 && insn[0] == 0x0F && insn[1] == 0x57) {
9097 delta = dis_SSE_E_to_G_all( pfx, delta+2, "xorps", Iop_XorV128 );
9098 goto decode_success;
9099 }
9100
sewardjd20c8852005-01-20 20:04:07 +00009101//.. /* ---------------------------------------------------- */
9102//.. /* --- end of the SSE decoder. --- */
9103//.. /* ---------------------------------------------------- */
9104//..
9105//.. /* ---------------------------------------------------- */
9106//.. /* --- start of the SSE2 decoder. --- */
9107//.. /* ---------------------------------------------------- */
9108//..
9109//.. /* Skip parts of the decoder which don't apply given the stated
9110//.. guest subarchitecture. */
9111//.. if (subarch == VexSubArchX86_sse0 || subarch == VexSubArchX86_sse1)
9112//.. goto after_sse_decoders;
9113//..
9114//.. insn = (UChar*)&guest_code[delta];
9115//..
9116//.. /* 66 0F 58 = ADDPD -- add 32Fx4 from R/M to R */
9117//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x58) {
9118//.. delta = dis_SSE_E_to_G_all( sorb, delta+2, "addpd", Iop_Add64Fx2 );
9119//.. goto decode_success;
9120//.. }
sewardj1001dc42005-02-21 08:25:55 +00009121
9122 /* F2 0F 58 = ADDSD -- add 64F0x2 from R/M to R */
9123 if (haveF2no66noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x58) {
9124 vassert(sz == 4);
9125 delta = dis_SSE_E_to_G_lo64( pfx, delta+2, "addsd", Iop_Add64F0x2 );
9126 goto decode_success;
9127 }
9128
sewardj8d965312005-02-25 02:48:47 +00009129 /* 66 0F 55 = ANDNPD -- G = (not G) and E */
9130 if (have66noF2noF3(pfx) && sz == 2
9131 && insn[0] == 0x0F && insn[1] == 0x55) {
9132 delta = dis_SSE_E_to_G_all_invG( pfx, delta+2, "andnpd", Iop_AndV128 );
9133 goto decode_success;
9134 }
sewardj1a01e652005-02-23 11:39:21 +00009135
9136 /* 66 0F 54 = ANDPD -- G = G and E */
9137 if (have66noF2noF3(pfx) && sz == 2
9138 && insn[0] == 0x0F && insn[1] == 0x54) {
9139 delta = dis_SSE_E_to_G_all( pfx, delta+2, "andpd", Iop_AndV128 );
9140 goto decode_success;
9141 }
9142
sewardjd20c8852005-01-20 20:04:07 +00009143//.. /* 66 0F C2 = CMPPD -- 64Fx2 comparison from R/M to R */
9144//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xC2) {
9145//.. delta = dis_SSEcmp_E_to_G( sorb, delta+2, "cmppd", True, 8 );
9146//.. goto decode_success;
9147//.. }
sewardj8d965312005-02-25 02:48:47 +00009148
9149 /* F2 0F C2 = CMPSD -- 64F0x2 comparison from R/M to R */
9150 if (haveF2no66noF3(pfx) && sz == 4
9151 && insn[0] == 0x0F && insn[1] == 0xC2) {
9152 delta = dis_SSEcmp_E_to_G( pfx, delta+2, "cmpsd", False, 8 );
9153 goto decode_success;
9154 }
sewardj18303862005-02-21 12:36:54 +00009155
9156 /* 66 0F 2F = COMISD -- 64F0x2 comparison G,E, and set ZCP */
9157 /* 66 0F 2E = UCOMISD -- 64F0x2 comparison G,E, and set ZCP */
sewardjc49ce232005-02-25 13:03:03 +00009158 if (have66noF2noF3(pfx) && sz == 2
sewardj18303862005-02-21 12:36:54 +00009159 && insn[0] == 0x0F && (insn[1] == 0x2F || insn[1] == 0x2E)) {
9160 IRTemp argL = newTemp(Ity_F64);
9161 IRTemp argR = newTemp(Ity_F64);
9162 modrm = getUChar(delta+2);
9163 if (epartIsReg(modrm)) {
9164 assign( argR, getXMMRegLane64F( eregOfRexRM(pfx,modrm),
9165 0/*lowest lane*/ ) );
9166 delta += 2+1;
9167 DIP("%scomisd %s,%s\n", insn[1]==0x2E ? "u" : "",
9168 nameXMMReg(eregOfRexRM(pfx,modrm)),
9169 nameXMMReg(gregOfRexRM(pfx,modrm)) );
9170 } else {
9171 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9172 assign( argR, loadLE(Ity_F64, mkexpr(addr)) );
9173 delta += 2+alen;
9174 DIP("%scomisd %s,%s\n", insn[1]==0x2E ? "u" : "",
9175 dis_buf,
9176 nameXMMReg(gregOfRexRM(pfx,modrm)) );
9177 }
9178 assign( argL, getXMMRegLane64F( gregOfRexRM(pfx,modrm),
9179 0/*lowest lane*/ ) );
9180
9181 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(AMD64G_CC_OP_COPY) ));
9182 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
9183 stmt( IRStmt_Put(
9184 OFFB_CC_DEP1,
9185 binop( Iop_And64,
9186 unop( Iop_32Uto64,
9187 binop(Iop_CmpF64, mkexpr(argL), mkexpr(argR)) ),
9188 mkU64(0x45)
9189 )));
9190
9191 goto decode_success;
9192 }
9193
sewardjd20c8852005-01-20 20:04:07 +00009194//.. /* F3 0F E6 = CVTDQ2PD -- convert 2 x I32 in mem/lo half xmm to 2 x
9195//.. F64 in xmm(G) */
9196//.. if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0xE6) {
9197//.. IRTemp arg64 = newTemp(Ity_I64);
9198//.. vassert(sz == 4);
9199//..
sewardj8c332e22005-01-28 01:36:56 +00009200//.. modrm = getUChar(delta+3);
sewardjd20c8852005-01-20 20:04:07 +00009201//.. if (epartIsReg(modrm)) {
9202//.. assign( arg64, getXMMRegLane64(eregOfRM(modrm), 0) );
9203//.. delta += 3+1;
9204//.. DIP("cvtdq2pd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9205//.. nameXMMReg(gregOfRM(modrm)));
9206//.. } else {
9207//.. addr = disAMode ( &alen, sorb, delta+3, dis_buf );
sewardj8d965312005-02-25 02:48:47 +00009208//.. assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
sewardjd20c8852005-01-20 20:04:07 +00009209//.. delta += 3+alen;
9210//.. DIP("cvtdq2pd %s,%s\n", dis_buf,
9211//.. nameXMMReg(gregOfRM(modrm)) );
9212//.. }
9213//..
9214//.. putXMMRegLane64F(
9215//.. gregOfRM(modrm), 0,
9216//.. unop(Iop_I32toF64, unop(Iop_64to32, mkexpr(arg64)))
9217//.. );
9218//..
9219//.. putXMMRegLane64F(
9220//.. gregOfRM(modrm), 1,
9221//.. unop(Iop_I32toF64, unop(Iop_64HIto32, mkexpr(arg64)))
9222//.. );
9223//..
9224//.. goto decode_success;
9225//.. }
9226//..
9227//.. /* 0F 5B = CVTDQ2PS -- convert 4 x I32 in mem/xmm to 4 x F32 in
9228//.. xmm(G) */
9229//.. if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5B) {
9230//.. IRTemp argV = newTemp(Ity_V128);
9231//.. IRTemp rmode = newTemp(Ity_I32);
9232//..
sewardj8c332e22005-01-28 01:36:56 +00009233//.. modrm = getUChar(delta+2);
sewardjd20c8852005-01-20 20:04:07 +00009234//.. if (epartIsReg(modrm)) {
9235//.. assign( argV, getXMMReg(eregOfRM(modrm)) );
9236//.. delta += 2+1;
9237//.. DIP("cvtdq2ps %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9238//.. nameXMMReg(gregOfRM(modrm)));
9239//.. } else {
9240//.. addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9241//.. assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
9242//.. delta += 2+alen;
9243//.. DIP("cvtdq2ps %s,%s\n", dis_buf,
9244//.. nameXMMReg(gregOfRM(modrm)) );
9245//.. }
9246//..
9247//.. assign( rmode, get_sse_roundingmode() );
9248//.. breakup128to32s( argV, &t3, &t2, &t1, &t0 );
9249//..
9250//.. # define CVT(_t) binop( Iop_F64toF32, \
9251//.. mkexpr(rmode), \
9252//.. unop(Iop_I32toF64,mkexpr(_t)))
9253//..
9254//.. putXMMRegLane32F( gregOfRM(modrm), 3, CVT(t3) );
9255//.. putXMMRegLane32F( gregOfRM(modrm), 2, CVT(t2) );
9256//.. putXMMRegLane32F( gregOfRM(modrm), 1, CVT(t1) );
9257//.. putXMMRegLane32F( gregOfRM(modrm), 0, CVT(t0) );
9258//..
9259//.. # undef CVT
9260//..
9261//.. goto decode_success;
9262//.. }
9263//..
9264//.. /* F2 0F E6 = CVTPD2DQ -- convert 2 x F64 in mem/xmm to 2 x I32 in
9265//.. lo half xmm(G), and zero upper half */
9266//.. if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0xE6) {
9267//.. IRTemp argV = newTemp(Ity_V128);
9268//.. IRTemp rmode = newTemp(Ity_I32);
9269//.. vassert(sz == 4);
9270//..
sewardj8c332e22005-01-28 01:36:56 +00009271//.. modrm = getUChar(delta+3);
sewardjd20c8852005-01-20 20:04:07 +00009272//.. if (epartIsReg(modrm)) {
9273//.. assign( argV, getXMMReg(eregOfRM(modrm)) );
9274//.. delta += 3+1;
9275//.. DIP("cvtpd2dq %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9276//.. nameXMMReg(gregOfRM(modrm)));
9277//.. } else {
9278//.. addr = disAMode ( &alen, sorb, delta+3, dis_buf );
9279//.. assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
9280//.. delta += 3+alen;
9281//.. DIP("cvtpd2dq %s,%s\n", dis_buf,
9282//.. nameXMMReg(gregOfRM(modrm)) );
9283//.. }
9284//..
9285//.. assign( rmode, get_sse_roundingmode() );
9286//.. t0 = newTemp(Ity_F64);
9287//.. t1 = newTemp(Ity_F64);
9288//.. assign( t0, unop(Iop_ReinterpI64asF64,
9289//.. unop(Iop_128to64, mkexpr(argV))) );
9290//.. assign( t1, unop(Iop_ReinterpI64asF64,
9291//.. unop(Iop_128HIto64, mkexpr(argV))) );
9292//..
9293//.. # define CVT(_t) binop( Iop_F64toI32, \
9294//.. mkexpr(rmode), \
9295//.. mkexpr(_t) )
9296//..
9297//.. putXMMRegLane32( gregOfRM(modrm), 3, mkU32(0) );
9298//.. putXMMRegLane32( gregOfRM(modrm), 2, mkU32(0) );
9299//.. putXMMRegLane32( gregOfRM(modrm), 1, CVT(t1) );
9300//.. putXMMRegLane32( gregOfRM(modrm), 0, CVT(t0) );
9301//..
9302//.. # undef CVT
9303//..
9304//.. goto decode_success;
9305//.. }
9306//..
9307//.. /* 66 0F 2D = CVTPD2PI -- convert 2 x F64 in mem/xmm to 2 x
9308//.. I32 in mmx, according to prevailing SSE rounding mode */
9309//.. /* 66 0F 2C = CVTTPD2PI -- convert 2 x F64 in mem/xmm to 2 x
9310//.. I32 in mmx, rounding towards zero */
9311//.. if (sz == 2 && insn[0] == 0x0F && (insn[1] == 0x2D || insn[1] == 0x2C)) {
9312//.. IRTemp dst64 = newTemp(Ity_I64);
9313//.. IRTemp rmode = newTemp(Ity_I32);
9314//.. IRTemp f64lo = newTemp(Ity_F64);
9315//.. IRTemp f64hi = newTemp(Ity_F64);
9316//.. Bool r2zero = insn[1] == 0x2C;
9317//..
9318//.. do_MMX_preamble();
sewardj8c332e22005-01-28 01:36:56 +00009319//.. modrm = getUChar(delta+2);
sewardjd20c8852005-01-20 20:04:07 +00009320//..
9321//.. if (epartIsReg(modrm)) {
9322//.. delta += 2+1;
9323//.. assign(f64lo, getXMMRegLane64F(eregOfRM(modrm), 0));
9324//.. assign(f64hi, getXMMRegLane64F(eregOfRM(modrm), 1));
9325//.. DIP("cvt%spd2pi %s,%s\n", r2zero ? "t" : "",
9326//.. nameXMMReg(eregOfRM(modrm)),
9327//.. nameMMXReg(gregOfRM(modrm)));
9328//.. } else {
9329//.. addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9330//.. assign(f64lo, loadLE(Ity_F64, mkexpr(addr)));
9331//.. assign(f64hi, loadLE(Ity_F64, binop( Iop_Add32,
9332//.. mkexpr(addr),
9333//.. mkU32(8) )));
9334//.. delta += 2+alen;
9335//.. DIP("cvt%spf2pi %s,%s\n", r2zero ? "t" : "",
9336//.. dis_buf,
9337//.. nameMMXReg(gregOfRM(modrm)));
9338//.. }
9339//..
9340//.. if (r2zero) {
9341//.. assign(rmode, mkU32((UInt)Irrm_ZERO) );
9342//.. } else {
9343//.. assign( rmode, get_sse_roundingmode() );
9344//.. }
9345//..
9346//.. assign(
9347//.. dst64,
9348//.. binop( Iop_32HLto64,
9349//.. binop( Iop_F64toI32, mkexpr(rmode), mkexpr(f64hi) ),
9350//.. binop( Iop_F64toI32, mkexpr(rmode), mkexpr(f64lo) )
9351//.. )
9352//.. );
9353//..
9354//.. putMMXReg(gregOfRM(modrm), mkexpr(dst64));
9355//.. goto decode_success;
9356//.. }
9357//..
9358//.. /* 66 0F 5A = CVTPD2PS -- convert 2 x F64 in mem/xmm to 2 x F32 in
9359//.. lo half xmm(G), and zero upper half */
9360//.. /* Note, this is practically identical to CVTPD2DQ. It would have
9361//.. been nicer to merge them together, but the insn[] offsets differ
9362//.. by one. */
9363//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5A) {
9364//.. IRTemp argV = newTemp(Ity_V128);
9365//.. IRTemp rmode = newTemp(Ity_I32);
9366//..
sewardj8c332e22005-01-28 01:36:56 +00009367//.. modrm = getUChar(delta+2);
sewardjd20c8852005-01-20 20:04:07 +00009368//.. if (epartIsReg(modrm)) {
9369//.. assign( argV, getXMMReg(eregOfRM(modrm)) );
9370//.. delta += 2+1;
9371//.. DIP("cvtpd2ps %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9372//.. nameXMMReg(gregOfRM(modrm)));
9373//.. } else {
9374//.. addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9375//.. assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
9376//.. delta += 2+alen;
9377//.. DIP("cvtpd2ps %s,%s\n", dis_buf,
9378//.. nameXMMReg(gregOfRM(modrm)) );
9379//.. }
9380//..
9381//.. assign( rmode, get_sse_roundingmode() );
9382//.. t0 = newTemp(Ity_F64);
9383//.. t1 = newTemp(Ity_F64);
9384//.. assign( t0, unop(Iop_ReinterpI64asF64,
9385//.. unop(Iop_128to64, mkexpr(argV))) );
9386//.. assign( t1, unop(Iop_ReinterpI64asF64,
9387//.. unop(Iop_128HIto64, mkexpr(argV))) );
9388//..
9389//.. # define CVT(_t) binop( Iop_F64toF32, \
9390//.. mkexpr(rmode), \
9391//.. mkexpr(_t) )
9392//..
9393//.. putXMMRegLane32( gregOfRM(modrm), 3, mkU32(0) );
9394//.. putXMMRegLane32( gregOfRM(modrm), 2, mkU32(0) );
9395//.. putXMMRegLane32F( gregOfRM(modrm), 1, CVT(t1) );
9396//.. putXMMRegLane32F( gregOfRM(modrm), 0, CVT(t0) );
9397//..
9398//.. # undef CVT
9399//..
9400//.. goto decode_success;
9401//.. }
9402//..
9403//.. /* 66 0F 2A = CVTPI2PD -- convert 2 x I32 in mem/mmx to 2 x F64 in
9404//.. xmm(G) */
9405//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x2A) {
9406//.. IRTemp arg64 = newTemp(Ity_I64);
9407//..
sewardj8c332e22005-01-28 01:36:56 +00009408//.. modrm = getUChar(delta+2);
sewardjd20c8852005-01-20 20:04:07 +00009409//.. do_MMX_preamble();
9410//.. if (epartIsReg(modrm)) {
9411//.. assign( arg64, getMMXReg(eregOfRM(modrm)) );
9412//.. delta += 2+1;
9413//.. DIP("cvtpi2pd %s,%s\n", nameMMXReg(eregOfRM(modrm)),
9414//.. nameXMMReg(gregOfRM(modrm)));
9415//.. } else {
9416//.. addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9417//.. assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
9418//.. delta += 2+alen;
9419//.. DIP("cvtpi2pd %s,%s\n", dis_buf,
9420//.. nameXMMReg(gregOfRM(modrm)) );
9421//.. }
9422//..
9423//.. putXMMRegLane64F(
9424//.. gregOfRM(modrm), 0,
9425//.. unop(Iop_I32toF64, unop(Iop_64to32, mkexpr(arg64)) )
9426//.. );
9427//..
9428//.. putXMMRegLane64F(
9429//.. gregOfRM(modrm), 1,
9430//.. unop(Iop_I32toF64, unop(Iop_64HIto32, mkexpr(arg64)) )
9431//.. );
9432//..
9433//.. goto decode_success;
9434//.. }
9435//..
9436//.. /* 66 0F 5B = CVTPS2DQ -- convert 4 x F32 in mem/xmm to 4 x I32 in
9437//.. xmm(G) */
9438//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5B) {
9439//.. IRTemp argV = newTemp(Ity_V128);
9440//.. IRTemp rmode = newTemp(Ity_I32);
9441//..
sewardj8c332e22005-01-28 01:36:56 +00009442//.. modrm = getUChar(delta+2);
sewardjd20c8852005-01-20 20:04:07 +00009443//.. if (epartIsReg(modrm)) {
9444//.. assign( argV, getXMMReg(eregOfRM(modrm)) );
9445//.. delta += 2+1;
9446//.. DIP("cvtps2dq %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9447//.. nameXMMReg(gregOfRM(modrm)));
9448//.. } else {
9449//.. addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9450//.. assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
9451//.. delta += 2+alen;
9452//.. DIP("cvtps2dq %s,%s\n", dis_buf,
9453//.. nameXMMReg(gregOfRM(modrm)) );
9454//.. }
9455//..
9456//.. assign( rmode, get_sse_roundingmode() );
9457//.. breakup128to32s( argV, &t3, &t2, &t1, &t0 );
9458//..
9459//.. /* This is less than ideal. If it turns out to be a performance
9460//.. bottleneck it can be improved. */
9461//.. # define CVT(_t) \
9462//.. binop( Iop_F64toI32, \
9463//.. mkexpr(rmode), \
9464//.. unop( Iop_F32toF64, \
9465//.. unop( Iop_ReinterpI32asF32, mkexpr(_t))) )
9466//..
9467//.. putXMMRegLane32( gregOfRM(modrm), 3, CVT(t3) );
9468//.. putXMMRegLane32( gregOfRM(modrm), 2, CVT(t2) );
9469//.. putXMMRegLane32( gregOfRM(modrm), 1, CVT(t1) );
9470//.. putXMMRegLane32( gregOfRM(modrm), 0, CVT(t0) );
9471//..
9472//.. # undef CVT
9473//..
9474//.. goto decode_success;
9475//.. }
9476//..
9477//.. /* 0F 5A = CVTPS2PD -- convert 2 x F32 in low half mem/xmm to 2 x
9478//.. F64 in xmm(G). */
9479//.. if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5A) {
9480//.. IRTemp f32lo = newTemp(Ity_F32);
9481//.. IRTemp f32hi = newTemp(Ity_F32);
9482//..
sewardj8c332e22005-01-28 01:36:56 +00009483//.. modrm = getUChar(delta+2);
sewardjd20c8852005-01-20 20:04:07 +00009484//.. if (epartIsReg(modrm)) {
9485//.. assign( f32lo, getXMMRegLane32F(eregOfRM(modrm), 0) );
9486//.. assign( f32hi, getXMMRegLane32F(eregOfRM(modrm), 1) );
9487//.. delta += 2+1;
9488//.. DIP("cvtps2pd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9489//.. nameXMMReg(gregOfRM(modrm)));
9490//.. } else {
9491//.. addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9492//.. assign( f32lo, loadLE(Ity_F32, mkexpr(addr)) );
9493//.. assign( f32hi, loadLE(Ity_F32,
9494//.. binop(Iop_Add32,mkexpr(addr),mkU32(4))) );
9495//.. delta += 2+alen;
9496//.. DIP("cvtps2pd %s,%s\n", dis_buf,
9497//.. nameXMMReg(gregOfRM(modrm)) );
9498//.. }
9499//..
9500//.. putXMMRegLane64F( gregOfRM(modrm), 1,
9501//.. unop(Iop_F32toF64, mkexpr(f32hi)) );
9502//.. putXMMRegLane64F( gregOfRM(modrm), 0,
9503//.. unop(Iop_F32toF64, mkexpr(f32lo)) );
9504//..
9505//.. goto decode_success;
9506//.. }
9507//..
9508//.. /* F2 0F 2D = CVTSD2SI -- convert F64 in mem/low half xmm to
9509//.. I32 in ireg, according to prevailing SSE rounding mode */
sewardj1a01e652005-02-23 11:39:21 +00009510 /* F2 0F 2C = CVTTSD2SI
9511 when sz==4 -- convert F64 in mem/low half xmm to I32 in ireg,
9512 truncating towards zero
9513 when sz==8 -- convert F64 in mem/low half xmm to I64 in ireg,
9514 truncating towards zero
9515 */
9516 if (haveF2no66noF3(pfx)
9517 && insn[0] == 0x0F
9518 && ( /* insn[1] == 0x2D || */ insn[1] == 0x2C)) {
9519 IRTemp rmode = newTemp(Ity_I32);
9520 IRTemp f64lo = newTemp(Ity_F64);
sewardj1027dc22005-02-26 01:55:02 +00009521 Bool r2zero = toBool(insn[1] == 0x2C);
sewardj1a01e652005-02-23 11:39:21 +00009522 vassert(sz == 4 || sz == 8);
9523
9524 modrm = getUChar(delta+2);
9525 if (epartIsReg(modrm)) {
9526 delta += 2+1;
9527 assign(f64lo, getXMMRegLane64F(eregOfRexRM(pfx,modrm), 0));
9528 DIP("cvt%ssd2si %s,%s\n", r2zero ? "t" : "",
9529 nameXMMReg(eregOfRexRM(pfx,modrm)),
sewardj5b470602005-02-27 13:10:48 +00009530 nameIReg(sz, gregOfRexRM(pfx,modrm), False));
sewardj1a01e652005-02-23 11:39:21 +00009531 } else {
9532 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9533 assign(f64lo, loadLE(Ity_F64, mkexpr(addr)));
9534 delta += 2+alen;
9535 DIP("cvt%ssd2si %s,%s\n", r2zero ? "t" : "",
9536 dis_buf,
sewardj5b470602005-02-27 13:10:48 +00009537 nameIReg(sz, gregOfRexRM(pfx,modrm), False));
sewardj1a01e652005-02-23 11:39:21 +00009538 }
9539
9540 if (r2zero) {
9541 assign( rmode, mkU32((UInt)Irrm_ZERO) );
9542 } else {
9543 assign( rmode, get_sse_roundingmode() );
9544 }
9545
9546 if (sz == 4) {
sewardj5b470602005-02-27 13:10:48 +00009547 putIReg32( gregOfRexRM(pfx,modrm),
9548 binop( Iop_F64toI32, mkexpr(rmode), mkexpr(f64lo)) );
sewardj1a01e652005-02-23 11:39:21 +00009549 } else {
sewardj5b470602005-02-27 13:10:48 +00009550 putIReg64( gregOfRexRM(pfx,modrm),
9551 binop( Iop_F64toI64, mkexpr(rmode), mkexpr(f64lo)) );
sewardj1a01e652005-02-23 11:39:21 +00009552 }
9553
9554 goto decode_success;
9555 }
9556
sewardj8d965312005-02-25 02:48:47 +00009557 /* F2 0F 5A = CVTSD2SS -- convert F64 in mem/low half xmm to F32 in
9558 low 1/4 xmm(G), according to prevailing SSE rounding mode */
9559 if (haveF2no66noF3(pfx) && sz == 4
9560 && insn[0] == 0x0F && insn[1] == 0x5A) {
9561 IRTemp rmode = newTemp(Ity_I32);
9562 IRTemp f64lo = newTemp(Ity_F64);
9563 vassert(sz == 4);
9564
9565 modrm = getUChar(delta+2);
9566 if (epartIsReg(modrm)) {
9567 delta += 2+1;
9568 assign(f64lo, getXMMRegLane64F(eregOfRexRM(pfx,modrm), 0));
9569 DIP("cvtsd2ss %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
9570 nameXMMReg(gregOfRexRM(pfx,modrm)));
9571 } else {
9572 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9573 assign(f64lo, loadLE(Ity_F64, mkexpr(addr)));
9574 delta += 2+alen;
9575 DIP("cvtsd2ss %s,%s\n", dis_buf,
9576 nameXMMReg(gregOfRexRM(pfx,modrm)));
9577 }
9578
9579 assign( rmode, get_sse_roundingmode() );
9580 putXMMRegLane32F(
9581 gregOfRexRM(pfx,modrm), 0,
9582 binop( Iop_F64toF32, mkexpr(rmode), mkexpr(f64lo) )
9583 );
9584
9585 goto decode_success;
9586 }
sewardj1a01e652005-02-23 11:39:21 +00009587
9588 /* F2 0F 2A = CVTSI2SD
9589 when sz==4 -- convert I32 in mem/ireg to F64 in low half xmm
9590 when sz==8 -- convert I64 in mem/ireg to F64 in low half xmm
9591 */
sewardj8d965312005-02-25 02:48:47 +00009592 if (haveF2no66noF3(pfx) && (sz == 4 || sz == 8)
9593 && insn[0] == 0x0F && insn[1] == 0x2A) {
sewardj1a01e652005-02-23 11:39:21 +00009594 modrm = getUChar(delta+2);
9595
9596 if (sz == 4) {
9597 IRTemp arg32 = newTemp(Ity_I32);
9598 if (epartIsReg(modrm)) {
sewardj5b470602005-02-27 13:10:48 +00009599 assign( arg32, getIReg32(eregOfRexRM(pfx,modrm)) );
sewardj1a01e652005-02-23 11:39:21 +00009600 delta += 2+1;
sewardj5b470602005-02-27 13:10:48 +00009601 DIP("cvtsi2sd %s,%s\n", nameIReg32(eregOfRexRM(pfx,modrm)),
sewardj1a01e652005-02-23 11:39:21 +00009602 nameXMMReg(gregOfRexRM(pfx,modrm)));
9603 } else {
9604 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9605 assign( arg32, loadLE(Ity_I32, mkexpr(addr)) );
9606 delta += 2+alen;
9607 DIP("cvtsi2sd %s,%s\n", dis_buf,
9608 nameXMMReg(gregOfRexRM(pfx,modrm)) );
9609 }
9610 putXMMRegLane64F( gregOfRexRM(pfx,modrm), 0,
9611 unop(Iop_I32toF64, mkexpr(arg32))
9612 );
9613 } else {
9614 /* sz == 8 */
9615 IRTemp arg64 = newTemp(Ity_I64);
9616 if (epartIsReg(modrm)) {
sewardj5b470602005-02-27 13:10:48 +00009617 assign( arg64, getIReg64(eregOfRexRM(pfx,modrm)) );
sewardj1a01e652005-02-23 11:39:21 +00009618 delta += 2+1;
sewardj5b470602005-02-27 13:10:48 +00009619 DIP("cvtsi2sdq %s,%s\n", nameIReg64(eregOfRexRM(pfx,modrm)),
sewardj8d965312005-02-25 02:48:47 +00009620 nameXMMReg(gregOfRexRM(pfx,modrm)));
sewardj1a01e652005-02-23 11:39:21 +00009621 } else {
9622 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9623 assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
9624 delta += 2+alen;
sewardj8d965312005-02-25 02:48:47 +00009625 DIP("cvtsi2sdq %s,%s\n", dis_buf,
9626 nameXMMReg(gregOfRexRM(pfx,modrm)) );
sewardj1a01e652005-02-23 11:39:21 +00009627 }
9628 putXMMRegLane64F(
9629 gregOfRexRM(pfx,modrm),
9630 0,
9631 binop( Iop_I64toF64,
9632 get_sse_roundingmode(),
9633 mkexpr(arg64)
9634 )
9635 );
9636
9637 }
9638
9639 goto decode_success;
9640 }
9641
sewardjc49ce232005-02-25 13:03:03 +00009642 /* F3 0F 5A = CVTSS2SD -- convert F32 in mem/low 1/4 xmm to F64 in
9643 low half xmm(G) */
9644 if (haveF3no66noF2(pfx) && sz == 4
9645 && insn[0] == 0x0F && insn[1] == 0x5A) {
9646 IRTemp f32lo = newTemp(Ity_F32);
9647
9648 modrm = getUChar(delta+2);
9649 if (epartIsReg(modrm)) {
9650 delta += 2+1;
9651 assign(f32lo, getXMMRegLane32F(eregOfRexRM(pfx,modrm), 0));
9652 DIP("cvtss2sd %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
9653 nameXMMReg(gregOfRexRM(pfx,modrm)));
9654 } else {
9655 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9656 assign(f32lo, loadLE(Ity_F32, mkexpr(addr)));
9657 delta += 2+alen;
9658 DIP("cvtss2sd %s,%s\n", dis_buf,
9659 nameXMMReg(gregOfRexRM(pfx,modrm)));
9660 }
9661
9662 putXMMRegLane64F( gregOfRexRM(pfx,modrm), 0,
9663 unop( Iop_F32toF64, mkexpr(f32lo) ) );
9664
9665 goto decode_success;
9666 }
9667
sewardjd20c8852005-01-20 20:04:07 +00009668//.. /* 66 0F E6 = CVTTPD2DQ -- convert 2 x F64 in mem/xmm to 2 x I32 in
9669//.. lo half xmm(G), and zero upper half, rounding towards zero */
9670//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE6) {
9671//.. IRTemp argV = newTemp(Ity_V128);
9672//.. IRTemp rmode = newTemp(Ity_I32);
9673//..
sewardj8c332e22005-01-28 01:36:56 +00009674//.. modrm = getUChar(delta+2);
sewardjd20c8852005-01-20 20:04:07 +00009675//.. if (epartIsReg(modrm)) {
9676//.. assign( argV, getXMMReg(eregOfRM(modrm)) );
9677//.. delta += 2+1;
9678//.. DIP("cvttpd2dq %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9679//.. nameXMMReg(gregOfRM(modrm)));
9680//.. } else {
9681//.. addr = disAMode ( &alen, sorb, delta+2, dis_buf );
sewardj1a01e652005-02-23 11:39:21 +00009682//.. assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
sewardjd20c8852005-01-20 20:04:07 +00009683//.. delta += 2+alen;
9684//.. DIP("cvttpd2dq %s,%s\n", dis_buf,
9685//.. nameXMMReg(gregOfRM(modrm)) );
9686//.. }
9687//..
9688//.. assign( rmode, mkU32((UInt)Irrm_ZERO) );
9689//..
9690//.. t0 = newTemp(Ity_F64);
9691//.. t1 = newTemp(Ity_F64);
9692//.. assign( t0, unop(Iop_ReinterpI64asF64,
9693//.. unop(Iop_128to64, mkexpr(argV))) );
9694//.. assign( t1, unop(Iop_ReinterpI64asF64,
9695//.. unop(Iop_128HIto64, mkexpr(argV))) );
9696//..
9697//.. # define CVT(_t) binop( Iop_F64toI32, \
9698//.. mkexpr(rmode), \
9699//.. mkexpr(_t) )
9700//..
9701//.. putXMMRegLane32( gregOfRM(modrm), 3, mkU32(0) );
9702//.. putXMMRegLane32( gregOfRM(modrm), 2, mkU32(0) );
9703//.. putXMMRegLane32( gregOfRM(modrm), 1, CVT(t1) );
9704//.. putXMMRegLane32( gregOfRM(modrm), 0, CVT(t0) );
9705//..
9706//.. # undef CVT
9707//..
9708//.. goto decode_success;
9709//.. }
9710//..
9711//.. /* F3 0F 5B = CVTTPS2DQ -- convert 4 x F32 in mem/xmm to 4 x I32 in
9712//.. xmm(G), rounding towards zero */
9713//.. if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5B) {
9714//.. IRTemp argV = newTemp(Ity_V128);
9715//.. IRTemp rmode = newTemp(Ity_I32);
9716//.. vassert(sz == 4);
9717//..
sewardj8c332e22005-01-28 01:36:56 +00009718//.. modrm = getUChar(delta+3);
sewardjd20c8852005-01-20 20:04:07 +00009719//.. if (epartIsReg(modrm)) {
9720//.. assign( argV, getXMMReg(eregOfRM(modrm)) );
9721//.. delta += 3+1;
9722//.. DIP("cvttps2dq %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9723//.. nameXMMReg(gregOfRM(modrm)));
9724//.. } else {
9725//.. addr = disAMode ( &alen, sorb, delta+3, dis_buf );
9726//.. assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
9727//.. delta += 3+alen;
9728//.. DIP("cvttps2dq %s,%s\n", dis_buf,
9729//.. nameXMMReg(gregOfRM(modrm)) );
9730//.. }
9731//..
9732//.. assign( rmode, mkU32((UInt)Irrm_ZERO) );
9733//.. breakup128to32s( argV, &t3, &t2, &t1, &t0 );
9734//..
9735//.. /* This is less than ideal. If it turns out to be a performance
9736//.. bottleneck it can be improved. */
9737//.. # define CVT(_t) \
9738//.. binop( Iop_F64toI32, \
9739//.. mkexpr(rmode), \
9740//.. unop( Iop_F32toF64, \
9741//.. unop( Iop_ReinterpI32asF32, mkexpr(_t))) )
9742//..
9743//.. putXMMRegLane32( gregOfRM(modrm), 3, CVT(t3) );
9744//.. putXMMRegLane32( gregOfRM(modrm), 2, CVT(t2) );
9745//.. putXMMRegLane32( gregOfRM(modrm), 1, CVT(t1) );
9746//.. putXMMRegLane32( gregOfRM(modrm), 0, CVT(t0) );
9747//..
9748//.. # undef CVT
9749//..
9750//.. goto decode_success;
9751//.. }
9752//..
9753//.. /* 66 0F 5E = DIVPD -- div 64Fx2 from R/M to R */
9754//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5E) {
9755//.. delta = dis_SSE_E_to_G_all( sorb, delta+2, "divpd", Iop_Div64Fx2 );
9756//.. goto decode_success;
9757//.. }
sewardj1001dc42005-02-21 08:25:55 +00009758
9759 /* F2 0F 5E = DIVSD -- div 64F0x2 from R/M to R */
9760 if (haveF2no66noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x5E) {
9761 vassert(sz == 4);
9762 delta = dis_SSE_E_to_G_lo64( pfx, delta+2, "divsd", Iop_Div64F0x2 );
9763 goto decode_success;
9764 }
9765
sewardjd20c8852005-01-20 20:04:07 +00009766//.. /* 0F AE /5 = LFENCE -- flush pending operations to memory */
9767//.. /* 0F AE /6 = MFENCE -- flush pending operations to memory */
9768//.. if (insn[0] == 0x0F && insn[1] == 0xAE
9769//.. && epartIsReg(insn[2])
9770//.. && (gregOfRM(insn[2]) == 5 || gregOfRM(insn[2]) == 6)) {
9771//.. vassert(sz == 4);
9772//.. delta += 3;
9773//.. /* Insert a memory fence. It's sometimes important that these
9774//.. are carried through to the generated code. */
9775//.. stmt( IRStmt_MFence() );
9776//.. DIP("%sfence\n", gregOfRM(insn[2])==5 ? "l" : "m");
9777//.. goto decode_success;
9778//.. }
9779//..
9780//.. /* 66 0F 5F = MAXPD -- max 64Fx2 from R/M to R */
9781//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5F) {
9782//.. delta = dis_SSE_E_to_G_all( sorb, delta+2, "maxpd", Iop_Max64Fx2 );
9783//.. goto decode_success;
9784//.. }
sewardj1a01e652005-02-23 11:39:21 +00009785
9786 /* F2 0F 5F = MAXSD -- max 64F0x2 from R/M to R */
9787 if (haveF2no66noF3(pfx) && sz == 4
9788 && insn[0] == 0x0F && insn[1] == 0x5F) {
9789 delta = dis_SSE_E_to_G_lo64( pfx, delta+2, "maxsd", Iop_Max64F0x2 );
9790 goto decode_success;
9791 }
9792
sewardjd20c8852005-01-20 20:04:07 +00009793//.. /* 66 0F 5D = MINPD -- min 64Fx2 from R/M to R */
9794//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5D) {
9795//.. delta = dis_SSE_E_to_G_all( sorb, delta+2, "minpd", Iop_Min64Fx2 );
9796//.. goto decode_success;
9797//.. }
sewardjc49ce232005-02-25 13:03:03 +00009798
9799 /* F2 0F 5D = MINSD -- min 64F0x2 from R/M to R */
9800 if (haveF2no66noF3(pfx) && sz == 4
9801 && insn[0] == 0x0F && insn[1] == 0x5D) {
9802 delta = dis_SSE_E_to_G_lo64( pfx, delta+2, "minsd", Iop_Min64F0x2 );
9803 goto decode_success;
9804 }
sewardj8d965312005-02-25 02:48:47 +00009805
9806 /* 66 0F 28 = MOVAPD -- move from E (mem or xmm) to G (xmm). */
9807 /* 66 0F 10 = MOVUPD -- move from E (mem or xmm) to G (xmm). */
9808 /* 66 0F 6F = MOVDQA -- move from E (mem or xmm) to G (xmm). */
9809 if (have66noF2noF3(pfx) && sz == 2
9810 && insn[0] == 0x0F
9811 && (insn[1] == 0x28 || insn[1] == 0x10 || insn[1] == 0x6F)) {
9812 HChar* wot = insn[1]==0x28 ? "apd" :
9813 insn[1]==0x10 ? "upd" : "dqa";
9814 modrm = getUChar(delta+2);
9815 if (epartIsReg(modrm)) {
9816 putXMMReg( gregOfRexRM(pfx,modrm),
9817 getXMMReg( eregOfRexRM(pfx,modrm) ));
9818 DIP("mov%s %s,%s\n", wot, nameXMMReg(eregOfRexRM(pfx,modrm)),
9819 nameXMMReg(gregOfRexRM(pfx,modrm)));
9820 delta += 2+1;
9821 } else {
9822 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9823 putXMMReg( gregOfRexRM(pfx,modrm),
9824 loadLE(Ity_V128, mkexpr(addr)) );
9825 DIP("mov%s %s,%s\n", wot, dis_buf,
9826 nameXMMReg(gregOfRexRM(pfx,modrm)));
9827 delta += 2+alen;
9828 }
9829 goto decode_success;
9830 }
9831
sewardjd20c8852005-01-20 20:04:07 +00009832//.. /* 66 0F 29 = MOVAPD -- move from G (xmm) to E (mem or xmm). */
9833//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x29) {
sewardj8c332e22005-01-28 01:36:56 +00009834//.. modrm = getUChar(delta+2);
sewardjd20c8852005-01-20 20:04:07 +00009835//.. if (epartIsReg(modrm)) {
9836//.. /* fall through; awaiting test case */
9837//.. } else {
9838//.. addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9839//.. storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) );
9840//.. DIP("movapd %s,%s\n", nameXMMReg(gregOfRM(modrm)),
9841//.. dis_buf );
9842//.. delta += 2+alen;
9843//.. goto decode_success;
9844//.. }
9845//.. }
9846//..
9847//.. /* 66 0F 6E = MOVD from r/m32 to xmm, zeroing high 3/4 of xmm. */
9848//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x6E) {
sewardj8c332e22005-01-28 01:36:56 +00009849//.. modrm = getUChar(delta+2);
sewardjd20c8852005-01-20 20:04:07 +00009850//.. if (epartIsReg(modrm)) {
9851//.. delta += 2+1;
9852//.. putXMMReg(
9853//.. gregOfRM(modrm),
9854//.. unop( Iop_32Uto128, getIReg(4, eregOfRM(modrm)) )
9855//.. );
9856//.. DIP("movd %s, %s\n",
9857//.. nameIReg(4,eregOfRM(modrm)), nameXMMReg(gregOfRM(modrm)));
9858//.. } else {
9859//.. addr = disAMode( &alen, sorb, delta+2, dis_buf );
9860//.. delta += 2+alen;
9861//.. putXMMReg(
9862//.. gregOfRM(modrm),
9863//.. unop( Iop_32Uto128,loadLE(Ity_I32, mkexpr(addr)) )
9864//.. );
9865//.. DIP("movd %s, %s\n", dis_buf, nameXMMReg(gregOfRM(modrm)));
9866//.. }
9867//.. goto decode_success;
9868//.. }
9869//..
9870//.. /* 66 0F 7E = MOVD from xmm low 1/4 to r/m32. */
9871//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x7E) {
sewardj8c332e22005-01-28 01:36:56 +00009872//.. modrm = getUChar(delta+2);
sewardjd20c8852005-01-20 20:04:07 +00009873//.. if (epartIsReg(modrm)) {
9874//.. delta += 2+1;
9875//.. putIReg( 4, eregOfRM(modrm),
9876//.. getXMMRegLane32(gregOfRM(modrm), 0) );
9877//.. DIP("movd %s, %s\n",
9878//.. nameXMMReg(gregOfRM(modrm)), nameIReg(4,eregOfRM(modrm)));
9879//.. } else {
9880//.. addr = disAMode( &alen, sorb, delta+2, dis_buf );
9881//.. delta += 2+alen;
9882//.. storeLE( mkexpr(addr),
9883//.. getXMMRegLane32(gregOfRM(modrm), 0) );
9884//.. DIP("movd %s, %s\n", nameXMMReg(gregOfRM(modrm)), dis_buf);
9885//.. }
9886//.. goto decode_success;
9887//.. }
9888//..
9889//.. /* 66 0F 7F = MOVDQA -- move from G (xmm) to E (mem or xmm). */
9890//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x7F) {
sewardj8c332e22005-01-28 01:36:56 +00009891//.. modrm = getUChar(delta+2);
sewardjd20c8852005-01-20 20:04:07 +00009892//.. if (epartIsReg(modrm)) {
9893//.. delta += 2+1;
9894//.. putXMMReg( eregOfRM(modrm),
9895//.. getXMMReg(gregOfRM(modrm)) );
9896//.. DIP("movdqa %s, %s\n", nameXMMReg(gregOfRM(modrm)),
9897//.. nameXMMReg(eregOfRM(modrm)));
9898//.. } else {
9899//.. addr = disAMode( &alen, sorb, delta+2, dis_buf );
9900//.. delta += 2+alen;
9901//.. storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) );
9902//.. DIP("movdqa %s, %s\n", nameXMMReg(gregOfRM(modrm)), dis_buf);
9903//.. }
9904//.. goto decode_success;
9905//.. }
9906//..
9907//.. /* F3 0F 6F = MOVDQU -- move from E (mem or xmm) to G (xmm). */
9908//.. /* Unfortunately can't simply use the MOVDQA case since the
9909//.. prefix lengths are different (66 vs F3) */
9910//.. if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x6F) {
9911//.. vassert(sz == 4);
sewardj8c332e22005-01-28 01:36:56 +00009912//.. modrm = getUChar(delta+3);
sewardjd20c8852005-01-20 20:04:07 +00009913//.. if (epartIsReg(modrm)) {
9914//.. putXMMReg( gregOfRM(modrm),
9915//.. getXMMReg( eregOfRM(modrm) ));
9916//.. DIP("movdqu %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9917//.. nameXMMReg(gregOfRM(modrm)));
9918//.. delta += 3+1;
9919//.. } else {
9920//.. addr = disAMode ( &alen, sorb, delta+3, dis_buf );
9921//.. putXMMReg( gregOfRM(modrm),
9922//.. loadLE(Ity_V128, mkexpr(addr)) );
9923//.. DIP("movdqu %s,%s\n", dis_buf,
9924//.. nameXMMReg(gregOfRM(modrm)));
9925//.. delta += 3+alen;
9926//.. }
9927//.. goto decode_success;
9928//.. }
9929//..
9930//.. /* F3 0F 7F = MOVDQU -- move from G (xmm) to E (mem or xmm). */
9931//.. /* Unfortunately can't simply use the MOVDQA case since the
9932//.. prefix lengths are different (66 vs F3) */
9933//.. if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x7F) {
9934//.. vassert(sz == 4);
sewardj8c332e22005-01-28 01:36:56 +00009935//.. modrm = getUChar(delta+3);
sewardjd20c8852005-01-20 20:04:07 +00009936//.. if (epartIsReg(modrm)) {
9937//.. delta += 3+1;
9938//.. putXMMReg( eregOfRM(modrm),
9939//.. getXMMReg(gregOfRM(modrm)) );
9940//.. DIP("movdqu %s, %s\n", nameXMMReg(gregOfRM(modrm)),
9941//.. nameXMMReg(eregOfRM(modrm)));
9942//.. } else {
9943//.. addr = disAMode( &alen, sorb, delta+3, dis_buf );
9944//.. delta += 3+alen;
9945//.. storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) );
9946//.. DIP("movdqu %s, %s\n", nameXMMReg(gregOfRM(modrm)), dis_buf);
9947//.. }
9948//.. goto decode_success;
9949//.. }
9950//..
9951//.. /* F2 0F D6 = MOVDQ2Q -- move from E (lo half xmm, not mem) to G (mmx). */
9952//.. if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0xD6) {
9953//.. vassert(sz == 4);
sewardj8c332e22005-01-28 01:36:56 +00009954//.. modrm = getUChar(delta+3);
sewardjd20c8852005-01-20 20:04:07 +00009955//.. if (epartIsReg(modrm)) {
9956//.. do_MMX_preamble();
9957//.. putMMXReg( gregOfRM(modrm),
9958//.. getXMMRegLane64( eregOfRM(modrm), 0 ));
9959//.. DIP("movdq2q %s,%s\n", nameXMMReg(eregOfRM(modrm)),
9960//.. nameMMXReg(gregOfRM(modrm)));
9961//.. delta += 3+1;
9962//.. goto decode_success;
9963//.. } else {
9964//.. /* fall through, apparently no mem case for this insn */
9965//.. }
9966//.. }
9967//..
9968//.. /* 66 0F 16 = MOVHPD -- move from mem to high half of XMM. */
9969//.. /* These seems identical to MOVHPS. This instruction encoding is
9970//.. completely crazy. */
9971//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x16) {
sewardj8c332e22005-01-28 01:36:56 +00009972//.. modrm = getUChar(delta+2);
sewardjd20c8852005-01-20 20:04:07 +00009973//.. if (epartIsReg(modrm)) {
9974//.. /* fall through; apparently reg-reg is not possible */
9975//.. } else {
9976//.. addr = disAMode ( &alen, sorb, delta+2, dis_buf );
9977//.. delta += 2+alen;
9978//.. putXMMRegLane64( gregOfRM(modrm), 1/*upper lane*/,
9979//.. loadLE(Ity_I64, mkexpr(addr)) );
9980//.. DIP("movhpd %s,%s\n", dis_buf,
9981//.. nameXMMReg( gregOfRM(modrm) ));
9982//.. goto decode_success;
9983//.. }
9984//.. }
9985//..
9986//.. /* 66 0F 17 = MOVHPD -- move from high half of XMM to mem. */
9987//.. /* Again, this seems identical to MOVHPS. */
9988//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x17) {
9989//.. if (!epartIsReg(insn[2])) {
9990//.. delta += 2;
9991//.. addr = disAMode ( &alen, sorb, delta, dis_buf );
9992//.. delta += alen;
9993//.. storeLE( mkexpr(addr),
9994//.. getXMMRegLane64( gregOfRM(insn[2]),
9995//.. 1/*upper lane*/ ) );
9996//.. DIP("movhpd %s,%s\n", nameXMMReg( gregOfRM(insn[2]) ),
9997//.. dis_buf);
9998//.. goto decode_success;
9999//.. }
10000//.. /* else fall through */
10001//.. }
sewardj1001dc42005-02-21 08:25:55 +000010002
10003 /* 66 0F 12 = MOVLPD -- move from mem to low half of XMM. */
10004 /* Identical to MOVLPS ? */
10005 if (have66noF2noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x12) {
10006 modrm = getUChar(delta+2);
10007 if (epartIsReg(modrm)) {
10008 /* fall through; apparently reg-reg is not possible */
10009 } else {
10010 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10011 delta += 2+alen;
10012 putXMMRegLane64( gregOfRexRM(pfx,modrm),
10013 0/*lower lane*/,
10014 loadLE(Ity_I64, mkexpr(addr)) );
10015 DIP("movlpd %s, %s\n",
10016 dis_buf, nameXMMReg( gregOfRexRM(pfx,modrm) ));
10017 goto decode_success;
10018 }
10019 }
10020
sewardjd20c8852005-01-20 20:04:07 +000010021//.. /* 66 0F 13 = MOVLPD -- move from low half of XMM to mem. */
10022//.. /* Identical to MOVLPS ? */
10023//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x13) {
10024//.. if (!epartIsReg(insn[2])) {
10025//.. delta += 2;
10026//.. addr = disAMode ( &alen, sorb, delta, dis_buf );
10027//.. delta += alen;
10028//.. storeLE( mkexpr(addr),
10029//.. getXMMRegLane64( gregOfRM(insn[2]),
10030//.. 0/*lower lane*/ ) );
10031//.. DIP("movlpd %s, %s\n", nameXMMReg( gregOfRM(insn[2]) ),
10032//.. dis_buf);
10033//.. goto decode_success;
10034//.. }
10035//.. /* else fall through */
10036//.. }
10037//..
10038//.. /* 66 0F 50 = MOVMSKPD - move 2 sign bits from 2 x F64 in xmm(E) to
10039//.. 2 lowest bits of ireg(G) */
10040//.. if (insn[0] == 0x0F && insn[1] == 0x50) {
sewardj8c332e22005-01-28 01:36:56 +000010041//.. modrm = getUChar(delta+2);
sewardjd20c8852005-01-20 20:04:07 +000010042//.. if (sz == 2 && epartIsReg(modrm)) {
10043//.. Int src;
10044//.. t0 = newTemp(Ity_I32);
10045//.. t1 = newTemp(Ity_I32);
10046//.. delta += 2+1;
10047//.. src = eregOfRM(modrm);
10048//.. assign( t0, binop( Iop_And32,
10049//.. binop(Iop_Shr32, getXMMRegLane32(src,1), mkU8(31)),
10050//.. mkU32(1) ));
10051//.. assign( t1, binop( Iop_And32,
10052//.. binop(Iop_Shr32, getXMMRegLane32(src,3), mkU8(30)),
10053//.. mkU32(2) ));
10054//.. putIReg(4, gregOfRM(modrm),
10055//.. binop(Iop_Or32, mkexpr(t0), mkexpr(t1))
10056//.. );
10057//.. DIP("movmskpd %s,%s\n", nameXMMReg(src),
10058//.. nameIReg(4, gregOfRM(modrm)));
10059//.. goto decode_success;
10060//.. }
10061//.. /* else fall through */
10062//.. }
10063//..
10064//.. /* 66 0F E7 = MOVNTDQ -- for us, just a plain SSE store. */
10065//.. if (insn[0] == 0x0F && insn[1] == 0xE7) {
sewardj8c332e22005-01-28 01:36:56 +000010066//.. modrm = getUChar(delta+2);
sewardjd20c8852005-01-20 20:04:07 +000010067//.. if (sz == 2 && !epartIsReg(modrm)) {
10068//.. addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10069//.. storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) );
10070//.. DIP("movntdq %s,%s\n", dis_buf,
10071//.. nameXMMReg(gregOfRM(modrm)));
10072//.. delta += 2+alen;
10073//.. goto decode_success;
10074//.. }
10075//.. /* else fall through */
10076//.. }
10077//..
10078//.. /* 0F C3 = MOVNTI -- for us, just a plain ireg store. */
10079//.. if (insn[0] == 0x0F && insn[1] == 0xC3) {
10080//.. vassert(sz == 4);
sewardj8c332e22005-01-28 01:36:56 +000010081//.. modrm = getUChar(delta+2);
sewardjd20c8852005-01-20 20:04:07 +000010082//.. if (!epartIsReg(modrm)) {
10083//.. addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10084//.. storeLE( mkexpr(addr), getIReg(4, gregOfRM(modrm)) );
10085//.. DIP("movnti %s,%s\n", dis_buf,
10086//.. nameIReg(4, gregOfRM(modrm)));
10087//.. delta += 2+alen;
10088//.. goto decode_success;
10089//.. }
10090//.. /* else fall through */
10091//.. }
10092//..
10093//.. /* 66 0F D6 = MOVQ -- move 64 bits from G (lo half xmm) to E (mem
10094//.. or lo half xmm). */
10095//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD6) {
sewardj8c332e22005-01-28 01:36:56 +000010096//.. modrm = getUChar(delta+2);
sewardjd20c8852005-01-20 20:04:07 +000010097//.. if (epartIsReg(modrm)) {
10098//.. /* fall through, awaiting test case */
10099//.. } else {
10100//.. addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10101//.. storeLE( mkexpr(addr),
10102//.. getXMMRegLane64( gregOfRM(modrm), 0 ));
10103//.. DIP("movq %s,%s\n", nameXMMReg(gregOfRM(modrm)), dis_buf );
10104//.. delta += 2+alen;
10105//.. goto decode_success;
10106//.. }
10107//.. }
10108//..
10109//.. /* F3 0F D6 = MOVQ2DQ -- move from E (mmx) to G (lo half xmm, zero
10110//.. hi half). */
10111//.. if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0xD6) {
10112//.. vassert(sz == 4);
sewardj8c332e22005-01-28 01:36:56 +000010113//.. modrm = getUChar(delta+3);
sewardjd20c8852005-01-20 20:04:07 +000010114//.. if (epartIsReg(modrm)) {
10115//.. do_MMX_preamble();
10116//.. putXMMReg( gregOfRM(modrm),
10117//.. unop(Iop_64Uto128, getMMXReg( eregOfRM(modrm) )) );
10118//.. DIP("movq2dq %s,%s\n", nameMMXReg(eregOfRM(modrm)),
10119//.. nameXMMReg(gregOfRM(modrm)));
10120//.. delta += 3+1;
10121//.. goto decode_success;
10122//.. } else {
10123//.. /* fall through, apparently no mem case for this insn */
10124//.. }
10125//.. }
10126//..
10127//.. /* F3 0F 7E = MOVQ -- move 64 bits from E (mem or lo half xmm) to
10128//.. G (lo half xmm). If E is mem, upper half of G is zeroed out. */
sewardj1001dc42005-02-21 08:25:55 +000010129 /* F2 0F 10 = MOVSD -- move 64 bits from E (mem or lo half xmm) to
10130 G (lo half xmm). If E is mem, upper half of G is zeroed out.
10131 (original defn) */
10132 if ((haveF2no66noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x10)
10133//.. || (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x7E)
10134 ) {
10135 vassert(sz == 4);
10136 modrm = getUChar(delta+2);
10137 if (epartIsReg(modrm)) {
10138 putXMMRegLane64( gregOfRexRM(pfx,modrm), 0,
10139 getXMMRegLane64( eregOfRexRM(pfx,modrm), 0 ));
10140 DIP("movsd %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
10141 nameXMMReg(gregOfRexRM(pfx,modrm)));
10142 delta += 2+1;
10143 } else {
10144 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10145 putXMMReg( gregOfRexRM(pfx,modrm), mkV128(0) );
10146 putXMMRegLane64( gregOfRexRM(pfx,modrm), 0,
10147 loadLE(Ity_I64, mkexpr(addr)) );
10148 DIP("movsd %s,%s\n", dis_buf,
10149 nameXMMReg(gregOfRexRM(pfx,modrm)));
10150 delta += 2+alen;
10151 }
10152 goto decode_success;
10153 }
10154
10155 /* F2 0F 11 = MOVSD -- move 64 bits from G (lo half xmm) to E (mem
10156 or lo half xmm). */
sewardj8d965312005-02-25 02:48:47 +000010157 if (haveF2no66noF3(pfx) && sz == 4
10158 && insn[0] == 0x0F && insn[1] == 0x11) {
sewardj1001dc42005-02-21 08:25:55 +000010159 modrm = getUChar(delta+2);
10160 if (epartIsReg(modrm)) {
10161 /* fall through, we don't yet have a test case */
10162 } else {
10163 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10164 storeLE( mkexpr(addr),
10165 getXMMRegLane64(gregOfRexRM(pfx,modrm), 0) );
10166 DIP("movsd %s,%s\n", nameXMMReg(gregOfRexRM(pfx,modrm)),
10167 dis_buf);
10168 delta += 2+alen;
10169 goto decode_success;
10170 }
10171 }
10172
sewardjd20c8852005-01-20 20:04:07 +000010173//.. /* 66 0F 59 = MULPD -- mul 64Fx2 from R/M to R */
10174//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x59) {
10175//.. delta = dis_SSE_E_to_G_all( sorb, delta+2, "mulpd", Iop_Mul64Fx2 );
10176//.. goto decode_success;
10177//.. }
sewardj1001dc42005-02-21 08:25:55 +000010178
10179 /* F2 0F 59 = MULSD -- mul 64F0x2 from R/M to R */
sewardj8d965312005-02-25 02:48:47 +000010180 if (haveF2no66noF3(pfx) && sz == 4
10181 && insn[0] == 0x0F && insn[1] == 0x59) {
sewardj1001dc42005-02-21 08:25:55 +000010182 delta = dis_SSE_E_to_G_lo64( pfx, delta+2, "mulsd", Iop_Mul64F0x2 );
10183 goto decode_success;
10184 }
10185
sewardj8d965312005-02-25 02:48:47 +000010186 /* 66 0F 56 = ORPD -- G = G and E */
10187 if (have66noF2noF3(pfx) && sz == 2
10188 && insn[0] == 0x0F && insn[1] == 0x56) {
10189 delta = dis_SSE_E_to_G_all( pfx, delta+2, "orpd", Iop_OrV128 );
10190 goto decode_success;
10191 }
10192
sewardjd20c8852005-01-20 20:04:07 +000010193//.. /* 66 0F C6 /r ib = SHUFPD -- shuffle packed F64s */
10194//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xC6) {
10195//.. Int select;
10196//.. IRTemp sV = newTemp(Ity_V128);
10197//.. IRTemp dV = newTemp(Ity_V128);
10198//.. IRTemp s1 = newTemp(Ity_I64);
10199//.. IRTemp s0 = newTemp(Ity_I64);
10200//.. IRTemp d1 = newTemp(Ity_I64);
10201//.. IRTemp d0 = newTemp(Ity_I64);
10202//..
10203//.. modrm = insn[2];
10204//.. assign( dV, getXMMReg(gregOfRM(modrm)) );
10205//..
10206//.. if (epartIsReg(modrm)) {
10207//.. assign( sV, getXMMReg(eregOfRM(modrm)) );
10208//.. select = (Int)insn[3];
10209//.. delta += 2+2;
10210//.. DIP("shufpd $%d,%s,%s\n", select,
10211//.. nameXMMReg(eregOfRM(modrm)),
10212//.. nameXMMReg(gregOfRM(modrm)));
10213//.. } else {
10214//.. addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10215//.. assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
10216//.. select = (Int)insn[2+alen];
10217//.. delta += 3+alen;
10218//.. DIP("shufpd $%d,%s,%s\n", select,
10219//.. dis_buf,
10220//.. nameXMMReg(gregOfRM(modrm)));
10221//.. }
10222//..
10223//.. assign( d1, unop(Iop_128HIto64, mkexpr(dV)) );
10224//.. assign( d0, unop(Iop_128to64, mkexpr(dV)) );
10225//.. assign( s1, unop(Iop_128HIto64, mkexpr(sV)) );
10226//.. assign( s0, unop(Iop_128to64, mkexpr(sV)) );
10227//..
10228//.. # define SELD(n) mkexpr((n)==0 ? d0 : d1)
10229//.. # define SELS(n) mkexpr((n)==0 ? s0 : s1)
10230//..
10231//.. putXMMReg(
10232//.. gregOfRM(modrm),
10233//.. binop(Iop_64HLto128, SELS((select>>1)&1), SELD((select>>0)&1) )
10234//.. );
10235//..
10236//.. # undef SELD
10237//.. # undef SELS
10238//..
10239//.. goto decode_success;
10240//.. }
10241//..
10242//.. /* 66 0F 51 = SQRTPD -- approx sqrt 64Fx2 from R/M to R */
10243//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x51) {
10244//.. delta = dis_SSE_E_to_G_unary_all( sorb, delta+2,
10245//.. "sqrtpd", Iop_Sqrt64Fx2 );
10246//.. goto decode_success;
10247//.. }
sewardj1001dc42005-02-21 08:25:55 +000010248
10249 /* F2 0F 51 = SQRTSD -- approx sqrt 64F0x2 from R/M to R */
10250 if (haveF2no66noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x51) {
10251 vassert(sz == 4);
10252 delta = dis_SSE_E_to_G_unary_lo64( pfx, delta+2,
10253 "sqrtsd", Iop_Sqrt64F0x2 );
10254 goto decode_success;
10255 }
10256
sewardjd20c8852005-01-20 20:04:07 +000010257//.. /* 66 0F 5C = SUBPD -- sub 64Fx2 from R/M to R */
10258//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5C) {
10259//.. delta = dis_SSE_E_to_G_all( sorb, delta+2, "subpd", Iop_Sub64Fx2 );
10260//.. goto decode_success;
10261//.. }
sewardj1001dc42005-02-21 08:25:55 +000010262
10263 /* F2 0F 5C = SUBSD -- sub 64F0x2 from R/M to R */
10264 if (haveF2no66noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x5C) {
10265 vassert(sz == 4);
10266 delta = dis_SSE_E_to_G_lo64( pfx, delta+2, "subsd", Iop_Sub64F0x2 );
10267 goto decode_success;
10268 }
10269
sewardj1a01e652005-02-23 11:39:21 +000010270 /* 66 0F 15 = UNPCKHPD -- unpack and interleave high part F64s */
10271 /* 66 0F 14 = UNPCKLPD -- unpack and interleave low part F64s */
10272 /* These just appear to be special cases of SHUFPS */
10273 if (have66noF2noF3(pfx)
10274 && sz == 2 /* could be 8 if rex also present */
10275 && insn[0] == 0x0F && (insn[1] == 0x15 || insn[1] == 0x14)) {
10276 IRTemp s1 = newTemp(Ity_I64);
10277 IRTemp s0 = newTemp(Ity_I64);
10278 IRTemp d1 = newTemp(Ity_I64);
10279 IRTemp d0 = newTemp(Ity_I64);
10280 IRTemp sV = newTemp(Ity_V128);
10281 IRTemp dV = newTemp(Ity_V128);
sewardj1027dc22005-02-26 01:55:02 +000010282 Bool hi = toBool(insn[1] == 0x15);
sewardj1a01e652005-02-23 11:39:21 +000010283
10284 modrm = insn[2];
10285 assign( dV, getXMMReg(gregOfRexRM(pfx,modrm)) );
10286
10287 if (epartIsReg(modrm)) {
10288 assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
10289 delta += 2+1;
10290 DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
10291 nameXMMReg(eregOfRexRM(pfx,modrm)),
10292 nameXMMReg(gregOfRexRM(pfx,modrm)));
10293 } else {
10294 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10295 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
10296 delta += 2+alen;
10297 DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
10298 dis_buf,
10299 nameXMMReg(gregOfRexRM(pfx,modrm)));
10300 }
10301
10302 assign( d1, unop(Iop_V128HIto64, mkexpr(dV)) );
10303 assign( d0, unop(Iop_V128to64, mkexpr(dV)) );
10304 assign( s1, unop(Iop_V128HIto64, mkexpr(sV)) );
10305 assign( s0, unop(Iop_V128to64, mkexpr(sV)) );
10306
10307 if (hi) {
10308 putXMMReg( gregOfRexRM(pfx,modrm),
10309 binop(Iop_64HLtoV128, mkexpr(s1), mkexpr(d1)) );
10310 } else {
10311 putXMMReg( gregOfRexRM(pfx,modrm),
10312 binop(Iop_64HLtoV128, mkexpr(s0), mkexpr(d0)) );
10313 }
10314
10315 goto decode_success;
10316 }
sewardj9da16972005-02-21 13:58:26 +000010317
10318 /* 66 0F 57 = XORPD -- G = G xor E */
10319 if (have66noF2noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x57) {
10320 delta = dis_SSE_E_to_G_all( pfx, delta+2, "xorpd", Iop_XorV128 );
10321 goto decode_success;
10322 }
10323
sewardjd20c8852005-01-20 20:04:07 +000010324//.. /* 66 0F 6B = PACKSSDW */
10325//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x6B) {
10326//.. delta = dis_SSEint_E_to_G( sorb, delta+2,
10327//.. "packssdw", Iop_QNarrow32Sx4, True );
10328//.. goto decode_success;
10329//.. }
10330//..
10331//.. /* 66 0F 63 = PACKSSWB */
10332//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x63) {
10333//.. delta = dis_SSEint_E_to_G( sorb, delta+2,
10334//.. "packsswb", Iop_QNarrow16Sx8, True );
10335//.. goto decode_success;
10336//.. }
10337//..
10338//.. /* 66 0F 67 = PACKUSWB */
10339//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x67) {
10340//.. delta = dis_SSEint_E_to_G( sorb, delta+2,
10341//.. "packuswb", Iop_QNarrow16Ux8, True );
10342//.. goto decode_success;
10343//.. }
10344//..
10345//.. /* 66 0F FC = PADDB */
10346//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xFC) {
10347//.. delta = dis_SSEint_E_to_G( sorb, delta+2,
10348//.. "paddb", Iop_Add8x16, False );
10349//.. goto decode_success;
10350//.. }
10351//..
10352//.. /* 66 0F FE = PADDD */
10353//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xFE) {
10354//.. delta = dis_SSEint_E_to_G( sorb, delta+2,
10355//.. "paddd", Iop_Add32x4, False );
10356//.. goto decode_success;
10357//.. }
10358//..
10359//.. /* ***--- this is an MMX class insn introduced in SSE2 ---*** */
10360//.. /* 0F D4 = PADDQ -- add 64x1 */
10361//.. if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xD4) {
10362//.. do_MMX_preamble();
10363//.. delta = dis_MMXop_regmem_to_reg (
10364//.. sorb, delta+2, insn[1], "paddq", False );
10365//.. goto decode_success;
10366//.. }
10367//..
10368//.. /* 66 0F D4 = PADDQ */
10369//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD4) {
10370//.. delta = dis_SSEint_E_to_G( sorb, delta+2,
10371//.. "paddq", Iop_Add64x2, False );
10372//.. goto decode_success;
10373//.. }
10374//..
10375//.. /* 66 0F FD = PADDW */
10376//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xFD) {
10377//.. delta = dis_SSEint_E_to_G( sorb, delta+2,
10378//.. "paddw", Iop_Add16x8, False );
10379//.. goto decode_success;
10380//.. }
10381//..
10382//.. /* 66 0F EC = PADDSB */
10383//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xEC) {
10384//.. delta = dis_SSEint_E_to_G( sorb, delta+2,
10385//.. "paddsb", Iop_QAdd8Sx16, False );
10386//.. goto decode_success;
10387//.. }
10388//..
10389//.. /* 66 0F ED = PADDSW */
10390//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xED) {
10391//.. delta = dis_SSEint_E_to_G( sorb, delta+2,
10392//.. "paddsw", Iop_QAdd16Sx8, False );
10393//.. goto decode_success;
10394//.. }
10395//..
10396//.. /* 66 0F DC = PADDUSB */
10397//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDC) {
10398//.. delta = dis_SSEint_E_to_G( sorb, delta+2,
10399//.. "paddusb", Iop_QAdd8Ux16, False );
10400//.. goto decode_success;
10401//.. }
10402//..
10403//.. /* 66 0F DD = PADDUSW */
10404//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDD) {
10405//.. delta = dis_SSEint_E_to_G( sorb, delta+2,
10406//.. "paddusw", Iop_QAdd16Ux8, False );
10407//.. goto decode_success;
10408//.. }
10409//..
10410//.. /* 66 0F DB = PAND */
10411//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDB) {
10412//.. delta = dis_SSE_E_to_G_all( sorb, delta+2, "pand", Iop_And128 );
10413//.. goto decode_success;
10414//.. }
10415//..
10416//.. /* 66 0F DF = PANDN */
10417//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDF) {
10418//.. delta = dis_SSE_E_to_G_all_invG( sorb, delta+2, "pandn", Iop_And128 );
10419//.. goto decode_success;
10420//.. }
10421//..
10422//.. /* 66 0F E0 = PAVGB */
10423//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE0) {
10424//.. delta = dis_SSEint_E_to_G( sorb, delta+2,
10425//.. "pavgb", Iop_Avg8Ux16, False );
10426//.. goto decode_success;
10427//.. }
10428//..
10429//.. /* 66 0F E3 = PAVGW */
10430//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE3) {
10431//.. delta = dis_SSEint_E_to_G( sorb, delta+2,
10432//.. "pavgw", Iop_Avg16Ux8, False );
10433//.. goto decode_success;
10434//.. }
10435//..
10436//.. /* 66 0F 74 = PCMPEQB */
10437//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x74) {
10438//.. delta = dis_SSEint_E_to_G( sorb, delta+2,
10439//.. "pcmpeqb", Iop_CmpEQ8x16, False );
10440//.. goto decode_success;
10441//.. }
10442//..
10443//.. /* 66 0F 76 = PCMPEQD */
10444//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x76) {
10445//.. delta = dis_SSEint_E_to_G( sorb, delta+2,
10446//.. "pcmpeqd", Iop_CmpEQ32x4, False );
10447//.. goto decode_success;
10448//.. }
10449//..
10450//.. /* 66 0F 75 = PCMPEQW */
10451//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x75) {
10452//.. delta = dis_SSEint_E_to_G( sorb, delta+2,
10453//.. "pcmpeqw", Iop_CmpEQ16x8, False );
10454//.. goto decode_success;
10455//.. }
10456//..
10457//.. /* 66 0F 64 = PCMPGTB */
10458//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x64) {
10459//.. delta = dis_SSEint_E_to_G( sorb, delta+2,
10460//.. "pcmpgtb", Iop_CmpGT8Sx16, False );
10461//.. goto decode_success;
10462//.. }
10463//..
10464//.. /* 66 0F 66 = PCMPGTD */
10465//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x66) {
10466//.. delta = dis_SSEint_E_to_G( sorb, delta+2,
10467//.. "pcmpgtd", Iop_CmpGT32Sx4, False );
10468//.. goto decode_success;
10469//.. }
10470//..
10471//.. /* 66 0F 65 = PCMPGTW */
10472//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x65) {
10473//.. delta = dis_SSEint_E_to_G( sorb, delta+2,
10474//.. "pcmpgtw", Iop_CmpGT16Sx8, False );
10475//.. goto decode_success;
10476//.. }
10477//..
10478//.. /* 66 0F C5 = PEXTRW -- extract 16-bit field from xmm(E) and put
10479//.. zero-extend of it in ireg(G). */
10480//.. if (insn[0] == 0x0F && insn[1] == 0xC5) {
10481//.. modrm = insn[2];
10482//.. if (sz == 2 && epartIsReg(modrm)) {
10483//.. t5 = newTemp(Ity_V128);
10484//.. t4 = newTemp(Ity_I16);
10485//.. assign(t5, getXMMReg(eregOfRM(modrm)));
10486//.. breakup128to32s( t5, &t3, &t2, &t1, &t0 );
10487//.. switch (insn[3] & 7) {
10488//.. case 0: assign(t4, unop(Iop_32to16, mkexpr(t0))); break;
10489//.. case 1: assign(t4, unop(Iop_32HIto16, mkexpr(t0))); break;
10490//.. case 2: assign(t4, unop(Iop_32to16, mkexpr(t1))); break;
10491//.. case 3: assign(t4, unop(Iop_32HIto16, mkexpr(t1))); break;
10492//.. case 4: assign(t4, unop(Iop_32to16, mkexpr(t2))); break;
10493//.. case 5: assign(t4, unop(Iop_32HIto16, mkexpr(t2))); break;
10494//.. case 6: assign(t4, unop(Iop_32to16, mkexpr(t3))); break;
10495//.. case 7: assign(t4, unop(Iop_32HIto16, mkexpr(t3))); break;
10496//.. default: vassert(0);
10497//.. }
10498//.. putIReg(4, gregOfRM(modrm), unop(Iop_16Uto32, mkexpr(t4)));
10499//.. DIP("pextrw $%d,%s,%s\n",
10500//.. (Int)insn[3], nameXMMReg(eregOfRM(modrm)),
10501//.. nameIReg(4,gregOfRM(modrm)));
10502//.. delta += 4;
10503//.. goto decode_success;
10504//.. }
10505//.. /* else fall through */
10506//.. }
10507//..
10508//.. /* 66 0F C4 = PINSRW -- get 16 bits from E(mem or low half ireg) and
10509//.. put it into the specified lane of xmm(G). */
10510//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xC4) {
10511//.. Int lane;
10512//.. t4 = newTemp(Ity_I16);
10513//.. modrm = insn[2];
10514//..
10515//.. if (epartIsReg(modrm)) {
10516//.. assign(t4, getIReg(2, eregOfRM(modrm)));
10517//.. lane = insn[3];
10518//.. delta += 2+2;
10519//.. DIP("pinsrw $%d,%s,%s\n", (Int)lane,
10520//.. nameIReg(2,eregOfRM(modrm)),
10521//.. nameXMMReg(gregOfRM(modrm)));
10522//.. } else {
10523//.. /* awaiting test case */
10524//.. goto decode_failure;
10525//.. }
10526//..
10527//.. putXMMRegLane16( gregOfRM(modrm), lane & 7, mkexpr(t4) );
10528//.. goto decode_success;
10529//.. }
10530//..
10531//.. /* 66 0F EE = PMAXSW -- 16x8 signed max */
10532//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xEE) {
10533//.. delta = dis_SSEint_E_to_G( sorb, delta+2,
10534//.. "pmaxsw", Iop_Max16Sx8, False );
10535//.. goto decode_success;
10536//.. }
10537//..
10538//.. /* 66 0F DE = PMAXUB -- 8x16 unsigned max */
10539//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDE) {
10540//.. delta = dis_SSEint_E_to_G( sorb, delta+2,
10541//.. "pmaxub", Iop_Max8Ux16, False );
10542//.. goto decode_success;
10543//.. }
10544//..
10545//.. /* 66 0F EA = PMINSW -- 16x8 signed min */
10546//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xEA) {
10547//.. delta = dis_SSEint_E_to_G( sorb, delta+2,
10548//.. "pminsw", Iop_Min16Sx8, False );
10549//.. goto decode_success;
10550//.. }
10551//..
10552//.. /* 66 0F DA = PMINUB -- 8x16 unsigned min */
10553//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDA) {
10554//.. delta = dis_SSEint_E_to_G( sorb, delta+2,
10555//.. "pminub", Iop_Min8Ux16, False );
10556//.. goto decode_success;
10557//.. }
10558//..
10559//.. /* 66 0F D7 = PMOVMSKB -- extract sign bits from each of 16 lanes in
10560//.. xmm(G), turn them into a byte, and put zero-extend of it in
10561//.. ireg(G). Doing this directly is just too cumbersome; give up
10562//.. therefore and call a helper. */
10563//.. /* UInt x86g_calculate_sse_pmovmskb ( ULong w64hi, ULong w64lo ); */
10564//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD7) {
10565//.. modrm = insn[2];
10566//.. if (epartIsReg(modrm)) {
10567//.. t0 = newTemp(Ity_I64);
10568//.. t1 = newTemp(Ity_I64);
10569//.. assign(t0, getXMMRegLane64(eregOfRM(modrm), 0));
10570//.. assign(t1, getXMMRegLane64(eregOfRM(modrm), 1));
10571//.. t5 = newTemp(Ity_I32);
10572//.. assign(t5, mkIRExprCCall(
10573//.. Ity_I32, 0/*regparms*/,
10574//.. "x86g_calculate_sse_pmovmskb",
10575//.. &x86g_calculate_sse_pmovmskb,
10576//.. mkIRExprVec_2( mkexpr(t1), mkexpr(t0) )));
10577//.. putIReg(4, gregOfRM(modrm), mkexpr(t5));
10578//.. DIP("pmovmskb %s,%s\n", nameXMMReg(eregOfRM(modrm)),
10579//.. nameIReg(4,gregOfRM(modrm)));
10580//.. delta += 3;
10581//.. goto decode_success;
10582//.. }
10583//.. /* else fall through */
10584//.. }
10585//..
10586//.. /* 66 0F E4 = PMULHUW -- 16x8 hi-half of unsigned widening multiply */
10587//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE4) {
10588//.. delta = dis_SSEint_E_to_G( sorb, delta+2,
10589//.. "pmulhuw", Iop_MulHi16Ux8, False );
10590//.. goto decode_success;
10591//.. }
10592//..
10593//.. /* 66 0F E5 = PMULHW -- 16x8 hi-half of signed widening multiply */
10594//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE5) {
10595//.. delta = dis_SSEint_E_to_G( sorb, delta+2,
10596//.. "pmulhw", Iop_MulHi16Sx8, False );
10597//.. goto decode_success;
10598//.. }
10599//..
10600//.. /* 66 0F D5 = PMULHL -- 16x8 multiply */
10601//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD5) {
10602//.. delta = dis_SSEint_E_to_G( sorb, delta+2,
10603//.. "pmullw", Iop_Mul16x8, False );
10604//.. goto decode_success;
10605//.. }
10606//..
10607//.. /* ***--- this is an MMX class insn introduced in SSE2 ---*** */
10608//.. /* 0F F4 = PMULUDQ -- unsigned widening multiply of 32-lanes 0 x
10609//.. 0 to form 64-bit result */
10610//.. if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xF4) {
10611//.. IRTemp sV = newTemp(Ity_I64);
10612//.. IRTemp dV = newTemp(Ity_I64);
10613//.. t1 = newTemp(Ity_I32);
10614//.. t0 = newTemp(Ity_I32);
10615//.. modrm = insn[2];
10616//..
10617//.. do_MMX_preamble();
10618//.. assign( dV, getMMXReg(gregOfRM(modrm)) );
10619//..
10620//.. if (epartIsReg(modrm)) {
10621//.. assign( sV, getMMXReg(eregOfRM(modrm)) );
10622//.. delta += 2+1;
10623//.. DIP("pmuludq %s,%s\n", nameMMXReg(eregOfRM(modrm)),
10624//.. nameMMXReg(gregOfRM(modrm)));
10625//.. } else {
10626//.. addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10627//.. assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
10628//.. delta += 2+alen;
10629//.. DIP("pmuludq %s,%s\n", dis_buf,
10630//.. nameMMXReg(gregOfRM(modrm)));
10631//.. }
10632//..
10633//.. assign( t0, unop(Iop_64to32, mkexpr(dV)) );
10634//.. assign( t1, unop(Iop_64to32, mkexpr(sV)) );
10635//.. putMMXReg( gregOfRM(modrm),
10636//.. binop( Iop_MullU32, mkexpr(t0), mkexpr(t1) ) );
10637//.. goto decode_success;
10638//.. }
10639//..
10640//.. /* 66 0F F4 = PMULUDQ -- unsigned widening multiply of 32-lanes 0 x
10641//.. 0 to form lower 64-bit half and lanes 2 x 2 to form upper 64-bit
10642//.. half */
10643//.. /* This is a really poor translation -- could be improved if
10644//.. performance critical */
10645//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF4) {
10646//.. IRTemp sV, dV;
10647//.. IRTemp s3, s2, s1, s0, d3, d2, d1, d0;
10648//.. sV = newTemp(Ity_V128);
10649//.. dV = newTemp(Ity_V128);
10650//.. s3 = s2 = s1 = s0 = d3 = d2 = d1 = d0 = IRTemp_INVALID;
10651//.. t1 = newTemp(Ity_I64);
10652//.. t0 = newTemp(Ity_I64);
10653//.. modrm = insn[2];
10654//.. assign( dV, getXMMReg(gregOfRM(modrm)) );
10655//..
10656//.. if (epartIsReg(modrm)) {
10657//.. assign( sV, getXMMReg(eregOfRM(modrm)) );
10658//.. delta += 2+1;
10659//.. DIP("pmuludq %s,%s\n", nameXMMReg(eregOfRM(modrm)),
10660//.. nameXMMReg(gregOfRM(modrm)));
10661//.. } else {
10662//.. addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10663//.. assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
10664//.. delta += 2+alen;
10665//.. DIP("pmuludq %s,%s\n", dis_buf,
10666//.. nameXMMReg(gregOfRM(modrm)));
10667//.. }
10668//..
10669//.. breakup128to32s( dV, &d3, &d2, &d1, &d0 );
10670//.. breakup128to32s( sV, &s3, &s2, &s1, &s0 );
10671//..
10672//.. assign( t0, binop( Iop_MullU32, mkexpr(d0), mkexpr(s0)) );
10673//.. putXMMRegLane64( gregOfRM(modrm), 0, mkexpr(t0) );
10674//.. assign( t1, binop( Iop_MullU32, mkexpr(d2), mkexpr(s2)) );
10675//.. putXMMRegLane64( gregOfRM(modrm), 1, mkexpr(t1) );
10676//.. goto decode_success;
10677//.. }
10678//..
10679//.. /* 66 0F EB = POR */
10680//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xEB) {
10681//.. delta = dis_SSE_E_to_G_all( sorb, delta+2, "por", Iop_Or128 );
10682//.. goto decode_success;
10683//.. }
10684//..
10685//.. /* 66 0F 70 = PSHUFD -- rearrange 4x32 from E(xmm or mem) to G(xmm) */
10686//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x70) {
10687//.. Int order;
10688//.. IRTemp sV, dV, s3, s2, s1, s0;
10689//.. s3 = s2 = s1 = s0 = IRTemp_INVALID;
10690//.. sV = newTemp(Ity_V128);
10691//.. dV = newTemp(Ity_V128);
10692//.. modrm = insn[2];
10693//.. if (epartIsReg(modrm)) {
10694//.. assign( sV, getXMMReg(eregOfRM(modrm)) );
10695//.. order = (Int)insn[3];
10696//.. delta += 2+2;
10697//.. DIP("pshufd $%d,%s,%s\n", order,
10698//.. nameXMMReg(eregOfRM(modrm)),
10699//.. nameXMMReg(gregOfRM(modrm)));
10700//.. } else {
10701//.. addr = disAMode ( &alen, sorb, delta+2, dis_buf );
10702//.. assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
10703//.. order = (Int)insn[2+alen];
10704//.. delta += 3+alen;
10705//.. DIP("pshufd $%d,%s,%s\n", order,
10706//.. dis_buf,
10707//.. nameXMMReg(gregOfRM(modrm)));
10708//.. }
10709//.. breakup128to32s( sV, &s3, &s2, &s1, &s0 );
10710//..
10711//.. # define SEL(n) \
10712//.. ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
10713//.. assign(dV,
10714//.. mk128from32s( SEL((order>>6)&3), SEL((order>>4)&3),
10715//.. SEL((order>>2)&3), SEL((order>>0)&3) )
10716//.. );
10717//.. putXMMReg(gregOfRM(modrm), mkexpr(dV));
10718//.. # undef SEL
10719//.. goto decode_success;
10720//.. }
10721//..
10722//.. /* F3 0F 70 = PSHUFHW -- rearrange upper half 4x16 from E(xmm or
10723//.. mem) to G(xmm), and copy lower half */
10724//.. if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x70) {
10725//.. Int order;
10726//.. IRTemp sVhi, dVhi, sV, dV, s3, s2, s1, s0;
10727//.. s3 = s2 = s1 = s0 = IRTemp_INVALID;
10728//.. sV = newTemp(Ity_V128);
10729//.. dV = newTemp(Ity_V128);
10730//.. sVhi = newTemp(Ity_I64);
10731//.. dVhi = newTemp(Ity_I64);
10732//.. modrm = insn[3];
10733//.. if (epartIsReg(modrm)) {
10734//.. assign( sV, getXMMReg(eregOfRM(modrm)) );
10735//.. order = (Int)insn[4];
10736//.. delta += 4+1;
10737//.. DIP("pshufhw $%d,%s,%s\n", order,
10738//.. nameXMMReg(eregOfRM(modrm)),
10739//.. nameXMMReg(gregOfRM(modrm)));
10740//.. } else {
10741//.. addr = disAMode ( &alen, sorb, delta+3, dis_buf );
10742//.. assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
10743//.. order = (Int)insn[3+alen];
10744//.. delta += 4+alen;
10745//.. DIP("pshufhw $%d,%s,%s\n", order,
10746//.. dis_buf,
10747//.. nameXMMReg(gregOfRM(modrm)));
10748//.. }
10749//.. assign( sVhi, unop(Iop_128HIto64, mkexpr(sV)) );
10750//.. breakup64to16s( sVhi, &s3, &s2, &s1, &s0 );
10751//..
10752//.. # define SEL(n) \
10753//.. ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
10754//.. assign(dVhi,
10755//.. mk64from16s( SEL((order>>6)&3), SEL((order>>4)&3),
10756//.. SEL((order>>2)&3), SEL((order>>0)&3) )
10757//.. );
10758//.. assign(dV, binop( Iop_64HLto128,
10759//.. mkexpr(dVhi),
10760//.. unop(Iop_128to64, mkexpr(sV))) );
10761//.. putXMMReg(gregOfRM(modrm), mkexpr(dV));
10762//.. # undef SEL
10763//.. goto decode_success;
10764//.. }
10765//..
10766//.. /* F2 0F 70 = PSHUFLW -- rearrange lower half 4x16 from E(xmm or
10767//.. mem) to G(xmm), and copy upper half */
10768//.. if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x70) {
10769//.. Int order;
10770//.. IRTemp sVlo, dVlo, sV, dV, s3, s2, s1, s0;
10771//.. s3 = s2 = s1 = s0 = IRTemp_INVALID;
10772//.. sV = newTemp(Ity_V128);
10773//.. dV = newTemp(Ity_V128);
10774//.. sVlo = newTemp(Ity_I64);
10775//.. dVlo = newTemp(Ity_I64);
10776//.. modrm = insn[3];
10777//.. if (epartIsReg(modrm)) {
10778//.. assign( sV, getXMMReg(eregOfRM(modrm)) );
10779//.. order = (Int)insn[4];
10780//.. delta += 4+1;
10781//.. DIP("pshuflw $%d,%s,%s\n", order,
10782//.. nameXMMReg(eregOfRM(modrm)),
10783//.. nameXMMReg(gregOfRM(modrm)));
10784//.. } else {
10785//.. addr = disAMode ( &alen, sorb, delta+3, dis_buf );
10786//.. assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
10787//.. order = (Int)insn[3+alen];
10788//.. delta += 4+alen;
10789//.. DIP("pshuflw $%d,%s,%s\n", order,
10790//.. dis_buf,
10791//.. nameXMMReg(gregOfRM(modrm)));
10792//.. }
10793//.. assign( sVlo, unop(Iop_128to64, mkexpr(sV)) );
10794//.. breakup64to16s( sVlo, &s3, &s2, &s1, &s0 );
10795//..
10796//.. # define SEL(n) \
10797//.. ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
10798//.. assign(dVlo,
10799//.. mk64from16s( SEL((order>>6)&3), SEL((order>>4)&3),
10800//.. SEL((order>>2)&3), SEL((order>>0)&3) )
10801//.. );
10802//.. assign(dV, binop( Iop_64HLto128,
10803//.. unop(Iop_128HIto64, mkexpr(sV)),
10804//.. mkexpr(dVlo) ) );
10805//.. putXMMReg(gregOfRM(modrm), mkexpr(dV));
10806//.. # undef SEL
10807//.. goto decode_success;
10808//.. }
10809//..
10810//.. /* 66 0F 72 /6 ib = PSLLD by immediate */
10811//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x72
10812//.. && epartIsReg(insn[2])
10813//.. && gregOfRM(insn[2]) == 6) {
10814//.. delta = dis_SSE_shiftE_imm( delta+2, "pslld", Iop_ShlN32x4 );
10815//.. goto decode_success;
10816//.. }
10817//..
10818//.. /* 66 0F F2 = PSLLD by E */
10819//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF2) {
10820//.. delta = dis_SSE_shiftG_byE( sorb, delta+2, "pslld", Iop_ShlN32x4 );
10821//.. goto decode_success;
10822//.. }
10823//..
10824//.. /* 66 0F 73 /7 ib = PSLLDQ by immediate */
10825//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x73
10826//.. && epartIsReg(insn[2])
10827//.. && gregOfRM(insn[2]) == 7) {
10828//.. IRTemp sV, dV, hi64, lo64, hi64r, lo64r;
10829//.. Int imm = (Int)insn[3];
10830//.. Int reg = eregOfRM(insn[2]);
10831//.. DIP("pslldq $%d,%s\n", imm, nameXMMReg(reg));
10832//.. vassert(imm >= 0 && imm <= 255);
10833//.. delta += 4;
10834//..
10835//.. sV = newTemp(Ity_V128);
10836//.. dV = newTemp(Ity_V128);
10837//.. hi64 = newTemp(Ity_I64);
10838//.. lo64 = newTemp(Ity_I64);
10839//.. hi64r = newTemp(Ity_I64);
10840//.. lo64r = newTemp(Ity_I64);
10841//..
10842//.. if (imm >= 16) {
10843//.. vassert(0); /* awaiting test case */
10844//.. putXMMReg(reg, mkV128(0x0000));
10845//.. goto decode_success;
10846//.. }
10847//..
10848//.. assign( sV, getXMMReg(reg) );
10849//.. assign( hi64, unop(Iop_128HIto64, mkexpr(sV)) );
10850//.. assign( lo64, unop(Iop_128to64, mkexpr(sV)) );
10851//..
10852//.. if (imm == 8) {
10853//.. assign( lo64r, mkU64(0) );
10854//.. assign( hi64r, mkexpr(lo64) );
10855//.. }
10856//.. else
10857//.. if (imm > 8) {
10858//.. vassert(0); /* awaiting test case */
10859//.. assign( lo64r, mkU64(0) );
10860//.. assign( hi64r, binop( Iop_Shl64,
10861//.. mkexpr(lo64),
10862//.. mkU8( 8*(imm-8) ) ));
10863//.. } else {
10864//.. assign( lo64r, binop( Iop_Shl64,
10865//.. mkexpr(lo64),
10866//.. mkU8(8 * imm) ));
10867//.. assign( hi64r,
10868//.. binop( Iop_Or64,
10869//.. binop(Iop_Shl64, mkexpr(hi64),
10870//.. mkU8(8 * imm)),
10871//.. binop(Iop_Shr64, mkexpr(lo64),
10872//.. mkU8(8 * (8 - imm)) )
10873//.. )
10874//.. );
10875//.. }
10876//.. assign( dV, binop(Iop_64HLto128, mkexpr(hi64r), mkexpr(lo64r)) );
10877//.. putXMMReg(reg, mkexpr(dV));
10878//.. goto decode_success;
10879//.. }
10880//..
10881//.. /* 66 0F 73 /6 ib = PSLLQ by immediate */
10882//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x73
10883//.. && epartIsReg(insn[2])
10884//.. && gregOfRM(insn[2]) == 6) {
10885//.. delta = dis_SSE_shiftE_imm( delta+2, "psllq", Iop_ShlN64x2 );
10886//.. goto decode_success;
10887//.. }
10888//..
10889//.. /* 66 0F F3 = PSLLQ by E */
10890//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF3) {
10891//.. delta = dis_SSE_shiftG_byE( sorb, delta+2, "psllq", Iop_ShlN64x2 );
10892//.. goto decode_success;
10893//.. }
10894//..
10895//.. /* 66 0F 71 /6 ib = PSLLW by immediate */
10896//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x71
10897//.. && epartIsReg(insn[2])
10898//.. && gregOfRM(insn[2]) == 6) {
10899//.. delta = dis_SSE_shiftE_imm( delta+2, "psllw", Iop_ShlN16x8 );
10900//.. goto decode_success;
10901//.. }
10902//..
10903//.. /* 66 0F F1 = PSLLW by E */
10904//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF1) {
10905//.. delta = dis_SSE_shiftG_byE( sorb, delta+2, "psllw", Iop_ShlN16x8 );
10906//.. goto decode_success;
10907//.. }
10908//..
10909//.. /* 66 0F 72 /4 ib = PSRAD by immediate */
10910//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x72
10911//.. && epartIsReg(insn[2])
10912//.. && gregOfRM(insn[2]) == 4) {
10913//.. delta = dis_SSE_shiftE_imm( delta+2, "psrad", Iop_SarN32x4 );
10914//.. goto decode_success;
10915//.. }
10916//..
10917//.. /* 66 0F E2 = PSRAD by E */
10918//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE2) {
10919//.. delta = dis_SSE_shiftG_byE( sorb, delta+2, "psrad", Iop_SarN32x4 );
10920//.. goto decode_success;
10921//.. }
10922//..
10923//.. /* 66 0F 71 /4 ib = PSRAW by immediate */
10924//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x71
10925//.. && epartIsReg(insn[2])
10926//.. && gregOfRM(insn[2]) == 4) {
10927//.. delta = dis_SSE_shiftE_imm( delta+2, "psraw", Iop_SarN16x8 );
10928//.. goto decode_success;
10929//.. }
10930//..
10931//.. /* 66 0F E1 = PSRAW by E */
10932//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE1) {
10933//.. delta = dis_SSE_shiftG_byE( sorb, delta+2, "psraw", Iop_SarN16x8 );
10934//.. goto decode_success;
10935//.. }
10936//..
10937//.. /* 66 0F 72 /2 ib = PSRLD by immediate */
10938//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x72
10939//.. && epartIsReg(insn[2])
10940//.. && gregOfRM(insn[2]) == 2) {
10941//.. delta = dis_SSE_shiftE_imm( delta+2, "psrld", Iop_ShrN32x4 );
10942//.. goto decode_success;
10943//.. }
10944//..
10945//.. /* 66 0F D2 = PSRLD by E */
10946//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD2) {
10947//.. delta = dis_SSE_shiftG_byE( sorb, delta+2, "psrld", Iop_ShrN32x4 );
10948//.. goto decode_success;
10949//.. }
10950//..
10951//.. /* 66 0F 73 /3 ib = PSRLDQ by immediate */
10952//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x73
10953//.. && epartIsReg(insn[2])
10954//.. && gregOfRM(insn[2]) == 3) {
10955//.. IRTemp sV, dV, hi64, lo64, hi64r, lo64r;
10956//.. Int imm = (Int)insn[3];
10957//.. Int reg = eregOfRM(insn[2]);
10958//.. DIP("psrldq $%d,%s\n", imm, nameXMMReg(reg));
10959//.. vassert(imm >= 0 && imm <= 255);
10960//.. delta += 4;
10961//..
10962//.. sV = newTemp(Ity_V128);
10963//.. dV = newTemp(Ity_V128);
10964//.. hi64 = newTemp(Ity_I64);
10965//.. lo64 = newTemp(Ity_I64);
10966//.. hi64r = newTemp(Ity_I64);
10967//.. lo64r = newTemp(Ity_I64);
10968//..
10969//.. if (imm >= 16) {
10970//.. vassert(0); /* awaiting test case */
10971//.. putXMMReg(reg, mkV128(0x0000));
10972//.. goto decode_success;
10973//.. }
10974//..
10975//.. assign( sV, getXMMReg(reg) );
10976//.. assign( hi64, unop(Iop_128HIto64, mkexpr(sV)) );
10977//.. assign( lo64, unop(Iop_128to64, mkexpr(sV)) );
10978//..
10979//.. if (imm == 8) {
10980//.. assign( hi64r, mkU64(0) );
10981//.. assign( lo64r, mkexpr(hi64) );
10982//.. }
10983//.. else
10984//.. if (imm > 8) {
10985//.. vassert(0); /* awaiting test case */
10986//.. assign( hi64r, mkU64(0) );
10987//.. assign( lo64r, binop( Iop_Shr64,
10988//.. mkexpr(hi64),
10989//.. mkU8( 8*(imm-8) ) ));
10990//.. } else {
10991//.. assign( hi64r, binop( Iop_Shr64,
10992//.. mkexpr(hi64),
10993//.. mkU8(8 * imm) ));
10994//.. assign( lo64r,
10995//.. binop( Iop_Or64,
10996//.. binop(Iop_Shr64, mkexpr(lo64),
10997//.. mkU8(8 * imm)),
10998//.. binop(Iop_Shl64, mkexpr(hi64),
10999//.. mkU8(8 * (8 - imm)) )
11000//.. )
11001//.. );
11002//.. }
11003//..
11004//.. assign( dV, binop(Iop_64HLto128, mkexpr(hi64r), mkexpr(lo64r)) );
11005//.. putXMMReg(reg, mkexpr(dV));
11006//.. goto decode_success;
11007//.. }
11008//..
11009//.. /* 66 0F 73 /2 ib = PSRLQ by immediate */
11010//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x73
11011//.. && epartIsReg(insn[2])
11012//.. && gregOfRM(insn[2]) == 2) {
11013//.. delta = dis_SSE_shiftE_imm( delta+2, "psrlq", Iop_ShrN64x2 );
11014//.. goto decode_success;
11015//.. }
11016//..
11017//.. /* 66 0F D3 = PSRLQ by E */
11018//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD3) {
11019//.. delta = dis_SSE_shiftG_byE( sorb, delta+2, "psrlq", Iop_ShrN64x2 );
11020//.. goto decode_success;
11021//.. }
11022//..
11023//.. /* 66 0F 71 /2 ib = PSRLW by immediate */
11024//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x71
11025//.. && epartIsReg(insn[2])
11026//.. && gregOfRM(insn[2]) == 2) {
11027//.. delta = dis_SSE_shiftE_imm( delta+2, "psrlw", Iop_ShrN16x8 );
11028//.. goto decode_success;
11029//.. }
11030//..
11031//.. /* 66 0F D1 = PSRLW by E */
11032//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD1) {
11033//.. delta = dis_SSE_shiftG_byE( sorb, delta+2, "psrlw", Iop_ShrN16x8 );
11034//.. goto decode_success;
11035//.. }
11036//..
11037//.. /* 66 0F F8 = PSUBB */
11038//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF8) {
11039//.. delta = dis_SSEint_E_to_G( sorb, delta+2,
11040//.. "psubb", Iop_Sub8x16, False );
11041//.. goto decode_success;
11042//.. }
11043//..
11044//.. /* 66 0F FA = PSUBD */
11045//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xFA) {
11046//.. delta = dis_SSEint_E_to_G( sorb, delta+2,
11047//.. "psubd", Iop_Sub32x4, False );
11048//.. goto decode_success;
11049//.. }
11050//..
11051//.. /* ***--- this is an MMX class insn introduced in SSE2 ---*** */
11052//.. /* 0F FB = PSUBQ -- sub 64x1 */
11053//.. if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xFB) {
11054//.. do_MMX_preamble();
11055//.. delta = dis_MMXop_regmem_to_reg (
11056//.. sorb, delta+2, insn[1], "psubq", False );
11057//.. goto decode_success;
11058//.. }
11059//..
11060//.. /* 66 0F FB = PSUBQ */
11061//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xFB) {
11062//.. delta = dis_SSEint_E_to_G( sorb, delta+2,
11063//.. "psubq", Iop_Sub64x2, False );
11064//.. goto decode_success;
11065//.. }
11066//..
11067//.. /* 66 0F F9 = PSUBW */
11068//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF9) {
11069//.. delta = dis_SSEint_E_to_G( sorb, delta+2,
11070//.. "psubw", Iop_Sub16x8, False );
11071//.. goto decode_success;
11072//.. }
11073//..
11074//.. /* 66 0F E8 = PSUBSB */
11075//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE8) {
11076//.. delta = dis_SSEint_E_to_G( sorb, delta+2,
11077//.. "psubsb", Iop_QSub8Sx16, False );
11078//.. goto decode_success;
11079//.. }
11080//..
11081//.. /* 66 0F E9 = PSUBSW */
11082//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE9) {
11083//.. delta = dis_SSEint_E_to_G( sorb, delta+2,
11084//.. "psubsw", Iop_QSub16Sx8, False );
11085//.. goto decode_success;
11086//.. }
11087//..
11088//.. /* 66 0F D8 = PSUBSB */
11089//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD8) {
11090//.. delta = dis_SSEint_E_to_G( sorb, delta+2,
11091//.. "psubusb", Iop_QSub8Ux16, False );
11092//.. goto decode_success;
11093//.. }
11094//..
11095//.. /* 66 0F D9 = PSUBSW */
11096//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD9) {
11097//.. delta = dis_SSEint_E_to_G( sorb, delta+2,
11098//.. "psubusw", Iop_QSub16Ux8, False );
11099//.. goto decode_success;
11100//.. }
11101//..
11102//.. /* 66 0F 68 = PUNPCKHBW */
11103//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x68) {
11104//.. delta = dis_SSEint_E_to_G( sorb, delta+2,
11105//.. "punpckhbw",
11106//.. Iop_InterleaveHI8x16, True );
11107//.. goto decode_success;
11108//.. }
11109//..
11110//.. /* 66 0F 6A = PUNPCKHDQ */
11111//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x6A) {
11112//.. delta = dis_SSEint_E_to_G( sorb, delta+2,
11113//.. "punpckhdq",
11114//.. Iop_InterleaveHI32x4, True );
11115//.. goto decode_success;
11116//.. }
11117//..
11118//.. /* 66 0F 6D = PUNPCKHQDQ */
11119//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x6D) {
11120//.. delta = dis_SSEint_E_to_G( sorb, delta+2,
11121//.. "punpckhqdq",
11122//.. Iop_InterleaveHI64x2, True );
11123//.. goto decode_success;
11124//.. }
11125//..
11126//.. /* 66 0F 69 = PUNPCKHWD */
11127//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x69) {
11128//.. delta = dis_SSEint_E_to_G( sorb, delta+2,
11129//.. "punpckhwd",
11130//.. Iop_InterleaveHI16x8, True );
11131//.. goto decode_success;
11132//.. }
11133//..
11134//.. /* 66 0F 60 = PUNPCKLBW */
11135//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x60) {
11136//.. delta = dis_SSEint_E_to_G( sorb, delta+2,
11137//.. "punpcklbw",
11138//.. Iop_InterleaveLO8x16, True );
11139//.. goto decode_success;
11140//.. }
11141//..
11142//.. /* 66 0F 62 = PUNPCKLDQ */
11143//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x62) {
11144//.. delta = dis_SSEint_E_to_G( sorb, delta+2,
11145//.. "punpckldq",
11146//.. Iop_InterleaveLO32x4, True );
11147//.. goto decode_success;
11148//.. }
11149//..
11150//.. /* 66 0F 6C = PUNPCKLQDQ */
11151//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x6C) {
11152//.. delta = dis_SSEint_E_to_G( sorb, delta+2,
11153//.. "punpcklqdq",
11154//.. Iop_InterleaveLO64x2, True );
11155//.. goto decode_success;
11156//.. }
11157//..
11158//.. /* 66 0F 61 = PUNPCKLWD */
11159//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x61) {
11160//.. delta = dis_SSEint_E_to_G( sorb, delta+2,
11161//.. "punpcklwd",
11162//.. Iop_InterleaveLO16x8, True );
11163//.. goto decode_success;
11164//.. }
11165//..
11166//.. /* 66 0F EF = PXOR */
11167//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xEF) {
11168//.. delta = dis_SSE_E_to_G_all( sorb, delta+2, "pxor", Iop_Xor128 );
11169//.. goto decode_success;
11170//.. }
11171//..
11172//..
11173//.. //-- /* FXSAVE/FXRSTOR m32 -- load/store the FPU/MMX/SSE state. */
11174//.. //-- if (insn[0] == 0x0F && insn[1] == 0xAE
11175//.. //-- && (!epartIsReg(insn[2]))
11176//.. //-- && (gregOfRM(insn[2]) == 1 || gregOfRM(insn[2]) == 0) ) {
11177//.. //-- Bool store = gregOfRM(insn[2]) == 0;
11178//.. //-- vg_assert(sz == 4);
11179//.. //-- pair = disAMode ( cb, sorb, eip+2, dis_buf );
11180//.. //-- t1 = LOW24(pair);
11181//.. //-- eip += 2+HI8(pair);
11182//.. //-- uInstr3(cb, store ? SSE2a_MemWr : SSE2a_MemRd, 512,
11183//.. //-- Lit16, (((UShort)insn[0]) << 8) | (UShort)insn[1],
11184//.. //-- Lit16, (UShort)insn[2],
11185//.. //-- TempReg, t1 );
11186//.. //-- DIP("fx%s %s\n", store ? "save" : "rstor", dis_buf );
11187//.. //-- goto decode_success;
11188//.. //-- }
11189//.. //--
11190//.. //-- /* CLFLUSH -- flush cache line */
11191//.. //-- if (insn[0] == 0x0F && insn[1] == 0xAE
11192//.. //-- && (!epartIsReg(insn[2]))
11193//.. //-- && (gregOfRM(insn[2]) == 7))
11194//.. //-- {
11195//.. //-- vg_assert(sz == 4);
11196//.. //-- pair = disAMode ( cb, sorb, eip+2, dis_buf );
11197//.. //-- t1 = LOW24(pair);
11198//.. //-- eip += 2+HI8(pair);
11199//.. //-- uInstr3(cb, SSE2a_MemRd, 0, /* ignore sz for internal ops */
11200//.. //-- Lit16, (((UShort)0x0F) << 8) | (UShort)0xAE,
11201//.. //-- Lit16, (UShort)insn[2],
11202//.. //-- TempReg, t1 );
11203//.. //-- DIP("clflush %s\n", dis_buf);
11204//.. //-- goto decode_success;
11205//.. //-- }
sewardjdf0e0022005-01-25 15:48:43 +000011206
11207
11208 /* ---------------------------------------------------- */
11209 /* --- end of the SSE/SSE2 decoder. --- */
11210 /* ---------------------------------------------------- */
11211
sewardj7a240552005-01-28 21:37:12 +000011212 /*after_sse_decoders:*/
sewardjdf0e0022005-01-25 15:48:43 +000011213
11214 /* Get the primary opcode. */
sewardj8c332e22005-01-28 01:36:56 +000011215 opc = getUChar(delta); delta++;
sewardjdf0e0022005-01-25 15:48:43 +000011216
11217 /* We get here if the current insn isn't SSE, or this CPU doesn't
11218 support SSE. */
11219
11220 switch (opc) {
11221
11222 /* ------------------------ Control flow --------------- */
11223
sewardjd20c8852005-01-20 20:04:07 +000011224//.. case 0xC2: /* RET imm16 */
11225//.. d32 = getUDisp16(delta);
11226//.. delta += 2;
11227//.. dis_ret(d32);
11228//.. whatNext = Dis_StopHere;
11229//.. DIP("ret %d\n", d32);
11230//.. break;
sewardj2f959cc2005-01-26 01:19:35 +000011231 case 0xC3: /* RET */
sewardj55dbb262005-01-28 16:36:51 +000011232 if (haveF2(pfx)) goto decode_failure;
11233 /* F3 is acceptable on AMD. */
sewardj2f959cc2005-01-26 01:19:35 +000011234 dis_ret(0);
11235 whatNext = Dis_StopHere;
sewardje941eea2005-01-30 19:52:28 +000011236 DIP(haveF3(pfx) ? "rep ; ret\n" : "ret\n");
sewardj2f959cc2005-01-26 01:19:35 +000011237 break;
11238
sewardj3ca55a12005-01-27 16:06:23 +000011239 case 0xE8: /* CALL J4 */
11240 if (haveF2orF3(pfx)) goto decode_failure;
11241 d64 = getSDisp32(delta); delta += 4;
11242 d64 += (guest_rip_bbstart+delta);
11243 /* (guest_rip_bbstart+delta) == return-to addr, d64 == call-to addr */
11244 t1 = newTemp(Ity_I64);
11245 assign(t1, binop(Iop_Sub64, getIReg64(R_RSP), mkU64(8)));
11246 putIReg64(R_RSP, mkexpr(t1));
11247 storeLE( mkexpr(t1), mkU64(guest_rip_bbstart+delta));
11248 if (resteerOK && resteerOkFn((Addr64)d64)) {
11249 /* follow into the call target. */
11250 whatNext = Dis_Resteer;
11251 *whereNext = d64;
11252 } else {
11253 jmp_lit(Ijk_Call,d64);
11254 whatNext = Dis_StopHere;
11255 }
11256 DIP("call 0x%llx\n",d64);
11257 break;
11258
sewardjd20c8852005-01-20 20:04:07 +000011259//.. //-- case 0xC8: /* ENTER */
11260//.. //-- d32 = getUDisp16(eip); eip += 2;
sewardj8c332e22005-01-28 01:36:56 +000011261//.. //-- abyte = getUChar(delta); delta++;
sewardjd20c8852005-01-20 20:04:07 +000011262//.. //--
11263//.. //-- vg_assert(sz == 4);
11264//.. //-- vg_assert(abyte == 0);
11265//.. //--
11266//.. //-- t1 = newTemp(cb); t2 = newTemp(cb);
11267//.. //-- uInstr2(cb, GET, sz, ArchReg, R_EBP, TempReg, t1);
11268//.. //-- uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t2);
11269//.. //-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
11270//.. //-- uLiteral(cb, sz);
11271//.. //-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
11272//.. //-- uInstr2(cb, STORE, 4, TempReg, t1, TempReg, t2);
11273//.. //-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_EBP);
11274//.. //-- if (d32) {
11275//.. //-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
11276//.. //-- uLiteral(cb, d32);
11277//.. //-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
11278//.. //-- }
11279//.. //-- DIP("enter 0x%x, 0x%x", d32, abyte);
11280//.. //-- break;
sewardje1698952005-02-08 15:02:39 +000011281
11282 case 0xC9: /* LEAVE */
11283 /* In 64-bit mode this defaults to a 64-bit operand size. There
11284 is no way to encode a 32-bit variant. Hence sz==4 but we do
11285 it as if sz=8. */
11286 if (sz != 4)
11287 goto decode_failure;
11288 t1 = newTemp(Ity_I64);
11289 t2 = newTemp(Ity_I64);
11290 assign(t1, getIReg64(R_RBP));
11291 /* First PUT RSP looks redundant, but need it because RSP must
11292 always be up-to-date for Memcheck to work... */
11293 putIReg64(R_RSP, mkexpr(t1));
11294 assign(t2, loadLE(Ity_I64,mkexpr(t1)));
11295 putIReg64(R_RBP, mkexpr(t2));
11296 putIReg64(R_RSP, binop(Iop_Add64, mkexpr(t1), mkU64(8)) );
11297 DIP("leave\n");
11298 break;
11299
sewardjd20c8852005-01-20 20:04:07 +000011300//.. //-- /* ---------------- Misc weird-ass insns --------------- */
11301//.. //--
11302//.. //-- case 0x27: /* DAA */
11303//.. //-- case 0x2F: /* DAS */
11304//.. //-- t1 = newTemp(cb);
11305//.. //-- uInstr2(cb, GET, 1, ArchReg, R_AL, TempReg, t1);
11306//.. //-- /* Widen %AL to 32 bits, so it's all defined when we push it. */
11307//.. //-- uInstr1(cb, WIDEN, 4, TempReg, t1);
11308//.. //-- uWiden(cb, 1, False);
11309//.. //-- uInstr0(cb, CALLM_S, 0);
11310//.. //-- uInstr1(cb, PUSH, 4, TempReg, t1);
11311//.. //-- uInstr1(cb, CALLM, 0, Lit16,
11312//.. //-- opc == 0x27 ? VGOFF_(helper_DAA) : VGOFF_(helper_DAS) );
11313//.. //-- uFlagsRWU(cb, FlagsAC, FlagsSZACP, FlagO);
11314//.. //-- uInstr1(cb, POP, 4, TempReg, t1);
11315//.. //-- uInstr0(cb, CALLM_E, 0);
11316//.. //-- uInstr2(cb, PUT, 1, TempReg, t1, ArchReg, R_AL);
11317//.. //-- DIP(opc == 0x27 ? "daa\n" : "das\n");
11318//.. //-- break;
11319//.. //--
11320//.. //-- case 0x37: /* AAA */
11321//.. //-- case 0x3F: /* AAS */
11322//.. //-- t1 = newTemp(cb);
11323//.. //-- uInstr2(cb, GET, 2, ArchReg, R_EAX, TempReg, t1);
11324//.. //-- /* Widen %AL to 32 bits, so it's all defined when we push it. */
11325//.. //-- uInstr1(cb, WIDEN, 4, TempReg, t1);
11326//.. //-- uWiden(cb, 2, False);
11327//.. //-- uInstr0(cb, CALLM_S, 0);
11328//.. //-- uInstr1(cb, PUSH, 4, TempReg, t1);
11329//.. //-- uInstr1(cb, CALLM, 0, Lit16,
11330//.. //-- opc == 0x37 ? VGOFF_(helper_AAA) : VGOFF_(helper_AAS) );
11331//.. //-- uFlagsRWU(cb, FlagA, FlagsAC, FlagsEmpty);
11332//.. //-- uInstr1(cb, POP, 4, TempReg, t1);
11333//.. //-- uInstr0(cb, CALLM_E, 0);
11334//.. //-- uInstr2(cb, PUT, 2, TempReg, t1, ArchReg, R_EAX);
11335//.. //-- DIP(opc == 0x37 ? "aaa\n" : "aas\n");
11336//.. //-- break;
11337//.. //--
11338//.. //-- case 0xD4: /* AAM */
11339//.. //-- case 0xD5: /* AAD */
sewardj8c332e22005-01-28 01:36:56 +000011340//.. //-- d32 = getUChar(delta); delta++;
sewardjd20c8852005-01-20 20:04:07 +000011341//.. //-- if (d32 != 10) VG_(core_panic)("disInstr: AAM/AAD but base not 10 !");
11342//.. //-- t1 = newTemp(cb);
11343//.. //-- uInstr2(cb, GET, 2, ArchReg, R_EAX, TempReg, t1);
11344//.. //-- /* Widen %AX to 32 bits, so it's all defined when we push it. */
11345//.. //-- uInstr1(cb, WIDEN, 4, TempReg, t1);
11346//.. //-- uWiden(cb, 2, False);
11347//.. //-- uInstr0(cb, CALLM_S, 0);
11348//.. //-- uInstr1(cb, PUSH, 4, TempReg, t1);
11349//.. //-- uInstr1(cb, CALLM, 0, Lit16,
11350//.. //-- opc == 0xD4 ? VGOFF_(helper_AAM) : VGOFF_(helper_AAD) );
11351//.. //-- uFlagsRWU(cb, FlagsEmpty, FlagsSZP, FlagsEmpty);
11352//.. //-- uInstr1(cb, POP, 4, TempReg, t1);
11353//.. //-- uInstr0(cb, CALLM_E, 0);
11354//.. //-- uInstr2(cb, PUT, 2, TempReg, t1, ArchReg, R_EAX);
11355//.. //-- DIP(opc == 0xD4 ? "aam\n" : "aad\n");
11356//.. //-- break;
sewardj3ca55a12005-01-27 16:06:23 +000011357
11358 /* ------------------------ CWD/CDQ -------------------- */
11359
11360 case 0x98: /* CBW */
11361 if (haveF2orF3(pfx)) goto decode_failure;
11362 if (sz == 8) {
sewardj5b470602005-02-27 13:10:48 +000011363 putIRegRAX( 8, unop(Iop_32Sto64, getIRegRAX(4)) );
sewardje941eea2005-01-30 19:52:28 +000011364 DIP(/*"cdqe\n"*/"cltq");
11365 break;
11366 }
sewardj3ca55a12005-01-27 16:06:23 +000011367 if (sz == 4) {
sewardj5b470602005-02-27 13:10:48 +000011368 putIRegRAX( 4, unop(Iop_16Sto32, getIRegRAX(2)) );
sewardj7eaa7cf2005-01-31 18:55:22 +000011369 DIP("cwtl\n");
sewardje941eea2005-01-30 19:52:28 +000011370 break;
11371 }
sewardj3ca55a12005-01-27 16:06:23 +000011372 if (sz == 2) {
11373 vassert(sz == 2);
sewardj5b470602005-02-27 13:10:48 +000011374 putIRegRAX( 2, unop(Iop_8Sto16, getIRegRAX(1)) );
sewardj3ca55a12005-01-27 16:06:23 +000011375 DIP("cbw\n");
11376 }
sewardje941eea2005-01-30 19:52:28 +000011377 goto decode_failure;
sewardj3ca55a12005-01-27 16:06:23 +000011378
11379 case 0x99: /* CWD/CDQ/CQO */
11380 if (haveF2orF3(pfx)) goto decode_failure;
11381 vassert(sz == 2 || sz == 4 || sz == 8);
11382 ty = szToITy(sz);
sewardj5b470602005-02-27 13:10:48 +000011383 putIRegRDX( sz,
11384 binop(mkSizedOp(ty,Iop_Sar8),
11385 getIRegRAX(sz),
11386 mkU8(sz == 2 ? 15 : (sz == 4 ? 31 : 63))) );
sewardje941eea2005-01-30 19:52:28 +000011387 DIP(sz == 2 ? "cwd\n"
sewardj5b470602005-02-27 13:10:48 +000011388 : (sz == 4 ? /*"cdq\n"*/ "cltd\n"
11389 : "cqo\n"));
sewardj3ca55a12005-01-27 16:06:23 +000011390 break;
11391
sewardj8d965312005-02-25 02:48:47 +000011392 /* ------------------------ FPU ops -------------------- */
11393
sewardjd20c8852005-01-20 20:04:07 +000011394//.. case 0x9E: /* SAHF */
11395//.. codegen_SAHF();
11396//.. DIP("sahf\n");
11397//.. break;
11398//..
11399//.. //-- case 0x9F: /* LAHF */
11400//.. //-- codegen_LAHF ( cb );
11401//.. //-- DIP("lahf\n");
11402//.. //-- break;
11403//.. //--
11404//.. case 0x9B: /* FWAIT */
11405//.. /* ignore? */
11406//.. DIP("fwait\n");
11407//.. break;
sewardj8d965312005-02-25 02:48:47 +000011408
11409 case 0xD8:
11410 case 0xD9:
11411 case 0xDA:
11412 case 0xDB:
11413 case 0xDC:
11414 case 0xDD:
11415 case 0xDE:
11416 case 0xDF:
sewardj5b470602005-02-27 13:10:48 +000011417 if (haveF2orF3(pfx)) goto decode_failure;
sewardj8d965312005-02-25 02:48:47 +000011418 if (sz == 4 && haveNo66noF2noF3(pfx)) {
11419 ULong delta0 = delta;
11420 Bool decode_OK = False;
11421 delta = dis_FPU ( &decode_OK, pfx, delta );
11422 if (!decode_OK) {
11423 delta = delta0;
11424 goto decode_failure;
11425 }
11426 break;
11427 } else {
11428 goto decode_failure;
11429 }
11430
sewardjd20c8852005-01-20 20:04:07 +000011431//.. /* ------------------------ INC & DEC ------------------ */
11432//..
11433//.. case 0x40: /* INC eAX */
11434//.. case 0x41: /* INC eCX */
11435//.. case 0x42: /* INC eDX */
11436//.. case 0x43: /* INC eBX */
11437//.. case 0x44: /* INC eSP */
11438//.. case 0x45: /* INC eBP */
11439//.. case 0x46: /* INC eSI */
11440//.. case 0x47: /* INC eDI */
11441//.. vassert(sz == 2 || sz == 4);
11442//.. ty = szToITy(sz);
11443//.. t1 = newTemp(ty);
11444//.. assign( t1, binop(mkSizedOp(ty,Iop_Add8),
11445//.. getIReg(sz, (UInt)(opc - 0x40)),
11446//.. mkU(ty,1)) );
11447//.. setFlags_INC_DEC( True, t1, ty );
11448//.. putIReg(sz, (UInt)(opc - 0x40), mkexpr(t1));
11449//.. DIP("inc%c %s\n", nameISize(sz), nameIReg(sz,opc-0x40));
11450//.. break;
11451//..
11452//.. case 0x48: /* DEC eAX */
11453//.. case 0x49: /* DEC eCX */
11454//.. case 0x4A: /* DEC eDX */
11455//.. case 0x4B: /* DEC eBX */
11456//.. case 0x4C: /* DEC eSP */
11457//.. case 0x4D: /* DEC eBP */
11458//.. case 0x4E: /* DEC eSI */
11459//.. case 0x4F: /* DEC eDI */
11460//.. vassert(sz == 2 || sz == 4);
11461//.. ty = szToITy(sz);
11462//.. t1 = newTemp(ty);
11463//.. assign( t1, binop(mkSizedOp(ty,Iop_Sub8),
11464//.. getIReg(sz, (UInt)(opc - 0x48)),
11465//.. mkU(ty,1)) );
11466//.. setFlags_INC_DEC( False, t1, ty );
11467//.. putIReg(sz, (UInt)(opc - 0x48), mkexpr(t1));
11468//.. DIP("dec%c %s\n", nameISize(sz), nameIReg(sz,opc-0x48));
11469//.. break;
sewardjf8c37f72005-02-07 18:55:29 +000011470
11471 /* ------------------------ Jcond, byte offset --------- */
11472
11473 case 0xEB: /* Jb (jump, byte offset) */
sewardj5b470602005-02-27 13:10:48 +000011474 if (haveF2orF3(pfx)) goto decode_failure;
sewardjf8c37f72005-02-07 18:55:29 +000011475 if (sz != 4)
11476 goto decode_failure; /* JRS added 2004 July 11 */
11477 d64 = (guest_rip_bbstart+delta+1) + getSDisp8(delta);
11478 delta++;
11479 if (resteerOK && resteerOkFn(d64)) {
11480 whatNext = Dis_Resteer;
11481 *whereNext = d64;
11482 } else {
11483 jmp_lit(Ijk_Boring,d64);
11484 whatNext = Dis_StopHere;
11485 }
11486 DIP("jmp-8 0x%llx\n", d64);
11487 break;
sewardj1389d4d2005-01-28 13:46:29 +000011488
11489 case 0xE9: /* Jv (jump, 16/32 offset) */
sewardj5b470602005-02-27 13:10:48 +000011490 if (haveF2orF3(pfx)) goto decode_failure;
sewardjf8c37f72005-02-07 18:55:29 +000011491 if (sz != 4)
11492 goto decode_failure; /* JRS added 2004 July 11 */
sewardj1389d4d2005-01-28 13:46:29 +000011493 d64 = (guest_rip_bbstart+delta+sz) + getSDisp(sz,delta);
11494 delta += sz;
11495 if (resteerOK && resteerOkFn(d64)) {
11496 whatNext = Dis_Resteer;
11497 *whereNext = d64;
11498 } else {
11499 jmp_lit(Ijk_Boring,d64);
11500 whatNext = Dis_StopHere;
11501 }
11502 DIP("jmp 0x%llx\n", d64);
11503 break;
11504
sewardjf8c37f72005-02-07 18:55:29 +000011505 case 0x70:
11506 case 0x71:
11507 case 0x72: /* JBb/JNAEb (jump below) */
11508 case 0x73: /* JNBb/JAEb (jump not below) */
11509 case 0x74: /* JZb/JEb (jump zero) */
11510 case 0x75: /* JNZb/JNEb (jump not zero) */
11511 case 0x76: /* JBEb/JNAb (jump below or equal) */
11512 case 0x77: /* JNBEb/JAb (jump not below or equal) */
11513 case 0x78: /* JSb (jump negative) */
11514 case 0x79: /* JSb (jump not negative) */
11515 case 0x7A: /* JP (jump parity even) */
11516 case 0x7B: /* JNP/JPO (jump parity odd) */
11517 case 0x7C: /* JLb/JNGEb (jump less) */
11518 case 0x7D: /* JGEb/JNLb (jump greater or equal) */
11519 case 0x7E: /* JLEb/JNGb (jump less or equal) */
11520 case 0x7F: /* JGb/JNLEb (jump greater) */
sewardj5b470602005-02-27 13:10:48 +000011521 if (haveF2orF3(pfx)) goto decode_failure;
sewardjf8c37f72005-02-07 18:55:29 +000011522 d64 = (guest_rip_bbstart+delta+1) + getSDisp8(delta);
11523 delta++;
11524 jcc_01( (AMD64Condcode)(opc - 0x70),
11525 guest_rip_bbstart+delta,
11526 d64 );
11527 whatNext = Dis_StopHere;
11528 DIP("j%s-8 0x%llx\n", name_AMD64Condcode(opc - 0x70), d64);
11529 break;
11530
sewardjd20c8852005-01-20 20:04:07 +000011531//.. case 0xE3: /* JECXZ or perhaps JCXZ, depending on OSO ? Intel
11532//.. manual says it depends on address size override,
11533//.. which doesn't sound right to me. */
11534//.. vassert(sz==4); /* possibly also OK for sz==2 */
11535//.. d32 = (((Addr32)guest_eip_bbstart)+delta+1) + getSDisp8(delta);
11536//.. delta++;
11537//.. ty = szToITy(sz);
11538//.. stmt( IRStmt_Exit(
11539//.. binop(mkSizedOp(ty,Iop_CmpEQ8),
11540//.. getIReg(sz,R_ECX),
11541//.. mkU(ty,0)),
11542//.. Ijk_Boring,
11543//.. IRConst_U32(d32))
11544//.. );
11545//..
11546//.. DIP("j%sz 0x%x\n", nameIReg(sz, R_ECX), d32);
11547//.. break;
11548//..
11549//.. //-- case 0xE0: /* LOOPNE disp8 */
11550//.. //-- case 0xE1: /* LOOPE disp8 */
11551//.. //-- case 0xE2: /* LOOP disp8 */
11552//.. //-- /* Again, the docs say this uses ECX/CX as a count depending on
11553//.. //-- the address size override, not the operand one. Since we
11554//.. //-- don't handle address size overrides, I guess that means
11555//.. //-- ECX. */
11556//.. //-- d32 = (eip+1) + getSDisp8(eip); eip++;
11557//.. //-- t1 = newTemp(cb);
11558//.. //-- uInstr2(cb, GET, 4, ArchReg, R_ECX, TempReg, t1);
11559//.. //-- uInstr1(cb, DEC, 4, TempReg, t1);
11560//.. //-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_ECX);
11561//.. //-- uInstr2(cb, JIFZ, 4, TempReg, t1, Literal, 0);
11562//.. //-- uLiteral(cb, eip);
11563//.. //-- if (opc == 0xE0 || opc == 0xE1) { /* LOOPE/LOOPNE */
11564//.. //-- jcc_lit(cb, eip, (opc == 0xE1 ? CondNZ : CondZ));
11565//.. //-- }
11566//.. //-- jmp_lit(cb, d32);
11567//.. //-- whatNext = Dis_StopHere;
11568//.. //-- DIP("loop 0x%x\n", d32);
11569//.. //-- break;
sewardj32b2bbe2005-01-28 00:50:10 +000011570
11571 /* ------------------------ IMUL ----------------------- */
11572
11573 case 0x69: /* IMUL Iv, Ev, Gv */
sewardj5b470602005-02-27 13:10:48 +000011574 if (haveF2orF3(pfx)) goto decode_failure;
sewardj32b2bbe2005-01-28 00:50:10 +000011575 delta = dis_imul_I_E_G ( pfx, sz, delta, sz );
11576 break;
sewardj7de0d3c2005-02-13 02:26:41 +000011577 case 0x6B: /* IMUL Ib, Ev, Gv */
11578 delta = dis_imul_I_E_G ( pfx, sz, delta, 1 );
11579 break;
sewardj1389d4d2005-01-28 13:46:29 +000011580
11581 /* ------------------------ MOV ------------------------ */
11582
11583 case 0x88: /* MOV Gb,Eb */
sewardj5b470602005-02-27 13:10:48 +000011584 if (haveF2orF3(pfx)) goto decode_failure;
sewardj1389d4d2005-01-28 13:46:29 +000011585 delta = dis_mov_G_E(pfx, 1, delta);
11586 break;
11587
11588 case 0x89: /* MOV Gv,Ev */
sewardj5b470602005-02-27 13:10:48 +000011589 if (haveF2orF3(pfx)) goto decode_failure;
sewardj1389d4d2005-01-28 13:46:29 +000011590 delta = dis_mov_G_E(pfx, sz, delta);
11591 break;
11592
sewardjd0a12df2005-02-10 02:07:43 +000011593 case 0x8A: /* MOV Eb,Gb */
sewardj5b470602005-02-27 13:10:48 +000011594 if (haveF2orF3(pfx)) goto decode_failure;
sewardjd0a12df2005-02-10 02:07:43 +000011595 delta = dis_mov_E_G(pfx, 1, delta);
11596 break;
11597
sewardj1389d4d2005-01-28 13:46:29 +000011598 case 0x8B: /* MOV Ev,Gv */
sewardj5b470602005-02-27 13:10:48 +000011599 if (haveF2orF3(pfx)) goto decode_failure;
sewardj1389d4d2005-01-28 13:46:29 +000011600 delta = dis_mov_E_G(pfx, sz, delta);
11601 break;
11602
11603 case 0x8D: /* LEA M,Gv */
sewardj5b470602005-02-27 13:10:48 +000011604 if (haveF2orF3(pfx)) goto decode_failure;
sewardj1389d4d2005-01-28 13:46:29 +000011605 if (sz != 4 && sz != 8)
11606 goto decode_failure;
11607 modrm = getUChar(delta);
11608 if (epartIsReg(modrm))
11609 goto decode_failure;
11610 /* NOTE! this is the one place where a segment override prefix
11611 has no effect on the address calculation. Therefore we clear
11612 any segment override bits in pfx. */
sewardje1698952005-02-08 15:02:39 +000011613 addr = disAMode ( &alen, clearSegBits(pfx), delta, dis_buf, 0 );
sewardj1389d4d2005-01-28 13:46:29 +000011614 delta += alen;
11615 /* This is a hack. But it isn't clear that really doing the
11616 calculation at 32 bits is really worth it. Hence for leal,
11617 do the full 64-bit calculation and then truncate it. */
sewardj5b470602005-02-27 13:10:48 +000011618 putIRegG( sz, pfx, modrm,
sewardj1389d4d2005-01-28 13:46:29 +000011619 sz == 4
11620 ? unop(Iop_64to32, mkexpr(addr))
11621 : mkexpr(addr)
11622 );
11623 DIP("lea%c %s, %s\n", nameISize(sz), dis_buf,
sewardj5b470602005-02-27 13:10:48 +000011624 nameIRegG(sz,pfx,modrm));
sewardj1389d4d2005-01-28 13:46:29 +000011625 break;
11626
sewardjd20c8852005-01-20 20:04:07 +000011627//.. case 0x8C: /* MOV Sw,Ew -- MOV from a SEGMENT REGISTER */
11628//.. delta = dis_mov_Sw_Ew(sorb, sz, delta);
11629//.. break;
11630//..
11631//.. case 0x8E: /* MOV Ew,Sw -- MOV to a SEGMENT REGISTER */
11632//.. delta = dis_mov_Ew_Sw(sorb, delta);
11633//.. break;
11634//..
11635//.. case 0xA0: /* MOV Ob,AL */
11636//.. sz = 1;
11637//.. /* Fall through ... */
11638//.. case 0xA1: /* MOV Ov,eAX */
11639//.. d32 = getUDisp32(delta); delta += 4;
11640//.. ty = szToITy(sz);
11641//.. addr = newTemp(Ity_I32);
11642//.. assign( addr, handleSegOverride(sorb, mkU32(d32)) );
11643//.. putIReg(sz, R_EAX, loadLE(ty, mkexpr(addr)));
11644//.. DIP("mov%c %s0x%x, %s\n", nameISize(sz), sorbTxt(sorb),
11645//.. d32, nameIReg(sz,R_EAX));
11646//.. break;
11647//..
11648//.. case 0xA2: /* MOV Ob,AL */
11649//.. sz = 1;
11650//.. /* Fall through ... */
11651//.. case 0xA3: /* MOV eAX,Ov */
11652//.. d32 = getUDisp32(delta); delta += 4;
11653//.. ty = szToITy(sz);
11654//.. addr = newTemp(Ity_I32);
11655//.. assign( addr, handleSegOverride(sorb, mkU32(d32)) );
11656//.. storeLE( mkexpr(addr), getIReg(sz,R_EAX) );
11657//.. DIP("mov%c %s, %s0x%x\n", nameISize(sz), nameIReg(sz,R_EAX),
11658//.. sorbTxt(sorb), d32);
11659//.. break;
sewardjb095fba2005-02-13 14:13:04 +000011660
11661/* XXXX be careful here with moves to AH/BH/CH/DH */
sewardjd20c8852005-01-20 20:04:07 +000011662//.. case 0xB0: /* MOV imm,AL */
11663//.. case 0xB1: /* MOV imm,CL */
sewardjb095fba2005-02-13 14:13:04 +000011664 case 0xB2: /* MOV imm,DL */
sewardjd20c8852005-01-20 20:04:07 +000011665//.. case 0xB3: /* MOV imm,BL */
11666//.. case 0xB4: /* MOV imm,AH */
11667//.. case 0xB5: /* MOV imm,CH */
11668//.. case 0xB6: /* MOV imm,DH */
11669//.. case 0xB7: /* MOV imm,BH */
sewardj5b470602005-02-27 13:10:48 +000011670 if (haveF2orF3(pfx)) goto decode_failure;
sewardjb095fba2005-02-13 14:13:04 +000011671 d64 = getUChar(delta);
11672 delta += 1;
sewardj5b470602005-02-27 13:10:48 +000011673 putIRegRexB(1, pfx, opc-0xB0, mkU8(d64));
11674 DIP("movb $%lld,%s\n", d64, nameIRegRexB(1,pfx,opc-0xB0));
sewardjb095fba2005-02-13 14:13:04 +000011675 break;
sewardj1389d4d2005-01-28 13:46:29 +000011676
11677 case 0xB8: /* MOV imm,eAX */
11678 case 0xB9: /* MOV imm,eCX */
11679 case 0xBA: /* MOV imm,eDX */
11680 case 0xBB: /* MOV imm,eBX */
11681 case 0xBC: /* MOV imm,eSP */
11682 case 0xBD: /* MOV imm,eBP */
11683 case 0xBE: /* MOV imm,eSI */
11684 case 0xBF: /* MOV imm,eDI */
sewardj03b07cc2005-01-31 18:09:43 +000011685 /* This is the one-and-only place where 64-bit literals are
11686 allowed in the instruction stream. */
sewardj5b470602005-02-27 13:10:48 +000011687 if (haveF2orF3(pfx)) goto decode_failure;
sewardj03b07cc2005-01-31 18:09:43 +000011688 if (sz == 8) {
11689 d64 = getDisp64(delta);
sewardj7eaa7cf2005-01-31 18:55:22 +000011690 delta += 8;
sewardj5b470602005-02-27 13:10:48 +000011691 putIRegRexB(8, pfx, opc-0xB8, mkU64(d64));
sewardj227458e2005-01-31 19:04:50 +000011692 DIP("movabsq $%lld,%s\n", (Long)d64,
sewardj5b470602005-02-27 13:10:48 +000011693 nameIRegRexB(8,pfx,opc-0xB8));
sewardj03b07cc2005-01-31 18:09:43 +000011694 } else {
11695 d64 = getSDisp(imin(4,sz),delta);
11696 delta += imin(4,sz);
sewardj5b470602005-02-27 13:10:48 +000011697 putIRegRexB(sz, pfx, opc-0xB8,
11698 mkU(szToITy(sz), d64 & mkSizeMask(sz)));
sewardj227458e2005-01-31 19:04:50 +000011699 DIP("mov%c $%lld,%s\n", nameISize(sz),
11700 (Long)d64,
sewardj5b470602005-02-27 13:10:48 +000011701 nameIRegRexB(sz,pfx,opc-0xB8));
sewardj03b07cc2005-01-31 18:09:43 +000011702 }
sewardj1389d4d2005-01-28 13:46:29 +000011703 break;
11704
11705 case 0xC6: /* MOV Ib,Eb */
11706 sz = 1;
11707 goto do_Mov_I_E;
11708 case 0xC7: /* MOV Iv,Ev */
11709 goto do_Mov_I_E;
11710
11711 do_Mov_I_E:
sewardj5b470602005-02-27 13:10:48 +000011712 if (haveF2orF3(pfx)) goto decode_failure;
sewardj1389d4d2005-01-28 13:46:29 +000011713 modrm = getUChar(delta);
11714 if (epartIsReg(modrm)) {
sewardj1389d4d2005-01-28 13:46:29 +000011715 delta++; /* mod/rm byte */
11716 d64 = getSDisp(imin(4,sz),delta);
11717 delta += imin(4,sz);
sewardj5b470602005-02-27 13:10:48 +000011718 putIRegE(sz, pfx, modrm,
11719 mkU(szToITy(sz), d64 & mkSizeMask(sz)));
sewardj227458e2005-01-31 19:04:50 +000011720 DIP("mov%c $%lld, %s\n", nameISize(sz),
11721 (Long)d64,
sewardj5b470602005-02-27 13:10:48 +000011722 nameIRegE(sz,pfx,modrm));
sewardj1389d4d2005-01-28 13:46:29 +000011723 } else {
sewardj5b470602005-02-27 13:10:48 +000011724 addr = disAMode ( &alen, pfx, delta, dis_buf,
11725 /*xtra*/imin(4,sz) );
sewardj1389d4d2005-01-28 13:46:29 +000011726 delta += alen;
sewardje941eea2005-01-30 19:52:28 +000011727 d64 = getSDisp(imin(4,sz),delta);
sewardj1389d4d2005-01-28 13:46:29 +000011728 delta += imin(4,sz);
sewardje941eea2005-01-30 19:52:28 +000011729 storeLE(mkexpr(addr),
11730 mkU(szToITy(sz), d64 & mkSizeMask(sz)));
sewardj227458e2005-01-31 19:04:50 +000011731 DIP("mov%c $%lld, %s\n", nameISize(sz), (Long)d64, dis_buf);
sewardj1389d4d2005-01-28 13:46:29 +000011732 }
11733 break;
11734
sewardj5e525292005-01-28 15:13:10 +000011735 /* ------------------------ MOVx ------------------------ */
11736
11737 case 0x63: /* MOVSX */
sewardj5b470602005-02-27 13:10:48 +000011738 if (haveF2orF3(pfx)) goto decode_failure;
sewardj5e525292005-01-28 15:13:10 +000011739 if (haveREX(pfx) && 1==getRexW(pfx)) {
11740 vassert(sz == 8);
11741 /* movsx r/m32 to r64 */
11742 modrm = getUChar(delta);
11743 if (epartIsReg(modrm)) {
11744 delta++;
sewardj5b470602005-02-27 13:10:48 +000011745 putIRegG(8, pfx, modrm,
sewardj5e525292005-01-28 15:13:10 +000011746 unop(Iop_32Sto64,
sewardj5b470602005-02-27 13:10:48 +000011747 getIRegE(4, pfx, modrm)));
sewardj5e525292005-01-28 15:13:10 +000011748 DIP("movslq %s,%s\n",
sewardj5b470602005-02-27 13:10:48 +000011749 nameIRegE(4, pfx, modrm),
11750 nameIRegG(8, pfx, modrm));
sewardj5e525292005-01-28 15:13:10 +000011751 break;
11752 } else {
sewardje1698952005-02-08 15:02:39 +000011753 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
sewardj5e525292005-01-28 15:13:10 +000011754 delta += alen;
sewardj5b470602005-02-27 13:10:48 +000011755 putIRegG(8, pfx, modrm,
sewardj5e525292005-01-28 15:13:10 +000011756 unop(Iop_32Sto64,
11757 loadLE(Ity_I32, mkexpr(addr))));
11758 DIP("movslq %s,%s\n", dis_buf,
sewardj5b470602005-02-27 13:10:48 +000011759 nameIRegG(8, pfx, modrm));
sewardj5e525292005-01-28 15:13:10 +000011760 break;
11761 }
11762 } else {
11763 goto decode_failure;
11764 }
11765
sewardjd20c8852005-01-20 20:04:07 +000011766//.. /* ------------------------ opl imm, A ----------------- */
11767//..
11768//.. case 0x04: /* ADD Ib, AL */
11769//.. delta = dis_op_imm_A( 1, Iop_Add8, True, delta, "add" );
11770//.. break;
sewardj03b07cc2005-01-31 18:09:43 +000011771 case 0x05: /* ADD Iv, eAX */
sewardj5b470602005-02-27 13:10:48 +000011772 if (haveF2orF3(pfx)) goto decode_failure;
sewardj03b07cc2005-01-31 18:09:43 +000011773 delta = dis_op_imm_A(sz, Iop_Add8, True, delta, "add" );
11774 break;
11775
sewardjd20c8852005-01-20 20:04:07 +000011776//.. case 0x0C: /* OR Ib, AL */
11777//.. delta = dis_op_imm_A( 1, Iop_Or8, True, delta, "or" );
11778//.. break;
sewardj03b07cc2005-01-31 18:09:43 +000011779 case 0x0D: /* OR Iv, eAX */
sewardj5b470602005-02-27 13:10:48 +000011780 if (haveF2orF3(pfx)) goto decode_failure;
sewardj03b07cc2005-01-31 18:09:43 +000011781 delta = dis_op_imm_A( sz, Iop_Or8, True, delta, "or" );
11782 break;
11783
sewardjd20c8852005-01-20 20:04:07 +000011784//.. //-- case 0x14: /* ADC Ib, AL */
11785//.. //-- delta = dis_op_imm_A( 1, ADC, True, delta, "adc" );
11786//.. //-- break;
11787//.. //-- case 0x15: /* ADC Iv, eAX */
11788//.. //-- delta = dis_op_imm_A( sz, ADC, True, delta, "adc" );
11789//.. //-- break;
11790//.. //--
11791//.. //-- case 0x1C: /* SBB Ib, AL */
11792//.. //-- delta = dis_op_imm_A( 1, SBB, True, delta, "sbb" );
11793//.. //-- break;
11794//.. //-- case 0x1D: /* SBB Iv, eAX */
11795//.. //-- delta = dis_op_imm_A( sz, SBB, True, delta, "sbb" );
11796//.. //-- break;
11797//.. //--
11798//.. case 0x24: /* AND Ib, AL */
11799//.. delta = dis_op_imm_A( 1, Iop_And8, True, delta, "and" );
11800//.. break;
sewardj3ca55a12005-01-27 16:06:23 +000011801 case 0x25: /* AND Iv, eAX */
11802 if (haveF2orF3(pfx)) goto decode_failure;
11803 delta = dis_op_imm_A( sz, Iop_And8, True, delta, "and" );
11804 break;
11805
sewardjd20c8852005-01-20 20:04:07 +000011806//.. case 0x2C: /* SUB Ib, AL */
11807//.. delta = dis_op_imm_A(1, Iop_Sub8, True, delta, "sub" );
11808//.. break;
sewardj03b07cc2005-01-31 18:09:43 +000011809 case 0x2D: /* SUB Iv, eAX */
sewardj5b470602005-02-27 13:10:48 +000011810 if (haveF2orF3(pfx)) goto decode_failure;
sewardj03b07cc2005-01-31 18:09:43 +000011811 delta = dis_op_imm_A( sz, Iop_Sub8, True, delta, "sub" );
11812 break;
11813
sewardjd20c8852005-01-20 20:04:07 +000011814//.. case 0x34: /* XOR Ib, AL */
11815//.. delta = dis_op_imm_A( 1, Iop_Xor8, True, delta, "xor" );
11816//.. break;
sewardj85520e42005-02-19 15:22:38 +000011817 case 0x35: /* XOR Iv, eAX */
sewardj5b470602005-02-27 13:10:48 +000011818 if (haveF2orF3(pfx)) goto decode_failure;
sewardj85520e42005-02-19 15:22:38 +000011819 delta = dis_op_imm_A( sz, Iop_Xor8, True, delta, "xor" );
11820 break;
sewardj03b07cc2005-01-31 18:09:43 +000011821
11822 case 0x3C: /* CMP Ib, AL */
11823 if (haveF2orF3(pfx)) goto decode_failure;
11824 delta = dis_op_imm_A( 1, Iop_Sub8, False, delta, "cmp" );
11825 break;
sewardj354e5c62005-01-27 20:12:52 +000011826 case 0x3D: /* CMP Iv, eAX */
11827 if (haveF2orF3(pfx)) goto decode_failure;
11828 delta = dis_op_imm_A( sz, Iop_Sub8, False, delta, "cmp" );
11829 break;
11830
sewardj118b23e2005-01-29 02:14:44 +000011831 case 0xA8: /* TEST Ib, AL */
sewardj03b07cc2005-01-31 18:09:43 +000011832 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000011833 delta = dis_op_imm_A( 1, Iop_And8, False, delta, "test" );
11834 break;
11835 case 0xA9: /* TEST Iv, eAX */
sewardj03b07cc2005-01-31 18:09:43 +000011836 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000011837 delta = dis_op_imm_A( sz, Iop_And8, False, delta, "test" );
11838 break;
11839
11840 /* ------------------------ opl Ev, Gv ----------------- */
11841
sewardj03b07cc2005-01-31 18:09:43 +000011842 case 0x02: /* ADD Eb,Gb */
11843 if (haveF2orF3(pfx)) goto decode_failure;
11844 delta = dis_op2_E_G ( pfx, False, Iop_Add8, True, 1, delta, "add" );
11845 break;
sewardjdf0e0022005-01-25 15:48:43 +000011846 case 0x03: /* ADD Ev,Gv */
sewardj3ca55a12005-01-27 16:06:23 +000011847 if (haveF2orF3(pfx)) goto decode_failure;
sewardjdf0e0022005-01-25 15:48:43 +000011848 delta = dis_op2_E_G ( pfx, False, Iop_Add8, True, sz, delta, "add" );
sewardjdf0e0022005-01-25 15:48:43 +000011849 break;
11850
sewardj03b07cc2005-01-31 18:09:43 +000011851 case 0x0A: /* OR Eb,Gb */
sewardj5b470602005-02-27 13:10:48 +000011852 if (haveF2orF3(pfx)) goto decode_failure;
sewardj03b07cc2005-01-31 18:09:43 +000011853 delta = dis_op2_E_G ( pfx, False, Iop_Or8, True, 1, delta, "or" );
11854 break;
11855 case 0x0B: /* OR Ev,Gv */
sewardj5b470602005-02-27 13:10:48 +000011856 if (haveF2orF3(pfx)) goto decode_failure;
sewardj03b07cc2005-01-31 18:09:43 +000011857 delta = dis_op2_E_G ( pfx, False, Iop_Or8, True, sz, delta, "or" );
11858 break;
11859//--
sewardjd20c8852005-01-20 20:04:07 +000011860//.. //-- case 0x12: /* ADC Eb,Gb */
11861//.. //-- delta = dis_op2_E_G ( sorb, True, ADC, True, 1, delta, "adc" );
11862//.. //-- break;
11863//.. case 0x13: /* ADC Ev,Gv */
11864//.. delta = dis_op2_E_G ( sorb, True, Iop_Add8, True, sz, delta, "adc" );
11865//.. break;
11866//..
11867//.. //-- case 0x1A: /* SBB Eb,Gb */
11868//.. //-- delta = dis_op2_E_G ( sorb, True, SBB, True, 1, delta, "sbb" );
11869//.. //-- break;
11870//.. case 0x1B: /* SBB Ev,Gv */
11871//.. delta = dis_op2_E_G ( sorb, True, Iop_Sub8, True, sz, delta, "sbb" );
11872//.. break;
sewardj03b07cc2005-01-31 18:09:43 +000011873
11874 case 0x22: /* AND Eb,Gb */
11875 if (haveF2orF3(pfx)) goto decode_failure;
11876 delta = dis_op2_E_G ( pfx, False, Iop_And8, True, 1, delta, "and" );
11877 break;
11878 case 0x23: /* AND Ev,Gv */
11879 if (haveF2orF3(pfx)) goto decode_failure;
11880 delta = dis_op2_E_G ( pfx, False, Iop_And8, True, sz, delta, "and" );
11881 break;
11882
11883 case 0x2A: /* SUB Eb,Gb */
11884 if (haveF2orF3(pfx)) goto decode_failure;
11885 delta = dis_op2_E_G ( pfx, False, Iop_Sub8, True, 1, delta, "sub" );
11886 break;
sewardj118b23e2005-01-29 02:14:44 +000011887 case 0x2B: /* SUB Ev,Gv */
sewardj03b07cc2005-01-31 18:09:43 +000011888 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000011889 delta = dis_op2_E_G ( pfx, False, Iop_Sub8, True, sz, delta, "sub" );
11890 break;
11891
sewardj03b07cc2005-01-31 18:09:43 +000011892 case 0x32: /* XOR Eb,Gb */
11893 if (haveF2orF3(pfx)) goto decode_failure;
11894 delta = dis_op2_E_G ( pfx, False, Iop_Xor8, True, 1, delta, "xor" );
11895 break;
11896 case 0x33: /* XOR Ev,Gv */
11897 if (haveF2orF3(pfx)) goto decode_failure;
11898 delta = dis_op2_E_G ( pfx, False, Iop_Xor8, True, sz, delta, "xor" );
11899 break;
11900
sewardjb095fba2005-02-13 14:13:04 +000011901 case 0x3A: /* CMP Eb,Gb */
11902 if (haveF2orF3(pfx)) goto decode_failure;
11903 delta = dis_op2_E_G ( pfx, False, Iop_Sub8, False, 1, delta, "cmp" );
11904 break;
sewardj354e5c62005-01-27 20:12:52 +000011905 case 0x3B: /* CMP Ev,Gv */
11906 if (haveF2orF3(pfx)) goto decode_failure;
11907 delta = dis_op2_E_G ( pfx, False, Iop_Sub8, False, sz, delta, "cmp" );
11908 break;
11909
sewardj118b23e2005-01-29 02:14:44 +000011910 case 0x84: /* TEST Eb,Gb */
sewardj03b07cc2005-01-31 18:09:43 +000011911 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000011912 delta = dis_op2_E_G ( pfx, False, Iop_And8, False, 1, delta, "test" );
11913 break;
11914 case 0x85: /* TEST Ev,Gv */
sewardj03b07cc2005-01-31 18:09:43 +000011915 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000011916 delta = dis_op2_E_G ( pfx, False, Iop_And8, False, sz, delta, "test" );
11917 break;
11918
11919 /* ------------------------ opl Gv, Ev ----------------- */
11920
sewardj85520e42005-02-19 15:22:38 +000011921 case 0x00: /* ADD Gb,Eb */
11922 if (haveF2orF3(pfx)) goto decode_failure;
11923 delta = dis_op2_G_E ( pfx, False, Iop_Add8, True, 1, delta, "add" );
11924 break;
sewardj3ca55a12005-01-27 16:06:23 +000011925 case 0x01: /* ADD Gv,Ev */
sewardj354e5c62005-01-27 20:12:52 +000011926 if (haveF2orF3(pfx)) goto decode_failure;
sewardj3ca55a12005-01-27 16:06:23 +000011927 delta = dis_op2_G_E ( pfx, False, Iop_Add8, True, sz, delta, "add" );
11928 break;
11929
sewardj03b07cc2005-01-31 18:09:43 +000011930 case 0x08: /* OR Gb,Eb */
11931 if (haveF2orF3(pfx)) goto decode_failure;
11932 delta = dis_op2_G_E ( pfx, False, Iop_Or8, True, 1, delta, "or" );
11933 break;
sewardj55dbb262005-01-28 16:36:51 +000011934 case 0x09: /* OR Gv,Ev */
11935 if (haveF2orF3(pfx)) goto decode_failure;
11936 delta = dis_op2_G_E ( pfx, False, Iop_Or8, True, sz, delta, "or" );
11937 break;
11938
sewardj85520e42005-02-19 15:22:38 +000011939 case 0x10: /* ADC Gb,Eb */
11940 if (haveF2orF3(pfx)) goto decode_failure;
11941 delta = dis_op2_G_E ( pfx, True, Iop_Add8, True, 1, delta, "adc" );
11942 break;
11943 case 0x11: /* ADC Gv,Ev */
11944 if (haveF2orF3(pfx)) goto decode_failure;
11945 delta = dis_op2_G_E ( pfx, True, Iop_Add8, True, sz, delta, "adc" );
11946 break;
11947
11948 case 0x18: /* SBB Gb,Eb */
11949 if (haveF2orF3(pfx)) goto decode_failure;
11950 delta = dis_op2_G_E ( pfx, True, Iop_Sub8, True, 1, delta, "sbb" );
11951 break;
sewardj03b07cc2005-01-31 18:09:43 +000011952 case 0x19: /* SBB Gv,Ev */
sewardja6b93d12005-02-17 09:28:28 +000011953 if (haveF2orF3(pfx)) goto decode_failure;
sewardj03b07cc2005-01-31 18:09:43 +000011954 delta = dis_op2_G_E ( pfx, True, Iop_Sub8, True, sz, delta, "sbb" );
11955 break;
11956
sewardj85520e42005-02-19 15:22:38 +000011957 case 0x20: /* AND Gb,Eb */
11958 if (haveF2orF3(pfx)) goto decode_failure;
11959 delta = dis_op2_G_E ( pfx, False, Iop_And8, True, 1, delta, "and" );
11960 break;
sewardj3ca55a12005-01-27 16:06:23 +000011961 case 0x21: /* AND Gv,Ev */
sewardj354e5c62005-01-27 20:12:52 +000011962 if (haveF2orF3(pfx)) goto decode_failure;
sewardj3ca55a12005-01-27 16:06:23 +000011963 delta = dis_op2_G_E ( pfx, False, Iop_And8, True, sz, delta, "and" );
11964 break;
sewardj03b07cc2005-01-31 18:09:43 +000011965
11966 case 0x28: /* SUB Gb,Eb */
11967 if (haveF2orF3(pfx)) goto decode_failure;
11968 delta = dis_op2_G_E ( pfx, False, Iop_Sub8, True, 1, delta, "sub" );
11969 break;
sewardj118b23e2005-01-29 02:14:44 +000011970 case 0x29: /* SUB Gv,Ev */
sewardj03b07cc2005-01-31 18:09:43 +000011971 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000011972 delta = dis_op2_G_E ( pfx, False, Iop_Sub8, True, sz, delta, "sub" );
11973 break;
11974
sewardjb095fba2005-02-13 14:13:04 +000011975 case 0x30: /* XOR Gb,Eb */
11976 if (haveF2orF3(pfx)) goto decode_failure;
11977 delta = dis_op2_G_E ( pfx, False, Iop_Xor8, True, 1, delta, "xor" );
11978 break;
sewardj118b23e2005-01-29 02:14:44 +000011979 case 0x31: /* XOR Gv,Ev */
sewardj03b07cc2005-01-31 18:09:43 +000011980 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000011981 delta = dis_op2_G_E ( pfx, False, Iop_Xor8, True, sz, delta, "xor" );
11982 break;
sewardj354e5c62005-01-27 20:12:52 +000011983
11984 case 0x38: /* CMP Gb,Eb */
11985 if (haveF2orF3(pfx)) goto decode_failure;
11986 delta = dis_op2_G_E ( pfx, False, Iop_Sub8, False, 1, delta, "cmp" );
11987 break;
11988 case 0x39: /* CMP Gv,Ev */
11989 if (haveF2orF3(pfx)) goto decode_failure;
11990 delta = dis_op2_G_E ( pfx, False, Iop_Sub8, False, sz, delta, "cmp" );
11991 break;
11992
sewardj55dbb262005-01-28 16:36:51 +000011993 /* ------------------------ POP ------------------------ */
11994
11995 case 0x58: /* POP eAX */
11996 case 0x59: /* POP eCX */
11997 case 0x5A: /* POP eDX */
11998 case 0x5B: /* POP eBX */
11999 case 0x5D: /* POP eBP */
12000 case 0x5E: /* POP eSI */
12001 case 0x5F: /* POP eDI */
12002 case 0x5C: /* POP eSP */
sewardj03b07cc2005-01-31 18:09:43 +000012003 if (haveF2orF3(pfx)) goto decode_failure;
sewardj55dbb262005-01-28 16:36:51 +000012004 vassert(sz == 2 || sz == 4 || sz == 8);
12005 if (sz == 4)
12006 sz = 8; /* there is no encoding for 32-bit pop in 64-bit mode */
12007 t1 = newTemp(szToITy(sz));
12008 t2 = newTemp(Ity_I64);
12009 assign(t2, getIReg64(R_RSP));
12010 assign(t1, loadLE(szToITy(sz),mkexpr(t2)));
12011 putIReg64(R_RSP, binop(Iop_Add64, mkexpr(t2), mkU64(sz)));
sewardj5b470602005-02-27 13:10:48 +000012012 putIRegRexB(sz, pfx, opc-0x58, mkexpr(t1));
12013 DIP("pop%c %s\n", nameISize(sz), nameIRegRexB(sz,pfx,opc-0x58));
sewardj55dbb262005-01-28 16:36:51 +000012014 break;
12015
sewardj85520e42005-02-19 15:22:38 +000012016 case 0x9D: /* POPF */
12017 /* Note. There is no encoding for a 32-bit popf in 64-bit mode.
12018 So sz==4 actually means sz==8. */
sewardj5b470602005-02-27 13:10:48 +000012019 if (haveF2orF3(pfx)) goto decode_failure;
sewardj85520e42005-02-19 15:22:38 +000012020 vassert(sz == 2 || sz == 4);
12021 if (sz == 4) sz = 8;
sewardj5b470602005-02-27 13:10:48 +000012022 if (sz != 8) goto decode_failure; // until we know a sz==2 test case exists
sewardj85520e42005-02-19 15:22:38 +000012023 t1 = newTemp(Ity_I64); t2 = newTemp(Ity_I64);
12024 assign(t2, getIReg64(R_RSP));
12025 assign(t1, widenUto64(loadLE(szToITy(sz),mkexpr(t2))));
12026 putIReg64(R_RSP, binop(Iop_Add64, mkexpr(t2), mkU64(sz)));
12027 /* t1 is the flag word. Mask out everything except OSZACP and
12028 set the flags thunk to AMD64G_CC_OP_COPY. */
12029 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(AMD64G_CC_OP_COPY) ));
12030 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
12031 stmt( IRStmt_Put( OFFB_CC_DEP1,
12032 binop(Iop_And64,
12033 mkexpr(t1),
12034 mkU64( AMD64G_CC_MASK_C | AMD64G_CC_MASK_P
12035 | AMD64G_CC_MASK_A | AMD64G_CC_MASK_Z
12036 | AMD64G_CC_MASK_S| AMD64G_CC_MASK_O )
12037 )
12038 )
12039 );
12040
12041 /* Also need to set the D flag, which is held in bit 10 of t1.
12042 If zero, put 1 in OFFB_DFLAG, else -1 in OFFB_DFLAG. */
12043 stmt( IRStmt_Put(
12044 OFFB_DFLAG,
12045 IRExpr_Mux0X(
12046 unop(Iop_32to8,
12047 unop(Iop_64to32,
12048 binop(Iop_And64,
12049 binop(Iop_Shr64, mkexpr(t1), mkU8(10)),
12050 mkU64(1)))),
12051 mkU64(1),
12052 mkU64(0xFFFFFFFFFFFFFFFFULL)))
12053 );
12054
12055 /* And set the ID flag */
12056 stmt( IRStmt_Put(
12057 OFFB_IDFLAG,
12058 IRExpr_Mux0X(
12059 unop(Iop_32to8,
12060 unop(Iop_64to32,
12061 binop(Iop_And64,
12062 binop(Iop_Shr64, mkexpr(t1), mkU8(21)),
12063 mkU64(1)))),
12064 mkU64(0),
12065 mkU64(1)))
12066 );
12067
12068 DIP("popf%c\n", nameISize(sz));
12069 break;
12070
sewardjd20c8852005-01-20 20:04:07 +000012071//.. case 0x61: /* POPA */
12072//.. /* This is almost certainly wrong for sz==2. So ... */
12073//.. if (sz != 4) goto decode_failure;
12074//..
12075//.. /* t5 is the old %ESP value. */
12076//.. t5 = newTemp(Ity_I32);
12077//.. assign( t5, getIReg(4, R_ESP) );
12078//..
12079//.. /* Reload all the registers, except %esp. */
12080//.. putIReg(4,R_EAX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(28)) ));
12081//.. putIReg(4,R_ECX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(24)) ));
12082//.. putIReg(4,R_EDX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(20)) ));
12083//.. putIReg(4,R_EBX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(16)) ));
12084//.. /* ignore saved %ESP */
12085//.. putIReg(4,R_EBP, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32( 8)) ));
12086//.. putIReg(4,R_ESI, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32( 4)) ));
12087//.. putIReg(4,R_EDI, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32( 0)) ));
12088//..
12089//.. /* and move %ESP back up */
12090//.. putIReg( 4, R_ESP, binop(Iop_Add32, mkexpr(t5), mkU32(8*4)) );
12091//..
12092//.. DIP("pusha%c\n", nameISize(sz));
12093//.. break;
12094//..
12095//.. case 0x8F: /* POPL/POPW m32 */
12096//.. { Int len;
sewardj8c332e22005-01-28 01:36:56 +000012097//.. UChar rm = getUChar(delta);
sewardjd20c8852005-01-20 20:04:07 +000012098//..
12099//.. /* make sure this instruction is correct POP */
12100//.. vassert(!epartIsReg(rm) && (gregOfRM(rm) == 0));
12101//.. /* and has correct size */
12102//.. vassert(sz == 4);
12103//..
12104//.. t1 = newTemp(Ity_I32); t3 = newTemp(Ity_I32);
12105//.. /* set t1 to ESP: t1 = ESP */
12106//.. assign( t1, getIReg(4, R_ESP) );
12107//.. /* load M[ESP] to virtual register t3: t3 = M[t1] */
12108//.. assign( t3, loadLE(Ity_I32, mkexpr(t1)) );
12109//..
12110//.. /* increase ESP; must be done before the STORE. Intel manual says:
12111//.. If the ESP register is used as a base register for addressing
12112//.. a destination operand in memory, the POP instruction computes
12113//.. the effective address of the operand after it increments the
12114//.. ESP register.
12115//.. */
12116//.. putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t1), mkU32(sz)) );
12117//..
12118//.. /* resolve MODR/M */
12119//.. addr = disAMode ( &len, sorb, delta, dis_buf);
12120//.. storeLE( mkexpr(addr), mkexpr(t3) );
12121//..
12122//.. DIP("popl %s\n", dis_buf);
12123//..
12124//.. delta += len;
12125//.. break;
12126//.. }
12127//..
12128//.. //-- case 0x1F: /* POP %DS */
12129//.. //-- dis_pop_segreg( cb, R_DS, sz ); break;
12130//.. //-- case 0x07: /* POP %ES */
12131//.. //-- dis_pop_segreg( cb, R_ES, sz ); break;
12132//.. //-- case 0x17: /* POP %SS */
12133//.. //-- dis_pop_segreg( cb, R_SS, sz ); break;
sewardj55dbb262005-01-28 16:36:51 +000012134
12135 /* ------------------------ PUSH ----------------------- */
12136
12137 case 0x50: /* PUSH eAX */
12138 case 0x51: /* PUSH eCX */
12139 case 0x52: /* PUSH eDX */
12140 case 0x53: /* PUSH eBX */
12141 case 0x55: /* PUSH eBP */
12142 case 0x56: /* PUSH eSI */
12143 case 0x57: /* PUSH eDI */
12144 case 0x54: /* PUSH eSP */
12145 /* This is the Right Way, in that the value to be pushed is
12146 established before %rsp is changed, so that pushq %rsp
12147 correctly pushes the old value. */
sewardj03b07cc2005-01-31 18:09:43 +000012148 if (haveF2orF3(pfx)) goto decode_failure;
sewardj55dbb262005-01-28 16:36:51 +000012149 vassert(sz == 2 || sz == 4 || sz == 8);
12150 if (sz == 4)
12151 sz = 8; /* there is no encoding for 32-bit push in 64-bit mode */
12152 ty = sz==2 ? Ity_I16 : Ity_I64;
12153 t1 = newTemp(ty);
12154 t2 = newTemp(Ity_I64);
sewardj5b470602005-02-27 13:10:48 +000012155 assign(t1, getIRegRexB(sz, pfx, opc-0x50));
sewardj55dbb262005-01-28 16:36:51 +000012156 assign(t2, binop(Iop_Sub64, getIReg64(R_RSP), mkU64(sz)));
12157 putIReg64(R_RSP, mkexpr(t2) );
12158 storeLE(mkexpr(t2),mkexpr(t1));
sewardj5b470602005-02-27 13:10:48 +000012159 DIP("push%c %s\n", nameISize(sz), nameIRegRexB(sz,pfx,opc-0x50));
sewardj55dbb262005-01-28 16:36:51 +000012160 break;
12161
sewardja6b93d12005-02-17 09:28:28 +000012162 case 0x68: /* PUSH Iv */
sewardj5b470602005-02-27 13:10:48 +000012163 if (haveF2orF3(pfx)) goto decode_failure;
sewardja6b93d12005-02-17 09:28:28 +000012164 /* Note, sz==4 is not possible in 64-bit mode. Hence ... */
12165 if (sz == 4) sz = 8;
12166 d64 = getSDisp(imin(4,sz),delta);
12167 delta += imin(4,sz);
12168 goto do_push_I;
sewardj909c06d2005-02-19 22:47:41 +000012169 case 0x6A: /* PUSH Ib, sign-extended to sz */
sewardj5b470602005-02-27 13:10:48 +000012170 if (haveF2orF3(pfx)) goto decode_failure;
sewardj909c06d2005-02-19 22:47:41 +000012171 /* Note, sz==4 is not possible in 64-bit mode. Hence ... */
12172 if (sz == 4) sz = 8;
12173 d64 = getSDisp8(delta); delta += 1;
12174 goto do_push_I;
sewardja6b93d12005-02-17 09:28:28 +000012175 do_push_I:
12176 ty = szToITy(sz);
sewardj909c06d2005-02-19 22:47:41 +000012177 t1 = newTemp(Ity_I64);
12178 t2 = newTemp(ty);
sewardja6b93d12005-02-17 09:28:28 +000012179 assign( t1, binop(Iop_Sub64,getIReg64(R_RSP),mkU64(sz)) );
12180 putIReg64(R_RSP, mkexpr(t1) );
12181 storeLE( mkexpr(t1), mkU(ty,d64) );
sewardj1027dc22005-02-26 01:55:02 +000012182 DIP("push%c $%lld\n", nameISize(sz), (Long)d64);
sewardja6b93d12005-02-17 09:28:28 +000012183 break;
12184
sewardj85520e42005-02-19 15:22:38 +000012185 case 0x9C: /* PUSHF */ {
12186 /* Note. There is no encoding for a 32-bit pushf in 64-bit
12187 mode. So sz==4 actually means sz==8. */
sewardj5b470602005-02-27 13:10:48 +000012188 if (haveF2orF3(pfx)) goto decode_failure;
sewardj85520e42005-02-19 15:22:38 +000012189 vassert(sz == 2 || sz == 4);
12190 if (sz == 4) sz = 8;
sewardj5b470602005-02-27 13:10:48 +000012191 if (sz != 8) goto decode_failure; // until we know a sz==2 test case exists
sewardj85520e42005-02-19 15:22:38 +000012192
12193 t1 = newTemp(Ity_I64);
12194 assign( t1, binop(Iop_Sub64,getIReg64(R_RSP),mkU64(sz)) );
12195 putIReg64(R_RSP, mkexpr(t1) );
12196
12197 t2 = newTemp(Ity_I64);
12198 assign( t2, mk_amd64g_calculate_rflags_all() );
12199
12200 /* Patch in the D flag. This can simply be a copy of bit 10 of
12201 baseBlock[OFFB_DFLAG]. */
12202 t3 = newTemp(Ity_I64);
12203 assign( t3, binop(Iop_Or64,
12204 mkexpr(t2),
12205 binop(Iop_And64,
12206 IRExpr_Get(OFFB_DFLAG,Ity_I64),
12207 mkU64(1<<10)))
12208 );
12209
12210 /* And patch in the ID flag. */
12211 t4 = newTemp(Ity_I64);
12212 assign( t4, binop(Iop_Or64,
12213 mkexpr(t3),
12214 binop(Iop_And64,
12215 binop(Iop_Shl64, IRExpr_Get(OFFB_IDFLAG,Ity_I64),
12216 mkU8(21)),
12217 mkU64(1<<21)))
12218 );
12219
12220 /* if sz==2, the stored value needs to be narrowed. */
12221 if (sz == 2)
12222 storeLE( mkexpr(t1), unop(Iop_32to16,
12223 unop(Iop_64to32,mkexpr(t4))) );
12224 else
12225 storeLE( mkexpr(t1), mkexpr(t4) );
12226
12227 DIP("pushf%c\n", nameISize(sz));
12228 break;
12229 }
12230
sewardjd20c8852005-01-20 20:04:07 +000012231//.. case 0x60: /* PUSHA */
12232//.. /* This is almost certainly wrong for sz==2. So ... */
12233//.. if (sz != 4) goto decode_failure;
12234//..
12235//.. /* This is the Right Way, in that the value to be pushed is
12236//.. established before %esp is changed, so that pusha
12237//.. correctly pushes the old %esp value. New value of %esp is
12238//.. pushed at start. */
12239//.. /* t0 is the %ESP value we're going to push. */
12240//.. t0 = newTemp(Ity_I32);
12241//.. assign( t0, getIReg(4, R_ESP) );
12242//..
12243//.. /* t5 will be the new %ESP value. */
12244//.. t5 = newTemp(Ity_I32);
12245//.. assign( t5, binop(Iop_Sub32, mkexpr(t0), mkU32(8*4)) );
12246//..
12247//.. /* Update guest state before prodding memory. */
12248//.. putIReg(4, R_ESP, mkexpr(t5));
12249//..
12250//.. /* Dump all the registers. */
12251//.. storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(28)), getIReg(4,R_EAX) );
12252//.. storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(24)), getIReg(4,R_ECX) );
12253//.. storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(20)), getIReg(4,R_EDX) );
12254//.. storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(16)), getIReg(4,R_EBX) );
12255//.. storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(12)), mkexpr(t0) /*esp*/);
12256//.. storeLE( binop(Iop_Add32,mkexpr(t5),mkU32( 8)), getIReg(4,R_EBP) );
12257//.. storeLE( binop(Iop_Add32,mkexpr(t5),mkU32( 4)), getIReg(4,R_ESI) );
12258//.. storeLE( binop(Iop_Add32,mkexpr(t5),mkU32( 0)), getIReg(4,R_EDI) );
12259//..
12260//.. DIP("pusha%c\n", nameISize(sz));
12261//.. break;
12262//..
12263//..
12264//.. //-- case 0x0E: /* PUSH %CS */
12265//.. //-- dis_push_segreg( cb, R_CS, sz ); break;
12266//.. //-- case 0x1E: /* PUSH %DS */
12267//.. //-- dis_push_segreg( cb, R_DS, sz ); break;
12268//.. //-- case 0x06: /* PUSH %ES */
12269//.. //-- dis_push_segreg( cb, R_ES, sz ); break;
12270//.. //-- case 0x16: /* PUSH %SS */
12271//.. //-- dis_push_segreg( cb, R_SS, sz ); break;
12272//..
12273//.. /* ------------------------ SCAS et al ----------------- */
12274//..
12275//.. case 0xA4: /* MOVS, no REP prefix */
12276//.. case 0xA5:
12277//.. dis_string_op( dis_MOVS, ( opc == 0xA4 ? 1 : sz ), "movs", sorb );
12278//.. break;
12279//..
12280//.. case 0xA6: /* CMPSb, no REP prefix */
12281//.. //-- case 0xA7:
12282//.. dis_string_op( dis_CMPS, ( opc == 0xA6 ? 1 : sz ), "cmps", sorb );
12283//.. break;
12284//.. //--
sewardjd20c8852005-01-20 20:04:07 +000012285//.. //--
12286//.. //-- case 0xAC: /* LODS, no REP prefix */
12287//.. //-- case 0xAD:
12288//.. //-- dis_string_op( cb, dis_LODS, ( opc == 0xAC ? 1 : sz ), "lods", sorb );
12289//.. //-- break;
12290//..
12291//.. case 0xAE: /* SCAS, no REP prefix */
12292//.. case 0xAF:
12293//.. dis_string_op( dis_SCAS, ( opc == 0xAE ? 1 : sz ), "scas", sorb );
12294//.. break;
sewardjd0a12df2005-02-10 02:07:43 +000012295
12296
12297 case 0xFC: /* CLD */
sewardj5b470602005-02-27 13:10:48 +000012298 if (haveF2orF3(pfx)) goto decode_failure;
sewardjd0a12df2005-02-10 02:07:43 +000012299 stmt( IRStmt_Put( OFFB_DFLAG, mkU64(1)) );
12300 DIP("cld\n");
12301 break;
12302
sewardj909c06d2005-02-19 22:47:41 +000012303 case 0xFD: /* STD */
sewardj5b470602005-02-27 13:10:48 +000012304 if (haveF2orF3(pfx)) goto decode_failure;
sewardj909c06d2005-02-19 22:47:41 +000012305 stmt( IRStmt_Put( OFFB_DFLAG, mkU64(-1ULL)) );
12306 DIP("std\n");
12307 break;
12308
sewardjd20c8852005-01-20 20:04:07 +000012309//.. //-- case 0xF8: /* CLC */
12310//.. //-- uInstr0(cb, CALLM_S, 0);
12311//.. //-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_CLC));
12312//.. //-- uFlagsRWU(cb, FlagsEmpty, FlagC, FlagsOSZAP);
12313//.. //-- uInstr0(cb, CALLM_E, 0);
12314//.. //-- DIP("clc\n");
12315//.. //-- break;
12316//.. //--
12317//.. //-- case 0xF9: /* STC */
12318//.. //-- uInstr0(cb, CALLM_S, 0);
12319//.. //-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_STC));
12320//.. //-- uFlagsRWU(cb, FlagsEmpty, FlagC, FlagsOSZAP);
12321//.. //-- uInstr0(cb, CALLM_E, 0);
12322//.. //-- DIP("stc\n");
12323//.. //-- break;
12324//.. //--
12325//.. //-- case 0xF5: /* CMC */
12326//.. //-- uInstr0(cb, CALLM_S, 0);
12327//.. //-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_CMC));
12328//.. //-- uFlagsRWU(cb, FlagC, FlagC, FlagsOSZAP);
12329//.. //-- uInstr0(cb, CALLM_E, 0);
12330//.. //-- DIP("cmc\n");
12331//.. //-- break;
12332//..
12333//.. /* REPNE prefix insn */
12334//.. case 0xF2: {
12335//.. Addr32 eip_orig = guest_eip_bbstart + delta - 1;
12336//.. vassert(sorb == 0);
sewardj8c332e22005-01-28 01:36:56 +000012337//.. abyte = getUChar(delta); delta++;
sewardjd20c8852005-01-20 20:04:07 +000012338//..
sewardj8c332e22005-01-28 01:36:56 +000012339//.. if (abyte == 0x66) { sz = 2; abyte = getUChar(delta); delta++; }
sewardjd20c8852005-01-20 20:04:07 +000012340//.. whatNext = Dis_StopHere;
12341//..
12342//.. switch (abyte) {
12343//.. /* According to the Intel manual, "repne movs" should never occur, but
12344//.. * in practice it has happened, so allow for it here... */
12345//.. case 0xA4: sz = 1; /* REPNE MOVS<sz> */
12346//.. goto decode_failure;
12347//.. //-- case 0xA5:
12348//.. // dis_REP_op ( CondNZ, dis_MOVS, sz, eip_orig,
12349//.. // guest_eip_bbstart+delta, "repne movs" );
12350//.. // break;
12351//.. //--
12352//.. //-- case 0xA6: sz = 1; /* REPNE CMPS<sz> */
12353//.. //-- case 0xA7:
12354//.. //-- dis_REP_op ( cb, CondNZ, dis_CMPS, sz, eip_orig, eip, "repne cmps" );
12355//.. //-- break;
12356//.. //--
12357//.. case 0xAE: sz = 1; /* REPNE SCAS<sz> */
12358//.. case 0xAF:
12359//.. dis_REP_op ( X86CondNZ, dis_SCAS, sz, eip_orig,
12360//.. guest_eip_bbstart+delta, "repne scas" );
12361//.. break;
12362//..
12363//.. default:
12364//.. goto decode_failure;
12365//.. }
12366//.. break;
12367//.. }
sewardjd0a12df2005-02-10 02:07:43 +000012368
sewardj909c06d2005-02-19 22:47:41 +000012369 /* ------ AE: SCAS variants ------ */
12370 case 0xAE:
12371 case 0xAF:
12372 /* F2 AE/AF: repne scasb/repne scas{w,l,q} */
sewardj85520e42005-02-19 15:22:38 +000012373 if (haveF2(pfx) && !haveF3(pfx)) {
12374 if (opc == 0xAE)
12375 sz = 1;
12376 dis_REP_op ( AMD64CondNZ, dis_SCAS, sz,
12377 guest_rip_curr_instr,
sewardj909c06d2005-02-19 22:47:41 +000012378 guest_rip_bbstart+delta, "repne scas", pfx );
sewardj85520e42005-02-19 15:22:38 +000012379 whatNext = Dis_StopHere;
12380 break;
12381 }
sewardj909c06d2005-02-19 22:47:41 +000012382 /* AE/AF: scasb/scas{w,l,q} */
12383 if (!haveF2(pfx) && !haveF3(pfx)) {
12384 if (opc == 0xAE)
12385 sz = 1;
12386 dis_string_op( dis_SCAS, sz, "scas", pfx );
12387 break;
12388 }
sewardj85520e42005-02-19 15:22:38 +000012389 goto decode_failure;
sewardjd0a12df2005-02-10 02:07:43 +000012390
sewardj909c06d2005-02-19 22:47:41 +000012391 /* ------ A6, A7: CMPS variants ------ */
12392 case 0xA6:
12393 case 0xA7:
12394 /* F3 A6/A7: repe cmps/rep cmps{w,l,q} */
sewardjd0a12df2005-02-10 02:07:43 +000012395 if (haveF3(pfx) && !haveF2(pfx)) {
12396 if (opc == 0xA6)
12397 sz = 1;
12398 dis_REP_op ( AMD64CondZ, dis_CMPS, sz,
sewardja6b93d12005-02-17 09:28:28 +000012399 guest_rip_curr_instr,
sewardj909c06d2005-02-19 22:47:41 +000012400 guest_rip_bbstart+delta, "repe cmps", pfx );
sewardja6b93d12005-02-17 09:28:28 +000012401 whatNext = Dis_StopHere;
12402 break;
12403 }
12404 goto decode_failure;
12405
sewardj909c06d2005-02-19 22:47:41 +000012406 /* ------ AA, AB: STOS variants ------ */
12407 case 0xAA:
12408 case 0xAB:
12409 /* F3 AA/AB: rep stosb/rep stos{w,l,q} */
sewardja6b93d12005-02-17 09:28:28 +000012410 if (haveF3(pfx) && !haveF2(pfx)) {
sewardj909c06d2005-02-19 22:47:41 +000012411 if (opc == 0xAA)
12412 sz = 1;
sewardja6b93d12005-02-17 09:28:28 +000012413 dis_REP_op ( AMD64CondAlways, dis_STOS, sz,
12414 guest_rip_curr_instr,
sewardj909c06d2005-02-19 22:47:41 +000012415 guest_rip_bbstart+delta, "rep stos", pfx );
12416 whatNext = Dis_StopHere;
12417 break;
12418 }
12419 /* AA/AB: stosb/stos{w,l,q} */
12420 if (!haveF3(pfx) && !haveF2(pfx)) {
12421 if (opc == 0xAA)
12422 sz = 1;
12423 dis_string_op( dis_STOS, sz, "stos", pfx );
sewardjd0a12df2005-02-10 02:07:43 +000012424 break;
12425 }
12426 goto decode_failure;
12427
sewardj909c06d2005-02-19 22:47:41 +000012428 /* ------ A4, A5: MOVS variants ------ */
12429 case 0xA4:
12430 case 0xA5:
12431 /* F3 A4: rep movsb */
12432 if (haveF3(pfx) && !haveF2(pfx)) {
12433 if (opc == 0xA4)
12434 sz = 1;
12435 dis_REP_op ( AMD64CondAlways, dis_MOVS, sz,
12436 guest_rip_curr_instr,
12437 guest_rip_bbstart+delta, "rep movs", pfx );
12438 whatNext = Dis_StopHere;
12439 break;
12440 }
12441 /* A4: movsb */
12442 if (!haveF3(pfx) && !haveF2(pfx)) {
12443 if (opc == 0xA4)
12444 sz = 1;
12445 dis_string_op( dis_MOVS, sz, "movs", pfx );
12446 break;
12447 }
12448 goto decode_failure;
12449
12450//.. case 0xA5:
12451//.. dis_string_op( dis_MOVS, ( opc == 0xA4 ? 1 : sz ), "movs", sorb );
12452//.. break;
12453
12454//.. case 0xA4: /* MOVS, no REP prefix */
12455//.. case 0xA5:
12456//.. dis_string_op( dis_MOVS, ( opc == 0xA4 ? 1 : sz ), "movs", sorb );
12457//.. break;
12458
sewardjd0a12df2005-02-10 02:07:43 +000012459//.. case 0xF3: {
sewardjd20c8852005-01-20 20:04:07 +000012460//.. Addr32 eip_orig = guest_eip_bbstart + delta - 1;
12461//.. vassert(sorb == 0);
sewardj8c332e22005-01-28 01:36:56 +000012462//.. abyte = getUChar(delta); delta++;
sewardjd20c8852005-01-20 20:04:07 +000012463//..
sewardj8c332e22005-01-28 01:36:56 +000012464//.. if (abyte == 0x66) { sz = 2; abyte = getUChar(delta); delta++; }
sewardjd20c8852005-01-20 20:04:07 +000012465//.. whatNext = Dis_StopHere;
12466//..
12467//.. switch (abyte) {
12468//.. case 0xA4: sz = 1; /* REP MOVS<sz> */
12469//.. case 0xA5:
12470//.. dis_REP_op ( X86CondAlways, dis_MOVS, sz, eip_orig,
12471//.. guest_eip_bbstart+delta, "rep movs" );
12472//.. break;
12473//..
12474//.. case 0xA6: sz = 1; /* REPE CMP<sz> */
12475//.. case 0xA7:
12476//.. dis_REP_op ( X86CondZ, dis_CMPS, sz, eip_orig,
12477//.. guest_eip_bbstart+delta, "repe cmps" );
12478//.. break;
12479//..
12480//.. case 0xAA: sz = 1; /* REP STOS<sz> */
12481//.. case 0xAB:
12482//.. dis_REP_op ( X86CondAlways, dis_STOS, sz, eip_orig,
12483//.. guest_eip_bbstart+delta, "rep stos" );
12484//.. break;
12485//.. //--
12486//.. //-- case 0xAE: sz = 1; /* REPE SCAS<sz> */
12487//.. //-- case 0xAF:
12488//.. //-- dis_REP_op ( cb, CondZ, dis_SCAS, sz, eip_orig, eip, "repe scas" );
12489//.. //-- break;
12490//..
12491//.. case 0x90: /* REP NOP (PAUSE) */
12492//.. /* a hint to the P4 re spin-wait loop */
12493//.. DIP("rep nop (P4 pause)\n");
12494//.. jmp_lit(Ijk_Yield, ((Addr32)guest_eip_bbstart)+delta);
12495//.. whatNext = Dis_StopHere;
12496//.. break;
12497//..
12498//.. //-- case 0xC3: /* REP RET */
12499//.. //-- /* AMD K7/K8-specific optimisation; faster than vanilla RET */
12500//.. //-- dis_ret(cb, 0);
12501//.. //-- DIP("rep ret\n");
12502//.. //-- break;
12503//..
12504//.. default:
12505//.. goto decode_failure;
12506//.. }
12507//.. break;
12508//.. }
sewardj7de0d3c2005-02-13 02:26:41 +000012509
12510 /* ------------------------ XCHG ----------------------- */
12511
sewardjd20c8852005-01-20 20:04:07 +000012512//.. case 0x86: /* XCHG Gb,Eb */
12513//.. sz = 1;
12514//.. /* Fall through ... */
sewardj7de0d3c2005-02-13 02:26:41 +000012515 case 0x87: /* XCHG Gv,Ev */
sewardj5b470602005-02-27 13:10:48 +000012516 if (haveF2orF3(pfx)) goto decode_failure;
sewardj7de0d3c2005-02-13 02:26:41 +000012517 modrm = getUChar(delta);
12518 ty = szToITy(sz);
12519 t1 = newTemp(ty); t2 = newTemp(ty);
12520 if (epartIsReg(modrm)) {
sewardj5b470602005-02-27 13:10:48 +000012521 assign(t1, getIRegE(sz, pfx, modrm));
12522 assign(t2, getIRegG(sz, pfx, modrm));
12523 putIRegG(sz, pfx, modrm, mkexpr(t1));
12524 putIRegE(sz, pfx, modrm, mkexpr(t2));
sewardj7de0d3c2005-02-13 02:26:41 +000012525 delta++;
12526 DIP("xchg%c %s, %s\n",
sewardj5b470602005-02-27 13:10:48 +000012527 nameISize(sz), nameIRegG(sz, pfx, modrm),
12528 nameIRegE(sz, pfx, modrm));
sewardj7de0d3c2005-02-13 02:26:41 +000012529 } else {
12530 goto decode_failure; /* awaiting test case */
12531 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
sewardj5b470602005-02-27 13:10:48 +000012532 assign( t1, loadLE(ty, mkexpr(addr)) );
12533 assign( t2, getIRegG(sz, pfx, modrm) );
sewardj7de0d3c2005-02-13 02:26:41 +000012534 storeLE( mkexpr(addr), mkexpr(t2) );
sewardj5b470602005-02-27 13:10:48 +000012535 putIRegG( sz, pfx, modrm, mkexpr(t1) );
sewardj7de0d3c2005-02-13 02:26:41 +000012536 delta += alen;
12537 DIP("xchg%c %s, %s\n", nameISize(sz),
sewardj5b470602005-02-27 13:10:48 +000012538 nameIRegG(sz, pfx, modrm), dis_buf);
sewardj7de0d3c2005-02-13 02:26:41 +000012539 }
12540 break;
sewardj118b23e2005-01-29 02:14:44 +000012541
12542 case 0x90: /* XCHG eAX,eAX */
sewardja6b93d12005-02-17 09:28:28 +000012543 if (haveF2orF3(pfx)) goto decode_failure;
sewardj8d965312005-02-25 02:48:47 +000012544 DIP("nop\n");
12545 break;
sewardja6b93d12005-02-17 09:28:28 +000012546 case 0x91: /* XCHG rAX,rCX */
12547 case 0x92: /* XCHG rAX,rDX */
12548 case 0x93: /* XCHG rAX,rBX */
12549 case 0x94: /* XCHG rAX,rSP */
12550 case 0x95: /* XCHG rAX,rBP */
12551 case 0x96: /* XCHG rAX,rSI */
12552 case 0x97: /* XCHG rAX,rDI */
12553 if (haveF2orF3(pfx)) goto decode_failure;
12554 if (sz != 8) goto decode_failure; /* temp hack */
12555 codegen_xchg_rAX_Reg ( pfx, sz, opc - 0x90 );
12556 break;
12557
sewardjd20c8852005-01-20 20:04:07 +000012558//.. //-- /* ------------------------ XLAT ----------------------- */
12559//.. //--
12560//.. //-- case 0xD7: /* XLAT */
12561//.. //-- t1 = newTemp(cb); t2 = newTemp(cb);
12562//.. //-- uInstr2(cb, GET, sz, ArchReg, R_EBX, TempReg, t1); /* get eBX */
12563//.. //-- handleSegOverride( cb, sorb, t1 ); /* make t1 DS:eBX */
12564//.. //-- uInstr2(cb, GET, 1, ArchReg, R_AL, TempReg, t2); /* get AL */
12565//.. //-- /* Widen %AL to 32 bits, so it's all defined when we add it. */
12566//.. //-- uInstr1(cb, WIDEN, 4, TempReg, t2);
12567//.. //-- uWiden(cb, 1, False);
12568//.. //-- uInstr2(cb, ADD, sz, TempReg, t2, TempReg, t1); /* add AL to eBX */
12569//.. //-- uInstr2(cb, LOAD, 1, TempReg, t1, TempReg, t2); /* get byte at t1 into t2 */
12570//.. //-- uInstr2(cb, PUT, 1, TempReg, t2, ArchReg, R_AL); /* put byte into AL */
12571//.. //--
12572//.. //-- DIP("xlat%c [ebx]\n", nameISize(sz));
12573//.. //-- break;
12574//.. //--
12575//.. //-- /* ------------------------ IN / OUT ----------------------- */
12576//.. //--
12577//.. //-- case 0xE4: /* IN ib, %al */
12578//.. //-- case 0xE5: /* IN ib, %{e}ax */
12579//.. //-- case 0xEC: /* IN (%dx),%al */
12580//.. //-- case 0xED: /* IN (%dx),%{e}ax */
12581//.. //-- t1 = newTemp(cb);
12582//.. //-- t2 = newTemp(cb);
12583//.. //-- t3 = newTemp(cb);
12584//.. //--
12585//.. //-- uInstr0(cb, CALLM_S, 0);
12586//.. //-- /* operand size? */
12587//.. //-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t1);
12588//.. //-- uLiteral(cb, ( opc == 0xE4 || opc == 0xEC ) ? 1 : sz);
12589//.. //-- uInstr1(cb, PUSH, 4, TempReg, t1);
12590//.. //-- /* port number ? */
12591//.. //-- if ( opc == 0xE4 || opc == 0xE5 ) {
12592//.. //-- abyte = getUChar(eip); eip++;
12593//.. //-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
12594//.. //-- uLiteral(cb, abyte);
12595//.. //-- }
12596//.. //-- else
12597//.. //-- uInstr2(cb, GET, 4, ArchReg, R_EDX, TempReg, t2);
12598//.. //--
12599//.. //-- uInstr1(cb, PUSH, 4, TempReg, t2);
12600//.. //-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_IN));
12601//.. //-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
12602//.. //-- uInstr1(cb, POP, 4, TempReg, t2);
12603//.. //-- uInstr1(cb, CLEAR, 0, Lit16, 4);
12604//.. //-- uInstr0(cb, CALLM_E, 0);
12605//.. //-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_EAX);
12606//.. //-- if ( opc == 0xE4 || opc == 0xE5 ) {
12607//.. //-- DIP("in 0x%x, %%eax/%%ax/%%al\n", getUChar(eip-1) );
12608//.. //-- } else {
12609//.. //-- DIP("in (%%dx), %%eax/%%ax/%%al\n");
12610//.. //-- }
12611//.. //-- break;
12612//.. //-- case 0xE6: /* OUT %al,ib */
12613//.. //-- case 0xE7: /* OUT %{e}ax,ib */
12614//.. //-- case 0xEE: /* OUT %al,(%dx) */
12615//.. //-- case 0xEF: /* OUT %{e}ax,(%dx) */
12616//.. //-- t1 = newTemp(cb);
12617//.. //-- t2 = newTemp(cb);
12618//.. //-- t3 = newTemp(cb);
12619//.. //--
12620//.. //-- uInstr0(cb, CALLM_S, 0);
12621//.. //-- /* operand size? */
12622//.. //-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t1);
12623//.. //-- uLiteral(cb, ( opc == 0xE6 || opc == 0xEE ) ? 1 : sz);
12624//.. //-- uInstr1(cb, PUSH, 4, TempReg, t1);
12625//.. //-- /* port number ? */
12626//.. //-- if ( opc == 0xE6 || opc == 0xE7 ) {
12627//.. //-- abyte = getUChar(eip); eip++;
12628//.. //-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
12629//.. //-- uLiteral(cb, abyte);
12630//.. //-- }
12631//.. //-- else
12632//.. //-- uInstr2(cb, GET, 4, ArchReg, R_EDX, TempReg, t2);
12633//.. //-- uInstr1(cb, PUSH, 4, TempReg, t2);
12634//.. //-- uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, t3);
12635//.. //-- uInstr1(cb, PUSH, 4, TempReg, t3);
12636//.. //-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_OUT));
12637//.. //-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
12638//.. //-- uInstr1(cb, CLEAR, 0, Lit16, 12);
12639//.. //-- uInstr0(cb, CALLM_E, 0);
12640//.. //-- if ( opc == 0xE4 || opc == 0xE5 ) {
12641//.. //-- DIP("out %%eax/%%ax/%%al, 0x%x\n", getUChar(eip-1) );
12642//.. //-- } else {
12643//.. //-- DIP("out %%eax/%%ax/%%al, (%%dx)\n");
12644//.. //-- }
12645//.. //-- break;
sewardj3ca55a12005-01-27 16:06:23 +000012646
12647 /* ------------------------ (Grp1 extensions) ---------- */
12648
12649 case 0x80: /* Grp1 Ib,Eb */
sewardj5b470602005-02-27 13:10:48 +000012650 if (haveF2orF3(pfx)) goto decode_failure;
sewardj8c332e22005-01-28 01:36:56 +000012651 modrm = getUChar(delta);
sewardj3ca55a12005-01-27 16:06:23 +000012652 am_sz = lengthAMode(pfx,delta);
12653 sz = 1;
12654 d_sz = 1;
12655 d64 = getSDisp8(delta + am_sz);
12656 delta = dis_Grp1 ( pfx, delta, modrm, am_sz, d_sz, sz, d64 );
12657 break;
12658
12659 case 0x81: /* Grp1 Iv,Ev */
12660 if (haveF2orF3(pfx)) goto decode_failure;
sewardj8c332e22005-01-28 01:36:56 +000012661 modrm = getUChar(delta);
sewardj3ca55a12005-01-27 16:06:23 +000012662 am_sz = lengthAMode(pfx,delta);
12663 d_sz = imin(sz,4);
12664 d64 = getSDisp(d_sz, delta + am_sz);
12665 delta = dis_Grp1 ( pfx, delta, modrm, am_sz, d_sz, sz, d64 );
12666 break;
12667
12668 case 0x83: /* Grp1 Ib,Ev */
12669 if (haveF2orF3(pfx)) goto decode_failure;
sewardj8c332e22005-01-28 01:36:56 +000012670 modrm = getUChar(delta);
sewardj3ca55a12005-01-27 16:06:23 +000012671 am_sz = lengthAMode(pfx,delta);
12672 d_sz = 1;
12673 d64 = getSDisp8(delta + am_sz);
12674 delta = dis_Grp1 ( pfx, delta, modrm, am_sz, d_sz, sz, d64 );
12675 break;
12676
sewardj118b23e2005-01-29 02:14:44 +000012677 /* ------------------------ (Grp2 extensions) ---------- */
sewardj03b07cc2005-01-31 18:09:43 +000012678
sewardj118b23e2005-01-29 02:14:44 +000012679 case 0xC0: /* Grp2 Ib,Eb */
sewardj5b470602005-02-27 13:10:48 +000012680 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000012681 modrm = getUChar(delta);
12682 am_sz = lengthAMode(pfx,delta);
12683 d_sz = 1;
12684 d64 = getUChar(delta + am_sz);
12685 sz = 1;
12686 delta = dis_Grp2 ( pfx, delta, modrm, am_sz, d_sz, sz,
12687 mkU8(d64 & 0xFF), NULL );
12688 break;
sewardj03b07cc2005-01-31 18:09:43 +000012689
sewardj118b23e2005-01-29 02:14:44 +000012690 case 0xC1: /* Grp2 Ib,Ev */
sewardj5b470602005-02-27 13:10:48 +000012691 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000012692 modrm = getUChar(delta);
12693 am_sz = lengthAMode(pfx,delta);
12694 d_sz = 1;
12695 d64 = getUChar(delta + am_sz);
12696 delta = dis_Grp2 ( pfx, delta, modrm, am_sz, d_sz, sz,
12697 mkU8(d64 & 0xFF), NULL );
12698 break;
12699
sewardj03b07cc2005-01-31 18:09:43 +000012700 case 0xD0: /* Grp2 1,Eb */
sewardj5b470602005-02-27 13:10:48 +000012701 if (haveF2orF3(pfx)) goto decode_failure;
sewardj03b07cc2005-01-31 18:09:43 +000012702 modrm = getUChar(delta);
12703 am_sz = lengthAMode(pfx,delta);
12704 d_sz = 0;
12705 d64 = 1;
12706 sz = 1;
12707 delta = dis_Grp2 ( pfx, delta, modrm, am_sz, d_sz, sz,
12708 mkU8(d64), NULL );
12709 break;
sewardj118b23e2005-01-29 02:14:44 +000012710
12711 case 0xD1: /* Grp2 1,Ev */
sewardj5b470602005-02-27 13:10:48 +000012712 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000012713 modrm = getUChar(delta);
12714 am_sz = lengthAMode(pfx,delta);
12715 d_sz = 0;
12716 d64 = 1;
12717 delta = dis_Grp2 ( pfx, delta, modrm, am_sz, d_sz, sz,
12718 mkU8(d64), NULL );
12719 break;
12720
sewardj85520e42005-02-19 15:22:38 +000012721 case 0xD2: /* Grp2 CL,Eb */
sewardj5b470602005-02-27 13:10:48 +000012722 if (haveF2orF3(pfx)) goto decode_failure;
sewardj85520e42005-02-19 15:22:38 +000012723 modrm = getUChar(delta);
12724 am_sz = lengthAMode(pfx,delta);
12725 d_sz = 0;
12726 sz = 1;
12727 delta = dis_Grp2 ( pfx, delta, modrm, am_sz, d_sz, sz,
sewardj5b470602005-02-27 13:10:48 +000012728 getIRegCL(), "%cl" );
sewardj85520e42005-02-19 15:22:38 +000012729 break;
sewardj118b23e2005-01-29 02:14:44 +000012730
12731 case 0xD3: /* Grp2 CL,Ev */
sewardj5b470602005-02-27 13:10:48 +000012732 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000012733 modrm = getUChar(delta);
12734 am_sz = lengthAMode(pfx,delta);
12735 d_sz = 0;
12736 delta = dis_Grp2 ( pfx, delta, modrm, am_sz, d_sz, sz,
sewardj5b470602005-02-27 13:10:48 +000012737 getIRegCL(), "%cl" );
sewardj118b23e2005-01-29 02:14:44 +000012738 break;
sewardj32b2bbe2005-01-28 00:50:10 +000012739
12740 /* ------------------------ (Grp3 extensions) ---------- */
12741
sewardj118b23e2005-01-29 02:14:44 +000012742 case 0xF6: /* Grp3 Eb */
sewardj5b470602005-02-27 13:10:48 +000012743 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000012744 delta = dis_Grp3 ( pfx, 1, delta );
12745 break;
sewardj32b2bbe2005-01-28 00:50:10 +000012746 case 0xF7: /* Grp3 Ev */
sewardj5b470602005-02-27 13:10:48 +000012747 if (haveF2orF3(pfx)) goto decode_failure;
sewardj32b2bbe2005-01-28 00:50:10 +000012748 delta = dis_Grp3 ( pfx, sz, delta );
12749 break;
12750
sewardj03b07cc2005-01-31 18:09:43 +000012751 /* ------------------------ (Grp4 extensions) ---------- */
12752
12753 case 0xFE: /* Grp4 Eb */
sewardj5b470602005-02-27 13:10:48 +000012754 if (haveF2orF3(pfx)) goto decode_failure;
sewardj03b07cc2005-01-31 18:09:43 +000012755 delta = dis_Grp4 ( pfx, delta );
12756 break;
sewardj354e5c62005-01-27 20:12:52 +000012757
12758 /* ------------------------ (Grp5 extensions) ---------- */
12759
12760 case 0xFF: /* Grp5 Ev */
sewardj5b470602005-02-27 13:10:48 +000012761 if (haveF2orF3(pfx)) goto decode_failure;
sewardj354e5c62005-01-27 20:12:52 +000012762 delta = dis_Grp5 ( pfx, sz, delta, &whatNext );
12763 break;
sewardj3ca55a12005-01-27 16:06:23 +000012764
12765 /* ------------------------ Escapes to 2-byte opcodes -- */
12766
12767 case 0x0F: {
sewardj8c332e22005-01-28 01:36:56 +000012768 opc = getUChar(delta); delta++;
sewardj3ca55a12005-01-27 16:06:23 +000012769 switch (opc) {
12770
sewardjd20c8852005-01-20 20:04:07 +000012771//.. //-- /* =-=-=-=-=-=-=-=-=- Grp8 =-=-=-=-=-=-=-=-=-=-=-= */
12772//.. //--
12773//.. //-- case 0xBA: /* Grp8 Ib,Ev */
12774//.. //-- modrm = getUChar(eip);
12775//.. //-- am_sz = lengthAMode(eip);
12776//.. //-- d32 = getSDisp8(eip + am_sz);
12777//.. //-- eip = dis_Grp8_BT ( cb, sorb, eip, modrm, am_sz, sz, d32 );
12778//.. //-- break;
12779//..
12780//.. /* =-=-=-=-=-=-=-=-=- BSF/BSR -=-=-=-=-=-=-=-=-=-= */
12781//..
12782//.. case 0xBC: /* BSF Gv,Ev */
12783//.. delta = dis_bs_E_G ( sorb, sz, delta, True );
12784//.. break;
12785//.. case 0xBD: /* BSR Gv,Ev */
12786//.. delta = dis_bs_E_G ( sorb, sz, delta, False );
12787//.. break;
12788//..
12789//.. /* =-=-=-=-=-=-=-=-=- BSWAP -=-=-=-=-=-=-=-=-=-=-= */
12790//..
12791//.. case 0xC8: /* BSWAP %eax */
12792//.. case 0xC9:
12793//.. case 0xCA:
12794//.. case 0xCB:
12795//.. case 0xCC:
12796//.. case 0xCD:
12797//.. case 0xCE:
12798//.. case 0xCF: /* BSWAP %edi */
12799//.. /* AFAICS from the Intel docs, this only exists at size 4. */
12800//.. vassert(sz == 4);
12801//.. t1 = newTemp(Ity_I32);
12802//.. t2 = newTemp(Ity_I32);
12803//.. assign( t1, getIReg(4, opc-0xC8) );
12804//..
12805//.. assign( t2,
12806//.. binop(Iop_Or32,
12807//.. binop(Iop_Shl32, mkexpr(t1), mkU8(24)),
12808//.. binop(Iop_Or32,
12809//.. binop(Iop_And32, binop(Iop_Shl32, mkexpr(t1), mkU8(8)),
12810//.. mkU32(0x00FF0000)),
12811//.. binop(Iop_Or32,
12812//.. binop(Iop_And32, binop(Iop_Shr32, mkexpr(t1), mkU8(8)),
12813//.. mkU32(0x0000FF00)),
12814//.. binop(Iop_And32, binop(Iop_Shr32, mkexpr(t1), mkU8(24)),
12815//.. mkU32(0x000000FF) )
12816//.. )))
12817//.. );
12818//..
12819//.. putIReg(4, opc-0xC8, mkexpr(t2));
12820//.. DIP("bswapl %s\n", nameIReg(4, opc-0xC8));
12821//.. break;
12822//..
12823//.. /* =-=-=-=-=-=-=-=-=- BT/BTS/BTR/BTC =-=-=-=-=-=-= */
12824//..
12825//.. case 0xA3: /* BT Gv,Ev */
12826//.. delta = dis_bt_G_E ( sorb, sz, delta, BtOpNone );
12827//.. break;
12828//.. case 0xB3: /* BTR Gv,Ev */
12829//.. delta = dis_bt_G_E ( sorb, sz, delta, BtOpReset );
12830//.. break;
12831//.. case 0xAB: /* BTS Gv,Ev */
12832//.. delta = dis_bt_G_E ( sorb, sz, delta, BtOpSet );
12833//.. break;
12834//.. case 0xBB: /* BTC Gv,Ev */
12835//.. delta = dis_bt_G_E ( sorb, sz, delta, BtOpComp );
12836//.. break;
sewardj3ca55a12005-01-27 16:06:23 +000012837
12838 /* =-=-=-=-=-=-=-=-=- CMOV =-=-=-=-=-=-=-=-=-=-=-= */
12839
12840 case 0x40:
12841 case 0x41:
12842 case 0x42: /* CMOVBb/CMOVNAEb (cmov below) */
12843 case 0x43: /* CMOVNBb/CMOVAEb (cmov not below) */
12844 case 0x44: /* CMOVZb/CMOVEb (cmov zero) */
12845 case 0x45: /* CMOVNZb/CMOVNEb (cmov not zero) */
12846 case 0x46: /* CMOVBEb/CMOVNAb (cmov below or equal) */
12847 case 0x47: /* CMOVNBEb/CMOVAb (cmov not below or equal) */
12848 case 0x48: /* CMOVSb (cmov negative) */
12849 case 0x49: /* CMOVSb (cmov not negative) */
12850 case 0x4A: /* CMOVP (cmov parity even) */
12851 case 0x4B: /* CMOVNP (cmov parity odd) */
12852 case 0x4C: /* CMOVLb/CMOVNGEb (cmov less) */
12853 case 0x4D: /* CMOVGEb/CMOVNLb (cmov greater or equal) */
12854 case 0x4E: /* CMOVLEb/CMOVNGb (cmov less or equal) */
12855 case 0x4F: /* CMOVGb/CMOVNLEb (cmov greater) */
sewardj5b470602005-02-27 13:10:48 +000012856 if (haveF2orF3(pfx)) goto decode_failure;
sewardj3ca55a12005-01-27 16:06:23 +000012857 delta = dis_cmov_E_G(pfx, sz, (AMD64Condcode)(opc - 0x40), delta);
12858 break;
12859
sewardja6b93d12005-02-17 09:28:28 +000012860 /* =-=-=-=-=-=-=-=-=- CMPXCHG -=-=-=-=-=-=-=-=-=-= */
12861
sewardjd20c8852005-01-20 20:04:07 +000012862//.. case 0xB0: /* CMPXCHG Gb,Eb */
12863//.. delta = dis_cmpxchg_G_E ( sorb, 1, delta );
12864//.. break;
sewardja6b93d12005-02-17 09:28:28 +000012865 case 0xB1: /* CMPXCHG Gv,Ev */
sewardj5b470602005-02-27 13:10:48 +000012866 if (haveF2orF3(pfx)) goto decode_failure;
sewardja6b93d12005-02-17 09:28:28 +000012867 delta = dis_cmpxchg_G_E ( pfx, sz, delta );
12868 break;
sewardjd20c8852005-01-20 20:04:07 +000012869//.. //-- case 0xC7: /* CMPXCHG8B Gv */
12870//.. //-- eip = dis_cmpxchg8b ( cb, sorb, eip );
12871//.. //-- break;
12872//.. //--
sewardjd0a12df2005-02-10 02:07:43 +000012873 /* =-=-=-=-=-=-=-=-=- CPUID -=-=-=-=-=-=-=-=-=-=-= */
12874
12875 case 0xA2: { /* CPUID */
12876 /* Uses dirty helper:
12877 void amd64g_dirtyhelper_CPUID ( VexGuestAMD64State* )
12878 declared to mod rax, wr rbx, rcx, rdx
12879 */
12880 IRDirty* d = NULL;
12881 HChar* fName = NULL;
12882 void* fAddr = NULL;
sewardj5b470602005-02-27 13:10:48 +000012883 if (haveF2orF3(pfx)) goto decode_failure;
sewardjd0a12df2005-02-10 02:07:43 +000012884 switch (subarch) {
12885 case VexSubArch_NONE:
12886 fName = "amd64g_dirtyhelper_CPUID";
12887 fAddr = &amd64g_dirtyhelper_CPUID;
12888 break;
12889 default:
12890 vpanic("disInstr(amd64)(cpuid)");
12891 }
12892 vassert(fName); vassert(fAddr);
12893 d = unsafeIRDirty_0_N ( 0/*regparms*/,
12894 fName, fAddr, mkIRExprVec_0() );
12895 /* declare guest state effects */
12896 d->needsBBP = True;
12897 d->nFxState = 4;
12898 d->fxState[0].fx = Ifx_Modify;
12899 d->fxState[0].offset = OFFB_RAX;
12900 d->fxState[0].size = 8;
12901 d->fxState[1].fx = Ifx_Write;
12902 d->fxState[1].offset = OFFB_RBX;
12903 d->fxState[1].size = 8;
12904 d->fxState[2].fx = Ifx_Write;
12905 d->fxState[2].offset = OFFB_RCX;
12906 d->fxState[2].size = 8;
12907 d->fxState[3].fx = Ifx_Write;
12908 d->fxState[3].offset = OFFB_RDX;
12909 d->fxState[3].size = 8;
12910 /* execute the dirty call, side-effecting guest state */
12911 stmt( IRStmt_Dirty(d) );
12912 /* CPUID is a serialising insn. So, just in case someone is
12913 using it as a memory fence ... */
12914 stmt( IRStmt_MFence() );
12915 DIP("cpuid\n");
12916 break;
12917 }
12918
sewardj5e525292005-01-28 15:13:10 +000012919 /* =-=-=-=-=-=-=-=-=- MOVZX, MOVSX =-=-=-=-=-=-=-= */
12920
12921 case 0xB6: /* MOVZXb Eb,Gv */
sewardj5b470602005-02-27 13:10:48 +000012922 if (haveF2orF3(pfx)) goto decode_failure;
sewardj5e525292005-01-28 15:13:10 +000012923 if (sz != 2 && sz != 4 && sz != 8)
12924 goto decode_failure;
12925 delta = dis_movx_E_G ( pfx, delta, 1, sz, False );
12926 break;
12927 case 0xB7: /* MOVZXw Ew,Gv */
sewardj5b470602005-02-27 13:10:48 +000012928 if (haveF2orF3(pfx)) goto decode_failure;
sewardj5e525292005-01-28 15:13:10 +000012929 if (sz != 4 && sz != 8)
12930 goto decode_failure;
12931 delta = dis_movx_E_G ( pfx, delta, 2, sz, False );
12932 break;
12933
sewardj03b07cc2005-01-31 18:09:43 +000012934 case 0xBE: /* MOVSXb Eb,Gv */
sewardj5b470602005-02-27 13:10:48 +000012935 if (haveF2orF3(pfx)) goto decode_failure;
sewardj03b07cc2005-01-31 18:09:43 +000012936 if (sz != 4 && sz != 8)
12937 goto decode_failure;
12938 delta = dis_movx_E_G ( pfx, delta, 1, sz, True );
12939 break;
12940 case 0xBF: /* MOVSXw Ew,Gv */
sewardj5b470602005-02-27 13:10:48 +000012941 if (haveF2orF3(pfx)) goto decode_failure;
sewardj03b07cc2005-01-31 18:09:43 +000012942 if (sz != 4 && sz != 8)
12943 goto decode_failure;
12944 delta = dis_movx_E_G ( pfx, delta, 2, sz, True );
12945 break;
12946
sewardjd20c8852005-01-20 20:04:07 +000012947//.. //-- /* =-=-=-=-=-=-=-=-=-=-= MOVNTI -=-=-=-=-=-=-=-=-= */
12948//.. //--
12949//.. //-- case 0xC3: /* MOVNTI Gv,Ev */
12950//.. //-- vg_assert(sz == 4);
12951//.. //-- modrm = getUChar(eip);
12952//.. //-- vg_assert(!epartIsReg(modrm));
12953//.. //-- t1 = newTemp(cb);
12954//.. //-- uInstr2(cb, GET, 4, ArchReg, gregOfRM(modrm), TempReg, t1);
12955//.. //-- pair = disAMode ( cb, sorb, eip, dis_buf );
12956//.. //-- t2 = LOW24(pair);
12957//.. //-- eip += HI8(pair);
12958//.. //-- uInstr2(cb, STORE, 4, TempReg, t1, TempReg, t2);
12959//.. //-- DIP("movnti %s,%s\n", nameIReg(4,gregOfRM(modrm)), dis_buf);
12960//.. //-- break;
sewardj32b2bbe2005-01-28 00:50:10 +000012961
12962 /* =-=-=-=-=-=-=-=-=- MUL/IMUL =-=-=-=-=-=-=-=-=-= */
12963
12964 case 0xAF: /* IMUL Ev, Gv */
sewardj5b470602005-02-27 13:10:48 +000012965 if (haveF2orF3(pfx)) goto decode_failure;
sewardj32b2bbe2005-01-28 00:50:10 +000012966 delta = dis_mul_E_G ( pfx, sz, delta );
12967 break;
12968
sewardj1389d4d2005-01-28 13:46:29 +000012969 /* =-=-=-=-=-=-=-=-=- Jcond d32 -=-=-=-=-=-=-=-=-= */
12970 case 0x80:
12971 case 0x81:
12972 case 0x82: /* JBb/JNAEb (jump below) */
12973 case 0x83: /* JNBb/JAEb (jump not below) */
12974 case 0x84: /* JZb/JEb (jump zero) */
12975 case 0x85: /* JNZb/JNEb (jump not zero) */
12976 case 0x86: /* JBEb/JNAb (jump below or equal) */
12977 case 0x87: /* JNBEb/JAb (jump not below or equal) */
12978 case 0x88: /* JSb (jump negative) */
12979 case 0x89: /* JSb (jump not negative) */
12980 case 0x8A: /* JP (jump parity even) */
12981 case 0x8B: /* JNP/JPO (jump parity odd) */
12982 case 0x8C: /* JLb/JNGEb (jump less) */
12983 case 0x8D: /* JGEb/JNLb (jump greater or equal) */
12984 case 0x8E: /* JLEb/JNGb (jump less or equal) */
12985 case 0x8F: /* JGb/JNLEb (jump greater) */
sewardj5b470602005-02-27 13:10:48 +000012986 if (haveF2orF3(pfx)) goto decode_failure;
sewardj1389d4d2005-01-28 13:46:29 +000012987 d64 = (guest_rip_bbstart+delta+4) + getSDisp32(delta);
12988 delta += 4;
12989 jcc_01( (AMD64Condcode)(opc - 0x80),
12990 guest_rip_bbstart+delta,
12991 d64 );
12992 whatNext = Dis_StopHere;
12993 DIP("j%s-32 0x%llx\n", name_AMD64Condcode(opc - 0x80), d64);
12994 break;
12995
sewardj31191072005-02-05 18:24:47 +000012996 /* =-=-=-=-=-=-=-=-=- RDTSC -=-=-=-=-=-=-=-=-=-=-= */
12997
12998 case 0x31: /* RDTSC */
sewardj5b470602005-02-27 13:10:48 +000012999 if (haveF2orF3(pfx)) goto decode_failure;
sewardj31191072005-02-05 18:24:47 +000013000 if (1) vex_printf("vex amd64->IR: kludged rdtsc\n");
sewardj5b470602005-02-27 13:10:48 +000013001 putIRegRAX(4, mkU32(0));
13002 putIRegRDX(4, mkU32(0));
sewardj31191072005-02-05 18:24:47 +000013003
sewardjd20c8852005-01-20 20:04:07 +000013004//.. //-- t1 = newTemp(cb);
13005//.. //-- t2 = newTemp(cb);
13006//.. //-- t3 = newTemp(cb);
13007//.. //-- uInstr0(cb, CALLM_S, 0);
13008//.. //-- // Nb: even though these args aren't used by RDTSC_helper, need
13009//.. //-- // them to be defined (for Memcheck). The TempRegs pushed must
13010//.. //-- // also be distinct.
13011//.. //-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t1);
13012//.. //-- uLiteral(cb, 0);
13013//.. //-- uInstr1(cb, PUSH, 4, TempReg, t1);
13014//.. //-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
13015//.. //-- uLiteral(cb, 0);
13016//.. //-- uInstr1(cb, PUSH, 4, TempReg, t2);
13017//.. //-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_RDTSC));
13018//.. //-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
13019//.. //-- uInstr1(cb, POP, 4, TempReg, t3);
13020//.. //-- uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_EDX);
13021//.. //-- uInstr1(cb, POP, 4, TempReg, t3);
13022//.. //-- uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_EAX);
13023//.. //-- uInstr0(cb, CALLM_E, 0);
sewardj31191072005-02-05 18:24:47 +000013024 DIP("rdtsc\n");
13025 break;
13026
sewardjd20c8852005-01-20 20:04:07 +000013027//.. /* =-=-=-=-=-=-=-=-=- PUSH/POP Sreg =-=-=-=-=-=-=-=-=-= */
13028//..
13029//.. case 0xA1: /* POP %FS */
13030//.. dis_pop_segreg( R_FS, sz ); break;
13031//.. case 0xA9: /* POP %GS */
13032//.. dis_pop_segreg( R_GS, sz ); break;
13033//..
13034//.. case 0xA0: /* PUSH %FS */
13035//.. dis_push_segreg( R_FS, sz ); break;
13036//.. case 0xA8: /* PUSH %GS */
13037//.. dis_push_segreg( R_GS, sz ); break;
sewardj118b23e2005-01-29 02:14:44 +000013038
13039 /* =-=-=-=-=-=-=-=-=- SETcc Eb =-=-=-=-=-=-=-=-=-= */
13040 case 0x90:
13041 case 0x91:
13042 case 0x92: /* set-Bb/set-NAEb (set if below) */
13043 case 0x93: /* set-NBb/set-AEb (set if not below) */
13044 case 0x94: /* set-Zb/set-Eb (set if zero) */
13045 case 0x95: /* set-NZb/set-NEb (set if not zero) */
13046 case 0x96: /* set-BEb/set-NAb (set if below or equal) */
13047 case 0x97: /* set-NBEb/set-Ab (set if not below or equal) */
13048 case 0x98: /* set-Sb (set if negative) */
13049 case 0x99: /* set-Sb (set if not negative) */
13050 case 0x9A: /* set-P (set if parity even) */
13051 case 0x9B: /* set-NP (set if parity odd) */
13052 case 0x9C: /* set-Lb/set-NGEb (set if less) */
13053 case 0x9D: /* set-GEb/set-NLb (set if greater or equal) */
13054 case 0x9E: /* set-LEb/set-NGb (set if less or equal) */
13055 case 0x9F: /* set-Gb/set-NLEb (set if greater) */
sewardj5b470602005-02-27 13:10:48 +000013056 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000013057 t1 = newTemp(Ity_I8);
13058 assign( t1, unop(Iop_1Uto8,mk_amd64g_calculate_condition(opc-0x90)) );
13059 modrm = getUChar(delta);
13060 if (epartIsReg(modrm)) {
13061 delta++;
sewardj5b470602005-02-27 13:10:48 +000013062 putIRegE(1, pfx, modrm, mkexpr(t1));
sewardj118b23e2005-01-29 02:14:44 +000013063 DIP("set%s %s\n", name_AMD64Condcode(opc-0x90),
sewardj5b470602005-02-27 13:10:48 +000013064 nameIRegE(1,pfx,modrm));
sewardj118b23e2005-01-29 02:14:44 +000013065 } else {
sewardje1698952005-02-08 15:02:39 +000013066 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
sewardj118b23e2005-01-29 02:14:44 +000013067 delta += alen;
13068 storeLE( mkexpr(addr), mkexpr(t1) );
13069 DIP("set%s %s\n", name_AMD64Condcode(opc-0x90), dis_buf);
13070 }
13071 break;
13072
sewardjd20c8852005-01-20 20:04:07 +000013073//.. /* =-=-=-=-=-=-=-=-=- SHLD/SHRD -=-=-=-=-=-=-=-=-= */
13074//..
13075//.. case 0xA4: /* SHLDv imm8,Gv,Ev */
sewardj8c332e22005-01-28 01:36:56 +000013076//.. modrm = getUChar(delta);
sewardjd20c8852005-01-20 20:04:07 +000013077//.. d32 = delta + lengthAMode(delta);
13078//.. vex_sprintf(dis_buf, "$%d", delta);
13079//.. delta = dis_SHLRD_Gv_Ev (
13080//.. sorb, delta, modrm, sz,
sewardj8c332e22005-01-28 01:36:56 +000013081//.. mkU8(getUChar(d32)), True, /* literal */
sewardjd20c8852005-01-20 20:04:07 +000013082//.. dis_buf, True );
13083//.. break;
13084//.. case 0xA5: /* SHLDv %cl,Gv,Ev */
sewardj8c332e22005-01-28 01:36:56 +000013085//.. modrm = getUChar(delta);
sewardjd20c8852005-01-20 20:04:07 +000013086//.. delta = dis_SHLRD_Gv_Ev (
13087//.. sorb, delta, modrm, sz,
13088//.. getIReg(1,R_ECX), False, /* not literal */
13089//.. "%cl", True );
13090//.. break;
13091//..
13092//.. case 0xAC: /* SHRDv imm8,Gv,Ev */
sewardj8c332e22005-01-28 01:36:56 +000013093//.. modrm = getUChar(delta);
sewardjd20c8852005-01-20 20:04:07 +000013094//.. d32 = delta + lengthAMode(delta);
13095//.. vex_sprintf(dis_buf, "$%d", delta);
13096//.. delta = dis_SHLRD_Gv_Ev (
13097//.. sorb, delta, modrm, sz,
sewardj8c332e22005-01-28 01:36:56 +000013098//.. mkU8(getUChar(d32)), True, /* literal */
sewardjd20c8852005-01-20 20:04:07 +000013099//.. dis_buf, False );
13100//.. break;
13101//.. case 0xAD: /* SHRDv %cl,Gv,Ev */
sewardj8c332e22005-01-28 01:36:56 +000013102//.. modrm = getUChar(delta);
sewardjd20c8852005-01-20 20:04:07 +000013103//.. delta = dis_SHLRD_Gv_Ev (
13104//.. sorb, delta, modrm, sz,
13105//.. getIReg(1,R_ECX), False, /* not literal */
13106//.. "%cl", False );
13107//.. break;
sewardje1698952005-02-08 15:02:39 +000013108
13109 /* =-=-=-=-=-=-=-=-=- SYSCALL -=-=-=-=-=-=-=-=-=-= */
13110 case 0x05: /* SYSCALL */
13111 guest_rip_next_mustcheck = True;
13112 guest_rip_next_assumed = guest_rip_bbstart + delta;
13113 putIReg64( R_RCX, mkU64(guest_rip_next_assumed) );
13114 /* It's important that all guest state is up-to-date
13115 at this point. So we declare an end-of-block here, which
13116 forces any cached guest state to be flushed. */
13117 jmp_lit(Ijk_Syscall, guest_rip_next_assumed);
13118 whatNext = Dis_StopHere;
13119 DIP("syscall\n");
13120 break;
13121
sewardjd20c8852005-01-20 20:04:07 +000013122//.. /* =-=-=-=-=-=-=-=-=- XADD -=-=-=-=-=-=-=-=-=-= */
13123//..
13124//.. //-- case 0xC0: /* XADD Gb,Eb */
13125//.. //-- eip = dis_xadd_G_E ( cb, sorb, 1, eip );
13126//.. //-- break;
13127//.. case 0xC1: /* XADD Gv,Ev */
13128//.. delta = dis_xadd_G_E ( sorb, sz, delta );
13129//.. break;
13130//..
13131//.. /* =-=-=-=-=-=-=-=-=- MMXery =-=-=-=-=-=-=-=-=-=-= */
13132//..
13133//.. case 0x71:
13134//.. case 0x72:
13135//.. case 0x73: /* PSLLgg/PSRAgg/PSRLgg mmxreg by imm8 */
13136//..
13137//.. case 0x6E: /* MOVD (src)ireg-or-mem, (dst)mmxreg */
13138//.. case 0x7E: /* MOVD (src)mmxreg, (dst)ireg-or-mem */
13139//.. case 0x7F: /* MOVQ (src)mmxreg, (dst)mmxreg-or-mem */
13140//.. case 0x6F: /* MOVQ (src)mmxreg-or-mem, (dst)mmxreg */
13141//..
13142//.. case 0xFC:
13143//.. case 0xFD:
13144//.. case 0xFE: /* PADDgg (src)mmxreg-or-mem, (dst)mmxreg */
13145//..
13146//.. case 0xEC:
13147//.. case 0xED: /* PADDSgg (src)mmxreg-or-mem, (dst)mmxreg */
13148//..
13149//.. case 0xDC:
13150//.. case 0xDD: /* PADDUSgg (src)mmxreg-or-mem, (dst)mmxreg */
13151//..
13152//.. case 0xF8:
13153//.. case 0xF9:
13154//.. case 0xFA: /* PSUBgg (src)mmxreg-or-mem, (dst)mmxreg */
13155//..
13156//.. case 0xE8:
13157//.. case 0xE9: /* PSUBSgg (src)mmxreg-or-mem, (dst)mmxreg */
13158//..
13159//.. case 0xD8:
13160//.. case 0xD9: /* PSUBUSgg (src)mmxreg-or-mem, (dst)mmxreg */
13161//..
13162//.. case 0xE5: /* PMULHW (src)mmxreg-or-mem, (dst)mmxreg */
13163//.. case 0xD5: /* PMULLW (src)mmxreg-or-mem, (dst)mmxreg */
13164//..
13165//.. case 0xF5: /* PMADDWD (src)mmxreg-or-mem, (dst)mmxreg */
13166//..
13167//.. case 0x74:
13168//.. case 0x75:
13169//.. case 0x76: /* PCMPEQgg (src)mmxreg-or-mem, (dst)mmxreg */
13170//..
13171//.. case 0x64:
13172//.. case 0x65:
13173//.. case 0x66: /* PCMPGTgg (src)mmxreg-or-mem, (dst)mmxreg */
13174//..
13175//.. case 0x6B: /* PACKSSDW (src)mmxreg-or-mem, (dst)mmxreg */
13176//.. case 0x63: /* PACKSSWB (src)mmxreg-or-mem, (dst)mmxreg */
13177//.. case 0x67: /* PACKUSWB (src)mmxreg-or-mem, (dst)mmxreg */
13178//..
13179//.. case 0x68:
13180//.. case 0x69:
13181//.. case 0x6A: /* PUNPCKHgg (src)mmxreg-or-mem, (dst)mmxreg */
13182//..
13183//.. case 0x60:
13184//.. case 0x61:
13185//.. case 0x62: /* PUNPCKLgg (src)mmxreg-or-mem, (dst)mmxreg */
13186//..
13187//.. case 0xDB: /* PAND (src)mmxreg-or-mem, (dst)mmxreg */
13188//.. case 0xDF: /* PANDN (src)mmxreg-or-mem, (dst)mmxreg */
13189//.. case 0xEB: /* POR (src)mmxreg-or-mem, (dst)mmxreg */
13190//.. case 0xEF: /* PXOR (src)mmxreg-or-mem, (dst)mmxreg */
13191//..
13192//.. case 0xF1: /* PSLLgg (src)mmxreg-or-mem, (dst)mmxreg */
13193//.. case 0xF2:
13194//.. case 0xF3:
13195//..
13196//.. case 0xD1: /* PSRLgg (src)mmxreg-or-mem, (dst)mmxreg */
13197//.. case 0xD2:
13198//.. case 0xD3:
13199//..
13200//.. case 0xE1: /* PSRAgg (src)mmxreg-or-mem, (dst)mmxreg */
13201//.. case 0xE2:
13202//.. {
sewardj9da16972005-02-21 13:58:26 +000013203//.. ULong delta0 = delta-1;
sewardjd20c8852005-01-20 20:04:07 +000013204//.. Bool decode_OK = False;
13205//..
13206//.. /* If sz==2 this is SSE, and we assume sse idec has
13207//.. already spotted those cases by now. */
13208//.. if (sz != 4)
13209//.. goto decode_failure;
13210//..
13211//.. delta = dis_MMX ( &decode_OK, sorb, sz, delta-1 );
13212//.. if (!decode_OK) {
13213//.. delta = delta0;
13214//.. goto decode_failure;
13215//.. }
13216//.. break;
13217//.. }
13218//..
13219//.. case 0x77: /* EMMS */
13220//.. if (sz != 4)
13221//.. goto decode_failure;
13222//.. do_EMMS_preamble();
13223//.. DIP("emms\n");
13224//.. break;
sewardj3ca55a12005-01-27 16:06:23 +000013225
13226 /* =-=-=-=-=-=-=-=-=- unimp2 =-=-=-=-=-=-=-=-=-=-= */
13227
13228 default:
13229 goto decode_failure;
13230 } /* switch (opc) for the 2-byte opcodes */
13231 goto decode_success;
13232 } /* case 0x0F: of primary opcode */
sewardjdf0e0022005-01-25 15:48:43 +000013233
13234 /* ------------------------ ??? ------------------------ */
13235
13236 default:
13237 decode_failure:
13238 /* All decode failures end up here. */
13239 vex_printf("vex amd64->IR: unhandled instruction bytes: "
13240 "0x%x 0x%x 0x%x 0x%x\n",
sewardj8c332e22005-01-28 01:36:56 +000013241 (Int)getUChar(delta_start+0),
13242 (Int)getUChar(delta_start+1),
13243 (Int)getUChar(delta_start+2),
13244 (Int)getUChar(delta_start+3) );
sewardjdf0e0022005-01-25 15:48:43 +000013245
13246 /* Tell the dispatcher that this insn cannot be decoded, and so has
13247 not been executed, and (is currently) the next to be executed.
13248 RIP should be up-to-date since it made so at the start of each
13249 insn, but nevertheless be paranoid and update it again right
13250 now. */
13251 stmt( IRStmt_Put( OFFB_RIP, mkU64(guest_rip_curr_instr) ) );
13252 jmp_lit(Ijk_NoDecode, guest_rip_curr_instr);
13253 whatNext = Dis_StopHere;
13254 *size = 0;
13255 return whatNext;
13256
13257 } /* switch (opc) for the main (primary) opcode switch. */
13258
13259 decode_success:
13260 /* All decode successes end up here. */
13261 DIP("\n");
sewardjdf0e0022005-01-25 15:48:43 +000013262 *size = delta - delta_start;
13263 return whatNext;
13264}
13265
13266#undef DIP
13267#undef DIS
sewardjd20c8852005-01-20 20:04:07 +000013268
13269/*--------------------------------------------------------------------*/
13270/*--- end guest-amd64/toIR.c ---*/
13271/*--------------------------------------------------------------------*/