blob: 30f79d42f36992dc980a42285c791f76fc756497 [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
sewardj7bd6ffe2005-08-03 16:07:36 +000013 Copyright (C) 2004-2005 OpenWorks LLP. All rights reserved.
sewardjd20c8852005-01-20 20:04:07 +000014
sewardj7bd6ffe2005-08-03 16:07:36 +000015 This library is made available under a dual licensing scheme.
sewardjd20c8852005-01-20 20:04:07 +000016
sewardj7bd6ffe2005-08-03 16:07:36 +000017 If you link LibVEX against other code all of which is itself
18 licensed under the GNU General Public License, version 2 dated June
19 1991 ("GPL v2"), then you may use LibVEX under the terms of the GPL
20 v2, as appearing in the file LICENSE.GPL. If the file LICENSE.GPL
21 is missing, you can obtain a copy of the GPL v2 from the Free
22 Software Foundation Inc., 51 Franklin St, Fifth Floor, Boston, MA
23 02110-1301, USA.
24
25 For any other uses of LibVEX, you must first obtain a commercial
26 license from OpenWorks LLP. Please contact info@open-works.co.uk
27 for information about commercial licensing.
28
29 This software is provided by OpenWorks LLP "as is" and any express
30 or implied warranties, including, but not limited to, the implied
31 warranties of merchantability and fitness for a particular purpose
32 are disclaimed. In no event shall OpenWorks LLP be liable for any
33 direct, indirect, incidental, special, exemplary, or consequential
34 damages (including, but not limited to, procurement of substitute
35 goods or services; loss of use, data, or profits; or business
36 interruption) however caused and on any theory of liability,
37 whether in contract, strict liability, or tort (including
38 negligence or otherwise) arising in any way out of the use of this
39 software, even if advised of the possibility of such damage.
sewardjd20c8852005-01-20 20:04:07 +000040
41 Neither the names of the U.S. Department of Energy nor the
42 University of California nor the names of its contributors may be
43 used to endorse or promote products derived from this software
44 without prior written permission.
sewardjd20c8852005-01-20 20:04:07 +000045*/
46
sewardj9ff93bc2005-03-23 11:25:12 +000047/* LIMITATIONS:
48
49 LOCK prefix handling is only safe in the situation where
50 Vex-generated code is run single-threadedly. (This is not the same
51 as saying that Valgrind can't safely use Vex to run multithreaded
52 programs). See comment attached to LOCK prefix handling in
53 disInstr for details.
54*/
55
sewardj820611e2005-08-24 10:56:01 +000056/* TODO:
57
58 All Puts to CC_OP/CC_DEP1/CC_DEP2/CC_NDEP should really be checked
59 to ensure a 64-bit value is being written.
60
sewardjd20c8852005-01-20 20:04:07 +000061//.. x87 FP Limitations:
62//..
63//.. * all arithmetic done at 64 bits
64//..
65//.. * no FP exceptions, except for handling stack over/underflow
66//..
67//.. * FP rounding mode observed only for float->int conversions
68//.. and int->float conversions which could lose accuracy, and
69//.. for float-to-float rounding. For all other operations,
70//.. round-to-nearest is used, regardless.
71//..
72//.. * FP sin/cos/tan/sincos: C2 flag is always cleared. IOW the
73//.. simulation claims the argument is in-range (-2^63 <= arg <= 2^63)
74//.. even when it isn't.
75//..
76//.. * some of the FCOM cases could do with testing -- not convinced
77//.. that the args are the right way round.
78//..
79//.. * FSAVE does not re-initialise the FPU; it should do
80//..
81//.. * FINIT not only initialises the FPU environment, it also
82//.. zeroes all the FP registers. It should leave the registers
83//.. unchanged.
84//..
85//.. RDTSC returns zero, always.
86//..
87//.. SAHF should cause eflags[1] == 1, and in fact it produces 0. As
88//.. per Intel docs this bit has no meaning anyway. Since PUSHF is the
89//.. only way to observe eflags[1], a proper fix would be to make that
90//.. bit be set by PUSHF.
91//..
92//.. This module uses global variables and so is not MT-safe (if that
sewardj820611e2005-08-24 10:56:01 +000093//.. should ever become relevant).
94*/
sewardj44d494d2005-01-20 20:26:33 +000095
96/* Translates AMD64 code to IR. */
97
98#include "libvex_basictypes.h"
99#include "libvex_ir.h"
100#include "libvex.h"
101#include "libvex_guest_amd64.h"
102
103#include "main/vex_util.h"
104#include "main/vex_globals.h"
sewardj9e6491a2005-07-02 19:24:10 +0000105#include "guest-generic/bb_to_IR.h"
sewardj44d494d2005-01-20 20:26:33 +0000106#include "guest-amd64/gdefs.h"
107
108
sewardjecb94892005-01-21 14:26:37 +0000109/*------------------------------------------------------------*/
110/*--- Globals ---*/
111/*------------------------------------------------------------*/
112
sewardj9e6491a2005-07-02 19:24:10 +0000113/* These are set at the start of the translation of an insn, right
114 down in disInstr_AMD64, so that we don't have to pass them around
115 endlessly. They are all constant during the translation of any
116 given insn. */
sewardj4b744762005-02-07 15:02:25 +0000117
sewardjecb94892005-01-21 14:26:37 +0000118/* These are set at the start of the translation of a BB, so
119 that we don't have to pass them around endlessly. */
120
121/* We need to know this to do sub-register accesses correctly. */
sewardjecb94892005-01-21 14:26:37 +0000122static Bool host_is_bigendian;
123
sewardj9e6491a2005-07-02 19:24:10 +0000124/* Pointer to the guest code area (points to start of BB, not to the
125 insn being processed). */
sewardjb3a04292005-01-21 20:33:44 +0000126static UChar* guest_code;
127
sewardjdf0e0022005-01-25 15:48:43 +0000128/* The guest address corresponding to guest_code[0]. */
sewardj9e6491a2005-07-02 19:24:10 +0000129static Addr64 guest_RIP_bbstart;
sewardj4b744762005-02-07 15:02:25 +0000130
sewardjb3a04292005-01-21 20:33:44 +0000131/* The guest address for the instruction currently being
132 translated. */
sewardj9e6491a2005-07-02 19:24:10 +0000133static Addr64 guest_RIP_curr_instr;
sewardjecb94892005-01-21 14:26:37 +0000134
sewardj9e6491a2005-07-02 19:24:10 +0000135/* The IRBB* into which we're generating code. */
136static IRBB* irbb;
sewardjecb94892005-01-21 14:26:37 +0000137
sewardj4b744762005-02-07 15:02:25 +0000138/* For ensuring that %rip-relative addressing is done right. A read
139 of %rip generates the address of the next instruction. It may be
140 that we don't conveniently know that inside disAMode(). For sanity
141 checking, if the next insn %rip is needed, we make a guess at what
142 it is, record that guess here, and set the accompanying Bool to
143 indicate that -- after this insn's decode is finished -- that guess
144 needs to be checked. */
145
146/* At the start of each insn decode, is set to (0, False).
147 After the decode, if _mustcheck is now True, _assumed is
148 checked. */
149
sewardj9e6491a2005-07-02 19:24:10 +0000150static Addr64 guest_RIP_next_assumed;
151static Bool guest_RIP_next_mustcheck;
sewardj4b744762005-02-07 15:02:25 +0000152
153
sewardjecb94892005-01-21 14:26:37 +0000154/*------------------------------------------------------------*/
155/*--- Helpers for constructing IR. ---*/
156/*------------------------------------------------------------*/
157
sewardjb3a04292005-01-21 20:33:44 +0000158/* Generate a new temporary of the given type. */
159static IRTemp newTemp ( IRType ty )
160{
sewardj496a58d2005-03-20 18:44:44 +0000161 vassert(isPlausibleIRType(ty));
sewardjb3a04292005-01-21 20:33:44 +0000162 return newIRTemp( irbb->tyenv, ty );
163}
164
sewardjecb94892005-01-21 14:26:37 +0000165/* Add a statement to the list held by "irbb". */
166static void stmt ( IRStmt* st )
167{
168 addStmtToIRBB( irbb, st );
169}
sewardjb3a04292005-01-21 20:33:44 +0000170
171/* Generate a statement "dst := e". */
172static void assign ( IRTemp dst, IRExpr* e )
173{
174 stmt( IRStmt_Tmp(dst, e) );
175}
176
sewardjecb94892005-01-21 14:26:37 +0000177static IRExpr* unop ( IROp op, IRExpr* a )
178{
179 return IRExpr_Unop(op, a);
180}
181
sewardjb3a04292005-01-21 20:33:44 +0000182static IRExpr* binop ( IROp op, IRExpr* a1, IRExpr* a2 )
183{
184 return IRExpr_Binop(op, a1, a2);
185}
186
sewardjdf0e0022005-01-25 15:48:43 +0000187static IRExpr* mkexpr ( IRTemp tmp )
188{
189 return IRExpr_Tmp(tmp);
190}
sewardjb3a04292005-01-21 20:33:44 +0000191
sewardj3ca55a12005-01-27 16:06:23 +0000192static IRExpr* mkU8 ( ULong i )
sewardjb3a04292005-01-21 20:33:44 +0000193{
194 vassert(i < 256);
sewardj3ca55a12005-01-27 16:06:23 +0000195 return IRExpr_Const(IRConst_U8( (UChar)i ));
sewardjb3a04292005-01-21 20:33:44 +0000196}
197
sewardj5e525292005-01-28 15:13:10 +0000198static IRExpr* mkU16 ( ULong i )
199{
200 vassert(i < 0x10000ULL);
201 return IRExpr_Const(IRConst_U16( (UShort)i ));
202}
sewardj3ca55a12005-01-27 16:06:23 +0000203
204static IRExpr* mkU32 ( ULong i )
205{
206 vassert(i < 0x100000000ULL);
207 return IRExpr_Const(IRConst_U32( (UInt)i ));
208}
sewardjb3a04292005-01-21 20:33:44 +0000209
210static IRExpr* mkU64 ( ULong i )
211{
212 return IRExpr_Const(IRConst_U64(i));
213}
sewardjecb94892005-01-21 14:26:37 +0000214
sewardj3ca55a12005-01-27 16:06:23 +0000215static IRExpr* mkU ( IRType ty, ULong i )
216{
217 switch (ty) {
218 case Ity_I8: return mkU8(i);
sewardj5e525292005-01-28 15:13:10 +0000219 case Ity_I16: return mkU16(i);
sewardj3ca55a12005-01-27 16:06:23 +0000220 case Ity_I32: return mkU32(i);
221 case Ity_I64: return mkU64(i);
222 default: vpanic("mkU(amd64)");
223 }
224}
225
sewardj5e525292005-01-28 15:13:10 +0000226static void storeLE ( IRExpr* addr, IRExpr* data )
227{
sewardjaf1ceca2005-06-30 23:31:27 +0000228 stmt( IRStmt_Store(Iend_LE,addr,data) );
sewardj5e525292005-01-28 15:13:10 +0000229}
230
231static IRExpr* loadLE ( IRType ty, IRExpr* data )
232{
sewardjaf1ceca2005-06-30 23:31:27 +0000233 return IRExpr_Load(Iend_LE,ty,data);
sewardj5e525292005-01-28 15:13:10 +0000234}
235
236static IROp mkSizedOp ( IRType ty, IROp op8 )
237{
238 vassert(op8 == Iop_Add8 || op8 == Iop_Sub8
239 || op8 == Iop_Mul8
240 || op8 == Iop_Or8 || op8 == Iop_And8 || op8 == Iop_Xor8
241 || op8 == Iop_Shl8 || op8 == Iop_Shr8 || op8 == Iop_Sar8
242 || op8 == Iop_CmpEQ8 || op8 == Iop_CmpNE8
243 || op8 == Iop_Not8 );
244 switch (ty) {
245 case Ity_I8: return 0 +op8;
246 case Ity_I16: return 1 +op8;
247 case Ity_I32: return 2 +op8;
248 case Ity_I64: return 3 +op8;
249 default: vpanic("mkSizedOp(amd64)");
250 }
251}
252
253static
254IRExpr* doScalarWidening ( Int szSmall, Int szBig, Bool signd, IRExpr* src )
255{
256 if (szSmall == 1 && szBig == 4) {
257 return unop(signd ? Iop_8Sto32 : Iop_8Uto32, src);
258 }
259 if (szSmall == 1 && szBig == 2) {
260 return unop(signd ? Iop_8Sto16 : Iop_8Uto16, src);
261 }
262 if (szSmall == 2 && szBig == 4) {
263 return unop(signd ? Iop_16Sto32 : Iop_16Uto32, src);
264 }
265 if (szSmall == 1 && szBig == 8 && !signd) {
sewardje58967e2005-04-27 11:50:56 +0000266 return unop(Iop_8Uto64, src);
sewardj5e525292005-01-28 15:13:10 +0000267 }
sewardj03b07cc2005-01-31 18:09:43 +0000268 if (szSmall == 1 && szBig == 8 && signd) {
sewardje58967e2005-04-27 11:50:56 +0000269 return unop(Iop_8Sto64, src);
sewardj03b07cc2005-01-31 18:09:43 +0000270 }
sewardj5e525292005-01-28 15:13:10 +0000271 if (szSmall == 2 && szBig == 8 && !signd) {
sewardje58967e2005-04-27 11:50:56 +0000272 return unop(Iop_16Uto64, src);
sewardj5e525292005-01-28 15:13:10 +0000273 }
sewardj03b07cc2005-01-31 18:09:43 +0000274 if (szSmall == 2 && szBig == 8 && signd) {
sewardje58967e2005-04-27 11:50:56 +0000275 return unop(Iop_16Sto64, src);
sewardj03b07cc2005-01-31 18:09:43 +0000276 }
sewardj5e525292005-01-28 15:13:10 +0000277 vpanic("doScalarWidening(amd64)");
278}
279
280
sewardjecb94892005-01-21 14:26:37 +0000281
282/*------------------------------------------------------------*/
283/*--- Debugging output ---*/
284/*------------------------------------------------------------*/
285
sewardjb3a04292005-01-21 20:33:44 +0000286/* Bomb out if we can't handle something. */
287__attribute__ ((noreturn))
288static void unimplemented ( HChar* str )
289{
290 vex_printf("amd64toIR: unimplemented feature\n");
291 vpanic(str);
292}
293
sewardjecb94892005-01-21 14:26:37 +0000294#define DIP(format, args...) \
sewardj9e6491a2005-07-02 19:24:10 +0000295 if (vex_traceflags & VEX_TRACE_FE) \
sewardjecb94892005-01-21 14:26:37 +0000296 vex_printf(format, ## args)
297
298#define DIS(buf, format, args...) \
sewardj9e6491a2005-07-02 19:24:10 +0000299 if (vex_traceflags & VEX_TRACE_FE) \
sewardjecb94892005-01-21 14:26:37 +0000300 vex_sprintf(buf, format, ## args)
301
302
303/*------------------------------------------------------------*/
304/*--- Offsets of various parts of the amd64 guest state. ---*/
305/*------------------------------------------------------------*/
306
307#define OFFB_RAX offsetof(VexGuestAMD64State,guest_RAX)
308#define OFFB_RBX offsetof(VexGuestAMD64State,guest_RBX)
309#define OFFB_RCX offsetof(VexGuestAMD64State,guest_RCX)
310#define OFFB_RDX offsetof(VexGuestAMD64State,guest_RDX)
311#define OFFB_RSP offsetof(VexGuestAMD64State,guest_RSP)
312#define OFFB_RBP offsetof(VexGuestAMD64State,guest_RBP)
313#define OFFB_RSI offsetof(VexGuestAMD64State,guest_RSI)
314#define OFFB_RDI offsetof(VexGuestAMD64State,guest_RDI)
315#define OFFB_R8 offsetof(VexGuestAMD64State,guest_R8)
316#define OFFB_R9 offsetof(VexGuestAMD64State,guest_R9)
317#define OFFB_R10 offsetof(VexGuestAMD64State,guest_R10)
318#define OFFB_R11 offsetof(VexGuestAMD64State,guest_R11)
319#define OFFB_R12 offsetof(VexGuestAMD64State,guest_R12)
320#define OFFB_R13 offsetof(VexGuestAMD64State,guest_R13)
321#define OFFB_R14 offsetof(VexGuestAMD64State,guest_R14)
322#define OFFB_R15 offsetof(VexGuestAMD64State,guest_R15)
323
324#define OFFB_RIP offsetof(VexGuestAMD64State,guest_RIP)
325
sewardja6b93d12005-02-17 09:28:28 +0000326#define OFFB_FS_ZERO offsetof(VexGuestAMD64State,guest_FS_ZERO)
327
sewardjecb94892005-01-21 14:26:37 +0000328#define OFFB_CC_OP offsetof(VexGuestAMD64State,guest_CC_OP)
329#define OFFB_CC_DEP1 offsetof(VexGuestAMD64State,guest_CC_DEP1)
330#define OFFB_CC_DEP2 offsetof(VexGuestAMD64State,guest_CC_DEP2)
331#define OFFB_CC_NDEP offsetof(VexGuestAMD64State,guest_CC_NDEP)
332
sewardj8d965312005-02-25 02:48:47 +0000333#define OFFB_FPREGS offsetof(VexGuestAMD64State,guest_FPREG[0])
334#define OFFB_FPTAGS offsetof(VexGuestAMD64State,guest_FPTAG[0])
sewardjd0a12df2005-02-10 02:07:43 +0000335#define OFFB_DFLAG offsetof(VexGuestAMD64State,guest_DFLAG)
sewardj85520e42005-02-19 15:22:38 +0000336#define OFFB_IDFLAG offsetof(VexGuestAMD64State,guest_IDFLAG)
sewardj8d965312005-02-25 02:48:47 +0000337#define OFFB_FTOP offsetof(VexGuestAMD64State,guest_FTOP)
sewardj25a85812005-05-08 23:03:48 +0000338#define OFFB_FC3210 offsetof(VexGuestAMD64State,guest_FC3210)
sewardjc49ce232005-02-25 13:03:03 +0000339#define OFFB_FPROUND offsetof(VexGuestAMD64State,guest_FPROUND)
sewardjd20c8852005-01-20 20:04:07 +0000340//..
341//.. #define OFFB_CS offsetof(VexGuestX86State,guest_CS)
342//.. #define OFFB_DS offsetof(VexGuestX86State,guest_DS)
343//.. #define OFFB_ES offsetof(VexGuestX86State,guest_ES)
344//.. #define OFFB_FS offsetof(VexGuestX86State,guest_FS)
345//.. #define OFFB_GS offsetof(VexGuestX86State,guest_GS)
346//.. #define OFFB_SS offsetof(VexGuestX86State,guest_SS)
347//.. #define OFFB_LDT offsetof(VexGuestX86State,guest_LDT)
348//.. #define OFFB_GDT offsetof(VexGuestX86State,guest_GDT)
sewardj1001dc42005-02-21 08:25:55 +0000349
350#define OFFB_SSEROUND offsetof(VexGuestAMD64State,guest_SSEROUND)
351#define OFFB_XMM0 offsetof(VexGuestAMD64State,guest_XMM0)
352#define OFFB_XMM1 offsetof(VexGuestAMD64State,guest_XMM1)
353#define OFFB_XMM2 offsetof(VexGuestAMD64State,guest_XMM2)
354#define OFFB_XMM3 offsetof(VexGuestAMD64State,guest_XMM3)
355#define OFFB_XMM4 offsetof(VexGuestAMD64State,guest_XMM4)
356#define OFFB_XMM5 offsetof(VexGuestAMD64State,guest_XMM5)
357#define OFFB_XMM6 offsetof(VexGuestAMD64State,guest_XMM6)
358#define OFFB_XMM7 offsetof(VexGuestAMD64State,guest_XMM7)
359#define OFFB_XMM8 offsetof(VexGuestAMD64State,guest_XMM8)
360#define OFFB_XMM9 offsetof(VexGuestAMD64State,guest_XMM9)
361#define OFFB_XMM10 offsetof(VexGuestAMD64State,guest_XMM10)
362#define OFFB_XMM11 offsetof(VexGuestAMD64State,guest_XMM11)
363#define OFFB_XMM12 offsetof(VexGuestAMD64State,guest_XMM12)
364#define OFFB_XMM13 offsetof(VexGuestAMD64State,guest_XMM13)
365#define OFFB_XMM14 offsetof(VexGuestAMD64State,guest_XMM14)
366#define OFFB_XMM15 offsetof(VexGuestAMD64State,guest_XMM15)
367
sewardjbcbb9de2005-03-27 02:22:32 +0000368#define OFFB_EMWARN offsetof(VexGuestAMD64State,guest_EMWARN)
sewardjdf0e0022005-01-25 15:48:43 +0000369
370
371/*------------------------------------------------------------*/
sewardjecb94892005-01-21 14:26:37 +0000372/*--- Helper bits and pieces for deconstructing the ---*/
373/*--- amd64 insn stream. ---*/
374/*------------------------------------------------------------*/
375
376/* This is the AMD64 register encoding -- integer regs. */
377#define R_RAX 0
378#define R_RCX 1
379#define R_RDX 2
380#define R_RBX 3
381#define R_RSP 4
382#define R_RBP 5
383#define R_RSI 6
384#define R_RDI 7
385#define R_R8 8
386#define R_R9 9
387#define R_R10 10
388#define R_R11 11
389#define R_R12 12
390#define R_R13 13
391#define R_R14 14
392#define R_R15 15
393
sewardjd20c8852005-01-20 20:04:07 +0000394//.. #define R_AL (0+R_EAX)
395//.. #define R_AH (4+R_EAX)
sewardjecb94892005-01-21 14:26:37 +0000396
397/* This is the Intel register encoding -- segment regs. */
398#define R_ES 0
399#define R_CS 1
400#define R_SS 2
401#define R_DS 3
402#define R_FS 4
403#define R_GS 5
404
405
sewardjb3a04292005-01-21 20:33:44 +0000406/* Various simple conversions */
407
408static ULong extend_s_8to64 ( UChar x )
409{
410 return (ULong)((((Long)x) << 56) >> 56);
411}
412
413static ULong extend_s_16to64 ( UShort x )
414{
415 return (ULong)((((Long)x) << 48) >> 48);
416}
417
418static ULong extend_s_32to64 ( UInt x )
419{
420 return (ULong)((((Long)x) << 32) >> 32);
421}
422
sewardjdf0e0022005-01-25 15:48:43 +0000423/* Figure out whether the mod and rm parts of a modRM byte refer to a
424 register or memory. If so, the byte will have the form 11XXXYYY,
425 where YYY is the register number. */
sewardj5b470602005-02-27 13:10:48 +0000426inline
sewardjdf0e0022005-01-25 15:48:43 +0000427static Bool epartIsReg ( UChar mod_reg_rm )
428{
sewardj7a240552005-01-28 21:37:12 +0000429 return toBool(0xC0 == (mod_reg_rm & 0xC0));
sewardjdf0e0022005-01-25 15:48:43 +0000430}
431
sewardj901ed122005-02-27 13:25:31 +0000432/* Extract the 'g' field from a modRM byte. This only produces 3
433 bits, which is not a complete register number. You should avoid
434 this function if at all possible. */
435inline
436static Int gregLO3ofRM ( UChar mod_reg_rm )
sewardjdf0e0022005-01-25 15:48:43 +0000437{
438 return (Int)( (mod_reg_rm >> 3) & 7 );
439}
440
sewardj8711f662005-05-09 17:52:56 +0000441/* Ditto the 'e' field of a modRM byte. */
442inline
443static Int eregLO3ofRM ( UChar mod_reg_rm )
444{
445 return (Int)(mod_reg_rm & 0x7);
446}
447
sewardjdf0e0022005-01-25 15:48:43 +0000448/* Get a 8/16/32-bit unsigned value out of the insn stream. */
449
sewardj270def42005-07-03 01:03:01 +0000450static UChar getUChar ( Long delta )
sewardjdf0e0022005-01-25 15:48:43 +0000451{
sewardj8c332e22005-01-28 01:36:56 +0000452 UChar v = guest_code[delta+0];
453 return v;
sewardjdf0e0022005-01-25 15:48:43 +0000454}
455
sewardj270def42005-07-03 01:03:01 +0000456//.. static UInt getUDisp16 ( Long delta )
sewardjd20c8852005-01-20 20:04:07 +0000457//.. {
458//.. UInt v = guest_code[delta+1]; v <<= 8;
459//.. v |= guest_code[delta+0];
460//.. return v & 0xFFFF;
461//.. }
462//..
sewardj270def42005-07-03 01:03:01 +0000463//.. static UInt getUDisp ( Int size, Long delta )
sewardjd20c8852005-01-20 20:04:07 +0000464//.. {
465//.. switch (size) {
466//.. case 4: return getUDisp32(delta);
467//.. case 2: return getUDisp16(delta);
468//.. case 1: return getUChar(delta);
469//.. default: vpanic("getUDisp(x86)");
470//.. }
471//.. return 0; /*notreached*/
472//.. }
sewardjb3a04292005-01-21 20:33:44 +0000473
474
475/* Get a byte value out of the insn stream and sign-extend to 64
476 bits. */
sewardj270def42005-07-03 01:03:01 +0000477static Long getSDisp8 ( Long delta )
sewardjb3a04292005-01-21 20:33:44 +0000478{
479 return extend_s_8to64( guest_code[delta] );
480}
481
sewardj5e525292005-01-28 15:13:10 +0000482/* Get a 16-bit value out of the insn stream and sign-extend to 64
483 bits. */
sewardj270def42005-07-03 01:03:01 +0000484static Long getSDisp16 ( Long delta )
sewardj5e525292005-01-28 15:13:10 +0000485{
sewardj118b23e2005-01-29 02:14:44 +0000486 UInt v = guest_code[delta+1]; v <<= 8;
sewardj5e525292005-01-28 15:13:10 +0000487 v |= guest_code[delta+0];
sewardj118b23e2005-01-29 02:14:44 +0000488 return extend_s_16to64( (UShort)v );
sewardj5e525292005-01-28 15:13:10 +0000489}
490
sewardjb3a04292005-01-21 20:33:44 +0000491/* Get a 32-bit value out of the insn stream and sign-extend to 64
492 bits. */
sewardj270def42005-07-03 01:03:01 +0000493static Long getSDisp32 ( Long delta )
sewardjb3a04292005-01-21 20:33:44 +0000494{
495 UInt v = guest_code[delta+3]; v <<= 8;
496 v |= guest_code[delta+2]; v <<= 8;
497 v |= guest_code[delta+1]; v <<= 8;
498 v |= guest_code[delta+0];
499 return extend_s_32to64( v );
500}
501
sewardj03b07cc2005-01-31 18:09:43 +0000502/* Get a 64-bit value out of the insn stream. */
sewardj270def42005-07-03 01:03:01 +0000503static Long getDisp64 ( Long delta )
sewardj03b07cc2005-01-31 18:09:43 +0000504{
sewardj7eaa7cf2005-01-31 18:55:22 +0000505 ULong v = 0;
sewardj03b07cc2005-01-31 18:09:43 +0000506 v |= guest_code[delta+7]; v <<= 8;
507 v |= guest_code[delta+6]; v <<= 8;
508 v |= guest_code[delta+5]; v <<= 8;
509 v |= guest_code[delta+4]; v <<= 8;
510 v |= guest_code[delta+3]; v <<= 8;
511 v |= guest_code[delta+2]; v <<= 8;
512 v |= guest_code[delta+1]; v <<= 8;
513 v |= guest_code[delta+0];
514 return v;
515}
516
sewardj3ca55a12005-01-27 16:06:23 +0000517/* Note: because AMD64 doesn't allow 64-bit literals, it is an error
518 if this is called with size==8. Should not happen. */
sewardj270def42005-07-03 01:03:01 +0000519static Long getSDisp ( Int size, Long delta )
sewardj3ca55a12005-01-27 16:06:23 +0000520{
521 switch (size) {
522 case 4: return getSDisp32(delta);
sewardj5e525292005-01-28 15:13:10 +0000523 case 2: return getSDisp16(delta);
sewardj3ca55a12005-01-27 16:06:23 +0000524 case 1: return getSDisp8(delta);
525 default: vpanic("getSDisp(amd64)");
526 }
527}
528
sewardj1389d4d2005-01-28 13:46:29 +0000529static ULong mkSizeMask ( Int sz )
sewardj3ca55a12005-01-27 16:06:23 +0000530{
531 switch (sz) {
sewardj1389d4d2005-01-28 13:46:29 +0000532 case 1: return 0x00000000000000FFULL;
533 case 2: return 0x000000000000FFFFULL;
534 case 4: return 0x00000000FFFFFFFFULL;
sewardj3ca55a12005-01-27 16:06:23 +0000535 case 8: return 0xFFFFFFFFFFFFFFFFULL;
536 default: vpanic("mkSzMask(amd64)");
537 }
538}
539
540static Int imin ( Int a, Int b )
541{
542 return (a < b) ? a : b;
543}
sewardjecb94892005-01-21 14:26:37 +0000544
sewardj5b470602005-02-27 13:10:48 +0000545static IRType szToITy ( Int n )
546{
547 switch (n) {
548 case 1: return Ity_I8;
549 case 2: return Ity_I16;
550 case 4: return Ity_I32;
551 case 8: return Ity_I64;
sewardjf53b7352005-04-06 20:01:56 +0000552 default: vex_printf("\nszToITy(%d)\n", n);
553 vpanic("szToITy(amd64)");
sewardj5b470602005-02-27 13:10:48 +0000554 }
555}
556
sewardjecb94892005-01-21 14:26:37 +0000557
558/*------------------------------------------------------------*/
559/*--- For dealing with prefixes. ---*/
560/*------------------------------------------------------------*/
561
562/* The idea is to pass around an int holding a bitmask summarising
563 info from the prefixes seen on the current instruction, including
564 info from the REX byte. This info is used in various places, but
565 most especially when making sense of register fields in
566 instructions.
567
568 The top 16 bits of the prefix are 0x3141, just as a hacky way
569 to ensure it really is a valid prefix.
sewardjdf0e0022005-01-25 15:48:43 +0000570
571 Things you can safely assume about a well-formed prefix:
572 * at most one segment-override bit (CS,DS,ES,FS,GS,SS) is set.
sewardj5b470602005-02-27 13:10:48 +0000573 * if REX is not present then REXW,REXR,REXX,REXB will read
574 as zero.
sewardjdf0e0022005-01-25 15:48:43 +0000575 * F2 and F3 will not both be 1.
sewardjecb94892005-01-21 14:26:37 +0000576*/
577
578typedef UInt Prefix;
579
sewardj3ca55a12005-01-27 16:06:23 +0000580#define PFX_ASO (1<<0) /* address-size override present (0x67) */
581#define PFX_66 (1<<1) /* operand-size override-to-16 present (0x66) */
582#define PFX_REX (1<<2) /* REX byte present (0x40 to 0x4F) */
583#define PFX_REXW (1<<3) /* REX W bit, if REX present, else 0 */
584#define PFX_REXR (1<<4) /* REX R bit, if REX present, else 0 */
585#define PFX_REXX (1<<5) /* REX X bit, if REX present, else 0 */
586#define PFX_REXB (1<<6) /* REX B bit, if REX present, else 0 */
587#define PFX_LOCK (1<<7) /* bus LOCK prefix present (0xF0) */
588#define PFX_F2 (1<<8) /* REP/REPE/REPZ prefix present (0xF2) */
589#define PFX_F3 (1<<9) /* REPNE/REPNZ prefix present (0xF3) */
590#define PFX_CS (1<<10) /* CS segment prefix present (0x2E) */
591#define PFX_DS (1<<11) /* DS segment prefix present (0x3E) */
592#define PFX_ES (1<<12) /* ES segment prefix present (0x26) */
593#define PFX_FS (1<<13) /* FS segment prefix present (0x64) */
594#define PFX_GS (1<<14) /* GS segment prefix present (0x65) */
595#define PFX_SS (1<<15) /* SS segment prefix present (0x36) */
596
597#define PFX_EMPTY 0x31410000
sewardjecb94892005-01-21 14:26:37 +0000598
sewardjb3a04292005-01-21 20:33:44 +0000599static Bool IS_VALID_PFX ( Prefix pfx ) {
sewardj7a240552005-01-28 21:37:12 +0000600 return toBool((pfx & 0xFFFF0000) == PFX_EMPTY);
sewardjecb94892005-01-21 14:26:37 +0000601}
602
sewardjb3a04292005-01-21 20:33:44 +0000603static Bool haveREX ( Prefix pfx ) {
sewardj7a240552005-01-28 21:37:12 +0000604 return toBool(pfx & PFX_REX);
sewardjecb94892005-01-21 14:26:37 +0000605}
606
sewardj5e525292005-01-28 15:13:10 +0000607static Int getRexW ( Prefix pfx ) {
608 return (pfx & PFX_REXW) ? 1 : 0;
609}
sewardj901ed122005-02-27 13:25:31 +0000610/* Apparently unused.
sewardjdf0e0022005-01-25 15:48:43 +0000611static Int getRexR ( Prefix pfx ) {
612 return (pfx & PFX_REXR) ? 1 : 0;
613}
sewardj901ed122005-02-27 13:25:31 +0000614*/
sewardj5b470602005-02-27 13:10:48 +0000615static Int getRexX ( Prefix pfx ) {
616 return (pfx & PFX_REXX) ? 1 : 0;
617}
sewardjdf0e0022005-01-25 15:48:43 +0000618static Int getRexB ( Prefix pfx ) {
619 return (pfx & PFX_REXB) ? 1 : 0;
620}
621
sewardj3ca55a12005-01-27 16:06:23 +0000622/* Check a prefix doesn't have F2 or F3 set in it, since usually that
623 completely changes what instruction it really is. */
624static Bool haveF2orF3 ( Prefix pfx ) {
sewardj7a240552005-01-28 21:37:12 +0000625 return toBool((pfx & (PFX_F2|PFX_F3)) > 0);
sewardj3ca55a12005-01-27 16:06:23 +0000626}
sewardj55dbb262005-01-28 16:36:51 +0000627static Bool haveF2 ( Prefix pfx ) {
sewardj7a240552005-01-28 21:37:12 +0000628 return toBool((pfx & PFX_F2) > 0);
sewardj55dbb262005-01-28 16:36:51 +0000629}
630static Bool haveF3 ( Prefix pfx ) {
sewardj7a240552005-01-28 21:37:12 +0000631 return toBool((pfx & PFX_F3) > 0);
sewardj55dbb262005-01-28 16:36:51 +0000632}
sewardj6359f812005-07-20 10:15:34 +0000633
sewardjc8b26352005-07-20 09:23:13 +0000634static Bool have66 ( Prefix pfx ) {
635 return toBool((pfx & PFX_66) > 0);
636}
sewardj6359f812005-07-20 10:15:34 +0000637static Bool haveASO ( Prefix pfx ) {
638 return toBool((pfx & PFX_ASO) > 0);
639}
sewardjecb94892005-01-21 14:26:37 +0000640
sewardj1001dc42005-02-21 08:25:55 +0000641/* Return True iff pfx has 66 set and F2 and F3 clear */
642static Bool have66noF2noF3 ( Prefix pfx )
643{
644 return
sewardj8d965312005-02-25 02:48:47 +0000645 toBool((pfx & (PFX_66|PFX_F2|PFX_F3)) == PFX_66);
sewardj1001dc42005-02-21 08:25:55 +0000646}
647
648/* Return True iff pfx has F2 set and 66 and F3 clear */
649static Bool haveF2no66noF3 ( Prefix pfx )
650{
651 return
sewardj8d965312005-02-25 02:48:47 +0000652 toBool((pfx & (PFX_66|PFX_F2|PFX_F3)) == PFX_F2);
653}
654
655/* Return True iff pfx has F3 set and 66 and F2 clear */
656static Bool haveF3no66noF2 ( Prefix pfx )
657{
658 return
659 toBool((pfx & (PFX_66|PFX_F2|PFX_F3)) == PFX_F3);
sewardj1001dc42005-02-21 08:25:55 +0000660}
661
662/* Return True iff pfx has 66, F2 and F3 clear */
663static Bool haveNo66noF2noF3 ( Prefix pfx )
664{
665 return
sewardj8d965312005-02-25 02:48:47 +0000666 toBool((pfx & (PFX_66|PFX_F2|PFX_F3)) == 0);
sewardj1001dc42005-02-21 08:25:55 +0000667}
668
sewardj8711f662005-05-09 17:52:56 +0000669/* Return True iff pfx has any of 66, F2 and F3 set */
670static Bool have66orF2orF3 ( Prefix pfx )
671{
sewardjca673ab2005-05-11 10:03:08 +0000672 return toBool( ! haveNo66noF2noF3(pfx) );
sewardj8711f662005-05-09 17:52:56 +0000673}
674
sewardj1389d4d2005-01-28 13:46:29 +0000675/* Clear all the segment-override bits in a prefix. */
676static Prefix clearSegBits ( Prefix p )
677{
sewardj1001dc42005-02-21 08:25:55 +0000678 return
679 p & ~(PFX_CS | PFX_DS | PFX_ES | PFX_FS | PFX_GS | PFX_SS);
680}
681
sewardj1389d4d2005-01-28 13:46:29 +0000682
sewardjecb94892005-01-21 14:26:37 +0000683/*------------------------------------------------------------*/
sewardj5b470602005-02-27 13:10:48 +0000684/*--- For dealing with integer registers ---*/
sewardjecb94892005-01-21 14:26:37 +0000685/*------------------------------------------------------------*/
686
sewardj5b470602005-02-27 13:10:48 +0000687/* This is somewhat complex. The rules are:
688
689 For 64, 32 and 16 bit register references, the e or g fields in the
690 modrm bytes supply the low 3 bits of the register number. The
691 fourth (most-significant) bit of the register number is supplied by
692 the REX byte, if it is present; else that bit is taken to be zero.
693
694 The REX.R bit supplies the high bit corresponding to the g register
695 field, and the REX.B bit supplies the high bit corresponding to the
696 e register field (when the mod part of modrm indicates that modrm's
697 e component refers to a register and not to memory).
698
699 The REX.X bit supplies a high register bit for certain registers
700 in SIB address modes, and is generally rarely used.
701
702 For 8 bit register references, the presence of the REX byte itself
703 has significance. If there is no REX present, then the 3-bit
704 number extracted from the modrm e or g field is treated as an index
705 into the sequence %al %cl %dl %bl %ah %ch %dh %bh -- that is, the
706 old x86 encoding scheme.
707
708 But if there is a REX present, the register reference is
709 interpreted in the same way as for 64/32/16-bit references: a high
710 bit is extracted from REX, giving a 4-bit number, and the denoted
711 register is the lowest 8 bits of the 16 integer registers denoted
712 by the number. In particular, values 3 through 7 of this sequence
713 do not refer to %ah %ch %dh %bh but instead to the lowest 8 bits of
714 %rsp %rbp %rsi %rdi.
715
716 The REX.W bit has no bearing at all on register numbers. Instead
717 its presence indicates that the operand size is to be overridden
718 from its default value (32 bits) to 64 bits instead. This is in
719 the same fashion that an 0x66 prefix indicates the operand size is
720 to be overridden from 32 bits down to 16 bits. When both REX.W and
721 0x66 are present there is a conflict, and REX.W takes precedence.
722
723 Rather than try to handle this complexity using a single huge
724 function, several smaller ones are provided. The aim is to make it
725 as difficult as possible to screw up register decoding in a subtle
726 and hard-to-track-down way.
727
728 Because these routines fish around in the host's memory (that is,
729 in the guest state area) for sub-parts of guest registers, their
730 correctness depends on the host's endianness. So far these
731 routines only work for little-endian hosts. Those for which
732 endianness is important have assertions to ensure sanity.
733*/
sewardjecb94892005-01-21 14:26:37 +0000734
735
sewardj5b470602005-02-27 13:10:48 +0000736/* About the simplest question you can ask: where do the 64-bit
737 integer registers live (in the guest state) ? */
sewardjecb94892005-01-21 14:26:37 +0000738
sewardj3ca55a12005-01-27 16:06:23 +0000739static Int integerGuestReg64Offset ( UInt reg )
sewardjb3a04292005-01-21 20:33:44 +0000740{
741 switch (reg) {
742 case R_RAX: return OFFB_RAX;
743 case R_RCX: return OFFB_RCX;
744 case R_RDX: return OFFB_RDX;
745 case R_RBX: return OFFB_RBX;
746 case R_RSP: return OFFB_RSP;
747 case R_RBP: return OFFB_RBP;
748 case R_RSI: return OFFB_RSI;
749 case R_RDI: return OFFB_RDI;
750 case R_R8: return OFFB_R8;
751 case R_R9: return OFFB_R9;
752 case R_R10: return OFFB_R10;
753 case R_R11: return OFFB_R11;
754 case R_R12: return OFFB_R12;
755 case R_R13: return OFFB_R13;
756 case R_R14: return OFFB_R14;
757 case R_R15: return OFFB_R15;
758 default: vpanic("integerGuestReg64Offset(amd64)");
759 }
760}
761
762
sewardj5b470602005-02-27 13:10:48 +0000763/* Produce the name of an integer register, for printing purposes.
764 reg is a number in the range 0 .. 15 that has been generated from a
765 3-bit reg-field number and a REX extension bit. irregular denotes
766 the case where sz==1 and no REX byte is present. */
sewardjecb94892005-01-21 14:26:37 +0000767
768static
sewardj5b470602005-02-27 13:10:48 +0000769HChar* nameIReg ( Int sz, UInt reg, Bool irregular )
sewardjecb94892005-01-21 14:26:37 +0000770{
sewardjecb94892005-01-21 14:26:37 +0000771 static HChar* ireg64_names[16]
772 = { "%rax", "%rcx", "%rdx", "%rbx", "%rsp", "%rbp", "%rsi", "%rdi",
773 "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15" };
774 static HChar* ireg32_names[16]
775 = { "%eax", "%ecx", "%edx", "%ebx", "%esp", "%ebp", "%esi", "%edi",
776 "%r8d", "%r9d", "%r10d","%r11d","%r12d","%r13d","%r14d","%r15d" };
777 static HChar* ireg16_names[16]
778 = { "%ax", "%cx", "%dx", "%bx", "%sp", "%bp", "%si", "%di",
779 "%r8w", "%r9w", "%r10w","%r11w","%r12w","%r13w","%r14w","%r15w" };
780 static HChar* ireg8_names[16]
781 = { "%al", "%cl", "%dl", "%bl", "%spl", "%bpl", "%sil", "%dil",
782 "%r8b", "%r9b", "%r10b","%r11b","%r12b","%r13b","%r14b","%r15b" };
sewardj5b470602005-02-27 13:10:48 +0000783 static HChar* ireg8_irregular[8]
sewardjecb94892005-01-21 14:26:37 +0000784 = { "%al", "%cl", "%dl", "%bl", "%ah", "%ch", "%dh", "%bh" };
785
sewardj5b470602005-02-27 13:10:48 +0000786 vassert(reg < 16);
787 if (sz == 1) {
788 if (irregular)
789 vassert(reg < 8);
790 } else {
791 vassert(irregular == False);
792 }
sewardjecb94892005-01-21 14:26:37 +0000793
794 switch (sz) {
sewardj5b470602005-02-27 13:10:48 +0000795 case 8: return ireg64_names[reg];
796 case 4: return ireg32_names[reg];
797 case 2: return ireg16_names[reg];
798 case 1: if (irregular) {
799 return ireg8_irregular[reg];
800 } else {
801 return ireg8_names[reg];
802 }
803 default: vpanic("nameIReg(amd64)");
sewardjecb94892005-01-21 14:26:37 +0000804 }
sewardjecb94892005-01-21 14:26:37 +0000805}
806
sewardj5b470602005-02-27 13:10:48 +0000807/* Using the same argument conventions as nameIReg, produce the
808 guest state offset of an integer register. */
sewardjb3a04292005-01-21 20:33:44 +0000809
sewardjecb94892005-01-21 14:26:37 +0000810static
sewardj5b470602005-02-27 13:10:48 +0000811Int offsetIReg ( Int sz, UInt reg, Bool irregular )
sewardjecb94892005-01-21 14:26:37 +0000812{
sewardj5b470602005-02-27 13:10:48 +0000813 vassert(reg < 16);
814 if (sz == 1) {
815 if (irregular)
816 vassert(reg < 8);
817 } else {
818 vassert(irregular == False);
sewardjecb94892005-01-21 14:26:37 +0000819 }
sewardj5b470602005-02-27 13:10:48 +0000820
821 /* Deal with irregular case -- sz==1 and no REX present */
822 if (sz == 1 && irregular) {
823 switch (reg) {
824 case R_RSP: return 1+ OFFB_RAX;
825 case R_RBP: return 1+ OFFB_RCX;
826 case R_RSI: return 1+ OFFB_RDX;
827 case R_RDI: return 1+ OFFB_RBX;
828 default: break; /* use the normal case */
829 }
sewardjecb94892005-01-21 14:26:37 +0000830 }
sewardj5b470602005-02-27 13:10:48 +0000831
832 /* Normal case */
833 return integerGuestReg64Offset(reg);
sewardjecb94892005-01-21 14:26:37 +0000834}
835
836
sewardj5b470602005-02-27 13:10:48 +0000837/* Read the %CL register :: Ity_I8, for shift/rotate operations. */
838
839static IRExpr* getIRegCL ( void )
840{
841 vassert(!host_is_bigendian);
842 return IRExpr_Get( OFFB_RCX, Ity_I8 );
843}
844
845
846/* Write to the %AH register. */
847
848static void putIRegAH ( IRExpr* e )
849{
850 vassert(!host_is_bigendian);
851 vassert(typeOfIRExpr(irbb->tyenv, e) == Ity_I8);
852 stmt( IRStmt_Put( OFFB_RAX+1, e ) );
853}
854
855
856/* Read/write various widths of %RAX, as it has various
857 special-purpose uses. */
858
859static HChar* nameIRegRAX ( Int sz )
860{
861 switch (sz) {
862 case 1: return "%al";
863 case 2: return "%ax";
864 case 4: return "%eax";
865 case 8: return "%rax";
866 default: vpanic("nameIRegRAX(amd64)");
867 }
868}
869
870static IRExpr* getIRegRAX ( Int sz )
871{
872 vassert(!host_is_bigendian);
873 switch (sz) {
874 case 1: return IRExpr_Get( OFFB_RAX, Ity_I8 );
875 case 2: return IRExpr_Get( OFFB_RAX, Ity_I16 );
876 case 4: return IRExpr_Get( OFFB_RAX, Ity_I32 );
877 case 8: return IRExpr_Get( OFFB_RAX, Ity_I64 );
878 default: vpanic("getIRegRAX(amd64)");
879 }
880}
881
882static void putIRegRAX ( Int sz, IRExpr* e )
883{
884 IRType ty = typeOfIRExpr(irbb->tyenv, e);
885 vassert(!host_is_bigendian);
886 switch (sz) {
887 case 8: vassert(ty == Ity_I64);
888 stmt( IRStmt_Put( OFFB_RAX, e ));
889 break;
890 case 4: vassert(ty == Ity_I32);
891 stmt( IRStmt_Put( OFFB_RAX, unop(Iop_32Uto64,e) ));
892 break;
893 case 2: vassert(ty == Ity_I16);
894 stmt( IRStmt_Put( OFFB_RAX, e ));
895 break;
896 case 1: vassert(ty == Ity_I8);
897 stmt( IRStmt_Put( OFFB_RAX, e ));
898 break;
899 default: vpanic("putIRegRAX(amd64)");
900 }
901}
902
903
904/* Read/write various widths of %RDX, as it has various
905 special-purpose uses. */
906
907static IRExpr* getIRegRDX ( Int sz )
908{
909 vassert(!host_is_bigendian);
910 switch (sz) {
911 case 1: return IRExpr_Get( OFFB_RDX, Ity_I8 );
912 case 2: return IRExpr_Get( OFFB_RDX, Ity_I16 );
913 case 4: return IRExpr_Get( OFFB_RDX, Ity_I32 );
914 case 8: return IRExpr_Get( OFFB_RDX, Ity_I64 );
915 default: vpanic("getIRegRDX(amd64)");
916 }
917}
918
919static void putIRegRDX ( Int sz, IRExpr* e )
920{
921 vassert(!host_is_bigendian);
922 vassert(typeOfIRExpr(irbb->tyenv, e) == szToITy(sz));
923 switch (sz) {
924 case 8: stmt( IRStmt_Put( OFFB_RDX, e ));
925 break;
926 case 4: stmt( IRStmt_Put( OFFB_RDX, unop(Iop_32Uto64,e) ));
927 break;
928 case 2: stmt( IRStmt_Put( OFFB_RDX, e ));
929 break;
930 case 1: stmt( IRStmt_Put( OFFB_RDX, e ));
931 break;
932 default: vpanic("putIRegRDX(amd64)");
933 }
934}
935
936
937/* Simplistic functions to deal with the integer registers as a
938 straightforward bank of 16 64-bit regs. */
sewardjb3a04292005-01-21 20:33:44 +0000939
940static IRExpr* getIReg64 ( UInt regno )
941{
942 return IRExpr_Get( integerGuestReg64Offset(regno),
943 Ity_I64 );
944}
945
sewardj2f959cc2005-01-26 01:19:35 +0000946static void putIReg64 ( UInt regno, IRExpr* e )
947{
948 vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_I64);
949 stmt( IRStmt_Put( integerGuestReg64Offset(regno), e ) );
950}
951
sewardjb3a04292005-01-21 20:33:44 +0000952static HChar* nameIReg64 ( UInt regno )
953{
sewardj5b470602005-02-27 13:10:48 +0000954 return nameIReg( 8, regno, False );
sewardjb3a04292005-01-21 20:33:44 +0000955}
sewardj5b470602005-02-27 13:10:48 +0000956
957
958/* Simplistic functions to deal with the lower halves of integer
959 registers as a straightforward bank of 16 32-bit regs. */
960
961static IRExpr* getIReg32 ( UInt regno )
962{
963 vassert(!host_is_bigendian);
964 return IRExpr_Get( integerGuestReg64Offset(regno),
965 Ity_I32 );
966}
967
968static void putIReg32 ( UInt regno, IRExpr* e )
969{
970 vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_I32);
971 stmt( IRStmt_Put( integerGuestReg64Offset(regno),
972 unop(Iop_32Uto64,e) ) );
973}
974
975static HChar* nameIReg32 ( UInt regno )
976{
977 return nameIReg( 4, regno, False );
978}
979
980
sewardja7ba8c42005-05-10 20:08:34 +0000981/* Simplistic functions to deal with the lower quarters of integer
982 registers as a straightforward bank of 16 16-bit regs. */
983
984static IRExpr* getIReg16 ( UInt regno )
985{
986 vassert(!host_is_bigendian);
987 return IRExpr_Get( integerGuestReg64Offset(regno),
988 Ity_I16 );
989}
990
991static HChar* nameIReg16 ( UInt regno )
992{
993 return nameIReg( 2, regno, False );
994}
995
996
sewardj5b470602005-02-27 13:10:48 +0000997/* Sometimes what we know is a 3-bit register number, a REX byte, and
998 which field of the REX byte is to be used to extend to a 4-bit
999 number. These functions cater for that situation.
1000*/
1001static IRExpr* getIReg64rexX ( Prefix pfx, UInt lo3bits )
1002{
1003 vassert(lo3bits < 8);
1004 vassert(IS_VALID_PFX(pfx));
1005 return getIReg64( lo3bits | (getRexX(pfx) << 3) );
1006}
1007
1008static HChar* nameIReg64rexX ( Prefix pfx, UInt lo3bits )
1009{
1010 vassert(lo3bits < 8);
1011 vassert(IS_VALID_PFX(pfx));
1012 return nameIReg( 8, lo3bits | (getRexX(pfx) << 3), False );
1013}
1014
1015static HChar* nameIRegRexB ( Int sz, Prefix pfx, UInt lo3bits )
1016{
1017 vassert(lo3bits < 8);
1018 vassert(IS_VALID_PFX(pfx));
1019 vassert(sz == 8 || sz == 4 || sz == 2 || sz == 1);
1020 return nameIReg( sz, lo3bits | (getRexB(pfx) << 3),
sewardj397f88b2005-02-27 13:39:25 +00001021 toBool(sz==1 && !haveREX(pfx)) );
sewardj5b470602005-02-27 13:10:48 +00001022}
1023
1024static IRExpr* getIRegRexB ( Int sz, Prefix pfx, UInt lo3bits )
1025{
1026 vassert(lo3bits < 8);
1027 vassert(IS_VALID_PFX(pfx));
1028 vassert(sz == 8 || sz == 4 || sz == 2 || sz == 1);
1029 return IRExpr_Get(
1030 offsetIReg( sz, lo3bits | (getRexB(pfx) << 3),
sewardj397f88b2005-02-27 13:39:25 +00001031 toBool(sz==1 && !haveREX(pfx)) ),
sewardj5b470602005-02-27 13:10:48 +00001032 szToITy(sz)
1033 );
1034}
1035
1036static void putIRegRexB ( Int sz, Prefix pfx, UInt lo3bits, IRExpr* e )
1037{
1038 vassert(lo3bits < 8);
1039 vassert(IS_VALID_PFX(pfx));
sewardj98e9f342005-07-23 12:07:37 +00001040 vassert(sz == 8 || sz == 4 || sz == 2 || sz == 1);
sewardj5b470602005-02-27 13:10:48 +00001041 vassert(typeOfIRExpr(irbb->tyenv, e) == szToITy(sz));
1042 stmt( IRStmt_Put(
1043 offsetIReg( sz, lo3bits | (getRexB(pfx) << 3),
sewardj397f88b2005-02-27 13:39:25 +00001044 toBool(sz==1 && !haveREX(pfx)) ),
sewardj5b470602005-02-27 13:10:48 +00001045 sz==4 ? unop(Iop_32Uto64,e) : e
1046 ));
1047}
1048
1049
1050/* Functions for getting register numbers from modrm bytes and REX
1051 when we don't have to consider the complexities of integer subreg
1052 accesses.
1053*/
1054/* Extract the g reg field from a modRM byte, and augment it using the
1055 REX.R bit from the supplied REX byte. The R bit usually is
1056 associated with the g register field.
1057*/
1058static UInt gregOfRexRM ( Prefix pfx, UChar mod_reg_rm )
1059{
1060 Int reg = (Int)( (mod_reg_rm >> 3) & 7 );
1061 reg += (pfx & PFX_REXR) ? 8 : 0;
1062 return reg;
1063}
1064
1065/* Extract the e reg field from a modRM byte, and augment it using the
1066 REX.B bit from the supplied REX byte. The B bit usually is
1067 associated with the e register field (when modrm indicates e is a
1068 register, that is).
1069*/
1070static UInt eregOfRexRM ( Prefix pfx, UChar mod_reg_rm )
1071{
1072 Int rm;
1073 vassert(epartIsReg(mod_reg_rm));
1074 rm = (Int)(mod_reg_rm & 0x7);
1075 rm += (pfx & PFX_REXB) ? 8 : 0;
1076 return rm;
1077}
1078
1079
1080/* General functions for dealing with integer register access. */
1081
1082/* Produce the guest state offset for a reference to the 'g' register
1083 field in a modrm byte, taking into account REX (or its absence),
1084 and the size of the access.
1085*/
1086static UInt offsetIRegG ( Int sz, Prefix pfx, UChar mod_reg_rm )
1087{
1088 UInt reg;
1089 vassert(!host_is_bigendian);
1090 vassert(IS_VALID_PFX(pfx));
1091 vassert(sz == 8 || sz == 4 || sz == 2 || sz == 1);
1092 reg = gregOfRexRM( pfx, mod_reg_rm );
sewardj397f88b2005-02-27 13:39:25 +00001093 return offsetIReg( sz, reg, toBool(sz == 1 && !haveREX(pfx)) );
sewardj5b470602005-02-27 13:10:48 +00001094}
1095
1096static
1097IRExpr* getIRegG ( Int sz, Prefix pfx, UChar mod_reg_rm )
1098{
1099 return IRExpr_Get( offsetIRegG( sz, pfx, mod_reg_rm ),
1100 szToITy(sz) );
1101}
1102
1103static
1104void putIRegG ( Int sz, Prefix pfx, UChar mod_reg_rm, IRExpr* e )
1105{
1106 vassert(typeOfIRExpr(irbb->tyenv,e) == szToITy(sz));
1107 if (sz == 4) {
1108 e = unop(Iop_32Uto64,e);
1109 }
1110 stmt( IRStmt_Put( offsetIRegG( sz, pfx, mod_reg_rm ), e ) );
1111}
1112
1113static
1114HChar* nameIRegG ( Int sz, Prefix pfx, UChar mod_reg_rm )
1115{
1116 return nameIReg( sz, gregOfRexRM(pfx,mod_reg_rm),
sewardj397f88b2005-02-27 13:39:25 +00001117 toBool(sz==1 && !haveREX(pfx)) );
sewardj5b470602005-02-27 13:10:48 +00001118}
1119
1120
1121/* Produce the guest state offset for a reference to the 'e' register
1122 field in a modrm byte, taking into account REX (or its absence),
1123 and the size of the access. eregOfRexRM will assert if mod_reg_rm
1124 denotes a memory access rather than a register access.
1125*/
1126static UInt offsetIRegE ( Int sz, Prefix pfx, UChar mod_reg_rm )
1127{
1128 UInt reg;
1129 vassert(!host_is_bigendian);
1130 vassert(IS_VALID_PFX(pfx));
1131 vassert(sz == 8 || sz == 4 || sz == 2 || sz == 1);
1132 reg = eregOfRexRM( pfx, mod_reg_rm );
sewardj397f88b2005-02-27 13:39:25 +00001133 return offsetIReg( sz, reg, toBool(sz == 1 && !haveREX(pfx)) );
sewardj5b470602005-02-27 13:10:48 +00001134}
1135
1136static
1137IRExpr* getIRegE ( Int sz, Prefix pfx, UChar mod_reg_rm )
1138{
1139 return IRExpr_Get( offsetIRegE( sz, pfx, mod_reg_rm ),
1140 szToITy(sz) );
1141}
1142
1143static
1144void putIRegE ( Int sz, Prefix pfx, UChar mod_reg_rm, IRExpr* e )
1145{
1146 vassert(typeOfIRExpr(irbb->tyenv,e) == szToITy(sz));
1147 if (sz == 4) {
1148 e = unop(Iop_32Uto64,e);
1149 }
1150 stmt( IRStmt_Put( offsetIRegE( sz, pfx, mod_reg_rm ), e ) );
1151}
1152
1153static
1154HChar* nameIRegE ( Int sz, Prefix pfx, UChar mod_reg_rm )
1155{
1156 return nameIReg( sz, eregOfRexRM(pfx,mod_reg_rm),
sewardj397f88b2005-02-27 13:39:25 +00001157 toBool(sz==1 && !haveREX(pfx)) );
sewardj5b470602005-02-27 13:10:48 +00001158}
1159
1160
1161/*------------------------------------------------------------*/
1162/*--- For dealing with XMM registers ---*/
1163/*------------------------------------------------------------*/
sewardjecb94892005-01-21 14:26:37 +00001164
sewardjd20c8852005-01-20 20:04:07 +00001165//.. static Int segmentGuestRegOffset ( UInt sreg )
1166//.. {
1167//.. switch (sreg) {
1168//.. case R_ES: return OFFB_ES;
1169//.. case R_CS: return OFFB_CS;
1170//.. case R_SS: return OFFB_SS;
1171//.. case R_DS: return OFFB_DS;
1172//.. case R_FS: return OFFB_FS;
1173//.. case R_GS: return OFFB_GS;
1174//.. default: vpanic("segmentGuestRegOffset(x86)");
1175//.. }
1176//.. }
sewardj1001dc42005-02-21 08:25:55 +00001177
1178static Int xmmGuestRegOffset ( UInt xmmreg )
1179{
1180 switch (xmmreg) {
1181 case 0: return OFFB_XMM0;
1182 case 1: return OFFB_XMM1;
1183 case 2: return OFFB_XMM2;
1184 case 3: return OFFB_XMM3;
1185 case 4: return OFFB_XMM4;
1186 case 5: return OFFB_XMM5;
1187 case 6: return OFFB_XMM6;
1188 case 7: return OFFB_XMM7;
1189 case 8: return OFFB_XMM8;
1190 case 9: return OFFB_XMM9;
1191 case 10: return OFFB_XMM10;
1192 case 11: return OFFB_XMM11;
1193 case 12: return OFFB_XMM12;
1194 case 13: return OFFB_XMM13;
1195 case 14: return OFFB_XMM14;
1196 case 15: return OFFB_XMM15;
1197 default: vpanic("xmmGuestRegOffset(amd64)");
1198 }
1199}
1200
sewardj97628592005-05-10 22:42:54 +00001201/* Lanes of vector registers are always numbered from zero being the
1202 least significant lane (rightmost in the register). */
1203
1204static Int xmmGuestRegLane16offset ( UInt xmmreg, Int laneno )
1205{
1206 /* Correct for little-endian host only. */
1207 vassert(!host_is_bigendian);
1208 vassert(laneno >= 0 && laneno < 8);
1209 return xmmGuestRegOffset( xmmreg ) + 2 * laneno;
1210}
sewardj8d965312005-02-25 02:48:47 +00001211
1212static Int xmmGuestRegLane32offset ( UInt xmmreg, Int laneno )
1213{
1214 /* Correct for little-endian host only. */
1215 vassert(!host_is_bigendian);
1216 vassert(laneno >= 0 && laneno < 4);
1217 return xmmGuestRegOffset( xmmreg ) + 4 * laneno;
1218}
sewardj1001dc42005-02-21 08:25:55 +00001219
1220static Int xmmGuestRegLane64offset ( UInt xmmreg, Int laneno )
1221{
1222 /* Correct for little-endian host only. */
1223 vassert(!host_is_bigendian);
1224 vassert(laneno >= 0 && laneno < 2);
1225 return xmmGuestRegOffset( xmmreg ) + 8 * laneno;
1226}
1227
sewardjd20c8852005-01-20 20:04:07 +00001228//.. static IRExpr* getSReg ( UInt sreg )
1229//.. {
1230//.. return IRExpr_Get( segmentGuestRegOffset(sreg), Ity_I16 );
1231//.. }
1232//..
1233//.. static void putSReg ( UInt sreg, IRExpr* e )
1234//.. {
1235//.. vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_I16);
1236//.. stmt( IRStmt_Put( segmentGuestRegOffset(sreg), e ) );
1237//.. }
sewardj1001dc42005-02-21 08:25:55 +00001238
1239static IRExpr* getXMMReg ( UInt xmmreg )
1240{
1241 return IRExpr_Get( xmmGuestRegOffset(xmmreg), Ity_V128 );
1242}
1243
1244static IRExpr* getXMMRegLane64 ( UInt xmmreg, Int laneno )
1245{
1246 return IRExpr_Get( xmmGuestRegLane64offset(xmmreg,laneno), Ity_I64 );
1247}
1248
sewardj18303862005-02-21 12:36:54 +00001249static IRExpr* getXMMRegLane64F ( UInt xmmreg, Int laneno )
1250{
1251 return IRExpr_Get( xmmGuestRegLane64offset(xmmreg,laneno), Ity_F64 );
1252}
1253
sewardj8d965312005-02-25 02:48:47 +00001254static IRExpr* getXMMRegLane32 ( UInt xmmreg, Int laneno )
1255{
1256 return IRExpr_Get( xmmGuestRegLane32offset(xmmreg,laneno), Ity_I32 );
1257}
1258
sewardjc49ce232005-02-25 13:03:03 +00001259static IRExpr* getXMMRegLane32F ( UInt xmmreg, Int laneno )
1260{
1261 return IRExpr_Get( xmmGuestRegLane32offset(xmmreg,laneno), Ity_F32 );
1262}
sewardj1001dc42005-02-21 08:25:55 +00001263
1264static void putXMMReg ( UInt xmmreg, IRExpr* e )
1265{
1266 vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_V128);
1267 stmt( IRStmt_Put( xmmGuestRegOffset(xmmreg), e ) );
1268}
1269
1270static void putXMMRegLane64 ( UInt xmmreg, Int laneno, IRExpr* e )
1271{
1272 vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_I64);
1273 stmt( IRStmt_Put( xmmGuestRegLane64offset(xmmreg,laneno), e ) );
1274}
1275
sewardj1a01e652005-02-23 11:39:21 +00001276static void putXMMRegLane64F ( UInt xmmreg, Int laneno, IRExpr* e )
1277{
1278 vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_F64);
1279 stmt( IRStmt_Put( xmmGuestRegLane64offset(xmmreg,laneno), e ) );
1280}
1281
sewardj8d965312005-02-25 02:48:47 +00001282static void putXMMRegLane32F ( UInt xmmreg, Int laneno, IRExpr* e )
1283{
1284 vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_F32);
1285 stmt( IRStmt_Put( xmmGuestRegLane32offset(xmmreg,laneno), e ) );
1286}
1287
1288static void putXMMRegLane32 ( UInt xmmreg, Int laneno, IRExpr* e )
1289{
1290 vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_I32);
1291 stmt( IRStmt_Put( xmmGuestRegLane32offset(xmmreg,laneno), e ) );
1292}
1293
sewardj97628592005-05-10 22:42:54 +00001294static void putXMMRegLane16 ( UInt xmmreg, Int laneno, IRExpr* e )
1295{
1296 vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_I16);
1297 stmt( IRStmt_Put( xmmGuestRegLane16offset(xmmreg,laneno), e ) );
1298}
sewardj3ca55a12005-01-27 16:06:23 +00001299
sewardj1001dc42005-02-21 08:25:55 +00001300static IRExpr* mkV128 ( UShort mask )
1301{
1302 return IRExpr_Const(IRConst_V128(mask));
1303}
sewardjdf0e0022005-01-25 15:48:43 +00001304
sewardje8f65252005-08-23 23:44:35 +00001305static IRExpr* mkAnd1 ( IRExpr* x, IRExpr* y )
1306{
1307 vassert(typeOfIRExpr(irbb->tyenv,x) == Ity_I1);
1308 vassert(typeOfIRExpr(irbb->tyenv,y) == Ity_I1);
1309 return unop(Iop_64to1,
1310 binop(Iop_And64,
1311 unop(Iop_1Uto64,x),
1312 unop(Iop_1Uto64,y)));
1313}
1314
sewardj5b470602005-02-27 13:10:48 +00001315
sewardj118b23e2005-01-29 02:14:44 +00001316/*------------------------------------------------------------*/
sewardje8f65252005-08-23 23:44:35 +00001317/*--- Helpers for %rflags. ---*/
sewardj118b23e2005-01-29 02:14:44 +00001318/*------------------------------------------------------------*/
1319
1320/* -------------- Evaluating the flags-thunk. -------------- */
1321
1322/* Build IR to calculate all the eflags from stored
1323 CC_OP/CC_DEP1/CC_DEP2/CC_NDEP. Returns an expression ::
1324 Ity_I64. */
1325static IRExpr* mk_amd64g_calculate_rflags_all ( void )
1326{
1327 IRExpr** args
1328 = mkIRExprVec_4( IRExpr_Get(OFFB_CC_OP, Ity_I64),
1329 IRExpr_Get(OFFB_CC_DEP1, Ity_I64),
1330 IRExpr_Get(OFFB_CC_DEP2, Ity_I64),
1331 IRExpr_Get(OFFB_CC_NDEP, Ity_I64) );
1332 IRExpr* call
1333 = mkIRExprCCall(
1334 Ity_I64,
1335 0/*regparm*/,
1336 "amd64g_calculate_rflags_all", &amd64g_calculate_rflags_all,
1337 args
1338 );
1339 /* Exclude OP and NDEP from definedness checking. We're only
1340 interested in DEP1 and DEP2. */
1341 call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<3);
1342 return call;
1343}
sewardj3ca55a12005-01-27 16:06:23 +00001344
1345/* Build IR to calculate some particular condition from stored
1346 CC_OP/CC_DEP1/CC_DEP2/CC_NDEP. Returns an expression ::
1347 Ity_Bit. */
1348static IRExpr* mk_amd64g_calculate_condition ( AMD64Condcode cond )
1349{
1350 IRExpr** args
1351 = mkIRExprVec_5( mkU64(cond),
1352 IRExpr_Get(OFFB_CC_OP, Ity_I64),
1353 IRExpr_Get(OFFB_CC_DEP1, Ity_I64),
1354 IRExpr_Get(OFFB_CC_DEP2, Ity_I64),
1355 IRExpr_Get(OFFB_CC_NDEP, Ity_I64) );
1356 IRExpr* call
1357 = mkIRExprCCall(
1358 Ity_I64,
1359 0/*regparm*/,
1360 "amd64g_calculate_condition", &amd64g_calculate_condition,
1361 args
1362 );
1363 /* Exclude the requested condition, OP and NDEP from definedness
1364 checking. We're only interested in DEP1 and DEP2. */
1365 call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<1) | (1<<4);
sewardje58967e2005-04-27 11:50:56 +00001366 return unop(Iop_64to1, call);
sewardj3ca55a12005-01-27 16:06:23 +00001367}
sewardjdf0e0022005-01-25 15:48:43 +00001368
1369/* Build IR to calculate just the carry flag from stored
1370 CC_OP/CC_DEP1/CC_DEP2/CC_NDEP. Returns an expression :: Ity_I64. */
1371static IRExpr* mk_amd64g_calculate_rflags_c ( void )
1372{
1373 IRExpr** args
1374 = mkIRExprVec_4( IRExpr_Get(OFFB_CC_OP, Ity_I64),
1375 IRExpr_Get(OFFB_CC_DEP1, Ity_I64),
1376 IRExpr_Get(OFFB_CC_DEP2, Ity_I64),
1377 IRExpr_Get(OFFB_CC_NDEP, Ity_I64) );
1378 IRExpr* call
1379 = mkIRExprCCall(
1380 Ity_I64,
1381 0/*regparm*/,
1382 "amd64g_calculate_rflags_c", &amd64g_calculate_rflags_c,
1383 args
1384 );
1385 /* Exclude OP and NDEP from definedness checking. We're only
1386 interested in DEP1 and DEP2. */
1387 call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<3);
1388 return call;
1389}
1390
1391
1392/* -------------- Building the flags-thunk. -------------- */
1393
1394/* The machinery in this section builds the flag-thunk following a
1395 flag-setting operation. Hence the various setFlags_* functions.
1396*/
1397
1398static Bool isAddSub ( IROp op8 )
1399{
sewardj7a240552005-01-28 21:37:12 +00001400 return toBool(op8 == Iop_Add8 || op8 == Iop_Sub8);
sewardjdf0e0022005-01-25 15:48:43 +00001401}
1402
sewardj3ca55a12005-01-27 16:06:23 +00001403static Bool isLogic ( IROp op8 )
1404{
sewardj7a240552005-01-28 21:37:12 +00001405 return toBool(op8 == Iop_And8 || op8 == Iop_Or8 || op8 == Iop_Xor8);
sewardj3ca55a12005-01-27 16:06:23 +00001406}
sewardjdf0e0022005-01-25 15:48:43 +00001407
1408/* U-widen 8/16/32/64 bit int expr to 64. */
1409static IRExpr* widenUto64 ( IRExpr* e )
1410{
1411 switch (typeOfIRExpr(irbb->tyenv,e)) {
1412 case Ity_I64: return e;
1413 case Ity_I32: return unop(Iop_32Uto64, e);
sewardje58967e2005-04-27 11:50:56 +00001414 case Ity_I16: return unop(Iop_16Uto64, e);
1415 case Ity_I8: return unop(Iop_8Uto64, e);
sewardj118b23e2005-01-29 02:14:44 +00001416 default: vpanic("widenUto64");
sewardjdf0e0022005-01-25 15:48:43 +00001417 }
1418}
1419
sewardj118b23e2005-01-29 02:14:44 +00001420/* S-widen 8/16/32/64 bit int expr to 32. */
1421static IRExpr* widenSto64 ( IRExpr* e )
1422{
1423 switch (typeOfIRExpr(irbb->tyenv,e)) {
1424 case Ity_I64: return e;
1425 case Ity_I32: return unop(Iop_32Sto64, e);
sewardje58967e2005-04-27 11:50:56 +00001426 case Ity_I16: return unop(Iop_16Sto64, e);
1427 case Ity_I8: return unop(Iop_8Sto64, e);
sewardj118b23e2005-01-29 02:14:44 +00001428 default: vpanic("widenSto64");
1429 }
1430}
sewardjdf0e0022005-01-25 15:48:43 +00001431
1432/* Narrow 8/16/32/64 bit int expr to 8/16/32/64. Clearly only some
1433 of these combinations make sense. */
1434static IRExpr* narrowTo ( IRType dst_ty, IRExpr* e )
1435{
1436 IRType src_ty = typeOfIRExpr(irbb->tyenv,e);
1437 if (src_ty == dst_ty)
1438 return e;
1439 if (src_ty == Ity_I32 && dst_ty == Ity_I16)
1440 return unop(Iop_32to16, e);
1441 if (src_ty == Ity_I32 && dst_ty == Ity_I8)
1442 return unop(Iop_32to8, e);
sewardj118b23e2005-01-29 02:14:44 +00001443 if (src_ty == Ity_I64 && dst_ty == Ity_I32)
1444 return unop(Iop_64to32, e);
1445 if (src_ty == Ity_I64 && dst_ty == Ity_I16)
sewardje58967e2005-04-27 11:50:56 +00001446 return unop(Iop_64to16, e);
sewardj03b07cc2005-01-31 18:09:43 +00001447 if (src_ty == Ity_I64 && dst_ty == Ity_I8)
sewardje58967e2005-04-27 11:50:56 +00001448 return unop(Iop_64to8, e);
sewardjdf0e0022005-01-25 15:48:43 +00001449
1450 vex_printf("\nsrc, dst tys are: ");
1451 ppIRType(src_ty);
1452 vex_printf(", ");
1453 ppIRType(dst_ty);
1454 vex_printf("\n");
1455 vpanic("narrowTo(amd64)");
1456}
1457
1458
1459/* Set the flags thunk OP, DEP1 and DEP2 fields. The supplied op is
1460 auto-sized up to the real op. */
1461
1462static
1463void setFlags_DEP1_DEP2 ( IROp op8, IRTemp dep1, IRTemp dep2, IRType ty )
1464{
1465 Int ccOp = 0;
1466 switch (ty) {
1467 case Ity_I8: ccOp = 0; break;
1468 case Ity_I16: ccOp = 1; break;
1469 case Ity_I32: ccOp = 2; break;
1470 case Ity_I64: ccOp = 3; break;
1471 default: vassert(0);
1472 }
1473 switch (op8) {
1474 case Iop_Add8: ccOp += AMD64G_CC_OP_ADDB; break;
1475 case Iop_Sub8: ccOp += AMD64G_CC_OP_SUBB; break;
1476 default: ppIROp(op8);
1477 vpanic("setFlags_DEP1_DEP2(amd64)");
1478 }
1479 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(ccOp)) );
1480 stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto64(mkexpr(dep1))) );
1481 stmt( IRStmt_Put( OFFB_CC_DEP2, widenUto64(mkexpr(dep2))) );
1482}
1483
1484
1485/* Set the OP and DEP1 fields only, and write zero to DEP2. */
1486
1487static
1488void setFlags_DEP1 ( IROp op8, IRTemp dep1, IRType ty )
1489{
1490 Int ccOp = 0;
1491 switch (ty) {
1492 case Ity_I8: ccOp = 0; break;
1493 case Ity_I16: ccOp = 1; break;
1494 case Ity_I32: ccOp = 2; break;
1495 case Ity_I64: ccOp = 3; break;
1496 default: vassert(0);
1497 }
1498 switch (op8) {
1499 case Iop_Or8:
1500 case Iop_And8:
1501 case Iop_Xor8: ccOp += AMD64G_CC_OP_LOGICB; break;
1502 default: ppIROp(op8);
1503 vpanic("setFlags_DEP1(amd64)");
1504 }
1505 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(ccOp)) );
1506 stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto64(mkexpr(dep1))) );
1507 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0)) );
1508}
1509
1510
sewardj118b23e2005-01-29 02:14:44 +00001511/* For shift operations, we put in the result and the undershifted
1512 result. Except if the shift amount is zero, the thunk is left
1513 unchanged. */
1514
1515static void setFlags_DEP1_DEP2_shift ( IROp op64,
1516 IRTemp res,
1517 IRTemp resUS,
1518 IRType ty,
1519 IRTemp guard )
1520{
1521 Int ccOp = 0;
1522 switch (ty) {
1523 case Ity_I8: ccOp = 0; break;
1524 case Ity_I16: ccOp = 1; break;
1525 case Ity_I32: ccOp = 2; break;
1526 case Ity_I64: ccOp = 3; break;
1527 default: vassert(0);
1528 }
1529
1530 vassert(guard);
1531
1532 /* Both kinds of right shifts are handled by the same thunk
1533 operation. */
1534 switch (op64) {
1535 case Iop_Shr64:
1536 case Iop_Sar64: ccOp += AMD64G_CC_OP_SHRB; break;
1537 case Iop_Shl64: ccOp += AMD64G_CC_OP_SHLB; break;
1538 default: ppIROp(op64);
1539 vpanic("setFlags_DEP1_DEP2_shift(amd64)");
1540 }
1541
1542 /* DEP1 contains the result, DEP2 contains the undershifted value. */
1543 stmt( IRStmt_Put( OFFB_CC_OP,
1544 IRExpr_Mux0X( mkexpr(guard),
1545 IRExpr_Get(OFFB_CC_OP,Ity_I64),
1546 mkU64(ccOp))) );
1547 stmt( IRStmt_Put( OFFB_CC_DEP1,
1548 IRExpr_Mux0X( mkexpr(guard),
1549 IRExpr_Get(OFFB_CC_DEP1,Ity_I64),
1550 widenUto64(mkexpr(res)))) );
1551 stmt( IRStmt_Put( OFFB_CC_DEP2,
1552 IRExpr_Mux0X( mkexpr(guard),
1553 IRExpr_Get(OFFB_CC_DEP2,Ity_I64),
1554 widenUto64(mkexpr(resUS)))) );
1555}
sewardj354e5c62005-01-27 20:12:52 +00001556
1557
1558/* For the inc/dec case, we store in DEP1 the result value and in NDEP
1559 the former value of the carry flag, which unfortunately we have to
1560 compute. */
1561
1562static void setFlags_INC_DEC ( Bool inc, IRTemp res, IRType ty )
1563{
1564 Int ccOp = inc ? AMD64G_CC_OP_INCB : AMD64G_CC_OP_DECB;
1565
1566 switch (ty) {
1567 case Ity_I8: ccOp += 0; break;
1568 case Ity_I16: ccOp += 1; break;
1569 case Ity_I32: ccOp += 2; break;
1570 case Ity_I64: ccOp += 3; break;
1571 default: vassert(0);
1572 }
1573
1574 /* This has to come first, because calculating the C flag
1575 may require reading all four thunk fields. */
1576 stmt( IRStmt_Put( OFFB_CC_NDEP, mk_amd64g_calculate_rflags_c()) );
1577 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(ccOp)) );
1578 stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(res)) );
1579 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0)) );
1580}
1581
1582
sewardj32b2bbe2005-01-28 00:50:10 +00001583/* Multiplies are pretty much like add and sub: DEP1 and DEP2 hold the
1584 two arguments. */
1585
1586static
1587void setFlags_MUL ( IRType ty, IRTemp arg1, IRTemp arg2, ULong base_op )
1588{
1589 switch (ty) {
1590 case Ity_I8:
1591 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(base_op+0) ) );
1592 break;
1593 case Ity_I16:
1594 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(base_op+1) ) );
1595 break;
1596 case Ity_I32:
1597 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(base_op+2) ) );
1598 break;
1599 case Ity_I64:
1600 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(base_op+3) ) );
1601 break;
1602 default:
1603 vpanic("setFlags_MUL(amd64)");
1604 }
1605 stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto64(mkexpr(arg1)) ));
1606 stmt( IRStmt_Put( OFFB_CC_DEP2, widenUto64(mkexpr(arg2)) ));
1607}
sewardj3ca55a12005-01-27 16:06:23 +00001608
1609
1610/* -------------- Condition codes. -------------- */
1611
1612/* Condition codes, using the AMD encoding. */
1613
sewardj8c332e22005-01-28 01:36:56 +00001614static HChar* name_AMD64Condcode ( AMD64Condcode cond )
sewardj3ca55a12005-01-27 16:06:23 +00001615{
1616 switch (cond) {
1617 case AMD64CondO: return "o";
1618 case AMD64CondNO: return "no";
1619 case AMD64CondB: return "b";
sewardje941eea2005-01-30 19:52:28 +00001620 case AMD64CondNB: return "ae"; /*"nb";*/
1621 case AMD64CondZ: return "e"; /*"z";*/
1622 case AMD64CondNZ: return "ne"; /*"nz";*/
sewardj3ca55a12005-01-27 16:06:23 +00001623 case AMD64CondBE: return "be";
sewardje941eea2005-01-30 19:52:28 +00001624 case AMD64CondNBE: return "a"; /*"nbe";*/
sewardj3ca55a12005-01-27 16:06:23 +00001625 case AMD64CondS: return "s";
1626 case AMD64CondNS: return "ns";
1627 case AMD64CondP: return "p";
1628 case AMD64CondNP: return "np";
1629 case AMD64CondL: return "l";
sewardje941eea2005-01-30 19:52:28 +00001630 case AMD64CondNL: return "ge"; /*"nl";*/
sewardj3ca55a12005-01-27 16:06:23 +00001631 case AMD64CondLE: return "le";
sewardje941eea2005-01-30 19:52:28 +00001632 case AMD64CondNLE: return "g"; /*"nle";*/
sewardj3ca55a12005-01-27 16:06:23 +00001633 case AMD64CondAlways: return "ALWAYS";
1634 default: vpanic("name_AMD64Condcode");
1635 }
1636}
1637
sewardj1389d4d2005-01-28 13:46:29 +00001638static
1639AMD64Condcode positiveIse_AMD64Condcode ( AMD64Condcode cond,
1640 /*OUT*/Bool* needInvert )
1641{
1642 vassert(cond >= AMD64CondO && cond <= AMD64CondNLE);
1643 if (cond & 1) {
1644 *needInvert = True;
1645 return cond-1;
1646 } else {
1647 *needInvert = False;
1648 return cond;
1649 }
1650}
sewardjdf0e0022005-01-25 15:48:43 +00001651
1652
1653/* -------------- Helpers for ADD/SUB with carry. -------------- */
1654
1655/* Given ta1, ta2 and tres, compute tres = ADC(ta1,ta2) and set flags
1656 appropriately.
1657*/
1658static void helper_ADC ( Int sz,
1659 IRTemp tres, IRTemp ta1, IRTemp ta2 )
1660{
1661 UInt thunkOp;
1662 IRType ty = szToITy(sz);
1663 IRTemp oldc = newTemp(Ity_I64);
1664 IRTemp oldcn = newTemp(ty);
1665 IROp plus = mkSizedOp(ty, Iop_Add8);
1666 IROp xor = mkSizedOp(ty, Iop_Xor8);
1667
1668 switch (sz) {
1669 case 8: thunkOp = AMD64G_CC_OP_ADCQ; break;
1670 case 4: thunkOp = AMD64G_CC_OP_ADCL; break;
1671 case 2: thunkOp = AMD64G_CC_OP_ADCW; break;
1672 case 1: thunkOp = AMD64G_CC_OP_ADCB; break;
1673 default: vassert(0);
1674 }
1675
1676 /* oldc = old carry flag, 0 or 1 */
1677 assign( oldc, binop(Iop_And64,
1678 mk_amd64g_calculate_rflags_c(),
1679 mkU64(1)) );
1680
1681 assign( oldcn, narrowTo(ty, mkexpr(oldc)) );
1682
1683 assign( tres, binop(plus,
1684 binop(plus,mkexpr(ta1),mkexpr(ta2)),
1685 mkexpr(oldcn)) );
1686
1687 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(thunkOp) ) );
sewardj820611e2005-08-24 10:56:01 +00001688 stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto64(mkexpr(ta1)) ));
1689 stmt( IRStmt_Put( OFFB_CC_DEP2, widenUto64(binop(xor, mkexpr(ta2),
1690 mkexpr(oldcn)) )) );
sewardjdf0e0022005-01-25 15:48:43 +00001691 stmt( IRStmt_Put( OFFB_CC_NDEP, mkexpr(oldc) ) );
1692}
1693
1694
1695/* Given ta1, ta2 and tres, compute tres = SBB(ta1,ta2) and set flags
1696 appropriately.
1697*/
1698static void helper_SBB ( Int sz,
1699 IRTemp tres, IRTemp ta1, IRTemp ta2 )
1700{
1701 UInt thunkOp;
1702 IRType ty = szToITy(sz);
1703 IRTemp oldc = newTemp(Ity_I64);
1704 IRTemp oldcn = newTemp(ty);
1705 IROp minus = mkSizedOp(ty, Iop_Sub8);
1706 IROp xor = mkSizedOp(ty, Iop_Xor8);
1707
1708 switch (sz) {
1709 case 8: thunkOp = AMD64G_CC_OP_SBBQ; break;
1710 case 4: thunkOp = AMD64G_CC_OP_SBBL; break;
1711 case 2: thunkOp = AMD64G_CC_OP_SBBW; break;
1712 case 1: thunkOp = AMD64G_CC_OP_SBBB; break;
1713 default: vassert(0);
1714 }
1715
1716 /* oldc = old carry flag, 0 or 1 */
1717 assign( oldc, binop(Iop_And64,
1718 mk_amd64g_calculate_rflags_c(),
1719 mkU64(1)) );
1720
1721 assign( oldcn, narrowTo(ty, mkexpr(oldc)) );
1722
1723 assign( tres, binop(minus,
1724 binop(minus,mkexpr(ta1),mkexpr(ta2)),
1725 mkexpr(oldcn)) );
1726
1727 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(thunkOp) ) );
sewardj820611e2005-08-24 10:56:01 +00001728 stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto64(mkexpr(ta1) )) );
1729 stmt( IRStmt_Put( OFFB_CC_DEP2, widenUto64(binop(xor, mkexpr(ta2),
1730 mkexpr(oldcn)) )) );
sewardjdf0e0022005-01-25 15:48:43 +00001731 stmt( IRStmt_Put( OFFB_CC_NDEP, mkexpr(oldc) ) );
1732}
1733
1734
sewardj3ca55a12005-01-27 16:06:23 +00001735/* -------------- Helpers for disassembly printing. -------------- */
1736
1737static HChar* nameGrp1 ( Int opc_aux )
1738{
1739 static HChar* grp1_names[8]
1740 = { "add", "or", "adc", "sbb", "and", "sub", "xor", "cmp" };
1741 if (opc_aux < 0 || opc_aux > 7) vpanic("nameGrp1(amd64)");
1742 return grp1_names[opc_aux];
1743}
1744
sewardj118b23e2005-01-29 02:14:44 +00001745static HChar* nameGrp2 ( Int opc_aux )
1746{
1747 static HChar* grp2_names[8]
1748 = { "rol", "ror", "rcl", "rcr", "shl", "shr", "shl", "sar" };
sewardje941eea2005-01-30 19:52:28 +00001749 if (opc_aux < 0 || opc_aux > 7) vpanic("nameGrp2(amd64)");
sewardj118b23e2005-01-29 02:14:44 +00001750 return grp2_names[opc_aux];
1751}
1752
sewardj03b07cc2005-01-31 18:09:43 +00001753static HChar* nameGrp4 ( Int opc_aux )
1754{
1755 static HChar* grp4_names[8]
1756 = { "inc", "dec", "???", "???", "???", "???", "???", "???" };
1757 if (opc_aux < 0 || opc_aux > 1) vpanic("nameGrp4(amd64)");
1758 return grp4_names[opc_aux];
1759}
sewardj354e5c62005-01-27 20:12:52 +00001760
1761static HChar* nameGrp5 ( Int opc_aux )
1762{
1763 static HChar* grp5_names[8]
1764 = { "inc", "dec", "call*", "call*", "jmp*", "jmp*", "push", "???" };
1765 if (opc_aux < 0 || opc_aux > 6) vpanic("nameGrp5(amd64)");
1766 return grp5_names[opc_aux];
1767}
1768
sewardj1d511802005-03-27 17:59:45 +00001769static HChar* nameGrp8 ( Int opc_aux )
1770{
1771 static HChar* grp8_names[8]
1772 = { "???", "???", "???", "???", "bt", "bts", "btr", "btc" };
1773 if (opc_aux < 4 || opc_aux > 7) vpanic("nameGrp8(amd64)");
1774 return grp8_names[opc_aux];
1775}
1776
sewardjd20c8852005-01-20 20:04:07 +00001777//.. static HChar* nameSReg ( UInt sreg )
1778//.. {
1779//.. switch (sreg) {
1780//.. case R_ES: return "%es";
1781//.. case R_CS: return "%cs";
1782//.. case R_SS: return "%ss";
1783//.. case R_DS: return "%ds";
1784//.. case R_FS: return "%fs";
1785//.. case R_GS: return "%gs";
1786//.. default: vpanic("nameSReg(x86)");
1787//.. }
1788//.. }
sewardj8711f662005-05-09 17:52:56 +00001789
1790static HChar* nameMMXReg ( Int mmxreg )
1791{
1792 static HChar* mmx_names[8]
1793 = { "%mm0", "%mm1", "%mm2", "%mm3", "%mm4", "%mm5", "%mm6", "%mm7" };
1794 if (mmxreg < 0 || mmxreg > 7) vpanic("nameMMXReg(amd64,guest)");
1795 return mmx_names[mmxreg];
1796}
sewardj1001dc42005-02-21 08:25:55 +00001797
1798static HChar* nameXMMReg ( Int xmmreg )
1799{
1800 static HChar* xmm_names[16]
1801 = { "%xmm0", "%xmm1", "%xmm2", "%xmm3",
1802 "%xmm4", "%xmm5", "%xmm6", "%xmm7",
1803 "%xmm8", "%xmm9", "%xmm10", "%xmm11",
1804 "%xmm12", "%xmm13", "%xmm14", "%xmm15" };
1805 if (xmmreg < 0 || xmmreg > 15) vpanic("nameXMMReg(amd64)");
1806 return xmm_names[xmmreg];
1807}
1808
sewardjca673ab2005-05-11 10:03:08 +00001809static HChar* nameMMXGran ( Int gran )
sewardj8711f662005-05-09 17:52:56 +00001810{
1811 switch (gran) {
1812 case 0: return "b";
1813 case 1: return "w";
1814 case 2: return "d";
1815 case 3: return "q";
1816 default: vpanic("nameMMXGran(amd64,guest)");
1817 }
1818}
sewardjdf0e0022005-01-25 15:48:43 +00001819
sewardj8c332e22005-01-28 01:36:56 +00001820static HChar nameISize ( Int size )
sewardjdf0e0022005-01-25 15:48:43 +00001821{
1822 switch (size) {
1823 case 8: return 'q';
1824 case 4: return 'l';
1825 case 2: return 'w';
1826 case 1: return 'b';
1827 default: vpanic("nameISize(amd64)");
1828 }
1829}
1830
1831
1832/*------------------------------------------------------------*/
1833/*--- JMP helpers ---*/
1834/*------------------------------------------------------------*/
1835
1836static void jmp_lit( IRJumpKind kind, Addr64 d64 )
1837{
1838 irbb->next = mkU64(d64);
1839 irbb->jumpkind = kind;
1840}
1841
sewardj2f959cc2005-01-26 01:19:35 +00001842static void jmp_treg( IRJumpKind kind, IRTemp t )
1843{
sewardj3ca55a12005-01-27 16:06:23 +00001844 irbb->next = mkexpr(t);
sewardj2f959cc2005-01-26 01:19:35 +00001845 irbb->jumpkind = kind;
1846}
1847
sewardj1389d4d2005-01-28 13:46:29 +00001848static
1849void jcc_01 ( AMD64Condcode cond, Addr64 d64_false, Addr64 d64_true )
1850{
1851 Bool invert;
1852 AMD64Condcode condPos;
1853 condPos = positiveIse_AMD64Condcode ( cond, &invert );
1854 if (invert) {
1855 stmt( IRStmt_Exit( mk_amd64g_calculate_condition(condPos),
1856 Ijk_Boring,
1857 IRConst_U64(d64_false) ) );
1858 irbb->next = mkU64(d64_true);
1859 irbb->jumpkind = Ijk_Boring;
1860 } else {
1861 stmt( IRStmt_Exit( mk_amd64g_calculate_condition(condPos),
1862 Ijk_Boring,
1863 IRConst_U64(d64_true) ) );
1864 irbb->next = mkU64(d64_false);
1865 irbb->jumpkind = Ijk_Boring;
1866 }
1867}
sewardjb3a04292005-01-21 20:33:44 +00001868
sewardj5a9ffab2005-05-12 17:55:01 +00001869/* Let new_rsp be the %rsp value after a call/return. This function
1870 generates an AbiHint to say that -128(%rsp) .. -1(%rsp) should now
1871 be regarded as uninitialised.
1872*/
1873static void make_redzone_AbiHint ( IRTemp new_rsp, HChar* who )
1874{
1875 if (0) vex_printf("AbiHint: %s\n", who);
1876 vassert(typeOfIRTemp(irbb->tyenv, new_rsp) == Ity_I64);
1877 stmt( IRStmt_AbiHint(
1878 binop(Iop_Sub64, mkexpr(new_rsp), mkU64(128)),
1879 128
1880 ));
1881}
1882
sewardjb3a04292005-01-21 20:33:44 +00001883
1884/*------------------------------------------------------------*/
1885/*--- Disassembling addressing modes ---*/
1886/*------------------------------------------------------------*/
1887
1888static
sewardj8c332e22005-01-28 01:36:56 +00001889HChar* sorbTxt ( Prefix pfx )
sewardjb3a04292005-01-21 20:33:44 +00001890{
1891 if (pfx & PFX_CS) return "%cs:";
1892 if (pfx & PFX_DS) return "%ds:";
1893 if (pfx & PFX_ES) return "%es:";
1894 if (pfx & PFX_FS) return "%fs:";
1895 if (pfx & PFX_GS) return "%gs:";
1896 if (pfx & PFX_SS) return "%ss:";
1897 return ""; /* no override */
1898}
1899
1900
1901/* 'virtual' is an IRExpr* holding a virtual address. Convert it to a
1902 linear address by adding any required segment override as indicated
1903 by sorb. */
1904static
1905IRExpr* handleSegOverride ( Prefix pfx, IRExpr* virtual )
1906{
sewardja6b93d12005-02-17 09:28:28 +00001907 if (pfx & PFX_FS) {
1908 /* Note that this is a linux-kernel specific hack that relies
1909 on the assumption that %fs is always zero. */
1910 /* return virtual + guest_FS_ZERO. */
1911 return binop(Iop_Add64, virtual, IRExpr_Get(OFFB_FS_ZERO, Ity_I64));
1912 }
sewardjb3a04292005-01-21 20:33:44 +00001913
sewardja6b93d12005-02-17 09:28:28 +00001914 if (pfx & PFX_GS) {
1915 unimplemented("amd64 %gs segment override");
1916 }
1917
1918 /* cs, ds, es and ss are simply ignored in 64-bit mode. */
1919 return virtual;
sewardjb3a04292005-01-21 20:33:44 +00001920}
sewardja6b93d12005-02-17 09:28:28 +00001921
sewardjd20c8852005-01-20 20:04:07 +00001922//.. {
1923//.. Int sreg;
1924//.. IRType hWordTy;
1925//.. IRTemp ldt_ptr, gdt_ptr, seg_selector, r64;
1926//..
1927//.. if (sorb == 0)
1928//.. /* the common case - no override */
1929//.. return virtual;
1930//..
1931//.. switch (sorb) {
1932//.. case 0x3E: sreg = R_DS; break;
1933//.. case 0x26: sreg = R_ES; break;
1934//.. case 0x64: sreg = R_FS; break;
1935//.. case 0x65: sreg = R_GS; break;
1936//.. default: vpanic("handleSegOverride(x86,guest)");
1937//.. }
1938//..
1939//.. hWordTy = sizeof(HWord)==4 ? Ity_I32 : Ity_I64;
1940//..
1941//.. seg_selector = newTemp(Ity_I32);
1942//.. ldt_ptr = newTemp(hWordTy);
1943//.. gdt_ptr = newTemp(hWordTy);
1944//.. r64 = newTemp(Ity_I64);
1945//..
1946//.. assign( seg_selector, unop(Iop_16Uto32, getSReg(sreg)) );
1947//.. assign( ldt_ptr, IRExpr_Get( OFFB_LDT, hWordTy ));
1948//.. assign( gdt_ptr, IRExpr_Get( OFFB_GDT, hWordTy ));
1949//..
1950//.. /*
1951//.. Call this to do the translation and limit checks:
1952//.. ULong x86g_use_seg_selector ( HWord ldt, HWord gdt,
1953//.. UInt seg_selector, UInt virtual_addr )
1954//.. */
1955//.. assign(
1956//.. r64,
1957//.. mkIRExprCCall(
1958//.. Ity_I64,
1959//.. 0/*regparms*/,
1960//.. "x86g_use_seg_selector",
1961//.. &x86g_use_seg_selector,
1962//.. mkIRExprVec_4( mkexpr(ldt_ptr), mkexpr(gdt_ptr),
1963//.. mkexpr(seg_selector), virtual)
1964//.. )
1965//.. );
1966//..
1967//.. /* If the high 32 of the result are non-zero, there was a
1968//.. failure in address translation. In which case, make a
1969//.. quick exit.
1970//.. */
1971//.. stmt(
1972//.. IRStmt_Exit(
1973//.. binop(Iop_CmpNE32, unop(Iop_64HIto32, mkexpr(r64)), mkU32(0)),
1974//.. Ijk_MapFail,
1975//.. IRConst_U32( guest_eip_curr_instr )
1976//.. )
1977//.. );
1978//..
1979//.. /* otherwise, here's the translated result. */
1980//.. return unop(Iop_64to32, mkexpr(r64));
1981//.. }
sewardjb3a04292005-01-21 20:33:44 +00001982
1983
1984/* Generate IR to calculate an address indicated by a ModRM and
1985 following SIB bytes. The expression, and the number of bytes in
1986 the address mode, are returned (the latter in *len). Note that
1987 this fn should not be called if the R/M part of the address denotes
1988 a register instead of memory. If print_codegen is true, text of
1989 the addressing mode is placed in buf.
1990
1991 The computed address is stored in a new tempreg, and the
sewardje1698952005-02-08 15:02:39 +00001992 identity of the tempreg is returned.
1993
1994 extra_bytes holds the number of bytes after the amode, as supplied
1995 by the caller. This is needed to make sense of %rip-relative
1996 addresses. Note that the value that *len is set to is only the
1997 length of the amode itself and does not include the value supplied
sewardj09717342005-05-05 21:34:02 +00001998 in extra_bytes.
sewardje1698952005-02-08 15:02:39 +00001999 */
sewardjb3a04292005-01-21 20:33:44 +00002000
2001static IRTemp disAMode_copy2tmp ( IRExpr* addr64 )
2002{
2003 IRTemp tmp = newTemp(Ity_I64);
2004 assign( tmp, addr64 );
2005 return tmp;
2006}
2007
2008static
sewardj270def42005-07-03 01:03:01 +00002009IRTemp disAMode ( Int* len, Prefix pfx, Long delta,
sewardje1698952005-02-08 15:02:39 +00002010 HChar* buf, Int extra_bytes )
sewardjb3a04292005-01-21 20:33:44 +00002011{
sewardj8c332e22005-01-28 01:36:56 +00002012 UChar mod_reg_rm = getUChar(delta);
sewardjb3a04292005-01-21 20:33:44 +00002013 delta++;
2014
2015 buf[0] = (UChar)0;
sewardje1698952005-02-08 15:02:39 +00002016 vassert(extra_bytes >= 0 && extra_bytes < 10);
sewardjb3a04292005-01-21 20:33:44 +00002017
2018 /* squeeze out the reg field from mod_reg_rm, since a 256-entry
2019 jump table seems a bit excessive.
2020 */
sewardj7a240552005-01-28 21:37:12 +00002021 mod_reg_rm &= 0xC7; /* is now XX000YYY */
sewardj1027dc22005-02-26 01:55:02 +00002022 mod_reg_rm = toUChar(mod_reg_rm | (mod_reg_rm >> 3));
2023 /* is now XX0XXYYY */
sewardj7a240552005-01-28 21:37:12 +00002024 mod_reg_rm &= 0x1F; /* is now 000XXYYY */
sewardjb3a04292005-01-21 20:33:44 +00002025 switch (mod_reg_rm) {
2026
2027 /* REX.B==0: (%rax) .. (%rdi), not including (%rsp) or (%rbp).
2028 REX.B==1: (%r8) .. (%r15), not including (%r12) or (%r13).
2029 */
2030 case 0x00: case 0x01: case 0x02: case 0x03:
2031 /* ! 04 */ /* ! 05 */ case 0x06: case 0x07:
sewardj1027dc22005-02-26 01:55:02 +00002032 { UChar rm = toUChar(mod_reg_rm & 7);
sewardj5b470602005-02-27 13:10:48 +00002033 DIS(buf, "%s(%s)", sorbTxt(pfx), nameIRegRexB(8,pfx,rm));
sewardjb3a04292005-01-21 20:33:44 +00002034 *len = 1;
2035 return disAMode_copy2tmp(
sewardj5b470602005-02-27 13:10:48 +00002036 handleSegOverride(pfx, getIRegRexB(8,pfx,rm)));
sewardjb3a04292005-01-21 20:33:44 +00002037 }
2038
2039 /* REX.B==0: d8(%rax) ... d8(%rdi), not including d8(%rsp)
2040 REX.B==1: d8(%r8) ... d8(%r15), not including d8(%r12)
2041 */
2042 case 0x08: case 0x09: case 0x0A: case 0x0B:
2043 /* ! 0C */ case 0x0D: case 0x0E: case 0x0F:
sewardj1027dc22005-02-26 01:55:02 +00002044 { UChar rm = toUChar(mod_reg_rm & 7);
sewardj8c332e22005-01-28 01:36:56 +00002045 Long d = getSDisp8(delta);
sewardj7eaa7cf2005-01-31 18:55:22 +00002046 if (d == 0) {
sewardj5b470602005-02-27 13:10:48 +00002047 DIS(buf, "%s(%s)", sorbTxt(pfx), nameIRegRexB(8,pfx,rm));
sewardj7eaa7cf2005-01-31 18:55:22 +00002048 } else {
sewardj5b470602005-02-27 13:10:48 +00002049 DIS(buf, "%s%lld(%s)", sorbTxt(pfx), d, nameIRegRexB(8,pfx,rm));
sewardj7eaa7cf2005-01-31 18:55:22 +00002050 }
sewardjb3a04292005-01-21 20:33:44 +00002051 *len = 2;
2052 return disAMode_copy2tmp(
2053 handleSegOverride(pfx,
sewardj5b470602005-02-27 13:10:48 +00002054 binop(Iop_Add64,getIRegRexB(8,pfx,rm),mkU64(d))));
sewardjb3a04292005-01-21 20:33:44 +00002055 }
2056
2057 /* REX.B==0: d32(%rax) ... d32(%rdi), not including d32(%rsp)
2058 REX.B==1: d32(%r8) ... d32(%r15), not including d32(%r12)
2059 */
2060 case 0x10: case 0x11: case 0x12: case 0x13:
2061 /* ! 14 */ case 0x15: case 0x16: case 0x17:
sewardj1027dc22005-02-26 01:55:02 +00002062 { UChar rm = toUChar(mod_reg_rm & 7);
sewardj227458e2005-01-31 19:04:50 +00002063 Long d = getSDisp32(delta);
sewardj5b470602005-02-27 13:10:48 +00002064 DIS(buf, "%s%lld(%s)", sorbTxt(pfx), d, nameIRegRexB(8,pfx,rm));
sewardjb3a04292005-01-21 20:33:44 +00002065 *len = 5;
2066 return disAMode_copy2tmp(
2067 handleSegOverride(pfx,
sewardj5b470602005-02-27 13:10:48 +00002068 binop(Iop_Add64,getIRegRexB(8,pfx,rm),mkU64(d))));
sewardjb3a04292005-01-21 20:33:44 +00002069 }
2070
2071 /* REX.B==0: a register, %rax .. %rdi. This shouldn't happen. */
2072 /* REX.B==1: a register, %r8 .. %r16. This shouldn't happen. */
2073 case 0x18: case 0x19: case 0x1A: case 0x1B:
2074 case 0x1C: case 0x1D: case 0x1E: case 0x1F:
sewardj354e5c62005-01-27 20:12:52 +00002075 vpanic("disAMode(amd64): not an addr!");
sewardjb3a04292005-01-21 20:33:44 +00002076
sewardj9e6491a2005-07-02 19:24:10 +00002077 /* RIP + disp32. This assumes that guest_RIP_curr_instr is set
sewardjb3a04292005-01-21 20:33:44 +00002078 correctly at the start of handling each instruction. */
2079 case 0x05:
sewardj227458e2005-01-31 19:04:50 +00002080 { Long d = getSDisp32(delta);
sewardjb3a04292005-01-21 20:33:44 +00002081 *len = 5;
sewardj7eaa7cf2005-01-31 18:55:22 +00002082 DIS(buf, "%s%lld(%%rip)", sorbTxt(pfx), d);
sewardj4b744762005-02-07 15:02:25 +00002083 /* We need to know the next instruction's start address.
2084 Try and figure out what it is, record the guess, and ask
2085 the top-level driver logic (bbToIR_AMD64) to check we
2086 guessed right, after the instruction is completely
2087 decoded. */
sewardj9e6491a2005-07-02 19:24:10 +00002088 guest_RIP_next_mustcheck = True;
2089 guest_RIP_next_assumed = guest_RIP_bbstart
sewardje1698952005-02-08 15:02:39 +00002090 + delta+4 + extra_bytes;
sewardjb3a04292005-01-21 20:33:44 +00002091 return disAMode_copy2tmp(
2092 handleSegOverride(pfx,
sewardj9e6491a2005-07-02 19:24:10 +00002093 binop(Iop_Add64, mkU64(guest_RIP_next_assumed),
sewardjb3a04292005-01-21 20:33:44 +00002094 mkU64(d))));
2095 }
sewardj3ca55a12005-01-27 16:06:23 +00002096
sewardj2f959cc2005-01-26 01:19:35 +00002097 case 0x04: {
2098 /* SIB, with no displacement. Special cases:
sewardj3ca55a12005-01-27 16:06:23 +00002099 -- %rsp cannot act as an index value.
2100 If index_r indicates %rsp, zero is used for the index.
2101 -- when mod is zero and base indicates RBP or R13, base is
2102 instead a 32-bit sign-extended literal.
sewardj2f959cc2005-01-26 01:19:35 +00002103 It's all madness, I tell you. Extract %index, %base and
2104 scale from the SIB byte. The value denoted is then:
sewardj3ca55a12005-01-27 16:06:23 +00002105 | %index == %RSP && (%base == %RBP || %base == %R13)
sewardj2f959cc2005-01-26 01:19:35 +00002106 = d32 following SIB byte
sewardj3ca55a12005-01-27 16:06:23 +00002107 | %index == %RSP && !(%base == %RBP || %base == %R13)
sewardj2f959cc2005-01-26 01:19:35 +00002108 = %base
sewardj3ca55a12005-01-27 16:06:23 +00002109 | %index != %RSP && (%base == %RBP || %base == %R13)
sewardj2f959cc2005-01-26 01:19:35 +00002110 = d32 following SIB byte + (%index << scale)
sewardj3ca55a12005-01-27 16:06:23 +00002111 | %index != %RSP && !(%base == %RBP || %base == %R13)
sewardj2f959cc2005-01-26 01:19:35 +00002112 = %base + (%index << scale)
2113 */
sewardj8c332e22005-01-28 01:36:56 +00002114 UChar sib = getUChar(delta);
sewardj1027dc22005-02-26 01:55:02 +00002115 UChar scale = toUChar((sib >> 6) & 3);
2116 UChar index_r = toUChar((sib >> 3) & 7);
2117 UChar base_r = toUChar(sib & 7);
sewardj3ca55a12005-01-27 16:06:23 +00002118 /* correct since #(R13) == 8 + #(RBP) */
sewardj7a240552005-01-28 21:37:12 +00002119 Bool base_is_BPor13 = toBool(base_r == R_RBP);
2120 Bool index_is_SP = toBool(index_r == R_RSP && 0==getRexX(pfx));
sewardj2f959cc2005-01-26 01:19:35 +00002121 delta++;
sewardjb3a04292005-01-21 20:33:44 +00002122
sewardj3ca55a12005-01-27 16:06:23 +00002123 if ((!index_is_SP) && (!base_is_BPor13)) {
sewardje941eea2005-01-30 19:52:28 +00002124 if (scale == 0) {
2125 DIS(buf, "%s(%s,%s)", sorbTxt(pfx),
sewardj5b470602005-02-27 13:10:48 +00002126 nameIRegRexB(8,pfx,base_r),
2127 nameIReg64rexX(pfx,index_r));
sewardje941eea2005-01-30 19:52:28 +00002128 } else {
2129 DIS(buf, "%s(%s,%s,%d)", sorbTxt(pfx),
sewardj5b470602005-02-27 13:10:48 +00002130 nameIRegRexB(8,pfx,base_r),
2131 nameIReg64rexX(pfx,index_r), 1<<scale);
sewardje941eea2005-01-30 19:52:28 +00002132 }
sewardj2f959cc2005-01-26 01:19:35 +00002133 *len = 2;
sewardj2f959cc2005-01-26 01:19:35 +00002134 return
2135 disAMode_copy2tmp(
sewardj3ca55a12005-01-27 16:06:23 +00002136 handleSegOverride(pfx,
2137 binop(Iop_Add64,
sewardj5b470602005-02-27 13:10:48 +00002138 getIRegRexB(8,pfx,base_r),
2139 binop(Iop_Shl64, getIReg64rexX(pfx,index_r),
sewardj2f959cc2005-01-26 01:19:35 +00002140 mkU8(scale)))));
2141 }
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(,%s,%d)", sorbTxt(pfx), d,
sewardj5b470602005-02-27 13:10:48 +00002146 nameIReg64rexX(pfx,index_r), 1<<scale);
sewardj2f959cc2005-01-26 01:19:35 +00002147 *len = 6;
sewardj2f959cc2005-01-26 01:19:35 +00002148 return
2149 disAMode_copy2tmp(
sewardj3ca55a12005-01-27 16:06:23 +00002150 handleSegOverride(pfx,
2151 binop(Iop_Add64,
sewardj5b470602005-02-27 13:10:48 +00002152 binop(Iop_Shl64, getIReg64rexX(pfx,index_r),
sewardj3ca55a12005-01-27 16:06:23 +00002153 mkU8(scale)),
2154 mkU64(d))));
sewardj2f959cc2005-01-26 01:19:35 +00002155 }
2156
sewardj3ca55a12005-01-27 16:06:23 +00002157 if (index_is_SP && (!base_is_BPor13)) {
sewardj5b470602005-02-27 13:10:48 +00002158 DIS(buf, "%s(%s)", sorbTxt(pfx), nameIRegRexB(8,pfx,base_r));
sewardj2f959cc2005-01-26 01:19:35 +00002159 *len = 2;
sewardj2f959cc2005-01-26 01:19:35 +00002160 return disAMode_copy2tmp(
sewardj5b470602005-02-27 13:10:48 +00002161 handleSegOverride(pfx, getIRegRexB(8,pfx,base_r)));
sewardj2f959cc2005-01-26 01:19:35 +00002162 }
2163
sewardj3ca55a12005-01-27 16:06:23 +00002164 if (index_is_SP && base_is_BPor13) {
sewardj227458e2005-01-31 19:04:50 +00002165 Long d = getSDisp32(delta);
sewardj7eaa7cf2005-01-31 18:55:22 +00002166 DIS(buf, "%s%lld", sorbTxt(pfx), d);
sewardj2f959cc2005-01-26 01:19:35 +00002167 *len = 6;
sewardj2f959cc2005-01-26 01:19:35 +00002168 return disAMode_copy2tmp(
sewardj3ca55a12005-01-27 16:06:23 +00002169 handleSegOverride(pfx, mkU64(d)));
sewardj2f959cc2005-01-26 01:19:35 +00002170 }
2171
2172 vassert(0);
2173 }
sewardj3ca55a12005-01-27 16:06:23 +00002174
sewardj2f959cc2005-01-26 01:19:35 +00002175 /* SIB, with 8-bit displacement. Special cases:
2176 -- %esp cannot act as an index value.
2177 If index_r indicates %esp, zero is used for the index.
2178 Denoted value is:
2179 | %index == %ESP
2180 = d8 + %base
2181 | %index != %ESP
2182 = d8 + %base + (%index << scale)
2183 */
2184 case 0x0C: {
sewardj8c332e22005-01-28 01:36:56 +00002185 UChar sib = getUChar(delta);
sewardj1027dc22005-02-26 01:55:02 +00002186 UChar scale = toUChar((sib >> 6) & 3);
2187 UChar index_r = toUChar((sib >> 3) & 7);
2188 UChar base_r = toUChar(sib & 7);
sewardj8c332e22005-01-28 01:36:56 +00002189 Long d = getSDisp8(delta+1);
sewardj2f959cc2005-01-26 01:19:35 +00002190
sewardj3ca55a12005-01-27 16:06:23 +00002191 if (index_r == R_RSP && 0==getRexX(pfx)) {
sewardje941eea2005-01-30 19:52:28 +00002192 DIS(buf, "%s%lld(%s)", sorbTxt(pfx),
sewardj5b470602005-02-27 13:10:48 +00002193 d, nameIRegRexB(8,pfx,base_r));
sewardj2f959cc2005-01-26 01:19:35 +00002194 *len = 3;
sewardj2f959cc2005-01-26 01:19:35 +00002195 return disAMode_copy2tmp(
sewardj3ca55a12005-01-27 16:06:23 +00002196 handleSegOverride(pfx,
sewardj5b470602005-02-27 13:10:48 +00002197 binop(Iop_Add64, getIRegRexB(8,pfx,base_r), mkU64(d)) ));
sewardj2f959cc2005-01-26 01:19:35 +00002198 } else {
sewardje941eea2005-01-30 19:52:28 +00002199 if (scale == 0) {
2200 DIS(buf, "%s%lld(%s,%s)", sorbTxt(pfx), d,
sewardj5b470602005-02-27 13:10:48 +00002201 nameIRegRexB(8,pfx,base_r),
2202 nameIReg64rexX(pfx,index_r));
sewardje941eea2005-01-30 19:52:28 +00002203 } else {
2204 DIS(buf, "%s%lld(%s,%s,%d)", sorbTxt(pfx), d,
sewardj5b470602005-02-27 13:10:48 +00002205 nameIRegRexB(8,pfx,base_r),
2206 nameIReg64rexX(pfx,index_r), 1<<scale);
sewardje941eea2005-01-30 19:52:28 +00002207 }
sewardj2f959cc2005-01-26 01:19:35 +00002208 *len = 3;
sewardj2f959cc2005-01-26 01:19:35 +00002209 return
2210 disAMode_copy2tmp(
sewardj3ca55a12005-01-27 16:06:23 +00002211 handleSegOverride(pfx,
2212 binop(Iop_Add64,
2213 binop(Iop_Add64,
sewardj5b470602005-02-27 13:10:48 +00002214 getIRegRexB(8,pfx,base_r),
sewardj3ca55a12005-01-27 16:06:23 +00002215 binop(Iop_Shl64,
sewardj5b470602005-02-27 13:10:48 +00002216 getIReg64rexX(pfx,index_r), mkU8(scale))),
sewardj3ca55a12005-01-27 16:06:23 +00002217 mkU64(d))));
sewardj2f959cc2005-01-26 01:19:35 +00002218 }
sewardj3ca55a12005-01-27 16:06:23 +00002219 vassert(0); /*NOTREACHED*/
sewardj2f959cc2005-01-26 01:19:35 +00002220 }
sewardj3ca55a12005-01-27 16:06:23 +00002221
sewardj2f959cc2005-01-26 01:19:35 +00002222 /* SIB, with 32-bit displacement. Special cases:
2223 -- %rsp cannot act as an index value.
2224 If index_r indicates %rsp, zero is used for the index.
2225 Denoted value is:
2226 | %index == %RSP
2227 = d32 + %base
2228 | %index != %RSP
2229 = d32 + %base + (%index << scale)
2230 */
2231 case 0x14: {
sewardj8c332e22005-01-28 01:36:56 +00002232 UChar sib = getUChar(delta);
sewardj1027dc22005-02-26 01:55:02 +00002233 UChar scale = toUChar((sib >> 6) & 3);
2234 UChar index_r = toUChar((sib >> 3) & 7);
2235 UChar base_r = toUChar(sib & 7);
sewardj8c332e22005-01-28 01:36:56 +00002236 Long d = getSDisp32(delta+1);
sewardj2f959cc2005-01-26 01:19:35 +00002237
2238 if (index_r == R_RSP && 0==getRexX(pfx)) {
sewardje941eea2005-01-30 19:52:28 +00002239 DIS(buf, "%s%lld(%s)", sorbTxt(pfx),
sewardj5b470602005-02-27 13:10:48 +00002240 d, nameIRegRexB(8,pfx,base_r));
sewardj2f959cc2005-01-26 01:19:35 +00002241 *len = 6;
sewardj2f959cc2005-01-26 01:19:35 +00002242 return disAMode_copy2tmp(
2243 handleSegOverride(pfx,
sewardj5b470602005-02-27 13:10:48 +00002244 binop(Iop_Add64, getIRegRexB(8,pfx,base_r), mkU64(d)) ));
sewardj2f959cc2005-01-26 01:19:35 +00002245 } else {
sewardje941eea2005-01-30 19:52:28 +00002246 if (scale == 0) {
2247 DIS(buf, "%s%lld(%s,%s)", sorbTxt(pfx), d,
sewardj5b470602005-02-27 13:10:48 +00002248 nameIRegRexB(8,pfx,base_r),
2249 nameIReg64rexX(pfx,index_r));
sewardje941eea2005-01-30 19:52:28 +00002250 } else {
2251 DIS(buf, "%s%lld(%s,%s,%d)", sorbTxt(pfx), d,
sewardj5b470602005-02-27 13:10:48 +00002252 nameIRegRexB(8,pfx,base_r),
2253 nameIReg64rexX(pfx,index_r), 1<<scale);
sewardje941eea2005-01-30 19:52:28 +00002254 }
sewardj2f959cc2005-01-26 01:19:35 +00002255 *len = 6;
2256 return
2257 disAMode_copy2tmp(
2258 handleSegOverride(pfx,
2259 binop(Iop_Add64,
2260 binop(Iop_Add64,
sewardj5b470602005-02-27 13:10:48 +00002261 getIRegRexB(8,pfx,base_r),
sewardj2f959cc2005-01-26 01:19:35 +00002262 binop(Iop_Shl64,
sewardj5b470602005-02-27 13:10:48 +00002263 getIReg64rexX(pfx,index_r), mkU8(scale))),
sewardj2f959cc2005-01-26 01:19:35 +00002264 mkU64(d))));
2265 }
sewardj3ca55a12005-01-27 16:06:23 +00002266 vassert(0); /*NOTREACHED*/
sewardj2f959cc2005-01-26 01:19:35 +00002267 }
2268
sewardjb3a04292005-01-21 20:33:44 +00002269 default:
2270 vpanic("disAMode(amd64)");
2271 return 0; /*notreached*/
2272 }
2273}
2274
2275
sewardj3ca55a12005-01-27 16:06:23 +00002276/* Figure out the number of (insn-stream) bytes constituting the amode
2277 beginning at delta. Is useful for getting hold of literals beyond
2278 the end of the amode before it has been disassembled. */
2279
sewardj270def42005-07-03 01:03:01 +00002280static UInt lengthAMode ( Prefix pfx, Long delta )
sewardj3ca55a12005-01-27 16:06:23 +00002281{
sewardj8c332e22005-01-28 01:36:56 +00002282 UChar mod_reg_rm = getUChar(delta);
sewardj3ca55a12005-01-27 16:06:23 +00002283 delta++;
2284
2285 /* squeeze out the reg field from mod_reg_rm, since a 256-entry
2286 jump table seems a bit excessive.
2287 */
sewardj7a240552005-01-28 21:37:12 +00002288 mod_reg_rm &= 0xC7; /* is now XX000YYY */
sewardj1027dc22005-02-26 01:55:02 +00002289 mod_reg_rm = toUChar(mod_reg_rm | (mod_reg_rm >> 3));
2290 /* is now XX0XXYYY */
sewardj7a240552005-01-28 21:37:12 +00002291 mod_reg_rm &= 0x1F; /* is now 000XXYYY */
sewardj3ca55a12005-01-27 16:06:23 +00002292 switch (mod_reg_rm) {
2293
2294 /* REX.B==0: (%rax) .. (%rdi), not including (%rsp) or (%rbp).
2295 REX.B==1: (%r8) .. (%r15), not including (%r12) or (%r13).
2296 */
2297 case 0x00: case 0x01: case 0x02: case 0x03:
2298 /* ! 04 */ /* ! 05 */ case 0x06: case 0x07:
sewardj3ca55a12005-01-27 16:06:23 +00002299 return 1;
2300
2301 /* REX.B==0: d8(%rax) ... d8(%rdi), not including d8(%rsp)
2302 REX.B==1: d8(%r8) ... d8(%r15), not including d8(%r12)
2303 */
2304 case 0x08: case 0x09: case 0x0A: case 0x0B:
2305 /* ! 0C */ case 0x0D: case 0x0E: case 0x0F:
sewardj3ca55a12005-01-27 16:06:23 +00002306 return 2;
2307
2308 /* REX.B==0: d32(%rax) ... d32(%rdi), not including d32(%rsp)
2309 REX.B==1: d32(%r8) ... d32(%r15), not including d32(%r12)
2310 */
2311 case 0x10: case 0x11: case 0x12: case 0x13:
2312 /* ! 14 */ case 0x15: case 0x16: case 0x17:
sewardj3ca55a12005-01-27 16:06:23 +00002313 return 5;
2314
2315 /* REX.B==0: a register, %rax .. %rdi. This shouldn't happen. */
2316 /* REX.B==1: a register, %r8 .. %r16. This shouldn't happen. */
2317 /* Not an address, but still handled. */
2318 case 0x18: case 0x19: case 0x1A: case 0x1B:
2319 case 0x1C: case 0x1D: case 0x1E: case 0x1F:
2320 return 1;
2321
2322 /* RIP + disp32. */
2323 case 0x05:
sewardj3ca55a12005-01-27 16:06:23 +00002324 return 5;
2325
2326 case 0x04: {
2327 /* SIB, with no displacement. */
sewardj8c332e22005-01-28 01:36:56 +00002328 UChar sib = getUChar(delta);
sewardj1027dc22005-02-26 01:55:02 +00002329 UChar base_r = toUChar(sib & 7);
sewardj3ca55a12005-01-27 16:06:23 +00002330 /* correct since #(R13) == 8 + #(RBP) */
sewardj7a240552005-01-28 21:37:12 +00002331 Bool base_is_BPor13 = toBool(base_r == R_RBP);
sewardj3ca55a12005-01-27 16:06:23 +00002332
2333 if (base_is_BPor13) {
sewardj3ca55a12005-01-27 16:06:23 +00002334 return 6;
2335 } else {
sewardj3ca55a12005-01-27 16:06:23 +00002336 return 2;
2337 }
2338 }
2339
2340 /* SIB, with 8-bit displacement. */
2341 case 0x0C:
2342 return 3;
2343
2344 /* SIB, with 32-bit displacement. */
2345 case 0x14:
2346 return 6;
2347
2348 default:
2349 vpanic("lengthAMode(amd64)");
2350 return 0; /*notreached*/
2351 }
2352}
2353
2354
sewardjdf0e0022005-01-25 15:48:43 +00002355/*------------------------------------------------------------*/
2356/*--- Disassembling common idioms ---*/
2357/*------------------------------------------------------------*/
2358
sewardjdf0e0022005-01-25 15:48:43 +00002359/* Handle binary integer instructions of the form
2360 op E, G meaning
2361 op reg-or-mem, reg
2362 Is passed the a ptr to the modRM byte, the actual operation, and the
2363 data size. Returns the address advanced completely over this
2364 instruction.
2365
2366 E(src) is reg-or-mem
2367 G(dst) is reg.
2368
2369 If E is reg, --> GET %G, tmp
2370 OP %E, tmp
2371 PUT tmp, %G
2372
2373 If E is mem and OP is not reversible,
2374 --> (getAddr E) -> tmpa
2375 LD (tmpa), tmpa
2376 GET %G, tmp2
2377 OP tmpa, tmp2
2378 PUT tmp2, %G
2379
2380 If E is mem and OP is reversible
2381 --> (getAddr E) -> tmpa
2382 LD (tmpa), tmpa
2383 OP %G, tmpa
2384 PUT tmpa, %G
2385*/
2386static
2387ULong dis_op2_E_G ( Prefix pfx,
2388 Bool addSubCarry,
2389 IROp op8,
2390 Bool keep,
2391 Int size,
sewardj270def42005-07-03 01:03:01 +00002392 Long delta0,
sewardj8c332e22005-01-28 01:36:56 +00002393 HChar* t_amd64opc )
sewardjdf0e0022005-01-25 15:48:43 +00002394{
2395 HChar dis_buf[50];
2396 Int len;
2397 IRType ty = szToITy(size);
2398 IRTemp dst1 = newTemp(ty);
2399 IRTemp src = newTemp(ty);
2400 IRTemp dst0 = newTemp(ty);
2401 UChar rm = getUChar(delta0);
2402 IRTemp addr = IRTemp_INVALID;
2403
2404 /* addSubCarry == True indicates the intended operation is
2405 add-with-carry or subtract-with-borrow. */
2406 if (addSubCarry) {
2407 vassert(op8 == Iop_Add8 || op8 == Iop_Sub8);
2408 vassert(keep);
2409 }
2410
2411 if (epartIsReg(rm)) {
sewardjdf0e0022005-01-25 15:48:43 +00002412 /* Specially handle XOR reg,reg, because that doesn't really
2413 depend on reg, and doing the obvious thing potentially
2414 generates a spurious value check failure due to the bogus
2415 dependency. */
sewardj5b470602005-02-27 13:10:48 +00002416 if ((op8 == Iop_Xor8 || (op8 == Iop_Sub8 && addSubCarry))
2417 && offsetIRegG(size,pfx,rm) == offsetIRegE(size,pfx,rm)) {
sewardj4f9847d2005-07-25 11:58:34 +00002418 if (False && op8 == Iop_Sub8)
sewardj5b470602005-02-27 13:10:48 +00002419 vex_printf("vex amd64->IR: sbb %%r,%%r optimisation(1)\n");
2420 putIRegG(size,pfx,rm, mkU(ty,0));
sewardjdf0e0022005-01-25 15:48:43 +00002421 }
sewardj5b470602005-02-27 13:10:48 +00002422
2423 assign( dst0, getIRegG(size,pfx,rm) );
2424 assign( src, getIRegE(size,pfx,rm) );
sewardjdf0e0022005-01-25 15:48:43 +00002425
2426 if (addSubCarry && op8 == Iop_Add8) {
sewardj3ca55a12005-01-27 16:06:23 +00002427 vassert(0); /* awaiting test case */
sewardjdf0e0022005-01-25 15:48:43 +00002428 helper_ADC( size, dst1, dst0, src );
sewardj5b470602005-02-27 13:10:48 +00002429 putIRegG(size, pfx, rm, mkexpr(dst1));
sewardjdf0e0022005-01-25 15:48:43 +00002430 } else
2431 if (addSubCarry && op8 == Iop_Sub8) {
2432 helper_SBB( size, dst1, dst0, src );
sewardj5b470602005-02-27 13:10:48 +00002433 putIRegG(size, pfx, rm, mkexpr(dst1));
sewardjdf0e0022005-01-25 15:48:43 +00002434 } else {
2435 assign( dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
2436 if (isAddSub(op8))
2437 setFlags_DEP1_DEP2(op8, dst0, src, ty);
2438 else
2439 setFlags_DEP1(op8, dst1, ty);
2440 if (keep)
sewardj5b470602005-02-27 13:10:48 +00002441 putIRegG(size, pfx, rm, mkexpr(dst1));
sewardjdf0e0022005-01-25 15:48:43 +00002442 }
2443
2444 DIP("%s%c %s,%s\n", t_amd64opc, nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00002445 nameIRegE(size,pfx,rm),
2446 nameIRegG(size,pfx,rm));
sewardjdf0e0022005-01-25 15:48:43 +00002447 return 1+delta0;
2448 } else {
2449 /* E refers to memory */
sewardje1698952005-02-08 15:02:39 +00002450 addr = disAMode ( &len, pfx, delta0, dis_buf, 0 );
sewardj5b470602005-02-27 13:10:48 +00002451 assign( dst0, getIRegG(size,pfx,rm) );
sewardjdf0e0022005-01-25 15:48:43 +00002452 assign( src, loadLE(szToITy(size), mkexpr(addr)) );
2453
2454 if (addSubCarry && op8 == Iop_Add8) {
2455 helper_ADC( size, dst1, dst0, src );
sewardj5b470602005-02-27 13:10:48 +00002456 putIRegG(size, pfx, rm, mkexpr(dst1));
sewardjdf0e0022005-01-25 15:48:43 +00002457 } else
2458 if (addSubCarry && op8 == Iop_Sub8) {
2459 helper_SBB( size, dst1, dst0, src );
sewardj5b470602005-02-27 13:10:48 +00002460 putIRegG(size, pfx, rm, mkexpr(dst1));
sewardjdf0e0022005-01-25 15:48:43 +00002461 } else {
2462 assign( dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
2463 if (isAddSub(op8))
2464 setFlags_DEP1_DEP2(op8, dst0, src, ty);
2465 else
2466 setFlags_DEP1(op8, dst1, ty);
2467 if (keep)
sewardj5b470602005-02-27 13:10:48 +00002468 putIRegG(size, pfx, rm, mkexpr(dst1));
sewardjdf0e0022005-01-25 15:48:43 +00002469 }
2470
2471 DIP("%s%c %s,%s\n", t_amd64opc, nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00002472 dis_buf, nameIRegG(size, pfx, rm));
sewardjdf0e0022005-01-25 15:48:43 +00002473 return len+delta0;
2474 }
2475}
2476
2477
2478
sewardj3ca55a12005-01-27 16:06:23 +00002479/* Handle binary integer instructions of the form
2480 op G, E meaning
2481 op reg, reg-or-mem
2482 Is passed the a ptr to the modRM byte, the actual operation, and the
2483 data size. Returns the address advanced completely over this
2484 instruction.
2485
2486 G(src) is reg.
2487 E(dst) is reg-or-mem
2488
2489 If E is reg, --> GET %E, tmp
2490 OP %G, tmp
2491 PUT tmp, %E
2492
2493 If E is mem, --> (getAddr E) -> tmpa
2494 LD (tmpa), tmpv
2495 OP %G, tmpv
2496 ST tmpv, (tmpa)
2497*/
2498static
sewardj8c332e22005-01-28 01:36:56 +00002499ULong dis_op2_G_E ( Prefix pfx,
2500 Bool addSubCarry,
2501 IROp op8,
2502 Bool keep,
2503 Int size,
sewardj270def42005-07-03 01:03:01 +00002504 Long delta0,
sewardj8c332e22005-01-28 01:36:56 +00002505 HChar* t_amd64opc )
sewardj3ca55a12005-01-27 16:06:23 +00002506{
2507 HChar dis_buf[50];
2508 Int len;
2509 IRType ty = szToITy(size);
2510 IRTemp dst1 = newTemp(ty);
2511 IRTemp src = newTemp(ty);
2512 IRTemp dst0 = newTemp(ty);
sewardj8c332e22005-01-28 01:36:56 +00002513 UChar rm = getUChar(delta0);
sewardj3ca55a12005-01-27 16:06:23 +00002514 IRTemp addr = IRTemp_INVALID;
2515
2516 /* addSubCarry == True indicates the intended operation is
2517 add-with-carry or subtract-with-borrow. */
2518 if (addSubCarry) {
2519 vassert(op8 == Iop_Add8 || op8 == Iop_Sub8);
2520 vassert(keep);
2521 }
2522
2523 if (epartIsReg(rm)) {
2524 /* Specially handle XOR reg,reg, because that doesn't really
2525 depend on reg, and doing the obvious thing potentially
2526 generates a spurious value check failure due to the bogus
sewardj5b470602005-02-27 13:10:48 +00002527 dependency. Ditto SBB reg,reg. */
2528 if ((op8 == Iop_Xor8 || (op8 == Iop_Sub8 && addSubCarry))
2529 && offsetIRegG(size,pfx,rm) == offsetIRegE(size,pfx,rm)) {
2530 putIRegE(size,pfx,rm, mkU(ty,0));
sewardj3ca55a12005-01-27 16:06:23 +00002531 }
sewardj5b470602005-02-27 13:10:48 +00002532
2533 assign(dst0, getIRegE(size,pfx,rm));
2534 assign(src, getIRegG(size,pfx,rm));
sewardj3ca55a12005-01-27 16:06:23 +00002535
2536 if (addSubCarry && op8 == Iop_Add8) {
sewardj3ca55a12005-01-27 16:06:23 +00002537 helper_ADC( size, dst1, dst0, src );
sewardj5b470602005-02-27 13:10:48 +00002538 putIRegE(size, pfx, rm, mkexpr(dst1));
sewardj3ca55a12005-01-27 16:06:23 +00002539 } else
2540 if (addSubCarry && op8 == Iop_Sub8) {
sewardj3ca55a12005-01-27 16:06:23 +00002541 helper_SBB( size, dst1, dst0, src );
sewardj5b470602005-02-27 13:10:48 +00002542 putIRegE(size, pfx, rm, mkexpr(dst1));
sewardj3ca55a12005-01-27 16:06:23 +00002543 } else {
2544 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
2545 if (isAddSub(op8))
2546 setFlags_DEP1_DEP2(op8, dst0, src, ty);
2547 else
2548 setFlags_DEP1(op8, dst1, ty);
2549 if (keep)
sewardj5b470602005-02-27 13:10:48 +00002550 putIRegE(size, pfx, rm, mkexpr(dst1));
sewardj3ca55a12005-01-27 16:06:23 +00002551 }
2552
2553 DIP("%s%c %s,%s\n", t_amd64opc, nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00002554 nameIRegG(size,pfx,rm),
2555 nameIRegE(size,pfx,rm));
sewardj3ca55a12005-01-27 16:06:23 +00002556 return 1+delta0;
2557 }
2558
2559 /* E refers to memory */
2560 {
sewardje1698952005-02-08 15:02:39 +00002561 addr = disAMode ( &len, pfx, delta0, dis_buf, 0 );
sewardj3ca55a12005-01-27 16:06:23 +00002562 assign(dst0, loadLE(ty,mkexpr(addr)));
sewardj5b470602005-02-27 13:10:48 +00002563 assign(src, getIRegG(size,pfx,rm));
sewardj3ca55a12005-01-27 16:06:23 +00002564
2565 if (addSubCarry && op8 == Iop_Add8) {
sewardj3ca55a12005-01-27 16:06:23 +00002566 helper_ADC( size, dst1, dst0, src );
2567 storeLE(mkexpr(addr), mkexpr(dst1));
2568 } else
2569 if (addSubCarry && op8 == Iop_Sub8) {
2570 vassert(0); /* awaiting test case */
2571 helper_SBB( size, dst1, dst0, src );
2572 storeLE(mkexpr(addr), mkexpr(dst1));
2573 } else {
2574 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
2575 if (isAddSub(op8))
2576 setFlags_DEP1_DEP2(op8, dst0, src, ty);
2577 else
2578 setFlags_DEP1(op8, dst1, ty);
2579 if (keep)
2580 storeLE(mkexpr(addr), mkexpr(dst1));
2581 }
2582
2583 DIP("%s%c %s,%s\n", t_amd64opc, nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00002584 nameIRegG(size,pfx,rm), dis_buf);
sewardj3ca55a12005-01-27 16:06:23 +00002585 return len+delta0;
2586 }
2587}
2588
2589
sewardj1389d4d2005-01-28 13:46:29 +00002590/* Handle move instructions of the form
2591 mov E, G meaning
2592 mov reg-or-mem, reg
2593 Is passed the a ptr to the modRM byte, and the data size. Returns
2594 the address advanced completely over this instruction.
2595
2596 E(src) is reg-or-mem
2597 G(dst) is reg.
2598
2599 If E is reg, --> GET %E, tmpv
2600 PUT tmpv, %G
2601
2602 If E is mem --> (getAddr E) -> tmpa
2603 LD (tmpa), tmpb
2604 PUT tmpb, %G
2605*/
2606static
2607ULong dis_mov_E_G ( Prefix pfx,
2608 Int size,
sewardj270def42005-07-03 01:03:01 +00002609 Long delta0 )
sewardj1389d4d2005-01-28 13:46:29 +00002610{
2611 Int len;
2612 UChar rm = getUChar(delta0);
2613 HChar dis_buf[50];
2614
2615 if (epartIsReg(rm)) {
sewardj5b470602005-02-27 13:10:48 +00002616 putIRegG(size, pfx, rm, getIRegE(size, pfx, rm));
sewardje941eea2005-01-30 19:52:28 +00002617 DIP("mov%c %s,%s\n", nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00002618 nameIRegE(size,pfx,rm),
2619 nameIRegG(size,pfx,rm));
sewardj1389d4d2005-01-28 13:46:29 +00002620 return 1+delta0;
2621 }
2622
2623 /* E refers to memory */
2624 {
sewardje1698952005-02-08 15:02:39 +00002625 IRTemp addr = disAMode ( &len, pfx, delta0, dis_buf, 0 );
sewardj5b470602005-02-27 13:10:48 +00002626 putIRegG(size, pfx, rm, loadLE(szToITy(size), mkexpr(addr)));
sewardj1389d4d2005-01-28 13:46:29 +00002627 DIP("mov%c %s,%s\n", nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00002628 dis_buf,
2629 nameIRegG(size,pfx,rm));
sewardj1389d4d2005-01-28 13:46:29 +00002630 return delta0+len;
2631 }
2632}
2633
2634
2635/* Handle move instructions of the form
2636 mov G, E meaning
2637 mov reg, reg-or-mem
2638 Is passed the a ptr to the modRM byte, and the data size. Returns
2639 the address advanced completely over this instruction.
2640
2641 G(src) is reg.
2642 E(dst) is reg-or-mem
2643
2644 If E is reg, --> GET %G, tmp
2645 PUT tmp, %E
2646
2647 If E is mem, --> (getAddr E) -> tmpa
2648 GET %G, tmpv
2649 ST tmpv, (tmpa)
2650*/
2651static
2652ULong dis_mov_G_E ( Prefix pfx,
2653 Int size,
sewardj270def42005-07-03 01:03:01 +00002654 Long delta0 )
sewardj1389d4d2005-01-28 13:46:29 +00002655{
2656 Int len;
2657 UChar rm = getUChar(delta0);
2658 HChar dis_buf[50];
2659
2660 if (epartIsReg(rm)) {
sewardj5b470602005-02-27 13:10:48 +00002661 putIRegE(size, pfx, rm, getIRegG(size, pfx, rm));
sewardje941eea2005-01-30 19:52:28 +00002662 DIP("mov%c %s,%s\n", nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00002663 nameIRegG(size,pfx,rm),
2664 nameIRegE(size,pfx,rm));
sewardj1389d4d2005-01-28 13:46:29 +00002665 return 1+delta0;
2666 }
2667
2668 /* E refers to memory */
2669 {
sewardje1698952005-02-08 15:02:39 +00002670 IRTemp addr = disAMode ( &len, pfx, delta0, dis_buf, 0 );
sewardj5b470602005-02-27 13:10:48 +00002671 storeLE( mkexpr(addr), getIRegG(size, pfx, rm) );
sewardj1389d4d2005-01-28 13:46:29 +00002672 DIP("mov%c %s,%s\n", nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00002673 nameIRegG(size,pfx,rm),
2674 dis_buf);
sewardj1389d4d2005-01-28 13:46:29 +00002675 return len+delta0;
2676 }
2677}
sewardj3ca55a12005-01-27 16:06:23 +00002678
2679
2680/* op $immediate, AL/AX/EAX/RAX. */
2681static
sewardj8c332e22005-01-28 01:36:56 +00002682ULong dis_op_imm_A ( Int size,
sewardj41c01092005-07-23 13:50:32 +00002683 Bool carrying,
sewardj8c332e22005-01-28 01:36:56 +00002684 IROp op8,
2685 Bool keep,
sewardj270def42005-07-03 01:03:01 +00002686 Long delta,
sewardj8c332e22005-01-28 01:36:56 +00002687 HChar* t_amd64opc )
sewardj3ca55a12005-01-27 16:06:23 +00002688{
2689 Int size4 = imin(size,4);
2690 IRType ty = szToITy(size);
2691 IRTemp dst0 = newTemp(ty);
2692 IRTemp src = newTemp(ty);
2693 IRTemp dst1 = newTemp(ty);
sewardj8c332e22005-01-28 01:36:56 +00002694 Long lit = getSDisp(size4,delta);
sewardj5b470602005-02-27 13:10:48 +00002695 assign(dst0, getIRegRAX(size));
sewardj1389d4d2005-01-28 13:46:29 +00002696 assign(src, mkU(ty,lit & mkSizeMask(size)));
sewardj41c01092005-07-23 13:50:32 +00002697
2698 if (isAddSub(op8) && !carrying) {
2699 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
sewardj3ca55a12005-01-27 16:06:23 +00002700 setFlags_DEP1_DEP2(op8, dst0, src, ty);
sewardj41c01092005-07-23 13:50:32 +00002701 }
sewardj3ca55a12005-01-27 16:06:23 +00002702 else
sewardj41c01092005-07-23 13:50:32 +00002703 if (isLogic(op8)) {
2704 vassert(!carrying);
2705 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
sewardj3ca55a12005-01-27 16:06:23 +00002706 setFlags_DEP1(op8, dst1, ty);
sewardj41c01092005-07-23 13:50:32 +00002707 }
sewardj3ca55a12005-01-27 16:06:23 +00002708 else
sewardj41c01092005-07-23 13:50:32 +00002709 if (op8 == Iop_Add8 && carrying) {
2710 helper_ADC( size, dst1, dst0, src );
2711 }
2712 else
2713 vpanic("dis_op_imm_A(amd64,guest)");
sewardj3ca55a12005-01-27 16:06:23 +00002714
2715 if (keep)
sewardj5b470602005-02-27 13:10:48 +00002716 putIRegRAX(size, mkexpr(dst1));
sewardj3ca55a12005-01-27 16:06:23 +00002717
2718 DIP("%s%c $%lld, %s\n", t_amd64opc, nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00002719 lit, nameIRegRAX(size));
sewardj3ca55a12005-01-27 16:06:23 +00002720 return delta+size4;
2721}
2722
2723
sewardj5e525292005-01-28 15:13:10 +00002724/* Sign- and Zero-extending moves. */
2725static
2726ULong dis_movx_E_G ( Prefix pfx,
sewardj270def42005-07-03 01:03:01 +00002727 Long delta, Int szs, Int szd, Bool sign_extend )
sewardj5e525292005-01-28 15:13:10 +00002728{
2729 UChar rm = getUChar(delta);
2730 if (epartIsReg(rm)) {
sewardj5b470602005-02-27 13:10:48 +00002731 putIRegG(szd, pfx, rm,
sewardj5e525292005-01-28 15:13:10 +00002732 doScalarWidening(
2733 szs,szd,sign_extend,
sewardj5b470602005-02-27 13:10:48 +00002734 getIRegE(szs,pfx,rm)));
sewardj5e525292005-01-28 15:13:10 +00002735 DIP("mov%c%c%c %s,%s\n", sign_extend ? 's' : 'z',
2736 nameISize(szs),
2737 nameISize(szd),
sewardj5b470602005-02-27 13:10:48 +00002738 nameIRegE(szs,pfx,rm),
2739 nameIRegG(szd,pfx,rm));
sewardj5e525292005-01-28 15:13:10 +00002740 return 1+delta;
2741 }
2742
2743 /* E refers to memory */
2744 {
2745 Int len;
2746 HChar dis_buf[50];
sewardje1698952005-02-08 15:02:39 +00002747 IRTemp addr = disAMode ( &len, pfx, delta, dis_buf, 0 );
sewardj5b470602005-02-27 13:10:48 +00002748 putIRegG(szd, pfx, rm,
sewardj5e525292005-01-28 15:13:10 +00002749 doScalarWidening(
2750 szs,szd,sign_extend,
2751 loadLE(szToITy(szs),mkexpr(addr))));
2752 DIP("mov%c%c%c %s,%s\n", sign_extend ? 's' : 'z',
2753 nameISize(szs),
2754 nameISize(szd),
2755 dis_buf,
sewardj5b470602005-02-27 13:10:48 +00002756 nameIRegG(szd,pfx,rm));
sewardj5e525292005-01-28 15:13:10 +00002757 return len+delta;
2758 }
2759}
sewardj32b2bbe2005-01-28 00:50:10 +00002760
2761
sewardj03b07cc2005-01-31 18:09:43 +00002762/* Generate code to divide ArchRegs RDX:RAX / EDX:EAX / DX:AX / AX by
2763 the 64 / 32 / 16 / 8 bit quantity in the given IRTemp. */
sewardj32b2bbe2005-01-28 00:50:10 +00002764static
2765void codegen_div ( Int sz, IRTemp t, Bool signed_divide )
2766{
sewardj03b07cc2005-01-31 18:09:43 +00002767 /* special-case the 64-bit case */
2768 if (sz == 8) {
2769 IROp op = signed_divide ? Iop_DivModS128to64
2770 : Iop_DivModU128to64;
sewardja6b93d12005-02-17 09:28:28 +00002771 IRTemp src128 = newTemp(Ity_I128);
2772 IRTemp dst128 = newTemp(Ity_I128);
sewardj03b07cc2005-01-31 18:09:43 +00002773 assign( src128, binop(Iop_64HLto128,
sewardja6b93d12005-02-17 09:28:28 +00002774 getIReg64(R_RDX),
2775 getIReg64(R_RAX)) );
sewardj03b07cc2005-01-31 18:09:43 +00002776 assign( dst128, binop(op, mkexpr(src128), mkexpr(t)) );
sewardja6b93d12005-02-17 09:28:28 +00002777 putIReg64( R_RAX, unop(Iop_128to64,mkexpr(dst128)) );
2778 putIReg64( R_RDX, unop(Iop_128HIto64,mkexpr(dst128)) );
sewardj03b07cc2005-01-31 18:09:43 +00002779 } else {
2780 IROp op = signed_divide ? Iop_DivModS64to32
2781 : Iop_DivModU64to32;
2782 IRTemp src64 = newTemp(Ity_I64);
2783 IRTemp dst64 = newTemp(Ity_I64);
2784 switch (sz) {
sewardj85520e42005-02-19 15:22:38 +00002785 case 4:
sewardj5b470602005-02-27 13:10:48 +00002786 assign( src64,
2787 binop(Iop_32HLto64, getIRegRDX(4), getIRegRAX(4)) );
2788 assign( dst64,
2789 binop(op, mkexpr(src64), mkexpr(t)) );
2790 putIRegRAX( 4, unop(Iop_64to32,mkexpr(dst64)) );
2791 putIRegRDX( 4, unop(Iop_64HIto32,mkexpr(dst64)) );
sewardj85520e42005-02-19 15:22:38 +00002792 break;
2793 case 2: {
2794 IROp widen3264 = signed_divide ? Iop_32Sto64 : Iop_32Uto64;
2795 IROp widen1632 = signed_divide ? Iop_16Sto32 : Iop_16Uto32;
2796 assign( src64, unop(widen3264,
2797 binop(Iop_16HLto32,
sewardj5b470602005-02-27 13:10:48 +00002798 getIRegRDX(2),
2799 getIRegRAX(2))) );
sewardj85520e42005-02-19 15:22:38 +00002800 assign( dst64, binop(op, mkexpr(src64), unop(widen1632,mkexpr(t))) );
sewardj5b470602005-02-27 13:10:48 +00002801 putIRegRAX( 2, unop(Iop_32to16,unop(Iop_64to32,mkexpr(dst64))) );
2802 putIRegRDX( 2, unop(Iop_32to16,unop(Iop_64HIto32,mkexpr(dst64))) );
sewardj85520e42005-02-19 15:22:38 +00002803 break;
2804 }
2805 case 1: {
2806 IROp widen3264 = signed_divide ? Iop_32Sto64 : Iop_32Uto64;
2807 IROp widen1632 = signed_divide ? Iop_16Sto32 : Iop_16Uto32;
2808 IROp widen816 = signed_divide ? Iop_8Sto16 : Iop_8Uto16;
2809 assign( src64, unop(widen3264,
sewardj5b470602005-02-27 13:10:48 +00002810 unop(widen1632, getIRegRAX(2))) );
sewardj85520e42005-02-19 15:22:38 +00002811 assign( dst64,
2812 binop(op, mkexpr(src64),
2813 unop(widen1632, unop(widen816, mkexpr(t)))) );
sewardj5b470602005-02-27 13:10:48 +00002814 putIRegRAX( 1, unop(Iop_16to8,
2815 unop(Iop_32to16,
2816 unop(Iop_64to32,mkexpr(dst64)))) );
2817 putIRegAH( unop(Iop_16to8,
2818 unop(Iop_32to16,
2819 unop(Iop_64HIto32,mkexpr(dst64)))) );
sewardj85520e42005-02-19 15:22:38 +00002820 break;
2821 }
2822 default:
2823 vpanic("codegen_div(amd64)");
sewardj03b07cc2005-01-31 18:09:43 +00002824 }
sewardj32b2bbe2005-01-28 00:50:10 +00002825 }
2826}
sewardj3ca55a12005-01-27 16:06:23 +00002827
2828static
sewardj8c332e22005-01-28 01:36:56 +00002829ULong dis_Grp1 ( Prefix pfx,
sewardj270def42005-07-03 01:03:01 +00002830 Long delta, UChar modrm,
sewardj227458e2005-01-31 19:04:50 +00002831 Int am_sz, Int d_sz, Int sz, Long d64 )
sewardj3ca55a12005-01-27 16:06:23 +00002832{
2833 Int len;
2834 HChar dis_buf[50];
2835 IRType ty = szToITy(sz);
2836 IRTemp dst1 = newTemp(ty);
2837 IRTemp src = newTemp(ty);
2838 IRTemp dst0 = newTemp(ty);
2839 IRTemp addr = IRTemp_INVALID;
2840 IROp op8 = Iop_INVALID;
sewardj1389d4d2005-01-28 13:46:29 +00002841 ULong mask = mkSizeMask(sz);
sewardj3ca55a12005-01-27 16:06:23 +00002842
sewardj901ed122005-02-27 13:25:31 +00002843 switch (gregLO3ofRM(modrm)) {
sewardj3ca55a12005-01-27 16:06:23 +00002844 case 0: op8 = Iop_Add8; break; case 1: op8 = Iop_Or8; break;
2845 case 2: break; // ADC
2846 case 3: break; // SBB
2847 case 4: op8 = Iop_And8; break; case 5: op8 = Iop_Sub8; break;
2848 case 6: op8 = Iop_Xor8; break; case 7: op8 = Iop_Sub8; break;
2849 default: vpanic("dis_Grp1(amd64): unhandled case");
2850 }
2851
2852 if (epartIsReg(modrm)) {
2853 vassert(am_sz == 1);
2854
sewardj5b470602005-02-27 13:10:48 +00002855 assign(dst0, getIRegE(sz,pfx,modrm));
sewardj227458e2005-01-31 19:04:50 +00002856 assign(src, mkU(ty,d64 & mask));
sewardj3ca55a12005-01-27 16:06:23 +00002857
sewardj901ed122005-02-27 13:25:31 +00002858 if (gregLO3ofRM(modrm) == 2 /* ADC */) {
sewardj3ca55a12005-01-27 16:06:23 +00002859 helper_ADC( sz, dst1, dst0, src );
2860 } else
sewardj901ed122005-02-27 13:25:31 +00002861 if (gregLO3ofRM(modrm) == 3 /* SBB */) {
sewardj3ca55a12005-01-27 16:06:23 +00002862 helper_SBB( sz, dst1, dst0, src );
2863 } else {
2864 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
2865 if (isAddSub(op8))
2866 setFlags_DEP1_DEP2(op8, dst0, src, ty);
2867 else
2868 setFlags_DEP1(op8, dst1, ty);
2869 }
2870
sewardj901ed122005-02-27 13:25:31 +00002871 if (gregLO3ofRM(modrm) < 7)
sewardj5b470602005-02-27 13:10:48 +00002872 putIRegE(sz, pfx, modrm, mkexpr(dst1));
sewardj3ca55a12005-01-27 16:06:23 +00002873
2874 delta += (am_sz + d_sz);
sewardje941eea2005-01-30 19:52:28 +00002875 DIP("%s%c $%lld, %s\n",
sewardj901ed122005-02-27 13:25:31 +00002876 nameGrp1(gregLO3ofRM(modrm)), nameISize(sz), d64,
sewardj5b470602005-02-27 13:10:48 +00002877 nameIRegE(sz,pfx,modrm));
sewardj3ca55a12005-01-27 16:06:23 +00002878 } else {
sewardje1698952005-02-08 15:02:39 +00002879 addr = disAMode ( &len, pfx, delta, dis_buf, /*xtra*/d_sz );
sewardj3ca55a12005-01-27 16:06:23 +00002880
2881 assign(dst0, loadLE(ty,mkexpr(addr)));
sewardj227458e2005-01-31 19:04:50 +00002882 assign(src, mkU(ty,d64 & mask));
sewardj3ca55a12005-01-27 16:06:23 +00002883
sewardj901ed122005-02-27 13:25:31 +00002884 if (gregLO3ofRM(modrm) == 2 /* ADC */) {
sewardj3ca55a12005-01-27 16:06:23 +00002885 helper_ADC( sz, dst1, dst0, src );
2886 } else
sewardj901ed122005-02-27 13:25:31 +00002887 if (gregLO3ofRM(modrm) == 3 /* SBB */) {
sewardj3ca55a12005-01-27 16:06:23 +00002888 helper_SBB( sz, dst1, dst0, src );
2889 } else {
2890 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
2891 if (isAddSub(op8))
2892 setFlags_DEP1_DEP2(op8, dst0, src, ty);
2893 else
2894 setFlags_DEP1(op8, dst1, ty);
2895 }
2896
sewardj901ed122005-02-27 13:25:31 +00002897 if (gregLO3ofRM(modrm) < 7)
sewardj3ca55a12005-01-27 16:06:23 +00002898 storeLE(mkexpr(addr), mkexpr(dst1));
2899
2900 delta += (len+d_sz);
sewardje941eea2005-01-30 19:52:28 +00002901 DIP("%s%c $%lld, %s\n",
sewardj901ed122005-02-27 13:25:31 +00002902 nameGrp1(gregLO3ofRM(modrm)), nameISize(sz),
sewardj227458e2005-01-31 19:04:50 +00002903 d64, dis_buf);
sewardj3ca55a12005-01-27 16:06:23 +00002904 }
2905 return delta;
2906}
2907
2908
sewardj118b23e2005-01-29 02:14:44 +00002909/* Group 2 extended opcodes. shift_expr must be an 8-bit typed
2910 expression. */
2911
2912static
2913ULong dis_Grp2 ( Prefix pfx,
sewardj270def42005-07-03 01:03:01 +00002914 Long delta, UChar modrm,
sewardj118b23e2005-01-29 02:14:44 +00002915 Int am_sz, Int d_sz, Int sz, IRExpr* shift_expr,
2916 HChar* shift_expr_txt )
2917{
2918 /* delta on entry points at the modrm byte. */
2919 HChar dis_buf[50];
2920 Int len;
2921 Bool isShift, isRotate, isRotateRC;
2922 IRType ty = szToITy(sz);
2923 IRTemp dst0 = newTemp(ty);
2924 IRTemp dst1 = newTemp(ty);
2925 IRTemp addr = IRTemp_INVALID;
2926
2927 vassert(sz == 1 || sz == 2 || sz == 4 || sz == 8);
2928
2929 /* Put value to shift/rotate in dst0. */
2930 if (epartIsReg(modrm)) {
sewardj5b470602005-02-27 13:10:48 +00002931 assign(dst0, getIRegE(sz, pfx, modrm));
sewardj118b23e2005-01-29 02:14:44 +00002932 delta += (am_sz + d_sz);
2933 } else {
sewardj3587c6b2005-08-14 00:09:58 +00002934 addr = disAMode ( &len, pfx, delta, dis_buf, /*xtra*/d_sz );
sewardj118b23e2005-01-29 02:14:44 +00002935 assign(dst0, loadLE(ty,mkexpr(addr)));
2936 delta += len + d_sz;
2937 }
2938
2939 isShift = False;
sewardj901ed122005-02-27 13:25:31 +00002940 switch (gregLO3ofRM(modrm)) { case 4: case 5: case 7: isShift = True; }
sewardj118b23e2005-01-29 02:14:44 +00002941
2942 isRotate = False;
sewardj901ed122005-02-27 13:25:31 +00002943 switch (gregLO3ofRM(modrm)) { case 0: case 1: isRotate = True; }
sewardj118b23e2005-01-29 02:14:44 +00002944
sewardj901ed122005-02-27 13:25:31 +00002945 isRotateRC = toBool(gregLO3ofRM(modrm) == 3);
sewardj118b23e2005-01-29 02:14:44 +00002946
2947 if (!isShift && !isRotate && !isRotateRC) {
sewardj901ed122005-02-27 13:25:31 +00002948 vex_printf("\ncase %d\n", gregLO3ofRM(modrm));
sewardj118b23e2005-01-29 02:14:44 +00002949 vpanic("dis_Grp2(Reg): unhandled case(amd64)");
2950 }
2951
2952 if (isRotateRC) {
sewardj112b0992005-07-23 13:19:32 +00002953 /* Call a helper; this insn is so ridiculous it does not deserve
2954 better. One problem is, the helper has to calculate both the
2955 new value and the new flags. This is more than 64 bits, and
2956 there is no way to return more than 64 bits from the helper.
2957 Hence the crude and obvious solution is to call it twice,
2958 using the sign of the sz field to indicate whether it is the
2959 value or rflags result we want.
2960 */
2961 IRExpr** argsVALUE;
2962 IRExpr** argsRFLAGS;
2963
2964 IRTemp new_value = newTemp(Ity_I64);
2965 IRTemp new_rflags = newTemp(Ity_I64);
2966 IRTemp old_rflags = newTemp(Ity_I64);
2967
2968 assign( old_rflags, widenUto64(mk_amd64g_calculate_rflags_all()) );
2969
2970 argsVALUE
2971 = mkIRExprVec_4( widenUto64(mkexpr(dst0)), /* thing to rotate */
2972 widenUto64(shift_expr), /* rotate amount */
2973 mkexpr(old_rflags),
2974 mkU64(sz) );
2975 assign( new_value,
2976 mkIRExprCCall(
2977 Ity_I64,
2978 0/*regparm*/,
2979 "amd64g_calculate_RCR", &amd64g_calculate_RCR,
2980 argsVALUE
2981 )
2982 );
2983
2984 argsRFLAGS
2985 = mkIRExprVec_4( widenUto64(mkexpr(dst0)), /* thing to rotate */
2986 widenUto64(shift_expr), /* rotate amount */
2987 mkexpr(old_rflags),
2988 mkU64(-sz) );
2989 assign( new_rflags,
2990 mkIRExprCCall(
2991 Ity_I64,
2992 0/*regparm*/,
2993 "amd64g_calculate_RCR", &amd64g_calculate_RCR,
2994 argsRFLAGS
2995 )
2996 );
2997
2998 assign( dst1, narrowTo(ty, mkexpr(new_value)) );
2999 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(AMD64G_CC_OP_COPY) ));
3000 stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(new_rflags) ));
3001 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
3002 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU64(0) ));
sewardj118b23e2005-01-29 02:14:44 +00003003 }
3004
sewardj112b0992005-07-23 13:19:32 +00003005 else
sewardj118b23e2005-01-29 02:14:44 +00003006 if (isShift) {
3007
3008 IRTemp pre64 = newTemp(Ity_I64);
3009 IRTemp res64 = newTemp(Ity_I64);
3010 IRTemp res64ss = newTemp(Ity_I64);
3011 IRTemp shift_amt = newTemp(Ity_I8);
sewardj1027dc22005-02-26 01:55:02 +00003012 UChar mask = toUChar(sz==8 ? 63 : 31);
sewardj118b23e2005-01-29 02:14:44 +00003013 IROp op64;
3014
sewardj901ed122005-02-27 13:25:31 +00003015 switch (gregLO3ofRM(modrm)) {
sewardj118b23e2005-01-29 02:14:44 +00003016 case 4: op64 = Iop_Shl64; break;
3017 case 5: op64 = Iop_Shr64; break;
3018 case 7: op64 = Iop_Sar64; break;
3019 default: vpanic("dis_Grp2:shift"); break;
3020 }
3021
3022 /* Widen the value to be shifted to 64 bits, do the shift, and
3023 narrow back down. This seems surprisingly long-winded, but
3024 unfortunately the AMD semantics requires that 8/16/32-bit
3025 shifts give defined results for shift values all the way up
sewardj03c96e82005-02-19 18:12:45 +00003026 to 32, and this seems the simplest way to do it. It has the
sewardj118b23e2005-01-29 02:14:44 +00003027 advantage that the only IR level shifts generated are of 64
3028 bit values, and the shift amount is guaranteed to be in the
3029 range 0 .. 63, thereby observing the IR semantics requiring
sewardj03c96e82005-02-19 18:12:45 +00003030 all shift values to be in the range 0 .. 2^word_size-1.
sewardj118b23e2005-01-29 02:14:44 +00003031
sewardj03c96e82005-02-19 18:12:45 +00003032 Therefore the shift amount is masked with 63 for 64-bit shifts
3033 and 31 for all others.
3034 */
3035 /* shift_amt = shift_expr & MASK, regardless of operation size */
3036 assign( shift_amt, binop(Iop_And8, shift_expr, mkU8(mask)) );
sewardj118b23e2005-01-29 02:14:44 +00003037
sewardj03c96e82005-02-19 18:12:45 +00003038 /* suitably widen the value to be shifted to 64 bits. */
sewardj118b23e2005-01-29 02:14:44 +00003039 assign( pre64, op64==Iop_Sar64 ? widenSto64(mkexpr(dst0))
3040 : widenUto64(mkexpr(dst0)) );
3041
3042 /* res64 = pre64 `shift` shift_amt */
3043 assign( res64, binop(op64, mkexpr(pre64), mkexpr(shift_amt)) );
3044
sewardj03c96e82005-02-19 18:12:45 +00003045 /* res64ss = pre64 `shift` ((shift_amt - 1) & MASK) */
sewardj118b23e2005-01-29 02:14:44 +00003046 assign( res64ss,
3047 binop(op64,
3048 mkexpr(pre64),
3049 binop(Iop_And8,
3050 binop(Iop_Sub8,
3051 mkexpr(shift_amt), mkU8(1)),
sewardj03c96e82005-02-19 18:12:45 +00003052 mkU8(mask))) );
sewardj118b23e2005-01-29 02:14:44 +00003053
3054 /* Build the flags thunk. */
3055 setFlags_DEP1_DEP2_shift(op64, res64, res64ss, ty, shift_amt);
3056
3057 /* Narrow the result back down. */
3058 assign( dst1, narrowTo(ty, mkexpr(res64)) );
3059
3060 } /* if (isShift) */
3061
3062 else
3063 if (isRotate) {
3064 Int ccOp = ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1
3065 : (ty==Ity_I32 ? 2 : 3));
sewardj901ed122005-02-27 13:25:31 +00003066 Bool left = toBool(gregLO3ofRM(modrm) == 0);
sewardj118b23e2005-01-29 02:14:44 +00003067 IRTemp rot_amt = newTemp(Ity_I8);
3068 IRTemp rot_amt64 = newTemp(Ity_I8);
3069 IRTemp oldFlags = newTemp(Ity_I64);
sewardj1027dc22005-02-26 01:55:02 +00003070 UChar mask = toUChar(sz==8 ? 63 : 31);
sewardj118b23e2005-01-29 02:14:44 +00003071
3072 /* rot_amt = shift_expr & mask */
3073 /* By masking the rotate amount thusly, the IR-level Shl/Shr
3074 expressions never shift beyond the word size and thus remain
3075 well defined. */
sewardj03c96e82005-02-19 18:12:45 +00003076 assign(rot_amt64, binop(Iop_And8, shift_expr, mkU8(mask)));
sewardj118b23e2005-01-29 02:14:44 +00003077
3078 if (ty == Ity_I64)
3079 assign(rot_amt, mkexpr(rot_amt64));
3080 else
3081 assign(rot_amt, binop(Iop_And8, mkexpr(rot_amt64), mkU8(8*sz-1)));
3082
3083 if (left) {
3084
3085 /* dst1 = (dst0 << rot_amt) | (dst0 >>u (wordsize-rot_amt)) */
3086 assign(dst1,
3087 binop( mkSizedOp(ty,Iop_Or8),
3088 binop( mkSizedOp(ty,Iop_Shl8),
3089 mkexpr(dst0),
3090 mkexpr(rot_amt)
3091 ),
3092 binop( mkSizedOp(ty,Iop_Shr8),
3093 mkexpr(dst0),
3094 binop(Iop_Sub8,mkU8(8*sz), mkexpr(rot_amt))
3095 )
3096 )
3097 );
3098 ccOp += AMD64G_CC_OP_ROLB;
3099
3100 } else { /* right */
3101
3102 /* dst1 = (dst0 >>u rot_amt) | (dst0 << (wordsize-rot_amt)) */
3103 assign(dst1,
3104 binop( mkSizedOp(ty,Iop_Or8),
3105 binop( mkSizedOp(ty,Iop_Shr8),
3106 mkexpr(dst0),
3107 mkexpr(rot_amt)
3108 ),
3109 binop( mkSizedOp(ty,Iop_Shl8),
3110 mkexpr(dst0),
3111 binop(Iop_Sub8,mkU8(8*sz), mkexpr(rot_amt))
3112 )
3113 )
3114 );
3115 ccOp += AMD64G_CC_OP_RORB;
3116
3117 }
3118
3119 /* dst1 now holds the rotated value. Build flag thunk. We
3120 need the resulting value for this, and the previous flags.
3121 Except don't set it if the rotate count is zero. */
3122
3123 assign(oldFlags, mk_amd64g_calculate_rflags_all());
3124
3125 /* CC_DEP1 is the rotated value. CC_NDEP is flags before. */
3126 stmt( IRStmt_Put( OFFB_CC_OP,
3127 IRExpr_Mux0X( mkexpr(rot_amt64),
3128 IRExpr_Get(OFFB_CC_OP,Ity_I64),
3129 mkU64(ccOp))) );
3130 stmt( IRStmt_Put( OFFB_CC_DEP1,
3131 IRExpr_Mux0X( mkexpr(rot_amt64),
3132 IRExpr_Get(OFFB_CC_DEP1,Ity_I64),
3133 widenUto64(mkexpr(dst1)))) );
3134 stmt( IRStmt_Put( OFFB_CC_DEP2,
3135 IRExpr_Mux0X( mkexpr(rot_amt64),
3136 IRExpr_Get(OFFB_CC_DEP2,Ity_I64),
3137 mkU64(0))) );
3138 stmt( IRStmt_Put( OFFB_CC_NDEP,
3139 IRExpr_Mux0X( mkexpr(rot_amt64),
3140 IRExpr_Get(OFFB_CC_NDEP,Ity_I64),
3141 mkexpr(oldFlags))) );
3142 } /* if (isRotate) */
3143
3144 /* Save result, and finish up. */
3145 if (epartIsReg(modrm)) {
sewardj5b470602005-02-27 13:10:48 +00003146 putIRegE(sz, pfx, modrm, mkexpr(dst1));
sewardj118b23e2005-01-29 02:14:44 +00003147 if (vex_traceflags & VEX_TRACE_FE) {
3148 vex_printf("%s%c ",
sewardj901ed122005-02-27 13:25:31 +00003149 nameGrp2(gregLO3ofRM(modrm)), nameISize(sz) );
sewardj118b23e2005-01-29 02:14:44 +00003150 if (shift_expr_txt)
3151 vex_printf("%s", shift_expr_txt);
3152 else
3153 ppIRExpr(shift_expr);
sewardj5b470602005-02-27 13:10:48 +00003154 vex_printf(", %s\n", nameIRegE(sz,pfx,modrm));
sewardj118b23e2005-01-29 02:14:44 +00003155 }
3156 } else {
3157 storeLE(mkexpr(addr), mkexpr(dst1));
3158 if (vex_traceflags & VEX_TRACE_FE) {
3159 vex_printf("%s%c ",
sewardj901ed122005-02-27 13:25:31 +00003160 nameGrp2(gregLO3ofRM(modrm)), nameISize(sz) );
sewardj118b23e2005-01-29 02:14:44 +00003161 if (shift_expr_txt)
3162 vex_printf("%s", shift_expr_txt);
3163 else
3164 ppIRExpr(shift_expr);
3165 vex_printf(", %s\n", dis_buf);
3166 }
3167 }
3168 return delta;
3169}
3170
3171
sewardj1d511802005-03-27 17:59:45 +00003172/* Group 8 extended opcodes (but BT/BTS/BTC/BTR only). */
3173static
3174ULong dis_Grp8_Imm ( Prefix pfx,
sewardj270def42005-07-03 01:03:01 +00003175 Long delta, UChar modrm,
sewardj1d511802005-03-27 17:59:45 +00003176 Int am_sz, Int sz, ULong src_val,
3177 Bool* decode_OK )
3178{
3179 /* src_val denotes a d8.
3180 And delta on entry points at the modrm byte. */
sewardj118b23e2005-01-29 02:14:44 +00003181
sewardj1d511802005-03-27 17:59:45 +00003182 IRType ty = szToITy(sz);
3183 IRTemp t2 = newTemp(Ity_I64);
3184 IRTemp t2m = newTemp(Ity_I64);
3185 IRTemp t_addr = IRTemp_INVALID;
3186 HChar dis_buf[50];
3187 ULong mask;
sewardj9b967672005-02-08 11:13:09 +00003188
sewardj1d511802005-03-27 17:59:45 +00003189 /* we're optimists :-) */
3190 *decode_OK = True;
3191
3192 /* Limit src_val -- the bit offset -- to something within a word.
3193 The Intel docs say that literal offsets larger than a word are
3194 masked in this way. */
3195 switch (sz) {
3196 case 2: src_val &= 15; break;
3197 case 4: src_val &= 31; break;
sewardj537cab02005-04-07 02:03:52 +00003198 case 8: src_val &= 63; break;
sewardj1d511802005-03-27 17:59:45 +00003199 default: *decode_OK = False; return delta;
3200 }
3201
3202 /* Invent a mask suitable for the operation. */
3203 switch (gregLO3ofRM(modrm)) {
sewardj74b4f892005-05-06 01:43:56 +00003204 case 4: /* BT */ mask = 0; break;
3205 case 5: /* BTS */ mask = 1ULL << src_val; break;
3206 case 6: /* BTR */ mask = ~(1ULL << src_val); break;
3207 case 7: /* BTC */ mask = 1ULL << src_val; break;
sewardj1d511802005-03-27 17:59:45 +00003208 /* If this needs to be extended, probably simplest to make a
3209 new function to handle the other cases (0 .. 3). The
3210 Intel docs do however not indicate any use for 0 .. 3, so
3211 we don't expect this to happen. */
3212 default: *decode_OK = False; return delta;
3213 }
3214
3215 /* Fetch the value to be tested and modified into t2, which is
3216 64-bits wide regardless of sz. */
3217 if (epartIsReg(modrm)) {
3218 vassert(am_sz == 1);
3219 assign( t2, widenUto64(getIRegE(sz, pfx, modrm)) );
3220 delta += (am_sz + 1);
3221 DIP("%s%c $0x%llx, %s\n", nameGrp8(gregLO3ofRM(modrm)),
3222 nameISize(sz),
3223 src_val, nameIRegE(sz,pfx,modrm));
3224 } else {
3225 Int len;
3226 t_addr = disAMode ( &len, pfx, delta, dis_buf, 1 );
3227 delta += (len+1);
3228 assign( t2, widenUto64(loadLE(ty, mkexpr(t_addr))) );
3229 DIP("%s%c $0x%llx, %s\n", nameGrp8(gregLO3ofRM(modrm)),
3230 nameISize(sz),
3231 src_val, dis_buf);
3232 }
3233
3234 /* Copy relevant bit from t2 into the carry flag. */
3235 /* Flags: C=selected bit, O,S,Z,A,P undefined, so are set to zero. */
3236 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(AMD64G_CC_OP_COPY) ));
3237 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
3238 stmt( IRStmt_Put(
3239 OFFB_CC_DEP1,
3240 binop(Iop_And64,
3241 binop(Iop_Shr64, mkexpr(t2), mkU8(src_val)),
3242 mkU64(1))
3243 ));
3244
3245 /* Compute the new value into t2m, if non-BT. */
3246 switch (gregLO3ofRM(modrm)) {
3247 case 4: /* BT */
3248 break;
3249 case 5: /* BTS */
3250 assign( t2m, binop(Iop_Or64, mkU64(mask), mkexpr(t2)) );
3251 break;
3252 case 6: /* BTR */
3253 assign( t2m, binop(Iop_And64, mkU64(mask), mkexpr(t2)) );
3254 break;
3255 case 7: /* BTC */
3256 assign( t2m, binop(Iop_Xor64, mkU64(mask), mkexpr(t2)) );
3257 break;
3258 default:
3259 vassert(0);
3260 }
3261
3262 /* Write the result back, if non-BT. */
3263 if (gregLO3ofRM(modrm) != 4 /* BT */) {
3264 if (epartIsReg(modrm)) {
3265 putIRegE(sz, pfx, modrm, narrowTo(ty, mkexpr(t2m)));
3266 } else {
3267 storeLE(mkexpr(t_addr), narrowTo(ty, mkexpr(t2m)));
3268 }
3269 }
3270
3271 return delta;
3272}
sewardj9b967672005-02-08 11:13:09 +00003273
3274
3275/* Signed/unsigned widening multiply. Generate IR to multiply the
3276 value in RAX/EAX/AX/AL by the given IRTemp, and park the result in
3277 RDX:RAX/EDX:EAX/DX:AX/AX.
3278*/
3279static void codegen_mulL_A_D ( Int sz, Bool syned,
sewardj1027dc22005-02-26 01:55:02 +00003280 IRTemp tmp, HChar* tmp_txt )
sewardj9b967672005-02-08 11:13:09 +00003281{
3282 IRType ty = szToITy(sz);
3283 IRTemp t1 = newTemp(ty);
3284
sewardj5b470602005-02-27 13:10:48 +00003285 assign( t1, getIRegRAX(sz) );
sewardj9b967672005-02-08 11:13:09 +00003286
3287 switch (ty) {
3288 case Ity_I64: {
3289 IRTemp res128 = newTemp(Ity_I128);
3290 IRTemp resHi = newTemp(Ity_I64);
3291 IRTemp resLo = newTemp(Ity_I64);
3292 IROp mulOp = syned ? Iop_MullS64 : Iop_MullU64;
sewardj8bdb89a2005-05-05 21:46:50 +00003293 UInt tBaseOp = syned ? AMD64G_CC_OP_SMULB : AMD64G_CC_OP_UMULB;
sewardj9b967672005-02-08 11:13:09 +00003294 setFlags_MUL ( Ity_I64, t1, tmp, tBaseOp );
3295 assign( res128, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
3296 assign( resHi, unop(Iop_128HIto64,mkexpr(res128)));
3297 assign( resLo, unop(Iop_128to64,mkexpr(res128)));
sewardj5b470602005-02-27 13:10:48 +00003298 putIReg64(R_RDX, mkexpr(resHi));
3299 putIReg64(R_RAX, mkexpr(resLo));
sewardj9b967672005-02-08 11:13:09 +00003300 break;
3301 }
sewardj85520e42005-02-19 15:22:38 +00003302 case Ity_I32: {
3303 IRTemp res64 = newTemp(Ity_I64);
3304 IRTemp resHi = newTemp(Ity_I32);
3305 IRTemp resLo = newTemp(Ity_I32);
3306 IROp mulOp = syned ? Iop_MullS32 : Iop_MullU32;
3307 UInt tBaseOp = syned ? AMD64G_CC_OP_SMULB : AMD64G_CC_OP_UMULB;
3308 setFlags_MUL ( Ity_I32, t1, tmp, tBaseOp );
3309 assign( res64, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
3310 assign( resHi, unop(Iop_64HIto32,mkexpr(res64)));
3311 assign( resLo, unop(Iop_64to32,mkexpr(res64)));
sewardj5b470602005-02-27 13:10:48 +00003312 putIRegRDX(4, mkexpr(resHi));
3313 putIRegRAX(4, mkexpr(resLo));
sewardj85520e42005-02-19 15:22:38 +00003314 break;
3315 }
3316 case Ity_I16: {
3317 IRTemp res32 = newTemp(Ity_I32);
3318 IRTemp resHi = newTemp(Ity_I16);
3319 IRTemp resLo = newTemp(Ity_I16);
3320 IROp mulOp = syned ? Iop_MullS16 : Iop_MullU16;
3321 UInt tBaseOp = syned ? AMD64G_CC_OP_SMULB : AMD64G_CC_OP_UMULB;
3322 setFlags_MUL ( Ity_I16, t1, tmp, tBaseOp );
3323 assign( res32, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
3324 assign( resHi, unop(Iop_32HIto16,mkexpr(res32)));
3325 assign( resLo, unop(Iop_32to16,mkexpr(res32)));
sewardj5b470602005-02-27 13:10:48 +00003326 putIRegRDX(2, mkexpr(resHi));
3327 putIRegRAX(2, mkexpr(resLo));
sewardj85520e42005-02-19 15:22:38 +00003328 break;
3329 }
3330 case Ity_I8: {
3331 IRTemp res16 = newTemp(Ity_I16);
3332 IRTemp resHi = newTemp(Ity_I8);
3333 IRTemp resLo = newTemp(Ity_I8);
3334 IROp mulOp = syned ? Iop_MullS8 : Iop_MullU8;
3335 UInt tBaseOp = syned ? AMD64G_CC_OP_SMULB : AMD64G_CC_OP_UMULB;
3336 setFlags_MUL ( Ity_I8, t1, tmp, tBaseOp );
3337 assign( res16, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
3338 assign( resHi, unop(Iop_16HIto8,mkexpr(res16)));
3339 assign( resLo, unop(Iop_16to8,mkexpr(res16)));
sewardj5b470602005-02-27 13:10:48 +00003340 putIRegRAX(2, mkexpr(res16));
sewardj85520e42005-02-19 15:22:38 +00003341 break;
3342 }
sewardj9b967672005-02-08 11:13:09 +00003343 default:
sewardj85520e42005-02-19 15:22:38 +00003344 ppIRType(ty);
sewardj9b967672005-02-08 11:13:09 +00003345 vpanic("codegen_mulL_A_D(amd64)");
3346 }
3347 DIP("%s%c %s\n", syned ? "imul" : "mul", nameISize(sz), tmp_txt);
3348}
sewardj32b2bbe2005-01-28 00:50:10 +00003349
3350
3351/* Group 3 extended opcodes. */
3352static
sewardj270def42005-07-03 01:03:01 +00003353ULong dis_Grp3 ( Prefix pfx, Int sz, Long delta )
sewardj32b2bbe2005-01-28 00:50:10 +00003354{
sewardj227458e2005-01-31 19:04:50 +00003355 Long d64;
sewardj32b2bbe2005-01-28 00:50:10 +00003356 UChar modrm;
3357 HChar dis_buf[50];
3358 Int len;
3359 IRTemp addr;
3360 IRType ty = szToITy(sz);
3361 IRTemp t1 = newTemp(ty);
sewardj55dbb262005-01-28 16:36:51 +00003362 IRTemp dst1, src, dst0;
sewardj8c332e22005-01-28 01:36:56 +00003363 modrm = getUChar(delta);
sewardj32b2bbe2005-01-28 00:50:10 +00003364 if (epartIsReg(modrm)) {
sewardj901ed122005-02-27 13:25:31 +00003365 switch (gregLO3ofRM(modrm)) {
sewardj118b23e2005-01-29 02:14:44 +00003366 case 0: { /* TEST */
3367 delta++;
3368 d64 = getSDisp(imin(4,sz), delta);
3369 delta += imin(4,sz);
3370 dst1 = newTemp(ty);
3371 assign(dst1, binop(mkSizedOp(ty,Iop_And8),
sewardj5b470602005-02-27 13:10:48 +00003372 getIRegE(sz,pfx,modrm),
sewardj03b07cc2005-01-31 18:09:43 +00003373 mkU(ty, d64 & mkSizeMask(sz))));
sewardj118b23e2005-01-29 02:14:44 +00003374 setFlags_DEP1( Iop_And8, dst1, ty );
sewardj7eaa7cf2005-01-31 18:55:22 +00003375 DIP("test%c $%lld, %s\n",
sewardj118b23e2005-01-29 02:14:44 +00003376 nameISize(sz), d64,
sewardj5b470602005-02-27 13:10:48 +00003377 nameIRegE(sz, pfx, modrm));
sewardj118b23e2005-01-29 02:14:44 +00003378 break;
3379 }
sewardj55dbb262005-01-28 16:36:51 +00003380 case 2: /* NOT */
3381 delta++;
sewardj5b470602005-02-27 13:10:48 +00003382 putIRegE(sz, pfx, modrm,
3383 unop(mkSizedOp(ty,Iop_Not8),
3384 getIRegE(sz, pfx, modrm)));
sewardj55dbb262005-01-28 16:36:51 +00003385 DIP("not%c %s\n", nameISize(sz),
sewardj5b470602005-02-27 13:10:48 +00003386 nameIRegE(sz, pfx, modrm));
sewardj55dbb262005-01-28 16:36:51 +00003387 break;
3388 case 3: /* NEG */
3389 delta++;
3390 dst0 = newTemp(ty);
3391 src = newTemp(ty);
3392 dst1 = newTemp(ty);
3393 assign(dst0, mkU(ty,0));
sewardj5b470602005-02-27 13:10:48 +00003394 assign(src, getIRegE(sz, pfx, modrm));
sewardj55dbb262005-01-28 16:36:51 +00003395 assign(dst1, binop(mkSizedOp(ty,Iop_Sub8), mkexpr(dst0), mkexpr(src)));
3396 setFlags_DEP1_DEP2(Iop_Sub8, dst0, src, ty);
sewardj5b470602005-02-27 13:10:48 +00003397 putIRegE(sz, pfx, modrm, mkexpr(dst1));
3398 DIP("neg%c %s\n", nameISize(sz), nameIRegE(sz, pfx, modrm));
sewardj55dbb262005-01-28 16:36:51 +00003399 break;
sewardj9b967672005-02-08 11:13:09 +00003400 case 4: /* MUL (unsigned widening) */
3401 delta++;
3402 src = newTemp(ty);
sewardj5b470602005-02-27 13:10:48 +00003403 assign(src, getIRegE(sz,pfx,modrm));
sewardj9b967672005-02-08 11:13:09 +00003404 codegen_mulL_A_D ( sz, False, src,
sewardj5b470602005-02-27 13:10:48 +00003405 nameIRegE(sz,pfx,modrm) );
sewardj9b967672005-02-08 11:13:09 +00003406 break;
sewardj85520e42005-02-19 15:22:38 +00003407 case 5: /* IMUL (signed widening) */
3408 delta++;
3409 src = newTemp(ty);
sewardj5b470602005-02-27 13:10:48 +00003410 assign(src, getIRegE(sz,pfx,modrm));
sewardj85520e42005-02-19 15:22:38 +00003411 codegen_mulL_A_D ( sz, True, src,
sewardj5b470602005-02-27 13:10:48 +00003412 nameIRegE(sz,pfx,modrm) );
sewardj85520e42005-02-19 15:22:38 +00003413 break;
sewardj03b07cc2005-01-31 18:09:43 +00003414 case 6: /* DIV */
3415 delta++;
sewardj5b470602005-02-27 13:10:48 +00003416 assign( t1, getIRegE(sz, pfx, modrm) );
sewardj03b07cc2005-01-31 18:09:43 +00003417 codegen_div ( sz, t1, False );
3418 DIP("div%c %s\n", nameISize(sz),
sewardj5b470602005-02-27 13:10:48 +00003419 nameIRegE(sz, pfx, modrm));
sewardj03b07cc2005-01-31 18:09:43 +00003420 break;
sewardj32b2bbe2005-01-28 00:50:10 +00003421 case 7: /* IDIV */
3422 delta++;
sewardj5b470602005-02-27 13:10:48 +00003423 assign( t1, getIRegE(sz, pfx, modrm) );
sewardj32b2bbe2005-01-28 00:50:10 +00003424 codegen_div ( sz, t1, True );
3425 DIP("idiv%c %s\n", nameISize(sz),
sewardj5b470602005-02-27 13:10:48 +00003426 nameIRegE(sz, pfx, modrm));
sewardj32b2bbe2005-01-28 00:50:10 +00003427 break;
3428 default:
3429 vex_printf(
sewardj901ed122005-02-27 13:25:31 +00003430 "unhandled Grp3(R) case %d\n", (Int)gregLO3ofRM(modrm));
sewardj32b2bbe2005-01-28 00:50:10 +00003431 vpanic("Grp3(amd64)");
3432 }
3433 } else {
sewardj7de0d3c2005-02-13 02:26:41 +00003434 addr = disAMode ( &len, pfx, delta, dis_buf,
3435 /* we have to inform disAMode of any immediate
3436 bytes used */
sewardj901ed122005-02-27 13:25:31 +00003437 gregLO3ofRM(modrm)==0/*TEST*/
sewardj7de0d3c2005-02-13 02:26:41 +00003438 ? imin(4,sz)
3439 : 0
3440 );
sewardj32b2bbe2005-01-28 00:50:10 +00003441 t1 = newTemp(ty);
3442 delta += len;
3443 assign(t1, loadLE(ty,mkexpr(addr)));
sewardj901ed122005-02-27 13:25:31 +00003444 switch (gregLO3ofRM(modrm)) {
sewardj03b07cc2005-01-31 18:09:43 +00003445 case 0: { /* TEST */
3446 d64 = getSDisp(imin(4,sz), delta);
3447 delta += imin(4,sz);
3448 dst1 = newTemp(ty);
3449 assign(dst1, binop(mkSizedOp(ty,Iop_And8),
3450 mkexpr(t1),
3451 mkU(ty, d64 & mkSizeMask(sz))));
3452 setFlags_DEP1( Iop_And8, dst1, ty );
3453 DIP("test%c $%lld, %s\n", nameISize(sz), d64, dis_buf);
3454 break;
3455 }
sewardj82c9f2f2005-03-02 16:05:13 +00003456 /* probably OK, but awaiting test case */
3457 case 2: /* NOT */
3458 storeLE( mkexpr(addr), unop(mkSizedOp(ty,Iop_Not8), mkexpr(t1)));
3459 DIP("not%c %s\n", nameISize(sz), dis_buf);
3460 break;
sewardj7de0d3c2005-02-13 02:26:41 +00003461 case 3: /* NEG */
3462 dst0 = newTemp(ty);
3463 src = newTemp(ty);
3464 dst1 = newTemp(ty);
3465 assign(dst0, mkU(ty,0));
3466 assign(src, mkexpr(t1));
3467 assign(dst1, binop(mkSizedOp(ty,Iop_Sub8), mkexpr(dst0), mkexpr(src)));
3468 setFlags_DEP1_DEP2(Iop_Sub8, dst0, src, ty);
3469 storeLE( mkexpr(addr), mkexpr(dst1) );
3470 DIP("neg%c %s\n", nameISize(sz), dis_buf);
3471 break;
sewardj31eecde2005-03-23 03:39:55 +00003472 case 4: /* MUL (unsigned widening) */
3473 codegen_mulL_A_D ( sz, False, t1, dis_buf );
3474 break;
sewardj3aba9eb2005-03-30 23:20:47 +00003475 case 5: /* IMUL */
3476 codegen_mulL_A_D ( sz, True, t1, dis_buf );
3477 break;
sewardj1001dc42005-02-21 08:25:55 +00003478 case 6: /* DIV */
3479 codegen_div ( sz, t1, False );
3480 DIP("div%c %s\n", nameISize(sz), dis_buf);
3481 break;
sewardj82c9f2f2005-03-02 16:05:13 +00003482 case 7: /* IDIV */
3483 codegen_div ( sz, t1, True );
3484 DIP("idiv%c %s\n", nameISize(sz), dis_buf);
3485 break;
sewardj32b2bbe2005-01-28 00:50:10 +00003486 default:
3487 vex_printf(
sewardj901ed122005-02-27 13:25:31 +00003488 "unhandled Grp3(M) case %d\n", (Int)gregLO3ofRM(modrm));
sewardj32b2bbe2005-01-28 00:50:10 +00003489 vpanic("Grp3(amd64)");
3490 }
3491 }
3492 return delta;
3493}
3494
3495
sewardj03b07cc2005-01-31 18:09:43 +00003496/* Group 4 extended opcodes. */
3497static
sewardj270def42005-07-03 01:03:01 +00003498ULong dis_Grp4 ( Prefix pfx, Long delta )
sewardj03b07cc2005-01-31 18:09:43 +00003499{
3500 Int alen;
3501 UChar modrm;
3502 HChar dis_buf[50];
3503 IRType ty = Ity_I8;
3504 IRTemp t1 = newTemp(ty);
3505 IRTemp t2 = newTemp(ty);
3506
3507 modrm = getUChar(delta);
3508 if (epartIsReg(modrm)) {
sewardj5b470602005-02-27 13:10:48 +00003509 assign(t1, getIRegE(1, pfx, modrm));
sewardj901ed122005-02-27 13:25:31 +00003510 switch (gregLO3ofRM(modrm)) {
sewardj85520e42005-02-19 15:22:38 +00003511 case 0: /* INC */
3512 assign(t2, binop(Iop_Add8, mkexpr(t1), mkU8(1)));
sewardj5b470602005-02-27 13:10:48 +00003513 putIRegE(1, pfx, modrm, mkexpr(t2));
sewardj85520e42005-02-19 15:22:38 +00003514 setFlags_INC_DEC( True, t2, ty );
3515 break;
sewardj03b07cc2005-01-31 18:09:43 +00003516 case 1: /* DEC */
3517 assign(t2, binop(Iop_Sub8, mkexpr(t1), mkU8(1)));
sewardj5b470602005-02-27 13:10:48 +00003518 putIRegE(1, pfx, modrm, mkexpr(t2));
sewardj03b07cc2005-01-31 18:09:43 +00003519 setFlags_INC_DEC( False, t2, ty );
3520 break;
3521 default:
3522 vex_printf(
sewardj901ed122005-02-27 13:25:31 +00003523 "unhandled Grp4(R) case %d\n", (Int)gregLO3ofRM(modrm));
sewardj03b07cc2005-01-31 18:09:43 +00003524 vpanic("Grp4(amd64,R)");
3525 }
3526 delta++;
sewardj901ed122005-02-27 13:25:31 +00003527 DIP("%sb %s\n", nameGrp4(gregLO3ofRM(modrm)),
sewardj5b470602005-02-27 13:10:48 +00003528 nameIRegE(1, pfx, modrm));
sewardj03b07cc2005-01-31 18:09:43 +00003529 } else {
sewardje1698952005-02-08 15:02:39 +00003530 IRTemp addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
sewardj03b07cc2005-01-31 18:09:43 +00003531 assign( t1, loadLE(ty, mkexpr(addr)) );
sewardj901ed122005-02-27 13:25:31 +00003532 switch (gregLO3ofRM(modrm)) {
sewardj007e9ec2005-03-23 11:36:48 +00003533 case 0: /* INC */
3534 assign(t2, binop(Iop_Add8, mkexpr(t1), mkU8(1)));
3535 storeLE( mkexpr(addr), mkexpr(t2) );
3536 setFlags_INC_DEC( True, t2, ty );
3537 break;
3538 case 1: /* DEC */
3539 assign(t2, binop(Iop_Sub8, mkexpr(t1), mkU8(1)));
3540 storeLE( mkexpr(addr), mkexpr(t2) );
3541 setFlags_INC_DEC( False, t2, ty );
3542 break;
sewardj03b07cc2005-01-31 18:09:43 +00003543 default:
3544 vex_printf(
sewardj901ed122005-02-27 13:25:31 +00003545 "unhandled Grp4(M) case %d\n", (Int)gregLO3ofRM(modrm));
sewardj03b07cc2005-01-31 18:09:43 +00003546 vpanic("Grp4(amd64,M)");
3547 }
3548 delta += alen;
sewardj901ed122005-02-27 13:25:31 +00003549 DIP("%sb %s\n", nameGrp4(gregLO3ofRM(modrm)), dis_buf);
sewardj03b07cc2005-01-31 18:09:43 +00003550 }
3551 return delta;
3552}
sewardj354e5c62005-01-27 20:12:52 +00003553
3554
3555/* Group 5 extended opcodes. */
3556static
sewardj270def42005-07-03 01:03:01 +00003557ULong dis_Grp5 ( Prefix pfx, Int sz, Long delta, DisResult* dres )
sewardj354e5c62005-01-27 20:12:52 +00003558{
3559 Int len;
3560 UChar modrm;
3561 HChar dis_buf[50];
3562 IRTemp addr = IRTemp_INVALID;
3563 IRType ty = szToITy(sz);
3564 IRTemp t1 = newTemp(ty);
3565 IRTemp t2 = IRTemp_INVALID;
sewardj03b07cc2005-01-31 18:09:43 +00003566 IRTemp t3 = IRTemp_INVALID;
sewardj7eaa7cf2005-01-31 18:55:22 +00003567 Bool showSz = True;
sewardj354e5c62005-01-27 20:12:52 +00003568
sewardj8c332e22005-01-28 01:36:56 +00003569 modrm = getUChar(delta);
sewardj354e5c62005-01-27 20:12:52 +00003570 if (epartIsReg(modrm)) {
sewardj5b470602005-02-27 13:10:48 +00003571 assign(t1, getIRegE(sz,pfx,modrm));
sewardj901ed122005-02-27 13:25:31 +00003572 switch (gregLO3ofRM(modrm)) {
sewardj32b2bbe2005-01-28 00:50:10 +00003573 case 0: /* INC */
3574 t2 = newTemp(ty);
3575 assign(t2, binop(mkSizedOp(ty,Iop_Add8),
3576 mkexpr(t1), mkU(ty,1)));
3577 setFlags_INC_DEC( True, t2, ty );
sewardj5b470602005-02-27 13:10:48 +00003578 putIRegE(sz,pfx,modrm, mkexpr(t2));
sewardj32b2bbe2005-01-28 00:50:10 +00003579 break;
3580 case 1: /* DEC */
3581 t2 = newTemp(ty);
3582 assign(t2, binop(mkSizedOp(ty,Iop_Sub8),
3583 mkexpr(t1), mkU(ty,1)));
3584 setFlags_INC_DEC( False, t2, ty );
sewardj5b470602005-02-27 13:10:48 +00003585 putIRegE(sz,pfx,modrm, mkexpr(t2));
sewardj32b2bbe2005-01-28 00:50:10 +00003586 break;
sewardj354e5c62005-01-27 20:12:52 +00003587 case 2: /* call Ev */
sewardj03b07cc2005-01-31 18:09:43 +00003588 /* Ignore any sz value and operate as if sz==8. */
sewardjb7bcdf92005-08-02 21:20:36 +00003589 vassert(sz == 4 || sz == 8);
sewardj03b07cc2005-01-31 18:09:43 +00003590 sz = 8;
3591 t3 = newTemp(Ity_I64);
sewardj5b470602005-02-27 13:10:48 +00003592 assign(t3, getIRegE(sz,pfx,modrm));
sewardj03b07cc2005-01-31 18:09:43 +00003593 t2 = newTemp(Ity_I64);
3594 assign(t2, binop(Iop_Sub64, getIReg64(R_RSP), mkU64(8)));
3595 putIReg64(R_RSP, mkexpr(t2));
sewardj9e6491a2005-07-02 19:24:10 +00003596 storeLE( mkexpr(t2), mkU64(guest_RIP_bbstart+delta+1));
sewardj5a9ffab2005-05-12 17:55:01 +00003597 make_redzone_AbiHint(t2, "call-Ev(reg)");
sewardj03b07cc2005-01-31 18:09:43 +00003598 jmp_treg(Ijk_Call,t3);
sewardj9e6491a2005-07-02 19:24:10 +00003599 dres->whatNext = Dis_StopHere;
sewardj7eaa7cf2005-01-31 18:55:22 +00003600 showSz = False;
sewardj354e5c62005-01-27 20:12:52 +00003601 break;
sewardj354e5c62005-01-27 20:12:52 +00003602 case 4: /* jmp Ev */
sewardj03b07cc2005-01-31 18:09:43 +00003603 /* Ignore any sz value and operate as if sz==8. */
sewardj0bfc6b62005-07-07 14:15:35 +00003604 vassert(sz == 4 || sz == 8);
sewardj03b07cc2005-01-31 18:09:43 +00003605 sz = 8;
3606 t3 = newTemp(Ity_I64);
sewardj5b470602005-02-27 13:10:48 +00003607 assign(t3, getIRegE(sz,pfx,modrm));
sewardj03b07cc2005-01-31 18:09:43 +00003608 jmp_treg(Ijk_Boring,t3);
sewardj9e6491a2005-07-02 19:24:10 +00003609 dres->whatNext = Dis_StopHere;
sewardj7eaa7cf2005-01-31 18:55:22 +00003610 showSz = False;
sewardj354e5c62005-01-27 20:12:52 +00003611 break;
sewardj354e5c62005-01-27 20:12:52 +00003612 default:
3613 vex_printf(
sewardj901ed122005-02-27 13:25:31 +00003614 "unhandled Grp5(R) case %d\n", (Int)gregLO3ofRM(modrm));
sewardj354e5c62005-01-27 20:12:52 +00003615 vpanic("Grp5(amd64)");
3616 }
3617 delta++;
sewardj901ed122005-02-27 13:25:31 +00003618 DIP("%s%c %s\n", nameGrp5(gregLO3ofRM(modrm)),
sewardj7eaa7cf2005-01-31 18:55:22 +00003619 showSz ? nameISize(sz) : ' ',
sewardj5b470602005-02-27 13:10:48 +00003620 nameIRegE(sz, pfx, modrm));
sewardj354e5c62005-01-27 20:12:52 +00003621 } else {
sewardje1698952005-02-08 15:02:39 +00003622 addr = disAMode ( &len, pfx, delta, dis_buf, 0 );
sewardj901ed122005-02-27 13:25:31 +00003623 if (gregLO3ofRM(modrm) != 2 && gregLO3ofRM(modrm) != 4
3624 && gregLO3ofRM(modrm) != 6) {
sewardj03b07cc2005-01-31 18:09:43 +00003625 assign(t1, loadLE(ty,mkexpr(addr)));
sewardj909c06d2005-02-19 22:47:41 +00003626 }
sewardj901ed122005-02-27 13:25:31 +00003627 switch (gregLO3ofRM(modrm)) {
sewardj354e5c62005-01-27 20:12:52 +00003628 case 0: /* INC */
sewardj354e5c62005-01-27 20:12:52 +00003629 t2 = newTemp(ty);
3630 assign(t2, binop(mkSizedOp(ty,Iop_Add8),
3631 mkexpr(t1), mkU(ty,1)));
3632 setFlags_INC_DEC( True, t2, ty );
3633 storeLE(mkexpr(addr),mkexpr(t2));
3634 break;
sewardj354e5c62005-01-27 20:12:52 +00003635 case 1: /* DEC */
3636 t2 = newTemp(ty);
3637 assign(t2, binop(mkSizedOp(ty,Iop_Sub8),
3638 mkexpr(t1), mkU(ty,1)));
3639 setFlags_INC_DEC( False, t2, ty );
3640 storeLE(mkexpr(addr),mkexpr(t2));
3641 break;
3642 case 2: /* call Ev */
sewardj03b07cc2005-01-31 18:09:43 +00003643 /* Ignore any sz value and operate as if sz==8. */
sewardj354e5c62005-01-27 20:12:52 +00003644 vassert(sz == 4);
sewardj7eaa7cf2005-01-31 18:55:22 +00003645 sz = 8;
sewardj03b07cc2005-01-31 18:09:43 +00003646 t3 = newTemp(Ity_I64);
3647 assign(t3, loadLE(Ity_I64,mkexpr(addr)));
3648 t2 = newTemp(Ity_I64);
3649 assign(t2, binop(Iop_Sub64, getIReg64(R_RSP), mkU64(8)));
3650 putIReg64(R_RSP, mkexpr(t2));
sewardj9e6491a2005-07-02 19:24:10 +00003651 storeLE( mkexpr(t2), mkU64(guest_RIP_bbstart+delta+len));
sewardj5a9ffab2005-05-12 17:55:01 +00003652 make_redzone_AbiHint(t2, "call-Ev(mem)");
sewardj03b07cc2005-01-31 18:09:43 +00003653 jmp_treg(Ijk_Call,t3);
sewardj9e6491a2005-07-02 19:24:10 +00003654 dres->whatNext = Dis_StopHere;
sewardj7eaa7cf2005-01-31 18:55:22 +00003655 showSz = False;
sewardj354e5c62005-01-27 20:12:52 +00003656 break;
sewardj354e5c62005-01-27 20:12:52 +00003657 case 4: /* JMP Ev */
sewardj03b07cc2005-01-31 18:09:43 +00003658 /* Ignore any sz value and operate as if sz==8. */
sewardj354e5c62005-01-27 20:12:52 +00003659 vassert(sz == 4);
sewardj7eaa7cf2005-01-31 18:55:22 +00003660 sz = 8;
sewardj03b07cc2005-01-31 18:09:43 +00003661 t3 = newTemp(Ity_I64);
3662 assign(t3, loadLE(Ity_I64,mkexpr(addr)));
3663 jmp_treg(Ijk_Boring,t3);
sewardj9e6491a2005-07-02 19:24:10 +00003664 dres->whatNext = Dis_StopHere;
sewardj7eaa7cf2005-01-31 18:55:22 +00003665 showSz = False;
sewardj354e5c62005-01-27 20:12:52 +00003666 break;
sewardj354e5c62005-01-27 20:12:52 +00003667 case 6: /* PUSH Ev */
sewardja6b93d12005-02-17 09:28:28 +00003668 /* There is no encoding for 32-bit operand size; hence ... */
3669 if (sz == 4) sz = 8;
3670 vassert(sz == 8 || sz == 2);
sewardj909c06d2005-02-19 22:47:41 +00003671 if (sz == 8) {
3672 t3 = newTemp(Ity_I64);
3673 assign(t3, loadLE(Ity_I64,mkexpr(addr)));
3674 t2 = newTemp(Ity_I64);
3675 assign( t2, binop(Iop_Sub64,getIReg64(R_RSP),mkU64(sz)) );
3676 putIReg64(R_RSP, mkexpr(t2) );
3677 storeLE( mkexpr(t2), mkexpr(t3) );
3678 break;
3679 } else {
3680 goto unhandled; /* awaiting test case */
3681 }
sewardj354e5c62005-01-27 20:12:52 +00003682 default:
sewardja6b93d12005-02-17 09:28:28 +00003683 unhandled:
sewardj354e5c62005-01-27 20:12:52 +00003684 vex_printf(
sewardj901ed122005-02-27 13:25:31 +00003685 "unhandled Grp5(M) case %d\n", (Int)gregLO3ofRM(modrm));
sewardj354e5c62005-01-27 20:12:52 +00003686 vpanic("Grp5(amd64)");
3687 }
3688 delta += len;
sewardj901ed122005-02-27 13:25:31 +00003689 DIP("%s%c %s\n", nameGrp5(gregLO3ofRM(modrm)),
sewardj7eaa7cf2005-01-31 18:55:22 +00003690 showSz ? nameISize(sz) : ' ',
3691 dis_buf);
sewardj354e5c62005-01-27 20:12:52 +00003692 }
3693 return delta;
3694}
3695
3696
sewardjd0a12df2005-02-10 02:07:43 +00003697/*------------------------------------------------------------*/
3698/*--- Disassembling string ops (including REP prefixes) ---*/
3699/*------------------------------------------------------------*/
3700
3701/* Code shared by all the string ops */
3702static
3703void dis_string_op_increment ( Int sz, IRTemp t_inc )
3704{
3705 UChar logSz;
3706 if (sz == 8 || sz == 4 || sz == 2) {
3707 logSz = 1;
3708 if (sz == 4) logSz = 2;
3709 if (sz == 8) logSz = 3;
3710 assign( t_inc,
3711 binop(Iop_Shl64, IRExpr_Get( OFFB_DFLAG, Ity_I64 ),
3712 mkU8(logSz) ) );
3713 } else {
3714 assign( t_inc,
3715 IRExpr_Get( OFFB_DFLAG, Ity_I64 ) );
3716 }
3717}
3718
sewardj909c06d2005-02-19 22:47:41 +00003719static
3720void dis_string_op( void (*dis_OP)( Int, IRTemp ),
3721 Int sz, HChar* name, Prefix pfx )
3722{
3723 IRTemp t_inc = newTemp(Ity_I64);
3724 /* Really we ought to inspect the override prefixes, but we don't.
3725 The following assertion catches any resulting sillyness. */
3726 vassert(pfx == clearSegBits(pfx));
3727 dis_string_op_increment(sz, t_inc);
3728 dis_OP( sz, t_inc );
3729 DIP("%s%c\n", name, nameISize(sz));
3730}
3731
3732static
3733void dis_MOVS ( Int sz, IRTemp t_inc )
3734{
3735 IRType ty = szToITy(sz);
3736 IRTemp td = newTemp(Ity_I64); /* RDI */
3737 IRTemp ts = newTemp(Ity_I64); /* RSI */
3738
3739 assign( td, getIReg64(R_RDI) );
3740 assign( ts, getIReg64(R_RSI) );
3741
3742 storeLE( mkexpr(td), loadLE(ty,mkexpr(ts)) );
3743
3744 putIReg64( R_RDI, binop(Iop_Add64, mkexpr(td), mkexpr(t_inc)) );
3745 putIReg64( R_RSI, binop(Iop_Add64, mkexpr(ts), mkexpr(t_inc)) );
3746}
3747
sewardjd20c8852005-01-20 20:04:07 +00003748//.. //-- static
3749//.. //-- void dis_LODS ( UCodeBlock* cb, Int sz, Int t_inc )
3750//.. //-- {
3751//.. //-- Int ta = newTemp(cb); /* EAX */
3752//.. //-- Int ts = newTemp(cb); /* ESI */
3753//.. //--
3754//.. //-- uInstr2(cb, GET, 4, ArchReg, R_ESI, TempReg, ts);
3755//.. //-- uInstr2(cb, LOAD, sz, TempReg, ts, TempReg, ta);
3756//.. //-- uInstr2(cb, PUT, sz, TempReg, ta, ArchReg, R_EAX);
3757//.. //--
3758//.. //-- uInstr2(cb, ADD, 4, TempReg, t_inc, TempReg, ts);
3759//.. //-- uInstr2(cb, PUT, 4, TempReg, ts, ArchReg, R_ESI);
3760//.. //-- }
sewardja6b93d12005-02-17 09:28:28 +00003761
3762static
3763void dis_STOS ( Int sz, IRTemp t_inc )
3764{
3765 IRType ty = szToITy(sz);
3766 IRTemp ta = newTemp(ty); /* rAX */
3767 IRTemp td = newTemp(Ity_I64); /* RDI */
3768
sewardj5b470602005-02-27 13:10:48 +00003769 assign( ta, getIRegRAX(sz) );
sewardja6b93d12005-02-17 09:28:28 +00003770
3771 assign( td, getIReg64(R_RDI) );
3772
3773 storeLE( mkexpr(td), mkexpr(ta) );
3774
3775 putIReg64( R_RDI, binop(Iop_Add64, mkexpr(td), mkexpr(t_inc)) );
3776}
sewardjd0a12df2005-02-10 02:07:43 +00003777
3778static
3779void dis_CMPS ( Int sz, IRTemp t_inc )
3780{
3781 IRType ty = szToITy(sz);
3782 IRTemp tdv = newTemp(ty); /* (RDI) */
3783 IRTemp tsv = newTemp(ty); /* (RSI) */
3784 IRTemp td = newTemp(Ity_I64); /* RDI */
3785 IRTemp ts = newTemp(Ity_I64); /* RSI */
3786
3787 assign( td, getIReg64(R_RDI) );
3788
3789 assign( ts, getIReg64(R_RSI) );
3790
3791 assign( tdv, loadLE(ty,mkexpr(td)) );
3792
3793 assign( tsv, loadLE(ty,mkexpr(ts)) );
3794
3795 setFlags_DEP1_DEP2 ( Iop_Sub8, tsv, tdv, ty );
3796
3797 putIReg64(R_RDI, binop(Iop_Add64, mkexpr(td), mkexpr(t_inc)) );
3798
3799 putIReg64(R_RSI, binop(Iop_Add64, mkexpr(ts), mkexpr(t_inc)) );
3800}
3801
sewardj85520e42005-02-19 15:22:38 +00003802static
3803void dis_SCAS ( Int sz, IRTemp t_inc )
3804{
3805 IRType ty = szToITy(sz);
3806 IRTemp ta = newTemp(ty); /* rAX */
3807 IRTemp td = newTemp(Ity_I64); /* RDI */
3808 IRTemp tdv = newTemp(ty); /* (RDI) */
3809
sewardj5b470602005-02-27 13:10:48 +00003810 assign( ta, getIRegRAX(sz) );
sewardj85520e42005-02-19 15:22:38 +00003811
3812 assign( td, getIReg64(R_RDI) );
3813
3814 assign( tdv, loadLE(ty,mkexpr(td)) );
3815
3816 setFlags_DEP1_DEP2 ( Iop_Sub8, ta, tdv, ty );
3817
3818 putIReg64(R_RDI, binop(Iop_Add64, mkexpr(td), mkexpr(t_inc)) );
3819}
sewardjd0a12df2005-02-10 02:07:43 +00003820
3821
3822/* Wrap the appropriate string op inside a REP/REPE/REPNE. We assume
3823 the insn is the last one in the basic block, and so emit a jump to
3824 the next insn, rather than just falling through. */
3825static
3826void dis_REP_op ( AMD64Condcode cond,
3827 void (*dis_OP)(Int, IRTemp),
sewardj909c06d2005-02-19 22:47:41 +00003828 Int sz, Addr64 rip, Addr64 rip_next, HChar* name,
3829 Prefix pfx )
sewardjd0a12df2005-02-10 02:07:43 +00003830{
3831 IRTemp t_inc = newTemp(Ity_I64);
3832 IRTemp tc = newTemp(Ity_I64); /* RCX */
3833
sewardj909c06d2005-02-19 22:47:41 +00003834 /* Really we ought to inspect the override prefixes, but we don't.
3835 The following assertion catches any resulting sillyness. */
3836 vassert(pfx == clearSegBits(pfx));
3837
sewardjd0a12df2005-02-10 02:07:43 +00003838 assign( tc, getIReg64(R_RCX) );
3839
3840 stmt( IRStmt_Exit( binop(Iop_CmpEQ64,mkexpr(tc),mkU64(0)),
3841 Ijk_Boring,
3842 IRConst_U64(rip_next) ) );
3843
3844 putIReg64(R_RCX, binop(Iop_Sub64, mkexpr(tc), mkU64(1)) );
3845
3846 dis_string_op_increment(sz, t_inc);
3847 dis_OP (sz, t_inc);
3848
3849 if (cond == AMD64CondAlways) {
3850 jmp_lit(Ijk_Boring,rip);
3851 } else {
3852 stmt( IRStmt_Exit( mk_amd64g_calculate_condition(cond),
3853 Ijk_Boring,
3854 IRConst_U64(rip) ) );
3855 jmp_lit(Ijk_Boring,rip_next);
3856 }
3857 DIP("%s%c\n", name, nameISize(sz));
3858}
sewardj32b2bbe2005-01-28 00:50:10 +00003859
3860
3861/*------------------------------------------------------------*/
3862/*--- Arithmetic, etc. ---*/
3863/*------------------------------------------------------------*/
3864
3865/* IMUL E, G. Supplied eip points to the modR/M byte. */
3866static
3867ULong dis_mul_E_G ( Prefix pfx,
3868 Int size,
sewardj270def42005-07-03 01:03:01 +00003869 Long delta0 )
sewardj32b2bbe2005-01-28 00:50:10 +00003870{
3871 Int alen;
3872 HChar dis_buf[50];
sewardj8c332e22005-01-28 01:36:56 +00003873 UChar rm = getUChar(delta0);
sewardj32b2bbe2005-01-28 00:50:10 +00003874 IRType ty = szToITy(size);
3875 IRTemp te = newTemp(ty);
3876 IRTemp tg = newTemp(ty);
3877 IRTemp resLo = newTemp(ty);
3878
sewardj5b470602005-02-27 13:10:48 +00003879 assign( tg, getIRegG(size, pfx, rm) );
sewardj32b2bbe2005-01-28 00:50:10 +00003880 if (epartIsReg(rm)) {
sewardj5b470602005-02-27 13:10:48 +00003881 assign( te, getIRegE(size, pfx, rm) );
sewardj32b2bbe2005-01-28 00:50:10 +00003882 } else {
sewardje1698952005-02-08 15:02:39 +00003883 IRTemp addr = disAMode( &alen, pfx, delta0, dis_buf, 0 );
sewardj32b2bbe2005-01-28 00:50:10 +00003884 assign( te, loadLE(ty,mkexpr(addr)) );
3885 }
3886
3887 setFlags_MUL ( ty, te, tg, AMD64G_CC_OP_SMULB );
3888
3889 assign( resLo, binop( mkSizedOp(ty, Iop_Mul8), mkexpr(te), mkexpr(tg) ) );
3890
sewardj5b470602005-02-27 13:10:48 +00003891 putIRegG(size, pfx, rm, mkexpr(resLo) );
sewardj32b2bbe2005-01-28 00:50:10 +00003892
3893 if (epartIsReg(rm)) {
3894 DIP("imul%c %s, %s\n", nameISize(size),
sewardj901ed122005-02-27 13:25:31 +00003895 nameIRegE(size,pfx,rm),
3896 nameIRegG(size,pfx,rm));
sewardj32b2bbe2005-01-28 00:50:10 +00003897 return 1+delta0;
3898 } else {
3899 DIP("imul%c %s, %s\n", nameISize(size),
3900 dis_buf,
sewardj901ed122005-02-27 13:25:31 +00003901 nameIRegG(size,pfx,rm));
sewardj32b2bbe2005-01-28 00:50:10 +00003902 return alen+delta0;
3903 }
3904}
3905
3906
3907/* IMUL I * E -> G. Supplied rip points to the modR/M byte. */
3908static
3909ULong dis_imul_I_E_G ( Prefix pfx,
3910 Int size,
sewardj270def42005-07-03 01:03:01 +00003911 Long delta,
sewardj32b2bbe2005-01-28 00:50:10 +00003912 Int litsize )
3913{
3914 Long d64;
3915 Int alen;
3916 HChar dis_buf[50];
sewardj8c332e22005-01-28 01:36:56 +00003917 UChar rm = getUChar(delta);
sewardj32b2bbe2005-01-28 00:50:10 +00003918 IRType ty = szToITy(size);
3919 IRTemp te = newTemp(ty);
3920 IRTemp tl = newTemp(ty);
3921 IRTemp resLo = newTemp(ty);
3922
sewardj85520e42005-02-19 15:22:38 +00003923 vassert(/*size == 1 ||*/ size == 2 || size == 4 || size == 8);
sewardj32b2bbe2005-01-28 00:50:10 +00003924
3925 if (epartIsReg(rm)) {
sewardj5b470602005-02-27 13:10:48 +00003926 assign(te, getIRegE(size, pfx, rm));
sewardj32b2bbe2005-01-28 00:50:10 +00003927 delta++;
3928 } else {
sewardj7de0d3c2005-02-13 02:26:41 +00003929 IRTemp addr = disAMode( &alen, pfx, delta, dis_buf,
3930 imin(4,litsize) );
sewardj32b2bbe2005-01-28 00:50:10 +00003931 assign(te, loadLE(ty, mkexpr(addr)));
3932 delta += alen;
3933 }
3934 d64 = getSDisp(imin(4,litsize),delta);
3935 delta += imin(4,litsize);
3936
sewardj1389d4d2005-01-28 13:46:29 +00003937 d64 &= mkSizeMask(size);
sewardj32b2bbe2005-01-28 00:50:10 +00003938 assign(tl, mkU(ty,d64));
3939
3940 assign( resLo, binop( mkSizedOp(ty, Iop_Mul8), mkexpr(te), mkexpr(tl) ));
3941
3942 setFlags_MUL ( ty, te, tl, AMD64G_CC_OP_SMULB );
3943
sewardj5b470602005-02-27 13:10:48 +00003944 putIRegG(size, pfx, rm, mkexpr(resLo));
sewardj32b2bbe2005-01-28 00:50:10 +00003945
3946 DIP("imul%c $%lld, %s, %s\n",
3947 nameISize(size), d64,
sewardj5b470602005-02-27 13:10:48 +00003948 ( epartIsReg(rm) ? nameIRegE(size,pfx,rm) : dis_buf ),
3949 nameIRegG(size,pfx,rm) );
sewardj32b2bbe2005-01-28 00:50:10 +00003950 return delta;
3951}
3952
3953
sewardjbcbb9de2005-03-27 02:22:32 +00003954/*------------------------------------------------------------*/
3955/*--- ---*/
3956/*--- x87 FLOATING POINT INSTRUCTIONS ---*/
3957/*--- ---*/
3958/*------------------------------------------------------------*/
3959
3960/* --- Helper functions for dealing with the register stack. --- */
3961
3962/* --- Set the emulation-warning pseudo-register. --- */
3963
3964static void put_emwarn ( IRExpr* e /* :: Ity_I32 */ )
3965{
3966 vassert(typeOfIRExpr(irbb->tyenv, e) == Ity_I32);
3967 stmt( IRStmt_Put( OFFB_EMWARN, e ) );
3968}
sewardj8d965312005-02-25 02:48:47 +00003969
3970/* --- Produce an IRExpr* denoting a 64-bit QNaN. --- */
3971
3972static IRExpr* mkQNaN64 ( void )
3973{
3974 /* QNaN is 0 2047 1 0(51times)
3975 == 0b 11111111111b 1 0(51times)
3976 == 0x7FF8 0000 0000 0000
3977 */
3978 return IRExpr_Const(IRConst_F64i(0x7FF8000000000000ULL));
3979}
3980
3981/* --------- Get/put the top-of-stack pointer :: Ity_I32 --------- */
3982
3983static IRExpr* get_ftop ( void )
3984{
3985 return IRExpr_Get( OFFB_FTOP, Ity_I32 );
3986}
3987
3988static void put_ftop ( IRExpr* e )
3989{
3990 vassert(typeOfIRExpr(irbb->tyenv, e) == Ity_I32);
3991 stmt( IRStmt_Put( OFFB_FTOP, e ) );
3992}
3993
sewardj25a85812005-05-08 23:03:48 +00003994/* --------- Get/put the C3210 bits. --------- */
3995
3996static IRExpr* /* :: Ity_I64 */ get_C3210 ( void )
3997{
3998 return IRExpr_Get( OFFB_FC3210, Ity_I64 );
3999}
4000
4001static void put_C3210 ( IRExpr* e /* :: Ity_I64 */ )
4002{
4003 vassert(typeOfIRExpr(irbb->tyenv, e) == Ity_I64);
4004 stmt( IRStmt_Put( OFFB_FC3210, e ) );
4005}
sewardjc49ce232005-02-25 13:03:03 +00004006
4007/* --------- Get/put the FPU rounding mode. --------- */
4008static IRExpr* /* :: Ity_I32 */ get_fpround ( void )
4009{
4010 return unop(Iop_64to32, IRExpr_Get( OFFB_FPROUND, Ity_I64 ));
4011}
4012
sewardj5e205372005-05-09 02:57:08 +00004013static void put_fpround ( IRExpr* /* :: Ity_I32 */ e )
4014{
4015 vassert(typeOfIRExpr(irbb->tyenv, e) == Ity_I32);
4016 stmt( IRStmt_Put( OFFB_FPROUND, unop(Iop_32Uto64,e) ) );
4017}
sewardjc49ce232005-02-25 13:03:03 +00004018
4019
4020/* --------- Synthesise a 2-bit FPU rounding mode. --------- */
4021/* Produces a value in 0 .. 3, which is encoded as per the type
4022 IRRoundingMode. Since the guest_FPROUND value is also encoded as
4023 per IRRoundingMode, we merely need to get it and mask it for
4024 safety.
4025*/
4026static IRExpr* /* :: Ity_I32 */ get_roundingmode ( void )
4027{
4028 return binop( Iop_And32, get_fpround(), mkU32(3) );
4029}
sewardj8d965312005-02-25 02:48:47 +00004030
4031
4032/* --------- Get/set FP register tag bytes. --------- */
4033
4034/* Given i, and some expression e, generate 'ST_TAG(i) = e'. */
4035
4036static void put_ST_TAG ( Int i, IRExpr* value )
4037{
4038 IRArray* descr;
4039 vassert(typeOfIRExpr(irbb->tyenv, value) == Ity_I8);
4040 descr = mkIRArray( OFFB_FPTAGS, Ity_I8, 8 );
4041 stmt( IRStmt_PutI( descr, get_ftop(), i, value ) );
4042}
4043
4044/* Given i, generate an expression yielding 'ST_TAG(i)'. This will be
4045 zero to indicate "Empty" and nonzero to indicate "NonEmpty". */
4046
4047static IRExpr* get_ST_TAG ( Int i )
4048{
4049 IRArray* descr = mkIRArray( OFFB_FPTAGS, Ity_I8, 8 );
4050 return IRExpr_GetI( descr, get_ftop(), i );
4051}
4052
4053
4054/* --------- Get/set FP registers. --------- */
4055
4056/* Given i, and some expression e, emit 'ST(i) = e' and set the
4057 register's tag to indicate the register is full. The previous
4058 state of the register is not checked. */
4059
4060static void put_ST_UNCHECKED ( Int i, IRExpr* value )
4061{
4062 IRArray* descr;
4063 vassert(typeOfIRExpr(irbb->tyenv, value) == Ity_F64);
4064 descr = mkIRArray( OFFB_FPREGS, Ity_F64, 8 );
4065 stmt( IRStmt_PutI( descr, get_ftop(), i, value ) );
4066 /* Mark the register as in-use. */
4067 put_ST_TAG(i, mkU8(1));
4068}
4069
4070/* Given i, and some expression e, emit
4071 ST(i) = is_full(i) ? NaN : e
4072 and set the tag accordingly.
4073*/
4074
4075static void put_ST ( Int i, IRExpr* value )
4076{
4077 put_ST_UNCHECKED( i,
4078 IRExpr_Mux0X( get_ST_TAG(i),
4079 /* 0 means empty */
4080 value,
4081 /* non-0 means full */
4082 mkQNaN64()
4083 )
4084 );
4085}
4086
4087
4088/* Given i, generate an expression yielding 'ST(i)'. */
4089
4090static IRExpr* get_ST_UNCHECKED ( Int i )
4091{
4092 IRArray* descr = mkIRArray( OFFB_FPREGS, Ity_F64, 8 );
4093 return IRExpr_GetI( descr, get_ftop(), i );
4094}
4095
4096
4097/* Given i, generate an expression yielding
4098 is_full(i) ? ST(i) : NaN
4099*/
4100
4101static IRExpr* get_ST ( Int i )
4102{
4103 return
4104 IRExpr_Mux0X( get_ST_TAG(i),
4105 /* 0 means empty */
4106 mkQNaN64(),
4107 /* non-0 means full */
4108 get_ST_UNCHECKED(i));
4109}
4110
4111
4112/* Adjust FTOP downwards by one register. */
4113
4114static void fp_push ( void )
4115{
4116 put_ftop( binop(Iop_Sub32, get_ftop(), mkU32(1)) );
4117}
4118
4119/* Adjust FTOP upwards by one register, and mark the vacated register
4120 as empty. */
4121
4122static void fp_pop ( void )
4123{
4124 put_ST_TAG(0, mkU8(0));
4125 put_ftop( binop(Iop_Add32, get_ftop(), mkU32(1)) );
4126}
4127
sewardj25a85812005-05-08 23:03:48 +00004128/* Clear the C2 bit of the FPU status register, for
4129 sin/cos/tan/sincos. */
4130
4131static void clear_C2 ( void )
4132{
4133 put_C3210( binop(Iop_And64, get_C3210(), mkU64(~AMD64G_FC_MASK_C2)) );
4134}
sewardj48a89d82005-05-06 11:50:13 +00004135
4136
4137/* ------------------------------------------------------- */
4138/* Given all that stack-mangling junk, we can now go ahead
4139 and describe FP instructions.
4140*/
4141
4142/* ST(0) = ST(0) `op` mem64/32(addr)
4143 Need to check ST(0)'s tag on read, but not on write.
4144*/
4145static
sewardjca673ab2005-05-11 10:03:08 +00004146void fp_do_op_mem_ST_0 ( IRTemp addr, HChar* op_txt, HChar* dis_buf,
sewardj48a89d82005-05-06 11:50:13 +00004147 IROp op, Bool dbl )
4148{
4149 DIP("f%s%c %s\n", op_txt, dbl?'l':'s', dis_buf);
4150 if (dbl) {
4151 put_ST_UNCHECKED(0,
4152 binop( op,
4153 get_ST(0),
4154 loadLE(Ity_F64,mkexpr(addr))
4155 ));
4156 } else {
4157 put_ST_UNCHECKED(0,
4158 binop( op,
4159 get_ST(0),
4160 unop(Iop_F32toF64, loadLE(Ity_F32,mkexpr(addr)))
4161 ));
4162 }
4163}
sewardj7bc00082005-03-27 05:08:32 +00004164
4165
4166/* ST(0) = mem64/32(addr) `op` ST(0)
4167 Need to check ST(0)'s tag on read, but not on write.
4168*/
4169static
4170void fp_do_oprev_mem_ST_0 ( IRTemp addr, HChar* op_txt, HChar* dis_buf,
4171 IROp op, Bool dbl )
4172{
4173 DIP("f%s%c %s\n", op_txt, dbl?'l':'s', dis_buf);
4174 if (dbl) {
4175 put_ST_UNCHECKED(0,
4176 binop( op,
4177 loadLE(Ity_F64,mkexpr(addr)),
4178 get_ST(0)
4179 ));
4180 } else {
4181 put_ST_UNCHECKED(0,
4182 binop( op,
4183 unop(Iop_F32toF64, loadLE(Ity_F32,mkexpr(addr))),
4184 get_ST(0)
4185 ));
4186 }
4187}
sewardj37d52572005-02-25 14:22:12 +00004188
4189
4190/* ST(dst) = ST(dst) `op` ST(src).
4191 Check dst and src tags when reading but not on write.
4192*/
4193static
4194void fp_do_op_ST_ST ( HChar* op_txt, IROp op, UInt st_src, UInt st_dst,
4195 Bool pop_after )
4196{
sewardj1027dc22005-02-26 01:55:02 +00004197 DIP("f%s%s st(%u), st(%u)\n", op_txt, pop_after?"p":"", st_src, st_dst );
sewardj37d52572005-02-25 14:22:12 +00004198 put_ST_UNCHECKED(
4199 st_dst,
4200 binop(op, get_ST(st_dst), get_ST(st_src) )
4201 );
4202 if (pop_after)
4203 fp_pop();
4204}
4205
sewardj137015d2005-03-27 04:01:15 +00004206/* ST(dst) = ST(src) `op` ST(dst).
4207 Check dst and src tags when reading but not on write.
4208*/
4209static
4210void fp_do_oprev_ST_ST ( HChar* op_txt, IROp op, UInt st_src, UInt st_dst,
4211 Bool pop_after )
4212{
4213 DIP("f%s%s st(%u), st(%u)\n", op_txt, pop_after?"p":"", st_src, st_dst );
4214 put_ST_UNCHECKED(
4215 st_dst,
4216 binop(op, get_ST(st_src), get_ST(st_dst) )
4217 );
4218 if (pop_after)
4219 fp_pop();
4220}
sewardjc49ce232005-02-25 13:03:03 +00004221
4222/* %rflags(Z,P,C) = UCOMI( st(0), st(i) ) */
4223static void fp_do_ucomi_ST0_STi ( UInt i, Bool pop_after )
4224{
sewardj1027dc22005-02-26 01:55:02 +00004225 DIP("fucomi%s %%st(0),%%st(%u)\n", pop_after ? "p" : "", i);
sewardjc49ce232005-02-25 13:03:03 +00004226 /* This is a bit of a hack (and isn't really right). It sets
4227 Z,P,C,O correctly, but forces A and S to zero, whereas the Intel
4228 documentation implies A and S are unchanged.
4229 */
4230 /* It's also fishy in that it is used both for COMIP and
4231 UCOMIP, and they aren't the same (although similar). */
4232 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(AMD64G_CC_OP_COPY) ));
4233 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
4234 stmt( IRStmt_Put(
4235 OFFB_CC_DEP1,
4236 binop( Iop_And64,
4237 unop( Iop_32Uto64,
4238 binop(Iop_CmpF64, get_ST(0), get_ST(i))),
4239 mkU64(0x45)
4240 )));
4241 if (pop_after)
4242 fp_pop();
4243}
sewardj8d965312005-02-25 02:48:47 +00004244
4245
4246static
sewardjb4fd2e72005-03-23 13:34:11 +00004247ULong dis_FPU ( /*OUT*/Bool* decode_ok,
sewardj270def42005-07-03 01:03:01 +00004248 Prefix pfx, Long delta )
sewardj8d965312005-02-25 02:48:47 +00004249{
4250 Int len;
4251 UInt r_src, r_dst;
4252 HChar dis_buf[50];
4253 IRTemp t1, t2;
4254
4255 /* On entry, delta points at the second byte of the insn (the modrm
4256 byte).*/
4257 UChar first_opcode = getUChar(delta-1);
4258 UChar modrm = getUChar(delta+0);
4259
sewardj37d52572005-02-25 14:22:12 +00004260 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xD8 opcodes +-+-+-+-+-+-+-+ */
4261
4262 if (first_opcode == 0xD8) {
4263 if (modrm < 0xC0) {
4264
4265 /* bits 5,4,3 are an opcode extension, and the modRM also
4266 specifies an address. */
sewardj7bc00082005-03-27 05:08:32 +00004267 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
4268 delta += len;
sewardj37d52572005-02-25 14:22:12 +00004269
sewardj901ed122005-02-27 13:25:31 +00004270 switch (gregLO3ofRM(modrm)) {
sewardj37d52572005-02-25 14:22:12 +00004271
sewardj48a89d82005-05-06 11:50:13 +00004272 case 0: /* FADD single-real */
4273 fp_do_op_mem_ST_0 ( addr, "add", dis_buf, Iop_AddF64, False );
4274 break;
4275
sewardje6939f02005-05-07 01:01:24 +00004276 case 1: /* FMUL single-real */
4277 fp_do_op_mem_ST_0 ( addr, "mul", dis_buf, Iop_MulF64, False );
4278 break;
4279
sewardjd20c8852005-01-20 20:04:07 +00004280//.. case 2: /* FCOM single-real */
4281//.. DIP("fcoms %s\n", dis_buf);
4282//.. /* This forces C1 to zero, which isn't right. */
4283//.. put_C3210(
4284//.. binop( Iop_And32,
4285//.. binop(Iop_Shl32,
4286//.. binop(Iop_CmpF64,
4287//.. get_ST(0),
4288//.. unop(Iop_F32toF64,
4289//.. loadLE(Ity_F32,mkexpr(addr)))),
4290//.. mkU8(8)),
4291//.. mkU32(0x4500)
4292//.. ));
4293//.. break;
4294//..
4295//.. case 3: /* FCOMP single-real */
4296//.. DIP("fcomps %s\n", dis_buf);
4297//.. /* This forces C1 to zero, which isn't right. */
4298//.. put_C3210(
4299//.. binop( Iop_And32,
4300//.. binop(Iop_Shl32,
4301//.. binop(Iop_CmpF64,
4302//.. get_ST(0),
4303//.. unop(Iop_F32toF64,
4304//.. loadLE(Ity_F32,mkexpr(addr)))),
4305//.. mkU8(8)),
4306//.. mkU32(0x4500)
4307//.. ));
4308//.. fp_pop();
4309//.. break;
sewardje6939f02005-05-07 01:01:24 +00004310
4311 case 4: /* FSUB single-real */
4312 fp_do_op_mem_ST_0 ( addr, "sub", dis_buf, Iop_SubF64, False );
4313 break;
sewardj7bc00082005-03-27 05:08:32 +00004314
4315 case 5: /* FSUBR single-real */
4316 fp_do_oprev_mem_ST_0 ( addr, "subr", dis_buf, Iop_SubF64, False );
4317 break;
4318
sewardje6939f02005-05-07 01:01:24 +00004319 case 6: /* FDIV single-real */
4320 fp_do_op_mem_ST_0 ( addr, "div", dis_buf, Iop_DivF64, False );
4321 break;
4322
4323 case 7: /* FDIVR single-real */
4324 fp_do_oprev_mem_ST_0 ( addr, "divr", dis_buf, Iop_DivF64, False );
4325 break;
sewardj37d52572005-02-25 14:22:12 +00004326
4327 default:
sewardj901ed122005-02-27 13:25:31 +00004328 vex_printf("unhandled opc_aux = 0x%2x\n", gregLO3ofRM(modrm));
sewardj37d52572005-02-25 14:22:12 +00004329 vex_printf("first_opcode == 0xD8\n");
4330 goto decode_fail;
4331 }
4332 } else {
4333 delta++;
4334 switch (modrm) {
4335
4336 case 0xC0 ... 0xC7: /* FADD %st(?),%st(0) */
4337 fp_do_op_ST_ST ( "add", Iop_AddF64, modrm - 0xC0, 0, False );
4338 break;
4339
sewardj137015d2005-03-27 04:01:15 +00004340 case 0xC8 ... 0xCF: /* FMUL %st(?),%st(0) */
4341 fp_do_op_ST_ST ( "mul", Iop_MulF64, modrm - 0xC8, 0, False );
4342 break;
4343
sewardjd20c8852005-01-20 20:04:07 +00004344//.. #if 1
4345//.. /* Dunno if this is right */
4346//.. case 0xD0 ... 0xD7: /* FCOM %st(?),%st(0) */
4347//.. r_dst = (UInt)modrm - 0xD0;
4348//.. DIP("fcom %%st(0),%%st(%d)\n", r_dst);
4349//.. /* This forces C1 to zero, which isn't right. */
4350//.. put_C3210(
4351//.. binop( Iop_And32,
4352//.. binop(Iop_Shl32,
4353//.. binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
4354//.. mkU8(8)),
4355//.. mkU32(0x4500)
4356//.. ));
4357//.. break;
4358//.. #endif
4359//.. #if 1
4360//.. /* Dunno if this is right */
4361//.. case 0xD8 ... 0xDF: /* FCOMP %st(?),%st(0) */
4362//.. r_dst = (UInt)modrm - 0xD8;
4363//.. DIP("fcomp %%st(0),%%st(%d)\n", r_dst);
4364//.. /* This forces C1 to zero, which isn't right. */
4365//.. put_C3210(
4366//.. binop( Iop_And32,
4367//.. binop(Iop_Shl32,
4368//.. binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
4369//.. mkU8(8)),
4370//.. mkU32(0x4500)
4371//.. ));
4372//.. fp_pop();
4373//.. break;
4374//.. #endif
sewardj137015d2005-03-27 04:01:15 +00004375 case 0xE0 ... 0xE7: /* FSUB %st(?),%st(0) */
4376 fp_do_op_ST_ST ( "sub", Iop_SubF64, modrm - 0xE0, 0, False );
4377 break;
4378
sewardje6939f02005-05-07 01:01:24 +00004379 case 0xE8 ... 0xEF: /* FSUBR %st(?),%st(0) */
4380 fp_do_oprev_ST_ST ( "subr", Iop_SubF64, modrm - 0xE8, 0, False );
4381 break;
sewardj137015d2005-03-27 04:01:15 +00004382
4383 case 0xF0 ... 0xF7: /* FDIV %st(?),%st(0) */
4384 fp_do_op_ST_ST ( "div", Iop_DivF64, modrm - 0xF0, 0, False );
4385 break;
4386
sewardj48a89d82005-05-06 11:50:13 +00004387 case 0xF8 ... 0xFF: /* FDIVR %st(?),%st(0) */
4388 fp_do_oprev_ST_ST ( "divr", Iop_DivF64, modrm - 0xF8, 0, False );
4389 break;
sewardj37d52572005-02-25 14:22:12 +00004390
4391 default:
4392 goto decode_fail;
4393 }
4394 }
4395 }
sewardj8d965312005-02-25 02:48:47 +00004396
4397 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xD9 opcodes +-+-+-+-+-+-+-+ */
sewardj37d52572005-02-25 14:22:12 +00004398 else
sewardj8d965312005-02-25 02:48:47 +00004399 if (first_opcode == 0xD9) {
4400 if (modrm < 0xC0) {
4401
4402 /* bits 5,4,3 are an opcode extension, and the modRM also
4403 specifies an address. */
4404 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
4405 delta += len;
4406
sewardj901ed122005-02-27 13:25:31 +00004407 switch (gregLO3ofRM(modrm)) {
sewardj8d965312005-02-25 02:48:47 +00004408
sewardjc49ce232005-02-25 13:03:03 +00004409 case 0: /* FLD single-real */
4410 DIP("flds %s\n", dis_buf);
4411 fp_push();
4412 put_ST(0, unop(Iop_F32toF64,
4413 loadLE(Ity_F32, mkexpr(addr))));
4414 break;
4415
4416 case 2: /* FST single-real */
4417 DIP("fsts %s\n", dis_buf);
4418 storeLE(mkexpr(addr),
4419 binop(Iop_F64toF32, get_roundingmode(), get_ST(0)));
4420 break;
4421
4422 case 3: /* FSTP single-real */
4423 DIP("fstps %s\n", dis_buf);
4424 storeLE(mkexpr(addr),
4425 binop(Iop_F64toF32, get_roundingmode(), get_ST(0)));
4426 fp_pop();
4427 break;
4428
sewardj4017a3b2005-06-13 12:17:27 +00004429 case 4: { /* FLDENV m28 */
4430 /* Uses dirty helper:
4431 VexEmWarn amd64g_do_FLDENV ( VexGuestX86State*, HWord ) */
4432 IRTemp ew = newTemp(Ity_I32);
4433 IRTemp w64 = newTemp(Ity_I64);
4434 IRDirty* d = unsafeIRDirty_0_N (
4435 0/*regparms*/,
4436 "amd64g_dirtyhelper_FLDENV",
4437 &amd64g_dirtyhelper_FLDENV,
4438 mkIRExprVec_1( mkexpr(addr) )
4439 );
4440 d->needsBBP = True;
4441 d->tmp = w64;
4442 /* declare we're reading memory */
4443 d->mFx = Ifx_Read;
4444 d->mAddr = mkexpr(addr);
4445 d->mSize = 28;
4446
4447 /* declare we're writing guest state */
4448 d->nFxState = 4;
4449
4450 d->fxState[0].fx = Ifx_Write;
4451 d->fxState[0].offset = OFFB_FTOP;
4452 d->fxState[0].size = sizeof(UInt);
4453
4454 d->fxState[1].fx = Ifx_Write;
4455 d->fxState[1].offset = OFFB_FPTAGS;
4456 d->fxState[1].size = 8 * sizeof(UChar);
4457
4458 d->fxState[2].fx = Ifx_Write;
4459 d->fxState[2].offset = OFFB_FPROUND;
4460 d->fxState[2].size = sizeof(ULong);
4461
4462 d->fxState[3].fx = Ifx_Write;
4463 d->fxState[3].offset = OFFB_FC3210;
4464 d->fxState[3].size = sizeof(ULong);
4465
4466 stmt( IRStmt_Dirty(d) );
4467
4468 /* ew contains any emulation warning we may need to
4469 issue. If needed, side-exit to the next insn,
4470 reporting the warning, so that Valgrind's dispatcher
4471 sees the warning. */
4472 assign(ew, unop(Iop_64to32,mkexpr(w64)) );
4473 put_emwarn( mkexpr(ew) );
4474 stmt(
4475 IRStmt_Exit(
4476 binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
4477 Ijk_EmWarn,
sewardj9e6491a2005-07-02 19:24:10 +00004478 IRConst_U64( guest_RIP_bbstart+delta )
sewardj4017a3b2005-06-13 12:17:27 +00004479 )
4480 );
4481
4482 DIP("fldenv %s\n", dis_buf);
4483 break;
4484 }
sewardj5e205372005-05-09 02:57:08 +00004485
4486 case 5: {/* FLDCW */
4487 /* The only thing we observe in the control word is the
4488 rounding mode. Therefore, pass the 16-bit value
4489 (x87 native-format control word) to a clean helper,
4490 getting back a 64-bit value, the lower half of which
4491 is the FPROUND value to store, and the upper half of
4492 which is the emulation-warning token which may be
4493 generated.
4494 */
4495 /* ULong amd64h_check_fldcw ( ULong ); */
4496 IRTemp t64 = newTemp(Ity_I64);
4497 IRTemp ew = newTemp(Ity_I32);
4498 DIP("fldcw %s\n", dis_buf);
4499 assign( t64, mkIRExprCCall(
4500 Ity_I64, 0/*regparms*/,
4501 "amd64g_check_fldcw",
4502 &amd64g_check_fldcw,
4503 mkIRExprVec_1(
4504 unop( Iop_16Uto64,
4505 loadLE(Ity_I16, mkexpr(addr)))
4506 )
4507 )
4508 );
4509
4510 put_fpround( unop(Iop_64to32, mkexpr(t64)) );
4511 assign( ew, unop(Iop_64HIto32, mkexpr(t64) ) );
4512 put_emwarn( mkexpr(ew) );
4513 /* Finally, if an emulation warning was reported,
4514 side-exit to the next insn, reporting the warning,
4515 so that Valgrind's dispatcher sees the warning. */
4516 stmt(
4517 IRStmt_Exit(
4518 binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
4519 Ijk_EmWarn,
sewardj9e6491a2005-07-02 19:24:10 +00004520 IRConst_U64( guest_RIP_bbstart+delta )
sewardj5e205372005-05-09 02:57:08 +00004521 )
4522 );
4523 break;
4524 }
4525
sewardj4017a3b2005-06-13 12:17:27 +00004526 case 6: { /* FNSTENV m28 */
4527 /* Uses dirty helper:
4528 void amd64g_do_FSTENV ( VexGuestAMD64State*, HWord ) */
4529 IRDirty* d = unsafeIRDirty_0_N (
4530 0/*regparms*/,
4531 "amd64g_dirtyhelper_FSTENV",
4532 &amd64g_dirtyhelper_FSTENV,
4533 mkIRExprVec_1( mkexpr(addr) )
4534 );
4535 d->needsBBP = True;
4536 /* declare we're writing memory */
4537 d->mFx = Ifx_Write;
4538 d->mAddr = mkexpr(addr);
4539 d->mSize = 28;
4540
4541 /* declare we're reading guest state */
4542 d->nFxState = 4;
4543
4544 d->fxState[0].fx = Ifx_Read;
4545 d->fxState[0].offset = OFFB_FTOP;
4546 d->fxState[0].size = sizeof(UInt);
4547
4548 d->fxState[1].fx = Ifx_Read;
4549 d->fxState[1].offset = OFFB_FPTAGS;
4550 d->fxState[1].size = 8 * sizeof(UChar);
4551
4552 d->fxState[2].fx = Ifx_Read;
4553 d->fxState[2].offset = OFFB_FPROUND;
4554 d->fxState[2].size = sizeof(ULong);
4555
4556 d->fxState[3].fx = Ifx_Read;
4557 d->fxState[3].offset = OFFB_FC3210;
4558 d->fxState[3].size = sizeof(ULong);
4559
4560 stmt( IRStmt_Dirty(d) );
4561
4562 DIP("fnstenv %s\n", dis_buf);
4563 break;
4564 }
sewardj5e205372005-05-09 02:57:08 +00004565
4566 case 7: /* FNSTCW */
4567 /* Fake up a native x87 FPU control word. The only
4568 thing it depends on is FPROUND[1:0], so call a clean
4569 helper to cook it up. */
sewardj4017a3b2005-06-13 12:17:27 +00004570 /* ULong amd64g_create_fpucw ( ULong fpround ) */
sewardj5e205372005-05-09 02:57:08 +00004571 DIP("fnstcw %s\n", dis_buf);
4572 storeLE(
4573 mkexpr(addr),
4574 unop( Iop_64to16,
4575 mkIRExprCCall(
4576 Ity_I64, 0/*regp*/,
4577 "amd64g_create_fpucw", &amd64g_create_fpucw,
4578 mkIRExprVec_1( unop(Iop_32Uto64, get_fpround()) )
4579 )
4580 )
4581 );
4582 break;
sewardj8d965312005-02-25 02:48:47 +00004583
4584 default:
sewardj901ed122005-02-27 13:25:31 +00004585 vex_printf("unhandled opc_aux = 0x%2x\n", gregLO3ofRM(modrm));
sewardj8d965312005-02-25 02:48:47 +00004586 vex_printf("first_opcode == 0xD9\n");
4587 goto decode_fail;
4588 }
4589
4590 } else {
4591 delta++;
4592 switch (modrm) {
4593
sewardjc49ce232005-02-25 13:03:03 +00004594 case 0xC0 ... 0xC7: /* FLD %st(?) */
4595 r_src = (UInt)modrm - 0xC0;
sewardj1027dc22005-02-26 01:55:02 +00004596 DIP("fld %%st(%u)\n", r_src);
sewardjc49ce232005-02-25 13:03:03 +00004597 t1 = newTemp(Ity_F64);
4598 assign(t1, get_ST(r_src));
4599 fp_push();
4600 put_ST(0, mkexpr(t1));
4601 break;
sewardj8d965312005-02-25 02:48:47 +00004602
4603 case 0xC8 ... 0xCF: /* FXCH %st(?) */
4604 r_src = (UInt)modrm - 0xC8;
sewardj1027dc22005-02-26 01:55:02 +00004605 DIP("fxch %%st(%u)\n", r_src);
sewardj8d965312005-02-25 02:48:47 +00004606 t1 = newTemp(Ity_F64);
4607 t2 = newTemp(Ity_F64);
4608 assign(t1, get_ST(0));
4609 assign(t2, get_ST(r_src));
4610 put_ST_UNCHECKED(0, mkexpr(t2));
4611 put_ST_UNCHECKED(r_src, mkexpr(t1));
4612 break;
4613
4614 case 0xE0: /* FCHS */
4615 DIP("fchs\n");
4616 put_ST_UNCHECKED(0, unop(Iop_NegF64, get_ST(0)));
4617 break;
4618
sewardj137015d2005-03-27 04:01:15 +00004619 case 0xE1: /* FABS */
4620 DIP("fabs\n");
4621 put_ST_UNCHECKED(0, unop(Iop_AbsF64, get_ST(0)));
4622 break;
4623
sewardj4f9847d2005-07-25 11:58:34 +00004624 case 0xE5: { /* FXAM */
4625 /* This is an interesting one. It examines %st(0),
4626 regardless of whether the tag says it's empty or not.
4627 Here, just pass both the tag (in our format) and the
4628 value (as a double, actually a ULong) to a helper
4629 function. */
4630 IRExpr** args
4631 = mkIRExprVec_2( unop(Iop_8Uto64, get_ST_TAG(0)),
4632 unop(Iop_ReinterpF64asI64,
4633 get_ST_UNCHECKED(0)) );
4634 put_C3210(mkIRExprCCall(
4635 Ity_I64,
4636 0/*regparm*/,
4637 "amd64g_calculate_FXAM", &amd64g_calculate_FXAM,
4638 args
4639 ));
4640 DIP("fxam\n");
4641 break;
4642 }
sewardjc49ce232005-02-25 13:03:03 +00004643
4644 case 0xE8: /* FLD1 */
4645 DIP("fld1\n");
4646 fp_push();
4647 /* put_ST(0, IRExpr_Const(IRConst_F64(1.0))); */
4648 put_ST(0, IRExpr_Const(IRConst_F64i(0x3ff0000000000000ULL)));
4649 break;
4650
sewardj6847d8c2005-05-12 19:21:55 +00004651 case 0xE9: /* FLDL2T */
4652 DIP("fldl2t\n");
4653 fp_push();
4654 /* put_ST(0, IRExpr_Const(IRConst_F64(3.32192809488736234781))); */
4655 put_ST(0, IRExpr_Const(IRConst_F64i(0x400a934f0979a371ULL)));
4656 break;
4657
4658 case 0xEA: /* FLDL2E */
4659 DIP("fldl2e\n");
4660 fp_push();
4661 /* put_ST(0, IRExpr_Const(IRConst_F64(1.44269504088896340739))); */
4662 put_ST(0, IRExpr_Const(IRConst_F64i(0x3ff71547652b82feULL)));
4663 break;
4664
4665 case 0xEB: /* FLDPI */
4666 DIP("fldpi\n");
4667 fp_push();
4668 /* put_ST(0, IRExpr_Const(IRConst_F64(3.14159265358979323851))); */
4669 put_ST(0, IRExpr_Const(IRConst_F64i(0x400921fb54442d18ULL)));
4670 break;
4671
4672 case 0xEC: /* FLDLG2 */
4673 DIP("fldlg2\n");
4674 fp_push();
4675 /* put_ST(0, IRExpr_Const(IRConst_F64(0.301029995663981143))); */
4676 put_ST(0, IRExpr_Const(IRConst_F64i(0x3fd34413509f79ffULL)));
4677 break;
4678
4679 case 0xED: /* FLDLN2 */
4680 DIP("fldln2\n");
4681 fp_push();
4682 /* put_ST(0, IRExpr_Const(IRConst_F64(0.69314718055994530942))); */
4683 put_ST(0, IRExpr_Const(IRConst_F64i(0x3fe62e42fefa39efULL)));
4684 break;
sewardjc49ce232005-02-25 13:03:03 +00004685
4686 case 0xEE: /* FLDZ */
4687 DIP("fldz\n");
4688 fp_push();
4689 /* put_ST(0, IRExpr_Const(IRConst_F64(0.0))); */
4690 put_ST(0, IRExpr_Const(IRConst_F64i(0x0000000000000000ULL)));
4691 break;
4692
sewardj25a85812005-05-08 23:03:48 +00004693 case 0xF0: /* F2XM1 */
4694 DIP("f2xm1\n");
4695 put_ST_UNCHECKED(0, unop(Iop_2xm1F64, get_ST(0)));
4696 break;
4697
4698 case 0xF1: /* FYL2X */
4699 DIP("fyl2x\n");
4700 put_ST_UNCHECKED(1, binop(Iop_Yl2xF64,
4701 get_ST(1), get_ST(0)));
4702 fp_pop();
4703 break;
4704
sewardj5e205372005-05-09 02:57:08 +00004705 case 0xF2: /* FPTAN */
4706 DIP("ftan\n");
4707 put_ST_UNCHECKED(0, unop(Iop_TanF64, get_ST(0)));
4708 fp_push();
4709 put_ST(0, IRExpr_Const(IRConst_F64(1.0)));
4710 clear_C2(); /* HACK */
4711 break;
sewardj25a85812005-05-08 23:03:48 +00004712
4713 case 0xF3: /* FPATAN */
4714 DIP("fpatan\n");
4715 put_ST_UNCHECKED(1, binop(Iop_AtanF64,
4716 get_ST(1), get_ST(0)));
4717 fp_pop();
4718 break;
4719
sewardjd20c8852005-01-20 20:04:07 +00004720//.. case 0xF5: { /* FPREM1 -- IEEE compliant */
4721//.. IRTemp a1 = newTemp(Ity_F64);
4722//.. IRTemp a2 = newTemp(Ity_F64);
4723//.. DIP("fprem1\n");
4724//.. /* Do FPREM1 twice, once to get the remainder, and once
4725//.. to get the C3210 flag values. */
4726//.. assign( a1, get_ST(0) );
4727//.. assign( a2, get_ST(1) );
4728//.. put_ST_UNCHECKED(0, binop(Iop_PRem1F64,
4729//.. mkexpr(a1), mkexpr(a2)));
4730//.. put_C3210( binop(Iop_PRem1C3210F64, mkexpr(a1), mkexpr(a2)) );
4731//.. break;
4732//.. }
sewardj6847d8c2005-05-12 19:21:55 +00004733
4734 case 0xF7: /* FINCSTP */
4735 DIP("fincstp\n");
4736 put_ftop( binop(Iop_Add32, get_ftop(), mkU32(1)) );
4737 break;
4738
sewardjd20c8852005-01-20 20:04:07 +00004739//.. case 0xF8: { /* FPREM -- not IEEE compliant */
4740//.. IRTemp a1 = newTemp(Ity_F64);
4741//.. IRTemp a2 = newTemp(Ity_F64);
4742//.. DIP("fprem\n");
4743//.. /* Do FPREM twice, once to get the remainder, and once
4744//.. to get the C3210 flag values. */
4745//.. assign( a1, get_ST(0) );
4746//.. assign( a2, get_ST(1) );
4747//.. put_ST_UNCHECKED(0, binop(Iop_PRemF64,
4748//.. mkexpr(a1), mkexpr(a2)));
4749//.. put_C3210( binop(Iop_PRemC3210F64, mkexpr(a1), mkexpr(a2)) );
4750//.. break;
4751//.. }
4752//..
sewardj5e205372005-05-09 02:57:08 +00004753 case 0xF9: /* FYL2XP1 */
4754 DIP("fyl2xp1\n");
4755 put_ST_UNCHECKED(1, binop(Iop_Yl2xp1F64,
4756 get_ST(1), get_ST(0)));
4757 fp_pop();
4758 break;
sewardje6939f02005-05-07 01:01:24 +00004759
4760 case 0xFA: /* FSQRT */
4761 DIP("fsqrt\n");
4762 put_ST_UNCHECKED(0, unop(Iop_SqrtF64, get_ST(0)));
4763 break;
4764
sewardj25a85812005-05-08 23:03:48 +00004765 case 0xFB: { /* FSINCOS */
4766 IRTemp a1 = newTemp(Ity_F64);
4767 assign( a1, get_ST(0) );
4768 DIP("fsincos\n");
4769 put_ST_UNCHECKED(0, unop(Iop_SinF64, mkexpr(a1)));
4770 fp_push();
4771 put_ST(0, unop(Iop_CosF64, mkexpr(a1)));
4772 clear_C2(); /* HACK */
4773 break;
4774 }
4775
4776 case 0xFC: /* FRNDINT */
4777 DIP("frndint\n");
4778 put_ST_UNCHECKED(0,
4779 binop(Iop_RoundF64, get_roundingmode(), get_ST(0)) );
4780 break;
4781
4782 case 0xFD: /* FSCALE */
4783 DIP("fscale\n");
4784 put_ST_UNCHECKED(0, binop(Iop_ScaleF64,
4785 get_ST(0), get_ST(1)));
4786 break;
4787
4788 case 0xFE: /* FSIN */
4789 DIP("fsin\n");
4790 put_ST_UNCHECKED(0, unop(Iop_SinF64, get_ST(0)));
4791 clear_C2(); /* HACK */
4792 break;
4793
4794 case 0xFF: /* FCOS */
4795 DIP("fcos\n");
4796 put_ST_UNCHECKED(0, unop(Iop_CosF64, get_ST(0)));
4797 clear_C2(); /* HACK */
4798 break;
sewardj8d965312005-02-25 02:48:47 +00004799
4800 default:
4801 goto decode_fail;
4802 }
4803 }
4804 }
4805
4806 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDA opcodes +-+-+-+-+-+-+-+ */
4807 else
4808 if (first_opcode == 0xDA) {
4809
4810 if (modrm < 0xC0) {
4811
4812 /* bits 5,4,3 are an opcode extension, and the modRM also
4813 specifies an address. */
sewardj6847d8c2005-05-12 19:21:55 +00004814 IROp fop;
4815 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
sewardj8d965312005-02-25 02:48:47 +00004816 delta += len;
sewardj901ed122005-02-27 13:25:31 +00004817 switch (gregLO3ofRM(modrm)) {
sewardj8d965312005-02-25 02:48:47 +00004818
sewardj6847d8c2005-05-12 19:21:55 +00004819 case 0: /* FIADD m32int */ /* ST(0) += m32int */
4820 DIP("fiaddl %s\n", dis_buf);
4821 fop = Iop_AddF64;
4822 goto do_fop_m32;
4823
4824 case 1: /* FIMUL m32int */ /* ST(0) *= m32int */
4825 DIP("fimull %s\n", dis_buf);
4826 fop = Iop_MulF64;
4827 goto do_fop_m32;
4828
4829 case 4: /* FISUB m32int */ /* ST(0) -= m32int */
4830 DIP("fisubl %s\n", dis_buf);
4831 fop = Iop_SubF64;
4832 goto do_fop_m32;
4833
4834 case 5: /* FISUBR m32int */ /* ST(0) = m32int - ST(0) */
4835 DIP("fisubrl %s\n", dis_buf);
4836 fop = Iop_SubF64;
4837 goto do_foprev_m32;
4838
4839 case 6: /* FIDIV m32int */ /* ST(0) /= m32int */
4840 DIP("fisubl %s\n", dis_buf);
4841 fop = Iop_DivF64;
4842 goto do_fop_m32;
4843
4844 case 7: /* FIDIVR m32int */ /* ST(0) = m32int / ST(0) */
4845 DIP("fidivrl %s\n", dis_buf);
4846 fop = Iop_DivF64;
4847 goto do_foprev_m32;
4848
4849 do_fop_m32:
4850 put_ST_UNCHECKED(0,
4851 binop(fop,
4852 get_ST(0),
4853 unop(Iop_I32toF64,
4854 loadLE(Ity_I32, mkexpr(addr)))));
4855 break;
4856
4857 do_foprev_m32:
4858 put_ST_UNCHECKED(0,
4859 binop(fop,
4860 unop(Iop_I32toF64,
4861 loadLE(Ity_I32, mkexpr(addr))),
4862 get_ST(0)));
4863 break;
sewardj8d965312005-02-25 02:48:47 +00004864
4865 default:
sewardj901ed122005-02-27 13:25:31 +00004866 vex_printf("unhandled opc_aux = 0x%2x\n", gregLO3ofRM(modrm));
sewardj8d965312005-02-25 02:48:47 +00004867 vex_printf("first_opcode == 0xDA\n");
4868 goto decode_fail;
4869 }
4870
4871 } else {
4872
4873 delta++;
4874 switch (modrm) {
4875
sewardj48a89d82005-05-06 11:50:13 +00004876 case 0xC0 ... 0xC7: /* FCMOVB ST(i), ST(0) */
4877 r_src = (UInt)modrm - 0xC0;
sewardjca673ab2005-05-11 10:03:08 +00004878 DIP("fcmovb %%st(%u), %%st(0)\n", r_src);
sewardj48a89d82005-05-06 11:50:13 +00004879 put_ST_UNCHECKED(0,
4880 IRExpr_Mux0X(
4881 unop(Iop_1Uto8,
4882 mk_amd64g_calculate_condition(AMD64CondB)),
4883 get_ST(0), get_ST(r_src)) );
4884 break;
sewardj8d965312005-02-25 02:48:47 +00004885
4886 case 0xC8 ... 0xCF: /* FCMOVE(Z) ST(i), ST(0) */
4887 r_src = (UInt)modrm - 0xC8;
sewardj1027dc22005-02-26 01:55:02 +00004888 DIP("fcmovz %%st(%u), %%st(0)\n", r_src);
sewardj8d965312005-02-25 02:48:47 +00004889 put_ST_UNCHECKED(0,
4890 IRExpr_Mux0X(
4891 unop(Iop_1Uto8,
4892 mk_amd64g_calculate_condition(AMD64CondZ)),
4893 get_ST(0), get_ST(r_src)) );
4894 break;
4895
sewardj37d52572005-02-25 14:22:12 +00004896 case 0xD0 ... 0xD7: /* FCMOVBE ST(i), ST(0) */
4897 r_src = (UInt)modrm - 0xD0;
sewardj1027dc22005-02-26 01:55:02 +00004898 DIP("fcmovbe %%st(%u), %%st(0)\n", r_src);
sewardj37d52572005-02-25 14:22:12 +00004899 put_ST_UNCHECKED(0,
4900 IRExpr_Mux0X(
4901 unop(Iop_1Uto8,
4902 mk_amd64g_calculate_condition(AMD64CondBE)),
4903 get_ST(0), get_ST(r_src)) );
4904 break;
4905
sewardj25a85812005-05-08 23:03:48 +00004906 case 0xD8 ... 0xDF: /* FCMOVU ST(i), ST(0) */
4907 r_src = (UInt)modrm - 0xD8;
4908 DIP("fcmovu %%st(%u), %%st(0)\n", r_src);
4909 put_ST_UNCHECKED(0,
4910 IRExpr_Mux0X(
4911 unop(Iop_1Uto8,
4912 mk_amd64g_calculate_condition(AMD64CondP)),
4913 get_ST(0), get_ST(r_src)) );
4914 break;
4915
sewardjd20c8852005-01-20 20:04:07 +00004916//.. case 0xE9: /* FUCOMPP %st(0),%st(1) */
4917//.. DIP("fucompp %%st(0),%%st(1)\n");
4918//.. /* This forces C1 to zero, which isn't right. */
4919//.. put_C3210(
4920//.. binop( Iop_And32,
4921//.. binop(Iop_Shl32,
4922//.. binop(Iop_CmpF64, get_ST(0), get_ST(1)),
4923//.. mkU8(8)),
4924//.. mkU32(0x4500)
4925//.. ));
4926//.. fp_pop();
4927//.. fp_pop();
4928//.. break;
sewardj8d965312005-02-25 02:48:47 +00004929
4930 default:
4931 goto decode_fail;
4932 }
4933
4934 }
4935 }
4936
sewardjc49ce232005-02-25 13:03:03 +00004937 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDB opcodes +-+-+-+-+-+-+-+ */
4938 else
4939 if (first_opcode == 0xDB) {
4940 if (modrm < 0xC0) {
4941
4942 /* bits 5,4,3 are an opcode extension, and the modRM also
4943 specifies an address. */
4944 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
4945 delta += len;
4946
sewardj901ed122005-02-27 13:25:31 +00004947 switch (gregLO3ofRM(modrm)) {
sewardjc49ce232005-02-25 13:03:03 +00004948
sewardj5cc00ff2005-03-27 04:48:32 +00004949 case 0: /* FILD m32int */
4950 DIP("fildl %s\n", dis_buf);
4951 fp_push();
4952 put_ST(0, unop(Iop_I32toF64,
4953 loadLE(Ity_I32, mkexpr(addr))));
4954 break;
4955
sewardj6847d8c2005-05-12 19:21:55 +00004956 case 2: /* FIST m32 */
4957 DIP("fistl %s\n", dis_buf);
4958 storeLE( mkexpr(addr),
4959 binop(Iop_F64toI32, get_roundingmode(), get_ST(0)) );
4960 break;
sewardj37d52572005-02-25 14:22:12 +00004961
4962 case 3: /* FISTP m32 */
4963 DIP("fistpl %s\n", dis_buf);
4964 storeLE( mkexpr(addr),
4965 binop(Iop_F64toI32, get_roundingmode(), get_ST(0)) );
4966 fp_pop();
4967 break;
4968
sewardj924215b2005-03-26 21:50:31 +00004969 case 5: { /* FLD extended-real */
4970 /* Uses dirty helper:
4971 ULong amd64g_loadF80le ( ULong )
4972 addr holds the address. First, do a dirty call to
4973 get hold of the data. */
4974 IRTemp val = newTemp(Ity_I64);
4975 IRExpr** args = mkIRExprVec_1 ( mkexpr(addr) );
4976
4977 IRDirty* d = unsafeIRDirty_1_N (
4978 val,
4979 0/*regparms*/,
sewardj8707fef2005-08-23 23:26:37 +00004980 "amd64g_dirtyhelper_loadF80le",
4981 &amd64g_dirtyhelper_loadF80le,
sewardj924215b2005-03-26 21:50:31 +00004982 args
4983 );
4984 /* declare that we're reading memory */
4985 d->mFx = Ifx_Read;
4986 d->mAddr = mkexpr(addr);
4987 d->mSize = 10;
4988
4989 /* execute the dirty call, dumping the result in val. */
4990 stmt( IRStmt_Dirty(d) );
4991 fp_push();
4992 put_ST(0, unop(Iop_ReinterpI64asF64, mkexpr(val)));
4993
4994 DIP("fldt %s\n", dis_buf);
4995 break;
4996 }
4997
4998 case 7: { /* FSTP extended-real */
4999 /* Uses dirty helper:
5000 void amd64g_storeF80le ( ULong addr, ULong data )
5001 */
5002 IRExpr** args
5003 = mkIRExprVec_2( mkexpr(addr),
5004 unop(Iop_ReinterpF64asI64, get_ST(0)) );
5005
5006 IRDirty* d = unsafeIRDirty_0_N (
5007 0/*regparms*/,
sewardj8707fef2005-08-23 23:26:37 +00005008 "amd64g_dirtyhelper_storeF80le",
5009 &amd64g_dirtyhelper_storeF80le,
sewardj924215b2005-03-26 21:50:31 +00005010 args
5011 );
5012 /* declare we're writing memory */
5013 d->mFx = Ifx_Write;
5014 d->mAddr = mkexpr(addr);
5015 d->mSize = 10;
5016
5017 /* execute the dirty call. */
5018 stmt( IRStmt_Dirty(d) );
5019 fp_pop();
5020
5021 DIP("fstpt\n %s", dis_buf);
5022 break;
5023 }
sewardjc49ce232005-02-25 13:03:03 +00005024
5025 default:
sewardj901ed122005-02-27 13:25:31 +00005026 vex_printf("unhandled opc_aux = 0x%2x\n", gregLO3ofRM(modrm));
sewardjc49ce232005-02-25 13:03:03 +00005027 vex_printf("first_opcode == 0xDB\n");
5028 goto decode_fail;
5029 }
5030
5031 } else {
5032
5033 delta++;
5034 switch (modrm) {
5035
sewardj48a89d82005-05-06 11:50:13 +00005036 case 0xC0 ... 0xC7: /* FCMOVNB ST(i), ST(0) */
5037 r_src = (UInt)modrm - 0xC0;
sewardjca673ab2005-05-11 10:03:08 +00005038 DIP("fcmovnb %%st(%u), %%st(0)\n", r_src);
sewardj48a89d82005-05-06 11:50:13 +00005039 put_ST_UNCHECKED(0,
5040 IRExpr_Mux0X(
5041 unop(Iop_1Uto8,
5042 mk_amd64g_calculate_condition(AMD64CondNB)),
5043 get_ST(0), get_ST(r_src)) );
5044 break;
sewardj924215b2005-03-26 21:50:31 +00005045
5046 case 0xC8 ... 0xCF: /* FCMOVNE(NZ) ST(i), ST(0) */
5047 r_src = (UInt)modrm - 0xC8;
sewardj40e144d2005-03-28 00:46:27 +00005048 DIP("fcmovnz %%st(%u), %%st(0)\n", r_src);
sewardj137015d2005-03-27 04:01:15 +00005049 put_ST_UNCHECKED(
5050 0,
5051 IRExpr_Mux0X(
5052 unop(Iop_1Uto8,
5053 mk_amd64g_calculate_condition(AMD64CondNZ)),
5054 get_ST(0),
5055 get_ST(r_src)
5056 )
5057 );
sewardj924215b2005-03-26 21:50:31 +00005058 break;
5059
sewardj137015d2005-03-27 04:01:15 +00005060 case 0xD0 ... 0xD7: /* FCMOVNBE ST(i), ST(0) */
5061 r_src = (UInt)modrm - 0xD0;
sewardj40e144d2005-03-28 00:46:27 +00005062 DIP("fcmovnbe %%st(%u), %%st(0)\n", r_src);
sewardj137015d2005-03-27 04:01:15 +00005063 put_ST_UNCHECKED(
5064 0,
5065 IRExpr_Mux0X(
5066 unop(Iop_1Uto8,
5067 mk_amd64g_calculate_condition(AMD64CondNBE)),
5068 get_ST(0),
5069 get_ST(r_src)
5070 )
5071 );
5072 break;
5073
sewardj4e1a1e92005-05-25 00:44:13 +00005074 case 0xE2:
5075 DIP("fnclex\n");
5076 break;
5077
sewardjd20c8852005-01-20 20:04:07 +00005078//.. case 0xE3: {
5079//.. /* Uses dirty helper:
5080//.. void x86g_do_FINIT ( VexGuestX86State* ) */
5081//.. IRDirty* d = unsafeIRDirty_0_N (
5082//.. 0/*regparms*/,
5083//.. "x86g_dirtyhelper_FINIT",
5084//.. &x86g_dirtyhelper_FINIT,
5085//.. mkIRExprVec_0()
5086//.. );
5087//.. d->needsBBP = True;
5088//..
5089//.. /* declare we're writing guest state */
5090//.. d->nFxState = 5;
5091//..
5092//.. d->fxState[0].fx = Ifx_Write;
5093//.. d->fxState[0].offset = OFFB_FTOP;
5094//.. d->fxState[0].size = sizeof(UInt);
5095//..
5096//.. d->fxState[1].fx = Ifx_Write;
5097//.. d->fxState[1].offset = OFFB_FPREGS;
5098//.. d->fxState[1].size = 8 * sizeof(ULong);
5099//..
5100//.. d->fxState[2].fx = Ifx_Write;
5101//.. d->fxState[2].offset = OFFB_FPTAGS;
5102//.. d->fxState[2].size = 8 * sizeof(UChar);
5103//..
5104//.. d->fxState[3].fx = Ifx_Write;
5105//.. d->fxState[3].offset = OFFB_FPROUND;
5106//.. d->fxState[3].size = sizeof(UInt);
5107//..
5108//.. d->fxState[4].fx = Ifx_Write;
5109//.. d->fxState[4].offset = OFFB_FC3210;
5110//.. d->fxState[4].size = sizeof(UInt);
5111//..
5112//.. stmt( IRStmt_Dirty(d) );
5113//..
5114//.. DIP("fninit\n");
5115//.. break;
5116//.. }
sewardjc49ce232005-02-25 13:03:03 +00005117
5118 case 0xE8 ... 0xEF: /* FUCOMI %st(0),%st(?) */
5119 fp_do_ucomi_ST0_STi( (UInt)modrm - 0xE8, False );
5120 break;
5121
sewardj48a89d82005-05-06 11:50:13 +00005122 case 0xF0 ... 0xF7: /* FCOMI %st(0),%st(?) */
5123 fp_do_ucomi_ST0_STi( (UInt)modrm - 0xF0, False );
5124 break;
sewardjc49ce232005-02-25 13:03:03 +00005125
5126 default:
5127 goto decode_fail;
5128 }
5129 }
5130 }
5131
sewardj137015d2005-03-27 04:01:15 +00005132 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDC opcodes +-+-+-+-+-+-+-+ */
5133 else
5134 if (first_opcode == 0xDC) {
5135 if (modrm < 0xC0) {
5136
sewardj434e0692005-03-27 17:36:08 +00005137 /* bits 5,4,3 are an opcode extension, and the modRM also
5138 specifies an address. */
5139 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
5140 delta += len;
5141
5142 switch (gregLO3ofRM(modrm)) {
5143
sewardje6939f02005-05-07 01:01:24 +00005144 case 0: /* FADD double-real */
5145 fp_do_op_mem_ST_0 ( addr, "add", dis_buf, Iop_AddF64, True );
5146 break;
5147
5148 case 1: /* FMUL double-real */
5149 fp_do_op_mem_ST_0 ( addr, "mul", dis_buf, Iop_MulF64, True );
5150 break;
5151
sewardjd20c8852005-01-20 20:04:07 +00005152//.. case 2: /* FCOM double-real */
5153//.. DIP("fcoml %s\n", dis_buf);
5154//.. /* This forces C1 to zero, which isn't right. */
5155//.. put_C3210(
5156//.. binop( Iop_And32,
5157//.. binop(Iop_Shl32,
5158//.. binop(Iop_CmpF64,
5159//.. get_ST(0),
5160//.. loadLE(Ity_F64,mkexpr(addr))),
5161//.. mkU8(8)),
5162//.. mkU32(0x4500)
5163//.. ));
5164//.. break;
sewardj566d2c72005-08-10 11:43:42 +00005165
5166 case 3: /* FCOMP double-real */
5167 DIP("fcompl %s\n", dis_buf);
5168 /* This forces C1 to zero, which isn't right. */
5169 put_C3210(
5170 unop(Iop_32Uto64,
5171 binop( Iop_And32,
5172 binop(Iop_Shl32,
5173 binop(Iop_CmpF64,
5174 get_ST(0),
5175 loadLE(Ity_F64,mkexpr(addr))),
5176 mkU8(8)),
5177 mkU32(0x4500)
5178 )));
5179 fp_pop();
5180 break;
sewardje6939f02005-05-07 01:01:24 +00005181
5182 case 4: /* FSUB double-real */
5183 fp_do_op_mem_ST_0 ( addr, "sub", dis_buf, Iop_SubF64, True );
5184 break;
sewardj434e0692005-03-27 17:36:08 +00005185
5186 case 5: /* FSUBR double-real */
5187 fp_do_oprev_mem_ST_0 ( addr, "subr", dis_buf, Iop_SubF64, True );
5188 break;
5189
sewardje6939f02005-05-07 01:01:24 +00005190 case 6: /* FDIV double-real */
5191 fp_do_op_mem_ST_0 ( addr, "div", dis_buf, Iop_DivF64, True );
5192 break;
5193
5194 case 7: /* FDIVR double-real */
5195 fp_do_oprev_mem_ST_0 ( addr, "divr", dis_buf, Iop_DivF64, True );
5196 break;
sewardj434e0692005-03-27 17:36:08 +00005197
5198 default:
5199 vex_printf("unhandled opc_aux = 0x%2x\n", gregLO3ofRM(modrm));
5200 vex_printf("first_opcode == 0xDC\n");
5201 goto decode_fail;
5202 }
sewardj137015d2005-03-27 04:01:15 +00005203
5204 } else {
5205
5206 delta++;
5207 switch (modrm) {
5208
5209 case 0xC0 ... 0xC7: /* FADD %st(0),%st(?) */
5210 fp_do_op_ST_ST ( "add", Iop_AddF64, 0, modrm - 0xC0, False );
5211 break;
5212
sewardj7bc00082005-03-27 05:08:32 +00005213 case 0xC8 ... 0xCF: /* FMUL %st(0),%st(?) */
5214 fp_do_op_ST_ST ( "mul", Iop_MulF64, 0, modrm - 0xC8, False );
5215 break;
5216
sewardj434e0692005-03-27 17:36:08 +00005217 case 0xE0 ... 0xE7: /* FSUBR %st(0),%st(?) */
5218 fp_do_oprev_ST_ST ( "subr", Iop_SubF64, 0, modrm - 0xE0, False );
5219 break;
5220
sewardje6939f02005-05-07 01:01:24 +00005221 case 0xE8 ... 0xEF: /* FSUB %st(0),%st(?) */
5222 fp_do_op_ST_ST ( "sub", Iop_SubF64, 0, modrm - 0xE8, False );
5223 break;
5224
5225 case 0xF0 ... 0xF7: /* FDIVR %st(0),%st(?) */
5226 fp_do_oprev_ST_ST ( "divr", Iop_DivF64, 0, modrm - 0xF0, False );
5227 break;
sewardj137015d2005-03-27 04:01:15 +00005228
5229 case 0xF8 ... 0xFF: /* FDIV %st(0),%st(?) */
5230 fp_do_op_ST_ST ( "div", Iop_DivF64, 0, modrm - 0xF8, False );
5231 break;
5232
5233 default:
5234 goto decode_fail;
5235 }
5236
5237 }
5238 }
sewardj8d965312005-02-25 02:48:47 +00005239
5240 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDD opcodes +-+-+-+-+-+-+-+ */
5241 else
5242 if (first_opcode == 0xDD) {
5243
5244 if (modrm < 0xC0) {
5245
5246 /* bits 5,4,3 are an opcode extension, and the modRM also
5247 specifies an address. */
5248 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
5249 delta += len;
5250
sewardj901ed122005-02-27 13:25:31 +00005251 switch (gregLO3ofRM(modrm)) {
sewardj8d965312005-02-25 02:48:47 +00005252
5253 case 0: /* FLD double-real */
5254 DIP("fldl %s\n", dis_buf);
5255 fp_push();
sewardjaf1ceca2005-06-30 23:31:27 +00005256 put_ST(0, loadLE(Ity_F64, mkexpr(addr)));
sewardj8d965312005-02-25 02:48:47 +00005257 break;
5258
sewardjc49ce232005-02-25 13:03:03 +00005259 case 2: /* FST double-real */
5260 DIP("fstl %s\n", dis_buf);
5261 storeLE(mkexpr(addr), get_ST(0));
5262 break;
sewardj8d965312005-02-25 02:48:47 +00005263
5264 case 3: /* FSTP double-real */
5265 DIP("fstpl %s\n", dis_buf);
5266 storeLE(mkexpr(addr), get_ST(0));
5267 fp_pop();
5268 break;
5269
sewardjd20c8852005-01-20 20:04:07 +00005270//.. case 4: { /* FRSTOR m108 */
5271//.. /* Uses dirty helper:
5272//.. VexEmWarn x86g_do_FRSTOR ( VexGuestX86State*, Addr32 ) */
5273//.. IRTemp ew = newTemp(Ity_I32);
5274//.. IRDirty* d = unsafeIRDirty_0_N (
5275//.. 0/*regparms*/,
5276//.. "x86g_dirtyhelper_FRSTOR",
5277//.. &x86g_dirtyhelper_FRSTOR,
5278//.. mkIRExprVec_1( mkexpr(addr) )
5279//.. );
5280//.. d->needsBBP = True;
5281//.. d->tmp = ew;
5282//.. /* declare we're reading memory */
5283//.. d->mFx = Ifx_Read;
5284//.. d->mAddr = mkexpr(addr);
5285//.. d->mSize = 108;
5286//..
5287//.. /* declare we're writing guest state */
5288//.. d->nFxState = 5;
5289//..
5290//.. d->fxState[0].fx = Ifx_Write;
5291//.. d->fxState[0].offset = OFFB_FTOP;
5292//.. d->fxState[0].size = sizeof(UInt);
5293//..
5294//.. d->fxState[1].fx = Ifx_Write;
5295//.. d->fxState[1].offset = OFFB_FPREGS;
5296//.. d->fxState[1].size = 8 * sizeof(ULong);
5297//..
5298//.. d->fxState[2].fx = Ifx_Write;
5299//.. d->fxState[2].offset = OFFB_FPTAGS;
5300//.. d->fxState[2].size = 8 * sizeof(UChar);
5301//..
5302//.. d->fxState[3].fx = Ifx_Write;
5303//.. d->fxState[3].offset = OFFB_FPROUND;
5304//.. d->fxState[3].size = sizeof(UInt);
5305//..
5306//.. d->fxState[4].fx = Ifx_Write;
5307//.. d->fxState[4].offset = OFFB_FC3210;
5308//.. d->fxState[4].size = sizeof(UInt);
5309//..
5310//.. stmt( IRStmt_Dirty(d) );
5311//..
5312//.. /* ew contains any emulation warning we may need to
5313//.. issue. If needed, side-exit to the next insn,
5314//.. reporting the warning, so that Valgrind's dispatcher
5315//.. sees the warning. */
5316//.. put_emwarn( mkexpr(ew) );
5317//.. stmt(
5318//.. IRStmt_Exit(
5319//.. binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
5320//.. Ijk_EmWarn,
5321//.. IRConst_U32( ((Addr32)guest_eip_bbstart)+delta)
5322//.. )
5323//.. );
5324//..
5325//.. DIP("frstor %s\n", dis_buf);
5326//.. break;
5327//.. }
5328//..
5329//.. case 6: { /* FNSAVE m108 */
5330//.. /* Uses dirty helper:
5331//.. void x86g_do_FSAVE ( VexGuestX86State*, UInt ) */
5332//.. IRDirty* d = unsafeIRDirty_0_N (
5333//.. 0/*regparms*/,
5334//.. "x86g_dirtyhelper_FSAVE",
5335//.. &x86g_dirtyhelper_FSAVE,
5336//.. mkIRExprVec_1( mkexpr(addr) )
5337//.. );
5338//.. d->needsBBP = True;
5339//.. /* declare we're writing memory */
5340//.. d->mFx = Ifx_Write;
5341//.. d->mAddr = mkexpr(addr);
5342//.. d->mSize = 108;
5343//..
5344//.. /* declare we're reading guest state */
5345//.. d->nFxState = 5;
5346//..
5347//.. d->fxState[0].fx = Ifx_Read;
5348//.. d->fxState[0].offset = OFFB_FTOP;
5349//.. d->fxState[0].size = sizeof(UInt);
5350//..
5351//.. d->fxState[1].fx = Ifx_Read;
5352//.. d->fxState[1].offset = OFFB_FPREGS;
5353//.. d->fxState[1].size = 8 * sizeof(ULong);
5354//..
5355//.. d->fxState[2].fx = Ifx_Read;
5356//.. d->fxState[2].offset = OFFB_FPTAGS;
5357//.. d->fxState[2].size = 8 * sizeof(UChar);
5358//..
5359//.. d->fxState[3].fx = Ifx_Read;
5360//.. d->fxState[3].offset = OFFB_FPROUND;
5361//.. d->fxState[3].size = sizeof(UInt);
5362//..
5363//.. d->fxState[4].fx = Ifx_Read;
5364//.. d->fxState[4].offset = OFFB_FC3210;
5365//.. d->fxState[4].size = sizeof(UInt);
5366//..
5367//.. stmt( IRStmt_Dirty(d) );
5368//..
5369//.. DIP("fnsave %s\n", dis_buf);
5370//.. break;
5371//.. }
sewardj8d965312005-02-25 02:48:47 +00005372
5373 default:
sewardj901ed122005-02-27 13:25:31 +00005374 vex_printf("unhandled opc_aux = 0x%2x\n", gregLO3ofRM(modrm));
sewardj8d965312005-02-25 02:48:47 +00005375 vex_printf("first_opcode == 0xDD\n");
5376 goto decode_fail;
5377 }
5378 } else {
5379 delta++;
5380 switch (modrm) {
5381
sewardj6847d8c2005-05-12 19:21:55 +00005382 case 0xC0 ... 0xC7: /* FFREE %st(?) */
5383 r_dst = (UInt)modrm - 0xC0;
5384 DIP("ffree %%st(%u)\n", r_dst);
5385 put_ST_TAG ( r_dst, mkU8(0) );
5386 break;
5387
sewardjbfabcc42005-08-08 09:58:05 +00005388 case 0xD0 ... 0xD7: /* FST %st(0),%st(?) */
5389 r_dst = (UInt)modrm - 0xD0;
sewardjc7cd2142005-09-09 22:31:49 +00005390 DIP("fst %%st(0),%%st(%u)\n", r_dst);
sewardjbfabcc42005-08-08 09:58:05 +00005391 /* P4 manual says: "If the destination operand is a
5392 non-empty register, the invalid-operation exception
5393 is not generated. Hence put_ST_UNCHECKED. */
5394 put_ST_UNCHECKED(r_dst, get_ST(0));
5395 break;
sewardj8d965312005-02-25 02:48:47 +00005396
5397 case 0xD8 ... 0xDF: /* FSTP %st(0),%st(?) */
5398 r_dst = (UInt)modrm - 0xD8;
sewardj1027dc22005-02-26 01:55:02 +00005399 DIP("fstp %%st(0),%%st(%u)\n", r_dst);
sewardj8d965312005-02-25 02:48:47 +00005400 /* P4 manual says: "If the destination operand is a
5401 non-empty register, the invalid-operation exception
5402 is not generated. Hence put_ST_UNCHECKED. */
5403 put_ST_UNCHECKED(r_dst, get_ST(0));
5404 fp_pop();
5405 break;
5406
sewardjd20c8852005-01-20 20:04:07 +00005407//.. case 0xE0 ... 0xE7: /* FUCOM %st(0),%st(?) */
5408//.. r_dst = (UInt)modrm - 0xE0;
5409//.. DIP("fucom %%st(0),%%st(%d)\n", r_dst);
5410//.. /* This forces C1 to zero, which isn't right. */
5411//.. put_C3210(
5412//.. binop( Iop_And32,
5413//.. binop(Iop_Shl32,
5414//.. binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
5415//.. mkU8(8)),
5416//.. mkU32(0x4500)
5417//.. ));
5418//.. break;
5419//..
5420//.. case 0xE8 ... 0xEF: /* FUCOMP %st(0),%st(?) */
5421//.. r_dst = (UInt)modrm - 0xE8;
5422//.. DIP("fucomp %%st(0),%%st(%d)\n", r_dst);
5423//.. /* This forces C1 to zero, which isn't right. */
5424//.. put_C3210(
5425//.. binop( Iop_And32,
5426//.. binop(Iop_Shl32,
5427//.. binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
5428//.. mkU8(8)),
5429//.. mkU32(0x4500)
5430//.. ));
5431//.. fp_pop();
5432//.. break;
sewardj8d965312005-02-25 02:48:47 +00005433
5434 default:
5435 goto decode_fail;
5436 }
5437 }
5438 }
5439
sewardj137015d2005-03-27 04:01:15 +00005440 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDE opcodes +-+-+-+-+-+-+-+ */
5441 else
5442 if (first_opcode == 0xDE) {
5443
5444 if (modrm < 0xC0) {
5445
sewardj6847d8c2005-05-12 19:21:55 +00005446 /* bits 5,4,3 are an opcode extension, and the modRM also
5447 specifies an address. */
5448 IROp fop;
5449 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
5450 delta += len;
5451
5452 switch (gregLO3ofRM(modrm)) {
5453
5454 case 0: /* FIADD m16int */ /* ST(0) += m16int */
5455 DIP("fiaddw %s\n", dis_buf);
5456 fop = Iop_AddF64;
5457 goto do_fop_m16;
5458
5459 case 1: /* FIMUL m16int */ /* ST(0) *= m16int */
5460 DIP("fimulw %s\n", dis_buf);
5461 fop = Iop_MulF64;
5462 goto do_fop_m16;
5463
5464 case 4: /* FISUB m16int */ /* ST(0) -= m16int */
5465 DIP("fisubw %s\n", dis_buf);
5466 fop = Iop_SubF64;
5467 goto do_fop_m16;
5468
5469 case 5: /* FISUBR m16int */ /* ST(0) = m16int - ST(0) */
5470 DIP("fisubrw %s\n", dis_buf);
5471 fop = Iop_SubF64;
5472 goto do_foprev_m16;
5473
5474 case 6: /* FIDIV m16int */ /* ST(0) /= m16int */
5475 DIP("fisubw %s\n", dis_buf);
5476 fop = Iop_DivF64;
5477 goto do_fop_m16;
5478
5479 case 7: /* FIDIVR m16int */ /* ST(0) = m16int / ST(0) */
5480 DIP("fidivrw %s\n", dis_buf);
5481 fop = Iop_DivF64;
5482 goto do_foprev_m16;
5483
5484 do_fop_m16:
5485 put_ST_UNCHECKED(0,
5486 binop(fop,
5487 get_ST(0),
5488 unop(Iop_I32toF64,
5489 unop(Iop_16Sto32,
5490 loadLE(Ity_I16, mkexpr(addr))))));
5491 break;
5492
5493 do_foprev_m16:
5494 put_ST_UNCHECKED(0,
5495 binop(fop,
5496 unop(Iop_I32toF64,
5497 unop(Iop_16Sto32,
5498 loadLE(Ity_I16, mkexpr(addr)))),
5499 get_ST(0)));
5500 break;
5501
5502 default:
5503 vex_printf("unhandled opc_aux = 0x%2x\n", gregLO3ofRM(modrm));
5504 vex_printf("first_opcode == 0xDE\n");
5505 goto decode_fail;
5506 }
sewardj137015d2005-03-27 04:01:15 +00005507
5508 } else {
5509
5510 delta++;
5511 switch (modrm) {
5512
5513 case 0xC0 ... 0xC7: /* FADDP %st(0),%st(?) */
5514 fp_do_op_ST_ST ( "add", Iop_AddF64, 0, modrm - 0xC0, True );
5515 break;
5516
5517 case 0xC8 ... 0xCF: /* FMULP %st(0),%st(?) */
5518 fp_do_op_ST_ST ( "mul", Iop_MulF64, 0, modrm - 0xC8, True );
5519 break;
5520
sewardjd20c8852005-01-20 20:04:07 +00005521//.. case 0xD9: /* FCOMPP %st(0),%st(1) */
5522//.. DIP("fuompp %%st(0),%%st(1)\n");
5523//.. /* This forces C1 to zero, which isn't right. */
5524//.. put_C3210(
5525//.. binop( Iop_And32,
5526//.. binop(Iop_Shl32,
5527//.. binop(Iop_CmpF64, get_ST(0), get_ST(1)),
5528//.. mkU8(8)),
5529//.. mkU32(0x4500)
5530//.. ));
5531//.. fp_pop();
5532//.. fp_pop();
5533//.. break;
sewardj137015d2005-03-27 04:01:15 +00005534
5535 case 0xE0 ... 0xE7: /* FSUBRP %st(0),%st(?) */
5536 fp_do_oprev_ST_ST ( "subr", Iop_SubF64, 0, modrm - 0xE0, True );
5537 break;
5538
5539 case 0xE8 ... 0xEF: /* FSUBP %st(0),%st(?) */
5540 fp_do_op_ST_ST ( "sub", Iop_SubF64, 0, modrm - 0xE8, True );
5541 break;
5542
5543 case 0xF0 ... 0xF7: /* FDIVRP %st(0),%st(?) */
5544 fp_do_oprev_ST_ST ( "divr", Iop_DivF64, 0, modrm - 0xF0, True );
5545 break;
5546
5547 case 0xF8 ... 0xFF: /* FDIVP %st(0),%st(?) */
5548 fp_do_op_ST_ST ( "div", Iop_DivF64, 0, modrm - 0xF8, True );
5549 break;
5550
5551 default:
5552 goto decode_fail;
5553 }
5554
5555 }
5556 }
sewardjc49ce232005-02-25 13:03:03 +00005557
5558 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDF opcodes +-+-+-+-+-+-+-+ */
5559 else
5560 if (first_opcode == 0xDF) {
5561
5562 if (modrm < 0xC0) {
5563
5564 /* bits 5,4,3 are an opcode extension, and the modRM also
5565 specifies an address. */
5566 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
5567 delta += len;
5568
sewardj901ed122005-02-27 13:25:31 +00005569 switch (gregLO3ofRM(modrm)) {
sewardjc49ce232005-02-25 13:03:03 +00005570
sewardj434e0692005-03-27 17:36:08 +00005571 case 0: /* FILD m16int */
5572 DIP("fildw %s\n", dis_buf);
5573 fp_push();
5574 put_ST(0, unop(Iop_I32toF64,
5575 unop(Iop_16Sto32,
5576 loadLE(Ity_I16, mkexpr(addr)))));
5577 break;
5578
sewardjd20c8852005-01-20 20:04:07 +00005579//.. case 2: /* FIST m16 */
5580//.. DIP("fistp %s\n", dis_buf);
5581//.. storeLE( mkexpr(addr),
5582//.. binop(Iop_F64toI16, get_roundingmode(), get_ST(0)) );
5583//.. break;
sewardj6847d8c2005-05-12 19:21:55 +00005584
sewardjd20c8852005-01-20 20:04:07 +00005585//.. case 3: /* FISTP m16 */
5586//.. DIP("fistps %s\n", dis_buf);
5587//.. storeLE( mkexpr(addr),
5588//.. binop(Iop_F64toI16, get_roundingmode(), get_ST(0)) );
5589//.. fp_pop();
5590//.. break;
sewardj37d52572005-02-25 14:22:12 +00005591
5592 case 5: /* FILD m64 */
5593 DIP("fildll %s\n", dis_buf);
5594 fp_push();
5595 put_ST(0, binop(Iop_I64toF64,
5596 get_roundingmode(),
5597 loadLE(Ity_I64, mkexpr(addr))));
5598 break;
5599
sewardj6847d8c2005-05-12 19:21:55 +00005600 case 7: /* FISTP m64 */
5601 DIP("fistpll %s\n", dis_buf);
5602 storeLE( mkexpr(addr),
5603 binop(Iop_F64toI64, get_roundingmode(), get_ST(0)) );
5604 fp_pop();
5605 break;
sewardjc49ce232005-02-25 13:03:03 +00005606
5607 default:
sewardj901ed122005-02-27 13:25:31 +00005608 vex_printf("unhandled opc_aux = 0x%2x\n", gregLO3ofRM(modrm));
sewardjc49ce232005-02-25 13:03:03 +00005609 vex_printf("first_opcode == 0xDF\n");
5610 goto decode_fail;
5611 }
5612
5613 } else {
5614
5615 delta++;
5616 switch (modrm) {
5617
5618 case 0xC0: /* FFREEP %st(0) */
5619 DIP("ffreep %%st(%d)\n", 0);
5620 put_ST_TAG ( 0, mkU8(0) );
5621 fp_pop();
5622 break;
5623
sewardj4f9847d2005-07-25 11:58:34 +00005624 case 0xE0: /* FNSTSW %ax */
5625 DIP("fnstsw %%ax\n");
5626 /* Invent a plausible-looking FPU status word value and
5627 dump it in %AX:
5628 ((ftop & 7) << 11) | (c3210 & 0x4700)
5629 */
5630 putIRegRAX(
5631 2,
5632 unop(Iop_32to16,
5633 binop(Iop_Or32,
5634 binop(Iop_Shl32,
5635 binop(Iop_And32, get_ftop(), mkU32(7)),
5636 mkU8(11)),
5637 binop(Iop_And32,
5638 unop(Iop_64to32, get_C3210()),
5639 mkU32(0x4700))
5640 )));
5641 break;
sewardj924215b2005-03-26 21:50:31 +00005642
5643 case 0xE8 ... 0xEF: /* FUCOMIP %st(0),%st(?) */
5644 fp_do_ucomi_ST0_STi( (UInt)modrm - 0xE8, True );
5645 break;
5646
sewardj48a89d82005-05-06 11:50:13 +00005647 case 0xF0 ... 0xF7: /* FCOMIP %st(0),%st(?) */
5648 /* not really right since COMIP != UCOMIP */
5649 fp_do_ucomi_ST0_STi( (UInt)modrm - 0xF0, True );
5650 break;
sewardjc49ce232005-02-25 13:03:03 +00005651
5652 default:
5653 goto decode_fail;
5654 }
5655 }
5656
5657 }
sewardj8d965312005-02-25 02:48:47 +00005658
5659 else
sewardj137015d2005-03-27 04:01:15 +00005660 goto decode_fail;
sewardj8d965312005-02-25 02:48:47 +00005661
5662 *decode_ok = True;
5663 return delta;
5664
5665 decode_fail:
5666 *decode_ok = False;
5667 return delta;
5668}
5669
5670
sewardj8711f662005-05-09 17:52:56 +00005671/*------------------------------------------------------------*/
5672/*--- ---*/
5673/*--- MMX INSTRUCTIONS ---*/
5674/*--- ---*/
5675/*------------------------------------------------------------*/
5676
5677/* Effect of MMX insns on x87 FPU state (table 11-2 of
5678 IA32 arch manual, volume 3):
5679
5680 Read from, or write to MMX register (viz, any insn except EMMS):
5681 * All tags set to Valid (non-empty) -- FPTAGS[i] := nonzero
5682 * FP stack pointer set to zero
5683
5684 EMMS:
5685 * All tags set to Invalid (empty) -- FPTAGS[i] := zero
5686 * FP stack pointer set to zero
5687*/
5688
5689static void do_MMX_preamble ( void )
5690{
5691 Int i;
5692 IRArray* descr = mkIRArray( OFFB_FPTAGS, Ity_I8, 8 );
5693 IRExpr* zero = mkU32(0);
5694 IRExpr* tag1 = mkU8(1);
5695 put_ftop(zero);
5696 for (i = 0; i < 8; i++)
5697 stmt( IRStmt_PutI( descr, zero, i, tag1 ) );
5698}
5699
5700static void do_EMMS_preamble ( void )
5701{
5702 Int i;
5703 IRArray* descr = mkIRArray( OFFB_FPTAGS, Ity_I8, 8 );
5704 IRExpr* zero = mkU32(0);
5705 IRExpr* tag0 = mkU8(0);
5706 put_ftop(zero);
5707 for (i = 0; i < 8; i++)
5708 stmt( IRStmt_PutI( descr, zero, i, tag0 ) );
5709}
5710
5711
5712static IRExpr* getMMXReg ( UInt archreg )
5713{
5714 vassert(archreg < 8);
5715 return IRExpr_Get( OFFB_FPREGS + 8 * archreg, Ity_I64 );
5716}
5717
5718
5719static void putMMXReg ( UInt archreg, IRExpr* e )
5720{
5721 vassert(archreg < 8);
5722 vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_I64);
5723 stmt( IRStmt_Put( OFFB_FPREGS + 8 * archreg, e ) );
5724}
5725
5726
5727/* Helper for non-shift MMX insns. Note this is incomplete in the
5728 sense that it does not first call do_MMX_preamble() -- that is the
5729 responsibility of its caller. */
5730
5731static
5732ULong dis_MMXop_regmem_to_reg ( Prefix pfx,
sewardj270def42005-07-03 01:03:01 +00005733 Long delta,
sewardj8711f662005-05-09 17:52:56 +00005734 UChar opc,
sewardjca673ab2005-05-11 10:03:08 +00005735 HChar* name,
sewardj8711f662005-05-09 17:52:56 +00005736 Bool show_granularity )
5737{
5738 HChar dis_buf[50];
5739 UChar modrm = getUChar(delta);
5740 Bool isReg = epartIsReg(modrm);
5741 IRExpr* argL = NULL;
5742 IRExpr* argR = NULL;
5743 IRExpr* argG = NULL;
5744 IRExpr* argE = NULL;
5745 IRTemp res = newTemp(Ity_I64);
5746
5747 Bool invG = False;
5748 IROp op = Iop_INVALID;
5749 void* hAddr = NULL;
sewardjca673ab2005-05-11 10:03:08 +00005750 HChar* hName = NULL;
sewardj8711f662005-05-09 17:52:56 +00005751 Bool eLeft = False;
5752
5753# define XXX(_name) do { hAddr = &_name; hName = #_name; } while (0)
5754
5755 switch (opc) {
5756 /* Original MMX ones */
5757 case 0xFC: op = Iop_Add8x8; break;
5758 case 0xFD: op = Iop_Add16x4; break;
5759 case 0xFE: op = Iop_Add32x2; break;
5760
5761 case 0xEC: op = Iop_QAdd8Sx8; break;
5762 case 0xED: op = Iop_QAdd16Sx4; break;
5763
5764 case 0xDC: op = Iop_QAdd8Ux8; break;
5765 case 0xDD: op = Iop_QAdd16Ux4; break;
5766
5767 case 0xF8: op = Iop_Sub8x8; break;
5768 case 0xF9: op = Iop_Sub16x4; break;
5769 case 0xFA: op = Iop_Sub32x2; break;
5770
5771 case 0xE8: op = Iop_QSub8Sx8; break;
5772 case 0xE9: op = Iop_QSub16Sx4; break;
5773
5774 case 0xD8: op = Iop_QSub8Ux8; break;
5775 case 0xD9: op = Iop_QSub16Ux4; break;
5776
5777 case 0xE5: op = Iop_MulHi16Sx4; break;
5778 case 0xD5: op = Iop_Mul16x4; break;
5779 case 0xF5: XXX(amd64g_calculate_mmx_pmaddwd); break;
5780
5781 case 0x74: op = Iop_CmpEQ8x8; break;
5782 case 0x75: op = Iop_CmpEQ16x4; break;
5783 case 0x76: op = Iop_CmpEQ32x2; break;
5784
5785 case 0x64: op = Iop_CmpGT8Sx8; break;
5786 case 0x65: op = Iop_CmpGT16Sx4; break;
5787 case 0x66: op = Iop_CmpGT32Sx2; break;
5788
5789 case 0x6B: op = Iop_QNarrow32Sx2; eLeft = True; break;
5790 case 0x63: op = Iop_QNarrow16Sx4; eLeft = True; break;
5791 case 0x67: op = Iop_QNarrow16Ux4; eLeft = True; break;
5792
5793 case 0x68: op = Iop_InterleaveHI8x8; eLeft = True; break;
5794 case 0x69: op = Iop_InterleaveHI16x4; eLeft = True; break;
5795 case 0x6A: op = Iop_InterleaveHI32x2; eLeft = True; break;
5796
5797 case 0x60: op = Iop_InterleaveLO8x8; eLeft = True; break;
5798 case 0x61: op = Iop_InterleaveLO16x4; eLeft = True; break;
5799 case 0x62: op = Iop_InterleaveLO32x2; eLeft = True; break;
5800
5801 case 0xDB: op = Iop_And64; break;
5802 case 0xDF: op = Iop_And64; invG = True; break;
5803 case 0xEB: op = Iop_Or64; break;
5804 case 0xEF: /* Possibly do better here if argL and argR are the
5805 same reg */
5806 op = Iop_Xor64; break;
5807
5808 /* Introduced in SSE1 */
5809 case 0xE0: op = Iop_Avg8Ux8; break;
5810 case 0xE3: op = Iop_Avg16Ux4; break;
5811 case 0xEE: op = Iop_Max16Sx4; break;
5812 case 0xDE: op = Iop_Max8Ux8; break;
5813 case 0xEA: op = Iop_Min16Sx4; break;
5814 case 0xDA: op = Iop_Min8Ux8; break;
5815 case 0xE4: op = Iop_MulHi16Ux4; break;
sewardja7ba8c42005-05-10 20:08:34 +00005816 case 0xF6: XXX(amd64g_calculate_mmx_psadbw); break;
sewardj8711f662005-05-09 17:52:56 +00005817
5818 /* Introduced in SSE2 */
5819 case 0xD4: op = Iop_Add64; break;
5820 case 0xFB: op = Iop_Sub64; break;
5821
5822 default:
5823 vex_printf("\n0x%x\n", (Int)opc);
5824 vpanic("dis_MMXop_regmem_to_reg");
5825 }
5826
5827# undef XXX
5828
5829 argG = getMMXReg(gregLO3ofRM(modrm));
5830 if (invG)
5831 argG = unop(Iop_Not64, argG);
5832
5833 if (isReg) {
5834 delta++;
5835 argE = getMMXReg(eregLO3ofRM(modrm));
5836 } else {
5837 Int len;
5838 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
5839 delta += len;
5840 argE = loadLE(Ity_I64, mkexpr(addr));
5841 }
5842
5843 if (eLeft) {
5844 argL = argE;
5845 argR = argG;
5846 } else {
5847 argL = argG;
5848 argR = argE;
5849 }
5850
5851 if (op != Iop_INVALID) {
5852 vassert(hName == NULL);
5853 vassert(hAddr == NULL);
5854 assign(res, binop(op, argL, argR));
5855 } else {
5856 vassert(hName != NULL);
5857 vassert(hAddr != NULL);
5858 assign( res,
5859 mkIRExprCCall(
5860 Ity_I64,
5861 0/*regparms*/, hName, hAddr,
5862 mkIRExprVec_2( argL, argR )
5863 )
5864 );
5865 }
5866
5867 putMMXReg( gregLO3ofRM(modrm), mkexpr(res) );
5868
5869 DIP("%s%s %s, %s\n",
5870 name, show_granularity ? nameMMXGran(opc & 3) : "",
5871 ( isReg ? nameMMXReg(eregLO3ofRM(modrm)) : dis_buf ),
5872 nameMMXReg(gregLO3ofRM(modrm)) );
5873
5874 return delta;
5875}
5876
5877
5878/* Vector by scalar shift of G by the amount specified at the bottom
5879 of E. This is a straight copy of dis_SSE_shiftG_byE. */
5880
sewardj270def42005-07-03 01:03:01 +00005881static ULong dis_MMX_shiftG_byE ( Prefix pfx, Long delta,
sewardj8711f662005-05-09 17:52:56 +00005882 HChar* opname, IROp op )
5883{
5884 HChar dis_buf[50];
5885 Int alen, size;
5886 IRTemp addr;
5887 Bool shl, shr, sar;
5888 UChar rm = getUChar(delta);
5889 IRTemp g0 = newTemp(Ity_I64);
5890 IRTemp g1 = newTemp(Ity_I64);
5891 IRTemp amt = newTemp(Ity_I64);
5892 IRTemp amt8 = newTemp(Ity_I8);
5893
5894 if (epartIsReg(rm)) {
5895 assign( amt, getMMXReg(eregLO3ofRM(rm)) );
5896 DIP("%s %s,%s\n", opname,
5897 nameMMXReg(eregLO3ofRM(rm)),
5898 nameMMXReg(gregLO3ofRM(rm)) );
5899 delta++;
5900 } else {
5901 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
5902 assign( amt, loadLE(Ity_I64, mkexpr(addr)) );
5903 DIP("%s %s,%s\n", opname,
5904 dis_buf,
5905 nameMMXReg(gregLO3ofRM(rm)) );
5906 delta += alen;
5907 }
5908 assign( g0, getMMXReg(gregLO3ofRM(rm)) );
5909 assign( amt8, unop(Iop_64to8, mkexpr(amt)) );
5910
5911 shl = shr = sar = False;
5912 size = 0;
5913 switch (op) {
5914 case Iop_ShlN16x4: shl = True; size = 32; break;
5915 case Iop_ShlN32x2: shl = True; size = 32; break;
5916 case Iop_Shl64: shl = True; size = 64; break;
5917 case Iop_ShrN16x4: shr = True; size = 16; break;
5918 case Iop_ShrN32x2: shr = True; size = 32; break;
5919 case Iop_Shr64: shr = True; size = 64; break;
5920 case Iop_SarN16x4: sar = True; size = 16; break;
5921 case Iop_SarN32x2: sar = True; size = 32; break;
5922 default: vassert(0);
5923 }
5924
5925 if (shl || shr) {
5926 assign(
5927 g1,
5928 IRExpr_Mux0X(
5929 unop(Iop_1Uto8,binop(Iop_CmpLT64U,mkexpr(amt),mkU64(size))),
5930 mkU64(0),
5931 binop(op, mkexpr(g0), mkexpr(amt8))
5932 )
5933 );
5934 } else
5935 if (sar) {
5936 assign(
5937 g1,
5938 IRExpr_Mux0X(
5939 unop(Iop_1Uto8,binop(Iop_CmpLT64U,mkexpr(amt),mkU64(size))),
5940 binop(op, mkexpr(g0), mkU8(size-1)),
5941 binop(op, mkexpr(g0), mkexpr(amt8))
5942 )
5943 );
5944 } else {
5945 vassert(0);
5946 }
5947
5948 putMMXReg( gregLO3ofRM(rm), mkexpr(g1) );
5949 return delta;
5950}
5951
5952
sewardj3d8107c2005-05-09 22:23:38 +00005953/* Vector by scalar shift of E by an immediate byte. This is a
5954 straight copy of dis_SSE_shiftE_imm. */
5955
5956static
sewardj270def42005-07-03 01:03:01 +00005957ULong dis_MMX_shiftE_imm ( Long delta, HChar* opname, IROp op )
sewardj3d8107c2005-05-09 22:23:38 +00005958{
5959 Bool shl, shr, sar;
5960 UChar rm = getUChar(delta);
5961 IRTemp e0 = newTemp(Ity_I64);
5962 IRTemp e1 = newTemp(Ity_I64);
5963 UChar amt, size;
5964 vassert(epartIsReg(rm));
5965 vassert(gregLO3ofRM(rm) == 2
5966 || gregLO3ofRM(rm) == 4 || gregLO3ofRM(rm) == 6);
sewardjca673ab2005-05-11 10:03:08 +00005967 amt = getUChar(delta+1);
sewardj3d8107c2005-05-09 22:23:38 +00005968 delta += 2;
5969 DIP("%s $%d,%s\n", opname,
5970 (Int)amt,
5971 nameMMXReg(eregLO3ofRM(rm)) );
5972
5973 assign( e0, getMMXReg(eregLO3ofRM(rm)) );
5974
5975 shl = shr = sar = False;
5976 size = 0;
5977 switch (op) {
5978 case Iop_ShlN16x4: shl = True; size = 16; break;
5979 case Iop_ShlN32x2: shl = True; size = 32; break;
5980 case Iop_Shl64: shl = True; size = 64; break;
5981 case Iop_SarN16x4: sar = True; size = 16; break;
5982 case Iop_SarN32x2: sar = True; size = 32; break;
5983 case Iop_ShrN16x4: shr = True; size = 16; break;
5984 case Iop_ShrN32x2: shr = True; size = 32; break;
5985 case Iop_Shr64: shr = True; size = 64; break;
5986 default: vassert(0);
5987 }
5988
5989 if (shl || shr) {
5990 assign( e1, amt >= size
5991 ? mkU64(0)
5992 : binop(op, mkexpr(e0), mkU8(amt))
5993 );
5994 } else
5995 if (sar) {
5996 assign( e1, amt >= size
5997 ? binop(op, mkexpr(e0), mkU8(size-1))
5998 : binop(op, mkexpr(e0), mkU8(amt))
5999 );
6000 } else {
6001 vassert(0);
6002 }
6003
6004 putMMXReg( eregLO3ofRM(rm), mkexpr(e1) );
6005 return delta;
6006}
sewardj8711f662005-05-09 17:52:56 +00006007
6008
6009/* Completely handle all MMX instructions except emms. */
6010
6011static
sewardj270def42005-07-03 01:03:01 +00006012ULong dis_MMX ( Bool* decode_ok, Prefix pfx, Int sz, Long delta )
sewardj8711f662005-05-09 17:52:56 +00006013{
6014 Int len;
6015 UChar modrm;
6016 HChar dis_buf[50];
6017 UChar opc = getUChar(delta);
6018 delta++;
6019
6020 /* dis_MMX handles all insns except emms. */
6021 do_MMX_preamble();
6022
6023 switch (opc) {
6024
sewardj3d8107c2005-05-09 22:23:38 +00006025 case 0x6E:
6026 if (sz == 4) {
6027 /* MOVD (src)ireg32-or-mem32 (E), (dst)mmxreg (G)*/
6028 modrm = getUChar(delta);
6029 if (epartIsReg(modrm)) {
6030 delta++;
6031 putMMXReg(
6032 gregLO3ofRM(modrm),
6033 binop( Iop_32HLto64,
6034 mkU32(0),
6035 getIReg32(eregOfRexRM(pfx,modrm)) ) );
6036 DIP("movd %s, %s\n",
6037 nameIReg32(eregOfRexRM(pfx,modrm)),
6038 nameMMXReg(gregLO3ofRM(modrm)));
6039 } else {
6040 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
6041 delta += len;
6042 putMMXReg(
6043 gregLO3ofRM(modrm),
6044 binop( Iop_32HLto64,
6045 mkU32(0),
6046 loadLE(Ity_I32, mkexpr(addr)) ) );
6047 DIP("movd %s, %s\n", dis_buf, nameMMXReg(gregLO3ofRM(modrm)));
6048 }
6049 }
6050 else
6051 if (sz == 8) {
6052 /* MOVD (src)ireg64-or-mem64 (E), (dst)mmxreg (G)*/
6053 modrm = getUChar(delta);
6054 if (epartIsReg(modrm)) {
6055 delta++;
6056 putMMXReg( gregLO3ofRM(modrm),
6057 getIReg64(eregOfRexRM(pfx,modrm)) );
6058 DIP("movd %s, %s\n",
6059 nameIReg64(eregOfRexRM(pfx,modrm)),
6060 nameMMXReg(gregLO3ofRM(modrm)));
6061 } else {
6062 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
6063 delta += len;
6064 putMMXReg( gregLO3ofRM(modrm),
6065 loadLE(Ity_I64, mkexpr(addr)) );
6066 DIP("movd{64} %s, %s\n", dis_buf, nameMMXReg(gregLO3ofRM(modrm)));
6067 }
6068 }
6069 else {
6070 goto mmx_decode_failure;
6071 }
6072 break;
6073
6074 case 0x7E:
6075 if (sz == 4) {
6076 /* MOVD (src)mmxreg (G), (dst)ireg32-or-mem32 (E) */
6077 modrm = getUChar(delta);
6078 if (epartIsReg(modrm)) {
6079 delta++;
6080 putIReg32( eregOfRexRM(pfx,modrm),
6081 unop(Iop_64to32, getMMXReg(gregLO3ofRM(modrm)) ) );
6082 DIP("movd %s, %s\n",
6083 nameMMXReg(gregLO3ofRM(modrm)),
6084 nameIReg32(eregOfRexRM(pfx,modrm)));
6085 } else {
6086 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
6087 delta += len;
6088 storeLE( mkexpr(addr),
6089 unop(Iop_64to32, getMMXReg(gregLO3ofRM(modrm)) ) );
6090 DIP("movd %s, %s\n", nameMMXReg(gregLO3ofRM(modrm)), dis_buf);
6091 }
6092 }
6093 else
6094 if (sz == 8) {
6095 /* MOVD (src)mmxreg (G), (dst)ireg64-or-mem64 (E) */
6096 modrm = getUChar(delta);
6097 if (epartIsReg(modrm)) {
6098 delta++;
6099 putIReg64( eregOfRexRM(pfx,modrm),
6100 getMMXReg(gregLO3ofRM(modrm)) );
6101 DIP("movd %s, %s\n",
6102 nameMMXReg(gregLO3ofRM(modrm)),
6103 nameIReg64(eregOfRexRM(pfx,modrm)));
6104 } else {
6105 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
6106 delta += len;
6107 storeLE( mkexpr(addr),
6108 getMMXReg(gregLO3ofRM(modrm)) );
6109 DIP("movd{64} %s, %s\n", nameMMXReg(gregLO3ofRM(modrm)), dis_buf);
6110 }
6111 } else {
6112 goto mmx_decode_failure;
6113 }
6114 break;
sewardj8711f662005-05-09 17:52:56 +00006115
6116 case 0x6F:
6117 /* MOVQ (src)mmxreg-or-mem, (dst)mmxreg */
6118 if (sz != 4)
6119 goto mmx_decode_failure;
6120 modrm = getUChar(delta);
6121 if (epartIsReg(modrm)) {
6122 delta++;
6123 putMMXReg( gregLO3ofRM(modrm), getMMXReg(eregLO3ofRM(modrm)) );
6124 DIP("movq %s, %s\n",
6125 nameMMXReg(eregLO3ofRM(modrm)),
6126 nameMMXReg(gregLO3ofRM(modrm)));
6127 } else {
6128 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
6129 delta += len;
6130 putMMXReg( gregLO3ofRM(modrm), loadLE(Ity_I64, mkexpr(addr)) );
6131 DIP("movq %s, %s\n",
6132 dis_buf, nameMMXReg(gregLO3ofRM(modrm)));
6133 }
6134 break;
6135
6136 case 0x7F:
6137 /* MOVQ (src)mmxreg, (dst)mmxreg-or-mem */
6138 if (sz != 4)
6139 goto mmx_decode_failure;
6140 modrm = getUChar(delta);
6141 if (epartIsReg(modrm)) {
6142 /* Fall through. The assembler doesn't appear to generate
6143 these. */
6144 goto mmx_decode_failure;
6145 } else {
6146 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
6147 delta += len;
6148 storeLE( mkexpr(addr), getMMXReg(gregLO3ofRM(modrm)) );
6149 DIP("mov(nt)q %s, %s\n",
6150 nameMMXReg(gregLO3ofRM(modrm)), dis_buf);
6151 }
6152 break;
6153
6154 case 0xFC:
6155 case 0xFD:
6156 case 0xFE: /* PADDgg (src)mmxreg-or-mem, (dst)mmxreg */
6157 if (sz != 4)
6158 goto mmx_decode_failure;
6159 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "padd", True );
6160 break;
6161
6162 case 0xEC:
6163 case 0xED: /* PADDSgg (src)mmxreg-or-mem, (dst)mmxreg */
6164 if (sz != 4)
6165 goto mmx_decode_failure;
6166 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "padds", True );
6167 break;
6168
6169 case 0xDC:
6170 case 0xDD: /* PADDUSgg (src)mmxreg-or-mem, (dst)mmxreg */
6171 if (sz != 4)
6172 goto mmx_decode_failure;
6173 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "paddus", True );
6174 break;
6175
6176 case 0xF8:
6177 case 0xF9:
6178 case 0xFA: /* PSUBgg (src)mmxreg-or-mem, (dst)mmxreg */
6179 if (sz != 4)
6180 goto mmx_decode_failure;
6181 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "psub", True );
6182 break;
6183
6184 case 0xE8:
6185 case 0xE9: /* PSUBSgg (src)mmxreg-or-mem, (dst)mmxreg */
6186 if (sz != 4)
6187 goto mmx_decode_failure;
6188 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "psubs", True );
6189 break;
6190
6191 case 0xD8:
6192 case 0xD9: /* PSUBUSgg (src)mmxreg-or-mem, (dst)mmxreg */
6193 if (sz != 4)
6194 goto mmx_decode_failure;
6195 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "psubus", True );
6196 break;
6197
6198 case 0xE5: /* PMULHW (src)mmxreg-or-mem, (dst)mmxreg */
6199 if (sz != 4)
6200 goto mmx_decode_failure;
6201 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "pmulhw", False );
6202 break;
6203
6204 case 0xD5: /* PMULLW (src)mmxreg-or-mem, (dst)mmxreg */
6205 if (sz != 4)
6206 goto mmx_decode_failure;
6207 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "pmullw", False );
6208 break;
6209
6210 case 0xF5: /* PMADDWD (src)mmxreg-or-mem, (dst)mmxreg */
6211 vassert(sz == 4);
6212 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "pmaddwd", False );
6213 break;
6214
6215 case 0x74:
6216 case 0x75:
6217 case 0x76: /* PCMPEQgg (src)mmxreg-or-mem, (dst)mmxreg */
6218 if (sz != 4)
6219 goto mmx_decode_failure;
6220 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "pcmpeq", True );
6221 break;
6222
6223 case 0x64:
6224 case 0x65:
6225 case 0x66: /* PCMPGTgg (src)mmxreg-or-mem, (dst)mmxreg */
6226 if (sz != 4)
6227 goto mmx_decode_failure;
6228 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "pcmpgt", True );
6229 break;
6230
6231 case 0x6B: /* PACKSSDW (src)mmxreg-or-mem, (dst)mmxreg */
6232 if (sz != 4)
6233 goto mmx_decode_failure;
6234 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "packssdw", False );
6235 break;
6236
6237 case 0x63: /* PACKSSWB (src)mmxreg-or-mem, (dst)mmxreg */
6238 if (sz != 4)
6239 goto mmx_decode_failure;
6240 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "packsswb", False );
6241 break;
6242
6243 case 0x67: /* PACKUSWB (src)mmxreg-or-mem, (dst)mmxreg */
6244 if (sz != 4)
6245 goto mmx_decode_failure;
6246 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "packuswb", False );
6247 break;
6248
6249 case 0x68:
6250 case 0x69:
6251 case 0x6A: /* PUNPCKHgg (src)mmxreg-or-mem, (dst)mmxreg */
6252 if (sz != 4)
6253 goto mmx_decode_failure;
6254 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "punpckh", True );
6255 break;
6256
6257 case 0x60:
6258 case 0x61:
6259 case 0x62: /* PUNPCKLgg (src)mmxreg-or-mem, (dst)mmxreg */
6260 if (sz != 4)
6261 goto mmx_decode_failure;
6262 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "punpckl", True );
6263 break;
6264
6265 case 0xDB: /* PAND (src)mmxreg-or-mem, (dst)mmxreg */
6266 if (sz != 4)
6267 goto mmx_decode_failure;
6268 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "pand", False );
6269 break;
6270
6271 case 0xDF: /* PANDN (src)mmxreg-or-mem, (dst)mmxreg */
6272 if (sz != 4)
6273 goto mmx_decode_failure;
6274 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "pandn", False );
6275 break;
6276
6277 case 0xEB: /* POR (src)mmxreg-or-mem, (dst)mmxreg */
6278 if (sz != 4)
6279 goto mmx_decode_failure;
6280 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "por", False );
6281 break;
6282
6283 case 0xEF: /* PXOR (src)mmxreg-or-mem, (dst)mmxreg */
6284 if (sz != 4)
6285 goto mmx_decode_failure;
6286 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "pxor", False );
6287 break;
6288
6289# define SHIFT_BY_REG(_name,_op) \
6290 delta = dis_MMX_shiftG_byE(pfx, delta, _name, _op); \
6291 break;
6292
6293 /* PSLLgg (src)mmxreg-or-mem, (dst)mmxreg */
6294 case 0xF1: SHIFT_BY_REG("psllw", Iop_ShlN16x4);
6295 case 0xF2: SHIFT_BY_REG("pslld", Iop_ShlN32x2);
6296 case 0xF3: SHIFT_BY_REG("psllq", Iop_Shl64);
6297
6298 /* PSRLgg (src)mmxreg-or-mem, (dst)mmxreg */
6299 case 0xD1: SHIFT_BY_REG("psrlw", Iop_ShrN16x4);
6300 case 0xD2: SHIFT_BY_REG("psrld", Iop_ShrN32x2);
6301 case 0xD3: SHIFT_BY_REG("psrlq", Iop_Shr64);
6302
6303 /* PSRAgg (src)mmxreg-or-mem, (dst)mmxreg */
6304 case 0xE1: SHIFT_BY_REG("psraw", Iop_SarN16x4);
6305 case 0xE2: SHIFT_BY_REG("psrad", Iop_SarN32x2);
6306
6307# undef SHIFT_BY_REG
sewardj3d8107c2005-05-09 22:23:38 +00006308
6309 case 0x71:
6310 case 0x72:
6311 case 0x73: {
6312 /* (sz==4): PSLLgg/PSRAgg/PSRLgg mmxreg by imm8 */
sewardjca673ab2005-05-11 10:03:08 +00006313 UChar byte2, subopc;
sewardj3d8107c2005-05-09 22:23:38 +00006314 if (sz != 4)
6315 goto mmx_decode_failure;
sewardjca673ab2005-05-11 10:03:08 +00006316 byte2 = getUChar(delta); /* amode / sub-opcode */
6317 subopc = toUChar( (byte2 >> 3) & 7 );
sewardj3d8107c2005-05-09 22:23:38 +00006318
6319# define SHIFT_BY_IMM(_name,_op) \
6320 do { delta = dis_MMX_shiftE_imm(delta,_name,_op); \
6321 } while (0)
6322
6323 if (subopc == 2 /*SRL*/ && opc == 0x71)
6324 SHIFT_BY_IMM("psrlw", Iop_ShrN16x4);
6325 else if (subopc == 2 /*SRL*/ && opc == 0x72)
6326 SHIFT_BY_IMM("psrld", Iop_ShrN32x2);
6327 else if (subopc == 2 /*SRL*/ && opc == 0x73)
6328 SHIFT_BY_IMM("psrlq", Iop_Shr64);
6329
6330 else if (subopc == 4 /*SAR*/ && opc == 0x71)
6331 SHIFT_BY_IMM("psraw", Iop_SarN16x4);
6332 else if (subopc == 4 /*SAR*/ && opc == 0x72)
6333 SHIFT_BY_IMM("psrad", Iop_SarN32x2);
6334
6335 else if (subopc == 6 /*SHL*/ && opc == 0x71)
6336 SHIFT_BY_IMM("psllw", Iop_ShlN16x4);
6337 else if (subopc == 6 /*SHL*/ && opc == 0x72)
6338 SHIFT_BY_IMM("pslld", Iop_ShlN32x2);
6339 else if (subopc == 6 /*SHL*/ && opc == 0x73)
6340 SHIFT_BY_IMM("psllq", Iop_Shl64);
6341
6342 else goto mmx_decode_failure;
6343
6344# undef SHIFT_BY_IMM
6345 break;
6346 }
sewardj8711f662005-05-09 17:52:56 +00006347
6348 /* --- MMX decode failure --- */
6349 default:
6350 mmx_decode_failure:
6351 *decode_ok = False;
6352 return delta; /* ignored */
6353
6354 }
6355
6356 *decode_ok = True;
6357 return delta;
6358}
6359
6360
sewardjd20c8852005-01-20 20:04:07 +00006361//.. /*------------------------------------------------------------*/
6362//.. /*--- More misc arithmetic and other obscure insns. ---*/
6363//.. /*------------------------------------------------------------*/
6364//..
6365//.. /* Double length left and right shifts. Apparently only required in
6366//.. v-size (no b- variant). */
6367//.. static
6368//.. UInt dis_SHLRD_Gv_Ev ( UChar sorb,
sewardj270def42005-07-03 01:03:01 +00006369//.. Long delta, UChar modrm,
sewardjd20c8852005-01-20 20:04:07 +00006370//.. Int sz,
6371//.. IRExpr* shift_amt,
6372//.. Bool amt_is_literal,
6373//.. Char* shift_amt_txt,
6374//.. Bool left_shift )
6375//.. {
6376//.. /* shift_amt :: Ity_I8 is the amount to shift. shift_amt_txt is used
6377//.. for printing it. And eip on entry points at the modrm byte. */
6378//.. Int len;
6379//.. HChar dis_buf[50];
6380//..
6381//.. IRType ty = szToITy(sz);
6382//.. IRTemp gsrc = newTemp(ty);
6383//.. IRTemp esrc = newTemp(ty);
6384//.. IRTemp addr = IRTemp_INVALID;
6385//.. IRTemp tmpSH = newTemp(Ity_I8);
6386//.. IRTemp tmpL = IRTemp_INVALID;
6387//.. IRTemp tmpRes = IRTemp_INVALID;
6388//.. IRTemp tmpSubSh = IRTemp_INVALID;
6389//.. IROp mkpair;
6390//.. IROp getres;
6391//.. IROp shift;
6392//.. IRExpr* mask = NULL;
6393//..
6394//.. vassert(sz == 2 || sz == 4);
6395//..
6396//.. /* The E-part is the destination; this is shifted. The G-part
6397//.. supplies bits to be shifted into the E-part, but is not
6398//.. changed.
6399//..
6400//.. If shifting left, form a double-length word with E at the top
6401//.. and G at the bottom, and shift this left. The result is then in
6402//.. the high part.
6403//..
6404//.. If shifting right, form a double-length word with G at the top
6405//.. and E at the bottom, and shift this right. The result is then
6406//.. at the bottom. */
6407//..
6408//.. /* Fetch the operands. */
6409//..
6410//.. assign( gsrc, getIReg(sz, gregOfRM(modrm)) );
6411//..
6412//.. if (epartIsReg(modrm)) {
6413//.. delta++;
6414//.. assign( esrc, getIReg(sz, eregOfRM(modrm)) );
6415//.. DIP("sh%cd%c %s, %s, %s\n",
6416//.. ( left_shift ? 'l' : 'r' ), nameISize(sz),
6417//.. shift_amt_txt,
6418//.. nameIReg(sz, gregOfRM(modrm)), nameIReg(sz, eregOfRM(modrm)));
6419//.. } else {
6420//.. addr = disAMode ( &len, sorb, delta, dis_buf );
6421//.. delta += len;
6422//.. assign( esrc, loadLE(ty, mkexpr(addr)) );
6423//.. DIP("sh%cd%c %s, %s, %s\n",
6424//.. ( left_shift ? 'l' : 'r' ), nameISize(sz),
6425//.. shift_amt_txt,
6426//.. nameIReg(sz, gregOfRM(modrm)), dis_buf);
6427//.. }
6428//..
6429//.. /* Round up the relevant primops. */
6430//..
6431//.. if (sz == 4) {
6432//.. tmpL = newTemp(Ity_I64);
6433//.. tmpRes = newTemp(Ity_I32);
6434//.. tmpSubSh = newTemp(Ity_I32);
6435//.. mkpair = Iop_32HLto64;
6436//.. getres = left_shift ? Iop_64HIto32 : Iop_64to32;
6437//.. shift = left_shift ? Iop_Shl64 : Iop_Shr64;
6438//.. mask = mkU8(31);
6439//.. } else {
6440//.. /* sz == 2 */
6441//.. tmpL = newTemp(Ity_I32);
6442//.. tmpRes = newTemp(Ity_I16);
6443//.. tmpSubSh = newTemp(Ity_I16);
6444//.. mkpair = Iop_16HLto32;
6445//.. getres = left_shift ? Iop_32HIto16 : Iop_32to16;
6446//.. shift = left_shift ? Iop_Shl32 : Iop_Shr32;
6447//.. mask = mkU8(15);
6448//.. }
6449//..
6450//.. /* Do the shift, calculate the subshift value, and set
6451//.. the flag thunk. */
6452//..
6453//.. assign( tmpSH, binop(Iop_And8, shift_amt, mask) );
6454//..
6455//.. if (left_shift)
6456//.. assign( tmpL, binop(mkpair, mkexpr(esrc), mkexpr(gsrc)) );
6457//.. else
6458//.. assign( tmpL, binop(mkpair, mkexpr(gsrc), mkexpr(esrc)) );
6459//..
6460//.. assign( tmpRes, unop(getres, binop(shift, mkexpr(tmpL), mkexpr(tmpSH)) ) );
6461//.. assign( tmpSubSh,
6462//.. unop(getres,
6463//.. binop(shift,
6464//.. mkexpr(tmpL),
6465//.. binop(Iop_And8,
6466//.. binop(Iop_Sub8, mkexpr(tmpSH), mkU8(1) ),
6467//.. mask))) );
6468//..
6469//.. setFlags_DEP1_DEP2_shift ( left_shift ? Iop_Shl32 : Iop_Sar32,
6470//.. tmpRes, tmpSubSh, ty, tmpSH );
6471//..
6472//.. /* Put result back. */
6473//..
6474//.. if (epartIsReg(modrm)) {
6475//.. putIReg(sz, eregOfRM(modrm), mkexpr(tmpRes));
6476//.. } else {
6477//.. storeLE( mkexpr(addr), mkexpr(tmpRes) );
6478//.. }
6479//..
6480//.. if (amt_is_literal) delta++;
6481//.. return delta;
6482//.. }
sewardj9ed16802005-08-24 10:46:19 +00006483
6484
6485/* Handle BT/BTS/BTR/BTC Gv, Ev. Apparently b-size is not
6486 required. */
6487
6488typedef enum { BtOpNone, BtOpSet, BtOpReset, BtOpComp } BtOp;
6489
6490static HChar* nameBtOp ( BtOp op )
6491{
6492 switch (op) {
6493 case BtOpNone: return "";
6494 case BtOpSet: return "s";
6495 case BtOpReset: return "r";
6496 case BtOpComp: return "c";
6497 default: vpanic("nameBtOp(amd64)");
6498 }
6499}
6500
6501
6502static
6503ULong dis_bt_G_E ( Prefix pfx, Int sz, Long delta, BtOp op )
6504{
6505 HChar dis_buf[50];
6506 UChar modrm;
6507 Int len;
6508 IRTemp t_fetched, t_bitno0, t_bitno1, t_bitno2, t_addr0,
6509 t_addr1, t_rsp, t_mask;
6510
6511 vassert(sz == 2 || sz == 4 || sz == 8);
6512
6513 t_fetched = t_bitno0 = t_bitno1 = t_bitno2
6514 = t_addr0 = t_addr1 = t_rsp = t_mask = IRTemp_INVALID;
6515
6516 t_fetched = newTemp(Ity_I8);
6517 t_bitno0 = newTemp(Ity_I64);
6518 t_bitno1 = newTemp(Ity_I64);
6519 t_bitno2 = newTemp(Ity_I8);
6520 t_addr1 = newTemp(Ity_I64);
6521 modrm = getUChar(delta);
6522
6523 assign( t_bitno0, widenSto64(getIRegG(sz, pfx, modrm)) );
6524
6525 if (epartIsReg(modrm)) {
6526 delta++;
6527 /* Get it onto the client's stack. */
6528 t_rsp = newTemp(Ity_I64);
6529 t_addr0 = newTemp(Ity_I64);
6530
6531 assign( t_rsp, binop(Iop_Sub64, getIReg64(R_RSP), mkU64(sz)) );
6532 putIReg64(R_RSP, mkexpr(t_rsp));
6533
6534 storeLE( mkexpr(t_rsp), getIRegE(sz, pfx, modrm) );
6535
6536 /* Make t_addr0 point at it. */
6537 assign( t_addr0, mkexpr(t_rsp) );
6538
6539 /* Mask out upper bits of the shift amount, since we're doing a
6540 reg. */
6541 assign( t_bitno1, binop(Iop_And64,
6542 mkexpr(t_bitno0),
6543 mkU64(sz == 8 ? 63 : sz == 4 ? 31 : 15)) );
6544
6545 } else {
6546 t_addr0 = disAMode ( &len, pfx, delta, dis_buf, 0 );
6547 delta += len;
6548 assign( t_bitno1, mkexpr(t_bitno0) );
6549 }
6550
6551 /* At this point: t_addr0 is the address being operated on. If it
6552 was a reg, we will have pushed it onto the client's stack.
6553 t_bitno1 is the bit number, suitably masked in the case of a
6554 reg. */
6555
6556 /* Now the main sequence. */
6557 assign( t_addr1,
6558 binop(Iop_Add64,
6559 mkexpr(t_addr0),
6560 binop(Iop_Sar64, mkexpr(t_bitno1), mkU8(3))) );
6561
6562 /* t_addr1 now holds effective address */
6563
6564 assign( t_bitno2,
6565 unop(Iop_64to8,
6566 binop(Iop_And64, mkexpr(t_bitno1), mkU64(7))) );
6567
6568 /* t_bitno2 contains offset of bit within byte */
6569
6570 if (op != BtOpNone) {
6571 t_mask = newTemp(Ity_I8);
6572 assign( t_mask, binop(Iop_Shl8, mkU8(1), mkexpr(t_bitno2)) );
6573 }
6574
6575 /* t_mask is now a suitable byte mask */
6576
6577 assign( t_fetched, loadLE(Ity_I8, mkexpr(t_addr1)) );
6578
6579 if (op != BtOpNone) {
6580 switch (op) {
6581 case BtOpSet:
6582 storeLE( mkexpr(t_addr1),
6583 binop(Iop_Or8, mkexpr(t_fetched),
6584 mkexpr(t_mask)) );
6585 break;
6586 case BtOpComp:
6587 storeLE( mkexpr(t_addr1),
6588 binop(Iop_Xor8, mkexpr(t_fetched),
6589 mkexpr(t_mask)) );
6590 break;
6591 case BtOpReset:
6592 storeLE( mkexpr(t_addr1),
6593 binop(Iop_And8, mkexpr(t_fetched),
6594 unop(Iop_Not8, mkexpr(t_mask))) );
6595 break;
6596 default:
6597 vpanic("dis_bt_G_E(amd64)");
6598 }
6599 }
6600
6601 /* Side effect done; now get selected bit into Carry flag */
6602 /* Flags: C=selected bit, O,S,Z,A,P undefined, so are set to zero. */
6603 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(AMD64G_CC_OP_COPY) ));
6604 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
6605 stmt( IRStmt_Put(
6606 OFFB_CC_DEP1,
6607 binop(Iop_And64,
6608 binop(Iop_Shr64,
6609 unop(Iop_8Uto64, mkexpr(t_fetched)),
6610 mkexpr(t_bitno2)),
6611 mkU64(1)))
6612 );
6613 /* Set NDEP even though it isn't used. This makes redundant-PUT
6614 elimination of previous stores to this field work better. */
6615 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU64(0) ));
6616
6617 /* Move reg operand from stack back to reg */
6618 if (epartIsReg(modrm)) {
6619 /* t_esp still points at it. */
6620 putIRegE(sz, pfx, modrm, loadLE(szToITy(sz), mkexpr(t_rsp)) );
6621 putIReg64(R_RSP, binop(Iop_Add64, mkexpr(t_rsp), mkU64(sz)) );
6622 }
6623
6624 DIP("bt%s%c %s, %s\n",
6625 nameBtOp(op), nameISize(sz), nameIRegG(sz, pfx, modrm),
6626 ( epartIsReg(modrm) ? nameIRegE(sz, pfx, modrm) : dis_buf ) );
6627
6628 return delta;
6629}
sewardjf53b7352005-04-06 20:01:56 +00006630
6631
6632
6633/* Handle BSF/BSR. Only v-size seems necessary. */
6634static
sewardj270def42005-07-03 01:03:01 +00006635ULong dis_bs_E_G ( Prefix pfx, Int sz, Long delta, Bool fwds )
sewardjf53b7352005-04-06 20:01:56 +00006636{
6637 Bool isReg;
6638 UChar modrm;
6639 HChar dis_buf[50];
6640
6641 IRType ty = szToITy(sz);
6642 IRTemp src = newTemp(ty);
6643 IRTemp dst = newTemp(ty);
6644 IRTemp src64 = newTemp(Ity_I64);
6645 IRTemp dst64 = newTemp(Ity_I64);
6646 IRTemp src8 = newTemp(Ity_I8);
6647
6648 vassert(sz == 8 || sz == 4 || sz == 2);
6649
6650 modrm = getUChar(delta);
6651 isReg = epartIsReg(modrm);
6652 if (isReg) {
6653 delta++;
6654 assign( src, getIRegE(sz, pfx, modrm) );
6655 } else {
6656 Int len;
6657 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
6658 delta += len;
6659 assign( src, loadLE(ty, mkexpr(addr)) );
6660 }
6661
6662 DIP("bs%c%c %s, %s\n",
6663 fwds ? 'f' : 'r', nameISize(sz),
6664 ( isReg ? nameIRegE(sz, pfx, modrm) : dis_buf ),
6665 nameIRegG(sz, pfx, modrm));
6666
6667 /* First, widen src to 64 bits if it is not already. */
6668 assign( src64, widenUto64(mkexpr(src)) );
6669
6670 /* Generate an 8-bit expression which is zero iff the
6671 original is zero, and nonzero otherwise */
6672 assign( src8,
6673 unop(Iop_1Uto8,
6674 binop(Iop_CmpNE64,
6675 mkexpr(src64), mkU64(0))) );
6676
6677 /* Flags: Z is 1 iff source value is zero. All others
6678 are undefined -- we force them to zero. */
6679 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(AMD64G_CC_OP_COPY) ));
6680 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
6681 stmt( IRStmt_Put(
6682 OFFB_CC_DEP1,
6683 IRExpr_Mux0X( mkexpr(src8),
6684 /* src==0 */
6685 mkU64(AMD64G_CC_MASK_Z),
6686 /* src!=0 */
6687 mkU64(0)
6688 )
6689 ));
6690 /* Set NDEP even though it isn't used. This makes redundant-PUT
6691 elimination of previous stores to this field work better. */
6692 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU64(0) ));
6693
6694 /* Result: iff source value is zero, we can't use
6695 Iop_Clz64/Iop_Ctz64 as they have no defined result in that case.
6696 But anyway, amd64 semantics say the result is undefined in
6697 such situations. Hence handle the zero case specially. */
6698
6699 /* Bleh. What we compute:
6700
6701 bsf64: if src == 0 then {dst is unchanged}
6702 else Ctz64(src)
6703
6704 bsr64: if src == 0 then {dst is unchanged}
6705 else 63 - Clz64(src)
6706
6707 bsf32: if src == 0 then {dst is unchanged}
6708 else Ctz64(32Uto64(src))
6709
6710 bsr32: if src == 0 then {dst is unchanged}
6711 else 63 - Clz64(32Uto64(src))
6712
6713 bsf16: if src == 0 then {dst is unchanged}
6714 else Ctz64(32Uto64(16Uto32(src)))
6715
6716 bsr16: if src == 0 then {dst is unchanged}
6717 else 63 - Clz64(32Uto64(16Uto32(src)))
6718 */
6719
6720 /* The main computation, guarding against zero. */
6721 assign( dst64,
6722 IRExpr_Mux0X(
6723 mkexpr(src8),
6724 /* src == 0 -- leave dst unchanged */
6725 widenUto64( getIRegG( sz, pfx, modrm ) ),
6726 /* src != 0 */
6727 fwds ? unop(Iop_Ctz64, mkexpr(src64))
6728 : binop(Iop_Sub64,
6729 mkU64(63),
6730 unop(Iop_Clz64, mkexpr(src64)))
6731 )
6732 );
6733
6734 if (sz == 2)
sewardje58967e2005-04-27 11:50:56 +00006735 assign( dst, unop(Iop_64to16, mkexpr(dst64)) );
sewardjf53b7352005-04-06 20:01:56 +00006736 else
6737 if (sz == 4)
6738 assign( dst, unop(Iop_64to32, mkexpr(dst64)) );
6739 else
6740 assign( dst, mkexpr(dst64) );
6741
6742 /* dump result back */
6743 putIRegG( sz, pfx, modrm, mkexpr(dst) );
6744
6745 return delta;
6746}
sewardja6b93d12005-02-17 09:28:28 +00006747
6748
6749/* swap rAX with the reg specified by reg and REX.B */
6750static
sewardj5b470602005-02-27 13:10:48 +00006751void codegen_xchg_rAX_Reg ( Prefix pfx, Int sz, UInt regLo3 )
sewardja6b93d12005-02-17 09:28:28 +00006752{
6753 IRType ty = szToITy(sz);
6754 IRTemp t1 = newTemp(ty);
6755 IRTemp t2 = newTemp(ty);
sewardj2d4fcd52005-05-18 11:47:47 +00006756 vassert(sz == 4 || sz == 8);
sewardj5b470602005-02-27 13:10:48 +00006757 vassert(regLo3 < 8);
sewardj2d4fcd52005-05-18 11:47:47 +00006758 if (sz == 8) {
6759 assign( t1, getIReg64(R_RAX) );
6760 assign( t2, getIRegRexB(8, pfx, regLo3) );
6761 putIReg64( R_RAX, mkexpr(t2) );
6762 putIRegRexB(8, pfx, regLo3, mkexpr(t1) );
6763 } else {
6764 assign( t1, getIReg32(R_RAX) );
6765 assign( t2, getIRegRexB(4, pfx, regLo3) );
6766 putIReg32( R_RAX, mkexpr(t2) );
6767 putIRegRexB(4, pfx, regLo3, mkexpr(t1) );
6768 }
sewardja6b93d12005-02-17 09:28:28 +00006769 DIP("xchg%c %s, %s\n",
sewardj5b470602005-02-27 13:10:48 +00006770 nameISize(sz), nameIRegRAX(sz),
sewardj2d4fcd52005-05-18 11:47:47 +00006771 nameIRegRexB(sz,pfx, regLo3));
sewardja6b93d12005-02-17 09:28:28 +00006772}
6773
6774
sewardjd20c8852005-01-20 20:04:07 +00006775//.. static
6776//.. void codegen_SAHF ( void )
6777//.. {
6778//.. /* Set the flags to:
6779//.. (x86g_calculate_flags_all() & X86G_CC_MASK_O) -- retain the old O flag
6780//.. | (%AH & (X86G_CC_MASK_S|X86G_CC_MASK_Z|X86G_CC_MASK_A
6781//.. |X86G_CC_MASK_P|X86G_CC_MASK_C)
6782//.. */
6783//.. UInt mask_SZACP = X86G_CC_MASK_S|X86G_CC_MASK_Z|X86G_CC_MASK_A
6784//.. |X86G_CC_MASK_C|X86G_CC_MASK_P;
6785//.. IRTemp oldflags = newTemp(Ity_I32);
6786//.. assign( oldflags, mk_x86g_calculate_eflags_all() );
6787//.. stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
6788//.. stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
6789//.. stmt( IRStmt_Put( OFFB_CC_DEP1,
6790//.. binop(Iop_Or32,
6791//.. binop(Iop_And32, mkexpr(oldflags), mkU32(X86G_CC_MASK_O)),
6792//.. binop(Iop_And32,
6793//.. binop(Iop_Shr32, getIReg(4, R_EAX), mkU8(8)),
6794//.. mkU32(mask_SZACP))
6795//.. )
6796//.. ));
6797//.. }
6798//..
6799//..
6800//.. //-- static
6801//.. //-- void codegen_LAHF ( UCodeBlock* cb )
6802//.. //-- {
6803//.. //-- Int t = newTemp(cb);
6804//.. //--
6805//.. //-- /* Pushed arg is ignored, it just provides somewhere to put the
6806//.. //-- return value. */
6807//.. //-- uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, t);
6808//.. //-- uInstr0(cb, CALLM_S, 0);
6809//.. //-- uInstr1(cb, PUSH, 4, TempReg, t);
6810//.. //-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_LAHF));
6811//.. //-- uFlagsRWU(cb, FlagsSZACP, FlagsEmpty, FlagsEmpty);
6812//.. //-- uInstr1(cb, POP, 4, TempReg, t);
6813//.. //-- uInstr0(cb, CALLM_E, 0);
6814//.. //--
6815//.. //-- /* At this point, the %ah sub-register in %eax has been updated,
6816//.. //-- the rest is the same, so do a PUT of the whole thing. */
6817//.. //-- uInstr2(cb, PUT, 4, TempReg, t, ArchReg, R_EAX);
6818//.. //-- }
6819//.. //--
sewardja6b93d12005-02-17 09:28:28 +00006820
6821static
6822ULong dis_cmpxchg_G_E ( Prefix pfx,
6823 Int size,
sewardj270def42005-07-03 01:03:01 +00006824 Long delta0 )
sewardja6b93d12005-02-17 09:28:28 +00006825{
6826 HChar dis_buf[50];
6827 Int len;
6828
6829 IRType ty = szToITy(size);
6830 IRTemp acc = newTemp(ty);
6831 IRTemp src = newTemp(ty);
6832 IRTemp dest = newTemp(ty);
6833 IRTemp dest2 = newTemp(ty);
6834 IRTemp acc2 = newTemp(ty);
6835 IRTemp cond8 = newTemp(Ity_I8);
6836 IRTemp addr = IRTemp_INVALID;
6837 UChar rm = getUChar(delta0);
6838
6839 if (epartIsReg(rm)) {
sewardj5b470602005-02-27 13:10:48 +00006840 vassert(0); /* awaiting test case */
6841 assign( dest, getIRegE(size, pfx, rm) );
sewardja6b93d12005-02-17 09:28:28 +00006842 delta0++;
6843 DIP("cmpxchg%c %s,%s\n", nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00006844 nameIRegG(size,pfx,rm),
6845 nameIRegE(size,pfx,rm) );
sewardja6b93d12005-02-17 09:28:28 +00006846 } else {
6847 addr = disAMode ( &len, pfx, delta0, dis_buf, 0 );
6848 assign( dest, loadLE(ty, mkexpr(addr)) );
6849 delta0 += len;
6850 DIP("cmpxchg%c %s,%s\n", nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00006851 nameIRegG(size,pfx,rm), dis_buf);
sewardja6b93d12005-02-17 09:28:28 +00006852 }
6853
sewardj5b470602005-02-27 13:10:48 +00006854 assign( src, getIRegG(size, pfx, rm) );
6855 assign( acc, getIRegRAX(size) );
sewardja6b93d12005-02-17 09:28:28 +00006856 setFlags_DEP1_DEP2(Iop_Sub8, acc, dest, ty);
6857 assign( cond8, unop(Iop_1Uto8, mk_amd64g_calculate_condition(AMD64CondZ)) );
6858 assign( dest2, IRExpr_Mux0X(mkexpr(cond8), mkexpr(dest), mkexpr(src)) );
6859 assign( acc2, IRExpr_Mux0X(mkexpr(cond8), mkexpr(dest), mkexpr(acc)) );
sewardj5b470602005-02-27 13:10:48 +00006860 putIRegRAX(size, mkexpr(acc2));
sewardja6b93d12005-02-17 09:28:28 +00006861
6862 if (epartIsReg(rm)) {
sewardj5b470602005-02-27 13:10:48 +00006863 putIRegE(size, pfx, rm, mkexpr(dest2));
sewardja6b93d12005-02-17 09:28:28 +00006864 } else {
6865 storeLE( mkexpr(addr), mkexpr(dest2) );
6866 }
6867
6868 return delta0;
6869}
6870
6871
sewardjd20c8852005-01-20 20:04:07 +00006872//.. //-- static
6873//.. //-- Addr dis_cmpxchg8b ( UCodeBlock* cb,
6874//.. //-- UChar sorb,
6875//.. //-- Addr eip0 )
6876//.. //-- {
6877//.. //-- Int tal, tah, junkl, junkh, destl, desth, srcl, srch, accl, acch;
6878//.. //-- HChar dis_buf[50];
6879//.. //-- UChar rm;
6880//.. //-- UInt pair;
6881//.. //--
6882//.. //-- rm = getUChar(eip0);
6883//.. //-- accl = newTemp(cb);
6884//.. //-- acch = newTemp(cb);
6885//.. //-- srcl = newTemp(cb);
6886//.. //-- srch = newTemp(cb);
6887//.. //-- destl = newTemp(cb);
6888//.. //-- desth = newTemp(cb);
6889//.. //-- junkl = newTemp(cb);
6890//.. //-- junkh = newTemp(cb);
6891//.. //--
6892//.. //-- vg_assert(!epartIsReg(rm));
6893//.. //--
6894//.. //-- pair = disAMode ( cb, sorb, eip0, dis_buf );
6895//.. //-- tal = LOW24(pair);
6896//.. //-- tah = newTemp(cb);
6897//.. //-- uInstr2(cb, MOV, 4, TempReg, tal, TempReg, tah);
6898//.. //-- uInstr2(cb, ADD, 4, Literal, 0, TempReg, tah);
6899//.. //-- uLiteral(cb, 4);
6900//.. //-- eip0 += HI8(pair);
6901//.. //-- DIP("cmpxchg8b %s\n", dis_buf);
6902//.. //--
6903//.. //-- uInstr0(cb, CALLM_S, 0);
6904//.. //--
6905//.. //-- uInstr2(cb, LOAD, 4, TempReg, tah, TempReg, desth);
6906//.. //-- uInstr1(cb, PUSH, 4, TempReg, desth);
6907//.. //-- uInstr2(cb, LOAD, 4, TempReg, tal, TempReg, destl);
6908//.. //-- uInstr1(cb, PUSH, 4, TempReg, destl);
6909//.. //-- uInstr2(cb, GET, 4, ArchReg, R_ECX, TempReg, srch);
6910//.. //-- uInstr1(cb, PUSH, 4, TempReg, srch);
6911//.. //-- uInstr2(cb, GET, 4, ArchReg, R_EBX, TempReg, srcl);
6912//.. //-- uInstr1(cb, PUSH, 4, TempReg, srcl);
6913//.. //-- uInstr2(cb, GET, 4, ArchReg, R_EDX, TempReg, acch);
6914//.. //-- uInstr1(cb, PUSH, 4, TempReg, acch);
6915//.. //-- uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, accl);
6916//.. //-- uInstr1(cb, PUSH, 4, TempReg, accl);
6917//.. //--
6918//.. //-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_cmpxchg8b));
6919//.. //-- uFlagsRWU(cb, FlagsEmpty, FlagZ, FlagsEmpty);
6920//.. //--
6921//.. //-- uInstr1(cb, POP, 4, TempReg, accl);
6922//.. //-- uInstr2(cb, PUT, 4, TempReg, accl, ArchReg, R_EAX);
6923//.. //-- uInstr1(cb, POP, 4, TempReg, acch);
6924//.. //-- uInstr2(cb, PUT, 4, TempReg, acch, ArchReg, R_EDX);
6925//.. //-- uInstr1(cb, POP, 4, TempReg, srcl);
6926//.. //-- uInstr2(cb, PUT, 4, TempReg, srcl, ArchReg, R_EBX);
6927//.. //-- uInstr1(cb, POP, 4, TempReg, srch);
6928//.. //-- uInstr2(cb, PUT, 4, TempReg, srch, ArchReg, R_ECX);
6929//.. //-- uInstr1(cb, POP, 4, TempReg, destl);
6930//.. //-- uInstr2(cb, STORE, 4, TempReg, destl, TempReg, tal);
6931//.. //-- uInstr1(cb, POP, 4, TempReg, desth);
6932//.. //-- uInstr2(cb, STORE, 4, TempReg, desth, TempReg, tah);
6933//.. //--
6934//.. //-- uInstr0(cb, CALLM_E, 0);
6935//.. //--
6936//.. //-- return eip0;
6937//.. //-- }
sewardj3ca55a12005-01-27 16:06:23 +00006938
6939
6940/* Handle conditional move instructions of the form
6941 cmovcc E(reg-or-mem), G(reg)
6942
6943 E(src) is reg-or-mem
6944 G(dst) is reg.
6945
6946 If E is reg, --> GET %E, tmps
6947 GET %G, tmpd
6948 CMOVcc tmps, tmpd
6949 PUT tmpd, %G
6950
6951 If E is mem --> (getAddr E) -> tmpa
6952 LD (tmpa), tmps
6953 GET %G, tmpd
6954 CMOVcc tmps, tmpd
6955 PUT tmpd, %G
6956*/
6957static
6958ULong dis_cmov_E_G ( Prefix pfx,
6959 Int sz,
6960 AMD64Condcode cond,
sewardj270def42005-07-03 01:03:01 +00006961 Long delta0 )
sewardj3ca55a12005-01-27 16:06:23 +00006962{
sewardj8c332e22005-01-28 01:36:56 +00006963 UChar rm = getUChar(delta0);
sewardj3ca55a12005-01-27 16:06:23 +00006964 HChar dis_buf[50];
6965 Int len;
6966
6967 IRType ty = szToITy(sz);
6968 IRTemp tmps = newTemp(ty);
6969 IRTemp tmpd = newTemp(ty);
6970
6971 if (epartIsReg(rm)) {
sewardj5b470602005-02-27 13:10:48 +00006972 assign( tmps, getIRegE(sz, pfx, rm) );
6973 assign( tmpd, getIRegG(sz, pfx, rm) );
sewardj3ca55a12005-01-27 16:06:23 +00006974
sewardj5b470602005-02-27 13:10:48 +00006975 putIRegG( sz, pfx, rm,
sewardj3ca55a12005-01-27 16:06:23 +00006976 IRExpr_Mux0X( unop(Iop_1Uto8,
6977 mk_amd64g_calculate_condition(cond)),
6978 mkexpr(tmpd),
6979 mkexpr(tmps) )
6980 );
sewardje941eea2005-01-30 19:52:28 +00006981 DIP("cmov%s %s,%s\n", name_AMD64Condcode(cond),
sewardj5b470602005-02-27 13:10:48 +00006982 nameIRegE(sz,pfx,rm),
6983 nameIRegG(sz,pfx,rm));
sewardj3ca55a12005-01-27 16:06:23 +00006984 return 1+delta0;
6985 }
6986
6987 /* E refers to memory */
6988 {
sewardje1698952005-02-08 15:02:39 +00006989 IRTemp addr = disAMode ( &len, pfx, delta0, dis_buf, 0 );
sewardj3ca55a12005-01-27 16:06:23 +00006990 assign( tmps, loadLE(ty, mkexpr(addr)) );
sewardj5b470602005-02-27 13:10:48 +00006991 assign( tmpd, getIRegG(sz, pfx, rm) );
sewardj3ca55a12005-01-27 16:06:23 +00006992
sewardj5b470602005-02-27 13:10:48 +00006993 putIRegG( sz, pfx, rm,
sewardj3ca55a12005-01-27 16:06:23 +00006994 IRExpr_Mux0X( unop(Iop_1Uto8,
6995 mk_amd64g_calculate_condition(cond)),
6996 mkexpr(tmpd),
6997 mkexpr(tmps) )
6998 );
6999
sewardj7eaa7cf2005-01-31 18:55:22 +00007000 DIP("cmov%s %s,%s\n", name_AMD64Condcode(cond),
7001 dis_buf,
sewardj5b470602005-02-27 13:10:48 +00007002 nameIRegG(sz,pfx,rm));
sewardj3ca55a12005-01-27 16:06:23 +00007003 return len+delta0;
7004 }
7005}
7006
7007
sewardjb4fd2e72005-03-23 13:34:11 +00007008static
7009ULong dis_xadd_G_E ( /*OUT*/Bool* decode_ok,
sewardj270def42005-07-03 01:03:01 +00007010 Prefix pfx, Int sz, Long delta0 )
sewardjb4fd2e72005-03-23 13:34:11 +00007011{
7012 Int len;
7013 UChar rm = getUChar(delta0);
7014 HChar dis_buf[50];
7015
7016 IRType ty = szToITy(sz);
7017 IRTemp tmpd = newTemp(ty);
7018 IRTemp tmpt0 = newTemp(ty);
7019 IRTemp tmpt1 = newTemp(ty);
7020 *decode_ok = True;
7021
7022 if (epartIsReg(rm)) {
7023 *decode_ok = False;
7024 return delta0;
7025 } else {
7026 IRTemp addr = disAMode ( &len, pfx, delta0, dis_buf, 0 );
7027 assign( tmpd, loadLE(ty, mkexpr(addr)) );
7028 assign( tmpt0, getIRegG(sz, pfx, rm) );
7029 assign( tmpt1, binop(mkSizedOp(ty,Iop_Add8), mkexpr(tmpd), mkexpr(tmpt0)) );
7030 setFlags_DEP1_DEP2( Iop_Add8, tmpd, tmpt0, ty );
7031 storeLE( mkexpr(addr), mkexpr(tmpt1) );
7032 putIRegG(sz, pfx, rm, mkexpr(tmpd));
7033 DIP("xadd%c %s, %s\n",
7034 nameISize(sz), nameIRegG(sz,pfx,rm), dis_buf);
7035 return len+delta0;
7036 }
7037}
7038
sewardjd20c8852005-01-20 20:04:07 +00007039//.. /* Move 16 bits from Ew (ireg or mem) to G (a segment register). */
7040//..
7041//.. static
sewardj270def42005-07-03 01:03:01 +00007042//.. UInt dis_mov_Ew_Sw ( UChar sorb, Long delta0 )
sewardjd20c8852005-01-20 20:04:07 +00007043//.. {
7044//.. Int len;
7045//.. IRTemp addr;
sewardj8c332e22005-01-28 01:36:56 +00007046//.. UChar rm = getUChar(delta0);
sewardjd20c8852005-01-20 20:04:07 +00007047//.. HChar dis_buf[50];
7048//..
7049//.. if (epartIsReg(rm)) {
7050//.. putSReg( gregOfRM(rm), getIReg(2, eregOfRM(rm)) );
7051//.. DIP("movw %s,%s\n", nameIReg(2,eregOfRM(rm)), nameSReg(gregOfRM(rm)));
7052//.. return 1+delta0;
7053//.. } else {
7054//.. addr = disAMode ( &len, sorb, delta0, dis_buf );
7055//.. putSReg( gregOfRM(rm), loadLE(Ity_I16, mkexpr(addr)) );
7056//.. DIP("movw %s,%s\n", dis_buf, nameSReg(gregOfRM(rm)));
7057//.. return len+delta0;
7058//.. }
7059//.. }
7060//..
7061//.. /* Move 16 bits from G (a segment register) to Ew (ireg or mem). If
7062//.. dst is ireg and sz==4, zero out top half of it. */
7063//..
7064//.. static
7065//.. UInt dis_mov_Sw_Ew ( UChar sorb,
7066//.. Int sz,
7067//.. UInt delta0 )
7068//.. {
7069//.. Int len;
7070//.. IRTemp addr;
sewardj8c332e22005-01-28 01:36:56 +00007071//.. UChar rm = getUChar(delta0);
sewardjd20c8852005-01-20 20:04:07 +00007072//.. HChar dis_buf[50];
7073//..
7074//.. vassert(sz == 2 || sz == 4);
7075//..
7076//.. if (epartIsReg(rm)) {
7077//.. if (sz == 4)
7078//.. putIReg(4, eregOfRM(rm), unop(Iop_16Uto32, getSReg(gregOfRM(rm))));
7079//.. else
7080//.. putIReg(2, eregOfRM(rm), getSReg(gregOfRM(rm)));
7081//..
7082//.. DIP("mov %s,%s\n", nameSReg(gregOfRM(rm)), nameIReg(sz,eregOfRM(rm)));
7083//.. return 1+delta0;
7084//.. } else {
7085//.. addr = disAMode ( &len, sorb, delta0, dis_buf );
7086//.. storeLE( mkexpr(addr), getSReg(gregOfRM(rm)) );
7087//.. DIP("mov %s,%s\n", nameSReg(gregOfRM(rm)), dis_buf);
7088//.. return len+delta0;
7089//.. }
7090//.. }
7091//..
7092//..
7093//.. static
7094//.. void dis_push_segreg ( UInt sreg, Int sz )
7095//.. {
7096//.. IRTemp t1 = newTemp(Ity_I16);
7097//.. IRTemp ta = newTemp(Ity_I32);
7098//.. vassert(sz == 2 || sz == 4);
7099//..
7100//.. assign( t1, getSReg(sreg) );
7101//.. assign( ta, binop(Iop_Sub32, getIReg(4, R_ESP), mkU32(sz)) );
7102//.. putIReg(4, R_ESP, mkexpr(ta));
7103//.. storeLE( mkexpr(ta), mkexpr(t1) );
7104//..
7105//.. DIP("pushw %s\n", nameSReg(sreg));
7106//.. }
7107//..
7108//.. static
7109//.. void dis_pop_segreg ( UInt sreg, Int sz )
7110//.. {
7111//.. IRTemp t1 = newTemp(Ity_I16);
7112//.. IRTemp ta = newTemp(Ity_I32);
7113//.. vassert(sz == 2 || sz == 4);
7114//..
7115//.. assign( ta, getIReg(4, R_ESP) );
7116//.. assign( t1, loadLE(Ity_I16, mkexpr(ta)) );
7117//..
7118//.. putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(ta), mkU32(sz)) );
7119//.. putSReg( sreg, mkexpr(t1) );
7120//.. DIP("pop %s\n", nameSReg(sreg));
7121//.. }
sewardj2f959cc2005-01-26 01:19:35 +00007122
7123static
7124void dis_ret ( ULong d64 )
7125{
7126 IRTemp t1 = newTemp(Ity_I64);
7127 IRTemp t2 = newTemp(Ity_I64);
sewardj5a9ffab2005-05-12 17:55:01 +00007128 IRTemp t3 = newTemp(Ity_I64);
sewardj2f959cc2005-01-26 01:19:35 +00007129 assign(t1, getIReg64(R_RSP));
7130 assign(t2, loadLE(Ity_I64,mkexpr(t1)));
sewardj5a9ffab2005-05-12 17:55:01 +00007131 assign(t3, binop(Iop_Add64, mkexpr(t1), mkU64(8+d64)));
7132 putIReg64(R_RSP, mkexpr(t3));
7133 make_redzone_AbiHint(t3, "ret");
sewardj2f959cc2005-01-26 01:19:35 +00007134 jmp_treg(Ijk_Ret,t2);
7135}
7136
sewardj5b470602005-02-27 13:10:48 +00007137
sewardj1001dc42005-02-21 08:25:55 +00007138/*------------------------------------------------------------*/
7139/*--- SSE/SSE2/SSE3 helpers ---*/
7140/*------------------------------------------------------------*/
7141
7142/* Worker function; do not call directly.
7143 Handles full width G = G `op` E and G = (not G) `op` E.
7144*/
7145
sewardj8d965312005-02-25 02:48:47 +00007146static ULong dis_SSE_E_to_G_all_wrk (
sewardj270def42005-07-03 01:03:01 +00007147 Prefix pfx, Long delta,
sewardj8d965312005-02-25 02:48:47 +00007148 HChar* opname, IROp op,
7149 Bool invertG
7150 )
sewardj9da16972005-02-21 13:58:26 +00007151{
7152 HChar dis_buf[50];
7153 Int alen;
7154 IRTemp addr;
7155 UChar rm = getUChar(delta);
7156 IRExpr* gpart
7157 = invertG ? unop(Iop_NotV128, getXMMReg(gregOfRexRM(pfx,rm)))
7158 : getXMMReg(gregOfRexRM(pfx,rm));
7159 if (epartIsReg(rm)) {
7160 putXMMReg( gregOfRexRM(pfx,rm),
7161 binop(op, gpart,
7162 getXMMReg(eregOfRexRM(pfx,rm))) );
7163 DIP("%s %s,%s\n", opname,
7164 nameXMMReg(eregOfRexRM(pfx,rm)),
7165 nameXMMReg(gregOfRexRM(pfx,rm)) );
7166 return delta+1;
7167 } else {
7168 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
7169 putXMMReg( gregOfRexRM(pfx,rm),
7170 binop(op, gpart,
7171 loadLE(Ity_V128, mkexpr(addr))) );
7172 DIP("%s %s,%s\n", opname,
7173 dis_buf,
7174 nameXMMReg(gregOfRexRM(pfx,rm)) );
7175 return delta+alen;
7176 }
7177}
7178
7179
7180/* All lanes SSE binary operation, G = G `op` E. */
7181
7182static
sewardj270def42005-07-03 01:03:01 +00007183ULong dis_SSE_E_to_G_all ( Prefix pfx, Long delta,
sewardj8d965312005-02-25 02:48:47 +00007184 HChar* opname, IROp op )
sewardj9da16972005-02-21 13:58:26 +00007185{
7186 return dis_SSE_E_to_G_all_wrk( pfx, delta, opname, op, False );
7187}
7188
sewardj8d965312005-02-25 02:48:47 +00007189/* All lanes SSE binary operation, G = (not G) `op` E. */
7190
7191static
sewardj270def42005-07-03 01:03:01 +00007192ULong dis_SSE_E_to_G_all_invG ( Prefix pfx, Long delta,
sewardj8d965312005-02-25 02:48:47 +00007193 HChar* opname, IROp op )
7194{
7195 return dis_SSE_E_to_G_all_wrk( pfx, delta, opname, op, True );
7196}
7197
7198
7199/* Lowest 32-bit lane only SSE binary operation, G = G `op` E. */
7200
sewardj270def42005-07-03 01:03:01 +00007201static ULong dis_SSE_E_to_G_lo32 ( Prefix pfx, Long delta,
sewardj8d965312005-02-25 02:48:47 +00007202 HChar* opname, IROp op )
7203{
7204 HChar dis_buf[50];
7205 Int alen;
7206 IRTemp addr;
7207 UChar rm = getUChar(delta);
sewardj9c9ee3d2005-02-26 01:17:42 +00007208 IRExpr* gpart = getXMMReg(gregOfRexRM(pfx,rm));
sewardj8d965312005-02-25 02:48:47 +00007209 if (epartIsReg(rm)) {
sewardj9c9ee3d2005-02-26 01:17:42 +00007210 putXMMReg( gregOfRexRM(pfx,rm),
sewardj8d965312005-02-25 02:48:47 +00007211 binop(op, gpart,
7212 getXMMReg(eregOfRexRM(pfx,rm))) );
7213 DIP("%s %s,%s\n", opname,
7214 nameXMMReg(eregOfRexRM(pfx,rm)),
7215 nameXMMReg(gregOfRexRM(pfx,rm)) );
7216 return delta+1;
7217 } else {
7218 /* We can only do a 32-bit memory read, so the upper 3/4 of the
7219 E operand needs to be made simply of zeroes. */
7220 IRTemp epart = newTemp(Ity_V128);
7221 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
7222 assign( epart, unop( Iop_32UtoV128,
7223 loadLE(Ity_I32, mkexpr(addr))) );
7224 putXMMReg( gregOfRexRM(pfx,rm),
7225 binop(op, gpart, mkexpr(epart)) );
7226 DIP("%s %s,%s\n", opname,
7227 dis_buf,
7228 nameXMMReg(gregOfRexRM(pfx,rm)) );
7229 return delta+alen;
7230 }
7231}
sewardj1001dc42005-02-21 08:25:55 +00007232
7233
7234/* Lower 64-bit lane only SSE binary operation, G = G `op` E. */
7235
sewardj270def42005-07-03 01:03:01 +00007236static ULong dis_SSE_E_to_G_lo64 ( Prefix pfx, Long delta,
sewardj8d965312005-02-25 02:48:47 +00007237 HChar* opname, IROp op )
sewardj1001dc42005-02-21 08:25:55 +00007238{
7239 HChar dis_buf[50];
7240 Int alen;
7241 IRTemp addr;
7242 UChar rm = getUChar(delta);
7243 IRExpr* gpart = getXMMReg(gregOfRexRM(pfx,rm));
7244 if (epartIsReg(rm)) {
7245 putXMMReg( gregOfRexRM(pfx,rm),
7246 binop(op, gpart,
7247 getXMMReg(eregOfRexRM(pfx,rm))) );
7248 DIP("%s %s,%s\n", opname,
7249 nameXMMReg(eregOfRexRM(pfx,rm)),
7250 nameXMMReg(gregOfRexRM(pfx,rm)) );
7251 return delta+1;
7252 } else {
7253 /* We can only do a 64-bit memory read, so the upper half of the
7254 E operand needs to be made simply of zeroes. */
7255 IRTemp epart = newTemp(Ity_V128);
7256 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
7257 assign( epart, unop( Iop_64UtoV128,
7258 loadLE(Ity_I64, mkexpr(addr))) );
7259 putXMMReg( gregOfRexRM(pfx,rm),
7260 binop(op, gpart, mkexpr(epart)) );
7261 DIP("%s %s,%s\n", opname,
7262 dis_buf,
7263 nameXMMReg(gregOfRexRM(pfx,rm)) );
7264 return delta+alen;
7265 }
7266}
7267
7268
sewardja7ba8c42005-05-10 20:08:34 +00007269/* All lanes unary SSE operation, G = op(E). */
7270
7271static ULong dis_SSE_E_to_G_unary_all (
sewardj270def42005-07-03 01:03:01 +00007272 Prefix pfx, Long delta,
sewardja7ba8c42005-05-10 20:08:34 +00007273 HChar* opname, IROp op
7274 )
7275{
7276 HChar dis_buf[50];
7277 Int alen;
7278 IRTemp addr;
7279 UChar rm = getUChar(delta);
7280 if (epartIsReg(rm)) {
7281 putXMMReg( gregOfRexRM(pfx,rm),
7282 unop(op, getXMMReg(eregOfRexRM(pfx,rm))) );
7283 DIP("%s %s,%s\n", opname,
7284 nameXMMReg(eregOfRexRM(pfx,rm)),
7285 nameXMMReg(gregOfRexRM(pfx,rm)) );
7286 return delta+1;
7287 } else {
7288 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
7289 putXMMReg( gregOfRexRM(pfx,rm),
7290 unop(op, loadLE(Ity_V128, mkexpr(addr))) );
7291 DIP("%s %s,%s\n", opname,
7292 dis_buf,
7293 nameXMMReg(gregOfRexRM(pfx,rm)) );
7294 return delta+alen;
7295 }
7296}
7297
7298
7299/* Lowest 32-bit lane only unary SSE operation, G = op(E). */
7300
7301static ULong dis_SSE_E_to_G_unary_lo32 (
sewardj270def42005-07-03 01:03:01 +00007302 Prefix pfx, Long delta,
sewardja7ba8c42005-05-10 20:08:34 +00007303 HChar* opname, IROp op
7304 )
7305{
7306 /* First we need to get the old G value and patch the low 32 bits
7307 of the E operand into it. Then apply op and write back to G. */
7308 HChar dis_buf[50];
7309 Int alen;
7310 IRTemp addr;
7311 UChar rm = getUChar(delta);
7312 IRTemp oldG0 = newTemp(Ity_V128);
7313 IRTemp oldG1 = newTemp(Ity_V128);
7314
7315 assign( oldG0, getXMMReg(gregOfRexRM(pfx,rm)) );
7316
7317 if (epartIsReg(rm)) {
7318 assign( oldG1,
7319 binop( Iop_SetV128lo32,
7320 mkexpr(oldG0),
7321 getXMMRegLane32(eregOfRexRM(pfx,rm), 0)) );
7322 putXMMReg( gregOfRexRM(pfx,rm), unop(op, mkexpr(oldG1)) );
7323 DIP("%s %s,%s\n", opname,
7324 nameXMMReg(eregOfRexRM(pfx,rm)),
7325 nameXMMReg(gregOfRexRM(pfx,rm)) );
7326 return delta+1;
7327 } else {
7328 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
7329 assign( oldG1,
7330 binop( Iop_SetV128lo32,
7331 mkexpr(oldG0),
7332 loadLE(Ity_I32, mkexpr(addr)) ));
7333 putXMMReg( gregOfRexRM(pfx,rm), unop(op, mkexpr(oldG1)) );
7334 DIP("%s %s,%s\n", opname,
7335 dis_buf,
7336 nameXMMReg(gregOfRexRM(pfx,rm)) );
7337 return delta+alen;
7338 }
7339}
sewardj1001dc42005-02-21 08:25:55 +00007340
7341
7342/* Lowest 64-bit lane only unary SSE operation, G = op(E). */
7343
sewardj8d965312005-02-25 02:48:47 +00007344static ULong dis_SSE_E_to_G_unary_lo64 (
sewardj270def42005-07-03 01:03:01 +00007345 Prefix pfx, Long delta,
sewardj8d965312005-02-25 02:48:47 +00007346 HChar* opname, IROp op
7347 )
sewardj1001dc42005-02-21 08:25:55 +00007348{
7349 /* First we need to get the old G value and patch the low 64 bits
7350 of the E operand into it. Then apply op and write back to G. */
7351 HChar dis_buf[50];
7352 Int alen;
7353 IRTemp addr;
7354 UChar rm = getUChar(delta);
7355 IRTemp oldG0 = newTemp(Ity_V128);
7356 IRTemp oldG1 = newTemp(Ity_V128);
7357
7358 assign( oldG0, getXMMReg(gregOfRexRM(pfx,rm)) );
7359
7360 if (epartIsReg(rm)) {
7361 assign( oldG1,
7362 binop( Iop_SetV128lo64,
7363 mkexpr(oldG0),
7364 getXMMRegLane64(eregOfRexRM(pfx,rm), 0)) );
7365 putXMMReg( gregOfRexRM(pfx,rm), unop(op, mkexpr(oldG1)) );
7366 DIP("%s %s,%s\n", opname,
7367 nameXMMReg(eregOfRexRM(pfx,rm)),
7368 nameXMMReg(gregOfRexRM(pfx,rm)) );
7369 return delta+1;
7370 } else {
7371 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
7372 assign( oldG1,
7373 binop( Iop_SetV128lo64,
7374 mkexpr(oldG0),
7375 loadLE(Ity_I64, mkexpr(addr)) ));
7376 putXMMReg( gregOfRexRM(pfx,rm), unop(op, mkexpr(oldG1)) );
7377 DIP("%s %s,%s\n", opname,
7378 dis_buf,
7379 nameXMMReg(gregOfRexRM(pfx,rm)) );
7380 return delta+alen;
7381 }
7382}
7383
7384
sewardj09717342005-05-05 21:34:02 +00007385/* SSE integer binary operation:
7386 G = G `op` E (eLeft == False)
7387 G = E `op` G (eLeft == True)
7388*/
7389static ULong dis_SSEint_E_to_G(
sewardj270def42005-07-03 01:03:01 +00007390 Prefix pfx, Long delta,
sewardj09717342005-05-05 21:34:02 +00007391 HChar* opname, IROp op,
7392 Bool eLeft
7393 )
7394{
7395 HChar dis_buf[50];
7396 Int alen;
7397 IRTemp addr;
7398 UChar rm = getUChar(delta);
7399 IRExpr* gpart = getXMMReg(gregOfRexRM(pfx,rm));
7400 IRExpr* epart = NULL;
7401 if (epartIsReg(rm)) {
7402 epart = getXMMReg(eregOfRexRM(pfx,rm));
7403 DIP("%s %s,%s\n", opname,
7404 nameXMMReg(eregOfRexRM(pfx,rm)),
7405 nameXMMReg(gregOfRexRM(pfx,rm)) );
7406 delta += 1;
7407 } else {
7408 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
7409 epart = loadLE(Ity_V128, mkexpr(addr));
7410 DIP("%s %s,%s\n", opname,
7411 dis_buf,
7412 nameXMMReg(gregOfRexRM(pfx,rm)) );
7413 delta += alen;
7414 }
7415 putXMMReg( gregOfRexRM(pfx,rm),
7416 eLeft ? binop(op, epart, gpart)
7417 : binop(op, gpart, epart) );
7418 return delta;
7419}
sewardj8d965312005-02-25 02:48:47 +00007420
7421
7422/* Helper for doing SSE FP comparisons. */
7423
7424static void findSSECmpOp ( Bool* needNot, IROp* op,
7425 Int imm8, Bool all_lanes, Int sz )
7426{
7427 imm8 &= 7;
7428 *needNot = False;
7429 *op = Iop_INVALID;
7430 if (imm8 >= 4) {
7431 *needNot = True;
7432 imm8 -= 4;
7433 }
7434
7435 if (sz == 4 && all_lanes) {
7436 switch (imm8) {
7437 case 0: *op = Iop_CmpEQ32Fx4; return;
7438 case 1: *op = Iop_CmpLT32Fx4; return;
7439 case 2: *op = Iop_CmpLE32Fx4; return;
7440 case 3: *op = Iop_CmpUN32Fx4; return;
7441 default: break;
7442 }
7443 }
7444 if (sz == 4 && !all_lanes) {
7445 switch (imm8) {
7446 case 0: *op = Iop_CmpEQ32F0x4; return;
7447 case 1: *op = Iop_CmpLT32F0x4; return;
7448 case 2: *op = Iop_CmpLE32F0x4; return;
7449 case 3: *op = Iop_CmpUN32F0x4; return;
7450 default: break;
7451 }
7452 }
7453 if (sz == 8 && all_lanes) {
7454 switch (imm8) {
7455 case 0: *op = Iop_CmpEQ64Fx2; return;
7456 case 1: *op = Iop_CmpLT64Fx2; return;
7457 case 2: *op = Iop_CmpLE64Fx2; return;
7458 case 3: *op = Iop_CmpUN64Fx2; return;
7459 default: break;
7460 }
7461 }
7462 if (sz == 8 && !all_lanes) {
7463 switch (imm8) {
7464 case 0: *op = Iop_CmpEQ64F0x2; return;
7465 case 1: *op = Iop_CmpLT64F0x2; return;
7466 case 2: *op = Iop_CmpLE64F0x2; return;
7467 case 3: *op = Iop_CmpUN64F0x2; return;
7468 default: break;
7469 }
7470 }
7471 vpanic("findSSECmpOp(amd64,guest)");
7472}
7473
7474/* Handles SSE 32F comparisons. */
7475
sewardj270def42005-07-03 01:03:01 +00007476static ULong dis_SSEcmp_E_to_G ( Prefix pfx, Long delta,
sewardj8d965312005-02-25 02:48:47 +00007477 HChar* opname, Bool all_lanes, Int sz )
7478{
7479 HChar dis_buf[50];
7480 Int alen, imm8;
7481 IRTemp addr;
7482 Bool needNot = False;
7483 IROp op = Iop_INVALID;
7484 IRTemp plain = newTemp(Ity_V128);
7485 UChar rm = getUChar(delta);
7486 UShort mask = 0;
7487 vassert(sz == 4 || sz == 8);
7488 if (epartIsReg(rm)) {
7489 imm8 = getUChar(delta+1);
7490 findSSECmpOp(&needNot, &op, imm8, all_lanes, sz);
7491 assign( plain, binop(op, getXMMReg(gregOfRexRM(pfx,rm)),
7492 getXMMReg(eregOfRexRM(pfx,rm))) );
7493 delta += 2;
7494 DIP("%s $%d,%s,%s\n", opname,
7495 (Int)imm8,
7496 nameXMMReg(eregOfRexRM(pfx,rm)),
7497 nameXMMReg(gregOfRexRM(pfx,rm)) );
7498 } else {
7499 addr = disAMode ( &alen, pfx, delta, dis_buf, 1 );
7500 imm8 = getUChar(delta+alen);
7501 findSSECmpOp(&needNot, &op, imm8, all_lanes, sz);
7502 assign( plain, binop(op, getXMMReg(gregOfRexRM(pfx,rm)),
7503 loadLE(Ity_V128, mkexpr(addr))) );
7504 delta += alen+1;
7505 DIP("%s $%d,%s,%s\n", opname,
7506 (Int)imm8,
7507 dis_buf,
7508 nameXMMReg(gregOfRexRM(pfx,rm)) );
7509 }
7510
7511 if (needNot && all_lanes) {
sewardj9c9ee3d2005-02-26 01:17:42 +00007512 putXMMReg( gregOfRexRM(pfx,rm),
sewardj8d965312005-02-25 02:48:47 +00007513 unop(Iop_NotV128, mkexpr(plain)) );
7514 }
7515 else
7516 if (needNot && !all_lanes) {
sewardj1027dc22005-02-26 01:55:02 +00007517 mask = toUShort(sz==4 ? 0x000F : 0x00FF);
sewardj8d965312005-02-25 02:48:47 +00007518 putXMMReg( gregOfRexRM(pfx,rm),
7519 binop(Iop_XorV128, mkexpr(plain), mkV128(mask)) );
7520 }
7521 else {
7522 putXMMReg( gregOfRexRM(pfx,rm), mkexpr(plain) );
7523 }
7524
7525 return delta;
7526}
7527
7528
sewardjadffcef2005-05-11 00:03:06 +00007529/* Vector by scalar shift of G by the amount specified at the bottom
7530 of E. */
7531
sewardj270def42005-07-03 01:03:01 +00007532static ULong dis_SSE_shiftG_byE ( Prefix pfx, Long delta,
sewardjadffcef2005-05-11 00:03:06 +00007533 HChar* opname, IROp op )
7534{
7535 HChar dis_buf[50];
7536 Int alen, size;
7537 IRTemp addr;
7538 Bool shl, shr, sar;
7539 UChar rm = getUChar(delta);
7540 IRTemp g0 = newTemp(Ity_V128);
7541 IRTemp g1 = newTemp(Ity_V128);
7542 IRTemp amt = newTemp(Ity_I32);
7543 IRTemp amt8 = newTemp(Ity_I8);
7544 if (epartIsReg(rm)) {
7545 assign( amt, getXMMRegLane32(eregOfRexRM(pfx,rm), 0) );
7546 DIP("%s %s,%s\n", opname,
7547 nameXMMReg(eregOfRexRM(pfx,rm)),
7548 nameXMMReg(gregOfRexRM(pfx,rm)) );
7549 delta++;
7550 } else {
7551 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
7552 assign( amt, loadLE(Ity_I32, mkexpr(addr)) );
7553 DIP("%s %s,%s\n", opname,
7554 dis_buf,
7555 nameXMMReg(gregOfRexRM(pfx,rm)) );
7556 delta += alen;
7557 }
7558 assign( g0, getXMMReg(gregOfRexRM(pfx,rm)) );
7559 assign( amt8, unop(Iop_32to8, mkexpr(amt)) );
7560
7561 shl = shr = sar = False;
7562 size = 0;
7563 switch (op) {
7564 case Iop_ShlN16x8: shl = True; size = 32; break;
7565 case Iop_ShlN32x4: shl = True; size = 32; break;
7566 case Iop_ShlN64x2: shl = True; size = 64; break;
7567 case Iop_SarN16x8: sar = True; size = 16; break;
7568 case Iop_SarN32x4: sar = True; size = 32; break;
7569 case Iop_ShrN16x8: shr = True; size = 16; break;
7570 case Iop_ShrN32x4: shr = True; size = 32; break;
7571 case Iop_ShrN64x2: shr = True; size = 64; break;
7572 default: vassert(0);
7573 }
7574
7575 if (shl || shr) {
7576 assign(
7577 g1,
7578 IRExpr_Mux0X(
7579 unop(Iop_1Uto8,
7580 binop(Iop_CmpLT64U, unop(Iop_32Uto64,mkexpr(amt)), mkU64(size))),
7581 mkV128(0x0000),
7582 binop(op, mkexpr(g0), mkexpr(amt8))
7583 )
7584 );
7585 } else
7586 if (sar) {
7587 assign(
7588 g1,
7589 IRExpr_Mux0X(
7590 unop(Iop_1Uto8,
7591 binop(Iop_CmpLT64U, unop(Iop_32Uto64,mkexpr(amt)), mkU64(size))),
7592 binop(op, mkexpr(g0), mkU8(size-1)),
7593 binop(op, mkexpr(g0), mkexpr(amt8))
7594 )
7595 );
7596 } else {
7597 vassert(0);
7598 }
7599
7600 putXMMReg( gregOfRexRM(pfx,rm), mkexpr(g1) );
7601 return delta;
7602}
sewardj09717342005-05-05 21:34:02 +00007603
7604
7605/* Vector by scalar shift of E by an immediate byte. */
7606
7607static
7608ULong dis_SSE_shiftE_imm ( Prefix pfx,
sewardj270def42005-07-03 01:03:01 +00007609 Long delta, HChar* opname, IROp op )
sewardj09717342005-05-05 21:34:02 +00007610{
7611 Bool shl, shr, sar;
7612 UChar rm = getUChar(delta);
7613 IRTemp e0 = newTemp(Ity_V128);
7614 IRTemp e1 = newTemp(Ity_V128);
7615 UChar amt, size;
7616 vassert(epartIsReg(rm));
7617 vassert(gregLO3ofRM(rm) == 2
7618 || gregLO3ofRM(rm) == 4 || gregLO3ofRM(rm) == 6);
sewardjca673ab2005-05-11 10:03:08 +00007619 amt = getUChar(delta+1);
sewardj09717342005-05-05 21:34:02 +00007620 delta += 2;
7621 DIP("%s $%d,%s\n", opname,
7622 (Int)amt,
7623 nameXMMReg(eregOfRexRM(pfx,rm)) );
7624 assign( e0, getXMMReg(eregOfRexRM(pfx,rm)) );
7625
7626 shl = shr = sar = False;
7627 size = 0;
7628 switch (op) {
7629 case Iop_ShlN16x8: shl = True; size = 16; break;
7630 case Iop_ShlN32x4: shl = True; size = 32; break;
7631 case Iop_ShlN64x2: shl = True; size = 64; break;
7632 case Iop_SarN16x8: sar = True; size = 16; break;
7633 case Iop_SarN32x4: sar = True; size = 32; break;
7634 case Iop_ShrN16x8: shr = True; size = 16; break;
7635 case Iop_ShrN32x4: shr = True; size = 32; break;
7636 case Iop_ShrN64x2: shr = True; size = 64; break;
7637 default: vassert(0);
7638 }
7639
7640 if (shl || shr) {
7641 assign( e1, amt >= size
7642 ? mkV128(0x0000)
7643 : binop(op, mkexpr(e0), mkU8(amt))
7644 );
7645 } else
7646 if (sar) {
7647 assign( e1, amt >= size
7648 ? binop(op, mkexpr(e0), mkU8(size-1))
7649 : binop(op, mkexpr(e0), mkU8(amt))
7650 );
7651 } else {
7652 vassert(0);
7653 }
7654
7655 putXMMReg( eregOfRexRM(pfx,rm), mkexpr(e1) );
7656 return delta;
7657}
sewardj1a01e652005-02-23 11:39:21 +00007658
7659
7660/* Get the current SSE rounding mode. */
7661
7662static IRExpr* /* :: Ity_I32 */ get_sse_roundingmode ( void )
7663{
7664 return
7665 unop( Iop_64to32,
7666 binop( Iop_And64,
7667 IRExpr_Get( OFFB_SSEROUND, Ity_I64 ),
7668 mkU64(3) ));
7669}
7670
sewardjbcbb9de2005-03-27 02:22:32 +00007671static void put_sse_roundingmode ( IRExpr* sseround )
7672{
7673 vassert(typeOfIRExpr(irbb->tyenv, sseround) == Ity_I32);
7674 stmt( IRStmt_Put( OFFB_SSEROUND,
7675 unop(Iop_32Uto64,sseround) ) );
7676}
7677
sewardja7ba8c42005-05-10 20:08:34 +00007678/* Break a 128-bit value up into four 32-bit ints. */
7679
7680static void breakup128to32s ( IRTemp t128,
7681 /*OUTs*/
7682 IRTemp* t3, IRTemp* t2,
7683 IRTemp* t1, IRTemp* t0 )
7684{
7685 IRTemp hi64 = newTemp(Ity_I64);
7686 IRTemp lo64 = newTemp(Ity_I64);
7687 assign( hi64, unop(Iop_V128HIto64, mkexpr(t128)) );
7688 assign( lo64, unop(Iop_V128to64, mkexpr(t128)) );
7689
7690 vassert(t0 && *t0 == IRTemp_INVALID);
7691 vassert(t1 && *t1 == IRTemp_INVALID);
7692 vassert(t2 && *t2 == IRTemp_INVALID);
7693 vassert(t3 && *t3 == IRTemp_INVALID);
7694
7695 *t0 = newTemp(Ity_I32);
7696 *t1 = newTemp(Ity_I32);
7697 *t2 = newTemp(Ity_I32);
7698 *t3 = newTemp(Ity_I32);
7699 assign( *t0, unop(Iop_64to32, mkexpr(lo64)) );
7700 assign( *t1, unop(Iop_64HIto32, mkexpr(lo64)) );
7701 assign( *t2, unop(Iop_64to32, mkexpr(hi64)) );
7702 assign( *t3, unop(Iop_64HIto32, mkexpr(hi64)) );
7703}
7704
7705/* Construct a 128-bit value from four 32-bit ints. */
7706
7707static IRExpr* mk128from32s ( IRTemp t3, IRTemp t2,
7708 IRTemp t1, IRTemp t0 )
7709{
7710 return
7711 binop( Iop_64HLtoV128,
7712 binop(Iop_32HLto64, mkexpr(t3), mkexpr(t2)),
7713 binop(Iop_32HLto64, mkexpr(t1), mkexpr(t0))
7714 );
7715}
7716
7717/* Break a 64-bit value up into four 16-bit ints. */
7718
7719static void breakup64to16s ( IRTemp t64,
7720 /*OUTs*/
7721 IRTemp* t3, IRTemp* t2,
7722 IRTemp* t1, IRTemp* t0 )
7723{
7724 IRTemp hi32 = newTemp(Ity_I32);
7725 IRTemp lo32 = newTemp(Ity_I32);
7726 assign( hi32, unop(Iop_64HIto32, mkexpr(t64)) );
7727 assign( lo32, unop(Iop_64to32, mkexpr(t64)) );
7728
7729 vassert(t0 && *t0 == IRTemp_INVALID);
7730 vassert(t1 && *t1 == IRTemp_INVALID);
7731 vassert(t2 && *t2 == IRTemp_INVALID);
7732 vassert(t3 && *t3 == IRTemp_INVALID);
7733
7734 *t0 = newTemp(Ity_I16);
7735 *t1 = newTemp(Ity_I16);
7736 *t2 = newTemp(Ity_I16);
7737 *t3 = newTemp(Ity_I16);
7738 assign( *t0, unop(Iop_32to16, mkexpr(lo32)) );
7739 assign( *t1, unop(Iop_32HIto16, mkexpr(lo32)) );
7740 assign( *t2, unop(Iop_32to16, mkexpr(hi32)) );
7741 assign( *t3, unop(Iop_32HIto16, mkexpr(hi32)) );
7742}
7743
7744/* Construct a 64-bit value from four 16-bit ints. */
7745
7746static IRExpr* mk64from16s ( IRTemp t3, IRTemp t2,
7747 IRTemp t1, IRTemp t0 )
7748{
7749 return
7750 binop( Iop_32HLto64,
7751 binop(Iop_16HLto32, mkexpr(t3), mkexpr(t2)),
7752 binop(Iop_16HLto32, mkexpr(t1), mkexpr(t0))
7753 );
7754}
sewardjdf0e0022005-01-25 15:48:43 +00007755
7756
7757/*------------------------------------------------------------*/
7758/*--- Disassemble a single instruction ---*/
7759/*------------------------------------------------------------*/
7760
sewardj9e6491a2005-07-02 19:24:10 +00007761/* Disassemble a single instruction into IR. The instruction is
7762 located in host memory at &guest_code[delta]. */
sewardjdf0e0022005-01-25 15:48:43 +00007763
sewardj9e6491a2005-07-02 19:24:10 +00007764static
7765DisResult disInstr_AMD64_WRK (
7766 Bool put_IP,
7767 Bool (*resteerOkFn) ( Addr64 ),
7768 Long delta64,
7769 VexArchInfo* archinfo
7770 )
sewardjdf0e0022005-01-25 15:48:43 +00007771{
7772 IRType ty;
sewardja7ba8c42005-05-10 20:08:34 +00007773 IRTemp addr, t0, t1, t2, t3, t4, t5, t6;
sewardjdf0e0022005-01-25 15:48:43 +00007774 Int alen;
sewardj7a240552005-01-28 21:37:12 +00007775 UChar opc, modrm, /*abyte,*/ pre;
sewardj1027dc22005-02-26 01:55:02 +00007776 Long d64;
sewardjdf0e0022005-01-25 15:48:43 +00007777 HChar dis_buf[50];
7778 Int am_sz, d_sz, n, n_prefixes;
sewardj9e6491a2005-07-02 19:24:10 +00007779 DisResult dres;
sewardja6b93d12005-02-17 09:28:28 +00007780 UChar* insn; /* used in SSE decoders */
sewardjdf0e0022005-01-25 15:48:43 +00007781
sewardj9e6491a2005-07-02 19:24:10 +00007782 /* The running delta */
7783 Long delta = delta64;
7784
sewardjdf0e0022005-01-25 15:48:43 +00007785 /* Holds eip at the start of the insn, so that we can print
7786 consistent error messages for unimplemented insns. */
sewardj270def42005-07-03 01:03:01 +00007787 Long delta_start = delta;
sewardjdf0e0022005-01-25 15:48:43 +00007788
7789 /* sz denotes the nominal data-op size of the insn; we change it to
7790 2 if an 0x66 prefix is seen and 8 if REX.W is 1. In case of
7791 conflict REX.W takes precedence. */
7792 Int sz = 4;
7793
sewardj3ca55a12005-01-27 16:06:23 +00007794 /* pfx holds the summary of prefixes. */
7795 Prefix pfx = PFX_EMPTY;
sewardjdf0e0022005-01-25 15:48:43 +00007796
sewardj9e6491a2005-07-02 19:24:10 +00007797 /* Set result defaults. */
7798 dres.whatNext = Dis_Continue;
7799 dres.len = 0;
7800 dres.continueAt = 0;
sewardjdf0e0022005-01-25 15:48:43 +00007801
sewardj9e6491a2005-07-02 19:24:10 +00007802 vassert(guest_RIP_next_assumed == 0);
7803 vassert(guest_RIP_next_mustcheck == False);
sewardj4b744762005-02-07 15:02:25 +00007804
sewardja7ba8c42005-05-10 20:08:34 +00007805 addr = t0 = t1 = t2 = t3 = t4 = t5 = t6 = IRTemp_INVALID;
sewardjdf0e0022005-01-25 15:48:43 +00007806
sewardj9e6491a2005-07-02 19:24:10 +00007807 DIP("\t0x%llx: ", guest_RIP_bbstart+delta);
7808
7809 /* We may be asked to update the guest RIP before going further. */
7810 if (put_IP)
7811 stmt( IRStmt_Put( OFFB_RIP, mkU64(guest_RIP_curr_instr)) );
sewardjdf0e0022005-01-25 15:48:43 +00007812
7813 /* Spot the client-request magic sequence. */
7814 {
7815 UChar* code = (UChar*)(guest_code + delta);
7816 /* Spot this:
7817 C1C01D roll $29, %eax
7818 C1C003 roll $3, %eax
7819 C1C81B rorl $27, %eax
7820 C1C805 rorl $5, %eax
7821 C1C00D roll $13, %eax
7822 C1C013 roll $19, %eax
7823 */
7824 if (code[ 0] == 0xC1 && code[ 1] == 0xC0 && code[ 2] == 0x1D &&
7825 code[ 3] == 0xC1 && code[ 4] == 0xC0 && code[ 5] == 0x03 &&
7826 code[ 6] == 0xC1 && code[ 7] == 0xC8 && code[ 8] == 0x1B &&
7827 code[ 9] == 0xC1 && code[10] == 0xC8 && code[11] == 0x05 &&
7828 code[12] == 0xC1 && code[13] == 0xC0 && code[14] == 0x0D &&
7829 code[15] == 0xC1 && code[16] == 0xC0 && code[17] == 0x13
7830 ) {
7831 DIP("%%edx = client_request ( %%eax )\n");
7832 delta += 18;
sewardj9e6491a2005-07-02 19:24:10 +00007833 jmp_lit(Ijk_ClientReq, guest_RIP_bbstart+delta);
7834 dres.whatNext = Dis_StopHere;
sewardjdf0e0022005-01-25 15:48:43 +00007835 goto decode_success;
7836 }
7837 }
7838
7839 /* Eat prefixes, summarising the result in pfx and sz, and rejecting
7840 as many invalid combinations as possible. */
7841 n_prefixes = 0;
7842 while (True) {
7843 if (n_prefixes > 5) goto decode_failure;
sewardj8c332e22005-01-28 01:36:56 +00007844 pre = getUChar(delta);
sewardjdf0e0022005-01-25 15:48:43 +00007845 switch (pre) {
7846 case 0x66: pfx |= PFX_66; break;
7847 case 0x67: pfx |= PFX_ASO; break;
7848 case 0xF2: pfx |= PFX_F2; break;
7849 case 0xF3: pfx |= PFX_F3; break;
7850 case 0xF0: pfx |= PFX_LOCK; break;
7851 case 0x2E: pfx |= PFX_CS; break;
7852 case 0x3E: pfx |= PFX_DS; break;
7853 case 0x26: pfx |= PFX_ES; break;
7854 case 0x64: pfx |= PFX_FS; break;
7855 case 0x65: pfx |= PFX_GS; break;
7856 case 0x36: pfx |= PFX_SS; break;
7857 case 0x40 ... 0x4F:
7858 pfx |= PFX_REX;
7859 if (pre & (1<<3)) pfx |= PFX_REXW;
7860 if (pre & (1<<2)) pfx |= PFX_REXR;
7861 if (pre & (1<<1)) pfx |= PFX_REXX;
7862 if (pre & (1<<0)) pfx |= PFX_REXB;
7863 break;
7864 default:
7865 goto not_a_prefix;
7866 }
7867 n_prefixes++;
7868 delta++;
7869 }
7870
7871 not_a_prefix:
7872 /* Dump invalid combinations */
sewardj3ca55a12005-01-27 16:06:23 +00007873 if (pfx & PFX_ASO)
7874 goto decode_failure; /* don't support address-size override */
sewardjdf0e0022005-01-25 15:48:43 +00007875
7876 n = 0;
7877 if (pfx & PFX_F2) n++;
7878 if (pfx & PFX_F3) n++;
sewardj3ca55a12005-01-27 16:06:23 +00007879 if (n > 1)
7880 goto decode_failure; /* can't have both */
sewardjdf0e0022005-01-25 15:48:43 +00007881
7882 n = 0;
7883 if (pfx & PFX_CS) n++;
7884 if (pfx & PFX_DS) n++;
7885 if (pfx & PFX_ES) n++;
7886 if (pfx & PFX_FS) n++;
7887 if (pfx & PFX_GS) n++;
7888 if (pfx & PFX_SS) n++;
sewardj3ca55a12005-01-27 16:06:23 +00007889 if (n > 1)
7890 goto decode_failure; /* multiple seg overrides == illegal */
sewardjdf0e0022005-01-25 15:48:43 +00007891
7892 /* Set up sz. */
7893 sz = 4;
7894 if (pfx & PFX_66) sz = 2;
7895 if ((pfx & PFX_REX) && (pfx & PFX_REXW)) sz = 8;
7896
sewardj9ff93bc2005-03-23 11:25:12 +00007897 /* Kludge re LOCK prefixes. We assume here that all code generated
7898 by Vex is going to be run in a single-threaded context, in other
7899 words that concurrent executions of Vex-generated translations
7900 will not happen. That is certainly the case for how the
7901 Valgrind-3.0 code line uses Vex. Given that assumption, it
7902 seems safe to ignore LOCK prefixes since there will never be any
7903 other thread running at the same time as this one. However, at
7904 least emit a memory fence on the basis that it would at least be
7905 prudent to flush any memory transactions from this thread as far
7906 as possible down the memory hierarchy. */
7907 if (pfx & PFX_LOCK) {
7908 /* vex_printf("vex amd64->IR: ignoring LOCK prefix on: ");
7909 insn_verbose = True; */
7910 stmt( IRStmt_MFence() );
sewardjdf0e0022005-01-25 15:48:43 +00007911 }
7912
sewardja6b93d12005-02-17 09:28:28 +00007913
7914 /* ---------------------------------------------------- */
sewardj09717342005-05-05 21:34:02 +00007915 /* --- The SSE/SSE2 decoder. --- */
sewardja6b93d12005-02-17 09:28:28 +00007916 /* ---------------------------------------------------- */
7917
7918 /* What did I do to deserve SSE ? Perhaps I was really bad in a
7919 previous life? */
7920
sewardj09717342005-05-05 21:34:02 +00007921 /* Note, this doesn't handle SSE3 right now. All amd64s support
7922 SSE2 as a minimum so there is no point distinguishing SSE1 vs
7923 SSE2. */
7924
sewardja6b93d12005-02-17 09:28:28 +00007925 insn = (UChar*)&guest_code[delta];
7926
sewardjd20c8852005-01-20 20:04:07 +00007927//.. /* Treat fxsave specially. It should be doable even on an SSE0
7928//.. (Pentium-II class) CPU. Hence be prepared to handle it on
7929//.. any subarchitecture variant.
7930//.. */
7931//..
7932//.. /* 0F AE /0 = FXSAVE m512 -- write x87 and SSE state to memory */
7933//.. if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xAE
7934//.. && !epartIsReg(insn[2]) && gregOfRM(insn[2]) == 0) {
sewardj8c332e22005-01-28 01:36:56 +00007935//.. modrm = getUChar(delta+2);
sewardjd20c8852005-01-20 20:04:07 +00007936//.. vassert(sz == 4);
7937//.. vassert(!epartIsReg(modrm));
7938//..
7939//.. addr = disAMode ( &alen, sorb, delta+2, dis_buf );
7940//.. delta += 2+alen;
7941//..
7942//.. DIP("fxsave %s\n", dis_buf);
7943//..
7944//.. /* Uses dirty helper:
7945//.. void x86g_do_FXSAVE ( VexGuestX86State*, UInt ) */
7946//.. IRDirty* d = unsafeIRDirty_0_N (
7947//.. 0/*regparms*/,
7948//.. "x86g_dirtyhelper_FXSAVE",
7949//.. &x86g_dirtyhelper_FXSAVE,
7950//.. mkIRExprVec_1( mkexpr(addr) )
7951//.. );
7952//.. d->needsBBP = True;
7953//..
7954//.. /* declare we're writing memory */
7955//.. d->mFx = Ifx_Write;
7956//.. d->mAddr = mkexpr(addr);
7957//.. d->mSize = 512;
7958//..
7959//.. /* declare we're reading guest state */
7960//.. d->nFxState = 7;
7961//..
7962//.. d->fxState[0].fx = Ifx_Read;
7963//.. d->fxState[0].offset = OFFB_FTOP;
7964//.. d->fxState[0].size = sizeof(UInt);
7965//..
7966//.. d->fxState[1].fx = Ifx_Read;
7967//.. d->fxState[1].offset = OFFB_FPREGS;
7968//.. d->fxState[1].size = 8 * sizeof(ULong);
7969//..
7970//.. d->fxState[2].fx = Ifx_Read;
7971//.. d->fxState[2].offset = OFFB_FPTAGS;
7972//.. d->fxState[2].size = 8 * sizeof(UChar);
7973//..
7974//.. d->fxState[3].fx = Ifx_Read;
7975//.. d->fxState[3].offset = OFFB_FPROUND;
7976//.. d->fxState[3].size = sizeof(UInt);
7977//..
7978//.. d->fxState[4].fx = Ifx_Read;
7979//.. d->fxState[4].offset = OFFB_FC3210;
7980//.. d->fxState[4].size = sizeof(UInt);
7981//..
7982//.. d->fxState[5].fx = Ifx_Read;
7983//.. d->fxState[5].offset = OFFB_XMM0;
7984//.. d->fxState[5].size = 8 * sizeof(U128);
7985//..
7986//.. d->fxState[6].fx = Ifx_Read;
7987//.. d->fxState[6].offset = OFFB_SSEROUND;
7988//.. d->fxState[6].size = sizeof(UInt);
7989//..
7990//.. /* Be paranoid ... this assertion tries to ensure the 8 %xmm
7991//.. images are packed back-to-back. If not, the value of
7992//.. d->fxState[5].size is wrong. */
7993//.. vassert(16 == sizeof(U128));
7994//.. vassert(OFFB_XMM7 == (OFFB_XMM0 + 7 * 16));
7995//..
7996//.. stmt( IRStmt_Dirty(d) );
7997//..
7998//.. goto decode_success;
7999//.. }
8000//..
8001//.. /* ------ SSE decoder main ------ */
8002//..
8003//.. /* Skip parts of the decoder which don't apply given the stated
8004//.. guest subarchitecture. */
8005//.. if (subarch == VexSubArchX86_sse0)
8006//.. goto after_sse_decoders;
8007//..
8008//.. /* Otherwise we must be doing sse1 or sse2, so we can at least try
8009//.. for SSE1 here. */
sewardj432f8b62005-05-10 02:50:05 +00008010
8011 /* 0F 58 = ADDPS -- add 32Fx4 from R/M to R */
8012 if (haveNo66noF2noF3(pfx) && sz == 4
8013 && insn[0] == 0x0F && insn[1] == 0x58) {
8014 delta = dis_SSE_E_to_G_all( pfx, delta+2, "addps", Iop_Add32Fx4 );
8015 goto decode_success;
8016 }
sewardj8d965312005-02-25 02:48:47 +00008017
8018 /* F3 0F 58 = ADDSS -- add 32F0x4 from R/M to R */
8019 if (haveF3no66noF2(pfx) && sz == 4
8020 && insn[0] == 0x0F && insn[1] == 0x58) {
8021 delta = dis_SSE_E_to_G_lo32( pfx, delta+2, "addss", Iop_Add32F0x4 );
8022 goto decode_success;
8023 }
8024
sewardj3aba9eb2005-03-30 23:20:47 +00008025 /* 0F 55 = ANDNPS -- G = (not G) and E */
8026 if (haveNo66noF2noF3(pfx) && sz == 4
8027 && insn[0] == 0x0F && insn[1] == 0x55) {
8028 delta = dis_SSE_E_to_G_all_invG( pfx, delta+2, "andnps", Iop_AndV128 );
8029 goto decode_success;
8030 }
sewardj37d52572005-02-25 14:22:12 +00008031
8032 /* 0F 54 = ANDPS -- G = G and E */
8033 if (haveNo66noF2noF3(pfx) && sz == 4
8034 && insn[0] == 0x0F && insn[1] == 0x54) {
8035 delta = dis_SSE_E_to_G_all( pfx, delta+2, "andps", Iop_AndV128 );
8036 goto decode_success;
8037 }
8038
sewardj432f8b62005-05-10 02:50:05 +00008039 /* 0F C2 = CMPPS -- 32Fx4 comparison from R/M to R */
8040 if (haveNo66noF2noF3(pfx) && sz == 4
8041 && insn[0] == 0x0F && insn[1] == 0xC2) {
8042 delta = dis_SSEcmp_E_to_G( pfx, delta+2, "cmpps", True, 4 );
8043 goto decode_success;
8044 }
sewardj3aba9eb2005-03-30 23:20:47 +00008045
8046 /* F3 0F C2 = CMPSS -- 32F0x4 comparison from R/M to R */
8047 if (haveF3no66noF2(pfx) && sz == 4
8048 && insn[0] == 0x0F && insn[1] == 0xC2) {
8049 delta = dis_SSEcmp_E_to_G( pfx, delta+2, "cmpss", False, 4 );
8050 goto decode_success;
8051 }
sewardjc49ce232005-02-25 13:03:03 +00008052
8053 /* 0F 2F = COMISS -- 32F0x4 comparison G,E, and set ZCP */
8054 /* 0F 2E = UCOMISS -- 32F0x4 comparison G,E, and set ZCP */
8055 if (haveNo66noF2noF3(pfx) && sz == 4
8056 && insn[0] == 0x0F && (insn[1] == 0x2F || insn[1] == 0x2E)) {
8057 IRTemp argL = newTemp(Ity_F32);
8058 IRTemp argR = newTemp(Ity_F32);
8059 modrm = getUChar(delta+2);
8060 if (epartIsReg(modrm)) {
8061 assign( argR, getXMMRegLane32F( eregOfRexRM(pfx,modrm),
8062 0/*lowest lane*/ ) );
8063 delta += 2+1;
8064 DIP("%scomiss %s,%s\n", insn[1]==0x2E ? "u" : "",
8065 nameXMMReg(eregOfRexRM(pfx,modrm)),
8066 nameXMMReg(gregOfRexRM(pfx,modrm)) );
8067 } else {
8068 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8069 assign( argR, loadLE(Ity_F32, mkexpr(addr)) );
8070 delta += 2+alen;
8071 DIP("%scomiss %s,%s\n", insn[1]==0x2E ? "u" : "",
8072 dis_buf,
8073 nameXMMReg(gregOfRexRM(pfx,modrm)) );
8074 }
8075 assign( argL, getXMMRegLane32F( gregOfRexRM(pfx,modrm),
8076 0/*lowest lane*/ ) );
8077
8078 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(AMD64G_CC_OP_COPY) ));
8079 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
8080 stmt( IRStmt_Put(
8081 OFFB_CC_DEP1,
8082 binop( Iop_And64,
8083 unop( Iop_32Uto64,
8084 binop(Iop_CmpF64,
8085 unop(Iop_F32toF64,mkexpr(argL)),
8086 unop(Iop_F32toF64,mkexpr(argR)))),
8087 mkU64(0x45)
8088 )));
8089
8090 goto decode_success;
8091 }
8092
sewardj432f8b62005-05-10 02:50:05 +00008093 /* 0F 2A = CVTPI2PS -- convert 2 x I32 in mem/mmx to 2 x F32 in low
8094 half xmm */
8095 if (haveNo66noF2noF3(pfx) && sz == 4
8096 && insn[0] == 0x0F && insn[1] == 0x2A) {
8097 IRTemp arg64 = newTemp(Ity_I64);
8098 IRTemp rmode = newTemp(Ity_I32);
8099
8100 modrm = getUChar(delta+2);
8101 do_MMX_preamble();
8102 if (epartIsReg(modrm)) {
8103 assign( arg64, getMMXReg(eregLO3ofRM(modrm)) );
8104 delta += 2+1;
8105 DIP("cvtpi2ps %s,%s\n", nameMMXReg(eregLO3ofRM(modrm)),
8106 nameXMMReg(gregOfRexRM(pfx,modrm)));
8107 } else {
8108 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8109 assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
8110 delta += 2+alen;
8111 DIP("cvtpi2ps %s,%s\n", dis_buf,
8112 nameXMMReg(gregOfRexRM(pfx,modrm)) );
8113 }
8114
8115 assign( rmode, get_sse_roundingmode() );
8116
8117 putXMMRegLane32F(
8118 gregOfRexRM(pfx,modrm), 0,
8119 binop(Iop_F64toF32,
8120 mkexpr(rmode),
8121 unop(Iop_I32toF64,
8122 unop(Iop_64to32, mkexpr(arg64)) )) );
8123
8124 putXMMRegLane32F(
8125 gregOfRexRM(pfx,modrm), 1,
8126 binop(Iop_F64toF32,
8127 mkexpr(rmode),
8128 unop(Iop_I32toF64,
8129 unop(Iop_64HIto32, mkexpr(arg64)) )) );
8130
8131 goto decode_success;
8132 }
sewardj8d965312005-02-25 02:48:47 +00008133
8134 /* F3 0F 2A = CVTSI2SS
8135 -- sz==4: convert I32 in mem/ireg to F32 in low quarter xmm
8136 -- sz==8: convert I64 in mem/ireg to F32 in low quarter xmm */
8137 if (haveF3no66noF2(pfx) && (sz == 4 || sz == 8)
8138 && insn[0] == 0x0F && insn[1] == 0x2A) {
8139
8140 IRTemp rmode = newTemp(Ity_I32);
8141 assign( rmode, get_sse_roundingmode() );
8142 modrm = getUChar(delta+2);
8143
8144 if (sz == 4) {
8145 IRTemp arg32 = newTemp(Ity_I32);
8146 if (epartIsReg(modrm)) {
sewardj5b470602005-02-27 13:10:48 +00008147 assign( arg32, getIReg32(eregOfRexRM(pfx,modrm)) );
sewardj8d965312005-02-25 02:48:47 +00008148 delta += 2+1;
sewardj5b470602005-02-27 13:10:48 +00008149 DIP("cvtsi2ss %s,%s\n", nameIReg32(eregOfRexRM(pfx,modrm)),
sewardj8d965312005-02-25 02:48:47 +00008150 nameXMMReg(gregOfRexRM(pfx,modrm)));
8151 } else {
sewardj8d965312005-02-25 02:48:47 +00008152 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8153 assign( arg32, loadLE(Ity_I32, mkexpr(addr)) );
8154 delta += 2+alen;
8155 DIP("cvtsi2ss %s,%s\n", dis_buf,
8156 nameXMMReg(gregOfRexRM(pfx,modrm)) );
8157 }
8158 putXMMRegLane32F(
8159 gregOfRexRM(pfx,modrm), 0,
8160 binop(Iop_F64toF32,
8161 mkexpr(rmode),
8162 unop(Iop_I32toF64, mkexpr(arg32)) ) );
8163 } else {
8164 /* sz == 8 */
8165 IRTemp arg64 = newTemp(Ity_I64);
8166 if (epartIsReg(modrm)) {
sewardj5b470602005-02-27 13:10:48 +00008167 assign( arg64, getIReg64(eregOfRexRM(pfx,modrm)) );
sewardj8d965312005-02-25 02:48:47 +00008168 delta += 2+1;
sewardj5b470602005-02-27 13:10:48 +00008169 DIP("cvtsi2ssq %s,%s\n", nameIReg64(eregOfRexRM(pfx,modrm)),
sewardj8d965312005-02-25 02:48:47 +00008170 nameXMMReg(gregOfRexRM(pfx,modrm)));
8171 } else {
sewardj82c9f2f2005-03-02 16:05:13 +00008172 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8173 assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
8174 delta += 2+alen;
8175 DIP("cvtsi2ssq %s,%s\n", dis_buf,
8176 nameXMMReg(gregOfRexRM(pfx,modrm)) );
sewardj8d965312005-02-25 02:48:47 +00008177 }
8178 putXMMRegLane32F(
8179 gregOfRexRM(pfx,modrm), 0,
8180 binop(Iop_F64toF32,
8181 mkexpr(rmode),
8182 binop(Iop_I64toF64, mkexpr(rmode), mkexpr(arg64)) ) );
8183 }
8184
8185 goto decode_success;
8186 }
8187
sewardj432f8b62005-05-10 02:50:05 +00008188 /* 0F 2D = CVTPS2PI -- convert 2 x F32 in mem/low half xmm to 2 x
8189 I32 in mmx, according to prevailing SSE rounding mode */
sewardja7ba8c42005-05-10 20:08:34 +00008190 /* 0F 2C = CVTTPS2PI -- convert 2 x F32 in mem/low half xmm to 2 x
8191 I32 in mmx, rounding towards zero */
sewardj432f8b62005-05-10 02:50:05 +00008192 if (haveNo66noF2noF3(pfx) && sz == 4
sewardja7ba8c42005-05-10 20:08:34 +00008193 && insn[0] == 0x0F && (insn[1] == 0x2D || insn[1] == 0x2C)) {
sewardj432f8b62005-05-10 02:50:05 +00008194 IRTemp dst64 = newTemp(Ity_I64);
8195 IRTemp rmode = newTemp(Ity_I32);
8196 IRTemp f32lo = newTemp(Ity_F32);
8197 IRTemp f32hi = newTemp(Ity_F32);
8198 Bool r2zero = toBool(insn[1] == 0x2C);
8199
8200 do_MMX_preamble();
8201 modrm = getUChar(delta+2);
8202
8203 if (epartIsReg(modrm)) {
8204 delta += 2+1;
8205 assign(f32lo, getXMMRegLane32F(eregOfRexRM(pfx,modrm), 0));
8206 assign(f32hi, getXMMRegLane32F(eregOfRexRM(pfx,modrm), 1));
8207 DIP("cvt%sps2pi %s,%s\n", r2zero ? "t" : "",
8208 nameXMMReg(eregOfRexRM(pfx,modrm)),
8209 nameMMXReg(gregLO3ofRM(modrm)));
8210 } else {
8211 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8212 assign(f32lo, loadLE(Ity_F32, mkexpr(addr)));
8213 assign(f32hi, loadLE(Ity_F32, binop( Iop_Add64,
8214 mkexpr(addr),
8215 mkU64(4) )));
8216 delta += 2+alen;
8217 DIP("cvt%sps2pi %s,%s\n", r2zero ? "t" : "",
8218 dis_buf,
8219 nameMMXReg(gregLO3ofRM(modrm)));
8220 }
8221
8222 if (r2zero) {
8223 assign(rmode, mkU32((UInt)Irrm_ZERO) );
8224 } else {
8225 assign( rmode, get_sse_roundingmode() );
8226 }
8227
8228 assign(
8229 dst64,
8230 binop( Iop_32HLto64,
8231 binop( Iop_F64toI32,
8232 mkexpr(rmode),
8233 unop( Iop_F32toF64, mkexpr(f32hi) ) ),
8234 binop( Iop_F64toI32,
8235 mkexpr(rmode),
8236 unop( Iop_F32toF64, mkexpr(f32lo) ) )
8237 )
8238 );
8239
8240 putMMXReg(gregLO3ofRM(modrm), mkexpr(dst64));
8241 goto decode_success;
8242 }
8243
8244 /* F3 0F 2D = CVTSS2SI
8245 when sz==4 -- convert F32 in mem/low quarter xmm to I32 in ireg,
8246 according to prevailing SSE rounding mode
8247 when sz==8 -- convert F32 in mem/low quarter xmm to I64 in ireg,
8248 according to prevailing SSE rounding mode
8249 */
sewardj82c9f2f2005-03-02 16:05:13 +00008250 /* F3 0F 2C = CVTTSS2SI
8251 when sz==4 -- convert F32 in mem/low quarter xmm to I32 in ireg,
8252 truncating towards zero
8253 when sz==8 -- convert F32 in mem/low quarter xmm to I64 in ireg,
8254 truncating towards zero
8255 */
8256 if (haveF3no66noF2(pfx)
8257 && insn[0] == 0x0F
sewardj432f8b62005-05-10 02:50:05 +00008258 && (insn[1] == 0x2D || insn[1] == 0x2C)) {
sewardj82c9f2f2005-03-02 16:05:13 +00008259 IRTemp rmode = newTemp(Ity_I32);
8260 IRTemp f32lo = newTemp(Ity_F32);
8261 Bool r2zero = toBool(insn[1] == 0x2C);
8262 vassert(sz == 4 || sz == 8);
8263
8264 modrm = getUChar(delta+2);
8265 if (epartIsReg(modrm)) {
8266 delta += 2+1;
8267 assign(f32lo, getXMMRegLane32F(eregOfRexRM(pfx,modrm), 0));
8268 DIP("cvt%sss2si %s,%s\n", r2zero ? "t" : "",
8269 nameXMMReg(eregOfRexRM(pfx,modrm)),
8270 nameIReg(sz, gregOfRexRM(pfx,modrm), False));
8271 } else {
8272 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8273 assign(f32lo, loadLE(Ity_F32, mkexpr(addr)));
8274 delta += 2+alen;
8275 DIP("cvt%sss2si %s,%s\n", r2zero ? "t" : "",
8276 dis_buf,
8277 nameIReg(sz, gregOfRexRM(pfx,modrm), False));
8278 }
8279
8280 if (r2zero) {
8281 assign( rmode, mkU32((UInt)Irrm_ZERO) );
8282 } else {
8283 assign( rmode, get_sse_roundingmode() );
8284 }
8285
8286 if (sz == 4) {
8287 putIReg32( gregOfRexRM(pfx,modrm),
8288 binop( Iop_F64toI32,
8289 mkexpr(rmode),
8290 unop(Iop_F32toF64, mkexpr(f32lo))) );
8291 } else {
8292 putIReg64( gregOfRexRM(pfx,modrm),
8293 binop( Iop_F64toI64,
8294 mkexpr(rmode),
8295 unop(Iop_F32toF64, mkexpr(f32lo))) );
8296 }
8297
8298 goto decode_success;
8299 }
8300
sewardj432f8b62005-05-10 02:50:05 +00008301 /* 0F 5E = DIVPS -- div 32Fx4 from R/M to R */
8302 if (haveNo66noF2noF3(pfx) && sz == 4
8303 && insn[0] == 0x0F && insn[1] == 0x5E) {
8304 delta = dis_SSE_E_to_G_all( pfx, delta+2, "divps", Iop_Div32Fx4 );
8305 goto decode_success;
8306 }
sewardjc49ce232005-02-25 13:03:03 +00008307
8308 /* F3 0F 5E = DIVSS -- div 32F0x4 from R/M to R */
8309 if (haveF3no66noF2(pfx) && sz == 4
8310 && insn[0] == 0x0F && insn[1] == 0x5E) {
8311 delta = dis_SSE_E_to_G_lo32( pfx, delta+2, "divss", Iop_Div32F0x4 );
8312 goto decode_success;
8313 }
8314
sewardjbcbb9de2005-03-27 02:22:32 +00008315 /* 0F AE /2 = LDMXCSR m32 -- load %mxcsr */
8316 if (insn[0] == 0x0F && insn[1] == 0xAE
8317 && haveNo66noF2noF3(pfx)
8318 && !epartIsReg(insn[2]) && gregLO3ofRM(insn[2]) == 2) {
8319
8320 IRTemp t64 = newTemp(Ity_I64);
8321 IRTemp ew = newTemp(Ity_I32);
8322
8323 vassert(sz == 4);
8324 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8325 delta += 2+alen;
8326 DIP("ldmxcsr %s\n", dis_buf);
8327
8328 /* The only thing we observe in %mxcsr is the rounding mode.
8329 Therefore, pass the 32-bit value (SSE native-format control
8330 word) to a clean helper, getting back a 64-bit value, the
8331 lower half of which is the SSEROUND value to store, and the
8332 upper half of which is the emulation-warning token which may
8333 be generated.
8334 */
8335 /* ULong amd64h_check_ldmxcsr ( ULong ); */
8336 assign( t64, mkIRExprCCall(
8337 Ity_I64, 0/*regparms*/,
8338 "amd64g_check_ldmxcsr",
8339 &amd64g_check_ldmxcsr,
8340 mkIRExprVec_1(
8341 unop(Iop_32Uto64,
8342 loadLE(Ity_I32, mkexpr(addr))
8343 )
8344 )
8345 )
8346 );
8347
8348 put_sse_roundingmode( unop(Iop_64to32, mkexpr(t64)) );
8349 assign( ew, unop(Iop_64HIto32, mkexpr(t64) ) );
8350 put_emwarn( mkexpr(ew) );
8351 /* Finally, if an emulation warning was reported, side-exit to
8352 the next insn, reporting the warning, so that Valgrind's
8353 dispatcher sees the warning. */
8354 stmt(
8355 IRStmt_Exit(
8356 binop(Iop_CmpNE64, unop(Iop_32Uto64,mkexpr(ew)), mkU64(0)),
8357 Ijk_EmWarn,
sewardj9e6491a2005-07-02 19:24:10 +00008358 IRConst_U64(guest_RIP_bbstart+delta)
sewardjbcbb9de2005-03-27 02:22:32 +00008359 )
8360 );
8361 goto decode_success;
8362 }
8363
sewardj432f8b62005-05-10 02:50:05 +00008364 /* 0F 5F = MAXPS -- max 32Fx4 from R/M to R */
8365 if (haveNo66noF2noF3(pfx) && sz == 4
8366 && insn[0] == 0x0F && insn[1] == 0x5F) {
8367 delta = dis_SSE_E_to_G_all( pfx, delta+2, "maxps", Iop_Max32Fx4 );
8368 goto decode_success;
8369 }
sewardj37d52572005-02-25 14:22:12 +00008370
8371 /* F3 0F 5F = MAXSS -- max 32F0x4 from R/M to R */
8372 if (haveF3no66noF2(pfx) && sz == 4
8373 && insn[0] == 0x0F && insn[1] == 0x5F) {
8374 delta = dis_SSE_E_to_G_lo32( pfx, delta+2, "maxss", Iop_Max32F0x4 );
8375 goto decode_success;
8376 }
8377
sewardj432f8b62005-05-10 02:50:05 +00008378 /* 0F 5D = MINPS -- min 32Fx4 from R/M to R */
8379 if (haveNo66noF2noF3(pfx) && sz == 4
8380 && insn[0] == 0x0F && insn[1] == 0x5D) {
8381 delta = dis_SSE_E_to_G_all( pfx, delta+2, "minps", Iop_Min32Fx4 );
8382 goto decode_success;
8383 }
sewardj37d52572005-02-25 14:22:12 +00008384
8385 /* F3 0F 5D = MINSS -- min 32F0x4 from R/M to R */
8386 if (haveF3no66noF2(pfx) && sz == 4
8387 && insn[0] == 0x0F && insn[1] == 0x5D) {
8388 delta = dis_SSE_E_to_G_lo32( pfx, delta+2, "minss", Iop_Min32F0x4 );
8389 goto decode_success;
8390 }
sewardj8d965312005-02-25 02:48:47 +00008391
8392 /* 0F 28 = MOVAPS -- move from E (mem or xmm) to G (xmm). */
8393 /* 0F 10 = MOVUPS -- move from E (mem or xmm) to G (xmm). */
8394 if (haveNo66noF2noF3(pfx) && sz == 4
8395 && insn[0] == 0x0F && (insn[1] == 0x28 || insn[1] == 0x10)) {
8396 modrm = getUChar(delta+2);
8397 if (epartIsReg(modrm)) {
8398 putXMMReg( gregOfRexRM(pfx,modrm),
8399 getXMMReg( eregOfRexRM(pfx,modrm) ));
8400 DIP("mov[ua]ps %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
8401 nameXMMReg(gregOfRexRM(pfx,modrm)));
8402 delta += 2+1;
8403 } else {
8404 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8405 putXMMReg( gregOfRexRM(pfx,modrm),
8406 loadLE(Ity_V128, mkexpr(addr)) );
8407 DIP("mov[ua]ps %s,%s\n", dis_buf,
8408 nameXMMReg(gregOfRexRM(pfx,modrm)));
8409 delta += 2+alen;
8410 }
8411 goto decode_success;
8412 }
sewardj1001dc42005-02-21 08:25:55 +00008413
8414 /* 0F 29 = MOVAPS -- move from G (xmm) to E (mem or xmm). */
sewardj446d2672005-06-10 11:04:52 +00008415 /* 0F 11 = MOVUPS -- move from G (xmm) to E (mem or xmm). */
sewardj8d965312005-02-25 02:48:47 +00008416 if (haveNo66noF2noF3(pfx) && sz == 4
sewardj446d2672005-06-10 11:04:52 +00008417 && insn[0] == 0x0F && (insn[1] == 0x29 || insn[1] == 0x11)) {
sewardj1001dc42005-02-21 08:25:55 +00008418 modrm = getUChar(delta+2);
8419 if (epartIsReg(modrm)) {
8420 /* fall through; awaiting test case */
8421 } else {
8422 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8423 storeLE( mkexpr(addr), getXMMReg(gregOfRexRM(pfx,modrm)) );
sewardj446d2672005-06-10 11:04:52 +00008424 DIP("mov[ua]ps %s,%s\n", nameXMMReg(gregOfRexRM(pfx,modrm)),
8425 dis_buf );
sewardj1001dc42005-02-21 08:25:55 +00008426 delta += 2+alen;
8427 goto decode_success;
8428 }
8429 }
8430
sewardj432f8b62005-05-10 02:50:05 +00008431 /* 0F 16 = MOVHPS -- move from mem to high half of XMM. */
8432 /* 0F 16 = MOVLHPS -- move from lo half to hi half of XMM. */
8433 if (haveNo66noF2noF3(pfx) && sz == 4
8434 && insn[0] == 0x0F && insn[1] == 0x16) {
8435 modrm = getUChar(delta+2);
8436 if (epartIsReg(modrm)) {
8437 delta += 2+1;
8438 putXMMRegLane64( gregOfRexRM(pfx,modrm), 1/*upper lane*/,
8439 getXMMRegLane64( eregOfRexRM(pfx,modrm), 0 ) );
8440 DIP("movhps %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
8441 nameXMMReg(gregOfRexRM(pfx,modrm)));
8442 } else {
8443 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8444 delta += 2+alen;
8445 putXMMRegLane64( gregOfRexRM(pfx,modrm), 1/*upper lane*/,
8446 loadLE(Ity_I64, mkexpr(addr)) );
8447 DIP("movhps %s,%s\n", dis_buf,
8448 nameXMMReg( gregOfRexRM(pfx,modrm) ));
8449 }
8450 goto decode_success;
8451 }
8452
8453 /* 0F 17 = MOVHPS -- move from high half of XMM to mem. */
8454 if (haveNo66noF2noF3(pfx) && sz == 4
8455 && insn[0] == 0x0F && insn[1] == 0x17) {
8456 if (!epartIsReg(insn[2])) {
8457 delta += 2;
8458 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
8459 delta += alen;
8460 storeLE( mkexpr(addr),
8461 getXMMRegLane64( gregOfRexRM(pfx,insn[2]),
8462 1/*upper lane*/ ) );
8463 DIP("movhps %s,%s\n", nameXMMReg( gregOfRexRM(pfx,insn[2]) ),
8464 dis_buf);
8465 goto decode_success;
8466 }
8467 /* else fall through */
8468 }
8469
8470 /* 0F 12 = MOVLPS -- move from mem to low half of XMM. */
8471 /* OF 12 = MOVHLPS -- from from hi half to lo half of XMM. */
8472 if (haveNo66noF2noF3(pfx) && sz == 4
8473 && insn[0] == 0x0F && insn[1] == 0x12) {
8474 modrm = getUChar(delta+2);
8475 if (epartIsReg(modrm)) {
8476 delta += 2+1;
8477 putXMMRegLane64( gregOfRexRM(pfx,modrm),
8478 0/*lower lane*/,
8479 getXMMRegLane64( eregOfRexRM(pfx,modrm), 1 ));
8480 DIP("movhlps %s, %s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
8481 nameXMMReg(gregOfRexRM(pfx,modrm)));
8482 } else {
8483 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8484 delta += 2+alen;
8485 putXMMRegLane64( gregOfRexRM(pfx,modrm), 0/*lower lane*/,
8486 loadLE(Ity_I64, mkexpr(addr)) );
8487 DIP("movlps %s, %s\n",
8488 dis_buf, nameXMMReg( gregOfRexRM(pfx,modrm) ));
8489 }
8490 goto decode_success;
8491 }
8492
8493 /* 0F 13 = MOVLPS -- move from low half of XMM to mem. */
8494 if (haveNo66noF2noF3(pfx) && sz == 4
8495 && insn[0] == 0x0F && insn[1] == 0x13) {
8496 if (!epartIsReg(insn[2])) {
8497 delta += 2;
8498 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
8499 delta += alen;
8500 storeLE( mkexpr(addr),
8501 getXMMRegLane64( gregOfRexRM(pfx,insn[2]),
8502 0/*lower lane*/ ) );
8503 DIP("movlps %s, %s\n", nameXMMReg( gregOfRexRM(pfx,insn[2]) ),
8504 dis_buf);
8505 goto decode_success;
8506 }
8507 /* else fall through */
8508 }
8509
sewardja7ba8c42005-05-10 20:08:34 +00008510 /* 0F 50 = MOVMSKPS - move 4 sign bits from 4 x F32 in xmm(E)
8511 to 4 lowest bits of ireg(G) */
8512 if (haveNo66noF2noF3(pfx) && sz == 4
8513 && insn[0] == 0x0F && insn[1] == 0x50) {
8514 modrm = getUChar(delta+2);
8515 if (epartIsReg(modrm)) {
8516 Int src;
8517 t0 = newTemp(Ity_I32);
8518 t1 = newTemp(Ity_I32);
8519 t2 = newTemp(Ity_I32);
8520 t3 = newTemp(Ity_I32);
8521 delta += 2+1;
8522 src = eregOfRexRM(pfx,modrm);
8523 assign( t0, binop( Iop_And32,
8524 binop(Iop_Shr32, getXMMRegLane32(src,0), mkU8(31)),
8525 mkU32(1) ));
8526 assign( t1, binop( Iop_And32,
8527 binop(Iop_Shr32, getXMMRegLane32(src,1), mkU8(30)),
8528 mkU32(2) ));
8529 assign( t2, binop( Iop_And32,
8530 binop(Iop_Shr32, getXMMRegLane32(src,2), mkU8(29)),
8531 mkU32(4) ));
8532 assign( t3, binop( Iop_And32,
8533 binop(Iop_Shr32, getXMMRegLane32(src,3), mkU8(28)),
8534 mkU32(8) ));
8535 putIReg32( gregOfRexRM(pfx,modrm),
8536 binop(Iop_Or32,
8537 binop(Iop_Or32, mkexpr(t0), mkexpr(t1)),
8538 binop(Iop_Or32, mkexpr(t2), mkexpr(t3))
8539 )
8540 );
8541 DIP("movmskps %s,%s\n", nameXMMReg(src),
8542 nameIReg32(gregOfRexRM(pfx,modrm)));
8543 goto decode_success;
8544 }
8545 /* else fall through */
8546 }
8547
sewardj612be432005-05-11 02:55:54 +00008548 /* 66 0F 2B = MOVNTPD -- for us, just a plain SSE store. */
sewardja7ba8c42005-05-10 20:08:34 +00008549 /* 0F 2B = MOVNTPS -- for us, just a plain SSE store. */
sewardj612be432005-05-11 02:55:54 +00008550 if ( ( (haveNo66noF2noF3(pfx) && sz == 4)
8551 || (have66noF2noF3(pfx) && sz == 2)
8552 )
8553 && insn[0] == 0x0F && insn[1] == 0x2B) {
sewardja7ba8c42005-05-10 20:08:34 +00008554 modrm = getUChar(delta+2);
8555 if (!epartIsReg(modrm)) {
8556 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8557 storeLE( mkexpr(addr), getXMMReg(gregOfRexRM(pfx,modrm)) );
sewardj612be432005-05-11 02:55:54 +00008558 DIP("movntp%s %s,%s\n", sz==2 ? "d" : "s",
8559 dis_buf,
8560 nameXMMReg(gregOfRexRM(pfx,modrm)));
sewardja7ba8c42005-05-10 20:08:34 +00008561 delta += 2+alen;
8562 goto decode_success;
8563 }
8564 /* else fall through */
8565 }
8566
8567 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8568 /* 0F E7 = MOVNTQ -- for us, just a plain MMX store. Note, the
8569 Intel manual does not say anything about the usual business of
8570 the FP reg tags getting trashed whenever an MMX insn happens.
8571 So we just leave them alone.
8572 */
8573 if (haveNo66noF2noF3(pfx) && sz == 4
8574 && insn[0] == 0x0F && insn[1] == 0xE7) {
8575 modrm = getUChar(delta+2);
8576 if (!epartIsReg(modrm)) {
8577 /* do_MMX_preamble(); Intel docs don't specify this */
8578 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8579 storeLE( mkexpr(addr), getMMXReg(gregLO3ofRM(modrm)) );
8580 DIP("movntq %s,%s\n", dis_buf,
8581 nameMMXReg(gregLO3ofRM(modrm)));
8582 delta += 2+alen;
8583 goto decode_success;
8584 }
8585 /* else fall through */
8586 }
sewardj8d965312005-02-25 02:48:47 +00008587
8588 /* F3 0F 10 = MOVSS -- move 32 bits from E (mem or lo 1/4 xmm) to G
8589 (lo 1/4 xmm). If E is mem, upper 3/4 of G is zeroed out. */
8590 if (haveF3no66noF2(pfx) && sz == 4
8591 && insn[0] == 0x0F && insn[1] == 0x10) {
8592 modrm = getUChar(delta+2);
8593 if (epartIsReg(modrm)) {
8594 putXMMRegLane32( gregOfRexRM(pfx,modrm), 0,
8595 getXMMRegLane32( eregOfRexRM(pfx,modrm), 0 ));
8596 DIP("movss %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
8597 nameXMMReg(gregOfRexRM(pfx,modrm)));
8598 delta += 2+1;
8599 } else {
8600 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8601 putXMMReg( gregOfRexRM(pfx,modrm), mkV128(0) );
8602 putXMMRegLane32( gregOfRexRM(pfx,modrm), 0,
8603 loadLE(Ity_I32, mkexpr(addr)) );
8604 DIP("movss %s,%s\n", dis_buf,
8605 nameXMMReg(gregOfRexRM(pfx,modrm)));
8606 delta += 2+alen;
8607 }
8608 goto decode_success;
8609 }
8610
8611 /* F3 0F 11 = MOVSS -- move 32 bits from G (lo 1/4 xmm) to E (mem
8612 or lo 1/4 xmm). */
8613 if (haveF3no66noF2(pfx) && sz == 4
8614 && insn[0] == 0x0F && insn[1] == 0x11) {
8615 modrm = getUChar(delta+2);
8616 if (epartIsReg(modrm)) {
8617 /* fall through, we don't yet have a test case */
8618 } else {
8619 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8620 storeLE( mkexpr(addr),
8621 getXMMRegLane32(gregOfRexRM(pfx,modrm), 0) );
8622 DIP("movss %s,%s\n", nameXMMReg(gregOfRexRM(pfx,modrm)),
8623 dis_buf);
8624 delta += 2+alen;
8625 goto decode_success;
8626 }
8627 }
8628
sewardj432f8b62005-05-10 02:50:05 +00008629 /* 0F 59 = MULPS -- mul 32Fx4 from R/M to R */
8630 if (haveNo66noF2noF3(pfx) && sz == 4
8631 && insn[0] == 0x0F && insn[1] == 0x59) {
8632 delta = dis_SSE_E_to_G_all( pfx, delta+2, "mulps", Iop_Mul32Fx4 );
8633 goto decode_success;
8634 }
sewardj8d965312005-02-25 02:48:47 +00008635
8636 /* F3 0F 59 = MULSS -- mul 32F0x4 from R/M to R */
8637 if (haveF3no66noF2(pfx) && sz == 4
8638 && insn[0] == 0x0F && insn[1] == 0x59) {
8639 delta = dis_SSE_E_to_G_lo32( pfx, delta+2, "mulss", Iop_Mul32F0x4 );
8640 goto decode_success;
8641 }
8642
sewardj3aba9eb2005-03-30 23:20:47 +00008643 /* 0F 56 = ORPS -- G = G and E */
8644 if (haveNo66noF2noF3(pfx) && sz == 4
8645 && insn[0] == 0x0F && insn[1] == 0x56) {
8646 delta = dis_SSE_E_to_G_all( pfx, delta+2, "orps", Iop_OrV128 );
8647 goto decode_success;
8648 }
8649
sewardja7ba8c42005-05-10 20:08:34 +00008650 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8651 /* 0F E0 = PAVGB -- 8x8 unsigned Packed Average, with rounding */
8652 if (haveNo66noF2noF3(pfx) && sz == 4
8653 && insn[0] == 0x0F && insn[1] == 0xE0) {
8654 do_MMX_preamble();
8655 delta = dis_MMXop_regmem_to_reg (
8656 pfx, delta+2, insn[1], "pavgb", False );
8657 goto decode_success;
8658 }
8659
8660 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8661 /* 0F E3 = PAVGW -- 16x4 unsigned Packed Average, with rounding */
8662 if (haveNo66noF2noF3(pfx) && sz == 4
8663 && insn[0] == 0x0F && insn[1] == 0xE3) {
8664 do_MMX_preamble();
8665 delta = dis_MMXop_regmem_to_reg (
8666 pfx, delta+2, insn[1], "pavgw", False );
8667 goto decode_success;
8668 }
8669
8670 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8671 /* 0F C5 = PEXTRW -- extract 16-bit field from mmx(E) and put
8672 zero-extend of it in ireg(G). */
8673 if (haveNo66noF2noF3(pfx) && sz == 4
8674 && insn[0] == 0x0F && insn[1] == 0xC5) {
8675 modrm = insn[2];
8676 if (epartIsReg(modrm)) {
8677 IRTemp sV = newTemp(Ity_I64);
8678 t5 = newTemp(Ity_I16);
8679 do_MMX_preamble();
8680 assign(sV, getMMXReg(eregLO3ofRM(modrm)));
8681 breakup64to16s( sV, &t3, &t2, &t1, &t0 );
8682 switch (insn[3] & 3) {
8683 case 0: assign(t5, mkexpr(t0)); break;
8684 case 1: assign(t5, mkexpr(t1)); break;
8685 case 2: assign(t5, mkexpr(t2)); break;
8686 case 3: assign(t5, mkexpr(t3)); break;
8687 default: vassert(0);
8688 }
8689 putIReg32(gregOfRexRM(pfx,modrm), unop(Iop_16Uto32, mkexpr(t5)));
8690 DIP("pextrw $%d,%s,%s\n",
8691 (Int)insn[3], nameMMXReg(eregLO3ofRM(modrm)),
8692 nameIReg32(gregOfRexRM(pfx,modrm)));
8693 delta += 4;
8694 goto decode_success;
8695 }
8696 /* else fall through */
8697 /* note, for anyone filling in the mem case: this insn has one
8698 byte after the amode and therefore you must pass 1 as the
8699 last arg to disAMode */
8700 }
8701
8702 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8703 /* 0F C4 = PINSRW -- get 16 bits from E(mem or low half ireg) and
8704 put it into the specified lane of mmx(G). */
8705 if (haveNo66noF2noF3(pfx) && sz == 4
8706 && insn[0] == 0x0F && insn[1] == 0xC4) {
8707 /* Use t0 .. t3 to hold the 4 original 16-bit lanes of the
8708 mmx reg. t4 is the new lane value. t5 is the original
8709 mmx value. t6 is the new mmx value. */
8710 Int lane;
8711 t4 = newTemp(Ity_I16);
8712 t5 = newTemp(Ity_I64);
8713 t6 = newTemp(Ity_I64);
8714 modrm = insn[2];
8715 do_MMX_preamble();
8716
8717 assign(t5, getMMXReg(gregLO3ofRM(modrm)));
8718 breakup64to16s( t5, &t3, &t2, &t1, &t0 );
8719
8720 if (epartIsReg(modrm)) {
8721 assign(t4, getIReg16(eregOfRexRM(pfx,modrm)));
8722 delta += 3+1;
8723 lane = insn[3+1-1];
8724 DIP("pinsrw $%d,%s,%s\n", (Int)lane,
8725 nameIReg16(eregOfRexRM(pfx,modrm)),
8726 nameMMXReg(gregLO3ofRM(modrm)));
8727 } else {
8728 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 1 );
8729 delta += 3+alen;
8730 lane = insn[3+alen-1];
8731 assign(t4, loadLE(Ity_I16, mkexpr(addr)));
8732 DIP("pinsrw $%d,%s,%s\n", (Int)lane,
8733 dis_buf,
8734 nameMMXReg(gregLO3ofRM(modrm)));
8735 }
8736
8737 switch (lane & 3) {
8738 case 0: assign(t6, mk64from16s(t3,t2,t1,t4)); break;
8739 case 1: assign(t6, mk64from16s(t3,t2,t4,t0)); break;
8740 case 2: assign(t6, mk64from16s(t3,t4,t1,t0)); break;
8741 case 3: assign(t6, mk64from16s(t4,t2,t1,t0)); break;
8742 default: vassert(0);
8743 }
8744 putMMXReg(gregLO3ofRM(modrm), mkexpr(t6));
8745 goto decode_success;
8746 }
8747
8748 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8749 /* 0F EE = PMAXSW -- 16x4 signed max */
8750 if (haveNo66noF2noF3(pfx) && sz == 4
8751 && insn[0] == 0x0F && insn[1] == 0xEE) {
8752 do_MMX_preamble();
8753 delta = dis_MMXop_regmem_to_reg (
8754 pfx, delta+2, insn[1], "pmaxsw", False );
8755 goto decode_success;
8756 }
8757
8758 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8759 /* 0F DE = PMAXUB -- 8x8 unsigned max */
8760 if (haveNo66noF2noF3(pfx) && sz == 4
8761 && insn[0] == 0x0F && insn[1] == 0xDE) {
8762 do_MMX_preamble();
8763 delta = dis_MMXop_regmem_to_reg (
8764 pfx, delta+2, insn[1], "pmaxub", False );
8765 goto decode_success;
8766 }
8767
8768 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8769 /* 0F EA = PMINSW -- 16x4 signed min */
8770 if (haveNo66noF2noF3(pfx) && sz == 4
8771 && insn[0] == 0x0F && insn[1] == 0xEA) {
8772 do_MMX_preamble();
8773 delta = dis_MMXop_regmem_to_reg (
8774 pfx, delta+2, insn[1], "pminsw", False );
8775 goto decode_success;
8776 }
8777
8778 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8779 /* 0F DA = PMINUB -- 8x8 unsigned min */
8780 if (haveNo66noF2noF3(pfx) && sz == 4
8781 && insn[0] == 0x0F && insn[1] == 0xDA) {
8782 do_MMX_preamble();
8783 delta = dis_MMXop_regmem_to_reg (
8784 pfx, delta+2, insn[1], "pminub", False );
8785 goto decode_success;
8786 }
8787
8788 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8789 /* 0F D7 = PMOVMSKB -- extract sign bits from each of 8 lanes in
8790 mmx(G), turn them into a byte, and put zero-extend of it in
8791 ireg(G). */
8792 if (haveNo66noF2noF3(pfx) && sz == 4
8793 && insn[0] == 0x0F && insn[1] == 0xD7) {
8794 modrm = insn[2];
8795 if (epartIsReg(modrm)) {
8796 do_MMX_preamble();
8797 t0 = newTemp(Ity_I64);
8798 t1 = newTemp(Ity_I64);
8799 assign(t0, getMMXReg(eregLO3ofRM(modrm)));
8800 assign(t1, mkIRExprCCall(
8801 Ity_I64, 0/*regparms*/,
8802 "amd64g_calculate_mmx_pmovmskb",
8803 &amd64g_calculate_mmx_pmovmskb,
8804 mkIRExprVec_1(mkexpr(t0))));
8805 putIReg32(gregOfRexRM(pfx,modrm), unop(Iop_64to32,mkexpr(t1)));
8806 DIP("pmovmskb %s,%s\n", nameMMXReg(eregLO3ofRM(modrm)),
8807 nameIReg32(gregOfRexRM(pfx,modrm)));
8808 delta += 3;
8809 goto decode_success;
8810 }
8811 /* else fall through */
8812 }
8813
8814 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8815 /* 0F E4 = PMULUH -- 16x4 hi-half of unsigned widening multiply */
8816 if (haveNo66noF2noF3(pfx) && sz == 4
8817 && insn[0] == 0x0F && insn[1] == 0xE4) {
8818 do_MMX_preamble();
8819 delta = dis_MMXop_regmem_to_reg (
8820 pfx, delta+2, insn[1], "pmuluh", False );
8821 goto decode_success;
8822 }
sewardja6b93d12005-02-17 09:28:28 +00008823
8824 /* 0F 18 /0 = PREFETCHNTA -- prefetch into caches, */
8825 /* 0F 18 /1 = PREFETCH0 -- with various different hints */
8826 /* 0F 18 /2 = PREFETCH1 */
8827 /* 0F 18 /3 = PREFETCH2 */
8828 if (insn[0] == 0x0F && insn[1] == 0x18
sewardjbcbb9de2005-03-27 02:22:32 +00008829 && haveNo66noF2noF3(pfx)
sewardja6b93d12005-02-17 09:28:28 +00008830 && !epartIsReg(insn[2])
sewardj901ed122005-02-27 13:25:31 +00008831 && gregLO3ofRM(insn[2]) >= 0 && gregLO3ofRM(insn[2]) <= 3) {
sewardja6b93d12005-02-17 09:28:28 +00008832 HChar* hintstr = "??";
8833
8834 modrm = getUChar(delta+2);
8835 vassert(!epartIsReg(modrm));
8836
8837 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8838 delta += 2+alen;
8839
sewardj901ed122005-02-27 13:25:31 +00008840 switch (gregLO3ofRM(modrm)) {
sewardja6b93d12005-02-17 09:28:28 +00008841 case 0: hintstr = "nta"; break;
8842 case 1: hintstr = "t0"; break;
8843 case 2: hintstr = "t1"; break;
8844 case 3: hintstr = "t2"; break;
8845 default: vassert(0);
8846 }
8847
8848 DIP("prefetch%s %s\n", hintstr, dis_buf);
8849 goto decode_success;
8850 }
8851
sewardja7ba8c42005-05-10 20:08:34 +00008852 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8853 /* 0F F6 = PSADBW -- sum of 8Ux8 absolute differences */
8854 if (haveNo66noF2noF3(pfx) && sz == 4
8855 && insn[0] == 0x0F && insn[1] == 0xF6) {
8856 do_MMX_preamble();
8857 delta = dis_MMXop_regmem_to_reg (
8858 pfx, delta+2, insn[1], "psadbw", False );
8859 goto decode_success;
8860 }
8861
8862 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8863 /* 0F 70 = PSHUFW -- rearrange 4x16 from E(mmx or mem) to G(mmx) */
8864 if (haveNo66noF2noF3(pfx) && sz == 4
8865 && insn[0] == 0x0F && insn[1] == 0x70) {
8866 Int order;
8867 IRTemp sV, dV, s3, s2, s1, s0;
8868 s3 = s2 = s1 = s0 = IRTemp_INVALID;
8869 sV = newTemp(Ity_I64);
8870 dV = newTemp(Ity_I64);
8871 do_MMX_preamble();
8872 modrm = insn[2];
8873 if (epartIsReg(modrm)) {
8874 assign( sV, getMMXReg(eregLO3ofRM(modrm)) );
8875 order = (Int)insn[3];
8876 delta += 2+2;
8877 DIP("pshufw $%d,%s,%s\n", order,
8878 nameMMXReg(eregLO3ofRM(modrm)),
8879 nameMMXReg(gregLO3ofRM(modrm)));
8880 } else {
8881 addr = disAMode ( &alen, pfx, delta+2, dis_buf,
8882 1/*extra byte after amode*/ );
8883 assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
8884 order = (Int)insn[2+alen];
8885 delta += 3+alen;
8886 DIP("pshufw $%d,%s,%s\n", order,
8887 dis_buf,
8888 nameMMXReg(gregLO3ofRM(modrm)));
8889 }
8890 breakup64to16s( sV, &s3, &s2, &s1, &s0 );
8891# define SEL(n) \
8892 ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
8893 assign(dV,
8894 mk64from16s( SEL((order>>6)&3), SEL((order>>4)&3),
8895 SEL((order>>2)&3), SEL((order>>0)&3) )
8896 );
8897 putMMXReg(gregLO3ofRM(modrm), mkexpr(dV));
8898# undef SEL
8899 goto decode_success;
8900 }
8901
8902 /* 0F 53 = RCPPS -- approx reciprocal 32Fx4 from R/M to R */
8903 if (haveNo66noF2noF3(pfx) && sz == 4
8904 && insn[0] == 0x0F && insn[1] == 0x53) {
8905 delta = dis_SSE_E_to_G_unary_all( pfx, delta+2,
8906 "rcpps", Iop_Recip32Fx4 );
8907 goto decode_success;
8908 }
8909
8910 /* F3 0F 53 = RCPSS -- approx reciprocal 32F0x4 from R/M to R */
8911 if (haveF3no66noF2(pfx) && sz == 4
8912 && insn[0] == 0x0F && insn[1] == 0x53) {
8913 delta = dis_SSE_E_to_G_unary_lo32( pfx, delta+2,
8914 "rcpss", Iop_Recip32F0x4 );
8915 goto decode_success;
8916 }
8917
8918 /* 0F 52 = RSQRTPS -- approx reciprocal sqrt 32Fx4 from R/M to R */
8919 if (haveNo66noF2noF3(pfx) && sz == 4
8920 && insn[0] == 0x0F && insn[1] == 0x52) {
8921 delta = dis_SSE_E_to_G_unary_all( pfx, delta+2,
8922 "rsqrtps", Iop_RSqrt32Fx4 );
8923 goto decode_success;
8924 }
8925
8926 /* F3 0F 52 = RSQRTSS -- approx reciprocal sqrt 32F0x4 from R/M to R */
8927 if (haveF3no66noF2(pfx) && sz == 4
8928 && insn[0] == 0x0F && insn[1] == 0x52) {
8929 delta = dis_SSE_E_to_G_unary_lo32( pfx, delta+2,
8930 "rsqrtss", Iop_RSqrt32F0x4 );
8931 goto decode_success;
8932 }
sewardjf53b7352005-04-06 20:01:56 +00008933
8934 /* 0F AE /7 = SFENCE -- flush pending operations to memory */
8935 if (haveNo66noF2noF3(pfx)
8936 && insn[0] == 0x0F && insn[1] == 0xAE
8937 && epartIsReg(insn[2]) && gregLO3ofRM(insn[2]) == 7
8938 && sz == 4) {
8939 delta += 3;
8940 /* Insert a memory fence. It's sometimes important that these
8941 are carried through to the generated code. */
8942 stmt( IRStmt_MFence() );
8943 DIP("sfence\n");
8944 goto decode_success;
8945 }
8946
sewardja7ba8c42005-05-10 20:08:34 +00008947 /* 0F C6 /r ib = SHUFPS -- shuffle packed F32s */
8948 if (haveNo66noF2noF3(pfx) && sz == 4
8949 && insn[0] == 0x0F && insn[1] == 0xC6) {
8950 Int select;
8951 IRTemp sV, dV;
8952 IRTemp s3, s2, s1, s0, d3, d2, d1, d0;
8953 sV = newTemp(Ity_V128);
8954 dV = newTemp(Ity_V128);
8955 s3 = s2 = s1 = s0 = d3 = d2 = d1 = d0 = IRTemp_INVALID;
8956 modrm = insn[2];
8957 assign( dV, getXMMReg(gregOfRexRM(pfx,modrm)) );
8958
8959 if (epartIsReg(modrm)) {
8960 assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
8961 select = (Int)insn[3];
8962 delta += 2+2;
8963 DIP("shufps $%d,%s,%s\n", select,
8964 nameXMMReg(eregOfRexRM(pfx,modrm)),
8965 nameXMMReg(gregOfRexRM(pfx,modrm)));
8966 } else {
8967 addr = disAMode ( &alen, pfx, delta+2, dis_buf,
8968 1/*byte at end of insn*/ );
8969 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
8970 select = (Int)insn[2+alen];
8971 delta += 3+alen;
8972 DIP("shufps $%d,%s,%s\n", select,
8973 dis_buf,
8974 nameXMMReg(gregOfRexRM(pfx,modrm)));
8975 }
8976
8977 breakup128to32s( dV, &d3, &d2, &d1, &d0 );
8978 breakup128to32s( sV, &s3, &s2, &s1, &s0 );
8979
8980# define SELD(n) ((n)==0 ? d0 : ((n)==1 ? d1 : ((n)==2 ? d2 : d3)))
8981# define SELS(n) ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
8982
8983 putXMMReg(
8984 gregOfRexRM(pfx,modrm),
8985 mk128from32s( SELS((select>>6)&3), SELS((select>>4)&3),
8986 SELD((select>>2)&3), SELD((select>>0)&3) )
8987 );
8988
8989# undef SELD
8990# undef SELS
8991
8992 goto decode_success;
8993 }
8994
8995 /* 0F 51 = SQRTPS -- approx sqrt 32Fx4 from R/M to R */
8996 if (haveNo66noF2noF3(pfx) && sz == 4
8997 && insn[0] == 0x0F && insn[1] == 0x51) {
8998 delta = dis_SSE_E_to_G_unary_all( pfx, delta+2,
8999 "sqrtps", Iop_Sqrt32Fx4 );
9000 goto decode_success;
9001 }
9002
9003 /* F3 0F 51 = SQRTSS -- approx sqrt 32F0x4 from R/M to R */
9004 if (haveF3no66noF2(pfx) && sz == 4
9005 && insn[0] == 0x0F && insn[1] == 0x51) {
9006 delta = dis_SSE_E_to_G_unary_lo32( pfx, delta+2,
9007 "sqrtss", Iop_Sqrt32F0x4 );
9008 goto decode_success;
9009 }
sewardjbcbb9de2005-03-27 02:22:32 +00009010
9011 /* 0F AE /3 = STMXCSR m32 -- store %mxcsr */
9012 if (insn[0] == 0x0F && insn[1] == 0xAE
9013 && haveNo66noF2noF3(pfx)
9014 && !epartIsReg(insn[2]) && gregLO3ofRM(insn[2]) == 3) {
9015
9016 vassert(sz == 4);
9017 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9018 delta += 2+alen;
9019
9020 /* Fake up a native SSE mxcsr word. The only thing it depends
9021 on is SSEROUND[1:0], so call a clean helper to cook it up.
9022 */
9023 /* ULong amd64h_create_mxcsr ( ULong sseround ) */
9024 DIP("stmxcsr %s\n", dis_buf);
9025 storeLE(
9026 mkexpr(addr),
9027 unop(Iop_64to32,
9028 mkIRExprCCall(
9029 Ity_I64, 0/*regp*/,
9030 "amd64g_create_mxcsr", &amd64g_create_mxcsr,
9031 mkIRExprVec_1( unop(Iop_32Uto64,get_sse_roundingmode()) )
9032 )
9033 )
9034 );
9035 goto decode_success;
9036 }
9037
sewardj432f8b62005-05-10 02:50:05 +00009038 /* 0F 5C = SUBPS -- sub 32Fx4 from R/M to R */
9039 if (haveNo66noF2noF3(pfx) && sz == 4
9040 && insn[0] == 0x0F && insn[1] == 0x5C) {
9041 delta = dis_SSE_E_to_G_all( pfx, delta+2, "subps", Iop_Sub32Fx4 );
9042 goto decode_success;
9043 }
sewardj8d965312005-02-25 02:48:47 +00009044
9045 /* F3 0F 5C = SUBSS -- sub 32F0x4 from R/M to R */
9046 if (haveF3no66noF2(pfx) && sz == 4
9047 && insn[0] == 0x0F && insn[1] == 0x5C) {
9048 delta = dis_SSE_E_to_G_lo32( pfx, delta+2, "subss", Iop_Sub32F0x4 );
9049 goto decode_success;
9050 }
9051
sewardja7ba8c42005-05-10 20:08:34 +00009052 /* 0F 15 = UNPCKHPS -- unpack and interleave high part F32s */
9053 /* 0F 14 = UNPCKLPS -- unpack and interleave low part F32s */
9054 /* These just appear to be special cases of SHUFPS */
9055 if (haveNo66noF2noF3(pfx) && sz == 4
9056 && insn[0] == 0x0F && (insn[1] == 0x15 || insn[1] == 0x14)) {
9057 IRTemp sV, dV;
9058 IRTemp s3, s2, s1, s0, d3, d2, d1, d0;
sewardjca673ab2005-05-11 10:03:08 +00009059 Bool hi = toBool(insn[1] == 0x15);
sewardja7ba8c42005-05-10 20:08:34 +00009060 sV = newTemp(Ity_V128);
9061 dV = newTemp(Ity_V128);
9062 s3 = s2 = s1 = s0 = d3 = d2 = d1 = d0 = IRTemp_INVALID;
9063 modrm = insn[2];
9064 assign( dV, getXMMReg(gregOfRexRM(pfx,modrm)) );
9065
9066 if (epartIsReg(modrm)) {
9067 assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
9068 delta += 2+1;
9069 DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
9070 nameXMMReg(eregOfRexRM(pfx,modrm)),
9071 nameXMMReg(gregOfRexRM(pfx,modrm)));
9072 } else {
9073 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9074 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
9075 delta += 2+alen;
9076 DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
9077 dis_buf,
9078 nameXMMReg(gregOfRexRM(pfx,modrm)));
9079 }
9080
9081 breakup128to32s( dV, &d3, &d2, &d1, &d0 );
9082 breakup128to32s( sV, &s3, &s2, &s1, &s0 );
9083
9084 if (hi) {
9085 putXMMReg( gregOfRexRM(pfx,modrm), mk128from32s( s3, d3, s2, d2 ) );
9086 } else {
9087 putXMMReg( gregOfRexRM(pfx,modrm), mk128from32s( s1, d1, s0, d0 ) );
9088 }
9089
9090 goto decode_success;
9091 }
sewardj8d965312005-02-25 02:48:47 +00009092
9093 /* 0F 57 = XORPS -- G = G and E */
9094 if (haveNo66noF2noF3(pfx) && sz == 4
9095 && insn[0] == 0x0F && insn[1] == 0x57) {
9096 delta = dis_SSE_E_to_G_all( pfx, delta+2, "xorps", Iop_XorV128 );
9097 goto decode_success;
9098 }
9099
sewardj5992bd02005-05-11 02:13:42 +00009100 /* ---------------------------------------------------- */
9101 /* --- end of the SSE decoder. --- */
9102 /* ---------------------------------------------------- */
9103
9104 /* ---------------------------------------------------- */
9105 /* --- start of the SSE2 decoder. --- */
9106 /* ---------------------------------------------------- */
sewardj4c328cf2005-05-05 12:05:54 +00009107
9108 /* 66 0F 58 = ADDPD -- add 32Fx4 from R/M to R */
9109 if (have66noF2noF3(pfx) && sz == 2
9110 && insn[0] == 0x0F && insn[1] == 0x58) {
9111 delta = dis_SSE_E_to_G_all( pfx, delta+2, "addpd", Iop_Add64Fx2 );
9112 goto decode_success;
9113 }
sewardj1001dc42005-02-21 08:25:55 +00009114
9115 /* F2 0F 58 = ADDSD -- add 64F0x2 from R/M to R */
9116 if (haveF2no66noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x58) {
9117 vassert(sz == 4);
9118 delta = dis_SSE_E_to_G_lo64( pfx, delta+2, "addsd", Iop_Add64F0x2 );
9119 goto decode_success;
9120 }
9121
sewardj8d965312005-02-25 02:48:47 +00009122 /* 66 0F 55 = ANDNPD -- G = (not G) and E */
9123 if (have66noF2noF3(pfx) && sz == 2
9124 && insn[0] == 0x0F && insn[1] == 0x55) {
9125 delta = dis_SSE_E_to_G_all_invG( pfx, delta+2, "andnpd", Iop_AndV128 );
9126 goto decode_success;
9127 }
sewardj1a01e652005-02-23 11:39:21 +00009128
9129 /* 66 0F 54 = ANDPD -- G = G and E */
9130 if (have66noF2noF3(pfx) && sz == 2
9131 && insn[0] == 0x0F && insn[1] == 0x54) {
9132 delta = dis_SSE_E_to_G_all( pfx, delta+2, "andpd", Iop_AndV128 );
9133 goto decode_success;
9134 }
9135
sewardj97628592005-05-10 22:42:54 +00009136 /* 66 0F C2 = CMPPD -- 64Fx2 comparison from R/M to R */
9137 if (have66noF2noF3(pfx) && sz == 2
9138 && insn[0] == 0x0F && insn[1] == 0xC2) {
9139 delta = dis_SSEcmp_E_to_G( pfx, delta+2, "cmppd", True, 8 );
9140 goto decode_success;
9141 }
sewardj8d965312005-02-25 02:48:47 +00009142
9143 /* F2 0F C2 = CMPSD -- 64F0x2 comparison from R/M to R */
9144 if (haveF2no66noF3(pfx) && sz == 4
9145 && insn[0] == 0x0F && insn[1] == 0xC2) {
9146 delta = dis_SSEcmp_E_to_G( pfx, delta+2, "cmpsd", False, 8 );
9147 goto decode_success;
9148 }
sewardj18303862005-02-21 12:36:54 +00009149
9150 /* 66 0F 2F = COMISD -- 64F0x2 comparison G,E, and set ZCP */
9151 /* 66 0F 2E = UCOMISD -- 64F0x2 comparison G,E, and set ZCP */
sewardjc49ce232005-02-25 13:03:03 +00009152 if (have66noF2noF3(pfx) && sz == 2
sewardj18303862005-02-21 12:36:54 +00009153 && insn[0] == 0x0F && (insn[1] == 0x2F || insn[1] == 0x2E)) {
9154 IRTemp argL = newTemp(Ity_F64);
9155 IRTemp argR = newTemp(Ity_F64);
9156 modrm = getUChar(delta+2);
9157 if (epartIsReg(modrm)) {
9158 assign( argR, getXMMRegLane64F( eregOfRexRM(pfx,modrm),
9159 0/*lowest lane*/ ) );
9160 delta += 2+1;
9161 DIP("%scomisd %s,%s\n", insn[1]==0x2E ? "u" : "",
9162 nameXMMReg(eregOfRexRM(pfx,modrm)),
9163 nameXMMReg(gregOfRexRM(pfx,modrm)) );
9164 } else {
9165 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9166 assign( argR, loadLE(Ity_F64, mkexpr(addr)) );
9167 delta += 2+alen;
9168 DIP("%scomisd %s,%s\n", insn[1]==0x2E ? "u" : "",
9169 dis_buf,
9170 nameXMMReg(gregOfRexRM(pfx,modrm)) );
9171 }
9172 assign( argL, getXMMRegLane64F( gregOfRexRM(pfx,modrm),
9173 0/*lowest lane*/ ) );
9174
9175 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(AMD64G_CC_OP_COPY) ));
9176 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
9177 stmt( IRStmt_Put(
9178 OFFB_CC_DEP1,
9179 binop( Iop_And64,
9180 unop( Iop_32Uto64,
9181 binop(Iop_CmpF64, mkexpr(argL), mkexpr(argR)) ),
9182 mkU64(0x45)
9183 )));
9184
9185 goto decode_success;
9186 }
9187
sewardj09717342005-05-05 21:34:02 +00009188 /* F3 0F E6 = CVTDQ2PD -- convert 2 x I32 in mem/lo half xmm to 2 x
9189 F64 in xmm(G) */
9190 if (haveF3no66noF2(pfx) && insn[0] == 0x0F && insn[1] == 0xE6) {
9191 IRTemp arg64 = newTemp(Ity_I64);
9192 if (sz != 4) goto decode_failure;
9193
9194 modrm = getUChar(delta+2);
9195 if (epartIsReg(modrm)) {
9196 assign( arg64, getXMMRegLane64(eregOfRexRM(pfx,modrm), 0) );
9197 delta += 2+1;
9198 DIP("cvtdq2pd %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
9199 nameXMMReg(gregOfRexRM(pfx,modrm)));
9200 } else {
9201 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9202 assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
9203 delta += 2+alen;
9204 DIP("cvtdq2pd %s,%s\n", dis_buf,
9205 nameXMMReg(gregOfRexRM(pfx,modrm)) );
9206 }
9207
9208 putXMMRegLane64F(
9209 gregOfRexRM(pfx,modrm), 0,
9210 unop(Iop_I32toF64, unop(Iop_64to32, mkexpr(arg64)))
9211 );
9212
9213 putXMMRegLane64F(
9214 gregOfRexRM(pfx,modrm), 1,
9215 unop(Iop_I32toF64, unop(Iop_64HIto32, mkexpr(arg64)))
9216 );
9217
9218 goto decode_success;
9219 }
9220
sewardj5992bd02005-05-11 02:13:42 +00009221 /* 0F 5B = CVTDQ2PS -- convert 4 x I32 in mem/xmm to 4 x F32 in
9222 xmm(G) */
9223 if (haveNo66noF2noF3(pfx) && sz == 4
9224 && insn[0] == 0x0F && insn[1] == 0x5B) {
sewardj09717342005-05-05 21:34:02 +00009225 IRTemp argV = newTemp(Ity_V128);
9226 IRTemp rmode = newTemp(Ity_I32);
sewardj09717342005-05-05 21:34:02 +00009227
9228 modrm = getUChar(delta+2);
9229 if (epartIsReg(modrm)) {
9230 assign( argV, getXMMReg(eregOfRexRM(pfx,modrm)) );
9231 delta += 2+1;
sewardj5992bd02005-05-11 02:13:42 +00009232 DIP("cvtdq2ps %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
sewardj09717342005-05-05 21:34:02 +00009233 nameXMMReg(gregOfRexRM(pfx,modrm)));
9234 } else {
9235 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
sewardj5992bd02005-05-11 02:13:42 +00009236 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
sewardj09717342005-05-05 21:34:02 +00009237 delta += 2+alen;
sewardj5992bd02005-05-11 02:13:42 +00009238 DIP("cvtdq2ps %s,%s\n", dis_buf,
sewardj09717342005-05-05 21:34:02 +00009239 nameXMMReg(gregOfRexRM(pfx,modrm)) );
9240 }
9241
9242 assign( rmode, get_sse_roundingmode() );
sewardj5992bd02005-05-11 02:13:42 +00009243 breakup128to32s( argV, &t3, &t2, &t1, &t0 );
9244
9245# define CVT(_t) binop( Iop_F64toF32, \
9246 mkexpr(rmode), \
9247 unop(Iop_I32toF64,mkexpr(_t)))
9248
9249 putXMMRegLane32F( gregOfRexRM(pfx,modrm), 3, CVT(t3) );
9250 putXMMRegLane32F( gregOfRexRM(pfx,modrm), 2, CVT(t2) );
9251 putXMMRegLane32F( gregOfRexRM(pfx,modrm), 1, CVT(t1) );
9252 putXMMRegLane32F( gregOfRexRM(pfx,modrm), 0, CVT(t0) );
9253
9254# undef CVT
9255
9256 goto decode_success;
9257 }
9258
9259 /* 66 0F E6 = CVTTPD2DQ -- convert 2 x F64 in mem/xmm to 2 x I32 in
9260 lo half xmm(G), and zero upper half, rounding towards zero */
9261 /* F2 0F E6 = CVTPD2DQ -- convert 2 x F64 in mem/xmm to 2 x I32 in
9262 lo half xmm(G), according to prevailing rounding mode, and zero
9263 upper half */
9264 if ( ( (haveF2no66noF3(pfx) && sz == 4)
9265 || (have66noF2noF3(pfx) && sz == 2)
9266 )
9267 && insn[0] == 0x0F && insn[1] == 0xE6) {
9268 IRTemp argV = newTemp(Ity_V128);
9269 IRTemp rmode = newTemp(Ity_I32);
9270 Bool r2zero = toBool(sz == 2);
9271
9272 modrm = getUChar(delta+2);
9273 if (epartIsReg(modrm)) {
9274 assign( argV, getXMMReg(eregOfRexRM(pfx,modrm)) );
9275 delta += 2+1;
9276 DIP("cvt%spd2dq %s,%s\n", r2zero ? "t" : "",
9277 nameXMMReg(eregOfRexRM(pfx,modrm)),
9278 nameXMMReg(gregOfRexRM(pfx,modrm)));
9279 } else {
9280 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9281 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
9282 delta += 2+alen;
9283 DIP("cvt%spd2dq %s,%s\n", r2zero ? "t" : "",
9284 dis_buf,
9285 nameXMMReg(gregOfRexRM(pfx,modrm)) );
9286 }
9287
9288 if (r2zero) {
9289 assign(rmode, mkU32((UInt)Irrm_ZERO) );
9290 } else {
9291 assign( rmode, get_sse_roundingmode() );
9292 }
9293
sewardj09717342005-05-05 21:34:02 +00009294 t0 = newTemp(Ity_F64);
9295 t1 = newTemp(Ity_F64);
9296 assign( t0, unop(Iop_ReinterpI64asF64,
9297 unop(Iop_V128to64, mkexpr(argV))) );
9298 assign( t1, unop(Iop_ReinterpI64asF64,
9299 unop(Iop_V128HIto64, mkexpr(argV))) );
9300
9301# define CVT(_t) binop( Iop_F64toI32, \
9302 mkexpr(rmode), \
9303 mkexpr(_t) )
9304
9305 putXMMRegLane32( gregOfRexRM(pfx,modrm), 3, mkU32(0) );
9306 putXMMRegLane32( gregOfRexRM(pfx,modrm), 2, mkU32(0) );
9307 putXMMRegLane32( gregOfRexRM(pfx,modrm), 1, CVT(t1) );
9308 putXMMRegLane32( gregOfRexRM(pfx,modrm), 0, CVT(t0) );
9309
9310# undef CVT
9311
9312 goto decode_success;
9313 }
9314
sewardj5992bd02005-05-11 02:13:42 +00009315 /* 66 0F 2D = CVTPD2PI -- convert 2 x F64 in mem/xmm to 2 x
9316 I32 in mmx, according to prevailing SSE rounding mode */
9317 /* 66 0F 2C = CVTTPD2PI -- convert 2 x F64 in mem/xmm to 2 x
9318 I32 in mmx, rounding towards zero */
9319 if (have66noF2noF3(pfx) && sz == 2
9320 && insn[0] == 0x0F && (insn[1] == 0x2D || insn[1] == 0x2C)) {
9321 IRTemp dst64 = newTemp(Ity_I64);
9322 IRTemp rmode = newTemp(Ity_I32);
9323 IRTemp f64lo = newTemp(Ity_F64);
9324 IRTemp f64hi = newTemp(Ity_F64);
sewardjca673ab2005-05-11 10:03:08 +00009325 Bool r2zero = toBool(insn[1] == 0x2C);
sewardj5992bd02005-05-11 02:13:42 +00009326
9327 do_MMX_preamble();
9328 modrm = getUChar(delta+2);
9329
9330 if (epartIsReg(modrm)) {
9331 delta += 2+1;
9332 assign(f64lo, getXMMRegLane64F(eregOfRexRM(pfx,modrm), 0));
9333 assign(f64hi, getXMMRegLane64F(eregOfRexRM(pfx,modrm), 1));
9334 DIP("cvt%spd2pi %s,%s\n", r2zero ? "t" : "",
9335 nameXMMReg(eregOfRexRM(pfx,modrm)),
9336 nameMMXReg(gregLO3ofRM(modrm)));
9337 } else {
9338 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9339 assign(f64lo, loadLE(Ity_F64, mkexpr(addr)));
9340 assign(f64hi, loadLE(Ity_F64, binop( Iop_Add64,
9341 mkexpr(addr),
9342 mkU64(8) )));
9343 delta += 2+alen;
9344 DIP("cvt%spf2pi %s,%s\n", r2zero ? "t" : "",
9345 dis_buf,
9346 nameMMXReg(gregLO3ofRM(modrm)));
9347 }
9348
9349 if (r2zero) {
9350 assign(rmode, mkU32((UInt)Irrm_ZERO) );
9351 } else {
9352 assign( rmode, get_sse_roundingmode() );
9353 }
9354
9355 assign(
9356 dst64,
9357 binop( Iop_32HLto64,
9358 binop( Iop_F64toI32, mkexpr(rmode), mkexpr(f64hi) ),
9359 binop( Iop_F64toI32, mkexpr(rmode), mkexpr(f64lo) )
9360 )
9361 );
9362
9363 putMMXReg(gregLO3ofRM(modrm), mkexpr(dst64));
9364 goto decode_success;
9365 }
9366
9367 /* 66 0F 5A = CVTPD2PS -- convert 2 x F64 in mem/xmm to 2 x F32 in
9368 lo half xmm(G), rounding according to prevailing SSE rounding
9369 mode, and zero upper half */
9370 /* Note, this is practically identical to CVTPD2DQ. It would have
9371 been nicer to merge them together, but the insn[] offsets differ
9372 by one. */
9373 if (have66noF2noF3(pfx) && sz == 2
9374 && insn[0] == 0x0F && insn[1] == 0x5A) {
9375 IRTemp argV = newTemp(Ity_V128);
9376 IRTemp rmode = newTemp(Ity_I32);
9377
9378 modrm = getUChar(delta+2);
9379 if (epartIsReg(modrm)) {
9380 assign( argV, getXMMReg(eregOfRexRM(pfx,modrm)) );
9381 delta += 2+1;
9382 DIP("cvtpd2ps %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
9383 nameXMMReg(gregOfRexRM(pfx,modrm)));
9384 } else {
9385 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9386 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
9387 delta += 2+alen;
9388 DIP("cvtpd2ps %s,%s\n", dis_buf,
9389 nameXMMReg(gregOfRexRM(pfx,modrm)) );
9390 }
9391
9392 assign( rmode, get_sse_roundingmode() );
9393 t0 = newTemp(Ity_F64);
9394 t1 = newTemp(Ity_F64);
9395 assign( t0, unop(Iop_ReinterpI64asF64,
9396 unop(Iop_V128to64, mkexpr(argV))) );
9397 assign( t1, unop(Iop_ReinterpI64asF64,
9398 unop(Iop_V128HIto64, mkexpr(argV))) );
9399
9400# define CVT(_t) binop( Iop_F64toF32, \
9401 mkexpr(rmode), \
9402 mkexpr(_t) )
9403
9404 putXMMRegLane32( gregOfRexRM(pfx,modrm), 3, mkU32(0) );
9405 putXMMRegLane32( gregOfRexRM(pfx,modrm), 2, mkU32(0) );
9406 putXMMRegLane32F( gregOfRexRM(pfx,modrm), 1, CVT(t1) );
9407 putXMMRegLane32F( gregOfRexRM(pfx,modrm), 0, CVT(t0) );
9408
9409# undef CVT
9410
9411 goto decode_success;
9412 }
9413
9414 /* 66 0F 2A = CVTPI2PD -- convert 2 x I32 in mem/mmx to 2 x F64 in
9415 xmm(G) */
9416 if (have66noF2noF3(pfx) && sz == 2
9417 && insn[0] == 0x0F && insn[1] == 0x2A) {
9418 IRTemp arg64 = newTemp(Ity_I64);
9419
9420 modrm = getUChar(delta+2);
9421 do_MMX_preamble();
9422 if (epartIsReg(modrm)) {
9423 assign( arg64, getMMXReg(eregLO3ofRM(modrm)) );
9424 delta += 2+1;
9425 DIP("cvtpi2pd %s,%s\n", nameMMXReg(eregLO3ofRM(modrm)),
9426 nameXMMReg(gregOfRexRM(pfx,modrm)));
9427 } else {
9428 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9429 assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
9430 delta += 2+alen;
9431 DIP("cvtpi2pd %s,%s\n", dis_buf,
9432 nameXMMReg(gregOfRexRM(pfx,modrm)) );
9433 }
9434
9435 putXMMRegLane64F(
9436 gregOfRexRM(pfx,modrm), 0,
9437 unop(Iop_I32toF64, unop(Iop_64to32, mkexpr(arg64)) )
9438 );
9439
9440 putXMMRegLane64F(
9441 gregOfRexRM(pfx,modrm), 1,
9442 unop(Iop_I32toF64, unop(Iop_64HIto32, mkexpr(arg64)) )
9443 );
9444
9445 goto decode_success;
9446 }
9447
9448 /* F3 0F 5B = CVTTPS2DQ -- convert 4 x F32 in mem/xmm to 4 x I32 in
9449 xmm(G), rounding towards zero */
9450 /* 66 0F 5B = CVTPS2DQ -- convert 4 x F32 in mem/xmm to 4 x I32 in
9451 xmm(G), as per the prevailing rounding mode */
9452 if ( ( (have66noF2noF3(pfx) && sz == 2)
9453 || (haveF3no66noF2(pfx) && sz == 4)
9454 )
9455 && insn[0] == 0x0F && insn[1] == 0x5B) {
9456 IRTemp argV = newTemp(Ity_V128);
9457 IRTemp rmode = newTemp(Ity_I32);
9458 Bool r2zero = toBool(sz == 4);
9459
9460 modrm = getUChar(delta+2);
9461 if (epartIsReg(modrm)) {
9462 assign( argV, getXMMReg(eregOfRexRM(pfx,modrm)) );
9463 delta += 2+1;
9464 DIP("cvtps2dq %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
9465 nameXMMReg(gregOfRexRM(pfx,modrm)));
9466 } else {
9467 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9468 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
9469 delta += 2+alen;
9470 DIP("cvtps2dq %s,%s\n", dis_buf,
9471 nameXMMReg(gregOfRexRM(pfx,modrm)) );
9472 }
9473
9474 if (r2zero) {
9475 assign( rmode, mkU32((UInt)Irrm_ZERO) );
9476 } else {
9477 assign( rmode, get_sse_roundingmode() );
9478 }
9479
9480 breakup128to32s( argV, &t3, &t2, &t1, &t0 );
9481
9482 /* This is less than ideal. If it turns out to be a performance
9483 bottleneck it can be improved. */
9484# define CVT(_t) \
9485 binop( Iop_F64toI32, \
9486 mkexpr(rmode), \
9487 unop( Iop_F32toF64, \
9488 unop( Iop_ReinterpI32asF32, mkexpr(_t))) )
9489
9490 putXMMRegLane32( gregOfRexRM(pfx,modrm), 3, CVT(t3) );
9491 putXMMRegLane32( gregOfRexRM(pfx,modrm), 2, CVT(t2) );
9492 putXMMRegLane32( gregOfRexRM(pfx,modrm), 1, CVT(t1) );
9493 putXMMRegLane32( gregOfRexRM(pfx,modrm), 0, CVT(t0) );
9494
9495# undef CVT
9496
9497 goto decode_success;
9498 }
9499
9500 /* 0F 5A = CVTPS2PD -- convert 2 x F32 in low half mem/xmm to 2 x
9501 F64 in xmm(G). */
9502 if (haveNo66noF2noF3(pfx) && sz == 4
9503 && insn[0] == 0x0F && insn[1] == 0x5A) {
9504 IRTemp f32lo = newTemp(Ity_F32);
9505 IRTemp f32hi = newTemp(Ity_F32);
9506
9507 modrm = getUChar(delta+2);
9508 if (epartIsReg(modrm)) {
9509 assign( f32lo, getXMMRegLane32F(eregOfRexRM(pfx,modrm), 0) );
9510 assign( f32hi, getXMMRegLane32F(eregOfRexRM(pfx,modrm), 1) );
9511 delta += 2+1;
9512 DIP("cvtps2pd %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
9513 nameXMMReg(gregOfRexRM(pfx,modrm)));
9514 } else {
9515 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9516 assign( f32lo, loadLE(Ity_F32, mkexpr(addr)) );
9517 assign( f32hi, loadLE(Ity_F32,
9518 binop(Iop_Add64,mkexpr(addr),mkU64(4))) );
9519 delta += 2+alen;
9520 DIP("cvtps2pd %s,%s\n", dis_buf,
9521 nameXMMReg(gregOfRexRM(pfx,modrm)) );
9522 }
9523
9524 putXMMRegLane64F( gregOfRexRM(pfx,modrm), 1,
9525 unop(Iop_F32toF64, mkexpr(f32hi)) );
9526 putXMMRegLane64F( gregOfRexRM(pfx,modrm), 0,
9527 unop(Iop_F32toF64, mkexpr(f32lo)) );
9528
9529 goto decode_success;
9530 }
9531
9532 /* F2 0F 2D = CVTSD2SI
9533 when sz==4 -- convert F64 in mem/low half xmm to I32 in ireg,
9534 according to prevailing SSE rounding mode
9535 when sz==8 -- convert F64 in mem/low half xmm to I64 in ireg,
9536 according to prevailing SSE rounding mode
9537 */
sewardj1a01e652005-02-23 11:39:21 +00009538 /* F2 0F 2C = CVTTSD2SI
9539 when sz==4 -- convert F64 in mem/low half xmm to I32 in ireg,
9540 truncating towards zero
9541 when sz==8 -- convert F64 in mem/low half xmm to I64 in ireg,
9542 truncating towards zero
9543 */
9544 if (haveF2no66noF3(pfx)
9545 && insn[0] == 0x0F
sewardj5992bd02005-05-11 02:13:42 +00009546 && (insn[1] == 0x2D || insn[1] == 0x2C)) {
sewardj1a01e652005-02-23 11:39:21 +00009547 IRTemp rmode = newTemp(Ity_I32);
9548 IRTemp f64lo = newTemp(Ity_F64);
sewardj1027dc22005-02-26 01:55:02 +00009549 Bool r2zero = toBool(insn[1] == 0x2C);
sewardj1a01e652005-02-23 11:39:21 +00009550 vassert(sz == 4 || sz == 8);
9551
9552 modrm = getUChar(delta+2);
9553 if (epartIsReg(modrm)) {
9554 delta += 2+1;
9555 assign(f64lo, getXMMRegLane64F(eregOfRexRM(pfx,modrm), 0));
9556 DIP("cvt%ssd2si %s,%s\n", r2zero ? "t" : "",
9557 nameXMMReg(eregOfRexRM(pfx,modrm)),
sewardj5b470602005-02-27 13:10:48 +00009558 nameIReg(sz, gregOfRexRM(pfx,modrm), False));
sewardj1a01e652005-02-23 11:39:21 +00009559 } else {
9560 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9561 assign(f64lo, loadLE(Ity_F64, mkexpr(addr)));
9562 delta += 2+alen;
9563 DIP("cvt%ssd2si %s,%s\n", r2zero ? "t" : "",
9564 dis_buf,
sewardj5b470602005-02-27 13:10:48 +00009565 nameIReg(sz, gregOfRexRM(pfx,modrm), False));
sewardj1a01e652005-02-23 11:39:21 +00009566 }
9567
9568 if (r2zero) {
9569 assign( rmode, mkU32((UInt)Irrm_ZERO) );
9570 } else {
9571 assign( rmode, get_sse_roundingmode() );
9572 }
9573
9574 if (sz == 4) {
sewardj5b470602005-02-27 13:10:48 +00009575 putIReg32( gregOfRexRM(pfx,modrm),
9576 binop( Iop_F64toI32, mkexpr(rmode), mkexpr(f64lo)) );
sewardj1a01e652005-02-23 11:39:21 +00009577 } else {
sewardj5b470602005-02-27 13:10:48 +00009578 putIReg64( gregOfRexRM(pfx,modrm),
9579 binop( Iop_F64toI64, mkexpr(rmode), mkexpr(f64lo)) );
sewardj1a01e652005-02-23 11:39:21 +00009580 }
9581
9582 goto decode_success;
9583 }
9584
sewardj8d965312005-02-25 02:48:47 +00009585 /* F2 0F 5A = CVTSD2SS -- convert F64 in mem/low half xmm to F32 in
9586 low 1/4 xmm(G), according to prevailing SSE rounding mode */
9587 if (haveF2no66noF3(pfx) && sz == 4
9588 && insn[0] == 0x0F && insn[1] == 0x5A) {
9589 IRTemp rmode = newTemp(Ity_I32);
9590 IRTemp f64lo = newTemp(Ity_F64);
9591 vassert(sz == 4);
9592
9593 modrm = getUChar(delta+2);
9594 if (epartIsReg(modrm)) {
9595 delta += 2+1;
9596 assign(f64lo, getXMMRegLane64F(eregOfRexRM(pfx,modrm), 0));
9597 DIP("cvtsd2ss %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
9598 nameXMMReg(gregOfRexRM(pfx,modrm)));
9599 } else {
9600 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9601 assign(f64lo, loadLE(Ity_F64, mkexpr(addr)));
9602 delta += 2+alen;
9603 DIP("cvtsd2ss %s,%s\n", dis_buf,
9604 nameXMMReg(gregOfRexRM(pfx,modrm)));
9605 }
9606
9607 assign( rmode, get_sse_roundingmode() );
9608 putXMMRegLane32F(
9609 gregOfRexRM(pfx,modrm), 0,
9610 binop( Iop_F64toF32, mkexpr(rmode), mkexpr(f64lo) )
9611 );
9612
9613 goto decode_success;
9614 }
sewardj1a01e652005-02-23 11:39:21 +00009615
9616 /* F2 0F 2A = CVTSI2SD
9617 when sz==4 -- convert I32 in mem/ireg to F64 in low half xmm
9618 when sz==8 -- convert I64 in mem/ireg to F64 in low half xmm
9619 */
sewardj8d965312005-02-25 02:48:47 +00009620 if (haveF2no66noF3(pfx) && (sz == 4 || sz == 8)
9621 && insn[0] == 0x0F && insn[1] == 0x2A) {
sewardj1a01e652005-02-23 11:39:21 +00009622 modrm = getUChar(delta+2);
9623
9624 if (sz == 4) {
9625 IRTemp arg32 = newTemp(Ity_I32);
9626 if (epartIsReg(modrm)) {
sewardj5b470602005-02-27 13:10:48 +00009627 assign( arg32, getIReg32(eregOfRexRM(pfx,modrm)) );
sewardj1a01e652005-02-23 11:39:21 +00009628 delta += 2+1;
sewardj5b470602005-02-27 13:10:48 +00009629 DIP("cvtsi2sd %s,%s\n", nameIReg32(eregOfRexRM(pfx,modrm)),
sewardj1a01e652005-02-23 11:39:21 +00009630 nameXMMReg(gregOfRexRM(pfx,modrm)));
9631 } else {
9632 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9633 assign( arg32, loadLE(Ity_I32, mkexpr(addr)) );
9634 delta += 2+alen;
9635 DIP("cvtsi2sd %s,%s\n", dis_buf,
9636 nameXMMReg(gregOfRexRM(pfx,modrm)) );
9637 }
9638 putXMMRegLane64F( gregOfRexRM(pfx,modrm), 0,
9639 unop(Iop_I32toF64, mkexpr(arg32))
9640 );
9641 } else {
9642 /* sz == 8 */
9643 IRTemp arg64 = newTemp(Ity_I64);
9644 if (epartIsReg(modrm)) {
sewardj5b470602005-02-27 13:10:48 +00009645 assign( arg64, getIReg64(eregOfRexRM(pfx,modrm)) );
sewardj1a01e652005-02-23 11:39:21 +00009646 delta += 2+1;
sewardj5b470602005-02-27 13:10:48 +00009647 DIP("cvtsi2sdq %s,%s\n", nameIReg64(eregOfRexRM(pfx,modrm)),
sewardj8d965312005-02-25 02:48:47 +00009648 nameXMMReg(gregOfRexRM(pfx,modrm)));
sewardj1a01e652005-02-23 11:39:21 +00009649 } else {
9650 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9651 assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
9652 delta += 2+alen;
sewardj8d965312005-02-25 02:48:47 +00009653 DIP("cvtsi2sdq %s,%s\n", dis_buf,
9654 nameXMMReg(gregOfRexRM(pfx,modrm)) );
sewardj1a01e652005-02-23 11:39:21 +00009655 }
9656 putXMMRegLane64F(
9657 gregOfRexRM(pfx,modrm),
9658 0,
9659 binop( Iop_I64toF64,
9660 get_sse_roundingmode(),
9661 mkexpr(arg64)
9662 )
9663 );
9664
9665 }
9666
9667 goto decode_success;
9668 }
9669
sewardjc49ce232005-02-25 13:03:03 +00009670 /* F3 0F 5A = CVTSS2SD -- convert F32 in mem/low 1/4 xmm to F64 in
9671 low half xmm(G) */
9672 if (haveF3no66noF2(pfx) && sz == 4
9673 && insn[0] == 0x0F && insn[1] == 0x5A) {
9674 IRTemp f32lo = newTemp(Ity_F32);
9675
9676 modrm = getUChar(delta+2);
9677 if (epartIsReg(modrm)) {
9678 delta += 2+1;
9679 assign(f32lo, getXMMRegLane32F(eregOfRexRM(pfx,modrm), 0));
9680 DIP("cvtss2sd %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
9681 nameXMMReg(gregOfRexRM(pfx,modrm)));
9682 } else {
9683 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9684 assign(f32lo, loadLE(Ity_F32, mkexpr(addr)));
9685 delta += 2+alen;
9686 DIP("cvtss2sd %s,%s\n", dis_buf,
9687 nameXMMReg(gregOfRexRM(pfx,modrm)));
9688 }
9689
9690 putXMMRegLane64F( gregOfRexRM(pfx,modrm), 0,
9691 unop( Iop_F32toF64, mkexpr(f32lo) ) );
9692
9693 goto decode_success;
9694 }
9695
sewardj5992bd02005-05-11 02:13:42 +00009696 /* 66 0F 5E = DIVPD -- div 64Fx2 from R/M to R */
9697 if (have66noF2noF3(pfx) && sz == 2
9698 && insn[0] == 0x0F && insn[1] == 0x5E) {
9699 delta = dis_SSE_E_to_G_all( pfx, delta+2, "divpd", Iop_Div64Fx2 );
9700 goto decode_success;
9701 }
sewardj1001dc42005-02-21 08:25:55 +00009702
9703 /* F2 0F 5E = DIVSD -- div 64F0x2 from R/M to R */
9704 if (haveF2no66noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x5E) {
9705 vassert(sz == 4);
9706 delta = dis_SSE_E_to_G_lo64( pfx, delta+2, "divsd", Iop_Div64F0x2 );
9707 goto decode_success;
9708 }
9709
sewardj5992bd02005-05-11 02:13:42 +00009710 /* 0F AE /5 = LFENCE -- flush pending operations to memory */
9711 /* 0F AE /6 = MFENCE -- flush pending operations to memory */
9712 if (haveNo66noF2noF3(pfx) && sz == 4
9713 && insn[0] == 0x0F && insn[1] == 0xAE
9714 && epartIsReg(insn[2])
9715 && (gregLO3ofRM(insn[2]) == 5 || gregLO3ofRM(insn[2]) == 6)) {
9716 delta += 3;
9717 /* Insert a memory fence. It's sometimes important that these
9718 are carried through to the generated code. */
9719 stmt( IRStmt_MFence() );
9720 DIP("%sfence\n", gregLO3ofRM(insn[2])==5 ? "l" : "m");
9721 goto decode_success;
9722 }
9723
9724 /* 66 0F 5F = MAXPD -- max 64Fx2 from R/M to R */
9725 if (have66noF2noF3(pfx) && sz == 2
9726 && insn[0] == 0x0F && insn[1] == 0x5F) {
9727 delta = dis_SSE_E_to_G_all( pfx, delta+2, "maxpd", Iop_Max64Fx2 );
9728 goto decode_success;
9729 }
sewardj1a01e652005-02-23 11:39:21 +00009730
9731 /* F2 0F 5F = MAXSD -- max 64F0x2 from R/M to R */
9732 if (haveF2no66noF3(pfx) && sz == 4
9733 && insn[0] == 0x0F && insn[1] == 0x5F) {
9734 delta = dis_SSE_E_to_G_lo64( pfx, delta+2, "maxsd", Iop_Max64F0x2 );
9735 goto decode_success;
9736 }
9737
sewardj5992bd02005-05-11 02:13:42 +00009738 /* 66 0F 5D = MINPD -- min 64Fx2 from R/M to R */
9739 if (have66noF2noF3(pfx) && sz == 2
9740 && insn[0] == 0x0F && insn[1] == 0x5D) {
9741 delta = dis_SSE_E_to_G_all( pfx, delta+2, "minpd", Iop_Min64Fx2 );
9742 goto decode_success;
9743 }
sewardjc49ce232005-02-25 13:03:03 +00009744
9745 /* F2 0F 5D = MINSD -- min 64F0x2 from R/M to R */
9746 if (haveF2no66noF3(pfx) && sz == 4
9747 && insn[0] == 0x0F && insn[1] == 0x5D) {
9748 delta = dis_SSE_E_to_G_lo64( pfx, delta+2, "minsd", Iop_Min64F0x2 );
9749 goto decode_success;
9750 }
sewardj8d965312005-02-25 02:48:47 +00009751
9752 /* 66 0F 28 = MOVAPD -- move from E (mem or xmm) to G (xmm). */
9753 /* 66 0F 10 = MOVUPD -- move from E (mem or xmm) to G (xmm). */
9754 /* 66 0F 6F = MOVDQA -- move from E (mem or xmm) to G (xmm). */
9755 if (have66noF2noF3(pfx) && sz == 2
9756 && insn[0] == 0x0F
9757 && (insn[1] == 0x28 || insn[1] == 0x10 || insn[1] == 0x6F)) {
9758 HChar* wot = insn[1]==0x28 ? "apd" :
9759 insn[1]==0x10 ? "upd" : "dqa";
9760 modrm = getUChar(delta+2);
9761 if (epartIsReg(modrm)) {
9762 putXMMReg( gregOfRexRM(pfx,modrm),
9763 getXMMReg( eregOfRexRM(pfx,modrm) ));
9764 DIP("mov%s %s,%s\n", wot, nameXMMReg(eregOfRexRM(pfx,modrm)),
9765 nameXMMReg(gregOfRexRM(pfx,modrm)));
9766 delta += 2+1;
9767 } else {
9768 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9769 putXMMReg( gregOfRexRM(pfx,modrm),
9770 loadLE(Ity_V128, mkexpr(addr)) );
9771 DIP("mov%s %s,%s\n", wot, dis_buf,
9772 nameXMMReg(gregOfRexRM(pfx,modrm)));
9773 delta += 2+alen;
9774 }
9775 goto decode_success;
9776 }
9777
sewardj4c328cf2005-05-05 12:05:54 +00009778 /* 66 0F 29 = MOVAPD -- move from G (xmm) to E (mem or xmm). */
9779 if (have66noF2noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x29) {
9780 modrm = getUChar(delta+2);
9781 if (epartIsReg(modrm)) {
9782 /* fall through; awaiting test case */
9783 } else {
9784 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9785 storeLE( mkexpr(addr), getXMMReg(gregOfRexRM(pfx,modrm)) );
9786 DIP("movapd %s,%s\n", nameXMMReg(gregOfRexRM(pfx,modrm)),
9787 dis_buf );
9788 delta += 2+alen;
9789 goto decode_success;
9790 }
9791 }
9792
sewardj09717342005-05-05 21:34:02 +00009793 /* 66 0F 6E = MOVD from ireg32/m32 to xmm lo 1/4, zeroing high 3/4 of xmm. */
9794 /* or from ireg64/m64 to xmm lo 1/2, zeroing high 1/2 of xmm. */
9795 if (have66noF2noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x6E) {
sewardj97628592005-05-10 22:42:54 +00009796 vassert(sz == 2 || sz == 8);
9797 if (sz == 2) sz = 4;
sewardj09717342005-05-05 21:34:02 +00009798 modrm = getUChar(delta+2);
9799 if (epartIsReg(modrm)) {
9800 delta += 2+1;
9801 if (sz == 4) {
sewardj09717342005-05-05 21:34:02 +00009802 putXMMReg(
9803 gregOfRexRM(pfx,modrm),
9804 unop( Iop_32UtoV128, getIReg32(eregOfRexRM(pfx,modrm)) )
9805 );
9806 DIP("movd %s, %s\n", nameIReg32(eregOfRexRM(pfx,modrm)),
9807 nameXMMReg(gregOfRexRM(pfx,modrm)));
9808 } else {
9809 putXMMReg(
9810 gregOfRexRM(pfx,modrm),
9811 unop( Iop_64UtoV128, getIReg64(eregOfRexRM(pfx,modrm)) )
9812 );
9813 DIP("movq %s, %s\n", nameIReg64(eregOfRexRM(pfx,modrm)),
9814 nameXMMReg(gregOfRexRM(pfx,modrm)));
9815 }
9816 } else {
9817 addr = disAMode( &alen, pfx, delta+2, dis_buf, 0 );
9818 delta += 2+alen;
9819 putXMMReg(
9820 gregOfRexRM(pfx,modrm),
9821 sz == 4
9822 ? unop( Iop_32UtoV128,loadLE(Ity_I32, mkexpr(addr)) )
9823 : unop( Iop_64UtoV128,loadLE(Ity_I64, mkexpr(addr)) )
9824 );
9825 DIP("mov%c %s, %s\n", sz == 4 ? 'd' : 'q', dis_buf,
9826 nameXMMReg(gregOfRexRM(pfx,modrm)));
9827 }
9828 goto decode_success;
9829 }
9830
9831 /* 66 0F 7E = MOVD from xmm low 1/4 to ireg32 or m32. */
9832 /* or from xmm low 1/2 to ireg64 or m64. */
9833 if (have66noF2noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x7E) {
9834 if (sz == 2) sz = 4;
9835 vassert(sz == 4 || sz == 8);
9836 modrm = getUChar(delta+2);
9837 if (epartIsReg(modrm)) {
9838 delta += 2+1;
9839 if (sz == 4) {
9840 putIReg32( eregOfRexRM(pfx,modrm),
9841 getXMMRegLane32(gregOfRexRM(pfx,modrm), 0) );
9842 DIP("movd %s, %s\n", nameXMMReg(gregOfRexRM(pfx,modrm)),
9843 nameIReg32(eregOfRexRM(pfx,modrm)));
9844 } else {
9845 putIReg64( eregOfRexRM(pfx,modrm),
9846 getXMMRegLane64(gregOfRexRM(pfx,modrm), 0) );
9847 DIP("movq %s, %s\n", nameXMMReg(gregOfRexRM(pfx,modrm)),
9848 nameIReg64(eregOfRexRM(pfx,modrm)));
9849 }
9850 } else {
9851 addr = disAMode( &alen, pfx, delta+2, dis_buf, 0 );
9852 delta += 2+alen;
9853 storeLE( mkexpr(addr),
9854 sz == 4
9855 ? getXMMRegLane32(gregOfRexRM(pfx,modrm),0)
9856 : getXMMRegLane64(gregOfRexRM(pfx,modrm),0) );
9857 DIP("mov%c %s, %s\n", sz == 4 ? 'd' : 'q',
9858 nameXMMReg(gregOfRexRM(pfx,modrm)), dis_buf);
9859 }
9860 goto decode_success;
9861 }
9862
9863 /* 66 0F 7F = MOVDQA -- move from G (xmm) to E (mem or xmm). */
9864 if (have66noF2noF3(pfx) && sz == 2
9865 && insn[0] == 0x0F && insn[1] == 0x7F) {
9866 modrm = getUChar(delta+2);
9867 if (epartIsReg(modrm)) {
9868 delta += 2+1;
9869 putXMMReg( eregOfRexRM(pfx,modrm),
9870 getXMMReg(gregOfRexRM(pfx,modrm)) );
9871 DIP("movdqa %s, %s\n", nameXMMReg(gregOfRexRM(pfx,modrm)),
9872 nameXMMReg(eregOfRexRM(pfx,modrm)));
9873 } else {
9874 addr = disAMode( &alen, pfx, delta+2, dis_buf, 0 );
9875 delta += 2+alen;
9876 storeLE( mkexpr(addr), getXMMReg(gregOfRexRM(pfx,modrm)) );
9877 DIP("movdqa %s, %s\n", nameXMMReg(gregOfRexRM(pfx,modrm)), dis_buf);
9878 }
9879 goto decode_success;
9880 }
9881
sewardj612be432005-05-11 02:55:54 +00009882 /* F3 0F 6F = MOVDQU -- move from E (mem or xmm) to G (xmm). */
9883 if (haveF3no66noF2(pfx) && sz == 4
9884 && insn[0] == 0x0F && insn[1] == 0x6F) {
9885 modrm = getUChar(delta+2);
9886 if (epartIsReg(modrm)) {
9887 putXMMReg( gregOfRexRM(pfx,modrm),
9888 getXMMReg( eregOfRexRM(pfx,modrm) ));
9889 DIP("movdqu %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
9890 nameXMMReg(gregOfRexRM(pfx,modrm)));
9891 delta += 2+1;
9892 } else {
9893 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9894 putXMMReg( gregOfRexRM(pfx,modrm),
9895 loadLE(Ity_V128, mkexpr(addr)) );
9896 DIP("movdqu %s,%s\n", dis_buf,
9897 nameXMMReg(gregOfRexRM(pfx,modrm)));
9898 delta += 2+alen;
9899 }
9900 goto decode_success;
9901 }
9902
9903 /* F3 0F 7F = MOVDQU -- move from G (xmm) to E (mem or xmm). */
9904 if (haveF3no66noF2(pfx) && sz == 4
9905 && insn[0] == 0x0F && insn[1] == 0x7F) {
9906 modrm = getUChar(delta+2);
9907 if (epartIsReg(modrm)) {
9908 goto decode_failure; /* awaiting test case */
9909 delta += 2+1;
9910 putXMMReg( eregOfRexRM(pfx,modrm),
9911 getXMMReg(gregOfRexRM(pfx,modrm)) );
9912 DIP("movdqu %s, %s\n", nameXMMReg(gregOfRexRM(pfx,modrm)),
9913 nameXMMReg(eregOfRexRM(pfx,modrm)));
9914 } else {
9915 addr = disAMode( &alen, pfx, delta+2, dis_buf, 0 );
9916 delta += 2+alen;
9917 storeLE( mkexpr(addr), getXMMReg(gregOfRexRM(pfx,modrm)) );
9918 DIP("movdqu %s, %s\n", nameXMMReg(gregOfRexRM(pfx,modrm)), dis_buf);
9919 }
9920 goto decode_success;
9921 }
9922
9923 /* F2 0F D6 = MOVDQ2Q -- move from E (lo half xmm, not mem) to G (mmx). */
9924 if (haveF2no66noF3(pfx) && sz == 4
9925 && insn[0] == 0x0F && insn[1] == 0xD6) {
9926 modrm = getUChar(delta+2);
9927 if (epartIsReg(modrm)) {
9928 do_MMX_preamble();
9929 putMMXReg( gregLO3ofRM(modrm),
9930 getXMMRegLane64( eregOfRexRM(pfx,modrm), 0 ));
9931 DIP("movdq2q %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
9932 nameMMXReg(gregLO3ofRM(modrm)));
9933 delta += 2+1;
9934 goto decode_success;
9935 } else {
9936 /* apparently no mem case for this insn */
9937 goto decode_failure;
9938 }
9939 }
sewardj4c328cf2005-05-05 12:05:54 +00009940
9941 /* 66 0F 16 = MOVHPD -- move from mem to high half of XMM. */
9942 /* These seems identical to MOVHPS. This instruction encoding is
9943 completely crazy. */
9944 if (have66noF2noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x16) {
9945 modrm = getUChar(delta+2);
9946 if (epartIsReg(modrm)) {
9947 /* fall through; apparently reg-reg is not possible */
9948 } else {
9949 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9950 delta += 2+alen;
9951 putXMMRegLane64( gregOfRexRM(pfx,modrm), 1/*upper lane*/,
9952 loadLE(Ity_I64, mkexpr(addr)) );
9953 DIP("movhpd %s,%s\n", dis_buf,
9954 nameXMMReg( gregOfRexRM(pfx,modrm) ));
9955 goto decode_success;
9956 }
9957 }
9958
9959 /* 66 0F 17 = MOVHPD -- move from high half of XMM to mem. */
9960 /* Again, this seems identical to MOVHPS. */
9961 if (have66noF2noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x17) {
9962 if (!epartIsReg(insn[2])) {
9963 delta += 2;
9964 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
9965 delta += alen;
9966 storeLE( mkexpr(addr),
9967 getXMMRegLane64( gregOfRexRM(pfx,insn[2]),
9968 1/*upper lane*/ ) );
9969 DIP("movhpd %s,%s\n", nameXMMReg( gregOfRexRM(pfx,insn[2]) ),
9970 dis_buf);
9971 goto decode_success;
9972 }
9973 /* else fall through */
9974 }
sewardj1001dc42005-02-21 08:25:55 +00009975
9976 /* 66 0F 12 = MOVLPD -- move from mem to low half of XMM. */
9977 /* Identical to MOVLPS ? */
9978 if (have66noF2noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x12) {
9979 modrm = getUChar(delta+2);
9980 if (epartIsReg(modrm)) {
9981 /* fall through; apparently reg-reg is not possible */
9982 } else {
9983 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9984 delta += 2+alen;
9985 putXMMRegLane64( gregOfRexRM(pfx,modrm),
9986 0/*lower lane*/,
9987 loadLE(Ity_I64, mkexpr(addr)) );
9988 DIP("movlpd %s, %s\n",
9989 dis_buf, nameXMMReg( gregOfRexRM(pfx,modrm) ));
9990 goto decode_success;
9991 }
9992 }
9993
sewardj4c328cf2005-05-05 12:05:54 +00009994 /* 66 0F 13 = MOVLPD -- move from low half of XMM to mem. */
9995 /* Identical to MOVLPS ? */
9996 if (have66noF2noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x13) {
9997 modrm = getUChar(delta+2);
9998 if (!epartIsReg(modrm)) {
9999 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10000 delta += 2+alen;
10001 storeLE( mkexpr(addr),
10002 getXMMRegLane64( gregOfRexRM(pfx,modrm),
10003 0/*lower lane*/ ) );
10004 DIP("movlpd %s, %s\n", nameXMMReg( gregOfRexRM(pfx,modrm) ),
10005 dis_buf);
10006 goto decode_success;
10007 }
10008 /* else fall through */
10009 }
10010
sewardj612be432005-05-11 02:55:54 +000010011 /* 66 0F 50 = MOVMSKPD - move 2 sign bits from 2 x F64 in xmm(E) to
10012 2 lowest bits of ireg(G) */
10013 if (have66noF2noF3(pfx) && sz == 2
10014 && insn[0] == 0x0F && insn[1] == 0x50) {
10015 modrm = getUChar(delta+2);
10016 if (epartIsReg(modrm)) {
10017 Int src;
10018 t0 = newTemp(Ity_I32);
10019 t1 = newTemp(Ity_I32);
10020 delta += 2+1;
10021 src = eregOfRexRM(pfx,modrm);
10022 assign( t0, binop( Iop_And32,
10023 binop(Iop_Shr32, getXMMRegLane32(src,1), mkU8(31)),
10024 mkU32(1) ));
10025 assign( t1, binop( Iop_And32,
10026 binop(Iop_Shr32, getXMMRegLane32(src,3), mkU8(30)),
10027 mkU32(2) ));
10028 putIReg32( gregOfRexRM(pfx,modrm),
10029 binop(Iop_Or32, mkexpr(t0), mkexpr(t1))
10030 );
10031 DIP("movmskpd %s,%s\n", nameXMMReg(src),
10032 nameIReg32(gregOfRexRM(pfx,modrm)));
10033 goto decode_success;
10034 }
10035 /* else fall through */
10036 goto decode_failure;
10037 }
10038
10039 /* 66 0F E7 = MOVNTDQ -- for us, just a plain SSE store. */
10040 if (have66noF2noF3(pfx) && sz == 2
10041 && insn[0] == 0x0F && insn[1] == 0xE7) {
10042 modrm = getUChar(delta+2);
10043 if (!epartIsReg(modrm)) {
10044 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10045 storeLE( mkexpr(addr), getXMMReg(gregOfRexRM(pfx,modrm)) );
10046 DIP("movntdq %s,%s\n", dis_buf,
10047 nameXMMReg(gregOfRexRM(pfx,modrm)));
10048 delta += 2+alen;
10049 goto decode_success;
10050 }
10051 /* else fall through */
10052 goto decode_failure;
10053 }
sewardjf53b7352005-04-06 20:01:56 +000010054
10055 /* 0F C3 = MOVNTI -- for us, just a plain ireg store. */
10056 if (haveNo66noF2noF3(pfx) &&
10057 insn[0] == 0x0F && insn[1] == 0xC3) {
10058 vassert(sz == 4 || sz == 8);
10059 modrm = getUChar(delta+2);
10060 if (!epartIsReg(modrm)) {
10061 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10062 storeLE( mkexpr(addr), getIRegG(sz, pfx, modrm) );
10063 DIP("movnti %s,%s\n", dis_buf,
10064 nameIRegG(sz, pfx, modrm));
10065 delta += 2+alen;
10066 goto decode_success;
10067 }
10068 /* else fall through */
10069 }
sewardj5cc00ff2005-03-27 04:48:32 +000010070
10071 /* 66 0F D6 = MOVQ -- move 64 bits from G (lo half xmm) to E (mem
10072 or lo half xmm). */
10073 if (have66noF2noF3(pfx) && insn[0] == 0x0F && insn[1] == 0xD6) {
10074 vassert(sz == 2);
10075 modrm = getUChar(delta+2);
10076 if (epartIsReg(modrm)) {
10077 /* fall through, awaiting test case */
sewardj94a48b22005-05-14 11:17:25 +000010078 /* dst: lo half copied, hi half zeroed */
sewardj5cc00ff2005-03-27 04:48:32 +000010079 } else {
10080 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10081 storeLE( mkexpr(addr),
10082 getXMMRegLane64( gregOfRexRM(pfx,modrm), 0 ));
10083 DIP("movq %s,%s\n", nameXMMReg(gregOfRexRM(pfx,modrm)), dis_buf );
10084 delta += 2+alen;
10085 goto decode_success;
10086 }
10087 }
10088
sewardj612be432005-05-11 02:55:54 +000010089 /* F3 0F D6 = MOVQ2DQ -- move from E (mmx) to G (lo half xmm, zero
10090 hi half). */
10091 if (haveF3no66noF2(pfx) && sz == 4
10092 && insn[0] == 0x0F && insn[1] == 0xD6) {
10093 modrm = getUChar(delta+2);
10094 if (epartIsReg(modrm)) {
10095 do_MMX_preamble();
10096 putXMMReg( gregOfRexRM(pfx,modrm),
10097 unop(Iop_64UtoV128, getMMXReg( eregLO3ofRM(modrm) )) );
10098 DIP("movq2dq %s,%s\n", nameMMXReg(eregLO3ofRM(modrm)),
10099 nameXMMReg(gregOfRexRM(pfx,modrm)));
10100 delta += 2+1;
10101 goto decode_success;
10102 } else {
10103 /* apparently no mem case for this insn */
10104 goto decode_failure;
10105 }
10106 }
10107
10108 /* F3 0F 7E = MOVQ -- move 64 bits from E (mem or lo half xmm) to
sewardj94a48b22005-05-14 11:17:25 +000010109 G (lo half xmm). Upper half of G is zeroed out. */
sewardj1001dc42005-02-21 08:25:55 +000010110 /* F2 0F 10 = MOVSD -- move 64 bits from E (mem or lo half xmm) to
10111 G (lo half xmm). If E is mem, upper half of G is zeroed out.
sewardj94a48b22005-05-14 11:17:25 +000010112 If E is reg, upper half of G is unchanged. */
sewardj612be432005-05-11 02:55:54 +000010113 if ( (haveF2no66noF3(pfx) && sz == 4
10114 && insn[0] == 0x0F && insn[1] == 0x10)
sewardj5cc00ff2005-03-27 04:48:32 +000010115 ||
sewardj612be432005-05-11 02:55:54 +000010116 (haveF3no66noF2(pfx) && sz == 4
10117 && insn[0] == 0x0F && insn[1] == 0x7E)
sewardj1001dc42005-02-21 08:25:55 +000010118 ) {
sewardj1001dc42005-02-21 08:25:55 +000010119 modrm = getUChar(delta+2);
10120 if (epartIsReg(modrm)) {
10121 putXMMRegLane64( gregOfRexRM(pfx,modrm), 0,
10122 getXMMRegLane64( eregOfRexRM(pfx,modrm), 0 ));
sewardj94a48b22005-05-14 11:17:25 +000010123 if (insn[1] == 0x7E/*MOVQ*/) {
10124 /* zero bits 127:64 */
10125 putXMMRegLane64( gregOfRexRM(pfx,modrm), 1, mkU64(0) );
10126 }
sewardj1001dc42005-02-21 08:25:55 +000010127 DIP("movsd %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
10128 nameXMMReg(gregOfRexRM(pfx,modrm)));
10129 delta += 2+1;
10130 } else {
10131 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10132 putXMMReg( gregOfRexRM(pfx,modrm), mkV128(0) );
10133 putXMMRegLane64( gregOfRexRM(pfx,modrm), 0,
10134 loadLE(Ity_I64, mkexpr(addr)) );
10135 DIP("movsd %s,%s\n", dis_buf,
10136 nameXMMReg(gregOfRexRM(pfx,modrm)));
10137 delta += 2+alen;
10138 }
10139 goto decode_success;
10140 }
10141
10142 /* F2 0F 11 = MOVSD -- move 64 bits from G (lo half xmm) to E (mem
10143 or lo half xmm). */
sewardj8d965312005-02-25 02:48:47 +000010144 if (haveF2no66noF3(pfx) && sz == 4
10145 && insn[0] == 0x0F && insn[1] == 0x11) {
sewardj1001dc42005-02-21 08:25:55 +000010146 modrm = getUChar(delta+2);
10147 if (epartIsReg(modrm)) {
10148 /* fall through, we don't yet have a test case */
10149 } else {
10150 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10151 storeLE( mkexpr(addr),
10152 getXMMRegLane64(gregOfRexRM(pfx,modrm), 0) );
10153 DIP("movsd %s,%s\n", nameXMMReg(gregOfRexRM(pfx,modrm)),
10154 dis_buf);
10155 delta += 2+alen;
10156 goto decode_success;
10157 }
10158 }
10159
sewardj4c328cf2005-05-05 12:05:54 +000010160 /* 66 0F 59 = MULPD -- mul 64Fx2 from R/M to R */
10161 if (have66noF2noF3(pfx) && sz == 2
10162 && insn[0] == 0x0F && insn[1] == 0x59) {
10163 delta = dis_SSE_E_to_G_all( pfx, delta+2, "mulpd", Iop_Mul64Fx2 );
10164 goto decode_success;
10165 }
sewardj1001dc42005-02-21 08:25:55 +000010166
10167 /* F2 0F 59 = MULSD -- mul 64F0x2 from R/M to R */
sewardj8d965312005-02-25 02:48:47 +000010168 if (haveF2no66noF3(pfx) && sz == 4
10169 && insn[0] == 0x0F && insn[1] == 0x59) {
sewardj1001dc42005-02-21 08:25:55 +000010170 delta = dis_SSE_E_to_G_lo64( pfx, delta+2, "mulsd", Iop_Mul64F0x2 );
10171 goto decode_success;
10172 }
10173
sewardj8d965312005-02-25 02:48:47 +000010174 /* 66 0F 56 = ORPD -- G = G and E */
10175 if (have66noF2noF3(pfx) && sz == 2
10176 && insn[0] == 0x0F && insn[1] == 0x56) {
10177 delta = dis_SSE_E_to_G_all( pfx, delta+2, "orpd", Iop_OrV128 );
10178 goto decode_success;
10179 }
10180
sewardj09717342005-05-05 21:34:02 +000010181 /* 66 0F C6 /r ib = SHUFPD -- shuffle packed F64s */
10182 if (have66noF2noF3(pfx) && sz == 2
10183 && insn[0] == 0x0F && insn[1] == 0xC6) {
10184 Int select;
10185 IRTemp sV = newTemp(Ity_V128);
10186 IRTemp dV = newTemp(Ity_V128);
10187 IRTemp s1 = newTemp(Ity_I64);
10188 IRTemp s0 = newTemp(Ity_I64);
10189 IRTemp d1 = newTemp(Ity_I64);
10190 IRTemp d0 = newTemp(Ity_I64);
10191
10192 modrm = insn[2];
10193 assign( dV, getXMMReg(gregOfRexRM(pfx,modrm)) );
10194
10195 if (epartIsReg(modrm)) {
10196 assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
10197 select = (Int)insn[3];
10198 delta += 2+2;
10199 DIP("shufpd $%d,%s,%s\n", select,
10200 nameXMMReg(eregOfRexRM(pfx,modrm)),
10201 nameXMMReg(gregOfRexRM(pfx,modrm)));
10202 } else {
10203 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 1 );
10204 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
10205 select = (Int)insn[2+alen];
10206 delta += 3+alen;
10207 DIP("shufpd $%d,%s,%s\n", select,
10208 dis_buf,
10209 nameXMMReg(gregOfRexRM(pfx,modrm)));
10210 }
10211
10212 assign( d1, unop(Iop_V128HIto64, mkexpr(dV)) );
10213 assign( d0, unop(Iop_V128to64, mkexpr(dV)) );
10214 assign( s1, unop(Iop_V128HIto64, mkexpr(sV)) );
10215 assign( s0, unop(Iop_V128to64, mkexpr(sV)) );
10216
10217# define SELD(n) mkexpr((n)==0 ? d0 : d1)
10218# define SELS(n) mkexpr((n)==0 ? s0 : s1)
10219
10220 putXMMReg(
10221 gregOfRexRM(pfx,modrm),
10222 binop(Iop_64HLtoV128, SELS((select>>1)&1), SELD((select>>0)&1) )
10223 );
10224
10225# undef SELD
10226# undef SELS
10227
10228 goto decode_success;
10229 }
10230
sewardj97628592005-05-10 22:42:54 +000010231 /* 66 0F 51 = SQRTPD -- approx sqrt 64Fx2 from R/M to R */
10232 if (have66noF2noF3(pfx) && sz == 2
10233 && insn[0] == 0x0F && insn[1] == 0x51) {
10234 delta = dis_SSE_E_to_G_unary_all( pfx, delta+2,
10235 "sqrtpd", Iop_Sqrt64Fx2 );
10236 goto decode_success;
10237 }
sewardj1001dc42005-02-21 08:25:55 +000010238
10239 /* F2 0F 51 = SQRTSD -- approx sqrt 64F0x2 from R/M to R */
10240 if (haveF2no66noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x51) {
10241 vassert(sz == 4);
10242 delta = dis_SSE_E_to_G_unary_lo64( pfx, delta+2,
10243 "sqrtsd", Iop_Sqrt64F0x2 );
10244 goto decode_success;
10245 }
10246
sewardj4c328cf2005-05-05 12:05:54 +000010247 /* 66 0F 5C = SUBPD -- sub 64Fx2 from R/M to R */
10248 if (have66noF2noF3(pfx) && sz == 2
10249 && insn[0] == 0x0F && insn[1] == 0x5C) {
10250 delta = dis_SSE_E_to_G_all( pfx, delta+2, "subpd", Iop_Sub64Fx2 );
10251 goto decode_success;
10252 }
sewardj1001dc42005-02-21 08:25:55 +000010253
10254 /* F2 0F 5C = SUBSD -- sub 64F0x2 from R/M to R */
10255 if (haveF2no66noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x5C) {
10256 vassert(sz == 4);
10257 delta = dis_SSE_E_to_G_lo64( pfx, delta+2, "subsd", Iop_Sub64F0x2 );
10258 goto decode_success;
10259 }
10260
sewardj1a01e652005-02-23 11:39:21 +000010261 /* 66 0F 15 = UNPCKHPD -- unpack and interleave high part F64s */
10262 /* 66 0F 14 = UNPCKLPD -- unpack and interleave low part F64s */
10263 /* These just appear to be special cases of SHUFPS */
10264 if (have66noF2noF3(pfx)
10265 && sz == 2 /* could be 8 if rex also present */
10266 && insn[0] == 0x0F && (insn[1] == 0x15 || insn[1] == 0x14)) {
10267 IRTemp s1 = newTemp(Ity_I64);
10268 IRTemp s0 = newTemp(Ity_I64);
10269 IRTemp d1 = newTemp(Ity_I64);
10270 IRTemp d0 = newTemp(Ity_I64);
10271 IRTemp sV = newTemp(Ity_V128);
10272 IRTemp dV = newTemp(Ity_V128);
sewardj1027dc22005-02-26 01:55:02 +000010273 Bool hi = toBool(insn[1] == 0x15);
sewardj1a01e652005-02-23 11:39:21 +000010274
10275 modrm = insn[2];
10276 assign( dV, getXMMReg(gregOfRexRM(pfx,modrm)) );
10277
10278 if (epartIsReg(modrm)) {
10279 assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
10280 delta += 2+1;
10281 DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
10282 nameXMMReg(eregOfRexRM(pfx,modrm)),
10283 nameXMMReg(gregOfRexRM(pfx,modrm)));
10284 } else {
10285 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10286 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
10287 delta += 2+alen;
10288 DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
10289 dis_buf,
10290 nameXMMReg(gregOfRexRM(pfx,modrm)));
10291 }
10292
10293 assign( d1, unop(Iop_V128HIto64, mkexpr(dV)) );
10294 assign( d0, unop(Iop_V128to64, mkexpr(dV)) );
10295 assign( s1, unop(Iop_V128HIto64, mkexpr(sV)) );
10296 assign( s0, unop(Iop_V128to64, mkexpr(sV)) );
10297
10298 if (hi) {
10299 putXMMReg( gregOfRexRM(pfx,modrm),
10300 binop(Iop_64HLtoV128, mkexpr(s1), mkexpr(d1)) );
10301 } else {
10302 putXMMReg( gregOfRexRM(pfx,modrm),
10303 binop(Iop_64HLtoV128, mkexpr(s0), mkexpr(d0)) );
10304 }
10305
10306 goto decode_success;
10307 }
sewardj9da16972005-02-21 13:58:26 +000010308
10309 /* 66 0F 57 = XORPD -- G = G xor E */
sewardj97628592005-05-10 22:42:54 +000010310 if (have66noF2noF3(pfx) && sz == 2
10311 && insn[0] == 0x0F && insn[1] == 0x57) {
sewardj9da16972005-02-21 13:58:26 +000010312 delta = dis_SSE_E_to_G_all( pfx, delta+2, "xorpd", Iop_XorV128 );
10313 goto decode_success;
10314 }
10315
sewardj97628592005-05-10 22:42:54 +000010316 /* 66 0F 6B = PACKSSDW */
10317 if (have66noF2noF3(pfx) && sz == 2
10318 && insn[0] == 0x0F && insn[1] == 0x6B) {
10319 delta = dis_SSEint_E_to_G( pfx, delta+2,
10320 "packssdw", Iop_QNarrow32Sx4, True );
10321 goto decode_success;
10322 }
10323
10324 /* 66 0F 63 = PACKSSWB */
10325 if (have66noF2noF3(pfx) && sz == 2
10326 && insn[0] == 0x0F && insn[1] == 0x63) {
10327 delta = dis_SSEint_E_to_G( pfx, delta+2,
10328 "packsswb", Iop_QNarrow16Sx8, True );
10329 goto decode_success;
10330 }
10331
10332 /* 66 0F 67 = PACKUSWB */
10333 if (have66noF2noF3(pfx) && sz == 2
10334 && insn[0] == 0x0F && insn[1] == 0x67) {
10335 delta = dis_SSEint_E_to_G( pfx, delta+2,
10336 "packuswb", Iop_QNarrow16Ux8, True );
10337 goto decode_success;
10338 }
10339
10340 /* 66 0F FC = PADDB */
10341 if (have66noF2noF3(pfx) && sz == 2
10342 && insn[0] == 0x0F && insn[1] == 0xFC) {
10343 delta = dis_SSEint_E_to_G( pfx, delta+2,
10344 "paddb", Iop_Add8x16, False );
10345 goto decode_success;
10346 }
10347
10348 /* 66 0F FE = PADDD */
10349 if (have66noF2noF3(pfx) && sz == 2
10350 && insn[0] == 0x0F && insn[1] == 0xFE) {
10351 delta = dis_SSEint_E_to_G( pfx, delta+2,
10352 "paddd", Iop_Add32x4, False );
10353 goto decode_success;
10354 }
sewardj8711f662005-05-09 17:52:56 +000010355
10356 /* ***--- this is an MMX class insn introduced in SSE2 ---*** */
10357 /* 0F D4 = PADDQ -- add 64x1 */
10358 if (haveNo66noF2noF3(pfx) && sz == 4
10359 && insn[0] == 0x0F && insn[1] == 0xD4) {
10360 do_MMX_preamble();
10361 delta = dis_MMXop_regmem_to_reg (
10362 pfx, delta+2, insn[1], "paddq", False );
10363 goto decode_success;
10364 }
sewardj09717342005-05-05 21:34:02 +000010365
10366 /* 66 0F D4 = PADDQ */
10367 if (have66noF2noF3(pfx) && sz == 2
10368 && insn[0] == 0x0F && insn[1] == 0xD4) {
10369 delta = dis_SSEint_E_to_G( pfx, delta+2,
10370 "paddq", Iop_Add64x2, False );
10371 goto decode_success;
10372 }
10373
sewardj5992bd02005-05-11 02:13:42 +000010374 /* 66 0F FD = PADDW */
10375 if (have66noF2noF3(pfx) && sz == 2
10376 && insn[0] == 0x0F && insn[1] == 0xFD) {
10377 delta = dis_SSEint_E_to_G( pfx, delta+2,
10378 "paddw", Iop_Add16x8, False );
10379 goto decode_success;
10380 }
10381
10382 /* 66 0F EC = PADDSB */
10383 if (have66noF2noF3(pfx) && sz == 2
10384 && insn[0] == 0x0F && insn[1] == 0xEC) {
10385 delta = dis_SSEint_E_to_G( pfx, delta+2,
10386 "paddsb", Iop_QAdd8Sx16, False );
10387 goto decode_success;
10388 }
10389
10390 /* 66 0F ED = PADDSW */
10391 if (have66noF2noF3(pfx) && sz == 2
10392 && insn[0] == 0x0F && insn[1] == 0xED) {
10393 delta = dis_SSEint_E_to_G( pfx, delta+2,
10394 "paddsw", Iop_QAdd16Sx8, False );
10395 goto decode_success;
10396 }
10397
10398 /* 66 0F DC = PADDUSB */
10399 if (have66noF2noF3(pfx) && sz == 2
10400 && insn[0] == 0x0F && insn[1] == 0xDC) {
10401 delta = dis_SSEint_E_to_G( pfx, delta+2,
10402 "paddusb", Iop_QAdd8Ux16, False );
10403 goto decode_success;
10404 }
10405
10406 /* 66 0F DD = PADDUSW */
10407 if (have66noF2noF3(pfx) && sz == 2
10408 && insn[0] == 0x0F && insn[1] == 0xDD) {
10409 delta = dis_SSEint_E_to_G( pfx, delta+2,
10410 "paddusw", Iop_QAdd16Ux8, False );
10411 goto decode_success;
10412 }
sewardj09717342005-05-05 21:34:02 +000010413
10414 /* 66 0F DB = PAND */
10415 if (have66noF2noF3(pfx) && sz == 2
10416 && insn[0] == 0x0F && insn[1] == 0xDB) {
10417 delta = dis_SSE_E_to_G_all( pfx, delta+2, "pand", Iop_AndV128 );
10418 goto decode_success;
10419 }
10420
sewardj5992bd02005-05-11 02:13:42 +000010421 /* 66 0F DF = PANDN */
10422 if (have66noF2noF3(pfx) && sz == 2
10423 && insn[0] == 0x0F && insn[1] == 0xDF) {
10424 delta = dis_SSE_E_to_G_all_invG( pfx, delta+2, "pandn", Iop_AndV128 );
10425 goto decode_success;
10426 }
10427
10428 /* 66 0F E0 = PAVGB */
10429 if (have66noF2noF3(pfx) && sz == 2
10430 && insn[0] == 0x0F && insn[1] == 0xE0) {
10431 delta = dis_SSEint_E_to_G( pfx, delta+2,
10432 "pavgb", Iop_Avg8Ux16, False );
10433 goto decode_success;
10434 }
10435
10436 /* 66 0F E3 = PAVGW */
10437 if (have66noF2noF3(pfx) && sz == 2
10438 && insn[0] == 0x0F && insn[1] == 0xE3) {
10439 delta = dis_SSEint_E_to_G( pfx, delta+2,
10440 "pavgw", Iop_Avg16Ux8, False );
10441 goto decode_success;
10442 }
10443
10444 /* 66 0F 74 = PCMPEQB */
10445 if (have66noF2noF3(pfx) && sz == 2
10446 && insn[0] == 0x0F && insn[1] == 0x74) {
10447 delta = dis_SSEint_E_to_G( pfx, delta+2,
10448 "pcmpeqb", Iop_CmpEQ8x16, False );
10449 goto decode_success;
10450 }
10451
10452 /* 66 0F 76 = PCMPEQD */
10453 if (have66noF2noF3(pfx) && sz == 2
10454 && insn[0] == 0x0F && insn[1] == 0x76) {
10455 delta = dis_SSEint_E_to_G( pfx, delta+2,
10456 "pcmpeqd", Iop_CmpEQ32x4, False );
10457 goto decode_success;
10458 }
10459
10460 /* 66 0F 75 = PCMPEQW */
10461 if (have66noF2noF3(pfx) && sz == 2
10462 && insn[0] == 0x0F && insn[1] == 0x75) {
10463 delta = dis_SSEint_E_to_G( pfx, delta+2,
10464 "pcmpeqw", Iop_CmpEQ16x8, False );
10465 goto decode_success;
10466 }
10467
10468 /* 66 0F 64 = PCMPGTB */
10469 if (have66noF2noF3(pfx) && sz == 2
10470 && insn[0] == 0x0F && insn[1] == 0x64) {
10471 delta = dis_SSEint_E_to_G( pfx, delta+2,
10472 "pcmpgtb", Iop_CmpGT8Sx16, False );
10473 goto decode_success;
10474 }
10475
10476 /* 66 0F 66 = PCMPGTD */
10477 if (have66noF2noF3(pfx) && sz == 2
10478 && insn[0] == 0x0F && insn[1] == 0x66) {
10479 delta = dis_SSEint_E_to_G( pfx, delta+2,
10480 "pcmpgtd", Iop_CmpGT32Sx4, False );
10481 goto decode_success;
10482 }
10483
10484 /* 66 0F 65 = PCMPGTW */
10485 if (have66noF2noF3(pfx) && sz == 2
10486 && insn[0] == 0x0F && insn[1] == 0x65) {
10487 delta = dis_SSEint_E_to_G( pfx, delta+2,
10488 "pcmpgtw", Iop_CmpGT16Sx8, False );
10489 goto decode_success;
10490 }
sewardj97628592005-05-10 22:42:54 +000010491
10492 /* 66 0F C5 = PEXTRW -- extract 16-bit field from xmm(E) and put
10493 zero-extend of it in ireg(G). */
10494 if (have66noF2noF3(pfx) && sz == 2
10495 && insn[0] == 0x0F && insn[1] == 0xC5) {
10496 modrm = insn[2];
10497 if (epartIsReg(modrm)) {
10498 t5 = newTemp(Ity_V128);
10499 t4 = newTemp(Ity_I16);
10500 assign(t5, getXMMReg(eregOfRexRM(pfx,modrm)));
10501 breakup128to32s( t5, &t3, &t2, &t1, &t0 );
10502 switch (insn[3] & 7) {
10503 case 0: assign(t4, unop(Iop_32to16, mkexpr(t0))); break;
10504 case 1: assign(t4, unop(Iop_32HIto16, mkexpr(t0))); break;
10505 case 2: assign(t4, unop(Iop_32to16, mkexpr(t1))); break;
10506 case 3: assign(t4, unop(Iop_32HIto16, mkexpr(t1))); break;
10507 case 4: assign(t4, unop(Iop_32to16, mkexpr(t2))); break;
10508 case 5: assign(t4, unop(Iop_32HIto16, mkexpr(t2))); break;
10509 case 6: assign(t4, unop(Iop_32to16, mkexpr(t3))); break;
10510 case 7: assign(t4, unop(Iop_32HIto16, mkexpr(t3))); break;
10511 default: vassert(0);
10512 }
10513 putIReg32(gregOfRexRM(pfx,modrm), unop(Iop_16Uto32, mkexpr(t4)));
10514 DIP("pextrw $%d,%s,%s\n",
10515 (Int)insn[3], nameXMMReg(eregOfRexRM(pfx,modrm)),
10516 nameIReg32(gregOfRexRM(pfx,modrm)));
10517 delta += 4;
10518 goto decode_success;
10519 }
10520 /* else fall through */
10521 /* note, if memory case is ever filled in, there is 1 byte after
10522 amode */
10523 }
10524
10525 /* 66 0F C4 = PINSRW -- get 16 bits from E(mem or low half ireg) and
10526 put it into the specified lane of xmm(G). */
10527 if (have66noF2noF3(pfx) && sz == 2
10528 && insn[0] == 0x0F && insn[1] == 0xC4) {
10529 Int lane;
10530 t4 = newTemp(Ity_I16);
10531 modrm = insn[2];
10532
10533 if (epartIsReg(modrm)) {
10534 assign(t4, getIReg16(eregOfRexRM(pfx,modrm)));
10535 delta += 3+1;
10536 lane = insn[3+1-1];
10537 DIP("pinsrw $%d,%s,%s\n", (Int)lane,
10538 nameIReg16(eregOfRexRM(pfx,modrm)),
10539 nameXMMReg(gregOfRexRM(pfx,modrm)));
10540 } else {
10541 addr = disAMode ( &alen, pfx, delta+2, dis_buf,
10542 1/*byte after the amode*/ );
10543 delta += 3+alen;
10544 lane = insn[3+alen-1];
10545 assign(t4, loadLE(Ity_I16, mkexpr(addr)));
10546 DIP("pinsrw $%d,%s,%s\n", (Int)lane,
10547 dis_buf,
10548 nameXMMReg(gregOfRexRM(pfx,modrm)));
10549 }
10550
10551 putXMMRegLane16( gregOfRexRM(pfx,modrm), lane & 7, mkexpr(t4) );
10552 goto decode_success;
10553 }
10554
sewardjadffcef2005-05-11 00:03:06 +000010555 /* 66 0F EE = PMAXSW -- 16x8 signed max */
10556 if (have66noF2noF3(pfx) && sz == 2
10557 && insn[0] == 0x0F && insn[1] == 0xEE) {
10558 delta = dis_SSEint_E_to_G( pfx, delta+2,
10559 "pmaxsw", Iop_Max16Sx8, False );
10560 goto decode_success;
10561 }
10562
10563 /* 66 0F DE = PMAXUB -- 8x16 unsigned max */
10564 if (have66noF2noF3(pfx) && sz == 2
10565 && insn[0] == 0x0F && insn[1] == 0xDE) {
10566 delta = dis_SSEint_E_to_G( pfx, delta+2,
10567 "pmaxub", Iop_Max8Ux16, False );
10568 goto decode_success;
10569 }
10570
10571 /* 66 0F EA = PMINSW -- 16x8 signed min */
10572 if (have66noF2noF3(pfx) && sz == 2
10573 && insn[0] == 0x0F && insn[1] == 0xEA) {
10574 delta = dis_SSEint_E_to_G( pfx, delta+2,
10575 "pminsw", Iop_Min16Sx8, False );
10576 goto decode_success;
10577 }
10578
10579 /* 66 0F DA = PMINUB -- 8x16 unsigned min */
10580 if (have66noF2noF3(pfx) && sz == 2
10581 && insn[0] == 0x0F && insn[1] == 0xDA) {
10582 delta = dis_SSEint_E_to_G( pfx, delta+2,
10583 "pminub", Iop_Min8Ux16, False );
10584 goto decode_success;
10585 }
10586
10587 /* 66 0F D7 = PMOVMSKB -- extract sign bits from each of 16 lanes in
10588 xmm(E), turn them into a byte, and put zero-extend of it in
10589 ireg(G). Doing this directly is just too cumbersome; give up
10590 therefore and call a helper. */
10591 /* UInt x86g_calculate_sse_pmovmskb ( ULong w64hi, ULong w64lo ); */
10592 if (have66noF2noF3(pfx) && sz == 2
10593 && insn[0] == 0x0F && insn[1] == 0xD7) {
10594 modrm = insn[2];
10595 if (epartIsReg(modrm)) {
10596 t0 = newTemp(Ity_I64);
10597 t1 = newTemp(Ity_I64);
10598 assign(t0, getXMMRegLane64(eregOfRexRM(pfx,modrm), 0));
10599 assign(t1, getXMMRegLane64(eregOfRexRM(pfx,modrm), 1));
10600 t5 = newTemp(Ity_I64);
10601 assign(t5, mkIRExprCCall(
10602 Ity_I64, 0/*regparms*/,
10603 "amd64g_calculate_sse_pmovmskb",
10604 &amd64g_calculate_sse_pmovmskb,
10605 mkIRExprVec_2( mkexpr(t1), mkexpr(t0) )));
10606 putIReg32(gregOfRexRM(pfx,modrm), unop(Iop_64to32,mkexpr(t5)));
10607 DIP("pmovmskb %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
10608 nameIReg32(gregOfRexRM(pfx,modrm)));
10609 delta += 3;
10610 goto decode_success;
10611 }
10612 /* else fall through */
10613 }
10614
10615 /* 66 0F E4 = PMULHUW -- 16x8 hi-half of unsigned widening multiply */
10616 if (have66noF2noF3(pfx) && sz == 2
10617 && insn[0] == 0x0F && insn[1] == 0xE4) {
10618 delta = dis_SSEint_E_to_G( pfx, delta+2,
10619 "pmulhuw", Iop_MulHi16Ux8, False );
10620 goto decode_success;
10621 }
10622
10623 /* 66 0F E5 = PMULHW -- 16x8 hi-half of signed widening multiply */
10624 if (have66noF2noF3(pfx) && sz == 2
10625 && insn[0] == 0x0F && insn[1] == 0xE5) {
10626 delta = dis_SSEint_E_to_G( pfx, delta+2,
10627 "pmulhw", Iop_MulHi16Sx8, False );
10628 goto decode_success;
10629 }
10630
10631 /* 66 0F D5 = PMULHL -- 16x8 multiply */
10632 if (have66noF2noF3(pfx) && sz == 2
10633 && insn[0] == 0x0F && insn[1] == 0xD5) {
10634 delta = dis_SSEint_E_to_G( pfx, delta+2,
10635 "pmullw", Iop_Mul16x8, False );
10636 goto decode_success;
10637 }
10638
10639 /* ***--- this is an MMX class insn introduced in SSE2 ---*** */
10640 /* 0F F4 = PMULUDQ -- unsigned widening multiply of 32-lanes 0 x
10641 0 to form 64-bit result */
10642 if (haveNo66noF2noF3(pfx) && sz == 4
10643 && insn[0] == 0x0F && insn[1] == 0xF4) {
10644 IRTemp sV = newTemp(Ity_I64);
10645 IRTemp dV = newTemp(Ity_I64);
10646 t1 = newTemp(Ity_I32);
10647 t0 = newTemp(Ity_I32);
10648 modrm = insn[2];
10649
10650 do_MMX_preamble();
10651 assign( dV, getMMXReg(gregLO3ofRM(modrm)) );
10652
10653 if (epartIsReg(modrm)) {
10654 assign( sV, getMMXReg(eregLO3ofRM(modrm)) );
10655 delta += 2+1;
10656 DIP("pmuludq %s,%s\n", nameMMXReg(eregLO3ofRM(modrm)),
10657 nameMMXReg(gregLO3ofRM(modrm)));
10658 } else {
10659 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10660 assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
10661 delta += 2+alen;
10662 DIP("pmuludq %s,%s\n", dis_buf,
10663 nameMMXReg(gregLO3ofRM(modrm)));
10664 }
10665
10666 assign( t0, unop(Iop_64to32, mkexpr(dV)) );
10667 assign( t1, unop(Iop_64to32, mkexpr(sV)) );
10668 putMMXReg( gregLO3ofRM(modrm),
10669 binop( Iop_MullU32, mkexpr(t0), mkexpr(t1) ) );
10670 goto decode_success;
10671 }
10672
10673 /* 66 0F F4 = PMULUDQ -- unsigned widening multiply of 32-lanes 0 x
10674 0 to form lower 64-bit half and lanes 2 x 2 to form upper 64-bit
10675 half */
10676 /* This is a really poor translation -- could be improved if
10677 performance critical */
10678 if (have66noF2noF3(pfx) && sz == 2
10679 && insn[0] == 0x0F && insn[1] == 0xF4) {
10680 IRTemp sV, dV;
10681 IRTemp s3, s2, s1, s0, d3, d2, d1, d0;
10682 sV = newTemp(Ity_V128);
10683 dV = newTemp(Ity_V128);
10684 s3 = s2 = s1 = s0 = d3 = d2 = d1 = d0 = IRTemp_INVALID;
10685 t1 = newTemp(Ity_I64);
10686 t0 = newTemp(Ity_I64);
10687 modrm = insn[2];
10688 assign( dV, getXMMReg(gregOfRexRM(pfx,modrm)) );
10689
10690 if (epartIsReg(modrm)) {
10691 assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
10692 delta += 2+1;
10693 DIP("pmuludq %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
10694 nameXMMReg(gregOfRexRM(pfx,modrm)));
10695 } else {
10696 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10697 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
10698 delta += 2+alen;
10699 DIP("pmuludq %s,%s\n", dis_buf,
10700 nameXMMReg(gregOfRexRM(pfx,modrm)));
10701 }
10702
10703 breakup128to32s( dV, &d3, &d2, &d1, &d0 );
10704 breakup128to32s( sV, &s3, &s2, &s1, &s0 );
10705
10706 assign( t0, binop( Iop_MullU32, mkexpr(d0), mkexpr(s0)) );
10707 putXMMRegLane64( gregOfRexRM(pfx,modrm), 0, mkexpr(t0) );
10708 assign( t1, binop( Iop_MullU32, mkexpr(d2), mkexpr(s2)) );
10709 putXMMRegLane64( gregOfRexRM(pfx,modrm), 1, mkexpr(t1) );
10710 goto decode_success;
10711 }
sewardj09717342005-05-05 21:34:02 +000010712
10713 /* 66 0F EB = POR */
10714 if (have66noF2noF3(pfx) && sz == 2
10715 && insn[0] == 0x0F && insn[1] == 0xEB) {
10716 delta = dis_SSE_E_to_G_all( pfx, delta+2, "por", Iop_OrV128 );
10717 goto decode_success;
10718 }
10719
sewardjadffcef2005-05-11 00:03:06 +000010720 /* 66 0F 70 = PSHUFD -- rearrange 4x32 from E(xmm or mem) to G(xmm) */
10721 if (have66noF2noF3(pfx) && sz == 2
10722 && insn[0] == 0x0F && insn[1] == 0x70) {
10723 Int order;
10724 IRTemp sV, dV, s3, s2, s1, s0;
10725 s3 = s2 = s1 = s0 = IRTemp_INVALID;
10726 sV = newTemp(Ity_V128);
10727 dV = newTemp(Ity_V128);
10728 modrm = insn[2];
10729 if (epartIsReg(modrm)) {
10730 assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
10731 order = (Int)insn[3];
10732 delta += 3+1;
10733 DIP("pshufd $%d,%s,%s\n", order,
10734 nameXMMReg(eregOfRexRM(pfx,modrm)),
10735 nameXMMReg(gregOfRexRM(pfx,modrm)));
10736 } else {
10737 addr = disAMode ( &alen, pfx, delta+2, dis_buf,
10738 1/*byte after the amode*/ );
10739 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
10740 order = (Int)insn[2+alen];
10741 delta += 2+alen+1;
10742 DIP("pshufd $%d,%s,%s\n", order,
10743 dis_buf,
10744 nameXMMReg(gregOfRexRM(pfx,modrm)));
10745 }
10746 breakup128to32s( sV, &s3, &s2, &s1, &s0 );
10747
10748# define SEL(n) \
10749 ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
10750 assign(dV,
10751 mk128from32s( SEL((order>>6)&3), SEL((order>>4)&3),
10752 SEL((order>>2)&3), SEL((order>>0)&3) )
10753 );
10754 putXMMReg(gregOfRexRM(pfx,modrm), mkexpr(dV));
10755# undef SEL
10756 goto decode_success;
10757 }
10758
10759 /* F3 0F 70 = PSHUFHW -- rearrange upper half 4x16 from E(xmm or
10760 mem) to G(xmm), and copy lower half */
10761 if (haveF3no66noF2(pfx) && sz == 4
10762 && insn[0] == 0x0F && insn[1] == 0x70) {
10763 Int order;
10764 IRTemp sVhi, dVhi, sV, dV, s3, s2, s1, s0;
10765 s3 = s2 = s1 = s0 = IRTemp_INVALID;
10766 sV = newTemp(Ity_V128);
10767 dV = newTemp(Ity_V128);
10768 sVhi = newTemp(Ity_I64);
10769 dVhi = newTemp(Ity_I64);
10770 modrm = insn[2];
10771 if (epartIsReg(modrm)) {
10772 assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
10773 order = (Int)insn[3];
10774 delta += 3+1;
10775 DIP("pshufhw $%d,%s,%s\n", order,
10776 nameXMMReg(eregOfRexRM(pfx,modrm)),
10777 nameXMMReg(gregOfRexRM(pfx,modrm)));
10778 } else {
10779 addr = disAMode ( &alen, pfx, delta+2, dis_buf,
10780 1/*byte after the amode*/ );
10781 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
10782 order = (Int)insn[2+alen];
10783 delta += 2+alen+1;
10784 DIP("pshufhw $%d,%s,%s\n", order,
10785 dis_buf,
10786 nameXMMReg(gregOfRexRM(pfx,modrm)));
10787 }
10788 assign( sVhi, unop(Iop_V128HIto64, mkexpr(sV)) );
10789 breakup64to16s( sVhi, &s3, &s2, &s1, &s0 );
10790
10791# define SEL(n) \
10792 ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
10793 assign(dVhi,
10794 mk64from16s( SEL((order>>6)&3), SEL((order>>4)&3),
10795 SEL((order>>2)&3), SEL((order>>0)&3) )
10796 );
10797 assign(dV, binop( Iop_64HLtoV128,
10798 mkexpr(dVhi),
10799 unop(Iop_V128to64, mkexpr(sV))) );
10800 putXMMReg(gregOfRexRM(pfx,modrm), mkexpr(dV));
10801# undef SEL
10802 goto decode_success;
10803 }
10804
10805 /* F2 0F 70 = PSHUFLW -- rearrange lower half 4x16 from E(xmm or
10806 mem) to G(xmm), and copy upper half */
10807 if (haveF2no66noF3(pfx) && sz == 4
10808 && insn[0] == 0x0F && insn[1] == 0x70) {
10809 Int order;
10810 IRTemp sVlo, dVlo, sV, dV, s3, s2, s1, s0;
10811 s3 = s2 = s1 = s0 = IRTemp_INVALID;
10812 sV = newTemp(Ity_V128);
10813 dV = newTemp(Ity_V128);
10814 sVlo = newTemp(Ity_I64);
10815 dVlo = newTemp(Ity_I64);
10816 modrm = insn[2];
10817 if (epartIsReg(modrm)) {
10818 assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
10819 order = (Int)insn[3];
10820 delta += 3+1;
10821 DIP("pshuflw $%d,%s,%s\n", order,
10822 nameXMMReg(eregOfRexRM(pfx,modrm)),
10823 nameXMMReg(gregOfRexRM(pfx,modrm)));
10824 } else {
10825 addr = disAMode ( &alen, pfx, delta+2, dis_buf,
10826 1/*byte after the amode*/ );
10827 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
10828 order = (Int)insn[2+alen];
10829 delta += 2+alen+1;
10830 DIP("pshuflw $%d,%s,%s\n", order,
10831 dis_buf,
10832 nameXMMReg(gregOfRexRM(pfx,modrm)));
10833 }
10834 assign( sVlo, unop(Iop_V128to64, mkexpr(sV)) );
10835 breakup64to16s( sVlo, &s3, &s2, &s1, &s0 );
10836
10837# define SEL(n) \
10838 ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
10839 assign(dVlo,
10840 mk64from16s( SEL((order>>6)&3), SEL((order>>4)&3),
10841 SEL((order>>2)&3), SEL((order>>0)&3) )
10842 );
10843 assign(dV, binop( Iop_64HLtoV128,
10844 unop(Iop_V128HIto64, mkexpr(sV)),
10845 mkexpr(dVlo) ) );
10846 putXMMReg(gregOfRexRM(pfx,modrm), mkexpr(dV));
10847# undef SEL
10848 goto decode_success;
10849 }
10850
10851 /* 66 0F 72 /6 ib = PSLLD by immediate */
10852 if (have66noF2noF3(pfx) && sz == 2
10853 && insn[0] == 0x0F && insn[1] == 0x72
10854 && epartIsReg(insn[2])
10855 && gregLO3ofRM(insn[2]) == 6) {
10856 delta = dis_SSE_shiftE_imm( pfx, delta+2, "pslld", Iop_ShlN32x4 );
10857 goto decode_success;
10858 }
10859
10860 /* 66 0F F2 = PSLLD by E */
10861 if (have66noF2noF3(pfx) && sz == 2
10862 && insn[0] == 0x0F && insn[1] == 0xF2) {
10863 delta = dis_SSE_shiftG_byE( pfx, delta+2, "pslld", Iop_ShlN32x4 );
10864 goto decode_success;
10865 }
sewardj97628592005-05-10 22:42:54 +000010866
10867 /* 66 0F 73 /7 ib = PSLLDQ by immediate */
10868 /* note, if mem case ever filled in, 1 byte after amode */
10869 if (have66noF2noF3(pfx) && sz == 2
10870 && insn[0] == 0x0F && insn[1] == 0x73
10871 && epartIsReg(insn[2])
10872 && gregLO3ofRM(insn[2]) == 7) {
10873 IRTemp sV, dV, hi64, lo64, hi64r, lo64r;
10874 Int imm = (Int)insn[3];
10875 Int reg = eregOfRexRM(pfx,insn[2]);
10876 DIP("pslldq $%d,%s\n", imm, nameXMMReg(reg));
10877 vassert(imm >= 0 && imm <= 255);
10878 delta += 4;
10879
10880 sV = newTemp(Ity_V128);
10881 dV = newTemp(Ity_V128);
10882 hi64 = newTemp(Ity_I64);
10883 lo64 = newTemp(Ity_I64);
10884 hi64r = newTemp(Ity_I64);
10885 lo64r = newTemp(Ity_I64);
10886
10887 if (imm >= 16) {
10888 putXMMReg(reg, mkV128(0x0000));
10889 goto decode_success;
10890 }
10891
10892 assign( sV, getXMMReg(reg) );
10893 assign( hi64, unop(Iop_V128HIto64, mkexpr(sV)) );
10894 assign( lo64, unop(Iop_V128to64, mkexpr(sV)) );
10895
10896 if (imm == 0) {
10897 assign( lo64r, mkexpr(lo64) );
10898 assign( hi64r, mkexpr(hi64) );
10899 }
10900 else
10901 if (imm == 8) {
10902 assign( lo64r, mkU64(0) );
10903 assign( hi64r, mkexpr(lo64) );
10904 }
10905 else
10906 if (imm > 8) {
10907 assign( lo64r, mkU64(0) );
10908 assign( hi64r, binop( Iop_Shl64,
10909 mkexpr(lo64),
10910 mkU8( 8*(imm-8) ) ));
10911 } else {
10912 assign( lo64r, binop( Iop_Shl64,
10913 mkexpr(lo64),
10914 mkU8(8 * imm) ));
10915 assign( hi64r,
10916 binop( Iop_Or64,
10917 binop(Iop_Shl64, mkexpr(hi64),
10918 mkU8(8 * imm)),
10919 binop(Iop_Shr64, mkexpr(lo64),
10920 mkU8(8 * (8 - imm)) )
10921 )
10922 );
10923 }
10924 assign( dV, binop(Iop_64HLtoV128, mkexpr(hi64r), mkexpr(lo64r)) );
10925 putXMMReg(reg, mkexpr(dV));
10926 goto decode_success;
10927 }
10928
sewardjadffcef2005-05-11 00:03:06 +000010929 /* 66 0F 73 /6 ib = PSLLQ by immediate */
10930 if (have66noF2noF3(pfx) && sz == 2
10931 && insn[0] == 0x0F && insn[1] == 0x73
10932 && epartIsReg(insn[2])
10933 && gregLO3ofRM(insn[2]) == 6) {
10934 delta = dis_SSE_shiftE_imm( pfx, delta+2, "psllq", Iop_ShlN64x2 );
10935 goto decode_success;
10936 }
10937
10938 /* 66 0F F3 = PSLLQ by E */
10939 if (have66noF2noF3(pfx) && sz == 2
10940 && insn[0] == 0x0F && insn[1] == 0xF3) {
10941 delta = dis_SSE_shiftG_byE( pfx, delta+2, "psllq", Iop_ShlN64x2 );
10942 goto decode_success;
10943 }
10944
10945 /* 66 0F 71 /6 ib = PSLLW by immediate */
10946 if (have66noF2noF3(pfx) && sz == 2
10947 && insn[0] == 0x0F && insn[1] == 0x71
10948 && epartIsReg(insn[2])
10949 && gregLO3ofRM(insn[2]) == 6) {
10950 delta = dis_SSE_shiftE_imm( pfx, delta+2, "psllw", Iop_ShlN16x8 );
10951 goto decode_success;
10952 }
10953
10954 /* 66 0F F1 = PSLLW by E */
10955 if (have66noF2noF3(pfx) && sz == 2
10956 && insn[0] == 0x0F && insn[1] == 0xF1) {
10957 delta = dis_SSE_shiftG_byE( pfx, delta+2, "psllw", Iop_ShlN16x8 );
10958 goto decode_success;
10959 }
10960
10961 /* 66 0F 72 /4 ib = PSRAD by immediate */
10962 if (have66noF2noF3(pfx) && sz == 2
10963 && insn[0] == 0x0F && insn[1] == 0x72
10964 && epartIsReg(insn[2])
10965 && gregLO3ofRM(insn[2]) == 4) {
10966 delta = dis_SSE_shiftE_imm( pfx, delta+2, "psrad", Iop_SarN32x4 );
10967 goto decode_success;
10968 }
10969
10970 /* 66 0F E2 = PSRAD by E */
10971 if (have66noF2noF3(pfx) && sz == 2
10972 && insn[0] == 0x0F && insn[1] == 0xE2) {
10973 delta = dis_SSE_shiftG_byE( pfx, delta+2, "psrad", Iop_SarN32x4 );
10974 goto decode_success;
10975 }
10976
10977 /* 66 0F 71 /4 ib = PSRAW by immediate */
10978 if (have66noF2noF3(pfx) && sz == 2
10979 && insn[0] == 0x0F && insn[1] == 0x71
10980 && epartIsReg(insn[2])
10981 && gregLO3ofRM(insn[2]) == 4) {
10982 delta = dis_SSE_shiftE_imm( pfx, delta+2, "psraw", Iop_SarN16x8 );
10983 goto decode_success;
10984 }
10985
10986 /* 66 0F E1 = PSRAW by E */
10987 if (have66noF2noF3(pfx) && sz == 2
10988 && insn[0] == 0x0F && insn[1] == 0xE1) {
10989 delta = dis_SSE_shiftG_byE( pfx, delta+2, "psraw", Iop_SarN16x8 );
10990 goto decode_success;
10991 }
10992
10993 /* 66 0F 72 /2 ib = PSRLD by immediate */
10994 if (have66noF2noF3(pfx) && sz == 2
10995 && insn[0] == 0x0F && insn[1] == 0x72
10996 && epartIsReg(insn[2])
10997 && gregLO3ofRM(insn[2]) == 2) {
10998 delta = dis_SSE_shiftE_imm( pfx, delta+2, "psrld", Iop_ShrN32x4 );
10999 goto decode_success;
11000 }
11001
11002 /* 66 0F D2 = PSRLD by E */
11003 if (have66noF2noF3(pfx) && sz == 2
11004 && insn[0] == 0x0F && insn[1] == 0xD2) {
11005 delta = dis_SSE_shiftG_byE( pfx, delta+2, "psrld", Iop_ShrN32x4 );
11006 goto decode_success;
11007 }
sewardj97628592005-05-10 22:42:54 +000011008
11009 /* 66 0F 73 /3 ib = PSRLDQ by immediate */
11010 /* note, if mem case ever filled in, 1 byte after amode */
11011 if (have66noF2noF3(pfx) && sz == 2
11012 && insn[0] == 0x0F && insn[1] == 0x73
11013 && epartIsReg(insn[2])
11014 && gregLO3ofRM(insn[2]) == 3) {
11015 IRTemp sV, dV, hi64, lo64, hi64r, lo64r;
11016 Int imm = (Int)insn[3];
11017 Int reg = eregOfRexRM(pfx,insn[2]);
11018 DIP("psrldq $%d,%s\n", imm, nameXMMReg(reg));
11019 vassert(imm >= 0 && imm <= 255);
11020 delta += 4;
11021
11022 sV = newTemp(Ity_V128);
11023 dV = newTemp(Ity_V128);
11024 hi64 = newTemp(Ity_I64);
11025 lo64 = newTemp(Ity_I64);
11026 hi64r = newTemp(Ity_I64);
11027 lo64r = newTemp(Ity_I64);
11028
11029 if (imm >= 16) {
11030 putXMMReg(reg, mkV128(0x0000));
11031 goto decode_success;
11032 }
11033
11034 assign( sV, getXMMReg(reg) );
11035 assign( hi64, unop(Iop_V128HIto64, mkexpr(sV)) );
11036 assign( lo64, unop(Iop_V128to64, mkexpr(sV)) );
11037
11038 if (imm == 0) {
11039 assign( lo64r, mkexpr(lo64) );
11040 assign( hi64r, mkexpr(hi64) );
11041 }
11042 else
11043 if (imm == 8) {
11044 assign( hi64r, mkU64(0) );
11045 assign( lo64r, mkexpr(hi64) );
11046 }
11047 else
11048 if (imm > 8) {
11049 assign( hi64r, mkU64(0) );
11050 assign( lo64r, binop( Iop_Shr64,
11051 mkexpr(hi64),
11052 mkU8( 8*(imm-8) ) ));
11053 } else {
11054 assign( hi64r, binop( Iop_Shr64,
11055 mkexpr(hi64),
11056 mkU8(8 * imm) ));
11057 assign( lo64r,
11058 binop( Iop_Or64,
11059 binop(Iop_Shr64, mkexpr(lo64),
11060 mkU8(8 * imm)),
11061 binop(Iop_Shl64, mkexpr(hi64),
11062 mkU8(8 * (8 - imm)) )
11063 )
11064 );
11065 }
11066
11067 assign( dV, binop(Iop_64HLtoV128, mkexpr(hi64r), mkexpr(lo64r)) );
11068 putXMMReg(reg, mkexpr(dV));
11069 goto decode_success;
11070 }
sewardj09717342005-05-05 21:34:02 +000011071
11072 /* 66 0F 73 /2 ib = PSRLQ by immediate */
11073 if (have66noF2noF3(pfx) && sz == 2
11074 && insn[0] == 0x0F && insn[1] == 0x73
11075 && epartIsReg(insn[2])
11076 && gregLO3ofRM(insn[2]) == 2) {
11077 delta = dis_SSE_shiftE_imm( pfx, delta+2, "psrlq", Iop_ShrN64x2 );
11078 goto decode_success;
11079 }
11080
sewardjadffcef2005-05-11 00:03:06 +000011081 /* 66 0F D3 = PSRLQ by E */
11082 if (have66noF2noF3(pfx) && sz == 2
11083 && insn[0] == 0x0F && insn[1] == 0xD3) {
11084 delta = dis_SSE_shiftG_byE( pfx, delta+2, "psrlq", Iop_ShrN64x2 );
11085 goto decode_success;
11086 }
11087
11088 /* 66 0F 71 /2 ib = PSRLW by immediate */
11089 if (have66noF2noF3(pfx) && sz == 2
11090 && insn[0] == 0x0F && insn[1] == 0x71
11091 && epartIsReg(insn[2])
11092 && gregLO3ofRM(insn[2]) == 2) {
11093 delta = dis_SSE_shiftE_imm( pfx, delta+2, "psrlw", Iop_ShrN16x8 );
11094 goto decode_success;
11095 }
11096
11097 /* 66 0F D1 = PSRLW by E */
11098 if (have66noF2noF3(pfx) && sz == 2
11099 && insn[0] == 0x0F && insn[1] == 0xD1) {
11100 delta = dis_SSE_shiftG_byE( pfx, delta+2, "psrlw", Iop_ShrN16x8 );
11101 goto decode_success;
11102 }
sewardj97628592005-05-10 22:42:54 +000011103
11104 /* 66 0F F8 = PSUBB */
11105 if (have66noF2noF3(pfx) && sz == 2
11106 && insn[0] == 0x0F && insn[1] == 0xF8) {
11107 delta = dis_SSEint_E_to_G( pfx, delta+2,
11108 "psubb", Iop_Sub8x16, False );
11109 goto decode_success;
11110 }
11111
11112 /* 66 0F FA = PSUBD */
11113 if (have66noF2noF3(pfx) && sz == 2
11114 && insn[0] == 0x0F && insn[1] == 0xFA) {
11115 delta = dis_SSEint_E_to_G( pfx, delta+2,
11116 "psubd", Iop_Sub32x4, False );
11117 goto decode_success;
11118 }
sewardj8711f662005-05-09 17:52:56 +000011119
11120 /* ***--- this is an MMX class insn introduced in SSE2 ---*** */
11121 /* 0F FB = PSUBQ -- sub 64x1 */
11122 if (haveNo66noF2noF3(pfx) && sz == 4
11123 && insn[0] == 0x0F && insn[1] == 0xFB) {
11124 do_MMX_preamble();
11125 delta = dis_MMXop_regmem_to_reg (
11126 pfx, delta+2, insn[1], "psubq", False );
11127 goto decode_success;
11128 }
sewardj09717342005-05-05 21:34:02 +000011129
11130 /* 66 0F FB = PSUBQ */
11131 if (have66noF2noF3(pfx) && sz == 2
11132 && insn[0] == 0x0F && insn[1] == 0xFB) {
11133 delta = dis_SSEint_E_to_G( pfx, delta+2,
11134 "psubq", Iop_Sub64x2, False );
11135 goto decode_success;
11136 }
11137
sewardj97628592005-05-10 22:42:54 +000011138 /* 66 0F F9 = PSUBW */
11139 if (have66noF2noF3(pfx) && sz == 2
11140 && insn[0] == 0x0F && insn[1] == 0xF9) {
11141 delta = dis_SSEint_E_to_G( pfx, delta+2,
11142 "psubw", Iop_Sub16x8, False );
11143 goto decode_success;
11144 }
11145
11146 /* 66 0F E8 = PSUBSB */
11147 if (have66noF2noF3(pfx) && sz == 2
11148 && insn[0] == 0x0F && insn[1] == 0xE8) {
11149 delta = dis_SSEint_E_to_G( pfx, delta+2,
11150 "psubsb", Iop_QSub8Sx16, False );
11151 goto decode_success;
11152 }
11153
11154 /* 66 0F E9 = PSUBSW */
11155 if (have66noF2noF3(pfx) && sz == 2
11156 && insn[0] == 0x0F && insn[1] == 0xE9) {
11157 delta = dis_SSEint_E_to_G( pfx, delta+2,
11158 "psubsw", Iop_QSub16Sx8, False );
11159 goto decode_success;
11160 }
11161
11162 /* 66 0F D8 = PSUBSB */
11163 if (have66noF2noF3(pfx) && sz == 2
11164 && insn[0] == 0x0F && insn[1] == 0xD8) {
11165 delta = dis_SSEint_E_to_G( pfx, delta+2,
11166 "psubusb", Iop_QSub8Ux16, False );
11167 goto decode_success;
11168 }
11169
11170 /* 66 0F D9 = PSUBSW */
11171 if (have66noF2noF3(pfx) && sz == 2
11172 && insn[0] == 0x0F && insn[1] == 0xD9) {
11173 delta = dis_SSEint_E_to_G( pfx, delta+2,
11174 "psubusw", Iop_QSub16Ux8, False );
11175 goto decode_success;
11176 }
11177
11178 /* 66 0F 68 = PUNPCKHBW */
11179 if (have66noF2noF3(pfx) && sz == 2
11180 && insn[0] == 0x0F && insn[1] == 0x68) {
11181 delta = dis_SSEint_E_to_G( pfx, delta+2,
11182 "punpckhbw",
11183 Iop_InterleaveHI8x16, True );
11184 goto decode_success;
11185 }
11186
11187 /* 66 0F 6A = PUNPCKHDQ */
11188 if (have66noF2noF3(pfx) && sz == 2
11189 && insn[0] == 0x0F && insn[1] == 0x6A) {
11190 delta = dis_SSEint_E_to_G( pfx, delta+2,
11191 "punpckhdq",
11192 Iop_InterleaveHI32x4, True );
11193 goto decode_success;
11194 }
11195
11196 /* 66 0F 6D = PUNPCKHQDQ */
11197 if (have66noF2noF3(pfx) && sz == 2
11198 && insn[0] == 0x0F && insn[1] == 0x6D) {
11199 delta = dis_SSEint_E_to_G( pfx, delta+2,
11200 "punpckhqdq",
11201 Iop_InterleaveHI64x2, True );
11202 goto decode_success;
11203 }
11204
11205 /* 66 0F 69 = PUNPCKHWD */
11206 if (have66noF2noF3(pfx) && sz == 2
11207 && insn[0] == 0x0F && insn[1] == 0x69) {
11208 delta = dis_SSEint_E_to_G( pfx, delta+2,
11209 "punpckhwd",
11210 Iop_InterleaveHI16x8, True );
11211 goto decode_success;
11212 }
11213
11214 /* 66 0F 60 = PUNPCKLBW */
11215 if (have66noF2noF3(pfx) && sz == 2
11216 && insn[0] == 0x0F && insn[1] == 0x60) {
11217 delta = dis_SSEint_E_to_G( pfx, delta+2,
11218 "punpcklbw",
11219 Iop_InterleaveLO8x16, True );
11220 goto decode_success;
11221 }
11222
11223 /* 66 0F 62 = PUNPCKLDQ */
11224 if (have66noF2noF3(pfx) && sz == 2
11225 && insn[0] == 0x0F && insn[1] == 0x62) {
11226 delta = dis_SSEint_E_to_G( pfx, delta+2,
11227 "punpckldq",
11228 Iop_InterleaveLO32x4, True );
11229 goto decode_success;
11230 }
11231
11232 /* 66 0F 6C = PUNPCKLQDQ */
11233 if (have66noF2noF3(pfx) && sz == 2
11234 && insn[0] == 0x0F && insn[1] == 0x6C) {
11235 delta = dis_SSEint_E_to_G( pfx, delta+2,
11236 "punpcklqdq",
11237 Iop_InterleaveLO64x2, True );
11238 goto decode_success;
11239 }
11240
11241 /* 66 0F 61 = PUNPCKLWD */
11242 if (have66noF2noF3(pfx) && sz == 2
11243 && insn[0] == 0x0F && insn[1] == 0x61) {
11244 delta = dis_SSEint_E_to_G( pfx, delta+2,
11245 "punpcklwd",
11246 Iop_InterleaveLO16x8, True );
11247 goto decode_success;
11248 }
sewardj09717342005-05-05 21:34:02 +000011249
11250 /* 66 0F EF = PXOR */
11251 if (have66noF2noF3(pfx) && sz == 2
11252 && insn[0] == 0x0F && insn[1] == 0xEF) {
11253 delta = dis_SSE_E_to_G_all( pfx, delta+2, "pxor", Iop_XorV128 );
11254 goto decode_success;
11255 }
11256
sewardjd20c8852005-01-20 20:04:07 +000011257//.. //-- /* FXSAVE/FXRSTOR m32 -- load/store the FPU/MMX/SSE state. */
11258//.. //-- if (insn[0] == 0x0F && insn[1] == 0xAE
11259//.. //-- && (!epartIsReg(insn[2]))
11260//.. //-- && (gregOfRM(insn[2]) == 1 || gregOfRM(insn[2]) == 0) ) {
11261//.. //-- Bool store = gregOfRM(insn[2]) == 0;
11262//.. //-- vg_assert(sz == 4);
11263//.. //-- pair = disAMode ( cb, sorb, eip+2, dis_buf );
11264//.. //-- t1 = LOW24(pair);
11265//.. //-- eip += 2+HI8(pair);
11266//.. //-- uInstr3(cb, store ? SSE2a_MemWr : SSE2a_MemRd, 512,
11267//.. //-- Lit16, (((UShort)insn[0]) << 8) | (UShort)insn[1],
11268//.. //-- Lit16, (UShort)insn[2],
11269//.. //-- TempReg, t1 );
11270//.. //-- DIP("fx%s %s\n", store ? "save" : "rstor", dis_buf );
11271//.. //-- goto decode_success;
11272//.. //-- }
11273//.. //--
11274//.. //-- /* CLFLUSH -- flush cache line */
11275//.. //-- if (insn[0] == 0x0F && insn[1] == 0xAE
11276//.. //-- && (!epartIsReg(insn[2]))
11277//.. //-- && (gregOfRM(insn[2]) == 7))
11278//.. //-- {
11279//.. //-- vg_assert(sz == 4);
11280//.. //-- pair = disAMode ( cb, sorb, eip+2, dis_buf );
11281//.. //-- t1 = LOW24(pair);
11282//.. //-- eip += 2+HI8(pair);
11283//.. //-- uInstr3(cb, SSE2a_MemRd, 0, /* ignore sz for internal ops */
11284//.. //-- Lit16, (((UShort)0x0F) << 8) | (UShort)0xAE,
11285//.. //-- Lit16, (UShort)insn[2],
11286//.. //-- TempReg, t1 );
11287//.. //-- DIP("clflush %s\n", dis_buf);
11288//.. //-- goto decode_success;
11289//.. //-- }
sewardjdf0e0022005-01-25 15:48:43 +000011290
11291
11292 /* ---------------------------------------------------- */
11293 /* --- end of the SSE/SSE2 decoder. --- */
11294 /* ---------------------------------------------------- */
11295
sewardj7a240552005-01-28 21:37:12 +000011296 /*after_sse_decoders:*/
sewardjdf0e0022005-01-25 15:48:43 +000011297
11298 /* Get the primary opcode. */
sewardj8c332e22005-01-28 01:36:56 +000011299 opc = getUChar(delta); delta++;
sewardjdf0e0022005-01-25 15:48:43 +000011300
11301 /* We get here if the current insn isn't SSE, or this CPU doesn't
11302 support SSE. */
11303
11304 switch (opc) {
11305
11306 /* ------------------------ Control flow --------------- */
11307
sewardjd20c8852005-01-20 20:04:07 +000011308//.. case 0xC2: /* RET imm16 */
11309//.. d32 = getUDisp16(delta);
11310//.. delta += 2;
11311//.. dis_ret(d32);
11312//.. whatNext = Dis_StopHere;
11313//.. DIP("ret %d\n", d32);
11314//.. break;
sewardj2f959cc2005-01-26 01:19:35 +000011315 case 0xC3: /* RET */
sewardj55dbb262005-01-28 16:36:51 +000011316 if (haveF2(pfx)) goto decode_failure;
11317 /* F3 is acceptable on AMD. */
sewardj2f959cc2005-01-26 01:19:35 +000011318 dis_ret(0);
sewardj9e6491a2005-07-02 19:24:10 +000011319 dres.whatNext = Dis_StopHere;
sewardje941eea2005-01-30 19:52:28 +000011320 DIP(haveF3(pfx) ? "rep ; ret\n" : "ret\n");
sewardj2f959cc2005-01-26 01:19:35 +000011321 break;
11322
sewardj3ca55a12005-01-27 16:06:23 +000011323 case 0xE8: /* CALL J4 */
11324 if (haveF2orF3(pfx)) goto decode_failure;
11325 d64 = getSDisp32(delta); delta += 4;
sewardj9e6491a2005-07-02 19:24:10 +000011326 d64 += (guest_RIP_bbstart+delta);
11327 /* (guest_RIP_bbstart+delta) == return-to addr, d64 == call-to addr */
sewardj3ca55a12005-01-27 16:06:23 +000011328 t1 = newTemp(Ity_I64);
11329 assign(t1, binop(Iop_Sub64, getIReg64(R_RSP), mkU64(8)));
11330 putIReg64(R_RSP, mkexpr(t1));
sewardj9e6491a2005-07-02 19:24:10 +000011331 storeLE( mkexpr(t1), mkU64(guest_RIP_bbstart+delta));
sewardj5a9ffab2005-05-12 17:55:01 +000011332 make_redzone_AbiHint(t1, "call-d32");
sewardj9e6491a2005-07-02 19:24:10 +000011333 if (resteerOkFn((Addr64)d64)) {
sewardj3ca55a12005-01-27 16:06:23 +000011334 /* follow into the call target. */
sewardj9e6491a2005-07-02 19:24:10 +000011335 dres.whatNext = Dis_Resteer;
11336 dres.continueAt = d64;
sewardj3ca55a12005-01-27 16:06:23 +000011337 } else {
11338 jmp_lit(Ijk_Call,d64);
sewardj9e6491a2005-07-02 19:24:10 +000011339 dres.whatNext = Dis_StopHere;
sewardj3ca55a12005-01-27 16:06:23 +000011340 }
11341 DIP("call 0x%llx\n",d64);
11342 break;
11343
sewardjd20c8852005-01-20 20:04:07 +000011344//.. //-- case 0xC8: /* ENTER */
11345//.. //-- d32 = getUDisp16(eip); eip += 2;
sewardj8c332e22005-01-28 01:36:56 +000011346//.. //-- abyte = getUChar(delta); delta++;
sewardjd20c8852005-01-20 20:04:07 +000011347//.. //--
11348//.. //-- vg_assert(sz == 4);
11349//.. //-- vg_assert(abyte == 0);
11350//.. //--
11351//.. //-- t1 = newTemp(cb); t2 = newTemp(cb);
11352//.. //-- uInstr2(cb, GET, sz, ArchReg, R_EBP, TempReg, t1);
11353//.. //-- uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t2);
11354//.. //-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
11355//.. //-- uLiteral(cb, sz);
11356//.. //-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
11357//.. //-- uInstr2(cb, STORE, 4, TempReg, t1, TempReg, t2);
11358//.. //-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_EBP);
11359//.. //-- if (d32) {
11360//.. //-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
11361//.. //-- uLiteral(cb, d32);
11362//.. //-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
11363//.. //-- }
11364//.. //-- DIP("enter 0x%x, 0x%x", d32, abyte);
11365//.. //-- break;
sewardje1698952005-02-08 15:02:39 +000011366
11367 case 0xC9: /* LEAVE */
11368 /* In 64-bit mode this defaults to a 64-bit operand size. There
11369 is no way to encode a 32-bit variant. Hence sz==4 but we do
11370 it as if sz=8. */
11371 if (sz != 4)
11372 goto decode_failure;
11373 t1 = newTemp(Ity_I64);
11374 t2 = newTemp(Ity_I64);
11375 assign(t1, getIReg64(R_RBP));
11376 /* First PUT RSP looks redundant, but need it because RSP must
11377 always be up-to-date for Memcheck to work... */
11378 putIReg64(R_RSP, mkexpr(t1));
11379 assign(t2, loadLE(Ity_I64,mkexpr(t1)));
11380 putIReg64(R_RBP, mkexpr(t2));
11381 putIReg64(R_RSP, binop(Iop_Add64, mkexpr(t1), mkU64(8)) );
11382 DIP("leave\n");
11383 break;
11384
sewardjd20c8852005-01-20 20:04:07 +000011385//.. //-- /* ---------------- Misc weird-ass insns --------------- */
11386//.. //--
11387//.. //-- case 0x27: /* DAA */
11388//.. //-- case 0x2F: /* DAS */
11389//.. //-- t1 = newTemp(cb);
11390//.. //-- uInstr2(cb, GET, 1, ArchReg, R_AL, TempReg, t1);
11391//.. //-- /* Widen %AL to 32 bits, so it's all defined when we push it. */
11392//.. //-- uInstr1(cb, WIDEN, 4, TempReg, t1);
11393//.. //-- uWiden(cb, 1, False);
11394//.. //-- uInstr0(cb, CALLM_S, 0);
11395//.. //-- uInstr1(cb, PUSH, 4, TempReg, t1);
11396//.. //-- uInstr1(cb, CALLM, 0, Lit16,
11397//.. //-- opc == 0x27 ? VGOFF_(helper_DAA) : VGOFF_(helper_DAS) );
11398//.. //-- uFlagsRWU(cb, FlagsAC, FlagsSZACP, FlagO);
11399//.. //-- uInstr1(cb, POP, 4, TempReg, t1);
11400//.. //-- uInstr0(cb, CALLM_E, 0);
11401//.. //-- uInstr2(cb, PUT, 1, TempReg, t1, ArchReg, R_AL);
11402//.. //-- DIP(opc == 0x27 ? "daa\n" : "das\n");
11403//.. //-- break;
11404//.. //--
11405//.. //-- case 0x37: /* AAA */
11406//.. //-- case 0x3F: /* AAS */
11407//.. //-- t1 = newTemp(cb);
11408//.. //-- uInstr2(cb, GET, 2, ArchReg, R_EAX, TempReg, t1);
11409//.. //-- /* Widen %AL to 32 bits, so it's all defined when we push it. */
11410//.. //-- uInstr1(cb, WIDEN, 4, TempReg, t1);
11411//.. //-- uWiden(cb, 2, False);
11412//.. //-- uInstr0(cb, CALLM_S, 0);
11413//.. //-- uInstr1(cb, PUSH, 4, TempReg, t1);
11414//.. //-- uInstr1(cb, CALLM, 0, Lit16,
11415//.. //-- opc == 0x37 ? VGOFF_(helper_AAA) : VGOFF_(helper_AAS) );
11416//.. //-- uFlagsRWU(cb, FlagA, FlagsAC, FlagsEmpty);
11417//.. //-- uInstr1(cb, POP, 4, TempReg, t1);
11418//.. //-- uInstr0(cb, CALLM_E, 0);
11419//.. //-- uInstr2(cb, PUT, 2, TempReg, t1, ArchReg, R_EAX);
11420//.. //-- DIP(opc == 0x37 ? "aaa\n" : "aas\n");
11421//.. //-- break;
11422//.. //--
11423//.. //-- case 0xD4: /* AAM */
11424//.. //-- case 0xD5: /* AAD */
sewardj8c332e22005-01-28 01:36:56 +000011425//.. //-- d32 = getUChar(delta); delta++;
sewardjd20c8852005-01-20 20:04:07 +000011426//.. //-- if (d32 != 10) VG_(core_panic)("disInstr: AAM/AAD but base not 10 !");
11427//.. //-- t1 = newTemp(cb);
11428//.. //-- uInstr2(cb, GET, 2, ArchReg, R_EAX, TempReg, t1);
11429//.. //-- /* Widen %AX to 32 bits, so it's all defined when we push it. */
11430//.. //-- uInstr1(cb, WIDEN, 4, TempReg, t1);
11431//.. //-- uWiden(cb, 2, False);
11432//.. //-- uInstr0(cb, CALLM_S, 0);
11433//.. //-- uInstr1(cb, PUSH, 4, TempReg, t1);
11434//.. //-- uInstr1(cb, CALLM, 0, Lit16,
11435//.. //-- opc == 0xD4 ? VGOFF_(helper_AAM) : VGOFF_(helper_AAD) );
11436//.. //-- uFlagsRWU(cb, FlagsEmpty, FlagsSZP, FlagsEmpty);
11437//.. //-- uInstr1(cb, POP, 4, TempReg, t1);
11438//.. //-- uInstr0(cb, CALLM_E, 0);
11439//.. //-- uInstr2(cb, PUT, 2, TempReg, t1, ArchReg, R_EAX);
11440//.. //-- DIP(opc == 0xD4 ? "aam\n" : "aad\n");
11441//.. //-- break;
sewardj3ca55a12005-01-27 16:06:23 +000011442
11443 /* ------------------------ CWD/CDQ -------------------- */
11444
11445 case 0x98: /* CBW */
11446 if (haveF2orF3(pfx)) goto decode_failure;
11447 if (sz == 8) {
sewardj5b470602005-02-27 13:10:48 +000011448 putIRegRAX( 8, unop(Iop_32Sto64, getIRegRAX(4)) );
sewardje941eea2005-01-30 19:52:28 +000011449 DIP(/*"cdqe\n"*/"cltq");
11450 break;
11451 }
sewardj3ca55a12005-01-27 16:06:23 +000011452 if (sz == 4) {
sewardj5b470602005-02-27 13:10:48 +000011453 putIRegRAX( 4, unop(Iop_16Sto32, getIRegRAX(2)) );
sewardj7eaa7cf2005-01-31 18:55:22 +000011454 DIP("cwtl\n");
sewardje941eea2005-01-30 19:52:28 +000011455 break;
11456 }
sewardj3ca55a12005-01-27 16:06:23 +000011457 if (sz == 2) {
sewardj5b470602005-02-27 13:10:48 +000011458 putIRegRAX( 2, unop(Iop_8Sto16, getIRegRAX(1)) );
sewardj3ca55a12005-01-27 16:06:23 +000011459 DIP("cbw\n");
sewardj7bc00082005-03-27 05:08:32 +000011460 break;
sewardj3ca55a12005-01-27 16:06:23 +000011461 }
sewardje941eea2005-01-30 19:52:28 +000011462 goto decode_failure;
sewardj3ca55a12005-01-27 16:06:23 +000011463
11464 case 0x99: /* CWD/CDQ/CQO */
11465 if (haveF2orF3(pfx)) goto decode_failure;
11466 vassert(sz == 2 || sz == 4 || sz == 8);
11467 ty = szToITy(sz);
sewardj5b470602005-02-27 13:10:48 +000011468 putIRegRDX( sz,
11469 binop(mkSizedOp(ty,Iop_Sar8),
11470 getIRegRAX(sz),
11471 mkU8(sz == 2 ? 15 : (sz == 4 ? 31 : 63))) );
sewardje941eea2005-01-30 19:52:28 +000011472 DIP(sz == 2 ? "cwd\n"
sewardj5b470602005-02-27 13:10:48 +000011473 : (sz == 4 ? /*"cdq\n"*/ "cltd\n"
11474 : "cqo\n"));
sewardj3ca55a12005-01-27 16:06:23 +000011475 break;
11476
sewardj8d965312005-02-25 02:48:47 +000011477 /* ------------------------ FPU ops -------------------- */
11478
sewardjd20c8852005-01-20 20:04:07 +000011479//.. case 0x9E: /* SAHF */
11480//.. codegen_SAHF();
11481//.. DIP("sahf\n");
11482//.. break;
11483//..
11484//.. //-- case 0x9F: /* LAHF */
11485//.. //-- codegen_LAHF ( cb );
11486//.. //-- DIP("lahf\n");
11487//.. //-- break;
11488//.. //--
sewardj6847d8c2005-05-12 19:21:55 +000011489 case 0x9B: /* FWAIT */
11490 /* ignore? */
11491 DIP("fwait\n");
11492 break;
sewardj8d965312005-02-25 02:48:47 +000011493
11494 case 0xD8:
11495 case 0xD9:
11496 case 0xDA:
11497 case 0xDB:
11498 case 0xDC:
11499 case 0xDD:
11500 case 0xDE:
11501 case 0xDF:
sewardj5b470602005-02-27 13:10:48 +000011502 if (haveF2orF3(pfx)) goto decode_failure;
sewardj8d965312005-02-25 02:48:47 +000011503 if (sz == 4 && haveNo66noF2noF3(pfx)) {
sewardj270def42005-07-03 01:03:01 +000011504 Long delta0 = delta;
11505 Bool decode_OK = False;
sewardj8d965312005-02-25 02:48:47 +000011506 delta = dis_FPU ( &decode_OK, pfx, delta );
11507 if (!decode_OK) {
11508 delta = delta0;
11509 goto decode_failure;
11510 }
11511 break;
11512 } else {
11513 goto decode_failure;
11514 }
11515
sewardjf8c37f72005-02-07 18:55:29 +000011516 /* ------------------------ Jcond, byte offset --------- */
11517
11518 case 0xEB: /* Jb (jump, byte offset) */
sewardj5b470602005-02-27 13:10:48 +000011519 if (haveF2orF3(pfx)) goto decode_failure;
sewardjf8c37f72005-02-07 18:55:29 +000011520 if (sz != 4)
11521 goto decode_failure; /* JRS added 2004 July 11 */
sewardj9e6491a2005-07-02 19:24:10 +000011522 d64 = (guest_RIP_bbstart+delta+1) + getSDisp8(delta);
sewardjf8c37f72005-02-07 18:55:29 +000011523 delta++;
sewardj9e6491a2005-07-02 19:24:10 +000011524 if (resteerOkFn(d64)) {
11525 dres.whatNext = Dis_Resteer;
11526 dres.continueAt = d64;
sewardjf8c37f72005-02-07 18:55:29 +000011527 } else {
11528 jmp_lit(Ijk_Boring,d64);
sewardj9e6491a2005-07-02 19:24:10 +000011529 dres.whatNext = Dis_StopHere;
sewardjf8c37f72005-02-07 18:55:29 +000011530 }
11531 DIP("jmp-8 0x%llx\n", d64);
11532 break;
sewardj1389d4d2005-01-28 13:46:29 +000011533
11534 case 0xE9: /* Jv (jump, 16/32 offset) */
sewardj5b470602005-02-27 13:10:48 +000011535 if (haveF2orF3(pfx)) goto decode_failure;
sewardjf8c37f72005-02-07 18:55:29 +000011536 if (sz != 4)
11537 goto decode_failure; /* JRS added 2004 July 11 */
sewardj9e6491a2005-07-02 19:24:10 +000011538 d64 = (guest_RIP_bbstart+delta+sz) + getSDisp(sz,delta);
sewardj1389d4d2005-01-28 13:46:29 +000011539 delta += sz;
sewardj9e6491a2005-07-02 19:24:10 +000011540 if (resteerOkFn(d64)) {
11541 dres.whatNext = Dis_Resteer;
11542 dres.continueAt = d64;
sewardj1389d4d2005-01-28 13:46:29 +000011543 } else {
11544 jmp_lit(Ijk_Boring,d64);
sewardj9e6491a2005-07-02 19:24:10 +000011545 dres.whatNext = Dis_StopHere;
sewardj1389d4d2005-01-28 13:46:29 +000011546 }
11547 DIP("jmp 0x%llx\n", d64);
11548 break;
11549
sewardjf8c37f72005-02-07 18:55:29 +000011550 case 0x70:
11551 case 0x71:
11552 case 0x72: /* JBb/JNAEb (jump below) */
11553 case 0x73: /* JNBb/JAEb (jump not below) */
11554 case 0x74: /* JZb/JEb (jump zero) */
11555 case 0x75: /* JNZb/JNEb (jump not zero) */
11556 case 0x76: /* JBEb/JNAb (jump below or equal) */
11557 case 0x77: /* JNBEb/JAb (jump not below or equal) */
11558 case 0x78: /* JSb (jump negative) */
11559 case 0x79: /* JSb (jump not negative) */
11560 case 0x7A: /* JP (jump parity even) */
11561 case 0x7B: /* JNP/JPO (jump parity odd) */
11562 case 0x7C: /* JLb/JNGEb (jump less) */
11563 case 0x7D: /* JGEb/JNLb (jump greater or equal) */
11564 case 0x7E: /* JLEb/JNGb (jump less or equal) */
11565 case 0x7F: /* JGb/JNLEb (jump greater) */
sewardj5b470602005-02-27 13:10:48 +000011566 if (haveF2orF3(pfx)) goto decode_failure;
sewardj9e6491a2005-07-02 19:24:10 +000011567 d64 = (guest_RIP_bbstart+delta+1) + getSDisp8(delta);
sewardjf8c37f72005-02-07 18:55:29 +000011568 delta++;
11569 jcc_01( (AMD64Condcode)(opc - 0x70),
sewardj9e6491a2005-07-02 19:24:10 +000011570 guest_RIP_bbstart+delta,
sewardjf8c37f72005-02-07 18:55:29 +000011571 d64 );
sewardj9e6491a2005-07-02 19:24:10 +000011572 dres.whatNext = Dis_StopHere;
sewardjf8c37f72005-02-07 18:55:29 +000011573 DIP("j%s-8 0x%llx\n", name_AMD64Condcode(opc - 0x70), d64);
11574 break;
11575
sewardjfdfa8862005-10-05 16:58:23 +000011576 case 0xE3: /* JRCXZ or perhaps JECXZ, depending on OSO ? Intel
11577 manual says it depends on address size override,
11578 which doesn't sound right to me. But the amd manual
11579 alsay says that, so I guess it is. In which case 8
11580 is the only valid size. */
11581 if (have66orF2orF3(pfx) || haveASO(pfx)) goto decode_failure;
11582 d64 = (guest_RIP_bbstart+delta+1) + getSDisp8(delta);
11583 delta++;
11584 stmt( IRStmt_Exit( binop(Iop_CmpEQ64, getIReg64(R_RCX), mkU64(0)),
11585 Ijk_Boring,
11586 IRConst_U64(d64))
11587 );
11588 DIP("jrcxz 0x%llx\n", d64);
11589 break;
sewardj6359f812005-07-20 10:15:34 +000011590
sewardje8f65252005-08-23 23:44:35 +000011591 case 0xE0: /* LOOPNE disp8: decrement count, jump if count != 0 && ZF==0 */
11592 case 0xE1: /* LOOPE disp8: decrement count, jump if count != 0 && ZF==1 */
11593 case 0xE2: /* LOOP disp8: decrement count, jump if count != 0 */
11594 { /* The docs say this uses rCX as a count depending on the
11595 address size override, not the operand one. Since we don't
11596 handle address size overrides, I guess that means RCX. */
11597 IRExpr* zbit = NULL;
11598 IRExpr* count = NULL;
11599 IRExpr* cond = NULL;
11600 HChar* xtra = NULL;
11601
11602 if (have66orF2orF3(pfx) || haveASO(pfx)) goto decode_failure;
11603 d64 = guest_RIP_bbstart+delta+1 + getSDisp8(delta);
11604 delta++;
11605 putIReg64(R_RCX, binop(Iop_Sub64, getIReg64(R_RCX), mkU64(1)));
11606
11607 count = getIReg64(R_RCX);
11608 cond = binop(Iop_CmpNE64, count, mkU64(0));
11609 switch (opc) {
11610 case 0xE2:
11611 xtra = "";
11612 break;
11613 case 0xE1:
11614 xtra = "e";
11615 zbit = mk_amd64g_calculate_condition( AMD64CondZ );
11616 cond = mkAnd1(cond, zbit);
11617 break;
11618 case 0xE0:
11619 xtra = "ne";
11620 zbit = mk_amd64g_calculate_condition( AMD64CondNZ );
11621 cond = mkAnd1(cond, zbit);
11622 break;
11623 default:
11624 vassert(0);
11625 }
11626 stmt( IRStmt_Exit(cond, Ijk_Boring, IRConst_U64(d64)) );
11627
11628 DIP("loop%s 0x%llx\n", xtra, d64);
11629 break;
11630 }
sewardj32b2bbe2005-01-28 00:50:10 +000011631
11632 /* ------------------------ IMUL ----------------------- */
11633
11634 case 0x69: /* IMUL Iv, Ev, Gv */
sewardj5b470602005-02-27 13:10:48 +000011635 if (haveF2orF3(pfx)) goto decode_failure;
sewardj32b2bbe2005-01-28 00:50:10 +000011636 delta = dis_imul_I_E_G ( pfx, sz, delta, sz );
11637 break;
sewardj7de0d3c2005-02-13 02:26:41 +000011638 case 0x6B: /* IMUL Ib, Ev, Gv */
11639 delta = dis_imul_I_E_G ( pfx, sz, delta, 1 );
11640 break;
sewardj1389d4d2005-01-28 13:46:29 +000011641
11642 /* ------------------------ MOV ------------------------ */
11643
11644 case 0x88: /* MOV Gb,Eb */
sewardj5b470602005-02-27 13:10:48 +000011645 if (haveF2orF3(pfx)) goto decode_failure;
sewardj1389d4d2005-01-28 13:46:29 +000011646 delta = dis_mov_G_E(pfx, 1, delta);
11647 break;
11648
11649 case 0x89: /* MOV Gv,Ev */
sewardj5b470602005-02-27 13:10:48 +000011650 if (haveF2orF3(pfx)) goto decode_failure;
sewardj1389d4d2005-01-28 13:46:29 +000011651 delta = dis_mov_G_E(pfx, sz, delta);
11652 break;
11653
sewardjd0a12df2005-02-10 02:07:43 +000011654 case 0x8A: /* MOV Eb,Gb */
sewardj5b470602005-02-27 13:10:48 +000011655 if (haveF2orF3(pfx)) goto decode_failure;
sewardjd0a12df2005-02-10 02:07:43 +000011656 delta = dis_mov_E_G(pfx, 1, delta);
11657 break;
11658
sewardj1389d4d2005-01-28 13:46:29 +000011659 case 0x8B: /* MOV Ev,Gv */
sewardj5b470602005-02-27 13:10:48 +000011660 if (haveF2orF3(pfx)) goto decode_failure;
sewardj1389d4d2005-01-28 13:46:29 +000011661 delta = dis_mov_E_G(pfx, sz, delta);
11662 break;
11663
11664 case 0x8D: /* LEA M,Gv */
sewardj5b470602005-02-27 13:10:48 +000011665 if (haveF2orF3(pfx)) goto decode_failure;
sewardj1389d4d2005-01-28 13:46:29 +000011666 if (sz != 4 && sz != 8)
11667 goto decode_failure;
11668 modrm = getUChar(delta);
11669 if (epartIsReg(modrm))
11670 goto decode_failure;
11671 /* NOTE! this is the one place where a segment override prefix
11672 has no effect on the address calculation. Therefore we clear
11673 any segment override bits in pfx. */
sewardje1698952005-02-08 15:02:39 +000011674 addr = disAMode ( &alen, clearSegBits(pfx), delta, dis_buf, 0 );
sewardj1389d4d2005-01-28 13:46:29 +000011675 delta += alen;
11676 /* This is a hack. But it isn't clear that really doing the
11677 calculation at 32 bits is really worth it. Hence for leal,
11678 do the full 64-bit calculation and then truncate it. */
sewardj5b470602005-02-27 13:10:48 +000011679 putIRegG( sz, pfx, modrm,
sewardj1389d4d2005-01-28 13:46:29 +000011680 sz == 4
11681 ? unop(Iop_64to32, mkexpr(addr))
11682 : mkexpr(addr)
11683 );
11684 DIP("lea%c %s, %s\n", nameISize(sz), dis_buf,
sewardj5b470602005-02-27 13:10:48 +000011685 nameIRegG(sz,pfx,modrm));
sewardj1389d4d2005-01-28 13:46:29 +000011686 break;
11687
sewardjd20c8852005-01-20 20:04:07 +000011688//.. case 0x8C: /* MOV Sw,Ew -- MOV from a SEGMENT REGISTER */
11689//.. delta = dis_mov_Sw_Ew(sorb, sz, delta);
11690//.. break;
11691//..
11692//.. case 0x8E: /* MOV Ew,Sw -- MOV to a SEGMENT REGISTER */
11693//.. delta = dis_mov_Ew_Sw(sorb, delta);
11694//.. break;
sewardj2bd97d12005-08-02 21:27:25 +000011695
11696 case 0xA0: /* MOV Ob,AL */
11697 if (have66orF2orF3(pfx)) goto decode_failure;
11698 sz = 1;
11699 /* Fall through ... */
sewardj87277cb2005-08-01 13:03:32 +000011700 case 0xA1: /* MOV Ov,eAX */
sewardj2bd97d12005-08-02 21:27:25 +000011701 if (sz != 8 && sz != 4 && sz != 2 && sz != 1)
11702 goto decode_failure;
sewardj87277cb2005-08-01 13:03:32 +000011703 d64 = getDisp64(delta);
11704 delta += 8;
11705 ty = szToITy(sz);
11706 addr = newTemp(Ity_I64);
11707 assign( addr, handleSegOverride(pfx, mkU64(d64)) );
11708 putIRegRAX(sz, loadLE( ty, mkexpr(addr) ));
11709 DIP("mov%c %s0x%llx, %s\n", nameISize(sz),
11710 sorbTxt(pfx), d64,
11711 nameIRegRAX(sz));
11712 break;
11713
sewardj2bd97d12005-08-02 21:27:25 +000011714 case 0xA2: /* MOV AL,Ob */
11715 if (have66orF2orF3(pfx)) goto decode_failure;
11716 sz = 1;
11717 /* Fall through ... */
sewardj87277cb2005-08-01 13:03:32 +000011718 case 0xA3: /* MOV eAX,Ov */
sewardj2bd97d12005-08-02 21:27:25 +000011719 if (sz != 8 && sz != 4 && sz != 2 && sz != 1)
11720 goto decode_failure;
sewardj87277cb2005-08-01 13:03:32 +000011721 d64 = getDisp64(delta);
11722 delta += 8;
11723 ty = szToITy(sz);
11724 addr = newTemp(Ity_I64);
11725 assign( addr, handleSegOverride(pfx, mkU64(d64)) );
11726 storeLE( mkexpr(addr), getIRegRAX(sz) );
11727 DIP("mov%c %s, %s0x%llx\n", nameISize(sz), nameIRegRAX(sz),
11728 sorbTxt(pfx), d64);
11729 break;
sewardjb095fba2005-02-13 14:13:04 +000011730
sewardj8711f662005-05-09 17:52:56 +000011731 /* XXXX be careful here with moves to AH/BH/CH/DH */
sewardj007e9ec2005-03-23 11:36:48 +000011732 case 0xB0: /* MOV imm,AL */
11733 case 0xB1: /* MOV imm,CL */
sewardjb095fba2005-02-13 14:13:04 +000011734 case 0xB2: /* MOV imm,DL */
sewardj007e9ec2005-03-23 11:36:48 +000011735 case 0xB3: /* MOV imm,BL */
11736 case 0xB4: /* MOV imm,AH */
11737 case 0xB5: /* MOV imm,CH */
11738 case 0xB6: /* MOV imm,DH */
sewardj31eecde2005-03-23 03:39:55 +000011739 case 0xB7: /* MOV imm,BH */
sewardj5b470602005-02-27 13:10:48 +000011740 if (haveF2orF3(pfx)) goto decode_failure;
sewardjb095fba2005-02-13 14:13:04 +000011741 d64 = getUChar(delta);
11742 delta += 1;
sewardj5b470602005-02-27 13:10:48 +000011743 putIRegRexB(1, pfx, opc-0xB0, mkU8(d64));
11744 DIP("movb $%lld,%s\n", d64, nameIRegRexB(1,pfx,opc-0xB0));
sewardjb095fba2005-02-13 14:13:04 +000011745 break;
sewardj1389d4d2005-01-28 13:46:29 +000011746
11747 case 0xB8: /* MOV imm,eAX */
11748 case 0xB9: /* MOV imm,eCX */
11749 case 0xBA: /* MOV imm,eDX */
11750 case 0xBB: /* MOV imm,eBX */
11751 case 0xBC: /* MOV imm,eSP */
11752 case 0xBD: /* MOV imm,eBP */
11753 case 0xBE: /* MOV imm,eSI */
11754 case 0xBF: /* MOV imm,eDI */
sewardj03b07cc2005-01-31 18:09:43 +000011755 /* This is the one-and-only place where 64-bit literals are
11756 allowed in the instruction stream. */
sewardj5b470602005-02-27 13:10:48 +000011757 if (haveF2orF3(pfx)) goto decode_failure;
sewardj03b07cc2005-01-31 18:09:43 +000011758 if (sz == 8) {
11759 d64 = getDisp64(delta);
sewardj7eaa7cf2005-01-31 18:55:22 +000011760 delta += 8;
sewardj5b470602005-02-27 13:10:48 +000011761 putIRegRexB(8, pfx, opc-0xB8, mkU64(d64));
sewardj227458e2005-01-31 19:04:50 +000011762 DIP("movabsq $%lld,%s\n", (Long)d64,
sewardj5b470602005-02-27 13:10:48 +000011763 nameIRegRexB(8,pfx,opc-0xB8));
sewardj03b07cc2005-01-31 18:09:43 +000011764 } else {
11765 d64 = getSDisp(imin(4,sz),delta);
11766 delta += imin(4,sz);
sewardj5b470602005-02-27 13:10:48 +000011767 putIRegRexB(sz, pfx, opc-0xB8,
11768 mkU(szToITy(sz), d64 & mkSizeMask(sz)));
sewardj227458e2005-01-31 19:04:50 +000011769 DIP("mov%c $%lld,%s\n", nameISize(sz),
11770 (Long)d64,
sewardj5b470602005-02-27 13:10:48 +000011771 nameIRegRexB(sz,pfx,opc-0xB8));
sewardj03b07cc2005-01-31 18:09:43 +000011772 }
sewardj1389d4d2005-01-28 13:46:29 +000011773 break;
11774
11775 case 0xC6: /* MOV Ib,Eb */
11776 sz = 1;
11777 goto do_Mov_I_E;
11778 case 0xC7: /* MOV Iv,Ev */
11779 goto do_Mov_I_E;
11780
11781 do_Mov_I_E:
sewardj5b470602005-02-27 13:10:48 +000011782 if (haveF2orF3(pfx)) goto decode_failure;
sewardj1389d4d2005-01-28 13:46:29 +000011783 modrm = getUChar(delta);
11784 if (epartIsReg(modrm)) {
sewardj1389d4d2005-01-28 13:46:29 +000011785 delta++; /* mod/rm byte */
11786 d64 = getSDisp(imin(4,sz),delta);
11787 delta += imin(4,sz);
sewardj5b470602005-02-27 13:10:48 +000011788 putIRegE(sz, pfx, modrm,
11789 mkU(szToITy(sz), d64 & mkSizeMask(sz)));
sewardj227458e2005-01-31 19:04:50 +000011790 DIP("mov%c $%lld, %s\n", nameISize(sz),
11791 (Long)d64,
sewardj5b470602005-02-27 13:10:48 +000011792 nameIRegE(sz,pfx,modrm));
sewardj1389d4d2005-01-28 13:46:29 +000011793 } else {
sewardj5b470602005-02-27 13:10:48 +000011794 addr = disAMode ( &alen, pfx, delta, dis_buf,
11795 /*xtra*/imin(4,sz) );
sewardj1389d4d2005-01-28 13:46:29 +000011796 delta += alen;
sewardje941eea2005-01-30 19:52:28 +000011797 d64 = getSDisp(imin(4,sz),delta);
sewardj1389d4d2005-01-28 13:46:29 +000011798 delta += imin(4,sz);
sewardje941eea2005-01-30 19:52:28 +000011799 storeLE(mkexpr(addr),
11800 mkU(szToITy(sz), d64 & mkSizeMask(sz)));
sewardj227458e2005-01-31 19:04:50 +000011801 DIP("mov%c $%lld, %s\n", nameISize(sz), (Long)d64, dis_buf);
sewardj1389d4d2005-01-28 13:46:29 +000011802 }
11803 break;
11804
sewardj5e525292005-01-28 15:13:10 +000011805 /* ------------------------ MOVx ------------------------ */
11806
11807 case 0x63: /* MOVSX */
sewardj5b470602005-02-27 13:10:48 +000011808 if (haveF2orF3(pfx)) goto decode_failure;
sewardj5e525292005-01-28 15:13:10 +000011809 if (haveREX(pfx) && 1==getRexW(pfx)) {
11810 vassert(sz == 8);
11811 /* movsx r/m32 to r64 */
11812 modrm = getUChar(delta);
11813 if (epartIsReg(modrm)) {
11814 delta++;
sewardj5b470602005-02-27 13:10:48 +000011815 putIRegG(8, pfx, modrm,
sewardj5e525292005-01-28 15:13:10 +000011816 unop(Iop_32Sto64,
sewardj5b470602005-02-27 13:10:48 +000011817 getIRegE(4, pfx, modrm)));
sewardj5e525292005-01-28 15:13:10 +000011818 DIP("movslq %s,%s\n",
sewardj5b470602005-02-27 13:10:48 +000011819 nameIRegE(4, pfx, modrm),
11820 nameIRegG(8, pfx, modrm));
sewardj5e525292005-01-28 15:13:10 +000011821 break;
11822 } else {
sewardje1698952005-02-08 15:02:39 +000011823 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
sewardj5e525292005-01-28 15:13:10 +000011824 delta += alen;
sewardj5b470602005-02-27 13:10:48 +000011825 putIRegG(8, pfx, modrm,
sewardj5e525292005-01-28 15:13:10 +000011826 unop(Iop_32Sto64,
11827 loadLE(Ity_I32, mkexpr(addr))));
11828 DIP("movslq %s,%s\n", dis_buf,
sewardj5b470602005-02-27 13:10:48 +000011829 nameIRegG(8, pfx, modrm));
sewardj5e525292005-01-28 15:13:10 +000011830 break;
11831 }
11832 } else {
11833 goto decode_failure;
11834 }
11835
sewardj4c328cf2005-05-05 12:05:54 +000011836 /* ------------------------ opl imm, A ----------------- */
11837
11838 case 0x04: /* ADD Ib, AL */
11839 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000011840 delta = dis_op_imm_A( 1, False, Iop_Add8, True, delta, "add" );
sewardj4c328cf2005-05-05 12:05:54 +000011841 break;
sewardj03b07cc2005-01-31 18:09:43 +000011842 case 0x05: /* ADD Iv, eAX */
sewardj5b470602005-02-27 13:10:48 +000011843 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000011844 delta = dis_op_imm_A(sz, False, Iop_Add8, True, delta, "add" );
sewardj03b07cc2005-01-31 18:09:43 +000011845 break;
11846
sewardj007e9ec2005-03-23 11:36:48 +000011847 case 0x0C: /* OR Ib, AL */
11848 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000011849 delta = dis_op_imm_A( 1, False, Iop_Or8, True, delta, "or" );
sewardj007e9ec2005-03-23 11:36:48 +000011850 break;
sewardj03b07cc2005-01-31 18:09:43 +000011851 case 0x0D: /* OR Iv, eAX */
sewardj5b470602005-02-27 13:10:48 +000011852 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000011853 delta = dis_op_imm_A( sz, False, Iop_Or8, True, delta, "or" );
sewardj03b07cc2005-01-31 18:09:43 +000011854 break;
11855
sewardj41c01092005-07-23 13:50:32 +000011856 case 0x14: /* ADC Ib, AL */
11857 delta = dis_op_imm_A( 1, True, Iop_Add8, True, delta, "adc" );
11858 break;
sewardjd20c8852005-01-20 20:04:07 +000011859//.. //-- case 0x15: /* ADC Iv, eAX */
11860//.. //-- delta = dis_op_imm_A( sz, ADC, True, delta, "adc" );
11861//.. //-- break;
11862//.. //--
11863//.. //-- case 0x1C: /* SBB Ib, AL */
11864//.. //-- delta = dis_op_imm_A( 1, SBB, True, delta, "sbb" );
11865//.. //-- break;
11866//.. //-- case 0x1D: /* SBB Iv, eAX */
11867//.. //-- delta = dis_op_imm_A( sz, SBB, True, delta, "sbb" );
11868//.. //-- break;
11869//.. //--
sewardj007e9ec2005-03-23 11:36:48 +000011870 case 0x24: /* AND Ib, AL */
11871 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000011872 delta = dis_op_imm_A( 1, False, Iop_And8, True, delta, "and" );
sewardj007e9ec2005-03-23 11:36:48 +000011873 break;
sewardj3ca55a12005-01-27 16:06:23 +000011874 case 0x25: /* AND Iv, eAX */
11875 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000011876 delta = dis_op_imm_A( sz, False, Iop_And8, True, delta, "and" );
sewardj3ca55a12005-01-27 16:06:23 +000011877 break;
11878
sewardj137015d2005-03-27 04:01:15 +000011879 case 0x2C: /* SUB Ib, AL */
11880 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000011881 delta = dis_op_imm_A(1, False, Iop_Sub8, True, delta, "sub" );
sewardj137015d2005-03-27 04:01:15 +000011882 break;
sewardj03b07cc2005-01-31 18:09:43 +000011883 case 0x2D: /* SUB Iv, eAX */
sewardj5b470602005-02-27 13:10:48 +000011884 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000011885 delta = dis_op_imm_A( sz, False, Iop_Sub8, True, delta, "sub" );
sewardj03b07cc2005-01-31 18:09:43 +000011886 break;
11887
sewardj8eb804f2005-05-18 10:22:47 +000011888 case 0x34: /* XOR Ib, AL */
11889 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000011890 delta = dis_op_imm_A( 1, False, Iop_Xor8, True, delta, "xor" );
sewardj8eb804f2005-05-18 10:22:47 +000011891 break;
sewardj85520e42005-02-19 15:22:38 +000011892 case 0x35: /* XOR Iv, eAX */
sewardj5b470602005-02-27 13:10:48 +000011893 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000011894 delta = dis_op_imm_A( sz, False, Iop_Xor8, True, delta, "xor" );
sewardj85520e42005-02-19 15:22:38 +000011895 break;
sewardj03b07cc2005-01-31 18:09:43 +000011896
11897 case 0x3C: /* CMP Ib, AL */
11898 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000011899 delta = dis_op_imm_A( 1, False, Iop_Sub8, False, delta, "cmp" );
sewardj03b07cc2005-01-31 18:09:43 +000011900 break;
sewardj354e5c62005-01-27 20:12:52 +000011901 case 0x3D: /* CMP Iv, eAX */
11902 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000011903 delta = dis_op_imm_A( sz, False, Iop_Sub8, False, delta, "cmp" );
sewardj354e5c62005-01-27 20:12:52 +000011904 break;
11905
sewardj118b23e2005-01-29 02:14:44 +000011906 case 0xA8: /* TEST Ib, AL */
sewardj03b07cc2005-01-31 18:09:43 +000011907 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000011908 delta = dis_op_imm_A( 1, False, Iop_And8, False, delta, "test" );
sewardj118b23e2005-01-29 02:14:44 +000011909 break;
11910 case 0xA9: /* TEST Iv, eAX */
sewardj03b07cc2005-01-31 18:09:43 +000011911 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000011912 delta = dis_op_imm_A( sz, False, Iop_And8, False, delta, "test" );
sewardj118b23e2005-01-29 02:14:44 +000011913 break;
11914
11915 /* ------------------------ opl Ev, Gv ----------------- */
11916
sewardj03b07cc2005-01-31 18:09:43 +000011917 case 0x02: /* ADD Eb,Gb */
11918 if (haveF2orF3(pfx)) goto decode_failure;
11919 delta = dis_op2_E_G ( pfx, False, Iop_Add8, True, 1, delta, "add" );
11920 break;
sewardjdf0e0022005-01-25 15:48:43 +000011921 case 0x03: /* ADD Ev,Gv */
sewardj3ca55a12005-01-27 16:06:23 +000011922 if (haveF2orF3(pfx)) goto decode_failure;
sewardjdf0e0022005-01-25 15:48:43 +000011923 delta = dis_op2_E_G ( pfx, False, Iop_Add8, True, sz, delta, "add" );
sewardjdf0e0022005-01-25 15:48:43 +000011924 break;
11925
sewardj03b07cc2005-01-31 18:09:43 +000011926 case 0x0A: /* OR Eb,Gb */
sewardj5b470602005-02-27 13:10:48 +000011927 if (haveF2orF3(pfx)) goto decode_failure;
sewardj03b07cc2005-01-31 18:09:43 +000011928 delta = dis_op2_E_G ( pfx, False, Iop_Or8, True, 1, delta, "or" );
11929 break;
11930 case 0x0B: /* OR Ev,Gv */
sewardj5b470602005-02-27 13:10:48 +000011931 if (haveF2orF3(pfx)) goto decode_failure;
sewardj03b07cc2005-01-31 18:09:43 +000011932 delta = dis_op2_E_G ( pfx, False, Iop_Or8, True, sz, delta, "or" );
11933 break;
11934//--
sewardjd20c8852005-01-20 20:04:07 +000011935//.. //-- case 0x12: /* ADC Eb,Gb */
11936//.. //-- delta = dis_op2_E_G ( sorb, True, ADC, True, 1, delta, "adc" );
11937//.. //-- break;
sewardj22cab062005-07-19 23:59:54 +000011938 case 0x13: /* ADC Ev,Gv */
11939 delta = dis_op2_E_G ( pfx, True, Iop_Add8, True, sz, delta, "adc" );
11940 break;
11941
sewardjd20c8852005-01-20 20:04:07 +000011942//.. //-- case 0x1A: /* SBB Eb,Gb */
11943//.. //-- delta = dis_op2_E_G ( sorb, True, SBB, True, 1, delta, "sbb" );
11944//.. //-- break;
sewardj7a06b852005-07-20 10:55:26 +000011945 case 0x1B: /* SBB Ev,Gv */
11946 delta = dis_op2_E_G ( pfx, True, Iop_Sub8, True, sz, delta, "sbb" );
11947 break;
sewardj03b07cc2005-01-31 18:09:43 +000011948
11949 case 0x22: /* AND Eb,Gb */
11950 if (haveF2orF3(pfx)) goto decode_failure;
11951 delta = dis_op2_E_G ( pfx, False, Iop_And8, True, 1, delta, "and" );
11952 break;
11953 case 0x23: /* AND Ev,Gv */
11954 if (haveF2orF3(pfx)) goto decode_failure;
11955 delta = dis_op2_E_G ( pfx, False, Iop_And8, True, sz, delta, "and" );
11956 break;
11957
11958 case 0x2A: /* SUB Eb,Gb */
11959 if (haveF2orF3(pfx)) goto decode_failure;
11960 delta = dis_op2_E_G ( pfx, False, Iop_Sub8, True, 1, delta, "sub" );
11961 break;
sewardj118b23e2005-01-29 02:14:44 +000011962 case 0x2B: /* SUB Ev,Gv */
sewardj03b07cc2005-01-31 18:09:43 +000011963 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000011964 delta = dis_op2_E_G ( pfx, False, Iop_Sub8, True, sz, delta, "sub" );
11965 break;
11966
sewardj03b07cc2005-01-31 18:09:43 +000011967 case 0x32: /* XOR Eb,Gb */
11968 if (haveF2orF3(pfx)) goto decode_failure;
11969 delta = dis_op2_E_G ( pfx, False, Iop_Xor8, True, 1, delta, "xor" );
11970 break;
11971 case 0x33: /* XOR Ev,Gv */
11972 if (haveF2orF3(pfx)) goto decode_failure;
11973 delta = dis_op2_E_G ( pfx, False, Iop_Xor8, True, sz, delta, "xor" );
11974 break;
11975
sewardjb095fba2005-02-13 14:13:04 +000011976 case 0x3A: /* CMP Eb,Gb */
11977 if (haveF2orF3(pfx)) goto decode_failure;
11978 delta = dis_op2_E_G ( pfx, False, Iop_Sub8, False, 1, delta, "cmp" );
11979 break;
sewardj354e5c62005-01-27 20:12:52 +000011980 case 0x3B: /* CMP Ev,Gv */
11981 if (haveF2orF3(pfx)) goto decode_failure;
11982 delta = dis_op2_E_G ( pfx, False, Iop_Sub8, False, sz, delta, "cmp" );
11983 break;
11984
sewardj118b23e2005-01-29 02:14:44 +000011985 case 0x84: /* TEST Eb,Gb */
sewardj03b07cc2005-01-31 18:09:43 +000011986 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000011987 delta = dis_op2_E_G ( pfx, False, Iop_And8, False, 1, delta, "test" );
11988 break;
11989 case 0x85: /* TEST Ev,Gv */
sewardj03b07cc2005-01-31 18:09:43 +000011990 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000011991 delta = dis_op2_E_G ( pfx, False, Iop_And8, False, sz, delta, "test" );
11992 break;
11993
11994 /* ------------------------ opl Gv, Ev ----------------- */
11995
sewardj85520e42005-02-19 15:22:38 +000011996 case 0x00: /* ADD Gb,Eb */
11997 if (haveF2orF3(pfx)) goto decode_failure;
11998 delta = dis_op2_G_E ( pfx, False, Iop_Add8, True, 1, delta, "add" );
11999 break;
sewardj3ca55a12005-01-27 16:06:23 +000012000 case 0x01: /* ADD Gv,Ev */
sewardj354e5c62005-01-27 20:12:52 +000012001 if (haveF2orF3(pfx)) goto decode_failure;
sewardj3ca55a12005-01-27 16:06:23 +000012002 delta = dis_op2_G_E ( pfx, False, Iop_Add8, True, sz, delta, "add" );
12003 break;
12004
sewardj03b07cc2005-01-31 18:09:43 +000012005 case 0x08: /* OR Gb,Eb */
12006 if (haveF2orF3(pfx)) goto decode_failure;
12007 delta = dis_op2_G_E ( pfx, False, Iop_Or8, True, 1, delta, "or" );
12008 break;
sewardj55dbb262005-01-28 16:36:51 +000012009 case 0x09: /* OR Gv,Ev */
12010 if (haveF2orF3(pfx)) goto decode_failure;
12011 delta = dis_op2_G_E ( pfx, False, Iop_Or8, True, sz, delta, "or" );
12012 break;
12013
sewardj85520e42005-02-19 15:22:38 +000012014 case 0x10: /* ADC Gb,Eb */
12015 if (haveF2orF3(pfx)) goto decode_failure;
12016 delta = dis_op2_G_E ( pfx, True, Iop_Add8, True, 1, delta, "adc" );
12017 break;
12018 case 0x11: /* ADC Gv,Ev */
12019 if (haveF2orF3(pfx)) goto decode_failure;
12020 delta = dis_op2_G_E ( pfx, True, Iop_Add8, True, sz, delta, "adc" );
12021 break;
12022
12023 case 0x18: /* SBB Gb,Eb */
12024 if (haveF2orF3(pfx)) goto decode_failure;
12025 delta = dis_op2_G_E ( pfx, True, Iop_Sub8, True, 1, delta, "sbb" );
12026 break;
sewardj03b07cc2005-01-31 18:09:43 +000012027 case 0x19: /* SBB Gv,Ev */
sewardja6b93d12005-02-17 09:28:28 +000012028 if (haveF2orF3(pfx)) goto decode_failure;
sewardj03b07cc2005-01-31 18:09:43 +000012029 delta = dis_op2_G_E ( pfx, True, Iop_Sub8, True, sz, delta, "sbb" );
12030 break;
12031
sewardj85520e42005-02-19 15:22:38 +000012032 case 0x20: /* AND Gb,Eb */
12033 if (haveF2orF3(pfx)) goto decode_failure;
12034 delta = dis_op2_G_E ( pfx, False, Iop_And8, True, 1, delta, "and" );
12035 break;
sewardj3ca55a12005-01-27 16:06:23 +000012036 case 0x21: /* AND Gv,Ev */
sewardj354e5c62005-01-27 20:12:52 +000012037 if (haveF2orF3(pfx)) goto decode_failure;
sewardj3ca55a12005-01-27 16:06:23 +000012038 delta = dis_op2_G_E ( pfx, False, Iop_And8, True, sz, delta, "and" );
12039 break;
sewardj03b07cc2005-01-31 18:09:43 +000012040
12041 case 0x28: /* SUB Gb,Eb */
12042 if (haveF2orF3(pfx)) goto decode_failure;
12043 delta = dis_op2_G_E ( pfx, False, Iop_Sub8, True, 1, delta, "sub" );
12044 break;
sewardj118b23e2005-01-29 02:14:44 +000012045 case 0x29: /* SUB Gv,Ev */
sewardj03b07cc2005-01-31 18:09:43 +000012046 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000012047 delta = dis_op2_G_E ( pfx, False, Iop_Sub8, True, sz, delta, "sub" );
12048 break;
12049
sewardjb095fba2005-02-13 14:13:04 +000012050 case 0x30: /* XOR Gb,Eb */
12051 if (haveF2orF3(pfx)) goto decode_failure;
12052 delta = dis_op2_G_E ( pfx, False, Iop_Xor8, True, 1, delta, "xor" );
12053 break;
sewardj118b23e2005-01-29 02:14:44 +000012054 case 0x31: /* XOR Gv,Ev */
sewardj03b07cc2005-01-31 18:09:43 +000012055 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000012056 delta = dis_op2_G_E ( pfx, False, Iop_Xor8, True, sz, delta, "xor" );
12057 break;
sewardj354e5c62005-01-27 20:12:52 +000012058
12059 case 0x38: /* CMP Gb,Eb */
12060 if (haveF2orF3(pfx)) goto decode_failure;
12061 delta = dis_op2_G_E ( pfx, False, Iop_Sub8, False, 1, delta, "cmp" );
12062 break;
12063 case 0x39: /* CMP Gv,Ev */
12064 if (haveF2orF3(pfx)) goto decode_failure;
12065 delta = dis_op2_G_E ( pfx, False, Iop_Sub8, False, sz, delta, "cmp" );
12066 break;
12067
sewardj55dbb262005-01-28 16:36:51 +000012068 /* ------------------------ POP ------------------------ */
12069
12070 case 0x58: /* POP eAX */
12071 case 0x59: /* POP eCX */
12072 case 0x5A: /* POP eDX */
12073 case 0x5B: /* POP eBX */
12074 case 0x5D: /* POP eBP */
12075 case 0x5E: /* POP eSI */
12076 case 0x5F: /* POP eDI */
12077 case 0x5C: /* POP eSP */
sewardj03b07cc2005-01-31 18:09:43 +000012078 if (haveF2orF3(pfx)) goto decode_failure;
sewardj55dbb262005-01-28 16:36:51 +000012079 vassert(sz == 2 || sz == 4 || sz == 8);
12080 if (sz == 4)
12081 sz = 8; /* there is no encoding for 32-bit pop in 64-bit mode */
12082 t1 = newTemp(szToITy(sz));
12083 t2 = newTemp(Ity_I64);
12084 assign(t2, getIReg64(R_RSP));
12085 assign(t1, loadLE(szToITy(sz),mkexpr(t2)));
12086 putIReg64(R_RSP, binop(Iop_Add64, mkexpr(t2), mkU64(sz)));
sewardj5b470602005-02-27 13:10:48 +000012087 putIRegRexB(sz, pfx, opc-0x58, mkexpr(t1));
12088 DIP("pop%c %s\n", nameISize(sz), nameIRegRexB(sz,pfx,opc-0x58));
sewardj55dbb262005-01-28 16:36:51 +000012089 break;
12090
sewardj85520e42005-02-19 15:22:38 +000012091 case 0x9D: /* POPF */
12092 /* Note. There is no encoding for a 32-bit popf in 64-bit mode.
12093 So sz==4 actually means sz==8. */
sewardj5b470602005-02-27 13:10:48 +000012094 if (haveF2orF3(pfx)) goto decode_failure;
sewardj85520e42005-02-19 15:22:38 +000012095 vassert(sz == 2 || sz == 4);
12096 if (sz == 4) sz = 8;
sewardj5b470602005-02-27 13:10:48 +000012097 if (sz != 8) goto decode_failure; // until we know a sz==2 test case exists
sewardj85520e42005-02-19 15:22:38 +000012098 t1 = newTemp(Ity_I64); t2 = newTemp(Ity_I64);
12099 assign(t2, getIReg64(R_RSP));
12100 assign(t1, widenUto64(loadLE(szToITy(sz),mkexpr(t2))));
12101 putIReg64(R_RSP, binop(Iop_Add64, mkexpr(t2), mkU64(sz)));
12102 /* t1 is the flag word. Mask out everything except OSZACP and
12103 set the flags thunk to AMD64G_CC_OP_COPY. */
12104 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(AMD64G_CC_OP_COPY) ));
12105 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
12106 stmt( IRStmt_Put( OFFB_CC_DEP1,
12107 binop(Iop_And64,
12108 mkexpr(t1),
12109 mkU64( AMD64G_CC_MASK_C | AMD64G_CC_MASK_P
12110 | AMD64G_CC_MASK_A | AMD64G_CC_MASK_Z
12111 | AMD64G_CC_MASK_S| AMD64G_CC_MASK_O )
12112 )
12113 )
12114 );
12115
12116 /* Also need to set the D flag, which is held in bit 10 of t1.
12117 If zero, put 1 in OFFB_DFLAG, else -1 in OFFB_DFLAG. */
12118 stmt( IRStmt_Put(
12119 OFFB_DFLAG,
12120 IRExpr_Mux0X(
12121 unop(Iop_32to8,
12122 unop(Iop_64to32,
12123 binop(Iop_And64,
12124 binop(Iop_Shr64, mkexpr(t1), mkU8(10)),
12125 mkU64(1)))),
12126 mkU64(1),
12127 mkU64(0xFFFFFFFFFFFFFFFFULL)))
12128 );
12129
12130 /* And set the ID flag */
12131 stmt( IRStmt_Put(
12132 OFFB_IDFLAG,
12133 IRExpr_Mux0X(
12134 unop(Iop_32to8,
12135 unop(Iop_64to32,
12136 binop(Iop_And64,
12137 binop(Iop_Shr64, mkexpr(t1), mkU8(21)),
12138 mkU64(1)))),
12139 mkU64(0),
12140 mkU64(1)))
12141 );
12142
12143 DIP("popf%c\n", nameISize(sz));
12144 break;
12145
sewardjd20c8852005-01-20 20:04:07 +000012146//.. case 0x61: /* POPA */
12147//.. /* This is almost certainly wrong for sz==2. So ... */
12148//.. if (sz != 4) goto decode_failure;
12149//..
12150//.. /* t5 is the old %ESP value. */
12151//.. t5 = newTemp(Ity_I32);
12152//.. assign( t5, getIReg(4, R_ESP) );
12153//..
12154//.. /* Reload all the registers, except %esp. */
12155//.. putIReg(4,R_EAX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(28)) ));
12156//.. putIReg(4,R_ECX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(24)) ));
12157//.. putIReg(4,R_EDX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(20)) ));
12158//.. putIReg(4,R_EBX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(16)) ));
12159//.. /* ignore saved %ESP */
12160//.. putIReg(4,R_EBP, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32( 8)) ));
12161//.. putIReg(4,R_ESI, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32( 4)) ));
12162//.. putIReg(4,R_EDI, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32( 0)) ));
12163//..
12164//.. /* and move %ESP back up */
12165//.. putIReg( 4, R_ESP, binop(Iop_Add32, mkexpr(t5), mkU32(8*4)) );
12166//..
12167//.. DIP("pusha%c\n", nameISize(sz));
12168//.. break;
sewardj432f8b62005-05-10 02:50:05 +000012169
12170 case 0x8F: { /* POPQ m64 / POPW m16 */
sewardj1bd14e72005-05-11 16:24:00 +000012171 Int len;
12172 UChar rm;
sewardj432f8b62005-05-10 02:50:05 +000012173 /* There is no encoding for 32-bit pop in 64-bit mode.
12174 So sz==4 actually means sz==8. */
12175 if (haveF2orF3(pfx)) goto decode_failure;
12176 vassert(sz == 2 || sz == 4);
12177 if (sz == 4) sz = 8;
12178 if (sz != 8) goto decode_failure; // until we know a sz==2 test case exists
12179
sewardj1bd14e72005-05-11 16:24:00 +000012180 rm = getUChar(delta);
sewardj432f8b62005-05-10 02:50:05 +000012181
12182 /* make sure this instruction is correct POP */
12183 if (epartIsReg(rm) || gregLO3ofRM(rm) != 0)
12184 goto decode_failure;
12185 /* and has correct size */
12186 vassert(sz == 8);
12187
12188 t1 = newTemp(Ity_I64);
12189 t3 = newTemp(Ity_I64);
12190 assign( t1, getIReg64(R_RSP) );
12191 assign( t3, loadLE(Ity_I64, mkexpr(t1)) );
12192
12193 /* Increase RSP; must be done before the STORE. Intel manual
12194 says: If the RSP register is used as a base register for
12195 addressing a destination operand in memory, the POP
12196 instruction computes the effective address of the operand
12197 after it increments the RSP register. */
12198 putIReg64(R_RSP, binop(Iop_Add64, mkexpr(t1), mkU64(sz)) );
12199
12200 addr = disAMode ( &len, pfx, delta, dis_buf, 0 );
12201 storeLE( mkexpr(addr), mkexpr(t3) );
12202
12203 DIP("popl %s\n", dis_buf);
12204
12205 delta += len;
12206 break;
12207 }
12208
sewardjd20c8852005-01-20 20:04:07 +000012209//.. //-- case 0x1F: /* POP %DS */
12210//.. //-- dis_pop_segreg( cb, R_DS, sz ); break;
12211//.. //-- case 0x07: /* POP %ES */
12212//.. //-- dis_pop_segreg( cb, R_ES, sz ); break;
12213//.. //-- case 0x17: /* POP %SS */
12214//.. //-- dis_pop_segreg( cb, R_SS, sz ); break;
sewardj55dbb262005-01-28 16:36:51 +000012215
12216 /* ------------------------ PUSH ----------------------- */
12217
12218 case 0x50: /* PUSH eAX */
12219 case 0x51: /* PUSH eCX */
12220 case 0x52: /* PUSH eDX */
12221 case 0x53: /* PUSH eBX */
12222 case 0x55: /* PUSH eBP */
12223 case 0x56: /* PUSH eSI */
12224 case 0x57: /* PUSH eDI */
12225 case 0x54: /* PUSH eSP */
12226 /* This is the Right Way, in that the value to be pushed is
12227 established before %rsp is changed, so that pushq %rsp
12228 correctly pushes the old value. */
sewardj03b07cc2005-01-31 18:09:43 +000012229 if (haveF2orF3(pfx)) goto decode_failure;
sewardj55dbb262005-01-28 16:36:51 +000012230 vassert(sz == 2 || sz == 4 || sz == 8);
12231 if (sz == 4)
12232 sz = 8; /* there is no encoding for 32-bit push in 64-bit mode */
12233 ty = sz==2 ? Ity_I16 : Ity_I64;
12234 t1 = newTemp(ty);
12235 t2 = newTemp(Ity_I64);
sewardj5b470602005-02-27 13:10:48 +000012236 assign(t1, getIRegRexB(sz, pfx, opc-0x50));
sewardj55dbb262005-01-28 16:36:51 +000012237 assign(t2, binop(Iop_Sub64, getIReg64(R_RSP), mkU64(sz)));
12238 putIReg64(R_RSP, mkexpr(t2) );
12239 storeLE(mkexpr(t2),mkexpr(t1));
sewardj5b470602005-02-27 13:10:48 +000012240 DIP("push%c %s\n", nameISize(sz), nameIRegRexB(sz,pfx,opc-0x50));
sewardj55dbb262005-01-28 16:36:51 +000012241 break;
12242
sewardja6b93d12005-02-17 09:28:28 +000012243 case 0x68: /* PUSH Iv */
sewardj5b470602005-02-27 13:10:48 +000012244 if (haveF2orF3(pfx)) goto decode_failure;
sewardja6b93d12005-02-17 09:28:28 +000012245 /* Note, sz==4 is not possible in 64-bit mode. Hence ... */
12246 if (sz == 4) sz = 8;
12247 d64 = getSDisp(imin(4,sz),delta);
12248 delta += imin(4,sz);
12249 goto do_push_I;
sewardj909c06d2005-02-19 22:47:41 +000012250 case 0x6A: /* PUSH Ib, sign-extended to sz */
sewardj5b470602005-02-27 13:10:48 +000012251 if (haveF2orF3(pfx)) goto decode_failure;
sewardj909c06d2005-02-19 22:47:41 +000012252 /* Note, sz==4 is not possible in 64-bit mode. Hence ... */
12253 if (sz == 4) sz = 8;
12254 d64 = getSDisp8(delta); delta += 1;
12255 goto do_push_I;
sewardja6b93d12005-02-17 09:28:28 +000012256 do_push_I:
12257 ty = szToITy(sz);
sewardj909c06d2005-02-19 22:47:41 +000012258 t1 = newTemp(Ity_I64);
12259 t2 = newTemp(ty);
sewardja6b93d12005-02-17 09:28:28 +000012260 assign( t1, binop(Iop_Sub64,getIReg64(R_RSP),mkU64(sz)) );
12261 putIReg64(R_RSP, mkexpr(t1) );
12262 storeLE( mkexpr(t1), mkU(ty,d64) );
sewardj1027dc22005-02-26 01:55:02 +000012263 DIP("push%c $%lld\n", nameISize(sz), (Long)d64);
sewardja6b93d12005-02-17 09:28:28 +000012264 break;
12265
sewardj85520e42005-02-19 15:22:38 +000012266 case 0x9C: /* PUSHF */ {
12267 /* Note. There is no encoding for a 32-bit pushf in 64-bit
12268 mode. So sz==4 actually means sz==8. */
sewardj5b470602005-02-27 13:10:48 +000012269 if (haveF2orF3(pfx)) goto decode_failure;
sewardj85520e42005-02-19 15:22:38 +000012270 vassert(sz == 2 || sz == 4);
12271 if (sz == 4) sz = 8;
sewardj5b470602005-02-27 13:10:48 +000012272 if (sz != 8) goto decode_failure; // until we know a sz==2 test case exists
sewardj85520e42005-02-19 15:22:38 +000012273
12274 t1 = newTemp(Ity_I64);
12275 assign( t1, binop(Iop_Sub64,getIReg64(R_RSP),mkU64(sz)) );
12276 putIReg64(R_RSP, mkexpr(t1) );
12277
12278 t2 = newTemp(Ity_I64);
12279 assign( t2, mk_amd64g_calculate_rflags_all() );
12280
12281 /* Patch in the D flag. This can simply be a copy of bit 10 of
12282 baseBlock[OFFB_DFLAG]. */
12283 t3 = newTemp(Ity_I64);
12284 assign( t3, binop(Iop_Or64,
12285 mkexpr(t2),
12286 binop(Iop_And64,
12287 IRExpr_Get(OFFB_DFLAG,Ity_I64),
12288 mkU64(1<<10)))
12289 );
12290
12291 /* And patch in the ID flag. */
12292 t4 = newTemp(Ity_I64);
12293 assign( t4, binop(Iop_Or64,
12294 mkexpr(t3),
12295 binop(Iop_And64,
12296 binop(Iop_Shl64, IRExpr_Get(OFFB_IDFLAG,Ity_I64),
12297 mkU8(21)),
12298 mkU64(1<<21)))
12299 );
12300
12301 /* if sz==2, the stored value needs to be narrowed. */
12302 if (sz == 2)
12303 storeLE( mkexpr(t1), unop(Iop_32to16,
12304 unop(Iop_64to32,mkexpr(t4))) );
12305 else
12306 storeLE( mkexpr(t1), mkexpr(t4) );
12307
12308 DIP("pushf%c\n", nameISize(sz));
12309 break;
12310 }
12311
sewardjd20c8852005-01-20 20:04:07 +000012312//.. case 0x60: /* PUSHA */
12313//.. /* This is almost certainly wrong for sz==2. So ... */
12314//.. if (sz != 4) goto decode_failure;
12315//..
12316//.. /* This is the Right Way, in that the value to be pushed is
12317//.. established before %esp is changed, so that pusha
12318//.. correctly pushes the old %esp value. New value of %esp is
12319//.. pushed at start. */
12320//.. /* t0 is the %ESP value we're going to push. */
12321//.. t0 = newTemp(Ity_I32);
12322//.. assign( t0, getIReg(4, R_ESP) );
12323//..
12324//.. /* t5 will be the new %ESP value. */
12325//.. t5 = newTemp(Ity_I32);
12326//.. assign( t5, binop(Iop_Sub32, mkexpr(t0), mkU32(8*4)) );
12327//..
12328//.. /* Update guest state before prodding memory. */
12329//.. putIReg(4, R_ESP, mkexpr(t5));
12330//..
12331//.. /* Dump all the registers. */
12332//.. storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(28)), getIReg(4,R_EAX) );
12333//.. storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(24)), getIReg(4,R_ECX) );
12334//.. storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(20)), getIReg(4,R_EDX) );
12335//.. storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(16)), getIReg(4,R_EBX) );
12336//.. storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(12)), mkexpr(t0) /*esp*/);
12337//.. storeLE( binop(Iop_Add32,mkexpr(t5),mkU32( 8)), getIReg(4,R_EBP) );
12338//.. storeLE( binop(Iop_Add32,mkexpr(t5),mkU32( 4)), getIReg(4,R_ESI) );
12339//.. storeLE( binop(Iop_Add32,mkexpr(t5),mkU32( 0)), getIReg(4,R_EDI) );
12340//..
12341//.. DIP("pusha%c\n", nameISize(sz));
12342//.. break;
12343//..
12344//..
12345//.. //-- case 0x0E: /* PUSH %CS */
12346//.. //-- dis_push_segreg( cb, R_CS, sz ); break;
12347//.. //-- case 0x1E: /* PUSH %DS */
12348//.. //-- dis_push_segreg( cb, R_DS, sz ); break;
12349//.. //-- case 0x06: /* PUSH %ES */
12350//.. //-- dis_push_segreg( cb, R_ES, sz ); break;
12351//.. //-- case 0x16: /* PUSH %SS */
12352//.. //-- dis_push_segreg( cb, R_SS, sz ); break;
12353//..
12354//.. /* ------------------------ SCAS et al ----------------- */
12355//..
12356//.. case 0xA4: /* MOVS, no REP prefix */
12357//.. case 0xA5:
12358//.. dis_string_op( dis_MOVS, ( opc == 0xA4 ? 1 : sz ), "movs", sorb );
12359//.. break;
12360//..
12361//.. case 0xA6: /* CMPSb, no REP prefix */
12362//.. //-- case 0xA7:
12363//.. dis_string_op( dis_CMPS, ( opc == 0xA6 ? 1 : sz ), "cmps", sorb );
12364//.. break;
12365//.. //--
sewardjd20c8852005-01-20 20:04:07 +000012366//.. //--
12367//.. //-- case 0xAC: /* LODS, no REP prefix */
12368//.. //-- case 0xAD:
12369//.. //-- dis_string_op( cb, dis_LODS, ( opc == 0xAC ? 1 : sz ), "lods", sorb );
12370//.. //-- break;
12371//..
12372//.. case 0xAE: /* SCAS, no REP prefix */
12373//.. case 0xAF:
12374//.. dis_string_op( dis_SCAS, ( opc == 0xAE ? 1 : sz ), "scas", sorb );
12375//.. break;
sewardjd0a12df2005-02-10 02:07:43 +000012376
12377
12378 case 0xFC: /* CLD */
sewardj5b470602005-02-27 13:10:48 +000012379 if (haveF2orF3(pfx)) goto decode_failure;
sewardjd0a12df2005-02-10 02:07:43 +000012380 stmt( IRStmt_Put( OFFB_DFLAG, mkU64(1)) );
12381 DIP("cld\n");
12382 break;
12383
sewardj909c06d2005-02-19 22:47:41 +000012384 case 0xFD: /* STD */
sewardj5b470602005-02-27 13:10:48 +000012385 if (haveF2orF3(pfx)) goto decode_failure;
sewardj909c06d2005-02-19 22:47:41 +000012386 stmt( IRStmt_Put( OFFB_DFLAG, mkU64(-1ULL)) );
12387 DIP("std\n");
12388 break;
12389
sewardjd20c8852005-01-20 20:04:07 +000012390//.. //-- case 0xF8: /* CLC */
12391//.. //-- uInstr0(cb, CALLM_S, 0);
12392//.. //-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_CLC));
12393//.. //-- uFlagsRWU(cb, FlagsEmpty, FlagC, FlagsOSZAP);
12394//.. //-- uInstr0(cb, CALLM_E, 0);
12395//.. //-- DIP("clc\n");
12396//.. //-- break;
12397//.. //--
12398//.. //-- case 0xF9: /* STC */
12399//.. //-- uInstr0(cb, CALLM_S, 0);
12400//.. //-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_STC));
12401//.. //-- uFlagsRWU(cb, FlagsEmpty, FlagC, FlagsOSZAP);
12402//.. //-- uInstr0(cb, CALLM_E, 0);
12403//.. //-- DIP("stc\n");
12404//.. //-- break;
12405//.. //--
12406//.. //-- case 0xF5: /* CMC */
12407//.. //-- uInstr0(cb, CALLM_S, 0);
12408//.. //-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_CMC));
12409//.. //-- uFlagsRWU(cb, FlagC, FlagC, FlagsOSZAP);
12410//.. //-- uInstr0(cb, CALLM_E, 0);
12411//.. //-- DIP("cmc\n");
12412//.. //-- break;
12413//..
12414//.. /* REPNE prefix insn */
12415//.. case 0xF2: {
12416//.. Addr32 eip_orig = guest_eip_bbstart + delta - 1;
12417//.. vassert(sorb == 0);
sewardj8c332e22005-01-28 01:36:56 +000012418//.. abyte = getUChar(delta); delta++;
sewardjd20c8852005-01-20 20:04:07 +000012419//..
sewardj8c332e22005-01-28 01:36:56 +000012420//.. if (abyte == 0x66) { sz = 2; abyte = getUChar(delta); delta++; }
sewardjd20c8852005-01-20 20:04:07 +000012421//.. whatNext = Dis_StopHere;
12422//..
12423//.. switch (abyte) {
12424//.. /* According to the Intel manual, "repne movs" should never occur, but
12425//.. * in practice it has happened, so allow for it here... */
12426//.. case 0xA4: sz = 1; /* REPNE MOVS<sz> */
12427//.. goto decode_failure;
12428//.. //-- case 0xA5:
12429//.. // dis_REP_op ( CondNZ, dis_MOVS, sz, eip_orig,
12430//.. // guest_eip_bbstart+delta, "repne movs" );
12431//.. // break;
12432//.. //--
12433//.. //-- case 0xA6: sz = 1; /* REPNE CMPS<sz> */
12434//.. //-- case 0xA7:
12435//.. //-- dis_REP_op ( cb, CondNZ, dis_CMPS, sz, eip_orig, eip, "repne cmps" );
12436//.. //-- break;
12437//.. //--
12438//.. case 0xAE: sz = 1; /* REPNE SCAS<sz> */
12439//.. case 0xAF:
12440//.. dis_REP_op ( X86CondNZ, dis_SCAS, sz, eip_orig,
12441//.. guest_eip_bbstart+delta, "repne scas" );
12442//.. break;
12443//..
12444//.. default:
12445//.. goto decode_failure;
12446//.. }
12447//.. break;
12448//.. }
sewardjd0a12df2005-02-10 02:07:43 +000012449
sewardj909c06d2005-02-19 22:47:41 +000012450 /* ------ AE: SCAS variants ------ */
12451 case 0xAE:
12452 case 0xAF:
12453 /* F2 AE/AF: repne scasb/repne scas{w,l,q} */
sewardj85520e42005-02-19 15:22:38 +000012454 if (haveF2(pfx) && !haveF3(pfx)) {
12455 if (opc == 0xAE)
12456 sz = 1;
12457 dis_REP_op ( AMD64CondNZ, dis_SCAS, sz,
sewardj9e6491a2005-07-02 19:24:10 +000012458 guest_RIP_curr_instr,
12459 guest_RIP_bbstart+delta, "repne scas", pfx );
12460 dres.whatNext = Dis_StopHere;
sewardj85520e42005-02-19 15:22:38 +000012461 break;
12462 }
sewardj909c06d2005-02-19 22:47:41 +000012463 /* AE/AF: scasb/scas{w,l,q} */
12464 if (!haveF2(pfx) && !haveF3(pfx)) {
12465 if (opc == 0xAE)
12466 sz = 1;
12467 dis_string_op( dis_SCAS, sz, "scas", pfx );
12468 break;
12469 }
sewardj85520e42005-02-19 15:22:38 +000012470 goto decode_failure;
sewardjd0a12df2005-02-10 02:07:43 +000012471
sewardj909c06d2005-02-19 22:47:41 +000012472 /* ------ A6, A7: CMPS variants ------ */
12473 case 0xA6:
12474 case 0xA7:
12475 /* F3 A6/A7: repe cmps/rep cmps{w,l,q} */
sewardjd0a12df2005-02-10 02:07:43 +000012476 if (haveF3(pfx) && !haveF2(pfx)) {
12477 if (opc == 0xA6)
12478 sz = 1;
12479 dis_REP_op ( AMD64CondZ, dis_CMPS, sz,
sewardj9e6491a2005-07-02 19:24:10 +000012480 guest_RIP_curr_instr,
12481 guest_RIP_bbstart+delta, "repe cmps", pfx );
12482 dres.whatNext = Dis_StopHere;
sewardja6b93d12005-02-17 09:28:28 +000012483 break;
12484 }
12485 goto decode_failure;
12486
sewardj909c06d2005-02-19 22:47:41 +000012487 /* ------ AA, AB: STOS variants ------ */
12488 case 0xAA:
12489 case 0xAB:
12490 /* F3 AA/AB: rep stosb/rep stos{w,l,q} */
sewardja6b93d12005-02-17 09:28:28 +000012491 if (haveF3(pfx) && !haveF2(pfx)) {
sewardj909c06d2005-02-19 22:47:41 +000012492 if (opc == 0xAA)
12493 sz = 1;
sewardja6b93d12005-02-17 09:28:28 +000012494 dis_REP_op ( AMD64CondAlways, dis_STOS, sz,
sewardj9e6491a2005-07-02 19:24:10 +000012495 guest_RIP_curr_instr,
12496 guest_RIP_bbstart+delta, "rep stos", pfx );
12497 dres.whatNext = Dis_StopHere;
sewardj909c06d2005-02-19 22:47:41 +000012498 break;
12499 }
12500 /* AA/AB: stosb/stos{w,l,q} */
12501 if (!haveF3(pfx) && !haveF2(pfx)) {
12502 if (opc == 0xAA)
12503 sz = 1;
12504 dis_string_op( dis_STOS, sz, "stos", pfx );
sewardjd0a12df2005-02-10 02:07:43 +000012505 break;
12506 }
12507 goto decode_failure;
12508
sewardj909c06d2005-02-19 22:47:41 +000012509 /* ------ A4, A5: MOVS variants ------ */
12510 case 0xA4:
12511 case 0xA5:
12512 /* F3 A4: rep movsb */
12513 if (haveF3(pfx) && !haveF2(pfx)) {
12514 if (opc == 0xA4)
12515 sz = 1;
12516 dis_REP_op ( AMD64CondAlways, dis_MOVS, sz,
sewardj9e6491a2005-07-02 19:24:10 +000012517 guest_RIP_curr_instr,
12518 guest_RIP_bbstart+delta, "rep movs", pfx );
12519 dres.whatNext = Dis_StopHere;
sewardj909c06d2005-02-19 22:47:41 +000012520 break;
12521 }
12522 /* A4: movsb */
12523 if (!haveF3(pfx) && !haveF2(pfx)) {
12524 if (opc == 0xA4)
12525 sz = 1;
12526 dis_string_op( dis_MOVS, sz, "movs", pfx );
12527 break;
12528 }
12529 goto decode_failure;
12530
sewardj7de0d3c2005-02-13 02:26:41 +000012531
12532 /* ------------------------ XCHG ----------------------- */
12533
sewardj1bf95982005-05-18 12:04:04 +000012534 case 0x86: /* XCHG Gb,Eb */
12535 sz = 1;
12536 /* Fall through ... */
sewardj7de0d3c2005-02-13 02:26:41 +000012537 case 0x87: /* XCHG Gv,Ev */
sewardj5b470602005-02-27 13:10:48 +000012538 if (haveF2orF3(pfx)) goto decode_failure;
sewardj7de0d3c2005-02-13 02:26:41 +000012539 modrm = getUChar(delta);
12540 ty = szToITy(sz);
12541 t1 = newTemp(ty); t2 = newTemp(ty);
12542 if (epartIsReg(modrm)) {
sewardj5b470602005-02-27 13:10:48 +000012543 assign(t1, getIRegE(sz, pfx, modrm));
12544 assign(t2, getIRegG(sz, pfx, modrm));
12545 putIRegG(sz, pfx, modrm, mkexpr(t1));
12546 putIRegE(sz, pfx, modrm, mkexpr(t2));
sewardj7de0d3c2005-02-13 02:26:41 +000012547 delta++;
12548 DIP("xchg%c %s, %s\n",
sewardj5b470602005-02-27 13:10:48 +000012549 nameISize(sz), nameIRegG(sz, pfx, modrm),
12550 nameIRegE(sz, pfx, modrm));
sewardj7de0d3c2005-02-13 02:26:41 +000012551 } else {
sewardj7de0d3c2005-02-13 02:26:41 +000012552 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
sewardj5b470602005-02-27 13:10:48 +000012553 assign( t1, loadLE(ty, mkexpr(addr)) );
12554 assign( t2, getIRegG(sz, pfx, modrm) );
sewardj7de0d3c2005-02-13 02:26:41 +000012555 storeLE( mkexpr(addr), mkexpr(t2) );
sewardj5b470602005-02-27 13:10:48 +000012556 putIRegG( sz, pfx, modrm, mkexpr(t1) );
sewardj7de0d3c2005-02-13 02:26:41 +000012557 delta += alen;
12558 DIP("xchg%c %s, %s\n", nameISize(sz),
sewardj5b470602005-02-27 13:10:48 +000012559 nameIRegG(sz, pfx, modrm), dis_buf);
sewardj7de0d3c2005-02-13 02:26:41 +000012560 }
12561 break;
sewardj118b23e2005-01-29 02:14:44 +000012562
12563 case 0x90: /* XCHG eAX,eAX */
sewardjc8b26352005-07-20 09:23:13 +000012564 /* detect and handle F3 90 (rep nop) specially */
12565 if (!have66(pfx) && !haveF2(pfx) && haveF3(pfx)) {
12566 DIP("rep nop (P4 pause)\n");
12567 /* "observe" the hint. The Vex client needs to be careful not
12568 to cause very long delays as a result, though. */
12569 jmp_lit(Ijk_Yield, guest_RIP_bbstart+delta);
12570 dres.whatNext = Dis_StopHere;
12571 break;
12572 }
sewardj2d4fcd52005-05-18 11:47:47 +000012573 /* detect and handle NOPs specially */
12574 if (/* F2/F3 probably change meaning completely */
12575 !haveF2orF3(pfx)
12576 /* If REX.B is 1, we're not exchanging rAX with itself */
12577 && getRexB(pfx)==0 ) {
12578 DIP("nop\n");
12579 break;
12580 }
12581 /* else fall through to normal case. */
sewardja6b93d12005-02-17 09:28:28 +000012582 case 0x91: /* XCHG rAX,rCX */
12583 case 0x92: /* XCHG rAX,rDX */
12584 case 0x93: /* XCHG rAX,rBX */
12585 case 0x94: /* XCHG rAX,rSP */
12586 case 0x95: /* XCHG rAX,rBP */
12587 case 0x96: /* XCHG rAX,rSI */
12588 case 0x97: /* XCHG rAX,rDI */
sewardj2d4fcd52005-05-18 11:47:47 +000012589
12590 /* guard against mutancy */
sewardja6b93d12005-02-17 09:28:28 +000012591 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2d4fcd52005-05-18 11:47:47 +000012592
12593 /* sz == 2 could legitimately happen, but we don't handle it yet */
12594 if (sz == 2) goto decode_failure; /* awaiting test case */
12595
sewardja6b93d12005-02-17 09:28:28 +000012596 codegen_xchg_rAX_Reg ( pfx, sz, opc - 0x90 );
12597 break;
12598
sewardjd20c8852005-01-20 20:04:07 +000012599//.. //-- /* ------------------------ XLAT ----------------------- */
12600//.. //--
12601//.. //-- case 0xD7: /* XLAT */
12602//.. //-- t1 = newTemp(cb); t2 = newTemp(cb);
12603//.. //-- uInstr2(cb, GET, sz, ArchReg, R_EBX, TempReg, t1); /* get eBX */
12604//.. //-- handleSegOverride( cb, sorb, t1 ); /* make t1 DS:eBX */
12605//.. //-- uInstr2(cb, GET, 1, ArchReg, R_AL, TempReg, t2); /* get AL */
12606//.. //-- /* Widen %AL to 32 bits, so it's all defined when we add it. */
12607//.. //-- uInstr1(cb, WIDEN, 4, TempReg, t2);
12608//.. //-- uWiden(cb, 1, False);
12609//.. //-- uInstr2(cb, ADD, sz, TempReg, t2, TempReg, t1); /* add AL to eBX */
12610//.. //-- uInstr2(cb, LOAD, 1, TempReg, t1, TempReg, t2); /* get byte at t1 into t2 */
12611//.. //-- uInstr2(cb, PUT, 1, TempReg, t2, ArchReg, R_AL); /* put byte into AL */
12612//.. //--
12613//.. //-- DIP("xlat%c [ebx]\n", nameISize(sz));
12614//.. //-- break;
12615//.. //--
12616//.. //-- /* ------------------------ IN / OUT ----------------------- */
12617//.. //--
12618//.. //-- case 0xE4: /* IN ib, %al */
12619//.. //-- case 0xE5: /* IN ib, %{e}ax */
12620//.. //-- case 0xEC: /* IN (%dx),%al */
12621//.. //-- case 0xED: /* IN (%dx),%{e}ax */
12622//.. //-- t1 = newTemp(cb);
12623//.. //-- t2 = newTemp(cb);
12624//.. //-- t3 = newTemp(cb);
12625//.. //--
12626//.. //-- uInstr0(cb, CALLM_S, 0);
12627//.. //-- /* operand size? */
12628//.. //-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t1);
12629//.. //-- uLiteral(cb, ( opc == 0xE4 || opc == 0xEC ) ? 1 : sz);
12630//.. //-- uInstr1(cb, PUSH, 4, TempReg, t1);
12631//.. //-- /* port number ? */
12632//.. //-- if ( opc == 0xE4 || opc == 0xE5 ) {
12633//.. //-- abyte = getUChar(eip); eip++;
12634//.. //-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
12635//.. //-- uLiteral(cb, abyte);
12636//.. //-- }
12637//.. //-- else
12638//.. //-- uInstr2(cb, GET, 4, ArchReg, R_EDX, TempReg, t2);
12639//.. //--
12640//.. //-- uInstr1(cb, PUSH, 4, TempReg, t2);
12641//.. //-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_IN));
12642//.. //-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
12643//.. //-- uInstr1(cb, POP, 4, TempReg, t2);
12644//.. //-- uInstr1(cb, CLEAR, 0, Lit16, 4);
12645//.. //-- uInstr0(cb, CALLM_E, 0);
12646//.. //-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_EAX);
12647//.. //-- if ( opc == 0xE4 || opc == 0xE5 ) {
12648//.. //-- DIP("in 0x%x, %%eax/%%ax/%%al\n", getUChar(eip-1) );
12649//.. //-- } else {
12650//.. //-- DIP("in (%%dx), %%eax/%%ax/%%al\n");
12651//.. //-- }
12652//.. //-- break;
12653//.. //-- case 0xE6: /* OUT %al,ib */
12654//.. //-- case 0xE7: /* OUT %{e}ax,ib */
12655//.. //-- case 0xEE: /* OUT %al,(%dx) */
12656//.. //-- case 0xEF: /* OUT %{e}ax,(%dx) */
12657//.. //-- t1 = newTemp(cb);
12658//.. //-- t2 = newTemp(cb);
12659//.. //-- t3 = newTemp(cb);
12660//.. //--
12661//.. //-- uInstr0(cb, CALLM_S, 0);
12662//.. //-- /* operand size? */
12663//.. //-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t1);
12664//.. //-- uLiteral(cb, ( opc == 0xE6 || opc == 0xEE ) ? 1 : sz);
12665//.. //-- uInstr1(cb, PUSH, 4, TempReg, t1);
12666//.. //-- /* port number ? */
12667//.. //-- if ( opc == 0xE6 || opc == 0xE7 ) {
12668//.. //-- abyte = getUChar(eip); eip++;
12669//.. //-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
12670//.. //-- uLiteral(cb, abyte);
12671//.. //-- }
12672//.. //-- else
12673//.. //-- uInstr2(cb, GET, 4, ArchReg, R_EDX, TempReg, t2);
12674//.. //-- uInstr1(cb, PUSH, 4, TempReg, t2);
12675//.. //-- uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, t3);
12676//.. //-- uInstr1(cb, PUSH, 4, TempReg, t3);
12677//.. //-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_OUT));
12678//.. //-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
12679//.. //-- uInstr1(cb, CLEAR, 0, Lit16, 12);
12680//.. //-- uInstr0(cb, CALLM_E, 0);
12681//.. //-- if ( opc == 0xE4 || opc == 0xE5 ) {
12682//.. //-- DIP("out %%eax/%%ax/%%al, 0x%x\n", getUChar(eip-1) );
12683//.. //-- } else {
12684//.. //-- DIP("out %%eax/%%ax/%%al, (%%dx)\n");
12685//.. //-- }
12686//.. //-- break;
sewardj3ca55a12005-01-27 16:06:23 +000012687
12688 /* ------------------------ (Grp1 extensions) ---------- */
12689
12690 case 0x80: /* Grp1 Ib,Eb */
sewardj5b470602005-02-27 13:10:48 +000012691 if (haveF2orF3(pfx)) goto decode_failure;
sewardj8c332e22005-01-28 01:36:56 +000012692 modrm = getUChar(delta);
sewardj3ca55a12005-01-27 16:06:23 +000012693 am_sz = lengthAMode(pfx,delta);
12694 sz = 1;
12695 d_sz = 1;
12696 d64 = getSDisp8(delta + am_sz);
12697 delta = dis_Grp1 ( pfx, delta, modrm, am_sz, d_sz, sz, d64 );
12698 break;
12699
12700 case 0x81: /* Grp1 Iv,Ev */
12701 if (haveF2orF3(pfx)) goto decode_failure;
sewardj8c332e22005-01-28 01:36:56 +000012702 modrm = getUChar(delta);
sewardj3ca55a12005-01-27 16:06:23 +000012703 am_sz = lengthAMode(pfx,delta);
12704 d_sz = imin(sz,4);
12705 d64 = getSDisp(d_sz, delta + am_sz);
12706 delta = dis_Grp1 ( pfx, delta, modrm, am_sz, d_sz, sz, d64 );
12707 break;
12708
12709 case 0x83: /* Grp1 Ib,Ev */
12710 if (haveF2orF3(pfx)) goto decode_failure;
sewardj8c332e22005-01-28 01:36:56 +000012711 modrm = getUChar(delta);
sewardj3ca55a12005-01-27 16:06:23 +000012712 am_sz = lengthAMode(pfx,delta);
12713 d_sz = 1;
12714 d64 = getSDisp8(delta + am_sz);
12715 delta = dis_Grp1 ( pfx, delta, modrm, am_sz, d_sz, sz, d64 );
12716 break;
12717
sewardj118b23e2005-01-29 02:14:44 +000012718 /* ------------------------ (Grp2 extensions) ---------- */
sewardj03b07cc2005-01-31 18:09:43 +000012719
sewardj118b23e2005-01-29 02:14:44 +000012720 case 0xC0: /* Grp2 Ib,Eb */
sewardj5b470602005-02-27 13:10:48 +000012721 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000012722 modrm = getUChar(delta);
12723 am_sz = lengthAMode(pfx,delta);
12724 d_sz = 1;
12725 d64 = getUChar(delta + am_sz);
12726 sz = 1;
12727 delta = dis_Grp2 ( pfx, delta, modrm, am_sz, d_sz, sz,
12728 mkU8(d64 & 0xFF), NULL );
12729 break;
sewardj03b07cc2005-01-31 18:09:43 +000012730
sewardj118b23e2005-01-29 02:14:44 +000012731 case 0xC1: /* Grp2 Ib,Ev */
sewardj5b470602005-02-27 13:10:48 +000012732 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000012733 modrm = getUChar(delta);
12734 am_sz = lengthAMode(pfx,delta);
12735 d_sz = 1;
12736 d64 = getUChar(delta + am_sz);
12737 delta = dis_Grp2 ( pfx, delta, modrm, am_sz, d_sz, sz,
12738 mkU8(d64 & 0xFF), NULL );
12739 break;
12740
sewardj03b07cc2005-01-31 18:09:43 +000012741 case 0xD0: /* Grp2 1,Eb */
sewardj5b470602005-02-27 13:10:48 +000012742 if (haveF2orF3(pfx)) goto decode_failure;
sewardj03b07cc2005-01-31 18:09:43 +000012743 modrm = getUChar(delta);
12744 am_sz = lengthAMode(pfx,delta);
12745 d_sz = 0;
12746 d64 = 1;
12747 sz = 1;
12748 delta = dis_Grp2 ( pfx, delta, modrm, am_sz, d_sz, sz,
12749 mkU8(d64), NULL );
12750 break;
sewardj118b23e2005-01-29 02:14:44 +000012751
12752 case 0xD1: /* Grp2 1,Ev */
sewardj5b470602005-02-27 13:10:48 +000012753 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000012754 modrm = getUChar(delta);
12755 am_sz = lengthAMode(pfx,delta);
12756 d_sz = 0;
12757 d64 = 1;
12758 delta = dis_Grp2 ( pfx, delta, modrm, am_sz, d_sz, sz,
12759 mkU8(d64), NULL );
12760 break;
12761
sewardj85520e42005-02-19 15:22:38 +000012762 case 0xD2: /* Grp2 CL,Eb */
sewardj5b470602005-02-27 13:10:48 +000012763 if (haveF2orF3(pfx)) goto decode_failure;
sewardj85520e42005-02-19 15:22:38 +000012764 modrm = getUChar(delta);
12765 am_sz = lengthAMode(pfx,delta);
12766 d_sz = 0;
12767 sz = 1;
12768 delta = dis_Grp2 ( pfx, delta, modrm, am_sz, d_sz, sz,
sewardj5b470602005-02-27 13:10:48 +000012769 getIRegCL(), "%cl" );
sewardj85520e42005-02-19 15:22:38 +000012770 break;
sewardj118b23e2005-01-29 02:14:44 +000012771
12772 case 0xD3: /* Grp2 CL,Ev */
sewardj5b470602005-02-27 13:10:48 +000012773 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000012774 modrm = getUChar(delta);
12775 am_sz = lengthAMode(pfx,delta);
12776 d_sz = 0;
12777 delta = dis_Grp2 ( pfx, delta, modrm, am_sz, d_sz, sz,
sewardj5b470602005-02-27 13:10:48 +000012778 getIRegCL(), "%cl" );
sewardj118b23e2005-01-29 02:14:44 +000012779 break;
sewardj32b2bbe2005-01-28 00:50:10 +000012780
12781 /* ------------------------ (Grp3 extensions) ---------- */
12782
sewardj118b23e2005-01-29 02:14:44 +000012783 case 0xF6: /* Grp3 Eb */
sewardj5b470602005-02-27 13:10:48 +000012784 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000012785 delta = dis_Grp3 ( pfx, 1, delta );
12786 break;
sewardj32b2bbe2005-01-28 00:50:10 +000012787 case 0xF7: /* Grp3 Ev */
sewardj5b470602005-02-27 13:10:48 +000012788 if (haveF2orF3(pfx)) goto decode_failure;
sewardj32b2bbe2005-01-28 00:50:10 +000012789 delta = dis_Grp3 ( pfx, sz, delta );
12790 break;
12791
sewardj03b07cc2005-01-31 18:09:43 +000012792 /* ------------------------ (Grp4 extensions) ---------- */
12793
12794 case 0xFE: /* Grp4 Eb */
sewardj5b470602005-02-27 13:10:48 +000012795 if (haveF2orF3(pfx)) goto decode_failure;
sewardj03b07cc2005-01-31 18:09:43 +000012796 delta = dis_Grp4 ( pfx, delta );
12797 break;
sewardj354e5c62005-01-27 20:12:52 +000012798
12799 /* ------------------------ (Grp5 extensions) ---------- */
12800
12801 case 0xFF: /* Grp5 Ev */
sewardj5b470602005-02-27 13:10:48 +000012802 if (haveF2orF3(pfx)) goto decode_failure;
sewardj9e6491a2005-07-02 19:24:10 +000012803 delta = dis_Grp5 ( pfx, sz, delta, &dres );
sewardj354e5c62005-01-27 20:12:52 +000012804 break;
sewardj3ca55a12005-01-27 16:06:23 +000012805
12806 /* ------------------------ Escapes to 2-byte opcodes -- */
12807
12808 case 0x0F: {
sewardj8c332e22005-01-28 01:36:56 +000012809 opc = getUChar(delta); delta++;
sewardj3ca55a12005-01-27 16:06:23 +000012810 switch (opc) {
12811
sewardj1d511802005-03-27 17:59:45 +000012812 /* =-=-=-=-=-=-=-=-=- Grp8 =-=-=-=-=-=-=-=-=-=-=-= */
12813
12814 case 0xBA: { /* Grp8 Ib,Ev */
12815 Bool decode_OK = False;
12816 if (haveF2orF3(pfx)) goto decode_failure;
12817 modrm = getUChar(delta);
12818 am_sz = lengthAMode(pfx,delta);
12819 d64 = getSDisp8(delta + am_sz);
12820 delta = dis_Grp8_Imm ( pfx, delta, modrm, am_sz, sz, d64,
12821 &decode_OK );
12822 if (!decode_OK)
12823 goto decode_failure;
12824 break;
12825 }
12826
sewardjf53b7352005-04-06 20:01:56 +000012827 /* =-=-=-=-=-=-=-=-=- BSF/BSR -=-=-=-=-=-=-=-=-=-= */
12828
12829 case 0xBC: /* BSF Gv,Ev */
12830 if (haveF2orF3(pfx)) goto decode_failure;
12831 delta = dis_bs_E_G ( pfx, sz, delta, True );
12832 break;
sewardj537cab02005-04-07 02:03:52 +000012833 case 0xBD: /* BSR Gv,Ev */
12834 if (haveF2orF3(pfx)) goto decode_failure;
12835 delta = dis_bs_E_G ( pfx, sz, delta, False );
12836 break;
sewardj82c9f2f2005-03-02 16:05:13 +000012837
12838 /* =-=-=-=-=-=-=-=-=- BSWAP -=-=-=-=-=-=-=-=-=-=-= */
12839
12840 case 0xC8: /* BSWAP %eax */
12841 case 0xC9:
12842 case 0xCA:
12843 case 0xCB:
12844 case 0xCC:
12845 case 0xCD:
12846 case 0xCE:
12847 case 0xCF: /* BSWAP %edi */
12848 if (haveF2orF3(pfx)) goto decode_failure;
12849 /* According to the AMD64 docs, this insn can have size 4 or
12850 8. */
12851 if (sz == 4) {
12852 t1 = newTemp(Ity_I32);
12853 t2 = newTemp(Ity_I32);
12854 assign( t1, getIRegRexB(4, pfx, opc-0xC8) );
12855 assign( t2,
12856 binop(Iop_Or32,
12857 binop(Iop_Shl32, mkexpr(t1), mkU8(24)),
12858 binop(Iop_Or32,
12859 binop(Iop_And32, binop(Iop_Shl32, mkexpr(t1), mkU8(8)),
12860 mkU32(0x00FF0000)),
12861 binop(Iop_Or32,
12862 binop(Iop_And32, binop(Iop_Shr32, mkexpr(t1), mkU8(8)),
12863 mkU32(0x0000FF00)),
12864 binop(Iop_And32, binop(Iop_Shr32, mkexpr(t1), mkU8(24)),
12865 mkU32(0x000000FF) )
12866 )))
12867 );
12868 putIRegRexB(4, pfx, opc-0xC8, mkexpr(t2));
12869 DIP("bswapl %s\n", nameIRegRexB(4, pfx, opc-0xC8));
12870 break;
sewardj98e9f342005-07-23 12:07:37 +000012871 }
12872 else if (sz == 8) {
12873 t1 = newTemp(Ity_I64);
12874 t2 = newTemp(Ity_I64);
12875 assign( t1, getIRegRexB(8, pfx, opc-0xC8) );
12876
12877# define LANE(_nn) \
12878 binop( Iop_Shl64, \
12879 binop( Iop_And64, \
12880 binop(Iop_Shr64, mkexpr(t1), \
12881 mkU8(8 * (7 - (_nn)))), \
12882 mkU64(0xFF)), \
12883 mkU8(8 * (_nn)))
12884
12885 assign(
12886 t2,
12887 binop(Iop_Or64,
12888 binop(Iop_Or64,
12889 binop(Iop_Or64,LANE(0),LANE(1)),
12890 binop(Iop_Or64,LANE(2),LANE(3))
12891 ),
12892 binop(Iop_Or64,
12893 binop(Iop_Or64,LANE(4),LANE(5)),
12894 binop(Iop_Or64,LANE(6),LANE(7))
12895 )
12896 )
12897 );
12898
12899# undef LANE
12900
12901 putIRegRexB(8, pfx, opc-0xC8, mkexpr(t2));
12902 DIP("bswapq %s\n", nameIRegRexB(8, pfx, opc-0xC8));
12903 break;
sewardj82c9f2f2005-03-02 16:05:13 +000012904 } else {
12905 goto decode_failure;
12906 }
12907
sewardj9ed16802005-08-24 10:46:19 +000012908 /* =-=-=-=-=-=-=-=-=- BT/BTS/BTR/BTC =-=-=-=-=-=-= */
12909
sewardja7690fb2005-10-05 17:19:11 +000012910 /* All of these are possible at sizes 2, 4 and 8, but until a
12911 size 2 test case shows up, only handle sizes 4 and 8. */
sewardj9ed16802005-08-24 10:46:19 +000012912
12913 case 0xA3: /* BT Gv,Ev */
12914 if (haveF2orF3(pfx)) goto decode_failure;
sewardja7690fb2005-10-05 17:19:11 +000012915 if (sz != 8 && sz != 4) goto decode_failure;
sewardj9ed16802005-08-24 10:46:19 +000012916 delta = dis_bt_G_E ( pfx, sz, delta, BtOpNone );
12917 break;
12918 case 0xB3: /* BTR Gv,Ev */
12919 if (haveF2orF3(pfx)) goto decode_failure;
sewardja7690fb2005-10-05 17:19:11 +000012920 if (sz != 8 && sz != 4) goto decode_failure;
sewardj9ed16802005-08-24 10:46:19 +000012921 delta = dis_bt_G_E ( pfx, sz, delta, BtOpReset );
12922 break;
12923 case 0xAB: /* BTS Gv,Ev */
12924 if (haveF2orF3(pfx)) goto decode_failure;
sewardja7690fb2005-10-05 17:19:11 +000012925 if (sz != 8 && sz != 4) goto decode_failure;
sewardj9ed16802005-08-24 10:46:19 +000012926 delta = dis_bt_G_E ( pfx, sz, delta, BtOpSet );
12927 break;
12928 case 0xBB: /* BTC Gv,Ev */
12929 if (haveF2orF3(pfx)) goto decode_failure;
sewardja7690fb2005-10-05 17:19:11 +000012930 if (sz != 8 && sz != 4) goto decode_failure;
sewardj9ed16802005-08-24 10:46:19 +000012931 delta = dis_bt_G_E ( pfx, sz, delta, BtOpComp );
12932 break;
sewardj3ca55a12005-01-27 16:06:23 +000012933
12934 /* =-=-=-=-=-=-=-=-=- CMOV =-=-=-=-=-=-=-=-=-=-=-= */
12935
12936 case 0x40:
12937 case 0x41:
12938 case 0x42: /* CMOVBb/CMOVNAEb (cmov below) */
12939 case 0x43: /* CMOVNBb/CMOVAEb (cmov not below) */
12940 case 0x44: /* CMOVZb/CMOVEb (cmov zero) */
12941 case 0x45: /* CMOVNZb/CMOVNEb (cmov not zero) */
12942 case 0x46: /* CMOVBEb/CMOVNAb (cmov below or equal) */
12943 case 0x47: /* CMOVNBEb/CMOVAb (cmov not below or equal) */
12944 case 0x48: /* CMOVSb (cmov negative) */
12945 case 0x49: /* CMOVSb (cmov not negative) */
12946 case 0x4A: /* CMOVP (cmov parity even) */
12947 case 0x4B: /* CMOVNP (cmov parity odd) */
12948 case 0x4C: /* CMOVLb/CMOVNGEb (cmov less) */
12949 case 0x4D: /* CMOVGEb/CMOVNLb (cmov greater or equal) */
12950 case 0x4E: /* CMOVLEb/CMOVNGb (cmov less or equal) */
12951 case 0x4F: /* CMOVGb/CMOVNLEb (cmov greater) */
sewardj5b470602005-02-27 13:10:48 +000012952 if (haveF2orF3(pfx)) goto decode_failure;
sewardj3ca55a12005-01-27 16:06:23 +000012953 delta = dis_cmov_E_G(pfx, sz, (AMD64Condcode)(opc - 0x40), delta);
12954 break;
12955
sewardja6b93d12005-02-17 09:28:28 +000012956 /* =-=-=-=-=-=-=-=-=- CMPXCHG -=-=-=-=-=-=-=-=-=-= */
12957
sewardjd20c8852005-01-20 20:04:07 +000012958//.. case 0xB0: /* CMPXCHG Gb,Eb */
12959//.. delta = dis_cmpxchg_G_E ( sorb, 1, delta );
12960//.. break;
sewardja6b93d12005-02-17 09:28:28 +000012961 case 0xB1: /* CMPXCHG Gv,Ev */
sewardj5b470602005-02-27 13:10:48 +000012962 if (haveF2orF3(pfx)) goto decode_failure;
sewardja6b93d12005-02-17 09:28:28 +000012963 delta = dis_cmpxchg_G_E ( pfx, sz, delta );
12964 break;
sewardjd20c8852005-01-20 20:04:07 +000012965//.. //-- case 0xC7: /* CMPXCHG8B Gv */
12966//.. //-- eip = dis_cmpxchg8b ( cb, sorb, eip );
12967//.. //-- break;
12968//.. //--
sewardjd0a12df2005-02-10 02:07:43 +000012969 /* =-=-=-=-=-=-=-=-=- CPUID -=-=-=-=-=-=-=-=-=-=-= */
12970
12971 case 0xA2: { /* CPUID */
12972 /* Uses dirty helper:
12973 void amd64g_dirtyhelper_CPUID ( VexGuestAMD64State* )
12974 declared to mod rax, wr rbx, rcx, rdx
12975 */
12976 IRDirty* d = NULL;
12977 HChar* fName = NULL;
12978 void* fAddr = NULL;
sewardj5b470602005-02-27 13:10:48 +000012979 if (haveF2orF3(pfx)) goto decode_failure;
sewardj27e1dd62005-06-30 11:49:14 +000012980 switch (archinfo->subarch) {
sewardjd0a12df2005-02-10 02:07:43 +000012981 case VexSubArch_NONE:
12982 fName = "amd64g_dirtyhelper_CPUID";
12983 fAddr = &amd64g_dirtyhelper_CPUID;
12984 break;
12985 default:
12986 vpanic("disInstr(amd64)(cpuid)");
12987 }
12988 vassert(fName); vassert(fAddr);
12989 d = unsafeIRDirty_0_N ( 0/*regparms*/,
12990 fName, fAddr, mkIRExprVec_0() );
12991 /* declare guest state effects */
12992 d->needsBBP = True;
12993 d->nFxState = 4;
12994 d->fxState[0].fx = Ifx_Modify;
12995 d->fxState[0].offset = OFFB_RAX;
12996 d->fxState[0].size = 8;
12997 d->fxState[1].fx = Ifx_Write;
12998 d->fxState[1].offset = OFFB_RBX;
12999 d->fxState[1].size = 8;
13000 d->fxState[2].fx = Ifx_Write;
13001 d->fxState[2].offset = OFFB_RCX;
13002 d->fxState[2].size = 8;
13003 d->fxState[3].fx = Ifx_Write;
13004 d->fxState[3].offset = OFFB_RDX;
13005 d->fxState[3].size = 8;
13006 /* execute the dirty call, side-effecting guest state */
13007 stmt( IRStmt_Dirty(d) );
13008 /* CPUID is a serialising insn. So, just in case someone is
13009 using it as a memory fence ... */
13010 stmt( IRStmt_MFence() );
13011 DIP("cpuid\n");
13012 break;
13013 }
13014
sewardj5e525292005-01-28 15:13:10 +000013015 /* =-=-=-=-=-=-=-=-=- MOVZX, MOVSX =-=-=-=-=-=-=-= */
13016
13017 case 0xB6: /* MOVZXb Eb,Gv */
sewardj5b470602005-02-27 13:10:48 +000013018 if (haveF2orF3(pfx)) goto decode_failure;
sewardj5e525292005-01-28 15:13:10 +000013019 if (sz != 2 && sz != 4 && sz != 8)
13020 goto decode_failure;
13021 delta = dis_movx_E_G ( pfx, delta, 1, sz, False );
13022 break;
13023 case 0xB7: /* MOVZXw Ew,Gv */
sewardj5b470602005-02-27 13:10:48 +000013024 if (haveF2orF3(pfx)) goto decode_failure;
sewardj5e525292005-01-28 15:13:10 +000013025 if (sz != 4 && sz != 8)
13026 goto decode_failure;
13027 delta = dis_movx_E_G ( pfx, delta, 2, sz, False );
13028 break;
13029
sewardj03b07cc2005-01-31 18:09:43 +000013030 case 0xBE: /* MOVSXb Eb,Gv */
sewardj5b470602005-02-27 13:10:48 +000013031 if (haveF2orF3(pfx)) goto decode_failure;
sewardj82c9f2f2005-03-02 16:05:13 +000013032 if (sz != 2 && sz != 4 && sz != 8)
sewardj03b07cc2005-01-31 18:09:43 +000013033 goto decode_failure;
13034 delta = dis_movx_E_G ( pfx, delta, 1, sz, True );
13035 break;
13036 case 0xBF: /* MOVSXw Ew,Gv */
sewardj5b470602005-02-27 13:10:48 +000013037 if (haveF2orF3(pfx)) goto decode_failure;
sewardj03b07cc2005-01-31 18:09:43 +000013038 if (sz != 4 && sz != 8)
13039 goto decode_failure;
13040 delta = dis_movx_E_G ( pfx, delta, 2, sz, True );
13041 break;
13042
sewardjd20c8852005-01-20 20:04:07 +000013043//.. //-- /* =-=-=-=-=-=-=-=-=-=-= MOVNTI -=-=-=-=-=-=-=-=-= */
13044//.. //--
13045//.. //-- case 0xC3: /* MOVNTI Gv,Ev */
13046//.. //-- vg_assert(sz == 4);
13047//.. //-- modrm = getUChar(eip);
13048//.. //-- vg_assert(!epartIsReg(modrm));
13049//.. //-- t1 = newTemp(cb);
13050//.. //-- uInstr2(cb, GET, 4, ArchReg, gregOfRM(modrm), TempReg, t1);
13051//.. //-- pair = disAMode ( cb, sorb, eip, dis_buf );
13052//.. //-- t2 = LOW24(pair);
13053//.. //-- eip += HI8(pair);
13054//.. //-- uInstr2(cb, STORE, 4, TempReg, t1, TempReg, t2);
13055//.. //-- DIP("movnti %s,%s\n", nameIReg(4,gregOfRM(modrm)), dis_buf);
13056//.. //-- break;
sewardj32b2bbe2005-01-28 00:50:10 +000013057
13058 /* =-=-=-=-=-=-=-=-=- MUL/IMUL =-=-=-=-=-=-=-=-=-= */
13059
13060 case 0xAF: /* IMUL Ev, Gv */
sewardj5b470602005-02-27 13:10:48 +000013061 if (haveF2orF3(pfx)) goto decode_failure;
sewardj32b2bbe2005-01-28 00:50:10 +000013062 delta = dis_mul_E_G ( pfx, sz, delta );
13063 break;
13064
sewardj1389d4d2005-01-28 13:46:29 +000013065 /* =-=-=-=-=-=-=-=-=- Jcond d32 -=-=-=-=-=-=-=-=-= */
13066 case 0x80:
13067 case 0x81:
13068 case 0x82: /* JBb/JNAEb (jump below) */
13069 case 0x83: /* JNBb/JAEb (jump not below) */
13070 case 0x84: /* JZb/JEb (jump zero) */
13071 case 0x85: /* JNZb/JNEb (jump not zero) */
13072 case 0x86: /* JBEb/JNAb (jump below or equal) */
13073 case 0x87: /* JNBEb/JAb (jump not below or equal) */
13074 case 0x88: /* JSb (jump negative) */
13075 case 0x89: /* JSb (jump not negative) */
13076 case 0x8A: /* JP (jump parity even) */
13077 case 0x8B: /* JNP/JPO (jump parity odd) */
13078 case 0x8C: /* JLb/JNGEb (jump less) */
13079 case 0x8D: /* JGEb/JNLb (jump greater or equal) */
13080 case 0x8E: /* JLEb/JNGb (jump less or equal) */
13081 case 0x8F: /* JGb/JNLEb (jump greater) */
sewardj5b470602005-02-27 13:10:48 +000013082 if (haveF2orF3(pfx)) goto decode_failure;
sewardj9e6491a2005-07-02 19:24:10 +000013083 d64 = (guest_RIP_bbstart+delta+4) + getSDisp32(delta);
sewardj1389d4d2005-01-28 13:46:29 +000013084 delta += 4;
13085 jcc_01( (AMD64Condcode)(opc - 0x80),
sewardj9e6491a2005-07-02 19:24:10 +000013086 guest_RIP_bbstart+delta,
sewardj1389d4d2005-01-28 13:46:29 +000013087 d64 );
sewardj9e6491a2005-07-02 19:24:10 +000013088 dres.whatNext = Dis_StopHere;
sewardj1389d4d2005-01-28 13:46:29 +000013089 DIP("j%s-32 0x%llx\n", name_AMD64Condcode(opc - 0x80), d64);
13090 break;
13091
sewardjb04a47c2005-08-10 12:27:46 +000013092 /* =-=-=-=-=-=-=-=-=- PREFETCH =-=-=-=-=-=-=-=-=-= */
13093 case 0x0D: /* 0F 0D /0 -- prefetch mem8 */
13094 /* 0F 0D /1 -- prefetchw mem8 */
13095 if (have66orF2orF3(pfx)) goto decode_failure;
13096 modrm = getUChar(delta);
13097 if (epartIsReg(modrm)) goto decode_failure;
13098 if (gregLO3ofRM(modrm) != 0 && gregLO3ofRM(modrm) != 1)
13099 goto decode_failure;
13100
13101 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
13102 delta += alen;
13103
13104 switch (gregLO3ofRM(modrm)) {
13105 case 0: DIP("prefetch %s\n", dis_buf); break;
13106 case 1: DIP("prefetchw %s\n", dis_buf); break;
13107 default: vassert(0); /*NOTREACHED*/
13108 }
13109 break;
13110
sewardj31191072005-02-05 18:24:47 +000013111 /* =-=-=-=-=-=-=-=-=- RDTSC -=-=-=-=-=-=-=-=-=-=-= */
sewardjbc6af532005-08-23 23:16:51 +000013112 case 0x31: { /* RDTSC */
13113 IRTemp val = newTemp(Ity_I64);
13114 IRExpr** args = mkIRExprVec_0();
13115 IRDirty* d = unsafeIRDirty_1_N (
13116 val,
13117 0/*regparms*/,
13118 "amd64g_dirtyhelper_RDTSC",
13119 &amd64g_dirtyhelper_RDTSC,
13120 args
13121 );
13122 if (have66orF2orF3(pfx)) goto decode_failure;
13123 /* execute the dirty call, dumping the result in val. */
13124 stmt( IRStmt_Dirty(d) );
13125 putIRegRDX(4, unop(Iop_64HIto32, mkexpr(val)));
13126 putIRegRAX(4, unop(Iop_64to32, mkexpr(val)));
sewardj31191072005-02-05 18:24:47 +000013127 DIP("rdtsc\n");
13128 break;
sewardjbc6af532005-08-23 23:16:51 +000013129 }
sewardj31191072005-02-05 18:24:47 +000013130
sewardjd20c8852005-01-20 20:04:07 +000013131//.. /* =-=-=-=-=-=-=-=-=- PUSH/POP Sreg =-=-=-=-=-=-=-=-=-= */
13132//..
13133//.. case 0xA1: /* POP %FS */
13134//.. dis_pop_segreg( R_FS, sz ); break;
13135//.. case 0xA9: /* POP %GS */
13136//.. dis_pop_segreg( R_GS, sz ); break;
13137//..
13138//.. case 0xA0: /* PUSH %FS */
13139//.. dis_push_segreg( R_FS, sz ); break;
13140//.. case 0xA8: /* PUSH %GS */
13141//.. dis_push_segreg( R_GS, sz ); break;
sewardj118b23e2005-01-29 02:14:44 +000013142
13143 /* =-=-=-=-=-=-=-=-=- SETcc Eb =-=-=-=-=-=-=-=-=-= */
13144 case 0x90:
13145 case 0x91:
13146 case 0x92: /* set-Bb/set-NAEb (set if below) */
13147 case 0x93: /* set-NBb/set-AEb (set if not below) */
13148 case 0x94: /* set-Zb/set-Eb (set if zero) */
13149 case 0x95: /* set-NZb/set-NEb (set if not zero) */
13150 case 0x96: /* set-BEb/set-NAb (set if below or equal) */
13151 case 0x97: /* set-NBEb/set-Ab (set if not below or equal) */
13152 case 0x98: /* set-Sb (set if negative) */
13153 case 0x99: /* set-Sb (set if not negative) */
13154 case 0x9A: /* set-P (set if parity even) */
13155 case 0x9B: /* set-NP (set if parity odd) */
13156 case 0x9C: /* set-Lb/set-NGEb (set if less) */
13157 case 0x9D: /* set-GEb/set-NLb (set if greater or equal) */
13158 case 0x9E: /* set-LEb/set-NGb (set if less or equal) */
13159 case 0x9F: /* set-Gb/set-NLEb (set if greater) */
sewardj5b470602005-02-27 13:10:48 +000013160 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000013161 t1 = newTemp(Ity_I8);
13162 assign( t1, unop(Iop_1Uto8,mk_amd64g_calculate_condition(opc-0x90)) );
13163 modrm = getUChar(delta);
13164 if (epartIsReg(modrm)) {
13165 delta++;
sewardj5b470602005-02-27 13:10:48 +000013166 putIRegE(1, pfx, modrm, mkexpr(t1));
sewardj118b23e2005-01-29 02:14:44 +000013167 DIP("set%s %s\n", name_AMD64Condcode(opc-0x90),
sewardj5b470602005-02-27 13:10:48 +000013168 nameIRegE(1,pfx,modrm));
sewardj118b23e2005-01-29 02:14:44 +000013169 } else {
sewardj5cc00ff2005-03-27 04:48:32 +000013170 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
13171 delta += alen;
13172 storeLE( mkexpr(addr), mkexpr(t1) );
13173 DIP("set%s %s\n", name_AMD64Condcode(opc-0x90), dis_buf);
sewardj118b23e2005-01-29 02:14:44 +000013174 }
13175 break;
13176
sewardjd20c8852005-01-20 20:04:07 +000013177//.. /* =-=-=-=-=-=-=-=-=- SHLD/SHRD -=-=-=-=-=-=-=-=-= */
13178//..
13179//.. case 0xA4: /* SHLDv imm8,Gv,Ev */
sewardj8c332e22005-01-28 01:36:56 +000013180//.. modrm = getUChar(delta);
sewardjd20c8852005-01-20 20:04:07 +000013181//.. d32 = delta + lengthAMode(delta);
13182//.. vex_sprintf(dis_buf, "$%d", delta);
13183//.. delta = dis_SHLRD_Gv_Ev (
13184//.. sorb, delta, modrm, sz,
sewardj8c332e22005-01-28 01:36:56 +000013185//.. mkU8(getUChar(d32)), True, /* literal */
sewardjd20c8852005-01-20 20:04:07 +000013186//.. dis_buf, True );
13187//.. break;
13188//.. case 0xA5: /* SHLDv %cl,Gv,Ev */
sewardj8c332e22005-01-28 01:36:56 +000013189//.. modrm = getUChar(delta);
sewardjd20c8852005-01-20 20:04:07 +000013190//.. delta = dis_SHLRD_Gv_Ev (
13191//.. sorb, delta, modrm, sz,
13192//.. getIReg(1,R_ECX), False, /* not literal */
13193//.. "%cl", True );
13194//.. break;
13195//..
13196//.. case 0xAC: /* SHRDv imm8,Gv,Ev */
sewardj8c332e22005-01-28 01:36:56 +000013197//.. modrm = getUChar(delta);
sewardjd20c8852005-01-20 20:04:07 +000013198//.. d32 = delta + lengthAMode(delta);
13199//.. vex_sprintf(dis_buf, "$%d", delta);
13200//.. delta = dis_SHLRD_Gv_Ev (
13201//.. sorb, delta, modrm, sz,
sewardj8c332e22005-01-28 01:36:56 +000013202//.. mkU8(getUChar(d32)), True, /* literal */
sewardjd20c8852005-01-20 20:04:07 +000013203//.. dis_buf, False );
13204//.. break;
13205//.. case 0xAD: /* SHRDv %cl,Gv,Ev */
sewardj8c332e22005-01-28 01:36:56 +000013206//.. modrm = getUChar(delta);
sewardjd20c8852005-01-20 20:04:07 +000013207//.. delta = dis_SHLRD_Gv_Ev (
13208//.. sorb, delta, modrm, sz,
13209//.. getIReg(1,R_ECX), False, /* not literal */
13210//.. "%cl", False );
13211//.. break;
sewardje1698952005-02-08 15:02:39 +000013212
13213 /* =-=-=-=-=-=-=-=-=- SYSCALL -=-=-=-=-=-=-=-=-=-= */
13214 case 0x05: /* SYSCALL */
sewardj9e6491a2005-07-02 19:24:10 +000013215 guest_RIP_next_mustcheck = True;
13216 guest_RIP_next_assumed = guest_RIP_bbstart + delta;
13217 putIReg64( R_RCX, mkU64(guest_RIP_next_assumed) );
sewardje1698952005-02-08 15:02:39 +000013218 /* It's important that all guest state is up-to-date
13219 at this point. So we declare an end-of-block here, which
13220 forces any cached guest state to be flushed. */
sewardj9e6491a2005-07-02 19:24:10 +000013221 jmp_lit(Ijk_Syscall, guest_RIP_next_assumed);
13222 dres.whatNext = Dis_StopHere;
sewardje1698952005-02-08 15:02:39 +000013223 DIP("syscall\n");
13224 break;
13225
sewardjb4fd2e72005-03-23 13:34:11 +000013226 /* =-=-=-=-=-=-=-=-=- XADD -=-=-=-=-=-=-=-=-=-= */
13227
sewardjd20c8852005-01-20 20:04:07 +000013228//.. //-- case 0xC0: /* XADD Gb,Eb */
13229//.. //-- eip = dis_xadd_G_E ( cb, sorb, 1, eip );
13230//.. //-- break;
sewardjb4fd2e72005-03-23 13:34:11 +000013231 case 0xC1: { /* XADD Gv,Ev */
13232 Bool decode_OK = False;
13233 delta = dis_xadd_G_E ( &decode_OK, pfx, sz, delta );
13234 if (!decode_OK)
13235 goto decode_failure;
13236 break;
13237 }
13238
sewardj8711f662005-05-09 17:52:56 +000013239 /* =-=-=-=-=-=-=-=-=- MMXery =-=-=-=-=-=-=-=-=-=-= */
13240
sewardj3d8107c2005-05-09 22:23:38 +000013241 case 0x71:
13242 case 0x72:
13243 case 0x73: /* PSLLgg/PSRAgg/PSRLgg mmxreg by imm8 */
13244
13245 case 0x6E: /* MOVD (src)ireg-or-mem, (dst)mmxreg */
13246 case 0x7E: /* MOVD (src)mmxreg, (dst)ireg-or-mem */
sewardj8711f662005-05-09 17:52:56 +000013247 case 0x7F: /* MOVQ (src)mmxreg, (dst)mmxreg-or-mem */
13248 case 0x6F: /* MOVQ (src)mmxreg-or-mem, (dst)mmxreg */
13249
13250 case 0xFC:
13251 case 0xFD:
13252 case 0xFE: /* PADDgg (src)mmxreg-or-mem, (dst)mmxreg */
13253
13254 case 0xEC:
13255 case 0xED: /* PADDSgg (src)mmxreg-or-mem, (dst)mmxreg */
13256
13257 case 0xDC:
13258 case 0xDD: /* PADDUSgg (src)mmxreg-or-mem, (dst)mmxreg */
13259
13260 case 0xF8:
13261 case 0xF9:
13262 case 0xFA: /* PSUBgg (src)mmxreg-or-mem, (dst)mmxreg */
13263
13264 case 0xE8:
13265 case 0xE9: /* PSUBSgg (src)mmxreg-or-mem, (dst)mmxreg */
13266
13267 case 0xD8:
13268 case 0xD9: /* PSUBUSgg (src)mmxreg-or-mem, (dst)mmxreg */
13269
13270 case 0xE5: /* PMULHW (src)mmxreg-or-mem, (dst)mmxreg */
13271 case 0xD5: /* PMULLW (src)mmxreg-or-mem, (dst)mmxreg */
13272
13273 case 0xF5: /* PMADDWD (src)mmxreg-or-mem, (dst)mmxreg */
13274
13275 case 0x74:
13276 case 0x75:
13277 case 0x76: /* PCMPEQgg (src)mmxreg-or-mem, (dst)mmxreg */
13278
13279 case 0x64:
13280 case 0x65:
13281 case 0x66: /* PCMPGTgg (src)mmxreg-or-mem, (dst)mmxreg */
13282
13283 case 0x6B: /* PACKSSDW (src)mmxreg-or-mem, (dst)mmxreg */
13284 case 0x63: /* PACKSSWB (src)mmxreg-or-mem, (dst)mmxreg */
13285 case 0x67: /* PACKUSWB (src)mmxreg-or-mem, (dst)mmxreg */
13286
13287 case 0x68:
13288 case 0x69:
13289 case 0x6A: /* PUNPCKHgg (src)mmxreg-or-mem, (dst)mmxreg */
13290
13291 case 0x60:
13292 case 0x61:
13293 case 0x62: /* PUNPCKLgg (src)mmxreg-or-mem, (dst)mmxreg */
13294
13295 case 0xDB: /* PAND (src)mmxreg-or-mem, (dst)mmxreg */
13296 case 0xDF: /* PANDN (src)mmxreg-or-mem, (dst)mmxreg */
13297 case 0xEB: /* POR (src)mmxreg-or-mem, (dst)mmxreg */
13298 case 0xEF: /* PXOR (src)mmxreg-or-mem, (dst)mmxreg */
13299
13300 case 0xF1: /* PSLLgg (src)mmxreg-or-mem, (dst)mmxreg */
13301 case 0xF2:
13302 case 0xF3:
13303
13304 case 0xD1: /* PSRLgg (src)mmxreg-or-mem, (dst)mmxreg */
13305 case 0xD2:
13306 case 0xD3:
13307
13308 case 0xE1: /* PSRAgg (src)mmxreg-or-mem, (dst)mmxreg */
13309 case 0xE2:
13310 {
sewardj270def42005-07-03 01:03:01 +000013311 Long delta0 = delta-1;
sewardj8711f662005-05-09 17:52:56 +000013312 Bool decode_OK = False;
13313
13314 /* If sz==2 this is SSE, and we assume sse idec has
13315 already spotted those cases by now. */
sewardj3d8107c2005-05-09 22:23:38 +000013316 if (sz != 4 && sz != 8)
sewardj8711f662005-05-09 17:52:56 +000013317 goto decode_failure;
13318 if (have66orF2orF3(pfx))
13319 goto decode_failure;
13320
13321 delta = dis_MMX ( &decode_OK, pfx, sz, delta-1 );
13322 if (!decode_OK) {
13323 delta = delta0;
13324 goto decode_failure;
13325 }
13326 break;
13327 }
13328
13329 case 0x77: /* EMMS */
13330 if (sz != 4)
13331 goto decode_failure;
13332 do_EMMS_preamble();
13333 DIP("emms\n");
13334 break;
sewardj3ca55a12005-01-27 16:06:23 +000013335
13336 /* =-=-=-=-=-=-=-=-=- unimp2 =-=-=-=-=-=-=-=-=-=-= */
13337
13338 default:
13339 goto decode_failure;
13340 } /* switch (opc) for the 2-byte opcodes */
13341 goto decode_success;
13342 } /* case 0x0F: of primary opcode */
sewardjdf0e0022005-01-25 15:48:43 +000013343
13344 /* ------------------------ ??? ------------------------ */
13345
13346 default:
13347 decode_failure:
13348 /* All decode failures end up here. */
13349 vex_printf("vex amd64->IR: unhandled instruction bytes: "
13350 "0x%x 0x%x 0x%x 0x%x\n",
sewardj8c332e22005-01-28 01:36:56 +000013351 (Int)getUChar(delta_start+0),
13352 (Int)getUChar(delta_start+1),
13353 (Int)getUChar(delta_start+2),
13354 (Int)getUChar(delta_start+3) );
sewardjdf0e0022005-01-25 15:48:43 +000013355
13356 /* Tell the dispatcher that this insn cannot be decoded, and so has
13357 not been executed, and (is currently) the next to be executed.
13358 RIP should be up-to-date since it made so at the start of each
13359 insn, but nevertheless be paranoid and update it again right
13360 now. */
sewardj9e6491a2005-07-02 19:24:10 +000013361 stmt( IRStmt_Put( OFFB_RIP, mkU64(guest_RIP_curr_instr) ) );
13362 jmp_lit(Ijk_NoDecode, guest_RIP_curr_instr);
13363 dres.whatNext = Dis_StopHere;
13364 dres.len = 0;
13365 return dres;
sewardjdf0e0022005-01-25 15:48:43 +000013366
13367 } /* switch (opc) for the main (primary) opcode switch. */
13368
13369 decode_success:
13370 /* All decode successes end up here. */
13371 DIP("\n");
sewardj9e6491a2005-07-02 19:24:10 +000013372 dres.len = (Int)toUInt(delta - delta_start);
13373 return dres;
sewardjdf0e0022005-01-25 15:48:43 +000013374}
13375
13376#undef DIP
13377#undef DIS
sewardjd20c8852005-01-20 20:04:07 +000013378
sewardj9e6491a2005-07-02 19:24:10 +000013379
13380/*------------------------------------------------------------*/
13381/*--- Top-level fn ---*/
13382/*------------------------------------------------------------*/
13383
13384/* Disassemble a single instruction into IR. The instruction
13385 is located in host memory at &guest_code[delta]. */
13386
13387DisResult disInstr_AMD64 ( IRBB* irbb_IN,
13388 Bool put_IP,
13389 Bool (*resteerOkFn) ( Addr64 ),
13390 UChar* guest_code_IN,
13391 Long delta,
13392 Addr64 guest_IP,
13393 VexArchInfo* archinfo,
13394 Bool host_bigendian_IN )
13395{
13396 DisResult dres;
13397
13398 /* Set globals (see top of this file) */
13399 guest_code = guest_code_IN;
13400 irbb = irbb_IN;
13401 host_is_bigendian = host_bigendian_IN;
13402 guest_RIP_curr_instr = guest_IP;
13403 guest_RIP_bbstart = guest_IP - delta;
13404
13405 /* We'll consult these after doing disInstr_AMD64_WRK. */
13406 guest_RIP_next_assumed = 0;
13407 guest_RIP_next_mustcheck = False;
13408
13409 dres = disInstr_AMD64_WRK ( put_IP, resteerOkFn,
13410 delta, archinfo );
13411
13412 /* If disInstr_AMD64_WRK tried to figure out the next rip, check it
13413 got it right. Failure of this assertion is serious and denotes
13414 a bug in disInstr. */
13415 if (guest_RIP_next_mustcheck
13416 && guest_RIP_next_assumed != guest_RIP_curr_instr + dres.len) {
13417 vex_printf("\n");
13418 vex_printf("assumed next %%rip = 0x%llx\n",
13419 guest_RIP_next_assumed );
13420 vex_printf(" actual next %%rip = 0x%llx\n",
13421 guest_RIP_curr_instr + dres.len );
13422 vpanic("bbToIR_AMD64: disInstr miscalculated next %rip");
13423 }
13424
13425 return dres;
13426}
13427
13428
13429
sewardjd20c8852005-01-20 20:04:07 +000013430/*--------------------------------------------------------------------*/
13431/*--- end guest-amd64/toIR.c ---*/
13432/*--------------------------------------------------------------------*/