blob: af68babc6a42f2dfba8811a7f30d1aa68497ffe9 [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
sewardje7441532007-01-08 05:51:05 +000013 Copyright (C) 2004-2007 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
sewardj42561ef2005-11-04 14:18:31 +000096/* Notes re address size overrides (0x67).
97
98 According to the AMD documentation (24594 Rev 3.09, Sept 2003,
99 "AMD64 Architecture Programmer's Manual Volume 3: General-Purpose
100 and System Instructions"), Section 1.2.3 ("Address-Size Override
101 Prefix"):
102
103 0x67 applies to all explicit memory references, causing the top
104 32 bits of the effective address to become zero.
105
106 0x67 has no effect on stack references (push/pop); these always
107 use a 64-bit address.
108
109 0x67 changes the interpretation of instructions which implicitly
110 reference RCX/RSI/RDI, so that in fact ECX/ESI/EDI are used
111 instead. These are:
112
113 cmp{s,sb,sw,sd,sq}
114 in{s,sb,sw,sd}
115 jcxz, jecxz, jrcxz
116 lod{s,sb,sw,sd,sq}
117 loop{,e,bz,be,z}
118 mov{s,sb,sw,sd,sq}
119 out{s,sb,sw,sd}
120 rep{,e,ne,nz}
121 sca{s,sb,sw,sd,sq}
122 sto{s,sb,sw,sd,sq}
123 xlat{,b} */
124
sewardjce02aa72006-01-12 12:27:58 +0000125/* "Special" instructions.
126
127 This instruction decoder can decode three special instructions
128 which mean nothing natively (are no-ops as far as regs/mem are
129 concerned) but have meaning for supporting Valgrind. A special
130 instruction is flagged by the 16-byte preamble 48C1C703 48C1C70D
131 48C1C73D 48C1C733 (in the standard interpretation, that means: rolq
132 $3, %rdi; rolq $13, %rdi; rolq $61, %rdi; rolq $51, %rdi).
133 Following that, one of the following 3 are allowed (standard
134 interpretation in parentheses):
135
136 4887DB (xchgq %rbx,%rbx) %RDX = client_request ( %RAX )
137 4887C9 (xchgq %rcx,%rcx) %RAX = guest_NRADDR
138 4887D2 (xchgq %rdx,%rdx) call-noredir *%RAX
139
140 Any other bytes following the 16-byte preamble are illegal and
141 constitute a failure in instruction decoding. This all assumes
142 that the preamble will never occur except in specific code
143 fragments designed for Valgrind to catch.
144
145 No prefixes may precede a "Special" instruction. */
146
sewardj44d494d2005-01-20 20:26:33 +0000147/* Translates AMD64 code to IR. */
148
149#include "libvex_basictypes.h"
150#include "libvex_ir.h"
151#include "libvex.h"
152#include "libvex_guest_amd64.h"
153
154#include "main/vex_util.h"
155#include "main/vex_globals.h"
sewardj9e6491a2005-07-02 19:24:10 +0000156#include "guest-generic/bb_to_IR.h"
sewardj879cee02006-03-07 01:15:50 +0000157#include "guest-generic/g_generic_x87.h"
sewardj44d494d2005-01-20 20:26:33 +0000158#include "guest-amd64/gdefs.h"
159
160
sewardjecb94892005-01-21 14:26:37 +0000161/*------------------------------------------------------------*/
162/*--- Globals ---*/
163/*------------------------------------------------------------*/
164
sewardj9e6491a2005-07-02 19:24:10 +0000165/* These are set at the start of the translation of an insn, right
166 down in disInstr_AMD64, so that we don't have to pass them around
167 endlessly. They are all constant during the translation of any
168 given insn. */
sewardj4b744762005-02-07 15:02:25 +0000169
sewardjecb94892005-01-21 14:26:37 +0000170/* These are set at the start of the translation of a BB, so
171 that we don't have to pass them around endlessly. */
172
173/* We need to know this to do sub-register accesses correctly. */
sewardjecb94892005-01-21 14:26:37 +0000174static Bool host_is_bigendian;
175
sewardj9e6491a2005-07-02 19:24:10 +0000176/* Pointer to the guest code area (points to start of BB, not to the
177 insn being processed). */
sewardjb3a04292005-01-21 20:33:44 +0000178static UChar* guest_code;
179
sewardjdf0e0022005-01-25 15:48:43 +0000180/* The guest address corresponding to guest_code[0]. */
sewardj9e6491a2005-07-02 19:24:10 +0000181static Addr64 guest_RIP_bbstart;
sewardj4b744762005-02-07 15:02:25 +0000182
sewardjb3a04292005-01-21 20:33:44 +0000183/* The guest address for the instruction currently being
184 translated. */
sewardj9e6491a2005-07-02 19:24:10 +0000185static Addr64 guest_RIP_curr_instr;
sewardjecb94892005-01-21 14:26:37 +0000186
sewardjdd40fdf2006-12-24 02:20:24 +0000187/* The IRSB* into which we're generating code. */
188static IRSB* irsb;
sewardjecb94892005-01-21 14:26:37 +0000189
sewardj4b744762005-02-07 15:02:25 +0000190/* For ensuring that %rip-relative addressing is done right. A read
191 of %rip generates the address of the next instruction. It may be
192 that we don't conveniently know that inside disAMode(). For sanity
193 checking, if the next insn %rip is needed, we make a guess at what
194 it is, record that guess here, and set the accompanying Bool to
195 indicate that -- after this insn's decode is finished -- that guess
196 needs to be checked. */
197
198/* At the start of each insn decode, is set to (0, False).
199 After the decode, if _mustcheck is now True, _assumed is
200 checked. */
201
sewardj9e6491a2005-07-02 19:24:10 +0000202static Addr64 guest_RIP_next_assumed;
203static Bool guest_RIP_next_mustcheck;
sewardj4b744762005-02-07 15:02:25 +0000204
205
sewardjecb94892005-01-21 14:26:37 +0000206/*------------------------------------------------------------*/
207/*--- Helpers for constructing IR. ---*/
208/*------------------------------------------------------------*/
209
sewardjb3a04292005-01-21 20:33:44 +0000210/* Generate a new temporary of the given type. */
211static IRTemp newTemp ( IRType ty )
212{
sewardj496a58d2005-03-20 18:44:44 +0000213 vassert(isPlausibleIRType(ty));
sewardjdd40fdf2006-12-24 02:20:24 +0000214 return newIRTemp( irsb->tyenv, ty );
sewardjb3a04292005-01-21 20:33:44 +0000215}
216
sewardjdd40fdf2006-12-24 02:20:24 +0000217/* Add a statement to the list held by "irsb". */
sewardjecb94892005-01-21 14:26:37 +0000218static void stmt ( IRStmt* st )
219{
sewardjdd40fdf2006-12-24 02:20:24 +0000220 addStmtToIRSB( irsb, st );
sewardjecb94892005-01-21 14:26:37 +0000221}
sewardjb3a04292005-01-21 20:33:44 +0000222
223/* Generate a statement "dst := e". */
224static void assign ( IRTemp dst, IRExpr* e )
225{
sewardjdd40fdf2006-12-24 02:20:24 +0000226 stmt( IRStmt_WrTmp(dst, e) );
sewardjb3a04292005-01-21 20:33:44 +0000227}
228
sewardjecb94892005-01-21 14:26:37 +0000229static IRExpr* unop ( IROp op, IRExpr* a )
230{
231 return IRExpr_Unop(op, a);
232}
233
sewardjb3a04292005-01-21 20:33:44 +0000234static IRExpr* binop ( IROp op, IRExpr* a1, IRExpr* a2 )
235{
236 return IRExpr_Binop(op, a1, a2);
237}
238
sewardj4796d662006-02-05 16:06:26 +0000239static IRExpr* triop ( IROp op, IRExpr* a1, IRExpr* a2, IRExpr* a3 )
240{
241 return IRExpr_Triop(op, a1, a2, a3);
242}
243
sewardjdf0e0022005-01-25 15:48:43 +0000244static IRExpr* mkexpr ( IRTemp tmp )
245{
sewardjdd40fdf2006-12-24 02:20:24 +0000246 return IRExpr_RdTmp(tmp);
sewardjdf0e0022005-01-25 15:48:43 +0000247}
sewardjb3a04292005-01-21 20:33:44 +0000248
sewardj3ca55a12005-01-27 16:06:23 +0000249static IRExpr* mkU8 ( ULong i )
sewardjb3a04292005-01-21 20:33:44 +0000250{
251 vassert(i < 256);
sewardj3ca55a12005-01-27 16:06:23 +0000252 return IRExpr_Const(IRConst_U8( (UChar)i ));
sewardjb3a04292005-01-21 20:33:44 +0000253}
254
sewardj5e525292005-01-28 15:13:10 +0000255static IRExpr* mkU16 ( ULong i )
256{
257 vassert(i < 0x10000ULL);
258 return IRExpr_Const(IRConst_U16( (UShort)i ));
259}
sewardj3ca55a12005-01-27 16:06:23 +0000260
261static IRExpr* mkU32 ( ULong i )
262{
263 vassert(i < 0x100000000ULL);
264 return IRExpr_Const(IRConst_U32( (UInt)i ));
265}
sewardjb3a04292005-01-21 20:33:44 +0000266
267static IRExpr* mkU64 ( ULong i )
268{
269 return IRExpr_Const(IRConst_U64(i));
270}
sewardjecb94892005-01-21 14:26:37 +0000271
sewardj3ca55a12005-01-27 16:06:23 +0000272static IRExpr* mkU ( IRType ty, ULong i )
273{
274 switch (ty) {
275 case Ity_I8: return mkU8(i);
sewardj5e525292005-01-28 15:13:10 +0000276 case Ity_I16: return mkU16(i);
sewardj3ca55a12005-01-27 16:06:23 +0000277 case Ity_I32: return mkU32(i);
278 case Ity_I64: return mkU64(i);
279 default: vpanic("mkU(amd64)");
280 }
281}
282
sewardj5e525292005-01-28 15:13:10 +0000283static void storeLE ( IRExpr* addr, IRExpr* data )
284{
sewardjaf1ceca2005-06-30 23:31:27 +0000285 stmt( IRStmt_Store(Iend_LE,addr,data) );
sewardj5e525292005-01-28 15:13:10 +0000286}
287
288static IRExpr* loadLE ( IRType ty, IRExpr* data )
289{
sewardjaf1ceca2005-06-30 23:31:27 +0000290 return IRExpr_Load(Iend_LE,ty,data);
sewardj5e525292005-01-28 15:13:10 +0000291}
292
293static IROp mkSizedOp ( IRType ty, IROp op8 )
294{
295 vassert(op8 == Iop_Add8 || op8 == Iop_Sub8
296 || op8 == Iop_Mul8
297 || op8 == Iop_Or8 || op8 == Iop_And8 || op8 == Iop_Xor8
298 || op8 == Iop_Shl8 || op8 == Iop_Shr8 || op8 == Iop_Sar8
299 || op8 == Iop_CmpEQ8 || op8 == Iop_CmpNE8
300 || op8 == Iop_Not8 );
301 switch (ty) {
302 case Ity_I8: return 0 +op8;
303 case Ity_I16: return 1 +op8;
304 case Ity_I32: return 2 +op8;
305 case Ity_I64: return 3 +op8;
306 default: vpanic("mkSizedOp(amd64)");
307 }
308}
309
310static
311IRExpr* doScalarWidening ( Int szSmall, Int szBig, Bool signd, IRExpr* src )
312{
313 if (szSmall == 1 && szBig == 4) {
314 return unop(signd ? Iop_8Sto32 : Iop_8Uto32, src);
315 }
316 if (szSmall == 1 && szBig == 2) {
317 return unop(signd ? Iop_8Sto16 : Iop_8Uto16, src);
318 }
319 if (szSmall == 2 && szBig == 4) {
320 return unop(signd ? Iop_16Sto32 : Iop_16Uto32, src);
321 }
322 if (szSmall == 1 && szBig == 8 && !signd) {
sewardje58967e2005-04-27 11:50:56 +0000323 return unop(Iop_8Uto64, src);
sewardj5e525292005-01-28 15:13:10 +0000324 }
sewardj03b07cc2005-01-31 18:09:43 +0000325 if (szSmall == 1 && szBig == 8 && signd) {
sewardje58967e2005-04-27 11:50:56 +0000326 return unop(Iop_8Sto64, src);
sewardj03b07cc2005-01-31 18:09:43 +0000327 }
sewardj5e525292005-01-28 15:13:10 +0000328 if (szSmall == 2 && szBig == 8 && !signd) {
sewardje58967e2005-04-27 11:50:56 +0000329 return unop(Iop_16Uto64, src);
sewardj5e525292005-01-28 15:13:10 +0000330 }
sewardj03b07cc2005-01-31 18:09:43 +0000331 if (szSmall == 2 && szBig == 8 && signd) {
sewardje58967e2005-04-27 11:50:56 +0000332 return unop(Iop_16Sto64, src);
sewardj03b07cc2005-01-31 18:09:43 +0000333 }
sewardj5e525292005-01-28 15:13:10 +0000334 vpanic("doScalarWidening(amd64)");
335}
336
337
sewardjecb94892005-01-21 14:26:37 +0000338
339/*------------------------------------------------------------*/
340/*--- Debugging output ---*/
341/*------------------------------------------------------------*/
342
sewardjb3a04292005-01-21 20:33:44 +0000343/* Bomb out if we can't handle something. */
344__attribute__ ((noreturn))
345static void unimplemented ( HChar* str )
346{
347 vex_printf("amd64toIR: unimplemented feature\n");
348 vpanic(str);
349}
350
sewardjecb94892005-01-21 14:26:37 +0000351#define DIP(format, args...) \
sewardj9e6491a2005-07-02 19:24:10 +0000352 if (vex_traceflags & VEX_TRACE_FE) \
sewardjecb94892005-01-21 14:26:37 +0000353 vex_printf(format, ## args)
354
355#define DIS(buf, format, args...) \
sewardj9e6491a2005-07-02 19:24:10 +0000356 if (vex_traceflags & VEX_TRACE_FE) \
sewardjecb94892005-01-21 14:26:37 +0000357 vex_sprintf(buf, format, ## args)
358
359
360/*------------------------------------------------------------*/
361/*--- Offsets of various parts of the amd64 guest state. ---*/
362/*------------------------------------------------------------*/
363
364#define OFFB_RAX offsetof(VexGuestAMD64State,guest_RAX)
365#define OFFB_RBX offsetof(VexGuestAMD64State,guest_RBX)
366#define OFFB_RCX offsetof(VexGuestAMD64State,guest_RCX)
367#define OFFB_RDX offsetof(VexGuestAMD64State,guest_RDX)
368#define OFFB_RSP offsetof(VexGuestAMD64State,guest_RSP)
369#define OFFB_RBP offsetof(VexGuestAMD64State,guest_RBP)
370#define OFFB_RSI offsetof(VexGuestAMD64State,guest_RSI)
371#define OFFB_RDI offsetof(VexGuestAMD64State,guest_RDI)
372#define OFFB_R8 offsetof(VexGuestAMD64State,guest_R8)
373#define OFFB_R9 offsetof(VexGuestAMD64State,guest_R9)
374#define OFFB_R10 offsetof(VexGuestAMD64State,guest_R10)
375#define OFFB_R11 offsetof(VexGuestAMD64State,guest_R11)
376#define OFFB_R12 offsetof(VexGuestAMD64State,guest_R12)
377#define OFFB_R13 offsetof(VexGuestAMD64State,guest_R13)
378#define OFFB_R14 offsetof(VexGuestAMD64State,guest_R14)
379#define OFFB_R15 offsetof(VexGuestAMD64State,guest_R15)
380
381#define OFFB_RIP offsetof(VexGuestAMD64State,guest_RIP)
382
sewardja6b93d12005-02-17 09:28:28 +0000383#define OFFB_FS_ZERO offsetof(VexGuestAMD64State,guest_FS_ZERO)
384
sewardjecb94892005-01-21 14:26:37 +0000385#define OFFB_CC_OP offsetof(VexGuestAMD64State,guest_CC_OP)
386#define OFFB_CC_DEP1 offsetof(VexGuestAMD64State,guest_CC_DEP1)
387#define OFFB_CC_DEP2 offsetof(VexGuestAMD64State,guest_CC_DEP2)
388#define OFFB_CC_NDEP offsetof(VexGuestAMD64State,guest_CC_NDEP)
389
sewardj8d965312005-02-25 02:48:47 +0000390#define OFFB_FPREGS offsetof(VexGuestAMD64State,guest_FPREG[0])
391#define OFFB_FPTAGS offsetof(VexGuestAMD64State,guest_FPTAG[0])
sewardjd0a12df2005-02-10 02:07:43 +0000392#define OFFB_DFLAG offsetof(VexGuestAMD64State,guest_DFLAG)
sewardj85520e42005-02-19 15:22:38 +0000393#define OFFB_IDFLAG offsetof(VexGuestAMD64State,guest_IDFLAG)
sewardj8d965312005-02-25 02:48:47 +0000394#define OFFB_FTOP offsetof(VexGuestAMD64State,guest_FTOP)
sewardj25a85812005-05-08 23:03:48 +0000395#define OFFB_FC3210 offsetof(VexGuestAMD64State,guest_FC3210)
sewardjc49ce232005-02-25 13:03:03 +0000396#define OFFB_FPROUND offsetof(VexGuestAMD64State,guest_FPROUND)
sewardjd20c8852005-01-20 20:04:07 +0000397//..
398//.. #define OFFB_CS offsetof(VexGuestX86State,guest_CS)
399//.. #define OFFB_DS offsetof(VexGuestX86State,guest_DS)
400//.. #define OFFB_ES offsetof(VexGuestX86State,guest_ES)
401//.. #define OFFB_FS offsetof(VexGuestX86State,guest_FS)
402//.. #define OFFB_GS offsetof(VexGuestX86State,guest_GS)
403//.. #define OFFB_SS offsetof(VexGuestX86State,guest_SS)
404//.. #define OFFB_LDT offsetof(VexGuestX86State,guest_LDT)
405//.. #define OFFB_GDT offsetof(VexGuestX86State,guest_GDT)
sewardj1001dc42005-02-21 08:25:55 +0000406
407#define OFFB_SSEROUND offsetof(VexGuestAMD64State,guest_SSEROUND)
408#define OFFB_XMM0 offsetof(VexGuestAMD64State,guest_XMM0)
409#define OFFB_XMM1 offsetof(VexGuestAMD64State,guest_XMM1)
410#define OFFB_XMM2 offsetof(VexGuestAMD64State,guest_XMM2)
411#define OFFB_XMM3 offsetof(VexGuestAMD64State,guest_XMM3)
412#define OFFB_XMM4 offsetof(VexGuestAMD64State,guest_XMM4)
413#define OFFB_XMM5 offsetof(VexGuestAMD64State,guest_XMM5)
414#define OFFB_XMM6 offsetof(VexGuestAMD64State,guest_XMM6)
415#define OFFB_XMM7 offsetof(VexGuestAMD64State,guest_XMM7)
416#define OFFB_XMM8 offsetof(VexGuestAMD64State,guest_XMM8)
417#define OFFB_XMM9 offsetof(VexGuestAMD64State,guest_XMM9)
418#define OFFB_XMM10 offsetof(VexGuestAMD64State,guest_XMM10)
419#define OFFB_XMM11 offsetof(VexGuestAMD64State,guest_XMM11)
420#define OFFB_XMM12 offsetof(VexGuestAMD64State,guest_XMM12)
421#define OFFB_XMM13 offsetof(VexGuestAMD64State,guest_XMM13)
422#define OFFB_XMM14 offsetof(VexGuestAMD64State,guest_XMM14)
423#define OFFB_XMM15 offsetof(VexGuestAMD64State,guest_XMM15)
424
sewardjbcbb9de2005-03-27 02:22:32 +0000425#define OFFB_EMWARN offsetof(VexGuestAMD64State,guest_EMWARN)
sewardj3e616e62006-01-07 22:58:54 +0000426#define OFFB_TISTART offsetof(VexGuestAMD64State,guest_TISTART)
427#define OFFB_TILEN offsetof(VexGuestAMD64State,guest_TILEN)
sewardjdf0e0022005-01-25 15:48:43 +0000428
sewardjce02aa72006-01-12 12:27:58 +0000429#define OFFB_NRADDR offsetof(VexGuestAMD64State,guest_NRADDR)
430
sewardjdf0e0022005-01-25 15:48:43 +0000431
432/*------------------------------------------------------------*/
sewardjecb94892005-01-21 14:26:37 +0000433/*--- Helper bits and pieces for deconstructing the ---*/
434/*--- amd64 insn stream. ---*/
435/*------------------------------------------------------------*/
436
437/* This is the AMD64 register encoding -- integer regs. */
438#define R_RAX 0
439#define R_RCX 1
440#define R_RDX 2
441#define R_RBX 3
442#define R_RSP 4
443#define R_RBP 5
444#define R_RSI 6
445#define R_RDI 7
446#define R_R8 8
447#define R_R9 9
448#define R_R10 10
449#define R_R11 11
450#define R_R12 12
451#define R_R13 13
452#define R_R14 14
453#define R_R15 15
454
sewardjd20c8852005-01-20 20:04:07 +0000455//.. #define R_AL (0+R_EAX)
456//.. #define R_AH (4+R_EAX)
sewardjecb94892005-01-21 14:26:37 +0000457
458/* This is the Intel register encoding -- segment regs. */
459#define R_ES 0
460#define R_CS 1
461#define R_SS 2
462#define R_DS 3
463#define R_FS 4
464#define R_GS 5
465
466
sewardjb3a04292005-01-21 20:33:44 +0000467/* Various simple conversions */
468
469static ULong extend_s_8to64 ( UChar x )
470{
471 return (ULong)((((Long)x) << 56) >> 56);
472}
473
474static ULong extend_s_16to64 ( UShort x )
475{
476 return (ULong)((((Long)x) << 48) >> 48);
477}
478
479static ULong extend_s_32to64 ( UInt x )
480{
481 return (ULong)((((Long)x) << 32) >> 32);
482}
483
sewardjdf0e0022005-01-25 15:48:43 +0000484/* Figure out whether the mod and rm parts of a modRM byte refer to a
485 register or memory. If so, the byte will have the form 11XXXYYY,
486 where YYY is the register number. */
sewardj5b470602005-02-27 13:10:48 +0000487inline
sewardjdf0e0022005-01-25 15:48:43 +0000488static Bool epartIsReg ( UChar mod_reg_rm )
489{
sewardj7a240552005-01-28 21:37:12 +0000490 return toBool(0xC0 == (mod_reg_rm & 0xC0));
sewardjdf0e0022005-01-25 15:48:43 +0000491}
492
sewardj901ed122005-02-27 13:25:31 +0000493/* Extract the 'g' field from a modRM byte. This only produces 3
494 bits, which is not a complete register number. You should avoid
495 this function if at all possible. */
496inline
497static Int gregLO3ofRM ( UChar mod_reg_rm )
sewardjdf0e0022005-01-25 15:48:43 +0000498{
499 return (Int)( (mod_reg_rm >> 3) & 7 );
500}
501
sewardj8711f662005-05-09 17:52:56 +0000502/* Ditto the 'e' field of a modRM byte. */
503inline
504static Int eregLO3ofRM ( UChar mod_reg_rm )
505{
506 return (Int)(mod_reg_rm & 0x7);
507}
508
sewardjdf0e0022005-01-25 15:48:43 +0000509/* Get a 8/16/32-bit unsigned value out of the insn stream. */
510
sewardj270def42005-07-03 01:03:01 +0000511static UChar getUChar ( Long delta )
sewardjdf0e0022005-01-25 15:48:43 +0000512{
sewardj8c332e22005-01-28 01:36:56 +0000513 UChar v = guest_code[delta+0];
514 return v;
sewardjdf0e0022005-01-25 15:48:43 +0000515}
516
sewardj47c2d4d2006-11-14 17:50:16 +0000517static UInt getUDisp16 ( Long delta )
518{
519 UInt v = guest_code[delta+1]; v <<= 8;
520 v |= guest_code[delta+0];
521 return v & 0xFFFF;
522}
523
sewardj270def42005-07-03 01:03:01 +0000524//.. static UInt getUDisp ( Int size, Long delta )
sewardjd20c8852005-01-20 20:04:07 +0000525//.. {
526//.. switch (size) {
527//.. case 4: return getUDisp32(delta);
528//.. case 2: return getUDisp16(delta);
529//.. case 1: return getUChar(delta);
530//.. default: vpanic("getUDisp(x86)");
531//.. }
532//.. return 0; /*notreached*/
533//.. }
sewardjb3a04292005-01-21 20:33:44 +0000534
535
536/* Get a byte value out of the insn stream and sign-extend to 64
537 bits. */
sewardj270def42005-07-03 01:03:01 +0000538static Long getSDisp8 ( Long delta )
sewardjb3a04292005-01-21 20:33:44 +0000539{
540 return extend_s_8to64( guest_code[delta] );
541}
542
sewardj5e525292005-01-28 15:13:10 +0000543/* Get a 16-bit value out of the insn stream and sign-extend to 64
544 bits. */
sewardj270def42005-07-03 01:03:01 +0000545static Long getSDisp16 ( Long delta )
sewardj5e525292005-01-28 15:13:10 +0000546{
sewardj118b23e2005-01-29 02:14:44 +0000547 UInt v = guest_code[delta+1]; v <<= 8;
sewardj5e525292005-01-28 15:13:10 +0000548 v |= guest_code[delta+0];
sewardj118b23e2005-01-29 02:14:44 +0000549 return extend_s_16to64( (UShort)v );
sewardj5e525292005-01-28 15:13:10 +0000550}
551
sewardjb3a04292005-01-21 20:33:44 +0000552/* Get a 32-bit value out of the insn stream and sign-extend to 64
553 bits. */
sewardj270def42005-07-03 01:03:01 +0000554static Long getSDisp32 ( Long delta )
sewardjb3a04292005-01-21 20:33:44 +0000555{
556 UInt v = guest_code[delta+3]; v <<= 8;
557 v |= guest_code[delta+2]; v <<= 8;
558 v |= guest_code[delta+1]; v <<= 8;
559 v |= guest_code[delta+0];
560 return extend_s_32to64( v );
561}
562
sewardj03b07cc2005-01-31 18:09:43 +0000563/* Get a 64-bit value out of the insn stream. */
sewardj270def42005-07-03 01:03:01 +0000564static Long getDisp64 ( Long delta )
sewardj03b07cc2005-01-31 18:09:43 +0000565{
sewardj7eaa7cf2005-01-31 18:55:22 +0000566 ULong v = 0;
sewardj03b07cc2005-01-31 18:09:43 +0000567 v |= guest_code[delta+7]; v <<= 8;
568 v |= guest_code[delta+6]; v <<= 8;
569 v |= guest_code[delta+5]; v <<= 8;
570 v |= guest_code[delta+4]; v <<= 8;
571 v |= guest_code[delta+3]; v <<= 8;
572 v |= guest_code[delta+2]; v <<= 8;
573 v |= guest_code[delta+1]; v <<= 8;
574 v |= guest_code[delta+0];
575 return v;
576}
577
sewardj3ca55a12005-01-27 16:06:23 +0000578/* Note: because AMD64 doesn't allow 64-bit literals, it is an error
579 if this is called with size==8. Should not happen. */
sewardj270def42005-07-03 01:03:01 +0000580static Long getSDisp ( Int size, Long delta )
sewardj3ca55a12005-01-27 16:06:23 +0000581{
582 switch (size) {
583 case 4: return getSDisp32(delta);
sewardj5e525292005-01-28 15:13:10 +0000584 case 2: return getSDisp16(delta);
sewardj3ca55a12005-01-27 16:06:23 +0000585 case 1: return getSDisp8(delta);
586 default: vpanic("getSDisp(amd64)");
587 }
588}
589
sewardj1389d4d2005-01-28 13:46:29 +0000590static ULong mkSizeMask ( Int sz )
sewardj3ca55a12005-01-27 16:06:23 +0000591{
592 switch (sz) {
sewardj1389d4d2005-01-28 13:46:29 +0000593 case 1: return 0x00000000000000FFULL;
594 case 2: return 0x000000000000FFFFULL;
595 case 4: return 0x00000000FFFFFFFFULL;
sewardj3ca55a12005-01-27 16:06:23 +0000596 case 8: return 0xFFFFFFFFFFFFFFFFULL;
597 default: vpanic("mkSzMask(amd64)");
598 }
599}
600
601static Int imin ( Int a, Int b )
602{
603 return (a < b) ? a : b;
604}
sewardjecb94892005-01-21 14:26:37 +0000605
sewardj5b470602005-02-27 13:10:48 +0000606static IRType szToITy ( Int n )
607{
608 switch (n) {
609 case 1: return Ity_I8;
610 case 2: return Ity_I16;
611 case 4: return Ity_I32;
612 case 8: return Ity_I64;
sewardjf53b7352005-04-06 20:01:56 +0000613 default: vex_printf("\nszToITy(%d)\n", n);
614 vpanic("szToITy(amd64)");
sewardj5b470602005-02-27 13:10:48 +0000615 }
616}
617
sewardjecb94892005-01-21 14:26:37 +0000618
619/*------------------------------------------------------------*/
620/*--- For dealing with prefixes. ---*/
621/*------------------------------------------------------------*/
622
623/* The idea is to pass around an int holding a bitmask summarising
624 info from the prefixes seen on the current instruction, including
625 info from the REX byte. This info is used in various places, but
626 most especially when making sense of register fields in
627 instructions.
628
629 The top 16 bits of the prefix are 0x3141, just as a hacky way
630 to ensure it really is a valid prefix.
sewardjdf0e0022005-01-25 15:48:43 +0000631
632 Things you can safely assume about a well-formed prefix:
633 * at most one segment-override bit (CS,DS,ES,FS,GS,SS) is set.
sewardj5b470602005-02-27 13:10:48 +0000634 * if REX is not present then REXW,REXR,REXX,REXB will read
635 as zero.
sewardjdf0e0022005-01-25 15:48:43 +0000636 * F2 and F3 will not both be 1.
sewardjecb94892005-01-21 14:26:37 +0000637*/
638
639typedef UInt Prefix;
640
sewardj3ca55a12005-01-27 16:06:23 +0000641#define PFX_ASO (1<<0) /* address-size override present (0x67) */
642#define PFX_66 (1<<1) /* operand-size override-to-16 present (0x66) */
643#define PFX_REX (1<<2) /* REX byte present (0x40 to 0x4F) */
644#define PFX_REXW (1<<3) /* REX W bit, if REX present, else 0 */
645#define PFX_REXR (1<<4) /* REX R bit, if REX present, else 0 */
646#define PFX_REXX (1<<5) /* REX X bit, if REX present, else 0 */
647#define PFX_REXB (1<<6) /* REX B bit, if REX present, else 0 */
648#define PFX_LOCK (1<<7) /* bus LOCK prefix present (0xF0) */
649#define PFX_F2 (1<<8) /* REP/REPE/REPZ prefix present (0xF2) */
650#define PFX_F3 (1<<9) /* REPNE/REPNZ prefix present (0xF3) */
651#define PFX_CS (1<<10) /* CS segment prefix present (0x2E) */
652#define PFX_DS (1<<11) /* DS segment prefix present (0x3E) */
653#define PFX_ES (1<<12) /* ES segment prefix present (0x26) */
654#define PFX_FS (1<<13) /* FS segment prefix present (0x64) */
655#define PFX_GS (1<<14) /* GS segment prefix present (0x65) */
656#define PFX_SS (1<<15) /* SS segment prefix present (0x36) */
657
658#define PFX_EMPTY 0x31410000
sewardjecb94892005-01-21 14:26:37 +0000659
sewardjb3a04292005-01-21 20:33:44 +0000660static Bool IS_VALID_PFX ( Prefix pfx ) {
sewardj7a240552005-01-28 21:37:12 +0000661 return toBool((pfx & 0xFFFF0000) == PFX_EMPTY);
sewardjecb94892005-01-21 14:26:37 +0000662}
663
sewardjb3a04292005-01-21 20:33:44 +0000664static Bool haveREX ( Prefix pfx ) {
sewardj7a240552005-01-28 21:37:12 +0000665 return toBool(pfx & PFX_REX);
sewardjecb94892005-01-21 14:26:37 +0000666}
667
sewardj5e525292005-01-28 15:13:10 +0000668static Int getRexW ( Prefix pfx ) {
669 return (pfx & PFX_REXW) ? 1 : 0;
670}
sewardj901ed122005-02-27 13:25:31 +0000671/* Apparently unused.
sewardjdf0e0022005-01-25 15:48:43 +0000672static Int getRexR ( Prefix pfx ) {
673 return (pfx & PFX_REXR) ? 1 : 0;
674}
sewardj901ed122005-02-27 13:25:31 +0000675*/
sewardj5b470602005-02-27 13:10:48 +0000676static Int getRexX ( Prefix pfx ) {
677 return (pfx & PFX_REXX) ? 1 : 0;
678}
sewardjdf0e0022005-01-25 15:48:43 +0000679static Int getRexB ( Prefix pfx ) {
680 return (pfx & PFX_REXB) ? 1 : 0;
681}
682
sewardj3ca55a12005-01-27 16:06:23 +0000683/* Check a prefix doesn't have F2 or F3 set in it, since usually that
684 completely changes what instruction it really is. */
685static Bool haveF2orF3 ( Prefix pfx ) {
sewardj7a240552005-01-28 21:37:12 +0000686 return toBool((pfx & (PFX_F2|PFX_F3)) > 0);
sewardj3ca55a12005-01-27 16:06:23 +0000687}
sewardj55dbb262005-01-28 16:36:51 +0000688static Bool haveF2 ( Prefix pfx ) {
sewardj7a240552005-01-28 21:37:12 +0000689 return toBool((pfx & PFX_F2) > 0);
sewardj55dbb262005-01-28 16:36:51 +0000690}
691static Bool haveF3 ( Prefix pfx ) {
sewardj7a240552005-01-28 21:37:12 +0000692 return toBool((pfx & PFX_F3) > 0);
sewardj55dbb262005-01-28 16:36:51 +0000693}
sewardj6359f812005-07-20 10:15:34 +0000694
sewardjc8b26352005-07-20 09:23:13 +0000695static Bool have66 ( Prefix pfx ) {
696 return toBool((pfx & PFX_66) > 0);
697}
sewardj6359f812005-07-20 10:15:34 +0000698static Bool haveASO ( Prefix pfx ) {
699 return toBool((pfx & PFX_ASO) > 0);
700}
sewardjecb94892005-01-21 14:26:37 +0000701
sewardj1001dc42005-02-21 08:25:55 +0000702/* Return True iff pfx has 66 set and F2 and F3 clear */
703static Bool have66noF2noF3 ( Prefix pfx )
704{
705 return
sewardj8d965312005-02-25 02:48:47 +0000706 toBool((pfx & (PFX_66|PFX_F2|PFX_F3)) == PFX_66);
sewardj1001dc42005-02-21 08:25:55 +0000707}
708
709/* Return True iff pfx has F2 set and 66 and F3 clear */
710static Bool haveF2no66noF3 ( Prefix pfx )
711{
712 return
sewardj8d965312005-02-25 02:48:47 +0000713 toBool((pfx & (PFX_66|PFX_F2|PFX_F3)) == PFX_F2);
714}
715
716/* Return True iff pfx has F3 set and 66 and F2 clear */
717static Bool haveF3no66noF2 ( Prefix pfx )
718{
719 return
720 toBool((pfx & (PFX_66|PFX_F2|PFX_F3)) == PFX_F3);
sewardj1001dc42005-02-21 08:25:55 +0000721}
722
723/* Return True iff pfx has 66, F2 and F3 clear */
724static Bool haveNo66noF2noF3 ( Prefix pfx )
725{
726 return
sewardj8d965312005-02-25 02:48:47 +0000727 toBool((pfx & (PFX_66|PFX_F2|PFX_F3)) == 0);
sewardj1001dc42005-02-21 08:25:55 +0000728}
729
sewardj8711f662005-05-09 17:52:56 +0000730/* Return True iff pfx has any of 66, F2 and F3 set */
731static Bool have66orF2orF3 ( Prefix pfx )
732{
sewardjca673ab2005-05-11 10:03:08 +0000733 return toBool( ! haveNo66noF2noF3(pfx) );
sewardj8711f662005-05-09 17:52:56 +0000734}
735
sewardj47c2d4d2006-11-14 17:50:16 +0000736/* Return True iff pfx has 66 or F2 set */
737static Bool have66orF2 ( Prefix pfx )
738{
739 return toBool((pfx & (PFX_66|PFX_F2)) > 0);
740}
741
sewardj1389d4d2005-01-28 13:46:29 +0000742/* Clear all the segment-override bits in a prefix. */
743static Prefix clearSegBits ( Prefix p )
744{
sewardj1001dc42005-02-21 08:25:55 +0000745 return
746 p & ~(PFX_CS | PFX_DS | PFX_ES | PFX_FS | PFX_GS | PFX_SS);
747}
748
sewardj1389d4d2005-01-28 13:46:29 +0000749
sewardjecb94892005-01-21 14:26:37 +0000750/*------------------------------------------------------------*/
sewardj5b470602005-02-27 13:10:48 +0000751/*--- For dealing with integer registers ---*/
sewardjecb94892005-01-21 14:26:37 +0000752/*------------------------------------------------------------*/
753
sewardj5b470602005-02-27 13:10:48 +0000754/* This is somewhat complex. The rules are:
755
756 For 64, 32 and 16 bit register references, the e or g fields in the
757 modrm bytes supply the low 3 bits of the register number. The
758 fourth (most-significant) bit of the register number is supplied by
759 the REX byte, if it is present; else that bit is taken to be zero.
760
761 The REX.R bit supplies the high bit corresponding to the g register
762 field, and the REX.B bit supplies the high bit corresponding to the
763 e register field (when the mod part of modrm indicates that modrm's
764 e component refers to a register and not to memory).
765
766 The REX.X bit supplies a high register bit for certain registers
767 in SIB address modes, and is generally rarely used.
768
769 For 8 bit register references, the presence of the REX byte itself
770 has significance. If there is no REX present, then the 3-bit
771 number extracted from the modrm e or g field is treated as an index
772 into the sequence %al %cl %dl %bl %ah %ch %dh %bh -- that is, the
773 old x86 encoding scheme.
774
775 But if there is a REX present, the register reference is
776 interpreted in the same way as for 64/32/16-bit references: a high
777 bit is extracted from REX, giving a 4-bit number, and the denoted
778 register is the lowest 8 bits of the 16 integer registers denoted
779 by the number. In particular, values 3 through 7 of this sequence
780 do not refer to %ah %ch %dh %bh but instead to the lowest 8 bits of
781 %rsp %rbp %rsi %rdi.
782
783 The REX.W bit has no bearing at all on register numbers. Instead
784 its presence indicates that the operand size is to be overridden
785 from its default value (32 bits) to 64 bits instead. This is in
786 the same fashion that an 0x66 prefix indicates the operand size is
787 to be overridden from 32 bits down to 16 bits. When both REX.W and
788 0x66 are present there is a conflict, and REX.W takes precedence.
789
790 Rather than try to handle this complexity using a single huge
791 function, several smaller ones are provided. The aim is to make it
792 as difficult as possible to screw up register decoding in a subtle
793 and hard-to-track-down way.
794
795 Because these routines fish around in the host's memory (that is,
796 in the guest state area) for sub-parts of guest registers, their
797 correctness depends on the host's endianness. So far these
798 routines only work for little-endian hosts. Those for which
799 endianness is important have assertions to ensure sanity.
800*/
sewardjecb94892005-01-21 14:26:37 +0000801
802
sewardj5b470602005-02-27 13:10:48 +0000803/* About the simplest question you can ask: where do the 64-bit
804 integer registers live (in the guest state) ? */
sewardjecb94892005-01-21 14:26:37 +0000805
sewardj3ca55a12005-01-27 16:06:23 +0000806static Int integerGuestReg64Offset ( UInt reg )
sewardjb3a04292005-01-21 20:33:44 +0000807{
808 switch (reg) {
809 case R_RAX: return OFFB_RAX;
810 case R_RCX: return OFFB_RCX;
811 case R_RDX: return OFFB_RDX;
812 case R_RBX: return OFFB_RBX;
813 case R_RSP: return OFFB_RSP;
814 case R_RBP: return OFFB_RBP;
815 case R_RSI: return OFFB_RSI;
816 case R_RDI: return OFFB_RDI;
817 case R_R8: return OFFB_R8;
818 case R_R9: return OFFB_R9;
819 case R_R10: return OFFB_R10;
820 case R_R11: return OFFB_R11;
821 case R_R12: return OFFB_R12;
822 case R_R13: return OFFB_R13;
823 case R_R14: return OFFB_R14;
824 case R_R15: return OFFB_R15;
825 default: vpanic("integerGuestReg64Offset(amd64)");
826 }
827}
828
829
sewardj5b470602005-02-27 13:10:48 +0000830/* Produce the name of an integer register, for printing purposes.
831 reg is a number in the range 0 .. 15 that has been generated from a
832 3-bit reg-field number and a REX extension bit. irregular denotes
833 the case where sz==1 and no REX byte is present. */
sewardjecb94892005-01-21 14:26:37 +0000834
835static
sewardj5b470602005-02-27 13:10:48 +0000836HChar* nameIReg ( Int sz, UInt reg, Bool irregular )
sewardjecb94892005-01-21 14:26:37 +0000837{
sewardjecb94892005-01-21 14:26:37 +0000838 static HChar* ireg64_names[16]
839 = { "%rax", "%rcx", "%rdx", "%rbx", "%rsp", "%rbp", "%rsi", "%rdi",
840 "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15" };
841 static HChar* ireg32_names[16]
842 = { "%eax", "%ecx", "%edx", "%ebx", "%esp", "%ebp", "%esi", "%edi",
843 "%r8d", "%r9d", "%r10d","%r11d","%r12d","%r13d","%r14d","%r15d" };
844 static HChar* ireg16_names[16]
845 = { "%ax", "%cx", "%dx", "%bx", "%sp", "%bp", "%si", "%di",
846 "%r8w", "%r9w", "%r10w","%r11w","%r12w","%r13w","%r14w","%r15w" };
847 static HChar* ireg8_names[16]
848 = { "%al", "%cl", "%dl", "%bl", "%spl", "%bpl", "%sil", "%dil",
849 "%r8b", "%r9b", "%r10b","%r11b","%r12b","%r13b","%r14b","%r15b" };
sewardj5b470602005-02-27 13:10:48 +0000850 static HChar* ireg8_irregular[8]
sewardjecb94892005-01-21 14:26:37 +0000851 = { "%al", "%cl", "%dl", "%bl", "%ah", "%ch", "%dh", "%bh" };
852
sewardj5b470602005-02-27 13:10:48 +0000853 vassert(reg < 16);
854 if (sz == 1) {
855 if (irregular)
856 vassert(reg < 8);
857 } else {
858 vassert(irregular == False);
859 }
sewardjecb94892005-01-21 14:26:37 +0000860
861 switch (sz) {
sewardj5b470602005-02-27 13:10:48 +0000862 case 8: return ireg64_names[reg];
863 case 4: return ireg32_names[reg];
864 case 2: return ireg16_names[reg];
865 case 1: if (irregular) {
866 return ireg8_irregular[reg];
867 } else {
868 return ireg8_names[reg];
869 }
870 default: vpanic("nameIReg(amd64)");
sewardjecb94892005-01-21 14:26:37 +0000871 }
sewardjecb94892005-01-21 14:26:37 +0000872}
873
sewardj5b470602005-02-27 13:10:48 +0000874/* Using the same argument conventions as nameIReg, produce the
875 guest state offset of an integer register. */
sewardjb3a04292005-01-21 20:33:44 +0000876
sewardjecb94892005-01-21 14:26:37 +0000877static
sewardj5b470602005-02-27 13:10:48 +0000878Int offsetIReg ( Int sz, UInt reg, Bool irregular )
sewardjecb94892005-01-21 14:26:37 +0000879{
sewardj5b470602005-02-27 13:10:48 +0000880 vassert(reg < 16);
881 if (sz == 1) {
882 if (irregular)
883 vassert(reg < 8);
884 } else {
885 vassert(irregular == False);
sewardjecb94892005-01-21 14:26:37 +0000886 }
sewardj5b470602005-02-27 13:10:48 +0000887
888 /* Deal with irregular case -- sz==1 and no REX present */
889 if (sz == 1 && irregular) {
890 switch (reg) {
891 case R_RSP: return 1+ OFFB_RAX;
892 case R_RBP: return 1+ OFFB_RCX;
893 case R_RSI: return 1+ OFFB_RDX;
894 case R_RDI: return 1+ OFFB_RBX;
895 default: break; /* use the normal case */
896 }
sewardjecb94892005-01-21 14:26:37 +0000897 }
sewardj5b470602005-02-27 13:10:48 +0000898
899 /* Normal case */
900 return integerGuestReg64Offset(reg);
sewardjecb94892005-01-21 14:26:37 +0000901}
902
903
sewardj5b470602005-02-27 13:10:48 +0000904/* Read the %CL register :: Ity_I8, for shift/rotate operations. */
905
906static IRExpr* getIRegCL ( void )
907{
908 vassert(!host_is_bigendian);
909 return IRExpr_Get( OFFB_RCX, Ity_I8 );
910}
911
912
913/* Write to the %AH register. */
914
915static void putIRegAH ( IRExpr* e )
916{
917 vassert(!host_is_bigendian);
sewardjdd40fdf2006-12-24 02:20:24 +0000918 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I8);
sewardj5b470602005-02-27 13:10:48 +0000919 stmt( IRStmt_Put( OFFB_RAX+1, e ) );
920}
921
922
923/* Read/write various widths of %RAX, as it has various
924 special-purpose uses. */
925
926static HChar* nameIRegRAX ( Int sz )
927{
928 switch (sz) {
929 case 1: return "%al";
930 case 2: return "%ax";
931 case 4: return "%eax";
932 case 8: return "%rax";
933 default: vpanic("nameIRegRAX(amd64)");
934 }
935}
936
937static IRExpr* getIRegRAX ( Int sz )
938{
939 vassert(!host_is_bigendian);
940 switch (sz) {
941 case 1: return IRExpr_Get( OFFB_RAX, Ity_I8 );
942 case 2: return IRExpr_Get( OFFB_RAX, Ity_I16 );
943 case 4: return IRExpr_Get( OFFB_RAX, Ity_I32 );
944 case 8: return IRExpr_Get( OFFB_RAX, Ity_I64 );
945 default: vpanic("getIRegRAX(amd64)");
946 }
947}
948
949static void putIRegRAX ( Int sz, IRExpr* e )
950{
sewardjdd40fdf2006-12-24 02:20:24 +0000951 IRType ty = typeOfIRExpr(irsb->tyenv, e);
sewardj5b470602005-02-27 13:10:48 +0000952 vassert(!host_is_bigendian);
953 switch (sz) {
954 case 8: vassert(ty == Ity_I64);
955 stmt( IRStmt_Put( OFFB_RAX, e ));
956 break;
957 case 4: vassert(ty == Ity_I32);
958 stmt( IRStmt_Put( OFFB_RAX, unop(Iop_32Uto64,e) ));
959 break;
960 case 2: vassert(ty == Ity_I16);
961 stmt( IRStmt_Put( OFFB_RAX, e ));
962 break;
963 case 1: vassert(ty == Ity_I8);
964 stmt( IRStmt_Put( OFFB_RAX, e ));
965 break;
966 default: vpanic("putIRegRAX(amd64)");
967 }
968}
969
970
971/* Read/write various widths of %RDX, as it has various
972 special-purpose uses. */
973
974static IRExpr* getIRegRDX ( Int sz )
975{
976 vassert(!host_is_bigendian);
977 switch (sz) {
978 case 1: return IRExpr_Get( OFFB_RDX, Ity_I8 );
979 case 2: return IRExpr_Get( OFFB_RDX, Ity_I16 );
980 case 4: return IRExpr_Get( OFFB_RDX, Ity_I32 );
981 case 8: return IRExpr_Get( OFFB_RDX, Ity_I64 );
982 default: vpanic("getIRegRDX(amd64)");
983 }
984}
985
986static void putIRegRDX ( Int sz, IRExpr* e )
987{
988 vassert(!host_is_bigendian);
sewardjdd40fdf2006-12-24 02:20:24 +0000989 vassert(typeOfIRExpr(irsb->tyenv, e) == szToITy(sz));
sewardj5b470602005-02-27 13:10:48 +0000990 switch (sz) {
991 case 8: stmt( IRStmt_Put( OFFB_RDX, e ));
992 break;
993 case 4: stmt( IRStmt_Put( OFFB_RDX, unop(Iop_32Uto64,e) ));
994 break;
995 case 2: stmt( IRStmt_Put( OFFB_RDX, e ));
996 break;
997 case 1: stmt( IRStmt_Put( OFFB_RDX, e ));
998 break;
999 default: vpanic("putIRegRDX(amd64)");
1000 }
1001}
1002
1003
1004/* Simplistic functions to deal with the integer registers as a
1005 straightforward bank of 16 64-bit regs. */
sewardjb3a04292005-01-21 20:33:44 +00001006
1007static IRExpr* getIReg64 ( UInt regno )
1008{
1009 return IRExpr_Get( integerGuestReg64Offset(regno),
1010 Ity_I64 );
1011}
1012
sewardj2f959cc2005-01-26 01:19:35 +00001013static void putIReg64 ( UInt regno, IRExpr* e )
1014{
sewardjdd40fdf2006-12-24 02:20:24 +00001015 vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_I64);
sewardj2f959cc2005-01-26 01:19:35 +00001016 stmt( IRStmt_Put( integerGuestReg64Offset(regno), e ) );
1017}
1018
sewardjb3a04292005-01-21 20:33:44 +00001019static HChar* nameIReg64 ( UInt regno )
1020{
sewardj5b470602005-02-27 13:10:48 +00001021 return nameIReg( 8, regno, False );
sewardjb3a04292005-01-21 20:33:44 +00001022}
sewardj5b470602005-02-27 13:10:48 +00001023
1024
1025/* Simplistic functions to deal with the lower halves of integer
1026 registers as a straightforward bank of 16 32-bit regs. */
1027
1028static IRExpr* getIReg32 ( UInt regno )
1029{
1030 vassert(!host_is_bigendian);
1031 return IRExpr_Get( integerGuestReg64Offset(regno),
1032 Ity_I32 );
1033}
1034
1035static void putIReg32 ( UInt regno, IRExpr* e )
1036{
sewardjdd40fdf2006-12-24 02:20:24 +00001037 vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_I32);
sewardj5b470602005-02-27 13:10:48 +00001038 stmt( IRStmt_Put( integerGuestReg64Offset(regno),
1039 unop(Iop_32Uto64,e) ) );
1040}
1041
1042static HChar* nameIReg32 ( UInt regno )
1043{
1044 return nameIReg( 4, regno, False );
1045}
1046
1047
sewardja7ba8c42005-05-10 20:08:34 +00001048/* Simplistic functions to deal with the lower quarters of integer
1049 registers as a straightforward bank of 16 16-bit regs. */
1050
1051static IRExpr* getIReg16 ( UInt regno )
1052{
1053 vassert(!host_is_bigendian);
1054 return IRExpr_Get( integerGuestReg64Offset(regno),
1055 Ity_I16 );
1056}
1057
1058static HChar* nameIReg16 ( UInt regno )
1059{
1060 return nameIReg( 2, regno, False );
1061}
1062
1063
sewardj5b470602005-02-27 13:10:48 +00001064/* Sometimes what we know is a 3-bit register number, a REX byte, and
1065 which field of the REX byte is to be used to extend to a 4-bit
1066 number. These functions cater for that situation.
1067*/
1068static IRExpr* getIReg64rexX ( Prefix pfx, UInt lo3bits )
1069{
1070 vassert(lo3bits < 8);
1071 vassert(IS_VALID_PFX(pfx));
1072 return getIReg64( lo3bits | (getRexX(pfx) << 3) );
1073}
1074
1075static HChar* nameIReg64rexX ( Prefix pfx, UInt lo3bits )
1076{
1077 vassert(lo3bits < 8);
1078 vassert(IS_VALID_PFX(pfx));
1079 return nameIReg( 8, lo3bits | (getRexX(pfx) << 3), False );
1080}
1081
1082static HChar* nameIRegRexB ( Int sz, Prefix pfx, UInt lo3bits )
1083{
1084 vassert(lo3bits < 8);
1085 vassert(IS_VALID_PFX(pfx));
1086 vassert(sz == 8 || sz == 4 || sz == 2 || sz == 1);
1087 return nameIReg( sz, lo3bits | (getRexB(pfx) << 3),
sewardj397f88b2005-02-27 13:39:25 +00001088 toBool(sz==1 && !haveREX(pfx)) );
sewardj5b470602005-02-27 13:10:48 +00001089}
1090
1091static IRExpr* getIRegRexB ( Int sz, Prefix pfx, UInt lo3bits )
1092{
1093 vassert(lo3bits < 8);
1094 vassert(IS_VALID_PFX(pfx));
1095 vassert(sz == 8 || sz == 4 || sz == 2 || sz == 1);
1096 return IRExpr_Get(
1097 offsetIReg( sz, lo3bits | (getRexB(pfx) << 3),
sewardj397f88b2005-02-27 13:39:25 +00001098 toBool(sz==1 && !haveREX(pfx)) ),
sewardj5b470602005-02-27 13:10:48 +00001099 szToITy(sz)
1100 );
1101}
1102
1103static void putIRegRexB ( Int sz, Prefix pfx, UInt lo3bits, IRExpr* e )
1104{
1105 vassert(lo3bits < 8);
1106 vassert(IS_VALID_PFX(pfx));
sewardj98e9f342005-07-23 12:07:37 +00001107 vassert(sz == 8 || sz == 4 || sz == 2 || sz == 1);
sewardjdd40fdf2006-12-24 02:20:24 +00001108 vassert(typeOfIRExpr(irsb->tyenv, e) == szToITy(sz));
sewardj5b470602005-02-27 13:10:48 +00001109 stmt( IRStmt_Put(
1110 offsetIReg( sz, lo3bits | (getRexB(pfx) << 3),
sewardj397f88b2005-02-27 13:39:25 +00001111 toBool(sz==1 && !haveREX(pfx)) ),
sewardj5b470602005-02-27 13:10:48 +00001112 sz==4 ? unop(Iop_32Uto64,e) : e
1113 ));
1114}
1115
1116
1117/* Functions for getting register numbers from modrm bytes and REX
1118 when we don't have to consider the complexities of integer subreg
1119 accesses.
1120*/
1121/* Extract the g reg field from a modRM byte, and augment it using the
1122 REX.R bit from the supplied REX byte. The R bit usually is
1123 associated with the g register field.
1124*/
1125static UInt gregOfRexRM ( Prefix pfx, UChar mod_reg_rm )
1126{
1127 Int reg = (Int)( (mod_reg_rm >> 3) & 7 );
1128 reg += (pfx & PFX_REXR) ? 8 : 0;
1129 return reg;
1130}
1131
1132/* Extract the e reg field from a modRM byte, and augment it using the
1133 REX.B bit from the supplied REX byte. The B bit usually is
1134 associated with the e register field (when modrm indicates e is a
1135 register, that is).
1136*/
1137static UInt eregOfRexRM ( Prefix pfx, UChar mod_reg_rm )
1138{
1139 Int rm;
1140 vassert(epartIsReg(mod_reg_rm));
1141 rm = (Int)(mod_reg_rm & 0x7);
1142 rm += (pfx & PFX_REXB) ? 8 : 0;
1143 return rm;
1144}
1145
1146
1147/* General functions for dealing with integer register access. */
1148
1149/* Produce the guest state offset for a reference to the 'g' register
1150 field in a modrm byte, taking into account REX (or its absence),
1151 and the size of the access.
1152*/
1153static UInt offsetIRegG ( Int sz, Prefix pfx, UChar mod_reg_rm )
1154{
1155 UInt reg;
1156 vassert(!host_is_bigendian);
1157 vassert(IS_VALID_PFX(pfx));
1158 vassert(sz == 8 || sz == 4 || sz == 2 || sz == 1);
1159 reg = gregOfRexRM( pfx, mod_reg_rm );
sewardj397f88b2005-02-27 13:39:25 +00001160 return offsetIReg( sz, reg, toBool(sz == 1 && !haveREX(pfx)) );
sewardj5b470602005-02-27 13:10:48 +00001161}
1162
1163static
1164IRExpr* getIRegG ( Int sz, Prefix pfx, UChar mod_reg_rm )
1165{
1166 return IRExpr_Get( offsetIRegG( sz, pfx, mod_reg_rm ),
1167 szToITy(sz) );
1168}
1169
1170static
1171void putIRegG ( Int sz, Prefix pfx, UChar mod_reg_rm, IRExpr* e )
1172{
sewardjdd40fdf2006-12-24 02:20:24 +00001173 vassert(typeOfIRExpr(irsb->tyenv,e) == szToITy(sz));
sewardj5b470602005-02-27 13:10:48 +00001174 if (sz == 4) {
1175 e = unop(Iop_32Uto64,e);
1176 }
1177 stmt( IRStmt_Put( offsetIRegG( sz, pfx, mod_reg_rm ), e ) );
1178}
1179
1180static
1181HChar* nameIRegG ( Int sz, Prefix pfx, UChar mod_reg_rm )
1182{
1183 return nameIReg( sz, gregOfRexRM(pfx,mod_reg_rm),
sewardj397f88b2005-02-27 13:39:25 +00001184 toBool(sz==1 && !haveREX(pfx)) );
sewardj5b470602005-02-27 13:10:48 +00001185}
1186
1187
1188/* Produce the guest state offset for a reference to the 'e' register
1189 field in a modrm byte, taking into account REX (or its absence),
1190 and the size of the access. eregOfRexRM will assert if mod_reg_rm
1191 denotes a memory access rather than a register access.
1192*/
1193static UInt offsetIRegE ( Int sz, Prefix pfx, UChar mod_reg_rm )
1194{
1195 UInt reg;
1196 vassert(!host_is_bigendian);
1197 vassert(IS_VALID_PFX(pfx));
1198 vassert(sz == 8 || sz == 4 || sz == 2 || sz == 1);
1199 reg = eregOfRexRM( pfx, mod_reg_rm );
sewardj397f88b2005-02-27 13:39:25 +00001200 return offsetIReg( sz, reg, toBool(sz == 1 && !haveREX(pfx)) );
sewardj5b470602005-02-27 13:10:48 +00001201}
1202
1203static
1204IRExpr* getIRegE ( Int sz, Prefix pfx, UChar mod_reg_rm )
1205{
1206 return IRExpr_Get( offsetIRegE( sz, pfx, mod_reg_rm ),
1207 szToITy(sz) );
1208}
1209
1210static
1211void putIRegE ( Int sz, Prefix pfx, UChar mod_reg_rm, IRExpr* e )
1212{
sewardjdd40fdf2006-12-24 02:20:24 +00001213 vassert(typeOfIRExpr(irsb->tyenv,e) == szToITy(sz));
sewardj5b470602005-02-27 13:10:48 +00001214 if (sz == 4) {
1215 e = unop(Iop_32Uto64,e);
1216 }
1217 stmt( IRStmt_Put( offsetIRegE( sz, pfx, mod_reg_rm ), e ) );
1218}
1219
1220static
1221HChar* nameIRegE ( Int sz, Prefix pfx, UChar mod_reg_rm )
1222{
1223 return nameIReg( sz, eregOfRexRM(pfx,mod_reg_rm),
sewardj397f88b2005-02-27 13:39:25 +00001224 toBool(sz==1 && !haveREX(pfx)) );
sewardj5b470602005-02-27 13:10:48 +00001225}
1226
1227
1228/*------------------------------------------------------------*/
1229/*--- For dealing with XMM registers ---*/
1230/*------------------------------------------------------------*/
sewardjecb94892005-01-21 14:26:37 +00001231
sewardjd20c8852005-01-20 20:04:07 +00001232//.. static Int segmentGuestRegOffset ( UInt sreg )
1233//.. {
1234//.. switch (sreg) {
1235//.. case R_ES: return OFFB_ES;
1236//.. case R_CS: return OFFB_CS;
1237//.. case R_SS: return OFFB_SS;
1238//.. case R_DS: return OFFB_DS;
1239//.. case R_FS: return OFFB_FS;
1240//.. case R_GS: return OFFB_GS;
1241//.. default: vpanic("segmentGuestRegOffset(x86)");
1242//.. }
1243//.. }
sewardj1001dc42005-02-21 08:25:55 +00001244
1245static Int xmmGuestRegOffset ( UInt xmmreg )
1246{
1247 switch (xmmreg) {
1248 case 0: return OFFB_XMM0;
1249 case 1: return OFFB_XMM1;
1250 case 2: return OFFB_XMM2;
1251 case 3: return OFFB_XMM3;
1252 case 4: return OFFB_XMM4;
1253 case 5: return OFFB_XMM5;
1254 case 6: return OFFB_XMM6;
1255 case 7: return OFFB_XMM7;
1256 case 8: return OFFB_XMM8;
1257 case 9: return OFFB_XMM9;
1258 case 10: return OFFB_XMM10;
1259 case 11: return OFFB_XMM11;
1260 case 12: return OFFB_XMM12;
1261 case 13: return OFFB_XMM13;
1262 case 14: return OFFB_XMM14;
1263 case 15: return OFFB_XMM15;
1264 default: vpanic("xmmGuestRegOffset(amd64)");
1265 }
1266}
1267
sewardj97628592005-05-10 22:42:54 +00001268/* Lanes of vector registers are always numbered from zero being the
1269 least significant lane (rightmost in the register). */
1270
1271static Int xmmGuestRegLane16offset ( UInt xmmreg, Int laneno )
1272{
1273 /* Correct for little-endian host only. */
1274 vassert(!host_is_bigendian);
1275 vassert(laneno >= 0 && laneno < 8);
1276 return xmmGuestRegOffset( xmmreg ) + 2 * laneno;
1277}
sewardj8d965312005-02-25 02:48:47 +00001278
1279static Int xmmGuestRegLane32offset ( UInt xmmreg, Int laneno )
1280{
1281 /* Correct for little-endian host only. */
1282 vassert(!host_is_bigendian);
1283 vassert(laneno >= 0 && laneno < 4);
1284 return xmmGuestRegOffset( xmmreg ) + 4 * laneno;
1285}
sewardj1001dc42005-02-21 08:25:55 +00001286
1287static Int xmmGuestRegLane64offset ( UInt xmmreg, Int laneno )
1288{
1289 /* Correct for little-endian host only. */
1290 vassert(!host_is_bigendian);
1291 vassert(laneno >= 0 && laneno < 2);
1292 return xmmGuestRegOffset( xmmreg ) + 8 * laneno;
1293}
1294
sewardjd20c8852005-01-20 20:04:07 +00001295//.. static IRExpr* getSReg ( UInt sreg )
1296//.. {
1297//.. return IRExpr_Get( segmentGuestRegOffset(sreg), Ity_I16 );
1298//.. }
1299//..
1300//.. static void putSReg ( UInt sreg, IRExpr* e )
1301//.. {
sewardjdd40fdf2006-12-24 02:20:24 +00001302//.. vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_I16);
sewardjd20c8852005-01-20 20:04:07 +00001303//.. stmt( IRStmt_Put( segmentGuestRegOffset(sreg), e ) );
1304//.. }
sewardj1001dc42005-02-21 08:25:55 +00001305
1306static IRExpr* getXMMReg ( UInt xmmreg )
1307{
1308 return IRExpr_Get( xmmGuestRegOffset(xmmreg), Ity_V128 );
1309}
1310
1311static IRExpr* getXMMRegLane64 ( UInt xmmreg, Int laneno )
1312{
1313 return IRExpr_Get( xmmGuestRegLane64offset(xmmreg,laneno), Ity_I64 );
1314}
1315
sewardj18303862005-02-21 12:36:54 +00001316static IRExpr* getXMMRegLane64F ( UInt xmmreg, Int laneno )
1317{
1318 return IRExpr_Get( xmmGuestRegLane64offset(xmmreg,laneno), Ity_F64 );
1319}
1320
sewardj8d965312005-02-25 02:48:47 +00001321static IRExpr* getXMMRegLane32 ( UInt xmmreg, Int laneno )
1322{
1323 return IRExpr_Get( xmmGuestRegLane32offset(xmmreg,laneno), Ity_I32 );
1324}
1325
sewardjc49ce232005-02-25 13:03:03 +00001326static IRExpr* getXMMRegLane32F ( UInt xmmreg, Int laneno )
1327{
1328 return IRExpr_Get( xmmGuestRegLane32offset(xmmreg,laneno), Ity_F32 );
1329}
sewardj1001dc42005-02-21 08:25:55 +00001330
1331static void putXMMReg ( UInt xmmreg, IRExpr* e )
1332{
sewardjdd40fdf2006-12-24 02:20:24 +00001333 vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_V128);
sewardj1001dc42005-02-21 08:25:55 +00001334 stmt( IRStmt_Put( xmmGuestRegOffset(xmmreg), e ) );
1335}
1336
1337static void putXMMRegLane64 ( UInt xmmreg, Int laneno, IRExpr* e )
1338{
sewardjdd40fdf2006-12-24 02:20:24 +00001339 vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_I64);
sewardj1001dc42005-02-21 08:25:55 +00001340 stmt( IRStmt_Put( xmmGuestRegLane64offset(xmmreg,laneno), e ) );
1341}
1342
sewardj1a01e652005-02-23 11:39:21 +00001343static void putXMMRegLane64F ( UInt xmmreg, Int laneno, IRExpr* e )
1344{
sewardjdd40fdf2006-12-24 02:20:24 +00001345 vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_F64);
sewardj1a01e652005-02-23 11:39:21 +00001346 stmt( IRStmt_Put( xmmGuestRegLane64offset(xmmreg,laneno), e ) );
1347}
1348
sewardj8d965312005-02-25 02:48:47 +00001349static void putXMMRegLane32F ( UInt xmmreg, Int laneno, IRExpr* e )
1350{
sewardjdd40fdf2006-12-24 02:20:24 +00001351 vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_F32);
sewardj8d965312005-02-25 02:48:47 +00001352 stmt( IRStmt_Put( xmmGuestRegLane32offset(xmmreg,laneno), e ) );
1353}
1354
1355static void putXMMRegLane32 ( UInt xmmreg, Int laneno, IRExpr* e )
1356{
sewardjdd40fdf2006-12-24 02:20:24 +00001357 vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_I32);
sewardj8d965312005-02-25 02:48:47 +00001358 stmt( IRStmt_Put( xmmGuestRegLane32offset(xmmreg,laneno), e ) );
1359}
1360
sewardj97628592005-05-10 22:42:54 +00001361static void putXMMRegLane16 ( UInt xmmreg, Int laneno, IRExpr* e )
1362{
sewardjdd40fdf2006-12-24 02:20:24 +00001363 vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_I16);
sewardj97628592005-05-10 22:42:54 +00001364 stmt( IRStmt_Put( xmmGuestRegLane16offset(xmmreg,laneno), e ) );
1365}
sewardj3ca55a12005-01-27 16:06:23 +00001366
sewardj1001dc42005-02-21 08:25:55 +00001367static IRExpr* mkV128 ( UShort mask )
1368{
1369 return IRExpr_Const(IRConst_V128(mask));
1370}
sewardjdf0e0022005-01-25 15:48:43 +00001371
sewardje8f65252005-08-23 23:44:35 +00001372static IRExpr* mkAnd1 ( IRExpr* x, IRExpr* y )
1373{
sewardjdd40fdf2006-12-24 02:20:24 +00001374 vassert(typeOfIRExpr(irsb->tyenv,x) == Ity_I1);
1375 vassert(typeOfIRExpr(irsb->tyenv,y) == Ity_I1);
sewardje8f65252005-08-23 23:44:35 +00001376 return unop(Iop_64to1,
1377 binop(Iop_And64,
1378 unop(Iop_1Uto64,x),
1379 unop(Iop_1Uto64,y)));
1380}
1381
sewardj5b470602005-02-27 13:10:48 +00001382
sewardj118b23e2005-01-29 02:14:44 +00001383/*------------------------------------------------------------*/
sewardje8f65252005-08-23 23:44:35 +00001384/*--- Helpers for %rflags. ---*/
sewardj118b23e2005-01-29 02:14:44 +00001385/*------------------------------------------------------------*/
1386
1387/* -------------- Evaluating the flags-thunk. -------------- */
1388
1389/* Build IR to calculate all the eflags from stored
1390 CC_OP/CC_DEP1/CC_DEP2/CC_NDEP. Returns an expression ::
1391 Ity_I64. */
1392static IRExpr* mk_amd64g_calculate_rflags_all ( void )
1393{
1394 IRExpr** args
1395 = mkIRExprVec_4( IRExpr_Get(OFFB_CC_OP, Ity_I64),
1396 IRExpr_Get(OFFB_CC_DEP1, Ity_I64),
1397 IRExpr_Get(OFFB_CC_DEP2, Ity_I64),
1398 IRExpr_Get(OFFB_CC_NDEP, Ity_I64) );
1399 IRExpr* call
1400 = mkIRExprCCall(
1401 Ity_I64,
1402 0/*regparm*/,
1403 "amd64g_calculate_rflags_all", &amd64g_calculate_rflags_all,
1404 args
1405 );
1406 /* Exclude OP and NDEP from definedness checking. We're only
1407 interested in DEP1 and DEP2. */
1408 call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<3);
1409 return call;
1410}
sewardj3ca55a12005-01-27 16:06:23 +00001411
1412/* Build IR to calculate some particular condition from stored
1413 CC_OP/CC_DEP1/CC_DEP2/CC_NDEP. Returns an expression ::
1414 Ity_Bit. */
1415static IRExpr* mk_amd64g_calculate_condition ( AMD64Condcode cond )
1416{
1417 IRExpr** args
1418 = mkIRExprVec_5( mkU64(cond),
1419 IRExpr_Get(OFFB_CC_OP, Ity_I64),
1420 IRExpr_Get(OFFB_CC_DEP1, Ity_I64),
1421 IRExpr_Get(OFFB_CC_DEP2, Ity_I64),
1422 IRExpr_Get(OFFB_CC_NDEP, Ity_I64) );
1423 IRExpr* call
1424 = mkIRExprCCall(
1425 Ity_I64,
1426 0/*regparm*/,
1427 "amd64g_calculate_condition", &amd64g_calculate_condition,
1428 args
1429 );
1430 /* Exclude the requested condition, OP and NDEP from definedness
1431 checking. We're only interested in DEP1 and DEP2. */
1432 call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<1) | (1<<4);
sewardje58967e2005-04-27 11:50:56 +00001433 return unop(Iop_64to1, call);
sewardj3ca55a12005-01-27 16:06:23 +00001434}
sewardjdf0e0022005-01-25 15:48:43 +00001435
1436/* Build IR to calculate just the carry flag from stored
1437 CC_OP/CC_DEP1/CC_DEP2/CC_NDEP. Returns an expression :: Ity_I64. */
1438static IRExpr* mk_amd64g_calculate_rflags_c ( void )
1439{
1440 IRExpr** args
1441 = mkIRExprVec_4( IRExpr_Get(OFFB_CC_OP, Ity_I64),
1442 IRExpr_Get(OFFB_CC_DEP1, Ity_I64),
1443 IRExpr_Get(OFFB_CC_DEP2, Ity_I64),
1444 IRExpr_Get(OFFB_CC_NDEP, Ity_I64) );
1445 IRExpr* call
1446 = mkIRExprCCall(
1447 Ity_I64,
1448 0/*regparm*/,
1449 "amd64g_calculate_rflags_c", &amd64g_calculate_rflags_c,
1450 args
1451 );
1452 /* Exclude OP and NDEP from definedness checking. We're only
1453 interested in DEP1 and DEP2. */
1454 call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<3);
1455 return call;
1456}
1457
1458
1459/* -------------- Building the flags-thunk. -------------- */
1460
1461/* The machinery in this section builds the flag-thunk following a
1462 flag-setting operation. Hence the various setFlags_* functions.
1463*/
1464
1465static Bool isAddSub ( IROp op8 )
1466{
sewardj7a240552005-01-28 21:37:12 +00001467 return toBool(op8 == Iop_Add8 || op8 == Iop_Sub8);
sewardjdf0e0022005-01-25 15:48:43 +00001468}
1469
sewardj3ca55a12005-01-27 16:06:23 +00001470static Bool isLogic ( IROp op8 )
1471{
sewardj7a240552005-01-28 21:37:12 +00001472 return toBool(op8 == Iop_And8 || op8 == Iop_Or8 || op8 == Iop_Xor8);
sewardj3ca55a12005-01-27 16:06:23 +00001473}
sewardjdf0e0022005-01-25 15:48:43 +00001474
1475/* U-widen 8/16/32/64 bit int expr to 64. */
1476static IRExpr* widenUto64 ( IRExpr* e )
1477{
sewardjdd40fdf2006-12-24 02:20:24 +00001478 switch (typeOfIRExpr(irsb->tyenv,e)) {
sewardjdf0e0022005-01-25 15:48:43 +00001479 case Ity_I64: return e;
1480 case Ity_I32: return unop(Iop_32Uto64, e);
sewardje58967e2005-04-27 11:50:56 +00001481 case Ity_I16: return unop(Iop_16Uto64, e);
1482 case Ity_I8: return unop(Iop_8Uto64, e);
sewardj118b23e2005-01-29 02:14:44 +00001483 default: vpanic("widenUto64");
sewardjdf0e0022005-01-25 15:48:43 +00001484 }
1485}
1486
sewardj118b23e2005-01-29 02:14:44 +00001487/* S-widen 8/16/32/64 bit int expr to 32. */
1488static IRExpr* widenSto64 ( IRExpr* e )
1489{
sewardjdd40fdf2006-12-24 02:20:24 +00001490 switch (typeOfIRExpr(irsb->tyenv,e)) {
sewardj118b23e2005-01-29 02:14:44 +00001491 case Ity_I64: return e;
1492 case Ity_I32: return unop(Iop_32Sto64, e);
sewardje58967e2005-04-27 11:50:56 +00001493 case Ity_I16: return unop(Iop_16Sto64, e);
1494 case Ity_I8: return unop(Iop_8Sto64, e);
sewardj118b23e2005-01-29 02:14:44 +00001495 default: vpanic("widenSto64");
1496 }
1497}
sewardjdf0e0022005-01-25 15:48:43 +00001498
1499/* Narrow 8/16/32/64 bit int expr to 8/16/32/64. Clearly only some
1500 of these combinations make sense. */
1501static IRExpr* narrowTo ( IRType dst_ty, IRExpr* e )
1502{
sewardjdd40fdf2006-12-24 02:20:24 +00001503 IRType src_ty = typeOfIRExpr(irsb->tyenv,e);
sewardjdf0e0022005-01-25 15:48:43 +00001504 if (src_ty == dst_ty)
1505 return e;
1506 if (src_ty == Ity_I32 && dst_ty == Ity_I16)
1507 return unop(Iop_32to16, e);
1508 if (src_ty == Ity_I32 && dst_ty == Ity_I8)
1509 return unop(Iop_32to8, e);
sewardj118b23e2005-01-29 02:14:44 +00001510 if (src_ty == Ity_I64 && dst_ty == Ity_I32)
1511 return unop(Iop_64to32, e);
1512 if (src_ty == Ity_I64 && dst_ty == Ity_I16)
sewardje58967e2005-04-27 11:50:56 +00001513 return unop(Iop_64to16, e);
sewardj03b07cc2005-01-31 18:09:43 +00001514 if (src_ty == Ity_I64 && dst_ty == Ity_I8)
sewardje58967e2005-04-27 11:50:56 +00001515 return unop(Iop_64to8, e);
sewardjdf0e0022005-01-25 15:48:43 +00001516
1517 vex_printf("\nsrc, dst tys are: ");
1518 ppIRType(src_ty);
1519 vex_printf(", ");
1520 ppIRType(dst_ty);
1521 vex_printf("\n");
1522 vpanic("narrowTo(amd64)");
1523}
1524
1525
1526/* Set the flags thunk OP, DEP1 and DEP2 fields. The supplied op is
1527 auto-sized up to the real op. */
1528
1529static
1530void setFlags_DEP1_DEP2 ( IROp op8, IRTemp dep1, IRTemp dep2, IRType ty )
1531{
1532 Int ccOp = 0;
1533 switch (ty) {
1534 case Ity_I8: ccOp = 0; break;
1535 case Ity_I16: ccOp = 1; break;
1536 case Ity_I32: ccOp = 2; break;
1537 case Ity_I64: ccOp = 3; break;
1538 default: vassert(0);
1539 }
1540 switch (op8) {
1541 case Iop_Add8: ccOp += AMD64G_CC_OP_ADDB; break;
1542 case Iop_Sub8: ccOp += AMD64G_CC_OP_SUBB; break;
1543 default: ppIROp(op8);
1544 vpanic("setFlags_DEP1_DEP2(amd64)");
1545 }
1546 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(ccOp)) );
1547 stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto64(mkexpr(dep1))) );
1548 stmt( IRStmt_Put( OFFB_CC_DEP2, widenUto64(mkexpr(dep2))) );
1549}
1550
1551
1552/* Set the OP and DEP1 fields only, and write zero to DEP2. */
1553
1554static
1555void setFlags_DEP1 ( IROp op8, IRTemp dep1, IRType ty )
1556{
1557 Int ccOp = 0;
1558 switch (ty) {
1559 case Ity_I8: ccOp = 0; break;
1560 case Ity_I16: ccOp = 1; break;
1561 case Ity_I32: ccOp = 2; break;
1562 case Ity_I64: ccOp = 3; break;
1563 default: vassert(0);
1564 }
1565 switch (op8) {
1566 case Iop_Or8:
1567 case Iop_And8:
1568 case Iop_Xor8: ccOp += AMD64G_CC_OP_LOGICB; break;
1569 default: ppIROp(op8);
1570 vpanic("setFlags_DEP1(amd64)");
1571 }
1572 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(ccOp)) );
1573 stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto64(mkexpr(dep1))) );
1574 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0)) );
1575}
1576
1577
sewardj118b23e2005-01-29 02:14:44 +00001578/* For shift operations, we put in the result and the undershifted
1579 result. Except if the shift amount is zero, the thunk is left
1580 unchanged. */
1581
1582static void setFlags_DEP1_DEP2_shift ( IROp op64,
1583 IRTemp res,
1584 IRTemp resUS,
1585 IRType ty,
1586 IRTemp guard )
1587{
1588 Int ccOp = 0;
1589 switch (ty) {
1590 case Ity_I8: ccOp = 0; break;
1591 case Ity_I16: ccOp = 1; break;
1592 case Ity_I32: ccOp = 2; break;
1593 case Ity_I64: ccOp = 3; break;
1594 default: vassert(0);
1595 }
1596
1597 vassert(guard);
1598
1599 /* Both kinds of right shifts are handled by the same thunk
1600 operation. */
1601 switch (op64) {
1602 case Iop_Shr64:
1603 case Iop_Sar64: ccOp += AMD64G_CC_OP_SHRB; break;
1604 case Iop_Shl64: ccOp += AMD64G_CC_OP_SHLB; break;
1605 default: ppIROp(op64);
1606 vpanic("setFlags_DEP1_DEP2_shift(amd64)");
1607 }
1608
1609 /* DEP1 contains the result, DEP2 contains the undershifted value. */
1610 stmt( IRStmt_Put( OFFB_CC_OP,
1611 IRExpr_Mux0X( mkexpr(guard),
1612 IRExpr_Get(OFFB_CC_OP,Ity_I64),
1613 mkU64(ccOp))) );
1614 stmt( IRStmt_Put( OFFB_CC_DEP1,
1615 IRExpr_Mux0X( mkexpr(guard),
1616 IRExpr_Get(OFFB_CC_DEP1,Ity_I64),
1617 widenUto64(mkexpr(res)))) );
1618 stmt( IRStmt_Put( OFFB_CC_DEP2,
1619 IRExpr_Mux0X( mkexpr(guard),
1620 IRExpr_Get(OFFB_CC_DEP2,Ity_I64),
1621 widenUto64(mkexpr(resUS)))) );
1622}
sewardj354e5c62005-01-27 20:12:52 +00001623
1624
1625/* For the inc/dec case, we store in DEP1 the result value and in NDEP
1626 the former value of the carry flag, which unfortunately we have to
1627 compute. */
1628
1629static void setFlags_INC_DEC ( Bool inc, IRTemp res, IRType ty )
1630{
1631 Int ccOp = inc ? AMD64G_CC_OP_INCB : AMD64G_CC_OP_DECB;
1632
1633 switch (ty) {
1634 case Ity_I8: ccOp += 0; break;
1635 case Ity_I16: ccOp += 1; break;
1636 case Ity_I32: ccOp += 2; break;
1637 case Ity_I64: ccOp += 3; break;
1638 default: vassert(0);
1639 }
1640
1641 /* This has to come first, because calculating the C flag
1642 may require reading all four thunk fields. */
1643 stmt( IRStmt_Put( OFFB_CC_NDEP, mk_amd64g_calculate_rflags_c()) );
1644 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(ccOp)) );
1645 stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(res)) );
1646 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0)) );
1647}
1648
1649
sewardj32b2bbe2005-01-28 00:50:10 +00001650/* Multiplies are pretty much like add and sub: DEP1 and DEP2 hold the
1651 two arguments. */
1652
1653static
1654void setFlags_MUL ( IRType ty, IRTemp arg1, IRTemp arg2, ULong base_op )
1655{
1656 switch (ty) {
1657 case Ity_I8:
1658 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(base_op+0) ) );
1659 break;
1660 case Ity_I16:
1661 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(base_op+1) ) );
1662 break;
1663 case Ity_I32:
1664 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(base_op+2) ) );
1665 break;
1666 case Ity_I64:
1667 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(base_op+3) ) );
1668 break;
1669 default:
1670 vpanic("setFlags_MUL(amd64)");
1671 }
1672 stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto64(mkexpr(arg1)) ));
1673 stmt( IRStmt_Put( OFFB_CC_DEP2, widenUto64(mkexpr(arg2)) ));
1674}
sewardj3ca55a12005-01-27 16:06:23 +00001675
1676
1677/* -------------- Condition codes. -------------- */
1678
1679/* Condition codes, using the AMD encoding. */
1680
sewardj8c332e22005-01-28 01:36:56 +00001681static HChar* name_AMD64Condcode ( AMD64Condcode cond )
sewardj3ca55a12005-01-27 16:06:23 +00001682{
1683 switch (cond) {
1684 case AMD64CondO: return "o";
1685 case AMD64CondNO: return "no";
1686 case AMD64CondB: return "b";
sewardje941eea2005-01-30 19:52:28 +00001687 case AMD64CondNB: return "ae"; /*"nb";*/
1688 case AMD64CondZ: return "e"; /*"z";*/
1689 case AMD64CondNZ: return "ne"; /*"nz";*/
sewardj3ca55a12005-01-27 16:06:23 +00001690 case AMD64CondBE: return "be";
sewardje941eea2005-01-30 19:52:28 +00001691 case AMD64CondNBE: return "a"; /*"nbe";*/
sewardj3ca55a12005-01-27 16:06:23 +00001692 case AMD64CondS: return "s";
1693 case AMD64CondNS: return "ns";
1694 case AMD64CondP: return "p";
1695 case AMD64CondNP: return "np";
1696 case AMD64CondL: return "l";
sewardje941eea2005-01-30 19:52:28 +00001697 case AMD64CondNL: return "ge"; /*"nl";*/
sewardj3ca55a12005-01-27 16:06:23 +00001698 case AMD64CondLE: return "le";
sewardje941eea2005-01-30 19:52:28 +00001699 case AMD64CondNLE: return "g"; /*"nle";*/
sewardj3ca55a12005-01-27 16:06:23 +00001700 case AMD64CondAlways: return "ALWAYS";
1701 default: vpanic("name_AMD64Condcode");
1702 }
1703}
1704
sewardj1389d4d2005-01-28 13:46:29 +00001705static
1706AMD64Condcode positiveIse_AMD64Condcode ( AMD64Condcode cond,
1707 /*OUT*/Bool* needInvert )
1708{
1709 vassert(cond >= AMD64CondO && cond <= AMD64CondNLE);
1710 if (cond & 1) {
1711 *needInvert = True;
1712 return cond-1;
1713 } else {
1714 *needInvert = False;
1715 return cond;
1716 }
1717}
sewardjdf0e0022005-01-25 15:48:43 +00001718
1719
1720/* -------------- Helpers for ADD/SUB with carry. -------------- */
1721
1722/* Given ta1, ta2 and tres, compute tres = ADC(ta1,ta2) and set flags
1723 appropriately.
1724*/
1725static void helper_ADC ( Int sz,
1726 IRTemp tres, IRTemp ta1, IRTemp ta2 )
1727{
1728 UInt thunkOp;
1729 IRType ty = szToITy(sz);
1730 IRTemp oldc = newTemp(Ity_I64);
1731 IRTemp oldcn = newTemp(ty);
1732 IROp plus = mkSizedOp(ty, Iop_Add8);
1733 IROp xor = mkSizedOp(ty, Iop_Xor8);
1734
1735 switch (sz) {
1736 case 8: thunkOp = AMD64G_CC_OP_ADCQ; break;
1737 case 4: thunkOp = AMD64G_CC_OP_ADCL; break;
1738 case 2: thunkOp = AMD64G_CC_OP_ADCW; break;
1739 case 1: thunkOp = AMD64G_CC_OP_ADCB; break;
1740 default: vassert(0);
1741 }
1742
1743 /* oldc = old carry flag, 0 or 1 */
1744 assign( oldc, binop(Iop_And64,
1745 mk_amd64g_calculate_rflags_c(),
1746 mkU64(1)) );
1747
1748 assign( oldcn, narrowTo(ty, mkexpr(oldc)) );
1749
1750 assign( tres, binop(plus,
1751 binop(plus,mkexpr(ta1),mkexpr(ta2)),
1752 mkexpr(oldcn)) );
1753
1754 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(thunkOp) ) );
sewardj820611e2005-08-24 10:56:01 +00001755 stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto64(mkexpr(ta1)) ));
1756 stmt( IRStmt_Put( OFFB_CC_DEP2, widenUto64(binop(xor, mkexpr(ta2),
1757 mkexpr(oldcn)) )) );
sewardjdf0e0022005-01-25 15:48:43 +00001758 stmt( IRStmt_Put( OFFB_CC_NDEP, mkexpr(oldc) ) );
1759}
1760
1761
1762/* Given ta1, ta2 and tres, compute tres = SBB(ta1,ta2) and set flags
1763 appropriately.
1764*/
1765static void helper_SBB ( Int sz,
1766 IRTemp tres, IRTemp ta1, IRTemp ta2 )
1767{
1768 UInt thunkOp;
1769 IRType ty = szToITy(sz);
1770 IRTemp oldc = newTemp(Ity_I64);
1771 IRTemp oldcn = newTemp(ty);
1772 IROp minus = mkSizedOp(ty, Iop_Sub8);
1773 IROp xor = mkSizedOp(ty, Iop_Xor8);
1774
1775 switch (sz) {
1776 case 8: thunkOp = AMD64G_CC_OP_SBBQ; break;
1777 case 4: thunkOp = AMD64G_CC_OP_SBBL; break;
1778 case 2: thunkOp = AMD64G_CC_OP_SBBW; break;
1779 case 1: thunkOp = AMD64G_CC_OP_SBBB; break;
1780 default: vassert(0);
1781 }
1782
1783 /* oldc = old carry flag, 0 or 1 */
1784 assign( oldc, binop(Iop_And64,
1785 mk_amd64g_calculate_rflags_c(),
1786 mkU64(1)) );
1787
1788 assign( oldcn, narrowTo(ty, mkexpr(oldc)) );
1789
1790 assign( tres, binop(minus,
1791 binop(minus,mkexpr(ta1),mkexpr(ta2)),
1792 mkexpr(oldcn)) );
1793
1794 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(thunkOp) ) );
sewardj820611e2005-08-24 10:56:01 +00001795 stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto64(mkexpr(ta1) )) );
1796 stmt( IRStmt_Put( OFFB_CC_DEP2, widenUto64(binop(xor, mkexpr(ta2),
1797 mkexpr(oldcn)) )) );
sewardjdf0e0022005-01-25 15:48:43 +00001798 stmt( IRStmt_Put( OFFB_CC_NDEP, mkexpr(oldc) ) );
1799}
1800
1801
sewardj3ca55a12005-01-27 16:06:23 +00001802/* -------------- Helpers for disassembly printing. -------------- */
1803
1804static HChar* nameGrp1 ( Int opc_aux )
1805{
1806 static HChar* grp1_names[8]
1807 = { "add", "or", "adc", "sbb", "and", "sub", "xor", "cmp" };
1808 if (opc_aux < 0 || opc_aux > 7) vpanic("nameGrp1(amd64)");
1809 return grp1_names[opc_aux];
1810}
1811
sewardj118b23e2005-01-29 02:14:44 +00001812static HChar* nameGrp2 ( Int opc_aux )
1813{
1814 static HChar* grp2_names[8]
1815 = { "rol", "ror", "rcl", "rcr", "shl", "shr", "shl", "sar" };
sewardje941eea2005-01-30 19:52:28 +00001816 if (opc_aux < 0 || opc_aux > 7) vpanic("nameGrp2(amd64)");
sewardj118b23e2005-01-29 02:14:44 +00001817 return grp2_names[opc_aux];
1818}
1819
sewardj03b07cc2005-01-31 18:09:43 +00001820static HChar* nameGrp4 ( Int opc_aux )
1821{
1822 static HChar* grp4_names[8]
1823 = { "inc", "dec", "???", "???", "???", "???", "???", "???" };
1824 if (opc_aux < 0 || opc_aux > 1) vpanic("nameGrp4(amd64)");
1825 return grp4_names[opc_aux];
1826}
sewardj354e5c62005-01-27 20:12:52 +00001827
1828static HChar* nameGrp5 ( Int opc_aux )
1829{
1830 static HChar* grp5_names[8]
1831 = { "inc", "dec", "call*", "call*", "jmp*", "jmp*", "push", "???" };
1832 if (opc_aux < 0 || opc_aux > 6) vpanic("nameGrp5(amd64)");
1833 return grp5_names[opc_aux];
1834}
1835
sewardj1d511802005-03-27 17:59:45 +00001836static HChar* nameGrp8 ( Int opc_aux )
1837{
1838 static HChar* grp8_names[8]
1839 = { "???", "???", "???", "???", "bt", "bts", "btr", "btc" };
1840 if (opc_aux < 4 || opc_aux > 7) vpanic("nameGrp8(amd64)");
1841 return grp8_names[opc_aux];
1842}
1843
sewardjd20c8852005-01-20 20:04:07 +00001844//.. static HChar* nameSReg ( UInt sreg )
1845//.. {
1846//.. switch (sreg) {
1847//.. case R_ES: return "%es";
1848//.. case R_CS: return "%cs";
1849//.. case R_SS: return "%ss";
1850//.. case R_DS: return "%ds";
1851//.. case R_FS: return "%fs";
1852//.. case R_GS: return "%gs";
1853//.. default: vpanic("nameSReg(x86)");
1854//.. }
1855//.. }
sewardj8711f662005-05-09 17:52:56 +00001856
1857static HChar* nameMMXReg ( Int mmxreg )
1858{
1859 static HChar* mmx_names[8]
1860 = { "%mm0", "%mm1", "%mm2", "%mm3", "%mm4", "%mm5", "%mm6", "%mm7" };
1861 if (mmxreg < 0 || mmxreg > 7) vpanic("nameMMXReg(amd64,guest)");
1862 return mmx_names[mmxreg];
1863}
sewardj1001dc42005-02-21 08:25:55 +00001864
1865static HChar* nameXMMReg ( Int xmmreg )
1866{
1867 static HChar* xmm_names[16]
1868 = { "%xmm0", "%xmm1", "%xmm2", "%xmm3",
1869 "%xmm4", "%xmm5", "%xmm6", "%xmm7",
1870 "%xmm8", "%xmm9", "%xmm10", "%xmm11",
1871 "%xmm12", "%xmm13", "%xmm14", "%xmm15" };
1872 if (xmmreg < 0 || xmmreg > 15) vpanic("nameXMMReg(amd64)");
1873 return xmm_names[xmmreg];
1874}
1875
sewardjca673ab2005-05-11 10:03:08 +00001876static HChar* nameMMXGran ( Int gran )
sewardj8711f662005-05-09 17:52:56 +00001877{
1878 switch (gran) {
1879 case 0: return "b";
1880 case 1: return "w";
1881 case 2: return "d";
1882 case 3: return "q";
1883 default: vpanic("nameMMXGran(amd64,guest)");
1884 }
1885}
sewardjdf0e0022005-01-25 15:48:43 +00001886
sewardj8c332e22005-01-28 01:36:56 +00001887static HChar nameISize ( Int size )
sewardjdf0e0022005-01-25 15:48:43 +00001888{
1889 switch (size) {
1890 case 8: return 'q';
1891 case 4: return 'l';
1892 case 2: return 'w';
1893 case 1: return 'b';
1894 default: vpanic("nameISize(amd64)");
1895 }
1896}
1897
1898
1899/*------------------------------------------------------------*/
1900/*--- JMP helpers ---*/
1901/*------------------------------------------------------------*/
1902
1903static void jmp_lit( IRJumpKind kind, Addr64 d64 )
1904{
sewardjdd40fdf2006-12-24 02:20:24 +00001905 irsb->next = mkU64(d64);
1906 irsb->jumpkind = kind;
sewardjdf0e0022005-01-25 15:48:43 +00001907}
1908
sewardj2f959cc2005-01-26 01:19:35 +00001909static void jmp_treg( IRJumpKind kind, IRTemp t )
1910{
sewardjdd40fdf2006-12-24 02:20:24 +00001911 irsb->next = mkexpr(t);
1912 irsb->jumpkind = kind;
sewardj2f959cc2005-01-26 01:19:35 +00001913}
1914
sewardj1389d4d2005-01-28 13:46:29 +00001915static
1916void jcc_01 ( AMD64Condcode cond, Addr64 d64_false, Addr64 d64_true )
1917{
1918 Bool invert;
1919 AMD64Condcode condPos;
1920 condPos = positiveIse_AMD64Condcode ( cond, &invert );
1921 if (invert) {
1922 stmt( IRStmt_Exit( mk_amd64g_calculate_condition(condPos),
1923 Ijk_Boring,
1924 IRConst_U64(d64_false) ) );
sewardjdd40fdf2006-12-24 02:20:24 +00001925 irsb->next = mkU64(d64_true);
1926 irsb->jumpkind = Ijk_Boring;
sewardj1389d4d2005-01-28 13:46:29 +00001927 } else {
1928 stmt( IRStmt_Exit( mk_amd64g_calculate_condition(condPos),
1929 Ijk_Boring,
1930 IRConst_U64(d64_true) ) );
sewardjdd40fdf2006-12-24 02:20:24 +00001931 irsb->next = mkU64(d64_false);
1932 irsb->jumpkind = Ijk_Boring;
sewardj1389d4d2005-01-28 13:46:29 +00001933 }
1934}
sewardjb3a04292005-01-21 20:33:44 +00001935
sewardj5a9ffab2005-05-12 17:55:01 +00001936/* Let new_rsp be the %rsp value after a call/return. This function
1937 generates an AbiHint to say that -128(%rsp) .. -1(%rsp) should now
1938 be regarded as uninitialised.
1939*/
sewardjaca070a2006-10-17 00:28:22 +00001940static
sewardjdd40fdf2006-12-24 02:20:24 +00001941void make_redzone_AbiHint ( VexAbiInfo* vbi, IRTemp new_rsp, HChar* who )
sewardj5a9ffab2005-05-12 17:55:01 +00001942{
sewardjdd40fdf2006-12-24 02:20:24 +00001943 Int szB = vbi->guest_stack_redzone_size;
sewardjaca070a2006-10-17 00:28:22 +00001944 vassert(szB >= 0);
1945
1946 /* A bit of a kludge. Currently the only AbI we've guested AMD64
1947 for is ELF. So just check it's the expected 128 value
1948 (paranoia). */
1949 vassert(szB == 128);
1950
sewardj5a9ffab2005-05-12 17:55:01 +00001951 if (0) vex_printf("AbiHint: %s\n", who);
sewardjdd40fdf2006-12-24 02:20:24 +00001952 vassert(typeOfIRTemp(irsb->tyenv, new_rsp) == Ity_I64);
sewardjaca070a2006-10-17 00:28:22 +00001953 if (szB > 0)
1954 stmt( IRStmt_AbiHint(
1955 binop(Iop_Sub64, mkexpr(new_rsp), mkU64(szB)),
1956 szB
1957 ));
sewardj5a9ffab2005-05-12 17:55:01 +00001958}
1959
sewardjb3a04292005-01-21 20:33:44 +00001960
1961/*------------------------------------------------------------*/
1962/*--- Disassembling addressing modes ---*/
1963/*------------------------------------------------------------*/
1964
1965static
sewardjc4356f02007-11-09 21:15:04 +00001966HChar* segRegTxt ( Prefix pfx )
sewardjb3a04292005-01-21 20:33:44 +00001967{
1968 if (pfx & PFX_CS) return "%cs:";
1969 if (pfx & PFX_DS) return "%ds:";
1970 if (pfx & PFX_ES) return "%es:";
1971 if (pfx & PFX_FS) return "%fs:";
1972 if (pfx & PFX_GS) return "%gs:";
1973 if (pfx & PFX_SS) return "%ss:";
1974 return ""; /* no override */
1975}
1976
1977
1978/* 'virtual' is an IRExpr* holding a virtual address. Convert it to a
1979 linear address by adding any required segment override as indicated
sewardj42561ef2005-11-04 14:18:31 +00001980 by sorb, and also dealing with any address size override
1981 present. */
sewardjb3a04292005-01-21 20:33:44 +00001982static
sewardj42561ef2005-11-04 14:18:31 +00001983IRExpr* handleAddrOverrides ( Prefix pfx, IRExpr* virtual )
sewardjb3a04292005-01-21 20:33:44 +00001984{
sewardj42561ef2005-11-04 14:18:31 +00001985 /* --- segment overrides --- */
1986
sewardja6b93d12005-02-17 09:28:28 +00001987 if (pfx & PFX_FS) {
1988 /* Note that this is a linux-kernel specific hack that relies
1989 on the assumption that %fs is always zero. */
1990 /* return virtual + guest_FS_ZERO. */
sewardj42561ef2005-11-04 14:18:31 +00001991 virtual = binop(Iop_Add64, virtual, IRExpr_Get(OFFB_FS_ZERO, Ity_I64));
sewardja6b93d12005-02-17 09:28:28 +00001992 }
sewardjb3a04292005-01-21 20:33:44 +00001993
sewardja6b93d12005-02-17 09:28:28 +00001994 if (pfx & PFX_GS) {
1995 unimplemented("amd64 %gs segment override");
1996 }
1997
1998 /* cs, ds, es and ss are simply ignored in 64-bit mode. */
sewardj42561ef2005-11-04 14:18:31 +00001999
2000 /* --- address size override --- */
2001 if (haveASO(pfx))
2002 virtual = unop(Iop_32Uto64, unop(Iop_64to32, virtual));
2003
sewardja6b93d12005-02-17 09:28:28 +00002004 return virtual;
sewardjb3a04292005-01-21 20:33:44 +00002005}
sewardja6b93d12005-02-17 09:28:28 +00002006
sewardjd20c8852005-01-20 20:04:07 +00002007//.. {
2008//.. Int sreg;
2009//.. IRType hWordTy;
2010//.. IRTemp ldt_ptr, gdt_ptr, seg_selector, r64;
2011//..
2012//.. if (sorb == 0)
2013//.. /* the common case - no override */
2014//.. return virtual;
2015//..
2016//.. switch (sorb) {
2017//.. case 0x3E: sreg = R_DS; break;
2018//.. case 0x26: sreg = R_ES; break;
2019//.. case 0x64: sreg = R_FS; break;
2020//.. case 0x65: sreg = R_GS; break;
sewardj42561ef2005-11-04 14:18:31 +00002021//.. default: vpanic("handleAddrOverrides(x86,guest)");
sewardjd20c8852005-01-20 20:04:07 +00002022//.. }
2023//..
2024//.. hWordTy = sizeof(HWord)==4 ? Ity_I32 : Ity_I64;
2025//..
2026//.. seg_selector = newTemp(Ity_I32);
2027//.. ldt_ptr = newTemp(hWordTy);
2028//.. gdt_ptr = newTemp(hWordTy);
2029//.. r64 = newTemp(Ity_I64);
2030//..
2031//.. assign( seg_selector, unop(Iop_16Uto32, getSReg(sreg)) );
2032//.. assign( ldt_ptr, IRExpr_Get( OFFB_LDT, hWordTy ));
2033//.. assign( gdt_ptr, IRExpr_Get( OFFB_GDT, hWordTy ));
2034//..
2035//.. /*
2036//.. Call this to do the translation and limit checks:
2037//.. ULong x86g_use_seg_selector ( HWord ldt, HWord gdt,
2038//.. UInt seg_selector, UInt virtual_addr )
2039//.. */
2040//.. assign(
2041//.. r64,
2042//.. mkIRExprCCall(
2043//.. Ity_I64,
2044//.. 0/*regparms*/,
2045//.. "x86g_use_seg_selector",
2046//.. &x86g_use_seg_selector,
2047//.. mkIRExprVec_4( mkexpr(ldt_ptr), mkexpr(gdt_ptr),
2048//.. mkexpr(seg_selector), virtual)
2049//.. )
2050//.. );
2051//..
2052//.. /* If the high 32 of the result are non-zero, there was a
2053//.. failure in address translation. In which case, make a
2054//.. quick exit.
2055//.. */
2056//.. stmt(
2057//.. IRStmt_Exit(
2058//.. binop(Iop_CmpNE32, unop(Iop_64HIto32, mkexpr(r64)), mkU32(0)),
2059//.. Ijk_MapFail,
2060//.. IRConst_U32( guest_eip_curr_instr )
2061//.. )
2062//.. );
2063//..
2064//.. /* otherwise, here's the translated result. */
2065//.. return unop(Iop_64to32, mkexpr(r64));
2066//.. }
sewardjb3a04292005-01-21 20:33:44 +00002067
2068
2069/* Generate IR to calculate an address indicated by a ModRM and
2070 following SIB bytes. The expression, and the number of bytes in
2071 the address mode, are returned (the latter in *len). Note that
2072 this fn should not be called if the R/M part of the address denotes
2073 a register instead of memory. If print_codegen is true, text of
2074 the addressing mode is placed in buf.
2075
2076 The computed address is stored in a new tempreg, and the
sewardje1698952005-02-08 15:02:39 +00002077 identity of the tempreg is returned.
2078
2079 extra_bytes holds the number of bytes after the amode, as supplied
2080 by the caller. This is needed to make sense of %rip-relative
2081 addresses. Note that the value that *len is set to is only the
2082 length of the amode itself and does not include the value supplied
sewardj09717342005-05-05 21:34:02 +00002083 in extra_bytes.
sewardje1698952005-02-08 15:02:39 +00002084 */
sewardjb3a04292005-01-21 20:33:44 +00002085
2086static IRTemp disAMode_copy2tmp ( IRExpr* addr64 )
2087{
2088 IRTemp tmp = newTemp(Ity_I64);
2089 assign( tmp, addr64 );
2090 return tmp;
2091}
2092
2093static
sewardj270def42005-07-03 01:03:01 +00002094IRTemp disAMode ( Int* len, Prefix pfx, Long delta,
sewardje1698952005-02-08 15:02:39 +00002095 HChar* buf, Int extra_bytes )
sewardjb3a04292005-01-21 20:33:44 +00002096{
sewardj8c332e22005-01-28 01:36:56 +00002097 UChar mod_reg_rm = getUChar(delta);
sewardjb3a04292005-01-21 20:33:44 +00002098 delta++;
2099
2100 buf[0] = (UChar)0;
sewardje1698952005-02-08 15:02:39 +00002101 vassert(extra_bytes >= 0 && extra_bytes < 10);
sewardjb3a04292005-01-21 20:33:44 +00002102
2103 /* squeeze out the reg field from mod_reg_rm, since a 256-entry
2104 jump table seems a bit excessive.
2105 */
sewardj7a240552005-01-28 21:37:12 +00002106 mod_reg_rm &= 0xC7; /* is now XX000YYY */
sewardj1027dc22005-02-26 01:55:02 +00002107 mod_reg_rm = toUChar(mod_reg_rm | (mod_reg_rm >> 3));
2108 /* is now XX0XXYYY */
sewardj7a240552005-01-28 21:37:12 +00002109 mod_reg_rm &= 0x1F; /* is now 000XXYYY */
sewardjb3a04292005-01-21 20:33:44 +00002110 switch (mod_reg_rm) {
2111
2112 /* REX.B==0: (%rax) .. (%rdi), not including (%rsp) or (%rbp).
2113 REX.B==1: (%r8) .. (%r15), not including (%r12) or (%r13).
2114 */
2115 case 0x00: case 0x01: case 0x02: case 0x03:
2116 /* ! 04 */ /* ! 05 */ case 0x06: case 0x07:
sewardj1027dc22005-02-26 01:55:02 +00002117 { UChar rm = toUChar(mod_reg_rm & 7);
sewardjc4356f02007-11-09 21:15:04 +00002118 DIS(buf, "%s(%s)", segRegTxt(pfx), nameIRegRexB(8,pfx,rm));
sewardjb3a04292005-01-21 20:33:44 +00002119 *len = 1;
2120 return disAMode_copy2tmp(
sewardj42561ef2005-11-04 14:18:31 +00002121 handleAddrOverrides(pfx, getIRegRexB(8,pfx,rm)));
sewardjb3a04292005-01-21 20:33:44 +00002122 }
2123
2124 /* REX.B==0: d8(%rax) ... d8(%rdi), not including d8(%rsp)
2125 REX.B==1: d8(%r8) ... d8(%r15), not including d8(%r12)
2126 */
2127 case 0x08: case 0x09: case 0x0A: case 0x0B:
2128 /* ! 0C */ case 0x0D: case 0x0E: case 0x0F:
sewardj1027dc22005-02-26 01:55:02 +00002129 { UChar rm = toUChar(mod_reg_rm & 7);
sewardj8c332e22005-01-28 01:36:56 +00002130 Long d = getSDisp8(delta);
sewardj7eaa7cf2005-01-31 18:55:22 +00002131 if (d == 0) {
sewardjc4356f02007-11-09 21:15:04 +00002132 DIS(buf, "%s(%s)", segRegTxt(pfx), nameIRegRexB(8,pfx,rm));
sewardj7eaa7cf2005-01-31 18:55:22 +00002133 } else {
sewardjc4356f02007-11-09 21:15:04 +00002134 DIS(buf, "%s%lld(%s)", segRegTxt(pfx), d, nameIRegRexB(8,pfx,rm));
sewardj7eaa7cf2005-01-31 18:55:22 +00002135 }
sewardjb3a04292005-01-21 20:33:44 +00002136 *len = 2;
2137 return disAMode_copy2tmp(
sewardj42561ef2005-11-04 14:18:31 +00002138 handleAddrOverrides(pfx,
sewardj5b470602005-02-27 13:10:48 +00002139 binop(Iop_Add64,getIRegRexB(8,pfx,rm),mkU64(d))));
sewardjb3a04292005-01-21 20:33:44 +00002140 }
2141
2142 /* REX.B==0: d32(%rax) ... d32(%rdi), not including d32(%rsp)
2143 REX.B==1: d32(%r8) ... d32(%r15), not including d32(%r12)
2144 */
2145 case 0x10: case 0x11: case 0x12: case 0x13:
2146 /* ! 14 */ case 0x15: case 0x16: case 0x17:
sewardj1027dc22005-02-26 01:55:02 +00002147 { UChar rm = toUChar(mod_reg_rm & 7);
sewardj227458e2005-01-31 19:04:50 +00002148 Long d = getSDisp32(delta);
sewardjc4356f02007-11-09 21:15:04 +00002149 DIS(buf, "%s%lld(%s)", segRegTxt(pfx), d, nameIRegRexB(8,pfx,rm));
sewardjb3a04292005-01-21 20:33:44 +00002150 *len = 5;
2151 return disAMode_copy2tmp(
sewardj42561ef2005-11-04 14:18:31 +00002152 handleAddrOverrides(pfx,
sewardj5b470602005-02-27 13:10:48 +00002153 binop(Iop_Add64,getIRegRexB(8,pfx,rm),mkU64(d))));
sewardjb3a04292005-01-21 20:33:44 +00002154 }
2155
2156 /* REX.B==0: a register, %rax .. %rdi. This shouldn't happen. */
2157 /* REX.B==1: a register, %r8 .. %r16. This shouldn't happen. */
2158 case 0x18: case 0x19: case 0x1A: case 0x1B:
2159 case 0x1C: case 0x1D: case 0x1E: case 0x1F:
sewardj354e5c62005-01-27 20:12:52 +00002160 vpanic("disAMode(amd64): not an addr!");
sewardjb3a04292005-01-21 20:33:44 +00002161
sewardj9e6491a2005-07-02 19:24:10 +00002162 /* RIP + disp32. This assumes that guest_RIP_curr_instr is set
sewardjb3a04292005-01-21 20:33:44 +00002163 correctly at the start of handling each instruction. */
2164 case 0x05:
sewardj227458e2005-01-31 19:04:50 +00002165 { Long d = getSDisp32(delta);
sewardjb3a04292005-01-21 20:33:44 +00002166 *len = 5;
sewardjc4356f02007-11-09 21:15:04 +00002167 DIS(buf, "%s%lld(%%rip)", segRegTxt(pfx), d);
sewardj4b744762005-02-07 15:02:25 +00002168 /* We need to know the next instruction's start address.
2169 Try and figure out what it is, record the guess, and ask
2170 the top-level driver logic (bbToIR_AMD64) to check we
2171 guessed right, after the instruction is completely
2172 decoded. */
sewardj9e6491a2005-07-02 19:24:10 +00002173 guest_RIP_next_mustcheck = True;
2174 guest_RIP_next_assumed = guest_RIP_bbstart
sewardje1698952005-02-08 15:02:39 +00002175 + delta+4 + extra_bytes;
sewardjb3a04292005-01-21 20:33:44 +00002176 return disAMode_copy2tmp(
sewardj42561ef2005-11-04 14:18:31 +00002177 handleAddrOverrides(pfx,
sewardj9e6491a2005-07-02 19:24:10 +00002178 binop(Iop_Add64, mkU64(guest_RIP_next_assumed),
sewardjb3a04292005-01-21 20:33:44 +00002179 mkU64(d))));
2180 }
sewardj3ca55a12005-01-27 16:06:23 +00002181
sewardj2f959cc2005-01-26 01:19:35 +00002182 case 0x04: {
2183 /* SIB, with no displacement. Special cases:
sewardj3ca55a12005-01-27 16:06:23 +00002184 -- %rsp cannot act as an index value.
2185 If index_r indicates %rsp, zero is used for the index.
2186 -- when mod is zero and base indicates RBP or R13, base is
2187 instead a 32-bit sign-extended literal.
sewardj2f959cc2005-01-26 01:19:35 +00002188 It's all madness, I tell you. Extract %index, %base and
2189 scale from the SIB byte. The value denoted is then:
sewardj3ca55a12005-01-27 16:06:23 +00002190 | %index == %RSP && (%base == %RBP || %base == %R13)
sewardj2f959cc2005-01-26 01:19:35 +00002191 = d32 following SIB byte
sewardj3ca55a12005-01-27 16:06:23 +00002192 | %index == %RSP && !(%base == %RBP || %base == %R13)
sewardj2f959cc2005-01-26 01:19:35 +00002193 = %base
sewardj3ca55a12005-01-27 16:06:23 +00002194 | %index != %RSP && (%base == %RBP || %base == %R13)
sewardj2f959cc2005-01-26 01:19:35 +00002195 = d32 following SIB byte + (%index << scale)
sewardj3ca55a12005-01-27 16:06:23 +00002196 | %index != %RSP && !(%base == %RBP || %base == %R13)
sewardj2f959cc2005-01-26 01:19:35 +00002197 = %base + (%index << scale)
2198 */
sewardj8c332e22005-01-28 01:36:56 +00002199 UChar sib = getUChar(delta);
sewardj1027dc22005-02-26 01:55:02 +00002200 UChar scale = toUChar((sib >> 6) & 3);
2201 UChar index_r = toUChar((sib >> 3) & 7);
2202 UChar base_r = toUChar(sib & 7);
sewardj3ca55a12005-01-27 16:06:23 +00002203 /* correct since #(R13) == 8 + #(RBP) */
sewardj7a240552005-01-28 21:37:12 +00002204 Bool base_is_BPor13 = toBool(base_r == R_RBP);
2205 Bool index_is_SP = toBool(index_r == R_RSP && 0==getRexX(pfx));
sewardj2f959cc2005-01-26 01:19:35 +00002206 delta++;
sewardjb3a04292005-01-21 20:33:44 +00002207
sewardj3ca55a12005-01-27 16:06:23 +00002208 if ((!index_is_SP) && (!base_is_BPor13)) {
sewardje941eea2005-01-30 19:52:28 +00002209 if (scale == 0) {
sewardjc4356f02007-11-09 21:15:04 +00002210 DIS(buf, "%s(%s,%s)", segRegTxt(pfx),
sewardj5b470602005-02-27 13:10:48 +00002211 nameIRegRexB(8,pfx,base_r),
2212 nameIReg64rexX(pfx,index_r));
sewardje941eea2005-01-30 19:52:28 +00002213 } else {
sewardjc4356f02007-11-09 21:15:04 +00002214 DIS(buf, "%s(%s,%s,%d)", segRegTxt(pfx),
sewardj5b470602005-02-27 13:10:48 +00002215 nameIRegRexB(8,pfx,base_r),
2216 nameIReg64rexX(pfx,index_r), 1<<scale);
sewardje941eea2005-01-30 19:52:28 +00002217 }
sewardj2f959cc2005-01-26 01:19:35 +00002218 *len = 2;
sewardj2f959cc2005-01-26 01:19:35 +00002219 return
2220 disAMode_copy2tmp(
sewardj42561ef2005-11-04 14:18:31 +00002221 handleAddrOverrides(pfx,
sewardj3ca55a12005-01-27 16:06:23 +00002222 binop(Iop_Add64,
sewardj5b470602005-02-27 13:10:48 +00002223 getIRegRexB(8,pfx,base_r),
2224 binop(Iop_Shl64, getIReg64rexX(pfx,index_r),
sewardj2f959cc2005-01-26 01:19:35 +00002225 mkU8(scale)))));
2226 }
2227
sewardj3ca55a12005-01-27 16:06:23 +00002228 if ((!index_is_SP) && base_is_BPor13) {
sewardj227458e2005-01-31 19:04:50 +00002229 Long d = getSDisp32(delta);
sewardjc4356f02007-11-09 21:15:04 +00002230 DIS(buf, "%s%lld(,%s,%d)", segRegTxt(pfx), d,
sewardj5b470602005-02-27 13:10:48 +00002231 nameIReg64rexX(pfx,index_r), 1<<scale);
sewardj2f959cc2005-01-26 01:19:35 +00002232 *len = 6;
sewardj2f959cc2005-01-26 01:19:35 +00002233 return
2234 disAMode_copy2tmp(
sewardj42561ef2005-11-04 14:18:31 +00002235 handleAddrOverrides(pfx,
sewardj3ca55a12005-01-27 16:06:23 +00002236 binop(Iop_Add64,
sewardj5b470602005-02-27 13:10:48 +00002237 binop(Iop_Shl64, getIReg64rexX(pfx,index_r),
sewardj3ca55a12005-01-27 16:06:23 +00002238 mkU8(scale)),
2239 mkU64(d))));
sewardj2f959cc2005-01-26 01:19:35 +00002240 }
2241
sewardj3ca55a12005-01-27 16:06:23 +00002242 if (index_is_SP && (!base_is_BPor13)) {
sewardjc4356f02007-11-09 21:15:04 +00002243 DIS(buf, "%s(%s)", segRegTxt(pfx), nameIRegRexB(8,pfx,base_r));
sewardj2f959cc2005-01-26 01:19:35 +00002244 *len = 2;
sewardj2f959cc2005-01-26 01:19:35 +00002245 return disAMode_copy2tmp(
sewardj42561ef2005-11-04 14:18:31 +00002246 handleAddrOverrides(pfx, getIRegRexB(8,pfx,base_r)));
sewardj2f959cc2005-01-26 01:19:35 +00002247 }
2248
sewardj3ca55a12005-01-27 16:06:23 +00002249 if (index_is_SP && base_is_BPor13) {
sewardj227458e2005-01-31 19:04:50 +00002250 Long d = getSDisp32(delta);
sewardjc4356f02007-11-09 21:15:04 +00002251 DIS(buf, "%s%lld", segRegTxt(pfx), d);
sewardj2f959cc2005-01-26 01:19:35 +00002252 *len = 6;
sewardj2f959cc2005-01-26 01:19:35 +00002253 return disAMode_copy2tmp(
sewardj42561ef2005-11-04 14:18:31 +00002254 handleAddrOverrides(pfx, mkU64(d)));
sewardj2f959cc2005-01-26 01:19:35 +00002255 }
2256
2257 vassert(0);
2258 }
sewardj3ca55a12005-01-27 16:06:23 +00002259
sewardj2f959cc2005-01-26 01:19:35 +00002260 /* SIB, with 8-bit displacement. Special cases:
2261 -- %esp cannot act as an index value.
2262 If index_r indicates %esp, zero is used for the index.
2263 Denoted value is:
2264 | %index == %ESP
2265 = d8 + %base
2266 | %index != %ESP
2267 = d8 + %base + (%index << scale)
2268 */
2269 case 0x0C: {
sewardj8c332e22005-01-28 01:36:56 +00002270 UChar sib = getUChar(delta);
sewardj1027dc22005-02-26 01:55:02 +00002271 UChar scale = toUChar((sib >> 6) & 3);
2272 UChar index_r = toUChar((sib >> 3) & 7);
2273 UChar base_r = toUChar(sib & 7);
sewardj8c332e22005-01-28 01:36:56 +00002274 Long d = getSDisp8(delta+1);
sewardj2f959cc2005-01-26 01:19:35 +00002275
sewardj3ca55a12005-01-27 16:06:23 +00002276 if (index_r == R_RSP && 0==getRexX(pfx)) {
sewardjc4356f02007-11-09 21:15:04 +00002277 DIS(buf, "%s%lld(%s)", segRegTxt(pfx),
sewardj5b470602005-02-27 13:10:48 +00002278 d, nameIRegRexB(8,pfx,base_r));
sewardj2f959cc2005-01-26 01:19:35 +00002279 *len = 3;
sewardj2f959cc2005-01-26 01:19:35 +00002280 return disAMode_copy2tmp(
sewardj42561ef2005-11-04 14:18:31 +00002281 handleAddrOverrides(pfx,
sewardj5b470602005-02-27 13:10:48 +00002282 binop(Iop_Add64, getIRegRexB(8,pfx,base_r), mkU64(d)) ));
sewardj2f959cc2005-01-26 01:19:35 +00002283 } else {
sewardje941eea2005-01-30 19:52:28 +00002284 if (scale == 0) {
sewardjc4356f02007-11-09 21:15:04 +00002285 DIS(buf, "%s%lld(%s,%s)", segRegTxt(pfx), d,
sewardj5b470602005-02-27 13:10:48 +00002286 nameIRegRexB(8,pfx,base_r),
2287 nameIReg64rexX(pfx,index_r));
sewardje941eea2005-01-30 19:52:28 +00002288 } else {
sewardjc4356f02007-11-09 21:15:04 +00002289 DIS(buf, "%s%lld(%s,%s,%d)", segRegTxt(pfx), d,
sewardj5b470602005-02-27 13:10:48 +00002290 nameIRegRexB(8,pfx,base_r),
2291 nameIReg64rexX(pfx,index_r), 1<<scale);
sewardje941eea2005-01-30 19:52:28 +00002292 }
sewardj2f959cc2005-01-26 01:19:35 +00002293 *len = 3;
sewardj2f959cc2005-01-26 01:19:35 +00002294 return
2295 disAMode_copy2tmp(
sewardj42561ef2005-11-04 14:18:31 +00002296 handleAddrOverrides(pfx,
sewardj3ca55a12005-01-27 16:06:23 +00002297 binop(Iop_Add64,
2298 binop(Iop_Add64,
sewardj5b470602005-02-27 13:10:48 +00002299 getIRegRexB(8,pfx,base_r),
sewardj3ca55a12005-01-27 16:06:23 +00002300 binop(Iop_Shl64,
sewardj5b470602005-02-27 13:10:48 +00002301 getIReg64rexX(pfx,index_r), mkU8(scale))),
sewardj3ca55a12005-01-27 16:06:23 +00002302 mkU64(d))));
sewardj2f959cc2005-01-26 01:19:35 +00002303 }
sewardj3ca55a12005-01-27 16:06:23 +00002304 vassert(0); /*NOTREACHED*/
sewardj2f959cc2005-01-26 01:19:35 +00002305 }
sewardj3ca55a12005-01-27 16:06:23 +00002306
sewardj2f959cc2005-01-26 01:19:35 +00002307 /* SIB, with 32-bit displacement. Special cases:
2308 -- %rsp cannot act as an index value.
2309 If index_r indicates %rsp, zero is used for the index.
2310 Denoted value is:
2311 | %index == %RSP
2312 = d32 + %base
2313 | %index != %RSP
2314 = d32 + %base + (%index << scale)
2315 */
2316 case 0x14: {
sewardj8c332e22005-01-28 01:36:56 +00002317 UChar sib = getUChar(delta);
sewardj1027dc22005-02-26 01:55:02 +00002318 UChar scale = toUChar((sib >> 6) & 3);
2319 UChar index_r = toUChar((sib >> 3) & 7);
2320 UChar base_r = toUChar(sib & 7);
sewardj8c332e22005-01-28 01:36:56 +00002321 Long d = getSDisp32(delta+1);
sewardj2f959cc2005-01-26 01:19:35 +00002322
2323 if (index_r == R_RSP && 0==getRexX(pfx)) {
sewardjc4356f02007-11-09 21:15:04 +00002324 DIS(buf, "%s%lld(%s)", segRegTxt(pfx),
sewardj5b470602005-02-27 13:10:48 +00002325 d, nameIRegRexB(8,pfx,base_r));
sewardj2f959cc2005-01-26 01:19:35 +00002326 *len = 6;
sewardj2f959cc2005-01-26 01:19:35 +00002327 return disAMode_copy2tmp(
sewardj42561ef2005-11-04 14:18:31 +00002328 handleAddrOverrides(pfx,
sewardj5b470602005-02-27 13:10:48 +00002329 binop(Iop_Add64, getIRegRexB(8,pfx,base_r), mkU64(d)) ));
sewardj2f959cc2005-01-26 01:19:35 +00002330 } else {
sewardje941eea2005-01-30 19:52:28 +00002331 if (scale == 0) {
sewardjc4356f02007-11-09 21:15:04 +00002332 DIS(buf, "%s%lld(%s,%s)", segRegTxt(pfx), d,
sewardj5b470602005-02-27 13:10:48 +00002333 nameIRegRexB(8,pfx,base_r),
2334 nameIReg64rexX(pfx,index_r));
sewardje941eea2005-01-30 19:52:28 +00002335 } else {
sewardjc4356f02007-11-09 21:15:04 +00002336 DIS(buf, "%s%lld(%s,%s,%d)", segRegTxt(pfx), d,
sewardj5b470602005-02-27 13:10:48 +00002337 nameIRegRexB(8,pfx,base_r),
2338 nameIReg64rexX(pfx,index_r), 1<<scale);
sewardje941eea2005-01-30 19:52:28 +00002339 }
sewardj2f959cc2005-01-26 01:19:35 +00002340 *len = 6;
2341 return
2342 disAMode_copy2tmp(
sewardj42561ef2005-11-04 14:18:31 +00002343 handleAddrOverrides(pfx,
sewardj2f959cc2005-01-26 01:19:35 +00002344 binop(Iop_Add64,
2345 binop(Iop_Add64,
sewardj5b470602005-02-27 13:10:48 +00002346 getIRegRexB(8,pfx,base_r),
sewardj2f959cc2005-01-26 01:19:35 +00002347 binop(Iop_Shl64,
sewardj5b470602005-02-27 13:10:48 +00002348 getIReg64rexX(pfx,index_r), mkU8(scale))),
sewardj2f959cc2005-01-26 01:19:35 +00002349 mkU64(d))));
2350 }
sewardj3ca55a12005-01-27 16:06:23 +00002351 vassert(0); /*NOTREACHED*/
sewardj2f959cc2005-01-26 01:19:35 +00002352 }
2353
sewardjb3a04292005-01-21 20:33:44 +00002354 default:
2355 vpanic("disAMode(amd64)");
2356 return 0; /*notreached*/
2357 }
2358}
2359
2360
sewardj3ca55a12005-01-27 16:06:23 +00002361/* Figure out the number of (insn-stream) bytes constituting the amode
2362 beginning at delta. Is useful for getting hold of literals beyond
2363 the end of the amode before it has been disassembled. */
2364
sewardj270def42005-07-03 01:03:01 +00002365static UInt lengthAMode ( Prefix pfx, Long delta )
sewardj3ca55a12005-01-27 16:06:23 +00002366{
sewardj8c332e22005-01-28 01:36:56 +00002367 UChar mod_reg_rm = getUChar(delta);
sewardj3ca55a12005-01-27 16:06:23 +00002368 delta++;
2369
2370 /* squeeze out the reg field from mod_reg_rm, since a 256-entry
2371 jump table seems a bit excessive.
2372 */
sewardj7a240552005-01-28 21:37:12 +00002373 mod_reg_rm &= 0xC7; /* is now XX000YYY */
sewardj1027dc22005-02-26 01:55:02 +00002374 mod_reg_rm = toUChar(mod_reg_rm | (mod_reg_rm >> 3));
2375 /* is now XX0XXYYY */
sewardj7a240552005-01-28 21:37:12 +00002376 mod_reg_rm &= 0x1F; /* is now 000XXYYY */
sewardj3ca55a12005-01-27 16:06:23 +00002377 switch (mod_reg_rm) {
2378
2379 /* REX.B==0: (%rax) .. (%rdi), not including (%rsp) or (%rbp).
2380 REX.B==1: (%r8) .. (%r15), not including (%r12) or (%r13).
2381 */
2382 case 0x00: case 0x01: case 0x02: case 0x03:
2383 /* ! 04 */ /* ! 05 */ case 0x06: case 0x07:
sewardj3ca55a12005-01-27 16:06:23 +00002384 return 1;
2385
2386 /* REX.B==0: d8(%rax) ... d8(%rdi), not including d8(%rsp)
2387 REX.B==1: d8(%r8) ... d8(%r15), not including d8(%r12)
2388 */
2389 case 0x08: case 0x09: case 0x0A: case 0x0B:
2390 /* ! 0C */ case 0x0D: case 0x0E: case 0x0F:
sewardj3ca55a12005-01-27 16:06:23 +00002391 return 2;
2392
2393 /* REX.B==0: d32(%rax) ... d32(%rdi), not including d32(%rsp)
2394 REX.B==1: d32(%r8) ... d32(%r15), not including d32(%r12)
2395 */
2396 case 0x10: case 0x11: case 0x12: case 0x13:
2397 /* ! 14 */ case 0x15: case 0x16: case 0x17:
sewardj3ca55a12005-01-27 16:06:23 +00002398 return 5;
2399
2400 /* REX.B==0: a register, %rax .. %rdi. This shouldn't happen. */
2401 /* REX.B==1: a register, %r8 .. %r16. This shouldn't happen. */
2402 /* Not an address, but still handled. */
2403 case 0x18: case 0x19: case 0x1A: case 0x1B:
2404 case 0x1C: case 0x1D: case 0x1E: case 0x1F:
2405 return 1;
2406
2407 /* RIP + disp32. */
2408 case 0x05:
sewardj3ca55a12005-01-27 16:06:23 +00002409 return 5;
2410
2411 case 0x04: {
2412 /* SIB, with no displacement. */
sewardj8c332e22005-01-28 01:36:56 +00002413 UChar sib = getUChar(delta);
sewardj1027dc22005-02-26 01:55:02 +00002414 UChar base_r = toUChar(sib & 7);
sewardj3ca55a12005-01-27 16:06:23 +00002415 /* correct since #(R13) == 8 + #(RBP) */
sewardj7a240552005-01-28 21:37:12 +00002416 Bool base_is_BPor13 = toBool(base_r == R_RBP);
sewardj3ca55a12005-01-27 16:06:23 +00002417
2418 if (base_is_BPor13) {
sewardj3ca55a12005-01-27 16:06:23 +00002419 return 6;
2420 } else {
sewardj3ca55a12005-01-27 16:06:23 +00002421 return 2;
2422 }
2423 }
2424
2425 /* SIB, with 8-bit displacement. */
2426 case 0x0C:
2427 return 3;
2428
2429 /* SIB, with 32-bit displacement. */
2430 case 0x14:
2431 return 6;
2432
2433 default:
2434 vpanic("lengthAMode(amd64)");
2435 return 0; /*notreached*/
2436 }
2437}
2438
2439
sewardjdf0e0022005-01-25 15:48:43 +00002440/*------------------------------------------------------------*/
2441/*--- Disassembling common idioms ---*/
2442/*------------------------------------------------------------*/
2443
sewardjdf0e0022005-01-25 15:48:43 +00002444/* Handle binary integer instructions of the form
2445 op E, G meaning
2446 op reg-or-mem, reg
2447 Is passed the a ptr to the modRM byte, the actual operation, and the
2448 data size. Returns the address advanced completely over this
2449 instruction.
2450
2451 E(src) is reg-or-mem
2452 G(dst) is reg.
2453
2454 If E is reg, --> GET %G, tmp
2455 OP %E, tmp
2456 PUT tmp, %G
2457
2458 If E is mem and OP is not reversible,
2459 --> (getAddr E) -> tmpa
2460 LD (tmpa), tmpa
2461 GET %G, tmp2
2462 OP tmpa, tmp2
2463 PUT tmp2, %G
2464
2465 If E is mem and OP is reversible
2466 --> (getAddr E) -> tmpa
2467 LD (tmpa), tmpa
2468 OP %G, tmpa
2469 PUT tmpa, %G
2470*/
2471static
2472ULong dis_op2_E_G ( Prefix pfx,
2473 Bool addSubCarry,
2474 IROp op8,
2475 Bool keep,
2476 Int size,
sewardj270def42005-07-03 01:03:01 +00002477 Long delta0,
sewardj8c332e22005-01-28 01:36:56 +00002478 HChar* t_amd64opc )
sewardjdf0e0022005-01-25 15:48:43 +00002479{
2480 HChar dis_buf[50];
2481 Int len;
2482 IRType ty = szToITy(size);
2483 IRTemp dst1 = newTemp(ty);
2484 IRTemp src = newTemp(ty);
2485 IRTemp dst0 = newTemp(ty);
2486 UChar rm = getUChar(delta0);
2487 IRTemp addr = IRTemp_INVALID;
2488
2489 /* addSubCarry == True indicates the intended operation is
2490 add-with-carry or subtract-with-borrow. */
2491 if (addSubCarry) {
2492 vassert(op8 == Iop_Add8 || op8 == Iop_Sub8);
2493 vassert(keep);
2494 }
2495
2496 if (epartIsReg(rm)) {
sewardjdf0e0022005-01-25 15:48:43 +00002497 /* Specially handle XOR reg,reg, because that doesn't really
2498 depend on reg, and doing the obvious thing potentially
2499 generates a spurious value check failure due to the bogus
2500 dependency. */
sewardj5b470602005-02-27 13:10:48 +00002501 if ((op8 == Iop_Xor8 || (op8 == Iop_Sub8 && addSubCarry))
2502 && offsetIRegG(size,pfx,rm) == offsetIRegE(size,pfx,rm)) {
sewardj4f9847d2005-07-25 11:58:34 +00002503 if (False && op8 == Iop_Sub8)
sewardj5b470602005-02-27 13:10:48 +00002504 vex_printf("vex amd64->IR: sbb %%r,%%r optimisation(1)\n");
2505 putIRegG(size,pfx,rm, mkU(ty,0));
sewardjdf0e0022005-01-25 15:48:43 +00002506 }
sewardj5b470602005-02-27 13:10:48 +00002507
2508 assign( dst0, getIRegG(size,pfx,rm) );
2509 assign( src, getIRegE(size,pfx,rm) );
sewardjdf0e0022005-01-25 15:48:43 +00002510
2511 if (addSubCarry && op8 == Iop_Add8) {
2512 helper_ADC( size, dst1, dst0, src );
sewardj5b470602005-02-27 13:10:48 +00002513 putIRegG(size, pfx, rm, mkexpr(dst1));
sewardjdf0e0022005-01-25 15:48:43 +00002514 } else
2515 if (addSubCarry && op8 == Iop_Sub8) {
2516 helper_SBB( size, dst1, dst0, src );
sewardj5b470602005-02-27 13:10:48 +00002517 putIRegG(size, pfx, rm, mkexpr(dst1));
sewardjdf0e0022005-01-25 15:48:43 +00002518 } else {
2519 assign( dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
2520 if (isAddSub(op8))
2521 setFlags_DEP1_DEP2(op8, dst0, src, ty);
2522 else
2523 setFlags_DEP1(op8, dst1, ty);
2524 if (keep)
sewardj5b470602005-02-27 13:10:48 +00002525 putIRegG(size, pfx, rm, mkexpr(dst1));
sewardjdf0e0022005-01-25 15:48:43 +00002526 }
2527
2528 DIP("%s%c %s,%s\n", t_amd64opc, nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00002529 nameIRegE(size,pfx,rm),
2530 nameIRegG(size,pfx,rm));
sewardjdf0e0022005-01-25 15:48:43 +00002531 return 1+delta0;
2532 } else {
2533 /* E refers to memory */
sewardje1698952005-02-08 15:02:39 +00002534 addr = disAMode ( &len, pfx, delta0, dis_buf, 0 );
sewardj5b470602005-02-27 13:10:48 +00002535 assign( dst0, getIRegG(size,pfx,rm) );
sewardjdf0e0022005-01-25 15:48:43 +00002536 assign( src, loadLE(szToITy(size), mkexpr(addr)) );
2537
2538 if (addSubCarry && op8 == Iop_Add8) {
2539 helper_ADC( size, dst1, dst0, src );
sewardj5b470602005-02-27 13:10:48 +00002540 putIRegG(size, pfx, rm, mkexpr(dst1));
sewardjdf0e0022005-01-25 15:48:43 +00002541 } else
2542 if (addSubCarry && op8 == Iop_Sub8) {
2543 helper_SBB( size, dst1, dst0, src );
sewardj5b470602005-02-27 13:10:48 +00002544 putIRegG(size, pfx, rm, mkexpr(dst1));
sewardjdf0e0022005-01-25 15:48:43 +00002545 } else {
2546 assign( dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
2547 if (isAddSub(op8))
2548 setFlags_DEP1_DEP2(op8, dst0, src, ty);
2549 else
2550 setFlags_DEP1(op8, dst1, ty);
2551 if (keep)
sewardj5b470602005-02-27 13:10:48 +00002552 putIRegG(size, pfx, rm, mkexpr(dst1));
sewardjdf0e0022005-01-25 15:48:43 +00002553 }
2554
2555 DIP("%s%c %s,%s\n", t_amd64opc, nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00002556 dis_buf, nameIRegG(size, pfx, rm));
sewardjdf0e0022005-01-25 15:48:43 +00002557 return len+delta0;
2558 }
2559}
2560
2561
2562
sewardj3ca55a12005-01-27 16:06:23 +00002563/* Handle binary integer instructions of the form
2564 op G, E meaning
2565 op reg, reg-or-mem
2566 Is passed the a ptr to the modRM byte, the actual operation, and the
2567 data size. Returns the address advanced completely over this
2568 instruction.
2569
2570 G(src) is reg.
2571 E(dst) is reg-or-mem
2572
2573 If E is reg, --> GET %E, tmp
2574 OP %G, tmp
2575 PUT tmp, %E
2576
2577 If E is mem, --> (getAddr E) -> tmpa
2578 LD (tmpa), tmpv
2579 OP %G, tmpv
2580 ST tmpv, (tmpa)
2581*/
2582static
sewardj8c332e22005-01-28 01:36:56 +00002583ULong dis_op2_G_E ( Prefix pfx,
2584 Bool addSubCarry,
2585 IROp op8,
2586 Bool keep,
2587 Int size,
sewardj270def42005-07-03 01:03:01 +00002588 Long delta0,
sewardj8c332e22005-01-28 01:36:56 +00002589 HChar* t_amd64opc )
sewardj3ca55a12005-01-27 16:06:23 +00002590{
2591 HChar dis_buf[50];
2592 Int len;
2593 IRType ty = szToITy(size);
2594 IRTemp dst1 = newTemp(ty);
2595 IRTemp src = newTemp(ty);
2596 IRTemp dst0 = newTemp(ty);
sewardj8c332e22005-01-28 01:36:56 +00002597 UChar rm = getUChar(delta0);
sewardj3ca55a12005-01-27 16:06:23 +00002598 IRTemp addr = IRTemp_INVALID;
2599
2600 /* addSubCarry == True indicates the intended operation is
2601 add-with-carry or subtract-with-borrow. */
2602 if (addSubCarry) {
2603 vassert(op8 == Iop_Add8 || op8 == Iop_Sub8);
2604 vassert(keep);
2605 }
2606
2607 if (epartIsReg(rm)) {
2608 /* Specially handle XOR reg,reg, because that doesn't really
2609 depend on reg, and doing the obvious thing potentially
2610 generates a spurious value check failure due to the bogus
sewardj5b470602005-02-27 13:10:48 +00002611 dependency. Ditto SBB reg,reg. */
2612 if ((op8 == Iop_Xor8 || (op8 == Iop_Sub8 && addSubCarry))
2613 && offsetIRegG(size,pfx,rm) == offsetIRegE(size,pfx,rm)) {
2614 putIRegE(size,pfx,rm, mkU(ty,0));
sewardj3ca55a12005-01-27 16:06:23 +00002615 }
sewardj5b470602005-02-27 13:10:48 +00002616
2617 assign(dst0, getIRegE(size,pfx,rm));
2618 assign(src, getIRegG(size,pfx,rm));
sewardj3ca55a12005-01-27 16:06:23 +00002619
2620 if (addSubCarry && op8 == Iop_Add8) {
sewardj3ca55a12005-01-27 16:06:23 +00002621 helper_ADC( size, dst1, dst0, src );
sewardj5b470602005-02-27 13:10:48 +00002622 putIRegE(size, pfx, rm, mkexpr(dst1));
sewardj3ca55a12005-01-27 16:06:23 +00002623 } else
2624 if (addSubCarry && op8 == Iop_Sub8) {
sewardj3ca55a12005-01-27 16:06:23 +00002625 helper_SBB( size, dst1, dst0, src );
sewardj5b470602005-02-27 13:10:48 +00002626 putIRegE(size, pfx, rm, mkexpr(dst1));
sewardj3ca55a12005-01-27 16:06:23 +00002627 } else {
2628 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
2629 if (isAddSub(op8))
2630 setFlags_DEP1_DEP2(op8, dst0, src, ty);
2631 else
2632 setFlags_DEP1(op8, dst1, ty);
2633 if (keep)
sewardj5b470602005-02-27 13:10:48 +00002634 putIRegE(size, pfx, rm, mkexpr(dst1));
sewardj3ca55a12005-01-27 16:06:23 +00002635 }
2636
2637 DIP("%s%c %s,%s\n", t_amd64opc, nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00002638 nameIRegG(size,pfx,rm),
2639 nameIRegE(size,pfx,rm));
sewardj3ca55a12005-01-27 16:06:23 +00002640 return 1+delta0;
2641 }
2642
2643 /* E refers to memory */
2644 {
sewardje1698952005-02-08 15:02:39 +00002645 addr = disAMode ( &len, pfx, delta0, dis_buf, 0 );
sewardj3ca55a12005-01-27 16:06:23 +00002646 assign(dst0, loadLE(ty,mkexpr(addr)));
sewardj5b470602005-02-27 13:10:48 +00002647 assign(src, getIRegG(size,pfx,rm));
sewardj3ca55a12005-01-27 16:06:23 +00002648
2649 if (addSubCarry && op8 == Iop_Add8) {
sewardj3ca55a12005-01-27 16:06:23 +00002650 helper_ADC( size, dst1, dst0, src );
2651 storeLE(mkexpr(addr), mkexpr(dst1));
2652 } else
2653 if (addSubCarry && op8 == Iop_Sub8) {
sewardj3ca55a12005-01-27 16:06:23 +00002654 helper_SBB( size, dst1, dst0, src );
2655 storeLE(mkexpr(addr), mkexpr(dst1));
2656 } else {
2657 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
2658 if (isAddSub(op8))
2659 setFlags_DEP1_DEP2(op8, dst0, src, ty);
2660 else
2661 setFlags_DEP1(op8, dst1, ty);
2662 if (keep)
2663 storeLE(mkexpr(addr), mkexpr(dst1));
2664 }
2665
2666 DIP("%s%c %s,%s\n", t_amd64opc, nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00002667 nameIRegG(size,pfx,rm), dis_buf);
sewardj3ca55a12005-01-27 16:06:23 +00002668 return len+delta0;
2669 }
2670}
2671
2672
sewardj1389d4d2005-01-28 13:46:29 +00002673/* Handle move instructions of the form
2674 mov E, G meaning
2675 mov reg-or-mem, reg
2676 Is passed the a ptr to the modRM byte, and the data size. Returns
2677 the address advanced completely over this instruction.
2678
2679 E(src) is reg-or-mem
2680 G(dst) is reg.
2681
2682 If E is reg, --> GET %E, tmpv
2683 PUT tmpv, %G
2684
2685 If E is mem --> (getAddr E) -> tmpa
2686 LD (tmpa), tmpb
2687 PUT tmpb, %G
2688*/
2689static
2690ULong dis_mov_E_G ( Prefix pfx,
2691 Int size,
sewardj270def42005-07-03 01:03:01 +00002692 Long delta0 )
sewardj1389d4d2005-01-28 13:46:29 +00002693{
2694 Int len;
2695 UChar rm = getUChar(delta0);
2696 HChar dis_buf[50];
2697
2698 if (epartIsReg(rm)) {
sewardj5b470602005-02-27 13:10:48 +00002699 putIRegG(size, pfx, rm, getIRegE(size, pfx, rm));
sewardje941eea2005-01-30 19:52:28 +00002700 DIP("mov%c %s,%s\n", nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00002701 nameIRegE(size,pfx,rm),
2702 nameIRegG(size,pfx,rm));
sewardj1389d4d2005-01-28 13:46:29 +00002703 return 1+delta0;
2704 }
2705
2706 /* E refers to memory */
2707 {
sewardje1698952005-02-08 15:02:39 +00002708 IRTemp addr = disAMode ( &len, pfx, delta0, dis_buf, 0 );
sewardj5b470602005-02-27 13:10:48 +00002709 putIRegG(size, pfx, rm, loadLE(szToITy(size), mkexpr(addr)));
sewardj1389d4d2005-01-28 13:46:29 +00002710 DIP("mov%c %s,%s\n", nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00002711 dis_buf,
2712 nameIRegG(size,pfx,rm));
sewardj1389d4d2005-01-28 13:46:29 +00002713 return delta0+len;
2714 }
2715}
2716
2717
2718/* Handle move instructions of the form
2719 mov G, E meaning
2720 mov reg, reg-or-mem
2721 Is passed the a ptr to the modRM byte, and the data size. Returns
2722 the address advanced completely over this instruction.
2723
2724 G(src) is reg.
2725 E(dst) is reg-or-mem
2726
2727 If E is reg, --> GET %G, tmp
2728 PUT tmp, %E
2729
2730 If E is mem, --> (getAddr E) -> tmpa
2731 GET %G, tmpv
2732 ST tmpv, (tmpa)
2733*/
2734static
2735ULong dis_mov_G_E ( Prefix pfx,
2736 Int size,
sewardj270def42005-07-03 01:03:01 +00002737 Long delta0 )
sewardj1389d4d2005-01-28 13:46:29 +00002738{
2739 Int len;
2740 UChar rm = getUChar(delta0);
2741 HChar dis_buf[50];
2742
2743 if (epartIsReg(rm)) {
sewardj5b470602005-02-27 13:10:48 +00002744 putIRegE(size, pfx, rm, getIRegG(size, pfx, rm));
sewardje941eea2005-01-30 19:52:28 +00002745 DIP("mov%c %s,%s\n", nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00002746 nameIRegG(size,pfx,rm),
2747 nameIRegE(size,pfx,rm));
sewardj1389d4d2005-01-28 13:46:29 +00002748 return 1+delta0;
2749 }
2750
2751 /* E refers to memory */
2752 {
sewardje1698952005-02-08 15:02:39 +00002753 IRTemp addr = disAMode ( &len, pfx, delta0, dis_buf, 0 );
sewardj5b470602005-02-27 13:10:48 +00002754 storeLE( mkexpr(addr), getIRegG(size, pfx, rm) );
sewardj1389d4d2005-01-28 13:46:29 +00002755 DIP("mov%c %s,%s\n", nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00002756 nameIRegG(size,pfx,rm),
2757 dis_buf);
sewardj1389d4d2005-01-28 13:46:29 +00002758 return len+delta0;
2759 }
2760}
sewardj3ca55a12005-01-27 16:06:23 +00002761
2762
2763/* op $immediate, AL/AX/EAX/RAX. */
2764static
sewardj8c332e22005-01-28 01:36:56 +00002765ULong dis_op_imm_A ( Int size,
sewardj41c01092005-07-23 13:50:32 +00002766 Bool carrying,
sewardj8c332e22005-01-28 01:36:56 +00002767 IROp op8,
2768 Bool keep,
sewardj270def42005-07-03 01:03:01 +00002769 Long delta,
sewardj8c332e22005-01-28 01:36:56 +00002770 HChar* t_amd64opc )
sewardj3ca55a12005-01-27 16:06:23 +00002771{
2772 Int size4 = imin(size,4);
2773 IRType ty = szToITy(size);
2774 IRTemp dst0 = newTemp(ty);
2775 IRTemp src = newTemp(ty);
2776 IRTemp dst1 = newTemp(ty);
sewardj8c332e22005-01-28 01:36:56 +00002777 Long lit = getSDisp(size4,delta);
sewardj5b470602005-02-27 13:10:48 +00002778 assign(dst0, getIRegRAX(size));
sewardj1389d4d2005-01-28 13:46:29 +00002779 assign(src, mkU(ty,lit & mkSizeMask(size)));
sewardj41c01092005-07-23 13:50:32 +00002780
2781 if (isAddSub(op8) && !carrying) {
2782 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
sewardj3ca55a12005-01-27 16:06:23 +00002783 setFlags_DEP1_DEP2(op8, dst0, src, ty);
sewardj41c01092005-07-23 13:50:32 +00002784 }
sewardj3ca55a12005-01-27 16:06:23 +00002785 else
sewardj41c01092005-07-23 13:50:32 +00002786 if (isLogic(op8)) {
2787 vassert(!carrying);
2788 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
sewardj3ca55a12005-01-27 16:06:23 +00002789 setFlags_DEP1(op8, dst1, ty);
sewardj41c01092005-07-23 13:50:32 +00002790 }
sewardj3ca55a12005-01-27 16:06:23 +00002791 else
sewardj41c01092005-07-23 13:50:32 +00002792 if (op8 == Iop_Add8 && carrying) {
2793 helper_ADC( size, dst1, dst0, src );
2794 }
2795 else
sewardj5fadaf92006-05-12 20:45:59 +00002796 if (op8 == Iop_Sub8 && carrying) {
2797 helper_SBB( size, dst1, dst0, src );
2798 }
2799 else
sewardj41c01092005-07-23 13:50:32 +00002800 vpanic("dis_op_imm_A(amd64,guest)");
sewardj3ca55a12005-01-27 16:06:23 +00002801
2802 if (keep)
sewardj5b470602005-02-27 13:10:48 +00002803 putIRegRAX(size, mkexpr(dst1));
sewardj3ca55a12005-01-27 16:06:23 +00002804
2805 DIP("%s%c $%lld, %s\n", t_amd64opc, nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00002806 lit, nameIRegRAX(size));
sewardj3ca55a12005-01-27 16:06:23 +00002807 return delta+size4;
2808}
2809
2810
sewardj5e525292005-01-28 15:13:10 +00002811/* Sign- and Zero-extending moves. */
2812static
2813ULong dis_movx_E_G ( Prefix pfx,
sewardj270def42005-07-03 01:03:01 +00002814 Long delta, Int szs, Int szd, Bool sign_extend )
sewardj5e525292005-01-28 15:13:10 +00002815{
2816 UChar rm = getUChar(delta);
2817 if (epartIsReg(rm)) {
sewardj5b470602005-02-27 13:10:48 +00002818 putIRegG(szd, pfx, rm,
sewardj5e525292005-01-28 15:13:10 +00002819 doScalarWidening(
2820 szs,szd,sign_extend,
sewardj5b470602005-02-27 13:10:48 +00002821 getIRegE(szs,pfx,rm)));
sewardj5e525292005-01-28 15:13:10 +00002822 DIP("mov%c%c%c %s,%s\n", sign_extend ? 's' : 'z',
2823 nameISize(szs),
2824 nameISize(szd),
sewardj5b470602005-02-27 13:10:48 +00002825 nameIRegE(szs,pfx,rm),
2826 nameIRegG(szd,pfx,rm));
sewardj5e525292005-01-28 15:13:10 +00002827 return 1+delta;
2828 }
2829
2830 /* E refers to memory */
2831 {
2832 Int len;
2833 HChar dis_buf[50];
sewardje1698952005-02-08 15:02:39 +00002834 IRTemp addr = disAMode ( &len, pfx, delta, dis_buf, 0 );
sewardj5b470602005-02-27 13:10:48 +00002835 putIRegG(szd, pfx, rm,
sewardj5e525292005-01-28 15:13:10 +00002836 doScalarWidening(
2837 szs,szd,sign_extend,
2838 loadLE(szToITy(szs),mkexpr(addr))));
2839 DIP("mov%c%c%c %s,%s\n", sign_extend ? 's' : 'z',
2840 nameISize(szs),
2841 nameISize(szd),
2842 dis_buf,
sewardj5b470602005-02-27 13:10:48 +00002843 nameIRegG(szd,pfx,rm));
sewardj5e525292005-01-28 15:13:10 +00002844 return len+delta;
2845 }
2846}
sewardj32b2bbe2005-01-28 00:50:10 +00002847
2848
sewardj03b07cc2005-01-31 18:09:43 +00002849/* Generate code to divide ArchRegs RDX:RAX / EDX:EAX / DX:AX / AX by
2850 the 64 / 32 / 16 / 8 bit quantity in the given IRTemp. */
sewardj32b2bbe2005-01-28 00:50:10 +00002851static
2852void codegen_div ( Int sz, IRTemp t, Bool signed_divide )
2853{
sewardj03b07cc2005-01-31 18:09:43 +00002854 /* special-case the 64-bit case */
2855 if (sz == 8) {
2856 IROp op = signed_divide ? Iop_DivModS128to64
2857 : Iop_DivModU128to64;
sewardja6b93d12005-02-17 09:28:28 +00002858 IRTemp src128 = newTemp(Ity_I128);
2859 IRTemp dst128 = newTemp(Ity_I128);
sewardj03b07cc2005-01-31 18:09:43 +00002860 assign( src128, binop(Iop_64HLto128,
sewardja6b93d12005-02-17 09:28:28 +00002861 getIReg64(R_RDX),
2862 getIReg64(R_RAX)) );
sewardj03b07cc2005-01-31 18:09:43 +00002863 assign( dst128, binop(op, mkexpr(src128), mkexpr(t)) );
sewardja6b93d12005-02-17 09:28:28 +00002864 putIReg64( R_RAX, unop(Iop_128to64,mkexpr(dst128)) );
2865 putIReg64( R_RDX, unop(Iop_128HIto64,mkexpr(dst128)) );
sewardj03b07cc2005-01-31 18:09:43 +00002866 } else {
2867 IROp op = signed_divide ? Iop_DivModS64to32
2868 : Iop_DivModU64to32;
2869 IRTemp src64 = newTemp(Ity_I64);
2870 IRTemp dst64 = newTemp(Ity_I64);
2871 switch (sz) {
sewardj85520e42005-02-19 15:22:38 +00002872 case 4:
sewardj5b470602005-02-27 13:10:48 +00002873 assign( src64,
2874 binop(Iop_32HLto64, getIRegRDX(4), getIRegRAX(4)) );
2875 assign( dst64,
2876 binop(op, mkexpr(src64), mkexpr(t)) );
2877 putIRegRAX( 4, unop(Iop_64to32,mkexpr(dst64)) );
2878 putIRegRDX( 4, unop(Iop_64HIto32,mkexpr(dst64)) );
sewardj85520e42005-02-19 15:22:38 +00002879 break;
2880 case 2: {
2881 IROp widen3264 = signed_divide ? Iop_32Sto64 : Iop_32Uto64;
2882 IROp widen1632 = signed_divide ? Iop_16Sto32 : Iop_16Uto32;
2883 assign( src64, unop(widen3264,
2884 binop(Iop_16HLto32,
sewardj5b470602005-02-27 13:10:48 +00002885 getIRegRDX(2),
2886 getIRegRAX(2))) );
sewardj85520e42005-02-19 15:22:38 +00002887 assign( dst64, binop(op, mkexpr(src64), unop(widen1632,mkexpr(t))) );
sewardj5b470602005-02-27 13:10:48 +00002888 putIRegRAX( 2, unop(Iop_32to16,unop(Iop_64to32,mkexpr(dst64))) );
2889 putIRegRDX( 2, unop(Iop_32to16,unop(Iop_64HIto32,mkexpr(dst64))) );
sewardj85520e42005-02-19 15:22:38 +00002890 break;
2891 }
2892 case 1: {
2893 IROp widen3264 = signed_divide ? Iop_32Sto64 : Iop_32Uto64;
2894 IROp widen1632 = signed_divide ? Iop_16Sto32 : Iop_16Uto32;
2895 IROp widen816 = signed_divide ? Iop_8Sto16 : Iop_8Uto16;
2896 assign( src64, unop(widen3264,
sewardj5b470602005-02-27 13:10:48 +00002897 unop(widen1632, getIRegRAX(2))) );
sewardj85520e42005-02-19 15:22:38 +00002898 assign( dst64,
2899 binop(op, mkexpr(src64),
2900 unop(widen1632, unop(widen816, mkexpr(t)))) );
sewardj5b470602005-02-27 13:10:48 +00002901 putIRegRAX( 1, unop(Iop_16to8,
2902 unop(Iop_32to16,
2903 unop(Iop_64to32,mkexpr(dst64)))) );
2904 putIRegAH( unop(Iop_16to8,
2905 unop(Iop_32to16,
2906 unop(Iop_64HIto32,mkexpr(dst64)))) );
sewardj85520e42005-02-19 15:22:38 +00002907 break;
2908 }
2909 default:
2910 vpanic("codegen_div(amd64)");
sewardj03b07cc2005-01-31 18:09:43 +00002911 }
sewardj32b2bbe2005-01-28 00:50:10 +00002912 }
2913}
sewardj3ca55a12005-01-27 16:06:23 +00002914
2915static
sewardj8c332e22005-01-28 01:36:56 +00002916ULong dis_Grp1 ( Prefix pfx,
sewardj270def42005-07-03 01:03:01 +00002917 Long delta, UChar modrm,
sewardj227458e2005-01-31 19:04:50 +00002918 Int am_sz, Int d_sz, Int sz, Long d64 )
sewardj3ca55a12005-01-27 16:06:23 +00002919{
2920 Int len;
2921 HChar dis_buf[50];
2922 IRType ty = szToITy(sz);
2923 IRTemp dst1 = newTemp(ty);
2924 IRTemp src = newTemp(ty);
2925 IRTemp dst0 = newTemp(ty);
2926 IRTemp addr = IRTemp_INVALID;
2927 IROp op8 = Iop_INVALID;
sewardj1389d4d2005-01-28 13:46:29 +00002928 ULong mask = mkSizeMask(sz);
sewardj3ca55a12005-01-27 16:06:23 +00002929
sewardj901ed122005-02-27 13:25:31 +00002930 switch (gregLO3ofRM(modrm)) {
sewardj3ca55a12005-01-27 16:06:23 +00002931 case 0: op8 = Iop_Add8; break; case 1: op8 = Iop_Or8; break;
2932 case 2: break; // ADC
2933 case 3: break; // SBB
2934 case 4: op8 = Iop_And8; break; case 5: op8 = Iop_Sub8; break;
2935 case 6: op8 = Iop_Xor8; break; case 7: op8 = Iop_Sub8; break;
sewardjfd4203c2007-03-21 00:21:56 +00002936 /*NOTREACHED*/
sewardj3ca55a12005-01-27 16:06:23 +00002937 default: vpanic("dis_Grp1(amd64): unhandled case");
2938 }
2939
2940 if (epartIsReg(modrm)) {
2941 vassert(am_sz == 1);
2942
sewardj5b470602005-02-27 13:10:48 +00002943 assign(dst0, getIRegE(sz,pfx,modrm));
sewardj227458e2005-01-31 19:04:50 +00002944 assign(src, mkU(ty,d64 & mask));
sewardj3ca55a12005-01-27 16:06:23 +00002945
sewardj901ed122005-02-27 13:25:31 +00002946 if (gregLO3ofRM(modrm) == 2 /* ADC */) {
sewardj3ca55a12005-01-27 16:06:23 +00002947 helper_ADC( sz, dst1, dst0, src );
2948 } else
sewardj901ed122005-02-27 13:25:31 +00002949 if (gregLO3ofRM(modrm) == 3 /* SBB */) {
sewardj3ca55a12005-01-27 16:06:23 +00002950 helper_SBB( sz, dst1, dst0, src );
2951 } else {
2952 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
2953 if (isAddSub(op8))
2954 setFlags_DEP1_DEP2(op8, dst0, src, ty);
2955 else
2956 setFlags_DEP1(op8, dst1, ty);
2957 }
2958
sewardj901ed122005-02-27 13:25:31 +00002959 if (gregLO3ofRM(modrm) < 7)
sewardj5b470602005-02-27 13:10:48 +00002960 putIRegE(sz, pfx, modrm, mkexpr(dst1));
sewardj3ca55a12005-01-27 16:06:23 +00002961
2962 delta += (am_sz + d_sz);
sewardje941eea2005-01-30 19:52:28 +00002963 DIP("%s%c $%lld, %s\n",
sewardj901ed122005-02-27 13:25:31 +00002964 nameGrp1(gregLO3ofRM(modrm)), nameISize(sz), d64,
sewardj5b470602005-02-27 13:10:48 +00002965 nameIRegE(sz,pfx,modrm));
sewardj3ca55a12005-01-27 16:06:23 +00002966 } else {
sewardje1698952005-02-08 15:02:39 +00002967 addr = disAMode ( &len, pfx, delta, dis_buf, /*xtra*/d_sz );
sewardj3ca55a12005-01-27 16:06:23 +00002968
2969 assign(dst0, loadLE(ty,mkexpr(addr)));
sewardj227458e2005-01-31 19:04:50 +00002970 assign(src, mkU(ty,d64 & mask));
sewardj3ca55a12005-01-27 16:06:23 +00002971
sewardj901ed122005-02-27 13:25:31 +00002972 if (gregLO3ofRM(modrm) == 2 /* ADC */) {
sewardj3ca55a12005-01-27 16:06:23 +00002973 helper_ADC( sz, dst1, dst0, src );
2974 } else
sewardj901ed122005-02-27 13:25:31 +00002975 if (gregLO3ofRM(modrm) == 3 /* SBB */) {
sewardj3ca55a12005-01-27 16:06:23 +00002976 helper_SBB( sz, dst1, dst0, src );
2977 } else {
2978 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
2979 if (isAddSub(op8))
2980 setFlags_DEP1_DEP2(op8, dst0, src, ty);
2981 else
2982 setFlags_DEP1(op8, dst1, ty);
2983 }
2984
sewardj901ed122005-02-27 13:25:31 +00002985 if (gregLO3ofRM(modrm) < 7)
sewardj3ca55a12005-01-27 16:06:23 +00002986 storeLE(mkexpr(addr), mkexpr(dst1));
2987
2988 delta += (len+d_sz);
sewardje941eea2005-01-30 19:52:28 +00002989 DIP("%s%c $%lld, %s\n",
sewardj901ed122005-02-27 13:25:31 +00002990 nameGrp1(gregLO3ofRM(modrm)), nameISize(sz),
sewardj227458e2005-01-31 19:04:50 +00002991 d64, dis_buf);
sewardj3ca55a12005-01-27 16:06:23 +00002992 }
2993 return delta;
2994}
2995
2996
sewardj118b23e2005-01-29 02:14:44 +00002997/* Group 2 extended opcodes. shift_expr must be an 8-bit typed
2998 expression. */
2999
3000static
3001ULong dis_Grp2 ( Prefix pfx,
sewardj270def42005-07-03 01:03:01 +00003002 Long delta, UChar modrm,
sewardj118b23e2005-01-29 02:14:44 +00003003 Int am_sz, Int d_sz, Int sz, IRExpr* shift_expr,
sewardjfd4203c2007-03-21 00:21:56 +00003004 HChar* shift_expr_txt, Bool* decode_OK )
sewardj118b23e2005-01-29 02:14:44 +00003005{
3006 /* delta on entry points at the modrm byte. */
3007 HChar dis_buf[50];
3008 Int len;
sewardjb5e5c6d2007-01-12 20:29:01 +00003009 Bool isShift, isRotate, isRotateC;
sewardj118b23e2005-01-29 02:14:44 +00003010 IRType ty = szToITy(sz);
3011 IRTemp dst0 = newTemp(ty);
3012 IRTemp dst1 = newTemp(ty);
3013 IRTemp addr = IRTemp_INVALID;
3014
sewardjfd4203c2007-03-21 00:21:56 +00003015 *decode_OK = True;
3016
sewardj118b23e2005-01-29 02:14:44 +00003017 vassert(sz == 1 || sz == 2 || sz == 4 || sz == 8);
3018
3019 /* Put value to shift/rotate in dst0. */
3020 if (epartIsReg(modrm)) {
sewardj5b470602005-02-27 13:10:48 +00003021 assign(dst0, getIRegE(sz, pfx, modrm));
sewardj118b23e2005-01-29 02:14:44 +00003022 delta += (am_sz + d_sz);
3023 } else {
sewardj3587c6b2005-08-14 00:09:58 +00003024 addr = disAMode ( &len, pfx, delta, dis_buf, /*xtra*/d_sz );
sewardj118b23e2005-01-29 02:14:44 +00003025 assign(dst0, loadLE(ty,mkexpr(addr)));
3026 delta += len + d_sz;
3027 }
3028
3029 isShift = False;
sewardj901ed122005-02-27 13:25:31 +00003030 switch (gregLO3ofRM(modrm)) { case 4: case 5: case 7: isShift = True; }
sewardj118b23e2005-01-29 02:14:44 +00003031
3032 isRotate = False;
sewardj901ed122005-02-27 13:25:31 +00003033 switch (gregLO3ofRM(modrm)) { case 0: case 1: isRotate = True; }
sewardj118b23e2005-01-29 02:14:44 +00003034
sewardjb5e5c6d2007-01-12 20:29:01 +00003035 isRotateC = False;
3036 switch (gregLO3ofRM(modrm)) { case 2: case 3: isRotateC = True; }
sewardj118b23e2005-01-29 02:14:44 +00003037
sewardjfd4203c2007-03-21 00:21:56 +00003038 if (gregLO3ofRM(modrm) == 6) {
3039 *decode_OK = False;
3040 return delta;
3041 }
3042
sewardjb5e5c6d2007-01-12 20:29:01 +00003043 if (!isShift && !isRotate && !isRotateC) {
sewardjfd4203c2007-03-21 00:21:56 +00003044 /*NOTREACHED*/
sewardj118b23e2005-01-29 02:14:44 +00003045 vpanic("dis_Grp2(Reg): unhandled case(amd64)");
3046 }
3047
sewardjb5e5c6d2007-01-12 20:29:01 +00003048 if (isRotateC) {
sewardj112b0992005-07-23 13:19:32 +00003049 /* Call a helper; this insn is so ridiculous it does not deserve
3050 better. One problem is, the helper has to calculate both the
3051 new value and the new flags. This is more than 64 bits, and
3052 there is no way to return more than 64 bits from the helper.
3053 Hence the crude and obvious solution is to call it twice,
3054 using the sign of the sz field to indicate whether it is the
3055 value or rflags result we want.
3056 */
sewardjb5e5c6d2007-01-12 20:29:01 +00003057 Bool left = toBool(gregLO3ofRM(modrm) == 2);
sewardj112b0992005-07-23 13:19:32 +00003058 IRExpr** argsVALUE;
3059 IRExpr** argsRFLAGS;
3060
3061 IRTemp new_value = newTemp(Ity_I64);
3062 IRTemp new_rflags = newTemp(Ity_I64);
3063 IRTemp old_rflags = newTemp(Ity_I64);
3064
3065 assign( old_rflags, widenUto64(mk_amd64g_calculate_rflags_all()) );
3066
3067 argsVALUE
3068 = mkIRExprVec_4( widenUto64(mkexpr(dst0)), /* thing to rotate */
3069 widenUto64(shift_expr), /* rotate amount */
3070 mkexpr(old_rflags),
3071 mkU64(sz) );
3072 assign( new_value,
3073 mkIRExprCCall(
3074 Ity_I64,
3075 0/*regparm*/,
sewardjb5e5c6d2007-01-12 20:29:01 +00003076 left ? "amd64g_calculate_RCL" : "amd64g_calculate_RCR",
3077 left ? &amd64g_calculate_RCL : &amd64g_calculate_RCR,
sewardj112b0992005-07-23 13:19:32 +00003078 argsVALUE
3079 )
3080 );
3081
3082 argsRFLAGS
3083 = mkIRExprVec_4( widenUto64(mkexpr(dst0)), /* thing to rotate */
3084 widenUto64(shift_expr), /* rotate amount */
3085 mkexpr(old_rflags),
3086 mkU64(-sz) );
3087 assign( new_rflags,
3088 mkIRExprCCall(
3089 Ity_I64,
3090 0/*regparm*/,
sewardjb5e5c6d2007-01-12 20:29:01 +00003091 left ? "amd64g_calculate_RCL" : "amd64g_calculate_RCR",
3092 left ? &amd64g_calculate_RCL : &amd64g_calculate_RCR,
sewardj112b0992005-07-23 13:19:32 +00003093 argsRFLAGS
3094 )
3095 );
3096
3097 assign( dst1, narrowTo(ty, mkexpr(new_value)) );
3098 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(AMD64G_CC_OP_COPY) ));
3099 stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(new_rflags) ));
3100 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
3101 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU64(0) ));
sewardj118b23e2005-01-29 02:14:44 +00003102 }
3103
sewardj112b0992005-07-23 13:19:32 +00003104 else
sewardj118b23e2005-01-29 02:14:44 +00003105 if (isShift) {
3106
3107 IRTemp pre64 = newTemp(Ity_I64);
3108 IRTemp res64 = newTemp(Ity_I64);
3109 IRTemp res64ss = newTemp(Ity_I64);
3110 IRTemp shift_amt = newTemp(Ity_I8);
sewardj1027dc22005-02-26 01:55:02 +00003111 UChar mask = toUChar(sz==8 ? 63 : 31);
sewardj118b23e2005-01-29 02:14:44 +00003112 IROp op64;
3113
sewardj901ed122005-02-27 13:25:31 +00003114 switch (gregLO3ofRM(modrm)) {
sewardj118b23e2005-01-29 02:14:44 +00003115 case 4: op64 = Iop_Shl64; break;
3116 case 5: op64 = Iop_Shr64; break;
3117 case 7: op64 = Iop_Sar64; break;
sewardjfd4203c2007-03-21 00:21:56 +00003118 /*NOTREACHED*/
sewardj118b23e2005-01-29 02:14:44 +00003119 default: vpanic("dis_Grp2:shift"); break;
3120 }
3121
3122 /* Widen the value to be shifted to 64 bits, do the shift, and
3123 narrow back down. This seems surprisingly long-winded, but
3124 unfortunately the AMD semantics requires that 8/16/32-bit
3125 shifts give defined results for shift values all the way up
sewardj03c96e82005-02-19 18:12:45 +00003126 to 32, and this seems the simplest way to do it. It has the
sewardj118b23e2005-01-29 02:14:44 +00003127 advantage that the only IR level shifts generated are of 64
3128 bit values, and the shift amount is guaranteed to be in the
3129 range 0 .. 63, thereby observing the IR semantics requiring
sewardj03c96e82005-02-19 18:12:45 +00003130 all shift values to be in the range 0 .. 2^word_size-1.
sewardj118b23e2005-01-29 02:14:44 +00003131
sewardj03c96e82005-02-19 18:12:45 +00003132 Therefore the shift amount is masked with 63 for 64-bit shifts
3133 and 31 for all others.
3134 */
3135 /* shift_amt = shift_expr & MASK, regardless of operation size */
3136 assign( shift_amt, binop(Iop_And8, shift_expr, mkU8(mask)) );
sewardj118b23e2005-01-29 02:14:44 +00003137
sewardj03c96e82005-02-19 18:12:45 +00003138 /* suitably widen the value to be shifted to 64 bits. */
sewardj118b23e2005-01-29 02:14:44 +00003139 assign( pre64, op64==Iop_Sar64 ? widenSto64(mkexpr(dst0))
3140 : widenUto64(mkexpr(dst0)) );
3141
3142 /* res64 = pre64 `shift` shift_amt */
3143 assign( res64, binop(op64, mkexpr(pre64), mkexpr(shift_amt)) );
3144
sewardj03c96e82005-02-19 18:12:45 +00003145 /* res64ss = pre64 `shift` ((shift_amt - 1) & MASK) */
sewardj118b23e2005-01-29 02:14:44 +00003146 assign( res64ss,
3147 binop(op64,
3148 mkexpr(pre64),
3149 binop(Iop_And8,
3150 binop(Iop_Sub8,
3151 mkexpr(shift_amt), mkU8(1)),
sewardj03c96e82005-02-19 18:12:45 +00003152 mkU8(mask))) );
sewardj118b23e2005-01-29 02:14:44 +00003153
3154 /* Build the flags thunk. */
3155 setFlags_DEP1_DEP2_shift(op64, res64, res64ss, ty, shift_amt);
3156
3157 /* Narrow the result back down. */
3158 assign( dst1, narrowTo(ty, mkexpr(res64)) );
3159
3160 } /* if (isShift) */
3161
3162 else
3163 if (isRotate) {
3164 Int ccOp = ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1
3165 : (ty==Ity_I32 ? 2 : 3));
sewardj901ed122005-02-27 13:25:31 +00003166 Bool left = toBool(gregLO3ofRM(modrm) == 0);
sewardj118b23e2005-01-29 02:14:44 +00003167 IRTemp rot_amt = newTemp(Ity_I8);
3168 IRTemp rot_amt64 = newTemp(Ity_I8);
3169 IRTemp oldFlags = newTemp(Ity_I64);
sewardj1027dc22005-02-26 01:55:02 +00003170 UChar mask = toUChar(sz==8 ? 63 : 31);
sewardj118b23e2005-01-29 02:14:44 +00003171
3172 /* rot_amt = shift_expr & mask */
3173 /* By masking the rotate amount thusly, the IR-level Shl/Shr
3174 expressions never shift beyond the word size and thus remain
3175 well defined. */
sewardj03c96e82005-02-19 18:12:45 +00003176 assign(rot_amt64, binop(Iop_And8, shift_expr, mkU8(mask)));
sewardj118b23e2005-01-29 02:14:44 +00003177
3178 if (ty == Ity_I64)
3179 assign(rot_amt, mkexpr(rot_amt64));
3180 else
3181 assign(rot_amt, binop(Iop_And8, mkexpr(rot_amt64), mkU8(8*sz-1)));
3182
3183 if (left) {
3184
3185 /* dst1 = (dst0 << rot_amt) | (dst0 >>u (wordsize-rot_amt)) */
3186 assign(dst1,
3187 binop( mkSizedOp(ty,Iop_Or8),
3188 binop( mkSizedOp(ty,Iop_Shl8),
3189 mkexpr(dst0),
3190 mkexpr(rot_amt)
3191 ),
3192 binop( mkSizedOp(ty,Iop_Shr8),
3193 mkexpr(dst0),
3194 binop(Iop_Sub8,mkU8(8*sz), mkexpr(rot_amt))
3195 )
3196 )
3197 );
3198 ccOp += AMD64G_CC_OP_ROLB;
3199
3200 } else { /* right */
3201
3202 /* dst1 = (dst0 >>u rot_amt) | (dst0 << (wordsize-rot_amt)) */
3203 assign(dst1,
3204 binop( mkSizedOp(ty,Iop_Or8),
3205 binop( mkSizedOp(ty,Iop_Shr8),
3206 mkexpr(dst0),
3207 mkexpr(rot_amt)
3208 ),
3209 binop( mkSizedOp(ty,Iop_Shl8),
3210 mkexpr(dst0),
3211 binop(Iop_Sub8,mkU8(8*sz), mkexpr(rot_amt))
3212 )
3213 )
3214 );
3215 ccOp += AMD64G_CC_OP_RORB;
3216
3217 }
3218
3219 /* dst1 now holds the rotated value. Build flag thunk. We
3220 need the resulting value for this, and the previous flags.
3221 Except don't set it if the rotate count is zero. */
3222
3223 assign(oldFlags, mk_amd64g_calculate_rflags_all());
3224
3225 /* CC_DEP1 is the rotated value. CC_NDEP is flags before. */
3226 stmt( IRStmt_Put( OFFB_CC_OP,
3227 IRExpr_Mux0X( mkexpr(rot_amt64),
3228 IRExpr_Get(OFFB_CC_OP,Ity_I64),
3229 mkU64(ccOp))) );
3230 stmt( IRStmt_Put( OFFB_CC_DEP1,
3231 IRExpr_Mux0X( mkexpr(rot_amt64),
3232 IRExpr_Get(OFFB_CC_DEP1,Ity_I64),
3233 widenUto64(mkexpr(dst1)))) );
3234 stmt( IRStmt_Put( OFFB_CC_DEP2,
3235 IRExpr_Mux0X( mkexpr(rot_amt64),
3236 IRExpr_Get(OFFB_CC_DEP2,Ity_I64),
3237 mkU64(0))) );
3238 stmt( IRStmt_Put( OFFB_CC_NDEP,
3239 IRExpr_Mux0X( mkexpr(rot_amt64),
3240 IRExpr_Get(OFFB_CC_NDEP,Ity_I64),
3241 mkexpr(oldFlags))) );
3242 } /* if (isRotate) */
3243
3244 /* Save result, and finish up. */
3245 if (epartIsReg(modrm)) {
sewardj5b470602005-02-27 13:10:48 +00003246 putIRegE(sz, pfx, modrm, mkexpr(dst1));
sewardj118b23e2005-01-29 02:14:44 +00003247 if (vex_traceflags & VEX_TRACE_FE) {
3248 vex_printf("%s%c ",
sewardj901ed122005-02-27 13:25:31 +00003249 nameGrp2(gregLO3ofRM(modrm)), nameISize(sz) );
sewardj118b23e2005-01-29 02:14:44 +00003250 if (shift_expr_txt)
3251 vex_printf("%s", shift_expr_txt);
3252 else
3253 ppIRExpr(shift_expr);
sewardj5b470602005-02-27 13:10:48 +00003254 vex_printf(", %s\n", nameIRegE(sz,pfx,modrm));
sewardj118b23e2005-01-29 02:14:44 +00003255 }
3256 } else {
3257 storeLE(mkexpr(addr), mkexpr(dst1));
3258 if (vex_traceflags & VEX_TRACE_FE) {
3259 vex_printf("%s%c ",
sewardj901ed122005-02-27 13:25:31 +00003260 nameGrp2(gregLO3ofRM(modrm)), nameISize(sz) );
sewardj118b23e2005-01-29 02:14:44 +00003261 if (shift_expr_txt)
3262 vex_printf("%s", shift_expr_txt);
3263 else
3264 ppIRExpr(shift_expr);
3265 vex_printf(", %s\n", dis_buf);
3266 }
3267 }
3268 return delta;
3269}
3270
3271
sewardj1d511802005-03-27 17:59:45 +00003272/* Group 8 extended opcodes (but BT/BTS/BTC/BTR only). */
3273static
3274ULong dis_Grp8_Imm ( Prefix pfx,
sewardj270def42005-07-03 01:03:01 +00003275 Long delta, UChar modrm,
sewardj1d511802005-03-27 17:59:45 +00003276 Int am_sz, Int sz, ULong src_val,
3277 Bool* decode_OK )
3278{
3279 /* src_val denotes a d8.
3280 And delta on entry points at the modrm byte. */
sewardj118b23e2005-01-29 02:14:44 +00003281
sewardj1d511802005-03-27 17:59:45 +00003282 IRType ty = szToITy(sz);
3283 IRTemp t2 = newTemp(Ity_I64);
3284 IRTemp t2m = newTemp(Ity_I64);
3285 IRTemp t_addr = IRTemp_INVALID;
3286 HChar dis_buf[50];
3287 ULong mask;
sewardj9b967672005-02-08 11:13:09 +00003288
sewardj1d511802005-03-27 17:59:45 +00003289 /* we're optimists :-) */
3290 *decode_OK = True;
3291
3292 /* Limit src_val -- the bit offset -- to something within a word.
3293 The Intel docs say that literal offsets larger than a word are
3294 masked in this way. */
3295 switch (sz) {
3296 case 2: src_val &= 15; break;
3297 case 4: src_val &= 31; break;
sewardj537cab02005-04-07 02:03:52 +00003298 case 8: src_val &= 63; break;
sewardj1d511802005-03-27 17:59:45 +00003299 default: *decode_OK = False; return delta;
3300 }
3301
3302 /* Invent a mask suitable for the operation. */
3303 switch (gregLO3ofRM(modrm)) {
sewardj74b4f892005-05-06 01:43:56 +00003304 case 4: /* BT */ mask = 0; break;
3305 case 5: /* BTS */ mask = 1ULL << src_val; break;
3306 case 6: /* BTR */ mask = ~(1ULL << src_val); break;
3307 case 7: /* BTC */ mask = 1ULL << src_val; break;
sewardj1d511802005-03-27 17:59:45 +00003308 /* If this needs to be extended, probably simplest to make a
3309 new function to handle the other cases (0 .. 3). The
3310 Intel docs do however not indicate any use for 0 .. 3, so
3311 we don't expect this to happen. */
3312 default: *decode_OK = False; return delta;
3313 }
3314
3315 /* Fetch the value to be tested and modified into t2, which is
3316 64-bits wide regardless of sz. */
3317 if (epartIsReg(modrm)) {
3318 vassert(am_sz == 1);
3319 assign( t2, widenUto64(getIRegE(sz, pfx, modrm)) );
3320 delta += (am_sz + 1);
3321 DIP("%s%c $0x%llx, %s\n", nameGrp8(gregLO3ofRM(modrm)),
3322 nameISize(sz),
3323 src_val, nameIRegE(sz,pfx,modrm));
3324 } else {
3325 Int len;
3326 t_addr = disAMode ( &len, pfx, delta, dis_buf, 1 );
3327 delta += (len+1);
3328 assign( t2, widenUto64(loadLE(ty, mkexpr(t_addr))) );
3329 DIP("%s%c $0x%llx, %s\n", nameGrp8(gregLO3ofRM(modrm)),
3330 nameISize(sz),
3331 src_val, dis_buf);
3332 }
3333
3334 /* Copy relevant bit from t2 into the carry flag. */
3335 /* Flags: C=selected bit, O,S,Z,A,P undefined, so are set to zero. */
3336 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(AMD64G_CC_OP_COPY) ));
3337 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
3338 stmt( IRStmt_Put(
3339 OFFB_CC_DEP1,
3340 binop(Iop_And64,
3341 binop(Iop_Shr64, mkexpr(t2), mkU8(src_val)),
3342 mkU64(1))
3343 ));
3344
3345 /* Compute the new value into t2m, if non-BT. */
3346 switch (gregLO3ofRM(modrm)) {
3347 case 4: /* BT */
3348 break;
3349 case 5: /* BTS */
3350 assign( t2m, binop(Iop_Or64, mkU64(mask), mkexpr(t2)) );
3351 break;
3352 case 6: /* BTR */
3353 assign( t2m, binop(Iop_And64, mkU64(mask), mkexpr(t2)) );
3354 break;
3355 case 7: /* BTC */
3356 assign( t2m, binop(Iop_Xor64, mkU64(mask), mkexpr(t2)) );
3357 break;
3358 default:
3359 vassert(0);
3360 }
3361
3362 /* Write the result back, if non-BT. */
3363 if (gregLO3ofRM(modrm) != 4 /* BT */) {
3364 if (epartIsReg(modrm)) {
3365 putIRegE(sz, pfx, modrm, narrowTo(ty, mkexpr(t2m)));
3366 } else {
3367 storeLE(mkexpr(t_addr), narrowTo(ty, mkexpr(t2m)));
3368 }
3369 }
3370
3371 return delta;
3372}
sewardj9b967672005-02-08 11:13:09 +00003373
3374
3375/* Signed/unsigned widening multiply. Generate IR to multiply the
3376 value in RAX/EAX/AX/AL by the given IRTemp, and park the result in
3377 RDX:RAX/EDX:EAX/DX:AX/AX.
3378*/
3379static void codegen_mulL_A_D ( Int sz, Bool syned,
sewardj1027dc22005-02-26 01:55:02 +00003380 IRTemp tmp, HChar* tmp_txt )
sewardj9b967672005-02-08 11:13:09 +00003381{
3382 IRType ty = szToITy(sz);
3383 IRTemp t1 = newTemp(ty);
3384
sewardj5b470602005-02-27 13:10:48 +00003385 assign( t1, getIRegRAX(sz) );
sewardj9b967672005-02-08 11:13:09 +00003386
3387 switch (ty) {
3388 case Ity_I64: {
3389 IRTemp res128 = newTemp(Ity_I128);
3390 IRTemp resHi = newTemp(Ity_I64);
3391 IRTemp resLo = newTemp(Ity_I64);
3392 IROp mulOp = syned ? Iop_MullS64 : Iop_MullU64;
sewardj8bdb89a2005-05-05 21:46:50 +00003393 UInt tBaseOp = syned ? AMD64G_CC_OP_SMULB : AMD64G_CC_OP_UMULB;
sewardj9b967672005-02-08 11:13:09 +00003394 setFlags_MUL ( Ity_I64, t1, tmp, tBaseOp );
3395 assign( res128, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
3396 assign( resHi, unop(Iop_128HIto64,mkexpr(res128)));
3397 assign( resLo, unop(Iop_128to64,mkexpr(res128)));
sewardj5b470602005-02-27 13:10:48 +00003398 putIReg64(R_RDX, mkexpr(resHi));
3399 putIReg64(R_RAX, mkexpr(resLo));
sewardj9b967672005-02-08 11:13:09 +00003400 break;
3401 }
sewardj85520e42005-02-19 15:22:38 +00003402 case Ity_I32: {
3403 IRTemp res64 = newTemp(Ity_I64);
3404 IRTemp resHi = newTemp(Ity_I32);
3405 IRTemp resLo = newTemp(Ity_I32);
3406 IROp mulOp = syned ? Iop_MullS32 : Iop_MullU32;
3407 UInt tBaseOp = syned ? AMD64G_CC_OP_SMULB : AMD64G_CC_OP_UMULB;
3408 setFlags_MUL ( Ity_I32, t1, tmp, tBaseOp );
3409 assign( res64, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
3410 assign( resHi, unop(Iop_64HIto32,mkexpr(res64)));
3411 assign( resLo, unop(Iop_64to32,mkexpr(res64)));
sewardj5b470602005-02-27 13:10:48 +00003412 putIRegRDX(4, mkexpr(resHi));
3413 putIRegRAX(4, mkexpr(resLo));
sewardj85520e42005-02-19 15:22:38 +00003414 break;
3415 }
3416 case Ity_I16: {
3417 IRTemp res32 = newTemp(Ity_I32);
3418 IRTemp resHi = newTemp(Ity_I16);
3419 IRTemp resLo = newTemp(Ity_I16);
3420 IROp mulOp = syned ? Iop_MullS16 : Iop_MullU16;
3421 UInt tBaseOp = syned ? AMD64G_CC_OP_SMULB : AMD64G_CC_OP_UMULB;
3422 setFlags_MUL ( Ity_I16, t1, tmp, tBaseOp );
3423 assign( res32, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
3424 assign( resHi, unop(Iop_32HIto16,mkexpr(res32)));
3425 assign( resLo, unop(Iop_32to16,mkexpr(res32)));
sewardj5b470602005-02-27 13:10:48 +00003426 putIRegRDX(2, mkexpr(resHi));
3427 putIRegRAX(2, mkexpr(resLo));
sewardj85520e42005-02-19 15:22:38 +00003428 break;
3429 }
3430 case Ity_I8: {
3431 IRTemp res16 = newTemp(Ity_I16);
3432 IRTemp resHi = newTemp(Ity_I8);
3433 IRTemp resLo = newTemp(Ity_I8);
3434 IROp mulOp = syned ? Iop_MullS8 : Iop_MullU8;
3435 UInt tBaseOp = syned ? AMD64G_CC_OP_SMULB : AMD64G_CC_OP_UMULB;
3436 setFlags_MUL ( Ity_I8, t1, tmp, tBaseOp );
3437 assign( res16, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
3438 assign( resHi, unop(Iop_16HIto8,mkexpr(res16)));
3439 assign( resLo, unop(Iop_16to8,mkexpr(res16)));
sewardj5b470602005-02-27 13:10:48 +00003440 putIRegRAX(2, mkexpr(res16));
sewardj85520e42005-02-19 15:22:38 +00003441 break;
3442 }
sewardj9b967672005-02-08 11:13:09 +00003443 default:
sewardj85520e42005-02-19 15:22:38 +00003444 ppIRType(ty);
sewardj9b967672005-02-08 11:13:09 +00003445 vpanic("codegen_mulL_A_D(amd64)");
3446 }
3447 DIP("%s%c %s\n", syned ? "imul" : "mul", nameISize(sz), tmp_txt);
3448}
sewardj32b2bbe2005-01-28 00:50:10 +00003449
3450
3451/* Group 3 extended opcodes. */
3452static
sewardjfd4203c2007-03-21 00:21:56 +00003453ULong dis_Grp3 ( Prefix pfx, Int sz, Long delta, Bool* decode_OK )
sewardj32b2bbe2005-01-28 00:50:10 +00003454{
sewardj227458e2005-01-31 19:04:50 +00003455 Long d64;
sewardj32b2bbe2005-01-28 00:50:10 +00003456 UChar modrm;
3457 HChar dis_buf[50];
3458 Int len;
3459 IRTemp addr;
3460 IRType ty = szToITy(sz);
3461 IRTemp t1 = newTemp(ty);
sewardj55dbb262005-01-28 16:36:51 +00003462 IRTemp dst1, src, dst0;
sewardjfd4203c2007-03-21 00:21:56 +00003463 *decode_OK = True;
sewardj8c332e22005-01-28 01:36:56 +00003464 modrm = getUChar(delta);
sewardj32b2bbe2005-01-28 00:50:10 +00003465 if (epartIsReg(modrm)) {
sewardj901ed122005-02-27 13:25:31 +00003466 switch (gregLO3ofRM(modrm)) {
sewardj118b23e2005-01-29 02:14:44 +00003467 case 0: { /* TEST */
3468 delta++;
3469 d64 = getSDisp(imin(4,sz), delta);
3470 delta += imin(4,sz);
3471 dst1 = newTemp(ty);
3472 assign(dst1, binop(mkSizedOp(ty,Iop_And8),
sewardj5b470602005-02-27 13:10:48 +00003473 getIRegE(sz,pfx,modrm),
sewardj03b07cc2005-01-31 18:09:43 +00003474 mkU(ty, d64 & mkSizeMask(sz))));
sewardj118b23e2005-01-29 02:14:44 +00003475 setFlags_DEP1( Iop_And8, dst1, ty );
sewardj7eaa7cf2005-01-31 18:55:22 +00003476 DIP("test%c $%lld, %s\n",
sewardj118b23e2005-01-29 02:14:44 +00003477 nameISize(sz), d64,
sewardj5b470602005-02-27 13:10:48 +00003478 nameIRegE(sz, pfx, modrm));
sewardj118b23e2005-01-29 02:14:44 +00003479 break;
3480 }
sewardjfd4203c2007-03-21 00:21:56 +00003481 case 1:
3482 *decode_OK = False;
3483 return delta;
sewardj55dbb262005-01-28 16:36:51 +00003484 case 2: /* NOT */
3485 delta++;
sewardj5b470602005-02-27 13:10:48 +00003486 putIRegE(sz, pfx, modrm,
3487 unop(mkSizedOp(ty,Iop_Not8),
3488 getIRegE(sz, pfx, modrm)));
sewardj55dbb262005-01-28 16:36:51 +00003489 DIP("not%c %s\n", nameISize(sz),
sewardj5b470602005-02-27 13:10:48 +00003490 nameIRegE(sz, pfx, modrm));
sewardj55dbb262005-01-28 16:36:51 +00003491 break;
3492 case 3: /* NEG */
3493 delta++;
3494 dst0 = newTemp(ty);
3495 src = newTemp(ty);
3496 dst1 = newTemp(ty);
3497 assign(dst0, mkU(ty,0));
sewardj5b470602005-02-27 13:10:48 +00003498 assign(src, getIRegE(sz, pfx, modrm));
sewardj55dbb262005-01-28 16:36:51 +00003499 assign(dst1, binop(mkSizedOp(ty,Iop_Sub8), mkexpr(dst0), mkexpr(src)));
3500 setFlags_DEP1_DEP2(Iop_Sub8, dst0, src, ty);
sewardj5b470602005-02-27 13:10:48 +00003501 putIRegE(sz, pfx, modrm, mkexpr(dst1));
3502 DIP("neg%c %s\n", nameISize(sz), nameIRegE(sz, pfx, modrm));
sewardj55dbb262005-01-28 16:36:51 +00003503 break;
sewardj9b967672005-02-08 11:13:09 +00003504 case 4: /* MUL (unsigned widening) */
3505 delta++;
3506 src = newTemp(ty);
sewardj5b470602005-02-27 13:10:48 +00003507 assign(src, getIRegE(sz,pfx,modrm));
sewardj9b967672005-02-08 11:13:09 +00003508 codegen_mulL_A_D ( sz, False, src,
sewardj5b470602005-02-27 13:10:48 +00003509 nameIRegE(sz,pfx,modrm) );
sewardj9b967672005-02-08 11:13:09 +00003510 break;
sewardj85520e42005-02-19 15:22:38 +00003511 case 5: /* IMUL (signed widening) */
3512 delta++;
3513 src = newTemp(ty);
sewardj5b470602005-02-27 13:10:48 +00003514 assign(src, getIRegE(sz,pfx,modrm));
sewardj85520e42005-02-19 15:22:38 +00003515 codegen_mulL_A_D ( sz, True, src,
sewardj5b470602005-02-27 13:10:48 +00003516 nameIRegE(sz,pfx,modrm) );
sewardj85520e42005-02-19 15:22:38 +00003517 break;
sewardj03b07cc2005-01-31 18:09:43 +00003518 case 6: /* DIV */
3519 delta++;
sewardj5b470602005-02-27 13:10:48 +00003520 assign( t1, getIRegE(sz, pfx, modrm) );
sewardj03b07cc2005-01-31 18:09:43 +00003521 codegen_div ( sz, t1, False );
3522 DIP("div%c %s\n", nameISize(sz),
sewardj5b470602005-02-27 13:10:48 +00003523 nameIRegE(sz, pfx, modrm));
sewardj03b07cc2005-01-31 18:09:43 +00003524 break;
sewardj32b2bbe2005-01-28 00:50:10 +00003525 case 7: /* IDIV */
3526 delta++;
sewardj5b470602005-02-27 13:10:48 +00003527 assign( t1, getIRegE(sz, pfx, modrm) );
sewardj32b2bbe2005-01-28 00:50:10 +00003528 codegen_div ( sz, t1, True );
3529 DIP("idiv%c %s\n", nameISize(sz),
sewardj5b470602005-02-27 13:10:48 +00003530 nameIRegE(sz, pfx, modrm));
sewardj32b2bbe2005-01-28 00:50:10 +00003531 break;
3532 default:
sewardjfd4203c2007-03-21 00:21:56 +00003533 /*NOTREACHED*/
3534 vpanic("Grp3(amd64,R)");
sewardj32b2bbe2005-01-28 00:50:10 +00003535 }
3536 } else {
sewardj7de0d3c2005-02-13 02:26:41 +00003537 addr = disAMode ( &len, pfx, delta, dis_buf,
3538 /* we have to inform disAMode of any immediate
3539 bytes used */
sewardj901ed122005-02-27 13:25:31 +00003540 gregLO3ofRM(modrm)==0/*TEST*/
sewardj7de0d3c2005-02-13 02:26:41 +00003541 ? imin(4,sz)
3542 : 0
3543 );
sewardj32b2bbe2005-01-28 00:50:10 +00003544 t1 = newTemp(ty);
3545 delta += len;
3546 assign(t1, loadLE(ty,mkexpr(addr)));
sewardj901ed122005-02-27 13:25:31 +00003547 switch (gregLO3ofRM(modrm)) {
sewardj03b07cc2005-01-31 18:09:43 +00003548 case 0: { /* TEST */
3549 d64 = getSDisp(imin(4,sz), delta);
3550 delta += imin(4,sz);
3551 dst1 = newTemp(ty);
3552 assign(dst1, binop(mkSizedOp(ty,Iop_And8),
3553 mkexpr(t1),
3554 mkU(ty, d64 & mkSizeMask(sz))));
3555 setFlags_DEP1( Iop_And8, dst1, ty );
3556 DIP("test%c $%lld, %s\n", nameISize(sz), d64, dis_buf);
3557 break;
3558 }
sewardjfd4203c2007-03-21 00:21:56 +00003559 case 1:
3560 *decode_OK = False;
3561 return delta;
sewardj82c9f2f2005-03-02 16:05:13 +00003562 case 2: /* NOT */
3563 storeLE( mkexpr(addr), unop(mkSizedOp(ty,Iop_Not8), mkexpr(t1)));
3564 DIP("not%c %s\n", nameISize(sz), dis_buf);
3565 break;
sewardj7de0d3c2005-02-13 02:26:41 +00003566 case 3: /* NEG */
3567 dst0 = newTemp(ty);
3568 src = newTemp(ty);
3569 dst1 = newTemp(ty);
3570 assign(dst0, mkU(ty,0));
3571 assign(src, mkexpr(t1));
3572 assign(dst1, binop(mkSizedOp(ty,Iop_Sub8), mkexpr(dst0), mkexpr(src)));
3573 setFlags_DEP1_DEP2(Iop_Sub8, dst0, src, ty);
3574 storeLE( mkexpr(addr), mkexpr(dst1) );
3575 DIP("neg%c %s\n", nameISize(sz), dis_buf);
3576 break;
sewardj31eecde2005-03-23 03:39:55 +00003577 case 4: /* MUL (unsigned widening) */
3578 codegen_mulL_A_D ( sz, False, t1, dis_buf );
3579 break;
sewardj3aba9eb2005-03-30 23:20:47 +00003580 case 5: /* IMUL */
3581 codegen_mulL_A_D ( sz, True, t1, dis_buf );
3582 break;
sewardj1001dc42005-02-21 08:25:55 +00003583 case 6: /* DIV */
3584 codegen_div ( sz, t1, False );
3585 DIP("div%c %s\n", nameISize(sz), dis_buf);
3586 break;
sewardj82c9f2f2005-03-02 16:05:13 +00003587 case 7: /* IDIV */
3588 codegen_div ( sz, t1, True );
3589 DIP("idiv%c %s\n", nameISize(sz), dis_buf);
3590 break;
sewardj32b2bbe2005-01-28 00:50:10 +00003591 default:
sewardjfd4203c2007-03-21 00:21:56 +00003592 /*NOTREACHED*/
3593 vpanic("Grp3(amd64,M)");
sewardj32b2bbe2005-01-28 00:50:10 +00003594 }
3595 }
3596 return delta;
3597}
3598
3599
sewardj03b07cc2005-01-31 18:09:43 +00003600/* Group 4 extended opcodes. */
3601static
sewardjfd4203c2007-03-21 00:21:56 +00003602ULong dis_Grp4 ( Prefix pfx, Long delta, Bool* decode_OK )
sewardj03b07cc2005-01-31 18:09:43 +00003603{
3604 Int alen;
3605 UChar modrm;
3606 HChar dis_buf[50];
3607 IRType ty = Ity_I8;
3608 IRTemp t1 = newTemp(ty);
3609 IRTemp t2 = newTemp(ty);
3610
sewardjfd4203c2007-03-21 00:21:56 +00003611 *decode_OK = True;
3612
sewardj03b07cc2005-01-31 18:09:43 +00003613 modrm = getUChar(delta);
3614 if (epartIsReg(modrm)) {
sewardj5b470602005-02-27 13:10:48 +00003615 assign(t1, getIRegE(1, pfx, modrm));
sewardj901ed122005-02-27 13:25:31 +00003616 switch (gregLO3ofRM(modrm)) {
sewardj85520e42005-02-19 15:22:38 +00003617 case 0: /* INC */
3618 assign(t2, binop(Iop_Add8, mkexpr(t1), mkU8(1)));
sewardj5b470602005-02-27 13:10:48 +00003619 putIRegE(1, pfx, modrm, mkexpr(t2));
sewardj85520e42005-02-19 15:22:38 +00003620 setFlags_INC_DEC( True, t2, ty );
3621 break;
sewardj03b07cc2005-01-31 18:09:43 +00003622 case 1: /* DEC */
3623 assign(t2, binop(Iop_Sub8, mkexpr(t1), mkU8(1)));
sewardj5b470602005-02-27 13:10:48 +00003624 putIRegE(1, pfx, modrm, mkexpr(t2));
sewardj03b07cc2005-01-31 18:09:43 +00003625 setFlags_INC_DEC( False, t2, ty );
3626 break;
3627 default:
sewardjfd4203c2007-03-21 00:21:56 +00003628 *decode_OK = False;
3629 return delta;
sewardj03b07cc2005-01-31 18:09:43 +00003630 }
3631 delta++;
sewardj901ed122005-02-27 13:25:31 +00003632 DIP("%sb %s\n", nameGrp4(gregLO3ofRM(modrm)),
sewardj5b470602005-02-27 13:10:48 +00003633 nameIRegE(1, pfx, modrm));
sewardj03b07cc2005-01-31 18:09:43 +00003634 } else {
sewardje1698952005-02-08 15:02:39 +00003635 IRTemp addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
sewardj03b07cc2005-01-31 18:09:43 +00003636 assign( t1, loadLE(ty, mkexpr(addr)) );
sewardj901ed122005-02-27 13:25:31 +00003637 switch (gregLO3ofRM(modrm)) {
sewardj007e9ec2005-03-23 11:36:48 +00003638 case 0: /* INC */
3639 assign(t2, binop(Iop_Add8, mkexpr(t1), mkU8(1)));
3640 storeLE( mkexpr(addr), mkexpr(t2) );
3641 setFlags_INC_DEC( True, t2, ty );
3642 break;
3643 case 1: /* DEC */
3644 assign(t2, binop(Iop_Sub8, mkexpr(t1), mkU8(1)));
3645 storeLE( mkexpr(addr), mkexpr(t2) );
3646 setFlags_INC_DEC( False, t2, ty );
3647 break;
sewardj03b07cc2005-01-31 18:09:43 +00003648 default:
sewardjfd4203c2007-03-21 00:21:56 +00003649 *decode_OK = False;
3650 return delta;
sewardj03b07cc2005-01-31 18:09:43 +00003651 }
3652 delta += alen;
sewardj901ed122005-02-27 13:25:31 +00003653 DIP("%sb %s\n", nameGrp4(gregLO3ofRM(modrm)), dis_buf);
sewardj03b07cc2005-01-31 18:09:43 +00003654 }
3655 return delta;
3656}
sewardj354e5c62005-01-27 20:12:52 +00003657
3658
3659/* Group 5 extended opcodes. */
3660static
sewardjdd40fdf2006-12-24 02:20:24 +00003661ULong dis_Grp5 ( VexAbiInfo* vbi,
sewardjfd4203c2007-03-21 00:21:56 +00003662 Prefix pfx, Int sz, Long delta,
3663 DisResult* dres, Bool* decode_OK )
sewardj354e5c62005-01-27 20:12:52 +00003664{
3665 Int len;
3666 UChar modrm;
3667 HChar dis_buf[50];
3668 IRTemp addr = IRTemp_INVALID;
3669 IRType ty = szToITy(sz);
3670 IRTemp t1 = newTemp(ty);
3671 IRTemp t2 = IRTemp_INVALID;
sewardj03b07cc2005-01-31 18:09:43 +00003672 IRTemp t3 = IRTemp_INVALID;
sewardj7eaa7cf2005-01-31 18:55:22 +00003673 Bool showSz = True;
sewardj354e5c62005-01-27 20:12:52 +00003674
sewardjfd4203c2007-03-21 00:21:56 +00003675 *decode_OK = True;
3676
sewardj8c332e22005-01-28 01:36:56 +00003677 modrm = getUChar(delta);
sewardj354e5c62005-01-27 20:12:52 +00003678 if (epartIsReg(modrm)) {
sewardj5b470602005-02-27 13:10:48 +00003679 assign(t1, getIRegE(sz,pfx,modrm));
sewardj901ed122005-02-27 13:25:31 +00003680 switch (gregLO3ofRM(modrm)) {
sewardj32b2bbe2005-01-28 00:50:10 +00003681 case 0: /* INC */
3682 t2 = newTemp(ty);
3683 assign(t2, binop(mkSizedOp(ty,Iop_Add8),
3684 mkexpr(t1), mkU(ty,1)));
3685 setFlags_INC_DEC( True, t2, ty );
sewardj5b470602005-02-27 13:10:48 +00003686 putIRegE(sz,pfx,modrm, mkexpr(t2));
sewardj32b2bbe2005-01-28 00:50:10 +00003687 break;
3688 case 1: /* DEC */
3689 t2 = newTemp(ty);
3690 assign(t2, binop(mkSizedOp(ty,Iop_Sub8),
3691 mkexpr(t1), mkU(ty,1)));
3692 setFlags_INC_DEC( False, t2, ty );
sewardj5b470602005-02-27 13:10:48 +00003693 putIRegE(sz,pfx,modrm, mkexpr(t2));
sewardj32b2bbe2005-01-28 00:50:10 +00003694 break;
sewardj354e5c62005-01-27 20:12:52 +00003695 case 2: /* call Ev */
sewardj03b07cc2005-01-31 18:09:43 +00003696 /* Ignore any sz value and operate as if sz==8. */
sewardjb7bcdf92005-08-02 21:20:36 +00003697 vassert(sz == 4 || sz == 8);
sewardj03b07cc2005-01-31 18:09:43 +00003698 sz = 8;
3699 t3 = newTemp(Ity_I64);
sewardj5b470602005-02-27 13:10:48 +00003700 assign(t3, getIRegE(sz,pfx,modrm));
sewardj03b07cc2005-01-31 18:09:43 +00003701 t2 = newTemp(Ity_I64);
3702 assign(t2, binop(Iop_Sub64, getIReg64(R_RSP), mkU64(8)));
3703 putIReg64(R_RSP, mkexpr(t2));
sewardj9e6491a2005-07-02 19:24:10 +00003704 storeLE( mkexpr(t2), mkU64(guest_RIP_bbstart+delta+1));
sewardjdd40fdf2006-12-24 02:20:24 +00003705 make_redzone_AbiHint(vbi, t2, "call-Ev(reg)");
sewardj03b07cc2005-01-31 18:09:43 +00003706 jmp_treg(Ijk_Call,t3);
sewardj9e6491a2005-07-02 19:24:10 +00003707 dres->whatNext = Dis_StopHere;
sewardj7eaa7cf2005-01-31 18:55:22 +00003708 showSz = False;
sewardj354e5c62005-01-27 20:12:52 +00003709 break;
sewardj354e5c62005-01-27 20:12:52 +00003710 case 4: /* jmp Ev */
sewardj03b07cc2005-01-31 18:09:43 +00003711 /* Ignore any sz value and operate as if sz==8. */
sewardj0bfc6b62005-07-07 14:15:35 +00003712 vassert(sz == 4 || sz == 8);
sewardj03b07cc2005-01-31 18:09:43 +00003713 sz = 8;
3714 t3 = newTemp(Ity_I64);
sewardj5b470602005-02-27 13:10:48 +00003715 assign(t3, getIRegE(sz,pfx,modrm));
sewardj03b07cc2005-01-31 18:09:43 +00003716 jmp_treg(Ijk_Boring,t3);
sewardj9e6491a2005-07-02 19:24:10 +00003717 dres->whatNext = Dis_StopHere;
sewardj7eaa7cf2005-01-31 18:55:22 +00003718 showSz = False;
sewardj354e5c62005-01-27 20:12:52 +00003719 break;
sewardj354e5c62005-01-27 20:12:52 +00003720 default:
sewardjfd4203c2007-03-21 00:21:56 +00003721 *decode_OK = False;
3722 return delta;
sewardj354e5c62005-01-27 20:12:52 +00003723 }
3724 delta++;
sewardj901ed122005-02-27 13:25:31 +00003725 DIP("%s%c %s\n", nameGrp5(gregLO3ofRM(modrm)),
sewardj7eaa7cf2005-01-31 18:55:22 +00003726 showSz ? nameISize(sz) : ' ',
sewardj5b470602005-02-27 13:10:48 +00003727 nameIRegE(sz, pfx, modrm));
sewardj354e5c62005-01-27 20:12:52 +00003728 } else {
sewardje1698952005-02-08 15:02:39 +00003729 addr = disAMode ( &len, pfx, delta, dis_buf, 0 );
sewardj901ed122005-02-27 13:25:31 +00003730 if (gregLO3ofRM(modrm) != 2 && gregLO3ofRM(modrm) != 4
3731 && gregLO3ofRM(modrm) != 6) {
sewardj03b07cc2005-01-31 18:09:43 +00003732 assign(t1, loadLE(ty,mkexpr(addr)));
sewardj909c06d2005-02-19 22:47:41 +00003733 }
sewardj901ed122005-02-27 13:25:31 +00003734 switch (gregLO3ofRM(modrm)) {
sewardj354e5c62005-01-27 20:12:52 +00003735 case 0: /* INC */
sewardj354e5c62005-01-27 20:12:52 +00003736 t2 = newTemp(ty);
3737 assign(t2, binop(mkSizedOp(ty,Iop_Add8),
3738 mkexpr(t1), mkU(ty,1)));
3739 setFlags_INC_DEC( True, t2, ty );
3740 storeLE(mkexpr(addr),mkexpr(t2));
3741 break;
sewardj354e5c62005-01-27 20:12:52 +00003742 case 1: /* DEC */
3743 t2 = newTemp(ty);
3744 assign(t2, binop(mkSizedOp(ty,Iop_Sub8),
3745 mkexpr(t1), mkU(ty,1)));
3746 setFlags_INC_DEC( False, t2, ty );
3747 storeLE(mkexpr(addr),mkexpr(t2));
3748 break;
3749 case 2: /* call Ev */
sewardj03b07cc2005-01-31 18:09:43 +00003750 /* Ignore any sz value and operate as if sz==8. */
sewardj354e5c62005-01-27 20:12:52 +00003751 vassert(sz == 4);
sewardj7eaa7cf2005-01-31 18:55:22 +00003752 sz = 8;
sewardj03b07cc2005-01-31 18:09:43 +00003753 t3 = newTemp(Ity_I64);
3754 assign(t3, loadLE(Ity_I64,mkexpr(addr)));
3755 t2 = newTemp(Ity_I64);
3756 assign(t2, binop(Iop_Sub64, getIReg64(R_RSP), mkU64(8)));
3757 putIReg64(R_RSP, mkexpr(t2));
sewardj9e6491a2005-07-02 19:24:10 +00003758 storeLE( mkexpr(t2), mkU64(guest_RIP_bbstart+delta+len));
sewardjdd40fdf2006-12-24 02:20:24 +00003759 make_redzone_AbiHint(vbi, t2, "call-Ev(mem)");
sewardj03b07cc2005-01-31 18:09:43 +00003760 jmp_treg(Ijk_Call,t3);
sewardj9e6491a2005-07-02 19:24:10 +00003761 dres->whatNext = Dis_StopHere;
sewardj7eaa7cf2005-01-31 18:55:22 +00003762 showSz = False;
sewardj354e5c62005-01-27 20:12:52 +00003763 break;
sewardj354e5c62005-01-27 20:12:52 +00003764 case 4: /* JMP Ev */
sewardj03b07cc2005-01-31 18:09:43 +00003765 /* Ignore any sz value and operate as if sz==8. */
sewardj354e5c62005-01-27 20:12:52 +00003766 vassert(sz == 4);
sewardj7eaa7cf2005-01-31 18:55:22 +00003767 sz = 8;
sewardj03b07cc2005-01-31 18:09:43 +00003768 t3 = newTemp(Ity_I64);
3769 assign(t3, loadLE(Ity_I64,mkexpr(addr)));
3770 jmp_treg(Ijk_Boring,t3);
sewardj9e6491a2005-07-02 19:24:10 +00003771 dres->whatNext = Dis_StopHere;
sewardj7eaa7cf2005-01-31 18:55:22 +00003772 showSz = False;
sewardj354e5c62005-01-27 20:12:52 +00003773 break;
sewardj354e5c62005-01-27 20:12:52 +00003774 case 6: /* PUSH Ev */
sewardja6b93d12005-02-17 09:28:28 +00003775 /* There is no encoding for 32-bit operand size; hence ... */
3776 if (sz == 4) sz = 8;
3777 vassert(sz == 8 || sz == 2);
sewardj909c06d2005-02-19 22:47:41 +00003778 if (sz == 8) {
3779 t3 = newTemp(Ity_I64);
3780 assign(t3, loadLE(Ity_I64,mkexpr(addr)));
3781 t2 = newTemp(Ity_I64);
3782 assign( t2, binop(Iop_Sub64,getIReg64(R_RSP),mkU64(sz)) );
3783 putIReg64(R_RSP, mkexpr(t2) );
3784 storeLE( mkexpr(t2), mkexpr(t3) );
3785 break;
3786 } else {
3787 goto unhandled; /* awaiting test case */
3788 }
sewardj354e5c62005-01-27 20:12:52 +00003789 default:
sewardja6b93d12005-02-17 09:28:28 +00003790 unhandled:
sewardjfd4203c2007-03-21 00:21:56 +00003791 *decode_OK = False;
3792 return delta;
sewardj354e5c62005-01-27 20:12:52 +00003793 }
3794 delta += len;
sewardj901ed122005-02-27 13:25:31 +00003795 DIP("%s%c %s\n", nameGrp5(gregLO3ofRM(modrm)),
sewardj7eaa7cf2005-01-31 18:55:22 +00003796 showSz ? nameISize(sz) : ' ',
3797 dis_buf);
sewardj354e5c62005-01-27 20:12:52 +00003798 }
3799 return delta;
3800}
3801
3802
sewardjd0a12df2005-02-10 02:07:43 +00003803/*------------------------------------------------------------*/
3804/*--- Disassembling string ops (including REP prefixes) ---*/
3805/*------------------------------------------------------------*/
3806
3807/* Code shared by all the string ops */
3808static
3809void dis_string_op_increment ( Int sz, IRTemp t_inc )
3810{
3811 UChar logSz;
3812 if (sz == 8 || sz == 4 || sz == 2) {
3813 logSz = 1;
3814 if (sz == 4) logSz = 2;
3815 if (sz == 8) logSz = 3;
3816 assign( t_inc,
3817 binop(Iop_Shl64, IRExpr_Get( OFFB_DFLAG, Ity_I64 ),
3818 mkU8(logSz) ) );
3819 } else {
3820 assign( t_inc,
3821 IRExpr_Get( OFFB_DFLAG, Ity_I64 ) );
3822 }
3823}
3824
sewardj909c06d2005-02-19 22:47:41 +00003825static
3826void dis_string_op( void (*dis_OP)( Int, IRTemp ),
3827 Int sz, HChar* name, Prefix pfx )
3828{
3829 IRTemp t_inc = newTemp(Ity_I64);
3830 /* Really we ought to inspect the override prefixes, but we don't.
3831 The following assertion catches any resulting sillyness. */
3832 vassert(pfx == clearSegBits(pfx));
3833 dis_string_op_increment(sz, t_inc);
3834 dis_OP( sz, t_inc );
3835 DIP("%s%c\n", name, nameISize(sz));
3836}
3837
3838static
3839void dis_MOVS ( Int sz, IRTemp t_inc )
3840{
3841 IRType ty = szToITy(sz);
3842 IRTemp td = newTemp(Ity_I64); /* RDI */
3843 IRTemp ts = newTemp(Ity_I64); /* RSI */
3844
3845 assign( td, getIReg64(R_RDI) );
3846 assign( ts, getIReg64(R_RSI) );
3847
3848 storeLE( mkexpr(td), loadLE(ty,mkexpr(ts)) );
3849
3850 putIReg64( R_RDI, binop(Iop_Add64, mkexpr(td), mkexpr(t_inc)) );
3851 putIReg64( R_RSI, binop(Iop_Add64, mkexpr(ts), mkexpr(t_inc)) );
3852}
3853
sewardjd20c8852005-01-20 20:04:07 +00003854//.. //-- static
3855//.. //-- void dis_LODS ( UCodeBlock* cb, Int sz, Int t_inc )
3856//.. //-- {
3857//.. //-- Int ta = newTemp(cb); /* EAX */
3858//.. //-- Int ts = newTemp(cb); /* ESI */
3859//.. //--
3860//.. //-- uInstr2(cb, GET, 4, ArchReg, R_ESI, TempReg, ts);
3861//.. //-- uInstr2(cb, LOAD, sz, TempReg, ts, TempReg, ta);
3862//.. //-- uInstr2(cb, PUT, sz, TempReg, ta, ArchReg, R_EAX);
3863//.. //--
3864//.. //-- uInstr2(cb, ADD, 4, TempReg, t_inc, TempReg, ts);
3865//.. //-- uInstr2(cb, PUT, 4, TempReg, ts, ArchReg, R_ESI);
3866//.. //-- }
sewardja6b93d12005-02-17 09:28:28 +00003867
3868static
3869void dis_STOS ( Int sz, IRTemp t_inc )
3870{
3871 IRType ty = szToITy(sz);
3872 IRTemp ta = newTemp(ty); /* rAX */
3873 IRTemp td = newTemp(Ity_I64); /* RDI */
3874
sewardj5b470602005-02-27 13:10:48 +00003875 assign( ta, getIRegRAX(sz) );
sewardja6b93d12005-02-17 09:28:28 +00003876
3877 assign( td, getIReg64(R_RDI) );
3878
3879 storeLE( mkexpr(td), mkexpr(ta) );
3880
3881 putIReg64( R_RDI, binop(Iop_Add64, mkexpr(td), mkexpr(t_inc)) );
3882}
sewardjd0a12df2005-02-10 02:07:43 +00003883
3884static
3885void dis_CMPS ( Int sz, IRTemp t_inc )
3886{
3887 IRType ty = szToITy(sz);
3888 IRTemp tdv = newTemp(ty); /* (RDI) */
3889 IRTemp tsv = newTemp(ty); /* (RSI) */
3890 IRTemp td = newTemp(Ity_I64); /* RDI */
3891 IRTemp ts = newTemp(Ity_I64); /* RSI */
3892
3893 assign( td, getIReg64(R_RDI) );
3894
3895 assign( ts, getIReg64(R_RSI) );
3896
3897 assign( tdv, loadLE(ty,mkexpr(td)) );
3898
3899 assign( tsv, loadLE(ty,mkexpr(ts)) );
3900
3901 setFlags_DEP1_DEP2 ( Iop_Sub8, tsv, tdv, ty );
3902
3903 putIReg64(R_RDI, binop(Iop_Add64, mkexpr(td), mkexpr(t_inc)) );
3904
3905 putIReg64(R_RSI, binop(Iop_Add64, mkexpr(ts), mkexpr(t_inc)) );
3906}
3907
sewardj85520e42005-02-19 15:22:38 +00003908static
3909void dis_SCAS ( Int sz, IRTemp t_inc )
3910{
3911 IRType ty = szToITy(sz);
3912 IRTemp ta = newTemp(ty); /* rAX */
3913 IRTemp td = newTemp(Ity_I64); /* RDI */
3914 IRTemp tdv = newTemp(ty); /* (RDI) */
3915
sewardj5b470602005-02-27 13:10:48 +00003916 assign( ta, getIRegRAX(sz) );
sewardj85520e42005-02-19 15:22:38 +00003917
3918 assign( td, getIReg64(R_RDI) );
3919
3920 assign( tdv, loadLE(ty,mkexpr(td)) );
3921
3922 setFlags_DEP1_DEP2 ( Iop_Sub8, ta, tdv, ty );
3923
3924 putIReg64(R_RDI, binop(Iop_Add64, mkexpr(td), mkexpr(t_inc)) );
3925}
sewardjd0a12df2005-02-10 02:07:43 +00003926
3927
3928/* Wrap the appropriate string op inside a REP/REPE/REPNE. We assume
3929 the insn is the last one in the basic block, and so emit a jump to
3930 the next insn, rather than just falling through. */
3931static
3932void dis_REP_op ( AMD64Condcode cond,
3933 void (*dis_OP)(Int, IRTemp),
sewardj909c06d2005-02-19 22:47:41 +00003934 Int sz, Addr64 rip, Addr64 rip_next, HChar* name,
3935 Prefix pfx )
sewardjd0a12df2005-02-10 02:07:43 +00003936{
3937 IRTemp t_inc = newTemp(Ity_I64);
3938 IRTemp tc = newTemp(Ity_I64); /* RCX */
3939
sewardj909c06d2005-02-19 22:47:41 +00003940 /* Really we ought to inspect the override prefixes, but we don't.
3941 The following assertion catches any resulting sillyness. */
3942 vassert(pfx == clearSegBits(pfx));
3943
sewardjd0a12df2005-02-10 02:07:43 +00003944 assign( tc, getIReg64(R_RCX) );
3945
3946 stmt( IRStmt_Exit( binop(Iop_CmpEQ64,mkexpr(tc),mkU64(0)),
3947 Ijk_Boring,
3948 IRConst_U64(rip_next) ) );
3949
3950 putIReg64(R_RCX, binop(Iop_Sub64, mkexpr(tc), mkU64(1)) );
3951
3952 dis_string_op_increment(sz, t_inc);
3953 dis_OP (sz, t_inc);
3954
3955 if (cond == AMD64CondAlways) {
3956 jmp_lit(Ijk_Boring,rip);
3957 } else {
3958 stmt( IRStmt_Exit( mk_amd64g_calculate_condition(cond),
3959 Ijk_Boring,
3960 IRConst_U64(rip) ) );
3961 jmp_lit(Ijk_Boring,rip_next);
3962 }
3963 DIP("%s%c\n", name, nameISize(sz));
3964}
sewardj32b2bbe2005-01-28 00:50:10 +00003965
3966
3967/*------------------------------------------------------------*/
3968/*--- Arithmetic, etc. ---*/
3969/*------------------------------------------------------------*/
3970
3971/* IMUL E, G. Supplied eip points to the modR/M byte. */
3972static
3973ULong dis_mul_E_G ( Prefix pfx,
3974 Int size,
sewardj270def42005-07-03 01:03:01 +00003975 Long delta0 )
sewardj32b2bbe2005-01-28 00:50:10 +00003976{
3977 Int alen;
3978 HChar dis_buf[50];
sewardj8c332e22005-01-28 01:36:56 +00003979 UChar rm = getUChar(delta0);
sewardj32b2bbe2005-01-28 00:50:10 +00003980 IRType ty = szToITy(size);
3981 IRTemp te = newTemp(ty);
3982 IRTemp tg = newTemp(ty);
3983 IRTemp resLo = newTemp(ty);
3984
sewardj5b470602005-02-27 13:10:48 +00003985 assign( tg, getIRegG(size, pfx, rm) );
sewardj32b2bbe2005-01-28 00:50:10 +00003986 if (epartIsReg(rm)) {
sewardj5b470602005-02-27 13:10:48 +00003987 assign( te, getIRegE(size, pfx, rm) );
sewardj32b2bbe2005-01-28 00:50:10 +00003988 } else {
sewardje1698952005-02-08 15:02:39 +00003989 IRTemp addr = disAMode( &alen, pfx, delta0, dis_buf, 0 );
sewardj32b2bbe2005-01-28 00:50:10 +00003990 assign( te, loadLE(ty,mkexpr(addr)) );
3991 }
3992
3993 setFlags_MUL ( ty, te, tg, AMD64G_CC_OP_SMULB );
3994
3995 assign( resLo, binop( mkSizedOp(ty, Iop_Mul8), mkexpr(te), mkexpr(tg) ) );
3996
sewardj5b470602005-02-27 13:10:48 +00003997 putIRegG(size, pfx, rm, mkexpr(resLo) );
sewardj32b2bbe2005-01-28 00:50:10 +00003998
3999 if (epartIsReg(rm)) {
4000 DIP("imul%c %s, %s\n", nameISize(size),
sewardj901ed122005-02-27 13:25:31 +00004001 nameIRegE(size,pfx,rm),
4002 nameIRegG(size,pfx,rm));
sewardj32b2bbe2005-01-28 00:50:10 +00004003 return 1+delta0;
4004 } else {
4005 DIP("imul%c %s, %s\n", nameISize(size),
4006 dis_buf,
sewardj901ed122005-02-27 13:25:31 +00004007 nameIRegG(size,pfx,rm));
sewardj32b2bbe2005-01-28 00:50:10 +00004008 return alen+delta0;
4009 }
4010}
4011
4012
4013/* IMUL I * E -> G. Supplied rip points to the modR/M byte. */
4014static
4015ULong dis_imul_I_E_G ( Prefix pfx,
4016 Int size,
sewardj270def42005-07-03 01:03:01 +00004017 Long delta,
sewardj32b2bbe2005-01-28 00:50:10 +00004018 Int litsize )
4019{
4020 Long d64;
4021 Int alen;
4022 HChar dis_buf[50];
sewardj8c332e22005-01-28 01:36:56 +00004023 UChar rm = getUChar(delta);
sewardj32b2bbe2005-01-28 00:50:10 +00004024 IRType ty = szToITy(size);
4025 IRTemp te = newTemp(ty);
4026 IRTemp tl = newTemp(ty);
4027 IRTemp resLo = newTemp(ty);
4028
sewardj85520e42005-02-19 15:22:38 +00004029 vassert(/*size == 1 ||*/ size == 2 || size == 4 || size == 8);
sewardj32b2bbe2005-01-28 00:50:10 +00004030
4031 if (epartIsReg(rm)) {
sewardj5b470602005-02-27 13:10:48 +00004032 assign(te, getIRegE(size, pfx, rm));
sewardj32b2bbe2005-01-28 00:50:10 +00004033 delta++;
4034 } else {
sewardj7de0d3c2005-02-13 02:26:41 +00004035 IRTemp addr = disAMode( &alen, pfx, delta, dis_buf,
4036 imin(4,litsize) );
sewardj32b2bbe2005-01-28 00:50:10 +00004037 assign(te, loadLE(ty, mkexpr(addr)));
4038 delta += alen;
4039 }
4040 d64 = getSDisp(imin(4,litsize),delta);
4041 delta += imin(4,litsize);
4042
sewardj1389d4d2005-01-28 13:46:29 +00004043 d64 &= mkSizeMask(size);
sewardj32b2bbe2005-01-28 00:50:10 +00004044 assign(tl, mkU(ty,d64));
4045
4046 assign( resLo, binop( mkSizedOp(ty, Iop_Mul8), mkexpr(te), mkexpr(tl) ));
4047
4048 setFlags_MUL ( ty, te, tl, AMD64G_CC_OP_SMULB );
4049
sewardj5b470602005-02-27 13:10:48 +00004050 putIRegG(size, pfx, rm, mkexpr(resLo));
sewardj32b2bbe2005-01-28 00:50:10 +00004051
4052 DIP("imul%c $%lld, %s, %s\n",
4053 nameISize(size), d64,
sewardj5b470602005-02-27 13:10:48 +00004054 ( epartIsReg(rm) ? nameIRegE(size,pfx,rm) : dis_buf ),
4055 nameIRegG(size,pfx,rm) );
sewardj32b2bbe2005-01-28 00:50:10 +00004056 return delta;
4057}
4058
4059
sewardjbcbb9de2005-03-27 02:22:32 +00004060/*------------------------------------------------------------*/
4061/*--- ---*/
4062/*--- x87 FLOATING POINT INSTRUCTIONS ---*/
4063/*--- ---*/
4064/*------------------------------------------------------------*/
4065
4066/* --- Helper functions for dealing with the register stack. --- */
4067
4068/* --- Set the emulation-warning pseudo-register. --- */
4069
4070static void put_emwarn ( IRExpr* e /* :: Ity_I32 */ )
4071{
sewardjdd40fdf2006-12-24 02:20:24 +00004072 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I32);
sewardjbcbb9de2005-03-27 02:22:32 +00004073 stmt( IRStmt_Put( OFFB_EMWARN, e ) );
4074}
sewardj8d965312005-02-25 02:48:47 +00004075
4076/* --- Produce an IRExpr* denoting a 64-bit QNaN. --- */
4077
4078static IRExpr* mkQNaN64 ( void )
4079{
4080 /* QNaN is 0 2047 1 0(51times)
4081 == 0b 11111111111b 1 0(51times)
4082 == 0x7FF8 0000 0000 0000
4083 */
4084 return IRExpr_Const(IRConst_F64i(0x7FF8000000000000ULL));
4085}
4086
4087/* --------- Get/put the top-of-stack pointer :: Ity_I32 --------- */
4088
4089static IRExpr* get_ftop ( void )
4090{
4091 return IRExpr_Get( OFFB_FTOP, Ity_I32 );
4092}
4093
4094static void put_ftop ( IRExpr* e )
4095{
sewardjdd40fdf2006-12-24 02:20:24 +00004096 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I32);
sewardj8d965312005-02-25 02:48:47 +00004097 stmt( IRStmt_Put( OFFB_FTOP, e ) );
4098}
4099
sewardj25a85812005-05-08 23:03:48 +00004100/* --------- Get/put the C3210 bits. --------- */
4101
4102static IRExpr* /* :: Ity_I64 */ get_C3210 ( void )
4103{
4104 return IRExpr_Get( OFFB_FC3210, Ity_I64 );
4105}
4106
4107static void put_C3210 ( IRExpr* e /* :: Ity_I64 */ )
4108{
sewardjdd40fdf2006-12-24 02:20:24 +00004109 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I64);
sewardj25a85812005-05-08 23:03:48 +00004110 stmt( IRStmt_Put( OFFB_FC3210, e ) );
4111}
sewardjc49ce232005-02-25 13:03:03 +00004112
4113/* --------- Get/put the FPU rounding mode. --------- */
4114static IRExpr* /* :: Ity_I32 */ get_fpround ( void )
4115{
4116 return unop(Iop_64to32, IRExpr_Get( OFFB_FPROUND, Ity_I64 ));
4117}
4118
sewardj5e205372005-05-09 02:57:08 +00004119static void put_fpround ( IRExpr* /* :: Ity_I32 */ e )
4120{
sewardjdd40fdf2006-12-24 02:20:24 +00004121 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I32);
sewardj5e205372005-05-09 02:57:08 +00004122 stmt( IRStmt_Put( OFFB_FPROUND, unop(Iop_32Uto64,e) ) );
4123}
sewardjc49ce232005-02-25 13:03:03 +00004124
4125
4126/* --------- Synthesise a 2-bit FPU rounding mode. --------- */
4127/* Produces a value in 0 .. 3, which is encoded as per the type
4128 IRRoundingMode. Since the guest_FPROUND value is also encoded as
4129 per IRRoundingMode, we merely need to get it and mask it for
4130 safety.
4131*/
4132static IRExpr* /* :: Ity_I32 */ get_roundingmode ( void )
4133{
4134 return binop( Iop_And32, get_fpround(), mkU32(3) );
4135}
sewardj8d965312005-02-25 02:48:47 +00004136
sewardj4796d662006-02-05 16:06:26 +00004137static IRExpr* /* :: Ity_I32 */ get_FAKE_roundingmode ( void )
4138{
4139 return mkU32(Irrm_NEAREST);
4140}
4141
sewardj8d965312005-02-25 02:48:47 +00004142
4143/* --------- Get/set FP register tag bytes. --------- */
4144
4145/* Given i, and some expression e, generate 'ST_TAG(i) = e'. */
4146
4147static void put_ST_TAG ( Int i, IRExpr* value )
4148{
sewardjdd40fdf2006-12-24 02:20:24 +00004149 IRRegArray* descr;
4150 vassert(typeOfIRExpr(irsb->tyenv, value) == Ity_I8);
4151 descr = mkIRRegArray( OFFB_FPTAGS, Ity_I8, 8 );
sewardj8d965312005-02-25 02:48:47 +00004152 stmt( IRStmt_PutI( descr, get_ftop(), i, value ) );
4153}
4154
4155/* Given i, generate an expression yielding 'ST_TAG(i)'. This will be
4156 zero to indicate "Empty" and nonzero to indicate "NonEmpty". */
4157
4158static IRExpr* get_ST_TAG ( Int i )
4159{
sewardjdd40fdf2006-12-24 02:20:24 +00004160 IRRegArray* descr = mkIRRegArray( OFFB_FPTAGS, Ity_I8, 8 );
sewardj8d965312005-02-25 02:48:47 +00004161 return IRExpr_GetI( descr, get_ftop(), i );
4162}
4163
4164
4165/* --------- Get/set FP registers. --------- */
4166
4167/* Given i, and some expression e, emit 'ST(i) = e' and set the
4168 register's tag to indicate the register is full. The previous
4169 state of the register is not checked. */
4170
4171static void put_ST_UNCHECKED ( Int i, IRExpr* value )
4172{
sewardjdd40fdf2006-12-24 02:20:24 +00004173 IRRegArray* descr;
4174 vassert(typeOfIRExpr(irsb->tyenv, value) == Ity_F64);
4175 descr = mkIRRegArray( OFFB_FPREGS, Ity_F64, 8 );
sewardj8d965312005-02-25 02:48:47 +00004176 stmt( IRStmt_PutI( descr, get_ftop(), i, value ) );
4177 /* Mark the register as in-use. */
4178 put_ST_TAG(i, mkU8(1));
4179}
4180
4181/* Given i, and some expression e, emit
4182 ST(i) = is_full(i) ? NaN : e
4183 and set the tag accordingly.
4184*/
4185
4186static void put_ST ( Int i, IRExpr* value )
4187{
4188 put_ST_UNCHECKED( i,
4189 IRExpr_Mux0X( get_ST_TAG(i),
4190 /* 0 means empty */
4191 value,
4192 /* non-0 means full */
4193 mkQNaN64()
4194 )
4195 );
4196}
4197
4198
4199/* Given i, generate an expression yielding 'ST(i)'. */
4200
4201static IRExpr* get_ST_UNCHECKED ( Int i )
4202{
sewardjdd40fdf2006-12-24 02:20:24 +00004203 IRRegArray* descr = mkIRRegArray( OFFB_FPREGS, Ity_F64, 8 );
sewardj8d965312005-02-25 02:48:47 +00004204 return IRExpr_GetI( descr, get_ftop(), i );
4205}
4206
4207
4208/* Given i, generate an expression yielding
4209 is_full(i) ? ST(i) : NaN
4210*/
4211
4212static IRExpr* get_ST ( Int i )
4213{
4214 return
4215 IRExpr_Mux0X( get_ST_TAG(i),
4216 /* 0 means empty */
4217 mkQNaN64(),
4218 /* non-0 means full */
4219 get_ST_UNCHECKED(i));
4220}
4221
4222
4223/* Adjust FTOP downwards by one register. */
4224
4225static void fp_push ( void )
4226{
4227 put_ftop( binop(Iop_Sub32, get_ftop(), mkU32(1)) );
4228}
4229
4230/* Adjust FTOP upwards by one register, and mark the vacated register
4231 as empty. */
4232
4233static void fp_pop ( void )
4234{
4235 put_ST_TAG(0, mkU8(0));
4236 put_ftop( binop(Iop_Add32, get_ftop(), mkU32(1)) );
4237}
4238
sewardj25a85812005-05-08 23:03:48 +00004239/* Clear the C2 bit of the FPU status register, for
4240 sin/cos/tan/sincos. */
4241
4242static void clear_C2 ( void )
4243{
4244 put_C3210( binop(Iop_And64, get_C3210(), mkU64(~AMD64G_FC_MASK_C2)) );
4245}
sewardj48a89d82005-05-06 11:50:13 +00004246
sewardj7c2d2822006-03-07 00:22:02 +00004247/* Invent a plausible-looking FPU status word value:
4248 ((ftop & 7) << 11) | (c3210 & 0x4700)
4249 */
4250static IRExpr* get_FPU_sw ( void )
4251{
4252 return
4253 unop(Iop_32to16,
4254 binop(Iop_Or32,
4255 binop(Iop_Shl32,
4256 binop(Iop_And32, get_ftop(), mkU32(7)),
4257 mkU8(11)),
4258 binop(Iop_And32, unop(Iop_64to32, get_C3210()),
4259 mkU32(0x4700))
4260 ));
4261}
4262
sewardj48a89d82005-05-06 11:50:13 +00004263
4264/* ------------------------------------------------------- */
4265/* Given all that stack-mangling junk, we can now go ahead
4266 and describe FP instructions.
4267*/
4268
4269/* ST(0) = ST(0) `op` mem64/32(addr)
4270 Need to check ST(0)'s tag on read, but not on write.
4271*/
4272static
sewardjca673ab2005-05-11 10:03:08 +00004273void fp_do_op_mem_ST_0 ( IRTemp addr, HChar* op_txt, HChar* dis_buf,
sewardj48a89d82005-05-06 11:50:13 +00004274 IROp op, Bool dbl )
4275{
4276 DIP("f%s%c %s\n", op_txt, dbl?'l':'s', dis_buf);
4277 if (dbl) {
4278 put_ST_UNCHECKED(0,
sewardj4796d662006-02-05 16:06:26 +00004279 triop( op,
4280 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardj48a89d82005-05-06 11:50:13 +00004281 get_ST(0),
4282 loadLE(Ity_F64,mkexpr(addr))
4283 ));
4284 } else {
4285 put_ST_UNCHECKED(0,
sewardj4796d662006-02-05 16:06:26 +00004286 triop( op,
4287 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardj48a89d82005-05-06 11:50:13 +00004288 get_ST(0),
4289 unop(Iop_F32toF64, loadLE(Ity_F32,mkexpr(addr)))
4290 ));
4291 }
4292}
sewardj7bc00082005-03-27 05:08:32 +00004293
4294
4295/* ST(0) = mem64/32(addr) `op` ST(0)
4296 Need to check ST(0)'s tag on read, but not on write.
4297*/
4298static
4299void fp_do_oprev_mem_ST_0 ( IRTemp addr, HChar* op_txt, HChar* dis_buf,
4300 IROp op, Bool dbl )
4301{
4302 DIP("f%s%c %s\n", op_txt, dbl?'l':'s', dis_buf);
4303 if (dbl) {
4304 put_ST_UNCHECKED(0,
sewardj4796d662006-02-05 16:06:26 +00004305 triop( op,
4306 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardj7bc00082005-03-27 05:08:32 +00004307 loadLE(Ity_F64,mkexpr(addr)),
4308 get_ST(0)
4309 ));
4310 } else {
4311 put_ST_UNCHECKED(0,
sewardj4796d662006-02-05 16:06:26 +00004312 triop( op,
4313 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardj7bc00082005-03-27 05:08:32 +00004314 unop(Iop_F32toF64, loadLE(Ity_F32,mkexpr(addr))),
4315 get_ST(0)
4316 ));
4317 }
4318}
sewardj37d52572005-02-25 14:22:12 +00004319
4320
4321/* ST(dst) = ST(dst) `op` ST(src).
4322 Check dst and src tags when reading but not on write.
4323*/
4324static
4325void fp_do_op_ST_ST ( HChar* op_txt, IROp op, UInt st_src, UInt st_dst,
4326 Bool pop_after )
4327{
sewardj1027dc22005-02-26 01:55:02 +00004328 DIP("f%s%s st(%u), st(%u)\n", op_txt, pop_after?"p":"", st_src, st_dst );
sewardj37d52572005-02-25 14:22:12 +00004329 put_ST_UNCHECKED(
4330 st_dst,
sewardj4796d662006-02-05 16:06:26 +00004331 triop( op,
4332 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4333 get_ST(st_dst),
4334 get_ST(st_src) )
sewardj37d52572005-02-25 14:22:12 +00004335 );
4336 if (pop_after)
4337 fp_pop();
4338}
4339
sewardj137015d2005-03-27 04:01:15 +00004340/* ST(dst) = ST(src) `op` ST(dst).
4341 Check dst and src tags when reading but not on write.
4342*/
4343static
4344void fp_do_oprev_ST_ST ( HChar* op_txt, IROp op, UInt st_src, UInt st_dst,
4345 Bool pop_after )
4346{
4347 DIP("f%s%s st(%u), st(%u)\n", op_txt, pop_after?"p":"", st_src, st_dst );
4348 put_ST_UNCHECKED(
4349 st_dst,
sewardj4796d662006-02-05 16:06:26 +00004350 triop( op,
4351 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4352 get_ST(st_src),
4353 get_ST(st_dst) )
sewardj137015d2005-03-27 04:01:15 +00004354 );
4355 if (pop_after)
4356 fp_pop();
4357}
sewardjc49ce232005-02-25 13:03:03 +00004358
4359/* %rflags(Z,P,C) = UCOMI( st(0), st(i) ) */
4360static void fp_do_ucomi_ST0_STi ( UInt i, Bool pop_after )
4361{
sewardj1027dc22005-02-26 01:55:02 +00004362 DIP("fucomi%s %%st(0),%%st(%u)\n", pop_after ? "p" : "", i);
sewardjc49ce232005-02-25 13:03:03 +00004363 /* This is a bit of a hack (and isn't really right). It sets
4364 Z,P,C,O correctly, but forces A and S to zero, whereas the Intel
4365 documentation implies A and S are unchanged.
4366 */
4367 /* It's also fishy in that it is used both for COMIP and
4368 UCOMIP, and they aren't the same (although similar). */
4369 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(AMD64G_CC_OP_COPY) ));
4370 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
4371 stmt( IRStmt_Put(
4372 OFFB_CC_DEP1,
4373 binop( Iop_And64,
4374 unop( Iop_32Uto64,
4375 binop(Iop_CmpF64, get_ST(0), get_ST(i))),
4376 mkU64(0x45)
4377 )));
4378 if (pop_after)
4379 fp_pop();
4380}
sewardj8d965312005-02-25 02:48:47 +00004381
4382
sewardjb707d102007-07-11 22:49:26 +00004383/* returns
4384 32to16( if e32 <s -32768 || e32 >s 32767 then -32768 else e32 )
4385*/
4386static IRExpr* x87ishly_qnarrow_32_to_16 ( IRExpr* e32 )
4387{
4388 IRTemp t32 = newTemp(Ity_I32);
4389 assign( t32, e32 );
4390 return
4391 IRExpr_Mux0X(
4392 unop(Iop_1Uto8,
4393 binop(Iop_CmpLT64U,
4394 unop(Iop_32Uto64,
4395 binop(Iop_Add32, mkexpr(t32), mkU32(32768))),
4396 mkU64(65536))),
4397 mkU16( 0x8000 ),
4398 unop(Iop_32to16, mkexpr(t32)));
4399}
4400
4401
sewardj8d965312005-02-25 02:48:47 +00004402static
sewardjb4fd2e72005-03-23 13:34:11 +00004403ULong dis_FPU ( /*OUT*/Bool* decode_ok,
sewardj270def42005-07-03 01:03:01 +00004404 Prefix pfx, Long delta )
sewardj8d965312005-02-25 02:48:47 +00004405{
4406 Int len;
4407 UInt r_src, r_dst;
4408 HChar dis_buf[50];
4409 IRTemp t1, t2;
4410
4411 /* On entry, delta points at the second byte of the insn (the modrm
4412 byte).*/
4413 UChar first_opcode = getUChar(delta-1);
4414 UChar modrm = getUChar(delta+0);
4415
sewardj37d52572005-02-25 14:22:12 +00004416 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xD8 opcodes +-+-+-+-+-+-+-+ */
4417
4418 if (first_opcode == 0xD8) {
4419 if (modrm < 0xC0) {
4420
4421 /* bits 5,4,3 are an opcode extension, and the modRM also
4422 specifies an address. */
sewardj7bc00082005-03-27 05:08:32 +00004423 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
4424 delta += len;
sewardj37d52572005-02-25 14:22:12 +00004425
sewardj901ed122005-02-27 13:25:31 +00004426 switch (gregLO3ofRM(modrm)) {
sewardj37d52572005-02-25 14:22:12 +00004427
sewardj48a89d82005-05-06 11:50:13 +00004428 case 0: /* FADD single-real */
4429 fp_do_op_mem_ST_0 ( addr, "add", dis_buf, Iop_AddF64, False );
4430 break;
4431
sewardje6939f02005-05-07 01:01:24 +00004432 case 1: /* FMUL single-real */
4433 fp_do_op_mem_ST_0 ( addr, "mul", dis_buf, Iop_MulF64, False );
4434 break;
4435
sewardjd20c8852005-01-20 20:04:07 +00004436//.. case 2: /* FCOM single-real */
4437//.. DIP("fcoms %s\n", dis_buf);
4438//.. /* This forces C1 to zero, which isn't right. */
4439//.. put_C3210(
4440//.. binop( Iop_And32,
4441//.. binop(Iop_Shl32,
4442//.. binop(Iop_CmpF64,
4443//.. get_ST(0),
4444//.. unop(Iop_F32toF64,
4445//.. loadLE(Ity_F32,mkexpr(addr)))),
4446//.. mkU8(8)),
4447//.. mkU32(0x4500)
4448//.. ));
4449//.. break;
4450//..
4451//.. case 3: /* FCOMP single-real */
4452//.. DIP("fcomps %s\n", dis_buf);
4453//.. /* This forces C1 to zero, which isn't right. */
4454//.. put_C3210(
4455//.. binop( Iop_And32,
4456//.. binop(Iop_Shl32,
4457//.. binop(Iop_CmpF64,
4458//.. get_ST(0),
4459//.. unop(Iop_F32toF64,
4460//.. loadLE(Ity_F32,mkexpr(addr)))),
4461//.. mkU8(8)),
4462//.. mkU32(0x4500)
4463//.. ));
4464//.. fp_pop();
4465//.. break;
sewardje6939f02005-05-07 01:01:24 +00004466
4467 case 4: /* FSUB single-real */
4468 fp_do_op_mem_ST_0 ( addr, "sub", dis_buf, Iop_SubF64, False );
4469 break;
sewardj7bc00082005-03-27 05:08:32 +00004470
4471 case 5: /* FSUBR single-real */
4472 fp_do_oprev_mem_ST_0 ( addr, "subr", dis_buf, Iop_SubF64, False );
4473 break;
4474
sewardje6939f02005-05-07 01:01:24 +00004475 case 6: /* FDIV single-real */
4476 fp_do_op_mem_ST_0 ( addr, "div", dis_buf, Iop_DivF64, False );
4477 break;
4478
4479 case 7: /* FDIVR single-real */
4480 fp_do_oprev_mem_ST_0 ( addr, "divr", dis_buf, Iop_DivF64, False );
4481 break;
sewardj37d52572005-02-25 14:22:12 +00004482
4483 default:
sewardj901ed122005-02-27 13:25:31 +00004484 vex_printf("unhandled opc_aux = 0x%2x\n", gregLO3ofRM(modrm));
sewardj37d52572005-02-25 14:22:12 +00004485 vex_printf("first_opcode == 0xD8\n");
4486 goto decode_fail;
4487 }
4488 } else {
4489 delta++;
4490 switch (modrm) {
4491
4492 case 0xC0 ... 0xC7: /* FADD %st(?),%st(0) */
4493 fp_do_op_ST_ST ( "add", Iop_AddF64, modrm - 0xC0, 0, False );
4494 break;
4495
sewardj137015d2005-03-27 04:01:15 +00004496 case 0xC8 ... 0xCF: /* FMUL %st(?),%st(0) */
4497 fp_do_op_ST_ST ( "mul", Iop_MulF64, modrm - 0xC8, 0, False );
4498 break;
4499
sewardj1859ecd2007-02-23 08:48:22 +00004500 /* Dunno if this is right */
4501 case 0xD0 ... 0xD7: /* FCOM %st(?),%st(0) */
4502 r_dst = (UInt)modrm - 0xD0;
4503 DIP("fcom %%st(0),%%st(%d)\n", r_dst);
4504 /* This forces C1 to zero, which isn't right. */
4505 put_C3210(
4506 unop(Iop_32Uto64,
4507 binop( Iop_And32,
4508 binop(Iop_Shl32,
4509 binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
4510 mkU8(8)),
4511 mkU32(0x4500)
4512 )));
4513 break;
4514
sewardj90e2e4b2007-05-04 09:41:24 +00004515 /* Dunno if this is right */
4516 case 0xD8 ... 0xDF: /* FCOMP %st(?),%st(0) */
4517 r_dst = (UInt)modrm - 0xD8;
4518 DIP("fcomp %%st(0),%%st(%d)\n", r_dst);
4519 /* This forces C1 to zero, which isn't right. */
4520 put_C3210(
4521 unop(Iop_32Uto64,
4522 binop( Iop_And32,
4523 binop(Iop_Shl32,
4524 binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
4525 mkU8(8)),
4526 mkU32(0x4500)
4527 )));
4528 fp_pop();
4529 break;
4530
sewardj137015d2005-03-27 04:01:15 +00004531 case 0xE0 ... 0xE7: /* FSUB %st(?),%st(0) */
4532 fp_do_op_ST_ST ( "sub", Iop_SubF64, modrm - 0xE0, 0, False );
4533 break;
4534
sewardje6939f02005-05-07 01:01:24 +00004535 case 0xE8 ... 0xEF: /* FSUBR %st(?),%st(0) */
4536 fp_do_oprev_ST_ST ( "subr", Iop_SubF64, modrm - 0xE8, 0, False );
4537 break;
sewardj137015d2005-03-27 04:01:15 +00004538
4539 case 0xF0 ... 0xF7: /* FDIV %st(?),%st(0) */
4540 fp_do_op_ST_ST ( "div", Iop_DivF64, modrm - 0xF0, 0, False );
4541 break;
4542
sewardj48a89d82005-05-06 11:50:13 +00004543 case 0xF8 ... 0xFF: /* FDIVR %st(?),%st(0) */
4544 fp_do_oprev_ST_ST ( "divr", Iop_DivF64, modrm - 0xF8, 0, False );
4545 break;
sewardj37d52572005-02-25 14:22:12 +00004546
4547 default:
4548 goto decode_fail;
4549 }
4550 }
4551 }
sewardj8d965312005-02-25 02:48:47 +00004552
4553 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xD9 opcodes +-+-+-+-+-+-+-+ */
sewardj37d52572005-02-25 14:22:12 +00004554 else
sewardj8d965312005-02-25 02:48:47 +00004555 if (first_opcode == 0xD9) {
4556 if (modrm < 0xC0) {
4557
4558 /* bits 5,4,3 are an opcode extension, and the modRM also
4559 specifies an address. */
4560 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
4561 delta += len;
4562
sewardj901ed122005-02-27 13:25:31 +00004563 switch (gregLO3ofRM(modrm)) {
sewardj8d965312005-02-25 02:48:47 +00004564
sewardjc49ce232005-02-25 13:03:03 +00004565 case 0: /* FLD single-real */
4566 DIP("flds %s\n", dis_buf);
4567 fp_push();
4568 put_ST(0, unop(Iop_F32toF64,
4569 loadLE(Ity_F32, mkexpr(addr))));
4570 break;
4571
4572 case 2: /* FST single-real */
4573 DIP("fsts %s\n", dis_buf);
4574 storeLE(mkexpr(addr),
4575 binop(Iop_F64toF32, get_roundingmode(), get_ST(0)));
4576 break;
4577
4578 case 3: /* FSTP single-real */
4579 DIP("fstps %s\n", dis_buf);
4580 storeLE(mkexpr(addr),
4581 binop(Iop_F64toF32, get_roundingmode(), get_ST(0)));
4582 fp_pop();
4583 break;
4584
sewardj4017a3b2005-06-13 12:17:27 +00004585 case 4: { /* FLDENV m28 */
4586 /* Uses dirty helper:
4587 VexEmWarn amd64g_do_FLDENV ( VexGuestX86State*, HWord ) */
4588 IRTemp ew = newTemp(Ity_I32);
4589 IRTemp w64 = newTemp(Ity_I64);
4590 IRDirty* d = unsafeIRDirty_0_N (
4591 0/*regparms*/,
4592 "amd64g_dirtyhelper_FLDENV",
4593 &amd64g_dirtyhelper_FLDENV,
4594 mkIRExprVec_1( mkexpr(addr) )
4595 );
4596 d->needsBBP = True;
4597 d->tmp = w64;
4598 /* declare we're reading memory */
4599 d->mFx = Ifx_Read;
4600 d->mAddr = mkexpr(addr);
4601 d->mSize = 28;
4602
4603 /* declare we're writing guest state */
4604 d->nFxState = 4;
4605
4606 d->fxState[0].fx = Ifx_Write;
4607 d->fxState[0].offset = OFFB_FTOP;
4608 d->fxState[0].size = sizeof(UInt);
4609
4610 d->fxState[1].fx = Ifx_Write;
4611 d->fxState[1].offset = OFFB_FPTAGS;
4612 d->fxState[1].size = 8 * sizeof(UChar);
4613
4614 d->fxState[2].fx = Ifx_Write;
4615 d->fxState[2].offset = OFFB_FPROUND;
4616 d->fxState[2].size = sizeof(ULong);
4617
4618 d->fxState[3].fx = Ifx_Write;
4619 d->fxState[3].offset = OFFB_FC3210;
4620 d->fxState[3].size = sizeof(ULong);
4621
4622 stmt( IRStmt_Dirty(d) );
4623
4624 /* ew contains any emulation warning we may need to
4625 issue. If needed, side-exit to the next insn,
4626 reporting the warning, so that Valgrind's dispatcher
4627 sees the warning. */
4628 assign(ew, unop(Iop_64to32,mkexpr(w64)) );
4629 put_emwarn( mkexpr(ew) );
4630 stmt(
4631 IRStmt_Exit(
4632 binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
4633 Ijk_EmWarn,
sewardj9e6491a2005-07-02 19:24:10 +00004634 IRConst_U64( guest_RIP_bbstart+delta )
sewardj4017a3b2005-06-13 12:17:27 +00004635 )
4636 );
4637
4638 DIP("fldenv %s\n", dis_buf);
4639 break;
4640 }
sewardj5e205372005-05-09 02:57:08 +00004641
4642 case 5: {/* FLDCW */
4643 /* The only thing we observe in the control word is the
4644 rounding mode. Therefore, pass the 16-bit value
4645 (x87 native-format control word) to a clean helper,
4646 getting back a 64-bit value, the lower half of which
4647 is the FPROUND value to store, and the upper half of
4648 which is the emulation-warning token which may be
4649 generated.
4650 */
4651 /* ULong amd64h_check_fldcw ( ULong ); */
4652 IRTemp t64 = newTemp(Ity_I64);
4653 IRTemp ew = newTemp(Ity_I32);
4654 DIP("fldcw %s\n", dis_buf);
4655 assign( t64, mkIRExprCCall(
4656 Ity_I64, 0/*regparms*/,
4657 "amd64g_check_fldcw",
4658 &amd64g_check_fldcw,
4659 mkIRExprVec_1(
4660 unop( Iop_16Uto64,
4661 loadLE(Ity_I16, mkexpr(addr)))
4662 )
4663 )
4664 );
4665
4666 put_fpround( unop(Iop_64to32, mkexpr(t64)) );
4667 assign( ew, unop(Iop_64HIto32, mkexpr(t64) ) );
4668 put_emwarn( mkexpr(ew) );
4669 /* Finally, if an emulation warning was reported,
4670 side-exit to the next insn, reporting the warning,
4671 so that Valgrind's dispatcher sees the warning. */
4672 stmt(
4673 IRStmt_Exit(
4674 binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
4675 Ijk_EmWarn,
sewardj9e6491a2005-07-02 19:24:10 +00004676 IRConst_U64( guest_RIP_bbstart+delta )
sewardj5e205372005-05-09 02:57:08 +00004677 )
4678 );
4679 break;
4680 }
4681
sewardj4017a3b2005-06-13 12:17:27 +00004682 case 6: { /* FNSTENV m28 */
4683 /* Uses dirty helper:
4684 void amd64g_do_FSTENV ( VexGuestAMD64State*, HWord ) */
4685 IRDirty* d = unsafeIRDirty_0_N (
4686 0/*regparms*/,
4687 "amd64g_dirtyhelper_FSTENV",
4688 &amd64g_dirtyhelper_FSTENV,
4689 mkIRExprVec_1( mkexpr(addr) )
4690 );
4691 d->needsBBP = True;
4692 /* declare we're writing memory */
4693 d->mFx = Ifx_Write;
4694 d->mAddr = mkexpr(addr);
4695 d->mSize = 28;
4696
4697 /* declare we're reading guest state */
4698 d->nFxState = 4;
4699
4700 d->fxState[0].fx = Ifx_Read;
4701 d->fxState[0].offset = OFFB_FTOP;
4702 d->fxState[0].size = sizeof(UInt);
4703
4704 d->fxState[1].fx = Ifx_Read;
4705 d->fxState[1].offset = OFFB_FPTAGS;
4706 d->fxState[1].size = 8 * sizeof(UChar);
4707
4708 d->fxState[2].fx = Ifx_Read;
4709 d->fxState[2].offset = OFFB_FPROUND;
4710 d->fxState[2].size = sizeof(ULong);
4711
4712 d->fxState[3].fx = Ifx_Read;
4713 d->fxState[3].offset = OFFB_FC3210;
4714 d->fxState[3].size = sizeof(ULong);
4715
4716 stmt( IRStmt_Dirty(d) );
4717
4718 DIP("fnstenv %s\n", dis_buf);
4719 break;
4720 }
sewardj5e205372005-05-09 02:57:08 +00004721
4722 case 7: /* FNSTCW */
4723 /* Fake up a native x87 FPU control word. The only
4724 thing it depends on is FPROUND[1:0], so call a clean
4725 helper to cook it up. */
sewardj4017a3b2005-06-13 12:17:27 +00004726 /* ULong amd64g_create_fpucw ( ULong fpround ) */
sewardj5e205372005-05-09 02:57:08 +00004727 DIP("fnstcw %s\n", dis_buf);
4728 storeLE(
4729 mkexpr(addr),
4730 unop( Iop_64to16,
4731 mkIRExprCCall(
4732 Ity_I64, 0/*regp*/,
4733 "amd64g_create_fpucw", &amd64g_create_fpucw,
4734 mkIRExprVec_1( unop(Iop_32Uto64, get_fpround()) )
4735 )
4736 )
4737 );
4738 break;
sewardj8d965312005-02-25 02:48:47 +00004739
4740 default:
sewardj901ed122005-02-27 13:25:31 +00004741 vex_printf("unhandled opc_aux = 0x%2x\n", gregLO3ofRM(modrm));
sewardj8d965312005-02-25 02:48:47 +00004742 vex_printf("first_opcode == 0xD9\n");
4743 goto decode_fail;
4744 }
4745
4746 } else {
4747 delta++;
4748 switch (modrm) {
4749
sewardjc49ce232005-02-25 13:03:03 +00004750 case 0xC0 ... 0xC7: /* FLD %st(?) */
4751 r_src = (UInt)modrm - 0xC0;
sewardj1027dc22005-02-26 01:55:02 +00004752 DIP("fld %%st(%u)\n", r_src);
sewardjc49ce232005-02-25 13:03:03 +00004753 t1 = newTemp(Ity_F64);
4754 assign(t1, get_ST(r_src));
4755 fp_push();
4756 put_ST(0, mkexpr(t1));
4757 break;
sewardj8d965312005-02-25 02:48:47 +00004758
4759 case 0xC8 ... 0xCF: /* FXCH %st(?) */
4760 r_src = (UInt)modrm - 0xC8;
sewardj1027dc22005-02-26 01:55:02 +00004761 DIP("fxch %%st(%u)\n", r_src);
sewardj8d965312005-02-25 02:48:47 +00004762 t1 = newTemp(Ity_F64);
4763 t2 = newTemp(Ity_F64);
4764 assign(t1, get_ST(0));
4765 assign(t2, get_ST(r_src));
4766 put_ST_UNCHECKED(0, mkexpr(t2));
4767 put_ST_UNCHECKED(r_src, mkexpr(t1));
4768 break;
4769
4770 case 0xE0: /* FCHS */
4771 DIP("fchs\n");
4772 put_ST_UNCHECKED(0, unop(Iop_NegF64, get_ST(0)));
4773 break;
4774
sewardj137015d2005-03-27 04:01:15 +00004775 case 0xE1: /* FABS */
4776 DIP("fabs\n");
4777 put_ST_UNCHECKED(0, unop(Iop_AbsF64, get_ST(0)));
4778 break;
4779
sewardj4f9847d2005-07-25 11:58:34 +00004780 case 0xE5: { /* FXAM */
4781 /* This is an interesting one. It examines %st(0),
4782 regardless of whether the tag says it's empty or not.
4783 Here, just pass both the tag (in our format) and the
4784 value (as a double, actually a ULong) to a helper
4785 function. */
4786 IRExpr** args
4787 = mkIRExprVec_2( unop(Iop_8Uto64, get_ST_TAG(0)),
4788 unop(Iop_ReinterpF64asI64,
4789 get_ST_UNCHECKED(0)) );
4790 put_C3210(mkIRExprCCall(
4791 Ity_I64,
4792 0/*regparm*/,
4793 "amd64g_calculate_FXAM", &amd64g_calculate_FXAM,
4794 args
4795 ));
4796 DIP("fxam\n");
4797 break;
4798 }
sewardjc49ce232005-02-25 13:03:03 +00004799
4800 case 0xE8: /* FLD1 */
4801 DIP("fld1\n");
4802 fp_push();
4803 /* put_ST(0, IRExpr_Const(IRConst_F64(1.0))); */
4804 put_ST(0, IRExpr_Const(IRConst_F64i(0x3ff0000000000000ULL)));
4805 break;
4806
sewardj6847d8c2005-05-12 19:21:55 +00004807 case 0xE9: /* FLDL2T */
4808 DIP("fldl2t\n");
4809 fp_push();
4810 /* put_ST(0, IRExpr_Const(IRConst_F64(3.32192809488736234781))); */
4811 put_ST(0, IRExpr_Const(IRConst_F64i(0x400a934f0979a371ULL)));
4812 break;
4813
4814 case 0xEA: /* FLDL2E */
4815 DIP("fldl2e\n");
4816 fp_push();
4817 /* put_ST(0, IRExpr_Const(IRConst_F64(1.44269504088896340739))); */
4818 put_ST(0, IRExpr_Const(IRConst_F64i(0x3ff71547652b82feULL)));
4819 break;
4820
4821 case 0xEB: /* FLDPI */
4822 DIP("fldpi\n");
4823 fp_push();
4824 /* put_ST(0, IRExpr_Const(IRConst_F64(3.14159265358979323851))); */
4825 put_ST(0, IRExpr_Const(IRConst_F64i(0x400921fb54442d18ULL)));
4826 break;
4827
4828 case 0xEC: /* FLDLG2 */
4829 DIP("fldlg2\n");
4830 fp_push();
4831 /* put_ST(0, IRExpr_Const(IRConst_F64(0.301029995663981143))); */
4832 put_ST(0, IRExpr_Const(IRConst_F64i(0x3fd34413509f79ffULL)));
4833 break;
4834
4835 case 0xED: /* FLDLN2 */
4836 DIP("fldln2\n");
4837 fp_push();
4838 /* put_ST(0, IRExpr_Const(IRConst_F64(0.69314718055994530942))); */
4839 put_ST(0, IRExpr_Const(IRConst_F64i(0x3fe62e42fefa39efULL)));
4840 break;
sewardjc49ce232005-02-25 13:03:03 +00004841
4842 case 0xEE: /* FLDZ */
4843 DIP("fldz\n");
4844 fp_push();
4845 /* put_ST(0, IRExpr_Const(IRConst_F64(0.0))); */
4846 put_ST(0, IRExpr_Const(IRConst_F64i(0x0000000000000000ULL)));
4847 break;
4848
sewardj25a85812005-05-08 23:03:48 +00004849 case 0xF0: /* F2XM1 */
4850 DIP("f2xm1\n");
sewardj4796d662006-02-05 16:06:26 +00004851 put_ST_UNCHECKED(0,
4852 binop(Iop_2xm1F64,
4853 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4854 get_ST(0)));
sewardj25a85812005-05-08 23:03:48 +00004855 break;
4856
4857 case 0xF1: /* FYL2X */
4858 DIP("fyl2x\n");
sewardj4796d662006-02-05 16:06:26 +00004859 put_ST_UNCHECKED(1,
4860 triop(Iop_Yl2xF64,
4861 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4862 get_ST(1),
4863 get_ST(0)));
sewardj25a85812005-05-08 23:03:48 +00004864 fp_pop();
4865 break;
4866
sewardj5e205372005-05-09 02:57:08 +00004867 case 0xF2: /* FPTAN */
4868 DIP("ftan\n");
sewardj4796d662006-02-05 16:06:26 +00004869 put_ST_UNCHECKED(0,
4870 binop(Iop_TanF64,
4871 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4872 get_ST(0)));
sewardj5e205372005-05-09 02:57:08 +00004873 fp_push();
4874 put_ST(0, IRExpr_Const(IRConst_F64(1.0)));
4875 clear_C2(); /* HACK */
4876 break;
sewardj25a85812005-05-08 23:03:48 +00004877
4878 case 0xF3: /* FPATAN */
4879 DIP("fpatan\n");
sewardj4796d662006-02-05 16:06:26 +00004880 put_ST_UNCHECKED(1,
4881 triop(Iop_AtanF64,
4882 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4883 get_ST(1),
4884 get_ST(0)));
sewardj25a85812005-05-08 23:03:48 +00004885 fp_pop();
4886 break;
4887
sewardj879cee02006-03-07 01:15:50 +00004888 case 0xF4: { /* FXTRACT */
4889 IRTemp argF = newTemp(Ity_F64);
4890 IRTemp sigF = newTemp(Ity_F64);
4891 IRTemp expF = newTemp(Ity_F64);
4892 IRTemp argI = newTemp(Ity_I64);
4893 IRTemp sigI = newTemp(Ity_I64);
4894 IRTemp expI = newTemp(Ity_I64);
4895 DIP("fxtract\n");
4896 assign( argF, get_ST(0) );
4897 assign( argI, unop(Iop_ReinterpF64asI64, mkexpr(argF)));
4898 assign( sigI,
4899 mkIRExprCCall(
4900 Ity_I64, 0/*regparms*/,
4901 "x86amd64g_calculate_FXTRACT",
4902 &x86amd64g_calculate_FXTRACT,
4903 mkIRExprVec_2( mkexpr(argI),
4904 mkIRExpr_HWord(0)/*sig*/ ))
4905 );
4906 assign( expI,
4907 mkIRExprCCall(
4908 Ity_I64, 0/*regparms*/,
4909 "x86amd64g_calculate_FXTRACT",
4910 &x86amd64g_calculate_FXTRACT,
4911 mkIRExprVec_2( mkexpr(argI),
4912 mkIRExpr_HWord(1)/*exp*/ ))
4913 );
4914 assign( sigF, unop(Iop_ReinterpI64asF64, mkexpr(sigI)) );
4915 assign( expF, unop(Iop_ReinterpI64asF64, mkexpr(expI)) );
4916 /* exponent */
4917 put_ST_UNCHECKED(0, mkexpr(expF) );
4918 fp_push();
4919 /* significand */
4920 put_ST(0, mkexpr(sigF) );
4921 break;
4922 }
4923
sewardjd20c8852005-01-20 20:04:07 +00004924//.. case 0xF5: { /* FPREM1 -- IEEE compliant */
4925//.. IRTemp a1 = newTemp(Ity_F64);
4926//.. IRTemp a2 = newTemp(Ity_F64);
4927//.. DIP("fprem1\n");
4928//.. /* Do FPREM1 twice, once to get the remainder, and once
4929//.. to get the C3210 flag values. */
4930//.. assign( a1, get_ST(0) );
4931//.. assign( a2, get_ST(1) );
4932//.. put_ST_UNCHECKED(0, binop(Iop_PRem1F64,
4933//.. mkexpr(a1), mkexpr(a2)));
4934//.. put_C3210( binop(Iop_PRem1C3210F64, mkexpr(a1), mkexpr(a2)) );
4935//.. break;
4936//.. }
sewardj6847d8c2005-05-12 19:21:55 +00004937
4938 case 0xF7: /* FINCSTP */
4939 DIP("fincstp\n");
4940 put_ftop( binop(Iop_Add32, get_ftop(), mkU32(1)) );
4941 break;
4942
sewardjf4c803b2006-09-11 11:07:34 +00004943 case 0xF8: { /* FPREM -- not IEEE compliant */
4944 IRTemp a1 = newTemp(Ity_F64);
4945 IRTemp a2 = newTemp(Ity_F64);
4946 DIP("fprem\n");
4947 /* Do FPREM twice, once to get the remainder, and once
4948 to get the C3210 flag values. */
4949 assign( a1, get_ST(0) );
4950 assign( a2, get_ST(1) );
4951 put_ST_UNCHECKED(0,
4952 triop(Iop_PRemF64,
4953 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4954 mkexpr(a1),
4955 mkexpr(a2)));
4956 put_C3210(
4957 unop(Iop_32Uto64,
4958 triop(Iop_PRemC3210F64,
4959 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4960 mkexpr(a1),
4961 mkexpr(a2)) ));
4962 break;
4963 }
4964
sewardj5e205372005-05-09 02:57:08 +00004965 case 0xF9: /* FYL2XP1 */
4966 DIP("fyl2xp1\n");
sewardj4796d662006-02-05 16:06:26 +00004967 put_ST_UNCHECKED(1,
4968 triop(Iop_Yl2xp1F64,
4969 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4970 get_ST(1),
4971 get_ST(0)));
sewardj5e205372005-05-09 02:57:08 +00004972 fp_pop();
4973 break;
sewardje6939f02005-05-07 01:01:24 +00004974
4975 case 0xFA: /* FSQRT */
4976 DIP("fsqrt\n");
sewardj4796d662006-02-05 16:06:26 +00004977 put_ST_UNCHECKED(0,
4978 binop(Iop_SqrtF64,
4979 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4980 get_ST(0)));
sewardje6939f02005-05-07 01:01:24 +00004981 break;
4982
sewardj25a85812005-05-08 23:03:48 +00004983 case 0xFB: { /* FSINCOS */
4984 IRTemp a1 = newTemp(Ity_F64);
4985 assign( a1, get_ST(0) );
4986 DIP("fsincos\n");
sewardj4796d662006-02-05 16:06:26 +00004987 put_ST_UNCHECKED(0,
4988 binop(Iop_SinF64,
4989 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4990 mkexpr(a1)));
sewardj25a85812005-05-08 23:03:48 +00004991 fp_push();
sewardj4796d662006-02-05 16:06:26 +00004992 put_ST(0,
4993 binop(Iop_CosF64,
4994 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4995 mkexpr(a1)));
sewardj25a85812005-05-08 23:03:48 +00004996 clear_C2(); /* HACK */
4997 break;
4998 }
4999
5000 case 0xFC: /* FRNDINT */
5001 DIP("frndint\n");
5002 put_ST_UNCHECKED(0,
sewardjb183b852006-02-03 16:08:03 +00005003 binop(Iop_RoundF64toInt, get_roundingmode(), get_ST(0)) );
sewardj25a85812005-05-08 23:03:48 +00005004 break;
5005
5006 case 0xFD: /* FSCALE */
5007 DIP("fscale\n");
sewardj4796d662006-02-05 16:06:26 +00005008 put_ST_UNCHECKED(0,
5009 triop(Iop_ScaleF64,
5010 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
5011 get_ST(0),
5012 get_ST(1)));
sewardj25a85812005-05-08 23:03:48 +00005013 break;
5014
5015 case 0xFE: /* FSIN */
5016 DIP("fsin\n");
sewardj4796d662006-02-05 16:06:26 +00005017 put_ST_UNCHECKED(0,
5018 binop(Iop_SinF64,
5019 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
5020 get_ST(0)));
sewardj25a85812005-05-08 23:03:48 +00005021 clear_C2(); /* HACK */
5022 break;
5023
5024 case 0xFF: /* FCOS */
5025 DIP("fcos\n");
sewardj4796d662006-02-05 16:06:26 +00005026 put_ST_UNCHECKED(0,
5027 binop(Iop_CosF64,
5028 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
5029 get_ST(0)));
sewardj25a85812005-05-08 23:03:48 +00005030 clear_C2(); /* HACK */
5031 break;
sewardj8d965312005-02-25 02:48:47 +00005032
5033 default:
5034 goto decode_fail;
5035 }
5036 }
5037 }
5038
5039 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDA opcodes +-+-+-+-+-+-+-+ */
5040 else
5041 if (first_opcode == 0xDA) {
5042
5043 if (modrm < 0xC0) {
5044
5045 /* bits 5,4,3 are an opcode extension, and the modRM also
5046 specifies an address. */
sewardj6847d8c2005-05-12 19:21:55 +00005047 IROp fop;
5048 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
sewardj8d965312005-02-25 02:48:47 +00005049 delta += len;
sewardj901ed122005-02-27 13:25:31 +00005050 switch (gregLO3ofRM(modrm)) {
sewardj8d965312005-02-25 02:48:47 +00005051
sewardj6847d8c2005-05-12 19:21:55 +00005052 case 0: /* FIADD m32int */ /* ST(0) += m32int */
5053 DIP("fiaddl %s\n", dis_buf);
5054 fop = Iop_AddF64;
5055 goto do_fop_m32;
5056
5057 case 1: /* FIMUL m32int */ /* ST(0) *= m32int */
5058 DIP("fimull %s\n", dis_buf);
5059 fop = Iop_MulF64;
5060 goto do_fop_m32;
5061
5062 case 4: /* FISUB m32int */ /* ST(0) -= m32int */
5063 DIP("fisubl %s\n", dis_buf);
5064 fop = Iop_SubF64;
5065 goto do_fop_m32;
5066
5067 case 5: /* FISUBR m32int */ /* ST(0) = m32int - ST(0) */
5068 DIP("fisubrl %s\n", dis_buf);
5069 fop = Iop_SubF64;
5070 goto do_foprev_m32;
5071
5072 case 6: /* FIDIV m32int */ /* ST(0) /= m32int */
5073 DIP("fisubl %s\n", dis_buf);
5074 fop = Iop_DivF64;
5075 goto do_fop_m32;
5076
5077 case 7: /* FIDIVR m32int */ /* ST(0) = m32int / ST(0) */
5078 DIP("fidivrl %s\n", dis_buf);
5079 fop = Iop_DivF64;
5080 goto do_foprev_m32;
5081
5082 do_fop_m32:
5083 put_ST_UNCHECKED(0,
sewardj4796d662006-02-05 16:06:26 +00005084 triop(fop,
5085 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardj6847d8c2005-05-12 19:21:55 +00005086 get_ST(0),
5087 unop(Iop_I32toF64,
5088 loadLE(Ity_I32, mkexpr(addr)))));
5089 break;
5090
5091 do_foprev_m32:
5092 put_ST_UNCHECKED(0,
sewardj4796d662006-02-05 16:06:26 +00005093 triop(fop,
5094 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardj6847d8c2005-05-12 19:21:55 +00005095 unop(Iop_I32toF64,
5096 loadLE(Ity_I32, mkexpr(addr))),
5097 get_ST(0)));
5098 break;
sewardj8d965312005-02-25 02:48:47 +00005099
5100 default:
sewardj901ed122005-02-27 13:25:31 +00005101 vex_printf("unhandled opc_aux = 0x%2x\n", gregLO3ofRM(modrm));
sewardj8d965312005-02-25 02:48:47 +00005102 vex_printf("first_opcode == 0xDA\n");
5103 goto decode_fail;
5104 }
5105
5106 } else {
5107
5108 delta++;
5109 switch (modrm) {
5110
sewardj48a89d82005-05-06 11:50:13 +00005111 case 0xC0 ... 0xC7: /* FCMOVB ST(i), ST(0) */
5112 r_src = (UInt)modrm - 0xC0;
sewardjca673ab2005-05-11 10:03:08 +00005113 DIP("fcmovb %%st(%u), %%st(0)\n", r_src);
sewardj48a89d82005-05-06 11:50:13 +00005114 put_ST_UNCHECKED(0,
5115 IRExpr_Mux0X(
5116 unop(Iop_1Uto8,
5117 mk_amd64g_calculate_condition(AMD64CondB)),
5118 get_ST(0), get_ST(r_src)) );
5119 break;
sewardj8d965312005-02-25 02:48:47 +00005120
5121 case 0xC8 ... 0xCF: /* FCMOVE(Z) ST(i), ST(0) */
5122 r_src = (UInt)modrm - 0xC8;
sewardj1027dc22005-02-26 01:55:02 +00005123 DIP("fcmovz %%st(%u), %%st(0)\n", r_src);
sewardj8d965312005-02-25 02:48:47 +00005124 put_ST_UNCHECKED(0,
5125 IRExpr_Mux0X(
5126 unop(Iop_1Uto8,
5127 mk_amd64g_calculate_condition(AMD64CondZ)),
5128 get_ST(0), get_ST(r_src)) );
5129 break;
5130
sewardj37d52572005-02-25 14:22:12 +00005131 case 0xD0 ... 0xD7: /* FCMOVBE ST(i), ST(0) */
5132 r_src = (UInt)modrm - 0xD0;
sewardj1027dc22005-02-26 01:55:02 +00005133 DIP("fcmovbe %%st(%u), %%st(0)\n", r_src);
sewardj37d52572005-02-25 14:22:12 +00005134 put_ST_UNCHECKED(0,
5135 IRExpr_Mux0X(
5136 unop(Iop_1Uto8,
5137 mk_amd64g_calculate_condition(AMD64CondBE)),
5138 get_ST(0), get_ST(r_src)) );
5139 break;
5140
sewardj25a85812005-05-08 23:03:48 +00005141 case 0xD8 ... 0xDF: /* FCMOVU ST(i), ST(0) */
5142 r_src = (UInt)modrm - 0xD8;
5143 DIP("fcmovu %%st(%u), %%st(0)\n", r_src);
5144 put_ST_UNCHECKED(0,
5145 IRExpr_Mux0X(
5146 unop(Iop_1Uto8,
5147 mk_amd64g_calculate_condition(AMD64CondP)),
5148 get_ST(0), get_ST(r_src)) );
5149 break;
5150
sewardjd20c8852005-01-20 20:04:07 +00005151//.. case 0xE9: /* FUCOMPP %st(0),%st(1) */
5152//.. DIP("fucompp %%st(0),%%st(1)\n");
5153//.. /* This forces C1 to zero, which isn't right. */
5154//.. put_C3210(
5155//.. binop( Iop_And32,
5156//.. binop(Iop_Shl32,
5157//.. binop(Iop_CmpF64, get_ST(0), get_ST(1)),
5158//.. mkU8(8)),
5159//.. mkU32(0x4500)
5160//.. ));
5161//.. fp_pop();
5162//.. fp_pop();
5163//.. break;
sewardj8d965312005-02-25 02:48:47 +00005164
5165 default:
5166 goto decode_fail;
5167 }
5168
5169 }
5170 }
5171
sewardjc49ce232005-02-25 13:03:03 +00005172 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDB opcodes +-+-+-+-+-+-+-+ */
5173 else
5174 if (first_opcode == 0xDB) {
5175 if (modrm < 0xC0) {
5176
5177 /* bits 5,4,3 are an opcode extension, and the modRM also
5178 specifies an address. */
5179 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
5180 delta += len;
5181
sewardj901ed122005-02-27 13:25:31 +00005182 switch (gregLO3ofRM(modrm)) {
sewardjc49ce232005-02-25 13:03:03 +00005183
sewardj5cc00ff2005-03-27 04:48:32 +00005184 case 0: /* FILD m32int */
5185 DIP("fildl %s\n", dis_buf);
5186 fp_push();
5187 put_ST(0, unop(Iop_I32toF64,
5188 loadLE(Ity_I32, mkexpr(addr))));
5189 break;
5190
sewardjfcf21f32006-08-04 14:51:19 +00005191 case 1: /* FISTTPL m32 (SSE3) */
5192 DIP("fisttpl %s\n", dis_buf);
5193 storeLE( mkexpr(addr),
5194 binop(Iop_F64toI32, mkU32(Irrm_ZERO), get_ST(0)) );
5195 fp_pop();
5196 break;
5197
sewardj6847d8c2005-05-12 19:21:55 +00005198 case 2: /* FIST m32 */
5199 DIP("fistl %s\n", dis_buf);
5200 storeLE( mkexpr(addr),
5201 binop(Iop_F64toI32, get_roundingmode(), get_ST(0)) );
5202 break;
sewardj37d52572005-02-25 14:22:12 +00005203
5204 case 3: /* FISTP m32 */
5205 DIP("fistpl %s\n", dis_buf);
5206 storeLE( mkexpr(addr),
5207 binop(Iop_F64toI32, get_roundingmode(), get_ST(0)) );
5208 fp_pop();
5209 break;
5210
sewardj924215b2005-03-26 21:50:31 +00005211 case 5: { /* FLD extended-real */
5212 /* Uses dirty helper:
5213 ULong amd64g_loadF80le ( ULong )
5214 addr holds the address. First, do a dirty call to
5215 get hold of the data. */
5216 IRTemp val = newTemp(Ity_I64);
5217 IRExpr** args = mkIRExprVec_1 ( mkexpr(addr) );
5218
5219 IRDirty* d = unsafeIRDirty_1_N (
5220 val,
5221 0/*regparms*/,
sewardj8707fef2005-08-23 23:26:37 +00005222 "amd64g_dirtyhelper_loadF80le",
5223 &amd64g_dirtyhelper_loadF80le,
sewardj924215b2005-03-26 21:50:31 +00005224 args
5225 );
5226 /* declare that we're reading memory */
5227 d->mFx = Ifx_Read;
5228 d->mAddr = mkexpr(addr);
5229 d->mSize = 10;
5230
5231 /* execute the dirty call, dumping the result in val. */
5232 stmt( IRStmt_Dirty(d) );
5233 fp_push();
5234 put_ST(0, unop(Iop_ReinterpI64asF64, mkexpr(val)));
5235
5236 DIP("fldt %s\n", dis_buf);
5237 break;
5238 }
5239
5240 case 7: { /* FSTP extended-real */
5241 /* Uses dirty helper:
5242 void amd64g_storeF80le ( ULong addr, ULong data )
5243 */
5244 IRExpr** args
5245 = mkIRExprVec_2( mkexpr(addr),
5246 unop(Iop_ReinterpF64asI64, get_ST(0)) );
5247
5248 IRDirty* d = unsafeIRDirty_0_N (
5249 0/*regparms*/,
sewardj8707fef2005-08-23 23:26:37 +00005250 "amd64g_dirtyhelper_storeF80le",
5251 &amd64g_dirtyhelper_storeF80le,
sewardj924215b2005-03-26 21:50:31 +00005252 args
5253 );
5254 /* declare we're writing memory */
5255 d->mFx = Ifx_Write;
5256 d->mAddr = mkexpr(addr);
5257 d->mSize = 10;
5258
5259 /* execute the dirty call. */
5260 stmt( IRStmt_Dirty(d) );
5261 fp_pop();
5262
5263 DIP("fstpt\n %s", dis_buf);
5264 break;
5265 }
sewardjc49ce232005-02-25 13:03:03 +00005266
5267 default:
sewardj901ed122005-02-27 13:25:31 +00005268 vex_printf("unhandled opc_aux = 0x%2x\n", gregLO3ofRM(modrm));
sewardjc49ce232005-02-25 13:03:03 +00005269 vex_printf("first_opcode == 0xDB\n");
5270 goto decode_fail;
5271 }
5272
5273 } else {
5274
5275 delta++;
5276 switch (modrm) {
5277
sewardj48a89d82005-05-06 11:50:13 +00005278 case 0xC0 ... 0xC7: /* FCMOVNB ST(i), ST(0) */
5279 r_src = (UInt)modrm - 0xC0;
sewardjca673ab2005-05-11 10:03:08 +00005280 DIP("fcmovnb %%st(%u), %%st(0)\n", r_src);
sewardj48a89d82005-05-06 11:50:13 +00005281 put_ST_UNCHECKED(0,
5282 IRExpr_Mux0X(
5283 unop(Iop_1Uto8,
5284 mk_amd64g_calculate_condition(AMD64CondNB)),
5285 get_ST(0), get_ST(r_src)) );
5286 break;
sewardj924215b2005-03-26 21:50:31 +00005287
5288 case 0xC8 ... 0xCF: /* FCMOVNE(NZ) ST(i), ST(0) */
5289 r_src = (UInt)modrm - 0xC8;
sewardj40e144d2005-03-28 00:46:27 +00005290 DIP("fcmovnz %%st(%u), %%st(0)\n", r_src);
sewardj137015d2005-03-27 04:01:15 +00005291 put_ST_UNCHECKED(
5292 0,
5293 IRExpr_Mux0X(
5294 unop(Iop_1Uto8,
5295 mk_amd64g_calculate_condition(AMD64CondNZ)),
5296 get_ST(0),
5297 get_ST(r_src)
5298 )
5299 );
sewardj924215b2005-03-26 21:50:31 +00005300 break;
5301
sewardj137015d2005-03-27 04:01:15 +00005302 case 0xD0 ... 0xD7: /* FCMOVNBE ST(i), ST(0) */
5303 r_src = (UInt)modrm - 0xD0;
sewardj40e144d2005-03-28 00:46:27 +00005304 DIP("fcmovnbe %%st(%u), %%st(0)\n", r_src);
sewardj137015d2005-03-27 04:01:15 +00005305 put_ST_UNCHECKED(
5306 0,
5307 IRExpr_Mux0X(
5308 unop(Iop_1Uto8,
5309 mk_amd64g_calculate_condition(AMD64CondNBE)),
5310 get_ST(0),
5311 get_ST(r_src)
5312 )
5313 );
5314 break;
5315
sewardj3368e102006-03-06 19:05:07 +00005316 case 0xD8 ... 0xDF: /* FCMOVNU ST(i), ST(0) */
5317 r_src = (UInt)modrm - 0xD8;
5318 DIP("fcmovnu %%st(%u), %%st(0)\n", r_src);
5319 put_ST_UNCHECKED(
5320 0,
5321 IRExpr_Mux0X(
5322 unop(Iop_1Uto8,
5323 mk_amd64g_calculate_condition(AMD64CondNP)),
5324 get_ST(0),
5325 get_ST(r_src)
5326 )
5327 );
5328 break;
5329
sewardj4e1a1e92005-05-25 00:44:13 +00005330 case 0xE2:
5331 DIP("fnclex\n");
5332 break;
5333
sewardj0585a032005-11-05 02:55:06 +00005334 case 0xE3: {
5335 /* Uses dirty helper:
5336 void amd64g_do_FINIT ( VexGuestAMD64State* ) */
5337 IRDirty* d = unsafeIRDirty_0_N (
5338 0/*regparms*/,
5339 "amd64g_dirtyhelper_FINIT",
5340 &amd64g_dirtyhelper_FINIT,
5341 mkIRExprVec_0()
5342 );
5343 d->needsBBP = True;
5344
5345 /* declare we're writing guest state */
5346 d->nFxState = 5;
5347
5348 d->fxState[0].fx = Ifx_Write;
5349 d->fxState[0].offset = OFFB_FTOP;
5350 d->fxState[0].size = sizeof(UInt);
5351
5352 d->fxState[1].fx = Ifx_Write;
5353 d->fxState[1].offset = OFFB_FPREGS;
5354 d->fxState[1].size = 8 * sizeof(ULong);
5355
5356 d->fxState[2].fx = Ifx_Write;
5357 d->fxState[2].offset = OFFB_FPTAGS;
5358 d->fxState[2].size = 8 * sizeof(UChar);
5359
5360 d->fxState[3].fx = Ifx_Write;
5361 d->fxState[3].offset = OFFB_FPROUND;
5362 d->fxState[3].size = sizeof(ULong);
5363
5364 d->fxState[4].fx = Ifx_Write;
5365 d->fxState[4].offset = OFFB_FC3210;
5366 d->fxState[4].size = sizeof(ULong);
5367
5368 stmt( IRStmt_Dirty(d) );
5369
5370 DIP("fninit\n");
5371 break;
5372 }
sewardjc49ce232005-02-25 13:03:03 +00005373
5374 case 0xE8 ... 0xEF: /* FUCOMI %st(0),%st(?) */
5375 fp_do_ucomi_ST0_STi( (UInt)modrm - 0xE8, False );
5376 break;
5377
sewardj48a89d82005-05-06 11:50:13 +00005378 case 0xF0 ... 0xF7: /* FCOMI %st(0),%st(?) */
5379 fp_do_ucomi_ST0_STi( (UInt)modrm - 0xF0, False );
5380 break;
sewardjc49ce232005-02-25 13:03:03 +00005381
5382 default:
5383 goto decode_fail;
5384 }
5385 }
5386 }
5387
sewardj137015d2005-03-27 04:01:15 +00005388 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDC opcodes +-+-+-+-+-+-+-+ */
5389 else
5390 if (first_opcode == 0xDC) {
5391 if (modrm < 0xC0) {
5392
sewardj434e0692005-03-27 17:36:08 +00005393 /* bits 5,4,3 are an opcode extension, and the modRM also
5394 specifies an address. */
5395 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
5396 delta += len;
5397
5398 switch (gregLO3ofRM(modrm)) {
5399
sewardje6939f02005-05-07 01:01:24 +00005400 case 0: /* FADD double-real */
5401 fp_do_op_mem_ST_0 ( addr, "add", dis_buf, Iop_AddF64, True );
5402 break;
5403
5404 case 1: /* FMUL double-real */
5405 fp_do_op_mem_ST_0 ( addr, "mul", dis_buf, Iop_MulF64, True );
5406 break;
5407
sewardjd20c8852005-01-20 20:04:07 +00005408//.. case 2: /* FCOM double-real */
5409//.. DIP("fcoml %s\n", dis_buf);
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,
5415//.. get_ST(0),
5416//.. loadLE(Ity_F64,mkexpr(addr))),
5417//.. mkU8(8)),
5418//.. mkU32(0x4500)
5419//.. ));
5420//.. break;
sewardj566d2c72005-08-10 11:43:42 +00005421
5422 case 3: /* FCOMP double-real */
5423 DIP("fcompl %s\n", dis_buf);
5424 /* This forces C1 to zero, which isn't right. */
5425 put_C3210(
5426 unop(Iop_32Uto64,
5427 binop( Iop_And32,
5428 binop(Iop_Shl32,
5429 binop(Iop_CmpF64,
5430 get_ST(0),
5431 loadLE(Ity_F64,mkexpr(addr))),
5432 mkU8(8)),
5433 mkU32(0x4500)
5434 )));
5435 fp_pop();
5436 break;
sewardje6939f02005-05-07 01:01:24 +00005437
5438 case 4: /* FSUB double-real */
5439 fp_do_op_mem_ST_0 ( addr, "sub", dis_buf, Iop_SubF64, True );
5440 break;
sewardj434e0692005-03-27 17:36:08 +00005441
5442 case 5: /* FSUBR double-real */
5443 fp_do_oprev_mem_ST_0 ( addr, "subr", dis_buf, Iop_SubF64, True );
5444 break;
5445
sewardje6939f02005-05-07 01:01:24 +00005446 case 6: /* FDIV double-real */
5447 fp_do_op_mem_ST_0 ( addr, "div", dis_buf, Iop_DivF64, True );
5448 break;
5449
5450 case 7: /* FDIVR double-real */
5451 fp_do_oprev_mem_ST_0 ( addr, "divr", dis_buf, Iop_DivF64, True );
5452 break;
sewardj434e0692005-03-27 17:36:08 +00005453
5454 default:
5455 vex_printf("unhandled opc_aux = 0x%2x\n", gregLO3ofRM(modrm));
5456 vex_printf("first_opcode == 0xDC\n");
5457 goto decode_fail;
5458 }
sewardj137015d2005-03-27 04:01:15 +00005459
5460 } else {
5461
5462 delta++;
5463 switch (modrm) {
5464
5465 case 0xC0 ... 0xC7: /* FADD %st(0),%st(?) */
5466 fp_do_op_ST_ST ( "add", Iop_AddF64, 0, modrm - 0xC0, False );
5467 break;
5468
sewardj7bc00082005-03-27 05:08:32 +00005469 case 0xC8 ... 0xCF: /* FMUL %st(0),%st(?) */
5470 fp_do_op_ST_ST ( "mul", Iop_MulF64, 0, modrm - 0xC8, False );
5471 break;
5472
sewardj434e0692005-03-27 17:36:08 +00005473 case 0xE0 ... 0xE7: /* FSUBR %st(0),%st(?) */
5474 fp_do_oprev_ST_ST ( "subr", Iop_SubF64, 0, modrm - 0xE0, False );
5475 break;
5476
sewardje6939f02005-05-07 01:01:24 +00005477 case 0xE8 ... 0xEF: /* FSUB %st(0),%st(?) */
5478 fp_do_op_ST_ST ( "sub", Iop_SubF64, 0, modrm - 0xE8, False );
5479 break;
5480
5481 case 0xF0 ... 0xF7: /* FDIVR %st(0),%st(?) */
5482 fp_do_oprev_ST_ST ( "divr", Iop_DivF64, 0, modrm - 0xF0, False );
5483 break;
sewardj137015d2005-03-27 04:01:15 +00005484
5485 case 0xF8 ... 0xFF: /* FDIV %st(0),%st(?) */
5486 fp_do_op_ST_ST ( "div", Iop_DivF64, 0, modrm - 0xF8, False );
5487 break;
5488
5489 default:
5490 goto decode_fail;
5491 }
5492
5493 }
5494 }
sewardj8d965312005-02-25 02:48:47 +00005495
5496 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDD opcodes +-+-+-+-+-+-+-+ */
5497 else
5498 if (first_opcode == 0xDD) {
5499
5500 if (modrm < 0xC0) {
5501
5502 /* bits 5,4,3 are an opcode extension, and the modRM also
5503 specifies an address. */
5504 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
5505 delta += len;
5506
sewardj901ed122005-02-27 13:25:31 +00005507 switch (gregLO3ofRM(modrm)) {
sewardj8d965312005-02-25 02:48:47 +00005508
5509 case 0: /* FLD double-real */
5510 DIP("fldl %s\n", dis_buf);
5511 fp_push();
sewardjaf1ceca2005-06-30 23:31:27 +00005512 put_ST(0, loadLE(Ity_F64, mkexpr(addr)));
sewardj8d965312005-02-25 02:48:47 +00005513 break;
5514
sewardjfcf21f32006-08-04 14:51:19 +00005515 case 1: /* FISTTPQ m64 (SSE3) */
5516 DIP("fistppll %s\n", dis_buf);
5517 storeLE( mkexpr(addr),
5518 binop(Iop_F64toI64, mkU32(Irrm_ZERO), get_ST(0)) );
5519 fp_pop();
5520 break;
5521
sewardjc49ce232005-02-25 13:03:03 +00005522 case 2: /* FST double-real */
5523 DIP("fstl %s\n", dis_buf);
5524 storeLE(mkexpr(addr), get_ST(0));
5525 break;
sewardj8d965312005-02-25 02:48:47 +00005526
5527 case 3: /* FSTP double-real */
5528 DIP("fstpl %s\n", dis_buf);
5529 storeLE(mkexpr(addr), get_ST(0));
5530 fp_pop();
5531 break;
5532
sewardjd20c8852005-01-20 20:04:07 +00005533//.. case 4: { /* FRSTOR m108 */
5534//.. /* Uses dirty helper:
5535//.. VexEmWarn x86g_do_FRSTOR ( VexGuestX86State*, Addr32 ) */
5536//.. IRTemp ew = newTemp(Ity_I32);
5537//.. IRDirty* d = unsafeIRDirty_0_N (
5538//.. 0/*regparms*/,
5539//.. "x86g_dirtyhelper_FRSTOR",
5540//.. &x86g_dirtyhelper_FRSTOR,
5541//.. mkIRExprVec_1( mkexpr(addr) )
5542//.. );
5543//.. d->needsBBP = True;
5544//.. d->tmp = ew;
5545//.. /* declare we're reading memory */
5546//.. d->mFx = Ifx_Read;
5547//.. d->mAddr = mkexpr(addr);
5548//.. d->mSize = 108;
5549//..
5550//.. /* declare we're writing guest state */
5551//.. d->nFxState = 5;
5552//..
5553//.. d->fxState[0].fx = Ifx_Write;
5554//.. d->fxState[0].offset = OFFB_FTOP;
5555//.. d->fxState[0].size = sizeof(UInt);
5556//..
5557//.. d->fxState[1].fx = Ifx_Write;
5558//.. d->fxState[1].offset = OFFB_FPREGS;
5559//.. d->fxState[1].size = 8 * sizeof(ULong);
5560//..
5561//.. d->fxState[2].fx = Ifx_Write;
5562//.. d->fxState[2].offset = OFFB_FPTAGS;
5563//.. d->fxState[2].size = 8 * sizeof(UChar);
5564//..
5565//.. d->fxState[3].fx = Ifx_Write;
5566//.. d->fxState[3].offset = OFFB_FPROUND;
5567//.. d->fxState[3].size = sizeof(UInt);
5568//..
5569//.. d->fxState[4].fx = Ifx_Write;
5570//.. d->fxState[4].offset = OFFB_FC3210;
5571//.. d->fxState[4].size = sizeof(UInt);
5572//..
5573//.. stmt( IRStmt_Dirty(d) );
5574//..
5575//.. /* ew contains any emulation warning we may need to
5576//.. issue. If needed, side-exit to the next insn,
5577//.. reporting the warning, so that Valgrind's dispatcher
5578//.. sees the warning. */
5579//.. put_emwarn( mkexpr(ew) );
5580//.. stmt(
5581//.. IRStmt_Exit(
5582//.. binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
5583//.. Ijk_EmWarn,
5584//.. IRConst_U32( ((Addr32)guest_eip_bbstart)+delta)
5585//.. )
5586//.. );
5587//..
5588//.. DIP("frstor %s\n", dis_buf);
5589//.. break;
5590//.. }
5591//..
5592//.. case 6: { /* FNSAVE m108 */
5593//.. /* Uses dirty helper:
5594//.. void x86g_do_FSAVE ( VexGuestX86State*, UInt ) */
5595//.. IRDirty* d = unsafeIRDirty_0_N (
5596//.. 0/*regparms*/,
5597//.. "x86g_dirtyhelper_FSAVE",
5598//.. &x86g_dirtyhelper_FSAVE,
5599//.. mkIRExprVec_1( mkexpr(addr) )
5600//.. );
5601//.. d->needsBBP = True;
5602//.. /* declare we're writing memory */
5603//.. d->mFx = Ifx_Write;
5604//.. d->mAddr = mkexpr(addr);
5605//.. d->mSize = 108;
5606//..
5607//.. /* declare we're reading guest state */
5608//.. d->nFxState = 5;
5609//..
5610//.. d->fxState[0].fx = Ifx_Read;
5611//.. d->fxState[0].offset = OFFB_FTOP;
5612//.. d->fxState[0].size = sizeof(UInt);
5613//..
5614//.. d->fxState[1].fx = Ifx_Read;
5615//.. d->fxState[1].offset = OFFB_FPREGS;
5616//.. d->fxState[1].size = 8 * sizeof(ULong);
5617//..
5618//.. d->fxState[2].fx = Ifx_Read;
5619//.. d->fxState[2].offset = OFFB_FPTAGS;
5620//.. d->fxState[2].size = 8 * sizeof(UChar);
5621//..
5622//.. d->fxState[3].fx = Ifx_Read;
5623//.. d->fxState[3].offset = OFFB_FPROUND;
5624//.. d->fxState[3].size = sizeof(UInt);
5625//..
5626//.. d->fxState[4].fx = Ifx_Read;
5627//.. d->fxState[4].offset = OFFB_FC3210;
5628//.. d->fxState[4].size = sizeof(UInt);
5629//..
5630//.. stmt( IRStmt_Dirty(d) );
5631//..
5632//.. DIP("fnsave %s\n", dis_buf);
5633//.. break;
5634//.. }
sewardj8d965312005-02-25 02:48:47 +00005635
sewardj7c2d2822006-03-07 00:22:02 +00005636 case 7: { /* FNSTSW m16 */
5637 IRExpr* sw = get_FPU_sw();
sewardjdd40fdf2006-12-24 02:20:24 +00005638 vassert(typeOfIRExpr(irsb->tyenv, sw) == Ity_I16);
sewardj7c2d2822006-03-07 00:22:02 +00005639 storeLE( mkexpr(addr), sw );
5640 DIP("fnstsw %s\n", dis_buf);
5641 break;
5642 }
5643
sewardj8d965312005-02-25 02:48:47 +00005644 default:
sewardj901ed122005-02-27 13:25:31 +00005645 vex_printf("unhandled opc_aux = 0x%2x\n", gregLO3ofRM(modrm));
sewardj8d965312005-02-25 02:48:47 +00005646 vex_printf("first_opcode == 0xDD\n");
5647 goto decode_fail;
5648 }
5649 } else {
5650 delta++;
5651 switch (modrm) {
5652
sewardj6847d8c2005-05-12 19:21:55 +00005653 case 0xC0 ... 0xC7: /* FFREE %st(?) */
5654 r_dst = (UInt)modrm - 0xC0;
5655 DIP("ffree %%st(%u)\n", r_dst);
5656 put_ST_TAG ( r_dst, mkU8(0) );
5657 break;
5658
sewardjbfabcc42005-08-08 09:58:05 +00005659 case 0xD0 ... 0xD7: /* FST %st(0),%st(?) */
5660 r_dst = (UInt)modrm - 0xD0;
sewardjc7cd2142005-09-09 22:31:49 +00005661 DIP("fst %%st(0),%%st(%u)\n", r_dst);
sewardjbfabcc42005-08-08 09:58:05 +00005662 /* P4 manual says: "If the destination operand is a
5663 non-empty register, the invalid-operation exception
5664 is not generated. Hence put_ST_UNCHECKED. */
5665 put_ST_UNCHECKED(r_dst, get_ST(0));
5666 break;
sewardj8d965312005-02-25 02:48:47 +00005667
5668 case 0xD8 ... 0xDF: /* FSTP %st(0),%st(?) */
5669 r_dst = (UInt)modrm - 0xD8;
sewardj1027dc22005-02-26 01:55:02 +00005670 DIP("fstp %%st(0),%%st(%u)\n", r_dst);
sewardj8d965312005-02-25 02:48:47 +00005671 /* P4 manual says: "If the destination operand is a
5672 non-empty register, the invalid-operation exception
5673 is not generated. Hence put_ST_UNCHECKED. */
5674 put_ST_UNCHECKED(r_dst, get_ST(0));
5675 fp_pop();
5676 break;
5677
sewardjfb6c1792005-10-05 17:58:32 +00005678 case 0xE0 ... 0xE7: /* FUCOM %st(0),%st(?) */
5679 r_dst = (UInt)modrm - 0xE0;
sewardj62d05432005-10-29 22:30:47 +00005680 DIP("fucom %%st(0),%%st(%u)\n", r_dst);
sewardjfb6c1792005-10-05 17:58:32 +00005681 /* This forces C1 to zero, which isn't right. */
5682 put_C3210(
5683 unop(Iop_32Uto64,
5684 binop( Iop_And32,
5685 binop(Iop_Shl32,
5686 binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
5687 mkU8(8)),
5688 mkU32(0x4500)
5689 )));
5690 break;
5691
sewardj9fb2f472005-11-05 01:12:18 +00005692 case 0xE8 ... 0xEF: /* FUCOMP %st(0),%st(?) */
5693 r_dst = (UInt)modrm - 0xE8;
sewardj43f45732005-11-05 13:04:34 +00005694 DIP("fucomp %%st(0),%%st(%u)\n", r_dst);
sewardj9fb2f472005-11-05 01:12:18 +00005695 /* This forces C1 to zero, which isn't right. */
5696 put_C3210(
5697 unop(Iop_32Uto64,
5698 binop( Iop_And32,
5699 binop(Iop_Shl32,
5700 binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
5701 mkU8(8)),
5702 mkU32(0x4500)
5703 )));
5704 fp_pop();
5705 break;
sewardj8d965312005-02-25 02:48:47 +00005706
5707 default:
5708 goto decode_fail;
5709 }
5710 }
5711 }
5712
sewardj137015d2005-03-27 04:01:15 +00005713 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDE opcodes +-+-+-+-+-+-+-+ */
5714 else
5715 if (first_opcode == 0xDE) {
5716
5717 if (modrm < 0xC0) {
5718
sewardj6847d8c2005-05-12 19:21:55 +00005719 /* bits 5,4,3 are an opcode extension, and the modRM also
5720 specifies an address. */
5721 IROp fop;
5722 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
5723 delta += len;
5724
5725 switch (gregLO3ofRM(modrm)) {
5726
5727 case 0: /* FIADD m16int */ /* ST(0) += m16int */
5728 DIP("fiaddw %s\n", dis_buf);
5729 fop = Iop_AddF64;
5730 goto do_fop_m16;
5731
5732 case 1: /* FIMUL m16int */ /* ST(0) *= m16int */
5733 DIP("fimulw %s\n", dis_buf);
5734 fop = Iop_MulF64;
5735 goto do_fop_m16;
5736
5737 case 4: /* FISUB m16int */ /* ST(0) -= m16int */
5738 DIP("fisubw %s\n", dis_buf);
5739 fop = Iop_SubF64;
5740 goto do_fop_m16;
5741
5742 case 5: /* FISUBR m16int */ /* ST(0) = m16int - ST(0) */
5743 DIP("fisubrw %s\n", dis_buf);
5744 fop = Iop_SubF64;
5745 goto do_foprev_m16;
5746
5747 case 6: /* FIDIV m16int */ /* ST(0) /= m16int */
5748 DIP("fisubw %s\n", dis_buf);
5749 fop = Iop_DivF64;
5750 goto do_fop_m16;
5751
5752 case 7: /* FIDIVR m16int */ /* ST(0) = m16int / ST(0) */
5753 DIP("fidivrw %s\n", dis_buf);
5754 fop = Iop_DivF64;
5755 goto do_foprev_m16;
5756
5757 do_fop_m16:
5758 put_ST_UNCHECKED(0,
sewardj4796d662006-02-05 16:06:26 +00005759 triop(fop,
5760 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardj6847d8c2005-05-12 19:21:55 +00005761 get_ST(0),
5762 unop(Iop_I32toF64,
5763 unop(Iop_16Sto32,
5764 loadLE(Ity_I16, mkexpr(addr))))));
5765 break;
5766
5767 do_foprev_m16:
5768 put_ST_UNCHECKED(0,
sewardj4796d662006-02-05 16:06:26 +00005769 triop(fop,
5770 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardj6847d8c2005-05-12 19:21:55 +00005771 unop(Iop_I32toF64,
5772 unop(Iop_16Sto32,
5773 loadLE(Ity_I16, mkexpr(addr)))),
5774 get_ST(0)));
5775 break;
5776
5777 default:
5778 vex_printf("unhandled opc_aux = 0x%2x\n", gregLO3ofRM(modrm));
5779 vex_printf("first_opcode == 0xDE\n");
5780 goto decode_fail;
5781 }
sewardj137015d2005-03-27 04:01:15 +00005782
5783 } else {
5784
5785 delta++;
5786 switch (modrm) {
5787
5788 case 0xC0 ... 0xC7: /* FADDP %st(0),%st(?) */
5789 fp_do_op_ST_ST ( "add", Iop_AddF64, 0, modrm - 0xC0, True );
5790 break;
5791
5792 case 0xC8 ... 0xCF: /* FMULP %st(0),%st(?) */
5793 fp_do_op_ST_ST ( "mul", Iop_MulF64, 0, modrm - 0xC8, True );
5794 break;
5795
sewardj1859ecd2007-02-23 08:48:22 +00005796 case 0xD9: /* FCOMPP %st(0),%st(1) */
5797 DIP("fcompp %%st(0),%%st(1)\n");
5798 /* This forces C1 to zero, which isn't right. */
5799 put_C3210(
5800 unop(Iop_32Uto64,
5801 binop( Iop_And32,
5802 binop(Iop_Shl32,
5803 binop(Iop_CmpF64, get_ST(0), get_ST(1)),
5804 mkU8(8)),
5805 mkU32(0x4500)
5806 )));
5807 fp_pop();
5808 fp_pop();
5809 break;
sewardj137015d2005-03-27 04:01:15 +00005810
5811 case 0xE0 ... 0xE7: /* FSUBRP %st(0),%st(?) */
5812 fp_do_oprev_ST_ST ( "subr", Iop_SubF64, 0, modrm - 0xE0, True );
5813 break;
5814
5815 case 0xE8 ... 0xEF: /* FSUBP %st(0),%st(?) */
5816 fp_do_op_ST_ST ( "sub", Iop_SubF64, 0, modrm - 0xE8, True );
5817 break;
5818
5819 case 0xF0 ... 0xF7: /* FDIVRP %st(0),%st(?) */
5820 fp_do_oprev_ST_ST ( "divr", Iop_DivF64, 0, modrm - 0xF0, True );
5821 break;
5822
5823 case 0xF8 ... 0xFF: /* FDIVP %st(0),%st(?) */
5824 fp_do_op_ST_ST ( "div", Iop_DivF64, 0, modrm - 0xF8, True );
5825 break;
5826
5827 default:
5828 goto decode_fail;
5829 }
5830
5831 }
5832 }
sewardjc49ce232005-02-25 13:03:03 +00005833
5834 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDF opcodes +-+-+-+-+-+-+-+ */
5835 else
5836 if (first_opcode == 0xDF) {
5837
5838 if (modrm < 0xC0) {
5839
5840 /* bits 5,4,3 are an opcode extension, and the modRM also
5841 specifies an address. */
5842 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
5843 delta += len;
5844
sewardj901ed122005-02-27 13:25:31 +00005845 switch (gregLO3ofRM(modrm)) {
sewardjc49ce232005-02-25 13:03:03 +00005846
sewardj434e0692005-03-27 17:36:08 +00005847 case 0: /* FILD m16int */
5848 DIP("fildw %s\n", dis_buf);
5849 fp_push();
5850 put_ST(0, unop(Iop_I32toF64,
5851 unop(Iop_16Sto32,
5852 loadLE(Ity_I16, mkexpr(addr)))));
5853 break;
5854
sewardjfcf21f32006-08-04 14:51:19 +00005855 case 1: /* FISTTPS m16 (SSE3) */
5856 DIP("fisttps %s\n", dis_buf);
5857 storeLE( mkexpr(addr),
sewardjb707d102007-07-11 22:49:26 +00005858 x87ishly_qnarrow_32_to_16(
5859 binop(Iop_F64toI32, mkU32(Irrm_ZERO), get_ST(0)) ));
sewardjfcf21f32006-08-04 14:51:19 +00005860 fp_pop();
5861 break;
5862
sewardjd20c8852005-01-20 20:04:07 +00005863//.. case 2: /* FIST m16 */
5864//.. DIP("fistp %s\n", dis_buf);
5865//.. storeLE( mkexpr(addr),
5866//.. binop(Iop_F64toI16, get_roundingmode(), get_ST(0)) );
5867//.. break;
sewardj6847d8c2005-05-12 19:21:55 +00005868
sewardjb707d102007-07-11 22:49:26 +00005869 case 3: /* FISTP m16 */
5870 DIP("fistps %s\n", dis_buf);
5871 storeLE( mkexpr(addr),
5872 x87ishly_qnarrow_32_to_16(
5873 binop(Iop_F64toI32, get_roundingmode(), get_ST(0)) ));
5874 fp_pop();
5875 break;
sewardj37d52572005-02-25 14:22:12 +00005876
5877 case 5: /* FILD m64 */
5878 DIP("fildll %s\n", dis_buf);
5879 fp_push();
5880 put_ST(0, binop(Iop_I64toF64,
5881 get_roundingmode(),
5882 loadLE(Ity_I64, mkexpr(addr))));
5883 break;
5884
sewardj6847d8c2005-05-12 19:21:55 +00005885 case 7: /* FISTP m64 */
5886 DIP("fistpll %s\n", dis_buf);
5887 storeLE( mkexpr(addr),
5888 binop(Iop_F64toI64, get_roundingmode(), get_ST(0)) );
5889 fp_pop();
5890 break;
sewardjc49ce232005-02-25 13:03:03 +00005891
5892 default:
sewardj901ed122005-02-27 13:25:31 +00005893 vex_printf("unhandled opc_aux = 0x%2x\n", gregLO3ofRM(modrm));
sewardjc49ce232005-02-25 13:03:03 +00005894 vex_printf("first_opcode == 0xDF\n");
5895 goto decode_fail;
5896 }
5897
5898 } else {
5899
5900 delta++;
5901 switch (modrm) {
5902
5903 case 0xC0: /* FFREEP %st(0) */
5904 DIP("ffreep %%st(%d)\n", 0);
5905 put_ST_TAG ( 0, mkU8(0) );
5906 fp_pop();
5907 break;
5908
sewardj4f9847d2005-07-25 11:58:34 +00005909 case 0xE0: /* FNSTSW %ax */
5910 DIP("fnstsw %%ax\n");
5911 /* Invent a plausible-looking FPU status word value and
5912 dump it in %AX:
5913 ((ftop & 7) << 11) | (c3210 & 0x4700)
5914 */
5915 putIRegRAX(
5916 2,
5917 unop(Iop_32to16,
5918 binop(Iop_Or32,
5919 binop(Iop_Shl32,
5920 binop(Iop_And32, get_ftop(), mkU32(7)),
5921 mkU8(11)),
5922 binop(Iop_And32,
5923 unop(Iop_64to32, get_C3210()),
5924 mkU32(0x4700))
5925 )));
5926 break;
sewardj924215b2005-03-26 21:50:31 +00005927
5928 case 0xE8 ... 0xEF: /* FUCOMIP %st(0),%st(?) */
5929 fp_do_ucomi_ST0_STi( (UInt)modrm - 0xE8, True );
5930 break;
5931
sewardj48a89d82005-05-06 11:50:13 +00005932 case 0xF0 ... 0xF7: /* FCOMIP %st(0),%st(?) */
5933 /* not really right since COMIP != UCOMIP */
5934 fp_do_ucomi_ST0_STi( (UInt)modrm - 0xF0, True );
5935 break;
sewardjc49ce232005-02-25 13:03:03 +00005936
5937 default:
5938 goto decode_fail;
5939 }
5940 }
5941
5942 }
sewardj8d965312005-02-25 02:48:47 +00005943
5944 else
sewardj137015d2005-03-27 04:01:15 +00005945 goto decode_fail;
sewardj8d965312005-02-25 02:48:47 +00005946
5947 *decode_ok = True;
5948 return delta;
5949
5950 decode_fail:
5951 *decode_ok = False;
5952 return delta;
5953}
5954
5955
sewardj8711f662005-05-09 17:52:56 +00005956/*------------------------------------------------------------*/
5957/*--- ---*/
5958/*--- MMX INSTRUCTIONS ---*/
5959/*--- ---*/
5960/*------------------------------------------------------------*/
5961
5962/* Effect of MMX insns on x87 FPU state (table 11-2 of
5963 IA32 arch manual, volume 3):
5964
5965 Read from, or write to MMX register (viz, any insn except EMMS):
5966 * All tags set to Valid (non-empty) -- FPTAGS[i] := nonzero
5967 * FP stack pointer set to zero
5968
5969 EMMS:
5970 * All tags set to Invalid (empty) -- FPTAGS[i] := zero
5971 * FP stack pointer set to zero
5972*/
5973
5974static void do_MMX_preamble ( void )
5975{
sewardjdd40fdf2006-12-24 02:20:24 +00005976 Int i;
5977 IRRegArray* descr = mkIRRegArray( OFFB_FPTAGS, Ity_I8, 8 );
5978 IRExpr* zero = mkU32(0);
5979 IRExpr* tag1 = mkU8(1);
sewardj8711f662005-05-09 17:52:56 +00005980 put_ftop(zero);
5981 for (i = 0; i < 8; i++)
5982 stmt( IRStmt_PutI( descr, zero, i, tag1 ) );
5983}
5984
5985static void do_EMMS_preamble ( void )
5986{
sewardjdd40fdf2006-12-24 02:20:24 +00005987 Int i;
5988 IRRegArray* descr = mkIRRegArray( OFFB_FPTAGS, Ity_I8, 8 );
5989 IRExpr* zero = mkU32(0);
5990 IRExpr* tag0 = mkU8(0);
sewardj8711f662005-05-09 17:52:56 +00005991 put_ftop(zero);
5992 for (i = 0; i < 8; i++)
5993 stmt( IRStmt_PutI( descr, zero, i, tag0 ) );
5994}
5995
5996
5997static IRExpr* getMMXReg ( UInt archreg )
5998{
5999 vassert(archreg < 8);
6000 return IRExpr_Get( OFFB_FPREGS + 8 * archreg, Ity_I64 );
6001}
6002
6003
6004static void putMMXReg ( UInt archreg, IRExpr* e )
6005{
6006 vassert(archreg < 8);
sewardjdd40fdf2006-12-24 02:20:24 +00006007 vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_I64);
sewardj8711f662005-05-09 17:52:56 +00006008 stmt( IRStmt_Put( OFFB_FPREGS + 8 * archreg, e ) );
6009}
6010
6011
6012/* Helper for non-shift MMX insns. Note this is incomplete in the
6013 sense that it does not first call do_MMX_preamble() -- that is the
6014 responsibility of its caller. */
6015
6016static
6017ULong dis_MMXop_regmem_to_reg ( Prefix pfx,
sewardj270def42005-07-03 01:03:01 +00006018 Long delta,
sewardj8711f662005-05-09 17:52:56 +00006019 UChar opc,
sewardjca673ab2005-05-11 10:03:08 +00006020 HChar* name,
sewardj8711f662005-05-09 17:52:56 +00006021 Bool show_granularity )
6022{
6023 HChar dis_buf[50];
6024 UChar modrm = getUChar(delta);
6025 Bool isReg = epartIsReg(modrm);
6026 IRExpr* argL = NULL;
6027 IRExpr* argR = NULL;
6028 IRExpr* argG = NULL;
6029 IRExpr* argE = NULL;
6030 IRTemp res = newTemp(Ity_I64);
6031
6032 Bool invG = False;
6033 IROp op = Iop_INVALID;
6034 void* hAddr = NULL;
sewardjca673ab2005-05-11 10:03:08 +00006035 HChar* hName = NULL;
sewardj8711f662005-05-09 17:52:56 +00006036 Bool eLeft = False;
6037
6038# define XXX(_name) do { hAddr = &_name; hName = #_name; } while (0)
6039
6040 switch (opc) {
6041 /* Original MMX ones */
6042 case 0xFC: op = Iop_Add8x8; break;
6043 case 0xFD: op = Iop_Add16x4; break;
6044 case 0xFE: op = Iop_Add32x2; break;
6045
6046 case 0xEC: op = Iop_QAdd8Sx8; break;
6047 case 0xED: op = Iop_QAdd16Sx4; break;
6048
6049 case 0xDC: op = Iop_QAdd8Ux8; break;
6050 case 0xDD: op = Iop_QAdd16Ux4; break;
6051
6052 case 0xF8: op = Iop_Sub8x8; break;
6053 case 0xF9: op = Iop_Sub16x4; break;
6054 case 0xFA: op = Iop_Sub32x2; break;
6055
6056 case 0xE8: op = Iop_QSub8Sx8; break;
6057 case 0xE9: op = Iop_QSub16Sx4; break;
6058
6059 case 0xD8: op = Iop_QSub8Ux8; break;
6060 case 0xD9: op = Iop_QSub16Ux4; break;
6061
6062 case 0xE5: op = Iop_MulHi16Sx4; break;
6063 case 0xD5: op = Iop_Mul16x4; break;
6064 case 0xF5: XXX(amd64g_calculate_mmx_pmaddwd); break;
6065
6066 case 0x74: op = Iop_CmpEQ8x8; break;
6067 case 0x75: op = Iop_CmpEQ16x4; break;
6068 case 0x76: op = Iop_CmpEQ32x2; break;
6069
6070 case 0x64: op = Iop_CmpGT8Sx8; break;
6071 case 0x65: op = Iop_CmpGT16Sx4; break;
6072 case 0x66: op = Iop_CmpGT32Sx2; break;
6073
6074 case 0x6B: op = Iop_QNarrow32Sx2; eLeft = True; break;
6075 case 0x63: op = Iop_QNarrow16Sx4; eLeft = True; break;
6076 case 0x67: op = Iop_QNarrow16Ux4; eLeft = True; break;
6077
6078 case 0x68: op = Iop_InterleaveHI8x8; eLeft = True; break;
6079 case 0x69: op = Iop_InterleaveHI16x4; eLeft = True; break;
6080 case 0x6A: op = Iop_InterleaveHI32x2; eLeft = True; break;
6081
6082 case 0x60: op = Iop_InterleaveLO8x8; eLeft = True; break;
6083 case 0x61: op = Iop_InterleaveLO16x4; eLeft = True; break;
6084 case 0x62: op = Iop_InterleaveLO32x2; eLeft = True; break;
6085
6086 case 0xDB: op = Iop_And64; break;
6087 case 0xDF: op = Iop_And64; invG = True; break;
6088 case 0xEB: op = Iop_Or64; break;
6089 case 0xEF: /* Possibly do better here if argL and argR are the
6090 same reg */
6091 op = Iop_Xor64; break;
6092
6093 /* Introduced in SSE1 */
6094 case 0xE0: op = Iop_Avg8Ux8; break;
6095 case 0xE3: op = Iop_Avg16Ux4; break;
6096 case 0xEE: op = Iop_Max16Sx4; break;
6097 case 0xDE: op = Iop_Max8Ux8; break;
6098 case 0xEA: op = Iop_Min16Sx4; break;
6099 case 0xDA: op = Iop_Min8Ux8; break;
6100 case 0xE4: op = Iop_MulHi16Ux4; break;
sewardja7ba8c42005-05-10 20:08:34 +00006101 case 0xF6: XXX(amd64g_calculate_mmx_psadbw); break;
sewardj8711f662005-05-09 17:52:56 +00006102
6103 /* Introduced in SSE2 */
6104 case 0xD4: op = Iop_Add64; break;
6105 case 0xFB: op = Iop_Sub64; break;
6106
6107 default:
6108 vex_printf("\n0x%x\n", (Int)opc);
6109 vpanic("dis_MMXop_regmem_to_reg");
6110 }
6111
6112# undef XXX
6113
6114 argG = getMMXReg(gregLO3ofRM(modrm));
6115 if (invG)
6116 argG = unop(Iop_Not64, argG);
6117
6118 if (isReg) {
6119 delta++;
6120 argE = getMMXReg(eregLO3ofRM(modrm));
6121 } else {
6122 Int len;
6123 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
6124 delta += len;
6125 argE = loadLE(Ity_I64, mkexpr(addr));
6126 }
6127
6128 if (eLeft) {
6129 argL = argE;
6130 argR = argG;
6131 } else {
6132 argL = argG;
6133 argR = argE;
6134 }
6135
6136 if (op != Iop_INVALID) {
6137 vassert(hName == NULL);
6138 vassert(hAddr == NULL);
6139 assign(res, binop(op, argL, argR));
6140 } else {
6141 vassert(hName != NULL);
6142 vassert(hAddr != NULL);
6143 assign( res,
6144 mkIRExprCCall(
6145 Ity_I64,
6146 0/*regparms*/, hName, hAddr,
6147 mkIRExprVec_2( argL, argR )
6148 )
6149 );
6150 }
6151
6152 putMMXReg( gregLO3ofRM(modrm), mkexpr(res) );
6153
6154 DIP("%s%s %s, %s\n",
6155 name, show_granularity ? nameMMXGran(opc & 3) : "",
6156 ( isReg ? nameMMXReg(eregLO3ofRM(modrm)) : dis_buf ),
6157 nameMMXReg(gregLO3ofRM(modrm)) );
6158
6159 return delta;
6160}
6161
6162
6163/* Vector by scalar shift of G by the amount specified at the bottom
6164 of E. This is a straight copy of dis_SSE_shiftG_byE. */
6165
sewardj270def42005-07-03 01:03:01 +00006166static ULong dis_MMX_shiftG_byE ( Prefix pfx, Long delta,
sewardj8711f662005-05-09 17:52:56 +00006167 HChar* opname, IROp op )
6168{
6169 HChar dis_buf[50];
6170 Int alen, size;
6171 IRTemp addr;
6172 Bool shl, shr, sar;
6173 UChar rm = getUChar(delta);
6174 IRTemp g0 = newTemp(Ity_I64);
6175 IRTemp g1 = newTemp(Ity_I64);
6176 IRTemp amt = newTemp(Ity_I64);
6177 IRTemp amt8 = newTemp(Ity_I8);
6178
6179 if (epartIsReg(rm)) {
6180 assign( amt, getMMXReg(eregLO3ofRM(rm)) );
6181 DIP("%s %s,%s\n", opname,
6182 nameMMXReg(eregLO3ofRM(rm)),
6183 nameMMXReg(gregLO3ofRM(rm)) );
6184 delta++;
6185 } else {
6186 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
6187 assign( amt, loadLE(Ity_I64, mkexpr(addr)) );
6188 DIP("%s %s,%s\n", opname,
6189 dis_buf,
6190 nameMMXReg(gregLO3ofRM(rm)) );
6191 delta += alen;
6192 }
6193 assign( g0, getMMXReg(gregLO3ofRM(rm)) );
6194 assign( amt8, unop(Iop_64to8, mkexpr(amt)) );
6195
6196 shl = shr = sar = False;
6197 size = 0;
6198 switch (op) {
6199 case Iop_ShlN16x4: shl = True; size = 32; break;
6200 case Iop_ShlN32x2: shl = True; size = 32; break;
6201 case Iop_Shl64: shl = True; size = 64; break;
6202 case Iop_ShrN16x4: shr = True; size = 16; break;
6203 case Iop_ShrN32x2: shr = True; size = 32; break;
6204 case Iop_Shr64: shr = True; size = 64; break;
6205 case Iop_SarN16x4: sar = True; size = 16; break;
6206 case Iop_SarN32x2: sar = True; size = 32; break;
6207 default: vassert(0);
6208 }
6209
6210 if (shl || shr) {
6211 assign(
6212 g1,
6213 IRExpr_Mux0X(
6214 unop(Iop_1Uto8,binop(Iop_CmpLT64U,mkexpr(amt),mkU64(size))),
6215 mkU64(0),
6216 binop(op, mkexpr(g0), mkexpr(amt8))
6217 )
6218 );
6219 } else
6220 if (sar) {
6221 assign(
6222 g1,
6223 IRExpr_Mux0X(
6224 unop(Iop_1Uto8,binop(Iop_CmpLT64U,mkexpr(amt),mkU64(size))),
6225 binop(op, mkexpr(g0), mkU8(size-1)),
6226 binop(op, mkexpr(g0), mkexpr(amt8))
6227 )
6228 );
6229 } else {
6230 vassert(0);
6231 }
6232
6233 putMMXReg( gregLO3ofRM(rm), mkexpr(g1) );
6234 return delta;
6235}
6236
6237
sewardj3d8107c2005-05-09 22:23:38 +00006238/* Vector by scalar shift of E by an immediate byte. This is a
6239 straight copy of dis_SSE_shiftE_imm. */
6240
6241static
sewardj270def42005-07-03 01:03:01 +00006242ULong dis_MMX_shiftE_imm ( Long delta, HChar* opname, IROp op )
sewardj3d8107c2005-05-09 22:23:38 +00006243{
6244 Bool shl, shr, sar;
6245 UChar rm = getUChar(delta);
6246 IRTemp e0 = newTemp(Ity_I64);
6247 IRTemp e1 = newTemp(Ity_I64);
6248 UChar amt, size;
6249 vassert(epartIsReg(rm));
6250 vassert(gregLO3ofRM(rm) == 2
6251 || gregLO3ofRM(rm) == 4 || gregLO3ofRM(rm) == 6);
sewardjca673ab2005-05-11 10:03:08 +00006252 amt = getUChar(delta+1);
sewardj3d8107c2005-05-09 22:23:38 +00006253 delta += 2;
6254 DIP("%s $%d,%s\n", opname,
6255 (Int)amt,
6256 nameMMXReg(eregLO3ofRM(rm)) );
6257
6258 assign( e0, getMMXReg(eregLO3ofRM(rm)) );
6259
6260 shl = shr = sar = False;
6261 size = 0;
6262 switch (op) {
6263 case Iop_ShlN16x4: shl = True; size = 16; break;
6264 case Iop_ShlN32x2: shl = True; size = 32; break;
6265 case Iop_Shl64: shl = True; size = 64; break;
6266 case Iop_SarN16x4: sar = True; size = 16; break;
6267 case Iop_SarN32x2: sar = True; size = 32; break;
6268 case Iop_ShrN16x4: shr = True; size = 16; break;
6269 case Iop_ShrN32x2: shr = True; size = 32; break;
6270 case Iop_Shr64: shr = True; size = 64; break;
6271 default: vassert(0);
6272 }
6273
6274 if (shl || shr) {
6275 assign( e1, amt >= size
6276 ? mkU64(0)
6277 : binop(op, mkexpr(e0), mkU8(amt))
6278 );
6279 } else
6280 if (sar) {
6281 assign( e1, amt >= size
6282 ? binop(op, mkexpr(e0), mkU8(size-1))
6283 : binop(op, mkexpr(e0), mkU8(amt))
6284 );
6285 } else {
6286 vassert(0);
6287 }
6288
6289 putMMXReg( eregLO3ofRM(rm), mkexpr(e1) );
6290 return delta;
6291}
sewardj8711f662005-05-09 17:52:56 +00006292
6293
6294/* Completely handle all MMX instructions except emms. */
6295
6296static
sewardj270def42005-07-03 01:03:01 +00006297ULong dis_MMX ( Bool* decode_ok, Prefix pfx, Int sz, Long delta )
sewardj8711f662005-05-09 17:52:56 +00006298{
6299 Int len;
6300 UChar modrm;
6301 HChar dis_buf[50];
6302 UChar opc = getUChar(delta);
6303 delta++;
6304
6305 /* dis_MMX handles all insns except emms. */
6306 do_MMX_preamble();
6307
6308 switch (opc) {
6309
sewardj3d8107c2005-05-09 22:23:38 +00006310 case 0x6E:
6311 if (sz == 4) {
6312 /* MOVD (src)ireg32-or-mem32 (E), (dst)mmxreg (G)*/
6313 modrm = getUChar(delta);
6314 if (epartIsReg(modrm)) {
6315 delta++;
6316 putMMXReg(
6317 gregLO3ofRM(modrm),
6318 binop( Iop_32HLto64,
6319 mkU32(0),
6320 getIReg32(eregOfRexRM(pfx,modrm)) ) );
6321 DIP("movd %s, %s\n",
6322 nameIReg32(eregOfRexRM(pfx,modrm)),
6323 nameMMXReg(gregLO3ofRM(modrm)));
6324 } else {
6325 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
6326 delta += len;
6327 putMMXReg(
6328 gregLO3ofRM(modrm),
6329 binop( Iop_32HLto64,
6330 mkU32(0),
6331 loadLE(Ity_I32, mkexpr(addr)) ) );
6332 DIP("movd %s, %s\n", dis_buf, nameMMXReg(gregLO3ofRM(modrm)));
6333 }
6334 }
6335 else
6336 if (sz == 8) {
6337 /* MOVD (src)ireg64-or-mem64 (E), (dst)mmxreg (G)*/
6338 modrm = getUChar(delta);
6339 if (epartIsReg(modrm)) {
6340 delta++;
6341 putMMXReg( gregLO3ofRM(modrm),
6342 getIReg64(eregOfRexRM(pfx,modrm)) );
6343 DIP("movd %s, %s\n",
6344 nameIReg64(eregOfRexRM(pfx,modrm)),
6345 nameMMXReg(gregLO3ofRM(modrm)));
6346 } else {
6347 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
6348 delta += len;
6349 putMMXReg( gregLO3ofRM(modrm),
6350 loadLE(Ity_I64, mkexpr(addr)) );
6351 DIP("movd{64} %s, %s\n", dis_buf, nameMMXReg(gregLO3ofRM(modrm)));
6352 }
6353 }
6354 else {
6355 goto mmx_decode_failure;
6356 }
6357 break;
6358
6359 case 0x7E:
6360 if (sz == 4) {
6361 /* MOVD (src)mmxreg (G), (dst)ireg32-or-mem32 (E) */
6362 modrm = getUChar(delta);
6363 if (epartIsReg(modrm)) {
6364 delta++;
6365 putIReg32( eregOfRexRM(pfx,modrm),
6366 unop(Iop_64to32, getMMXReg(gregLO3ofRM(modrm)) ) );
6367 DIP("movd %s, %s\n",
6368 nameMMXReg(gregLO3ofRM(modrm)),
6369 nameIReg32(eregOfRexRM(pfx,modrm)));
6370 } else {
6371 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
6372 delta += len;
6373 storeLE( mkexpr(addr),
6374 unop(Iop_64to32, getMMXReg(gregLO3ofRM(modrm)) ) );
6375 DIP("movd %s, %s\n", nameMMXReg(gregLO3ofRM(modrm)), dis_buf);
6376 }
6377 }
6378 else
6379 if (sz == 8) {
6380 /* MOVD (src)mmxreg (G), (dst)ireg64-or-mem64 (E) */
6381 modrm = getUChar(delta);
6382 if (epartIsReg(modrm)) {
6383 delta++;
6384 putIReg64( eregOfRexRM(pfx,modrm),
6385 getMMXReg(gregLO3ofRM(modrm)) );
6386 DIP("movd %s, %s\n",
6387 nameMMXReg(gregLO3ofRM(modrm)),
6388 nameIReg64(eregOfRexRM(pfx,modrm)));
6389 } else {
6390 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
6391 delta += len;
6392 storeLE( mkexpr(addr),
6393 getMMXReg(gregLO3ofRM(modrm)) );
6394 DIP("movd{64} %s, %s\n", nameMMXReg(gregLO3ofRM(modrm)), dis_buf);
6395 }
6396 } else {
6397 goto mmx_decode_failure;
6398 }
6399 break;
sewardj8711f662005-05-09 17:52:56 +00006400
6401 case 0x6F:
6402 /* MOVQ (src)mmxreg-or-mem, (dst)mmxreg */
6403 if (sz != 4)
6404 goto mmx_decode_failure;
6405 modrm = getUChar(delta);
6406 if (epartIsReg(modrm)) {
6407 delta++;
6408 putMMXReg( gregLO3ofRM(modrm), getMMXReg(eregLO3ofRM(modrm)) );
6409 DIP("movq %s, %s\n",
6410 nameMMXReg(eregLO3ofRM(modrm)),
6411 nameMMXReg(gregLO3ofRM(modrm)));
6412 } else {
6413 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
6414 delta += len;
6415 putMMXReg( gregLO3ofRM(modrm), loadLE(Ity_I64, mkexpr(addr)) );
6416 DIP("movq %s, %s\n",
6417 dis_buf, nameMMXReg(gregLO3ofRM(modrm)));
6418 }
6419 break;
6420
6421 case 0x7F:
6422 /* MOVQ (src)mmxreg, (dst)mmxreg-or-mem */
6423 if (sz != 4)
6424 goto mmx_decode_failure;
6425 modrm = getUChar(delta);
6426 if (epartIsReg(modrm)) {
6427 /* Fall through. The assembler doesn't appear to generate
6428 these. */
6429 goto mmx_decode_failure;
6430 } else {
6431 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
6432 delta += len;
6433 storeLE( mkexpr(addr), getMMXReg(gregLO3ofRM(modrm)) );
6434 DIP("mov(nt)q %s, %s\n",
6435 nameMMXReg(gregLO3ofRM(modrm)), dis_buf);
6436 }
6437 break;
6438
6439 case 0xFC:
6440 case 0xFD:
6441 case 0xFE: /* PADDgg (src)mmxreg-or-mem, (dst)mmxreg */
6442 if (sz != 4)
6443 goto mmx_decode_failure;
6444 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "padd", True );
6445 break;
6446
6447 case 0xEC:
6448 case 0xED: /* PADDSgg (src)mmxreg-or-mem, (dst)mmxreg */
6449 if (sz != 4)
6450 goto mmx_decode_failure;
6451 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "padds", True );
6452 break;
6453
6454 case 0xDC:
6455 case 0xDD: /* PADDUSgg (src)mmxreg-or-mem, (dst)mmxreg */
6456 if (sz != 4)
6457 goto mmx_decode_failure;
6458 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "paddus", True );
6459 break;
6460
6461 case 0xF8:
6462 case 0xF9:
6463 case 0xFA: /* PSUBgg (src)mmxreg-or-mem, (dst)mmxreg */
6464 if (sz != 4)
6465 goto mmx_decode_failure;
6466 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "psub", True );
6467 break;
6468
6469 case 0xE8:
6470 case 0xE9: /* PSUBSgg (src)mmxreg-or-mem, (dst)mmxreg */
6471 if (sz != 4)
6472 goto mmx_decode_failure;
6473 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "psubs", True );
6474 break;
6475
6476 case 0xD8:
6477 case 0xD9: /* PSUBUSgg (src)mmxreg-or-mem, (dst)mmxreg */
6478 if (sz != 4)
6479 goto mmx_decode_failure;
6480 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "psubus", True );
6481 break;
6482
6483 case 0xE5: /* PMULHW (src)mmxreg-or-mem, (dst)mmxreg */
6484 if (sz != 4)
6485 goto mmx_decode_failure;
6486 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "pmulhw", False );
6487 break;
6488
6489 case 0xD5: /* PMULLW (src)mmxreg-or-mem, (dst)mmxreg */
6490 if (sz != 4)
6491 goto mmx_decode_failure;
6492 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "pmullw", False );
6493 break;
6494
6495 case 0xF5: /* PMADDWD (src)mmxreg-or-mem, (dst)mmxreg */
6496 vassert(sz == 4);
6497 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "pmaddwd", False );
6498 break;
6499
6500 case 0x74:
6501 case 0x75:
6502 case 0x76: /* PCMPEQgg (src)mmxreg-or-mem, (dst)mmxreg */
6503 if (sz != 4)
6504 goto mmx_decode_failure;
6505 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "pcmpeq", True );
6506 break;
6507
6508 case 0x64:
6509 case 0x65:
6510 case 0x66: /* PCMPGTgg (src)mmxreg-or-mem, (dst)mmxreg */
6511 if (sz != 4)
6512 goto mmx_decode_failure;
6513 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "pcmpgt", True );
6514 break;
6515
6516 case 0x6B: /* PACKSSDW (src)mmxreg-or-mem, (dst)mmxreg */
6517 if (sz != 4)
6518 goto mmx_decode_failure;
6519 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "packssdw", False );
6520 break;
6521
6522 case 0x63: /* PACKSSWB (src)mmxreg-or-mem, (dst)mmxreg */
6523 if (sz != 4)
6524 goto mmx_decode_failure;
6525 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "packsswb", False );
6526 break;
6527
6528 case 0x67: /* PACKUSWB (src)mmxreg-or-mem, (dst)mmxreg */
6529 if (sz != 4)
6530 goto mmx_decode_failure;
6531 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "packuswb", False );
6532 break;
6533
6534 case 0x68:
6535 case 0x69:
6536 case 0x6A: /* PUNPCKHgg (src)mmxreg-or-mem, (dst)mmxreg */
6537 if (sz != 4)
6538 goto mmx_decode_failure;
6539 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "punpckh", True );
6540 break;
6541
6542 case 0x60:
6543 case 0x61:
6544 case 0x62: /* PUNPCKLgg (src)mmxreg-or-mem, (dst)mmxreg */
6545 if (sz != 4)
6546 goto mmx_decode_failure;
6547 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "punpckl", True );
6548 break;
6549
6550 case 0xDB: /* PAND (src)mmxreg-or-mem, (dst)mmxreg */
6551 if (sz != 4)
6552 goto mmx_decode_failure;
6553 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "pand", False );
6554 break;
6555
6556 case 0xDF: /* PANDN (src)mmxreg-or-mem, (dst)mmxreg */
6557 if (sz != 4)
6558 goto mmx_decode_failure;
6559 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "pandn", False );
6560 break;
6561
6562 case 0xEB: /* POR (src)mmxreg-or-mem, (dst)mmxreg */
6563 if (sz != 4)
6564 goto mmx_decode_failure;
6565 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "por", False );
6566 break;
6567
6568 case 0xEF: /* PXOR (src)mmxreg-or-mem, (dst)mmxreg */
6569 if (sz != 4)
6570 goto mmx_decode_failure;
6571 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "pxor", False );
6572 break;
6573
6574# define SHIFT_BY_REG(_name,_op) \
6575 delta = dis_MMX_shiftG_byE(pfx, delta, _name, _op); \
6576 break;
6577
6578 /* PSLLgg (src)mmxreg-or-mem, (dst)mmxreg */
6579 case 0xF1: SHIFT_BY_REG("psllw", Iop_ShlN16x4);
6580 case 0xF2: SHIFT_BY_REG("pslld", Iop_ShlN32x2);
6581 case 0xF3: SHIFT_BY_REG("psllq", Iop_Shl64);
6582
6583 /* PSRLgg (src)mmxreg-or-mem, (dst)mmxreg */
6584 case 0xD1: SHIFT_BY_REG("psrlw", Iop_ShrN16x4);
6585 case 0xD2: SHIFT_BY_REG("psrld", Iop_ShrN32x2);
6586 case 0xD3: SHIFT_BY_REG("psrlq", Iop_Shr64);
6587
6588 /* PSRAgg (src)mmxreg-or-mem, (dst)mmxreg */
6589 case 0xE1: SHIFT_BY_REG("psraw", Iop_SarN16x4);
6590 case 0xE2: SHIFT_BY_REG("psrad", Iop_SarN32x2);
6591
6592# undef SHIFT_BY_REG
sewardj3d8107c2005-05-09 22:23:38 +00006593
6594 case 0x71:
6595 case 0x72:
6596 case 0x73: {
6597 /* (sz==4): PSLLgg/PSRAgg/PSRLgg mmxreg by imm8 */
sewardjca673ab2005-05-11 10:03:08 +00006598 UChar byte2, subopc;
sewardj3d8107c2005-05-09 22:23:38 +00006599 if (sz != 4)
6600 goto mmx_decode_failure;
sewardjca673ab2005-05-11 10:03:08 +00006601 byte2 = getUChar(delta); /* amode / sub-opcode */
6602 subopc = toUChar( (byte2 >> 3) & 7 );
sewardj3d8107c2005-05-09 22:23:38 +00006603
6604# define SHIFT_BY_IMM(_name,_op) \
6605 do { delta = dis_MMX_shiftE_imm(delta,_name,_op); \
6606 } while (0)
6607
6608 if (subopc == 2 /*SRL*/ && opc == 0x71)
6609 SHIFT_BY_IMM("psrlw", Iop_ShrN16x4);
6610 else if (subopc == 2 /*SRL*/ && opc == 0x72)
6611 SHIFT_BY_IMM("psrld", Iop_ShrN32x2);
6612 else if (subopc == 2 /*SRL*/ && opc == 0x73)
6613 SHIFT_BY_IMM("psrlq", Iop_Shr64);
6614
6615 else if (subopc == 4 /*SAR*/ && opc == 0x71)
6616 SHIFT_BY_IMM("psraw", Iop_SarN16x4);
6617 else if (subopc == 4 /*SAR*/ && opc == 0x72)
6618 SHIFT_BY_IMM("psrad", Iop_SarN32x2);
6619
6620 else if (subopc == 6 /*SHL*/ && opc == 0x71)
6621 SHIFT_BY_IMM("psllw", Iop_ShlN16x4);
6622 else if (subopc == 6 /*SHL*/ && opc == 0x72)
6623 SHIFT_BY_IMM("pslld", Iop_ShlN32x2);
6624 else if (subopc == 6 /*SHL*/ && opc == 0x73)
6625 SHIFT_BY_IMM("psllq", Iop_Shl64);
6626
6627 else goto mmx_decode_failure;
6628
6629# undef SHIFT_BY_IMM
6630 break;
6631 }
sewardj8711f662005-05-09 17:52:56 +00006632
sewardj02f79f12007-09-01 18:59:53 +00006633 case 0xF7: {
6634 IRTemp addr = newTemp(Ity_I64);
6635 IRTemp regD = newTemp(Ity_I64);
6636 IRTemp regM = newTemp(Ity_I64);
6637 IRTemp mask = newTemp(Ity_I64);
6638 IRTemp olddata = newTemp(Ity_I64);
6639 IRTemp newdata = newTemp(Ity_I64);
6640
6641 modrm = getUChar(delta);
6642 if (sz != 4 || (!epartIsReg(modrm)))
6643 goto mmx_decode_failure;
6644 delta++;
6645
6646 assign( addr, handleAddrOverrides( pfx, getIReg64(R_RDI) ));
6647 assign( regM, getMMXReg( eregLO3ofRM(modrm) ));
6648 assign( regD, getMMXReg( gregLO3ofRM(modrm) ));
6649 assign( mask, binop(Iop_SarN8x8, mkexpr(regM), mkU8(7)) );
6650 assign( olddata, loadLE( Ity_I64, mkexpr(addr) ));
6651 assign( newdata,
6652 binop(Iop_Or64,
6653 binop(Iop_And64,
6654 mkexpr(regD),
6655 mkexpr(mask) ),
6656 binop(Iop_And64,
6657 mkexpr(olddata),
6658 unop(Iop_Not64, mkexpr(mask)))) );
6659 storeLE( mkexpr(addr), mkexpr(newdata) );
6660 DIP("maskmovq %s,%s\n", nameMMXReg( eregLO3ofRM(modrm) ),
6661 nameMMXReg( gregLO3ofRM(modrm) ) );
6662 break;
6663 }
6664
sewardj8711f662005-05-09 17:52:56 +00006665 /* --- MMX decode failure --- */
6666 default:
6667 mmx_decode_failure:
6668 *decode_ok = False;
6669 return delta; /* ignored */
6670
6671 }
6672
6673 *decode_ok = True;
6674 return delta;
6675}
6676
6677
sewardj33ef9c22005-11-04 20:05:57 +00006678/*------------------------------------------------------------*/
6679/*--- More misc arithmetic and other obscure insns. ---*/
6680/*------------------------------------------------------------*/
6681
6682/* Generate base << amt with vacated places filled with stuff
6683 from xtra. amt guaranteed in 0 .. 63. */
6684static
6685IRExpr* shiftL64_with_extras ( IRTemp base, IRTemp xtra, IRTemp amt )
6686{
6687 /* if amt == 0
6688 then base
6689 else (base << amt) | (xtra >>u (64-amt))
6690 */
6691 return
6692 IRExpr_Mux0X(
6693 mkexpr(amt),
6694 mkexpr(base),
6695 binop(Iop_Or64,
6696 binop(Iop_Shl64, mkexpr(base), mkexpr(amt)),
6697 binop(Iop_Shr64, mkexpr(xtra),
6698 binop(Iop_Sub8, mkU8(64), mkexpr(amt)))
6699 )
6700 );
6701}
6702
6703/* Generate base >>u amt with vacated places filled with stuff
6704 from xtra. amt guaranteed in 0 .. 63. */
6705static
6706IRExpr* shiftR64_with_extras ( IRTemp xtra, IRTemp base, IRTemp amt )
6707{
6708 /* if amt == 0
6709 then base
6710 else (base >>u amt) | (xtra << (64-amt))
6711 */
6712 return
6713 IRExpr_Mux0X(
6714 mkexpr(amt),
6715 mkexpr(base),
6716 binop(Iop_Or64,
6717 binop(Iop_Shr64, mkexpr(base), mkexpr(amt)),
6718 binop(Iop_Shl64, mkexpr(xtra),
6719 binop(Iop_Sub8, mkU8(64), mkexpr(amt)))
6720 )
6721 );
6722}
6723
6724/* Double length left and right shifts. Apparently only required in
6725 v-size (no b- variant). */
6726static
6727ULong dis_SHLRD_Gv_Ev ( Prefix pfx,
6728 Long delta, UChar modrm,
6729 Int sz,
6730 IRExpr* shift_amt,
6731 Bool amt_is_literal,
sewardjf5268432005-11-05 02:58:55 +00006732 HChar* shift_amt_txt,
sewardj33ef9c22005-11-04 20:05:57 +00006733 Bool left_shift )
6734{
6735 /* shift_amt :: Ity_I8 is the amount to shift. shift_amt_txt is used
6736 for printing it. And eip on entry points at the modrm byte. */
6737 Int len;
6738 HChar dis_buf[50];
6739
6740 IRType ty = szToITy(sz);
6741 IRTemp gsrc = newTemp(ty);
6742 IRTemp esrc = newTemp(ty);
6743 IRTemp addr = IRTemp_INVALID;
6744 IRTemp tmpSH = newTemp(Ity_I8);
6745 IRTemp tmpSS = newTemp(Ity_I8);
6746 IRTemp tmp64 = IRTemp_INVALID;
6747 IRTemp res64 = IRTemp_INVALID;
6748 IRTemp rss64 = IRTemp_INVALID;
6749 IRTemp resTy = IRTemp_INVALID;
6750 IRTemp rssTy = IRTemp_INVALID;
6751 Int mask = sz==8 ? 63 : 31;
6752
6753 vassert(sz == 2 || sz == 4 || sz == 8);
6754
6755 /* The E-part is the destination; this is shifted. The G-part
6756 supplies bits to be shifted into the E-part, but is not
6757 changed.
6758
6759 If shifting left, form a double-length word with E at the top
6760 and G at the bottom, and shift this left. The result is then in
6761 the high part.
6762
6763 If shifting right, form a double-length word with G at the top
6764 and E at the bottom, and shift this right. The result is then
6765 at the bottom. */
6766
6767 /* Fetch the operands. */
6768
6769 assign( gsrc, getIRegG(sz, pfx, modrm) );
6770
6771 if (epartIsReg(modrm)) {
6772 delta++;
6773 assign( esrc, getIRegE(sz, pfx, modrm) );
6774 DIP("sh%cd%c %s, %s, %s\n",
6775 ( left_shift ? 'l' : 'r' ), nameISize(sz),
6776 shift_amt_txt,
6777 nameIRegG(sz, pfx, modrm), nameIRegE(sz, pfx, modrm));
6778 } else {
sewardj75ce3652005-11-04 20:49:36 +00006779 addr = disAMode ( &len, pfx, delta, dis_buf,
6780 /* # bytes following amode */
6781 amt_is_literal ? 1 : 0 );
sewardj33ef9c22005-11-04 20:05:57 +00006782 delta += len;
6783 assign( esrc, loadLE(ty, mkexpr(addr)) );
6784 DIP("sh%cd%c %s, %s, %s\n",
6785 ( left_shift ? 'l' : 'r' ), nameISize(sz),
6786 shift_amt_txt,
6787 nameIRegG(sz, pfx, modrm), dis_buf);
6788 }
6789
6790 /* Calculate the masked shift amount (tmpSH), the masked subshift
6791 amount (tmpSS), the shifted value (res64) and the subshifted
6792 value (rss64). */
6793
6794 assign( tmpSH, binop(Iop_And8, shift_amt, mkU8(mask)) );
6795 assign( tmpSS, binop(Iop_And8,
6796 binop(Iop_Sub8, mkexpr(tmpSH), mkU8(1) ),
6797 mkU8(mask)));
6798
6799 tmp64 = newTemp(Ity_I64);
6800 res64 = newTemp(Ity_I64);
6801 rss64 = newTemp(Ity_I64);
6802
6803 if (sz == 2 || sz == 4) {
6804
6805 /* G is xtra; E is data */
6806 /* what a freaking nightmare: */
6807 if (sz == 4 && left_shift) {
6808 assign( tmp64, binop(Iop_32HLto64, mkexpr(esrc), mkexpr(gsrc)) );
6809 assign( res64,
6810 binop(Iop_Shr64,
6811 binop(Iop_Shl64, mkexpr(tmp64), mkexpr(tmpSH)),
6812 mkU8(32)) );
6813 assign( rss64,
6814 binop(Iop_Shr64,
6815 binop(Iop_Shl64, mkexpr(tmp64), mkexpr(tmpSS)),
6816 mkU8(32)) );
6817 }
6818 else
6819 if (sz == 4 && !left_shift) {
6820 assign( tmp64, binop(Iop_32HLto64, mkexpr(gsrc), mkexpr(esrc)) );
6821 assign( res64, binop(Iop_Shr64, mkexpr(tmp64), mkexpr(tmpSH)) );
6822 assign( rss64, binop(Iop_Shr64, mkexpr(tmp64), mkexpr(tmpSS)) );
6823 }
6824 else
6825 if (sz == 2 && left_shift) {
6826 assign( tmp64,
6827 binop(Iop_32HLto64,
6828 binop(Iop_16HLto32, mkexpr(esrc), mkexpr(gsrc)),
6829 binop(Iop_16HLto32, mkexpr(gsrc), mkexpr(gsrc))
6830 ));
6831 /* result formed by shifting [esrc'gsrc'gsrc'gsrc] */
6832 assign( res64,
6833 binop(Iop_Shr64,
6834 binop(Iop_Shl64, mkexpr(tmp64), mkexpr(tmpSH)),
6835 mkU8(48)) );
6836 /* subshift formed by shifting [esrc'0000'0000'0000] */
6837 assign( rss64,
6838 binop(Iop_Shr64,
6839 binop(Iop_Shl64,
6840 binop(Iop_Shl64, unop(Iop_16Uto64, mkexpr(esrc)),
6841 mkU8(48)),
6842 mkexpr(tmpSS)),
6843 mkU8(48)) );
6844 }
6845 else
6846 if (sz == 2 && !left_shift) {
6847 assign( tmp64,
6848 binop(Iop_32HLto64,
6849 binop(Iop_16HLto32, mkexpr(gsrc), mkexpr(gsrc)),
6850 binop(Iop_16HLto32, mkexpr(gsrc), mkexpr(esrc))
6851 ));
6852 /* result formed by shifting [gsrc'gsrc'gsrc'esrc] */
6853 assign( res64, binop(Iop_Shr64, mkexpr(tmp64), mkexpr(tmpSH)) );
6854 /* subshift formed by shifting [0000'0000'0000'esrc] */
6855 assign( rss64, binop(Iop_Shr64,
6856 unop(Iop_16Uto64, mkexpr(esrc)),
6857 mkexpr(tmpSS)) );
6858 }
6859
6860 } else {
6861
6862 vassert(sz == 8);
6863 if (left_shift) {
6864 assign( res64, shiftL64_with_extras( esrc, gsrc, tmpSH ));
6865 assign( rss64, shiftL64_with_extras( esrc, gsrc, tmpSS ));
6866 } else {
6867 assign( res64, shiftR64_with_extras( gsrc, esrc, tmpSH ));
6868 assign( rss64, shiftR64_with_extras( gsrc, esrc, tmpSS ));
6869 }
6870
6871 }
6872
6873 resTy = newTemp(ty);
6874 rssTy = newTemp(ty);
6875 assign( resTy, narrowTo(ty, mkexpr(res64)) );
6876 assign( rssTy, narrowTo(ty, mkexpr(rss64)) );
6877
6878 /* Put result back and write the flags thunk. */
6879 setFlags_DEP1_DEP2_shift ( left_shift ? Iop_Shl64 : Iop_Sar64,
6880 resTy, rssTy, ty, tmpSH );
6881
6882 if (epartIsReg(modrm)) {
6883 putIRegE(sz, pfx, modrm, mkexpr(resTy));
6884 } else {
6885 storeLE( mkexpr(addr), mkexpr(resTy) );
6886 }
6887
6888 if (amt_is_literal) delta++;
6889 return delta;
6890}
sewardj9ed16802005-08-24 10:46:19 +00006891
6892
6893/* Handle BT/BTS/BTR/BTC Gv, Ev. Apparently b-size is not
6894 required. */
6895
6896typedef enum { BtOpNone, BtOpSet, BtOpReset, BtOpComp } BtOp;
6897
6898static HChar* nameBtOp ( BtOp op )
6899{
6900 switch (op) {
6901 case BtOpNone: return "";
6902 case BtOpSet: return "s";
6903 case BtOpReset: return "r";
6904 case BtOpComp: return "c";
6905 default: vpanic("nameBtOp(amd64)");
6906 }
6907}
6908
6909
6910static
6911ULong dis_bt_G_E ( Prefix pfx, Int sz, Long delta, BtOp op )
6912{
6913 HChar dis_buf[50];
6914 UChar modrm;
6915 Int len;
6916 IRTemp t_fetched, t_bitno0, t_bitno1, t_bitno2, t_addr0,
6917 t_addr1, t_rsp, t_mask;
6918
6919 vassert(sz == 2 || sz == 4 || sz == 8);
6920
6921 t_fetched = t_bitno0 = t_bitno1 = t_bitno2
6922 = t_addr0 = t_addr1 = t_rsp = t_mask = IRTemp_INVALID;
6923
6924 t_fetched = newTemp(Ity_I8);
6925 t_bitno0 = newTemp(Ity_I64);
6926 t_bitno1 = newTemp(Ity_I64);
6927 t_bitno2 = newTemp(Ity_I8);
6928 t_addr1 = newTemp(Ity_I64);
6929 modrm = getUChar(delta);
6930
6931 assign( t_bitno0, widenSto64(getIRegG(sz, pfx, modrm)) );
6932
6933 if (epartIsReg(modrm)) {
6934 delta++;
6935 /* Get it onto the client's stack. */
6936 t_rsp = newTemp(Ity_I64);
6937 t_addr0 = newTemp(Ity_I64);
6938
6939 assign( t_rsp, binop(Iop_Sub64, getIReg64(R_RSP), mkU64(sz)) );
6940 putIReg64(R_RSP, mkexpr(t_rsp));
6941
6942 storeLE( mkexpr(t_rsp), getIRegE(sz, pfx, modrm) );
6943
6944 /* Make t_addr0 point at it. */
6945 assign( t_addr0, mkexpr(t_rsp) );
6946
6947 /* Mask out upper bits of the shift amount, since we're doing a
6948 reg. */
6949 assign( t_bitno1, binop(Iop_And64,
6950 mkexpr(t_bitno0),
6951 mkU64(sz == 8 ? 63 : sz == 4 ? 31 : 15)) );
6952
6953 } else {
6954 t_addr0 = disAMode ( &len, pfx, delta, dis_buf, 0 );
6955 delta += len;
6956 assign( t_bitno1, mkexpr(t_bitno0) );
6957 }
6958
6959 /* At this point: t_addr0 is the address being operated on. If it
6960 was a reg, we will have pushed it onto the client's stack.
6961 t_bitno1 is the bit number, suitably masked in the case of a
6962 reg. */
6963
6964 /* Now the main sequence. */
6965 assign( t_addr1,
6966 binop(Iop_Add64,
6967 mkexpr(t_addr0),
6968 binop(Iop_Sar64, mkexpr(t_bitno1), mkU8(3))) );
6969
6970 /* t_addr1 now holds effective address */
6971
6972 assign( t_bitno2,
6973 unop(Iop_64to8,
6974 binop(Iop_And64, mkexpr(t_bitno1), mkU64(7))) );
6975
6976 /* t_bitno2 contains offset of bit within byte */
6977
6978 if (op != BtOpNone) {
6979 t_mask = newTemp(Ity_I8);
6980 assign( t_mask, binop(Iop_Shl8, mkU8(1), mkexpr(t_bitno2)) );
6981 }
6982
6983 /* t_mask is now a suitable byte mask */
6984
6985 assign( t_fetched, loadLE(Ity_I8, mkexpr(t_addr1)) );
6986
6987 if (op != BtOpNone) {
6988 switch (op) {
6989 case BtOpSet:
6990 storeLE( mkexpr(t_addr1),
6991 binop(Iop_Or8, mkexpr(t_fetched),
6992 mkexpr(t_mask)) );
6993 break;
6994 case BtOpComp:
6995 storeLE( mkexpr(t_addr1),
6996 binop(Iop_Xor8, mkexpr(t_fetched),
6997 mkexpr(t_mask)) );
6998 break;
6999 case BtOpReset:
7000 storeLE( mkexpr(t_addr1),
7001 binop(Iop_And8, mkexpr(t_fetched),
7002 unop(Iop_Not8, mkexpr(t_mask))) );
7003 break;
7004 default:
7005 vpanic("dis_bt_G_E(amd64)");
7006 }
7007 }
7008
7009 /* Side effect done; now get selected bit into Carry flag */
7010 /* Flags: C=selected bit, O,S,Z,A,P undefined, so are set to zero. */
7011 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(AMD64G_CC_OP_COPY) ));
7012 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
7013 stmt( IRStmt_Put(
7014 OFFB_CC_DEP1,
7015 binop(Iop_And64,
7016 binop(Iop_Shr64,
7017 unop(Iop_8Uto64, mkexpr(t_fetched)),
7018 mkexpr(t_bitno2)),
7019 mkU64(1)))
7020 );
7021 /* Set NDEP even though it isn't used. This makes redundant-PUT
7022 elimination of previous stores to this field work better. */
7023 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU64(0) ));
7024
7025 /* Move reg operand from stack back to reg */
7026 if (epartIsReg(modrm)) {
7027 /* t_esp still points at it. */
sewardj25d23862006-05-12 17:47:21 +00007028 /* only write the reg if actually modifying it; doing otherwise
7029 zeroes the top half erroneously when doing btl due to
7030 standard zero-extend rule */
7031 if (op != BtOpNone)
7032 putIRegE(sz, pfx, modrm, loadLE(szToITy(sz), mkexpr(t_rsp)) );
sewardj9ed16802005-08-24 10:46:19 +00007033 putIReg64(R_RSP, binop(Iop_Add64, mkexpr(t_rsp), mkU64(sz)) );
7034 }
7035
7036 DIP("bt%s%c %s, %s\n",
7037 nameBtOp(op), nameISize(sz), nameIRegG(sz, pfx, modrm),
7038 ( epartIsReg(modrm) ? nameIRegE(sz, pfx, modrm) : dis_buf ) );
7039
7040 return delta;
7041}
sewardjf53b7352005-04-06 20:01:56 +00007042
7043
7044
7045/* Handle BSF/BSR. Only v-size seems necessary. */
7046static
sewardj270def42005-07-03 01:03:01 +00007047ULong dis_bs_E_G ( Prefix pfx, Int sz, Long delta, Bool fwds )
sewardjf53b7352005-04-06 20:01:56 +00007048{
7049 Bool isReg;
7050 UChar modrm;
7051 HChar dis_buf[50];
7052
7053 IRType ty = szToITy(sz);
7054 IRTemp src = newTemp(ty);
7055 IRTemp dst = newTemp(ty);
7056 IRTemp src64 = newTemp(Ity_I64);
7057 IRTemp dst64 = newTemp(Ity_I64);
7058 IRTemp src8 = newTemp(Ity_I8);
7059
7060 vassert(sz == 8 || sz == 4 || sz == 2);
7061
7062 modrm = getUChar(delta);
7063 isReg = epartIsReg(modrm);
7064 if (isReg) {
7065 delta++;
7066 assign( src, getIRegE(sz, pfx, modrm) );
7067 } else {
7068 Int len;
7069 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
7070 delta += len;
7071 assign( src, loadLE(ty, mkexpr(addr)) );
7072 }
7073
7074 DIP("bs%c%c %s, %s\n",
7075 fwds ? 'f' : 'r', nameISize(sz),
7076 ( isReg ? nameIRegE(sz, pfx, modrm) : dis_buf ),
7077 nameIRegG(sz, pfx, modrm));
7078
7079 /* First, widen src to 64 bits if it is not already. */
7080 assign( src64, widenUto64(mkexpr(src)) );
7081
7082 /* Generate an 8-bit expression which is zero iff the
7083 original is zero, and nonzero otherwise */
7084 assign( src8,
7085 unop(Iop_1Uto8,
7086 binop(Iop_CmpNE64,
7087 mkexpr(src64), mkU64(0))) );
7088
7089 /* Flags: Z is 1 iff source value is zero. All others
7090 are undefined -- we force them to zero. */
7091 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(AMD64G_CC_OP_COPY) ));
7092 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
7093 stmt( IRStmt_Put(
7094 OFFB_CC_DEP1,
7095 IRExpr_Mux0X( mkexpr(src8),
7096 /* src==0 */
7097 mkU64(AMD64G_CC_MASK_Z),
7098 /* src!=0 */
7099 mkU64(0)
7100 )
7101 ));
7102 /* Set NDEP even though it isn't used. This makes redundant-PUT
7103 elimination of previous stores to this field work better. */
7104 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU64(0) ));
7105
7106 /* Result: iff source value is zero, we can't use
7107 Iop_Clz64/Iop_Ctz64 as they have no defined result in that case.
7108 But anyway, amd64 semantics say the result is undefined in
7109 such situations. Hence handle the zero case specially. */
7110
7111 /* Bleh. What we compute:
7112
7113 bsf64: if src == 0 then {dst is unchanged}
7114 else Ctz64(src)
7115
7116 bsr64: if src == 0 then {dst is unchanged}
7117 else 63 - Clz64(src)
7118
7119 bsf32: if src == 0 then {dst is unchanged}
7120 else Ctz64(32Uto64(src))
7121
7122 bsr32: if src == 0 then {dst is unchanged}
7123 else 63 - Clz64(32Uto64(src))
7124
7125 bsf16: if src == 0 then {dst is unchanged}
7126 else Ctz64(32Uto64(16Uto32(src)))
7127
7128 bsr16: if src == 0 then {dst is unchanged}
7129 else 63 - Clz64(32Uto64(16Uto32(src)))
7130 */
7131
7132 /* The main computation, guarding against zero. */
7133 assign( dst64,
7134 IRExpr_Mux0X(
7135 mkexpr(src8),
7136 /* src == 0 -- leave dst unchanged */
7137 widenUto64( getIRegG( sz, pfx, modrm ) ),
7138 /* src != 0 */
7139 fwds ? unop(Iop_Ctz64, mkexpr(src64))
7140 : binop(Iop_Sub64,
7141 mkU64(63),
7142 unop(Iop_Clz64, mkexpr(src64)))
7143 )
7144 );
7145
7146 if (sz == 2)
sewardje58967e2005-04-27 11:50:56 +00007147 assign( dst, unop(Iop_64to16, mkexpr(dst64)) );
sewardjf53b7352005-04-06 20:01:56 +00007148 else
7149 if (sz == 4)
7150 assign( dst, unop(Iop_64to32, mkexpr(dst64)) );
7151 else
7152 assign( dst, mkexpr(dst64) );
7153
7154 /* dump result back */
7155 putIRegG( sz, pfx, modrm, mkexpr(dst) );
7156
7157 return delta;
7158}
sewardja6b93d12005-02-17 09:28:28 +00007159
7160
7161/* swap rAX with the reg specified by reg and REX.B */
7162static
sewardj5b470602005-02-27 13:10:48 +00007163void codegen_xchg_rAX_Reg ( Prefix pfx, Int sz, UInt regLo3 )
sewardja6b93d12005-02-17 09:28:28 +00007164{
7165 IRType ty = szToITy(sz);
7166 IRTemp t1 = newTemp(ty);
7167 IRTemp t2 = newTemp(ty);
sewardj2d4fcd52005-05-18 11:47:47 +00007168 vassert(sz == 4 || sz == 8);
sewardj5b470602005-02-27 13:10:48 +00007169 vassert(regLo3 < 8);
sewardj2d4fcd52005-05-18 11:47:47 +00007170 if (sz == 8) {
7171 assign( t1, getIReg64(R_RAX) );
7172 assign( t2, getIRegRexB(8, pfx, regLo3) );
7173 putIReg64( R_RAX, mkexpr(t2) );
7174 putIRegRexB(8, pfx, regLo3, mkexpr(t1) );
7175 } else {
7176 assign( t1, getIReg32(R_RAX) );
7177 assign( t2, getIRegRexB(4, pfx, regLo3) );
7178 putIReg32( R_RAX, mkexpr(t2) );
7179 putIRegRexB(4, pfx, regLo3, mkexpr(t1) );
7180 }
sewardja6b93d12005-02-17 09:28:28 +00007181 DIP("xchg%c %s, %s\n",
sewardj5b470602005-02-27 13:10:48 +00007182 nameISize(sz), nameIRegRAX(sz),
sewardj2d4fcd52005-05-18 11:47:47 +00007183 nameIRegRexB(sz,pfx, regLo3));
sewardja6b93d12005-02-17 09:28:28 +00007184}
7185
7186
sewardj905edbd2007-04-07 12:25:37 +00007187static
7188void codegen_SAHF ( void )
7189{
7190 /* Set the flags to:
7191 (amd64g_calculate_flags_all() & AMD64G_CC_MASK_O)
7192 -- retain the old O flag
7193 | (%AH & (AMD64G_CC_MASK_S|AMD64G_CC_MASK_Z|AMD64G_CC_MASK_A
7194 |AMD64G_CC_MASK_P|AMD64G_CC_MASK_C)
7195 */
7196 ULong mask_SZACP = AMD64G_CC_MASK_S|AMD64G_CC_MASK_Z|AMD64G_CC_MASK_A
7197 |AMD64G_CC_MASK_C|AMD64G_CC_MASK_P;
7198 IRTemp oldflags = newTemp(Ity_I64);
7199 assign( oldflags, mk_amd64g_calculate_rflags_all() );
7200 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(AMD64G_CC_OP_COPY) ));
7201 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU64(0) ));
7202 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
7203 stmt( IRStmt_Put( OFFB_CC_DEP1,
7204 binop(Iop_Or64,
7205 binop(Iop_And64, mkexpr(oldflags), mkU64(AMD64G_CC_MASK_O)),
7206 binop(Iop_And64,
7207 binop(Iop_Shr64, getIReg64(R_RAX), mkU8(8)),
7208 mkU64(mask_SZACP))
7209 )
7210 ));
7211}
7212
7213
7214static
7215void codegen_LAHF ( void )
7216{
7217 /* AH <- EFLAGS(SF:ZF:0:AF:0:PF:1:CF) */
7218 IRExpr* rax_with_hole;
7219 IRExpr* new_byte;
7220 IRExpr* new_rax;
7221 ULong mask_SZACP = AMD64G_CC_MASK_S|AMD64G_CC_MASK_Z|AMD64G_CC_MASK_A
7222 |AMD64G_CC_MASK_C|AMD64G_CC_MASK_P;
7223
7224 IRTemp flags = newTemp(Ity_I64);
7225 assign( flags, mk_amd64g_calculate_rflags_all() );
7226
7227 rax_with_hole
7228 = binop(Iop_And64, getIReg64(R_RAX), mkU64(~0xFF00ULL));
7229 new_byte
7230 = binop(Iop_Or64, binop(Iop_And64, mkexpr(flags), mkU64(mask_SZACP)),
7231 mkU64(1<<1));
7232 new_rax
7233 = binop(Iop_Or64, rax_with_hole,
7234 binop(Iop_Shl64, new_byte, mkU8(8)));
7235 putIReg64(R_RAX, new_rax);
7236}
7237
sewardja6b93d12005-02-17 09:28:28 +00007238
7239static
sewardjd0aa0a52006-08-17 01:20:01 +00007240ULong dis_cmpxchg_G_E ( /*OUT*/Bool* ok,
7241 Prefix pfx,
7242 Int size,
7243 Long delta0 )
sewardja6b93d12005-02-17 09:28:28 +00007244{
7245 HChar dis_buf[50];
7246 Int len;
7247
7248 IRType ty = szToITy(size);
7249 IRTemp acc = newTemp(ty);
7250 IRTemp src = newTemp(ty);
7251 IRTemp dest = newTemp(ty);
7252 IRTemp dest2 = newTemp(ty);
7253 IRTemp acc2 = newTemp(ty);
7254 IRTemp cond8 = newTemp(Ity_I8);
7255 IRTemp addr = IRTemp_INVALID;
7256 UChar rm = getUChar(delta0);
7257
7258 if (epartIsReg(rm)) {
sewardjd0aa0a52006-08-17 01:20:01 +00007259 *ok = False;
7260 return delta0;
7261 /* awaiting test case */
sewardj5b470602005-02-27 13:10:48 +00007262 assign( dest, getIRegE(size, pfx, rm) );
sewardja6b93d12005-02-17 09:28:28 +00007263 delta0++;
7264 DIP("cmpxchg%c %s,%s\n", nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00007265 nameIRegG(size,pfx,rm),
7266 nameIRegE(size,pfx,rm) );
sewardja6b93d12005-02-17 09:28:28 +00007267 } else {
7268 addr = disAMode ( &len, pfx, delta0, dis_buf, 0 );
7269 assign( dest, loadLE(ty, mkexpr(addr)) );
7270 delta0 += len;
7271 DIP("cmpxchg%c %s,%s\n", nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00007272 nameIRegG(size,pfx,rm), dis_buf);
sewardja6b93d12005-02-17 09:28:28 +00007273 }
7274
sewardj5b470602005-02-27 13:10:48 +00007275 assign( src, getIRegG(size, pfx, rm) );
7276 assign( acc, getIRegRAX(size) );
sewardja6b93d12005-02-17 09:28:28 +00007277 setFlags_DEP1_DEP2(Iop_Sub8, acc, dest, ty);
7278 assign( cond8, unop(Iop_1Uto8, mk_amd64g_calculate_condition(AMD64CondZ)) );
7279 assign( dest2, IRExpr_Mux0X(mkexpr(cond8), mkexpr(dest), mkexpr(src)) );
7280 assign( acc2, IRExpr_Mux0X(mkexpr(cond8), mkexpr(dest), mkexpr(acc)) );
sewardj5b470602005-02-27 13:10:48 +00007281 putIRegRAX(size, mkexpr(acc2));
sewardja6b93d12005-02-17 09:28:28 +00007282
7283 if (epartIsReg(rm)) {
sewardj5b470602005-02-27 13:10:48 +00007284 putIRegE(size, pfx, rm, mkexpr(dest2));
sewardja6b93d12005-02-17 09:28:28 +00007285 } else {
7286 storeLE( mkexpr(addr), mkexpr(dest2) );
7287 }
7288
sewardjd0aa0a52006-08-17 01:20:01 +00007289 *ok = True;
sewardja6b93d12005-02-17 09:28:28 +00007290 return delta0;
7291}
7292
sewardjd0aa0a52006-08-17 01:20:01 +00007293static
7294ULong dis_cmpxchg8b ( /*OUT*/Bool* ok,
7295 Prefix pfx,
7296 Int sz,
7297 Long delta0 )
7298{
7299 HChar dis_buf[50];
7300 Int len;
7301
7302 IRType ty = szToITy(sz);
7303 IRTemp eq = newTemp(Ity_I8);
7304 IRTemp olda = newTemp(ty);
7305 IRTemp oldb = newTemp(ty);
7306 IRTemp oldc = newTemp(ty);
7307 IRTemp oldd = newTemp(ty);
7308 IRTemp newa = newTemp(Ity_I64);
7309 IRTemp newd = newTemp(Ity_I64);
7310 IRTemp oldml = newTemp(ty);
7311 IRTemp oldmh = newTemp(ty);
7312 IRTemp newml = newTemp(ty);
7313 IRTemp newmh = newTemp(ty);
7314 IRTemp addr = IRTemp_INVALID;
7315 IRTemp oldrf = newTemp(Ity_I64);
7316 IRTemp newrf = newTemp(Ity_I64);
7317 UChar rm = getUChar(delta0);
7318 vassert(sz == 4 || sz == 8); /* guaranteed by caller */
7319
7320 if (epartIsReg(rm)) {
7321 *ok = False;
7322 return delta0;
7323 }
7324
7325 addr = disAMode ( &len, pfx, delta0, dis_buf, 0 );
7326 delta0 += len;
7327 DIP("cmpxchg%s %s\n", sz == 4 ? "8" : "16", dis_buf);
7328
7329 if (sz == 4) {
7330 assign( olda, getIReg32( R_RAX ) );
7331 assign( oldb, getIReg32( R_RBX ) );
7332 assign( oldc, getIReg32( R_RCX ) );
7333 assign( oldd, getIReg32( R_RDX ) );
7334 assign( oldml, loadLE( Ity_I32, mkexpr(addr) ));
7335 assign( oldmh, loadLE( Ity_I32,
7336 binop(Iop_Add64,mkexpr(addr),mkU64(4)) ));
7337 assign(eq,
7338 unop(Iop_1Uto8,
7339 binop(Iop_CmpEQ32,
7340 binop(Iop_Or32,
7341 binop(Iop_Xor32,mkexpr(olda),mkexpr(oldml)),
7342 binop(Iop_Xor32,mkexpr(oldd),mkexpr(oldmh))),
7343 mkU32(0))));
7344 assign( newml, IRExpr_Mux0X(mkexpr(eq),mkexpr(oldml),mkexpr(oldb)) );
7345 assign( newmh, IRExpr_Mux0X(mkexpr(eq),mkexpr(oldmh),mkexpr(oldc)) );
7346 assign( newa, IRExpr_Mux0X(mkexpr(eq),
7347 unop(Iop_32Uto64,mkexpr(oldml)),
7348 getIRegRAX(8)) );
7349 assign( newd, IRExpr_Mux0X(mkexpr(eq),
7350 unop(Iop_32Uto64,mkexpr(oldmh)),
7351 getIRegRDX(8)) );
7352
7353 storeLE( mkexpr(addr), mkexpr(newml) );
7354 storeLE( binop(Iop_Add64,mkexpr(addr),mkU64(4)),
7355 mkexpr(newmh) );
7356 putIRegRAX( 8, mkexpr(newa) );
7357 putIRegRDX( 8, mkexpr(newd) );
7358 } else {
7359 assign( olda, getIReg64( R_RAX ) );
7360 assign( oldb, getIReg64( R_RBX ) );
7361 assign( oldc, getIReg64( R_RCX ) );
7362 assign( oldd, getIReg64( R_RDX ) );
7363 assign( oldml, loadLE( Ity_I64, mkexpr(addr) ));
7364 assign( oldmh, loadLE( Ity_I64,
7365 binop(Iop_Add64,mkexpr(addr),mkU64(8)) ));
7366 assign(eq,
7367 unop(Iop_1Uto8,
7368 binop(Iop_CmpEQ64,
7369 binop(Iop_Or64,
7370 binop(Iop_Xor64,mkexpr(olda),mkexpr(oldml)),
7371 binop(Iop_Xor64,mkexpr(oldd),mkexpr(oldmh))),
7372 mkU64(0))));
7373 assign( newml, IRExpr_Mux0X(mkexpr(eq),mkexpr(oldml),mkexpr(oldb)) );
7374 assign( newmh, IRExpr_Mux0X(mkexpr(eq),mkexpr(oldmh),mkexpr(oldc)) );
7375 assign( newa, IRExpr_Mux0X(mkexpr(eq),mkexpr(oldml),mkexpr(olda)) );
7376 assign( newd, IRExpr_Mux0X(mkexpr(eq),mkexpr(oldmh),mkexpr(oldd)) );
7377
7378 storeLE( mkexpr(addr), mkexpr(newml) );
7379 storeLE( binop(Iop_Add64,mkexpr(addr),mkU64(8)),
7380 mkexpr(newmh) );
7381 putIRegRAX( 8, mkexpr(newa) );
7382 putIRegRDX( 8, mkexpr(newd) );
7383 }
7384
7385 /* And set the flags. Z is set if original d:a == mem, else
7386 cleared. All others unchanged. (This is different from normal
7387 cmpxchg which just sets them according to SUB.). */
7388 assign( oldrf, binop(Iop_And64,
7389 mk_amd64g_calculate_rflags_all(),
7390 mkU64(~AMD64G_CC_MASK_Z)) );
7391 assign( newrf,
7392 binop(Iop_Or64,
7393 mkexpr(oldrf),
7394 binop(Iop_Shl64,
7395 binop(Iop_And64, unop(Iop_8Uto64, mkexpr(eq)), mkU64(1)),
7396 mkU8(AMD64G_CC_SHIFT_Z))
7397 ));
7398 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(AMD64G_CC_OP_COPY) ));
7399 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
7400 stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(newrf) ));
7401 /* Set NDEP even though it isn't used. This makes redundant-PUT
7402 elimination of previous stores to this field work better. */
7403 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU64(0) ));
7404
7405 *ok = True;
7406 return delta0;
7407}
sewardja6b93d12005-02-17 09:28:28 +00007408
sewardjd20c8852005-01-20 20:04:07 +00007409//.. //-- static
7410//.. //-- Addr dis_cmpxchg8b ( UCodeBlock* cb,
7411//.. //-- UChar sorb,
7412//.. //-- Addr eip0 )
7413//.. //-- {
7414//.. //-- Int tal, tah, junkl, junkh, destl, desth, srcl, srch, accl, acch;
7415//.. //-- HChar dis_buf[50];
7416//.. //-- UChar rm;
7417//.. //-- UInt pair;
7418//.. //--
7419//.. //-- rm = getUChar(eip0);
7420//.. //-- accl = newTemp(cb);
7421//.. //-- acch = newTemp(cb);
7422//.. //-- srcl = newTemp(cb);
7423//.. //-- srch = newTemp(cb);
7424//.. //-- destl = newTemp(cb);
7425//.. //-- desth = newTemp(cb);
7426//.. //-- junkl = newTemp(cb);
7427//.. //-- junkh = newTemp(cb);
7428//.. //--
7429//.. //-- vg_assert(!epartIsReg(rm));
7430//.. //--
7431//.. //-- pair = disAMode ( cb, sorb, eip0, dis_buf );
7432//.. //-- tal = LOW24(pair);
7433//.. //-- tah = newTemp(cb);
7434//.. //-- uInstr2(cb, MOV, 4, TempReg, tal, TempReg, tah);
7435//.. //-- uInstr2(cb, ADD, 4, Literal, 0, TempReg, tah);
7436//.. //-- uLiteral(cb, 4);
7437//.. //-- eip0 += HI8(pair);
7438//.. //-- DIP("cmpxchg8b %s\n", dis_buf);
7439//.. //--
7440//.. //-- uInstr0(cb, CALLM_S, 0);
7441//.. //--
7442//.. //-- uInstr2(cb, LOAD, 4, TempReg, tah, TempReg, desth);
7443//.. //-- uInstr1(cb, PUSH, 4, TempReg, desth);
7444//.. //-- uInstr2(cb, LOAD, 4, TempReg, tal, TempReg, destl);
7445//.. //-- uInstr1(cb, PUSH, 4, TempReg, destl);
7446//.. //-- uInstr2(cb, GET, 4, ArchReg, R_ECX, TempReg, srch);
7447//.. //-- uInstr1(cb, PUSH, 4, TempReg, srch);
7448//.. //-- uInstr2(cb, GET, 4, ArchReg, R_EBX, TempReg, srcl);
7449//.. //-- uInstr1(cb, PUSH, 4, TempReg, srcl);
7450//.. //-- uInstr2(cb, GET, 4, ArchReg, R_EDX, TempReg, acch);
7451//.. //-- uInstr1(cb, PUSH, 4, TempReg, acch);
7452//.. //-- uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, accl);
7453//.. //-- uInstr1(cb, PUSH, 4, TempReg, accl);
7454//.. //--
7455//.. //-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_cmpxchg8b));
7456//.. //-- uFlagsRWU(cb, FlagsEmpty, FlagZ, FlagsEmpty);
7457//.. //--
7458//.. //-- uInstr1(cb, POP, 4, TempReg, accl);
7459//.. //-- uInstr2(cb, PUT, 4, TempReg, accl, ArchReg, R_EAX);
7460//.. //-- uInstr1(cb, POP, 4, TempReg, acch);
7461//.. //-- uInstr2(cb, PUT, 4, TempReg, acch, ArchReg, R_EDX);
7462//.. //-- uInstr1(cb, POP, 4, TempReg, srcl);
7463//.. //-- uInstr2(cb, PUT, 4, TempReg, srcl, ArchReg, R_EBX);
7464//.. //-- uInstr1(cb, POP, 4, TempReg, srch);
7465//.. //-- uInstr2(cb, PUT, 4, TempReg, srch, ArchReg, R_ECX);
7466//.. //-- uInstr1(cb, POP, 4, TempReg, destl);
7467//.. //-- uInstr2(cb, STORE, 4, TempReg, destl, TempReg, tal);
7468//.. //-- uInstr1(cb, POP, 4, TempReg, desth);
7469//.. //-- uInstr2(cb, STORE, 4, TempReg, desth, TempReg, tah);
7470//.. //--
7471//.. //-- uInstr0(cb, CALLM_E, 0);
7472//.. //--
7473//.. //-- return eip0;
7474//.. //-- }
sewardj3ca55a12005-01-27 16:06:23 +00007475
7476
7477/* Handle conditional move instructions of the form
7478 cmovcc E(reg-or-mem), G(reg)
7479
7480 E(src) is reg-or-mem
7481 G(dst) is reg.
7482
7483 If E is reg, --> GET %E, tmps
7484 GET %G, tmpd
7485 CMOVcc tmps, tmpd
7486 PUT tmpd, %G
7487
7488 If E is mem --> (getAddr E) -> tmpa
7489 LD (tmpa), tmps
7490 GET %G, tmpd
7491 CMOVcc tmps, tmpd
7492 PUT tmpd, %G
7493*/
7494static
7495ULong dis_cmov_E_G ( Prefix pfx,
7496 Int sz,
7497 AMD64Condcode cond,
sewardj270def42005-07-03 01:03:01 +00007498 Long delta0 )
sewardj3ca55a12005-01-27 16:06:23 +00007499{
sewardj8c332e22005-01-28 01:36:56 +00007500 UChar rm = getUChar(delta0);
sewardj3ca55a12005-01-27 16:06:23 +00007501 HChar dis_buf[50];
7502 Int len;
7503
7504 IRType ty = szToITy(sz);
7505 IRTemp tmps = newTemp(ty);
7506 IRTemp tmpd = newTemp(ty);
7507
7508 if (epartIsReg(rm)) {
sewardj5b470602005-02-27 13:10:48 +00007509 assign( tmps, getIRegE(sz, pfx, rm) );
7510 assign( tmpd, getIRegG(sz, pfx, rm) );
sewardj3ca55a12005-01-27 16:06:23 +00007511
sewardj5b470602005-02-27 13:10:48 +00007512 putIRegG( sz, pfx, rm,
sewardj3ca55a12005-01-27 16:06:23 +00007513 IRExpr_Mux0X( unop(Iop_1Uto8,
7514 mk_amd64g_calculate_condition(cond)),
7515 mkexpr(tmpd),
7516 mkexpr(tmps) )
7517 );
sewardje941eea2005-01-30 19:52:28 +00007518 DIP("cmov%s %s,%s\n", name_AMD64Condcode(cond),
sewardj5b470602005-02-27 13:10:48 +00007519 nameIRegE(sz,pfx,rm),
7520 nameIRegG(sz,pfx,rm));
sewardj3ca55a12005-01-27 16:06:23 +00007521 return 1+delta0;
7522 }
7523
7524 /* E refers to memory */
7525 {
sewardje1698952005-02-08 15:02:39 +00007526 IRTemp addr = disAMode ( &len, pfx, delta0, dis_buf, 0 );
sewardj3ca55a12005-01-27 16:06:23 +00007527 assign( tmps, loadLE(ty, mkexpr(addr)) );
sewardj5b470602005-02-27 13:10:48 +00007528 assign( tmpd, getIRegG(sz, pfx, rm) );
sewardj3ca55a12005-01-27 16:06:23 +00007529
sewardj5b470602005-02-27 13:10:48 +00007530 putIRegG( sz, pfx, rm,
sewardj3ca55a12005-01-27 16:06:23 +00007531 IRExpr_Mux0X( unop(Iop_1Uto8,
7532 mk_amd64g_calculate_condition(cond)),
7533 mkexpr(tmpd),
7534 mkexpr(tmps) )
7535 );
7536
sewardj7eaa7cf2005-01-31 18:55:22 +00007537 DIP("cmov%s %s,%s\n", name_AMD64Condcode(cond),
7538 dis_buf,
sewardj5b470602005-02-27 13:10:48 +00007539 nameIRegG(sz,pfx,rm));
sewardj3ca55a12005-01-27 16:06:23 +00007540 return len+delta0;
7541 }
7542}
7543
7544
sewardjb4fd2e72005-03-23 13:34:11 +00007545static
7546ULong dis_xadd_G_E ( /*OUT*/Bool* decode_ok,
sewardj270def42005-07-03 01:03:01 +00007547 Prefix pfx, Int sz, Long delta0 )
sewardjb4fd2e72005-03-23 13:34:11 +00007548{
7549 Int len;
7550 UChar rm = getUChar(delta0);
7551 HChar dis_buf[50];
7552
7553 IRType ty = szToITy(sz);
7554 IRTemp tmpd = newTemp(ty);
7555 IRTemp tmpt0 = newTemp(ty);
7556 IRTemp tmpt1 = newTemp(ty);
7557 *decode_ok = True;
7558
7559 if (epartIsReg(rm)) {
7560 *decode_ok = False;
7561 return delta0;
7562 } else {
7563 IRTemp addr = disAMode ( &len, pfx, delta0, dis_buf, 0 );
7564 assign( tmpd, loadLE(ty, mkexpr(addr)) );
7565 assign( tmpt0, getIRegG(sz, pfx, rm) );
7566 assign( tmpt1, binop(mkSizedOp(ty,Iop_Add8), mkexpr(tmpd), mkexpr(tmpt0)) );
7567 setFlags_DEP1_DEP2( Iop_Add8, tmpd, tmpt0, ty );
7568 storeLE( mkexpr(addr), mkexpr(tmpt1) );
7569 putIRegG(sz, pfx, rm, mkexpr(tmpd));
7570 DIP("xadd%c %s, %s\n",
7571 nameISize(sz), nameIRegG(sz,pfx,rm), dis_buf);
7572 return len+delta0;
7573 }
7574}
7575
sewardjd20c8852005-01-20 20:04:07 +00007576//.. /* Move 16 bits from Ew (ireg or mem) to G (a segment register). */
7577//..
7578//.. static
sewardj270def42005-07-03 01:03:01 +00007579//.. UInt dis_mov_Ew_Sw ( UChar sorb, Long delta0 )
sewardjd20c8852005-01-20 20:04:07 +00007580//.. {
7581//.. Int len;
7582//.. IRTemp addr;
sewardj8c332e22005-01-28 01:36:56 +00007583//.. UChar rm = getUChar(delta0);
sewardjd20c8852005-01-20 20:04:07 +00007584//.. HChar dis_buf[50];
7585//..
7586//.. if (epartIsReg(rm)) {
7587//.. putSReg( gregOfRM(rm), getIReg(2, eregOfRM(rm)) );
7588//.. DIP("movw %s,%s\n", nameIReg(2,eregOfRM(rm)), nameSReg(gregOfRM(rm)));
7589//.. return 1+delta0;
7590//.. } else {
7591//.. addr = disAMode ( &len, sorb, delta0, dis_buf );
7592//.. putSReg( gregOfRM(rm), loadLE(Ity_I16, mkexpr(addr)) );
7593//.. DIP("movw %s,%s\n", dis_buf, nameSReg(gregOfRM(rm)));
7594//.. return len+delta0;
7595//.. }
7596//.. }
7597//..
7598//.. /* Move 16 bits from G (a segment register) to Ew (ireg or mem). If
7599//.. dst is ireg and sz==4, zero out top half of it. */
7600//..
7601//.. static
7602//.. UInt dis_mov_Sw_Ew ( UChar sorb,
7603//.. Int sz,
7604//.. UInt delta0 )
7605//.. {
7606//.. Int len;
7607//.. IRTemp addr;
sewardj8c332e22005-01-28 01:36:56 +00007608//.. UChar rm = getUChar(delta0);
sewardjd20c8852005-01-20 20:04:07 +00007609//.. HChar dis_buf[50];
7610//..
7611//.. vassert(sz == 2 || sz == 4);
7612//..
7613//.. if (epartIsReg(rm)) {
7614//.. if (sz == 4)
7615//.. putIReg(4, eregOfRM(rm), unop(Iop_16Uto32, getSReg(gregOfRM(rm))));
7616//.. else
7617//.. putIReg(2, eregOfRM(rm), getSReg(gregOfRM(rm)));
7618//..
7619//.. DIP("mov %s,%s\n", nameSReg(gregOfRM(rm)), nameIReg(sz,eregOfRM(rm)));
7620//.. return 1+delta0;
7621//.. } else {
7622//.. addr = disAMode ( &len, sorb, delta0, dis_buf );
7623//.. storeLE( mkexpr(addr), getSReg(gregOfRM(rm)) );
7624//.. DIP("mov %s,%s\n", nameSReg(gregOfRM(rm)), dis_buf);
7625//.. return len+delta0;
7626//.. }
7627//.. }
7628//..
7629//..
7630//.. static
7631//.. void dis_push_segreg ( UInt sreg, Int sz )
7632//.. {
7633//.. IRTemp t1 = newTemp(Ity_I16);
7634//.. IRTemp ta = newTemp(Ity_I32);
7635//.. vassert(sz == 2 || sz == 4);
7636//..
7637//.. assign( t1, getSReg(sreg) );
7638//.. assign( ta, binop(Iop_Sub32, getIReg(4, R_ESP), mkU32(sz)) );
7639//.. putIReg(4, R_ESP, mkexpr(ta));
7640//.. storeLE( mkexpr(ta), mkexpr(t1) );
7641//..
7642//.. DIP("pushw %s\n", nameSReg(sreg));
7643//.. }
7644//..
7645//.. static
7646//.. void dis_pop_segreg ( UInt sreg, Int sz )
7647//.. {
7648//.. IRTemp t1 = newTemp(Ity_I16);
7649//.. IRTemp ta = newTemp(Ity_I32);
7650//.. vassert(sz == 2 || sz == 4);
7651//..
7652//.. assign( ta, getIReg(4, R_ESP) );
7653//.. assign( t1, loadLE(Ity_I16, mkexpr(ta)) );
7654//..
7655//.. putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(ta), mkU32(sz)) );
7656//.. putSReg( sreg, mkexpr(t1) );
7657//.. DIP("pop %s\n", nameSReg(sreg));
7658//.. }
sewardj2f959cc2005-01-26 01:19:35 +00007659
7660static
sewardjdd40fdf2006-12-24 02:20:24 +00007661void dis_ret ( VexAbiInfo* vbi, ULong d64 )
sewardj2f959cc2005-01-26 01:19:35 +00007662{
7663 IRTemp t1 = newTemp(Ity_I64);
7664 IRTemp t2 = newTemp(Ity_I64);
sewardj5a9ffab2005-05-12 17:55:01 +00007665 IRTemp t3 = newTemp(Ity_I64);
sewardj2f959cc2005-01-26 01:19:35 +00007666 assign(t1, getIReg64(R_RSP));
7667 assign(t2, loadLE(Ity_I64,mkexpr(t1)));
sewardj5a9ffab2005-05-12 17:55:01 +00007668 assign(t3, binop(Iop_Add64, mkexpr(t1), mkU64(8+d64)));
7669 putIReg64(R_RSP, mkexpr(t3));
sewardjdd40fdf2006-12-24 02:20:24 +00007670 make_redzone_AbiHint(vbi, t3, "ret");
sewardj2f959cc2005-01-26 01:19:35 +00007671 jmp_treg(Ijk_Ret,t2);
7672}
7673
sewardj5b470602005-02-27 13:10:48 +00007674
sewardj1001dc42005-02-21 08:25:55 +00007675/*------------------------------------------------------------*/
7676/*--- SSE/SSE2/SSE3 helpers ---*/
7677/*------------------------------------------------------------*/
7678
7679/* Worker function; do not call directly.
7680 Handles full width G = G `op` E and G = (not G) `op` E.
7681*/
7682
sewardj8d965312005-02-25 02:48:47 +00007683static ULong dis_SSE_E_to_G_all_wrk (
sewardj270def42005-07-03 01:03:01 +00007684 Prefix pfx, Long delta,
sewardj8d965312005-02-25 02:48:47 +00007685 HChar* opname, IROp op,
7686 Bool invertG
7687 )
sewardj9da16972005-02-21 13:58:26 +00007688{
7689 HChar dis_buf[50];
7690 Int alen;
7691 IRTemp addr;
7692 UChar rm = getUChar(delta);
7693 IRExpr* gpart
7694 = invertG ? unop(Iop_NotV128, getXMMReg(gregOfRexRM(pfx,rm)))
7695 : getXMMReg(gregOfRexRM(pfx,rm));
7696 if (epartIsReg(rm)) {
7697 putXMMReg( gregOfRexRM(pfx,rm),
7698 binop(op, gpart,
7699 getXMMReg(eregOfRexRM(pfx,rm))) );
7700 DIP("%s %s,%s\n", opname,
7701 nameXMMReg(eregOfRexRM(pfx,rm)),
7702 nameXMMReg(gregOfRexRM(pfx,rm)) );
7703 return delta+1;
7704 } else {
7705 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
7706 putXMMReg( gregOfRexRM(pfx,rm),
7707 binop(op, gpart,
7708 loadLE(Ity_V128, mkexpr(addr))) );
7709 DIP("%s %s,%s\n", opname,
7710 dis_buf,
7711 nameXMMReg(gregOfRexRM(pfx,rm)) );
7712 return delta+alen;
7713 }
7714}
7715
7716
7717/* All lanes SSE binary operation, G = G `op` E. */
7718
7719static
sewardj270def42005-07-03 01:03:01 +00007720ULong dis_SSE_E_to_G_all ( Prefix pfx, Long delta,
sewardj8d965312005-02-25 02:48:47 +00007721 HChar* opname, IROp op )
sewardj9da16972005-02-21 13:58:26 +00007722{
7723 return dis_SSE_E_to_G_all_wrk( pfx, delta, opname, op, False );
7724}
7725
sewardj8d965312005-02-25 02:48:47 +00007726/* All lanes SSE binary operation, G = (not G) `op` E. */
7727
7728static
sewardj270def42005-07-03 01:03:01 +00007729ULong dis_SSE_E_to_G_all_invG ( Prefix pfx, Long delta,
sewardj8d965312005-02-25 02:48:47 +00007730 HChar* opname, IROp op )
7731{
7732 return dis_SSE_E_to_G_all_wrk( pfx, delta, opname, op, True );
7733}
7734
7735
7736/* Lowest 32-bit lane only SSE binary operation, G = G `op` E. */
7737
sewardj270def42005-07-03 01:03:01 +00007738static ULong dis_SSE_E_to_G_lo32 ( Prefix pfx, Long delta,
sewardj8d965312005-02-25 02:48:47 +00007739 HChar* opname, IROp op )
7740{
7741 HChar dis_buf[50];
7742 Int alen;
7743 IRTemp addr;
7744 UChar rm = getUChar(delta);
sewardj9c9ee3d2005-02-26 01:17:42 +00007745 IRExpr* gpart = getXMMReg(gregOfRexRM(pfx,rm));
sewardj8d965312005-02-25 02:48:47 +00007746 if (epartIsReg(rm)) {
sewardj9c9ee3d2005-02-26 01:17:42 +00007747 putXMMReg( gregOfRexRM(pfx,rm),
sewardj8d965312005-02-25 02:48:47 +00007748 binop(op, gpart,
7749 getXMMReg(eregOfRexRM(pfx,rm))) );
7750 DIP("%s %s,%s\n", opname,
7751 nameXMMReg(eregOfRexRM(pfx,rm)),
7752 nameXMMReg(gregOfRexRM(pfx,rm)) );
7753 return delta+1;
7754 } else {
7755 /* We can only do a 32-bit memory read, so the upper 3/4 of the
7756 E operand needs to be made simply of zeroes. */
7757 IRTemp epart = newTemp(Ity_V128);
7758 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
7759 assign( epart, unop( Iop_32UtoV128,
7760 loadLE(Ity_I32, mkexpr(addr))) );
7761 putXMMReg( gregOfRexRM(pfx,rm),
7762 binop(op, gpart, mkexpr(epart)) );
7763 DIP("%s %s,%s\n", opname,
7764 dis_buf,
7765 nameXMMReg(gregOfRexRM(pfx,rm)) );
7766 return delta+alen;
7767 }
7768}
sewardj1001dc42005-02-21 08:25:55 +00007769
7770
7771/* Lower 64-bit lane only SSE binary operation, G = G `op` E. */
7772
sewardj270def42005-07-03 01:03:01 +00007773static ULong dis_SSE_E_to_G_lo64 ( Prefix pfx, Long delta,
sewardj8d965312005-02-25 02:48:47 +00007774 HChar* opname, IROp op )
sewardj1001dc42005-02-21 08:25:55 +00007775{
7776 HChar dis_buf[50];
7777 Int alen;
7778 IRTemp addr;
7779 UChar rm = getUChar(delta);
7780 IRExpr* gpart = getXMMReg(gregOfRexRM(pfx,rm));
7781 if (epartIsReg(rm)) {
7782 putXMMReg( gregOfRexRM(pfx,rm),
7783 binop(op, gpart,
7784 getXMMReg(eregOfRexRM(pfx,rm))) );
7785 DIP("%s %s,%s\n", opname,
7786 nameXMMReg(eregOfRexRM(pfx,rm)),
7787 nameXMMReg(gregOfRexRM(pfx,rm)) );
7788 return delta+1;
7789 } else {
7790 /* We can only do a 64-bit memory read, so the upper half of the
7791 E operand needs to be made simply of zeroes. */
7792 IRTemp epart = newTemp(Ity_V128);
7793 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
7794 assign( epart, unop( Iop_64UtoV128,
7795 loadLE(Ity_I64, mkexpr(addr))) );
7796 putXMMReg( gregOfRexRM(pfx,rm),
7797 binop(op, gpart, mkexpr(epart)) );
7798 DIP("%s %s,%s\n", opname,
7799 dis_buf,
7800 nameXMMReg(gregOfRexRM(pfx,rm)) );
7801 return delta+alen;
7802 }
7803}
7804
7805
sewardja7ba8c42005-05-10 20:08:34 +00007806/* All lanes unary SSE operation, G = op(E). */
7807
7808static ULong dis_SSE_E_to_G_unary_all (
sewardj270def42005-07-03 01:03:01 +00007809 Prefix pfx, Long delta,
sewardja7ba8c42005-05-10 20:08:34 +00007810 HChar* opname, IROp op
7811 )
7812{
7813 HChar dis_buf[50];
7814 Int alen;
7815 IRTemp addr;
7816 UChar rm = getUChar(delta);
7817 if (epartIsReg(rm)) {
7818 putXMMReg( gregOfRexRM(pfx,rm),
7819 unop(op, getXMMReg(eregOfRexRM(pfx,rm))) );
7820 DIP("%s %s,%s\n", opname,
7821 nameXMMReg(eregOfRexRM(pfx,rm)),
7822 nameXMMReg(gregOfRexRM(pfx,rm)) );
7823 return delta+1;
7824 } else {
7825 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
7826 putXMMReg( gregOfRexRM(pfx,rm),
7827 unop(op, loadLE(Ity_V128, mkexpr(addr))) );
7828 DIP("%s %s,%s\n", opname,
7829 dis_buf,
7830 nameXMMReg(gregOfRexRM(pfx,rm)) );
7831 return delta+alen;
7832 }
7833}
7834
7835
7836/* Lowest 32-bit lane only unary SSE operation, G = op(E). */
7837
7838static ULong dis_SSE_E_to_G_unary_lo32 (
sewardj270def42005-07-03 01:03:01 +00007839 Prefix pfx, Long delta,
sewardja7ba8c42005-05-10 20:08:34 +00007840 HChar* opname, IROp op
7841 )
7842{
7843 /* First we need to get the old G value and patch the low 32 bits
7844 of the E operand into it. Then apply op and write back to G. */
7845 HChar dis_buf[50];
7846 Int alen;
7847 IRTemp addr;
7848 UChar rm = getUChar(delta);
7849 IRTemp oldG0 = newTemp(Ity_V128);
7850 IRTemp oldG1 = newTemp(Ity_V128);
7851
7852 assign( oldG0, getXMMReg(gregOfRexRM(pfx,rm)) );
7853
7854 if (epartIsReg(rm)) {
7855 assign( oldG1,
7856 binop( Iop_SetV128lo32,
7857 mkexpr(oldG0),
7858 getXMMRegLane32(eregOfRexRM(pfx,rm), 0)) );
7859 putXMMReg( gregOfRexRM(pfx,rm), unop(op, mkexpr(oldG1)) );
7860 DIP("%s %s,%s\n", opname,
7861 nameXMMReg(eregOfRexRM(pfx,rm)),
7862 nameXMMReg(gregOfRexRM(pfx,rm)) );
7863 return delta+1;
7864 } else {
7865 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
7866 assign( oldG1,
7867 binop( Iop_SetV128lo32,
7868 mkexpr(oldG0),
7869 loadLE(Ity_I32, mkexpr(addr)) ));
7870 putXMMReg( gregOfRexRM(pfx,rm), unop(op, mkexpr(oldG1)) );
7871 DIP("%s %s,%s\n", opname,
7872 dis_buf,
7873 nameXMMReg(gregOfRexRM(pfx,rm)) );
7874 return delta+alen;
7875 }
7876}
sewardj1001dc42005-02-21 08:25:55 +00007877
7878
7879/* Lowest 64-bit lane only unary SSE operation, G = op(E). */
7880
sewardj8d965312005-02-25 02:48:47 +00007881static ULong dis_SSE_E_to_G_unary_lo64 (
sewardj270def42005-07-03 01:03:01 +00007882 Prefix pfx, Long delta,
sewardj8d965312005-02-25 02:48:47 +00007883 HChar* opname, IROp op
7884 )
sewardj1001dc42005-02-21 08:25:55 +00007885{
7886 /* First we need to get the old G value and patch the low 64 bits
7887 of the E operand into it. Then apply op and write back to G. */
7888 HChar dis_buf[50];
7889 Int alen;
7890 IRTemp addr;
7891 UChar rm = getUChar(delta);
7892 IRTemp oldG0 = newTemp(Ity_V128);
7893 IRTemp oldG1 = newTemp(Ity_V128);
7894
7895 assign( oldG0, getXMMReg(gregOfRexRM(pfx,rm)) );
7896
7897 if (epartIsReg(rm)) {
7898 assign( oldG1,
7899 binop( Iop_SetV128lo64,
7900 mkexpr(oldG0),
7901 getXMMRegLane64(eregOfRexRM(pfx,rm), 0)) );
7902 putXMMReg( gregOfRexRM(pfx,rm), unop(op, mkexpr(oldG1)) );
7903 DIP("%s %s,%s\n", opname,
7904 nameXMMReg(eregOfRexRM(pfx,rm)),
7905 nameXMMReg(gregOfRexRM(pfx,rm)) );
7906 return delta+1;
7907 } else {
7908 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
7909 assign( oldG1,
7910 binop( Iop_SetV128lo64,
7911 mkexpr(oldG0),
7912 loadLE(Ity_I64, mkexpr(addr)) ));
7913 putXMMReg( gregOfRexRM(pfx,rm), unop(op, mkexpr(oldG1)) );
7914 DIP("%s %s,%s\n", opname,
7915 dis_buf,
7916 nameXMMReg(gregOfRexRM(pfx,rm)) );
7917 return delta+alen;
7918 }
7919}
7920
7921
sewardj09717342005-05-05 21:34:02 +00007922/* SSE integer binary operation:
7923 G = G `op` E (eLeft == False)
7924 G = E `op` G (eLeft == True)
7925*/
7926static ULong dis_SSEint_E_to_G(
sewardj270def42005-07-03 01:03:01 +00007927 Prefix pfx, Long delta,
sewardj09717342005-05-05 21:34:02 +00007928 HChar* opname, IROp op,
7929 Bool eLeft
7930 )
7931{
7932 HChar dis_buf[50];
7933 Int alen;
7934 IRTemp addr;
7935 UChar rm = getUChar(delta);
7936 IRExpr* gpart = getXMMReg(gregOfRexRM(pfx,rm));
7937 IRExpr* epart = NULL;
7938 if (epartIsReg(rm)) {
7939 epart = getXMMReg(eregOfRexRM(pfx,rm));
7940 DIP("%s %s,%s\n", opname,
7941 nameXMMReg(eregOfRexRM(pfx,rm)),
7942 nameXMMReg(gregOfRexRM(pfx,rm)) );
7943 delta += 1;
7944 } else {
7945 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
7946 epart = loadLE(Ity_V128, mkexpr(addr));
7947 DIP("%s %s,%s\n", opname,
7948 dis_buf,
7949 nameXMMReg(gregOfRexRM(pfx,rm)) );
7950 delta += alen;
7951 }
7952 putXMMReg( gregOfRexRM(pfx,rm),
7953 eLeft ? binop(op, epart, gpart)
7954 : binop(op, gpart, epart) );
7955 return delta;
7956}
sewardj8d965312005-02-25 02:48:47 +00007957
7958
7959/* Helper for doing SSE FP comparisons. */
7960
7961static void findSSECmpOp ( Bool* needNot, IROp* op,
7962 Int imm8, Bool all_lanes, Int sz )
7963{
7964 imm8 &= 7;
7965 *needNot = False;
7966 *op = Iop_INVALID;
7967 if (imm8 >= 4) {
7968 *needNot = True;
7969 imm8 -= 4;
7970 }
7971
7972 if (sz == 4 && all_lanes) {
7973 switch (imm8) {
7974 case 0: *op = Iop_CmpEQ32Fx4; return;
7975 case 1: *op = Iop_CmpLT32Fx4; return;
7976 case 2: *op = Iop_CmpLE32Fx4; return;
7977 case 3: *op = Iop_CmpUN32Fx4; return;
7978 default: break;
7979 }
7980 }
7981 if (sz == 4 && !all_lanes) {
7982 switch (imm8) {
7983 case 0: *op = Iop_CmpEQ32F0x4; return;
7984 case 1: *op = Iop_CmpLT32F0x4; return;
7985 case 2: *op = Iop_CmpLE32F0x4; return;
7986 case 3: *op = Iop_CmpUN32F0x4; return;
7987 default: break;
7988 }
7989 }
7990 if (sz == 8 && all_lanes) {
7991 switch (imm8) {
7992 case 0: *op = Iop_CmpEQ64Fx2; return;
7993 case 1: *op = Iop_CmpLT64Fx2; return;
7994 case 2: *op = Iop_CmpLE64Fx2; return;
7995 case 3: *op = Iop_CmpUN64Fx2; return;
7996 default: break;
7997 }
7998 }
7999 if (sz == 8 && !all_lanes) {
8000 switch (imm8) {
8001 case 0: *op = Iop_CmpEQ64F0x2; return;
8002 case 1: *op = Iop_CmpLT64F0x2; return;
8003 case 2: *op = Iop_CmpLE64F0x2; return;
8004 case 3: *op = Iop_CmpUN64F0x2; return;
8005 default: break;
8006 }
8007 }
8008 vpanic("findSSECmpOp(amd64,guest)");
8009}
8010
sewardjab9055b2006-01-01 13:17:38 +00008011/* Handles SSE 32F/64F comparisons. */
sewardj8d965312005-02-25 02:48:47 +00008012
sewardj270def42005-07-03 01:03:01 +00008013static ULong dis_SSEcmp_E_to_G ( Prefix pfx, Long delta,
sewardj8d965312005-02-25 02:48:47 +00008014 HChar* opname, Bool all_lanes, Int sz )
8015{
8016 HChar dis_buf[50];
8017 Int alen, imm8;
8018 IRTemp addr;
8019 Bool needNot = False;
8020 IROp op = Iop_INVALID;
8021 IRTemp plain = newTemp(Ity_V128);
8022 UChar rm = getUChar(delta);
8023 UShort mask = 0;
8024 vassert(sz == 4 || sz == 8);
8025 if (epartIsReg(rm)) {
8026 imm8 = getUChar(delta+1);
8027 findSSECmpOp(&needNot, &op, imm8, all_lanes, sz);
8028 assign( plain, binop(op, getXMMReg(gregOfRexRM(pfx,rm)),
8029 getXMMReg(eregOfRexRM(pfx,rm))) );
8030 delta += 2;
8031 DIP("%s $%d,%s,%s\n", opname,
8032 (Int)imm8,
8033 nameXMMReg(eregOfRexRM(pfx,rm)),
8034 nameXMMReg(gregOfRexRM(pfx,rm)) );
8035 } else {
8036 addr = disAMode ( &alen, pfx, delta, dis_buf, 1 );
8037 imm8 = getUChar(delta+alen);
8038 findSSECmpOp(&needNot, &op, imm8, all_lanes, sz);
sewardjab9055b2006-01-01 13:17:38 +00008039 assign( plain,
8040 binop(
8041 op,
8042 getXMMReg(gregOfRexRM(pfx,rm)),
8043 all_lanes ? loadLE(Ity_V128, mkexpr(addr))
8044 : sz == 8 ? unop( Iop_64UtoV128, loadLE(Ity_I64, mkexpr(addr)))
8045 : /*sz==4*/ unop( Iop_32UtoV128, loadLE(Ity_I32, mkexpr(addr)))
8046 )
8047 );
sewardj8d965312005-02-25 02:48:47 +00008048 delta += alen+1;
8049 DIP("%s $%d,%s,%s\n", opname,
8050 (Int)imm8,
8051 dis_buf,
8052 nameXMMReg(gregOfRexRM(pfx,rm)) );
8053 }
8054
8055 if (needNot && all_lanes) {
sewardj9c9ee3d2005-02-26 01:17:42 +00008056 putXMMReg( gregOfRexRM(pfx,rm),
sewardj8d965312005-02-25 02:48:47 +00008057 unop(Iop_NotV128, mkexpr(plain)) );
8058 }
8059 else
8060 if (needNot && !all_lanes) {
sewardj1027dc22005-02-26 01:55:02 +00008061 mask = toUShort(sz==4 ? 0x000F : 0x00FF);
sewardj8d965312005-02-25 02:48:47 +00008062 putXMMReg( gregOfRexRM(pfx,rm),
8063 binop(Iop_XorV128, mkexpr(plain), mkV128(mask)) );
8064 }
8065 else {
8066 putXMMReg( gregOfRexRM(pfx,rm), mkexpr(plain) );
8067 }
8068
8069 return delta;
8070}
8071
8072
sewardjadffcef2005-05-11 00:03:06 +00008073/* Vector by scalar shift of G by the amount specified at the bottom
8074 of E. */
8075
sewardj270def42005-07-03 01:03:01 +00008076static ULong dis_SSE_shiftG_byE ( Prefix pfx, Long delta,
sewardjadffcef2005-05-11 00:03:06 +00008077 HChar* opname, IROp op )
8078{
8079 HChar dis_buf[50];
8080 Int alen, size;
8081 IRTemp addr;
8082 Bool shl, shr, sar;
8083 UChar rm = getUChar(delta);
8084 IRTemp g0 = newTemp(Ity_V128);
8085 IRTemp g1 = newTemp(Ity_V128);
8086 IRTemp amt = newTemp(Ity_I32);
8087 IRTemp amt8 = newTemp(Ity_I8);
8088 if (epartIsReg(rm)) {
8089 assign( amt, getXMMRegLane32(eregOfRexRM(pfx,rm), 0) );
8090 DIP("%s %s,%s\n", opname,
8091 nameXMMReg(eregOfRexRM(pfx,rm)),
8092 nameXMMReg(gregOfRexRM(pfx,rm)) );
8093 delta++;
8094 } else {
8095 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
8096 assign( amt, loadLE(Ity_I32, mkexpr(addr)) );
8097 DIP("%s %s,%s\n", opname,
8098 dis_buf,
8099 nameXMMReg(gregOfRexRM(pfx,rm)) );
8100 delta += alen;
8101 }
8102 assign( g0, getXMMReg(gregOfRexRM(pfx,rm)) );
8103 assign( amt8, unop(Iop_32to8, mkexpr(amt)) );
8104
8105 shl = shr = sar = False;
8106 size = 0;
8107 switch (op) {
8108 case Iop_ShlN16x8: shl = True; size = 32; break;
8109 case Iop_ShlN32x4: shl = True; size = 32; break;
8110 case Iop_ShlN64x2: shl = True; size = 64; break;
8111 case Iop_SarN16x8: sar = True; size = 16; break;
8112 case Iop_SarN32x4: sar = True; size = 32; break;
8113 case Iop_ShrN16x8: shr = True; size = 16; break;
8114 case Iop_ShrN32x4: shr = True; size = 32; break;
8115 case Iop_ShrN64x2: shr = True; size = 64; break;
8116 default: vassert(0);
8117 }
8118
8119 if (shl || shr) {
8120 assign(
8121 g1,
8122 IRExpr_Mux0X(
8123 unop(Iop_1Uto8,
8124 binop(Iop_CmpLT64U, unop(Iop_32Uto64,mkexpr(amt)), mkU64(size))),
8125 mkV128(0x0000),
8126 binop(op, mkexpr(g0), mkexpr(amt8))
8127 )
8128 );
8129 } else
8130 if (sar) {
8131 assign(
8132 g1,
8133 IRExpr_Mux0X(
8134 unop(Iop_1Uto8,
8135 binop(Iop_CmpLT64U, unop(Iop_32Uto64,mkexpr(amt)), mkU64(size))),
8136 binop(op, mkexpr(g0), mkU8(size-1)),
8137 binop(op, mkexpr(g0), mkexpr(amt8))
8138 )
8139 );
8140 } else {
8141 vassert(0);
8142 }
8143
8144 putXMMReg( gregOfRexRM(pfx,rm), mkexpr(g1) );
8145 return delta;
8146}
sewardj09717342005-05-05 21:34:02 +00008147
8148
8149/* Vector by scalar shift of E by an immediate byte. */
8150
8151static
8152ULong dis_SSE_shiftE_imm ( Prefix pfx,
sewardj270def42005-07-03 01:03:01 +00008153 Long delta, HChar* opname, IROp op )
sewardj09717342005-05-05 21:34:02 +00008154{
8155 Bool shl, shr, sar;
8156 UChar rm = getUChar(delta);
8157 IRTemp e0 = newTemp(Ity_V128);
8158 IRTemp e1 = newTemp(Ity_V128);
8159 UChar amt, size;
8160 vassert(epartIsReg(rm));
8161 vassert(gregLO3ofRM(rm) == 2
8162 || gregLO3ofRM(rm) == 4 || gregLO3ofRM(rm) == 6);
sewardjca673ab2005-05-11 10:03:08 +00008163 amt = getUChar(delta+1);
sewardj09717342005-05-05 21:34:02 +00008164 delta += 2;
8165 DIP("%s $%d,%s\n", opname,
8166 (Int)amt,
8167 nameXMMReg(eregOfRexRM(pfx,rm)) );
8168 assign( e0, getXMMReg(eregOfRexRM(pfx,rm)) );
8169
8170 shl = shr = sar = False;
8171 size = 0;
8172 switch (op) {
8173 case Iop_ShlN16x8: shl = True; size = 16; break;
8174 case Iop_ShlN32x4: shl = True; size = 32; break;
8175 case Iop_ShlN64x2: shl = True; size = 64; break;
8176 case Iop_SarN16x8: sar = True; size = 16; break;
8177 case Iop_SarN32x4: sar = True; size = 32; break;
8178 case Iop_ShrN16x8: shr = True; size = 16; break;
8179 case Iop_ShrN32x4: shr = True; size = 32; break;
8180 case Iop_ShrN64x2: shr = True; size = 64; break;
8181 default: vassert(0);
8182 }
8183
8184 if (shl || shr) {
8185 assign( e1, amt >= size
8186 ? mkV128(0x0000)
8187 : binop(op, mkexpr(e0), mkU8(amt))
8188 );
8189 } else
8190 if (sar) {
8191 assign( e1, amt >= size
8192 ? binop(op, mkexpr(e0), mkU8(size-1))
8193 : binop(op, mkexpr(e0), mkU8(amt))
8194 );
8195 } else {
8196 vassert(0);
8197 }
8198
8199 putXMMReg( eregOfRexRM(pfx,rm), mkexpr(e1) );
8200 return delta;
8201}
sewardj1a01e652005-02-23 11:39:21 +00008202
8203
8204/* Get the current SSE rounding mode. */
8205
8206static IRExpr* /* :: Ity_I32 */ get_sse_roundingmode ( void )
8207{
8208 return
8209 unop( Iop_64to32,
8210 binop( Iop_And64,
8211 IRExpr_Get( OFFB_SSEROUND, Ity_I64 ),
8212 mkU64(3) ));
8213}
8214
sewardjbcbb9de2005-03-27 02:22:32 +00008215static void put_sse_roundingmode ( IRExpr* sseround )
8216{
sewardjdd40fdf2006-12-24 02:20:24 +00008217 vassert(typeOfIRExpr(irsb->tyenv, sseround) == Ity_I32);
sewardjbcbb9de2005-03-27 02:22:32 +00008218 stmt( IRStmt_Put( OFFB_SSEROUND,
8219 unop(Iop_32Uto64,sseround) ) );
8220}
8221
sewardja7ba8c42005-05-10 20:08:34 +00008222/* Break a 128-bit value up into four 32-bit ints. */
8223
8224static void breakup128to32s ( IRTemp t128,
8225 /*OUTs*/
8226 IRTemp* t3, IRTemp* t2,
8227 IRTemp* t1, IRTemp* t0 )
8228{
8229 IRTemp hi64 = newTemp(Ity_I64);
8230 IRTemp lo64 = newTemp(Ity_I64);
8231 assign( hi64, unop(Iop_V128HIto64, mkexpr(t128)) );
8232 assign( lo64, unop(Iop_V128to64, mkexpr(t128)) );
8233
8234 vassert(t0 && *t0 == IRTemp_INVALID);
8235 vassert(t1 && *t1 == IRTemp_INVALID);
8236 vassert(t2 && *t2 == IRTemp_INVALID);
8237 vassert(t3 && *t3 == IRTemp_INVALID);
8238
8239 *t0 = newTemp(Ity_I32);
8240 *t1 = newTemp(Ity_I32);
8241 *t2 = newTemp(Ity_I32);
8242 *t3 = newTemp(Ity_I32);
8243 assign( *t0, unop(Iop_64to32, mkexpr(lo64)) );
8244 assign( *t1, unop(Iop_64HIto32, mkexpr(lo64)) );
8245 assign( *t2, unop(Iop_64to32, mkexpr(hi64)) );
8246 assign( *t3, unop(Iop_64HIto32, mkexpr(hi64)) );
8247}
8248
8249/* Construct a 128-bit value from four 32-bit ints. */
8250
8251static IRExpr* mk128from32s ( IRTemp t3, IRTemp t2,
8252 IRTemp t1, IRTemp t0 )
8253{
8254 return
8255 binop( Iop_64HLtoV128,
8256 binop(Iop_32HLto64, mkexpr(t3), mkexpr(t2)),
8257 binop(Iop_32HLto64, mkexpr(t1), mkexpr(t0))
8258 );
8259}
8260
8261/* Break a 64-bit value up into four 16-bit ints. */
8262
8263static void breakup64to16s ( IRTemp t64,
8264 /*OUTs*/
8265 IRTemp* t3, IRTemp* t2,
8266 IRTemp* t1, IRTemp* t0 )
8267{
8268 IRTemp hi32 = newTemp(Ity_I32);
8269 IRTemp lo32 = newTemp(Ity_I32);
8270 assign( hi32, unop(Iop_64HIto32, mkexpr(t64)) );
8271 assign( lo32, unop(Iop_64to32, mkexpr(t64)) );
8272
8273 vassert(t0 && *t0 == IRTemp_INVALID);
8274 vassert(t1 && *t1 == IRTemp_INVALID);
8275 vassert(t2 && *t2 == IRTemp_INVALID);
8276 vassert(t3 && *t3 == IRTemp_INVALID);
8277
8278 *t0 = newTemp(Ity_I16);
8279 *t1 = newTemp(Ity_I16);
8280 *t2 = newTemp(Ity_I16);
8281 *t3 = newTemp(Ity_I16);
8282 assign( *t0, unop(Iop_32to16, mkexpr(lo32)) );
8283 assign( *t1, unop(Iop_32HIto16, mkexpr(lo32)) );
8284 assign( *t2, unop(Iop_32to16, mkexpr(hi32)) );
8285 assign( *t3, unop(Iop_32HIto16, mkexpr(hi32)) );
8286}
8287
8288/* Construct a 64-bit value from four 16-bit ints. */
8289
8290static IRExpr* mk64from16s ( IRTemp t3, IRTemp t2,
8291 IRTemp t1, IRTemp t0 )
8292{
8293 return
8294 binop( Iop_32HLto64,
8295 binop(Iop_16HLto32, mkexpr(t3), mkexpr(t2)),
8296 binop(Iop_16HLto32, mkexpr(t1), mkexpr(t0))
8297 );
8298}
sewardjdf0e0022005-01-25 15:48:43 +00008299
8300
sewardjc4356f02007-11-09 21:15:04 +00008301/* Helper for deciding whether a given insn (starting at the opcode
8302 byte) may validly be used with a LOCK prefix. The following insns
8303 may be used with LOCK when their destination operand is in memory.
8304 Note, this is slightly too permissive. Oh well. Note also, AFAICS
8305 this is exactly the same for both 32-bit and 64-bit mode.
8306
8307 ADD 80 /0, 81 /0, 83 /0, 00, 01, 02, 03
8308 OR 80 /1, 81 /1, 83 /1, 08, 09, 0A, 0B
8309 ADC 80 /2, 81 /2, 83 /2, 10, 11, 12, 13
8310 SBB 81 /3, 81 /3, 83 /3, 18, 19, 1A, 1B
8311 AND 80 /4, 81 /4, 83 /4, 20, 21, 22, 23
8312 SUB 80 /5, 81 /5, 83 /5, 28, 29, 2A, 2B
8313 XOR 80 /6, 81 /6, 83 /6, 30, 31, 32, 33
8314
8315 DEC FE /1, FF /1
8316 INC FE /0, FF /0
8317
8318 NEG F6 /3, F7 /3
8319 NOT F6 /2, F7 /2
8320
8321 XCHG 86, 87
8322
8323 BTC 0F BB, 0F BA /7
8324 BTR 0F B3, 0F BA /6
8325 BTS 0F AB, 0F BA /5
8326
8327 CMPXCHG 0F B0, 0F B1
8328 CMPXCHG8B 0F C7 /1
8329
8330 XADD 0F C0, 0F C1
8331*/
8332static Bool can_be_used_with_LOCK_prefix ( UChar* opc )
8333{
8334 switch (opc[0]) {
8335 case 0x00: case 0x01: case 0x02: case 0x03: return True;
8336 case 0x08: case 0x09: case 0x0A: case 0x0B: return True;
8337 case 0x10: case 0x11: case 0x12: case 0x13: return True;
8338 case 0x18: case 0x19: case 0x1A: case 0x1B: return True;
8339 case 0x20: case 0x21: case 0x22: case 0x23: return True;
8340 case 0x28: case 0x29: case 0x2A: case 0x2B: return True;
8341 case 0x30: case 0x31: case 0x32: case 0x33: return True;
8342
8343 case 0x80: case 0x81: case 0x83:
8344 if (gregLO3ofRM(opc[1]) >= 0 && gregLO3ofRM(opc[1]) <= 6)
8345 return True;
8346 break;
8347
8348 case 0xFE: case 0xFF:
8349 if (gregLO3ofRM(opc[1]) >= 0 && gregLO3ofRM(opc[1]) <= 1)
8350 return True;
8351 break;
8352
8353 case 0xF6: case 0xF7:
8354 if (gregLO3ofRM(opc[1]) >= 2 && gregLO3ofRM(opc[1]) <= 3)
8355 return True;
8356 break;
8357
8358 case 0x86: case 0x87:
8359 return True;
8360
8361 case 0x0F: {
8362 switch (opc[1]) {
8363 case 0xBB: case 0xB3: case 0xAB:
8364 return True;
8365 case 0xBA:
8366 if (gregLO3ofRM(opc[2]) >= 5 && gregLO3ofRM(opc[2]) <= 7)
8367 return True;
8368 break;
8369 case 0xB0: case 0xB1:
8370 return True;
8371 case 0xC7:
8372 if (gregLO3ofRM(opc[2]) == 1)
8373 return True;
8374 break;
8375 case 0xC0: case 0xC1:
8376 return True;
8377 default:
8378 break;
8379 } /* switch (opc[1]) */
8380 break;
8381 }
8382
8383 default:
8384 break;
8385 } /* switch (opc[0]) */
8386
8387 return False;
8388}
8389
8390
sewardjdf0e0022005-01-25 15:48:43 +00008391/*------------------------------------------------------------*/
8392/*--- Disassemble a single instruction ---*/
8393/*------------------------------------------------------------*/
8394
sewardj9e6491a2005-07-02 19:24:10 +00008395/* Disassemble a single instruction into IR. The instruction is
8396 located in host memory at &guest_code[delta]. */
sewardjdf0e0022005-01-25 15:48:43 +00008397
sewardj9e6491a2005-07-02 19:24:10 +00008398static
8399DisResult disInstr_AMD64_WRK (
8400 Bool put_IP,
sewardjc716aea2006-01-17 01:48:46 +00008401 Bool (*resteerOkFn) ( /*opaque*/void*, Addr64 ),
8402 void* callback_opaque,
sewardj9e6491a2005-07-02 19:24:10 +00008403 Long delta64,
sewardjaca070a2006-10-17 00:28:22 +00008404 VexArchInfo* archinfo,
sewardjdd40fdf2006-12-24 02:20:24 +00008405 VexAbiInfo* vmi
sewardj9e6491a2005-07-02 19:24:10 +00008406 )
sewardjdf0e0022005-01-25 15:48:43 +00008407{
8408 IRType ty;
sewardja7ba8c42005-05-10 20:08:34 +00008409 IRTemp addr, t0, t1, t2, t3, t4, t5, t6;
sewardjdf0e0022005-01-25 15:48:43 +00008410 Int alen;
sewardj7a240552005-01-28 21:37:12 +00008411 UChar opc, modrm, /*abyte,*/ pre;
sewardj1027dc22005-02-26 01:55:02 +00008412 Long d64;
sewardjdf0e0022005-01-25 15:48:43 +00008413 HChar dis_buf[50];
8414 Int am_sz, d_sz, n, n_prefixes;
sewardj9e6491a2005-07-02 19:24:10 +00008415 DisResult dres;
sewardja6b93d12005-02-17 09:28:28 +00008416 UChar* insn; /* used in SSE decoders */
sewardjdf0e0022005-01-25 15:48:43 +00008417
sewardj9e6491a2005-07-02 19:24:10 +00008418 /* The running delta */
8419 Long delta = delta64;
8420
sewardjdf0e0022005-01-25 15:48:43 +00008421 /* Holds eip at the start of the insn, so that we can print
8422 consistent error messages for unimplemented insns. */
sewardj270def42005-07-03 01:03:01 +00008423 Long delta_start = delta;
sewardjdf0e0022005-01-25 15:48:43 +00008424
8425 /* sz denotes the nominal data-op size of the insn; we change it to
8426 2 if an 0x66 prefix is seen and 8 if REX.W is 1. In case of
8427 conflict REX.W takes precedence. */
8428 Int sz = 4;
8429
sewardj3ca55a12005-01-27 16:06:23 +00008430 /* pfx holds the summary of prefixes. */
8431 Prefix pfx = PFX_EMPTY;
sewardjdf0e0022005-01-25 15:48:43 +00008432
sewardjc4356f02007-11-09 21:15:04 +00008433 /* do we need follow the insn with MBusEvent(BusUnlock) ? */
8434 Bool unlock_bus_after_insn = False;
8435
sewardj9e6491a2005-07-02 19:24:10 +00008436 /* Set result defaults. */
8437 dres.whatNext = Dis_Continue;
8438 dres.len = 0;
8439 dres.continueAt = 0;
sewardjdf0e0022005-01-25 15:48:43 +00008440
sewardj9e6491a2005-07-02 19:24:10 +00008441 vassert(guest_RIP_next_assumed == 0);
8442 vassert(guest_RIP_next_mustcheck == False);
sewardj4b744762005-02-07 15:02:25 +00008443
sewardja7ba8c42005-05-10 20:08:34 +00008444 addr = t0 = t1 = t2 = t3 = t4 = t5 = t6 = IRTemp_INVALID;
sewardjdf0e0022005-01-25 15:48:43 +00008445
sewardj9e6491a2005-07-02 19:24:10 +00008446 DIP("\t0x%llx: ", guest_RIP_bbstart+delta);
8447
8448 /* We may be asked to update the guest RIP before going further. */
8449 if (put_IP)
8450 stmt( IRStmt_Put( OFFB_RIP, mkU64(guest_RIP_curr_instr)) );
sewardjdf0e0022005-01-25 15:48:43 +00008451
sewardjce02aa72006-01-12 12:27:58 +00008452 /* Spot "Special" instructions (see comment at top of file). */
sewardjdf0e0022005-01-25 15:48:43 +00008453 {
8454 UChar* code = (UChar*)(guest_code + delta);
sewardjce02aa72006-01-12 12:27:58 +00008455 /* Spot the 16-byte preamble:
8456 48C1C703 rolq $3, %rdi
8457 48C1C70D rolq $13, %rdi
8458 48C1C73D rolq $61, %rdi
8459 48C1C733 rolq $51, %rdi
sewardjdf0e0022005-01-25 15:48:43 +00008460 */
sewardjce02aa72006-01-12 12:27:58 +00008461 if (code[ 0] == 0x48 && code[ 1] == 0xC1 && code[ 2] == 0xC7
8462 && code[ 3] == 0x03 &&
8463 code[ 4] == 0x48 && code[ 5] == 0xC1 && code[ 6] == 0xC7
8464 && code[ 7] == 0x0D &&
8465 code[ 8] == 0x48 && code[ 9] == 0xC1 && code[10] == 0xC7
8466 && code[11] == 0x3D &&
8467 code[12] == 0x48 && code[13] == 0xC1 && code[14] == 0xC7
8468 && code[15] == 0x33) {
8469 /* Got a "Special" instruction preamble. Which one is it? */
8470 if (code[16] == 0x48 && code[17] == 0x87
8471 && code[18] == 0xDB /* xchgq %rbx,%rbx */) {
8472 /* %RDX = client_request ( %RAX ) */
8473 DIP("%%rdx = client_request ( %%rax )\n");
8474 delta += 19;
8475 jmp_lit(Ijk_ClientReq, guest_RIP_bbstart+delta);
8476 dres.whatNext = Dis_StopHere;
8477 goto decode_success;
8478 }
8479 else
8480 if (code[16] == 0x48 && code[17] == 0x87
8481 && code[18] == 0xC9 /* xchgq %rcx,%rcx */) {
8482 /* %RAX = guest_NRADDR */
8483 DIP("%%rax = guest_NRADDR\n");
8484 delta += 19;
8485 putIRegRAX(8, IRExpr_Get( OFFB_NRADDR, Ity_I64 ));
8486 goto decode_success;
8487 }
8488 else
8489 if (code[16] == 0x48 && code[17] == 0x87
8490 && code[18] == 0xD2 /* xchgq %rdx,%rdx */) {
8491 /* call-noredir *%RAX */
8492 DIP("call-noredir *%%rax\n");
8493 delta += 19;
8494 t1 = newTemp(Ity_I64);
8495 assign(t1, getIRegRAX(8));
8496 t2 = newTemp(Ity_I64);
8497 assign(t2, binop(Iop_Sub64, getIReg64(R_RSP), mkU64(8)));
8498 putIReg64(R_RSP, mkexpr(t2));
8499 storeLE( mkexpr(t2), mkU64(guest_RIP_bbstart+delta));
8500 jmp_treg(Ijk_NoRedir,t1);
8501 dres.whatNext = Dis_StopHere;
8502 goto decode_success;
8503 }
8504 /* We don't know what it is. */
8505 goto decode_failure;
8506 /*NOTREACHED*/
sewardjdf0e0022005-01-25 15:48:43 +00008507 }
8508 }
8509
8510 /* Eat prefixes, summarising the result in pfx and sz, and rejecting
8511 as many invalid combinations as possible. */
8512 n_prefixes = 0;
8513 while (True) {
sewardj54477e32007-08-23 18:53:59 +00008514 if (n_prefixes > 7) goto decode_failure;
sewardj8c332e22005-01-28 01:36:56 +00008515 pre = getUChar(delta);
sewardjdf0e0022005-01-25 15:48:43 +00008516 switch (pre) {
8517 case 0x66: pfx |= PFX_66; break;
8518 case 0x67: pfx |= PFX_ASO; break;
8519 case 0xF2: pfx |= PFX_F2; break;
8520 case 0xF3: pfx |= PFX_F3; break;
8521 case 0xF0: pfx |= PFX_LOCK; break;
8522 case 0x2E: pfx |= PFX_CS; break;
8523 case 0x3E: pfx |= PFX_DS; break;
8524 case 0x26: pfx |= PFX_ES; break;
8525 case 0x64: pfx |= PFX_FS; break;
8526 case 0x65: pfx |= PFX_GS; break;
8527 case 0x36: pfx |= PFX_SS; break;
8528 case 0x40 ... 0x4F:
8529 pfx |= PFX_REX;
8530 if (pre & (1<<3)) pfx |= PFX_REXW;
8531 if (pre & (1<<2)) pfx |= PFX_REXR;
8532 if (pre & (1<<1)) pfx |= PFX_REXX;
8533 if (pre & (1<<0)) pfx |= PFX_REXB;
8534 break;
8535 default:
8536 goto not_a_prefix;
8537 }
8538 n_prefixes++;
8539 delta++;
8540 }
8541
8542 not_a_prefix:
sewardjdf0e0022005-01-25 15:48:43 +00008543
sewardj42561ef2005-11-04 14:18:31 +00008544 /* Dump invalid combinations */
sewardjdf0e0022005-01-25 15:48:43 +00008545 n = 0;
8546 if (pfx & PFX_F2) n++;
8547 if (pfx & PFX_F3) n++;
sewardj3ca55a12005-01-27 16:06:23 +00008548 if (n > 1)
8549 goto decode_failure; /* can't have both */
sewardjdf0e0022005-01-25 15:48:43 +00008550
8551 n = 0;
8552 if (pfx & PFX_CS) n++;
8553 if (pfx & PFX_DS) n++;
8554 if (pfx & PFX_ES) n++;
8555 if (pfx & PFX_FS) n++;
8556 if (pfx & PFX_GS) n++;
8557 if (pfx & PFX_SS) n++;
sewardj3ca55a12005-01-27 16:06:23 +00008558 if (n > 1)
8559 goto decode_failure; /* multiple seg overrides == illegal */
sewardjdf0e0022005-01-25 15:48:43 +00008560
sewardj42561ef2005-11-04 14:18:31 +00008561 if (pfx & PFX_GS)
8562 goto decode_failure; /* legal, but unsupported right now */
8563
sewardjdf0e0022005-01-25 15:48:43 +00008564 /* Set up sz. */
8565 sz = 4;
8566 if (pfx & PFX_66) sz = 2;
8567 if ((pfx & PFX_REX) && (pfx & PFX_REXW)) sz = 8;
8568
sewardj9ff93bc2005-03-23 11:25:12 +00008569 /* Kludge re LOCK prefixes. We assume here that all code generated
8570 by Vex is going to be run in a single-threaded context, in other
8571 words that concurrent executions of Vex-generated translations
sewardjc4356f02007-11-09 21:15:04 +00008572 will not happen. So we don't need to worry too much about
8573 preserving atomicity. However, mark the fact that the notional
8574 hardware bus lock is being acquired (and, after the insn,
8575 released), so that thread checking tools know this is a locked
8576 insn.
8577
8578 We check for, and immediately reject, (most) inappropriate uses
8579 of the LOCK prefix. Later (at decode_failure: and
8580 decode_success:), if we've added a BusLock event, then we will
8581 follow up with a BusUnlock event. How do we know execution will
8582 actually ever get to the BusUnlock event? Because
8583 can_be_used_with_LOCK_prefix rejects all control-flow changing
8584 instructions.
8585
8586 One loophole, though: if a LOCK prefix insn (seg)faults, then
8587 the BusUnlock event will never be reached. This could cause
8588 tools which track bus hardware lock to lose track. Really, we
8589 should explicitly release the lock after every insn, but that's
8590 obviously way too expensive. Really, any tool which tracks the
8591 state of the bus lock needs to ask V's core/tool interface to
8592 notify it of signal deliveries. On delivery of SIGSEGV to the
8593 guest, the tool will be notified, in which case it should
8594 release the bus hardware lock if it is held.
8595
8596 Note, guest-x86/toIR.c contains identical logic.
8597 */
sewardj9ff93bc2005-03-23 11:25:12 +00008598 if (pfx & PFX_LOCK) {
sewardjc4356f02007-11-09 21:15:04 +00008599 if (can_be_used_with_LOCK_prefix( (UChar*)&guest_code[delta] )) {
8600 stmt( IRStmt_MBE(Imbe_BusLock) );
8601 unlock_bus_after_insn = True;
8602 DIP("lock ");
8603 } else {
8604 goto decode_failure;
8605 }
sewardjdf0e0022005-01-25 15:48:43 +00008606 }
8607
sewardja6b93d12005-02-17 09:28:28 +00008608
8609 /* ---------------------------------------------------- */
sewardj09717342005-05-05 21:34:02 +00008610 /* --- The SSE/SSE2 decoder. --- */
sewardja6b93d12005-02-17 09:28:28 +00008611 /* ---------------------------------------------------- */
8612
8613 /* What did I do to deserve SSE ? Perhaps I was really bad in a
8614 previous life? */
8615
sewardj09717342005-05-05 21:34:02 +00008616 /* Note, this doesn't handle SSE3 right now. All amd64s support
8617 SSE2 as a minimum so there is no point distinguishing SSE1 vs
8618 SSE2. */
8619
sewardja6b93d12005-02-17 09:28:28 +00008620 insn = (UChar*)&guest_code[delta];
8621
sewardj5abcfe62007-01-10 04:59:33 +00008622 /* FXSAVE is spuriously at the start here only because it is
8623 thusly placed in guest-x86/toIR.c. */
8624
8625 /* 0F AE /0 = FXSAVE m512 -- write x87 and SSE state to memory.
8626 Note that REX.W 0F AE /0 writes a slightly different format and
8627 we don't handle that here. */
8628 if (haveNo66noF2noF3(pfx) && sz == 4
8629 && insn[0] == 0x0F && insn[1] == 0xAE
8630 && !epartIsReg(insn[2]) && gregOfRexRM(pfx,insn[2]) == 0) {
8631 IRDirty* d;
8632 modrm = getUChar(delta+2);
8633 vassert(sz == 4);
8634 vassert(!epartIsReg(modrm));
8635 /* REX.W must not be set. That should be assured us by sz == 4
8636 above. */
8637 vassert(!(pfx & PFX_REXW));
8638
8639 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8640 delta += 2+alen;
8641
8642 DIP("fxsave %s\n", dis_buf);
8643
8644 /* Uses dirty helper:
8645 void amd64g_do_FXSAVE ( VexGuestAMD64State*, UInt ) */
8646 d = unsafeIRDirty_0_N (
8647 0/*regparms*/,
8648 "amd64g_dirtyhelper_FXSAVE",
8649 &amd64g_dirtyhelper_FXSAVE,
8650 mkIRExprVec_1( mkexpr(addr) )
8651 );
8652 d->needsBBP = True;
8653
8654 /* declare we're writing memory */
8655 d->mFx = Ifx_Write;
8656 d->mAddr = mkexpr(addr);
8657 d->mSize = 512;
8658
8659 /* declare we're reading guest state */
8660 d->nFxState = 7;
8661
8662 d->fxState[0].fx = Ifx_Read;
8663 d->fxState[0].offset = OFFB_FTOP;
8664 d->fxState[0].size = sizeof(UInt);
8665
8666 d->fxState[1].fx = Ifx_Read;
8667 d->fxState[1].offset = OFFB_FPREGS;
8668 d->fxState[1].size = 8 * sizeof(ULong);
8669
8670 d->fxState[2].fx = Ifx_Read;
8671 d->fxState[2].offset = OFFB_FPTAGS;
8672 d->fxState[2].size = 8 * sizeof(UChar);
8673
8674 d->fxState[3].fx = Ifx_Read;
8675 d->fxState[3].offset = OFFB_FPROUND;
8676 d->fxState[3].size = sizeof(ULong);
8677
8678 d->fxState[4].fx = Ifx_Read;
8679 d->fxState[4].offset = OFFB_FC3210;
8680 d->fxState[4].size = sizeof(ULong);
8681
8682 d->fxState[5].fx = Ifx_Read;
8683 d->fxState[5].offset = OFFB_XMM0;
8684 d->fxState[5].size = 16 * sizeof(U128);
8685
8686 d->fxState[6].fx = Ifx_Read;
8687 d->fxState[6].offset = OFFB_SSEROUND;
8688 d->fxState[6].size = sizeof(ULong);
8689
8690 /* Be paranoid ... this assertion tries to ensure the 16 %xmm
8691 images are packed back-to-back. If not, the value of
8692 d->fxState[5].size is wrong. */
8693 vassert(16 == sizeof(U128));
8694 vassert(OFFB_XMM15 == (OFFB_XMM0 + 15 * 16));
8695
8696 stmt( IRStmt_Dirty(d) );
8697
8698 goto decode_success;
8699 }
8700
8701 /* ------ SSE decoder main ------ */
sewardj432f8b62005-05-10 02:50:05 +00008702
8703 /* 0F 58 = ADDPS -- add 32Fx4 from R/M to R */
8704 if (haveNo66noF2noF3(pfx) && sz == 4
8705 && insn[0] == 0x0F && insn[1] == 0x58) {
8706 delta = dis_SSE_E_to_G_all( pfx, delta+2, "addps", Iop_Add32Fx4 );
8707 goto decode_success;
8708 }
sewardj8d965312005-02-25 02:48:47 +00008709
8710 /* F3 0F 58 = ADDSS -- add 32F0x4 from R/M to R */
8711 if (haveF3no66noF2(pfx) && sz == 4
8712 && insn[0] == 0x0F && insn[1] == 0x58) {
8713 delta = dis_SSE_E_to_G_lo32( pfx, delta+2, "addss", Iop_Add32F0x4 );
8714 goto decode_success;
8715 }
8716
sewardj3aba9eb2005-03-30 23:20:47 +00008717 /* 0F 55 = ANDNPS -- G = (not G) and E */
8718 if (haveNo66noF2noF3(pfx) && sz == 4
8719 && insn[0] == 0x0F && insn[1] == 0x55) {
8720 delta = dis_SSE_E_to_G_all_invG( pfx, delta+2, "andnps", Iop_AndV128 );
8721 goto decode_success;
8722 }
sewardj37d52572005-02-25 14:22:12 +00008723
8724 /* 0F 54 = ANDPS -- G = G and E */
8725 if (haveNo66noF2noF3(pfx) && sz == 4
8726 && insn[0] == 0x0F && insn[1] == 0x54) {
8727 delta = dis_SSE_E_to_G_all( pfx, delta+2, "andps", Iop_AndV128 );
8728 goto decode_success;
8729 }
8730
sewardj432f8b62005-05-10 02:50:05 +00008731 /* 0F C2 = CMPPS -- 32Fx4 comparison from R/M to R */
8732 if (haveNo66noF2noF3(pfx) && sz == 4
8733 && insn[0] == 0x0F && insn[1] == 0xC2) {
8734 delta = dis_SSEcmp_E_to_G( pfx, delta+2, "cmpps", True, 4 );
8735 goto decode_success;
8736 }
sewardj3aba9eb2005-03-30 23:20:47 +00008737
8738 /* F3 0F C2 = CMPSS -- 32F0x4 comparison from R/M to R */
8739 if (haveF3no66noF2(pfx) && sz == 4
8740 && insn[0] == 0x0F && insn[1] == 0xC2) {
8741 delta = dis_SSEcmp_E_to_G( pfx, delta+2, "cmpss", False, 4 );
8742 goto decode_success;
8743 }
sewardjc49ce232005-02-25 13:03:03 +00008744
8745 /* 0F 2F = COMISS -- 32F0x4 comparison G,E, and set ZCP */
8746 /* 0F 2E = UCOMISS -- 32F0x4 comparison G,E, and set ZCP */
8747 if (haveNo66noF2noF3(pfx) && sz == 4
8748 && insn[0] == 0x0F && (insn[1] == 0x2F || insn[1] == 0x2E)) {
8749 IRTemp argL = newTemp(Ity_F32);
8750 IRTemp argR = newTemp(Ity_F32);
8751 modrm = getUChar(delta+2);
8752 if (epartIsReg(modrm)) {
8753 assign( argR, getXMMRegLane32F( eregOfRexRM(pfx,modrm),
8754 0/*lowest lane*/ ) );
8755 delta += 2+1;
8756 DIP("%scomiss %s,%s\n", insn[1]==0x2E ? "u" : "",
8757 nameXMMReg(eregOfRexRM(pfx,modrm)),
8758 nameXMMReg(gregOfRexRM(pfx,modrm)) );
8759 } else {
8760 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8761 assign( argR, loadLE(Ity_F32, mkexpr(addr)) );
8762 delta += 2+alen;
8763 DIP("%scomiss %s,%s\n", insn[1]==0x2E ? "u" : "",
8764 dis_buf,
8765 nameXMMReg(gregOfRexRM(pfx,modrm)) );
8766 }
8767 assign( argL, getXMMRegLane32F( gregOfRexRM(pfx,modrm),
8768 0/*lowest lane*/ ) );
8769
8770 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(AMD64G_CC_OP_COPY) ));
8771 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
8772 stmt( IRStmt_Put(
8773 OFFB_CC_DEP1,
8774 binop( Iop_And64,
8775 unop( Iop_32Uto64,
8776 binop(Iop_CmpF64,
8777 unop(Iop_F32toF64,mkexpr(argL)),
8778 unop(Iop_F32toF64,mkexpr(argR)))),
8779 mkU64(0x45)
8780 )));
8781
8782 goto decode_success;
8783 }
8784
sewardj432f8b62005-05-10 02:50:05 +00008785 /* 0F 2A = CVTPI2PS -- convert 2 x I32 in mem/mmx to 2 x F32 in low
8786 half xmm */
8787 if (haveNo66noF2noF3(pfx) && sz == 4
8788 && insn[0] == 0x0F && insn[1] == 0x2A) {
8789 IRTemp arg64 = newTemp(Ity_I64);
8790 IRTemp rmode = newTemp(Ity_I32);
8791
8792 modrm = getUChar(delta+2);
8793 do_MMX_preamble();
8794 if (epartIsReg(modrm)) {
8795 assign( arg64, getMMXReg(eregLO3ofRM(modrm)) );
8796 delta += 2+1;
8797 DIP("cvtpi2ps %s,%s\n", nameMMXReg(eregLO3ofRM(modrm)),
8798 nameXMMReg(gregOfRexRM(pfx,modrm)));
8799 } else {
8800 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8801 assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
8802 delta += 2+alen;
8803 DIP("cvtpi2ps %s,%s\n", dis_buf,
8804 nameXMMReg(gregOfRexRM(pfx,modrm)) );
8805 }
8806
8807 assign( rmode, get_sse_roundingmode() );
8808
8809 putXMMRegLane32F(
8810 gregOfRexRM(pfx,modrm), 0,
8811 binop(Iop_F64toF32,
8812 mkexpr(rmode),
8813 unop(Iop_I32toF64,
8814 unop(Iop_64to32, mkexpr(arg64)) )) );
8815
8816 putXMMRegLane32F(
8817 gregOfRexRM(pfx,modrm), 1,
8818 binop(Iop_F64toF32,
8819 mkexpr(rmode),
8820 unop(Iop_I32toF64,
8821 unop(Iop_64HIto32, mkexpr(arg64)) )) );
8822
8823 goto decode_success;
8824 }
sewardj8d965312005-02-25 02:48:47 +00008825
8826 /* F3 0F 2A = CVTSI2SS
8827 -- sz==4: convert I32 in mem/ireg to F32 in low quarter xmm
8828 -- sz==8: convert I64 in mem/ireg to F32 in low quarter xmm */
8829 if (haveF3no66noF2(pfx) && (sz == 4 || sz == 8)
8830 && insn[0] == 0x0F && insn[1] == 0x2A) {
8831
8832 IRTemp rmode = newTemp(Ity_I32);
8833 assign( rmode, get_sse_roundingmode() );
8834 modrm = getUChar(delta+2);
8835
8836 if (sz == 4) {
8837 IRTemp arg32 = newTemp(Ity_I32);
8838 if (epartIsReg(modrm)) {
sewardj5b470602005-02-27 13:10:48 +00008839 assign( arg32, getIReg32(eregOfRexRM(pfx,modrm)) );
sewardj8d965312005-02-25 02:48:47 +00008840 delta += 2+1;
sewardj5b470602005-02-27 13:10:48 +00008841 DIP("cvtsi2ss %s,%s\n", nameIReg32(eregOfRexRM(pfx,modrm)),
sewardj8d965312005-02-25 02:48:47 +00008842 nameXMMReg(gregOfRexRM(pfx,modrm)));
8843 } else {
sewardj8d965312005-02-25 02:48:47 +00008844 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8845 assign( arg32, loadLE(Ity_I32, mkexpr(addr)) );
8846 delta += 2+alen;
8847 DIP("cvtsi2ss %s,%s\n", dis_buf,
8848 nameXMMReg(gregOfRexRM(pfx,modrm)) );
8849 }
8850 putXMMRegLane32F(
8851 gregOfRexRM(pfx,modrm), 0,
8852 binop(Iop_F64toF32,
8853 mkexpr(rmode),
8854 unop(Iop_I32toF64, mkexpr(arg32)) ) );
8855 } else {
8856 /* sz == 8 */
8857 IRTemp arg64 = newTemp(Ity_I64);
8858 if (epartIsReg(modrm)) {
sewardj5b470602005-02-27 13:10:48 +00008859 assign( arg64, getIReg64(eregOfRexRM(pfx,modrm)) );
sewardj8d965312005-02-25 02:48:47 +00008860 delta += 2+1;
sewardj5b470602005-02-27 13:10:48 +00008861 DIP("cvtsi2ssq %s,%s\n", nameIReg64(eregOfRexRM(pfx,modrm)),
sewardj8d965312005-02-25 02:48:47 +00008862 nameXMMReg(gregOfRexRM(pfx,modrm)));
8863 } else {
sewardj82c9f2f2005-03-02 16:05:13 +00008864 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8865 assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
8866 delta += 2+alen;
8867 DIP("cvtsi2ssq %s,%s\n", dis_buf,
8868 nameXMMReg(gregOfRexRM(pfx,modrm)) );
sewardj8d965312005-02-25 02:48:47 +00008869 }
8870 putXMMRegLane32F(
8871 gregOfRexRM(pfx,modrm), 0,
8872 binop(Iop_F64toF32,
8873 mkexpr(rmode),
8874 binop(Iop_I64toF64, mkexpr(rmode), mkexpr(arg64)) ) );
8875 }
8876
8877 goto decode_success;
8878 }
8879
sewardj432f8b62005-05-10 02:50:05 +00008880 /* 0F 2D = CVTPS2PI -- convert 2 x F32 in mem/low half xmm to 2 x
8881 I32 in mmx, according to prevailing SSE rounding mode */
sewardja7ba8c42005-05-10 20:08:34 +00008882 /* 0F 2C = CVTTPS2PI -- convert 2 x F32 in mem/low half xmm to 2 x
8883 I32 in mmx, rounding towards zero */
sewardj432f8b62005-05-10 02:50:05 +00008884 if (haveNo66noF2noF3(pfx) && sz == 4
sewardja7ba8c42005-05-10 20:08:34 +00008885 && insn[0] == 0x0F && (insn[1] == 0x2D || insn[1] == 0x2C)) {
sewardj432f8b62005-05-10 02:50:05 +00008886 IRTemp dst64 = newTemp(Ity_I64);
8887 IRTemp rmode = newTemp(Ity_I32);
8888 IRTemp f32lo = newTemp(Ity_F32);
8889 IRTemp f32hi = newTemp(Ity_F32);
8890 Bool r2zero = toBool(insn[1] == 0x2C);
8891
8892 do_MMX_preamble();
8893 modrm = getUChar(delta+2);
8894
8895 if (epartIsReg(modrm)) {
8896 delta += 2+1;
8897 assign(f32lo, getXMMRegLane32F(eregOfRexRM(pfx,modrm), 0));
8898 assign(f32hi, getXMMRegLane32F(eregOfRexRM(pfx,modrm), 1));
8899 DIP("cvt%sps2pi %s,%s\n", r2zero ? "t" : "",
8900 nameXMMReg(eregOfRexRM(pfx,modrm)),
8901 nameMMXReg(gregLO3ofRM(modrm)));
8902 } else {
8903 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8904 assign(f32lo, loadLE(Ity_F32, mkexpr(addr)));
8905 assign(f32hi, loadLE(Ity_F32, binop( Iop_Add64,
8906 mkexpr(addr),
8907 mkU64(4) )));
8908 delta += 2+alen;
8909 DIP("cvt%sps2pi %s,%s\n", r2zero ? "t" : "",
8910 dis_buf,
8911 nameMMXReg(gregLO3ofRM(modrm)));
8912 }
8913
8914 if (r2zero) {
8915 assign(rmode, mkU32((UInt)Irrm_ZERO) );
8916 } else {
8917 assign( rmode, get_sse_roundingmode() );
8918 }
8919
8920 assign(
8921 dst64,
8922 binop( Iop_32HLto64,
8923 binop( Iop_F64toI32,
8924 mkexpr(rmode),
8925 unop( Iop_F32toF64, mkexpr(f32hi) ) ),
8926 binop( Iop_F64toI32,
8927 mkexpr(rmode),
8928 unop( Iop_F32toF64, mkexpr(f32lo) ) )
8929 )
8930 );
8931
8932 putMMXReg(gregLO3ofRM(modrm), mkexpr(dst64));
8933 goto decode_success;
8934 }
8935
8936 /* F3 0F 2D = CVTSS2SI
8937 when sz==4 -- convert F32 in mem/low quarter xmm to I32 in ireg,
8938 according to prevailing SSE rounding mode
8939 when sz==8 -- convert F32 in mem/low quarter xmm to I64 in ireg,
8940 according to prevailing SSE rounding mode
8941 */
sewardj82c9f2f2005-03-02 16:05:13 +00008942 /* F3 0F 2C = CVTTSS2SI
8943 when sz==4 -- convert F32 in mem/low quarter xmm to I32 in ireg,
8944 truncating towards zero
8945 when sz==8 -- convert F32 in mem/low quarter xmm to I64 in ireg,
8946 truncating towards zero
8947 */
8948 if (haveF3no66noF2(pfx)
8949 && insn[0] == 0x0F
sewardj432f8b62005-05-10 02:50:05 +00008950 && (insn[1] == 0x2D || insn[1] == 0x2C)) {
sewardj82c9f2f2005-03-02 16:05:13 +00008951 IRTemp rmode = newTemp(Ity_I32);
8952 IRTemp f32lo = newTemp(Ity_F32);
8953 Bool r2zero = toBool(insn[1] == 0x2C);
8954 vassert(sz == 4 || sz == 8);
8955
8956 modrm = getUChar(delta+2);
8957 if (epartIsReg(modrm)) {
8958 delta += 2+1;
8959 assign(f32lo, getXMMRegLane32F(eregOfRexRM(pfx,modrm), 0));
8960 DIP("cvt%sss2si %s,%s\n", r2zero ? "t" : "",
8961 nameXMMReg(eregOfRexRM(pfx,modrm)),
8962 nameIReg(sz, gregOfRexRM(pfx,modrm), False));
8963 } else {
8964 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8965 assign(f32lo, loadLE(Ity_F32, mkexpr(addr)));
8966 delta += 2+alen;
8967 DIP("cvt%sss2si %s,%s\n", r2zero ? "t" : "",
8968 dis_buf,
8969 nameIReg(sz, gregOfRexRM(pfx,modrm), False));
8970 }
8971
8972 if (r2zero) {
8973 assign( rmode, mkU32((UInt)Irrm_ZERO) );
8974 } else {
8975 assign( rmode, get_sse_roundingmode() );
8976 }
8977
8978 if (sz == 4) {
8979 putIReg32( gregOfRexRM(pfx,modrm),
8980 binop( Iop_F64toI32,
8981 mkexpr(rmode),
8982 unop(Iop_F32toF64, mkexpr(f32lo))) );
8983 } else {
8984 putIReg64( gregOfRexRM(pfx,modrm),
8985 binop( Iop_F64toI64,
8986 mkexpr(rmode),
8987 unop(Iop_F32toF64, mkexpr(f32lo))) );
8988 }
8989
8990 goto decode_success;
8991 }
8992
sewardj432f8b62005-05-10 02:50:05 +00008993 /* 0F 5E = DIVPS -- div 32Fx4 from R/M to R */
8994 if (haveNo66noF2noF3(pfx) && sz == 4
8995 && insn[0] == 0x0F && insn[1] == 0x5E) {
8996 delta = dis_SSE_E_to_G_all( pfx, delta+2, "divps", Iop_Div32Fx4 );
8997 goto decode_success;
8998 }
sewardjc49ce232005-02-25 13:03:03 +00008999
9000 /* F3 0F 5E = DIVSS -- div 32F0x4 from R/M to R */
9001 if (haveF3no66noF2(pfx) && sz == 4
9002 && insn[0] == 0x0F && insn[1] == 0x5E) {
9003 delta = dis_SSE_E_to_G_lo32( pfx, delta+2, "divss", Iop_Div32F0x4 );
9004 goto decode_success;
9005 }
9006
sewardjbcbb9de2005-03-27 02:22:32 +00009007 /* 0F AE /2 = LDMXCSR m32 -- load %mxcsr */
9008 if (insn[0] == 0x0F && insn[1] == 0xAE
9009 && haveNo66noF2noF3(pfx)
9010 && !epartIsReg(insn[2]) && gregLO3ofRM(insn[2]) == 2) {
9011
9012 IRTemp t64 = newTemp(Ity_I64);
9013 IRTemp ew = newTemp(Ity_I32);
9014
9015 vassert(sz == 4);
9016 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9017 delta += 2+alen;
9018 DIP("ldmxcsr %s\n", dis_buf);
9019
9020 /* The only thing we observe in %mxcsr is the rounding mode.
9021 Therefore, pass the 32-bit value (SSE native-format control
9022 word) to a clean helper, getting back a 64-bit value, the
9023 lower half of which is the SSEROUND value to store, and the
9024 upper half of which is the emulation-warning token which may
9025 be generated.
9026 */
9027 /* ULong amd64h_check_ldmxcsr ( ULong ); */
9028 assign( t64, mkIRExprCCall(
9029 Ity_I64, 0/*regparms*/,
9030 "amd64g_check_ldmxcsr",
9031 &amd64g_check_ldmxcsr,
9032 mkIRExprVec_1(
9033 unop(Iop_32Uto64,
9034 loadLE(Ity_I32, mkexpr(addr))
9035 )
9036 )
9037 )
9038 );
9039
9040 put_sse_roundingmode( unop(Iop_64to32, mkexpr(t64)) );
9041 assign( ew, unop(Iop_64HIto32, mkexpr(t64) ) );
9042 put_emwarn( mkexpr(ew) );
9043 /* Finally, if an emulation warning was reported, side-exit to
9044 the next insn, reporting the warning, so that Valgrind's
9045 dispatcher sees the warning. */
9046 stmt(
9047 IRStmt_Exit(
9048 binop(Iop_CmpNE64, unop(Iop_32Uto64,mkexpr(ew)), mkU64(0)),
9049 Ijk_EmWarn,
sewardj9e6491a2005-07-02 19:24:10 +00009050 IRConst_U64(guest_RIP_bbstart+delta)
sewardjbcbb9de2005-03-27 02:22:32 +00009051 )
9052 );
9053 goto decode_success;
9054 }
9055
sewardj02f79f12007-09-01 18:59:53 +00009056 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9057 /* 0F F7 = MASKMOVQ -- 8x8 masked store */
9058 if (haveNo66noF2noF3(pfx) && sz == 4
9059 && insn[0] == 0x0F && insn[1] == 0xF7) {
9060 Bool ok = False;
9061 delta = dis_MMX( &ok, pfx, sz, delta+1 );
9062 if (!ok)
9063 goto decode_failure;
9064 goto decode_success;
9065 }
9066
sewardj432f8b62005-05-10 02:50:05 +00009067 /* 0F 5F = MAXPS -- max 32Fx4 from R/M to R */
9068 if (haveNo66noF2noF3(pfx) && sz == 4
9069 && insn[0] == 0x0F && insn[1] == 0x5F) {
9070 delta = dis_SSE_E_to_G_all( pfx, delta+2, "maxps", Iop_Max32Fx4 );
9071 goto decode_success;
9072 }
sewardj37d52572005-02-25 14:22:12 +00009073
9074 /* F3 0F 5F = MAXSS -- max 32F0x4 from R/M to R */
9075 if (haveF3no66noF2(pfx) && sz == 4
9076 && insn[0] == 0x0F && insn[1] == 0x5F) {
9077 delta = dis_SSE_E_to_G_lo32( pfx, delta+2, "maxss", Iop_Max32F0x4 );
9078 goto decode_success;
9079 }
9080
sewardj432f8b62005-05-10 02:50:05 +00009081 /* 0F 5D = MINPS -- min 32Fx4 from R/M to R */
9082 if (haveNo66noF2noF3(pfx) && sz == 4
9083 && insn[0] == 0x0F && insn[1] == 0x5D) {
9084 delta = dis_SSE_E_to_G_all( pfx, delta+2, "minps", Iop_Min32Fx4 );
9085 goto decode_success;
9086 }
sewardj37d52572005-02-25 14:22:12 +00009087
9088 /* F3 0F 5D = MINSS -- min 32F0x4 from R/M to R */
9089 if (haveF3no66noF2(pfx) && sz == 4
9090 && insn[0] == 0x0F && insn[1] == 0x5D) {
9091 delta = dis_SSE_E_to_G_lo32( pfx, delta+2, "minss", Iop_Min32F0x4 );
9092 goto decode_success;
9093 }
sewardj8d965312005-02-25 02:48:47 +00009094
9095 /* 0F 28 = MOVAPS -- move from E (mem or xmm) to G (xmm). */
9096 /* 0F 10 = MOVUPS -- move from E (mem or xmm) to G (xmm). */
sewardjb4bf5882007-11-06 20:39:17 +00009097 if (haveNo66noF2noF3(pfx)
9098 && (sz == 4 || /* ignore redundant REX.W */ sz == 8)
sewardj8d965312005-02-25 02:48:47 +00009099 && insn[0] == 0x0F && (insn[1] == 0x28 || insn[1] == 0x10)) {
9100 modrm = getUChar(delta+2);
9101 if (epartIsReg(modrm)) {
9102 putXMMReg( gregOfRexRM(pfx,modrm),
9103 getXMMReg( eregOfRexRM(pfx,modrm) ));
9104 DIP("mov[ua]ps %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
9105 nameXMMReg(gregOfRexRM(pfx,modrm)));
9106 delta += 2+1;
9107 } else {
9108 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9109 putXMMReg( gregOfRexRM(pfx,modrm),
9110 loadLE(Ity_V128, mkexpr(addr)) );
9111 DIP("mov[ua]ps %s,%s\n", dis_buf,
9112 nameXMMReg(gregOfRexRM(pfx,modrm)));
9113 delta += 2+alen;
9114 }
9115 goto decode_success;
9116 }
sewardj1001dc42005-02-21 08:25:55 +00009117
9118 /* 0F 29 = MOVAPS -- move from G (xmm) to E (mem or xmm). */
sewardj446d2672005-06-10 11:04:52 +00009119 /* 0F 11 = MOVUPS -- move from G (xmm) to E (mem or xmm). */
sewardjb4bf5882007-11-06 20:39:17 +00009120 if (haveNo66noF2noF3(pfx)
9121 && (sz == 4 || /* ignore redundant REX.W */ sz == 8)
sewardj446d2672005-06-10 11:04:52 +00009122 && insn[0] == 0x0F && (insn[1] == 0x29 || insn[1] == 0x11)) {
sewardj1001dc42005-02-21 08:25:55 +00009123 modrm = getUChar(delta+2);
9124 if (epartIsReg(modrm)) {
9125 /* fall through; awaiting test case */
9126 } else {
9127 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9128 storeLE( mkexpr(addr), getXMMReg(gregOfRexRM(pfx,modrm)) );
sewardj446d2672005-06-10 11:04:52 +00009129 DIP("mov[ua]ps %s,%s\n", nameXMMReg(gregOfRexRM(pfx,modrm)),
9130 dis_buf );
sewardj1001dc42005-02-21 08:25:55 +00009131 delta += 2+alen;
9132 goto decode_success;
9133 }
9134 }
9135
sewardj432f8b62005-05-10 02:50:05 +00009136 /* 0F 16 = MOVHPS -- move from mem to high half of XMM. */
9137 /* 0F 16 = MOVLHPS -- move from lo half to hi half of XMM. */
sewardjb4bf5882007-11-06 20:39:17 +00009138 if (haveNo66noF2noF3(pfx)
9139 && (sz == 4 || /* ignore redundant REX.W */ sz == 8)
sewardj432f8b62005-05-10 02:50:05 +00009140 && insn[0] == 0x0F && insn[1] == 0x16) {
9141 modrm = getUChar(delta+2);
9142 if (epartIsReg(modrm)) {
9143 delta += 2+1;
9144 putXMMRegLane64( gregOfRexRM(pfx,modrm), 1/*upper lane*/,
9145 getXMMRegLane64( eregOfRexRM(pfx,modrm), 0 ) );
9146 DIP("movhps %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
9147 nameXMMReg(gregOfRexRM(pfx,modrm)));
9148 } else {
9149 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9150 delta += 2+alen;
9151 putXMMRegLane64( gregOfRexRM(pfx,modrm), 1/*upper lane*/,
9152 loadLE(Ity_I64, mkexpr(addr)) );
9153 DIP("movhps %s,%s\n", dis_buf,
9154 nameXMMReg( gregOfRexRM(pfx,modrm) ));
9155 }
9156 goto decode_success;
9157 }
9158
9159 /* 0F 17 = MOVHPS -- move from high half of XMM to mem. */
sewardjb4bf5882007-11-06 20:39:17 +00009160 if (haveNo66noF2noF3(pfx)
9161 && (sz == 4 || /* ignore redundant REX.W */ sz == 8)
sewardj432f8b62005-05-10 02:50:05 +00009162 && insn[0] == 0x0F && insn[1] == 0x17) {
9163 if (!epartIsReg(insn[2])) {
9164 delta += 2;
9165 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
9166 delta += alen;
9167 storeLE( mkexpr(addr),
9168 getXMMRegLane64( gregOfRexRM(pfx,insn[2]),
9169 1/*upper lane*/ ) );
9170 DIP("movhps %s,%s\n", nameXMMReg( gregOfRexRM(pfx,insn[2]) ),
9171 dis_buf);
9172 goto decode_success;
9173 }
9174 /* else fall through */
9175 }
9176
9177 /* 0F 12 = MOVLPS -- move from mem to low half of XMM. */
9178 /* OF 12 = MOVHLPS -- from from hi half to lo half of XMM. */
sewardjb4bf5882007-11-06 20:39:17 +00009179 if (haveNo66noF2noF3(pfx)
9180 && (sz == 4 || /* ignore redundant REX.W */ sz == 8)
sewardj432f8b62005-05-10 02:50:05 +00009181 && insn[0] == 0x0F && insn[1] == 0x12) {
9182 modrm = getUChar(delta+2);
9183 if (epartIsReg(modrm)) {
9184 delta += 2+1;
9185 putXMMRegLane64( gregOfRexRM(pfx,modrm),
9186 0/*lower lane*/,
9187 getXMMRegLane64( eregOfRexRM(pfx,modrm), 1 ));
9188 DIP("movhlps %s, %s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
9189 nameXMMReg(gregOfRexRM(pfx,modrm)));
9190 } else {
9191 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9192 delta += 2+alen;
9193 putXMMRegLane64( gregOfRexRM(pfx,modrm), 0/*lower lane*/,
9194 loadLE(Ity_I64, mkexpr(addr)) );
9195 DIP("movlps %s, %s\n",
9196 dis_buf, nameXMMReg( gregOfRexRM(pfx,modrm) ));
9197 }
9198 goto decode_success;
9199 }
9200
9201 /* 0F 13 = MOVLPS -- move from low half of XMM to mem. */
sewardjb4bf5882007-11-06 20:39:17 +00009202 if (haveNo66noF2noF3(pfx)
9203 && (sz == 4 || /* ignore redundant REX.W */ sz == 8)
sewardj432f8b62005-05-10 02:50:05 +00009204 && insn[0] == 0x0F && insn[1] == 0x13) {
9205 if (!epartIsReg(insn[2])) {
9206 delta += 2;
9207 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
9208 delta += alen;
9209 storeLE( mkexpr(addr),
9210 getXMMRegLane64( gregOfRexRM(pfx,insn[2]),
9211 0/*lower lane*/ ) );
9212 DIP("movlps %s, %s\n", nameXMMReg( gregOfRexRM(pfx,insn[2]) ),
9213 dis_buf);
9214 goto decode_success;
9215 }
9216 /* else fall through */
9217 }
9218
sewardja7ba8c42005-05-10 20:08:34 +00009219 /* 0F 50 = MOVMSKPS - move 4 sign bits from 4 x F32 in xmm(E)
9220 to 4 lowest bits of ireg(G) */
sewardjae84d782006-04-13 22:06:35 +00009221 if (haveNo66noF2noF3(pfx) && (sz == 4 || sz == 8)
sewardja7ba8c42005-05-10 20:08:34 +00009222 && insn[0] == 0x0F && insn[1] == 0x50) {
sewardjae84d782006-04-13 22:06:35 +00009223 /* sz == 8 is a kludge to handle insns with REX.W redundantly
9224 set to 1, which has been known to happen:
sewardjb4bf5882007-11-06 20:39:17 +00009225
sewardjae84d782006-04-13 22:06:35 +00009226 4c 0f 50 d9 rex64X movmskps %xmm1,%r11d
sewardjb4bf5882007-11-06 20:39:17 +00009227
9228 20071106: Intel docs say that REX.W isn't redundant: when
9229 present, a 64-bit register is written; when not present, only
9230 the 32-bit half is written. However, testing on a Core2
9231 machine suggests the entire 64 bit register is written
9232 irrespective of the status of REX.W. That could be because
9233 of the default rule that says "if the lower half of a 32-bit
9234 register is written, the upper half is zeroed". By using
9235 putIReg32 here we inadvertantly produce the same behaviour as
9236 the Core2, for the same reason -- putIReg32 implements said
9237 rule.
9238
9239 AMD docs give no indication that REX.W is even valid for this
9240 insn. */
sewardja7ba8c42005-05-10 20:08:34 +00009241 modrm = getUChar(delta+2);
9242 if (epartIsReg(modrm)) {
9243 Int src;
9244 t0 = newTemp(Ity_I32);
9245 t1 = newTemp(Ity_I32);
9246 t2 = newTemp(Ity_I32);
9247 t3 = newTemp(Ity_I32);
9248 delta += 2+1;
9249 src = eregOfRexRM(pfx,modrm);
9250 assign( t0, binop( Iop_And32,
9251 binop(Iop_Shr32, getXMMRegLane32(src,0), mkU8(31)),
9252 mkU32(1) ));
9253 assign( t1, binop( Iop_And32,
9254 binop(Iop_Shr32, getXMMRegLane32(src,1), mkU8(30)),
9255 mkU32(2) ));
9256 assign( t2, binop( Iop_And32,
9257 binop(Iop_Shr32, getXMMRegLane32(src,2), mkU8(29)),
9258 mkU32(4) ));
9259 assign( t3, binop( Iop_And32,
9260 binop(Iop_Shr32, getXMMRegLane32(src,3), mkU8(28)),
9261 mkU32(8) ));
9262 putIReg32( gregOfRexRM(pfx,modrm),
9263 binop(Iop_Or32,
9264 binop(Iop_Or32, mkexpr(t0), mkexpr(t1)),
9265 binop(Iop_Or32, mkexpr(t2), mkexpr(t3))
9266 )
9267 );
9268 DIP("movmskps %s,%s\n", nameXMMReg(src),
9269 nameIReg32(gregOfRexRM(pfx,modrm)));
9270 goto decode_success;
9271 }
9272 /* else fall through */
9273 }
9274
sewardj612be432005-05-11 02:55:54 +00009275 /* 66 0F 2B = MOVNTPD -- for us, just a plain SSE store. */
sewardja7ba8c42005-05-10 20:08:34 +00009276 /* 0F 2B = MOVNTPS -- for us, just a plain SSE store. */
sewardj612be432005-05-11 02:55:54 +00009277 if ( ( (haveNo66noF2noF3(pfx) && sz == 4)
9278 || (have66noF2noF3(pfx) && sz == 2)
9279 )
9280 && insn[0] == 0x0F && insn[1] == 0x2B) {
sewardja7ba8c42005-05-10 20:08:34 +00009281 modrm = getUChar(delta+2);
9282 if (!epartIsReg(modrm)) {
9283 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9284 storeLE( mkexpr(addr), getXMMReg(gregOfRexRM(pfx,modrm)) );
sewardj612be432005-05-11 02:55:54 +00009285 DIP("movntp%s %s,%s\n", sz==2 ? "d" : "s",
9286 dis_buf,
9287 nameXMMReg(gregOfRexRM(pfx,modrm)));
sewardja7ba8c42005-05-10 20:08:34 +00009288 delta += 2+alen;
9289 goto decode_success;
9290 }
9291 /* else fall through */
9292 }
9293
9294 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9295 /* 0F E7 = MOVNTQ -- for us, just a plain MMX store. Note, the
9296 Intel manual does not say anything about the usual business of
9297 the FP reg tags getting trashed whenever an MMX insn happens.
9298 So we just leave them alone.
9299 */
9300 if (haveNo66noF2noF3(pfx) && sz == 4
9301 && insn[0] == 0x0F && insn[1] == 0xE7) {
9302 modrm = getUChar(delta+2);
9303 if (!epartIsReg(modrm)) {
9304 /* do_MMX_preamble(); Intel docs don't specify this */
9305 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9306 storeLE( mkexpr(addr), getMMXReg(gregLO3ofRM(modrm)) );
9307 DIP("movntq %s,%s\n", dis_buf,
9308 nameMMXReg(gregLO3ofRM(modrm)));
9309 delta += 2+alen;
9310 goto decode_success;
9311 }
9312 /* else fall through */
9313 }
sewardj8d965312005-02-25 02:48:47 +00009314
9315 /* F3 0F 10 = MOVSS -- move 32 bits from E (mem or lo 1/4 xmm) to G
9316 (lo 1/4 xmm). If E is mem, upper 3/4 of G is zeroed out. */
sewardjb4bf5882007-11-06 20:39:17 +00009317 if (haveF3no66noF2(pfx)
9318 && (sz == 4|| /* ignore redundant REX.W */ sz == 8)
sewardj8d965312005-02-25 02:48:47 +00009319 && insn[0] == 0x0F && insn[1] == 0x10) {
9320 modrm = getUChar(delta+2);
9321 if (epartIsReg(modrm)) {
9322 putXMMRegLane32( gregOfRexRM(pfx,modrm), 0,
9323 getXMMRegLane32( eregOfRexRM(pfx,modrm), 0 ));
9324 DIP("movss %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
9325 nameXMMReg(gregOfRexRM(pfx,modrm)));
9326 delta += 2+1;
9327 } else {
9328 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9329 putXMMReg( gregOfRexRM(pfx,modrm), mkV128(0) );
9330 putXMMRegLane32( gregOfRexRM(pfx,modrm), 0,
9331 loadLE(Ity_I32, mkexpr(addr)) );
9332 DIP("movss %s,%s\n", dis_buf,
9333 nameXMMReg(gregOfRexRM(pfx,modrm)));
9334 delta += 2+alen;
9335 }
9336 goto decode_success;
9337 }
9338
9339 /* F3 0F 11 = MOVSS -- move 32 bits from G (lo 1/4 xmm) to E (mem
9340 or lo 1/4 xmm). */
9341 if (haveF3no66noF2(pfx) && sz == 4
9342 && insn[0] == 0x0F && insn[1] == 0x11) {
9343 modrm = getUChar(delta+2);
9344 if (epartIsReg(modrm)) {
9345 /* fall through, we don't yet have a test case */
9346 } else {
9347 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9348 storeLE( mkexpr(addr),
9349 getXMMRegLane32(gregOfRexRM(pfx,modrm), 0) );
9350 DIP("movss %s,%s\n", nameXMMReg(gregOfRexRM(pfx,modrm)),
9351 dis_buf);
9352 delta += 2+alen;
9353 goto decode_success;
9354 }
9355 }
9356
sewardj432f8b62005-05-10 02:50:05 +00009357 /* 0F 59 = MULPS -- mul 32Fx4 from R/M to R */
9358 if (haveNo66noF2noF3(pfx) && sz == 4
9359 && insn[0] == 0x0F && insn[1] == 0x59) {
9360 delta = dis_SSE_E_to_G_all( pfx, delta+2, "mulps", Iop_Mul32Fx4 );
9361 goto decode_success;
9362 }
sewardj8d965312005-02-25 02:48:47 +00009363
9364 /* F3 0F 59 = MULSS -- mul 32F0x4 from R/M to R */
9365 if (haveF3no66noF2(pfx) && sz == 4
9366 && insn[0] == 0x0F && insn[1] == 0x59) {
9367 delta = dis_SSE_E_to_G_lo32( pfx, delta+2, "mulss", Iop_Mul32F0x4 );
9368 goto decode_success;
9369 }
9370
sewardj3aba9eb2005-03-30 23:20:47 +00009371 /* 0F 56 = ORPS -- G = G and E */
9372 if (haveNo66noF2noF3(pfx) && sz == 4
9373 && insn[0] == 0x0F && insn[1] == 0x56) {
9374 delta = dis_SSE_E_to_G_all( pfx, delta+2, "orps", Iop_OrV128 );
9375 goto decode_success;
9376 }
9377
sewardja7ba8c42005-05-10 20:08:34 +00009378 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9379 /* 0F E0 = PAVGB -- 8x8 unsigned Packed Average, with rounding */
9380 if (haveNo66noF2noF3(pfx) && sz == 4
9381 && insn[0] == 0x0F && insn[1] == 0xE0) {
9382 do_MMX_preamble();
9383 delta = dis_MMXop_regmem_to_reg (
9384 pfx, delta+2, insn[1], "pavgb", False );
9385 goto decode_success;
9386 }
9387
9388 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9389 /* 0F E3 = PAVGW -- 16x4 unsigned Packed Average, with rounding */
9390 if (haveNo66noF2noF3(pfx) && sz == 4
9391 && insn[0] == 0x0F && insn[1] == 0xE3) {
9392 do_MMX_preamble();
9393 delta = dis_MMXop_regmem_to_reg (
9394 pfx, delta+2, insn[1], "pavgw", False );
9395 goto decode_success;
9396 }
9397
9398 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9399 /* 0F C5 = PEXTRW -- extract 16-bit field from mmx(E) and put
9400 zero-extend of it in ireg(G). */
sewardj9e234f62006-09-11 14:37:27 +00009401 if (haveNo66noF2noF3(pfx) && (sz == 4 || sz == 8)
sewardja7ba8c42005-05-10 20:08:34 +00009402 && insn[0] == 0x0F && insn[1] == 0xC5) {
9403 modrm = insn[2];
9404 if (epartIsReg(modrm)) {
9405 IRTemp sV = newTemp(Ity_I64);
9406 t5 = newTemp(Ity_I16);
9407 do_MMX_preamble();
9408 assign(sV, getMMXReg(eregLO3ofRM(modrm)));
9409 breakup64to16s( sV, &t3, &t2, &t1, &t0 );
9410 switch (insn[3] & 3) {
9411 case 0: assign(t5, mkexpr(t0)); break;
9412 case 1: assign(t5, mkexpr(t1)); break;
9413 case 2: assign(t5, mkexpr(t2)); break;
9414 case 3: assign(t5, mkexpr(t3)); break;
9415 default: vassert(0);
9416 }
sewardj9e234f62006-09-11 14:37:27 +00009417 if (sz == 8)
9418 putIReg64(gregOfRexRM(pfx,modrm), unop(Iop_16Uto64, mkexpr(t5)));
9419 else
9420 putIReg32(gregOfRexRM(pfx,modrm), unop(Iop_16Uto32, mkexpr(t5)));
sewardja7ba8c42005-05-10 20:08:34 +00009421 DIP("pextrw $%d,%s,%s\n",
9422 (Int)insn[3], nameMMXReg(eregLO3ofRM(modrm)),
sewardj9e234f62006-09-11 14:37:27 +00009423 sz==8 ? nameIReg64(gregOfRexRM(pfx,modrm))
9424 : nameIReg32(gregOfRexRM(pfx,modrm))
9425 );
sewardja7ba8c42005-05-10 20:08:34 +00009426 delta += 4;
9427 goto decode_success;
9428 }
9429 /* else fall through */
9430 /* note, for anyone filling in the mem case: this insn has one
9431 byte after the amode and therefore you must pass 1 as the
9432 last arg to disAMode */
9433 }
9434
9435 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9436 /* 0F C4 = PINSRW -- get 16 bits from E(mem or low half ireg) and
9437 put it into the specified lane of mmx(G). */
9438 if (haveNo66noF2noF3(pfx) && sz == 4
9439 && insn[0] == 0x0F && insn[1] == 0xC4) {
9440 /* Use t0 .. t3 to hold the 4 original 16-bit lanes of the
9441 mmx reg. t4 is the new lane value. t5 is the original
9442 mmx value. t6 is the new mmx value. */
9443 Int lane;
9444 t4 = newTemp(Ity_I16);
9445 t5 = newTemp(Ity_I64);
9446 t6 = newTemp(Ity_I64);
9447 modrm = insn[2];
9448 do_MMX_preamble();
9449
9450 assign(t5, getMMXReg(gregLO3ofRM(modrm)));
9451 breakup64to16s( t5, &t3, &t2, &t1, &t0 );
9452
9453 if (epartIsReg(modrm)) {
9454 assign(t4, getIReg16(eregOfRexRM(pfx,modrm)));
9455 delta += 3+1;
9456 lane = insn[3+1-1];
9457 DIP("pinsrw $%d,%s,%s\n", (Int)lane,
9458 nameIReg16(eregOfRexRM(pfx,modrm)),
9459 nameMMXReg(gregLO3ofRM(modrm)));
9460 } else {
9461 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 1 );
9462 delta += 3+alen;
9463 lane = insn[3+alen-1];
9464 assign(t4, loadLE(Ity_I16, mkexpr(addr)));
9465 DIP("pinsrw $%d,%s,%s\n", (Int)lane,
9466 dis_buf,
9467 nameMMXReg(gregLO3ofRM(modrm)));
9468 }
9469
9470 switch (lane & 3) {
9471 case 0: assign(t6, mk64from16s(t3,t2,t1,t4)); break;
9472 case 1: assign(t6, mk64from16s(t3,t2,t4,t0)); break;
9473 case 2: assign(t6, mk64from16s(t3,t4,t1,t0)); break;
9474 case 3: assign(t6, mk64from16s(t4,t2,t1,t0)); break;
9475 default: vassert(0);
9476 }
9477 putMMXReg(gregLO3ofRM(modrm), mkexpr(t6));
9478 goto decode_success;
9479 }
9480
9481 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9482 /* 0F EE = PMAXSW -- 16x4 signed max */
9483 if (haveNo66noF2noF3(pfx) && sz == 4
9484 && insn[0] == 0x0F && insn[1] == 0xEE) {
9485 do_MMX_preamble();
9486 delta = dis_MMXop_regmem_to_reg (
9487 pfx, delta+2, insn[1], "pmaxsw", False );
9488 goto decode_success;
9489 }
9490
9491 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9492 /* 0F DE = PMAXUB -- 8x8 unsigned max */
9493 if (haveNo66noF2noF3(pfx) && sz == 4
9494 && insn[0] == 0x0F && insn[1] == 0xDE) {
9495 do_MMX_preamble();
9496 delta = dis_MMXop_regmem_to_reg (
9497 pfx, delta+2, insn[1], "pmaxub", False );
9498 goto decode_success;
9499 }
9500
9501 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9502 /* 0F EA = PMINSW -- 16x4 signed min */
9503 if (haveNo66noF2noF3(pfx) && sz == 4
9504 && insn[0] == 0x0F && insn[1] == 0xEA) {
9505 do_MMX_preamble();
9506 delta = dis_MMXop_regmem_to_reg (
9507 pfx, delta+2, insn[1], "pminsw", False );
9508 goto decode_success;
9509 }
9510
9511 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9512 /* 0F DA = PMINUB -- 8x8 unsigned min */
9513 if (haveNo66noF2noF3(pfx) && sz == 4
9514 && insn[0] == 0x0F && insn[1] == 0xDA) {
9515 do_MMX_preamble();
9516 delta = dis_MMXop_regmem_to_reg (
9517 pfx, delta+2, insn[1], "pminub", False );
9518 goto decode_success;
9519 }
9520
9521 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9522 /* 0F D7 = PMOVMSKB -- extract sign bits from each of 8 lanes in
9523 mmx(G), turn them into a byte, and put zero-extend of it in
9524 ireg(G). */
9525 if (haveNo66noF2noF3(pfx) && sz == 4
9526 && insn[0] == 0x0F && insn[1] == 0xD7) {
9527 modrm = insn[2];
9528 if (epartIsReg(modrm)) {
9529 do_MMX_preamble();
9530 t0 = newTemp(Ity_I64);
9531 t1 = newTemp(Ity_I64);
9532 assign(t0, getMMXReg(eregLO3ofRM(modrm)));
9533 assign(t1, mkIRExprCCall(
9534 Ity_I64, 0/*regparms*/,
9535 "amd64g_calculate_mmx_pmovmskb",
9536 &amd64g_calculate_mmx_pmovmskb,
9537 mkIRExprVec_1(mkexpr(t0))));
9538 putIReg32(gregOfRexRM(pfx,modrm), unop(Iop_64to32,mkexpr(t1)));
9539 DIP("pmovmskb %s,%s\n", nameMMXReg(eregLO3ofRM(modrm)),
9540 nameIReg32(gregOfRexRM(pfx,modrm)));
9541 delta += 3;
9542 goto decode_success;
9543 }
9544 /* else fall through */
9545 }
9546
9547 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9548 /* 0F E4 = PMULUH -- 16x4 hi-half of unsigned widening multiply */
9549 if (haveNo66noF2noF3(pfx) && sz == 4
9550 && insn[0] == 0x0F && insn[1] == 0xE4) {
9551 do_MMX_preamble();
9552 delta = dis_MMXop_regmem_to_reg (
9553 pfx, delta+2, insn[1], "pmuluh", False );
9554 goto decode_success;
9555 }
sewardja6b93d12005-02-17 09:28:28 +00009556
9557 /* 0F 18 /0 = PREFETCHNTA -- prefetch into caches, */
9558 /* 0F 18 /1 = PREFETCH0 -- with various different hints */
9559 /* 0F 18 /2 = PREFETCH1 */
9560 /* 0F 18 /3 = PREFETCH2 */
9561 if (insn[0] == 0x0F && insn[1] == 0x18
sewardjbcbb9de2005-03-27 02:22:32 +00009562 && haveNo66noF2noF3(pfx)
sewardja6b93d12005-02-17 09:28:28 +00009563 && !epartIsReg(insn[2])
sewardj901ed122005-02-27 13:25:31 +00009564 && gregLO3ofRM(insn[2]) >= 0 && gregLO3ofRM(insn[2]) <= 3) {
sewardja6b93d12005-02-17 09:28:28 +00009565 HChar* hintstr = "??";
9566
9567 modrm = getUChar(delta+2);
9568 vassert(!epartIsReg(modrm));
9569
9570 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9571 delta += 2+alen;
9572
sewardj901ed122005-02-27 13:25:31 +00009573 switch (gregLO3ofRM(modrm)) {
sewardja6b93d12005-02-17 09:28:28 +00009574 case 0: hintstr = "nta"; break;
9575 case 1: hintstr = "t0"; break;
9576 case 2: hintstr = "t1"; break;
9577 case 3: hintstr = "t2"; break;
9578 default: vassert(0);
9579 }
9580
9581 DIP("prefetch%s %s\n", hintstr, dis_buf);
9582 goto decode_success;
9583 }
9584
sewardja7ba8c42005-05-10 20:08:34 +00009585 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9586 /* 0F F6 = PSADBW -- sum of 8Ux8 absolute differences */
9587 if (haveNo66noF2noF3(pfx) && sz == 4
9588 && insn[0] == 0x0F && insn[1] == 0xF6) {
9589 do_MMX_preamble();
9590 delta = dis_MMXop_regmem_to_reg (
9591 pfx, delta+2, insn[1], "psadbw", False );
9592 goto decode_success;
9593 }
9594
9595 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9596 /* 0F 70 = PSHUFW -- rearrange 4x16 from E(mmx or mem) to G(mmx) */
9597 if (haveNo66noF2noF3(pfx) && sz == 4
9598 && insn[0] == 0x0F && insn[1] == 0x70) {
9599 Int order;
9600 IRTemp sV, dV, s3, s2, s1, s0;
9601 s3 = s2 = s1 = s0 = IRTemp_INVALID;
9602 sV = newTemp(Ity_I64);
9603 dV = newTemp(Ity_I64);
9604 do_MMX_preamble();
9605 modrm = insn[2];
9606 if (epartIsReg(modrm)) {
9607 assign( sV, getMMXReg(eregLO3ofRM(modrm)) );
9608 order = (Int)insn[3];
9609 delta += 2+2;
9610 DIP("pshufw $%d,%s,%s\n", order,
9611 nameMMXReg(eregLO3ofRM(modrm)),
9612 nameMMXReg(gregLO3ofRM(modrm)));
9613 } else {
9614 addr = disAMode ( &alen, pfx, delta+2, dis_buf,
9615 1/*extra byte after amode*/ );
9616 assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
9617 order = (Int)insn[2+alen];
9618 delta += 3+alen;
9619 DIP("pshufw $%d,%s,%s\n", order,
9620 dis_buf,
9621 nameMMXReg(gregLO3ofRM(modrm)));
9622 }
9623 breakup64to16s( sV, &s3, &s2, &s1, &s0 );
9624# define SEL(n) \
9625 ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
9626 assign(dV,
9627 mk64from16s( SEL((order>>6)&3), SEL((order>>4)&3),
9628 SEL((order>>2)&3), SEL((order>>0)&3) )
9629 );
9630 putMMXReg(gregLO3ofRM(modrm), mkexpr(dV));
9631# undef SEL
9632 goto decode_success;
9633 }
9634
9635 /* 0F 53 = RCPPS -- approx reciprocal 32Fx4 from R/M to R */
9636 if (haveNo66noF2noF3(pfx) && sz == 4
9637 && insn[0] == 0x0F && insn[1] == 0x53) {
9638 delta = dis_SSE_E_to_G_unary_all( pfx, delta+2,
9639 "rcpps", Iop_Recip32Fx4 );
9640 goto decode_success;
9641 }
9642
9643 /* F3 0F 53 = RCPSS -- approx reciprocal 32F0x4 from R/M to R */
9644 if (haveF3no66noF2(pfx) && sz == 4
9645 && insn[0] == 0x0F && insn[1] == 0x53) {
9646 delta = dis_SSE_E_to_G_unary_lo32( pfx, delta+2,
9647 "rcpss", Iop_Recip32F0x4 );
9648 goto decode_success;
9649 }
9650
9651 /* 0F 52 = RSQRTPS -- approx reciprocal sqrt 32Fx4 from R/M to R */
9652 if (haveNo66noF2noF3(pfx) && sz == 4
9653 && insn[0] == 0x0F && insn[1] == 0x52) {
9654 delta = dis_SSE_E_to_G_unary_all( pfx, delta+2,
9655 "rsqrtps", Iop_RSqrt32Fx4 );
9656 goto decode_success;
9657 }
9658
9659 /* F3 0F 52 = RSQRTSS -- approx reciprocal sqrt 32F0x4 from R/M to R */
9660 if (haveF3no66noF2(pfx) && sz == 4
9661 && insn[0] == 0x0F && insn[1] == 0x52) {
9662 delta = dis_SSE_E_to_G_unary_lo32( pfx, delta+2,
9663 "rsqrtss", Iop_RSqrt32F0x4 );
9664 goto decode_success;
9665 }
sewardjf53b7352005-04-06 20:01:56 +00009666
9667 /* 0F AE /7 = SFENCE -- flush pending operations to memory */
9668 if (haveNo66noF2noF3(pfx)
9669 && insn[0] == 0x0F && insn[1] == 0xAE
9670 && epartIsReg(insn[2]) && gregLO3ofRM(insn[2]) == 7
9671 && sz == 4) {
9672 delta += 3;
9673 /* Insert a memory fence. It's sometimes important that these
9674 are carried through to the generated code. */
sewardjc4356f02007-11-09 21:15:04 +00009675 stmt( IRStmt_MBE(Imbe_Fence) );
sewardjf53b7352005-04-06 20:01:56 +00009676 DIP("sfence\n");
9677 goto decode_success;
9678 }
9679
sewardja7ba8c42005-05-10 20:08:34 +00009680 /* 0F C6 /r ib = SHUFPS -- shuffle packed F32s */
9681 if (haveNo66noF2noF3(pfx) && sz == 4
9682 && insn[0] == 0x0F && insn[1] == 0xC6) {
9683 Int select;
9684 IRTemp sV, dV;
9685 IRTemp s3, s2, s1, s0, d3, d2, d1, d0;
9686 sV = newTemp(Ity_V128);
9687 dV = newTemp(Ity_V128);
9688 s3 = s2 = s1 = s0 = d3 = d2 = d1 = d0 = IRTemp_INVALID;
9689 modrm = insn[2];
9690 assign( dV, getXMMReg(gregOfRexRM(pfx,modrm)) );
9691
9692 if (epartIsReg(modrm)) {
9693 assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
9694 select = (Int)insn[3];
9695 delta += 2+2;
9696 DIP("shufps $%d,%s,%s\n", select,
9697 nameXMMReg(eregOfRexRM(pfx,modrm)),
9698 nameXMMReg(gregOfRexRM(pfx,modrm)));
9699 } else {
9700 addr = disAMode ( &alen, pfx, delta+2, dis_buf,
9701 1/*byte at end of insn*/ );
9702 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
9703 select = (Int)insn[2+alen];
9704 delta += 3+alen;
9705 DIP("shufps $%d,%s,%s\n", select,
9706 dis_buf,
9707 nameXMMReg(gregOfRexRM(pfx,modrm)));
9708 }
9709
9710 breakup128to32s( dV, &d3, &d2, &d1, &d0 );
9711 breakup128to32s( sV, &s3, &s2, &s1, &s0 );
9712
9713# define SELD(n) ((n)==0 ? d0 : ((n)==1 ? d1 : ((n)==2 ? d2 : d3)))
9714# define SELS(n) ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
9715
9716 putXMMReg(
9717 gregOfRexRM(pfx,modrm),
9718 mk128from32s( SELS((select>>6)&3), SELS((select>>4)&3),
9719 SELD((select>>2)&3), SELD((select>>0)&3) )
9720 );
9721
9722# undef SELD
9723# undef SELS
9724
9725 goto decode_success;
9726 }
9727
9728 /* 0F 51 = SQRTPS -- approx sqrt 32Fx4 from R/M to R */
9729 if (haveNo66noF2noF3(pfx) && sz == 4
9730 && insn[0] == 0x0F && insn[1] == 0x51) {
9731 delta = dis_SSE_E_to_G_unary_all( pfx, delta+2,
9732 "sqrtps", Iop_Sqrt32Fx4 );
9733 goto decode_success;
9734 }
9735
9736 /* F3 0F 51 = SQRTSS -- approx sqrt 32F0x4 from R/M to R */
9737 if (haveF3no66noF2(pfx) && sz == 4
9738 && insn[0] == 0x0F && insn[1] == 0x51) {
9739 delta = dis_SSE_E_to_G_unary_lo32( pfx, delta+2,
9740 "sqrtss", Iop_Sqrt32F0x4 );
9741 goto decode_success;
9742 }
sewardjbcbb9de2005-03-27 02:22:32 +00009743
9744 /* 0F AE /3 = STMXCSR m32 -- store %mxcsr */
9745 if (insn[0] == 0x0F && insn[1] == 0xAE
9746 && haveNo66noF2noF3(pfx)
9747 && !epartIsReg(insn[2]) && gregLO3ofRM(insn[2]) == 3) {
9748
9749 vassert(sz == 4);
9750 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9751 delta += 2+alen;
9752
9753 /* Fake up a native SSE mxcsr word. The only thing it depends
9754 on is SSEROUND[1:0], so call a clean helper to cook it up.
9755 */
9756 /* ULong amd64h_create_mxcsr ( ULong sseround ) */
9757 DIP("stmxcsr %s\n", dis_buf);
9758 storeLE(
9759 mkexpr(addr),
9760 unop(Iop_64to32,
9761 mkIRExprCCall(
9762 Ity_I64, 0/*regp*/,
9763 "amd64g_create_mxcsr", &amd64g_create_mxcsr,
9764 mkIRExprVec_1( unop(Iop_32Uto64,get_sse_roundingmode()) )
9765 )
9766 )
9767 );
9768 goto decode_success;
9769 }
9770
sewardj432f8b62005-05-10 02:50:05 +00009771 /* 0F 5C = SUBPS -- sub 32Fx4 from R/M to R */
9772 if (haveNo66noF2noF3(pfx) && sz == 4
9773 && insn[0] == 0x0F && insn[1] == 0x5C) {
9774 delta = dis_SSE_E_to_G_all( pfx, delta+2, "subps", Iop_Sub32Fx4 );
9775 goto decode_success;
9776 }
sewardj8d965312005-02-25 02:48:47 +00009777
9778 /* F3 0F 5C = SUBSS -- sub 32F0x4 from R/M to R */
9779 if (haveF3no66noF2(pfx) && sz == 4
9780 && insn[0] == 0x0F && insn[1] == 0x5C) {
9781 delta = dis_SSE_E_to_G_lo32( pfx, delta+2, "subss", Iop_Sub32F0x4 );
9782 goto decode_success;
9783 }
9784
sewardja7ba8c42005-05-10 20:08:34 +00009785 /* 0F 15 = UNPCKHPS -- unpack and interleave high part F32s */
9786 /* 0F 14 = UNPCKLPS -- unpack and interleave low part F32s */
9787 /* These just appear to be special cases of SHUFPS */
9788 if (haveNo66noF2noF3(pfx) && sz == 4
9789 && insn[0] == 0x0F && (insn[1] == 0x15 || insn[1] == 0x14)) {
9790 IRTemp sV, dV;
9791 IRTemp s3, s2, s1, s0, d3, d2, d1, d0;
sewardjca673ab2005-05-11 10:03:08 +00009792 Bool hi = toBool(insn[1] == 0x15);
sewardja7ba8c42005-05-10 20:08:34 +00009793 sV = newTemp(Ity_V128);
9794 dV = newTemp(Ity_V128);
9795 s3 = s2 = s1 = s0 = d3 = d2 = d1 = d0 = IRTemp_INVALID;
9796 modrm = insn[2];
9797 assign( dV, getXMMReg(gregOfRexRM(pfx,modrm)) );
9798
9799 if (epartIsReg(modrm)) {
9800 assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
9801 delta += 2+1;
9802 DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
9803 nameXMMReg(eregOfRexRM(pfx,modrm)),
9804 nameXMMReg(gregOfRexRM(pfx,modrm)));
9805 } else {
9806 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9807 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
9808 delta += 2+alen;
9809 DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
9810 dis_buf,
9811 nameXMMReg(gregOfRexRM(pfx,modrm)));
9812 }
9813
9814 breakup128to32s( dV, &d3, &d2, &d1, &d0 );
9815 breakup128to32s( sV, &s3, &s2, &s1, &s0 );
9816
9817 if (hi) {
9818 putXMMReg( gregOfRexRM(pfx,modrm), mk128from32s( s3, d3, s2, d2 ) );
9819 } else {
9820 putXMMReg( gregOfRexRM(pfx,modrm), mk128from32s( s1, d1, s0, d0 ) );
9821 }
9822
9823 goto decode_success;
9824 }
sewardj8d965312005-02-25 02:48:47 +00009825
9826 /* 0F 57 = XORPS -- G = G and E */
9827 if (haveNo66noF2noF3(pfx) && sz == 4
9828 && insn[0] == 0x0F && insn[1] == 0x57) {
9829 delta = dis_SSE_E_to_G_all( pfx, delta+2, "xorps", Iop_XorV128 );
9830 goto decode_success;
9831 }
9832
sewardj5992bd02005-05-11 02:13:42 +00009833 /* ---------------------------------------------------- */
9834 /* --- end of the SSE decoder. --- */
9835 /* ---------------------------------------------------- */
9836
9837 /* ---------------------------------------------------- */
9838 /* --- start of the SSE2 decoder. --- */
9839 /* ---------------------------------------------------- */
sewardj4c328cf2005-05-05 12:05:54 +00009840
9841 /* 66 0F 58 = ADDPD -- add 32Fx4 from R/M to R */
sewardjb4bf5882007-11-06 20:39:17 +00009842 if (have66noF2noF3(pfx)
9843 && (sz == 2 || /* ignore redundant REX.W */ sz == 8)
sewardj4c328cf2005-05-05 12:05:54 +00009844 && insn[0] == 0x0F && insn[1] == 0x58) {
9845 delta = dis_SSE_E_to_G_all( pfx, delta+2, "addpd", Iop_Add64Fx2 );
9846 goto decode_success;
9847 }
sewardj1001dc42005-02-21 08:25:55 +00009848
9849 /* F2 0F 58 = ADDSD -- add 64F0x2 from R/M to R */
sewardjb4bf5882007-11-06 20:39:17 +00009850 if (haveF2no66noF3(pfx)
9851 && (sz == 4 || /* ignore redundant REX.W */ sz == 8)
9852 && insn[0] == 0x0F && insn[1] == 0x58) {
sewardj1001dc42005-02-21 08:25:55 +00009853 delta = dis_SSE_E_to_G_lo64( pfx, delta+2, "addsd", Iop_Add64F0x2 );
9854 goto decode_success;
9855 }
9856
sewardj8d965312005-02-25 02:48:47 +00009857 /* 66 0F 55 = ANDNPD -- G = (not G) and E */
9858 if (have66noF2noF3(pfx) && sz == 2
9859 && insn[0] == 0x0F && insn[1] == 0x55) {
9860 delta = dis_SSE_E_to_G_all_invG( pfx, delta+2, "andnpd", Iop_AndV128 );
9861 goto decode_success;
9862 }
sewardj1a01e652005-02-23 11:39:21 +00009863
9864 /* 66 0F 54 = ANDPD -- G = G and E */
9865 if (have66noF2noF3(pfx) && sz == 2
9866 && insn[0] == 0x0F && insn[1] == 0x54) {
9867 delta = dis_SSE_E_to_G_all( pfx, delta+2, "andpd", Iop_AndV128 );
9868 goto decode_success;
9869 }
9870
sewardj97628592005-05-10 22:42:54 +00009871 /* 66 0F C2 = CMPPD -- 64Fx2 comparison from R/M to R */
9872 if (have66noF2noF3(pfx) && sz == 2
9873 && insn[0] == 0x0F && insn[1] == 0xC2) {
9874 delta = dis_SSEcmp_E_to_G( pfx, delta+2, "cmppd", True, 8 );
9875 goto decode_success;
9876 }
sewardj8d965312005-02-25 02:48:47 +00009877
9878 /* F2 0F C2 = CMPSD -- 64F0x2 comparison from R/M to R */
9879 if (haveF2no66noF3(pfx) && sz == 4
9880 && insn[0] == 0x0F && insn[1] == 0xC2) {
9881 delta = dis_SSEcmp_E_to_G( pfx, delta+2, "cmpsd", False, 8 );
9882 goto decode_success;
9883 }
sewardj18303862005-02-21 12:36:54 +00009884
9885 /* 66 0F 2F = COMISD -- 64F0x2 comparison G,E, and set ZCP */
9886 /* 66 0F 2E = UCOMISD -- 64F0x2 comparison G,E, and set ZCP */
sewardjc49ce232005-02-25 13:03:03 +00009887 if (have66noF2noF3(pfx) && sz == 2
sewardj18303862005-02-21 12:36:54 +00009888 && insn[0] == 0x0F && (insn[1] == 0x2F || insn[1] == 0x2E)) {
9889 IRTemp argL = newTemp(Ity_F64);
9890 IRTemp argR = newTemp(Ity_F64);
9891 modrm = getUChar(delta+2);
9892 if (epartIsReg(modrm)) {
9893 assign( argR, getXMMRegLane64F( eregOfRexRM(pfx,modrm),
9894 0/*lowest lane*/ ) );
9895 delta += 2+1;
9896 DIP("%scomisd %s,%s\n", insn[1]==0x2E ? "u" : "",
9897 nameXMMReg(eregOfRexRM(pfx,modrm)),
9898 nameXMMReg(gregOfRexRM(pfx,modrm)) );
9899 } else {
9900 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9901 assign( argR, loadLE(Ity_F64, mkexpr(addr)) );
9902 delta += 2+alen;
9903 DIP("%scomisd %s,%s\n", insn[1]==0x2E ? "u" : "",
9904 dis_buf,
9905 nameXMMReg(gregOfRexRM(pfx,modrm)) );
9906 }
9907 assign( argL, getXMMRegLane64F( gregOfRexRM(pfx,modrm),
9908 0/*lowest lane*/ ) );
9909
9910 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(AMD64G_CC_OP_COPY) ));
9911 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
9912 stmt( IRStmt_Put(
9913 OFFB_CC_DEP1,
9914 binop( Iop_And64,
9915 unop( Iop_32Uto64,
9916 binop(Iop_CmpF64, mkexpr(argL), mkexpr(argR)) ),
9917 mkU64(0x45)
9918 )));
9919
9920 goto decode_success;
9921 }
9922
sewardj09717342005-05-05 21:34:02 +00009923 /* F3 0F E6 = CVTDQ2PD -- convert 2 x I32 in mem/lo half xmm to 2 x
9924 F64 in xmm(G) */
9925 if (haveF3no66noF2(pfx) && insn[0] == 0x0F && insn[1] == 0xE6) {
9926 IRTemp arg64 = newTemp(Ity_I64);
9927 if (sz != 4) goto decode_failure;
9928
9929 modrm = getUChar(delta+2);
9930 if (epartIsReg(modrm)) {
9931 assign( arg64, getXMMRegLane64(eregOfRexRM(pfx,modrm), 0) );
9932 delta += 2+1;
9933 DIP("cvtdq2pd %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
9934 nameXMMReg(gregOfRexRM(pfx,modrm)));
9935 } else {
9936 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9937 assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
9938 delta += 2+alen;
9939 DIP("cvtdq2pd %s,%s\n", dis_buf,
9940 nameXMMReg(gregOfRexRM(pfx,modrm)) );
9941 }
9942
9943 putXMMRegLane64F(
9944 gregOfRexRM(pfx,modrm), 0,
9945 unop(Iop_I32toF64, unop(Iop_64to32, mkexpr(arg64)))
9946 );
9947
9948 putXMMRegLane64F(
9949 gregOfRexRM(pfx,modrm), 1,
9950 unop(Iop_I32toF64, unop(Iop_64HIto32, mkexpr(arg64)))
9951 );
9952
9953 goto decode_success;
9954 }
9955
sewardj5992bd02005-05-11 02:13:42 +00009956 /* 0F 5B = CVTDQ2PS -- convert 4 x I32 in mem/xmm to 4 x F32 in
9957 xmm(G) */
9958 if (haveNo66noF2noF3(pfx) && sz == 4
9959 && insn[0] == 0x0F && insn[1] == 0x5B) {
sewardj09717342005-05-05 21:34:02 +00009960 IRTemp argV = newTemp(Ity_V128);
9961 IRTemp rmode = newTemp(Ity_I32);
sewardj09717342005-05-05 21:34:02 +00009962
9963 modrm = getUChar(delta+2);
9964 if (epartIsReg(modrm)) {
9965 assign( argV, getXMMReg(eregOfRexRM(pfx,modrm)) );
9966 delta += 2+1;
sewardj5992bd02005-05-11 02:13:42 +00009967 DIP("cvtdq2ps %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
sewardj09717342005-05-05 21:34:02 +00009968 nameXMMReg(gregOfRexRM(pfx,modrm)));
9969 } else {
9970 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
sewardj5992bd02005-05-11 02:13:42 +00009971 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
sewardj09717342005-05-05 21:34:02 +00009972 delta += 2+alen;
sewardj5992bd02005-05-11 02:13:42 +00009973 DIP("cvtdq2ps %s,%s\n", dis_buf,
sewardj09717342005-05-05 21:34:02 +00009974 nameXMMReg(gregOfRexRM(pfx,modrm)) );
9975 }
9976
9977 assign( rmode, get_sse_roundingmode() );
sewardj5992bd02005-05-11 02:13:42 +00009978 breakup128to32s( argV, &t3, &t2, &t1, &t0 );
9979
9980# define CVT(_t) binop( Iop_F64toF32, \
9981 mkexpr(rmode), \
9982 unop(Iop_I32toF64,mkexpr(_t)))
9983
9984 putXMMRegLane32F( gregOfRexRM(pfx,modrm), 3, CVT(t3) );
9985 putXMMRegLane32F( gregOfRexRM(pfx,modrm), 2, CVT(t2) );
9986 putXMMRegLane32F( gregOfRexRM(pfx,modrm), 1, CVT(t1) );
9987 putXMMRegLane32F( gregOfRexRM(pfx,modrm), 0, CVT(t0) );
9988
9989# undef CVT
9990
9991 goto decode_success;
9992 }
9993
9994 /* 66 0F E6 = CVTTPD2DQ -- convert 2 x F64 in mem/xmm to 2 x I32 in
9995 lo half xmm(G), and zero upper half, rounding towards zero */
9996 /* F2 0F E6 = CVTPD2DQ -- convert 2 x F64 in mem/xmm to 2 x I32 in
9997 lo half xmm(G), according to prevailing rounding mode, and zero
9998 upper half */
9999 if ( ( (haveF2no66noF3(pfx) && sz == 4)
10000 || (have66noF2noF3(pfx) && sz == 2)
10001 )
10002 && insn[0] == 0x0F && insn[1] == 0xE6) {
10003 IRTemp argV = newTemp(Ity_V128);
10004 IRTemp rmode = newTemp(Ity_I32);
10005 Bool r2zero = toBool(sz == 2);
10006
10007 modrm = getUChar(delta+2);
10008 if (epartIsReg(modrm)) {
10009 assign( argV, getXMMReg(eregOfRexRM(pfx,modrm)) );
10010 delta += 2+1;
10011 DIP("cvt%spd2dq %s,%s\n", r2zero ? "t" : "",
10012 nameXMMReg(eregOfRexRM(pfx,modrm)),
10013 nameXMMReg(gregOfRexRM(pfx,modrm)));
10014 } else {
10015 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10016 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
10017 delta += 2+alen;
10018 DIP("cvt%spd2dq %s,%s\n", r2zero ? "t" : "",
10019 dis_buf,
10020 nameXMMReg(gregOfRexRM(pfx,modrm)) );
10021 }
10022
10023 if (r2zero) {
10024 assign(rmode, mkU32((UInt)Irrm_ZERO) );
10025 } else {
10026 assign( rmode, get_sse_roundingmode() );
10027 }
10028
sewardj09717342005-05-05 21:34:02 +000010029 t0 = newTemp(Ity_F64);
10030 t1 = newTemp(Ity_F64);
10031 assign( t0, unop(Iop_ReinterpI64asF64,
10032 unop(Iop_V128to64, mkexpr(argV))) );
10033 assign( t1, unop(Iop_ReinterpI64asF64,
10034 unop(Iop_V128HIto64, mkexpr(argV))) );
10035
10036# define CVT(_t) binop( Iop_F64toI32, \
10037 mkexpr(rmode), \
10038 mkexpr(_t) )
10039
10040 putXMMRegLane32( gregOfRexRM(pfx,modrm), 3, mkU32(0) );
10041 putXMMRegLane32( gregOfRexRM(pfx,modrm), 2, mkU32(0) );
10042 putXMMRegLane32( gregOfRexRM(pfx,modrm), 1, CVT(t1) );
10043 putXMMRegLane32( gregOfRexRM(pfx,modrm), 0, CVT(t0) );
10044
10045# undef CVT
10046
10047 goto decode_success;
10048 }
10049
sewardj5992bd02005-05-11 02:13:42 +000010050 /* 66 0F 2D = CVTPD2PI -- convert 2 x F64 in mem/xmm to 2 x
10051 I32 in mmx, according to prevailing SSE rounding mode */
10052 /* 66 0F 2C = CVTTPD2PI -- convert 2 x F64 in mem/xmm to 2 x
10053 I32 in mmx, rounding towards zero */
10054 if (have66noF2noF3(pfx) && sz == 2
10055 && insn[0] == 0x0F && (insn[1] == 0x2D || insn[1] == 0x2C)) {
10056 IRTemp dst64 = newTemp(Ity_I64);
10057 IRTemp rmode = newTemp(Ity_I32);
10058 IRTemp f64lo = newTemp(Ity_F64);
10059 IRTemp f64hi = newTemp(Ity_F64);
sewardjca673ab2005-05-11 10:03:08 +000010060 Bool r2zero = toBool(insn[1] == 0x2C);
sewardj5992bd02005-05-11 02:13:42 +000010061
10062 do_MMX_preamble();
10063 modrm = getUChar(delta+2);
10064
10065 if (epartIsReg(modrm)) {
10066 delta += 2+1;
10067 assign(f64lo, getXMMRegLane64F(eregOfRexRM(pfx,modrm), 0));
10068 assign(f64hi, getXMMRegLane64F(eregOfRexRM(pfx,modrm), 1));
10069 DIP("cvt%spd2pi %s,%s\n", r2zero ? "t" : "",
10070 nameXMMReg(eregOfRexRM(pfx,modrm)),
10071 nameMMXReg(gregLO3ofRM(modrm)));
10072 } else {
10073 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10074 assign(f64lo, loadLE(Ity_F64, mkexpr(addr)));
10075 assign(f64hi, loadLE(Ity_F64, binop( Iop_Add64,
10076 mkexpr(addr),
10077 mkU64(8) )));
10078 delta += 2+alen;
10079 DIP("cvt%spf2pi %s,%s\n", r2zero ? "t" : "",
10080 dis_buf,
10081 nameMMXReg(gregLO3ofRM(modrm)));
10082 }
10083
10084 if (r2zero) {
10085 assign(rmode, mkU32((UInt)Irrm_ZERO) );
10086 } else {
10087 assign( rmode, get_sse_roundingmode() );
10088 }
10089
10090 assign(
10091 dst64,
10092 binop( Iop_32HLto64,
10093 binop( Iop_F64toI32, mkexpr(rmode), mkexpr(f64hi) ),
10094 binop( Iop_F64toI32, mkexpr(rmode), mkexpr(f64lo) )
10095 )
10096 );
10097
10098 putMMXReg(gregLO3ofRM(modrm), mkexpr(dst64));
10099 goto decode_success;
10100 }
10101
10102 /* 66 0F 5A = CVTPD2PS -- convert 2 x F64 in mem/xmm to 2 x F32 in
10103 lo half xmm(G), rounding according to prevailing SSE rounding
10104 mode, and zero upper half */
10105 /* Note, this is practically identical to CVTPD2DQ. It would have
10106 been nicer to merge them together, but the insn[] offsets differ
10107 by one. */
10108 if (have66noF2noF3(pfx) && sz == 2
10109 && insn[0] == 0x0F && insn[1] == 0x5A) {
10110 IRTemp argV = newTemp(Ity_V128);
10111 IRTemp rmode = newTemp(Ity_I32);
10112
10113 modrm = getUChar(delta+2);
10114 if (epartIsReg(modrm)) {
10115 assign( argV, getXMMReg(eregOfRexRM(pfx,modrm)) );
10116 delta += 2+1;
10117 DIP("cvtpd2ps %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
10118 nameXMMReg(gregOfRexRM(pfx,modrm)));
10119 } else {
10120 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10121 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
10122 delta += 2+alen;
10123 DIP("cvtpd2ps %s,%s\n", dis_buf,
10124 nameXMMReg(gregOfRexRM(pfx,modrm)) );
10125 }
10126
10127 assign( rmode, get_sse_roundingmode() );
10128 t0 = newTemp(Ity_F64);
10129 t1 = newTemp(Ity_F64);
10130 assign( t0, unop(Iop_ReinterpI64asF64,
10131 unop(Iop_V128to64, mkexpr(argV))) );
10132 assign( t1, unop(Iop_ReinterpI64asF64,
10133 unop(Iop_V128HIto64, mkexpr(argV))) );
10134
10135# define CVT(_t) binop( Iop_F64toF32, \
10136 mkexpr(rmode), \
10137 mkexpr(_t) )
10138
10139 putXMMRegLane32( gregOfRexRM(pfx,modrm), 3, mkU32(0) );
10140 putXMMRegLane32( gregOfRexRM(pfx,modrm), 2, mkU32(0) );
10141 putXMMRegLane32F( gregOfRexRM(pfx,modrm), 1, CVT(t1) );
10142 putXMMRegLane32F( gregOfRexRM(pfx,modrm), 0, CVT(t0) );
10143
10144# undef CVT
10145
10146 goto decode_success;
10147 }
10148
10149 /* 66 0F 2A = CVTPI2PD -- convert 2 x I32 in mem/mmx to 2 x F64 in
10150 xmm(G) */
10151 if (have66noF2noF3(pfx) && sz == 2
10152 && insn[0] == 0x0F && insn[1] == 0x2A) {
10153 IRTemp arg64 = newTemp(Ity_I64);
10154
10155 modrm = getUChar(delta+2);
10156 do_MMX_preamble();
10157 if (epartIsReg(modrm)) {
10158 assign( arg64, getMMXReg(eregLO3ofRM(modrm)) );
10159 delta += 2+1;
10160 DIP("cvtpi2pd %s,%s\n", nameMMXReg(eregLO3ofRM(modrm)),
10161 nameXMMReg(gregOfRexRM(pfx,modrm)));
10162 } else {
10163 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10164 assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
10165 delta += 2+alen;
10166 DIP("cvtpi2pd %s,%s\n", dis_buf,
10167 nameXMMReg(gregOfRexRM(pfx,modrm)) );
10168 }
10169
10170 putXMMRegLane64F(
10171 gregOfRexRM(pfx,modrm), 0,
10172 unop(Iop_I32toF64, unop(Iop_64to32, mkexpr(arg64)) )
10173 );
10174
10175 putXMMRegLane64F(
10176 gregOfRexRM(pfx,modrm), 1,
10177 unop(Iop_I32toF64, unop(Iop_64HIto32, mkexpr(arg64)) )
10178 );
10179
10180 goto decode_success;
10181 }
10182
10183 /* F3 0F 5B = CVTTPS2DQ -- convert 4 x F32 in mem/xmm to 4 x I32 in
10184 xmm(G), rounding towards zero */
10185 /* 66 0F 5B = CVTPS2DQ -- convert 4 x F32 in mem/xmm to 4 x I32 in
10186 xmm(G), as per the prevailing rounding mode */
10187 if ( ( (have66noF2noF3(pfx) && sz == 2)
10188 || (haveF3no66noF2(pfx) && sz == 4)
10189 )
10190 && insn[0] == 0x0F && insn[1] == 0x5B) {
10191 IRTemp argV = newTemp(Ity_V128);
10192 IRTemp rmode = newTemp(Ity_I32);
10193 Bool r2zero = toBool(sz == 4);
10194
10195 modrm = getUChar(delta+2);
10196 if (epartIsReg(modrm)) {
10197 assign( argV, getXMMReg(eregOfRexRM(pfx,modrm)) );
10198 delta += 2+1;
10199 DIP("cvtps2dq %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
10200 nameXMMReg(gregOfRexRM(pfx,modrm)));
10201 } else {
10202 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10203 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
10204 delta += 2+alen;
10205 DIP("cvtps2dq %s,%s\n", dis_buf,
10206 nameXMMReg(gregOfRexRM(pfx,modrm)) );
10207 }
10208
10209 if (r2zero) {
10210 assign( rmode, mkU32((UInt)Irrm_ZERO) );
10211 } else {
10212 assign( rmode, get_sse_roundingmode() );
10213 }
10214
10215 breakup128to32s( argV, &t3, &t2, &t1, &t0 );
10216
10217 /* This is less than ideal. If it turns out to be a performance
10218 bottleneck it can be improved. */
10219# define CVT(_t) \
10220 binop( Iop_F64toI32, \
10221 mkexpr(rmode), \
10222 unop( Iop_F32toF64, \
10223 unop( Iop_ReinterpI32asF32, mkexpr(_t))) )
10224
10225 putXMMRegLane32( gregOfRexRM(pfx,modrm), 3, CVT(t3) );
10226 putXMMRegLane32( gregOfRexRM(pfx,modrm), 2, CVT(t2) );
10227 putXMMRegLane32( gregOfRexRM(pfx,modrm), 1, CVT(t1) );
10228 putXMMRegLane32( gregOfRexRM(pfx,modrm), 0, CVT(t0) );
10229
10230# undef CVT
10231
10232 goto decode_success;
10233 }
10234
10235 /* 0F 5A = CVTPS2PD -- convert 2 x F32 in low half mem/xmm to 2 x
10236 F64 in xmm(G). */
10237 if (haveNo66noF2noF3(pfx) && sz == 4
10238 && insn[0] == 0x0F && insn[1] == 0x5A) {
10239 IRTemp f32lo = newTemp(Ity_F32);
10240 IRTemp f32hi = newTemp(Ity_F32);
10241
10242 modrm = getUChar(delta+2);
10243 if (epartIsReg(modrm)) {
10244 assign( f32lo, getXMMRegLane32F(eregOfRexRM(pfx,modrm), 0) );
10245 assign( f32hi, getXMMRegLane32F(eregOfRexRM(pfx,modrm), 1) );
10246 delta += 2+1;
10247 DIP("cvtps2pd %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
10248 nameXMMReg(gregOfRexRM(pfx,modrm)));
10249 } else {
10250 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10251 assign( f32lo, loadLE(Ity_F32, mkexpr(addr)) );
10252 assign( f32hi, loadLE(Ity_F32,
10253 binop(Iop_Add64,mkexpr(addr),mkU64(4))) );
10254 delta += 2+alen;
10255 DIP("cvtps2pd %s,%s\n", dis_buf,
10256 nameXMMReg(gregOfRexRM(pfx,modrm)) );
10257 }
10258
10259 putXMMRegLane64F( gregOfRexRM(pfx,modrm), 1,
10260 unop(Iop_F32toF64, mkexpr(f32hi)) );
10261 putXMMRegLane64F( gregOfRexRM(pfx,modrm), 0,
10262 unop(Iop_F32toF64, mkexpr(f32lo)) );
10263
10264 goto decode_success;
10265 }
10266
10267 /* F2 0F 2D = CVTSD2SI
10268 when sz==4 -- convert F64 in mem/low half xmm to I32 in ireg,
10269 according to prevailing SSE rounding mode
10270 when sz==8 -- convert F64 in mem/low half xmm to I64 in ireg,
10271 according to prevailing SSE rounding mode
10272 */
sewardj1a01e652005-02-23 11:39:21 +000010273 /* F2 0F 2C = CVTTSD2SI
10274 when sz==4 -- convert F64 in mem/low half xmm to I32 in ireg,
10275 truncating towards zero
10276 when sz==8 -- convert F64 in mem/low half xmm to I64 in ireg,
10277 truncating towards zero
10278 */
10279 if (haveF2no66noF3(pfx)
10280 && insn[0] == 0x0F
sewardj5992bd02005-05-11 02:13:42 +000010281 && (insn[1] == 0x2D || insn[1] == 0x2C)) {
sewardj1a01e652005-02-23 11:39:21 +000010282 IRTemp rmode = newTemp(Ity_I32);
10283 IRTemp f64lo = newTemp(Ity_F64);
sewardj1027dc22005-02-26 01:55:02 +000010284 Bool r2zero = toBool(insn[1] == 0x2C);
sewardj1a01e652005-02-23 11:39:21 +000010285 vassert(sz == 4 || sz == 8);
10286
10287 modrm = getUChar(delta+2);
10288 if (epartIsReg(modrm)) {
10289 delta += 2+1;
10290 assign(f64lo, getXMMRegLane64F(eregOfRexRM(pfx,modrm), 0));
10291 DIP("cvt%ssd2si %s,%s\n", r2zero ? "t" : "",
10292 nameXMMReg(eregOfRexRM(pfx,modrm)),
sewardj5b470602005-02-27 13:10:48 +000010293 nameIReg(sz, gregOfRexRM(pfx,modrm), False));
sewardj1a01e652005-02-23 11:39:21 +000010294 } else {
10295 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10296 assign(f64lo, loadLE(Ity_F64, mkexpr(addr)));
10297 delta += 2+alen;
10298 DIP("cvt%ssd2si %s,%s\n", r2zero ? "t" : "",
10299 dis_buf,
sewardj5b470602005-02-27 13:10:48 +000010300 nameIReg(sz, gregOfRexRM(pfx,modrm), False));
sewardj1a01e652005-02-23 11:39:21 +000010301 }
10302
10303 if (r2zero) {
10304 assign( rmode, mkU32((UInt)Irrm_ZERO) );
10305 } else {
10306 assign( rmode, get_sse_roundingmode() );
10307 }
10308
10309 if (sz == 4) {
sewardj5b470602005-02-27 13:10:48 +000010310 putIReg32( gregOfRexRM(pfx,modrm),
10311 binop( Iop_F64toI32, mkexpr(rmode), mkexpr(f64lo)) );
sewardj1a01e652005-02-23 11:39:21 +000010312 } else {
sewardj5b470602005-02-27 13:10:48 +000010313 putIReg64( gregOfRexRM(pfx,modrm),
10314 binop( Iop_F64toI64, mkexpr(rmode), mkexpr(f64lo)) );
sewardj1a01e652005-02-23 11:39:21 +000010315 }
10316
10317 goto decode_success;
10318 }
10319
sewardj8d965312005-02-25 02:48:47 +000010320 /* F2 0F 5A = CVTSD2SS -- convert F64 in mem/low half xmm to F32 in
10321 low 1/4 xmm(G), according to prevailing SSE rounding mode */
10322 if (haveF2no66noF3(pfx) && sz == 4
10323 && insn[0] == 0x0F && insn[1] == 0x5A) {
10324 IRTemp rmode = newTemp(Ity_I32);
10325 IRTemp f64lo = newTemp(Ity_F64);
10326 vassert(sz == 4);
10327
10328 modrm = getUChar(delta+2);
10329 if (epartIsReg(modrm)) {
10330 delta += 2+1;
10331 assign(f64lo, getXMMRegLane64F(eregOfRexRM(pfx,modrm), 0));
10332 DIP("cvtsd2ss %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
10333 nameXMMReg(gregOfRexRM(pfx,modrm)));
10334 } else {
10335 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10336 assign(f64lo, loadLE(Ity_F64, mkexpr(addr)));
10337 delta += 2+alen;
10338 DIP("cvtsd2ss %s,%s\n", dis_buf,
10339 nameXMMReg(gregOfRexRM(pfx,modrm)));
10340 }
10341
10342 assign( rmode, get_sse_roundingmode() );
10343 putXMMRegLane32F(
10344 gregOfRexRM(pfx,modrm), 0,
10345 binop( Iop_F64toF32, mkexpr(rmode), mkexpr(f64lo) )
10346 );
10347
10348 goto decode_success;
10349 }
sewardj1a01e652005-02-23 11:39:21 +000010350
10351 /* F2 0F 2A = CVTSI2SD
10352 when sz==4 -- convert I32 in mem/ireg to F64 in low half xmm
10353 when sz==8 -- convert I64 in mem/ireg to F64 in low half xmm
10354 */
sewardj8d965312005-02-25 02:48:47 +000010355 if (haveF2no66noF3(pfx) && (sz == 4 || sz == 8)
10356 && insn[0] == 0x0F && insn[1] == 0x2A) {
sewardj1a01e652005-02-23 11:39:21 +000010357 modrm = getUChar(delta+2);
10358
10359 if (sz == 4) {
10360 IRTemp arg32 = newTemp(Ity_I32);
10361 if (epartIsReg(modrm)) {
sewardj5b470602005-02-27 13:10:48 +000010362 assign( arg32, getIReg32(eregOfRexRM(pfx,modrm)) );
sewardj1a01e652005-02-23 11:39:21 +000010363 delta += 2+1;
sewardj5b470602005-02-27 13:10:48 +000010364 DIP("cvtsi2sd %s,%s\n", nameIReg32(eregOfRexRM(pfx,modrm)),
sewardj1a01e652005-02-23 11:39:21 +000010365 nameXMMReg(gregOfRexRM(pfx,modrm)));
10366 } else {
10367 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10368 assign( arg32, loadLE(Ity_I32, mkexpr(addr)) );
10369 delta += 2+alen;
10370 DIP("cvtsi2sd %s,%s\n", dis_buf,
10371 nameXMMReg(gregOfRexRM(pfx,modrm)) );
10372 }
10373 putXMMRegLane64F( gregOfRexRM(pfx,modrm), 0,
10374 unop(Iop_I32toF64, mkexpr(arg32))
10375 );
10376 } else {
10377 /* sz == 8 */
10378 IRTemp arg64 = newTemp(Ity_I64);
10379 if (epartIsReg(modrm)) {
sewardj5b470602005-02-27 13:10:48 +000010380 assign( arg64, getIReg64(eregOfRexRM(pfx,modrm)) );
sewardj1a01e652005-02-23 11:39:21 +000010381 delta += 2+1;
sewardj5b470602005-02-27 13:10:48 +000010382 DIP("cvtsi2sdq %s,%s\n", nameIReg64(eregOfRexRM(pfx,modrm)),
sewardj8d965312005-02-25 02:48:47 +000010383 nameXMMReg(gregOfRexRM(pfx,modrm)));
sewardj1a01e652005-02-23 11:39:21 +000010384 } else {
10385 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10386 assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
10387 delta += 2+alen;
sewardj8d965312005-02-25 02:48:47 +000010388 DIP("cvtsi2sdq %s,%s\n", dis_buf,
10389 nameXMMReg(gregOfRexRM(pfx,modrm)) );
sewardj1a01e652005-02-23 11:39:21 +000010390 }
10391 putXMMRegLane64F(
10392 gregOfRexRM(pfx,modrm),
10393 0,
10394 binop( Iop_I64toF64,
10395 get_sse_roundingmode(),
10396 mkexpr(arg64)
10397 )
10398 );
10399
10400 }
10401
10402 goto decode_success;
10403 }
10404
sewardjc49ce232005-02-25 13:03:03 +000010405 /* F3 0F 5A = CVTSS2SD -- convert F32 in mem/low 1/4 xmm to F64 in
10406 low half xmm(G) */
10407 if (haveF3no66noF2(pfx) && sz == 4
10408 && insn[0] == 0x0F && insn[1] == 0x5A) {
10409 IRTemp f32lo = newTemp(Ity_F32);
10410
10411 modrm = getUChar(delta+2);
10412 if (epartIsReg(modrm)) {
10413 delta += 2+1;
10414 assign(f32lo, getXMMRegLane32F(eregOfRexRM(pfx,modrm), 0));
10415 DIP("cvtss2sd %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
10416 nameXMMReg(gregOfRexRM(pfx,modrm)));
10417 } else {
10418 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10419 assign(f32lo, loadLE(Ity_F32, mkexpr(addr)));
10420 delta += 2+alen;
10421 DIP("cvtss2sd %s,%s\n", dis_buf,
10422 nameXMMReg(gregOfRexRM(pfx,modrm)));
10423 }
10424
10425 putXMMRegLane64F( gregOfRexRM(pfx,modrm), 0,
10426 unop( Iop_F32toF64, mkexpr(f32lo) ) );
10427
10428 goto decode_success;
10429 }
10430
sewardj5992bd02005-05-11 02:13:42 +000010431 /* 66 0F 5E = DIVPD -- div 64Fx2 from R/M to R */
10432 if (have66noF2noF3(pfx) && sz == 2
10433 && insn[0] == 0x0F && insn[1] == 0x5E) {
10434 delta = dis_SSE_E_to_G_all( pfx, delta+2, "divpd", Iop_Div64Fx2 );
10435 goto decode_success;
10436 }
sewardj1001dc42005-02-21 08:25:55 +000010437
10438 /* F2 0F 5E = DIVSD -- div 64F0x2 from R/M to R */
10439 if (haveF2no66noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x5E) {
10440 vassert(sz == 4);
10441 delta = dis_SSE_E_to_G_lo64( pfx, delta+2, "divsd", Iop_Div64F0x2 );
10442 goto decode_success;
10443 }
10444
sewardj5992bd02005-05-11 02:13:42 +000010445 /* 0F AE /5 = LFENCE -- flush pending operations to memory */
10446 /* 0F AE /6 = MFENCE -- flush pending operations to memory */
10447 if (haveNo66noF2noF3(pfx) && sz == 4
10448 && insn[0] == 0x0F && insn[1] == 0xAE
10449 && epartIsReg(insn[2])
10450 && (gregLO3ofRM(insn[2]) == 5 || gregLO3ofRM(insn[2]) == 6)) {
10451 delta += 3;
10452 /* Insert a memory fence. It's sometimes important that these
10453 are carried through to the generated code. */
sewardjc4356f02007-11-09 21:15:04 +000010454 stmt( IRStmt_MBE(Imbe_Fence) );
sewardj5992bd02005-05-11 02:13:42 +000010455 DIP("%sfence\n", gregLO3ofRM(insn[2])==5 ? "l" : "m");
10456 goto decode_success;
10457 }
10458
10459 /* 66 0F 5F = MAXPD -- max 64Fx2 from R/M to R */
10460 if (have66noF2noF3(pfx) && sz == 2
10461 && insn[0] == 0x0F && insn[1] == 0x5F) {
10462 delta = dis_SSE_E_to_G_all( pfx, delta+2, "maxpd", Iop_Max64Fx2 );
10463 goto decode_success;
10464 }
sewardj1a01e652005-02-23 11:39:21 +000010465
10466 /* F2 0F 5F = MAXSD -- max 64F0x2 from R/M to R */
10467 if (haveF2no66noF3(pfx) && sz == 4
10468 && insn[0] == 0x0F && insn[1] == 0x5F) {
10469 delta = dis_SSE_E_to_G_lo64( pfx, delta+2, "maxsd", Iop_Max64F0x2 );
10470 goto decode_success;
10471 }
10472
sewardj5992bd02005-05-11 02:13:42 +000010473 /* 66 0F 5D = MINPD -- min 64Fx2 from R/M to R */
10474 if (have66noF2noF3(pfx) && sz == 2
10475 && insn[0] == 0x0F && insn[1] == 0x5D) {
10476 delta = dis_SSE_E_to_G_all( pfx, delta+2, "minpd", Iop_Min64Fx2 );
10477 goto decode_success;
10478 }
sewardjc49ce232005-02-25 13:03:03 +000010479
10480 /* F2 0F 5D = MINSD -- min 64F0x2 from R/M to R */
10481 if (haveF2no66noF3(pfx) && sz == 4
10482 && insn[0] == 0x0F && insn[1] == 0x5D) {
10483 delta = dis_SSE_E_to_G_lo64( pfx, delta+2, "minsd", Iop_Min64F0x2 );
10484 goto decode_success;
10485 }
sewardj8d965312005-02-25 02:48:47 +000010486
10487 /* 66 0F 28 = MOVAPD -- move from E (mem or xmm) to G (xmm). */
10488 /* 66 0F 10 = MOVUPD -- move from E (mem or xmm) to G (xmm). */
10489 /* 66 0F 6F = MOVDQA -- move from E (mem or xmm) to G (xmm). */
sewardjb4bf5882007-11-06 20:39:17 +000010490 if (have66noF2noF3(pfx)
10491 && (sz == 2 || /* ignore redundant REX.W */ sz == 8)
sewardj8d965312005-02-25 02:48:47 +000010492 && insn[0] == 0x0F
10493 && (insn[1] == 0x28 || insn[1] == 0x10 || insn[1] == 0x6F)) {
10494 HChar* wot = insn[1]==0x28 ? "apd" :
10495 insn[1]==0x10 ? "upd" : "dqa";
10496 modrm = getUChar(delta+2);
10497 if (epartIsReg(modrm)) {
10498 putXMMReg( gregOfRexRM(pfx,modrm),
10499 getXMMReg( eregOfRexRM(pfx,modrm) ));
10500 DIP("mov%s %s,%s\n", wot, nameXMMReg(eregOfRexRM(pfx,modrm)),
10501 nameXMMReg(gregOfRexRM(pfx,modrm)));
10502 delta += 2+1;
10503 } else {
10504 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10505 putXMMReg( gregOfRexRM(pfx,modrm),
10506 loadLE(Ity_V128, mkexpr(addr)) );
10507 DIP("mov%s %s,%s\n", wot, dis_buf,
10508 nameXMMReg(gregOfRexRM(pfx,modrm)));
10509 delta += 2+alen;
10510 }
10511 goto decode_success;
10512 }
10513
sewardj4c328cf2005-05-05 12:05:54 +000010514 /* 66 0F 29 = MOVAPD -- move from G (xmm) to E (mem or xmm). */
sewardj240fd862005-11-01 18:59:38 +000010515 /* 66 0F 11 = MOVUPD -- move from G (xmm) to E (mem or xmm). */
10516 if (have66noF2noF3(pfx) && insn[0] == 0x0F
10517 && (insn[1] == 0x29 || insn[1] == 0x11)) {
sewardj4c328cf2005-05-05 12:05:54 +000010518 modrm = getUChar(delta+2);
10519 if (epartIsReg(modrm)) {
10520 /* fall through; awaiting test case */
10521 } else {
10522 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10523 storeLE( mkexpr(addr), getXMMReg(gregOfRexRM(pfx,modrm)) );
sewardj240fd862005-11-01 18:59:38 +000010524 DIP("mov[ua]pd %s,%s\n", nameXMMReg(gregOfRexRM(pfx,modrm)),
10525 dis_buf );
sewardj4c328cf2005-05-05 12:05:54 +000010526 delta += 2+alen;
10527 goto decode_success;
10528 }
10529 }
10530
sewardj09717342005-05-05 21:34:02 +000010531 /* 66 0F 6E = MOVD from ireg32/m32 to xmm lo 1/4, zeroing high 3/4 of xmm. */
10532 /* or from ireg64/m64 to xmm lo 1/2, zeroing high 1/2 of xmm. */
10533 if (have66noF2noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x6E) {
sewardj97628592005-05-10 22:42:54 +000010534 vassert(sz == 2 || sz == 8);
10535 if (sz == 2) sz = 4;
sewardj09717342005-05-05 21:34:02 +000010536 modrm = getUChar(delta+2);
10537 if (epartIsReg(modrm)) {
10538 delta += 2+1;
10539 if (sz == 4) {
sewardj09717342005-05-05 21:34:02 +000010540 putXMMReg(
10541 gregOfRexRM(pfx,modrm),
10542 unop( Iop_32UtoV128, getIReg32(eregOfRexRM(pfx,modrm)) )
10543 );
10544 DIP("movd %s, %s\n", nameIReg32(eregOfRexRM(pfx,modrm)),
10545 nameXMMReg(gregOfRexRM(pfx,modrm)));
10546 } else {
10547 putXMMReg(
10548 gregOfRexRM(pfx,modrm),
10549 unop( Iop_64UtoV128, getIReg64(eregOfRexRM(pfx,modrm)) )
10550 );
10551 DIP("movq %s, %s\n", nameIReg64(eregOfRexRM(pfx,modrm)),
10552 nameXMMReg(gregOfRexRM(pfx,modrm)));
10553 }
10554 } else {
10555 addr = disAMode( &alen, pfx, delta+2, dis_buf, 0 );
10556 delta += 2+alen;
10557 putXMMReg(
10558 gregOfRexRM(pfx,modrm),
10559 sz == 4
10560 ? unop( Iop_32UtoV128,loadLE(Ity_I32, mkexpr(addr)) )
10561 : unop( Iop_64UtoV128,loadLE(Ity_I64, mkexpr(addr)) )
10562 );
10563 DIP("mov%c %s, %s\n", sz == 4 ? 'd' : 'q', dis_buf,
10564 nameXMMReg(gregOfRexRM(pfx,modrm)));
10565 }
10566 goto decode_success;
10567 }
10568
10569 /* 66 0F 7E = MOVD from xmm low 1/4 to ireg32 or m32. */
10570 /* or from xmm low 1/2 to ireg64 or m64. */
10571 if (have66noF2noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x7E) {
10572 if (sz == 2) sz = 4;
10573 vassert(sz == 4 || sz == 8);
10574 modrm = getUChar(delta+2);
10575 if (epartIsReg(modrm)) {
10576 delta += 2+1;
10577 if (sz == 4) {
10578 putIReg32( eregOfRexRM(pfx,modrm),
10579 getXMMRegLane32(gregOfRexRM(pfx,modrm), 0) );
10580 DIP("movd %s, %s\n", nameXMMReg(gregOfRexRM(pfx,modrm)),
10581 nameIReg32(eregOfRexRM(pfx,modrm)));
10582 } else {
10583 putIReg64( eregOfRexRM(pfx,modrm),
10584 getXMMRegLane64(gregOfRexRM(pfx,modrm), 0) );
10585 DIP("movq %s, %s\n", nameXMMReg(gregOfRexRM(pfx,modrm)),
10586 nameIReg64(eregOfRexRM(pfx,modrm)));
10587 }
10588 } else {
10589 addr = disAMode( &alen, pfx, delta+2, dis_buf, 0 );
10590 delta += 2+alen;
10591 storeLE( mkexpr(addr),
10592 sz == 4
10593 ? getXMMRegLane32(gregOfRexRM(pfx,modrm),0)
10594 : getXMMRegLane64(gregOfRexRM(pfx,modrm),0) );
10595 DIP("mov%c %s, %s\n", sz == 4 ? 'd' : 'q',
10596 nameXMMReg(gregOfRexRM(pfx,modrm)), dis_buf);
10597 }
10598 goto decode_success;
10599 }
10600
10601 /* 66 0F 7F = MOVDQA -- move from G (xmm) to E (mem or xmm). */
10602 if (have66noF2noF3(pfx) && sz == 2
10603 && insn[0] == 0x0F && insn[1] == 0x7F) {
10604 modrm = getUChar(delta+2);
10605 if (epartIsReg(modrm)) {
10606 delta += 2+1;
10607 putXMMReg( eregOfRexRM(pfx,modrm),
10608 getXMMReg(gregOfRexRM(pfx,modrm)) );
10609 DIP("movdqa %s, %s\n", nameXMMReg(gregOfRexRM(pfx,modrm)),
10610 nameXMMReg(eregOfRexRM(pfx,modrm)));
10611 } else {
10612 addr = disAMode( &alen, pfx, delta+2, dis_buf, 0 );
10613 delta += 2+alen;
10614 storeLE( mkexpr(addr), getXMMReg(gregOfRexRM(pfx,modrm)) );
10615 DIP("movdqa %s, %s\n", nameXMMReg(gregOfRexRM(pfx,modrm)), dis_buf);
10616 }
10617 goto decode_success;
10618 }
10619
sewardj612be432005-05-11 02:55:54 +000010620 /* F3 0F 6F = MOVDQU -- move from E (mem or xmm) to G (xmm). */
10621 if (haveF3no66noF2(pfx) && sz == 4
10622 && insn[0] == 0x0F && insn[1] == 0x6F) {
10623 modrm = getUChar(delta+2);
10624 if (epartIsReg(modrm)) {
10625 putXMMReg( gregOfRexRM(pfx,modrm),
10626 getXMMReg( eregOfRexRM(pfx,modrm) ));
10627 DIP("movdqu %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
10628 nameXMMReg(gregOfRexRM(pfx,modrm)));
10629 delta += 2+1;
10630 } else {
10631 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10632 putXMMReg( gregOfRexRM(pfx,modrm),
10633 loadLE(Ity_V128, mkexpr(addr)) );
10634 DIP("movdqu %s,%s\n", dis_buf,
10635 nameXMMReg(gregOfRexRM(pfx,modrm)));
10636 delta += 2+alen;
10637 }
10638 goto decode_success;
10639 }
10640
10641 /* F3 0F 7F = MOVDQU -- move from G (xmm) to E (mem or xmm). */
10642 if (haveF3no66noF2(pfx) && sz == 4
10643 && insn[0] == 0x0F && insn[1] == 0x7F) {
10644 modrm = getUChar(delta+2);
10645 if (epartIsReg(modrm)) {
10646 goto decode_failure; /* awaiting test case */
10647 delta += 2+1;
10648 putXMMReg( eregOfRexRM(pfx,modrm),
10649 getXMMReg(gregOfRexRM(pfx,modrm)) );
10650 DIP("movdqu %s, %s\n", nameXMMReg(gregOfRexRM(pfx,modrm)),
10651 nameXMMReg(eregOfRexRM(pfx,modrm)));
10652 } else {
10653 addr = disAMode( &alen, pfx, delta+2, dis_buf, 0 );
10654 delta += 2+alen;
10655 storeLE( mkexpr(addr), getXMMReg(gregOfRexRM(pfx,modrm)) );
10656 DIP("movdqu %s, %s\n", nameXMMReg(gregOfRexRM(pfx,modrm)), dis_buf);
10657 }
10658 goto decode_success;
10659 }
10660
10661 /* F2 0F D6 = MOVDQ2Q -- move from E (lo half xmm, not mem) to G (mmx). */
10662 if (haveF2no66noF3(pfx) && sz == 4
10663 && insn[0] == 0x0F && insn[1] == 0xD6) {
10664 modrm = getUChar(delta+2);
10665 if (epartIsReg(modrm)) {
10666 do_MMX_preamble();
10667 putMMXReg( gregLO3ofRM(modrm),
10668 getXMMRegLane64( eregOfRexRM(pfx,modrm), 0 ));
10669 DIP("movdq2q %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
10670 nameMMXReg(gregLO3ofRM(modrm)));
10671 delta += 2+1;
10672 goto decode_success;
10673 } else {
10674 /* apparently no mem case for this insn */
10675 goto decode_failure;
10676 }
10677 }
sewardj4c328cf2005-05-05 12:05:54 +000010678
10679 /* 66 0F 16 = MOVHPD -- move from mem to high half of XMM. */
10680 /* These seems identical to MOVHPS. This instruction encoding is
10681 completely crazy. */
10682 if (have66noF2noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x16) {
10683 modrm = getUChar(delta+2);
10684 if (epartIsReg(modrm)) {
10685 /* fall through; apparently reg-reg is not possible */
10686 } else {
10687 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10688 delta += 2+alen;
10689 putXMMRegLane64( gregOfRexRM(pfx,modrm), 1/*upper lane*/,
10690 loadLE(Ity_I64, mkexpr(addr)) );
10691 DIP("movhpd %s,%s\n", dis_buf,
10692 nameXMMReg( gregOfRexRM(pfx,modrm) ));
10693 goto decode_success;
10694 }
10695 }
10696
10697 /* 66 0F 17 = MOVHPD -- move from high half of XMM to mem. */
10698 /* Again, this seems identical to MOVHPS. */
10699 if (have66noF2noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x17) {
10700 if (!epartIsReg(insn[2])) {
10701 delta += 2;
10702 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
10703 delta += alen;
10704 storeLE( mkexpr(addr),
10705 getXMMRegLane64( gregOfRexRM(pfx,insn[2]),
10706 1/*upper lane*/ ) );
10707 DIP("movhpd %s,%s\n", nameXMMReg( gregOfRexRM(pfx,insn[2]) ),
10708 dis_buf);
10709 goto decode_success;
10710 }
10711 /* else fall through */
10712 }
sewardj1001dc42005-02-21 08:25:55 +000010713
10714 /* 66 0F 12 = MOVLPD -- move from mem to low half of XMM. */
10715 /* Identical to MOVLPS ? */
10716 if (have66noF2noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x12) {
10717 modrm = getUChar(delta+2);
10718 if (epartIsReg(modrm)) {
10719 /* fall through; apparently reg-reg is not possible */
10720 } else {
10721 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10722 delta += 2+alen;
10723 putXMMRegLane64( gregOfRexRM(pfx,modrm),
10724 0/*lower lane*/,
10725 loadLE(Ity_I64, mkexpr(addr)) );
10726 DIP("movlpd %s, %s\n",
10727 dis_buf, nameXMMReg( gregOfRexRM(pfx,modrm) ));
10728 goto decode_success;
10729 }
10730 }
10731
sewardj4c328cf2005-05-05 12:05:54 +000010732 /* 66 0F 13 = MOVLPD -- move from low half of XMM to mem. */
10733 /* Identical to MOVLPS ? */
10734 if (have66noF2noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x13) {
10735 modrm = getUChar(delta+2);
10736 if (!epartIsReg(modrm)) {
10737 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10738 delta += 2+alen;
10739 storeLE( mkexpr(addr),
10740 getXMMRegLane64( gregOfRexRM(pfx,modrm),
10741 0/*lower lane*/ ) );
10742 DIP("movlpd %s, %s\n", nameXMMReg( gregOfRexRM(pfx,modrm) ),
10743 dis_buf);
10744 goto decode_success;
10745 }
10746 /* else fall through */
10747 }
10748
sewardj612be432005-05-11 02:55:54 +000010749 /* 66 0F 50 = MOVMSKPD - move 2 sign bits from 2 x F64 in xmm(E) to
10750 2 lowest bits of ireg(G) */
sewardjae84d782006-04-13 22:06:35 +000010751 if (have66noF2noF3(pfx) && (sz == 2 || sz == 8)
sewardj612be432005-05-11 02:55:54 +000010752 && insn[0] == 0x0F && insn[1] == 0x50) {
sewardjae84d782006-04-13 22:06:35 +000010753 /* sz == 8 is a kludge to handle insns with REX.W redundantly
10754 set to 1, which has been known to happen:
10755 66 4c 0f 50 d9 rex64X movmskpd %xmm1,%r11d
sewardjb4bf5882007-11-06 20:39:17 +000010756 20071106: see further comments on MOVMSKPS implementation above.
sewardjae84d782006-04-13 22:06:35 +000010757 */
sewardj612be432005-05-11 02:55:54 +000010758 modrm = getUChar(delta+2);
10759 if (epartIsReg(modrm)) {
10760 Int src;
10761 t0 = newTemp(Ity_I32);
10762 t1 = newTemp(Ity_I32);
10763 delta += 2+1;
10764 src = eregOfRexRM(pfx,modrm);
10765 assign( t0, binop( Iop_And32,
10766 binop(Iop_Shr32, getXMMRegLane32(src,1), mkU8(31)),
10767 mkU32(1) ));
10768 assign( t1, binop( Iop_And32,
10769 binop(Iop_Shr32, getXMMRegLane32(src,3), mkU8(30)),
10770 mkU32(2) ));
10771 putIReg32( gregOfRexRM(pfx,modrm),
10772 binop(Iop_Or32, mkexpr(t0), mkexpr(t1))
10773 );
10774 DIP("movmskpd %s,%s\n", nameXMMReg(src),
10775 nameIReg32(gregOfRexRM(pfx,modrm)));
10776 goto decode_success;
10777 }
10778 /* else fall through */
10779 goto decode_failure;
10780 }
10781
sewardj02f79f12007-09-01 18:59:53 +000010782 /* 66 0F F7 = MASKMOVDQU -- store selected bytes of double quadword */
10783 if (have66noF2noF3(pfx) && sz == 2
10784 && insn[0] == 0x0F && insn[1] == 0xF7) {
10785 modrm = getUChar(delta+2);
10786 if (epartIsReg(modrm)) {
10787 IRTemp regD = newTemp(Ity_V128);
10788 IRTemp mask = newTemp(Ity_V128);
10789 IRTemp olddata = newTemp(Ity_V128);
10790 IRTemp newdata = newTemp(Ity_V128);
10791 addr = newTemp(Ity_I64);
10792
10793 assign( addr, handleAddrOverrides( pfx, getIReg64(R_RDI) ));
10794 assign( regD, getXMMReg( gregOfRexRM(pfx,modrm) ));
10795
10796 /* Unfortunately can't do the obvious thing with SarN8x16
10797 here since that can't be re-emitted as SSE2 code - no such
10798 insn. */
10799 assign(
10800 mask,
10801 binop(Iop_64HLtoV128,
10802 binop(Iop_SarN8x8,
10803 getXMMRegLane64( eregOfRexRM(pfx,modrm), 1 ),
10804 mkU8(7) ),
10805 binop(Iop_SarN8x8,
10806 getXMMRegLane64( eregOfRexRM(pfx,modrm), 0 ),
10807 mkU8(7) ) ));
10808 assign( olddata, loadLE( Ity_V128, mkexpr(addr) ));
10809 assign( newdata,
10810 binop(Iop_OrV128,
10811 binop(Iop_AndV128,
10812 mkexpr(regD),
10813 mkexpr(mask) ),
10814 binop(Iop_AndV128,
10815 mkexpr(olddata),
10816 unop(Iop_NotV128, mkexpr(mask)))) );
10817 storeLE( mkexpr(addr), mkexpr(newdata) );
10818
10819 delta += 2+1;
10820 DIP("maskmovdqu %s,%s\n", nameXMMReg( eregOfRexRM(pfx,modrm) ),
10821 nameXMMReg( gregOfRexRM(pfx,modrm) ) );
10822 goto decode_success;
10823 }
10824 /* else fall through */
10825 }
10826
sewardj612be432005-05-11 02:55:54 +000010827 /* 66 0F E7 = MOVNTDQ -- for us, just a plain SSE store. */
10828 if (have66noF2noF3(pfx) && sz == 2
10829 && insn[0] == 0x0F && insn[1] == 0xE7) {
10830 modrm = getUChar(delta+2);
10831 if (!epartIsReg(modrm)) {
10832 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10833 storeLE( mkexpr(addr), getXMMReg(gregOfRexRM(pfx,modrm)) );
10834 DIP("movntdq %s,%s\n", dis_buf,
10835 nameXMMReg(gregOfRexRM(pfx,modrm)));
10836 delta += 2+alen;
10837 goto decode_success;
10838 }
10839 /* else fall through */
10840 goto decode_failure;
10841 }
sewardjf53b7352005-04-06 20:01:56 +000010842
10843 /* 0F C3 = MOVNTI -- for us, just a plain ireg store. */
10844 if (haveNo66noF2noF3(pfx) &&
10845 insn[0] == 0x0F && insn[1] == 0xC3) {
10846 vassert(sz == 4 || sz == 8);
10847 modrm = getUChar(delta+2);
10848 if (!epartIsReg(modrm)) {
10849 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10850 storeLE( mkexpr(addr), getIRegG(sz, pfx, modrm) );
10851 DIP("movnti %s,%s\n", dis_buf,
10852 nameIRegG(sz, pfx, modrm));
10853 delta += 2+alen;
10854 goto decode_success;
10855 }
10856 /* else fall through */
10857 }
sewardj5cc00ff2005-03-27 04:48:32 +000010858
10859 /* 66 0F D6 = MOVQ -- move 64 bits from G (lo half xmm) to E (mem
10860 or lo half xmm). */
sewardjb4bf5882007-11-06 20:39:17 +000010861 if (have66noF2noF3(pfx)
10862 && (sz == 2 || /* ignore redundant REX.W */ sz == 8)
10863 && insn[0] == 0x0F && insn[1] == 0xD6) {
sewardj5cc00ff2005-03-27 04:48:32 +000010864 modrm = getUChar(delta+2);
10865 if (epartIsReg(modrm)) {
10866 /* fall through, awaiting test case */
sewardj94a48b22005-05-14 11:17:25 +000010867 /* dst: lo half copied, hi half zeroed */
sewardj5cc00ff2005-03-27 04:48:32 +000010868 } else {
10869 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10870 storeLE( mkexpr(addr),
10871 getXMMRegLane64( gregOfRexRM(pfx,modrm), 0 ));
10872 DIP("movq %s,%s\n", nameXMMReg(gregOfRexRM(pfx,modrm)), dis_buf );
10873 delta += 2+alen;
10874 goto decode_success;
10875 }
10876 }
10877
sewardj612be432005-05-11 02:55:54 +000010878 /* F3 0F D6 = MOVQ2DQ -- move from E (mmx) to G (lo half xmm, zero
10879 hi half). */
10880 if (haveF3no66noF2(pfx) && sz == 4
10881 && insn[0] == 0x0F && insn[1] == 0xD6) {
10882 modrm = getUChar(delta+2);
10883 if (epartIsReg(modrm)) {
10884 do_MMX_preamble();
10885 putXMMReg( gregOfRexRM(pfx,modrm),
10886 unop(Iop_64UtoV128, getMMXReg( eregLO3ofRM(modrm) )) );
10887 DIP("movq2dq %s,%s\n", nameMMXReg(eregLO3ofRM(modrm)),
10888 nameXMMReg(gregOfRexRM(pfx,modrm)));
10889 delta += 2+1;
10890 goto decode_success;
10891 } else {
10892 /* apparently no mem case for this insn */
10893 goto decode_failure;
10894 }
10895 }
10896
10897 /* F3 0F 7E = MOVQ -- move 64 bits from E (mem or lo half xmm) to
sewardj94a48b22005-05-14 11:17:25 +000010898 G (lo half xmm). Upper half of G is zeroed out. */
sewardj1001dc42005-02-21 08:25:55 +000010899 /* F2 0F 10 = MOVSD -- move 64 bits from E (mem or lo half xmm) to
10900 G (lo half xmm). If E is mem, upper half of G is zeroed out.
sewardj94a48b22005-05-14 11:17:25 +000010901 If E is reg, upper half of G is unchanged. */
sewardjb4bf5882007-11-06 20:39:17 +000010902 if ( (haveF2no66noF3(pfx)
10903 && (sz == 4 || /* ignore redundant REX.W */ sz == 8)
sewardj612be432005-05-11 02:55:54 +000010904 && insn[0] == 0x0F && insn[1] == 0x10)
sewardj5cc00ff2005-03-27 04:48:32 +000010905 ||
sewardjb4bf5882007-11-06 20:39:17 +000010906 (haveF3no66noF2(pfx)
10907 && (sz == 4 || /* ignore redundant REX.W */ sz == 8)
sewardj612be432005-05-11 02:55:54 +000010908 && insn[0] == 0x0F && insn[1] == 0x7E)
sewardj1001dc42005-02-21 08:25:55 +000010909 ) {
sewardj1001dc42005-02-21 08:25:55 +000010910 modrm = getUChar(delta+2);
10911 if (epartIsReg(modrm)) {
10912 putXMMRegLane64( gregOfRexRM(pfx,modrm), 0,
10913 getXMMRegLane64( eregOfRexRM(pfx,modrm), 0 ));
sewardj94a48b22005-05-14 11:17:25 +000010914 if (insn[1] == 0x7E/*MOVQ*/) {
10915 /* zero bits 127:64 */
10916 putXMMRegLane64( gregOfRexRM(pfx,modrm), 1, mkU64(0) );
10917 }
sewardj1001dc42005-02-21 08:25:55 +000010918 DIP("movsd %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
10919 nameXMMReg(gregOfRexRM(pfx,modrm)));
10920 delta += 2+1;
10921 } else {
10922 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10923 putXMMReg( gregOfRexRM(pfx,modrm), mkV128(0) );
10924 putXMMRegLane64( gregOfRexRM(pfx,modrm), 0,
10925 loadLE(Ity_I64, mkexpr(addr)) );
10926 DIP("movsd %s,%s\n", dis_buf,
10927 nameXMMReg(gregOfRexRM(pfx,modrm)));
10928 delta += 2+alen;
10929 }
10930 goto decode_success;
10931 }
10932
10933 /* F2 0F 11 = MOVSD -- move 64 bits from G (lo half xmm) to E (mem
10934 or lo half xmm). */
sewardjb4bf5882007-11-06 20:39:17 +000010935 if (haveF2no66noF3(pfx)
10936 && (sz == 4 || /* ignore redundant REX.W */ sz == 8)
sewardj8d965312005-02-25 02:48:47 +000010937 && insn[0] == 0x0F && insn[1] == 0x11) {
sewardj1001dc42005-02-21 08:25:55 +000010938 modrm = getUChar(delta+2);
10939 if (epartIsReg(modrm)) {
10940 /* fall through, we don't yet have a test case */
10941 } else {
10942 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10943 storeLE( mkexpr(addr),
10944 getXMMRegLane64(gregOfRexRM(pfx,modrm), 0) );
10945 DIP("movsd %s,%s\n", nameXMMReg(gregOfRexRM(pfx,modrm)),
10946 dis_buf);
10947 delta += 2+alen;
10948 goto decode_success;
10949 }
10950 }
10951
sewardj4c328cf2005-05-05 12:05:54 +000010952 /* 66 0F 59 = MULPD -- mul 64Fx2 from R/M to R */
sewardjb4bf5882007-11-06 20:39:17 +000010953 if (have66noF2noF3(pfx)
10954 && (sz == 2 || /* ignore redundant REX.W */ sz == 8)
sewardj4c328cf2005-05-05 12:05:54 +000010955 && insn[0] == 0x0F && insn[1] == 0x59) {
10956 delta = dis_SSE_E_to_G_all( pfx, delta+2, "mulpd", Iop_Mul64Fx2 );
10957 goto decode_success;
10958 }
sewardj1001dc42005-02-21 08:25:55 +000010959
10960 /* F2 0F 59 = MULSD -- mul 64F0x2 from R/M to R */
sewardjb4bf5882007-11-06 20:39:17 +000010961 if (haveF2no66noF3(pfx)
10962 && (sz == 4 || /* ignore redundant REX.W */ sz == 8)
sewardj8d965312005-02-25 02:48:47 +000010963 && insn[0] == 0x0F && insn[1] == 0x59) {
sewardj1001dc42005-02-21 08:25:55 +000010964 delta = dis_SSE_E_to_G_lo64( pfx, delta+2, "mulsd", Iop_Mul64F0x2 );
10965 goto decode_success;
10966 }
10967
sewardj8d965312005-02-25 02:48:47 +000010968 /* 66 0F 56 = ORPD -- G = G and E */
10969 if (have66noF2noF3(pfx) && sz == 2
10970 && insn[0] == 0x0F && insn[1] == 0x56) {
10971 delta = dis_SSE_E_to_G_all( pfx, delta+2, "orpd", Iop_OrV128 );
10972 goto decode_success;
10973 }
10974
sewardj09717342005-05-05 21:34:02 +000010975 /* 66 0F C6 /r ib = SHUFPD -- shuffle packed F64s */
10976 if (have66noF2noF3(pfx) && sz == 2
10977 && insn[0] == 0x0F && insn[1] == 0xC6) {
10978 Int select;
10979 IRTemp sV = newTemp(Ity_V128);
10980 IRTemp dV = newTemp(Ity_V128);
10981 IRTemp s1 = newTemp(Ity_I64);
10982 IRTemp s0 = newTemp(Ity_I64);
10983 IRTemp d1 = newTemp(Ity_I64);
10984 IRTemp d0 = newTemp(Ity_I64);
10985
10986 modrm = insn[2];
10987 assign( dV, getXMMReg(gregOfRexRM(pfx,modrm)) );
10988
10989 if (epartIsReg(modrm)) {
10990 assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
10991 select = (Int)insn[3];
10992 delta += 2+2;
10993 DIP("shufpd $%d,%s,%s\n", select,
10994 nameXMMReg(eregOfRexRM(pfx,modrm)),
10995 nameXMMReg(gregOfRexRM(pfx,modrm)));
10996 } else {
10997 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 1 );
10998 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
10999 select = (Int)insn[2+alen];
11000 delta += 3+alen;
11001 DIP("shufpd $%d,%s,%s\n", select,
11002 dis_buf,
11003 nameXMMReg(gregOfRexRM(pfx,modrm)));
11004 }
11005
11006 assign( d1, unop(Iop_V128HIto64, mkexpr(dV)) );
11007 assign( d0, unop(Iop_V128to64, mkexpr(dV)) );
11008 assign( s1, unop(Iop_V128HIto64, mkexpr(sV)) );
11009 assign( s0, unop(Iop_V128to64, mkexpr(sV)) );
11010
11011# define SELD(n) mkexpr((n)==0 ? d0 : d1)
11012# define SELS(n) mkexpr((n)==0 ? s0 : s1)
11013
11014 putXMMReg(
11015 gregOfRexRM(pfx,modrm),
11016 binop(Iop_64HLtoV128, SELS((select>>1)&1), SELD((select>>0)&1) )
11017 );
11018
11019# undef SELD
11020# undef SELS
11021
11022 goto decode_success;
11023 }
11024
sewardj97628592005-05-10 22:42:54 +000011025 /* 66 0F 51 = SQRTPD -- approx sqrt 64Fx2 from R/M to R */
11026 if (have66noF2noF3(pfx) && sz == 2
11027 && insn[0] == 0x0F && insn[1] == 0x51) {
11028 delta = dis_SSE_E_to_G_unary_all( pfx, delta+2,
11029 "sqrtpd", Iop_Sqrt64Fx2 );
11030 goto decode_success;
11031 }
sewardj1001dc42005-02-21 08:25:55 +000011032
11033 /* F2 0F 51 = SQRTSD -- approx sqrt 64F0x2 from R/M to R */
11034 if (haveF2no66noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x51) {
11035 vassert(sz == 4);
11036 delta = dis_SSE_E_to_G_unary_lo64( pfx, delta+2,
11037 "sqrtsd", Iop_Sqrt64F0x2 );
11038 goto decode_success;
11039 }
11040
sewardj4c328cf2005-05-05 12:05:54 +000011041 /* 66 0F 5C = SUBPD -- sub 64Fx2 from R/M to R */
11042 if (have66noF2noF3(pfx) && sz == 2
11043 && insn[0] == 0x0F && insn[1] == 0x5C) {
11044 delta = dis_SSE_E_to_G_all( pfx, delta+2, "subpd", Iop_Sub64Fx2 );
11045 goto decode_success;
11046 }
sewardj1001dc42005-02-21 08:25:55 +000011047
11048 /* F2 0F 5C = SUBSD -- sub 64F0x2 from R/M to R */
sewardjb4bf5882007-11-06 20:39:17 +000011049 if (haveF2no66noF3(pfx)
11050 && (sz == 4 || /* ignore redundant REX.W */ sz == 8)
11051 && insn[0] == 0x0F && insn[1] == 0x5C) {
sewardj1001dc42005-02-21 08:25:55 +000011052 delta = dis_SSE_E_to_G_lo64( pfx, delta+2, "subsd", Iop_Sub64F0x2 );
11053 goto decode_success;
11054 }
11055
sewardj1a01e652005-02-23 11:39:21 +000011056 /* 66 0F 15 = UNPCKHPD -- unpack and interleave high part F64s */
11057 /* 66 0F 14 = UNPCKLPD -- unpack and interleave low part F64s */
11058 /* These just appear to be special cases of SHUFPS */
11059 if (have66noF2noF3(pfx)
11060 && sz == 2 /* could be 8 if rex also present */
11061 && insn[0] == 0x0F && (insn[1] == 0x15 || insn[1] == 0x14)) {
11062 IRTemp s1 = newTemp(Ity_I64);
11063 IRTemp s0 = newTemp(Ity_I64);
11064 IRTemp d1 = newTemp(Ity_I64);
11065 IRTemp d0 = newTemp(Ity_I64);
11066 IRTemp sV = newTemp(Ity_V128);
11067 IRTemp dV = newTemp(Ity_V128);
sewardj1027dc22005-02-26 01:55:02 +000011068 Bool hi = toBool(insn[1] == 0x15);
sewardj1a01e652005-02-23 11:39:21 +000011069
11070 modrm = insn[2];
11071 assign( dV, getXMMReg(gregOfRexRM(pfx,modrm)) );
11072
11073 if (epartIsReg(modrm)) {
11074 assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
11075 delta += 2+1;
11076 DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
11077 nameXMMReg(eregOfRexRM(pfx,modrm)),
11078 nameXMMReg(gregOfRexRM(pfx,modrm)));
11079 } else {
11080 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
11081 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
11082 delta += 2+alen;
11083 DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
11084 dis_buf,
11085 nameXMMReg(gregOfRexRM(pfx,modrm)));
11086 }
11087
11088 assign( d1, unop(Iop_V128HIto64, mkexpr(dV)) );
11089 assign( d0, unop(Iop_V128to64, mkexpr(dV)) );
11090 assign( s1, unop(Iop_V128HIto64, mkexpr(sV)) );
11091 assign( s0, unop(Iop_V128to64, mkexpr(sV)) );
11092
11093 if (hi) {
11094 putXMMReg( gregOfRexRM(pfx,modrm),
11095 binop(Iop_64HLtoV128, mkexpr(s1), mkexpr(d1)) );
11096 } else {
11097 putXMMReg( gregOfRexRM(pfx,modrm),
11098 binop(Iop_64HLtoV128, mkexpr(s0), mkexpr(d0)) );
11099 }
11100
11101 goto decode_success;
11102 }
sewardj9da16972005-02-21 13:58:26 +000011103
11104 /* 66 0F 57 = XORPD -- G = G xor E */
sewardj97628592005-05-10 22:42:54 +000011105 if (have66noF2noF3(pfx) && sz == 2
11106 && insn[0] == 0x0F && insn[1] == 0x57) {
sewardj9da16972005-02-21 13:58:26 +000011107 delta = dis_SSE_E_to_G_all( pfx, delta+2, "xorpd", Iop_XorV128 );
11108 goto decode_success;
11109 }
11110
sewardj97628592005-05-10 22:42:54 +000011111 /* 66 0F 6B = PACKSSDW */
11112 if (have66noF2noF3(pfx) && sz == 2
11113 && insn[0] == 0x0F && insn[1] == 0x6B) {
11114 delta = dis_SSEint_E_to_G( pfx, delta+2,
11115 "packssdw", Iop_QNarrow32Sx4, True );
11116 goto decode_success;
11117 }
11118
11119 /* 66 0F 63 = PACKSSWB */
11120 if (have66noF2noF3(pfx) && sz == 2
11121 && insn[0] == 0x0F && insn[1] == 0x63) {
11122 delta = dis_SSEint_E_to_G( pfx, delta+2,
11123 "packsswb", Iop_QNarrow16Sx8, True );
11124 goto decode_success;
11125 }
11126
11127 /* 66 0F 67 = PACKUSWB */
11128 if (have66noF2noF3(pfx) && sz == 2
11129 && insn[0] == 0x0F && insn[1] == 0x67) {
11130 delta = dis_SSEint_E_to_G( pfx, delta+2,
11131 "packuswb", Iop_QNarrow16Ux8, True );
11132 goto decode_success;
11133 }
11134
11135 /* 66 0F FC = PADDB */
11136 if (have66noF2noF3(pfx) && sz == 2
11137 && insn[0] == 0x0F && insn[1] == 0xFC) {
11138 delta = dis_SSEint_E_to_G( pfx, delta+2,
11139 "paddb", Iop_Add8x16, False );
11140 goto decode_success;
11141 }
11142
11143 /* 66 0F FE = PADDD */
11144 if (have66noF2noF3(pfx) && sz == 2
11145 && insn[0] == 0x0F && insn[1] == 0xFE) {
11146 delta = dis_SSEint_E_to_G( pfx, delta+2,
11147 "paddd", Iop_Add32x4, False );
11148 goto decode_success;
11149 }
sewardj8711f662005-05-09 17:52:56 +000011150
11151 /* ***--- this is an MMX class insn introduced in SSE2 ---*** */
11152 /* 0F D4 = PADDQ -- add 64x1 */
11153 if (haveNo66noF2noF3(pfx) && sz == 4
11154 && insn[0] == 0x0F && insn[1] == 0xD4) {
11155 do_MMX_preamble();
11156 delta = dis_MMXop_regmem_to_reg (
11157 pfx, delta+2, insn[1], "paddq", False );
11158 goto decode_success;
11159 }
sewardj09717342005-05-05 21:34:02 +000011160
11161 /* 66 0F D4 = PADDQ */
11162 if (have66noF2noF3(pfx) && sz == 2
11163 && insn[0] == 0x0F && insn[1] == 0xD4) {
11164 delta = dis_SSEint_E_to_G( pfx, delta+2,
11165 "paddq", Iop_Add64x2, False );
11166 goto decode_success;
11167 }
11168
sewardj5992bd02005-05-11 02:13:42 +000011169 /* 66 0F FD = PADDW */
11170 if (have66noF2noF3(pfx) && sz == 2
11171 && insn[0] == 0x0F && insn[1] == 0xFD) {
11172 delta = dis_SSEint_E_to_G( pfx, delta+2,
11173 "paddw", Iop_Add16x8, False );
11174 goto decode_success;
11175 }
11176
11177 /* 66 0F EC = PADDSB */
11178 if (have66noF2noF3(pfx) && sz == 2
11179 && insn[0] == 0x0F && insn[1] == 0xEC) {
11180 delta = dis_SSEint_E_to_G( pfx, delta+2,
11181 "paddsb", Iop_QAdd8Sx16, False );
11182 goto decode_success;
11183 }
11184
11185 /* 66 0F ED = PADDSW */
11186 if (have66noF2noF3(pfx) && sz == 2
11187 && insn[0] == 0x0F && insn[1] == 0xED) {
11188 delta = dis_SSEint_E_to_G( pfx, delta+2,
11189 "paddsw", Iop_QAdd16Sx8, False );
11190 goto decode_success;
11191 }
11192
11193 /* 66 0F DC = PADDUSB */
11194 if (have66noF2noF3(pfx) && sz == 2
11195 && insn[0] == 0x0F && insn[1] == 0xDC) {
11196 delta = dis_SSEint_E_to_G( pfx, delta+2,
11197 "paddusb", Iop_QAdd8Ux16, False );
11198 goto decode_success;
11199 }
11200
11201 /* 66 0F DD = PADDUSW */
11202 if (have66noF2noF3(pfx) && sz == 2
11203 && insn[0] == 0x0F && insn[1] == 0xDD) {
11204 delta = dis_SSEint_E_to_G( pfx, delta+2,
11205 "paddusw", Iop_QAdd16Ux8, False );
11206 goto decode_success;
11207 }
sewardj09717342005-05-05 21:34:02 +000011208
11209 /* 66 0F DB = PAND */
11210 if (have66noF2noF3(pfx) && sz == 2
11211 && insn[0] == 0x0F && insn[1] == 0xDB) {
11212 delta = dis_SSE_E_to_G_all( pfx, delta+2, "pand", Iop_AndV128 );
11213 goto decode_success;
11214 }
11215
sewardj5992bd02005-05-11 02:13:42 +000011216 /* 66 0F DF = PANDN */
11217 if (have66noF2noF3(pfx) && sz == 2
11218 && insn[0] == 0x0F && insn[1] == 0xDF) {
11219 delta = dis_SSE_E_to_G_all_invG( pfx, delta+2, "pandn", Iop_AndV128 );
11220 goto decode_success;
11221 }
11222
11223 /* 66 0F E0 = PAVGB */
11224 if (have66noF2noF3(pfx) && sz == 2
11225 && insn[0] == 0x0F && insn[1] == 0xE0) {
11226 delta = dis_SSEint_E_to_G( pfx, delta+2,
11227 "pavgb", Iop_Avg8Ux16, False );
11228 goto decode_success;
11229 }
11230
11231 /* 66 0F E3 = PAVGW */
11232 if (have66noF2noF3(pfx) && sz == 2
11233 && insn[0] == 0x0F && insn[1] == 0xE3) {
11234 delta = dis_SSEint_E_to_G( pfx, delta+2,
11235 "pavgw", Iop_Avg16Ux8, False );
11236 goto decode_success;
11237 }
11238
11239 /* 66 0F 74 = PCMPEQB */
11240 if (have66noF2noF3(pfx) && sz == 2
11241 && insn[0] == 0x0F && insn[1] == 0x74) {
11242 delta = dis_SSEint_E_to_G( pfx, delta+2,
11243 "pcmpeqb", Iop_CmpEQ8x16, False );
11244 goto decode_success;
11245 }
11246
11247 /* 66 0F 76 = PCMPEQD */
11248 if (have66noF2noF3(pfx) && sz == 2
11249 && insn[0] == 0x0F && insn[1] == 0x76) {
11250 delta = dis_SSEint_E_to_G( pfx, delta+2,
11251 "pcmpeqd", Iop_CmpEQ32x4, False );
11252 goto decode_success;
11253 }
11254
11255 /* 66 0F 75 = PCMPEQW */
11256 if (have66noF2noF3(pfx) && sz == 2
11257 && insn[0] == 0x0F && insn[1] == 0x75) {
11258 delta = dis_SSEint_E_to_G( pfx, delta+2,
11259 "pcmpeqw", Iop_CmpEQ16x8, False );
11260 goto decode_success;
11261 }
11262
11263 /* 66 0F 64 = PCMPGTB */
11264 if (have66noF2noF3(pfx) && sz == 2
11265 && insn[0] == 0x0F && insn[1] == 0x64) {
11266 delta = dis_SSEint_E_to_G( pfx, delta+2,
11267 "pcmpgtb", Iop_CmpGT8Sx16, False );
11268 goto decode_success;
11269 }
11270
11271 /* 66 0F 66 = PCMPGTD */
11272 if (have66noF2noF3(pfx) && sz == 2
11273 && insn[0] == 0x0F && insn[1] == 0x66) {
11274 delta = dis_SSEint_E_to_G( pfx, delta+2,
11275 "pcmpgtd", Iop_CmpGT32Sx4, False );
11276 goto decode_success;
11277 }
11278
11279 /* 66 0F 65 = PCMPGTW */
11280 if (have66noF2noF3(pfx) && sz == 2
11281 && insn[0] == 0x0F && insn[1] == 0x65) {
11282 delta = dis_SSEint_E_to_G( pfx, delta+2,
11283 "pcmpgtw", Iop_CmpGT16Sx8, False );
11284 goto decode_success;
11285 }
sewardj97628592005-05-10 22:42:54 +000011286
11287 /* 66 0F C5 = PEXTRW -- extract 16-bit field from xmm(E) and put
11288 zero-extend of it in ireg(G). */
11289 if (have66noF2noF3(pfx) && sz == 2
11290 && insn[0] == 0x0F && insn[1] == 0xC5) {
11291 modrm = insn[2];
11292 if (epartIsReg(modrm)) {
11293 t5 = newTemp(Ity_V128);
11294 t4 = newTemp(Ity_I16);
11295 assign(t5, getXMMReg(eregOfRexRM(pfx,modrm)));
11296 breakup128to32s( t5, &t3, &t2, &t1, &t0 );
11297 switch (insn[3] & 7) {
11298 case 0: assign(t4, unop(Iop_32to16, mkexpr(t0))); break;
11299 case 1: assign(t4, unop(Iop_32HIto16, mkexpr(t0))); break;
11300 case 2: assign(t4, unop(Iop_32to16, mkexpr(t1))); break;
11301 case 3: assign(t4, unop(Iop_32HIto16, mkexpr(t1))); break;
11302 case 4: assign(t4, unop(Iop_32to16, mkexpr(t2))); break;
11303 case 5: assign(t4, unop(Iop_32HIto16, mkexpr(t2))); break;
11304 case 6: assign(t4, unop(Iop_32to16, mkexpr(t3))); break;
11305 case 7: assign(t4, unop(Iop_32HIto16, mkexpr(t3))); break;
11306 default: vassert(0);
11307 }
11308 putIReg32(gregOfRexRM(pfx,modrm), unop(Iop_16Uto32, mkexpr(t4)));
11309 DIP("pextrw $%d,%s,%s\n",
11310 (Int)insn[3], nameXMMReg(eregOfRexRM(pfx,modrm)),
11311 nameIReg32(gregOfRexRM(pfx,modrm)));
11312 delta += 4;
11313 goto decode_success;
11314 }
11315 /* else fall through */
11316 /* note, if memory case is ever filled in, there is 1 byte after
11317 amode */
11318 }
11319
11320 /* 66 0F C4 = PINSRW -- get 16 bits from E(mem or low half ireg) and
11321 put it into the specified lane of xmm(G). */
11322 if (have66noF2noF3(pfx) && sz == 2
11323 && insn[0] == 0x0F && insn[1] == 0xC4) {
11324 Int lane;
11325 t4 = newTemp(Ity_I16);
11326 modrm = insn[2];
11327
11328 if (epartIsReg(modrm)) {
11329 assign(t4, getIReg16(eregOfRexRM(pfx,modrm)));
11330 delta += 3+1;
11331 lane = insn[3+1-1];
11332 DIP("pinsrw $%d,%s,%s\n", (Int)lane,
11333 nameIReg16(eregOfRexRM(pfx,modrm)),
11334 nameXMMReg(gregOfRexRM(pfx,modrm)));
11335 } else {
11336 addr = disAMode ( &alen, pfx, delta+2, dis_buf,
11337 1/*byte after the amode*/ );
11338 delta += 3+alen;
11339 lane = insn[3+alen-1];
11340 assign(t4, loadLE(Ity_I16, mkexpr(addr)));
11341 DIP("pinsrw $%d,%s,%s\n", (Int)lane,
11342 dis_buf,
11343 nameXMMReg(gregOfRexRM(pfx,modrm)));
11344 }
11345
11346 putXMMRegLane16( gregOfRexRM(pfx,modrm), lane & 7, mkexpr(t4) );
11347 goto decode_success;
11348 }
11349
sewardjdb859032006-04-08 16:15:53 +000011350 /* 66 0F F5 = PMADDWD -- Multiply and add packed integers from
11351 E(xmm or mem) to G(xmm) */
11352 if (have66noF2noF3(pfx) && sz == 2
11353 && insn[0] == 0x0F && insn[1] == 0xF5) {
11354 IRTemp s1V = newTemp(Ity_V128);
11355 IRTemp s2V = newTemp(Ity_V128);
11356 IRTemp dV = newTemp(Ity_V128);
11357 IRTemp s1Hi = newTemp(Ity_I64);
11358 IRTemp s1Lo = newTemp(Ity_I64);
11359 IRTemp s2Hi = newTemp(Ity_I64);
11360 IRTemp s2Lo = newTemp(Ity_I64);
11361 IRTemp dHi = newTemp(Ity_I64);
11362 IRTemp dLo = newTemp(Ity_I64);
11363 modrm = insn[2];
11364 if (epartIsReg(modrm)) {
11365 assign( s1V, getXMMReg(eregOfRexRM(pfx,modrm)) );
11366 delta += 2+1;
11367 DIP("pmaddwd %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
11368 nameXMMReg(gregOfRexRM(pfx,modrm)));
11369 } else {
11370 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
11371 assign( s1V, loadLE(Ity_V128, mkexpr(addr)) );
11372 delta += 2+alen;
11373 DIP("pmaddwd %s,%s\n", dis_buf,
11374 nameXMMReg(gregOfRexRM(pfx,modrm)));
11375 }
11376 assign( s2V, getXMMReg(gregOfRexRM(pfx,modrm)) );
11377 assign( s1Hi, unop(Iop_V128HIto64, mkexpr(s1V)) );
11378 assign( s1Lo, unop(Iop_V128to64, mkexpr(s1V)) );
11379 assign( s2Hi, unop(Iop_V128HIto64, mkexpr(s2V)) );
11380 assign( s2Lo, unop(Iop_V128to64, mkexpr(s2V)) );
11381 assign( dHi, mkIRExprCCall(
11382 Ity_I64, 0/*regparms*/,
11383 "amd64g_calculate_mmx_pmaddwd",
11384 &amd64g_calculate_mmx_pmaddwd,
11385 mkIRExprVec_2( mkexpr(s1Hi), mkexpr(s2Hi))
11386 ));
11387 assign( dLo, mkIRExprCCall(
11388 Ity_I64, 0/*regparms*/,
11389 "amd64g_calculate_mmx_pmaddwd",
11390 &amd64g_calculate_mmx_pmaddwd,
11391 mkIRExprVec_2( mkexpr(s1Lo), mkexpr(s2Lo))
11392 ));
11393 assign( dV, binop(Iop_64HLtoV128, mkexpr(dHi), mkexpr(dLo))) ;
11394 putXMMReg(gregOfRexRM(pfx,modrm), mkexpr(dV));
11395 goto decode_success;
11396 }
11397
sewardjadffcef2005-05-11 00:03:06 +000011398 /* 66 0F EE = PMAXSW -- 16x8 signed max */
11399 if (have66noF2noF3(pfx) && sz == 2
11400 && insn[0] == 0x0F && insn[1] == 0xEE) {
11401 delta = dis_SSEint_E_to_G( pfx, delta+2,
11402 "pmaxsw", Iop_Max16Sx8, False );
11403 goto decode_success;
11404 }
11405
11406 /* 66 0F DE = PMAXUB -- 8x16 unsigned max */
11407 if (have66noF2noF3(pfx) && sz == 2
11408 && insn[0] == 0x0F && insn[1] == 0xDE) {
11409 delta = dis_SSEint_E_to_G( pfx, delta+2,
11410 "pmaxub", Iop_Max8Ux16, False );
11411 goto decode_success;
11412 }
11413
11414 /* 66 0F EA = PMINSW -- 16x8 signed min */
11415 if (have66noF2noF3(pfx) && sz == 2
11416 && insn[0] == 0x0F && insn[1] == 0xEA) {
11417 delta = dis_SSEint_E_to_G( pfx, delta+2,
11418 "pminsw", Iop_Min16Sx8, False );
11419 goto decode_success;
11420 }
11421
11422 /* 66 0F DA = PMINUB -- 8x16 unsigned min */
11423 if (have66noF2noF3(pfx) && sz == 2
11424 && insn[0] == 0x0F && insn[1] == 0xDA) {
11425 delta = dis_SSEint_E_to_G( pfx, delta+2,
11426 "pminub", Iop_Min8Ux16, False );
11427 goto decode_success;
11428 }
11429
11430 /* 66 0F D7 = PMOVMSKB -- extract sign bits from each of 16 lanes in
11431 xmm(E), turn them into a byte, and put zero-extend of it in
11432 ireg(G). Doing this directly is just too cumbersome; give up
11433 therefore and call a helper. */
11434 /* UInt x86g_calculate_sse_pmovmskb ( ULong w64hi, ULong w64lo ); */
11435 if (have66noF2noF3(pfx) && sz == 2
11436 && insn[0] == 0x0F && insn[1] == 0xD7) {
11437 modrm = insn[2];
11438 if (epartIsReg(modrm)) {
11439 t0 = newTemp(Ity_I64);
11440 t1 = newTemp(Ity_I64);
11441 assign(t0, getXMMRegLane64(eregOfRexRM(pfx,modrm), 0));
11442 assign(t1, getXMMRegLane64(eregOfRexRM(pfx,modrm), 1));
11443 t5 = newTemp(Ity_I64);
11444 assign(t5, mkIRExprCCall(
11445 Ity_I64, 0/*regparms*/,
11446 "amd64g_calculate_sse_pmovmskb",
11447 &amd64g_calculate_sse_pmovmskb,
11448 mkIRExprVec_2( mkexpr(t1), mkexpr(t0) )));
11449 putIReg32(gregOfRexRM(pfx,modrm), unop(Iop_64to32,mkexpr(t5)));
11450 DIP("pmovmskb %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
11451 nameIReg32(gregOfRexRM(pfx,modrm)));
11452 delta += 3;
11453 goto decode_success;
11454 }
11455 /* else fall through */
11456 }
11457
11458 /* 66 0F E4 = PMULHUW -- 16x8 hi-half of unsigned widening multiply */
11459 if (have66noF2noF3(pfx) && sz == 2
11460 && insn[0] == 0x0F && insn[1] == 0xE4) {
11461 delta = dis_SSEint_E_to_G( pfx, delta+2,
11462 "pmulhuw", Iop_MulHi16Ux8, False );
11463 goto decode_success;
11464 }
11465
11466 /* 66 0F E5 = PMULHW -- 16x8 hi-half of signed widening multiply */
11467 if (have66noF2noF3(pfx) && sz == 2
11468 && insn[0] == 0x0F && insn[1] == 0xE5) {
11469 delta = dis_SSEint_E_to_G( pfx, delta+2,
11470 "pmulhw", Iop_MulHi16Sx8, False );
11471 goto decode_success;
11472 }
11473
11474 /* 66 0F D5 = PMULHL -- 16x8 multiply */
11475 if (have66noF2noF3(pfx) && sz == 2
11476 && insn[0] == 0x0F && insn[1] == 0xD5) {
11477 delta = dis_SSEint_E_to_G( pfx, delta+2,
11478 "pmullw", Iop_Mul16x8, False );
11479 goto decode_success;
11480 }
11481
11482 /* ***--- this is an MMX class insn introduced in SSE2 ---*** */
11483 /* 0F F4 = PMULUDQ -- unsigned widening multiply of 32-lanes 0 x
11484 0 to form 64-bit result */
11485 if (haveNo66noF2noF3(pfx) && sz == 4
11486 && insn[0] == 0x0F && insn[1] == 0xF4) {
11487 IRTemp sV = newTemp(Ity_I64);
11488 IRTemp dV = newTemp(Ity_I64);
11489 t1 = newTemp(Ity_I32);
11490 t0 = newTemp(Ity_I32);
11491 modrm = insn[2];
11492
11493 do_MMX_preamble();
11494 assign( dV, getMMXReg(gregLO3ofRM(modrm)) );
11495
11496 if (epartIsReg(modrm)) {
11497 assign( sV, getMMXReg(eregLO3ofRM(modrm)) );
11498 delta += 2+1;
11499 DIP("pmuludq %s,%s\n", nameMMXReg(eregLO3ofRM(modrm)),
11500 nameMMXReg(gregLO3ofRM(modrm)));
11501 } else {
11502 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
11503 assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
11504 delta += 2+alen;
11505 DIP("pmuludq %s,%s\n", dis_buf,
11506 nameMMXReg(gregLO3ofRM(modrm)));
11507 }
11508
11509 assign( t0, unop(Iop_64to32, mkexpr(dV)) );
11510 assign( t1, unop(Iop_64to32, mkexpr(sV)) );
11511 putMMXReg( gregLO3ofRM(modrm),
11512 binop( Iop_MullU32, mkexpr(t0), mkexpr(t1) ) );
11513 goto decode_success;
11514 }
11515
11516 /* 66 0F F4 = PMULUDQ -- unsigned widening multiply of 32-lanes 0 x
11517 0 to form lower 64-bit half and lanes 2 x 2 to form upper 64-bit
11518 half */
11519 /* This is a really poor translation -- could be improved if
11520 performance critical */
11521 if (have66noF2noF3(pfx) && sz == 2
11522 && insn[0] == 0x0F && insn[1] == 0xF4) {
11523 IRTemp sV, dV;
11524 IRTemp s3, s2, s1, s0, d3, d2, d1, d0;
11525 sV = newTemp(Ity_V128);
11526 dV = newTemp(Ity_V128);
11527 s3 = s2 = s1 = s0 = d3 = d2 = d1 = d0 = IRTemp_INVALID;
11528 t1 = newTemp(Ity_I64);
11529 t0 = newTemp(Ity_I64);
11530 modrm = insn[2];
11531 assign( dV, getXMMReg(gregOfRexRM(pfx,modrm)) );
11532
11533 if (epartIsReg(modrm)) {
11534 assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
11535 delta += 2+1;
11536 DIP("pmuludq %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
11537 nameXMMReg(gregOfRexRM(pfx,modrm)));
11538 } else {
11539 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
11540 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
11541 delta += 2+alen;
11542 DIP("pmuludq %s,%s\n", dis_buf,
11543 nameXMMReg(gregOfRexRM(pfx,modrm)));
11544 }
11545
11546 breakup128to32s( dV, &d3, &d2, &d1, &d0 );
11547 breakup128to32s( sV, &s3, &s2, &s1, &s0 );
11548
11549 assign( t0, binop( Iop_MullU32, mkexpr(d0), mkexpr(s0)) );
11550 putXMMRegLane64( gregOfRexRM(pfx,modrm), 0, mkexpr(t0) );
11551 assign( t1, binop( Iop_MullU32, mkexpr(d2), mkexpr(s2)) );
11552 putXMMRegLane64( gregOfRexRM(pfx,modrm), 1, mkexpr(t1) );
11553 goto decode_success;
11554 }
sewardj09717342005-05-05 21:34:02 +000011555
11556 /* 66 0F EB = POR */
11557 if (have66noF2noF3(pfx) && sz == 2
11558 && insn[0] == 0x0F && insn[1] == 0xEB) {
11559 delta = dis_SSE_E_to_G_all( pfx, delta+2, "por", Iop_OrV128 );
11560 goto decode_success;
11561 }
11562
sewardj59e96c12006-07-24 08:51:16 +000011563 /* 66 0F F6 = PSADBW -- 2 x (8x8 -> 48 zeroes ++ u16) Sum Abs Diffs
11564 from E(xmm or mem) to G(xmm) */
11565 if (have66noF2noF3(pfx) && sz == 2
11566 && insn[0] == 0x0F && insn[1] == 0xF6) {
11567 IRTemp s1V = newTemp(Ity_V128);
11568 IRTemp s2V = newTemp(Ity_V128);
11569 IRTemp dV = newTemp(Ity_V128);
11570 IRTemp s1Hi = newTemp(Ity_I64);
11571 IRTemp s1Lo = newTemp(Ity_I64);
11572 IRTemp s2Hi = newTemp(Ity_I64);
11573 IRTemp s2Lo = newTemp(Ity_I64);
11574 IRTemp dHi = newTemp(Ity_I64);
11575 IRTemp dLo = newTemp(Ity_I64);
11576 modrm = insn[2];
11577 if (epartIsReg(modrm)) {
11578 assign( s1V, getXMMReg(eregOfRexRM(pfx,modrm)) );
11579 delta += 2+1;
11580 DIP("psadbw %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
11581 nameXMMReg(gregOfRexRM(pfx,modrm)));
11582 } else {
11583 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
11584 assign( s1V, loadLE(Ity_V128, mkexpr(addr)) );
11585 delta += 2+alen;
11586 DIP("psadbw %s,%s\n", dis_buf,
11587 nameXMMReg(gregOfRexRM(pfx,modrm)));
11588 }
11589 assign( s2V, getXMMReg(gregOfRexRM(pfx,modrm)) );
11590 assign( s1Hi, unop(Iop_V128HIto64, mkexpr(s1V)) );
11591 assign( s1Lo, unop(Iop_V128to64, mkexpr(s1V)) );
11592 assign( s2Hi, unop(Iop_V128HIto64, mkexpr(s2V)) );
11593 assign( s2Lo, unop(Iop_V128to64, mkexpr(s2V)) );
11594 assign( dHi, mkIRExprCCall(
11595 Ity_I64, 0/*regparms*/,
11596 "amd64g_calculate_mmx_psadbw",
11597 &amd64g_calculate_mmx_psadbw,
11598 mkIRExprVec_2( mkexpr(s1Hi), mkexpr(s2Hi))
11599 ));
11600 assign( dLo, mkIRExprCCall(
11601 Ity_I64, 0/*regparms*/,
11602 "amd64g_calculate_mmx_psadbw",
11603 &amd64g_calculate_mmx_psadbw,
11604 mkIRExprVec_2( mkexpr(s1Lo), mkexpr(s2Lo))
11605 ));
11606 assign( dV, binop(Iop_64HLtoV128, mkexpr(dHi), mkexpr(dLo))) ;
11607 putXMMReg(gregOfRexRM(pfx,modrm), mkexpr(dV));
11608 goto decode_success;
11609 }
11610
sewardjadffcef2005-05-11 00:03:06 +000011611 /* 66 0F 70 = PSHUFD -- rearrange 4x32 from E(xmm or mem) to G(xmm) */
11612 if (have66noF2noF3(pfx) && sz == 2
11613 && insn[0] == 0x0F && insn[1] == 0x70) {
11614 Int order;
11615 IRTemp sV, dV, s3, s2, s1, s0;
11616 s3 = s2 = s1 = s0 = IRTemp_INVALID;
11617 sV = newTemp(Ity_V128);
11618 dV = newTemp(Ity_V128);
11619 modrm = insn[2];
11620 if (epartIsReg(modrm)) {
11621 assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
11622 order = (Int)insn[3];
11623 delta += 3+1;
11624 DIP("pshufd $%d,%s,%s\n", order,
11625 nameXMMReg(eregOfRexRM(pfx,modrm)),
11626 nameXMMReg(gregOfRexRM(pfx,modrm)));
11627 } else {
11628 addr = disAMode ( &alen, pfx, delta+2, dis_buf,
11629 1/*byte after the amode*/ );
11630 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
11631 order = (Int)insn[2+alen];
11632 delta += 2+alen+1;
11633 DIP("pshufd $%d,%s,%s\n", order,
11634 dis_buf,
11635 nameXMMReg(gregOfRexRM(pfx,modrm)));
11636 }
11637 breakup128to32s( sV, &s3, &s2, &s1, &s0 );
11638
11639# define SEL(n) \
11640 ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
11641 assign(dV,
11642 mk128from32s( SEL((order>>6)&3), SEL((order>>4)&3),
11643 SEL((order>>2)&3), SEL((order>>0)&3) )
11644 );
11645 putXMMReg(gregOfRexRM(pfx,modrm), mkexpr(dV));
11646# undef SEL
11647 goto decode_success;
11648 }
11649
11650 /* F3 0F 70 = PSHUFHW -- rearrange upper half 4x16 from E(xmm or
11651 mem) to G(xmm), and copy lower half */
11652 if (haveF3no66noF2(pfx) && sz == 4
11653 && insn[0] == 0x0F && insn[1] == 0x70) {
11654 Int order;
11655 IRTemp sVhi, dVhi, sV, dV, s3, s2, s1, s0;
11656 s3 = s2 = s1 = s0 = IRTemp_INVALID;
11657 sV = newTemp(Ity_V128);
11658 dV = newTemp(Ity_V128);
11659 sVhi = newTemp(Ity_I64);
11660 dVhi = newTemp(Ity_I64);
11661 modrm = insn[2];
11662 if (epartIsReg(modrm)) {
11663 assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
11664 order = (Int)insn[3];
11665 delta += 3+1;
11666 DIP("pshufhw $%d,%s,%s\n", order,
11667 nameXMMReg(eregOfRexRM(pfx,modrm)),
11668 nameXMMReg(gregOfRexRM(pfx,modrm)));
11669 } else {
11670 addr = disAMode ( &alen, pfx, delta+2, dis_buf,
11671 1/*byte after the amode*/ );
11672 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
11673 order = (Int)insn[2+alen];
11674 delta += 2+alen+1;
11675 DIP("pshufhw $%d,%s,%s\n", order,
11676 dis_buf,
11677 nameXMMReg(gregOfRexRM(pfx,modrm)));
11678 }
11679 assign( sVhi, unop(Iop_V128HIto64, mkexpr(sV)) );
11680 breakup64to16s( sVhi, &s3, &s2, &s1, &s0 );
11681
11682# define SEL(n) \
11683 ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
11684 assign(dVhi,
11685 mk64from16s( SEL((order>>6)&3), SEL((order>>4)&3),
11686 SEL((order>>2)&3), SEL((order>>0)&3) )
11687 );
11688 assign(dV, binop( Iop_64HLtoV128,
11689 mkexpr(dVhi),
11690 unop(Iop_V128to64, mkexpr(sV))) );
11691 putXMMReg(gregOfRexRM(pfx,modrm), mkexpr(dV));
11692# undef SEL
11693 goto decode_success;
11694 }
11695
11696 /* F2 0F 70 = PSHUFLW -- rearrange lower half 4x16 from E(xmm or
11697 mem) to G(xmm), and copy upper half */
11698 if (haveF2no66noF3(pfx) && sz == 4
11699 && insn[0] == 0x0F && insn[1] == 0x70) {
11700 Int order;
11701 IRTemp sVlo, dVlo, sV, dV, s3, s2, s1, s0;
11702 s3 = s2 = s1 = s0 = IRTemp_INVALID;
11703 sV = newTemp(Ity_V128);
11704 dV = newTemp(Ity_V128);
11705 sVlo = newTemp(Ity_I64);
11706 dVlo = newTemp(Ity_I64);
11707 modrm = insn[2];
11708 if (epartIsReg(modrm)) {
11709 assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
11710 order = (Int)insn[3];
11711 delta += 3+1;
11712 DIP("pshuflw $%d,%s,%s\n", order,
11713 nameXMMReg(eregOfRexRM(pfx,modrm)),
11714 nameXMMReg(gregOfRexRM(pfx,modrm)));
11715 } else {
11716 addr = disAMode ( &alen, pfx, delta+2, dis_buf,
11717 1/*byte after the amode*/ );
11718 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
11719 order = (Int)insn[2+alen];
11720 delta += 2+alen+1;
11721 DIP("pshuflw $%d,%s,%s\n", order,
11722 dis_buf,
11723 nameXMMReg(gregOfRexRM(pfx,modrm)));
11724 }
11725 assign( sVlo, unop(Iop_V128to64, mkexpr(sV)) );
11726 breakup64to16s( sVlo, &s3, &s2, &s1, &s0 );
11727
11728# define SEL(n) \
11729 ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
11730 assign(dVlo,
11731 mk64from16s( SEL((order>>6)&3), SEL((order>>4)&3),
11732 SEL((order>>2)&3), SEL((order>>0)&3) )
11733 );
11734 assign(dV, binop( Iop_64HLtoV128,
11735 unop(Iop_V128HIto64, mkexpr(sV)),
11736 mkexpr(dVlo) ) );
11737 putXMMReg(gregOfRexRM(pfx,modrm), mkexpr(dV));
11738# undef SEL
11739 goto decode_success;
11740 }
11741
11742 /* 66 0F 72 /6 ib = PSLLD by immediate */
11743 if (have66noF2noF3(pfx) && sz == 2
11744 && insn[0] == 0x0F && insn[1] == 0x72
11745 && epartIsReg(insn[2])
11746 && gregLO3ofRM(insn[2]) == 6) {
11747 delta = dis_SSE_shiftE_imm( pfx, delta+2, "pslld", Iop_ShlN32x4 );
11748 goto decode_success;
11749 }
11750
11751 /* 66 0F F2 = PSLLD by E */
11752 if (have66noF2noF3(pfx) && sz == 2
11753 && insn[0] == 0x0F && insn[1] == 0xF2) {
11754 delta = dis_SSE_shiftG_byE( pfx, delta+2, "pslld", Iop_ShlN32x4 );
11755 goto decode_success;
11756 }
sewardj97628592005-05-10 22:42:54 +000011757
11758 /* 66 0F 73 /7 ib = PSLLDQ by immediate */
11759 /* note, if mem case ever filled in, 1 byte after amode */
11760 if (have66noF2noF3(pfx) && sz == 2
11761 && insn[0] == 0x0F && insn[1] == 0x73
11762 && epartIsReg(insn[2])
11763 && gregLO3ofRM(insn[2]) == 7) {
11764 IRTemp sV, dV, hi64, lo64, hi64r, lo64r;
11765 Int imm = (Int)insn[3];
11766 Int reg = eregOfRexRM(pfx,insn[2]);
11767 DIP("pslldq $%d,%s\n", imm, nameXMMReg(reg));
11768 vassert(imm >= 0 && imm <= 255);
11769 delta += 4;
11770
11771 sV = newTemp(Ity_V128);
11772 dV = newTemp(Ity_V128);
11773 hi64 = newTemp(Ity_I64);
11774 lo64 = newTemp(Ity_I64);
11775 hi64r = newTemp(Ity_I64);
11776 lo64r = newTemp(Ity_I64);
11777
11778 if (imm >= 16) {
11779 putXMMReg(reg, mkV128(0x0000));
11780 goto decode_success;
11781 }
11782
11783 assign( sV, getXMMReg(reg) );
11784 assign( hi64, unop(Iop_V128HIto64, mkexpr(sV)) );
11785 assign( lo64, unop(Iop_V128to64, mkexpr(sV)) );
11786
11787 if (imm == 0) {
11788 assign( lo64r, mkexpr(lo64) );
11789 assign( hi64r, mkexpr(hi64) );
11790 }
11791 else
11792 if (imm == 8) {
11793 assign( lo64r, mkU64(0) );
11794 assign( hi64r, mkexpr(lo64) );
11795 }
11796 else
11797 if (imm > 8) {
11798 assign( lo64r, mkU64(0) );
11799 assign( hi64r, binop( Iop_Shl64,
11800 mkexpr(lo64),
11801 mkU8( 8*(imm-8) ) ));
11802 } else {
11803 assign( lo64r, binop( Iop_Shl64,
11804 mkexpr(lo64),
11805 mkU8(8 * imm) ));
11806 assign( hi64r,
11807 binop( Iop_Or64,
11808 binop(Iop_Shl64, mkexpr(hi64),
11809 mkU8(8 * imm)),
11810 binop(Iop_Shr64, mkexpr(lo64),
11811 mkU8(8 * (8 - imm)) )
11812 )
11813 );
11814 }
11815 assign( dV, binop(Iop_64HLtoV128, mkexpr(hi64r), mkexpr(lo64r)) );
11816 putXMMReg(reg, mkexpr(dV));
11817 goto decode_success;
11818 }
11819
sewardjadffcef2005-05-11 00:03:06 +000011820 /* 66 0F 73 /6 ib = PSLLQ by immediate */
11821 if (have66noF2noF3(pfx) && sz == 2
11822 && insn[0] == 0x0F && insn[1] == 0x73
11823 && epartIsReg(insn[2])
11824 && gregLO3ofRM(insn[2]) == 6) {
11825 delta = dis_SSE_shiftE_imm( pfx, delta+2, "psllq", Iop_ShlN64x2 );
11826 goto decode_success;
11827 }
11828
11829 /* 66 0F F3 = PSLLQ by E */
11830 if (have66noF2noF3(pfx) && sz == 2
11831 && insn[0] == 0x0F && insn[1] == 0xF3) {
11832 delta = dis_SSE_shiftG_byE( pfx, delta+2, "psllq", Iop_ShlN64x2 );
11833 goto decode_success;
11834 }
11835
11836 /* 66 0F 71 /6 ib = PSLLW by immediate */
11837 if (have66noF2noF3(pfx) && sz == 2
11838 && insn[0] == 0x0F && insn[1] == 0x71
11839 && epartIsReg(insn[2])
11840 && gregLO3ofRM(insn[2]) == 6) {
11841 delta = dis_SSE_shiftE_imm( pfx, delta+2, "psllw", Iop_ShlN16x8 );
11842 goto decode_success;
11843 }
11844
11845 /* 66 0F F1 = PSLLW by E */
11846 if (have66noF2noF3(pfx) && sz == 2
11847 && insn[0] == 0x0F && insn[1] == 0xF1) {
11848 delta = dis_SSE_shiftG_byE( pfx, delta+2, "psllw", Iop_ShlN16x8 );
11849 goto decode_success;
11850 }
11851
11852 /* 66 0F 72 /4 ib = PSRAD by immediate */
11853 if (have66noF2noF3(pfx) && sz == 2
11854 && insn[0] == 0x0F && insn[1] == 0x72
11855 && epartIsReg(insn[2])
11856 && gregLO3ofRM(insn[2]) == 4) {
11857 delta = dis_SSE_shiftE_imm( pfx, delta+2, "psrad", Iop_SarN32x4 );
11858 goto decode_success;
11859 }
11860
11861 /* 66 0F E2 = PSRAD by E */
11862 if (have66noF2noF3(pfx) && sz == 2
11863 && insn[0] == 0x0F && insn[1] == 0xE2) {
11864 delta = dis_SSE_shiftG_byE( pfx, delta+2, "psrad", Iop_SarN32x4 );
11865 goto decode_success;
11866 }
11867
11868 /* 66 0F 71 /4 ib = PSRAW by immediate */
11869 if (have66noF2noF3(pfx) && sz == 2
11870 && insn[0] == 0x0F && insn[1] == 0x71
11871 && epartIsReg(insn[2])
11872 && gregLO3ofRM(insn[2]) == 4) {
11873 delta = dis_SSE_shiftE_imm( pfx, delta+2, "psraw", Iop_SarN16x8 );
11874 goto decode_success;
11875 }
11876
11877 /* 66 0F E1 = PSRAW by E */
11878 if (have66noF2noF3(pfx) && sz == 2
11879 && insn[0] == 0x0F && insn[1] == 0xE1) {
11880 delta = dis_SSE_shiftG_byE( pfx, delta+2, "psraw", Iop_SarN16x8 );
11881 goto decode_success;
11882 }
11883
11884 /* 66 0F 72 /2 ib = PSRLD by immediate */
11885 if (have66noF2noF3(pfx) && sz == 2
11886 && insn[0] == 0x0F && insn[1] == 0x72
11887 && epartIsReg(insn[2])
11888 && gregLO3ofRM(insn[2]) == 2) {
11889 delta = dis_SSE_shiftE_imm( pfx, delta+2, "psrld", Iop_ShrN32x4 );
11890 goto decode_success;
11891 }
11892
11893 /* 66 0F D2 = PSRLD by E */
11894 if (have66noF2noF3(pfx) && sz == 2
11895 && insn[0] == 0x0F && insn[1] == 0xD2) {
11896 delta = dis_SSE_shiftG_byE( pfx, delta+2, "psrld", Iop_ShrN32x4 );
11897 goto decode_success;
11898 }
sewardj97628592005-05-10 22:42:54 +000011899
11900 /* 66 0F 73 /3 ib = PSRLDQ by immediate */
11901 /* note, if mem case ever filled in, 1 byte after amode */
11902 if (have66noF2noF3(pfx) && sz == 2
11903 && insn[0] == 0x0F && insn[1] == 0x73
11904 && epartIsReg(insn[2])
11905 && gregLO3ofRM(insn[2]) == 3) {
11906 IRTemp sV, dV, hi64, lo64, hi64r, lo64r;
11907 Int imm = (Int)insn[3];
11908 Int reg = eregOfRexRM(pfx,insn[2]);
11909 DIP("psrldq $%d,%s\n", imm, nameXMMReg(reg));
11910 vassert(imm >= 0 && imm <= 255);
11911 delta += 4;
11912
11913 sV = newTemp(Ity_V128);
11914 dV = newTemp(Ity_V128);
11915 hi64 = newTemp(Ity_I64);
11916 lo64 = newTemp(Ity_I64);
11917 hi64r = newTemp(Ity_I64);
11918 lo64r = newTemp(Ity_I64);
11919
11920 if (imm >= 16) {
11921 putXMMReg(reg, mkV128(0x0000));
11922 goto decode_success;
11923 }
11924
11925 assign( sV, getXMMReg(reg) );
11926 assign( hi64, unop(Iop_V128HIto64, mkexpr(sV)) );
11927 assign( lo64, unop(Iop_V128to64, mkexpr(sV)) );
11928
11929 if (imm == 0) {
11930 assign( lo64r, mkexpr(lo64) );
11931 assign( hi64r, mkexpr(hi64) );
11932 }
11933 else
11934 if (imm == 8) {
11935 assign( hi64r, mkU64(0) );
11936 assign( lo64r, mkexpr(hi64) );
11937 }
11938 else
11939 if (imm > 8) {
11940 assign( hi64r, mkU64(0) );
11941 assign( lo64r, binop( Iop_Shr64,
11942 mkexpr(hi64),
11943 mkU8( 8*(imm-8) ) ));
11944 } else {
11945 assign( hi64r, binop( Iop_Shr64,
11946 mkexpr(hi64),
11947 mkU8(8 * imm) ));
11948 assign( lo64r,
11949 binop( Iop_Or64,
11950 binop(Iop_Shr64, mkexpr(lo64),
11951 mkU8(8 * imm)),
11952 binop(Iop_Shl64, mkexpr(hi64),
11953 mkU8(8 * (8 - imm)) )
11954 )
11955 );
11956 }
11957
11958 assign( dV, binop(Iop_64HLtoV128, mkexpr(hi64r), mkexpr(lo64r)) );
11959 putXMMReg(reg, mkexpr(dV));
11960 goto decode_success;
11961 }
sewardj09717342005-05-05 21:34:02 +000011962
11963 /* 66 0F 73 /2 ib = PSRLQ by immediate */
11964 if (have66noF2noF3(pfx) && sz == 2
11965 && insn[0] == 0x0F && insn[1] == 0x73
11966 && epartIsReg(insn[2])
11967 && gregLO3ofRM(insn[2]) == 2) {
11968 delta = dis_SSE_shiftE_imm( pfx, delta+2, "psrlq", Iop_ShrN64x2 );
11969 goto decode_success;
11970 }
11971
sewardjadffcef2005-05-11 00:03:06 +000011972 /* 66 0F D3 = PSRLQ by E */
11973 if (have66noF2noF3(pfx) && sz == 2
11974 && insn[0] == 0x0F && insn[1] == 0xD3) {
11975 delta = dis_SSE_shiftG_byE( pfx, delta+2, "psrlq", Iop_ShrN64x2 );
11976 goto decode_success;
11977 }
11978
11979 /* 66 0F 71 /2 ib = PSRLW by immediate */
11980 if (have66noF2noF3(pfx) && sz == 2
11981 && insn[0] == 0x0F && insn[1] == 0x71
11982 && epartIsReg(insn[2])
11983 && gregLO3ofRM(insn[2]) == 2) {
11984 delta = dis_SSE_shiftE_imm( pfx, delta+2, "psrlw", Iop_ShrN16x8 );
11985 goto decode_success;
11986 }
11987
11988 /* 66 0F D1 = PSRLW by E */
11989 if (have66noF2noF3(pfx) && sz == 2
11990 && insn[0] == 0x0F && insn[1] == 0xD1) {
11991 delta = dis_SSE_shiftG_byE( pfx, delta+2, "psrlw", Iop_ShrN16x8 );
11992 goto decode_success;
11993 }
sewardj97628592005-05-10 22:42:54 +000011994
11995 /* 66 0F F8 = PSUBB */
11996 if (have66noF2noF3(pfx) && sz == 2
11997 && insn[0] == 0x0F && insn[1] == 0xF8) {
11998 delta = dis_SSEint_E_to_G( pfx, delta+2,
11999 "psubb", Iop_Sub8x16, False );
12000 goto decode_success;
12001 }
12002
12003 /* 66 0F FA = PSUBD */
12004 if (have66noF2noF3(pfx) && sz == 2
12005 && insn[0] == 0x0F && insn[1] == 0xFA) {
12006 delta = dis_SSEint_E_to_G( pfx, delta+2,
12007 "psubd", Iop_Sub32x4, False );
12008 goto decode_success;
12009 }
sewardj8711f662005-05-09 17:52:56 +000012010
12011 /* ***--- this is an MMX class insn introduced in SSE2 ---*** */
12012 /* 0F FB = PSUBQ -- sub 64x1 */
12013 if (haveNo66noF2noF3(pfx) && sz == 4
12014 && insn[0] == 0x0F && insn[1] == 0xFB) {
12015 do_MMX_preamble();
12016 delta = dis_MMXop_regmem_to_reg (
12017 pfx, delta+2, insn[1], "psubq", False );
12018 goto decode_success;
12019 }
sewardj09717342005-05-05 21:34:02 +000012020
12021 /* 66 0F FB = PSUBQ */
12022 if (have66noF2noF3(pfx) && sz == 2
12023 && insn[0] == 0x0F && insn[1] == 0xFB) {
12024 delta = dis_SSEint_E_to_G( pfx, delta+2,
12025 "psubq", Iop_Sub64x2, False );
12026 goto decode_success;
12027 }
12028
sewardj97628592005-05-10 22:42:54 +000012029 /* 66 0F F9 = PSUBW */
12030 if (have66noF2noF3(pfx) && sz == 2
12031 && insn[0] == 0x0F && insn[1] == 0xF9) {
12032 delta = dis_SSEint_E_to_G( pfx, delta+2,
12033 "psubw", Iop_Sub16x8, False );
12034 goto decode_success;
12035 }
12036
12037 /* 66 0F E8 = PSUBSB */
12038 if (have66noF2noF3(pfx) && sz == 2
12039 && insn[0] == 0x0F && insn[1] == 0xE8) {
12040 delta = dis_SSEint_E_to_G( pfx, delta+2,
12041 "psubsb", Iop_QSub8Sx16, False );
12042 goto decode_success;
12043 }
12044
12045 /* 66 0F E9 = PSUBSW */
12046 if (have66noF2noF3(pfx) && sz == 2
12047 && insn[0] == 0x0F && insn[1] == 0xE9) {
12048 delta = dis_SSEint_E_to_G( pfx, delta+2,
12049 "psubsw", Iop_QSub16Sx8, False );
12050 goto decode_success;
12051 }
12052
12053 /* 66 0F D8 = PSUBSB */
12054 if (have66noF2noF3(pfx) && sz == 2
12055 && insn[0] == 0x0F && insn[1] == 0xD8) {
12056 delta = dis_SSEint_E_to_G( pfx, delta+2,
12057 "psubusb", Iop_QSub8Ux16, False );
12058 goto decode_success;
12059 }
12060
12061 /* 66 0F D9 = PSUBSW */
12062 if (have66noF2noF3(pfx) && sz == 2
12063 && insn[0] == 0x0F && insn[1] == 0xD9) {
12064 delta = dis_SSEint_E_to_G( pfx, delta+2,
12065 "psubusw", Iop_QSub16Ux8, False );
12066 goto decode_success;
12067 }
12068
12069 /* 66 0F 68 = PUNPCKHBW */
12070 if (have66noF2noF3(pfx) && sz == 2
12071 && insn[0] == 0x0F && insn[1] == 0x68) {
12072 delta = dis_SSEint_E_to_G( pfx, delta+2,
12073 "punpckhbw",
12074 Iop_InterleaveHI8x16, True );
12075 goto decode_success;
12076 }
12077
12078 /* 66 0F 6A = PUNPCKHDQ */
12079 if (have66noF2noF3(pfx) && sz == 2
12080 && insn[0] == 0x0F && insn[1] == 0x6A) {
12081 delta = dis_SSEint_E_to_G( pfx, delta+2,
12082 "punpckhdq",
12083 Iop_InterleaveHI32x4, True );
12084 goto decode_success;
12085 }
12086
12087 /* 66 0F 6D = PUNPCKHQDQ */
12088 if (have66noF2noF3(pfx) && sz == 2
12089 && insn[0] == 0x0F && insn[1] == 0x6D) {
12090 delta = dis_SSEint_E_to_G( pfx, delta+2,
12091 "punpckhqdq",
12092 Iop_InterleaveHI64x2, True );
12093 goto decode_success;
12094 }
12095
12096 /* 66 0F 69 = PUNPCKHWD */
12097 if (have66noF2noF3(pfx) && sz == 2
12098 && insn[0] == 0x0F && insn[1] == 0x69) {
12099 delta = dis_SSEint_E_to_G( pfx, delta+2,
12100 "punpckhwd",
12101 Iop_InterleaveHI16x8, True );
12102 goto decode_success;
12103 }
12104
12105 /* 66 0F 60 = PUNPCKLBW */
12106 if (have66noF2noF3(pfx) && sz == 2
12107 && insn[0] == 0x0F && insn[1] == 0x60) {
12108 delta = dis_SSEint_E_to_G( pfx, delta+2,
12109 "punpcklbw",
12110 Iop_InterleaveLO8x16, True );
12111 goto decode_success;
12112 }
12113
12114 /* 66 0F 62 = PUNPCKLDQ */
12115 if (have66noF2noF3(pfx) && sz == 2
12116 && insn[0] == 0x0F && insn[1] == 0x62) {
12117 delta = dis_SSEint_E_to_G( pfx, delta+2,
12118 "punpckldq",
12119 Iop_InterleaveLO32x4, True );
12120 goto decode_success;
12121 }
12122
12123 /* 66 0F 6C = PUNPCKLQDQ */
12124 if (have66noF2noF3(pfx) && sz == 2
12125 && insn[0] == 0x0F && insn[1] == 0x6C) {
12126 delta = dis_SSEint_E_to_G( pfx, delta+2,
12127 "punpcklqdq",
12128 Iop_InterleaveLO64x2, True );
12129 goto decode_success;
12130 }
12131
12132 /* 66 0F 61 = PUNPCKLWD */
12133 if (have66noF2noF3(pfx) && sz == 2
12134 && insn[0] == 0x0F && insn[1] == 0x61) {
12135 delta = dis_SSEint_E_to_G( pfx, delta+2,
12136 "punpcklwd",
12137 Iop_InterleaveLO16x8, True );
12138 goto decode_success;
12139 }
sewardj09717342005-05-05 21:34:02 +000012140
12141 /* 66 0F EF = PXOR */
12142 if (have66noF2noF3(pfx) && sz == 2
12143 && insn[0] == 0x0F && insn[1] == 0xEF) {
12144 delta = dis_SSE_E_to_G_all( pfx, delta+2, "pxor", Iop_XorV128 );
12145 goto decode_success;
12146 }
12147
sewardjd20c8852005-01-20 20:04:07 +000012148//.. //-- /* FXSAVE/FXRSTOR m32 -- load/store the FPU/MMX/SSE state. */
12149//.. //-- if (insn[0] == 0x0F && insn[1] == 0xAE
12150//.. //-- && (!epartIsReg(insn[2]))
12151//.. //-- && (gregOfRM(insn[2]) == 1 || gregOfRM(insn[2]) == 0) ) {
12152//.. //-- Bool store = gregOfRM(insn[2]) == 0;
12153//.. //-- vg_assert(sz == 4);
12154//.. //-- pair = disAMode ( cb, sorb, eip+2, dis_buf );
12155//.. //-- t1 = LOW24(pair);
12156//.. //-- eip += 2+HI8(pair);
12157//.. //-- uInstr3(cb, store ? SSE2a_MemWr : SSE2a_MemRd, 512,
12158//.. //-- Lit16, (((UShort)insn[0]) << 8) | (UShort)insn[1],
12159//.. //-- Lit16, (UShort)insn[2],
12160//.. //-- TempReg, t1 );
12161//.. //-- DIP("fx%s %s\n", store ? "save" : "rstor", dis_buf );
12162//.. //-- goto decode_success;
12163//.. //-- }
sewardj3e616e62006-01-07 22:58:54 +000012164
12165 /* 0F AE /7 = CLFLUSH -- flush cache line */
12166 if (haveNo66noF2noF3(pfx) && sz == 4
12167 && insn[0] == 0x0F && insn[1] == 0xAE
12168 && !epartIsReg(insn[2]) && gregLO3ofRM(insn[2]) == 7) {
12169
12170 /* This is something of a hack. We need to know the size of the
12171 cache line containing addr. Since we don't (easily), assume
12172 256 on the basis that no real cache would have a line that
12173 big. It's safe to invalidate more stuff than we need, just
12174 inefficient. */
12175 ULong lineszB = 256ULL;
12176
12177 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
12178 delta += 2+alen;
12179
12180 /* Round addr down to the start of the containing block. */
12181 stmt( IRStmt_Put(
12182 OFFB_TISTART,
12183 binop( Iop_And64,
12184 mkexpr(addr),
12185 mkU64( ~(lineszB-1) ))) );
12186
12187 stmt( IRStmt_Put(OFFB_TILEN, mkU64(lineszB) ) );
12188
sewardjdd40fdf2006-12-24 02:20:24 +000012189 irsb->jumpkind = Ijk_TInval;
12190 irsb->next = mkU64(guest_RIP_bbstart+delta);
sewardj3e616e62006-01-07 22:58:54 +000012191 dres.whatNext = Dis_StopHere;
12192
12193 DIP("clflush %s\n", dis_buf);
12194 goto decode_success;
12195 }
sewardjdf0e0022005-01-25 15:48:43 +000012196
sewardjdf0e0022005-01-25 15:48:43 +000012197 /* ---------------------------------------------------- */
12198 /* --- end of the SSE/SSE2 decoder. --- */
12199 /* ---------------------------------------------------- */
12200
sewardjfcf21f32006-08-04 14:51:19 +000012201 /* ---------------------------------------------------- */
12202 /* --- start of the SSE3 decoder. --- */
12203 /* ---------------------------------------------------- */
12204
12205 /* F3 0F 12 = MOVSLDUP -- move from E (mem or xmm) to G (xmm),
12206 duplicating some lanes (2:2:0:0). */
12207 /* F3 0F 16 = MOVSHDUP -- move from E (mem or xmm) to G (xmm),
12208 duplicating some lanes (3:3:1:1). */
12209 if (haveF3no66noF2(pfx) && sz == 4
12210 && insn[0] == 0x0F && (insn[1] == 0x12 || insn[1] == 0x16)) {
12211 IRTemp s3, s2, s1, s0;
12212 IRTemp sV = newTemp(Ity_V128);
12213 Bool isH = insn[1] == 0x16;
12214 s3 = s2 = s1 = s0 = IRTemp_INVALID;
12215
12216 modrm = insn[2];
12217 if (epartIsReg(modrm)) {
12218 assign( sV, getXMMReg( eregOfRexRM(pfx,modrm)) );
12219 DIP("movs%cdup %s,%s\n", isH ? 'h' : 'l',
12220 nameXMMReg(eregOfRexRM(pfx,modrm)),
12221 nameXMMReg(gregOfRexRM(pfx,modrm)));
12222 delta += 2+1;
12223 } else {
12224 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
12225 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
12226 DIP("movs%cdup %s,%s\n", isH ? 'h' : 'l',
12227 dis_buf,
12228 nameXMMReg(gregOfRexRM(pfx,modrm)));
12229 delta += 2+alen;
12230 }
12231
12232 breakup128to32s( sV, &s3, &s2, &s1, &s0 );
12233 putXMMReg( gregOfRexRM(pfx,modrm),
12234 isH ? mk128from32s( s3, s3, s1, s1 )
12235 : mk128from32s( s2, s2, s0, s0 ) );
12236 goto decode_success;
12237 }
12238
12239 /* F2 0F 12 = MOVDDUP -- move from E (mem or xmm) to G (xmm),
12240 duplicating some lanes (0:1:0:1). */
sewardjb4bf5882007-11-06 20:39:17 +000012241 if (haveF2no66noF3(pfx)
12242 && (sz == 4 || /* ignore redundant REX.W */ sz == 8)
sewardjfcf21f32006-08-04 14:51:19 +000012243 && insn[0] == 0x0F && insn[1] == 0x12) {
12244 IRTemp sV = newTemp(Ity_V128);
12245 IRTemp d0 = newTemp(Ity_I64);
12246
12247 modrm = insn[2];
12248 if (epartIsReg(modrm)) {
12249 assign( sV, getXMMReg( eregOfRexRM(pfx,modrm)) );
12250 DIP("movddup %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
12251 nameXMMReg(gregOfRexRM(pfx,modrm)));
12252 delta += 2+1;
12253 assign ( d0, unop(Iop_V128to64, mkexpr(sV)) );
12254 } else {
12255 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
12256 assign( d0, loadLE(Ity_I64, mkexpr(addr)) );
12257 DIP("movddup %s,%s\n", dis_buf,
12258 nameXMMReg(gregOfRexRM(pfx,modrm)));
12259 delta += 2+alen;
12260 }
12261
12262 putXMMReg( gregOfRexRM(pfx,modrm),
12263 binop(Iop_64HLtoV128,mkexpr(d0),mkexpr(d0)) );
12264 goto decode_success;
12265 }
12266
12267 /* F2 0F D0 = ADDSUBPS -- 32x4 +/-/+/- from E (mem or xmm) to G (xmm). */
12268 if (haveF2no66noF3(pfx) && sz == 4
12269 && insn[0] == 0x0F && insn[1] == 0xD0) {
12270 IRTemp a3, a2, a1, a0, s3, s2, s1, s0;
12271 IRTemp eV = newTemp(Ity_V128);
12272 IRTemp gV = newTemp(Ity_V128);
12273 IRTemp addV = newTemp(Ity_V128);
12274 IRTemp subV = newTemp(Ity_V128);
12275 a3 = a2 = a1 = a0 = s3 = s2 = s1 = s0 = IRTemp_INVALID;
12276
12277 modrm = insn[2];
12278 if (epartIsReg(modrm)) {
12279 assign( eV, getXMMReg( eregOfRexRM(pfx,modrm)) );
12280 DIP("addsubps %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
12281 nameXMMReg(gregOfRexRM(pfx,modrm)));
12282 delta += 2+1;
12283 } else {
12284 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
12285 assign( eV, loadLE(Ity_V128, mkexpr(addr)) );
12286 DIP("addsubps %s,%s\n", dis_buf,
12287 nameXMMReg(gregOfRexRM(pfx,modrm)));
12288 delta += 2+alen;
12289 }
12290
12291 assign( gV, getXMMReg(gregOfRexRM(pfx,modrm)) );
12292
12293 assign( addV, binop(Iop_Add32Fx4, mkexpr(gV), mkexpr(eV)) );
12294 assign( subV, binop(Iop_Sub32Fx4, mkexpr(gV), mkexpr(eV)) );
12295
12296 breakup128to32s( addV, &a3, &a2, &a1, &a0 );
12297 breakup128to32s( subV, &s3, &s2, &s1, &s0 );
12298
12299 putXMMReg( gregOfRexRM(pfx,modrm), mk128from32s( a3, s2, a1, s0 ));
12300 goto decode_success;
12301 }
12302
12303 /* 66 0F D0 = ADDSUBPD -- 64x4 +/- from E (mem or xmm) to G (xmm). */
12304 if (have66noF2noF3(pfx) && sz == 2
12305 && insn[0] == 0x0F && insn[1] == 0xD0) {
12306 IRTemp eV = newTemp(Ity_V128);
12307 IRTemp gV = newTemp(Ity_V128);
12308 IRTemp addV = newTemp(Ity_V128);
12309 IRTemp subV = newTemp(Ity_V128);
12310 IRTemp a1 = newTemp(Ity_I64);
12311 IRTemp s0 = newTemp(Ity_I64);
12312
12313 modrm = insn[2];
12314 if (epartIsReg(modrm)) {
12315 assign( eV, getXMMReg( eregOfRexRM(pfx,modrm)) );
12316 DIP("addsubpd %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
12317 nameXMMReg(gregOfRexRM(pfx,modrm)));
12318 delta += 2+1;
12319 } else {
12320 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
12321 assign( eV, loadLE(Ity_V128, mkexpr(addr)) );
12322 DIP("addsubpd %s,%s\n", dis_buf,
12323 nameXMMReg(gregOfRexRM(pfx,modrm)));
12324 delta += 2+alen;
12325 }
12326
12327 assign( gV, getXMMReg(gregOfRexRM(pfx,modrm)) );
12328
12329 assign( addV, binop(Iop_Add64Fx2, mkexpr(gV), mkexpr(eV)) );
12330 assign( subV, binop(Iop_Sub64Fx2, mkexpr(gV), mkexpr(eV)) );
12331
12332 assign( a1, unop(Iop_V128HIto64, mkexpr(addV) ));
12333 assign( s0, unop(Iop_V128to64, mkexpr(subV) ));
12334
12335 putXMMReg( gregOfRexRM(pfx,modrm),
12336 binop(Iop_64HLtoV128, mkexpr(a1), mkexpr(s0)) );
12337 goto decode_success;
12338 }
12339
12340 /* F2 0F 7D = HSUBPS -- 32x4 sub across from E (mem or xmm) to G (xmm). */
12341 /* F2 0F 7C = HADDPS -- 32x4 add across from E (mem or xmm) to G (xmm). */
12342 if (haveF2no66noF3(pfx) && sz == 4
12343 && insn[0] == 0x0F && (insn[1] == 0x7C || insn[1] == 0x7D)) {
12344 IRTemp e3, e2, e1, e0, g3, g2, g1, g0;
12345 IRTemp eV = newTemp(Ity_V128);
12346 IRTemp gV = newTemp(Ity_V128);
12347 IRTemp leftV = newTemp(Ity_V128);
12348 IRTemp rightV = newTemp(Ity_V128);
12349 Bool isAdd = insn[1] == 0x7C;
12350 HChar* str = isAdd ? "add" : "sub";
12351 e3 = e2 = e1 = e0 = g3 = g2 = g1 = g0 = IRTemp_INVALID;
12352
12353 modrm = insn[2];
12354 if (epartIsReg(modrm)) {
12355 assign( eV, getXMMReg( eregOfRexRM(pfx,modrm)) );
12356 DIP("h%sps %s,%s\n", str, nameXMMReg(eregOfRexRM(pfx,modrm)),
12357 nameXMMReg(gregOfRexRM(pfx,modrm)));
12358 delta += 2+1;
12359 } else {
12360 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
12361 assign( eV, loadLE(Ity_V128, mkexpr(addr)) );
12362 DIP("h%sps %s,%s\n", str, dis_buf,
12363 nameXMMReg(gregOfRexRM(pfx,modrm)));
12364 delta += 2+alen;
12365 }
12366
12367 assign( gV, getXMMReg(gregOfRexRM(pfx,modrm)) );
12368
12369 breakup128to32s( eV, &e3, &e2, &e1, &e0 );
12370 breakup128to32s( gV, &g3, &g2, &g1, &g0 );
12371
12372 assign( leftV, mk128from32s( e2, e0, g2, g0 ) );
12373 assign( rightV, mk128from32s( e3, e1, g3, g1 ) );
12374
12375 putXMMReg( gregOfRexRM(pfx,modrm),
12376 binop(isAdd ? Iop_Add32Fx4 : Iop_Sub32Fx4,
12377 mkexpr(leftV), mkexpr(rightV) ) );
12378 goto decode_success;
12379 }
12380
12381 /* 66 0F 7D = HSUBPD -- 64x2 sub across from E (mem or xmm) to G (xmm). */
12382 /* 66 0F 7C = HADDPD -- 64x2 add across from E (mem or xmm) to G (xmm). */
12383 if (have66noF2noF3(pfx) && sz == 2
12384 && insn[0] == 0x0F && (insn[1] == 0x7C || insn[1] == 0x7D)) {
12385 IRTemp e1 = newTemp(Ity_I64);
12386 IRTemp e0 = newTemp(Ity_I64);
12387 IRTemp g1 = newTemp(Ity_I64);
12388 IRTemp g0 = newTemp(Ity_I64);
12389 IRTemp eV = newTemp(Ity_V128);
12390 IRTemp gV = newTemp(Ity_V128);
12391 IRTemp leftV = newTemp(Ity_V128);
12392 IRTemp rightV = newTemp(Ity_V128);
12393 Bool isAdd = insn[1] == 0x7C;
12394 HChar* str = isAdd ? "add" : "sub";
12395
12396 modrm = insn[2];
12397 if (epartIsReg(modrm)) {
12398 assign( eV, getXMMReg( eregOfRexRM(pfx,modrm)) );
12399 DIP("h%spd %s,%s\n", str, nameXMMReg(eregOfRexRM(pfx,modrm)),
12400 nameXMMReg(gregOfRexRM(pfx,modrm)));
12401 delta += 2+1;
12402 } else {
12403 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
12404 assign( eV, loadLE(Ity_V128, mkexpr(addr)) );
12405 DIP("h%spd %s,%s\n", str, dis_buf,
12406 nameXMMReg(gregOfRexRM(pfx,modrm)));
12407 delta += 2+alen;
12408 }
12409
12410 assign( gV, getXMMReg(gregOfRexRM(pfx,modrm)) );
12411
12412 assign( e1, unop(Iop_V128HIto64, mkexpr(eV) ));
12413 assign( e0, unop(Iop_V128to64, mkexpr(eV) ));
12414 assign( g1, unop(Iop_V128HIto64, mkexpr(gV) ));
12415 assign( g0, unop(Iop_V128to64, mkexpr(gV) ));
12416
12417 assign( leftV, binop(Iop_64HLtoV128, mkexpr(e0),mkexpr(g0)) );
12418 assign( rightV, binop(Iop_64HLtoV128, mkexpr(e1),mkexpr(g1)) );
12419
12420 putXMMReg( gregOfRexRM(pfx,modrm),
12421 binop(isAdd ? Iop_Add64Fx2 : Iop_Sub64Fx2,
12422 mkexpr(leftV), mkexpr(rightV) ) );
12423 goto decode_success;
12424 }
12425
12426 /* F2 0F F0 = LDDQU -- move from E (mem or xmm) to G (xmm). */
12427 if (haveF2no66noF3(pfx) && sz == 4
12428 && insn[0] == 0x0F && insn[1] == 0xF0) {
12429 modrm = insn[2];
12430 if (epartIsReg(modrm)) {
12431 goto decode_failure;
12432 } else {
12433 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
12434 putXMMReg( gregOfRexRM(pfx,modrm),
12435 loadLE(Ity_V128, mkexpr(addr)) );
12436 DIP("lddqu %s,%s\n", dis_buf,
12437 nameXMMReg(gregOfRexRM(pfx,modrm)));
12438 delta += 2+alen;
12439 }
12440 goto decode_success;
12441 }
12442
12443 /* ---------------------------------------------------- */
12444 /* --- end of the SSE3 decoder. --- */
12445 /* ---------------------------------------------------- */
12446
sewardj7a240552005-01-28 21:37:12 +000012447 /*after_sse_decoders:*/
sewardjdf0e0022005-01-25 15:48:43 +000012448
12449 /* Get the primary opcode. */
sewardj8c332e22005-01-28 01:36:56 +000012450 opc = getUChar(delta); delta++;
sewardjdf0e0022005-01-25 15:48:43 +000012451
12452 /* We get here if the current insn isn't SSE, or this CPU doesn't
12453 support SSE. */
12454
12455 switch (opc) {
12456
12457 /* ------------------------ Control flow --------------- */
12458
sewardj47c2d4d2006-11-14 17:50:16 +000012459 case 0xC2: /* RET imm16 */
12460 if (have66orF2orF3(pfx)) goto decode_failure;
12461 d64 = getUDisp16(delta);
12462 delta += 2;
12463 dis_ret(vmi, d64);
12464 dres.whatNext = Dis_StopHere;
12465 DIP("ret %lld\n", d64);
12466 break;
12467
sewardj2f959cc2005-01-26 01:19:35 +000012468 case 0xC3: /* RET */
sewardj47c2d4d2006-11-14 17:50:16 +000012469 if (have66orF2(pfx)) goto decode_failure;
sewardj55dbb262005-01-28 16:36:51 +000012470 /* F3 is acceptable on AMD. */
sewardjaca070a2006-10-17 00:28:22 +000012471 dis_ret(vmi, 0);
sewardj9e6491a2005-07-02 19:24:10 +000012472 dres.whatNext = Dis_StopHere;
sewardje941eea2005-01-30 19:52:28 +000012473 DIP(haveF3(pfx) ? "rep ; ret\n" : "ret\n");
sewardj2f959cc2005-01-26 01:19:35 +000012474 break;
12475
sewardj3ca55a12005-01-27 16:06:23 +000012476 case 0xE8: /* CALL J4 */
12477 if (haveF2orF3(pfx)) goto decode_failure;
12478 d64 = getSDisp32(delta); delta += 4;
sewardj9e6491a2005-07-02 19:24:10 +000012479 d64 += (guest_RIP_bbstart+delta);
12480 /* (guest_RIP_bbstart+delta) == return-to addr, d64 == call-to addr */
sewardj3ca55a12005-01-27 16:06:23 +000012481 t1 = newTemp(Ity_I64);
12482 assign(t1, binop(Iop_Sub64, getIReg64(R_RSP), mkU64(8)));
12483 putIReg64(R_RSP, mkexpr(t1));
sewardj9e6491a2005-07-02 19:24:10 +000012484 storeLE( mkexpr(t1), mkU64(guest_RIP_bbstart+delta));
sewardjaca070a2006-10-17 00:28:22 +000012485 make_redzone_AbiHint(vmi, t1, "call-d32");
sewardjc716aea2006-01-17 01:48:46 +000012486 if (resteerOkFn( callback_opaque, (Addr64)d64) ) {
sewardj3ca55a12005-01-27 16:06:23 +000012487 /* follow into the call target. */
sewardj9e6491a2005-07-02 19:24:10 +000012488 dres.whatNext = Dis_Resteer;
12489 dres.continueAt = d64;
sewardj3ca55a12005-01-27 16:06:23 +000012490 } else {
12491 jmp_lit(Ijk_Call,d64);
sewardj9e6491a2005-07-02 19:24:10 +000012492 dres.whatNext = Dis_StopHere;
sewardj3ca55a12005-01-27 16:06:23 +000012493 }
12494 DIP("call 0x%llx\n",d64);
12495 break;
12496
sewardjd20c8852005-01-20 20:04:07 +000012497//.. //-- case 0xC8: /* ENTER */
12498//.. //-- d32 = getUDisp16(eip); eip += 2;
sewardj8c332e22005-01-28 01:36:56 +000012499//.. //-- abyte = getUChar(delta); delta++;
sewardjd20c8852005-01-20 20:04:07 +000012500//.. //--
12501//.. //-- vg_assert(sz == 4);
12502//.. //-- vg_assert(abyte == 0);
12503//.. //--
12504//.. //-- t1 = newTemp(cb); t2 = newTemp(cb);
12505//.. //-- uInstr2(cb, GET, sz, ArchReg, R_EBP, TempReg, t1);
12506//.. //-- uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t2);
12507//.. //-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
12508//.. //-- uLiteral(cb, sz);
12509//.. //-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
12510//.. //-- uInstr2(cb, STORE, 4, TempReg, t1, TempReg, t2);
12511//.. //-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_EBP);
12512//.. //-- if (d32) {
12513//.. //-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
12514//.. //-- uLiteral(cb, d32);
12515//.. //-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
12516//.. //-- }
12517//.. //-- DIP("enter 0x%x, 0x%x", d32, abyte);
12518//.. //-- break;
sewardje1698952005-02-08 15:02:39 +000012519
12520 case 0xC9: /* LEAVE */
12521 /* In 64-bit mode this defaults to a 64-bit operand size. There
12522 is no way to encode a 32-bit variant. Hence sz==4 but we do
12523 it as if sz=8. */
12524 if (sz != 4)
12525 goto decode_failure;
12526 t1 = newTemp(Ity_I64);
12527 t2 = newTemp(Ity_I64);
12528 assign(t1, getIReg64(R_RBP));
12529 /* First PUT RSP looks redundant, but need it because RSP must
12530 always be up-to-date for Memcheck to work... */
12531 putIReg64(R_RSP, mkexpr(t1));
12532 assign(t2, loadLE(Ity_I64,mkexpr(t1)));
12533 putIReg64(R_RBP, mkexpr(t2));
12534 putIReg64(R_RSP, binop(Iop_Add64, mkexpr(t1), mkU64(8)) );
12535 DIP("leave\n");
12536 break;
12537
sewardjd20c8852005-01-20 20:04:07 +000012538//.. //-- /* ---------------- Misc weird-ass insns --------------- */
12539//.. //--
12540//.. //-- case 0x27: /* DAA */
12541//.. //-- case 0x2F: /* DAS */
12542//.. //-- t1 = newTemp(cb);
12543//.. //-- uInstr2(cb, GET, 1, ArchReg, R_AL, TempReg, t1);
12544//.. //-- /* Widen %AL to 32 bits, so it's all defined when we push it. */
12545//.. //-- uInstr1(cb, WIDEN, 4, TempReg, t1);
12546//.. //-- uWiden(cb, 1, False);
12547//.. //-- uInstr0(cb, CALLM_S, 0);
12548//.. //-- uInstr1(cb, PUSH, 4, TempReg, t1);
12549//.. //-- uInstr1(cb, CALLM, 0, Lit16,
12550//.. //-- opc == 0x27 ? VGOFF_(helper_DAA) : VGOFF_(helper_DAS) );
12551//.. //-- uFlagsRWU(cb, FlagsAC, FlagsSZACP, FlagO);
12552//.. //-- uInstr1(cb, POP, 4, TempReg, t1);
12553//.. //-- uInstr0(cb, CALLM_E, 0);
12554//.. //-- uInstr2(cb, PUT, 1, TempReg, t1, ArchReg, R_AL);
12555//.. //-- DIP(opc == 0x27 ? "daa\n" : "das\n");
12556//.. //-- break;
12557//.. //--
12558//.. //-- case 0x37: /* AAA */
12559//.. //-- case 0x3F: /* AAS */
12560//.. //-- t1 = newTemp(cb);
12561//.. //-- uInstr2(cb, GET, 2, ArchReg, R_EAX, TempReg, t1);
12562//.. //-- /* Widen %AL to 32 bits, so it's all defined when we push it. */
12563//.. //-- uInstr1(cb, WIDEN, 4, TempReg, t1);
12564//.. //-- uWiden(cb, 2, False);
12565//.. //-- uInstr0(cb, CALLM_S, 0);
12566//.. //-- uInstr1(cb, PUSH, 4, TempReg, t1);
12567//.. //-- uInstr1(cb, CALLM, 0, Lit16,
12568//.. //-- opc == 0x37 ? VGOFF_(helper_AAA) : VGOFF_(helper_AAS) );
12569//.. //-- uFlagsRWU(cb, FlagA, FlagsAC, FlagsEmpty);
12570//.. //-- uInstr1(cb, POP, 4, TempReg, t1);
12571//.. //-- uInstr0(cb, CALLM_E, 0);
12572//.. //-- uInstr2(cb, PUT, 2, TempReg, t1, ArchReg, R_EAX);
12573//.. //-- DIP(opc == 0x37 ? "aaa\n" : "aas\n");
12574//.. //-- break;
12575//.. //--
12576//.. //-- case 0xD4: /* AAM */
12577//.. //-- case 0xD5: /* AAD */
sewardj8c332e22005-01-28 01:36:56 +000012578//.. //-- d32 = getUChar(delta); delta++;
sewardjd20c8852005-01-20 20:04:07 +000012579//.. //-- if (d32 != 10) VG_(core_panic)("disInstr: AAM/AAD but base not 10 !");
12580//.. //-- t1 = newTemp(cb);
12581//.. //-- uInstr2(cb, GET, 2, ArchReg, R_EAX, TempReg, t1);
12582//.. //-- /* Widen %AX to 32 bits, so it's all defined when we push it. */
12583//.. //-- uInstr1(cb, WIDEN, 4, TempReg, t1);
12584//.. //-- uWiden(cb, 2, False);
12585//.. //-- uInstr0(cb, CALLM_S, 0);
12586//.. //-- uInstr1(cb, PUSH, 4, TempReg, t1);
12587//.. //-- uInstr1(cb, CALLM, 0, Lit16,
12588//.. //-- opc == 0xD4 ? VGOFF_(helper_AAM) : VGOFF_(helper_AAD) );
12589//.. //-- uFlagsRWU(cb, FlagsEmpty, FlagsSZP, FlagsEmpty);
12590//.. //-- uInstr1(cb, POP, 4, TempReg, t1);
12591//.. //-- uInstr0(cb, CALLM_E, 0);
12592//.. //-- uInstr2(cb, PUT, 2, TempReg, t1, ArchReg, R_EAX);
12593//.. //-- DIP(opc == 0xD4 ? "aam\n" : "aad\n");
12594//.. //-- break;
sewardj3ca55a12005-01-27 16:06:23 +000012595
12596 /* ------------------------ CWD/CDQ -------------------- */
12597
12598 case 0x98: /* CBW */
12599 if (haveF2orF3(pfx)) goto decode_failure;
12600 if (sz == 8) {
sewardj5b470602005-02-27 13:10:48 +000012601 putIRegRAX( 8, unop(Iop_32Sto64, getIRegRAX(4)) );
sewardje941eea2005-01-30 19:52:28 +000012602 DIP(/*"cdqe\n"*/"cltq");
12603 break;
12604 }
sewardj3ca55a12005-01-27 16:06:23 +000012605 if (sz == 4) {
sewardj5b470602005-02-27 13:10:48 +000012606 putIRegRAX( 4, unop(Iop_16Sto32, getIRegRAX(2)) );
sewardj7eaa7cf2005-01-31 18:55:22 +000012607 DIP("cwtl\n");
sewardje941eea2005-01-30 19:52:28 +000012608 break;
12609 }
sewardj3ca55a12005-01-27 16:06:23 +000012610 if (sz == 2) {
sewardj5b470602005-02-27 13:10:48 +000012611 putIRegRAX( 2, unop(Iop_8Sto16, getIRegRAX(1)) );
sewardj3ca55a12005-01-27 16:06:23 +000012612 DIP("cbw\n");
sewardj7bc00082005-03-27 05:08:32 +000012613 break;
sewardj3ca55a12005-01-27 16:06:23 +000012614 }
sewardje941eea2005-01-30 19:52:28 +000012615 goto decode_failure;
sewardj3ca55a12005-01-27 16:06:23 +000012616
12617 case 0x99: /* CWD/CDQ/CQO */
12618 if (haveF2orF3(pfx)) goto decode_failure;
12619 vassert(sz == 2 || sz == 4 || sz == 8);
12620 ty = szToITy(sz);
sewardj5b470602005-02-27 13:10:48 +000012621 putIRegRDX( sz,
12622 binop(mkSizedOp(ty,Iop_Sar8),
12623 getIRegRAX(sz),
12624 mkU8(sz == 2 ? 15 : (sz == 4 ? 31 : 63))) );
sewardje941eea2005-01-30 19:52:28 +000012625 DIP(sz == 2 ? "cwd\n"
sewardj5b470602005-02-27 13:10:48 +000012626 : (sz == 4 ? /*"cdq\n"*/ "cltd\n"
12627 : "cqo\n"));
sewardj3ca55a12005-01-27 16:06:23 +000012628 break;
12629
sewardj8d965312005-02-25 02:48:47 +000012630 /* ------------------------ FPU ops -------------------- */
12631
sewardj905edbd2007-04-07 12:25:37 +000012632 case 0x9E: /* SAHF */
12633 codegen_SAHF();
12634 DIP("sahf\n");
12635 break;
12636
12637 case 0x9F: /* LAHF */
12638 codegen_LAHF();
12639 DIP("lahf\n");
12640 break;
12641
sewardj6847d8c2005-05-12 19:21:55 +000012642 case 0x9B: /* FWAIT */
12643 /* ignore? */
12644 DIP("fwait\n");
12645 break;
sewardj8d965312005-02-25 02:48:47 +000012646
12647 case 0xD8:
12648 case 0xD9:
12649 case 0xDA:
12650 case 0xDB:
12651 case 0xDC:
12652 case 0xDD:
12653 case 0xDE:
sewardj5619f792007-03-11 19:34:13 +000012654 case 0xDF: {
12655 Bool redundantREXWok = False;
12656
12657 if (haveF2orF3(pfx))
12658 goto decode_failure;
12659
12660 /* kludge to tolerate redundant rex.w prefixes (should do this
12661 properly one day) */
12662 /* mono 1.1.18.1 produces 48 D9 FA, which is rex.w fsqrt */
12663 if ( (opc == 0xD9 && getUChar(delta+0) == 0xFA)/*fsqrt*/ )
12664 redundantREXWok = True;
12665
12666 if ( (sz == 4
12667 || (sz == 8 && redundantREXWok))
12668 && haveNo66noF2noF3(pfx)) {
sewardj270def42005-07-03 01:03:01 +000012669 Long delta0 = delta;
12670 Bool decode_OK = False;
sewardj8d965312005-02-25 02:48:47 +000012671 delta = dis_FPU ( &decode_OK, pfx, delta );
12672 if (!decode_OK) {
12673 delta = delta0;
12674 goto decode_failure;
12675 }
12676 break;
12677 } else {
12678 goto decode_failure;
12679 }
sewardj5619f792007-03-11 19:34:13 +000012680 }
sewardj8d965312005-02-25 02:48:47 +000012681
sewardj4fa325a2005-11-03 13:27:24 +000012682 /* ------------------------ INT ------------------------ */
12683
sewardjada80ba2007-03-12 00:43:59 +000012684 case 0xCC: /* INT 3 */
sewardj0f500042007-08-29 09:09:17 +000012685 jmp_lit(Ijk_SigTRAP, guest_RIP_bbstart + delta);
sewardjada80ba2007-03-12 00:43:59 +000012686 dres.whatNext = Dis_StopHere;
12687 DIP("int $0x3\n");
12688 break;
12689
sewardj4fa325a2005-11-03 13:27:24 +000012690 case 0xCD: { /* INT imm8 */
12691 IRJumpKind jk = Ijk_Boring;
12692 if (have66orF2orF3(pfx)) goto decode_failure;
12693 d64 = getUChar(delta); delta++;
12694 switch (d64) {
12695 case 32: jk = Ijk_Sys_int32; break;
12696 default: goto decode_failure;
12697 }
12698 guest_RIP_next_mustcheck = True;
12699 guest_RIP_next_assumed = guest_RIP_bbstart + delta;
12700 jmp_lit(jk, guest_RIP_next_assumed);
12701 /* It's important that all ArchRegs carry their up-to-date value
12702 at this point. So we declare an end-of-block here, which
12703 forces any TempRegs caching ArchRegs to be flushed. */
12704 dres.whatNext = Dis_StopHere;
12705 DIP("int $0x%02x\n", (UInt)d64);
12706 break;
12707 }
12708
sewardjf8c37f72005-02-07 18:55:29 +000012709 /* ------------------------ Jcond, byte offset --------- */
12710
12711 case 0xEB: /* Jb (jump, byte offset) */
sewardj5b470602005-02-27 13:10:48 +000012712 if (haveF2orF3(pfx)) goto decode_failure;
sewardjf8c37f72005-02-07 18:55:29 +000012713 if (sz != 4)
12714 goto decode_failure; /* JRS added 2004 July 11 */
sewardj9e6491a2005-07-02 19:24:10 +000012715 d64 = (guest_RIP_bbstart+delta+1) + getSDisp8(delta);
sewardjf8c37f72005-02-07 18:55:29 +000012716 delta++;
sewardjc716aea2006-01-17 01:48:46 +000012717 if (resteerOkFn(callback_opaque,d64)) {
sewardj9e6491a2005-07-02 19:24:10 +000012718 dres.whatNext = Dis_Resteer;
12719 dres.continueAt = d64;
sewardjf8c37f72005-02-07 18:55:29 +000012720 } else {
12721 jmp_lit(Ijk_Boring,d64);
sewardj9e6491a2005-07-02 19:24:10 +000012722 dres.whatNext = Dis_StopHere;
sewardjf8c37f72005-02-07 18:55:29 +000012723 }
12724 DIP("jmp-8 0x%llx\n", d64);
12725 break;
sewardj1389d4d2005-01-28 13:46:29 +000012726
12727 case 0xE9: /* Jv (jump, 16/32 offset) */
sewardj5b470602005-02-27 13:10:48 +000012728 if (haveF2orF3(pfx)) goto decode_failure;
sewardjf8c37f72005-02-07 18:55:29 +000012729 if (sz != 4)
12730 goto decode_failure; /* JRS added 2004 July 11 */
sewardj9e6491a2005-07-02 19:24:10 +000012731 d64 = (guest_RIP_bbstart+delta+sz) + getSDisp(sz,delta);
sewardj1389d4d2005-01-28 13:46:29 +000012732 delta += sz;
sewardjc716aea2006-01-17 01:48:46 +000012733 if (resteerOkFn(callback_opaque,d64)) {
sewardj9e6491a2005-07-02 19:24:10 +000012734 dres.whatNext = Dis_Resteer;
12735 dres.continueAt = d64;
sewardj1389d4d2005-01-28 13:46:29 +000012736 } else {
12737 jmp_lit(Ijk_Boring,d64);
sewardj9e6491a2005-07-02 19:24:10 +000012738 dres.whatNext = Dis_StopHere;
sewardj1389d4d2005-01-28 13:46:29 +000012739 }
12740 DIP("jmp 0x%llx\n", d64);
12741 break;
12742
sewardjf8c37f72005-02-07 18:55:29 +000012743 case 0x70:
12744 case 0x71:
12745 case 0x72: /* JBb/JNAEb (jump below) */
12746 case 0x73: /* JNBb/JAEb (jump not below) */
12747 case 0x74: /* JZb/JEb (jump zero) */
12748 case 0x75: /* JNZb/JNEb (jump not zero) */
12749 case 0x76: /* JBEb/JNAb (jump below or equal) */
12750 case 0x77: /* JNBEb/JAb (jump not below or equal) */
12751 case 0x78: /* JSb (jump negative) */
12752 case 0x79: /* JSb (jump not negative) */
12753 case 0x7A: /* JP (jump parity even) */
12754 case 0x7B: /* JNP/JPO (jump parity odd) */
12755 case 0x7C: /* JLb/JNGEb (jump less) */
12756 case 0x7D: /* JGEb/JNLb (jump greater or equal) */
12757 case 0x7E: /* JLEb/JNGb (jump less or equal) */
12758 case 0x7F: /* JGb/JNLEb (jump greater) */
sewardj5b470602005-02-27 13:10:48 +000012759 if (haveF2orF3(pfx)) goto decode_failure;
sewardj9e6491a2005-07-02 19:24:10 +000012760 d64 = (guest_RIP_bbstart+delta+1) + getSDisp8(delta);
sewardjf8c37f72005-02-07 18:55:29 +000012761 delta++;
12762 jcc_01( (AMD64Condcode)(opc - 0x70),
sewardj9e6491a2005-07-02 19:24:10 +000012763 guest_RIP_bbstart+delta,
sewardjf8c37f72005-02-07 18:55:29 +000012764 d64 );
sewardj9e6491a2005-07-02 19:24:10 +000012765 dres.whatNext = Dis_StopHere;
sewardjf8c37f72005-02-07 18:55:29 +000012766 DIP("j%s-8 0x%llx\n", name_AMD64Condcode(opc - 0x70), d64);
12767 break;
12768
sewardjc01c1fa2005-11-04 14:34:52 +000012769 case 0xE3:
12770 /* JRCXZ or JECXZ, depending address size override. */
12771 if (have66orF2orF3(pfx)) goto decode_failure;
sewardjfdfa8862005-10-05 16:58:23 +000012772 d64 = (guest_RIP_bbstart+delta+1) + getSDisp8(delta);
12773 delta++;
sewardjc01c1fa2005-11-04 14:34:52 +000012774 if (haveASO(pfx)) {
12775 /* 32-bit */
12776 stmt( IRStmt_Exit( binop(Iop_CmpEQ64,
12777 unop(Iop_32Uto64, getIReg32(R_RCX)),
12778 mkU64(0)),
12779 Ijk_Boring,
12780 IRConst_U64(d64))
12781 );
12782 DIP("jecxz 0x%llx\n", d64);
12783 } else {
12784 /* 64-bit */
12785 stmt( IRStmt_Exit( binop(Iop_CmpEQ64,
12786 getIReg64(R_RCX),
12787 mkU64(0)),
12788 Ijk_Boring,
12789 IRConst_U64(d64))
12790 );
12791 DIP("jrcxz 0x%llx\n", d64);
12792 }
sewardjfdfa8862005-10-05 16:58:23 +000012793 break;
sewardj6359f812005-07-20 10:15:34 +000012794
sewardje8f65252005-08-23 23:44:35 +000012795 case 0xE0: /* LOOPNE disp8: decrement count, jump if count != 0 && ZF==0 */
12796 case 0xE1: /* LOOPE disp8: decrement count, jump if count != 0 && ZF==1 */
12797 case 0xE2: /* LOOP disp8: decrement count, jump if count != 0 */
12798 { /* The docs say this uses rCX as a count depending on the
12799 address size override, not the operand one. Since we don't
12800 handle address size overrides, I guess that means RCX. */
12801 IRExpr* zbit = NULL;
12802 IRExpr* count = NULL;
12803 IRExpr* cond = NULL;
12804 HChar* xtra = NULL;
12805
12806 if (have66orF2orF3(pfx) || haveASO(pfx)) goto decode_failure;
12807 d64 = guest_RIP_bbstart+delta+1 + getSDisp8(delta);
12808 delta++;
12809 putIReg64(R_RCX, binop(Iop_Sub64, getIReg64(R_RCX), mkU64(1)));
12810
12811 count = getIReg64(R_RCX);
12812 cond = binop(Iop_CmpNE64, count, mkU64(0));
12813 switch (opc) {
12814 case 0xE2:
12815 xtra = "";
12816 break;
12817 case 0xE1:
12818 xtra = "e";
12819 zbit = mk_amd64g_calculate_condition( AMD64CondZ );
12820 cond = mkAnd1(cond, zbit);
12821 break;
12822 case 0xE0:
12823 xtra = "ne";
12824 zbit = mk_amd64g_calculate_condition( AMD64CondNZ );
12825 cond = mkAnd1(cond, zbit);
12826 break;
12827 default:
12828 vassert(0);
12829 }
12830 stmt( IRStmt_Exit(cond, Ijk_Boring, IRConst_U64(d64)) );
12831
12832 DIP("loop%s 0x%llx\n", xtra, d64);
12833 break;
12834 }
sewardj32b2bbe2005-01-28 00:50:10 +000012835
12836 /* ------------------------ IMUL ----------------------- */
12837
12838 case 0x69: /* IMUL Iv, Ev, Gv */
sewardj5b470602005-02-27 13:10:48 +000012839 if (haveF2orF3(pfx)) goto decode_failure;
sewardj32b2bbe2005-01-28 00:50:10 +000012840 delta = dis_imul_I_E_G ( pfx, sz, delta, sz );
12841 break;
sewardj7de0d3c2005-02-13 02:26:41 +000012842 case 0x6B: /* IMUL Ib, Ev, Gv */
12843 delta = dis_imul_I_E_G ( pfx, sz, delta, 1 );
12844 break;
sewardj1389d4d2005-01-28 13:46:29 +000012845
12846 /* ------------------------ MOV ------------------------ */
12847
12848 case 0x88: /* MOV Gb,Eb */
sewardj5b470602005-02-27 13:10:48 +000012849 if (haveF2orF3(pfx)) goto decode_failure;
sewardj1389d4d2005-01-28 13:46:29 +000012850 delta = dis_mov_G_E(pfx, 1, delta);
12851 break;
12852
12853 case 0x89: /* MOV Gv,Ev */
sewardj5b470602005-02-27 13:10:48 +000012854 if (haveF2orF3(pfx)) goto decode_failure;
sewardj1389d4d2005-01-28 13:46:29 +000012855 delta = dis_mov_G_E(pfx, sz, delta);
12856 break;
12857
sewardjd0a12df2005-02-10 02:07:43 +000012858 case 0x8A: /* MOV Eb,Gb */
sewardj5b470602005-02-27 13:10:48 +000012859 if (haveF2orF3(pfx)) goto decode_failure;
sewardjd0a12df2005-02-10 02:07:43 +000012860 delta = dis_mov_E_G(pfx, 1, delta);
12861 break;
12862
sewardj1389d4d2005-01-28 13:46:29 +000012863 case 0x8B: /* MOV Ev,Gv */
sewardj5b470602005-02-27 13:10:48 +000012864 if (haveF2orF3(pfx)) goto decode_failure;
sewardj1389d4d2005-01-28 13:46:29 +000012865 delta = dis_mov_E_G(pfx, sz, delta);
12866 break;
12867
12868 case 0x8D: /* LEA M,Gv */
sewardj5b470602005-02-27 13:10:48 +000012869 if (haveF2orF3(pfx)) goto decode_failure;
sewardj1389d4d2005-01-28 13:46:29 +000012870 if (sz != 4 && sz != 8)
12871 goto decode_failure;
12872 modrm = getUChar(delta);
12873 if (epartIsReg(modrm))
12874 goto decode_failure;
12875 /* NOTE! this is the one place where a segment override prefix
12876 has no effect on the address calculation. Therefore we clear
12877 any segment override bits in pfx. */
sewardje1698952005-02-08 15:02:39 +000012878 addr = disAMode ( &alen, clearSegBits(pfx), delta, dis_buf, 0 );
sewardj1389d4d2005-01-28 13:46:29 +000012879 delta += alen;
12880 /* This is a hack. But it isn't clear that really doing the
12881 calculation at 32 bits is really worth it. Hence for leal,
12882 do the full 64-bit calculation and then truncate it. */
sewardj5b470602005-02-27 13:10:48 +000012883 putIRegG( sz, pfx, modrm,
sewardj1389d4d2005-01-28 13:46:29 +000012884 sz == 4
12885 ? unop(Iop_64to32, mkexpr(addr))
12886 : mkexpr(addr)
12887 );
12888 DIP("lea%c %s, %s\n", nameISize(sz), dis_buf,
sewardj5b470602005-02-27 13:10:48 +000012889 nameIRegG(sz,pfx,modrm));
sewardj1389d4d2005-01-28 13:46:29 +000012890 break;
12891
sewardjd20c8852005-01-20 20:04:07 +000012892//.. case 0x8C: /* MOV Sw,Ew -- MOV from a SEGMENT REGISTER */
12893//.. delta = dis_mov_Sw_Ew(sorb, sz, delta);
12894//.. break;
12895//..
12896//.. case 0x8E: /* MOV Ew,Sw -- MOV to a SEGMENT REGISTER */
12897//.. delta = dis_mov_Ew_Sw(sorb, delta);
12898//.. break;
sewardj2bd97d12005-08-02 21:27:25 +000012899
12900 case 0xA0: /* MOV Ob,AL */
12901 if (have66orF2orF3(pfx)) goto decode_failure;
12902 sz = 1;
12903 /* Fall through ... */
sewardj87277cb2005-08-01 13:03:32 +000012904 case 0xA1: /* MOV Ov,eAX */
sewardj2bd97d12005-08-02 21:27:25 +000012905 if (sz != 8 && sz != 4 && sz != 2 && sz != 1)
12906 goto decode_failure;
sewardj87277cb2005-08-01 13:03:32 +000012907 d64 = getDisp64(delta);
12908 delta += 8;
12909 ty = szToITy(sz);
12910 addr = newTemp(Ity_I64);
sewardj42561ef2005-11-04 14:18:31 +000012911 assign( addr, handleAddrOverrides(pfx, mkU64(d64)) );
sewardj87277cb2005-08-01 13:03:32 +000012912 putIRegRAX(sz, loadLE( ty, mkexpr(addr) ));
12913 DIP("mov%c %s0x%llx, %s\n", nameISize(sz),
sewardjc4356f02007-11-09 21:15:04 +000012914 segRegTxt(pfx), d64,
sewardj87277cb2005-08-01 13:03:32 +000012915 nameIRegRAX(sz));
12916 break;
12917
sewardj2bd97d12005-08-02 21:27:25 +000012918 case 0xA2: /* MOV AL,Ob */
12919 if (have66orF2orF3(pfx)) goto decode_failure;
12920 sz = 1;
12921 /* Fall through ... */
sewardj87277cb2005-08-01 13:03:32 +000012922 case 0xA3: /* MOV eAX,Ov */
sewardj2bd97d12005-08-02 21:27:25 +000012923 if (sz != 8 && sz != 4 && sz != 2 && sz != 1)
12924 goto decode_failure;
sewardj87277cb2005-08-01 13:03:32 +000012925 d64 = getDisp64(delta);
12926 delta += 8;
12927 ty = szToITy(sz);
12928 addr = newTemp(Ity_I64);
sewardj42561ef2005-11-04 14:18:31 +000012929 assign( addr, handleAddrOverrides(pfx, mkU64(d64)) );
sewardj87277cb2005-08-01 13:03:32 +000012930 storeLE( mkexpr(addr), getIRegRAX(sz) );
12931 DIP("mov%c %s, %s0x%llx\n", nameISize(sz), nameIRegRAX(sz),
sewardjc4356f02007-11-09 21:15:04 +000012932 segRegTxt(pfx), d64);
sewardj87277cb2005-08-01 13:03:32 +000012933 break;
sewardjb095fba2005-02-13 14:13:04 +000012934
sewardj8711f662005-05-09 17:52:56 +000012935 /* XXXX be careful here with moves to AH/BH/CH/DH */
sewardj007e9ec2005-03-23 11:36:48 +000012936 case 0xB0: /* MOV imm,AL */
12937 case 0xB1: /* MOV imm,CL */
sewardjb095fba2005-02-13 14:13:04 +000012938 case 0xB2: /* MOV imm,DL */
sewardj007e9ec2005-03-23 11:36:48 +000012939 case 0xB3: /* MOV imm,BL */
12940 case 0xB4: /* MOV imm,AH */
12941 case 0xB5: /* MOV imm,CH */
12942 case 0xB6: /* MOV imm,DH */
sewardj31eecde2005-03-23 03:39:55 +000012943 case 0xB7: /* MOV imm,BH */
sewardj5b470602005-02-27 13:10:48 +000012944 if (haveF2orF3(pfx)) goto decode_failure;
sewardjb095fba2005-02-13 14:13:04 +000012945 d64 = getUChar(delta);
12946 delta += 1;
sewardj5b470602005-02-27 13:10:48 +000012947 putIRegRexB(1, pfx, opc-0xB0, mkU8(d64));
12948 DIP("movb $%lld,%s\n", d64, nameIRegRexB(1,pfx,opc-0xB0));
sewardjb095fba2005-02-13 14:13:04 +000012949 break;
sewardj1389d4d2005-01-28 13:46:29 +000012950
12951 case 0xB8: /* MOV imm,eAX */
12952 case 0xB9: /* MOV imm,eCX */
12953 case 0xBA: /* MOV imm,eDX */
12954 case 0xBB: /* MOV imm,eBX */
12955 case 0xBC: /* MOV imm,eSP */
12956 case 0xBD: /* MOV imm,eBP */
12957 case 0xBE: /* MOV imm,eSI */
12958 case 0xBF: /* MOV imm,eDI */
sewardj03b07cc2005-01-31 18:09:43 +000012959 /* This is the one-and-only place where 64-bit literals are
12960 allowed in the instruction stream. */
sewardj5b470602005-02-27 13:10:48 +000012961 if (haveF2orF3(pfx)) goto decode_failure;
sewardj03b07cc2005-01-31 18:09:43 +000012962 if (sz == 8) {
12963 d64 = getDisp64(delta);
sewardj7eaa7cf2005-01-31 18:55:22 +000012964 delta += 8;
sewardj5b470602005-02-27 13:10:48 +000012965 putIRegRexB(8, pfx, opc-0xB8, mkU64(d64));
sewardj227458e2005-01-31 19:04:50 +000012966 DIP("movabsq $%lld,%s\n", (Long)d64,
sewardj5b470602005-02-27 13:10:48 +000012967 nameIRegRexB(8,pfx,opc-0xB8));
sewardj03b07cc2005-01-31 18:09:43 +000012968 } else {
12969 d64 = getSDisp(imin(4,sz),delta);
12970 delta += imin(4,sz);
sewardj5b470602005-02-27 13:10:48 +000012971 putIRegRexB(sz, pfx, opc-0xB8,
12972 mkU(szToITy(sz), d64 & mkSizeMask(sz)));
sewardj227458e2005-01-31 19:04:50 +000012973 DIP("mov%c $%lld,%s\n", nameISize(sz),
12974 (Long)d64,
sewardj5b470602005-02-27 13:10:48 +000012975 nameIRegRexB(sz,pfx,opc-0xB8));
sewardj03b07cc2005-01-31 18:09:43 +000012976 }
sewardj1389d4d2005-01-28 13:46:29 +000012977 break;
12978
12979 case 0xC6: /* MOV Ib,Eb */
12980 sz = 1;
12981 goto do_Mov_I_E;
12982 case 0xC7: /* MOV Iv,Ev */
12983 goto do_Mov_I_E;
12984
12985 do_Mov_I_E:
sewardj5b470602005-02-27 13:10:48 +000012986 if (haveF2orF3(pfx)) goto decode_failure;
sewardj1389d4d2005-01-28 13:46:29 +000012987 modrm = getUChar(delta);
12988 if (epartIsReg(modrm)) {
sewardj1389d4d2005-01-28 13:46:29 +000012989 delta++; /* mod/rm byte */
12990 d64 = getSDisp(imin(4,sz),delta);
12991 delta += imin(4,sz);
sewardj5b470602005-02-27 13:10:48 +000012992 putIRegE(sz, pfx, modrm,
12993 mkU(szToITy(sz), d64 & mkSizeMask(sz)));
sewardj227458e2005-01-31 19:04:50 +000012994 DIP("mov%c $%lld, %s\n", nameISize(sz),
12995 (Long)d64,
sewardj5b470602005-02-27 13:10:48 +000012996 nameIRegE(sz,pfx,modrm));
sewardj1389d4d2005-01-28 13:46:29 +000012997 } else {
sewardj5b470602005-02-27 13:10:48 +000012998 addr = disAMode ( &alen, pfx, delta, dis_buf,
12999 /*xtra*/imin(4,sz) );
sewardj1389d4d2005-01-28 13:46:29 +000013000 delta += alen;
sewardje941eea2005-01-30 19:52:28 +000013001 d64 = getSDisp(imin(4,sz),delta);
sewardj1389d4d2005-01-28 13:46:29 +000013002 delta += imin(4,sz);
sewardje941eea2005-01-30 19:52:28 +000013003 storeLE(mkexpr(addr),
13004 mkU(szToITy(sz), d64 & mkSizeMask(sz)));
sewardj227458e2005-01-31 19:04:50 +000013005 DIP("mov%c $%lld, %s\n", nameISize(sz), (Long)d64, dis_buf);
sewardj1389d4d2005-01-28 13:46:29 +000013006 }
13007 break;
13008
sewardj5e525292005-01-28 15:13:10 +000013009 /* ------------------------ MOVx ------------------------ */
13010
13011 case 0x63: /* MOVSX */
sewardj5b470602005-02-27 13:10:48 +000013012 if (haveF2orF3(pfx)) goto decode_failure;
sewardj5e525292005-01-28 15:13:10 +000013013 if (haveREX(pfx) && 1==getRexW(pfx)) {
13014 vassert(sz == 8);
13015 /* movsx r/m32 to r64 */
13016 modrm = getUChar(delta);
13017 if (epartIsReg(modrm)) {
13018 delta++;
sewardj5b470602005-02-27 13:10:48 +000013019 putIRegG(8, pfx, modrm,
sewardj5e525292005-01-28 15:13:10 +000013020 unop(Iop_32Sto64,
sewardj5b470602005-02-27 13:10:48 +000013021 getIRegE(4, pfx, modrm)));
sewardj5e525292005-01-28 15:13:10 +000013022 DIP("movslq %s,%s\n",
sewardj5b470602005-02-27 13:10:48 +000013023 nameIRegE(4, pfx, modrm),
13024 nameIRegG(8, pfx, modrm));
sewardj5e525292005-01-28 15:13:10 +000013025 break;
13026 } else {
sewardje1698952005-02-08 15:02:39 +000013027 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
sewardj5e525292005-01-28 15:13:10 +000013028 delta += alen;
sewardj5b470602005-02-27 13:10:48 +000013029 putIRegG(8, pfx, modrm,
sewardj5e525292005-01-28 15:13:10 +000013030 unop(Iop_32Sto64,
13031 loadLE(Ity_I32, mkexpr(addr))));
13032 DIP("movslq %s,%s\n", dis_buf,
sewardj5b470602005-02-27 13:10:48 +000013033 nameIRegG(8, pfx, modrm));
sewardj5e525292005-01-28 15:13:10 +000013034 break;
13035 }
13036 } else {
13037 goto decode_failure;
13038 }
13039
sewardj4c328cf2005-05-05 12:05:54 +000013040 /* ------------------------ opl imm, A ----------------- */
13041
13042 case 0x04: /* ADD Ib, AL */
13043 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000013044 delta = dis_op_imm_A( 1, False, Iop_Add8, True, delta, "add" );
sewardj4c328cf2005-05-05 12:05:54 +000013045 break;
sewardj03b07cc2005-01-31 18:09:43 +000013046 case 0x05: /* ADD Iv, eAX */
sewardj5b470602005-02-27 13:10:48 +000013047 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000013048 delta = dis_op_imm_A(sz, False, Iop_Add8, True, delta, "add" );
sewardj03b07cc2005-01-31 18:09:43 +000013049 break;
13050
sewardj007e9ec2005-03-23 11:36:48 +000013051 case 0x0C: /* OR Ib, AL */
13052 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000013053 delta = dis_op_imm_A( 1, False, Iop_Or8, True, delta, "or" );
sewardj007e9ec2005-03-23 11:36:48 +000013054 break;
sewardj03b07cc2005-01-31 18:09:43 +000013055 case 0x0D: /* OR Iv, eAX */
sewardj5b470602005-02-27 13:10:48 +000013056 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000013057 delta = dis_op_imm_A( sz, False, Iop_Or8, True, delta, "or" );
sewardj03b07cc2005-01-31 18:09:43 +000013058 break;
13059
sewardj41c01092005-07-23 13:50:32 +000013060 case 0x14: /* ADC Ib, AL */
sewardj671da872007-11-15 23:30:16 +000013061 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000013062 delta = dis_op_imm_A( 1, True, Iop_Add8, True, delta, "adc" );
13063 break;
sewardjd20c8852005-01-20 20:04:07 +000013064//.. //-- case 0x15: /* ADC Iv, eAX */
13065//.. //-- delta = dis_op_imm_A( sz, ADC, True, delta, "adc" );
13066//.. //-- break;
sewardj5fadaf92006-05-12 20:45:59 +000013067
13068 case 0x1C: /* SBB Ib, AL */
13069 if (haveF2orF3(pfx)) goto decode_failure;
13070 delta = dis_op_imm_A( 1, True, Iop_Sub8, True, delta, "sbb" );
13071 break;
sewardjd20c8852005-01-20 20:04:07 +000013072//.. //-- case 0x1D: /* SBB Iv, eAX */
13073//.. //-- delta = dis_op_imm_A( sz, SBB, True, delta, "sbb" );
13074//.. //-- break;
13075//.. //--
sewardj007e9ec2005-03-23 11:36:48 +000013076 case 0x24: /* AND Ib, AL */
13077 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000013078 delta = dis_op_imm_A( 1, False, Iop_And8, True, delta, "and" );
sewardj007e9ec2005-03-23 11:36:48 +000013079 break;
sewardj3ca55a12005-01-27 16:06:23 +000013080 case 0x25: /* AND Iv, eAX */
13081 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000013082 delta = dis_op_imm_A( sz, False, Iop_And8, True, delta, "and" );
sewardj3ca55a12005-01-27 16:06:23 +000013083 break;
13084
sewardj137015d2005-03-27 04:01:15 +000013085 case 0x2C: /* SUB Ib, AL */
13086 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000013087 delta = dis_op_imm_A(1, False, Iop_Sub8, True, delta, "sub" );
sewardj137015d2005-03-27 04:01:15 +000013088 break;
sewardj03b07cc2005-01-31 18:09:43 +000013089 case 0x2D: /* SUB Iv, eAX */
sewardj5b470602005-02-27 13:10:48 +000013090 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000013091 delta = dis_op_imm_A( sz, False, Iop_Sub8, True, delta, "sub" );
sewardj03b07cc2005-01-31 18:09:43 +000013092 break;
13093
sewardj8eb804f2005-05-18 10:22:47 +000013094 case 0x34: /* XOR Ib, AL */
13095 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000013096 delta = dis_op_imm_A( 1, False, Iop_Xor8, True, delta, "xor" );
sewardj8eb804f2005-05-18 10:22:47 +000013097 break;
sewardj85520e42005-02-19 15:22:38 +000013098 case 0x35: /* XOR Iv, eAX */
sewardj5b470602005-02-27 13:10:48 +000013099 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000013100 delta = dis_op_imm_A( sz, False, Iop_Xor8, True, delta, "xor" );
sewardj85520e42005-02-19 15:22:38 +000013101 break;
sewardj03b07cc2005-01-31 18:09:43 +000013102
13103 case 0x3C: /* CMP Ib, AL */
13104 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000013105 delta = dis_op_imm_A( 1, False, Iop_Sub8, False, delta, "cmp" );
sewardj03b07cc2005-01-31 18:09:43 +000013106 break;
sewardj354e5c62005-01-27 20:12:52 +000013107 case 0x3D: /* CMP Iv, eAX */
13108 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000013109 delta = dis_op_imm_A( sz, False, Iop_Sub8, False, delta, "cmp" );
sewardj354e5c62005-01-27 20:12:52 +000013110 break;
13111
sewardj118b23e2005-01-29 02:14:44 +000013112 case 0xA8: /* TEST Ib, AL */
sewardj03b07cc2005-01-31 18:09:43 +000013113 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000013114 delta = dis_op_imm_A( 1, False, Iop_And8, False, delta, "test" );
sewardj118b23e2005-01-29 02:14:44 +000013115 break;
13116 case 0xA9: /* TEST Iv, eAX */
sewardj03b07cc2005-01-31 18:09:43 +000013117 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000013118 delta = dis_op_imm_A( sz, False, Iop_And8, False, delta, "test" );
sewardj118b23e2005-01-29 02:14:44 +000013119 break;
13120
13121 /* ------------------------ opl Ev, Gv ----------------- */
13122
sewardj03b07cc2005-01-31 18:09:43 +000013123 case 0x02: /* ADD Eb,Gb */
13124 if (haveF2orF3(pfx)) goto decode_failure;
13125 delta = dis_op2_E_G ( pfx, False, Iop_Add8, True, 1, delta, "add" );
13126 break;
sewardjdf0e0022005-01-25 15:48:43 +000013127 case 0x03: /* ADD Ev,Gv */
sewardj3ca55a12005-01-27 16:06:23 +000013128 if (haveF2orF3(pfx)) goto decode_failure;
sewardjdf0e0022005-01-25 15:48:43 +000013129 delta = dis_op2_E_G ( pfx, False, Iop_Add8, True, sz, delta, "add" );
sewardjdf0e0022005-01-25 15:48:43 +000013130 break;
13131
sewardj03b07cc2005-01-31 18:09:43 +000013132 case 0x0A: /* OR Eb,Gb */
sewardj5b470602005-02-27 13:10:48 +000013133 if (haveF2orF3(pfx)) goto decode_failure;
sewardj03b07cc2005-01-31 18:09:43 +000013134 delta = dis_op2_E_G ( pfx, False, Iop_Or8, True, 1, delta, "or" );
13135 break;
13136 case 0x0B: /* OR Ev,Gv */
sewardj5b470602005-02-27 13:10:48 +000013137 if (haveF2orF3(pfx)) goto decode_failure;
sewardj03b07cc2005-01-31 18:09:43 +000013138 delta = dis_op2_E_G ( pfx, False, Iop_Or8, True, sz, delta, "or" );
13139 break;
sewardj671da872007-11-15 23:30:16 +000013140
13141 case 0x12: /* ADC Eb,Gb */
13142 if (haveF2orF3(pfx)) goto decode_failure;
13143 delta = dis_op2_E_G ( pfx, True, Iop_Add8, True, 1, delta, "adc" );
13144 break;
sewardj22cab062005-07-19 23:59:54 +000013145 case 0x13: /* ADC Ev,Gv */
sewardj671da872007-11-15 23:30:16 +000013146 if (haveF2orF3(pfx)) goto decode_failure;
sewardj22cab062005-07-19 23:59:54 +000013147 delta = dis_op2_E_G ( pfx, True, Iop_Add8, True, sz, delta, "adc" );
13148 break;
13149
sewardjd20c8852005-01-20 20:04:07 +000013150//.. //-- case 0x1A: /* SBB Eb,Gb */
13151//.. //-- delta = dis_op2_E_G ( sorb, True, SBB, True, 1, delta, "sbb" );
13152//.. //-- break;
sewardj7a06b852005-07-20 10:55:26 +000013153 case 0x1B: /* SBB Ev,Gv */
sewardj671da872007-11-15 23:30:16 +000013154 if (haveF2orF3(pfx)) goto decode_failure;
sewardj7a06b852005-07-20 10:55:26 +000013155 delta = dis_op2_E_G ( pfx, True, Iop_Sub8, True, sz, delta, "sbb" );
13156 break;
sewardj03b07cc2005-01-31 18:09:43 +000013157
13158 case 0x22: /* AND Eb,Gb */
13159 if (haveF2orF3(pfx)) goto decode_failure;
13160 delta = dis_op2_E_G ( pfx, False, Iop_And8, True, 1, delta, "and" );
13161 break;
13162 case 0x23: /* AND Ev,Gv */
13163 if (haveF2orF3(pfx)) goto decode_failure;
13164 delta = dis_op2_E_G ( pfx, False, Iop_And8, True, sz, delta, "and" );
13165 break;
13166
13167 case 0x2A: /* SUB Eb,Gb */
13168 if (haveF2orF3(pfx)) goto decode_failure;
13169 delta = dis_op2_E_G ( pfx, False, Iop_Sub8, True, 1, delta, "sub" );
13170 break;
sewardj118b23e2005-01-29 02:14:44 +000013171 case 0x2B: /* SUB Ev,Gv */
sewardj03b07cc2005-01-31 18:09:43 +000013172 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000013173 delta = dis_op2_E_G ( pfx, False, Iop_Sub8, True, sz, delta, "sub" );
13174 break;
13175
sewardj03b07cc2005-01-31 18:09:43 +000013176 case 0x32: /* XOR Eb,Gb */
13177 if (haveF2orF3(pfx)) goto decode_failure;
13178 delta = dis_op2_E_G ( pfx, False, Iop_Xor8, True, 1, delta, "xor" );
13179 break;
13180 case 0x33: /* XOR Ev,Gv */
13181 if (haveF2orF3(pfx)) goto decode_failure;
13182 delta = dis_op2_E_G ( pfx, False, Iop_Xor8, True, sz, delta, "xor" );
13183 break;
13184
sewardjb095fba2005-02-13 14:13:04 +000013185 case 0x3A: /* CMP Eb,Gb */
13186 if (haveF2orF3(pfx)) goto decode_failure;
13187 delta = dis_op2_E_G ( pfx, False, Iop_Sub8, False, 1, delta, "cmp" );
13188 break;
sewardj354e5c62005-01-27 20:12:52 +000013189 case 0x3B: /* CMP Ev,Gv */
13190 if (haveF2orF3(pfx)) goto decode_failure;
13191 delta = dis_op2_E_G ( pfx, False, Iop_Sub8, False, sz, delta, "cmp" );
13192 break;
13193
sewardj118b23e2005-01-29 02:14:44 +000013194 case 0x84: /* TEST Eb,Gb */
sewardj03b07cc2005-01-31 18:09:43 +000013195 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000013196 delta = dis_op2_E_G ( pfx, False, Iop_And8, False, 1, delta, "test" );
13197 break;
13198 case 0x85: /* TEST Ev,Gv */
sewardj03b07cc2005-01-31 18:09:43 +000013199 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000013200 delta = dis_op2_E_G ( pfx, False, Iop_And8, False, sz, delta, "test" );
13201 break;
13202
13203 /* ------------------------ opl Gv, Ev ----------------- */
13204
sewardj85520e42005-02-19 15:22:38 +000013205 case 0x00: /* ADD Gb,Eb */
13206 if (haveF2orF3(pfx)) goto decode_failure;
13207 delta = dis_op2_G_E ( pfx, False, Iop_Add8, True, 1, delta, "add" );
13208 break;
sewardj3ca55a12005-01-27 16:06:23 +000013209 case 0x01: /* ADD Gv,Ev */
sewardj354e5c62005-01-27 20:12:52 +000013210 if (haveF2orF3(pfx)) goto decode_failure;
sewardj3ca55a12005-01-27 16:06:23 +000013211 delta = dis_op2_G_E ( pfx, False, Iop_Add8, True, sz, delta, "add" );
13212 break;
13213
sewardj03b07cc2005-01-31 18:09:43 +000013214 case 0x08: /* OR Gb,Eb */
13215 if (haveF2orF3(pfx)) goto decode_failure;
13216 delta = dis_op2_G_E ( pfx, False, Iop_Or8, True, 1, delta, "or" );
13217 break;
sewardj55dbb262005-01-28 16:36:51 +000013218 case 0x09: /* OR Gv,Ev */
13219 if (haveF2orF3(pfx)) goto decode_failure;
13220 delta = dis_op2_G_E ( pfx, False, Iop_Or8, True, sz, delta, "or" );
13221 break;
13222
sewardj85520e42005-02-19 15:22:38 +000013223 case 0x10: /* ADC Gb,Eb */
13224 if (haveF2orF3(pfx)) goto decode_failure;
13225 delta = dis_op2_G_E ( pfx, True, Iop_Add8, True, 1, delta, "adc" );
13226 break;
13227 case 0x11: /* ADC Gv,Ev */
13228 if (haveF2orF3(pfx)) goto decode_failure;
13229 delta = dis_op2_G_E ( pfx, True, Iop_Add8, True, sz, delta, "adc" );
13230 break;
13231
13232 case 0x18: /* SBB Gb,Eb */
13233 if (haveF2orF3(pfx)) goto decode_failure;
13234 delta = dis_op2_G_E ( pfx, True, Iop_Sub8, True, 1, delta, "sbb" );
13235 break;
sewardj03b07cc2005-01-31 18:09:43 +000013236 case 0x19: /* SBB Gv,Ev */
sewardja6b93d12005-02-17 09:28:28 +000013237 if (haveF2orF3(pfx)) goto decode_failure;
sewardj03b07cc2005-01-31 18:09:43 +000013238 delta = dis_op2_G_E ( pfx, True, Iop_Sub8, True, sz, delta, "sbb" );
13239 break;
13240
sewardj85520e42005-02-19 15:22:38 +000013241 case 0x20: /* AND Gb,Eb */
13242 if (haveF2orF3(pfx)) goto decode_failure;
13243 delta = dis_op2_G_E ( pfx, False, Iop_And8, True, 1, delta, "and" );
13244 break;
sewardj3ca55a12005-01-27 16:06:23 +000013245 case 0x21: /* AND Gv,Ev */
sewardj354e5c62005-01-27 20:12:52 +000013246 if (haveF2orF3(pfx)) goto decode_failure;
sewardj3ca55a12005-01-27 16:06:23 +000013247 delta = dis_op2_G_E ( pfx, False, Iop_And8, True, sz, delta, "and" );
13248 break;
sewardj03b07cc2005-01-31 18:09:43 +000013249
13250 case 0x28: /* SUB Gb,Eb */
13251 if (haveF2orF3(pfx)) goto decode_failure;
13252 delta = dis_op2_G_E ( pfx, False, Iop_Sub8, True, 1, delta, "sub" );
13253 break;
sewardj118b23e2005-01-29 02:14:44 +000013254 case 0x29: /* SUB Gv,Ev */
sewardj03b07cc2005-01-31 18:09:43 +000013255 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000013256 delta = dis_op2_G_E ( pfx, False, Iop_Sub8, True, sz, delta, "sub" );
13257 break;
13258
sewardjb095fba2005-02-13 14:13:04 +000013259 case 0x30: /* XOR Gb,Eb */
13260 if (haveF2orF3(pfx)) goto decode_failure;
13261 delta = dis_op2_G_E ( pfx, False, Iop_Xor8, True, 1, delta, "xor" );
13262 break;
sewardj118b23e2005-01-29 02:14:44 +000013263 case 0x31: /* XOR Gv,Ev */
sewardj03b07cc2005-01-31 18:09:43 +000013264 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000013265 delta = dis_op2_G_E ( pfx, False, Iop_Xor8, True, sz, delta, "xor" );
13266 break;
sewardj354e5c62005-01-27 20:12:52 +000013267
13268 case 0x38: /* CMP Gb,Eb */
13269 if (haveF2orF3(pfx)) goto decode_failure;
13270 delta = dis_op2_G_E ( pfx, False, Iop_Sub8, False, 1, delta, "cmp" );
13271 break;
13272 case 0x39: /* CMP Gv,Ev */
13273 if (haveF2orF3(pfx)) goto decode_failure;
13274 delta = dis_op2_G_E ( pfx, False, Iop_Sub8, False, sz, delta, "cmp" );
13275 break;
13276
sewardj55dbb262005-01-28 16:36:51 +000013277 /* ------------------------ POP ------------------------ */
13278
13279 case 0x58: /* POP eAX */
13280 case 0x59: /* POP eCX */
13281 case 0x5A: /* POP eDX */
13282 case 0x5B: /* POP eBX */
13283 case 0x5D: /* POP eBP */
13284 case 0x5E: /* POP eSI */
13285 case 0x5F: /* POP eDI */
13286 case 0x5C: /* POP eSP */
sewardj03b07cc2005-01-31 18:09:43 +000013287 if (haveF2orF3(pfx)) goto decode_failure;
sewardj55dbb262005-01-28 16:36:51 +000013288 vassert(sz == 2 || sz == 4 || sz == 8);
13289 if (sz == 4)
13290 sz = 8; /* there is no encoding for 32-bit pop in 64-bit mode */
13291 t1 = newTemp(szToITy(sz));
13292 t2 = newTemp(Ity_I64);
13293 assign(t2, getIReg64(R_RSP));
13294 assign(t1, loadLE(szToITy(sz),mkexpr(t2)));
13295 putIReg64(R_RSP, binop(Iop_Add64, mkexpr(t2), mkU64(sz)));
sewardj5b470602005-02-27 13:10:48 +000013296 putIRegRexB(sz, pfx, opc-0x58, mkexpr(t1));
13297 DIP("pop%c %s\n", nameISize(sz), nameIRegRexB(sz,pfx,opc-0x58));
sewardj55dbb262005-01-28 16:36:51 +000013298 break;
13299
sewardj85520e42005-02-19 15:22:38 +000013300 case 0x9D: /* POPF */
13301 /* Note. There is no encoding for a 32-bit popf in 64-bit mode.
13302 So sz==4 actually means sz==8. */
sewardj5b470602005-02-27 13:10:48 +000013303 if (haveF2orF3(pfx)) goto decode_failure;
sewardj85520e42005-02-19 15:22:38 +000013304 vassert(sz == 2 || sz == 4);
13305 if (sz == 4) sz = 8;
sewardj5b470602005-02-27 13:10:48 +000013306 if (sz != 8) goto decode_failure; // until we know a sz==2 test case exists
sewardj85520e42005-02-19 15:22:38 +000013307 t1 = newTemp(Ity_I64); t2 = newTemp(Ity_I64);
13308 assign(t2, getIReg64(R_RSP));
13309 assign(t1, widenUto64(loadLE(szToITy(sz),mkexpr(t2))));
13310 putIReg64(R_RSP, binop(Iop_Add64, mkexpr(t2), mkU64(sz)));
13311 /* t1 is the flag word. Mask out everything except OSZACP and
13312 set the flags thunk to AMD64G_CC_OP_COPY. */
13313 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(AMD64G_CC_OP_COPY) ));
13314 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
13315 stmt( IRStmt_Put( OFFB_CC_DEP1,
13316 binop(Iop_And64,
13317 mkexpr(t1),
13318 mkU64( AMD64G_CC_MASK_C | AMD64G_CC_MASK_P
13319 | AMD64G_CC_MASK_A | AMD64G_CC_MASK_Z
13320 | AMD64G_CC_MASK_S| AMD64G_CC_MASK_O )
13321 )
13322 )
13323 );
13324
13325 /* Also need to set the D flag, which is held in bit 10 of t1.
13326 If zero, put 1 in OFFB_DFLAG, else -1 in OFFB_DFLAG. */
13327 stmt( IRStmt_Put(
13328 OFFB_DFLAG,
13329 IRExpr_Mux0X(
13330 unop(Iop_32to8,
13331 unop(Iop_64to32,
13332 binop(Iop_And64,
13333 binop(Iop_Shr64, mkexpr(t1), mkU8(10)),
13334 mkU64(1)))),
13335 mkU64(1),
13336 mkU64(0xFFFFFFFFFFFFFFFFULL)))
13337 );
13338
13339 /* And set the ID flag */
13340 stmt( IRStmt_Put(
13341 OFFB_IDFLAG,
13342 IRExpr_Mux0X(
13343 unop(Iop_32to8,
13344 unop(Iop_64to32,
13345 binop(Iop_And64,
13346 binop(Iop_Shr64, mkexpr(t1), mkU8(21)),
13347 mkU64(1)))),
13348 mkU64(0),
13349 mkU64(1)))
13350 );
13351
13352 DIP("popf%c\n", nameISize(sz));
13353 break;
13354
sewardjd20c8852005-01-20 20:04:07 +000013355//.. case 0x61: /* POPA */
13356//.. /* This is almost certainly wrong for sz==2. So ... */
13357//.. if (sz != 4) goto decode_failure;
13358//..
13359//.. /* t5 is the old %ESP value. */
13360//.. t5 = newTemp(Ity_I32);
13361//.. assign( t5, getIReg(4, R_ESP) );
13362//..
13363//.. /* Reload all the registers, except %esp. */
13364//.. putIReg(4,R_EAX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(28)) ));
13365//.. putIReg(4,R_ECX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(24)) ));
13366//.. putIReg(4,R_EDX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(20)) ));
13367//.. putIReg(4,R_EBX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(16)) ));
13368//.. /* ignore saved %ESP */
13369//.. putIReg(4,R_EBP, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32( 8)) ));
13370//.. putIReg(4,R_ESI, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32( 4)) ));
13371//.. putIReg(4,R_EDI, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32( 0)) ));
13372//..
13373//.. /* and move %ESP back up */
13374//.. putIReg( 4, R_ESP, binop(Iop_Add32, mkexpr(t5), mkU32(8*4)) );
13375//..
13376//.. DIP("pusha%c\n", nameISize(sz));
13377//.. break;
sewardj432f8b62005-05-10 02:50:05 +000013378
13379 case 0x8F: { /* POPQ m64 / POPW m16 */
sewardj1bd14e72005-05-11 16:24:00 +000013380 Int len;
13381 UChar rm;
sewardj432f8b62005-05-10 02:50:05 +000013382 /* There is no encoding for 32-bit pop in 64-bit mode.
13383 So sz==4 actually means sz==8. */
13384 if (haveF2orF3(pfx)) goto decode_failure;
13385 vassert(sz == 2 || sz == 4);
13386 if (sz == 4) sz = 8;
13387 if (sz != 8) goto decode_failure; // until we know a sz==2 test case exists
13388
sewardj1bd14e72005-05-11 16:24:00 +000013389 rm = getUChar(delta);
sewardj432f8b62005-05-10 02:50:05 +000013390
13391 /* make sure this instruction is correct POP */
13392 if (epartIsReg(rm) || gregLO3ofRM(rm) != 0)
13393 goto decode_failure;
13394 /* and has correct size */
13395 vassert(sz == 8);
13396
13397 t1 = newTemp(Ity_I64);
13398 t3 = newTemp(Ity_I64);
13399 assign( t1, getIReg64(R_RSP) );
13400 assign( t3, loadLE(Ity_I64, mkexpr(t1)) );
13401
13402 /* Increase RSP; must be done before the STORE. Intel manual
13403 says: If the RSP register is used as a base register for
13404 addressing a destination operand in memory, the POP
13405 instruction computes the effective address of the operand
13406 after it increments the RSP register. */
13407 putIReg64(R_RSP, binop(Iop_Add64, mkexpr(t1), mkU64(sz)) );
13408
13409 addr = disAMode ( &len, pfx, delta, dis_buf, 0 );
13410 storeLE( mkexpr(addr), mkexpr(t3) );
13411
13412 DIP("popl %s\n", dis_buf);
13413
13414 delta += len;
13415 break;
13416 }
13417
sewardjd20c8852005-01-20 20:04:07 +000013418//.. //-- case 0x1F: /* POP %DS */
13419//.. //-- dis_pop_segreg( cb, R_DS, sz ); break;
13420//.. //-- case 0x07: /* POP %ES */
13421//.. //-- dis_pop_segreg( cb, R_ES, sz ); break;
13422//.. //-- case 0x17: /* POP %SS */
13423//.. //-- dis_pop_segreg( cb, R_SS, sz ); break;
sewardj55dbb262005-01-28 16:36:51 +000013424
13425 /* ------------------------ PUSH ----------------------- */
13426
13427 case 0x50: /* PUSH eAX */
13428 case 0x51: /* PUSH eCX */
13429 case 0x52: /* PUSH eDX */
13430 case 0x53: /* PUSH eBX */
13431 case 0x55: /* PUSH eBP */
13432 case 0x56: /* PUSH eSI */
13433 case 0x57: /* PUSH eDI */
13434 case 0x54: /* PUSH eSP */
13435 /* This is the Right Way, in that the value to be pushed is
13436 established before %rsp is changed, so that pushq %rsp
13437 correctly pushes the old value. */
sewardj03b07cc2005-01-31 18:09:43 +000013438 if (haveF2orF3(pfx)) goto decode_failure;
sewardj55dbb262005-01-28 16:36:51 +000013439 vassert(sz == 2 || sz == 4 || sz == 8);
13440 if (sz == 4)
13441 sz = 8; /* there is no encoding for 32-bit push in 64-bit mode */
13442 ty = sz==2 ? Ity_I16 : Ity_I64;
13443 t1 = newTemp(ty);
13444 t2 = newTemp(Ity_I64);
sewardj5b470602005-02-27 13:10:48 +000013445 assign(t1, getIRegRexB(sz, pfx, opc-0x50));
sewardj55dbb262005-01-28 16:36:51 +000013446 assign(t2, binop(Iop_Sub64, getIReg64(R_RSP), mkU64(sz)));
13447 putIReg64(R_RSP, mkexpr(t2) );
13448 storeLE(mkexpr(t2),mkexpr(t1));
sewardj5b470602005-02-27 13:10:48 +000013449 DIP("push%c %s\n", nameISize(sz), nameIRegRexB(sz,pfx,opc-0x50));
sewardj55dbb262005-01-28 16:36:51 +000013450 break;
13451
sewardja6b93d12005-02-17 09:28:28 +000013452 case 0x68: /* PUSH Iv */
sewardj5b470602005-02-27 13:10:48 +000013453 if (haveF2orF3(pfx)) goto decode_failure;
sewardja6b93d12005-02-17 09:28:28 +000013454 /* Note, sz==4 is not possible in 64-bit mode. Hence ... */
13455 if (sz == 4) sz = 8;
13456 d64 = getSDisp(imin(4,sz),delta);
13457 delta += imin(4,sz);
13458 goto do_push_I;
sewardj909c06d2005-02-19 22:47:41 +000013459 case 0x6A: /* PUSH Ib, sign-extended to sz */
sewardj5b470602005-02-27 13:10:48 +000013460 if (haveF2orF3(pfx)) goto decode_failure;
sewardj909c06d2005-02-19 22:47:41 +000013461 /* Note, sz==4 is not possible in 64-bit mode. Hence ... */
13462 if (sz == 4) sz = 8;
13463 d64 = getSDisp8(delta); delta += 1;
13464 goto do_push_I;
sewardja6b93d12005-02-17 09:28:28 +000013465 do_push_I:
13466 ty = szToITy(sz);
sewardj909c06d2005-02-19 22:47:41 +000013467 t1 = newTemp(Ity_I64);
13468 t2 = newTemp(ty);
sewardja6b93d12005-02-17 09:28:28 +000013469 assign( t1, binop(Iop_Sub64,getIReg64(R_RSP),mkU64(sz)) );
13470 putIReg64(R_RSP, mkexpr(t1) );
sewardjb2da8ec2006-08-28 18:54:18 +000013471 /* stop mkU16 asserting if d32 is a negative 16-bit number
13472 (bug #132813) */
13473 if (ty == Ity_I16)
13474 d64 &= 0xFFFF;
sewardja6b93d12005-02-17 09:28:28 +000013475 storeLE( mkexpr(t1), mkU(ty,d64) );
sewardj1027dc22005-02-26 01:55:02 +000013476 DIP("push%c $%lld\n", nameISize(sz), (Long)d64);
sewardja6b93d12005-02-17 09:28:28 +000013477 break;
13478
sewardj85520e42005-02-19 15:22:38 +000013479 case 0x9C: /* PUSHF */ {
13480 /* Note. There is no encoding for a 32-bit pushf in 64-bit
13481 mode. So sz==4 actually means sz==8. */
sewardj11faabe2006-07-24 09:09:36 +000013482 /* 24 July 06: has also been seen with a redundant REX prefix,
13483 so must also allow sz==8. */
sewardj5b470602005-02-27 13:10:48 +000013484 if (haveF2orF3(pfx)) goto decode_failure;
sewardj11faabe2006-07-24 09:09:36 +000013485 vassert(sz == 2 || sz == 4 || sz == 8);
sewardj85520e42005-02-19 15:22:38 +000013486 if (sz == 4) sz = 8;
sewardj5b470602005-02-27 13:10:48 +000013487 if (sz != 8) goto decode_failure; // until we know a sz==2 test case exists
sewardj85520e42005-02-19 15:22:38 +000013488
13489 t1 = newTemp(Ity_I64);
13490 assign( t1, binop(Iop_Sub64,getIReg64(R_RSP),mkU64(sz)) );
13491 putIReg64(R_RSP, mkexpr(t1) );
13492
13493 t2 = newTemp(Ity_I64);
13494 assign( t2, mk_amd64g_calculate_rflags_all() );
13495
13496 /* Patch in the D flag. This can simply be a copy of bit 10 of
13497 baseBlock[OFFB_DFLAG]. */
13498 t3 = newTemp(Ity_I64);
13499 assign( t3, binop(Iop_Or64,
13500 mkexpr(t2),
13501 binop(Iop_And64,
13502 IRExpr_Get(OFFB_DFLAG,Ity_I64),
13503 mkU64(1<<10)))
13504 );
13505
13506 /* And patch in the ID flag. */
13507 t4 = newTemp(Ity_I64);
13508 assign( t4, binop(Iop_Or64,
13509 mkexpr(t3),
13510 binop(Iop_And64,
13511 binop(Iop_Shl64, IRExpr_Get(OFFB_IDFLAG,Ity_I64),
13512 mkU8(21)),
13513 mkU64(1<<21)))
13514 );
13515
13516 /* if sz==2, the stored value needs to be narrowed. */
13517 if (sz == 2)
13518 storeLE( mkexpr(t1), unop(Iop_32to16,
13519 unop(Iop_64to32,mkexpr(t4))) );
13520 else
13521 storeLE( mkexpr(t1), mkexpr(t4) );
13522
13523 DIP("pushf%c\n", nameISize(sz));
13524 break;
13525 }
13526
sewardjd20c8852005-01-20 20:04:07 +000013527//.. case 0x60: /* PUSHA */
13528//.. /* This is almost certainly wrong for sz==2. So ... */
13529//.. if (sz != 4) goto decode_failure;
13530//..
13531//.. /* This is the Right Way, in that the value to be pushed is
13532//.. established before %esp is changed, so that pusha
13533//.. correctly pushes the old %esp value. New value of %esp is
13534//.. pushed at start. */
13535//.. /* t0 is the %ESP value we're going to push. */
13536//.. t0 = newTemp(Ity_I32);
13537//.. assign( t0, getIReg(4, R_ESP) );
13538//..
13539//.. /* t5 will be the new %ESP value. */
13540//.. t5 = newTemp(Ity_I32);
13541//.. assign( t5, binop(Iop_Sub32, mkexpr(t0), mkU32(8*4)) );
13542//..
13543//.. /* Update guest state before prodding memory. */
13544//.. putIReg(4, R_ESP, mkexpr(t5));
13545//..
13546//.. /* Dump all the registers. */
13547//.. storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(28)), getIReg(4,R_EAX) );
13548//.. storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(24)), getIReg(4,R_ECX) );
13549//.. storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(20)), getIReg(4,R_EDX) );
13550//.. storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(16)), getIReg(4,R_EBX) );
13551//.. storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(12)), mkexpr(t0) /*esp*/);
13552//.. storeLE( binop(Iop_Add32,mkexpr(t5),mkU32( 8)), getIReg(4,R_EBP) );
13553//.. storeLE( binop(Iop_Add32,mkexpr(t5),mkU32( 4)), getIReg(4,R_ESI) );
13554//.. storeLE( binop(Iop_Add32,mkexpr(t5),mkU32( 0)), getIReg(4,R_EDI) );
13555//..
13556//.. DIP("pusha%c\n", nameISize(sz));
13557//.. break;
13558//..
13559//..
13560//.. //-- case 0x0E: /* PUSH %CS */
13561//.. //-- dis_push_segreg( cb, R_CS, sz ); break;
13562//.. //-- case 0x1E: /* PUSH %DS */
13563//.. //-- dis_push_segreg( cb, R_DS, sz ); break;
13564//.. //-- case 0x06: /* PUSH %ES */
13565//.. //-- dis_push_segreg( cb, R_ES, sz ); break;
13566//.. //-- case 0x16: /* PUSH %SS */
13567//.. //-- dis_push_segreg( cb, R_SS, sz ); break;
13568//..
13569//.. /* ------------------------ SCAS et al ----------------- */
13570//..
13571//.. case 0xA4: /* MOVS, no REP prefix */
13572//.. case 0xA5:
13573//.. dis_string_op( dis_MOVS, ( opc == 0xA4 ? 1 : sz ), "movs", sorb );
13574//.. break;
13575//..
13576//.. case 0xA6: /* CMPSb, no REP prefix */
13577//.. //-- case 0xA7:
13578//.. dis_string_op( dis_CMPS, ( opc == 0xA6 ? 1 : sz ), "cmps", sorb );
13579//.. break;
13580//.. //--
sewardjd20c8852005-01-20 20:04:07 +000013581//.. //--
13582//.. //-- case 0xAC: /* LODS, no REP prefix */
13583//.. //-- case 0xAD:
13584//.. //-- dis_string_op( cb, dis_LODS, ( opc == 0xAC ? 1 : sz ), "lods", sorb );
13585//.. //-- break;
13586//..
13587//.. case 0xAE: /* SCAS, no REP prefix */
13588//.. case 0xAF:
13589//.. dis_string_op( dis_SCAS, ( opc == 0xAE ? 1 : sz ), "scas", sorb );
13590//.. break;
sewardjd0a12df2005-02-10 02:07:43 +000013591
13592
13593 case 0xFC: /* CLD */
sewardj5b470602005-02-27 13:10:48 +000013594 if (haveF2orF3(pfx)) goto decode_failure;
sewardjd0a12df2005-02-10 02:07:43 +000013595 stmt( IRStmt_Put( OFFB_DFLAG, mkU64(1)) );
13596 DIP("cld\n");
13597 break;
13598
sewardj909c06d2005-02-19 22:47:41 +000013599 case 0xFD: /* STD */
sewardj5b470602005-02-27 13:10:48 +000013600 if (haveF2orF3(pfx)) goto decode_failure;
sewardj909c06d2005-02-19 22:47:41 +000013601 stmt( IRStmt_Put( OFFB_DFLAG, mkU64(-1ULL)) );
13602 DIP("std\n");
13603 break;
13604
sewardj31804462006-05-12 20:15:33 +000013605 case 0xF8: /* CLC */
13606 case 0xF9: /* STC */
13607 case 0xF5: /* CMC */
13608 t0 = newTemp(Ity_I64);
13609 t1 = newTemp(Ity_I64);
13610 assign( t0, mk_amd64g_calculate_rflags_all() );
13611 switch (opc) {
13612 case 0xF8:
13613 assign( t1, binop(Iop_And64, mkexpr(t0),
13614 mkU64(~AMD64G_CC_MASK_C)));
13615 DIP("clc\n");
13616 break;
13617 case 0xF9:
13618 assign( t1, binop(Iop_Or64, mkexpr(t0),
13619 mkU64(AMD64G_CC_MASK_C)));
13620 DIP("stc\n");
13621 break;
13622 case 0xF5:
13623 assign( t1, binop(Iop_Xor64, mkexpr(t0),
13624 mkU64(AMD64G_CC_MASK_C)));
13625 DIP("cmc\n");
13626 break;
13627 default:
13628 vpanic("disInstr(x64)(clc/stc/cmc)");
13629 }
13630 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(AMD64G_CC_OP_COPY) ));
13631 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
13632 stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(t1) ));
13633 /* Set NDEP even though it isn't used. This makes redundant-PUT
13634 elimination of previous stores to this field work better. */
13635 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU64(0) ));
13636 break;
13637
sewardjd20c8852005-01-20 20:04:07 +000013638//.. /* REPNE prefix insn */
13639//.. case 0xF2: {
13640//.. Addr32 eip_orig = guest_eip_bbstart + delta - 1;
13641//.. vassert(sorb == 0);
sewardj8c332e22005-01-28 01:36:56 +000013642//.. abyte = getUChar(delta); delta++;
sewardjd20c8852005-01-20 20:04:07 +000013643//..
sewardj8c332e22005-01-28 01:36:56 +000013644//.. if (abyte == 0x66) { sz = 2; abyte = getUChar(delta); delta++; }
sewardjd20c8852005-01-20 20:04:07 +000013645//.. whatNext = Dis_StopHere;
13646//..
13647//.. switch (abyte) {
13648//.. /* According to the Intel manual, "repne movs" should never occur, but
13649//.. * in practice it has happened, so allow for it here... */
13650//.. case 0xA4: sz = 1; /* REPNE MOVS<sz> */
13651//.. goto decode_failure;
13652//.. //-- case 0xA5:
13653//.. // dis_REP_op ( CondNZ, dis_MOVS, sz, eip_orig,
13654//.. // guest_eip_bbstart+delta, "repne movs" );
13655//.. // break;
13656//.. //--
13657//.. //-- case 0xA6: sz = 1; /* REPNE CMPS<sz> */
13658//.. //-- case 0xA7:
13659//.. //-- dis_REP_op ( cb, CondNZ, dis_CMPS, sz, eip_orig, eip, "repne cmps" );
13660//.. //-- break;
13661//.. //--
13662//.. case 0xAE: sz = 1; /* REPNE SCAS<sz> */
13663//.. case 0xAF:
13664//.. dis_REP_op ( X86CondNZ, dis_SCAS, sz, eip_orig,
13665//.. guest_eip_bbstart+delta, "repne scas" );
13666//.. break;
13667//..
13668//.. default:
13669//.. goto decode_failure;
13670//.. }
13671//.. break;
13672//.. }
sewardjd0a12df2005-02-10 02:07:43 +000013673
sewardj909c06d2005-02-19 22:47:41 +000013674 /* ------ AE: SCAS variants ------ */
13675 case 0xAE:
13676 case 0xAF:
13677 /* F2 AE/AF: repne scasb/repne scas{w,l,q} */
sewardj42561ef2005-11-04 14:18:31 +000013678 if (haveASO(pfx))
13679 goto decode_failure;
sewardj85520e42005-02-19 15:22:38 +000013680 if (haveF2(pfx) && !haveF3(pfx)) {
13681 if (opc == 0xAE)
13682 sz = 1;
13683 dis_REP_op ( AMD64CondNZ, dis_SCAS, sz,
sewardj9e6491a2005-07-02 19:24:10 +000013684 guest_RIP_curr_instr,
13685 guest_RIP_bbstart+delta, "repne scas", pfx );
13686 dres.whatNext = Dis_StopHere;
sewardj85520e42005-02-19 15:22:38 +000013687 break;
13688 }
sewardj909c06d2005-02-19 22:47:41 +000013689 /* AE/AF: scasb/scas{w,l,q} */
13690 if (!haveF2(pfx) && !haveF3(pfx)) {
13691 if (opc == 0xAE)
13692 sz = 1;
13693 dis_string_op( dis_SCAS, sz, "scas", pfx );
13694 break;
13695 }
sewardj85520e42005-02-19 15:22:38 +000013696 goto decode_failure;
sewardjd0a12df2005-02-10 02:07:43 +000013697
sewardj909c06d2005-02-19 22:47:41 +000013698 /* ------ A6, A7: CMPS variants ------ */
13699 case 0xA6:
13700 case 0xA7:
13701 /* F3 A6/A7: repe cmps/rep cmps{w,l,q} */
sewardj42561ef2005-11-04 14:18:31 +000013702 if (haveASO(pfx))
13703 goto decode_failure;
sewardjd0a12df2005-02-10 02:07:43 +000013704 if (haveF3(pfx) && !haveF2(pfx)) {
13705 if (opc == 0xA6)
13706 sz = 1;
13707 dis_REP_op ( AMD64CondZ, dis_CMPS, sz,
sewardj9e6491a2005-07-02 19:24:10 +000013708 guest_RIP_curr_instr,
13709 guest_RIP_bbstart+delta, "repe cmps", pfx );
13710 dres.whatNext = Dis_StopHere;
sewardja6b93d12005-02-17 09:28:28 +000013711 break;
13712 }
13713 goto decode_failure;
13714
sewardj909c06d2005-02-19 22:47:41 +000013715 /* ------ AA, AB: STOS variants ------ */
13716 case 0xAA:
13717 case 0xAB:
13718 /* F3 AA/AB: rep stosb/rep stos{w,l,q} */
sewardj42561ef2005-11-04 14:18:31 +000013719 if (haveASO(pfx))
13720 goto decode_failure;
sewardja6b93d12005-02-17 09:28:28 +000013721 if (haveF3(pfx) && !haveF2(pfx)) {
sewardj909c06d2005-02-19 22:47:41 +000013722 if (opc == 0xAA)
13723 sz = 1;
sewardja6b93d12005-02-17 09:28:28 +000013724 dis_REP_op ( AMD64CondAlways, dis_STOS, sz,
sewardj9e6491a2005-07-02 19:24:10 +000013725 guest_RIP_curr_instr,
13726 guest_RIP_bbstart+delta, "rep stos", pfx );
13727 dres.whatNext = Dis_StopHere;
sewardj909c06d2005-02-19 22:47:41 +000013728 break;
13729 }
13730 /* AA/AB: stosb/stos{w,l,q} */
13731 if (!haveF3(pfx) && !haveF2(pfx)) {
13732 if (opc == 0xAA)
13733 sz = 1;
13734 dis_string_op( dis_STOS, sz, "stos", pfx );
sewardjd0a12df2005-02-10 02:07:43 +000013735 break;
13736 }
13737 goto decode_failure;
13738
sewardj909c06d2005-02-19 22:47:41 +000013739 /* ------ A4, A5: MOVS variants ------ */
13740 case 0xA4:
13741 case 0xA5:
13742 /* F3 A4: rep movsb */
sewardj42561ef2005-11-04 14:18:31 +000013743 if (haveASO(pfx))
13744 goto decode_failure;
sewardj909c06d2005-02-19 22:47:41 +000013745 if (haveF3(pfx) && !haveF2(pfx)) {
13746 if (opc == 0xA4)
13747 sz = 1;
13748 dis_REP_op ( AMD64CondAlways, dis_MOVS, sz,
sewardj9e6491a2005-07-02 19:24:10 +000013749 guest_RIP_curr_instr,
13750 guest_RIP_bbstart+delta, "rep movs", pfx );
13751 dres.whatNext = Dis_StopHere;
sewardj909c06d2005-02-19 22:47:41 +000013752 break;
13753 }
13754 /* A4: movsb */
13755 if (!haveF3(pfx) && !haveF2(pfx)) {
13756 if (opc == 0xA4)
13757 sz = 1;
13758 dis_string_op( dis_MOVS, sz, "movs", pfx );
13759 break;
13760 }
13761 goto decode_failure;
13762
sewardj7de0d3c2005-02-13 02:26:41 +000013763
13764 /* ------------------------ XCHG ----------------------- */
13765
sewardjc4356f02007-11-09 21:15:04 +000013766 /* XCHG reg,mem automatically asserts LOCK# even without a LOCK
13767 prefix. Therefore, surround it with a IRStmt_MBE(Imbe_BusLock)
13768 and IRStmt_MBE(Imbe_BusUnlock) pair. But be careful; if it is
13769 used with an explicit LOCK prefix, we don't want to end up with
13770 two IRStmt_MBE(Imbe_BusLock)s -- one made here and one made by
13771 the generic LOCK logic at the top of disInstr. */
sewardj1bf95982005-05-18 12:04:04 +000013772 case 0x86: /* XCHG Gb,Eb */
13773 sz = 1;
13774 /* Fall through ... */
sewardj7de0d3c2005-02-13 02:26:41 +000013775 case 0x87: /* XCHG Gv,Ev */
sewardj5b470602005-02-27 13:10:48 +000013776 if (haveF2orF3(pfx)) goto decode_failure;
sewardj7de0d3c2005-02-13 02:26:41 +000013777 modrm = getUChar(delta);
13778 ty = szToITy(sz);
13779 t1 = newTemp(ty); t2 = newTemp(ty);
13780 if (epartIsReg(modrm)) {
sewardj5b470602005-02-27 13:10:48 +000013781 assign(t1, getIRegE(sz, pfx, modrm));
13782 assign(t2, getIRegG(sz, pfx, modrm));
13783 putIRegG(sz, pfx, modrm, mkexpr(t1));
13784 putIRegE(sz, pfx, modrm, mkexpr(t2));
sewardj7de0d3c2005-02-13 02:26:41 +000013785 delta++;
13786 DIP("xchg%c %s, %s\n",
sewardj5b470602005-02-27 13:10:48 +000013787 nameISize(sz), nameIRegG(sz, pfx, modrm),
13788 nameIRegE(sz, pfx, modrm));
sewardj7de0d3c2005-02-13 02:26:41 +000013789 } else {
sewardjc4356f02007-11-09 21:15:04 +000013790 /* Need to add IRStmt_MBE(Imbe_BusLock). */
13791 if (pfx & PFX_LOCK) {
13792 /* check it's already been taken care of */
13793 vassert(unlock_bus_after_insn);
13794 } else {
13795 vassert(!unlock_bus_after_insn);
13796 stmt( IRStmt_MBE(Imbe_BusLock) );
13797 unlock_bus_after_insn = True;
13798 }
13799 /* Because unlock_bus_after_insn is now True, generic logic
13800 at the bottom of disInstr will add the
13801 IRStmt_MBE(Imbe_BusUnlock). */
sewardj7de0d3c2005-02-13 02:26:41 +000013802 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
sewardj5b470602005-02-27 13:10:48 +000013803 assign( t1, loadLE(ty, mkexpr(addr)) );
13804 assign( t2, getIRegG(sz, pfx, modrm) );
sewardj7de0d3c2005-02-13 02:26:41 +000013805 storeLE( mkexpr(addr), mkexpr(t2) );
sewardj5b470602005-02-27 13:10:48 +000013806 putIRegG( sz, pfx, modrm, mkexpr(t1) );
sewardj7de0d3c2005-02-13 02:26:41 +000013807 delta += alen;
13808 DIP("xchg%c %s, %s\n", nameISize(sz),
sewardj5b470602005-02-27 13:10:48 +000013809 nameIRegG(sz, pfx, modrm), dis_buf);
sewardj7de0d3c2005-02-13 02:26:41 +000013810 }
13811 break;
sewardj118b23e2005-01-29 02:14:44 +000013812
13813 case 0x90: /* XCHG eAX,eAX */
sewardjc8b26352005-07-20 09:23:13 +000013814 /* detect and handle F3 90 (rep nop) specially */
13815 if (!have66(pfx) && !haveF2(pfx) && haveF3(pfx)) {
13816 DIP("rep nop (P4 pause)\n");
13817 /* "observe" the hint. The Vex client needs to be careful not
13818 to cause very long delays as a result, though. */
13819 jmp_lit(Ijk_Yield, guest_RIP_bbstart+delta);
13820 dres.whatNext = Dis_StopHere;
13821 break;
13822 }
sewardj2d4fcd52005-05-18 11:47:47 +000013823 /* detect and handle NOPs specially */
13824 if (/* F2/F3 probably change meaning completely */
13825 !haveF2orF3(pfx)
13826 /* If REX.B is 1, we're not exchanging rAX with itself */
13827 && getRexB(pfx)==0 ) {
13828 DIP("nop\n");
13829 break;
13830 }
13831 /* else fall through to normal case. */
sewardja6b93d12005-02-17 09:28:28 +000013832 case 0x91: /* XCHG rAX,rCX */
13833 case 0x92: /* XCHG rAX,rDX */
13834 case 0x93: /* XCHG rAX,rBX */
13835 case 0x94: /* XCHG rAX,rSP */
13836 case 0x95: /* XCHG rAX,rBP */
13837 case 0x96: /* XCHG rAX,rSI */
13838 case 0x97: /* XCHG rAX,rDI */
sewardj2d4fcd52005-05-18 11:47:47 +000013839
13840 /* guard against mutancy */
sewardja6b93d12005-02-17 09:28:28 +000013841 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2d4fcd52005-05-18 11:47:47 +000013842
13843 /* sz == 2 could legitimately happen, but we don't handle it yet */
13844 if (sz == 2) goto decode_failure; /* awaiting test case */
13845
sewardja6b93d12005-02-17 09:28:28 +000013846 codegen_xchg_rAX_Reg ( pfx, sz, opc - 0x90 );
13847 break;
13848
sewardjd20c8852005-01-20 20:04:07 +000013849//.. //-- /* ------------------------ XLAT ----------------------- */
13850//.. //--
13851//.. //-- case 0xD7: /* XLAT */
13852//.. //-- t1 = newTemp(cb); t2 = newTemp(cb);
13853//.. //-- uInstr2(cb, GET, sz, ArchReg, R_EBX, TempReg, t1); /* get eBX */
sewardj42561ef2005-11-04 14:18:31 +000013854//.. //-- handleAddrOverrides( cb, sorb, t1 ); /* make t1 DS:eBX */
sewardjd20c8852005-01-20 20:04:07 +000013855//.. //-- uInstr2(cb, GET, 1, ArchReg, R_AL, TempReg, t2); /* get AL */
13856//.. //-- /* Widen %AL to 32 bits, so it's all defined when we add it. */
13857//.. //-- uInstr1(cb, WIDEN, 4, TempReg, t2);
13858//.. //-- uWiden(cb, 1, False);
13859//.. //-- uInstr2(cb, ADD, sz, TempReg, t2, TempReg, t1); /* add AL to eBX */
13860//.. //-- uInstr2(cb, LOAD, 1, TempReg, t1, TempReg, t2); /* get byte at t1 into t2 */
13861//.. //-- uInstr2(cb, PUT, 1, TempReg, t2, ArchReg, R_AL); /* put byte into AL */
13862//.. //--
13863//.. //-- DIP("xlat%c [ebx]\n", nameISize(sz));
13864//.. //-- break;
13865//.. //--
13866//.. //-- /* ------------------------ IN / OUT ----------------------- */
13867//.. //--
13868//.. //-- case 0xE4: /* IN ib, %al */
13869//.. //-- case 0xE5: /* IN ib, %{e}ax */
13870//.. //-- case 0xEC: /* IN (%dx),%al */
13871//.. //-- case 0xED: /* IN (%dx),%{e}ax */
13872//.. //-- t1 = newTemp(cb);
13873//.. //-- t2 = newTemp(cb);
13874//.. //-- t3 = newTemp(cb);
13875//.. //--
13876//.. //-- uInstr0(cb, CALLM_S, 0);
13877//.. //-- /* operand size? */
13878//.. //-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t1);
13879//.. //-- uLiteral(cb, ( opc == 0xE4 || opc == 0xEC ) ? 1 : sz);
13880//.. //-- uInstr1(cb, PUSH, 4, TempReg, t1);
13881//.. //-- /* port number ? */
13882//.. //-- if ( opc == 0xE4 || opc == 0xE5 ) {
13883//.. //-- abyte = getUChar(eip); eip++;
13884//.. //-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
13885//.. //-- uLiteral(cb, abyte);
13886//.. //-- }
13887//.. //-- else
13888//.. //-- uInstr2(cb, GET, 4, ArchReg, R_EDX, TempReg, t2);
13889//.. //--
13890//.. //-- uInstr1(cb, PUSH, 4, TempReg, t2);
13891//.. //-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_IN));
13892//.. //-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
13893//.. //-- uInstr1(cb, POP, 4, TempReg, t2);
13894//.. //-- uInstr1(cb, CLEAR, 0, Lit16, 4);
13895//.. //-- uInstr0(cb, CALLM_E, 0);
13896//.. //-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_EAX);
13897//.. //-- if ( opc == 0xE4 || opc == 0xE5 ) {
13898//.. //-- DIP("in 0x%x, %%eax/%%ax/%%al\n", getUChar(eip-1) );
13899//.. //-- } else {
13900//.. //-- DIP("in (%%dx), %%eax/%%ax/%%al\n");
13901//.. //-- }
13902//.. //-- break;
13903//.. //-- case 0xE6: /* OUT %al,ib */
13904//.. //-- case 0xE7: /* OUT %{e}ax,ib */
13905//.. //-- case 0xEE: /* OUT %al,(%dx) */
13906//.. //-- case 0xEF: /* OUT %{e}ax,(%dx) */
13907//.. //-- t1 = newTemp(cb);
13908//.. //-- t2 = newTemp(cb);
13909//.. //-- t3 = newTemp(cb);
13910//.. //--
13911//.. //-- uInstr0(cb, CALLM_S, 0);
13912//.. //-- /* operand size? */
13913//.. //-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t1);
13914//.. //-- uLiteral(cb, ( opc == 0xE6 || opc == 0xEE ) ? 1 : sz);
13915//.. //-- uInstr1(cb, PUSH, 4, TempReg, t1);
13916//.. //-- /* port number ? */
13917//.. //-- if ( opc == 0xE6 || opc == 0xE7 ) {
13918//.. //-- abyte = getUChar(eip); eip++;
13919//.. //-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
13920//.. //-- uLiteral(cb, abyte);
13921//.. //-- }
13922//.. //-- else
13923//.. //-- uInstr2(cb, GET, 4, ArchReg, R_EDX, TempReg, t2);
13924//.. //-- uInstr1(cb, PUSH, 4, TempReg, t2);
13925//.. //-- uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, t3);
13926//.. //-- uInstr1(cb, PUSH, 4, TempReg, t3);
13927//.. //-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_OUT));
13928//.. //-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
13929//.. //-- uInstr1(cb, CLEAR, 0, Lit16, 12);
13930//.. //-- uInstr0(cb, CALLM_E, 0);
13931//.. //-- if ( opc == 0xE4 || opc == 0xE5 ) {
13932//.. //-- DIP("out %%eax/%%ax/%%al, 0x%x\n", getUChar(eip-1) );
13933//.. //-- } else {
13934//.. //-- DIP("out %%eax/%%ax/%%al, (%%dx)\n");
13935//.. //-- }
13936//.. //-- break;
sewardj3ca55a12005-01-27 16:06:23 +000013937
13938 /* ------------------------ (Grp1 extensions) ---------- */
13939
13940 case 0x80: /* Grp1 Ib,Eb */
sewardj5b470602005-02-27 13:10:48 +000013941 if (haveF2orF3(pfx)) goto decode_failure;
sewardj8c332e22005-01-28 01:36:56 +000013942 modrm = getUChar(delta);
sewardj3ca55a12005-01-27 16:06:23 +000013943 am_sz = lengthAMode(pfx,delta);
13944 sz = 1;
13945 d_sz = 1;
13946 d64 = getSDisp8(delta + am_sz);
13947 delta = dis_Grp1 ( pfx, delta, modrm, am_sz, d_sz, sz, d64 );
13948 break;
13949
13950 case 0x81: /* Grp1 Iv,Ev */
13951 if (haveF2orF3(pfx)) goto decode_failure;
sewardj8c332e22005-01-28 01:36:56 +000013952 modrm = getUChar(delta);
sewardj3ca55a12005-01-27 16:06:23 +000013953 am_sz = lengthAMode(pfx,delta);
13954 d_sz = imin(sz,4);
13955 d64 = getSDisp(d_sz, delta + am_sz);
13956 delta = dis_Grp1 ( pfx, delta, modrm, am_sz, d_sz, sz, d64 );
13957 break;
13958
13959 case 0x83: /* Grp1 Ib,Ev */
13960 if (haveF2orF3(pfx)) goto decode_failure;
sewardj8c332e22005-01-28 01:36:56 +000013961 modrm = getUChar(delta);
sewardj3ca55a12005-01-27 16:06:23 +000013962 am_sz = lengthAMode(pfx,delta);
13963 d_sz = 1;
13964 d64 = getSDisp8(delta + am_sz);
13965 delta = dis_Grp1 ( pfx, delta, modrm, am_sz, d_sz, sz, d64 );
13966 break;
13967
sewardj118b23e2005-01-29 02:14:44 +000013968 /* ------------------------ (Grp2 extensions) ---------- */
sewardj03b07cc2005-01-31 18:09:43 +000013969
sewardjfd4203c2007-03-21 00:21:56 +000013970 case 0xC0: { /* Grp2 Ib,Eb */
13971 Bool decode_OK = True;
sewardj5b470602005-02-27 13:10:48 +000013972 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000013973 modrm = getUChar(delta);
13974 am_sz = lengthAMode(pfx,delta);
13975 d_sz = 1;
13976 d64 = getUChar(delta + am_sz);
13977 sz = 1;
13978 delta = dis_Grp2 ( pfx, delta, modrm, am_sz, d_sz, sz,
sewardjfd4203c2007-03-21 00:21:56 +000013979 mkU8(d64 & 0xFF), NULL, &decode_OK );
13980 if (!decode_OK) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000013981 break;
sewardjfd4203c2007-03-21 00:21:56 +000013982 }
13983 case 0xC1: { /* Grp2 Ib,Ev */
13984 Bool decode_OK = True;
sewardj5b470602005-02-27 13:10:48 +000013985 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000013986 modrm = getUChar(delta);
13987 am_sz = lengthAMode(pfx,delta);
13988 d_sz = 1;
13989 d64 = getUChar(delta + am_sz);
13990 delta = dis_Grp2 ( pfx, delta, modrm, am_sz, d_sz, sz,
sewardjfd4203c2007-03-21 00:21:56 +000013991 mkU8(d64 & 0xFF), NULL, &decode_OK );
13992 if (!decode_OK) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000013993 break;
sewardjfd4203c2007-03-21 00:21:56 +000013994 }
13995 case 0xD0: { /* Grp2 1,Eb */
13996 Bool decode_OK = True;
sewardj5b470602005-02-27 13:10:48 +000013997 if (haveF2orF3(pfx)) goto decode_failure;
sewardj03b07cc2005-01-31 18:09:43 +000013998 modrm = getUChar(delta);
13999 am_sz = lengthAMode(pfx,delta);
14000 d_sz = 0;
14001 d64 = 1;
14002 sz = 1;
14003 delta = dis_Grp2 ( pfx, delta, modrm, am_sz, d_sz, sz,
sewardjfd4203c2007-03-21 00:21:56 +000014004 mkU8(d64), NULL, &decode_OK );
14005 if (!decode_OK) goto decode_failure;
sewardj03b07cc2005-01-31 18:09:43 +000014006 break;
sewardjfd4203c2007-03-21 00:21:56 +000014007 }
14008 case 0xD1: { /* Grp2 1,Ev */
14009 Bool decode_OK = True;
sewardj5b470602005-02-27 13:10:48 +000014010 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000014011 modrm = getUChar(delta);
14012 am_sz = lengthAMode(pfx,delta);
14013 d_sz = 0;
14014 d64 = 1;
14015 delta = dis_Grp2 ( pfx, delta, modrm, am_sz, d_sz, sz,
sewardjfd4203c2007-03-21 00:21:56 +000014016 mkU8(d64), NULL, &decode_OK );
14017 if (!decode_OK) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000014018 break;
sewardjfd4203c2007-03-21 00:21:56 +000014019 }
14020 case 0xD2: { /* Grp2 CL,Eb */
14021 Bool decode_OK = True;
sewardj5b470602005-02-27 13:10:48 +000014022 if (haveF2orF3(pfx)) goto decode_failure;
sewardj85520e42005-02-19 15:22:38 +000014023 modrm = getUChar(delta);
14024 am_sz = lengthAMode(pfx,delta);
14025 d_sz = 0;
14026 sz = 1;
14027 delta = dis_Grp2 ( pfx, delta, modrm, am_sz, d_sz, sz,
sewardjfd4203c2007-03-21 00:21:56 +000014028 getIRegCL(), "%cl", &decode_OK );
14029 if (!decode_OK) goto decode_failure;
sewardj85520e42005-02-19 15:22:38 +000014030 break;
sewardjfd4203c2007-03-21 00:21:56 +000014031 }
14032 case 0xD3: { /* Grp2 CL,Ev */
14033 Bool decode_OK = True;
sewardj5b470602005-02-27 13:10:48 +000014034 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000014035 modrm = getUChar(delta);
14036 am_sz = lengthAMode(pfx,delta);
14037 d_sz = 0;
14038 delta = dis_Grp2 ( pfx, delta, modrm, am_sz, d_sz, sz,
sewardjfd4203c2007-03-21 00:21:56 +000014039 getIRegCL(), "%cl", &decode_OK );
14040 if (!decode_OK) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000014041 break;
sewardjfd4203c2007-03-21 00:21:56 +000014042 }
sewardj32b2bbe2005-01-28 00:50:10 +000014043
14044 /* ------------------------ (Grp3 extensions) ---------- */
14045
sewardjfd4203c2007-03-21 00:21:56 +000014046 case 0xF6: { /* Grp3 Eb */
14047 Bool decode_OK = True;
sewardj5b470602005-02-27 13:10:48 +000014048 if (haveF2orF3(pfx)) goto decode_failure;
sewardjfd4203c2007-03-21 00:21:56 +000014049 delta = dis_Grp3 ( pfx, 1, delta, &decode_OK );
14050 if (!decode_OK) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000014051 break;
sewardjfd4203c2007-03-21 00:21:56 +000014052 }
14053 case 0xF7: { /* Grp3 Ev */
14054 Bool decode_OK = True;
sewardj5b470602005-02-27 13:10:48 +000014055 if (haveF2orF3(pfx)) goto decode_failure;
sewardjfd4203c2007-03-21 00:21:56 +000014056 delta = dis_Grp3 ( pfx, sz, delta, &decode_OK );
14057 if (!decode_OK) goto decode_failure;
sewardj32b2bbe2005-01-28 00:50:10 +000014058 break;
sewardjfd4203c2007-03-21 00:21:56 +000014059 }
sewardj32b2bbe2005-01-28 00:50:10 +000014060
sewardj03b07cc2005-01-31 18:09:43 +000014061 /* ------------------------ (Grp4 extensions) ---------- */
14062
sewardjfd4203c2007-03-21 00:21:56 +000014063 case 0xFE: { /* Grp4 Eb */
14064 Bool decode_OK = True;
sewardj5b470602005-02-27 13:10:48 +000014065 if (haveF2orF3(pfx)) goto decode_failure;
sewardjfd4203c2007-03-21 00:21:56 +000014066 delta = dis_Grp4 ( pfx, delta, &decode_OK );
14067 if (!decode_OK) goto decode_failure;
sewardj03b07cc2005-01-31 18:09:43 +000014068 break;
sewardjfd4203c2007-03-21 00:21:56 +000014069 }
sewardj354e5c62005-01-27 20:12:52 +000014070
14071 /* ------------------------ (Grp5 extensions) ---------- */
14072
sewardjfd4203c2007-03-21 00:21:56 +000014073 case 0xFF: { /* Grp5 Ev */
14074 Bool decode_OK = True;
sewardj5b470602005-02-27 13:10:48 +000014075 if (haveF2orF3(pfx)) goto decode_failure;
sewardjfd4203c2007-03-21 00:21:56 +000014076 delta = dis_Grp5 ( vmi, pfx, sz, delta, &dres, &decode_OK );
14077 if (!decode_OK) goto decode_failure;
sewardj354e5c62005-01-27 20:12:52 +000014078 break;
sewardjfd4203c2007-03-21 00:21:56 +000014079 }
sewardj3ca55a12005-01-27 16:06:23 +000014080
14081 /* ------------------------ Escapes to 2-byte opcodes -- */
14082
14083 case 0x0F: {
sewardj8c332e22005-01-28 01:36:56 +000014084 opc = getUChar(delta); delta++;
sewardj3ca55a12005-01-27 16:06:23 +000014085 switch (opc) {
14086
sewardj1d511802005-03-27 17:59:45 +000014087 /* =-=-=-=-=-=-=-=-=- Grp8 =-=-=-=-=-=-=-=-=-=-=-= */
14088
14089 case 0xBA: { /* Grp8 Ib,Ev */
14090 Bool decode_OK = False;
14091 if (haveF2orF3(pfx)) goto decode_failure;
14092 modrm = getUChar(delta);
14093 am_sz = lengthAMode(pfx,delta);
14094 d64 = getSDisp8(delta + am_sz);
14095 delta = dis_Grp8_Imm ( pfx, delta, modrm, am_sz, sz, d64,
14096 &decode_OK );
14097 if (!decode_OK)
14098 goto decode_failure;
14099 break;
14100 }
14101
sewardjf53b7352005-04-06 20:01:56 +000014102 /* =-=-=-=-=-=-=-=-=- BSF/BSR -=-=-=-=-=-=-=-=-=-= */
14103
14104 case 0xBC: /* BSF Gv,Ev */
14105 if (haveF2orF3(pfx)) goto decode_failure;
14106 delta = dis_bs_E_G ( pfx, sz, delta, True );
14107 break;
sewardj537cab02005-04-07 02:03:52 +000014108 case 0xBD: /* BSR Gv,Ev */
14109 if (haveF2orF3(pfx)) goto decode_failure;
14110 delta = dis_bs_E_G ( pfx, sz, delta, False );
14111 break;
sewardj82c9f2f2005-03-02 16:05:13 +000014112
14113 /* =-=-=-=-=-=-=-=-=- BSWAP -=-=-=-=-=-=-=-=-=-=-= */
14114
14115 case 0xC8: /* BSWAP %eax */
14116 case 0xC9:
14117 case 0xCA:
14118 case 0xCB:
14119 case 0xCC:
14120 case 0xCD:
14121 case 0xCE:
14122 case 0xCF: /* BSWAP %edi */
14123 if (haveF2orF3(pfx)) goto decode_failure;
14124 /* According to the AMD64 docs, this insn can have size 4 or
14125 8. */
14126 if (sz == 4) {
14127 t1 = newTemp(Ity_I32);
14128 t2 = newTemp(Ity_I32);
14129 assign( t1, getIRegRexB(4, pfx, opc-0xC8) );
14130 assign( t2,
14131 binop(Iop_Or32,
14132 binop(Iop_Shl32, mkexpr(t1), mkU8(24)),
14133 binop(Iop_Or32,
sewardj61408222006-08-16 00:25:28 +000014134 binop(Iop_And32, binop(Iop_Shl32, mkexpr(t1), mkU8(8)),
sewardj82c9f2f2005-03-02 16:05:13 +000014135 mkU32(0x00FF0000)),
14136 binop(Iop_Or32,
14137 binop(Iop_And32, binop(Iop_Shr32, mkexpr(t1), mkU8(8)),
14138 mkU32(0x0000FF00)),
14139 binop(Iop_And32, binop(Iop_Shr32, mkexpr(t1), mkU8(24)),
14140 mkU32(0x000000FF) )
14141 )))
14142 );
14143 putIRegRexB(4, pfx, opc-0xC8, mkexpr(t2));
14144 DIP("bswapl %s\n", nameIRegRexB(4, pfx, opc-0xC8));
14145 break;
sewardj98e9f342005-07-23 12:07:37 +000014146 }
14147 else if (sz == 8) {
sewardj61408222006-08-16 00:25:28 +000014148 IRTemp m8 = newTemp(Ity_I64);
14149 IRTemp s8 = newTemp(Ity_I64);
14150 IRTemp m16 = newTemp(Ity_I64);
14151 IRTemp s16 = newTemp(Ity_I64);
14152 IRTemp m32 = newTemp(Ity_I64);
sewardj98e9f342005-07-23 12:07:37 +000014153 t1 = newTemp(Ity_I64);
14154 t2 = newTemp(Ity_I64);
14155 assign( t1, getIRegRexB(8, pfx, opc-0xC8) );
14156
sewardj61408222006-08-16 00:25:28 +000014157 assign( m8, mkU64(0xFF00FF00FF00FF00ULL) );
14158 assign( s8,
14159 binop(Iop_Or64,
14160 binop(Iop_Shr64,
14161 binop(Iop_And64,mkexpr(t1),mkexpr(m8)),
14162 mkU8(8)),
14163 binop(Iop_And64,
14164 binop(Iop_Shl64,mkexpr(t1),mkU8(8)),
14165 mkexpr(m8))
14166 )
14167 );
sewardj98e9f342005-07-23 12:07:37 +000014168
sewardj61408222006-08-16 00:25:28 +000014169 assign( m16, mkU64(0xFFFF0000FFFF0000ULL) );
14170 assign( s16,
14171 binop(Iop_Or64,
14172 binop(Iop_Shr64,
14173 binop(Iop_And64,mkexpr(s8),mkexpr(m16)),
14174 mkU8(16)),
14175 binop(Iop_And64,
14176 binop(Iop_Shl64,mkexpr(s8),mkU8(16)),
14177 mkexpr(m16))
14178 )
14179 );
sewardj98e9f342005-07-23 12:07:37 +000014180
sewardj61408222006-08-16 00:25:28 +000014181 assign( m32, mkU64(0xFFFFFFFF00000000ULL) );
14182 assign( t2,
14183 binop(Iop_Or64,
14184 binop(Iop_Shr64,
14185 binop(Iop_And64,mkexpr(s16),mkexpr(m32)),
14186 mkU8(32)),
14187 binop(Iop_And64,
14188 binop(Iop_Shl64,mkexpr(s16),mkU8(32)),
14189 mkexpr(m32))
14190 )
14191 );
sewardj98e9f342005-07-23 12:07:37 +000014192
14193 putIRegRexB(8, pfx, opc-0xC8, mkexpr(t2));
14194 DIP("bswapq %s\n", nameIRegRexB(8, pfx, opc-0xC8));
14195 break;
sewardj82c9f2f2005-03-02 16:05:13 +000014196 } else {
14197 goto decode_failure;
14198 }
14199
sewardj9ed16802005-08-24 10:46:19 +000014200 /* =-=-=-=-=-=-=-=-=- BT/BTS/BTR/BTC =-=-=-=-=-=-= */
14201
sewardja7690fb2005-10-05 17:19:11 +000014202 /* All of these are possible at sizes 2, 4 and 8, but until a
14203 size 2 test case shows up, only handle sizes 4 and 8. */
sewardj9ed16802005-08-24 10:46:19 +000014204
14205 case 0xA3: /* BT Gv,Ev */
14206 if (haveF2orF3(pfx)) goto decode_failure;
sewardj25d23862006-05-12 17:47:21 +000014207 if (sz != 8 && sz != 4 && sz != 2) goto decode_failure;
sewardj9ed16802005-08-24 10:46:19 +000014208 delta = dis_bt_G_E ( pfx, sz, delta, BtOpNone );
14209 break;
14210 case 0xB3: /* BTR Gv,Ev */
14211 if (haveF2orF3(pfx)) goto decode_failure;
sewardj25d23862006-05-12 17:47:21 +000014212 if (sz != 8 && sz != 4 && sz != 2) goto decode_failure;
sewardj9ed16802005-08-24 10:46:19 +000014213 delta = dis_bt_G_E ( pfx, sz, delta, BtOpReset );
14214 break;
14215 case 0xAB: /* BTS Gv,Ev */
14216 if (haveF2orF3(pfx)) goto decode_failure;
sewardj25d23862006-05-12 17:47:21 +000014217 if (sz != 8 && sz != 4 && sz != 2) goto decode_failure;
sewardj9ed16802005-08-24 10:46:19 +000014218 delta = dis_bt_G_E ( pfx, sz, delta, BtOpSet );
14219 break;
14220 case 0xBB: /* BTC Gv,Ev */
14221 if (haveF2orF3(pfx)) goto decode_failure;
sewardj25d23862006-05-12 17:47:21 +000014222 if (sz != 8 && sz != 4 && sz != 2) goto decode_failure;
sewardj9ed16802005-08-24 10:46:19 +000014223 delta = dis_bt_G_E ( pfx, sz, delta, BtOpComp );
14224 break;
sewardj3ca55a12005-01-27 16:06:23 +000014225
14226 /* =-=-=-=-=-=-=-=-=- CMOV =-=-=-=-=-=-=-=-=-=-=-= */
14227
14228 case 0x40:
14229 case 0x41:
14230 case 0x42: /* CMOVBb/CMOVNAEb (cmov below) */
14231 case 0x43: /* CMOVNBb/CMOVAEb (cmov not below) */
14232 case 0x44: /* CMOVZb/CMOVEb (cmov zero) */
14233 case 0x45: /* CMOVNZb/CMOVNEb (cmov not zero) */
14234 case 0x46: /* CMOVBEb/CMOVNAb (cmov below or equal) */
14235 case 0x47: /* CMOVNBEb/CMOVAb (cmov not below or equal) */
14236 case 0x48: /* CMOVSb (cmov negative) */
14237 case 0x49: /* CMOVSb (cmov not negative) */
14238 case 0x4A: /* CMOVP (cmov parity even) */
14239 case 0x4B: /* CMOVNP (cmov parity odd) */
14240 case 0x4C: /* CMOVLb/CMOVNGEb (cmov less) */
14241 case 0x4D: /* CMOVGEb/CMOVNLb (cmov greater or equal) */
14242 case 0x4E: /* CMOVLEb/CMOVNGb (cmov less or equal) */
14243 case 0x4F: /* CMOVGb/CMOVNLEb (cmov greater) */
sewardj5b470602005-02-27 13:10:48 +000014244 if (haveF2orF3(pfx)) goto decode_failure;
sewardj3ca55a12005-01-27 16:06:23 +000014245 delta = dis_cmov_E_G(pfx, sz, (AMD64Condcode)(opc - 0x40), delta);
14246 break;
14247
sewardja6b93d12005-02-17 09:28:28 +000014248 /* =-=-=-=-=-=-=-=-=- CMPXCHG -=-=-=-=-=-=-=-=-=-= */
14249
sewardj7f45b2b2007-11-16 00:18:44 +000014250 case 0xB0: { /* CMPXCHG Gb,Eb */
14251 Bool ok = True;
14252 if (haveF2orF3(pfx)) goto decode_failure;
14253 delta = dis_cmpxchg_G_E ( &ok, pfx, 1, delta );
14254 if (!ok) goto decode_failure;
14255 break;
14256 }
sewardjd0aa0a52006-08-17 01:20:01 +000014257 case 0xB1: { /* CMPXCHG Gv,Ev (allowed in 16,32,64 bit) */
14258 Bool ok = True;
sewardj5b470602005-02-27 13:10:48 +000014259 if (haveF2orF3(pfx)) goto decode_failure;
sewardjd0aa0a52006-08-17 01:20:01 +000014260 if (sz != 2 && sz != 4 && sz != 8) goto decode_failure;
14261 delta = dis_cmpxchg_G_E ( &ok, pfx, sz, delta );
14262 if (!ok) goto decode_failure;
sewardja6b93d12005-02-17 09:28:28 +000014263 break;
sewardjd0aa0a52006-08-17 01:20:01 +000014264 }
14265 case 0xC7: { /* CMPXCHG8B Ev, CMPXCHG16B Ev */
14266 Bool ok = True;
14267 if (have66orF2orF3(pfx)) goto decode_failure;
14268 if (sz != 4 && sz != 8) goto decode_failure;
14269 delta = dis_cmpxchg8b ( &ok, pfx, sz, delta );
14270 break;
14271 }
14272
sewardjd0a12df2005-02-10 02:07:43 +000014273 /* =-=-=-=-=-=-=-=-=- CPUID -=-=-=-=-=-=-=-=-=-=-= */
14274
14275 case 0xA2: { /* CPUID */
14276 /* Uses dirty helper:
14277 void amd64g_dirtyhelper_CPUID ( VexGuestAMD64State* )
14278 declared to mod rax, wr rbx, rcx, rdx
14279 */
14280 IRDirty* d = NULL;
14281 HChar* fName = NULL;
14282 void* fAddr = NULL;
sewardj5b470602005-02-27 13:10:48 +000014283 if (haveF2orF3(pfx)) goto decode_failure;
sewardj5117ce12006-01-27 21:20:15 +000014284 if (archinfo->hwcaps == 0/*baseline, == SSE2*/) {
14285 fName = "amd64g_dirtyhelper_CPUID";
14286 fAddr = &amd64g_dirtyhelper_CPUID;
sewardjd0a12df2005-02-10 02:07:43 +000014287 }
sewardj5117ce12006-01-27 21:20:15 +000014288 else
14289 vpanic("disInstr(amd64)(cpuid)");
14290
sewardjd0a12df2005-02-10 02:07:43 +000014291 vassert(fName); vassert(fAddr);
14292 d = unsafeIRDirty_0_N ( 0/*regparms*/,
14293 fName, fAddr, mkIRExprVec_0() );
14294 /* declare guest state effects */
14295 d->needsBBP = True;
14296 d->nFxState = 4;
14297 d->fxState[0].fx = Ifx_Modify;
14298 d->fxState[0].offset = OFFB_RAX;
14299 d->fxState[0].size = 8;
14300 d->fxState[1].fx = Ifx_Write;
14301 d->fxState[1].offset = OFFB_RBX;
14302 d->fxState[1].size = 8;
14303 d->fxState[2].fx = Ifx_Write;
14304 d->fxState[2].offset = OFFB_RCX;
14305 d->fxState[2].size = 8;
14306 d->fxState[3].fx = Ifx_Write;
14307 d->fxState[3].offset = OFFB_RDX;
14308 d->fxState[3].size = 8;
14309 /* execute the dirty call, side-effecting guest state */
14310 stmt( IRStmt_Dirty(d) );
14311 /* CPUID is a serialising insn. So, just in case someone is
14312 using it as a memory fence ... */
sewardjc4356f02007-11-09 21:15:04 +000014313 stmt( IRStmt_MBE(Imbe_Fence) );
sewardjd0a12df2005-02-10 02:07:43 +000014314 DIP("cpuid\n");
14315 break;
14316 }
14317
sewardj5e525292005-01-28 15:13:10 +000014318 /* =-=-=-=-=-=-=-=-=- MOVZX, MOVSX =-=-=-=-=-=-=-= */
14319
14320 case 0xB6: /* MOVZXb Eb,Gv */
sewardj5b470602005-02-27 13:10:48 +000014321 if (haveF2orF3(pfx)) goto decode_failure;
sewardj5e525292005-01-28 15:13:10 +000014322 if (sz != 2 && sz != 4 && sz != 8)
14323 goto decode_failure;
14324 delta = dis_movx_E_G ( pfx, delta, 1, sz, False );
14325 break;
14326 case 0xB7: /* MOVZXw Ew,Gv */
sewardj5b470602005-02-27 13:10:48 +000014327 if (haveF2orF3(pfx)) goto decode_failure;
sewardj5e525292005-01-28 15:13:10 +000014328 if (sz != 4 && sz != 8)
14329 goto decode_failure;
14330 delta = dis_movx_E_G ( pfx, delta, 2, sz, False );
14331 break;
14332
sewardj03b07cc2005-01-31 18:09:43 +000014333 case 0xBE: /* MOVSXb Eb,Gv */
sewardj5b470602005-02-27 13:10:48 +000014334 if (haveF2orF3(pfx)) goto decode_failure;
sewardj82c9f2f2005-03-02 16:05:13 +000014335 if (sz != 2 && sz != 4 && sz != 8)
sewardj03b07cc2005-01-31 18:09:43 +000014336 goto decode_failure;
14337 delta = dis_movx_E_G ( pfx, delta, 1, sz, True );
14338 break;
14339 case 0xBF: /* MOVSXw Ew,Gv */
sewardj5b470602005-02-27 13:10:48 +000014340 if (haveF2orF3(pfx)) goto decode_failure;
sewardj03b07cc2005-01-31 18:09:43 +000014341 if (sz != 4 && sz != 8)
14342 goto decode_failure;
14343 delta = dis_movx_E_G ( pfx, delta, 2, sz, True );
14344 break;
14345
sewardjd20c8852005-01-20 20:04:07 +000014346//.. //-- /* =-=-=-=-=-=-=-=-=-=-= MOVNTI -=-=-=-=-=-=-=-=-= */
14347//.. //--
14348//.. //-- case 0xC3: /* MOVNTI Gv,Ev */
14349//.. //-- vg_assert(sz == 4);
14350//.. //-- modrm = getUChar(eip);
14351//.. //-- vg_assert(!epartIsReg(modrm));
14352//.. //-- t1 = newTemp(cb);
14353//.. //-- uInstr2(cb, GET, 4, ArchReg, gregOfRM(modrm), TempReg, t1);
14354//.. //-- pair = disAMode ( cb, sorb, eip, dis_buf );
14355//.. //-- t2 = LOW24(pair);
14356//.. //-- eip += HI8(pair);
14357//.. //-- uInstr2(cb, STORE, 4, TempReg, t1, TempReg, t2);
14358//.. //-- DIP("movnti %s,%s\n", nameIReg(4,gregOfRM(modrm)), dis_buf);
14359//.. //-- break;
sewardj32b2bbe2005-01-28 00:50:10 +000014360
14361 /* =-=-=-=-=-=-=-=-=- MUL/IMUL =-=-=-=-=-=-=-=-=-= */
14362
14363 case 0xAF: /* IMUL Ev, Gv */
sewardj5b470602005-02-27 13:10:48 +000014364 if (haveF2orF3(pfx)) goto decode_failure;
sewardj32b2bbe2005-01-28 00:50:10 +000014365 delta = dis_mul_E_G ( pfx, sz, delta );
14366 break;
14367
sewardjec387ca2006-08-01 18:36:25 +000014368 /* =-=-=-=-=-=-=-=-=- NOPs =-=-=-=-=-=-=-=-=-=-=-= */
14369
14370 case 0x1F:
14371 if (haveF2orF3(pfx)) goto decode_failure;
14372 modrm = getUChar(delta);
14373 if (epartIsReg(modrm)) goto decode_failure;
14374 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
14375 delta += alen;
14376 DIP("nop%c %s\n", nameISize(sz), dis_buf);
14377 break;
14378
sewardj1389d4d2005-01-28 13:46:29 +000014379 /* =-=-=-=-=-=-=-=-=- Jcond d32 -=-=-=-=-=-=-=-=-= */
14380 case 0x80:
14381 case 0x81:
14382 case 0x82: /* JBb/JNAEb (jump below) */
14383 case 0x83: /* JNBb/JAEb (jump not below) */
14384 case 0x84: /* JZb/JEb (jump zero) */
14385 case 0x85: /* JNZb/JNEb (jump not zero) */
14386 case 0x86: /* JBEb/JNAb (jump below or equal) */
14387 case 0x87: /* JNBEb/JAb (jump not below or equal) */
14388 case 0x88: /* JSb (jump negative) */
14389 case 0x89: /* JSb (jump not negative) */
14390 case 0x8A: /* JP (jump parity even) */
14391 case 0x8B: /* JNP/JPO (jump parity odd) */
14392 case 0x8C: /* JLb/JNGEb (jump less) */
14393 case 0x8D: /* JGEb/JNLb (jump greater or equal) */
14394 case 0x8E: /* JLEb/JNGb (jump less or equal) */
14395 case 0x8F: /* JGb/JNLEb (jump greater) */
sewardj5b470602005-02-27 13:10:48 +000014396 if (haveF2orF3(pfx)) goto decode_failure;
sewardj9e6491a2005-07-02 19:24:10 +000014397 d64 = (guest_RIP_bbstart+delta+4) + getSDisp32(delta);
sewardj1389d4d2005-01-28 13:46:29 +000014398 delta += 4;
14399 jcc_01( (AMD64Condcode)(opc - 0x80),
sewardj9e6491a2005-07-02 19:24:10 +000014400 guest_RIP_bbstart+delta,
sewardj1389d4d2005-01-28 13:46:29 +000014401 d64 );
sewardj9e6491a2005-07-02 19:24:10 +000014402 dres.whatNext = Dis_StopHere;
sewardj1389d4d2005-01-28 13:46:29 +000014403 DIP("j%s-32 0x%llx\n", name_AMD64Condcode(opc - 0x80), d64);
14404 break;
14405
sewardjb04a47c2005-08-10 12:27:46 +000014406 /* =-=-=-=-=-=-=-=-=- PREFETCH =-=-=-=-=-=-=-=-=-= */
14407 case 0x0D: /* 0F 0D /0 -- prefetch mem8 */
14408 /* 0F 0D /1 -- prefetchw mem8 */
14409 if (have66orF2orF3(pfx)) goto decode_failure;
14410 modrm = getUChar(delta);
14411 if (epartIsReg(modrm)) goto decode_failure;
14412 if (gregLO3ofRM(modrm) != 0 && gregLO3ofRM(modrm) != 1)
14413 goto decode_failure;
14414
14415 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
14416 delta += alen;
14417
14418 switch (gregLO3ofRM(modrm)) {
14419 case 0: DIP("prefetch %s\n", dis_buf); break;
14420 case 1: DIP("prefetchw %s\n", dis_buf); break;
14421 default: vassert(0); /*NOTREACHED*/
14422 }
14423 break;
14424
sewardj31191072005-02-05 18:24:47 +000014425 /* =-=-=-=-=-=-=-=-=- RDTSC -=-=-=-=-=-=-=-=-=-=-= */
sewardjbc6af532005-08-23 23:16:51 +000014426 case 0x31: { /* RDTSC */
14427 IRTemp val = newTemp(Ity_I64);
14428 IRExpr** args = mkIRExprVec_0();
14429 IRDirty* d = unsafeIRDirty_1_N (
14430 val,
14431 0/*regparms*/,
14432 "amd64g_dirtyhelper_RDTSC",
14433 &amd64g_dirtyhelper_RDTSC,
14434 args
14435 );
14436 if (have66orF2orF3(pfx)) goto decode_failure;
14437 /* execute the dirty call, dumping the result in val. */
14438 stmt( IRStmt_Dirty(d) );
14439 putIRegRDX(4, unop(Iop_64HIto32, mkexpr(val)));
14440 putIRegRAX(4, unop(Iop_64to32, mkexpr(val)));
sewardj31191072005-02-05 18:24:47 +000014441 DIP("rdtsc\n");
14442 break;
sewardjbc6af532005-08-23 23:16:51 +000014443 }
sewardj31191072005-02-05 18:24:47 +000014444
sewardjd20c8852005-01-20 20:04:07 +000014445//.. /* =-=-=-=-=-=-=-=-=- PUSH/POP Sreg =-=-=-=-=-=-=-=-=-= */
14446//..
14447//.. case 0xA1: /* POP %FS */
14448//.. dis_pop_segreg( R_FS, sz ); break;
14449//.. case 0xA9: /* POP %GS */
14450//.. dis_pop_segreg( R_GS, sz ); break;
14451//..
14452//.. case 0xA0: /* PUSH %FS */
14453//.. dis_push_segreg( R_FS, sz ); break;
14454//.. case 0xA8: /* PUSH %GS */
14455//.. dis_push_segreg( R_GS, sz ); break;
sewardj118b23e2005-01-29 02:14:44 +000014456
14457 /* =-=-=-=-=-=-=-=-=- SETcc Eb =-=-=-=-=-=-=-=-=-= */
14458 case 0x90:
14459 case 0x91:
14460 case 0x92: /* set-Bb/set-NAEb (set if below) */
14461 case 0x93: /* set-NBb/set-AEb (set if not below) */
14462 case 0x94: /* set-Zb/set-Eb (set if zero) */
14463 case 0x95: /* set-NZb/set-NEb (set if not zero) */
14464 case 0x96: /* set-BEb/set-NAb (set if below or equal) */
14465 case 0x97: /* set-NBEb/set-Ab (set if not below or equal) */
14466 case 0x98: /* set-Sb (set if negative) */
14467 case 0x99: /* set-Sb (set if not negative) */
14468 case 0x9A: /* set-P (set if parity even) */
14469 case 0x9B: /* set-NP (set if parity odd) */
14470 case 0x9C: /* set-Lb/set-NGEb (set if less) */
14471 case 0x9D: /* set-GEb/set-NLb (set if greater or equal) */
14472 case 0x9E: /* set-LEb/set-NGb (set if less or equal) */
14473 case 0x9F: /* set-Gb/set-NLEb (set if greater) */
sewardj5b470602005-02-27 13:10:48 +000014474 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000014475 t1 = newTemp(Ity_I8);
14476 assign( t1, unop(Iop_1Uto8,mk_amd64g_calculate_condition(opc-0x90)) );
14477 modrm = getUChar(delta);
14478 if (epartIsReg(modrm)) {
14479 delta++;
sewardj5b470602005-02-27 13:10:48 +000014480 putIRegE(1, pfx, modrm, mkexpr(t1));
sewardj118b23e2005-01-29 02:14:44 +000014481 DIP("set%s %s\n", name_AMD64Condcode(opc-0x90),
sewardj5b470602005-02-27 13:10:48 +000014482 nameIRegE(1,pfx,modrm));
sewardj118b23e2005-01-29 02:14:44 +000014483 } else {
sewardj5cc00ff2005-03-27 04:48:32 +000014484 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
14485 delta += alen;
14486 storeLE( mkexpr(addr), mkexpr(t1) );
14487 DIP("set%s %s\n", name_AMD64Condcode(opc-0x90), dis_buf);
sewardj118b23e2005-01-29 02:14:44 +000014488 }
14489 break;
14490
sewardj33ef9c22005-11-04 20:05:57 +000014491 /* =-=-=-=-=-=-=-=-=- SHLD/SHRD -=-=-=-=-=-=-=-=-= */
14492
sewardj1287ab42006-05-12 21:03:48 +000014493 case 0xA4: /* SHLDv imm8,Gv,Ev */
14494 modrm = getUChar(delta);
14495 d64 = delta + lengthAMode(pfx, delta);
14496 vex_sprintf(dis_buf, "$%d", (Int)getUChar(d64));
14497 delta = dis_SHLRD_Gv_Ev (
14498 pfx, delta, modrm, sz,
14499 mkU8(getUChar(d64)), True, /* literal */
14500 dis_buf, True /* left */ );
14501 break;
sewardj33ef9c22005-11-04 20:05:57 +000014502 case 0xA5: /* SHLDv %cl,Gv,Ev */
14503 modrm = getUChar(delta);
14504 delta = dis_SHLRD_Gv_Ev (
14505 pfx, delta, modrm, sz,
14506 getIRegCL(), False, /* not literal */
14507 "%cl", True /* left */ );
14508 break;
14509
sewardj75ce3652005-11-04 20:49:36 +000014510 case 0xAC: /* SHRDv imm8,Gv,Ev */
14511 modrm = getUChar(delta);
14512 d64 = delta + lengthAMode(pfx, delta);
14513 vex_sprintf(dis_buf, "$%d", (Int)getUChar(d64));
14514 delta = dis_SHLRD_Gv_Ev (
14515 pfx, delta, modrm, sz,
14516 mkU8(getUChar(d64)), True, /* literal */
14517 dis_buf, False /* right */ );
14518 break;
sewardj33ef9c22005-11-04 20:05:57 +000014519 case 0xAD: /* SHRDv %cl,Gv,Ev */
14520 modrm = getUChar(delta);
14521 delta = dis_SHLRD_Gv_Ev (
14522 pfx, delta, modrm, sz,
14523 getIRegCL(), False, /* not literal */
14524 "%cl", False /* right */);
14525 break;
sewardje1698952005-02-08 15:02:39 +000014526
14527 /* =-=-=-=-=-=-=-=-=- SYSCALL -=-=-=-=-=-=-=-=-=-= */
14528 case 0x05: /* SYSCALL */
sewardj9e6491a2005-07-02 19:24:10 +000014529 guest_RIP_next_mustcheck = True;
14530 guest_RIP_next_assumed = guest_RIP_bbstart + delta;
14531 putIReg64( R_RCX, mkU64(guest_RIP_next_assumed) );
sewardje1698952005-02-08 15:02:39 +000014532 /* It's important that all guest state is up-to-date
14533 at this point. So we declare an end-of-block here, which
14534 forces any cached guest state to be flushed. */
sewardj4fa325a2005-11-03 13:27:24 +000014535 jmp_lit(Ijk_Sys_syscall, guest_RIP_next_assumed);
14536 dres.whatNext = Dis_StopHere;
14537 DIP("syscall\n");
14538 break;
sewardje1698952005-02-08 15:02:39 +000014539
sewardjb4fd2e72005-03-23 13:34:11 +000014540 /* =-=-=-=-=-=-=-=-=- XADD -=-=-=-=-=-=-=-=-=-= */
14541
sewardjd20c8852005-01-20 20:04:07 +000014542//.. //-- case 0xC0: /* XADD Gb,Eb */
14543//.. //-- eip = dis_xadd_G_E ( cb, sorb, 1, eip );
14544//.. //-- break;
sewardjb4fd2e72005-03-23 13:34:11 +000014545 case 0xC1: { /* XADD Gv,Ev */
14546 Bool decode_OK = False;
14547 delta = dis_xadd_G_E ( &decode_OK, pfx, sz, delta );
14548 if (!decode_OK)
14549 goto decode_failure;
14550 break;
14551 }
14552
sewardj8711f662005-05-09 17:52:56 +000014553 /* =-=-=-=-=-=-=-=-=- MMXery =-=-=-=-=-=-=-=-=-=-= */
14554
sewardj3d8107c2005-05-09 22:23:38 +000014555 case 0x71:
14556 case 0x72:
14557 case 0x73: /* PSLLgg/PSRAgg/PSRLgg mmxreg by imm8 */
14558
14559 case 0x6E: /* MOVD (src)ireg-or-mem, (dst)mmxreg */
14560 case 0x7E: /* MOVD (src)mmxreg, (dst)ireg-or-mem */
sewardj8711f662005-05-09 17:52:56 +000014561 case 0x7F: /* MOVQ (src)mmxreg, (dst)mmxreg-or-mem */
14562 case 0x6F: /* MOVQ (src)mmxreg-or-mem, (dst)mmxreg */
14563
14564 case 0xFC:
14565 case 0xFD:
14566 case 0xFE: /* PADDgg (src)mmxreg-or-mem, (dst)mmxreg */
14567
14568 case 0xEC:
14569 case 0xED: /* PADDSgg (src)mmxreg-or-mem, (dst)mmxreg */
14570
14571 case 0xDC:
14572 case 0xDD: /* PADDUSgg (src)mmxreg-or-mem, (dst)mmxreg */
14573
14574 case 0xF8:
14575 case 0xF9:
14576 case 0xFA: /* PSUBgg (src)mmxreg-or-mem, (dst)mmxreg */
14577
14578 case 0xE8:
14579 case 0xE9: /* PSUBSgg (src)mmxreg-or-mem, (dst)mmxreg */
14580
14581 case 0xD8:
14582 case 0xD9: /* PSUBUSgg (src)mmxreg-or-mem, (dst)mmxreg */
14583
14584 case 0xE5: /* PMULHW (src)mmxreg-or-mem, (dst)mmxreg */
14585 case 0xD5: /* PMULLW (src)mmxreg-or-mem, (dst)mmxreg */
14586
14587 case 0xF5: /* PMADDWD (src)mmxreg-or-mem, (dst)mmxreg */
14588
14589 case 0x74:
14590 case 0x75:
14591 case 0x76: /* PCMPEQgg (src)mmxreg-or-mem, (dst)mmxreg */
14592
14593 case 0x64:
14594 case 0x65:
14595 case 0x66: /* PCMPGTgg (src)mmxreg-or-mem, (dst)mmxreg */
14596
14597 case 0x6B: /* PACKSSDW (src)mmxreg-or-mem, (dst)mmxreg */
14598 case 0x63: /* PACKSSWB (src)mmxreg-or-mem, (dst)mmxreg */
14599 case 0x67: /* PACKUSWB (src)mmxreg-or-mem, (dst)mmxreg */
14600
14601 case 0x68:
14602 case 0x69:
14603 case 0x6A: /* PUNPCKHgg (src)mmxreg-or-mem, (dst)mmxreg */
14604
14605 case 0x60:
14606 case 0x61:
14607 case 0x62: /* PUNPCKLgg (src)mmxreg-or-mem, (dst)mmxreg */
14608
14609 case 0xDB: /* PAND (src)mmxreg-or-mem, (dst)mmxreg */
14610 case 0xDF: /* PANDN (src)mmxreg-or-mem, (dst)mmxreg */
14611 case 0xEB: /* POR (src)mmxreg-or-mem, (dst)mmxreg */
14612 case 0xEF: /* PXOR (src)mmxreg-or-mem, (dst)mmxreg */
14613
14614 case 0xF1: /* PSLLgg (src)mmxreg-or-mem, (dst)mmxreg */
14615 case 0xF2:
14616 case 0xF3:
14617
14618 case 0xD1: /* PSRLgg (src)mmxreg-or-mem, (dst)mmxreg */
14619 case 0xD2:
14620 case 0xD3:
14621
14622 case 0xE1: /* PSRAgg (src)mmxreg-or-mem, (dst)mmxreg */
14623 case 0xE2:
14624 {
sewardj270def42005-07-03 01:03:01 +000014625 Long delta0 = delta-1;
sewardj8711f662005-05-09 17:52:56 +000014626 Bool decode_OK = False;
14627
14628 /* If sz==2 this is SSE, and we assume sse idec has
14629 already spotted those cases by now. */
sewardj3d8107c2005-05-09 22:23:38 +000014630 if (sz != 4 && sz != 8)
sewardj8711f662005-05-09 17:52:56 +000014631 goto decode_failure;
14632 if (have66orF2orF3(pfx))
14633 goto decode_failure;
14634
14635 delta = dis_MMX ( &decode_OK, pfx, sz, delta-1 );
14636 if (!decode_OK) {
14637 delta = delta0;
14638 goto decode_failure;
14639 }
14640 break;
14641 }
14642
sewardjae84d782006-04-13 22:06:35 +000014643 case 0x0E: /* FEMMS */
sewardj8711f662005-05-09 17:52:56 +000014644 case 0x77: /* EMMS */
14645 if (sz != 4)
14646 goto decode_failure;
14647 do_EMMS_preamble();
sewardjae84d782006-04-13 22:06:35 +000014648 DIP("{f}emms\n");
sewardj8711f662005-05-09 17:52:56 +000014649 break;
sewardj3ca55a12005-01-27 16:06:23 +000014650
14651 /* =-=-=-=-=-=-=-=-=- unimp2 =-=-=-=-=-=-=-=-=-=-= */
14652
14653 default:
14654 goto decode_failure;
14655 } /* switch (opc) for the 2-byte opcodes */
14656 goto decode_success;
14657 } /* case 0x0F: of primary opcode */
sewardjdf0e0022005-01-25 15:48:43 +000014658
14659 /* ------------------------ ??? ------------------------ */
14660
14661 default:
14662 decode_failure:
14663 /* All decode failures end up here. */
14664 vex_printf("vex amd64->IR: unhandled instruction bytes: "
14665 "0x%x 0x%x 0x%x 0x%x\n",
sewardj8c332e22005-01-28 01:36:56 +000014666 (Int)getUChar(delta_start+0),
14667 (Int)getUChar(delta_start+1),
14668 (Int)getUChar(delta_start+2),
14669 (Int)getUChar(delta_start+3) );
sewardjdf0e0022005-01-25 15:48:43 +000014670
14671 /* Tell the dispatcher that this insn cannot be decoded, and so has
14672 not been executed, and (is currently) the next to be executed.
14673 RIP should be up-to-date since it made so at the start of each
14674 insn, but nevertheless be paranoid and update it again right
14675 now. */
sewardj9e6491a2005-07-02 19:24:10 +000014676 stmt( IRStmt_Put( OFFB_RIP, mkU64(guest_RIP_curr_instr) ) );
sewardjc4356f02007-11-09 21:15:04 +000014677 if (unlock_bus_after_insn)
14678 stmt( IRStmt_MBE(Imbe_BusUnlock) );
sewardj9e6491a2005-07-02 19:24:10 +000014679 jmp_lit(Ijk_NoDecode, guest_RIP_curr_instr);
14680 dres.whatNext = Dis_StopHere;
14681 dres.len = 0;
14682 return dres;
sewardjdf0e0022005-01-25 15:48:43 +000014683
14684 } /* switch (opc) for the main (primary) opcode switch. */
14685
14686 decode_success:
14687 /* All decode successes end up here. */
14688 DIP("\n");
sewardjc4356f02007-11-09 21:15:04 +000014689 if (unlock_bus_after_insn)
14690 stmt( IRStmt_MBE(Imbe_BusUnlock) );
sewardj9e6491a2005-07-02 19:24:10 +000014691 dres.len = (Int)toUInt(delta - delta_start);
14692 return dres;
sewardjdf0e0022005-01-25 15:48:43 +000014693}
14694
14695#undef DIP
14696#undef DIS
sewardjd20c8852005-01-20 20:04:07 +000014697
sewardj9e6491a2005-07-02 19:24:10 +000014698
14699/*------------------------------------------------------------*/
14700/*--- Top-level fn ---*/
14701/*------------------------------------------------------------*/
14702
14703/* Disassemble a single instruction into IR. The instruction
14704 is located in host memory at &guest_code[delta]. */
14705
sewardjdd40fdf2006-12-24 02:20:24 +000014706DisResult disInstr_AMD64 ( IRSB* irsb_IN,
sewardj9e6491a2005-07-02 19:24:10 +000014707 Bool put_IP,
sewardjc716aea2006-01-17 01:48:46 +000014708 Bool (*resteerOkFn) ( void*, Addr64 ),
14709 void* callback_opaque,
sewardj9e6491a2005-07-02 19:24:10 +000014710 UChar* guest_code_IN,
14711 Long delta,
14712 Addr64 guest_IP,
sewardja5f55da2006-04-30 23:37:32 +000014713 VexArch guest_arch,
sewardj9e6491a2005-07-02 19:24:10 +000014714 VexArchInfo* archinfo,
sewardjdd40fdf2006-12-24 02:20:24 +000014715 VexAbiInfo* abiinfo,
sewardj9e6491a2005-07-02 19:24:10 +000014716 Bool host_bigendian_IN )
14717{
14718 DisResult dres;
14719
14720 /* Set globals (see top of this file) */
sewardja5f55da2006-04-30 23:37:32 +000014721 vassert(guest_arch == VexArchAMD64);
sewardj9e6491a2005-07-02 19:24:10 +000014722 guest_code = guest_code_IN;
sewardjdd40fdf2006-12-24 02:20:24 +000014723 irsb = irsb_IN;
sewardj9e6491a2005-07-02 19:24:10 +000014724 host_is_bigendian = host_bigendian_IN;
14725 guest_RIP_curr_instr = guest_IP;
14726 guest_RIP_bbstart = guest_IP - delta;
14727
14728 /* We'll consult these after doing disInstr_AMD64_WRK. */
14729 guest_RIP_next_assumed = 0;
14730 guest_RIP_next_mustcheck = False;
14731
sewardjc716aea2006-01-17 01:48:46 +000014732 dres = disInstr_AMD64_WRK ( put_IP, resteerOkFn, callback_opaque,
sewardjdd40fdf2006-12-24 02:20:24 +000014733 delta, archinfo, abiinfo );
sewardj9e6491a2005-07-02 19:24:10 +000014734
14735 /* If disInstr_AMD64_WRK tried to figure out the next rip, check it
14736 got it right. Failure of this assertion is serious and denotes
14737 a bug in disInstr. */
14738 if (guest_RIP_next_mustcheck
14739 && guest_RIP_next_assumed != guest_RIP_curr_instr + dres.len) {
14740 vex_printf("\n");
14741 vex_printf("assumed next %%rip = 0x%llx\n",
14742 guest_RIP_next_assumed );
14743 vex_printf(" actual next %%rip = 0x%llx\n",
14744 guest_RIP_curr_instr + dres.len );
14745 vpanic("bbToIR_AMD64: disInstr miscalculated next %rip");
14746 }
14747
14748 return dres;
14749}
14750
14751
14752
sewardjd20c8852005-01-20 20:04:07 +000014753/*--------------------------------------------------------------------*/
14754/*--- end guest-amd64/toIR.c ---*/
14755/*--------------------------------------------------------------------*/