blob: d3d410cffbfa5bf7c7efb0cdb4e42a5c9c8cb1f2 [file] [log] [blame]
sewardjd20c8852005-01-20 20:04:07 +00001
2/*--------------------------------------------------------------------*/
3/*--- ---*/
4/*--- This file (guest-amd64/toIR.c) is ---*/
sewardjdbcfae72005-08-02 11:14:04 +00005/*--- Copyright (C) OpenWorks LLP. All rights reserved. ---*/
sewardjd20c8852005-01-20 20:04:07 +00006/*--- ---*/
7/*--------------------------------------------------------------------*/
8
9/*
10 This file is part of LibVEX, a library for dynamic binary
11 instrumentation and translation.
12
sewardj496a58d2005-03-20 18:44:44 +000013 Copyright (C) 2004-2005 OpenWorks LLP.
sewardjd20c8852005-01-20 20:04:07 +000014
15 This program is free software; you can redistribute it and/or modify
16 it under the terms of the GNU General Public License as published by
17 the Free Software Foundation; Version 2 dated June 1991 of the
18 license.
19
20 This program is distributed in the hope that it will be useful,
21 but WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or liability
23 for damages. See the GNU General Public License for more details.
24
25 Neither the names of the U.S. Department of Energy nor the
26 University of California nor the names of its contributors may be
27 used to endorse or promote products derived from this software
28 without prior written permission.
29
30 You should have received a copy of the GNU General Public License
31 along with this program; if not, write to the Free Software
32 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
33 USA.
34*/
35
sewardj9ff93bc2005-03-23 11:25:12 +000036/* LIMITATIONS:
37
38 LOCK prefix handling is only safe in the situation where
39 Vex-generated code is run single-threadedly. (This is not the same
40 as saying that Valgrind can't safely use Vex to run multithreaded
41 programs). See comment attached to LOCK prefix handling in
42 disInstr for details.
43*/
44
sewardjd20c8852005-01-20 20:04:07 +000045//.. /* TODO:
sewardjd20c8852005-01-20 20:04:07 +000046//..
47//.. check flag settings for cmpxchg
48//.. FUCOMI(P): what happens to A and S flags? Currently are forced
49//.. to zero.
50//..
51//.. x87 FP Limitations:
52//..
53//.. * all arithmetic done at 64 bits
54//..
55//.. * no FP exceptions, except for handling stack over/underflow
56//..
57//.. * FP rounding mode observed only for float->int conversions
58//.. and int->float conversions which could lose accuracy, and
59//.. for float-to-float rounding. For all other operations,
60//.. round-to-nearest is used, regardless.
61//..
62//.. * FP sin/cos/tan/sincos: C2 flag is always cleared. IOW the
63//.. simulation claims the argument is in-range (-2^63 <= arg <= 2^63)
64//.. even when it isn't.
65//..
66//.. * some of the FCOM cases could do with testing -- not convinced
67//.. that the args are the right way round.
68//..
69//.. * FSAVE does not re-initialise the FPU; it should do
70//..
71//.. * FINIT not only initialises the FPU environment, it also
72//.. zeroes all the FP registers. It should leave the registers
73//.. unchanged.
74//..
75//.. RDTSC returns zero, always.
76//..
77//.. SAHF should cause eflags[1] == 1, and in fact it produces 0. As
78//.. per Intel docs this bit has no meaning anyway. Since PUSHF is the
79//.. only way to observe eflags[1], a proper fix would be to make that
80//.. bit be set by PUSHF.
81//..
82//.. This module uses global variables and so is not MT-safe (if that
83//.. should ever become relevant). */
sewardj44d494d2005-01-20 20:26:33 +000084
85/* Translates AMD64 code to IR. */
86
87#include "libvex_basictypes.h"
88#include "libvex_ir.h"
89#include "libvex.h"
90#include "libvex_guest_amd64.h"
91
92#include "main/vex_util.h"
93#include "main/vex_globals.h"
sewardj9e6491a2005-07-02 19:24:10 +000094#include "guest-generic/bb_to_IR.h"
sewardj44d494d2005-01-20 20:26:33 +000095#include "guest-amd64/gdefs.h"
96
97
sewardjecb94892005-01-21 14:26:37 +000098/*------------------------------------------------------------*/
99/*--- Globals ---*/
100/*------------------------------------------------------------*/
101
sewardj9e6491a2005-07-02 19:24:10 +0000102/* These are set at the start of the translation of an insn, right
103 down in disInstr_AMD64, so that we don't have to pass them around
104 endlessly. They are all constant during the translation of any
105 given insn. */
sewardj4b744762005-02-07 15:02:25 +0000106
sewardjecb94892005-01-21 14:26:37 +0000107/* These are set at the start of the translation of a BB, so
108 that we don't have to pass them around endlessly. */
109
110/* We need to know this to do sub-register accesses correctly. */
sewardjecb94892005-01-21 14:26:37 +0000111static Bool host_is_bigendian;
112
sewardj9e6491a2005-07-02 19:24:10 +0000113/* Pointer to the guest code area (points to start of BB, not to the
114 insn being processed). */
sewardjb3a04292005-01-21 20:33:44 +0000115static UChar* guest_code;
116
sewardjdf0e0022005-01-25 15:48:43 +0000117/* The guest address corresponding to guest_code[0]. */
sewardj9e6491a2005-07-02 19:24:10 +0000118static Addr64 guest_RIP_bbstart;
sewardj4b744762005-02-07 15:02:25 +0000119
sewardjb3a04292005-01-21 20:33:44 +0000120/* The guest address for the instruction currently being
121 translated. */
sewardj9e6491a2005-07-02 19:24:10 +0000122static Addr64 guest_RIP_curr_instr;
sewardjecb94892005-01-21 14:26:37 +0000123
sewardj9e6491a2005-07-02 19:24:10 +0000124/* The IRBB* into which we're generating code. */
125static IRBB* irbb;
sewardjecb94892005-01-21 14:26:37 +0000126
sewardj4b744762005-02-07 15:02:25 +0000127/* For ensuring that %rip-relative addressing is done right. A read
128 of %rip generates the address of the next instruction. It may be
129 that we don't conveniently know that inside disAMode(). For sanity
130 checking, if the next insn %rip is needed, we make a guess at what
131 it is, record that guess here, and set the accompanying Bool to
132 indicate that -- after this insn's decode is finished -- that guess
133 needs to be checked. */
134
135/* At the start of each insn decode, is set to (0, False).
136 After the decode, if _mustcheck is now True, _assumed is
137 checked. */
138
sewardj9e6491a2005-07-02 19:24:10 +0000139static Addr64 guest_RIP_next_assumed;
140static Bool guest_RIP_next_mustcheck;
sewardj4b744762005-02-07 15:02:25 +0000141
142
sewardjecb94892005-01-21 14:26:37 +0000143/*------------------------------------------------------------*/
144/*--- Helpers for constructing IR. ---*/
145/*------------------------------------------------------------*/
146
sewardjb3a04292005-01-21 20:33:44 +0000147/* Generate a new temporary of the given type. */
148static IRTemp newTemp ( IRType ty )
149{
sewardj496a58d2005-03-20 18:44:44 +0000150 vassert(isPlausibleIRType(ty));
sewardjb3a04292005-01-21 20:33:44 +0000151 return newIRTemp( irbb->tyenv, ty );
152}
153
sewardjecb94892005-01-21 14:26:37 +0000154/* Add a statement to the list held by "irbb". */
155static void stmt ( IRStmt* st )
156{
157 addStmtToIRBB( irbb, st );
158}
sewardjb3a04292005-01-21 20:33:44 +0000159
160/* Generate a statement "dst := e". */
161static void assign ( IRTemp dst, IRExpr* e )
162{
163 stmt( IRStmt_Tmp(dst, e) );
164}
165
sewardjecb94892005-01-21 14:26:37 +0000166static IRExpr* unop ( IROp op, IRExpr* a )
167{
168 return IRExpr_Unop(op, a);
169}
170
sewardjb3a04292005-01-21 20:33:44 +0000171static IRExpr* binop ( IROp op, IRExpr* a1, IRExpr* a2 )
172{
173 return IRExpr_Binop(op, a1, a2);
174}
175
sewardjdf0e0022005-01-25 15:48:43 +0000176static IRExpr* mkexpr ( IRTemp tmp )
177{
178 return IRExpr_Tmp(tmp);
179}
sewardjb3a04292005-01-21 20:33:44 +0000180
sewardj3ca55a12005-01-27 16:06:23 +0000181static IRExpr* mkU8 ( ULong i )
sewardjb3a04292005-01-21 20:33:44 +0000182{
183 vassert(i < 256);
sewardj3ca55a12005-01-27 16:06:23 +0000184 return IRExpr_Const(IRConst_U8( (UChar)i ));
sewardjb3a04292005-01-21 20:33:44 +0000185}
186
sewardj5e525292005-01-28 15:13:10 +0000187static IRExpr* mkU16 ( ULong i )
188{
189 vassert(i < 0x10000ULL);
190 return IRExpr_Const(IRConst_U16( (UShort)i ));
191}
sewardj3ca55a12005-01-27 16:06:23 +0000192
193static IRExpr* mkU32 ( ULong i )
194{
195 vassert(i < 0x100000000ULL);
196 return IRExpr_Const(IRConst_U32( (UInt)i ));
197}
sewardjb3a04292005-01-21 20:33:44 +0000198
199static IRExpr* mkU64 ( ULong i )
200{
201 return IRExpr_Const(IRConst_U64(i));
202}
sewardjecb94892005-01-21 14:26:37 +0000203
sewardj3ca55a12005-01-27 16:06:23 +0000204static IRExpr* mkU ( IRType ty, ULong i )
205{
206 switch (ty) {
207 case Ity_I8: return mkU8(i);
sewardj5e525292005-01-28 15:13:10 +0000208 case Ity_I16: return mkU16(i);
sewardj3ca55a12005-01-27 16:06:23 +0000209 case Ity_I32: return mkU32(i);
210 case Ity_I64: return mkU64(i);
211 default: vpanic("mkU(amd64)");
212 }
213}
214
sewardj5e525292005-01-28 15:13:10 +0000215static void storeLE ( IRExpr* addr, IRExpr* data )
216{
sewardjaf1ceca2005-06-30 23:31:27 +0000217 stmt( IRStmt_Store(Iend_LE,addr,data) );
sewardj5e525292005-01-28 15:13:10 +0000218}
219
220static IRExpr* loadLE ( IRType ty, IRExpr* data )
221{
sewardjaf1ceca2005-06-30 23:31:27 +0000222 return IRExpr_Load(Iend_LE,ty,data);
sewardj5e525292005-01-28 15:13:10 +0000223}
224
225static IROp mkSizedOp ( IRType ty, IROp op8 )
226{
227 vassert(op8 == Iop_Add8 || op8 == Iop_Sub8
228 || op8 == Iop_Mul8
229 || op8 == Iop_Or8 || op8 == Iop_And8 || op8 == Iop_Xor8
230 || op8 == Iop_Shl8 || op8 == Iop_Shr8 || op8 == Iop_Sar8
231 || op8 == Iop_CmpEQ8 || op8 == Iop_CmpNE8
232 || op8 == Iop_Not8 );
233 switch (ty) {
234 case Ity_I8: return 0 +op8;
235 case Ity_I16: return 1 +op8;
236 case Ity_I32: return 2 +op8;
237 case Ity_I64: return 3 +op8;
238 default: vpanic("mkSizedOp(amd64)");
239 }
240}
241
242static
243IRExpr* doScalarWidening ( Int szSmall, Int szBig, Bool signd, IRExpr* src )
244{
245 if (szSmall == 1 && szBig == 4) {
246 return unop(signd ? Iop_8Sto32 : Iop_8Uto32, src);
247 }
248 if (szSmall == 1 && szBig == 2) {
249 return unop(signd ? Iop_8Sto16 : Iop_8Uto16, src);
250 }
251 if (szSmall == 2 && szBig == 4) {
252 return unop(signd ? Iop_16Sto32 : Iop_16Uto32, src);
253 }
254 if (szSmall == 1 && szBig == 8 && !signd) {
sewardje58967e2005-04-27 11:50:56 +0000255 return unop(Iop_8Uto64, src);
sewardj5e525292005-01-28 15:13:10 +0000256 }
sewardj03b07cc2005-01-31 18:09:43 +0000257 if (szSmall == 1 && szBig == 8 && signd) {
sewardje58967e2005-04-27 11:50:56 +0000258 return unop(Iop_8Sto64, src);
sewardj03b07cc2005-01-31 18:09:43 +0000259 }
sewardj5e525292005-01-28 15:13:10 +0000260 if (szSmall == 2 && szBig == 8 && !signd) {
sewardje58967e2005-04-27 11:50:56 +0000261 return unop(Iop_16Uto64, src);
sewardj5e525292005-01-28 15:13:10 +0000262 }
sewardj03b07cc2005-01-31 18:09:43 +0000263 if (szSmall == 2 && szBig == 8 && signd) {
sewardje58967e2005-04-27 11:50:56 +0000264 return unop(Iop_16Sto64, src);
sewardj03b07cc2005-01-31 18:09:43 +0000265 }
sewardj5e525292005-01-28 15:13:10 +0000266 vpanic("doScalarWidening(amd64)");
267}
268
269
sewardjecb94892005-01-21 14:26:37 +0000270
271/*------------------------------------------------------------*/
272/*--- Debugging output ---*/
273/*------------------------------------------------------------*/
274
sewardjb3a04292005-01-21 20:33:44 +0000275/* Bomb out if we can't handle something. */
276__attribute__ ((noreturn))
277static void unimplemented ( HChar* str )
278{
279 vex_printf("amd64toIR: unimplemented feature\n");
280 vpanic(str);
281}
282
sewardjecb94892005-01-21 14:26:37 +0000283#define DIP(format, args...) \
sewardj9e6491a2005-07-02 19:24:10 +0000284 if (vex_traceflags & VEX_TRACE_FE) \
sewardjecb94892005-01-21 14:26:37 +0000285 vex_printf(format, ## args)
286
287#define DIS(buf, format, args...) \
sewardj9e6491a2005-07-02 19:24:10 +0000288 if (vex_traceflags & VEX_TRACE_FE) \
sewardjecb94892005-01-21 14:26:37 +0000289 vex_sprintf(buf, format, ## args)
290
291
292/*------------------------------------------------------------*/
293/*--- Offsets of various parts of the amd64 guest state. ---*/
294/*------------------------------------------------------------*/
295
296#define OFFB_RAX offsetof(VexGuestAMD64State,guest_RAX)
297#define OFFB_RBX offsetof(VexGuestAMD64State,guest_RBX)
298#define OFFB_RCX offsetof(VexGuestAMD64State,guest_RCX)
299#define OFFB_RDX offsetof(VexGuestAMD64State,guest_RDX)
300#define OFFB_RSP offsetof(VexGuestAMD64State,guest_RSP)
301#define OFFB_RBP offsetof(VexGuestAMD64State,guest_RBP)
302#define OFFB_RSI offsetof(VexGuestAMD64State,guest_RSI)
303#define OFFB_RDI offsetof(VexGuestAMD64State,guest_RDI)
304#define OFFB_R8 offsetof(VexGuestAMD64State,guest_R8)
305#define OFFB_R9 offsetof(VexGuestAMD64State,guest_R9)
306#define OFFB_R10 offsetof(VexGuestAMD64State,guest_R10)
307#define OFFB_R11 offsetof(VexGuestAMD64State,guest_R11)
308#define OFFB_R12 offsetof(VexGuestAMD64State,guest_R12)
309#define OFFB_R13 offsetof(VexGuestAMD64State,guest_R13)
310#define OFFB_R14 offsetof(VexGuestAMD64State,guest_R14)
311#define OFFB_R15 offsetof(VexGuestAMD64State,guest_R15)
312
313#define OFFB_RIP offsetof(VexGuestAMD64State,guest_RIP)
314
sewardja6b93d12005-02-17 09:28:28 +0000315#define OFFB_FS_ZERO offsetof(VexGuestAMD64State,guest_FS_ZERO)
316
sewardjecb94892005-01-21 14:26:37 +0000317#define OFFB_CC_OP offsetof(VexGuestAMD64State,guest_CC_OP)
318#define OFFB_CC_DEP1 offsetof(VexGuestAMD64State,guest_CC_DEP1)
319#define OFFB_CC_DEP2 offsetof(VexGuestAMD64State,guest_CC_DEP2)
320#define OFFB_CC_NDEP offsetof(VexGuestAMD64State,guest_CC_NDEP)
321
sewardj8d965312005-02-25 02:48:47 +0000322#define OFFB_FPREGS offsetof(VexGuestAMD64State,guest_FPREG[0])
323#define OFFB_FPTAGS offsetof(VexGuestAMD64State,guest_FPTAG[0])
sewardjd0a12df2005-02-10 02:07:43 +0000324#define OFFB_DFLAG offsetof(VexGuestAMD64State,guest_DFLAG)
sewardj85520e42005-02-19 15:22:38 +0000325#define OFFB_IDFLAG offsetof(VexGuestAMD64State,guest_IDFLAG)
sewardj8d965312005-02-25 02:48:47 +0000326#define OFFB_FTOP offsetof(VexGuestAMD64State,guest_FTOP)
sewardj25a85812005-05-08 23:03:48 +0000327#define OFFB_FC3210 offsetof(VexGuestAMD64State,guest_FC3210)
sewardjc49ce232005-02-25 13:03:03 +0000328#define OFFB_FPROUND offsetof(VexGuestAMD64State,guest_FPROUND)
sewardjd20c8852005-01-20 20:04:07 +0000329//..
330//.. #define OFFB_CS offsetof(VexGuestX86State,guest_CS)
331//.. #define OFFB_DS offsetof(VexGuestX86State,guest_DS)
332//.. #define OFFB_ES offsetof(VexGuestX86State,guest_ES)
333//.. #define OFFB_FS offsetof(VexGuestX86State,guest_FS)
334//.. #define OFFB_GS offsetof(VexGuestX86State,guest_GS)
335//.. #define OFFB_SS offsetof(VexGuestX86State,guest_SS)
336//.. #define OFFB_LDT offsetof(VexGuestX86State,guest_LDT)
337//.. #define OFFB_GDT offsetof(VexGuestX86State,guest_GDT)
sewardj1001dc42005-02-21 08:25:55 +0000338
339#define OFFB_SSEROUND offsetof(VexGuestAMD64State,guest_SSEROUND)
340#define OFFB_XMM0 offsetof(VexGuestAMD64State,guest_XMM0)
341#define OFFB_XMM1 offsetof(VexGuestAMD64State,guest_XMM1)
342#define OFFB_XMM2 offsetof(VexGuestAMD64State,guest_XMM2)
343#define OFFB_XMM3 offsetof(VexGuestAMD64State,guest_XMM3)
344#define OFFB_XMM4 offsetof(VexGuestAMD64State,guest_XMM4)
345#define OFFB_XMM5 offsetof(VexGuestAMD64State,guest_XMM5)
346#define OFFB_XMM6 offsetof(VexGuestAMD64State,guest_XMM6)
347#define OFFB_XMM7 offsetof(VexGuestAMD64State,guest_XMM7)
348#define OFFB_XMM8 offsetof(VexGuestAMD64State,guest_XMM8)
349#define OFFB_XMM9 offsetof(VexGuestAMD64State,guest_XMM9)
350#define OFFB_XMM10 offsetof(VexGuestAMD64State,guest_XMM10)
351#define OFFB_XMM11 offsetof(VexGuestAMD64State,guest_XMM11)
352#define OFFB_XMM12 offsetof(VexGuestAMD64State,guest_XMM12)
353#define OFFB_XMM13 offsetof(VexGuestAMD64State,guest_XMM13)
354#define OFFB_XMM14 offsetof(VexGuestAMD64State,guest_XMM14)
355#define OFFB_XMM15 offsetof(VexGuestAMD64State,guest_XMM15)
356
sewardjbcbb9de2005-03-27 02:22:32 +0000357#define OFFB_EMWARN offsetof(VexGuestAMD64State,guest_EMWARN)
sewardjdf0e0022005-01-25 15:48:43 +0000358
359
360/*------------------------------------------------------------*/
sewardjecb94892005-01-21 14:26:37 +0000361/*--- Helper bits and pieces for deconstructing the ---*/
362/*--- amd64 insn stream. ---*/
363/*------------------------------------------------------------*/
364
365/* This is the AMD64 register encoding -- integer regs. */
366#define R_RAX 0
367#define R_RCX 1
368#define R_RDX 2
369#define R_RBX 3
370#define R_RSP 4
371#define R_RBP 5
372#define R_RSI 6
373#define R_RDI 7
374#define R_R8 8
375#define R_R9 9
376#define R_R10 10
377#define R_R11 11
378#define R_R12 12
379#define R_R13 13
380#define R_R14 14
381#define R_R15 15
382
sewardjd20c8852005-01-20 20:04:07 +0000383//.. #define R_AL (0+R_EAX)
384//.. #define R_AH (4+R_EAX)
sewardjecb94892005-01-21 14:26:37 +0000385
386/* This is the Intel register encoding -- segment regs. */
387#define R_ES 0
388#define R_CS 1
389#define R_SS 2
390#define R_DS 3
391#define R_FS 4
392#define R_GS 5
393
394
sewardjb3a04292005-01-21 20:33:44 +0000395/* Various simple conversions */
396
397static ULong extend_s_8to64 ( UChar x )
398{
399 return (ULong)((((Long)x) << 56) >> 56);
400}
401
402static ULong extend_s_16to64 ( UShort x )
403{
404 return (ULong)((((Long)x) << 48) >> 48);
405}
406
407static ULong extend_s_32to64 ( UInt x )
408{
409 return (ULong)((((Long)x) << 32) >> 32);
410}
411
sewardjdf0e0022005-01-25 15:48:43 +0000412/* Figure out whether the mod and rm parts of a modRM byte refer to a
413 register or memory. If so, the byte will have the form 11XXXYYY,
414 where YYY is the register number. */
sewardj5b470602005-02-27 13:10:48 +0000415inline
sewardjdf0e0022005-01-25 15:48:43 +0000416static Bool epartIsReg ( UChar mod_reg_rm )
417{
sewardj7a240552005-01-28 21:37:12 +0000418 return toBool(0xC0 == (mod_reg_rm & 0xC0));
sewardjdf0e0022005-01-25 15:48:43 +0000419}
420
sewardj901ed122005-02-27 13:25:31 +0000421/* Extract the 'g' field from a modRM byte. This only produces 3
422 bits, which is not a complete register number. You should avoid
423 this function if at all possible. */
424inline
425static Int gregLO3ofRM ( UChar mod_reg_rm )
sewardjdf0e0022005-01-25 15:48:43 +0000426{
427 return (Int)( (mod_reg_rm >> 3) & 7 );
428}
429
sewardj8711f662005-05-09 17:52:56 +0000430/* Ditto the 'e' field of a modRM byte. */
431inline
432static Int eregLO3ofRM ( UChar mod_reg_rm )
433{
434 return (Int)(mod_reg_rm & 0x7);
435}
436
sewardjdf0e0022005-01-25 15:48:43 +0000437/* Get a 8/16/32-bit unsigned value out of the insn stream. */
438
sewardj270def42005-07-03 01:03:01 +0000439static UChar getUChar ( Long delta )
sewardjdf0e0022005-01-25 15:48:43 +0000440{
sewardj8c332e22005-01-28 01:36:56 +0000441 UChar v = guest_code[delta+0];
442 return v;
sewardjdf0e0022005-01-25 15:48:43 +0000443}
444
sewardj270def42005-07-03 01:03:01 +0000445//.. static UInt getUDisp16 ( Long delta )
sewardjd20c8852005-01-20 20:04:07 +0000446//.. {
447//.. UInt v = guest_code[delta+1]; v <<= 8;
448//.. v |= guest_code[delta+0];
449//.. return v & 0xFFFF;
450//.. }
451//..
sewardj270def42005-07-03 01:03:01 +0000452//.. static UInt getUDisp ( Int size, Long delta )
sewardjd20c8852005-01-20 20:04:07 +0000453//.. {
454//.. switch (size) {
455//.. case 4: return getUDisp32(delta);
456//.. case 2: return getUDisp16(delta);
457//.. case 1: return getUChar(delta);
458//.. default: vpanic("getUDisp(x86)");
459//.. }
460//.. return 0; /*notreached*/
461//.. }
sewardjb3a04292005-01-21 20:33:44 +0000462
463
464/* Get a byte value out of the insn stream and sign-extend to 64
465 bits. */
sewardj270def42005-07-03 01:03:01 +0000466static Long getSDisp8 ( Long delta )
sewardjb3a04292005-01-21 20:33:44 +0000467{
468 return extend_s_8to64( guest_code[delta] );
469}
470
sewardj5e525292005-01-28 15:13:10 +0000471/* Get a 16-bit value out of the insn stream and sign-extend to 64
472 bits. */
sewardj270def42005-07-03 01:03:01 +0000473static Long getSDisp16 ( Long delta )
sewardj5e525292005-01-28 15:13:10 +0000474{
sewardj118b23e2005-01-29 02:14:44 +0000475 UInt v = guest_code[delta+1]; v <<= 8;
sewardj5e525292005-01-28 15:13:10 +0000476 v |= guest_code[delta+0];
sewardj118b23e2005-01-29 02:14:44 +0000477 return extend_s_16to64( (UShort)v );
sewardj5e525292005-01-28 15:13:10 +0000478}
479
sewardjb3a04292005-01-21 20:33:44 +0000480/* Get a 32-bit value out of the insn stream and sign-extend to 64
481 bits. */
sewardj270def42005-07-03 01:03:01 +0000482static Long getSDisp32 ( Long delta )
sewardjb3a04292005-01-21 20:33:44 +0000483{
484 UInt v = guest_code[delta+3]; v <<= 8;
485 v |= guest_code[delta+2]; v <<= 8;
486 v |= guest_code[delta+1]; v <<= 8;
487 v |= guest_code[delta+0];
488 return extend_s_32to64( v );
489}
490
sewardj03b07cc2005-01-31 18:09:43 +0000491/* Get a 64-bit value out of the insn stream. */
sewardj270def42005-07-03 01:03:01 +0000492static Long getDisp64 ( Long delta )
sewardj03b07cc2005-01-31 18:09:43 +0000493{
sewardj7eaa7cf2005-01-31 18:55:22 +0000494 ULong v = 0;
sewardj03b07cc2005-01-31 18:09:43 +0000495 v |= guest_code[delta+7]; v <<= 8;
496 v |= guest_code[delta+6]; v <<= 8;
497 v |= guest_code[delta+5]; v <<= 8;
498 v |= guest_code[delta+4]; v <<= 8;
499 v |= guest_code[delta+3]; v <<= 8;
500 v |= guest_code[delta+2]; v <<= 8;
501 v |= guest_code[delta+1]; v <<= 8;
502 v |= guest_code[delta+0];
503 return v;
504}
505
sewardj3ca55a12005-01-27 16:06:23 +0000506/* Note: because AMD64 doesn't allow 64-bit literals, it is an error
507 if this is called with size==8. Should not happen. */
sewardj270def42005-07-03 01:03:01 +0000508static Long getSDisp ( Int size, Long delta )
sewardj3ca55a12005-01-27 16:06:23 +0000509{
510 switch (size) {
511 case 4: return getSDisp32(delta);
sewardj5e525292005-01-28 15:13:10 +0000512 case 2: return getSDisp16(delta);
sewardj3ca55a12005-01-27 16:06:23 +0000513 case 1: return getSDisp8(delta);
514 default: vpanic("getSDisp(amd64)");
515 }
516}
517
sewardj1389d4d2005-01-28 13:46:29 +0000518static ULong mkSizeMask ( Int sz )
sewardj3ca55a12005-01-27 16:06:23 +0000519{
520 switch (sz) {
sewardj1389d4d2005-01-28 13:46:29 +0000521 case 1: return 0x00000000000000FFULL;
522 case 2: return 0x000000000000FFFFULL;
523 case 4: return 0x00000000FFFFFFFFULL;
sewardj3ca55a12005-01-27 16:06:23 +0000524 case 8: return 0xFFFFFFFFFFFFFFFFULL;
525 default: vpanic("mkSzMask(amd64)");
526 }
527}
528
529static Int imin ( Int a, Int b )
530{
531 return (a < b) ? a : b;
532}
sewardjecb94892005-01-21 14:26:37 +0000533
sewardj5b470602005-02-27 13:10:48 +0000534static IRType szToITy ( Int n )
535{
536 switch (n) {
537 case 1: return Ity_I8;
538 case 2: return Ity_I16;
539 case 4: return Ity_I32;
540 case 8: return Ity_I64;
sewardjf53b7352005-04-06 20:01:56 +0000541 default: vex_printf("\nszToITy(%d)\n", n);
542 vpanic("szToITy(amd64)");
sewardj5b470602005-02-27 13:10:48 +0000543 }
544}
545
sewardjecb94892005-01-21 14:26:37 +0000546
547/*------------------------------------------------------------*/
548/*--- For dealing with prefixes. ---*/
549/*------------------------------------------------------------*/
550
551/* The idea is to pass around an int holding a bitmask summarising
552 info from the prefixes seen on the current instruction, including
553 info from the REX byte. This info is used in various places, but
554 most especially when making sense of register fields in
555 instructions.
556
557 The top 16 bits of the prefix are 0x3141, just as a hacky way
558 to ensure it really is a valid prefix.
sewardjdf0e0022005-01-25 15:48:43 +0000559
560 Things you can safely assume about a well-formed prefix:
561 * at most one segment-override bit (CS,DS,ES,FS,GS,SS) is set.
sewardj5b470602005-02-27 13:10:48 +0000562 * if REX is not present then REXW,REXR,REXX,REXB will read
563 as zero.
sewardjdf0e0022005-01-25 15:48:43 +0000564 * F2 and F3 will not both be 1.
sewardjecb94892005-01-21 14:26:37 +0000565*/
566
567typedef UInt Prefix;
568
sewardj3ca55a12005-01-27 16:06:23 +0000569#define PFX_ASO (1<<0) /* address-size override present (0x67) */
570#define PFX_66 (1<<1) /* operand-size override-to-16 present (0x66) */
571#define PFX_REX (1<<2) /* REX byte present (0x40 to 0x4F) */
572#define PFX_REXW (1<<3) /* REX W bit, if REX present, else 0 */
573#define PFX_REXR (1<<4) /* REX R bit, if REX present, else 0 */
574#define PFX_REXX (1<<5) /* REX X bit, if REX present, else 0 */
575#define PFX_REXB (1<<6) /* REX B bit, if REX present, else 0 */
576#define PFX_LOCK (1<<7) /* bus LOCK prefix present (0xF0) */
577#define PFX_F2 (1<<8) /* REP/REPE/REPZ prefix present (0xF2) */
578#define PFX_F3 (1<<9) /* REPNE/REPNZ prefix present (0xF3) */
579#define PFX_CS (1<<10) /* CS segment prefix present (0x2E) */
580#define PFX_DS (1<<11) /* DS segment prefix present (0x3E) */
581#define PFX_ES (1<<12) /* ES segment prefix present (0x26) */
582#define PFX_FS (1<<13) /* FS segment prefix present (0x64) */
583#define PFX_GS (1<<14) /* GS segment prefix present (0x65) */
584#define PFX_SS (1<<15) /* SS segment prefix present (0x36) */
585
586#define PFX_EMPTY 0x31410000
sewardjecb94892005-01-21 14:26:37 +0000587
sewardjb3a04292005-01-21 20:33:44 +0000588static Bool IS_VALID_PFX ( Prefix pfx ) {
sewardj7a240552005-01-28 21:37:12 +0000589 return toBool((pfx & 0xFFFF0000) == PFX_EMPTY);
sewardjecb94892005-01-21 14:26:37 +0000590}
591
sewardjb3a04292005-01-21 20:33:44 +0000592static Bool haveREX ( Prefix pfx ) {
sewardj7a240552005-01-28 21:37:12 +0000593 return toBool(pfx & PFX_REX);
sewardjecb94892005-01-21 14:26:37 +0000594}
595
sewardj5e525292005-01-28 15:13:10 +0000596static Int getRexW ( Prefix pfx ) {
597 return (pfx & PFX_REXW) ? 1 : 0;
598}
sewardj901ed122005-02-27 13:25:31 +0000599/* Apparently unused.
sewardjdf0e0022005-01-25 15:48:43 +0000600static Int getRexR ( Prefix pfx ) {
601 return (pfx & PFX_REXR) ? 1 : 0;
602}
sewardj901ed122005-02-27 13:25:31 +0000603*/
sewardj5b470602005-02-27 13:10:48 +0000604static Int getRexX ( Prefix pfx ) {
605 return (pfx & PFX_REXX) ? 1 : 0;
606}
sewardjdf0e0022005-01-25 15:48:43 +0000607static Int getRexB ( Prefix pfx ) {
608 return (pfx & PFX_REXB) ? 1 : 0;
609}
610
sewardj3ca55a12005-01-27 16:06:23 +0000611/* Check a prefix doesn't have F2 or F3 set in it, since usually that
612 completely changes what instruction it really is. */
613static Bool haveF2orF3 ( Prefix pfx ) {
sewardj7a240552005-01-28 21:37:12 +0000614 return toBool((pfx & (PFX_F2|PFX_F3)) > 0);
sewardj3ca55a12005-01-27 16:06:23 +0000615}
sewardj55dbb262005-01-28 16:36:51 +0000616static Bool haveF2 ( Prefix pfx ) {
sewardj7a240552005-01-28 21:37:12 +0000617 return toBool((pfx & PFX_F2) > 0);
sewardj55dbb262005-01-28 16:36:51 +0000618}
619static Bool haveF3 ( Prefix pfx ) {
sewardj7a240552005-01-28 21:37:12 +0000620 return toBool((pfx & PFX_F3) > 0);
sewardj55dbb262005-01-28 16:36:51 +0000621}
sewardj6359f812005-07-20 10:15:34 +0000622
sewardjc8b26352005-07-20 09:23:13 +0000623static Bool have66 ( Prefix pfx ) {
624 return toBool((pfx & PFX_66) > 0);
625}
sewardj6359f812005-07-20 10:15:34 +0000626static Bool haveASO ( Prefix pfx ) {
627 return toBool((pfx & PFX_ASO) > 0);
628}
sewardjecb94892005-01-21 14:26:37 +0000629
sewardj1001dc42005-02-21 08:25:55 +0000630/* Return True iff pfx has 66 set and F2 and F3 clear */
631static Bool have66noF2noF3 ( Prefix pfx )
632{
633 return
sewardj8d965312005-02-25 02:48:47 +0000634 toBool((pfx & (PFX_66|PFX_F2|PFX_F3)) == PFX_66);
sewardj1001dc42005-02-21 08:25:55 +0000635}
636
637/* Return True iff pfx has F2 set and 66 and F3 clear */
638static Bool haveF2no66noF3 ( Prefix pfx )
639{
640 return
sewardj8d965312005-02-25 02:48:47 +0000641 toBool((pfx & (PFX_66|PFX_F2|PFX_F3)) == PFX_F2);
642}
643
644/* Return True iff pfx has F3 set and 66 and F2 clear */
645static Bool haveF3no66noF2 ( Prefix pfx )
646{
647 return
648 toBool((pfx & (PFX_66|PFX_F2|PFX_F3)) == PFX_F3);
sewardj1001dc42005-02-21 08:25:55 +0000649}
650
651/* Return True iff pfx has 66, F2 and F3 clear */
652static Bool haveNo66noF2noF3 ( Prefix pfx )
653{
654 return
sewardj8d965312005-02-25 02:48:47 +0000655 toBool((pfx & (PFX_66|PFX_F2|PFX_F3)) == 0);
sewardj1001dc42005-02-21 08:25:55 +0000656}
657
sewardj8711f662005-05-09 17:52:56 +0000658/* Return True iff pfx has any of 66, F2 and F3 set */
659static Bool have66orF2orF3 ( Prefix pfx )
660{
sewardjca673ab2005-05-11 10:03:08 +0000661 return toBool( ! haveNo66noF2noF3(pfx) );
sewardj8711f662005-05-09 17:52:56 +0000662}
663
sewardj1389d4d2005-01-28 13:46:29 +0000664/* Clear all the segment-override bits in a prefix. */
665static Prefix clearSegBits ( Prefix p )
666{
sewardj1001dc42005-02-21 08:25:55 +0000667 return
668 p & ~(PFX_CS | PFX_DS | PFX_ES | PFX_FS | PFX_GS | PFX_SS);
669}
670
sewardj1389d4d2005-01-28 13:46:29 +0000671
sewardjecb94892005-01-21 14:26:37 +0000672/*------------------------------------------------------------*/
sewardj5b470602005-02-27 13:10:48 +0000673/*--- For dealing with integer registers ---*/
sewardjecb94892005-01-21 14:26:37 +0000674/*------------------------------------------------------------*/
675
sewardj5b470602005-02-27 13:10:48 +0000676/* This is somewhat complex. The rules are:
677
678 For 64, 32 and 16 bit register references, the e or g fields in the
679 modrm bytes supply the low 3 bits of the register number. The
680 fourth (most-significant) bit of the register number is supplied by
681 the REX byte, if it is present; else that bit is taken to be zero.
682
683 The REX.R bit supplies the high bit corresponding to the g register
684 field, and the REX.B bit supplies the high bit corresponding to the
685 e register field (when the mod part of modrm indicates that modrm's
686 e component refers to a register and not to memory).
687
688 The REX.X bit supplies a high register bit for certain registers
689 in SIB address modes, and is generally rarely used.
690
691 For 8 bit register references, the presence of the REX byte itself
692 has significance. If there is no REX present, then the 3-bit
693 number extracted from the modrm e or g field is treated as an index
694 into the sequence %al %cl %dl %bl %ah %ch %dh %bh -- that is, the
695 old x86 encoding scheme.
696
697 But if there is a REX present, the register reference is
698 interpreted in the same way as for 64/32/16-bit references: a high
699 bit is extracted from REX, giving a 4-bit number, and the denoted
700 register is the lowest 8 bits of the 16 integer registers denoted
701 by the number. In particular, values 3 through 7 of this sequence
702 do not refer to %ah %ch %dh %bh but instead to the lowest 8 bits of
703 %rsp %rbp %rsi %rdi.
704
705 The REX.W bit has no bearing at all on register numbers. Instead
706 its presence indicates that the operand size is to be overridden
707 from its default value (32 bits) to 64 bits instead. This is in
708 the same fashion that an 0x66 prefix indicates the operand size is
709 to be overridden from 32 bits down to 16 bits. When both REX.W and
710 0x66 are present there is a conflict, and REX.W takes precedence.
711
712 Rather than try to handle this complexity using a single huge
713 function, several smaller ones are provided. The aim is to make it
714 as difficult as possible to screw up register decoding in a subtle
715 and hard-to-track-down way.
716
717 Because these routines fish around in the host's memory (that is,
718 in the guest state area) for sub-parts of guest registers, their
719 correctness depends on the host's endianness. So far these
720 routines only work for little-endian hosts. Those for which
721 endianness is important have assertions to ensure sanity.
722*/
sewardjecb94892005-01-21 14:26:37 +0000723
724
sewardj5b470602005-02-27 13:10:48 +0000725/* About the simplest question you can ask: where do the 64-bit
726 integer registers live (in the guest state) ? */
sewardjecb94892005-01-21 14:26:37 +0000727
sewardj3ca55a12005-01-27 16:06:23 +0000728static Int integerGuestReg64Offset ( UInt reg )
sewardjb3a04292005-01-21 20:33:44 +0000729{
730 switch (reg) {
731 case R_RAX: return OFFB_RAX;
732 case R_RCX: return OFFB_RCX;
733 case R_RDX: return OFFB_RDX;
734 case R_RBX: return OFFB_RBX;
735 case R_RSP: return OFFB_RSP;
736 case R_RBP: return OFFB_RBP;
737 case R_RSI: return OFFB_RSI;
738 case R_RDI: return OFFB_RDI;
739 case R_R8: return OFFB_R8;
740 case R_R9: return OFFB_R9;
741 case R_R10: return OFFB_R10;
742 case R_R11: return OFFB_R11;
743 case R_R12: return OFFB_R12;
744 case R_R13: return OFFB_R13;
745 case R_R14: return OFFB_R14;
746 case R_R15: return OFFB_R15;
747 default: vpanic("integerGuestReg64Offset(amd64)");
748 }
749}
750
751
sewardj5b470602005-02-27 13:10:48 +0000752/* Produce the name of an integer register, for printing purposes.
753 reg is a number in the range 0 .. 15 that has been generated from a
754 3-bit reg-field number and a REX extension bit. irregular denotes
755 the case where sz==1 and no REX byte is present. */
sewardjecb94892005-01-21 14:26:37 +0000756
757static
sewardj5b470602005-02-27 13:10:48 +0000758HChar* nameIReg ( Int sz, UInt reg, Bool irregular )
sewardjecb94892005-01-21 14:26:37 +0000759{
sewardjecb94892005-01-21 14:26:37 +0000760 static HChar* ireg64_names[16]
761 = { "%rax", "%rcx", "%rdx", "%rbx", "%rsp", "%rbp", "%rsi", "%rdi",
762 "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15" };
763 static HChar* ireg32_names[16]
764 = { "%eax", "%ecx", "%edx", "%ebx", "%esp", "%ebp", "%esi", "%edi",
765 "%r8d", "%r9d", "%r10d","%r11d","%r12d","%r13d","%r14d","%r15d" };
766 static HChar* ireg16_names[16]
767 = { "%ax", "%cx", "%dx", "%bx", "%sp", "%bp", "%si", "%di",
768 "%r8w", "%r9w", "%r10w","%r11w","%r12w","%r13w","%r14w","%r15w" };
769 static HChar* ireg8_names[16]
770 = { "%al", "%cl", "%dl", "%bl", "%spl", "%bpl", "%sil", "%dil",
771 "%r8b", "%r9b", "%r10b","%r11b","%r12b","%r13b","%r14b","%r15b" };
sewardj5b470602005-02-27 13:10:48 +0000772 static HChar* ireg8_irregular[8]
sewardjecb94892005-01-21 14:26:37 +0000773 = { "%al", "%cl", "%dl", "%bl", "%ah", "%ch", "%dh", "%bh" };
774
sewardj5b470602005-02-27 13:10:48 +0000775 vassert(reg < 16);
776 if (sz == 1) {
777 if (irregular)
778 vassert(reg < 8);
779 } else {
780 vassert(irregular == False);
781 }
sewardjecb94892005-01-21 14:26:37 +0000782
783 switch (sz) {
sewardj5b470602005-02-27 13:10:48 +0000784 case 8: return ireg64_names[reg];
785 case 4: return ireg32_names[reg];
786 case 2: return ireg16_names[reg];
787 case 1: if (irregular) {
788 return ireg8_irregular[reg];
789 } else {
790 return ireg8_names[reg];
791 }
792 default: vpanic("nameIReg(amd64)");
sewardjecb94892005-01-21 14:26:37 +0000793 }
sewardjecb94892005-01-21 14:26:37 +0000794}
795
sewardj5b470602005-02-27 13:10:48 +0000796/* Using the same argument conventions as nameIReg, produce the
797 guest state offset of an integer register. */
sewardjb3a04292005-01-21 20:33:44 +0000798
sewardjecb94892005-01-21 14:26:37 +0000799static
sewardj5b470602005-02-27 13:10:48 +0000800Int offsetIReg ( Int sz, UInt reg, Bool irregular )
sewardjecb94892005-01-21 14:26:37 +0000801{
sewardj5b470602005-02-27 13:10:48 +0000802 vassert(reg < 16);
803 if (sz == 1) {
804 if (irregular)
805 vassert(reg < 8);
806 } else {
807 vassert(irregular == False);
sewardjecb94892005-01-21 14:26:37 +0000808 }
sewardj5b470602005-02-27 13:10:48 +0000809
810 /* Deal with irregular case -- sz==1 and no REX present */
811 if (sz == 1 && irregular) {
812 switch (reg) {
813 case R_RSP: return 1+ OFFB_RAX;
814 case R_RBP: return 1+ OFFB_RCX;
815 case R_RSI: return 1+ OFFB_RDX;
816 case R_RDI: return 1+ OFFB_RBX;
817 default: break; /* use the normal case */
818 }
sewardjecb94892005-01-21 14:26:37 +0000819 }
sewardj5b470602005-02-27 13:10:48 +0000820
821 /* Normal case */
822 return integerGuestReg64Offset(reg);
sewardjecb94892005-01-21 14:26:37 +0000823}
824
825
sewardj5b470602005-02-27 13:10:48 +0000826/* Read the %CL register :: Ity_I8, for shift/rotate operations. */
827
828static IRExpr* getIRegCL ( void )
829{
830 vassert(!host_is_bigendian);
831 return IRExpr_Get( OFFB_RCX, Ity_I8 );
832}
833
834
835/* Write to the %AH register. */
836
837static void putIRegAH ( IRExpr* e )
838{
839 vassert(!host_is_bigendian);
840 vassert(typeOfIRExpr(irbb->tyenv, e) == Ity_I8);
841 stmt( IRStmt_Put( OFFB_RAX+1, e ) );
842}
843
844
845/* Read/write various widths of %RAX, as it has various
846 special-purpose uses. */
847
848static HChar* nameIRegRAX ( Int sz )
849{
850 switch (sz) {
851 case 1: return "%al";
852 case 2: return "%ax";
853 case 4: return "%eax";
854 case 8: return "%rax";
855 default: vpanic("nameIRegRAX(amd64)");
856 }
857}
858
859static IRExpr* getIRegRAX ( Int sz )
860{
861 vassert(!host_is_bigendian);
862 switch (sz) {
863 case 1: return IRExpr_Get( OFFB_RAX, Ity_I8 );
864 case 2: return IRExpr_Get( OFFB_RAX, Ity_I16 );
865 case 4: return IRExpr_Get( OFFB_RAX, Ity_I32 );
866 case 8: return IRExpr_Get( OFFB_RAX, Ity_I64 );
867 default: vpanic("getIRegRAX(amd64)");
868 }
869}
870
871static void putIRegRAX ( Int sz, IRExpr* e )
872{
873 IRType ty = typeOfIRExpr(irbb->tyenv, e);
874 vassert(!host_is_bigendian);
875 switch (sz) {
876 case 8: vassert(ty == Ity_I64);
877 stmt( IRStmt_Put( OFFB_RAX, e ));
878 break;
879 case 4: vassert(ty == Ity_I32);
880 stmt( IRStmt_Put( OFFB_RAX, unop(Iop_32Uto64,e) ));
881 break;
882 case 2: vassert(ty == Ity_I16);
883 stmt( IRStmt_Put( OFFB_RAX, e ));
884 break;
885 case 1: vassert(ty == Ity_I8);
886 stmt( IRStmt_Put( OFFB_RAX, e ));
887 break;
888 default: vpanic("putIRegRAX(amd64)");
889 }
890}
891
892
893/* Read/write various widths of %RDX, as it has various
894 special-purpose uses. */
895
896static IRExpr* getIRegRDX ( Int sz )
897{
898 vassert(!host_is_bigendian);
899 switch (sz) {
900 case 1: return IRExpr_Get( OFFB_RDX, Ity_I8 );
901 case 2: return IRExpr_Get( OFFB_RDX, Ity_I16 );
902 case 4: return IRExpr_Get( OFFB_RDX, Ity_I32 );
903 case 8: return IRExpr_Get( OFFB_RDX, Ity_I64 );
904 default: vpanic("getIRegRDX(amd64)");
905 }
906}
907
908static void putIRegRDX ( Int sz, IRExpr* e )
909{
910 vassert(!host_is_bigendian);
911 vassert(typeOfIRExpr(irbb->tyenv, e) == szToITy(sz));
912 switch (sz) {
913 case 8: stmt( IRStmt_Put( OFFB_RDX, e ));
914 break;
915 case 4: stmt( IRStmt_Put( OFFB_RDX, unop(Iop_32Uto64,e) ));
916 break;
917 case 2: stmt( IRStmt_Put( OFFB_RDX, e ));
918 break;
919 case 1: stmt( IRStmt_Put( OFFB_RDX, e ));
920 break;
921 default: vpanic("putIRegRDX(amd64)");
922 }
923}
924
925
926/* Simplistic functions to deal with the integer registers as a
927 straightforward bank of 16 64-bit regs. */
sewardjb3a04292005-01-21 20:33:44 +0000928
929static IRExpr* getIReg64 ( UInt regno )
930{
931 return IRExpr_Get( integerGuestReg64Offset(regno),
932 Ity_I64 );
933}
934
sewardj2f959cc2005-01-26 01:19:35 +0000935static void putIReg64 ( UInt regno, IRExpr* e )
936{
937 vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_I64);
938 stmt( IRStmt_Put( integerGuestReg64Offset(regno), e ) );
939}
940
sewardjb3a04292005-01-21 20:33:44 +0000941static HChar* nameIReg64 ( UInt regno )
942{
sewardj5b470602005-02-27 13:10:48 +0000943 return nameIReg( 8, regno, False );
sewardjb3a04292005-01-21 20:33:44 +0000944}
sewardj5b470602005-02-27 13:10:48 +0000945
946
947/* Simplistic functions to deal with the lower halves of integer
948 registers as a straightforward bank of 16 32-bit regs. */
949
950static IRExpr* getIReg32 ( UInt regno )
951{
952 vassert(!host_is_bigendian);
953 return IRExpr_Get( integerGuestReg64Offset(regno),
954 Ity_I32 );
955}
956
957static void putIReg32 ( UInt regno, IRExpr* e )
958{
959 vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_I32);
960 stmt( IRStmt_Put( integerGuestReg64Offset(regno),
961 unop(Iop_32Uto64,e) ) );
962}
963
964static HChar* nameIReg32 ( UInt regno )
965{
966 return nameIReg( 4, regno, False );
967}
968
969
sewardja7ba8c42005-05-10 20:08:34 +0000970/* Simplistic functions to deal with the lower quarters of integer
971 registers as a straightforward bank of 16 16-bit regs. */
972
973static IRExpr* getIReg16 ( UInt regno )
974{
975 vassert(!host_is_bigendian);
976 return IRExpr_Get( integerGuestReg64Offset(regno),
977 Ity_I16 );
978}
979
980static HChar* nameIReg16 ( UInt regno )
981{
982 return nameIReg( 2, regno, False );
983}
984
985
sewardj5b470602005-02-27 13:10:48 +0000986/* Sometimes what we know is a 3-bit register number, a REX byte, and
987 which field of the REX byte is to be used to extend to a 4-bit
988 number. These functions cater for that situation.
989*/
990static IRExpr* getIReg64rexX ( Prefix pfx, UInt lo3bits )
991{
992 vassert(lo3bits < 8);
993 vassert(IS_VALID_PFX(pfx));
994 return getIReg64( lo3bits | (getRexX(pfx) << 3) );
995}
996
997static HChar* nameIReg64rexX ( Prefix pfx, UInt lo3bits )
998{
999 vassert(lo3bits < 8);
1000 vassert(IS_VALID_PFX(pfx));
1001 return nameIReg( 8, lo3bits | (getRexX(pfx) << 3), False );
1002}
1003
1004static HChar* nameIRegRexB ( Int sz, Prefix pfx, UInt lo3bits )
1005{
1006 vassert(lo3bits < 8);
1007 vassert(IS_VALID_PFX(pfx));
1008 vassert(sz == 8 || sz == 4 || sz == 2 || sz == 1);
1009 return nameIReg( sz, lo3bits | (getRexB(pfx) << 3),
sewardj397f88b2005-02-27 13:39:25 +00001010 toBool(sz==1 && !haveREX(pfx)) );
sewardj5b470602005-02-27 13:10:48 +00001011}
1012
1013static IRExpr* getIRegRexB ( Int sz, Prefix pfx, UInt lo3bits )
1014{
1015 vassert(lo3bits < 8);
1016 vassert(IS_VALID_PFX(pfx));
1017 vassert(sz == 8 || sz == 4 || sz == 2 || sz == 1);
1018 return IRExpr_Get(
1019 offsetIReg( sz, lo3bits | (getRexB(pfx) << 3),
sewardj397f88b2005-02-27 13:39:25 +00001020 toBool(sz==1 && !haveREX(pfx)) ),
sewardj5b470602005-02-27 13:10:48 +00001021 szToITy(sz)
1022 );
1023}
1024
1025static void putIRegRexB ( Int sz, Prefix pfx, UInt lo3bits, IRExpr* e )
1026{
1027 vassert(lo3bits < 8);
1028 vassert(IS_VALID_PFX(pfx));
sewardj98e9f342005-07-23 12:07:37 +00001029 vassert(sz == 8 || sz == 4 || sz == 2 || sz == 1);
sewardj5b470602005-02-27 13:10:48 +00001030 vassert(typeOfIRExpr(irbb->tyenv, e) == szToITy(sz));
1031 stmt( IRStmt_Put(
1032 offsetIReg( sz, lo3bits | (getRexB(pfx) << 3),
sewardj397f88b2005-02-27 13:39:25 +00001033 toBool(sz==1 && !haveREX(pfx)) ),
sewardj5b470602005-02-27 13:10:48 +00001034 sz==4 ? unop(Iop_32Uto64,e) : e
1035 ));
1036}
1037
1038
1039/* Functions for getting register numbers from modrm bytes and REX
1040 when we don't have to consider the complexities of integer subreg
1041 accesses.
1042*/
1043/* Extract the g reg field from a modRM byte, and augment it using the
1044 REX.R bit from the supplied REX byte. The R bit usually is
1045 associated with the g register field.
1046*/
1047static UInt gregOfRexRM ( Prefix pfx, UChar mod_reg_rm )
1048{
1049 Int reg = (Int)( (mod_reg_rm >> 3) & 7 );
1050 reg += (pfx & PFX_REXR) ? 8 : 0;
1051 return reg;
1052}
1053
1054/* Extract the e reg field from a modRM byte, and augment it using the
1055 REX.B bit from the supplied REX byte. The B bit usually is
1056 associated with the e register field (when modrm indicates e is a
1057 register, that is).
1058*/
1059static UInt eregOfRexRM ( Prefix pfx, UChar mod_reg_rm )
1060{
1061 Int rm;
1062 vassert(epartIsReg(mod_reg_rm));
1063 rm = (Int)(mod_reg_rm & 0x7);
1064 rm += (pfx & PFX_REXB) ? 8 : 0;
1065 return rm;
1066}
1067
1068
1069/* General functions for dealing with integer register access. */
1070
1071/* Produce the guest state offset for a reference to the 'g' register
1072 field in a modrm byte, taking into account REX (or its absence),
1073 and the size of the access.
1074*/
1075static UInt offsetIRegG ( Int sz, Prefix pfx, UChar mod_reg_rm )
1076{
1077 UInt reg;
1078 vassert(!host_is_bigendian);
1079 vassert(IS_VALID_PFX(pfx));
1080 vassert(sz == 8 || sz == 4 || sz == 2 || sz == 1);
1081 reg = gregOfRexRM( pfx, mod_reg_rm );
sewardj397f88b2005-02-27 13:39:25 +00001082 return offsetIReg( sz, reg, toBool(sz == 1 && !haveREX(pfx)) );
sewardj5b470602005-02-27 13:10:48 +00001083}
1084
1085static
1086IRExpr* getIRegG ( Int sz, Prefix pfx, UChar mod_reg_rm )
1087{
1088 return IRExpr_Get( offsetIRegG( sz, pfx, mod_reg_rm ),
1089 szToITy(sz) );
1090}
1091
1092static
1093void putIRegG ( Int sz, Prefix pfx, UChar mod_reg_rm, IRExpr* e )
1094{
1095 vassert(typeOfIRExpr(irbb->tyenv,e) == szToITy(sz));
1096 if (sz == 4) {
1097 e = unop(Iop_32Uto64,e);
1098 }
1099 stmt( IRStmt_Put( offsetIRegG( sz, pfx, mod_reg_rm ), e ) );
1100}
1101
1102static
1103HChar* nameIRegG ( Int sz, Prefix pfx, UChar mod_reg_rm )
1104{
1105 return nameIReg( sz, gregOfRexRM(pfx,mod_reg_rm),
sewardj397f88b2005-02-27 13:39:25 +00001106 toBool(sz==1 && !haveREX(pfx)) );
sewardj5b470602005-02-27 13:10:48 +00001107}
1108
1109
1110/* Produce the guest state offset for a reference to the 'e' register
1111 field in a modrm byte, taking into account REX (or its absence),
1112 and the size of the access. eregOfRexRM will assert if mod_reg_rm
1113 denotes a memory access rather than a register access.
1114*/
1115static UInt offsetIRegE ( Int sz, Prefix pfx, UChar mod_reg_rm )
1116{
1117 UInt reg;
1118 vassert(!host_is_bigendian);
1119 vassert(IS_VALID_PFX(pfx));
1120 vassert(sz == 8 || sz == 4 || sz == 2 || sz == 1);
1121 reg = eregOfRexRM( pfx, mod_reg_rm );
sewardj397f88b2005-02-27 13:39:25 +00001122 return offsetIReg( sz, reg, toBool(sz == 1 && !haveREX(pfx)) );
sewardj5b470602005-02-27 13:10:48 +00001123}
1124
1125static
1126IRExpr* getIRegE ( Int sz, Prefix pfx, UChar mod_reg_rm )
1127{
1128 return IRExpr_Get( offsetIRegE( sz, pfx, mod_reg_rm ),
1129 szToITy(sz) );
1130}
1131
1132static
1133void putIRegE ( Int sz, Prefix pfx, UChar mod_reg_rm, IRExpr* e )
1134{
1135 vassert(typeOfIRExpr(irbb->tyenv,e) == szToITy(sz));
1136 if (sz == 4) {
1137 e = unop(Iop_32Uto64,e);
1138 }
1139 stmt( IRStmt_Put( offsetIRegE( sz, pfx, mod_reg_rm ), e ) );
1140}
1141
1142static
1143HChar* nameIRegE ( Int sz, Prefix pfx, UChar mod_reg_rm )
1144{
1145 return nameIReg( sz, eregOfRexRM(pfx,mod_reg_rm),
sewardj397f88b2005-02-27 13:39:25 +00001146 toBool(sz==1 && !haveREX(pfx)) );
sewardj5b470602005-02-27 13:10:48 +00001147}
1148
1149
1150/*------------------------------------------------------------*/
1151/*--- For dealing with XMM registers ---*/
1152/*------------------------------------------------------------*/
sewardjecb94892005-01-21 14:26:37 +00001153
sewardjd20c8852005-01-20 20:04:07 +00001154//.. static Int segmentGuestRegOffset ( UInt sreg )
1155//.. {
1156//.. switch (sreg) {
1157//.. case R_ES: return OFFB_ES;
1158//.. case R_CS: return OFFB_CS;
1159//.. case R_SS: return OFFB_SS;
1160//.. case R_DS: return OFFB_DS;
1161//.. case R_FS: return OFFB_FS;
1162//.. case R_GS: return OFFB_GS;
1163//.. default: vpanic("segmentGuestRegOffset(x86)");
1164//.. }
1165//.. }
sewardj1001dc42005-02-21 08:25:55 +00001166
1167static Int xmmGuestRegOffset ( UInt xmmreg )
1168{
1169 switch (xmmreg) {
1170 case 0: return OFFB_XMM0;
1171 case 1: return OFFB_XMM1;
1172 case 2: return OFFB_XMM2;
1173 case 3: return OFFB_XMM3;
1174 case 4: return OFFB_XMM4;
1175 case 5: return OFFB_XMM5;
1176 case 6: return OFFB_XMM6;
1177 case 7: return OFFB_XMM7;
1178 case 8: return OFFB_XMM8;
1179 case 9: return OFFB_XMM9;
1180 case 10: return OFFB_XMM10;
1181 case 11: return OFFB_XMM11;
1182 case 12: return OFFB_XMM12;
1183 case 13: return OFFB_XMM13;
1184 case 14: return OFFB_XMM14;
1185 case 15: return OFFB_XMM15;
1186 default: vpanic("xmmGuestRegOffset(amd64)");
1187 }
1188}
1189
sewardj97628592005-05-10 22:42:54 +00001190/* Lanes of vector registers are always numbered from zero being the
1191 least significant lane (rightmost in the register). */
1192
1193static Int xmmGuestRegLane16offset ( UInt xmmreg, Int laneno )
1194{
1195 /* Correct for little-endian host only. */
1196 vassert(!host_is_bigendian);
1197 vassert(laneno >= 0 && laneno < 8);
1198 return xmmGuestRegOffset( xmmreg ) + 2 * laneno;
1199}
sewardj8d965312005-02-25 02:48:47 +00001200
1201static Int xmmGuestRegLane32offset ( UInt xmmreg, Int laneno )
1202{
1203 /* Correct for little-endian host only. */
1204 vassert(!host_is_bigendian);
1205 vassert(laneno >= 0 && laneno < 4);
1206 return xmmGuestRegOffset( xmmreg ) + 4 * laneno;
1207}
sewardj1001dc42005-02-21 08:25:55 +00001208
1209static Int xmmGuestRegLane64offset ( UInt xmmreg, Int laneno )
1210{
1211 /* Correct for little-endian host only. */
1212 vassert(!host_is_bigendian);
1213 vassert(laneno >= 0 && laneno < 2);
1214 return xmmGuestRegOffset( xmmreg ) + 8 * laneno;
1215}
1216
sewardjd20c8852005-01-20 20:04:07 +00001217//.. static IRExpr* getSReg ( UInt sreg )
1218//.. {
1219//.. return IRExpr_Get( segmentGuestRegOffset(sreg), Ity_I16 );
1220//.. }
1221//..
1222//.. static void putSReg ( UInt sreg, IRExpr* e )
1223//.. {
1224//.. vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_I16);
1225//.. stmt( IRStmt_Put( segmentGuestRegOffset(sreg), e ) );
1226//.. }
sewardj1001dc42005-02-21 08:25:55 +00001227
1228static IRExpr* getXMMReg ( UInt xmmreg )
1229{
1230 return IRExpr_Get( xmmGuestRegOffset(xmmreg), Ity_V128 );
1231}
1232
1233static IRExpr* getXMMRegLane64 ( UInt xmmreg, Int laneno )
1234{
1235 return IRExpr_Get( xmmGuestRegLane64offset(xmmreg,laneno), Ity_I64 );
1236}
1237
sewardj18303862005-02-21 12:36:54 +00001238static IRExpr* getXMMRegLane64F ( UInt xmmreg, Int laneno )
1239{
1240 return IRExpr_Get( xmmGuestRegLane64offset(xmmreg,laneno), Ity_F64 );
1241}
1242
sewardj8d965312005-02-25 02:48:47 +00001243static IRExpr* getXMMRegLane32 ( UInt xmmreg, Int laneno )
1244{
1245 return IRExpr_Get( xmmGuestRegLane32offset(xmmreg,laneno), Ity_I32 );
1246}
1247
sewardjc49ce232005-02-25 13:03:03 +00001248static IRExpr* getXMMRegLane32F ( UInt xmmreg, Int laneno )
1249{
1250 return IRExpr_Get( xmmGuestRegLane32offset(xmmreg,laneno), Ity_F32 );
1251}
sewardj1001dc42005-02-21 08:25:55 +00001252
1253static void putXMMReg ( UInt xmmreg, IRExpr* e )
1254{
1255 vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_V128);
1256 stmt( IRStmt_Put( xmmGuestRegOffset(xmmreg), e ) );
1257}
1258
1259static void putXMMRegLane64 ( UInt xmmreg, Int laneno, IRExpr* e )
1260{
1261 vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_I64);
1262 stmt( IRStmt_Put( xmmGuestRegLane64offset(xmmreg,laneno), e ) );
1263}
1264
sewardj1a01e652005-02-23 11:39:21 +00001265static void putXMMRegLane64F ( UInt xmmreg, Int laneno, IRExpr* e )
1266{
1267 vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_F64);
1268 stmt( IRStmt_Put( xmmGuestRegLane64offset(xmmreg,laneno), e ) );
1269}
1270
sewardj8d965312005-02-25 02:48:47 +00001271static void putXMMRegLane32F ( UInt xmmreg, Int laneno, IRExpr* e )
1272{
1273 vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_F32);
1274 stmt( IRStmt_Put( xmmGuestRegLane32offset(xmmreg,laneno), e ) );
1275}
1276
1277static void putXMMRegLane32 ( UInt xmmreg, Int laneno, IRExpr* e )
1278{
1279 vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_I32);
1280 stmt( IRStmt_Put( xmmGuestRegLane32offset(xmmreg,laneno), e ) );
1281}
1282
sewardj97628592005-05-10 22:42:54 +00001283static void putXMMRegLane16 ( UInt xmmreg, Int laneno, IRExpr* e )
1284{
1285 vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_I16);
1286 stmt( IRStmt_Put( xmmGuestRegLane16offset(xmmreg,laneno), e ) );
1287}
sewardj3ca55a12005-01-27 16:06:23 +00001288
sewardj1001dc42005-02-21 08:25:55 +00001289static IRExpr* mkV128 ( UShort mask )
1290{
1291 return IRExpr_Const(IRConst_V128(mask));
1292}
sewardjdf0e0022005-01-25 15:48:43 +00001293
sewardj5b470602005-02-27 13:10:48 +00001294
sewardj118b23e2005-01-29 02:14:44 +00001295/*------------------------------------------------------------*/
1296/*--- Helpers for %eflags. ---*/
1297/*------------------------------------------------------------*/
1298
1299/* -------------- Evaluating the flags-thunk. -------------- */
1300
1301/* Build IR to calculate all the eflags from stored
1302 CC_OP/CC_DEP1/CC_DEP2/CC_NDEP. Returns an expression ::
1303 Ity_I64. */
1304static IRExpr* mk_amd64g_calculate_rflags_all ( void )
1305{
1306 IRExpr** args
1307 = mkIRExprVec_4( IRExpr_Get(OFFB_CC_OP, Ity_I64),
1308 IRExpr_Get(OFFB_CC_DEP1, Ity_I64),
1309 IRExpr_Get(OFFB_CC_DEP2, Ity_I64),
1310 IRExpr_Get(OFFB_CC_NDEP, Ity_I64) );
1311 IRExpr* call
1312 = mkIRExprCCall(
1313 Ity_I64,
1314 0/*regparm*/,
1315 "amd64g_calculate_rflags_all", &amd64g_calculate_rflags_all,
1316 args
1317 );
1318 /* Exclude OP and NDEP from definedness checking. We're only
1319 interested in DEP1 and DEP2. */
1320 call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<3);
1321 return call;
1322}
sewardj3ca55a12005-01-27 16:06:23 +00001323
1324/* Build IR to calculate some particular condition from stored
1325 CC_OP/CC_DEP1/CC_DEP2/CC_NDEP. Returns an expression ::
1326 Ity_Bit. */
1327static IRExpr* mk_amd64g_calculate_condition ( AMD64Condcode cond )
1328{
1329 IRExpr** args
1330 = mkIRExprVec_5( mkU64(cond),
1331 IRExpr_Get(OFFB_CC_OP, Ity_I64),
1332 IRExpr_Get(OFFB_CC_DEP1, Ity_I64),
1333 IRExpr_Get(OFFB_CC_DEP2, Ity_I64),
1334 IRExpr_Get(OFFB_CC_NDEP, Ity_I64) );
1335 IRExpr* call
1336 = mkIRExprCCall(
1337 Ity_I64,
1338 0/*regparm*/,
1339 "amd64g_calculate_condition", &amd64g_calculate_condition,
1340 args
1341 );
1342 /* Exclude the requested condition, OP and NDEP from definedness
1343 checking. We're only interested in DEP1 and DEP2. */
1344 call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<1) | (1<<4);
sewardje58967e2005-04-27 11:50:56 +00001345 return unop(Iop_64to1, call);
sewardj3ca55a12005-01-27 16:06:23 +00001346}
sewardjdf0e0022005-01-25 15:48:43 +00001347
1348/* Build IR to calculate just the carry flag from stored
1349 CC_OP/CC_DEP1/CC_DEP2/CC_NDEP. Returns an expression :: Ity_I64. */
1350static IRExpr* mk_amd64g_calculate_rflags_c ( void )
1351{
1352 IRExpr** args
1353 = mkIRExprVec_4( IRExpr_Get(OFFB_CC_OP, Ity_I64),
1354 IRExpr_Get(OFFB_CC_DEP1, Ity_I64),
1355 IRExpr_Get(OFFB_CC_DEP2, Ity_I64),
1356 IRExpr_Get(OFFB_CC_NDEP, Ity_I64) );
1357 IRExpr* call
1358 = mkIRExprCCall(
1359 Ity_I64,
1360 0/*regparm*/,
1361 "amd64g_calculate_rflags_c", &amd64g_calculate_rflags_c,
1362 args
1363 );
1364 /* Exclude OP and NDEP from definedness checking. We're only
1365 interested in DEP1 and DEP2. */
1366 call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<3);
1367 return call;
1368}
1369
1370
1371/* -------------- Building the flags-thunk. -------------- */
1372
1373/* The machinery in this section builds the flag-thunk following a
1374 flag-setting operation. Hence the various setFlags_* functions.
1375*/
1376
1377static Bool isAddSub ( IROp op8 )
1378{
sewardj7a240552005-01-28 21:37:12 +00001379 return toBool(op8 == Iop_Add8 || op8 == Iop_Sub8);
sewardjdf0e0022005-01-25 15:48:43 +00001380}
1381
sewardj3ca55a12005-01-27 16:06:23 +00001382static Bool isLogic ( IROp op8 )
1383{
sewardj7a240552005-01-28 21:37:12 +00001384 return toBool(op8 == Iop_And8 || op8 == Iop_Or8 || op8 == Iop_Xor8);
sewardj3ca55a12005-01-27 16:06:23 +00001385}
sewardjdf0e0022005-01-25 15:48:43 +00001386
1387/* U-widen 8/16/32/64 bit int expr to 64. */
1388static IRExpr* widenUto64 ( IRExpr* e )
1389{
1390 switch (typeOfIRExpr(irbb->tyenv,e)) {
1391 case Ity_I64: return e;
1392 case Ity_I32: return unop(Iop_32Uto64, e);
sewardje58967e2005-04-27 11:50:56 +00001393 case Ity_I16: return unop(Iop_16Uto64, e);
1394 case Ity_I8: return unop(Iop_8Uto64, e);
sewardj118b23e2005-01-29 02:14:44 +00001395 default: vpanic("widenUto64");
sewardjdf0e0022005-01-25 15:48:43 +00001396 }
1397}
1398
sewardj118b23e2005-01-29 02:14:44 +00001399/* S-widen 8/16/32/64 bit int expr to 32. */
1400static IRExpr* widenSto64 ( IRExpr* e )
1401{
1402 switch (typeOfIRExpr(irbb->tyenv,e)) {
1403 case Ity_I64: return e;
1404 case Ity_I32: return unop(Iop_32Sto64, e);
sewardje58967e2005-04-27 11:50:56 +00001405 case Ity_I16: return unop(Iop_16Sto64, e);
1406 case Ity_I8: return unop(Iop_8Sto64, e);
sewardj118b23e2005-01-29 02:14:44 +00001407 default: vpanic("widenSto64");
1408 }
1409}
sewardjdf0e0022005-01-25 15:48:43 +00001410
1411/* Narrow 8/16/32/64 bit int expr to 8/16/32/64. Clearly only some
1412 of these combinations make sense. */
1413static IRExpr* narrowTo ( IRType dst_ty, IRExpr* e )
1414{
1415 IRType src_ty = typeOfIRExpr(irbb->tyenv,e);
1416 if (src_ty == dst_ty)
1417 return e;
1418 if (src_ty == Ity_I32 && dst_ty == Ity_I16)
1419 return unop(Iop_32to16, e);
1420 if (src_ty == Ity_I32 && dst_ty == Ity_I8)
1421 return unop(Iop_32to8, e);
sewardj118b23e2005-01-29 02:14:44 +00001422 if (src_ty == Ity_I64 && dst_ty == Ity_I32)
1423 return unop(Iop_64to32, e);
1424 if (src_ty == Ity_I64 && dst_ty == Ity_I16)
sewardje58967e2005-04-27 11:50:56 +00001425 return unop(Iop_64to16, e);
sewardj03b07cc2005-01-31 18:09:43 +00001426 if (src_ty == Ity_I64 && dst_ty == Ity_I8)
sewardje58967e2005-04-27 11:50:56 +00001427 return unop(Iop_64to8, e);
sewardjdf0e0022005-01-25 15:48:43 +00001428
1429 vex_printf("\nsrc, dst tys are: ");
1430 ppIRType(src_ty);
1431 vex_printf(", ");
1432 ppIRType(dst_ty);
1433 vex_printf("\n");
1434 vpanic("narrowTo(amd64)");
1435}
1436
1437
1438/* Set the flags thunk OP, DEP1 and DEP2 fields. The supplied op is
1439 auto-sized up to the real op. */
1440
1441static
1442void setFlags_DEP1_DEP2 ( IROp op8, IRTemp dep1, IRTemp dep2, IRType ty )
1443{
1444 Int ccOp = 0;
1445 switch (ty) {
1446 case Ity_I8: ccOp = 0; break;
1447 case Ity_I16: ccOp = 1; break;
1448 case Ity_I32: ccOp = 2; break;
1449 case Ity_I64: ccOp = 3; break;
1450 default: vassert(0);
1451 }
1452 switch (op8) {
1453 case Iop_Add8: ccOp += AMD64G_CC_OP_ADDB; break;
1454 case Iop_Sub8: ccOp += AMD64G_CC_OP_SUBB; break;
1455 default: ppIROp(op8);
1456 vpanic("setFlags_DEP1_DEP2(amd64)");
1457 }
1458 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(ccOp)) );
1459 stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto64(mkexpr(dep1))) );
1460 stmt( IRStmt_Put( OFFB_CC_DEP2, widenUto64(mkexpr(dep2))) );
1461}
1462
1463
1464/* Set the OP and DEP1 fields only, and write zero to DEP2. */
1465
1466static
1467void setFlags_DEP1 ( IROp op8, IRTemp dep1, IRType ty )
1468{
1469 Int ccOp = 0;
1470 switch (ty) {
1471 case Ity_I8: ccOp = 0; break;
1472 case Ity_I16: ccOp = 1; break;
1473 case Ity_I32: ccOp = 2; break;
1474 case Ity_I64: ccOp = 3; break;
1475 default: vassert(0);
1476 }
1477 switch (op8) {
1478 case Iop_Or8:
1479 case Iop_And8:
1480 case Iop_Xor8: ccOp += AMD64G_CC_OP_LOGICB; break;
1481 default: ppIROp(op8);
1482 vpanic("setFlags_DEP1(amd64)");
1483 }
1484 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(ccOp)) );
1485 stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto64(mkexpr(dep1))) );
1486 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0)) );
1487}
1488
1489
sewardj118b23e2005-01-29 02:14:44 +00001490/* For shift operations, we put in the result and the undershifted
1491 result. Except if the shift amount is zero, the thunk is left
1492 unchanged. */
1493
1494static void setFlags_DEP1_DEP2_shift ( IROp op64,
1495 IRTemp res,
1496 IRTemp resUS,
1497 IRType ty,
1498 IRTemp guard )
1499{
1500 Int ccOp = 0;
1501 switch (ty) {
1502 case Ity_I8: ccOp = 0; break;
1503 case Ity_I16: ccOp = 1; break;
1504 case Ity_I32: ccOp = 2; break;
1505 case Ity_I64: ccOp = 3; break;
1506 default: vassert(0);
1507 }
1508
1509 vassert(guard);
1510
1511 /* Both kinds of right shifts are handled by the same thunk
1512 operation. */
1513 switch (op64) {
1514 case Iop_Shr64:
1515 case Iop_Sar64: ccOp += AMD64G_CC_OP_SHRB; break;
1516 case Iop_Shl64: ccOp += AMD64G_CC_OP_SHLB; break;
1517 default: ppIROp(op64);
1518 vpanic("setFlags_DEP1_DEP2_shift(amd64)");
1519 }
1520
1521 /* DEP1 contains the result, DEP2 contains the undershifted value. */
1522 stmt( IRStmt_Put( OFFB_CC_OP,
1523 IRExpr_Mux0X( mkexpr(guard),
1524 IRExpr_Get(OFFB_CC_OP,Ity_I64),
1525 mkU64(ccOp))) );
1526 stmt( IRStmt_Put( OFFB_CC_DEP1,
1527 IRExpr_Mux0X( mkexpr(guard),
1528 IRExpr_Get(OFFB_CC_DEP1,Ity_I64),
1529 widenUto64(mkexpr(res)))) );
1530 stmt( IRStmt_Put( OFFB_CC_DEP2,
1531 IRExpr_Mux0X( mkexpr(guard),
1532 IRExpr_Get(OFFB_CC_DEP2,Ity_I64),
1533 widenUto64(mkexpr(resUS)))) );
1534}
sewardj354e5c62005-01-27 20:12:52 +00001535
1536
1537/* For the inc/dec case, we store in DEP1 the result value and in NDEP
1538 the former value of the carry flag, which unfortunately we have to
1539 compute. */
1540
1541static void setFlags_INC_DEC ( Bool inc, IRTemp res, IRType ty )
1542{
1543 Int ccOp = inc ? AMD64G_CC_OP_INCB : AMD64G_CC_OP_DECB;
1544
1545 switch (ty) {
1546 case Ity_I8: ccOp += 0; break;
1547 case Ity_I16: ccOp += 1; break;
1548 case Ity_I32: ccOp += 2; break;
1549 case Ity_I64: ccOp += 3; break;
1550 default: vassert(0);
1551 }
1552
1553 /* This has to come first, because calculating the C flag
1554 may require reading all four thunk fields. */
1555 stmt( IRStmt_Put( OFFB_CC_NDEP, mk_amd64g_calculate_rflags_c()) );
1556 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(ccOp)) );
1557 stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(res)) );
1558 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0)) );
1559}
1560
1561
sewardj32b2bbe2005-01-28 00:50:10 +00001562/* Multiplies are pretty much like add and sub: DEP1 and DEP2 hold the
1563 two arguments. */
1564
1565static
1566void setFlags_MUL ( IRType ty, IRTemp arg1, IRTemp arg2, ULong base_op )
1567{
1568 switch (ty) {
1569 case Ity_I8:
1570 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(base_op+0) ) );
1571 break;
1572 case Ity_I16:
1573 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(base_op+1) ) );
1574 break;
1575 case Ity_I32:
1576 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(base_op+2) ) );
1577 break;
1578 case Ity_I64:
1579 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(base_op+3) ) );
1580 break;
1581 default:
1582 vpanic("setFlags_MUL(amd64)");
1583 }
1584 stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto64(mkexpr(arg1)) ));
1585 stmt( IRStmt_Put( OFFB_CC_DEP2, widenUto64(mkexpr(arg2)) ));
1586}
sewardj3ca55a12005-01-27 16:06:23 +00001587
1588
1589/* -------------- Condition codes. -------------- */
1590
1591/* Condition codes, using the AMD encoding. */
1592
sewardj8c332e22005-01-28 01:36:56 +00001593static HChar* name_AMD64Condcode ( AMD64Condcode cond )
sewardj3ca55a12005-01-27 16:06:23 +00001594{
1595 switch (cond) {
1596 case AMD64CondO: return "o";
1597 case AMD64CondNO: return "no";
1598 case AMD64CondB: return "b";
sewardje941eea2005-01-30 19:52:28 +00001599 case AMD64CondNB: return "ae"; /*"nb";*/
1600 case AMD64CondZ: return "e"; /*"z";*/
1601 case AMD64CondNZ: return "ne"; /*"nz";*/
sewardj3ca55a12005-01-27 16:06:23 +00001602 case AMD64CondBE: return "be";
sewardje941eea2005-01-30 19:52:28 +00001603 case AMD64CondNBE: return "a"; /*"nbe";*/
sewardj3ca55a12005-01-27 16:06:23 +00001604 case AMD64CondS: return "s";
1605 case AMD64CondNS: return "ns";
1606 case AMD64CondP: return "p";
1607 case AMD64CondNP: return "np";
1608 case AMD64CondL: return "l";
sewardje941eea2005-01-30 19:52:28 +00001609 case AMD64CondNL: return "ge"; /*"nl";*/
sewardj3ca55a12005-01-27 16:06:23 +00001610 case AMD64CondLE: return "le";
sewardje941eea2005-01-30 19:52:28 +00001611 case AMD64CondNLE: return "g"; /*"nle";*/
sewardj3ca55a12005-01-27 16:06:23 +00001612 case AMD64CondAlways: return "ALWAYS";
1613 default: vpanic("name_AMD64Condcode");
1614 }
1615}
1616
sewardj1389d4d2005-01-28 13:46:29 +00001617static
1618AMD64Condcode positiveIse_AMD64Condcode ( AMD64Condcode cond,
1619 /*OUT*/Bool* needInvert )
1620{
1621 vassert(cond >= AMD64CondO && cond <= AMD64CondNLE);
1622 if (cond & 1) {
1623 *needInvert = True;
1624 return cond-1;
1625 } else {
1626 *needInvert = False;
1627 return cond;
1628 }
1629}
sewardjdf0e0022005-01-25 15:48:43 +00001630
1631
1632/* -------------- Helpers for ADD/SUB with carry. -------------- */
1633
1634/* Given ta1, ta2 and tres, compute tres = ADC(ta1,ta2) and set flags
1635 appropriately.
1636*/
1637static void helper_ADC ( Int sz,
1638 IRTemp tres, IRTemp ta1, IRTemp ta2 )
1639{
1640 UInt thunkOp;
1641 IRType ty = szToITy(sz);
1642 IRTemp oldc = newTemp(Ity_I64);
1643 IRTemp oldcn = newTemp(ty);
1644 IROp plus = mkSizedOp(ty, Iop_Add8);
1645 IROp xor = mkSizedOp(ty, Iop_Xor8);
1646
1647 switch (sz) {
1648 case 8: thunkOp = AMD64G_CC_OP_ADCQ; break;
1649 case 4: thunkOp = AMD64G_CC_OP_ADCL; break;
1650 case 2: thunkOp = AMD64G_CC_OP_ADCW; break;
1651 case 1: thunkOp = AMD64G_CC_OP_ADCB; break;
1652 default: vassert(0);
1653 }
1654
1655 /* oldc = old carry flag, 0 or 1 */
1656 assign( oldc, binop(Iop_And64,
1657 mk_amd64g_calculate_rflags_c(),
1658 mkU64(1)) );
1659
1660 assign( oldcn, narrowTo(ty, mkexpr(oldc)) );
1661
1662 assign( tres, binop(plus,
1663 binop(plus,mkexpr(ta1),mkexpr(ta2)),
1664 mkexpr(oldcn)) );
1665
1666 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(thunkOp) ) );
1667 stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(ta1) ) );
1668 stmt( IRStmt_Put( OFFB_CC_DEP2, binop(xor, mkexpr(ta2),
1669 mkexpr(oldcn)) ) );
1670 stmt( IRStmt_Put( OFFB_CC_NDEP, mkexpr(oldc) ) );
1671}
1672
1673
1674/* Given ta1, ta2 and tres, compute tres = SBB(ta1,ta2) and set flags
1675 appropriately.
1676*/
1677static void helper_SBB ( Int sz,
1678 IRTemp tres, IRTemp ta1, IRTemp ta2 )
1679{
1680 UInt thunkOp;
1681 IRType ty = szToITy(sz);
1682 IRTemp oldc = newTemp(Ity_I64);
1683 IRTemp oldcn = newTemp(ty);
1684 IROp minus = mkSizedOp(ty, Iop_Sub8);
1685 IROp xor = mkSizedOp(ty, Iop_Xor8);
1686
1687 switch (sz) {
1688 case 8: thunkOp = AMD64G_CC_OP_SBBQ; break;
1689 case 4: thunkOp = AMD64G_CC_OP_SBBL; break;
1690 case 2: thunkOp = AMD64G_CC_OP_SBBW; break;
1691 case 1: thunkOp = AMD64G_CC_OP_SBBB; break;
1692 default: vassert(0);
1693 }
1694
1695 /* oldc = old carry flag, 0 or 1 */
1696 assign( oldc, binop(Iop_And64,
1697 mk_amd64g_calculate_rflags_c(),
1698 mkU64(1)) );
1699
1700 assign( oldcn, narrowTo(ty, mkexpr(oldc)) );
1701
1702 assign( tres, binop(minus,
1703 binop(minus,mkexpr(ta1),mkexpr(ta2)),
1704 mkexpr(oldcn)) );
1705
1706 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(thunkOp) ) );
1707 stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(ta1) ) );
1708 stmt( IRStmt_Put( OFFB_CC_DEP2, binop(xor, mkexpr(ta2),
1709 mkexpr(oldcn)) ) );
1710 stmt( IRStmt_Put( OFFB_CC_NDEP, mkexpr(oldc) ) );
1711}
1712
1713
sewardj3ca55a12005-01-27 16:06:23 +00001714/* -------------- Helpers for disassembly printing. -------------- */
1715
1716static HChar* nameGrp1 ( Int opc_aux )
1717{
1718 static HChar* grp1_names[8]
1719 = { "add", "or", "adc", "sbb", "and", "sub", "xor", "cmp" };
1720 if (opc_aux < 0 || opc_aux > 7) vpanic("nameGrp1(amd64)");
1721 return grp1_names[opc_aux];
1722}
1723
sewardj118b23e2005-01-29 02:14:44 +00001724static HChar* nameGrp2 ( Int opc_aux )
1725{
1726 static HChar* grp2_names[8]
1727 = { "rol", "ror", "rcl", "rcr", "shl", "shr", "shl", "sar" };
sewardje941eea2005-01-30 19:52:28 +00001728 if (opc_aux < 0 || opc_aux > 7) vpanic("nameGrp2(amd64)");
sewardj118b23e2005-01-29 02:14:44 +00001729 return grp2_names[opc_aux];
1730}
1731
sewardj03b07cc2005-01-31 18:09:43 +00001732static HChar* nameGrp4 ( Int opc_aux )
1733{
1734 static HChar* grp4_names[8]
1735 = { "inc", "dec", "???", "???", "???", "???", "???", "???" };
1736 if (opc_aux < 0 || opc_aux > 1) vpanic("nameGrp4(amd64)");
1737 return grp4_names[opc_aux];
1738}
sewardj354e5c62005-01-27 20:12:52 +00001739
1740static HChar* nameGrp5 ( Int opc_aux )
1741{
1742 static HChar* grp5_names[8]
1743 = { "inc", "dec", "call*", "call*", "jmp*", "jmp*", "push", "???" };
1744 if (opc_aux < 0 || opc_aux > 6) vpanic("nameGrp5(amd64)");
1745 return grp5_names[opc_aux];
1746}
1747
sewardj1d511802005-03-27 17:59:45 +00001748static HChar* nameGrp8 ( Int opc_aux )
1749{
1750 static HChar* grp8_names[8]
1751 = { "???", "???", "???", "???", "bt", "bts", "btr", "btc" };
1752 if (opc_aux < 4 || opc_aux > 7) vpanic("nameGrp8(amd64)");
1753 return grp8_names[opc_aux];
1754}
1755
sewardjd20c8852005-01-20 20:04:07 +00001756//.. static HChar* nameSReg ( UInt sreg )
1757//.. {
1758//.. switch (sreg) {
1759//.. case R_ES: return "%es";
1760//.. case R_CS: return "%cs";
1761//.. case R_SS: return "%ss";
1762//.. case R_DS: return "%ds";
1763//.. case R_FS: return "%fs";
1764//.. case R_GS: return "%gs";
1765//.. default: vpanic("nameSReg(x86)");
1766//.. }
1767//.. }
sewardj8711f662005-05-09 17:52:56 +00001768
1769static HChar* nameMMXReg ( Int mmxreg )
1770{
1771 static HChar* mmx_names[8]
1772 = { "%mm0", "%mm1", "%mm2", "%mm3", "%mm4", "%mm5", "%mm6", "%mm7" };
1773 if (mmxreg < 0 || mmxreg > 7) vpanic("nameMMXReg(amd64,guest)");
1774 return mmx_names[mmxreg];
1775}
sewardj1001dc42005-02-21 08:25:55 +00001776
1777static HChar* nameXMMReg ( Int xmmreg )
1778{
1779 static HChar* xmm_names[16]
1780 = { "%xmm0", "%xmm1", "%xmm2", "%xmm3",
1781 "%xmm4", "%xmm5", "%xmm6", "%xmm7",
1782 "%xmm8", "%xmm9", "%xmm10", "%xmm11",
1783 "%xmm12", "%xmm13", "%xmm14", "%xmm15" };
1784 if (xmmreg < 0 || xmmreg > 15) vpanic("nameXMMReg(amd64)");
1785 return xmm_names[xmmreg];
1786}
1787
sewardjca673ab2005-05-11 10:03:08 +00001788static HChar* nameMMXGran ( Int gran )
sewardj8711f662005-05-09 17:52:56 +00001789{
1790 switch (gran) {
1791 case 0: return "b";
1792 case 1: return "w";
1793 case 2: return "d";
1794 case 3: return "q";
1795 default: vpanic("nameMMXGran(amd64,guest)");
1796 }
1797}
sewardjdf0e0022005-01-25 15:48:43 +00001798
sewardj8c332e22005-01-28 01:36:56 +00001799static HChar nameISize ( Int size )
sewardjdf0e0022005-01-25 15:48:43 +00001800{
1801 switch (size) {
1802 case 8: return 'q';
1803 case 4: return 'l';
1804 case 2: return 'w';
1805 case 1: return 'b';
1806 default: vpanic("nameISize(amd64)");
1807 }
1808}
1809
1810
1811/*------------------------------------------------------------*/
1812/*--- JMP helpers ---*/
1813/*------------------------------------------------------------*/
1814
1815static void jmp_lit( IRJumpKind kind, Addr64 d64 )
1816{
1817 irbb->next = mkU64(d64);
1818 irbb->jumpkind = kind;
1819}
1820
sewardj2f959cc2005-01-26 01:19:35 +00001821static void jmp_treg( IRJumpKind kind, IRTemp t )
1822{
sewardj3ca55a12005-01-27 16:06:23 +00001823 irbb->next = mkexpr(t);
sewardj2f959cc2005-01-26 01:19:35 +00001824 irbb->jumpkind = kind;
1825}
1826
sewardj1389d4d2005-01-28 13:46:29 +00001827static
1828void jcc_01 ( AMD64Condcode cond, Addr64 d64_false, Addr64 d64_true )
1829{
1830 Bool invert;
1831 AMD64Condcode condPos;
1832 condPos = positiveIse_AMD64Condcode ( cond, &invert );
1833 if (invert) {
1834 stmt( IRStmt_Exit( mk_amd64g_calculate_condition(condPos),
1835 Ijk_Boring,
1836 IRConst_U64(d64_false) ) );
1837 irbb->next = mkU64(d64_true);
1838 irbb->jumpkind = Ijk_Boring;
1839 } else {
1840 stmt( IRStmt_Exit( mk_amd64g_calculate_condition(condPos),
1841 Ijk_Boring,
1842 IRConst_U64(d64_true) ) );
1843 irbb->next = mkU64(d64_false);
1844 irbb->jumpkind = Ijk_Boring;
1845 }
1846}
sewardjb3a04292005-01-21 20:33:44 +00001847
sewardj5a9ffab2005-05-12 17:55:01 +00001848/* Let new_rsp be the %rsp value after a call/return. This function
1849 generates an AbiHint to say that -128(%rsp) .. -1(%rsp) should now
1850 be regarded as uninitialised.
1851*/
1852static void make_redzone_AbiHint ( IRTemp new_rsp, HChar* who )
1853{
1854 if (0) vex_printf("AbiHint: %s\n", who);
1855 vassert(typeOfIRTemp(irbb->tyenv, new_rsp) == Ity_I64);
1856 stmt( IRStmt_AbiHint(
1857 binop(Iop_Sub64, mkexpr(new_rsp), mkU64(128)),
1858 128
1859 ));
1860}
1861
sewardjb3a04292005-01-21 20:33:44 +00001862
1863/*------------------------------------------------------------*/
1864/*--- Disassembling addressing modes ---*/
1865/*------------------------------------------------------------*/
1866
1867static
sewardj8c332e22005-01-28 01:36:56 +00001868HChar* sorbTxt ( Prefix pfx )
sewardjb3a04292005-01-21 20:33:44 +00001869{
1870 if (pfx & PFX_CS) return "%cs:";
1871 if (pfx & PFX_DS) return "%ds:";
1872 if (pfx & PFX_ES) return "%es:";
1873 if (pfx & PFX_FS) return "%fs:";
1874 if (pfx & PFX_GS) return "%gs:";
1875 if (pfx & PFX_SS) return "%ss:";
1876 return ""; /* no override */
1877}
1878
1879
1880/* 'virtual' is an IRExpr* holding a virtual address. Convert it to a
1881 linear address by adding any required segment override as indicated
1882 by sorb. */
1883static
1884IRExpr* handleSegOverride ( Prefix pfx, IRExpr* virtual )
1885{
sewardja6b93d12005-02-17 09:28:28 +00001886 if (pfx & PFX_FS) {
1887 /* Note that this is a linux-kernel specific hack that relies
1888 on the assumption that %fs is always zero. */
1889 /* return virtual + guest_FS_ZERO. */
1890 return binop(Iop_Add64, virtual, IRExpr_Get(OFFB_FS_ZERO, Ity_I64));
1891 }
sewardjb3a04292005-01-21 20:33:44 +00001892
sewardja6b93d12005-02-17 09:28:28 +00001893 if (pfx & PFX_GS) {
1894 unimplemented("amd64 %gs segment override");
1895 }
1896
1897 /* cs, ds, es and ss are simply ignored in 64-bit mode. */
1898 return virtual;
sewardjb3a04292005-01-21 20:33:44 +00001899}
sewardja6b93d12005-02-17 09:28:28 +00001900
sewardjd20c8852005-01-20 20:04:07 +00001901//.. {
1902//.. Int sreg;
1903//.. IRType hWordTy;
1904//.. IRTemp ldt_ptr, gdt_ptr, seg_selector, r64;
1905//..
1906//.. if (sorb == 0)
1907//.. /* the common case - no override */
1908//.. return virtual;
1909//..
1910//.. switch (sorb) {
1911//.. case 0x3E: sreg = R_DS; break;
1912//.. case 0x26: sreg = R_ES; break;
1913//.. case 0x64: sreg = R_FS; break;
1914//.. case 0x65: sreg = R_GS; break;
1915//.. default: vpanic("handleSegOverride(x86,guest)");
1916//.. }
1917//..
1918//.. hWordTy = sizeof(HWord)==4 ? Ity_I32 : Ity_I64;
1919//..
1920//.. seg_selector = newTemp(Ity_I32);
1921//.. ldt_ptr = newTemp(hWordTy);
1922//.. gdt_ptr = newTemp(hWordTy);
1923//.. r64 = newTemp(Ity_I64);
1924//..
1925//.. assign( seg_selector, unop(Iop_16Uto32, getSReg(sreg)) );
1926//.. assign( ldt_ptr, IRExpr_Get( OFFB_LDT, hWordTy ));
1927//.. assign( gdt_ptr, IRExpr_Get( OFFB_GDT, hWordTy ));
1928//..
1929//.. /*
1930//.. Call this to do the translation and limit checks:
1931//.. ULong x86g_use_seg_selector ( HWord ldt, HWord gdt,
1932//.. UInt seg_selector, UInt virtual_addr )
1933//.. */
1934//.. assign(
1935//.. r64,
1936//.. mkIRExprCCall(
1937//.. Ity_I64,
1938//.. 0/*regparms*/,
1939//.. "x86g_use_seg_selector",
1940//.. &x86g_use_seg_selector,
1941//.. mkIRExprVec_4( mkexpr(ldt_ptr), mkexpr(gdt_ptr),
1942//.. mkexpr(seg_selector), virtual)
1943//.. )
1944//.. );
1945//..
1946//.. /* If the high 32 of the result are non-zero, there was a
1947//.. failure in address translation. In which case, make a
1948//.. quick exit.
1949//.. */
1950//.. stmt(
1951//.. IRStmt_Exit(
1952//.. binop(Iop_CmpNE32, unop(Iop_64HIto32, mkexpr(r64)), mkU32(0)),
1953//.. Ijk_MapFail,
1954//.. IRConst_U32( guest_eip_curr_instr )
1955//.. )
1956//.. );
1957//..
1958//.. /* otherwise, here's the translated result. */
1959//.. return unop(Iop_64to32, mkexpr(r64));
1960//.. }
sewardjb3a04292005-01-21 20:33:44 +00001961
1962
1963/* Generate IR to calculate an address indicated by a ModRM and
1964 following SIB bytes. The expression, and the number of bytes in
1965 the address mode, are returned (the latter in *len). Note that
1966 this fn should not be called if the R/M part of the address denotes
1967 a register instead of memory. If print_codegen is true, text of
1968 the addressing mode is placed in buf.
1969
1970 The computed address is stored in a new tempreg, and the
sewardje1698952005-02-08 15:02:39 +00001971 identity of the tempreg is returned.
1972
1973 extra_bytes holds the number of bytes after the amode, as supplied
1974 by the caller. This is needed to make sense of %rip-relative
1975 addresses. Note that the value that *len is set to is only the
1976 length of the amode itself and does not include the value supplied
sewardj09717342005-05-05 21:34:02 +00001977 in extra_bytes.
sewardje1698952005-02-08 15:02:39 +00001978 */
sewardjb3a04292005-01-21 20:33:44 +00001979
1980static IRTemp disAMode_copy2tmp ( IRExpr* addr64 )
1981{
1982 IRTemp tmp = newTemp(Ity_I64);
1983 assign( tmp, addr64 );
1984 return tmp;
1985}
1986
1987static
sewardj270def42005-07-03 01:03:01 +00001988IRTemp disAMode ( Int* len, Prefix pfx, Long delta,
sewardje1698952005-02-08 15:02:39 +00001989 HChar* buf, Int extra_bytes )
sewardjb3a04292005-01-21 20:33:44 +00001990{
sewardj8c332e22005-01-28 01:36:56 +00001991 UChar mod_reg_rm = getUChar(delta);
sewardjb3a04292005-01-21 20:33:44 +00001992 delta++;
1993
1994 buf[0] = (UChar)0;
sewardje1698952005-02-08 15:02:39 +00001995 vassert(extra_bytes >= 0 && extra_bytes < 10);
sewardjb3a04292005-01-21 20:33:44 +00001996
1997 /* squeeze out the reg field from mod_reg_rm, since a 256-entry
1998 jump table seems a bit excessive.
1999 */
sewardj7a240552005-01-28 21:37:12 +00002000 mod_reg_rm &= 0xC7; /* is now XX000YYY */
sewardj1027dc22005-02-26 01:55:02 +00002001 mod_reg_rm = toUChar(mod_reg_rm | (mod_reg_rm >> 3));
2002 /* is now XX0XXYYY */
sewardj7a240552005-01-28 21:37:12 +00002003 mod_reg_rm &= 0x1F; /* is now 000XXYYY */
sewardjb3a04292005-01-21 20:33:44 +00002004 switch (mod_reg_rm) {
2005
2006 /* REX.B==0: (%rax) .. (%rdi), not including (%rsp) or (%rbp).
2007 REX.B==1: (%r8) .. (%r15), not including (%r12) or (%r13).
2008 */
2009 case 0x00: case 0x01: case 0x02: case 0x03:
2010 /* ! 04 */ /* ! 05 */ case 0x06: case 0x07:
sewardj1027dc22005-02-26 01:55:02 +00002011 { UChar rm = toUChar(mod_reg_rm & 7);
sewardj5b470602005-02-27 13:10:48 +00002012 DIS(buf, "%s(%s)", sorbTxt(pfx), nameIRegRexB(8,pfx,rm));
sewardjb3a04292005-01-21 20:33:44 +00002013 *len = 1;
2014 return disAMode_copy2tmp(
sewardj5b470602005-02-27 13:10:48 +00002015 handleSegOverride(pfx, getIRegRexB(8,pfx,rm)));
sewardjb3a04292005-01-21 20:33:44 +00002016 }
2017
2018 /* REX.B==0: d8(%rax) ... d8(%rdi), not including d8(%rsp)
2019 REX.B==1: d8(%r8) ... d8(%r15), not including d8(%r12)
2020 */
2021 case 0x08: case 0x09: case 0x0A: case 0x0B:
2022 /* ! 0C */ case 0x0D: case 0x0E: case 0x0F:
sewardj1027dc22005-02-26 01:55:02 +00002023 { UChar rm = toUChar(mod_reg_rm & 7);
sewardj8c332e22005-01-28 01:36:56 +00002024 Long d = getSDisp8(delta);
sewardj7eaa7cf2005-01-31 18:55:22 +00002025 if (d == 0) {
sewardj5b470602005-02-27 13:10:48 +00002026 DIS(buf, "%s(%s)", sorbTxt(pfx), nameIRegRexB(8,pfx,rm));
sewardj7eaa7cf2005-01-31 18:55:22 +00002027 } else {
sewardj5b470602005-02-27 13:10:48 +00002028 DIS(buf, "%s%lld(%s)", sorbTxt(pfx), d, nameIRegRexB(8,pfx,rm));
sewardj7eaa7cf2005-01-31 18:55:22 +00002029 }
sewardjb3a04292005-01-21 20:33:44 +00002030 *len = 2;
2031 return disAMode_copy2tmp(
2032 handleSegOverride(pfx,
sewardj5b470602005-02-27 13:10:48 +00002033 binop(Iop_Add64,getIRegRexB(8,pfx,rm),mkU64(d))));
sewardjb3a04292005-01-21 20:33:44 +00002034 }
2035
2036 /* REX.B==0: d32(%rax) ... d32(%rdi), not including d32(%rsp)
2037 REX.B==1: d32(%r8) ... d32(%r15), not including d32(%r12)
2038 */
2039 case 0x10: case 0x11: case 0x12: case 0x13:
2040 /* ! 14 */ case 0x15: case 0x16: case 0x17:
sewardj1027dc22005-02-26 01:55:02 +00002041 { UChar rm = toUChar(mod_reg_rm & 7);
sewardj227458e2005-01-31 19:04:50 +00002042 Long d = getSDisp32(delta);
sewardj5b470602005-02-27 13:10:48 +00002043 DIS(buf, "%s%lld(%s)", sorbTxt(pfx), d, nameIRegRexB(8,pfx,rm));
sewardjb3a04292005-01-21 20:33:44 +00002044 *len = 5;
2045 return disAMode_copy2tmp(
2046 handleSegOverride(pfx,
sewardj5b470602005-02-27 13:10:48 +00002047 binop(Iop_Add64,getIRegRexB(8,pfx,rm),mkU64(d))));
sewardjb3a04292005-01-21 20:33:44 +00002048 }
2049
2050 /* REX.B==0: a register, %rax .. %rdi. This shouldn't happen. */
2051 /* REX.B==1: a register, %r8 .. %r16. This shouldn't happen. */
2052 case 0x18: case 0x19: case 0x1A: case 0x1B:
2053 case 0x1C: case 0x1D: case 0x1E: case 0x1F:
sewardj354e5c62005-01-27 20:12:52 +00002054 vpanic("disAMode(amd64): not an addr!");
sewardjb3a04292005-01-21 20:33:44 +00002055
sewardj9e6491a2005-07-02 19:24:10 +00002056 /* RIP + disp32. This assumes that guest_RIP_curr_instr is set
sewardjb3a04292005-01-21 20:33:44 +00002057 correctly at the start of handling each instruction. */
2058 case 0x05:
sewardj227458e2005-01-31 19:04:50 +00002059 { Long d = getSDisp32(delta);
sewardjb3a04292005-01-21 20:33:44 +00002060 *len = 5;
sewardj7eaa7cf2005-01-31 18:55:22 +00002061 DIS(buf, "%s%lld(%%rip)", sorbTxt(pfx), d);
sewardj4b744762005-02-07 15:02:25 +00002062 /* We need to know the next instruction's start address.
2063 Try and figure out what it is, record the guess, and ask
2064 the top-level driver logic (bbToIR_AMD64) to check we
2065 guessed right, after the instruction is completely
2066 decoded. */
sewardj9e6491a2005-07-02 19:24:10 +00002067 guest_RIP_next_mustcheck = True;
2068 guest_RIP_next_assumed = guest_RIP_bbstart
sewardje1698952005-02-08 15:02:39 +00002069 + delta+4 + extra_bytes;
sewardjb3a04292005-01-21 20:33:44 +00002070 return disAMode_copy2tmp(
2071 handleSegOverride(pfx,
sewardj9e6491a2005-07-02 19:24:10 +00002072 binop(Iop_Add64, mkU64(guest_RIP_next_assumed),
sewardjb3a04292005-01-21 20:33:44 +00002073 mkU64(d))));
2074 }
sewardj3ca55a12005-01-27 16:06:23 +00002075
sewardj2f959cc2005-01-26 01:19:35 +00002076 case 0x04: {
2077 /* SIB, with no displacement. Special cases:
sewardj3ca55a12005-01-27 16:06:23 +00002078 -- %rsp cannot act as an index value.
2079 If index_r indicates %rsp, zero is used for the index.
2080 -- when mod is zero and base indicates RBP or R13, base is
2081 instead a 32-bit sign-extended literal.
sewardj2f959cc2005-01-26 01:19:35 +00002082 It's all madness, I tell you. Extract %index, %base and
2083 scale from the SIB byte. The value denoted is then:
sewardj3ca55a12005-01-27 16:06:23 +00002084 | %index == %RSP && (%base == %RBP || %base == %R13)
sewardj2f959cc2005-01-26 01:19:35 +00002085 = d32 following SIB byte
sewardj3ca55a12005-01-27 16:06:23 +00002086 | %index == %RSP && !(%base == %RBP || %base == %R13)
sewardj2f959cc2005-01-26 01:19:35 +00002087 = %base
sewardj3ca55a12005-01-27 16:06:23 +00002088 | %index != %RSP && (%base == %RBP || %base == %R13)
sewardj2f959cc2005-01-26 01:19:35 +00002089 = d32 following SIB byte + (%index << scale)
sewardj3ca55a12005-01-27 16:06:23 +00002090 | %index != %RSP && !(%base == %RBP || %base == %R13)
sewardj2f959cc2005-01-26 01:19:35 +00002091 = %base + (%index << scale)
2092 */
sewardj8c332e22005-01-28 01:36:56 +00002093 UChar sib = getUChar(delta);
sewardj1027dc22005-02-26 01:55:02 +00002094 UChar scale = toUChar((sib >> 6) & 3);
2095 UChar index_r = toUChar((sib >> 3) & 7);
2096 UChar base_r = toUChar(sib & 7);
sewardj3ca55a12005-01-27 16:06:23 +00002097 /* correct since #(R13) == 8 + #(RBP) */
sewardj7a240552005-01-28 21:37:12 +00002098 Bool base_is_BPor13 = toBool(base_r == R_RBP);
2099 Bool index_is_SP = toBool(index_r == R_RSP && 0==getRexX(pfx));
sewardj2f959cc2005-01-26 01:19:35 +00002100 delta++;
sewardjb3a04292005-01-21 20:33:44 +00002101
sewardj3ca55a12005-01-27 16:06:23 +00002102 if ((!index_is_SP) && (!base_is_BPor13)) {
sewardje941eea2005-01-30 19:52:28 +00002103 if (scale == 0) {
2104 DIS(buf, "%s(%s,%s)", sorbTxt(pfx),
sewardj5b470602005-02-27 13:10:48 +00002105 nameIRegRexB(8,pfx,base_r),
2106 nameIReg64rexX(pfx,index_r));
sewardje941eea2005-01-30 19:52:28 +00002107 } else {
2108 DIS(buf, "%s(%s,%s,%d)", sorbTxt(pfx),
sewardj5b470602005-02-27 13:10:48 +00002109 nameIRegRexB(8,pfx,base_r),
2110 nameIReg64rexX(pfx,index_r), 1<<scale);
sewardje941eea2005-01-30 19:52:28 +00002111 }
sewardj2f959cc2005-01-26 01:19:35 +00002112 *len = 2;
sewardj2f959cc2005-01-26 01:19:35 +00002113 return
2114 disAMode_copy2tmp(
sewardj3ca55a12005-01-27 16:06:23 +00002115 handleSegOverride(pfx,
2116 binop(Iop_Add64,
sewardj5b470602005-02-27 13:10:48 +00002117 getIRegRexB(8,pfx,base_r),
2118 binop(Iop_Shl64, getIReg64rexX(pfx,index_r),
sewardj2f959cc2005-01-26 01:19:35 +00002119 mkU8(scale)))));
2120 }
2121
sewardj3ca55a12005-01-27 16:06:23 +00002122 if ((!index_is_SP) && base_is_BPor13) {
sewardj227458e2005-01-31 19:04:50 +00002123 Long d = getSDisp32(delta);
sewardj7eaa7cf2005-01-31 18:55:22 +00002124 DIS(buf, "%s%lld(,%s,%d)", sorbTxt(pfx), d,
sewardj5b470602005-02-27 13:10:48 +00002125 nameIReg64rexX(pfx,index_r), 1<<scale);
sewardj2f959cc2005-01-26 01:19:35 +00002126 *len = 6;
sewardj2f959cc2005-01-26 01:19:35 +00002127 return
2128 disAMode_copy2tmp(
sewardj3ca55a12005-01-27 16:06:23 +00002129 handleSegOverride(pfx,
2130 binop(Iop_Add64,
sewardj5b470602005-02-27 13:10:48 +00002131 binop(Iop_Shl64, getIReg64rexX(pfx,index_r),
sewardj3ca55a12005-01-27 16:06:23 +00002132 mkU8(scale)),
2133 mkU64(d))));
sewardj2f959cc2005-01-26 01:19:35 +00002134 }
2135
sewardj3ca55a12005-01-27 16:06:23 +00002136 if (index_is_SP && (!base_is_BPor13)) {
sewardj5b470602005-02-27 13:10:48 +00002137 DIS(buf, "%s(%s)", sorbTxt(pfx), nameIRegRexB(8,pfx,base_r));
sewardj2f959cc2005-01-26 01:19:35 +00002138 *len = 2;
sewardj2f959cc2005-01-26 01:19:35 +00002139 return disAMode_copy2tmp(
sewardj5b470602005-02-27 13:10:48 +00002140 handleSegOverride(pfx, getIRegRexB(8,pfx,base_r)));
sewardj2f959cc2005-01-26 01:19:35 +00002141 }
2142
sewardj3ca55a12005-01-27 16:06:23 +00002143 if (index_is_SP && base_is_BPor13) {
sewardj227458e2005-01-31 19:04:50 +00002144 Long d = getSDisp32(delta);
sewardj7eaa7cf2005-01-31 18:55:22 +00002145 DIS(buf, "%s%lld", sorbTxt(pfx), d);
sewardj2f959cc2005-01-26 01:19:35 +00002146 *len = 6;
sewardj2f959cc2005-01-26 01:19:35 +00002147 return disAMode_copy2tmp(
sewardj3ca55a12005-01-27 16:06:23 +00002148 handleSegOverride(pfx, mkU64(d)));
sewardj2f959cc2005-01-26 01:19:35 +00002149 }
2150
2151 vassert(0);
2152 }
sewardj3ca55a12005-01-27 16:06:23 +00002153
sewardj2f959cc2005-01-26 01:19:35 +00002154 /* SIB, with 8-bit displacement. Special cases:
2155 -- %esp cannot act as an index value.
2156 If index_r indicates %esp, zero is used for the index.
2157 Denoted value is:
2158 | %index == %ESP
2159 = d8 + %base
2160 | %index != %ESP
2161 = d8 + %base + (%index << scale)
2162 */
2163 case 0x0C: {
sewardj8c332e22005-01-28 01:36:56 +00002164 UChar sib = getUChar(delta);
sewardj1027dc22005-02-26 01:55:02 +00002165 UChar scale = toUChar((sib >> 6) & 3);
2166 UChar index_r = toUChar((sib >> 3) & 7);
2167 UChar base_r = toUChar(sib & 7);
sewardj8c332e22005-01-28 01:36:56 +00002168 Long d = getSDisp8(delta+1);
sewardj2f959cc2005-01-26 01:19:35 +00002169
sewardj3ca55a12005-01-27 16:06:23 +00002170 if (index_r == R_RSP && 0==getRexX(pfx)) {
sewardje941eea2005-01-30 19:52:28 +00002171 DIS(buf, "%s%lld(%s)", sorbTxt(pfx),
sewardj5b470602005-02-27 13:10:48 +00002172 d, nameIRegRexB(8,pfx,base_r));
sewardj2f959cc2005-01-26 01:19:35 +00002173 *len = 3;
sewardj2f959cc2005-01-26 01:19:35 +00002174 return disAMode_copy2tmp(
sewardj3ca55a12005-01-27 16:06:23 +00002175 handleSegOverride(pfx,
sewardj5b470602005-02-27 13:10:48 +00002176 binop(Iop_Add64, getIRegRexB(8,pfx,base_r), mkU64(d)) ));
sewardj2f959cc2005-01-26 01:19:35 +00002177 } else {
sewardje941eea2005-01-30 19:52:28 +00002178 if (scale == 0) {
2179 DIS(buf, "%s%lld(%s,%s)", sorbTxt(pfx), d,
sewardj5b470602005-02-27 13:10:48 +00002180 nameIRegRexB(8,pfx,base_r),
2181 nameIReg64rexX(pfx,index_r));
sewardje941eea2005-01-30 19:52:28 +00002182 } else {
2183 DIS(buf, "%s%lld(%s,%s,%d)", sorbTxt(pfx), d,
sewardj5b470602005-02-27 13:10:48 +00002184 nameIRegRexB(8,pfx,base_r),
2185 nameIReg64rexX(pfx,index_r), 1<<scale);
sewardje941eea2005-01-30 19:52:28 +00002186 }
sewardj2f959cc2005-01-26 01:19:35 +00002187 *len = 3;
sewardj2f959cc2005-01-26 01:19:35 +00002188 return
2189 disAMode_copy2tmp(
sewardj3ca55a12005-01-27 16:06:23 +00002190 handleSegOverride(pfx,
2191 binop(Iop_Add64,
2192 binop(Iop_Add64,
sewardj5b470602005-02-27 13:10:48 +00002193 getIRegRexB(8,pfx,base_r),
sewardj3ca55a12005-01-27 16:06:23 +00002194 binop(Iop_Shl64,
sewardj5b470602005-02-27 13:10:48 +00002195 getIReg64rexX(pfx,index_r), mkU8(scale))),
sewardj3ca55a12005-01-27 16:06:23 +00002196 mkU64(d))));
sewardj2f959cc2005-01-26 01:19:35 +00002197 }
sewardj3ca55a12005-01-27 16:06:23 +00002198 vassert(0); /*NOTREACHED*/
sewardj2f959cc2005-01-26 01:19:35 +00002199 }
sewardj3ca55a12005-01-27 16:06:23 +00002200
sewardj2f959cc2005-01-26 01:19:35 +00002201 /* SIB, with 32-bit displacement. Special cases:
2202 -- %rsp cannot act as an index value.
2203 If index_r indicates %rsp, zero is used for the index.
2204 Denoted value is:
2205 | %index == %RSP
2206 = d32 + %base
2207 | %index != %RSP
2208 = d32 + %base + (%index << scale)
2209 */
2210 case 0x14: {
sewardj8c332e22005-01-28 01:36:56 +00002211 UChar sib = getUChar(delta);
sewardj1027dc22005-02-26 01:55:02 +00002212 UChar scale = toUChar((sib >> 6) & 3);
2213 UChar index_r = toUChar((sib >> 3) & 7);
2214 UChar base_r = toUChar(sib & 7);
sewardj8c332e22005-01-28 01:36:56 +00002215 Long d = getSDisp32(delta+1);
sewardj2f959cc2005-01-26 01:19:35 +00002216
2217 if (index_r == R_RSP && 0==getRexX(pfx)) {
sewardje941eea2005-01-30 19:52:28 +00002218 DIS(buf, "%s%lld(%s)", sorbTxt(pfx),
sewardj5b470602005-02-27 13:10:48 +00002219 d, nameIRegRexB(8,pfx,base_r));
sewardj2f959cc2005-01-26 01:19:35 +00002220 *len = 6;
sewardj2f959cc2005-01-26 01:19:35 +00002221 return disAMode_copy2tmp(
2222 handleSegOverride(pfx,
sewardj5b470602005-02-27 13:10:48 +00002223 binop(Iop_Add64, getIRegRexB(8,pfx,base_r), mkU64(d)) ));
sewardj2f959cc2005-01-26 01:19:35 +00002224 } else {
sewardje941eea2005-01-30 19:52:28 +00002225 if (scale == 0) {
2226 DIS(buf, "%s%lld(%s,%s)", sorbTxt(pfx), d,
sewardj5b470602005-02-27 13:10:48 +00002227 nameIRegRexB(8,pfx,base_r),
2228 nameIReg64rexX(pfx,index_r));
sewardje941eea2005-01-30 19:52:28 +00002229 } else {
2230 DIS(buf, "%s%lld(%s,%s,%d)", sorbTxt(pfx), d,
sewardj5b470602005-02-27 13:10:48 +00002231 nameIRegRexB(8,pfx,base_r),
2232 nameIReg64rexX(pfx,index_r), 1<<scale);
sewardje941eea2005-01-30 19:52:28 +00002233 }
sewardj2f959cc2005-01-26 01:19:35 +00002234 *len = 6;
2235 return
2236 disAMode_copy2tmp(
2237 handleSegOverride(pfx,
2238 binop(Iop_Add64,
2239 binop(Iop_Add64,
sewardj5b470602005-02-27 13:10:48 +00002240 getIRegRexB(8,pfx,base_r),
sewardj2f959cc2005-01-26 01:19:35 +00002241 binop(Iop_Shl64,
sewardj5b470602005-02-27 13:10:48 +00002242 getIReg64rexX(pfx,index_r), mkU8(scale))),
sewardj2f959cc2005-01-26 01:19:35 +00002243 mkU64(d))));
2244 }
sewardj3ca55a12005-01-27 16:06:23 +00002245 vassert(0); /*NOTREACHED*/
sewardj2f959cc2005-01-26 01:19:35 +00002246 }
2247
sewardjb3a04292005-01-21 20:33:44 +00002248 default:
2249 vpanic("disAMode(amd64)");
2250 return 0; /*notreached*/
2251 }
2252}
2253
2254
sewardj3ca55a12005-01-27 16:06:23 +00002255/* Figure out the number of (insn-stream) bytes constituting the amode
2256 beginning at delta. Is useful for getting hold of literals beyond
2257 the end of the amode before it has been disassembled. */
2258
sewardj270def42005-07-03 01:03:01 +00002259static UInt lengthAMode ( Prefix pfx, Long delta )
sewardj3ca55a12005-01-27 16:06:23 +00002260{
sewardj8c332e22005-01-28 01:36:56 +00002261 UChar mod_reg_rm = getUChar(delta);
sewardj3ca55a12005-01-27 16:06:23 +00002262 delta++;
2263
2264 /* squeeze out the reg field from mod_reg_rm, since a 256-entry
2265 jump table seems a bit excessive.
2266 */
sewardj7a240552005-01-28 21:37:12 +00002267 mod_reg_rm &= 0xC7; /* is now XX000YYY */
sewardj1027dc22005-02-26 01:55:02 +00002268 mod_reg_rm = toUChar(mod_reg_rm | (mod_reg_rm >> 3));
2269 /* is now XX0XXYYY */
sewardj7a240552005-01-28 21:37:12 +00002270 mod_reg_rm &= 0x1F; /* is now 000XXYYY */
sewardj3ca55a12005-01-27 16:06:23 +00002271 switch (mod_reg_rm) {
2272
2273 /* REX.B==0: (%rax) .. (%rdi), not including (%rsp) or (%rbp).
2274 REX.B==1: (%r8) .. (%r15), not including (%r12) or (%r13).
2275 */
2276 case 0x00: case 0x01: case 0x02: case 0x03:
2277 /* ! 04 */ /* ! 05 */ case 0x06: case 0x07:
sewardj3ca55a12005-01-27 16:06:23 +00002278 return 1;
2279
2280 /* REX.B==0: d8(%rax) ... d8(%rdi), not including d8(%rsp)
2281 REX.B==1: d8(%r8) ... d8(%r15), not including d8(%r12)
2282 */
2283 case 0x08: case 0x09: case 0x0A: case 0x0B:
2284 /* ! 0C */ case 0x0D: case 0x0E: case 0x0F:
sewardj3ca55a12005-01-27 16:06:23 +00002285 return 2;
2286
2287 /* REX.B==0: d32(%rax) ... d32(%rdi), not including d32(%rsp)
2288 REX.B==1: d32(%r8) ... d32(%r15), not including d32(%r12)
2289 */
2290 case 0x10: case 0x11: case 0x12: case 0x13:
2291 /* ! 14 */ case 0x15: case 0x16: case 0x17:
sewardj3ca55a12005-01-27 16:06:23 +00002292 return 5;
2293
2294 /* REX.B==0: a register, %rax .. %rdi. This shouldn't happen. */
2295 /* REX.B==1: a register, %r8 .. %r16. This shouldn't happen. */
2296 /* Not an address, but still handled. */
2297 case 0x18: case 0x19: case 0x1A: case 0x1B:
2298 case 0x1C: case 0x1D: case 0x1E: case 0x1F:
2299 return 1;
2300
2301 /* RIP + disp32. */
2302 case 0x05:
sewardj3ca55a12005-01-27 16:06:23 +00002303 return 5;
2304
2305 case 0x04: {
2306 /* SIB, with no displacement. */
sewardj8c332e22005-01-28 01:36:56 +00002307 UChar sib = getUChar(delta);
sewardj1027dc22005-02-26 01:55:02 +00002308 UChar base_r = toUChar(sib & 7);
sewardj3ca55a12005-01-27 16:06:23 +00002309 /* correct since #(R13) == 8 + #(RBP) */
sewardj7a240552005-01-28 21:37:12 +00002310 Bool base_is_BPor13 = toBool(base_r == R_RBP);
sewardj3ca55a12005-01-27 16:06:23 +00002311
2312 if (base_is_BPor13) {
sewardj3ca55a12005-01-27 16:06:23 +00002313 return 6;
2314 } else {
sewardj3ca55a12005-01-27 16:06:23 +00002315 return 2;
2316 }
2317 }
2318
2319 /* SIB, with 8-bit displacement. */
2320 case 0x0C:
2321 return 3;
2322
2323 /* SIB, with 32-bit displacement. */
2324 case 0x14:
2325 return 6;
2326
2327 default:
2328 vpanic("lengthAMode(amd64)");
2329 return 0; /*notreached*/
2330 }
2331}
2332
2333
sewardjdf0e0022005-01-25 15:48:43 +00002334/*------------------------------------------------------------*/
2335/*--- Disassembling common idioms ---*/
2336/*------------------------------------------------------------*/
2337
sewardjdf0e0022005-01-25 15:48:43 +00002338/* Handle binary integer instructions of the form
2339 op E, G meaning
2340 op reg-or-mem, reg
2341 Is passed the a ptr to the modRM byte, the actual operation, and the
2342 data size. Returns the address advanced completely over this
2343 instruction.
2344
2345 E(src) is reg-or-mem
2346 G(dst) is reg.
2347
2348 If E is reg, --> GET %G, tmp
2349 OP %E, tmp
2350 PUT tmp, %G
2351
2352 If E is mem and OP is not reversible,
2353 --> (getAddr E) -> tmpa
2354 LD (tmpa), tmpa
2355 GET %G, tmp2
2356 OP tmpa, tmp2
2357 PUT tmp2, %G
2358
2359 If E is mem and OP is reversible
2360 --> (getAddr E) -> tmpa
2361 LD (tmpa), tmpa
2362 OP %G, tmpa
2363 PUT tmpa, %G
2364*/
2365static
2366ULong dis_op2_E_G ( Prefix pfx,
2367 Bool addSubCarry,
2368 IROp op8,
2369 Bool keep,
2370 Int size,
sewardj270def42005-07-03 01:03:01 +00002371 Long delta0,
sewardj8c332e22005-01-28 01:36:56 +00002372 HChar* t_amd64opc )
sewardjdf0e0022005-01-25 15:48:43 +00002373{
2374 HChar dis_buf[50];
2375 Int len;
2376 IRType ty = szToITy(size);
2377 IRTemp dst1 = newTemp(ty);
2378 IRTemp src = newTemp(ty);
2379 IRTemp dst0 = newTemp(ty);
2380 UChar rm = getUChar(delta0);
2381 IRTemp addr = IRTemp_INVALID;
2382
2383 /* addSubCarry == True indicates the intended operation is
2384 add-with-carry or subtract-with-borrow. */
2385 if (addSubCarry) {
2386 vassert(op8 == Iop_Add8 || op8 == Iop_Sub8);
2387 vassert(keep);
2388 }
2389
2390 if (epartIsReg(rm)) {
sewardjdf0e0022005-01-25 15:48:43 +00002391 /* Specially handle XOR reg,reg, because that doesn't really
2392 depend on reg, and doing the obvious thing potentially
2393 generates a spurious value check failure due to the bogus
2394 dependency. */
sewardj5b470602005-02-27 13:10:48 +00002395 if ((op8 == Iop_Xor8 || (op8 == Iop_Sub8 && addSubCarry))
2396 && offsetIRegG(size,pfx,rm) == offsetIRegE(size,pfx,rm)) {
sewardj4f9847d2005-07-25 11:58:34 +00002397 if (False && op8 == Iop_Sub8)
sewardj5b470602005-02-27 13:10:48 +00002398 vex_printf("vex amd64->IR: sbb %%r,%%r optimisation(1)\n");
2399 putIRegG(size,pfx,rm, mkU(ty,0));
sewardjdf0e0022005-01-25 15:48:43 +00002400 }
sewardj5b470602005-02-27 13:10:48 +00002401
2402 assign( dst0, getIRegG(size,pfx,rm) );
2403 assign( src, getIRegE(size,pfx,rm) );
sewardjdf0e0022005-01-25 15:48:43 +00002404
2405 if (addSubCarry && op8 == Iop_Add8) {
sewardj3ca55a12005-01-27 16:06:23 +00002406 vassert(0); /* awaiting test case */
sewardjdf0e0022005-01-25 15:48:43 +00002407 helper_ADC( size, dst1, dst0, src );
sewardj5b470602005-02-27 13:10:48 +00002408 putIRegG(size, pfx, rm, mkexpr(dst1));
sewardjdf0e0022005-01-25 15:48:43 +00002409 } else
2410 if (addSubCarry && op8 == Iop_Sub8) {
sewardj3ca55a12005-01-27 16:06:23 +00002411 vassert(0); /* awaiting test case */
sewardjdf0e0022005-01-25 15:48:43 +00002412 helper_SBB( size, dst1, dst0, src );
sewardj5b470602005-02-27 13:10:48 +00002413 putIRegG(size, pfx, rm, mkexpr(dst1));
sewardjdf0e0022005-01-25 15:48:43 +00002414 } else {
2415 assign( dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
2416 if (isAddSub(op8))
2417 setFlags_DEP1_DEP2(op8, dst0, src, ty);
2418 else
2419 setFlags_DEP1(op8, dst1, ty);
2420 if (keep)
sewardj5b470602005-02-27 13:10:48 +00002421 putIRegG(size, pfx, rm, mkexpr(dst1));
sewardjdf0e0022005-01-25 15:48:43 +00002422 }
2423
2424 DIP("%s%c %s,%s\n", t_amd64opc, nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00002425 nameIRegE(size,pfx,rm),
2426 nameIRegG(size,pfx,rm));
sewardjdf0e0022005-01-25 15:48:43 +00002427 return 1+delta0;
2428 } else {
2429 /* E refers to memory */
sewardje1698952005-02-08 15:02:39 +00002430 addr = disAMode ( &len, pfx, delta0, dis_buf, 0 );
sewardj5b470602005-02-27 13:10:48 +00002431 assign( dst0, getIRegG(size,pfx,rm) );
sewardjdf0e0022005-01-25 15:48:43 +00002432 assign( src, loadLE(szToITy(size), mkexpr(addr)) );
2433
2434 if (addSubCarry && op8 == Iop_Add8) {
2435 helper_ADC( size, dst1, dst0, src );
sewardj5b470602005-02-27 13:10:48 +00002436 putIRegG(size, pfx, rm, mkexpr(dst1));
sewardjdf0e0022005-01-25 15:48:43 +00002437 } else
2438 if (addSubCarry && op8 == Iop_Sub8) {
2439 helper_SBB( size, dst1, dst0, src );
sewardj5b470602005-02-27 13:10:48 +00002440 putIRegG(size, pfx, rm, mkexpr(dst1));
sewardjdf0e0022005-01-25 15:48:43 +00002441 } else {
2442 assign( dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
2443 if (isAddSub(op8))
2444 setFlags_DEP1_DEP2(op8, dst0, src, ty);
2445 else
2446 setFlags_DEP1(op8, dst1, ty);
2447 if (keep)
sewardj5b470602005-02-27 13:10:48 +00002448 putIRegG(size, pfx, rm, mkexpr(dst1));
sewardjdf0e0022005-01-25 15:48:43 +00002449 }
2450
2451 DIP("%s%c %s,%s\n", t_amd64opc, nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00002452 dis_buf, nameIRegG(size, pfx, rm));
sewardjdf0e0022005-01-25 15:48:43 +00002453 return len+delta0;
2454 }
2455}
2456
2457
2458
sewardj3ca55a12005-01-27 16:06:23 +00002459/* Handle binary integer instructions of the form
2460 op G, E meaning
2461 op reg, reg-or-mem
2462 Is passed the a ptr to the modRM byte, the actual operation, and the
2463 data size. Returns the address advanced completely over this
2464 instruction.
2465
2466 G(src) is reg.
2467 E(dst) is reg-or-mem
2468
2469 If E is reg, --> GET %E, tmp
2470 OP %G, tmp
2471 PUT tmp, %E
2472
2473 If E is mem, --> (getAddr E) -> tmpa
2474 LD (tmpa), tmpv
2475 OP %G, tmpv
2476 ST tmpv, (tmpa)
2477*/
2478static
sewardj8c332e22005-01-28 01:36:56 +00002479ULong dis_op2_G_E ( Prefix pfx,
2480 Bool addSubCarry,
2481 IROp op8,
2482 Bool keep,
2483 Int size,
sewardj270def42005-07-03 01:03:01 +00002484 Long delta0,
sewardj8c332e22005-01-28 01:36:56 +00002485 HChar* t_amd64opc )
sewardj3ca55a12005-01-27 16:06:23 +00002486{
2487 HChar dis_buf[50];
2488 Int len;
2489 IRType ty = szToITy(size);
2490 IRTemp dst1 = newTemp(ty);
2491 IRTemp src = newTemp(ty);
2492 IRTemp dst0 = newTemp(ty);
sewardj8c332e22005-01-28 01:36:56 +00002493 UChar rm = getUChar(delta0);
sewardj3ca55a12005-01-27 16:06:23 +00002494 IRTemp addr = IRTemp_INVALID;
2495
2496 /* addSubCarry == True indicates the intended operation is
2497 add-with-carry or subtract-with-borrow. */
2498 if (addSubCarry) {
2499 vassert(op8 == Iop_Add8 || op8 == Iop_Sub8);
2500 vassert(keep);
2501 }
2502
2503 if (epartIsReg(rm)) {
2504 /* Specially handle XOR reg,reg, because that doesn't really
2505 depend on reg, and doing the obvious thing potentially
2506 generates a spurious value check failure due to the bogus
sewardj5b470602005-02-27 13:10:48 +00002507 dependency. Ditto SBB reg,reg. */
2508 if ((op8 == Iop_Xor8 || (op8 == Iop_Sub8 && addSubCarry))
2509 && offsetIRegG(size,pfx,rm) == offsetIRegE(size,pfx,rm)) {
2510 putIRegE(size,pfx,rm, mkU(ty,0));
sewardj3ca55a12005-01-27 16:06:23 +00002511 }
sewardj5b470602005-02-27 13:10:48 +00002512
2513 assign(dst0, getIRegE(size,pfx,rm));
2514 assign(src, getIRegG(size,pfx,rm));
sewardj3ca55a12005-01-27 16:06:23 +00002515
2516 if (addSubCarry && op8 == Iop_Add8) {
sewardj3ca55a12005-01-27 16:06:23 +00002517 helper_ADC( size, dst1, dst0, src );
sewardj5b470602005-02-27 13:10:48 +00002518 putIRegE(size, pfx, rm, mkexpr(dst1));
sewardj3ca55a12005-01-27 16:06:23 +00002519 } else
2520 if (addSubCarry && op8 == Iop_Sub8) {
sewardj3ca55a12005-01-27 16:06:23 +00002521 helper_SBB( size, dst1, dst0, src );
sewardj5b470602005-02-27 13:10:48 +00002522 putIRegE(size, pfx, rm, mkexpr(dst1));
sewardj3ca55a12005-01-27 16:06:23 +00002523 } else {
2524 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
2525 if (isAddSub(op8))
2526 setFlags_DEP1_DEP2(op8, dst0, src, ty);
2527 else
2528 setFlags_DEP1(op8, dst1, ty);
2529 if (keep)
sewardj5b470602005-02-27 13:10:48 +00002530 putIRegE(size, pfx, rm, mkexpr(dst1));
sewardj3ca55a12005-01-27 16:06:23 +00002531 }
2532
2533 DIP("%s%c %s,%s\n", t_amd64opc, nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00002534 nameIRegG(size,pfx,rm),
2535 nameIRegE(size,pfx,rm));
sewardj3ca55a12005-01-27 16:06:23 +00002536 return 1+delta0;
2537 }
2538
2539 /* E refers to memory */
2540 {
sewardje1698952005-02-08 15:02:39 +00002541 addr = disAMode ( &len, pfx, delta0, dis_buf, 0 );
sewardj3ca55a12005-01-27 16:06:23 +00002542 assign(dst0, loadLE(ty,mkexpr(addr)));
sewardj5b470602005-02-27 13:10:48 +00002543 assign(src, getIRegG(size,pfx,rm));
sewardj3ca55a12005-01-27 16:06:23 +00002544
2545 if (addSubCarry && op8 == Iop_Add8) {
sewardj3ca55a12005-01-27 16:06:23 +00002546 helper_ADC( size, dst1, dst0, src );
2547 storeLE(mkexpr(addr), mkexpr(dst1));
2548 } else
2549 if (addSubCarry && op8 == Iop_Sub8) {
2550 vassert(0); /* awaiting test case */
2551 helper_SBB( size, dst1, dst0, src );
2552 storeLE(mkexpr(addr), mkexpr(dst1));
2553 } else {
2554 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
2555 if (isAddSub(op8))
2556 setFlags_DEP1_DEP2(op8, dst0, src, ty);
2557 else
2558 setFlags_DEP1(op8, dst1, ty);
2559 if (keep)
2560 storeLE(mkexpr(addr), mkexpr(dst1));
2561 }
2562
2563 DIP("%s%c %s,%s\n", t_amd64opc, nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00002564 nameIRegG(size,pfx,rm), dis_buf);
sewardj3ca55a12005-01-27 16:06:23 +00002565 return len+delta0;
2566 }
2567}
2568
2569
sewardj1389d4d2005-01-28 13:46:29 +00002570/* Handle move instructions of the form
2571 mov E, G meaning
2572 mov reg-or-mem, reg
2573 Is passed the a ptr to the modRM byte, and the data size. Returns
2574 the address advanced completely over this instruction.
2575
2576 E(src) is reg-or-mem
2577 G(dst) is reg.
2578
2579 If E is reg, --> GET %E, tmpv
2580 PUT tmpv, %G
2581
2582 If E is mem --> (getAddr E) -> tmpa
2583 LD (tmpa), tmpb
2584 PUT tmpb, %G
2585*/
2586static
2587ULong dis_mov_E_G ( Prefix pfx,
2588 Int size,
sewardj270def42005-07-03 01:03:01 +00002589 Long delta0 )
sewardj1389d4d2005-01-28 13:46:29 +00002590{
2591 Int len;
2592 UChar rm = getUChar(delta0);
2593 HChar dis_buf[50];
2594
2595 if (epartIsReg(rm)) {
sewardj5b470602005-02-27 13:10:48 +00002596 putIRegG(size, pfx, rm, getIRegE(size, pfx, rm));
sewardje941eea2005-01-30 19:52:28 +00002597 DIP("mov%c %s,%s\n", nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00002598 nameIRegE(size,pfx,rm),
2599 nameIRegG(size,pfx,rm));
sewardj1389d4d2005-01-28 13:46:29 +00002600 return 1+delta0;
2601 }
2602
2603 /* E refers to memory */
2604 {
sewardje1698952005-02-08 15:02:39 +00002605 IRTemp addr = disAMode ( &len, pfx, delta0, dis_buf, 0 );
sewardj5b470602005-02-27 13:10:48 +00002606 putIRegG(size, pfx, rm, loadLE(szToITy(size), mkexpr(addr)));
sewardj1389d4d2005-01-28 13:46:29 +00002607 DIP("mov%c %s,%s\n", nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00002608 dis_buf,
2609 nameIRegG(size,pfx,rm));
sewardj1389d4d2005-01-28 13:46:29 +00002610 return delta0+len;
2611 }
2612}
2613
2614
2615/* Handle move instructions of the form
2616 mov G, E meaning
2617 mov reg, reg-or-mem
2618 Is passed the a ptr to the modRM byte, and the data size. Returns
2619 the address advanced completely over this instruction.
2620
2621 G(src) is reg.
2622 E(dst) is reg-or-mem
2623
2624 If E is reg, --> GET %G, tmp
2625 PUT tmp, %E
2626
2627 If E is mem, --> (getAddr E) -> tmpa
2628 GET %G, tmpv
2629 ST tmpv, (tmpa)
2630*/
2631static
2632ULong dis_mov_G_E ( Prefix pfx,
2633 Int size,
sewardj270def42005-07-03 01:03:01 +00002634 Long delta0 )
sewardj1389d4d2005-01-28 13:46:29 +00002635{
2636 Int len;
2637 UChar rm = getUChar(delta0);
2638 HChar dis_buf[50];
2639
2640 if (epartIsReg(rm)) {
sewardj5b470602005-02-27 13:10:48 +00002641 putIRegE(size, pfx, rm, getIRegG(size, pfx, rm));
sewardje941eea2005-01-30 19:52:28 +00002642 DIP("mov%c %s,%s\n", nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00002643 nameIRegG(size,pfx,rm),
2644 nameIRegE(size,pfx,rm));
sewardj1389d4d2005-01-28 13:46:29 +00002645 return 1+delta0;
2646 }
2647
2648 /* E refers to memory */
2649 {
sewardje1698952005-02-08 15:02:39 +00002650 IRTemp addr = disAMode ( &len, pfx, delta0, dis_buf, 0 );
sewardj5b470602005-02-27 13:10:48 +00002651 storeLE( mkexpr(addr), getIRegG(size, pfx, rm) );
sewardj1389d4d2005-01-28 13:46:29 +00002652 DIP("mov%c %s,%s\n", nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00002653 nameIRegG(size,pfx,rm),
2654 dis_buf);
sewardj1389d4d2005-01-28 13:46:29 +00002655 return len+delta0;
2656 }
2657}
sewardj3ca55a12005-01-27 16:06:23 +00002658
2659
2660/* op $immediate, AL/AX/EAX/RAX. */
2661static
sewardj8c332e22005-01-28 01:36:56 +00002662ULong dis_op_imm_A ( Int size,
sewardj41c01092005-07-23 13:50:32 +00002663 Bool carrying,
sewardj8c332e22005-01-28 01:36:56 +00002664 IROp op8,
2665 Bool keep,
sewardj270def42005-07-03 01:03:01 +00002666 Long delta,
sewardj8c332e22005-01-28 01:36:56 +00002667 HChar* t_amd64opc )
sewardj3ca55a12005-01-27 16:06:23 +00002668{
2669 Int size4 = imin(size,4);
2670 IRType ty = szToITy(size);
2671 IRTemp dst0 = newTemp(ty);
2672 IRTemp src = newTemp(ty);
2673 IRTemp dst1 = newTemp(ty);
sewardj8c332e22005-01-28 01:36:56 +00002674 Long lit = getSDisp(size4,delta);
sewardj5b470602005-02-27 13:10:48 +00002675 assign(dst0, getIRegRAX(size));
sewardj1389d4d2005-01-28 13:46:29 +00002676 assign(src, mkU(ty,lit & mkSizeMask(size)));
sewardj41c01092005-07-23 13:50:32 +00002677
2678 if (isAddSub(op8) && !carrying) {
2679 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
sewardj3ca55a12005-01-27 16:06:23 +00002680 setFlags_DEP1_DEP2(op8, dst0, src, ty);
sewardj41c01092005-07-23 13:50:32 +00002681 }
sewardj3ca55a12005-01-27 16:06:23 +00002682 else
sewardj41c01092005-07-23 13:50:32 +00002683 if (isLogic(op8)) {
2684 vassert(!carrying);
2685 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
sewardj3ca55a12005-01-27 16:06:23 +00002686 setFlags_DEP1(op8, dst1, ty);
sewardj41c01092005-07-23 13:50:32 +00002687 }
sewardj3ca55a12005-01-27 16:06:23 +00002688 else
sewardj41c01092005-07-23 13:50:32 +00002689 if (op8 == Iop_Add8 && carrying) {
2690 helper_ADC( size, dst1, dst0, src );
2691 }
2692 else
2693 vpanic("dis_op_imm_A(amd64,guest)");
sewardj3ca55a12005-01-27 16:06:23 +00002694
2695 if (keep)
sewardj5b470602005-02-27 13:10:48 +00002696 putIRegRAX(size, mkexpr(dst1));
sewardj3ca55a12005-01-27 16:06:23 +00002697
2698 DIP("%s%c $%lld, %s\n", t_amd64opc, nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00002699 lit, nameIRegRAX(size));
sewardj3ca55a12005-01-27 16:06:23 +00002700 return delta+size4;
2701}
2702
2703
sewardj5e525292005-01-28 15:13:10 +00002704/* Sign- and Zero-extending moves. */
2705static
2706ULong dis_movx_E_G ( Prefix pfx,
sewardj270def42005-07-03 01:03:01 +00002707 Long delta, Int szs, Int szd, Bool sign_extend )
sewardj5e525292005-01-28 15:13:10 +00002708{
2709 UChar rm = getUChar(delta);
2710 if (epartIsReg(rm)) {
sewardj5b470602005-02-27 13:10:48 +00002711 putIRegG(szd, pfx, rm,
sewardj5e525292005-01-28 15:13:10 +00002712 doScalarWidening(
2713 szs,szd,sign_extend,
sewardj5b470602005-02-27 13:10:48 +00002714 getIRegE(szs,pfx,rm)));
sewardj5e525292005-01-28 15:13:10 +00002715 DIP("mov%c%c%c %s,%s\n", sign_extend ? 's' : 'z',
2716 nameISize(szs),
2717 nameISize(szd),
sewardj5b470602005-02-27 13:10:48 +00002718 nameIRegE(szs,pfx,rm),
2719 nameIRegG(szd,pfx,rm));
sewardj5e525292005-01-28 15:13:10 +00002720 return 1+delta;
2721 }
2722
2723 /* E refers to memory */
2724 {
2725 Int len;
2726 HChar dis_buf[50];
sewardje1698952005-02-08 15:02:39 +00002727 IRTemp addr = disAMode ( &len, pfx, delta, dis_buf, 0 );
sewardj5b470602005-02-27 13:10:48 +00002728 putIRegG(szd, pfx, rm,
sewardj5e525292005-01-28 15:13:10 +00002729 doScalarWidening(
2730 szs,szd,sign_extend,
2731 loadLE(szToITy(szs),mkexpr(addr))));
2732 DIP("mov%c%c%c %s,%s\n", sign_extend ? 's' : 'z',
2733 nameISize(szs),
2734 nameISize(szd),
2735 dis_buf,
sewardj5b470602005-02-27 13:10:48 +00002736 nameIRegG(szd,pfx,rm));
sewardj5e525292005-01-28 15:13:10 +00002737 return len+delta;
2738 }
2739}
sewardj32b2bbe2005-01-28 00:50:10 +00002740
2741
sewardj03b07cc2005-01-31 18:09:43 +00002742/* Generate code to divide ArchRegs RDX:RAX / EDX:EAX / DX:AX / AX by
2743 the 64 / 32 / 16 / 8 bit quantity in the given IRTemp. */
sewardj32b2bbe2005-01-28 00:50:10 +00002744static
2745void codegen_div ( Int sz, IRTemp t, Bool signed_divide )
2746{
sewardj03b07cc2005-01-31 18:09:43 +00002747 /* special-case the 64-bit case */
2748 if (sz == 8) {
2749 IROp op = signed_divide ? Iop_DivModS128to64
2750 : Iop_DivModU128to64;
sewardja6b93d12005-02-17 09:28:28 +00002751 IRTemp src128 = newTemp(Ity_I128);
2752 IRTemp dst128 = newTemp(Ity_I128);
sewardj03b07cc2005-01-31 18:09:43 +00002753 assign( src128, binop(Iop_64HLto128,
sewardja6b93d12005-02-17 09:28:28 +00002754 getIReg64(R_RDX),
2755 getIReg64(R_RAX)) );
sewardj03b07cc2005-01-31 18:09:43 +00002756 assign( dst128, binop(op, mkexpr(src128), mkexpr(t)) );
sewardja6b93d12005-02-17 09:28:28 +00002757 putIReg64( R_RAX, unop(Iop_128to64,mkexpr(dst128)) );
2758 putIReg64( R_RDX, unop(Iop_128HIto64,mkexpr(dst128)) );
sewardj03b07cc2005-01-31 18:09:43 +00002759 } else {
2760 IROp op = signed_divide ? Iop_DivModS64to32
2761 : Iop_DivModU64to32;
2762 IRTemp src64 = newTemp(Ity_I64);
2763 IRTemp dst64 = newTemp(Ity_I64);
2764 switch (sz) {
sewardj85520e42005-02-19 15:22:38 +00002765 case 4:
sewardj5b470602005-02-27 13:10:48 +00002766 assign( src64,
2767 binop(Iop_32HLto64, getIRegRDX(4), getIRegRAX(4)) );
2768 assign( dst64,
2769 binop(op, mkexpr(src64), mkexpr(t)) );
2770 putIRegRAX( 4, unop(Iop_64to32,mkexpr(dst64)) );
2771 putIRegRDX( 4, unop(Iop_64HIto32,mkexpr(dst64)) );
sewardj85520e42005-02-19 15:22:38 +00002772 break;
2773 case 2: {
2774 IROp widen3264 = signed_divide ? Iop_32Sto64 : Iop_32Uto64;
2775 IROp widen1632 = signed_divide ? Iop_16Sto32 : Iop_16Uto32;
2776 assign( src64, unop(widen3264,
2777 binop(Iop_16HLto32,
sewardj5b470602005-02-27 13:10:48 +00002778 getIRegRDX(2),
2779 getIRegRAX(2))) );
sewardj85520e42005-02-19 15:22:38 +00002780 assign( dst64, binop(op, mkexpr(src64), unop(widen1632,mkexpr(t))) );
sewardj5b470602005-02-27 13:10:48 +00002781 putIRegRAX( 2, unop(Iop_32to16,unop(Iop_64to32,mkexpr(dst64))) );
2782 putIRegRDX( 2, unop(Iop_32to16,unop(Iop_64HIto32,mkexpr(dst64))) );
sewardj85520e42005-02-19 15:22:38 +00002783 break;
2784 }
2785 case 1: {
2786 IROp widen3264 = signed_divide ? Iop_32Sto64 : Iop_32Uto64;
2787 IROp widen1632 = signed_divide ? Iop_16Sto32 : Iop_16Uto32;
2788 IROp widen816 = signed_divide ? Iop_8Sto16 : Iop_8Uto16;
2789 assign( src64, unop(widen3264,
sewardj5b470602005-02-27 13:10:48 +00002790 unop(widen1632, getIRegRAX(2))) );
sewardj85520e42005-02-19 15:22:38 +00002791 assign( dst64,
2792 binop(op, mkexpr(src64),
2793 unop(widen1632, unop(widen816, mkexpr(t)))) );
sewardj5b470602005-02-27 13:10:48 +00002794 putIRegRAX( 1, unop(Iop_16to8,
2795 unop(Iop_32to16,
2796 unop(Iop_64to32,mkexpr(dst64)))) );
2797 putIRegAH( unop(Iop_16to8,
2798 unop(Iop_32to16,
2799 unop(Iop_64HIto32,mkexpr(dst64)))) );
sewardj85520e42005-02-19 15:22:38 +00002800 break;
2801 }
2802 default:
2803 vpanic("codegen_div(amd64)");
sewardj03b07cc2005-01-31 18:09:43 +00002804 }
sewardj32b2bbe2005-01-28 00:50:10 +00002805 }
2806}
sewardj3ca55a12005-01-27 16:06:23 +00002807
2808static
sewardj8c332e22005-01-28 01:36:56 +00002809ULong dis_Grp1 ( Prefix pfx,
sewardj270def42005-07-03 01:03:01 +00002810 Long delta, UChar modrm,
sewardj227458e2005-01-31 19:04:50 +00002811 Int am_sz, Int d_sz, Int sz, Long d64 )
sewardj3ca55a12005-01-27 16:06:23 +00002812{
2813 Int len;
2814 HChar dis_buf[50];
2815 IRType ty = szToITy(sz);
2816 IRTemp dst1 = newTemp(ty);
2817 IRTemp src = newTemp(ty);
2818 IRTemp dst0 = newTemp(ty);
2819 IRTemp addr = IRTemp_INVALID;
2820 IROp op8 = Iop_INVALID;
sewardj1389d4d2005-01-28 13:46:29 +00002821 ULong mask = mkSizeMask(sz);
sewardj3ca55a12005-01-27 16:06:23 +00002822
sewardj901ed122005-02-27 13:25:31 +00002823 switch (gregLO3ofRM(modrm)) {
sewardj3ca55a12005-01-27 16:06:23 +00002824 case 0: op8 = Iop_Add8; break; case 1: op8 = Iop_Or8; break;
2825 case 2: break; // ADC
2826 case 3: break; // SBB
2827 case 4: op8 = Iop_And8; break; case 5: op8 = Iop_Sub8; break;
2828 case 6: op8 = Iop_Xor8; break; case 7: op8 = Iop_Sub8; break;
2829 default: vpanic("dis_Grp1(amd64): unhandled case");
2830 }
2831
2832 if (epartIsReg(modrm)) {
2833 vassert(am_sz == 1);
2834
sewardj5b470602005-02-27 13:10:48 +00002835 assign(dst0, getIRegE(sz,pfx,modrm));
sewardj227458e2005-01-31 19:04:50 +00002836 assign(src, mkU(ty,d64 & mask));
sewardj3ca55a12005-01-27 16:06:23 +00002837
sewardj901ed122005-02-27 13:25:31 +00002838 if (gregLO3ofRM(modrm) == 2 /* ADC */) {
sewardj3ca55a12005-01-27 16:06:23 +00002839 helper_ADC( sz, dst1, dst0, src );
2840 } else
sewardj901ed122005-02-27 13:25:31 +00002841 if (gregLO3ofRM(modrm) == 3 /* SBB */) {
sewardj3ca55a12005-01-27 16:06:23 +00002842 helper_SBB( sz, dst1, dst0, src );
2843 } else {
2844 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
2845 if (isAddSub(op8))
2846 setFlags_DEP1_DEP2(op8, dst0, src, ty);
2847 else
2848 setFlags_DEP1(op8, dst1, ty);
2849 }
2850
sewardj901ed122005-02-27 13:25:31 +00002851 if (gregLO3ofRM(modrm) < 7)
sewardj5b470602005-02-27 13:10:48 +00002852 putIRegE(sz, pfx, modrm, mkexpr(dst1));
sewardj3ca55a12005-01-27 16:06:23 +00002853
2854 delta += (am_sz + d_sz);
sewardje941eea2005-01-30 19:52:28 +00002855 DIP("%s%c $%lld, %s\n",
sewardj901ed122005-02-27 13:25:31 +00002856 nameGrp1(gregLO3ofRM(modrm)), nameISize(sz), d64,
sewardj5b470602005-02-27 13:10:48 +00002857 nameIRegE(sz,pfx,modrm));
sewardj3ca55a12005-01-27 16:06:23 +00002858 } else {
sewardje1698952005-02-08 15:02:39 +00002859 addr = disAMode ( &len, pfx, delta, dis_buf, /*xtra*/d_sz );
sewardj3ca55a12005-01-27 16:06:23 +00002860
2861 assign(dst0, loadLE(ty,mkexpr(addr)));
sewardj227458e2005-01-31 19:04:50 +00002862 assign(src, mkU(ty,d64 & mask));
sewardj3ca55a12005-01-27 16:06:23 +00002863
sewardj901ed122005-02-27 13:25:31 +00002864 if (gregLO3ofRM(modrm) == 2 /* ADC */) {
sewardj3ca55a12005-01-27 16:06:23 +00002865 helper_ADC( sz, dst1, dst0, src );
2866 } else
sewardj901ed122005-02-27 13:25:31 +00002867 if (gregLO3ofRM(modrm) == 3 /* SBB */) {
sewardj3ca55a12005-01-27 16:06:23 +00002868 helper_SBB( sz, dst1, dst0, src );
2869 } else {
2870 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
2871 if (isAddSub(op8))
2872 setFlags_DEP1_DEP2(op8, dst0, src, ty);
2873 else
2874 setFlags_DEP1(op8, dst1, ty);
2875 }
2876
sewardj901ed122005-02-27 13:25:31 +00002877 if (gregLO3ofRM(modrm) < 7)
sewardj3ca55a12005-01-27 16:06:23 +00002878 storeLE(mkexpr(addr), mkexpr(dst1));
2879
2880 delta += (len+d_sz);
sewardje941eea2005-01-30 19:52:28 +00002881 DIP("%s%c $%lld, %s\n",
sewardj901ed122005-02-27 13:25:31 +00002882 nameGrp1(gregLO3ofRM(modrm)), nameISize(sz),
sewardj227458e2005-01-31 19:04:50 +00002883 d64, dis_buf);
sewardj3ca55a12005-01-27 16:06:23 +00002884 }
2885 return delta;
2886}
2887
2888
sewardj118b23e2005-01-29 02:14:44 +00002889/* Group 2 extended opcodes. shift_expr must be an 8-bit typed
2890 expression. */
2891
2892static
2893ULong dis_Grp2 ( Prefix pfx,
sewardj270def42005-07-03 01:03:01 +00002894 Long delta, UChar modrm,
sewardj118b23e2005-01-29 02:14:44 +00002895 Int am_sz, Int d_sz, Int sz, IRExpr* shift_expr,
2896 HChar* shift_expr_txt )
2897{
2898 /* delta on entry points at the modrm byte. */
2899 HChar dis_buf[50];
2900 Int len;
2901 Bool isShift, isRotate, isRotateRC;
2902 IRType ty = szToITy(sz);
2903 IRTemp dst0 = newTemp(ty);
2904 IRTemp dst1 = newTemp(ty);
2905 IRTemp addr = IRTemp_INVALID;
2906
2907 vassert(sz == 1 || sz == 2 || sz == 4 || sz == 8);
2908
2909 /* Put value to shift/rotate in dst0. */
2910 if (epartIsReg(modrm)) {
sewardj5b470602005-02-27 13:10:48 +00002911 assign(dst0, getIRegE(sz, pfx, modrm));
sewardj118b23e2005-01-29 02:14:44 +00002912 delta += (am_sz + d_sz);
2913 } else {
sewardje1698952005-02-08 15:02:39 +00002914 addr = disAMode ( &len, pfx, delta, dis_buf, 0 );
sewardj118b23e2005-01-29 02:14:44 +00002915 assign(dst0, loadLE(ty,mkexpr(addr)));
2916 delta += len + d_sz;
2917 }
2918
2919 isShift = False;
sewardj901ed122005-02-27 13:25:31 +00002920 switch (gregLO3ofRM(modrm)) { case 4: case 5: case 7: isShift = True; }
sewardj118b23e2005-01-29 02:14:44 +00002921
2922 isRotate = False;
sewardj901ed122005-02-27 13:25:31 +00002923 switch (gregLO3ofRM(modrm)) { case 0: case 1: isRotate = True; }
sewardj118b23e2005-01-29 02:14:44 +00002924
sewardj901ed122005-02-27 13:25:31 +00002925 isRotateRC = toBool(gregLO3ofRM(modrm) == 3);
sewardj118b23e2005-01-29 02:14:44 +00002926
2927 if (!isShift && !isRotate && !isRotateRC) {
sewardj901ed122005-02-27 13:25:31 +00002928 vex_printf("\ncase %d\n", gregLO3ofRM(modrm));
sewardj118b23e2005-01-29 02:14:44 +00002929 vpanic("dis_Grp2(Reg): unhandled case(amd64)");
2930 }
2931
2932 if (isRotateRC) {
sewardj112b0992005-07-23 13:19:32 +00002933 /* Call a helper; this insn is so ridiculous it does not deserve
2934 better. One problem is, the helper has to calculate both the
2935 new value and the new flags. This is more than 64 bits, and
2936 there is no way to return more than 64 bits from the helper.
2937 Hence the crude and obvious solution is to call it twice,
2938 using the sign of the sz field to indicate whether it is the
2939 value or rflags result we want.
2940 */
2941 IRExpr** argsVALUE;
2942 IRExpr** argsRFLAGS;
2943
2944 IRTemp new_value = newTemp(Ity_I64);
2945 IRTemp new_rflags = newTemp(Ity_I64);
2946 IRTemp old_rflags = newTemp(Ity_I64);
2947
2948 assign( old_rflags, widenUto64(mk_amd64g_calculate_rflags_all()) );
2949
2950 argsVALUE
2951 = mkIRExprVec_4( widenUto64(mkexpr(dst0)), /* thing to rotate */
2952 widenUto64(shift_expr), /* rotate amount */
2953 mkexpr(old_rflags),
2954 mkU64(sz) );
2955 assign( new_value,
2956 mkIRExprCCall(
2957 Ity_I64,
2958 0/*regparm*/,
2959 "amd64g_calculate_RCR", &amd64g_calculate_RCR,
2960 argsVALUE
2961 )
2962 );
2963
2964 argsRFLAGS
2965 = mkIRExprVec_4( widenUto64(mkexpr(dst0)), /* thing to rotate */
2966 widenUto64(shift_expr), /* rotate amount */
2967 mkexpr(old_rflags),
2968 mkU64(-sz) );
2969 assign( new_rflags,
2970 mkIRExprCCall(
2971 Ity_I64,
2972 0/*regparm*/,
2973 "amd64g_calculate_RCR", &amd64g_calculate_RCR,
2974 argsRFLAGS
2975 )
2976 );
2977
2978 assign( dst1, narrowTo(ty, mkexpr(new_value)) );
2979 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(AMD64G_CC_OP_COPY) ));
2980 stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(new_rflags) ));
2981 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
2982 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU64(0) ));
sewardj118b23e2005-01-29 02:14:44 +00002983 }
2984
sewardj112b0992005-07-23 13:19:32 +00002985 else
sewardj118b23e2005-01-29 02:14:44 +00002986 if (isShift) {
2987
2988 IRTemp pre64 = newTemp(Ity_I64);
2989 IRTemp res64 = newTemp(Ity_I64);
2990 IRTemp res64ss = newTemp(Ity_I64);
2991 IRTemp shift_amt = newTemp(Ity_I8);
sewardj1027dc22005-02-26 01:55:02 +00002992 UChar mask = toUChar(sz==8 ? 63 : 31);
sewardj118b23e2005-01-29 02:14:44 +00002993 IROp op64;
2994
sewardj901ed122005-02-27 13:25:31 +00002995 switch (gregLO3ofRM(modrm)) {
sewardj118b23e2005-01-29 02:14:44 +00002996 case 4: op64 = Iop_Shl64; break;
2997 case 5: op64 = Iop_Shr64; break;
2998 case 7: op64 = Iop_Sar64; break;
2999 default: vpanic("dis_Grp2:shift"); break;
3000 }
3001
3002 /* Widen the value to be shifted to 64 bits, do the shift, and
3003 narrow back down. This seems surprisingly long-winded, but
3004 unfortunately the AMD semantics requires that 8/16/32-bit
3005 shifts give defined results for shift values all the way up
sewardj03c96e82005-02-19 18:12:45 +00003006 to 32, and this seems the simplest way to do it. It has the
sewardj118b23e2005-01-29 02:14:44 +00003007 advantage that the only IR level shifts generated are of 64
3008 bit values, and the shift amount is guaranteed to be in the
3009 range 0 .. 63, thereby observing the IR semantics requiring
sewardj03c96e82005-02-19 18:12:45 +00003010 all shift values to be in the range 0 .. 2^word_size-1.
sewardj118b23e2005-01-29 02:14:44 +00003011
sewardj03c96e82005-02-19 18:12:45 +00003012 Therefore the shift amount is masked with 63 for 64-bit shifts
3013 and 31 for all others.
3014 */
3015 /* shift_amt = shift_expr & MASK, regardless of operation size */
3016 assign( shift_amt, binop(Iop_And8, shift_expr, mkU8(mask)) );
sewardj118b23e2005-01-29 02:14:44 +00003017
sewardj03c96e82005-02-19 18:12:45 +00003018 /* suitably widen the value to be shifted to 64 bits. */
sewardj118b23e2005-01-29 02:14:44 +00003019 assign( pre64, op64==Iop_Sar64 ? widenSto64(mkexpr(dst0))
3020 : widenUto64(mkexpr(dst0)) );
3021
3022 /* res64 = pre64 `shift` shift_amt */
3023 assign( res64, binop(op64, mkexpr(pre64), mkexpr(shift_amt)) );
3024
sewardj03c96e82005-02-19 18:12:45 +00003025 /* res64ss = pre64 `shift` ((shift_amt - 1) & MASK) */
sewardj118b23e2005-01-29 02:14:44 +00003026 assign( res64ss,
3027 binop(op64,
3028 mkexpr(pre64),
3029 binop(Iop_And8,
3030 binop(Iop_Sub8,
3031 mkexpr(shift_amt), mkU8(1)),
sewardj03c96e82005-02-19 18:12:45 +00003032 mkU8(mask))) );
sewardj118b23e2005-01-29 02:14:44 +00003033
3034 /* Build the flags thunk. */
3035 setFlags_DEP1_DEP2_shift(op64, res64, res64ss, ty, shift_amt);
3036
3037 /* Narrow the result back down. */
3038 assign( dst1, narrowTo(ty, mkexpr(res64)) );
3039
3040 } /* if (isShift) */
3041
3042 else
3043 if (isRotate) {
3044 Int ccOp = ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1
3045 : (ty==Ity_I32 ? 2 : 3));
sewardj901ed122005-02-27 13:25:31 +00003046 Bool left = toBool(gregLO3ofRM(modrm) == 0);
sewardj118b23e2005-01-29 02:14:44 +00003047 IRTemp rot_amt = newTemp(Ity_I8);
3048 IRTemp rot_amt64 = newTemp(Ity_I8);
3049 IRTemp oldFlags = newTemp(Ity_I64);
sewardj1027dc22005-02-26 01:55:02 +00003050 UChar mask = toUChar(sz==8 ? 63 : 31);
sewardj118b23e2005-01-29 02:14:44 +00003051
3052 /* rot_amt = shift_expr & mask */
3053 /* By masking the rotate amount thusly, the IR-level Shl/Shr
3054 expressions never shift beyond the word size and thus remain
3055 well defined. */
sewardj03c96e82005-02-19 18:12:45 +00003056 assign(rot_amt64, binop(Iop_And8, shift_expr, mkU8(mask)));
sewardj118b23e2005-01-29 02:14:44 +00003057
3058 if (ty == Ity_I64)
3059 assign(rot_amt, mkexpr(rot_amt64));
3060 else
3061 assign(rot_amt, binop(Iop_And8, mkexpr(rot_amt64), mkU8(8*sz-1)));
3062
3063 if (left) {
3064
3065 /* dst1 = (dst0 << rot_amt) | (dst0 >>u (wordsize-rot_amt)) */
3066 assign(dst1,
3067 binop( mkSizedOp(ty,Iop_Or8),
3068 binop( mkSizedOp(ty,Iop_Shl8),
3069 mkexpr(dst0),
3070 mkexpr(rot_amt)
3071 ),
3072 binop( mkSizedOp(ty,Iop_Shr8),
3073 mkexpr(dst0),
3074 binop(Iop_Sub8,mkU8(8*sz), mkexpr(rot_amt))
3075 )
3076 )
3077 );
3078 ccOp += AMD64G_CC_OP_ROLB;
3079
3080 } else { /* right */
3081
3082 /* dst1 = (dst0 >>u rot_amt) | (dst0 << (wordsize-rot_amt)) */
3083 assign(dst1,
3084 binop( mkSizedOp(ty,Iop_Or8),
3085 binop( mkSizedOp(ty,Iop_Shr8),
3086 mkexpr(dst0),
3087 mkexpr(rot_amt)
3088 ),
3089 binop( mkSizedOp(ty,Iop_Shl8),
3090 mkexpr(dst0),
3091 binop(Iop_Sub8,mkU8(8*sz), mkexpr(rot_amt))
3092 )
3093 )
3094 );
3095 ccOp += AMD64G_CC_OP_RORB;
3096
3097 }
3098
3099 /* dst1 now holds the rotated value. Build flag thunk. We
3100 need the resulting value for this, and the previous flags.
3101 Except don't set it if the rotate count is zero. */
3102
3103 assign(oldFlags, mk_amd64g_calculate_rflags_all());
3104
3105 /* CC_DEP1 is the rotated value. CC_NDEP is flags before. */
3106 stmt( IRStmt_Put( OFFB_CC_OP,
3107 IRExpr_Mux0X( mkexpr(rot_amt64),
3108 IRExpr_Get(OFFB_CC_OP,Ity_I64),
3109 mkU64(ccOp))) );
3110 stmt( IRStmt_Put( OFFB_CC_DEP1,
3111 IRExpr_Mux0X( mkexpr(rot_amt64),
3112 IRExpr_Get(OFFB_CC_DEP1,Ity_I64),
3113 widenUto64(mkexpr(dst1)))) );
3114 stmt( IRStmt_Put( OFFB_CC_DEP2,
3115 IRExpr_Mux0X( mkexpr(rot_amt64),
3116 IRExpr_Get(OFFB_CC_DEP2,Ity_I64),
3117 mkU64(0))) );
3118 stmt( IRStmt_Put( OFFB_CC_NDEP,
3119 IRExpr_Mux0X( mkexpr(rot_amt64),
3120 IRExpr_Get(OFFB_CC_NDEP,Ity_I64),
3121 mkexpr(oldFlags))) );
3122 } /* if (isRotate) */
3123
3124 /* Save result, and finish up. */
3125 if (epartIsReg(modrm)) {
sewardj5b470602005-02-27 13:10:48 +00003126 putIRegE(sz, pfx, modrm, mkexpr(dst1));
sewardj118b23e2005-01-29 02:14:44 +00003127 if (vex_traceflags & VEX_TRACE_FE) {
3128 vex_printf("%s%c ",
sewardj901ed122005-02-27 13:25:31 +00003129 nameGrp2(gregLO3ofRM(modrm)), nameISize(sz) );
sewardj118b23e2005-01-29 02:14:44 +00003130 if (shift_expr_txt)
3131 vex_printf("%s", shift_expr_txt);
3132 else
3133 ppIRExpr(shift_expr);
sewardj5b470602005-02-27 13:10:48 +00003134 vex_printf(", %s\n", nameIRegE(sz,pfx,modrm));
sewardj118b23e2005-01-29 02:14:44 +00003135 }
3136 } else {
3137 storeLE(mkexpr(addr), mkexpr(dst1));
3138 if (vex_traceflags & VEX_TRACE_FE) {
3139 vex_printf("%s%c ",
sewardj901ed122005-02-27 13:25:31 +00003140 nameGrp2(gregLO3ofRM(modrm)), nameISize(sz) );
sewardj118b23e2005-01-29 02:14:44 +00003141 if (shift_expr_txt)
3142 vex_printf("%s", shift_expr_txt);
3143 else
3144 ppIRExpr(shift_expr);
3145 vex_printf(", %s\n", dis_buf);
3146 }
3147 }
3148 return delta;
3149}
3150
3151
sewardj1d511802005-03-27 17:59:45 +00003152/* Group 8 extended opcodes (but BT/BTS/BTC/BTR only). */
3153static
3154ULong dis_Grp8_Imm ( Prefix pfx,
sewardj270def42005-07-03 01:03:01 +00003155 Long delta, UChar modrm,
sewardj1d511802005-03-27 17:59:45 +00003156 Int am_sz, Int sz, ULong src_val,
3157 Bool* decode_OK )
3158{
3159 /* src_val denotes a d8.
3160 And delta on entry points at the modrm byte. */
sewardj118b23e2005-01-29 02:14:44 +00003161
sewardj1d511802005-03-27 17:59:45 +00003162 IRType ty = szToITy(sz);
3163 IRTemp t2 = newTemp(Ity_I64);
3164 IRTemp t2m = newTemp(Ity_I64);
3165 IRTemp t_addr = IRTemp_INVALID;
3166 HChar dis_buf[50];
3167 ULong mask;
sewardj9b967672005-02-08 11:13:09 +00003168
sewardj1d511802005-03-27 17:59:45 +00003169 /* we're optimists :-) */
3170 *decode_OK = True;
3171
3172 /* Limit src_val -- the bit offset -- to something within a word.
3173 The Intel docs say that literal offsets larger than a word are
3174 masked in this way. */
3175 switch (sz) {
3176 case 2: src_val &= 15; break;
3177 case 4: src_val &= 31; break;
sewardj537cab02005-04-07 02:03:52 +00003178 case 8: src_val &= 63; break;
sewardj1d511802005-03-27 17:59:45 +00003179 default: *decode_OK = False; return delta;
3180 }
3181
3182 /* Invent a mask suitable for the operation. */
3183 switch (gregLO3ofRM(modrm)) {
sewardj74b4f892005-05-06 01:43:56 +00003184 case 4: /* BT */ mask = 0; break;
3185 case 5: /* BTS */ mask = 1ULL << src_val; break;
3186 case 6: /* BTR */ mask = ~(1ULL << src_val); break;
3187 case 7: /* BTC */ mask = 1ULL << src_val; break;
sewardj1d511802005-03-27 17:59:45 +00003188 /* If this needs to be extended, probably simplest to make a
3189 new function to handle the other cases (0 .. 3). The
3190 Intel docs do however not indicate any use for 0 .. 3, so
3191 we don't expect this to happen. */
3192 default: *decode_OK = False; return delta;
3193 }
3194
3195 /* Fetch the value to be tested and modified into t2, which is
3196 64-bits wide regardless of sz. */
3197 if (epartIsReg(modrm)) {
3198 vassert(am_sz == 1);
3199 assign( t2, widenUto64(getIRegE(sz, pfx, modrm)) );
3200 delta += (am_sz + 1);
3201 DIP("%s%c $0x%llx, %s\n", nameGrp8(gregLO3ofRM(modrm)),
3202 nameISize(sz),
3203 src_val, nameIRegE(sz,pfx,modrm));
3204 } else {
3205 Int len;
3206 t_addr = disAMode ( &len, pfx, delta, dis_buf, 1 );
3207 delta += (len+1);
3208 assign( t2, widenUto64(loadLE(ty, mkexpr(t_addr))) );
3209 DIP("%s%c $0x%llx, %s\n", nameGrp8(gregLO3ofRM(modrm)),
3210 nameISize(sz),
3211 src_val, dis_buf);
3212 }
3213
3214 /* Copy relevant bit from t2 into the carry flag. */
3215 /* Flags: C=selected bit, O,S,Z,A,P undefined, so are set to zero. */
3216 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(AMD64G_CC_OP_COPY) ));
3217 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
3218 stmt( IRStmt_Put(
3219 OFFB_CC_DEP1,
3220 binop(Iop_And64,
3221 binop(Iop_Shr64, mkexpr(t2), mkU8(src_val)),
3222 mkU64(1))
3223 ));
3224
3225 /* Compute the new value into t2m, if non-BT. */
3226 switch (gregLO3ofRM(modrm)) {
3227 case 4: /* BT */
3228 break;
3229 case 5: /* BTS */
3230 assign( t2m, binop(Iop_Or64, mkU64(mask), mkexpr(t2)) );
3231 break;
3232 case 6: /* BTR */
3233 assign( t2m, binop(Iop_And64, mkU64(mask), mkexpr(t2)) );
3234 break;
3235 case 7: /* BTC */
3236 assign( t2m, binop(Iop_Xor64, mkU64(mask), mkexpr(t2)) );
3237 break;
3238 default:
3239 vassert(0);
3240 }
3241
3242 /* Write the result back, if non-BT. */
3243 if (gregLO3ofRM(modrm) != 4 /* BT */) {
3244 if (epartIsReg(modrm)) {
3245 putIRegE(sz, pfx, modrm, narrowTo(ty, mkexpr(t2m)));
3246 } else {
3247 storeLE(mkexpr(t_addr), narrowTo(ty, mkexpr(t2m)));
3248 }
3249 }
3250
3251 return delta;
3252}
sewardj9b967672005-02-08 11:13:09 +00003253
3254
3255/* Signed/unsigned widening multiply. Generate IR to multiply the
3256 value in RAX/EAX/AX/AL by the given IRTemp, and park the result in
3257 RDX:RAX/EDX:EAX/DX:AX/AX.
3258*/
3259static void codegen_mulL_A_D ( Int sz, Bool syned,
sewardj1027dc22005-02-26 01:55:02 +00003260 IRTemp tmp, HChar* tmp_txt )
sewardj9b967672005-02-08 11:13:09 +00003261{
3262 IRType ty = szToITy(sz);
3263 IRTemp t1 = newTemp(ty);
3264
sewardj5b470602005-02-27 13:10:48 +00003265 assign( t1, getIRegRAX(sz) );
sewardj9b967672005-02-08 11:13:09 +00003266
3267 switch (ty) {
3268 case Ity_I64: {
3269 IRTemp res128 = newTemp(Ity_I128);
3270 IRTemp resHi = newTemp(Ity_I64);
3271 IRTemp resLo = newTemp(Ity_I64);
3272 IROp mulOp = syned ? Iop_MullS64 : Iop_MullU64;
sewardj8bdb89a2005-05-05 21:46:50 +00003273 UInt tBaseOp = syned ? AMD64G_CC_OP_SMULB : AMD64G_CC_OP_UMULB;
sewardj9b967672005-02-08 11:13:09 +00003274 setFlags_MUL ( Ity_I64, t1, tmp, tBaseOp );
3275 assign( res128, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
3276 assign( resHi, unop(Iop_128HIto64,mkexpr(res128)));
3277 assign( resLo, unop(Iop_128to64,mkexpr(res128)));
sewardj5b470602005-02-27 13:10:48 +00003278 putIReg64(R_RDX, mkexpr(resHi));
3279 putIReg64(R_RAX, mkexpr(resLo));
sewardj9b967672005-02-08 11:13:09 +00003280 break;
3281 }
sewardj85520e42005-02-19 15:22:38 +00003282 case Ity_I32: {
3283 IRTemp res64 = newTemp(Ity_I64);
3284 IRTemp resHi = newTemp(Ity_I32);
3285 IRTemp resLo = newTemp(Ity_I32);
3286 IROp mulOp = syned ? Iop_MullS32 : Iop_MullU32;
3287 UInt tBaseOp = syned ? AMD64G_CC_OP_SMULB : AMD64G_CC_OP_UMULB;
3288 setFlags_MUL ( Ity_I32, t1, tmp, tBaseOp );
3289 assign( res64, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
3290 assign( resHi, unop(Iop_64HIto32,mkexpr(res64)));
3291 assign( resLo, unop(Iop_64to32,mkexpr(res64)));
sewardj5b470602005-02-27 13:10:48 +00003292 putIRegRDX(4, mkexpr(resHi));
3293 putIRegRAX(4, mkexpr(resLo));
sewardj85520e42005-02-19 15:22:38 +00003294 break;
3295 }
3296 case Ity_I16: {
3297 IRTemp res32 = newTemp(Ity_I32);
3298 IRTemp resHi = newTemp(Ity_I16);
3299 IRTemp resLo = newTemp(Ity_I16);
3300 IROp mulOp = syned ? Iop_MullS16 : Iop_MullU16;
3301 UInt tBaseOp = syned ? AMD64G_CC_OP_SMULB : AMD64G_CC_OP_UMULB;
3302 setFlags_MUL ( Ity_I16, t1, tmp, tBaseOp );
3303 assign( res32, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
3304 assign( resHi, unop(Iop_32HIto16,mkexpr(res32)));
3305 assign( resLo, unop(Iop_32to16,mkexpr(res32)));
sewardj5b470602005-02-27 13:10:48 +00003306 putIRegRDX(2, mkexpr(resHi));
3307 putIRegRAX(2, mkexpr(resLo));
sewardj85520e42005-02-19 15:22:38 +00003308 break;
3309 }
3310 case Ity_I8: {
3311 IRTemp res16 = newTemp(Ity_I16);
3312 IRTemp resHi = newTemp(Ity_I8);
3313 IRTemp resLo = newTemp(Ity_I8);
3314 IROp mulOp = syned ? Iop_MullS8 : Iop_MullU8;
3315 UInt tBaseOp = syned ? AMD64G_CC_OP_SMULB : AMD64G_CC_OP_UMULB;
3316 setFlags_MUL ( Ity_I8, t1, tmp, tBaseOp );
3317 assign( res16, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
3318 assign( resHi, unop(Iop_16HIto8,mkexpr(res16)));
3319 assign( resLo, unop(Iop_16to8,mkexpr(res16)));
sewardj5b470602005-02-27 13:10:48 +00003320 putIRegRAX(2, mkexpr(res16));
sewardj85520e42005-02-19 15:22:38 +00003321 break;
3322 }
sewardj9b967672005-02-08 11:13:09 +00003323 default:
sewardj85520e42005-02-19 15:22:38 +00003324 ppIRType(ty);
sewardj9b967672005-02-08 11:13:09 +00003325 vpanic("codegen_mulL_A_D(amd64)");
3326 }
3327 DIP("%s%c %s\n", syned ? "imul" : "mul", nameISize(sz), tmp_txt);
3328}
sewardj32b2bbe2005-01-28 00:50:10 +00003329
3330
3331/* Group 3 extended opcodes. */
3332static
sewardj270def42005-07-03 01:03:01 +00003333ULong dis_Grp3 ( Prefix pfx, Int sz, Long delta )
sewardj32b2bbe2005-01-28 00:50:10 +00003334{
sewardj227458e2005-01-31 19:04:50 +00003335 Long d64;
sewardj32b2bbe2005-01-28 00:50:10 +00003336 UChar modrm;
3337 HChar dis_buf[50];
3338 Int len;
3339 IRTemp addr;
3340 IRType ty = szToITy(sz);
3341 IRTemp t1 = newTemp(ty);
sewardj55dbb262005-01-28 16:36:51 +00003342 IRTemp dst1, src, dst0;
sewardj8c332e22005-01-28 01:36:56 +00003343 modrm = getUChar(delta);
sewardj32b2bbe2005-01-28 00:50:10 +00003344 if (epartIsReg(modrm)) {
sewardj901ed122005-02-27 13:25:31 +00003345 switch (gregLO3ofRM(modrm)) {
sewardj118b23e2005-01-29 02:14:44 +00003346 case 0: { /* TEST */
3347 delta++;
3348 d64 = getSDisp(imin(4,sz), delta);
3349 delta += imin(4,sz);
3350 dst1 = newTemp(ty);
3351 assign(dst1, binop(mkSizedOp(ty,Iop_And8),
sewardj5b470602005-02-27 13:10:48 +00003352 getIRegE(sz,pfx,modrm),
sewardj03b07cc2005-01-31 18:09:43 +00003353 mkU(ty, d64 & mkSizeMask(sz))));
sewardj118b23e2005-01-29 02:14:44 +00003354 setFlags_DEP1( Iop_And8, dst1, ty );
sewardj7eaa7cf2005-01-31 18:55:22 +00003355 DIP("test%c $%lld, %s\n",
sewardj118b23e2005-01-29 02:14:44 +00003356 nameISize(sz), d64,
sewardj5b470602005-02-27 13:10:48 +00003357 nameIRegE(sz, pfx, modrm));
sewardj118b23e2005-01-29 02:14:44 +00003358 break;
3359 }
sewardj55dbb262005-01-28 16:36:51 +00003360 case 2: /* NOT */
3361 delta++;
sewardj5b470602005-02-27 13:10:48 +00003362 putIRegE(sz, pfx, modrm,
3363 unop(mkSizedOp(ty,Iop_Not8),
3364 getIRegE(sz, pfx, modrm)));
sewardj55dbb262005-01-28 16:36:51 +00003365 DIP("not%c %s\n", nameISize(sz),
sewardj5b470602005-02-27 13:10:48 +00003366 nameIRegE(sz, pfx, modrm));
sewardj55dbb262005-01-28 16:36:51 +00003367 break;
3368 case 3: /* NEG */
3369 delta++;
3370 dst0 = newTemp(ty);
3371 src = newTemp(ty);
3372 dst1 = newTemp(ty);
3373 assign(dst0, mkU(ty,0));
sewardj5b470602005-02-27 13:10:48 +00003374 assign(src, getIRegE(sz, pfx, modrm));
sewardj55dbb262005-01-28 16:36:51 +00003375 assign(dst1, binop(mkSizedOp(ty,Iop_Sub8), mkexpr(dst0), mkexpr(src)));
3376 setFlags_DEP1_DEP2(Iop_Sub8, dst0, src, ty);
sewardj5b470602005-02-27 13:10:48 +00003377 putIRegE(sz, pfx, modrm, mkexpr(dst1));
3378 DIP("neg%c %s\n", nameISize(sz), nameIRegE(sz, pfx, modrm));
sewardj55dbb262005-01-28 16:36:51 +00003379 break;
sewardj9b967672005-02-08 11:13:09 +00003380 case 4: /* MUL (unsigned widening) */
3381 delta++;
3382 src = newTemp(ty);
sewardj5b470602005-02-27 13:10:48 +00003383 assign(src, getIRegE(sz,pfx,modrm));
sewardj9b967672005-02-08 11:13:09 +00003384 codegen_mulL_A_D ( sz, False, src,
sewardj5b470602005-02-27 13:10:48 +00003385 nameIRegE(sz,pfx,modrm) );
sewardj9b967672005-02-08 11:13:09 +00003386 break;
sewardj85520e42005-02-19 15:22:38 +00003387 case 5: /* IMUL (signed widening) */
3388 delta++;
3389 src = newTemp(ty);
sewardj5b470602005-02-27 13:10:48 +00003390 assign(src, getIRegE(sz,pfx,modrm));
sewardj85520e42005-02-19 15:22:38 +00003391 codegen_mulL_A_D ( sz, True, src,
sewardj5b470602005-02-27 13:10:48 +00003392 nameIRegE(sz,pfx,modrm) );
sewardj85520e42005-02-19 15:22:38 +00003393 break;
sewardj03b07cc2005-01-31 18:09:43 +00003394 case 6: /* DIV */
3395 delta++;
sewardj5b470602005-02-27 13:10:48 +00003396 assign( t1, getIRegE(sz, pfx, modrm) );
sewardj03b07cc2005-01-31 18:09:43 +00003397 codegen_div ( sz, t1, False );
3398 DIP("div%c %s\n", nameISize(sz),
sewardj5b470602005-02-27 13:10:48 +00003399 nameIRegE(sz, pfx, modrm));
sewardj03b07cc2005-01-31 18:09:43 +00003400 break;
sewardj32b2bbe2005-01-28 00:50:10 +00003401 case 7: /* IDIV */
3402 delta++;
sewardj5b470602005-02-27 13:10:48 +00003403 assign( t1, getIRegE(sz, pfx, modrm) );
sewardj32b2bbe2005-01-28 00:50:10 +00003404 codegen_div ( sz, t1, True );
3405 DIP("idiv%c %s\n", nameISize(sz),
sewardj5b470602005-02-27 13:10:48 +00003406 nameIRegE(sz, pfx, modrm));
sewardj32b2bbe2005-01-28 00:50:10 +00003407 break;
3408 default:
3409 vex_printf(
sewardj901ed122005-02-27 13:25:31 +00003410 "unhandled Grp3(R) case %d\n", (Int)gregLO3ofRM(modrm));
sewardj32b2bbe2005-01-28 00:50:10 +00003411 vpanic("Grp3(amd64)");
3412 }
3413 } else {
sewardj7de0d3c2005-02-13 02:26:41 +00003414 addr = disAMode ( &len, pfx, delta, dis_buf,
3415 /* we have to inform disAMode of any immediate
3416 bytes used */
sewardj901ed122005-02-27 13:25:31 +00003417 gregLO3ofRM(modrm)==0/*TEST*/
sewardj7de0d3c2005-02-13 02:26:41 +00003418 ? imin(4,sz)
3419 : 0
3420 );
sewardj32b2bbe2005-01-28 00:50:10 +00003421 t1 = newTemp(ty);
3422 delta += len;
3423 assign(t1, loadLE(ty,mkexpr(addr)));
sewardj901ed122005-02-27 13:25:31 +00003424 switch (gregLO3ofRM(modrm)) {
sewardj03b07cc2005-01-31 18:09:43 +00003425 case 0: { /* TEST */
3426 d64 = getSDisp(imin(4,sz), delta);
3427 delta += imin(4,sz);
3428 dst1 = newTemp(ty);
3429 assign(dst1, binop(mkSizedOp(ty,Iop_And8),
3430 mkexpr(t1),
3431 mkU(ty, d64 & mkSizeMask(sz))));
3432 setFlags_DEP1( Iop_And8, dst1, ty );
3433 DIP("test%c $%lld, %s\n", nameISize(sz), d64, dis_buf);
3434 break;
3435 }
sewardj82c9f2f2005-03-02 16:05:13 +00003436 /* probably OK, but awaiting test case */
3437 case 2: /* NOT */
3438 storeLE( mkexpr(addr), unop(mkSizedOp(ty,Iop_Not8), mkexpr(t1)));
3439 DIP("not%c %s\n", nameISize(sz), dis_buf);
3440 break;
sewardj7de0d3c2005-02-13 02:26:41 +00003441 case 3: /* NEG */
3442 dst0 = newTemp(ty);
3443 src = newTemp(ty);
3444 dst1 = newTemp(ty);
3445 assign(dst0, mkU(ty,0));
3446 assign(src, mkexpr(t1));
3447 assign(dst1, binop(mkSizedOp(ty,Iop_Sub8), mkexpr(dst0), mkexpr(src)));
3448 setFlags_DEP1_DEP2(Iop_Sub8, dst0, src, ty);
3449 storeLE( mkexpr(addr), mkexpr(dst1) );
3450 DIP("neg%c %s\n", nameISize(sz), dis_buf);
3451 break;
sewardj31eecde2005-03-23 03:39:55 +00003452 case 4: /* MUL (unsigned widening) */
3453 codegen_mulL_A_D ( sz, False, t1, dis_buf );
3454 break;
sewardj3aba9eb2005-03-30 23:20:47 +00003455 case 5: /* IMUL */
3456 codegen_mulL_A_D ( sz, True, t1, dis_buf );
3457 break;
sewardj1001dc42005-02-21 08:25:55 +00003458 case 6: /* DIV */
3459 codegen_div ( sz, t1, False );
3460 DIP("div%c %s\n", nameISize(sz), dis_buf);
3461 break;
sewardj82c9f2f2005-03-02 16:05:13 +00003462 case 7: /* IDIV */
3463 codegen_div ( sz, t1, True );
3464 DIP("idiv%c %s\n", nameISize(sz), dis_buf);
3465 break;
sewardj32b2bbe2005-01-28 00:50:10 +00003466 default:
3467 vex_printf(
sewardj901ed122005-02-27 13:25:31 +00003468 "unhandled Grp3(M) case %d\n", (Int)gregLO3ofRM(modrm));
sewardj32b2bbe2005-01-28 00:50:10 +00003469 vpanic("Grp3(amd64)");
3470 }
3471 }
3472 return delta;
3473}
3474
3475
sewardj03b07cc2005-01-31 18:09:43 +00003476/* Group 4 extended opcodes. */
3477static
sewardj270def42005-07-03 01:03:01 +00003478ULong dis_Grp4 ( Prefix pfx, Long delta )
sewardj03b07cc2005-01-31 18:09:43 +00003479{
3480 Int alen;
3481 UChar modrm;
3482 HChar dis_buf[50];
3483 IRType ty = Ity_I8;
3484 IRTemp t1 = newTemp(ty);
3485 IRTemp t2 = newTemp(ty);
3486
3487 modrm = getUChar(delta);
3488 if (epartIsReg(modrm)) {
sewardj5b470602005-02-27 13:10:48 +00003489 assign(t1, getIRegE(1, pfx, modrm));
sewardj901ed122005-02-27 13:25:31 +00003490 switch (gregLO3ofRM(modrm)) {
sewardj85520e42005-02-19 15:22:38 +00003491 case 0: /* INC */
3492 assign(t2, binop(Iop_Add8, mkexpr(t1), mkU8(1)));
sewardj5b470602005-02-27 13:10:48 +00003493 putIRegE(1, pfx, modrm, mkexpr(t2));
sewardj85520e42005-02-19 15:22:38 +00003494 setFlags_INC_DEC( True, t2, ty );
3495 break;
sewardj03b07cc2005-01-31 18:09:43 +00003496 case 1: /* DEC */
3497 assign(t2, binop(Iop_Sub8, mkexpr(t1), mkU8(1)));
sewardj5b470602005-02-27 13:10:48 +00003498 putIRegE(1, pfx, modrm, mkexpr(t2));
sewardj03b07cc2005-01-31 18:09:43 +00003499 setFlags_INC_DEC( False, t2, ty );
3500 break;
3501 default:
3502 vex_printf(
sewardj901ed122005-02-27 13:25:31 +00003503 "unhandled Grp4(R) case %d\n", (Int)gregLO3ofRM(modrm));
sewardj03b07cc2005-01-31 18:09:43 +00003504 vpanic("Grp4(amd64,R)");
3505 }
3506 delta++;
sewardj901ed122005-02-27 13:25:31 +00003507 DIP("%sb %s\n", nameGrp4(gregLO3ofRM(modrm)),
sewardj5b470602005-02-27 13:10:48 +00003508 nameIRegE(1, pfx, modrm));
sewardj03b07cc2005-01-31 18:09:43 +00003509 } else {
sewardje1698952005-02-08 15:02:39 +00003510 IRTemp addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
sewardj03b07cc2005-01-31 18:09:43 +00003511 assign( t1, loadLE(ty, mkexpr(addr)) );
sewardj901ed122005-02-27 13:25:31 +00003512 switch (gregLO3ofRM(modrm)) {
sewardj007e9ec2005-03-23 11:36:48 +00003513 case 0: /* INC */
3514 assign(t2, binop(Iop_Add8, mkexpr(t1), mkU8(1)));
3515 storeLE( mkexpr(addr), mkexpr(t2) );
3516 setFlags_INC_DEC( True, t2, ty );
3517 break;
3518 case 1: /* DEC */
3519 assign(t2, binop(Iop_Sub8, mkexpr(t1), mkU8(1)));
3520 storeLE( mkexpr(addr), mkexpr(t2) );
3521 setFlags_INC_DEC( False, t2, ty );
3522 break;
sewardj03b07cc2005-01-31 18:09:43 +00003523 default:
3524 vex_printf(
sewardj901ed122005-02-27 13:25:31 +00003525 "unhandled Grp4(M) case %d\n", (Int)gregLO3ofRM(modrm));
sewardj03b07cc2005-01-31 18:09:43 +00003526 vpanic("Grp4(amd64,M)");
3527 }
3528 delta += alen;
sewardj901ed122005-02-27 13:25:31 +00003529 DIP("%sb %s\n", nameGrp4(gregLO3ofRM(modrm)), dis_buf);
sewardj03b07cc2005-01-31 18:09:43 +00003530 }
3531 return delta;
3532}
sewardj354e5c62005-01-27 20:12:52 +00003533
3534
3535/* Group 5 extended opcodes. */
3536static
sewardj270def42005-07-03 01:03:01 +00003537ULong dis_Grp5 ( Prefix pfx, Int sz, Long delta, DisResult* dres )
sewardj354e5c62005-01-27 20:12:52 +00003538{
3539 Int len;
3540 UChar modrm;
3541 HChar dis_buf[50];
3542 IRTemp addr = IRTemp_INVALID;
3543 IRType ty = szToITy(sz);
3544 IRTemp t1 = newTemp(ty);
3545 IRTemp t2 = IRTemp_INVALID;
sewardj03b07cc2005-01-31 18:09:43 +00003546 IRTemp t3 = IRTemp_INVALID;
sewardj7eaa7cf2005-01-31 18:55:22 +00003547 Bool showSz = True;
sewardj354e5c62005-01-27 20:12:52 +00003548
sewardj8c332e22005-01-28 01:36:56 +00003549 modrm = getUChar(delta);
sewardj354e5c62005-01-27 20:12:52 +00003550 if (epartIsReg(modrm)) {
sewardj5b470602005-02-27 13:10:48 +00003551 assign(t1, getIRegE(sz,pfx,modrm));
sewardj901ed122005-02-27 13:25:31 +00003552 switch (gregLO3ofRM(modrm)) {
sewardj32b2bbe2005-01-28 00:50:10 +00003553 case 0: /* INC */
3554 t2 = newTemp(ty);
3555 assign(t2, binop(mkSizedOp(ty,Iop_Add8),
3556 mkexpr(t1), mkU(ty,1)));
3557 setFlags_INC_DEC( True, t2, ty );
sewardj5b470602005-02-27 13:10:48 +00003558 putIRegE(sz,pfx,modrm, mkexpr(t2));
sewardj32b2bbe2005-01-28 00:50:10 +00003559 break;
3560 case 1: /* DEC */
3561 t2 = newTemp(ty);
3562 assign(t2, binop(mkSizedOp(ty,Iop_Sub8),
3563 mkexpr(t1), mkU(ty,1)));
3564 setFlags_INC_DEC( False, t2, ty );
sewardj5b470602005-02-27 13:10:48 +00003565 putIRegE(sz,pfx,modrm, mkexpr(t2));
sewardj32b2bbe2005-01-28 00:50:10 +00003566 break;
sewardj354e5c62005-01-27 20:12:52 +00003567 case 2: /* call Ev */
sewardj03b07cc2005-01-31 18:09:43 +00003568 /* Ignore any sz value and operate as if sz==8. */
sewardjb7bcdf92005-08-02 21:20:36 +00003569 vassert(sz == 4 || sz == 8);
sewardj03b07cc2005-01-31 18:09:43 +00003570 sz = 8;
3571 t3 = newTemp(Ity_I64);
sewardj5b470602005-02-27 13:10:48 +00003572 assign(t3, getIRegE(sz,pfx,modrm));
sewardj03b07cc2005-01-31 18:09:43 +00003573 t2 = newTemp(Ity_I64);
3574 assign(t2, binop(Iop_Sub64, getIReg64(R_RSP), mkU64(8)));
3575 putIReg64(R_RSP, mkexpr(t2));
sewardj9e6491a2005-07-02 19:24:10 +00003576 storeLE( mkexpr(t2), mkU64(guest_RIP_bbstart+delta+1));
sewardj5a9ffab2005-05-12 17:55:01 +00003577 make_redzone_AbiHint(t2, "call-Ev(reg)");
sewardj03b07cc2005-01-31 18:09:43 +00003578 jmp_treg(Ijk_Call,t3);
sewardj9e6491a2005-07-02 19:24:10 +00003579 dres->whatNext = Dis_StopHere;
sewardj7eaa7cf2005-01-31 18:55:22 +00003580 showSz = False;
sewardj354e5c62005-01-27 20:12:52 +00003581 break;
sewardj354e5c62005-01-27 20:12:52 +00003582 case 4: /* jmp Ev */
sewardj03b07cc2005-01-31 18:09:43 +00003583 /* Ignore any sz value and operate as if sz==8. */
sewardj0bfc6b62005-07-07 14:15:35 +00003584 vassert(sz == 4 || sz == 8);
sewardj03b07cc2005-01-31 18:09:43 +00003585 sz = 8;
3586 t3 = newTemp(Ity_I64);
sewardj5b470602005-02-27 13:10:48 +00003587 assign(t3, getIRegE(sz,pfx,modrm));
sewardj03b07cc2005-01-31 18:09:43 +00003588 jmp_treg(Ijk_Boring,t3);
sewardj9e6491a2005-07-02 19:24:10 +00003589 dres->whatNext = Dis_StopHere;
sewardj7eaa7cf2005-01-31 18:55:22 +00003590 showSz = False;
sewardj354e5c62005-01-27 20:12:52 +00003591 break;
sewardj354e5c62005-01-27 20:12:52 +00003592 default:
3593 vex_printf(
sewardj901ed122005-02-27 13:25:31 +00003594 "unhandled Grp5(R) case %d\n", (Int)gregLO3ofRM(modrm));
sewardj354e5c62005-01-27 20:12:52 +00003595 vpanic("Grp5(amd64)");
3596 }
3597 delta++;
sewardj901ed122005-02-27 13:25:31 +00003598 DIP("%s%c %s\n", nameGrp5(gregLO3ofRM(modrm)),
sewardj7eaa7cf2005-01-31 18:55:22 +00003599 showSz ? nameISize(sz) : ' ',
sewardj5b470602005-02-27 13:10:48 +00003600 nameIRegE(sz, pfx, modrm));
sewardj354e5c62005-01-27 20:12:52 +00003601 } else {
sewardje1698952005-02-08 15:02:39 +00003602 addr = disAMode ( &len, pfx, delta, dis_buf, 0 );
sewardj901ed122005-02-27 13:25:31 +00003603 if (gregLO3ofRM(modrm) != 2 && gregLO3ofRM(modrm) != 4
3604 && gregLO3ofRM(modrm) != 6) {
sewardj03b07cc2005-01-31 18:09:43 +00003605 assign(t1, loadLE(ty,mkexpr(addr)));
sewardj909c06d2005-02-19 22:47:41 +00003606 }
sewardj901ed122005-02-27 13:25:31 +00003607 switch (gregLO3ofRM(modrm)) {
sewardj354e5c62005-01-27 20:12:52 +00003608 case 0: /* INC */
sewardj354e5c62005-01-27 20:12:52 +00003609 t2 = newTemp(ty);
3610 assign(t2, binop(mkSizedOp(ty,Iop_Add8),
3611 mkexpr(t1), mkU(ty,1)));
3612 setFlags_INC_DEC( True, t2, ty );
3613 storeLE(mkexpr(addr),mkexpr(t2));
3614 break;
sewardj354e5c62005-01-27 20:12:52 +00003615 case 1: /* DEC */
3616 t2 = newTemp(ty);
3617 assign(t2, binop(mkSizedOp(ty,Iop_Sub8),
3618 mkexpr(t1), mkU(ty,1)));
3619 setFlags_INC_DEC( False, t2, ty );
3620 storeLE(mkexpr(addr),mkexpr(t2));
3621 break;
3622 case 2: /* call Ev */
sewardj03b07cc2005-01-31 18:09:43 +00003623 /* Ignore any sz value and operate as if sz==8. */
sewardj354e5c62005-01-27 20:12:52 +00003624 vassert(sz == 4);
sewardj7eaa7cf2005-01-31 18:55:22 +00003625 sz = 8;
sewardj03b07cc2005-01-31 18:09:43 +00003626 t3 = newTemp(Ity_I64);
3627 assign(t3, loadLE(Ity_I64,mkexpr(addr)));
3628 t2 = newTemp(Ity_I64);
3629 assign(t2, binop(Iop_Sub64, getIReg64(R_RSP), mkU64(8)));
3630 putIReg64(R_RSP, mkexpr(t2));
sewardj9e6491a2005-07-02 19:24:10 +00003631 storeLE( mkexpr(t2), mkU64(guest_RIP_bbstart+delta+len));
sewardj5a9ffab2005-05-12 17:55:01 +00003632 make_redzone_AbiHint(t2, "call-Ev(mem)");
sewardj03b07cc2005-01-31 18:09:43 +00003633 jmp_treg(Ijk_Call,t3);
sewardj9e6491a2005-07-02 19:24:10 +00003634 dres->whatNext = Dis_StopHere;
sewardj7eaa7cf2005-01-31 18:55:22 +00003635 showSz = False;
sewardj354e5c62005-01-27 20:12:52 +00003636 break;
sewardj354e5c62005-01-27 20:12:52 +00003637 case 4: /* JMP Ev */
sewardj03b07cc2005-01-31 18:09:43 +00003638 /* Ignore any sz value and operate as if sz==8. */
sewardj354e5c62005-01-27 20:12:52 +00003639 vassert(sz == 4);
sewardj7eaa7cf2005-01-31 18:55:22 +00003640 sz = 8;
sewardj03b07cc2005-01-31 18:09:43 +00003641 t3 = newTemp(Ity_I64);
3642 assign(t3, loadLE(Ity_I64,mkexpr(addr)));
3643 jmp_treg(Ijk_Boring,t3);
sewardj9e6491a2005-07-02 19:24:10 +00003644 dres->whatNext = Dis_StopHere;
sewardj7eaa7cf2005-01-31 18:55:22 +00003645 showSz = False;
sewardj354e5c62005-01-27 20:12:52 +00003646 break;
sewardj354e5c62005-01-27 20:12:52 +00003647 case 6: /* PUSH Ev */
sewardja6b93d12005-02-17 09:28:28 +00003648 /* There is no encoding for 32-bit operand size; hence ... */
3649 if (sz == 4) sz = 8;
3650 vassert(sz == 8 || sz == 2);
sewardj909c06d2005-02-19 22:47:41 +00003651 if (sz == 8) {
3652 t3 = newTemp(Ity_I64);
3653 assign(t3, loadLE(Ity_I64,mkexpr(addr)));
3654 t2 = newTemp(Ity_I64);
3655 assign( t2, binop(Iop_Sub64,getIReg64(R_RSP),mkU64(sz)) );
3656 putIReg64(R_RSP, mkexpr(t2) );
3657 storeLE( mkexpr(t2), mkexpr(t3) );
3658 break;
3659 } else {
3660 goto unhandled; /* awaiting test case */
3661 }
sewardj354e5c62005-01-27 20:12:52 +00003662 default:
sewardja6b93d12005-02-17 09:28:28 +00003663 unhandled:
sewardj354e5c62005-01-27 20:12:52 +00003664 vex_printf(
sewardj901ed122005-02-27 13:25:31 +00003665 "unhandled Grp5(M) case %d\n", (Int)gregLO3ofRM(modrm));
sewardj354e5c62005-01-27 20:12:52 +00003666 vpanic("Grp5(amd64)");
3667 }
3668 delta += len;
sewardj901ed122005-02-27 13:25:31 +00003669 DIP("%s%c %s\n", nameGrp5(gregLO3ofRM(modrm)),
sewardj7eaa7cf2005-01-31 18:55:22 +00003670 showSz ? nameISize(sz) : ' ',
3671 dis_buf);
sewardj354e5c62005-01-27 20:12:52 +00003672 }
3673 return delta;
3674}
3675
3676
sewardjd0a12df2005-02-10 02:07:43 +00003677/*------------------------------------------------------------*/
3678/*--- Disassembling string ops (including REP prefixes) ---*/
3679/*------------------------------------------------------------*/
3680
3681/* Code shared by all the string ops */
3682static
3683void dis_string_op_increment ( Int sz, IRTemp t_inc )
3684{
3685 UChar logSz;
3686 if (sz == 8 || sz == 4 || sz == 2) {
3687 logSz = 1;
3688 if (sz == 4) logSz = 2;
3689 if (sz == 8) logSz = 3;
3690 assign( t_inc,
3691 binop(Iop_Shl64, IRExpr_Get( OFFB_DFLAG, Ity_I64 ),
3692 mkU8(logSz) ) );
3693 } else {
3694 assign( t_inc,
3695 IRExpr_Get( OFFB_DFLAG, Ity_I64 ) );
3696 }
3697}
3698
sewardj909c06d2005-02-19 22:47:41 +00003699static
3700void dis_string_op( void (*dis_OP)( Int, IRTemp ),
3701 Int sz, HChar* name, Prefix pfx )
3702{
3703 IRTemp t_inc = newTemp(Ity_I64);
3704 /* Really we ought to inspect the override prefixes, but we don't.
3705 The following assertion catches any resulting sillyness. */
3706 vassert(pfx == clearSegBits(pfx));
3707 dis_string_op_increment(sz, t_inc);
3708 dis_OP( sz, t_inc );
3709 DIP("%s%c\n", name, nameISize(sz));
3710}
3711
3712static
3713void dis_MOVS ( Int sz, IRTemp t_inc )
3714{
3715 IRType ty = szToITy(sz);
3716 IRTemp td = newTemp(Ity_I64); /* RDI */
3717 IRTemp ts = newTemp(Ity_I64); /* RSI */
3718
3719 assign( td, getIReg64(R_RDI) );
3720 assign( ts, getIReg64(R_RSI) );
3721
3722 storeLE( mkexpr(td), loadLE(ty,mkexpr(ts)) );
3723
3724 putIReg64( R_RDI, binop(Iop_Add64, mkexpr(td), mkexpr(t_inc)) );
3725 putIReg64( R_RSI, binop(Iop_Add64, mkexpr(ts), mkexpr(t_inc)) );
3726}
3727
sewardjd20c8852005-01-20 20:04:07 +00003728//.. //-- static
3729//.. //-- void dis_LODS ( UCodeBlock* cb, Int sz, Int t_inc )
3730//.. //-- {
3731//.. //-- Int ta = newTemp(cb); /* EAX */
3732//.. //-- Int ts = newTemp(cb); /* ESI */
3733//.. //--
3734//.. //-- uInstr2(cb, GET, 4, ArchReg, R_ESI, TempReg, ts);
3735//.. //-- uInstr2(cb, LOAD, sz, TempReg, ts, TempReg, ta);
3736//.. //-- uInstr2(cb, PUT, sz, TempReg, ta, ArchReg, R_EAX);
3737//.. //--
3738//.. //-- uInstr2(cb, ADD, 4, TempReg, t_inc, TempReg, ts);
3739//.. //-- uInstr2(cb, PUT, 4, TempReg, ts, ArchReg, R_ESI);
3740//.. //-- }
sewardja6b93d12005-02-17 09:28:28 +00003741
3742static
3743void dis_STOS ( Int sz, IRTemp t_inc )
3744{
3745 IRType ty = szToITy(sz);
3746 IRTemp ta = newTemp(ty); /* rAX */
3747 IRTemp td = newTemp(Ity_I64); /* RDI */
3748
sewardj5b470602005-02-27 13:10:48 +00003749 assign( ta, getIRegRAX(sz) );
sewardja6b93d12005-02-17 09:28:28 +00003750
3751 assign( td, getIReg64(R_RDI) );
3752
3753 storeLE( mkexpr(td), mkexpr(ta) );
3754
3755 putIReg64( R_RDI, binop(Iop_Add64, mkexpr(td), mkexpr(t_inc)) );
3756}
sewardjd0a12df2005-02-10 02:07:43 +00003757
3758static
3759void dis_CMPS ( Int sz, IRTemp t_inc )
3760{
3761 IRType ty = szToITy(sz);
3762 IRTemp tdv = newTemp(ty); /* (RDI) */
3763 IRTemp tsv = newTemp(ty); /* (RSI) */
3764 IRTemp td = newTemp(Ity_I64); /* RDI */
3765 IRTemp ts = newTemp(Ity_I64); /* RSI */
3766
3767 assign( td, getIReg64(R_RDI) );
3768
3769 assign( ts, getIReg64(R_RSI) );
3770
3771 assign( tdv, loadLE(ty,mkexpr(td)) );
3772
3773 assign( tsv, loadLE(ty,mkexpr(ts)) );
3774
3775 setFlags_DEP1_DEP2 ( Iop_Sub8, tsv, tdv, ty );
3776
3777 putIReg64(R_RDI, binop(Iop_Add64, mkexpr(td), mkexpr(t_inc)) );
3778
3779 putIReg64(R_RSI, binop(Iop_Add64, mkexpr(ts), mkexpr(t_inc)) );
3780}
3781
sewardj85520e42005-02-19 15:22:38 +00003782static
3783void dis_SCAS ( Int sz, IRTemp t_inc )
3784{
3785 IRType ty = szToITy(sz);
3786 IRTemp ta = newTemp(ty); /* rAX */
3787 IRTemp td = newTemp(Ity_I64); /* RDI */
3788 IRTemp tdv = newTemp(ty); /* (RDI) */
3789
sewardj5b470602005-02-27 13:10:48 +00003790 assign( ta, getIRegRAX(sz) );
sewardj85520e42005-02-19 15:22:38 +00003791
3792 assign( td, getIReg64(R_RDI) );
3793
3794 assign( tdv, loadLE(ty,mkexpr(td)) );
3795
3796 setFlags_DEP1_DEP2 ( Iop_Sub8, ta, tdv, ty );
3797
3798 putIReg64(R_RDI, binop(Iop_Add64, mkexpr(td), mkexpr(t_inc)) );
3799}
sewardjd0a12df2005-02-10 02:07:43 +00003800
3801
3802/* Wrap the appropriate string op inside a REP/REPE/REPNE. We assume
3803 the insn is the last one in the basic block, and so emit a jump to
3804 the next insn, rather than just falling through. */
3805static
3806void dis_REP_op ( AMD64Condcode cond,
3807 void (*dis_OP)(Int, IRTemp),
sewardj909c06d2005-02-19 22:47:41 +00003808 Int sz, Addr64 rip, Addr64 rip_next, HChar* name,
3809 Prefix pfx )
sewardjd0a12df2005-02-10 02:07:43 +00003810{
3811 IRTemp t_inc = newTemp(Ity_I64);
3812 IRTemp tc = newTemp(Ity_I64); /* RCX */
3813
sewardj909c06d2005-02-19 22:47:41 +00003814 /* Really we ought to inspect the override prefixes, but we don't.
3815 The following assertion catches any resulting sillyness. */
3816 vassert(pfx == clearSegBits(pfx));
3817
sewardjd0a12df2005-02-10 02:07:43 +00003818 assign( tc, getIReg64(R_RCX) );
3819
3820 stmt( IRStmt_Exit( binop(Iop_CmpEQ64,mkexpr(tc),mkU64(0)),
3821 Ijk_Boring,
3822 IRConst_U64(rip_next) ) );
3823
3824 putIReg64(R_RCX, binop(Iop_Sub64, mkexpr(tc), mkU64(1)) );
3825
3826 dis_string_op_increment(sz, t_inc);
3827 dis_OP (sz, t_inc);
3828
3829 if (cond == AMD64CondAlways) {
3830 jmp_lit(Ijk_Boring,rip);
3831 } else {
3832 stmt( IRStmt_Exit( mk_amd64g_calculate_condition(cond),
3833 Ijk_Boring,
3834 IRConst_U64(rip) ) );
3835 jmp_lit(Ijk_Boring,rip_next);
3836 }
3837 DIP("%s%c\n", name, nameISize(sz));
3838}
sewardj32b2bbe2005-01-28 00:50:10 +00003839
3840
3841/*------------------------------------------------------------*/
3842/*--- Arithmetic, etc. ---*/
3843/*------------------------------------------------------------*/
3844
3845/* IMUL E, G. Supplied eip points to the modR/M byte. */
3846static
3847ULong dis_mul_E_G ( Prefix pfx,
3848 Int size,
sewardj270def42005-07-03 01:03:01 +00003849 Long delta0 )
sewardj32b2bbe2005-01-28 00:50:10 +00003850{
3851 Int alen;
3852 HChar dis_buf[50];
sewardj8c332e22005-01-28 01:36:56 +00003853 UChar rm = getUChar(delta0);
sewardj32b2bbe2005-01-28 00:50:10 +00003854 IRType ty = szToITy(size);
3855 IRTemp te = newTemp(ty);
3856 IRTemp tg = newTemp(ty);
3857 IRTemp resLo = newTemp(ty);
3858
sewardj5b470602005-02-27 13:10:48 +00003859 assign( tg, getIRegG(size, pfx, rm) );
sewardj32b2bbe2005-01-28 00:50:10 +00003860 if (epartIsReg(rm)) {
sewardj5b470602005-02-27 13:10:48 +00003861 assign( te, getIRegE(size, pfx, rm) );
sewardj32b2bbe2005-01-28 00:50:10 +00003862 } else {
sewardje1698952005-02-08 15:02:39 +00003863 IRTemp addr = disAMode( &alen, pfx, delta0, dis_buf, 0 );
sewardj32b2bbe2005-01-28 00:50:10 +00003864 assign( te, loadLE(ty,mkexpr(addr)) );
3865 }
3866
3867 setFlags_MUL ( ty, te, tg, AMD64G_CC_OP_SMULB );
3868
3869 assign( resLo, binop( mkSizedOp(ty, Iop_Mul8), mkexpr(te), mkexpr(tg) ) );
3870
sewardj5b470602005-02-27 13:10:48 +00003871 putIRegG(size, pfx, rm, mkexpr(resLo) );
sewardj32b2bbe2005-01-28 00:50:10 +00003872
3873 if (epartIsReg(rm)) {
3874 DIP("imul%c %s, %s\n", nameISize(size),
sewardj901ed122005-02-27 13:25:31 +00003875 nameIRegE(size,pfx,rm),
3876 nameIRegG(size,pfx,rm));
sewardj32b2bbe2005-01-28 00:50:10 +00003877 return 1+delta0;
3878 } else {
3879 DIP("imul%c %s, %s\n", nameISize(size),
3880 dis_buf,
sewardj901ed122005-02-27 13:25:31 +00003881 nameIRegG(size,pfx,rm));
sewardj32b2bbe2005-01-28 00:50:10 +00003882 return alen+delta0;
3883 }
3884}
3885
3886
3887/* IMUL I * E -> G. Supplied rip points to the modR/M byte. */
3888static
3889ULong dis_imul_I_E_G ( Prefix pfx,
3890 Int size,
sewardj270def42005-07-03 01:03:01 +00003891 Long delta,
sewardj32b2bbe2005-01-28 00:50:10 +00003892 Int litsize )
3893{
3894 Long d64;
3895 Int alen;
3896 HChar dis_buf[50];
sewardj8c332e22005-01-28 01:36:56 +00003897 UChar rm = getUChar(delta);
sewardj32b2bbe2005-01-28 00:50:10 +00003898 IRType ty = szToITy(size);
3899 IRTemp te = newTemp(ty);
3900 IRTemp tl = newTemp(ty);
3901 IRTemp resLo = newTemp(ty);
3902
sewardj85520e42005-02-19 15:22:38 +00003903 vassert(/*size == 1 ||*/ size == 2 || size == 4 || size == 8);
sewardj32b2bbe2005-01-28 00:50:10 +00003904
3905 if (epartIsReg(rm)) {
sewardj5b470602005-02-27 13:10:48 +00003906 assign(te, getIRegE(size, pfx, rm));
sewardj32b2bbe2005-01-28 00:50:10 +00003907 delta++;
3908 } else {
sewardj7de0d3c2005-02-13 02:26:41 +00003909 IRTemp addr = disAMode( &alen, pfx, delta, dis_buf,
3910 imin(4,litsize) );
sewardj32b2bbe2005-01-28 00:50:10 +00003911 assign(te, loadLE(ty, mkexpr(addr)));
3912 delta += alen;
3913 }
3914 d64 = getSDisp(imin(4,litsize),delta);
3915 delta += imin(4,litsize);
3916
sewardj1389d4d2005-01-28 13:46:29 +00003917 d64 &= mkSizeMask(size);
sewardj32b2bbe2005-01-28 00:50:10 +00003918 assign(tl, mkU(ty,d64));
3919
3920 assign( resLo, binop( mkSizedOp(ty, Iop_Mul8), mkexpr(te), mkexpr(tl) ));
3921
3922 setFlags_MUL ( ty, te, tl, AMD64G_CC_OP_SMULB );
3923
sewardj5b470602005-02-27 13:10:48 +00003924 putIRegG(size, pfx, rm, mkexpr(resLo));
sewardj32b2bbe2005-01-28 00:50:10 +00003925
3926 DIP("imul%c $%lld, %s, %s\n",
3927 nameISize(size), d64,
sewardj5b470602005-02-27 13:10:48 +00003928 ( epartIsReg(rm) ? nameIRegE(size,pfx,rm) : dis_buf ),
3929 nameIRegG(size,pfx,rm) );
sewardj32b2bbe2005-01-28 00:50:10 +00003930 return delta;
3931}
3932
3933
sewardjbcbb9de2005-03-27 02:22:32 +00003934/*------------------------------------------------------------*/
3935/*--- ---*/
3936/*--- x87 FLOATING POINT INSTRUCTIONS ---*/
3937/*--- ---*/
3938/*------------------------------------------------------------*/
3939
3940/* --- Helper functions for dealing with the register stack. --- */
3941
3942/* --- Set the emulation-warning pseudo-register. --- */
3943
3944static void put_emwarn ( IRExpr* e /* :: Ity_I32 */ )
3945{
3946 vassert(typeOfIRExpr(irbb->tyenv, e) == Ity_I32);
3947 stmt( IRStmt_Put( OFFB_EMWARN, e ) );
3948}
sewardj8d965312005-02-25 02:48:47 +00003949
3950/* --- Produce an IRExpr* denoting a 64-bit QNaN. --- */
3951
3952static IRExpr* mkQNaN64 ( void )
3953{
3954 /* QNaN is 0 2047 1 0(51times)
3955 == 0b 11111111111b 1 0(51times)
3956 == 0x7FF8 0000 0000 0000
3957 */
3958 return IRExpr_Const(IRConst_F64i(0x7FF8000000000000ULL));
3959}
3960
3961/* --------- Get/put the top-of-stack pointer :: Ity_I32 --------- */
3962
3963static IRExpr* get_ftop ( void )
3964{
3965 return IRExpr_Get( OFFB_FTOP, Ity_I32 );
3966}
3967
3968static void put_ftop ( IRExpr* e )
3969{
3970 vassert(typeOfIRExpr(irbb->tyenv, e) == Ity_I32);
3971 stmt( IRStmt_Put( OFFB_FTOP, e ) );
3972}
3973
sewardj25a85812005-05-08 23:03:48 +00003974/* --------- Get/put the C3210 bits. --------- */
3975
3976static IRExpr* /* :: Ity_I64 */ get_C3210 ( void )
3977{
3978 return IRExpr_Get( OFFB_FC3210, Ity_I64 );
3979}
3980
3981static void put_C3210 ( IRExpr* e /* :: Ity_I64 */ )
3982{
3983 vassert(typeOfIRExpr(irbb->tyenv, e) == Ity_I64);
3984 stmt( IRStmt_Put( OFFB_FC3210, e ) );
3985}
sewardjc49ce232005-02-25 13:03:03 +00003986
3987/* --------- Get/put the FPU rounding mode. --------- */
3988static IRExpr* /* :: Ity_I32 */ get_fpround ( void )
3989{
3990 return unop(Iop_64to32, IRExpr_Get( OFFB_FPROUND, Ity_I64 ));
3991}
3992
sewardj5e205372005-05-09 02:57:08 +00003993static void put_fpround ( IRExpr* /* :: Ity_I32 */ e )
3994{
3995 vassert(typeOfIRExpr(irbb->tyenv, e) == Ity_I32);
3996 stmt( IRStmt_Put( OFFB_FPROUND, unop(Iop_32Uto64,e) ) );
3997}
sewardjc49ce232005-02-25 13:03:03 +00003998
3999
4000/* --------- Synthesise a 2-bit FPU rounding mode. --------- */
4001/* Produces a value in 0 .. 3, which is encoded as per the type
4002 IRRoundingMode. Since the guest_FPROUND value is also encoded as
4003 per IRRoundingMode, we merely need to get it and mask it for
4004 safety.
4005*/
4006static IRExpr* /* :: Ity_I32 */ get_roundingmode ( void )
4007{
4008 return binop( Iop_And32, get_fpround(), mkU32(3) );
4009}
sewardj8d965312005-02-25 02:48:47 +00004010
4011
4012/* --------- Get/set FP register tag bytes. --------- */
4013
4014/* Given i, and some expression e, generate 'ST_TAG(i) = e'. */
4015
4016static void put_ST_TAG ( Int i, IRExpr* value )
4017{
4018 IRArray* descr;
4019 vassert(typeOfIRExpr(irbb->tyenv, value) == Ity_I8);
4020 descr = mkIRArray( OFFB_FPTAGS, Ity_I8, 8 );
4021 stmt( IRStmt_PutI( descr, get_ftop(), i, value ) );
4022}
4023
4024/* Given i, generate an expression yielding 'ST_TAG(i)'. This will be
4025 zero to indicate "Empty" and nonzero to indicate "NonEmpty". */
4026
4027static IRExpr* get_ST_TAG ( Int i )
4028{
4029 IRArray* descr = mkIRArray( OFFB_FPTAGS, Ity_I8, 8 );
4030 return IRExpr_GetI( descr, get_ftop(), i );
4031}
4032
4033
4034/* --------- Get/set FP registers. --------- */
4035
4036/* Given i, and some expression e, emit 'ST(i) = e' and set the
4037 register's tag to indicate the register is full. The previous
4038 state of the register is not checked. */
4039
4040static void put_ST_UNCHECKED ( Int i, IRExpr* value )
4041{
4042 IRArray* descr;
4043 vassert(typeOfIRExpr(irbb->tyenv, value) == Ity_F64);
4044 descr = mkIRArray( OFFB_FPREGS, Ity_F64, 8 );
4045 stmt( IRStmt_PutI( descr, get_ftop(), i, value ) );
4046 /* Mark the register as in-use. */
4047 put_ST_TAG(i, mkU8(1));
4048}
4049
4050/* Given i, and some expression e, emit
4051 ST(i) = is_full(i) ? NaN : e
4052 and set the tag accordingly.
4053*/
4054
4055static void put_ST ( Int i, IRExpr* value )
4056{
4057 put_ST_UNCHECKED( i,
4058 IRExpr_Mux0X( get_ST_TAG(i),
4059 /* 0 means empty */
4060 value,
4061 /* non-0 means full */
4062 mkQNaN64()
4063 )
4064 );
4065}
4066
4067
4068/* Given i, generate an expression yielding 'ST(i)'. */
4069
4070static IRExpr* get_ST_UNCHECKED ( Int i )
4071{
4072 IRArray* descr = mkIRArray( OFFB_FPREGS, Ity_F64, 8 );
4073 return IRExpr_GetI( descr, get_ftop(), i );
4074}
4075
4076
4077/* Given i, generate an expression yielding
4078 is_full(i) ? ST(i) : NaN
4079*/
4080
4081static IRExpr* get_ST ( Int i )
4082{
4083 return
4084 IRExpr_Mux0X( get_ST_TAG(i),
4085 /* 0 means empty */
4086 mkQNaN64(),
4087 /* non-0 means full */
4088 get_ST_UNCHECKED(i));
4089}
4090
4091
4092/* Adjust FTOP downwards by one register. */
4093
4094static void fp_push ( void )
4095{
4096 put_ftop( binop(Iop_Sub32, get_ftop(), mkU32(1)) );
4097}
4098
4099/* Adjust FTOP upwards by one register, and mark the vacated register
4100 as empty. */
4101
4102static void fp_pop ( void )
4103{
4104 put_ST_TAG(0, mkU8(0));
4105 put_ftop( binop(Iop_Add32, get_ftop(), mkU32(1)) );
4106}
4107
sewardj25a85812005-05-08 23:03:48 +00004108/* Clear the C2 bit of the FPU status register, for
4109 sin/cos/tan/sincos. */
4110
4111static void clear_C2 ( void )
4112{
4113 put_C3210( binop(Iop_And64, get_C3210(), mkU64(~AMD64G_FC_MASK_C2)) );
4114}
sewardj48a89d82005-05-06 11:50:13 +00004115
4116
4117/* ------------------------------------------------------- */
4118/* Given all that stack-mangling junk, we can now go ahead
4119 and describe FP instructions.
4120*/
4121
4122/* ST(0) = ST(0) `op` mem64/32(addr)
4123 Need to check ST(0)'s tag on read, but not on write.
4124*/
4125static
sewardjca673ab2005-05-11 10:03:08 +00004126void fp_do_op_mem_ST_0 ( IRTemp addr, HChar* op_txt, HChar* dis_buf,
sewardj48a89d82005-05-06 11:50:13 +00004127 IROp op, Bool dbl )
4128{
4129 DIP("f%s%c %s\n", op_txt, dbl?'l':'s', dis_buf);
4130 if (dbl) {
4131 put_ST_UNCHECKED(0,
4132 binop( op,
4133 get_ST(0),
4134 loadLE(Ity_F64,mkexpr(addr))
4135 ));
4136 } else {
4137 put_ST_UNCHECKED(0,
4138 binop( op,
4139 get_ST(0),
4140 unop(Iop_F32toF64, loadLE(Ity_F32,mkexpr(addr)))
4141 ));
4142 }
4143}
sewardj7bc00082005-03-27 05:08:32 +00004144
4145
4146/* ST(0) = mem64/32(addr) `op` ST(0)
4147 Need to check ST(0)'s tag on read, but not on write.
4148*/
4149static
4150void fp_do_oprev_mem_ST_0 ( IRTemp addr, HChar* op_txt, HChar* dis_buf,
4151 IROp op, Bool dbl )
4152{
4153 DIP("f%s%c %s\n", op_txt, dbl?'l':'s', dis_buf);
4154 if (dbl) {
4155 put_ST_UNCHECKED(0,
4156 binop( op,
4157 loadLE(Ity_F64,mkexpr(addr)),
4158 get_ST(0)
4159 ));
4160 } else {
4161 put_ST_UNCHECKED(0,
4162 binop( op,
4163 unop(Iop_F32toF64, loadLE(Ity_F32,mkexpr(addr))),
4164 get_ST(0)
4165 ));
4166 }
4167}
sewardj37d52572005-02-25 14:22:12 +00004168
4169
4170/* ST(dst) = ST(dst) `op` ST(src).
4171 Check dst and src tags when reading but not on write.
4172*/
4173static
4174void fp_do_op_ST_ST ( HChar* op_txt, IROp op, UInt st_src, UInt st_dst,
4175 Bool pop_after )
4176{
sewardj1027dc22005-02-26 01:55:02 +00004177 DIP("f%s%s st(%u), st(%u)\n", op_txt, pop_after?"p":"", st_src, st_dst );
sewardj37d52572005-02-25 14:22:12 +00004178 put_ST_UNCHECKED(
4179 st_dst,
4180 binop(op, get_ST(st_dst), get_ST(st_src) )
4181 );
4182 if (pop_after)
4183 fp_pop();
4184}
4185
sewardj137015d2005-03-27 04:01:15 +00004186/* ST(dst) = ST(src) `op` ST(dst).
4187 Check dst and src tags when reading but not on write.
4188*/
4189static
4190void fp_do_oprev_ST_ST ( HChar* op_txt, IROp op, UInt st_src, UInt st_dst,
4191 Bool pop_after )
4192{
4193 DIP("f%s%s st(%u), st(%u)\n", op_txt, pop_after?"p":"", st_src, st_dst );
4194 put_ST_UNCHECKED(
4195 st_dst,
4196 binop(op, get_ST(st_src), get_ST(st_dst) )
4197 );
4198 if (pop_after)
4199 fp_pop();
4200}
sewardjc49ce232005-02-25 13:03:03 +00004201
4202/* %rflags(Z,P,C) = UCOMI( st(0), st(i) ) */
4203static void fp_do_ucomi_ST0_STi ( UInt i, Bool pop_after )
4204{
sewardj1027dc22005-02-26 01:55:02 +00004205 DIP("fucomi%s %%st(0),%%st(%u)\n", pop_after ? "p" : "", i);
sewardjc49ce232005-02-25 13:03:03 +00004206 /* This is a bit of a hack (and isn't really right). It sets
4207 Z,P,C,O correctly, but forces A and S to zero, whereas the Intel
4208 documentation implies A and S are unchanged.
4209 */
4210 /* It's also fishy in that it is used both for COMIP and
4211 UCOMIP, and they aren't the same (although similar). */
4212 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(AMD64G_CC_OP_COPY) ));
4213 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
4214 stmt( IRStmt_Put(
4215 OFFB_CC_DEP1,
4216 binop( Iop_And64,
4217 unop( Iop_32Uto64,
4218 binop(Iop_CmpF64, get_ST(0), get_ST(i))),
4219 mkU64(0x45)
4220 )));
4221 if (pop_after)
4222 fp_pop();
4223}
sewardj8d965312005-02-25 02:48:47 +00004224
4225
4226static
sewardjb4fd2e72005-03-23 13:34:11 +00004227ULong dis_FPU ( /*OUT*/Bool* decode_ok,
sewardj270def42005-07-03 01:03:01 +00004228 Prefix pfx, Long delta )
sewardj8d965312005-02-25 02:48:47 +00004229{
4230 Int len;
4231 UInt r_src, r_dst;
4232 HChar dis_buf[50];
4233 IRTemp t1, t2;
4234
4235 /* On entry, delta points at the second byte of the insn (the modrm
4236 byte).*/
4237 UChar first_opcode = getUChar(delta-1);
4238 UChar modrm = getUChar(delta+0);
4239
sewardj37d52572005-02-25 14:22:12 +00004240 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xD8 opcodes +-+-+-+-+-+-+-+ */
4241
4242 if (first_opcode == 0xD8) {
4243 if (modrm < 0xC0) {
4244
4245 /* bits 5,4,3 are an opcode extension, and the modRM also
4246 specifies an address. */
sewardj7bc00082005-03-27 05:08:32 +00004247 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
4248 delta += len;
sewardj37d52572005-02-25 14:22:12 +00004249
sewardj901ed122005-02-27 13:25:31 +00004250 switch (gregLO3ofRM(modrm)) {
sewardj37d52572005-02-25 14:22:12 +00004251
sewardj48a89d82005-05-06 11:50:13 +00004252 case 0: /* FADD single-real */
4253 fp_do_op_mem_ST_0 ( addr, "add", dis_buf, Iop_AddF64, False );
4254 break;
4255
sewardje6939f02005-05-07 01:01:24 +00004256 case 1: /* FMUL single-real */
4257 fp_do_op_mem_ST_0 ( addr, "mul", dis_buf, Iop_MulF64, False );
4258 break;
4259
sewardjd20c8852005-01-20 20:04:07 +00004260//.. case 2: /* FCOM single-real */
4261//.. DIP("fcoms %s\n", dis_buf);
4262//.. /* This forces C1 to zero, which isn't right. */
4263//.. put_C3210(
4264//.. binop( Iop_And32,
4265//.. binop(Iop_Shl32,
4266//.. binop(Iop_CmpF64,
4267//.. get_ST(0),
4268//.. unop(Iop_F32toF64,
4269//.. loadLE(Ity_F32,mkexpr(addr)))),
4270//.. mkU8(8)),
4271//.. mkU32(0x4500)
4272//.. ));
4273//.. break;
4274//..
4275//.. case 3: /* FCOMP single-real */
4276//.. DIP("fcomps %s\n", dis_buf);
4277//.. /* This forces C1 to zero, which isn't right. */
4278//.. put_C3210(
4279//.. binop( Iop_And32,
4280//.. binop(Iop_Shl32,
4281//.. binop(Iop_CmpF64,
4282//.. get_ST(0),
4283//.. unop(Iop_F32toF64,
4284//.. loadLE(Ity_F32,mkexpr(addr)))),
4285//.. mkU8(8)),
4286//.. mkU32(0x4500)
4287//.. ));
4288//.. fp_pop();
4289//.. break;
sewardje6939f02005-05-07 01:01:24 +00004290
4291 case 4: /* FSUB single-real */
4292 fp_do_op_mem_ST_0 ( addr, "sub", dis_buf, Iop_SubF64, False );
4293 break;
sewardj7bc00082005-03-27 05:08:32 +00004294
4295 case 5: /* FSUBR single-real */
4296 fp_do_oprev_mem_ST_0 ( addr, "subr", dis_buf, Iop_SubF64, False );
4297 break;
4298
sewardje6939f02005-05-07 01:01:24 +00004299 case 6: /* FDIV single-real */
4300 fp_do_op_mem_ST_0 ( addr, "div", dis_buf, Iop_DivF64, False );
4301 break;
4302
4303 case 7: /* FDIVR single-real */
4304 fp_do_oprev_mem_ST_0 ( addr, "divr", dis_buf, Iop_DivF64, False );
4305 break;
sewardj37d52572005-02-25 14:22:12 +00004306
4307 default:
sewardj901ed122005-02-27 13:25:31 +00004308 vex_printf("unhandled opc_aux = 0x%2x\n", gregLO3ofRM(modrm));
sewardj37d52572005-02-25 14:22:12 +00004309 vex_printf("first_opcode == 0xD8\n");
4310 goto decode_fail;
4311 }
4312 } else {
4313 delta++;
4314 switch (modrm) {
4315
4316 case 0xC0 ... 0xC7: /* FADD %st(?),%st(0) */
4317 fp_do_op_ST_ST ( "add", Iop_AddF64, modrm - 0xC0, 0, False );
4318 break;
4319
sewardj137015d2005-03-27 04:01:15 +00004320 case 0xC8 ... 0xCF: /* FMUL %st(?),%st(0) */
4321 fp_do_op_ST_ST ( "mul", Iop_MulF64, modrm - 0xC8, 0, False );
4322 break;
4323
sewardjd20c8852005-01-20 20:04:07 +00004324//.. #if 1
4325//.. /* Dunno if this is right */
4326//.. case 0xD0 ... 0xD7: /* FCOM %st(?),%st(0) */
4327//.. r_dst = (UInt)modrm - 0xD0;
4328//.. DIP("fcom %%st(0),%%st(%d)\n", r_dst);
4329//.. /* This forces C1 to zero, which isn't right. */
4330//.. put_C3210(
4331//.. binop( Iop_And32,
4332//.. binop(Iop_Shl32,
4333//.. binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
4334//.. mkU8(8)),
4335//.. mkU32(0x4500)
4336//.. ));
4337//.. break;
4338//.. #endif
4339//.. #if 1
4340//.. /* Dunno if this is right */
4341//.. case 0xD8 ... 0xDF: /* FCOMP %st(?),%st(0) */
4342//.. r_dst = (UInt)modrm - 0xD8;
4343//.. DIP("fcomp %%st(0),%%st(%d)\n", r_dst);
4344//.. /* This forces C1 to zero, which isn't right. */
4345//.. put_C3210(
4346//.. binop( Iop_And32,
4347//.. binop(Iop_Shl32,
4348//.. binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
4349//.. mkU8(8)),
4350//.. mkU32(0x4500)
4351//.. ));
4352//.. fp_pop();
4353//.. break;
4354//.. #endif
sewardj137015d2005-03-27 04:01:15 +00004355 case 0xE0 ... 0xE7: /* FSUB %st(?),%st(0) */
4356 fp_do_op_ST_ST ( "sub", Iop_SubF64, modrm - 0xE0, 0, False );
4357 break;
4358
sewardje6939f02005-05-07 01:01:24 +00004359 case 0xE8 ... 0xEF: /* FSUBR %st(?),%st(0) */
4360 fp_do_oprev_ST_ST ( "subr", Iop_SubF64, modrm - 0xE8, 0, False );
4361 break;
sewardj137015d2005-03-27 04:01:15 +00004362
4363 case 0xF0 ... 0xF7: /* FDIV %st(?),%st(0) */
4364 fp_do_op_ST_ST ( "div", Iop_DivF64, modrm - 0xF0, 0, False );
4365 break;
4366
sewardj48a89d82005-05-06 11:50:13 +00004367 case 0xF8 ... 0xFF: /* FDIVR %st(?),%st(0) */
4368 fp_do_oprev_ST_ST ( "divr", Iop_DivF64, modrm - 0xF8, 0, False );
4369 break;
sewardj37d52572005-02-25 14:22:12 +00004370
4371 default:
4372 goto decode_fail;
4373 }
4374 }
4375 }
sewardj8d965312005-02-25 02:48:47 +00004376
4377 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xD9 opcodes +-+-+-+-+-+-+-+ */
sewardj37d52572005-02-25 14:22:12 +00004378 else
sewardj8d965312005-02-25 02:48:47 +00004379 if (first_opcode == 0xD9) {
4380 if (modrm < 0xC0) {
4381
4382 /* bits 5,4,3 are an opcode extension, and the modRM also
4383 specifies an address. */
4384 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
4385 delta += len;
4386
sewardj901ed122005-02-27 13:25:31 +00004387 switch (gregLO3ofRM(modrm)) {
sewardj8d965312005-02-25 02:48:47 +00004388
sewardjc49ce232005-02-25 13:03:03 +00004389 case 0: /* FLD single-real */
4390 DIP("flds %s\n", dis_buf);
4391 fp_push();
4392 put_ST(0, unop(Iop_F32toF64,
4393 loadLE(Ity_F32, mkexpr(addr))));
4394 break;
4395
4396 case 2: /* FST single-real */
4397 DIP("fsts %s\n", dis_buf);
4398 storeLE(mkexpr(addr),
4399 binop(Iop_F64toF32, get_roundingmode(), get_ST(0)));
4400 break;
4401
4402 case 3: /* FSTP single-real */
4403 DIP("fstps %s\n", dis_buf);
4404 storeLE(mkexpr(addr),
4405 binop(Iop_F64toF32, get_roundingmode(), get_ST(0)));
4406 fp_pop();
4407 break;
4408
sewardj4017a3b2005-06-13 12:17:27 +00004409 case 4: { /* FLDENV m28 */
4410 /* Uses dirty helper:
4411 VexEmWarn amd64g_do_FLDENV ( VexGuestX86State*, HWord ) */
4412 IRTemp ew = newTemp(Ity_I32);
4413 IRTemp w64 = newTemp(Ity_I64);
4414 IRDirty* d = unsafeIRDirty_0_N (
4415 0/*regparms*/,
4416 "amd64g_dirtyhelper_FLDENV",
4417 &amd64g_dirtyhelper_FLDENV,
4418 mkIRExprVec_1( mkexpr(addr) )
4419 );
4420 d->needsBBP = True;
4421 d->tmp = w64;
4422 /* declare we're reading memory */
4423 d->mFx = Ifx_Read;
4424 d->mAddr = mkexpr(addr);
4425 d->mSize = 28;
4426
4427 /* declare we're writing guest state */
4428 d->nFxState = 4;
4429
4430 d->fxState[0].fx = Ifx_Write;
4431 d->fxState[0].offset = OFFB_FTOP;
4432 d->fxState[0].size = sizeof(UInt);
4433
4434 d->fxState[1].fx = Ifx_Write;
4435 d->fxState[1].offset = OFFB_FPTAGS;
4436 d->fxState[1].size = 8 * sizeof(UChar);
4437
4438 d->fxState[2].fx = Ifx_Write;
4439 d->fxState[2].offset = OFFB_FPROUND;
4440 d->fxState[2].size = sizeof(ULong);
4441
4442 d->fxState[3].fx = Ifx_Write;
4443 d->fxState[3].offset = OFFB_FC3210;
4444 d->fxState[3].size = sizeof(ULong);
4445
4446 stmt( IRStmt_Dirty(d) );
4447
4448 /* ew contains any emulation warning we may need to
4449 issue. If needed, side-exit to the next insn,
4450 reporting the warning, so that Valgrind's dispatcher
4451 sees the warning. */
4452 assign(ew, unop(Iop_64to32,mkexpr(w64)) );
4453 put_emwarn( mkexpr(ew) );
4454 stmt(
4455 IRStmt_Exit(
4456 binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
4457 Ijk_EmWarn,
sewardj9e6491a2005-07-02 19:24:10 +00004458 IRConst_U64( guest_RIP_bbstart+delta )
sewardj4017a3b2005-06-13 12:17:27 +00004459 )
4460 );
4461
4462 DIP("fldenv %s\n", dis_buf);
4463 break;
4464 }
sewardj5e205372005-05-09 02:57:08 +00004465
4466 case 5: {/* FLDCW */
4467 /* The only thing we observe in the control word is the
4468 rounding mode. Therefore, pass the 16-bit value
4469 (x87 native-format control word) to a clean helper,
4470 getting back a 64-bit value, the lower half of which
4471 is the FPROUND value to store, and the upper half of
4472 which is the emulation-warning token which may be
4473 generated.
4474 */
4475 /* ULong amd64h_check_fldcw ( ULong ); */
4476 IRTemp t64 = newTemp(Ity_I64);
4477 IRTemp ew = newTemp(Ity_I32);
4478 DIP("fldcw %s\n", dis_buf);
4479 assign( t64, mkIRExprCCall(
4480 Ity_I64, 0/*regparms*/,
4481 "amd64g_check_fldcw",
4482 &amd64g_check_fldcw,
4483 mkIRExprVec_1(
4484 unop( Iop_16Uto64,
4485 loadLE(Ity_I16, mkexpr(addr)))
4486 )
4487 )
4488 );
4489
4490 put_fpround( unop(Iop_64to32, mkexpr(t64)) );
4491 assign( ew, unop(Iop_64HIto32, mkexpr(t64) ) );
4492 put_emwarn( mkexpr(ew) );
4493 /* Finally, if an emulation warning was reported,
4494 side-exit to the next insn, reporting the warning,
4495 so that Valgrind's dispatcher sees the warning. */
4496 stmt(
4497 IRStmt_Exit(
4498 binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
4499 Ijk_EmWarn,
sewardj9e6491a2005-07-02 19:24:10 +00004500 IRConst_U64( guest_RIP_bbstart+delta )
sewardj5e205372005-05-09 02:57:08 +00004501 )
4502 );
4503 break;
4504 }
4505
sewardj4017a3b2005-06-13 12:17:27 +00004506 case 6: { /* FNSTENV m28 */
4507 /* Uses dirty helper:
4508 void amd64g_do_FSTENV ( VexGuestAMD64State*, HWord ) */
4509 IRDirty* d = unsafeIRDirty_0_N (
4510 0/*regparms*/,
4511 "amd64g_dirtyhelper_FSTENV",
4512 &amd64g_dirtyhelper_FSTENV,
4513 mkIRExprVec_1( mkexpr(addr) )
4514 );
4515 d->needsBBP = True;
4516 /* declare we're writing memory */
4517 d->mFx = Ifx_Write;
4518 d->mAddr = mkexpr(addr);
4519 d->mSize = 28;
4520
4521 /* declare we're reading guest state */
4522 d->nFxState = 4;
4523
4524 d->fxState[0].fx = Ifx_Read;
4525 d->fxState[0].offset = OFFB_FTOP;
4526 d->fxState[0].size = sizeof(UInt);
4527
4528 d->fxState[1].fx = Ifx_Read;
4529 d->fxState[1].offset = OFFB_FPTAGS;
4530 d->fxState[1].size = 8 * sizeof(UChar);
4531
4532 d->fxState[2].fx = Ifx_Read;
4533 d->fxState[2].offset = OFFB_FPROUND;
4534 d->fxState[2].size = sizeof(ULong);
4535
4536 d->fxState[3].fx = Ifx_Read;
4537 d->fxState[3].offset = OFFB_FC3210;
4538 d->fxState[3].size = sizeof(ULong);
4539
4540 stmt( IRStmt_Dirty(d) );
4541
4542 DIP("fnstenv %s\n", dis_buf);
4543 break;
4544 }
sewardj5e205372005-05-09 02:57:08 +00004545
4546 case 7: /* FNSTCW */
4547 /* Fake up a native x87 FPU control word. The only
4548 thing it depends on is FPROUND[1:0], so call a clean
4549 helper to cook it up. */
sewardj4017a3b2005-06-13 12:17:27 +00004550 /* ULong amd64g_create_fpucw ( ULong fpround ) */
sewardj5e205372005-05-09 02:57:08 +00004551 DIP("fnstcw %s\n", dis_buf);
4552 storeLE(
4553 mkexpr(addr),
4554 unop( Iop_64to16,
4555 mkIRExprCCall(
4556 Ity_I64, 0/*regp*/,
4557 "amd64g_create_fpucw", &amd64g_create_fpucw,
4558 mkIRExprVec_1( unop(Iop_32Uto64, get_fpround()) )
4559 )
4560 )
4561 );
4562 break;
sewardj8d965312005-02-25 02:48:47 +00004563
4564 default:
sewardj901ed122005-02-27 13:25:31 +00004565 vex_printf("unhandled opc_aux = 0x%2x\n", gregLO3ofRM(modrm));
sewardj8d965312005-02-25 02:48:47 +00004566 vex_printf("first_opcode == 0xD9\n");
4567 goto decode_fail;
4568 }
4569
4570 } else {
4571 delta++;
4572 switch (modrm) {
4573
sewardjc49ce232005-02-25 13:03:03 +00004574 case 0xC0 ... 0xC7: /* FLD %st(?) */
4575 r_src = (UInt)modrm - 0xC0;
sewardj1027dc22005-02-26 01:55:02 +00004576 DIP("fld %%st(%u)\n", r_src);
sewardjc49ce232005-02-25 13:03:03 +00004577 t1 = newTemp(Ity_F64);
4578 assign(t1, get_ST(r_src));
4579 fp_push();
4580 put_ST(0, mkexpr(t1));
4581 break;
sewardj8d965312005-02-25 02:48:47 +00004582
4583 case 0xC8 ... 0xCF: /* FXCH %st(?) */
4584 r_src = (UInt)modrm - 0xC8;
sewardj1027dc22005-02-26 01:55:02 +00004585 DIP("fxch %%st(%u)\n", r_src);
sewardj8d965312005-02-25 02:48:47 +00004586 t1 = newTemp(Ity_F64);
4587 t2 = newTemp(Ity_F64);
4588 assign(t1, get_ST(0));
4589 assign(t2, get_ST(r_src));
4590 put_ST_UNCHECKED(0, mkexpr(t2));
4591 put_ST_UNCHECKED(r_src, mkexpr(t1));
4592 break;
4593
4594 case 0xE0: /* FCHS */
4595 DIP("fchs\n");
4596 put_ST_UNCHECKED(0, unop(Iop_NegF64, get_ST(0)));
4597 break;
4598
sewardj137015d2005-03-27 04:01:15 +00004599 case 0xE1: /* FABS */
4600 DIP("fabs\n");
4601 put_ST_UNCHECKED(0, unop(Iop_AbsF64, get_ST(0)));
4602 break;
4603
sewardj4f9847d2005-07-25 11:58:34 +00004604 case 0xE5: { /* FXAM */
4605 /* This is an interesting one. It examines %st(0),
4606 regardless of whether the tag says it's empty or not.
4607 Here, just pass both the tag (in our format) and the
4608 value (as a double, actually a ULong) to a helper
4609 function. */
4610 IRExpr** args
4611 = mkIRExprVec_2( unop(Iop_8Uto64, get_ST_TAG(0)),
4612 unop(Iop_ReinterpF64asI64,
4613 get_ST_UNCHECKED(0)) );
4614 put_C3210(mkIRExprCCall(
4615 Ity_I64,
4616 0/*regparm*/,
4617 "amd64g_calculate_FXAM", &amd64g_calculate_FXAM,
4618 args
4619 ));
4620 DIP("fxam\n");
4621 break;
4622 }
sewardjc49ce232005-02-25 13:03:03 +00004623
4624 case 0xE8: /* FLD1 */
4625 DIP("fld1\n");
4626 fp_push();
4627 /* put_ST(0, IRExpr_Const(IRConst_F64(1.0))); */
4628 put_ST(0, IRExpr_Const(IRConst_F64i(0x3ff0000000000000ULL)));
4629 break;
4630
sewardj6847d8c2005-05-12 19:21:55 +00004631 case 0xE9: /* FLDL2T */
4632 DIP("fldl2t\n");
4633 fp_push();
4634 /* put_ST(0, IRExpr_Const(IRConst_F64(3.32192809488736234781))); */
4635 put_ST(0, IRExpr_Const(IRConst_F64i(0x400a934f0979a371ULL)));
4636 break;
4637
4638 case 0xEA: /* FLDL2E */
4639 DIP("fldl2e\n");
4640 fp_push();
4641 /* put_ST(0, IRExpr_Const(IRConst_F64(1.44269504088896340739))); */
4642 put_ST(0, IRExpr_Const(IRConst_F64i(0x3ff71547652b82feULL)));
4643 break;
4644
4645 case 0xEB: /* FLDPI */
4646 DIP("fldpi\n");
4647 fp_push();
4648 /* put_ST(0, IRExpr_Const(IRConst_F64(3.14159265358979323851))); */
4649 put_ST(0, IRExpr_Const(IRConst_F64i(0x400921fb54442d18ULL)));
4650 break;
4651
4652 case 0xEC: /* FLDLG2 */
4653 DIP("fldlg2\n");
4654 fp_push();
4655 /* put_ST(0, IRExpr_Const(IRConst_F64(0.301029995663981143))); */
4656 put_ST(0, IRExpr_Const(IRConst_F64i(0x3fd34413509f79ffULL)));
4657 break;
4658
4659 case 0xED: /* FLDLN2 */
4660 DIP("fldln2\n");
4661 fp_push();
4662 /* put_ST(0, IRExpr_Const(IRConst_F64(0.69314718055994530942))); */
4663 put_ST(0, IRExpr_Const(IRConst_F64i(0x3fe62e42fefa39efULL)));
4664 break;
sewardjc49ce232005-02-25 13:03:03 +00004665
4666 case 0xEE: /* FLDZ */
4667 DIP("fldz\n");
4668 fp_push();
4669 /* put_ST(0, IRExpr_Const(IRConst_F64(0.0))); */
4670 put_ST(0, IRExpr_Const(IRConst_F64i(0x0000000000000000ULL)));
4671 break;
4672
sewardj25a85812005-05-08 23:03:48 +00004673 case 0xF0: /* F2XM1 */
4674 DIP("f2xm1\n");
4675 put_ST_UNCHECKED(0, unop(Iop_2xm1F64, get_ST(0)));
4676 break;
4677
4678 case 0xF1: /* FYL2X */
4679 DIP("fyl2x\n");
4680 put_ST_UNCHECKED(1, binop(Iop_Yl2xF64,
4681 get_ST(1), get_ST(0)));
4682 fp_pop();
4683 break;
4684
sewardj5e205372005-05-09 02:57:08 +00004685 case 0xF2: /* FPTAN */
4686 DIP("ftan\n");
4687 put_ST_UNCHECKED(0, unop(Iop_TanF64, get_ST(0)));
4688 fp_push();
4689 put_ST(0, IRExpr_Const(IRConst_F64(1.0)));
4690 clear_C2(); /* HACK */
4691 break;
sewardj25a85812005-05-08 23:03:48 +00004692
4693 case 0xF3: /* FPATAN */
4694 DIP("fpatan\n");
4695 put_ST_UNCHECKED(1, binop(Iop_AtanF64,
4696 get_ST(1), get_ST(0)));
4697 fp_pop();
4698 break;
4699
sewardjd20c8852005-01-20 20:04:07 +00004700//.. case 0xF5: { /* FPREM1 -- IEEE compliant */
4701//.. IRTemp a1 = newTemp(Ity_F64);
4702//.. IRTemp a2 = newTemp(Ity_F64);
4703//.. DIP("fprem1\n");
4704//.. /* Do FPREM1 twice, once to get the remainder, and once
4705//.. to get the C3210 flag values. */
4706//.. assign( a1, get_ST(0) );
4707//.. assign( a2, get_ST(1) );
4708//.. put_ST_UNCHECKED(0, binop(Iop_PRem1F64,
4709//.. mkexpr(a1), mkexpr(a2)));
4710//.. put_C3210( binop(Iop_PRem1C3210F64, mkexpr(a1), mkexpr(a2)) );
4711//.. break;
4712//.. }
sewardj6847d8c2005-05-12 19:21:55 +00004713
4714 case 0xF7: /* FINCSTP */
4715 DIP("fincstp\n");
4716 put_ftop( binop(Iop_Add32, get_ftop(), mkU32(1)) );
4717 break;
4718
sewardjd20c8852005-01-20 20:04:07 +00004719//.. case 0xF8: { /* FPREM -- not IEEE compliant */
4720//.. IRTemp a1 = newTemp(Ity_F64);
4721//.. IRTemp a2 = newTemp(Ity_F64);
4722//.. DIP("fprem\n");
4723//.. /* Do FPREM twice, once to get the remainder, and once
4724//.. to get the C3210 flag values. */
4725//.. assign( a1, get_ST(0) );
4726//.. assign( a2, get_ST(1) );
4727//.. put_ST_UNCHECKED(0, binop(Iop_PRemF64,
4728//.. mkexpr(a1), mkexpr(a2)));
4729//.. put_C3210( binop(Iop_PRemC3210F64, mkexpr(a1), mkexpr(a2)) );
4730//.. break;
4731//.. }
4732//..
sewardj5e205372005-05-09 02:57:08 +00004733 case 0xF9: /* FYL2XP1 */
4734 DIP("fyl2xp1\n");
4735 put_ST_UNCHECKED(1, binop(Iop_Yl2xp1F64,
4736 get_ST(1), get_ST(0)));
4737 fp_pop();
4738 break;
sewardje6939f02005-05-07 01:01:24 +00004739
4740 case 0xFA: /* FSQRT */
4741 DIP("fsqrt\n");
4742 put_ST_UNCHECKED(0, unop(Iop_SqrtF64, get_ST(0)));
4743 break;
4744
sewardj25a85812005-05-08 23:03:48 +00004745 case 0xFB: { /* FSINCOS */
4746 IRTemp a1 = newTemp(Ity_F64);
4747 assign( a1, get_ST(0) );
4748 DIP("fsincos\n");
4749 put_ST_UNCHECKED(0, unop(Iop_SinF64, mkexpr(a1)));
4750 fp_push();
4751 put_ST(0, unop(Iop_CosF64, mkexpr(a1)));
4752 clear_C2(); /* HACK */
4753 break;
4754 }
4755
4756 case 0xFC: /* FRNDINT */
4757 DIP("frndint\n");
4758 put_ST_UNCHECKED(0,
4759 binop(Iop_RoundF64, get_roundingmode(), get_ST(0)) );
4760 break;
4761
4762 case 0xFD: /* FSCALE */
4763 DIP("fscale\n");
4764 put_ST_UNCHECKED(0, binop(Iop_ScaleF64,
4765 get_ST(0), get_ST(1)));
4766 break;
4767
4768 case 0xFE: /* FSIN */
4769 DIP("fsin\n");
4770 put_ST_UNCHECKED(0, unop(Iop_SinF64, get_ST(0)));
4771 clear_C2(); /* HACK */
4772 break;
4773
4774 case 0xFF: /* FCOS */
4775 DIP("fcos\n");
4776 put_ST_UNCHECKED(0, unop(Iop_CosF64, get_ST(0)));
4777 clear_C2(); /* HACK */
4778 break;
sewardj8d965312005-02-25 02:48:47 +00004779
4780 default:
4781 goto decode_fail;
4782 }
4783 }
4784 }
4785
4786 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDA opcodes +-+-+-+-+-+-+-+ */
4787 else
4788 if (first_opcode == 0xDA) {
4789
4790 if (modrm < 0xC0) {
4791
4792 /* bits 5,4,3 are an opcode extension, and the modRM also
4793 specifies an address. */
sewardj6847d8c2005-05-12 19:21:55 +00004794 IROp fop;
4795 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
sewardj8d965312005-02-25 02:48:47 +00004796 delta += len;
sewardj901ed122005-02-27 13:25:31 +00004797 switch (gregLO3ofRM(modrm)) {
sewardj8d965312005-02-25 02:48:47 +00004798
sewardj6847d8c2005-05-12 19:21:55 +00004799 case 0: /* FIADD m32int */ /* ST(0) += m32int */
4800 DIP("fiaddl %s\n", dis_buf);
4801 fop = Iop_AddF64;
4802 goto do_fop_m32;
4803
4804 case 1: /* FIMUL m32int */ /* ST(0) *= m32int */
4805 DIP("fimull %s\n", dis_buf);
4806 fop = Iop_MulF64;
4807 goto do_fop_m32;
4808
4809 case 4: /* FISUB m32int */ /* ST(0) -= m32int */
4810 DIP("fisubl %s\n", dis_buf);
4811 fop = Iop_SubF64;
4812 goto do_fop_m32;
4813
4814 case 5: /* FISUBR m32int */ /* ST(0) = m32int - ST(0) */
4815 DIP("fisubrl %s\n", dis_buf);
4816 fop = Iop_SubF64;
4817 goto do_foprev_m32;
4818
4819 case 6: /* FIDIV m32int */ /* ST(0) /= m32int */
4820 DIP("fisubl %s\n", dis_buf);
4821 fop = Iop_DivF64;
4822 goto do_fop_m32;
4823
4824 case 7: /* FIDIVR m32int */ /* ST(0) = m32int / ST(0) */
4825 DIP("fidivrl %s\n", dis_buf);
4826 fop = Iop_DivF64;
4827 goto do_foprev_m32;
4828
4829 do_fop_m32:
4830 put_ST_UNCHECKED(0,
4831 binop(fop,
4832 get_ST(0),
4833 unop(Iop_I32toF64,
4834 loadLE(Ity_I32, mkexpr(addr)))));
4835 break;
4836
4837 do_foprev_m32:
4838 put_ST_UNCHECKED(0,
4839 binop(fop,
4840 unop(Iop_I32toF64,
4841 loadLE(Ity_I32, mkexpr(addr))),
4842 get_ST(0)));
4843 break;
sewardj8d965312005-02-25 02:48:47 +00004844
4845 default:
sewardj901ed122005-02-27 13:25:31 +00004846 vex_printf("unhandled opc_aux = 0x%2x\n", gregLO3ofRM(modrm));
sewardj8d965312005-02-25 02:48:47 +00004847 vex_printf("first_opcode == 0xDA\n");
4848 goto decode_fail;
4849 }
4850
4851 } else {
4852
4853 delta++;
4854 switch (modrm) {
4855
sewardj48a89d82005-05-06 11:50:13 +00004856 case 0xC0 ... 0xC7: /* FCMOVB ST(i), ST(0) */
4857 r_src = (UInt)modrm - 0xC0;
sewardjca673ab2005-05-11 10:03:08 +00004858 DIP("fcmovb %%st(%u), %%st(0)\n", r_src);
sewardj48a89d82005-05-06 11:50:13 +00004859 put_ST_UNCHECKED(0,
4860 IRExpr_Mux0X(
4861 unop(Iop_1Uto8,
4862 mk_amd64g_calculate_condition(AMD64CondB)),
4863 get_ST(0), get_ST(r_src)) );
4864 break;
sewardj8d965312005-02-25 02:48:47 +00004865
4866 case 0xC8 ... 0xCF: /* FCMOVE(Z) ST(i), ST(0) */
4867 r_src = (UInt)modrm - 0xC8;
sewardj1027dc22005-02-26 01:55:02 +00004868 DIP("fcmovz %%st(%u), %%st(0)\n", r_src);
sewardj8d965312005-02-25 02:48:47 +00004869 put_ST_UNCHECKED(0,
4870 IRExpr_Mux0X(
4871 unop(Iop_1Uto8,
4872 mk_amd64g_calculate_condition(AMD64CondZ)),
4873 get_ST(0), get_ST(r_src)) );
4874 break;
4875
sewardj37d52572005-02-25 14:22:12 +00004876 case 0xD0 ... 0xD7: /* FCMOVBE ST(i), ST(0) */
4877 r_src = (UInt)modrm - 0xD0;
sewardj1027dc22005-02-26 01:55:02 +00004878 DIP("fcmovbe %%st(%u), %%st(0)\n", r_src);
sewardj37d52572005-02-25 14:22:12 +00004879 put_ST_UNCHECKED(0,
4880 IRExpr_Mux0X(
4881 unop(Iop_1Uto8,
4882 mk_amd64g_calculate_condition(AMD64CondBE)),
4883 get_ST(0), get_ST(r_src)) );
4884 break;
4885
sewardj25a85812005-05-08 23:03:48 +00004886 case 0xD8 ... 0xDF: /* FCMOVU ST(i), ST(0) */
4887 r_src = (UInt)modrm - 0xD8;
4888 DIP("fcmovu %%st(%u), %%st(0)\n", r_src);
4889 put_ST_UNCHECKED(0,
4890 IRExpr_Mux0X(
4891 unop(Iop_1Uto8,
4892 mk_amd64g_calculate_condition(AMD64CondP)),
4893 get_ST(0), get_ST(r_src)) );
4894 break;
4895
sewardjd20c8852005-01-20 20:04:07 +00004896//.. case 0xE9: /* FUCOMPP %st(0),%st(1) */
4897//.. DIP("fucompp %%st(0),%%st(1)\n");
4898//.. /* This forces C1 to zero, which isn't right. */
4899//.. put_C3210(
4900//.. binop( Iop_And32,
4901//.. binop(Iop_Shl32,
4902//.. binop(Iop_CmpF64, get_ST(0), get_ST(1)),
4903//.. mkU8(8)),
4904//.. mkU32(0x4500)
4905//.. ));
4906//.. fp_pop();
4907//.. fp_pop();
4908//.. break;
sewardj8d965312005-02-25 02:48:47 +00004909
4910 default:
4911 goto decode_fail;
4912 }
4913
4914 }
4915 }
4916
sewardjc49ce232005-02-25 13:03:03 +00004917 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDB opcodes +-+-+-+-+-+-+-+ */
4918 else
4919 if (first_opcode == 0xDB) {
4920 if (modrm < 0xC0) {
4921
4922 /* bits 5,4,3 are an opcode extension, and the modRM also
4923 specifies an address. */
4924 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
4925 delta += len;
4926
sewardj901ed122005-02-27 13:25:31 +00004927 switch (gregLO3ofRM(modrm)) {
sewardjc49ce232005-02-25 13:03:03 +00004928
sewardj5cc00ff2005-03-27 04:48:32 +00004929 case 0: /* FILD m32int */
4930 DIP("fildl %s\n", dis_buf);
4931 fp_push();
4932 put_ST(0, unop(Iop_I32toF64,
4933 loadLE(Ity_I32, mkexpr(addr))));
4934 break;
4935
sewardj6847d8c2005-05-12 19:21:55 +00004936 case 2: /* FIST m32 */
4937 DIP("fistl %s\n", dis_buf);
4938 storeLE( mkexpr(addr),
4939 binop(Iop_F64toI32, get_roundingmode(), get_ST(0)) );
4940 break;
sewardj37d52572005-02-25 14:22:12 +00004941
4942 case 3: /* FISTP m32 */
4943 DIP("fistpl %s\n", dis_buf);
4944 storeLE( mkexpr(addr),
4945 binop(Iop_F64toI32, get_roundingmode(), get_ST(0)) );
4946 fp_pop();
4947 break;
4948
sewardj924215b2005-03-26 21:50:31 +00004949 case 5: { /* FLD extended-real */
4950 /* Uses dirty helper:
4951 ULong amd64g_loadF80le ( ULong )
4952 addr holds the address. First, do a dirty call to
4953 get hold of the data. */
4954 IRTemp val = newTemp(Ity_I64);
4955 IRExpr** args = mkIRExprVec_1 ( mkexpr(addr) );
4956
4957 IRDirty* d = unsafeIRDirty_1_N (
4958 val,
4959 0/*regparms*/,
4960 "amd64g_loadF80le", &amd64g_loadF80le,
4961 args
4962 );
4963 /* declare that we're reading memory */
4964 d->mFx = Ifx_Read;
4965 d->mAddr = mkexpr(addr);
4966 d->mSize = 10;
4967
4968 /* execute the dirty call, dumping the result in val. */
4969 stmt( IRStmt_Dirty(d) );
4970 fp_push();
4971 put_ST(0, unop(Iop_ReinterpI64asF64, mkexpr(val)));
4972
4973 DIP("fldt %s\n", dis_buf);
4974 break;
4975 }
4976
4977 case 7: { /* FSTP extended-real */
4978 /* Uses dirty helper:
4979 void amd64g_storeF80le ( ULong addr, ULong data )
4980 */
4981 IRExpr** args
4982 = mkIRExprVec_2( mkexpr(addr),
4983 unop(Iop_ReinterpF64asI64, get_ST(0)) );
4984
4985 IRDirty* d = unsafeIRDirty_0_N (
4986 0/*regparms*/,
4987 "amd64g_storeF80le", &amd64g_storeF80le,
4988 args
4989 );
4990 /* declare we're writing memory */
4991 d->mFx = Ifx_Write;
4992 d->mAddr = mkexpr(addr);
4993 d->mSize = 10;
4994
4995 /* execute the dirty call. */
4996 stmt( IRStmt_Dirty(d) );
4997 fp_pop();
4998
4999 DIP("fstpt\n %s", dis_buf);
5000 break;
5001 }
sewardjc49ce232005-02-25 13:03:03 +00005002
5003 default:
sewardj901ed122005-02-27 13:25:31 +00005004 vex_printf("unhandled opc_aux = 0x%2x\n", gregLO3ofRM(modrm));
sewardjc49ce232005-02-25 13:03:03 +00005005 vex_printf("first_opcode == 0xDB\n");
5006 goto decode_fail;
5007 }
5008
5009 } else {
5010
5011 delta++;
5012 switch (modrm) {
5013
sewardj48a89d82005-05-06 11:50:13 +00005014 case 0xC0 ... 0xC7: /* FCMOVNB ST(i), ST(0) */
5015 r_src = (UInt)modrm - 0xC0;
sewardjca673ab2005-05-11 10:03:08 +00005016 DIP("fcmovnb %%st(%u), %%st(0)\n", r_src);
sewardj48a89d82005-05-06 11:50:13 +00005017 put_ST_UNCHECKED(0,
5018 IRExpr_Mux0X(
5019 unop(Iop_1Uto8,
5020 mk_amd64g_calculate_condition(AMD64CondNB)),
5021 get_ST(0), get_ST(r_src)) );
5022 break;
sewardj924215b2005-03-26 21:50:31 +00005023
5024 case 0xC8 ... 0xCF: /* FCMOVNE(NZ) ST(i), ST(0) */
5025 r_src = (UInt)modrm - 0xC8;
sewardj40e144d2005-03-28 00:46:27 +00005026 DIP("fcmovnz %%st(%u), %%st(0)\n", r_src);
sewardj137015d2005-03-27 04:01:15 +00005027 put_ST_UNCHECKED(
5028 0,
5029 IRExpr_Mux0X(
5030 unop(Iop_1Uto8,
5031 mk_amd64g_calculate_condition(AMD64CondNZ)),
5032 get_ST(0),
5033 get_ST(r_src)
5034 )
5035 );
sewardj924215b2005-03-26 21:50:31 +00005036 break;
5037
sewardj137015d2005-03-27 04:01:15 +00005038 case 0xD0 ... 0xD7: /* FCMOVNBE ST(i), ST(0) */
5039 r_src = (UInt)modrm - 0xD0;
sewardj40e144d2005-03-28 00:46:27 +00005040 DIP("fcmovnbe %%st(%u), %%st(0)\n", r_src);
sewardj137015d2005-03-27 04:01:15 +00005041 put_ST_UNCHECKED(
5042 0,
5043 IRExpr_Mux0X(
5044 unop(Iop_1Uto8,
5045 mk_amd64g_calculate_condition(AMD64CondNBE)),
5046 get_ST(0),
5047 get_ST(r_src)
5048 )
5049 );
5050 break;
5051
sewardj4e1a1e92005-05-25 00:44:13 +00005052 case 0xE2:
5053 DIP("fnclex\n");
5054 break;
5055
sewardjd20c8852005-01-20 20:04:07 +00005056//.. case 0xE3: {
5057//.. /* Uses dirty helper:
5058//.. void x86g_do_FINIT ( VexGuestX86State* ) */
5059//.. IRDirty* d = unsafeIRDirty_0_N (
5060//.. 0/*regparms*/,
5061//.. "x86g_dirtyhelper_FINIT",
5062//.. &x86g_dirtyhelper_FINIT,
5063//.. mkIRExprVec_0()
5064//.. );
5065//.. d->needsBBP = True;
5066//..
5067//.. /* declare we're writing guest state */
5068//.. d->nFxState = 5;
5069//..
5070//.. d->fxState[0].fx = Ifx_Write;
5071//.. d->fxState[0].offset = OFFB_FTOP;
5072//.. d->fxState[0].size = sizeof(UInt);
5073//..
5074//.. d->fxState[1].fx = Ifx_Write;
5075//.. d->fxState[1].offset = OFFB_FPREGS;
5076//.. d->fxState[1].size = 8 * sizeof(ULong);
5077//..
5078//.. d->fxState[2].fx = Ifx_Write;
5079//.. d->fxState[2].offset = OFFB_FPTAGS;
5080//.. d->fxState[2].size = 8 * sizeof(UChar);
5081//..
5082//.. d->fxState[3].fx = Ifx_Write;
5083//.. d->fxState[3].offset = OFFB_FPROUND;
5084//.. d->fxState[3].size = sizeof(UInt);
5085//..
5086//.. d->fxState[4].fx = Ifx_Write;
5087//.. d->fxState[4].offset = OFFB_FC3210;
5088//.. d->fxState[4].size = sizeof(UInt);
5089//..
5090//.. stmt( IRStmt_Dirty(d) );
5091//..
5092//.. DIP("fninit\n");
5093//.. break;
5094//.. }
sewardjc49ce232005-02-25 13:03:03 +00005095
5096 case 0xE8 ... 0xEF: /* FUCOMI %st(0),%st(?) */
5097 fp_do_ucomi_ST0_STi( (UInt)modrm - 0xE8, False );
5098 break;
5099
sewardj48a89d82005-05-06 11:50:13 +00005100 case 0xF0 ... 0xF7: /* FCOMI %st(0),%st(?) */
5101 fp_do_ucomi_ST0_STi( (UInt)modrm - 0xF0, False );
5102 break;
sewardjc49ce232005-02-25 13:03:03 +00005103
5104 default:
5105 goto decode_fail;
5106 }
5107 }
5108 }
5109
sewardj137015d2005-03-27 04:01:15 +00005110 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDC opcodes +-+-+-+-+-+-+-+ */
5111 else
5112 if (first_opcode == 0xDC) {
5113 if (modrm < 0xC0) {
5114
sewardj434e0692005-03-27 17:36:08 +00005115 /* bits 5,4,3 are an opcode extension, and the modRM also
5116 specifies an address. */
5117 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
5118 delta += len;
5119
5120 switch (gregLO3ofRM(modrm)) {
5121
sewardje6939f02005-05-07 01:01:24 +00005122 case 0: /* FADD double-real */
5123 fp_do_op_mem_ST_0 ( addr, "add", dis_buf, Iop_AddF64, True );
5124 break;
5125
5126 case 1: /* FMUL double-real */
5127 fp_do_op_mem_ST_0 ( addr, "mul", dis_buf, Iop_MulF64, True );
5128 break;
5129
sewardjd20c8852005-01-20 20:04:07 +00005130//.. case 2: /* FCOM double-real */
5131//.. DIP("fcoml %s\n", dis_buf);
5132//.. /* This forces C1 to zero, which isn't right. */
5133//.. put_C3210(
5134//.. binop( Iop_And32,
5135//.. binop(Iop_Shl32,
5136//.. binop(Iop_CmpF64,
5137//.. get_ST(0),
5138//.. loadLE(Ity_F64,mkexpr(addr))),
5139//.. mkU8(8)),
5140//.. mkU32(0x4500)
5141//.. ));
5142//.. break;
5143//..
5144//.. case 3: /* FCOMP double-real */
5145//.. DIP("fcompl %s\n", dis_buf);
5146//.. /* This forces C1 to zero, which isn't right. */
5147//.. put_C3210(
5148//.. binop( Iop_And32,
5149//.. binop(Iop_Shl32,
5150//.. binop(Iop_CmpF64,
5151//.. get_ST(0),
5152//.. loadLE(Ity_F64,mkexpr(addr))),
5153//.. mkU8(8)),
5154//.. mkU32(0x4500)
5155//.. ));
5156//.. fp_pop();
5157//.. break;
sewardje6939f02005-05-07 01:01:24 +00005158
5159 case 4: /* FSUB double-real */
5160 fp_do_op_mem_ST_0 ( addr, "sub", dis_buf, Iop_SubF64, True );
5161 break;
sewardj434e0692005-03-27 17:36:08 +00005162
5163 case 5: /* FSUBR double-real */
5164 fp_do_oprev_mem_ST_0 ( addr, "subr", dis_buf, Iop_SubF64, True );
5165 break;
5166
sewardje6939f02005-05-07 01:01:24 +00005167 case 6: /* FDIV double-real */
5168 fp_do_op_mem_ST_0 ( addr, "div", dis_buf, Iop_DivF64, True );
5169 break;
5170
5171 case 7: /* FDIVR double-real */
5172 fp_do_oprev_mem_ST_0 ( addr, "divr", dis_buf, Iop_DivF64, True );
5173 break;
sewardj434e0692005-03-27 17:36:08 +00005174
5175 default:
5176 vex_printf("unhandled opc_aux = 0x%2x\n", gregLO3ofRM(modrm));
5177 vex_printf("first_opcode == 0xDC\n");
5178 goto decode_fail;
5179 }
sewardj137015d2005-03-27 04:01:15 +00005180
5181 } else {
5182
5183 delta++;
5184 switch (modrm) {
5185
5186 case 0xC0 ... 0xC7: /* FADD %st(0),%st(?) */
5187 fp_do_op_ST_ST ( "add", Iop_AddF64, 0, modrm - 0xC0, False );
5188 break;
5189
sewardj7bc00082005-03-27 05:08:32 +00005190 case 0xC8 ... 0xCF: /* FMUL %st(0),%st(?) */
5191 fp_do_op_ST_ST ( "mul", Iop_MulF64, 0, modrm - 0xC8, False );
5192 break;
5193
sewardj434e0692005-03-27 17:36:08 +00005194 case 0xE0 ... 0xE7: /* FSUBR %st(0),%st(?) */
5195 fp_do_oprev_ST_ST ( "subr", Iop_SubF64, 0, modrm - 0xE0, False );
5196 break;
5197
sewardje6939f02005-05-07 01:01:24 +00005198 case 0xE8 ... 0xEF: /* FSUB %st(0),%st(?) */
5199 fp_do_op_ST_ST ( "sub", Iop_SubF64, 0, modrm - 0xE8, False );
5200 break;
5201
5202 case 0xF0 ... 0xF7: /* FDIVR %st(0),%st(?) */
5203 fp_do_oprev_ST_ST ( "divr", Iop_DivF64, 0, modrm - 0xF0, False );
5204 break;
sewardj137015d2005-03-27 04:01:15 +00005205
5206 case 0xF8 ... 0xFF: /* FDIV %st(0),%st(?) */
5207 fp_do_op_ST_ST ( "div", Iop_DivF64, 0, modrm - 0xF8, False );
5208 break;
5209
5210 default:
5211 goto decode_fail;
5212 }
5213
5214 }
5215 }
sewardj8d965312005-02-25 02:48:47 +00005216
5217 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDD opcodes +-+-+-+-+-+-+-+ */
5218 else
5219 if (first_opcode == 0xDD) {
5220
5221 if (modrm < 0xC0) {
5222
5223 /* bits 5,4,3 are an opcode extension, and the modRM also
5224 specifies an address. */
5225 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
5226 delta += len;
5227
sewardj901ed122005-02-27 13:25:31 +00005228 switch (gregLO3ofRM(modrm)) {
sewardj8d965312005-02-25 02:48:47 +00005229
5230 case 0: /* FLD double-real */
5231 DIP("fldl %s\n", dis_buf);
5232 fp_push();
sewardjaf1ceca2005-06-30 23:31:27 +00005233 put_ST(0, loadLE(Ity_F64, mkexpr(addr)));
sewardj8d965312005-02-25 02:48:47 +00005234 break;
5235
sewardjc49ce232005-02-25 13:03:03 +00005236 case 2: /* FST double-real */
5237 DIP("fstl %s\n", dis_buf);
5238 storeLE(mkexpr(addr), get_ST(0));
5239 break;
sewardj8d965312005-02-25 02:48:47 +00005240
5241 case 3: /* FSTP double-real */
5242 DIP("fstpl %s\n", dis_buf);
5243 storeLE(mkexpr(addr), get_ST(0));
5244 fp_pop();
5245 break;
5246
sewardjd20c8852005-01-20 20:04:07 +00005247//.. case 4: { /* FRSTOR m108 */
5248//.. /* Uses dirty helper:
5249//.. VexEmWarn x86g_do_FRSTOR ( VexGuestX86State*, Addr32 ) */
5250//.. IRTemp ew = newTemp(Ity_I32);
5251//.. IRDirty* d = unsafeIRDirty_0_N (
5252//.. 0/*regparms*/,
5253//.. "x86g_dirtyhelper_FRSTOR",
5254//.. &x86g_dirtyhelper_FRSTOR,
5255//.. mkIRExprVec_1( mkexpr(addr) )
5256//.. );
5257//.. d->needsBBP = True;
5258//.. d->tmp = ew;
5259//.. /* declare we're reading memory */
5260//.. d->mFx = Ifx_Read;
5261//.. d->mAddr = mkexpr(addr);
5262//.. d->mSize = 108;
5263//..
5264//.. /* declare we're writing guest state */
5265//.. d->nFxState = 5;
5266//..
5267//.. d->fxState[0].fx = Ifx_Write;
5268//.. d->fxState[0].offset = OFFB_FTOP;
5269//.. d->fxState[0].size = sizeof(UInt);
5270//..
5271//.. d->fxState[1].fx = Ifx_Write;
5272//.. d->fxState[1].offset = OFFB_FPREGS;
5273//.. d->fxState[1].size = 8 * sizeof(ULong);
5274//..
5275//.. d->fxState[2].fx = Ifx_Write;
5276//.. d->fxState[2].offset = OFFB_FPTAGS;
5277//.. d->fxState[2].size = 8 * sizeof(UChar);
5278//..
5279//.. d->fxState[3].fx = Ifx_Write;
5280//.. d->fxState[3].offset = OFFB_FPROUND;
5281//.. d->fxState[3].size = sizeof(UInt);
5282//..
5283//.. d->fxState[4].fx = Ifx_Write;
5284//.. d->fxState[4].offset = OFFB_FC3210;
5285//.. d->fxState[4].size = sizeof(UInt);
5286//..
5287//.. stmt( IRStmt_Dirty(d) );
5288//..
5289//.. /* ew contains any emulation warning we may need to
5290//.. issue. If needed, side-exit to the next insn,
5291//.. reporting the warning, so that Valgrind's dispatcher
5292//.. sees the warning. */
5293//.. put_emwarn( mkexpr(ew) );
5294//.. stmt(
5295//.. IRStmt_Exit(
5296//.. binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
5297//.. Ijk_EmWarn,
5298//.. IRConst_U32( ((Addr32)guest_eip_bbstart)+delta)
5299//.. )
5300//.. );
5301//..
5302//.. DIP("frstor %s\n", dis_buf);
5303//.. break;
5304//.. }
5305//..
5306//.. case 6: { /* FNSAVE m108 */
5307//.. /* Uses dirty helper:
5308//.. void x86g_do_FSAVE ( VexGuestX86State*, UInt ) */
5309//.. IRDirty* d = unsafeIRDirty_0_N (
5310//.. 0/*regparms*/,
5311//.. "x86g_dirtyhelper_FSAVE",
5312//.. &x86g_dirtyhelper_FSAVE,
5313//.. mkIRExprVec_1( mkexpr(addr) )
5314//.. );
5315//.. d->needsBBP = True;
5316//.. /* declare we're writing memory */
5317//.. d->mFx = Ifx_Write;
5318//.. d->mAddr = mkexpr(addr);
5319//.. d->mSize = 108;
5320//..
5321//.. /* declare we're reading guest state */
5322//.. d->nFxState = 5;
5323//..
5324//.. d->fxState[0].fx = Ifx_Read;
5325//.. d->fxState[0].offset = OFFB_FTOP;
5326//.. d->fxState[0].size = sizeof(UInt);
5327//..
5328//.. d->fxState[1].fx = Ifx_Read;
5329//.. d->fxState[1].offset = OFFB_FPREGS;
5330//.. d->fxState[1].size = 8 * sizeof(ULong);
5331//..
5332//.. d->fxState[2].fx = Ifx_Read;
5333//.. d->fxState[2].offset = OFFB_FPTAGS;
5334//.. d->fxState[2].size = 8 * sizeof(UChar);
5335//..
5336//.. d->fxState[3].fx = Ifx_Read;
5337//.. d->fxState[3].offset = OFFB_FPROUND;
5338//.. d->fxState[3].size = sizeof(UInt);
5339//..
5340//.. d->fxState[4].fx = Ifx_Read;
5341//.. d->fxState[4].offset = OFFB_FC3210;
5342//.. d->fxState[4].size = sizeof(UInt);
5343//..
5344//.. stmt( IRStmt_Dirty(d) );
5345//..
5346//.. DIP("fnsave %s\n", dis_buf);
5347//.. break;
5348//.. }
sewardj8d965312005-02-25 02:48:47 +00005349
5350 default:
sewardj901ed122005-02-27 13:25:31 +00005351 vex_printf("unhandled opc_aux = 0x%2x\n", gregLO3ofRM(modrm));
sewardj8d965312005-02-25 02:48:47 +00005352 vex_printf("first_opcode == 0xDD\n");
5353 goto decode_fail;
5354 }
5355 } else {
5356 delta++;
5357 switch (modrm) {
5358
sewardj6847d8c2005-05-12 19:21:55 +00005359 case 0xC0 ... 0xC7: /* FFREE %st(?) */
5360 r_dst = (UInt)modrm - 0xC0;
5361 DIP("ffree %%st(%u)\n", r_dst);
5362 put_ST_TAG ( r_dst, mkU8(0) );
5363 break;
5364
sewardjd20c8852005-01-20 20:04:07 +00005365//.. case 0xD0 ... 0xD7: /* FST %st(0),%st(?) */
5366//.. r_dst = (UInt)modrm - 0xD0;
5367//.. DIP("fst %%st(0),%%st(%d)\n", r_dst);
5368//.. /* P4 manual says: "If the destination operand is a
5369//.. non-empty register, the invalid-operation exception
5370//.. is not generated. Hence put_ST_UNCHECKED. */
5371//.. put_ST_UNCHECKED(r_dst, get_ST(0));
5372//.. break;
sewardj8d965312005-02-25 02:48:47 +00005373
5374 case 0xD8 ... 0xDF: /* FSTP %st(0),%st(?) */
5375 r_dst = (UInt)modrm - 0xD8;
sewardj1027dc22005-02-26 01:55:02 +00005376 DIP("fstp %%st(0),%%st(%u)\n", r_dst);
sewardj8d965312005-02-25 02:48:47 +00005377 /* P4 manual says: "If the destination operand is a
5378 non-empty register, the invalid-operation exception
5379 is not generated. Hence put_ST_UNCHECKED. */
5380 put_ST_UNCHECKED(r_dst, get_ST(0));
5381 fp_pop();
5382 break;
5383
sewardjd20c8852005-01-20 20:04:07 +00005384//.. case 0xE0 ... 0xE7: /* FUCOM %st(0),%st(?) */
5385//.. r_dst = (UInt)modrm - 0xE0;
5386//.. DIP("fucom %%st(0),%%st(%d)\n", r_dst);
5387//.. /* This forces C1 to zero, which isn't right. */
5388//.. put_C3210(
5389//.. binop( Iop_And32,
5390//.. binop(Iop_Shl32,
5391//.. binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
5392//.. mkU8(8)),
5393//.. mkU32(0x4500)
5394//.. ));
5395//.. break;
5396//..
5397//.. case 0xE8 ... 0xEF: /* FUCOMP %st(0),%st(?) */
5398//.. r_dst = (UInt)modrm - 0xE8;
5399//.. DIP("fucomp %%st(0),%%st(%d)\n", r_dst);
5400//.. /* This forces C1 to zero, which isn't right. */
5401//.. put_C3210(
5402//.. binop( Iop_And32,
5403//.. binop(Iop_Shl32,
5404//.. binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
5405//.. mkU8(8)),
5406//.. mkU32(0x4500)
5407//.. ));
5408//.. fp_pop();
5409//.. break;
sewardj8d965312005-02-25 02:48:47 +00005410
5411 default:
5412 goto decode_fail;
5413 }
5414 }
5415 }
5416
sewardj137015d2005-03-27 04:01:15 +00005417 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDE opcodes +-+-+-+-+-+-+-+ */
5418 else
5419 if (first_opcode == 0xDE) {
5420
5421 if (modrm < 0xC0) {
5422
sewardj6847d8c2005-05-12 19:21:55 +00005423 /* bits 5,4,3 are an opcode extension, and the modRM also
5424 specifies an address. */
5425 IROp fop;
5426 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
5427 delta += len;
5428
5429 switch (gregLO3ofRM(modrm)) {
5430
5431 case 0: /* FIADD m16int */ /* ST(0) += m16int */
5432 DIP("fiaddw %s\n", dis_buf);
5433 fop = Iop_AddF64;
5434 goto do_fop_m16;
5435
5436 case 1: /* FIMUL m16int */ /* ST(0) *= m16int */
5437 DIP("fimulw %s\n", dis_buf);
5438 fop = Iop_MulF64;
5439 goto do_fop_m16;
5440
5441 case 4: /* FISUB m16int */ /* ST(0) -= m16int */
5442 DIP("fisubw %s\n", dis_buf);
5443 fop = Iop_SubF64;
5444 goto do_fop_m16;
5445
5446 case 5: /* FISUBR m16int */ /* ST(0) = m16int - ST(0) */
5447 DIP("fisubrw %s\n", dis_buf);
5448 fop = Iop_SubF64;
5449 goto do_foprev_m16;
5450
5451 case 6: /* FIDIV m16int */ /* ST(0) /= m16int */
5452 DIP("fisubw %s\n", dis_buf);
5453 fop = Iop_DivF64;
5454 goto do_fop_m16;
5455
5456 case 7: /* FIDIVR m16int */ /* ST(0) = m16int / ST(0) */
5457 DIP("fidivrw %s\n", dis_buf);
5458 fop = Iop_DivF64;
5459 goto do_foprev_m16;
5460
5461 do_fop_m16:
5462 put_ST_UNCHECKED(0,
5463 binop(fop,
5464 get_ST(0),
5465 unop(Iop_I32toF64,
5466 unop(Iop_16Sto32,
5467 loadLE(Ity_I16, mkexpr(addr))))));
5468 break;
5469
5470 do_foprev_m16:
5471 put_ST_UNCHECKED(0,
5472 binop(fop,
5473 unop(Iop_I32toF64,
5474 unop(Iop_16Sto32,
5475 loadLE(Ity_I16, mkexpr(addr)))),
5476 get_ST(0)));
5477 break;
5478
5479 default:
5480 vex_printf("unhandled opc_aux = 0x%2x\n", gregLO3ofRM(modrm));
5481 vex_printf("first_opcode == 0xDE\n");
5482 goto decode_fail;
5483 }
sewardj137015d2005-03-27 04:01:15 +00005484
5485 } else {
5486
5487 delta++;
5488 switch (modrm) {
5489
5490 case 0xC0 ... 0xC7: /* FADDP %st(0),%st(?) */
5491 fp_do_op_ST_ST ( "add", Iop_AddF64, 0, modrm - 0xC0, True );
5492 break;
5493
5494 case 0xC8 ... 0xCF: /* FMULP %st(0),%st(?) */
5495 fp_do_op_ST_ST ( "mul", Iop_MulF64, 0, modrm - 0xC8, True );
5496 break;
5497
sewardjd20c8852005-01-20 20:04:07 +00005498//.. case 0xD9: /* FCOMPP %st(0),%st(1) */
5499//.. DIP("fuompp %%st(0),%%st(1)\n");
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(1)),
5505//.. mkU8(8)),
5506//.. mkU32(0x4500)
5507//.. ));
5508//.. fp_pop();
5509//.. fp_pop();
5510//.. break;
sewardj137015d2005-03-27 04:01:15 +00005511
5512 case 0xE0 ... 0xE7: /* FSUBRP %st(0),%st(?) */
5513 fp_do_oprev_ST_ST ( "subr", Iop_SubF64, 0, modrm - 0xE0, True );
5514 break;
5515
5516 case 0xE8 ... 0xEF: /* FSUBP %st(0),%st(?) */
5517 fp_do_op_ST_ST ( "sub", Iop_SubF64, 0, modrm - 0xE8, True );
5518 break;
5519
5520 case 0xF0 ... 0xF7: /* FDIVRP %st(0),%st(?) */
5521 fp_do_oprev_ST_ST ( "divr", Iop_DivF64, 0, modrm - 0xF0, True );
5522 break;
5523
5524 case 0xF8 ... 0xFF: /* FDIVP %st(0),%st(?) */
5525 fp_do_op_ST_ST ( "div", Iop_DivF64, 0, modrm - 0xF8, True );
5526 break;
5527
5528 default:
5529 goto decode_fail;
5530 }
5531
5532 }
5533 }
sewardjc49ce232005-02-25 13:03:03 +00005534
5535 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDF opcodes +-+-+-+-+-+-+-+ */
5536 else
5537 if (first_opcode == 0xDF) {
5538
5539 if (modrm < 0xC0) {
5540
5541 /* bits 5,4,3 are an opcode extension, and the modRM also
5542 specifies an address. */
5543 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
5544 delta += len;
5545
sewardj901ed122005-02-27 13:25:31 +00005546 switch (gregLO3ofRM(modrm)) {
sewardjc49ce232005-02-25 13:03:03 +00005547
sewardj434e0692005-03-27 17:36:08 +00005548 case 0: /* FILD m16int */
5549 DIP("fildw %s\n", dis_buf);
5550 fp_push();
5551 put_ST(0, unop(Iop_I32toF64,
5552 unop(Iop_16Sto32,
5553 loadLE(Ity_I16, mkexpr(addr)))));
5554 break;
5555
sewardjd20c8852005-01-20 20:04:07 +00005556//.. case 2: /* FIST m16 */
5557//.. DIP("fistp %s\n", dis_buf);
5558//.. storeLE( mkexpr(addr),
5559//.. binop(Iop_F64toI16, get_roundingmode(), get_ST(0)) );
5560//.. break;
sewardj6847d8c2005-05-12 19:21:55 +00005561
sewardjd20c8852005-01-20 20:04:07 +00005562//.. case 3: /* FISTP m16 */
5563//.. DIP("fistps %s\n", dis_buf);
5564//.. storeLE( mkexpr(addr),
5565//.. binop(Iop_F64toI16, get_roundingmode(), get_ST(0)) );
5566//.. fp_pop();
5567//.. break;
sewardj37d52572005-02-25 14:22:12 +00005568
5569 case 5: /* FILD m64 */
5570 DIP("fildll %s\n", dis_buf);
5571 fp_push();
5572 put_ST(0, binop(Iop_I64toF64,
5573 get_roundingmode(),
5574 loadLE(Ity_I64, mkexpr(addr))));
5575 break;
5576
sewardj6847d8c2005-05-12 19:21:55 +00005577 case 7: /* FISTP m64 */
5578 DIP("fistpll %s\n", dis_buf);
5579 storeLE( mkexpr(addr),
5580 binop(Iop_F64toI64, get_roundingmode(), get_ST(0)) );
5581 fp_pop();
5582 break;
sewardjc49ce232005-02-25 13:03:03 +00005583
5584 default:
sewardj901ed122005-02-27 13:25:31 +00005585 vex_printf("unhandled opc_aux = 0x%2x\n", gregLO3ofRM(modrm));
sewardjc49ce232005-02-25 13:03:03 +00005586 vex_printf("first_opcode == 0xDF\n");
5587 goto decode_fail;
5588 }
5589
5590 } else {
5591
5592 delta++;
5593 switch (modrm) {
5594
5595 case 0xC0: /* FFREEP %st(0) */
5596 DIP("ffreep %%st(%d)\n", 0);
5597 put_ST_TAG ( 0, mkU8(0) );
5598 fp_pop();
5599 break;
5600
sewardj4f9847d2005-07-25 11:58:34 +00005601 case 0xE0: /* FNSTSW %ax */
5602 DIP("fnstsw %%ax\n");
5603 /* Invent a plausible-looking FPU status word value and
5604 dump it in %AX:
5605 ((ftop & 7) << 11) | (c3210 & 0x4700)
5606 */
5607 putIRegRAX(
5608 2,
5609 unop(Iop_32to16,
5610 binop(Iop_Or32,
5611 binop(Iop_Shl32,
5612 binop(Iop_And32, get_ftop(), mkU32(7)),
5613 mkU8(11)),
5614 binop(Iop_And32,
5615 unop(Iop_64to32, get_C3210()),
5616 mkU32(0x4700))
5617 )));
5618 break;
sewardj924215b2005-03-26 21:50:31 +00005619
5620 case 0xE8 ... 0xEF: /* FUCOMIP %st(0),%st(?) */
5621 fp_do_ucomi_ST0_STi( (UInt)modrm - 0xE8, True );
5622 break;
5623
sewardj48a89d82005-05-06 11:50:13 +00005624 case 0xF0 ... 0xF7: /* FCOMIP %st(0),%st(?) */
5625 /* not really right since COMIP != UCOMIP */
5626 fp_do_ucomi_ST0_STi( (UInt)modrm - 0xF0, True );
5627 break;
sewardjc49ce232005-02-25 13:03:03 +00005628
5629 default:
5630 goto decode_fail;
5631 }
5632 }
5633
5634 }
sewardj8d965312005-02-25 02:48:47 +00005635
5636 else
sewardj137015d2005-03-27 04:01:15 +00005637 goto decode_fail;
sewardj8d965312005-02-25 02:48:47 +00005638
5639 *decode_ok = True;
5640 return delta;
5641
5642 decode_fail:
5643 *decode_ok = False;
5644 return delta;
5645}
5646
5647
sewardj8711f662005-05-09 17:52:56 +00005648/*------------------------------------------------------------*/
5649/*--- ---*/
5650/*--- MMX INSTRUCTIONS ---*/
5651/*--- ---*/
5652/*------------------------------------------------------------*/
5653
5654/* Effect of MMX insns on x87 FPU state (table 11-2 of
5655 IA32 arch manual, volume 3):
5656
5657 Read from, or write to MMX register (viz, any insn except EMMS):
5658 * All tags set to Valid (non-empty) -- FPTAGS[i] := nonzero
5659 * FP stack pointer set to zero
5660
5661 EMMS:
5662 * All tags set to Invalid (empty) -- FPTAGS[i] := zero
5663 * FP stack pointer set to zero
5664*/
5665
5666static void do_MMX_preamble ( void )
5667{
5668 Int i;
5669 IRArray* descr = mkIRArray( OFFB_FPTAGS, Ity_I8, 8 );
5670 IRExpr* zero = mkU32(0);
5671 IRExpr* tag1 = mkU8(1);
5672 put_ftop(zero);
5673 for (i = 0; i < 8; i++)
5674 stmt( IRStmt_PutI( descr, zero, i, tag1 ) );
5675}
5676
5677static void do_EMMS_preamble ( void )
5678{
5679 Int i;
5680 IRArray* descr = mkIRArray( OFFB_FPTAGS, Ity_I8, 8 );
5681 IRExpr* zero = mkU32(0);
5682 IRExpr* tag0 = mkU8(0);
5683 put_ftop(zero);
5684 for (i = 0; i < 8; i++)
5685 stmt( IRStmt_PutI( descr, zero, i, tag0 ) );
5686}
5687
5688
5689static IRExpr* getMMXReg ( UInt archreg )
5690{
5691 vassert(archreg < 8);
5692 return IRExpr_Get( OFFB_FPREGS + 8 * archreg, Ity_I64 );
5693}
5694
5695
5696static void putMMXReg ( UInt archreg, IRExpr* e )
5697{
5698 vassert(archreg < 8);
5699 vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_I64);
5700 stmt( IRStmt_Put( OFFB_FPREGS + 8 * archreg, e ) );
5701}
5702
5703
5704/* Helper for non-shift MMX insns. Note this is incomplete in the
5705 sense that it does not first call do_MMX_preamble() -- that is the
5706 responsibility of its caller. */
5707
5708static
5709ULong dis_MMXop_regmem_to_reg ( Prefix pfx,
sewardj270def42005-07-03 01:03:01 +00005710 Long delta,
sewardj8711f662005-05-09 17:52:56 +00005711 UChar opc,
sewardjca673ab2005-05-11 10:03:08 +00005712 HChar* name,
sewardj8711f662005-05-09 17:52:56 +00005713 Bool show_granularity )
5714{
5715 HChar dis_buf[50];
5716 UChar modrm = getUChar(delta);
5717 Bool isReg = epartIsReg(modrm);
5718 IRExpr* argL = NULL;
5719 IRExpr* argR = NULL;
5720 IRExpr* argG = NULL;
5721 IRExpr* argE = NULL;
5722 IRTemp res = newTemp(Ity_I64);
5723
5724 Bool invG = False;
5725 IROp op = Iop_INVALID;
5726 void* hAddr = NULL;
sewardjca673ab2005-05-11 10:03:08 +00005727 HChar* hName = NULL;
sewardj8711f662005-05-09 17:52:56 +00005728 Bool eLeft = False;
5729
5730# define XXX(_name) do { hAddr = &_name; hName = #_name; } while (0)
5731
5732 switch (opc) {
5733 /* Original MMX ones */
5734 case 0xFC: op = Iop_Add8x8; break;
5735 case 0xFD: op = Iop_Add16x4; break;
5736 case 0xFE: op = Iop_Add32x2; break;
5737
5738 case 0xEC: op = Iop_QAdd8Sx8; break;
5739 case 0xED: op = Iop_QAdd16Sx4; break;
5740
5741 case 0xDC: op = Iop_QAdd8Ux8; break;
5742 case 0xDD: op = Iop_QAdd16Ux4; break;
5743
5744 case 0xF8: op = Iop_Sub8x8; break;
5745 case 0xF9: op = Iop_Sub16x4; break;
5746 case 0xFA: op = Iop_Sub32x2; break;
5747
5748 case 0xE8: op = Iop_QSub8Sx8; break;
5749 case 0xE9: op = Iop_QSub16Sx4; break;
5750
5751 case 0xD8: op = Iop_QSub8Ux8; break;
5752 case 0xD9: op = Iop_QSub16Ux4; break;
5753
5754 case 0xE5: op = Iop_MulHi16Sx4; break;
5755 case 0xD5: op = Iop_Mul16x4; break;
5756 case 0xF5: XXX(amd64g_calculate_mmx_pmaddwd); break;
5757
5758 case 0x74: op = Iop_CmpEQ8x8; break;
5759 case 0x75: op = Iop_CmpEQ16x4; break;
5760 case 0x76: op = Iop_CmpEQ32x2; break;
5761
5762 case 0x64: op = Iop_CmpGT8Sx8; break;
5763 case 0x65: op = Iop_CmpGT16Sx4; break;
5764 case 0x66: op = Iop_CmpGT32Sx2; break;
5765
5766 case 0x6B: op = Iop_QNarrow32Sx2; eLeft = True; break;
5767 case 0x63: op = Iop_QNarrow16Sx4; eLeft = True; break;
5768 case 0x67: op = Iop_QNarrow16Ux4; eLeft = True; break;
5769
5770 case 0x68: op = Iop_InterleaveHI8x8; eLeft = True; break;
5771 case 0x69: op = Iop_InterleaveHI16x4; eLeft = True; break;
5772 case 0x6A: op = Iop_InterleaveHI32x2; eLeft = True; break;
5773
5774 case 0x60: op = Iop_InterleaveLO8x8; eLeft = True; break;
5775 case 0x61: op = Iop_InterleaveLO16x4; eLeft = True; break;
5776 case 0x62: op = Iop_InterleaveLO32x2; eLeft = True; break;
5777
5778 case 0xDB: op = Iop_And64; break;
5779 case 0xDF: op = Iop_And64; invG = True; break;
5780 case 0xEB: op = Iop_Or64; break;
5781 case 0xEF: /* Possibly do better here if argL and argR are the
5782 same reg */
5783 op = Iop_Xor64; break;
5784
5785 /* Introduced in SSE1 */
5786 case 0xE0: op = Iop_Avg8Ux8; break;
5787 case 0xE3: op = Iop_Avg16Ux4; break;
5788 case 0xEE: op = Iop_Max16Sx4; break;
5789 case 0xDE: op = Iop_Max8Ux8; break;
5790 case 0xEA: op = Iop_Min16Sx4; break;
5791 case 0xDA: op = Iop_Min8Ux8; break;
5792 case 0xE4: op = Iop_MulHi16Ux4; break;
sewardja7ba8c42005-05-10 20:08:34 +00005793 case 0xF6: XXX(amd64g_calculate_mmx_psadbw); break;
sewardj8711f662005-05-09 17:52:56 +00005794
5795 /* Introduced in SSE2 */
5796 case 0xD4: op = Iop_Add64; break;
5797 case 0xFB: op = Iop_Sub64; break;
5798
5799 default:
5800 vex_printf("\n0x%x\n", (Int)opc);
5801 vpanic("dis_MMXop_regmem_to_reg");
5802 }
5803
5804# undef XXX
5805
5806 argG = getMMXReg(gregLO3ofRM(modrm));
5807 if (invG)
5808 argG = unop(Iop_Not64, argG);
5809
5810 if (isReg) {
5811 delta++;
5812 argE = getMMXReg(eregLO3ofRM(modrm));
5813 } else {
5814 Int len;
5815 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
5816 delta += len;
5817 argE = loadLE(Ity_I64, mkexpr(addr));
5818 }
5819
5820 if (eLeft) {
5821 argL = argE;
5822 argR = argG;
5823 } else {
5824 argL = argG;
5825 argR = argE;
5826 }
5827
5828 if (op != Iop_INVALID) {
5829 vassert(hName == NULL);
5830 vassert(hAddr == NULL);
5831 assign(res, binop(op, argL, argR));
5832 } else {
5833 vassert(hName != NULL);
5834 vassert(hAddr != NULL);
5835 assign( res,
5836 mkIRExprCCall(
5837 Ity_I64,
5838 0/*regparms*/, hName, hAddr,
5839 mkIRExprVec_2( argL, argR )
5840 )
5841 );
5842 }
5843
5844 putMMXReg( gregLO3ofRM(modrm), mkexpr(res) );
5845
5846 DIP("%s%s %s, %s\n",
5847 name, show_granularity ? nameMMXGran(opc & 3) : "",
5848 ( isReg ? nameMMXReg(eregLO3ofRM(modrm)) : dis_buf ),
5849 nameMMXReg(gregLO3ofRM(modrm)) );
5850
5851 return delta;
5852}
5853
5854
5855/* Vector by scalar shift of G by the amount specified at the bottom
5856 of E. This is a straight copy of dis_SSE_shiftG_byE. */
5857
sewardj270def42005-07-03 01:03:01 +00005858static ULong dis_MMX_shiftG_byE ( Prefix pfx, Long delta,
sewardj8711f662005-05-09 17:52:56 +00005859 HChar* opname, IROp op )
5860{
5861 HChar dis_buf[50];
5862 Int alen, size;
5863 IRTemp addr;
5864 Bool shl, shr, sar;
5865 UChar rm = getUChar(delta);
5866 IRTemp g0 = newTemp(Ity_I64);
5867 IRTemp g1 = newTemp(Ity_I64);
5868 IRTemp amt = newTemp(Ity_I64);
5869 IRTemp amt8 = newTemp(Ity_I8);
5870
5871 if (epartIsReg(rm)) {
5872 assign( amt, getMMXReg(eregLO3ofRM(rm)) );
5873 DIP("%s %s,%s\n", opname,
5874 nameMMXReg(eregLO3ofRM(rm)),
5875 nameMMXReg(gregLO3ofRM(rm)) );
5876 delta++;
5877 } else {
5878 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
5879 assign( amt, loadLE(Ity_I64, mkexpr(addr)) );
5880 DIP("%s %s,%s\n", opname,
5881 dis_buf,
5882 nameMMXReg(gregLO3ofRM(rm)) );
5883 delta += alen;
5884 }
5885 assign( g0, getMMXReg(gregLO3ofRM(rm)) );
5886 assign( amt8, unop(Iop_64to8, mkexpr(amt)) );
5887
5888 shl = shr = sar = False;
5889 size = 0;
5890 switch (op) {
5891 case Iop_ShlN16x4: shl = True; size = 32; break;
5892 case Iop_ShlN32x2: shl = True; size = 32; break;
5893 case Iop_Shl64: shl = True; size = 64; break;
5894 case Iop_ShrN16x4: shr = True; size = 16; break;
5895 case Iop_ShrN32x2: shr = True; size = 32; break;
5896 case Iop_Shr64: shr = True; size = 64; break;
5897 case Iop_SarN16x4: sar = True; size = 16; break;
5898 case Iop_SarN32x2: sar = True; size = 32; break;
5899 default: vassert(0);
5900 }
5901
5902 if (shl || shr) {
5903 assign(
5904 g1,
5905 IRExpr_Mux0X(
5906 unop(Iop_1Uto8,binop(Iop_CmpLT64U,mkexpr(amt),mkU64(size))),
5907 mkU64(0),
5908 binop(op, mkexpr(g0), mkexpr(amt8))
5909 )
5910 );
5911 } else
5912 if (sar) {
5913 assign(
5914 g1,
5915 IRExpr_Mux0X(
5916 unop(Iop_1Uto8,binop(Iop_CmpLT64U,mkexpr(amt),mkU64(size))),
5917 binop(op, mkexpr(g0), mkU8(size-1)),
5918 binop(op, mkexpr(g0), mkexpr(amt8))
5919 )
5920 );
5921 } else {
5922 vassert(0);
5923 }
5924
5925 putMMXReg( gregLO3ofRM(rm), mkexpr(g1) );
5926 return delta;
5927}
5928
5929
sewardj3d8107c2005-05-09 22:23:38 +00005930/* Vector by scalar shift of E by an immediate byte. This is a
5931 straight copy of dis_SSE_shiftE_imm. */
5932
5933static
sewardj270def42005-07-03 01:03:01 +00005934ULong dis_MMX_shiftE_imm ( Long delta, HChar* opname, IROp op )
sewardj3d8107c2005-05-09 22:23:38 +00005935{
5936 Bool shl, shr, sar;
5937 UChar rm = getUChar(delta);
5938 IRTemp e0 = newTemp(Ity_I64);
5939 IRTemp e1 = newTemp(Ity_I64);
5940 UChar amt, size;
5941 vassert(epartIsReg(rm));
5942 vassert(gregLO3ofRM(rm) == 2
5943 || gregLO3ofRM(rm) == 4 || gregLO3ofRM(rm) == 6);
sewardjca673ab2005-05-11 10:03:08 +00005944 amt = getUChar(delta+1);
sewardj3d8107c2005-05-09 22:23:38 +00005945 delta += 2;
5946 DIP("%s $%d,%s\n", opname,
5947 (Int)amt,
5948 nameMMXReg(eregLO3ofRM(rm)) );
5949
5950 assign( e0, getMMXReg(eregLO3ofRM(rm)) );
5951
5952 shl = shr = sar = False;
5953 size = 0;
5954 switch (op) {
5955 case Iop_ShlN16x4: shl = True; size = 16; break;
5956 case Iop_ShlN32x2: shl = True; size = 32; break;
5957 case Iop_Shl64: shl = True; size = 64; break;
5958 case Iop_SarN16x4: sar = True; size = 16; break;
5959 case Iop_SarN32x2: sar = True; size = 32; break;
5960 case Iop_ShrN16x4: shr = True; size = 16; break;
5961 case Iop_ShrN32x2: shr = True; size = 32; break;
5962 case Iop_Shr64: shr = True; size = 64; break;
5963 default: vassert(0);
5964 }
5965
5966 if (shl || shr) {
5967 assign( e1, amt >= size
5968 ? mkU64(0)
5969 : binop(op, mkexpr(e0), mkU8(amt))
5970 );
5971 } else
5972 if (sar) {
5973 assign( e1, amt >= size
5974 ? binop(op, mkexpr(e0), mkU8(size-1))
5975 : binop(op, mkexpr(e0), mkU8(amt))
5976 );
5977 } else {
5978 vassert(0);
5979 }
5980
5981 putMMXReg( eregLO3ofRM(rm), mkexpr(e1) );
5982 return delta;
5983}
sewardj8711f662005-05-09 17:52:56 +00005984
5985
5986/* Completely handle all MMX instructions except emms. */
5987
5988static
sewardj270def42005-07-03 01:03:01 +00005989ULong dis_MMX ( Bool* decode_ok, Prefix pfx, Int sz, Long delta )
sewardj8711f662005-05-09 17:52:56 +00005990{
5991 Int len;
5992 UChar modrm;
5993 HChar dis_buf[50];
5994 UChar opc = getUChar(delta);
5995 delta++;
5996
5997 /* dis_MMX handles all insns except emms. */
5998 do_MMX_preamble();
5999
6000 switch (opc) {
6001
sewardj3d8107c2005-05-09 22:23:38 +00006002 case 0x6E:
6003 if (sz == 4) {
6004 /* MOVD (src)ireg32-or-mem32 (E), (dst)mmxreg (G)*/
6005 modrm = getUChar(delta);
6006 if (epartIsReg(modrm)) {
6007 delta++;
6008 putMMXReg(
6009 gregLO3ofRM(modrm),
6010 binop( Iop_32HLto64,
6011 mkU32(0),
6012 getIReg32(eregOfRexRM(pfx,modrm)) ) );
6013 DIP("movd %s, %s\n",
6014 nameIReg32(eregOfRexRM(pfx,modrm)),
6015 nameMMXReg(gregLO3ofRM(modrm)));
6016 } else {
6017 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
6018 delta += len;
6019 putMMXReg(
6020 gregLO3ofRM(modrm),
6021 binop( Iop_32HLto64,
6022 mkU32(0),
6023 loadLE(Ity_I32, mkexpr(addr)) ) );
6024 DIP("movd %s, %s\n", dis_buf, nameMMXReg(gregLO3ofRM(modrm)));
6025 }
6026 }
6027 else
6028 if (sz == 8) {
6029 /* MOVD (src)ireg64-or-mem64 (E), (dst)mmxreg (G)*/
6030 modrm = getUChar(delta);
6031 if (epartIsReg(modrm)) {
6032 delta++;
6033 putMMXReg( gregLO3ofRM(modrm),
6034 getIReg64(eregOfRexRM(pfx,modrm)) );
6035 DIP("movd %s, %s\n",
6036 nameIReg64(eregOfRexRM(pfx,modrm)),
6037 nameMMXReg(gregLO3ofRM(modrm)));
6038 } else {
6039 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
6040 delta += len;
6041 putMMXReg( gregLO3ofRM(modrm),
6042 loadLE(Ity_I64, mkexpr(addr)) );
6043 DIP("movd{64} %s, %s\n", dis_buf, nameMMXReg(gregLO3ofRM(modrm)));
6044 }
6045 }
6046 else {
6047 goto mmx_decode_failure;
6048 }
6049 break;
6050
6051 case 0x7E:
6052 if (sz == 4) {
6053 /* MOVD (src)mmxreg (G), (dst)ireg32-or-mem32 (E) */
6054 modrm = getUChar(delta);
6055 if (epartIsReg(modrm)) {
6056 delta++;
6057 putIReg32( eregOfRexRM(pfx,modrm),
6058 unop(Iop_64to32, getMMXReg(gregLO3ofRM(modrm)) ) );
6059 DIP("movd %s, %s\n",
6060 nameMMXReg(gregLO3ofRM(modrm)),
6061 nameIReg32(eregOfRexRM(pfx,modrm)));
6062 } else {
6063 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
6064 delta += len;
6065 storeLE( mkexpr(addr),
6066 unop(Iop_64to32, getMMXReg(gregLO3ofRM(modrm)) ) );
6067 DIP("movd %s, %s\n", nameMMXReg(gregLO3ofRM(modrm)), dis_buf);
6068 }
6069 }
6070 else
6071 if (sz == 8) {
6072 /* MOVD (src)mmxreg (G), (dst)ireg64-or-mem64 (E) */
6073 modrm = getUChar(delta);
6074 if (epartIsReg(modrm)) {
6075 delta++;
6076 putIReg64( eregOfRexRM(pfx,modrm),
6077 getMMXReg(gregLO3ofRM(modrm)) );
6078 DIP("movd %s, %s\n",
6079 nameMMXReg(gregLO3ofRM(modrm)),
6080 nameIReg64(eregOfRexRM(pfx,modrm)));
6081 } else {
6082 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
6083 delta += len;
6084 storeLE( mkexpr(addr),
6085 getMMXReg(gregLO3ofRM(modrm)) );
6086 DIP("movd{64} %s, %s\n", nameMMXReg(gregLO3ofRM(modrm)), dis_buf);
6087 }
6088 } else {
6089 goto mmx_decode_failure;
6090 }
6091 break;
sewardj8711f662005-05-09 17:52:56 +00006092
6093 case 0x6F:
6094 /* MOVQ (src)mmxreg-or-mem, (dst)mmxreg */
6095 if (sz != 4)
6096 goto mmx_decode_failure;
6097 modrm = getUChar(delta);
6098 if (epartIsReg(modrm)) {
6099 delta++;
6100 putMMXReg( gregLO3ofRM(modrm), getMMXReg(eregLO3ofRM(modrm)) );
6101 DIP("movq %s, %s\n",
6102 nameMMXReg(eregLO3ofRM(modrm)),
6103 nameMMXReg(gregLO3ofRM(modrm)));
6104 } else {
6105 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
6106 delta += len;
6107 putMMXReg( gregLO3ofRM(modrm), loadLE(Ity_I64, mkexpr(addr)) );
6108 DIP("movq %s, %s\n",
6109 dis_buf, nameMMXReg(gregLO3ofRM(modrm)));
6110 }
6111 break;
6112
6113 case 0x7F:
6114 /* MOVQ (src)mmxreg, (dst)mmxreg-or-mem */
6115 if (sz != 4)
6116 goto mmx_decode_failure;
6117 modrm = getUChar(delta);
6118 if (epartIsReg(modrm)) {
6119 /* Fall through. The assembler doesn't appear to generate
6120 these. */
6121 goto mmx_decode_failure;
6122 } else {
6123 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
6124 delta += len;
6125 storeLE( mkexpr(addr), getMMXReg(gregLO3ofRM(modrm)) );
6126 DIP("mov(nt)q %s, %s\n",
6127 nameMMXReg(gregLO3ofRM(modrm)), dis_buf);
6128 }
6129 break;
6130
6131 case 0xFC:
6132 case 0xFD:
6133 case 0xFE: /* PADDgg (src)mmxreg-or-mem, (dst)mmxreg */
6134 if (sz != 4)
6135 goto mmx_decode_failure;
6136 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "padd", True );
6137 break;
6138
6139 case 0xEC:
6140 case 0xED: /* PADDSgg (src)mmxreg-or-mem, (dst)mmxreg */
6141 if (sz != 4)
6142 goto mmx_decode_failure;
6143 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "padds", True );
6144 break;
6145
6146 case 0xDC:
6147 case 0xDD: /* PADDUSgg (src)mmxreg-or-mem, (dst)mmxreg */
6148 if (sz != 4)
6149 goto mmx_decode_failure;
6150 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "paddus", True );
6151 break;
6152
6153 case 0xF8:
6154 case 0xF9:
6155 case 0xFA: /* PSUBgg (src)mmxreg-or-mem, (dst)mmxreg */
6156 if (sz != 4)
6157 goto mmx_decode_failure;
6158 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "psub", True );
6159 break;
6160
6161 case 0xE8:
6162 case 0xE9: /* PSUBSgg (src)mmxreg-or-mem, (dst)mmxreg */
6163 if (sz != 4)
6164 goto mmx_decode_failure;
6165 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "psubs", True );
6166 break;
6167
6168 case 0xD8:
6169 case 0xD9: /* PSUBUSgg (src)mmxreg-or-mem, (dst)mmxreg */
6170 if (sz != 4)
6171 goto mmx_decode_failure;
6172 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "psubus", True );
6173 break;
6174
6175 case 0xE5: /* PMULHW (src)mmxreg-or-mem, (dst)mmxreg */
6176 if (sz != 4)
6177 goto mmx_decode_failure;
6178 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "pmulhw", False );
6179 break;
6180
6181 case 0xD5: /* PMULLW (src)mmxreg-or-mem, (dst)mmxreg */
6182 if (sz != 4)
6183 goto mmx_decode_failure;
6184 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "pmullw", False );
6185 break;
6186
6187 case 0xF5: /* PMADDWD (src)mmxreg-or-mem, (dst)mmxreg */
6188 vassert(sz == 4);
6189 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "pmaddwd", False );
6190 break;
6191
6192 case 0x74:
6193 case 0x75:
6194 case 0x76: /* PCMPEQgg (src)mmxreg-or-mem, (dst)mmxreg */
6195 if (sz != 4)
6196 goto mmx_decode_failure;
6197 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "pcmpeq", True );
6198 break;
6199
6200 case 0x64:
6201 case 0x65:
6202 case 0x66: /* PCMPGTgg (src)mmxreg-or-mem, (dst)mmxreg */
6203 if (sz != 4)
6204 goto mmx_decode_failure;
6205 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "pcmpgt", True );
6206 break;
6207
6208 case 0x6B: /* PACKSSDW (src)mmxreg-or-mem, (dst)mmxreg */
6209 if (sz != 4)
6210 goto mmx_decode_failure;
6211 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "packssdw", False );
6212 break;
6213
6214 case 0x63: /* PACKSSWB (src)mmxreg-or-mem, (dst)mmxreg */
6215 if (sz != 4)
6216 goto mmx_decode_failure;
6217 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "packsswb", False );
6218 break;
6219
6220 case 0x67: /* PACKUSWB (src)mmxreg-or-mem, (dst)mmxreg */
6221 if (sz != 4)
6222 goto mmx_decode_failure;
6223 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "packuswb", False );
6224 break;
6225
6226 case 0x68:
6227 case 0x69:
6228 case 0x6A: /* PUNPCKHgg (src)mmxreg-or-mem, (dst)mmxreg */
6229 if (sz != 4)
6230 goto mmx_decode_failure;
6231 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "punpckh", True );
6232 break;
6233
6234 case 0x60:
6235 case 0x61:
6236 case 0x62: /* PUNPCKLgg (src)mmxreg-or-mem, (dst)mmxreg */
6237 if (sz != 4)
6238 goto mmx_decode_failure;
6239 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "punpckl", True );
6240 break;
6241
6242 case 0xDB: /* PAND (src)mmxreg-or-mem, (dst)mmxreg */
6243 if (sz != 4)
6244 goto mmx_decode_failure;
6245 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "pand", False );
6246 break;
6247
6248 case 0xDF: /* PANDN (src)mmxreg-or-mem, (dst)mmxreg */
6249 if (sz != 4)
6250 goto mmx_decode_failure;
6251 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "pandn", False );
6252 break;
6253
6254 case 0xEB: /* POR (src)mmxreg-or-mem, (dst)mmxreg */
6255 if (sz != 4)
6256 goto mmx_decode_failure;
6257 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "por", False );
6258 break;
6259
6260 case 0xEF: /* PXOR (src)mmxreg-or-mem, (dst)mmxreg */
6261 if (sz != 4)
6262 goto mmx_decode_failure;
6263 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "pxor", False );
6264 break;
6265
6266# define SHIFT_BY_REG(_name,_op) \
6267 delta = dis_MMX_shiftG_byE(pfx, delta, _name, _op); \
6268 break;
6269
6270 /* PSLLgg (src)mmxreg-or-mem, (dst)mmxreg */
6271 case 0xF1: SHIFT_BY_REG("psllw", Iop_ShlN16x4);
6272 case 0xF2: SHIFT_BY_REG("pslld", Iop_ShlN32x2);
6273 case 0xF3: SHIFT_BY_REG("psllq", Iop_Shl64);
6274
6275 /* PSRLgg (src)mmxreg-or-mem, (dst)mmxreg */
6276 case 0xD1: SHIFT_BY_REG("psrlw", Iop_ShrN16x4);
6277 case 0xD2: SHIFT_BY_REG("psrld", Iop_ShrN32x2);
6278 case 0xD3: SHIFT_BY_REG("psrlq", Iop_Shr64);
6279
6280 /* PSRAgg (src)mmxreg-or-mem, (dst)mmxreg */
6281 case 0xE1: SHIFT_BY_REG("psraw", Iop_SarN16x4);
6282 case 0xE2: SHIFT_BY_REG("psrad", Iop_SarN32x2);
6283
6284# undef SHIFT_BY_REG
sewardj3d8107c2005-05-09 22:23:38 +00006285
6286 case 0x71:
6287 case 0x72:
6288 case 0x73: {
6289 /* (sz==4): PSLLgg/PSRAgg/PSRLgg mmxreg by imm8 */
sewardjca673ab2005-05-11 10:03:08 +00006290 UChar byte2, subopc;
sewardj3d8107c2005-05-09 22:23:38 +00006291 if (sz != 4)
6292 goto mmx_decode_failure;
sewardjca673ab2005-05-11 10:03:08 +00006293 byte2 = getUChar(delta); /* amode / sub-opcode */
6294 subopc = toUChar( (byte2 >> 3) & 7 );
sewardj3d8107c2005-05-09 22:23:38 +00006295
6296# define SHIFT_BY_IMM(_name,_op) \
6297 do { delta = dis_MMX_shiftE_imm(delta,_name,_op); \
6298 } while (0)
6299
6300 if (subopc == 2 /*SRL*/ && opc == 0x71)
6301 SHIFT_BY_IMM("psrlw", Iop_ShrN16x4);
6302 else if (subopc == 2 /*SRL*/ && opc == 0x72)
6303 SHIFT_BY_IMM("psrld", Iop_ShrN32x2);
6304 else if (subopc == 2 /*SRL*/ && opc == 0x73)
6305 SHIFT_BY_IMM("psrlq", Iop_Shr64);
6306
6307 else if (subopc == 4 /*SAR*/ && opc == 0x71)
6308 SHIFT_BY_IMM("psraw", Iop_SarN16x4);
6309 else if (subopc == 4 /*SAR*/ && opc == 0x72)
6310 SHIFT_BY_IMM("psrad", Iop_SarN32x2);
6311
6312 else if (subopc == 6 /*SHL*/ && opc == 0x71)
6313 SHIFT_BY_IMM("psllw", Iop_ShlN16x4);
6314 else if (subopc == 6 /*SHL*/ && opc == 0x72)
6315 SHIFT_BY_IMM("pslld", Iop_ShlN32x2);
6316 else if (subopc == 6 /*SHL*/ && opc == 0x73)
6317 SHIFT_BY_IMM("psllq", Iop_Shl64);
6318
6319 else goto mmx_decode_failure;
6320
6321# undef SHIFT_BY_IMM
6322 break;
6323 }
sewardj8711f662005-05-09 17:52:56 +00006324
6325 /* --- MMX decode failure --- */
6326 default:
6327 mmx_decode_failure:
6328 *decode_ok = False;
6329 return delta; /* ignored */
6330
6331 }
6332
6333 *decode_ok = True;
6334 return delta;
6335}
6336
6337
sewardjd20c8852005-01-20 20:04:07 +00006338//.. /*------------------------------------------------------------*/
6339//.. /*--- More misc arithmetic and other obscure insns. ---*/
6340//.. /*------------------------------------------------------------*/
6341//..
6342//.. /* Double length left and right shifts. Apparently only required in
6343//.. v-size (no b- variant). */
6344//.. static
6345//.. UInt dis_SHLRD_Gv_Ev ( UChar sorb,
sewardj270def42005-07-03 01:03:01 +00006346//.. Long delta, UChar modrm,
sewardjd20c8852005-01-20 20:04:07 +00006347//.. Int sz,
6348//.. IRExpr* shift_amt,
6349//.. Bool amt_is_literal,
6350//.. Char* shift_amt_txt,
6351//.. Bool left_shift )
6352//.. {
6353//.. /* shift_amt :: Ity_I8 is the amount to shift. shift_amt_txt is used
6354//.. for printing it. And eip on entry points at the modrm byte. */
6355//.. Int len;
6356//.. HChar dis_buf[50];
6357//..
6358//.. IRType ty = szToITy(sz);
6359//.. IRTemp gsrc = newTemp(ty);
6360//.. IRTemp esrc = newTemp(ty);
6361//.. IRTemp addr = IRTemp_INVALID;
6362//.. IRTemp tmpSH = newTemp(Ity_I8);
6363//.. IRTemp tmpL = IRTemp_INVALID;
6364//.. IRTemp tmpRes = IRTemp_INVALID;
6365//.. IRTemp tmpSubSh = IRTemp_INVALID;
6366//.. IROp mkpair;
6367//.. IROp getres;
6368//.. IROp shift;
6369//.. IRExpr* mask = NULL;
6370//..
6371//.. vassert(sz == 2 || sz == 4);
6372//..
6373//.. /* The E-part is the destination; this is shifted. The G-part
6374//.. supplies bits to be shifted into the E-part, but is not
6375//.. changed.
6376//..
6377//.. If shifting left, form a double-length word with E at the top
6378//.. and G at the bottom, and shift this left. The result is then in
6379//.. the high part.
6380//..
6381//.. If shifting right, form a double-length word with G at the top
6382//.. and E at the bottom, and shift this right. The result is then
6383//.. at the bottom. */
6384//..
6385//.. /* Fetch the operands. */
6386//..
6387//.. assign( gsrc, getIReg(sz, gregOfRM(modrm)) );
6388//..
6389//.. if (epartIsReg(modrm)) {
6390//.. delta++;
6391//.. assign( esrc, getIReg(sz, eregOfRM(modrm)) );
6392//.. DIP("sh%cd%c %s, %s, %s\n",
6393//.. ( left_shift ? 'l' : 'r' ), nameISize(sz),
6394//.. shift_amt_txt,
6395//.. nameIReg(sz, gregOfRM(modrm)), nameIReg(sz, eregOfRM(modrm)));
6396//.. } else {
6397//.. addr = disAMode ( &len, sorb, delta, dis_buf );
6398//.. delta += len;
6399//.. assign( esrc, loadLE(ty, mkexpr(addr)) );
6400//.. DIP("sh%cd%c %s, %s, %s\n",
6401//.. ( left_shift ? 'l' : 'r' ), nameISize(sz),
6402//.. shift_amt_txt,
6403//.. nameIReg(sz, gregOfRM(modrm)), dis_buf);
6404//.. }
6405//..
6406//.. /* Round up the relevant primops. */
6407//..
6408//.. if (sz == 4) {
6409//.. tmpL = newTemp(Ity_I64);
6410//.. tmpRes = newTemp(Ity_I32);
6411//.. tmpSubSh = newTemp(Ity_I32);
6412//.. mkpair = Iop_32HLto64;
6413//.. getres = left_shift ? Iop_64HIto32 : Iop_64to32;
6414//.. shift = left_shift ? Iop_Shl64 : Iop_Shr64;
6415//.. mask = mkU8(31);
6416//.. } else {
6417//.. /* sz == 2 */
6418//.. tmpL = newTemp(Ity_I32);
6419//.. tmpRes = newTemp(Ity_I16);
6420//.. tmpSubSh = newTemp(Ity_I16);
6421//.. mkpair = Iop_16HLto32;
6422//.. getres = left_shift ? Iop_32HIto16 : Iop_32to16;
6423//.. shift = left_shift ? Iop_Shl32 : Iop_Shr32;
6424//.. mask = mkU8(15);
6425//.. }
6426//..
6427//.. /* Do the shift, calculate the subshift value, and set
6428//.. the flag thunk. */
6429//..
6430//.. assign( tmpSH, binop(Iop_And8, shift_amt, mask) );
6431//..
6432//.. if (left_shift)
6433//.. assign( tmpL, binop(mkpair, mkexpr(esrc), mkexpr(gsrc)) );
6434//.. else
6435//.. assign( tmpL, binop(mkpair, mkexpr(gsrc), mkexpr(esrc)) );
6436//..
6437//.. assign( tmpRes, unop(getres, binop(shift, mkexpr(tmpL), mkexpr(tmpSH)) ) );
6438//.. assign( tmpSubSh,
6439//.. unop(getres,
6440//.. binop(shift,
6441//.. mkexpr(tmpL),
6442//.. binop(Iop_And8,
6443//.. binop(Iop_Sub8, mkexpr(tmpSH), mkU8(1) ),
6444//.. mask))) );
6445//..
6446//.. setFlags_DEP1_DEP2_shift ( left_shift ? Iop_Shl32 : Iop_Sar32,
6447//.. tmpRes, tmpSubSh, ty, tmpSH );
6448//..
6449//.. /* Put result back. */
6450//..
6451//.. if (epartIsReg(modrm)) {
6452//.. putIReg(sz, eregOfRM(modrm), mkexpr(tmpRes));
6453//.. } else {
6454//.. storeLE( mkexpr(addr), mkexpr(tmpRes) );
6455//.. }
6456//..
6457//.. if (amt_is_literal) delta++;
6458//.. return delta;
6459//.. }
6460//..
6461//..
6462//.. /* Handle BT/BTS/BTR/BTC Gv, Ev. Apparently b-size is not
6463//.. required. */
6464//..
6465//.. typedef enum { BtOpNone, BtOpSet, BtOpReset, BtOpComp } BtOp;
6466//..
6467//.. static Char* nameBtOp ( BtOp op )
6468//.. {
6469//.. switch (op) {
6470//.. case BtOpNone: return "";
6471//.. case BtOpSet: return "s";
6472//.. case BtOpReset: return "r";
6473//.. case BtOpComp: return "c";
6474//.. default: vpanic("nameBtOp(x86)");
6475//.. }
6476//.. }
6477//..
6478//..
6479//.. static
sewardj270def42005-07-03 01:03:01 +00006480//.. UInt dis_bt_G_E ( UChar sorb, Int sz, Long delta, BtOp op )
sewardjd20c8852005-01-20 20:04:07 +00006481//.. {
6482//.. HChar dis_buf[50];
6483//.. UChar modrm;
6484//.. Int len;
6485//.. IRTemp t_fetched, t_bitno0, t_bitno1, t_bitno2, t_addr0,
6486//.. t_addr1, t_esp, t_mask;
6487//..
6488//.. vassert(sz == 2 || sz == 4);
6489//..
6490//.. t_fetched = t_bitno0 = t_bitno1 = t_bitno2
6491//.. = t_addr0 = t_addr1 = t_esp = t_mask = IRTemp_INVALID;
6492//..
6493//.. t_fetched = newTemp(Ity_I8);
6494//.. t_bitno0 = newTemp(Ity_I32);
6495//.. t_bitno1 = newTemp(Ity_I32);
6496//.. t_bitno2 = newTemp(Ity_I8);
6497//.. t_addr1 = newTemp(Ity_I32);
sewardj8c332e22005-01-28 01:36:56 +00006498//.. modrm = getUChar(delta);
sewardjd20c8852005-01-20 20:04:07 +00006499//..
6500//.. assign( t_bitno0, widenUto32(getIReg(sz, gregOfRM(modrm))) );
6501//..
6502//.. if (epartIsReg(modrm)) {
6503//.. delta++;
6504//.. /* Get it onto the client's stack. */
6505//.. t_esp = newTemp(Ity_I32);
6506//.. t_addr0 = newTemp(Ity_I32);
6507//..
6508//.. assign( t_esp, binop(Iop_Sub32, getIReg(4, R_ESP), mkU32(sz)) );
6509//.. putIReg(4, R_ESP, mkexpr(t_esp));
6510//..
6511//.. storeLE( mkexpr(t_esp), getIReg(sz, eregOfRM(modrm)) );
6512//..
6513//.. /* Make t_addr0 point at it. */
6514//.. assign( t_addr0, mkexpr(t_esp) );
6515//..
6516//.. /* Mask out upper bits of the shift amount, since we're doing a
6517//.. reg. */
6518//.. assign( t_bitno1, binop(Iop_And32,
6519//.. mkexpr(t_bitno0),
6520//.. mkU32(sz == 4 ? 31 : 15)) );
6521//..
6522//.. } else {
6523//.. t_addr0 = disAMode ( &len, sorb, delta, dis_buf );
6524//.. delta += len;
6525//.. assign( t_bitno1, mkexpr(t_bitno0) );
6526//.. }
6527//..
6528//.. /* At this point: t_addr0 is the address being operated on. If it
6529//.. was a reg, we will have pushed it onto the client's stack.
6530//.. t_bitno1 is the bit number, suitably masked in the case of a
6531//.. reg. */
6532//..
6533//.. /* Now the main sequence. */
6534//.. assign( t_addr1,
6535//.. binop(Iop_Add32,
6536//.. mkexpr(t_addr0),
6537//.. binop(Iop_Sar32, mkexpr(t_bitno1), mkU8(3))) );
6538//..
6539//.. /* t_addr1 now holds effective address */
6540//..
6541//.. assign( t_bitno2,
6542//.. unop(Iop_32to8,
6543//.. binop(Iop_And32, mkexpr(t_bitno1), mkU32(7))) );
6544//..
6545//.. /* t_bitno2 contains offset of bit within byte */
6546//..
6547//.. if (op != BtOpNone) {
6548//.. t_mask = newTemp(Ity_I8);
6549//.. assign( t_mask, binop(Iop_Shl8, mkU8(1), mkexpr(t_bitno2)) );
6550//.. }
6551//..
6552//.. /* t_mask is now a suitable byte mask */
6553//..
6554//.. assign( t_fetched, loadLE(Ity_I8, mkexpr(t_addr1)) );
6555//..
6556//.. if (op != BtOpNone) {
6557//.. switch (op) {
6558//.. case BtOpSet:
6559//.. storeLE( mkexpr(t_addr1),
6560//.. binop(Iop_Or8, mkexpr(t_fetched),
6561//.. mkexpr(t_mask)) );
6562//.. break;
6563//.. case BtOpComp:
6564//.. storeLE( mkexpr(t_addr1),
6565//.. binop(Iop_Xor8, mkexpr(t_fetched),
6566//.. mkexpr(t_mask)) );
6567//.. break;
6568//.. case BtOpReset:
6569//.. storeLE( mkexpr(t_addr1),
6570//.. binop(Iop_And8, mkexpr(t_fetched),
6571//.. unop(Iop_Not8, mkexpr(t_mask))) );
6572//.. break;
6573//.. default:
6574//.. vpanic("dis_bt_G_E(x86)");
6575//.. }
6576//.. }
6577//..
6578//.. /* Side effect done; now get selected bit into Carry flag */
6579//.. /* Flags: C=selected bit, O,S,Z,A,P undefined, so are set to zero. */
6580//.. stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
6581//.. stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
6582//.. stmt( IRStmt_Put(
6583//.. OFFB_CC_DEP1,
6584//.. binop(Iop_And32,
6585//.. binop(Iop_Shr32,
6586//.. unop(Iop_8Uto32, mkexpr(t_fetched)),
6587//.. mkexpr(t_bitno2)),
6588//.. mkU32(1)))
6589//.. );
6590//..
6591//.. /* Move reg operand from stack back to reg */
6592//.. if (epartIsReg(modrm)) {
6593//.. /* t_esp still points at it. */
6594//.. putIReg(sz, eregOfRM(modrm), loadLE(szToITy(sz), mkexpr(t_esp)) );
6595//.. putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t_esp), mkU32(sz)) );
6596//.. }
6597//..
6598//.. DIP("bt%s%c %s, %s\n",
6599//.. nameBtOp(op), nameISize(sz), nameIReg(sz, gregOfRM(modrm)),
6600//.. ( epartIsReg(modrm) ? nameIReg(sz, eregOfRM(modrm)) : dis_buf ) );
6601//..
6602//.. return delta;
6603//.. }
sewardjf53b7352005-04-06 20:01:56 +00006604
6605
6606
6607/* Handle BSF/BSR. Only v-size seems necessary. */
6608static
sewardj270def42005-07-03 01:03:01 +00006609ULong dis_bs_E_G ( Prefix pfx, Int sz, Long delta, Bool fwds )
sewardjf53b7352005-04-06 20:01:56 +00006610{
6611 Bool isReg;
6612 UChar modrm;
6613 HChar dis_buf[50];
6614
6615 IRType ty = szToITy(sz);
6616 IRTemp src = newTemp(ty);
6617 IRTemp dst = newTemp(ty);
6618 IRTemp src64 = newTemp(Ity_I64);
6619 IRTemp dst64 = newTemp(Ity_I64);
6620 IRTemp src8 = newTemp(Ity_I8);
6621
6622 vassert(sz == 8 || sz == 4 || sz == 2);
6623
6624 modrm = getUChar(delta);
6625 isReg = epartIsReg(modrm);
6626 if (isReg) {
6627 delta++;
6628 assign( src, getIRegE(sz, pfx, modrm) );
6629 } else {
6630 Int len;
6631 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
6632 delta += len;
6633 assign( src, loadLE(ty, mkexpr(addr)) );
6634 }
6635
6636 DIP("bs%c%c %s, %s\n",
6637 fwds ? 'f' : 'r', nameISize(sz),
6638 ( isReg ? nameIRegE(sz, pfx, modrm) : dis_buf ),
6639 nameIRegG(sz, pfx, modrm));
6640
6641 /* First, widen src to 64 bits if it is not already. */
6642 assign( src64, widenUto64(mkexpr(src)) );
6643
6644 /* Generate an 8-bit expression which is zero iff the
6645 original is zero, and nonzero otherwise */
6646 assign( src8,
6647 unop(Iop_1Uto8,
6648 binop(Iop_CmpNE64,
6649 mkexpr(src64), mkU64(0))) );
6650
6651 /* Flags: Z is 1 iff source value is zero. All others
6652 are undefined -- we force them to zero. */
6653 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(AMD64G_CC_OP_COPY) ));
6654 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
6655 stmt( IRStmt_Put(
6656 OFFB_CC_DEP1,
6657 IRExpr_Mux0X( mkexpr(src8),
6658 /* src==0 */
6659 mkU64(AMD64G_CC_MASK_Z),
6660 /* src!=0 */
6661 mkU64(0)
6662 )
6663 ));
6664 /* Set NDEP even though it isn't used. This makes redundant-PUT
6665 elimination of previous stores to this field work better. */
6666 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU64(0) ));
6667
6668 /* Result: iff source value is zero, we can't use
6669 Iop_Clz64/Iop_Ctz64 as they have no defined result in that case.
6670 But anyway, amd64 semantics say the result is undefined in
6671 such situations. Hence handle the zero case specially. */
6672
6673 /* Bleh. What we compute:
6674
6675 bsf64: if src == 0 then {dst is unchanged}
6676 else Ctz64(src)
6677
6678 bsr64: if src == 0 then {dst is unchanged}
6679 else 63 - Clz64(src)
6680
6681 bsf32: if src == 0 then {dst is unchanged}
6682 else Ctz64(32Uto64(src))
6683
6684 bsr32: if src == 0 then {dst is unchanged}
6685 else 63 - Clz64(32Uto64(src))
6686
6687 bsf16: if src == 0 then {dst is unchanged}
6688 else Ctz64(32Uto64(16Uto32(src)))
6689
6690 bsr16: if src == 0 then {dst is unchanged}
6691 else 63 - Clz64(32Uto64(16Uto32(src)))
6692 */
6693
6694 /* The main computation, guarding against zero. */
6695 assign( dst64,
6696 IRExpr_Mux0X(
6697 mkexpr(src8),
6698 /* src == 0 -- leave dst unchanged */
6699 widenUto64( getIRegG( sz, pfx, modrm ) ),
6700 /* src != 0 */
6701 fwds ? unop(Iop_Ctz64, mkexpr(src64))
6702 : binop(Iop_Sub64,
6703 mkU64(63),
6704 unop(Iop_Clz64, mkexpr(src64)))
6705 )
6706 );
6707
6708 if (sz == 2)
sewardje58967e2005-04-27 11:50:56 +00006709 assign( dst, unop(Iop_64to16, mkexpr(dst64)) );
sewardjf53b7352005-04-06 20:01:56 +00006710 else
6711 if (sz == 4)
6712 assign( dst, unop(Iop_64to32, mkexpr(dst64)) );
6713 else
6714 assign( dst, mkexpr(dst64) );
6715
6716 /* dump result back */
6717 putIRegG( sz, pfx, modrm, mkexpr(dst) );
6718
6719 return delta;
6720}
sewardja6b93d12005-02-17 09:28:28 +00006721
6722
6723/* swap rAX with the reg specified by reg and REX.B */
6724static
sewardj5b470602005-02-27 13:10:48 +00006725void codegen_xchg_rAX_Reg ( Prefix pfx, Int sz, UInt regLo3 )
sewardja6b93d12005-02-17 09:28:28 +00006726{
6727 IRType ty = szToITy(sz);
6728 IRTemp t1 = newTemp(ty);
6729 IRTemp t2 = newTemp(ty);
sewardj2d4fcd52005-05-18 11:47:47 +00006730 vassert(sz == 4 || sz == 8);
sewardj5b470602005-02-27 13:10:48 +00006731 vassert(regLo3 < 8);
sewardj2d4fcd52005-05-18 11:47:47 +00006732 if (sz == 8) {
6733 assign( t1, getIReg64(R_RAX) );
6734 assign( t2, getIRegRexB(8, pfx, regLo3) );
6735 putIReg64( R_RAX, mkexpr(t2) );
6736 putIRegRexB(8, pfx, regLo3, mkexpr(t1) );
6737 } else {
6738 assign( t1, getIReg32(R_RAX) );
6739 assign( t2, getIRegRexB(4, pfx, regLo3) );
6740 putIReg32( R_RAX, mkexpr(t2) );
6741 putIRegRexB(4, pfx, regLo3, mkexpr(t1) );
6742 }
sewardja6b93d12005-02-17 09:28:28 +00006743 DIP("xchg%c %s, %s\n",
sewardj5b470602005-02-27 13:10:48 +00006744 nameISize(sz), nameIRegRAX(sz),
sewardj2d4fcd52005-05-18 11:47:47 +00006745 nameIRegRexB(sz,pfx, regLo3));
sewardja6b93d12005-02-17 09:28:28 +00006746}
6747
6748
sewardjd20c8852005-01-20 20:04:07 +00006749//.. static
6750//.. void codegen_SAHF ( void )
6751//.. {
6752//.. /* Set the flags to:
6753//.. (x86g_calculate_flags_all() & X86G_CC_MASK_O) -- retain the old O flag
6754//.. | (%AH & (X86G_CC_MASK_S|X86G_CC_MASK_Z|X86G_CC_MASK_A
6755//.. |X86G_CC_MASK_P|X86G_CC_MASK_C)
6756//.. */
6757//.. UInt mask_SZACP = X86G_CC_MASK_S|X86G_CC_MASK_Z|X86G_CC_MASK_A
6758//.. |X86G_CC_MASK_C|X86G_CC_MASK_P;
6759//.. IRTemp oldflags = newTemp(Ity_I32);
6760//.. assign( oldflags, mk_x86g_calculate_eflags_all() );
6761//.. stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
6762//.. stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
6763//.. stmt( IRStmt_Put( OFFB_CC_DEP1,
6764//.. binop(Iop_Or32,
6765//.. binop(Iop_And32, mkexpr(oldflags), mkU32(X86G_CC_MASK_O)),
6766//.. binop(Iop_And32,
6767//.. binop(Iop_Shr32, getIReg(4, R_EAX), mkU8(8)),
6768//.. mkU32(mask_SZACP))
6769//.. )
6770//.. ));
6771//.. }
6772//..
6773//..
6774//.. //-- static
6775//.. //-- void codegen_LAHF ( UCodeBlock* cb )
6776//.. //-- {
6777//.. //-- Int t = newTemp(cb);
6778//.. //--
6779//.. //-- /* Pushed arg is ignored, it just provides somewhere to put the
6780//.. //-- return value. */
6781//.. //-- uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, t);
6782//.. //-- uInstr0(cb, CALLM_S, 0);
6783//.. //-- uInstr1(cb, PUSH, 4, TempReg, t);
6784//.. //-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_LAHF));
6785//.. //-- uFlagsRWU(cb, FlagsSZACP, FlagsEmpty, FlagsEmpty);
6786//.. //-- uInstr1(cb, POP, 4, TempReg, t);
6787//.. //-- uInstr0(cb, CALLM_E, 0);
6788//.. //--
6789//.. //-- /* At this point, the %ah sub-register in %eax has been updated,
6790//.. //-- the rest is the same, so do a PUT of the whole thing. */
6791//.. //-- uInstr2(cb, PUT, 4, TempReg, t, ArchReg, R_EAX);
6792//.. //-- }
6793//.. //--
sewardja6b93d12005-02-17 09:28:28 +00006794
6795static
6796ULong dis_cmpxchg_G_E ( Prefix pfx,
6797 Int size,
sewardj270def42005-07-03 01:03:01 +00006798 Long delta0 )
sewardja6b93d12005-02-17 09:28:28 +00006799{
6800 HChar dis_buf[50];
6801 Int len;
6802
6803 IRType ty = szToITy(size);
6804 IRTemp acc = newTemp(ty);
6805 IRTemp src = newTemp(ty);
6806 IRTemp dest = newTemp(ty);
6807 IRTemp dest2 = newTemp(ty);
6808 IRTemp acc2 = newTemp(ty);
6809 IRTemp cond8 = newTemp(Ity_I8);
6810 IRTemp addr = IRTemp_INVALID;
6811 UChar rm = getUChar(delta0);
6812
6813 if (epartIsReg(rm)) {
sewardj5b470602005-02-27 13:10:48 +00006814 vassert(0); /* awaiting test case */
6815 assign( dest, getIRegE(size, pfx, rm) );
sewardja6b93d12005-02-17 09:28:28 +00006816 delta0++;
6817 DIP("cmpxchg%c %s,%s\n", nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00006818 nameIRegG(size,pfx,rm),
6819 nameIRegE(size,pfx,rm) );
sewardja6b93d12005-02-17 09:28:28 +00006820 } else {
6821 addr = disAMode ( &len, pfx, delta0, dis_buf, 0 );
6822 assign( dest, loadLE(ty, mkexpr(addr)) );
6823 delta0 += len;
6824 DIP("cmpxchg%c %s,%s\n", nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00006825 nameIRegG(size,pfx,rm), dis_buf);
sewardja6b93d12005-02-17 09:28:28 +00006826 }
6827
sewardj5b470602005-02-27 13:10:48 +00006828 assign( src, getIRegG(size, pfx, rm) );
6829 assign( acc, getIRegRAX(size) );
sewardja6b93d12005-02-17 09:28:28 +00006830 setFlags_DEP1_DEP2(Iop_Sub8, acc, dest, ty);
6831 assign( cond8, unop(Iop_1Uto8, mk_amd64g_calculate_condition(AMD64CondZ)) );
6832 assign( dest2, IRExpr_Mux0X(mkexpr(cond8), mkexpr(dest), mkexpr(src)) );
6833 assign( acc2, IRExpr_Mux0X(mkexpr(cond8), mkexpr(dest), mkexpr(acc)) );
sewardj5b470602005-02-27 13:10:48 +00006834 putIRegRAX(size, mkexpr(acc2));
sewardja6b93d12005-02-17 09:28:28 +00006835
6836 if (epartIsReg(rm)) {
sewardj5b470602005-02-27 13:10:48 +00006837 putIRegE(size, pfx, rm, mkexpr(dest2));
sewardja6b93d12005-02-17 09:28:28 +00006838 } else {
6839 storeLE( mkexpr(addr), mkexpr(dest2) );
6840 }
6841
6842 return delta0;
6843}
6844
6845
sewardjd20c8852005-01-20 20:04:07 +00006846//.. //-- static
6847//.. //-- Addr dis_cmpxchg8b ( UCodeBlock* cb,
6848//.. //-- UChar sorb,
6849//.. //-- Addr eip0 )
6850//.. //-- {
6851//.. //-- Int tal, tah, junkl, junkh, destl, desth, srcl, srch, accl, acch;
6852//.. //-- HChar dis_buf[50];
6853//.. //-- UChar rm;
6854//.. //-- UInt pair;
6855//.. //--
6856//.. //-- rm = getUChar(eip0);
6857//.. //-- accl = newTemp(cb);
6858//.. //-- acch = newTemp(cb);
6859//.. //-- srcl = newTemp(cb);
6860//.. //-- srch = newTemp(cb);
6861//.. //-- destl = newTemp(cb);
6862//.. //-- desth = newTemp(cb);
6863//.. //-- junkl = newTemp(cb);
6864//.. //-- junkh = newTemp(cb);
6865//.. //--
6866//.. //-- vg_assert(!epartIsReg(rm));
6867//.. //--
6868//.. //-- pair = disAMode ( cb, sorb, eip0, dis_buf );
6869//.. //-- tal = LOW24(pair);
6870//.. //-- tah = newTemp(cb);
6871//.. //-- uInstr2(cb, MOV, 4, TempReg, tal, TempReg, tah);
6872//.. //-- uInstr2(cb, ADD, 4, Literal, 0, TempReg, tah);
6873//.. //-- uLiteral(cb, 4);
6874//.. //-- eip0 += HI8(pair);
6875//.. //-- DIP("cmpxchg8b %s\n", dis_buf);
6876//.. //--
6877//.. //-- uInstr0(cb, CALLM_S, 0);
6878//.. //--
6879//.. //-- uInstr2(cb, LOAD, 4, TempReg, tah, TempReg, desth);
6880//.. //-- uInstr1(cb, PUSH, 4, TempReg, desth);
6881//.. //-- uInstr2(cb, LOAD, 4, TempReg, tal, TempReg, destl);
6882//.. //-- uInstr1(cb, PUSH, 4, TempReg, destl);
6883//.. //-- uInstr2(cb, GET, 4, ArchReg, R_ECX, TempReg, srch);
6884//.. //-- uInstr1(cb, PUSH, 4, TempReg, srch);
6885//.. //-- uInstr2(cb, GET, 4, ArchReg, R_EBX, TempReg, srcl);
6886//.. //-- uInstr1(cb, PUSH, 4, TempReg, srcl);
6887//.. //-- uInstr2(cb, GET, 4, ArchReg, R_EDX, TempReg, acch);
6888//.. //-- uInstr1(cb, PUSH, 4, TempReg, acch);
6889//.. //-- uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, accl);
6890//.. //-- uInstr1(cb, PUSH, 4, TempReg, accl);
6891//.. //--
6892//.. //-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_cmpxchg8b));
6893//.. //-- uFlagsRWU(cb, FlagsEmpty, FlagZ, FlagsEmpty);
6894//.. //--
6895//.. //-- uInstr1(cb, POP, 4, TempReg, accl);
6896//.. //-- uInstr2(cb, PUT, 4, TempReg, accl, ArchReg, R_EAX);
6897//.. //-- uInstr1(cb, POP, 4, TempReg, acch);
6898//.. //-- uInstr2(cb, PUT, 4, TempReg, acch, ArchReg, R_EDX);
6899//.. //-- uInstr1(cb, POP, 4, TempReg, srcl);
6900//.. //-- uInstr2(cb, PUT, 4, TempReg, srcl, ArchReg, R_EBX);
6901//.. //-- uInstr1(cb, POP, 4, TempReg, srch);
6902//.. //-- uInstr2(cb, PUT, 4, TempReg, srch, ArchReg, R_ECX);
6903//.. //-- uInstr1(cb, POP, 4, TempReg, destl);
6904//.. //-- uInstr2(cb, STORE, 4, TempReg, destl, TempReg, tal);
6905//.. //-- uInstr1(cb, POP, 4, TempReg, desth);
6906//.. //-- uInstr2(cb, STORE, 4, TempReg, desth, TempReg, tah);
6907//.. //--
6908//.. //-- uInstr0(cb, CALLM_E, 0);
6909//.. //--
6910//.. //-- return eip0;
6911//.. //-- }
sewardj3ca55a12005-01-27 16:06:23 +00006912
6913
6914/* Handle conditional move instructions of the form
6915 cmovcc E(reg-or-mem), G(reg)
6916
6917 E(src) is reg-or-mem
6918 G(dst) is reg.
6919
6920 If E is reg, --> GET %E, tmps
6921 GET %G, tmpd
6922 CMOVcc tmps, tmpd
6923 PUT tmpd, %G
6924
6925 If E is mem --> (getAddr E) -> tmpa
6926 LD (tmpa), tmps
6927 GET %G, tmpd
6928 CMOVcc tmps, tmpd
6929 PUT tmpd, %G
6930*/
6931static
6932ULong dis_cmov_E_G ( Prefix pfx,
6933 Int sz,
6934 AMD64Condcode cond,
sewardj270def42005-07-03 01:03:01 +00006935 Long delta0 )
sewardj3ca55a12005-01-27 16:06:23 +00006936{
sewardj8c332e22005-01-28 01:36:56 +00006937 UChar rm = getUChar(delta0);
sewardj3ca55a12005-01-27 16:06:23 +00006938 HChar dis_buf[50];
6939 Int len;
6940
6941 IRType ty = szToITy(sz);
6942 IRTemp tmps = newTemp(ty);
6943 IRTemp tmpd = newTemp(ty);
6944
6945 if (epartIsReg(rm)) {
sewardj5b470602005-02-27 13:10:48 +00006946 assign( tmps, getIRegE(sz, pfx, rm) );
6947 assign( tmpd, getIRegG(sz, pfx, rm) );
sewardj3ca55a12005-01-27 16:06:23 +00006948
sewardj5b470602005-02-27 13:10:48 +00006949 putIRegG( sz, pfx, rm,
sewardj3ca55a12005-01-27 16:06:23 +00006950 IRExpr_Mux0X( unop(Iop_1Uto8,
6951 mk_amd64g_calculate_condition(cond)),
6952 mkexpr(tmpd),
6953 mkexpr(tmps) )
6954 );
sewardje941eea2005-01-30 19:52:28 +00006955 DIP("cmov%s %s,%s\n", name_AMD64Condcode(cond),
sewardj5b470602005-02-27 13:10:48 +00006956 nameIRegE(sz,pfx,rm),
6957 nameIRegG(sz,pfx,rm));
sewardj3ca55a12005-01-27 16:06:23 +00006958 return 1+delta0;
6959 }
6960
6961 /* E refers to memory */
6962 {
sewardje1698952005-02-08 15:02:39 +00006963 IRTemp addr = disAMode ( &len, pfx, delta0, dis_buf, 0 );
sewardj3ca55a12005-01-27 16:06:23 +00006964 assign( tmps, loadLE(ty, mkexpr(addr)) );
sewardj5b470602005-02-27 13:10:48 +00006965 assign( tmpd, getIRegG(sz, pfx, rm) );
sewardj3ca55a12005-01-27 16:06:23 +00006966
sewardj5b470602005-02-27 13:10:48 +00006967 putIRegG( sz, pfx, rm,
sewardj3ca55a12005-01-27 16:06:23 +00006968 IRExpr_Mux0X( unop(Iop_1Uto8,
6969 mk_amd64g_calculate_condition(cond)),
6970 mkexpr(tmpd),
6971 mkexpr(tmps) )
6972 );
6973
sewardj7eaa7cf2005-01-31 18:55:22 +00006974 DIP("cmov%s %s,%s\n", name_AMD64Condcode(cond),
6975 dis_buf,
sewardj5b470602005-02-27 13:10:48 +00006976 nameIRegG(sz,pfx,rm));
sewardj3ca55a12005-01-27 16:06:23 +00006977 return len+delta0;
6978 }
6979}
6980
6981
sewardjb4fd2e72005-03-23 13:34:11 +00006982static
6983ULong dis_xadd_G_E ( /*OUT*/Bool* decode_ok,
sewardj270def42005-07-03 01:03:01 +00006984 Prefix pfx, Int sz, Long delta0 )
sewardjb4fd2e72005-03-23 13:34:11 +00006985{
6986 Int len;
6987 UChar rm = getUChar(delta0);
6988 HChar dis_buf[50];
6989
6990 IRType ty = szToITy(sz);
6991 IRTemp tmpd = newTemp(ty);
6992 IRTemp tmpt0 = newTemp(ty);
6993 IRTemp tmpt1 = newTemp(ty);
6994 *decode_ok = True;
6995
6996 if (epartIsReg(rm)) {
6997 *decode_ok = False;
6998 return delta0;
6999 } else {
7000 IRTemp addr = disAMode ( &len, pfx, delta0, dis_buf, 0 );
7001 assign( tmpd, loadLE(ty, mkexpr(addr)) );
7002 assign( tmpt0, getIRegG(sz, pfx, rm) );
7003 assign( tmpt1, binop(mkSizedOp(ty,Iop_Add8), mkexpr(tmpd), mkexpr(tmpt0)) );
7004 setFlags_DEP1_DEP2( Iop_Add8, tmpd, tmpt0, ty );
7005 storeLE( mkexpr(addr), mkexpr(tmpt1) );
7006 putIRegG(sz, pfx, rm, mkexpr(tmpd));
7007 DIP("xadd%c %s, %s\n",
7008 nameISize(sz), nameIRegG(sz,pfx,rm), dis_buf);
7009 return len+delta0;
7010 }
7011}
7012
sewardjd20c8852005-01-20 20:04:07 +00007013//.. /* Move 16 bits from Ew (ireg or mem) to G (a segment register). */
7014//..
7015//.. static
sewardj270def42005-07-03 01:03:01 +00007016//.. UInt dis_mov_Ew_Sw ( UChar sorb, Long delta0 )
sewardjd20c8852005-01-20 20:04:07 +00007017//.. {
7018//.. Int len;
7019//.. IRTemp addr;
sewardj8c332e22005-01-28 01:36:56 +00007020//.. UChar rm = getUChar(delta0);
sewardjd20c8852005-01-20 20:04:07 +00007021//.. HChar dis_buf[50];
7022//..
7023//.. if (epartIsReg(rm)) {
7024//.. putSReg( gregOfRM(rm), getIReg(2, eregOfRM(rm)) );
7025//.. DIP("movw %s,%s\n", nameIReg(2,eregOfRM(rm)), nameSReg(gregOfRM(rm)));
7026//.. return 1+delta0;
7027//.. } else {
7028//.. addr = disAMode ( &len, sorb, delta0, dis_buf );
7029//.. putSReg( gregOfRM(rm), loadLE(Ity_I16, mkexpr(addr)) );
7030//.. DIP("movw %s,%s\n", dis_buf, nameSReg(gregOfRM(rm)));
7031//.. return len+delta0;
7032//.. }
7033//.. }
7034//..
7035//.. /* Move 16 bits from G (a segment register) to Ew (ireg or mem). If
7036//.. dst is ireg and sz==4, zero out top half of it. */
7037//..
7038//.. static
7039//.. UInt dis_mov_Sw_Ew ( UChar sorb,
7040//.. Int sz,
7041//.. UInt delta0 )
7042//.. {
7043//.. Int len;
7044//.. IRTemp addr;
sewardj8c332e22005-01-28 01:36:56 +00007045//.. UChar rm = getUChar(delta0);
sewardjd20c8852005-01-20 20:04:07 +00007046//.. HChar dis_buf[50];
7047//..
7048//.. vassert(sz == 2 || sz == 4);
7049//..
7050//.. if (epartIsReg(rm)) {
7051//.. if (sz == 4)
7052//.. putIReg(4, eregOfRM(rm), unop(Iop_16Uto32, getSReg(gregOfRM(rm))));
7053//.. else
7054//.. putIReg(2, eregOfRM(rm), getSReg(gregOfRM(rm)));
7055//..
7056//.. DIP("mov %s,%s\n", nameSReg(gregOfRM(rm)), nameIReg(sz,eregOfRM(rm)));
7057//.. return 1+delta0;
7058//.. } else {
7059//.. addr = disAMode ( &len, sorb, delta0, dis_buf );
7060//.. storeLE( mkexpr(addr), getSReg(gregOfRM(rm)) );
7061//.. DIP("mov %s,%s\n", nameSReg(gregOfRM(rm)), dis_buf);
7062//.. return len+delta0;
7063//.. }
7064//.. }
7065//..
7066//..
7067//.. static
7068//.. void dis_push_segreg ( UInt sreg, Int sz )
7069//.. {
7070//.. IRTemp t1 = newTemp(Ity_I16);
7071//.. IRTemp ta = newTemp(Ity_I32);
7072//.. vassert(sz == 2 || sz == 4);
7073//..
7074//.. assign( t1, getSReg(sreg) );
7075//.. assign( ta, binop(Iop_Sub32, getIReg(4, R_ESP), mkU32(sz)) );
7076//.. putIReg(4, R_ESP, mkexpr(ta));
7077//.. storeLE( mkexpr(ta), mkexpr(t1) );
7078//..
7079//.. DIP("pushw %s\n", nameSReg(sreg));
7080//.. }
7081//..
7082//.. static
7083//.. void dis_pop_segreg ( UInt sreg, Int sz )
7084//.. {
7085//.. IRTemp t1 = newTemp(Ity_I16);
7086//.. IRTemp ta = newTemp(Ity_I32);
7087//.. vassert(sz == 2 || sz == 4);
7088//..
7089//.. assign( ta, getIReg(4, R_ESP) );
7090//.. assign( t1, loadLE(Ity_I16, mkexpr(ta)) );
7091//..
7092//.. putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(ta), mkU32(sz)) );
7093//.. putSReg( sreg, mkexpr(t1) );
7094//.. DIP("pop %s\n", nameSReg(sreg));
7095//.. }
sewardj2f959cc2005-01-26 01:19:35 +00007096
7097static
7098void dis_ret ( ULong d64 )
7099{
7100 IRTemp t1 = newTemp(Ity_I64);
7101 IRTemp t2 = newTemp(Ity_I64);
sewardj5a9ffab2005-05-12 17:55:01 +00007102 IRTemp t3 = newTemp(Ity_I64);
sewardj2f959cc2005-01-26 01:19:35 +00007103 assign(t1, getIReg64(R_RSP));
7104 assign(t2, loadLE(Ity_I64,mkexpr(t1)));
sewardj5a9ffab2005-05-12 17:55:01 +00007105 assign(t3, binop(Iop_Add64, mkexpr(t1), mkU64(8+d64)));
7106 putIReg64(R_RSP, mkexpr(t3));
7107 make_redzone_AbiHint(t3, "ret");
sewardj2f959cc2005-01-26 01:19:35 +00007108 jmp_treg(Ijk_Ret,t2);
7109}
7110
sewardj5b470602005-02-27 13:10:48 +00007111
sewardj1001dc42005-02-21 08:25:55 +00007112/*------------------------------------------------------------*/
7113/*--- SSE/SSE2/SSE3 helpers ---*/
7114/*------------------------------------------------------------*/
7115
7116/* Worker function; do not call directly.
7117 Handles full width G = G `op` E and G = (not G) `op` E.
7118*/
7119
sewardj8d965312005-02-25 02:48:47 +00007120static ULong dis_SSE_E_to_G_all_wrk (
sewardj270def42005-07-03 01:03:01 +00007121 Prefix pfx, Long delta,
sewardj8d965312005-02-25 02:48:47 +00007122 HChar* opname, IROp op,
7123 Bool invertG
7124 )
sewardj9da16972005-02-21 13:58:26 +00007125{
7126 HChar dis_buf[50];
7127 Int alen;
7128 IRTemp addr;
7129 UChar rm = getUChar(delta);
7130 IRExpr* gpart
7131 = invertG ? unop(Iop_NotV128, getXMMReg(gregOfRexRM(pfx,rm)))
7132 : getXMMReg(gregOfRexRM(pfx,rm));
7133 if (epartIsReg(rm)) {
7134 putXMMReg( gregOfRexRM(pfx,rm),
7135 binop(op, gpart,
7136 getXMMReg(eregOfRexRM(pfx,rm))) );
7137 DIP("%s %s,%s\n", opname,
7138 nameXMMReg(eregOfRexRM(pfx,rm)),
7139 nameXMMReg(gregOfRexRM(pfx,rm)) );
7140 return delta+1;
7141 } else {
7142 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
7143 putXMMReg( gregOfRexRM(pfx,rm),
7144 binop(op, gpart,
7145 loadLE(Ity_V128, mkexpr(addr))) );
7146 DIP("%s %s,%s\n", opname,
7147 dis_buf,
7148 nameXMMReg(gregOfRexRM(pfx,rm)) );
7149 return delta+alen;
7150 }
7151}
7152
7153
7154/* All lanes SSE binary operation, G = G `op` E. */
7155
7156static
sewardj270def42005-07-03 01:03:01 +00007157ULong dis_SSE_E_to_G_all ( Prefix pfx, Long delta,
sewardj8d965312005-02-25 02:48:47 +00007158 HChar* opname, IROp op )
sewardj9da16972005-02-21 13:58:26 +00007159{
7160 return dis_SSE_E_to_G_all_wrk( pfx, delta, opname, op, False );
7161}
7162
sewardj8d965312005-02-25 02:48:47 +00007163/* All lanes SSE binary operation, G = (not G) `op` E. */
7164
7165static
sewardj270def42005-07-03 01:03:01 +00007166ULong dis_SSE_E_to_G_all_invG ( Prefix pfx, Long delta,
sewardj8d965312005-02-25 02:48:47 +00007167 HChar* opname, IROp op )
7168{
7169 return dis_SSE_E_to_G_all_wrk( pfx, delta, opname, op, True );
7170}
7171
7172
7173/* Lowest 32-bit lane only SSE binary operation, G = G `op` E. */
7174
sewardj270def42005-07-03 01:03:01 +00007175static ULong dis_SSE_E_to_G_lo32 ( Prefix pfx, Long delta,
sewardj8d965312005-02-25 02:48:47 +00007176 HChar* opname, IROp op )
7177{
7178 HChar dis_buf[50];
7179 Int alen;
7180 IRTemp addr;
7181 UChar rm = getUChar(delta);
sewardj9c9ee3d2005-02-26 01:17:42 +00007182 IRExpr* gpart = getXMMReg(gregOfRexRM(pfx,rm));
sewardj8d965312005-02-25 02:48:47 +00007183 if (epartIsReg(rm)) {
sewardj9c9ee3d2005-02-26 01:17:42 +00007184 putXMMReg( gregOfRexRM(pfx,rm),
sewardj8d965312005-02-25 02:48:47 +00007185 binop(op, gpart,
7186 getXMMReg(eregOfRexRM(pfx,rm))) );
7187 DIP("%s %s,%s\n", opname,
7188 nameXMMReg(eregOfRexRM(pfx,rm)),
7189 nameXMMReg(gregOfRexRM(pfx,rm)) );
7190 return delta+1;
7191 } else {
7192 /* We can only do a 32-bit memory read, so the upper 3/4 of the
7193 E operand needs to be made simply of zeroes. */
7194 IRTemp epart = newTemp(Ity_V128);
7195 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
7196 assign( epart, unop( Iop_32UtoV128,
7197 loadLE(Ity_I32, mkexpr(addr))) );
7198 putXMMReg( gregOfRexRM(pfx,rm),
7199 binop(op, gpart, mkexpr(epart)) );
7200 DIP("%s %s,%s\n", opname,
7201 dis_buf,
7202 nameXMMReg(gregOfRexRM(pfx,rm)) );
7203 return delta+alen;
7204 }
7205}
sewardj1001dc42005-02-21 08:25:55 +00007206
7207
7208/* Lower 64-bit lane only SSE binary operation, G = G `op` E. */
7209
sewardj270def42005-07-03 01:03:01 +00007210static ULong dis_SSE_E_to_G_lo64 ( Prefix pfx, Long delta,
sewardj8d965312005-02-25 02:48:47 +00007211 HChar* opname, IROp op )
sewardj1001dc42005-02-21 08:25:55 +00007212{
7213 HChar dis_buf[50];
7214 Int alen;
7215 IRTemp addr;
7216 UChar rm = getUChar(delta);
7217 IRExpr* gpart = getXMMReg(gregOfRexRM(pfx,rm));
7218 if (epartIsReg(rm)) {
7219 putXMMReg( gregOfRexRM(pfx,rm),
7220 binop(op, gpart,
7221 getXMMReg(eregOfRexRM(pfx,rm))) );
7222 DIP("%s %s,%s\n", opname,
7223 nameXMMReg(eregOfRexRM(pfx,rm)),
7224 nameXMMReg(gregOfRexRM(pfx,rm)) );
7225 return delta+1;
7226 } else {
7227 /* We can only do a 64-bit memory read, so the upper half of the
7228 E operand needs to be made simply of zeroes. */
7229 IRTemp epart = newTemp(Ity_V128);
7230 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
7231 assign( epart, unop( Iop_64UtoV128,
7232 loadLE(Ity_I64, mkexpr(addr))) );
7233 putXMMReg( gregOfRexRM(pfx,rm),
7234 binop(op, gpart, mkexpr(epart)) );
7235 DIP("%s %s,%s\n", opname,
7236 dis_buf,
7237 nameXMMReg(gregOfRexRM(pfx,rm)) );
7238 return delta+alen;
7239 }
7240}
7241
7242
sewardja7ba8c42005-05-10 20:08:34 +00007243/* All lanes unary SSE operation, G = op(E). */
7244
7245static ULong dis_SSE_E_to_G_unary_all (
sewardj270def42005-07-03 01:03:01 +00007246 Prefix pfx, Long delta,
sewardja7ba8c42005-05-10 20:08:34 +00007247 HChar* opname, IROp op
7248 )
7249{
7250 HChar dis_buf[50];
7251 Int alen;
7252 IRTemp addr;
7253 UChar rm = getUChar(delta);
7254 if (epartIsReg(rm)) {
7255 putXMMReg( gregOfRexRM(pfx,rm),
7256 unop(op, getXMMReg(eregOfRexRM(pfx,rm))) );
7257 DIP("%s %s,%s\n", opname,
7258 nameXMMReg(eregOfRexRM(pfx,rm)),
7259 nameXMMReg(gregOfRexRM(pfx,rm)) );
7260 return delta+1;
7261 } else {
7262 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
7263 putXMMReg( gregOfRexRM(pfx,rm),
7264 unop(op, loadLE(Ity_V128, mkexpr(addr))) );
7265 DIP("%s %s,%s\n", opname,
7266 dis_buf,
7267 nameXMMReg(gregOfRexRM(pfx,rm)) );
7268 return delta+alen;
7269 }
7270}
7271
7272
7273/* Lowest 32-bit lane only unary SSE operation, G = op(E). */
7274
7275static ULong dis_SSE_E_to_G_unary_lo32 (
sewardj270def42005-07-03 01:03:01 +00007276 Prefix pfx, Long delta,
sewardja7ba8c42005-05-10 20:08:34 +00007277 HChar* opname, IROp op
7278 )
7279{
7280 /* First we need to get the old G value and patch the low 32 bits
7281 of the E operand into it. Then apply op and write back to G. */
7282 HChar dis_buf[50];
7283 Int alen;
7284 IRTemp addr;
7285 UChar rm = getUChar(delta);
7286 IRTemp oldG0 = newTemp(Ity_V128);
7287 IRTemp oldG1 = newTemp(Ity_V128);
7288
7289 assign( oldG0, getXMMReg(gregOfRexRM(pfx,rm)) );
7290
7291 if (epartIsReg(rm)) {
7292 assign( oldG1,
7293 binop( Iop_SetV128lo32,
7294 mkexpr(oldG0),
7295 getXMMRegLane32(eregOfRexRM(pfx,rm), 0)) );
7296 putXMMReg( gregOfRexRM(pfx,rm), unop(op, mkexpr(oldG1)) );
7297 DIP("%s %s,%s\n", opname,
7298 nameXMMReg(eregOfRexRM(pfx,rm)),
7299 nameXMMReg(gregOfRexRM(pfx,rm)) );
7300 return delta+1;
7301 } else {
7302 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
7303 assign( oldG1,
7304 binop( Iop_SetV128lo32,
7305 mkexpr(oldG0),
7306 loadLE(Ity_I32, mkexpr(addr)) ));
7307 putXMMReg( gregOfRexRM(pfx,rm), unop(op, mkexpr(oldG1)) );
7308 DIP("%s %s,%s\n", opname,
7309 dis_buf,
7310 nameXMMReg(gregOfRexRM(pfx,rm)) );
7311 return delta+alen;
7312 }
7313}
sewardj1001dc42005-02-21 08:25:55 +00007314
7315
7316/* Lowest 64-bit lane only unary SSE operation, G = op(E). */
7317
sewardj8d965312005-02-25 02:48:47 +00007318static ULong dis_SSE_E_to_G_unary_lo64 (
sewardj270def42005-07-03 01:03:01 +00007319 Prefix pfx, Long delta,
sewardj8d965312005-02-25 02:48:47 +00007320 HChar* opname, IROp op
7321 )
sewardj1001dc42005-02-21 08:25:55 +00007322{
7323 /* First we need to get the old G value and patch the low 64 bits
7324 of the E operand into it. Then apply op and write back to G. */
7325 HChar dis_buf[50];
7326 Int alen;
7327 IRTemp addr;
7328 UChar rm = getUChar(delta);
7329 IRTemp oldG0 = newTemp(Ity_V128);
7330 IRTemp oldG1 = newTemp(Ity_V128);
7331
7332 assign( oldG0, getXMMReg(gregOfRexRM(pfx,rm)) );
7333
7334 if (epartIsReg(rm)) {
7335 assign( oldG1,
7336 binop( Iop_SetV128lo64,
7337 mkexpr(oldG0),
7338 getXMMRegLane64(eregOfRexRM(pfx,rm), 0)) );
7339 putXMMReg( gregOfRexRM(pfx,rm), unop(op, mkexpr(oldG1)) );
7340 DIP("%s %s,%s\n", opname,
7341 nameXMMReg(eregOfRexRM(pfx,rm)),
7342 nameXMMReg(gregOfRexRM(pfx,rm)) );
7343 return delta+1;
7344 } else {
7345 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
7346 assign( oldG1,
7347 binop( Iop_SetV128lo64,
7348 mkexpr(oldG0),
7349 loadLE(Ity_I64, mkexpr(addr)) ));
7350 putXMMReg( gregOfRexRM(pfx,rm), unop(op, mkexpr(oldG1)) );
7351 DIP("%s %s,%s\n", opname,
7352 dis_buf,
7353 nameXMMReg(gregOfRexRM(pfx,rm)) );
7354 return delta+alen;
7355 }
7356}
7357
7358
sewardj09717342005-05-05 21:34:02 +00007359/* SSE integer binary operation:
7360 G = G `op` E (eLeft == False)
7361 G = E `op` G (eLeft == True)
7362*/
7363static ULong dis_SSEint_E_to_G(
sewardj270def42005-07-03 01:03:01 +00007364 Prefix pfx, Long delta,
sewardj09717342005-05-05 21:34:02 +00007365 HChar* opname, IROp op,
7366 Bool eLeft
7367 )
7368{
7369 HChar dis_buf[50];
7370 Int alen;
7371 IRTemp addr;
7372 UChar rm = getUChar(delta);
7373 IRExpr* gpart = getXMMReg(gregOfRexRM(pfx,rm));
7374 IRExpr* epart = NULL;
7375 if (epartIsReg(rm)) {
7376 epart = getXMMReg(eregOfRexRM(pfx,rm));
7377 DIP("%s %s,%s\n", opname,
7378 nameXMMReg(eregOfRexRM(pfx,rm)),
7379 nameXMMReg(gregOfRexRM(pfx,rm)) );
7380 delta += 1;
7381 } else {
7382 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
7383 epart = loadLE(Ity_V128, mkexpr(addr));
7384 DIP("%s %s,%s\n", opname,
7385 dis_buf,
7386 nameXMMReg(gregOfRexRM(pfx,rm)) );
7387 delta += alen;
7388 }
7389 putXMMReg( gregOfRexRM(pfx,rm),
7390 eLeft ? binop(op, epart, gpart)
7391 : binop(op, gpart, epart) );
7392 return delta;
7393}
sewardj8d965312005-02-25 02:48:47 +00007394
7395
7396/* Helper for doing SSE FP comparisons. */
7397
7398static void findSSECmpOp ( Bool* needNot, IROp* op,
7399 Int imm8, Bool all_lanes, Int sz )
7400{
7401 imm8 &= 7;
7402 *needNot = False;
7403 *op = Iop_INVALID;
7404 if (imm8 >= 4) {
7405 *needNot = True;
7406 imm8 -= 4;
7407 }
7408
7409 if (sz == 4 && all_lanes) {
7410 switch (imm8) {
7411 case 0: *op = Iop_CmpEQ32Fx4; return;
7412 case 1: *op = Iop_CmpLT32Fx4; return;
7413 case 2: *op = Iop_CmpLE32Fx4; return;
7414 case 3: *op = Iop_CmpUN32Fx4; return;
7415 default: break;
7416 }
7417 }
7418 if (sz == 4 && !all_lanes) {
7419 switch (imm8) {
7420 case 0: *op = Iop_CmpEQ32F0x4; return;
7421 case 1: *op = Iop_CmpLT32F0x4; return;
7422 case 2: *op = Iop_CmpLE32F0x4; return;
7423 case 3: *op = Iop_CmpUN32F0x4; return;
7424 default: break;
7425 }
7426 }
7427 if (sz == 8 && all_lanes) {
7428 switch (imm8) {
7429 case 0: *op = Iop_CmpEQ64Fx2; return;
7430 case 1: *op = Iop_CmpLT64Fx2; return;
7431 case 2: *op = Iop_CmpLE64Fx2; return;
7432 case 3: *op = Iop_CmpUN64Fx2; return;
7433 default: break;
7434 }
7435 }
7436 if (sz == 8 && !all_lanes) {
7437 switch (imm8) {
7438 case 0: *op = Iop_CmpEQ64F0x2; return;
7439 case 1: *op = Iop_CmpLT64F0x2; return;
7440 case 2: *op = Iop_CmpLE64F0x2; return;
7441 case 3: *op = Iop_CmpUN64F0x2; return;
7442 default: break;
7443 }
7444 }
7445 vpanic("findSSECmpOp(amd64,guest)");
7446}
7447
7448/* Handles SSE 32F comparisons. */
7449
sewardj270def42005-07-03 01:03:01 +00007450static ULong dis_SSEcmp_E_to_G ( Prefix pfx, Long delta,
sewardj8d965312005-02-25 02:48:47 +00007451 HChar* opname, Bool all_lanes, Int sz )
7452{
7453 HChar dis_buf[50];
7454 Int alen, imm8;
7455 IRTemp addr;
7456 Bool needNot = False;
7457 IROp op = Iop_INVALID;
7458 IRTemp plain = newTemp(Ity_V128);
7459 UChar rm = getUChar(delta);
7460 UShort mask = 0;
7461 vassert(sz == 4 || sz == 8);
7462 if (epartIsReg(rm)) {
7463 imm8 = getUChar(delta+1);
7464 findSSECmpOp(&needNot, &op, imm8, all_lanes, sz);
7465 assign( plain, binop(op, getXMMReg(gregOfRexRM(pfx,rm)),
7466 getXMMReg(eregOfRexRM(pfx,rm))) );
7467 delta += 2;
7468 DIP("%s $%d,%s,%s\n", opname,
7469 (Int)imm8,
7470 nameXMMReg(eregOfRexRM(pfx,rm)),
7471 nameXMMReg(gregOfRexRM(pfx,rm)) );
7472 } else {
7473 addr = disAMode ( &alen, pfx, delta, dis_buf, 1 );
7474 imm8 = getUChar(delta+alen);
7475 findSSECmpOp(&needNot, &op, imm8, all_lanes, sz);
7476 assign( plain, binop(op, getXMMReg(gregOfRexRM(pfx,rm)),
7477 loadLE(Ity_V128, mkexpr(addr))) );
7478 delta += alen+1;
7479 DIP("%s $%d,%s,%s\n", opname,
7480 (Int)imm8,
7481 dis_buf,
7482 nameXMMReg(gregOfRexRM(pfx,rm)) );
7483 }
7484
7485 if (needNot && all_lanes) {
sewardj9c9ee3d2005-02-26 01:17:42 +00007486 putXMMReg( gregOfRexRM(pfx,rm),
sewardj8d965312005-02-25 02:48:47 +00007487 unop(Iop_NotV128, mkexpr(plain)) );
7488 }
7489 else
7490 if (needNot && !all_lanes) {
sewardj1027dc22005-02-26 01:55:02 +00007491 mask = toUShort(sz==4 ? 0x000F : 0x00FF);
sewardj8d965312005-02-25 02:48:47 +00007492 putXMMReg( gregOfRexRM(pfx,rm),
7493 binop(Iop_XorV128, mkexpr(plain), mkV128(mask)) );
7494 }
7495 else {
7496 putXMMReg( gregOfRexRM(pfx,rm), mkexpr(plain) );
7497 }
7498
7499 return delta;
7500}
7501
7502
sewardjadffcef2005-05-11 00:03:06 +00007503/* Vector by scalar shift of G by the amount specified at the bottom
7504 of E. */
7505
sewardj270def42005-07-03 01:03:01 +00007506static ULong dis_SSE_shiftG_byE ( Prefix pfx, Long delta,
sewardjadffcef2005-05-11 00:03:06 +00007507 HChar* opname, IROp op )
7508{
7509 HChar dis_buf[50];
7510 Int alen, size;
7511 IRTemp addr;
7512 Bool shl, shr, sar;
7513 UChar rm = getUChar(delta);
7514 IRTemp g0 = newTemp(Ity_V128);
7515 IRTemp g1 = newTemp(Ity_V128);
7516 IRTemp amt = newTemp(Ity_I32);
7517 IRTemp amt8 = newTemp(Ity_I8);
7518 if (epartIsReg(rm)) {
7519 assign( amt, getXMMRegLane32(eregOfRexRM(pfx,rm), 0) );
7520 DIP("%s %s,%s\n", opname,
7521 nameXMMReg(eregOfRexRM(pfx,rm)),
7522 nameXMMReg(gregOfRexRM(pfx,rm)) );
7523 delta++;
7524 } else {
7525 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
7526 assign( amt, loadLE(Ity_I32, mkexpr(addr)) );
7527 DIP("%s %s,%s\n", opname,
7528 dis_buf,
7529 nameXMMReg(gregOfRexRM(pfx,rm)) );
7530 delta += alen;
7531 }
7532 assign( g0, getXMMReg(gregOfRexRM(pfx,rm)) );
7533 assign( amt8, unop(Iop_32to8, mkexpr(amt)) );
7534
7535 shl = shr = sar = False;
7536 size = 0;
7537 switch (op) {
7538 case Iop_ShlN16x8: shl = True; size = 32; break;
7539 case Iop_ShlN32x4: shl = True; size = 32; break;
7540 case Iop_ShlN64x2: shl = True; size = 64; break;
7541 case Iop_SarN16x8: sar = True; size = 16; break;
7542 case Iop_SarN32x4: sar = True; size = 32; break;
7543 case Iop_ShrN16x8: shr = True; size = 16; break;
7544 case Iop_ShrN32x4: shr = True; size = 32; break;
7545 case Iop_ShrN64x2: shr = True; size = 64; break;
7546 default: vassert(0);
7547 }
7548
7549 if (shl || shr) {
7550 assign(
7551 g1,
7552 IRExpr_Mux0X(
7553 unop(Iop_1Uto8,
7554 binop(Iop_CmpLT64U, unop(Iop_32Uto64,mkexpr(amt)), mkU64(size))),
7555 mkV128(0x0000),
7556 binop(op, mkexpr(g0), mkexpr(amt8))
7557 )
7558 );
7559 } else
7560 if (sar) {
7561 assign(
7562 g1,
7563 IRExpr_Mux0X(
7564 unop(Iop_1Uto8,
7565 binop(Iop_CmpLT64U, unop(Iop_32Uto64,mkexpr(amt)), mkU64(size))),
7566 binop(op, mkexpr(g0), mkU8(size-1)),
7567 binop(op, mkexpr(g0), mkexpr(amt8))
7568 )
7569 );
7570 } else {
7571 vassert(0);
7572 }
7573
7574 putXMMReg( gregOfRexRM(pfx,rm), mkexpr(g1) );
7575 return delta;
7576}
sewardj09717342005-05-05 21:34:02 +00007577
7578
7579/* Vector by scalar shift of E by an immediate byte. */
7580
7581static
7582ULong dis_SSE_shiftE_imm ( Prefix pfx,
sewardj270def42005-07-03 01:03:01 +00007583 Long delta, HChar* opname, IROp op )
sewardj09717342005-05-05 21:34:02 +00007584{
7585 Bool shl, shr, sar;
7586 UChar rm = getUChar(delta);
7587 IRTemp e0 = newTemp(Ity_V128);
7588 IRTemp e1 = newTemp(Ity_V128);
7589 UChar amt, size;
7590 vassert(epartIsReg(rm));
7591 vassert(gregLO3ofRM(rm) == 2
7592 || gregLO3ofRM(rm) == 4 || gregLO3ofRM(rm) == 6);
sewardjca673ab2005-05-11 10:03:08 +00007593 amt = getUChar(delta+1);
sewardj09717342005-05-05 21:34:02 +00007594 delta += 2;
7595 DIP("%s $%d,%s\n", opname,
7596 (Int)amt,
7597 nameXMMReg(eregOfRexRM(pfx,rm)) );
7598 assign( e0, getXMMReg(eregOfRexRM(pfx,rm)) );
7599
7600 shl = shr = sar = False;
7601 size = 0;
7602 switch (op) {
7603 case Iop_ShlN16x8: shl = True; size = 16; break;
7604 case Iop_ShlN32x4: shl = True; size = 32; break;
7605 case Iop_ShlN64x2: shl = True; size = 64; break;
7606 case Iop_SarN16x8: sar = True; size = 16; break;
7607 case Iop_SarN32x4: sar = True; size = 32; break;
7608 case Iop_ShrN16x8: shr = True; size = 16; break;
7609 case Iop_ShrN32x4: shr = True; size = 32; break;
7610 case Iop_ShrN64x2: shr = True; size = 64; break;
7611 default: vassert(0);
7612 }
7613
7614 if (shl || shr) {
7615 assign( e1, amt >= size
7616 ? mkV128(0x0000)
7617 : binop(op, mkexpr(e0), mkU8(amt))
7618 );
7619 } else
7620 if (sar) {
7621 assign( e1, amt >= size
7622 ? binop(op, mkexpr(e0), mkU8(size-1))
7623 : binop(op, mkexpr(e0), mkU8(amt))
7624 );
7625 } else {
7626 vassert(0);
7627 }
7628
7629 putXMMReg( eregOfRexRM(pfx,rm), mkexpr(e1) );
7630 return delta;
7631}
sewardj1a01e652005-02-23 11:39:21 +00007632
7633
7634/* Get the current SSE rounding mode. */
7635
7636static IRExpr* /* :: Ity_I32 */ get_sse_roundingmode ( void )
7637{
7638 return
7639 unop( Iop_64to32,
7640 binop( Iop_And64,
7641 IRExpr_Get( OFFB_SSEROUND, Ity_I64 ),
7642 mkU64(3) ));
7643}
7644
sewardjbcbb9de2005-03-27 02:22:32 +00007645static void put_sse_roundingmode ( IRExpr* sseround )
7646{
7647 vassert(typeOfIRExpr(irbb->tyenv, sseround) == Ity_I32);
7648 stmt( IRStmt_Put( OFFB_SSEROUND,
7649 unop(Iop_32Uto64,sseround) ) );
7650}
7651
sewardja7ba8c42005-05-10 20:08:34 +00007652/* Break a 128-bit value up into four 32-bit ints. */
7653
7654static void breakup128to32s ( IRTemp t128,
7655 /*OUTs*/
7656 IRTemp* t3, IRTemp* t2,
7657 IRTemp* t1, IRTemp* t0 )
7658{
7659 IRTemp hi64 = newTemp(Ity_I64);
7660 IRTemp lo64 = newTemp(Ity_I64);
7661 assign( hi64, unop(Iop_V128HIto64, mkexpr(t128)) );
7662 assign( lo64, unop(Iop_V128to64, mkexpr(t128)) );
7663
7664 vassert(t0 && *t0 == IRTemp_INVALID);
7665 vassert(t1 && *t1 == IRTemp_INVALID);
7666 vassert(t2 && *t2 == IRTemp_INVALID);
7667 vassert(t3 && *t3 == IRTemp_INVALID);
7668
7669 *t0 = newTemp(Ity_I32);
7670 *t1 = newTemp(Ity_I32);
7671 *t2 = newTemp(Ity_I32);
7672 *t3 = newTemp(Ity_I32);
7673 assign( *t0, unop(Iop_64to32, mkexpr(lo64)) );
7674 assign( *t1, unop(Iop_64HIto32, mkexpr(lo64)) );
7675 assign( *t2, unop(Iop_64to32, mkexpr(hi64)) );
7676 assign( *t3, unop(Iop_64HIto32, mkexpr(hi64)) );
7677}
7678
7679/* Construct a 128-bit value from four 32-bit ints. */
7680
7681static IRExpr* mk128from32s ( IRTemp t3, IRTemp t2,
7682 IRTemp t1, IRTemp t0 )
7683{
7684 return
7685 binop( Iop_64HLtoV128,
7686 binop(Iop_32HLto64, mkexpr(t3), mkexpr(t2)),
7687 binop(Iop_32HLto64, mkexpr(t1), mkexpr(t0))
7688 );
7689}
7690
7691/* Break a 64-bit value up into four 16-bit ints. */
7692
7693static void breakup64to16s ( IRTemp t64,
7694 /*OUTs*/
7695 IRTemp* t3, IRTemp* t2,
7696 IRTemp* t1, IRTemp* t0 )
7697{
7698 IRTemp hi32 = newTemp(Ity_I32);
7699 IRTemp lo32 = newTemp(Ity_I32);
7700 assign( hi32, unop(Iop_64HIto32, mkexpr(t64)) );
7701 assign( lo32, unop(Iop_64to32, mkexpr(t64)) );
7702
7703 vassert(t0 && *t0 == IRTemp_INVALID);
7704 vassert(t1 && *t1 == IRTemp_INVALID);
7705 vassert(t2 && *t2 == IRTemp_INVALID);
7706 vassert(t3 && *t3 == IRTemp_INVALID);
7707
7708 *t0 = newTemp(Ity_I16);
7709 *t1 = newTemp(Ity_I16);
7710 *t2 = newTemp(Ity_I16);
7711 *t3 = newTemp(Ity_I16);
7712 assign( *t0, unop(Iop_32to16, mkexpr(lo32)) );
7713 assign( *t1, unop(Iop_32HIto16, mkexpr(lo32)) );
7714 assign( *t2, unop(Iop_32to16, mkexpr(hi32)) );
7715 assign( *t3, unop(Iop_32HIto16, mkexpr(hi32)) );
7716}
7717
7718/* Construct a 64-bit value from four 16-bit ints. */
7719
7720static IRExpr* mk64from16s ( IRTemp t3, IRTemp t2,
7721 IRTemp t1, IRTemp t0 )
7722{
7723 return
7724 binop( Iop_32HLto64,
7725 binop(Iop_16HLto32, mkexpr(t3), mkexpr(t2)),
7726 binop(Iop_16HLto32, mkexpr(t1), mkexpr(t0))
7727 );
7728}
sewardjdf0e0022005-01-25 15:48:43 +00007729
7730
7731/*------------------------------------------------------------*/
7732/*--- Disassemble a single instruction ---*/
7733/*------------------------------------------------------------*/
7734
sewardj9e6491a2005-07-02 19:24:10 +00007735/* Disassemble a single instruction into IR. The instruction is
7736 located in host memory at &guest_code[delta]. */
sewardjdf0e0022005-01-25 15:48:43 +00007737
sewardj9e6491a2005-07-02 19:24:10 +00007738static
7739DisResult disInstr_AMD64_WRK (
7740 Bool put_IP,
7741 Bool (*resteerOkFn) ( Addr64 ),
7742 Long delta64,
7743 VexArchInfo* archinfo
7744 )
sewardjdf0e0022005-01-25 15:48:43 +00007745{
7746 IRType ty;
sewardja7ba8c42005-05-10 20:08:34 +00007747 IRTemp addr, t0, t1, t2, t3, t4, t5, t6;
sewardjdf0e0022005-01-25 15:48:43 +00007748 Int alen;
sewardj7a240552005-01-28 21:37:12 +00007749 UChar opc, modrm, /*abyte,*/ pre;
sewardj1027dc22005-02-26 01:55:02 +00007750 Long d64;
sewardjdf0e0022005-01-25 15:48:43 +00007751 HChar dis_buf[50];
7752 Int am_sz, d_sz, n, n_prefixes;
sewardj9e6491a2005-07-02 19:24:10 +00007753 DisResult dres;
sewardja6b93d12005-02-17 09:28:28 +00007754 UChar* insn; /* used in SSE decoders */
sewardjdf0e0022005-01-25 15:48:43 +00007755
sewardj9e6491a2005-07-02 19:24:10 +00007756 /* The running delta */
7757 Long delta = delta64;
7758
sewardjdf0e0022005-01-25 15:48:43 +00007759 /* Holds eip at the start of the insn, so that we can print
7760 consistent error messages for unimplemented insns. */
sewardj270def42005-07-03 01:03:01 +00007761 Long delta_start = delta;
sewardjdf0e0022005-01-25 15:48:43 +00007762
7763 /* sz denotes the nominal data-op size of the insn; we change it to
7764 2 if an 0x66 prefix is seen and 8 if REX.W is 1. In case of
7765 conflict REX.W takes precedence. */
7766 Int sz = 4;
7767
sewardj3ca55a12005-01-27 16:06:23 +00007768 /* pfx holds the summary of prefixes. */
7769 Prefix pfx = PFX_EMPTY;
sewardjdf0e0022005-01-25 15:48:43 +00007770
sewardj9e6491a2005-07-02 19:24:10 +00007771 /* Set result defaults. */
7772 dres.whatNext = Dis_Continue;
7773 dres.len = 0;
7774 dres.continueAt = 0;
sewardjdf0e0022005-01-25 15:48:43 +00007775
sewardj9e6491a2005-07-02 19:24:10 +00007776 vassert(guest_RIP_next_assumed == 0);
7777 vassert(guest_RIP_next_mustcheck == False);
sewardj4b744762005-02-07 15:02:25 +00007778
sewardja7ba8c42005-05-10 20:08:34 +00007779 addr = t0 = t1 = t2 = t3 = t4 = t5 = t6 = IRTemp_INVALID;
sewardjdf0e0022005-01-25 15:48:43 +00007780
sewardj9e6491a2005-07-02 19:24:10 +00007781 DIP("\t0x%llx: ", guest_RIP_bbstart+delta);
7782
7783 /* We may be asked to update the guest RIP before going further. */
7784 if (put_IP)
7785 stmt( IRStmt_Put( OFFB_RIP, mkU64(guest_RIP_curr_instr)) );
sewardjdf0e0022005-01-25 15:48:43 +00007786
7787 /* Spot the client-request magic sequence. */
7788 {
7789 UChar* code = (UChar*)(guest_code + delta);
7790 /* Spot this:
7791 C1C01D roll $29, %eax
7792 C1C003 roll $3, %eax
7793 C1C81B rorl $27, %eax
7794 C1C805 rorl $5, %eax
7795 C1C00D roll $13, %eax
7796 C1C013 roll $19, %eax
7797 */
7798 if (code[ 0] == 0xC1 && code[ 1] == 0xC0 && code[ 2] == 0x1D &&
7799 code[ 3] == 0xC1 && code[ 4] == 0xC0 && code[ 5] == 0x03 &&
7800 code[ 6] == 0xC1 && code[ 7] == 0xC8 && code[ 8] == 0x1B &&
7801 code[ 9] == 0xC1 && code[10] == 0xC8 && code[11] == 0x05 &&
7802 code[12] == 0xC1 && code[13] == 0xC0 && code[14] == 0x0D &&
7803 code[15] == 0xC1 && code[16] == 0xC0 && code[17] == 0x13
7804 ) {
7805 DIP("%%edx = client_request ( %%eax )\n");
7806 delta += 18;
sewardj9e6491a2005-07-02 19:24:10 +00007807 jmp_lit(Ijk_ClientReq, guest_RIP_bbstart+delta);
7808 dres.whatNext = Dis_StopHere;
sewardjdf0e0022005-01-25 15:48:43 +00007809 goto decode_success;
7810 }
7811 }
7812
7813 /* Eat prefixes, summarising the result in pfx and sz, and rejecting
7814 as many invalid combinations as possible. */
7815 n_prefixes = 0;
7816 while (True) {
7817 if (n_prefixes > 5) goto decode_failure;
sewardj8c332e22005-01-28 01:36:56 +00007818 pre = getUChar(delta);
sewardjdf0e0022005-01-25 15:48:43 +00007819 switch (pre) {
7820 case 0x66: pfx |= PFX_66; break;
7821 case 0x67: pfx |= PFX_ASO; break;
7822 case 0xF2: pfx |= PFX_F2; break;
7823 case 0xF3: pfx |= PFX_F3; break;
7824 case 0xF0: pfx |= PFX_LOCK; break;
7825 case 0x2E: pfx |= PFX_CS; break;
7826 case 0x3E: pfx |= PFX_DS; break;
7827 case 0x26: pfx |= PFX_ES; break;
7828 case 0x64: pfx |= PFX_FS; break;
7829 case 0x65: pfx |= PFX_GS; break;
7830 case 0x36: pfx |= PFX_SS; break;
7831 case 0x40 ... 0x4F:
7832 pfx |= PFX_REX;
7833 if (pre & (1<<3)) pfx |= PFX_REXW;
7834 if (pre & (1<<2)) pfx |= PFX_REXR;
7835 if (pre & (1<<1)) pfx |= PFX_REXX;
7836 if (pre & (1<<0)) pfx |= PFX_REXB;
7837 break;
7838 default:
7839 goto not_a_prefix;
7840 }
7841 n_prefixes++;
7842 delta++;
7843 }
7844
7845 not_a_prefix:
7846 /* Dump invalid combinations */
sewardj3ca55a12005-01-27 16:06:23 +00007847 if (pfx & PFX_ASO)
7848 goto decode_failure; /* don't support address-size override */
sewardjdf0e0022005-01-25 15:48:43 +00007849
7850 n = 0;
7851 if (pfx & PFX_F2) n++;
7852 if (pfx & PFX_F3) n++;
sewardj3ca55a12005-01-27 16:06:23 +00007853 if (n > 1)
7854 goto decode_failure; /* can't have both */
sewardjdf0e0022005-01-25 15:48:43 +00007855
7856 n = 0;
7857 if (pfx & PFX_CS) n++;
7858 if (pfx & PFX_DS) n++;
7859 if (pfx & PFX_ES) n++;
7860 if (pfx & PFX_FS) n++;
7861 if (pfx & PFX_GS) n++;
7862 if (pfx & PFX_SS) n++;
sewardj3ca55a12005-01-27 16:06:23 +00007863 if (n > 1)
7864 goto decode_failure; /* multiple seg overrides == illegal */
sewardjdf0e0022005-01-25 15:48:43 +00007865
7866 /* Set up sz. */
7867 sz = 4;
7868 if (pfx & PFX_66) sz = 2;
7869 if ((pfx & PFX_REX) && (pfx & PFX_REXW)) sz = 8;
7870
sewardj9ff93bc2005-03-23 11:25:12 +00007871 /* Kludge re LOCK prefixes. We assume here that all code generated
7872 by Vex is going to be run in a single-threaded context, in other
7873 words that concurrent executions of Vex-generated translations
7874 will not happen. That is certainly the case for how the
7875 Valgrind-3.0 code line uses Vex. Given that assumption, it
7876 seems safe to ignore LOCK prefixes since there will never be any
7877 other thread running at the same time as this one. However, at
7878 least emit a memory fence on the basis that it would at least be
7879 prudent to flush any memory transactions from this thread as far
7880 as possible down the memory hierarchy. */
7881 if (pfx & PFX_LOCK) {
7882 /* vex_printf("vex amd64->IR: ignoring LOCK prefix on: ");
7883 insn_verbose = True; */
7884 stmt( IRStmt_MFence() );
sewardjdf0e0022005-01-25 15:48:43 +00007885 }
7886
sewardja6b93d12005-02-17 09:28:28 +00007887
7888 /* ---------------------------------------------------- */
sewardj09717342005-05-05 21:34:02 +00007889 /* --- The SSE/SSE2 decoder. --- */
sewardja6b93d12005-02-17 09:28:28 +00007890 /* ---------------------------------------------------- */
7891
7892 /* What did I do to deserve SSE ? Perhaps I was really bad in a
7893 previous life? */
7894
sewardj09717342005-05-05 21:34:02 +00007895 /* Note, this doesn't handle SSE3 right now. All amd64s support
7896 SSE2 as a minimum so there is no point distinguishing SSE1 vs
7897 SSE2. */
7898
sewardja6b93d12005-02-17 09:28:28 +00007899 insn = (UChar*)&guest_code[delta];
7900
sewardjd20c8852005-01-20 20:04:07 +00007901//.. /* Treat fxsave specially. It should be doable even on an SSE0
7902//.. (Pentium-II class) CPU. Hence be prepared to handle it on
7903//.. any subarchitecture variant.
7904//.. */
7905//..
7906//.. /* 0F AE /0 = FXSAVE m512 -- write x87 and SSE state to memory */
7907//.. if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xAE
7908//.. && !epartIsReg(insn[2]) && gregOfRM(insn[2]) == 0) {
sewardj8c332e22005-01-28 01:36:56 +00007909//.. modrm = getUChar(delta+2);
sewardjd20c8852005-01-20 20:04:07 +00007910//.. vassert(sz == 4);
7911//.. vassert(!epartIsReg(modrm));
7912//..
7913//.. addr = disAMode ( &alen, sorb, delta+2, dis_buf );
7914//.. delta += 2+alen;
7915//..
7916//.. DIP("fxsave %s\n", dis_buf);
7917//..
7918//.. /* Uses dirty helper:
7919//.. void x86g_do_FXSAVE ( VexGuestX86State*, UInt ) */
7920//.. IRDirty* d = unsafeIRDirty_0_N (
7921//.. 0/*regparms*/,
7922//.. "x86g_dirtyhelper_FXSAVE",
7923//.. &x86g_dirtyhelper_FXSAVE,
7924//.. mkIRExprVec_1( mkexpr(addr) )
7925//.. );
7926//.. d->needsBBP = True;
7927//..
7928//.. /* declare we're writing memory */
7929//.. d->mFx = Ifx_Write;
7930//.. d->mAddr = mkexpr(addr);
7931//.. d->mSize = 512;
7932//..
7933//.. /* declare we're reading guest state */
7934//.. d->nFxState = 7;
7935//..
7936//.. d->fxState[0].fx = Ifx_Read;
7937//.. d->fxState[0].offset = OFFB_FTOP;
7938//.. d->fxState[0].size = sizeof(UInt);
7939//..
7940//.. d->fxState[1].fx = Ifx_Read;
7941//.. d->fxState[1].offset = OFFB_FPREGS;
7942//.. d->fxState[1].size = 8 * sizeof(ULong);
7943//..
7944//.. d->fxState[2].fx = Ifx_Read;
7945//.. d->fxState[2].offset = OFFB_FPTAGS;
7946//.. d->fxState[2].size = 8 * sizeof(UChar);
7947//..
7948//.. d->fxState[3].fx = Ifx_Read;
7949//.. d->fxState[3].offset = OFFB_FPROUND;
7950//.. d->fxState[3].size = sizeof(UInt);
7951//..
7952//.. d->fxState[4].fx = Ifx_Read;
7953//.. d->fxState[4].offset = OFFB_FC3210;
7954//.. d->fxState[4].size = sizeof(UInt);
7955//..
7956//.. d->fxState[5].fx = Ifx_Read;
7957//.. d->fxState[5].offset = OFFB_XMM0;
7958//.. d->fxState[5].size = 8 * sizeof(U128);
7959//..
7960//.. d->fxState[6].fx = Ifx_Read;
7961//.. d->fxState[6].offset = OFFB_SSEROUND;
7962//.. d->fxState[6].size = sizeof(UInt);
7963//..
7964//.. /* Be paranoid ... this assertion tries to ensure the 8 %xmm
7965//.. images are packed back-to-back. If not, the value of
7966//.. d->fxState[5].size is wrong. */
7967//.. vassert(16 == sizeof(U128));
7968//.. vassert(OFFB_XMM7 == (OFFB_XMM0 + 7 * 16));
7969//..
7970//.. stmt( IRStmt_Dirty(d) );
7971//..
7972//.. goto decode_success;
7973//.. }
7974//..
7975//.. /* ------ SSE decoder main ------ */
7976//..
7977//.. /* Skip parts of the decoder which don't apply given the stated
7978//.. guest subarchitecture. */
7979//.. if (subarch == VexSubArchX86_sse0)
7980//.. goto after_sse_decoders;
7981//..
7982//.. /* Otherwise we must be doing sse1 or sse2, so we can at least try
7983//.. for SSE1 here. */
sewardj432f8b62005-05-10 02:50:05 +00007984
7985 /* 0F 58 = ADDPS -- add 32Fx4 from R/M to R */
7986 if (haveNo66noF2noF3(pfx) && sz == 4
7987 && insn[0] == 0x0F && insn[1] == 0x58) {
7988 delta = dis_SSE_E_to_G_all( pfx, delta+2, "addps", Iop_Add32Fx4 );
7989 goto decode_success;
7990 }
sewardj8d965312005-02-25 02:48:47 +00007991
7992 /* F3 0F 58 = ADDSS -- add 32F0x4 from R/M to R */
7993 if (haveF3no66noF2(pfx) && sz == 4
7994 && insn[0] == 0x0F && insn[1] == 0x58) {
7995 delta = dis_SSE_E_to_G_lo32( pfx, delta+2, "addss", Iop_Add32F0x4 );
7996 goto decode_success;
7997 }
7998
sewardj3aba9eb2005-03-30 23:20:47 +00007999 /* 0F 55 = ANDNPS -- G = (not G) and E */
8000 if (haveNo66noF2noF3(pfx) && sz == 4
8001 && insn[0] == 0x0F && insn[1] == 0x55) {
8002 delta = dis_SSE_E_to_G_all_invG( pfx, delta+2, "andnps", Iop_AndV128 );
8003 goto decode_success;
8004 }
sewardj37d52572005-02-25 14:22:12 +00008005
8006 /* 0F 54 = ANDPS -- G = G and E */
8007 if (haveNo66noF2noF3(pfx) && sz == 4
8008 && insn[0] == 0x0F && insn[1] == 0x54) {
8009 delta = dis_SSE_E_to_G_all( pfx, delta+2, "andps", Iop_AndV128 );
8010 goto decode_success;
8011 }
8012
sewardj432f8b62005-05-10 02:50:05 +00008013 /* 0F C2 = CMPPS -- 32Fx4 comparison from R/M to R */
8014 if (haveNo66noF2noF3(pfx) && sz == 4
8015 && insn[0] == 0x0F && insn[1] == 0xC2) {
8016 delta = dis_SSEcmp_E_to_G( pfx, delta+2, "cmpps", True, 4 );
8017 goto decode_success;
8018 }
sewardj3aba9eb2005-03-30 23:20:47 +00008019
8020 /* F3 0F C2 = CMPSS -- 32F0x4 comparison from R/M to R */
8021 if (haveF3no66noF2(pfx) && sz == 4
8022 && insn[0] == 0x0F && insn[1] == 0xC2) {
8023 delta = dis_SSEcmp_E_to_G( pfx, delta+2, "cmpss", False, 4 );
8024 goto decode_success;
8025 }
sewardjc49ce232005-02-25 13:03:03 +00008026
8027 /* 0F 2F = COMISS -- 32F0x4 comparison G,E, and set ZCP */
8028 /* 0F 2E = UCOMISS -- 32F0x4 comparison G,E, and set ZCP */
8029 if (haveNo66noF2noF3(pfx) && sz == 4
8030 && insn[0] == 0x0F && (insn[1] == 0x2F || insn[1] == 0x2E)) {
8031 IRTemp argL = newTemp(Ity_F32);
8032 IRTemp argR = newTemp(Ity_F32);
8033 modrm = getUChar(delta+2);
8034 if (epartIsReg(modrm)) {
8035 assign( argR, getXMMRegLane32F( eregOfRexRM(pfx,modrm),
8036 0/*lowest lane*/ ) );
8037 delta += 2+1;
8038 DIP("%scomiss %s,%s\n", insn[1]==0x2E ? "u" : "",
8039 nameXMMReg(eregOfRexRM(pfx,modrm)),
8040 nameXMMReg(gregOfRexRM(pfx,modrm)) );
8041 } else {
8042 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8043 assign( argR, loadLE(Ity_F32, mkexpr(addr)) );
8044 delta += 2+alen;
8045 DIP("%scomiss %s,%s\n", insn[1]==0x2E ? "u" : "",
8046 dis_buf,
8047 nameXMMReg(gregOfRexRM(pfx,modrm)) );
8048 }
8049 assign( argL, getXMMRegLane32F( gregOfRexRM(pfx,modrm),
8050 0/*lowest lane*/ ) );
8051
8052 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(AMD64G_CC_OP_COPY) ));
8053 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
8054 stmt( IRStmt_Put(
8055 OFFB_CC_DEP1,
8056 binop( Iop_And64,
8057 unop( Iop_32Uto64,
8058 binop(Iop_CmpF64,
8059 unop(Iop_F32toF64,mkexpr(argL)),
8060 unop(Iop_F32toF64,mkexpr(argR)))),
8061 mkU64(0x45)
8062 )));
8063
8064 goto decode_success;
8065 }
8066
sewardj432f8b62005-05-10 02:50:05 +00008067 /* 0F 2A = CVTPI2PS -- convert 2 x I32 in mem/mmx to 2 x F32 in low
8068 half xmm */
8069 if (haveNo66noF2noF3(pfx) && sz == 4
8070 && insn[0] == 0x0F && insn[1] == 0x2A) {
8071 IRTemp arg64 = newTemp(Ity_I64);
8072 IRTemp rmode = newTemp(Ity_I32);
8073
8074 modrm = getUChar(delta+2);
8075 do_MMX_preamble();
8076 if (epartIsReg(modrm)) {
8077 assign( arg64, getMMXReg(eregLO3ofRM(modrm)) );
8078 delta += 2+1;
8079 DIP("cvtpi2ps %s,%s\n", nameMMXReg(eregLO3ofRM(modrm)),
8080 nameXMMReg(gregOfRexRM(pfx,modrm)));
8081 } else {
8082 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8083 assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
8084 delta += 2+alen;
8085 DIP("cvtpi2ps %s,%s\n", dis_buf,
8086 nameXMMReg(gregOfRexRM(pfx,modrm)) );
8087 }
8088
8089 assign( rmode, get_sse_roundingmode() );
8090
8091 putXMMRegLane32F(
8092 gregOfRexRM(pfx,modrm), 0,
8093 binop(Iop_F64toF32,
8094 mkexpr(rmode),
8095 unop(Iop_I32toF64,
8096 unop(Iop_64to32, mkexpr(arg64)) )) );
8097
8098 putXMMRegLane32F(
8099 gregOfRexRM(pfx,modrm), 1,
8100 binop(Iop_F64toF32,
8101 mkexpr(rmode),
8102 unop(Iop_I32toF64,
8103 unop(Iop_64HIto32, mkexpr(arg64)) )) );
8104
8105 goto decode_success;
8106 }
sewardj8d965312005-02-25 02:48:47 +00008107
8108 /* F3 0F 2A = CVTSI2SS
8109 -- sz==4: convert I32 in mem/ireg to F32 in low quarter xmm
8110 -- sz==8: convert I64 in mem/ireg to F32 in low quarter xmm */
8111 if (haveF3no66noF2(pfx) && (sz == 4 || sz == 8)
8112 && insn[0] == 0x0F && insn[1] == 0x2A) {
8113
8114 IRTemp rmode = newTemp(Ity_I32);
8115 assign( rmode, get_sse_roundingmode() );
8116 modrm = getUChar(delta+2);
8117
8118 if (sz == 4) {
8119 IRTemp arg32 = newTemp(Ity_I32);
8120 if (epartIsReg(modrm)) {
sewardj5b470602005-02-27 13:10:48 +00008121 assign( arg32, getIReg32(eregOfRexRM(pfx,modrm)) );
sewardj8d965312005-02-25 02:48:47 +00008122 delta += 2+1;
sewardj5b470602005-02-27 13:10:48 +00008123 DIP("cvtsi2ss %s,%s\n", nameIReg32(eregOfRexRM(pfx,modrm)),
sewardj8d965312005-02-25 02:48:47 +00008124 nameXMMReg(gregOfRexRM(pfx,modrm)));
8125 } else {
sewardj8d965312005-02-25 02:48:47 +00008126 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8127 assign( arg32, loadLE(Ity_I32, mkexpr(addr)) );
8128 delta += 2+alen;
8129 DIP("cvtsi2ss %s,%s\n", dis_buf,
8130 nameXMMReg(gregOfRexRM(pfx,modrm)) );
8131 }
8132 putXMMRegLane32F(
8133 gregOfRexRM(pfx,modrm), 0,
8134 binop(Iop_F64toF32,
8135 mkexpr(rmode),
8136 unop(Iop_I32toF64, mkexpr(arg32)) ) );
8137 } else {
8138 /* sz == 8 */
8139 IRTemp arg64 = newTemp(Ity_I64);
8140 if (epartIsReg(modrm)) {
sewardj5b470602005-02-27 13:10:48 +00008141 assign( arg64, getIReg64(eregOfRexRM(pfx,modrm)) );
sewardj8d965312005-02-25 02:48:47 +00008142 delta += 2+1;
sewardj5b470602005-02-27 13:10:48 +00008143 DIP("cvtsi2ssq %s,%s\n", nameIReg64(eregOfRexRM(pfx,modrm)),
sewardj8d965312005-02-25 02:48:47 +00008144 nameXMMReg(gregOfRexRM(pfx,modrm)));
8145 } else {
sewardj82c9f2f2005-03-02 16:05:13 +00008146 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8147 assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
8148 delta += 2+alen;
8149 DIP("cvtsi2ssq %s,%s\n", dis_buf,
8150 nameXMMReg(gregOfRexRM(pfx,modrm)) );
sewardj8d965312005-02-25 02:48:47 +00008151 }
8152 putXMMRegLane32F(
8153 gregOfRexRM(pfx,modrm), 0,
8154 binop(Iop_F64toF32,
8155 mkexpr(rmode),
8156 binop(Iop_I64toF64, mkexpr(rmode), mkexpr(arg64)) ) );
8157 }
8158
8159 goto decode_success;
8160 }
8161
sewardj432f8b62005-05-10 02:50:05 +00008162 /* 0F 2D = CVTPS2PI -- convert 2 x F32 in mem/low half xmm to 2 x
8163 I32 in mmx, according to prevailing SSE rounding mode */
sewardja7ba8c42005-05-10 20:08:34 +00008164 /* 0F 2C = CVTTPS2PI -- convert 2 x F32 in mem/low half xmm to 2 x
8165 I32 in mmx, rounding towards zero */
sewardj432f8b62005-05-10 02:50:05 +00008166 if (haveNo66noF2noF3(pfx) && sz == 4
sewardja7ba8c42005-05-10 20:08:34 +00008167 && insn[0] == 0x0F && (insn[1] == 0x2D || insn[1] == 0x2C)) {
sewardj432f8b62005-05-10 02:50:05 +00008168 IRTemp dst64 = newTemp(Ity_I64);
8169 IRTemp rmode = newTemp(Ity_I32);
8170 IRTemp f32lo = newTemp(Ity_F32);
8171 IRTemp f32hi = newTemp(Ity_F32);
8172 Bool r2zero = toBool(insn[1] == 0x2C);
8173
8174 do_MMX_preamble();
8175 modrm = getUChar(delta+2);
8176
8177 if (epartIsReg(modrm)) {
8178 delta += 2+1;
8179 assign(f32lo, getXMMRegLane32F(eregOfRexRM(pfx,modrm), 0));
8180 assign(f32hi, getXMMRegLane32F(eregOfRexRM(pfx,modrm), 1));
8181 DIP("cvt%sps2pi %s,%s\n", r2zero ? "t" : "",
8182 nameXMMReg(eregOfRexRM(pfx,modrm)),
8183 nameMMXReg(gregLO3ofRM(modrm)));
8184 } else {
8185 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8186 assign(f32lo, loadLE(Ity_F32, mkexpr(addr)));
8187 assign(f32hi, loadLE(Ity_F32, binop( Iop_Add64,
8188 mkexpr(addr),
8189 mkU64(4) )));
8190 delta += 2+alen;
8191 DIP("cvt%sps2pi %s,%s\n", r2zero ? "t" : "",
8192 dis_buf,
8193 nameMMXReg(gregLO3ofRM(modrm)));
8194 }
8195
8196 if (r2zero) {
8197 assign(rmode, mkU32((UInt)Irrm_ZERO) );
8198 } else {
8199 assign( rmode, get_sse_roundingmode() );
8200 }
8201
8202 assign(
8203 dst64,
8204 binop( Iop_32HLto64,
8205 binop( Iop_F64toI32,
8206 mkexpr(rmode),
8207 unop( Iop_F32toF64, mkexpr(f32hi) ) ),
8208 binop( Iop_F64toI32,
8209 mkexpr(rmode),
8210 unop( Iop_F32toF64, mkexpr(f32lo) ) )
8211 )
8212 );
8213
8214 putMMXReg(gregLO3ofRM(modrm), mkexpr(dst64));
8215 goto decode_success;
8216 }
8217
8218 /* F3 0F 2D = CVTSS2SI
8219 when sz==4 -- convert F32 in mem/low quarter xmm to I32 in ireg,
8220 according to prevailing SSE rounding mode
8221 when sz==8 -- convert F32 in mem/low quarter xmm to I64 in ireg,
8222 according to prevailing SSE rounding mode
8223 */
sewardj82c9f2f2005-03-02 16:05:13 +00008224 /* F3 0F 2C = CVTTSS2SI
8225 when sz==4 -- convert F32 in mem/low quarter xmm to I32 in ireg,
8226 truncating towards zero
8227 when sz==8 -- convert F32 in mem/low quarter xmm to I64 in ireg,
8228 truncating towards zero
8229 */
8230 if (haveF3no66noF2(pfx)
8231 && insn[0] == 0x0F
sewardj432f8b62005-05-10 02:50:05 +00008232 && (insn[1] == 0x2D || insn[1] == 0x2C)) {
sewardj82c9f2f2005-03-02 16:05:13 +00008233 IRTemp rmode = newTemp(Ity_I32);
8234 IRTemp f32lo = newTemp(Ity_F32);
8235 Bool r2zero = toBool(insn[1] == 0x2C);
8236 vassert(sz == 4 || sz == 8);
8237
8238 modrm = getUChar(delta+2);
8239 if (epartIsReg(modrm)) {
8240 delta += 2+1;
8241 assign(f32lo, getXMMRegLane32F(eregOfRexRM(pfx,modrm), 0));
8242 DIP("cvt%sss2si %s,%s\n", r2zero ? "t" : "",
8243 nameXMMReg(eregOfRexRM(pfx,modrm)),
8244 nameIReg(sz, gregOfRexRM(pfx,modrm), False));
8245 } else {
8246 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8247 assign(f32lo, loadLE(Ity_F32, mkexpr(addr)));
8248 delta += 2+alen;
8249 DIP("cvt%sss2si %s,%s\n", r2zero ? "t" : "",
8250 dis_buf,
8251 nameIReg(sz, gregOfRexRM(pfx,modrm), False));
8252 }
8253
8254 if (r2zero) {
8255 assign( rmode, mkU32((UInt)Irrm_ZERO) );
8256 } else {
8257 assign( rmode, get_sse_roundingmode() );
8258 }
8259
8260 if (sz == 4) {
8261 putIReg32( gregOfRexRM(pfx,modrm),
8262 binop( Iop_F64toI32,
8263 mkexpr(rmode),
8264 unop(Iop_F32toF64, mkexpr(f32lo))) );
8265 } else {
8266 putIReg64( gregOfRexRM(pfx,modrm),
8267 binop( Iop_F64toI64,
8268 mkexpr(rmode),
8269 unop(Iop_F32toF64, mkexpr(f32lo))) );
8270 }
8271
8272 goto decode_success;
8273 }
8274
sewardj432f8b62005-05-10 02:50:05 +00008275 /* 0F 5E = DIVPS -- div 32Fx4 from R/M to R */
8276 if (haveNo66noF2noF3(pfx) && sz == 4
8277 && insn[0] == 0x0F && insn[1] == 0x5E) {
8278 delta = dis_SSE_E_to_G_all( pfx, delta+2, "divps", Iop_Div32Fx4 );
8279 goto decode_success;
8280 }
sewardjc49ce232005-02-25 13:03:03 +00008281
8282 /* F3 0F 5E = DIVSS -- div 32F0x4 from R/M to R */
8283 if (haveF3no66noF2(pfx) && sz == 4
8284 && insn[0] == 0x0F && insn[1] == 0x5E) {
8285 delta = dis_SSE_E_to_G_lo32( pfx, delta+2, "divss", Iop_Div32F0x4 );
8286 goto decode_success;
8287 }
8288
sewardjbcbb9de2005-03-27 02:22:32 +00008289 /* 0F AE /2 = LDMXCSR m32 -- load %mxcsr */
8290 if (insn[0] == 0x0F && insn[1] == 0xAE
8291 && haveNo66noF2noF3(pfx)
8292 && !epartIsReg(insn[2]) && gregLO3ofRM(insn[2]) == 2) {
8293
8294 IRTemp t64 = newTemp(Ity_I64);
8295 IRTemp ew = newTemp(Ity_I32);
8296
8297 vassert(sz == 4);
8298 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8299 delta += 2+alen;
8300 DIP("ldmxcsr %s\n", dis_buf);
8301
8302 /* The only thing we observe in %mxcsr is the rounding mode.
8303 Therefore, pass the 32-bit value (SSE native-format control
8304 word) to a clean helper, getting back a 64-bit value, the
8305 lower half of which is the SSEROUND value to store, and the
8306 upper half of which is the emulation-warning token which may
8307 be generated.
8308 */
8309 /* ULong amd64h_check_ldmxcsr ( ULong ); */
8310 assign( t64, mkIRExprCCall(
8311 Ity_I64, 0/*regparms*/,
8312 "amd64g_check_ldmxcsr",
8313 &amd64g_check_ldmxcsr,
8314 mkIRExprVec_1(
8315 unop(Iop_32Uto64,
8316 loadLE(Ity_I32, mkexpr(addr))
8317 )
8318 )
8319 )
8320 );
8321
8322 put_sse_roundingmode( unop(Iop_64to32, mkexpr(t64)) );
8323 assign( ew, unop(Iop_64HIto32, mkexpr(t64) ) );
8324 put_emwarn( mkexpr(ew) );
8325 /* Finally, if an emulation warning was reported, side-exit to
8326 the next insn, reporting the warning, so that Valgrind's
8327 dispatcher sees the warning. */
8328 stmt(
8329 IRStmt_Exit(
8330 binop(Iop_CmpNE64, unop(Iop_32Uto64,mkexpr(ew)), mkU64(0)),
8331 Ijk_EmWarn,
sewardj9e6491a2005-07-02 19:24:10 +00008332 IRConst_U64(guest_RIP_bbstart+delta)
sewardjbcbb9de2005-03-27 02:22:32 +00008333 )
8334 );
8335 goto decode_success;
8336 }
8337
sewardj432f8b62005-05-10 02:50:05 +00008338 /* 0F 5F = MAXPS -- max 32Fx4 from R/M to R */
8339 if (haveNo66noF2noF3(pfx) && sz == 4
8340 && insn[0] == 0x0F && insn[1] == 0x5F) {
8341 delta = dis_SSE_E_to_G_all( pfx, delta+2, "maxps", Iop_Max32Fx4 );
8342 goto decode_success;
8343 }
sewardj37d52572005-02-25 14:22:12 +00008344
8345 /* F3 0F 5F = MAXSS -- max 32F0x4 from R/M to R */
8346 if (haveF3no66noF2(pfx) && sz == 4
8347 && insn[0] == 0x0F && insn[1] == 0x5F) {
8348 delta = dis_SSE_E_to_G_lo32( pfx, delta+2, "maxss", Iop_Max32F0x4 );
8349 goto decode_success;
8350 }
8351
sewardj432f8b62005-05-10 02:50:05 +00008352 /* 0F 5D = MINPS -- min 32Fx4 from R/M to R */
8353 if (haveNo66noF2noF3(pfx) && sz == 4
8354 && insn[0] == 0x0F && insn[1] == 0x5D) {
8355 delta = dis_SSE_E_to_G_all( pfx, delta+2, "minps", Iop_Min32Fx4 );
8356 goto decode_success;
8357 }
sewardj37d52572005-02-25 14:22:12 +00008358
8359 /* F3 0F 5D = MINSS -- min 32F0x4 from R/M to R */
8360 if (haveF3no66noF2(pfx) && sz == 4
8361 && insn[0] == 0x0F && insn[1] == 0x5D) {
8362 delta = dis_SSE_E_to_G_lo32( pfx, delta+2, "minss", Iop_Min32F0x4 );
8363 goto decode_success;
8364 }
sewardj8d965312005-02-25 02:48:47 +00008365
8366 /* 0F 28 = MOVAPS -- move from E (mem or xmm) to G (xmm). */
8367 /* 0F 10 = MOVUPS -- move from E (mem or xmm) to G (xmm). */
8368 if (haveNo66noF2noF3(pfx) && sz == 4
8369 && insn[0] == 0x0F && (insn[1] == 0x28 || insn[1] == 0x10)) {
8370 modrm = getUChar(delta+2);
8371 if (epartIsReg(modrm)) {
8372 putXMMReg( gregOfRexRM(pfx,modrm),
8373 getXMMReg( eregOfRexRM(pfx,modrm) ));
8374 DIP("mov[ua]ps %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
8375 nameXMMReg(gregOfRexRM(pfx,modrm)));
8376 delta += 2+1;
8377 } else {
8378 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8379 putXMMReg( gregOfRexRM(pfx,modrm),
8380 loadLE(Ity_V128, mkexpr(addr)) );
8381 DIP("mov[ua]ps %s,%s\n", dis_buf,
8382 nameXMMReg(gregOfRexRM(pfx,modrm)));
8383 delta += 2+alen;
8384 }
8385 goto decode_success;
8386 }
sewardj1001dc42005-02-21 08:25:55 +00008387
8388 /* 0F 29 = MOVAPS -- move from G (xmm) to E (mem or xmm). */
sewardj446d2672005-06-10 11:04:52 +00008389 /* 0F 11 = MOVUPS -- move from G (xmm) to E (mem or xmm). */
sewardj8d965312005-02-25 02:48:47 +00008390 if (haveNo66noF2noF3(pfx) && sz == 4
sewardj446d2672005-06-10 11:04:52 +00008391 && insn[0] == 0x0F && (insn[1] == 0x29 || insn[1] == 0x11)) {
sewardj1001dc42005-02-21 08:25:55 +00008392 modrm = getUChar(delta+2);
8393 if (epartIsReg(modrm)) {
8394 /* fall through; awaiting test case */
8395 } else {
8396 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8397 storeLE( mkexpr(addr), getXMMReg(gregOfRexRM(pfx,modrm)) );
sewardj446d2672005-06-10 11:04:52 +00008398 DIP("mov[ua]ps %s,%s\n", nameXMMReg(gregOfRexRM(pfx,modrm)),
8399 dis_buf );
sewardj1001dc42005-02-21 08:25:55 +00008400 delta += 2+alen;
8401 goto decode_success;
8402 }
8403 }
8404
sewardj432f8b62005-05-10 02:50:05 +00008405 /* 0F 16 = MOVHPS -- move from mem to high half of XMM. */
8406 /* 0F 16 = MOVLHPS -- move from lo half to hi half of XMM. */
8407 if (haveNo66noF2noF3(pfx) && sz == 4
8408 && insn[0] == 0x0F && insn[1] == 0x16) {
8409 modrm = getUChar(delta+2);
8410 if (epartIsReg(modrm)) {
8411 delta += 2+1;
8412 putXMMRegLane64( gregOfRexRM(pfx,modrm), 1/*upper lane*/,
8413 getXMMRegLane64( eregOfRexRM(pfx,modrm), 0 ) );
8414 DIP("movhps %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
8415 nameXMMReg(gregOfRexRM(pfx,modrm)));
8416 } else {
8417 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8418 delta += 2+alen;
8419 putXMMRegLane64( gregOfRexRM(pfx,modrm), 1/*upper lane*/,
8420 loadLE(Ity_I64, mkexpr(addr)) );
8421 DIP("movhps %s,%s\n", dis_buf,
8422 nameXMMReg( gregOfRexRM(pfx,modrm) ));
8423 }
8424 goto decode_success;
8425 }
8426
8427 /* 0F 17 = MOVHPS -- move from high half of XMM to mem. */
8428 if (haveNo66noF2noF3(pfx) && sz == 4
8429 && insn[0] == 0x0F && insn[1] == 0x17) {
8430 if (!epartIsReg(insn[2])) {
8431 delta += 2;
8432 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
8433 delta += alen;
8434 storeLE( mkexpr(addr),
8435 getXMMRegLane64( gregOfRexRM(pfx,insn[2]),
8436 1/*upper lane*/ ) );
8437 DIP("movhps %s,%s\n", nameXMMReg( gregOfRexRM(pfx,insn[2]) ),
8438 dis_buf);
8439 goto decode_success;
8440 }
8441 /* else fall through */
8442 }
8443
8444 /* 0F 12 = MOVLPS -- move from mem to low half of XMM. */
8445 /* OF 12 = MOVHLPS -- from from hi half to lo half of XMM. */
8446 if (haveNo66noF2noF3(pfx) && sz == 4
8447 && insn[0] == 0x0F && insn[1] == 0x12) {
8448 modrm = getUChar(delta+2);
8449 if (epartIsReg(modrm)) {
8450 delta += 2+1;
8451 putXMMRegLane64( gregOfRexRM(pfx,modrm),
8452 0/*lower lane*/,
8453 getXMMRegLane64( eregOfRexRM(pfx,modrm), 1 ));
8454 DIP("movhlps %s, %s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
8455 nameXMMReg(gregOfRexRM(pfx,modrm)));
8456 } else {
8457 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8458 delta += 2+alen;
8459 putXMMRegLane64( gregOfRexRM(pfx,modrm), 0/*lower lane*/,
8460 loadLE(Ity_I64, mkexpr(addr)) );
8461 DIP("movlps %s, %s\n",
8462 dis_buf, nameXMMReg( gregOfRexRM(pfx,modrm) ));
8463 }
8464 goto decode_success;
8465 }
8466
8467 /* 0F 13 = MOVLPS -- move from low half of XMM to mem. */
8468 if (haveNo66noF2noF3(pfx) && sz == 4
8469 && insn[0] == 0x0F && insn[1] == 0x13) {
8470 if (!epartIsReg(insn[2])) {
8471 delta += 2;
8472 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
8473 delta += alen;
8474 storeLE( mkexpr(addr),
8475 getXMMRegLane64( gregOfRexRM(pfx,insn[2]),
8476 0/*lower lane*/ ) );
8477 DIP("movlps %s, %s\n", nameXMMReg( gregOfRexRM(pfx,insn[2]) ),
8478 dis_buf);
8479 goto decode_success;
8480 }
8481 /* else fall through */
8482 }
8483
sewardja7ba8c42005-05-10 20:08:34 +00008484 /* 0F 50 = MOVMSKPS - move 4 sign bits from 4 x F32 in xmm(E)
8485 to 4 lowest bits of ireg(G) */
8486 if (haveNo66noF2noF3(pfx) && sz == 4
8487 && insn[0] == 0x0F && insn[1] == 0x50) {
8488 modrm = getUChar(delta+2);
8489 if (epartIsReg(modrm)) {
8490 Int src;
8491 t0 = newTemp(Ity_I32);
8492 t1 = newTemp(Ity_I32);
8493 t2 = newTemp(Ity_I32);
8494 t3 = newTemp(Ity_I32);
8495 delta += 2+1;
8496 src = eregOfRexRM(pfx,modrm);
8497 assign( t0, binop( Iop_And32,
8498 binop(Iop_Shr32, getXMMRegLane32(src,0), mkU8(31)),
8499 mkU32(1) ));
8500 assign( t1, binop( Iop_And32,
8501 binop(Iop_Shr32, getXMMRegLane32(src,1), mkU8(30)),
8502 mkU32(2) ));
8503 assign( t2, binop( Iop_And32,
8504 binop(Iop_Shr32, getXMMRegLane32(src,2), mkU8(29)),
8505 mkU32(4) ));
8506 assign( t3, binop( Iop_And32,
8507 binop(Iop_Shr32, getXMMRegLane32(src,3), mkU8(28)),
8508 mkU32(8) ));
8509 putIReg32( gregOfRexRM(pfx,modrm),
8510 binop(Iop_Or32,
8511 binop(Iop_Or32, mkexpr(t0), mkexpr(t1)),
8512 binop(Iop_Or32, mkexpr(t2), mkexpr(t3))
8513 )
8514 );
8515 DIP("movmskps %s,%s\n", nameXMMReg(src),
8516 nameIReg32(gregOfRexRM(pfx,modrm)));
8517 goto decode_success;
8518 }
8519 /* else fall through */
8520 }
8521
sewardj612be432005-05-11 02:55:54 +00008522 /* 66 0F 2B = MOVNTPD -- for us, just a plain SSE store. */
sewardja7ba8c42005-05-10 20:08:34 +00008523 /* 0F 2B = MOVNTPS -- for us, just a plain SSE store. */
sewardj612be432005-05-11 02:55:54 +00008524 if ( ( (haveNo66noF2noF3(pfx) && sz == 4)
8525 || (have66noF2noF3(pfx) && sz == 2)
8526 )
8527 && insn[0] == 0x0F && insn[1] == 0x2B) {
sewardja7ba8c42005-05-10 20:08:34 +00008528 modrm = getUChar(delta+2);
8529 if (!epartIsReg(modrm)) {
8530 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8531 storeLE( mkexpr(addr), getXMMReg(gregOfRexRM(pfx,modrm)) );
sewardj612be432005-05-11 02:55:54 +00008532 DIP("movntp%s %s,%s\n", sz==2 ? "d" : "s",
8533 dis_buf,
8534 nameXMMReg(gregOfRexRM(pfx,modrm)));
sewardja7ba8c42005-05-10 20:08:34 +00008535 delta += 2+alen;
8536 goto decode_success;
8537 }
8538 /* else fall through */
8539 }
8540
8541 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8542 /* 0F E7 = MOVNTQ -- for us, just a plain MMX store. Note, the
8543 Intel manual does not say anything about the usual business of
8544 the FP reg tags getting trashed whenever an MMX insn happens.
8545 So we just leave them alone.
8546 */
8547 if (haveNo66noF2noF3(pfx) && sz == 4
8548 && insn[0] == 0x0F && insn[1] == 0xE7) {
8549 modrm = getUChar(delta+2);
8550 if (!epartIsReg(modrm)) {
8551 /* do_MMX_preamble(); Intel docs don't specify this */
8552 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8553 storeLE( mkexpr(addr), getMMXReg(gregLO3ofRM(modrm)) );
8554 DIP("movntq %s,%s\n", dis_buf,
8555 nameMMXReg(gregLO3ofRM(modrm)));
8556 delta += 2+alen;
8557 goto decode_success;
8558 }
8559 /* else fall through */
8560 }
sewardj8d965312005-02-25 02:48:47 +00008561
8562 /* F3 0F 10 = MOVSS -- move 32 bits from E (mem or lo 1/4 xmm) to G
8563 (lo 1/4 xmm). If E is mem, upper 3/4 of G is zeroed out. */
8564 if (haveF3no66noF2(pfx) && sz == 4
8565 && insn[0] == 0x0F && insn[1] == 0x10) {
8566 modrm = getUChar(delta+2);
8567 if (epartIsReg(modrm)) {
8568 putXMMRegLane32( gregOfRexRM(pfx,modrm), 0,
8569 getXMMRegLane32( eregOfRexRM(pfx,modrm), 0 ));
8570 DIP("movss %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
8571 nameXMMReg(gregOfRexRM(pfx,modrm)));
8572 delta += 2+1;
8573 } else {
8574 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8575 putXMMReg( gregOfRexRM(pfx,modrm), mkV128(0) );
8576 putXMMRegLane32( gregOfRexRM(pfx,modrm), 0,
8577 loadLE(Ity_I32, mkexpr(addr)) );
8578 DIP("movss %s,%s\n", dis_buf,
8579 nameXMMReg(gregOfRexRM(pfx,modrm)));
8580 delta += 2+alen;
8581 }
8582 goto decode_success;
8583 }
8584
8585 /* F3 0F 11 = MOVSS -- move 32 bits from G (lo 1/4 xmm) to E (mem
8586 or lo 1/4 xmm). */
8587 if (haveF3no66noF2(pfx) && sz == 4
8588 && insn[0] == 0x0F && insn[1] == 0x11) {
8589 modrm = getUChar(delta+2);
8590 if (epartIsReg(modrm)) {
8591 /* fall through, we don't yet have a test case */
8592 } else {
8593 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8594 storeLE( mkexpr(addr),
8595 getXMMRegLane32(gregOfRexRM(pfx,modrm), 0) );
8596 DIP("movss %s,%s\n", nameXMMReg(gregOfRexRM(pfx,modrm)),
8597 dis_buf);
8598 delta += 2+alen;
8599 goto decode_success;
8600 }
8601 }
8602
sewardj432f8b62005-05-10 02:50:05 +00008603 /* 0F 59 = MULPS -- mul 32Fx4 from R/M to R */
8604 if (haveNo66noF2noF3(pfx) && sz == 4
8605 && insn[0] == 0x0F && insn[1] == 0x59) {
8606 delta = dis_SSE_E_to_G_all( pfx, delta+2, "mulps", Iop_Mul32Fx4 );
8607 goto decode_success;
8608 }
sewardj8d965312005-02-25 02:48:47 +00008609
8610 /* F3 0F 59 = MULSS -- mul 32F0x4 from R/M to R */
8611 if (haveF3no66noF2(pfx) && sz == 4
8612 && insn[0] == 0x0F && insn[1] == 0x59) {
8613 delta = dis_SSE_E_to_G_lo32( pfx, delta+2, "mulss", Iop_Mul32F0x4 );
8614 goto decode_success;
8615 }
8616
sewardj3aba9eb2005-03-30 23:20:47 +00008617 /* 0F 56 = ORPS -- G = G and E */
8618 if (haveNo66noF2noF3(pfx) && sz == 4
8619 && insn[0] == 0x0F && insn[1] == 0x56) {
8620 delta = dis_SSE_E_to_G_all( pfx, delta+2, "orps", Iop_OrV128 );
8621 goto decode_success;
8622 }
8623
sewardja7ba8c42005-05-10 20:08:34 +00008624 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8625 /* 0F E0 = PAVGB -- 8x8 unsigned Packed Average, with rounding */
8626 if (haveNo66noF2noF3(pfx) && sz == 4
8627 && insn[0] == 0x0F && insn[1] == 0xE0) {
8628 do_MMX_preamble();
8629 delta = dis_MMXop_regmem_to_reg (
8630 pfx, delta+2, insn[1], "pavgb", False );
8631 goto decode_success;
8632 }
8633
8634 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8635 /* 0F E3 = PAVGW -- 16x4 unsigned Packed Average, with rounding */
8636 if (haveNo66noF2noF3(pfx) && sz == 4
8637 && insn[0] == 0x0F && insn[1] == 0xE3) {
8638 do_MMX_preamble();
8639 delta = dis_MMXop_regmem_to_reg (
8640 pfx, delta+2, insn[1], "pavgw", False );
8641 goto decode_success;
8642 }
8643
8644 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8645 /* 0F C5 = PEXTRW -- extract 16-bit field from mmx(E) and put
8646 zero-extend of it in ireg(G). */
8647 if (haveNo66noF2noF3(pfx) && sz == 4
8648 && insn[0] == 0x0F && insn[1] == 0xC5) {
8649 modrm = insn[2];
8650 if (epartIsReg(modrm)) {
8651 IRTemp sV = newTemp(Ity_I64);
8652 t5 = newTemp(Ity_I16);
8653 do_MMX_preamble();
8654 assign(sV, getMMXReg(eregLO3ofRM(modrm)));
8655 breakup64to16s( sV, &t3, &t2, &t1, &t0 );
8656 switch (insn[3] & 3) {
8657 case 0: assign(t5, mkexpr(t0)); break;
8658 case 1: assign(t5, mkexpr(t1)); break;
8659 case 2: assign(t5, mkexpr(t2)); break;
8660 case 3: assign(t5, mkexpr(t3)); break;
8661 default: vassert(0);
8662 }
8663 putIReg32(gregOfRexRM(pfx,modrm), unop(Iop_16Uto32, mkexpr(t5)));
8664 DIP("pextrw $%d,%s,%s\n",
8665 (Int)insn[3], nameMMXReg(eregLO3ofRM(modrm)),
8666 nameIReg32(gregOfRexRM(pfx,modrm)));
8667 delta += 4;
8668 goto decode_success;
8669 }
8670 /* else fall through */
8671 /* note, for anyone filling in the mem case: this insn has one
8672 byte after the amode and therefore you must pass 1 as the
8673 last arg to disAMode */
8674 }
8675
8676 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8677 /* 0F C4 = PINSRW -- get 16 bits from E(mem or low half ireg) and
8678 put it into the specified lane of mmx(G). */
8679 if (haveNo66noF2noF3(pfx) && sz == 4
8680 && insn[0] == 0x0F && insn[1] == 0xC4) {
8681 /* Use t0 .. t3 to hold the 4 original 16-bit lanes of the
8682 mmx reg. t4 is the new lane value. t5 is the original
8683 mmx value. t6 is the new mmx value. */
8684 Int lane;
8685 t4 = newTemp(Ity_I16);
8686 t5 = newTemp(Ity_I64);
8687 t6 = newTemp(Ity_I64);
8688 modrm = insn[2];
8689 do_MMX_preamble();
8690
8691 assign(t5, getMMXReg(gregLO3ofRM(modrm)));
8692 breakup64to16s( t5, &t3, &t2, &t1, &t0 );
8693
8694 if (epartIsReg(modrm)) {
8695 assign(t4, getIReg16(eregOfRexRM(pfx,modrm)));
8696 delta += 3+1;
8697 lane = insn[3+1-1];
8698 DIP("pinsrw $%d,%s,%s\n", (Int)lane,
8699 nameIReg16(eregOfRexRM(pfx,modrm)),
8700 nameMMXReg(gregLO3ofRM(modrm)));
8701 } else {
8702 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 1 );
8703 delta += 3+alen;
8704 lane = insn[3+alen-1];
8705 assign(t4, loadLE(Ity_I16, mkexpr(addr)));
8706 DIP("pinsrw $%d,%s,%s\n", (Int)lane,
8707 dis_buf,
8708 nameMMXReg(gregLO3ofRM(modrm)));
8709 }
8710
8711 switch (lane & 3) {
8712 case 0: assign(t6, mk64from16s(t3,t2,t1,t4)); break;
8713 case 1: assign(t6, mk64from16s(t3,t2,t4,t0)); break;
8714 case 2: assign(t6, mk64from16s(t3,t4,t1,t0)); break;
8715 case 3: assign(t6, mk64from16s(t4,t2,t1,t0)); break;
8716 default: vassert(0);
8717 }
8718 putMMXReg(gregLO3ofRM(modrm), mkexpr(t6));
8719 goto decode_success;
8720 }
8721
8722 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8723 /* 0F EE = PMAXSW -- 16x4 signed max */
8724 if (haveNo66noF2noF3(pfx) && sz == 4
8725 && insn[0] == 0x0F && insn[1] == 0xEE) {
8726 do_MMX_preamble();
8727 delta = dis_MMXop_regmem_to_reg (
8728 pfx, delta+2, insn[1], "pmaxsw", False );
8729 goto decode_success;
8730 }
8731
8732 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8733 /* 0F DE = PMAXUB -- 8x8 unsigned max */
8734 if (haveNo66noF2noF3(pfx) && sz == 4
8735 && insn[0] == 0x0F && insn[1] == 0xDE) {
8736 do_MMX_preamble();
8737 delta = dis_MMXop_regmem_to_reg (
8738 pfx, delta+2, insn[1], "pmaxub", False );
8739 goto decode_success;
8740 }
8741
8742 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8743 /* 0F EA = PMINSW -- 16x4 signed min */
8744 if (haveNo66noF2noF3(pfx) && sz == 4
8745 && insn[0] == 0x0F && insn[1] == 0xEA) {
8746 do_MMX_preamble();
8747 delta = dis_MMXop_regmem_to_reg (
8748 pfx, delta+2, insn[1], "pminsw", False );
8749 goto decode_success;
8750 }
8751
8752 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8753 /* 0F DA = PMINUB -- 8x8 unsigned min */
8754 if (haveNo66noF2noF3(pfx) && sz == 4
8755 && insn[0] == 0x0F && insn[1] == 0xDA) {
8756 do_MMX_preamble();
8757 delta = dis_MMXop_regmem_to_reg (
8758 pfx, delta+2, insn[1], "pminub", False );
8759 goto decode_success;
8760 }
8761
8762 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8763 /* 0F D7 = PMOVMSKB -- extract sign bits from each of 8 lanes in
8764 mmx(G), turn them into a byte, and put zero-extend of it in
8765 ireg(G). */
8766 if (haveNo66noF2noF3(pfx) && sz == 4
8767 && insn[0] == 0x0F && insn[1] == 0xD7) {
8768 modrm = insn[2];
8769 if (epartIsReg(modrm)) {
8770 do_MMX_preamble();
8771 t0 = newTemp(Ity_I64);
8772 t1 = newTemp(Ity_I64);
8773 assign(t0, getMMXReg(eregLO3ofRM(modrm)));
8774 assign(t1, mkIRExprCCall(
8775 Ity_I64, 0/*regparms*/,
8776 "amd64g_calculate_mmx_pmovmskb",
8777 &amd64g_calculate_mmx_pmovmskb,
8778 mkIRExprVec_1(mkexpr(t0))));
8779 putIReg32(gregOfRexRM(pfx,modrm), unop(Iop_64to32,mkexpr(t1)));
8780 DIP("pmovmskb %s,%s\n", nameMMXReg(eregLO3ofRM(modrm)),
8781 nameIReg32(gregOfRexRM(pfx,modrm)));
8782 delta += 3;
8783 goto decode_success;
8784 }
8785 /* else fall through */
8786 }
8787
8788 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8789 /* 0F E4 = PMULUH -- 16x4 hi-half of unsigned widening multiply */
8790 if (haveNo66noF2noF3(pfx) && sz == 4
8791 && insn[0] == 0x0F && insn[1] == 0xE4) {
8792 do_MMX_preamble();
8793 delta = dis_MMXop_regmem_to_reg (
8794 pfx, delta+2, insn[1], "pmuluh", False );
8795 goto decode_success;
8796 }
sewardja6b93d12005-02-17 09:28:28 +00008797
8798 /* 0F 18 /0 = PREFETCHNTA -- prefetch into caches, */
8799 /* 0F 18 /1 = PREFETCH0 -- with various different hints */
8800 /* 0F 18 /2 = PREFETCH1 */
8801 /* 0F 18 /3 = PREFETCH2 */
8802 if (insn[0] == 0x0F && insn[1] == 0x18
sewardjbcbb9de2005-03-27 02:22:32 +00008803 && haveNo66noF2noF3(pfx)
sewardja6b93d12005-02-17 09:28:28 +00008804 && !epartIsReg(insn[2])
sewardj901ed122005-02-27 13:25:31 +00008805 && gregLO3ofRM(insn[2]) >= 0 && gregLO3ofRM(insn[2]) <= 3) {
sewardja6b93d12005-02-17 09:28:28 +00008806 HChar* hintstr = "??";
8807
8808 modrm = getUChar(delta+2);
8809 vassert(!epartIsReg(modrm));
8810
8811 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8812 delta += 2+alen;
8813
sewardj901ed122005-02-27 13:25:31 +00008814 switch (gregLO3ofRM(modrm)) {
sewardja6b93d12005-02-17 09:28:28 +00008815 case 0: hintstr = "nta"; break;
8816 case 1: hintstr = "t0"; break;
8817 case 2: hintstr = "t1"; break;
8818 case 3: hintstr = "t2"; break;
8819 default: vassert(0);
8820 }
8821
8822 DIP("prefetch%s %s\n", hintstr, dis_buf);
8823 goto decode_success;
8824 }
8825
sewardja7ba8c42005-05-10 20:08:34 +00008826 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8827 /* 0F F6 = PSADBW -- sum of 8Ux8 absolute differences */
8828 if (haveNo66noF2noF3(pfx) && sz == 4
8829 && insn[0] == 0x0F && insn[1] == 0xF6) {
8830 do_MMX_preamble();
8831 delta = dis_MMXop_regmem_to_reg (
8832 pfx, delta+2, insn[1], "psadbw", False );
8833 goto decode_success;
8834 }
8835
8836 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8837 /* 0F 70 = PSHUFW -- rearrange 4x16 from E(mmx or mem) to G(mmx) */
8838 if (haveNo66noF2noF3(pfx) && sz == 4
8839 && insn[0] == 0x0F && insn[1] == 0x70) {
8840 Int order;
8841 IRTemp sV, dV, s3, s2, s1, s0;
8842 s3 = s2 = s1 = s0 = IRTemp_INVALID;
8843 sV = newTemp(Ity_I64);
8844 dV = newTemp(Ity_I64);
8845 do_MMX_preamble();
8846 modrm = insn[2];
8847 if (epartIsReg(modrm)) {
8848 assign( sV, getMMXReg(eregLO3ofRM(modrm)) );
8849 order = (Int)insn[3];
8850 delta += 2+2;
8851 DIP("pshufw $%d,%s,%s\n", order,
8852 nameMMXReg(eregLO3ofRM(modrm)),
8853 nameMMXReg(gregLO3ofRM(modrm)));
8854 } else {
8855 addr = disAMode ( &alen, pfx, delta+2, dis_buf,
8856 1/*extra byte after amode*/ );
8857 assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
8858 order = (Int)insn[2+alen];
8859 delta += 3+alen;
8860 DIP("pshufw $%d,%s,%s\n", order,
8861 dis_buf,
8862 nameMMXReg(gregLO3ofRM(modrm)));
8863 }
8864 breakup64to16s( sV, &s3, &s2, &s1, &s0 );
8865# define SEL(n) \
8866 ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
8867 assign(dV,
8868 mk64from16s( SEL((order>>6)&3), SEL((order>>4)&3),
8869 SEL((order>>2)&3), SEL((order>>0)&3) )
8870 );
8871 putMMXReg(gregLO3ofRM(modrm), mkexpr(dV));
8872# undef SEL
8873 goto decode_success;
8874 }
8875
8876 /* 0F 53 = RCPPS -- approx reciprocal 32Fx4 from R/M to R */
8877 if (haveNo66noF2noF3(pfx) && sz == 4
8878 && insn[0] == 0x0F && insn[1] == 0x53) {
8879 delta = dis_SSE_E_to_G_unary_all( pfx, delta+2,
8880 "rcpps", Iop_Recip32Fx4 );
8881 goto decode_success;
8882 }
8883
8884 /* F3 0F 53 = RCPSS -- approx reciprocal 32F0x4 from R/M to R */
8885 if (haveF3no66noF2(pfx) && sz == 4
8886 && insn[0] == 0x0F && insn[1] == 0x53) {
8887 delta = dis_SSE_E_to_G_unary_lo32( pfx, delta+2,
8888 "rcpss", Iop_Recip32F0x4 );
8889 goto decode_success;
8890 }
8891
8892 /* 0F 52 = RSQRTPS -- approx reciprocal sqrt 32Fx4 from R/M to R */
8893 if (haveNo66noF2noF3(pfx) && sz == 4
8894 && insn[0] == 0x0F && insn[1] == 0x52) {
8895 delta = dis_SSE_E_to_G_unary_all( pfx, delta+2,
8896 "rsqrtps", Iop_RSqrt32Fx4 );
8897 goto decode_success;
8898 }
8899
8900 /* F3 0F 52 = RSQRTSS -- approx reciprocal sqrt 32F0x4 from R/M to R */
8901 if (haveF3no66noF2(pfx) && sz == 4
8902 && insn[0] == 0x0F && insn[1] == 0x52) {
8903 delta = dis_SSE_E_to_G_unary_lo32( pfx, delta+2,
8904 "rsqrtss", Iop_RSqrt32F0x4 );
8905 goto decode_success;
8906 }
sewardjf53b7352005-04-06 20:01:56 +00008907
8908 /* 0F AE /7 = SFENCE -- flush pending operations to memory */
8909 if (haveNo66noF2noF3(pfx)
8910 && insn[0] == 0x0F && insn[1] == 0xAE
8911 && epartIsReg(insn[2]) && gregLO3ofRM(insn[2]) == 7
8912 && sz == 4) {
8913 delta += 3;
8914 /* Insert a memory fence. It's sometimes important that these
8915 are carried through to the generated code. */
8916 stmt( IRStmt_MFence() );
8917 DIP("sfence\n");
8918 goto decode_success;
8919 }
8920
sewardja7ba8c42005-05-10 20:08:34 +00008921 /* 0F C6 /r ib = SHUFPS -- shuffle packed F32s */
8922 if (haveNo66noF2noF3(pfx) && sz == 4
8923 && insn[0] == 0x0F && insn[1] == 0xC6) {
8924 Int select;
8925 IRTemp sV, dV;
8926 IRTemp s3, s2, s1, s0, d3, d2, d1, d0;
8927 sV = newTemp(Ity_V128);
8928 dV = newTemp(Ity_V128);
8929 s3 = s2 = s1 = s0 = d3 = d2 = d1 = d0 = IRTemp_INVALID;
8930 modrm = insn[2];
8931 assign( dV, getXMMReg(gregOfRexRM(pfx,modrm)) );
8932
8933 if (epartIsReg(modrm)) {
8934 assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
8935 select = (Int)insn[3];
8936 delta += 2+2;
8937 DIP("shufps $%d,%s,%s\n", select,
8938 nameXMMReg(eregOfRexRM(pfx,modrm)),
8939 nameXMMReg(gregOfRexRM(pfx,modrm)));
8940 } else {
8941 addr = disAMode ( &alen, pfx, delta+2, dis_buf,
8942 1/*byte at end of insn*/ );
8943 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
8944 select = (Int)insn[2+alen];
8945 delta += 3+alen;
8946 DIP("shufps $%d,%s,%s\n", select,
8947 dis_buf,
8948 nameXMMReg(gregOfRexRM(pfx,modrm)));
8949 }
8950
8951 breakup128to32s( dV, &d3, &d2, &d1, &d0 );
8952 breakup128to32s( sV, &s3, &s2, &s1, &s0 );
8953
8954# define SELD(n) ((n)==0 ? d0 : ((n)==1 ? d1 : ((n)==2 ? d2 : d3)))
8955# define SELS(n) ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
8956
8957 putXMMReg(
8958 gregOfRexRM(pfx,modrm),
8959 mk128from32s( SELS((select>>6)&3), SELS((select>>4)&3),
8960 SELD((select>>2)&3), SELD((select>>0)&3) )
8961 );
8962
8963# undef SELD
8964# undef SELS
8965
8966 goto decode_success;
8967 }
8968
8969 /* 0F 51 = SQRTPS -- approx sqrt 32Fx4 from R/M to R */
8970 if (haveNo66noF2noF3(pfx) && sz == 4
8971 && insn[0] == 0x0F && insn[1] == 0x51) {
8972 delta = dis_SSE_E_to_G_unary_all( pfx, delta+2,
8973 "sqrtps", Iop_Sqrt32Fx4 );
8974 goto decode_success;
8975 }
8976
8977 /* F3 0F 51 = SQRTSS -- approx sqrt 32F0x4 from R/M to R */
8978 if (haveF3no66noF2(pfx) && sz == 4
8979 && insn[0] == 0x0F && insn[1] == 0x51) {
8980 delta = dis_SSE_E_to_G_unary_lo32( pfx, delta+2,
8981 "sqrtss", Iop_Sqrt32F0x4 );
8982 goto decode_success;
8983 }
sewardjbcbb9de2005-03-27 02:22:32 +00008984
8985 /* 0F AE /3 = STMXCSR m32 -- store %mxcsr */
8986 if (insn[0] == 0x0F && insn[1] == 0xAE
8987 && haveNo66noF2noF3(pfx)
8988 && !epartIsReg(insn[2]) && gregLO3ofRM(insn[2]) == 3) {
8989
8990 vassert(sz == 4);
8991 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8992 delta += 2+alen;
8993
8994 /* Fake up a native SSE mxcsr word. The only thing it depends
8995 on is SSEROUND[1:0], so call a clean helper to cook it up.
8996 */
8997 /* ULong amd64h_create_mxcsr ( ULong sseround ) */
8998 DIP("stmxcsr %s\n", dis_buf);
8999 storeLE(
9000 mkexpr(addr),
9001 unop(Iop_64to32,
9002 mkIRExprCCall(
9003 Ity_I64, 0/*regp*/,
9004 "amd64g_create_mxcsr", &amd64g_create_mxcsr,
9005 mkIRExprVec_1( unop(Iop_32Uto64,get_sse_roundingmode()) )
9006 )
9007 )
9008 );
9009 goto decode_success;
9010 }
9011
sewardj432f8b62005-05-10 02:50:05 +00009012 /* 0F 5C = SUBPS -- sub 32Fx4 from R/M to R */
9013 if (haveNo66noF2noF3(pfx) && sz == 4
9014 && insn[0] == 0x0F && insn[1] == 0x5C) {
9015 delta = dis_SSE_E_to_G_all( pfx, delta+2, "subps", Iop_Sub32Fx4 );
9016 goto decode_success;
9017 }
sewardj8d965312005-02-25 02:48:47 +00009018
9019 /* F3 0F 5C = SUBSS -- sub 32F0x4 from R/M to R */
9020 if (haveF3no66noF2(pfx) && sz == 4
9021 && insn[0] == 0x0F && insn[1] == 0x5C) {
9022 delta = dis_SSE_E_to_G_lo32( pfx, delta+2, "subss", Iop_Sub32F0x4 );
9023 goto decode_success;
9024 }
9025
sewardja7ba8c42005-05-10 20:08:34 +00009026 /* 0F 15 = UNPCKHPS -- unpack and interleave high part F32s */
9027 /* 0F 14 = UNPCKLPS -- unpack and interleave low part F32s */
9028 /* These just appear to be special cases of SHUFPS */
9029 if (haveNo66noF2noF3(pfx) && sz == 4
9030 && insn[0] == 0x0F && (insn[1] == 0x15 || insn[1] == 0x14)) {
9031 IRTemp sV, dV;
9032 IRTemp s3, s2, s1, s0, d3, d2, d1, d0;
sewardjca673ab2005-05-11 10:03:08 +00009033 Bool hi = toBool(insn[1] == 0x15);
sewardja7ba8c42005-05-10 20:08:34 +00009034 sV = newTemp(Ity_V128);
9035 dV = newTemp(Ity_V128);
9036 s3 = s2 = s1 = s0 = d3 = d2 = d1 = d0 = IRTemp_INVALID;
9037 modrm = insn[2];
9038 assign( dV, getXMMReg(gregOfRexRM(pfx,modrm)) );
9039
9040 if (epartIsReg(modrm)) {
9041 assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
9042 delta += 2+1;
9043 DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
9044 nameXMMReg(eregOfRexRM(pfx,modrm)),
9045 nameXMMReg(gregOfRexRM(pfx,modrm)));
9046 } else {
9047 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9048 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
9049 delta += 2+alen;
9050 DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
9051 dis_buf,
9052 nameXMMReg(gregOfRexRM(pfx,modrm)));
9053 }
9054
9055 breakup128to32s( dV, &d3, &d2, &d1, &d0 );
9056 breakup128to32s( sV, &s3, &s2, &s1, &s0 );
9057
9058 if (hi) {
9059 putXMMReg( gregOfRexRM(pfx,modrm), mk128from32s( s3, d3, s2, d2 ) );
9060 } else {
9061 putXMMReg( gregOfRexRM(pfx,modrm), mk128from32s( s1, d1, s0, d0 ) );
9062 }
9063
9064 goto decode_success;
9065 }
sewardj8d965312005-02-25 02:48:47 +00009066
9067 /* 0F 57 = XORPS -- G = G and E */
9068 if (haveNo66noF2noF3(pfx) && sz == 4
9069 && insn[0] == 0x0F && insn[1] == 0x57) {
9070 delta = dis_SSE_E_to_G_all( pfx, delta+2, "xorps", Iop_XorV128 );
9071 goto decode_success;
9072 }
9073
sewardj5992bd02005-05-11 02:13:42 +00009074 /* ---------------------------------------------------- */
9075 /* --- end of the SSE decoder. --- */
9076 /* ---------------------------------------------------- */
9077
9078 /* ---------------------------------------------------- */
9079 /* --- start of the SSE2 decoder. --- */
9080 /* ---------------------------------------------------- */
sewardj4c328cf2005-05-05 12:05:54 +00009081
9082 /* 66 0F 58 = ADDPD -- add 32Fx4 from R/M to R */
9083 if (have66noF2noF3(pfx) && sz == 2
9084 && insn[0] == 0x0F && insn[1] == 0x58) {
9085 delta = dis_SSE_E_to_G_all( pfx, delta+2, "addpd", Iop_Add64Fx2 );
9086 goto decode_success;
9087 }
sewardj1001dc42005-02-21 08:25:55 +00009088
9089 /* F2 0F 58 = ADDSD -- add 64F0x2 from R/M to R */
9090 if (haveF2no66noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x58) {
9091 vassert(sz == 4);
9092 delta = dis_SSE_E_to_G_lo64( pfx, delta+2, "addsd", Iop_Add64F0x2 );
9093 goto decode_success;
9094 }
9095
sewardj8d965312005-02-25 02:48:47 +00009096 /* 66 0F 55 = ANDNPD -- G = (not G) and E */
9097 if (have66noF2noF3(pfx) && sz == 2
9098 && insn[0] == 0x0F && insn[1] == 0x55) {
9099 delta = dis_SSE_E_to_G_all_invG( pfx, delta+2, "andnpd", Iop_AndV128 );
9100 goto decode_success;
9101 }
sewardj1a01e652005-02-23 11:39:21 +00009102
9103 /* 66 0F 54 = ANDPD -- G = G and E */
9104 if (have66noF2noF3(pfx) && sz == 2
9105 && insn[0] == 0x0F && insn[1] == 0x54) {
9106 delta = dis_SSE_E_to_G_all( pfx, delta+2, "andpd", Iop_AndV128 );
9107 goto decode_success;
9108 }
9109
sewardj97628592005-05-10 22:42:54 +00009110 /* 66 0F C2 = CMPPD -- 64Fx2 comparison from R/M to R */
9111 if (have66noF2noF3(pfx) && sz == 2
9112 && insn[0] == 0x0F && insn[1] == 0xC2) {
9113 delta = dis_SSEcmp_E_to_G( pfx, delta+2, "cmppd", True, 8 );
9114 goto decode_success;
9115 }
sewardj8d965312005-02-25 02:48:47 +00009116
9117 /* F2 0F C2 = CMPSD -- 64F0x2 comparison from R/M to R */
9118 if (haveF2no66noF3(pfx) && sz == 4
9119 && insn[0] == 0x0F && insn[1] == 0xC2) {
9120 delta = dis_SSEcmp_E_to_G( pfx, delta+2, "cmpsd", False, 8 );
9121 goto decode_success;
9122 }
sewardj18303862005-02-21 12:36:54 +00009123
9124 /* 66 0F 2F = COMISD -- 64F0x2 comparison G,E, and set ZCP */
9125 /* 66 0F 2E = UCOMISD -- 64F0x2 comparison G,E, and set ZCP */
sewardjc49ce232005-02-25 13:03:03 +00009126 if (have66noF2noF3(pfx) && sz == 2
sewardj18303862005-02-21 12:36:54 +00009127 && insn[0] == 0x0F && (insn[1] == 0x2F || insn[1] == 0x2E)) {
9128 IRTemp argL = newTemp(Ity_F64);
9129 IRTemp argR = newTemp(Ity_F64);
9130 modrm = getUChar(delta+2);
9131 if (epartIsReg(modrm)) {
9132 assign( argR, getXMMRegLane64F( eregOfRexRM(pfx,modrm),
9133 0/*lowest lane*/ ) );
9134 delta += 2+1;
9135 DIP("%scomisd %s,%s\n", insn[1]==0x2E ? "u" : "",
9136 nameXMMReg(eregOfRexRM(pfx,modrm)),
9137 nameXMMReg(gregOfRexRM(pfx,modrm)) );
9138 } else {
9139 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9140 assign( argR, loadLE(Ity_F64, mkexpr(addr)) );
9141 delta += 2+alen;
9142 DIP("%scomisd %s,%s\n", insn[1]==0x2E ? "u" : "",
9143 dis_buf,
9144 nameXMMReg(gregOfRexRM(pfx,modrm)) );
9145 }
9146 assign( argL, getXMMRegLane64F( gregOfRexRM(pfx,modrm),
9147 0/*lowest lane*/ ) );
9148
9149 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(AMD64G_CC_OP_COPY) ));
9150 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
9151 stmt( IRStmt_Put(
9152 OFFB_CC_DEP1,
9153 binop( Iop_And64,
9154 unop( Iop_32Uto64,
9155 binop(Iop_CmpF64, mkexpr(argL), mkexpr(argR)) ),
9156 mkU64(0x45)
9157 )));
9158
9159 goto decode_success;
9160 }
9161
sewardj09717342005-05-05 21:34:02 +00009162 /* F3 0F E6 = CVTDQ2PD -- convert 2 x I32 in mem/lo half xmm to 2 x
9163 F64 in xmm(G) */
9164 if (haveF3no66noF2(pfx) && insn[0] == 0x0F && insn[1] == 0xE6) {
9165 IRTemp arg64 = newTemp(Ity_I64);
9166 if (sz != 4) goto decode_failure;
9167
9168 modrm = getUChar(delta+2);
9169 if (epartIsReg(modrm)) {
9170 assign( arg64, getXMMRegLane64(eregOfRexRM(pfx,modrm), 0) );
9171 delta += 2+1;
9172 DIP("cvtdq2pd %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
9173 nameXMMReg(gregOfRexRM(pfx,modrm)));
9174 } else {
9175 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9176 assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
9177 delta += 2+alen;
9178 DIP("cvtdq2pd %s,%s\n", dis_buf,
9179 nameXMMReg(gregOfRexRM(pfx,modrm)) );
9180 }
9181
9182 putXMMRegLane64F(
9183 gregOfRexRM(pfx,modrm), 0,
9184 unop(Iop_I32toF64, unop(Iop_64to32, mkexpr(arg64)))
9185 );
9186
9187 putXMMRegLane64F(
9188 gregOfRexRM(pfx,modrm), 1,
9189 unop(Iop_I32toF64, unop(Iop_64HIto32, mkexpr(arg64)))
9190 );
9191
9192 goto decode_success;
9193 }
9194
sewardj5992bd02005-05-11 02:13:42 +00009195 /* 0F 5B = CVTDQ2PS -- convert 4 x I32 in mem/xmm to 4 x F32 in
9196 xmm(G) */
9197 if (haveNo66noF2noF3(pfx) && sz == 4
9198 && insn[0] == 0x0F && insn[1] == 0x5B) {
sewardj09717342005-05-05 21:34:02 +00009199 IRTemp argV = newTemp(Ity_V128);
9200 IRTemp rmode = newTemp(Ity_I32);
sewardj09717342005-05-05 21:34:02 +00009201
9202 modrm = getUChar(delta+2);
9203 if (epartIsReg(modrm)) {
9204 assign( argV, getXMMReg(eregOfRexRM(pfx,modrm)) );
9205 delta += 2+1;
sewardj5992bd02005-05-11 02:13:42 +00009206 DIP("cvtdq2ps %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
sewardj09717342005-05-05 21:34:02 +00009207 nameXMMReg(gregOfRexRM(pfx,modrm)));
9208 } else {
9209 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
sewardj5992bd02005-05-11 02:13:42 +00009210 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
sewardj09717342005-05-05 21:34:02 +00009211 delta += 2+alen;
sewardj5992bd02005-05-11 02:13:42 +00009212 DIP("cvtdq2ps %s,%s\n", dis_buf,
sewardj09717342005-05-05 21:34:02 +00009213 nameXMMReg(gregOfRexRM(pfx,modrm)) );
9214 }
9215
9216 assign( rmode, get_sse_roundingmode() );
sewardj5992bd02005-05-11 02:13:42 +00009217 breakup128to32s( argV, &t3, &t2, &t1, &t0 );
9218
9219# define CVT(_t) binop( Iop_F64toF32, \
9220 mkexpr(rmode), \
9221 unop(Iop_I32toF64,mkexpr(_t)))
9222
9223 putXMMRegLane32F( gregOfRexRM(pfx,modrm), 3, CVT(t3) );
9224 putXMMRegLane32F( gregOfRexRM(pfx,modrm), 2, CVT(t2) );
9225 putXMMRegLane32F( gregOfRexRM(pfx,modrm), 1, CVT(t1) );
9226 putXMMRegLane32F( gregOfRexRM(pfx,modrm), 0, CVT(t0) );
9227
9228# undef CVT
9229
9230 goto decode_success;
9231 }
9232
9233 /* 66 0F E6 = CVTTPD2DQ -- convert 2 x F64 in mem/xmm to 2 x I32 in
9234 lo half xmm(G), and zero upper half, rounding towards zero */
9235 /* F2 0F E6 = CVTPD2DQ -- convert 2 x F64 in mem/xmm to 2 x I32 in
9236 lo half xmm(G), according to prevailing rounding mode, and zero
9237 upper half */
9238 if ( ( (haveF2no66noF3(pfx) && sz == 4)
9239 || (have66noF2noF3(pfx) && sz == 2)
9240 )
9241 && insn[0] == 0x0F && insn[1] == 0xE6) {
9242 IRTemp argV = newTemp(Ity_V128);
9243 IRTemp rmode = newTemp(Ity_I32);
9244 Bool r2zero = toBool(sz == 2);
9245
9246 modrm = getUChar(delta+2);
9247 if (epartIsReg(modrm)) {
9248 assign( argV, getXMMReg(eregOfRexRM(pfx,modrm)) );
9249 delta += 2+1;
9250 DIP("cvt%spd2dq %s,%s\n", r2zero ? "t" : "",
9251 nameXMMReg(eregOfRexRM(pfx,modrm)),
9252 nameXMMReg(gregOfRexRM(pfx,modrm)));
9253 } else {
9254 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9255 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
9256 delta += 2+alen;
9257 DIP("cvt%spd2dq %s,%s\n", r2zero ? "t" : "",
9258 dis_buf,
9259 nameXMMReg(gregOfRexRM(pfx,modrm)) );
9260 }
9261
9262 if (r2zero) {
9263 assign(rmode, mkU32((UInt)Irrm_ZERO) );
9264 } else {
9265 assign( rmode, get_sse_roundingmode() );
9266 }
9267
sewardj09717342005-05-05 21:34:02 +00009268 t0 = newTemp(Ity_F64);
9269 t1 = newTemp(Ity_F64);
9270 assign( t0, unop(Iop_ReinterpI64asF64,
9271 unop(Iop_V128to64, mkexpr(argV))) );
9272 assign( t1, unop(Iop_ReinterpI64asF64,
9273 unop(Iop_V128HIto64, mkexpr(argV))) );
9274
9275# define CVT(_t) binop( Iop_F64toI32, \
9276 mkexpr(rmode), \
9277 mkexpr(_t) )
9278
9279 putXMMRegLane32( gregOfRexRM(pfx,modrm), 3, mkU32(0) );
9280 putXMMRegLane32( gregOfRexRM(pfx,modrm), 2, mkU32(0) );
9281 putXMMRegLane32( gregOfRexRM(pfx,modrm), 1, CVT(t1) );
9282 putXMMRegLane32( gregOfRexRM(pfx,modrm), 0, CVT(t0) );
9283
9284# undef CVT
9285
9286 goto decode_success;
9287 }
9288
sewardj5992bd02005-05-11 02:13:42 +00009289 /* 66 0F 2D = CVTPD2PI -- convert 2 x F64 in mem/xmm to 2 x
9290 I32 in mmx, according to prevailing SSE rounding mode */
9291 /* 66 0F 2C = CVTTPD2PI -- convert 2 x F64 in mem/xmm to 2 x
9292 I32 in mmx, rounding towards zero */
9293 if (have66noF2noF3(pfx) && sz == 2
9294 && insn[0] == 0x0F && (insn[1] == 0x2D || insn[1] == 0x2C)) {
9295 IRTemp dst64 = newTemp(Ity_I64);
9296 IRTemp rmode = newTemp(Ity_I32);
9297 IRTemp f64lo = newTemp(Ity_F64);
9298 IRTemp f64hi = newTemp(Ity_F64);
sewardjca673ab2005-05-11 10:03:08 +00009299 Bool r2zero = toBool(insn[1] == 0x2C);
sewardj5992bd02005-05-11 02:13:42 +00009300
9301 do_MMX_preamble();
9302 modrm = getUChar(delta+2);
9303
9304 if (epartIsReg(modrm)) {
9305 delta += 2+1;
9306 assign(f64lo, getXMMRegLane64F(eregOfRexRM(pfx,modrm), 0));
9307 assign(f64hi, getXMMRegLane64F(eregOfRexRM(pfx,modrm), 1));
9308 DIP("cvt%spd2pi %s,%s\n", r2zero ? "t" : "",
9309 nameXMMReg(eregOfRexRM(pfx,modrm)),
9310 nameMMXReg(gregLO3ofRM(modrm)));
9311 } else {
9312 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9313 assign(f64lo, loadLE(Ity_F64, mkexpr(addr)));
9314 assign(f64hi, loadLE(Ity_F64, binop( Iop_Add64,
9315 mkexpr(addr),
9316 mkU64(8) )));
9317 delta += 2+alen;
9318 DIP("cvt%spf2pi %s,%s\n", r2zero ? "t" : "",
9319 dis_buf,
9320 nameMMXReg(gregLO3ofRM(modrm)));
9321 }
9322
9323 if (r2zero) {
9324 assign(rmode, mkU32((UInt)Irrm_ZERO) );
9325 } else {
9326 assign( rmode, get_sse_roundingmode() );
9327 }
9328
9329 assign(
9330 dst64,
9331 binop( Iop_32HLto64,
9332 binop( Iop_F64toI32, mkexpr(rmode), mkexpr(f64hi) ),
9333 binop( Iop_F64toI32, mkexpr(rmode), mkexpr(f64lo) )
9334 )
9335 );
9336
9337 putMMXReg(gregLO3ofRM(modrm), mkexpr(dst64));
9338 goto decode_success;
9339 }
9340
9341 /* 66 0F 5A = CVTPD2PS -- convert 2 x F64 in mem/xmm to 2 x F32 in
9342 lo half xmm(G), rounding according to prevailing SSE rounding
9343 mode, and zero upper half */
9344 /* Note, this is practically identical to CVTPD2DQ. It would have
9345 been nicer to merge them together, but the insn[] offsets differ
9346 by one. */
9347 if (have66noF2noF3(pfx) && sz == 2
9348 && insn[0] == 0x0F && insn[1] == 0x5A) {
9349 IRTemp argV = newTemp(Ity_V128);
9350 IRTemp rmode = newTemp(Ity_I32);
9351
9352 modrm = getUChar(delta+2);
9353 if (epartIsReg(modrm)) {
9354 assign( argV, getXMMReg(eregOfRexRM(pfx,modrm)) );
9355 delta += 2+1;
9356 DIP("cvtpd2ps %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
9357 nameXMMReg(gregOfRexRM(pfx,modrm)));
9358 } else {
9359 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9360 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
9361 delta += 2+alen;
9362 DIP("cvtpd2ps %s,%s\n", dis_buf,
9363 nameXMMReg(gregOfRexRM(pfx,modrm)) );
9364 }
9365
9366 assign( rmode, get_sse_roundingmode() );
9367 t0 = newTemp(Ity_F64);
9368 t1 = newTemp(Ity_F64);
9369 assign( t0, unop(Iop_ReinterpI64asF64,
9370 unop(Iop_V128to64, mkexpr(argV))) );
9371 assign( t1, unop(Iop_ReinterpI64asF64,
9372 unop(Iop_V128HIto64, mkexpr(argV))) );
9373
9374# define CVT(_t) binop( Iop_F64toF32, \
9375 mkexpr(rmode), \
9376 mkexpr(_t) )
9377
9378 putXMMRegLane32( gregOfRexRM(pfx,modrm), 3, mkU32(0) );
9379 putXMMRegLane32( gregOfRexRM(pfx,modrm), 2, mkU32(0) );
9380 putXMMRegLane32F( gregOfRexRM(pfx,modrm), 1, CVT(t1) );
9381 putXMMRegLane32F( gregOfRexRM(pfx,modrm), 0, CVT(t0) );
9382
9383# undef CVT
9384
9385 goto decode_success;
9386 }
9387
9388 /* 66 0F 2A = CVTPI2PD -- convert 2 x I32 in mem/mmx to 2 x F64 in
9389 xmm(G) */
9390 if (have66noF2noF3(pfx) && sz == 2
9391 && insn[0] == 0x0F && insn[1] == 0x2A) {
9392 IRTemp arg64 = newTemp(Ity_I64);
9393
9394 modrm = getUChar(delta+2);
9395 do_MMX_preamble();
9396 if (epartIsReg(modrm)) {
9397 assign( arg64, getMMXReg(eregLO3ofRM(modrm)) );
9398 delta += 2+1;
9399 DIP("cvtpi2pd %s,%s\n", nameMMXReg(eregLO3ofRM(modrm)),
9400 nameXMMReg(gregOfRexRM(pfx,modrm)));
9401 } else {
9402 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9403 assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
9404 delta += 2+alen;
9405 DIP("cvtpi2pd %s,%s\n", dis_buf,
9406 nameXMMReg(gregOfRexRM(pfx,modrm)) );
9407 }
9408
9409 putXMMRegLane64F(
9410 gregOfRexRM(pfx,modrm), 0,
9411 unop(Iop_I32toF64, unop(Iop_64to32, mkexpr(arg64)) )
9412 );
9413
9414 putXMMRegLane64F(
9415 gregOfRexRM(pfx,modrm), 1,
9416 unop(Iop_I32toF64, unop(Iop_64HIto32, mkexpr(arg64)) )
9417 );
9418
9419 goto decode_success;
9420 }
9421
9422 /* F3 0F 5B = CVTTPS2DQ -- convert 4 x F32 in mem/xmm to 4 x I32 in
9423 xmm(G), rounding towards zero */
9424 /* 66 0F 5B = CVTPS2DQ -- convert 4 x F32 in mem/xmm to 4 x I32 in
9425 xmm(G), as per the prevailing rounding mode */
9426 if ( ( (have66noF2noF3(pfx) && sz == 2)
9427 || (haveF3no66noF2(pfx) && sz == 4)
9428 )
9429 && insn[0] == 0x0F && insn[1] == 0x5B) {
9430 IRTemp argV = newTemp(Ity_V128);
9431 IRTemp rmode = newTemp(Ity_I32);
9432 Bool r2zero = toBool(sz == 4);
9433
9434 modrm = getUChar(delta+2);
9435 if (epartIsReg(modrm)) {
9436 assign( argV, getXMMReg(eregOfRexRM(pfx,modrm)) );
9437 delta += 2+1;
9438 DIP("cvtps2dq %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
9439 nameXMMReg(gregOfRexRM(pfx,modrm)));
9440 } else {
9441 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9442 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
9443 delta += 2+alen;
9444 DIP("cvtps2dq %s,%s\n", dis_buf,
9445 nameXMMReg(gregOfRexRM(pfx,modrm)) );
9446 }
9447
9448 if (r2zero) {
9449 assign( rmode, mkU32((UInt)Irrm_ZERO) );
9450 } else {
9451 assign( rmode, get_sse_roundingmode() );
9452 }
9453
9454 breakup128to32s( argV, &t3, &t2, &t1, &t0 );
9455
9456 /* This is less than ideal. If it turns out to be a performance
9457 bottleneck it can be improved. */
9458# define CVT(_t) \
9459 binop( Iop_F64toI32, \
9460 mkexpr(rmode), \
9461 unop( Iop_F32toF64, \
9462 unop( Iop_ReinterpI32asF32, mkexpr(_t))) )
9463
9464 putXMMRegLane32( gregOfRexRM(pfx,modrm), 3, CVT(t3) );
9465 putXMMRegLane32( gregOfRexRM(pfx,modrm), 2, CVT(t2) );
9466 putXMMRegLane32( gregOfRexRM(pfx,modrm), 1, CVT(t1) );
9467 putXMMRegLane32( gregOfRexRM(pfx,modrm), 0, CVT(t0) );
9468
9469# undef CVT
9470
9471 goto decode_success;
9472 }
9473
9474 /* 0F 5A = CVTPS2PD -- convert 2 x F32 in low half mem/xmm to 2 x
9475 F64 in xmm(G). */
9476 if (haveNo66noF2noF3(pfx) && sz == 4
9477 && insn[0] == 0x0F && insn[1] == 0x5A) {
9478 IRTemp f32lo = newTemp(Ity_F32);
9479 IRTemp f32hi = newTemp(Ity_F32);
9480
9481 modrm = getUChar(delta+2);
9482 if (epartIsReg(modrm)) {
9483 assign( f32lo, getXMMRegLane32F(eregOfRexRM(pfx,modrm), 0) );
9484 assign( f32hi, getXMMRegLane32F(eregOfRexRM(pfx,modrm), 1) );
9485 delta += 2+1;
9486 DIP("cvtps2pd %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
9487 nameXMMReg(gregOfRexRM(pfx,modrm)));
9488 } else {
9489 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9490 assign( f32lo, loadLE(Ity_F32, mkexpr(addr)) );
9491 assign( f32hi, loadLE(Ity_F32,
9492 binop(Iop_Add64,mkexpr(addr),mkU64(4))) );
9493 delta += 2+alen;
9494 DIP("cvtps2pd %s,%s\n", dis_buf,
9495 nameXMMReg(gregOfRexRM(pfx,modrm)) );
9496 }
9497
9498 putXMMRegLane64F( gregOfRexRM(pfx,modrm), 1,
9499 unop(Iop_F32toF64, mkexpr(f32hi)) );
9500 putXMMRegLane64F( gregOfRexRM(pfx,modrm), 0,
9501 unop(Iop_F32toF64, mkexpr(f32lo)) );
9502
9503 goto decode_success;
9504 }
9505
9506 /* F2 0F 2D = CVTSD2SI
9507 when sz==4 -- convert F64 in mem/low half xmm to I32 in ireg,
9508 according to prevailing SSE rounding mode
9509 when sz==8 -- convert F64 in mem/low half xmm to I64 in ireg,
9510 according to prevailing SSE rounding mode
9511 */
sewardj1a01e652005-02-23 11:39:21 +00009512 /* F2 0F 2C = CVTTSD2SI
9513 when sz==4 -- convert F64 in mem/low half xmm to I32 in ireg,
9514 truncating towards zero
9515 when sz==8 -- convert F64 in mem/low half xmm to I64 in ireg,
9516 truncating towards zero
9517 */
9518 if (haveF2no66noF3(pfx)
9519 && insn[0] == 0x0F
sewardj5992bd02005-05-11 02:13:42 +00009520 && (insn[1] == 0x2D || insn[1] == 0x2C)) {
sewardj1a01e652005-02-23 11:39:21 +00009521 IRTemp rmode = newTemp(Ity_I32);
9522 IRTemp f64lo = newTemp(Ity_F64);
sewardj1027dc22005-02-26 01:55:02 +00009523 Bool r2zero = toBool(insn[1] == 0x2C);
sewardj1a01e652005-02-23 11:39:21 +00009524 vassert(sz == 4 || sz == 8);
9525
9526 modrm = getUChar(delta+2);
9527 if (epartIsReg(modrm)) {
9528 delta += 2+1;
9529 assign(f64lo, getXMMRegLane64F(eregOfRexRM(pfx,modrm), 0));
9530 DIP("cvt%ssd2si %s,%s\n", r2zero ? "t" : "",
9531 nameXMMReg(eregOfRexRM(pfx,modrm)),
sewardj5b470602005-02-27 13:10:48 +00009532 nameIReg(sz, gregOfRexRM(pfx,modrm), False));
sewardj1a01e652005-02-23 11:39:21 +00009533 } else {
9534 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9535 assign(f64lo, loadLE(Ity_F64, mkexpr(addr)));
9536 delta += 2+alen;
9537 DIP("cvt%ssd2si %s,%s\n", r2zero ? "t" : "",
9538 dis_buf,
sewardj5b470602005-02-27 13:10:48 +00009539 nameIReg(sz, gregOfRexRM(pfx,modrm), False));
sewardj1a01e652005-02-23 11:39:21 +00009540 }
9541
9542 if (r2zero) {
9543 assign( rmode, mkU32((UInt)Irrm_ZERO) );
9544 } else {
9545 assign( rmode, get_sse_roundingmode() );
9546 }
9547
9548 if (sz == 4) {
sewardj5b470602005-02-27 13:10:48 +00009549 putIReg32( gregOfRexRM(pfx,modrm),
9550 binop( Iop_F64toI32, mkexpr(rmode), mkexpr(f64lo)) );
sewardj1a01e652005-02-23 11:39:21 +00009551 } else {
sewardj5b470602005-02-27 13:10:48 +00009552 putIReg64( gregOfRexRM(pfx,modrm),
9553 binop( Iop_F64toI64, mkexpr(rmode), mkexpr(f64lo)) );
sewardj1a01e652005-02-23 11:39:21 +00009554 }
9555
9556 goto decode_success;
9557 }
9558
sewardj8d965312005-02-25 02:48:47 +00009559 /* F2 0F 5A = CVTSD2SS -- convert F64 in mem/low half xmm to F32 in
9560 low 1/4 xmm(G), according to prevailing SSE rounding mode */
9561 if (haveF2no66noF3(pfx) && sz == 4
9562 && insn[0] == 0x0F && insn[1] == 0x5A) {
9563 IRTemp rmode = newTemp(Ity_I32);
9564 IRTemp f64lo = newTemp(Ity_F64);
9565 vassert(sz == 4);
9566
9567 modrm = getUChar(delta+2);
9568 if (epartIsReg(modrm)) {
9569 delta += 2+1;
9570 assign(f64lo, getXMMRegLane64F(eregOfRexRM(pfx,modrm), 0));
9571 DIP("cvtsd2ss %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
9572 nameXMMReg(gregOfRexRM(pfx,modrm)));
9573 } else {
9574 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9575 assign(f64lo, loadLE(Ity_F64, mkexpr(addr)));
9576 delta += 2+alen;
9577 DIP("cvtsd2ss %s,%s\n", dis_buf,
9578 nameXMMReg(gregOfRexRM(pfx,modrm)));
9579 }
9580
9581 assign( rmode, get_sse_roundingmode() );
9582 putXMMRegLane32F(
9583 gregOfRexRM(pfx,modrm), 0,
9584 binop( Iop_F64toF32, mkexpr(rmode), mkexpr(f64lo) )
9585 );
9586
9587 goto decode_success;
9588 }
sewardj1a01e652005-02-23 11:39:21 +00009589
9590 /* F2 0F 2A = CVTSI2SD
9591 when sz==4 -- convert I32 in mem/ireg to F64 in low half xmm
9592 when sz==8 -- convert I64 in mem/ireg to F64 in low half xmm
9593 */
sewardj8d965312005-02-25 02:48:47 +00009594 if (haveF2no66noF3(pfx) && (sz == 4 || sz == 8)
9595 && insn[0] == 0x0F && insn[1] == 0x2A) {
sewardj1a01e652005-02-23 11:39:21 +00009596 modrm = getUChar(delta+2);
9597
9598 if (sz == 4) {
9599 IRTemp arg32 = newTemp(Ity_I32);
9600 if (epartIsReg(modrm)) {
sewardj5b470602005-02-27 13:10:48 +00009601 assign( arg32, getIReg32(eregOfRexRM(pfx,modrm)) );
sewardj1a01e652005-02-23 11:39:21 +00009602 delta += 2+1;
sewardj5b470602005-02-27 13:10:48 +00009603 DIP("cvtsi2sd %s,%s\n", nameIReg32(eregOfRexRM(pfx,modrm)),
sewardj1a01e652005-02-23 11:39:21 +00009604 nameXMMReg(gregOfRexRM(pfx,modrm)));
9605 } else {
9606 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9607 assign( arg32, loadLE(Ity_I32, mkexpr(addr)) );
9608 delta += 2+alen;
9609 DIP("cvtsi2sd %s,%s\n", dis_buf,
9610 nameXMMReg(gregOfRexRM(pfx,modrm)) );
9611 }
9612 putXMMRegLane64F( gregOfRexRM(pfx,modrm), 0,
9613 unop(Iop_I32toF64, mkexpr(arg32))
9614 );
9615 } else {
9616 /* sz == 8 */
9617 IRTemp arg64 = newTemp(Ity_I64);
9618 if (epartIsReg(modrm)) {
sewardj5b470602005-02-27 13:10:48 +00009619 assign( arg64, getIReg64(eregOfRexRM(pfx,modrm)) );
sewardj1a01e652005-02-23 11:39:21 +00009620 delta += 2+1;
sewardj5b470602005-02-27 13:10:48 +00009621 DIP("cvtsi2sdq %s,%s\n", nameIReg64(eregOfRexRM(pfx,modrm)),
sewardj8d965312005-02-25 02:48:47 +00009622 nameXMMReg(gregOfRexRM(pfx,modrm)));
sewardj1a01e652005-02-23 11:39:21 +00009623 } else {
9624 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9625 assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
9626 delta += 2+alen;
sewardj8d965312005-02-25 02:48:47 +00009627 DIP("cvtsi2sdq %s,%s\n", dis_buf,
9628 nameXMMReg(gregOfRexRM(pfx,modrm)) );
sewardj1a01e652005-02-23 11:39:21 +00009629 }
9630 putXMMRegLane64F(
9631 gregOfRexRM(pfx,modrm),
9632 0,
9633 binop( Iop_I64toF64,
9634 get_sse_roundingmode(),
9635 mkexpr(arg64)
9636 )
9637 );
9638
9639 }
9640
9641 goto decode_success;
9642 }
9643
sewardjc49ce232005-02-25 13:03:03 +00009644 /* F3 0F 5A = CVTSS2SD -- convert F32 in mem/low 1/4 xmm to F64 in
9645 low half xmm(G) */
9646 if (haveF3no66noF2(pfx) && sz == 4
9647 && insn[0] == 0x0F && insn[1] == 0x5A) {
9648 IRTemp f32lo = newTemp(Ity_F32);
9649
9650 modrm = getUChar(delta+2);
9651 if (epartIsReg(modrm)) {
9652 delta += 2+1;
9653 assign(f32lo, getXMMRegLane32F(eregOfRexRM(pfx,modrm), 0));
9654 DIP("cvtss2sd %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
9655 nameXMMReg(gregOfRexRM(pfx,modrm)));
9656 } else {
9657 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9658 assign(f32lo, loadLE(Ity_F32, mkexpr(addr)));
9659 delta += 2+alen;
9660 DIP("cvtss2sd %s,%s\n", dis_buf,
9661 nameXMMReg(gregOfRexRM(pfx,modrm)));
9662 }
9663
9664 putXMMRegLane64F( gregOfRexRM(pfx,modrm), 0,
9665 unop( Iop_F32toF64, mkexpr(f32lo) ) );
9666
9667 goto decode_success;
9668 }
9669
sewardj5992bd02005-05-11 02:13:42 +00009670 /* 66 0F 5E = DIVPD -- div 64Fx2 from R/M to R */
9671 if (have66noF2noF3(pfx) && sz == 2
9672 && insn[0] == 0x0F && insn[1] == 0x5E) {
9673 delta = dis_SSE_E_to_G_all( pfx, delta+2, "divpd", Iop_Div64Fx2 );
9674 goto decode_success;
9675 }
sewardj1001dc42005-02-21 08:25:55 +00009676
9677 /* F2 0F 5E = DIVSD -- div 64F0x2 from R/M to R */
9678 if (haveF2no66noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x5E) {
9679 vassert(sz == 4);
9680 delta = dis_SSE_E_to_G_lo64( pfx, delta+2, "divsd", Iop_Div64F0x2 );
9681 goto decode_success;
9682 }
9683
sewardj5992bd02005-05-11 02:13:42 +00009684 /* 0F AE /5 = LFENCE -- flush pending operations to memory */
9685 /* 0F AE /6 = MFENCE -- flush pending operations to memory */
9686 if (haveNo66noF2noF3(pfx) && sz == 4
9687 && insn[0] == 0x0F && insn[1] == 0xAE
9688 && epartIsReg(insn[2])
9689 && (gregLO3ofRM(insn[2]) == 5 || gregLO3ofRM(insn[2]) == 6)) {
9690 delta += 3;
9691 /* Insert a memory fence. It's sometimes important that these
9692 are carried through to the generated code. */
9693 stmt( IRStmt_MFence() );
9694 DIP("%sfence\n", gregLO3ofRM(insn[2])==5 ? "l" : "m");
9695 goto decode_success;
9696 }
9697
9698 /* 66 0F 5F = MAXPD -- max 64Fx2 from R/M to R */
9699 if (have66noF2noF3(pfx) && sz == 2
9700 && insn[0] == 0x0F && insn[1] == 0x5F) {
9701 delta = dis_SSE_E_to_G_all( pfx, delta+2, "maxpd", Iop_Max64Fx2 );
9702 goto decode_success;
9703 }
sewardj1a01e652005-02-23 11:39:21 +00009704
9705 /* F2 0F 5F = MAXSD -- max 64F0x2 from R/M to R */
9706 if (haveF2no66noF3(pfx) && sz == 4
9707 && insn[0] == 0x0F && insn[1] == 0x5F) {
9708 delta = dis_SSE_E_to_G_lo64( pfx, delta+2, "maxsd", Iop_Max64F0x2 );
9709 goto decode_success;
9710 }
9711
sewardj5992bd02005-05-11 02:13:42 +00009712 /* 66 0F 5D = MINPD -- min 64Fx2 from R/M to R */
9713 if (have66noF2noF3(pfx) && sz == 2
9714 && insn[0] == 0x0F && insn[1] == 0x5D) {
9715 delta = dis_SSE_E_to_G_all( pfx, delta+2, "minpd", Iop_Min64Fx2 );
9716 goto decode_success;
9717 }
sewardjc49ce232005-02-25 13:03:03 +00009718
9719 /* F2 0F 5D = MINSD -- min 64F0x2 from R/M to R */
9720 if (haveF2no66noF3(pfx) && sz == 4
9721 && insn[0] == 0x0F && insn[1] == 0x5D) {
9722 delta = dis_SSE_E_to_G_lo64( pfx, delta+2, "minsd", Iop_Min64F0x2 );
9723 goto decode_success;
9724 }
sewardj8d965312005-02-25 02:48:47 +00009725
9726 /* 66 0F 28 = MOVAPD -- move from E (mem or xmm) to G (xmm). */
9727 /* 66 0F 10 = MOVUPD -- move from E (mem or xmm) to G (xmm). */
9728 /* 66 0F 6F = MOVDQA -- move from E (mem or xmm) to G (xmm). */
9729 if (have66noF2noF3(pfx) && sz == 2
9730 && insn[0] == 0x0F
9731 && (insn[1] == 0x28 || insn[1] == 0x10 || insn[1] == 0x6F)) {
9732 HChar* wot = insn[1]==0x28 ? "apd" :
9733 insn[1]==0x10 ? "upd" : "dqa";
9734 modrm = getUChar(delta+2);
9735 if (epartIsReg(modrm)) {
9736 putXMMReg( gregOfRexRM(pfx,modrm),
9737 getXMMReg( eregOfRexRM(pfx,modrm) ));
9738 DIP("mov%s %s,%s\n", wot, nameXMMReg(eregOfRexRM(pfx,modrm)),
9739 nameXMMReg(gregOfRexRM(pfx,modrm)));
9740 delta += 2+1;
9741 } else {
9742 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9743 putXMMReg( gregOfRexRM(pfx,modrm),
9744 loadLE(Ity_V128, mkexpr(addr)) );
9745 DIP("mov%s %s,%s\n", wot, dis_buf,
9746 nameXMMReg(gregOfRexRM(pfx,modrm)));
9747 delta += 2+alen;
9748 }
9749 goto decode_success;
9750 }
9751
sewardj4c328cf2005-05-05 12:05:54 +00009752 /* 66 0F 29 = MOVAPD -- move from G (xmm) to E (mem or xmm). */
9753 if (have66noF2noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x29) {
9754 modrm = getUChar(delta+2);
9755 if (epartIsReg(modrm)) {
9756 /* fall through; awaiting test case */
9757 } else {
9758 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9759 storeLE( mkexpr(addr), getXMMReg(gregOfRexRM(pfx,modrm)) );
9760 DIP("movapd %s,%s\n", nameXMMReg(gregOfRexRM(pfx,modrm)),
9761 dis_buf );
9762 delta += 2+alen;
9763 goto decode_success;
9764 }
9765 }
9766
sewardj09717342005-05-05 21:34:02 +00009767 /* 66 0F 6E = MOVD from ireg32/m32 to xmm lo 1/4, zeroing high 3/4 of xmm. */
9768 /* or from ireg64/m64 to xmm lo 1/2, zeroing high 1/2 of xmm. */
9769 if (have66noF2noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x6E) {
sewardj97628592005-05-10 22:42:54 +00009770 vassert(sz == 2 || sz == 8);
9771 if (sz == 2) sz = 4;
sewardj09717342005-05-05 21:34:02 +00009772 modrm = getUChar(delta+2);
9773 if (epartIsReg(modrm)) {
9774 delta += 2+1;
9775 if (sz == 4) {
sewardj09717342005-05-05 21:34:02 +00009776 putXMMReg(
9777 gregOfRexRM(pfx,modrm),
9778 unop( Iop_32UtoV128, getIReg32(eregOfRexRM(pfx,modrm)) )
9779 );
9780 DIP("movd %s, %s\n", nameIReg32(eregOfRexRM(pfx,modrm)),
9781 nameXMMReg(gregOfRexRM(pfx,modrm)));
9782 } else {
9783 putXMMReg(
9784 gregOfRexRM(pfx,modrm),
9785 unop( Iop_64UtoV128, getIReg64(eregOfRexRM(pfx,modrm)) )
9786 );
9787 DIP("movq %s, %s\n", nameIReg64(eregOfRexRM(pfx,modrm)),
9788 nameXMMReg(gregOfRexRM(pfx,modrm)));
9789 }
9790 } else {
9791 addr = disAMode( &alen, pfx, delta+2, dis_buf, 0 );
9792 delta += 2+alen;
9793 putXMMReg(
9794 gregOfRexRM(pfx,modrm),
9795 sz == 4
9796 ? unop( Iop_32UtoV128,loadLE(Ity_I32, mkexpr(addr)) )
9797 : unop( Iop_64UtoV128,loadLE(Ity_I64, mkexpr(addr)) )
9798 );
9799 DIP("mov%c %s, %s\n", sz == 4 ? 'd' : 'q', dis_buf,
9800 nameXMMReg(gregOfRexRM(pfx,modrm)));
9801 }
9802 goto decode_success;
9803 }
9804
9805 /* 66 0F 7E = MOVD from xmm low 1/4 to ireg32 or m32. */
9806 /* or from xmm low 1/2 to ireg64 or m64. */
9807 if (have66noF2noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x7E) {
9808 if (sz == 2) sz = 4;
9809 vassert(sz == 4 || sz == 8);
9810 modrm = getUChar(delta+2);
9811 if (epartIsReg(modrm)) {
9812 delta += 2+1;
9813 if (sz == 4) {
9814 putIReg32( eregOfRexRM(pfx,modrm),
9815 getXMMRegLane32(gregOfRexRM(pfx,modrm), 0) );
9816 DIP("movd %s, %s\n", nameXMMReg(gregOfRexRM(pfx,modrm)),
9817 nameIReg32(eregOfRexRM(pfx,modrm)));
9818 } else {
9819 putIReg64( eregOfRexRM(pfx,modrm),
9820 getXMMRegLane64(gregOfRexRM(pfx,modrm), 0) );
9821 DIP("movq %s, %s\n", nameXMMReg(gregOfRexRM(pfx,modrm)),
9822 nameIReg64(eregOfRexRM(pfx,modrm)));
9823 }
9824 } else {
9825 addr = disAMode( &alen, pfx, delta+2, dis_buf, 0 );
9826 delta += 2+alen;
9827 storeLE( mkexpr(addr),
9828 sz == 4
9829 ? getXMMRegLane32(gregOfRexRM(pfx,modrm),0)
9830 : getXMMRegLane64(gregOfRexRM(pfx,modrm),0) );
9831 DIP("mov%c %s, %s\n", sz == 4 ? 'd' : 'q',
9832 nameXMMReg(gregOfRexRM(pfx,modrm)), dis_buf);
9833 }
9834 goto decode_success;
9835 }
9836
9837 /* 66 0F 7F = MOVDQA -- move from G (xmm) to E (mem or xmm). */
9838 if (have66noF2noF3(pfx) && sz == 2
9839 && insn[0] == 0x0F && insn[1] == 0x7F) {
9840 modrm = getUChar(delta+2);
9841 if (epartIsReg(modrm)) {
9842 delta += 2+1;
9843 putXMMReg( eregOfRexRM(pfx,modrm),
9844 getXMMReg(gregOfRexRM(pfx,modrm)) );
9845 DIP("movdqa %s, %s\n", nameXMMReg(gregOfRexRM(pfx,modrm)),
9846 nameXMMReg(eregOfRexRM(pfx,modrm)));
9847 } else {
9848 addr = disAMode( &alen, pfx, delta+2, dis_buf, 0 );
9849 delta += 2+alen;
9850 storeLE( mkexpr(addr), getXMMReg(gregOfRexRM(pfx,modrm)) );
9851 DIP("movdqa %s, %s\n", nameXMMReg(gregOfRexRM(pfx,modrm)), dis_buf);
9852 }
9853 goto decode_success;
9854 }
9855
sewardj612be432005-05-11 02:55:54 +00009856 /* F3 0F 6F = MOVDQU -- move from E (mem or xmm) to G (xmm). */
9857 if (haveF3no66noF2(pfx) && sz == 4
9858 && insn[0] == 0x0F && insn[1] == 0x6F) {
9859 modrm = getUChar(delta+2);
9860 if (epartIsReg(modrm)) {
9861 putXMMReg( gregOfRexRM(pfx,modrm),
9862 getXMMReg( eregOfRexRM(pfx,modrm) ));
9863 DIP("movdqu %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
9864 nameXMMReg(gregOfRexRM(pfx,modrm)));
9865 delta += 2+1;
9866 } else {
9867 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9868 putXMMReg( gregOfRexRM(pfx,modrm),
9869 loadLE(Ity_V128, mkexpr(addr)) );
9870 DIP("movdqu %s,%s\n", dis_buf,
9871 nameXMMReg(gregOfRexRM(pfx,modrm)));
9872 delta += 2+alen;
9873 }
9874 goto decode_success;
9875 }
9876
9877 /* F3 0F 7F = MOVDQU -- move from G (xmm) to E (mem or xmm). */
9878 if (haveF3no66noF2(pfx) && sz == 4
9879 && insn[0] == 0x0F && insn[1] == 0x7F) {
9880 modrm = getUChar(delta+2);
9881 if (epartIsReg(modrm)) {
9882 goto decode_failure; /* awaiting test case */
9883 delta += 2+1;
9884 putXMMReg( eregOfRexRM(pfx,modrm),
9885 getXMMReg(gregOfRexRM(pfx,modrm)) );
9886 DIP("movdqu %s, %s\n", nameXMMReg(gregOfRexRM(pfx,modrm)),
9887 nameXMMReg(eregOfRexRM(pfx,modrm)));
9888 } else {
9889 addr = disAMode( &alen, pfx, delta+2, dis_buf, 0 );
9890 delta += 2+alen;
9891 storeLE( mkexpr(addr), getXMMReg(gregOfRexRM(pfx,modrm)) );
9892 DIP("movdqu %s, %s\n", nameXMMReg(gregOfRexRM(pfx,modrm)), dis_buf);
9893 }
9894 goto decode_success;
9895 }
9896
9897 /* F2 0F D6 = MOVDQ2Q -- move from E (lo half xmm, not mem) to G (mmx). */
9898 if (haveF2no66noF3(pfx) && sz == 4
9899 && insn[0] == 0x0F && insn[1] == 0xD6) {
9900 modrm = getUChar(delta+2);
9901 if (epartIsReg(modrm)) {
9902 do_MMX_preamble();
9903 putMMXReg( gregLO3ofRM(modrm),
9904 getXMMRegLane64( eregOfRexRM(pfx,modrm), 0 ));
9905 DIP("movdq2q %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
9906 nameMMXReg(gregLO3ofRM(modrm)));
9907 delta += 2+1;
9908 goto decode_success;
9909 } else {
9910 /* apparently no mem case for this insn */
9911 goto decode_failure;
9912 }
9913 }
sewardj4c328cf2005-05-05 12:05:54 +00009914
9915 /* 66 0F 16 = MOVHPD -- move from mem to high half of XMM. */
9916 /* These seems identical to MOVHPS. This instruction encoding is
9917 completely crazy. */
9918 if (have66noF2noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x16) {
9919 modrm = getUChar(delta+2);
9920 if (epartIsReg(modrm)) {
9921 /* fall through; apparently reg-reg is not possible */
9922 } else {
9923 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9924 delta += 2+alen;
9925 putXMMRegLane64( gregOfRexRM(pfx,modrm), 1/*upper lane*/,
9926 loadLE(Ity_I64, mkexpr(addr)) );
9927 DIP("movhpd %s,%s\n", dis_buf,
9928 nameXMMReg( gregOfRexRM(pfx,modrm) ));
9929 goto decode_success;
9930 }
9931 }
9932
9933 /* 66 0F 17 = MOVHPD -- move from high half of XMM to mem. */
9934 /* Again, this seems identical to MOVHPS. */
9935 if (have66noF2noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x17) {
9936 if (!epartIsReg(insn[2])) {
9937 delta += 2;
9938 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
9939 delta += alen;
9940 storeLE( mkexpr(addr),
9941 getXMMRegLane64( gregOfRexRM(pfx,insn[2]),
9942 1/*upper lane*/ ) );
9943 DIP("movhpd %s,%s\n", nameXMMReg( gregOfRexRM(pfx,insn[2]) ),
9944 dis_buf);
9945 goto decode_success;
9946 }
9947 /* else fall through */
9948 }
sewardj1001dc42005-02-21 08:25:55 +00009949
9950 /* 66 0F 12 = MOVLPD -- move from mem to low half of XMM. */
9951 /* Identical to MOVLPS ? */
9952 if (have66noF2noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x12) {
9953 modrm = getUChar(delta+2);
9954 if (epartIsReg(modrm)) {
9955 /* fall through; apparently reg-reg is not possible */
9956 } else {
9957 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9958 delta += 2+alen;
9959 putXMMRegLane64( gregOfRexRM(pfx,modrm),
9960 0/*lower lane*/,
9961 loadLE(Ity_I64, mkexpr(addr)) );
9962 DIP("movlpd %s, %s\n",
9963 dis_buf, nameXMMReg( gregOfRexRM(pfx,modrm) ));
9964 goto decode_success;
9965 }
9966 }
9967
sewardj4c328cf2005-05-05 12:05:54 +00009968 /* 66 0F 13 = MOVLPD -- move from low half of XMM to mem. */
9969 /* Identical to MOVLPS ? */
9970 if (have66noF2noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x13) {
9971 modrm = getUChar(delta+2);
9972 if (!epartIsReg(modrm)) {
9973 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9974 delta += 2+alen;
9975 storeLE( mkexpr(addr),
9976 getXMMRegLane64( gregOfRexRM(pfx,modrm),
9977 0/*lower lane*/ ) );
9978 DIP("movlpd %s, %s\n", nameXMMReg( gregOfRexRM(pfx,modrm) ),
9979 dis_buf);
9980 goto decode_success;
9981 }
9982 /* else fall through */
9983 }
9984
sewardj612be432005-05-11 02:55:54 +00009985 /* 66 0F 50 = MOVMSKPD - move 2 sign bits from 2 x F64 in xmm(E) to
9986 2 lowest bits of ireg(G) */
9987 if (have66noF2noF3(pfx) && sz == 2
9988 && insn[0] == 0x0F && insn[1] == 0x50) {
9989 modrm = getUChar(delta+2);
9990 if (epartIsReg(modrm)) {
9991 Int src;
9992 t0 = newTemp(Ity_I32);
9993 t1 = newTemp(Ity_I32);
9994 delta += 2+1;
9995 src = eregOfRexRM(pfx,modrm);
9996 assign( t0, binop( Iop_And32,
9997 binop(Iop_Shr32, getXMMRegLane32(src,1), mkU8(31)),
9998 mkU32(1) ));
9999 assign( t1, binop( Iop_And32,
10000 binop(Iop_Shr32, getXMMRegLane32(src,3), mkU8(30)),
10001 mkU32(2) ));
10002 putIReg32( gregOfRexRM(pfx,modrm),
10003 binop(Iop_Or32, mkexpr(t0), mkexpr(t1))
10004 );
10005 DIP("movmskpd %s,%s\n", nameXMMReg(src),
10006 nameIReg32(gregOfRexRM(pfx,modrm)));
10007 goto decode_success;
10008 }
10009 /* else fall through */
10010 goto decode_failure;
10011 }
10012
10013 /* 66 0F E7 = MOVNTDQ -- for us, just a plain SSE store. */
10014 if (have66noF2noF3(pfx) && sz == 2
10015 && insn[0] == 0x0F && insn[1] == 0xE7) {
10016 modrm = getUChar(delta+2);
10017 if (!epartIsReg(modrm)) {
10018 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10019 storeLE( mkexpr(addr), getXMMReg(gregOfRexRM(pfx,modrm)) );
10020 DIP("movntdq %s,%s\n", dis_buf,
10021 nameXMMReg(gregOfRexRM(pfx,modrm)));
10022 delta += 2+alen;
10023 goto decode_success;
10024 }
10025 /* else fall through */
10026 goto decode_failure;
10027 }
sewardjf53b7352005-04-06 20:01:56 +000010028
10029 /* 0F C3 = MOVNTI -- for us, just a plain ireg store. */
10030 if (haveNo66noF2noF3(pfx) &&
10031 insn[0] == 0x0F && insn[1] == 0xC3) {
10032 vassert(sz == 4 || sz == 8);
10033 modrm = getUChar(delta+2);
10034 if (!epartIsReg(modrm)) {
10035 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10036 storeLE( mkexpr(addr), getIRegG(sz, pfx, modrm) );
10037 DIP("movnti %s,%s\n", dis_buf,
10038 nameIRegG(sz, pfx, modrm));
10039 delta += 2+alen;
10040 goto decode_success;
10041 }
10042 /* else fall through */
10043 }
sewardj5cc00ff2005-03-27 04:48:32 +000010044
10045 /* 66 0F D6 = MOVQ -- move 64 bits from G (lo half xmm) to E (mem
10046 or lo half xmm). */
10047 if (have66noF2noF3(pfx) && insn[0] == 0x0F && insn[1] == 0xD6) {
10048 vassert(sz == 2);
10049 modrm = getUChar(delta+2);
10050 if (epartIsReg(modrm)) {
10051 /* fall through, awaiting test case */
sewardj94a48b22005-05-14 11:17:25 +000010052 /* dst: lo half copied, hi half zeroed */
sewardj5cc00ff2005-03-27 04:48:32 +000010053 } else {
10054 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10055 storeLE( mkexpr(addr),
10056 getXMMRegLane64( gregOfRexRM(pfx,modrm), 0 ));
10057 DIP("movq %s,%s\n", nameXMMReg(gregOfRexRM(pfx,modrm)), dis_buf );
10058 delta += 2+alen;
10059 goto decode_success;
10060 }
10061 }
10062
sewardj612be432005-05-11 02:55:54 +000010063 /* F3 0F D6 = MOVQ2DQ -- move from E (mmx) to G (lo half xmm, zero
10064 hi half). */
10065 if (haveF3no66noF2(pfx) && sz == 4
10066 && insn[0] == 0x0F && insn[1] == 0xD6) {
10067 modrm = getUChar(delta+2);
10068 if (epartIsReg(modrm)) {
10069 do_MMX_preamble();
10070 putXMMReg( gregOfRexRM(pfx,modrm),
10071 unop(Iop_64UtoV128, getMMXReg( eregLO3ofRM(modrm) )) );
10072 DIP("movq2dq %s,%s\n", nameMMXReg(eregLO3ofRM(modrm)),
10073 nameXMMReg(gregOfRexRM(pfx,modrm)));
10074 delta += 2+1;
10075 goto decode_success;
10076 } else {
10077 /* apparently no mem case for this insn */
10078 goto decode_failure;
10079 }
10080 }
10081
10082 /* F3 0F 7E = MOVQ -- move 64 bits from E (mem or lo half xmm) to
sewardj94a48b22005-05-14 11:17:25 +000010083 G (lo half xmm). Upper half of G is zeroed out. */
sewardj1001dc42005-02-21 08:25:55 +000010084 /* F2 0F 10 = MOVSD -- move 64 bits from E (mem or lo half xmm) to
10085 G (lo half xmm). If E is mem, upper half of G is zeroed out.
sewardj94a48b22005-05-14 11:17:25 +000010086 If E is reg, upper half of G is unchanged. */
sewardj612be432005-05-11 02:55:54 +000010087 if ( (haveF2no66noF3(pfx) && sz == 4
10088 && insn[0] == 0x0F && insn[1] == 0x10)
sewardj5cc00ff2005-03-27 04:48:32 +000010089 ||
sewardj612be432005-05-11 02:55:54 +000010090 (haveF3no66noF2(pfx) && sz == 4
10091 && insn[0] == 0x0F && insn[1] == 0x7E)
sewardj1001dc42005-02-21 08:25:55 +000010092 ) {
sewardj1001dc42005-02-21 08:25:55 +000010093 modrm = getUChar(delta+2);
10094 if (epartIsReg(modrm)) {
10095 putXMMRegLane64( gregOfRexRM(pfx,modrm), 0,
10096 getXMMRegLane64( eregOfRexRM(pfx,modrm), 0 ));
sewardj94a48b22005-05-14 11:17:25 +000010097 if (insn[1] == 0x7E/*MOVQ*/) {
10098 /* zero bits 127:64 */
10099 putXMMRegLane64( gregOfRexRM(pfx,modrm), 1, mkU64(0) );
10100 }
sewardj1001dc42005-02-21 08:25:55 +000010101 DIP("movsd %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
10102 nameXMMReg(gregOfRexRM(pfx,modrm)));
10103 delta += 2+1;
10104 } else {
10105 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10106 putXMMReg( gregOfRexRM(pfx,modrm), mkV128(0) );
10107 putXMMRegLane64( gregOfRexRM(pfx,modrm), 0,
10108 loadLE(Ity_I64, mkexpr(addr)) );
10109 DIP("movsd %s,%s\n", dis_buf,
10110 nameXMMReg(gregOfRexRM(pfx,modrm)));
10111 delta += 2+alen;
10112 }
10113 goto decode_success;
10114 }
10115
10116 /* F2 0F 11 = MOVSD -- move 64 bits from G (lo half xmm) to E (mem
10117 or lo half xmm). */
sewardj8d965312005-02-25 02:48:47 +000010118 if (haveF2no66noF3(pfx) && sz == 4
10119 && insn[0] == 0x0F && insn[1] == 0x11) {
sewardj1001dc42005-02-21 08:25:55 +000010120 modrm = getUChar(delta+2);
10121 if (epartIsReg(modrm)) {
10122 /* fall through, we don't yet have a test case */
10123 } else {
10124 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10125 storeLE( mkexpr(addr),
10126 getXMMRegLane64(gregOfRexRM(pfx,modrm), 0) );
10127 DIP("movsd %s,%s\n", nameXMMReg(gregOfRexRM(pfx,modrm)),
10128 dis_buf);
10129 delta += 2+alen;
10130 goto decode_success;
10131 }
10132 }
10133
sewardj4c328cf2005-05-05 12:05:54 +000010134 /* 66 0F 59 = MULPD -- mul 64Fx2 from R/M to R */
10135 if (have66noF2noF3(pfx) && sz == 2
10136 && insn[0] == 0x0F && insn[1] == 0x59) {
10137 delta = dis_SSE_E_to_G_all( pfx, delta+2, "mulpd", Iop_Mul64Fx2 );
10138 goto decode_success;
10139 }
sewardj1001dc42005-02-21 08:25:55 +000010140
10141 /* F2 0F 59 = MULSD -- mul 64F0x2 from R/M to R */
sewardj8d965312005-02-25 02:48:47 +000010142 if (haveF2no66noF3(pfx) && sz == 4
10143 && insn[0] == 0x0F && insn[1] == 0x59) {
sewardj1001dc42005-02-21 08:25:55 +000010144 delta = dis_SSE_E_to_G_lo64( pfx, delta+2, "mulsd", Iop_Mul64F0x2 );
10145 goto decode_success;
10146 }
10147
sewardj8d965312005-02-25 02:48:47 +000010148 /* 66 0F 56 = ORPD -- G = G and E */
10149 if (have66noF2noF3(pfx) && sz == 2
10150 && insn[0] == 0x0F && insn[1] == 0x56) {
10151 delta = dis_SSE_E_to_G_all( pfx, delta+2, "orpd", Iop_OrV128 );
10152 goto decode_success;
10153 }
10154
sewardj09717342005-05-05 21:34:02 +000010155 /* 66 0F C6 /r ib = SHUFPD -- shuffle packed F64s */
10156 if (have66noF2noF3(pfx) && sz == 2
10157 && insn[0] == 0x0F && insn[1] == 0xC6) {
10158 Int select;
10159 IRTemp sV = newTemp(Ity_V128);
10160 IRTemp dV = newTemp(Ity_V128);
10161 IRTemp s1 = newTemp(Ity_I64);
10162 IRTemp s0 = newTemp(Ity_I64);
10163 IRTemp d1 = newTemp(Ity_I64);
10164 IRTemp d0 = newTemp(Ity_I64);
10165
10166 modrm = insn[2];
10167 assign( dV, getXMMReg(gregOfRexRM(pfx,modrm)) );
10168
10169 if (epartIsReg(modrm)) {
10170 assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
10171 select = (Int)insn[3];
10172 delta += 2+2;
10173 DIP("shufpd $%d,%s,%s\n", select,
10174 nameXMMReg(eregOfRexRM(pfx,modrm)),
10175 nameXMMReg(gregOfRexRM(pfx,modrm)));
10176 } else {
10177 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 1 );
10178 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
10179 select = (Int)insn[2+alen];
10180 delta += 3+alen;
10181 DIP("shufpd $%d,%s,%s\n", select,
10182 dis_buf,
10183 nameXMMReg(gregOfRexRM(pfx,modrm)));
10184 }
10185
10186 assign( d1, unop(Iop_V128HIto64, mkexpr(dV)) );
10187 assign( d0, unop(Iop_V128to64, mkexpr(dV)) );
10188 assign( s1, unop(Iop_V128HIto64, mkexpr(sV)) );
10189 assign( s0, unop(Iop_V128to64, mkexpr(sV)) );
10190
10191# define SELD(n) mkexpr((n)==0 ? d0 : d1)
10192# define SELS(n) mkexpr((n)==0 ? s0 : s1)
10193
10194 putXMMReg(
10195 gregOfRexRM(pfx,modrm),
10196 binop(Iop_64HLtoV128, SELS((select>>1)&1), SELD((select>>0)&1) )
10197 );
10198
10199# undef SELD
10200# undef SELS
10201
10202 goto decode_success;
10203 }
10204
sewardj97628592005-05-10 22:42:54 +000010205 /* 66 0F 51 = SQRTPD -- approx sqrt 64Fx2 from R/M to R */
10206 if (have66noF2noF3(pfx) && sz == 2
10207 && insn[0] == 0x0F && insn[1] == 0x51) {
10208 delta = dis_SSE_E_to_G_unary_all( pfx, delta+2,
10209 "sqrtpd", Iop_Sqrt64Fx2 );
10210 goto decode_success;
10211 }
sewardj1001dc42005-02-21 08:25:55 +000010212
10213 /* F2 0F 51 = SQRTSD -- approx sqrt 64F0x2 from R/M to R */
10214 if (haveF2no66noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x51) {
10215 vassert(sz == 4);
10216 delta = dis_SSE_E_to_G_unary_lo64( pfx, delta+2,
10217 "sqrtsd", Iop_Sqrt64F0x2 );
10218 goto decode_success;
10219 }
10220
sewardj4c328cf2005-05-05 12:05:54 +000010221 /* 66 0F 5C = SUBPD -- sub 64Fx2 from R/M to R */
10222 if (have66noF2noF3(pfx) && sz == 2
10223 && insn[0] == 0x0F && insn[1] == 0x5C) {
10224 delta = dis_SSE_E_to_G_all( pfx, delta+2, "subpd", Iop_Sub64Fx2 );
10225 goto decode_success;
10226 }
sewardj1001dc42005-02-21 08:25:55 +000010227
10228 /* F2 0F 5C = SUBSD -- sub 64F0x2 from R/M to R */
10229 if (haveF2no66noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x5C) {
10230 vassert(sz == 4);
10231 delta = dis_SSE_E_to_G_lo64( pfx, delta+2, "subsd", Iop_Sub64F0x2 );
10232 goto decode_success;
10233 }
10234
sewardj1a01e652005-02-23 11:39:21 +000010235 /* 66 0F 15 = UNPCKHPD -- unpack and interleave high part F64s */
10236 /* 66 0F 14 = UNPCKLPD -- unpack and interleave low part F64s */
10237 /* These just appear to be special cases of SHUFPS */
10238 if (have66noF2noF3(pfx)
10239 && sz == 2 /* could be 8 if rex also present */
10240 && insn[0] == 0x0F && (insn[1] == 0x15 || insn[1] == 0x14)) {
10241 IRTemp s1 = newTemp(Ity_I64);
10242 IRTemp s0 = newTemp(Ity_I64);
10243 IRTemp d1 = newTemp(Ity_I64);
10244 IRTemp d0 = newTemp(Ity_I64);
10245 IRTemp sV = newTemp(Ity_V128);
10246 IRTemp dV = newTemp(Ity_V128);
sewardj1027dc22005-02-26 01:55:02 +000010247 Bool hi = toBool(insn[1] == 0x15);
sewardj1a01e652005-02-23 11:39:21 +000010248
10249 modrm = insn[2];
10250 assign( dV, getXMMReg(gregOfRexRM(pfx,modrm)) );
10251
10252 if (epartIsReg(modrm)) {
10253 assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
10254 delta += 2+1;
10255 DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
10256 nameXMMReg(eregOfRexRM(pfx,modrm)),
10257 nameXMMReg(gregOfRexRM(pfx,modrm)));
10258 } else {
10259 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10260 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
10261 delta += 2+alen;
10262 DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
10263 dis_buf,
10264 nameXMMReg(gregOfRexRM(pfx,modrm)));
10265 }
10266
10267 assign( d1, unop(Iop_V128HIto64, mkexpr(dV)) );
10268 assign( d0, unop(Iop_V128to64, mkexpr(dV)) );
10269 assign( s1, unop(Iop_V128HIto64, mkexpr(sV)) );
10270 assign( s0, unop(Iop_V128to64, mkexpr(sV)) );
10271
10272 if (hi) {
10273 putXMMReg( gregOfRexRM(pfx,modrm),
10274 binop(Iop_64HLtoV128, mkexpr(s1), mkexpr(d1)) );
10275 } else {
10276 putXMMReg( gregOfRexRM(pfx,modrm),
10277 binop(Iop_64HLtoV128, mkexpr(s0), mkexpr(d0)) );
10278 }
10279
10280 goto decode_success;
10281 }
sewardj9da16972005-02-21 13:58:26 +000010282
10283 /* 66 0F 57 = XORPD -- G = G xor E */
sewardj97628592005-05-10 22:42:54 +000010284 if (have66noF2noF3(pfx) && sz == 2
10285 && insn[0] == 0x0F && insn[1] == 0x57) {
sewardj9da16972005-02-21 13:58:26 +000010286 delta = dis_SSE_E_to_G_all( pfx, delta+2, "xorpd", Iop_XorV128 );
10287 goto decode_success;
10288 }
10289
sewardj97628592005-05-10 22:42:54 +000010290 /* 66 0F 6B = PACKSSDW */
10291 if (have66noF2noF3(pfx) && sz == 2
10292 && insn[0] == 0x0F && insn[1] == 0x6B) {
10293 delta = dis_SSEint_E_to_G( pfx, delta+2,
10294 "packssdw", Iop_QNarrow32Sx4, True );
10295 goto decode_success;
10296 }
10297
10298 /* 66 0F 63 = PACKSSWB */
10299 if (have66noF2noF3(pfx) && sz == 2
10300 && insn[0] == 0x0F && insn[1] == 0x63) {
10301 delta = dis_SSEint_E_to_G( pfx, delta+2,
10302 "packsswb", Iop_QNarrow16Sx8, True );
10303 goto decode_success;
10304 }
10305
10306 /* 66 0F 67 = PACKUSWB */
10307 if (have66noF2noF3(pfx) && sz == 2
10308 && insn[0] == 0x0F && insn[1] == 0x67) {
10309 delta = dis_SSEint_E_to_G( pfx, delta+2,
10310 "packuswb", Iop_QNarrow16Ux8, True );
10311 goto decode_success;
10312 }
10313
10314 /* 66 0F FC = PADDB */
10315 if (have66noF2noF3(pfx) && sz == 2
10316 && insn[0] == 0x0F && insn[1] == 0xFC) {
10317 delta = dis_SSEint_E_to_G( pfx, delta+2,
10318 "paddb", Iop_Add8x16, False );
10319 goto decode_success;
10320 }
10321
10322 /* 66 0F FE = PADDD */
10323 if (have66noF2noF3(pfx) && sz == 2
10324 && insn[0] == 0x0F && insn[1] == 0xFE) {
10325 delta = dis_SSEint_E_to_G( pfx, delta+2,
10326 "paddd", Iop_Add32x4, False );
10327 goto decode_success;
10328 }
sewardj8711f662005-05-09 17:52:56 +000010329
10330 /* ***--- this is an MMX class insn introduced in SSE2 ---*** */
10331 /* 0F D4 = PADDQ -- add 64x1 */
10332 if (haveNo66noF2noF3(pfx) && sz == 4
10333 && insn[0] == 0x0F && insn[1] == 0xD4) {
10334 do_MMX_preamble();
10335 delta = dis_MMXop_regmem_to_reg (
10336 pfx, delta+2, insn[1], "paddq", False );
10337 goto decode_success;
10338 }
sewardj09717342005-05-05 21:34:02 +000010339
10340 /* 66 0F D4 = PADDQ */
10341 if (have66noF2noF3(pfx) && sz == 2
10342 && insn[0] == 0x0F && insn[1] == 0xD4) {
10343 delta = dis_SSEint_E_to_G( pfx, delta+2,
10344 "paddq", Iop_Add64x2, False );
10345 goto decode_success;
10346 }
10347
sewardj5992bd02005-05-11 02:13:42 +000010348 /* 66 0F FD = PADDW */
10349 if (have66noF2noF3(pfx) && sz == 2
10350 && insn[0] == 0x0F && insn[1] == 0xFD) {
10351 delta = dis_SSEint_E_to_G( pfx, delta+2,
10352 "paddw", Iop_Add16x8, False );
10353 goto decode_success;
10354 }
10355
10356 /* 66 0F EC = PADDSB */
10357 if (have66noF2noF3(pfx) && sz == 2
10358 && insn[0] == 0x0F && insn[1] == 0xEC) {
10359 delta = dis_SSEint_E_to_G( pfx, delta+2,
10360 "paddsb", Iop_QAdd8Sx16, False );
10361 goto decode_success;
10362 }
10363
10364 /* 66 0F ED = PADDSW */
10365 if (have66noF2noF3(pfx) && sz == 2
10366 && insn[0] == 0x0F && insn[1] == 0xED) {
10367 delta = dis_SSEint_E_to_G( pfx, delta+2,
10368 "paddsw", Iop_QAdd16Sx8, False );
10369 goto decode_success;
10370 }
10371
10372 /* 66 0F DC = PADDUSB */
10373 if (have66noF2noF3(pfx) && sz == 2
10374 && insn[0] == 0x0F && insn[1] == 0xDC) {
10375 delta = dis_SSEint_E_to_G( pfx, delta+2,
10376 "paddusb", Iop_QAdd8Ux16, False );
10377 goto decode_success;
10378 }
10379
10380 /* 66 0F DD = PADDUSW */
10381 if (have66noF2noF3(pfx) && sz == 2
10382 && insn[0] == 0x0F && insn[1] == 0xDD) {
10383 delta = dis_SSEint_E_to_G( pfx, delta+2,
10384 "paddusw", Iop_QAdd16Ux8, False );
10385 goto decode_success;
10386 }
sewardj09717342005-05-05 21:34:02 +000010387
10388 /* 66 0F DB = PAND */
10389 if (have66noF2noF3(pfx) && sz == 2
10390 && insn[0] == 0x0F && insn[1] == 0xDB) {
10391 delta = dis_SSE_E_to_G_all( pfx, delta+2, "pand", Iop_AndV128 );
10392 goto decode_success;
10393 }
10394
sewardj5992bd02005-05-11 02:13:42 +000010395 /* 66 0F DF = PANDN */
10396 if (have66noF2noF3(pfx) && sz == 2
10397 && insn[0] == 0x0F && insn[1] == 0xDF) {
10398 delta = dis_SSE_E_to_G_all_invG( pfx, delta+2, "pandn", Iop_AndV128 );
10399 goto decode_success;
10400 }
10401
10402 /* 66 0F E0 = PAVGB */
10403 if (have66noF2noF3(pfx) && sz == 2
10404 && insn[0] == 0x0F && insn[1] == 0xE0) {
10405 delta = dis_SSEint_E_to_G( pfx, delta+2,
10406 "pavgb", Iop_Avg8Ux16, False );
10407 goto decode_success;
10408 }
10409
10410 /* 66 0F E3 = PAVGW */
10411 if (have66noF2noF3(pfx) && sz == 2
10412 && insn[0] == 0x0F && insn[1] == 0xE3) {
10413 delta = dis_SSEint_E_to_G( pfx, delta+2,
10414 "pavgw", Iop_Avg16Ux8, False );
10415 goto decode_success;
10416 }
10417
10418 /* 66 0F 74 = PCMPEQB */
10419 if (have66noF2noF3(pfx) && sz == 2
10420 && insn[0] == 0x0F && insn[1] == 0x74) {
10421 delta = dis_SSEint_E_to_G( pfx, delta+2,
10422 "pcmpeqb", Iop_CmpEQ8x16, False );
10423 goto decode_success;
10424 }
10425
10426 /* 66 0F 76 = PCMPEQD */
10427 if (have66noF2noF3(pfx) && sz == 2
10428 && insn[0] == 0x0F && insn[1] == 0x76) {
10429 delta = dis_SSEint_E_to_G( pfx, delta+2,
10430 "pcmpeqd", Iop_CmpEQ32x4, False );
10431 goto decode_success;
10432 }
10433
10434 /* 66 0F 75 = PCMPEQW */
10435 if (have66noF2noF3(pfx) && sz == 2
10436 && insn[0] == 0x0F && insn[1] == 0x75) {
10437 delta = dis_SSEint_E_to_G( pfx, delta+2,
10438 "pcmpeqw", Iop_CmpEQ16x8, False );
10439 goto decode_success;
10440 }
10441
10442 /* 66 0F 64 = PCMPGTB */
10443 if (have66noF2noF3(pfx) && sz == 2
10444 && insn[0] == 0x0F && insn[1] == 0x64) {
10445 delta = dis_SSEint_E_to_G( pfx, delta+2,
10446 "pcmpgtb", Iop_CmpGT8Sx16, False );
10447 goto decode_success;
10448 }
10449
10450 /* 66 0F 66 = PCMPGTD */
10451 if (have66noF2noF3(pfx) && sz == 2
10452 && insn[0] == 0x0F && insn[1] == 0x66) {
10453 delta = dis_SSEint_E_to_G( pfx, delta+2,
10454 "pcmpgtd", Iop_CmpGT32Sx4, False );
10455 goto decode_success;
10456 }
10457
10458 /* 66 0F 65 = PCMPGTW */
10459 if (have66noF2noF3(pfx) && sz == 2
10460 && insn[0] == 0x0F && insn[1] == 0x65) {
10461 delta = dis_SSEint_E_to_G( pfx, delta+2,
10462 "pcmpgtw", Iop_CmpGT16Sx8, False );
10463 goto decode_success;
10464 }
sewardj97628592005-05-10 22:42:54 +000010465
10466 /* 66 0F C5 = PEXTRW -- extract 16-bit field from xmm(E) and put
10467 zero-extend of it in ireg(G). */
10468 if (have66noF2noF3(pfx) && sz == 2
10469 && insn[0] == 0x0F && insn[1] == 0xC5) {
10470 modrm = insn[2];
10471 if (epartIsReg(modrm)) {
10472 t5 = newTemp(Ity_V128);
10473 t4 = newTemp(Ity_I16);
10474 assign(t5, getXMMReg(eregOfRexRM(pfx,modrm)));
10475 breakup128to32s( t5, &t3, &t2, &t1, &t0 );
10476 switch (insn[3] & 7) {
10477 case 0: assign(t4, unop(Iop_32to16, mkexpr(t0))); break;
10478 case 1: assign(t4, unop(Iop_32HIto16, mkexpr(t0))); break;
10479 case 2: assign(t4, unop(Iop_32to16, mkexpr(t1))); break;
10480 case 3: assign(t4, unop(Iop_32HIto16, mkexpr(t1))); break;
10481 case 4: assign(t4, unop(Iop_32to16, mkexpr(t2))); break;
10482 case 5: assign(t4, unop(Iop_32HIto16, mkexpr(t2))); break;
10483 case 6: assign(t4, unop(Iop_32to16, mkexpr(t3))); break;
10484 case 7: assign(t4, unop(Iop_32HIto16, mkexpr(t3))); break;
10485 default: vassert(0);
10486 }
10487 putIReg32(gregOfRexRM(pfx,modrm), unop(Iop_16Uto32, mkexpr(t4)));
10488 DIP("pextrw $%d,%s,%s\n",
10489 (Int)insn[3], nameXMMReg(eregOfRexRM(pfx,modrm)),
10490 nameIReg32(gregOfRexRM(pfx,modrm)));
10491 delta += 4;
10492 goto decode_success;
10493 }
10494 /* else fall through */
10495 /* note, if memory case is ever filled in, there is 1 byte after
10496 amode */
10497 }
10498
10499 /* 66 0F C4 = PINSRW -- get 16 bits from E(mem or low half ireg) and
10500 put it into the specified lane of xmm(G). */
10501 if (have66noF2noF3(pfx) && sz == 2
10502 && insn[0] == 0x0F && insn[1] == 0xC4) {
10503 Int lane;
10504 t4 = newTemp(Ity_I16);
10505 modrm = insn[2];
10506
10507 if (epartIsReg(modrm)) {
10508 assign(t4, getIReg16(eregOfRexRM(pfx,modrm)));
10509 delta += 3+1;
10510 lane = insn[3+1-1];
10511 DIP("pinsrw $%d,%s,%s\n", (Int)lane,
10512 nameIReg16(eregOfRexRM(pfx,modrm)),
10513 nameXMMReg(gregOfRexRM(pfx,modrm)));
10514 } else {
10515 addr = disAMode ( &alen, pfx, delta+2, dis_buf,
10516 1/*byte after the amode*/ );
10517 delta += 3+alen;
10518 lane = insn[3+alen-1];
10519 assign(t4, loadLE(Ity_I16, mkexpr(addr)));
10520 DIP("pinsrw $%d,%s,%s\n", (Int)lane,
10521 dis_buf,
10522 nameXMMReg(gregOfRexRM(pfx,modrm)));
10523 }
10524
10525 putXMMRegLane16( gregOfRexRM(pfx,modrm), lane & 7, mkexpr(t4) );
10526 goto decode_success;
10527 }
10528
sewardjadffcef2005-05-11 00:03:06 +000010529 /* 66 0F EE = PMAXSW -- 16x8 signed max */
10530 if (have66noF2noF3(pfx) && sz == 2
10531 && insn[0] == 0x0F && insn[1] == 0xEE) {
10532 delta = dis_SSEint_E_to_G( pfx, delta+2,
10533 "pmaxsw", Iop_Max16Sx8, False );
10534 goto decode_success;
10535 }
10536
10537 /* 66 0F DE = PMAXUB -- 8x16 unsigned max */
10538 if (have66noF2noF3(pfx) && sz == 2
10539 && insn[0] == 0x0F && insn[1] == 0xDE) {
10540 delta = dis_SSEint_E_to_G( pfx, delta+2,
10541 "pmaxub", Iop_Max8Ux16, False );
10542 goto decode_success;
10543 }
10544
10545 /* 66 0F EA = PMINSW -- 16x8 signed min */
10546 if (have66noF2noF3(pfx) && sz == 2
10547 && insn[0] == 0x0F && insn[1] == 0xEA) {
10548 delta = dis_SSEint_E_to_G( pfx, delta+2,
10549 "pminsw", Iop_Min16Sx8, False );
10550 goto decode_success;
10551 }
10552
10553 /* 66 0F DA = PMINUB -- 8x16 unsigned min */
10554 if (have66noF2noF3(pfx) && sz == 2
10555 && insn[0] == 0x0F && insn[1] == 0xDA) {
10556 delta = dis_SSEint_E_to_G( pfx, delta+2,
10557 "pminub", Iop_Min8Ux16, False );
10558 goto decode_success;
10559 }
10560
10561 /* 66 0F D7 = PMOVMSKB -- extract sign bits from each of 16 lanes in
10562 xmm(E), turn them into a byte, and put zero-extend of it in
10563 ireg(G). Doing this directly is just too cumbersome; give up
10564 therefore and call a helper. */
10565 /* UInt x86g_calculate_sse_pmovmskb ( ULong w64hi, ULong w64lo ); */
10566 if (have66noF2noF3(pfx) && sz == 2
10567 && insn[0] == 0x0F && insn[1] == 0xD7) {
10568 modrm = insn[2];
10569 if (epartIsReg(modrm)) {
10570 t0 = newTemp(Ity_I64);
10571 t1 = newTemp(Ity_I64);
10572 assign(t0, getXMMRegLane64(eregOfRexRM(pfx,modrm), 0));
10573 assign(t1, getXMMRegLane64(eregOfRexRM(pfx,modrm), 1));
10574 t5 = newTemp(Ity_I64);
10575 assign(t5, mkIRExprCCall(
10576 Ity_I64, 0/*regparms*/,
10577 "amd64g_calculate_sse_pmovmskb",
10578 &amd64g_calculate_sse_pmovmskb,
10579 mkIRExprVec_2( mkexpr(t1), mkexpr(t0) )));
10580 putIReg32(gregOfRexRM(pfx,modrm), unop(Iop_64to32,mkexpr(t5)));
10581 DIP("pmovmskb %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
10582 nameIReg32(gregOfRexRM(pfx,modrm)));
10583 delta += 3;
10584 goto decode_success;
10585 }
10586 /* else fall through */
10587 }
10588
10589 /* 66 0F E4 = PMULHUW -- 16x8 hi-half of unsigned widening multiply */
10590 if (have66noF2noF3(pfx) && sz == 2
10591 && insn[0] == 0x0F && insn[1] == 0xE4) {
10592 delta = dis_SSEint_E_to_G( pfx, delta+2,
10593 "pmulhuw", Iop_MulHi16Ux8, False );
10594 goto decode_success;
10595 }
10596
10597 /* 66 0F E5 = PMULHW -- 16x8 hi-half of signed widening multiply */
10598 if (have66noF2noF3(pfx) && sz == 2
10599 && insn[0] == 0x0F && insn[1] == 0xE5) {
10600 delta = dis_SSEint_E_to_G( pfx, delta+2,
10601 "pmulhw", Iop_MulHi16Sx8, False );
10602 goto decode_success;
10603 }
10604
10605 /* 66 0F D5 = PMULHL -- 16x8 multiply */
10606 if (have66noF2noF3(pfx) && sz == 2
10607 && insn[0] == 0x0F && insn[1] == 0xD5) {
10608 delta = dis_SSEint_E_to_G( pfx, delta+2,
10609 "pmullw", Iop_Mul16x8, False );
10610 goto decode_success;
10611 }
10612
10613 /* ***--- this is an MMX class insn introduced in SSE2 ---*** */
10614 /* 0F F4 = PMULUDQ -- unsigned widening multiply of 32-lanes 0 x
10615 0 to form 64-bit result */
10616 if (haveNo66noF2noF3(pfx) && sz == 4
10617 && insn[0] == 0x0F && insn[1] == 0xF4) {
10618 IRTemp sV = newTemp(Ity_I64);
10619 IRTemp dV = newTemp(Ity_I64);
10620 t1 = newTemp(Ity_I32);
10621 t0 = newTemp(Ity_I32);
10622 modrm = insn[2];
10623
10624 do_MMX_preamble();
10625 assign( dV, getMMXReg(gregLO3ofRM(modrm)) );
10626
10627 if (epartIsReg(modrm)) {
10628 assign( sV, getMMXReg(eregLO3ofRM(modrm)) );
10629 delta += 2+1;
10630 DIP("pmuludq %s,%s\n", nameMMXReg(eregLO3ofRM(modrm)),
10631 nameMMXReg(gregLO3ofRM(modrm)));
10632 } else {
10633 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10634 assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
10635 delta += 2+alen;
10636 DIP("pmuludq %s,%s\n", dis_buf,
10637 nameMMXReg(gregLO3ofRM(modrm)));
10638 }
10639
10640 assign( t0, unop(Iop_64to32, mkexpr(dV)) );
10641 assign( t1, unop(Iop_64to32, mkexpr(sV)) );
10642 putMMXReg( gregLO3ofRM(modrm),
10643 binop( Iop_MullU32, mkexpr(t0), mkexpr(t1) ) );
10644 goto decode_success;
10645 }
10646
10647 /* 66 0F F4 = PMULUDQ -- unsigned widening multiply of 32-lanes 0 x
10648 0 to form lower 64-bit half and lanes 2 x 2 to form upper 64-bit
10649 half */
10650 /* This is a really poor translation -- could be improved if
10651 performance critical */
10652 if (have66noF2noF3(pfx) && sz == 2
10653 && insn[0] == 0x0F && insn[1] == 0xF4) {
10654 IRTemp sV, dV;
10655 IRTemp s3, s2, s1, s0, d3, d2, d1, d0;
10656 sV = newTemp(Ity_V128);
10657 dV = newTemp(Ity_V128);
10658 s3 = s2 = s1 = s0 = d3 = d2 = d1 = d0 = IRTemp_INVALID;
10659 t1 = newTemp(Ity_I64);
10660 t0 = newTemp(Ity_I64);
10661 modrm = insn[2];
10662 assign( dV, getXMMReg(gregOfRexRM(pfx,modrm)) );
10663
10664 if (epartIsReg(modrm)) {
10665 assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
10666 delta += 2+1;
10667 DIP("pmuludq %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
10668 nameXMMReg(gregOfRexRM(pfx,modrm)));
10669 } else {
10670 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10671 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
10672 delta += 2+alen;
10673 DIP("pmuludq %s,%s\n", dis_buf,
10674 nameXMMReg(gregOfRexRM(pfx,modrm)));
10675 }
10676
10677 breakup128to32s( dV, &d3, &d2, &d1, &d0 );
10678 breakup128to32s( sV, &s3, &s2, &s1, &s0 );
10679
10680 assign( t0, binop( Iop_MullU32, mkexpr(d0), mkexpr(s0)) );
10681 putXMMRegLane64( gregOfRexRM(pfx,modrm), 0, mkexpr(t0) );
10682 assign( t1, binop( Iop_MullU32, mkexpr(d2), mkexpr(s2)) );
10683 putXMMRegLane64( gregOfRexRM(pfx,modrm), 1, mkexpr(t1) );
10684 goto decode_success;
10685 }
sewardj09717342005-05-05 21:34:02 +000010686
10687 /* 66 0F EB = POR */
10688 if (have66noF2noF3(pfx) && sz == 2
10689 && insn[0] == 0x0F && insn[1] == 0xEB) {
10690 delta = dis_SSE_E_to_G_all( pfx, delta+2, "por", Iop_OrV128 );
10691 goto decode_success;
10692 }
10693
sewardjadffcef2005-05-11 00:03:06 +000010694 /* 66 0F 70 = PSHUFD -- rearrange 4x32 from E(xmm or mem) to G(xmm) */
10695 if (have66noF2noF3(pfx) && sz == 2
10696 && insn[0] == 0x0F && insn[1] == 0x70) {
10697 Int order;
10698 IRTemp sV, dV, s3, s2, s1, s0;
10699 s3 = s2 = s1 = s0 = IRTemp_INVALID;
10700 sV = newTemp(Ity_V128);
10701 dV = newTemp(Ity_V128);
10702 modrm = insn[2];
10703 if (epartIsReg(modrm)) {
10704 assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
10705 order = (Int)insn[3];
10706 delta += 3+1;
10707 DIP("pshufd $%d,%s,%s\n", order,
10708 nameXMMReg(eregOfRexRM(pfx,modrm)),
10709 nameXMMReg(gregOfRexRM(pfx,modrm)));
10710 } else {
10711 addr = disAMode ( &alen, pfx, delta+2, dis_buf,
10712 1/*byte after the amode*/ );
10713 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
10714 order = (Int)insn[2+alen];
10715 delta += 2+alen+1;
10716 DIP("pshufd $%d,%s,%s\n", order,
10717 dis_buf,
10718 nameXMMReg(gregOfRexRM(pfx,modrm)));
10719 }
10720 breakup128to32s( sV, &s3, &s2, &s1, &s0 );
10721
10722# define SEL(n) \
10723 ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
10724 assign(dV,
10725 mk128from32s( SEL((order>>6)&3), SEL((order>>4)&3),
10726 SEL((order>>2)&3), SEL((order>>0)&3) )
10727 );
10728 putXMMReg(gregOfRexRM(pfx,modrm), mkexpr(dV));
10729# undef SEL
10730 goto decode_success;
10731 }
10732
10733 /* F3 0F 70 = PSHUFHW -- rearrange upper half 4x16 from E(xmm or
10734 mem) to G(xmm), and copy lower half */
10735 if (haveF3no66noF2(pfx) && sz == 4
10736 && insn[0] == 0x0F && insn[1] == 0x70) {
10737 Int order;
10738 IRTemp sVhi, dVhi, sV, dV, s3, s2, s1, s0;
10739 s3 = s2 = s1 = s0 = IRTemp_INVALID;
10740 sV = newTemp(Ity_V128);
10741 dV = newTemp(Ity_V128);
10742 sVhi = newTemp(Ity_I64);
10743 dVhi = newTemp(Ity_I64);
10744 modrm = insn[2];
10745 if (epartIsReg(modrm)) {
10746 assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
10747 order = (Int)insn[3];
10748 delta += 3+1;
10749 DIP("pshufhw $%d,%s,%s\n", order,
10750 nameXMMReg(eregOfRexRM(pfx,modrm)),
10751 nameXMMReg(gregOfRexRM(pfx,modrm)));
10752 } else {
10753 addr = disAMode ( &alen, pfx, delta+2, dis_buf,
10754 1/*byte after the amode*/ );
10755 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
10756 order = (Int)insn[2+alen];
10757 delta += 2+alen+1;
10758 DIP("pshufhw $%d,%s,%s\n", order,
10759 dis_buf,
10760 nameXMMReg(gregOfRexRM(pfx,modrm)));
10761 }
10762 assign( sVhi, unop(Iop_V128HIto64, mkexpr(sV)) );
10763 breakup64to16s( sVhi, &s3, &s2, &s1, &s0 );
10764
10765# define SEL(n) \
10766 ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
10767 assign(dVhi,
10768 mk64from16s( SEL((order>>6)&3), SEL((order>>4)&3),
10769 SEL((order>>2)&3), SEL((order>>0)&3) )
10770 );
10771 assign(dV, binop( Iop_64HLtoV128,
10772 mkexpr(dVhi),
10773 unop(Iop_V128to64, mkexpr(sV))) );
10774 putXMMReg(gregOfRexRM(pfx,modrm), mkexpr(dV));
10775# undef SEL
10776 goto decode_success;
10777 }
10778
10779 /* F2 0F 70 = PSHUFLW -- rearrange lower half 4x16 from E(xmm or
10780 mem) to G(xmm), and copy upper half */
10781 if (haveF2no66noF3(pfx) && sz == 4
10782 && insn[0] == 0x0F && insn[1] == 0x70) {
10783 Int order;
10784 IRTemp sVlo, dVlo, sV, dV, s3, s2, s1, s0;
10785 s3 = s2 = s1 = s0 = IRTemp_INVALID;
10786 sV = newTemp(Ity_V128);
10787 dV = newTemp(Ity_V128);
10788 sVlo = newTemp(Ity_I64);
10789 dVlo = newTemp(Ity_I64);
10790 modrm = insn[2];
10791 if (epartIsReg(modrm)) {
10792 assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
10793 order = (Int)insn[3];
10794 delta += 3+1;
10795 DIP("pshuflw $%d,%s,%s\n", order,
10796 nameXMMReg(eregOfRexRM(pfx,modrm)),
10797 nameXMMReg(gregOfRexRM(pfx,modrm)));
10798 } else {
10799 addr = disAMode ( &alen, pfx, delta+2, dis_buf,
10800 1/*byte after the amode*/ );
10801 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
10802 order = (Int)insn[2+alen];
10803 delta += 2+alen+1;
10804 DIP("pshuflw $%d,%s,%s\n", order,
10805 dis_buf,
10806 nameXMMReg(gregOfRexRM(pfx,modrm)));
10807 }
10808 assign( sVlo, unop(Iop_V128to64, mkexpr(sV)) );
10809 breakup64to16s( sVlo, &s3, &s2, &s1, &s0 );
10810
10811# define SEL(n) \
10812 ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
10813 assign(dVlo,
10814 mk64from16s( SEL((order>>6)&3), SEL((order>>4)&3),
10815 SEL((order>>2)&3), SEL((order>>0)&3) )
10816 );
10817 assign(dV, binop( Iop_64HLtoV128,
10818 unop(Iop_V128HIto64, mkexpr(sV)),
10819 mkexpr(dVlo) ) );
10820 putXMMReg(gregOfRexRM(pfx,modrm), mkexpr(dV));
10821# undef SEL
10822 goto decode_success;
10823 }
10824
10825 /* 66 0F 72 /6 ib = PSLLD by immediate */
10826 if (have66noF2noF3(pfx) && sz == 2
10827 && insn[0] == 0x0F && insn[1] == 0x72
10828 && epartIsReg(insn[2])
10829 && gregLO3ofRM(insn[2]) == 6) {
10830 delta = dis_SSE_shiftE_imm( pfx, delta+2, "pslld", Iop_ShlN32x4 );
10831 goto decode_success;
10832 }
10833
10834 /* 66 0F F2 = PSLLD by E */
10835 if (have66noF2noF3(pfx) && sz == 2
10836 && insn[0] == 0x0F && insn[1] == 0xF2) {
10837 delta = dis_SSE_shiftG_byE( pfx, delta+2, "pslld", Iop_ShlN32x4 );
10838 goto decode_success;
10839 }
sewardj97628592005-05-10 22:42:54 +000010840
10841 /* 66 0F 73 /7 ib = PSLLDQ by immediate */
10842 /* note, if mem case ever filled in, 1 byte after amode */
10843 if (have66noF2noF3(pfx) && sz == 2
10844 && insn[0] == 0x0F && insn[1] == 0x73
10845 && epartIsReg(insn[2])
10846 && gregLO3ofRM(insn[2]) == 7) {
10847 IRTemp sV, dV, hi64, lo64, hi64r, lo64r;
10848 Int imm = (Int)insn[3];
10849 Int reg = eregOfRexRM(pfx,insn[2]);
10850 DIP("pslldq $%d,%s\n", imm, nameXMMReg(reg));
10851 vassert(imm >= 0 && imm <= 255);
10852 delta += 4;
10853
10854 sV = newTemp(Ity_V128);
10855 dV = newTemp(Ity_V128);
10856 hi64 = newTemp(Ity_I64);
10857 lo64 = newTemp(Ity_I64);
10858 hi64r = newTemp(Ity_I64);
10859 lo64r = newTemp(Ity_I64);
10860
10861 if (imm >= 16) {
10862 putXMMReg(reg, mkV128(0x0000));
10863 goto decode_success;
10864 }
10865
10866 assign( sV, getXMMReg(reg) );
10867 assign( hi64, unop(Iop_V128HIto64, mkexpr(sV)) );
10868 assign( lo64, unop(Iop_V128to64, mkexpr(sV)) );
10869
10870 if (imm == 0) {
10871 assign( lo64r, mkexpr(lo64) );
10872 assign( hi64r, mkexpr(hi64) );
10873 }
10874 else
10875 if (imm == 8) {
10876 assign( lo64r, mkU64(0) );
10877 assign( hi64r, mkexpr(lo64) );
10878 }
10879 else
10880 if (imm > 8) {
10881 assign( lo64r, mkU64(0) );
10882 assign( hi64r, binop( Iop_Shl64,
10883 mkexpr(lo64),
10884 mkU8( 8*(imm-8) ) ));
10885 } else {
10886 assign( lo64r, binop( Iop_Shl64,
10887 mkexpr(lo64),
10888 mkU8(8 * imm) ));
10889 assign( hi64r,
10890 binop( Iop_Or64,
10891 binop(Iop_Shl64, mkexpr(hi64),
10892 mkU8(8 * imm)),
10893 binop(Iop_Shr64, mkexpr(lo64),
10894 mkU8(8 * (8 - imm)) )
10895 )
10896 );
10897 }
10898 assign( dV, binop(Iop_64HLtoV128, mkexpr(hi64r), mkexpr(lo64r)) );
10899 putXMMReg(reg, mkexpr(dV));
10900 goto decode_success;
10901 }
10902
sewardjadffcef2005-05-11 00:03:06 +000010903 /* 66 0F 73 /6 ib = PSLLQ by immediate */
10904 if (have66noF2noF3(pfx) && sz == 2
10905 && insn[0] == 0x0F && insn[1] == 0x73
10906 && epartIsReg(insn[2])
10907 && gregLO3ofRM(insn[2]) == 6) {
10908 delta = dis_SSE_shiftE_imm( pfx, delta+2, "psllq", Iop_ShlN64x2 );
10909 goto decode_success;
10910 }
10911
10912 /* 66 0F F3 = PSLLQ by E */
10913 if (have66noF2noF3(pfx) && sz == 2
10914 && insn[0] == 0x0F && insn[1] == 0xF3) {
10915 delta = dis_SSE_shiftG_byE( pfx, delta+2, "psllq", Iop_ShlN64x2 );
10916 goto decode_success;
10917 }
10918
10919 /* 66 0F 71 /6 ib = PSLLW by immediate */
10920 if (have66noF2noF3(pfx) && sz == 2
10921 && insn[0] == 0x0F && insn[1] == 0x71
10922 && epartIsReg(insn[2])
10923 && gregLO3ofRM(insn[2]) == 6) {
10924 delta = dis_SSE_shiftE_imm( pfx, delta+2, "psllw", Iop_ShlN16x8 );
10925 goto decode_success;
10926 }
10927
10928 /* 66 0F F1 = PSLLW by E */
10929 if (have66noF2noF3(pfx) && sz == 2
10930 && insn[0] == 0x0F && insn[1] == 0xF1) {
10931 delta = dis_SSE_shiftG_byE( pfx, delta+2, "psllw", Iop_ShlN16x8 );
10932 goto decode_success;
10933 }
10934
10935 /* 66 0F 72 /4 ib = PSRAD by immediate */
10936 if (have66noF2noF3(pfx) && sz == 2
10937 && insn[0] == 0x0F && insn[1] == 0x72
10938 && epartIsReg(insn[2])
10939 && gregLO3ofRM(insn[2]) == 4) {
10940 delta = dis_SSE_shiftE_imm( pfx, delta+2, "psrad", Iop_SarN32x4 );
10941 goto decode_success;
10942 }
10943
10944 /* 66 0F E2 = PSRAD by E */
10945 if (have66noF2noF3(pfx) && sz == 2
10946 && insn[0] == 0x0F && insn[1] == 0xE2) {
10947 delta = dis_SSE_shiftG_byE( pfx, delta+2, "psrad", Iop_SarN32x4 );
10948 goto decode_success;
10949 }
10950
10951 /* 66 0F 71 /4 ib = PSRAW by immediate */
10952 if (have66noF2noF3(pfx) && sz == 2
10953 && insn[0] == 0x0F && insn[1] == 0x71
10954 && epartIsReg(insn[2])
10955 && gregLO3ofRM(insn[2]) == 4) {
10956 delta = dis_SSE_shiftE_imm( pfx, delta+2, "psraw", Iop_SarN16x8 );
10957 goto decode_success;
10958 }
10959
10960 /* 66 0F E1 = PSRAW by E */
10961 if (have66noF2noF3(pfx) && sz == 2
10962 && insn[0] == 0x0F && insn[1] == 0xE1) {
10963 delta = dis_SSE_shiftG_byE( pfx, delta+2, "psraw", Iop_SarN16x8 );
10964 goto decode_success;
10965 }
10966
10967 /* 66 0F 72 /2 ib = PSRLD by immediate */
10968 if (have66noF2noF3(pfx) && sz == 2
10969 && insn[0] == 0x0F && insn[1] == 0x72
10970 && epartIsReg(insn[2])
10971 && gregLO3ofRM(insn[2]) == 2) {
10972 delta = dis_SSE_shiftE_imm( pfx, delta+2, "psrld", Iop_ShrN32x4 );
10973 goto decode_success;
10974 }
10975
10976 /* 66 0F D2 = PSRLD by E */
10977 if (have66noF2noF3(pfx) && sz == 2
10978 && insn[0] == 0x0F && insn[1] == 0xD2) {
10979 delta = dis_SSE_shiftG_byE( pfx, delta+2, "psrld", Iop_ShrN32x4 );
10980 goto decode_success;
10981 }
sewardj97628592005-05-10 22:42:54 +000010982
10983 /* 66 0F 73 /3 ib = PSRLDQ by immediate */
10984 /* note, if mem case ever filled in, 1 byte after amode */
10985 if (have66noF2noF3(pfx) && sz == 2
10986 && insn[0] == 0x0F && insn[1] == 0x73
10987 && epartIsReg(insn[2])
10988 && gregLO3ofRM(insn[2]) == 3) {
10989 IRTemp sV, dV, hi64, lo64, hi64r, lo64r;
10990 Int imm = (Int)insn[3];
10991 Int reg = eregOfRexRM(pfx,insn[2]);
10992 DIP("psrldq $%d,%s\n", imm, nameXMMReg(reg));
10993 vassert(imm >= 0 && imm <= 255);
10994 delta += 4;
10995
10996 sV = newTemp(Ity_V128);
10997 dV = newTemp(Ity_V128);
10998 hi64 = newTemp(Ity_I64);
10999 lo64 = newTemp(Ity_I64);
11000 hi64r = newTemp(Ity_I64);
11001 lo64r = newTemp(Ity_I64);
11002
11003 if (imm >= 16) {
11004 putXMMReg(reg, mkV128(0x0000));
11005 goto decode_success;
11006 }
11007
11008 assign( sV, getXMMReg(reg) );
11009 assign( hi64, unop(Iop_V128HIto64, mkexpr(sV)) );
11010 assign( lo64, unop(Iop_V128to64, mkexpr(sV)) );
11011
11012 if (imm == 0) {
11013 assign( lo64r, mkexpr(lo64) );
11014 assign( hi64r, mkexpr(hi64) );
11015 }
11016 else
11017 if (imm == 8) {
11018 assign( hi64r, mkU64(0) );
11019 assign( lo64r, mkexpr(hi64) );
11020 }
11021 else
11022 if (imm > 8) {
11023 assign( hi64r, mkU64(0) );
11024 assign( lo64r, binop( Iop_Shr64,
11025 mkexpr(hi64),
11026 mkU8( 8*(imm-8) ) ));
11027 } else {
11028 assign( hi64r, binop( Iop_Shr64,
11029 mkexpr(hi64),
11030 mkU8(8 * imm) ));
11031 assign( lo64r,
11032 binop( Iop_Or64,
11033 binop(Iop_Shr64, mkexpr(lo64),
11034 mkU8(8 * imm)),
11035 binop(Iop_Shl64, mkexpr(hi64),
11036 mkU8(8 * (8 - imm)) )
11037 )
11038 );
11039 }
11040
11041 assign( dV, binop(Iop_64HLtoV128, mkexpr(hi64r), mkexpr(lo64r)) );
11042 putXMMReg(reg, mkexpr(dV));
11043 goto decode_success;
11044 }
sewardj09717342005-05-05 21:34:02 +000011045
11046 /* 66 0F 73 /2 ib = PSRLQ by immediate */
11047 if (have66noF2noF3(pfx) && sz == 2
11048 && insn[0] == 0x0F && insn[1] == 0x73
11049 && epartIsReg(insn[2])
11050 && gregLO3ofRM(insn[2]) == 2) {
11051 delta = dis_SSE_shiftE_imm( pfx, delta+2, "psrlq", Iop_ShrN64x2 );
11052 goto decode_success;
11053 }
11054
sewardjadffcef2005-05-11 00:03:06 +000011055 /* 66 0F D3 = PSRLQ by E */
11056 if (have66noF2noF3(pfx) && sz == 2
11057 && insn[0] == 0x0F && insn[1] == 0xD3) {
11058 delta = dis_SSE_shiftG_byE( pfx, delta+2, "psrlq", Iop_ShrN64x2 );
11059 goto decode_success;
11060 }
11061
11062 /* 66 0F 71 /2 ib = PSRLW by immediate */
11063 if (have66noF2noF3(pfx) && sz == 2
11064 && insn[0] == 0x0F && insn[1] == 0x71
11065 && epartIsReg(insn[2])
11066 && gregLO3ofRM(insn[2]) == 2) {
11067 delta = dis_SSE_shiftE_imm( pfx, delta+2, "psrlw", Iop_ShrN16x8 );
11068 goto decode_success;
11069 }
11070
11071 /* 66 0F D1 = PSRLW by E */
11072 if (have66noF2noF3(pfx) && sz == 2
11073 && insn[0] == 0x0F && insn[1] == 0xD1) {
11074 delta = dis_SSE_shiftG_byE( pfx, delta+2, "psrlw", Iop_ShrN16x8 );
11075 goto decode_success;
11076 }
sewardj97628592005-05-10 22:42:54 +000011077
11078 /* 66 0F F8 = PSUBB */
11079 if (have66noF2noF3(pfx) && sz == 2
11080 && insn[0] == 0x0F && insn[1] == 0xF8) {
11081 delta = dis_SSEint_E_to_G( pfx, delta+2,
11082 "psubb", Iop_Sub8x16, False );
11083 goto decode_success;
11084 }
11085
11086 /* 66 0F FA = PSUBD */
11087 if (have66noF2noF3(pfx) && sz == 2
11088 && insn[0] == 0x0F && insn[1] == 0xFA) {
11089 delta = dis_SSEint_E_to_G( pfx, delta+2,
11090 "psubd", Iop_Sub32x4, False );
11091 goto decode_success;
11092 }
sewardj8711f662005-05-09 17:52:56 +000011093
11094 /* ***--- this is an MMX class insn introduced in SSE2 ---*** */
11095 /* 0F FB = PSUBQ -- sub 64x1 */
11096 if (haveNo66noF2noF3(pfx) && sz == 4
11097 && insn[0] == 0x0F && insn[1] == 0xFB) {
11098 do_MMX_preamble();
11099 delta = dis_MMXop_regmem_to_reg (
11100 pfx, delta+2, insn[1], "psubq", False );
11101 goto decode_success;
11102 }
sewardj09717342005-05-05 21:34:02 +000011103
11104 /* 66 0F FB = PSUBQ */
11105 if (have66noF2noF3(pfx) && sz == 2
11106 && insn[0] == 0x0F && insn[1] == 0xFB) {
11107 delta = dis_SSEint_E_to_G( pfx, delta+2,
11108 "psubq", Iop_Sub64x2, False );
11109 goto decode_success;
11110 }
11111
sewardj97628592005-05-10 22:42:54 +000011112 /* 66 0F F9 = PSUBW */
11113 if (have66noF2noF3(pfx) && sz == 2
11114 && insn[0] == 0x0F && insn[1] == 0xF9) {
11115 delta = dis_SSEint_E_to_G( pfx, delta+2,
11116 "psubw", Iop_Sub16x8, False );
11117 goto decode_success;
11118 }
11119
11120 /* 66 0F E8 = PSUBSB */
11121 if (have66noF2noF3(pfx) && sz == 2
11122 && insn[0] == 0x0F && insn[1] == 0xE8) {
11123 delta = dis_SSEint_E_to_G( pfx, delta+2,
11124 "psubsb", Iop_QSub8Sx16, False );
11125 goto decode_success;
11126 }
11127
11128 /* 66 0F E9 = PSUBSW */
11129 if (have66noF2noF3(pfx) && sz == 2
11130 && insn[0] == 0x0F && insn[1] == 0xE9) {
11131 delta = dis_SSEint_E_to_G( pfx, delta+2,
11132 "psubsw", Iop_QSub16Sx8, False );
11133 goto decode_success;
11134 }
11135
11136 /* 66 0F D8 = PSUBSB */
11137 if (have66noF2noF3(pfx) && sz == 2
11138 && insn[0] == 0x0F && insn[1] == 0xD8) {
11139 delta = dis_SSEint_E_to_G( pfx, delta+2,
11140 "psubusb", Iop_QSub8Ux16, False );
11141 goto decode_success;
11142 }
11143
11144 /* 66 0F D9 = PSUBSW */
11145 if (have66noF2noF3(pfx) && sz == 2
11146 && insn[0] == 0x0F && insn[1] == 0xD9) {
11147 delta = dis_SSEint_E_to_G( pfx, delta+2,
11148 "psubusw", Iop_QSub16Ux8, False );
11149 goto decode_success;
11150 }
11151
11152 /* 66 0F 68 = PUNPCKHBW */
11153 if (have66noF2noF3(pfx) && sz == 2
11154 && insn[0] == 0x0F && insn[1] == 0x68) {
11155 delta = dis_SSEint_E_to_G( pfx, delta+2,
11156 "punpckhbw",
11157 Iop_InterleaveHI8x16, True );
11158 goto decode_success;
11159 }
11160
11161 /* 66 0F 6A = PUNPCKHDQ */
11162 if (have66noF2noF3(pfx) && sz == 2
11163 && insn[0] == 0x0F && insn[1] == 0x6A) {
11164 delta = dis_SSEint_E_to_G( pfx, delta+2,
11165 "punpckhdq",
11166 Iop_InterleaveHI32x4, True );
11167 goto decode_success;
11168 }
11169
11170 /* 66 0F 6D = PUNPCKHQDQ */
11171 if (have66noF2noF3(pfx) && sz == 2
11172 && insn[0] == 0x0F && insn[1] == 0x6D) {
11173 delta = dis_SSEint_E_to_G( pfx, delta+2,
11174 "punpckhqdq",
11175 Iop_InterleaveHI64x2, True );
11176 goto decode_success;
11177 }
11178
11179 /* 66 0F 69 = PUNPCKHWD */
11180 if (have66noF2noF3(pfx) && sz == 2
11181 && insn[0] == 0x0F && insn[1] == 0x69) {
11182 delta = dis_SSEint_E_to_G( pfx, delta+2,
11183 "punpckhwd",
11184 Iop_InterleaveHI16x8, True );
11185 goto decode_success;
11186 }
11187
11188 /* 66 0F 60 = PUNPCKLBW */
11189 if (have66noF2noF3(pfx) && sz == 2
11190 && insn[0] == 0x0F && insn[1] == 0x60) {
11191 delta = dis_SSEint_E_to_G( pfx, delta+2,
11192 "punpcklbw",
11193 Iop_InterleaveLO8x16, True );
11194 goto decode_success;
11195 }
11196
11197 /* 66 0F 62 = PUNPCKLDQ */
11198 if (have66noF2noF3(pfx) && sz == 2
11199 && insn[0] == 0x0F && insn[1] == 0x62) {
11200 delta = dis_SSEint_E_to_G( pfx, delta+2,
11201 "punpckldq",
11202 Iop_InterleaveLO32x4, True );
11203 goto decode_success;
11204 }
11205
11206 /* 66 0F 6C = PUNPCKLQDQ */
11207 if (have66noF2noF3(pfx) && sz == 2
11208 && insn[0] == 0x0F && insn[1] == 0x6C) {
11209 delta = dis_SSEint_E_to_G( pfx, delta+2,
11210 "punpcklqdq",
11211 Iop_InterleaveLO64x2, True );
11212 goto decode_success;
11213 }
11214
11215 /* 66 0F 61 = PUNPCKLWD */
11216 if (have66noF2noF3(pfx) && sz == 2
11217 && insn[0] == 0x0F && insn[1] == 0x61) {
11218 delta = dis_SSEint_E_to_G( pfx, delta+2,
11219 "punpcklwd",
11220 Iop_InterleaveLO16x8, True );
11221 goto decode_success;
11222 }
sewardj09717342005-05-05 21:34:02 +000011223
11224 /* 66 0F EF = PXOR */
11225 if (have66noF2noF3(pfx) && sz == 2
11226 && insn[0] == 0x0F && insn[1] == 0xEF) {
11227 delta = dis_SSE_E_to_G_all( pfx, delta+2, "pxor", Iop_XorV128 );
11228 goto decode_success;
11229 }
11230
sewardjd20c8852005-01-20 20:04:07 +000011231//.. //-- /* FXSAVE/FXRSTOR m32 -- load/store the FPU/MMX/SSE state. */
11232//.. //-- if (insn[0] == 0x0F && insn[1] == 0xAE
11233//.. //-- && (!epartIsReg(insn[2]))
11234//.. //-- && (gregOfRM(insn[2]) == 1 || gregOfRM(insn[2]) == 0) ) {
11235//.. //-- Bool store = gregOfRM(insn[2]) == 0;
11236//.. //-- vg_assert(sz == 4);
11237//.. //-- pair = disAMode ( cb, sorb, eip+2, dis_buf );
11238//.. //-- t1 = LOW24(pair);
11239//.. //-- eip += 2+HI8(pair);
11240//.. //-- uInstr3(cb, store ? SSE2a_MemWr : SSE2a_MemRd, 512,
11241//.. //-- Lit16, (((UShort)insn[0]) << 8) | (UShort)insn[1],
11242//.. //-- Lit16, (UShort)insn[2],
11243//.. //-- TempReg, t1 );
11244//.. //-- DIP("fx%s %s\n", store ? "save" : "rstor", dis_buf );
11245//.. //-- goto decode_success;
11246//.. //-- }
11247//.. //--
11248//.. //-- /* CLFLUSH -- flush cache line */
11249//.. //-- if (insn[0] == 0x0F && insn[1] == 0xAE
11250//.. //-- && (!epartIsReg(insn[2]))
11251//.. //-- && (gregOfRM(insn[2]) == 7))
11252//.. //-- {
11253//.. //-- vg_assert(sz == 4);
11254//.. //-- pair = disAMode ( cb, sorb, eip+2, dis_buf );
11255//.. //-- t1 = LOW24(pair);
11256//.. //-- eip += 2+HI8(pair);
11257//.. //-- uInstr3(cb, SSE2a_MemRd, 0, /* ignore sz for internal ops */
11258//.. //-- Lit16, (((UShort)0x0F) << 8) | (UShort)0xAE,
11259//.. //-- Lit16, (UShort)insn[2],
11260//.. //-- TempReg, t1 );
11261//.. //-- DIP("clflush %s\n", dis_buf);
11262//.. //-- goto decode_success;
11263//.. //-- }
sewardjdf0e0022005-01-25 15:48:43 +000011264
11265
11266 /* ---------------------------------------------------- */
11267 /* --- end of the SSE/SSE2 decoder. --- */
11268 /* ---------------------------------------------------- */
11269
sewardj7a240552005-01-28 21:37:12 +000011270 /*after_sse_decoders:*/
sewardjdf0e0022005-01-25 15:48:43 +000011271
11272 /* Get the primary opcode. */
sewardj8c332e22005-01-28 01:36:56 +000011273 opc = getUChar(delta); delta++;
sewardjdf0e0022005-01-25 15:48:43 +000011274
11275 /* We get here if the current insn isn't SSE, or this CPU doesn't
11276 support SSE. */
11277
11278 switch (opc) {
11279
11280 /* ------------------------ Control flow --------------- */
11281
sewardjd20c8852005-01-20 20:04:07 +000011282//.. case 0xC2: /* RET imm16 */
11283//.. d32 = getUDisp16(delta);
11284//.. delta += 2;
11285//.. dis_ret(d32);
11286//.. whatNext = Dis_StopHere;
11287//.. DIP("ret %d\n", d32);
11288//.. break;
sewardj2f959cc2005-01-26 01:19:35 +000011289 case 0xC3: /* RET */
sewardj55dbb262005-01-28 16:36:51 +000011290 if (haveF2(pfx)) goto decode_failure;
11291 /* F3 is acceptable on AMD. */
sewardj2f959cc2005-01-26 01:19:35 +000011292 dis_ret(0);
sewardj9e6491a2005-07-02 19:24:10 +000011293 dres.whatNext = Dis_StopHere;
sewardje941eea2005-01-30 19:52:28 +000011294 DIP(haveF3(pfx) ? "rep ; ret\n" : "ret\n");
sewardj2f959cc2005-01-26 01:19:35 +000011295 break;
11296
sewardj3ca55a12005-01-27 16:06:23 +000011297 case 0xE8: /* CALL J4 */
11298 if (haveF2orF3(pfx)) goto decode_failure;
11299 d64 = getSDisp32(delta); delta += 4;
sewardj9e6491a2005-07-02 19:24:10 +000011300 d64 += (guest_RIP_bbstart+delta);
11301 /* (guest_RIP_bbstart+delta) == return-to addr, d64 == call-to addr */
sewardj3ca55a12005-01-27 16:06:23 +000011302 t1 = newTemp(Ity_I64);
11303 assign(t1, binop(Iop_Sub64, getIReg64(R_RSP), mkU64(8)));
11304 putIReg64(R_RSP, mkexpr(t1));
sewardj9e6491a2005-07-02 19:24:10 +000011305 storeLE( mkexpr(t1), mkU64(guest_RIP_bbstart+delta));
sewardj5a9ffab2005-05-12 17:55:01 +000011306 make_redzone_AbiHint(t1, "call-d32");
sewardj9e6491a2005-07-02 19:24:10 +000011307 if (resteerOkFn((Addr64)d64)) {
sewardj3ca55a12005-01-27 16:06:23 +000011308 /* follow into the call target. */
sewardj9e6491a2005-07-02 19:24:10 +000011309 dres.whatNext = Dis_Resteer;
11310 dres.continueAt = d64;
sewardj3ca55a12005-01-27 16:06:23 +000011311 } else {
11312 jmp_lit(Ijk_Call,d64);
sewardj9e6491a2005-07-02 19:24:10 +000011313 dres.whatNext = Dis_StopHere;
sewardj3ca55a12005-01-27 16:06:23 +000011314 }
11315 DIP("call 0x%llx\n",d64);
11316 break;
11317
sewardjd20c8852005-01-20 20:04:07 +000011318//.. //-- case 0xC8: /* ENTER */
11319//.. //-- d32 = getUDisp16(eip); eip += 2;
sewardj8c332e22005-01-28 01:36:56 +000011320//.. //-- abyte = getUChar(delta); delta++;
sewardjd20c8852005-01-20 20:04:07 +000011321//.. //--
11322//.. //-- vg_assert(sz == 4);
11323//.. //-- vg_assert(abyte == 0);
11324//.. //--
11325//.. //-- t1 = newTemp(cb); t2 = newTemp(cb);
11326//.. //-- uInstr2(cb, GET, sz, ArchReg, R_EBP, TempReg, t1);
11327//.. //-- uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t2);
11328//.. //-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
11329//.. //-- uLiteral(cb, sz);
11330//.. //-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
11331//.. //-- uInstr2(cb, STORE, 4, TempReg, t1, TempReg, t2);
11332//.. //-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_EBP);
11333//.. //-- if (d32) {
11334//.. //-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
11335//.. //-- uLiteral(cb, d32);
11336//.. //-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
11337//.. //-- }
11338//.. //-- DIP("enter 0x%x, 0x%x", d32, abyte);
11339//.. //-- break;
sewardje1698952005-02-08 15:02:39 +000011340
11341 case 0xC9: /* LEAVE */
11342 /* In 64-bit mode this defaults to a 64-bit operand size. There
11343 is no way to encode a 32-bit variant. Hence sz==4 but we do
11344 it as if sz=8. */
11345 if (sz != 4)
11346 goto decode_failure;
11347 t1 = newTemp(Ity_I64);
11348 t2 = newTemp(Ity_I64);
11349 assign(t1, getIReg64(R_RBP));
11350 /* First PUT RSP looks redundant, but need it because RSP must
11351 always be up-to-date for Memcheck to work... */
11352 putIReg64(R_RSP, mkexpr(t1));
11353 assign(t2, loadLE(Ity_I64,mkexpr(t1)));
11354 putIReg64(R_RBP, mkexpr(t2));
11355 putIReg64(R_RSP, binop(Iop_Add64, mkexpr(t1), mkU64(8)) );
11356 DIP("leave\n");
11357 break;
11358
sewardjd20c8852005-01-20 20:04:07 +000011359//.. //-- /* ---------------- Misc weird-ass insns --------------- */
11360//.. //--
11361//.. //-- case 0x27: /* DAA */
11362//.. //-- case 0x2F: /* DAS */
11363//.. //-- t1 = newTemp(cb);
11364//.. //-- uInstr2(cb, GET, 1, ArchReg, R_AL, TempReg, t1);
11365//.. //-- /* Widen %AL to 32 bits, so it's all defined when we push it. */
11366//.. //-- uInstr1(cb, WIDEN, 4, TempReg, t1);
11367//.. //-- uWiden(cb, 1, False);
11368//.. //-- uInstr0(cb, CALLM_S, 0);
11369//.. //-- uInstr1(cb, PUSH, 4, TempReg, t1);
11370//.. //-- uInstr1(cb, CALLM, 0, Lit16,
11371//.. //-- opc == 0x27 ? VGOFF_(helper_DAA) : VGOFF_(helper_DAS) );
11372//.. //-- uFlagsRWU(cb, FlagsAC, FlagsSZACP, FlagO);
11373//.. //-- uInstr1(cb, POP, 4, TempReg, t1);
11374//.. //-- uInstr0(cb, CALLM_E, 0);
11375//.. //-- uInstr2(cb, PUT, 1, TempReg, t1, ArchReg, R_AL);
11376//.. //-- DIP(opc == 0x27 ? "daa\n" : "das\n");
11377//.. //-- break;
11378//.. //--
11379//.. //-- case 0x37: /* AAA */
11380//.. //-- case 0x3F: /* AAS */
11381//.. //-- t1 = newTemp(cb);
11382//.. //-- uInstr2(cb, GET, 2, ArchReg, R_EAX, TempReg, t1);
11383//.. //-- /* Widen %AL to 32 bits, so it's all defined when we push it. */
11384//.. //-- uInstr1(cb, WIDEN, 4, TempReg, t1);
11385//.. //-- uWiden(cb, 2, False);
11386//.. //-- uInstr0(cb, CALLM_S, 0);
11387//.. //-- uInstr1(cb, PUSH, 4, TempReg, t1);
11388//.. //-- uInstr1(cb, CALLM, 0, Lit16,
11389//.. //-- opc == 0x37 ? VGOFF_(helper_AAA) : VGOFF_(helper_AAS) );
11390//.. //-- uFlagsRWU(cb, FlagA, FlagsAC, FlagsEmpty);
11391//.. //-- uInstr1(cb, POP, 4, TempReg, t1);
11392//.. //-- uInstr0(cb, CALLM_E, 0);
11393//.. //-- uInstr2(cb, PUT, 2, TempReg, t1, ArchReg, R_EAX);
11394//.. //-- DIP(opc == 0x37 ? "aaa\n" : "aas\n");
11395//.. //-- break;
11396//.. //--
11397//.. //-- case 0xD4: /* AAM */
11398//.. //-- case 0xD5: /* AAD */
sewardj8c332e22005-01-28 01:36:56 +000011399//.. //-- d32 = getUChar(delta); delta++;
sewardjd20c8852005-01-20 20:04:07 +000011400//.. //-- if (d32 != 10) VG_(core_panic)("disInstr: AAM/AAD but base not 10 !");
11401//.. //-- t1 = newTemp(cb);
11402//.. //-- uInstr2(cb, GET, 2, ArchReg, R_EAX, TempReg, t1);
11403//.. //-- /* Widen %AX to 32 bits, so it's all defined when we push it. */
11404//.. //-- uInstr1(cb, WIDEN, 4, TempReg, t1);
11405//.. //-- uWiden(cb, 2, False);
11406//.. //-- uInstr0(cb, CALLM_S, 0);
11407//.. //-- uInstr1(cb, PUSH, 4, TempReg, t1);
11408//.. //-- uInstr1(cb, CALLM, 0, Lit16,
11409//.. //-- opc == 0xD4 ? VGOFF_(helper_AAM) : VGOFF_(helper_AAD) );
11410//.. //-- uFlagsRWU(cb, FlagsEmpty, FlagsSZP, FlagsEmpty);
11411//.. //-- uInstr1(cb, POP, 4, TempReg, t1);
11412//.. //-- uInstr0(cb, CALLM_E, 0);
11413//.. //-- uInstr2(cb, PUT, 2, TempReg, t1, ArchReg, R_EAX);
11414//.. //-- DIP(opc == 0xD4 ? "aam\n" : "aad\n");
11415//.. //-- break;
sewardj3ca55a12005-01-27 16:06:23 +000011416
11417 /* ------------------------ CWD/CDQ -------------------- */
11418
11419 case 0x98: /* CBW */
11420 if (haveF2orF3(pfx)) goto decode_failure;
11421 if (sz == 8) {
sewardj5b470602005-02-27 13:10:48 +000011422 putIRegRAX( 8, unop(Iop_32Sto64, getIRegRAX(4)) );
sewardje941eea2005-01-30 19:52:28 +000011423 DIP(/*"cdqe\n"*/"cltq");
11424 break;
11425 }
sewardj3ca55a12005-01-27 16:06:23 +000011426 if (sz == 4) {
sewardj5b470602005-02-27 13:10:48 +000011427 putIRegRAX( 4, unop(Iop_16Sto32, getIRegRAX(2)) );
sewardj7eaa7cf2005-01-31 18:55:22 +000011428 DIP("cwtl\n");
sewardje941eea2005-01-30 19:52:28 +000011429 break;
11430 }
sewardj3ca55a12005-01-27 16:06:23 +000011431 if (sz == 2) {
sewardj5b470602005-02-27 13:10:48 +000011432 putIRegRAX( 2, unop(Iop_8Sto16, getIRegRAX(1)) );
sewardj3ca55a12005-01-27 16:06:23 +000011433 DIP("cbw\n");
sewardj7bc00082005-03-27 05:08:32 +000011434 break;
sewardj3ca55a12005-01-27 16:06:23 +000011435 }
sewardje941eea2005-01-30 19:52:28 +000011436 goto decode_failure;
sewardj3ca55a12005-01-27 16:06:23 +000011437
11438 case 0x99: /* CWD/CDQ/CQO */
11439 if (haveF2orF3(pfx)) goto decode_failure;
11440 vassert(sz == 2 || sz == 4 || sz == 8);
11441 ty = szToITy(sz);
sewardj5b470602005-02-27 13:10:48 +000011442 putIRegRDX( sz,
11443 binop(mkSizedOp(ty,Iop_Sar8),
11444 getIRegRAX(sz),
11445 mkU8(sz == 2 ? 15 : (sz == 4 ? 31 : 63))) );
sewardje941eea2005-01-30 19:52:28 +000011446 DIP(sz == 2 ? "cwd\n"
sewardj5b470602005-02-27 13:10:48 +000011447 : (sz == 4 ? /*"cdq\n"*/ "cltd\n"
11448 : "cqo\n"));
sewardj3ca55a12005-01-27 16:06:23 +000011449 break;
11450
sewardj8d965312005-02-25 02:48:47 +000011451 /* ------------------------ FPU ops -------------------- */
11452
sewardjd20c8852005-01-20 20:04:07 +000011453//.. case 0x9E: /* SAHF */
11454//.. codegen_SAHF();
11455//.. DIP("sahf\n");
11456//.. break;
11457//..
11458//.. //-- case 0x9F: /* LAHF */
11459//.. //-- codegen_LAHF ( cb );
11460//.. //-- DIP("lahf\n");
11461//.. //-- break;
11462//.. //--
sewardj6847d8c2005-05-12 19:21:55 +000011463 case 0x9B: /* FWAIT */
11464 /* ignore? */
11465 DIP("fwait\n");
11466 break;
sewardj8d965312005-02-25 02:48:47 +000011467
11468 case 0xD8:
11469 case 0xD9:
11470 case 0xDA:
11471 case 0xDB:
11472 case 0xDC:
11473 case 0xDD:
11474 case 0xDE:
11475 case 0xDF:
sewardj5b470602005-02-27 13:10:48 +000011476 if (haveF2orF3(pfx)) goto decode_failure;
sewardj8d965312005-02-25 02:48:47 +000011477 if (sz == 4 && haveNo66noF2noF3(pfx)) {
sewardj270def42005-07-03 01:03:01 +000011478 Long delta0 = delta;
11479 Bool decode_OK = False;
sewardj8d965312005-02-25 02:48:47 +000011480 delta = dis_FPU ( &decode_OK, pfx, delta );
11481 if (!decode_OK) {
11482 delta = delta0;
11483 goto decode_failure;
11484 }
11485 break;
11486 } else {
11487 goto decode_failure;
11488 }
11489
sewardjf8c37f72005-02-07 18:55:29 +000011490 /* ------------------------ Jcond, byte offset --------- */
11491
11492 case 0xEB: /* Jb (jump, byte offset) */
sewardj5b470602005-02-27 13:10:48 +000011493 if (haveF2orF3(pfx)) goto decode_failure;
sewardjf8c37f72005-02-07 18:55:29 +000011494 if (sz != 4)
11495 goto decode_failure; /* JRS added 2004 July 11 */
sewardj9e6491a2005-07-02 19:24:10 +000011496 d64 = (guest_RIP_bbstart+delta+1) + getSDisp8(delta);
sewardjf8c37f72005-02-07 18:55:29 +000011497 delta++;
sewardj9e6491a2005-07-02 19:24:10 +000011498 if (resteerOkFn(d64)) {
11499 dres.whatNext = Dis_Resteer;
11500 dres.continueAt = d64;
sewardjf8c37f72005-02-07 18:55:29 +000011501 } else {
11502 jmp_lit(Ijk_Boring,d64);
sewardj9e6491a2005-07-02 19:24:10 +000011503 dres.whatNext = Dis_StopHere;
sewardjf8c37f72005-02-07 18:55:29 +000011504 }
11505 DIP("jmp-8 0x%llx\n", d64);
11506 break;
sewardj1389d4d2005-01-28 13:46:29 +000011507
11508 case 0xE9: /* Jv (jump, 16/32 offset) */
sewardj5b470602005-02-27 13:10:48 +000011509 if (haveF2orF3(pfx)) goto decode_failure;
sewardjf8c37f72005-02-07 18:55:29 +000011510 if (sz != 4)
11511 goto decode_failure; /* JRS added 2004 July 11 */
sewardj9e6491a2005-07-02 19:24:10 +000011512 d64 = (guest_RIP_bbstart+delta+sz) + getSDisp(sz,delta);
sewardj1389d4d2005-01-28 13:46:29 +000011513 delta += sz;
sewardj9e6491a2005-07-02 19:24:10 +000011514 if (resteerOkFn(d64)) {
11515 dres.whatNext = Dis_Resteer;
11516 dres.continueAt = d64;
sewardj1389d4d2005-01-28 13:46:29 +000011517 } else {
11518 jmp_lit(Ijk_Boring,d64);
sewardj9e6491a2005-07-02 19:24:10 +000011519 dres.whatNext = Dis_StopHere;
sewardj1389d4d2005-01-28 13:46:29 +000011520 }
11521 DIP("jmp 0x%llx\n", d64);
11522 break;
11523
sewardjf8c37f72005-02-07 18:55:29 +000011524 case 0x70:
11525 case 0x71:
11526 case 0x72: /* JBb/JNAEb (jump below) */
11527 case 0x73: /* JNBb/JAEb (jump not below) */
11528 case 0x74: /* JZb/JEb (jump zero) */
11529 case 0x75: /* JNZb/JNEb (jump not zero) */
11530 case 0x76: /* JBEb/JNAb (jump below or equal) */
11531 case 0x77: /* JNBEb/JAb (jump not below or equal) */
11532 case 0x78: /* JSb (jump negative) */
11533 case 0x79: /* JSb (jump not negative) */
11534 case 0x7A: /* JP (jump parity even) */
11535 case 0x7B: /* JNP/JPO (jump parity odd) */
11536 case 0x7C: /* JLb/JNGEb (jump less) */
11537 case 0x7D: /* JGEb/JNLb (jump greater or equal) */
11538 case 0x7E: /* JLEb/JNGb (jump less or equal) */
11539 case 0x7F: /* JGb/JNLEb (jump greater) */
sewardj5b470602005-02-27 13:10:48 +000011540 if (haveF2orF3(pfx)) goto decode_failure;
sewardj9e6491a2005-07-02 19:24:10 +000011541 d64 = (guest_RIP_bbstart+delta+1) + getSDisp8(delta);
sewardjf8c37f72005-02-07 18:55:29 +000011542 delta++;
11543 jcc_01( (AMD64Condcode)(opc - 0x70),
sewardj9e6491a2005-07-02 19:24:10 +000011544 guest_RIP_bbstart+delta,
sewardjf8c37f72005-02-07 18:55:29 +000011545 d64 );
sewardj9e6491a2005-07-02 19:24:10 +000011546 dres.whatNext = Dis_StopHere;
sewardjf8c37f72005-02-07 18:55:29 +000011547 DIP("j%s-8 0x%llx\n", name_AMD64Condcode(opc - 0x70), d64);
11548 break;
11549
sewardjd20c8852005-01-20 20:04:07 +000011550//.. case 0xE3: /* JECXZ or perhaps JCXZ, depending on OSO ? Intel
11551//.. manual says it depends on address size override,
11552//.. which doesn't sound right to me. */
11553//.. vassert(sz==4); /* possibly also OK for sz==2 */
11554//.. d32 = (((Addr32)guest_eip_bbstart)+delta+1) + getSDisp8(delta);
11555//.. delta++;
11556//.. ty = szToITy(sz);
11557//.. stmt( IRStmt_Exit(
11558//.. binop(mkSizedOp(ty,Iop_CmpEQ8),
11559//.. getIReg(sz,R_ECX),
11560//.. mkU(ty,0)),
11561//.. Ijk_Boring,
11562//.. IRConst_U32(d32))
11563//.. );
11564//..
11565//.. DIP("j%sz 0x%x\n", nameIReg(sz, R_ECX), d32);
11566//.. break;
11567//..
11568//.. //-- case 0xE0: /* LOOPNE disp8 */
11569//.. //-- case 0xE1: /* LOOPE disp8 */
sewardj6359f812005-07-20 10:15:34 +000011570 case 0xE2: /* LOOP disp8 */
11571 /* The docs say this uses RCX/ECX as a count depending on
11572 the address size override, not the operand one. Since we
11573 don't handle address size overrides, I guess that means
11574 RCX. */
11575 if (!haveF3(pfx) && !haveF2(pfx) && !have66(pfx) && !haveASO(pfx)) {
11576 /* RCX--; if (RCX != 0) goto d64; */
11577 d64 = guest_RIP_curr_instr + getSDisp8(delta) + 2; delta++;
11578 DIP("loop 0x%llx\n", (ULong)d64);
11579 putIReg64(R_RCX, binop(Iop_Sub64, getIReg64(R_RCX), mkU64(1)) );
11580 stmt( IRStmt_Exit(
11581 binop(Iop_CmpNE64,getIReg64(R_RCX),mkU64(0)),
11582 Ijk_Boring,
11583 IRConst_U64(d64)
11584 ));
11585 dres.whatNext = Dis_StopHere;
11586 irbb->next = mkU64(guest_RIP_curr_instr + 2);
11587 irbb->jumpkind = Ijk_Boring;
11588 break;
11589 }
11590 goto decode_failure;
11591
sewardjd20c8852005-01-20 20:04:07 +000011592//.. //-- d32 = (eip+1) + getSDisp8(eip); eip++;
11593//.. //-- t1 = newTemp(cb);
11594//.. //-- uInstr2(cb, GET, 4, ArchReg, R_ECX, TempReg, t1);
11595//.. //-- uInstr1(cb, DEC, 4, TempReg, t1);
11596//.. //-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_ECX);
11597//.. //-- uInstr2(cb, JIFZ, 4, TempReg, t1, Literal, 0);
11598//.. //-- uLiteral(cb, eip);
11599//.. //-- if (opc == 0xE0 || opc == 0xE1) { /* LOOPE/LOOPNE */
11600//.. //-- jcc_lit(cb, eip, (opc == 0xE1 ? CondNZ : CondZ));
11601//.. //-- }
11602//.. //-- jmp_lit(cb, d32);
11603//.. //-- whatNext = Dis_StopHere;
11604//.. //-- DIP("loop 0x%x\n", d32);
11605//.. //-- break;
sewardj32b2bbe2005-01-28 00:50:10 +000011606
11607 /* ------------------------ IMUL ----------------------- */
11608
11609 case 0x69: /* IMUL Iv, Ev, Gv */
sewardj5b470602005-02-27 13:10:48 +000011610 if (haveF2orF3(pfx)) goto decode_failure;
sewardj32b2bbe2005-01-28 00:50:10 +000011611 delta = dis_imul_I_E_G ( pfx, sz, delta, sz );
11612 break;
sewardj7de0d3c2005-02-13 02:26:41 +000011613 case 0x6B: /* IMUL Ib, Ev, Gv */
11614 delta = dis_imul_I_E_G ( pfx, sz, delta, 1 );
11615 break;
sewardj1389d4d2005-01-28 13:46:29 +000011616
11617 /* ------------------------ MOV ------------------------ */
11618
11619 case 0x88: /* MOV Gb,Eb */
sewardj5b470602005-02-27 13:10:48 +000011620 if (haveF2orF3(pfx)) goto decode_failure;
sewardj1389d4d2005-01-28 13:46:29 +000011621 delta = dis_mov_G_E(pfx, 1, delta);
11622 break;
11623
11624 case 0x89: /* MOV Gv,Ev */
sewardj5b470602005-02-27 13:10:48 +000011625 if (haveF2orF3(pfx)) goto decode_failure;
sewardj1389d4d2005-01-28 13:46:29 +000011626 delta = dis_mov_G_E(pfx, sz, delta);
11627 break;
11628
sewardjd0a12df2005-02-10 02:07:43 +000011629 case 0x8A: /* MOV Eb,Gb */
sewardj5b470602005-02-27 13:10:48 +000011630 if (haveF2orF3(pfx)) goto decode_failure;
sewardjd0a12df2005-02-10 02:07:43 +000011631 delta = dis_mov_E_G(pfx, 1, delta);
11632 break;
11633
sewardj1389d4d2005-01-28 13:46:29 +000011634 case 0x8B: /* MOV Ev,Gv */
sewardj5b470602005-02-27 13:10:48 +000011635 if (haveF2orF3(pfx)) goto decode_failure;
sewardj1389d4d2005-01-28 13:46:29 +000011636 delta = dis_mov_E_G(pfx, sz, delta);
11637 break;
11638
11639 case 0x8D: /* LEA M,Gv */
sewardj5b470602005-02-27 13:10:48 +000011640 if (haveF2orF3(pfx)) goto decode_failure;
sewardj1389d4d2005-01-28 13:46:29 +000011641 if (sz != 4 && sz != 8)
11642 goto decode_failure;
11643 modrm = getUChar(delta);
11644 if (epartIsReg(modrm))
11645 goto decode_failure;
11646 /* NOTE! this is the one place where a segment override prefix
11647 has no effect on the address calculation. Therefore we clear
11648 any segment override bits in pfx. */
sewardje1698952005-02-08 15:02:39 +000011649 addr = disAMode ( &alen, clearSegBits(pfx), delta, dis_buf, 0 );
sewardj1389d4d2005-01-28 13:46:29 +000011650 delta += alen;
11651 /* This is a hack. But it isn't clear that really doing the
11652 calculation at 32 bits is really worth it. Hence for leal,
11653 do the full 64-bit calculation and then truncate it. */
sewardj5b470602005-02-27 13:10:48 +000011654 putIRegG( sz, pfx, modrm,
sewardj1389d4d2005-01-28 13:46:29 +000011655 sz == 4
11656 ? unop(Iop_64to32, mkexpr(addr))
11657 : mkexpr(addr)
11658 );
11659 DIP("lea%c %s, %s\n", nameISize(sz), dis_buf,
sewardj5b470602005-02-27 13:10:48 +000011660 nameIRegG(sz,pfx,modrm));
sewardj1389d4d2005-01-28 13:46:29 +000011661 break;
11662
sewardjd20c8852005-01-20 20:04:07 +000011663//.. case 0x8C: /* MOV Sw,Ew -- MOV from a SEGMENT REGISTER */
11664//.. delta = dis_mov_Sw_Ew(sorb, sz, delta);
11665//.. break;
11666//..
11667//.. case 0x8E: /* MOV Ew,Sw -- MOV to a SEGMENT REGISTER */
11668//.. delta = dis_mov_Ew_Sw(sorb, delta);
11669//.. break;
sewardj2bd97d12005-08-02 21:27:25 +000011670
11671 case 0xA0: /* MOV Ob,AL */
11672 if (have66orF2orF3(pfx)) goto decode_failure;
11673 sz = 1;
11674 /* Fall through ... */
sewardj87277cb2005-08-01 13:03:32 +000011675 case 0xA1: /* MOV Ov,eAX */
sewardj2bd97d12005-08-02 21:27:25 +000011676 if (sz != 8 && sz != 4 && sz != 2 && sz != 1)
11677 goto decode_failure;
sewardj87277cb2005-08-01 13:03:32 +000011678 d64 = getDisp64(delta);
11679 delta += 8;
11680 ty = szToITy(sz);
11681 addr = newTemp(Ity_I64);
11682 assign( addr, handleSegOverride(pfx, mkU64(d64)) );
11683 putIRegRAX(sz, loadLE( ty, mkexpr(addr) ));
11684 DIP("mov%c %s0x%llx, %s\n", nameISize(sz),
11685 sorbTxt(pfx), d64,
11686 nameIRegRAX(sz));
11687 break;
11688
sewardj2bd97d12005-08-02 21:27:25 +000011689 case 0xA2: /* MOV AL,Ob */
11690 if (have66orF2orF3(pfx)) goto decode_failure;
11691 sz = 1;
11692 /* Fall through ... */
sewardj87277cb2005-08-01 13:03:32 +000011693 case 0xA3: /* MOV eAX,Ov */
sewardj2bd97d12005-08-02 21:27:25 +000011694 if (sz != 8 && sz != 4 && sz != 2 && sz != 1)
11695 goto decode_failure;
sewardj87277cb2005-08-01 13:03:32 +000011696 d64 = getDisp64(delta);
11697 delta += 8;
11698 ty = szToITy(sz);
11699 addr = newTemp(Ity_I64);
11700 assign( addr, handleSegOverride(pfx, mkU64(d64)) );
11701 storeLE( mkexpr(addr), getIRegRAX(sz) );
11702 DIP("mov%c %s, %s0x%llx\n", nameISize(sz), nameIRegRAX(sz),
11703 sorbTxt(pfx), d64);
11704 break;
sewardjb095fba2005-02-13 14:13:04 +000011705
sewardj8711f662005-05-09 17:52:56 +000011706 /* XXXX be careful here with moves to AH/BH/CH/DH */
sewardj007e9ec2005-03-23 11:36:48 +000011707 case 0xB0: /* MOV imm,AL */
11708 case 0xB1: /* MOV imm,CL */
sewardjb095fba2005-02-13 14:13:04 +000011709 case 0xB2: /* MOV imm,DL */
sewardj007e9ec2005-03-23 11:36:48 +000011710 case 0xB3: /* MOV imm,BL */
11711 case 0xB4: /* MOV imm,AH */
11712 case 0xB5: /* MOV imm,CH */
11713 case 0xB6: /* MOV imm,DH */
sewardj31eecde2005-03-23 03:39:55 +000011714 case 0xB7: /* MOV imm,BH */
sewardj5b470602005-02-27 13:10:48 +000011715 if (haveF2orF3(pfx)) goto decode_failure;
sewardjb095fba2005-02-13 14:13:04 +000011716 d64 = getUChar(delta);
11717 delta += 1;
sewardj5b470602005-02-27 13:10:48 +000011718 putIRegRexB(1, pfx, opc-0xB0, mkU8(d64));
11719 DIP("movb $%lld,%s\n", d64, nameIRegRexB(1,pfx,opc-0xB0));
sewardjb095fba2005-02-13 14:13:04 +000011720 break;
sewardj1389d4d2005-01-28 13:46:29 +000011721
11722 case 0xB8: /* MOV imm,eAX */
11723 case 0xB9: /* MOV imm,eCX */
11724 case 0xBA: /* MOV imm,eDX */
11725 case 0xBB: /* MOV imm,eBX */
11726 case 0xBC: /* MOV imm,eSP */
11727 case 0xBD: /* MOV imm,eBP */
11728 case 0xBE: /* MOV imm,eSI */
11729 case 0xBF: /* MOV imm,eDI */
sewardj03b07cc2005-01-31 18:09:43 +000011730 /* This is the one-and-only place where 64-bit literals are
11731 allowed in the instruction stream. */
sewardj5b470602005-02-27 13:10:48 +000011732 if (haveF2orF3(pfx)) goto decode_failure;
sewardj03b07cc2005-01-31 18:09:43 +000011733 if (sz == 8) {
11734 d64 = getDisp64(delta);
sewardj7eaa7cf2005-01-31 18:55:22 +000011735 delta += 8;
sewardj5b470602005-02-27 13:10:48 +000011736 putIRegRexB(8, pfx, opc-0xB8, mkU64(d64));
sewardj227458e2005-01-31 19:04:50 +000011737 DIP("movabsq $%lld,%s\n", (Long)d64,
sewardj5b470602005-02-27 13:10:48 +000011738 nameIRegRexB(8,pfx,opc-0xB8));
sewardj03b07cc2005-01-31 18:09:43 +000011739 } else {
11740 d64 = getSDisp(imin(4,sz),delta);
11741 delta += imin(4,sz);
sewardj5b470602005-02-27 13:10:48 +000011742 putIRegRexB(sz, pfx, opc-0xB8,
11743 mkU(szToITy(sz), d64 & mkSizeMask(sz)));
sewardj227458e2005-01-31 19:04:50 +000011744 DIP("mov%c $%lld,%s\n", nameISize(sz),
11745 (Long)d64,
sewardj5b470602005-02-27 13:10:48 +000011746 nameIRegRexB(sz,pfx,opc-0xB8));
sewardj03b07cc2005-01-31 18:09:43 +000011747 }
sewardj1389d4d2005-01-28 13:46:29 +000011748 break;
11749
11750 case 0xC6: /* MOV Ib,Eb */
11751 sz = 1;
11752 goto do_Mov_I_E;
11753 case 0xC7: /* MOV Iv,Ev */
11754 goto do_Mov_I_E;
11755
11756 do_Mov_I_E:
sewardj5b470602005-02-27 13:10:48 +000011757 if (haveF2orF3(pfx)) goto decode_failure;
sewardj1389d4d2005-01-28 13:46:29 +000011758 modrm = getUChar(delta);
11759 if (epartIsReg(modrm)) {
sewardj1389d4d2005-01-28 13:46:29 +000011760 delta++; /* mod/rm byte */
11761 d64 = getSDisp(imin(4,sz),delta);
11762 delta += imin(4,sz);
sewardj5b470602005-02-27 13:10:48 +000011763 putIRegE(sz, pfx, modrm,
11764 mkU(szToITy(sz), d64 & mkSizeMask(sz)));
sewardj227458e2005-01-31 19:04:50 +000011765 DIP("mov%c $%lld, %s\n", nameISize(sz),
11766 (Long)d64,
sewardj5b470602005-02-27 13:10:48 +000011767 nameIRegE(sz,pfx,modrm));
sewardj1389d4d2005-01-28 13:46:29 +000011768 } else {
sewardj5b470602005-02-27 13:10:48 +000011769 addr = disAMode ( &alen, pfx, delta, dis_buf,
11770 /*xtra*/imin(4,sz) );
sewardj1389d4d2005-01-28 13:46:29 +000011771 delta += alen;
sewardje941eea2005-01-30 19:52:28 +000011772 d64 = getSDisp(imin(4,sz),delta);
sewardj1389d4d2005-01-28 13:46:29 +000011773 delta += imin(4,sz);
sewardje941eea2005-01-30 19:52:28 +000011774 storeLE(mkexpr(addr),
11775 mkU(szToITy(sz), d64 & mkSizeMask(sz)));
sewardj227458e2005-01-31 19:04:50 +000011776 DIP("mov%c $%lld, %s\n", nameISize(sz), (Long)d64, dis_buf);
sewardj1389d4d2005-01-28 13:46:29 +000011777 }
11778 break;
11779
sewardj5e525292005-01-28 15:13:10 +000011780 /* ------------------------ MOVx ------------------------ */
11781
11782 case 0x63: /* MOVSX */
sewardj5b470602005-02-27 13:10:48 +000011783 if (haveF2orF3(pfx)) goto decode_failure;
sewardj5e525292005-01-28 15:13:10 +000011784 if (haveREX(pfx) && 1==getRexW(pfx)) {
11785 vassert(sz == 8);
11786 /* movsx r/m32 to r64 */
11787 modrm = getUChar(delta);
11788 if (epartIsReg(modrm)) {
11789 delta++;
sewardj5b470602005-02-27 13:10:48 +000011790 putIRegG(8, pfx, modrm,
sewardj5e525292005-01-28 15:13:10 +000011791 unop(Iop_32Sto64,
sewardj5b470602005-02-27 13:10:48 +000011792 getIRegE(4, pfx, modrm)));
sewardj5e525292005-01-28 15:13:10 +000011793 DIP("movslq %s,%s\n",
sewardj5b470602005-02-27 13:10:48 +000011794 nameIRegE(4, pfx, modrm),
11795 nameIRegG(8, pfx, modrm));
sewardj5e525292005-01-28 15:13:10 +000011796 break;
11797 } else {
sewardje1698952005-02-08 15:02:39 +000011798 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
sewardj5e525292005-01-28 15:13:10 +000011799 delta += alen;
sewardj5b470602005-02-27 13:10:48 +000011800 putIRegG(8, pfx, modrm,
sewardj5e525292005-01-28 15:13:10 +000011801 unop(Iop_32Sto64,
11802 loadLE(Ity_I32, mkexpr(addr))));
11803 DIP("movslq %s,%s\n", dis_buf,
sewardj5b470602005-02-27 13:10:48 +000011804 nameIRegG(8, pfx, modrm));
sewardj5e525292005-01-28 15:13:10 +000011805 break;
11806 }
11807 } else {
11808 goto decode_failure;
11809 }
11810
sewardj4c328cf2005-05-05 12:05:54 +000011811 /* ------------------------ opl imm, A ----------------- */
11812
11813 case 0x04: /* ADD Ib, AL */
11814 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000011815 delta = dis_op_imm_A( 1, False, Iop_Add8, True, delta, "add" );
sewardj4c328cf2005-05-05 12:05:54 +000011816 break;
sewardj03b07cc2005-01-31 18:09:43 +000011817 case 0x05: /* ADD Iv, eAX */
sewardj5b470602005-02-27 13:10:48 +000011818 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000011819 delta = dis_op_imm_A(sz, False, Iop_Add8, True, delta, "add" );
sewardj03b07cc2005-01-31 18:09:43 +000011820 break;
11821
sewardj007e9ec2005-03-23 11:36:48 +000011822 case 0x0C: /* OR Ib, AL */
11823 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000011824 delta = dis_op_imm_A( 1, False, Iop_Or8, True, delta, "or" );
sewardj007e9ec2005-03-23 11:36:48 +000011825 break;
sewardj03b07cc2005-01-31 18:09:43 +000011826 case 0x0D: /* OR Iv, eAX */
sewardj5b470602005-02-27 13:10:48 +000011827 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000011828 delta = dis_op_imm_A( sz, False, Iop_Or8, True, delta, "or" );
sewardj03b07cc2005-01-31 18:09:43 +000011829 break;
11830
sewardj41c01092005-07-23 13:50:32 +000011831 case 0x14: /* ADC Ib, AL */
11832 delta = dis_op_imm_A( 1, True, Iop_Add8, True, delta, "adc" );
11833 break;
sewardjd20c8852005-01-20 20:04:07 +000011834//.. //-- case 0x15: /* ADC Iv, eAX */
11835//.. //-- delta = dis_op_imm_A( sz, ADC, True, delta, "adc" );
11836//.. //-- break;
11837//.. //--
11838//.. //-- case 0x1C: /* SBB Ib, AL */
11839//.. //-- delta = dis_op_imm_A( 1, SBB, True, delta, "sbb" );
11840//.. //-- break;
11841//.. //-- case 0x1D: /* SBB Iv, eAX */
11842//.. //-- delta = dis_op_imm_A( sz, SBB, True, delta, "sbb" );
11843//.. //-- break;
11844//.. //--
sewardj007e9ec2005-03-23 11:36:48 +000011845 case 0x24: /* AND Ib, AL */
11846 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000011847 delta = dis_op_imm_A( 1, False, Iop_And8, True, delta, "and" );
sewardj007e9ec2005-03-23 11:36:48 +000011848 break;
sewardj3ca55a12005-01-27 16:06:23 +000011849 case 0x25: /* AND Iv, eAX */
11850 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000011851 delta = dis_op_imm_A( sz, False, Iop_And8, True, delta, "and" );
sewardj3ca55a12005-01-27 16:06:23 +000011852 break;
11853
sewardj137015d2005-03-27 04:01:15 +000011854 case 0x2C: /* SUB Ib, AL */
11855 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000011856 delta = dis_op_imm_A(1, False, Iop_Sub8, True, delta, "sub" );
sewardj137015d2005-03-27 04:01:15 +000011857 break;
sewardj03b07cc2005-01-31 18:09:43 +000011858 case 0x2D: /* SUB Iv, eAX */
sewardj5b470602005-02-27 13:10:48 +000011859 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000011860 delta = dis_op_imm_A( sz, False, Iop_Sub8, True, delta, "sub" );
sewardj03b07cc2005-01-31 18:09:43 +000011861 break;
11862
sewardj8eb804f2005-05-18 10:22:47 +000011863 case 0x34: /* XOR Ib, AL */
11864 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000011865 delta = dis_op_imm_A( 1, False, Iop_Xor8, True, delta, "xor" );
sewardj8eb804f2005-05-18 10:22:47 +000011866 break;
sewardj85520e42005-02-19 15:22:38 +000011867 case 0x35: /* XOR Iv, eAX */
sewardj5b470602005-02-27 13:10:48 +000011868 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000011869 delta = dis_op_imm_A( sz, False, Iop_Xor8, True, delta, "xor" );
sewardj85520e42005-02-19 15:22:38 +000011870 break;
sewardj03b07cc2005-01-31 18:09:43 +000011871
11872 case 0x3C: /* CMP Ib, AL */
11873 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000011874 delta = dis_op_imm_A( 1, False, Iop_Sub8, False, delta, "cmp" );
sewardj03b07cc2005-01-31 18:09:43 +000011875 break;
sewardj354e5c62005-01-27 20:12:52 +000011876 case 0x3D: /* CMP Iv, eAX */
11877 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000011878 delta = dis_op_imm_A( sz, False, Iop_Sub8, False, delta, "cmp" );
sewardj354e5c62005-01-27 20:12:52 +000011879 break;
11880
sewardj118b23e2005-01-29 02:14:44 +000011881 case 0xA8: /* TEST Ib, AL */
sewardj03b07cc2005-01-31 18:09:43 +000011882 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000011883 delta = dis_op_imm_A( 1, False, Iop_And8, False, delta, "test" );
sewardj118b23e2005-01-29 02:14:44 +000011884 break;
11885 case 0xA9: /* TEST Iv, eAX */
sewardj03b07cc2005-01-31 18:09:43 +000011886 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000011887 delta = dis_op_imm_A( sz, False, Iop_And8, False, delta, "test" );
sewardj118b23e2005-01-29 02:14:44 +000011888 break;
11889
11890 /* ------------------------ opl Ev, Gv ----------------- */
11891
sewardj03b07cc2005-01-31 18:09:43 +000011892 case 0x02: /* ADD Eb,Gb */
11893 if (haveF2orF3(pfx)) goto decode_failure;
11894 delta = dis_op2_E_G ( pfx, False, Iop_Add8, True, 1, delta, "add" );
11895 break;
sewardjdf0e0022005-01-25 15:48:43 +000011896 case 0x03: /* ADD Ev,Gv */
sewardj3ca55a12005-01-27 16:06:23 +000011897 if (haveF2orF3(pfx)) goto decode_failure;
sewardjdf0e0022005-01-25 15:48:43 +000011898 delta = dis_op2_E_G ( pfx, False, Iop_Add8, True, sz, delta, "add" );
sewardjdf0e0022005-01-25 15:48:43 +000011899 break;
11900
sewardj03b07cc2005-01-31 18:09:43 +000011901 case 0x0A: /* OR Eb,Gb */
sewardj5b470602005-02-27 13:10:48 +000011902 if (haveF2orF3(pfx)) goto decode_failure;
sewardj03b07cc2005-01-31 18:09:43 +000011903 delta = dis_op2_E_G ( pfx, False, Iop_Or8, True, 1, delta, "or" );
11904 break;
11905 case 0x0B: /* OR Ev,Gv */
sewardj5b470602005-02-27 13:10:48 +000011906 if (haveF2orF3(pfx)) goto decode_failure;
sewardj03b07cc2005-01-31 18:09:43 +000011907 delta = dis_op2_E_G ( pfx, False, Iop_Or8, True, sz, delta, "or" );
11908 break;
11909//--
sewardjd20c8852005-01-20 20:04:07 +000011910//.. //-- case 0x12: /* ADC Eb,Gb */
11911//.. //-- delta = dis_op2_E_G ( sorb, True, ADC, True, 1, delta, "adc" );
11912//.. //-- break;
sewardj22cab062005-07-19 23:59:54 +000011913 case 0x13: /* ADC Ev,Gv */
11914 delta = dis_op2_E_G ( pfx, True, Iop_Add8, True, sz, delta, "adc" );
11915 break;
11916
sewardjd20c8852005-01-20 20:04:07 +000011917//.. //-- case 0x1A: /* SBB Eb,Gb */
11918//.. //-- delta = dis_op2_E_G ( sorb, True, SBB, True, 1, delta, "sbb" );
11919//.. //-- break;
sewardj7a06b852005-07-20 10:55:26 +000011920 case 0x1B: /* SBB Ev,Gv */
11921 delta = dis_op2_E_G ( pfx, True, Iop_Sub8, True, sz, delta, "sbb" );
11922 break;
sewardj03b07cc2005-01-31 18:09:43 +000011923
11924 case 0x22: /* AND Eb,Gb */
11925 if (haveF2orF3(pfx)) goto decode_failure;
11926 delta = dis_op2_E_G ( pfx, False, Iop_And8, True, 1, delta, "and" );
11927 break;
11928 case 0x23: /* AND Ev,Gv */
11929 if (haveF2orF3(pfx)) goto decode_failure;
11930 delta = dis_op2_E_G ( pfx, False, Iop_And8, True, sz, delta, "and" );
11931 break;
11932
11933 case 0x2A: /* SUB Eb,Gb */
11934 if (haveF2orF3(pfx)) goto decode_failure;
11935 delta = dis_op2_E_G ( pfx, False, Iop_Sub8, True, 1, delta, "sub" );
11936 break;
sewardj118b23e2005-01-29 02:14:44 +000011937 case 0x2B: /* SUB Ev,Gv */
sewardj03b07cc2005-01-31 18:09:43 +000011938 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000011939 delta = dis_op2_E_G ( pfx, False, Iop_Sub8, True, sz, delta, "sub" );
11940 break;
11941
sewardj03b07cc2005-01-31 18:09:43 +000011942 case 0x32: /* XOR Eb,Gb */
11943 if (haveF2orF3(pfx)) goto decode_failure;
11944 delta = dis_op2_E_G ( pfx, False, Iop_Xor8, True, 1, delta, "xor" );
11945 break;
11946 case 0x33: /* XOR Ev,Gv */
11947 if (haveF2orF3(pfx)) goto decode_failure;
11948 delta = dis_op2_E_G ( pfx, False, Iop_Xor8, True, sz, delta, "xor" );
11949 break;
11950
sewardjb095fba2005-02-13 14:13:04 +000011951 case 0x3A: /* CMP Eb,Gb */
11952 if (haveF2orF3(pfx)) goto decode_failure;
11953 delta = dis_op2_E_G ( pfx, False, Iop_Sub8, False, 1, delta, "cmp" );
11954 break;
sewardj354e5c62005-01-27 20:12:52 +000011955 case 0x3B: /* CMP Ev,Gv */
11956 if (haveF2orF3(pfx)) goto decode_failure;
11957 delta = dis_op2_E_G ( pfx, False, Iop_Sub8, False, sz, delta, "cmp" );
11958 break;
11959
sewardj118b23e2005-01-29 02:14:44 +000011960 case 0x84: /* TEST Eb,Gb */
sewardj03b07cc2005-01-31 18:09:43 +000011961 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000011962 delta = dis_op2_E_G ( pfx, False, Iop_And8, False, 1, delta, "test" );
11963 break;
11964 case 0x85: /* TEST Ev,Gv */
sewardj03b07cc2005-01-31 18:09:43 +000011965 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000011966 delta = dis_op2_E_G ( pfx, False, Iop_And8, False, sz, delta, "test" );
11967 break;
11968
11969 /* ------------------------ opl Gv, Ev ----------------- */
11970
sewardj85520e42005-02-19 15:22:38 +000011971 case 0x00: /* ADD Gb,Eb */
11972 if (haveF2orF3(pfx)) goto decode_failure;
11973 delta = dis_op2_G_E ( pfx, False, Iop_Add8, True, 1, delta, "add" );
11974 break;
sewardj3ca55a12005-01-27 16:06:23 +000011975 case 0x01: /* ADD Gv,Ev */
sewardj354e5c62005-01-27 20:12:52 +000011976 if (haveF2orF3(pfx)) goto decode_failure;
sewardj3ca55a12005-01-27 16:06:23 +000011977 delta = dis_op2_G_E ( pfx, False, Iop_Add8, True, sz, delta, "add" );
11978 break;
11979
sewardj03b07cc2005-01-31 18:09:43 +000011980 case 0x08: /* OR Gb,Eb */
11981 if (haveF2orF3(pfx)) goto decode_failure;
11982 delta = dis_op2_G_E ( pfx, False, Iop_Or8, True, 1, delta, "or" );
11983 break;
sewardj55dbb262005-01-28 16:36:51 +000011984 case 0x09: /* OR Gv,Ev */
11985 if (haveF2orF3(pfx)) goto decode_failure;
11986 delta = dis_op2_G_E ( pfx, False, Iop_Or8, True, sz, delta, "or" );
11987 break;
11988
sewardj85520e42005-02-19 15:22:38 +000011989 case 0x10: /* ADC Gb,Eb */
11990 if (haveF2orF3(pfx)) goto decode_failure;
11991 delta = dis_op2_G_E ( pfx, True, Iop_Add8, True, 1, delta, "adc" );
11992 break;
11993 case 0x11: /* ADC Gv,Ev */
11994 if (haveF2orF3(pfx)) goto decode_failure;
11995 delta = dis_op2_G_E ( pfx, True, Iop_Add8, True, sz, delta, "adc" );
11996 break;
11997
11998 case 0x18: /* SBB Gb,Eb */
11999 if (haveF2orF3(pfx)) goto decode_failure;
12000 delta = dis_op2_G_E ( pfx, True, Iop_Sub8, True, 1, delta, "sbb" );
12001 break;
sewardj03b07cc2005-01-31 18:09:43 +000012002 case 0x19: /* SBB Gv,Ev */
sewardja6b93d12005-02-17 09:28:28 +000012003 if (haveF2orF3(pfx)) goto decode_failure;
sewardj03b07cc2005-01-31 18:09:43 +000012004 delta = dis_op2_G_E ( pfx, True, Iop_Sub8, True, sz, delta, "sbb" );
12005 break;
12006
sewardj85520e42005-02-19 15:22:38 +000012007 case 0x20: /* AND Gb,Eb */
12008 if (haveF2orF3(pfx)) goto decode_failure;
12009 delta = dis_op2_G_E ( pfx, False, Iop_And8, True, 1, delta, "and" );
12010 break;
sewardj3ca55a12005-01-27 16:06:23 +000012011 case 0x21: /* AND Gv,Ev */
sewardj354e5c62005-01-27 20:12:52 +000012012 if (haveF2orF3(pfx)) goto decode_failure;
sewardj3ca55a12005-01-27 16:06:23 +000012013 delta = dis_op2_G_E ( pfx, False, Iop_And8, True, sz, delta, "and" );
12014 break;
sewardj03b07cc2005-01-31 18:09:43 +000012015
12016 case 0x28: /* SUB Gb,Eb */
12017 if (haveF2orF3(pfx)) goto decode_failure;
12018 delta = dis_op2_G_E ( pfx, False, Iop_Sub8, True, 1, delta, "sub" );
12019 break;
sewardj118b23e2005-01-29 02:14:44 +000012020 case 0x29: /* SUB Gv,Ev */
sewardj03b07cc2005-01-31 18:09:43 +000012021 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000012022 delta = dis_op2_G_E ( pfx, False, Iop_Sub8, True, sz, delta, "sub" );
12023 break;
12024
sewardjb095fba2005-02-13 14:13:04 +000012025 case 0x30: /* XOR Gb,Eb */
12026 if (haveF2orF3(pfx)) goto decode_failure;
12027 delta = dis_op2_G_E ( pfx, False, Iop_Xor8, True, 1, delta, "xor" );
12028 break;
sewardj118b23e2005-01-29 02:14:44 +000012029 case 0x31: /* XOR Gv,Ev */
sewardj03b07cc2005-01-31 18:09:43 +000012030 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000012031 delta = dis_op2_G_E ( pfx, False, Iop_Xor8, True, sz, delta, "xor" );
12032 break;
sewardj354e5c62005-01-27 20:12:52 +000012033
12034 case 0x38: /* CMP Gb,Eb */
12035 if (haveF2orF3(pfx)) goto decode_failure;
12036 delta = dis_op2_G_E ( pfx, False, Iop_Sub8, False, 1, delta, "cmp" );
12037 break;
12038 case 0x39: /* CMP Gv,Ev */
12039 if (haveF2orF3(pfx)) goto decode_failure;
12040 delta = dis_op2_G_E ( pfx, False, Iop_Sub8, False, sz, delta, "cmp" );
12041 break;
12042
sewardj55dbb262005-01-28 16:36:51 +000012043 /* ------------------------ POP ------------------------ */
12044
12045 case 0x58: /* POP eAX */
12046 case 0x59: /* POP eCX */
12047 case 0x5A: /* POP eDX */
12048 case 0x5B: /* POP eBX */
12049 case 0x5D: /* POP eBP */
12050 case 0x5E: /* POP eSI */
12051 case 0x5F: /* POP eDI */
12052 case 0x5C: /* POP eSP */
sewardj03b07cc2005-01-31 18:09:43 +000012053 if (haveF2orF3(pfx)) goto decode_failure;
sewardj55dbb262005-01-28 16:36:51 +000012054 vassert(sz == 2 || sz == 4 || sz == 8);
12055 if (sz == 4)
12056 sz = 8; /* there is no encoding for 32-bit pop in 64-bit mode */
12057 t1 = newTemp(szToITy(sz));
12058 t2 = newTemp(Ity_I64);
12059 assign(t2, getIReg64(R_RSP));
12060 assign(t1, loadLE(szToITy(sz),mkexpr(t2)));
12061 putIReg64(R_RSP, binop(Iop_Add64, mkexpr(t2), mkU64(sz)));
sewardj5b470602005-02-27 13:10:48 +000012062 putIRegRexB(sz, pfx, opc-0x58, mkexpr(t1));
12063 DIP("pop%c %s\n", nameISize(sz), nameIRegRexB(sz,pfx,opc-0x58));
sewardj55dbb262005-01-28 16:36:51 +000012064 break;
12065
sewardj85520e42005-02-19 15:22:38 +000012066 case 0x9D: /* POPF */
12067 /* Note. There is no encoding for a 32-bit popf in 64-bit mode.
12068 So sz==4 actually means sz==8. */
sewardj5b470602005-02-27 13:10:48 +000012069 if (haveF2orF3(pfx)) goto decode_failure;
sewardj85520e42005-02-19 15:22:38 +000012070 vassert(sz == 2 || sz == 4);
12071 if (sz == 4) sz = 8;
sewardj5b470602005-02-27 13:10:48 +000012072 if (sz != 8) goto decode_failure; // until we know a sz==2 test case exists
sewardj85520e42005-02-19 15:22:38 +000012073 t1 = newTemp(Ity_I64); t2 = newTemp(Ity_I64);
12074 assign(t2, getIReg64(R_RSP));
12075 assign(t1, widenUto64(loadLE(szToITy(sz),mkexpr(t2))));
12076 putIReg64(R_RSP, binop(Iop_Add64, mkexpr(t2), mkU64(sz)));
12077 /* t1 is the flag word. Mask out everything except OSZACP and
12078 set the flags thunk to AMD64G_CC_OP_COPY. */
12079 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(AMD64G_CC_OP_COPY) ));
12080 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
12081 stmt( IRStmt_Put( OFFB_CC_DEP1,
12082 binop(Iop_And64,
12083 mkexpr(t1),
12084 mkU64( AMD64G_CC_MASK_C | AMD64G_CC_MASK_P
12085 | AMD64G_CC_MASK_A | AMD64G_CC_MASK_Z
12086 | AMD64G_CC_MASK_S| AMD64G_CC_MASK_O )
12087 )
12088 )
12089 );
12090
12091 /* Also need to set the D flag, which is held in bit 10 of t1.
12092 If zero, put 1 in OFFB_DFLAG, else -1 in OFFB_DFLAG. */
12093 stmt( IRStmt_Put(
12094 OFFB_DFLAG,
12095 IRExpr_Mux0X(
12096 unop(Iop_32to8,
12097 unop(Iop_64to32,
12098 binop(Iop_And64,
12099 binop(Iop_Shr64, mkexpr(t1), mkU8(10)),
12100 mkU64(1)))),
12101 mkU64(1),
12102 mkU64(0xFFFFFFFFFFFFFFFFULL)))
12103 );
12104
12105 /* And set the ID flag */
12106 stmt( IRStmt_Put(
12107 OFFB_IDFLAG,
12108 IRExpr_Mux0X(
12109 unop(Iop_32to8,
12110 unop(Iop_64to32,
12111 binop(Iop_And64,
12112 binop(Iop_Shr64, mkexpr(t1), mkU8(21)),
12113 mkU64(1)))),
12114 mkU64(0),
12115 mkU64(1)))
12116 );
12117
12118 DIP("popf%c\n", nameISize(sz));
12119 break;
12120
sewardjd20c8852005-01-20 20:04:07 +000012121//.. case 0x61: /* POPA */
12122//.. /* This is almost certainly wrong for sz==2. So ... */
12123//.. if (sz != 4) goto decode_failure;
12124//..
12125//.. /* t5 is the old %ESP value. */
12126//.. t5 = newTemp(Ity_I32);
12127//.. assign( t5, getIReg(4, R_ESP) );
12128//..
12129//.. /* Reload all the registers, except %esp. */
12130//.. putIReg(4,R_EAX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(28)) ));
12131//.. putIReg(4,R_ECX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(24)) ));
12132//.. putIReg(4,R_EDX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(20)) ));
12133//.. putIReg(4,R_EBX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(16)) ));
12134//.. /* ignore saved %ESP */
12135//.. putIReg(4,R_EBP, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32( 8)) ));
12136//.. putIReg(4,R_ESI, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32( 4)) ));
12137//.. putIReg(4,R_EDI, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32( 0)) ));
12138//..
12139//.. /* and move %ESP back up */
12140//.. putIReg( 4, R_ESP, binop(Iop_Add32, mkexpr(t5), mkU32(8*4)) );
12141//..
12142//.. DIP("pusha%c\n", nameISize(sz));
12143//.. break;
sewardj432f8b62005-05-10 02:50:05 +000012144
12145 case 0x8F: { /* POPQ m64 / POPW m16 */
sewardj1bd14e72005-05-11 16:24:00 +000012146 Int len;
12147 UChar rm;
sewardj432f8b62005-05-10 02:50:05 +000012148 /* There is no encoding for 32-bit pop in 64-bit mode.
12149 So sz==4 actually means sz==8. */
12150 if (haveF2orF3(pfx)) goto decode_failure;
12151 vassert(sz == 2 || sz == 4);
12152 if (sz == 4) sz = 8;
12153 if (sz != 8) goto decode_failure; // until we know a sz==2 test case exists
12154
sewardj1bd14e72005-05-11 16:24:00 +000012155 rm = getUChar(delta);
sewardj432f8b62005-05-10 02:50:05 +000012156
12157 /* make sure this instruction is correct POP */
12158 if (epartIsReg(rm) || gregLO3ofRM(rm) != 0)
12159 goto decode_failure;
12160 /* and has correct size */
12161 vassert(sz == 8);
12162
12163 t1 = newTemp(Ity_I64);
12164 t3 = newTemp(Ity_I64);
12165 assign( t1, getIReg64(R_RSP) );
12166 assign( t3, loadLE(Ity_I64, mkexpr(t1)) );
12167
12168 /* Increase RSP; must be done before the STORE. Intel manual
12169 says: If the RSP register is used as a base register for
12170 addressing a destination operand in memory, the POP
12171 instruction computes the effective address of the operand
12172 after it increments the RSP register. */
12173 putIReg64(R_RSP, binop(Iop_Add64, mkexpr(t1), mkU64(sz)) );
12174
12175 addr = disAMode ( &len, pfx, delta, dis_buf, 0 );
12176 storeLE( mkexpr(addr), mkexpr(t3) );
12177
12178 DIP("popl %s\n", dis_buf);
12179
12180 delta += len;
12181 break;
12182 }
12183
sewardjd20c8852005-01-20 20:04:07 +000012184//.. //-- case 0x1F: /* POP %DS */
12185//.. //-- dis_pop_segreg( cb, R_DS, sz ); break;
12186//.. //-- case 0x07: /* POP %ES */
12187//.. //-- dis_pop_segreg( cb, R_ES, sz ); break;
12188//.. //-- case 0x17: /* POP %SS */
12189//.. //-- dis_pop_segreg( cb, R_SS, sz ); break;
sewardj55dbb262005-01-28 16:36:51 +000012190
12191 /* ------------------------ PUSH ----------------------- */
12192
12193 case 0x50: /* PUSH eAX */
12194 case 0x51: /* PUSH eCX */
12195 case 0x52: /* PUSH eDX */
12196 case 0x53: /* PUSH eBX */
12197 case 0x55: /* PUSH eBP */
12198 case 0x56: /* PUSH eSI */
12199 case 0x57: /* PUSH eDI */
12200 case 0x54: /* PUSH eSP */
12201 /* This is the Right Way, in that the value to be pushed is
12202 established before %rsp is changed, so that pushq %rsp
12203 correctly pushes the old value. */
sewardj03b07cc2005-01-31 18:09:43 +000012204 if (haveF2orF3(pfx)) goto decode_failure;
sewardj55dbb262005-01-28 16:36:51 +000012205 vassert(sz == 2 || sz == 4 || sz == 8);
12206 if (sz == 4)
12207 sz = 8; /* there is no encoding for 32-bit push in 64-bit mode */
12208 ty = sz==2 ? Ity_I16 : Ity_I64;
12209 t1 = newTemp(ty);
12210 t2 = newTemp(Ity_I64);
sewardj5b470602005-02-27 13:10:48 +000012211 assign(t1, getIRegRexB(sz, pfx, opc-0x50));
sewardj55dbb262005-01-28 16:36:51 +000012212 assign(t2, binop(Iop_Sub64, getIReg64(R_RSP), mkU64(sz)));
12213 putIReg64(R_RSP, mkexpr(t2) );
12214 storeLE(mkexpr(t2),mkexpr(t1));
sewardj5b470602005-02-27 13:10:48 +000012215 DIP("push%c %s\n", nameISize(sz), nameIRegRexB(sz,pfx,opc-0x50));
sewardj55dbb262005-01-28 16:36:51 +000012216 break;
12217
sewardja6b93d12005-02-17 09:28:28 +000012218 case 0x68: /* PUSH Iv */
sewardj5b470602005-02-27 13:10:48 +000012219 if (haveF2orF3(pfx)) goto decode_failure;
sewardja6b93d12005-02-17 09:28:28 +000012220 /* Note, sz==4 is not possible in 64-bit mode. Hence ... */
12221 if (sz == 4) sz = 8;
12222 d64 = getSDisp(imin(4,sz),delta);
12223 delta += imin(4,sz);
12224 goto do_push_I;
sewardj909c06d2005-02-19 22:47:41 +000012225 case 0x6A: /* PUSH Ib, sign-extended to sz */
sewardj5b470602005-02-27 13:10:48 +000012226 if (haveF2orF3(pfx)) goto decode_failure;
sewardj909c06d2005-02-19 22:47:41 +000012227 /* Note, sz==4 is not possible in 64-bit mode. Hence ... */
12228 if (sz == 4) sz = 8;
12229 d64 = getSDisp8(delta); delta += 1;
12230 goto do_push_I;
sewardja6b93d12005-02-17 09:28:28 +000012231 do_push_I:
12232 ty = szToITy(sz);
sewardj909c06d2005-02-19 22:47:41 +000012233 t1 = newTemp(Ity_I64);
12234 t2 = newTemp(ty);
sewardja6b93d12005-02-17 09:28:28 +000012235 assign( t1, binop(Iop_Sub64,getIReg64(R_RSP),mkU64(sz)) );
12236 putIReg64(R_RSP, mkexpr(t1) );
12237 storeLE( mkexpr(t1), mkU(ty,d64) );
sewardj1027dc22005-02-26 01:55:02 +000012238 DIP("push%c $%lld\n", nameISize(sz), (Long)d64);
sewardja6b93d12005-02-17 09:28:28 +000012239 break;
12240
sewardj85520e42005-02-19 15:22:38 +000012241 case 0x9C: /* PUSHF */ {
12242 /* Note. There is no encoding for a 32-bit pushf in 64-bit
12243 mode. So sz==4 actually means sz==8. */
sewardj5b470602005-02-27 13:10:48 +000012244 if (haveF2orF3(pfx)) goto decode_failure;
sewardj85520e42005-02-19 15:22:38 +000012245 vassert(sz == 2 || sz == 4);
12246 if (sz == 4) sz = 8;
sewardj5b470602005-02-27 13:10:48 +000012247 if (sz != 8) goto decode_failure; // until we know a sz==2 test case exists
sewardj85520e42005-02-19 15:22:38 +000012248
12249 t1 = newTemp(Ity_I64);
12250 assign( t1, binop(Iop_Sub64,getIReg64(R_RSP),mkU64(sz)) );
12251 putIReg64(R_RSP, mkexpr(t1) );
12252
12253 t2 = newTemp(Ity_I64);
12254 assign( t2, mk_amd64g_calculate_rflags_all() );
12255
12256 /* Patch in the D flag. This can simply be a copy of bit 10 of
12257 baseBlock[OFFB_DFLAG]. */
12258 t3 = newTemp(Ity_I64);
12259 assign( t3, binop(Iop_Or64,
12260 mkexpr(t2),
12261 binop(Iop_And64,
12262 IRExpr_Get(OFFB_DFLAG,Ity_I64),
12263 mkU64(1<<10)))
12264 );
12265
12266 /* And patch in the ID flag. */
12267 t4 = newTemp(Ity_I64);
12268 assign( t4, binop(Iop_Or64,
12269 mkexpr(t3),
12270 binop(Iop_And64,
12271 binop(Iop_Shl64, IRExpr_Get(OFFB_IDFLAG,Ity_I64),
12272 mkU8(21)),
12273 mkU64(1<<21)))
12274 );
12275
12276 /* if sz==2, the stored value needs to be narrowed. */
12277 if (sz == 2)
12278 storeLE( mkexpr(t1), unop(Iop_32to16,
12279 unop(Iop_64to32,mkexpr(t4))) );
12280 else
12281 storeLE( mkexpr(t1), mkexpr(t4) );
12282
12283 DIP("pushf%c\n", nameISize(sz));
12284 break;
12285 }
12286
sewardjd20c8852005-01-20 20:04:07 +000012287//.. case 0x60: /* PUSHA */
12288//.. /* This is almost certainly wrong for sz==2. So ... */
12289//.. if (sz != 4) goto decode_failure;
12290//..
12291//.. /* This is the Right Way, in that the value to be pushed is
12292//.. established before %esp is changed, so that pusha
12293//.. correctly pushes the old %esp value. New value of %esp is
12294//.. pushed at start. */
12295//.. /* t0 is the %ESP value we're going to push. */
12296//.. t0 = newTemp(Ity_I32);
12297//.. assign( t0, getIReg(4, R_ESP) );
12298//..
12299//.. /* t5 will be the new %ESP value. */
12300//.. t5 = newTemp(Ity_I32);
12301//.. assign( t5, binop(Iop_Sub32, mkexpr(t0), mkU32(8*4)) );
12302//..
12303//.. /* Update guest state before prodding memory. */
12304//.. putIReg(4, R_ESP, mkexpr(t5));
12305//..
12306//.. /* Dump all the registers. */
12307//.. storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(28)), getIReg(4,R_EAX) );
12308//.. storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(24)), getIReg(4,R_ECX) );
12309//.. storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(20)), getIReg(4,R_EDX) );
12310//.. storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(16)), getIReg(4,R_EBX) );
12311//.. storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(12)), mkexpr(t0) /*esp*/);
12312//.. storeLE( binop(Iop_Add32,mkexpr(t5),mkU32( 8)), getIReg(4,R_EBP) );
12313//.. storeLE( binop(Iop_Add32,mkexpr(t5),mkU32( 4)), getIReg(4,R_ESI) );
12314//.. storeLE( binop(Iop_Add32,mkexpr(t5),mkU32( 0)), getIReg(4,R_EDI) );
12315//..
12316//.. DIP("pusha%c\n", nameISize(sz));
12317//.. break;
12318//..
12319//..
12320//.. //-- case 0x0E: /* PUSH %CS */
12321//.. //-- dis_push_segreg( cb, R_CS, sz ); break;
12322//.. //-- case 0x1E: /* PUSH %DS */
12323//.. //-- dis_push_segreg( cb, R_DS, sz ); break;
12324//.. //-- case 0x06: /* PUSH %ES */
12325//.. //-- dis_push_segreg( cb, R_ES, sz ); break;
12326//.. //-- case 0x16: /* PUSH %SS */
12327//.. //-- dis_push_segreg( cb, R_SS, sz ); break;
12328//..
12329//.. /* ------------------------ SCAS et al ----------------- */
12330//..
12331//.. case 0xA4: /* MOVS, no REP prefix */
12332//.. case 0xA5:
12333//.. dis_string_op( dis_MOVS, ( opc == 0xA4 ? 1 : sz ), "movs", sorb );
12334//.. break;
12335//..
12336//.. case 0xA6: /* CMPSb, no REP prefix */
12337//.. //-- case 0xA7:
12338//.. dis_string_op( dis_CMPS, ( opc == 0xA6 ? 1 : sz ), "cmps", sorb );
12339//.. break;
12340//.. //--
sewardjd20c8852005-01-20 20:04:07 +000012341//.. //--
12342//.. //-- case 0xAC: /* LODS, no REP prefix */
12343//.. //-- case 0xAD:
12344//.. //-- dis_string_op( cb, dis_LODS, ( opc == 0xAC ? 1 : sz ), "lods", sorb );
12345//.. //-- break;
12346//..
12347//.. case 0xAE: /* SCAS, no REP prefix */
12348//.. case 0xAF:
12349//.. dis_string_op( dis_SCAS, ( opc == 0xAE ? 1 : sz ), "scas", sorb );
12350//.. break;
sewardjd0a12df2005-02-10 02:07:43 +000012351
12352
12353 case 0xFC: /* CLD */
sewardj5b470602005-02-27 13:10:48 +000012354 if (haveF2orF3(pfx)) goto decode_failure;
sewardjd0a12df2005-02-10 02:07:43 +000012355 stmt( IRStmt_Put( OFFB_DFLAG, mkU64(1)) );
12356 DIP("cld\n");
12357 break;
12358
sewardj909c06d2005-02-19 22:47:41 +000012359 case 0xFD: /* STD */
sewardj5b470602005-02-27 13:10:48 +000012360 if (haveF2orF3(pfx)) goto decode_failure;
sewardj909c06d2005-02-19 22:47:41 +000012361 stmt( IRStmt_Put( OFFB_DFLAG, mkU64(-1ULL)) );
12362 DIP("std\n");
12363 break;
12364
sewardjd20c8852005-01-20 20:04:07 +000012365//.. //-- case 0xF8: /* CLC */
12366//.. //-- uInstr0(cb, CALLM_S, 0);
12367//.. //-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_CLC));
12368//.. //-- uFlagsRWU(cb, FlagsEmpty, FlagC, FlagsOSZAP);
12369//.. //-- uInstr0(cb, CALLM_E, 0);
12370//.. //-- DIP("clc\n");
12371//.. //-- break;
12372//.. //--
12373//.. //-- case 0xF9: /* STC */
12374//.. //-- uInstr0(cb, CALLM_S, 0);
12375//.. //-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_STC));
12376//.. //-- uFlagsRWU(cb, FlagsEmpty, FlagC, FlagsOSZAP);
12377//.. //-- uInstr0(cb, CALLM_E, 0);
12378//.. //-- DIP("stc\n");
12379//.. //-- break;
12380//.. //--
12381//.. //-- case 0xF5: /* CMC */
12382//.. //-- uInstr0(cb, CALLM_S, 0);
12383//.. //-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_CMC));
12384//.. //-- uFlagsRWU(cb, FlagC, FlagC, FlagsOSZAP);
12385//.. //-- uInstr0(cb, CALLM_E, 0);
12386//.. //-- DIP("cmc\n");
12387//.. //-- break;
12388//..
12389//.. /* REPNE prefix insn */
12390//.. case 0xF2: {
12391//.. Addr32 eip_orig = guest_eip_bbstart + delta - 1;
12392//.. vassert(sorb == 0);
sewardj8c332e22005-01-28 01:36:56 +000012393//.. abyte = getUChar(delta); delta++;
sewardjd20c8852005-01-20 20:04:07 +000012394//..
sewardj8c332e22005-01-28 01:36:56 +000012395//.. if (abyte == 0x66) { sz = 2; abyte = getUChar(delta); delta++; }
sewardjd20c8852005-01-20 20:04:07 +000012396//.. whatNext = Dis_StopHere;
12397//..
12398//.. switch (abyte) {
12399//.. /* According to the Intel manual, "repne movs" should never occur, but
12400//.. * in practice it has happened, so allow for it here... */
12401//.. case 0xA4: sz = 1; /* REPNE MOVS<sz> */
12402//.. goto decode_failure;
12403//.. //-- case 0xA5:
12404//.. // dis_REP_op ( CondNZ, dis_MOVS, sz, eip_orig,
12405//.. // guest_eip_bbstart+delta, "repne movs" );
12406//.. // break;
12407//.. //--
12408//.. //-- case 0xA6: sz = 1; /* REPNE CMPS<sz> */
12409//.. //-- case 0xA7:
12410//.. //-- dis_REP_op ( cb, CondNZ, dis_CMPS, sz, eip_orig, eip, "repne cmps" );
12411//.. //-- break;
12412//.. //--
12413//.. case 0xAE: sz = 1; /* REPNE SCAS<sz> */
12414//.. case 0xAF:
12415//.. dis_REP_op ( X86CondNZ, dis_SCAS, sz, eip_orig,
12416//.. guest_eip_bbstart+delta, "repne scas" );
12417//.. break;
12418//..
12419//.. default:
12420//.. goto decode_failure;
12421//.. }
12422//.. break;
12423//.. }
sewardjd0a12df2005-02-10 02:07:43 +000012424
sewardj909c06d2005-02-19 22:47:41 +000012425 /* ------ AE: SCAS variants ------ */
12426 case 0xAE:
12427 case 0xAF:
12428 /* F2 AE/AF: repne scasb/repne scas{w,l,q} */
sewardj85520e42005-02-19 15:22:38 +000012429 if (haveF2(pfx) && !haveF3(pfx)) {
12430 if (opc == 0xAE)
12431 sz = 1;
12432 dis_REP_op ( AMD64CondNZ, dis_SCAS, sz,
sewardj9e6491a2005-07-02 19:24:10 +000012433 guest_RIP_curr_instr,
12434 guest_RIP_bbstart+delta, "repne scas", pfx );
12435 dres.whatNext = Dis_StopHere;
sewardj85520e42005-02-19 15:22:38 +000012436 break;
12437 }
sewardj909c06d2005-02-19 22:47:41 +000012438 /* AE/AF: scasb/scas{w,l,q} */
12439 if (!haveF2(pfx) && !haveF3(pfx)) {
12440 if (opc == 0xAE)
12441 sz = 1;
12442 dis_string_op( dis_SCAS, sz, "scas", pfx );
12443 break;
12444 }
sewardj85520e42005-02-19 15:22:38 +000012445 goto decode_failure;
sewardjd0a12df2005-02-10 02:07:43 +000012446
sewardj909c06d2005-02-19 22:47:41 +000012447 /* ------ A6, A7: CMPS variants ------ */
12448 case 0xA6:
12449 case 0xA7:
12450 /* F3 A6/A7: repe cmps/rep cmps{w,l,q} */
sewardjd0a12df2005-02-10 02:07:43 +000012451 if (haveF3(pfx) && !haveF2(pfx)) {
12452 if (opc == 0xA6)
12453 sz = 1;
12454 dis_REP_op ( AMD64CondZ, dis_CMPS, sz,
sewardj9e6491a2005-07-02 19:24:10 +000012455 guest_RIP_curr_instr,
12456 guest_RIP_bbstart+delta, "repe cmps", pfx );
12457 dres.whatNext = Dis_StopHere;
sewardja6b93d12005-02-17 09:28:28 +000012458 break;
12459 }
12460 goto decode_failure;
12461
sewardj909c06d2005-02-19 22:47:41 +000012462 /* ------ AA, AB: STOS variants ------ */
12463 case 0xAA:
12464 case 0xAB:
12465 /* F3 AA/AB: rep stosb/rep stos{w,l,q} */
sewardja6b93d12005-02-17 09:28:28 +000012466 if (haveF3(pfx) && !haveF2(pfx)) {
sewardj909c06d2005-02-19 22:47:41 +000012467 if (opc == 0xAA)
12468 sz = 1;
sewardja6b93d12005-02-17 09:28:28 +000012469 dis_REP_op ( AMD64CondAlways, dis_STOS, sz,
sewardj9e6491a2005-07-02 19:24:10 +000012470 guest_RIP_curr_instr,
12471 guest_RIP_bbstart+delta, "rep stos", pfx );
12472 dres.whatNext = Dis_StopHere;
sewardj909c06d2005-02-19 22:47:41 +000012473 break;
12474 }
12475 /* AA/AB: stosb/stos{w,l,q} */
12476 if (!haveF3(pfx) && !haveF2(pfx)) {
12477 if (opc == 0xAA)
12478 sz = 1;
12479 dis_string_op( dis_STOS, sz, "stos", pfx );
sewardjd0a12df2005-02-10 02:07:43 +000012480 break;
12481 }
12482 goto decode_failure;
12483
sewardj909c06d2005-02-19 22:47:41 +000012484 /* ------ A4, A5: MOVS variants ------ */
12485 case 0xA4:
12486 case 0xA5:
12487 /* F3 A4: rep movsb */
12488 if (haveF3(pfx) && !haveF2(pfx)) {
12489 if (opc == 0xA4)
12490 sz = 1;
12491 dis_REP_op ( AMD64CondAlways, dis_MOVS, sz,
sewardj9e6491a2005-07-02 19:24:10 +000012492 guest_RIP_curr_instr,
12493 guest_RIP_bbstart+delta, "rep movs", pfx );
12494 dres.whatNext = Dis_StopHere;
sewardj909c06d2005-02-19 22:47:41 +000012495 break;
12496 }
12497 /* A4: movsb */
12498 if (!haveF3(pfx) && !haveF2(pfx)) {
12499 if (opc == 0xA4)
12500 sz = 1;
12501 dis_string_op( dis_MOVS, sz, "movs", pfx );
12502 break;
12503 }
12504 goto decode_failure;
12505
sewardj7de0d3c2005-02-13 02:26:41 +000012506
12507 /* ------------------------ XCHG ----------------------- */
12508
sewardj1bf95982005-05-18 12:04:04 +000012509 case 0x86: /* XCHG Gb,Eb */
12510 sz = 1;
12511 /* Fall through ... */
sewardj7de0d3c2005-02-13 02:26:41 +000012512 case 0x87: /* XCHG Gv,Ev */
sewardj5b470602005-02-27 13:10:48 +000012513 if (haveF2orF3(pfx)) goto decode_failure;
sewardj7de0d3c2005-02-13 02:26:41 +000012514 modrm = getUChar(delta);
12515 ty = szToITy(sz);
12516 t1 = newTemp(ty); t2 = newTemp(ty);
12517 if (epartIsReg(modrm)) {
sewardj5b470602005-02-27 13:10:48 +000012518 assign(t1, getIRegE(sz, pfx, modrm));
12519 assign(t2, getIRegG(sz, pfx, modrm));
12520 putIRegG(sz, pfx, modrm, mkexpr(t1));
12521 putIRegE(sz, pfx, modrm, mkexpr(t2));
sewardj7de0d3c2005-02-13 02:26:41 +000012522 delta++;
12523 DIP("xchg%c %s, %s\n",
sewardj5b470602005-02-27 13:10:48 +000012524 nameISize(sz), nameIRegG(sz, pfx, modrm),
12525 nameIRegE(sz, pfx, modrm));
sewardj7de0d3c2005-02-13 02:26:41 +000012526 } else {
sewardj7de0d3c2005-02-13 02:26:41 +000012527 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
sewardj5b470602005-02-27 13:10:48 +000012528 assign( t1, loadLE(ty, mkexpr(addr)) );
12529 assign( t2, getIRegG(sz, pfx, modrm) );
sewardj7de0d3c2005-02-13 02:26:41 +000012530 storeLE( mkexpr(addr), mkexpr(t2) );
sewardj5b470602005-02-27 13:10:48 +000012531 putIRegG( sz, pfx, modrm, mkexpr(t1) );
sewardj7de0d3c2005-02-13 02:26:41 +000012532 delta += alen;
12533 DIP("xchg%c %s, %s\n", nameISize(sz),
sewardj5b470602005-02-27 13:10:48 +000012534 nameIRegG(sz, pfx, modrm), dis_buf);
sewardj7de0d3c2005-02-13 02:26:41 +000012535 }
12536 break;
sewardj118b23e2005-01-29 02:14:44 +000012537
12538 case 0x90: /* XCHG eAX,eAX */
sewardjc8b26352005-07-20 09:23:13 +000012539 /* detect and handle F3 90 (rep nop) specially */
12540 if (!have66(pfx) && !haveF2(pfx) && haveF3(pfx)) {
12541 DIP("rep nop (P4 pause)\n");
12542 /* "observe" the hint. The Vex client needs to be careful not
12543 to cause very long delays as a result, though. */
12544 jmp_lit(Ijk_Yield, guest_RIP_bbstart+delta);
12545 dres.whatNext = Dis_StopHere;
12546 break;
12547 }
sewardj2d4fcd52005-05-18 11:47:47 +000012548 /* detect and handle NOPs specially */
12549 if (/* F2/F3 probably change meaning completely */
12550 !haveF2orF3(pfx)
12551 /* If REX.B is 1, we're not exchanging rAX with itself */
12552 && getRexB(pfx)==0 ) {
12553 DIP("nop\n");
12554 break;
12555 }
12556 /* else fall through to normal case. */
sewardja6b93d12005-02-17 09:28:28 +000012557 case 0x91: /* XCHG rAX,rCX */
12558 case 0x92: /* XCHG rAX,rDX */
12559 case 0x93: /* XCHG rAX,rBX */
12560 case 0x94: /* XCHG rAX,rSP */
12561 case 0x95: /* XCHG rAX,rBP */
12562 case 0x96: /* XCHG rAX,rSI */
12563 case 0x97: /* XCHG rAX,rDI */
sewardj2d4fcd52005-05-18 11:47:47 +000012564
12565 /* guard against mutancy */
sewardja6b93d12005-02-17 09:28:28 +000012566 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2d4fcd52005-05-18 11:47:47 +000012567
12568 /* sz == 2 could legitimately happen, but we don't handle it yet */
12569 if (sz == 2) goto decode_failure; /* awaiting test case */
12570
sewardja6b93d12005-02-17 09:28:28 +000012571 codegen_xchg_rAX_Reg ( pfx, sz, opc - 0x90 );
12572 break;
12573
sewardjd20c8852005-01-20 20:04:07 +000012574//.. //-- /* ------------------------ XLAT ----------------------- */
12575//.. //--
12576//.. //-- case 0xD7: /* XLAT */
12577//.. //-- t1 = newTemp(cb); t2 = newTemp(cb);
12578//.. //-- uInstr2(cb, GET, sz, ArchReg, R_EBX, TempReg, t1); /* get eBX */
12579//.. //-- handleSegOverride( cb, sorb, t1 ); /* make t1 DS:eBX */
12580//.. //-- uInstr2(cb, GET, 1, ArchReg, R_AL, TempReg, t2); /* get AL */
12581//.. //-- /* Widen %AL to 32 bits, so it's all defined when we add it. */
12582//.. //-- uInstr1(cb, WIDEN, 4, TempReg, t2);
12583//.. //-- uWiden(cb, 1, False);
12584//.. //-- uInstr2(cb, ADD, sz, TempReg, t2, TempReg, t1); /* add AL to eBX */
12585//.. //-- uInstr2(cb, LOAD, 1, TempReg, t1, TempReg, t2); /* get byte at t1 into t2 */
12586//.. //-- uInstr2(cb, PUT, 1, TempReg, t2, ArchReg, R_AL); /* put byte into AL */
12587//.. //--
12588//.. //-- DIP("xlat%c [ebx]\n", nameISize(sz));
12589//.. //-- break;
12590//.. //--
12591//.. //-- /* ------------------------ IN / OUT ----------------------- */
12592//.. //--
12593//.. //-- case 0xE4: /* IN ib, %al */
12594//.. //-- case 0xE5: /* IN ib, %{e}ax */
12595//.. //-- case 0xEC: /* IN (%dx),%al */
12596//.. //-- case 0xED: /* IN (%dx),%{e}ax */
12597//.. //-- t1 = newTemp(cb);
12598//.. //-- t2 = newTemp(cb);
12599//.. //-- t3 = newTemp(cb);
12600//.. //--
12601//.. //-- uInstr0(cb, CALLM_S, 0);
12602//.. //-- /* operand size? */
12603//.. //-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t1);
12604//.. //-- uLiteral(cb, ( opc == 0xE4 || opc == 0xEC ) ? 1 : sz);
12605//.. //-- uInstr1(cb, PUSH, 4, TempReg, t1);
12606//.. //-- /* port number ? */
12607//.. //-- if ( opc == 0xE4 || opc == 0xE5 ) {
12608//.. //-- abyte = getUChar(eip); eip++;
12609//.. //-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
12610//.. //-- uLiteral(cb, abyte);
12611//.. //-- }
12612//.. //-- else
12613//.. //-- uInstr2(cb, GET, 4, ArchReg, R_EDX, TempReg, t2);
12614//.. //--
12615//.. //-- uInstr1(cb, PUSH, 4, TempReg, t2);
12616//.. //-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_IN));
12617//.. //-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
12618//.. //-- uInstr1(cb, POP, 4, TempReg, t2);
12619//.. //-- uInstr1(cb, CLEAR, 0, Lit16, 4);
12620//.. //-- uInstr0(cb, CALLM_E, 0);
12621//.. //-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_EAX);
12622//.. //-- if ( opc == 0xE4 || opc == 0xE5 ) {
12623//.. //-- DIP("in 0x%x, %%eax/%%ax/%%al\n", getUChar(eip-1) );
12624//.. //-- } else {
12625//.. //-- DIP("in (%%dx), %%eax/%%ax/%%al\n");
12626//.. //-- }
12627//.. //-- break;
12628//.. //-- case 0xE6: /* OUT %al,ib */
12629//.. //-- case 0xE7: /* OUT %{e}ax,ib */
12630//.. //-- case 0xEE: /* OUT %al,(%dx) */
12631//.. //-- case 0xEF: /* OUT %{e}ax,(%dx) */
12632//.. //-- t1 = newTemp(cb);
12633//.. //-- t2 = newTemp(cb);
12634//.. //-- t3 = newTemp(cb);
12635//.. //--
12636//.. //-- uInstr0(cb, CALLM_S, 0);
12637//.. //-- /* operand size? */
12638//.. //-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t1);
12639//.. //-- uLiteral(cb, ( opc == 0xE6 || opc == 0xEE ) ? 1 : sz);
12640//.. //-- uInstr1(cb, PUSH, 4, TempReg, t1);
12641//.. //-- /* port number ? */
12642//.. //-- if ( opc == 0xE6 || opc == 0xE7 ) {
12643//.. //-- abyte = getUChar(eip); eip++;
12644//.. //-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
12645//.. //-- uLiteral(cb, abyte);
12646//.. //-- }
12647//.. //-- else
12648//.. //-- uInstr2(cb, GET, 4, ArchReg, R_EDX, TempReg, t2);
12649//.. //-- uInstr1(cb, PUSH, 4, TempReg, t2);
12650//.. //-- uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, t3);
12651//.. //-- uInstr1(cb, PUSH, 4, TempReg, t3);
12652//.. //-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_OUT));
12653//.. //-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
12654//.. //-- uInstr1(cb, CLEAR, 0, Lit16, 12);
12655//.. //-- uInstr0(cb, CALLM_E, 0);
12656//.. //-- if ( opc == 0xE4 || opc == 0xE5 ) {
12657//.. //-- DIP("out %%eax/%%ax/%%al, 0x%x\n", getUChar(eip-1) );
12658//.. //-- } else {
12659//.. //-- DIP("out %%eax/%%ax/%%al, (%%dx)\n");
12660//.. //-- }
12661//.. //-- break;
sewardj3ca55a12005-01-27 16:06:23 +000012662
12663 /* ------------------------ (Grp1 extensions) ---------- */
12664
12665 case 0x80: /* Grp1 Ib,Eb */
sewardj5b470602005-02-27 13:10:48 +000012666 if (haveF2orF3(pfx)) goto decode_failure;
sewardj8c332e22005-01-28 01:36:56 +000012667 modrm = getUChar(delta);
sewardj3ca55a12005-01-27 16:06:23 +000012668 am_sz = lengthAMode(pfx,delta);
12669 sz = 1;
12670 d_sz = 1;
12671 d64 = getSDisp8(delta + am_sz);
12672 delta = dis_Grp1 ( pfx, delta, modrm, am_sz, d_sz, sz, d64 );
12673 break;
12674
12675 case 0x81: /* Grp1 Iv,Ev */
12676 if (haveF2orF3(pfx)) goto decode_failure;
sewardj8c332e22005-01-28 01:36:56 +000012677 modrm = getUChar(delta);
sewardj3ca55a12005-01-27 16:06:23 +000012678 am_sz = lengthAMode(pfx,delta);
12679 d_sz = imin(sz,4);
12680 d64 = getSDisp(d_sz, delta + am_sz);
12681 delta = dis_Grp1 ( pfx, delta, modrm, am_sz, d_sz, sz, d64 );
12682 break;
12683
12684 case 0x83: /* Grp1 Ib,Ev */
12685 if (haveF2orF3(pfx)) goto decode_failure;
sewardj8c332e22005-01-28 01:36:56 +000012686 modrm = getUChar(delta);
sewardj3ca55a12005-01-27 16:06:23 +000012687 am_sz = lengthAMode(pfx,delta);
12688 d_sz = 1;
12689 d64 = getSDisp8(delta + am_sz);
12690 delta = dis_Grp1 ( pfx, delta, modrm, am_sz, d_sz, sz, d64 );
12691 break;
12692
sewardj118b23e2005-01-29 02:14:44 +000012693 /* ------------------------ (Grp2 extensions) ---------- */
sewardj03b07cc2005-01-31 18:09:43 +000012694
sewardj118b23e2005-01-29 02:14:44 +000012695 case 0xC0: /* Grp2 Ib,Eb */
sewardj5b470602005-02-27 13:10:48 +000012696 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000012697 modrm = getUChar(delta);
12698 am_sz = lengthAMode(pfx,delta);
12699 d_sz = 1;
12700 d64 = getUChar(delta + am_sz);
12701 sz = 1;
12702 delta = dis_Grp2 ( pfx, delta, modrm, am_sz, d_sz, sz,
12703 mkU8(d64 & 0xFF), NULL );
12704 break;
sewardj03b07cc2005-01-31 18:09:43 +000012705
sewardj118b23e2005-01-29 02:14:44 +000012706 case 0xC1: /* Grp2 Ib,Ev */
sewardj5b470602005-02-27 13:10:48 +000012707 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000012708 modrm = getUChar(delta);
12709 am_sz = lengthAMode(pfx,delta);
12710 d_sz = 1;
12711 d64 = getUChar(delta + am_sz);
12712 delta = dis_Grp2 ( pfx, delta, modrm, am_sz, d_sz, sz,
12713 mkU8(d64 & 0xFF), NULL );
12714 break;
12715
sewardj03b07cc2005-01-31 18:09:43 +000012716 case 0xD0: /* Grp2 1,Eb */
sewardj5b470602005-02-27 13:10:48 +000012717 if (haveF2orF3(pfx)) goto decode_failure;
sewardj03b07cc2005-01-31 18:09:43 +000012718 modrm = getUChar(delta);
12719 am_sz = lengthAMode(pfx,delta);
12720 d_sz = 0;
12721 d64 = 1;
12722 sz = 1;
12723 delta = dis_Grp2 ( pfx, delta, modrm, am_sz, d_sz, sz,
12724 mkU8(d64), NULL );
12725 break;
sewardj118b23e2005-01-29 02:14:44 +000012726
12727 case 0xD1: /* Grp2 1,Ev */
sewardj5b470602005-02-27 13:10:48 +000012728 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000012729 modrm = getUChar(delta);
12730 am_sz = lengthAMode(pfx,delta);
12731 d_sz = 0;
12732 d64 = 1;
12733 delta = dis_Grp2 ( pfx, delta, modrm, am_sz, d_sz, sz,
12734 mkU8(d64), NULL );
12735 break;
12736
sewardj85520e42005-02-19 15:22:38 +000012737 case 0xD2: /* Grp2 CL,Eb */
sewardj5b470602005-02-27 13:10:48 +000012738 if (haveF2orF3(pfx)) goto decode_failure;
sewardj85520e42005-02-19 15:22:38 +000012739 modrm = getUChar(delta);
12740 am_sz = lengthAMode(pfx,delta);
12741 d_sz = 0;
12742 sz = 1;
12743 delta = dis_Grp2 ( pfx, delta, modrm, am_sz, d_sz, sz,
sewardj5b470602005-02-27 13:10:48 +000012744 getIRegCL(), "%cl" );
sewardj85520e42005-02-19 15:22:38 +000012745 break;
sewardj118b23e2005-01-29 02:14:44 +000012746
12747 case 0xD3: /* Grp2 CL,Ev */
sewardj5b470602005-02-27 13:10:48 +000012748 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000012749 modrm = getUChar(delta);
12750 am_sz = lengthAMode(pfx,delta);
12751 d_sz = 0;
12752 delta = dis_Grp2 ( pfx, delta, modrm, am_sz, d_sz, sz,
sewardj5b470602005-02-27 13:10:48 +000012753 getIRegCL(), "%cl" );
sewardj118b23e2005-01-29 02:14:44 +000012754 break;
sewardj32b2bbe2005-01-28 00:50:10 +000012755
12756 /* ------------------------ (Grp3 extensions) ---------- */
12757
sewardj118b23e2005-01-29 02:14:44 +000012758 case 0xF6: /* Grp3 Eb */
sewardj5b470602005-02-27 13:10:48 +000012759 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000012760 delta = dis_Grp3 ( pfx, 1, delta );
12761 break;
sewardj32b2bbe2005-01-28 00:50:10 +000012762 case 0xF7: /* Grp3 Ev */
sewardj5b470602005-02-27 13:10:48 +000012763 if (haveF2orF3(pfx)) goto decode_failure;
sewardj32b2bbe2005-01-28 00:50:10 +000012764 delta = dis_Grp3 ( pfx, sz, delta );
12765 break;
12766
sewardj03b07cc2005-01-31 18:09:43 +000012767 /* ------------------------ (Grp4 extensions) ---------- */
12768
12769 case 0xFE: /* Grp4 Eb */
sewardj5b470602005-02-27 13:10:48 +000012770 if (haveF2orF3(pfx)) goto decode_failure;
sewardj03b07cc2005-01-31 18:09:43 +000012771 delta = dis_Grp4 ( pfx, delta );
12772 break;
sewardj354e5c62005-01-27 20:12:52 +000012773
12774 /* ------------------------ (Grp5 extensions) ---------- */
12775
12776 case 0xFF: /* Grp5 Ev */
sewardj5b470602005-02-27 13:10:48 +000012777 if (haveF2orF3(pfx)) goto decode_failure;
sewardj9e6491a2005-07-02 19:24:10 +000012778 delta = dis_Grp5 ( pfx, sz, delta, &dres );
sewardj354e5c62005-01-27 20:12:52 +000012779 break;
sewardj3ca55a12005-01-27 16:06:23 +000012780
12781 /* ------------------------ Escapes to 2-byte opcodes -- */
12782
12783 case 0x0F: {
sewardj8c332e22005-01-28 01:36:56 +000012784 opc = getUChar(delta); delta++;
sewardj3ca55a12005-01-27 16:06:23 +000012785 switch (opc) {
12786
sewardj1d511802005-03-27 17:59:45 +000012787 /* =-=-=-=-=-=-=-=-=- Grp8 =-=-=-=-=-=-=-=-=-=-=-= */
12788
12789 case 0xBA: { /* Grp8 Ib,Ev */
12790 Bool decode_OK = False;
12791 if (haveF2orF3(pfx)) goto decode_failure;
12792 modrm = getUChar(delta);
12793 am_sz = lengthAMode(pfx,delta);
12794 d64 = getSDisp8(delta + am_sz);
12795 delta = dis_Grp8_Imm ( pfx, delta, modrm, am_sz, sz, d64,
12796 &decode_OK );
12797 if (!decode_OK)
12798 goto decode_failure;
12799 break;
12800 }
12801
sewardjf53b7352005-04-06 20:01:56 +000012802 /* =-=-=-=-=-=-=-=-=- BSF/BSR -=-=-=-=-=-=-=-=-=-= */
12803
12804 case 0xBC: /* BSF Gv,Ev */
12805 if (haveF2orF3(pfx)) goto decode_failure;
12806 delta = dis_bs_E_G ( pfx, sz, delta, True );
12807 break;
sewardj537cab02005-04-07 02:03:52 +000012808 case 0xBD: /* BSR Gv,Ev */
12809 if (haveF2orF3(pfx)) goto decode_failure;
12810 delta = dis_bs_E_G ( pfx, sz, delta, False );
12811 break;
sewardj82c9f2f2005-03-02 16:05:13 +000012812
12813 /* =-=-=-=-=-=-=-=-=- BSWAP -=-=-=-=-=-=-=-=-=-=-= */
12814
12815 case 0xC8: /* BSWAP %eax */
12816 case 0xC9:
12817 case 0xCA:
12818 case 0xCB:
12819 case 0xCC:
12820 case 0xCD:
12821 case 0xCE:
12822 case 0xCF: /* BSWAP %edi */
12823 if (haveF2orF3(pfx)) goto decode_failure;
12824 /* According to the AMD64 docs, this insn can have size 4 or
12825 8. */
12826 if (sz == 4) {
12827 t1 = newTemp(Ity_I32);
12828 t2 = newTemp(Ity_I32);
12829 assign( t1, getIRegRexB(4, pfx, opc-0xC8) );
12830 assign( t2,
12831 binop(Iop_Or32,
12832 binop(Iop_Shl32, mkexpr(t1), mkU8(24)),
12833 binop(Iop_Or32,
12834 binop(Iop_And32, binop(Iop_Shl32, mkexpr(t1), mkU8(8)),
12835 mkU32(0x00FF0000)),
12836 binop(Iop_Or32,
12837 binop(Iop_And32, binop(Iop_Shr32, mkexpr(t1), mkU8(8)),
12838 mkU32(0x0000FF00)),
12839 binop(Iop_And32, binop(Iop_Shr32, mkexpr(t1), mkU8(24)),
12840 mkU32(0x000000FF) )
12841 )))
12842 );
12843 putIRegRexB(4, pfx, opc-0xC8, mkexpr(t2));
12844 DIP("bswapl %s\n", nameIRegRexB(4, pfx, opc-0xC8));
12845 break;
sewardj98e9f342005-07-23 12:07:37 +000012846 }
12847 else if (sz == 8) {
12848 t1 = newTemp(Ity_I64);
12849 t2 = newTemp(Ity_I64);
12850 assign( t1, getIRegRexB(8, pfx, opc-0xC8) );
12851
12852# define LANE(_nn) \
12853 binop( Iop_Shl64, \
12854 binop( Iop_And64, \
12855 binop(Iop_Shr64, mkexpr(t1), \
12856 mkU8(8 * (7 - (_nn)))), \
12857 mkU64(0xFF)), \
12858 mkU8(8 * (_nn)))
12859
12860 assign(
12861 t2,
12862 binop(Iop_Or64,
12863 binop(Iop_Or64,
12864 binop(Iop_Or64,LANE(0),LANE(1)),
12865 binop(Iop_Or64,LANE(2),LANE(3))
12866 ),
12867 binop(Iop_Or64,
12868 binop(Iop_Or64,LANE(4),LANE(5)),
12869 binop(Iop_Or64,LANE(6),LANE(7))
12870 )
12871 )
12872 );
12873
12874# undef LANE
12875
12876 putIRegRexB(8, pfx, opc-0xC8, mkexpr(t2));
12877 DIP("bswapq %s\n", nameIRegRexB(8, pfx, opc-0xC8));
12878 break;
sewardj82c9f2f2005-03-02 16:05:13 +000012879 } else {
12880 goto decode_failure;
12881 }
12882
sewardjd20c8852005-01-20 20:04:07 +000012883//.. /* =-=-=-=-=-=-=-=-=- BT/BTS/BTR/BTC =-=-=-=-=-=-= */
12884//..
12885//.. case 0xA3: /* BT Gv,Ev */
12886//.. delta = dis_bt_G_E ( sorb, sz, delta, BtOpNone );
12887//.. break;
12888//.. case 0xB3: /* BTR Gv,Ev */
12889//.. delta = dis_bt_G_E ( sorb, sz, delta, BtOpReset );
12890//.. break;
12891//.. case 0xAB: /* BTS Gv,Ev */
12892//.. delta = dis_bt_G_E ( sorb, sz, delta, BtOpSet );
12893//.. break;
12894//.. case 0xBB: /* BTC Gv,Ev */
12895//.. delta = dis_bt_G_E ( sorb, sz, delta, BtOpComp );
12896//.. break;
sewardj3ca55a12005-01-27 16:06:23 +000012897
12898 /* =-=-=-=-=-=-=-=-=- CMOV =-=-=-=-=-=-=-=-=-=-=-= */
12899
12900 case 0x40:
12901 case 0x41:
12902 case 0x42: /* CMOVBb/CMOVNAEb (cmov below) */
12903 case 0x43: /* CMOVNBb/CMOVAEb (cmov not below) */
12904 case 0x44: /* CMOVZb/CMOVEb (cmov zero) */
12905 case 0x45: /* CMOVNZb/CMOVNEb (cmov not zero) */
12906 case 0x46: /* CMOVBEb/CMOVNAb (cmov below or equal) */
12907 case 0x47: /* CMOVNBEb/CMOVAb (cmov not below or equal) */
12908 case 0x48: /* CMOVSb (cmov negative) */
12909 case 0x49: /* CMOVSb (cmov not negative) */
12910 case 0x4A: /* CMOVP (cmov parity even) */
12911 case 0x4B: /* CMOVNP (cmov parity odd) */
12912 case 0x4C: /* CMOVLb/CMOVNGEb (cmov less) */
12913 case 0x4D: /* CMOVGEb/CMOVNLb (cmov greater or equal) */
12914 case 0x4E: /* CMOVLEb/CMOVNGb (cmov less or equal) */
12915 case 0x4F: /* CMOVGb/CMOVNLEb (cmov greater) */
sewardj5b470602005-02-27 13:10:48 +000012916 if (haveF2orF3(pfx)) goto decode_failure;
sewardj3ca55a12005-01-27 16:06:23 +000012917 delta = dis_cmov_E_G(pfx, sz, (AMD64Condcode)(opc - 0x40), delta);
12918 break;
12919
sewardja6b93d12005-02-17 09:28:28 +000012920 /* =-=-=-=-=-=-=-=-=- CMPXCHG -=-=-=-=-=-=-=-=-=-= */
12921
sewardjd20c8852005-01-20 20:04:07 +000012922//.. case 0xB0: /* CMPXCHG Gb,Eb */
12923//.. delta = dis_cmpxchg_G_E ( sorb, 1, delta );
12924//.. break;
sewardja6b93d12005-02-17 09:28:28 +000012925 case 0xB1: /* CMPXCHG Gv,Ev */
sewardj5b470602005-02-27 13:10:48 +000012926 if (haveF2orF3(pfx)) goto decode_failure;
sewardja6b93d12005-02-17 09:28:28 +000012927 delta = dis_cmpxchg_G_E ( pfx, sz, delta );
12928 break;
sewardjd20c8852005-01-20 20:04:07 +000012929//.. //-- case 0xC7: /* CMPXCHG8B Gv */
12930//.. //-- eip = dis_cmpxchg8b ( cb, sorb, eip );
12931//.. //-- break;
12932//.. //--
sewardjd0a12df2005-02-10 02:07:43 +000012933 /* =-=-=-=-=-=-=-=-=- CPUID -=-=-=-=-=-=-=-=-=-=-= */
12934
12935 case 0xA2: { /* CPUID */
12936 /* Uses dirty helper:
12937 void amd64g_dirtyhelper_CPUID ( VexGuestAMD64State* )
12938 declared to mod rax, wr rbx, rcx, rdx
12939 */
12940 IRDirty* d = NULL;
12941 HChar* fName = NULL;
12942 void* fAddr = NULL;
sewardj5b470602005-02-27 13:10:48 +000012943 if (haveF2orF3(pfx)) goto decode_failure;
sewardj27e1dd62005-06-30 11:49:14 +000012944 switch (archinfo->subarch) {
sewardjd0a12df2005-02-10 02:07:43 +000012945 case VexSubArch_NONE:
12946 fName = "amd64g_dirtyhelper_CPUID";
12947 fAddr = &amd64g_dirtyhelper_CPUID;
12948 break;
12949 default:
12950 vpanic("disInstr(amd64)(cpuid)");
12951 }
12952 vassert(fName); vassert(fAddr);
12953 d = unsafeIRDirty_0_N ( 0/*regparms*/,
12954 fName, fAddr, mkIRExprVec_0() );
12955 /* declare guest state effects */
12956 d->needsBBP = True;
12957 d->nFxState = 4;
12958 d->fxState[0].fx = Ifx_Modify;
12959 d->fxState[0].offset = OFFB_RAX;
12960 d->fxState[0].size = 8;
12961 d->fxState[1].fx = Ifx_Write;
12962 d->fxState[1].offset = OFFB_RBX;
12963 d->fxState[1].size = 8;
12964 d->fxState[2].fx = Ifx_Write;
12965 d->fxState[2].offset = OFFB_RCX;
12966 d->fxState[2].size = 8;
12967 d->fxState[3].fx = Ifx_Write;
12968 d->fxState[3].offset = OFFB_RDX;
12969 d->fxState[3].size = 8;
12970 /* execute the dirty call, side-effecting guest state */
12971 stmt( IRStmt_Dirty(d) );
12972 /* CPUID is a serialising insn. So, just in case someone is
12973 using it as a memory fence ... */
12974 stmt( IRStmt_MFence() );
12975 DIP("cpuid\n");
12976 break;
12977 }
12978
sewardj5e525292005-01-28 15:13:10 +000012979 /* =-=-=-=-=-=-=-=-=- MOVZX, MOVSX =-=-=-=-=-=-=-= */
12980
12981 case 0xB6: /* MOVZXb Eb,Gv */
sewardj5b470602005-02-27 13:10:48 +000012982 if (haveF2orF3(pfx)) goto decode_failure;
sewardj5e525292005-01-28 15:13:10 +000012983 if (sz != 2 && sz != 4 && sz != 8)
12984 goto decode_failure;
12985 delta = dis_movx_E_G ( pfx, delta, 1, sz, False );
12986 break;
12987 case 0xB7: /* MOVZXw Ew,Gv */
sewardj5b470602005-02-27 13:10:48 +000012988 if (haveF2orF3(pfx)) goto decode_failure;
sewardj5e525292005-01-28 15:13:10 +000012989 if (sz != 4 && sz != 8)
12990 goto decode_failure;
12991 delta = dis_movx_E_G ( pfx, delta, 2, sz, False );
12992 break;
12993
sewardj03b07cc2005-01-31 18:09:43 +000012994 case 0xBE: /* MOVSXb Eb,Gv */
sewardj5b470602005-02-27 13:10:48 +000012995 if (haveF2orF3(pfx)) goto decode_failure;
sewardj82c9f2f2005-03-02 16:05:13 +000012996 if (sz != 2 && sz != 4 && sz != 8)
sewardj03b07cc2005-01-31 18:09:43 +000012997 goto decode_failure;
12998 delta = dis_movx_E_G ( pfx, delta, 1, sz, True );
12999 break;
13000 case 0xBF: /* MOVSXw Ew,Gv */
sewardj5b470602005-02-27 13:10:48 +000013001 if (haveF2orF3(pfx)) goto decode_failure;
sewardj03b07cc2005-01-31 18:09:43 +000013002 if (sz != 4 && sz != 8)
13003 goto decode_failure;
13004 delta = dis_movx_E_G ( pfx, delta, 2, sz, True );
13005 break;
13006
sewardjd20c8852005-01-20 20:04:07 +000013007//.. //-- /* =-=-=-=-=-=-=-=-=-=-= MOVNTI -=-=-=-=-=-=-=-=-= */
13008//.. //--
13009//.. //-- case 0xC3: /* MOVNTI Gv,Ev */
13010//.. //-- vg_assert(sz == 4);
13011//.. //-- modrm = getUChar(eip);
13012//.. //-- vg_assert(!epartIsReg(modrm));
13013//.. //-- t1 = newTemp(cb);
13014//.. //-- uInstr2(cb, GET, 4, ArchReg, gregOfRM(modrm), TempReg, t1);
13015//.. //-- pair = disAMode ( cb, sorb, eip, dis_buf );
13016//.. //-- t2 = LOW24(pair);
13017//.. //-- eip += HI8(pair);
13018//.. //-- uInstr2(cb, STORE, 4, TempReg, t1, TempReg, t2);
13019//.. //-- DIP("movnti %s,%s\n", nameIReg(4,gregOfRM(modrm)), dis_buf);
13020//.. //-- break;
sewardj32b2bbe2005-01-28 00:50:10 +000013021
13022 /* =-=-=-=-=-=-=-=-=- MUL/IMUL =-=-=-=-=-=-=-=-=-= */
13023
13024 case 0xAF: /* IMUL Ev, Gv */
sewardj5b470602005-02-27 13:10:48 +000013025 if (haveF2orF3(pfx)) goto decode_failure;
sewardj32b2bbe2005-01-28 00:50:10 +000013026 delta = dis_mul_E_G ( pfx, sz, delta );
13027 break;
13028
sewardj1389d4d2005-01-28 13:46:29 +000013029 /* =-=-=-=-=-=-=-=-=- Jcond d32 -=-=-=-=-=-=-=-=-= */
13030 case 0x80:
13031 case 0x81:
13032 case 0x82: /* JBb/JNAEb (jump below) */
13033 case 0x83: /* JNBb/JAEb (jump not below) */
13034 case 0x84: /* JZb/JEb (jump zero) */
13035 case 0x85: /* JNZb/JNEb (jump not zero) */
13036 case 0x86: /* JBEb/JNAb (jump below or equal) */
13037 case 0x87: /* JNBEb/JAb (jump not below or equal) */
13038 case 0x88: /* JSb (jump negative) */
13039 case 0x89: /* JSb (jump not negative) */
13040 case 0x8A: /* JP (jump parity even) */
13041 case 0x8B: /* JNP/JPO (jump parity odd) */
13042 case 0x8C: /* JLb/JNGEb (jump less) */
13043 case 0x8D: /* JGEb/JNLb (jump greater or equal) */
13044 case 0x8E: /* JLEb/JNGb (jump less or equal) */
13045 case 0x8F: /* JGb/JNLEb (jump greater) */
sewardj5b470602005-02-27 13:10:48 +000013046 if (haveF2orF3(pfx)) goto decode_failure;
sewardj9e6491a2005-07-02 19:24:10 +000013047 d64 = (guest_RIP_bbstart+delta+4) + getSDisp32(delta);
sewardj1389d4d2005-01-28 13:46:29 +000013048 delta += 4;
13049 jcc_01( (AMD64Condcode)(opc - 0x80),
sewardj9e6491a2005-07-02 19:24:10 +000013050 guest_RIP_bbstart+delta,
sewardj1389d4d2005-01-28 13:46:29 +000013051 d64 );
sewardj9e6491a2005-07-02 19:24:10 +000013052 dres.whatNext = Dis_StopHere;
sewardj1389d4d2005-01-28 13:46:29 +000013053 DIP("j%s-32 0x%llx\n", name_AMD64Condcode(opc - 0x80), d64);
13054 break;
13055
sewardj31191072005-02-05 18:24:47 +000013056 /* =-=-=-=-=-=-=-=-=- RDTSC -=-=-=-=-=-=-=-=-=-=-= */
13057
13058 case 0x31: /* RDTSC */
sewardj5b470602005-02-27 13:10:48 +000013059 if (haveF2orF3(pfx)) goto decode_failure;
sewardjc5f92972005-03-24 20:39:05 +000013060 if (0) vex_printf("vex amd64->IR: kludged rdtsc\n");
sewardj007e9ec2005-03-23 11:36:48 +000013061 putIRegRAX(4, mkU32(1));
sewardj5b470602005-02-27 13:10:48 +000013062 putIRegRDX(4, mkU32(0));
sewardj31191072005-02-05 18:24:47 +000013063
sewardjd20c8852005-01-20 20:04:07 +000013064//.. //-- t1 = newTemp(cb);
13065//.. //-- t2 = newTemp(cb);
13066//.. //-- t3 = newTemp(cb);
13067//.. //-- uInstr0(cb, CALLM_S, 0);
13068//.. //-- // Nb: even though these args aren't used by RDTSC_helper, need
13069//.. //-- // them to be defined (for Memcheck). The TempRegs pushed must
13070//.. //-- // also be distinct.
13071//.. //-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t1);
13072//.. //-- uLiteral(cb, 0);
13073//.. //-- uInstr1(cb, PUSH, 4, TempReg, t1);
13074//.. //-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
13075//.. //-- uLiteral(cb, 0);
13076//.. //-- uInstr1(cb, PUSH, 4, TempReg, t2);
13077//.. //-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_RDTSC));
13078//.. //-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
13079//.. //-- uInstr1(cb, POP, 4, TempReg, t3);
13080//.. //-- uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_EDX);
13081//.. //-- uInstr1(cb, POP, 4, TempReg, t3);
13082//.. //-- uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_EAX);
13083//.. //-- uInstr0(cb, CALLM_E, 0);
sewardj31191072005-02-05 18:24:47 +000013084 DIP("rdtsc\n");
13085 break;
13086
sewardjd20c8852005-01-20 20:04:07 +000013087//.. /* =-=-=-=-=-=-=-=-=- PUSH/POP Sreg =-=-=-=-=-=-=-=-=-= */
13088//..
13089//.. case 0xA1: /* POP %FS */
13090//.. dis_pop_segreg( R_FS, sz ); break;
13091//.. case 0xA9: /* POP %GS */
13092//.. dis_pop_segreg( R_GS, sz ); break;
13093//..
13094//.. case 0xA0: /* PUSH %FS */
13095//.. dis_push_segreg( R_FS, sz ); break;
13096//.. case 0xA8: /* PUSH %GS */
13097//.. dis_push_segreg( R_GS, sz ); break;
sewardj118b23e2005-01-29 02:14:44 +000013098
13099 /* =-=-=-=-=-=-=-=-=- SETcc Eb =-=-=-=-=-=-=-=-=-= */
13100 case 0x90:
13101 case 0x91:
13102 case 0x92: /* set-Bb/set-NAEb (set if below) */
13103 case 0x93: /* set-NBb/set-AEb (set if not below) */
13104 case 0x94: /* set-Zb/set-Eb (set if zero) */
13105 case 0x95: /* set-NZb/set-NEb (set if not zero) */
13106 case 0x96: /* set-BEb/set-NAb (set if below or equal) */
13107 case 0x97: /* set-NBEb/set-Ab (set if not below or equal) */
13108 case 0x98: /* set-Sb (set if negative) */
13109 case 0x99: /* set-Sb (set if not negative) */
13110 case 0x9A: /* set-P (set if parity even) */
13111 case 0x9B: /* set-NP (set if parity odd) */
13112 case 0x9C: /* set-Lb/set-NGEb (set if less) */
13113 case 0x9D: /* set-GEb/set-NLb (set if greater or equal) */
13114 case 0x9E: /* set-LEb/set-NGb (set if less or equal) */
13115 case 0x9F: /* set-Gb/set-NLEb (set if greater) */
sewardj5b470602005-02-27 13:10:48 +000013116 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000013117 t1 = newTemp(Ity_I8);
13118 assign( t1, unop(Iop_1Uto8,mk_amd64g_calculate_condition(opc-0x90)) );
13119 modrm = getUChar(delta);
13120 if (epartIsReg(modrm)) {
13121 delta++;
sewardj5b470602005-02-27 13:10:48 +000013122 putIRegE(1, pfx, modrm, mkexpr(t1));
sewardj118b23e2005-01-29 02:14:44 +000013123 DIP("set%s %s\n", name_AMD64Condcode(opc-0x90),
sewardj5b470602005-02-27 13:10:48 +000013124 nameIRegE(1,pfx,modrm));
sewardj118b23e2005-01-29 02:14:44 +000013125 } else {
sewardj5cc00ff2005-03-27 04:48:32 +000013126 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
13127 delta += alen;
13128 storeLE( mkexpr(addr), mkexpr(t1) );
13129 DIP("set%s %s\n", name_AMD64Condcode(opc-0x90), dis_buf);
sewardj118b23e2005-01-29 02:14:44 +000013130 }
13131 break;
13132
sewardjd20c8852005-01-20 20:04:07 +000013133//.. /* =-=-=-=-=-=-=-=-=- SHLD/SHRD -=-=-=-=-=-=-=-=-= */
13134//..
13135//.. case 0xA4: /* SHLDv imm8,Gv,Ev */
sewardj8c332e22005-01-28 01:36:56 +000013136//.. modrm = getUChar(delta);
sewardjd20c8852005-01-20 20:04:07 +000013137//.. d32 = delta + lengthAMode(delta);
13138//.. vex_sprintf(dis_buf, "$%d", delta);
13139//.. delta = dis_SHLRD_Gv_Ev (
13140//.. sorb, delta, modrm, sz,
sewardj8c332e22005-01-28 01:36:56 +000013141//.. mkU8(getUChar(d32)), True, /* literal */
sewardjd20c8852005-01-20 20:04:07 +000013142//.. dis_buf, True );
13143//.. break;
13144//.. case 0xA5: /* SHLDv %cl,Gv,Ev */
sewardj8c332e22005-01-28 01:36:56 +000013145//.. modrm = getUChar(delta);
sewardjd20c8852005-01-20 20:04:07 +000013146//.. delta = dis_SHLRD_Gv_Ev (
13147//.. sorb, delta, modrm, sz,
13148//.. getIReg(1,R_ECX), False, /* not literal */
13149//.. "%cl", True );
13150//.. break;
13151//..
13152//.. case 0xAC: /* SHRDv imm8,Gv,Ev */
sewardj8c332e22005-01-28 01:36:56 +000013153//.. modrm = getUChar(delta);
sewardjd20c8852005-01-20 20:04:07 +000013154//.. d32 = delta + lengthAMode(delta);
13155//.. vex_sprintf(dis_buf, "$%d", delta);
13156//.. delta = dis_SHLRD_Gv_Ev (
13157//.. sorb, delta, modrm, sz,
sewardj8c332e22005-01-28 01:36:56 +000013158//.. mkU8(getUChar(d32)), True, /* literal */
sewardjd20c8852005-01-20 20:04:07 +000013159//.. dis_buf, False );
13160//.. break;
13161//.. case 0xAD: /* SHRDv %cl,Gv,Ev */
sewardj8c332e22005-01-28 01:36:56 +000013162//.. modrm = getUChar(delta);
sewardjd20c8852005-01-20 20:04:07 +000013163//.. delta = dis_SHLRD_Gv_Ev (
13164//.. sorb, delta, modrm, sz,
13165//.. getIReg(1,R_ECX), False, /* not literal */
13166//.. "%cl", False );
13167//.. break;
sewardje1698952005-02-08 15:02:39 +000013168
13169 /* =-=-=-=-=-=-=-=-=- SYSCALL -=-=-=-=-=-=-=-=-=-= */
13170 case 0x05: /* SYSCALL */
sewardj9e6491a2005-07-02 19:24:10 +000013171 guest_RIP_next_mustcheck = True;
13172 guest_RIP_next_assumed = guest_RIP_bbstart + delta;
13173 putIReg64( R_RCX, mkU64(guest_RIP_next_assumed) );
sewardje1698952005-02-08 15:02:39 +000013174 /* It's important that all guest state is up-to-date
13175 at this point. So we declare an end-of-block here, which
13176 forces any cached guest state to be flushed. */
sewardj9e6491a2005-07-02 19:24:10 +000013177 jmp_lit(Ijk_Syscall, guest_RIP_next_assumed);
13178 dres.whatNext = Dis_StopHere;
sewardje1698952005-02-08 15:02:39 +000013179 DIP("syscall\n");
13180 break;
13181
sewardjb4fd2e72005-03-23 13:34:11 +000013182 /* =-=-=-=-=-=-=-=-=- XADD -=-=-=-=-=-=-=-=-=-= */
13183
sewardjd20c8852005-01-20 20:04:07 +000013184//.. //-- case 0xC0: /* XADD Gb,Eb */
13185//.. //-- eip = dis_xadd_G_E ( cb, sorb, 1, eip );
13186//.. //-- break;
sewardjb4fd2e72005-03-23 13:34:11 +000013187 case 0xC1: { /* XADD Gv,Ev */
13188 Bool decode_OK = False;
13189 delta = dis_xadd_G_E ( &decode_OK, pfx, sz, delta );
13190 if (!decode_OK)
13191 goto decode_failure;
13192 break;
13193 }
13194
sewardj8711f662005-05-09 17:52:56 +000013195 /* =-=-=-=-=-=-=-=-=- MMXery =-=-=-=-=-=-=-=-=-=-= */
13196
sewardj3d8107c2005-05-09 22:23:38 +000013197 case 0x71:
13198 case 0x72:
13199 case 0x73: /* PSLLgg/PSRAgg/PSRLgg mmxreg by imm8 */
13200
13201 case 0x6E: /* MOVD (src)ireg-or-mem, (dst)mmxreg */
13202 case 0x7E: /* MOVD (src)mmxreg, (dst)ireg-or-mem */
sewardj8711f662005-05-09 17:52:56 +000013203 case 0x7F: /* MOVQ (src)mmxreg, (dst)mmxreg-or-mem */
13204 case 0x6F: /* MOVQ (src)mmxreg-or-mem, (dst)mmxreg */
13205
13206 case 0xFC:
13207 case 0xFD:
13208 case 0xFE: /* PADDgg (src)mmxreg-or-mem, (dst)mmxreg */
13209
13210 case 0xEC:
13211 case 0xED: /* PADDSgg (src)mmxreg-or-mem, (dst)mmxreg */
13212
13213 case 0xDC:
13214 case 0xDD: /* PADDUSgg (src)mmxreg-or-mem, (dst)mmxreg */
13215
13216 case 0xF8:
13217 case 0xF9:
13218 case 0xFA: /* PSUBgg (src)mmxreg-or-mem, (dst)mmxreg */
13219
13220 case 0xE8:
13221 case 0xE9: /* PSUBSgg (src)mmxreg-or-mem, (dst)mmxreg */
13222
13223 case 0xD8:
13224 case 0xD9: /* PSUBUSgg (src)mmxreg-or-mem, (dst)mmxreg */
13225
13226 case 0xE5: /* PMULHW (src)mmxreg-or-mem, (dst)mmxreg */
13227 case 0xD5: /* PMULLW (src)mmxreg-or-mem, (dst)mmxreg */
13228
13229 case 0xF5: /* PMADDWD (src)mmxreg-or-mem, (dst)mmxreg */
13230
13231 case 0x74:
13232 case 0x75:
13233 case 0x76: /* PCMPEQgg (src)mmxreg-or-mem, (dst)mmxreg */
13234
13235 case 0x64:
13236 case 0x65:
13237 case 0x66: /* PCMPGTgg (src)mmxreg-or-mem, (dst)mmxreg */
13238
13239 case 0x6B: /* PACKSSDW (src)mmxreg-or-mem, (dst)mmxreg */
13240 case 0x63: /* PACKSSWB (src)mmxreg-or-mem, (dst)mmxreg */
13241 case 0x67: /* PACKUSWB (src)mmxreg-or-mem, (dst)mmxreg */
13242
13243 case 0x68:
13244 case 0x69:
13245 case 0x6A: /* PUNPCKHgg (src)mmxreg-or-mem, (dst)mmxreg */
13246
13247 case 0x60:
13248 case 0x61:
13249 case 0x62: /* PUNPCKLgg (src)mmxreg-or-mem, (dst)mmxreg */
13250
13251 case 0xDB: /* PAND (src)mmxreg-or-mem, (dst)mmxreg */
13252 case 0xDF: /* PANDN (src)mmxreg-or-mem, (dst)mmxreg */
13253 case 0xEB: /* POR (src)mmxreg-or-mem, (dst)mmxreg */
13254 case 0xEF: /* PXOR (src)mmxreg-or-mem, (dst)mmxreg */
13255
13256 case 0xF1: /* PSLLgg (src)mmxreg-or-mem, (dst)mmxreg */
13257 case 0xF2:
13258 case 0xF3:
13259
13260 case 0xD1: /* PSRLgg (src)mmxreg-or-mem, (dst)mmxreg */
13261 case 0xD2:
13262 case 0xD3:
13263
13264 case 0xE1: /* PSRAgg (src)mmxreg-or-mem, (dst)mmxreg */
13265 case 0xE2:
13266 {
sewardj270def42005-07-03 01:03:01 +000013267 Long delta0 = delta-1;
sewardj8711f662005-05-09 17:52:56 +000013268 Bool decode_OK = False;
13269
13270 /* If sz==2 this is SSE, and we assume sse idec has
13271 already spotted those cases by now. */
sewardj3d8107c2005-05-09 22:23:38 +000013272 if (sz != 4 && sz != 8)
sewardj8711f662005-05-09 17:52:56 +000013273 goto decode_failure;
13274 if (have66orF2orF3(pfx))
13275 goto decode_failure;
13276
13277 delta = dis_MMX ( &decode_OK, pfx, sz, delta-1 );
13278 if (!decode_OK) {
13279 delta = delta0;
13280 goto decode_failure;
13281 }
13282 break;
13283 }
13284
13285 case 0x77: /* EMMS */
13286 if (sz != 4)
13287 goto decode_failure;
13288 do_EMMS_preamble();
13289 DIP("emms\n");
13290 break;
sewardj3ca55a12005-01-27 16:06:23 +000013291
13292 /* =-=-=-=-=-=-=-=-=- unimp2 =-=-=-=-=-=-=-=-=-=-= */
13293
13294 default:
13295 goto decode_failure;
13296 } /* switch (opc) for the 2-byte opcodes */
13297 goto decode_success;
13298 } /* case 0x0F: of primary opcode */
sewardjdf0e0022005-01-25 15:48:43 +000013299
13300 /* ------------------------ ??? ------------------------ */
13301
13302 default:
13303 decode_failure:
13304 /* All decode failures end up here. */
13305 vex_printf("vex amd64->IR: unhandled instruction bytes: "
13306 "0x%x 0x%x 0x%x 0x%x\n",
sewardj8c332e22005-01-28 01:36:56 +000013307 (Int)getUChar(delta_start+0),
13308 (Int)getUChar(delta_start+1),
13309 (Int)getUChar(delta_start+2),
13310 (Int)getUChar(delta_start+3) );
sewardjdf0e0022005-01-25 15:48:43 +000013311
13312 /* Tell the dispatcher that this insn cannot be decoded, and so has
13313 not been executed, and (is currently) the next to be executed.
13314 RIP should be up-to-date since it made so at the start of each
13315 insn, but nevertheless be paranoid and update it again right
13316 now. */
sewardj9e6491a2005-07-02 19:24:10 +000013317 stmt( IRStmt_Put( OFFB_RIP, mkU64(guest_RIP_curr_instr) ) );
13318 jmp_lit(Ijk_NoDecode, guest_RIP_curr_instr);
13319 dres.whatNext = Dis_StopHere;
13320 dres.len = 0;
13321 return dres;
sewardjdf0e0022005-01-25 15:48:43 +000013322
13323 } /* switch (opc) for the main (primary) opcode switch. */
13324
13325 decode_success:
13326 /* All decode successes end up here. */
13327 DIP("\n");
sewardj9e6491a2005-07-02 19:24:10 +000013328 dres.len = (Int)toUInt(delta - delta_start);
13329 return dres;
sewardjdf0e0022005-01-25 15:48:43 +000013330}
13331
13332#undef DIP
13333#undef DIS
sewardjd20c8852005-01-20 20:04:07 +000013334
sewardj9e6491a2005-07-02 19:24:10 +000013335
13336/*------------------------------------------------------------*/
13337/*--- Top-level fn ---*/
13338/*------------------------------------------------------------*/
13339
13340/* Disassemble a single instruction into IR. The instruction
13341 is located in host memory at &guest_code[delta]. */
13342
13343DisResult disInstr_AMD64 ( IRBB* irbb_IN,
13344 Bool put_IP,
13345 Bool (*resteerOkFn) ( Addr64 ),
13346 UChar* guest_code_IN,
13347 Long delta,
13348 Addr64 guest_IP,
13349 VexArchInfo* archinfo,
13350 Bool host_bigendian_IN )
13351{
13352 DisResult dres;
13353
13354 /* Set globals (see top of this file) */
13355 guest_code = guest_code_IN;
13356 irbb = irbb_IN;
13357 host_is_bigendian = host_bigendian_IN;
13358 guest_RIP_curr_instr = guest_IP;
13359 guest_RIP_bbstart = guest_IP - delta;
13360
13361 /* We'll consult these after doing disInstr_AMD64_WRK. */
13362 guest_RIP_next_assumed = 0;
13363 guest_RIP_next_mustcheck = False;
13364
13365 dres = disInstr_AMD64_WRK ( put_IP, resteerOkFn,
13366 delta, archinfo );
13367
13368 /* If disInstr_AMD64_WRK tried to figure out the next rip, check it
13369 got it right. Failure of this assertion is serious and denotes
13370 a bug in disInstr. */
13371 if (guest_RIP_next_mustcheck
13372 && guest_RIP_next_assumed != guest_RIP_curr_instr + dres.len) {
13373 vex_printf("\n");
13374 vex_printf("assumed next %%rip = 0x%llx\n",
13375 guest_RIP_next_assumed );
13376 vex_printf(" actual next %%rip = 0x%llx\n",
13377 guest_RIP_curr_instr + dres.len );
13378 vpanic("bbToIR_AMD64: disInstr miscalculated next %rip");
13379 }
13380
13381 return dres;
13382}
13383
13384
13385
sewardjd20c8852005-01-20 20:04:07 +000013386/*--------------------------------------------------------------------*/
13387/*--- end guest-amd64/toIR.c ---*/
13388/*--------------------------------------------------------------------*/