blob: 74fc124f2d4b554c57629a69549e667c09713973 [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
sewardja33e9a42006-06-05 23:13:19 +000013 Copyright (C) 2004-2006 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
sewardj9e6491a2005-07-02 19:24:10 +0000187/* The IRBB* into which we're generating code. */
188static IRBB* irbb;
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));
sewardjb3a04292005-01-21 20:33:44 +0000214 return newIRTemp( irbb->tyenv, ty );
215}
216
sewardjecb94892005-01-21 14:26:37 +0000217/* Add a statement to the list held by "irbb". */
218static void stmt ( IRStmt* st )
219{
220 addStmtToIRBB( irbb, st );
221}
sewardjb3a04292005-01-21 20:33:44 +0000222
223/* Generate a statement "dst := e". */
224static void assign ( IRTemp dst, IRExpr* e )
225{
226 stmt( IRStmt_Tmp(dst, e) );
227}
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{
246 return IRExpr_Tmp(tmp);
247}
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
sewardj270def42005-07-03 01:03:01 +0000517//.. static UInt getUDisp16 ( Long delta )
sewardjd20c8852005-01-20 20:04:07 +0000518//.. {
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
sewardj1389d4d2005-01-28 13:46:29 +0000736/* Clear all the segment-override bits in a prefix. */
737static Prefix clearSegBits ( Prefix p )
738{
sewardj1001dc42005-02-21 08:25:55 +0000739 return
740 p & ~(PFX_CS | PFX_DS | PFX_ES | PFX_FS | PFX_GS | PFX_SS);
741}
742
sewardj1389d4d2005-01-28 13:46:29 +0000743
sewardjecb94892005-01-21 14:26:37 +0000744/*------------------------------------------------------------*/
sewardj5b470602005-02-27 13:10:48 +0000745/*--- For dealing with integer registers ---*/
sewardjecb94892005-01-21 14:26:37 +0000746/*------------------------------------------------------------*/
747
sewardj5b470602005-02-27 13:10:48 +0000748/* This is somewhat complex. The rules are:
749
750 For 64, 32 and 16 bit register references, the e or g fields in the
751 modrm bytes supply the low 3 bits of the register number. The
752 fourth (most-significant) bit of the register number is supplied by
753 the REX byte, if it is present; else that bit is taken to be zero.
754
755 The REX.R bit supplies the high bit corresponding to the g register
756 field, and the REX.B bit supplies the high bit corresponding to the
757 e register field (when the mod part of modrm indicates that modrm's
758 e component refers to a register and not to memory).
759
760 The REX.X bit supplies a high register bit for certain registers
761 in SIB address modes, and is generally rarely used.
762
763 For 8 bit register references, the presence of the REX byte itself
764 has significance. If there is no REX present, then the 3-bit
765 number extracted from the modrm e or g field is treated as an index
766 into the sequence %al %cl %dl %bl %ah %ch %dh %bh -- that is, the
767 old x86 encoding scheme.
768
769 But if there is a REX present, the register reference is
770 interpreted in the same way as for 64/32/16-bit references: a high
771 bit is extracted from REX, giving a 4-bit number, and the denoted
772 register is the lowest 8 bits of the 16 integer registers denoted
773 by the number. In particular, values 3 through 7 of this sequence
774 do not refer to %ah %ch %dh %bh but instead to the lowest 8 bits of
775 %rsp %rbp %rsi %rdi.
776
777 The REX.W bit has no bearing at all on register numbers. Instead
778 its presence indicates that the operand size is to be overridden
779 from its default value (32 bits) to 64 bits instead. This is in
780 the same fashion that an 0x66 prefix indicates the operand size is
781 to be overridden from 32 bits down to 16 bits. When both REX.W and
782 0x66 are present there is a conflict, and REX.W takes precedence.
783
784 Rather than try to handle this complexity using a single huge
785 function, several smaller ones are provided. The aim is to make it
786 as difficult as possible to screw up register decoding in a subtle
787 and hard-to-track-down way.
788
789 Because these routines fish around in the host's memory (that is,
790 in the guest state area) for sub-parts of guest registers, their
791 correctness depends on the host's endianness. So far these
792 routines only work for little-endian hosts. Those for which
793 endianness is important have assertions to ensure sanity.
794*/
sewardjecb94892005-01-21 14:26:37 +0000795
796
sewardj5b470602005-02-27 13:10:48 +0000797/* About the simplest question you can ask: where do the 64-bit
798 integer registers live (in the guest state) ? */
sewardjecb94892005-01-21 14:26:37 +0000799
sewardj3ca55a12005-01-27 16:06:23 +0000800static Int integerGuestReg64Offset ( UInt reg )
sewardjb3a04292005-01-21 20:33:44 +0000801{
802 switch (reg) {
803 case R_RAX: return OFFB_RAX;
804 case R_RCX: return OFFB_RCX;
805 case R_RDX: return OFFB_RDX;
806 case R_RBX: return OFFB_RBX;
807 case R_RSP: return OFFB_RSP;
808 case R_RBP: return OFFB_RBP;
809 case R_RSI: return OFFB_RSI;
810 case R_RDI: return OFFB_RDI;
811 case R_R8: return OFFB_R8;
812 case R_R9: return OFFB_R9;
813 case R_R10: return OFFB_R10;
814 case R_R11: return OFFB_R11;
815 case R_R12: return OFFB_R12;
816 case R_R13: return OFFB_R13;
817 case R_R14: return OFFB_R14;
818 case R_R15: return OFFB_R15;
819 default: vpanic("integerGuestReg64Offset(amd64)");
820 }
821}
822
823
sewardj5b470602005-02-27 13:10:48 +0000824/* Produce the name of an integer register, for printing purposes.
825 reg is a number in the range 0 .. 15 that has been generated from a
826 3-bit reg-field number and a REX extension bit. irregular denotes
827 the case where sz==1 and no REX byte is present. */
sewardjecb94892005-01-21 14:26:37 +0000828
829static
sewardj5b470602005-02-27 13:10:48 +0000830HChar* nameIReg ( Int sz, UInt reg, Bool irregular )
sewardjecb94892005-01-21 14:26:37 +0000831{
sewardjecb94892005-01-21 14:26:37 +0000832 static HChar* ireg64_names[16]
833 = { "%rax", "%rcx", "%rdx", "%rbx", "%rsp", "%rbp", "%rsi", "%rdi",
834 "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15" };
835 static HChar* ireg32_names[16]
836 = { "%eax", "%ecx", "%edx", "%ebx", "%esp", "%ebp", "%esi", "%edi",
837 "%r8d", "%r9d", "%r10d","%r11d","%r12d","%r13d","%r14d","%r15d" };
838 static HChar* ireg16_names[16]
839 = { "%ax", "%cx", "%dx", "%bx", "%sp", "%bp", "%si", "%di",
840 "%r8w", "%r9w", "%r10w","%r11w","%r12w","%r13w","%r14w","%r15w" };
841 static HChar* ireg8_names[16]
842 = { "%al", "%cl", "%dl", "%bl", "%spl", "%bpl", "%sil", "%dil",
843 "%r8b", "%r9b", "%r10b","%r11b","%r12b","%r13b","%r14b","%r15b" };
sewardj5b470602005-02-27 13:10:48 +0000844 static HChar* ireg8_irregular[8]
sewardjecb94892005-01-21 14:26:37 +0000845 = { "%al", "%cl", "%dl", "%bl", "%ah", "%ch", "%dh", "%bh" };
846
sewardj5b470602005-02-27 13:10:48 +0000847 vassert(reg < 16);
848 if (sz == 1) {
849 if (irregular)
850 vassert(reg < 8);
851 } else {
852 vassert(irregular == False);
853 }
sewardjecb94892005-01-21 14:26:37 +0000854
855 switch (sz) {
sewardj5b470602005-02-27 13:10:48 +0000856 case 8: return ireg64_names[reg];
857 case 4: return ireg32_names[reg];
858 case 2: return ireg16_names[reg];
859 case 1: if (irregular) {
860 return ireg8_irregular[reg];
861 } else {
862 return ireg8_names[reg];
863 }
864 default: vpanic("nameIReg(amd64)");
sewardjecb94892005-01-21 14:26:37 +0000865 }
sewardjecb94892005-01-21 14:26:37 +0000866}
867
sewardj5b470602005-02-27 13:10:48 +0000868/* Using the same argument conventions as nameIReg, produce the
869 guest state offset of an integer register. */
sewardjb3a04292005-01-21 20:33:44 +0000870
sewardjecb94892005-01-21 14:26:37 +0000871static
sewardj5b470602005-02-27 13:10:48 +0000872Int offsetIReg ( Int sz, UInt reg, Bool irregular )
sewardjecb94892005-01-21 14:26:37 +0000873{
sewardj5b470602005-02-27 13:10:48 +0000874 vassert(reg < 16);
875 if (sz == 1) {
876 if (irregular)
877 vassert(reg < 8);
878 } else {
879 vassert(irregular == False);
sewardjecb94892005-01-21 14:26:37 +0000880 }
sewardj5b470602005-02-27 13:10:48 +0000881
882 /* Deal with irregular case -- sz==1 and no REX present */
883 if (sz == 1 && irregular) {
884 switch (reg) {
885 case R_RSP: return 1+ OFFB_RAX;
886 case R_RBP: return 1+ OFFB_RCX;
887 case R_RSI: return 1+ OFFB_RDX;
888 case R_RDI: return 1+ OFFB_RBX;
889 default: break; /* use the normal case */
890 }
sewardjecb94892005-01-21 14:26:37 +0000891 }
sewardj5b470602005-02-27 13:10:48 +0000892
893 /* Normal case */
894 return integerGuestReg64Offset(reg);
sewardjecb94892005-01-21 14:26:37 +0000895}
896
897
sewardj5b470602005-02-27 13:10:48 +0000898/* Read the %CL register :: Ity_I8, for shift/rotate operations. */
899
900static IRExpr* getIRegCL ( void )
901{
902 vassert(!host_is_bigendian);
903 return IRExpr_Get( OFFB_RCX, Ity_I8 );
904}
905
906
907/* Write to the %AH register. */
908
909static void putIRegAH ( IRExpr* e )
910{
911 vassert(!host_is_bigendian);
912 vassert(typeOfIRExpr(irbb->tyenv, e) == Ity_I8);
913 stmt( IRStmt_Put( OFFB_RAX+1, e ) );
914}
915
916
917/* Read/write various widths of %RAX, as it has various
918 special-purpose uses. */
919
920static HChar* nameIRegRAX ( Int sz )
921{
922 switch (sz) {
923 case 1: return "%al";
924 case 2: return "%ax";
925 case 4: return "%eax";
926 case 8: return "%rax";
927 default: vpanic("nameIRegRAX(amd64)");
928 }
929}
930
931static IRExpr* getIRegRAX ( Int sz )
932{
933 vassert(!host_is_bigendian);
934 switch (sz) {
935 case 1: return IRExpr_Get( OFFB_RAX, Ity_I8 );
936 case 2: return IRExpr_Get( OFFB_RAX, Ity_I16 );
937 case 4: return IRExpr_Get( OFFB_RAX, Ity_I32 );
938 case 8: return IRExpr_Get( OFFB_RAX, Ity_I64 );
939 default: vpanic("getIRegRAX(amd64)");
940 }
941}
942
943static void putIRegRAX ( Int sz, IRExpr* e )
944{
945 IRType ty = typeOfIRExpr(irbb->tyenv, e);
946 vassert(!host_is_bigendian);
947 switch (sz) {
948 case 8: vassert(ty == Ity_I64);
949 stmt( IRStmt_Put( OFFB_RAX, e ));
950 break;
951 case 4: vassert(ty == Ity_I32);
952 stmt( IRStmt_Put( OFFB_RAX, unop(Iop_32Uto64,e) ));
953 break;
954 case 2: vassert(ty == Ity_I16);
955 stmt( IRStmt_Put( OFFB_RAX, e ));
956 break;
957 case 1: vassert(ty == Ity_I8);
958 stmt( IRStmt_Put( OFFB_RAX, e ));
959 break;
960 default: vpanic("putIRegRAX(amd64)");
961 }
962}
963
964
965/* Read/write various widths of %RDX, as it has various
966 special-purpose uses. */
967
968static IRExpr* getIRegRDX ( Int sz )
969{
970 vassert(!host_is_bigendian);
971 switch (sz) {
972 case 1: return IRExpr_Get( OFFB_RDX, Ity_I8 );
973 case 2: return IRExpr_Get( OFFB_RDX, Ity_I16 );
974 case 4: return IRExpr_Get( OFFB_RDX, Ity_I32 );
975 case 8: return IRExpr_Get( OFFB_RDX, Ity_I64 );
976 default: vpanic("getIRegRDX(amd64)");
977 }
978}
979
980static void putIRegRDX ( Int sz, IRExpr* e )
981{
982 vassert(!host_is_bigendian);
983 vassert(typeOfIRExpr(irbb->tyenv, e) == szToITy(sz));
984 switch (sz) {
985 case 8: stmt( IRStmt_Put( OFFB_RDX, e ));
986 break;
987 case 4: stmt( IRStmt_Put( OFFB_RDX, unop(Iop_32Uto64,e) ));
988 break;
989 case 2: stmt( IRStmt_Put( OFFB_RDX, e ));
990 break;
991 case 1: stmt( IRStmt_Put( OFFB_RDX, e ));
992 break;
993 default: vpanic("putIRegRDX(amd64)");
994 }
995}
996
997
998/* Simplistic functions to deal with the integer registers as a
999 straightforward bank of 16 64-bit regs. */
sewardjb3a04292005-01-21 20:33:44 +00001000
1001static IRExpr* getIReg64 ( UInt regno )
1002{
1003 return IRExpr_Get( integerGuestReg64Offset(regno),
1004 Ity_I64 );
1005}
1006
sewardj2f959cc2005-01-26 01:19:35 +00001007static void putIReg64 ( UInt regno, IRExpr* e )
1008{
1009 vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_I64);
1010 stmt( IRStmt_Put( integerGuestReg64Offset(regno), e ) );
1011}
1012
sewardjb3a04292005-01-21 20:33:44 +00001013static HChar* nameIReg64 ( UInt regno )
1014{
sewardj5b470602005-02-27 13:10:48 +00001015 return nameIReg( 8, regno, False );
sewardjb3a04292005-01-21 20:33:44 +00001016}
sewardj5b470602005-02-27 13:10:48 +00001017
1018
1019/* Simplistic functions to deal with the lower halves of integer
1020 registers as a straightforward bank of 16 32-bit regs. */
1021
1022static IRExpr* getIReg32 ( UInt regno )
1023{
1024 vassert(!host_is_bigendian);
1025 return IRExpr_Get( integerGuestReg64Offset(regno),
1026 Ity_I32 );
1027}
1028
1029static void putIReg32 ( UInt regno, IRExpr* e )
1030{
1031 vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_I32);
1032 stmt( IRStmt_Put( integerGuestReg64Offset(regno),
1033 unop(Iop_32Uto64,e) ) );
1034}
1035
1036static HChar* nameIReg32 ( UInt regno )
1037{
1038 return nameIReg( 4, regno, False );
1039}
1040
1041
sewardja7ba8c42005-05-10 20:08:34 +00001042/* Simplistic functions to deal with the lower quarters of integer
1043 registers as a straightforward bank of 16 16-bit regs. */
1044
1045static IRExpr* getIReg16 ( UInt regno )
1046{
1047 vassert(!host_is_bigendian);
1048 return IRExpr_Get( integerGuestReg64Offset(regno),
1049 Ity_I16 );
1050}
1051
1052static HChar* nameIReg16 ( UInt regno )
1053{
1054 return nameIReg( 2, regno, False );
1055}
1056
1057
sewardj5b470602005-02-27 13:10:48 +00001058/* Sometimes what we know is a 3-bit register number, a REX byte, and
1059 which field of the REX byte is to be used to extend to a 4-bit
1060 number. These functions cater for that situation.
1061*/
1062static IRExpr* getIReg64rexX ( Prefix pfx, UInt lo3bits )
1063{
1064 vassert(lo3bits < 8);
1065 vassert(IS_VALID_PFX(pfx));
1066 return getIReg64( lo3bits | (getRexX(pfx) << 3) );
1067}
1068
1069static HChar* nameIReg64rexX ( Prefix pfx, UInt lo3bits )
1070{
1071 vassert(lo3bits < 8);
1072 vassert(IS_VALID_PFX(pfx));
1073 return nameIReg( 8, lo3bits | (getRexX(pfx) << 3), False );
1074}
1075
1076static HChar* nameIRegRexB ( Int sz, Prefix pfx, UInt lo3bits )
1077{
1078 vassert(lo3bits < 8);
1079 vassert(IS_VALID_PFX(pfx));
1080 vassert(sz == 8 || sz == 4 || sz == 2 || sz == 1);
1081 return nameIReg( sz, lo3bits | (getRexB(pfx) << 3),
sewardj397f88b2005-02-27 13:39:25 +00001082 toBool(sz==1 && !haveREX(pfx)) );
sewardj5b470602005-02-27 13:10:48 +00001083}
1084
1085static IRExpr* getIRegRexB ( Int sz, Prefix pfx, UInt lo3bits )
1086{
1087 vassert(lo3bits < 8);
1088 vassert(IS_VALID_PFX(pfx));
1089 vassert(sz == 8 || sz == 4 || sz == 2 || sz == 1);
1090 return IRExpr_Get(
1091 offsetIReg( sz, lo3bits | (getRexB(pfx) << 3),
sewardj397f88b2005-02-27 13:39:25 +00001092 toBool(sz==1 && !haveREX(pfx)) ),
sewardj5b470602005-02-27 13:10:48 +00001093 szToITy(sz)
1094 );
1095}
1096
1097static void putIRegRexB ( Int sz, Prefix pfx, UInt lo3bits, IRExpr* e )
1098{
1099 vassert(lo3bits < 8);
1100 vassert(IS_VALID_PFX(pfx));
sewardj98e9f342005-07-23 12:07:37 +00001101 vassert(sz == 8 || sz == 4 || sz == 2 || sz == 1);
sewardj5b470602005-02-27 13:10:48 +00001102 vassert(typeOfIRExpr(irbb->tyenv, e) == szToITy(sz));
1103 stmt( IRStmt_Put(
1104 offsetIReg( sz, lo3bits | (getRexB(pfx) << 3),
sewardj397f88b2005-02-27 13:39:25 +00001105 toBool(sz==1 && !haveREX(pfx)) ),
sewardj5b470602005-02-27 13:10:48 +00001106 sz==4 ? unop(Iop_32Uto64,e) : e
1107 ));
1108}
1109
1110
1111/* Functions for getting register numbers from modrm bytes and REX
1112 when we don't have to consider the complexities of integer subreg
1113 accesses.
1114*/
1115/* Extract the g reg field from a modRM byte, and augment it using the
1116 REX.R bit from the supplied REX byte. The R bit usually is
1117 associated with the g register field.
1118*/
1119static UInt gregOfRexRM ( Prefix pfx, UChar mod_reg_rm )
1120{
1121 Int reg = (Int)( (mod_reg_rm >> 3) & 7 );
1122 reg += (pfx & PFX_REXR) ? 8 : 0;
1123 return reg;
1124}
1125
1126/* Extract the e reg field from a modRM byte, and augment it using the
1127 REX.B bit from the supplied REX byte. The B bit usually is
1128 associated with the e register field (when modrm indicates e is a
1129 register, that is).
1130*/
1131static UInt eregOfRexRM ( Prefix pfx, UChar mod_reg_rm )
1132{
1133 Int rm;
1134 vassert(epartIsReg(mod_reg_rm));
1135 rm = (Int)(mod_reg_rm & 0x7);
1136 rm += (pfx & PFX_REXB) ? 8 : 0;
1137 return rm;
1138}
1139
1140
1141/* General functions for dealing with integer register access. */
1142
1143/* Produce the guest state offset for a reference to the 'g' register
1144 field in a modrm byte, taking into account REX (or its absence),
1145 and the size of the access.
1146*/
1147static UInt offsetIRegG ( Int sz, Prefix pfx, UChar mod_reg_rm )
1148{
1149 UInt reg;
1150 vassert(!host_is_bigendian);
1151 vassert(IS_VALID_PFX(pfx));
1152 vassert(sz == 8 || sz == 4 || sz == 2 || sz == 1);
1153 reg = gregOfRexRM( pfx, mod_reg_rm );
sewardj397f88b2005-02-27 13:39:25 +00001154 return offsetIReg( sz, reg, toBool(sz == 1 && !haveREX(pfx)) );
sewardj5b470602005-02-27 13:10:48 +00001155}
1156
1157static
1158IRExpr* getIRegG ( Int sz, Prefix pfx, UChar mod_reg_rm )
1159{
1160 return IRExpr_Get( offsetIRegG( sz, pfx, mod_reg_rm ),
1161 szToITy(sz) );
1162}
1163
1164static
1165void putIRegG ( Int sz, Prefix pfx, UChar mod_reg_rm, IRExpr* e )
1166{
1167 vassert(typeOfIRExpr(irbb->tyenv,e) == szToITy(sz));
1168 if (sz == 4) {
1169 e = unop(Iop_32Uto64,e);
1170 }
1171 stmt( IRStmt_Put( offsetIRegG( sz, pfx, mod_reg_rm ), e ) );
1172}
1173
1174static
1175HChar* nameIRegG ( Int sz, Prefix pfx, UChar mod_reg_rm )
1176{
1177 return nameIReg( sz, gregOfRexRM(pfx,mod_reg_rm),
sewardj397f88b2005-02-27 13:39:25 +00001178 toBool(sz==1 && !haveREX(pfx)) );
sewardj5b470602005-02-27 13:10:48 +00001179}
1180
1181
1182/* Produce the guest state offset for a reference to the 'e' register
1183 field in a modrm byte, taking into account REX (or its absence),
1184 and the size of the access. eregOfRexRM will assert if mod_reg_rm
1185 denotes a memory access rather than a register access.
1186*/
1187static UInt offsetIRegE ( Int sz, Prefix pfx, UChar mod_reg_rm )
1188{
1189 UInt reg;
1190 vassert(!host_is_bigendian);
1191 vassert(IS_VALID_PFX(pfx));
1192 vassert(sz == 8 || sz == 4 || sz == 2 || sz == 1);
1193 reg = eregOfRexRM( pfx, mod_reg_rm );
sewardj397f88b2005-02-27 13:39:25 +00001194 return offsetIReg( sz, reg, toBool(sz == 1 && !haveREX(pfx)) );
sewardj5b470602005-02-27 13:10:48 +00001195}
1196
1197static
1198IRExpr* getIRegE ( Int sz, Prefix pfx, UChar mod_reg_rm )
1199{
1200 return IRExpr_Get( offsetIRegE( sz, pfx, mod_reg_rm ),
1201 szToITy(sz) );
1202}
1203
1204static
1205void putIRegE ( Int sz, Prefix pfx, UChar mod_reg_rm, IRExpr* e )
1206{
1207 vassert(typeOfIRExpr(irbb->tyenv,e) == szToITy(sz));
1208 if (sz == 4) {
1209 e = unop(Iop_32Uto64,e);
1210 }
1211 stmt( IRStmt_Put( offsetIRegE( sz, pfx, mod_reg_rm ), e ) );
1212}
1213
1214static
1215HChar* nameIRegE ( Int sz, Prefix pfx, UChar mod_reg_rm )
1216{
1217 return nameIReg( sz, eregOfRexRM(pfx,mod_reg_rm),
sewardj397f88b2005-02-27 13:39:25 +00001218 toBool(sz==1 && !haveREX(pfx)) );
sewardj5b470602005-02-27 13:10:48 +00001219}
1220
1221
1222/*------------------------------------------------------------*/
1223/*--- For dealing with XMM registers ---*/
1224/*------------------------------------------------------------*/
sewardjecb94892005-01-21 14:26:37 +00001225
sewardjd20c8852005-01-20 20:04:07 +00001226//.. static Int segmentGuestRegOffset ( UInt sreg )
1227//.. {
1228//.. switch (sreg) {
1229//.. case R_ES: return OFFB_ES;
1230//.. case R_CS: return OFFB_CS;
1231//.. case R_SS: return OFFB_SS;
1232//.. case R_DS: return OFFB_DS;
1233//.. case R_FS: return OFFB_FS;
1234//.. case R_GS: return OFFB_GS;
1235//.. default: vpanic("segmentGuestRegOffset(x86)");
1236//.. }
1237//.. }
sewardj1001dc42005-02-21 08:25:55 +00001238
1239static Int xmmGuestRegOffset ( UInt xmmreg )
1240{
1241 switch (xmmreg) {
1242 case 0: return OFFB_XMM0;
1243 case 1: return OFFB_XMM1;
1244 case 2: return OFFB_XMM2;
1245 case 3: return OFFB_XMM3;
1246 case 4: return OFFB_XMM4;
1247 case 5: return OFFB_XMM5;
1248 case 6: return OFFB_XMM6;
1249 case 7: return OFFB_XMM7;
1250 case 8: return OFFB_XMM8;
1251 case 9: return OFFB_XMM9;
1252 case 10: return OFFB_XMM10;
1253 case 11: return OFFB_XMM11;
1254 case 12: return OFFB_XMM12;
1255 case 13: return OFFB_XMM13;
1256 case 14: return OFFB_XMM14;
1257 case 15: return OFFB_XMM15;
1258 default: vpanic("xmmGuestRegOffset(amd64)");
1259 }
1260}
1261
sewardj97628592005-05-10 22:42:54 +00001262/* Lanes of vector registers are always numbered from zero being the
1263 least significant lane (rightmost in the register). */
1264
1265static Int xmmGuestRegLane16offset ( UInt xmmreg, Int laneno )
1266{
1267 /* Correct for little-endian host only. */
1268 vassert(!host_is_bigendian);
1269 vassert(laneno >= 0 && laneno < 8);
1270 return xmmGuestRegOffset( xmmreg ) + 2 * laneno;
1271}
sewardj8d965312005-02-25 02:48:47 +00001272
1273static Int xmmGuestRegLane32offset ( UInt xmmreg, Int laneno )
1274{
1275 /* Correct for little-endian host only. */
1276 vassert(!host_is_bigendian);
1277 vassert(laneno >= 0 && laneno < 4);
1278 return xmmGuestRegOffset( xmmreg ) + 4 * laneno;
1279}
sewardj1001dc42005-02-21 08:25:55 +00001280
1281static Int xmmGuestRegLane64offset ( UInt xmmreg, Int laneno )
1282{
1283 /* Correct for little-endian host only. */
1284 vassert(!host_is_bigendian);
1285 vassert(laneno >= 0 && laneno < 2);
1286 return xmmGuestRegOffset( xmmreg ) + 8 * laneno;
1287}
1288
sewardjd20c8852005-01-20 20:04:07 +00001289//.. static IRExpr* getSReg ( UInt sreg )
1290//.. {
1291//.. return IRExpr_Get( segmentGuestRegOffset(sreg), Ity_I16 );
1292//.. }
1293//..
1294//.. static void putSReg ( UInt sreg, IRExpr* e )
1295//.. {
1296//.. vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_I16);
1297//.. stmt( IRStmt_Put( segmentGuestRegOffset(sreg), e ) );
1298//.. }
sewardj1001dc42005-02-21 08:25:55 +00001299
1300static IRExpr* getXMMReg ( UInt xmmreg )
1301{
1302 return IRExpr_Get( xmmGuestRegOffset(xmmreg), Ity_V128 );
1303}
1304
1305static IRExpr* getXMMRegLane64 ( UInt xmmreg, Int laneno )
1306{
1307 return IRExpr_Get( xmmGuestRegLane64offset(xmmreg,laneno), Ity_I64 );
1308}
1309
sewardj18303862005-02-21 12:36:54 +00001310static IRExpr* getXMMRegLane64F ( UInt xmmreg, Int laneno )
1311{
1312 return IRExpr_Get( xmmGuestRegLane64offset(xmmreg,laneno), Ity_F64 );
1313}
1314
sewardj8d965312005-02-25 02:48:47 +00001315static IRExpr* getXMMRegLane32 ( UInt xmmreg, Int laneno )
1316{
1317 return IRExpr_Get( xmmGuestRegLane32offset(xmmreg,laneno), Ity_I32 );
1318}
1319
sewardjc49ce232005-02-25 13:03:03 +00001320static IRExpr* getXMMRegLane32F ( UInt xmmreg, Int laneno )
1321{
1322 return IRExpr_Get( xmmGuestRegLane32offset(xmmreg,laneno), Ity_F32 );
1323}
sewardj1001dc42005-02-21 08:25:55 +00001324
1325static void putXMMReg ( UInt xmmreg, IRExpr* e )
1326{
1327 vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_V128);
1328 stmt( IRStmt_Put( xmmGuestRegOffset(xmmreg), e ) );
1329}
1330
1331static void putXMMRegLane64 ( UInt xmmreg, Int laneno, IRExpr* e )
1332{
1333 vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_I64);
1334 stmt( IRStmt_Put( xmmGuestRegLane64offset(xmmreg,laneno), e ) );
1335}
1336
sewardj1a01e652005-02-23 11:39:21 +00001337static void putXMMRegLane64F ( UInt xmmreg, Int laneno, IRExpr* e )
1338{
1339 vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_F64);
1340 stmt( IRStmt_Put( xmmGuestRegLane64offset(xmmreg,laneno), e ) );
1341}
1342
sewardj8d965312005-02-25 02:48:47 +00001343static void putXMMRegLane32F ( UInt xmmreg, Int laneno, IRExpr* e )
1344{
1345 vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_F32);
1346 stmt( IRStmt_Put( xmmGuestRegLane32offset(xmmreg,laneno), e ) );
1347}
1348
1349static void putXMMRegLane32 ( UInt xmmreg, Int laneno, IRExpr* e )
1350{
1351 vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_I32);
1352 stmt( IRStmt_Put( xmmGuestRegLane32offset(xmmreg,laneno), e ) );
1353}
1354
sewardj97628592005-05-10 22:42:54 +00001355static void putXMMRegLane16 ( UInt xmmreg, Int laneno, IRExpr* e )
1356{
1357 vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_I16);
1358 stmt( IRStmt_Put( xmmGuestRegLane16offset(xmmreg,laneno), e ) );
1359}
sewardj3ca55a12005-01-27 16:06:23 +00001360
sewardj1001dc42005-02-21 08:25:55 +00001361static IRExpr* mkV128 ( UShort mask )
1362{
1363 return IRExpr_Const(IRConst_V128(mask));
1364}
sewardjdf0e0022005-01-25 15:48:43 +00001365
sewardje8f65252005-08-23 23:44:35 +00001366static IRExpr* mkAnd1 ( IRExpr* x, IRExpr* y )
1367{
1368 vassert(typeOfIRExpr(irbb->tyenv,x) == Ity_I1);
1369 vassert(typeOfIRExpr(irbb->tyenv,y) == Ity_I1);
1370 return unop(Iop_64to1,
1371 binop(Iop_And64,
1372 unop(Iop_1Uto64,x),
1373 unop(Iop_1Uto64,y)));
1374}
1375
sewardj5b470602005-02-27 13:10:48 +00001376
sewardj118b23e2005-01-29 02:14:44 +00001377/*------------------------------------------------------------*/
sewardje8f65252005-08-23 23:44:35 +00001378/*--- Helpers for %rflags. ---*/
sewardj118b23e2005-01-29 02:14:44 +00001379/*------------------------------------------------------------*/
1380
1381/* -------------- Evaluating the flags-thunk. -------------- */
1382
1383/* Build IR to calculate all the eflags from stored
1384 CC_OP/CC_DEP1/CC_DEP2/CC_NDEP. Returns an expression ::
1385 Ity_I64. */
1386static IRExpr* mk_amd64g_calculate_rflags_all ( void )
1387{
1388 IRExpr** args
1389 = mkIRExprVec_4( IRExpr_Get(OFFB_CC_OP, Ity_I64),
1390 IRExpr_Get(OFFB_CC_DEP1, Ity_I64),
1391 IRExpr_Get(OFFB_CC_DEP2, Ity_I64),
1392 IRExpr_Get(OFFB_CC_NDEP, Ity_I64) );
1393 IRExpr* call
1394 = mkIRExprCCall(
1395 Ity_I64,
1396 0/*regparm*/,
1397 "amd64g_calculate_rflags_all", &amd64g_calculate_rflags_all,
1398 args
1399 );
1400 /* Exclude OP and NDEP from definedness checking. We're only
1401 interested in DEP1 and DEP2. */
1402 call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<3);
1403 return call;
1404}
sewardj3ca55a12005-01-27 16:06:23 +00001405
1406/* Build IR to calculate some particular condition from stored
1407 CC_OP/CC_DEP1/CC_DEP2/CC_NDEP. Returns an expression ::
1408 Ity_Bit. */
1409static IRExpr* mk_amd64g_calculate_condition ( AMD64Condcode cond )
1410{
1411 IRExpr** args
1412 = mkIRExprVec_5( mkU64(cond),
1413 IRExpr_Get(OFFB_CC_OP, Ity_I64),
1414 IRExpr_Get(OFFB_CC_DEP1, Ity_I64),
1415 IRExpr_Get(OFFB_CC_DEP2, Ity_I64),
1416 IRExpr_Get(OFFB_CC_NDEP, Ity_I64) );
1417 IRExpr* call
1418 = mkIRExprCCall(
1419 Ity_I64,
1420 0/*regparm*/,
1421 "amd64g_calculate_condition", &amd64g_calculate_condition,
1422 args
1423 );
1424 /* Exclude the requested condition, OP and NDEP from definedness
1425 checking. We're only interested in DEP1 and DEP2. */
1426 call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<1) | (1<<4);
sewardje58967e2005-04-27 11:50:56 +00001427 return unop(Iop_64to1, call);
sewardj3ca55a12005-01-27 16:06:23 +00001428}
sewardjdf0e0022005-01-25 15:48:43 +00001429
1430/* Build IR to calculate just the carry flag from stored
1431 CC_OP/CC_DEP1/CC_DEP2/CC_NDEP. Returns an expression :: Ity_I64. */
1432static IRExpr* mk_amd64g_calculate_rflags_c ( void )
1433{
1434 IRExpr** args
1435 = mkIRExprVec_4( IRExpr_Get(OFFB_CC_OP, Ity_I64),
1436 IRExpr_Get(OFFB_CC_DEP1, Ity_I64),
1437 IRExpr_Get(OFFB_CC_DEP2, Ity_I64),
1438 IRExpr_Get(OFFB_CC_NDEP, Ity_I64) );
1439 IRExpr* call
1440 = mkIRExprCCall(
1441 Ity_I64,
1442 0/*regparm*/,
1443 "amd64g_calculate_rflags_c", &amd64g_calculate_rflags_c,
1444 args
1445 );
1446 /* Exclude OP and NDEP from definedness checking. We're only
1447 interested in DEP1 and DEP2. */
1448 call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<3);
1449 return call;
1450}
1451
1452
1453/* -------------- Building the flags-thunk. -------------- */
1454
1455/* The machinery in this section builds the flag-thunk following a
1456 flag-setting operation. Hence the various setFlags_* functions.
1457*/
1458
1459static Bool isAddSub ( IROp op8 )
1460{
sewardj7a240552005-01-28 21:37:12 +00001461 return toBool(op8 == Iop_Add8 || op8 == Iop_Sub8);
sewardjdf0e0022005-01-25 15:48:43 +00001462}
1463
sewardj3ca55a12005-01-27 16:06:23 +00001464static Bool isLogic ( IROp op8 )
1465{
sewardj7a240552005-01-28 21:37:12 +00001466 return toBool(op8 == Iop_And8 || op8 == Iop_Or8 || op8 == Iop_Xor8);
sewardj3ca55a12005-01-27 16:06:23 +00001467}
sewardjdf0e0022005-01-25 15:48:43 +00001468
1469/* U-widen 8/16/32/64 bit int expr to 64. */
1470static IRExpr* widenUto64 ( IRExpr* e )
1471{
1472 switch (typeOfIRExpr(irbb->tyenv,e)) {
1473 case Ity_I64: return e;
1474 case Ity_I32: return unop(Iop_32Uto64, e);
sewardje58967e2005-04-27 11:50:56 +00001475 case Ity_I16: return unop(Iop_16Uto64, e);
1476 case Ity_I8: return unop(Iop_8Uto64, e);
sewardj118b23e2005-01-29 02:14:44 +00001477 default: vpanic("widenUto64");
sewardjdf0e0022005-01-25 15:48:43 +00001478 }
1479}
1480
sewardj118b23e2005-01-29 02:14:44 +00001481/* S-widen 8/16/32/64 bit int expr to 32. */
1482static IRExpr* widenSto64 ( IRExpr* e )
1483{
1484 switch (typeOfIRExpr(irbb->tyenv,e)) {
1485 case Ity_I64: return e;
1486 case Ity_I32: return unop(Iop_32Sto64, e);
sewardje58967e2005-04-27 11:50:56 +00001487 case Ity_I16: return unop(Iop_16Sto64, e);
1488 case Ity_I8: return unop(Iop_8Sto64, e);
sewardj118b23e2005-01-29 02:14:44 +00001489 default: vpanic("widenSto64");
1490 }
1491}
sewardjdf0e0022005-01-25 15:48:43 +00001492
1493/* Narrow 8/16/32/64 bit int expr to 8/16/32/64. Clearly only some
1494 of these combinations make sense. */
1495static IRExpr* narrowTo ( IRType dst_ty, IRExpr* e )
1496{
1497 IRType src_ty = typeOfIRExpr(irbb->tyenv,e);
1498 if (src_ty == dst_ty)
1499 return e;
1500 if (src_ty == Ity_I32 && dst_ty == Ity_I16)
1501 return unop(Iop_32to16, e);
1502 if (src_ty == Ity_I32 && dst_ty == Ity_I8)
1503 return unop(Iop_32to8, e);
sewardj118b23e2005-01-29 02:14:44 +00001504 if (src_ty == Ity_I64 && dst_ty == Ity_I32)
1505 return unop(Iop_64to32, e);
1506 if (src_ty == Ity_I64 && dst_ty == Ity_I16)
sewardje58967e2005-04-27 11:50:56 +00001507 return unop(Iop_64to16, e);
sewardj03b07cc2005-01-31 18:09:43 +00001508 if (src_ty == Ity_I64 && dst_ty == Ity_I8)
sewardje58967e2005-04-27 11:50:56 +00001509 return unop(Iop_64to8, e);
sewardjdf0e0022005-01-25 15:48:43 +00001510
1511 vex_printf("\nsrc, dst tys are: ");
1512 ppIRType(src_ty);
1513 vex_printf(", ");
1514 ppIRType(dst_ty);
1515 vex_printf("\n");
1516 vpanic("narrowTo(amd64)");
1517}
1518
1519
1520/* Set the flags thunk OP, DEP1 and DEP2 fields. The supplied op is
1521 auto-sized up to the real op. */
1522
1523static
1524void setFlags_DEP1_DEP2 ( IROp op8, IRTemp dep1, IRTemp dep2, IRType ty )
1525{
1526 Int ccOp = 0;
1527 switch (ty) {
1528 case Ity_I8: ccOp = 0; break;
1529 case Ity_I16: ccOp = 1; break;
1530 case Ity_I32: ccOp = 2; break;
1531 case Ity_I64: ccOp = 3; break;
1532 default: vassert(0);
1533 }
1534 switch (op8) {
1535 case Iop_Add8: ccOp += AMD64G_CC_OP_ADDB; break;
1536 case Iop_Sub8: ccOp += AMD64G_CC_OP_SUBB; break;
1537 default: ppIROp(op8);
1538 vpanic("setFlags_DEP1_DEP2(amd64)");
1539 }
1540 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(ccOp)) );
1541 stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto64(mkexpr(dep1))) );
1542 stmt( IRStmt_Put( OFFB_CC_DEP2, widenUto64(mkexpr(dep2))) );
1543}
1544
1545
1546/* Set the OP and DEP1 fields only, and write zero to DEP2. */
1547
1548static
1549void setFlags_DEP1 ( IROp op8, IRTemp dep1, IRType ty )
1550{
1551 Int ccOp = 0;
1552 switch (ty) {
1553 case Ity_I8: ccOp = 0; break;
1554 case Ity_I16: ccOp = 1; break;
1555 case Ity_I32: ccOp = 2; break;
1556 case Ity_I64: ccOp = 3; break;
1557 default: vassert(0);
1558 }
1559 switch (op8) {
1560 case Iop_Or8:
1561 case Iop_And8:
1562 case Iop_Xor8: ccOp += AMD64G_CC_OP_LOGICB; break;
1563 default: ppIROp(op8);
1564 vpanic("setFlags_DEP1(amd64)");
1565 }
1566 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(ccOp)) );
1567 stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto64(mkexpr(dep1))) );
1568 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0)) );
1569}
1570
1571
sewardj118b23e2005-01-29 02:14:44 +00001572/* For shift operations, we put in the result and the undershifted
1573 result. Except if the shift amount is zero, the thunk is left
1574 unchanged. */
1575
1576static void setFlags_DEP1_DEP2_shift ( IROp op64,
1577 IRTemp res,
1578 IRTemp resUS,
1579 IRType ty,
1580 IRTemp guard )
1581{
1582 Int ccOp = 0;
1583 switch (ty) {
1584 case Ity_I8: ccOp = 0; break;
1585 case Ity_I16: ccOp = 1; break;
1586 case Ity_I32: ccOp = 2; break;
1587 case Ity_I64: ccOp = 3; break;
1588 default: vassert(0);
1589 }
1590
1591 vassert(guard);
1592
1593 /* Both kinds of right shifts are handled by the same thunk
1594 operation. */
1595 switch (op64) {
1596 case Iop_Shr64:
1597 case Iop_Sar64: ccOp += AMD64G_CC_OP_SHRB; break;
1598 case Iop_Shl64: ccOp += AMD64G_CC_OP_SHLB; break;
1599 default: ppIROp(op64);
1600 vpanic("setFlags_DEP1_DEP2_shift(amd64)");
1601 }
1602
1603 /* DEP1 contains the result, DEP2 contains the undershifted value. */
1604 stmt( IRStmt_Put( OFFB_CC_OP,
1605 IRExpr_Mux0X( mkexpr(guard),
1606 IRExpr_Get(OFFB_CC_OP,Ity_I64),
1607 mkU64(ccOp))) );
1608 stmt( IRStmt_Put( OFFB_CC_DEP1,
1609 IRExpr_Mux0X( mkexpr(guard),
1610 IRExpr_Get(OFFB_CC_DEP1,Ity_I64),
1611 widenUto64(mkexpr(res)))) );
1612 stmt( IRStmt_Put( OFFB_CC_DEP2,
1613 IRExpr_Mux0X( mkexpr(guard),
1614 IRExpr_Get(OFFB_CC_DEP2,Ity_I64),
1615 widenUto64(mkexpr(resUS)))) );
1616}
sewardj354e5c62005-01-27 20:12:52 +00001617
1618
1619/* For the inc/dec case, we store in DEP1 the result value and in NDEP
1620 the former value of the carry flag, which unfortunately we have to
1621 compute. */
1622
1623static void setFlags_INC_DEC ( Bool inc, IRTemp res, IRType ty )
1624{
1625 Int ccOp = inc ? AMD64G_CC_OP_INCB : AMD64G_CC_OP_DECB;
1626
1627 switch (ty) {
1628 case Ity_I8: ccOp += 0; break;
1629 case Ity_I16: ccOp += 1; break;
1630 case Ity_I32: ccOp += 2; break;
1631 case Ity_I64: ccOp += 3; break;
1632 default: vassert(0);
1633 }
1634
1635 /* This has to come first, because calculating the C flag
1636 may require reading all four thunk fields. */
1637 stmt( IRStmt_Put( OFFB_CC_NDEP, mk_amd64g_calculate_rflags_c()) );
1638 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(ccOp)) );
1639 stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(res)) );
1640 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0)) );
1641}
1642
1643
sewardj32b2bbe2005-01-28 00:50:10 +00001644/* Multiplies are pretty much like add and sub: DEP1 and DEP2 hold the
1645 two arguments. */
1646
1647static
1648void setFlags_MUL ( IRType ty, IRTemp arg1, IRTemp arg2, ULong base_op )
1649{
1650 switch (ty) {
1651 case Ity_I8:
1652 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(base_op+0) ) );
1653 break;
1654 case Ity_I16:
1655 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(base_op+1) ) );
1656 break;
1657 case Ity_I32:
1658 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(base_op+2) ) );
1659 break;
1660 case Ity_I64:
1661 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(base_op+3) ) );
1662 break;
1663 default:
1664 vpanic("setFlags_MUL(amd64)");
1665 }
1666 stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto64(mkexpr(arg1)) ));
1667 stmt( IRStmt_Put( OFFB_CC_DEP2, widenUto64(mkexpr(arg2)) ));
1668}
sewardj3ca55a12005-01-27 16:06:23 +00001669
1670
1671/* -------------- Condition codes. -------------- */
1672
1673/* Condition codes, using the AMD encoding. */
1674
sewardj8c332e22005-01-28 01:36:56 +00001675static HChar* name_AMD64Condcode ( AMD64Condcode cond )
sewardj3ca55a12005-01-27 16:06:23 +00001676{
1677 switch (cond) {
1678 case AMD64CondO: return "o";
1679 case AMD64CondNO: return "no";
1680 case AMD64CondB: return "b";
sewardje941eea2005-01-30 19:52:28 +00001681 case AMD64CondNB: return "ae"; /*"nb";*/
1682 case AMD64CondZ: return "e"; /*"z";*/
1683 case AMD64CondNZ: return "ne"; /*"nz";*/
sewardj3ca55a12005-01-27 16:06:23 +00001684 case AMD64CondBE: return "be";
sewardje941eea2005-01-30 19:52:28 +00001685 case AMD64CondNBE: return "a"; /*"nbe";*/
sewardj3ca55a12005-01-27 16:06:23 +00001686 case AMD64CondS: return "s";
1687 case AMD64CondNS: return "ns";
1688 case AMD64CondP: return "p";
1689 case AMD64CondNP: return "np";
1690 case AMD64CondL: return "l";
sewardje941eea2005-01-30 19:52:28 +00001691 case AMD64CondNL: return "ge"; /*"nl";*/
sewardj3ca55a12005-01-27 16:06:23 +00001692 case AMD64CondLE: return "le";
sewardje941eea2005-01-30 19:52:28 +00001693 case AMD64CondNLE: return "g"; /*"nle";*/
sewardj3ca55a12005-01-27 16:06:23 +00001694 case AMD64CondAlways: return "ALWAYS";
1695 default: vpanic("name_AMD64Condcode");
1696 }
1697}
1698
sewardj1389d4d2005-01-28 13:46:29 +00001699static
1700AMD64Condcode positiveIse_AMD64Condcode ( AMD64Condcode cond,
1701 /*OUT*/Bool* needInvert )
1702{
1703 vassert(cond >= AMD64CondO && cond <= AMD64CondNLE);
1704 if (cond & 1) {
1705 *needInvert = True;
1706 return cond-1;
1707 } else {
1708 *needInvert = False;
1709 return cond;
1710 }
1711}
sewardjdf0e0022005-01-25 15:48:43 +00001712
1713
1714/* -------------- Helpers for ADD/SUB with carry. -------------- */
1715
1716/* Given ta1, ta2 and tres, compute tres = ADC(ta1,ta2) and set flags
1717 appropriately.
1718*/
1719static void helper_ADC ( Int sz,
1720 IRTemp tres, IRTemp ta1, IRTemp ta2 )
1721{
1722 UInt thunkOp;
1723 IRType ty = szToITy(sz);
1724 IRTemp oldc = newTemp(Ity_I64);
1725 IRTemp oldcn = newTemp(ty);
1726 IROp plus = mkSizedOp(ty, Iop_Add8);
1727 IROp xor = mkSizedOp(ty, Iop_Xor8);
1728
1729 switch (sz) {
1730 case 8: thunkOp = AMD64G_CC_OP_ADCQ; break;
1731 case 4: thunkOp = AMD64G_CC_OP_ADCL; break;
1732 case 2: thunkOp = AMD64G_CC_OP_ADCW; break;
1733 case 1: thunkOp = AMD64G_CC_OP_ADCB; break;
1734 default: vassert(0);
1735 }
1736
1737 /* oldc = old carry flag, 0 or 1 */
1738 assign( oldc, binop(Iop_And64,
1739 mk_amd64g_calculate_rflags_c(),
1740 mkU64(1)) );
1741
1742 assign( oldcn, narrowTo(ty, mkexpr(oldc)) );
1743
1744 assign( tres, binop(plus,
1745 binop(plus,mkexpr(ta1),mkexpr(ta2)),
1746 mkexpr(oldcn)) );
1747
1748 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(thunkOp) ) );
sewardj820611e2005-08-24 10:56:01 +00001749 stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto64(mkexpr(ta1)) ));
1750 stmt( IRStmt_Put( OFFB_CC_DEP2, widenUto64(binop(xor, mkexpr(ta2),
1751 mkexpr(oldcn)) )) );
sewardjdf0e0022005-01-25 15:48:43 +00001752 stmt( IRStmt_Put( OFFB_CC_NDEP, mkexpr(oldc) ) );
1753}
1754
1755
1756/* Given ta1, ta2 and tres, compute tres = SBB(ta1,ta2) and set flags
1757 appropriately.
1758*/
1759static void helper_SBB ( Int sz,
1760 IRTemp tres, IRTemp ta1, IRTemp ta2 )
1761{
1762 UInt thunkOp;
1763 IRType ty = szToITy(sz);
1764 IRTemp oldc = newTemp(Ity_I64);
1765 IRTemp oldcn = newTemp(ty);
1766 IROp minus = mkSizedOp(ty, Iop_Sub8);
1767 IROp xor = mkSizedOp(ty, Iop_Xor8);
1768
1769 switch (sz) {
1770 case 8: thunkOp = AMD64G_CC_OP_SBBQ; break;
1771 case 4: thunkOp = AMD64G_CC_OP_SBBL; break;
1772 case 2: thunkOp = AMD64G_CC_OP_SBBW; break;
1773 case 1: thunkOp = AMD64G_CC_OP_SBBB; break;
1774 default: vassert(0);
1775 }
1776
1777 /* oldc = old carry flag, 0 or 1 */
1778 assign( oldc, binop(Iop_And64,
1779 mk_amd64g_calculate_rflags_c(),
1780 mkU64(1)) );
1781
1782 assign( oldcn, narrowTo(ty, mkexpr(oldc)) );
1783
1784 assign( tres, binop(minus,
1785 binop(minus,mkexpr(ta1),mkexpr(ta2)),
1786 mkexpr(oldcn)) );
1787
1788 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(thunkOp) ) );
sewardj820611e2005-08-24 10:56:01 +00001789 stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto64(mkexpr(ta1) )) );
1790 stmt( IRStmt_Put( OFFB_CC_DEP2, widenUto64(binop(xor, mkexpr(ta2),
1791 mkexpr(oldcn)) )) );
sewardjdf0e0022005-01-25 15:48:43 +00001792 stmt( IRStmt_Put( OFFB_CC_NDEP, mkexpr(oldc) ) );
1793}
1794
1795
sewardj3ca55a12005-01-27 16:06:23 +00001796/* -------------- Helpers for disassembly printing. -------------- */
1797
1798static HChar* nameGrp1 ( Int opc_aux )
1799{
1800 static HChar* grp1_names[8]
1801 = { "add", "or", "adc", "sbb", "and", "sub", "xor", "cmp" };
1802 if (opc_aux < 0 || opc_aux > 7) vpanic("nameGrp1(amd64)");
1803 return grp1_names[opc_aux];
1804}
1805
sewardj118b23e2005-01-29 02:14:44 +00001806static HChar* nameGrp2 ( Int opc_aux )
1807{
1808 static HChar* grp2_names[8]
1809 = { "rol", "ror", "rcl", "rcr", "shl", "shr", "shl", "sar" };
sewardje941eea2005-01-30 19:52:28 +00001810 if (opc_aux < 0 || opc_aux > 7) vpanic("nameGrp2(amd64)");
sewardj118b23e2005-01-29 02:14:44 +00001811 return grp2_names[opc_aux];
1812}
1813
sewardj03b07cc2005-01-31 18:09:43 +00001814static HChar* nameGrp4 ( Int opc_aux )
1815{
1816 static HChar* grp4_names[8]
1817 = { "inc", "dec", "???", "???", "???", "???", "???", "???" };
1818 if (opc_aux < 0 || opc_aux > 1) vpanic("nameGrp4(amd64)");
1819 return grp4_names[opc_aux];
1820}
sewardj354e5c62005-01-27 20:12:52 +00001821
1822static HChar* nameGrp5 ( Int opc_aux )
1823{
1824 static HChar* grp5_names[8]
1825 = { "inc", "dec", "call*", "call*", "jmp*", "jmp*", "push", "???" };
1826 if (opc_aux < 0 || opc_aux > 6) vpanic("nameGrp5(amd64)");
1827 return grp5_names[opc_aux];
1828}
1829
sewardj1d511802005-03-27 17:59:45 +00001830static HChar* nameGrp8 ( Int opc_aux )
1831{
1832 static HChar* grp8_names[8]
1833 = { "???", "???", "???", "???", "bt", "bts", "btr", "btc" };
1834 if (opc_aux < 4 || opc_aux > 7) vpanic("nameGrp8(amd64)");
1835 return grp8_names[opc_aux];
1836}
1837
sewardjd20c8852005-01-20 20:04:07 +00001838//.. static HChar* nameSReg ( UInt sreg )
1839//.. {
1840//.. switch (sreg) {
1841//.. case R_ES: return "%es";
1842//.. case R_CS: return "%cs";
1843//.. case R_SS: return "%ss";
1844//.. case R_DS: return "%ds";
1845//.. case R_FS: return "%fs";
1846//.. case R_GS: return "%gs";
1847//.. default: vpanic("nameSReg(x86)");
1848//.. }
1849//.. }
sewardj8711f662005-05-09 17:52:56 +00001850
1851static HChar* nameMMXReg ( Int mmxreg )
1852{
1853 static HChar* mmx_names[8]
1854 = { "%mm0", "%mm1", "%mm2", "%mm3", "%mm4", "%mm5", "%mm6", "%mm7" };
1855 if (mmxreg < 0 || mmxreg > 7) vpanic("nameMMXReg(amd64,guest)");
1856 return mmx_names[mmxreg];
1857}
sewardj1001dc42005-02-21 08:25:55 +00001858
1859static HChar* nameXMMReg ( Int xmmreg )
1860{
1861 static HChar* xmm_names[16]
1862 = { "%xmm0", "%xmm1", "%xmm2", "%xmm3",
1863 "%xmm4", "%xmm5", "%xmm6", "%xmm7",
1864 "%xmm8", "%xmm9", "%xmm10", "%xmm11",
1865 "%xmm12", "%xmm13", "%xmm14", "%xmm15" };
1866 if (xmmreg < 0 || xmmreg > 15) vpanic("nameXMMReg(amd64)");
1867 return xmm_names[xmmreg];
1868}
1869
sewardjca673ab2005-05-11 10:03:08 +00001870static HChar* nameMMXGran ( Int gran )
sewardj8711f662005-05-09 17:52:56 +00001871{
1872 switch (gran) {
1873 case 0: return "b";
1874 case 1: return "w";
1875 case 2: return "d";
1876 case 3: return "q";
1877 default: vpanic("nameMMXGran(amd64,guest)");
1878 }
1879}
sewardjdf0e0022005-01-25 15:48:43 +00001880
sewardj8c332e22005-01-28 01:36:56 +00001881static HChar nameISize ( Int size )
sewardjdf0e0022005-01-25 15:48:43 +00001882{
1883 switch (size) {
1884 case 8: return 'q';
1885 case 4: return 'l';
1886 case 2: return 'w';
1887 case 1: return 'b';
1888 default: vpanic("nameISize(amd64)");
1889 }
1890}
1891
1892
1893/*------------------------------------------------------------*/
1894/*--- JMP helpers ---*/
1895/*------------------------------------------------------------*/
1896
1897static void jmp_lit( IRJumpKind kind, Addr64 d64 )
1898{
1899 irbb->next = mkU64(d64);
1900 irbb->jumpkind = kind;
1901}
1902
sewardj2f959cc2005-01-26 01:19:35 +00001903static void jmp_treg( IRJumpKind kind, IRTemp t )
1904{
sewardj3ca55a12005-01-27 16:06:23 +00001905 irbb->next = mkexpr(t);
sewardj2f959cc2005-01-26 01:19:35 +00001906 irbb->jumpkind = kind;
1907}
1908
sewardj1389d4d2005-01-28 13:46:29 +00001909static
1910void jcc_01 ( AMD64Condcode cond, Addr64 d64_false, Addr64 d64_true )
1911{
1912 Bool invert;
1913 AMD64Condcode condPos;
1914 condPos = positiveIse_AMD64Condcode ( cond, &invert );
1915 if (invert) {
1916 stmt( IRStmt_Exit( mk_amd64g_calculate_condition(condPos),
1917 Ijk_Boring,
1918 IRConst_U64(d64_false) ) );
1919 irbb->next = mkU64(d64_true);
1920 irbb->jumpkind = Ijk_Boring;
1921 } else {
1922 stmt( IRStmt_Exit( mk_amd64g_calculate_condition(condPos),
1923 Ijk_Boring,
1924 IRConst_U64(d64_true) ) );
1925 irbb->next = mkU64(d64_false);
1926 irbb->jumpkind = Ijk_Boring;
1927 }
1928}
sewardjb3a04292005-01-21 20:33:44 +00001929
sewardj5a9ffab2005-05-12 17:55:01 +00001930/* Let new_rsp be the %rsp value after a call/return. This function
1931 generates an AbiHint to say that -128(%rsp) .. -1(%rsp) should now
1932 be regarded as uninitialised.
1933*/
1934static void make_redzone_AbiHint ( IRTemp new_rsp, HChar* who )
1935{
1936 if (0) vex_printf("AbiHint: %s\n", who);
1937 vassert(typeOfIRTemp(irbb->tyenv, new_rsp) == Ity_I64);
1938 stmt( IRStmt_AbiHint(
1939 binop(Iop_Sub64, mkexpr(new_rsp), mkU64(128)),
1940 128
1941 ));
1942}
1943
sewardjb3a04292005-01-21 20:33:44 +00001944
1945/*------------------------------------------------------------*/
1946/*--- Disassembling addressing modes ---*/
1947/*------------------------------------------------------------*/
1948
1949static
sewardj8c332e22005-01-28 01:36:56 +00001950HChar* sorbTxt ( Prefix pfx )
sewardjb3a04292005-01-21 20:33:44 +00001951{
1952 if (pfx & PFX_CS) return "%cs:";
1953 if (pfx & PFX_DS) return "%ds:";
1954 if (pfx & PFX_ES) return "%es:";
1955 if (pfx & PFX_FS) return "%fs:";
1956 if (pfx & PFX_GS) return "%gs:";
1957 if (pfx & PFX_SS) return "%ss:";
1958 return ""; /* no override */
1959}
1960
1961
1962/* 'virtual' is an IRExpr* holding a virtual address. Convert it to a
1963 linear address by adding any required segment override as indicated
sewardj42561ef2005-11-04 14:18:31 +00001964 by sorb, and also dealing with any address size override
1965 present. */
sewardjb3a04292005-01-21 20:33:44 +00001966static
sewardj42561ef2005-11-04 14:18:31 +00001967IRExpr* handleAddrOverrides ( Prefix pfx, IRExpr* virtual )
sewardjb3a04292005-01-21 20:33:44 +00001968{
sewardj42561ef2005-11-04 14:18:31 +00001969 /* --- segment overrides --- */
1970
sewardja6b93d12005-02-17 09:28:28 +00001971 if (pfx & PFX_FS) {
1972 /* Note that this is a linux-kernel specific hack that relies
1973 on the assumption that %fs is always zero. */
1974 /* return virtual + guest_FS_ZERO. */
sewardj42561ef2005-11-04 14:18:31 +00001975 virtual = binop(Iop_Add64, virtual, IRExpr_Get(OFFB_FS_ZERO, Ity_I64));
sewardja6b93d12005-02-17 09:28:28 +00001976 }
sewardjb3a04292005-01-21 20:33:44 +00001977
sewardja6b93d12005-02-17 09:28:28 +00001978 if (pfx & PFX_GS) {
1979 unimplemented("amd64 %gs segment override");
1980 }
1981
1982 /* cs, ds, es and ss are simply ignored in 64-bit mode. */
sewardj42561ef2005-11-04 14:18:31 +00001983
1984 /* --- address size override --- */
1985 if (haveASO(pfx))
1986 virtual = unop(Iop_32Uto64, unop(Iop_64to32, virtual));
1987
sewardja6b93d12005-02-17 09:28:28 +00001988 return virtual;
sewardjb3a04292005-01-21 20:33:44 +00001989}
sewardja6b93d12005-02-17 09:28:28 +00001990
sewardjd20c8852005-01-20 20:04:07 +00001991//.. {
1992//.. Int sreg;
1993//.. IRType hWordTy;
1994//.. IRTemp ldt_ptr, gdt_ptr, seg_selector, r64;
1995//..
1996//.. if (sorb == 0)
1997//.. /* the common case - no override */
1998//.. return virtual;
1999//..
2000//.. switch (sorb) {
2001//.. case 0x3E: sreg = R_DS; break;
2002//.. case 0x26: sreg = R_ES; break;
2003//.. case 0x64: sreg = R_FS; break;
2004//.. case 0x65: sreg = R_GS; break;
sewardj42561ef2005-11-04 14:18:31 +00002005//.. default: vpanic("handleAddrOverrides(x86,guest)");
sewardjd20c8852005-01-20 20:04:07 +00002006//.. }
2007//..
2008//.. hWordTy = sizeof(HWord)==4 ? Ity_I32 : Ity_I64;
2009//..
2010//.. seg_selector = newTemp(Ity_I32);
2011//.. ldt_ptr = newTemp(hWordTy);
2012//.. gdt_ptr = newTemp(hWordTy);
2013//.. r64 = newTemp(Ity_I64);
2014//..
2015//.. assign( seg_selector, unop(Iop_16Uto32, getSReg(sreg)) );
2016//.. assign( ldt_ptr, IRExpr_Get( OFFB_LDT, hWordTy ));
2017//.. assign( gdt_ptr, IRExpr_Get( OFFB_GDT, hWordTy ));
2018//..
2019//.. /*
2020//.. Call this to do the translation and limit checks:
2021//.. ULong x86g_use_seg_selector ( HWord ldt, HWord gdt,
2022//.. UInt seg_selector, UInt virtual_addr )
2023//.. */
2024//.. assign(
2025//.. r64,
2026//.. mkIRExprCCall(
2027//.. Ity_I64,
2028//.. 0/*regparms*/,
2029//.. "x86g_use_seg_selector",
2030//.. &x86g_use_seg_selector,
2031//.. mkIRExprVec_4( mkexpr(ldt_ptr), mkexpr(gdt_ptr),
2032//.. mkexpr(seg_selector), virtual)
2033//.. )
2034//.. );
2035//..
2036//.. /* If the high 32 of the result are non-zero, there was a
2037//.. failure in address translation. In which case, make a
2038//.. quick exit.
2039//.. */
2040//.. stmt(
2041//.. IRStmt_Exit(
2042//.. binop(Iop_CmpNE32, unop(Iop_64HIto32, mkexpr(r64)), mkU32(0)),
2043//.. Ijk_MapFail,
2044//.. IRConst_U32( guest_eip_curr_instr )
2045//.. )
2046//.. );
2047//..
2048//.. /* otherwise, here's the translated result. */
2049//.. return unop(Iop_64to32, mkexpr(r64));
2050//.. }
sewardjb3a04292005-01-21 20:33:44 +00002051
2052
2053/* Generate IR to calculate an address indicated by a ModRM and
2054 following SIB bytes. The expression, and the number of bytes in
2055 the address mode, are returned (the latter in *len). Note that
2056 this fn should not be called if the R/M part of the address denotes
2057 a register instead of memory. If print_codegen is true, text of
2058 the addressing mode is placed in buf.
2059
2060 The computed address is stored in a new tempreg, and the
sewardje1698952005-02-08 15:02:39 +00002061 identity of the tempreg is returned.
2062
2063 extra_bytes holds the number of bytes after the amode, as supplied
2064 by the caller. This is needed to make sense of %rip-relative
2065 addresses. Note that the value that *len is set to is only the
2066 length of the amode itself and does not include the value supplied
sewardj09717342005-05-05 21:34:02 +00002067 in extra_bytes.
sewardje1698952005-02-08 15:02:39 +00002068 */
sewardjb3a04292005-01-21 20:33:44 +00002069
2070static IRTemp disAMode_copy2tmp ( IRExpr* addr64 )
2071{
2072 IRTemp tmp = newTemp(Ity_I64);
2073 assign( tmp, addr64 );
2074 return tmp;
2075}
2076
2077static
sewardj270def42005-07-03 01:03:01 +00002078IRTemp disAMode ( Int* len, Prefix pfx, Long delta,
sewardje1698952005-02-08 15:02:39 +00002079 HChar* buf, Int extra_bytes )
sewardjb3a04292005-01-21 20:33:44 +00002080{
sewardj8c332e22005-01-28 01:36:56 +00002081 UChar mod_reg_rm = getUChar(delta);
sewardjb3a04292005-01-21 20:33:44 +00002082 delta++;
2083
2084 buf[0] = (UChar)0;
sewardje1698952005-02-08 15:02:39 +00002085 vassert(extra_bytes >= 0 && extra_bytes < 10);
sewardjb3a04292005-01-21 20:33:44 +00002086
2087 /* squeeze out the reg field from mod_reg_rm, since a 256-entry
2088 jump table seems a bit excessive.
2089 */
sewardj7a240552005-01-28 21:37:12 +00002090 mod_reg_rm &= 0xC7; /* is now XX000YYY */
sewardj1027dc22005-02-26 01:55:02 +00002091 mod_reg_rm = toUChar(mod_reg_rm | (mod_reg_rm >> 3));
2092 /* is now XX0XXYYY */
sewardj7a240552005-01-28 21:37:12 +00002093 mod_reg_rm &= 0x1F; /* is now 000XXYYY */
sewardjb3a04292005-01-21 20:33:44 +00002094 switch (mod_reg_rm) {
2095
2096 /* REX.B==0: (%rax) .. (%rdi), not including (%rsp) or (%rbp).
2097 REX.B==1: (%r8) .. (%r15), not including (%r12) or (%r13).
2098 */
2099 case 0x00: case 0x01: case 0x02: case 0x03:
2100 /* ! 04 */ /* ! 05 */ case 0x06: case 0x07:
sewardj1027dc22005-02-26 01:55:02 +00002101 { UChar rm = toUChar(mod_reg_rm & 7);
sewardj5b470602005-02-27 13:10:48 +00002102 DIS(buf, "%s(%s)", sorbTxt(pfx), nameIRegRexB(8,pfx,rm));
sewardjb3a04292005-01-21 20:33:44 +00002103 *len = 1;
2104 return disAMode_copy2tmp(
sewardj42561ef2005-11-04 14:18:31 +00002105 handleAddrOverrides(pfx, getIRegRexB(8,pfx,rm)));
sewardjb3a04292005-01-21 20:33:44 +00002106 }
2107
2108 /* REX.B==0: d8(%rax) ... d8(%rdi), not including d8(%rsp)
2109 REX.B==1: d8(%r8) ... d8(%r15), not including d8(%r12)
2110 */
2111 case 0x08: case 0x09: case 0x0A: case 0x0B:
2112 /* ! 0C */ case 0x0D: case 0x0E: case 0x0F:
sewardj1027dc22005-02-26 01:55:02 +00002113 { UChar rm = toUChar(mod_reg_rm & 7);
sewardj8c332e22005-01-28 01:36:56 +00002114 Long d = getSDisp8(delta);
sewardj7eaa7cf2005-01-31 18:55:22 +00002115 if (d == 0) {
sewardj5b470602005-02-27 13:10:48 +00002116 DIS(buf, "%s(%s)", sorbTxt(pfx), nameIRegRexB(8,pfx,rm));
sewardj7eaa7cf2005-01-31 18:55:22 +00002117 } else {
sewardj5b470602005-02-27 13:10:48 +00002118 DIS(buf, "%s%lld(%s)", sorbTxt(pfx), d, nameIRegRexB(8,pfx,rm));
sewardj7eaa7cf2005-01-31 18:55:22 +00002119 }
sewardjb3a04292005-01-21 20:33:44 +00002120 *len = 2;
2121 return disAMode_copy2tmp(
sewardj42561ef2005-11-04 14:18:31 +00002122 handleAddrOverrides(pfx,
sewardj5b470602005-02-27 13:10:48 +00002123 binop(Iop_Add64,getIRegRexB(8,pfx,rm),mkU64(d))));
sewardjb3a04292005-01-21 20:33:44 +00002124 }
2125
2126 /* REX.B==0: d32(%rax) ... d32(%rdi), not including d32(%rsp)
2127 REX.B==1: d32(%r8) ... d32(%r15), not including d32(%r12)
2128 */
2129 case 0x10: case 0x11: case 0x12: case 0x13:
2130 /* ! 14 */ case 0x15: case 0x16: case 0x17:
sewardj1027dc22005-02-26 01:55:02 +00002131 { UChar rm = toUChar(mod_reg_rm & 7);
sewardj227458e2005-01-31 19:04:50 +00002132 Long d = getSDisp32(delta);
sewardj5b470602005-02-27 13:10:48 +00002133 DIS(buf, "%s%lld(%s)", sorbTxt(pfx), d, nameIRegRexB(8,pfx,rm));
sewardjb3a04292005-01-21 20:33:44 +00002134 *len = 5;
2135 return disAMode_copy2tmp(
sewardj42561ef2005-11-04 14:18:31 +00002136 handleAddrOverrides(pfx,
sewardj5b470602005-02-27 13:10:48 +00002137 binop(Iop_Add64,getIRegRexB(8,pfx,rm),mkU64(d))));
sewardjb3a04292005-01-21 20:33:44 +00002138 }
2139
2140 /* REX.B==0: a register, %rax .. %rdi. This shouldn't happen. */
2141 /* REX.B==1: a register, %r8 .. %r16. This shouldn't happen. */
2142 case 0x18: case 0x19: case 0x1A: case 0x1B:
2143 case 0x1C: case 0x1D: case 0x1E: case 0x1F:
sewardj354e5c62005-01-27 20:12:52 +00002144 vpanic("disAMode(amd64): not an addr!");
sewardjb3a04292005-01-21 20:33:44 +00002145
sewardj9e6491a2005-07-02 19:24:10 +00002146 /* RIP + disp32. This assumes that guest_RIP_curr_instr is set
sewardjb3a04292005-01-21 20:33:44 +00002147 correctly at the start of handling each instruction. */
2148 case 0x05:
sewardj227458e2005-01-31 19:04:50 +00002149 { Long d = getSDisp32(delta);
sewardjb3a04292005-01-21 20:33:44 +00002150 *len = 5;
sewardj7eaa7cf2005-01-31 18:55:22 +00002151 DIS(buf, "%s%lld(%%rip)", sorbTxt(pfx), d);
sewardj4b744762005-02-07 15:02:25 +00002152 /* We need to know the next instruction's start address.
2153 Try and figure out what it is, record the guess, and ask
2154 the top-level driver logic (bbToIR_AMD64) to check we
2155 guessed right, after the instruction is completely
2156 decoded. */
sewardj9e6491a2005-07-02 19:24:10 +00002157 guest_RIP_next_mustcheck = True;
2158 guest_RIP_next_assumed = guest_RIP_bbstart
sewardje1698952005-02-08 15:02:39 +00002159 + delta+4 + extra_bytes;
sewardjb3a04292005-01-21 20:33:44 +00002160 return disAMode_copy2tmp(
sewardj42561ef2005-11-04 14:18:31 +00002161 handleAddrOverrides(pfx,
sewardj9e6491a2005-07-02 19:24:10 +00002162 binop(Iop_Add64, mkU64(guest_RIP_next_assumed),
sewardjb3a04292005-01-21 20:33:44 +00002163 mkU64(d))));
2164 }
sewardj3ca55a12005-01-27 16:06:23 +00002165
sewardj2f959cc2005-01-26 01:19:35 +00002166 case 0x04: {
2167 /* SIB, with no displacement. Special cases:
sewardj3ca55a12005-01-27 16:06:23 +00002168 -- %rsp cannot act as an index value.
2169 If index_r indicates %rsp, zero is used for the index.
2170 -- when mod is zero and base indicates RBP or R13, base is
2171 instead a 32-bit sign-extended literal.
sewardj2f959cc2005-01-26 01:19:35 +00002172 It's all madness, I tell you. Extract %index, %base and
2173 scale from the SIB byte. The value denoted is then:
sewardj3ca55a12005-01-27 16:06:23 +00002174 | %index == %RSP && (%base == %RBP || %base == %R13)
sewardj2f959cc2005-01-26 01:19:35 +00002175 = d32 following SIB byte
sewardj3ca55a12005-01-27 16:06:23 +00002176 | %index == %RSP && !(%base == %RBP || %base == %R13)
sewardj2f959cc2005-01-26 01:19:35 +00002177 = %base
sewardj3ca55a12005-01-27 16:06:23 +00002178 | %index != %RSP && (%base == %RBP || %base == %R13)
sewardj2f959cc2005-01-26 01:19:35 +00002179 = d32 following SIB byte + (%index << scale)
sewardj3ca55a12005-01-27 16:06:23 +00002180 | %index != %RSP && !(%base == %RBP || %base == %R13)
sewardj2f959cc2005-01-26 01:19:35 +00002181 = %base + (%index << scale)
2182 */
sewardj8c332e22005-01-28 01:36:56 +00002183 UChar sib = getUChar(delta);
sewardj1027dc22005-02-26 01:55:02 +00002184 UChar scale = toUChar((sib >> 6) & 3);
2185 UChar index_r = toUChar((sib >> 3) & 7);
2186 UChar base_r = toUChar(sib & 7);
sewardj3ca55a12005-01-27 16:06:23 +00002187 /* correct since #(R13) == 8 + #(RBP) */
sewardj7a240552005-01-28 21:37:12 +00002188 Bool base_is_BPor13 = toBool(base_r == R_RBP);
2189 Bool index_is_SP = toBool(index_r == R_RSP && 0==getRexX(pfx));
sewardj2f959cc2005-01-26 01:19:35 +00002190 delta++;
sewardjb3a04292005-01-21 20:33:44 +00002191
sewardj3ca55a12005-01-27 16:06:23 +00002192 if ((!index_is_SP) && (!base_is_BPor13)) {
sewardje941eea2005-01-30 19:52:28 +00002193 if (scale == 0) {
2194 DIS(buf, "%s(%s,%s)", sorbTxt(pfx),
sewardj5b470602005-02-27 13:10:48 +00002195 nameIRegRexB(8,pfx,base_r),
2196 nameIReg64rexX(pfx,index_r));
sewardje941eea2005-01-30 19:52:28 +00002197 } else {
2198 DIS(buf, "%s(%s,%s,%d)", sorbTxt(pfx),
sewardj5b470602005-02-27 13:10:48 +00002199 nameIRegRexB(8,pfx,base_r),
2200 nameIReg64rexX(pfx,index_r), 1<<scale);
sewardje941eea2005-01-30 19:52:28 +00002201 }
sewardj2f959cc2005-01-26 01:19:35 +00002202 *len = 2;
sewardj2f959cc2005-01-26 01:19:35 +00002203 return
2204 disAMode_copy2tmp(
sewardj42561ef2005-11-04 14:18:31 +00002205 handleAddrOverrides(pfx,
sewardj3ca55a12005-01-27 16:06:23 +00002206 binop(Iop_Add64,
sewardj5b470602005-02-27 13:10:48 +00002207 getIRegRexB(8,pfx,base_r),
2208 binop(Iop_Shl64, getIReg64rexX(pfx,index_r),
sewardj2f959cc2005-01-26 01:19:35 +00002209 mkU8(scale)))));
2210 }
2211
sewardj3ca55a12005-01-27 16:06:23 +00002212 if ((!index_is_SP) && base_is_BPor13) {
sewardj227458e2005-01-31 19:04:50 +00002213 Long d = getSDisp32(delta);
sewardj7eaa7cf2005-01-31 18:55:22 +00002214 DIS(buf, "%s%lld(,%s,%d)", sorbTxt(pfx), d,
sewardj5b470602005-02-27 13:10:48 +00002215 nameIReg64rexX(pfx,index_r), 1<<scale);
sewardj2f959cc2005-01-26 01:19:35 +00002216 *len = 6;
sewardj2f959cc2005-01-26 01:19:35 +00002217 return
2218 disAMode_copy2tmp(
sewardj42561ef2005-11-04 14:18:31 +00002219 handleAddrOverrides(pfx,
sewardj3ca55a12005-01-27 16:06:23 +00002220 binop(Iop_Add64,
sewardj5b470602005-02-27 13:10:48 +00002221 binop(Iop_Shl64, getIReg64rexX(pfx,index_r),
sewardj3ca55a12005-01-27 16:06:23 +00002222 mkU8(scale)),
2223 mkU64(d))));
sewardj2f959cc2005-01-26 01:19:35 +00002224 }
2225
sewardj3ca55a12005-01-27 16:06:23 +00002226 if (index_is_SP && (!base_is_BPor13)) {
sewardj5b470602005-02-27 13:10:48 +00002227 DIS(buf, "%s(%s)", sorbTxt(pfx), nameIRegRexB(8,pfx,base_r));
sewardj2f959cc2005-01-26 01:19:35 +00002228 *len = 2;
sewardj2f959cc2005-01-26 01:19:35 +00002229 return disAMode_copy2tmp(
sewardj42561ef2005-11-04 14:18:31 +00002230 handleAddrOverrides(pfx, getIRegRexB(8,pfx,base_r)));
sewardj2f959cc2005-01-26 01:19:35 +00002231 }
2232
sewardj3ca55a12005-01-27 16:06:23 +00002233 if (index_is_SP && base_is_BPor13) {
sewardj227458e2005-01-31 19:04:50 +00002234 Long d = getSDisp32(delta);
sewardj7eaa7cf2005-01-31 18:55:22 +00002235 DIS(buf, "%s%lld", sorbTxt(pfx), d);
sewardj2f959cc2005-01-26 01:19:35 +00002236 *len = 6;
sewardj2f959cc2005-01-26 01:19:35 +00002237 return disAMode_copy2tmp(
sewardj42561ef2005-11-04 14:18:31 +00002238 handleAddrOverrides(pfx, mkU64(d)));
sewardj2f959cc2005-01-26 01:19:35 +00002239 }
2240
2241 vassert(0);
2242 }
sewardj3ca55a12005-01-27 16:06:23 +00002243
sewardj2f959cc2005-01-26 01:19:35 +00002244 /* SIB, with 8-bit displacement. Special cases:
2245 -- %esp cannot act as an index value.
2246 If index_r indicates %esp, zero is used for the index.
2247 Denoted value is:
2248 | %index == %ESP
2249 = d8 + %base
2250 | %index != %ESP
2251 = d8 + %base + (%index << scale)
2252 */
2253 case 0x0C: {
sewardj8c332e22005-01-28 01:36:56 +00002254 UChar sib = getUChar(delta);
sewardj1027dc22005-02-26 01:55:02 +00002255 UChar scale = toUChar((sib >> 6) & 3);
2256 UChar index_r = toUChar((sib >> 3) & 7);
2257 UChar base_r = toUChar(sib & 7);
sewardj8c332e22005-01-28 01:36:56 +00002258 Long d = getSDisp8(delta+1);
sewardj2f959cc2005-01-26 01:19:35 +00002259
sewardj3ca55a12005-01-27 16:06:23 +00002260 if (index_r == R_RSP && 0==getRexX(pfx)) {
sewardje941eea2005-01-30 19:52:28 +00002261 DIS(buf, "%s%lld(%s)", sorbTxt(pfx),
sewardj5b470602005-02-27 13:10:48 +00002262 d, nameIRegRexB(8,pfx,base_r));
sewardj2f959cc2005-01-26 01:19:35 +00002263 *len = 3;
sewardj2f959cc2005-01-26 01:19:35 +00002264 return disAMode_copy2tmp(
sewardj42561ef2005-11-04 14:18:31 +00002265 handleAddrOverrides(pfx,
sewardj5b470602005-02-27 13:10:48 +00002266 binop(Iop_Add64, getIRegRexB(8,pfx,base_r), mkU64(d)) ));
sewardj2f959cc2005-01-26 01:19:35 +00002267 } else {
sewardje941eea2005-01-30 19:52:28 +00002268 if (scale == 0) {
2269 DIS(buf, "%s%lld(%s,%s)", sorbTxt(pfx), d,
sewardj5b470602005-02-27 13:10:48 +00002270 nameIRegRexB(8,pfx,base_r),
2271 nameIReg64rexX(pfx,index_r));
sewardje941eea2005-01-30 19:52:28 +00002272 } else {
2273 DIS(buf, "%s%lld(%s,%s,%d)", sorbTxt(pfx), d,
sewardj5b470602005-02-27 13:10:48 +00002274 nameIRegRexB(8,pfx,base_r),
2275 nameIReg64rexX(pfx,index_r), 1<<scale);
sewardje941eea2005-01-30 19:52:28 +00002276 }
sewardj2f959cc2005-01-26 01:19:35 +00002277 *len = 3;
sewardj2f959cc2005-01-26 01:19:35 +00002278 return
2279 disAMode_copy2tmp(
sewardj42561ef2005-11-04 14:18:31 +00002280 handleAddrOverrides(pfx,
sewardj3ca55a12005-01-27 16:06:23 +00002281 binop(Iop_Add64,
2282 binop(Iop_Add64,
sewardj5b470602005-02-27 13:10:48 +00002283 getIRegRexB(8,pfx,base_r),
sewardj3ca55a12005-01-27 16:06:23 +00002284 binop(Iop_Shl64,
sewardj5b470602005-02-27 13:10:48 +00002285 getIReg64rexX(pfx,index_r), mkU8(scale))),
sewardj3ca55a12005-01-27 16:06:23 +00002286 mkU64(d))));
sewardj2f959cc2005-01-26 01:19:35 +00002287 }
sewardj3ca55a12005-01-27 16:06:23 +00002288 vassert(0); /*NOTREACHED*/
sewardj2f959cc2005-01-26 01:19:35 +00002289 }
sewardj3ca55a12005-01-27 16:06:23 +00002290
sewardj2f959cc2005-01-26 01:19:35 +00002291 /* SIB, with 32-bit displacement. Special cases:
2292 -- %rsp cannot act as an index value.
2293 If index_r indicates %rsp, zero is used for the index.
2294 Denoted value is:
2295 | %index == %RSP
2296 = d32 + %base
2297 | %index != %RSP
2298 = d32 + %base + (%index << scale)
2299 */
2300 case 0x14: {
sewardj8c332e22005-01-28 01:36:56 +00002301 UChar sib = getUChar(delta);
sewardj1027dc22005-02-26 01:55:02 +00002302 UChar scale = toUChar((sib >> 6) & 3);
2303 UChar index_r = toUChar((sib >> 3) & 7);
2304 UChar base_r = toUChar(sib & 7);
sewardj8c332e22005-01-28 01:36:56 +00002305 Long d = getSDisp32(delta+1);
sewardj2f959cc2005-01-26 01:19:35 +00002306
2307 if (index_r == R_RSP && 0==getRexX(pfx)) {
sewardje941eea2005-01-30 19:52:28 +00002308 DIS(buf, "%s%lld(%s)", sorbTxt(pfx),
sewardj5b470602005-02-27 13:10:48 +00002309 d, nameIRegRexB(8,pfx,base_r));
sewardj2f959cc2005-01-26 01:19:35 +00002310 *len = 6;
sewardj2f959cc2005-01-26 01:19:35 +00002311 return disAMode_copy2tmp(
sewardj42561ef2005-11-04 14:18:31 +00002312 handleAddrOverrides(pfx,
sewardj5b470602005-02-27 13:10:48 +00002313 binop(Iop_Add64, getIRegRexB(8,pfx,base_r), mkU64(d)) ));
sewardj2f959cc2005-01-26 01:19:35 +00002314 } else {
sewardje941eea2005-01-30 19:52:28 +00002315 if (scale == 0) {
2316 DIS(buf, "%s%lld(%s,%s)", sorbTxt(pfx), d,
sewardj5b470602005-02-27 13:10:48 +00002317 nameIRegRexB(8,pfx,base_r),
2318 nameIReg64rexX(pfx,index_r));
sewardje941eea2005-01-30 19:52:28 +00002319 } else {
2320 DIS(buf, "%s%lld(%s,%s,%d)", sorbTxt(pfx), d,
sewardj5b470602005-02-27 13:10:48 +00002321 nameIRegRexB(8,pfx,base_r),
2322 nameIReg64rexX(pfx,index_r), 1<<scale);
sewardje941eea2005-01-30 19:52:28 +00002323 }
sewardj2f959cc2005-01-26 01:19:35 +00002324 *len = 6;
2325 return
2326 disAMode_copy2tmp(
sewardj42561ef2005-11-04 14:18:31 +00002327 handleAddrOverrides(pfx,
sewardj2f959cc2005-01-26 01:19:35 +00002328 binop(Iop_Add64,
2329 binop(Iop_Add64,
sewardj5b470602005-02-27 13:10:48 +00002330 getIRegRexB(8,pfx,base_r),
sewardj2f959cc2005-01-26 01:19:35 +00002331 binop(Iop_Shl64,
sewardj5b470602005-02-27 13:10:48 +00002332 getIReg64rexX(pfx,index_r), mkU8(scale))),
sewardj2f959cc2005-01-26 01:19:35 +00002333 mkU64(d))));
2334 }
sewardj3ca55a12005-01-27 16:06:23 +00002335 vassert(0); /*NOTREACHED*/
sewardj2f959cc2005-01-26 01:19:35 +00002336 }
2337
sewardjb3a04292005-01-21 20:33:44 +00002338 default:
2339 vpanic("disAMode(amd64)");
2340 return 0; /*notreached*/
2341 }
2342}
2343
2344
sewardj3ca55a12005-01-27 16:06:23 +00002345/* Figure out the number of (insn-stream) bytes constituting the amode
2346 beginning at delta. Is useful for getting hold of literals beyond
2347 the end of the amode before it has been disassembled. */
2348
sewardj270def42005-07-03 01:03:01 +00002349static UInt lengthAMode ( Prefix pfx, Long delta )
sewardj3ca55a12005-01-27 16:06:23 +00002350{
sewardj8c332e22005-01-28 01:36:56 +00002351 UChar mod_reg_rm = getUChar(delta);
sewardj3ca55a12005-01-27 16:06:23 +00002352 delta++;
2353
2354 /* squeeze out the reg field from mod_reg_rm, since a 256-entry
2355 jump table seems a bit excessive.
2356 */
sewardj7a240552005-01-28 21:37:12 +00002357 mod_reg_rm &= 0xC7; /* is now XX000YYY */
sewardj1027dc22005-02-26 01:55:02 +00002358 mod_reg_rm = toUChar(mod_reg_rm | (mod_reg_rm >> 3));
2359 /* is now XX0XXYYY */
sewardj7a240552005-01-28 21:37:12 +00002360 mod_reg_rm &= 0x1F; /* is now 000XXYYY */
sewardj3ca55a12005-01-27 16:06:23 +00002361 switch (mod_reg_rm) {
2362
2363 /* REX.B==0: (%rax) .. (%rdi), not including (%rsp) or (%rbp).
2364 REX.B==1: (%r8) .. (%r15), not including (%r12) or (%r13).
2365 */
2366 case 0x00: case 0x01: case 0x02: case 0x03:
2367 /* ! 04 */ /* ! 05 */ case 0x06: case 0x07:
sewardj3ca55a12005-01-27 16:06:23 +00002368 return 1;
2369
2370 /* REX.B==0: d8(%rax) ... d8(%rdi), not including d8(%rsp)
2371 REX.B==1: d8(%r8) ... d8(%r15), not including d8(%r12)
2372 */
2373 case 0x08: case 0x09: case 0x0A: case 0x0B:
2374 /* ! 0C */ case 0x0D: case 0x0E: case 0x0F:
sewardj3ca55a12005-01-27 16:06:23 +00002375 return 2;
2376
2377 /* REX.B==0: d32(%rax) ... d32(%rdi), not including d32(%rsp)
2378 REX.B==1: d32(%r8) ... d32(%r15), not including d32(%r12)
2379 */
2380 case 0x10: case 0x11: case 0x12: case 0x13:
2381 /* ! 14 */ case 0x15: case 0x16: case 0x17:
sewardj3ca55a12005-01-27 16:06:23 +00002382 return 5;
2383
2384 /* REX.B==0: a register, %rax .. %rdi. This shouldn't happen. */
2385 /* REX.B==1: a register, %r8 .. %r16. This shouldn't happen. */
2386 /* Not an address, but still handled. */
2387 case 0x18: case 0x19: case 0x1A: case 0x1B:
2388 case 0x1C: case 0x1D: case 0x1E: case 0x1F:
2389 return 1;
2390
2391 /* RIP + disp32. */
2392 case 0x05:
sewardj3ca55a12005-01-27 16:06:23 +00002393 return 5;
2394
2395 case 0x04: {
2396 /* SIB, with no displacement. */
sewardj8c332e22005-01-28 01:36:56 +00002397 UChar sib = getUChar(delta);
sewardj1027dc22005-02-26 01:55:02 +00002398 UChar base_r = toUChar(sib & 7);
sewardj3ca55a12005-01-27 16:06:23 +00002399 /* correct since #(R13) == 8 + #(RBP) */
sewardj7a240552005-01-28 21:37:12 +00002400 Bool base_is_BPor13 = toBool(base_r == R_RBP);
sewardj3ca55a12005-01-27 16:06:23 +00002401
2402 if (base_is_BPor13) {
sewardj3ca55a12005-01-27 16:06:23 +00002403 return 6;
2404 } else {
sewardj3ca55a12005-01-27 16:06:23 +00002405 return 2;
2406 }
2407 }
2408
2409 /* SIB, with 8-bit displacement. */
2410 case 0x0C:
2411 return 3;
2412
2413 /* SIB, with 32-bit displacement. */
2414 case 0x14:
2415 return 6;
2416
2417 default:
2418 vpanic("lengthAMode(amd64)");
2419 return 0; /*notreached*/
2420 }
2421}
2422
2423
sewardjdf0e0022005-01-25 15:48:43 +00002424/*------------------------------------------------------------*/
2425/*--- Disassembling common idioms ---*/
2426/*------------------------------------------------------------*/
2427
sewardjdf0e0022005-01-25 15:48:43 +00002428/* Handle binary integer instructions of the form
2429 op E, G meaning
2430 op reg-or-mem, reg
2431 Is passed the a ptr to the modRM byte, the actual operation, and the
2432 data size. Returns the address advanced completely over this
2433 instruction.
2434
2435 E(src) is reg-or-mem
2436 G(dst) is reg.
2437
2438 If E is reg, --> GET %G, tmp
2439 OP %E, tmp
2440 PUT tmp, %G
2441
2442 If E is mem and OP is not reversible,
2443 --> (getAddr E) -> tmpa
2444 LD (tmpa), tmpa
2445 GET %G, tmp2
2446 OP tmpa, tmp2
2447 PUT tmp2, %G
2448
2449 If E is mem and OP is reversible
2450 --> (getAddr E) -> tmpa
2451 LD (tmpa), tmpa
2452 OP %G, tmpa
2453 PUT tmpa, %G
2454*/
2455static
2456ULong dis_op2_E_G ( Prefix pfx,
2457 Bool addSubCarry,
2458 IROp op8,
2459 Bool keep,
2460 Int size,
sewardj270def42005-07-03 01:03:01 +00002461 Long delta0,
sewardj8c332e22005-01-28 01:36:56 +00002462 HChar* t_amd64opc )
sewardjdf0e0022005-01-25 15:48:43 +00002463{
2464 HChar dis_buf[50];
2465 Int len;
2466 IRType ty = szToITy(size);
2467 IRTemp dst1 = newTemp(ty);
2468 IRTemp src = newTemp(ty);
2469 IRTemp dst0 = newTemp(ty);
2470 UChar rm = getUChar(delta0);
2471 IRTemp addr = IRTemp_INVALID;
2472
2473 /* addSubCarry == True indicates the intended operation is
2474 add-with-carry or subtract-with-borrow. */
2475 if (addSubCarry) {
2476 vassert(op8 == Iop_Add8 || op8 == Iop_Sub8);
2477 vassert(keep);
2478 }
2479
2480 if (epartIsReg(rm)) {
sewardjdf0e0022005-01-25 15:48:43 +00002481 /* Specially handle XOR reg,reg, because that doesn't really
2482 depend on reg, and doing the obvious thing potentially
2483 generates a spurious value check failure due to the bogus
2484 dependency. */
sewardj5b470602005-02-27 13:10:48 +00002485 if ((op8 == Iop_Xor8 || (op8 == Iop_Sub8 && addSubCarry))
2486 && offsetIRegG(size,pfx,rm) == offsetIRegE(size,pfx,rm)) {
sewardj4f9847d2005-07-25 11:58:34 +00002487 if (False && op8 == Iop_Sub8)
sewardj5b470602005-02-27 13:10:48 +00002488 vex_printf("vex amd64->IR: sbb %%r,%%r optimisation(1)\n");
2489 putIRegG(size,pfx,rm, mkU(ty,0));
sewardjdf0e0022005-01-25 15:48:43 +00002490 }
sewardj5b470602005-02-27 13:10:48 +00002491
2492 assign( dst0, getIRegG(size,pfx,rm) );
2493 assign( src, getIRegE(size,pfx,rm) );
sewardjdf0e0022005-01-25 15:48:43 +00002494
2495 if (addSubCarry && op8 == Iop_Add8) {
sewardj3ca55a12005-01-27 16:06:23 +00002496 vassert(0); /* awaiting test case */
sewardjdf0e0022005-01-25 15:48:43 +00002497 helper_ADC( size, dst1, dst0, src );
sewardj5b470602005-02-27 13:10:48 +00002498 putIRegG(size, pfx, rm, mkexpr(dst1));
sewardjdf0e0022005-01-25 15:48:43 +00002499 } else
2500 if (addSubCarry && op8 == Iop_Sub8) {
2501 helper_SBB( size, dst1, dst0, src );
sewardj5b470602005-02-27 13:10:48 +00002502 putIRegG(size, pfx, rm, mkexpr(dst1));
sewardjdf0e0022005-01-25 15:48:43 +00002503 } else {
2504 assign( dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
2505 if (isAddSub(op8))
2506 setFlags_DEP1_DEP2(op8, dst0, src, ty);
2507 else
2508 setFlags_DEP1(op8, dst1, ty);
2509 if (keep)
sewardj5b470602005-02-27 13:10:48 +00002510 putIRegG(size, pfx, rm, mkexpr(dst1));
sewardjdf0e0022005-01-25 15:48:43 +00002511 }
2512
2513 DIP("%s%c %s,%s\n", t_amd64opc, nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00002514 nameIRegE(size,pfx,rm),
2515 nameIRegG(size,pfx,rm));
sewardjdf0e0022005-01-25 15:48:43 +00002516 return 1+delta0;
2517 } else {
2518 /* E refers to memory */
sewardje1698952005-02-08 15:02:39 +00002519 addr = disAMode ( &len, pfx, delta0, dis_buf, 0 );
sewardj5b470602005-02-27 13:10:48 +00002520 assign( dst0, getIRegG(size,pfx,rm) );
sewardjdf0e0022005-01-25 15:48:43 +00002521 assign( src, loadLE(szToITy(size), mkexpr(addr)) );
2522
2523 if (addSubCarry && op8 == Iop_Add8) {
2524 helper_ADC( size, dst1, dst0, src );
sewardj5b470602005-02-27 13:10:48 +00002525 putIRegG(size, pfx, rm, mkexpr(dst1));
sewardjdf0e0022005-01-25 15:48:43 +00002526 } else
2527 if (addSubCarry && op8 == Iop_Sub8) {
2528 helper_SBB( size, dst1, dst0, src );
sewardj5b470602005-02-27 13:10:48 +00002529 putIRegG(size, pfx, rm, mkexpr(dst1));
sewardjdf0e0022005-01-25 15:48:43 +00002530 } else {
2531 assign( dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
2532 if (isAddSub(op8))
2533 setFlags_DEP1_DEP2(op8, dst0, src, ty);
2534 else
2535 setFlags_DEP1(op8, dst1, ty);
2536 if (keep)
sewardj5b470602005-02-27 13:10:48 +00002537 putIRegG(size, pfx, rm, mkexpr(dst1));
sewardjdf0e0022005-01-25 15:48:43 +00002538 }
2539
2540 DIP("%s%c %s,%s\n", t_amd64opc, nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00002541 dis_buf, nameIRegG(size, pfx, rm));
sewardjdf0e0022005-01-25 15:48:43 +00002542 return len+delta0;
2543 }
2544}
2545
2546
2547
sewardj3ca55a12005-01-27 16:06:23 +00002548/* Handle binary integer instructions of the form
2549 op G, E meaning
2550 op reg, reg-or-mem
2551 Is passed the a ptr to the modRM byte, the actual operation, and the
2552 data size. Returns the address advanced completely over this
2553 instruction.
2554
2555 G(src) is reg.
2556 E(dst) is reg-or-mem
2557
2558 If E is reg, --> GET %E, tmp
2559 OP %G, tmp
2560 PUT tmp, %E
2561
2562 If E is mem, --> (getAddr E) -> tmpa
2563 LD (tmpa), tmpv
2564 OP %G, tmpv
2565 ST tmpv, (tmpa)
2566*/
2567static
sewardj8c332e22005-01-28 01:36:56 +00002568ULong dis_op2_G_E ( Prefix pfx,
2569 Bool addSubCarry,
2570 IROp op8,
2571 Bool keep,
2572 Int size,
sewardj270def42005-07-03 01:03:01 +00002573 Long delta0,
sewardj8c332e22005-01-28 01:36:56 +00002574 HChar* t_amd64opc )
sewardj3ca55a12005-01-27 16:06:23 +00002575{
2576 HChar dis_buf[50];
2577 Int len;
2578 IRType ty = szToITy(size);
2579 IRTemp dst1 = newTemp(ty);
2580 IRTemp src = newTemp(ty);
2581 IRTemp dst0 = newTemp(ty);
sewardj8c332e22005-01-28 01:36:56 +00002582 UChar rm = getUChar(delta0);
sewardj3ca55a12005-01-27 16:06:23 +00002583 IRTemp addr = IRTemp_INVALID;
2584
2585 /* addSubCarry == True indicates the intended operation is
2586 add-with-carry or subtract-with-borrow. */
2587 if (addSubCarry) {
2588 vassert(op8 == Iop_Add8 || op8 == Iop_Sub8);
2589 vassert(keep);
2590 }
2591
2592 if (epartIsReg(rm)) {
2593 /* Specially handle XOR reg,reg, because that doesn't really
2594 depend on reg, and doing the obvious thing potentially
2595 generates a spurious value check failure due to the bogus
sewardj5b470602005-02-27 13:10:48 +00002596 dependency. Ditto SBB reg,reg. */
2597 if ((op8 == Iop_Xor8 || (op8 == Iop_Sub8 && addSubCarry))
2598 && offsetIRegG(size,pfx,rm) == offsetIRegE(size,pfx,rm)) {
2599 putIRegE(size,pfx,rm, mkU(ty,0));
sewardj3ca55a12005-01-27 16:06:23 +00002600 }
sewardj5b470602005-02-27 13:10:48 +00002601
2602 assign(dst0, getIRegE(size,pfx,rm));
2603 assign(src, getIRegG(size,pfx,rm));
sewardj3ca55a12005-01-27 16:06:23 +00002604
2605 if (addSubCarry && op8 == Iop_Add8) {
sewardj3ca55a12005-01-27 16:06:23 +00002606 helper_ADC( size, dst1, dst0, src );
sewardj5b470602005-02-27 13:10:48 +00002607 putIRegE(size, pfx, rm, mkexpr(dst1));
sewardj3ca55a12005-01-27 16:06:23 +00002608 } else
2609 if (addSubCarry && op8 == Iop_Sub8) {
sewardj3ca55a12005-01-27 16:06:23 +00002610 helper_SBB( size, dst1, dst0, src );
sewardj5b470602005-02-27 13:10:48 +00002611 putIRegE(size, pfx, rm, mkexpr(dst1));
sewardj3ca55a12005-01-27 16:06:23 +00002612 } else {
2613 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
2614 if (isAddSub(op8))
2615 setFlags_DEP1_DEP2(op8, dst0, src, ty);
2616 else
2617 setFlags_DEP1(op8, dst1, ty);
2618 if (keep)
sewardj5b470602005-02-27 13:10:48 +00002619 putIRegE(size, pfx, rm, mkexpr(dst1));
sewardj3ca55a12005-01-27 16:06:23 +00002620 }
2621
2622 DIP("%s%c %s,%s\n", t_amd64opc, nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00002623 nameIRegG(size,pfx,rm),
2624 nameIRegE(size,pfx,rm));
sewardj3ca55a12005-01-27 16:06:23 +00002625 return 1+delta0;
2626 }
2627
2628 /* E refers to memory */
2629 {
sewardje1698952005-02-08 15:02:39 +00002630 addr = disAMode ( &len, pfx, delta0, dis_buf, 0 );
sewardj3ca55a12005-01-27 16:06:23 +00002631 assign(dst0, loadLE(ty,mkexpr(addr)));
sewardj5b470602005-02-27 13:10:48 +00002632 assign(src, getIRegG(size,pfx,rm));
sewardj3ca55a12005-01-27 16:06:23 +00002633
2634 if (addSubCarry && op8 == Iop_Add8) {
sewardj3ca55a12005-01-27 16:06:23 +00002635 helper_ADC( size, dst1, dst0, src );
2636 storeLE(mkexpr(addr), mkexpr(dst1));
2637 } else
2638 if (addSubCarry && op8 == Iop_Sub8) {
sewardj3ca55a12005-01-27 16:06:23 +00002639 helper_SBB( size, dst1, dst0, src );
2640 storeLE(mkexpr(addr), mkexpr(dst1));
2641 } else {
2642 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
2643 if (isAddSub(op8))
2644 setFlags_DEP1_DEP2(op8, dst0, src, ty);
2645 else
2646 setFlags_DEP1(op8, dst1, ty);
2647 if (keep)
2648 storeLE(mkexpr(addr), mkexpr(dst1));
2649 }
2650
2651 DIP("%s%c %s,%s\n", t_amd64opc, nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00002652 nameIRegG(size,pfx,rm), dis_buf);
sewardj3ca55a12005-01-27 16:06:23 +00002653 return len+delta0;
2654 }
2655}
2656
2657
sewardj1389d4d2005-01-28 13:46:29 +00002658/* Handle move instructions of the form
2659 mov E, G meaning
2660 mov reg-or-mem, reg
2661 Is passed the a ptr to the modRM byte, and the data size. Returns
2662 the address advanced completely over this instruction.
2663
2664 E(src) is reg-or-mem
2665 G(dst) is reg.
2666
2667 If E is reg, --> GET %E, tmpv
2668 PUT tmpv, %G
2669
2670 If E is mem --> (getAddr E) -> tmpa
2671 LD (tmpa), tmpb
2672 PUT tmpb, %G
2673*/
2674static
2675ULong dis_mov_E_G ( Prefix pfx,
2676 Int size,
sewardj270def42005-07-03 01:03:01 +00002677 Long delta0 )
sewardj1389d4d2005-01-28 13:46:29 +00002678{
2679 Int len;
2680 UChar rm = getUChar(delta0);
2681 HChar dis_buf[50];
2682
2683 if (epartIsReg(rm)) {
sewardj5b470602005-02-27 13:10:48 +00002684 putIRegG(size, pfx, rm, getIRegE(size, pfx, rm));
sewardje941eea2005-01-30 19:52:28 +00002685 DIP("mov%c %s,%s\n", nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00002686 nameIRegE(size,pfx,rm),
2687 nameIRegG(size,pfx,rm));
sewardj1389d4d2005-01-28 13:46:29 +00002688 return 1+delta0;
2689 }
2690
2691 /* E refers to memory */
2692 {
sewardje1698952005-02-08 15:02:39 +00002693 IRTemp addr = disAMode ( &len, pfx, delta0, dis_buf, 0 );
sewardj5b470602005-02-27 13:10:48 +00002694 putIRegG(size, pfx, rm, loadLE(szToITy(size), mkexpr(addr)));
sewardj1389d4d2005-01-28 13:46:29 +00002695 DIP("mov%c %s,%s\n", nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00002696 dis_buf,
2697 nameIRegG(size,pfx,rm));
sewardj1389d4d2005-01-28 13:46:29 +00002698 return delta0+len;
2699 }
2700}
2701
2702
2703/* Handle move instructions of the form
2704 mov G, E meaning
2705 mov reg, reg-or-mem
2706 Is passed the a ptr to the modRM byte, and the data size. Returns
2707 the address advanced completely over this instruction.
2708
2709 G(src) is reg.
2710 E(dst) is reg-or-mem
2711
2712 If E is reg, --> GET %G, tmp
2713 PUT tmp, %E
2714
2715 If E is mem, --> (getAddr E) -> tmpa
2716 GET %G, tmpv
2717 ST tmpv, (tmpa)
2718*/
2719static
2720ULong dis_mov_G_E ( Prefix pfx,
2721 Int size,
sewardj270def42005-07-03 01:03:01 +00002722 Long delta0 )
sewardj1389d4d2005-01-28 13:46:29 +00002723{
2724 Int len;
2725 UChar rm = getUChar(delta0);
2726 HChar dis_buf[50];
2727
2728 if (epartIsReg(rm)) {
sewardj5b470602005-02-27 13:10:48 +00002729 putIRegE(size, pfx, rm, getIRegG(size, pfx, rm));
sewardje941eea2005-01-30 19:52:28 +00002730 DIP("mov%c %s,%s\n", nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00002731 nameIRegG(size,pfx,rm),
2732 nameIRegE(size,pfx,rm));
sewardj1389d4d2005-01-28 13:46:29 +00002733 return 1+delta0;
2734 }
2735
2736 /* E refers to memory */
2737 {
sewardje1698952005-02-08 15:02:39 +00002738 IRTemp addr = disAMode ( &len, pfx, delta0, dis_buf, 0 );
sewardj5b470602005-02-27 13:10:48 +00002739 storeLE( mkexpr(addr), getIRegG(size, pfx, rm) );
sewardj1389d4d2005-01-28 13:46:29 +00002740 DIP("mov%c %s,%s\n", nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00002741 nameIRegG(size,pfx,rm),
2742 dis_buf);
sewardj1389d4d2005-01-28 13:46:29 +00002743 return len+delta0;
2744 }
2745}
sewardj3ca55a12005-01-27 16:06:23 +00002746
2747
2748/* op $immediate, AL/AX/EAX/RAX. */
2749static
sewardj8c332e22005-01-28 01:36:56 +00002750ULong dis_op_imm_A ( Int size,
sewardj41c01092005-07-23 13:50:32 +00002751 Bool carrying,
sewardj8c332e22005-01-28 01:36:56 +00002752 IROp op8,
2753 Bool keep,
sewardj270def42005-07-03 01:03:01 +00002754 Long delta,
sewardj8c332e22005-01-28 01:36:56 +00002755 HChar* t_amd64opc )
sewardj3ca55a12005-01-27 16:06:23 +00002756{
2757 Int size4 = imin(size,4);
2758 IRType ty = szToITy(size);
2759 IRTemp dst0 = newTemp(ty);
2760 IRTemp src = newTemp(ty);
2761 IRTemp dst1 = newTemp(ty);
sewardj8c332e22005-01-28 01:36:56 +00002762 Long lit = getSDisp(size4,delta);
sewardj5b470602005-02-27 13:10:48 +00002763 assign(dst0, getIRegRAX(size));
sewardj1389d4d2005-01-28 13:46:29 +00002764 assign(src, mkU(ty,lit & mkSizeMask(size)));
sewardj41c01092005-07-23 13:50:32 +00002765
2766 if (isAddSub(op8) && !carrying) {
2767 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
sewardj3ca55a12005-01-27 16:06:23 +00002768 setFlags_DEP1_DEP2(op8, dst0, src, ty);
sewardj41c01092005-07-23 13:50:32 +00002769 }
sewardj3ca55a12005-01-27 16:06:23 +00002770 else
sewardj41c01092005-07-23 13:50:32 +00002771 if (isLogic(op8)) {
2772 vassert(!carrying);
2773 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
sewardj3ca55a12005-01-27 16:06:23 +00002774 setFlags_DEP1(op8, dst1, ty);
sewardj41c01092005-07-23 13:50:32 +00002775 }
sewardj3ca55a12005-01-27 16:06:23 +00002776 else
sewardj41c01092005-07-23 13:50:32 +00002777 if (op8 == Iop_Add8 && carrying) {
2778 helper_ADC( size, dst1, dst0, src );
2779 }
2780 else
sewardj5fadaf92006-05-12 20:45:59 +00002781 if (op8 == Iop_Sub8 && carrying) {
2782 helper_SBB( size, dst1, dst0, src );
2783 }
2784 else
sewardj41c01092005-07-23 13:50:32 +00002785 vpanic("dis_op_imm_A(amd64,guest)");
sewardj3ca55a12005-01-27 16:06:23 +00002786
2787 if (keep)
sewardj5b470602005-02-27 13:10:48 +00002788 putIRegRAX(size, mkexpr(dst1));
sewardj3ca55a12005-01-27 16:06:23 +00002789
2790 DIP("%s%c $%lld, %s\n", t_amd64opc, nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00002791 lit, nameIRegRAX(size));
sewardj3ca55a12005-01-27 16:06:23 +00002792 return delta+size4;
2793}
2794
2795
sewardj5e525292005-01-28 15:13:10 +00002796/* Sign- and Zero-extending moves. */
2797static
2798ULong dis_movx_E_G ( Prefix pfx,
sewardj270def42005-07-03 01:03:01 +00002799 Long delta, Int szs, Int szd, Bool sign_extend )
sewardj5e525292005-01-28 15:13:10 +00002800{
2801 UChar rm = getUChar(delta);
2802 if (epartIsReg(rm)) {
sewardj5b470602005-02-27 13:10:48 +00002803 putIRegG(szd, pfx, rm,
sewardj5e525292005-01-28 15:13:10 +00002804 doScalarWidening(
2805 szs,szd,sign_extend,
sewardj5b470602005-02-27 13:10:48 +00002806 getIRegE(szs,pfx,rm)));
sewardj5e525292005-01-28 15:13:10 +00002807 DIP("mov%c%c%c %s,%s\n", sign_extend ? 's' : 'z',
2808 nameISize(szs),
2809 nameISize(szd),
sewardj5b470602005-02-27 13:10:48 +00002810 nameIRegE(szs,pfx,rm),
2811 nameIRegG(szd,pfx,rm));
sewardj5e525292005-01-28 15:13:10 +00002812 return 1+delta;
2813 }
2814
2815 /* E refers to memory */
2816 {
2817 Int len;
2818 HChar dis_buf[50];
sewardje1698952005-02-08 15:02:39 +00002819 IRTemp addr = disAMode ( &len, pfx, delta, dis_buf, 0 );
sewardj5b470602005-02-27 13:10:48 +00002820 putIRegG(szd, pfx, rm,
sewardj5e525292005-01-28 15:13:10 +00002821 doScalarWidening(
2822 szs,szd,sign_extend,
2823 loadLE(szToITy(szs),mkexpr(addr))));
2824 DIP("mov%c%c%c %s,%s\n", sign_extend ? 's' : 'z',
2825 nameISize(szs),
2826 nameISize(szd),
2827 dis_buf,
sewardj5b470602005-02-27 13:10:48 +00002828 nameIRegG(szd,pfx,rm));
sewardj5e525292005-01-28 15:13:10 +00002829 return len+delta;
2830 }
2831}
sewardj32b2bbe2005-01-28 00:50:10 +00002832
2833
sewardj03b07cc2005-01-31 18:09:43 +00002834/* Generate code to divide ArchRegs RDX:RAX / EDX:EAX / DX:AX / AX by
2835 the 64 / 32 / 16 / 8 bit quantity in the given IRTemp. */
sewardj32b2bbe2005-01-28 00:50:10 +00002836static
2837void codegen_div ( Int sz, IRTemp t, Bool signed_divide )
2838{
sewardj03b07cc2005-01-31 18:09:43 +00002839 /* special-case the 64-bit case */
2840 if (sz == 8) {
2841 IROp op = signed_divide ? Iop_DivModS128to64
2842 : Iop_DivModU128to64;
sewardja6b93d12005-02-17 09:28:28 +00002843 IRTemp src128 = newTemp(Ity_I128);
2844 IRTemp dst128 = newTemp(Ity_I128);
sewardj03b07cc2005-01-31 18:09:43 +00002845 assign( src128, binop(Iop_64HLto128,
sewardja6b93d12005-02-17 09:28:28 +00002846 getIReg64(R_RDX),
2847 getIReg64(R_RAX)) );
sewardj03b07cc2005-01-31 18:09:43 +00002848 assign( dst128, binop(op, mkexpr(src128), mkexpr(t)) );
sewardja6b93d12005-02-17 09:28:28 +00002849 putIReg64( R_RAX, unop(Iop_128to64,mkexpr(dst128)) );
2850 putIReg64( R_RDX, unop(Iop_128HIto64,mkexpr(dst128)) );
sewardj03b07cc2005-01-31 18:09:43 +00002851 } else {
2852 IROp op = signed_divide ? Iop_DivModS64to32
2853 : Iop_DivModU64to32;
2854 IRTemp src64 = newTemp(Ity_I64);
2855 IRTemp dst64 = newTemp(Ity_I64);
2856 switch (sz) {
sewardj85520e42005-02-19 15:22:38 +00002857 case 4:
sewardj5b470602005-02-27 13:10:48 +00002858 assign( src64,
2859 binop(Iop_32HLto64, getIRegRDX(4), getIRegRAX(4)) );
2860 assign( dst64,
2861 binop(op, mkexpr(src64), mkexpr(t)) );
2862 putIRegRAX( 4, unop(Iop_64to32,mkexpr(dst64)) );
2863 putIRegRDX( 4, unop(Iop_64HIto32,mkexpr(dst64)) );
sewardj85520e42005-02-19 15:22:38 +00002864 break;
2865 case 2: {
2866 IROp widen3264 = signed_divide ? Iop_32Sto64 : Iop_32Uto64;
2867 IROp widen1632 = signed_divide ? Iop_16Sto32 : Iop_16Uto32;
2868 assign( src64, unop(widen3264,
2869 binop(Iop_16HLto32,
sewardj5b470602005-02-27 13:10:48 +00002870 getIRegRDX(2),
2871 getIRegRAX(2))) );
sewardj85520e42005-02-19 15:22:38 +00002872 assign( dst64, binop(op, mkexpr(src64), unop(widen1632,mkexpr(t))) );
sewardj5b470602005-02-27 13:10:48 +00002873 putIRegRAX( 2, unop(Iop_32to16,unop(Iop_64to32,mkexpr(dst64))) );
2874 putIRegRDX( 2, unop(Iop_32to16,unop(Iop_64HIto32,mkexpr(dst64))) );
sewardj85520e42005-02-19 15:22:38 +00002875 break;
2876 }
2877 case 1: {
2878 IROp widen3264 = signed_divide ? Iop_32Sto64 : Iop_32Uto64;
2879 IROp widen1632 = signed_divide ? Iop_16Sto32 : Iop_16Uto32;
2880 IROp widen816 = signed_divide ? Iop_8Sto16 : Iop_8Uto16;
2881 assign( src64, unop(widen3264,
sewardj5b470602005-02-27 13:10:48 +00002882 unop(widen1632, getIRegRAX(2))) );
sewardj85520e42005-02-19 15:22:38 +00002883 assign( dst64,
2884 binop(op, mkexpr(src64),
2885 unop(widen1632, unop(widen816, mkexpr(t)))) );
sewardj5b470602005-02-27 13:10:48 +00002886 putIRegRAX( 1, unop(Iop_16to8,
2887 unop(Iop_32to16,
2888 unop(Iop_64to32,mkexpr(dst64)))) );
2889 putIRegAH( unop(Iop_16to8,
2890 unop(Iop_32to16,
2891 unop(Iop_64HIto32,mkexpr(dst64)))) );
sewardj85520e42005-02-19 15:22:38 +00002892 break;
2893 }
2894 default:
2895 vpanic("codegen_div(amd64)");
sewardj03b07cc2005-01-31 18:09:43 +00002896 }
sewardj32b2bbe2005-01-28 00:50:10 +00002897 }
2898}
sewardj3ca55a12005-01-27 16:06:23 +00002899
2900static
sewardj8c332e22005-01-28 01:36:56 +00002901ULong dis_Grp1 ( Prefix pfx,
sewardj270def42005-07-03 01:03:01 +00002902 Long delta, UChar modrm,
sewardj227458e2005-01-31 19:04:50 +00002903 Int am_sz, Int d_sz, Int sz, Long d64 )
sewardj3ca55a12005-01-27 16:06:23 +00002904{
2905 Int len;
2906 HChar dis_buf[50];
2907 IRType ty = szToITy(sz);
2908 IRTemp dst1 = newTemp(ty);
2909 IRTemp src = newTemp(ty);
2910 IRTemp dst0 = newTemp(ty);
2911 IRTemp addr = IRTemp_INVALID;
2912 IROp op8 = Iop_INVALID;
sewardj1389d4d2005-01-28 13:46:29 +00002913 ULong mask = mkSizeMask(sz);
sewardj3ca55a12005-01-27 16:06:23 +00002914
sewardj901ed122005-02-27 13:25:31 +00002915 switch (gregLO3ofRM(modrm)) {
sewardj3ca55a12005-01-27 16:06:23 +00002916 case 0: op8 = Iop_Add8; break; case 1: op8 = Iop_Or8; break;
2917 case 2: break; // ADC
2918 case 3: break; // SBB
2919 case 4: op8 = Iop_And8; break; case 5: op8 = Iop_Sub8; break;
2920 case 6: op8 = Iop_Xor8; break; case 7: op8 = Iop_Sub8; break;
2921 default: vpanic("dis_Grp1(amd64): unhandled case");
2922 }
2923
2924 if (epartIsReg(modrm)) {
2925 vassert(am_sz == 1);
2926
sewardj5b470602005-02-27 13:10:48 +00002927 assign(dst0, getIRegE(sz,pfx,modrm));
sewardj227458e2005-01-31 19:04:50 +00002928 assign(src, mkU(ty,d64 & mask));
sewardj3ca55a12005-01-27 16:06:23 +00002929
sewardj901ed122005-02-27 13:25:31 +00002930 if (gregLO3ofRM(modrm) == 2 /* ADC */) {
sewardj3ca55a12005-01-27 16:06:23 +00002931 helper_ADC( sz, dst1, dst0, src );
2932 } else
sewardj901ed122005-02-27 13:25:31 +00002933 if (gregLO3ofRM(modrm) == 3 /* SBB */) {
sewardj3ca55a12005-01-27 16:06:23 +00002934 helper_SBB( sz, dst1, dst0, src );
2935 } else {
2936 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
2937 if (isAddSub(op8))
2938 setFlags_DEP1_DEP2(op8, dst0, src, ty);
2939 else
2940 setFlags_DEP1(op8, dst1, ty);
2941 }
2942
sewardj901ed122005-02-27 13:25:31 +00002943 if (gregLO3ofRM(modrm) < 7)
sewardj5b470602005-02-27 13:10:48 +00002944 putIRegE(sz, pfx, modrm, mkexpr(dst1));
sewardj3ca55a12005-01-27 16:06:23 +00002945
2946 delta += (am_sz + d_sz);
sewardje941eea2005-01-30 19:52:28 +00002947 DIP("%s%c $%lld, %s\n",
sewardj901ed122005-02-27 13:25:31 +00002948 nameGrp1(gregLO3ofRM(modrm)), nameISize(sz), d64,
sewardj5b470602005-02-27 13:10:48 +00002949 nameIRegE(sz,pfx,modrm));
sewardj3ca55a12005-01-27 16:06:23 +00002950 } else {
sewardje1698952005-02-08 15:02:39 +00002951 addr = disAMode ( &len, pfx, delta, dis_buf, /*xtra*/d_sz );
sewardj3ca55a12005-01-27 16:06:23 +00002952
2953 assign(dst0, loadLE(ty,mkexpr(addr)));
sewardj227458e2005-01-31 19:04:50 +00002954 assign(src, mkU(ty,d64 & mask));
sewardj3ca55a12005-01-27 16:06:23 +00002955
sewardj901ed122005-02-27 13:25:31 +00002956 if (gregLO3ofRM(modrm) == 2 /* ADC */) {
sewardj3ca55a12005-01-27 16:06:23 +00002957 helper_ADC( sz, dst1, dst0, src );
2958 } else
sewardj901ed122005-02-27 13:25:31 +00002959 if (gregLO3ofRM(modrm) == 3 /* SBB */) {
sewardj3ca55a12005-01-27 16:06:23 +00002960 helper_SBB( sz, dst1, dst0, src );
2961 } else {
2962 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
2963 if (isAddSub(op8))
2964 setFlags_DEP1_DEP2(op8, dst0, src, ty);
2965 else
2966 setFlags_DEP1(op8, dst1, ty);
2967 }
2968
sewardj901ed122005-02-27 13:25:31 +00002969 if (gregLO3ofRM(modrm) < 7)
sewardj3ca55a12005-01-27 16:06:23 +00002970 storeLE(mkexpr(addr), mkexpr(dst1));
2971
2972 delta += (len+d_sz);
sewardje941eea2005-01-30 19:52:28 +00002973 DIP("%s%c $%lld, %s\n",
sewardj901ed122005-02-27 13:25:31 +00002974 nameGrp1(gregLO3ofRM(modrm)), nameISize(sz),
sewardj227458e2005-01-31 19:04:50 +00002975 d64, dis_buf);
sewardj3ca55a12005-01-27 16:06:23 +00002976 }
2977 return delta;
2978}
2979
2980
sewardj118b23e2005-01-29 02:14:44 +00002981/* Group 2 extended opcodes. shift_expr must be an 8-bit typed
2982 expression. */
2983
2984static
2985ULong dis_Grp2 ( Prefix pfx,
sewardj270def42005-07-03 01:03:01 +00002986 Long delta, UChar modrm,
sewardj118b23e2005-01-29 02:14:44 +00002987 Int am_sz, Int d_sz, Int sz, IRExpr* shift_expr,
2988 HChar* shift_expr_txt )
2989{
2990 /* delta on entry points at the modrm byte. */
2991 HChar dis_buf[50];
2992 Int len;
2993 Bool isShift, isRotate, isRotateRC;
2994 IRType ty = szToITy(sz);
2995 IRTemp dst0 = newTemp(ty);
2996 IRTemp dst1 = newTemp(ty);
2997 IRTemp addr = IRTemp_INVALID;
2998
2999 vassert(sz == 1 || sz == 2 || sz == 4 || sz == 8);
3000
3001 /* Put value to shift/rotate in dst0. */
3002 if (epartIsReg(modrm)) {
sewardj5b470602005-02-27 13:10:48 +00003003 assign(dst0, getIRegE(sz, pfx, modrm));
sewardj118b23e2005-01-29 02:14:44 +00003004 delta += (am_sz + d_sz);
3005 } else {
sewardj3587c6b2005-08-14 00:09:58 +00003006 addr = disAMode ( &len, pfx, delta, dis_buf, /*xtra*/d_sz );
sewardj118b23e2005-01-29 02:14:44 +00003007 assign(dst0, loadLE(ty,mkexpr(addr)));
3008 delta += len + d_sz;
3009 }
3010
3011 isShift = False;
sewardj901ed122005-02-27 13:25:31 +00003012 switch (gregLO3ofRM(modrm)) { case 4: case 5: case 7: isShift = True; }
sewardj118b23e2005-01-29 02:14:44 +00003013
3014 isRotate = False;
sewardj901ed122005-02-27 13:25:31 +00003015 switch (gregLO3ofRM(modrm)) { case 0: case 1: isRotate = True; }
sewardj118b23e2005-01-29 02:14:44 +00003016
sewardj901ed122005-02-27 13:25:31 +00003017 isRotateRC = toBool(gregLO3ofRM(modrm) == 3);
sewardj118b23e2005-01-29 02:14:44 +00003018
3019 if (!isShift && !isRotate && !isRotateRC) {
sewardj901ed122005-02-27 13:25:31 +00003020 vex_printf("\ncase %d\n", gregLO3ofRM(modrm));
sewardj118b23e2005-01-29 02:14:44 +00003021 vpanic("dis_Grp2(Reg): unhandled case(amd64)");
3022 }
3023
3024 if (isRotateRC) {
sewardj112b0992005-07-23 13:19:32 +00003025 /* Call a helper; this insn is so ridiculous it does not deserve
3026 better. One problem is, the helper has to calculate both the
3027 new value and the new flags. This is more than 64 bits, and
3028 there is no way to return more than 64 bits from the helper.
3029 Hence the crude and obvious solution is to call it twice,
3030 using the sign of the sz field to indicate whether it is the
3031 value or rflags result we want.
3032 */
3033 IRExpr** argsVALUE;
3034 IRExpr** argsRFLAGS;
3035
3036 IRTemp new_value = newTemp(Ity_I64);
3037 IRTemp new_rflags = newTemp(Ity_I64);
3038 IRTemp old_rflags = newTemp(Ity_I64);
3039
3040 assign( old_rflags, widenUto64(mk_amd64g_calculate_rflags_all()) );
3041
3042 argsVALUE
3043 = mkIRExprVec_4( widenUto64(mkexpr(dst0)), /* thing to rotate */
3044 widenUto64(shift_expr), /* rotate amount */
3045 mkexpr(old_rflags),
3046 mkU64(sz) );
3047 assign( new_value,
3048 mkIRExprCCall(
3049 Ity_I64,
3050 0/*regparm*/,
3051 "amd64g_calculate_RCR", &amd64g_calculate_RCR,
3052 argsVALUE
3053 )
3054 );
3055
3056 argsRFLAGS
3057 = mkIRExprVec_4( widenUto64(mkexpr(dst0)), /* thing to rotate */
3058 widenUto64(shift_expr), /* rotate amount */
3059 mkexpr(old_rflags),
3060 mkU64(-sz) );
3061 assign( new_rflags,
3062 mkIRExprCCall(
3063 Ity_I64,
3064 0/*regparm*/,
3065 "amd64g_calculate_RCR", &amd64g_calculate_RCR,
3066 argsRFLAGS
3067 )
3068 );
3069
3070 assign( dst1, narrowTo(ty, mkexpr(new_value)) );
3071 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(AMD64G_CC_OP_COPY) ));
3072 stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(new_rflags) ));
3073 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
3074 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU64(0) ));
sewardj118b23e2005-01-29 02:14:44 +00003075 }
3076
sewardj112b0992005-07-23 13:19:32 +00003077 else
sewardj118b23e2005-01-29 02:14:44 +00003078 if (isShift) {
3079
3080 IRTemp pre64 = newTemp(Ity_I64);
3081 IRTemp res64 = newTemp(Ity_I64);
3082 IRTemp res64ss = newTemp(Ity_I64);
3083 IRTemp shift_amt = newTemp(Ity_I8);
sewardj1027dc22005-02-26 01:55:02 +00003084 UChar mask = toUChar(sz==8 ? 63 : 31);
sewardj118b23e2005-01-29 02:14:44 +00003085 IROp op64;
3086
sewardj901ed122005-02-27 13:25:31 +00003087 switch (gregLO3ofRM(modrm)) {
sewardj118b23e2005-01-29 02:14:44 +00003088 case 4: op64 = Iop_Shl64; break;
3089 case 5: op64 = Iop_Shr64; break;
3090 case 7: op64 = Iop_Sar64; break;
3091 default: vpanic("dis_Grp2:shift"); break;
3092 }
3093
3094 /* Widen the value to be shifted to 64 bits, do the shift, and
3095 narrow back down. This seems surprisingly long-winded, but
3096 unfortunately the AMD semantics requires that 8/16/32-bit
3097 shifts give defined results for shift values all the way up
sewardj03c96e82005-02-19 18:12:45 +00003098 to 32, and this seems the simplest way to do it. It has the
sewardj118b23e2005-01-29 02:14:44 +00003099 advantage that the only IR level shifts generated are of 64
3100 bit values, and the shift amount is guaranteed to be in the
3101 range 0 .. 63, thereby observing the IR semantics requiring
sewardj03c96e82005-02-19 18:12:45 +00003102 all shift values to be in the range 0 .. 2^word_size-1.
sewardj118b23e2005-01-29 02:14:44 +00003103
sewardj03c96e82005-02-19 18:12:45 +00003104 Therefore the shift amount is masked with 63 for 64-bit shifts
3105 and 31 for all others.
3106 */
3107 /* shift_amt = shift_expr & MASK, regardless of operation size */
3108 assign( shift_amt, binop(Iop_And8, shift_expr, mkU8(mask)) );
sewardj118b23e2005-01-29 02:14:44 +00003109
sewardj03c96e82005-02-19 18:12:45 +00003110 /* suitably widen the value to be shifted to 64 bits. */
sewardj118b23e2005-01-29 02:14:44 +00003111 assign( pre64, op64==Iop_Sar64 ? widenSto64(mkexpr(dst0))
3112 : widenUto64(mkexpr(dst0)) );
3113
3114 /* res64 = pre64 `shift` shift_amt */
3115 assign( res64, binop(op64, mkexpr(pre64), mkexpr(shift_amt)) );
3116
sewardj03c96e82005-02-19 18:12:45 +00003117 /* res64ss = pre64 `shift` ((shift_amt - 1) & MASK) */
sewardj118b23e2005-01-29 02:14:44 +00003118 assign( res64ss,
3119 binop(op64,
3120 mkexpr(pre64),
3121 binop(Iop_And8,
3122 binop(Iop_Sub8,
3123 mkexpr(shift_amt), mkU8(1)),
sewardj03c96e82005-02-19 18:12:45 +00003124 mkU8(mask))) );
sewardj118b23e2005-01-29 02:14:44 +00003125
3126 /* Build the flags thunk. */
3127 setFlags_DEP1_DEP2_shift(op64, res64, res64ss, ty, shift_amt);
3128
3129 /* Narrow the result back down. */
3130 assign( dst1, narrowTo(ty, mkexpr(res64)) );
3131
3132 } /* if (isShift) */
3133
3134 else
3135 if (isRotate) {
3136 Int ccOp = ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1
3137 : (ty==Ity_I32 ? 2 : 3));
sewardj901ed122005-02-27 13:25:31 +00003138 Bool left = toBool(gregLO3ofRM(modrm) == 0);
sewardj118b23e2005-01-29 02:14:44 +00003139 IRTemp rot_amt = newTemp(Ity_I8);
3140 IRTemp rot_amt64 = newTemp(Ity_I8);
3141 IRTemp oldFlags = newTemp(Ity_I64);
sewardj1027dc22005-02-26 01:55:02 +00003142 UChar mask = toUChar(sz==8 ? 63 : 31);
sewardj118b23e2005-01-29 02:14:44 +00003143
3144 /* rot_amt = shift_expr & mask */
3145 /* By masking the rotate amount thusly, the IR-level Shl/Shr
3146 expressions never shift beyond the word size and thus remain
3147 well defined. */
sewardj03c96e82005-02-19 18:12:45 +00003148 assign(rot_amt64, binop(Iop_And8, shift_expr, mkU8(mask)));
sewardj118b23e2005-01-29 02:14:44 +00003149
3150 if (ty == Ity_I64)
3151 assign(rot_amt, mkexpr(rot_amt64));
3152 else
3153 assign(rot_amt, binop(Iop_And8, mkexpr(rot_amt64), mkU8(8*sz-1)));
3154
3155 if (left) {
3156
3157 /* dst1 = (dst0 << rot_amt) | (dst0 >>u (wordsize-rot_amt)) */
3158 assign(dst1,
3159 binop( mkSizedOp(ty,Iop_Or8),
3160 binop( mkSizedOp(ty,Iop_Shl8),
3161 mkexpr(dst0),
3162 mkexpr(rot_amt)
3163 ),
3164 binop( mkSizedOp(ty,Iop_Shr8),
3165 mkexpr(dst0),
3166 binop(Iop_Sub8,mkU8(8*sz), mkexpr(rot_amt))
3167 )
3168 )
3169 );
3170 ccOp += AMD64G_CC_OP_ROLB;
3171
3172 } else { /* right */
3173
3174 /* dst1 = (dst0 >>u rot_amt) | (dst0 << (wordsize-rot_amt)) */
3175 assign(dst1,
3176 binop( mkSizedOp(ty,Iop_Or8),
3177 binop( mkSizedOp(ty,Iop_Shr8),
3178 mkexpr(dst0),
3179 mkexpr(rot_amt)
3180 ),
3181 binop( mkSizedOp(ty,Iop_Shl8),
3182 mkexpr(dst0),
3183 binop(Iop_Sub8,mkU8(8*sz), mkexpr(rot_amt))
3184 )
3185 )
3186 );
3187 ccOp += AMD64G_CC_OP_RORB;
3188
3189 }
3190
3191 /* dst1 now holds the rotated value. Build flag thunk. We
3192 need the resulting value for this, and the previous flags.
3193 Except don't set it if the rotate count is zero. */
3194
3195 assign(oldFlags, mk_amd64g_calculate_rflags_all());
3196
3197 /* CC_DEP1 is the rotated value. CC_NDEP is flags before. */
3198 stmt( IRStmt_Put( OFFB_CC_OP,
3199 IRExpr_Mux0X( mkexpr(rot_amt64),
3200 IRExpr_Get(OFFB_CC_OP,Ity_I64),
3201 mkU64(ccOp))) );
3202 stmt( IRStmt_Put( OFFB_CC_DEP1,
3203 IRExpr_Mux0X( mkexpr(rot_amt64),
3204 IRExpr_Get(OFFB_CC_DEP1,Ity_I64),
3205 widenUto64(mkexpr(dst1)))) );
3206 stmt( IRStmt_Put( OFFB_CC_DEP2,
3207 IRExpr_Mux0X( mkexpr(rot_amt64),
3208 IRExpr_Get(OFFB_CC_DEP2,Ity_I64),
3209 mkU64(0))) );
3210 stmt( IRStmt_Put( OFFB_CC_NDEP,
3211 IRExpr_Mux0X( mkexpr(rot_amt64),
3212 IRExpr_Get(OFFB_CC_NDEP,Ity_I64),
3213 mkexpr(oldFlags))) );
3214 } /* if (isRotate) */
3215
3216 /* Save result, and finish up. */
3217 if (epartIsReg(modrm)) {
sewardj5b470602005-02-27 13:10:48 +00003218 putIRegE(sz, pfx, modrm, mkexpr(dst1));
sewardj118b23e2005-01-29 02:14:44 +00003219 if (vex_traceflags & VEX_TRACE_FE) {
3220 vex_printf("%s%c ",
sewardj901ed122005-02-27 13:25:31 +00003221 nameGrp2(gregLO3ofRM(modrm)), nameISize(sz) );
sewardj118b23e2005-01-29 02:14:44 +00003222 if (shift_expr_txt)
3223 vex_printf("%s", shift_expr_txt);
3224 else
3225 ppIRExpr(shift_expr);
sewardj5b470602005-02-27 13:10:48 +00003226 vex_printf(", %s\n", nameIRegE(sz,pfx,modrm));
sewardj118b23e2005-01-29 02:14:44 +00003227 }
3228 } else {
3229 storeLE(mkexpr(addr), mkexpr(dst1));
3230 if (vex_traceflags & VEX_TRACE_FE) {
3231 vex_printf("%s%c ",
sewardj901ed122005-02-27 13:25:31 +00003232 nameGrp2(gregLO3ofRM(modrm)), nameISize(sz) );
sewardj118b23e2005-01-29 02:14:44 +00003233 if (shift_expr_txt)
3234 vex_printf("%s", shift_expr_txt);
3235 else
3236 ppIRExpr(shift_expr);
3237 vex_printf(", %s\n", dis_buf);
3238 }
3239 }
3240 return delta;
3241}
3242
3243
sewardj1d511802005-03-27 17:59:45 +00003244/* Group 8 extended opcodes (but BT/BTS/BTC/BTR only). */
3245static
3246ULong dis_Grp8_Imm ( Prefix pfx,
sewardj270def42005-07-03 01:03:01 +00003247 Long delta, UChar modrm,
sewardj1d511802005-03-27 17:59:45 +00003248 Int am_sz, Int sz, ULong src_val,
3249 Bool* decode_OK )
3250{
3251 /* src_val denotes a d8.
3252 And delta on entry points at the modrm byte. */
sewardj118b23e2005-01-29 02:14:44 +00003253
sewardj1d511802005-03-27 17:59:45 +00003254 IRType ty = szToITy(sz);
3255 IRTemp t2 = newTemp(Ity_I64);
3256 IRTemp t2m = newTemp(Ity_I64);
3257 IRTemp t_addr = IRTemp_INVALID;
3258 HChar dis_buf[50];
3259 ULong mask;
sewardj9b967672005-02-08 11:13:09 +00003260
sewardj1d511802005-03-27 17:59:45 +00003261 /* we're optimists :-) */
3262 *decode_OK = True;
3263
3264 /* Limit src_val -- the bit offset -- to something within a word.
3265 The Intel docs say that literal offsets larger than a word are
3266 masked in this way. */
3267 switch (sz) {
3268 case 2: src_val &= 15; break;
3269 case 4: src_val &= 31; break;
sewardj537cab02005-04-07 02:03:52 +00003270 case 8: src_val &= 63; break;
sewardj1d511802005-03-27 17:59:45 +00003271 default: *decode_OK = False; return delta;
3272 }
3273
3274 /* Invent a mask suitable for the operation. */
3275 switch (gregLO3ofRM(modrm)) {
sewardj74b4f892005-05-06 01:43:56 +00003276 case 4: /* BT */ mask = 0; break;
3277 case 5: /* BTS */ mask = 1ULL << src_val; break;
3278 case 6: /* BTR */ mask = ~(1ULL << src_val); break;
3279 case 7: /* BTC */ mask = 1ULL << src_val; break;
sewardj1d511802005-03-27 17:59:45 +00003280 /* If this needs to be extended, probably simplest to make a
3281 new function to handle the other cases (0 .. 3). The
3282 Intel docs do however not indicate any use for 0 .. 3, so
3283 we don't expect this to happen. */
3284 default: *decode_OK = False; return delta;
3285 }
3286
3287 /* Fetch the value to be tested and modified into t2, which is
3288 64-bits wide regardless of sz. */
3289 if (epartIsReg(modrm)) {
3290 vassert(am_sz == 1);
3291 assign( t2, widenUto64(getIRegE(sz, pfx, modrm)) );
3292 delta += (am_sz + 1);
3293 DIP("%s%c $0x%llx, %s\n", nameGrp8(gregLO3ofRM(modrm)),
3294 nameISize(sz),
3295 src_val, nameIRegE(sz,pfx,modrm));
3296 } else {
3297 Int len;
3298 t_addr = disAMode ( &len, pfx, delta, dis_buf, 1 );
3299 delta += (len+1);
3300 assign( t2, widenUto64(loadLE(ty, mkexpr(t_addr))) );
3301 DIP("%s%c $0x%llx, %s\n", nameGrp8(gregLO3ofRM(modrm)),
3302 nameISize(sz),
3303 src_val, dis_buf);
3304 }
3305
3306 /* Copy relevant bit from t2 into the carry flag. */
3307 /* Flags: C=selected bit, O,S,Z,A,P undefined, so are set to zero. */
3308 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(AMD64G_CC_OP_COPY) ));
3309 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
3310 stmt( IRStmt_Put(
3311 OFFB_CC_DEP1,
3312 binop(Iop_And64,
3313 binop(Iop_Shr64, mkexpr(t2), mkU8(src_val)),
3314 mkU64(1))
3315 ));
3316
3317 /* Compute the new value into t2m, if non-BT. */
3318 switch (gregLO3ofRM(modrm)) {
3319 case 4: /* BT */
3320 break;
3321 case 5: /* BTS */
3322 assign( t2m, binop(Iop_Or64, mkU64(mask), mkexpr(t2)) );
3323 break;
3324 case 6: /* BTR */
3325 assign( t2m, binop(Iop_And64, mkU64(mask), mkexpr(t2)) );
3326 break;
3327 case 7: /* BTC */
3328 assign( t2m, binop(Iop_Xor64, mkU64(mask), mkexpr(t2)) );
3329 break;
3330 default:
3331 vassert(0);
3332 }
3333
3334 /* Write the result back, if non-BT. */
3335 if (gregLO3ofRM(modrm) != 4 /* BT */) {
3336 if (epartIsReg(modrm)) {
3337 putIRegE(sz, pfx, modrm, narrowTo(ty, mkexpr(t2m)));
3338 } else {
3339 storeLE(mkexpr(t_addr), narrowTo(ty, mkexpr(t2m)));
3340 }
3341 }
3342
3343 return delta;
3344}
sewardj9b967672005-02-08 11:13:09 +00003345
3346
3347/* Signed/unsigned widening multiply. Generate IR to multiply the
3348 value in RAX/EAX/AX/AL by the given IRTemp, and park the result in
3349 RDX:RAX/EDX:EAX/DX:AX/AX.
3350*/
3351static void codegen_mulL_A_D ( Int sz, Bool syned,
sewardj1027dc22005-02-26 01:55:02 +00003352 IRTemp tmp, HChar* tmp_txt )
sewardj9b967672005-02-08 11:13:09 +00003353{
3354 IRType ty = szToITy(sz);
3355 IRTemp t1 = newTemp(ty);
3356
sewardj5b470602005-02-27 13:10:48 +00003357 assign( t1, getIRegRAX(sz) );
sewardj9b967672005-02-08 11:13:09 +00003358
3359 switch (ty) {
3360 case Ity_I64: {
3361 IRTemp res128 = newTemp(Ity_I128);
3362 IRTemp resHi = newTemp(Ity_I64);
3363 IRTemp resLo = newTemp(Ity_I64);
3364 IROp mulOp = syned ? Iop_MullS64 : Iop_MullU64;
sewardj8bdb89a2005-05-05 21:46:50 +00003365 UInt tBaseOp = syned ? AMD64G_CC_OP_SMULB : AMD64G_CC_OP_UMULB;
sewardj9b967672005-02-08 11:13:09 +00003366 setFlags_MUL ( Ity_I64, t1, tmp, tBaseOp );
3367 assign( res128, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
3368 assign( resHi, unop(Iop_128HIto64,mkexpr(res128)));
3369 assign( resLo, unop(Iop_128to64,mkexpr(res128)));
sewardj5b470602005-02-27 13:10:48 +00003370 putIReg64(R_RDX, mkexpr(resHi));
3371 putIReg64(R_RAX, mkexpr(resLo));
sewardj9b967672005-02-08 11:13:09 +00003372 break;
3373 }
sewardj85520e42005-02-19 15:22:38 +00003374 case Ity_I32: {
3375 IRTemp res64 = newTemp(Ity_I64);
3376 IRTemp resHi = newTemp(Ity_I32);
3377 IRTemp resLo = newTemp(Ity_I32);
3378 IROp mulOp = syned ? Iop_MullS32 : Iop_MullU32;
3379 UInt tBaseOp = syned ? AMD64G_CC_OP_SMULB : AMD64G_CC_OP_UMULB;
3380 setFlags_MUL ( Ity_I32, t1, tmp, tBaseOp );
3381 assign( res64, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
3382 assign( resHi, unop(Iop_64HIto32,mkexpr(res64)));
3383 assign( resLo, unop(Iop_64to32,mkexpr(res64)));
sewardj5b470602005-02-27 13:10:48 +00003384 putIRegRDX(4, mkexpr(resHi));
3385 putIRegRAX(4, mkexpr(resLo));
sewardj85520e42005-02-19 15:22:38 +00003386 break;
3387 }
3388 case Ity_I16: {
3389 IRTemp res32 = newTemp(Ity_I32);
3390 IRTemp resHi = newTemp(Ity_I16);
3391 IRTemp resLo = newTemp(Ity_I16);
3392 IROp mulOp = syned ? Iop_MullS16 : Iop_MullU16;
3393 UInt tBaseOp = syned ? AMD64G_CC_OP_SMULB : AMD64G_CC_OP_UMULB;
3394 setFlags_MUL ( Ity_I16, t1, tmp, tBaseOp );
3395 assign( res32, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
3396 assign( resHi, unop(Iop_32HIto16,mkexpr(res32)));
3397 assign( resLo, unop(Iop_32to16,mkexpr(res32)));
sewardj5b470602005-02-27 13:10:48 +00003398 putIRegRDX(2, mkexpr(resHi));
3399 putIRegRAX(2, mkexpr(resLo));
sewardj85520e42005-02-19 15:22:38 +00003400 break;
3401 }
3402 case Ity_I8: {
3403 IRTemp res16 = newTemp(Ity_I16);
3404 IRTemp resHi = newTemp(Ity_I8);
3405 IRTemp resLo = newTemp(Ity_I8);
3406 IROp mulOp = syned ? Iop_MullS8 : Iop_MullU8;
3407 UInt tBaseOp = syned ? AMD64G_CC_OP_SMULB : AMD64G_CC_OP_UMULB;
3408 setFlags_MUL ( Ity_I8, t1, tmp, tBaseOp );
3409 assign( res16, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
3410 assign( resHi, unop(Iop_16HIto8,mkexpr(res16)));
3411 assign( resLo, unop(Iop_16to8,mkexpr(res16)));
sewardj5b470602005-02-27 13:10:48 +00003412 putIRegRAX(2, mkexpr(res16));
sewardj85520e42005-02-19 15:22:38 +00003413 break;
3414 }
sewardj9b967672005-02-08 11:13:09 +00003415 default:
sewardj85520e42005-02-19 15:22:38 +00003416 ppIRType(ty);
sewardj9b967672005-02-08 11:13:09 +00003417 vpanic("codegen_mulL_A_D(amd64)");
3418 }
3419 DIP("%s%c %s\n", syned ? "imul" : "mul", nameISize(sz), tmp_txt);
3420}
sewardj32b2bbe2005-01-28 00:50:10 +00003421
3422
3423/* Group 3 extended opcodes. */
3424static
sewardj270def42005-07-03 01:03:01 +00003425ULong dis_Grp3 ( Prefix pfx, Int sz, Long delta )
sewardj32b2bbe2005-01-28 00:50:10 +00003426{
sewardj227458e2005-01-31 19:04:50 +00003427 Long d64;
sewardj32b2bbe2005-01-28 00:50:10 +00003428 UChar modrm;
3429 HChar dis_buf[50];
3430 Int len;
3431 IRTemp addr;
3432 IRType ty = szToITy(sz);
3433 IRTemp t1 = newTemp(ty);
sewardj55dbb262005-01-28 16:36:51 +00003434 IRTemp dst1, src, dst0;
sewardj8c332e22005-01-28 01:36:56 +00003435 modrm = getUChar(delta);
sewardj32b2bbe2005-01-28 00:50:10 +00003436 if (epartIsReg(modrm)) {
sewardj901ed122005-02-27 13:25:31 +00003437 switch (gregLO3ofRM(modrm)) {
sewardj118b23e2005-01-29 02:14:44 +00003438 case 0: { /* TEST */
3439 delta++;
3440 d64 = getSDisp(imin(4,sz), delta);
3441 delta += imin(4,sz);
3442 dst1 = newTemp(ty);
3443 assign(dst1, binop(mkSizedOp(ty,Iop_And8),
sewardj5b470602005-02-27 13:10:48 +00003444 getIRegE(sz,pfx,modrm),
sewardj03b07cc2005-01-31 18:09:43 +00003445 mkU(ty, d64 & mkSizeMask(sz))));
sewardj118b23e2005-01-29 02:14:44 +00003446 setFlags_DEP1( Iop_And8, dst1, ty );
sewardj7eaa7cf2005-01-31 18:55:22 +00003447 DIP("test%c $%lld, %s\n",
sewardj118b23e2005-01-29 02:14:44 +00003448 nameISize(sz), d64,
sewardj5b470602005-02-27 13:10:48 +00003449 nameIRegE(sz, pfx, modrm));
sewardj118b23e2005-01-29 02:14:44 +00003450 break;
3451 }
sewardj55dbb262005-01-28 16:36:51 +00003452 case 2: /* NOT */
3453 delta++;
sewardj5b470602005-02-27 13:10:48 +00003454 putIRegE(sz, pfx, modrm,
3455 unop(mkSizedOp(ty,Iop_Not8),
3456 getIRegE(sz, pfx, modrm)));
sewardj55dbb262005-01-28 16:36:51 +00003457 DIP("not%c %s\n", nameISize(sz),
sewardj5b470602005-02-27 13:10:48 +00003458 nameIRegE(sz, pfx, modrm));
sewardj55dbb262005-01-28 16:36:51 +00003459 break;
3460 case 3: /* NEG */
3461 delta++;
3462 dst0 = newTemp(ty);
3463 src = newTemp(ty);
3464 dst1 = newTemp(ty);
3465 assign(dst0, mkU(ty,0));
sewardj5b470602005-02-27 13:10:48 +00003466 assign(src, getIRegE(sz, pfx, modrm));
sewardj55dbb262005-01-28 16:36:51 +00003467 assign(dst1, binop(mkSizedOp(ty,Iop_Sub8), mkexpr(dst0), mkexpr(src)));
3468 setFlags_DEP1_DEP2(Iop_Sub8, dst0, src, ty);
sewardj5b470602005-02-27 13:10:48 +00003469 putIRegE(sz, pfx, modrm, mkexpr(dst1));
3470 DIP("neg%c %s\n", nameISize(sz), nameIRegE(sz, pfx, modrm));
sewardj55dbb262005-01-28 16:36:51 +00003471 break;
sewardj9b967672005-02-08 11:13:09 +00003472 case 4: /* MUL (unsigned widening) */
3473 delta++;
3474 src = newTemp(ty);
sewardj5b470602005-02-27 13:10:48 +00003475 assign(src, getIRegE(sz,pfx,modrm));
sewardj9b967672005-02-08 11:13:09 +00003476 codegen_mulL_A_D ( sz, False, src,
sewardj5b470602005-02-27 13:10:48 +00003477 nameIRegE(sz,pfx,modrm) );
sewardj9b967672005-02-08 11:13:09 +00003478 break;
sewardj85520e42005-02-19 15:22:38 +00003479 case 5: /* IMUL (signed widening) */
3480 delta++;
3481 src = newTemp(ty);
sewardj5b470602005-02-27 13:10:48 +00003482 assign(src, getIRegE(sz,pfx,modrm));
sewardj85520e42005-02-19 15:22:38 +00003483 codegen_mulL_A_D ( sz, True, src,
sewardj5b470602005-02-27 13:10:48 +00003484 nameIRegE(sz,pfx,modrm) );
sewardj85520e42005-02-19 15:22:38 +00003485 break;
sewardj03b07cc2005-01-31 18:09:43 +00003486 case 6: /* DIV */
3487 delta++;
sewardj5b470602005-02-27 13:10:48 +00003488 assign( t1, getIRegE(sz, pfx, modrm) );
sewardj03b07cc2005-01-31 18:09:43 +00003489 codegen_div ( sz, t1, False );
3490 DIP("div%c %s\n", nameISize(sz),
sewardj5b470602005-02-27 13:10:48 +00003491 nameIRegE(sz, pfx, modrm));
sewardj03b07cc2005-01-31 18:09:43 +00003492 break;
sewardj32b2bbe2005-01-28 00:50:10 +00003493 case 7: /* IDIV */
3494 delta++;
sewardj5b470602005-02-27 13:10:48 +00003495 assign( t1, getIRegE(sz, pfx, modrm) );
sewardj32b2bbe2005-01-28 00:50:10 +00003496 codegen_div ( sz, t1, True );
3497 DIP("idiv%c %s\n", nameISize(sz),
sewardj5b470602005-02-27 13:10:48 +00003498 nameIRegE(sz, pfx, modrm));
sewardj32b2bbe2005-01-28 00:50:10 +00003499 break;
3500 default:
3501 vex_printf(
sewardj901ed122005-02-27 13:25:31 +00003502 "unhandled Grp3(R) case %d\n", (Int)gregLO3ofRM(modrm));
sewardj32b2bbe2005-01-28 00:50:10 +00003503 vpanic("Grp3(amd64)");
3504 }
3505 } else {
sewardj7de0d3c2005-02-13 02:26:41 +00003506 addr = disAMode ( &len, pfx, delta, dis_buf,
3507 /* we have to inform disAMode of any immediate
3508 bytes used */
sewardj901ed122005-02-27 13:25:31 +00003509 gregLO3ofRM(modrm)==0/*TEST*/
sewardj7de0d3c2005-02-13 02:26:41 +00003510 ? imin(4,sz)
3511 : 0
3512 );
sewardj32b2bbe2005-01-28 00:50:10 +00003513 t1 = newTemp(ty);
3514 delta += len;
3515 assign(t1, loadLE(ty,mkexpr(addr)));
sewardj901ed122005-02-27 13:25:31 +00003516 switch (gregLO3ofRM(modrm)) {
sewardj03b07cc2005-01-31 18:09:43 +00003517 case 0: { /* TEST */
3518 d64 = getSDisp(imin(4,sz), delta);
3519 delta += imin(4,sz);
3520 dst1 = newTemp(ty);
3521 assign(dst1, binop(mkSizedOp(ty,Iop_And8),
3522 mkexpr(t1),
3523 mkU(ty, d64 & mkSizeMask(sz))));
3524 setFlags_DEP1( Iop_And8, dst1, ty );
3525 DIP("test%c $%lld, %s\n", nameISize(sz), d64, dis_buf);
3526 break;
3527 }
sewardj82c9f2f2005-03-02 16:05:13 +00003528 /* probably OK, but awaiting test case */
3529 case 2: /* NOT */
3530 storeLE( mkexpr(addr), unop(mkSizedOp(ty,Iop_Not8), mkexpr(t1)));
3531 DIP("not%c %s\n", nameISize(sz), dis_buf);
3532 break;
sewardj7de0d3c2005-02-13 02:26:41 +00003533 case 3: /* NEG */
3534 dst0 = newTemp(ty);
3535 src = newTemp(ty);
3536 dst1 = newTemp(ty);
3537 assign(dst0, mkU(ty,0));
3538 assign(src, mkexpr(t1));
3539 assign(dst1, binop(mkSizedOp(ty,Iop_Sub8), mkexpr(dst0), mkexpr(src)));
3540 setFlags_DEP1_DEP2(Iop_Sub8, dst0, src, ty);
3541 storeLE( mkexpr(addr), mkexpr(dst1) );
3542 DIP("neg%c %s\n", nameISize(sz), dis_buf);
3543 break;
sewardj31eecde2005-03-23 03:39:55 +00003544 case 4: /* MUL (unsigned widening) */
3545 codegen_mulL_A_D ( sz, False, t1, dis_buf );
3546 break;
sewardj3aba9eb2005-03-30 23:20:47 +00003547 case 5: /* IMUL */
3548 codegen_mulL_A_D ( sz, True, t1, dis_buf );
3549 break;
sewardj1001dc42005-02-21 08:25:55 +00003550 case 6: /* DIV */
3551 codegen_div ( sz, t1, False );
3552 DIP("div%c %s\n", nameISize(sz), dis_buf);
3553 break;
sewardj82c9f2f2005-03-02 16:05:13 +00003554 case 7: /* IDIV */
3555 codegen_div ( sz, t1, True );
3556 DIP("idiv%c %s\n", nameISize(sz), dis_buf);
3557 break;
sewardj32b2bbe2005-01-28 00:50:10 +00003558 default:
3559 vex_printf(
sewardj901ed122005-02-27 13:25:31 +00003560 "unhandled Grp3(M) case %d\n", (Int)gregLO3ofRM(modrm));
sewardj32b2bbe2005-01-28 00:50:10 +00003561 vpanic("Grp3(amd64)");
3562 }
3563 }
3564 return delta;
3565}
3566
3567
sewardj03b07cc2005-01-31 18:09:43 +00003568/* Group 4 extended opcodes. */
3569static
sewardj270def42005-07-03 01:03:01 +00003570ULong dis_Grp4 ( Prefix pfx, Long delta )
sewardj03b07cc2005-01-31 18:09:43 +00003571{
3572 Int alen;
3573 UChar modrm;
3574 HChar dis_buf[50];
3575 IRType ty = Ity_I8;
3576 IRTemp t1 = newTemp(ty);
3577 IRTemp t2 = newTemp(ty);
3578
3579 modrm = getUChar(delta);
3580 if (epartIsReg(modrm)) {
sewardj5b470602005-02-27 13:10:48 +00003581 assign(t1, getIRegE(1, pfx, modrm));
sewardj901ed122005-02-27 13:25:31 +00003582 switch (gregLO3ofRM(modrm)) {
sewardj85520e42005-02-19 15:22:38 +00003583 case 0: /* INC */
3584 assign(t2, binop(Iop_Add8, mkexpr(t1), mkU8(1)));
sewardj5b470602005-02-27 13:10:48 +00003585 putIRegE(1, pfx, modrm, mkexpr(t2));
sewardj85520e42005-02-19 15:22:38 +00003586 setFlags_INC_DEC( True, t2, ty );
3587 break;
sewardj03b07cc2005-01-31 18:09:43 +00003588 case 1: /* DEC */
3589 assign(t2, binop(Iop_Sub8, mkexpr(t1), mkU8(1)));
sewardj5b470602005-02-27 13:10:48 +00003590 putIRegE(1, pfx, modrm, mkexpr(t2));
sewardj03b07cc2005-01-31 18:09:43 +00003591 setFlags_INC_DEC( False, t2, ty );
3592 break;
3593 default:
3594 vex_printf(
sewardj901ed122005-02-27 13:25:31 +00003595 "unhandled Grp4(R) case %d\n", (Int)gregLO3ofRM(modrm));
sewardj03b07cc2005-01-31 18:09:43 +00003596 vpanic("Grp4(amd64,R)");
3597 }
3598 delta++;
sewardj901ed122005-02-27 13:25:31 +00003599 DIP("%sb %s\n", nameGrp4(gregLO3ofRM(modrm)),
sewardj5b470602005-02-27 13:10:48 +00003600 nameIRegE(1, pfx, modrm));
sewardj03b07cc2005-01-31 18:09:43 +00003601 } else {
sewardje1698952005-02-08 15:02:39 +00003602 IRTemp addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
sewardj03b07cc2005-01-31 18:09:43 +00003603 assign( t1, loadLE(ty, mkexpr(addr)) );
sewardj901ed122005-02-27 13:25:31 +00003604 switch (gregLO3ofRM(modrm)) {
sewardj007e9ec2005-03-23 11:36:48 +00003605 case 0: /* INC */
3606 assign(t2, binop(Iop_Add8, mkexpr(t1), mkU8(1)));
3607 storeLE( mkexpr(addr), mkexpr(t2) );
3608 setFlags_INC_DEC( True, t2, ty );
3609 break;
3610 case 1: /* DEC */
3611 assign(t2, binop(Iop_Sub8, mkexpr(t1), mkU8(1)));
3612 storeLE( mkexpr(addr), mkexpr(t2) );
3613 setFlags_INC_DEC( False, t2, ty );
3614 break;
sewardj03b07cc2005-01-31 18:09:43 +00003615 default:
3616 vex_printf(
sewardj901ed122005-02-27 13:25:31 +00003617 "unhandled Grp4(M) case %d\n", (Int)gregLO3ofRM(modrm));
sewardj03b07cc2005-01-31 18:09:43 +00003618 vpanic("Grp4(amd64,M)");
3619 }
3620 delta += alen;
sewardj901ed122005-02-27 13:25:31 +00003621 DIP("%sb %s\n", nameGrp4(gregLO3ofRM(modrm)), dis_buf);
sewardj03b07cc2005-01-31 18:09:43 +00003622 }
3623 return delta;
3624}
sewardj354e5c62005-01-27 20:12:52 +00003625
3626
3627/* Group 5 extended opcodes. */
3628static
sewardj270def42005-07-03 01:03:01 +00003629ULong dis_Grp5 ( Prefix pfx, Int sz, Long delta, DisResult* dres )
sewardj354e5c62005-01-27 20:12:52 +00003630{
3631 Int len;
3632 UChar modrm;
3633 HChar dis_buf[50];
3634 IRTemp addr = IRTemp_INVALID;
3635 IRType ty = szToITy(sz);
3636 IRTemp t1 = newTemp(ty);
3637 IRTemp t2 = IRTemp_INVALID;
sewardj03b07cc2005-01-31 18:09:43 +00003638 IRTemp t3 = IRTemp_INVALID;
sewardj7eaa7cf2005-01-31 18:55:22 +00003639 Bool showSz = True;
sewardj354e5c62005-01-27 20:12:52 +00003640
sewardj8c332e22005-01-28 01:36:56 +00003641 modrm = getUChar(delta);
sewardj354e5c62005-01-27 20:12:52 +00003642 if (epartIsReg(modrm)) {
sewardj5b470602005-02-27 13:10:48 +00003643 assign(t1, getIRegE(sz,pfx,modrm));
sewardj901ed122005-02-27 13:25:31 +00003644 switch (gregLO3ofRM(modrm)) {
sewardj32b2bbe2005-01-28 00:50:10 +00003645 case 0: /* INC */
3646 t2 = newTemp(ty);
3647 assign(t2, binop(mkSizedOp(ty,Iop_Add8),
3648 mkexpr(t1), mkU(ty,1)));
3649 setFlags_INC_DEC( True, t2, ty );
sewardj5b470602005-02-27 13:10:48 +00003650 putIRegE(sz,pfx,modrm, mkexpr(t2));
sewardj32b2bbe2005-01-28 00:50:10 +00003651 break;
3652 case 1: /* DEC */
3653 t2 = newTemp(ty);
3654 assign(t2, binop(mkSizedOp(ty,Iop_Sub8),
3655 mkexpr(t1), mkU(ty,1)));
3656 setFlags_INC_DEC( False, t2, ty );
sewardj5b470602005-02-27 13:10:48 +00003657 putIRegE(sz,pfx,modrm, mkexpr(t2));
sewardj32b2bbe2005-01-28 00:50:10 +00003658 break;
sewardj354e5c62005-01-27 20:12:52 +00003659 case 2: /* call Ev */
sewardj03b07cc2005-01-31 18:09:43 +00003660 /* Ignore any sz value and operate as if sz==8. */
sewardjb7bcdf92005-08-02 21:20:36 +00003661 vassert(sz == 4 || sz == 8);
sewardj03b07cc2005-01-31 18:09:43 +00003662 sz = 8;
3663 t3 = newTemp(Ity_I64);
sewardj5b470602005-02-27 13:10:48 +00003664 assign(t3, getIRegE(sz,pfx,modrm));
sewardj03b07cc2005-01-31 18:09:43 +00003665 t2 = newTemp(Ity_I64);
3666 assign(t2, binop(Iop_Sub64, getIReg64(R_RSP), mkU64(8)));
3667 putIReg64(R_RSP, mkexpr(t2));
sewardj9e6491a2005-07-02 19:24:10 +00003668 storeLE( mkexpr(t2), mkU64(guest_RIP_bbstart+delta+1));
sewardj5a9ffab2005-05-12 17:55:01 +00003669 make_redzone_AbiHint(t2, "call-Ev(reg)");
sewardj03b07cc2005-01-31 18:09:43 +00003670 jmp_treg(Ijk_Call,t3);
sewardj9e6491a2005-07-02 19:24:10 +00003671 dres->whatNext = Dis_StopHere;
sewardj7eaa7cf2005-01-31 18:55:22 +00003672 showSz = False;
sewardj354e5c62005-01-27 20:12:52 +00003673 break;
sewardj354e5c62005-01-27 20:12:52 +00003674 case 4: /* jmp Ev */
sewardj03b07cc2005-01-31 18:09:43 +00003675 /* Ignore any sz value and operate as if sz==8. */
sewardj0bfc6b62005-07-07 14:15:35 +00003676 vassert(sz == 4 || sz == 8);
sewardj03b07cc2005-01-31 18:09:43 +00003677 sz = 8;
3678 t3 = newTemp(Ity_I64);
sewardj5b470602005-02-27 13:10:48 +00003679 assign(t3, getIRegE(sz,pfx,modrm));
sewardj03b07cc2005-01-31 18:09:43 +00003680 jmp_treg(Ijk_Boring,t3);
sewardj9e6491a2005-07-02 19:24:10 +00003681 dres->whatNext = Dis_StopHere;
sewardj7eaa7cf2005-01-31 18:55:22 +00003682 showSz = False;
sewardj354e5c62005-01-27 20:12:52 +00003683 break;
sewardj354e5c62005-01-27 20:12:52 +00003684 default:
3685 vex_printf(
sewardj901ed122005-02-27 13:25:31 +00003686 "unhandled Grp5(R) case %d\n", (Int)gregLO3ofRM(modrm));
sewardj354e5c62005-01-27 20:12:52 +00003687 vpanic("Grp5(amd64)");
3688 }
3689 delta++;
sewardj901ed122005-02-27 13:25:31 +00003690 DIP("%s%c %s\n", nameGrp5(gregLO3ofRM(modrm)),
sewardj7eaa7cf2005-01-31 18:55:22 +00003691 showSz ? nameISize(sz) : ' ',
sewardj5b470602005-02-27 13:10:48 +00003692 nameIRegE(sz, pfx, modrm));
sewardj354e5c62005-01-27 20:12:52 +00003693 } else {
sewardje1698952005-02-08 15:02:39 +00003694 addr = disAMode ( &len, pfx, delta, dis_buf, 0 );
sewardj901ed122005-02-27 13:25:31 +00003695 if (gregLO3ofRM(modrm) != 2 && gregLO3ofRM(modrm) != 4
3696 && gregLO3ofRM(modrm) != 6) {
sewardj03b07cc2005-01-31 18:09:43 +00003697 assign(t1, loadLE(ty,mkexpr(addr)));
sewardj909c06d2005-02-19 22:47:41 +00003698 }
sewardj901ed122005-02-27 13:25:31 +00003699 switch (gregLO3ofRM(modrm)) {
sewardj354e5c62005-01-27 20:12:52 +00003700 case 0: /* INC */
sewardj354e5c62005-01-27 20:12:52 +00003701 t2 = newTemp(ty);
3702 assign(t2, binop(mkSizedOp(ty,Iop_Add8),
3703 mkexpr(t1), mkU(ty,1)));
3704 setFlags_INC_DEC( True, t2, ty );
3705 storeLE(mkexpr(addr),mkexpr(t2));
3706 break;
sewardj354e5c62005-01-27 20:12:52 +00003707 case 1: /* DEC */
3708 t2 = newTemp(ty);
3709 assign(t2, binop(mkSizedOp(ty,Iop_Sub8),
3710 mkexpr(t1), mkU(ty,1)));
3711 setFlags_INC_DEC( False, t2, ty );
3712 storeLE(mkexpr(addr),mkexpr(t2));
3713 break;
3714 case 2: /* call Ev */
sewardj03b07cc2005-01-31 18:09:43 +00003715 /* Ignore any sz value and operate as if sz==8. */
sewardj354e5c62005-01-27 20:12:52 +00003716 vassert(sz == 4);
sewardj7eaa7cf2005-01-31 18:55:22 +00003717 sz = 8;
sewardj03b07cc2005-01-31 18:09:43 +00003718 t3 = newTemp(Ity_I64);
3719 assign(t3, loadLE(Ity_I64,mkexpr(addr)));
3720 t2 = newTemp(Ity_I64);
3721 assign(t2, binop(Iop_Sub64, getIReg64(R_RSP), mkU64(8)));
3722 putIReg64(R_RSP, mkexpr(t2));
sewardj9e6491a2005-07-02 19:24:10 +00003723 storeLE( mkexpr(t2), mkU64(guest_RIP_bbstart+delta+len));
sewardj5a9ffab2005-05-12 17:55:01 +00003724 make_redzone_AbiHint(t2, "call-Ev(mem)");
sewardj03b07cc2005-01-31 18:09:43 +00003725 jmp_treg(Ijk_Call,t3);
sewardj9e6491a2005-07-02 19:24:10 +00003726 dres->whatNext = Dis_StopHere;
sewardj7eaa7cf2005-01-31 18:55:22 +00003727 showSz = False;
sewardj354e5c62005-01-27 20:12:52 +00003728 break;
sewardj354e5c62005-01-27 20:12:52 +00003729 case 4: /* JMP Ev */
sewardj03b07cc2005-01-31 18:09:43 +00003730 /* Ignore any sz value and operate as if sz==8. */
sewardj354e5c62005-01-27 20:12:52 +00003731 vassert(sz == 4);
sewardj7eaa7cf2005-01-31 18:55:22 +00003732 sz = 8;
sewardj03b07cc2005-01-31 18:09:43 +00003733 t3 = newTemp(Ity_I64);
3734 assign(t3, loadLE(Ity_I64,mkexpr(addr)));
3735 jmp_treg(Ijk_Boring,t3);
sewardj9e6491a2005-07-02 19:24:10 +00003736 dres->whatNext = Dis_StopHere;
sewardj7eaa7cf2005-01-31 18:55:22 +00003737 showSz = False;
sewardj354e5c62005-01-27 20:12:52 +00003738 break;
sewardj354e5c62005-01-27 20:12:52 +00003739 case 6: /* PUSH Ev */
sewardja6b93d12005-02-17 09:28:28 +00003740 /* There is no encoding for 32-bit operand size; hence ... */
3741 if (sz == 4) sz = 8;
3742 vassert(sz == 8 || sz == 2);
sewardj909c06d2005-02-19 22:47:41 +00003743 if (sz == 8) {
3744 t3 = newTemp(Ity_I64);
3745 assign(t3, loadLE(Ity_I64,mkexpr(addr)));
3746 t2 = newTemp(Ity_I64);
3747 assign( t2, binop(Iop_Sub64,getIReg64(R_RSP),mkU64(sz)) );
3748 putIReg64(R_RSP, mkexpr(t2) );
3749 storeLE( mkexpr(t2), mkexpr(t3) );
3750 break;
3751 } else {
3752 goto unhandled; /* awaiting test case */
3753 }
sewardj354e5c62005-01-27 20:12:52 +00003754 default:
sewardja6b93d12005-02-17 09:28:28 +00003755 unhandled:
sewardj354e5c62005-01-27 20:12:52 +00003756 vex_printf(
sewardj901ed122005-02-27 13:25:31 +00003757 "unhandled Grp5(M) case %d\n", (Int)gregLO3ofRM(modrm));
sewardj354e5c62005-01-27 20:12:52 +00003758 vpanic("Grp5(amd64)");
3759 }
3760 delta += len;
sewardj901ed122005-02-27 13:25:31 +00003761 DIP("%s%c %s\n", nameGrp5(gregLO3ofRM(modrm)),
sewardj7eaa7cf2005-01-31 18:55:22 +00003762 showSz ? nameISize(sz) : ' ',
3763 dis_buf);
sewardj354e5c62005-01-27 20:12:52 +00003764 }
3765 return delta;
3766}
3767
3768
sewardjd0a12df2005-02-10 02:07:43 +00003769/*------------------------------------------------------------*/
3770/*--- Disassembling string ops (including REP prefixes) ---*/
3771/*------------------------------------------------------------*/
3772
3773/* Code shared by all the string ops */
3774static
3775void dis_string_op_increment ( Int sz, IRTemp t_inc )
3776{
3777 UChar logSz;
3778 if (sz == 8 || sz == 4 || sz == 2) {
3779 logSz = 1;
3780 if (sz == 4) logSz = 2;
3781 if (sz == 8) logSz = 3;
3782 assign( t_inc,
3783 binop(Iop_Shl64, IRExpr_Get( OFFB_DFLAG, Ity_I64 ),
3784 mkU8(logSz) ) );
3785 } else {
3786 assign( t_inc,
3787 IRExpr_Get( OFFB_DFLAG, Ity_I64 ) );
3788 }
3789}
3790
sewardj909c06d2005-02-19 22:47:41 +00003791static
3792void dis_string_op( void (*dis_OP)( Int, IRTemp ),
3793 Int sz, HChar* name, Prefix pfx )
3794{
3795 IRTemp t_inc = newTemp(Ity_I64);
3796 /* Really we ought to inspect the override prefixes, but we don't.
3797 The following assertion catches any resulting sillyness. */
3798 vassert(pfx == clearSegBits(pfx));
3799 dis_string_op_increment(sz, t_inc);
3800 dis_OP( sz, t_inc );
3801 DIP("%s%c\n", name, nameISize(sz));
3802}
3803
3804static
3805void dis_MOVS ( Int sz, IRTemp t_inc )
3806{
3807 IRType ty = szToITy(sz);
3808 IRTemp td = newTemp(Ity_I64); /* RDI */
3809 IRTemp ts = newTemp(Ity_I64); /* RSI */
3810
3811 assign( td, getIReg64(R_RDI) );
3812 assign( ts, getIReg64(R_RSI) );
3813
3814 storeLE( mkexpr(td), loadLE(ty,mkexpr(ts)) );
3815
3816 putIReg64( R_RDI, binop(Iop_Add64, mkexpr(td), mkexpr(t_inc)) );
3817 putIReg64( R_RSI, binop(Iop_Add64, mkexpr(ts), mkexpr(t_inc)) );
3818}
3819
sewardjd20c8852005-01-20 20:04:07 +00003820//.. //-- static
3821//.. //-- void dis_LODS ( UCodeBlock* cb, Int sz, Int t_inc )
3822//.. //-- {
3823//.. //-- Int ta = newTemp(cb); /* EAX */
3824//.. //-- Int ts = newTemp(cb); /* ESI */
3825//.. //--
3826//.. //-- uInstr2(cb, GET, 4, ArchReg, R_ESI, TempReg, ts);
3827//.. //-- uInstr2(cb, LOAD, sz, TempReg, ts, TempReg, ta);
3828//.. //-- uInstr2(cb, PUT, sz, TempReg, ta, ArchReg, R_EAX);
3829//.. //--
3830//.. //-- uInstr2(cb, ADD, 4, TempReg, t_inc, TempReg, ts);
3831//.. //-- uInstr2(cb, PUT, 4, TempReg, ts, ArchReg, R_ESI);
3832//.. //-- }
sewardja6b93d12005-02-17 09:28:28 +00003833
3834static
3835void dis_STOS ( Int sz, IRTemp t_inc )
3836{
3837 IRType ty = szToITy(sz);
3838 IRTemp ta = newTemp(ty); /* rAX */
3839 IRTemp td = newTemp(Ity_I64); /* RDI */
3840
sewardj5b470602005-02-27 13:10:48 +00003841 assign( ta, getIRegRAX(sz) );
sewardja6b93d12005-02-17 09:28:28 +00003842
3843 assign( td, getIReg64(R_RDI) );
3844
3845 storeLE( mkexpr(td), mkexpr(ta) );
3846
3847 putIReg64( R_RDI, binop(Iop_Add64, mkexpr(td), mkexpr(t_inc)) );
3848}
sewardjd0a12df2005-02-10 02:07:43 +00003849
3850static
3851void dis_CMPS ( Int sz, IRTemp t_inc )
3852{
3853 IRType ty = szToITy(sz);
3854 IRTemp tdv = newTemp(ty); /* (RDI) */
3855 IRTemp tsv = newTemp(ty); /* (RSI) */
3856 IRTemp td = newTemp(Ity_I64); /* RDI */
3857 IRTemp ts = newTemp(Ity_I64); /* RSI */
3858
3859 assign( td, getIReg64(R_RDI) );
3860
3861 assign( ts, getIReg64(R_RSI) );
3862
3863 assign( tdv, loadLE(ty,mkexpr(td)) );
3864
3865 assign( tsv, loadLE(ty,mkexpr(ts)) );
3866
3867 setFlags_DEP1_DEP2 ( Iop_Sub8, tsv, tdv, ty );
3868
3869 putIReg64(R_RDI, binop(Iop_Add64, mkexpr(td), mkexpr(t_inc)) );
3870
3871 putIReg64(R_RSI, binop(Iop_Add64, mkexpr(ts), mkexpr(t_inc)) );
3872}
3873
sewardj85520e42005-02-19 15:22:38 +00003874static
3875void dis_SCAS ( Int sz, IRTemp t_inc )
3876{
3877 IRType ty = szToITy(sz);
3878 IRTemp ta = newTemp(ty); /* rAX */
3879 IRTemp td = newTemp(Ity_I64); /* RDI */
3880 IRTemp tdv = newTemp(ty); /* (RDI) */
3881
sewardj5b470602005-02-27 13:10:48 +00003882 assign( ta, getIRegRAX(sz) );
sewardj85520e42005-02-19 15:22:38 +00003883
3884 assign( td, getIReg64(R_RDI) );
3885
3886 assign( tdv, loadLE(ty,mkexpr(td)) );
3887
3888 setFlags_DEP1_DEP2 ( Iop_Sub8, ta, tdv, ty );
3889
3890 putIReg64(R_RDI, binop(Iop_Add64, mkexpr(td), mkexpr(t_inc)) );
3891}
sewardjd0a12df2005-02-10 02:07:43 +00003892
3893
3894/* Wrap the appropriate string op inside a REP/REPE/REPNE. We assume
3895 the insn is the last one in the basic block, and so emit a jump to
3896 the next insn, rather than just falling through. */
3897static
3898void dis_REP_op ( AMD64Condcode cond,
3899 void (*dis_OP)(Int, IRTemp),
sewardj909c06d2005-02-19 22:47:41 +00003900 Int sz, Addr64 rip, Addr64 rip_next, HChar* name,
3901 Prefix pfx )
sewardjd0a12df2005-02-10 02:07:43 +00003902{
3903 IRTemp t_inc = newTemp(Ity_I64);
3904 IRTemp tc = newTemp(Ity_I64); /* RCX */
3905
sewardj909c06d2005-02-19 22:47:41 +00003906 /* Really we ought to inspect the override prefixes, but we don't.
3907 The following assertion catches any resulting sillyness. */
3908 vassert(pfx == clearSegBits(pfx));
3909
sewardjd0a12df2005-02-10 02:07:43 +00003910 assign( tc, getIReg64(R_RCX) );
3911
3912 stmt( IRStmt_Exit( binop(Iop_CmpEQ64,mkexpr(tc),mkU64(0)),
3913 Ijk_Boring,
3914 IRConst_U64(rip_next) ) );
3915
3916 putIReg64(R_RCX, binop(Iop_Sub64, mkexpr(tc), mkU64(1)) );
3917
3918 dis_string_op_increment(sz, t_inc);
3919 dis_OP (sz, t_inc);
3920
3921 if (cond == AMD64CondAlways) {
3922 jmp_lit(Ijk_Boring,rip);
3923 } else {
3924 stmt( IRStmt_Exit( mk_amd64g_calculate_condition(cond),
3925 Ijk_Boring,
3926 IRConst_U64(rip) ) );
3927 jmp_lit(Ijk_Boring,rip_next);
3928 }
3929 DIP("%s%c\n", name, nameISize(sz));
3930}
sewardj32b2bbe2005-01-28 00:50:10 +00003931
3932
3933/*------------------------------------------------------------*/
3934/*--- Arithmetic, etc. ---*/
3935/*------------------------------------------------------------*/
3936
3937/* IMUL E, G. Supplied eip points to the modR/M byte. */
3938static
3939ULong dis_mul_E_G ( Prefix pfx,
3940 Int size,
sewardj270def42005-07-03 01:03:01 +00003941 Long delta0 )
sewardj32b2bbe2005-01-28 00:50:10 +00003942{
3943 Int alen;
3944 HChar dis_buf[50];
sewardj8c332e22005-01-28 01:36:56 +00003945 UChar rm = getUChar(delta0);
sewardj32b2bbe2005-01-28 00:50:10 +00003946 IRType ty = szToITy(size);
3947 IRTemp te = newTemp(ty);
3948 IRTemp tg = newTemp(ty);
3949 IRTemp resLo = newTemp(ty);
3950
sewardj5b470602005-02-27 13:10:48 +00003951 assign( tg, getIRegG(size, pfx, rm) );
sewardj32b2bbe2005-01-28 00:50:10 +00003952 if (epartIsReg(rm)) {
sewardj5b470602005-02-27 13:10:48 +00003953 assign( te, getIRegE(size, pfx, rm) );
sewardj32b2bbe2005-01-28 00:50:10 +00003954 } else {
sewardje1698952005-02-08 15:02:39 +00003955 IRTemp addr = disAMode( &alen, pfx, delta0, dis_buf, 0 );
sewardj32b2bbe2005-01-28 00:50:10 +00003956 assign( te, loadLE(ty,mkexpr(addr)) );
3957 }
3958
3959 setFlags_MUL ( ty, te, tg, AMD64G_CC_OP_SMULB );
3960
3961 assign( resLo, binop( mkSizedOp(ty, Iop_Mul8), mkexpr(te), mkexpr(tg) ) );
3962
sewardj5b470602005-02-27 13:10:48 +00003963 putIRegG(size, pfx, rm, mkexpr(resLo) );
sewardj32b2bbe2005-01-28 00:50:10 +00003964
3965 if (epartIsReg(rm)) {
3966 DIP("imul%c %s, %s\n", nameISize(size),
sewardj901ed122005-02-27 13:25:31 +00003967 nameIRegE(size,pfx,rm),
3968 nameIRegG(size,pfx,rm));
sewardj32b2bbe2005-01-28 00:50:10 +00003969 return 1+delta0;
3970 } else {
3971 DIP("imul%c %s, %s\n", nameISize(size),
3972 dis_buf,
sewardj901ed122005-02-27 13:25:31 +00003973 nameIRegG(size,pfx,rm));
sewardj32b2bbe2005-01-28 00:50:10 +00003974 return alen+delta0;
3975 }
3976}
3977
3978
3979/* IMUL I * E -> G. Supplied rip points to the modR/M byte. */
3980static
3981ULong dis_imul_I_E_G ( Prefix pfx,
3982 Int size,
sewardj270def42005-07-03 01:03:01 +00003983 Long delta,
sewardj32b2bbe2005-01-28 00:50:10 +00003984 Int litsize )
3985{
3986 Long d64;
3987 Int alen;
3988 HChar dis_buf[50];
sewardj8c332e22005-01-28 01:36:56 +00003989 UChar rm = getUChar(delta);
sewardj32b2bbe2005-01-28 00:50:10 +00003990 IRType ty = szToITy(size);
3991 IRTemp te = newTemp(ty);
3992 IRTemp tl = newTemp(ty);
3993 IRTemp resLo = newTemp(ty);
3994
sewardj85520e42005-02-19 15:22:38 +00003995 vassert(/*size == 1 ||*/ size == 2 || size == 4 || size == 8);
sewardj32b2bbe2005-01-28 00:50:10 +00003996
3997 if (epartIsReg(rm)) {
sewardj5b470602005-02-27 13:10:48 +00003998 assign(te, getIRegE(size, pfx, rm));
sewardj32b2bbe2005-01-28 00:50:10 +00003999 delta++;
4000 } else {
sewardj7de0d3c2005-02-13 02:26:41 +00004001 IRTemp addr = disAMode( &alen, pfx, delta, dis_buf,
4002 imin(4,litsize) );
sewardj32b2bbe2005-01-28 00:50:10 +00004003 assign(te, loadLE(ty, mkexpr(addr)));
4004 delta += alen;
4005 }
4006 d64 = getSDisp(imin(4,litsize),delta);
4007 delta += imin(4,litsize);
4008
sewardj1389d4d2005-01-28 13:46:29 +00004009 d64 &= mkSizeMask(size);
sewardj32b2bbe2005-01-28 00:50:10 +00004010 assign(tl, mkU(ty,d64));
4011
4012 assign( resLo, binop( mkSizedOp(ty, Iop_Mul8), mkexpr(te), mkexpr(tl) ));
4013
4014 setFlags_MUL ( ty, te, tl, AMD64G_CC_OP_SMULB );
4015
sewardj5b470602005-02-27 13:10:48 +00004016 putIRegG(size, pfx, rm, mkexpr(resLo));
sewardj32b2bbe2005-01-28 00:50:10 +00004017
4018 DIP("imul%c $%lld, %s, %s\n",
4019 nameISize(size), d64,
sewardj5b470602005-02-27 13:10:48 +00004020 ( epartIsReg(rm) ? nameIRegE(size,pfx,rm) : dis_buf ),
4021 nameIRegG(size,pfx,rm) );
sewardj32b2bbe2005-01-28 00:50:10 +00004022 return delta;
4023}
4024
4025
sewardjbcbb9de2005-03-27 02:22:32 +00004026/*------------------------------------------------------------*/
4027/*--- ---*/
4028/*--- x87 FLOATING POINT INSTRUCTIONS ---*/
4029/*--- ---*/
4030/*------------------------------------------------------------*/
4031
4032/* --- Helper functions for dealing with the register stack. --- */
4033
4034/* --- Set the emulation-warning pseudo-register. --- */
4035
4036static void put_emwarn ( IRExpr* e /* :: Ity_I32 */ )
4037{
4038 vassert(typeOfIRExpr(irbb->tyenv, e) == Ity_I32);
4039 stmt( IRStmt_Put( OFFB_EMWARN, e ) );
4040}
sewardj8d965312005-02-25 02:48:47 +00004041
4042/* --- Produce an IRExpr* denoting a 64-bit QNaN. --- */
4043
4044static IRExpr* mkQNaN64 ( void )
4045{
4046 /* QNaN is 0 2047 1 0(51times)
4047 == 0b 11111111111b 1 0(51times)
4048 == 0x7FF8 0000 0000 0000
4049 */
4050 return IRExpr_Const(IRConst_F64i(0x7FF8000000000000ULL));
4051}
4052
4053/* --------- Get/put the top-of-stack pointer :: Ity_I32 --------- */
4054
4055static IRExpr* get_ftop ( void )
4056{
4057 return IRExpr_Get( OFFB_FTOP, Ity_I32 );
4058}
4059
4060static void put_ftop ( IRExpr* e )
4061{
4062 vassert(typeOfIRExpr(irbb->tyenv, e) == Ity_I32);
4063 stmt( IRStmt_Put( OFFB_FTOP, e ) );
4064}
4065
sewardj25a85812005-05-08 23:03:48 +00004066/* --------- Get/put the C3210 bits. --------- */
4067
4068static IRExpr* /* :: Ity_I64 */ get_C3210 ( void )
4069{
4070 return IRExpr_Get( OFFB_FC3210, Ity_I64 );
4071}
4072
4073static void put_C3210 ( IRExpr* e /* :: Ity_I64 */ )
4074{
4075 vassert(typeOfIRExpr(irbb->tyenv, e) == Ity_I64);
4076 stmt( IRStmt_Put( OFFB_FC3210, e ) );
4077}
sewardjc49ce232005-02-25 13:03:03 +00004078
4079/* --------- Get/put the FPU rounding mode. --------- */
4080static IRExpr* /* :: Ity_I32 */ get_fpround ( void )
4081{
4082 return unop(Iop_64to32, IRExpr_Get( OFFB_FPROUND, Ity_I64 ));
4083}
4084
sewardj5e205372005-05-09 02:57:08 +00004085static void put_fpround ( IRExpr* /* :: Ity_I32 */ e )
4086{
4087 vassert(typeOfIRExpr(irbb->tyenv, e) == Ity_I32);
4088 stmt( IRStmt_Put( OFFB_FPROUND, unop(Iop_32Uto64,e) ) );
4089}
sewardjc49ce232005-02-25 13:03:03 +00004090
4091
4092/* --------- Synthesise a 2-bit FPU rounding mode. --------- */
4093/* Produces a value in 0 .. 3, which is encoded as per the type
4094 IRRoundingMode. Since the guest_FPROUND value is also encoded as
4095 per IRRoundingMode, we merely need to get it and mask it for
4096 safety.
4097*/
4098static IRExpr* /* :: Ity_I32 */ get_roundingmode ( void )
4099{
4100 return binop( Iop_And32, get_fpround(), mkU32(3) );
4101}
sewardj8d965312005-02-25 02:48:47 +00004102
sewardj4796d662006-02-05 16:06:26 +00004103static IRExpr* /* :: Ity_I32 */ get_FAKE_roundingmode ( void )
4104{
4105 return mkU32(Irrm_NEAREST);
4106}
4107
sewardj8d965312005-02-25 02:48:47 +00004108
4109/* --------- Get/set FP register tag bytes. --------- */
4110
4111/* Given i, and some expression e, generate 'ST_TAG(i) = e'. */
4112
4113static void put_ST_TAG ( Int i, IRExpr* value )
4114{
4115 IRArray* descr;
4116 vassert(typeOfIRExpr(irbb->tyenv, value) == Ity_I8);
4117 descr = mkIRArray( OFFB_FPTAGS, Ity_I8, 8 );
4118 stmt( IRStmt_PutI( descr, get_ftop(), i, value ) );
4119}
4120
4121/* Given i, generate an expression yielding 'ST_TAG(i)'. This will be
4122 zero to indicate "Empty" and nonzero to indicate "NonEmpty". */
4123
4124static IRExpr* get_ST_TAG ( Int i )
4125{
4126 IRArray* descr = mkIRArray( OFFB_FPTAGS, Ity_I8, 8 );
4127 return IRExpr_GetI( descr, get_ftop(), i );
4128}
4129
4130
4131/* --------- Get/set FP registers. --------- */
4132
4133/* Given i, and some expression e, emit 'ST(i) = e' and set the
4134 register's tag to indicate the register is full. The previous
4135 state of the register is not checked. */
4136
4137static void put_ST_UNCHECKED ( Int i, IRExpr* value )
4138{
4139 IRArray* descr;
4140 vassert(typeOfIRExpr(irbb->tyenv, value) == Ity_F64);
4141 descr = mkIRArray( OFFB_FPREGS, Ity_F64, 8 );
4142 stmt( IRStmt_PutI( descr, get_ftop(), i, value ) );
4143 /* Mark the register as in-use. */
4144 put_ST_TAG(i, mkU8(1));
4145}
4146
4147/* Given i, and some expression e, emit
4148 ST(i) = is_full(i) ? NaN : e
4149 and set the tag accordingly.
4150*/
4151
4152static void put_ST ( Int i, IRExpr* value )
4153{
4154 put_ST_UNCHECKED( i,
4155 IRExpr_Mux0X( get_ST_TAG(i),
4156 /* 0 means empty */
4157 value,
4158 /* non-0 means full */
4159 mkQNaN64()
4160 )
4161 );
4162}
4163
4164
4165/* Given i, generate an expression yielding 'ST(i)'. */
4166
4167static IRExpr* get_ST_UNCHECKED ( Int i )
4168{
4169 IRArray* descr = mkIRArray( OFFB_FPREGS, Ity_F64, 8 );
4170 return IRExpr_GetI( descr, get_ftop(), i );
4171}
4172
4173
4174/* Given i, generate an expression yielding
4175 is_full(i) ? ST(i) : NaN
4176*/
4177
4178static IRExpr* get_ST ( Int i )
4179{
4180 return
4181 IRExpr_Mux0X( get_ST_TAG(i),
4182 /* 0 means empty */
4183 mkQNaN64(),
4184 /* non-0 means full */
4185 get_ST_UNCHECKED(i));
4186}
4187
4188
4189/* Adjust FTOP downwards by one register. */
4190
4191static void fp_push ( void )
4192{
4193 put_ftop( binop(Iop_Sub32, get_ftop(), mkU32(1)) );
4194}
4195
4196/* Adjust FTOP upwards by one register, and mark the vacated register
4197 as empty. */
4198
4199static void fp_pop ( void )
4200{
4201 put_ST_TAG(0, mkU8(0));
4202 put_ftop( binop(Iop_Add32, get_ftop(), mkU32(1)) );
4203}
4204
sewardj25a85812005-05-08 23:03:48 +00004205/* Clear the C2 bit of the FPU status register, for
4206 sin/cos/tan/sincos. */
4207
4208static void clear_C2 ( void )
4209{
4210 put_C3210( binop(Iop_And64, get_C3210(), mkU64(~AMD64G_FC_MASK_C2)) );
4211}
sewardj48a89d82005-05-06 11:50:13 +00004212
sewardj7c2d2822006-03-07 00:22:02 +00004213/* Invent a plausible-looking FPU status word value:
4214 ((ftop & 7) << 11) | (c3210 & 0x4700)
4215 */
4216static IRExpr* get_FPU_sw ( void )
4217{
4218 return
4219 unop(Iop_32to16,
4220 binop(Iop_Or32,
4221 binop(Iop_Shl32,
4222 binop(Iop_And32, get_ftop(), mkU32(7)),
4223 mkU8(11)),
4224 binop(Iop_And32, unop(Iop_64to32, get_C3210()),
4225 mkU32(0x4700))
4226 ));
4227}
4228
sewardj48a89d82005-05-06 11:50:13 +00004229
4230/* ------------------------------------------------------- */
4231/* Given all that stack-mangling junk, we can now go ahead
4232 and describe FP instructions.
4233*/
4234
4235/* ST(0) = ST(0) `op` mem64/32(addr)
4236 Need to check ST(0)'s tag on read, but not on write.
4237*/
4238static
sewardjca673ab2005-05-11 10:03:08 +00004239void fp_do_op_mem_ST_0 ( IRTemp addr, HChar* op_txt, HChar* dis_buf,
sewardj48a89d82005-05-06 11:50:13 +00004240 IROp op, Bool dbl )
4241{
4242 DIP("f%s%c %s\n", op_txt, dbl?'l':'s', dis_buf);
4243 if (dbl) {
4244 put_ST_UNCHECKED(0,
sewardj4796d662006-02-05 16:06:26 +00004245 triop( op,
4246 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardj48a89d82005-05-06 11:50:13 +00004247 get_ST(0),
4248 loadLE(Ity_F64,mkexpr(addr))
4249 ));
4250 } else {
4251 put_ST_UNCHECKED(0,
sewardj4796d662006-02-05 16:06:26 +00004252 triop( op,
4253 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardj48a89d82005-05-06 11:50:13 +00004254 get_ST(0),
4255 unop(Iop_F32toF64, loadLE(Ity_F32,mkexpr(addr)))
4256 ));
4257 }
4258}
sewardj7bc00082005-03-27 05:08:32 +00004259
4260
4261/* ST(0) = mem64/32(addr) `op` ST(0)
4262 Need to check ST(0)'s tag on read, but not on write.
4263*/
4264static
4265void fp_do_oprev_mem_ST_0 ( IRTemp addr, HChar* op_txt, HChar* dis_buf,
4266 IROp op, Bool dbl )
4267{
4268 DIP("f%s%c %s\n", op_txt, dbl?'l':'s', dis_buf);
4269 if (dbl) {
4270 put_ST_UNCHECKED(0,
sewardj4796d662006-02-05 16:06:26 +00004271 triop( op,
4272 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardj7bc00082005-03-27 05:08:32 +00004273 loadLE(Ity_F64,mkexpr(addr)),
4274 get_ST(0)
4275 ));
4276 } else {
4277 put_ST_UNCHECKED(0,
sewardj4796d662006-02-05 16:06:26 +00004278 triop( op,
4279 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardj7bc00082005-03-27 05:08:32 +00004280 unop(Iop_F32toF64, loadLE(Ity_F32,mkexpr(addr))),
4281 get_ST(0)
4282 ));
4283 }
4284}
sewardj37d52572005-02-25 14:22:12 +00004285
4286
4287/* ST(dst) = ST(dst) `op` ST(src).
4288 Check dst and src tags when reading but not on write.
4289*/
4290static
4291void fp_do_op_ST_ST ( HChar* op_txt, IROp op, UInt st_src, UInt st_dst,
4292 Bool pop_after )
4293{
sewardj1027dc22005-02-26 01:55:02 +00004294 DIP("f%s%s st(%u), st(%u)\n", op_txt, pop_after?"p":"", st_src, st_dst );
sewardj37d52572005-02-25 14:22:12 +00004295 put_ST_UNCHECKED(
4296 st_dst,
sewardj4796d662006-02-05 16:06:26 +00004297 triop( op,
4298 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4299 get_ST(st_dst),
4300 get_ST(st_src) )
sewardj37d52572005-02-25 14:22:12 +00004301 );
4302 if (pop_after)
4303 fp_pop();
4304}
4305
sewardj137015d2005-03-27 04:01:15 +00004306/* ST(dst) = ST(src) `op` ST(dst).
4307 Check dst and src tags when reading but not on write.
4308*/
4309static
4310void fp_do_oprev_ST_ST ( HChar* op_txt, IROp op, UInt st_src, UInt st_dst,
4311 Bool pop_after )
4312{
4313 DIP("f%s%s st(%u), st(%u)\n", op_txt, pop_after?"p":"", st_src, st_dst );
4314 put_ST_UNCHECKED(
4315 st_dst,
sewardj4796d662006-02-05 16:06:26 +00004316 triop( op,
4317 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4318 get_ST(st_src),
4319 get_ST(st_dst) )
sewardj137015d2005-03-27 04:01:15 +00004320 );
4321 if (pop_after)
4322 fp_pop();
4323}
sewardjc49ce232005-02-25 13:03:03 +00004324
4325/* %rflags(Z,P,C) = UCOMI( st(0), st(i) ) */
4326static void fp_do_ucomi_ST0_STi ( UInt i, Bool pop_after )
4327{
sewardj1027dc22005-02-26 01:55:02 +00004328 DIP("fucomi%s %%st(0),%%st(%u)\n", pop_after ? "p" : "", i);
sewardjc49ce232005-02-25 13:03:03 +00004329 /* This is a bit of a hack (and isn't really right). It sets
4330 Z,P,C,O correctly, but forces A and S to zero, whereas the Intel
4331 documentation implies A and S are unchanged.
4332 */
4333 /* It's also fishy in that it is used both for COMIP and
4334 UCOMIP, and they aren't the same (although similar). */
4335 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(AMD64G_CC_OP_COPY) ));
4336 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
4337 stmt( IRStmt_Put(
4338 OFFB_CC_DEP1,
4339 binop( Iop_And64,
4340 unop( Iop_32Uto64,
4341 binop(Iop_CmpF64, get_ST(0), get_ST(i))),
4342 mkU64(0x45)
4343 )));
4344 if (pop_after)
4345 fp_pop();
4346}
sewardj8d965312005-02-25 02:48:47 +00004347
4348
4349static
sewardjb4fd2e72005-03-23 13:34:11 +00004350ULong dis_FPU ( /*OUT*/Bool* decode_ok,
sewardj270def42005-07-03 01:03:01 +00004351 Prefix pfx, Long delta )
sewardj8d965312005-02-25 02:48:47 +00004352{
4353 Int len;
4354 UInt r_src, r_dst;
4355 HChar dis_buf[50];
4356 IRTemp t1, t2;
4357
4358 /* On entry, delta points at the second byte of the insn (the modrm
4359 byte).*/
4360 UChar first_opcode = getUChar(delta-1);
4361 UChar modrm = getUChar(delta+0);
4362
sewardj37d52572005-02-25 14:22:12 +00004363 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xD8 opcodes +-+-+-+-+-+-+-+ */
4364
4365 if (first_opcode == 0xD8) {
4366 if (modrm < 0xC0) {
4367
4368 /* bits 5,4,3 are an opcode extension, and the modRM also
4369 specifies an address. */
sewardj7bc00082005-03-27 05:08:32 +00004370 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
4371 delta += len;
sewardj37d52572005-02-25 14:22:12 +00004372
sewardj901ed122005-02-27 13:25:31 +00004373 switch (gregLO3ofRM(modrm)) {
sewardj37d52572005-02-25 14:22:12 +00004374
sewardj48a89d82005-05-06 11:50:13 +00004375 case 0: /* FADD single-real */
4376 fp_do_op_mem_ST_0 ( addr, "add", dis_buf, Iop_AddF64, False );
4377 break;
4378
sewardje6939f02005-05-07 01:01:24 +00004379 case 1: /* FMUL single-real */
4380 fp_do_op_mem_ST_0 ( addr, "mul", dis_buf, Iop_MulF64, False );
4381 break;
4382
sewardjd20c8852005-01-20 20:04:07 +00004383//.. case 2: /* FCOM single-real */
4384//.. DIP("fcoms %s\n", dis_buf);
4385//.. /* This forces C1 to zero, which isn't right. */
4386//.. put_C3210(
4387//.. binop( Iop_And32,
4388//.. binop(Iop_Shl32,
4389//.. binop(Iop_CmpF64,
4390//.. get_ST(0),
4391//.. unop(Iop_F32toF64,
4392//.. loadLE(Ity_F32,mkexpr(addr)))),
4393//.. mkU8(8)),
4394//.. mkU32(0x4500)
4395//.. ));
4396//.. break;
4397//..
4398//.. case 3: /* FCOMP single-real */
4399//.. DIP("fcomps %s\n", dis_buf);
4400//.. /* This forces C1 to zero, which isn't right. */
4401//.. put_C3210(
4402//.. binop( Iop_And32,
4403//.. binop(Iop_Shl32,
4404//.. binop(Iop_CmpF64,
4405//.. get_ST(0),
4406//.. unop(Iop_F32toF64,
4407//.. loadLE(Ity_F32,mkexpr(addr)))),
4408//.. mkU8(8)),
4409//.. mkU32(0x4500)
4410//.. ));
4411//.. fp_pop();
4412//.. break;
sewardje6939f02005-05-07 01:01:24 +00004413
4414 case 4: /* FSUB single-real */
4415 fp_do_op_mem_ST_0 ( addr, "sub", dis_buf, Iop_SubF64, False );
4416 break;
sewardj7bc00082005-03-27 05:08:32 +00004417
4418 case 5: /* FSUBR single-real */
4419 fp_do_oprev_mem_ST_0 ( addr, "subr", dis_buf, Iop_SubF64, False );
4420 break;
4421
sewardje6939f02005-05-07 01:01:24 +00004422 case 6: /* FDIV single-real */
4423 fp_do_op_mem_ST_0 ( addr, "div", dis_buf, Iop_DivF64, False );
4424 break;
4425
4426 case 7: /* FDIVR single-real */
4427 fp_do_oprev_mem_ST_0 ( addr, "divr", dis_buf, Iop_DivF64, False );
4428 break;
sewardj37d52572005-02-25 14:22:12 +00004429
4430 default:
sewardj901ed122005-02-27 13:25:31 +00004431 vex_printf("unhandled opc_aux = 0x%2x\n", gregLO3ofRM(modrm));
sewardj37d52572005-02-25 14:22:12 +00004432 vex_printf("first_opcode == 0xD8\n");
4433 goto decode_fail;
4434 }
4435 } else {
4436 delta++;
4437 switch (modrm) {
4438
4439 case 0xC0 ... 0xC7: /* FADD %st(?),%st(0) */
4440 fp_do_op_ST_ST ( "add", Iop_AddF64, modrm - 0xC0, 0, False );
4441 break;
4442
sewardj137015d2005-03-27 04:01:15 +00004443 case 0xC8 ... 0xCF: /* FMUL %st(?),%st(0) */
4444 fp_do_op_ST_ST ( "mul", Iop_MulF64, modrm - 0xC8, 0, False );
4445 break;
4446
sewardjd20c8852005-01-20 20:04:07 +00004447//.. #if 1
4448//.. /* Dunno if this is right */
4449//.. case 0xD0 ... 0xD7: /* FCOM %st(?),%st(0) */
4450//.. r_dst = (UInt)modrm - 0xD0;
4451//.. DIP("fcom %%st(0),%%st(%d)\n", r_dst);
4452//.. /* This forces C1 to zero, which isn't right. */
4453//.. put_C3210(
4454//.. binop( Iop_And32,
4455//.. binop(Iop_Shl32,
4456//.. binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
4457//.. mkU8(8)),
4458//.. mkU32(0x4500)
4459//.. ));
4460//.. break;
4461//.. #endif
4462//.. #if 1
4463//.. /* Dunno if this is right */
4464//.. case 0xD8 ... 0xDF: /* FCOMP %st(?),%st(0) */
4465//.. r_dst = (UInt)modrm - 0xD8;
4466//.. DIP("fcomp %%st(0),%%st(%d)\n", r_dst);
4467//.. /* This forces C1 to zero, which isn't right. */
4468//.. put_C3210(
4469//.. binop( Iop_And32,
4470//.. binop(Iop_Shl32,
4471//.. binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
4472//.. mkU8(8)),
4473//.. mkU32(0x4500)
4474//.. ));
4475//.. fp_pop();
4476//.. break;
4477//.. #endif
sewardj137015d2005-03-27 04:01:15 +00004478 case 0xE0 ... 0xE7: /* FSUB %st(?),%st(0) */
4479 fp_do_op_ST_ST ( "sub", Iop_SubF64, modrm - 0xE0, 0, False );
4480 break;
4481
sewardje6939f02005-05-07 01:01:24 +00004482 case 0xE8 ... 0xEF: /* FSUBR %st(?),%st(0) */
4483 fp_do_oprev_ST_ST ( "subr", Iop_SubF64, modrm - 0xE8, 0, False );
4484 break;
sewardj137015d2005-03-27 04:01:15 +00004485
4486 case 0xF0 ... 0xF7: /* FDIV %st(?),%st(0) */
4487 fp_do_op_ST_ST ( "div", Iop_DivF64, modrm - 0xF0, 0, False );
4488 break;
4489
sewardj48a89d82005-05-06 11:50:13 +00004490 case 0xF8 ... 0xFF: /* FDIVR %st(?),%st(0) */
4491 fp_do_oprev_ST_ST ( "divr", Iop_DivF64, modrm - 0xF8, 0, False );
4492 break;
sewardj37d52572005-02-25 14:22:12 +00004493
4494 default:
4495 goto decode_fail;
4496 }
4497 }
4498 }
sewardj8d965312005-02-25 02:48:47 +00004499
4500 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xD9 opcodes +-+-+-+-+-+-+-+ */
sewardj37d52572005-02-25 14:22:12 +00004501 else
sewardj8d965312005-02-25 02:48:47 +00004502 if (first_opcode == 0xD9) {
4503 if (modrm < 0xC0) {
4504
4505 /* bits 5,4,3 are an opcode extension, and the modRM also
4506 specifies an address. */
4507 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
4508 delta += len;
4509
sewardj901ed122005-02-27 13:25:31 +00004510 switch (gregLO3ofRM(modrm)) {
sewardj8d965312005-02-25 02:48:47 +00004511
sewardjc49ce232005-02-25 13:03:03 +00004512 case 0: /* FLD single-real */
4513 DIP("flds %s\n", dis_buf);
4514 fp_push();
4515 put_ST(0, unop(Iop_F32toF64,
4516 loadLE(Ity_F32, mkexpr(addr))));
4517 break;
4518
4519 case 2: /* FST single-real */
4520 DIP("fsts %s\n", dis_buf);
4521 storeLE(mkexpr(addr),
4522 binop(Iop_F64toF32, get_roundingmode(), get_ST(0)));
4523 break;
4524
4525 case 3: /* FSTP single-real */
4526 DIP("fstps %s\n", dis_buf);
4527 storeLE(mkexpr(addr),
4528 binop(Iop_F64toF32, get_roundingmode(), get_ST(0)));
4529 fp_pop();
4530 break;
4531
sewardj4017a3b2005-06-13 12:17:27 +00004532 case 4: { /* FLDENV m28 */
4533 /* Uses dirty helper:
4534 VexEmWarn amd64g_do_FLDENV ( VexGuestX86State*, HWord ) */
4535 IRTemp ew = newTemp(Ity_I32);
4536 IRTemp w64 = newTemp(Ity_I64);
4537 IRDirty* d = unsafeIRDirty_0_N (
4538 0/*regparms*/,
4539 "amd64g_dirtyhelper_FLDENV",
4540 &amd64g_dirtyhelper_FLDENV,
4541 mkIRExprVec_1( mkexpr(addr) )
4542 );
4543 d->needsBBP = True;
4544 d->tmp = w64;
4545 /* declare we're reading memory */
4546 d->mFx = Ifx_Read;
4547 d->mAddr = mkexpr(addr);
4548 d->mSize = 28;
4549
4550 /* declare we're writing guest state */
4551 d->nFxState = 4;
4552
4553 d->fxState[0].fx = Ifx_Write;
4554 d->fxState[0].offset = OFFB_FTOP;
4555 d->fxState[0].size = sizeof(UInt);
4556
4557 d->fxState[1].fx = Ifx_Write;
4558 d->fxState[1].offset = OFFB_FPTAGS;
4559 d->fxState[1].size = 8 * sizeof(UChar);
4560
4561 d->fxState[2].fx = Ifx_Write;
4562 d->fxState[2].offset = OFFB_FPROUND;
4563 d->fxState[2].size = sizeof(ULong);
4564
4565 d->fxState[3].fx = Ifx_Write;
4566 d->fxState[3].offset = OFFB_FC3210;
4567 d->fxState[3].size = sizeof(ULong);
4568
4569 stmt( IRStmt_Dirty(d) );
4570
4571 /* ew contains any emulation warning we may need to
4572 issue. If needed, side-exit to the next insn,
4573 reporting the warning, so that Valgrind's dispatcher
4574 sees the warning. */
4575 assign(ew, unop(Iop_64to32,mkexpr(w64)) );
4576 put_emwarn( mkexpr(ew) );
4577 stmt(
4578 IRStmt_Exit(
4579 binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
4580 Ijk_EmWarn,
sewardj9e6491a2005-07-02 19:24:10 +00004581 IRConst_U64( guest_RIP_bbstart+delta )
sewardj4017a3b2005-06-13 12:17:27 +00004582 )
4583 );
4584
4585 DIP("fldenv %s\n", dis_buf);
4586 break;
4587 }
sewardj5e205372005-05-09 02:57:08 +00004588
4589 case 5: {/* FLDCW */
4590 /* The only thing we observe in the control word is the
4591 rounding mode. Therefore, pass the 16-bit value
4592 (x87 native-format control word) to a clean helper,
4593 getting back a 64-bit value, the lower half of which
4594 is the FPROUND value to store, and the upper half of
4595 which is the emulation-warning token which may be
4596 generated.
4597 */
4598 /* ULong amd64h_check_fldcw ( ULong ); */
4599 IRTemp t64 = newTemp(Ity_I64);
4600 IRTemp ew = newTemp(Ity_I32);
4601 DIP("fldcw %s\n", dis_buf);
4602 assign( t64, mkIRExprCCall(
4603 Ity_I64, 0/*regparms*/,
4604 "amd64g_check_fldcw",
4605 &amd64g_check_fldcw,
4606 mkIRExprVec_1(
4607 unop( Iop_16Uto64,
4608 loadLE(Ity_I16, mkexpr(addr)))
4609 )
4610 )
4611 );
4612
4613 put_fpround( unop(Iop_64to32, mkexpr(t64)) );
4614 assign( ew, unop(Iop_64HIto32, mkexpr(t64) ) );
4615 put_emwarn( mkexpr(ew) );
4616 /* Finally, if an emulation warning was reported,
4617 side-exit to the next insn, reporting the warning,
4618 so that Valgrind's dispatcher sees the warning. */
4619 stmt(
4620 IRStmt_Exit(
4621 binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
4622 Ijk_EmWarn,
sewardj9e6491a2005-07-02 19:24:10 +00004623 IRConst_U64( guest_RIP_bbstart+delta )
sewardj5e205372005-05-09 02:57:08 +00004624 )
4625 );
4626 break;
4627 }
4628
sewardj4017a3b2005-06-13 12:17:27 +00004629 case 6: { /* FNSTENV m28 */
4630 /* Uses dirty helper:
4631 void amd64g_do_FSTENV ( VexGuestAMD64State*, HWord ) */
4632 IRDirty* d = unsafeIRDirty_0_N (
4633 0/*regparms*/,
4634 "amd64g_dirtyhelper_FSTENV",
4635 &amd64g_dirtyhelper_FSTENV,
4636 mkIRExprVec_1( mkexpr(addr) )
4637 );
4638 d->needsBBP = True;
4639 /* declare we're writing memory */
4640 d->mFx = Ifx_Write;
4641 d->mAddr = mkexpr(addr);
4642 d->mSize = 28;
4643
4644 /* declare we're reading guest state */
4645 d->nFxState = 4;
4646
4647 d->fxState[0].fx = Ifx_Read;
4648 d->fxState[0].offset = OFFB_FTOP;
4649 d->fxState[0].size = sizeof(UInt);
4650
4651 d->fxState[1].fx = Ifx_Read;
4652 d->fxState[1].offset = OFFB_FPTAGS;
4653 d->fxState[1].size = 8 * sizeof(UChar);
4654
4655 d->fxState[2].fx = Ifx_Read;
4656 d->fxState[2].offset = OFFB_FPROUND;
4657 d->fxState[2].size = sizeof(ULong);
4658
4659 d->fxState[3].fx = Ifx_Read;
4660 d->fxState[3].offset = OFFB_FC3210;
4661 d->fxState[3].size = sizeof(ULong);
4662
4663 stmt( IRStmt_Dirty(d) );
4664
4665 DIP("fnstenv %s\n", dis_buf);
4666 break;
4667 }
sewardj5e205372005-05-09 02:57:08 +00004668
4669 case 7: /* FNSTCW */
4670 /* Fake up a native x87 FPU control word. The only
4671 thing it depends on is FPROUND[1:0], so call a clean
4672 helper to cook it up. */
sewardj4017a3b2005-06-13 12:17:27 +00004673 /* ULong amd64g_create_fpucw ( ULong fpround ) */
sewardj5e205372005-05-09 02:57:08 +00004674 DIP("fnstcw %s\n", dis_buf);
4675 storeLE(
4676 mkexpr(addr),
4677 unop( Iop_64to16,
4678 mkIRExprCCall(
4679 Ity_I64, 0/*regp*/,
4680 "amd64g_create_fpucw", &amd64g_create_fpucw,
4681 mkIRExprVec_1( unop(Iop_32Uto64, get_fpround()) )
4682 )
4683 )
4684 );
4685 break;
sewardj8d965312005-02-25 02:48:47 +00004686
4687 default:
sewardj901ed122005-02-27 13:25:31 +00004688 vex_printf("unhandled opc_aux = 0x%2x\n", gregLO3ofRM(modrm));
sewardj8d965312005-02-25 02:48:47 +00004689 vex_printf("first_opcode == 0xD9\n");
4690 goto decode_fail;
4691 }
4692
4693 } else {
4694 delta++;
4695 switch (modrm) {
4696
sewardjc49ce232005-02-25 13:03:03 +00004697 case 0xC0 ... 0xC7: /* FLD %st(?) */
4698 r_src = (UInt)modrm - 0xC0;
sewardj1027dc22005-02-26 01:55:02 +00004699 DIP("fld %%st(%u)\n", r_src);
sewardjc49ce232005-02-25 13:03:03 +00004700 t1 = newTemp(Ity_F64);
4701 assign(t1, get_ST(r_src));
4702 fp_push();
4703 put_ST(0, mkexpr(t1));
4704 break;
sewardj8d965312005-02-25 02:48:47 +00004705
4706 case 0xC8 ... 0xCF: /* FXCH %st(?) */
4707 r_src = (UInt)modrm - 0xC8;
sewardj1027dc22005-02-26 01:55:02 +00004708 DIP("fxch %%st(%u)\n", r_src);
sewardj8d965312005-02-25 02:48:47 +00004709 t1 = newTemp(Ity_F64);
4710 t2 = newTemp(Ity_F64);
4711 assign(t1, get_ST(0));
4712 assign(t2, get_ST(r_src));
4713 put_ST_UNCHECKED(0, mkexpr(t2));
4714 put_ST_UNCHECKED(r_src, mkexpr(t1));
4715 break;
4716
4717 case 0xE0: /* FCHS */
4718 DIP("fchs\n");
4719 put_ST_UNCHECKED(0, unop(Iop_NegF64, get_ST(0)));
4720 break;
4721
sewardj137015d2005-03-27 04:01:15 +00004722 case 0xE1: /* FABS */
4723 DIP("fabs\n");
4724 put_ST_UNCHECKED(0, unop(Iop_AbsF64, get_ST(0)));
4725 break;
4726
sewardj4f9847d2005-07-25 11:58:34 +00004727 case 0xE5: { /* FXAM */
4728 /* This is an interesting one. It examines %st(0),
4729 regardless of whether the tag says it's empty or not.
4730 Here, just pass both the tag (in our format) and the
4731 value (as a double, actually a ULong) to a helper
4732 function. */
4733 IRExpr** args
4734 = mkIRExprVec_2( unop(Iop_8Uto64, get_ST_TAG(0)),
4735 unop(Iop_ReinterpF64asI64,
4736 get_ST_UNCHECKED(0)) );
4737 put_C3210(mkIRExprCCall(
4738 Ity_I64,
4739 0/*regparm*/,
4740 "amd64g_calculate_FXAM", &amd64g_calculate_FXAM,
4741 args
4742 ));
4743 DIP("fxam\n");
4744 break;
4745 }
sewardjc49ce232005-02-25 13:03:03 +00004746
4747 case 0xE8: /* FLD1 */
4748 DIP("fld1\n");
4749 fp_push();
4750 /* put_ST(0, IRExpr_Const(IRConst_F64(1.0))); */
4751 put_ST(0, IRExpr_Const(IRConst_F64i(0x3ff0000000000000ULL)));
4752 break;
4753
sewardj6847d8c2005-05-12 19:21:55 +00004754 case 0xE9: /* FLDL2T */
4755 DIP("fldl2t\n");
4756 fp_push();
4757 /* put_ST(0, IRExpr_Const(IRConst_F64(3.32192809488736234781))); */
4758 put_ST(0, IRExpr_Const(IRConst_F64i(0x400a934f0979a371ULL)));
4759 break;
4760
4761 case 0xEA: /* FLDL2E */
4762 DIP("fldl2e\n");
4763 fp_push();
4764 /* put_ST(0, IRExpr_Const(IRConst_F64(1.44269504088896340739))); */
4765 put_ST(0, IRExpr_Const(IRConst_F64i(0x3ff71547652b82feULL)));
4766 break;
4767
4768 case 0xEB: /* FLDPI */
4769 DIP("fldpi\n");
4770 fp_push();
4771 /* put_ST(0, IRExpr_Const(IRConst_F64(3.14159265358979323851))); */
4772 put_ST(0, IRExpr_Const(IRConst_F64i(0x400921fb54442d18ULL)));
4773 break;
4774
4775 case 0xEC: /* FLDLG2 */
4776 DIP("fldlg2\n");
4777 fp_push();
4778 /* put_ST(0, IRExpr_Const(IRConst_F64(0.301029995663981143))); */
4779 put_ST(0, IRExpr_Const(IRConst_F64i(0x3fd34413509f79ffULL)));
4780 break;
4781
4782 case 0xED: /* FLDLN2 */
4783 DIP("fldln2\n");
4784 fp_push();
4785 /* put_ST(0, IRExpr_Const(IRConst_F64(0.69314718055994530942))); */
4786 put_ST(0, IRExpr_Const(IRConst_F64i(0x3fe62e42fefa39efULL)));
4787 break;
sewardjc49ce232005-02-25 13:03:03 +00004788
4789 case 0xEE: /* FLDZ */
4790 DIP("fldz\n");
4791 fp_push();
4792 /* put_ST(0, IRExpr_Const(IRConst_F64(0.0))); */
4793 put_ST(0, IRExpr_Const(IRConst_F64i(0x0000000000000000ULL)));
4794 break;
4795
sewardj25a85812005-05-08 23:03:48 +00004796 case 0xF0: /* F2XM1 */
4797 DIP("f2xm1\n");
sewardj4796d662006-02-05 16:06:26 +00004798 put_ST_UNCHECKED(0,
4799 binop(Iop_2xm1F64,
4800 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4801 get_ST(0)));
sewardj25a85812005-05-08 23:03:48 +00004802 break;
4803
4804 case 0xF1: /* FYL2X */
4805 DIP("fyl2x\n");
sewardj4796d662006-02-05 16:06:26 +00004806 put_ST_UNCHECKED(1,
4807 triop(Iop_Yl2xF64,
4808 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4809 get_ST(1),
4810 get_ST(0)));
sewardj25a85812005-05-08 23:03:48 +00004811 fp_pop();
4812 break;
4813
sewardj5e205372005-05-09 02:57:08 +00004814 case 0xF2: /* FPTAN */
4815 DIP("ftan\n");
sewardj4796d662006-02-05 16:06:26 +00004816 put_ST_UNCHECKED(0,
4817 binop(Iop_TanF64,
4818 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4819 get_ST(0)));
sewardj5e205372005-05-09 02:57:08 +00004820 fp_push();
4821 put_ST(0, IRExpr_Const(IRConst_F64(1.0)));
4822 clear_C2(); /* HACK */
4823 break;
sewardj25a85812005-05-08 23:03:48 +00004824
4825 case 0xF3: /* FPATAN */
4826 DIP("fpatan\n");
sewardj4796d662006-02-05 16:06:26 +00004827 put_ST_UNCHECKED(1,
4828 triop(Iop_AtanF64,
4829 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4830 get_ST(1),
4831 get_ST(0)));
sewardj25a85812005-05-08 23:03:48 +00004832 fp_pop();
4833 break;
4834
sewardj879cee02006-03-07 01:15:50 +00004835 case 0xF4: { /* FXTRACT */
4836 IRTemp argF = newTemp(Ity_F64);
4837 IRTemp sigF = newTemp(Ity_F64);
4838 IRTemp expF = newTemp(Ity_F64);
4839 IRTemp argI = newTemp(Ity_I64);
4840 IRTemp sigI = newTemp(Ity_I64);
4841 IRTemp expI = newTemp(Ity_I64);
4842 DIP("fxtract\n");
4843 assign( argF, get_ST(0) );
4844 assign( argI, unop(Iop_ReinterpF64asI64, mkexpr(argF)));
4845 assign( sigI,
4846 mkIRExprCCall(
4847 Ity_I64, 0/*regparms*/,
4848 "x86amd64g_calculate_FXTRACT",
4849 &x86amd64g_calculate_FXTRACT,
4850 mkIRExprVec_2( mkexpr(argI),
4851 mkIRExpr_HWord(0)/*sig*/ ))
4852 );
4853 assign( expI,
4854 mkIRExprCCall(
4855 Ity_I64, 0/*regparms*/,
4856 "x86amd64g_calculate_FXTRACT",
4857 &x86amd64g_calculate_FXTRACT,
4858 mkIRExprVec_2( mkexpr(argI),
4859 mkIRExpr_HWord(1)/*exp*/ ))
4860 );
4861 assign( sigF, unop(Iop_ReinterpI64asF64, mkexpr(sigI)) );
4862 assign( expF, unop(Iop_ReinterpI64asF64, mkexpr(expI)) );
4863 /* exponent */
4864 put_ST_UNCHECKED(0, mkexpr(expF) );
4865 fp_push();
4866 /* significand */
4867 put_ST(0, mkexpr(sigF) );
4868 break;
4869 }
4870
sewardjd20c8852005-01-20 20:04:07 +00004871//.. case 0xF5: { /* FPREM1 -- IEEE compliant */
4872//.. IRTemp a1 = newTemp(Ity_F64);
4873//.. IRTemp a2 = newTemp(Ity_F64);
4874//.. DIP("fprem1\n");
4875//.. /* Do FPREM1 twice, once to get the remainder, and once
4876//.. to get the C3210 flag values. */
4877//.. assign( a1, get_ST(0) );
4878//.. assign( a2, get_ST(1) );
4879//.. put_ST_UNCHECKED(0, binop(Iop_PRem1F64,
4880//.. mkexpr(a1), mkexpr(a2)));
4881//.. put_C3210( binop(Iop_PRem1C3210F64, mkexpr(a1), mkexpr(a2)) );
4882//.. break;
4883//.. }
sewardj6847d8c2005-05-12 19:21:55 +00004884
4885 case 0xF7: /* FINCSTP */
4886 DIP("fincstp\n");
4887 put_ftop( binop(Iop_Add32, get_ftop(), mkU32(1)) );
4888 break;
4889
sewardjf4c803b2006-09-11 11:07:34 +00004890 case 0xF8: { /* FPREM -- not IEEE compliant */
4891 IRTemp a1 = newTemp(Ity_F64);
4892 IRTemp a2 = newTemp(Ity_F64);
4893 DIP("fprem\n");
4894 /* Do FPREM twice, once to get the remainder, and once
4895 to get the C3210 flag values. */
4896 assign( a1, get_ST(0) );
4897 assign( a2, get_ST(1) );
4898 put_ST_UNCHECKED(0,
4899 triop(Iop_PRemF64,
4900 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4901 mkexpr(a1),
4902 mkexpr(a2)));
4903 put_C3210(
4904 unop(Iop_32Uto64,
4905 triop(Iop_PRemC3210F64,
4906 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4907 mkexpr(a1),
4908 mkexpr(a2)) ));
4909 break;
4910 }
4911
sewardj5e205372005-05-09 02:57:08 +00004912 case 0xF9: /* FYL2XP1 */
4913 DIP("fyl2xp1\n");
sewardj4796d662006-02-05 16:06:26 +00004914 put_ST_UNCHECKED(1,
4915 triop(Iop_Yl2xp1F64,
4916 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4917 get_ST(1),
4918 get_ST(0)));
sewardj5e205372005-05-09 02:57:08 +00004919 fp_pop();
4920 break;
sewardje6939f02005-05-07 01:01:24 +00004921
4922 case 0xFA: /* FSQRT */
4923 DIP("fsqrt\n");
sewardj4796d662006-02-05 16:06:26 +00004924 put_ST_UNCHECKED(0,
4925 binop(Iop_SqrtF64,
4926 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4927 get_ST(0)));
sewardje6939f02005-05-07 01:01:24 +00004928 break;
4929
sewardj25a85812005-05-08 23:03:48 +00004930 case 0xFB: { /* FSINCOS */
4931 IRTemp a1 = newTemp(Ity_F64);
4932 assign( a1, get_ST(0) );
4933 DIP("fsincos\n");
sewardj4796d662006-02-05 16:06:26 +00004934 put_ST_UNCHECKED(0,
4935 binop(Iop_SinF64,
4936 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4937 mkexpr(a1)));
sewardj25a85812005-05-08 23:03:48 +00004938 fp_push();
sewardj4796d662006-02-05 16:06:26 +00004939 put_ST(0,
4940 binop(Iop_CosF64,
4941 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4942 mkexpr(a1)));
sewardj25a85812005-05-08 23:03:48 +00004943 clear_C2(); /* HACK */
4944 break;
4945 }
4946
4947 case 0xFC: /* FRNDINT */
4948 DIP("frndint\n");
4949 put_ST_UNCHECKED(0,
sewardjb183b852006-02-03 16:08:03 +00004950 binop(Iop_RoundF64toInt, get_roundingmode(), get_ST(0)) );
sewardj25a85812005-05-08 23:03:48 +00004951 break;
4952
4953 case 0xFD: /* FSCALE */
4954 DIP("fscale\n");
sewardj4796d662006-02-05 16:06:26 +00004955 put_ST_UNCHECKED(0,
4956 triop(Iop_ScaleF64,
4957 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4958 get_ST(0),
4959 get_ST(1)));
sewardj25a85812005-05-08 23:03:48 +00004960 break;
4961
4962 case 0xFE: /* FSIN */
4963 DIP("fsin\n");
sewardj4796d662006-02-05 16:06:26 +00004964 put_ST_UNCHECKED(0,
4965 binop(Iop_SinF64,
4966 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4967 get_ST(0)));
sewardj25a85812005-05-08 23:03:48 +00004968 clear_C2(); /* HACK */
4969 break;
4970
4971 case 0xFF: /* FCOS */
4972 DIP("fcos\n");
sewardj4796d662006-02-05 16:06:26 +00004973 put_ST_UNCHECKED(0,
4974 binop(Iop_CosF64,
4975 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4976 get_ST(0)));
sewardj25a85812005-05-08 23:03:48 +00004977 clear_C2(); /* HACK */
4978 break;
sewardj8d965312005-02-25 02:48:47 +00004979
4980 default:
4981 goto decode_fail;
4982 }
4983 }
4984 }
4985
4986 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDA opcodes +-+-+-+-+-+-+-+ */
4987 else
4988 if (first_opcode == 0xDA) {
4989
4990 if (modrm < 0xC0) {
4991
4992 /* bits 5,4,3 are an opcode extension, and the modRM also
4993 specifies an address. */
sewardj6847d8c2005-05-12 19:21:55 +00004994 IROp fop;
4995 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
sewardj8d965312005-02-25 02:48:47 +00004996 delta += len;
sewardj901ed122005-02-27 13:25:31 +00004997 switch (gregLO3ofRM(modrm)) {
sewardj8d965312005-02-25 02:48:47 +00004998
sewardj6847d8c2005-05-12 19:21:55 +00004999 case 0: /* FIADD m32int */ /* ST(0) += m32int */
5000 DIP("fiaddl %s\n", dis_buf);
5001 fop = Iop_AddF64;
5002 goto do_fop_m32;
5003
5004 case 1: /* FIMUL m32int */ /* ST(0) *= m32int */
5005 DIP("fimull %s\n", dis_buf);
5006 fop = Iop_MulF64;
5007 goto do_fop_m32;
5008
5009 case 4: /* FISUB m32int */ /* ST(0) -= m32int */
5010 DIP("fisubl %s\n", dis_buf);
5011 fop = Iop_SubF64;
5012 goto do_fop_m32;
5013
5014 case 5: /* FISUBR m32int */ /* ST(0) = m32int - ST(0) */
5015 DIP("fisubrl %s\n", dis_buf);
5016 fop = Iop_SubF64;
5017 goto do_foprev_m32;
5018
5019 case 6: /* FIDIV m32int */ /* ST(0) /= m32int */
5020 DIP("fisubl %s\n", dis_buf);
5021 fop = Iop_DivF64;
5022 goto do_fop_m32;
5023
5024 case 7: /* FIDIVR m32int */ /* ST(0) = m32int / ST(0) */
5025 DIP("fidivrl %s\n", dis_buf);
5026 fop = Iop_DivF64;
5027 goto do_foprev_m32;
5028
5029 do_fop_m32:
5030 put_ST_UNCHECKED(0,
sewardj4796d662006-02-05 16:06:26 +00005031 triop(fop,
5032 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardj6847d8c2005-05-12 19:21:55 +00005033 get_ST(0),
5034 unop(Iop_I32toF64,
5035 loadLE(Ity_I32, mkexpr(addr)))));
5036 break;
5037
5038 do_foprev_m32:
5039 put_ST_UNCHECKED(0,
sewardj4796d662006-02-05 16:06:26 +00005040 triop(fop,
5041 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardj6847d8c2005-05-12 19:21:55 +00005042 unop(Iop_I32toF64,
5043 loadLE(Ity_I32, mkexpr(addr))),
5044 get_ST(0)));
5045 break;
sewardj8d965312005-02-25 02:48:47 +00005046
5047 default:
sewardj901ed122005-02-27 13:25:31 +00005048 vex_printf("unhandled opc_aux = 0x%2x\n", gregLO3ofRM(modrm));
sewardj8d965312005-02-25 02:48:47 +00005049 vex_printf("first_opcode == 0xDA\n");
5050 goto decode_fail;
5051 }
5052
5053 } else {
5054
5055 delta++;
5056 switch (modrm) {
5057
sewardj48a89d82005-05-06 11:50:13 +00005058 case 0xC0 ... 0xC7: /* FCMOVB ST(i), ST(0) */
5059 r_src = (UInt)modrm - 0xC0;
sewardjca673ab2005-05-11 10:03:08 +00005060 DIP("fcmovb %%st(%u), %%st(0)\n", r_src);
sewardj48a89d82005-05-06 11:50:13 +00005061 put_ST_UNCHECKED(0,
5062 IRExpr_Mux0X(
5063 unop(Iop_1Uto8,
5064 mk_amd64g_calculate_condition(AMD64CondB)),
5065 get_ST(0), get_ST(r_src)) );
5066 break;
sewardj8d965312005-02-25 02:48:47 +00005067
5068 case 0xC8 ... 0xCF: /* FCMOVE(Z) ST(i), ST(0) */
5069 r_src = (UInt)modrm - 0xC8;
sewardj1027dc22005-02-26 01:55:02 +00005070 DIP("fcmovz %%st(%u), %%st(0)\n", r_src);
sewardj8d965312005-02-25 02:48:47 +00005071 put_ST_UNCHECKED(0,
5072 IRExpr_Mux0X(
5073 unop(Iop_1Uto8,
5074 mk_amd64g_calculate_condition(AMD64CondZ)),
5075 get_ST(0), get_ST(r_src)) );
5076 break;
5077
sewardj37d52572005-02-25 14:22:12 +00005078 case 0xD0 ... 0xD7: /* FCMOVBE ST(i), ST(0) */
5079 r_src = (UInt)modrm - 0xD0;
sewardj1027dc22005-02-26 01:55:02 +00005080 DIP("fcmovbe %%st(%u), %%st(0)\n", r_src);
sewardj37d52572005-02-25 14:22:12 +00005081 put_ST_UNCHECKED(0,
5082 IRExpr_Mux0X(
5083 unop(Iop_1Uto8,
5084 mk_amd64g_calculate_condition(AMD64CondBE)),
5085 get_ST(0), get_ST(r_src)) );
5086 break;
5087
sewardj25a85812005-05-08 23:03:48 +00005088 case 0xD8 ... 0xDF: /* FCMOVU ST(i), ST(0) */
5089 r_src = (UInt)modrm - 0xD8;
5090 DIP("fcmovu %%st(%u), %%st(0)\n", r_src);
5091 put_ST_UNCHECKED(0,
5092 IRExpr_Mux0X(
5093 unop(Iop_1Uto8,
5094 mk_amd64g_calculate_condition(AMD64CondP)),
5095 get_ST(0), get_ST(r_src)) );
5096 break;
5097
sewardjd20c8852005-01-20 20:04:07 +00005098//.. case 0xE9: /* FUCOMPP %st(0),%st(1) */
5099//.. DIP("fucompp %%st(0),%%st(1)\n");
5100//.. /* This forces C1 to zero, which isn't right. */
5101//.. put_C3210(
5102//.. binop( Iop_And32,
5103//.. binop(Iop_Shl32,
5104//.. binop(Iop_CmpF64, get_ST(0), get_ST(1)),
5105//.. mkU8(8)),
5106//.. mkU32(0x4500)
5107//.. ));
5108//.. fp_pop();
5109//.. fp_pop();
5110//.. break;
sewardj8d965312005-02-25 02:48:47 +00005111
5112 default:
5113 goto decode_fail;
5114 }
5115
5116 }
5117 }
5118
sewardjc49ce232005-02-25 13:03:03 +00005119 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDB opcodes +-+-+-+-+-+-+-+ */
5120 else
5121 if (first_opcode == 0xDB) {
5122 if (modrm < 0xC0) {
5123
5124 /* bits 5,4,3 are an opcode extension, and the modRM also
5125 specifies an address. */
5126 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
5127 delta += len;
5128
sewardj901ed122005-02-27 13:25:31 +00005129 switch (gregLO3ofRM(modrm)) {
sewardjc49ce232005-02-25 13:03:03 +00005130
sewardj5cc00ff2005-03-27 04:48:32 +00005131 case 0: /* FILD m32int */
5132 DIP("fildl %s\n", dis_buf);
5133 fp_push();
5134 put_ST(0, unop(Iop_I32toF64,
5135 loadLE(Ity_I32, mkexpr(addr))));
5136 break;
5137
sewardjfcf21f32006-08-04 14:51:19 +00005138 case 1: /* FISTTPL m32 (SSE3) */
5139 DIP("fisttpl %s\n", dis_buf);
5140 storeLE( mkexpr(addr),
5141 binop(Iop_F64toI32, mkU32(Irrm_ZERO), get_ST(0)) );
5142 fp_pop();
5143 break;
5144
sewardj6847d8c2005-05-12 19:21:55 +00005145 case 2: /* FIST m32 */
5146 DIP("fistl %s\n", dis_buf);
5147 storeLE( mkexpr(addr),
5148 binop(Iop_F64toI32, get_roundingmode(), get_ST(0)) );
5149 break;
sewardj37d52572005-02-25 14:22:12 +00005150
5151 case 3: /* FISTP m32 */
5152 DIP("fistpl %s\n", dis_buf);
5153 storeLE( mkexpr(addr),
5154 binop(Iop_F64toI32, get_roundingmode(), get_ST(0)) );
5155 fp_pop();
5156 break;
5157
sewardj924215b2005-03-26 21:50:31 +00005158 case 5: { /* FLD extended-real */
5159 /* Uses dirty helper:
5160 ULong amd64g_loadF80le ( ULong )
5161 addr holds the address. First, do a dirty call to
5162 get hold of the data. */
5163 IRTemp val = newTemp(Ity_I64);
5164 IRExpr** args = mkIRExprVec_1 ( mkexpr(addr) );
5165
5166 IRDirty* d = unsafeIRDirty_1_N (
5167 val,
5168 0/*regparms*/,
sewardj8707fef2005-08-23 23:26:37 +00005169 "amd64g_dirtyhelper_loadF80le",
5170 &amd64g_dirtyhelper_loadF80le,
sewardj924215b2005-03-26 21:50:31 +00005171 args
5172 );
5173 /* declare that we're reading memory */
5174 d->mFx = Ifx_Read;
5175 d->mAddr = mkexpr(addr);
5176 d->mSize = 10;
5177
5178 /* execute the dirty call, dumping the result in val. */
5179 stmt( IRStmt_Dirty(d) );
5180 fp_push();
5181 put_ST(0, unop(Iop_ReinterpI64asF64, mkexpr(val)));
5182
5183 DIP("fldt %s\n", dis_buf);
5184 break;
5185 }
5186
5187 case 7: { /* FSTP extended-real */
5188 /* Uses dirty helper:
5189 void amd64g_storeF80le ( ULong addr, ULong data )
5190 */
5191 IRExpr** args
5192 = mkIRExprVec_2( mkexpr(addr),
5193 unop(Iop_ReinterpF64asI64, get_ST(0)) );
5194
5195 IRDirty* d = unsafeIRDirty_0_N (
5196 0/*regparms*/,
sewardj8707fef2005-08-23 23:26:37 +00005197 "amd64g_dirtyhelper_storeF80le",
5198 &amd64g_dirtyhelper_storeF80le,
sewardj924215b2005-03-26 21:50:31 +00005199 args
5200 );
5201 /* declare we're writing memory */
5202 d->mFx = Ifx_Write;
5203 d->mAddr = mkexpr(addr);
5204 d->mSize = 10;
5205
5206 /* execute the dirty call. */
5207 stmt( IRStmt_Dirty(d) );
5208 fp_pop();
5209
5210 DIP("fstpt\n %s", dis_buf);
5211 break;
5212 }
sewardjc49ce232005-02-25 13:03:03 +00005213
5214 default:
sewardj901ed122005-02-27 13:25:31 +00005215 vex_printf("unhandled opc_aux = 0x%2x\n", gregLO3ofRM(modrm));
sewardjc49ce232005-02-25 13:03:03 +00005216 vex_printf("first_opcode == 0xDB\n");
5217 goto decode_fail;
5218 }
5219
5220 } else {
5221
5222 delta++;
5223 switch (modrm) {
5224
sewardj48a89d82005-05-06 11:50:13 +00005225 case 0xC0 ... 0xC7: /* FCMOVNB ST(i), ST(0) */
5226 r_src = (UInt)modrm - 0xC0;
sewardjca673ab2005-05-11 10:03:08 +00005227 DIP("fcmovnb %%st(%u), %%st(0)\n", r_src);
sewardj48a89d82005-05-06 11:50:13 +00005228 put_ST_UNCHECKED(0,
5229 IRExpr_Mux0X(
5230 unop(Iop_1Uto8,
5231 mk_amd64g_calculate_condition(AMD64CondNB)),
5232 get_ST(0), get_ST(r_src)) );
5233 break;
sewardj924215b2005-03-26 21:50:31 +00005234
5235 case 0xC8 ... 0xCF: /* FCMOVNE(NZ) ST(i), ST(0) */
5236 r_src = (UInt)modrm - 0xC8;
sewardj40e144d2005-03-28 00:46:27 +00005237 DIP("fcmovnz %%st(%u), %%st(0)\n", r_src);
sewardj137015d2005-03-27 04:01:15 +00005238 put_ST_UNCHECKED(
5239 0,
5240 IRExpr_Mux0X(
5241 unop(Iop_1Uto8,
5242 mk_amd64g_calculate_condition(AMD64CondNZ)),
5243 get_ST(0),
5244 get_ST(r_src)
5245 )
5246 );
sewardj924215b2005-03-26 21:50:31 +00005247 break;
5248
sewardj137015d2005-03-27 04:01:15 +00005249 case 0xD0 ... 0xD7: /* FCMOVNBE ST(i), ST(0) */
5250 r_src = (UInt)modrm - 0xD0;
sewardj40e144d2005-03-28 00:46:27 +00005251 DIP("fcmovnbe %%st(%u), %%st(0)\n", r_src);
sewardj137015d2005-03-27 04:01:15 +00005252 put_ST_UNCHECKED(
5253 0,
5254 IRExpr_Mux0X(
5255 unop(Iop_1Uto8,
5256 mk_amd64g_calculate_condition(AMD64CondNBE)),
5257 get_ST(0),
5258 get_ST(r_src)
5259 )
5260 );
5261 break;
5262
sewardj3368e102006-03-06 19:05:07 +00005263 case 0xD8 ... 0xDF: /* FCMOVNU ST(i), ST(0) */
5264 r_src = (UInt)modrm - 0xD8;
5265 DIP("fcmovnu %%st(%u), %%st(0)\n", r_src);
5266 put_ST_UNCHECKED(
5267 0,
5268 IRExpr_Mux0X(
5269 unop(Iop_1Uto8,
5270 mk_amd64g_calculate_condition(AMD64CondNP)),
5271 get_ST(0),
5272 get_ST(r_src)
5273 )
5274 );
5275 break;
5276
sewardj4e1a1e92005-05-25 00:44:13 +00005277 case 0xE2:
5278 DIP("fnclex\n");
5279 break;
5280
sewardj0585a032005-11-05 02:55:06 +00005281 case 0xE3: {
5282 /* Uses dirty helper:
5283 void amd64g_do_FINIT ( VexGuestAMD64State* ) */
5284 IRDirty* d = unsafeIRDirty_0_N (
5285 0/*regparms*/,
5286 "amd64g_dirtyhelper_FINIT",
5287 &amd64g_dirtyhelper_FINIT,
5288 mkIRExprVec_0()
5289 );
5290 d->needsBBP = True;
5291
5292 /* declare we're writing guest state */
5293 d->nFxState = 5;
5294
5295 d->fxState[0].fx = Ifx_Write;
5296 d->fxState[0].offset = OFFB_FTOP;
5297 d->fxState[0].size = sizeof(UInt);
5298
5299 d->fxState[1].fx = Ifx_Write;
5300 d->fxState[1].offset = OFFB_FPREGS;
5301 d->fxState[1].size = 8 * sizeof(ULong);
5302
5303 d->fxState[2].fx = Ifx_Write;
5304 d->fxState[2].offset = OFFB_FPTAGS;
5305 d->fxState[2].size = 8 * sizeof(UChar);
5306
5307 d->fxState[3].fx = Ifx_Write;
5308 d->fxState[3].offset = OFFB_FPROUND;
5309 d->fxState[3].size = sizeof(ULong);
5310
5311 d->fxState[4].fx = Ifx_Write;
5312 d->fxState[4].offset = OFFB_FC3210;
5313 d->fxState[4].size = sizeof(ULong);
5314
5315 stmt( IRStmt_Dirty(d) );
5316
5317 DIP("fninit\n");
5318 break;
5319 }
sewardjc49ce232005-02-25 13:03:03 +00005320
5321 case 0xE8 ... 0xEF: /* FUCOMI %st(0),%st(?) */
5322 fp_do_ucomi_ST0_STi( (UInt)modrm - 0xE8, False );
5323 break;
5324
sewardj48a89d82005-05-06 11:50:13 +00005325 case 0xF0 ... 0xF7: /* FCOMI %st(0),%st(?) */
5326 fp_do_ucomi_ST0_STi( (UInt)modrm - 0xF0, False );
5327 break;
sewardjc49ce232005-02-25 13:03:03 +00005328
5329 default:
5330 goto decode_fail;
5331 }
5332 }
5333 }
5334
sewardj137015d2005-03-27 04:01:15 +00005335 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDC opcodes +-+-+-+-+-+-+-+ */
5336 else
5337 if (first_opcode == 0xDC) {
5338 if (modrm < 0xC0) {
5339
sewardj434e0692005-03-27 17:36:08 +00005340 /* bits 5,4,3 are an opcode extension, and the modRM also
5341 specifies an address. */
5342 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
5343 delta += len;
5344
5345 switch (gregLO3ofRM(modrm)) {
5346
sewardje6939f02005-05-07 01:01:24 +00005347 case 0: /* FADD double-real */
5348 fp_do_op_mem_ST_0 ( addr, "add", dis_buf, Iop_AddF64, True );
5349 break;
5350
5351 case 1: /* FMUL double-real */
5352 fp_do_op_mem_ST_0 ( addr, "mul", dis_buf, Iop_MulF64, True );
5353 break;
5354
sewardjd20c8852005-01-20 20:04:07 +00005355//.. case 2: /* FCOM double-real */
5356//.. DIP("fcoml %s\n", dis_buf);
5357//.. /* This forces C1 to zero, which isn't right. */
5358//.. put_C3210(
5359//.. binop( Iop_And32,
5360//.. binop(Iop_Shl32,
5361//.. binop(Iop_CmpF64,
5362//.. get_ST(0),
5363//.. loadLE(Ity_F64,mkexpr(addr))),
5364//.. mkU8(8)),
5365//.. mkU32(0x4500)
5366//.. ));
5367//.. break;
sewardj566d2c72005-08-10 11:43:42 +00005368
5369 case 3: /* FCOMP double-real */
5370 DIP("fcompl %s\n", dis_buf);
5371 /* This forces C1 to zero, which isn't right. */
5372 put_C3210(
5373 unop(Iop_32Uto64,
5374 binop( Iop_And32,
5375 binop(Iop_Shl32,
5376 binop(Iop_CmpF64,
5377 get_ST(0),
5378 loadLE(Ity_F64,mkexpr(addr))),
5379 mkU8(8)),
5380 mkU32(0x4500)
5381 )));
5382 fp_pop();
5383 break;
sewardje6939f02005-05-07 01:01:24 +00005384
5385 case 4: /* FSUB double-real */
5386 fp_do_op_mem_ST_0 ( addr, "sub", dis_buf, Iop_SubF64, True );
5387 break;
sewardj434e0692005-03-27 17:36:08 +00005388
5389 case 5: /* FSUBR double-real */
5390 fp_do_oprev_mem_ST_0 ( addr, "subr", dis_buf, Iop_SubF64, True );
5391 break;
5392
sewardje6939f02005-05-07 01:01:24 +00005393 case 6: /* FDIV double-real */
5394 fp_do_op_mem_ST_0 ( addr, "div", dis_buf, Iop_DivF64, True );
5395 break;
5396
5397 case 7: /* FDIVR double-real */
5398 fp_do_oprev_mem_ST_0 ( addr, "divr", dis_buf, Iop_DivF64, True );
5399 break;
sewardj434e0692005-03-27 17:36:08 +00005400
5401 default:
5402 vex_printf("unhandled opc_aux = 0x%2x\n", gregLO3ofRM(modrm));
5403 vex_printf("first_opcode == 0xDC\n");
5404 goto decode_fail;
5405 }
sewardj137015d2005-03-27 04:01:15 +00005406
5407 } else {
5408
5409 delta++;
5410 switch (modrm) {
5411
5412 case 0xC0 ... 0xC7: /* FADD %st(0),%st(?) */
5413 fp_do_op_ST_ST ( "add", Iop_AddF64, 0, modrm - 0xC0, False );
5414 break;
5415
sewardj7bc00082005-03-27 05:08:32 +00005416 case 0xC8 ... 0xCF: /* FMUL %st(0),%st(?) */
5417 fp_do_op_ST_ST ( "mul", Iop_MulF64, 0, modrm - 0xC8, False );
5418 break;
5419
sewardj434e0692005-03-27 17:36:08 +00005420 case 0xE0 ... 0xE7: /* FSUBR %st(0),%st(?) */
5421 fp_do_oprev_ST_ST ( "subr", Iop_SubF64, 0, modrm - 0xE0, False );
5422 break;
5423
sewardje6939f02005-05-07 01:01:24 +00005424 case 0xE8 ... 0xEF: /* FSUB %st(0),%st(?) */
5425 fp_do_op_ST_ST ( "sub", Iop_SubF64, 0, modrm - 0xE8, False );
5426 break;
5427
5428 case 0xF0 ... 0xF7: /* FDIVR %st(0),%st(?) */
5429 fp_do_oprev_ST_ST ( "divr", Iop_DivF64, 0, modrm - 0xF0, False );
5430 break;
sewardj137015d2005-03-27 04:01:15 +00005431
5432 case 0xF8 ... 0xFF: /* FDIV %st(0),%st(?) */
5433 fp_do_op_ST_ST ( "div", Iop_DivF64, 0, modrm - 0xF8, False );
5434 break;
5435
5436 default:
5437 goto decode_fail;
5438 }
5439
5440 }
5441 }
sewardj8d965312005-02-25 02:48:47 +00005442
5443 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDD opcodes +-+-+-+-+-+-+-+ */
5444 else
5445 if (first_opcode == 0xDD) {
5446
5447 if (modrm < 0xC0) {
5448
5449 /* bits 5,4,3 are an opcode extension, and the modRM also
5450 specifies an address. */
5451 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
5452 delta += len;
5453
sewardj901ed122005-02-27 13:25:31 +00005454 switch (gregLO3ofRM(modrm)) {
sewardj8d965312005-02-25 02:48:47 +00005455
5456 case 0: /* FLD double-real */
5457 DIP("fldl %s\n", dis_buf);
5458 fp_push();
sewardjaf1ceca2005-06-30 23:31:27 +00005459 put_ST(0, loadLE(Ity_F64, mkexpr(addr)));
sewardj8d965312005-02-25 02:48:47 +00005460 break;
5461
sewardjfcf21f32006-08-04 14:51:19 +00005462 case 1: /* FISTTPQ m64 (SSE3) */
5463 DIP("fistppll %s\n", dis_buf);
5464 storeLE( mkexpr(addr),
5465 binop(Iop_F64toI64, mkU32(Irrm_ZERO), get_ST(0)) );
5466 fp_pop();
5467 break;
5468
sewardjc49ce232005-02-25 13:03:03 +00005469 case 2: /* FST double-real */
5470 DIP("fstl %s\n", dis_buf);
5471 storeLE(mkexpr(addr), get_ST(0));
5472 break;
sewardj8d965312005-02-25 02:48:47 +00005473
5474 case 3: /* FSTP double-real */
5475 DIP("fstpl %s\n", dis_buf);
5476 storeLE(mkexpr(addr), get_ST(0));
5477 fp_pop();
5478 break;
5479
sewardjd20c8852005-01-20 20:04:07 +00005480//.. case 4: { /* FRSTOR m108 */
5481//.. /* Uses dirty helper:
5482//.. VexEmWarn x86g_do_FRSTOR ( VexGuestX86State*, Addr32 ) */
5483//.. IRTemp ew = newTemp(Ity_I32);
5484//.. IRDirty* d = unsafeIRDirty_0_N (
5485//.. 0/*regparms*/,
5486//.. "x86g_dirtyhelper_FRSTOR",
5487//.. &x86g_dirtyhelper_FRSTOR,
5488//.. mkIRExprVec_1( mkexpr(addr) )
5489//.. );
5490//.. d->needsBBP = True;
5491//.. d->tmp = ew;
5492//.. /* declare we're reading memory */
5493//.. d->mFx = Ifx_Read;
5494//.. d->mAddr = mkexpr(addr);
5495//.. d->mSize = 108;
5496//..
5497//.. /* declare we're writing guest state */
5498//.. d->nFxState = 5;
5499//..
5500//.. d->fxState[0].fx = Ifx_Write;
5501//.. d->fxState[0].offset = OFFB_FTOP;
5502//.. d->fxState[0].size = sizeof(UInt);
5503//..
5504//.. d->fxState[1].fx = Ifx_Write;
5505//.. d->fxState[1].offset = OFFB_FPREGS;
5506//.. d->fxState[1].size = 8 * sizeof(ULong);
5507//..
5508//.. d->fxState[2].fx = Ifx_Write;
5509//.. d->fxState[2].offset = OFFB_FPTAGS;
5510//.. d->fxState[2].size = 8 * sizeof(UChar);
5511//..
5512//.. d->fxState[3].fx = Ifx_Write;
5513//.. d->fxState[3].offset = OFFB_FPROUND;
5514//.. d->fxState[3].size = sizeof(UInt);
5515//..
5516//.. d->fxState[4].fx = Ifx_Write;
5517//.. d->fxState[4].offset = OFFB_FC3210;
5518//.. d->fxState[4].size = sizeof(UInt);
5519//..
5520//.. stmt( IRStmt_Dirty(d) );
5521//..
5522//.. /* ew contains any emulation warning we may need to
5523//.. issue. If needed, side-exit to the next insn,
5524//.. reporting the warning, so that Valgrind's dispatcher
5525//.. sees the warning. */
5526//.. put_emwarn( mkexpr(ew) );
5527//.. stmt(
5528//.. IRStmt_Exit(
5529//.. binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
5530//.. Ijk_EmWarn,
5531//.. IRConst_U32( ((Addr32)guest_eip_bbstart)+delta)
5532//.. )
5533//.. );
5534//..
5535//.. DIP("frstor %s\n", dis_buf);
5536//.. break;
5537//.. }
5538//..
5539//.. case 6: { /* FNSAVE m108 */
5540//.. /* Uses dirty helper:
5541//.. void x86g_do_FSAVE ( VexGuestX86State*, UInt ) */
5542//.. IRDirty* d = unsafeIRDirty_0_N (
5543//.. 0/*regparms*/,
5544//.. "x86g_dirtyhelper_FSAVE",
5545//.. &x86g_dirtyhelper_FSAVE,
5546//.. mkIRExprVec_1( mkexpr(addr) )
5547//.. );
5548//.. d->needsBBP = True;
5549//.. /* declare we're writing memory */
5550//.. d->mFx = Ifx_Write;
5551//.. d->mAddr = mkexpr(addr);
5552//.. d->mSize = 108;
5553//..
5554//.. /* declare we're reading guest state */
5555//.. d->nFxState = 5;
5556//..
5557//.. d->fxState[0].fx = Ifx_Read;
5558//.. d->fxState[0].offset = OFFB_FTOP;
5559//.. d->fxState[0].size = sizeof(UInt);
5560//..
5561//.. d->fxState[1].fx = Ifx_Read;
5562//.. d->fxState[1].offset = OFFB_FPREGS;
5563//.. d->fxState[1].size = 8 * sizeof(ULong);
5564//..
5565//.. d->fxState[2].fx = Ifx_Read;
5566//.. d->fxState[2].offset = OFFB_FPTAGS;
5567//.. d->fxState[2].size = 8 * sizeof(UChar);
5568//..
5569//.. d->fxState[3].fx = Ifx_Read;
5570//.. d->fxState[3].offset = OFFB_FPROUND;
5571//.. d->fxState[3].size = sizeof(UInt);
5572//..
5573//.. d->fxState[4].fx = Ifx_Read;
5574//.. d->fxState[4].offset = OFFB_FC3210;
5575//.. d->fxState[4].size = sizeof(UInt);
5576//..
5577//.. stmt( IRStmt_Dirty(d) );
5578//..
5579//.. DIP("fnsave %s\n", dis_buf);
5580//.. break;
5581//.. }
sewardj8d965312005-02-25 02:48:47 +00005582
sewardj7c2d2822006-03-07 00:22:02 +00005583 case 7: { /* FNSTSW m16 */
5584 IRExpr* sw = get_FPU_sw();
5585 vassert(typeOfIRExpr(irbb->tyenv, sw) == Ity_I16);
5586 storeLE( mkexpr(addr), sw );
5587 DIP("fnstsw %s\n", dis_buf);
5588 break;
5589 }
5590
sewardj8d965312005-02-25 02:48:47 +00005591 default:
sewardj901ed122005-02-27 13:25:31 +00005592 vex_printf("unhandled opc_aux = 0x%2x\n", gregLO3ofRM(modrm));
sewardj8d965312005-02-25 02:48:47 +00005593 vex_printf("first_opcode == 0xDD\n");
5594 goto decode_fail;
5595 }
5596 } else {
5597 delta++;
5598 switch (modrm) {
5599
sewardj6847d8c2005-05-12 19:21:55 +00005600 case 0xC0 ... 0xC7: /* FFREE %st(?) */
5601 r_dst = (UInt)modrm - 0xC0;
5602 DIP("ffree %%st(%u)\n", r_dst);
5603 put_ST_TAG ( r_dst, mkU8(0) );
5604 break;
5605
sewardjbfabcc42005-08-08 09:58:05 +00005606 case 0xD0 ... 0xD7: /* FST %st(0),%st(?) */
5607 r_dst = (UInt)modrm - 0xD0;
sewardjc7cd2142005-09-09 22:31:49 +00005608 DIP("fst %%st(0),%%st(%u)\n", r_dst);
sewardjbfabcc42005-08-08 09:58:05 +00005609 /* P4 manual says: "If the destination operand is a
5610 non-empty register, the invalid-operation exception
5611 is not generated. Hence put_ST_UNCHECKED. */
5612 put_ST_UNCHECKED(r_dst, get_ST(0));
5613 break;
sewardj8d965312005-02-25 02:48:47 +00005614
5615 case 0xD8 ... 0xDF: /* FSTP %st(0),%st(?) */
5616 r_dst = (UInt)modrm - 0xD8;
sewardj1027dc22005-02-26 01:55:02 +00005617 DIP("fstp %%st(0),%%st(%u)\n", r_dst);
sewardj8d965312005-02-25 02:48:47 +00005618 /* P4 manual says: "If the destination operand is a
5619 non-empty register, the invalid-operation exception
5620 is not generated. Hence put_ST_UNCHECKED. */
5621 put_ST_UNCHECKED(r_dst, get_ST(0));
5622 fp_pop();
5623 break;
5624
sewardjfb6c1792005-10-05 17:58:32 +00005625 case 0xE0 ... 0xE7: /* FUCOM %st(0),%st(?) */
5626 r_dst = (UInt)modrm - 0xE0;
sewardj62d05432005-10-29 22:30:47 +00005627 DIP("fucom %%st(0),%%st(%u)\n", r_dst);
sewardjfb6c1792005-10-05 17:58:32 +00005628 /* This forces C1 to zero, which isn't right. */
5629 put_C3210(
5630 unop(Iop_32Uto64,
5631 binop( Iop_And32,
5632 binop(Iop_Shl32,
5633 binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
5634 mkU8(8)),
5635 mkU32(0x4500)
5636 )));
5637 break;
5638
sewardj9fb2f472005-11-05 01:12:18 +00005639 case 0xE8 ... 0xEF: /* FUCOMP %st(0),%st(?) */
5640 r_dst = (UInt)modrm - 0xE8;
sewardj43f45732005-11-05 13:04:34 +00005641 DIP("fucomp %%st(0),%%st(%u)\n", r_dst);
sewardj9fb2f472005-11-05 01:12:18 +00005642 /* This forces C1 to zero, which isn't right. */
5643 put_C3210(
5644 unop(Iop_32Uto64,
5645 binop( Iop_And32,
5646 binop(Iop_Shl32,
5647 binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
5648 mkU8(8)),
5649 mkU32(0x4500)
5650 )));
5651 fp_pop();
5652 break;
sewardj8d965312005-02-25 02:48:47 +00005653
5654 default:
5655 goto decode_fail;
5656 }
5657 }
5658 }
5659
sewardj137015d2005-03-27 04:01:15 +00005660 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDE opcodes +-+-+-+-+-+-+-+ */
5661 else
5662 if (first_opcode == 0xDE) {
5663
5664 if (modrm < 0xC0) {
5665
sewardj6847d8c2005-05-12 19:21:55 +00005666 /* bits 5,4,3 are an opcode extension, and the modRM also
5667 specifies an address. */
5668 IROp fop;
5669 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
5670 delta += len;
5671
5672 switch (gregLO3ofRM(modrm)) {
5673
5674 case 0: /* FIADD m16int */ /* ST(0) += m16int */
5675 DIP("fiaddw %s\n", dis_buf);
5676 fop = Iop_AddF64;
5677 goto do_fop_m16;
5678
5679 case 1: /* FIMUL m16int */ /* ST(0) *= m16int */
5680 DIP("fimulw %s\n", dis_buf);
5681 fop = Iop_MulF64;
5682 goto do_fop_m16;
5683
5684 case 4: /* FISUB m16int */ /* ST(0) -= m16int */
5685 DIP("fisubw %s\n", dis_buf);
5686 fop = Iop_SubF64;
5687 goto do_fop_m16;
5688
5689 case 5: /* FISUBR m16int */ /* ST(0) = m16int - ST(0) */
5690 DIP("fisubrw %s\n", dis_buf);
5691 fop = Iop_SubF64;
5692 goto do_foprev_m16;
5693
5694 case 6: /* FIDIV m16int */ /* ST(0) /= m16int */
5695 DIP("fisubw %s\n", dis_buf);
5696 fop = Iop_DivF64;
5697 goto do_fop_m16;
5698
5699 case 7: /* FIDIVR m16int */ /* ST(0) = m16int / ST(0) */
5700 DIP("fidivrw %s\n", dis_buf);
5701 fop = Iop_DivF64;
5702 goto do_foprev_m16;
5703
5704 do_fop_m16:
5705 put_ST_UNCHECKED(0,
sewardj4796d662006-02-05 16:06:26 +00005706 triop(fop,
5707 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardj6847d8c2005-05-12 19:21:55 +00005708 get_ST(0),
5709 unop(Iop_I32toF64,
5710 unop(Iop_16Sto32,
5711 loadLE(Ity_I16, mkexpr(addr))))));
5712 break;
5713
5714 do_foprev_m16:
5715 put_ST_UNCHECKED(0,
sewardj4796d662006-02-05 16:06:26 +00005716 triop(fop,
5717 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardj6847d8c2005-05-12 19:21:55 +00005718 unop(Iop_I32toF64,
5719 unop(Iop_16Sto32,
5720 loadLE(Ity_I16, mkexpr(addr)))),
5721 get_ST(0)));
5722 break;
5723
5724 default:
5725 vex_printf("unhandled opc_aux = 0x%2x\n", gregLO3ofRM(modrm));
5726 vex_printf("first_opcode == 0xDE\n");
5727 goto decode_fail;
5728 }
sewardj137015d2005-03-27 04:01:15 +00005729
5730 } else {
5731
5732 delta++;
5733 switch (modrm) {
5734
5735 case 0xC0 ... 0xC7: /* FADDP %st(0),%st(?) */
5736 fp_do_op_ST_ST ( "add", Iop_AddF64, 0, modrm - 0xC0, True );
5737 break;
5738
5739 case 0xC8 ... 0xCF: /* FMULP %st(0),%st(?) */
5740 fp_do_op_ST_ST ( "mul", Iop_MulF64, 0, modrm - 0xC8, True );
5741 break;
5742
sewardjd20c8852005-01-20 20:04:07 +00005743//.. case 0xD9: /* FCOMPP %st(0),%st(1) */
5744//.. DIP("fuompp %%st(0),%%st(1)\n");
5745//.. /* This forces C1 to zero, which isn't right. */
5746//.. put_C3210(
5747//.. binop( Iop_And32,
5748//.. binop(Iop_Shl32,
5749//.. binop(Iop_CmpF64, get_ST(0), get_ST(1)),
5750//.. mkU8(8)),
5751//.. mkU32(0x4500)
5752//.. ));
5753//.. fp_pop();
5754//.. fp_pop();
5755//.. break;
sewardj137015d2005-03-27 04:01:15 +00005756
5757 case 0xE0 ... 0xE7: /* FSUBRP %st(0),%st(?) */
5758 fp_do_oprev_ST_ST ( "subr", Iop_SubF64, 0, modrm - 0xE0, True );
5759 break;
5760
5761 case 0xE8 ... 0xEF: /* FSUBP %st(0),%st(?) */
5762 fp_do_op_ST_ST ( "sub", Iop_SubF64, 0, modrm - 0xE8, True );
5763 break;
5764
5765 case 0xF0 ... 0xF7: /* FDIVRP %st(0),%st(?) */
5766 fp_do_oprev_ST_ST ( "divr", Iop_DivF64, 0, modrm - 0xF0, True );
5767 break;
5768
5769 case 0xF8 ... 0xFF: /* FDIVP %st(0),%st(?) */
5770 fp_do_op_ST_ST ( "div", Iop_DivF64, 0, modrm - 0xF8, True );
5771 break;
5772
5773 default:
5774 goto decode_fail;
5775 }
5776
5777 }
5778 }
sewardjc49ce232005-02-25 13:03:03 +00005779
5780 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDF opcodes +-+-+-+-+-+-+-+ */
5781 else
5782 if (first_opcode == 0xDF) {
5783
5784 if (modrm < 0xC0) {
5785
5786 /* bits 5,4,3 are an opcode extension, and the modRM also
5787 specifies an address. */
5788 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
5789 delta += len;
5790
sewardj901ed122005-02-27 13:25:31 +00005791 switch (gregLO3ofRM(modrm)) {
sewardjc49ce232005-02-25 13:03:03 +00005792
sewardj434e0692005-03-27 17:36:08 +00005793 case 0: /* FILD m16int */
5794 DIP("fildw %s\n", dis_buf);
5795 fp_push();
5796 put_ST(0, unop(Iop_I32toF64,
5797 unop(Iop_16Sto32,
5798 loadLE(Ity_I16, mkexpr(addr)))));
5799 break;
5800
sewardjfcf21f32006-08-04 14:51:19 +00005801 case 1: /* FISTTPS m16 (SSE3) */
5802 DIP("fisttps %s\n", dis_buf);
5803 storeLE( mkexpr(addr),
5804 unop(Iop_32to16,
5805 binop(Iop_F64toI32, mkU32(Irrm_ZERO), get_ST(0))) );
5806 fp_pop();
5807 break;
5808
sewardjd20c8852005-01-20 20:04:07 +00005809//.. case 2: /* FIST m16 */
5810//.. DIP("fistp %s\n", dis_buf);
5811//.. storeLE( mkexpr(addr),
5812//.. binop(Iop_F64toI16, get_roundingmode(), get_ST(0)) );
5813//.. break;
sewardj6847d8c2005-05-12 19:21:55 +00005814
sewardjd20c8852005-01-20 20:04:07 +00005815//.. case 3: /* FISTP m16 */
5816//.. DIP("fistps %s\n", dis_buf);
5817//.. storeLE( mkexpr(addr),
5818//.. binop(Iop_F64toI16, get_roundingmode(), get_ST(0)) );
5819//.. fp_pop();
5820//.. break;
sewardj37d52572005-02-25 14:22:12 +00005821
5822 case 5: /* FILD m64 */
5823 DIP("fildll %s\n", dis_buf);
5824 fp_push();
5825 put_ST(0, binop(Iop_I64toF64,
5826 get_roundingmode(),
5827 loadLE(Ity_I64, mkexpr(addr))));
5828 break;
5829
sewardj6847d8c2005-05-12 19:21:55 +00005830 case 7: /* FISTP m64 */
5831 DIP("fistpll %s\n", dis_buf);
5832 storeLE( mkexpr(addr),
5833 binop(Iop_F64toI64, get_roundingmode(), get_ST(0)) );
5834 fp_pop();
5835 break;
sewardjc49ce232005-02-25 13:03:03 +00005836
5837 default:
sewardj901ed122005-02-27 13:25:31 +00005838 vex_printf("unhandled opc_aux = 0x%2x\n", gregLO3ofRM(modrm));
sewardjc49ce232005-02-25 13:03:03 +00005839 vex_printf("first_opcode == 0xDF\n");
5840 goto decode_fail;
5841 }
5842
5843 } else {
5844
5845 delta++;
5846 switch (modrm) {
5847
5848 case 0xC0: /* FFREEP %st(0) */
5849 DIP("ffreep %%st(%d)\n", 0);
5850 put_ST_TAG ( 0, mkU8(0) );
5851 fp_pop();
5852 break;
5853
sewardj4f9847d2005-07-25 11:58:34 +00005854 case 0xE0: /* FNSTSW %ax */
5855 DIP("fnstsw %%ax\n");
5856 /* Invent a plausible-looking FPU status word value and
5857 dump it in %AX:
5858 ((ftop & 7) << 11) | (c3210 & 0x4700)
5859 */
5860 putIRegRAX(
5861 2,
5862 unop(Iop_32to16,
5863 binop(Iop_Or32,
5864 binop(Iop_Shl32,
5865 binop(Iop_And32, get_ftop(), mkU32(7)),
5866 mkU8(11)),
5867 binop(Iop_And32,
5868 unop(Iop_64to32, get_C3210()),
5869 mkU32(0x4700))
5870 )));
5871 break;
sewardj924215b2005-03-26 21:50:31 +00005872
5873 case 0xE8 ... 0xEF: /* FUCOMIP %st(0),%st(?) */
5874 fp_do_ucomi_ST0_STi( (UInt)modrm - 0xE8, True );
5875 break;
5876
sewardj48a89d82005-05-06 11:50:13 +00005877 case 0xF0 ... 0xF7: /* FCOMIP %st(0),%st(?) */
5878 /* not really right since COMIP != UCOMIP */
5879 fp_do_ucomi_ST0_STi( (UInt)modrm - 0xF0, True );
5880 break;
sewardjc49ce232005-02-25 13:03:03 +00005881
5882 default:
5883 goto decode_fail;
5884 }
5885 }
5886
5887 }
sewardj8d965312005-02-25 02:48:47 +00005888
5889 else
sewardj137015d2005-03-27 04:01:15 +00005890 goto decode_fail;
sewardj8d965312005-02-25 02:48:47 +00005891
5892 *decode_ok = True;
5893 return delta;
5894
5895 decode_fail:
5896 *decode_ok = False;
5897 return delta;
5898}
5899
5900
sewardj8711f662005-05-09 17:52:56 +00005901/*------------------------------------------------------------*/
5902/*--- ---*/
5903/*--- MMX INSTRUCTIONS ---*/
5904/*--- ---*/
5905/*------------------------------------------------------------*/
5906
5907/* Effect of MMX insns on x87 FPU state (table 11-2 of
5908 IA32 arch manual, volume 3):
5909
5910 Read from, or write to MMX register (viz, any insn except EMMS):
5911 * All tags set to Valid (non-empty) -- FPTAGS[i] := nonzero
5912 * FP stack pointer set to zero
5913
5914 EMMS:
5915 * All tags set to Invalid (empty) -- FPTAGS[i] := zero
5916 * FP stack pointer set to zero
5917*/
5918
5919static void do_MMX_preamble ( void )
5920{
5921 Int i;
5922 IRArray* descr = mkIRArray( OFFB_FPTAGS, Ity_I8, 8 );
5923 IRExpr* zero = mkU32(0);
5924 IRExpr* tag1 = mkU8(1);
5925 put_ftop(zero);
5926 for (i = 0; i < 8; i++)
5927 stmt( IRStmt_PutI( descr, zero, i, tag1 ) );
5928}
5929
5930static void do_EMMS_preamble ( void )
5931{
5932 Int i;
5933 IRArray* descr = mkIRArray( OFFB_FPTAGS, Ity_I8, 8 );
5934 IRExpr* zero = mkU32(0);
5935 IRExpr* tag0 = mkU8(0);
5936 put_ftop(zero);
5937 for (i = 0; i < 8; i++)
5938 stmt( IRStmt_PutI( descr, zero, i, tag0 ) );
5939}
5940
5941
5942static IRExpr* getMMXReg ( UInt archreg )
5943{
5944 vassert(archreg < 8);
5945 return IRExpr_Get( OFFB_FPREGS + 8 * archreg, Ity_I64 );
5946}
5947
5948
5949static void putMMXReg ( UInt archreg, IRExpr* e )
5950{
5951 vassert(archreg < 8);
5952 vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_I64);
5953 stmt( IRStmt_Put( OFFB_FPREGS + 8 * archreg, e ) );
5954}
5955
5956
5957/* Helper for non-shift MMX insns. Note this is incomplete in the
5958 sense that it does not first call do_MMX_preamble() -- that is the
5959 responsibility of its caller. */
5960
5961static
5962ULong dis_MMXop_regmem_to_reg ( Prefix pfx,
sewardj270def42005-07-03 01:03:01 +00005963 Long delta,
sewardj8711f662005-05-09 17:52:56 +00005964 UChar opc,
sewardjca673ab2005-05-11 10:03:08 +00005965 HChar* name,
sewardj8711f662005-05-09 17:52:56 +00005966 Bool show_granularity )
5967{
5968 HChar dis_buf[50];
5969 UChar modrm = getUChar(delta);
5970 Bool isReg = epartIsReg(modrm);
5971 IRExpr* argL = NULL;
5972 IRExpr* argR = NULL;
5973 IRExpr* argG = NULL;
5974 IRExpr* argE = NULL;
5975 IRTemp res = newTemp(Ity_I64);
5976
5977 Bool invG = False;
5978 IROp op = Iop_INVALID;
5979 void* hAddr = NULL;
sewardjca673ab2005-05-11 10:03:08 +00005980 HChar* hName = NULL;
sewardj8711f662005-05-09 17:52:56 +00005981 Bool eLeft = False;
5982
5983# define XXX(_name) do { hAddr = &_name; hName = #_name; } while (0)
5984
5985 switch (opc) {
5986 /* Original MMX ones */
5987 case 0xFC: op = Iop_Add8x8; break;
5988 case 0xFD: op = Iop_Add16x4; break;
5989 case 0xFE: op = Iop_Add32x2; break;
5990
5991 case 0xEC: op = Iop_QAdd8Sx8; break;
5992 case 0xED: op = Iop_QAdd16Sx4; break;
5993
5994 case 0xDC: op = Iop_QAdd8Ux8; break;
5995 case 0xDD: op = Iop_QAdd16Ux4; break;
5996
5997 case 0xF8: op = Iop_Sub8x8; break;
5998 case 0xF9: op = Iop_Sub16x4; break;
5999 case 0xFA: op = Iop_Sub32x2; break;
6000
6001 case 0xE8: op = Iop_QSub8Sx8; break;
6002 case 0xE9: op = Iop_QSub16Sx4; break;
6003
6004 case 0xD8: op = Iop_QSub8Ux8; break;
6005 case 0xD9: op = Iop_QSub16Ux4; break;
6006
6007 case 0xE5: op = Iop_MulHi16Sx4; break;
6008 case 0xD5: op = Iop_Mul16x4; break;
6009 case 0xF5: XXX(amd64g_calculate_mmx_pmaddwd); break;
6010
6011 case 0x74: op = Iop_CmpEQ8x8; break;
6012 case 0x75: op = Iop_CmpEQ16x4; break;
6013 case 0x76: op = Iop_CmpEQ32x2; break;
6014
6015 case 0x64: op = Iop_CmpGT8Sx8; break;
6016 case 0x65: op = Iop_CmpGT16Sx4; break;
6017 case 0x66: op = Iop_CmpGT32Sx2; break;
6018
6019 case 0x6B: op = Iop_QNarrow32Sx2; eLeft = True; break;
6020 case 0x63: op = Iop_QNarrow16Sx4; eLeft = True; break;
6021 case 0x67: op = Iop_QNarrow16Ux4; eLeft = True; break;
6022
6023 case 0x68: op = Iop_InterleaveHI8x8; eLeft = True; break;
6024 case 0x69: op = Iop_InterleaveHI16x4; eLeft = True; break;
6025 case 0x6A: op = Iop_InterleaveHI32x2; eLeft = True; break;
6026
6027 case 0x60: op = Iop_InterleaveLO8x8; eLeft = True; break;
6028 case 0x61: op = Iop_InterleaveLO16x4; eLeft = True; break;
6029 case 0x62: op = Iop_InterleaveLO32x2; eLeft = True; break;
6030
6031 case 0xDB: op = Iop_And64; break;
6032 case 0xDF: op = Iop_And64; invG = True; break;
6033 case 0xEB: op = Iop_Or64; break;
6034 case 0xEF: /* Possibly do better here if argL and argR are the
6035 same reg */
6036 op = Iop_Xor64; break;
6037
6038 /* Introduced in SSE1 */
6039 case 0xE0: op = Iop_Avg8Ux8; break;
6040 case 0xE3: op = Iop_Avg16Ux4; break;
6041 case 0xEE: op = Iop_Max16Sx4; break;
6042 case 0xDE: op = Iop_Max8Ux8; break;
6043 case 0xEA: op = Iop_Min16Sx4; break;
6044 case 0xDA: op = Iop_Min8Ux8; break;
6045 case 0xE4: op = Iop_MulHi16Ux4; break;
sewardja7ba8c42005-05-10 20:08:34 +00006046 case 0xF6: XXX(amd64g_calculate_mmx_psadbw); break;
sewardj8711f662005-05-09 17:52:56 +00006047
6048 /* Introduced in SSE2 */
6049 case 0xD4: op = Iop_Add64; break;
6050 case 0xFB: op = Iop_Sub64; break;
6051
6052 default:
6053 vex_printf("\n0x%x\n", (Int)opc);
6054 vpanic("dis_MMXop_regmem_to_reg");
6055 }
6056
6057# undef XXX
6058
6059 argG = getMMXReg(gregLO3ofRM(modrm));
6060 if (invG)
6061 argG = unop(Iop_Not64, argG);
6062
6063 if (isReg) {
6064 delta++;
6065 argE = getMMXReg(eregLO3ofRM(modrm));
6066 } else {
6067 Int len;
6068 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
6069 delta += len;
6070 argE = loadLE(Ity_I64, mkexpr(addr));
6071 }
6072
6073 if (eLeft) {
6074 argL = argE;
6075 argR = argG;
6076 } else {
6077 argL = argG;
6078 argR = argE;
6079 }
6080
6081 if (op != Iop_INVALID) {
6082 vassert(hName == NULL);
6083 vassert(hAddr == NULL);
6084 assign(res, binop(op, argL, argR));
6085 } else {
6086 vassert(hName != NULL);
6087 vassert(hAddr != NULL);
6088 assign( res,
6089 mkIRExprCCall(
6090 Ity_I64,
6091 0/*regparms*/, hName, hAddr,
6092 mkIRExprVec_2( argL, argR )
6093 )
6094 );
6095 }
6096
6097 putMMXReg( gregLO3ofRM(modrm), mkexpr(res) );
6098
6099 DIP("%s%s %s, %s\n",
6100 name, show_granularity ? nameMMXGran(opc & 3) : "",
6101 ( isReg ? nameMMXReg(eregLO3ofRM(modrm)) : dis_buf ),
6102 nameMMXReg(gregLO3ofRM(modrm)) );
6103
6104 return delta;
6105}
6106
6107
6108/* Vector by scalar shift of G by the amount specified at the bottom
6109 of E. This is a straight copy of dis_SSE_shiftG_byE. */
6110
sewardj270def42005-07-03 01:03:01 +00006111static ULong dis_MMX_shiftG_byE ( Prefix pfx, Long delta,
sewardj8711f662005-05-09 17:52:56 +00006112 HChar* opname, IROp op )
6113{
6114 HChar dis_buf[50];
6115 Int alen, size;
6116 IRTemp addr;
6117 Bool shl, shr, sar;
6118 UChar rm = getUChar(delta);
6119 IRTemp g0 = newTemp(Ity_I64);
6120 IRTemp g1 = newTemp(Ity_I64);
6121 IRTemp amt = newTemp(Ity_I64);
6122 IRTemp amt8 = newTemp(Ity_I8);
6123
6124 if (epartIsReg(rm)) {
6125 assign( amt, getMMXReg(eregLO3ofRM(rm)) );
6126 DIP("%s %s,%s\n", opname,
6127 nameMMXReg(eregLO3ofRM(rm)),
6128 nameMMXReg(gregLO3ofRM(rm)) );
6129 delta++;
6130 } else {
6131 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
6132 assign( amt, loadLE(Ity_I64, mkexpr(addr)) );
6133 DIP("%s %s,%s\n", opname,
6134 dis_buf,
6135 nameMMXReg(gregLO3ofRM(rm)) );
6136 delta += alen;
6137 }
6138 assign( g0, getMMXReg(gregLO3ofRM(rm)) );
6139 assign( amt8, unop(Iop_64to8, mkexpr(amt)) );
6140
6141 shl = shr = sar = False;
6142 size = 0;
6143 switch (op) {
6144 case Iop_ShlN16x4: shl = True; size = 32; break;
6145 case Iop_ShlN32x2: shl = True; size = 32; break;
6146 case Iop_Shl64: shl = True; size = 64; break;
6147 case Iop_ShrN16x4: shr = True; size = 16; break;
6148 case Iop_ShrN32x2: shr = True; size = 32; break;
6149 case Iop_Shr64: shr = True; size = 64; break;
6150 case Iop_SarN16x4: sar = True; size = 16; break;
6151 case Iop_SarN32x2: sar = True; size = 32; break;
6152 default: vassert(0);
6153 }
6154
6155 if (shl || shr) {
6156 assign(
6157 g1,
6158 IRExpr_Mux0X(
6159 unop(Iop_1Uto8,binop(Iop_CmpLT64U,mkexpr(amt),mkU64(size))),
6160 mkU64(0),
6161 binop(op, mkexpr(g0), mkexpr(amt8))
6162 )
6163 );
6164 } else
6165 if (sar) {
6166 assign(
6167 g1,
6168 IRExpr_Mux0X(
6169 unop(Iop_1Uto8,binop(Iop_CmpLT64U,mkexpr(amt),mkU64(size))),
6170 binop(op, mkexpr(g0), mkU8(size-1)),
6171 binop(op, mkexpr(g0), mkexpr(amt8))
6172 )
6173 );
6174 } else {
6175 vassert(0);
6176 }
6177
6178 putMMXReg( gregLO3ofRM(rm), mkexpr(g1) );
6179 return delta;
6180}
6181
6182
sewardj3d8107c2005-05-09 22:23:38 +00006183/* Vector by scalar shift of E by an immediate byte. This is a
6184 straight copy of dis_SSE_shiftE_imm. */
6185
6186static
sewardj270def42005-07-03 01:03:01 +00006187ULong dis_MMX_shiftE_imm ( Long delta, HChar* opname, IROp op )
sewardj3d8107c2005-05-09 22:23:38 +00006188{
6189 Bool shl, shr, sar;
6190 UChar rm = getUChar(delta);
6191 IRTemp e0 = newTemp(Ity_I64);
6192 IRTemp e1 = newTemp(Ity_I64);
6193 UChar amt, size;
6194 vassert(epartIsReg(rm));
6195 vassert(gregLO3ofRM(rm) == 2
6196 || gregLO3ofRM(rm) == 4 || gregLO3ofRM(rm) == 6);
sewardjca673ab2005-05-11 10:03:08 +00006197 amt = getUChar(delta+1);
sewardj3d8107c2005-05-09 22:23:38 +00006198 delta += 2;
6199 DIP("%s $%d,%s\n", opname,
6200 (Int)amt,
6201 nameMMXReg(eregLO3ofRM(rm)) );
6202
6203 assign( e0, getMMXReg(eregLO3ofRM(rm)) );
6204
6205 shl = shr = sar = False;
6206 size = 0;
6207 switch (op) {
6208 case Iop_ShlN16x4: shl = True; size = 16; break;
6209 case Iop_ShlN32x2: shl = True; size = 32; break;
6210 case Iop_Shl64: shl = True; size = 64; break;
6211 case Iop_SarN16x4: sar = True; size = 16; break;
6212 case Iop_SarN32x2: sar = True; size = 32; break;
6213 case Iop_ShrN16x4: shr = True; size = 16; break;
6214 case Iop_ShrN32x2: shr = True; size = 32; break;
6215 case Iop_Shr64: shr = True; size = 64; break;
6216 default: vassert(0);
6217 }
6218
6219 if (shl || shr) {
6220 assign( e1, amt >= size
6221 ? mkU64(0)
6222 : binop(op, mkexpr(e0), mkU8(amt))
6223 );
6224 } else
6225 if (sar) {
6226 assign( e1, amt >= size
6227 ? binop(op, mkexpr(e0), mkU8(size-1))
6228 : binop(op, mkexpr(e0), mkU8(amt))
6229 );
6230 } else {
6231 vassert(0);
6232 }
6233
6234 putMMXReg( eregLO3ofRM(rm), mkexpr(e1) );
6235 return delta;
6236}
sewardj8711f662005-05-09 17:52:56 +00006237
6238
6239/* Completely handle all MMX instructions except emms. */
6240
6241static
sewardj270def42005-07-03 01:03:01 +00006242ULong dis_MMX ( Bool* decode_ok, Prefix pfx, Int sz, Long delta )
sewardj8711f662005-05-09 17:52:56 +00006243{
6244 Int len;
6245 UChar modrm;
6246 HChar dis_buf[50];
6247 UChar opc = getUChar(delta);
6248 delta++;
6249
6250 /* dis_MMX handles all insns except emms. */
6251 do_MMX_preamble();
6252
6253 switch (opc) {
6254
sewardj3d8107c2005-05-09 22:23:38 +00006255 case 0x6E:
6256 if (sz == 4) {
6257 /* MOVD (src)ireg32-or-mem32 (E), (dst)mmxreg (G)*/
6258 modrm = getUChar(delta);
6259 if (epartIsReg(modrm)) {
6260 delta++;
6261 putMMXReg(
6262 gregLO3ofRM(modrm),
6263 binop( Iop_32HLto64,
6264 mkU32(0),
6265 getIReg32(eregOfRexRM(pfx,modrm)) ) );
6266 DIP("movd %s, %s\n",
6267 nameIReg32(eregOfRexRM(pfx,modrm)),
6268 nameMMXReg(gregLO3ofRM(modrm)));
6269 } else {
6270 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
6271 delta += len;
6272 putMMXReg(
6273 gregLO3ofRM(modrm),
6274 binop( Iop_32HLto64,
6275 mkU32(0),
6276 loadLE(Ity_I32, mkexpr(addr)) ) );
6277 DIP("movd %s, %s\n", dis_buf, nameMMXReg(gregLO3ofRM(modrm)));
6278 }
6279 }
6280 else
6281 if (sz == 8) {
6282 /* MOVD (src)ireg64-or-mem64 (E), (dst)mmxreg (G)*/
6283 modrm = getUChar(delta);
6284 if (epartIsReg(modrm)) {
6285 delta++;
6286 putMMXReg( gregLO3ofRM(modrm),
6287 getIReg64(eregOfRexRM(pfx,modrm)) );
6288 DIP("movd %s, %s\n",
6289 nameIReg64(eregOfRexRM(pfx,modrm)),
6290 nameMMXReg(gregLO3ofRM(modrm)));
6291 } else {
6292 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
6293 delta += len;
6294 putMMXReg( gregLO3ofRM(modrm),
6295 loadLE(Ity_I64, mkexpr(addr)) );
6296 DIP("movd{64} %s, %s\n", dis_buf, nameMMXReg(gregLO3ofRM(modrm)));
6297 }
6298 }
6299 else {
6300 goto mmx_decode_failure;
6301 }
6302 break;
6303
6304 case 0x7E:
6305 if (sz == 4) {
6306 /* MOVD (src)mmxreg (G), (dst)ireg32-or-mem32 (E) */
6307 modrm = getUChar(delta);
6308 if (epartIsReg(modrm)) {
6309 delta++;
6310 putIReg32( eregOfRexRM(pfx,modrm),
6311 unop(Iop_64to32, getMMXReg(gregLO3ofRM(modrm)) ) );
6312 DIP("movd %s, %s\n",
6313 nameMMXReg(gregLO3ofRM(modrm)),
6314 nameIReg32(eregOfRexRM(pfx,modrm)));
6315 } else {
6316 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
6317 delta += len;
6318 storeLE( mkexpr(addr),
6319 unop(Iop_64to32, getMMXReg(gregLO3ofRM(modrm)) ) );
6320 DIP("movd %s, %s\n", nameMMXReg(gregLO3ofRM(modrm)), dis_buf);
6321 }
6322 }
6323 else
6324 if (sz == 8) {
6325 /* MOVD (src)mmxreg (G), (dst)ireg64-or-mem64 (E) */
6326 modrm = getUChar(delta);
6327 if (epartIsReg(modrm)) {
6328 delta++;
6329 putIReg64( eregOfRexRM(pfx,modrm),
6330 getMMXReg(gregLO3ofRM(modrm)) );
6331 DIP("movd %s, %s\n",
6332 nameMMXReg(gregLO3ofRM(modrm)),
6333 nameIReg64(eregOfRexRM(pfx,modrm)));
6334 } else {
6335 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
6336 delta += len;
6337 storeLE( mkexpr(addr),
6338 getMMXReg(gregLO3ofRM(modrm)) );
6339 DIP("movd{64} %s, %s\n", nameMMXReg(gregLO3ofRM(modrm)), dis_buf);
6340 }
6341 } else {
6342 goto mmx_decode_failure;
6343 }
6344 break;
sewardj8711f662005-05-09 17:52:56 +00006345
6346 case 0x6F:
6347 /* MOVQ (src)mmxreg-or-mem, (dst)mmxreg */
6348 if (sz != 4)
6349 goto mmx_decode_failure;
6350 modrm = getUChar(delta);
6351 if (epartIsReg(modrm)) {
6352 delta++;
6353 putMMXReg( gregLO3ofRM(modrm), getMMXReg(eregLO3ofRM(modrm)) );
6354 DIP("movq %s, %s\n",
6355 nameMMXReg(eregLO3ofRM(modrm)),
6356 nameMMXReg(gregLO3ofRM(modrm)));
6357 } else {
6358 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
6359 delta += len;
6360 putMMXReg( gregLO3ofRM(modrm), loadLE(Ity_I64, mkexpr(addr)) );
6361 DIP("movq %s, %s\n",
6362 dis_buf, nameMMXReg(gregLO3ofRM(modrm)));
6363 }
6364 break;
6365
6366 case 0x7F:
6367 /* MOVQ (src)mmxreg, (dst)mmxreg-or-mem */
6368 if (sz != 4)
6369 goto mmx_decode_failure;
6370 modrm = getUChar(delta);
6371 if (epartIsReg(modrm)) {
6372 /* Fall through. The assembler doesn't appear to generate
6373 these. */
6374 goto mmx_decode_failure;
6375 } else {
6376 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
6377 delta += len;
6378 storeLE( mkexpr(addr), getMMXReg(gregLO3ofRM(modrm)) );
6379 DIP("mov(nt)q %s, %s\n",
6380 nameMMXReg(gregLO3ofRM(modrm)), dis_buf);
6381 }
6382 break;
6383
6384 case 0xFC:
6385 case 0xFD:
6386 case 0xFE: /* PADDgg (src)mmxreg-or-mem, (dst)mmxreg */
6387 if (sz != 4)
6388 goto mmx_decode_failure;
6389 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "padd", True );
6390 break;
6391
6392 case 0xEC:
6393 case 0xED: /* PADDSgg (src)mmxreg-or-mem, (dst)mmxreg */
6394 if (sz != 4)
6395 goto mmx_decode_failure;
6396 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "padds", True );
6397 break;
6398
6399 case 0xDC:
6400 case 0xDD: /* PADDUSgg (src)mmxreg-or-mem, (dst)mmxreg */
6401 if (sz != 4)
6402 goto mmx_decode_failure;
6403 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "paddus", True );
6404 break;
6405
6406 case 0xF8:
6407 case 0xF9:
6408 case 0xFA: /* PSUBgg (src)mmxreg-or-mem, (dst)mmxreg */
6409 if (sz != 4)
6410 goto mmx_decode_failure;
6411 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "psub", True );
6412 break;
6413
6414 case 0xE8:
6415 case 0xE9: /* PSUBSgg (src)mmxreg-or-mem, (dst)mmxreg */
6416 if (sz != 4)
6417 goto mmx_decode_failure;
6418 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "psubs", True );
6419 break;
6420
6421 case 0xD8:
6422 case 0xD9: /* PSUBUSgg (src)mmxreg-or-mem, (dst)mmxreg */
6423 if (sz != 4)
6424 goto mmx_decode_failure;
6425 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "psubus", True );
6426 break;
6427
6428 case 0xE5: /* PMULHW (src)mmxreg-or-mem, (dst)mmxreg */
6429 if (sz != 4)
6430 goto mmx_decode_failure;
6431 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "pmulhw", False );
6432 break;
6433
6434 case 0xD5: /* PMULLW (src)mmxreg-or-mem, (dst)mmxreg */
6435 if (sz != 4)
6436 goto mmx_decode_failure;
6437 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "pmullw", False );
6438 break;
6439
6440 case 0xF5: /* PMADDWD (src)mmxreg-or-mem, (dst)mmxreg */
6441 vassert(sz == 4);
6442 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "pmaddwd", False );
6443 break;
6444
6445 case 0x74:
6446 case 0x75:
6447 case 0x76: /* PCMPEQgg (src)mmxreg-or-mem, (dst)mmxreg */
6448 if (sz != 4)
6449 goto mmx_decode_failure;
6450 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "pcmpeq", True );
6451 break;
6452
6453 case 0x64:
6454 case 0x65:
6455 case 0x66: /* PCMPGTgg (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, "pcmpgt", True );
6459 break;
6460
6461 case 0x6B: /* PACKSSDW (src)mmxreg-or-mem, (dst)mmxreg */
6462 if (sz != 4)
6463 goto mmx_decode_failure;
6464 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "packssdw", False );
6465 break;
6466
6467 case 0x63: /* PACKSSWB (src)mmxreg-or-mem, (dst)mmxreg */
6468 if (sz != 4)
6469 goto mmx_decode_failure;
6470 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "packsswb", False );
6471 break;
6472
6473 case 0x67: /* PACKUSWB (src)mmxreg-or-mem, (dst)mmxreg */
6474 if (sz != 4)
6475 goto mmx_decode_failure;
6476 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "packuswb", False );
6477 break;
6478
6479 case 0x68:
6480 case 0x69:
6481 case 0x6A: /* PUNPCKHgg (src)mmxreg-or-mem, (dst)mmxreg */
6482 if (sz != 4)
6483 goto mmx_decode_failure;
6484 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "punpckh", True );
6485 break;
6486
6487 case 0x60:
6488 case 0x61:
6489 case 0x62: /* PUNPCKLgg (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, "punpckl", True );
6493 break;
6494
6495 case 0xDB: /* PAND (src)mmxreg-or-mem, (dst)mmxreg */
6496 if (sz != 4)
6497 goto mmx_decode_failure;
6498 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "pand", False );
6499 break;
6500
6501 case 0xDF: /* PANDN (src)mmxreg-or-mem, (dst)mmxreg */
6502 if (sz != 4)
6503 goto mmx_decode_failure;
6504 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "pandn", False );
6505 break;
6506
6507 case 0xEB: /* POR (src)mmxreg-or-mem, (dst)mmxreg */
6508 if (sz != 4)
6509 goto mmx_decode_failure;
6510 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "por", False );
6511 break;
6512
6513 case 0xEF: /* PXOR (src)mmxreg-or-mem, (dst)mmxreg */
6514 if (sz != 4)
6515 goto mmx_decode_failure;
6516 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "pxor", False );
6517 break;
6518
6519# define SHIFT_BY_REG(_name,_op) \
6520 delta = dis_MMX_shiftG_byE(pfx, delta, _name, _op); \
6521 break;
6522
6523 /* PSLLgg (src)mmxreg-or-mem, (dst)mmxreg */
6524 case 0xF1: SHIFT_BY_REG("psllw", Iop_ShlN16x4);
6525 case 0xF2: SHIFT_BY_REG("pslld", Iop_ShlN32x2);
6526 case 0xF3: SHIFT_BY_REG("psllq", Iop_Shl64);
6527
6528 /* PSRLgg (src)mmxreg-or-mem, (dst)mmxreg */
6529 case 0xD1: SHIFT_BY_REG("psrlw", Iop_ShrN16x4);
6530 case 0xD2: SHIFT_BY_REG("psrld", Iop_ShrN32x2);
6531 case 0xD3: SHIFT_BY_REG("psrlq", Iop_Shr64);
6532
6533 /* PSRAgg (src)mmxreg-or-mem, (dst)mmxreg */
6534 case 0xE1: SHIFT_BY_REG("psraw", Iop_SarN16x4);
6535 case 0xE2: SHIFT_BY_REG("psrad", Iop_SarN32x2);
6536
6537# undef SHIFT_BY_REG
sewardj3d8107c2005-05-09 22:23:38 +00006538
6539 case 0x71:
6540 case 0x72:
6541 case 0x73: {
6542 /* (sz==4): PSLLgg/PSRAgg/PSRLgg mmxreg by imm8 */
sewardjca673ab2005-05-11 10:03:08 +00006543 UChar byte2, subopc;
sewardj3d8107c2005-05-09 22:23:38 +00006544 if (sz != 4)
6545 goto mmx_decode_failure;
sewardjca673ab2005-05-11 10:03:08 +00006546 byte2 = getUChar(delta); /* amode / sub-opcode */
6547 subopc = toUChar( (byte2 >> 3) & 7 );
sewardj3d8107c2005-05-09 22:23:38 +00006548
6549# define SHIFT_BY_IMM(_name,_op) \
6550 do { delta = dis_MMX_shiftE_imm(delta,_name,_op); \
6551 } while (0)
6552
6553 if (subopc == 2 /*SRL*/ && opc == 0x71)
6554 SHIFT_BY_IMM("psrlw", Iop_ShrN16x4);
6555 else if (subopc == 2 /*SRL*/ && opc == 0x72)
6556 SHIFT_BY_IMM("psrld", Iop_ShrN32x2);
6557 else if (subopc == 2 /*SRL*/ && opc == 0x73)
6558 SHIFT_BY_IMM("psrlq", Iop_Shr64);
6559
6560 else if (subopc == 4 /*SAR*/ && opc == 0x71)
6561 SHIFT_BY_IMM("psraw", Iop_SarN16x4);
6562 else if (subopc == 4 /*SAR*/ && opc == 0x72)
6563 SHIFT_BY_IMM("psrad", Iop_SarN32x2);
6564
6565 else if (subopc == 6 /*SHL*/ && opc == 0x71)
6566 SHIFT_BY_IMM("psllw", Iop_ShlN16x4);
6567 else if (subopc == 6 /*SHL*/ && opc == 0x72)
6568 SHIFT_BY_IMM("pslld", Iop_ShlN32x2);
6569 else if (subopc == 6 /*SHL*/ && opc == 0x73)
6570 SHIFT_BY_IMM("psllq", Iop_Shl64);
6571
6572 else goto mmx_decode_failure;
6573
6574# undef SHIFT_BY_IMM
6575 break;
6576 }
sewardj8711f662005-05-09 17:52:56 +00006577
6578 /* --- MMX decode failure --- */
6579 default:
6580 mmx_decode_failure:
6581 *decode_ok = False;
6582 return delta; /* ignored */
6583
6584 }
6585
6586 *decode_ok = True;
6587 return delta;
6588}
6589
6590
sewardj33ef9c22005-11-04 20:05:57 +00006591/*------------------------------------------------------------*/
6592/*--- More misc arithmetic and other obscure insns. ---*/
6593/*------------------------------------------------------------*/
6594
6595/* Generate base << amt with vacated places filled with stuff
6596 from xtra. amt guaranteed in 0 .. 63. */
6597static
6598IRExpr* shiftL64_with_extras ( IRTemp base, IRTemp xtra, IRTemp amt )
6599{
6600 /* if amt == 0
6601 then base
6602 else (base << amt) | (xtra >>u (64-amt))
6603 */
6604 return
6605 IRExpr_Mux0X(
6606 mkexpr(amt),
6607 mkexpr(base),
6608 binop(Iop_Or64,
6609 binop(Iop_Shl64, mkexpr(base), mkexpr(amt)),
6610 binop(Iop_Shr64, mkexpr(xtra),
6611 binop(Iop_Sub8, mkU8(64), mkexpr(amt)))
6612 )
6613 );
6614}
6615
6616/* Generate base >>u amt with vacated places filled with stuff
6617 from xtra. amt guaranteed in 0 .. 63. */
6618static
6619IRExpr* shiftR64_with_extras ( IRTemp xtra, IRTemp base, IRTemp amt )
6620{
6621 /* if amt == 0
6622 then base
6623 else (base >>u amt) | (xtra << (64-amt))
6624 */
6625 return
6626 IRExpr_Mux0X(
6627 mkexpr(amt),
6628 mkexpr(base),
6629 binop(Iop_Or64,
6630 binop(Iop_Shr64, mkexpr(base), mkexpr(amt)),
6631 binop(Iop_Shl64, mkexpr(xtra),
6632 binop(Iop_Sub8, mkU8(64), mkexpr(amt)))
6633 )
6634 );
6635}
6636
6637/* Double length left and right shifts. Apparently only required in
6638 v-size (no b- variant). */
6639static
6640ULong dis_SHLRD_Gv_Ev ( Prefix pfx,
6641 Long delta, UChar modrm,
6642 Int sz,
6643 IRExpr* shift_amt,
6644 Bool amt_is_literal,
sewardjf5268432005-11-05 02:58:55 +00006645 HChar* shift_amt_txt,
sewardj33ef9c22005-11-04 20:05:57 +00006646 Bool left_shift )
6647{
6648 /* shift_amt :: Ity_I8 is the amount to shift. shift_amt_txt is used
6649 for printing it. And eip on entry points at the modrm byte. */
6650 Int len;
6651 HChar dis_buf[50];
6652
6653 IRType ty = szToITy(sz);
6654 IRTemp gsrc = newTemp(ty);
6655 IRTemp esrc = newTemp(ty);
6656 IRTemp addr = IRTemp_INVALID;
6657 IRTemp tmpSH = newTemp(Ity_I8);
6658 IRTemp tmpSS = newTemp(Ity_I8);
6659 IRTemp tmp64 = IRTemp_INVALID;
6660 IRTemp res64 = IRTemp_INVALID;
6661 IRTemp rss64 = IRTemp_INVALID;
6662 IRTemp resTy = IRTemp_INVALID;
6663 IRTemp rssTy = IRTemp_INVALID;
6664 Int mask = sz==8 ? 63 : 31;
6665
6666 vassert(sz == 2 || sz == 4 || sz == 8);
6667
6668 /* The E-part is the destination; this is shifted. The G-part
6669 supplies bits to be shifted into the E-part, but is not
6670 changed.
6671
6672 If shifting left, form a double-length word with E at the top
6673 and G at the bottom, and shift this left. The result is then in
6674 the high part.
6675
6676 If shifting right, form a double-length word with G at the top
6677 and E at the bottom, and shift this right. The result is then
6678 at the bottom. */
6679
6680 /* Fetch the operands. */
6681
6682 assign( gsrc, getIRegG(sz, pfx, modrm) );
6683
6684 if (epartIsReg(modrm)) {
6685 delta++;
6686 assign( esrc, getIRegE(sz, pfx, modrm) );
6687 DIP("sh%cd%c %s, %s, %s\n",
6688 ( left_shift ? 'l' : 'r' ), nameISize(sz),
6689 shift_amt_txt,
6690 nameIRegG(sz, pfx, modrm), nameIRegE(sz, pfx, modrm));
6691 } else {
sewardj75ce3652005-11-04 20:49:36 +00006692 addr = disAMode ( &len, pfx, delta, dis_buf,
6693 /* # bytes following amode */
6694 amt_is_literal ? 1 : 0 );
sewardj33ef9c22005-11-04 20:05:57 +00006695 delta += len;
6696 assign( esrc, loadLE(ty, mkexpr(addr)) );
6697 DIP("sh%cd%c %s, %s, %s\n",
6698 ( left_shift ? 'l' : 'r' ), nameISize(sz),
6699 shift_amt_txt,
6700 nameIRegG(sz, pfx, modrm), dis_buf);
6701 }
6702
6703 /* Calculate the masked shift amount (tmpSH), the masked subshift
6704 amount (tmpSS), the shifted value (res64) and the subshifted
6705 value (rss64). */
6706
6707 assign( tmpSH, binop(Iop_And8, shift_amt, mkU8(mask)) );
6708 assign( tmpSS, binop(Iop_And8,
6709 binop(Iop_Sub8, mkexpr(tmpSH), mkU8(1) ),
6710 mkU8(mask)));
6711
6712 tmp64 = newTemp(Ity_I64);
6713 res64 = newTemp(Ity_I64);
6714 rss64 = newTemp(Ity_I64);
6715
6716 if (sz == 2 || sz == 4) {
6717
6718 /* G is xtra; E is data */
6719 /* what a freaking nightmare: */
6720 if (sz == 4 && left_shift) {
6721 assign( tmp64, binop(Iop_32HLto64, mkexpr(esrc), mkexpr(gsrc)) );
6722 assign( res64,
6723 binop(Iop_Shr64,
6724 binop(Iop_Shl64, mkexpr(tmp64), mkexpr(tmpSH)),
6725 mkU8(32)) );
6726 assign( rss64,
6727 binop(Iop_Shr64,
6728 binop(Iop_Shl64, mkexpr(tmp64), mkexpr(tmpSS)),
6729 mkU8(32)) );
6730 }
6731 else
6732 if (sz == 4 && !left_shift) {
6733 assign( tmp64, binop(Iop_32HLto64, mkexpr(gsrc), mkexpr(esrc)) );
6734 assign( res64, binop(Iop_Shr64, mkexpr(tmp64), mkexpr(tmpSH)) );
6735 assign( rss64, binop(Iop_Shr64, mkexpr(tmp64), mkexpr(tmpSS)) );
6736 }
6737 else
6738 if (sz == 2 && left_shift) {
6739 assign( tmp64,
6740 binop(Iop_32HLto64,
6741 binop(Iop_16HLto32, mkexpr(esrc), mkexpr(gsrc)),
6742 binop(Iop_16HLto32, mkexpr(gsrc), mkexpr(gsrc))
6743 ));
6744 /* result formed by shifting [esrc'gsrc'gsrc'gsrc] */
6745 assign( res64,
6746 binop(Iop_Shr64,
6747 binop(Iop_Shl64, mkexpr(tmp64), mkexpr(tmpSH)),
6748 mkU8(48)) );
6749 /* subshift formed by shifting [esrc'0000'0000'0000] */
6750 assign( rss64,
6751 binop(Iop_Shr64,
6752 binop(Iop_Shl64,
6753 binop(Iop_Shl64, unop(Iop_16Uto64, mkexpr(esrc)),
6754 mkU8(48)),
6755 mkexpr(tmpSS)),
6756 mkU8(48)) );
6757 }
6758 else
6759 if (sz == 2 && !left_shift) {
6760 assign( tmp64,
6761 binop(Iop_32HLto64,
6762 binop(Iop_16HLto32, mkexpr(gsrc), mkexpr(gsrc)),
6763 binop(Iop_16HLto32, mkexpr(gsrc), mkexpr(esrc))
6764 ));
6765 /* result formed by shifting [gsrc'gsrc'gsrc'esrc] */
6766 assign( res64, binop(Iop_Shr64, mkexpr(tmp64), mkexpr(tmpSH)) );
6767 /* subshift formed by shifting [0000'0000'0000'esrc] */
6768 assign( rss64, binop(Iop_Shr64,
6769 unop(Iop_16Uto64, mkexpr(esrc)),
6770 mkexpr(tmpSS)) );
6771 }
6772
6773 } else {
6774
6775 vassert(sz == 8);
6776 if (left_shift) {
6777 assign( res64, shiftL64_with_extras( esrc, gsrc, tmpSH ));
6778 assign( rss64, shiftL64_with_extras( esrc, gsrc, tmpSS ));
6779 } else {
6780 assign( res64, shiftR64_with_extras( gsrc, esrc, tmpSH ));
6781 assign( rss64, shiftR64_with_extras( gsrc, esrc, tmpSS ));
6782 }
6783
6784 }
6785
6786 resTy = newTemp(ty);
6787 rssTy = newTemp(ty);
6788 assign( resTy, narrowTo(ty, mkexpr(res64)) );
6789 assign( rssTy, narrowTo(ty, mkexpr(rss64)) );
6790
6791 /* Put result back and write the flags thunk. */
6792 setFlags_DEP1_DEP2_shift ( left_shift ? Iop_Shl64 : Iop_Sar64,
6793 resTy, rssTy, ty, tmpSH );
6794
6795 if (epartIsReg(modrm)) {
6796 putIRegE(sz, pfx, modrm, mkexpr(resTy));
6797 } else {
6798 storeLE( mkexpr(addr), mkexpr(resTy) );
6799 }
6800
6801 if (amt_is_literal) delta++;
6802 return delta;
6803}
sewardj9ed16802005-08-24 10:46:19 +00006804
6805
6806/* Handle BT/BTS/BTR/BTC Gv, Ev. Apparently b-size is not
6807 required. */
6808
6809typedef enum { BtOpNone, BtOpSet, BtOpReset, BtOpComp } BtOp;
6810
6811static HChar* nameBtOp ( BtOp op )
6812{
6813 switch (op) {
6814 case BtOpNone: return "";
6815 case BtOpSet: return "s";
6816 case BtOpReset: return "r";
6817 case BtOpComp: return "c";
6818 default: vpanic("nameBtOp(amd64)");
6819 }
6820}
6821
6822
6823static
6824ULong dis_bt_G_E ( Prefix pfx, Int sz, Long delta, BtOp op )
6825{
6826 HChar dis_buf[50];
6827 UChar modrm;
6828 Int len;
6829 IRTemp t_fetched, t_bitno0, t_bitno1, t_bitno2, t_addr0,
6830 t_addr1, t_rsp, t_mask;
6831
6832 vassert(sz == 2 || sz == 4 || sz == 8);
6833
6834 t_fetched = t_bitno0 = t_bitno1 = t_bitno2
6835 = t_addr0 = t_addr1 = t_rsp = t_mask = IRTemp_INVALID;
6836
6837 t_fetched = newTemp(Ity_I8);
6838 t_bitno0 = newTemp(Ity_I64);
6839 t_bitno1 = newTemp(Ity_I64);
6840 t_bitno2 = newTemp(Ity_I8);
6841 t_addr1 = newTemp(Ity_I64);
6842 modrm = getUChar(delta);
6843
6844 assign( t_bitno0, widenSto64(getIRegG(sz, pfx, modrm)) );
6845
6846 if (epartIsReg(modrm)) {
6847 delta++;
6848 /* Get it onto the client's stack. */
6849 t_rsp = newTemp(Ity_I64);
6850 t_addr0 = newTemp(Ity_I64);
6851
6852 assign( t_rsp, binop(Iop_Sub64, getIReg64(R_RSP), mkU64(sz)) );
6853 putIReg64(R_RSP, mkexpr(t_rsp));
6854
6855 storeLE( mkexpr(t_rsp), getIRegE(sz, pfx, modrm) );
6856
6857 /* Make t_addr0 point at it. */
6858 assign( t_addr0, mkexpr(t_rsp) );
6859
6860 /* Mask out upper bits of the shift amount, since we're doing a
6861 reg. */
6862 assign( t_bitno1, binop(Iop_And64,
6863 mkexpr(t_bitno0),
6864 mkU64(sz == 8 ? 63 : sz == 4 ? 31 : 15)) );
6865
6866 } else {
6867 t_addr0 = disAMode ( &len, pfx, delta, dis_buf, 0 );
6868 delta += len;
6869 assign( t_bitno1, mkexpr(t_bitno0) );
6870 }
6871
6872 /* At this point: t_addr0 is the address being operated on. If it
6873 was a reg, we will have pushed it onto the client's stack.
6874 t_bitno1 is the bit number, suitably masked in the case of a
6875 reg. */
6876
6877 /* Now the main sequence. */
6878 assign( t_addr1,
6879 binop(Iop_Add64,
6880 mkexpr(t_addr0),
6881 binop(Iop_Sar64, mkexpr(t_bitno1), mkU8(3))) );
6882
6883 /* t_addr1 now holds effective address */
6884
6885 assign( t_bitno2,
6886 unop(Iop_64to8,
6887 binop(Iop_And64, mkexpr(t_bitno1), mkU64(7))) );
6888
6889 /* t_bitno2 contains offset of bit within byte */
6890
6891 if (op != BtOpNone) {
6892 t_mask = newTemp(Ity_I8);
6893 assign( t_mask, binop(Iop_Shl8, mkU8(1), mkexpr(t_bitno2)) );
6894 }
6895
6896 /* t_mask is now a suitable byte mask */
6897
6898 assign( t_fetched, loadLE(Ity_I8, mkexpr(t_addr1)) );
6899
6900 if (op != BtOpNone) {
6901 switch (op) {
6902 case BtOpSet:
6903 storeLE( mkexpr(t_addr1),
6904 binop(Iop_Or8, mkexpr(t_fetched),
6905 mkexpr(t_mask)) );
6906 break;
6907 case BtOpComp:
6908 storeLE( mkexpr(t_addr1),
6909 binop(Iop_Xor8, mkexpr(t_fetched),
6910 mkexpr(t_mask)) );
6911 break;
6912 case BtOpReset:
6913 storeLE( mkexpr(t_addr1),
6914 binop(Iop_And8, mkexpr(t_fetched),
6915 unop(Iop_Not8, mkexpr(t_mask))) );
6916 break;
6917 default:
6918 vpanic("dis_bt_G_E(amd64)");
6919 }
6920 }
6921
6922 /* Side effect done; now get selected bit into Carry flag */
6923 /* Flags: C=selected bit, O,S,Z,A,P undefined, so are set to zero. */
6924 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(AMD64G_CC_OP_COPY) ));
6925 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
6926 stmt( IRStmt_Put(
6927 OFFB_CC_DEP1,
6928 binop(Iop_And64,
6929 binop(Iop_Shr64,
6930 unop(Iop_8Uto64, mkexpr(t_fetched)),
6931 mkexpr(t_bitno2)),
6932 mkU64(1)))
6933 );
6934 /* Set NDEP even though it isn't used. This makes redundant-PUT
6935 elimination of previous stores to this field work better. */
6936 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU64(0) ));
6937
6938 /* Move reg operand from stack back to reg */
6939 if (epartIsReg(modrm)) {
6940 /* t_esp still points at it. */
sewardj25d23862006-05-12 17:47:21 +00006941 /* only write the reg if actually modifying it; doing otherwise
6942 zeroes the top half erroneously when doing btl due to
6943 standard zero-extend rule */
6944 if (op != BtOpNone)
6945 putIRegE(sz, pfx, modrm, loadLE(szToITy(sz), mkexpr(t_rsp)) );
sewardj9ed16802005-08-24 10:46:19 +00006946 putIReg64(R_RSP, binop(Iop_Add64, mkexpr(t_rsp), mkU64(sz)) );
6947 }
6948
6949 DIP("bt%s%c %s, %s\n",
6950 nameBtOp(op), nameISize(sz), nameIRegG(sz, pfx, modrm),
6951 ( epartIsReg(modrm) ? nameIRegE(sz, pfx, modrm) : dis_buf ) );
6952
6953 return delta;
6954}
sewardjf53b7352005-04-06 20:01:56 +00006955
6956
6957
6958/* Handle BSF/BSR. Only v-size seems necessary. */
6959static
sewardj270def42005-07-03 01:03:01 +00006960ULong dis_bs_E_G ( Prefix pfx, Int sz, Long delta, Bool fwds )
sewardjf53b7352005-04-06 20:01:56 +00006961{
6962 Bool isReg;
6963 UChar modrm;
6964 HChar dis_buf[50];
6965
6966 IRType ty = szToITy(sz);
6967 IRTemp src = newTemp(ty);
6968 IRTemp dst = newTemp(ty);
6969 IRTemp src64 = newTemp(Ity_I64);
6970 IRTemp dst64 = newTemp(Ity_I64);
6971 IRTemp src8 = newTemp(Ity_I8);
6972
6973 vassert(sz == 8 || sz == 4 || sz == 2);
6974
6975 modrm = getUChar(delta);
6976 isReg = epartIsReg(modrm);
6977 if (isReg) {
6978 delta++;
6979 assign( src, getIRegE(sz, pfx, modrm) );
6980 } else {
6981 Int len;
6982 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
6983 delta += len;
6984 assign( src, loadLE(ty, mkexpr(addr)) );
6985 }
6986
6987 DIP("bs%c%c %s, %s\n",
6988 fwds ? 'f' : 'r', nameISize(sz),
6989 ( isReg ? nameIRegE(sz, pfx, modrm) : dis_buf ),
6990 nameIRegG(sz, pfx, modrm));
6991
6992 /* First, widen src to 64 bits if it is not already. */
6993 assign( src64, widenUto64(mkexpr(src)) );
6994
6995 /* Generate an 8-bit expression which is zero iff the
6996 original is zero, and nonzero otherwise */
6997 assign( src8,
6998 unop(Iop_1Uto8,
6999 binop(Iop_CmpNE64,
7000 mkexpr(src64), mkU64(0))) );
7001
7002 /* Flags: Z is 1 iff source value is zero. All others
7003 are undefined -- we force them to zero. */
7004 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(AMD64G_CC_OP_COPY) ));
7005 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
7006 stmt( IRStmt_Put(
7007 OFFB_CC_DEP1,
7008 IRExpr_Mux0X( mkexpr(src8),
7009 /* src==0 */
7010 mkU64(AMD64G_CC_MASK_Z),
7011 /* src!=0 */
7012 mkU64(0)
7013 )
7014 ));
7015 /* Set NDEP even though it isn't used. This makes redundant-PUT
7016 elimination of previous stores to this field work better. */
7017 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU64(0) ));
7018
7019 /* Result: iff source value is zero, we can't use
7020 Iop_Clz64/Iop_Ctz64 as they have no defined result in that case.
7021 But anyway, amd64 semantics say the result is undefined in
7022 such situations. Hence handle the zero case specially. */
7023
7024 /* Bleh. What we compute:
7025
7026 bsf64: if src == 0 then {dst is unchanged}
7027 else Ctz64(src)
7028
7029 bsr64: if src == 0 then {dst is unchanged}
7030 else 63 - Clz64(src)
7031
7032 bsf32: if src == 0 then {dst is unchanged}
7033 else Ctz64(32Uto64(src))
7034
7035 bsr32: if src == 0 then {dst is unchanged}
7036 else 63 - Clz64(32Uto64(src))
7037
7038 bsf16: if src == 0 then {dst is unchanged}
7039 else Ctz64(32Uto64(16Uto32(src)))
7040
7041 bsr16: if src == 0 then {dst is unchanged}
7042 else 63 - Clz64(32Uto64(16Uto32(src)))
7043 */
7044
7045 /* The main computation, guarding against zero. */
7046 assign( dst64,
7047 IRExpr_Mux0X(
7048 mkexpr(src8),
7049 /* src == 0 -- leave dst unchanged */
7050 widenUto64( getIRegG( sz, pfx, modrm ) ),
7051 /* src != 0 */
7052 fwds ? unop(Iop_Ctz64, mkexpr(src64))
7053 : binop(Iop_Sub64,
7054 mkU64(63),
7055 unop(Iop_Clz64, mkexpr(src64)))
7056 )
7057 );
7058
7059 if (sz == 2)
sewardje58967e2005-04-27 11:50:56 +00007060 assign( dst, unop(Iop_64to16, mkexpr(dst64)) );
sewardjf53b7352005-04-06 20:01:56 +00007061 else
7062 if (sz == 4)
7063 assign( dst, unop(Iop_64to32, mkexpr(dst64)) );
7064 else
7065 assign( dst, mkexpr(dst64) );
7066
7067 /* dump result back */
7068 putIRegG( sz, pfx, modrm, mkexpr(dst) );
7069
7070 return delta;
7071}
sewardja6b93d12005-02-17 09:28:28 +00007072
7073
7074/* swap rAX with the reg specified by reg and REX.B */
7075static
sewardj5b470602005-02-27 13:10:48 +00007076void codegen_xchg_rAX_Reg ( Prefix pfx, Int sz, UInt regLo3 )
sewardja6b93d12005-02-17 09:28:28 +00007077{
7078 IRType ty = szToITy(sz);
7079 IRTemp t1 = newTemp(ty);
7080 IRTemp t2 = newTemp(ty);
sewardj2d4fcd52005-05-18 11:47:47 +00007081 vassert(sz == 4 || sz == 8);
sewardj5b470602005-02-27 13:10:48 +00007082 vassert(regLo3 < 8);
sewardj2d4fcd52005-05-18 11:47:47 +00007083 if (sz == 8) {
7084 assign( t1, getIReg64(R_RAX) );
7085 assign( t2, getIRegRexB(8, pfx, regLo3) );
7086 putIReg64( R_RAX, mkexpr(t2) );
7087 putIRegRexB(8, pfx, regLo3, mkexpr(t1) );
7088 } else {
7089 assign( t1, getIReg32(R_RAX) );
7090 assign( t2, getIRegRexB(4, pfx, regLo3) );
7091 putIReg32( R_RAX, mkexpr(t2) );
7092 putIRegRexB(4, pfx, regLo3, mkexpr(t1) );
7093 }
sewardja6b93d12005-02-17 09:28:28 +00007094 DIP("xchg%c %s, %s\n",
sewardj5b470602005-02-27 13:10:48 +00007095 nameISize(sz), nameIRegRAX(sz),
sewardj2d4fcd52005-05-18 11:47:47 +00007096 nameIRegRexB(sz,pfx, regLo3));
sewardja6b93d12005-02-17 09:28:28 +00007097}
7098
7099
sewardjd20c8852005-01-20 20:04:07 +00007100//.. static
7101//.. void codegen_SAHF ( void )
7102//.. {
7103//.. /* Set the flags to:
7104//.. (x86g_calculate_flags_all() & X86G_CC_MASK_O) -- retain the old O flag
7105//.. | (%AH & (X86G_CC_MASK_S|X86G_CC_MASK_Z|X86G_CC_MASK_A
7106//.. |X86G_CC_MASK_P|X86G_CC_MASK_C)
7107//.. */
7108//.. UInt mask_SZACP = X86G_CC_MASK_S|X86G_CC_MASK_Z|X86G_CC_MASK_A
7109//.. |X86G_CC_MASK_C|X86G_CC_MASK_P;
7110//.. IRTemp oldflags = newTemp(Ity_I32);
7111//.. assign( oldflags, mk_x86g_calculate_eflags_all() );
7112//.. stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
7113//.. stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
7114//.. stmt( IRStmt_Put( OFFB_CC_DEP1,
7115//.. binop(Iop_Or32,
7116//.. binop(Iop_And32, mkexpr(oldflags), mkU32(X86G_CC_MASK_O)),
7117//.. binop(Iop_And32,
7118//.. binop(Iop_Shr32, getIReg(4, R_EAX), mkU8(8)),
7119//.. mkU32(mask_SZACP))
7120//.. )
7121//.. ));
7122//.. }
7123//..
7124//..
7125//.. //-- static
7126//.. //-- void codegen_LAHF ( UCodeBlock* cb )
7127//.. //-- {
7128//.. //-- Int t = newTemp(cb);
7129//.. //--
7130//.. //-- /* Pushed arg is ignored, it just provides somewhere to put the
7131//.. //-- return value. */
7132//.. //-- uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, t);
7133//.. //-- uInstr0(cb, CALLM_S, 0);
7134//.. //-- uInstr1(cb, PUSH, 4, TempReg, t);
7135//.. //-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_LAHF));
7136//.. //-- uFlagsRWU(cb, FlagsSZACP, FlagsEmpty, FlagsEmpty);
7137//.. //-- uInstr1(cb, POP, 4, TempReg, t);
7138//.. //-- uInstr0(cb, CALLM_E, 0);
7139//.. //--
7140//.. //-- /* At this point, the %ah sub-register in %eax has been updated,
7141//.. //-- the rest is the same, so do a PUT of the whole thing. */
7142//.. //-- uInstr2(cb, PUT, 4, TempReg, t, ArchReg, R_EAX);
7143//.. //-- }
7144//.. //--
sewardja6b93d12005-02-17 09:28:28 +00007145
7146static
sewardjd0aa0a52006-08-17 01:20:01 +00007147ULong dis_cmpxchg_G_E ( /*OUT*/Bool* ok,
7148 Prefix pfx,
7149 Int size,
7150 Long delta0 )
sewardja6b93d12005-02-17 09:28:28 +00007151{
7152 HChar dis_buf[50];
7153 Int len;
7154
7155 IRType ty = szToITy(size);
7156 IRTemp acc = newTemp(ty);
7157 IRTemp src = newTemp(ty);
7158 IRTemp dest = newTemp(ty);
7159 IRTemp dest2 = newTemp(ty);
7160 IRTemp acc2 = newTemp(ty);
7161 IRTemp cond8 = newTemp(Ity_I8);
7162 IRTemp addr = IRTemp_INVALID;
7163 UChar rm = getUChar(delta0);
7164
7165 if (epartIsReg(rm)) {
sewardjd0aa0a52006-08-17 01:20:01 +00007166 *ok = False;
7167 return delta0;
7168 /* awaiting test case */
sewardj5b470602005-02-27 13:10:48 +00007169 assign( dest, getIRegE(size, pfx, rm) );
sewardja6b93d12005-02-17 09:28:28 +00007170 delta0++;
7171 DIP("cmpxchg%c %s,%s\n", nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00007172 nameIRegG(size,pfx,rm),
7173 nameIRegE(size,pfx,rm) );
sewardja6b93d12005-02-17 09:28:28 +00007174 } else {
7175 addr = disAMode ( &len, pfx, delta0, dis_buf, 0 );
7176 assign( dest, loadLE(ty, mkexpr(addr)) );
7177 delta0 += len;
7178 DIP("cmpxchg%c %s,%s\n", nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00007179 nameIRegG(size,pfx,rm), dis_buf);
sewardja6b93d12005-02-17 09:28:28 +00007180 }
7181
sewardj5b470602005-02-27 13:10:48 +00007182 assign( src, getIRegG(size, pfx, rm) );
7183 assign( acc, getIRegRAX(size) );
sewardja6b93d12005-02-17 09:28:28 +00007184 setFlags_DEP1_DEP2(Iop_Sub8, acc, dest, ty);
7185 assign( cond8, unop(Iop_1Uto8, mk_amd64g_calculate_condition(AMD64CondZ)) );
7186 assign( dest2, IRExpr_Mux0X(mkexpr(cond8), mkexpr(dest), mkexpr(src)) );
7187 assign( acc2, IRExpr_Mux0X(mkexpr(cond8), mkexpr(dest), mkexpr(acc)) );
sewardj5b470602005-02-27 13:10:48 +00007188 putIRegRAX(size, mkexpr(acc2));
sewardja6b93d12005-02-17 09:28:28 +00007189
7190 if (epartIsReg(rm)) {
sewardj5b470602005-02-27 13:10:48 +00007191 putIRegE(size, pfx, rm, mkexpr(dest2));
sewardja6b93d12005-02-17 09:28:28 +00007192 } else {
7193 storeLE( mkexpr(addr), mkexpr(dest2) );
7194 }
7195
sewardjd0aa0a52006-08-17 01:20:01 +00007196 *ok = True;
sewardja6b93d12005-02-17 09:28:28 +00007197 return delta0;
7198}
7199
sewardjd0aa0a52006-08-17 01:20:01 +00007200static
7201ULong dis_cmpxchg8b ( /*OUT*/Bool* ok,
7202 Prefix pfx,
7203 Int sz,
7204 Long delta0 )
7205{
7206 HChar dis_buf[50];
7207 Int len;
7208
7209 IRType ty = szToITy(sz);
7210 IRTemp eq = newTemp(Ity_I8);
7211 IRTemp olda = newTemp(ty);
7212 IRTemp oldb = newTemp(ty);
7213 IRTemp oldc = newTemp(ty);
7214 IRTemp oldd = newTemp(ty);
7215 IRTemp newa = newTemp(Ity_I64);
7216 IRTemp newd = newTemp(Ity_I64);
7217 IRTemp oldml = newTemp(ty);
7218 IRTemp oldmh = newTemp(ty);
7219 IRTemp newml = newTemp(ty);
7220 IRTemp newmh = newTemp(ty);
7221 IRTemp addr = IRTemp_INVALID;
7222 IRTemp oldrf = newTemp(Ity_I64);
7223 IRTemp newrf = newTemp(Ity_I64);
7224 UChar rm = getUChar(delta0);
7225 vassert(sz == 4 || sz == 8); /* guaranteed by caller */
7226
7227 if (epartIsReg(rm)) {
7228 *ok = False;
7229 return delta0;
7230 }
7231
7232 addr = disAMode ( &len, pfx, delta0, dis_buf, 0 );
7233 delta0 += len;
7234 DIP("cmpxchg%s %s\n", sz == 4 ? "8" : "16", dis_buf);
7235
7236 if (sz == 4) {
7237 assign( olda, getIReg32( R_RAX ) );
7238 assign( oldb, getIReg32( R_RBX ) );
7239 assign( oldc, getIReg32( R_RCX ) );
7240 assign( oldd, getIReg32( R_RDX ) );
7241 assign( oldml, loadLE( Ity_I32, mkexpr(addr) ));
7242 assign( oldmh, loadLE( Ity_I32,
7243 binop(Iop_Add64,mkexpr(addr),mkU64(4)) ));
7244 assign(eq,
7245 unop(Iop_1Uto8,
7246 binop(Iop_CmpEQ32,
7247 binop(Iop_Or32,
7248 binop(Iop_Xor32,mkexpr(olda),mkexpr(oldml)),
7249 binop(Iop_Xor32,mkexpr(oldd),mkexpr(oldmh))),
7250 mkU32(0))));
7251 assign( newml, IRExpr_Mux0X(mkexpr(eq),mkexpr(oldml),mkexpr(oldb)) );
7252 assign( newmh, IRExpr_Mux0X(mkexpr(eq),mkexpr(oldmh),mkexpr(oldc)) );
7253 assign( newa, IRExpr_Mux0X(mkexpr(eq),
7254 unop(Iop_32Uto64,mkexpr(oldml)),
7255 getIRegRAX(8)) );
7256 assign( newd, IRExpr_Mux0X(mkexpr(eq),
7257 unop(Iop_32Uto64,mkexpr(oldmh)),
7258 getIRegRDX(8)) );
7259
7260 storeLE( mkexpr(addr), mkexpr(newml) );
7261 storeLE( binop(Iop_Add64,mkexpr(addr),mkU64(4)),
7262 mkexpr(newmh) );
7263 putIRegRAX( 8, mkexpr(newa) );
7264 putIRegRDX( 8, mkexpr(newd) );
7265 } else {
7266 assign( olda, getIReg64( R_RAX ) );
7267 assign( oldb, getIReg64( R_RBX ) );
7268 assign( oldc, getIReg64( R_RCX ) );
7269 assign( oldd, getIReg64( R_RDX ) );
7270 assign( oldml, loadLE( Ity_I64, mkexpr(addr) ));
7271 assign( oldmh, loadLE( Ity_I64,
7272 binop(Iop_Add64,mkexpr(addr),mkU64(8)) ));
7273 assign(eq,
7274 unop(Iop_1Uto8,
7275 binop(Iop_CmpEQ64,
7276 binop(Iop_Or64,
7277 binop(Iop_Xor64,mkexpr(olda),mkexpr(oldml)),
7278 binop(Iop_Xor64,mkexpr(oldd),mkexpr(oldmh))),
7279 mkU64(0))));
7280 assign( newml, IRExpr_Mux0X(mkexpr(eq),mkexpr(oldml),mkexpr(oldb)) );
7281 assign( newmh, IRExpr_Mux0X(mkexpr(eq),mkexpr(oldmh),mkexpr(oldc)) );
7282 assign( newa, IRExpr_Mux0X(mkexpr(eq),mkexpr(oldml),mkexpr(olda)) );
7283 assign( newd, IRExpr_Mux0X(mkexpr(eq),mkexpr(oldmh),mkexpr(oldd)) );
7284
7285 storeLE( mkexpr(addr), mkexpr(newml) );
7286 storeLE( binop(Iop_Add64,mkexpr(addr),mkU64(8)),
7287 mkexpr(newmh) );
7288 putIRegRAX( 8, mkexpr(newa) );
7289 putIRegRDX( 8, mkexpr(newd) );
7290 }
7291
7292 /* And set the flags. Z is set if original d:a == mem, else
7293 cleared. All others unchanged. (This is different from normal
7294 cmpxchg which just sets them according to SUB.). */
7295 assign( oldrf, binop(Iop_And64,
7296 mk_amd64g_calculate_rflags_all(),
7297 mkU64(~AMD64G_CC_MASK_Z)) );
7298 assign( newrf,
7299 binop(Iop_Or64,
7300 mkexpr(oldrf),
7301 binop(Iop_Shl64,
7302 binop(Iop_And64, unop(Iop_8Uto64, mkexpr(eq)), mkU64(1)),
7303 mkU8(AMD64G_CC_SHIFT_Z))
7304 ));
7305 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(AMD64G_CC_OP_COPY) ));
7306 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
7307 stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(newrf) ));
7308 /* Set NDEP even though it isn't used. This makes redundant-PUT
7309 elimination of previous stores to this field work better. */
7310 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU64(0) ));
7311
7312 *ok = True;
7313 return delta0;
7314}
sewardja6b93d12005-02-17 09:28:28 +00007315
sewardjd20c8852005-01-20 20:04:07 +00007316//.. //-- static
7317//.. //-- Addr dis_cmpxchg8b ( UCodeBlock* cb,
7318//.. //-- UChar sorb,
7319//.. //-- Addr eip0 )
7320//.. //-- {
7321//.. //-- Int tal, tah, junkl, junkh, destl, desth, srcl, srch, accl, acch;
7322//.. //-- HChar dis_buf[50];
7323//.. //-- UChar rm;
7324//.. //-- UInt pair;
7325//.. //--
7326//.. //-- rm = getUChar(eip0);
7327//.. //-- accl = newTemp(cb);
7328//.. //-- acch = newTemp(cb);
7329//.. //-- srcl = newTemp(cb);
7330//.. //-- srch = newTemp(cb);
7331//.. //-- destl = newTemp(cb);
7332//.. //-- desth = newTemp(cb);
7333//.. //-- junkl = newTemp(cb);
7334//.. //-- junkh = newTemp(cb);
7335//.. //--
7336//.. //-- vg_assert(!epartIsReg(rm));
7337//.. //--
7338//.. //-- pair = disAMode ( cb, sorb, eip0, dis_buf );
7339//.. //-- tal = LOW24(pair);
7340//.. //-- tah = newTemp(cb);
7341//.. //-- uInstr2(cb, MOV, 4, TempReg, tal, TempReg, tah);
7342//.. //-- uInstr2(cb, ADD, 4, Literal, 0, TempReg, tah);
7343//.. //-- uLiteral(cb, 4);
7344//.. //-- eip0 += HI8(pair);
7345//.. //-- DIP("cmpxchg8b %s\n", dis_buf);
7346//.. //--
7347//.. //-- uInstr0(cb, CALLM_S, 0);
7348//.. //--
7349//.. //-- uInstr2(cb, LOAD, 4, TempReg, tah, TempReg, desth);
7350//.. //-- uInstr1(cb, PUSH, 4, TempReg, desth);
7351//.. //-- uInstr2(cb, LOAD, 4, TempReg, tal, TempReg, destl);
7352//.. //-- uInstr1(cb, PUSH, 4, TempReg, destl);
7353//.. //-- uInstr2(cb, GET, 4, ArchReg, R_ECX, TempReg, srch);
7354//.. //-- uInstr1(cb, PUSH, 4, TempReg, srch);
7355//.. //-- uInstr2(cb, GET, 4, ArchReg, R_EBX, TempReg, srcl);
7356//.. //-- uInstr1(cb, PUSH, 4, TempReg, srcl);
7357//.. //-- uInstr2(cb, GET, 4, ArchReg, R_EDX, TempReg, acch);
7358//.. //-- uInstr1(cb, PUSH, 4, TempReg, acch);
7359//.. //-- uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, accl);
7360//.. //-- uInstr1(cb, PUSH, 4, TempReg, accl);
7361//.. //--
7362//.. //-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_cmpxchg8b));
7363//.. //-- uFlagsRWU(cb, FlagsEmpty, FlagZ, FlagsEmpty);
7364//.. //--
7365//.. //-- uInstr1(cb, POP, 4, TempReg, accl);
7366//.. //-- uInstr2(cb, PUT, 4, TempReg, accl, ArchReg, R_EAX);
7367//.. //-- uInstr1(cb, POP, 4, TempReg, acch);
7368//.. //-- uInstr2(cb, PUT, 4, TempReg, acch, ArchReg, R_EDX);
7369//.. //-- uInstr1(cb, POP, 4, TempReg, srcl);
7370//.. //-- uInstr2(cb, PUT, 4, TempReg, srcl, ArchReg, R_EBX);
7371//.. //-- uInstr1(cb, POP, 4, TempReg, srch);
7372//.. //-- uInstr2(cb, PUT, 4, TempReg, srch, ArchReg, R_ECX);
7373//.. //-- uInstr1(cb, POP, 4, TempReg, destl);
7374//.. //-- uInstr2(cb, STORE, 4, TempReg, destl, TempReg, tal);
7375//.. //-- uInstr1(cb, POP, 4, TempReg, desth);
7376//.. //-- uInstr2(cb, STORE, 4, TempReg, desth, TempReg, tah);
7377//.. //--
7378//.. //-- uInstr0(cb, CALLM_E, 0);
7379//.. //--
7380//.. //-- return eip0;
7381//.. //-- }
sewardj3ca55a12005-01-27 16:06:23 +00007382
7383
7384/* Handle conditional move instructions of the form
7385 cmovcc E(reg-or-mem), G(reg)
7386
7387 E(src) is reg-or-mem
7388 G(dst) is reg.
7389
7390 If E is reg, --> GET %E, tmps
7391 GET %G, tmpd
7392 CMOVcc tmps, tmpd
7393 PUT tmpd, %G
7394
7395 If E is mem --> (getAddr E) -> tmpa
7396 LD (tmpa), tmps
7397 GET %G, tmpd
7398 CMOVcc tmps, tmpd
7399 PUT tmpd, %G
7400*/
7401static
7402ULong dis_cmov_E_G ( Prefix pfx,
7403 Int sz,
7404 AMD64Condcode cond,
sewardj270def42005-07-03 01:03:01 +00007405 Long delta0 )
sewardj3ca55a12005-01-27 16:06:23 +00007406{
sewardj8c332e22005-01-28 01:36:56 +00007407 UChar rm = getUChar(delta0);
sewardj3ca55a12005-01-27 16:06:23 +00007408 HChar dis_buf[50];
7409 Int len;
7410
7411 IRType ty = szToITy(sz);
7412 IRTemp tmps = newTemp(ty);
7413 IRTemp tmpd = newTemp(ty);
7414
7415 if (epartIsReg(rm)) {
sewardj5b470602005-02-27 13:10:48 +00007416 assign( tmps, getIRegE(sz, pfx, rm) );
7417 assign( tmpd, getIRegG(sz, pfx, rm) );
sewardj3ca55a12005-01-27 16:06:23 +00007418
sewardj5b470602005-02-27 13:10:48 +00007419 putIRegG( sz, pfx, rm,
sewardj3ca55a12005-01-27 16:06:23 +00007420 IRExpr_Mux0X( unop(Iop_1Uto8,
7421 mk_amd64g_calculate_condition(cond)),
7422 mkexpr(tmpd),
7423 mkexpr(tmps) )
7424 );
sewardje941eea2005-01-30 19:52:28 +00007425 DIP("cmov%s %s,%s\n", name_AMD64Condcode(cond),
sewardj5b470602005-02-27 13:10:48 +00007426 nameIRegE(sz,pfx,rm),
7427 nameIRegG(sz,pfx,rm));
sewardj3ca55a12005-01-27 16:06:23 +00007428 return 1+delta0;
7429 }
7430
7431 /* E refers to memory */
7432 {
sewardje1698952005-02-08 15:02:39 +00007433 IRTemp addr = disAMode ( &len, pfx, delta0, dis_buf, 0 );
sewardj3ca55a12005-01-27 16:06:23 +00007434 assign( tmps, loadLE(ty, mkexpr(addr)) );
sewardj5b470602005-02-27 13:10:48 +00007435 assign( tmpd, getIRegG(sz, pfx, rm) );
sewardj3ca55a12005-01-27 16:06:23 +00007436
sewardj5b470602005-02-27 13:10:48 +00007437 putIRegG( sz, pfx, rm,
sewardj3ca55a12005-01-27 16:06:23 +00007438 IRExpr_Mux0X( unop(Iop_1Uto8,
7439 mk_amd64g_calculate_condition(cond)),
7440 mkexpr(tmpd),
7441 mkexpr(tmps) )
7442 );
7443
sewardj7eaa7cf2005-01-31 18:55:22 +00007444 DIP("cmov%s %s,%s\n", name_AMD64Condcode(cond),
7445 dis_buf,
sewardj5b470602005-02-27 13:10:48 +00007446 nameIRegG(sz,pfx,rm));
sewardj3ca55a12005-01-27 16:06:23 +00007447 return len+delta0;
7448 }
7449}
7450
7451
sewardjb4fd2e72005-03-23 13:34:11 +00007452static
7453ULong dis_xadd_G_E ( /*OUT*/Bool* decode_ok,
sewardj270def42005-07-03 01:03:01 +00007454 Prefix pfx, Int sz, Long delta0 )
sewardjb4fd2e72005-03-23 13:34:11 +00007455{
7456 Int len;
7457 UChar rm = getUChar(delta0);
7458 HChar dis_buf[50];
7459
7460 IRType ty = szToITy(sz);
7461 IRTemp tmpd = newTemp(ty);
7462 IRTemp tmpt0 = newTemp(ty);
7463 IRTemp tmpt1 = newTemp(ty);
7464 *decode_ok = True;
7465
7466 if (epartIsReg(rm)) {
7467 *decode_ok = False;
7468 return delta0;
7469 } else {
7470 IRTemp addr = disAMode ( &len, pfx, delta0, dis_buf, 0 );
7471 assign( tmpd, loadLE(ty, mkexpr(addr)) );
7472 assign( tmpt0, getIRegG(sz, pfx, rm) );
7473 assign( tmpt1, binop(mkSizedOp(ty,Iop_Add8), mkexpr(tmpd), mkexpr(tmpt0)) );
7474 setFlags_DEP1_DEP2( Iop_Add8, tmpd, tmpt0, ty );
7475 storeLE( mkexpr(addr), mkexpr(tmpt1) );
7476 putIRegG(sz, pfx, rm, mkexpr(tmpd));
7477 DIP("xadd%c %s, %s\n",
7478 nameISize(sz), nameIRegG(sz,pfx,rm), dis_buf);
7479 return len+delta0;
7480 }
7481}
7482
sewardjd20c8852005-01-20 20:04:07 +00007483//.. /* Move 16 bits from Ew (ireg or mem) to G (a segment register). */
7484//..
7485//.. static
sewardj270def42005-07-03 01:03:01 +00007486//.. UInt dis_mov_Ew_Sw ( UChar sorb, Long delta0 )
sewardjd20c8852005-01-20 20:04:07 +00007487//.. {
7488//.. Int len;
7489//.. IRTemp addr;
sewardj8c332e22005-01-28 01:36:56 +00007490//.. UChar rm = getUChar(delta0);
sewardjd20c8852005-01-20 20:04:07 +00007491//.. HChar dis_buf[50];
7492//..
7493//.. if (epartIsReg(rm)) {
7494//.. putSReg( gregOfRM(rm), getIReg(2, eregOfRM(rm)) );
7495//.. DIP("movw %s,%s\n", nameIReg(2,eregOfRM(rm)), nameSReg(gregOfRM(rm)));
7496//.. return 1+delta0;
7497//.. } else {
7498//.. addr = disAMode ( &len, sorb, delta0, dis_buf );
7499//.. putSReg( gregOfRM(rm), loadLE(Ity_I16, mkexpr(addr)) );
7500//.. DIP("movw %s,%s\n", dis_buf, nameSReg(gregOfRM(rm)));
7501//.. return len+delta0;
7502//.. }
7503//.. }
7504//..
7505//.. /* Move 16 bits from G (a segment register) to Ew (ireg or mem). If
7506//.. dst is ireg and sz==4, zero out top half of it. */
7507//..
7508//.. static
7509//.. UInt dis_mov_Sw_Ew ( UChar sorb,
7510//.. Int sz,
7511//.. UInt delta0 )
7512//.. {
7513//.. Int len;
7514//.. IRTemp addr;
sewardj8c332e22005-01-28 01:36:56 +00007515//.. UChar rm = getUChar(delta0);
sewardjd20c8852005-01-20 20:04:07 +00007516//.. HChar dis_buf[50];
7517//..
7518//.. vassert(sz == 2 || sz == 4);
7519//..
7520//.. if (epartIsReg(rm)) {
7521//.. if (sz == 4)
7522//.. putIReg(4, eregOfRM(rm), unop(Iop_16Uto32, getSReg(gregOfRM(rm))));
7523//.. else
7524//.. putIReg(2, eregOfRM(rm), getSReg(gregOfRM(rm)));
7525//..
7526//.. DIP("mov %s,%s\n", nameSReg(gregOfRM(rm)), nameIReg(sz,eregOfRM(rm)));
7527//.. return 1+delta0;
7528//.. } else {
7529//.. addr = disAMode ( &len, sorb, delta0, dis_buf );
7530//.. storeLE( mkexpr(addr), getSReg(gregOfRM(rm)) );
7531//.. DIP("mov %s,%s\n", nameSReg(gregOfRM(rm)), dis_buf);
7532//.. return len+delta0;
7533//.. }
7534//.. }
7535//..
7536//..
7537//.. static
7538//.. void dis_push_segreg ( UInt sreg, Int sz )
7539//.. {
7540//.. IRTemp t1 = newTemp(Ity_I16);
7541//.. IRTemp ta = newTemp(Ity_I32);
7542//.. vassert(sz == 2 || sz == 4);
7543//..
7544//.. assign( t1, getSReg(sreg) );
7545//.. assign( ta, binop(Iop_Sub32, getIReg(4, R_ESP), mkU32(sz)) );
7546//.. putIReg(4, R_ESP, mkexpr(ta));
7547//.. storeLE( mkexpr(ta), mkexpr(t1) );
7548//..
7549//.. DIP("pushw %s\n", nameSReg(sreg));
7550//.. }
7551//..
7552//.. static
7553//.. void dis_pop_segreg ( UInt sreg, Int sz )
7554//.. {
7555//.. IRTemp t1 = newTemp(Ity_I16);
7556//.. IRTemp ta = newTemp(Ity_I32);
7557//.. vassert(sz == 2 || sz == 4);
7558//..
7559//.. assign( ta, getIReg(4, R_ESP) );
7560//.. assign( t1, loadLE(Ity_I16, mkexpr(ta)) );
7561//..
7562//.. putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(ta), mkU32(sz)) );
7563//.. putSReg( sreg, mkexpr(t1) );
7564//.. DIP("pop %s\n", nameSReg(sreg));
7565//.. }
sewardj2f959cc2005-01-26 01:19:35 +00007566
7567static
7568void dis_ret ( ULong d64 )
7569{
7570 IRTemp t1 = newTemp(Ity_I64);
7571 IRTemp t2 = newTemp(Ity_I64);
sewardj5a9ffab2005-05-12 17:55:01 +00007572 IRTemp t3 = newTemp(Ity_I64);
sewardj2f959cc2005-01-26 01:19:35 +00007573 assign(t1, getIReg64(R_RSP));
7574 assign(t2, loadLE(Ity_I64,mkexpr(t1)));
sewardj5a9ffab2005-05-12 17:55:01 +00007575 assign(t3, binop(Iop_Add64, mkexpr(t1), mkU64(8+d64)));
7576 putIReg64(R_RSP, mkexpr(t3));
7577 make_redzone_AbiHint(t3, "ret");
sewardj2f959cc2005-01-26 01:19:35 +00007578 jmp_treg(Ijk_Ret,t2);
7579}
7580
sewardj5b470602005-02-27 13:10:48 +00007581
sewardj1001dc42005-02-21 08:25:55 +00007582/*------------------------------------------------------------*/
7583/*--- SSE/SSE2/SSE3 helpers ---*/
7584/*------------------------------------------------------------*/
7585
7586/* Worker function; do not call directly.
7587 Handles full width G = G `op` E and G = (not G) `op` E.
7588*/
7589
sewardj8d965312005-02-25 02:48:47 +00007590static ULong dis_SSE_E_to_G_all_wrk (
sewardj270def42005-07-03 01:03:01 +00007591 Prefix pfx, Long delta,
sewardj8d965312005-02-25 02:48:47 +00007592 HChar* opname, IROp op,
7593 Bool invertG
7594 )
sewardj9da16972005-02-21 13:58:26 +00007595{
7596 HChar dis_buf[50];
7597 Int alen;
7598 IRTemp addr;
7599 UChar rm = getUChar(delta);
7600 IRExpr* gpart
7601 = invertG ? unop(Iop_NotV128, getXMMReg(gregOfRexRM(pfx,rm)))
7602 : getXMMReg(gregOfRexRM(pfx,rm));
7603 if (epartIsReg(rm)) {
7604 putXMMReg( gregOfRexRM(pfx,rm),
7605 binop(op, gpart,
7606 getXMMReg(eregOfRexRM(pfx,rm))) );
7607 DIP("%s %s,%s\n", opname,
7608 nameXMMReg(eregOfRexRM(pfx,rm)),
7609 nameXMMReg(gregOfRexRM(pfx,rm)) );
7610 return delta+1;
7611 } else {
7612 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
7613 putXMMReg( gregOfRexRM(pfx,rm),
7614 binop(op, gpart,
7615 loadLE(Ity_V128, mkexpr(addr))) );
7616 DIP("%s %s,%s\n", opname,
7617 dis_buf,
7618 nameXMMReg(gregOfRexRM(pfx,rm)) );
7619 return delta+alen;
7620 }
7621}
7622
7623
7624/* All lanes SSE binary operation, G = G `op` E. */
7625
7626static
sewardj270def42005-07-03 01:03:01 +00007627ULong dis_SSE_E_to_G_all ( Prefix pfx, Long delta,
sewardj8d965312005-02-25 02:48:47 +00007628 HChar* opname, IROp op )
sewardj9da16972005-02-21 13:58:26 +00007629{
7630 return dis_SSE_E_to_G_all_wrk( pfx, delta, opname, op, False );
7631}
7632
sewardj8d965312005-02-25 02:48:47 +00007633/* All lanes SSE binary operation, G = (not G) `op` E. */
7634
7635static
sewardj270def42005-07-03 01:03:01 +00007636ULong dis_SSE_E_to_G_all_invG ( Prefix pfx, Long delta,
sewardj8d965312005-02-25 02:48:47 +00007637 HChar* opname, IROp op )
7638{
7639 return dis_SSE_E_to_G_all_wrk( pfx, delta, opname, op, True );
7640}
7641
7642
7643/* Lowest 32-bit lane only SSE binary operation, G = G `op` E. */
7644
sewardj270def42005-07-03 01:03:01 +00007645static ULong dis_SSE_E_to_G_lo32 ( Prefix pfx, Long delta,
sewardj8d965312005-02-25 02:48:47 +00007646 HChar* opname, IROp op )
7647{
7648 HChar dis_buf[50];
7649 Int alen;
7650 IRTemp addr;
7651 UChar rm = getUChar(delta);
sewardj9c9ee3d2005-02-26 01:17:42 +00007652 IRExpr* gpart = getXMMReg(gregOfRexRM(pfx,rm));
sewardj8d965312005-02-25 02:48:47 +00007653 if (epartIsReg(rm)) {
sewardj9c9ee3d2005-02-26 01:17:42 +00007654 putXMMReg( gregOfRexRM(pfx,rm),
sewardj8d965312005-02-25 02:48:47 +00007655 binop(op, gpart,
7656 getXMMReg(eregOfRexRM(pfx,rm))) );
7657 DIP("%s %s,%s\n", opname,
7658 nameXMMReg(eregOfRexRM(pfx,rm)),
7659 nameXMMReg(gregOfRexRM(pfx,rm)) );
7660 return delta+1;
7661 } else {
7662 /* We can only do a 32-bit memory read, so the upper 3/4 of the
7663 E operand needs to be made simply of zeroes. */
7664 IRTemp epart = newTemp(Ity_V128);
7665 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
7666 assign( epart, unop( Iop_32UtoV128,
7667 loadLE(Ity_I32, mkexpr(addr))) );
7668 putXMMReg( gregOfRexRM(pfx,rm),
7669 binop(op, gpart, mkexpr(epart)) );
7670 DIP("%s %s,%s\n", opname,
7671 dis_buf,
7672 nameXMMReg(gregOfRexRM(pfx,rm)) );
7673 return delta+alen;
7674 }
7675}
sewardj1001dc42005-02-21 08:25:55 +00007676
7677
7678/* Lower 64-bit lane only SSE binary operation, G = G `op` E. */
7679
sewardj270def42005-07-03 01:03:01 +00007680static ULong dis_SSE_E_to_G_lo64 ( Prefix pfx, Long delta,
sewardj8d965312005-02-25 02:48:47 +00007681 HChar* opname, IROp op )
sewardj1001dc42005-02-21 08:25:55 +00007682{
7683 HChar dis_buf[50];
7684 Int alen;
7685 IRTemp addr;
7686 UChar rm = getUChar(delta);
7687 IRExpr* gpart = getXMMReg(gregOfRexRM(pfx,rm));
7688 if (epartIsReg(rm)) {
7689 putXMMReg( gregOfRexRM(pfx,rm),
7690 binop(op, gpart,
7691 getXMMReg(eregOfRexRM(pfx,rm))) );
7692 DIP("%s %s,%s\n", opname,
7693 nameXMMReg(eregOfRexRM(pfx,rm)),
7694 nameXMMReg(gregOfRexRM(pfx,rm)) );
7695 return delta+1;
7696 } else {
7697 /* We can only do a 64-bit memory read, so the upper half of the
7698 E operand needs to be made simply of zeroes. */
7699 IRTemp epart = newTemp(Ity_V128);
7700 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
7701 assign( epart, unop( Iop_64UtoV128,
7702 loadLE(Ity_I64, mkexpr(addr))) );
7703 putXMMReg( gregOfRexRM(pfx,rm),
7704 binop(op, gpart, mkexpr(epart)) );
7705 DIP("%s %s,%s\n", opname,
7706 dis_buf,
7707 nameXMMReg(gregOfRexRM(pfx,rm)) );
7708 return delta+alen;
7709 }
7710}
7711
7712
sewardja7ba8c42005-05-10 20:08:34 +00007713/* All lanes unary SSE operation, G = op(E). */
7714
7715static ULong dis_SSE_E_to_G_unary_all (
sewardj270def42005-07-03 01:03:01 +00007716 Prefix pfx, Long delta,
sewardja7ba8c42005-05-10 20:08:34 +00007717 HChar* opname, IROp op
7718 )
7719{
7720 HChar dis_buf[50];
7721 Int alen;
7722 IRTemp addr;
7723 UChar rm = getUChar(delta);
7724 if (epartIsReg(rm)) {
7725 putXMMReg( gregOfRexRM(pfx,rm),
7726 unop(op, getXMMReg(eregOfRexRM(pfx,rm))) );
7727 DIP("%s %s,%s\n", opname,
7728 nameXMMReg(eregOfRexRM(pfx,rm)),
7729 nameXMMReg(gregOfRexRM(pfx,rm)) );
7730 return delta+1;
7731 } else {
7732 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
7733 putXMMReg( gregOfRexRM(pfx,rm),
7734 unop(op, loadLE(Ity_V128, mkexpr(addr))) );
7735 DIP("%s %s,%s\n", opname,
7736 dis_buf,
7737 nameXMMReg(gregOfRexRM(pfx,rm)) );
7738 return delta+alen;
7739 }
7740}
7741
7742
7743/* Lowest 32-bit lane only unary SSE operation, G = op(E). */
7744
7745static ULong dis_SSE_E_to_G_unary_lo32 (
sewardj270def42005-07-03 01:03:01 +00007746 Prefix pfx, Long delta,
sewardja7ba8c42005-05-10 20:08:34 +00007747 HChar* opname, IROp op
7748 )
7749{
7750 /* First we need to get the old G value and patch the low 32 bits
7751 of the E operand into it. Then apply op and write back to G. */
7752 HChar dis_buf[50];
7753 Int alen;
7754 IRTemp addr;
7755 UChar rm = getUChar(delta);
7756 IRTemp oldG0 = newTemp(Ity_V128);
7757 IRTemp oldG1 = newTemp(Ity_V128);
7758
7759 assign( oldG0, getXMMReg(gregOfRexRM(pfx,rm)) );
7760
7761 if (epartIsReg(rm)) {
7762 assign( oldG1,
7763 binop( Iop_SetV128lo32,
7764 mkexpr(oldG0),
7765 getXMMRegLane32(eregOfRexRM(pfx,rm), 0)) );
7766 putXMMReg( gregOfRexRM(pfx,rm), unop(op, mkexpr(oldG1)) );
7767 DIP("%s %s,%s\n", opname,
7768 nameXMMReg(eregOfRexRM(pfx,rm)),
7769 nameXMMReg(gregOfRexRM(pfx,rm)) );
7770 return delta+1;
7771 } else {
7772 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
7773 assign( oldG1,
7774 binop( Iop_SetV128lo32,
7775 mkexpr(oldG0),
7776 loadLE(Ity_I32, mkexpr(addr)) ));
7777 putXMMReg( gregOfRexRM(pfx,rm), unop(op, mkexpr(oldG1)) );
7778 DIP("%s %s,%s\n", opname,
7779 dis_buf,
7780 nameXMMReg(gregOfRexRM(pfx,rm)) );
7781 return delta+alen;
7782 }
7783}
sewardj1001dc42005-02-21 08:25:55 +00007784
7785
7786/* Lowest 64-bit lane only unary SSE operation, G = op(E). */
7787
sewardj8d965312005-02-25 02:48:47 +00007788static ULong dis_SSE_E_to_G_unary_lo64 (
sewardj270def42005-07-03 01:03:01 +00007789 Prefix pfx, Long delta,
sewardj8d965312005-02-25 02:48:47 +00007790 HChar* opname, IROp op
7791 )
sewardj1001dc42005-02-21 08:25:55 +00007792{
7793 /* First we need to get the old G value and patch the low 64 bits
7794 of the E operand into it. Then apply op and write back to G. */
7795 HChar dis_buf[50];
7796 Int alen;
7797 IRTemp addr;
7798 UChar rm = getUChar(delta);
7799 IRTemp oldG0 = newTemp(Ity_V128);
7800 IRTemp oldG1 = newTemp(Ity_V128);
7801
7802 assign( oldG0, getXMMReg(gregOfRexRM(pfx,rm)) );
7803
7804 if (epartIsReg(rm)) {
7805 assign( oldG1,
7806 binop( Iop_SetV128lo64,
7807 mkexpr(oldG0),
7808 getXMMRegLane64(eregOfRexRM(pfx,rm), 0)) );
7809 putXMMReg( gregOfRexRM(pfx,rm), unop(op, mkexpr(oldG1)) );
7810 DIP("%s %s,%s\n", opname,
7811 nameXMMReg(eregOfRexRM(pfx,rm)),
7812 nameXMMReg(gregOfRexRM(pfx,rm)) );
7813 return delta+1;
7814 } else {
7815 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
7816 assign( oldG1,
7817 binop( Iop_SetV128lo64,
7818 mkexpr(oldG0),
7819 loadLE(Ity_I64, mkexpr(addr)) ));
7820 putXMMReg( gregOfRexRM(pfx,rm), unop(op, mkexpr(oldG1)) );
7821 DIP("%s %s,%s\n", opname,
7822 dis_buf,
7823 nameXMMReg(gregOfRexRM(pfx,rm)) );
7824 return delta+alen;
7825 }
7826}
7827
7828
sewardj09717342005-05-05 21:34:02 +00007829/* SSE integer binary operation:
7830 G = G `op` E (eLeft == False)
7831 G = E `op` G (eLeft == True)
7832*/
7833static ULong dis_SSEint_E_to_G(
sewardj270def42005-07-03 01:03:01 +00007834 Prefix pfx, Long delta,
sewardj09717342005-05-05 21:34:02 +00007835 HChar* opname, IROp op,
7836 Bool eLeft
7837 )
7838{
7839 HChar dis_buf[50];
7840 Int alen;
7841 IRTemp addr;
7842 UChar rm = getUChar(delta);
7843 IRExpr* gpart = getXMMReg(gregOfRexRM(pfx,rm));
7844 IRExpr* epart = NULL;
7845 if (epartIsReg(rm)) {
7846 epart = getXMMReg(eregOfRexRM(pfx,rm));
7847 DIP("%s %s,%s\n", opname,
7848 nameXMMReg(eregOfRexRM(pfx,rm)),
7849 nameXMMReg(gregOfRexRM(pfx,rm)) );
7850 delta += 1;
7851 } else {
7852 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
7853 epart = loadLE(Ity_V128, mkexpr(addr));
7854 DIP("%s %s,%s\n", opname,
7855 dis_buf,
7856 nameXMMReg(gregOfRexRM(pfx,rm)) );
7857 delta += alen;
7858 }
7859 putXMMReg( gregOfRexRM(pfx,rm),
7860 eLeft ? binop(op, epart, gpart)
7861 : binop(op, gpart, epart) );
7862 return delta;
7863}
sewardj8d965312005-02-25 02:48:47 +00007864
7865
7866/* Helper for doing SSE FP comparisons. */
7867
7868static void findSSECmpOp ( Bool* needNot, IROp* op,
7869 Int imm8, Bool all_lanes, Int sz )
7870{
7871 imm8 &= 7;
7872 *needNot = False;
7873 *op = Iop_INVALID;
7874 if (imm8 >= 4) {
7875 *needNot = True;
7876 imm8 -= 4;
7877 }
7878
7879 if (sz == 4 && all_lanes) {
7880 switch (imm8) {
7881 case 0: *op = Iop_CmpEQ32Fx4; return;
7882 case 1: *op = Iop_CmpLT32Fx4; return;
7883 case 2: *op = Iop_CmpLE32Fx4; return;
7884 case 3: *op = Iop_CmpUN32Fx4; return;
7885 default: break;
7886 }
7887 }
7888 if (sz == 4 && !all_lanes) {
7889 switch (imm8) {
7890 case 0: *op = Iop_CmpEQ32F0x4; return;
7891 case 1: *op = Iop_CmpLT32F0x4; return;
7892 case 2: *op = Iop_CmpLE32F0x4; return;
7893 case 3: *op = Iop_CmpUN32F0x4; return;
7894 default: break;
7895 }
7896 }
7897 if (sz == 8 && all_lanes) {
7898 switch (imm8) {
7899 case 0: *op = Iop_CmpEQ64Fx2; return;
7900 case 1: *op = Iop_CmpLT64Fx2; return;
7901 case 2: *op = Iop_CmpLE64Fx2; return;
7902 case 3: *op = Iop_CmpUN64Fx2; return;
7903 default: break;
7904 }
7905 }
7906 if (sz == 8 && !all_lanes) {
7907 switch (imm8) {
7908 case 0: *op = Iop_CmpEQ64F0x2; return;
7909 case 1: *op = Iop_CmpLT64F0x2; return;
7910 case 2: *op = Iop_CmpLE64F0x2; return;
7911 case 3: *op = Iop_CmpUN64F0x2; return;
7912 default: break;
7913 }
7914 }
7915 vpanic("findSSECmpOp(amd64,guest)");
7916}
7917
sewardjab9055b2006-01-01 13:17:38 +00007918/* Handles SSE 32F/64F comparisons. */
sewardj8d965312005-02-25 02:48:47 +00007919
sewardj270def42005-07-03 01:03:01 +00007920static ULong dis_SSEcmp_E_to_G ( Prefix pfx, Long delta,
sewardj8d965312005-02-25 02:48:47 +00007921 HChar* opname, Bool all_lanes, Int sz )
7922{
7923 HChar dis_buf[50];
7924 Int alen, imm8;
7925 IRTemp addr;
7926 Bool needNot = False;
7927 IROp op = Iop_INVALID;
7928 IRTemp plain = newTemp(Ity_V128);
7929 UChar rm = getUChar(delta);
7930 UShort mask = 0;
7931 vassert(sz == 4 || sz == 8);
7932 if (epartIsReg(rm)) {
7933 imm8 = getUChar(delta+1);
7934 findSSECmpOp(&needNot, &op, imm8, all_lanes, sz);
7935 assign( plain, binop(op, getXMMReg(gregOfRexRM(pfx,rm)),
7936 getXMMReg(eregOfRexRM(pfx,rm))) );
7937 delta += 2;
7938 DIP("%s $%d,%s,%s\n", opname,
7939 (Int)imm8,
7940 nameXMMReg(eregOfRexRM(pfx,rm)),
7941 nameXMMReg(gregOfRexRM(pfx,rm)) );
7942 } else {
7943 addr = disAMode ( &alen, pfx, delta, dis_buf, 1 );
7944 imm8 = getUChar(delta+alen);
7945 findSSECmpOp(&needNot, &op, imm8, all_lanes, sz);
sewardjab9055b2006-01-01 13:17:38 +00007946 assign( plain,
7947 binop(
7948 op,
7949 getXMMReg(gregOfRexRM(pfx,rm)),
7950 all_lanes ? loadLE(Ity_V128, mkexpr(addr))
7951 : sz == 8 ? unop( Iop_64UtoV128, loadLE(Ity_I64, mkexpr(addr)))
7952 : /*sz==4*/ unop( Iop_32UtoV128, loadLE(Ity_I32, mkexpr(addr)))
7953 )
7954 );
sewardj8d965312005-02-25 02:48:47 +00007955 delta += alen+1;
7956 DIP("%s $%d,%s,%s\n", opname,
7957 (Int)imm8,
7958 dis_buf,
7959 nameXMMReg(gregOfRexRM(pfx,rm)) );
7960 }
7961
7962 if (needNot && all_lanes) {
sewardj9c9ee3d2005-02-26 01:17:42 +00007963 putXMMReg( gregOfRexRM(pfx,rm),
sewardj8d965312005-02-25 02:48:47 +00007964 unop(Iop_NotV128, mkexpr(plain)) );
7965 }
7966 else
7967 if (needNot && !all_lanes) {
sewardj1027dc22005-02-26 01:55:02 +00007968 mask = toUShort(sz==4 ? 0x000F : 0x00FF);
sewardj8d965312005-02-25 02:48:47 +00007969 putXMMReg( gregOfRexRM(pfx,rm),
7970 binop(Iop_XorV128, mkexpr(plain), mkV128(mask)) );
7971 }
7972 else {
7973 putXMMReg( gregOfRexRM(pfx,rm), mkexpr(plain) );
7974 }
7975
7976 return delta;
7977}
7978
7979
sewardjadffcef2005-05-11 00:03:06 +00007980/* Vector by scalar shift of G by the amount specified at the bottom
7981 of E. */
7982
sewardj270def42005-07-03 01:03:01 +00007983static ULong dis_SSE_shiftG_byE ( Prefix pfx, Long delta,
sewardjadffcef2005-05-11 00:03:06 +00007984 HChar* opname, IROp op )
7985{
7986 HChar dis_buf[50];
7987 Int alen, size;
7988 IRTemp addr;
7989 Bool shl, shr, sar;
7990 UChar rm = getUChar(delta);
7991 IRTemp g0 = newTemp(Ity_V128);
7992 IRTemp g1 = newTemp(Ity_V128);
7993 IRTemp amt = newTemp(Ity_I32);
7994 IRTemp amt8 = newTemp(Ity_I8);
7995 if (epartIsReg(rm)) {
7996 assign( amt, getXMMRegLane32(eregOfRexRM(pfx,rm), 0) );
7997 DIP("%s %s,%s\n", opname,
7998 nameXMMReg(eregOfRexRM(pfx,rm)),
7999 nameXMMReg(gregOfRexRM(pfx,rm)) );
8000 delta++;
8001 } else {
8002 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
8003 assign( amt, loadLE(Ity_I32, mkexpr(addr)) );
8004 DIP("%s %s,%s\n", opname,
8005 dis_buf,
8006 nameXMMReg(gregOfRexRM(pfx,rm)) );
8007 delta += alen;
8008 }
8009 assign( g0, getXMMReg(gregOfRexRM(pfx,rm)) );
8010 assign( amt8, unop(Iop_32to8, mkexpr(amt)) );
8011
8012 shl = shr = sar = False;
8013 size = 0;
8014 switch (op) {
8015 case Iop_ShlN16x8: shl = True; size = 32; break;
8016 case Iop_ShlN32x4: shl = True; size = 32; break;
8017 case Iop_ShlN64x2: shl = True; size = 64; break;
8018 case Iop_SarN16x8: sar = True; size = 16; break;
8019 case Iop_SarN32x4: sar = True; size = 32; break;
8020 case Iop_ShrN16x8: shr = True; size = 16; break;
8021 case Iop_ShrN32x4: shr = True; size = 32; break;
8022 case Iop_ShrN64x2: shr = True; size = 64; break;
8023 default: vassert(0);
8024 }
8025
8026 if (shl || shr) {
8027 assign(
8028 g1,
8029 IRExpr_Mux0X(
8030 unop(Iop_1Uto8,
8031 binop(Iop_CmpLT64U, unop(Iop_32Uto64,mkexpr(amt)), mkU64(size))),
8032 mkV128(0x0000),
8033 binop(op, mkexpr(g0), mkexpr(amt8))
8034 )
8035 );
8036 } else
8037 if (sar) {
8038 assign(
8039 g1,
8040 IRExpr_Mux0X(
8041 unop(Iop_1Uto8,
8042 binop(Iop_CmpLT64U, unop(Iop_32Uto64,mkexpr(amt)), mkU64(size))),
8043 binop(op, mkexpr(g0), mkU8(size-1)),
8044 binop(op, mkexpr(g0), mkexpr(amt8))
8045 )
8046 );
8047 } else {
8048 vassert(0);
8049 }
8050
8051 putXMMReg( gregOfRexRM(pfx,rm), mkexpr(g1) );
8052 return delta;
8053}
sewardj09717342005-05-05 21:34:02 +00008054
8055
8056/* Vector by scalar shift of E by an immediate byte. */
8057
8058static
8059ULong dis_SSE_shiftE_imm ( Prefix pfx,
sewardj270def42005-07-03 01:03:01 +00008060 Long delta, HChar* opname, IROp op )
sewardj09717342005-05-05 21:34:02 +00008061{
8062 Bool shl, shr, sar;
8063 UChar rm = getUChar(delta);
8064 IRTemp e0 = newTemp(Ity_V128);
8065 IRTemp e1 = newTemp(Ity_V128);
8066 UChar amt, size;
8067 vassert(epartIsReg(rm));
8068 vassert(gregLO3ofRM(rm) == 2
8069 || gregLO3ofRM(rm) == 4 || gregLO3ofRM(rm) == 6);
sewardjca673ab2005-05-11 10:03:08 +00008070 amt = getUChar(delta+1);
sewardj09717342005-05-05 21:34:02 +00008071 delta += 2;
8072 DIP("%s $%d,%s\n", opname,
8073 (Int)amt,
8074 nameXMMReg(eregOfRexRM(pfx,rm)) );
8075 assign( e0, getXMMReg(eregOfRexRM(pfx,rm)) );
8076
8077 shl = shr = sar = False;
8078 size = 0;
8079 switch (op) {
8080 case Iop_ShlN16x8: shl = True; size = 16; break;
8081 case Iop_ShlN32x4: shl = True; size = 32; break;
8082 case Iop_ShlN64x2: shl = True; size = 64; break;
8083 case Iop_SarN16x8: sar = True; size = 16; break;
8084 case Iop_SarN32x4: sar = True; size = 32; break;
8085 case Iop_ShrN16x8: shr = True; size = 16; break;
8086 case Iop_ShrN32x4: shr = True; size = 32; break;
8087 case Iop_ShrN64x2: shr = True; size = 64; break;
8088 default: vassert(0);
8089 }
8090
8091 if (shl || shr) {
8092 assign( e1, amt >= size
8093 ? mkV128(0x0000)
8094 : binop(op, mkexpr(e0), mkU8(amt))
8095 );
8096 } else
8097 if (sar) {
8098 assign( e1, amt >= size
8099 ? binop(op, mkexpr(e0), mkU8(size-1))
8100 : binop(op, mkexpr(e0), mkU8(amt))
8101 );
8102 } else {
8103 vassert(0);
8104 }
8105
8106 putXMMReg( eregOfRexRM(pfx,rm), mkexpr(e1) );
8107 return delta;
8108}
sewardj1a01e652005-02-23 11:39:21 +00008109
8110
8111/* Get the current SSE rounding mode. */
8112
8113static IRExpr* /* :: Ity_I32 */ get_sse_roundingmode ( void )
8114{
8115 return
8116 unop( Iop_64to32,
8117 binop( Iop_And64,
8118 IRExpr_Get( OFFB_SSEROUND, Ity_I64 ),
8119 mkU64(3) ));
8120}
8121
sewardjbcbb9de2005-03-27 02:22:32 +00008122static void put_sse_roundingmode ( IRExpr* sseround )
8123{
8124 vassert(typeOfIRExpr(irbb->tyenv, sseround) == Ity_I32);
8125 stmt( IRStmt_Put( OFFB_SSEROUND,
8126 unop(Iop_32Uto64,sseround) ) );
8127}
8128
sewardja7ba8c42005-05-10 20:08:34 +00008129/* Break a 128-bit value up into four 32-bit ints. */
8130
8131static void breakup128to32s ( IRTemp t128,
8132 /*OUTs*/
8133 IRTemp* t3, IRTemp* t2,
8134 IRTemp* t1, IRTemp* t0 )
8135{
8136 IRTemp hi64 = newTemp(Ity_I64);
8137 IRTemp lo64 = newTemp(Ity_I64);
8138 assign( hi64, unop(Iop_V128HIto64, mkexpr(t128)) );
8139 assign( lo64, unop(Iop_V128to64, mkexpr(t128)) );
8140
8141 vassert(t0 && *t0 == IRTemp_INVALID);
8142 vassert(t1 && *t1 == IRTemp_INVALID);
8143 vassert(t2 && *t2 == IRTemp_INVALID);
8144 vassert(t3 && *t3 == IRTemp_INVALID);
8145
8146 *t0 = newTemp(Ity_I32);
8147 *t1 = newTemp(Ity_I32);
8148 *t2 = newTemp(Ity_I32);
8149 *t3 = newTemp(Ity_I32);
8150 assign( *t0, unop(Iop_64to32, mkexpr(lo64)) );
8151 assign( *t1, unop(Iop_64HIto32, mkexpr(lo64)) );
8152 assign( *t2, unop(Iop_64to32, mkexpr(hi64)) );
8153 assign( *t3, unop(Iop_64HIto32, mkexpr(hi64)) );
8154}
8155
8156/* Construct a 128-bit value from four 32-bit ints. */
8157
8158static IRExpr* mk128from32s ( IRTemp t3, IRTemp t2,
8159 IRTemp t1, IRTemp t0 )
8160{
8161 return
8162 binop( Iop_64HLtoV128,
8163 binop(Iop_32HLto64, mkexpr(t3), mkexpr(t2)),
8164 binop(Iop_32HLto64, mkexpr(t1), mkexpr(t0))
8165 );
8166}
8167
8168/* Break a 64-bit value up into four 16-bit ints. */
8169
8170static void breakup64to16s ( IRTemp t64,
8171 /*OUTs*/
8172 IRTemp* t3, IRTemp* t2,
8173 IRTemp* t1, IRTemp* t0 )
8174{
8175 IRTemp hi32 = newTemp(Ity_I32);
8176 IRTemp lo32 = newTemp(Ity_I32);
8177 assign( hi32, unop(Iop_64HIto32, mkexpr(t64)) );
8178 assign( lo32, unop(Iop_64to32, mkexpr(t64)) );
8179
8180 vassert(t0 && *t0 == IRTemp_INVALID);
8181 vassert(t1 && *t1 == IRTemp_INVALID);
8182 vassert(t2 && *t2 == IRTemp_INVALID);
8183 vassert(t3 && *t3 == IRTemp_INVALID);
8184
8185 *t0 = newTemp(Ity_I16);
8186 *t1 = newTemp(Ity_I16);
8187 *t2 = newTemp(Ity_I16);
8188 *t3 = newTemp(Ity_I16);
8189 assign( *t0, unop(Iop_32to16, mkexpr(lo32)) );
8190 assign( *t1, unop(Iop_32HIto16, mkexpr(lo32)) );
8191 assign( *t2, unop(Iop_32to16, mkexpr(hi32)) );
8192 assign( *t3, unop(Iop_32HIto16, mkexpr(hi32)) );
8193}
8194
8195/* Construct a 64-bit value from four 16-bit ints. */
8196
8197static IRExpr* mk64from16s ( IRTemp t3, IRTemp t2,
8198 IRTemp t1, IRTemp t0 )
8199{
8200 return
8201 binop( Iop_32HLto64,
8202 binop(Iop_16HLto32, mkexpr(t3), mkexpr(t2)),
8203 binop(Iop_16HLto32, mkexpr(t1), mkexpr(t0))
8204 );
8205}
sewardjdf0e0022005-01-25 15:48:43 +00008206
8207
8208/*------------------------------------------------------------*/
8209/*--- Disassemble a single instruction ---*/
8210/*------------------------------------------------------------*/
8211
sewardj9e6491a2005-07-02 19:24:10 +00008212/* Disassemble a single instruction into IR. The instruction is
8213 located in host memory at &guest_code[delta]. */
sewardjdf0e0022005-01-25 15:48:43 +00008214
sewardj9e6491a2005-07-02 19:24:10 +00008215static
8216DisResult disInstr_AMD64_WRK (
8217 Bool put_IP,
sewardjc716aea2006-01-17 01:48:46 +00008218 Bool (*resteerOkFn) ( /*opaque*/void*, Addr64 ),
8219 void* callback_opaque,
sewardj9e6491a2005-07-02 19:24:10 +00008220 Long delta64,
8221 VexArchInfo* archinfo
8222 )
sewardjdf0e0022005-01-25 15:48:43 +00008223{
8224 IRType ty;
sewardja7ba8c42005-05-10 20:08:34 +00008225 IRTemp addr, t0, t1, t2, t3, t4, t5, t6;
sewardjdf0e0022005-01-25 15:48:43 +00008226 Int alen;
sewardj7a240552005-01-28 21:37:12 +00008227 UChar opc, modrm, /*abyte,*/ pre;
sewardj1027dc22005-02-26 01:55:02 +00008228 Long d64;
sewardjdf0e0022005-01-25 15:48:43 +00008229 HChar dis_buf[50];
8230 Int am_sz, d_sz, n, n_prefixes;
sewardj9e6491a2005-07-02 19:24:10 +00008231 DisResult dres;
sewardja6b93d12005-02-17 09:28:28 +00008232 UChar* insn; /* used in SSE decoders */
sewardjdf0e0022005-01-25 15:48:43 +00008233
sewardj9e6491a2005-07-02 19:24:10 +00008234 /* The running delta */
8235 Long delta = delta64;
8236
sewardjdf0e0022005-01-25 15:48:43 +00008237 /* Holds eip at the start of the insn, so that we can print
8238 consistent error messages for unimplemented insns. */
sewardj270def42005-07-03 01:03:01 +00008239 Long delta_start = delta;
sewardjdf0e0022005-01-25 15:48:43 +00008240
8241 /* sz denotes the nominal data-op size of the insn; we change it to
8242 2 if an 0x66 prefix is seen and 8 if REX.W is 1. In case of
8243 conflict REX.W takes precedence. */
8244 Int sz = 4;
8245
sewardj3ca55a12005-01-27 16:06:23 +00008246 /* pfx holds the summary of prefixes. */
8247 Prefix pfx = PFX_EMPTY;
sewardjdf0e0022005-01-25 15:48:43 +00008248
sewardj9e6491a2005-07-02 19:24:10 +00008249 /* Set result defaults. */
8250 dres.whatNext = Dis_Continue;
8251 dres.len = 0;
8252 dres.continueAt = 0;
sewardjdf0e0022005-01-25 15:48:43 +00008253
sewardj9e6491a2005-07-02 19:24:10 +00008254 vassert(guest_RIP_next_assumed == 0);
8255 vassert(guest_RIP_next_mustcheck == False);
sewardj4b744762005-02-07 15:02:25 +00008256
sewardja7ba8c42005-05-10 20:08:34 +00008257 addr = t0 = t1 = t2 = t3 = t4 = t5 = t6 = IRTemp_INVALID;
sewardjdf0e0022005-01-25 15:48:43 +00008258
sewardj9e6491a2005-07-02 19:24:10 +00008259 DIP("\t0x%llx: ", guest_RIP_bbstart+delta);
8260
8261 /* We may be asked to update the guest RIP before going further. */
8262 if (put_IP)
8263 stmt( IRStmt_Put( OFFB_RIP, mkU64(guest_RIP_curr_instr)) );
sewardjdf0e0022005-01-25 15:48:43 +00008264
sewardjce02aa72006-01-12 12:27:58 +00008265 /* Spot "Special" instructions (see comment at top of file). */
sewardjdf0e0022005-01-25 15:48:43 +00008266 {
8267 UChar* code = (UChar*)(guest_code + delta);
sewardjce02aa72006-01-12 12:27:58 +00008268 /* Spot the 16-byte preamble:
8269 48C1C703 rolq $3, %rdi
8270 48C1C70D rolq $13, %rdi
8271 48C1C73D rolq $61, %rdi
8272 48C1C733 rolq $51, %rdi
sewardjdf0e0022005-01-25 15:48:43 +00008273 */
sewardjce02aa72006-01-12 12:27:58 +00008274 if (code[ 0] == 0x48 && code[ 1] == 0xC1 && code[ 2] == 0xC7
8275 && code[ 3] == 0x03 &&
8276 code[ 4] == 0x48 && code[ 5] == 0xC1 && code[ 6] == 0xC7
8277 && code[ 7] == 0x0D &&
8278 code[ 8] == 0x48 && code[ 9] == 0xC1 && code[10] == 0xC7
8279 && code[11] == 0x3D &&
8280 code[12] == 0x48 && code[13] == 0xC1 && code[14] == 0xC7
8281 && code[15] == 0x33) {
8282 /* Got a "Special" instruction preamble. Which one is it? */
8283 if (code[16] == 0x48 && code[17] == 0x87
8284 && code[18] == 0xDB /* xchgq %rbx,%rbx */) {
8285 /* %RDX = client_request ( %RAX ) */
8286 DIP("%%rdx = client_request ( %%rax )\n");
8287 delta += 19;
8288 jmp_lit(Ijk_ClientReq, guest_RIP_bbstart+delta);
8289 dres.whatNext = Dis_StopHere;
8290 goto decode_success;
8291 }
8292 else
8293 if (code[16] == 0x48 && code[17] == 0x87
8294 && code[18] == 0xC9 /* xchgq %rcx,%rcx */) {
8295 /* %RAX = guest_NRADDR */
8296 DIP("%%rax = guest_NRADDR\n");
8297 delta += 19;
8298 putIRegRAX(8, IRExpr_Get( OFFB_NRADDR, Ity_I64 ));
8299 goto decode_success;
8300 }
8301 else
8302 if (code[16] == 0x48 && code[17] == 0x87
8303 && code[18] == 0xD2 /* xchgq %rdx,%rdx */) {
8304 /* call-noredir *%RAX */
8305 DIP("call-noredir *%%rax\n");
8306 delta += 19;
8307 t1 = newTemp(Ity_I64);
8308 assign(t1, getIRegRAX(8));
8309 t2 = newTemp(Ity_I64);
8310 assign(t2, binop(Iop_Sub64, getIReg64(R_RSP), mkU64(8)));
8311 putIReg64(R_RSP, mkexpr(t2));
8312 storeLE( mkexpr(t2), mkU64(guest_RIP_bbstart+delta));
8313 jmp_treg(Ijk_NoRedir,t1);
8314 dres.whatNext = Dis_StopHere;
8315 goto decode_success;
8316 }
8317 /* We don't know what it is. */
8318 goto decode_failure;
8319 /*NOTREACHED*/
sewardjdf0e0022005-01-25 15:48:43 +00008320 }
8321 }
8322
8323 /* Eat prefixes, summarising the result in pfx and sz, and rejecting
8324 as many invalid combinations as possible. */
8325 n_prefixes = 0;
8326 while (True) {
8327 if (n_prefixes > 5) goto decode_failure;
sewardj8c332e22005-01-28 01:36:56 +00008328 pre = getUChar(delta);
sewardjdf0e0022005-01-25 15:48:43 +00008329 switch (pre) {
8330 case 0x66: pfx |= PFX_66; break;
8331 case 0x67: pfx |= PFX_ASO; break;
8332 case 0xF2: pfx |= PFX_F2; break;
8333 case 0xF3: pfx |= PFX_F3; break;
8334 case 0xF0: pfx |= PFX_LOCK; break;
8335 case 0x2E: pfx |= PFX_CS; break;
8336 case 0x3E: pfx |= PFX_DS; break;
8337 case 0x26: pfx |= PFX_ES; break;
8338 case 0x64: pfx |= PFX_FS; break;
8339 case 0x65: pfx |= PFX_GS; break;
8340 case 0x36: pfx |= PFX_SS; break;
8341 case 0x40 ... 0x4F:
8342 pfx |= PFX_REX;
8343 if (pre & (1<<3)) pfx |= PFX_REXW;
8344 if (pre & (1<<2)) pfx |= PFX_REXR;
8345 if (pre & (1<<1)) pfx |= PFX_REXX;
8346 if (pre & (1<<0)) pfx |= PFX_REXB;
8347 break;
8348 default:
8349 goto not_a_prefix;
8350 }
8351 n_prefixes++;
8352 delta++;
8353 }
8354
8355 not_a_prefix:
sewardjdf0e0022005-01-25 15:48:43 +00008356
sewardj42561ef2005-11-04 14:18:31 +00008357 /* Dump invalid combinations */
sewardjdf0e0022005-01-25 15:48:43 +00008358 n = 0;
8359 if (pfx & PFX_F2) n++;
8360 if (pfx & PFX_F3) n++;
sewardj3ca55a12005-01-27 16:06:23 +00008361 if (n > 1)
8362 goto decode_failure; /* can't have both */
sewardjdf0e0022005-01-25 15:48:43 +00008363
8364 n = 0;
8365 if (pfx & PFX_CS) n++;
8366 if (pfx & PFX_DS) n++;
8367 if (pfx & PFX_ES) n++;
8368 if (pfx & PFX_FS) n++;
8369 if (pfx & PFX_GS) n++;
8370 if (pfx & PFX_SS) n++;
sewardj3ca55a12005-01-27 16:06:23 +00008371 if (n > 1)
8372 goto decode_failure; /* multiple seg overrides == illegal */
sewardjdf0e0022005-01-25 15:48:43 +00008373
sewardj42561ef2005-11-04 14:18:31 +00008374 if (pfx & PFX_GS)
8375 goto decode_failure; /* legal, but unsupported right now */
8376
sewardjdf0e0022005-01-25 15:48:43 +00008377 /* Set up sz. */
8378 sz = 4;
8379 if (pfx & PFX_66) sz = 2;
8380 if ((pfx & PFX_REX) && (pfx & PFX_REXW)) sz = 8;
8381
sewardj9ff93bc2005-03-23 11:25:12 +00008382 /* Kludge re LOCK prefixes. We assume here that all code generated
8383 by Vex is going to be run in a single-threaded context, in other
8384 words that concurrent executions of Vex-generated translations
8385 will not happen. That is certainly the case for how the
8386 Valgrind-3.0 code line uses Vex. Given that assumption, it
8387 seems safe to ignore LOCK prefixes since there will never be any
8388 other thread running at the same time as this one. However, at
8389 least emit a memory fence on the basis that it would at least be
8390 prudent to flush any memory transactions from this thread as far
8391 as possible down the memory hierarchy. */
8392 if (pfx & PFX_LOCK) {
8393 /* vex_printf("vex amd64->IR: ignoring LOCK prefix on: ");
8394 insn_verbose = True; */
8395 stmt( IRStmt_MFence() );
sewardjdf0e0022005-01-25 15:48:43 +00008396 }
8397
sewardja6b93d12005-02-17 09:28:28 +00008398
8399 /* ---------------------------------------------------- */
sewardj09717342005-05-05 21:34:02 +00008400 /* --- The SSE/SSE2 decoder. --- */
sewardja6b93d12005-02-17 09:28:28 +00008401 /* ---------------------------------------------------- */
8402
8403 /* What did I do to deserve SSE ? Perhaps I was really bad in a
8404 previous life? */
8405
sewardj09717342005-05-05 21:34:02 +00008406 /* Note, this doesn't handle SSE3 right now. All amd64s support
8407 SSE2 as a minimum so there is no point distinguishing SSE1 vs
8408 SSE2. */
8409
sewardja6b93d12005-02-17 09:28:28 +00008410 insn = (UChar*)&guest_code[delta];
8411
sewardjd20c8852005-01-20 20:04:07 +00008412//.. /* Treat fxsave specially. It should be doable even on an SSE0
8413//.. (Pentium-II class) CPU. Hence be prepared to handle it on
8414//.. any subarchitecture variant.
8415//.. */
8416//..
8417//.. /* 0F AE /0 = FXSAVE m512 -- write x87 and SSE state to memory */
8418//.. if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xAE
8419//.. && !epartIsReg(insn[2]) && gregOfRM(insn[2]) == 0) {
sewardj8c332e22005-01-28 01:36:56 +00008420//.. modrm = getUChar(delta+2);
sewardjd20c8852005-01-20 20:04:07 +00008421//.. vassert(sz == 4);
8422//.. vassert(!epartIsReg(modrm));
8423//..
8424//.. addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8425//.. delta += 2+alen;
8426//..
8427//.. DIP("fxsave %s\n", dis_buf);
8428//..
8429//.. /* Uses dirty helper:
8430//.. void x86g_do_FXSAVE ( VexGuestX86State*, UInt ) */
8431//.. IRDirty* d = unsafeIRDirty_0_N (
8432//.. 0/*regparms*/,
8433//.. "x86g_dirtyhelper_FXSAVE",
8434//.. &x86g_dirtyhelper_FXSAVE,
8435//.. mkIRExprVec_1( mkexpr(addr) )
8436//.. );
8437//.. d->needsBBP = True;
8438//..
8439//.. /* declare we're writing memory */
8440//.. d->mFx = Ifx_Write;
8441//.. d->mAddr = mkexpr(addr);
8442//.. d->mSize = 512;
8443//..
8444//.. /* declare we're reading guest state */
8445//.. d->nFxState = 7;
8446//..
8447//.. d->fxState[0].fx = Ifx_Read;
8448//.. d->fxState[0].offset = OFFB_FTOP;
8449//.. d->fxState[0].size = sizeof(UInt);
8450//..
8451//.. d->fxState[1].fx = Ifx_Read;
8452//.. d->fxState[1].offset = OFFB_FPREGS;
8453//.. d->fxState[1].size = 8 * sizeof(ULong);
8454//..
8455//.. d->fxState[2].fx = Ifx_Read;
8456//.. d->fxState[2].offset = OFFB_FPTAGS;
8457//.. d->fxState[2].size = 8 * sizeof(UChar);
8458//..
8459//.. d->fxState[3].fx = Ifx_Read;
8460//.. d->fxState[3].offset = OFFB_FPROUND;
8461//.. d->fxState[3].size = sizeof(UInt);
8462//..
8463//.. d->fxState[4].fx = Ifx_Read;
8464//.. d->fxState[4].offset = OFFB_FC3210;
8465//.. d->fxState[4].size = sizeof(UInt);
8466//..
8467//.. d->fxState[5].fx = Ifx_Read;
8468//.. d->fxState[5].offset = OFFB_XMM0;
8469//.. d->fxState[5].size = 8 * sizeof(U128);
8470//..
8471//.. d->fxState[6].fx = Ifx_Read;
8472//.. d->fxState[6].offset = OFFB_SSEROUND;
8473//.. d->fxState[6].size = sizeof(UInt);
8474//..
8475//.. /* Be paranoid ... this assertion tries to ensure the 8 %xmm
8476//.. images are packed back-to-back. If not, the value of
8477//.. d->fxState[5].size is wrong. */
8478//.. vassert(16 == sizeof(U128));
8479//.. vassert(OFFB_XMM7 == (OFFB_XMM0 + 7 * 16));
8480//..
8481//.. stmt( IRStmt_Dirty(d) );
8482//..
8483//.. goto decode_success;
8484//.. }
8485//..
8486//.. /* ------ SSE decoder main ------ */
8487//..
8488//.. /* Skip parts of the decoder which don't apply given the stated
8489//.. guest subarchitecture. */
8490//.. if (subarch == VexSubArchX86_sse0)
8491//.. goto after_sse_decoders;
8492//..
8493//.. /* Otherwise we must be doing sse1 or sse2, so we can at least try
8494//.. for SSE1 here. */
sewardj432f8b62005-05-10 02:50:05 +00008495
8496 /* 0F 58 = ADDPS -- add 32Fx4 from R/M to R */
8497 if (haveNo66noF2noF3(pfx) && sz == 4
8498 && insn[0] == 0x0F && insn[1] == 0x58) {
8499 delta = dis_SSE_E_to_G_all( pfx, delta+2, "addps", Iop_Add32Fx4 );
8500 goto decode_success;
8501 }
sewardj8d965312005-02-25 02:48:47 +00008502
8503 /* F3 0F 58 = ADDSS -- add 32F0x4 from R/M to R */
8504 if (haveF3no66noF2(pfx) && sz == 4
8505 && insn[0] == 0x0F && insn[1] == 0x58) {
8506 delta = dis_SSE_E_to_G_lo32( pfx, delta+2, "addss", Iop_Add32F0x4 );
8507 goto decode_success;
8508 }
8509
sewardj3aba9eb2005-03-30 23:20:47 +00008510 /* 0F 55 = ANDNPS -- G = (not G) and E */
8511 if (haveNo66noF2noF3(pfx) && sz == 4
8512 && insn[0] == 0x0F && insn[1] == 0x55) {
8513 delta = dis_SSE_E_to_G_all_invG( pfx, delta+2, "andnps", Iop_AndV128 );
8514 goto decode_success;
8515 }
sewardj37d52572005-02-25 14:22:12 +00008516
8517 /* 0F 54 = ANDPS -- G = G and E */
8518 if (haveNo66noF2noF3(pfx) && sz == 4
8519 && insn[0] == 0x0F && insn[1] == 0x54) {
8520 delta = dis_SSE_E_to_G_all( pfx, delta+2, "andps", Iop_AndV128 );
8521 goto decode_success;
8522 }
8523
sewardj432f8b62005-05-10 02:50:05 +00008524 /* 0F C2 = CMPPS -- 32Fx4 comparison from R/M to R */
8525 if (haveNo66noF2noF3(pfx) && sz == 4
8526 && insn[0] == 0x0F && insn[1] == 0xC2) {
8527 delta = dis_SSEcmp_E_to_G( pfx, delta+2, "cmpps", True, 4 );
8528 goto decode_success;
8529 }
sewardj3aba9eb2005-03-30 23:20:47 +00008530
8531 /* F3 0F C2 = CMPSS -- 32F0x4 comparison from R/M to R */
8532 if (haveF3no66noF2(pfx) && sz == 4
8533 && insn[0] == 0x0F && insn[1] == 0xC2) {
8534 delta = dis_SSEcmp_E_to_G( pfx, delta+2, "cmpss", False, 4 );
8535 goto decode_success;
8536 }
sewardjc49ce232005-02-25 13:03:03 +00008537
8538 /* 0F 2F = COMISS -- 32F0x4 comparison G,E, and set ZCP */
8539 /* 0F 2E = UCOMISS -- 32F0x4 comparison G,E, and set ZCP */
8540 if (haveNo66noF2noF3(pfx) && sz == 4
8541 && insn[0] == 0x0F && (insn[1] == 0x2F || insn[1] == 0x2E)) {
8542 IRTemp argL = newTemp(Ity_F32);
8543 IRTemp argR = newTemp(Ity_F32);
8544 modrm = getUChar(delta+2);
8545 if (epartIsReg(modrm)) {
8546 assign( argR, getXMMRegLane32F( eregOfRexRM(pfx,modrm),
8547 0/*lowest lane*/ ) );
8548 delta += 2+1;
8549 DIP("%scomiss %s,%s\n", insn[1]==0x2E ? "u" : "",
8550 nameXMMReg(eregOfRexRM(pfx,modrm)),
8551 nameXMMReg(gregOfRexRM(pfx,modrm)) );
8552 } else {
8553 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8554 assign( argR, loadLE(Ity_F32, mkexpr(addr)) );
8555 delta += 2+alen;
8556 DIP("%scomiss %s,%s\n", insn[1]==0x2E ? "u" : "",
8557 dis_buf,
8558 nameXMMReg(gregOfRexRM(pfx,modrm)) );
8559 }
8560 assign( argL, getXMMRegLane32F( gregOfRexRM(pfx,modrm),
8561 0/*lowest lane*/ ) );
8562
8563 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(AMD64G_CC_OP_COPY) ));
8564 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
8565 stmt( IRStmt_Put(
8566 OFFB_CC_DEP1,
8567 binop( Iop_And64,
8568 unop( Iop_32Uto64,
8569 binop(Iop_CmpF64,
8570 unop(Iop_F32toF64,mkexpr(argL)),
8571 unop(Iop_F32toF64,mkexpr(argR)))),
8572 mkU64(0x45)
8573 )));
8574
8575 goto decode_success;
8576 }
8577
sewardj432f8b62005-05-10 02:50:05 +00008578 /* 0F 2A = CVTPI2PS -- convert 2 x I32 in mem/mmx to 2 x F32 in low
8579 half xmm */
8580 if (haveNo66noF2noF3(pfx) && sz == 4
8581 && insn[0] == 0x0F && insn[1] == 0x2A) {
8582 IRTemp arg64 = newTemp(Ity_I64);
8583 IRTemp rmode = newTemp(Ity_I32);
8584
8585 modrm = getUChar(delta+2);
8586 do_MMX_preamble();
8587 if (epartIsReg(modrm)) {
8588 assign( arg64, getMMXReg(eregLO3ofRM(modrm)) );
8589 delta += 2+1;
8590 DIP("cvtpi2ps %s,%s\n", nameMMXReg(eregLO3ofRM(modrm)),
8591 nameXMMReg(gregOfRexRM(pfx,modrm)));
8592 } else {
8593 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8594 assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
8595 delta += 2+alen;
8596 DIP("cvtpi2ps %s,%s\n", dis_buf,
8597 nameXMMReg(gregOfRexRM(pfx,modrm)) );
8598 }
8599
8600 assign( rmode, get_sse_roundingmode() );
8601
8602 putXMMRegLane32F(
8603 gregOfRexRM(pfx,modrm), 0,
8604 binop(Iop_F64toF32,
8605 mkexpr(rmode),
8606 unop(Iop_I32toF64,
8607 unop(Iop_64to32, mkexpr(arg64)) )) );
8608
8609 putXMMRegLane32F(
8610 gregOfRexRM(pfx,modrm), 1,
8611 binop(Iop_F64toF32,
8612 mkexpr(rmode),
8613 unop(Iop_I32toF64,
8614 unop(Iop_64HIto32, mkexpr(arg64)) )) );
8615
8616 goto decode_success;
8617 }
sewardj8d965312005-02-25 02:48:47 +00008618
8619 /* F3 0F 2A = CVTSI2SS
8620 -- sz==4: convert I32 in mem/ireg to F32 in low quarter xmm
8621 -- sz==8: convert I64 in mem/ireg to F32 in low quarter xmm */
8622 if (haveF3no66noF2(pfx) && (sz == 4 || sz == 8)
8623 && insn[0] == 0x0F && insn[1] == 0x2A) {
8624
8625 IRTemp rmode = newTemp(Ity_I32);
8626 assign( rmode, get_sse_roundingmode() );
8627 modrm = getUChar(delta+2);
8628
8629 if (sz == 4) {
8630 IRTemp arg32 = newTemp(Ity_I32);
8631 if (epartIsReg(modrm)) {
sewardj5b470602005-02-27 13:10:48 +00008632 assign( arg32, getIReg32(eregOfRexRM(pfx,modrm)) );
sewardj8d965312005-02-25 02:48:47 +00008633 delta += 2+1;
sewardj5b470602005-02-27 13:10:48 +00008634 DIP("cvtsi2ss %s,%s\n", nameIReg32(eregOfRexRM(pfx,modrm)),
sewardj8d965312005-02-25 02:48:47 +00008635 nameXMMReg(gregOfRexRM(pfx,modrm)));
8636 } else {
sewardj8d965312005-02-25 02:48:47 +00008637 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8638 assign( arg32, loadLE(Ity_I32, mkexpr(addr)) );
8639 delta += 2+alen;
8640 DIP("cvtsi2ss %s,%s\n", dis_buf,
8641 nameXMMReg(gregOfRexRM(pfx,modrm)) );
8642 }
8643 putXMMRegLane32F(
8644 gregOfRexRM(pfx,modrm), 0,
8645 binop(Iop_F64toF32,
8646 mkexpr(rmode),
8647 unop(Iop_I32toF64, mkexpr(arg32)) ) );
8648 } else {
8649 /* sz == 8 */
8650 IRTemp arg64 = newTemp(Ity_I64);
8651 if (epartIsReg(modrm)) {
sewardj5b470602005-02-27 13:10:48 +00008652 assign( arg64, getIReg64(eregOfRexRM(pfx,modrm)) );
sewardj8d965312005-02-25 02:48:47 +00008653 delta += 2+1;
sewardj5b470602005-02-27 13:10:48 +00008654 DIP("cvtsi2ssq %s,%s\n", nameIReg64(eregOfRexRM(pfx,modrm)),
sewardj8d965312005-02-25 02:48:47 +00008655 nameXMMReg(gregOfRexRM(pfx,modrm)));
8656 } else {
sewardj82c9f2f2005-03-02 16:05:13 +00008657 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8658 assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
8659 delta += 2+alen;
8660 DIP("cvtsi2ssq %s,%s\n", dis_buf,
8661 nameXMMReg(gregOfRexRM(pfx,modrm)) );
sewardj8d965312005-02-25 02:48:47 +00008662 }
8663 putXMMRegLane32F(
8664 gregOfRexRM(pfx,modrm), 0,
8665 binop(Iop_F64toF32,
8666 mkexpr(rmode),
8667 binop(Iop_I64toF64, mkexpr(rmode), mkexpr(arg64)) ) );
8668 }
8669
8670 goto decode_success;
8671 }
8672
sewardj432f8b62005-05-10 02:50:05 +00008673 /* 0F 2D = CVTPS2PI -- convert 2 x F32 in mem/low half xmm to 2 x
8674 I32 in mmx, according to prevailing SSE rounding mode */
sewardja7ba8c42005-05-10 20:08:34 +00008675 /* 0F 2C = CVTTPS2PI -- convert 2 x F32 in mem/low half xmm to 2 x
8676 I32 in mmx, rounding towards zero */
sewardj432f8b62005-05-10 02:50:05 +00008677 if (haveNo66noF2noF3(pfx) && sz == 4
sewardja7ba8c42005-05-10 20:08:34 +00008678 && insn[0] == 0x0F && (insn[1] == 0x2D || insn[1] == 0x2C)) {
sewardj432f8b62005-05-10 02:50:05 +00008679 IRTemp dst64 = newTemp(Ity_I64);
8680 IRTemp rmode = newTemp(Ity_I32);
8681 IRTemp f32lo = newTemp(Ity_F32);
8682 IRTemp f32hi = newTemp(Ity_F32);
8683 Bool r2zero = toBool(insn[1] == 0x2C);
8684
8685 do_MMX_preamble();
8686 modrm = getUChar(delta+2);
8687
8688 if (epartIsReg(modrm)) {
8689 delta += 2+1;
8690 assign(f32lo, getXMMRegLane32F(eregOfRexRM(pfx,modrm), 0));
8691 assign(f32hi, getXMMRegLane32F(eregOfRexRM(pfx,modrm), 1));
8692 DIP("cvt%sps2pi %s,%s\n", r2zero ? "t" : "",
8693 nameXMMReg(eregOfRexRM(pfx,modrm)),
8694 nameMMXReg(gregLO3ofRM(modrm)));
8695 } else {
8696 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8697 assign(f32lo, loadLE(Ity_F32, mkexpr(addr)));
8698 assign(f32hi, loadLE(Ity_F32, binop( Iop_Add64,
8699 mkexpr(addr),
8700 mkU64(4) )));
8701 delta += 2+alen;
8702 DIP("cvt%sps2pi %s,%s\n", r2zero ? "t" : "",
8703 dis_buf,
8704 nameMMXReg(gregLO3ofRM(modrm)));
8705 }
8706
8707 if (r2zero) {
8708 assign(rmode, mkU32((UInt)Irrm_ZERO) );
8709 } else {
8710 assign( rmode, get_sse_roundingmode() );
8711 }
8712
8713 assign(
8714 dst64,
8715 binop( Iop_32HLto64,
8716 binop( Iop_F64toI32,
8717 mkexpr(rmode),
8718 unop( Iop_F32toF64, mkexpr(f32hi) ) ),
8719 binop( Iop_F64toI32,
8720 mkexpr(rmode),
8721 unop( Iop_F32toF64, mkexpr(f32lo) ) )
8722 )
8723 );
8724
8725 putMMXReg(gregLO3ofRM(modrm), mkexpr(dst64));
8726 goto decode_success;
8727 }
8728
8729 /* F3 0F 2D = CVTSS2SI
8730 when sz==4 -- convert F32 in mem/low quarter xmm to I32 in ireg,
8731 according to prevailing SSE rounding mode
8732 when sz==8 -- convert F32 in mem/low quarter xmm to I64 in ireg,
8733 according to prevailing SSE rounding mode
8734 */
sewardj82c9f2f2005-03-02 16:05:13 +00008735 /* F3 0F 2C = CVTTSS2SI
8736 when sz==4 -- convert F32 in mem/low quarter xmm to I32 in ireg,
8737 truncating towards zero
8738 when sz==8 -- convert F32 in mem/low quarter xmm to I64 in ireg,
8739 truncating towards zero
8740 */
8741 if (haveF3no66noF2(pfx)
8742 && insn[0] == 0x0F
sewardj432f8b62005-05-10 02:50:05 +00008743 && (insn[1] == 0x2D || insn[1] == 0x2C)) {
sewardj82c9f2f2005-03-02 16:05:13 +00008744 IRTemp rmode = newTemp(Ity_I32);
8745 IRTemp f32lo = newTemp(Ity_F32);
8746 Bool r2zero = toBool(insn[1] == 0x2C);
8747 vassert(sz == 4 || sz == 8);
8748
8749 modrm = getUChar(delta+2);
8750 if (epartIsReg(modrm)) {
8751 delta += 2+1;
8752 assign(f32lo, getXMMRegLane32F(eregOfRexRM(pfx,modrm), 0));
8753 DIP("cvt%sss2si %s,%s\n", r2zero ? "t" : "",
8754 nameXMMReg(eregOfRexRM(pfx,modrm)),
8755 nameIReg(sz, gregOfRexRM(pfx,modrm), False));
8756 } else {
8757 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8758 assign(f32lo, loadLE(Ity_F32, mkexpr(addr)));
8759 delta += 2+alen;
8760 DIP("cvt%sss2si %s,%s\n", r2zero ? "t" : "",
8761 dis_buf,
8762 nameIReg(sz, gregOfRexRM(pfx,modrm), False));
8763 }
8764
8765 if (r2zero) {
8766 assign( rmode, mkU32((UInt)Irrm_ZERO) );
8767 } else {
8768 assign( rmode, get_sse_roundingmode() );
8769 }
8770
8771 if (sz == 4) {
8772 putIReg32( gregOfRexRM(pfx,modrm),
8773 binop( Iop_F64toI32,
8774 mkexpr(rmode),
8775 unop(Iop_F32toF64, mkexpr(f32lo))) );
8776 } else {
8777 putIReg64( gregOfRexRM(pfx,modrm),
8778 binop( Iop_F64toI64,
8779 mkexpr(rmode),
8780 unop(Iop_F32toF64, mkexpr(f32lo))) );
8781 }
8782
8783 goto decode_success;
8784 }
8785
sewardj432f8b62005-05-10 02:50:05 +00008786 /* 0F 5E = DIVPS -- div 32Fx4 from R/M to R */
8787 if (haveNo66noF2noF3(pfx) && sz == 4
8788 && insn[0] == 0x0F && insn[1] == 0x5E) {
8789 delta = dis_SSE_E_to_G_all( pfx, delta+2, "divps", Iop_Div32Fx4 );
8790 goto decode_success;
8791 }
sewardjc49ce232005-02-25 13:03:03 +00008792
8793 /* F3 0F 5E = DIVSS -- div 32F0x4 from R/M to R */
8794 if (haveF3no66noF2(pfx) && sz == 4
8795 && insn[0] == 0x0F && insn[1] == 0x5E) {
8796 delta = dis_SSE_E_to_G_lo32( pfx, delta+2, "divss", Iop_Div32F0x4 );
8797 goto decode_success;
8798 }
8799
sewardjbcbb9de2005-03-27 02:22:32 +00008800 /* 0F AE /2 = LDMXCSR m32 -- load %mxcsr */
8801 if (insn[0] == 0x0F && insn[1] == 0xAE
8802 && haveNo66noF2noF3(pfx)
8803 && !epartIsReg(insn[2]) && gregLO3ofRM(insn[2]) == 2) {
8804
8805 IRTemp t64 = newTemp(Ity_I64);
8806 IRTemp ew = newTemp(Ity_I32);
8807
8808 vassert(sz == 4);
8809 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8810 delta += 2+alen;
8811 DIP("ldmxcsr %s\n", dis_buf);
8812
8813 /* The only thing we observe in %mxcsr is the rounding mode.
8814 Therefore, pass the 32-bit value (SSE native-format control
8815 word) to a clean helper, getting back a 64-bit value, the
8816 lower half of which is the SSEROUND value to store, and the
8817 upper half of which is the emulation-warning token which may
8818 be generated.
8819 */
8820 /* ULong amd64h_check_ldmxcsr ( ULong ); */
8821 assign( t64, mkIRExprCCall(
8822 Ity_I64, 0/*regparms*/,
8823 "amd64g_check_ldmxcsr",
8824 &amd64g_check_ldmxcsr,
8825 mkIRExprVec_1(
8826 unop(Iop_32Uto64,
8827 loadLE(Ity_I32, mkexpr(addr))
8828 )
8829 )
8830 )
8831 );
8832
8833 put_sse_roundingmode( unop(Iop_64to32, mkexpr(t64)) );
8834 assign( ew, unop(Iop_64HIto32, mkexpr(t64) ) );
8835 put_emwarn( mkexpr(ew) );
8836 /* Finally, if an emulation warning was reported, side-exit to
8837 the next insn, reporting the warning, so that Valgrind's
8838 dispatcher sees the warning. */
8839 stmt(
8840 IRStmt_Exit(
8841 binop(Iop_CmpNE64, unop(Iop_32Uto64,mkexpr(ew)), mkU64(0)),
8842 Ijk_EmWarn,
sewardj9e6491a2005-07-02 19:24:10 +00008843 IRConst_U64(guest_RIP_bbstart+delta)
sewardjbcbb9de2005-03-27 02:22:32 +00008844 )
8845 );
8846 goto decode_success;
8847 }
8848
sewardj432f8b62005-05-10 02:50:05 +00008849 /* 0F 5F = MAXPS -- max 32Fx4 from R/M to R */
8850 if (haveNo66noF2noF3(pfx) && sz == 4
8851 && insn[0] == 0x0F && insn[1] == 0x5F) {
8852 delta = dis_SSE_E_to_G_all( pfx, delta+2, "maxps", Iop_Max32Fx4 );
8853 goto decode_success;
8854 }
sewardj37d52572005-02-25 14:22:12 +00008855
8856 /* F3 0F 5F = MAXSS -- max 32F0x4 from R/M to R */
8857 if (haveF3no66noF2(pfx) && sz == 4
8858 && insn[0] == 0x0F && insn[1] == 0x5F) {
8859 delta = dis_SSE_E_to_G_lo32( pfx, delta+2, "maxss", Iop_Max32F0x4 );
8860 goto decode_success;
8861 }
8862
sewardj432f8b62005-05-10 02:50:05 +00008863 /* 0F 5D = MINPS -- min 32Fx4 from R/M to R */
8864 if (haveNo66noF2noF3(pfx) && sz == 4
8865 && insn[0] == 0x0F && insn[1] == 0x5D) {
8866 delta = dis_SSE_E_to_G_all( pfx, delta+2, "minps", Iop_Min32Fx4 );
8867 goto decode_success;
8868 }
sewardj37d52572005-02-25 14:22:12 +00008869
8870 /* F3 0F 5D = MINSS -- min 32F0x4 from R/M to R */
8871 if (haveF3no66noF2(pfx) && sz == 4
8872 && insn[0] == 0x0F && insn[1] == 0x5D) {
8873 delta = dis_SSE_E_to_G_lo32( pfx, delta+2, "minss", Iop_Min32F0x4 );
8874 goto decode_success;
8875 }
sewardj8d965312005-02-25 02:48:47 +00008876
8877 /* 0F 28 = MOVAPS -- move from E (mem or xmm) to G (xmm). */
8878 /* 0F 10 = MOVUPS -- move from E (mem or xmm) to G (xmm). */
8879 if (haveNo66noF2noF3(pfx) && sz == 4
8880 && insn[0] == 0x0F && (insn[1] == 0x28 || insn[1] == 0x10)) {
8881 modrm = getUChar(delta+2);
8882 if (epartIsReg(modrm)) {
8883 putXMMReg( gregOfRexRM(pfx,modrm),
8884 getXMMReg( eregOfRexRM(pfx,modrm) ));
8885 DIP("mov[ua]ps %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
8886 nameXMMReg(gregOfRexRM(pfx,modrm)));
8887 delta += 2+1;
8888 } else {
8889 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8890 putXMMReg( gregOfRexRM(pfx,modrm),
8891 loadLE(Ity_V128, mkexpr(addr)) );
8892 DIP("mov[ua]ps %s,%s\n", dis_buf,
8893 nameXMMReg(gregOfRexRM(pfx,modrm)));
8894 delta += 2+alen;
8895 }
8896 goto decode_success;
8897 }
sewardj1001dc42005-02-21 08:25:55 +00008898
8899 /* 0F 29 = MOVAPS -- move from G (xmm) to E (mem or xmm). */
sewardj446d2672005-06-10 11:04:52 +00008900 /* 0F 11 = MOVUPS -- move from G (xmm) to E (mem or xmm). */
sewardj8d965312005-02-25 02:48:47 +00008901 if (haveNo66noF2noF3(pfx) && sz == 4
sewardj446d2672005-06-10 11:04:52 +00008902 && insn[0] == 0x0F && (insn[1] == 0x29 || insn[1] == 0x11)) {
sewardj1001dc42005-02-21 08:25:55 +00008903 modrm = getUChar(delta+2);
8904 if (epartIsReg(modrm)) {
8905 /* fall through; awaiting test case */
8906 } else {
8907 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8908 storeLE( mkexpr(addr), getXMMReg(gregOfRexRM(pfx,modrm)) );
sewardj446d2672005-06-10 11:04:52 +00008909 DIP("mov[ua]ps %s,%s\n", nameXMMReg(gregOfRexRM(pfx,modrm)),
8910 dis_buf );
sewardj1001dc42005-02-21 08:25:55 +00008911 delta += 2+alen;
8912 goto decode_success;
8913 }
8914 }
8915
sewardj432f8b62005-05-10 02:50:05 +00008916 /* 0F 16 = MOVHPS -- move from mem to high half of XMM. */
8917 /* 0F 16 = MOVLHPS -- move from lo half to hi half of XMM. */
8918 if (haveNo66noF2noF3(pfx) && sz == 4
8919 && insn[0] == 0x0F && insn[1] == 0x16) {
8920 modrm = getUChar(delta+2);
8921 if (epartIsReg(modrm)) {
8922 delta += 2+1;
8923 putXMMRegLane64( gregOfRexRM(pfx,modrm), 1/*upper lane*/,
8924 getXMMRegLane64( eregOfRexRM(pfx,modrm), 0 ) );
8925 DIP("movhps %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
8926 nameXMMReg(gregOfRexRM(pfx,modrm)));
8927 } else {
8928 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8929 delta += 2+alen;
8930 putXMMRegLane64( gregOfRexRM(pfx,modrm), 1/*upper lane*/,
8931 loadLE(Ity_I64, mkexpr(addr)) );
8932 DIP("movhps %s,%s\n", dis_buf,
8933 nameXMMReg( gregOfRexRM(pfx,modrm) ));
8934 }
8935 goto decode_success;
8936 }
8937
8938 /* 0F 17 = MOVHPS -- move from high half of XMM to mem. */
8939 if (haveNo66noF2noF3(pfx) && sz == 4
8940 && insn[0] == 0x0F && insn[1] == 0x17) {
8941 if (!epartIsReg(insn[2])) {
8942 delta += 2;
8943 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
8944 delta += alen;
8945 storeLE( mkexpr(addr),
8946 getXMMRegLane64( gregOfRexRM(pfx,insn[2]),
8947 1/*upper lane*/ ) );
8948 DIP("movhps %s,%s\n", nameXMMReg( gregOfRexRM(pfx,insn[2]) ),
8949 dis_buf);
8950 goto decode_success;
8951 }
8952 /* else fall through */
8953 }
8954
8955 /* 0F 12 = MOVLPS -- move from mem to low half of XMM. */
8956 /* OF 12 = MOVHLPS -- from from hi half to lo half of XMM. */
8957 if (haveNo66noF2noF3(pfx) && sz == 4
8958 && insn[0] == 0x0F && insn[1] == 0x12) {
8959 modrm = getUChar(delta+2);
8960 if (epartIsReg(modrm)) {
8961 delta += 2+1;
8962 putXMMRegLane64( gregOfRexRM(pfx,modrm),
8963 0/*lower lane*/,
8964 getXMMRegLane64( eregOfRexRM(pfx,modrm), 1 ));
8965 DIP("movhlps %s, %s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
8966 nameXMMReg(gregOfRexRM(pfx,modrm)));
8967 } else {
8968 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8969 delta += 2+alen;
8970 putXMMRegLane64( gregOfRexRM(pfx,modrm), 0/*lower lane*/,
8971 loadLE(Ity_I64, mkexpr(addr)) );
8972 DIP("movlps %s, %s\n",
8973 dis_buf, nameXMMReg( gregOfRexRM(pfx,modrm) ));
8974 }
8975 goto decode_success;
8976 }
8977
8978 /* 0F 13 = MOVLPS -- move from low half of XMM to mem. */
8979 if (haveNo66noF2noF3(pfx) && sz == 4
8980 && insn[0] == 0x0F && insn[1] == 0x13) {
8981 if (!epartIsReg(insn[2])) {
8982 delta += 2;
8983 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
8984 delta += alen;
8985 storeLE( mkexpr(addr),
8986 getXMMRegLane64( gregOfRexRM(pfx,insn[2]),
8987 0/*lower lane*/ ) );
8988 DIP("movlps %s, %s\n", nameXMMReg( gregOfRexRM(pfx,insn[2]) ),
8989 dis_buf);
8990 goto decode_success;
8991 }
8992 /* else fall through */
8993 }
8994
sewardja7ba8c42005-05-10 20:08:34 +00008995 /* 0F 50 = MOVMSKPS - move 4 sign bits from 4 x F32 in xmm(E)
8996 to 4 lowest bits of ireg(G) */
sewardjae84d782006-04-13 22:06:35 +00008997 if (haveNo66noF2noF3(pfx) && (sz == 4 || sz == 8)
sewardja7ba8c42005-05-10 20:08:34 +00008998 && insn[0] == 0x0F && insn[1] == 0x50) {
sewardjae84d782006-04-13 22:06:35 +00008999 /* sz == 8 is a kludge to handle insns with REX.W redundantly
9000 set to 1, which has been known to happen:
9001 4c 0f 50 d9 rex64X movmskps %xmm1,%r11d
9002 */
sewardja7ba8c42005-05-10 20:08:34 +00009003 modrm = getUChar(delta+2);
9004 if (epartIsReg(modrm)) {
9005 Int src;
9006 t0 = newTemp(Ity_I32);
9007 t1 = newTemp(Ity_I32);
9008 t2 = newTemp(Ity_I32);
9009 t3 = newTemp(Ity_I32);
9010 delta += 2+1;
9011 src = eregOfRexRM(pfx,modrm);
9012 assign( t0, binop( Iop_And32,
9013 binop(Iop_Shr32, getXMMRegLane32(src,0), mkU8(31)),
9014 mkU32(1) ));
9015 assign( t1, binop( Iop_And32,
9016 binop(Iop_Shr32, getXMMRegLane32(src,1), mkU8(30)),
9017 mkU32(2) ));
9018 assign( t2, binop( Iop_And32,
9019 binop(Iop_Shr32, getXMMRegLane32(src,2), mkU8(29)),
9020 mkU32(4) ));
9021 assign( t3, binop( Iop_And32,
9022 binop(Iop_Shr32, getXMMRegLane32(src,3), mkU8(28)),
9023 mkU32(8) ));
9024 putIReg32( gregOfRexRM(pfx,modrm),
9025 binop(Iop_Or32,
9026 binop(Iop_Or32, mkexpr(t0), mkexpr(t1)),
9027 binop(Iop_Or32, mkexpr(t2), mkexpr(t3))
9028 )
9029 );
9030 DIP("movmskps %s,%s\n", nameXMMReg(src),
9031 nameIReg32(gregOfRexRM(pfx,modrm)));
9032 goto decode_success;
9033 }
9034 /* else fall through */
9035 }
9036
sewardj612be432005-05-11 02:55:54 +00009037 /* 66 0F 2B = MOVNTPD -- for us, just a plain SSE store. */
sewardja7ba8c42005-05-10 20:08:34 +00009038 /* 0F 2B = MOVNTPS -- for us, just a plain SSE store. */
sewardj612be432005-05-11 02:55:54 +00009039 if ( ( (haveNo66noF2noF3(pfx) && sz == 4)
9040 || (have66noF2noF3(pfx) && sz == 2)
9041 )
9042 && insn[0] == 0x0F && insn[1] == 0x2B) {
sewardja7ba8c42005-05-10 20:08:34 +00009043 modrm = getUChar(delta+2);
9044 if (!epartIsReg(modrm)) {
9045 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9046 storeLE( mkexpr(addr), getXMMReg(gregOfRexRM(pfx,modrm)) );
sewardj612be432005-05-11 02:55:54 +00009047 DIP("movntp%s %s,%s\n", sz==2 ? "d" : "s",
9048 dis_buf,
9049 nameXMMReg(gregOfRexRM(pfx,modrm)));
sewardja7ba8c42005-05-10 20:08:34 +00009050 delta += 2+alen;
9051 goto decode_success;
9052 }
9053 /* else fall through */
9054 }
9055
9056 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9057 /* 0F E7 = MOVNTQ -- for us, just a plain MMX store. Note, the
9058 Intel manual does not say anything about the usual business of
9059 the FP reg tags getting trashed whenever an MMX insn happens.
9060 So we just leave them alone.
9061 */
9062 if (haveNo66noF2noF3(pfx) && sz == 4
9063 && insn[0] == 0x0F && insn[1] == 0xE7) {
9064 modrm = getUChar(delta+2);
9065 if (!epartIsReg(modrm)) {
9066 /* do_MMX_preamble(); Intel docs don't specify this */
9067 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9068 storeLE( mkexpr(addr), getMMXReg(gregLO3ofRM(modrm)) );
9069 DIP("movntq %s,%s\n", dis_buf,
9070 nameMMXReg(gregLO3ofRM(modrm)));
9071 delta += 2+alen;
9072 goto decode_success;
9073 }
9074 /* else fall through */
9075 }
sewardj8d965312005-02-25 02:48:47 +00009076
9077 /* F3 0F 10 = MOVSS -- move 32 bits from E (mem or lo 1/4 xmm) to G
9078 (lo 1/4 xmm). If E is mem, upper 3/4 of G is zeroed out. */
9079 if (haveF3no66noF2(pfx) && sz == 4
9080 && insn[0] == 0x0F && insn[1] == 0x10) {
9081 modrm = getUChar(delta+2);
9082 if (epartIsReg(modrm)) {
9083 putXMMRegLane32( gregOfRexRM(pfx,modrm), 0,
9084 getXMMRegLane32( eregOfRexRM(pfx,modrm), 0 ));
9085 DIP("movss %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
9086 nameXMMReg(gregOfRexRM(pfx,modrm)));
9087 delta += 2+1;
9088 } else {
9089 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9090 putXMMReg( gregOfRexRM(pfx,modrm), mkV128(0) );
9091 putXMMRegLane32( gregOfRexRM(pfx,modrm), 0,
9092 loadLE(Ity_I32, mkexpr(addr)) );
9093 DIP("movss %s,%s\n", dis_buf,
9094 nameXMMReg(gregOfRexRM(pfx,modrm)));
9095 delta += 2+alen;
9096 }
9097 goto decode_success;
9098 }
9099
9100 /* F3 0F 11 = MOVSS -- move 32 bits from G (lo 1/4 xmm) to E (mem
9101 or lo 1/4 xmm). */
9102 if (haveF3no66noF2(pfx) && sz == 4
9103 && insn[0] == 0x0F && insn[1] == 0x11) {
9104 modrm = getUChar(delta+2);
9105 if (epartIsReg(modrm)) {
9106 /* fall through, we don't yet have a test case */
9107 } else {
9108 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9109 storeLE( mkexpr(addr),
9110 getXMMRegLane32(gregOfRexRM(pfx,modrm), 0) );
9111 DIP("movss %s,%s\n", nameXMMReg(gregOfRexRM(pfx,modrm)),
9112 dis_buf);
9113 delta += 2+alen;
9114 goto decode_success;
9115 }
9116 }
9117
sewardj432f8b62005-05-10 02:50:05 +00009118 /* 0F 59 = MULPS -- mul 32Fx4 from R/M to R */
9119 if (haveNo66noF2noF3(pfx) && sz == 4
9120 && insn[0] == 0x0F && insn[1] == 0x59) {
9121 delta = dis_SSE_E_to_G_all( pfx, delta+2, "mulps", Iop_Mul32Fx4 );
9122 goto decode_success;
9123 }
sewardj8d965312005-02-25 02:48:47 +00009124
9125 /* F3 0F 59 = MULSS -- mul 32F0x4 from R/M to R */
9126 if (haveF3no66noF2(pfx) && sz == 4
9127 && insn[0] == 0x0F && insn[1] == 0x59) {
9128 delta = dis_SSE_E_to_G_lo32( pfx, delta+2, "mulss", Iop_Mul32F0x4 );
9129 goto decode_success;
9130 }
9131
sewardj3aba9eb2005-03-30 23:20:47 +00009132 /* 0F 56 = ORPS -- G = G and E */
9133 if (haveNo66noF2noF3(pfx) && sz == 4
9134 && insn[0] == 0x0F && insn[1] == 0x56) {
9135 delta = dis_SSE_E_to_G_all( pfx, delta+2, "orps", Iop_OrV128 );
9136 goto decode_success;
9137 }
9138
sewardja7ba8c42005-05-10 20:08:34 +00009139 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9140 /* 0F E0 = PAVGB -- 8x8 unsigned Packed Average, with rounding */
9141 if (haveNo66noF2noF3(pfx) && sz == 4
9142 && insn[0] == 0x0F && insn[1] == 0xE0) {
9143 do_MMX_preamble();
9144 delta = dis_MMXop_regmem_to_reg (
9145 pfx, delta+2, insn[1], "pavgb", False );
9146 goto decode_success;
9147 }
9148
9149 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9150 /* 0F E3 = PAVGW -- 16x4 unsigned Packed Average, with rounding */
9151 if (haveNo66noF2noF3(pfx) && sz == 4
9152 && insn[0] == 0x0F && insn[1] == 0xE3) {
9153 do_MMX_preamble();
9154 delta = dis_MMXop_regmem_to_reg (
9155 pfx, delta+2, insn[1], "pavgw", False );
9156 goto decode_success;
9157 }
9158
9159 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9160 /* 0F C5 = PEXTRW -- extract 16-bit field from mmx(E) and put
9161 zero-extend of it in ireg(G). */
sewardj9e234f62006-09-11 14:37:27 +00009162 if (haveNo66noF2noF3(pfx) && (sz == 4 || sz == 8)
sewardja7ba8c42005-05-10 20:08:34 +00009163 && insn[0] == 0x0F && insn[1] == 0xC5) {
9164 modrm = insn[2];
9165 if (epartIsReg(modrm)) {
9166 IRTemp sV = newTemp(Ity_I64);
9167 t5 = newTemp(Ity_I16);
9168 do_MMX_preamble();
9169 assign(sV, getMMXReg(eregLO3ofRM(modrm)));
9170 breakup64to16s( sV, &t3, &t2, &t1, &t0 );
9171 switch (insn[3] & 3) {
9172 case 0: assign(t5, mkexpr(t0)); break;
9173 case 1: assign(t5, mkexpr(t1)); break;
9174 case 2: assign(t5, mkexpr(t2)); break;
9175 case 3: assign(t5, mkexpr(t3)); break;
9176 default: vassert(0);
9177 }
sewardj9e234f62006-09-11 14:37:27 +00009178 if (sz == 8)
9179 putIReg64(gregOfRexRM(pfx,modrm), unop(Iop_16Uto64, mkexpr(t5)));
9180 else
9181 putIReg32(gregOfRexRM(pfx,modrm), unop(Iop_16Uto32, mkexpr(t5)));
sewardja7ba8c42005-05-10 20:08:34 +00009182 DIP("pextrw $%d,%s,%s\n",
9183 (Int)insn[3], nameMMXReg(eregLO3ofRM(modrm)),
sewardj9e234f62006-09-11 14:37:27 +00009184 sz==8 ? nameIReg64(gregOfRexRM(pfx,modrm))
9185 : nameIReg32(gregOfRexRM(pfx,modrm))
9186 );
sewardja7ba8c42005-05-10 20:08:34 +00009187 delta += 4;
9188 goto decode_success;
9189 }
9190 /* else fall through */
9191 /* note, for anyone filling in the mem case: this insn has one
9192 byte after the amode and therefore you must pass 1 as the
9193 last arg to disAMode */
9194 }
9195
9196 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9197 /* 0F C4 = PINSRW -- get 16 bits from E(mem or low half ireg) and
9198 put it into the specified lane of mmx(G). */
9199 if (haveNo66noF2noF3(pfx) && sz == 4
9200 && insn[0] == 0x0F && insn[1] == 0xC4) {
9201 /* Use t0 .. t3 to hold the 4 original 16-bit lanes of the
9202 mmx reg. t4 is the new lane value. t5 is the original
9203 mmx value. t6 is the new mmx value. */
9204 Int lane;
9205 t4 = newTemp(Ity_I16);
9206 t5 = newTemp(Ity_I64);
9207 t6 = newTemp(Ity_I64);
9208 modrm = insn[2];
9209 do_MMX_preamble();
9210
9211 assign(t5, getMMXReg(gregLO3ofRM(modrm)));
9212 breakup64to16s( t5, &t3, &t2, &t1, &t0 );
9213
9214 if (epartIsReg(modrm)) {
9215 assign(t4, getIReg16(eregOfRexRM(pfx,modrm)));
9216 delta += 3+1;
9217 lane = insn[3+1-1];
9218 DIP("pinsrw $%d,%s,%s\n", (Int)lane,
9219 nameIReg16(eregOfRexRM(pfx,modrm)),
9220 nameMMXReg(gregLO3ofRM(modrm)));
9221 } else {
9222 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 1 );
9223 delta += 3+alen;
9224 lane = insn[3+alen-1];
9225 assign(t4, loadLE(Ity_I16, mkexpr(addr)));
9226 DIP("pinsrw $%d,%s,%s\n", (Int)lane,
9227 dis_buf,
9228 nameMMXReg(gregLO3ofRM(modrm)));
9229 }
9230
9231 switch (lane & 3) {
9232 case 0: assign(t6, mk64from16s(t3,t2,t1,t4)); break;
9233 case 1: assign(t6, mk64from16s(t3,t2,t4,t0)); break;
9234 case 2: assign(t6, mk64from16s(t3,t4,t1,t0)); break;
9235 case 3: assign(t6, mk64from16s(t4,t2,t1,t0)); break;
9236 default: vassert(0);
9237 }
9238 putMMXReg(gregLO3ofRM(modrm), mkexpr(t6));
9239 goto decode_success;
9240 }
9241
9242 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9243 /* 0F EE = PMAXSW -- 16x4 signed max */
9244 if (haveNo66noF2noF3(pfx) && sz == 4
9245 && insn[0] == 0x0F && insn[1] == 0xEE) {
9246 do_MMX_preamble();
9247 delta = dis_MMXop_regmem_to_reg (
9248 pfx, delta+2, insn[1], "pmaxsw", False );
9249 goto decode_success;
9250 }
9251
9252 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9253 /* 0F DE = PMAXUB -- 8x8 unsigned max */
9254 if (haveNo66noF2noF3(pfx) && sz == 4
9255 && insn[0] == 0x0F && insn[1] == 0xDE) {
9256 do_MMX_preamble();
9257 delta = dis_MMXop_regmem_to_reg (
9258 pfx, delta+2, insn[1], "pmaxub", False );
9259 goto decode_success;
9260 }
9261
9262 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9263 /* 0F EA = PMINSW -- 16x4 signed min */
9264 if (haveNo66noF2noF3(pfx) && sz == 4
9265 && insn[0] == 0x0F && insn[1] == 0xEA) {
9266 do_MMX_preamble();
9267 delta = dis_MMXop_regmem_to_reg (
9268 pfx, delta+2, insn[1], "pminsw", False );
9269 goto decode_success;
9270 }
9271
9272 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9273 /* 0F DA = PMINUB -- 8x8 unsigned min */
9274 if (haveNo66noF2noF3(pfx) && sz == 4
9275 && insn[0] == 0x0F && insn[1] == 0xDA) {
9276 do_MMX_preamble();
9277 delta = dis_MMXop_regmem_to_reg (
9278 pfx, delta+2, insn[1], "pminub", False );
9279 goto decode_success;
9280 }
9281
9282 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9283 /* 0F D7 = PMOVMSKB -- extract sign bits from each of 8 lanes in
9284 mmx(G), turn them into a byte, and put zero-extend of it in
9285 ireg(G). */
9286 if (haveNo66noF2noF3(pfx) && sz == 4
9287 && insn[0] == 0x0F && insn[1] == 0xD7) {
9288 modrm = insn[2];
9289 if (epartIsReg(modrm)) {
9290 do_MMX_preamble();
9291 t0 = newTemp(Ity_I64);
9292 t1 = newTemp(Ity_I64);
9293 assign(t0, getMMXReg(eregLO3ofRM(modrm)));
9294 assign(t1, mkIRExprCCall(
9295 Ity_I64, 0/*regparms*/,
9296 "amd64g_calculate_mmx_pmovmskb",
9297 &amd64g_calculate_mmx_pmovmskb,
9298 mkIRExprVec_1(mkexpr(t0))));
9299 putIReg32(gregOfRexRM(pfx,modrm), unop(Iop_64to32,mkexpr(t1)));
9300 DIP("pmovmskb %s,%s\n", nameMMXReg(eregLO3ofRM(modrm)),
9301 nameIReg32(gregOfRexRM(pfx,modrm)));
9302 delta += 3;
9303 goto decode_success;
9304 }
9305 /* else fall through */
9306 }
9307
9308 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9309 /* 0F E4 = PMULUH -- 16x4 hi-half of unsigned widening multiply */
9310 if (haveNo66noF2noF3(pfx) && sz == 4
9311 && insn[0] == 0x0F && insn[1] == 0xE4) {
9312 do_MMX_preamble();
9313 delta = dis_MMXop_regmem_to_reg (
9314 pfx, delta+2, insn[1], "pmuluh", False );
9315 goto decode_success;
9316 }
sewardja6b93d12005-02-17 09:28:28 +00009317
9318 /* 0F 18 /0 = PREFETCHNTA -- prefetch into caches, */
9319 /* 0F 18 /1 = PREFETCH0 -- with various different hints */
9320 /* 0F 18 /2 = PREFETCH1 */
9321 /* 0F 18 /3 = PREFETCH2 */
9322 if (insn[0] == 0x0F && insn[1] == 0x18
sewardjbcbb9de2005-03-27 02:22:32 +00009323 && haveNo66noF2noF3(pfx)
sewardja6b93d12005-02-17 09:28:28 +00009324 && !epartIsReg(insn[2])
sewardj901ed122005-02-27 13:25:31 +00009325 && gregLO3ofRM(insn[2]) >= 0 && gregLO3ofRM(insn[2]) <= 3) {
sewardja6b93d12005-02-17 09:28:28 +00009326 HChar* hintstr = "??";
9327
9328 modrm = getUChar(delta+2);
9329 vassert(!epartIsReg(modrm));
9330
9331 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9332 delta += 2+alen;
9333
sewardj901ed122005-02-27 13:25:31 +00009334 switch (gregLO3ofRM(modrm)) {
sewardja6b93d12005-02-17 09:28:28 +00009335 case 0: hintstr = "nta"; break;
9336 case 1: hintstr = "t0"; break;
9337 case 2: hintstr = "t1"; break;
9338 case 3: hintstr = "t2"; break;
9339 default: vassert(0);
9340 }
9341
9342 DIP("prefetch%s %s\n", hintstr, dis_buf);
9343 goto decode_success;
9344 }
9345
sewardja7ba8c42005-05-10 20:08:34 +00009346 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9347 /* 0F F6 = PSADBW -- sum of 8Ux8 absolute differences */
9348 if (haveNo66noF2noF3(pfx) && sz == 4
9349 && insn[0] == 0x0F && insn[1] == 0xF6) {
9350 do_MMX_preamble();
9351 delta = dis_MMXop_regmem_to_reg (
9352 pfx, delta+2, insn[1], "psadbw", False );
9353 goto decode_success;
9354 }
9355
9356 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9357 /* 0F 70 = PSHUFW -- rearrange 4x16 from E(mmx or mem) to G(mmx) */
9358 if (haveNo66noF2noF3(pfx) && sz == 4
9359 && insn[0] == 0x0F && insn[1] == 0x70) {
9360 Int order;
9361 IRTemp sV, dV, s3, s2, s1, s0;
9362 s3 = s2 = s1 = s0 = IRTemp_INVALID;
9363 sV = newTemp(Ity_I64);
9364 dV = newTemp(Ity_I64);
9365 do_MMX_preamble();
9366 modrm = insn[2];
9367 if (epartIsReg(modrm)) {
9368 assign( sV, getMMXReg(eregLO3ofRM(modrm)) );
9369 order = (Int)insn[3];
9370 delta += 2+2;
9371 DIP("pshufw $%d,%s,%s\n", order,
9372 nameMMXReg(eregLO3ofRM(modrm)),
9373 nameMMXReg(gregLO3ofRM(modrm)));
9374 } else {
9375 addr = disAMode ( &alen, pfx, delta+2, dis_buf,
9376 1/*extra byte after amode*/ );
9377 assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
9378 order = (Int)insn[2+alen];
9379 delta += 3+alen;
9380 DIP("pshufw $%d,%s,%s\n", order,
9381 dis_buf,
9382 nameMMXReg(gregLO3ofRM(modrm)));
9383 }
9384 breakup64to16s( sV, &s3, &s2, &s1, &s0 );
9385# define SEL(n) \
9386 ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
9387 assign(dV,
9388 mk64from16s( SEL((order>>6)&3), SEL((order>>4)&3),
9389 SEL((order>>2)&3), SEL((order>>0)&3) )
9390 );
9391 putMMXReg(gregLO3ofRM(modrm), mkexpr(dV));
9392# undef SEL
9393 goto decode_success;
9394 }
9395
9396 /* 0F 53 = RCPPS -- approx reciprocal 32Fx4 from R/M to R */
9397 if (haveNo66noF2noF3(pfx) && sz == 4
9398 && insn[0] == 0x0F && insn[1] == 0x53) {
9399 delta = dis_SSE_E_to_G_unary_all( pfx, delta+2,
9400 "rcpps", Iop_Recip32Fx4 );
9401 goto decode_success;
9402 }
9403
9404 /* F3 0F 53 = RCPSS -- approx reciprocal 32F0x4 from R/M to R */
9405 if (haveF3no66noF2(pfx) && sz == 4
9406 && insn[0] == 0x0F && insn[1] == 0x53) {
9407 delta = dis_SSE_E_to_G_unary_lo32( pfx, delta+2,
9408 "rcpss", Iop_Recip32F0x4 );
9409 goto decode_success;
9410 }
9411
9412 /* 0F 52 = RSQRTPS -- approx reciprocal sqrt 32Fx4 from R/M to R */
9413 if (haveNo66noF2noF3(pfx) && sz == 4
9414 && insn[0] == 0x0F && insn[1] == 0x52) {
9415 delta = dis_SSE_E_to_G_unary_all( pfx, delta+2,
9416 "rsqrtps", Iop_RSqrt32Fx4 );
9417 goto decode_success;
9418 }
9419
9420 /* F3 0F 52 = RSQRTSS -- approx reciprocal sqrt 32F0x4 from R/M to R */
9421 if (haveF3no66noF2(pfx) && sz == 4
9422 && insn[0] == 0x0F && insn[1] == 0x52) {
9423 delta = dis_SSE_E_to_G_unary_lo32( pfx, delta+2,
9424 "rsqrtss", Iop_RSqrt32F0x4 );
9425 goto decode_success;
9426 }
sewardjf53b7352005-04-06 20:01:56 +00009427
9428 /* 0F AE /7 = SFENCE -- flush pending operations to memory */
9429 if (haveNo66noF2noF3(pfx)
9430 && insn[0] == 0x0F && insn[1] == 0xAE
9431 && epartIsReg(insn[2]) && gregLO3ofRM(insn[2]) == 7
9432 && sz == 4) {
9433 delta += 3;
9434 /* Insert a memory fence. It's sometimes important that these
9435 are carried through to the generated code. */
9436 stmt( IRStmt_MFence() );
9437 DIP("sfence\n");
9438 goto decode_success;
9439 }
9440
sewardja7ba8c42005-05-10 20:08:34 +00009441 /* 0F C6 /r ib = SHUFPS -- shuffle packed F32s */
9442 if (haveNo66noF2noF3(pfx) && sz == 4
9443 && insn[0] == 0x0F && insn[1] == 0xC6) {
9444 Int select;
9445 IRTemp sV, dV;
9446 IRTemp s3, s2, s1, s0, d3, d2, d1, d0;
9447 sV = newTemp(Ity_V128);
9448 dV = newTemp(Ity_V128);
9449 s3 = s2 = s1 = s0 = d3 = d2 = d1 = d0 = IRTemp_INVALID;
9450 modrm = insn[2];
9451 assign( dV, getXMMReg(gregOfRexRM(pfx,modrm)) );
9452
9453 if (epartIsReg(modrm)) {
9454 assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
9455 select = (Int)insn[3];
9456 delta += 2+2;
9457 DIP("shufps $%d,%s,%s\n", select,
9458 nameXMMReg(eregOfRexRM(pfx,modrm)),
9459 nameXMMReg(gregOfRexRM(pfx,modrm)));
9460 } else {
9461 addr = disAMode ( &alen, pfx, delta+2, dis_buf,
9462 1/*byte at end of insn*/ );
9463 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
9464 select = (Int)insn[2+alen];
9465 delta += 3+alen;
9466 DIP("shufps $%d,%s,%s\n", select,
9467 dis_buf,
9468 nameXMMReg(gregOfRexRM(pfx,modrm)));
9469 }
9470
9471 breakup128to32s( dV, &d3, &d2, &d1, &d0 );
9472 breakup128to32s( sV, &s3, &s2, &s1, &s0 );
9473
9474# define SELD(n) ((n)==0 ? d0 : ((n)==1 ? d1 : ((n)==2 ? d2 : d3)))
9475# define SELS(n) ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
9476
9477 putXMMReg(
9478 gregOfRexRM(pfx,modrm),
9479 mk128from32s( SELS((select>>6)&3), SELS((select>>4)&3),
9480 SELD((select>>2)&3), SELD((select>>0)&3) )
9481 );
9482
9483# undef SELD
9484# undef SELS
9485
9486 goto decode_success;
9487 }
9488
9489 /* 0F 51 = SQRTPS -- approx sqrt 32Fx4 from R/M to R */
9490 if (haveNo66noF2noF3(pfx) && sz == 4
9491 && insn[0] == 0x0F && insn[1] == 0x51) {
9492 delta = dis_SSE_E_to_G_unary_all( pfx, delta+2,
9493 "sqrtps", Iop_Sqrt32Fx4 );
9494 goto decode_success;
9495 }
9496
9497 /* F3 0F 51 = SQRTSS -- approx sqrt 32F0x4 from R/M to R */
9498 if (haveF3no66noF2(pfx) && sz == 4
9499 && insn[0] == 0x0F && insn[1] == 0x51) {
9500 delta = dis_SSE_E_to_G_unary_lo32( pfx, delta+2,
9501 "sqrtss", Iop_Sqrt32F0x4 );
9502 goto decode_success;
9503 }
sewardjbcbb9de2005-03-27 02:22:32 +00009504
9505 /* 0F AE /3 = STMXCSR m32 -- store %mxcsr */
9506 if (insn[0] == 0x0F && insn[1] == 0xAE
9507 && haveNo66noF2noF3(pfx)
9508 && !epartIsReg(insn[2]) && gregLO3ofRM(insn[2]) == 3) {
9509
9510 vassert(sz == 4);
9511 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9512 delta += 2+alen;
9513
9514 /* Fake up a native SSE mxcsr word. The only thing it depends
9515 on is SSEROUND[1:0], so call a clean helper to cook it up.
9516 */
9517 /* ULong amd64h_create_mxcsr ( ULong sseround ) */
9518 DIP("stmxcsr %s\n", dis_buf);
9519 storeLE(
9520 mkexpr(addr),
9521 unop(Iop_64to32,
9522 mkIRExprCCall(
9523 Ity_I64, 0/*regp*/,
9524 "amd64g_create_mxcsr", &amd64g_create_mxcsr,
9525 mkIRExprVec_1( unop(Iop_32Uto64,get_sse_roundingmode()) )
9526 )
9527 )
9528 );
9529 goto decode_success;
9530 }
9531
sewardj432f8b62005-05-10 02:50:05 +00009532 /* 0F 5C = SUBPS -- sub 32Fx4 from R/M to R */
9533 if (haveNo66noF2noF3(pfx) && sz == 4
9534 && insn[0] == 0x0F && insn[1] == 0x5C) {
9535 delta = dis_SSE_E_to_G_all( pfx, delta+2, "subps", Iop_Sub32Fx4 );
9536 goto decode_success;
9537 }
sewardj8d965312005-02-25 02:48:47 +00009538
9539 /* F3 0F 5C = SUBSS -- sub 32F0x4 from R/M to R */
9540 if (haveF3no66noF2(pfx) && sz == 4
9541 && insn[0] == 0x0F && insn[1] == 0x5C) {
9542 delta = dis_SSE_E_to_G_lo32( pfx, delta+2, "subss", Iop_Sub32F0x4 );
9543 goto decode_success;
9544 }
9545
sewardja7ba8c42005-05-10 20:08:34 +00009546 /* 0F 15 = UNPCKHPS -- unpack and interleave high part F32s */
9547 /* 0F 14 = UNPCKLPS -- unpack and interleave low part F32s */
9548 /* These just appear to be special cases of SHUFPS */
9549 if (haveNo66noF2noF3(pfx) && sz == 4
9550 && insn[0] == 0x0F && (insn[1] == 0x15 || insn[1] == 0x14)) {
9551 IRTemp sV, dV;
9552 IRTemp s3, s2, s1, s0, d3, d2, d1, d0;
sewardjca673ab2005-05-11 10:03:08 +00009553 Bool hi = toBool(insn[1] == 0x15);
sewardja7ba8c42005-05-10 20:08:34 +00009554 sV = newTemp(Ity_V128);
9555 dV = newTemp(Ity_V128);
9556 s3 = s2 = s1 = s0 = d3 = d2 = d1 = d0 = IRTemp_INVALID;
9557 modrm = insn[2];
9558 assign( dV, getXMMReg(gregOfRexRM(pfx,modrm)) );
9559
9560 if (epartIsReg(modrm)) {
9561 assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
9562 delta += 2+1;
9563 DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
9564 nameXMMReg(eregOfRexRM(pfx,modrm)),
9565 nameXMMReg(gregOfRexRM(pfx,modrm)));
9566 } else {
9567 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9568 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
9569 delta += 2+alen;
9570 DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
9571 dis_buf,
9572 nameXMMReg(gregOfRexRM(pfx,modrm)));
9573 }
9574
9575 breakup128to32s( dV, &d3, &d2, &d1, &d0 );
9576 breakup128to32s( sV, &s3, &s2, &s1, &s0 );
9577
9578 if (hi) {
9579 putXMMReg( gregOfRexRM(pfx,modrm), mk128from32s( s3, d3, s2, d2 ) );
9580 } else {
9581 putXMMReg( gregOfRexRM(pfx,modrm), mk128from32s( s1, d1, s0, d0 ) );
9582 }
9583
9584 goto decode_success;
9585 }
sewardj8d965312005-02-25 02:48:47 +00009586
9587 /* 0F 57 = XORPS -- G = G and E */
9588 if (haveNo66noF2noF3(pfx) && sz == 4
9589 && insn[0] == 0x0F && insn[1] == 0x57) {
9590 delta = dis_SSE_E_to_G_all( pfx, delta+2, "xorps", Iop_XorV128 );
9591 goto decode_success;
9592 }
9593
sewardj5992bd02005-05-11 02:13:42 +00009594 /* ---------------------------------------------------- */
9595 /* --- end of the SSE decoder. --- */
9596 /* ---------------------------------------------------- */
9597
9598 /* ---------------------------------------------------- */
9599 /* --- start of the SSE2 decoder. --- */
9600 /* ---------------------------------------------------- */
sewardj4c328cf2005-05-05 12:05:54 +00009601
9602 /* 66 0F 58 = ADDPD -- add 32Fx4 from R/M to R */
9603 if (have66noF2noF3(pfx) && sz == 2
9604 && insn[0] == 0x0F && insn[1] == 0x58) {
9605 delta = dis_SSE_E_to_G_all( pfx, delta+2, "addpd", Iop_Add64Fx2 );
9606 goto decode_success;
9607 }
sewardj1001dc42005-02-21 08:25:55 +00009608
9609 /* F2 0F 58 = ADDSD -- add 64F0x2 from R/M to R */
9610 if (haveF2no66noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x58) {
9611 vassert(sz == 4);
9612 delta = dis_SSE_E_to_G_lo64( pfx, delta+2, "addsd", Iop_Add64F0x2 );
9613 goto decode_success;
9614 }
9615
sewardj8d965312005-02-25 02:48:47 +00009616 /* 66 0F 55 = ANDNPD -- G = (not G) and E */
9617 if (have66noF2noF3(pfx) && sz == 2
9618 && insn[0] == 0x0F && insn[1] == 0x55) {
9619 delta = dis_SSE_E_to_G_all_invG( pfx, delta+2, "andnpd", Iop_AndV128 );
9620 goto decode_success;
9621 }
sewardj1a01e652005-02-23 11:39:21 +00009622
9623 /* 66 0F 54 = ANDPD -- G = G and E */
9624 if (have66noF2noF3(pfx) && sz == 2
9625 && insn[0] == 0x0F && insn[1] == 0x54) {
9626 delta = dis_SSE_E_to_G_all( pfx, delta+2, "andpd", Iop_AndV128 );
9627 goto decode_success;
9628 }
9629
sewardj97628592005-05-10 22:42:54 +00009630 /* 66 0F C2 = CMPPD -- 64Fx2 comparison from R/M to R */
9631 if (have66noF2noF3(pfx) && sz == 2
9632 && insn[0] == 0x0F && insn[1] == 0xC2) {
9633 delta = dis_SSEcmp_E_to_G( pfx, delta+2, "cmppd", True, 8 );
9634 goto decode_success;
9635 }
sewardj8d965312005-02-25 02:48:47 +00009636
9637 /* F2 0F C2 = CMPSD -- 64F0x2 comparison from R/M to R */
9638 if (haveF2no66noF3(pfx) && sz == 4
9639 && insn[0] == 0x0F && insn[1] == 0xC2) {
9640 delta = dis_SSEcmp_E_to_G( pfx, delta+2, "cmpsd", False, 8 );
9641 goto decode_success;
9642 }
sewardj18303862005-02-21 12:36:54 +00009643
9644 /* 66 0F 2F = COMISD -- 64F0x2 comparison G,E, and set ZCP */
9645 /* 66 0F 2E = UCOMISD -- 64F0x2 comparison G,E, and set ZCP */
sewardjc49ce232005-02-25 13:03:03 +00009646 if (have66noF2noF3(pfx) && sz == 2
sewardj18303862005-02-21 12:36:54 +00009647 && insn[0] == 0x0F && (insn[1] == 0x2F || insn[1] == 0x2E)) {
9648 IRTemp argL = newTemp(Ity_F64);
9649 IRTemp argR = newTemp(Ity_F64);
9650 modrm = getUChar(delta+2);
9651 if (epartIsReg(modrm)) {
9652 assign( argR, getXMMRegLane64F( eregOfRexRM(pfx,modrm),
9653 0/*lowest lane*/ ) );
9654 delta += 2+1;
9655 DIP("%scomisd %s,%s\n", insn[1]==0x2E ? "u" : "",
9656 nameXMMReg(eregOfRexRM(pfx,modrm)),
9657 nameXMMReg(gregOfRexRM(pfx,modrm)) );
9658 } else {
9659 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9660 assign( argR, loadLE(Ity_F64, mkexpr(addr)) );
9661 delta += 2+alen;
9662 DIP("%scomisd %s,%s\n", insn[1]==0x2E ? "u" : "",
9663 dis_buf,
9664 nameXMMReg(gregOfRexRM(pfx,modrm)) );
9665 }
9666 assign( argL, getXMMRegLane64F( gregOfRexRM(pfx,modrm),
9667 0/*lowest lane*/ ) );
9668
9669 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(AMD64G_CC_OP_COPY) ));
9670 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
9671 stmt( IRStmt_Put(
9672 OFFB_CC_DEP1,
9673 binop( Iop_And64,
9674 unop( Iop_32Uto64,
9675 binop(Iop_CmpF64, mkexpr(argL), mkexpr(argR)) ),
9676 mkU64(0x45)
9677 )));
9678
9679 goto decode_success;
9680 }
9681
sewardj09717342005-05-05 21:34:02 +00009682 /* F3 0F E6 = CVTDQ2PD -- convert 2 x I32 in mem/lo half xmm to 2 x
9683 F64 in xmm(G) */
9684 if (haveF3no66noF2(pfx) && insn[0] == 0x0F && insn[1] == 0xE6) {
9685 IRTemp arg64 = newTemp(Ity_I64);
9686 if (sz != 4) goto decode_failure;
9687
9688 modrm = getUChar(delta+2);
9689 if (epartIsReg(modrm)) {
9690 assign( arg64, getXMMRegLane64(eregOfRexRM(pfx,modrm), 0) );
9691 delta += 2+1;
9692 DIP("cvtdq2pd %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
9693 nameXMMReg(gregOfRexRM(pfx,modrm)));
9694 } else {
9695 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9696 assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
9697 delta += 2+alen;
9698 DIP("cvtdq2pd %s,%s\n", dis_buf,
9699 nameXMMReg(gregOfRexRM(pfx,modrm)) );
9700 }
9701
9702 putXMMRegLane64F(
9703 gregOfRexRM(pfx,modrm), 0,
9704 unop(Iop_I32toF64, unop(Iop_64to32, mkexpr(arg64)))
9705 );
9706
9707 putXMMRegLane64F(
9708 gregOfRexRM(pfx,modrm), 1,
9709 unop(Iop_I32toF64, unop(Iop_64HIto32, mkexpr(arg64)))
9710 );
9711
9712 goto decode_success;
9713 }
9714
sewardj5992bd02005-05-11 02:13:42 +00009715 /* 0F 5B = CVTDQ2PS -- convert 4 x I32 in mem/xmm to 4 x F32 in
9716 xmm(G) */
9717 if (haveNo66noF2noF3(pfx) && sz == 4
9718 && insn[0] == 0x0F && insn[1] == 0x5B) {
sewardj09717342005-05-05 21:34:02 +00009719 IRTemp argV = newTemp(Ity_V128);
9720 IRTemp rmode = newTemp(Ity_I32);
sewardj09717342005-05-05 21:34:02 +00009721
9722 modrm = getUChar(delta+2);
9723 if (epartIsReg(modrm)) {
9724 assign( argV, getXMMReg(eregOfRexRM(pfx,modrm)) );
9725 delta += 2+1;
sewardj5992bd02005-05-11 02:13:42 +00009726 DIP("cvtdq2ps %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
sewardj09717342005-05-05 21:34:02 +00009727 nameXMMReg(gregOfRexRM(pfx,modrm)));
9728 } else {
9729 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
sewardj5992bd02005-05-11 02:13:42 +00009730 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
sewardj09717342005-05-05 21:34:02 +00009731 delta += 2+alen;
sewardj5992bd02005-05-11 02:13:42 +00009732 DIP("cvtdq2ps %s,%s\n", dis_buf,
sewardj09717342005-05-05 21:34:02 +00009733 nameXMMReg(gregOfRexRM(pfx,modrm)) );
9734 }
9735
9736 assign( rmode, get_sse_roundingmode() );
sewardj5992bd02005-05-11 02:13:42 +00009737 breakup128to32s( argV, &t3, &t2, &t1, &t0 );
9738
9739# define CVT(_t) binop( Iop_F64toF32, \
9740 mkexpr(rmode), \
9741 unop(Iop_I32toF64,mkexpr(_t)))
9742
9743 putXMMRegLane32F( gregOfRexRM(pfx,modrm), 3, CVT(t3) );
9744 putXMMRegLane32F( gregOfRexRM(pfx,modrm), 2, CVT(t2) );
9745 putXMMRegLane32F( gregOfRexRM(pfx,modrm), 1, CVT(t1) );
9746 putXMMRegLane32F( gregOfRexRM(pfx,modrm), 0, CVT(t0) );
9747
9748# undef CVT
9749
9750 goto decode_success;
9751 }
9752
9753 /* 66 0F E6 = CVTTPD2DQ -- convert 2 x F64 in mem/xmm to 2 x I32 in
9754 lo half xmm(G), and zero upper half, rounding towards zero */
9755 /* F2 0F E6 = CVTPD2DQ -- convert 2 x F64 in mem/xmm to 2 x I32 in
9756 lo half xmm(G), according to prevailing rounding mode, and zero
9757 upper half */
9758 if ( ( (haveF2no66noF3(pfx) && sz == 4)
9759 || (have66noF2noF3(pfx) && sz == 2)
9760 )
9761 && insn[0] == 0x0F && insn[1] == 0xE6) {
9762 IRTemp argV = newTemp(Ity_V128);
9763 IRTemp rmode = newTemp(Ity_I32);
9764 Bool r2zero = toBool(sz == 2);
9765
9766 modrm = getUChar(delta+2);
9767 if (epartIsReg(modrm)) {
9768 assign( argV, getXMMReg(eregOfRexRM(pfx,modrm)) );
9769 delta += 2+1;
9770 DIP("cvt%spd2dq %s,%s\n", r2zero ? "t" : "",
9771 nameXMMReg(eregOfRexRM(pfx,modrm)),
9772 nameXMMReg(gregOfRexRM(pfx,modrm)));
9773 } else {
9774 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9775 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
9776 delta += 2+alen;
9777 DIP("cvt%spd2dq %s,%s\n", r2zero ? "t" : "",
9778 dis_buf,
9779 nameXMMReg(gregOfRexRM(pfx,modrm)) );
9780 }
9781
9782 if (r2zero) {
9783 assign(rmode, mkU32((UInt)Irrm_ZERO) );
9784 } else {
9785 assign( rmode, get_sse_roundingmode() );
9786 }
9787
sewardj09717342005-05-05 21:34:02 +00009788 t0 = newTemp(Ity_F64);
9789 t1 = newTemp(Ity_F64);
9790 assign( t0, unop(Iop_ReinterpI64asF64,
9791 unop(Iop_V128to64, mkexpr(argV))) );
9792 assign( t1, unop(Iop_ReinterpI64asF64,
9793 unop(Iop_V128HIto64, mkexpr(argV))) );
9794
9795# define CVT(_t) binop( Iop_F64toI32, \
9796 mkexpr(rmode), \
9797 mkexpr(_t) )
9798
9799 putXMMRegLane32( gregOfRexRM(pfx,modrm), 3, mkU32(0) );
9800 putXMMRegLane32( gregOfRexRM(pfx,modrm), 2, mkU32(0) );
9801 putXMMRegLane32( gregOfRexRM(pfx,modrm), 1, CVT(t1) );
9802 putXMMRegLane32( gregOfRexRM(pfx,modrm), 0, CVT(t0) );
9803
9804# undef CVT
9805
9806 goto decode_success;
9807 }
9808
sewardj5992bd02005-05-11 02:13:42 +00009809 /* 66 0F 2D = CVTPD2PI -- convert 2 x F64 in mem/xmm to 2 x
9810 I32 in mmx, according to prevailing SSE rounding mode */
9811 /* 66 0F 2C = CVTTPD2PI -- convert 2 x F64 in mem/xmm to 2 x
9812 I32 in mmx, rounding towards zero */
9813 if (have66noF2noF3(pfx) && sz == 2
9814 && insn[0] == 0x0F && (insn[1] == 0x2D || insn[1] == 0x2C)) {
9815 IRTemp dst64 = newTemp(Ity_I64);
9816 IRTemp rmode = newTemp(Ity_I32);
9817 IRTemp f64lo = newTemp(Ity_F64);
9818 IRTemp f64hi = newTemp(Ity_F64);
sewardjca673ab2005-05-11 10:03:08 +00009819 Bool r2zero = toBool(insn[1] == 0x2C);
sewardj5992bd02005-05-11 02:13:42 +00009820
9821 do_MMX_preamble();
9822 modrm = getUChar(delta+2);
9823
9824 if (epartIsReg(modrm)) {
9825 delta += 2+1;
9826 assign(f64lo, getXMMRegLane64F(eregOfRexRM(pfx,modrm), 0));
9827 assign(f64hi, getXMMRegLane64F(eregOfRexRM(pfx,modrm), 1));
9828 DIP("cvt%spd2pi %s,%s\n", r2zero ? "t" : "",
9829 nameXMMReg(eregOfRexRM(pfx,modrm)),
9830 nameMMXReg(gregLO3ofRM(modrm)));
9831 } else {
9832 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9833 assign(f64lo, loadLE(Ity_F64, mkexpr(addr)));
9834 assign(f64hi, loadLE(Ity_F64, binop( Iop_Add64,
9835 mkexpr(addr),
9836 mkU64(8) )));
9837 delta += 2+alen;
9838 DIP("cvt%spf2pi %s,%s\n", r2zero ? "t" : "",
9839 dis_buf,
9840 nameMMXReg(gregLO3ofRM(modrm)));
9841 }
9842
9843 if (r2zero) {
9844 assign(rmode, mkU32((UInt)Irrm_ZERO) );
9845 } else {
9846 assign( rmode, get_sse_roundingmode() );
9847 }
9848
9849 assign(
9850 dst64,
9851 binop( Iop_32HLto64,
9852 binop( Iop_F64toI32, mkexpr(rmode), mkexpr(f64hi) ),
9853 binop( Iop_F64toI32, mkexpr(rmode), mkexpr(f64lo) )
9854 )
9855 );
9856
9857 putMMXReg(gregLO3ofRM(modrm), mkexpr(dst64));
9858 goto decode_success;
9859 }
9860
9861 /* 66 0F 5A = CVTPD2PS -- convert 2 x F64 in mem/xmm to 2 x F32 in
9862 lo half xmm(G), rounding according to prevailing SSE rounding
9863 mode, and zero upper half */
9864 /* Note, this is practically identical to CVTPD2DQ. It would have
9865 been nicer to merge them together, but the insn[] offsets differ
9866 by one. */
9867 if (have66noF2noF3(pfx) && sz == 2
9868 && insn[0] == 0x0F && insn[1] == 0x5A) {
9869 IRTemp argV = newTemp(Ity_V128);
9870 IRTemp rmode = newTemp(Ity_I32);
9871
9872 modrm = getUChar(delta+2);
9873 if (epartIsReg(modrm)) {
9874 assign( argV, getXMMReg(eregOfRexRM(pfx,modrm)) );
9875 delta += 2+1;
9876 DIP("cvtpd2ps %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
9877 nameXMMReg(gregOfRexRM(pfx,modrm)));
9878 } else {
9879 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9880 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
9881 delta += 2+alen;
9882 DIP("cvtpd2ps %s,%s\n", dis_buf,
9883 nameXMMReg(gregOfRexRM(pfx,modrm)) );
9884 }
9885
9886 assign( rmode, get_sse_roundingmode() );
9887 t0 = newTemp(Ity_F64);
9888 t1 = newTemp(Ity_F64);
9889 assign( t0, unop(Iop_ReinterpI64asF64,
9890 unop(Iop_V128to64, mkexpr(argV))) );
9891 assign( t1, unop(Iop_ReinterpI64asF64,
9892 unop(Iop_V128HIto64, mkexpr(argV))) );
9893
9894# define CVT(_t) binop( Iop_F64toF32, \
9895 mkexpr(rmode), \
9896 mkexpr(_t) )
9897
9898 putXMMRegLane32( gregOfRexRM(pfx,modrm), 3, mkU32(0) );
9899 putXMMRegLane32( gregOfRexRM(pfx,modrm), 2, mkU32(0) );
9900 putXMMRegLane32F( gregOfRexRM(pfx,modrm), 1, CVT(t1) );
9901 putXMMRegLane32F( gregOfRexRM(pfx,modrm), 0, CVT(t0) );
9902
9903# undef CVT
9904
9905 goto decode_success;
9906 }
9907
9908 /* 66 0F 2A = CVTPI2PD -- convert 2 x I32 in mem/mmx to 2 x F64 in
9909 xmm(G) */
9910 if (have66noF2noF3(pfx) && sz == 2
9911 && insn[0] == 0x0F && insn[1] == 0x2A) {
9912 IRTemp arg64 = newTemp(Ity_I64);
9913
9914 modrm = getUChar(delta+2);
9915 do_MMX_preamble();
9916 if (epartIsReg(modrm)) {
9917 assign( arg64, getMMXReg(eregLO3ofRM(modrm)) );
9918 delta += 2+1;
9919 DIP("cvtpi2pd %s,%s\n", nameMMXReg(eregLO3ofRM(modrm)),
9920 nameXMMReg(gregOfRexRM(pfx,modrm)));
9921 } else {
9922 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9923 assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
9924 delta += 2+alen;
9925 DIP("cvtpi2pd %s,%s\n", dis_buf,
9926 nameXMMReg(gregOfRexRM(pfx,modrm)) );
9927 }
9928
9929 putXMMRegLane64F(
9930 gregOfRexRM(pfx,modrm), 0,
9931 unop(Iop_I32toF64, unop(Iop_64to32, mkexpr(arg64)) )
9932 );
9933
9934 putXMMRegLane64F(
9935 gregOfRexRM(pfx,modrm), 1,
9936 unop(Iop_I32toF64, unop(Iop_64HIto32, mkexpr(arg64)) )
9937 );
9938
9939 goto decode_success;
9940 }
9941
9942 /* F3 0F 5B = CVTTPS2DQ -- convert 4 x F32 in mem/xmm to 4 x I32 in
9943 xmm(G), rounding towards zero */
9944 /* 66 0F 5B = CVTPS2DQ -- convert 4 x F32 in mem/xmm to 4 x I32 in
9945 xmm(G), as per the prevailing rounding mode */
9946 if ( ( (have66noF2noF3(pfx) && sz == 2)
9947 || (haveF3no66noF2(pfx) && sz == 4)
9948 )
9949 && insn[0] == 0x0F && insn[1] == 0x5B) {
9950 IRTemp argV = newTemp(Ity_V128);
9951 IRTemp rmode = newTemp(Ity_I32);
9952 Bool r2zero = toBool(sz == 4);
9953
9954 modrm = getUChar(delta+2);
9955 if (epartIsReg(modrm)) {
9956 assign( argV, getXMMReg(eregOfRexRM(pfx,modrm)) );
9957 delta += 2+1;
9958 DIP("cvtps2dq %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
9959 nameXMMReg(gregOfRexRM(pfx,modrm)));
9960 } else {
9961 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9962 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
9963 delta += 2+alen;
9964 DIP("cvtps2dq %s,%s\n", dis_buf,
9965 nameXMMReg(gregOfRexRM(pfx,modrm)) );
9966 }
9967
9968 if (r2zero) {
9969 assign( rmode, mkU32((UInt)Irrm_ZERO) );
9970 } else {
9971 assign( rmode, get_sse_roundingmode() );
9972 }
9973
9974 breakup128to32s( argV, &t3, &t2, &t1, &t0 );
9975
9976 /* This is less than ideal. If it turns out to be a performance
9977 bottleneck it can be improved. */
9978# define CVT(_t) \
9979 binop( Iop_F64toI32, \
9980 mkexpr(rmode), \
9981 unop( Iop_F32toF64, \
9982 unop( Iop_ReinterpI32asF32, mkexpr(_t))) )
9983
9984 putXMMRegLane32( gregOfRexRM(pfx,modrm), 3, CVT(t3) );
9985 putXMMRegLane32( gregOfRexRM(pfx,modrm), 2, CVT(t2) );
9986 putXMMRegLane32( gregOfRexRM(pfx,modrm), 1, CVT(t1) );
9987 putXMMRegLane32( gregOfRexRM(pfx,modrm), 0, CVT(t0) );
9988
9989# undef CVT
9990
9991 goto decode_success;
9992 }
9993
9994 /* 0F 5A = CVTPS2PD -- convert 2 x F32 in low half mem/xmm to 2 x
9995 F64 in xmm(G). */
9996 if (haveNo66noF2noF3(pfx) && sz == 4
9997 && insn[0] == 0x0F && insn[1] == 0x5A) {
9998 IRTemp f32lo = newTemp(Ity_F32);
9999 IRTemp f32hi = newTemp(Ity_F32);
10000
10001 modrm = getUChar(delta+2);
10002 if (epartIsReg(modrm)) {
10003 assign( f32lo, getXMMRegLane32F(eregOfRexRM(pfx,modrm), 0) );
10004 assign( f32hi, getXMMRegLane32F(eregOfRexRM(pfx,modrm), 1) );
10005 delta += 2+1;
10006 DIP("cvtps2pd %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
10007 nameXMMReg(gregOfRexRM(pfx,modrm)));
10008 } else {
10009 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10010 assign( f32lo, loadLE(Ity_F32, mkexpr(addr)) );
10011 assign( f32hi, loadLE(Ity_F32,
10012 binop(Iop_Add64,mkexpr(addr),mkU64(4))) );
10013 delta += 2+alen;
10014 DIP("cvtps2pd %s,%s\n", dis_buf,
10015 nameXMMReg(gregOfRexRM(pfx,modrm)) );
10016 }
10017
10018 putXMMRegLane64F( gregOfRexRM(pfx,modrm), 1,
10019 unop(Iop_F32toF64, mkexpr(f32hi)) );
10020 putXMMRegLane64F( gregOfRexRM(pfx,modrm), 0,
10021 unop(Iop_F32toF64, mkexpr(f32lo)) );
10022
10023 goto decode_success;
10024 }
10025
10026 /* F2 0F 2D = CVTSD2SI
10027 when sz==4 -- convert F64 in mem/low half xmm to I32 in ireg,
10028 according to prevailing SSE rounding mode
10029 when sz==8 -- convert F64 in mem/low half xmm to I64 in ireg,
10030 according to prevailing SSE rounding mode
10031 */
sewardj1a01e652005-02-23 11:39:21 +000010032 /* F2 0F 2C = CVTTSD2SI
10033 when sz==4 -- convert F64 in mem/low half xmm to I32 in ireg,
10034 truncating towards zero
10035 when sz==8 -- convert F64 in mem/low half xmm to I64 in ireg,
10036 truncating towards zero
10037 */
10038 if (haveF2no66noF3(pfx)
10039 && insn[0] == 0x0F
sewardj5992bd02005-05-11 02:13:42 +000010040 && (insn[1] == 0x2D || insn[1] == 0x2C)) {
sewardj1a01e652005-02-23 11:39:21 +000010041 IRTemp rmode = newTemp(Ity_I32);
10042 IRTemp f64lo = newTemp(Ity_F64);
sewardj1027dc22005-02-26 01:55:02 +000010043 Bool r2zero = toBool(insn[1] == 0x2C);
sewardj1a01e652005-02-23 11:39:21 +000010044 vassert(sz == 4 || sz == 8);
10045
10046 modrm = getUChar(delta+2);
10047 if (epartIsReg(modrm)) {
10048 delta += 2+1;
10049 assign(f64lo, getXMMRegLane64F(eregOfRexRM(pfx,modrm), 0));
10050 DIP("cvt%ssd2si %s,%s\n", r2zero ? "t" : "",
10051 nameXMMReg(eregOfRexRM(pfx,modrm)),
sewardj5b470602005-02-27 13:10:48 +000010052 nameIReg(sz, gregOfRexRM(pfx,modrm), False));
sewardj1a01e652005-02-23 11:39:21 +000010053 } else {
10054 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10055 assign(f64lo, loadLE(Ity_F64, mkexpr(addr)));
10056 delta += 2+alen;
10057 DIP("cvt%ssd2si %s,%s\n", r2zero ? "t" : "",
10058 dis_buf,
sewardj5b470602005-02-27 13:10:48 +000010059 nameIReg(sz, gregOfRexRM(pfx,modrm), False));
sewardj1a01e652005-02-23 11:39:21 +000010060 }
10061
10062 if (r2zero) {
10063 assign( rmode, mkU32((UInt)Irrm_ZERO) );
10064 } else {
10065 assign( rmode, get_sse_roundingmode() );
10066 }
10067
10068 if (sz == 4) {
sewardj5b470602005-02-27 13:10:48 +000010069 putIReg32( gregOfRexRM(pfx,modrm),
10070 binop( Iop_F64toI32, mkexpr(rmode), mkexpr(f64lo)) );
sewardj1a01e652005-02-23 11:39:21 +000010071 } else {
sewardj5b470602005-02-27 13:10:48 +000010072 putIReg64( gregOfRexRM(pfx,modrm),
10073 binop( Iop_F64toI64, mkexpr(rmode), mkexpr(f64lo)) );
sewardj1a01e652005-02-23 11:39:21 +000010074 }
10075
10076 goto decode_success;
10077 }
10078
sewardj8d965312005-02-25 02:48:47 +000010079 /* F2 0F 5A = CVTSD2SS -- convert F64 in mem/low half xmm to F32 in
10080 low 1/4 xmm(G), according to prevailing SSE rounding mode */
10081 if (haveF2no66noF3(pfx) && sz == 4
10082 && insn[0] == 0x0F && insn[1] == 0x5A) {
10083 IRTemp rmode = newTemp(Ity_I32);
10084 IRTemp f64lo = newTemp(Ity_F64);
10085 vassert(sz == 4);
10086
10087 modrm = getUChar(delta+2);
10088 if (epartIsReg(modrm)) {
10089 delta += 2+1;
10090 assign(f64lo, getXMMRegLane64F(eregOfRexRM(pfx,modrm), 0));
10091 DIP("cvtsd2ss %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
10092 nameXMMReg(gregOfRexRM(pfx,modrm)));
10093 } else {
10094 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10095 assign(f64lo, loadLE(Ity_F64, mkexpr(addr)));
10096 delta += 2+alen;
10097 DIP("cvtsd2ss %s,%s\n", dis_buf,
10098 nameXMMReg(gregOfRexRM(pfx,modrm)));
10099 }
10100
10101 assign( rmode, get_sse_roundingmode() );
10102 putXMMRegLane32F(
10103 gregOfRexRM(pfx,modrm), 0,
10104 binop( Iop_F64toF32, mkexpr(rmode), mkexpr(f64lo) )
10105 );
10106
10107 goto decode_success;
10108 }
sewardj1a01e652005-02-23 11:39:21 +000010109
10110 /* F2 0F 2A = CVTSI2SD
10111 when sz==4 -- convert I32 in mem/ireg to F64 in low half xmm
10112 when sz==8 -- convert I64 in mem/ireg to F64 in low half xmm
10113 */
sewardj8d965312005-02-25 02:48:47 +000010114 if (haveF2no66noF3(pfx) && (sz == 4 || sz == 8)
10115 && insn[0] == 0x0F && insn[1] == 0x2A) {
sewardj1a01e652005-02-23 11:39:21 +000010116 modrm = getUChar(delta+2);
10117
10118 if (sz == 4) {
10119 IRTemp arg32 = newTemp(Ity_I32);
10120 if (epartIsReg(modrm)) {
sewardj5b470602005-02-27 13:10:48 +000010121 assign( arg32, getIReg32(eregOfRexRM(pfx,modrm)) );
sewardj1a01e652005-02-23 11:39:21 +000010122 delta += 2+1;
sewardj5b470602005-02-27 13:10:48 +000010123 DIP("cvtsi2sd %s,%s\n", nameIReg32(eregOfRexRM(pfx,modrm)),
sewardj1a01e652005-02-23 11:39:21 +000010124 nameXMMReg(gregOfRexRM(pfx,modrm)));
10125 } else {
10126 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10127 assign( arg32, loadLE(Ity_I32, mkexpr(addr)) );
10128 delta += 2+alen;
10129 DIP("cvtsi2sd %s,%s\n", dis_buf,
10130 nameXMMReg(gregOfRexRM(pfx,modrm)) );
10131 }
10132 putXMMRegLane64F( gregOfRexRM(pfx,modrm), 0,
10133 unop(Iop_I32toF64, mkexpr(arg32))
10134 );
10135 } else {
10136 /* sz == 8 */
10137 IRTemp arg64 = newTemp(Ity_I64);
10138 if (epartIsReg(modrm)) {
sewardj5b470602005-02-27 13:10:48 +000010139 assign( arg64, getIReg64(eregOfRexRM(pfx,modrm)) );
sewardj1a01e652005-02-23 11:39:21 +000010140 delta += 2+1;
sewardj5b470602005-02-27 13:10:48 +000010141 DIP("cvtsi2sdq %s,%s\n", nameIReg64(eregOfRexRM(pfx,modrm)),
sewardj8d965312005-02-25 02:48:47 +000010142 nameXMMReg(gregOfRexRM(pfx,modrm)));
sewardj1a01e652005-02-23 11:39:21 +000010143 } else {
10144 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10145 assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
10146 delta += 2+alen;
sewardj8d965312005-02-25 02:48:47 +000010147 DIP("cvtsi2sdq %s,%s\n", dis_buf,
10148 nameXMMReg(gregOfRexRM(pfx,modrm)) );
sewardj1a01e652005-02-23 11:39:21 +000010149 }
10150 putXMMRegLane64F(
10151 gregOfRexRM(pfx,modrm),
10152 0,
10153 binop( Iop_I64toF64,
10154 get_sse_roundingmode(),
10155 mkexpr(arg64)
10156 )
10157 );
10158
10159 }
10160
10161 goto decode_success;
10162 }
10163
sewardjc49ce232005-02-25 13:03:03 +000010164 /* F3 0F 5A = CVTSS2SD -- convert F32 in mem/low 1/4 xmm to F64 in
10165 low half xmm(G) */
10166 if (haveF3no66noF2(pfx) && sz == 4
10167 && insn[0] == 0x0F && insn[1] == 0x5A) {
10168 IRTemp f32lo = newTemp(Ity_F32);
10169
10170 modrm = getUChar(delta+2);
10171 if (epartIsReg(modrm)) {
10172 delta += 2+1;
10173 assign(f32lo, getXMMRegLane32F(eregOfRexRM(pfx,modrm), 0));
10174 DIP("cvtss2sd %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
10175 nameXMMReg(gregOfRexRM(pfx,modrm)));
10176 } else {
10177 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10178 assign(f32lo, loadLE(Ity_F32, mkexpr(addr)));
10179 delta += 2+alen;
10180 DIP("cvtss2sd %s,%s\n", dis_buf,
10181 nameXMMReg(gregOfRexRM(pfx,modrm)));
10182 }
10183
10184 putXMMRegLane64F( gregOfRexRM(pfx,modrm), 0,
10185 unop( Iop_F32toF64, mkexpr(f32lo) ) );
10186
10187 goto decode_success;
10188 }
10189
sewardj5992bd02005-05-11 02:13:42 +000010190 /* 66 0F 5E = DIVPD -- div 64Fx2 from R/M to R */
10191 if (have66noF2noF3(pfx) && sz == 2
10192 && insn[0] == 0x0F && insn[1] == 0x5E) {
10193 delta = dis_SSE_E_to_G_all( pfx, delta+2, "divpd", Iop_Div64Fx2 );
10194 goto decode_success;
10195 }
sewardj1001dc42005-02-21 08:25:55 +000010196
10197 /* F2 0F 5E = DIVSD -- div 64F0x2 from R/M to R */
10198 if (haveF2no66noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x5E) {
10199 vassert(sz == 4);
10200 delta = dis_SSE_E_to_G_lo64( pfx, delta+2, "divsd", Iop_Div64F0x2 );
10201 goto decode_success;
10202 }
10203
sewardj5992bd02005-05-11 02:13:42 +000010204 /* 0F AE /5 = LFENCE -- flush pending operations to memory */
10205 /* 0F AE /6 = MFENCE -- flush pending operations to memory */
10206 if (haveNo66noF2noF3(pfx) && sz == 4
10207 && insn[0] == 0x0F && insn[1] == 0xAE
10208 && epartIsReg(insn[2])
10209 && (gregLO3ofRM(insn[2]) == 5 || gregLO3ofRM(insn[2]) == 6)) {
10210 delta += 3;
10211 /* Insert a memory fence. It's sometimes important that these
10212 are carried through to the generated code. */
10213 stmt( IRStmt_MFence() );
10214 DIP("%sfence\n", gregLO3ofRM(insn[2])==5 ? "l" : "m");
10215 goto decode_success;
10216 }
10217
10218 /* 66 0F 5F = MAXPD -- max 64Fx2 from R/M to R */
10219 if (have66noF2noF3(pfx) && sz == 2
10220 && insn[0] == 0x0F && insn[1] == 0x5F) {
10221 delta = dis_SSE_E_to_G_all( pfx, delta+2, "maxpd", Iop_Max64Fx2 );
10222 goto decode_success;
10223 }
sewardj1a01e652005-02-23 11:39:21 +000010224
10225 /* F2 0F 5F = MAXSD -- max 64F0x2 from R/M to R */
10226 if (haveF2no66noF3(pfx) && sz == 4
10227 && insn[0] == 0x0F && insn[1] == 0x5F) {
10228 delta = dis_SSE_E_to_G_lo64( pfx, delta+2, "maxsd", Iop_Max64F0x2 );
10229 goto decode_success;
10230 }
10231
sewardj5992bd02005-05-11 02:13:42 +000010232 /* 66 0F 5D = MINPD -- min 64Fx2 from R/M to R */
10233 if (have66noF2noF3(pfx) && sz == 2
10234 && insn[0] == 0x0F && insn[1] == 0x5D) {
10235 delta = dis_SSE_E_to_G_all( pfx, delta+2, "minpd", Iop_Min64Fx2 );
10236 goto decode_success;
10237 }
sewardjc49ce232005-02-25 13:03:03 +000010238
10239 /* F2 0F 5D = MINSD -- min 64F0x2 from R/M to R */
10240 if (haveF2no66noF3(pfx) && sz == 4
10241 && insn[0] == 0x0F && insn[1] == 0x5D) {
10242 delta = dis_SSE_E_to_G_lo64( pfx, delta+2, "minsd", Iop_Min64F0x2 );
10243 goto decode_success;
10244 }
sewardj8d965312005-02-25 02:48:47 +000010245
10246 /* 66 0F 28 = MOVAPD -- move from E (mem or xmm) to G (xmm). */
10247 /* 66 0F 10 = MOVUPD -- move from E (mem or xmm) to G (xmm). */
10248 /* 66 0F 6F = MOVDQA -- move from E (mem or xmm) to G (xmm). */
10249 if (have66noF2noF3(pfx) && sz == 2
10250 && insn[0] == 0x0F
10251 && (insn[1] == 0x28 || insn[1] == 0x10 || insn[1] == 0x6F)) {
10252 HChar* wot = insn[1]==0x28 ? "apd" :
10253 insn[1]==0x10 ? "upd" : "dqa";
10254 modrm = getUChar(delta+2);
10255 if (epartIsReg(modrm)) {
10256 putXMMReg( gregOfRexRM(pfx,modrm),
10257 getXMMReg( eregOfRexRM(pfx,modrm) ));
10258 DIP("mov%s %s,%s\n", wot, nameXMMReg(eregOfRexRM(pfx,modrm)),
10259 nameXMMReg(gregOfRexRM(pfx,modrm)));
10260 delta += 2+1;
10261 } else {
10262 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10263 putXMMReg( gregOfRexRM(pfx,modrm),
10264 loadLE(Ity_V128, mkexpr(addr)) );
10265 DIP("mov%s %s,%s\n", wot, dis_buf,
10266 nameXMMReg(gregOfRexRM(pfx,modrm)));
10267 delta += 2+alen;
10268 }
10269 goto decode_success;
10270 }
10271
sewardj4c328cf2005-05-05 12:05:54 +000010272 /* 66 0F 29 = MOVAPD -- move from G (xmm) to E (mem or xmm). */
sewardj240fd862005-11-01 18:59:38 +000010273 /* 66 0F 11 = MOVUPD -- move from G (xmm) to E (mem or xmm). */
10274 if (have66noF2noF3(pfx) && insn[0] == 0x0F
10275 && (insn[1] == 0x29 || insn[1] == 0x11)) {
sewardj4c328cf2005-05-05 12:05:54 +000010276 modrm = getUChar(delta+2);
10277 if (epartIsReg(modrm)) {
10278 /* fall through; awaiting test case */
10279 } else {
10280 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10281 storeLE( mkexpr(addr), getXMMReg(gregOfRexRM(pfx,modrm)) );
sewardj240fd862005-11-01 18:59:38 +000010282 DIP("mov[ua]pd %s,%s\n", nameXMMReg(gregOfRexRM(pfx,modrm)),
10283 dis_buf );
sewardj4c328cf2005-05-05 12:05:54 +000010284 delta += 2+alen;
10285 goto decode_success;
10286 }
10287 }
10288
sewardj09717342005-05-05 21:34:02 +000010289 /* 66 0F 6E = MOVD from ireg32/m32 to xmm lo 1/4, zeroing high 3/4 of xmm. */
10290 /* or from ireg64/m64 to xmm lo 1/2, zeroing high 1/2 of xmm. */
10291 if (have66noF2noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x6E) {
sewardj97628592005-05-10 22:42:54 +000010292 vassert(sz == 2 || sz == 8);
10293 if (sz == 2) sz = 4;
sewardj09717342005-05-05 21:34:02 +000010294 modrm = getUChar(delta+2);
10295 if (epartIsReg(modrm)) {
10296 delta += 2+1;
10297 if (sz == 4) {
sewardj09717342005-05-05 21:34:02 +000010298 putXMMReg(
10299 gregOfRexRM(pfx,modrm),
10300 unop( Iop_32UtoV128, getIReg32(eregOfRexRM(pfx,modrm)) )
10301 );
10302 DIP("movd %s, %s\n", nameIReg32(eregOfRexRM(pfx,modrm)),
10303 nameXMMReg(gregOfRexRM(pfx,modrm)));
10304 } else {
10305 putXMMReg(
10306 gregOfRexRM(pfx,modrm),
10307 unop( Iop_64UtoV128, getIReg64(eregOfRexRM(pfx,modrm)) )
10308 );
10309 DIP("movq %s, %s\n", nameIReg64(eregOfRexRM(pfx,modrm)),
10310 nameXMMReg(gregOfRexRM(pfx,modrm)));
10311 }
10312 } else {
10313 addr = disAMode( &alen, pfx, delta+2, dis_buf, 0 );
10314 delta += 2+alen;
10315 putXMMReg(
10316 gregOfRexRM(pfx,modrm),
10317 sz == 4
10318 ? unop( Iop_32UtoV128,loadLE(Ity_I32, mkexpr(addr)) )
10319 : unop( Iop_64UtoV128,loadLE(Ity_I64, mkexpr(addr)) )
10320 );
10321 DIP("mov%c %s, %s\n", sz == 4 ? 'd' : 'q', dis_buf,
10322 nameXMMReg(gregOfRexRM(pfx,modrm)));
10323 }
10324 goto decode_success;
10325 }
10326
10327 /* 66 0F 7E = MOVD from xmm low 1/4 to ireg32 or m32. */
10328 /* or from xmm low 1/2 to ireg64 or m64. */
10329 if (have66noF2noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x7E) {
10330 if (sz == 2) sz = 4;
10331 vassert(sz == 4 || sz == 8);
10332 modrm = getUChar(delta+2);
10333 if (epartIsReg(modrm)) {
10334 delta += 2+1;
10335 if (sz == 4) {
10336 putIReg32( eregOfRexRM(pfx,modrm),
10337 getXMMRegLane32(gregOfRexRM(pfx,modrm), 0) );
10338 DIP("movd %s, %s\n", nameXMMReg(gregOfRexRM(pfx,modrm)),
10339 nameIReg32(eregOfRexRM(pfx,modrm)));
10340 } else {
10341 putIReg64( eregOfRexRM(pfx,modrm),
10342 getXMMRegLane64(gregOfRexRM(pfx,modrm), 0) );
10343 DIP("movq %s, %s\n", nameXMMReg(gregOfRexRM(pfx,modrm)),
10344 nameIReg64(eregOfRexRM(pfx,modrm)));
10345 }
10346 } else {
10347 addr = disAMode( &alen, pfx, delta+2, dis_buf, 0 );
10348 delta += 2+alen;
10349 storeLE( mkexpr(addr),
10350 sz == 4
10351 ? getXMMRegLane32(gregOfRexRM(pfx,modrm),0)
10352 : getXMMRegLane64(gregOfRexRM(pfx,modrm),0) );
10353 DIP("mov%c %s, %s\n", sz == 4 ? 'd' : 'q',
10354 nameXMMReg(gregOfRexRM(pfx,modrm)), dis_buf);
10355 }
10356 goto decode_success;
10357 }
10358
10359 /* 66 0F 7F = MOVDQA -- move from G (xmm) to E (mem or xmm). */
10360 if (have66noF2noF3(pfx) && sz == 2
10361 && insn[0] == 0x0F && insn[1] == 0x7F) {
10362 modrm = getUChar(delta+2);
10363 if (epartIsReg(modrm)) {
10364 delta += 2+1;
10365 putXMMReg( eregOfRexRM(pfx,modrm),
10366 getXMMReg(gregOfRexRM(pfx,modrm)) );
10367 DIP("movdqa %s, %s\n", nameXMMReg(gregOfRexRM(pfx,modrm)),
10368 nameXMMReg(eregOfRexRM(pfx,modrm)));
10369 } else {
10370 addr = disAMode( &alen, pfx, delta+2, dis_buf, 0 );
10371 delta += 2+alen;
10372 storeLE( mkexpr(addr), getXMMReg(gregOfRexRM(pfx,modrm)) );
10373 DIP("movdqa %s, %s\n", nameXMMReg(gregOfRexRM(pfx,modrm)), dis_buf);
10374 }
10375 goto decode_success;
10376 }
10377
sewardj612be432005-05-11 02:55:54 +000010378 /* F3 0F 6F = MOVDQU -- move from E (mem or xmm) to G (xmm). */
10379 if (haveF3no66noF2(pfx) && sz == 4
10380 && insn[0] == 0x0F && insn[1] == 0x6F) {
10381 modrm = getUChar(delta+2);
10382 if (epartIsReg(modrm)) {
10383 putXMMReg( gregOfRexRM(pfx,modrm),
10384 getXMMReg( eregOfRexRM(pfx,modrm) ));
10385 DIP("movdqu %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
10386 nameXMMReg(gregOfRexRM(pfx,modrm)));
10387 delta += 2+1;
10388 } else {
10389 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10390 putXMMReg( gregOfRexRM(pfx,modrm),
10391 loadLE(Ity_V128, mkexpr(addr)) );
10392 DIP("movdqu %s,%s\n", dis_buf,
10393 nameXMMReg(gregOfRexRM(pfx,modrm)));
10394 delta += 2+alen;
10395 }
10396 goto decode_success;
10397 }
10398
10399 /* F3 0F 7F = MOVDQU -- move from G (xmm) to E (mem or xmm). */
10400 if (haveF3no66noF2(pfx) && sz == 4
10401 && insn[0] == 0x0F && insn[1] == 0x7F) {
10402 modrm = getUChar(delta+2);
10403 if (epartIsReg(modrm)) {
10404 goto decode_failure; /* awaiting test case */
10405 delta += 2+1;
10406 putXMMReg( eregOfRexRM(pfx,modrm),
10407 getXMMReg(gregOfRexRM(pfx,modrm)) );
10408 DIP("movdqu %s, %s\n", nameXMMReg(gregOfRexRM(pfx,modrm)),
10409 nameXMMReg(eregOfRexRM(pfx,modrm)));
10410 } else {
10411 addr = disAMode( &alen, pfx, delta+2, dis_buf, 0 );
10412 delta += 2+alen;
10413 storeLE( mkexpr(addr), getXMMReg(gregOfRexRM(pfx,modrm)) );
10414 DIP("movdqu %s, %s\n", nameXMMReg(gregOfRexRM(pfx,modrm)), dis_buf);
10415 }
10416 goto decode_success;
10417 }
10418
10419 /* F2 0F D6 = MOVDQ2Q -- move from E (lo half xmm, not mem) to G (mmx). */
10420 if (haveF2no66noF3(pfx) && sz == 4
10421 && insn[0] == 0x0F && insn[1] == 0xD6) {
10422 modrm = getUChar(delta+2);
10423 if (epartIsReg(modrm)) {
10424 do_MMX_preamble();
10425 putMMXReg( gregLO3ofRM(modrm),
10426 getXMMRegLane64( eregOfRexRM(pfx,modrm), 0 ));
10427 DIP("movdq2q %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
10428 nameMMXReg(gregLO3ofRM(modrm)));
10429 delta += 2+1;
10430 goto decode_success;
10431 } else {
10432 /* apparently no mem case for this insn */
10433 goto decode_failure;
10434 }
10435 }
sewardj4c328cf2005-05-05 12:05:54 +000010436
10437 /* 66 0F 16 = MOVHPD -- move from mem to high half of XMM. */
10438 /* These seems identical to MOVHPS. This instruction encoding is
10439 completely crazy. */
10440 if (have66noF2noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x16) {
10441 modrm = getUChar(delta+2);
10442 if (epartIsReg(modrm)) {
10443 /* fall through; apparently reg-reg is not possible */
10444 } else {
10445 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10446 delta += 2+alen;
10447 putXMMRegLane64( gregOfRexRM(pfx,modrm), 1/*upper lane*/,
10448 loadLE(Ity_I64, mkexpr(addr)) );
10449 DIP("movhpd %s,%s\n", dis_buf,
10450 nameXMMReg( gregOfRexRM(pfx,modrm) ));
10451 goto decode_success;
10452 }
10453 }
10454
10455 /* 66 0F 17 = MOVHPD -- move from high half of XMM to mem. */
10456 /* Again, this seems identical to MOVHPS. */
10457 if (have66noF2noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x17) {
10458 if (!epartIsReg(insn[2])) {
10459 delta += 2;
10460 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
10461 delta += alen;
10462 storeLE( mkexpr(addr),
10463 getXMMRegLane64( gregOfRexRM(pfx,insn[2]),
10464 1/*upper lane*/ ) );
10465 DIP("movhpd %s,%s\n", nameXMMReg( gregOfRexRM(pfx,insn[2]) ),
10466 dis_buf);
10467 goto decode_success;
10468 }
10469 /* else fall through */
10470 }
sewardj1001dc42005-02-21 08:25:55 +000010471
10472 /* 66 0F 12 = MOVLPD -- move from mem to low half of XMM. */
10473 /* Identical to MOVLPS ? */
10474 if (have66noF2noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x12) {
10475 modrm = getUChar(delta+2);
10476 if (epartIsReg(modrm)) {
10477 /* fall through; apparently reg-reg is not possible */
10478 } else {
10479 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10480 delta += 2+alen;
10481 putXMMRegLane64( gregOfRexRM(pfx,modrm),
10482 0/*lower lane*/,
10483 loadLE(Ity_I64, mkexpr(addr)) );
10484 DIP("movlpd %s, %s\n",
10485 dis_buf, nameXMMReg( gregOfRexRM(pfx,modrm) ));
10486 goto decode_success;
10487 }
10488 }
10489
sewardj4c328cf2005-05-05 12:05:54 +000010490 /* 66 0F 13 = MOVLPD -- move from low half of XMM to mem. */
10491 /* Identical to MOVLPS ? */
10492 if (have66noF2noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x13) {
10493 modrm = getUChar(delta+2);
10494 if (!epartIsReg(modrm)) {
10495 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10496 delta += 2+alen;
10497 storeLE( mkexpr(addr),
10498 getXMMRegLane64( gregOfRexRM(pfx,modrm),
10499 0/*lower lane*/ ) );
10500 DIP("movlpd %s, %s\n", nameXMMReg( gregOfRexRM(pfx,modrm) ),
10501 dis_buf);
10502 goto decode_success;
10503 }
10504 /* else fall through */
10505 }
10506
sewardj612be432005-05-11 02:55:54 +000010507 /* 66 0F 50 = MOVMSKPD - move 2 sign bits from 2 x F64 in xmm(E) to
10508 2 lowest bits of ireg(G) */
sewardjae84d782006-04-13 22:06:35 +000010509 if (have66noF2noF3(pfx) && (sz == 2 || sz == 8)
sewardj612be432005-05-11 02:55:54 +000010510 && insn[0] == 0x0F && insn[1] == 0x50) {
sewardjae84d782006-04-13 22:06:35 +000010511 /* sz == 8 is a kludge to handle insns with REX.W redundantly
10512 set to 1, which has been known to happen:
10513 66 4c 0f 50 d9 rex64X movmskpd %xmm1,%r11d
10514 */
sewardj612be432005-05-11 02:55:54 +000010515 modrm = getUChar(delta+2);
10516 if (epartIsReg(modrm)) {
10517 Int src;
10518 t0 = newTemp(Ity_I32);
10519 t1 = newTemp(Ity_I32);
10520 delta += 2+1;
10521 src = eregOfRexRM(pfx,modrm);
10522 assign( t0, binop( Iop_And32,
10523 binop(Iop_Shr32, getXMMRegLane32(src,1), mkU8(31)),
10524 mkU32(1) ));
10525 assign( t1, binop( Iop_And32,
10526 binop(Iop_Shr32, getXMMRegLane32(src,3), mkU8(30)),
10527 mkU32(2) ));
10528 putIReg32( gregOfRexRM(pfx,modrm),
10529 binop(Iop_Or32, mkexpr(t0), mkexpr(t1))
10530 );
10531 DIP("movmskpd %s,%s\n", nameXMMReg(src),
10532 nameIReg32(gregOfRexRM(pfx,modrm)));
10533 goto decode_success;
10534 }
10535 /* else fall through */
10536 goto decode_failure;
10537 }
10538
10539 /* 66 0F E7 = MOVNTDQ -- for us, just a plain SSE store. */
10540 if (have66noF2noF3(pfx) && sz == 2
10541 && insn[0] == 0x0F && insn[1] == 0xE7) {
10542 modrm = getUChar(delta+2);
10543 if (!epartIsReg(modrm)) {
10544 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10545 storeLE( mkexpr(addr), getXMMReg(gregOfRexRM(pfx,modrm)) );
10546 DIP("movntdq %s,%s\n", dis_buf,
10547 nameXMMReg(gregOfRexRM(pfx,modrm)));
10548 delta += 2+alen;
10549 goto decode_success;
10550 }
10551 /* else fall through */
10552 goto decode_failure;
10553 }
sewardjf53b7352005-04-06 20:01:56 +000010554
10555 /* 0F C3 = MOVNTI -- for us, just a plain ireg store. */
10556 if (haveNo66noF2noF3(pfx) &&
10557 insn[0] == 0x0F && insn[1] == 0xC3) {
10558 vassert(sz == 4 || sz == 8);
10559 modrm = getUChar(delta+2);
10560 if (!epartIsReg(modrm)) {
10561 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10562 storeLE( mkexpr(addr), getIRegG(sz, pfx, modrm) );
10563 DIP("movnti %s,%s\n", dis_buf,
10564 nameIRegG(sz, pfx, modrm));
10565 delta += 2+alen;
10566 goto decode_success;
10567 }
10568 /* else fall through */
10569 }
sewardj5cc00ff2005-03-27 04:48:32 +000010570
10571 /* 66 0F D6 = MOVQ -- move 64 bits from G (lo half xmm) to E (mem
10572 or lo half xmm). */
10573 if (have66noF2noF3(pfx) && insn[0] == 0x0F && insn[1] == 0xD6) {
10574 vassert(sz == 2);
10575 modrm = getUChar(delta+2);
10576 if (epartIsReg(modrm)) {
10577 /* fall through, awaiting test case */
sewardj94a48b22005-05-14 11:17:25 +000010578 /* dst: lo half copied, hi half zeroed */
sewardj5cc00ff2005-03-27 04:48:32 +000010579 } else {
10580 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10581 storeLE( mkexpr(addr),
10582 getXMMRegLane64( gregOfRexRM(pfx,modrm), 0 ));
10583 DIP("movq %s,%s\n", nameXMMReg(gregOfRexRM(pfx,modrm)), dis_buf );
10584 delta += 2+alen;
10585 goto decode_success;
10586 }
10587 }
10588
sewardj612be432005-05-11 02:55:54 +000010589 /* F3 0F D6 = MOVQ2DQ -- move from E (mmx) to G (lo half xmm, zero
10590 hi half). */
10591 if (haveF3no66noF2(pfx) && sz == 4
10592 && insn[0] == 0x0F && insn[1] == 0xD6) {
10593 modrm = getUChar(delta+2);
10594 if (epartIsReg(modrm)) {
10595 do_MMX_preamble();
10596 putXMMReg( gregOfRexRM(pfx,modrm),
10597 unop(Iop_64UtoV128, getMMXReg( eregLO3ofRM(modrm) )) );
10598 DIP("movq2dq %s,%s\n", nameMMXReg(eregLO3ofRM(modrm)),
10599 nameXMMReg(gregOfRexRM(pfx,modrm)));
10600 delta += 2+1;
10601 goto decode_success;
10602 } else {
10603 /* apparently no mem case for this insn */
10604 goto decode_failure;
10605 }
10606 }
10607
10608 /* F3 0F 7E = MOVQ -- move 64 bits from E (mem or lo half xmm) to
sewardj94a48b22005-05-14 11:17:25 +000010609 G (lo half xmm). Upper half of G is zeroed out. */
sewardj1001dc42005-02-21 08:25:55 +000010610 /* F2 0F 10 = MOVSD -- move 64 bits from E (mem or lo half xmm) to
10611 G (lo half xmm). If E is mem, upper half of G is zeroed out.
sewardj94a48b22005-05-14 11:17:25 +000010612 If E is reg, upper half of G is unchanged. */
sewardj612be432005-05-11 02:55:54 +000010613 if ( (haveF2no66noF3(pfx) && sz == 4
10614 && insn[0] == 0x0F && insn[1] == 0x10)
sewardj5cc00ff2005-03-27 04:48:32 +000010615 ||
sewardj612be432005-05-11 02:55:54 +000010616 (haveF3no66noF2(pfx) && sz == 4
10617 && insn[0] == 0x0F && insn[1] == 0x7E)
sewardj1001dc42005-02-21 08:25:55 +000010618 ) {
sewardj1001dc42005-02-21 08:25:55 +000010619 modrm = getUChar(delta+2);
10620 if (epartIsReg(modrm)) {
10621 putXMMRegLane64( gregOfRexRM(pfx,modrm), 0,
10622 getXMMRegLane64( eregOfRexRM(pfx,modrm), 0 ));
sewardj94a48b22005-05-14 11:17:25 +000010623 if (insn[1] == 0x7E/*MOVQ*/) {
10624 /* zero bits 127:64 */
10625 putXMMRegLane64( gregOfRexRM(pfx,modrm), 1, mkU64(0) );
10626 }
sewardj1001dc42005-02-21 08:25:55 +000010627 DIP("movsd %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), mkV128(0) );
10633 putXMMRegLane64( gregOfRexRM(pfx,modrm), 0,
10634 loadLE(Ity_I64, mkexpr(addr)) );
10635 DIP("movsd %s,%s\n", dis_buf,
10636 nameXMMReg(gregOfRexRM(pfx,modrm)));
10637 delta += 2+alen;
10638 }
10639 goto decode_success;
10640 }
10641
10642 /* F2 0F 11 = MOVSD -- move 64 bits from G (lo half xmm) to E (mem
10643 or lo half xmm). */
sewardj8d965312005-02-25 02:48:47 +000010644 if (haveF2no66noF3(pfx) && sz == 4
10645 && insn[0] == 0x0F && insn[1] == 0x11) {
sewardj1001dc42005-02-21 08:25:55 +000010646 modrm = getUChar(delta+2);
10647 if (epartIsReg(modrm)) {
10648 /* fall through, we don't yet have a test case */
10649 } else {
10650 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10651 storeLE( mkexpr(addr),
10652 getXMMRegLane64(gregOfRexRM(pfx,modrm), 0) );
10653 DIP("movsd %s,%s\n", nameXMMReg(gregOfRexRM(pfx,modrm)),
10654 dis_buf);
10655 delta += 2+alen;
10656 goto decode_success;
10657 }
10658 }
10659
sewardj4c328cf2005-05-05 12:05:54 +000010660 /* 66 0F 59 = MULPD -- mul 64Fx2 from R/M to R */
10661 if (have66noF2noF3(pfx) && sz == 2
10662 && insn[0] == 0x0F && insn[1] == 0x59) {
10663 delta = dis_SSE_E_to_G_all( pfx, delta+2, "mulpd", Iop_Mul64Fx2 );
10664 goto decode_success;
10665 }
sewardj1001dc42005-02-21 08:25:55 +000010666
10667 /* F2 0F 59 = MULSD -- mul 64F0x2 from R/M to R */
sewardj8d965312005-02-25 02:48:47 +000010668 if (haveF2no66noF3(pfx) && sz == 4
10669 && insn[0] == 0x0F && insn[1] == 0x59) {
sewardj1001dc42005-02-21 08:25:55 +000010670 delta = dis_SSE_E_to_G_lo64( pfx, delta+2, "mulsd", Iop_Mul64F0x2 );
10671 goto decode_success;
10672 }
10673
sewardj8d965312005-02-25 02:48:47 +000010674 /* 66 0F 56 = ORPD -- G = G and E */
10675 if (have66noF2noF3(pfx) && sz == 2
10676 && insn[0] == 0x0F && insn[1] == 0x56) {
10677 delta = dis_SSE_E_to_G_all( pfx, delta+2, "orpd", Iop_OrV128 );
10678 goto decode_success;
10679 }
10680
sewardj09717342005-05-05 21:34:02 +000010681 /* 66 0F C6 /r ib = SHUFPD -- shuffle packed F64s */
10682 if (have66noF2noF3(pfx) && sz == 2
10683 && insn[0] == 0x0F && insn[1] == 0xC6) {
10684 Int select;
10685 IRTemp sV = newTemp(Ity_V128);
10686 IRTemp dV = newTemp(Ity_V128);
10687 IRTemp s1 = newTemp(Ity_I64);
10688 IRTemp s0 = newTemp(Ity_I64);
10689 IRTemp d1 = newTemp(Ity_I64);
10690 IRTemp d0 = newTemp(Ity_I64);
10691
10692 modrm = insn[2];
10693 assign( dV, getXMMReg(gregOfRexRM(pfx,modrm)) );
10694
10695 if (epartIsReg(modrm)) {
10696 assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
10697 select = (Int)insn[3];
10698 delta += 2+2;
10699 DIP("shufpd $%d,%s,%s\n", select,
10700 nameXMMReg(eregOfRexRM(pfx,modrm)),
10701 nameXMMReg(gregOfRexRM(pfx,modrm)));
10702 } else {
10703 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 1 );
10704 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
10705 select = (Int)insn[2+alen];
10706 delta += 3+alen;
10707 DIP("shufpd $%d,%s,%s\n", select,
10708 dis_buf,
10709 nameXMMReg(gregOfRexRM(pfx,modrm)));
10710 }
10711
10712 assign( d1, unop(Iop_V128HIto64, mkexpr(dV)) );
10713 assign( d0, unop(Iop_V128to64, mkexpr(dV)) );
10714 assign( s1, unop(Iop_V128HIto64, mkexpr(sV)) );
10715 assign( s0, unop(Iop_V128to64, mkexpr(sV)) );
10716
10717# define SELD(n) mkexpr((n)==0 ? d0 : d1)
10718# define SELS(n) mkexpr((n)==0 ? s0 : s1)
10719
10720 putXMMReg(
10721 gregOfRexRM(pfx,modrm),
10722 binop(Iop_64HLtoV128, SELS((select>>1)&1), SELD((select>>0)&1) )
10723 );
10724
10725# undef SELD
10726# undef SELS
10727
10728 goto decode_success;
10729 }
10730
sewardj97628592005-05-10 22:42:54 +000010731 /* 66 0F 51 = SQRTPD -- approx sqrt 64Fx2 from R/M to R */
10732 if (have66noF2noF3(pfx) && sz == 2
10733 && insn[0] == 0x0F && insn[1] == 0x51) {
10734 delta = dis_SSE_E_to_G_unary_all( pfx, delta+2,
10735 "sqrtpd", Iop_Sqrt64Fx2 );
10736 goto decode_success;
10737 }
sewardj1001dc42005-02-21 08:25:55 +000010738
10739 /* F2 0F 51 = SQRTSD -- approx sqrt 64F0x2 from R/M to R */
10740 if (haveF2no66noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x51) {
10741 vassert(sz == 4);
10742 delta = dis_SSE_E_to_G_unary_lo64( pfx, delta+2,
10743 "sqrtsd", Iop_Sqrt64F0x2 );
10744 goto decode_success;
10745 }
10746
sewardj4c328cf2005-05-05 12:05:54 +000010747 /* 66 0F 5C = SUBPD -- sub 64Fx2 from R/M to R */
10748 if (have66noF2noF3(pfx) && sz == 2
10749 && insn[0] == 0x0F && insn[1] == 0x5C) {
10750 delta = dis_SSE_E_to_G_all( pfx, delta+2, "subpd", Iop_Sub64Fx2 );
10751 goto decode_success;
10752 }
sewardj1001dc42005-02-21 08:25:55 +000010753
10754 /* F2 0F 5C = SUBSD -- sub 64F0x2 from R/M to R */
10755 if (haveF2no66noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x5C) {
10756 vassert(sz == 4);
10757 delta = dis_SSE_E_to_G_lo64( pfx, delta+2, "subsd", Iop_Sub64F0x2 );
10758 goto decode_success;
10759 }
10760
sewardj1a01e652005-02-23 11:39:21 +000010761 /* 66 0F 15 = UNPCKHPD -- unpack and interleave high part F64s */
10762 /* 66 0F 14 = UNPCKLPD -- unpack and interleave low part F64s */
10763 /* These just appear to be special cases of SHUFPS */
10764 if (have66noF2noF3(pfx)
10765 && sz == 2 /* could be 8 if rex also present */
10766 && insn[0] == 0x0F && (insn[1] == 0x15 || insn[1] == 0x14)) {
10767 IRTemp s1 = newTemp(Ity_I64);
10768 IRTemp s0 = newTemp(Ity_I64);
10769 IRTemp d1 = newTemp(Ity_I64);
10770 IRTemp d0 = newTemp(Ity_I64);
10771 IRTemp sV = newTemp(Ity_V128);
10772 IRTemp dV = newTemp(Ity_V128);
sewardj1027dc22005-02-26 01:55:02 +000010773 Bool hi = toBool(insn[1] == 0x15);
sewardj1a01e652005-02-23 11:39:21 +000010774
10775 modrm = insn[2];
10776 assign( dV, getXMMReg(gregOfRexRM(pfx,modrm)) );
10777
10778 if (epartIsReg(modrm)) {
10779 assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
10780 delta += 2+1;
10781 DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
10782 nameXMMReg(eregOfRexRM(pfx,modrm)),
10783 nameXMMReg(gregOfRexRM(pfx,modrm)));
10784 } else {
10785 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10786 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
10787 delta += 2+alen;
10788 DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
10789 dis_buf,
10790 nameXMMReg(gregOfRexRM(pfx,modrm)));
10791 }
10792
10793 assign( d1, unop(Iop_V128HIto64, mkexpr(dV)) );
10794 assign( d0, unop(Iop_V128to64, mkexpr(dV)) );
10795 assign( s1, unop(Iop_V128HIto64, mkexpr(sV)) );
10796 assign( s0, unop(Iop_V128to64, mkexpr(sV)) );
10797
10798 if (hi) {
10799 putXMMReg( gregOfRexRM(pfx,modrm),
10800 binop(Iop_64HLtoV128, mkexpr(s1), mkexpr(d1)) );
10801 } else {
10802 putXMMReg( gregOfRexRM(pfx,modrm),
10803 binop(Iop_64HLtoV128, mkexpr(s0), mkexpr(d0)) );
10804 }
10805
10806 goto decode_success;
10807 }
sewardj9da16972005-02-21 13:58:26 +000010808
10809 /* 66 0F 57 = XORPD -- G = G xor E */
sewardj97628592005-05-10 22:42:54 +000010810 if (have66noF2noF3(pfx) && sz == 2
10811 && insn[0] == 0x0F && insn[1] == 0x57) {
sewardj9da16972005-02-21 13:58:26 +000010812 delta = dis_SSE_E_to_G_all( pfx, delta+2, "xorpd", Iop_XorV128 );
10813 goto decode_success;
10814 }
10815
sewardj97628592005-05-10 22:42:54 +000010816 /* 66 0F 6B = PACKSSDW */
10817 if (have66noF2noF3(pfx) && sz == 2
10818 && insn[0] == 0x0F && insn[1] == 0x6B) {
10819 delta = dis_SSEint_E_to_G( pfx, delta+2,
10820 "packssdw", Iop_QNarrow32Sx4, True );
10821 goto decode_success;
10822 }
10823
10824 /* 66 0F 63 = PACKSSWB */
10825 if (have66noF2noF3(pfx) && sz == 2
10826 && insn[0] == 0x0F && insn[1] == 0x63) {
10827 delta = dis_SSEint_E_to_G( pfx, delta+2,
10828 "packsswb", Iop_QNarrow16Sx8, True );
10829 goto decode_success;
10830 }
10831
10832 /* 66 0F 67 = PACKUSWB */
10833 if (have66noF2noF3(pfx) && sz == 2
10834 && insn[0] == 0x0F && insn[1] == 0x67) {
10835 delta = dis_SSEint_E_to_G( pfx, delta+2,
10836 "packuswb", Iop_QNarrow16Ux8, True );
10837 goto decode_success;
10838 }
10839
10840 /* 66 0F FC = PADDB */
10841 if (have66noF2noF3(pfx) && sz == 2
10842 && insn[0] == 0x0F && insn[1] == 0xFC) {
10843 delta = dis_SSEint_E_to_G( pfx, delta+2,
10844 "paddb", Iop_Add8x16, False );
10845 goto decode_success;
10846 }
10847
10848 /* 66 0F FE = PADDD */
10849 if (have66noF2noF3(pfx) && sz == 2
10850 && insn[0] == 0x0F && insn[1] == 0xFE) {
10851 delta = dis_SSEint_E_to_G( pfx, delta+2,
10852 "paddd", Iop_Add32x4, False );
10853 goto decode_success;
10854 }
sewardj8711f662005-05-09 17:52:56 +000010855
10856 /* ***--- this is an MMX class insn introduced in SSE2 ---*** */
10857 /* 0F D4 = PADDQ -- add 64x1 */
10858 if (haveNo66noF2noF3(pfx) && sz == 4
10859 && insn[0] == 0x0F && insn[1] == 0xD4) {
10860 do_MMX_preamble();
10861 delta = dis_MMXop_regmem_to_reg (
10862 pfx, delta+2, insn[1], "paddq", False );
10863 goto decode_success;
10864 }
sewardj09717342005-05-05 21:34:02 +000010865
10866 /* 66 0F D4 = PADDQ */
10867 if (have66noF2noF3(pfx) && sz == 2
10868 && insn[0] == 0x0F && insn[1] == 0xD4) {
10869 delta = dis_SSEint_E_to_G( pfx, delta+2,
10870 "paddq", Iop_Add64x2, False );
10871 goto decode_success;
10872 }
10873
sewardj5992bd02005-05-11 02:13:42 +000010874 /* 66 0F FD = PADDW */
10875 if (have66noF2noF3(pfx) && sz == 2
10876 && insn[0] == 0x0F && insn[1] == 0xFD) {
10877 delta = dis_SSEint_E_to_G( pfx, delta+2,
10878 "paddw", Iop_Add16x8, False );
10879 goto decode_success;
10880 }
10881
10882 /* 66 0F EC = PADDSB */
10883 if (have66noF2noF3(pfx) && sz == 2
10884 && insn[0] == 0x0F && insn[1] == 0xEC) {
10885 delta = dis_SSEint_E_to_G( pfx, delta+2,
10886 "paddsb", Iop_QAdd8Sx16, False );
10887 goto decode_success;
10888 }
10889
10890 /* 66 0F ED = PADDSW */
10891 if (have66noF2noF3(pfx) && sz == 2
10892 && insn[0] == 0x0F && insn[1] == 0xED) {
10893 delta = dis_SSEint_E_to_G( pfx, delta+2,
10894 "paddsw", Iop_QAdd16Sx8, False );
10895 goto decode_success;
10896 }
10897
10898 /* 66 0F DC = PADDUSB */
10899 if (have66noF2noF3(pfx) && sz == 2
10900 && insn[0] == 0x0F && insn[1] == 0xDC) {
10901 delta = dis_SSEint_E_to_G( pfx, delta+2,
10902 "paddusb", Iop_QAdd8Ux16, False );
10903 goto decode_success;
10904 }
10905
10906 /* 66 0F DD = PADDUSW */
10907 if (have66noF2noF3(pfx) && sz == 2
10908 && insn[0] == 0x0F && insn[1] == 0xDD) {
10909 delta = dis_SSEint_E_to_G( pfx, delta+2,
10910 "paddusw", Iop_QAdd16Ux8, False );
10911 goto decode_success;
10912 }
sewardj09717342005-05-05 21:34:02 +000010913
10914 /* 66 0F DB = PAND */
10915 if (have66noF2noF3(pfx) && sz == 2
10916 && insn[0] == 0x0F && insn[1] == 0xDB) {
10917 delta = dis_SSE_E_to_G_all( pfx, delta+2, "pand", Iop_AndV128 );
10918 goto decode_success;
10919 }
10920
sewardj5992bd02005-05-11 02:13:42 +000010921 /* 66 0F DF = PANDN */
10922 if (have66noF2noF3(pfx) && sz == 2
10923 && insn[0] == 0x0F && insn[1] == 0xDF) {
10924 delta = dis_SSE_E_to_G_all_invG( pfx, delta+2, "pandn", Iop_AndV128 );
10925 goto decode_success;
10926 }
10927
10928 /* 66 0F E0 = PAVGB */
10929 if (have66noF2noF3(pfx) && sz == 2
10930 && insn[0] == 0x0F && insn[1] == 0xE0) {
10931 delta = dis_SSEint_E_to_G( pfx, delta+2,
10932 "pavgb", Iop_Avg8Ux16, False );
10933 goto decode_success;
10934 }
10935
10936 /* 66 0F E3 = PAVGW */
10937 if (have66noF2noF3(pfx) && sz == 2
10938 && insn[0] == 0x0F && insn[1] == 0xE3) {
10939 delta = dis_SSEint_E_to_G( pfx, delta+2,
10940 "pavgw", Iop_Avg16Ux8, False );
10941 goto decode_success;
10942 }
10943
10944 /* 66 0F 74 = PCMPEQB */
10945 if (have66noF2noF3(pfx) && sz == 2
10946 && insn[0] == 0x0F && insn[1] == 0x74) {
10947 delta = dis_SSEint_E_to_G( pfx, delta+2,
10948 "pcmpeqb", Iop_CmpEQ8x16, False );
10949 goto decode_success;
10950 }
10951
10952 /* 66 0F 76 = PCMPEQD */
10953 if (have66noF2noF3(pfx) && sz == 2
10954 && insn[0] == 0x0F && insn[1] == 0x76) {
10955 delta = dis_SSEint_E_to_G( pfx, delta+2,
10956 "pcmpeqd", Iop_CmpEQ32x4, False );
10957 goto decode_success;
10958 }
10959
10960 /* 66 0F 75 = PCMPEQW */
10961 if (have66noF2noF3(pfx) && sz == 2
10962 && insn[0] == 0x0F && insn[1] == 0x75) {
10963 delta = dis_SSEint_E_to_G( pfx, delta+2,
10964 "pcmpeqw", Iop_CmpEQ16x8, False );
10965 goto decode_success;
10966 }
10967
10968 /* 66 0F 64 = PCMPGTB */
10969 if (have66noF2noF3(pfx) && sz == 2
10970 && insn[0] == 0x0F && insn[1] == 0x64) {
10971 delta = dis_SSEint_E_to_G( pfx, delta+2,
10972 "pcmpgtb", Iop_CmpGT8Sx16, False );
10973 goto decode_success;
10974 }
10975
10976 /* 66 0F 66 = PCMPGTD */
10977 if (have66noF2noF3(pfx) && sz == 2
10978 && insn[0] == 0x0F && insn[1] == 0x66) {
10979 delta = dis_SSEint_E_to_G( pfx, delta+2,
10980 "pcmpgtd", Iop_CmpGT32Sx4, False );
10981 goto decode_success;
10982 }
10983
10984 /* 66 0F 65 = PCMPGTW */
10985 if (have66noF2noF3(pfx) && sz == 2
10986 && insn[0] == 0x0F && insn[1] == 0x65) {
10987 delta = dis_SSEint_E_to_G( pfx, delta+2,
10988 "pcmpgtw", Iop_CmpGT16Sx8, False );
10989 goto decode_success;
10990 }
sewardj97628592005-05-10 22:42:54 +000010991
10992 /* 66 0F C5 = PEXTRW -- extract 16-bit field from xmm(E) and put
10993 zero-extend of it in ireg(G). */
10994 if (have66noF2noF3(pfx) && sz == 2
10995 && insn[0] == 0x0F && insn[1] == 0xC5) {
10996 modrm = insn[2];
10997 if (epartIsReg(modrm)) {
10998 t5 = newTemp(Ity_V128);
10999 t4 = newTemp(Ity_I16);
11000 assign(t5, getXMMReg(eregOfRexRM(pfx,modrm)));
11001 breakup128to32s( t5, &t3, &t2, &t1, &t0 );
11002 switch (insn[3] & 7) {
11003 case 0: assign(t4, unop(Iop_32to16, mkexpr(t0))); break;
11004 case 1: assign(t4, unop(Iop_32HIto16, mkexpr(t0))); break;
11005 case 2: assign(t4, unop(Iop_32to16, mkexpr(t1))); break;
11006 case 3: assign(t4, unop(Iop_32HIto16, mkexpr(t1))); break;
11007 case 4: assign(t4, unop(Iop_32to16, mkexpr(t2))); break;
11008 case 5: assign(t4, unop(Iop_32HIto16, mkexpr(t2))); break;
11009 case 6: assign(t4, unop(Iop_32to16, mkexpr(t3))); break;
11010 case 7: assign(t4, unop(Iop_32HIto16, mkexpr(t3))); break;
11011 default: vassert(0);
11012 }
11013 putIReg32(gregOfRexRM(pfx,modrm), unop(Iop_16Uto32, mkexpr(t4)));
11014 DIP("pextrw $%d,%s,%s\n",
11015 (Int)insn[3], nameXMMReg(eregOfRexRM(pfx,modrm)),
11016 nameIReg32(gregOfRexRM(pfx,modrm)));
11017 delta += 4;
11018 goto decode_success;
11019 }
11020 /* else fall through */
11021 /* note, if memory case is ever filled in, there is 1 byte after
11022 amode */
11023 }
11024
11025 /* 66 0F C4 = PINSRW -- get 16 bits from E(mem or low half ireg) and
11026 put it into the specified lane of xmm(G). */
11027 if (have66noF2noF3(pfx) && sz == 2
11028 && insn[0] == 0x0F && insn[1] == 0xC4) {
11029 Int lane;
11030 t4 = newTemp(Ity_I16);
11031 modrm = insn[2];
11032
11033 if (epartIsReg(modrm)) {
11034 assign(t4, getIReg16(eregOfRexRM(pfx,modrm)));
11035 delta += 3+1;
11036 lane = insn[3+1-1];
11037 DIP("pinsrw $%d,%s,%s\n", (Int)lane,
11038 nameIReg16(eregOfRexRM(pfx,modrm)),
11039 nameXMMReg(gregOfRexRM(pfx,modrm)));
11040 } else {
11041 addr = disAMode ( &alen, pfx, delta+2, dis_buf,
11042 1/*byte after the amode*/ );
11043 delta += 3+alen;
11044 lane = insn[3+alen-1];
11045 assign(t4, loadLE(Ity_I16, mkexpr(addr)));
11046 DIP("pinsrw $%d,%s,%s\n", (Int)lane,
11047 dis_buf,
11048 nameXMMReg(gregOfRexRM(pfx,modrm)));
11049 }
11050
11051 putXMMRegLane16( gregOfRexRM(pfx,modrm), lane & 7, mkexpr(t4) );
11052 goto decode_success;
11053 }
11054
sewardjdb859032006-04-08 16:15:53 +000011055 /* 66 0F F5 = PMADDWD -- Multiply and add packed integers from
11056 E(xmm or mem) to G(xmm) */
11057 if (have66noF2noF3(pfx) && sz == 2
11058 && insn[0] == 0x0F && insn[1] == 0xF5) {
11059 IRTemp s1V = newTemp(Ity_V128);
11060 IRTemp s2V = newTemp(Ity_V128);
11061 IRTemp dV = newTemp(Ity_V128);
11062 IRTemp s1Hi = newTemp(Ity_I64);
11063 IRTemp s1Lo = newTemp(Ity_I64);
11064 IRTemp s2Hi = newTemp(Ity_I64);
11065 IRTemp s2Lo = newTemp(Ity_I64);
11066 IRTemp dHi = newTemp(Ity_I64);
11067 IRTemp dLo = newTemp(Ity_I64);
11068 modrm = insn[2];
11069 if (epartIsReg(modrm)) {
11070 assign( s1V, getXMMReg(eregOfRexRM(pfx,modrm)) );
11071 delta += 2+1;
11072 DIP("pmaddwd %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
11073 nameXMMReg(gregOfRexRM(pfx,modrm)));
11074 } else {
11075 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
11076 assign( s1V, loadLE(Ity_V128, mkexpr(addr)) );
11077 delta += 2+alen;
11078 DIP("pmaddwd %s,%s\n", dis_buf,
11079 nameXMMReg(gregOfRexRM(pfx,modrm)));
11080 }
11081 assign( s2V, getXMMReg(gregOfRexRM(pfx,modrm)) );
11082 assign( s1Hi, unop(Iop_V128HIto64, mkexpr(s1V)) );
11083 assign( s1Lo, unop(Iop_V128to64, mkexpr(s1V)) );
11084 assign( s2Hi, unop(Iop_V128HIto64, mkexpr(s2V)) );
11085 assign( s2Lo, unop(Iop_V128to64, mkexpr(s2V)) );
11086 assign( dHi, mkIRExprCCall(
11087 Ity_I64, 0/*regparms*/,
11088 "amd64g_calculate_mmx_pmaddwd",
11089 &amd64g_calculate_mmx_pmaddwd,
11090 mkIRExprVec_2( mkexpr(s1Hi), mkexpr(s2Hi))
11091 ));
11092 assign( dLo, mkIRExprCCall(
11093 Ity_I64, 0/*regparms*/,
11094 "amd64g_calculate_mmx_pmaddwd",
11095 &amd64g_calculate_mmx_pmaddwd,
11096 mkIRExprVec_2( mkexpr(s1Lo), mkexpr(s2Lo))
11097 ));
11098 assign( dV, binop(Iop_64HLtoV128, mkexpr(dHi), mkexpr(dLo))) ;
11099 putXMMReg(gregOfRexRM(pfx,modrm), mkexpr(dV));
11100 goto decode_success;
11101 }
11102
sewardjadffcef2005-05-11 00:03:06 +000011103 /* 66 0F EE = PMAXSW -- 16x8 signed max */
11104 if (have66noF2noF3(pfx) && sz == 2
11105 && insn[0] == 0x0F && insn[1] == 0xEE) {
11106 delta = dis_SSEint_E_to_G( pfx, delta+2,
11107 "pmaxsw", Iop_Max16Sx8, False );
11108 goto decode_success;
11109 }
11110
11111 /* 66 0F DE = PMAXUB -- 8x16 unsigned max */
11112 if (have66noF2noF3(pfx) && sz == 2
11113 && insn[0] == 0x0F && insn[1] == 0xDE) {
11114 delta = dis_SSEint_E_to_G( pfx, delta+2,
11115 "pmaxub", Iop_Max8Ux16, False );
11116 goto decode_success;
11117 }
11118
11119 /* 66 0F EA = PMINSW -- 16x8 signed min */
11120 if (have66noF2noF3(pfx) && sz == 2
11121 && insn[0] == 0x0F && insn[1] == 0xEA) {
11122 delta = dis_SSEint_E_to_G( pfx, delta+2,
11123 "pminsw", Iop_Min16Sx8, False );
11124 goto decode_success;
11125 }
11126
11127 /* 66 0F DA = PMINUB -- 8x16 unsigned min */
11128 if (have66noF2noF3(pfx) && sz == 2
11129 && insn[0] == 0x0F && insn[1] == 0xDA) {
11130 delta = dis_SSEint_E_to_G( pfx, delta+2,
11131 "pminub", Iop_Min8Ux16, False );
11132 goto decode_success;
11133 }
11134
11135 /* 66 0F D7 = PMOVMSKB -- extract sign bits from each of 16 lanes in
11136 xmm(E), turn them into a byte, and put zero-extend of it in
11137 ireg(G). Doing this directly is just too cumbersome; give up
11138 therefore and call a helper. */
11139 /* UInt x86g_calculate_sse_pmovmskb ( ULong w64hi, ULong w64lo ); */
11140 if (have66noF2noF3(pfx) && sz == 2
11141 && insn[0] == 0x0F && insn[1] == 0xD7) {
11142 modrm = insn[2];
11143 if (epartIsReg(modrm)) {
11144 t0 = newTemp(Ity_I64);
11145 t1 = newTemp(Ity_I64);
11146 assign(t0, getXMMRegLane64(eregOfRexRM(pfx,modrm), 0));
11147 assign(t1, getXMMRegLane64(eregOfRexRM(pfx,modrm), 1));
11148 t5 = newTemp(Ity_I64);
11149 assign(t5, mkIRExprCCall(
11150 Ity_I64, 0/*regparms*/,
11151 "amd64g_calculate_sse_pmovmskb",
11152 &amd64g_calculate_sse_pmovmskb,
11153 mkIRExprVec_2( mkexpr(t1), mkexpr(t0) )));
11154 putIReg32(gregOfRexRM(pfx,modrm), unop(Iop_64to32,mkexpr(t5)));
11155 DIP("pmovmskb %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
11156 nameIReg32(gregOfRexRM(pfx,modrm)));
11157 delta += 3;
11158 goto decode_success;
11159 }
11160 /* else fall through */
11161 }
11162
11163 /* 66 0F E4 = PMULHUW -- 16x8 hi-half of unsigned widening multiply */
11164 if (have66noF2noF3(pfx) && sz == 2
11165 && insn[0] == 0x0F && insn[1] == 0xE4) {
11166 delta = dis_SSEint_E_to_G( pfx, delta+2,
11167 "pmulhuw", Iop_MulHi16Ux8, False );
11168 goto decode_success;
11169 }
11170
11171 /* 66 0F E5 = PMULHW -- 16x8 hi-half of signed widening multiply */
11172 if (have66noF2noF3(pfx) && sz == 2
11173 && insn[0] == 0x0F && insn[1] == 0xE5) {
11174 delta = dis_SSEint_E_to_G( pfx, delta+2,
11175 "pmulhw", Iop_MulHi16Sx8, False );
11176 goto decode_success;
11177 }
11178
11179 /* 66 0F D5 = PMULHL -- 16x8 multiply */
11180 if (have66noF2noF3(pfx) && sz == 2
11181 && insn[0] == 0x0F && insn[1] == 0xD5) {
11182 delta = dis_SSEint_E_to_G( pfx, delta+2,
11183 "pmullw", Iop_Mul16x8, False );
11184 goto decode_success;
11185 }
11186
11187 /* ***--- this is an MMX class insn introduced in SSE2 ---*** */
11188 /* 0F F4 = PMULUDQ -- unsigned widening multiply of 32-lanes 0 x
11189 0 to form 64-bit result */
11190 if (haveNo66noF2noF3(pfx) && sz == 4
11191 && insn[0] == 0x0F && insn[1] == 0xF4) {
11192 IRTemp sV = newTemp(Ity_I64);
11193 IRTemp dV = newTemp(Ity_I64);
11194 t1 = newTemp(Ity_I32);
11195 t0 = newTemp(Ity_I32);
11196 modrm = insn[2];
11197
11198 do_MMX_preamble();
11199 assign( dV, getMMXReg(gregLO3ofRM(modrm)) );
11200
11201 if (epartIsReg(modrm)) {
11202 assign( sV, getMMXReg(eregLO3ofRM(modrm)) );
11203 delta += 2+1;
11204 DIP("pmuludq %s,%s\n", nameMMXReg(eregLO3ofRM(modrm)),
11205 nameMMXReg(gregLO3ofRM(modrm)));
11206 } else {
11207 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
11208 assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
11209 delta += 2+alen;
11210 DIP("pmuludq %s,%s\n", dis_buf,
11211 nameMMXReg(gregLO3ofRM(modrm)));
11212 }
11213
11214 assign( t0, unop(Iop_64to32, mkexpr(dV)) );
11215 assign( t1, unop(Iop_64to32, mkexpr(sV)) );
11216 putMMXReg( gregLO3ofRM(modrm),
11217 binop( Iop_MullU32, mkexpr(t0), mkexpr(t1) ) );
11218 goto decode_success;
11219 }
11220
11221 /* 66 0F F4 = PMULUDQ -- unsigned widening multiply of 32-lanes 0 x
11222 0 to form lower 64-bit half and lanes 2 x 2 to form upper 64-bit
11223 half */
11224 /* This is a really poor translation -- could be improved if
11225 performance critical */
11226 if (have66noF2noF3(pfx) && sz == 2
11227 && insn[0] == 0x0F && insn[1] == 0xF4) {
11228 IRTemp sV, dV;
11229 IRTemp s3, s2, s1, s0, d3, d2, d1, d0;
11230 sV = newTemp(Ity_V128);
11231 dV = newTemp(Ity_V128);
11232 s3 = s2 = s1 = s0 = d3 = d2 = d1 = d0 = IRTemp_INVALID;
11233 t1 = newTemp(Ity_I64);
11234 t0 = newTemp(Ity_I64);
11235 modrm = insn[2];
11236 assign( dV, getXMMReg(gregOfRexRM(pfx,modrm)) );
11237
11238 if (epartIsReg(modrm)) {
11239 assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
11240 delta += 2+1;
11241 DIP("pmuludq %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
11242 nameXMMReg(gregOfRexRM(pfx,modrm)));
11243 } else {
11244 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
11245 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
11246 delta += 2+alen;
11247 DIP("pmuludq %s,%s\n", dis_buf,
11248 nameXMMReg(gregOfRexRM(pfx,modrm)));
11249 }
11250
11251 breakup128to32s( dV, &d3, &d2, &d1, &d0 );
11252 breakup128to32s( sV, &s3, &s2, &s1, &s0 );
11253
11254 assign( t0, binop( Iop_MullU32, mkexpr(d0), mkexpr(s0)) );
11255 putXMMRegLane64( gregOfRexRM(pfx,modrm), 0, mkexpr(t0) );
11256 assign( t1, binop( Iop_MullU32, mkexpr(d2), mkexpr(s2)) );
11257 putXMMRegLane64( gregOfRexRM(pfx,modrm), 1, mkexpr(t1) );
11258 goto decode_success;
11259 }
sewardj09717342005-05-05 21:34:02 +000011260
11261 /* 66 0F EB = POR */
11262 if (have66noF2noF3(pfx) && sz == 2
11263 && insn[0] == 0x0F && insn[1] == 0xEB) {
11264 delta = dis_SSE_E_to_G_all( pfx, delta+2, "por", Iop_OrV128 );
11265 goto decode_success;
11266 }
11267
sewardj59e96c12006-07-24 08:51:16 +000011268 /* 66 0F F6 = PSADBW -- 2 x (8x8 -> 48 zeroes ++ u16) Sum Abs Diffs
11269 from E(xmm or mem) to G(xmm) */
11270 if (have66noF2noF3(pfx) && sz == 2
11271 && insn[0] == 0x0F && insn[1] == 0xF6) {
11272 IRTemp s1V = newTemp(Ity_V128);
11273 IRTemp s2V = newTemp(Ity_V128);
11274 IRTemp dV = newTemp(Ity_V128);
11275 IRTemp s1Hi = newTemp(Ity_I64);
11276 IRTemp s1Lo = newTemp(Ity_I64);
11277 IRTemp s2Hi = newTemp(Ity_I64);
11278 IRTemp s2Lo = newTemp(Ity_I64);
11279 IRTemp dHi = newTemp(Ity_I64);
11280 IRTemp dLo = newTemp(Ity_I64);
11281 modrm = insn[2];
11282 if (epartIsReg(modrm)) {
11283 assign( s1V, getXMMReg(eregOfRexRM(pfx,modrm)) );
11284 delta += 2+1;
11285 DIP("psadbw %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
11286 nameXMMReg(gregOfRexRM(pfx,modrm)));
11287 } else {
11288 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
11289 assign( s1V, loadLE(Ity_V128, mkexpr(addr)) );
11290 delta += 2+alen;
11291 DIP("psadbw %s,%s\n", dis_buf,
11292 nameXMMReg(gregOfRexRM(pfx,modrm)));
11293 }
11294 assign( s2V, getXMMReg(gregOfRexRM(pfx,modrm)) );
11295 assign( s1Hi, unop(Iop_V128HIto64, mkexpr(s1V)) );
11296 assign( s1Lo, unop(Iop_V128to64, mkexpr(s1V)) );
11297 assign( s2Hi, unop(Iop_V128HIto64, mkexpr(s2V)) );
11298 assign( s2Lo, unop(Iop_V128to64, mkexpr(s2V)) );
11299 assign( dHi, mkIRExprCCall(
11300 Ity_I64, 0/*regparms*/,
11301 "amd64g_calculate_mmx_psadbw",
11302 &amd64g_calculate_mmx_psadbw,
11303 mkIRExprVec_2( mkexpr(s1Hi), mkexpr(s2Hi))
11304 ));
11305 assign( dLo, mkIRExprCCall(
11306 Ity_I64, 0/*regparms*/,
11307 "amd64g_calculate_mmx_psadbw",
11308 &amd64g_calculate_mmx_psadbw,
11309 mkIRExprVec_2( mkexpr(s1Lo), mkexpr(s2Lo))
11310 ));
11311 assign( dV, binop(Iop_64HLtoV128, mkexpr(dHi), mkexpr(dLo))) ;
11312 putXMMReg(gregOfRexRM(pfx,modrm), mkexpr(dV));
11313 goto decode_success;
11314 }
11315
sewardjadffcef2005-05-11 00:03:06 +000011316 /* 66 0F 70 = PSHUFD -- rearrange 4x32 from E(xmm or mem) to G(xmm) */
11317 if (have66noF2noF3(pfx) && sz == 2
11318 && insn[0] == 0x0F && insn[1] == 0x70) {
11319 Int order;
11320 IRTemp sV, dV, s3, s2, s1, s0;
11321 s3 = s2 = s1 = s0 = IRTemp_INVALID;
11322 sV = newTemp(Ity_V128);
11323 dV = newTemp(Ity_V128);
11324 modrm = insn[2];
11325 if (epartIsReg(modrm)) {
11326 assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
11327 order = (Int)insn[3];
11328 delta += 3+1;
11329 DIP("pshufd $%d,%s,%s\n", order,
11330 nameXMMReg(eregOfRexRM(pfx,modrm)),
11331 nameXMMReg(gregOfRexRM(pfx,modrm)));
11332 } else {
11333 addr = disAMode ( &alen, pfx, delta+2, dis_buf,
11334 1/*byte after the amode*/ );
11335 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
11336 order = (Int)insn[2+alen];
11337 delta += 2+alen+1;
11338 DIP("pshufd $%d,%s,%s\n", order,
11339 dis_buf,
11340 nameXMMReg(gregOfRexRM(pfx,modrm)));
11341 }
11342 breakup128to32s( sV, &s3, &s2, &s1, &s0 );
11343
11344# define SEL(n) \
11345 ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
11346 assign(dV,
11347 mk128from32s( SEL((order>>6)&3), SEL((order>>4)&3),
11348 SEL((order>>2)&3), SEL((order>>0)&3) )
11349 );
11350 putXMMReg(gregOfRexRM(pfx,modrm), mkexpr(dV));
11351# undef SEL
11352 goto decode_success;
11353 }
11354
11355 /* F3 0F 70 = PSHUFHW -- rearrange upper half 4x16 from E(xmm or
11356 mem) to G(xmm), and copy lower half */
11357 if (haveF3no66noF2(pfx) && sz == 4
11358 && insn[0] == 0x0F && insn[1] == 0x70) {
11359 Int order;
11360 IRTemp sVhi, dVhi, sV, dV, s3, s2, s1, s0;
11361 s3 = s2 = s1 = s0 = IRTemp_INVALID;
11362 sV = newTemp(Ity_V128);
11363 dV = newTemp(Ity_V128);
11364 sVhi = newTemp(Ity_I64);
11365 dVhi = newTemp(Ity_I64);
11366 modrm = insn[2];
11367 if (epartIsReg(modrm)) {
11368 assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
11369 order = (Int)insn[3];
11370 delta += 3+1;
11371 DIP("pshufhw $%d,%s,%s\n", order,
11372 nameXMMReg(eregOfRexRM(pfx,modrm)),
11373 nameXMMReg(gregOfRexRM(pfx,modrm)));
11374 } else {
11375 addr = disAMode ( &alen, pfx, delta+2, dis_buf,
11376 1/*byte after the amode*/ );
11377 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
11378 order = (Int)insn[2+alen];
11379 delta += 2+alen+1;
11380 DIP("pshufhw $%d,%s,%s\n", order,
11381 dis_buf,
11382 nameXMMReg(gregOfRexRM(pfx,modrm)));
11383 }
11384 assign( sVhi, unop(Iop_V128HIto64, mkexpr(sV)) );
11385 breakup64to16s( sVhi, &s3, &s2, &s1, &s0 );
11386
11387# define SEL(n) \
11388 ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
11389 assign(dVhi,
11390 mk64from16s( SEL((order>>6)&3), SEL((order>>4)&3),
11391 SEL((order>>2)&3), SEL((order>>0)&3) )
11392 );
11393 assign(dV, binop( Iop_64HLtoV128,
11394 mkexpr(dVhi),
11395 unop(Iop_V128to64, mkexpr(sV))) );
11396 putXMMReg(gregOfRexRM(pfx,modrm), mkexpr(dV));
11397# undef SEL
11398 goto decode_success;
11399 }
11400
11401 /* F2 0F 70 = PSHUFLW -- rearrange lower half 4x16 from E(xmm or
11402 mem) to G(xmm), and copy upper half */
11403 if (haveF2no66noF3(pfx) && sz == 4
11404 && insn[0] == 0x0F && insn[1] == 0x70) {
11405 Int order;
11406 IRTemp sVlo, dVlo, sV, dV, s3, s2, s1, s0;
11407 s3 = s2 = s1 = s0 = IRTemp_INVALID;
11408 sV = newTemp(Ity_V128);
11409 dV = newTemp(Ity_V128);
11410 sVlo = newTemp(Ity_I64);
11411 dVlo = newTemp(Ity_I64);
11412 modrm = insn[2];
11413 if (epartIsReg(modrm)) {
11414 assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
11415 order = (Int)insn[3];
11416 delta += 3+1;
11417 DIP("pshuflw $%d,%s,%s\n", order,
11418 nameXMMReg(eregOfRexRM(pfx,modrm)),
11419 nameXMMReg(gregOfRexRM(pfx,modrm)));
11420 } else {
11421 addr = disAMode ( &alen, pfx, delta+2, dis_buf,
11422 1/*byte after the amode*/ );
11423 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
11424 order = (Int)insn[2+alen];
11425 delta += 2+alen+1;
11426 DIP("pshuflw $%d,%s,%s\n", order,
11427 dis_buf,
11428 nameXMMReg(gregOfRexRM(pfx,modrm)));
11429 }
11430 assign( sVlo, unop(Iop_V128to64, mkexpr(sV)) );
11431 breakup64to16s( sVlo, &s3, &s2, &s1, &s0 );
11432
11433# define SEL(n) \
11434 ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
11435 assign(dVlo,
11436 mk64from16s( SEL((order>>6)&3), SEL((order>>4)&3),
11437 SEL((order>>2)&3), SEL((order>>0)&3) )
11438 );
11439 assign(dV, binop( Iop_64HLtoV128,
11440 unop(Iop_V128HIto64, mkexpr(sV)),
11441 mkexpr(dVlo) ) );
11442 putXMMReg(gregOfRexRM(pfx,modrm), mkexpr(dV));
11443# undef SEL
11444 goto decode_success;
11445 }
11446
11447 /* 66 0F 72 /6 ib = PSLLD by immediate */
11448 if (have66noF2noF3(pfx) && sz == 2
11449 && insn[0] == 0x0F && insn[1] == 0x72
11450 && epartIsReg(insn[2])
11451 && gregLO3ofRM(insn[2]) == 6) {
11452 delta = dis_SSE_shiftE_imm( pfx, delta+2, "pslld", Iop_ShlN32x4 );
11453 goto decode_success;
11454 }
11455
11456 /* 66 0F F2 = PSLLD by E */
11457 if (have66noF2noF3(pfx) && sz == 2
11458 && insn[0] == 0x0F && insn[1] == 0xF2) {
11459 delta = dis_SSE_shiftG_byE( pfx, delta+2, "pslld", Iop_ShlN32x4 );
11460 goto decode_success;
11461 }
sewardj97628592005-05-10 22:42:54 +000011462
11463 /* 66 0F 73 /7 ib = PSLLDQ by immediate */
11464 /* note, if mem case ever filled in, 1 byte after amode */
11465 if (have66noF2noF3(pfx) && sz == 2
11466 && insn[0] == 0x0F && insn[1] == 0x73
11467 && epartIsReg(insn[2])
11468 && gregLO3ofRM(insn[2]) == 7) {
11469 IRTemp sV, dV, hi64, lo64, hi64r, lo64r;
11470 Int imm = (Int)insn[3];
11471 Int reg = eregOfRexRM(pfx,insn[2]);
11472 DIP("pslldq $%d,%s\n", imm, nameXMMReg(reg));
11473 vassert(imm >= 0 && imm <= 255);
11474 delta += 4;
11475
11476 sV = newTemp(Ity_V128);
11477 dV = newTemp(Ity_V128);
11478 hi64 = newTemp(Ity_I64);
11479 lo64 = newTemp(Ity_I64);
11480 hi64r = newTemp(Ity_I64);
11481 lo64r = newTemp(Ity_I64);
11482
11483 if (imm >= 16) {
11484 putXMMReg(reg, mkV128(0x0000));
11485 goto decode_success;
11486 }
11487
11488 assign( sV, getXMMReg(reg) );
11489 assign( hi64, unop(Iop_V128HIto64, mkexpr(sV)) );
11490 assign( lo64, unop(Iop_V128to64, mkexpr(sV)) );
11491
11492 if (imm == 0) {
11493 assign( lo64r, mkexpr(lo64) );
11494 assign( hi64r, mkexpr(hi64) );
11495 }
11496 else
11497 if (imm == 8) {
11498 assign( lo64r, mkU64(0) );
11499 assign( hi64r, mkexpr(lo64) );
11500 }
11501 else
11502 if (imm > 8) {
11503 assign( lo64r, mkU64(0) );
11504 assign( hi64r, binop( Iop_Shl64,
11505 mkexpr(lo64),
11506 mkU8( 8*(imm-8) ) ));
11507 } else {
11508 assign( lo64r, binop( Iop_Shl64,
11509 mkexpr(lo64),
11510 mkU8(8 * imm) ));
11511 assign( hi64r,
11512 binop( Iop_Or64,
11513 binop(Iop_Shl64, mkexpr(hi64),
11514 mkU8(8 * imm)),
11515 binop(Iop_Shr64, mkexpr(lo64),
11516 mkU8(8 * (8 - imm)) )
11517 )
11518 );
11519 }
11520 assign( dV, binop(Iop_64HLtoV128, mkexpr(hi64r), mkexpr(lo64r)) );
11521 putXMMReg(reg, mkexpr(dV));
11522 goto decode_success;
11523 }
11524
sewardjadffcef2005-05-11 00:03:06 +000011525 /* 66 0F 73 /6 ib = PSLLQ by immediate */
11526 if (have66noF2noF3(pfx) && sz == 2
11527 && insn[0] == 0x0F && insn[1] == 0x73
11528 && epartIsReg(insn[2])
11529 && gregLO3ofRM(insn[2]) == 6) {
11530 delta = dis_SSE_shiftE_imm( pfx, delta+2, "psllq", Iop_ShlN64x2 );
11531 goto decode_success;
11532 }
11533
11534 /* 66 0F F3 = PSLLQ by E */
11535 if (have66noF2noF3(pfx) && sz == 2
11536 && insn[0] == 0x0F && insn[1] == 0xF3) {
11537 delta = dis_SSE_shiftG_byE( pfx, delta+2, "psllq", Iop_ShlN64x2 );
11538 goto decode_success;
11539 }
11540
11541 /* 66 0F 71 /6 ib = PSLLW by immediate */
11542 if (have66noF2noF3(pfx) && sz == 2
11543 && insn[0] == 0x0F && insn[1] == 0x71
11544 && epartIsReg(insn[2])
11545 && gregLO3ofRM(insn[2]) == 6) {
11546 delta = dis_SSE_shiftE_imm( pfx, delta+2, "psllw", Iop_ShlN16x8 );
11547 goto decode_success;
11548 }
11549
11550 /* 66 0F F1 = PSLLW by E */
11551 if (have66noF2noF3(pfx) && sz == 2
11552 && insn[0] == 0x0F && insn[1] == 0xF1) {
11553 delta = dis_SSE_shiftG_byE( pfx, delta+2, "psllw", Iop_ShlN16x8 );
11554 goto decode_success;
11555 }
11556
11557 /* 66 0F 72 /4 ib = PSRAD by immediate */
11558 if (have66noF2noF3(pfx) && sz == 2
11559 && insn[0] == 0x0F && insn[1] == 0x72
11560 && epartIsReg(insn[2])
11561 && gregLO3ofRM(insn[2]) == 4) {
11562 delta = dis_SSE_shiftE_imm( pfx, delta+2, "psrad", Iop_SarN32x4 );
11563 goto decode_success;
11564 }
11565
11566 /* 66 0F E2 = PSRAD by E */
11567 if (have66noF2noF3(pfx) && sz == 2
11568 && insn[0] == 0x0F && insn[1] == 0xE2) {
11569 delta = dis_SSE_shiftG_byE( pfx, delta+2, "psrad", Iop_SarN32x4 );
11570 goto decode_success;
11571 }
11572
11573 /* 66 0F 71 /4 ib = PSRAW by immediate */
11574 if (have66noF2noF3(pfx) && sz == 2
11575 && insn[0] == 0x0F && insn[1] == 0x71
11576 && epartIsReg(insn[2])
11577 && gregLO3ofRM(insn[2]) == 4) {
11578 delta = dis_SSE_shiftE_imm( pfx, delta+2, "psraw", Iop_SarN16x8 );
11579 goto decode_success;
11580 }
11581
11582 /* 66 0F E1 = PSRAW by E */
11583 if (have66noF2noF3(pfx) && sz == 2
11584 && insn[0] == 0x0F && insn[1] == 0xE1) {
11585 delta = dis_SSE_shiftG_byE( pfx, delta+2, "psraw", Iop_SarN16x8 );
11586 goto decode_success;
11587 }
11588
11589 /* 66 0F 72 /2 ib = PSRLD by immediate */
11590 if (have66noF2noF3(pfx) && sz == 2
11591 && insn[0] == 0x0F && insn[1] == 0x72
11592 && epartIsReg(insn[2])
11593 && gregLO3ofRM(insn[2]) == 2) {
11594 delta = dis_SSE_shiftE_imm( pfx, delta+2, "psrld", Iop_ShrN32x4 );
11595 goto decode_success;
11596 }
11597
11598 /* 66 0F D2 = PSRLD by E */
11599 if (have66noF2noF3(pfx) && sz == 2
11600 && insn[0] == 0x0F && insn[1] == 0xD2) {
11601 delta = dis_SSE_shiftG_byE( pfx, delta+2, "psrld", Iop_ShrN32x4 );
11602 goto decode_success;
11603 }
sewardj97628592005-05-10 22:42:54 +000011604
11605 /* 66 0F 73 /3 ib = PSRLDQ by immediate */
11606 /* note, if mem case ever filled in, 1 byte after amode */
11607 if (have66noF2noF3(pfx) && sz == 2
11608 && insn[0] == 0x0F && insn[1] == 0x73
11609 && epartIsReg(insn[2])
11610 && gregLO3ofRM(insn[2]) == 3) {
11611 IRTemp sV, dV, hi64, lo64, hi64r, lo64r;
11612 Int imm = (Int)insn[3];
11613 Int reg = eregOfRexRM(pfx,insn[2]);
11614 DIP("psrldq $%d,%s\n", imm, nameXMMReg(reg));
11615 vassert(imm >= 0 && imm <= 255);
11616 delta += 4;
11617
11618 sV = newTemp(Ity_V128);
11619 dV = newTemp(Ity_V128);
11620 hi64 = newTemp(Ity_I64);
11621 lo64 = newTemp(Ity_I64);
11622 hi64r = newTemp(Ity_I64);
11623 lo64r = newTemp(Ity_I64);
11624
11625 if (imm >= 16) {
11626 putXMMReg(reg, mkV128(0x0000));
11627 goto decode_success;
11628 }
11629
11630 assign( sV, getXMMReg(reg) );
11631 assign( hi64, unop(Iop_V128HIto64, mkexpr(sV)) );
11632 assign( lo64, unop(Iop_V128to64, mkexpr(sV)) );
11633
11634 if (imm == 0) {
11635 assign( lo64r, mkexpr(lo64) );
11636 assign( hi64r, mkexpr(hi64) );
11637 }
11638 else
11639 if (imm == 8) {
11640 assign( hi64r, mkU64(0) );
11641 assign( lo64r, mkexpr(hi64) );
11642 }
11643 else
11644 if (imm > 8) {
11645 assign( hi64r, mkU64(0) );
11646 assign( lo64r, binop( Iop_Shr64,
11647 mkexpr(hi64),
11648 mkU8( 8*(imm-8) ) ));
11649 } else {
11650 assign( hi64r, binop( Iop_Shr64,
11651 mkexpr(hi64),
11652 mkU8(8 * imm) ));
11653 assign( lo64r,
11654 binop( Iop_Or64,
11655 binop(Iop_Shr64, mkexpr(lo64),
11656 mkU8(8 * imm)),
11657 binop(Iop_Shl64, mkexpr(hi64),
11658 mkU8(8 * (8 - imm)) )
11659 )
11660 );
11661 }
11662
11663 assign( dV, binop(Iop_64HLtoV128, mkexpr(hi64r), mkexpr(lo64r)) );
11664 putXMMReg(reg, mkexpr(dV));
11665 goto decode_success;
11666 }
sewardj09717342005-05-05 21:34:02 +000011667
11668 /* 66 0F 73 /2 ib = PSRLQ by immediate */
11669 if (have66noF2noF3(pfx) && sz == 2
11670 && insn[0] == 0x0F && insn[1] == 0x73
11671 && epartIsReg(insn[2])
11672 && gregLO3ofRM(insn[2]) == 2) {
11673 delta = dis_SSE_shiftE_imm( pfx, delta+2, "psrlq", Iop_ShrN64x2 );
11674 goto decode_success;
11675 }
11676
sewardjadffcef2005-05-11 00:03:06 +000011677 /* 66 0F D3 = PSRLQ by E */
11678 if (have66noF2noF3(pfx) && sz == 2
11679 && insn[0] == 0x0F && insn[1] == 0xD3) {
11680 delta = dis_SSE_shiftG_byE( pfx, delta+2, "psrlq", Iop_ShrN64x2 );
11681 goto decode_success;
11682 }
11683
11684 /* 66 0F 71 /2 ib = PSRLW by immediate */
11685 if (have66noF2noF3(pfx) && sz == 2
11686 && insn[0] == 0x0F && insn[1] == 0x71
11687 && epartIsReg(insn[2])
11688 && gregLO3ofRM(insn[2]) == 2) {
11689 delta = dis_SSE_shiftE_imm( pfx, delta+2, "psrlw", Iop_ShrN16x8 );
11690 goto decode_success;
11691 }
11692
11693 /* 66 0F D1 = PSRLW by E */
11694 if (have66noF2noF3(pfx) && sz == 2
11695 && insn[0] == 0x0F && insn[1] == 0xD1) {
11696 delta = dis_SSE_shiftG_byE( pfx, delta+2, "psrlw", Iop_ShrN16x8 );
11697 goto decode_success;
11698 }
sewardj97628592005-05-10 22:42:54 +000011699
11700 /* 66 0F F8 = PSUBB */
11701 if (have66noF2noF3(pfx) && sz == 2
11702 && insn[0] == 0x0F && insn[1] == 0xF8) {
11703 delta = dis_SSEint_E_to_G( pfx, delta+2,
11704 "psubb", Iop_Sub8x16, False );
11705 goto decode_success;
11706 }
11707
11708 /* 66 0F FA = PSUBD */
11709 if (have66noF2noF3(pfx) && sz == 2
11710 && insn[0] == 0x0F && insn[1] == 0xFA) {
11711 delta = dis_SSEint_E_to_G( pfx, delta+2,
11712 "psubd", Iop_Sub32x4, False );
11713 goto decode_success;
11714 }
sewardj8711f662005-05-09 17:52:56 +000011715
11716 /* ***--- this is an MMX class insn introduced in SSE2 ---*** */
11717 /* 0F FB = PSUBQ -- sub 64x1 */
11718 if (haveNo66noF2noF3(pfx) && sz == 4
11719 && insn[0] == 0x0F && insn[1] == 0xFB) {
11720 do_MMX_preamble();
11721 delta = dis_MMXop_regmem_to_reg (
11722 pfx, delta+2, insn[1], "psubq", False );
11723 goto decode_success;
11724 }
sewardj09717342005-05-05 21:34:02 +000011725
11726 /* 66 0F FB = PSUBQ */
11727 if (have66noF2noF3(pfx) && sz == 2
11728 && insn[0] == 0x0F && insn[1] == 0xFB) {
11729 delta = dis_SSEint_E_to_G( pfx, delta+2,
11730 "psubq", Iop_Sub64x2, False );
11731 goto decode_success;
11732 }
11733
sewardj97628592005-05-10 22:42:54 +000011734 /* 66 0F F9 = PSUBW */
11735 if (have66noF2noF3(pfx) && sz == 2
11736 && insn[0] == 0x0F && insn[1] == 0xF9) {
11737 delta = dis_SSEint_E_to_G( pfx, delta+2,
11738 "psubw", Iop_Sub16x8, False );
11739 goto decode_success;
11740 }
11741
11742 /* 66 0F E8 = PSUBSB */
11743 if (have66noF2noF3(pfx) && sz == 2
11744 && insn[0] == 0x0F && insn[1] == 0xE8) {
11745 delta = dis_SSEint_E_to_G( pfx, delta+2,
11746 "psubsb", Iop_QSub8Sx16, False );
11747 goto decode_success;
11748 }
11749
11750 /* 66 0F E9 = PSUBSW */
11751 if (have66noF2noF3(pfx) && sz == 2
11752 && insn[0] == 0x0F && insn[1] == 0xE9) {
11753 delta = dis_SSEint_E_to_G( pfx, delta+2,
11754 "psubsw", Iop_QSub16Sx8, False );
11755 goto decode_success;
11756 }
11757
11758 /* 66 0F D8 = PSUBSB */
11759 if (have66noF2noF3(pfx) && sz == 2
11760 && insn[0] == 0x0F && insn[1] == 0xD8) {
11761 delta = dis_SSEint_E_to_G( pfx, delta+2,
11762 "psubusb", Iop_QSub8Ux16, False );
11763 goto decode_success;
11764 }
11765
11766 /* 66 0F D9 = PSUBSW */
11767 if (have66noF2noF3(pfx) && sz == 2
11768 && insn[0] == 0x0F && insn[1] == 0xD9) {
11769 delta = dis_SSEint_E_to_G( pfx, delta+2,
11770 "psubusw", Iop_QSub16Ux8, False );
11771 goto decode_success;
11772 }
11773
11774 /* 66 0F 68 = PUNPCKHBW */
11775 if (have66noF2noF3(pfx) && sz == 2
11776 && insn[0] == 0x0F && insn[1] == 0x68) {
11777 delta = dis_SSEint_E_to_G( pfx, delta+2,
11778 "punpckhbw",
11779 Iop_InterleaveHI8x16, True );
11780 goto decode_success;
11781 }
11782
11783 /* 66 0F 6A = PUNPCKHDQ */
11784 if (have66noF2noF3(pfx) && sz == 2
11785 && insn[0] == 0x0F && insn[1] == 0x6A) {
11786 delta = dis_SSEint_E_to_G( pfx, delta+2,
11787 "punpckhdq",
11788 Iop_InterleaveHI32x4, True );
11789 goto decode_success;
11790 }
11791
11792 /* 66 0F 6D = PUNPCKHQDQ */
11793 if (have66noF2noF3(pfx) && sz == 2
11794 && insn[0] == 0x0F && insn[1] == 0x6D) {
11795 delta = dis_SSEint_E_to_G( pfx, delta+2,
11796 "punpckhqdq",
11797 Iop_InterleaveHI64x2, True );
11798 goto decode_success;
11799 }
11800
11801 /* 66 0F 69 = PUNPCKHWD */
11802 if (have66noF2noF3(pfx) && sz == 2
11803 && insn[0] == 0x0F && insn[1] == 0x69) {
11804 delta = dis_SSEint_E_to_G( pfx, delta+2,
11805 "punpckhwd",
11806 Iop_InterleaveHI16x8, True );
11807 goto decode_success;
11808 }
11809
11810 /* 66 0F 60 = PUNPCKLBW */
11811 if (have66noF2noF3(pfx) && sz == 2
11812 && insn[0] == 0x0F && insn[1] == 0x60) {
11813 delta = dis_SSEint_E_to_G( pfx, delta+2,
11814 "punpcklbw",
11815 Iop_InterleaveLO8x16, True );
11816 goto decode_success;
11817 }
11818
11819 /* 66 0F 62 = PUNPCKLDQ */
11820 if (have66noF2noF3(pfx) && sz == 2
11821 && insn[0] == 0x0F && insn[1] == 0x62) {
11822 delta = dis_SSEint_E_to_G( pfx, delta+2,
11823 "punpckldq",
11824 Iop_InterleaveLO32x4, True );
11825 goto decode_success;
11826 }
11827
11828 /* 66 0F 6C = PUNPCKLQDQ */
11829 if (have66noF2noF3(pfx) && sz == 2
11830 && insn[0] == 0x0F && insn[1] == 0x6C) {
11831 delta = dis_SSEint_E_to_G( pfx, delta+2,
11832 "punpcklqdq",
11833 Iop_InterleaveLO64x2, True );
11834 goto decode_success;
11835 }
11836
11837 /* 66 0F 61 = PUNPCKLWD */
11838 if (have66noF2noF3(pfx) && sz == 2
11839 && insn[0] == 0x0F && insn[1] == 0x61) {
11840 delta = dis_SSEint_E_to_G( pfx, delta+2,
11841 "punpcklwd",
11842 Iop_InterleaveLO16x8, True );
11843 goto decode_success;
11844 }
sewardj09717342005-05-05 21:34:02 +000011845
11846 /* 66 0F EF = PXOR */
11847 if (have66noF2noF3(pfx) && sz == 2
11848 && insn[0] == 0x0F && insn[1] == 0xEF) {
11849 delta = dis_SSE_E_to_G_all( pfx, delta+2, "pxor", Iop_XorV128 );
11850 goto decode_success;
11851 }
11852
sewardjd20c8852005-01-20 20:04:07 +000011853//.. //-- /* FXSAVE/FXRSTOR m32 -- load/store the FPU/MMX/SSE state. */
11854//.. //-- if (insn[0] == 0x0F && insn[1] == 0xAE
11855//.. //-- && (!epartIsReg(insn[2]))
11856//.. //-- && (gregOfRM(insn[2]) == 1 || gregOfRM(insn[2]) == 0) ) {
11857//.. //-- Bool store = gregOfRM(insn[2]) == 0;
11858//.. //-- vg_assert(sz == 4);
11859//.. //-- pair = disAMode ( cb, sorb, eip+2, dis_buf );
11860//.. //-- t1 = LOW24(pair);
11861//.. //-- eip += 2+HI8(pair);
11862//.. //-- uInstr3(cb, store ? SSE2a_MemWr : SSE2a_MemRd, 512,
11863//.. //-- Lit16, (((UShort)insn[0]) << 8) | (UShort)insn[1],
11864//.. //-- Lit16, (UShort)insn[2],
11865//.. //-- TempReg, t1 );
11866//.. //-- DIP("fx%s %s\n", store ? "save" : "rstor", dis_buf );
11867//.. //-- goto decode_success;
11868//.. //-- }
sewardj3e616e62006-01-07 22:58:54 +000011869
11870 /* 0F AE /7 = CLFLUSH -- flush cache line */
11871 if (haveNo66noF2noF3(pfx) && sz == 4
11872 && insn[0] == 0x0F && insn[1] == 0xAE
11873 && !epartIsReg(insn[2]) && gregLO3ofRM(insn[2]) == 7) {
11874
11875 /* This is something of a hack. We need to know the size of the
11876 cache line containing addr. Since we don't (easily), assume
11877 256 on the basis that no real cache would have a line that
11878 big. It's safe to invalidate more stuff than we need, just
11879 inefficient. */
11880 ULong lineszB = 256ULL;
11881
11882 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
11883 delta += 2+alen;
11884
11885 /* Round addr down to the start of the containing block. */
11886 stmt( IRStmt_Put(
11887 OFFB_TISTART,
11888 binop( Iop_And64,
11889 mkexpr(addr),
11890 mkU64( ~(lineszB-1) ))) );
11891
11892 stmt( IRStmt_Put(OFFB_TILEN, mkU64(lineszB) ) );
11893
11894 irbb->jumpkind = Ijk_TInval;
11895 irbb->next = mkU64(guest_RIP_bbstart+delta);
11896 dres.whatNext = Dis_StopHere;
11897
11898 DIP("clflush %s\n", dis_buf);
11899 goto decode_success;
11900 }
sewardjdf0e0022005-01-25 15:48:43 +000011901
sewardjdf0e0022005-01-25 15:48:43 +000011902 /* ---------------------------------------------------- */
11903 /* --- end of the SSE/SSE2 decoder. --- */
11904 /* ---------------------------------------------------- */
11905
sewardjfcf21f32006-08-04 14:51:19 +000011906 /* ---------------------------------------------------- */
11907 /* --- start of the SSE3 decoder. --- */
11908 /* ---------------------------------------------------- */
11909
11910 /* F3 0F 12 = MOVSLDUP -- move from E (mem or xmm) to G (xmm),
11911 duplicating some lanes (2:2:0:0). */
11912 /* F3 0F 16 = MOVSHDUP -- move from E (mem or xmm) to G (xmm),
11913 duplicating some lanes (3:3:1:1). */
11914 if (haveF3no66noF2(pfx) && sz == 4
11915 && insn[0] == 0x0F && (insn[1] == 0x12 || insn[1] == 0x16)) {
11916 IRTemp s3, s2, s1, s0;
11917 IRTemp sV = newTemp(Ity_V128);
11918 Bool isH = insn[1] == 0x16;
11919 s3 = s2 = s1 = s0 = IRTemp_INVALID;
11920
11921 modrm = insn[2];
11922 if (epartIsReg(modrm)) {
11923 assign( sV, getXMMReg( eregOfRexRM(pfx,modrm)) );
11924 DIP("movs%cdup %s,%s\n", isH ? 'h' : 'l',
11925 nameXMMReg(eregOfRexRM(pfx,modrm)),
11926 nameXMMReg(gregOfRexRM(pfx,modrm)));
11927 delta += 2+1;
11928 } else {
11929 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
11930 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
11931 DIP("movs%cdup %s,%s\n", isH ? 'h' : 'l',
11932 dis_buf,
11933 nameXMMReg(gregOfRexRM(pfx,modrm)));
11934 delta += 2+alen;
11935 }
11936
11937 breakup128to32s( sV, &s3, &s2, &s1, &s0 );
11938 putXMMReg( gregOfRexRM(pfx,modrm),
11939 isH ? mk128from32s( s3, s3, s1, s1 )
11940 : mk128from32s( s2, s2, s0, s0 ) );
11941 goto decode_success;
11942 }
11943
11944 /* F2 0F 12 = MOVDDUP -- move from E (mem or xmm) to G (xmm),
11945 duplicating some lanes (0:1:0:1). */
11946 if (haveF2no66noF3(pfx) && sz == 4
11947 && insn[0] == 0x0F && insn[1] == 0x12) {
11948 IRTemp sV = newTemp(Ity_V128);
11949 IRTemp d0 = newTemp(Ity_I64);
11950
11951 modrm = insn[2];
11952 if (epartIsReg(modrm)) {
11953 assign( sV, getXMMReg( eregOfRexRM(pfx,modrm)) );
11954 DIP("movddup %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
11955 nameXMMReg(gregOfRexRM(pfx,modrm)));
11956 delta += 2+1;
11957 assign ( d0, unop(Iop_V128to64, mkexpr(sV)) );
11958 } else {
11959 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
11960 assign( d0, loadLE(Ity_I64, mkexpr(addr)) );
11961 DIP("movddup %s,%s\n", dis_buf,
11962 nameXMMReg(gregOfRexRM(pfx,modrm)));
11963 delta += 2+alen;
11964 }
11965
11966 putXMMReg( gregOfRexRM(pfx,modrm),
11967 binop(Iop_64HLtoV128,mkexpr(d0),mkexpr(d0)) );
11968 goto decode_success;
11969 }
11970
11971 /* F2 0F D0 = ADDSUBPS -- 32x4 +/-/+/- from E (mem or xmm) to G (xmm). */
11972 if (haveF2no66noF3(pfx) && sz == 4
11973 && insn[0] == 0x0F && insn[1] == 0xD0) {
11974 IRTemp a3, a2, a1, a0, s3, s2, s1, s0;
11975 IRTemp eV = newTemp(Ity_V128);
11976 IRTemp gV = newTemp(Ity_V128);
11977 IRTemp addV = newTemp(Ity_V128);
11978 IRTemp subV = newTemp(Ity_V128);
11979 a3 = a2 = a1 = a0 = s3 = s2 = s1 = s0 = IRTemp_INVALID;
11980
11981 modrm = insn[2];
11982 if (epartIsReg(modrm)) {
11983 assign( eV, getXMMReg( eregOfRexRM(pfx,modrm)) );
11984 DIP("addsubps %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
11985 nameXMMReg(gregOfRexRM(pfx,modrm)));
11986 delta += 2+1;
11987 } else {
11988 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
11989 assign( eV, loadLE(Ity_V128, mkexpr(addr)) );
11990 DIP("addsubps %s,%s\n", dis_buf,
11991 nameXMMReg(gregOfRexRM(pfx,modrm)));
11992 delta += 2+alen;
11993 }
11994
11995 assign( gV, getXMMReg(gregOfRexRM(pfx,modrm)) );
11996
11997 assign( addV, binop(Iop_Add32Fx4, mkexpr(gV), mkexpr(eV)) );
11998 assign( subV, binop(Iop_Sub32Fx4, mkexpr(gV), mkexpr(eV)) );
11999
12000 breakup128to32s( addV, &a3, &a2, &a1, &a0 );
12001 breakup128to32s( subV, &s3, &s2, &s1, &s0 );
12002
12003 putXMMReg( gregOfRexRM(pfx,modrm), mk128from32s( a3, s2, a1, s0 ));
12004 goto decode_success;
12005 }
12006
12007 /* 66 0F D0 = ADDSUBPD -- 64x4 +/- from E (mem or xmm) to G (xmm). */
12008 if (have66noF2noF3(pfx) && sz == 2
12009 && insn[0] == 0x0F && insn[1] == 0xD0) {
12010 IRTemp eV = newTemp(Ity_V128);
12011 IRTemp gV = newTemp(Ity_V128);
12012 IRTemp addV = newTemp(Ity_V128);
12013 IRTemp subV = newTemp(Ity_V128);
12014 IRTemp a1 = newTemp(Ity_I64);
12015 IRTemp s0 = newTemp(Ity_I64);
12016
12017 modrm = insn[2];
12018 if (epartIsReg(modrm)) {
12019 assign( eV, getXMMReg( eregOfRexRM(pfx,modrm)) );
12020 DIP("addsubpd %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
12021 nameXMMReg(gregOfRexRM(pfx,modrm)));
12022 delta += 2+1;
12023 } else {
12024 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
12025 assign( eV, loadLE(Ity_V128, mkexpr(addr)) );
12026 DIP("addsubpd %s,%s\n", dis_buf,
12027 nameXMMReg(gregOfRexRM(pfx,modrm)));
12028 delta += 2+alen;
12029 }
12030
12031 assign( gV, getXMMReg(gregOfRexRM(pfx,modrm)) );
12032
12033 assign( addV, binop(Iop_Add64Fx2, mkexpr(gV), mkexpr(eV)) );
12034 assign( subV, binop(Iop_Sub64Fx2, mkexpr(gV), mkexpr(eV)) );
12035
12036 assign( a1, unop(Iop_V128HIto64, mkexpr(addV) ));
12037 assign( s0, unop(Iop_V128to64, mkexpr(subV) ));
12038
12039 putXMMReg( gregOfRexRM(pfx,modrm),
12040 binop(Iop_64HLtoV128, mkexpr(a1), mkexpr(s0)) );
12041 goto decode_success;
12042 }
12043
12044 /* F2 0F 7D = HSUBPS -- 32x4 sub across from E (mem or xmm) to G (xmm). */
12045 /* F2 0F 7C = HADDPS -- 32x4 add across from E (mem or xmm) to G (xmm). */
12046 if (haveF2no66noF3(pfx) && sz == 4
12047 && insn[0] == 0x0F && (insn[1] == 0x7C || insn[1] == 0x7D)) {
12048 IRTemp e3, e2, e1, e0, g3, g2, g1, g0;
12049 IRTemp eV = newTemp(Ity_V128);
12050 IRTemp gV = newTemp(Ity_V128);
12051 IRTemp leftV = newTemp(Ity_V128);
12052 IRTemp rightV = newTemp(Ity_V128);
12053 Bool isAdd = insn[1] == 0x7C;
12054 HChar* str = isAdd ? "add" : "sub";
12055 e3 = e2 = e1 = e0 = g3 = g2 = g1 = g0 = IRTemp_INVALID;
12056
12057 modrm = insn[2];
12058 if (epartIsReg(modrm)) {
12059 assign( eV, getXMMReg( eregOfRexRM(pfx,modrm)) );
12060 DIP("h%sps %s,%s\n", str, nameXMMReg(eregOfRexRM(pfx,modrm)),
12061 nameXMMReg(gregOfRexRM(pfx,modrm)));
12062 delta += 2+1;
12063 } else {
12064 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
12065 assign( eV, loadLE(Ity_V128, mkexpr(addr)) );
12066 DIP("h%sps %s,%s\n", str, dis_buf,
12067 nameXMMReg(gregOfRexRM(pfx,modrm)));
12068 delta += 2+alen;
12069 }
12070
12071 assign( gV, getXMMReg(gregOfRexRM(pfx,modrm)) );
12072
12073 breakup128to32s( eV, &e3, &e2, &e1, &e0 );
12074 breakup128to32s( gV, &g3, &g2, &g1, &g0 );
12075
12076 assign( leftV, mk128from32s( e2, e0, g2, g0 ) );
12077 assign( rightV, mk128from32s( e3, e1, g3, g1 ) );
12078
12079 putXMMReg( gregOfRexRM(pfx,modrm),
12080 binop(isAdd ? Iop_Add32Fx4 : Iop_Sub32Fx4,
12081 mkexpr(leftV), mkexpr(rightV) ) );
12082 goto decode_success;
12083 }
12084
12085 /* 66 0F 7D = HSUBPD -- 64x2 sub across from E (mem or xmm) to G (xmm). */
12086 /* 66 0F 7C = HADDPD -- 64x2 add across from E (mem or xmm) to G (xmm). */
12087 if (have66noF2noF3(pfx) && sz == 2
12088 && insn[0] == 0x0F && (insn[1] == 0x7C || insn[1] == 0x7D)) {
12089 IRTemp e1 = newTemp(Ity_I64);
12090 IRTemp e0 = newTemp(Ity_I64);
12091 IRTemp g1 = newTemp(Ity_I64);
12092 IRTemp g0 = newTemp(Ity_I64);
12093 IRTemp eV = newTemp(Ity_V128);
12094 IRTemp gV = newTemp(Ity_V128);
12095 IRTemp leftV = newTemp(Ity_V128);
12096 IRTemp rightV = newTemp(Ity_V128);
12097 Bool isAdd = insn[1] == 0x7C;
12098 HChar* str = isAdd ? "add" : "sub";
12099
12100 modrm = insn[2];
12101 if (epartIsReg(modrm)) {
12102 assign( eV, getXMMReg( eregOfRexRM(pfx,modrm)) );
12103 DIP("h%spd %s,%s\n", str, nameXMMReg(eregOfRexRM(pfx,modrm)),
12104 nameXMMReg(gregOfRexRM(pfx,modrm)));
12105 delta += 2+1;
12106 } else {
12107 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
12108 assign( eV, loadLE(Ity_V128, mkexpr(addr)) );
12109 DIP("h%spd %s,%s\n", str, dis_buf,
12110 nameXMMReg(gregOfRexRM(pfx,modrm)));
12111 delta += 2+alen;
12112 }
12113
12114 assign( gV, getXMMReg(gregOfRexRM(pfx,modrm)) );
12115
12116 assign( e1, unop(Iop_V128HIto64, mkexpr(eV) ));
12117 assign( e0, unop(Iop_V128to64, mkexpr(eV) ));
12118 assign( g1, unop(Iop_V128HIto64, mkexpr(gV) ));
12119 assign( g0, unop(Iop_V128to64, mkexpr(gV) ));
12120
12121 assign( leftV, binop(Iop_64HLtoV128, mkexpr(e0),mkexpr(g0)) );
12122 assign( rightV, binop(Iop_64HLtoV128, mkexpr(e1),mkexpr(g1)) );
12123
12124 putXMMReg( gregOfRexRM(pfx,modrm),
12125 binop(isAdd ? Iop_Add64Fx2 : Iop_Sub64Fx2,
12126 mkexpr(leftV), mkexpr(rightV) ) );
12127 goto decode_success;
12128 }
12129
12130 /* F2 0F F0 = LDDQU -- move from E (mem or xmm) to G (xmm). */
12131 if (haveF2no66noF3(pfx) && sz == 4
12132 && insn[0] == 0x0F && insn[1] == 0xF0) {
12133 modrm = insn[2];
12134 if (epartIsReg(modrm)) {
12135 goto decode_failure;
12136 } else {
12137 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
12138 putXMMReg( gregOfRexRM(pfx,modrm),
12139 loadLE(Ity_V128, mkexpr(addr)) );
12140 DIP("lddqu %s,%s\n", dis_buf,
12141 nameXMMReg(gregOfRexRM(pfx,modrm)));
12142 delta += 2+alen;
12143 }
12144 goto decode_success;
12145 }
12146
12147 /* ---------------------------------------------------- */
12148 /* --- end of the SSE3 decoder. --- */
12149 /* ---------------------------------------------------- */
12150
sewardj7a240552005-01-28 21:37:12 +000012151 /*after_sse_decoders:*/
sewardjdf0e0022005-01-25 15:48:43 +000012152
12153 /* Get the primary opcode. */
sewardj8c332e22005-01-28 01:36:56 +000012154 opc = getUChar(delta); delta++;
sewardjdf0e0022005-01-25 15:48:43 +000012155
12156 /* We get here if the current insn isn't SSE, or this CPU doesn't
12157 support SSE. */
12158
12159 switch (opc) {
12160
12161 /* ------------------------ Control flow --------------- */
12162
sewardjd20c8852005-01-20 20:04:07 +000012163//.. case 0xC2: /* RET imm16 */
12164//.. d32 = getUDisp16(delta);
12165//.. delta += 2;
12166//.. dis_ret(d32);
12167//.. whatNext = Dis_StopHere;
12168//.. DIP("ret %d\n", d32);
12169//.. break;
sewardj2f959cc2005-01-26 01:19:35 +000012170 case 0xC3: /* RET */
sewardj55dbb262005-01-28 16:36:51 +000012171 if (haveF2(pfx)) goto decode_failure;
12172 /* F3 is acceptable on AMD. */
sewardj2f959cc2005-01-26 01:19:35 +000012173 dis_ret(0);
sewardj9e6491a2005-07-02 19:24:10 +000012174 dres.whatNext = Dis_StopHere;
sewardje941eea2005-01-30 19:52:28 +000012175 DIP(haveF3(pfx) ? "rep ; ret\n" : "ret\n");
sewardj2f959cc2005-01-26 01:19:35 +000012176 break;
12177
sewardj3ca55a12005-01-27 16:06:23 +000012178 case 0xE8: /* CALL J4 */
12179 if (haveF2orF3(pfx)) goto decode_failure;
12180 d64 = getSDisp32(delta); delta += 4;
sewardj9e6491a2005-07-02 19:24:10 +000012181 d64 += (guest_RIP_bbstart+delta);
12182 /* (guest_RIP_bbstart+delta) == return-to addr, d64 == call-to addr */
sewardj3ca55a12005-01-27 16:06:23 +000012183 t1 = newTemp(Ity_I64);
12184 assign(t1, binop(Iop_Sub64, getIReg64(R_RSP), mkU64(8)));
12185 putIReg64(R_RSP, mkexpr(t1));
sewardj9e6491a2005-07-02 19:24:10 +000012186 storeLE( mkexpr(t1), mkU64(guest_RIP_bbstart+delta));
sewardj5a9ffab2005-05-12 17:55:01 +000012187 make_redzone_AbiHint(t1, "call-d32");
sewardjc716aea2006-01-17 01:48:46 +000012188 if (resteerOkFn( callback_opaque, (Addr64)d64) ) {
sewardj3ca55a12005-01-27 16:06:23 +000012189 /* follow into the call target. */
sewardj9e6491a2005-07-02 19:24:10 +000012190 dres.whatNext = Dis_Resteer;
12191 dres.continueAt = d64;
sewardj3ca55a12005-01-27 16:06:23 +000012192 } else {
12193 jmp_lit(Ijk_Call,d64);
sewardj9e6491a2005-07-02 19:24:10 +000012194 dres.whatNext = Dis_StopHere;
sewardj3ca55a12005-01-27 16:06:23 +000012195 }
12196 DIP("call 0x%llx\n",d64);
12197 break;
12198
sewardjd20c8852005-01-20 20:04:07 +000012199//.. //-- case 0xC8: /* ENTER */
12200//.. //-- d32 = getUDisp16(eip); eip += 2;
sewardj8c332e22005-01-28 01:36:56 +000012201//.. //-- abyte = getUChar(delta); delta++;
sewardjd20c8852005-01-20 20:04:07 +000012202//.. //--
12203//.. //-- vg_assert(sz == 4);
12204//.. //-- vg_assert(abyte == 0);
12205//.. //--
12206//.. //-- t1 = newTemp(cb); t2 = newTemp(cb);
12207//.. //-- uInstr2(cb, GET, sz, ArchReg, R_EBP, TempReg, t1);
12208//.. //-- uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t2);
12209//.. //-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
12210//.. //-- uLiteral(cb, sz);
12211//.. //-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
12212//.. //-- uInstr2(cb, STORE, 4, TempReg, t1, TempReg, t2);
12213//.. //-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_EBP);
12214//.. //-- if (d32) {
12215//.. //-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
12216//.. //-- uLiteral(cb, d32);
12217//.. //-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
12218//.. //-- }
12219//.. //-- DIP("enter 0x%x, 0x%x", d32, abyte);
12220//.. //-- break;
sewardje1698952005-02-08 15:02:39 +000012221
12222 case 0xC9: /* LEAVE */
12223 /* In 64-bit mode this defaults to a 64-bit operand size. There
12224 is no way to encode a 32-bit variant. Hence sz==4 but we do
12225 it as if sz=8. */
12226 if (sz != 4)
12227 goto decode_failure;
12228 t1 = newTemp(Ity_I64);
12229 t2 = newTemp(Ity_I64);
12230 assign(t1, getIReg64(R_RBP));
12231 /* First PUT RSP looks redundant, but need it because RSP must
12232 always be up-to-date for Memcheck to work... */
12233 putIReg64(R_RSP, mkexpr(t1));
12234 assign(t2, loadLE(Ity_I64,mkexpr(t1)));
12235 putIReg64(R_RBP, mkexpr(t2));
12236 putIReg64(R_RSP, binop(Iop_Add64, mkexpr(t1), mkU64(8)) );
12237 DIP("leave\n");
12238 break;
12239
sewardjd20c8852005-01-20 20:04:07 +000012240//.. //-- /* ---------------- Misc weird-ass insns --------------- */
12241//.. //--
12242//.. //-- case 0x27: /* DAA */
12243//.. //-- case 0x2F: /* DAS */
12244//.. //-- t1 = newTemp(cb);
12245//.. //-- uInstr2(cb, GET, 1, ArchReg, R_AL, TempReg, t1);
12246//.. //-- /* Widen %AL to 32 bits, so it's all defined when we push it. */
12247//.. //-- uInstr1(cb, WIDEN, 4, TempReg, t1);
12248//.. //-- uWiden(cb, 1, False);
12249//.. //-- uInstr0(cb, CALLM_S, 0);
12250//.. //-- uInstr1(cb, PUSH, 4, TempReg, t1);
12251//.. //-- uInstr1(cb, CALLM, 0, Lit16,
12252//.. //-- opc == 0x27 ? VGOFF_(helper_DAA) : VGOFF_(helper_DAS) );
12253//.. //-- uFlagsRWU(cb, FlagsAC, FlagsSZACP, FlagO);
12254//.. //-- uInstr1(cb, POP, 4, TempReg, t1);
12255//.. //-- uInstr0(cb, CALLM_E, 0);
12256//.. //-- uInstr2(cb, PUT, 1, TempReg, t1, ArchReg, R_AL);
12257//.. //-- DIP(opc == 0x27 ? "daa\n" : "das\n");
12258//.. //-- break;
12259//.. //--
12260//.. //-- case 0x37: /* AAA */
12261//.. //-- case 0x3F: /* AAS */
12262//.. //-- t1 = newTemp(cb);
12263//.. //-- uInstr2(cb, GET, 2, ArchReg, R_EAX, TempReg, t1);
12264//.. //-- /* Widen %AL to 32 bits, so it's all defined when we push it. */
12265//.. //-- uInstr1(cb, WIDEN, 4, TempReg, t1);
12266//.. //-- uWiden(cb, 2, False);
12267//.. //-- uInstr0(cb, CALLM_S, 0);
12268//.. //-- uInstr1(cb, PUSH, 4, TempReg, t1);
12269//.. //-- uInstr1(cb, CALLM, 0, Lit16,
12270//.. //-- opc == 0x37 ? VGOFF_(helper_AAA) : VGOFF_(helper_AAS) );
12271//.. //-- uFlagsRWU(cb, FlagA, FlagsAC, FlagsEmpty);
12272//.. //-- uInstr1(cb, POP, 4, TempReg, t1);
12273//.. //-- uInstr0(cb, CALLM_E, 0);
12274//.. //-- uInstr2(cb, PUT, 2, TempReg, t1, ArchReg, R_EAX);
12275//.. //-- DIP(opc == 0x37 ? "aaa\n" : "aas\n");
12276//.. //-- break;
12277//.. //--
12278//.. //-- case 0xD4: /* AAM */
12279//.. //-- case 0xD5: /* AAD */
sewardj8c332e22005-01-28 01:36:56 +000012280//.. //-- d32 = getUChar(delta); delta++;
sewardjd20c8852005-01-20 20:04:07 +000012281//.. //-- if (d32 != 10) VG_(core_panic)("disInstr: AAM/AAD but base not 10 !");
12282//.. //-- t1 = newTemp(cb);
12283//.. //-- uInstr2(cb, GET, 2, ArchReg, R_EAX, TempReg, t1);
12284//.. //-- /* Widen %AX to 32 bits, so it's all defined when we push it. */
12285//.. //-- uInstr1(cb, WIDEN, 4, TempReg, t1);
12286//.. //-- uWiden(cb, 2, False);
12287//.. //-- uInstr0(cb, CALLM_S, 0);
12288//.. //-- uInstr1(cb, PUSH, 4, TempReg, t1);
12289//.. //-- uInstr1(cb, CALLM, 0, Lit16,
12290//.. //-- opc == 0xD4 ? VGOFF_(helper_AAM) : VGOFF_(helper_AAD) );
12291//.. //-- uFlagsRWU(cb, FlagsEmpty, FlagsSZP, FlagsEmpty);
12292//.. //-- uInstr1(cb, POP, 4, TempReg, t1);
12293//.. //-- uInstr0(cb, CALLM_E, 0);
12294//.. //-- uInstr2(cb, PUT, 2, TempReg, t1, ArchReg, R_EAX);
12295//.. //-- DIP(opc == 0xD4 ? "aam\n" : "aad\n");
12296//.. //-- break;
sewardj3ca55a12005-01-27 16:06:23 +000012297
12298 /* ------------------------ CWD/CDQ -------------------- */
12299
12300 case 0x98: /* CBW */
12301 if (haveF2orF3(pfx)) goto decode_failure;
12302 if (sz == 8) {
sewardj5b470602005-02-27 13:10:48 +000012303 putIRegRAX( 8, unop(Iop_32Sto64, getIRegRAX(4)) );
sewardje941eea2005-01-30 19:52:28 +000012304 DIP(/*"cdqe\n"*/"cltq");
12305 break;
12306 }
sewardj3ca55a12005-01-27 16:06:23 +000012307 if (sz == 4) {
sewardj5b470602005-02-27 13:10:48 +000012308 putIRegRAX( 4, unop(Iop_16Sto32, getIRegRAX(2)) );
sewardj7eaa7cf2005-01-31 18:55:22 +000012309 DIP("cwtl\n");
sewardje941eea2005-01-30 19:52:28 +000012310 break;
12311 }
sewardj3ca55a12005-01-27 16:06:23 +000012312 if (sz == 2) {
sewardj5b470602005-02-27 13:10:48 +000012313 putIRegRAX( 2, unop(Iop_8Sto16, getIRegRAX(1)) );
sewardj3ca55a12005-01-27 16:06:23 +000012314 DIP("cbw\n");
sewardj7bc00082005-03-27 05:08:32 +000012315 break;
sewardj3ca55a12005-01-27 16:06:23 +000012316 }
sewardje941eea2005-01-30 19:52:28 +000012317 goto decode_failure;
sewardj3ca55a12005-01-27 16:06:23 +000012318
12319 case 0x99: /* CWD/CDQ/CQO */
12320 if (haveF2orF3(pfx)) goto decode_failure;
12321 vassert(sz == 2 || sz == 4 || sz == 8);
12322 ty = szToITy(sz);
sewardj5b470602005-02-27 13:10:48 +000012323 putIRegRDX( sz,
12324 binop(mkSizedOp(ty,Iop_Sar8),
12325 getIRegRAX(sz),
12326 mkU8(sz == 2 ? 15 : (sz == 4 ? 31 : 63))) );
sewardje941eea2005-01-30 19:52:28 +000012327 DIP(sz == 2 ? "cwd\n"
sewardj5b470602005-02-27 13:10:48 +000012328 : (sz == 4 ? /*"cdq\n"*/ "cltd\n"
12329 : "cqo\n"));
sewardj3ca55a12005-01-27 16:06:23 +000012330 break;
12331
sewardj8d965312005-02-25 02:48:47 +000012332 /* ------------------------ FPU ops -------------------- */
12333
sewardjd20c8852005-01-20 20:04:07 +000012334//.. case 0x9E: /* SAHF */
12335//.. codegen_SAHF();
12336//.. DIP("sahf\n");
12337//.. break;
12338//..
12339//.. //-- case 0x9F: /* LAHF */
12340//.. //-- codegen_LAHF ( cb );
12341//.. //-- DIP("lahf\n");
12342//.. //-- break;
12343//.. //--
sewardj6847d8c2005-05-12 19:21:55 +000012344 case 0x9B: /* FWAIT */
12345 /* ignore? */
12346 DIP("fwait\n");
12347 break;
sewardj8d965312005-02-25 02:48:47 +000012348
12349 case 0xD8:
12350 case 0xD9:
12351 case 0xDA:
12352 case 0xDB:
12353 case 0xDC:
12354 case 0xDD:
12355 case 0xDE:
12356 case 0xDF:
sewardj5b470602005-02-27 13:10:48 +000012357 if (haveF2orF3(pfx)) goto decode_failure;
sewardj8d965312005-02-25 02:48:47 +000012358 if (sz == 4 && haveNo66noF2noF3(pfx)) {
sewardj270def42005-07-03 01:03:01 +000012359 Long delta0 = delta;
12360 Bool decode_OK = False;
sewardj8d965312005-02-25 02:48:47 +000012361 delta = dis_FPU ( &decode_OK, pfx, delta );
12362 if (!decode_OK) {
12363 delta = delta0;
12364 goto decode_failure;
12365 }
12366 break;
12367 } else {
12368 goto decode_failure;
12369 }
12370
sewardj4fa325a2005-11-03 13:27:24 +000012371 /* ------------------------ INT ------------------------ */
12372
12373 case 0xCD: { /* INT imm8 */
12374 IRJumpKind jk = Ijk_Boring;
12375 if (have66orF2orF3(pfx)) goto decode_failure;
12376 d64 = getUChar(delta); delta++;
12377 switch (d64) {
12378 case 32: jk = Ijk_Sys_int32; break;
12379 default: goto decode_failure;
12380 }
12381 guest_RIP_next_mustcheck = True;
12382 guest_RIP_next_assumed = guest_RIP_bbstart + delta;
12383 jmp_lit(jk, guest_RIP_next_assumed);
12384 /* It's important that all ArchRegs carry their up-to-date value
12385 at this point. So we declare an end-of-block here, which
12386 forces any TempRegs caching ArchRegs to be flushed. */
12387 dres.whatNext = Dis_StopHere;
12388 DIP("int $0x%02x\n", (UInt)d64);
12389 break;
12390 }
12391
sewardjf8c37f72005-02-07 18:55:29 +000012392 /* ------------------------ Jcond, byte offset --------- */
12393
12394 case 0xEB: /* Jb (jump, byte offset) */
sewardj5b470602005-02-27 13:10:48 +000012395 if (haveF2orF3(pfx)) goto decode_failure;
sewardjf8c37f72005-02-07 18:55:29 +000012396 if (sz != 4)
12397 goto decode_failure; /* JRS added 2004 July 11 */
sewardj9e6491a2005-07-02 19:24:10 +000012398 d64 = (guest_RIP_bbstart+delta+1) + getSDisp8(delta);
sewardjf8c37f72005-02-07 18:55:29 +000012399 delta++;
sewardjc716aea2006-01-17 01:48:46 +000012400 if (resteerOkFn(callback_opaque,d64)) {
sewardj9e6491a2005-07-02 19:24:10 +000012401 dres.whatNext = Dis_Resteer;
12402 dres.continueAt = d64;
sewardjf8c37f72005-02-07 18:55:29 +000012403 } else {
12404 jmp_lit(Ijk_Boring,d64);
sewardj9e6491a2005-07-02 19:24:10 +000012405 dres.whatNext = Dis_StopHere;
sewardjf8c37f72005-02-07 18:55:29 +000012406 }
12407 DIP("jmp-8 0x%llx\n", d64);
12408 break;
sewardj1389d4d2005-01-28 13:46:29 +000012409
12410 case 0xE9: /* Jv (jump, 16/32 offset) */
sewardj5b470602005-02-27 13:10:48 +000012411 if (haveF2orF3(pfx)) goto decode_failure;
sewardjf8c37f72005-02-07 18:55:29 +000012412 if (sz != 4)
12413 goto decode_failure; /* JRS added 2004 July 11 */
sewardj9e6491a2005-07-02 19:24:10 +000012414 d64 = (guest_RIP_bbstart+delta+sz) + getSDisp(sz,delta);
sewardj1389d4d2005-01-28 13:46:29 +000012415 delta += sz;
sewardjc716aea2006-01-17 01:48:46 +000012416 if (resteerOkFn(callback_opaque,d64)) {
sewardj9e6491a2005-07-02 19:24:10 +000012417 dres.whatNext = Dis_Resteer;
12418 dres.continueAt = d64;
sewardj1389d4d2005-01-28 13:46:29 +000012419 } else {
12420 jmp_lit(Ijk_Boring,d64);
sewardj9e6491a2005-07-02 19:24:10 +000012421 dres.whatNext = Dis_StopHere;
sewardj1389d4d2005-01-28 13:46:29 +000012422 }
12423 DIP("jmp 0x%llx\n", d64);
12424 break;
12425
sewardjf8c37f72005-02-07 18:55:29 +000012426 case 0x70:
12427 case 0x71:
12428 case 0x72: /* JBb/JNAEb (jump below) */
12429 case 0x73: /* JNBb/JAEb (jump not below) */
12430 case 0x74: /* JZb/JEb (jump zero) */
12431 case 0x75: /* JNZb/JNEb (jump not zero) */
12432 case 0x76: /* JBEb/JNAb (jump below or equal) */
12433 case 0x77: /* JNBEb/JAb (jump not below or equal) */
12434 case 0x78: /* JSb (jump negative) */
12435 case 0x79: /* JSb (jump not negative) */
12436 case 0x7A: /* JP (jump parity even) */
12437 case 0x7B: /* JNP/JPO (jump parity odd) */
12438 case 0x7C: /* JLb/JNGEb (jump less) */
12439 case 0x7D: /* JGEb/JNLb (jump greater or equal) */
12440 case 0x7E: /* JLEb/JNGb (jump less or equal) */
12441 case 0x7F: /* JGb/JNLEb (jump greater) */
sewardj5b470602005-02-27 13:10:48 +000012442 if (haveF2orF3(pfx)) goto decode_failure;
sewardj9e6491a2005-07-02 19:24:10 +000012443 d64 = (guest_RIP_bbstart+delta+1) + getSDisp8(delta);
sewardjf8c37f72005-02-07 18:55:29 +000012444 delta++;
12445 jcc_01( (AMD64Condcode)(opc - 0x70),
sewardj9e6491a2005-07-02 19:24:10 +000012446 guest_RIP_bbstart+delta,
sewardjf8c37f72005-02-07 18:55:29 +000012447 d64 );
sewardj9e6491a2005-07-02 19:24:10 +000012448 dres.whatNext = Dis_StopHere;
sewardjf8c37f72005-02-07 18:55:29 +000012449 DIP("j%s-8 0x%llx\n", name_AMD64Condcode(opc - 0x70), d64);
12450 break;
12451
sewardjc01c1fa2005-11-04 14:34:52 +000012452 case 0xE3:
12453 /* JRCXZ or JECXZ, depending address size override. */
12454 if (have66orF2orF3(pfx)) goto decode_failure;
sewardjfdfa8862005-10-05 16:58:23 +000012455 d64 = (guest_RIP_bbstart+delta+1) + getSDisp8(delta);
12456 delta++;
sewardjc01c1fa2005-11-04 14:34:52 +000012457 if (haveASO(pfx)) {
12458 /* 32-bit */
12459 stmt( IRStmt_Exit( binop(Iop_CmpEQ64,
12460 unop(Iop_32Uto64, getIReg32(R_RCX)),
12461 mkU64(0)),
12462 Ijk_Boring,
12463 IRConst_U64(d64))
12464 );
12465 DIP("jecxz 0x%llx\n", d64);
12466 } else {
12467 /* 64-bit */
12468 stmt( IRStmt_Exit( binop(Iop_CmpEQ64,
12469 getIReg64(R_RCX),
12470 mkU64(0)),
12471 Ijk_Boring,
12472 IRConst_U64(d64))
12473 );
12474 DIP("jrcxz 0x%llx\n", d64);
12475 }
sewardjfdfa8862005-10-05 16:58:23 +000012476 break;
sewardj6359f812005-07-20 10:15:34 +000012477
sewardje8f65252005-08-23 23:44:35 +000012478 case 0xE0: /* LOOPNE disp8: decrement count, jump if count != 0 && ZF==0 */
12479 case 0xE1: /* LOOPE disp8: decrement count, jump if count != 0 && ZF==1 */
12480 case 0xE2: /* LOOP disp8: decrement count, jump if count != 0 */
12481 { /* The docs say this uses rCX as a count depending on the
12482 address size override, not the operand one. Since we don't
12483 handle address size overrides, I guess that means RCX. */
12484 IRExpr* zbit = NULL;
12485 IRExpr* count = NULL;
12486 IRExpr* cond = NULL;
12487 HChar* xtra = NULL;
12488
12489 if (have66orF2orF3(pfx) || haveASO(pfx)) goto decode_failure;
12490 d64 = guest_RIP_bbstart+delta+1 + getSDisp8(delta);
12491 delta++;
12492 putIReg64(R_RCX, binop(Iop_Sub64, getIReg64(R_RCX), mkU64(1)));
12493
12494 count = getIReg64(R_RCX);
12495 cond = binop(Iop_CmpNE64, count, mkU64(0));
12496 switch (opc) {
12497 case 0xE2:
12498 xtra = "";
12499 break;
12500 case 0xE1:
12501 xtra = "e";
12502 zbit = mk_amd64g_calculate_condition( AMD64CondZ );
12503 cond = mkAnd1(cond, zbit);
12504 break;
12505 case 0xE0:
12506 xtra = "ne";
12507 zbit = mk_amd64g_calculate_condition( AMD64CondNZ );
12508 cond = mkAnd1(cond, zbit);
12509 break;
12510 default:
12511 vassert(0);
12512 }
12513 stmt( IRStmt_Exit(cond, Ijk_Boring, IRConst_U64(d64)) );
12514
12515 DIP("loop%s 0x%llx\n", xtra, d64);
12516 break;
12517 }
sewardj32b2bbe2005-01-28 00:50:10 +000012518
12519 /* ------------------------ IMUL ----------------------- */
12520
12521 case 0x69: /* IMUL Iv, Ev, Gv */
sewardj5b470602005-02-27 13:10:48 +000012522 if (haveF2orF3(pfx)) goto decode_failure;
sewardj32b2bbe2005-01-28 00:50:10 +000012523 delta = dis_imul_I_E_G ( pfx, sz, delta, sz );
12524 break;
sewardj7de0d3c2005-02-13 02:26:41 +000012525 case 0x6B: /* IMUL Ib, Ev, Gv */
12526 delta = dis_imul_I_E_G ( pfx, sz, delta, 1 );
12527 break;
sewardj1389d4d2005-01-28 13:46:29 +000012528
12529 /* ------------------------ MOV ------------------------ */
12530
12531 case 0x88: /* MOV Gb,Eb */
sewardj5b470602005-02-27 13:10:48 +000012532 if (haveF2orF3(pfx)) goto decode_failure;
sewardj1389d4d2005-01-28 13:46:29 +000012533 delta = dis_mov_G_E(pfx, 1, delta);
12534 break;
12535
12536 case 0x89: /* MOV Gv,Ev */
sewardj5b470602005-02-27 13:10:48 +000012537 if (haveF2orF3(pfx)) goto decode_failure;
sewardj1389d4d2005-01-28 13:46:29 +000012538 delta = dis_mov_G_E(pfx, sz, delta);
12539 break;
12540
sewardjd0a12df2005-02-10 02:07:43 +000012541 case 0x8A: /* MOV Eb,Gb */
sewardj5b470602005-02-27 13:10:48 +000012542 if (haveF2orF3(pfx)) goto decode_failure;
sewardjd0a12df2005-02-10 02:07:43 +000012543 delta = dis_mov_E_G(pfx, 1, delta);
12544 break;
12545
sewardj1389d4d2005-01-28 13:46:29 +000012546 case 0x8B: /* MOV Ev,Gv */
sewardj5b470602005-02-27 13:10:48 +000012547 if (haveF2orF3(pfx)) goto decode_failure;
sewardj1389d4d2005-01-28 13:46:29 +000012548 delta = dis_mov_E_G(pfx, sz, delta);
12549 break;
12550
12551 case 0x8D: /* LEA M,Gv */
sewardj5b470602005-02-27 13:10:48 +000012552 if (haveF2orF3(pfx)) goto decode_failure;
sewardj1389d4d2005-01-28 13:46:29 +000012553 if (sz != 4 && sz != 8)
12554 goto decode_failure;
12555 modrm = getUChar(delta);
12556 if (epartIsReg(modrm))
12557 goto decode_failure;
12558 /* NOTE! this is the one place where a segment override prefix
12559 has no effect on the address calculation. Therefore we clear
12560 any segment override bits in pfx. */
sewardje1698952005-02-08 15:02:39 +000012561 addr = disAMode ( &alen, clearSegBits(pfx), delta, dis_buf, 0 );
sewardj1389d4d2005-01-28 13:46:29 +000012562 delta += alen;
12563 /* This is a hack. But it isn't clear that really doing the
12564 calculation at 32 bits is really worth it. Hence for leal,
12565 do the full 64-bit calculation and then truncate it. */
sewardj5b470602005-02-27 13:10:48 +000012566 putIRegG( sz, pfx, modrm,
sewardj1389d4d2005-01-28 13:46:29 +000012567 sz == 4
12568 ? unop(Iop_64to32, mkexpr(addr))
12569 : mkexpr(addr)
12570 );
12571 DIP("lea%c %s, %s\n", nameISize(sz), dis_buf,
sewardj5b470602005-02-27 13:10:48 +000012572 nameIRegG(sz,pfx,modrm));
sewardj1389d4d2005-01-28 13:46:29 +000012573 break;
12574
sewardjd20c8852005-01-20 20:04:07 +000012575//.. case 0x8C: /* MOV Sw,Ew -- MOV from a SEGMENT REGISTER */
12576//.. delta = dis_mov_Sw_Ew(sorb, sz, delta);
12577//.. break;
12578//..
12579//.. case 0x8E: /* MOV Ew,Sw -- MOV to a SEGMENT REGISTER */
12580//.. delta = dis_mov_Ew_Sw(sorb, delta);
12581//.. break;
sewardj2bd97d12005-08-02 21:27:25 +000012582
12583 case 0xA0: /* MOV Ob,AL */
12584 if (have66orF2orF3(pfx)) goto decode_failure;
12585 sz = 1;
12586 /* Fall through ... */
sewardj87277cb2005-08-01 13:03:32 +000012587 case 0xA1: /* MOV Ov,eAX */
sewardj2bd97d12005-08-02 21:27:25 +000012588 if (sz != 8 && sz != 4 && sz != 2 && sz != 1)
12589 goto decode_failure;
sewardj87277cb2005-08-01 13:03:32 +000012590 d64 = getDisp64(delta);
12591 delta += 8;
12592 ty = szToITy(sz);
12593 addr = newTemp(Ity_I64);
sewardj42561ef2005-11-04 14:18:31 +000012594 assign( addr, handleAddrOverrides(pfx, mkU64(d64)) );
sewardj87277cb2005-08-01 13:03:32 +000012595 putIRegRAX(sz, loadLE( ty, mkexpr(addr) ));
12596 DIP("mov%c %s0x%llx, %s\n", nameISize(sz),
12597 sorbTxt(pfx), d64,
12598 nameIRegRAX(sz));
12599 break;
12600
sewardj2bd97d12005-08-02 21:27:25 +000012601 case 0xA2: /* MOV AL,Ob */
12602 if (have66orF2orF3(pfx)) goto decode_failure;
12603 sz = 1;
12604 /* Fall through ... */
sewardj87277cb2005-08-01 13:03:32 +000012605 case 0xA3: /* MOV eAX,Ov */
sewardj2bd97d12005-08-02 21:27:25 +000012606 if (sz != 8 && sz != 4 && sz != 2 && sz != 1)
12607 goto decode_failure;
sewardj87277cb2005-08-01 13:03:32 +000012608 d64 = getDisp64(delta);
12609 delta += 8;
12610 ty = szToITy(sz);
12611 addr = newTemp(Ity_I64);
sewardj42561ef2005-11-04 14:18:31 +000012612 assign( addr, handleAddrOverrides(pfx, mkU64(d64)) );
sewardj87277cb2005-08-01 13:03:32 +000012613 storeLE( mkexpr(addr), getIRegRAX(sz) );
12614 DIP("mov%c %s, %s0x%llx\n", nameISize(sz), nameIRegRAX(sz),
12615 sorbTxt(pfx), d64);
12616 break;
sewardjb095fba2005-02-13 14:13:04 +000012617
sewardj8711f662005-05-09 17:52:56 +000012618 /* XXXX be careful here with moves to AH/BH/CH/DH */
sewardj007e9ec2005-03-23 11:36:48 +000012619 case 0xB0: /* MOV imm,AL */
12620 case 0xB1: /* MOV imm,CL */
sewardjb095fba2005-02-13 14:13:04 +000012621 case 0xB2: /* MOV imm,DL */
sewardj007e9ec2005-03-23 11:36:48 +000012622 case 0xB3: /* MOV imm,BL */
12623 case 0xB4: /* MOV imm,AH */
12624 case 0xB5: /* MOV imm,CH */
12625 case 0xB6: /* MOV imm,DH */
sewardj31eecde2005-03-23 03:39:55 +000012626 case 0xB7: /* MOV imm,BH */
sewardj5b470602005-02-27 13:10:48 +000012627 if (haveF2orF3(pfx)) goto decode_failure;
sewardjb095fba2005-02-13 14:13:04 +000012628 d64 = getUChar(delta);
12629 delta += 1;
sewardj5b470602005-02-27 13:10:48 +000012630 putIRegRexB(1, pfx, opc-0xB0, mkU8(d64));
12631 DIP("movb $%lld,%s\n", d64, nameIRegRexB(1,pfx,opc-0xB0));
sewardjb095fba2005-02-13 14:13:04 +000012632 break;
sewardj1389d4d2005-01-28 13:46:29 +000012633
12634 case 0xB8: /* MOV imm,eAX */
12635 case 0xB9: /* MOV imm,eCX */
12636 case 0xBA: /* MOV imm,eDX */
12637 case 0xBB: /* MOV imm,eBX */
12638 case 0xBC: /* MOV imm,eSP */
12639 case 0xBD: /* MOV imm,eBP */
12640 case 0xBE: /* MOV imm,eSI */
12641 case 0xBF: /* MOV imm,eDI */
sewardj03b07cc2005-01-31 18:09:43 +000012642 /* This is the one-and-only place where 64-bit literals are
12643 allowed in the instruction stream. */
sewardj5b470602005-02-27 13:10:48 +000012644 if (haveF2orF3(pfx)) goto decode_failure;
sewardj03b07cc2005-01-31 18:09:43 +000012645 if (sz == 8) {
12646 d64 = getDisp64(delta);
sewardj7eaa7cf2005-01-31 18:55:22 +000012647 delta += 8;
sewardj5b470602005-02-27 13:10:48 +000012648 putIRegRexB(8, pfx, opc-0xB8, mkU64(d64));
sewardj227458e2005-01-31 19:04:50 +000012649 DIP("movabsq $%lld,%s\n", (Long)d64,
sewardj5b470602005-02-27 13:10:48 +000012650 nameIRegRexB(8,pfx,opc-0xB8));
sewardj03b07cc2005-01-31 18:09:43 +000012651 } else {
12652 d64 = getSDisp(imin(4,sz),delta);
12653 delta += imin(4,sz);
sewardj5b470602005-02-27 13:10:48 +000012654 putIRegRexB(sz, pfx, opc-0xB8,
12655 mkU(szToITy(sz), d64 & mkSizeMask(sz)));
sewardj227458e2005-01-31 19:04:50 +000012656 DIP("mov%c $%lld,%s\n", nameISize(sz),
12657 (Long)d64,
sewardj5b470602005-02-27 13:10:48 +000012658 nameIRegRexB(sz,pfx,opc-0xB8));
sewardj03b07cc2005-01-31 18:09:43 +000012659 }
sewardj1389d4d2005-01-28 13:46:29 +000012660 break;
12661
12662 case 0xC6: /* MOV Ib,Eb */
12663 sz = 1;
12664 goto do_Mov_I_E;
12665 case 0xC7: /* MOV Iv,Ev */
12666 goto do_Mov_I_E;
12667
12668 do_Mov_I_E:
sewardj5b470602005-02-27 13:10:48 +000012669 if (haveF2orF3(pfx)) goto decode_failure;
sewardj1389d4d2005-01-28 13:46:29 +000012670 modrm = getUChar(delta);
12671 if (epartIsReg(modrm)) {
sewardj1389d4d2005-01-28 13:46:29 +000012672 delta++; /* mod/rm byte */
12673 d64 = getSDisp(imin(4,sz),delta);
12674 delta += imin(4,sz);
sewardj5b470602005-02-27 13:10:48 +000012675 putIRegE(sz, pfx, modrm,
12676 mkU(szToITy(sz), d64 & mkSizeMask(sz)));
sewardj227458e2005-01-31 19:04:50 +000012677 DIP("mov%c $%lld, %s\n", nameISize(sz),
12678 (Long)d64,
sewardj5b470602005-02-27 13:10:48 +000012679 nameIRegE(sz,pfx,modrm));
sewardj1389d4d2005-01-28 13:46:29 +000012680 } else {
sewardj5b470602005-02-27 13:10:48 +000012681 addr = disAMode ( &alen, pfx, delta, dis_buf,
12682 /*xtra*/imin(4,sz) );
sewardj1389d4d2005-01-28 13:46:29 +000012683 delta += alen;
sewardje941eea2005-01-30 19:52:28 +000012684 d64 = getSDisp(imin(4,sz),delta);
sewardj1389d4d2005-01-28 13:46:29 +000012685 delta += imin(4,sz);
sewardje941eea2005-01-30 19:52:28 +000012686 storeLE(mkexpr(addr),
12687 mkU(szToITy(sz), d64 & mkSizeMask(sz)));
sewardj227458e2005-01-31 19:04:50 +000012688 DIP("mov%c $%lld, %s\n", nameISize(sz), (Long)d64, dis_buf);
sewardj1389d4d2005-01-28 13:46:29 +000012689 }
12690 break;
12691
sewardj5e525292005-01-28 15:13:10 +000012692 /* ------------------------ MOVx ------------------------ */
12693
12694 case 0x63: /* MOVSX */
sewardj5b470602005-02-27 13:10:48 +000012695 if (haveF2orF3(pfx)) goto decode_failure;
sewardj5e525292005-01-28 15:13:10 +000012696 if (haveREX(pfx) && 1==getRexW(pfx)) {
12697 vassert(sz == 8);
12698 /* movsx r/m32 to r64 */
12699 modrm = getUChar(delta);
12700 if (epartIsReg(modrm)) {
12701 delta++;
sewardj5b470602005-02-27 13:10:48 +000012702 putIRegG(8, pfx, modrm,
sewardj5e525292005-01-28 15:13:10 +000012703 unop(Iop_32Sto64,
sewardj5b470602005-02-27 13:10:48 +000012704 getIRegE(4, pfx, modrm)));
sewardj5e525292005-01-28 15:13:10 +000012705 DIP("movslq %s,%s\n",
sewardj5b470602005-02-27 13:10:48 +000012706 nameIRegE(4, pfx, modrm),
12707 nameIRegG(8, pfx, modrm));
sewardj5e525292005-01-28 15:13:10 +000012708 break;
12709 } else {
sewardje1698952005-02-08 15:02:39 +000012710 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
sewardj5e525292005-01-28 15:13:10 +000012711 delta += alen;
sewardj5b470602005-02-27 13:10:48 +000012712 putIRegG(8, pfx, modrm,
sewardj5e525292005-01-28 15:13:10 +000012713 unop(Iop_32Sto64,
12714 loadLE(Ity_I32, mkexpr(addr))));
12715 DIP("movslq %s,%s\n", dis_buf,
sewardj5b470602005-02-27 13:10:48 +000012716 nameIRegG(8, pfx, modrm));
sewardj5e525292005-01-28 15:13:10 +000012717 break;
12718 }
12719 } else {
12720 goto decode_failure;
12721 }
12722
sewardj4c328cf2005-05-05 12:05:54 +000012723 /* ------------------------ opl imm, A ----------------- */
12724
12725 case 0x04: /* ADD Ib, AL */
12726 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000012727 delta = dis_op_imm_A( 1, False, Iop_Add8, True, delta, "add" );
sewardj4c328cf2005-05-05 12:05:54 +000012728 break;
sewardj03b07cc2005-01-31 18:09:43 +000012729 case 0x05: /* ADD Iv, eAX */
sewardj5b470602005-02-27 13:10:48 +000012730 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000012731 delta = dis_op_imm_A(sz, False, Iop_Add8, True, delta, "add" );
sewardj03b07cc2005-01-31 18:09:43 +000012732 break;
12733
sewardj007e9ec2005-03-23 11:36:48 +000012734 case 0x0C: /* OR Ib, AL */
12735 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000012736 delta = dis_op_imm_A( 1, False, Iop_Or8, True, delta, "or" );
sewardj007e9ec2005-03-23 11:36:48 +000012737 break;
sewardj03b07cc2005-01-31 18:09:43 +000012738 case 0x0D: /* OR Iv, eAX */
sewardj5b470602005-02-27 13:10:48 +000012739 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000012740 delta = dis_op_imm_A( sz, False, Iop_Or8, True, delta, "or" );
sewardj03b07cc2005-01-31 18:09:43 +000012741 break;
12742
sewardj41c01092005-07-23 13:50:32 +000012743 case 0x14: /* ADC Ib, AL */
12744 delta = dis_op_imm_A( 1, True, Iop_Add8, True, delta, "adc" );
12745 break;
sewardjd20c8852005-01-20 20:04:07 +000012746//.. //-- case 0x15: /* ADC Iv, eAX */
12747//.. //-- delta = dis_op_imm_A( sz, ADC, True, delta, "adc" );
12748//.. //-- break;
sewardj5fadaf92006-05-12 20:45:59 +000012749
12750 case 0x1C: /* SBB Ib, AL */
12751 if (haveF2orF3(pfx)) goto decode_failure;
12752 delta = dis_op_imm_A( 1, True, Iop_Sub8, True, delta, "sbb" );
12753 break;
sewardjd20c8852005-01-20 20:04:07 +000012754//.. //-- case 0x1D: /* SBB Iv, eAX */
12755//.. //-- delta = dis_op_imm_A( sz, SBB, True, delta, "sbb" );
12756//.. //-- break;
12757//.. //--
sewardj007e9ec2005-03-23 11:36:48 +000012758 case 0x24: /* AND Ib, AL */
12759 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000012760 delta = dis_op_imm_A( 1, False, Iop_And8, True, delta, "and" );
sewardj007e9ec2005-03-23 11:36:48 +000012761 break;
sewardj3ca55a12005-01-27 16:06:23 +000012762 case 0x25: /* AND Iv, eAX */
12763 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000012764 delta = dis_op_imm_A( sz, False, Iop_And8, True, delta, "and" );
sewardj3ca55a12005-01-27 16:06:23 +000012765 break;
12766
sewardj137015d2005-03-27 04:01:15 +000012767 case 0x2C: /* SUB Ib, AL */
12768 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000012769 delta = dis_op_imm_A(1, False, Iop_Sub8, True, delta, "sub" );
sewardj137015d2005-03-27 04:01:15 +000012770 break;
sewardj03b07cc2005-01-31 18:09:43 +000012771 case 0x2D: /* SUB Iv, eAX */
sewardj5b470602005-02-27 13:10:48 +000012772 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000012773 delta = dis_op_imm_A( sz, False, Iop_Sub8, True, delta, "sub" );
sewardj03b07cc2005-01-31 18:09:43 +000012774 break;
12775
sewardj8eb804f2005-05-18 10:22:47 +000012776 case 0x34: /* XOR Ib, AL */
12777 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000012778 delta = dis_op_imm_A( 1, False, Iop_Xor8, True, delta, "xor" );
sewardj8eb804f2005-05-18 10:22:47 +000012779 break;
sewardj85520e42005-02-19 15:22:38 +000012780 case 0x35: /* XOR Iv, eAX */
sewardj5b470602005-02-27 13:10:48 +000012781 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000012782 delta = dis_op_imm_A( sz, False, Iop_Xor8, True, delta, "xor" );
sewardj85520e42005-02-19 15:22:38 +000012783 break;
sewardj03b07cc2005-01-31 18:09:43 +000012784
12785 case 0x3C: /* CMP Ib, AL */
12786 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000012787 delta = dis_op_imm_A( 1, False, Iop_Sub8, False, delta, "cmp" );
sewardj03b07cc2005-01-31 18:09:43 +000012788 break;
sewardj354e5c62005-01-27 20:12:52 +000012789 case 0x3D: /* CMP Iv, eAX */
12790 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000012791 delta = dis_op_imm_A( sz, False, Iop_Sub8, False, delta, "cmp" );
sewardj354e5c62005-01-27 20:12:52 +000012792 break;
12793
sewardj118b23e2005-01-29 02:14:44 +000012794 case 0xA8: /* TEST Ib, AL */
sewardj03b07cc2005-01-31 18:09:43 +000012795 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000012796 delta = dis_op_imm_A( 1, False, Iop_And8, False, delta, "test" );
sewardj118b23e2005-01-29 02:14:44 +000012797 break;
12798 case 0xA9: /* TEST Iv, eAX */
sewardj03b07cc2005-01-31 18:09:43 +000012799 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000012800 delta = dis_op_imm_A( sz, False, Iop_And8, False, delta, "test" );
sewardj118b23e2005-01-29 02:14:44 +000012801 break;
12802
12803 /* ------------------------ opl Ev, Gv ----------------- */
12804
sewardj03b07cc2005-01-31 18:09:43 +000012805 case 0x02: /* ADD Eb,Gb */
12806 if (haveF2orF3(pfx)) goto decode_failure;
12807 delta = dis_op2_E_G ( pfx, False, Iop_Add8, True, 1, delta, "add" );
12808 break;
sewardjdf0e0022005-01-25 15:48:43 +000012809 case 0x03: /* ADD Ev,Gv */
sewardj3ca55a12005-01-27 16:06:23 +000012810 if (haveF2orF3(pfx)) goto decode_failure;
sewardjdf0e0022005-01-25 15:48:43 +000012811 delta = dis_op2_E_G ( pfx, False, Iop_Add8, True, sz, delta, "add" );
sewardjdf0e0022005-01-25 15:48:43 +000012812 break;
12813
sewardj03b07cc2005-01-31 18:09:43 +000012814 case 0x0A: /* OR Eb,Gb */
sewardj5b470602005-02-27 13:10:48 +000012815 if (haveF2orF3(pfx)) goto decode_failure;
sewardj03b07cc2005-01-31 18:09:43 +000012816 delta = dis_op2_E_G ( pfx, False, Iop_Or8, True, 1, delta, "or" );
12817 break;
12818 case 0x0B: /* OR Ev,Gv */
sewardj5b470602005-02-27 13:10:48 +000012819 if (haveF2orF3(pfx)) goto decode_failure;
sewardj03b07cc2005-01-31 18:09:43 +000012820 delta = dis_op2_E_G ( pfx, False, Iop_Or8, True, sz, delta, "or" );
12821 break;
12822//--
sewardjd20c8852005-01-20 20:04:07 +000012823//.. //-- case 0x12: /* ADC Eb,Gb */
12824//.. //-- delta = dis_op2_E_G ( sorb, True, ADC, True, 1, delta, "adc" );
12825//.. //-- break;
sewardj22cab062005-07-19 23:59:54 +000012826 case 0x13: /* ADC Ev,Gv */
12827 delta = dis_op2_E_G ( pfx, True, Iop_Add8, True, sz, delta, "adc" );
12828 break;
12829
sewardjd20c8852005-01-20 20:04:07 +000012830//.. //-- case 0x1A: /* SBB Eb,Gb */
12831//.. //-- delta = dis_op2_E_G ( sorb, True, SBB, True, 1, delta, "sbb" );
12832//.. //-- break;
sewardj7a06b852005-07-20 10:55:26 +000012833 case 0x1B: /* SBB Ev,Gv */
12834 delta = dis_op2_E_G ( pfx, True, Iop_Sub8, True, sz, delta, "sbb" );
12835 break;
sewardj03b07cc2005-01-31 18:09:43 +000012836
12837 case 0x22: /* AND Eb,Gb */
12838 if (haveF2orF3(pfx)) goto decode_failure;
12839 delta = dis_op2_E_G ( pfx, False, Iop_And8, True, 1, delta, "and" );
12840 break;
12841 case 0x23: /* AND Ev,Gv */
12842 if (haveF2orF3(pfx)) goto decode_failure;
12843 delta = dis_op2_E_G ( pfx, False, Iop_And8, True, sz, delta, "and" );
12844 break;
12845
12846 case 0x2A: /* SUB Eb,Gb */
12847 if (haveF2orF3(pfx)) goto decode_failure;
12848 delta = dis_op2_E_G ( pfx, False, Iop_Sub8, True, 1, delta, "sub" );
12849 break;
sewardj118b23e2005-01-29 02:14:44 +000012850 case 0x2B: /* SUB Ev,Gv */
sewardj03b07cc2005-01-31 18:09:43 +000012851 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000012852 delta = dis_op2_E_G ( pfx, False, Iop_Sub8, True, sz, delta, "sub" );
12853 break;
12854
sewardj03b07cc2005-01-31 18:09:43 +000012855 case 0x32: /* XOR Eb,Gb */
12856 if (haveF2orF3(pfx)) goto decode_failure;
12857 delta = dis_op2_E_G ( pfx, False, Iop_Xor8, True, 1, delta, "xor" );
12858 break;
12859 case 0x33: /* XOR Ev,Gv */
12860 if (haveF2orF3(pfx)) goto decode_failure;
12861 delta = dis_op2_E_G ( pfx, False, Iop_Xor8, True, sz, delta, "xor" );
12862 break;
12863
sewardjb095fba2005-02-13 14:13:04 +000012864 case 0x3A: /* CMP Eb,Gb */
12865 if (haveF2orF3(pfx)) goto decode_failure;
12866 delta = dis_op2_E_G ( pfx, False, Iop_Sub8, False, 1, delta, "cmp" );
12867 break;
sewardj354e5c62005-01-27 20:12:52 +000012868 case 0x3B: /* CMP Ev,Gv */
12869 if (haveF2orF3(pfx)) goto decode_failure;
12870 delta = dis_op2_E_G ( pfx, False, Iop_Sub8, False, sz, delta, "cmp" );
12871 break;
12872
sewardj118b23e2005-01-29 02:14:44 +000012873 case 0x84: /* TEST Eb,Gb */
sewardj03b07cc2005-01-31 18:09:43 +000012874 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000012875 delta = dis_op2_E_G ( pfx, False, Iop_And8, False, 1, delta, "test" );
12876 break;
12877 case 0x85: /* TEST Ev,Gv */
sewardj03b07cc2005-01-31 18:09:43 +000012878 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000012879 delta = dis_op2_E_G ( pfx, False, Iop_And8, False, sz, delta, "test" );
12880 break;
12881
12882 /* ------------------------ opl Gv, Ev ----------------- */
12883
sewardj85520e42005-02-19 15:22:38 +000012884 case 0x00: /* ADD Gb,Eb */
12885 if (haveF2orF3(pfx)) goto decode_failure;
12886 delta = dis_op2_G_E ( pfx, False, Iop_Add8, True, 1, delta, "add" );
12887 break;
sewardj3ca55a12005-01-27 16:06:23 +000012888 case 0x01: /* ADD Gv,Ev */
sewardj354e5c62005-01-27 20:12:52 +000012889 if (haveF2orF3(pfx)) goto decode_failure;
sewardj3ca55a12005-01-27 16:06:23 +000012890 delta = dis_op2_G_E ( pfx, False, Iop_Add8, True, sz, delta, "add" );
12891 break;
12892
sewardj03b07cc2005-01-31 18:09:43 +000012893 case 0x08: /* OR Gb,Eb */
12894 if (haveF2orF3(pfx)) goto decode_failure;
12895 delta = dis_op2_G_E ( pfx, False, Iop_Or8, True, 1, delta, "or" );
12896 break;
sewardj55dbb262005-01-28 16:36:51 +000012897 case 0x09: /* OR Gv,Ev */
12898 if (haveF2orF3(pfx)) goto decode_failure;
12899 delta = dis_op2_G_E ( pfx, False, Iop_Or8, True, sz, delta, "or" );
12900 break;
12901
sewardj85520e42005-02-19 15:22:38 +000012902 case 0x10: /* ADC Gb,Eb */
12903 if (haveF2orF3(pfx)) goto decode_failure;
12904 delta = dis_op2_G_E ( pfx, True, Iop_Add8, True, 1, delta, "adc" );
12905 break;
12906 case 0x11: /* ADC Gv,Ev */
12907 if (haveF2orF3(pfx)) goto decode_failure;
12908 delta = dis_op2_G_E ( pfx, True, Iop_Add8, True, sz, delta, "adc" );
12909 break;
12910
12911 case 0x18: /* SBB Gb,Eb */
12912 if (haveF2orF3(pfx)) goto decode_failure;
12913 delta = dis_op2_G_E ( pfx, True, Iop_Sub8, True, 1, delta, "sbb" );
12914 break;
sewardj03b07cc2005-01-31 18:09:43 +000012915 case 0x19: /* SBB Gv,Ev */
sewardja6b93d12005-02-17 09:28:28 +000012916 if (haveF2orF3(pfx)) goto decode_failure;
sewardj03b07cc2005-01-31 18:09:43 +000012917 delta = dis_op2_G_E ( pfx, True, Iop_Sub8, True, sz, delta, "sbb" );
12918 break;
12919
sewardj85520e42005-02-19 15:22:38 +000012920 case 0x20: /* AND Gb,Eb */
12921 if (haveF2orF3(pfx)) goto decode_failure;
12922 delta = dis_op2_G_E ( pfx, False, Iop_And8, True, 1, delta, "and" );
12923 break;
sewardj3ca55a12005-01-27 16:06:23 +000012924 case 0x21: /* AND Gv,Ev */
sewardj354e5c62005-01-27 20:12:52 +000012925 if (haveF2orF3(pfx)) goto decode_failure;
sewardj3ca55a12005-01-27 16:06:23 +000012926 delta = dis_op2_G_E ( pfx, False, Iop_And8, True, sz, delta, "and" );
12927 break;
sewardj03b07cc2005-01-31 18:09:43 +000012928
12929 case 0x28: /* SUB Gb,Eb */
12930 if (haveF2orF3(pfx)) goto decode_failure;
12931 delta = dis_op2_G_E ( pfx, False, Iop_Sub8, True, 1, delta, "sub" );
12932 break;
sewardj118b23e2005-01-29 02:14:44 +000012933 case 0x29: /* SUB Gv,Ev */
sewardj03b07cc2005-01-31 18:09:43 +000012934 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000012935 delta = dis_op2_G_E ( pfx, False, Iop_Sub8, True, sz, delta, "sub" );
12936 break;
12937
sewardjb095fba2005-02-13 14:13:04 +000012938 case 0x30: /* XOR Gb,Eb */
12939 if (haveF2orF3(pfx)) goto decode_failure;
12940 delta = dis_op2_G_E ( pfx, False, Iop_Xor8, True, 1, delta, "xor" );
12941 break;
sewardj118b23e2005-01-29 02:14:44 +000012942 case 0x31: /* XOR Gv,Ev */
sewardj03b07cc2005-01-31 18:09:43 +000012943 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000012944 delta = dis_op2_G_E ( pfx, False, Iop_Xor8, True, sz, delta, "xor" );
12945 break;
sewardj354e5c62005-01-27 20:12:52 +000012946
12947 case 0x38: /* CMP Gb,Eb */
12948 if (haveF2orF3(pfx)) goto decode_failure;
12949 delta = dis_op2_G_E ( pfx, False, Iop_Sub8, False, 1, delta, "cmp" );
12950 break;
12951 case 0x39: /* CMP Gv,Ev */
12952 if (haveF2orF3(pfx)) goto decode_failure;
12953 delta = dis_op2_G_E ( pfx, False, Iop_Sub8, False, sz, delta, "cmp" );
12954 break;
12955
sewardj55dbb262005-01-28 16:36:51 +000012956 /* ------------------------ POP ------------------------ */
12957
12958 case 0x58: /* POP eAX */
12959 case 0x59: /* POP eCX */
12960 case 0x5A: /* POP eDX */
12961 case 0x5B: /* POP eBX */
12962 case 0x5D: /* POP eBP */
12963 case 0x5E: /* POP eSI */
12964 case 0x5F: /* POP eDI */
12965 case 0x5C: /* POP eSP */
sewardj03b07cc2005-01-31 18:09:43 +000012966 if (haveF2orF3(pfx)) goto decode_failure;
sewardj55dbb262005-01-28 16:36:51 +000012967 vassert(sz == 2 || sz == 4 || sz == 8);
12968 if (sz == 4)
12969 sz = 8; /* there is no encoding for 32-bit pop in 64-bit mode */
12970 t1 = newTemp(szToITy(sz));
12971 t2 = newTemp(Ity_I64);
12972 assign(t2, getIReg64(R_RSP));
12973 assign(t1, loadLE(szToITy(sz),mkexpr(t2)));
12974 putIReg64(R_RSP, binop(Iop_Add64, mkexpr(t2), mkU64(sz)));
sewardj5b470602005-02-27 13:10:48 +000012975 putIRegRexB(sz, pfx, opc-0x58, mkexpr(t1));
12976 DIP("pop%c %s\n", nameISize(sz), nameIRegRexB(sz,pfx,opc-0x58));
sewardj55dbb262005-01-28 16:36:51 +000012977 break;
12978
sewardj85520e42005-02-19 15:22:38 +000012979 case 0x9D: /* POPF */
12980 /* Note. There is no encoding for a 32-bit popf in 64-bit mode.
12981 So sz==4 actually means sz==8. */
sewardj5b470602005-02-27 13:10:48 +000012982 if (haveF2orF3(pfx)) goto decode_failure;
sewardj85520e42005-02-19 15:22:38 +000012983 vassert(sz == 2 || sz == 4);
12984 if (sz == 4) sz = 8;
sewardj5b470602005-02-27 13:10:48 +000012985 if (sz != 8) goto decode_failure; // until we know a sz==2 test case exists
sewardj85520e42005-02-19 15:22:38 +000012986 t1 = newTemp(Ity_I64); t2 = newTemp(Ity_I64);
12987 assign(t2, getIReg64(R_RSP));
12988 assign(t1, widenUto64(loadLE(szToITy(sz),mkexpr(t2))));
12989 putIReg64(R_RSP, binop(Iop_Add64, mkexpr(t2), mkU64(sz)));
12990 /* t1 is the flag word. Mask out everything except OSZACP and
12991 set the flags thunk to AMD64G_CC_OP_COPY. */
12992 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(AMD64G_CC_OP_COPY) ));
12993 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
12994 stmt( IRStmt_Put( OFFB_CC_DEP1,
12995 binop(Iop_And64,
12996 mkexpr(t1),
12997 mkU64( AMD64G_CC_MASK_C | AMD64G_CC_MASK_P
12998 | AMD64G_CC_MASK_A | AMD64G_CC_MASK_Z
12999 | AMD64G_CC_MASK_S| AMD64G_CC_MASK_O )
13000 )
13001 )
13002 );
13003
13004 /* Also need to set the D flag, which is held in bit 10 of t1.
13005 If zero, put 1 in OFFB_DFLAG, else -1 in OFFB_DFLAG. */
13006 stmt( IRStmt_Put(
13007 OFFB_DFLAG,
13008 IRExpr_Mux0X(
13009 unop(Iop_32to8,
13010 unop(Iop_64to32,
13011 binop(Iop_And64,
13012 binop(Iop_Shr64, mkexpr(t1), mkU8(10)),
13013 mkU64(1)))),
13014 mkU64(1),
13015 mkU64(0xFFFFFFFFFFFFFFFFULL)))
13016 );
13017
13018 /* And set the ID flag */
13019 stmt( IRStmt_Put(
13020 OFFB_IDFLAG,
13021 IRExpr_Mux0X(
13022 unop(Iop_32to8,
13023 unop(Iop_64to32,
13024 binop(Iop_And64,
13025 binop(Iop_Shr64, mkexpr(t1), mkU8(21)),
13026 mkU64(1)))),
13027 mkU64(0),
13028 mkU64(1)))
13029 );
13030
13031 DIP("popf%c\n", nameISize(sz));
13032 break;
13033
sewardjd20c8852005-01-20 20:04:07 +000013034//.. case 0x61: /* POPA */
13035//.. /* This is almost certainly wrong for sz==2. So ... */
13036//.. if (sz != 4) goto decode_failure;
13037//..
13038//.. /* t5 is the old %ESP value. */
13039//.. t5 = newTemp(Ity_I32);
13040//.. assign( t5, getIReg(4, R_ESP) );
13041//..
13042//.. /* Reload all the registers, except %esp. */
13043//.. putIReg(4,R_EAX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(28)) ));
13044//.. putIReg(4,R_ECX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(24)) ));
13045//.. putIReg(4,R_EDX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(20)) ));
13046//.. putIReg(4,R_EBX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(16)) ));
13047//.. /* ignore saved %ESP */
13048//.. putIReg(4,R_EBP, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32( 8)) ));
13049//.. putIReg(4,R_ESI, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32( 4)) ));
13050//.. putIReg(4,R_EDI, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32( 0)) ));
13051//..
13052//.. /* and move %ESP back up */
13053//.. putIReg( 4, R_ESP, binop(Iop_Add32, mkexpr(t5), mkU32(8*4)) );
13054//..
13055//.. DIP("pusha%c\n", nameISize(sz));
13056//.. break;
sewardj432f8b62005-05-10 02:50:05 +000013057
13058 case 0x8F: { /* POPQ m64 / POPW m16 */
sewardj1bd14e72005-05-11 16:24:00 +000013059 Int len;
13060 UChar rm;
sewardj432f8b62005-05-10 02:50:05 +000013061 /* There is no encoding for 32-bit pop in 64-bit mode.
13062 So sz==4 actually means sz==8. */
13063 if (haveF2orF3(pfx)) goto decode_failure;
13064 vassert(sz == 2 || sz == 4);
13065 if (sz == 4) sz = 8;
13066 if (sz != 8) goto decode_failure; // until we know a sz==2 test case exists
13067
sewardj1bd14e72005-05-11 16:24:00 +000013068 rm = getUChar(delta);
sewardj432f8b62005-05-10 02:50:05 +000013069
13070 /* make sure this instruction is correct POP */
13071 if (epartIsReg(rm) || gregLO3ofRM(rm) != 0)
13072 goto decode_failure;
13073 /* and has correct size */
13074 vassert(sz == 8);
13075
13076 t1 = newTemp(Ity_I64);
13077 t3 = newTemp(Ity_I64);
13078 assign( t1, getIReg64(R_RSP) );
13079 assign( t3, loadLE(Ity_I64, mkexpr(t1)) );
13080
13081 /* Increase RSP; must be done before the STORE. Intel manual
13082 says: If the RSP register is used as a base register for
13083 addressing a destination operand in memory, the POP
13084 instruction computes the effective address of the operand
13085 after it increments the RSP register. */
13086 putIReg64(R_RSP, binop(Iop_Add64, mkexpr(t1), mkU64(sz)) );
13087
13088 addr = disAMode ( &len, pfx, delta, dis_buf, 0 );
13089 storeLE( mkexpr(addr), mkexpr(t3) );
13090
13091 DIP("popl %s\n", dis_buf);
13092
13093 delta += len;
13094 break;
13095 }
13096
sewardjd20c8852005-01-20 20:04:07 +000013097//.. //-- case 0x1F: /* POP %DS */
13098//.. //-- dis_pop_segreg( cb, R_DS, sz ); break;
13099//.. //-- case 0x07: /* POP %ES */
13100//.. //-- dis_pop_segreg( cb, R_ES, sz ); break;
13101//.. //-- case 0x17: /* POP %SS */
13102//.. //-- dis_pop_segreg( cb, R_SS, sz ); break;
sewardj55dbb262005-01-28 16:36:51 +000013103
13104 /* ------------------------ PUSH ----------------------- */
13105
13106 case 0x50: /* PUSH eAX */
13107 case 0x51: /* PUSH eCX */
13108 case 0x52: /* PUSH eDX */
13109 case 0x53: /* PUSH eBX */
13110 case 0x55: /* PUSH eBP */
13111 case 0x56: /* PUSH eSI */
13112 case 0x57: /* PUSH eDI */
13113 case 0x54: /* PUSH eSP */
13114 /* This is the Right Way, in that the value to be pushed is
13115 established before %rsp is changed, so that pushq %rsp
13116 correctly pushes the old value. */
sewardj03b07cc2005-01-31 18:09:43 +000013117 if (haveF2orF3(pfx)) goto decode_failure;
sewardj55dbb262005-01-28 16:36:51 +000013118 vassert(sz == 2 || sz == 4 || sz == 8);
13119 if (sz == 4)
13120 sz = 8; /* there is no encoding for 32-bit push in 64-bit mode */
13121 ty = sz==2 ? Ity_I16 : Ity_I64;
13122 t1 = newTemp(ty);
13123 t2 = newTemp(Ity_I64);
sewardj5b470602005-02-27 13:10:48 +000013124 assign(t1, getIRegRexB(sz, pfx, opc-0x50));
sewardj55dbb262005-01-28 16:36:51 +000013125 assign(t2, binop(Iop_Sub64, getIReg64(R_RSP), mkU64(sz)));
13126 putIReg64(R_RSP, mkexpr(t2) );
13127 storeLE(mkexpr(t2),mkexpr(t1));
sewardj5b470602005-02-27 13:10:48 +000013128 DIP("push%c %s\n", nameISize(sz), nameIRegRexB(sz,pfx,opc-0x50));
sewardj55dbb262005-01-28 16:36:51 +000013129 break;
13130
sewardja6b93d12005-02-17 09:28:28 +000013131 case 0x68: /* PUSH Iv */
sewardj5b470602005-02-27 13:10:48 +000013132 if (haveF2orF3(pfx)) goto decode_failure;
sewardja6b93d12005-02-17 09:28:28 +000013133 /* Note, sz==4 is not possible in 64-bit mode. Hence ... */
13134 if (sz == 4) sz = 8;
13135 d64 = getSDisp(imin(4,sz),delta);
13136 delta += imin(4,sz);
13137 goto do_push_I;
sewardj909c06d2005-02-19 22:47:41 +000013138 case 0x6A: /* PUSH Ib, sign-extended to sz */
sewardj5b470602005-02-27 13:10:48 +000013139 if (haveF2orF3(pfx)) goto decode_failure;
sewardj909c06d2005-02-19 22:47:41 +000013140 /* Note, sz==4 is not possible in 64-bit mode. Hence ... */
13141 if (sz == 4) sz = 8;
13142 d64 = getSDisp8(delta); delta += 1;
13143 goto do_push_I;
sewardja6b93d12005-02-17 09:28:28 +000013144 do_push_I:
13145 ty = szToITy(sz);
sewardj909c06d2005-02-19 22:47:41 +000013146 t1 = newTemp(Ity_I64);
13147 t2 = newTemp(ty);
sewardja6b93d12005-02-17 09:28:28 +000013148 assign( t1, binop(Iop_Sub64,getIReg64(R_RSP),mkU64(sz)) );
13149 putIReg64(R_RSP, mkexpr(t1) );
sewardjb2da8ec2006-08-28 18:54:18 +000013150 /* stop mkU16 asserting if d32 is a negative 16-bit number
13151 (bug #132813) */
13152 if (ty == Ity_I16)
13153 d64 &= 0xFFFF;
sewardja6b93d12005-02-17 09:28:28 +000013154 storeLE( mkexpr(t1), mkU(ty,d64) );
sewardj1027dc22005-02-26 01:55:02 +000013155 DIP("push%c $%lld\n", nameISize(sz), (Long)d64);
sewardja6b93d12005-02-17 09:28:28 +000013156 break;
13157
sewardj85520e42005-02-19 15:22:38 +000013158 case 0x9C: /* PUSHF */ {
13159 /* Note. There is no encoding for a 32-bit pushf in 64-bit
13160 mode. So sz==4 actually means sz==8. */
sewardj11faabe2006-07-24 09:09:36 +000013161 /* 24 July 06: has also been seen with a redundant REX prefix,
13162 so must also allow sz==8. */
sewardj5b470602005-02-27 13:10:48 +000013163 if (haveF2orF3(pfx)) goto decode_failure;
sewardj11faabe2006-07-24 09:09:36 +000013164 vassert(sz == 2 || sz == 4 || sz == 8);
sewardj85520e42005-02-19 15:22:38 +000013165 if (sz == 4) sz = 8;
sewardj5b470602005-02-27 13:10:48 +000013166 if (sz != 8) goto decode_failure; // until we know a sz==2 test case exists
sewardj85520e42005-02-19 15:22:38 +000013167
13168 t1 = newTemp(Ity_I64);
13169 assign( t1, binop(Iop_Sub64,getIReg64(R_RSP),mkU64(sz)) );
13170 putIReg64(R_RSP, mkexpr(t1) );
13171
13172 t2 = newTemp(Ity_I64);
13173 assign( t2, mk_amd64g_calculate_rflags_all() );
13174
13175 /* Patch in the D flag. This can simply be a copy of bit 10 of
13176 baseBlock[OFFB_DFLAG]. */
13177 t3 = newTemp(Ity_I64);
13178 assign( t3, binop(Iop_Or64,
13179 mkexpr(t2),
13180 binop(Iop_And64,
13181 IRExpr_Get(OFFB_DFLAG,Ity_I64),
13182 mkU64(1<<10)))
13183 );
13184
13185 /* And patch in the ID flag. */
13186 t4 = newTemp(Ity_I64);
13187 assign( t4, binop(Iop_Or64,
13188 mkexpr(t3),
13189 binop(Iop_And64,
13190 binop(Iop_Shl64, IRExpr_Get(OFFB_IDFLAG,Ity_I64),
13191 mkU8(21)),
13192 mkU64(1<<21)))
13193 );
13194
13195 /* if sz==2, the stored value needs to be narrowed. */
13196 if (sz == 2)
13197 storeLE( mkexpr(t1), unop(Iop_32to16,
13198 unop(Iop_64to32,mkexpr(t4))) );
13199 else
13200 storeLE( mkexpr(t1), mkexpr(t4) );
13201
13202 DIP("pushf%c\n", nameISize(sz));
13203 break;
13204 }
13205
sewardjd20c8852005-01-20 20:04:07 +000013206//.. case 0x60: /* PUSHA */
13207//.. /* This is almost certainly wrong for sz==2. So ... */
13208//.. if (sz != 4) goto decode_failure;
13209//..
13210//.. /* This is the Right Way, in that the value to be pushed is
13211//.. established before %esp is changed, so that pusha
13212//.. correctly pushes the old %esp value. New value of %esp is
13213//.. pushed at start. */
13214//.. /* t0 is the %ESP value we're going to push. */
13215//.. t0 = newTemp(Ity_I32);
13216//.. assign( t0, getIReg(4, R_ESP) );
13217//..
13218//.. /* t5 will be the new %ESP value. */
13219//.. t5 = newTemp(Ity_I32);
13220//.. assign( t5, binop(Iop_Sub32, mkexpr(t0), mkU32(8*4)) );
13221//..
13222//.. /* Update guest state before prodding memory. */
13223//.. putIReg(4, R_ESP, mkexpr(t5));
13224//..
13225//.. /* Dump all the registers. */
13226//.. storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(28)), getIReg(4,R_EAX) );
13227//.. storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(24)), getIReg(4,R_ECX) );
13228//.. storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(20)), getIReg(4,R_EDX) );
13229//.. storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(16)), getIReg(4,R_EBX) );
13230//.. storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(12)), mkexpr(t0) /*esp*/);
13231//.. storeLE( binop(Iop_Add32,mkexpr(t5),mkU32( 8)), getIReg(4,R_EBP) );
13232//.. storeLE( binop(Iop_Add32,mkexpr(t5),mkU32( 4)), getIReg(4,R_ESI) );
13233//.. storeLE( binop(Iop_Add32,mkexpr(t5),mkU32( 0)), getIReg(4,R_EDI) );
13234//..
13235//.. DIP("pusha%c\n", nameISize(sz));
13236//.. break;
13237//..
13238//..
13239//.. //-- case 0x0E: /* PUSH %CS */
13240//.. //-- dis_push_segreg( cb, R_CS, sz ); break;
13241//.. //-- case 0x1E: /* PUSH %DS */
13242//.. //-- dis_push_segreg( cb, R_DS, sz ); break;
13243//.. //-- case 0x06: /* PUSH %ES */
13244//.. //-- dis_push_segreg( cb, R_ES, sz ); break;
13245//.. //-- case 0x16: /* PUSH %SS */
13246//.. //-- dis_push_segreg( cb, R_SS, sz ); break;
13247//..
13248//.. /* ------------------------ SCAS et al ----------------- */
13249//..
13250//.. case 0xA4: /* MOVS, no REP prefix */
13251//.. case 0xA5:
13252//.. dis_string_op( dis_MOVS, ( opc == 0xA4 ? 1 : sz ), "movs", sorb );
13253//.. break;
13254//..
13255//.. case 0xA6: /* CMPSb, no REP prefix */
13256//.. //-- case 0xA7:
13257//.. dis_string_op( dis_CMPS, ( opc == 0xA6 ? 1 : sz ), "cmps", sorb );
13258//.. break;
13259//.. //--
sewardjd20c8852005-01-20 20:04:07 +000013260//.. //--
13261//.. //-- case 0xAC: /* LODS, no REP prefix */
13262//.. //-- case 0xAD:
13263//.. //-- dis_string_op( cb, dis_LODS, ( opc == 0xAC ? 1 : sz ), "lods", sorb );
13264//.. //-- break;
13265//..
13266//.. case 0xAE: /* SCAS, no REP prefix */
13267//.. case 0xAF:
13268//.. dis_string_op( dis_SCAS, ( opc == 0xAE ? 1 : sz ), "scas", sorb );
13269//.. break;
sewardjd0a12df2005-02-10 02:07:43 +000013270
13271
13272 case 0xFC: /* CLD */
sewardj5b470602005-02-27 13:10:48 +000013273 if (haveF2orF3(pfx)) goto decode_failure;
sewardjd0a12df2005-02-10 02:07:43 +000013274 stmt( IRStmt_Put( OFFB_DFLAG, mkU64(1)) );
13275 DIP("cld\n");
13276 break;
13277
sewardj909c06d2005-02-19 22:47:41 +000013278 case 0xFD: /* STD */
sewardj5b470602005-02-27 13:10:48 +000013279 if (haveF2orF3(pfx)) goto decode_failure;
sewardj909c06d2005-02-19 22:47:41 +000013280 stmt( IRStmt_Put( OFFB_DFLAG, mkU64(-1ULL)) );
13281 DIP("std\n");
13282 break;
13283
sewardj31804462006-05-12 20:15:33 +000013284 case 0xF8: /* CLC */
13285 case 0xF9: /* STC */
13286 case 0xF5: /* CMC */
13287 t0 = newTemp(Ity_I64);
13288 t1 = newTemp(Ity_I64);
13289 assign( t0, mk_amd64g_calculate_rflags_all() );
13290 switch (opc) {
13291 case 0xF8:
13292 assign( t1, binop(Iop_And64, mkexpr(t0),
13293 mkU64(~AMD64G_CC_MASK_C)));
13294 DIP("clc\n");
13295 break;
13296 case 0xF9:
13297 assign( t1, binop(Iop_Or64, mkexpr(t0),
13298 mkU64(AMD64G_CC_MASK_C)));
13299 DIP("stc\n");
13300 break;
13301 case 0xF5:
13302 assign( t1, binop(Iop_Xor64, mkexpr(t0),
13303 mkU64(AMD64G_CC_MASK_C)));
13304 DIP("cmc\n");
13305 break;
13306 default:
13307 vpanic("disInstr(x64)(clc/stc/cmc)");
13308 }
13309 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(AMD64G_CC_OP_COPY) ));
13310 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
13311 stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(t1) ));
13312 /* Set NDEP even though it isn't used. This makes redundant-PUT
13313 elimination of previous stores to this field work better. */
13314 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU64(0) ));
13315 break;
13316
sewardjd20c8852005-01-20 20:04:07 +000013317//.. /* REPNE prefix insn */
13318//.. case 0xF2: {
13319//.. Addr32 eip_orig = guest_eip_bbstart + delta - 1;
13320//.. vassert(sorb == 0);
sewardj8c332e22005-01-28 01:36:56 +000013321//.. abyte = getUChar(delta); delta++;
sewardjd20c8852005-01-20 20:04:07 +000013322//..
sewardj8c332e22005-01-28 01:36:56 +000013323//.. if (abyte == 0x66) { sz = 2; abyte = getUChar(delta); delta++; }
sewardjd20c8852005-01-20 20:04:07 +000013324//.. whatNext = Dis_StopHere;
13325//..
13326//.. switch (abyte) {
13327//.. /* According to the Intel manual, "repne movs" should never occur, but
13328//.. * in practice it has happened, so allow for it here... */
13329//.. case 0xA4: sz = 1; /* REPNE MOVS<sz> */
13330//.. goto decode_failure;
13331//.. //-- case 0xA5:
13332//.. // dis_REP_op ( CondNZ, dis_MOVS, sz, eip_orig,
13333//.. // guest_eip_bbstart+delta, "repne movs" );
13334//.. // break;
13335//.. //--
13336//.. //-- case 0xA6: sz = 1; /* REPNE CMPS<sz> */
13337//.. //-- case 0xA7:
13338//.. //-- dis_REP_op ( cb, CondNZ, dis_CMPS, sz, eip_orig, eip, "repne cmps" );
13339//.. //-- break;
13340//.. //--
13341//.. case 0xAE: sz = 1; /* REPNE SCAS<sz> */
13342//.. case 0xAF:
13343//.. dis_REP_op ( X86CondNZ, dis_SCAS, sz, eip_orig,
13344//.. guest_eip_bbstart+delta, "repne scas" );
13345//.. break;
13346//..
13347//.. default:
13348//.. goto decode_failure;
13349//.. }
13350//.. break;
13351//.. }
sewardjd0a12df2005-02-10 02:07:43 +000013352
sewardj909c06d2005-02-19 22:47:41 +000013353 /* ------ AE: SCAS variants ------ */
13354 case 0xAE:
13355 case 0xAF:
13356 /* F2 AE/AF: repne scasb/repne scas{w,l,q} */
sewardj42561ef2005-11-04 14:18:31 +000013357 if (haveASO(pfx))
13358 goto decode_failure;
sewardj85520e42005-02-19 15:22:38 +000013359 if (haveF2(pfx) && !haveF3(pfx)) {
13360 if (opc == 0xAE)
13361 sz = 1;
13362 dis_REP_op ( AMD64CondNZ, dis_SCAS, sz,
sewardj9e6491a2005-07-02 19:24:10 +000013363 guest_RIP_curr_instr,
13364 guest_RIP_bbstart+delta, "repne scas", pfx );
13365 dres.whatNext = Dis_StopHere;
sewardj85520e42005-02-19 15:22:38 +000013366 break;
13367 }
sewardj909c06d2005-02-19 22:47:41 +000013368 /* AE/AF: scasb/scas{w,l,q} */
13369 if (!haveF2(pfx) && !haveF3(pfx)) {
13370 if (opc == 0xAE)
13371 sz = 1;
13372 dis_string_op( dis_SCAS, sz, "scas", pfx );
13373 break;
13374 }
sewardj85520e42005-02-19 15:22:38 +000013375 goto decode_failure;
sewardjd0a12df2005-02-10 02:07:43 +000013376
sewardj909c06d2005-02-19 22:47:41 +000013377 /* ------ A6, A7: CMPS variants ------ */
13378 case 0xA6:
13379 case 0xA7:
13380 /* F3 A6/A7: repe cmps/rep cmps{w,l,q} */
sewardj42561ef2005-11-04 14:18:31 +000013381 if (haveASO(pfx))
13382 goto decode_failure;
sewardjd0a12df2005-02-10 02:07:43 +000013383 if (haveF3(pfx) && !haveF2(pfx)) {
13384 if (opc == 0xA6)
13385 sz = 1;
13386 dis_REP_op ( AMD64CondZ, dis_CMPS, sz,
sewardj9e6491a2005-07-02 19:24:10 +000013387 guest_RIP_curr_instr,
13388 guest_RIP_bbstart+delta, "repe cmps", pfx );
13389 dres.whatNext = Dis_StopHere;
sewardja6b93d12005-02-17 09:28:28 +000013390 break;
13391 }
13392 goto decode_failure;
13393
sewardj909c06d2005-02-19 22:47:41 +000013394 /* ------ AA, AB: STOS variants ------ */
13395 case 0xAA:
13396 case 0xAB:
13397 /* F3 AA/AB: rep stosb/rep stos{w,l,q} */
sewardj42561ef2005-11-04 14:18:31 +000013398 if (haveASO(pfx))
13399 goto decode_failure;
sewardja6b93d12005-02-17 09:28:28 +000013400 if (haveF3(pfx) && !haveF2(pfx)) {
sewardj909c06d2005-02-19 22:47:41 +000013401 if (opc == 0xAA)
13402 sz = 1;
sewardja6b93d12005-02-17 09:28:28 +000013403 dis_REP_op ( AMD64CondAlways, dis_STOS, sz,
sewardj9e6491a2005-07-02 19:24:10 +000013404 guest_RIP_curr_instr,
13405 guest_RIP_bbstart+delta, "rep stos", pfx );
13406 dres.whatNext = Dis_StopHere;
sewardj909c06d2005-02-19 22:47:41 +000013407 break;
13408 }
13409 /* AA/AB: stosb/stos{w,l,q} */
13410 if (!haveF3(pfx) && !haveF2(pfx)) {
13411 if (opc == 0xAA)
13412 sz = 1;
13413 dis_string_op( dis_STOS, sz, "stos", pfx );
sewardjd0a12df2005-02-10 02:07:43 +000013414 break;
13415 }
13416 goto decode_failure;
13417
sewardj909c06d2005-02-19 22:47:41 +000013418 /* ------ A4, A5: MOVS variants ------ */
13419 case 0xA4:
13420 case 0xA5:
13421 /* F3 A4: rep movsb */
sewardj42561ef2005-11-04 14:18:31 +000013422 if (haveASO(pfx))
13423 goto decode_failure;
sewardj909c06d2005-02-19 22:47:41 +000013424 if (haveF3(pfx) && !haveF2(pfx)) {
13425 if (opc == 0xA4)
13426 sz = 1;
13427 dis_REP_op ( AMD64CondAlways, dis_MOVS, sz,
sewardj9e6491a2005-07-02 19:24:10 +000013428 guest_RIP_curr_instr,
13429 guest_RIP_bbstart+delta, "rep movs", pfx );
13430 dres.whatNext = Dis_StopHere;
sewardj909c06d2005-02-19 22:47:41 +000013431 break;
13432 }
13433 /* A4: movsb */
13434 if (!haveF3(pfx) && !haveF2(pfx)) {
13435 if (opc == 0xA4)
13436 sz = 1;
13437 dis_string_op( dis_MOVS, sz, "movs", pfx );
13438 break;
13439 }
13440 goto decode_failure;
13441
sewardj7de0d3c2005-02-13 02:26:41 +000013442
13443 /* ------------------------ XCHG ----------------------- */
13444
sewardj1bf95982005-05-18 12:04:04 +000013445 case 0x86: /* XCHG Gb,Eb */
13446 sz = 1;
13447 /* Fall through ... */
sewardj7de0d3c2005-02-13 02:26:41 +000013448 case 0x87: /* XCHG Gv,Ev */
sewardj5b470602005-02-27 13:10:48 +000013449 if (haveF2orF3(pfx)) goto decode_failure;
sewardj7de0d3c2005-02-13 02:26:41 +000013450 modrm = getUChar(delta);
13451 ty = szToITy(sz);
13452 t1 = newTemp(ty); t2 = newTemp(ty);
13453 if (epartIsReg(modrm)) {
sewardj5b470602005-02-27 13:10:48 +000013454 assign(t1, getIRegE(sz, pfx, modrm));
13455 assign(t2, getIRegG(sz, pfx, modrm));
13456 putIRegG(sz, pfx, modrm, mkexpr(t1));
13457 putIRegE(sz, pfx, modrm, mkexpr(t2));
sewardj7de0d3c2005-02-13 02:26:41 +000013458 delta++;
13459 DIP("xchg%c %s, %s\n",
sewardj5b470602005-02-27 13:10:48 +000013460 nameISize(sz), nameIRegG(sz, pfx, modrm),
13461 nameIRegE(sz, pfx, modrm));
sewardj7de0d3c2005-02-13 02:26:41 +000013462 } else {
sewardj7de0d3c2005-02-13 02:26:41 +000013463 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
sewardj5b470602005-02-27 13:10:48 +000013464 assign( t1, loadLE(ty, mkexpr(addr)) );
13465 assign( t2, getIRegG(sz, pfx, modrm) );
sewardj7de0d3c2005-02-13 02:26:41 +000013466 storeLE( mkexpr(addr), mkexpr(t2) );
sewardj5b470602005-02-27 13:10:48 +000013467 putIRegG( sz, pfx, modrm, mkexpr(t1) );
sewardj7de0d3c2005-02-13 02:26:41 +000013468 delta += alen;
13469 DIP("xchg%c %s, %s\n", nameISize(sz),
sewardj5b470602005-02-27 13:10:48 +000013470 nameIRegG(sz, pfx, modrm), dis_buf);
sewardj7de0d3c2005-02-13 02:26:41 +000013471 }
13472 break;
sewardj118b23e2005-01-29 02:14:44 +000013473
13474 case 0x90: /* XCHG eAX,eAX */
sewardjc8b26352005-07-20 09:23:13 +000013475 /* detect and handle F3 90 (rep nop) specially */
13476 if (!have66(pfx) && !haveF2(pfx) && haveF3(pfx)) {
13477 DIP("rep nop (P4 pause)\n");
13478 /* "observe" the hint. The Vex client needs to be careful not
13479 to cause very long delays as a result, though. */
13480 jmp_lit(Ijk_Yield, guest_RIP_bbstart+delta);
13481 dres.whatNext = Dis_StopHere;
13482 break;
13483 }
sewardj2d4fcd52005-05-18 11:47:47 +000013484 /* detect and handle NOPs specially */
13485 if (/* F2/F3 probably change meaning completely */
13486 !haveF2orF3(pfx)
13487 /* If REX.B is 1, we're not exchanging rAX with itself */
13488 && getRexB(pfx)==0 ) {
13489 DIP("nop\n");
13490 break;
13491 }
13492 /* else fall through to normal case. */
sewardja6b93d12005-02-17 09:28:28 +000013493 case 0x91: /* XCHG rAX,rCX */
13494 case 0x92: /* XCHG rAX,rDX */
13495 case 0x93: /* XCHG rAX,rBX */
13496 case 0x94: /* XCHG rAX,rSP */
13497 case 0x95: /* XCHG rAX,rBP */
13498 case 0x96: /* XCHG rAX,rSI */
13499 case 0x97: /* XCHG rAX,rDI */
sewardj2d4fcd52005-05-18 11:47:47 +000013500
13501 /* guard against mutancy */
sewardja6b93d12005-02-17 09:28:28 +000013502 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2d4fcd52005-05-18 11:47:47 +000013503
13504 /* sz == 2 could legitimately happen, but we don't handle it yet */
13505 if (sz == 2) goto decode_failure; /* awaiting test case */
13506
sewardja6b93d12005-02-17 09:28:28 +000013507 codegen_xchg_rAX_Reg ( pfx, sz, opc - 0x90 );
13508 break;
13509
sewardjd20c8852005-01-20 20:04:07 +000013510//.. //-- /* ------------------------ XLAT ----------------------- */
13511//.. //--
13512//.. //-- case 0xD7: /* XLAT */
13513//.. //-- t1 = newTemp(cb); t2 = newTemp(cb);
13514//.. //-- uInstr2(cb, GET, sz, ArchReg, R_EBX, TempReg, t1); /* get eBX */
sewardj42561ef2005-11-04 14:18:31 +000013515//.. //-- handleAddrOverrides( cb, sorb, t1 ); /* make t1 DS:eBX */
sewardjd20c8852005-01-20 20:04:07 +000013516//.. //-- uInstr2(cb, GET, 1, ArchReg, R_AL, TempReg, t2); /* get AL */
13517//.. //-- /* Widen %AL to 32 bits, so it's all defined when we add it. */
13518//.. //-- uInstr1(cb, WIDEN, 4, TempReg, t2);
13519//.. //-- uWiden(cb, 1, False);
13520//.. //-- uInstr2(cb, ADD, sz, TempReg, t2, TempReg, t1); /* add AL to eBX */
13521//.. //-- uInstr2(cb, LOAD, 1, TempReg, t1, TempReg, t2); /* get byte at t1 into t2 */
13522//.. //-- uInstr2(cb, PUT, 1, TempReg, t2, ArchReg, R_AL); /* put byte into AL */
13523//.. //--
13524//.. //-- DIP("xlat%c [ebx]\n", nameISize(sz));
13525//.. //-- break;
13526//.. //--
13527//.. //-- /* ------------------------ IN / OUT ----------------------- */
13528//.. //--
13529//.. //-- case 0xE4: /* IN ib, %al */
13530//.. //-- case 0xE5: /* IN ib, %{e}ax */
13531//.. //-- case 0xEC: /* IN (%dx),%al */
13532//.. //-- case 0xED: /* IN (%dx),%{e}ax */
13533//.. //-- t1 = newTemp(cb);
13534//.. //-- t2 = newTemp(cb);
13535//.. //-- t3 = newTemp(cb);
13536//.. //--
13537//.. //-- uInstr0(cb, CALLM_S, 0);
13538//.. //-- /* operand size? */
13539//.. //-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t1);
13540//.. //-- uLiteral(cb, ( opc == 0xE4 || opc == 0xEC ) ? 1 : sz);
13541//.. //-- uInstr1(cb, PUSH, 4, TempReg, t1);
13542//.. //-- /* port number ? */
13543//.. //-- if ( opc == 0xE4 || opc == 0xE5 ) {
13544//.. //-- abyte = getUChar(eip); eip++;
13545//.. //-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
13546//.. //-- uLiteral(cb, abyte);
13547//.. //-- }
13548//.. //-- else
13549//.. //-- uInstr2(cb, GET, 4, ArchReg, R_EDX, TempReg, t2);
13550//.. //--
13551//.. //-- uInstr1(cb, PUSH, 4, TempReg, t2);
13552//.. //-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_IN));
13553//.. //-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
13554//.. //-- uInstr1(cb, POP, 4, TempReg, t2);
13555//.. //-- uInstr1(cb, CLEAR, 0, Lit16, 4);
13556//.. //-- uInstr0(cb, CALLM_E, 0);
13557//.. //-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_EAX);
13558//.. //-- if ( opc == 0xE4 || opc == 0xE5 ) {
13559//.. //-- DIP("in 0x%x, %%eax/%%ax/%%al\n", getUChar(eip-1) );
13560//.. //-- } else {
13561//.. //-- DIP("in (%%dx), %%eax/%%ax/%%al\n");
13562//.. //-- }
13563//.. //-- break;
13564//.. //-- case 0xE6: /* OUT %al,ib */
13565//.. //-- case 0xE7: /* OUT %{e}ax,ib */
13566//.. //-- case 0xEE: /* OUT %al,(%dx) */
13567//.. //-- case 0xEF: /* OUT %{e}ax,(%dx) */
13568//.. //-- t1 = newTemp(cb);
13569//.. //-- t2 = newTemp(cb);
13570//.. //-- t3 = newTemp(cb);
13571//.. //--
13572//.. //-- uInstr0(cb, CALLM_S, 0);
13573//.. //-- /* operand size? */
13574//.. //-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t1);
13575//.. //-- uLiteral(cb, ( opc == 0xE6 || opc == 0xEE ) ? 1 : sz);
13576//.. //-- uInstr1(cb, PUSH, 4, TempReg, t1);
13577//.. //-- /* port number ? */
13578//.. //-- if ( opc == 0xE6 || opc == 0xE7 ) {
13579//.. //-- abyte = getUChar(eip); eip++;
13580//.. //-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
13581//.. //-- uLiteral(cb, abyte);
13582//.. //-- }
13583//.. //-- else
13584//.. //-- uInstr2(cb, GET, 4, ArchReg, R_EDX, TempReg, t2);
13585//.. //-- uInstr1(cb, PUSH, 4, TempReg, t2);
13586//.. //-- uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, t3);
13587//.. //-- uInstr1(cb, PUSH, 4, TempReg, t3);
13588//.. //-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_OUT));
13589//.. //-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
13590//.. //-- uInstr1(cb, CLEAR, 0, Lit16, 12);
13591//.. //-- uInstr0(cb, CALLM_E, 0);
13592//.. //-- if ( opc == 0xE4 || opc == 0xE5 ) {
13593//.. //-- DIP("out %%eax/%%ax/%%al, 0x%x\n", getUChar(eip-1) );
13594//.. //-- } else {
13595//.. //-- DIP("out %%eax/%%ax/%%al, (%%dx)\n");
13596//.. //-- }
13597//.. //-- break;
sewardj3ca55a12005-01-27 16:06:23 +000013598
13599 /* ------------------------ (Grp1 extensions) ---------- */
13600
13601 case 0x80: /* Grp1 Ib,Eb */
sewardj5b470602005-02-27 13:10:48 +000013602 if (haveF2orF3(pfx)) goto decode_failure;
sewardj8c332e22005-01-28 01:36:56 +000013603 modrm = getUChar(delta);
sewardj3ca55a12005-01-27 16:06:23 +000013604 am_sz = lengthAMode(pfx,delta);
13605 sz = 1;
13606 d_sz = 1;
13607 d64 = getSDisp8(delta + am_sz);
13608 delta = dis_Grp1 ( pfx, delta, modrm, am_sz, d_sz, sz, d64 );
13609 break;
13610
13611 case 0x81: /* Grp1 Iv,Ev */
13612 if (haveF2orF3(pfx)) goto decode_failure;
sewardj8c332e22005-01-28 01:36:56 +000013613 modrm = getUChar(delta);
sewardj3ca55a12005-01-27 16:06:23 +000013614 am_sz = lengthAMode(pfx,delta);
13615 d_sz = imin(sz,4);
13616 d64 = getSDisp(d_sz, delta + am_sz);
13617 delta = dis_Grp1 ( pfx, delta, modrm, am_sz, d_sz, sz, d64 );
13618 break;
13619
13620 case 0x83: /* Grp1 Ib,Ev */
13621 if (haveF2orF3(pfx)) goto decode_failure;
sewardj8c332e22005-01-28 01:36:56 +000013622 modrm = getUChar(delta);
sewardj3ca55a12005-01-27 16:06:23 +000013623 am_sz = lengthAMode(pfx,delta);
13624 d_sz = 1;
13625 d64 = getSDisp8(delta + am_sz);
13626 delta = dis_Grp1 ( pfx, delta, modrm, am_sz, d_sz, sz, d64 );
13627 break;
13628
sewardj118b23e2005-01-29 02:14:44 +000013629 /* ------------------------ (Grp2 extensions) ---------- */
sewardj03b07cc2005-01-31 18:09:43 +000013630
sewardj118b23e2005-01-29 02:14:44 +000013631 case 0xC0: /* Grp2 Ib,Eb */
sewardj5b470602005-02-27 13:10:48 +000013632 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000013633 modrm = getUChar(delta);
13634 am_sz = lengthAMode(pfx,delta);
13635 d_sz = 1;
13636 d64 = getUChar(delta + am_sz);
13637 sz = 1;
13638 delta = dis_Grp2 ( pfx, delta, modrm, am_sz, d_sz, sz,
13639 mkU8(d64 & 0xFF), NULL );
13640 break;
sewardj03b07cc2005-01-31 18:09:43 +000013641
sewardj118b23e2005-01-29 02:14:44 +000013642 case 0xC1: /* Grp2 Ib,Ev */
sewardj5b470602005-02-27 13:10:48 +000013643 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000013644 modrm = getUChar(delta);
13645 am_sz = lengthAMode(pfx,delta);
13646 d_sz = 1;
13647 d64 = getUChar(delta + am_sz);
13648 delta = dis_Grp2 ( pfx, delta, modrm, am_sz, d_sz, sz,
13649 mkU8(d64 & 0xFF), NULL );
13650 break;
13651
sewardj03b07cc2005-01-31 18:09:43 +000013652 case 0xD0: /* Grp2 1,Eb */
sewardj5b470602005-02-27 13:10:48 +000013653 if (haveF2orF3(pfx)) goto decode_failure;
sewardj03b07cc2005-01-31 18:09:43 +000013654 modrm = getUChar(delta);
13655 am_sz = lengthAMode(pfx,delta);
13656 d_sz = 0;
13657 d64 = 1;
13658 sz = 1;
13659 delta = dis_Grp2 ( pfx, delta, modrm, am_sz, d_sz, sz,
13660 mkU8(d64), NULL );
13661 break;
sewardj118b23e2005-01-29 02:14:44 +000013662
13663 case 0xD1: /* Grp2 1,Ev */
sewardj5b470602005-02-27 13:10:48 +000013664 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000013665 modrm = getUChar(delta);
13666 am_sz = lengthAMode(pfx,delta);
13667 d_sz = 0;
13668 d64 = 1;
13669 delta = dis_Grp2 ( pfx, delta, modrm, am_sz, d_sz, sz,
13670 mkU8(d64), NULL );
13671 break;
13672
sewardj85520e42005-02-19 15:22:38 +000013673 case 0xD2: /* Grp2 CL,Eb */
sewardj5b470602005-02-27 13:10:48 +000013674 if (haveF2orF3(pfx)) goto decode_failure;
sewardj85520e42005-02-19 15:22:38 +000013675 modrm = getUChar(delta);
13676 am_sz = lengthAMode(pfx,delta);
13677 d_sz = 0;
13678 sz = 1;
13679 delta = dis_Grp2 ( pfx, delta, modrm, am_sz, d_sz, sz,
sewardj5b470602005-02-27 13:10:48 +000013680 getIRegCL(), "%cl" );
sewardj85520e42005-02-19 15:22:38 +000013681 break;
sewardj118b23e2005-01-29 02:14:44 +000013682
13683 case 0xD3: /* Grp2 CL,Ev */
sewardj5b470602005-02-27 13:10:48 +000013684 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000013685 modrm = getUChar(delta);
13686 am_sz = lengthAMode(pfx,delta);
13687 d_sz = 0;
13688 delta = dis_Grp2 ( pfx, delta, modrm, am_sz, d_sz, sz,
sewardj5b470602005-02-27 13:10:48 +000013689 getIRegCL(), "%cl" );
sewardj118b23e2005-01-29 02:14:44 +000013690 break;
sewardj32b2bbe2005-01-28 00:50:10 +000013691
13692 /* ------------------------ (Grp3 extensions) ---------- */
13693
sewardj118b23e2005-01-29 02:14:44 +000013694 case 0xF6: /* Grp3 Eb */
sewardj5b470602005-02-27 13:10:48 +000013695 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000013696 delta = dis_Grp3 ( pfx, 1, delta );
13697 break;
sewardj32b2bbe2005-01-28 00:50:10 +000013698 case 0xF7: /* Grp3 Ev */
sewardj5b470602005-02-27 13:10:48 +000013699 if (haveF2orF3(pfx)) goto decode_failure;
sewardj32b2bbe2005-01-28 00:50:10 +000013700 delta = dis_Grp3 ( pfx, sz, delta );
13701 break;
13702
sewardj03b07cc2005-01-31 18:09:43 +000013703 /* ------------------------ (Grp4 extensions) ---------- */
13704
13705 case 0xFE: /* Grp4 Eb */
sewardj5b470602005-02-27 13:10:48 +000013706 if (haveF2orF3(pfx)) goto decode_failure;
sewardj03b07cc2005-01-31 18:09:43 +000013707 delta = dis_Grp4 ( pfx, delta );
13708 break;
sewardj354e5c62005-01-27 20:12:52 +000013709
13710 /* ------------------------ (Grp5 extensions) ---------- */
13711
13712 case 0xFF: /* Grp5 Ev */
sewardj5b470602005-02-27 13:10:48 +000013713 if (haveF2orF3(pfx)) goto decode_failure;
sewardj9e6491a2005-07-02 19:24:10 +000013714 delta = dis_Grp5 ( pfx, sz, delta, &dres );
sewardj354e5c62005-01-27 20:12:52 +000013715 break;
sewardj3ca55a12005-01-27 16:06:23 +000013716
13717 /* ------------------------ Escapes to 2-byte opcodes -- */
13718
13719 case 0x0F: {
sewardj8c332e22005-01-28 01:36:56 +000013720 opc = getUChar(delta); delta++;
sewardj3ca55a12005-01-27 16:06:23 +000013721 switch (opc) {
13722
sewardj1d511802005-03-27 17:59:45 +000013723 /* =-=-=-=-=-=-=-=-=- Grp8 =-=-=-=-=-=-=-=-=-=-=-= */
13724
13725 case 0xBA: { /* Grp8 Ib,Ev */
13726 Bool decode_OK = False;
13727 if (haveF2orF3(pfx)) goto decode_failure;
13728 modrm = getUChar(delta);
13729 am_sz = lengthAMode(pfx,delta);
13730 d64 = getSDisp8(delta + am_sz);
13731 delta = dis_Grp8_Imm ( pfx, delta, modrm, am_sz, sz, d64,
13732 &decode_OK );
13733 if (!decode_OK)
13734 goto decode_failure;
13735 break;
13736 }
13737
sewardjf53b7352005-04-06 20:01:56 +000013738 /* =-=-=-=-=-=-=-=-=- BSF/BSR -=-=-=-=-=-=-=-=-=-= */
13739
13740 case 0xBC: /* BSF Gv,Ev */
13741 if (haveF2orF3(pfx)) goto decode_failure;
13742 delta = dis_bs_E_G ( pfx, sz, delta, True );
13743 break;
sewardj537cab02005-04-07 02:03:52 +000013744 case 0xBD: /* BSR Gv,Ev */
13745 if (haveF2orF3(pfx)) goto decode_failure;
13746 delta = dis_bs_E_G ( pfx, sz, delta, False );
13747 break;
sewardj82c9f2f2005-03-02 16:05:13 +000013748
13749 /* =-=-=-=-=-=-=-=-=- BSWAP -=-=-=-=-=-=-=-=-=-=-= */
13750
13751 case 0xC8: /* BSWAP %eax */
13752 case 0xC9:
13753 case 0xCA:
13754 case 0xCB:
13755 case 0xCC:
13756 case 0xCD:
13757 case 0xCE:
13758 case 0xCF: /* BSWAP %edi */
13759 if (haveF2orF3(pfx)) goto decode_failure;
13760 /* According to the AMD64 docs, this insn can have size 4 or
13761 8. */
13762 if (sz == 4) {
13763 t1 = newTemp(Ity_I32);
13764 t2 = newTemp(Ity_I32);
13765 assign( t1, getIRegRexB(4, pfx, opc-0xC8) );
13766 assign( t2,
13767 binop(Iop_Or32,
13768 binop(Iop_Shl32, mkexpr(t1), mkU8(24)),
13769 binop(Iop_Or32,
sewardj61408222006-08-16 00:25:28 +000013770 binop(Iop_And32, binop(Iop_Shl32, mkexpr(t1), mkU8(8)),
sewardj82c9f2f2005-03-02 16:05:13 +000013771 mkU32(0x00FF0000)),
13772 binop(Iop_Or32,
13773 binop(Iop_And32, binop(Iop_Shr32, mkexpr(t1), mkU8(8)),
13774 mkU32(0x0000FF00)),
13775 binop(Iop_And32, binop(Iop_Shr32, mkexpr(t1), mkU8(24)),
13776 mkU32(0x000000FF) )
13777 )))
13778 );
13779 putIRegRexB(4, pfx, opc-0xC8, mkexpr(t2));
13780 DIP("bswapl %s\n", nameIRegRexB(4, pfx, opc-0xC8));
13781 break;
sewardj98e9f342005-07-23 12:07:37 +000013782 }
13783 else if (sz == 8) {
sewardj61408222006-08-16 00:25:28 +000013784 IRTemp m8 = newTemp(Ity_I64);
13785 IRTemp s8 = newTemp(Ity_I64);
13786 IRTemp m16 = newTemp(Ity_I64);
13787 IRTemp s16 = newTemp(Ity_I64);
13788 IRTemp m32 = newTemp(Ity_I64);
sewardj98e9f342005-07-23 12:07:37 +000013789 t1 = newTemp(Ity_I64);
13790 t2 = newTemp(Ity_I64);
13791 assign( t1, getIRegRexB(8, pfx, opc-0xC8) );
13792
sewardj61408222006-08-16 00:25:28 +000013793 assign( m8, mkU64(0xFF00FF00FF00FF00ULL) );
13794 assign( s8,
13795 binop(Iop_Or64,
13796 binop(Iop_Shr64,
13797 binop(Iop_And64,mkexpr(t1),mkexpr(m8)),
13798 mkU8(8)),
13799 binop(Iop_And64,
13800 binop(Iop_Shl64,mkexpr(t1),mkU8(8)),
13801 mkexpr(m8))
13802 )
13803 );
sewardj98e9f342005-07-23 12:07:37 +000013804
sewardj61408222006-08-16 00:25:28 +000013805 assign( m16, mkU64(0xFFFF0000FFFF0000ULL) );
13806 assign( s16,
13807 binop(Iop_Or64,
13808 binop(Iop_Shr64,
13809 binop(Iop_And64,mkexpr(s8),mkexpr(m16)),
13810 mkU8(16)),
13811 binop(Iop_And64,
13812 binop(Iop_Shl64,mkexpr(s8),mkU8(16)),
13813 mkexpr(m16))
13814 )
13815 );
sewardj98e9f342005-07-23 12:07:37 +000013816
sewardj61408222006-08-16 00:25:28 +000013817 assign( m32, mkU64(0xFFFFFFFF00000000ULL) );
13818 assign( t2,
13819 binop(Iop_Or64,
13820 binop(Iop_Shr64,
13821 binop(Iop_And64,mkexpr(s16),mkexpr(m32)),
13822 mkU8(32)),
13823 binop(Iop_And64,
13824 binop(Iop_Shl64,mkexpr(s16),mkU8(32)),
13825 mkexpr(m32))
13826 )
13827 );
sewardj98e9f342005-07-23 12:07:37 +000013828
13829 putIRegRexB(8, pfx, opc-0xC8, mkexpr(t2));
13830 DIP("bswapq %s\n", nameIRegRexB(8, pfx, opc-0xC8));
13831 break;
sewardj82c9f2f2005-03-02 16:05:13 +000013832 } else {
13833 goto decode_failure;
13834 }
13835
sewardj9ed16802005-08-24 10:46:19 +000013836 /* =-=-=-=-=-=-=-=-=- BT/BTS/BTR/BTC =-=-=-=-=-=-= */
13837
sewardja7690fb2005-10-05 17:19:11 +000013838 /* All of these are possible at sizes 2, 4 and 8, but until a
13839 size 2 test case shows up, only handle sizes 4 and 8. */
sewardj9ed16802005-08-24 10:46:19 +000013840
13841 case 0xA3: /* BT Gv,Ev */
13842 if (haveF2orF3(pfx)) goto decode_failure;
sewardj25d23862006-05-12 17:47:21 +000013843 if (sz != 8 && sz != 4 && sz != 2) goto decode_failure;
sewardj9ed16802005-08-24 10:46:19 +000013844 delta = dis_bt_G_E ( pfx, sz, delta, BtOpNone );
13845 break;
13846 case 0xB3: /* BTR Gv,Ev */
13847 if (haveF2orF3(pfx)) goto decode_failure;
sewardj25d23862006-05-12 17:47:21 +000013848 if (sz != 8 && sz != 4 && sz != 2) goto decode_failure;
sewardj9ed16802005-08-24 10:46:19 +000013849 delta = dis_bt_G_E ( pfx, sz, delta, BtOpReset );
13850 break;
13851 case 0xAB: /* BTS Gv,Ev */
13852 if (haveF2orF3(pfx)) goto decode_failure;
sewardj25d23862006-05-12 17:47:21 +000013853 if (sz != 8 && sz != 4 && sz != 2) goto decode_failure;
sewardj9ed16802005-08-24 10:46:19 +000013854 delta = dis_bt_G_E ( pfx, sz, delta, BtOpSet );
13855 break;
13856 case 0xBB: /* BTC Gv,Ev */
13857 if (haveF2orF3(pfx)) goto decode_failure;
sewardj25d23862006-05-12 17:47:21 +000013858 if (sz != 8 && sz != 4 && sz != 2) goto decode_failure;
sewardj9ed16802005-08-24 10:46:19 +000013859 delta = dis_bt_G_E ( pfx, sz, delta, BtOpComp );
13860 break;
sewardj3ca55a12005-01-27 16:06:23 +000013861
13862 /* =-=-=-=-=-=-=-=-=- CMOV =-=-=-=-=-=-=-=-=-=-=-= */
13863
13864 case 0x40:
13865 case 0x41:
13866 case 0x42: /* CMOVBb/CMOVNAEb (cmov below) */
13867 case 0x43: /* CMOVNBb/CMOVAEb (cmov not below) */
13868 case 0x44: /* CMOVZb/CMOVEb (cmov zero) */
13869 case 0x45: /* CMOVNZb/CMOVNEb (cmov not zero) */
13870 case 0x46: /* CMOVBEb/CMOVNAb (cmov below or equal) */
13871 case 0x47: /* CMOVNBEb/CMOVAb (cmov not below or equal) */
13872 case 0x48: /* CMOVSb (cmov negative) */
13873 case 0x49: /* CMOVSb (cmov not negative) */
13874 case 0x4A: /* CMOVP (cmov parity even) */
13875 case 0x4B: /* CMOVNP (cmov parity odd) */
13876 case 0x4C: /* CMOVLb/CMOVNGEb (cmov less) */
13877 case 0x4D: /* CMOVGEb/CMOVNLb (cmov greater or equal) */
13878 case 0x4E: /* CMOVLEb/CMOVNGb (cmov less or equal) */
13879 case 0x4F: /* CMOVGb/CMOVNLEb (cmov greater) */
sewardj5b470602005-02-27 13:10:48 +000013880 if (haveF2orF3(pfx)) goto decode_failure;
sewardj3ca55a12005-01-27 16:06:23 +000013881 delta = dis_cmov_E_G(pfx, sz, (AMD64Condcode)(opc - 0x40), delta);
13882 break;
13883
sewardja6b93d12005-02-17 09:28:28 +000013884 /* =-=-=-=-=-=-=-=-=- CMPXCHG -=-=-=-=-=-=-=-=-=-= */
13885
sewardjd20c8852005-01-20 20:04:07 +000013886//.. case 0xB0: /* CMPXCHG Gb,Eb */
13887//.. delta = dis_cmpxchg_G_E ( sorb, 1, delta );
13888//.. break;
sewardjd0aa0a52006-08-17 01:20:01 +000013889 case 0xB1: { /* CMPXCHG Gv,Ev (allowed in 16,32,64 bit) */
13890 Bool ok = True;
sewardj5b470602005-02-27 13:10:48 +000013891 if (haveF2orF3(pfx)) goto decode_failure;
sewardjd0aa0a52006-08-17 01:20:01 +000013892 if (sz != 2 && sz != 4 && sz != 8) goto decode_failure;
13893 delta = dis_cmpxchg_G_E ( &ok, pfx, sz, delta );
13894 if (!ok) goto decode_failure;
sewardja6b93d12005-02-17 09:28:28 +000013895 break;
sewardjd0aa0a52006-08-17 01:20:01 +000013896 }
13897 case 0xC7: { /* CMPXCHG8B Ev, CMPXCHG16B Ev */
13898 Bool ok = True;
13899 if (have66orF2orF3(pfx)) goto decode_failure;
13900 if (sz != 4 && sz != 8) goto decode_failure;
13901 delta = dis_cmpxchg8b ( &ok, pfx, sz, delta );
13902 break;
13903 }
13904
sewardjd0a12df2005-02-10 02:07:43 +000013905 /* =-=-=-=-=-=-=-=-=- CPUID -=-=-=-=-=-=-=-=-=-=-= */
13906
13907 case 0xA2: { /* CPUID */
13908 /* Uses dirty helper:
13909 void amd64g_dirtyhelper_CPUID ( VexGuestAMD64State* )
13910 declared to mod rax, wr rbx, rcx, rdx
13911 */
13912 IRDirty* d = NULL;
13913 HChar* fName = NULL;
13914 void* fAddr = NULL;
sewardj5b470602005-02-27 13:10:48 +000013915 if (haveF2orF3(pfx)) goto decode_failure;
sewardj5117ce12006-01-27 21:20:15 +000013916 if (archinfo->hwcaps == 0/*baseline, == SSE2*/) {
13917 fName = "amd64g_dirtyhelper_CPUID";
13918 fAddr = &amd64g_dirtyhelper_CPUID;
sewardjd0a12df2005-02-10 02:07:43 +000013919 }
sewardj5117ce12006-01-27 21:20:15 +000013920 else
13921 vpanic("disInstr(amd64)(cpuid)");
13922
sewardjd0a12df2005-02-10 02:07:43 +000013923 vassert(fName); vassert(fAddr);
13924 d = unsafeIRDirty_0_N ( 0/*regparms*/,
13925 fName, fAddr, mkIRExprVec_0() );
13926 /* declare guest state effects */
13927 d->needsBBP = True;
13928 d->nFxState = 4;
13929 d->fxState[0].fx = Ifx_Modify;
13930 d->fxState[0].offset = OFFB_RAX;
13931 d->fxState[0].size = 8;
13932 d->fxState[1].fx = Ifx_Write;
13933 d->fxState[1].offset = OFFB_RBX;
13934 d->fxState[1].size = 8;
13935 d->fxState[2].fx = Ifx_Write;
13936 d->fxState[2].offset = OFFB_RCX;
13937 d->fxState[2].size = 8;
13938 d->fxState[3].fx = Ifx_Write;
13939 d->fxState[3].offset = OFFB_RDX;
13940 d->fxState[3].size = 8;
13941 /* execute the dirty call, side-effecting guest state */
13942 stmt( IRStmt_Dirty(d) );
13943 /* CPUID is a serialising insn. So, just in case someone is
13944 using it as a memory fence ... */
13945 stmt( IRStmt_MFence() );
13946 DIP("cpuid\n");
13947 break;
13948 }
13949
sewardj5e525292005-01-28 15:13:10 +000013950 /* =-=-=-=-=-=-=-=-=- MOVZX, MOVSX =-=-=-=-=-=-=-= */
13951
13952 case 0xB6: /* MOVZXb Eb,Gv */
sewardj5b470602005-02-27 13:10:48 +000013953 if (haveF2orF3(pfx)) goto decode_failure;
sewardj5e525292005-01-28 15:13:10 +000013954 if (sz != 2 && sz != 4 && sz != 8)
13955 goto decode_failure;
13956 delta = dis_movx_E_G ( pfx, delta, 1, sz, False );
13957 break;
13958 case 0xB7: /* MOVZXw Ew,Gv */
sewardj5b470602005-02-27 13:10:48 +000013959 if (haveF2orF3(pfx)) goto decode_failure;
sewardj5e525292005-01-28 15:13:10 +000013960 if (sz != 4 && sz != 8)
13961 goto decode_failure;
13962 delta = dis_movx_E_G ( pfx, delta, 2, sz, False );
13963 break;
13964
sewardj03b07cc2005-01-31 18:09:43 +000013965 case 0xBE: /* MOVSXb Eb,Gv */
sewardj5b470602005-02-27 13:10:48 +000013966 if (haveF2orF3(pfx)) goto decode_failure;
sewardj82c9f2f2005-03-02 16:05:13 +000013967 if (sz != 2 && sz != 4 && sz != 8)
sewardj03b07cc2005-01-31 18:09:43 +000013968 goto decode_failure;
13969 delta = dis_movx_E_G ( pfx, delta, 1, sz, True );
13970 break;
13971 case 0xBF: /* MOVSXw Ew,Gv */
sewardj5b470602005-02-27 13:10:48 +000013972 if (haveF2orF3(pfx)) goto decode_failure;
sewardj03b07cc2005-01-31 18:09:43 +000013973 if (sz != 4 && sz != 8)
13974 goto decode_failure;
13975 delta = dis_movx_E_G ( pfx, delta, 2, sz, True );
13976 break;
13977
sewardjd20c8852005-01-20 20:04:07 +000013978//.. //-- /* =-=-=-=-=-=-=-=-=-=-= MOVNTI -=-=-=-=-=-=-=-=-= */
13979//.. //--
13980//.. //-- case 0xC3: /* MOVNTI Gv,Ev */
13981//.. //-- vg_assert(sz == 4);
13982//.. //-- modrm = getUChar(eip);
13983//.. //-- vg_assert(!epartIsReg(modrm));
13984//.. //-- t1 = newTemp(cb);
13985//.. //-- uInstr2(cb, GET, 4, ArchReg, gregOfRM(modrm), TempReg, t1);
13986//.. //-- pair = disAMode ( cb, sorb, eip, dis_buf );
13987//.. //-- t2 = LOW24(pair);
13988//.. //-- eip += HI8(pair);
13989//.. //-- uInstr2(cb, STORE, 4, TempReg, t1, TempReg, t2);
13990//.. //-- DIP("movnti %s,%s\n", nameIReg(4,gregOfRM(modrm)), dis_buf);
13991//.. //-- break;
sewardj32b2bbe2005-01-28 00:50:10 +000013992
13993 /* =-=-=-=-=-=-=-=-=- MUL/IMUL =-=-=-=-=-=-=-=-=-= */
13994
13995 case 0xAF: /* IMUL Ev, Gv */
sewardj5b470602005-02-27 13:10:48 +000013996 if (haveF2orF3(pfx)) goto decode_failure;
sewardj32b2bbe2005-01-28 00:50:10 +000013997 delta = dis_mul_E_G ( pfx, sz, delta );
13998 break;
13999
sewardjec387ca2006-08-01 18:36:25 +000014000 /* =-=-=-=-=-=-=-=-=- NOPs =-=-=-=-=-=-=-=-=-=-=-= */
14001
14002 case 0x1F:
14003 if (haveF2orF3(pfx)) goto decode_failure;
14004 modrm = getUChar(delta);
14005 if (epartIsReg(modrm)) goto decode_failure;
14006 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
14007 delta += alen;
14008 DIP("nop%c %s\n", nameISize(sz), dis_buf);
14009 break;
14010
sewardj1389d4d2005-01-28 13:46:29 +000014011 /* =-=-=-=-=-=-=-=-=- Jcond d32 -=-=-=-=-=-=-=-=-= */
14012 case 0x80:
14013 case 0x81:
14014 case 0x82: /* JBb/JNAEb (jump below) */
14015 case 0x83: /* JNBb/JAEb (jump not below) */
14016 case 0x84: /* JZb/JEb (jump zero) */
14017 case 0x85: /* JNZb/JNEb (jump not zero) */
14018 case 0x86: /* JBEb/JNAb (jump below or equal) */
14019 case 0x87: /* JNBEb/JAb (jump not below or equal) */
14020 case 0x88: /* JSb (jump negative) */
14021 case 0x89: /* JSb (jump not negative) */
14022 case 0x8A: /* JP (jump parity even) */
14023 case 0x8B: /* JNP/JPO (jump parity odd) */
14024 case 0x8C: /* JLb/JNGEb (jump less) */
14025 case 0x8D: /* JGEb/JNLb (jump greater or equal) */
14026 case 0x8E: /* JLEb/JNGb (jump less or equal) */
14027 case 0x8F: /* JGb/JNLEb (jump greater) */
sewardj5b470602005-02-27 13:10:48 +000014028 if (haveF2orF3(pfx)) goto decode_failure;
sewardj9e6491a2005-07-02 19:24:10 +000014029 d64 = (guest_RIP_bbstart+delta+4) + getSDisp32(delta);
sewardj1389d4d2005-01-28 13:46:29 +000014030 delta += 4;
14031 jcc_01( (AMD64Condcode)(opc - 0x80),
sewardj9e6491a2005-07-02 19:24:10 +000014032 guest_RIP_bbstart+delta,
sewardj1389d4d2005-01-28 13:46:29 +000014033 d64 );
sewardj9e6491a2005-07-02 19:24:10 +000014034 dres.whatNext = Dis_StopHere;
sewardj1389d4d2005-01-28 13:46:29 +000014035 DIP("j%s-32 0x%llx\n", name_AMD64Condcode(opc - 0x80), d64);
14036 break;
14037
sewardjb04a47c2005-08-10 12:27:46 +000014038 /* =-=-=-=-=-=-=-=-=- PREFETCH =-=-=-=-=-=-=-=-=-= */
14039 case 0x0D: /* 0F 0D /0 -- prefetch mem8 */
14040 /* 0F 0D /1 -- prefetchw mem8 */
14041 if (have66orF2orF3(pfx)) goto decode_failure;
14042 modrm = getUChar(delta);
14043 if (epartIsReg(modrm)) goto decode_failure;
14044 if (gregLO3ofRM(modrm) != 0 && gregLO3ofRM(modrm) != 1)
14045 goto decode_failure;
14046
14047 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
14048 delta += alen;
14049
14050 switch (gregLO3ofRM(modrm)) {
14051 case 0: DIP("prefetch %s\n", dis_buf); break;
14052 case 1: DIP("prefetchw %s\n", dis_buf); break;
14053 default: vassert(0); /*NOTREACHED*/
14054 }
14055 break;
14056
sewardj31191072005-02-05 18:24:47 +000014057 /* =-=-=-=-=-=-=-=-=- RDTSC -=-=-=-=-=-=-=-=-=-=-= */
sewardjbc6af532005-08-23 23:16:51 +000014058 case 0x31: { /* RDTSC */
14059 IRTemp val = newTemp(Ity_I64);
14060 IRExpr** args = mkIRExprVec_0();
14061 IRDirty* d = unsafeIRDirty_1_N (
14062 val,
14063 0/*regparms*/,
14064 "amd64g_dirtyhelper_RDTSC",
14065 &amd64g_dirtyhelper_RDTSC,
14066 args
14067 );
14068 if (have66orF2orF3(pfx)) goto decode_failure;
14069 /* execute the dirty call, dumping the result in val. */
14070 stmt( IRStmt_Dirty(d) );
14071 putIRegRDX(4, unop(Iop_64HIto32, mkexpr(val)));
14072 putIRegRAX(4, unop(Iop_64to32, mkexpr(val)));
sewardj31191072005-02-05 18:24:47 +000014073 DIP("rdtsc\n");
14074 break;
sewardjbc6af532005-08-23 23:16:51 +000014075 }
sewardj31191072005-02-05 18:24:47 +000014076
sewardjd20c8852005-01-20 20:04:07 +000014077//.. /* =-=-=-=-=-=-=-=-=- PUSH/POP Sreg =-=-=-=-=-=-=-=-=-= */
14078//..
14079//.. case 0xA1: /* POP %FS */
14080//.. dis_pop_segreg( R_FS, sz ); break;
14081//.. case 0xA9: /* POP %GS */
14082//.. dis_pop_segreg( R_GS, sz ); break;
14083//..
14084//.. case 0xA0: /* PUSH %FS */
14085//.. dis_push_segreg( R_FS, sz ); break;
14086//.. case 0xA8: /* PUSH %GS */
14087//.. dis_push_segreg( R_GS, sz ); break;
sewardj118b23e2005-01-29 02:14:44 +000014088
14089 /* =-=-=-=-=-=-=-=-=- SETcc Eb =-=-=-=-=-=-=-=-=-= */
14090 case 0x90:
14091 case 0x91:
14092 case 0x92: /* set-Bb/set-NAEb (set if below) */
14093 case 0x93: /* set-NBb/set-AEb (set if not below) */
14094 case 0x94: /* set-Zb/set-Eb (set if zero) */
14095 case 0x95: /* set-NZb/set-NEb (set if not zero) */
14096 case 0x96: /* set-BEb/set-NAb (set if below or equal) */
14097 case 0x97: /* set-NBEb/set-Ab (set if not below or equal) */
14098 case 0x98: /* set-Sb (set if negative) */
14099 case 0x99: /* set-Sb (set if not negative) */
14100 case 0x9A: /* set-P (set if parity even) */
14101 case 0x9B: /* set-NP (set if parity odd) */
14102 case 0x9C: /* set-Lb/set-NGEb (set if less) */
14103 case 0x9D: /* set-GEb/set-NLb (set if greater or equal) */
14104 case 0x9E: /* set-LEb/set-NGb (set if less or equal) */
14105 case 0x9F: /* set-Gb/set-NLEb (set if greater) */
sewardj5b470602005-02-27 13:10:48 +000014106 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000014107 t1 = newTemp(Ity_I8);
14108 assign( t1, unop(Iop_1Uto8,mk_amd64g_calculate_condition(opc-0x90)) );
14109 modrm = getUChar(delta);
14110 if (epartIsReg(modrm)) {
14111 delta++;
sewardj5b470602005-02-27 13:10:48 +000014112 putIRegE(1, pfx, modrm, mkexpr(t1));
sewardj118b23e2005-01-29 02:14:44 +000014113 DIP("set%s %s\n", name_AMD64Condcode(opc-0x90),
sewardj5b470602005-02-27 13:10:48 +000014114 nameIRegE(1,pfx,modrm));
sewardj118b23e2005-01-29 02:14:44 +000014115 } else {
sewardj5cc00ff2005-03-27 04:48:32 +000014116 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
14117 delta += alen;
14118 storeLE( mkexpr(addr), mkexpr(t1) );
14119 DIP("set%s %s\n", name_AMD64Condcode(opc-0x90), dis_buf);
sewardj118b23e2005-01-29 02:14:44 +000014120 }
14121 break;
14122
sewardj33ef9c22005-11-04 20:05:57 +000014123 /* =-=-=-=-=-=-=-=-=- SHLD/SHRD -=-=-=-=-=-=-=-=-= */
14124
sewardj1287ab42006-05-12 21:03:48 +000014125 case 0xA4: /* SHLDv imm8,Gv,Ev */
14126 modrm = getUChar(delta);
14127 d64 = delta + lengthAMode(pfx, delta);
14128 vex_sprintf(dis_buf, "$%d", (Int)getUChar(d64));
14129 delta = dis_SHLRD_Gv_Ev (
14130 pfx, delta, modrm, sz,
14131 mkU8(getUChar(d64)), True, /* literal */
14132 dis_buf, True /* left */ );
14133 break;
sewardj33ef9c22005-11-04 20:05:57 +000014134 case 0xA5: /* SHLDv %cl,Gv,Ev */
14135 modrm = getUChar(delta);
14136 delta = dis_SHLRD_Gv_Ev (
14137 pfx, delta, modrm, sz,
14138 getIRegCL(), False, /* not literal */
14139 "%cl", True /* left */ );
14140 break;
14141
sewardj75ce3652005-11-04 20:49:36 +000014142 case 0xAC: /* SHRDv imm8,Gv,Ev */
14143 modrm = getUChar(delta);
14144 d64 = delta + lengthAMode(pfx, delta);
14145 vex_sprintf(dis_buf, "$%d", (Int)getUChar(d64));
14146 delta = dis_SHLRD_Gv_Ev (
14147 pfx, delta, modrm, sz,
14148 mkU8(getUChar(d64)), True, /* literal */
14149 dis_buf, False /* right */ );
14150 break;
sewardj33ef9c22005-11-04 20:05:57 +000014151 case 0xAD: /* SHRDv %cl,Gv,Ev */
14152 modrm = getUChar(delta);
14153 delta = dis_SHLRD_Gv_Ev (
14154 pfx, delta, modrm, sz,
14155 getIRegCL(), False, /* not literal */
14156 "%cl", False /* right */);
14157 break;
sewardje1698952005-02-08 15:02:39 +000014158
14159 /* =-=-=-=-=-=-=-=-=- SYSCALL -=-=-=-=-=-=-=-=-=-= */
14160 case 0x05: /* SYSCALL */
sewardj9e6491a2005-07-02 19:24:10 +000014161 guest_RIP_next_mustcheck = True;
14162 guest_RIP_next_assumed = guest_RIP_bbstart + delta;
14163 putIReg64( R_RCX, mkU64(guest_RIP_next_assumed) );
sewardje1698952005-02-08 15:02:39 +000014164 /* It's important that all guest state is up-to-date
14165 at this point. So we declare an end-of-block here, which
14166 forces any cached guest state to be flushed. */
sewardj4fa325a2005-11-03 13:27:24 +000014167 jmp_lit(Ijk_Sys_syscall, guest_RIP_next_assumed);
14168 dres.whatNext = Dis_StopHere;
14169 DIP("syscall\n");
14170 break;
sewardje1698952005-02-08 15:02:39 +000014171
sewardjb4fd2e72005-03-23 13:34:11 +000014172 /* =-=-=-=-=-=-=-=-=- XADD -=-=-=-=-=-=-=-=-=-= */
14173
sewardjd20c8852005-01-20 20:04:07 +000014174//.. //-- case 0xC0: /* XADD Gb,Eb */
14175//.. //-- eip = dis_xadd_G_E ( cb, sorb, 1, eip );
14176//.. //-- break;
sewardjb4fd2e72005-03-23 13:34:11 +000014177 case 0xC1: { /* XADD Gv,Ev */
14178 Bool decode_OK = False;
14179 delta = dis_xadd_G_E ( &decode_OK, pfx, sz, delta );
14180 if (!decode_OK)
14181 goto decode_failure;
14182 break;
14183 }
14184
sewardj8711f662005-05-09 17:52:56 +000014185 /* =-=-=-=-=-=-=-=-=- MMXery =-=-=-=-=-=-=-=-=-=-= */
14186
sewardj3d8107c2005-05-09 22:23:38 +000014187 case 0x71:
14188 case 0x72:
14189 case 0x73: /* PSLLgg/PSRAgg/PSRLgg mmxreg by imm8 */
14190
14191 case 0x6E: /* MOVD (src)ireg-or-mem, (dst)mmxreg */
14192 case 0x7E: /* MOVD (src)mmxreg, (dst)ireg-or-mem */
sewardj8711f662005-05-09 17:52:56 +000014193 case 0x7F: /* MOVQ (src)mmxreg, (dst)mmxreg-or-mem */
14194 case 0x6F: /* MOVQ (src)mmxreg-or-mem, (dst)mmxreg */
14195
14196 case 0xFC:
14197 case 0xFD:
14198 case 0xFE: /* PADDgg (src)mmxreg-or-mem, (dst)mmxreg */
14199
14200 case 0xEC:
14201 case 0xED: /* PADDSgg (src)mmxreg-or-mem, (dst)mmxreg */
14202
14203 case 0xDC:
14204 case 0xDD: /* PADDUSgg (src)mmxreg-or-mem, (dst)mmxreg */
14205
14206 case 0xF8:
14207 case 0xF9:
14208 case 0xFA: /* PSUBgg (src)mmxreg-or-mem, (dst)mmxreg */
14209
14210 case 0xE8:
14211 case 0xE9: /* PSUBSgg (src)mmxreg-or-mem, (dst)mmxreg */
14212
14213 case 0xD8:
14214 case 0xD9: /* PSUBUSgg (src)mmxreg-or-mem, (dst)mmxreg */
14215
14216 case 0xE5: /* PMULHW (src)mmxreg-or-mem, (dst)mmxreg */
14217 case 0xD5: /* PMULLW (src)mmxreg-or-mem, (dst)mmxreg */
14218
14219 case 0xF5: /* PMADDWD (src)mmxreg-or-mem, (dst)mmxreg */
14220
14221 case 0x74:
14222 case 0x75:
14223 case 0x76: /* PCMPEQgg (src)mmxreg-or-mem, (dst)mmxreg */
14224
14225 case 0x64:
14226 case 0x65:
14227 case 0x66: /* PCMPGTgg (src)mmxreg-or-mem, (dst)mmxreg */
14228
14229 case 0x6B: /* PACKSSDW (src)mmxreg-or-mem, (dst)mmxreg */
14230 case 0x63: /* PACKSSWB (src)mmxreg-or-mem, (dst)mmxreg */
14231 case 0x67: /* PACKUSWB (src)mmxreg-or-mem, (dst)mmxreg */
14232
14233 case 0x68:
14234 case 0x69:
14235 case 0x6A: /* PUNPCKHgg (src)mmxreg-or-mem, (dst)mmxreg */
14236
14237 case 0x60:
14238 case 0x61:
14239 case 0x62: /* PUNPCKLgg (src)mmxreg-or-mem, (dst)mmxreg */
14240
14241 case 0xDB: /* PAND (src)mmxreg-or-mem, (dst)mmxreg */
14242 case 0xDF: /* PANDN (src)mmxreg-or-mem, (dst)mmxreg */
14243 case 0xEB: /* POR (src)mmxreg-or-mem, (dst)mmxreg */
14244 case 0xEF: /* PXOR (src)mmxreg-or-mem, (dst)mmxreg */
14245
14246 case 0xF1: /* PSLLgg (src)mmxreg-or-mem, (dst)mmxreg */
14247 case 0xF2:
14248 case 0xF3:
14249
14250 case 0xD1: /* PSRLgg (src)mmxreg-or-mem, (dst)mmxreg */
14251 case 0xD2:
14252 case 0xD3:
14253
14254 case 0xE1: /* PSRAgg (src)mmxreg-or-mem, (dst)mmxreg */
14255 case 0xE2:
14256 {
sewardj270def42005-07-03 01:03:01 +000014257 Long delta0 = delta-1;
sewardj8711f662005-05-09 17:52:56 +000014258 Bool decode_OK = False;
14259
14260 /* If sz==2 this is SSE, and we assume sse idec has
14261 already spotted those cases by now. */
sewardj3d8107c2005-05-09 22:23:38 +000014262 if (sz != 4 && sz != 8)
sewardj8711f662005-05-09 17:52:56 +000014263 goto decode_failure;
14264 if (have66orF2orF3(pfx))
14265 goto decode_failure;
14266
14267 delta = dis_MMX ( &decode_OK, pfx, sz, delta-1 );
14268 if (!decode_OK) {
14269 delta = delta0;
14270 goto decode_failure;
14271 }
14272 break;
14273 }
14274
sewardjae84d782006-04-13 22:06:35 +000014275 case 0x0E: /* FEMMS */
sewardj8711f662005-05-09 17:52:56 +000014276 case 0x77: /* EMMS */
14277 if (sz != 4)
14278 goto decode_failure;
14279 do_EMMS_preamble();
sewardjae84d782006-04-13 22:06:35 +000014280 DIP("{f}emms\n");
sewardj8711f662005-05-09 17:52:56 +000014281 break;
sewardj3ca55a12005-01-27 16:06:23 +000014282
14283 /* =-=-=-=-=-=-=-=-=- unimp2 =-=-=-=-=-=-=-=-=-=-= */
14284
14285 default:
14286 goto decode_failure;
14287 } /* switch (opc) for the 2-byte opcodes */
14288 goto decode_success;
14289 } /* case 0x0F: of primary opcode */
sewardjdf0e0022005-01-25 15:48:43 +000014290
14291 /* ------------------------ ??? ------------------------ */
14292
14293 default:
14294 decode_failure:
14295 /* All decode failures end up here. */
14296 vex_printf("vex amd64->IR: unhandled instruction bytes: "
14297 "0x%x 0x%x 0x%x 0x%x\n",
sewardj8c332e22005-01-28 01:36:56 +000014298 (Int)getUChar(delta_start+0),
14299 (Int)getUChar(delta_start+1),
14300 (Int)getUChar(delta_start+2),
14301 (Int)getUChar(delta_start+3) );
sewardjdf0e0022005-01-25 15:48:43 +000014302
14303 /* Tell the dispatcher that this insn cannot be decoded, and so has
14304 not been executed, and (is currently) the next to be executed.
14305 RIP should be up-to-date since it made so at the start of each
14306 insn, but nevertheless be paranoid and update it again right
14307 now. */
sewardj9e6491a2005-07-02 19:24:10 +000014308 stmt( IRStmt_Put( OFFB_RIP, mkU64(guest_RIP_curr_instr) ) );
14309 jmp_lit(Ijk_NoDecode, guest_RIP_curr_instr);
14310 dres.whatNext = Dis_StopHere;
14311 dres.len = 0;
14312 return dres;
sewardjdf0e0022005-01-25 15:48:43 +000014313
14314 } /* switch (opc) for the main (primary) opcode switch. */
14315
14316 decode_success:
14317 /* All decode successes end up here. */
14318 DIP("\n");
sewardj9e6491a2005-07-02 19:24:10 +000014319 dres.len = (Int)toUInt(delta - delta_start);
14320 return dres;
sewardjdf0e0022005-01-25 15:48:43 +000014321}
14322
14323#undef DIP
14324#undef DIS
sewardjd20c8852005-01-20 20:04:07 +000014325
sewardj9e6491a2005-07-02 19:24:10 +000014326
14327/*------------------------------------------------------------*/
14328/*--- Top-level fn ---*/
14329/*------------------------------------------------------------*/
14330
14331/* Disassemble a single instruction into IR. The instruction
14332 is located in host memory at &guest_code[delta]. */
14333
14334DisResult disInstr_AMD64 ( IRBB* irbb_IN,
14335 Bool put_IP,
sewardjc716aea2006-01-17 01:48:46 +000014336 Bool (*resteerOkFn) ( void*, Addr64 ),
14337 void* callback_opaque,
sewardj9e6491a2005-07-02 19:24:10 +000014338 UChar* guest_code_IN,
14339 Long delta,
14340 Addr64 guest_IP,
sewardja5f55da2006-04-30 23:37:32 +000014341 VexArch guest_arch,
sewardj9e6491a2005-07-02 19:24:10 +000014342 VexArchInfo* archinfo,
14343 Bool host_bigendian_IN )
14344{
14345 DisResult dres;
14346
14347 /* Set globals (see top of this file) */
sewardja5f55da2006-04-30 23:37:32 +000014348 vassert(guest_arch == VexArchAMD64);
sewardj9e6491a2005-07-02 19:24:10 +000014349 guest_code = guest_code_IN;
14350 irbb = irbb_IN;
14351 host_is_bigendian = host_bigendian_IN;
14352 guest_RIP_curr_instr = guest_IP;
14353 guest_RIP_bbstart = guest_IP - delta;
14354
14355 /* We'll consult these after doing disInstr_AMD64_WRK. */
14356 guest_RIP_next_assumed = 0;
14357 guest_RIP_next_mustcheck = False;
14358
sewardjc716aea2006-01-17 01:48:46 +000014359 dres = disInstr_AMD64_WRK ( put_IP, resteerOkFn, callback_opaque,
sewardj9e6491a2005-07-02 19:24:10 +000014360 delta, archinfo );
14361
14362 /* If disInstr_AMD64_WRK tried to figure out the next rip, check it
14363 got it right. Failure of this assertion is serious and denotes
14364 a bug in disInstr. */
14365 if (guest_RIP_next_mustcheck
14366 && guest_RIP_next_assumed != guest_RIP_curr_instr + dres.len) {
14367 vex_printf("\n");
14368 vex_printf("assumed next %%rip = 0x%llx\n",
14369 guest_RIP_next_assumed );
14370 vex_printf(" actual next %%rip = 0x%llx\n",
14371 guest_RIP_curr_instr + dres.len );
14372 vpanic("bbToIR_AMD64: disInstr miscalculated next %rip");
14373 }
14374
14375 return dres;
14376}
14377
14378
14379
sewardjd20c8852005-01-20 20:04:07 +000014380/*--------------------------------------------------------------------*/
14381/*--- end guest-amd64/toIR.c ---*/
14382/*--------------------------------------------------------------------*/