blob: a0f097a51bd32d00a3713bf24037d99cc201b2a0 [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
sewardjd20c8852005-01-20 20:04:07 +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, binop(Iop_PRemF64,
4899//.. mkexpr(a1), mkexpr(a2)));
4900//.. put_C3210( binop(Iop_PRemC3210F64, mkexpr(a1), mkexpr(a2)) );
4901//.. break;
4902//.. }
4903//..
sewardj5e205372005-05-09 02:57:08 +00004904 case 0xF9: /* FYL2XP1 */
4905 DIP("fyl2xp1\n");
sewardj4796d662006-02-05 16:06:26 +00004906 put_ST_UNCHECKED(1,
4907 triop(Iop_Yl2xp1F64,
4908 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4909 get_ST(1),
4910 get_ST(0)));
sewardj5e205372005-05-09 02:57:08 +00004911 fp_pop();
4912 break;
sewardje6939f02005-05-07 01:01:24 +00004913
4914 case 0xFA: /* FSQRT */
4915 DIP("fsqrt\n");
sewardj4796d662006-02-05 16:06:26 +00004916 put_ST_UNCHECKED(0,
4917 binop(Iop_SqrtF64,
4918 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4919 get_ST(0)));
sewardje6939f02005-05-07 01:01:24 +00004920 break;
4921
sewardj25a85812005-05-08 23:03:48 +00004922 case 0xFB: { /* FSINCOS */
4923 IRTemp a1 = newTemp(Ity_F64);
4924 assign( a1, get_ST(0) );
4925 DIP("fsincos\n");
sewardj4796d662006-02-05 16:06:26 +00004926 put_ST_UNCHECKED(0,
4927 binop(Iop_SinF64,
4928 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4929 mkexpr(a1)));
sewardj25a85812005-05-08 23:03:48 +00004930 fp_push();
sewardj4796d662006-02-05 16:06:26 +00004931 put_ST(0,
4932 binop(Iop_CosF64,
4933 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4934 mkexpr(a1)));
sewardj25a85812005-05-08 23:03:48 +00004935 clear_C2(); /* HACK */
4936 break;
4937 }
4938
4939 case 0xFC: /* FRNDINT */
4940 DIP("frndint\n");
4941 put_ST_UNCHECKED(0,
sewardjb183b852006-02-03 16:08:03 +00004942 binop(Iop_RoundF64toInt, get_roundingmode(), get_ST(0)) );
sewardj25a85812005-05-08 23:03:48 +00004943 break;
4944
4945 case 0xFD: /* FSCALE */
4946 DIP("fscale\n");
sewardj4796d662006-02-05 16:06:26 +00004947 put_ST_UNCHECKED(0,
4948 triop(Iop_ScaleF64,
4949 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4950 get_ST(0),
4951 get_ST(1)));
sewardj25a85812005-05-08 23:03:48 +00004952 break;
4953
4954 case 0xFE: /* FSIN */
4955 DIP("fsin\n");
sewardj4796d662006-02-05 16:06:26 +00004956 put_ST_UNCHECKED(0,
4957 binop(Iop_SinF64,
4958 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4959 get_ST(0)));
sewardj25a85812005-05-08 23:03:48 +00004960 clear_C2(); /* HACK */
4961 break;
4962
4963 case 0xFF: /* FCOS */
4964 DIP("fcos\n");
sewardj4796d662006-02-05 16:06:26 +00004965 put_ST_UNCHECKED(0,
4966 binop(Iop_CosF64,
4967 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4968 get_ST(0)));
sewardj25a85812005-05-08 23:03:48 +00004969 clear_C2(); /* HACK */
4970 break;
sewardj8d965312005-02-25 02:48:47 +00004971
4972 default:
4973 goto decode_fail;
4974 }
4975 }
4976 }
4977
4978 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDA opcodes +-+-+-+-+-+-+-+ */
4979 else
4980 if (first_opcode == 0xDA) {
4981
4982 if (modrm < 0xC0) {
4983
4984 /* bits 5,4,3 are an opcode extension, and the modRM also
4985 specifies an address. */
sewardj6847d8c2005-05-12 19:21:55 +00004986 IROp fop;
4987 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
sewardj8d965312005-02-25 02:48:47 +00004988 delta += len;
sewardj901ed122005-02-27 13:25:31 +00004989 switch (gregLO3ofRM(modrm)) {
sewardj8d965312005-02-25 02:48:47 +00004990
sewardj6847d8c2005-05-12 19:21:55 +00004991 case 0: /* FIADD m32int */ /* ST(0) += m32int */
4992 DIP("fiaddl %s\n", dis_buf);
4993 fop = Iop_AddF64;
4994 goto do_fop_m32;
4995
4996 case 1: /* FIMUL m32int */ /* ST(0) *= m32int */
4997 DIP("fimull %s\n", dis_buf);
4998 fop = Iop_MulF64;
4999 goto do_fop_m32;
5000
5001 case 4: /* FISUB m32int */ /* ST(0) -= m32int */
5002 DIP("fisubl %s\n", dis_buf);
5003 fop = Iop_SubF64;
5004 goto do_fop_m32;
5005
5006 case 5: /* FISUBR m32int */ /* ST(0) = m32int - ST(0) */
5007 DIP("fisubrl %s\n", dis_buf);
5008 fop = Iop_SubF64;
5009 goto do_foprev_m32;
5010
5011 case 6: /* FIDIV m32int */ /* ST(0) /= m32int */
5012 DIP("fisubl %s\n", dis_buf);
5013 fop = Iop_DivF64;
5014 goto do_fop_m32;
5015
5016 case 7: /* FIDIVR m32int */ /* ST(0) = m32int / ST(0) */
5017 DIP("fidivrl %s\n", dis_buf);
5018 fop = Iop_DivF64;
5019 goto do_foprev_m32;
5020
5021 do_fop_m32:
5022 put_ST_UNCHECKED(0,
sewardj4796d662006-02-05 16:06:26 +00005023 triop(fop,
5024 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardj6847d8c2005-05-12 19:21:55 +00005025 get_ST(0),
5026 unop(Iop_I32toF64,
5027 loadLE(Ity_I32, mkexpr(addr)))));
5028 break;
5029
5030 do_foprev_m32:
5031 put_ST_UNCHECKED(0,
sewardj4796d662006-02-05 16:06:26 +00005032 triop(fop,
5033 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardj6847d8c2005-05-12 19:21:55 +00005034 unop(Iop_I32toF64,
5035 loadLE(Ity_I32, mkexpr(addr))),
5036 get_ST(0)));
5037 break;
sewardj8d965312005-02-25 02:48:47 +00005038
5039 default:
sewardj901ed122005-02-27 13:25:31 +00005040 vex_printf("unhandled opc_aux = 0x%2x\n", gregLO3ofRM(modrm));
sewardj8d965312005-02-25 02:48:47 +00005041 vex_printf("first_opcode == 0xDA\n");
5042 goto decode_fail;
5043 }
5044
5045 } else {
5046
5047 delta++;
5048 switch (modrm) {
5049
sewardj48a89d82005-05-06 11:50:13 +00005050 case 0xC0 ... 0xC7: /* FCMOVB ST(i), ST(0) */
5051 r_src = (UInt)modrm - 0xC0;
sewardjca673ab2005-05-11 10:03:08 +00005052 DIP("fcmovb %%st(%u), %%st(0)\n", r_src);
sewardj48a89d82005-05-06 11:50:13 +00005053 put_ST_UNCHECKED(0,
5054 IRExpr_Mux0X(
5055 unop(Iop_1Uto8,
5056 mk_amd64g_calculate_condition(AMD64CondB)),
5057 get_ST(0), get_ST(r_src)) );
5058 break;
sewardj8d965312005-02-25 02:48:47 +00005059
5060 case 0xC8 ... 0xCF: /* FCMOVE(Z) ST(i), ST(0) */
5061 r_src = (UInt)modrm - 0xC8;
sewardj1027dc22005-02-26 01:55:02 +00005062 DIP("fcmovz %%st(%u), %%st(0)\n", r_src);
sewardj8d965312005-02-25 02:48:47 +00005063 put_ST_UNCHECKED(0,
5064 IRExpr_Mux0X(
5065 unop(Iop_1Uto8,
5066 mk_amd64g_calculate_condition(AMD64CondZ)),
5067 get_ST(0), get_ST(r_src)) );
5068 break;
5069
sewardj37d52572005-02-25 14:22:12 +00005070 case 0xD0 ... 0xD7: /* FCMOVBE ST(i), ST(0) */
5071 r_src = (UInt)modrm - 0xD0;
sewardj1027dc22005-02-26 01:55:02 +00005072 DIP("fcmovbe %%st(%u), %%st(0)\n", r_src);
sewardj37d52572005-02-25 14:22:12 +00005073 put_ST_UNCHECKED(0,
5074 IRExpr_Mux0X(
5075 unop(Iop_1Uto8,
5076 mk_amd64g_calculate_condition(AMD64CondBE)),
5077 get_ST(0), get_ST(r_src)) );
5078 break;
5079
sewardj25a85812005-05-08 23:03:48 +00005080 case 0xD8 ... 0xDF: /* FCMOVU ST(i), ST(0) */
5081 r_src = (UInt)modrm - 0xD8;
5082 DIP("fcmovu %%st(%u), %%st(0)\n", r_src);
5083 put_ST_UNCHECKED(0,
5084 IRExpr_Mux0X(
5085 unop(Iop_1Uto8,
5086 mk_amd64g_calculate_condition(AMD64CondP)),
5087 get_ST(0), get_ST(r_src)) );
5088 break;
5089
sewardjd20c8852005-01-20 20:04:07 +00005090//.. case 0xE9: /* FUCOMPP %st(0),%st(1) */
5091//.. DIP("fucompp %%st(0),%%st(1)\n");
5092//.. /* This forces C1 to zero, which isn't right. */
5093//.. put_C3210(
5094//.. binop( Iop_And32,
5095//.. binop(Iop_Shl32,
5096//.. binop(Iop_CmpF64, get_ST(0), get_ST(1)),
5097//.. mkU8(8)),
5098//.. mkU32(0x4500)
5099//.. ));
5100//.. fp_pop();
5101//.. fp_pop();
5102//.. break;
sewardj8d965312005-02-25 02:48:47 +00005103
5104 default:
5105 goto decode_fail;
5106 }
5107
5108 }
5109 }
5110
sewardjc49ce232005-02-25 13:03:03 +00005111 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDB opcodes +-+-+-+-+-+-+-+ */
5112 else
5113 if (first_opcode == 0xDB) {
5114 if (modrm < 0xC0) {
5115
5116 /* bits 5,4,3 are an opcode extension, and the modRM also
5117 specifies an address. */
5118 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
5119 delta += len;
5120
sewardj901ed122005-02-27 13:25:31 +00005121 switch (gregLO3ofRM(modrm)) {
sewardjc49ce232005-02-25 13:03:03 +00005122
sewardj5cc00ff2005-03-27 04:48:32 +00005123 case 0: /* FILD m32int */
5124 DIP("fildl %s\n", dis_buf);
5125 fp_push();
5126 put_ST(0, unop(Iop_I32toF64,
5127 loadLE(Ity_I32, mkexpr(addr))));
5128 break;
5129
sewardj6847d8c2005-05-12 19:21:55 +00005130 case 2: /* FIST m32 */
5131 DIP("fistl %s\n", dis_buf);
5132 storeLE( mkexpr(addr),
5133 binop(Iop_F64toI32, get_roundingmode(), get_ST(0)) );
5134 break;
sewardj37d52572005-02-25 14:22:12 +00005135
5136 case 3: /* FISTP m32 */
5137 DIP("fistpl %s\n", dis_buf);
5138 storeLE( mkexpr(addr),
5139 binop(Iop_F64toI32, get_roundingmode(), get_ST(0)) );
5140 fp_pop();
5141 break;
5142
sewardj924215b2005-03-26 21:50:31 +00005143 case 5: { /* FLD extended-real */
5144 /* Uses dirty helper:
5145 ULong amd64g_loadF80le ( ULong )
5146 addr holds the address. First, do a dirty call to
5147 get hold of the data. */
5148 IRTemp val = newTemp(Ity_I64);
5149 IRExpr** args = mkIRExprVec_1 ( mkexpr(addr) );
5150
5151 IRDirty* d = unsafeIRDirty_1_N (
5152 val,
5153 0/*regparms*/,
sewardj8707fef2005-08-23 23:26:37 +00005154 "amd64g_dirtyhelper_loadF80le",
5155 &amd64g_dirtyhelper_loadF80le,
sewardj924215b2005-03-26 21:50:31 +00005156 args
5157 );
5158 /* declare that we're reading memory */
5159 d->mFx = Ifx_Read;
5160 d->mAddr = mkexpr(addr);
5161 d->mSize = 10;
5162
5163 /* execute the dirty call, dumping the result in val. */
5164 stmt( IRStmt_Dirty(d) );
5165 fp_push();
5166 put_ST(0, unop(Iop_ReinterpI64asF64, mkexpr(val)));
5167
5168 DIP("fldt %s\n", dis_buf);
5169 break;
5170 }
5171
5172 case 7: { /* FSTP extended-real */
5173 /* Uses dirty helper:
5174 void amd64g_storeF80le ( ULong addr, ULong data )
5175 */
5176 IRExpr** args
5177 = mkIRExprVec_2( mkexpr(addr),
5178 unop(Iop_ReinterpF64asI64, get_ST(0)) );
5179
5180 IRDirty* d = unsafeIRDirty_0_N (
5181 0/*regparms*/,
sewardj8707fef2005-08-23 23:26:37 +00005182 "amd64g_dirtyhelper_storeF80le",
5183 &amd64g_dirtyhelper_storeF80le,
sewardj924215b2005-03-26 21:50:31 +00005184 args
5185 );
5186 /* declare we're writing memory */
5187 d->mFx = Ifx_Write;
5188 d->mAddr = mkexpr(addr);
5189 d->mSize = 10;
5190
5191 /* execute the dirty call. */
5192 stmt( IRStmt_Dirty(d) );
5193 fp_pop();
5194
5195 DIP("fstpt\n %s", dis_buf);
5196 break;
5197 }
sewardjc49ce232005-02-25 13:03:03 +00005198
5199 default:
sewardj901ed122005-02-27 13:25:31 +00005200 vex_printf("unhandled opc_aux = 0x%2x\n", gregLO3ofRM(modrm));
sewardjc49ce232005-02-25 13:03:03 +00005201 vex_printf("first_opcode == 0xDB\n");
5202 goto decode_fail;
5203 }
5204
5205 } else {
5206
5207 delta++;
5208 switch (modrm) {
5209
sewardj48a89d82005-05-06 11:50:13 +00005210 case 0xC0 ... 0xC7: /* FCMOVNB ST(i), ST(0) */
5211 r_src = (UInt)modrm - 0xC0;
sewardjca673ab2005-05-11 10:03:08 +00005212 DIP("fcmovnb %%st(%u), %%st(0)\n", r_src);
sewardj48a89d82005-05-06 11:50:13 +00005213 put_ST_UNCHECKED(0,
5214 IRExpr_Mux0X(
5215 unop(Iop_1Uto8,
5216 mk_amd64g_calculate_condition(AMD64CondNB)),
5217 get_ST(0), get_ST(r_src)) );
5218 break;
sewardj924215b2005-03-26 21:50:31 +00005219
5220 case 0xC8 ... 0xCF: /* FCMOVNE(NZ) ST(i), ST(0) */
5221 r_src = (UInt)modrm - 0xC8;
sewardj40e144d2005-03-28 00:46:27 +00005222 DIP("fcmovnz %%st(%u), %%st(0)\n", r_src);
sewardj137015d2005-03-27 04:01:15 +00005223 put_ST_UNCHECKED(
5224 0,
5225 IRExpr_Mux0X(
5226 unop(Iop_1Uto8,
5227 mk_amd64g_calculate_condition(AMD64CondNZ)),
5228 get_ST(0),
5229 get_ST(r_src)
5230 )
5231 );
sewardj924215b2005-03-26 21:50:31 +00005232 break;
5233
sewardj137015d2005-03-27 04:01:15 +00005234 case 0xD0 ... 0xD7: /* FCMOVNBE ST(i), ST(0) */
5235 r_src = (UInt)modrm - 0xD0;
sewardj40e144d2005-03-28 00:46:27 +00005236 DIP("fcmovnbe %%st(%u), %%st(0)\n", r_src);
sewardj137015d2005-03-27 04:01:15 +00005237 put_ST_UNCHECKED(
5238 0,
5239 IRExpr_Mux0X(
5240 unop(Iop_1Uto8,
5241 mk_amd64g_calculate_condition(AMD64CondNBE)),
5242 get_ST(0),
5243 get_ST(r_src)
5244 )
5245 );
5246 break;
5247
sewardj3368e102006-03-06 19:05:07 +00005248 case 0xD8 ... 0xDF: /* FCMOVNU ST(i), ST(0) */
5249 r_src = (UInt)modrm - 0xD8;
5250 DIP("fcmovnu %%st(%u), %%st(0)\n", r_src);
5251 put_ST_UNCHECKED(
5252 0,
5253 IRExpr_Mux0X(
5254 unop(Iop_1Uto8,
5255 mk_amd64g_calculate_condition(AMD64CondNP)),
5256 get_ST(0),
5257 get_ST(r_src)
5258 )
5259 );
5260 break;
5261
sewardj4e1a1e92005-05-25 00:44:13 +00005262 case 0xE2:
5263 DIP("fnclex\n");
5264 break;
5265
sewardj0585a032005-11-05 02:55:06 +00005266 case 0xE3: {
5267 /* Uses dirty helper:
5268 void amd64g_do_FINIT ( VexGuestAMD64State* ) */
5269 IRDirty* d = unsafeIRDirty_0_N (
5270 0/*regparms*/,
5271 "amd64g_dirtyhelper_FINIT",
5272 &amd64g_dirtyhelper_FINIT,
5273 mkIRExprVec_0()
5274 );
5275 d->needsBBP = True;
5276
5277 /* declare we're writing guest state */
5278 d->nFxState = 5;
5279
5280 d->fxState[0].fx = Ifx_Write;
5281 d->fxState[0].offset = OFFB_FTOP;
5282 d->fxState[0].size = sizeof(UInt);
5283
5284 d->fxState[1].fx = Ifx_Write;
5285 d->fxState[1].offset = OFFB_FPREGS;
5286 d->fxState[1].size = 8 * sizeof(ULong);
5287
5288 d->fxState[2].fx = Ifx_Write;
5289 d->fxState[2].offset = OFFB_FPTAGS;
5290 d->fxState[2].size = 8 * sizeof(UChar);
5291
5292 d->fxState[3].fx = Ifx_Write;
5293 d->fxState[3].offset = OFFB_FPROUND;
5294 d->fxState[3].size = sizeof(ULong);
5295
5296 d->fxState[4].fx = Ifx_Write;
5297 d->fxState[4].offset = OFFB_FC3210;
5298 d->fxState[4].size = sizeof(ULong);
5299
5300 stmt( IRStmt_Dirty(d) );
5301
5302 DIP("fninit\n");
5303 break;
5304 }
sewardjc49ce232005-02-25 13:03:03 +00005305
5306 case 0xE8 ... 0xEF: /* FUCOMI %st(0),%st(?) */
5307 fp_do_ucomi_ST0_STi( (UInt)modrm - 0xE8, False );
5308 break;
5309
sewardj48a89d82005-05-06 11:50:13 +00005310 case 0xF0 ... 0xF7: /* FCOMI %st(0),%st(?) */
5311 fp_do_ucomi_ST0_STi( (UInt)modrm - 0xF0, False );
5312 break;
sewardjc49ce232005-02-25 13:03:03 +00005313
5314 default:
5315 goto decode_fail;
5316 }
5317 }
5318 }
5319
sewardj137015d2005-03-27 04:01:15 +00005320 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDC opcodes +-+-+-+-+-+-+-+ */
5321 else
5322 if (first_opcode == 0xDC) {
5323 if (modrm < 0xC0) {
5324
sewardj434e0692005-03-27 17:36:08 +00005325 /* bits 5,4,3 are an opcode extension, and the modRM also
5326 specifies an address. */
5327 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
5328 delta += len;
5329
5330 switch (gregLO3ofRM(modrm)) {
5331
sewardje6939f02005-05-07 01:01:24 +00005332 case 0: /* FADD double-real */
5333 fp_do_op_mem_ST_0 ( addr, "add", dis_buf, Iop_AddF64, True );
5334 break;
5335
5336 case 1: /* FMUL double-real */
5337 fp_do_op_mem_ST_0 ( addr, "mul", dis_buf, Iop_MulF64, True );
5338 break;
5339
sewardjd20c8852005-01-20 20:04:07 +00005340//.. case 2: /* FCOM double-real */
5341//.. DIP("fcoml %s\n", dis_buf);
5342//.. /* This forces C1 to zero, which isn't right. */
5343//.. put_C3210(
5344//.. binop( Iop_And32,
5345//.. binop(Iop_Shl32,
5346//.. binop(Iop_CmpF64,
5347//.. get_ST(0),
5348//.. loadLE(Ity_F64,mkexpr(addr))),
5349//.. mkU8(8)),
5350//.. mkU32(0x4500)
5351//.. ));
5352//.. break;
sewardj566d2c72005-08-10 11:43:42 +00005353
5354 case 3: /* FCOMP double-real */
5355 DIP("fcompl %s\n", dis_buf);
5356 /* This forces C1 to zero, which isn't right. */
5357 put_C3210(
5358 unop(Iop_32Uto64,
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 fp_pop();
5368 break;
sewardje6939f02005-05-07 01:01:24 +00005369
5370 case 4: /* FSUB double-real */
5371 fp_do_op_mem_ST_0 ( addr, "sub", dis_buf, Iop_SubF64, True );
5372 break;
sewardj434e0692005-03-27 17:36:08 +00005373
5374 case 5: /* FSUBR double-real */
5375 fp_do_oprev_mem_ST_0 ( addr, "subr", dis_buf, Iop_SubF64, True );
5376 break;
5377
sewardje6939f02005-05-07 01:01:24 +00005378 case 6: /* FDIV double-real */
5379 fp_do_op_mem_ST_0 ( addr, "div", dis_buf, Iop_DivF64, True );
5380 break;
5381
5382 case 7: /* FDIVR double-real */
5383 fp_do_oprev_mem_ST_0 ( addr, "divr", dis_buf, Iop_DivF64, True );
5384 break;
sewardj434e0692005-03-27 17:36:08 +00005385
5386 default:
5387 vex_printf("unhandled opc_aux = 0x%2x\n", gregLO3ofRM(modrm));
5388 vex_printf("first_opcode == 0xDC\n");
5389 goto decode_fail;
5390 }
sewardj137015d2005-03-27 04:01:15 +00005391
5392 } else {
5393
5394 delta++;
5395 switch (modrm) {
5396
5397 case 0xC0 ... 0xC7: /* FADD %st(0),%st(?) */
5398 fp_do_op_ST_ST ( "add", Iop_AddF64, 0, modrm - 0xC0, False );
5399 break;
5400
sewardj7bc00082005-03-27 05:08:32 +00005401 case 0xC8 ... 0xCF: /* FMUL %st(0),%st(?) */
5402 fp_do_op_ST_ST ( "mul", Iop_MulF64, 0, modrm - 0xC8, False );
5403 break;
5404
sewardj434e0692005-03-27 17:36:08 +00005405 case 0xE0 ... 0xE7: /* FSUBR %st(0),%st(?) */
5406 fp_do_oprev_ST_ST ( "subr", Iop_SubF64, 0, modrm - 0xE0, False );
5407 break;
5408
sewardje6939f02005-05-07 01:01:24 +00005409 case 0xE8 ... 0xEF: /* FSUB %st(0),%st(?) */
5410 fp_do_op_ST_ST ( "sub", Iop_SubF64, 0, modrm - 0xE8, False );
5411 break;
5412
5413 case 0xF0 ... 0xF7: /* FDIVR %st(0),%st(?) */
5414 fp_do_oprev_ST_ST ( "divr", Iop_DivF64, 0, modrm - 0xF0, False );
5415 break;
sewardj137015d2005-03-27 04:01:15 +00005416
5417 case 0xF8 ... 0xFF: /* FDIV %st(0),%st(?) */
5418 fp_do_op_ST_ST ( "div", Iop_DivF64, 0, modrm - 0xF8, False );
5419 break;
5420
5421 default:
5422 goto decode_fail;
5423 }
5424
5425 }
5426 }
sewardj8d965312005-02-25 02:48:47 +00005427
5428 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDD opcodes +-+-+-+-+-+-+-+ */
5429 else
5430 if (first_opcode == 0xDD) {
5431
5432 if (modrm < 0xC0) {
5433
5434 /* bits 5,4,3 are an opcode extension, and the modRM also
5435 specifies an address. */
5436 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
5437 delta += len;
5438
sewardj901ed122005-02-27 13:25:31 +00005439 switch (gregLO3ofRM(modrm)) {
sewardj8d965312005-02-25 02:48:47 +00005440
5441 case 0: /* FLD double-real */
5442 DIP("fldl %s\n", dis_buf);
5443 fp_push();
sewardjaf1ceca2005-06-30 23:31:27 +00005444 put_ST(0, loadLE(Ity_F64, mkexpr(addr)));
sewardj8d965312005-02-25 02:48:47 +00005445 break;
5446
sewardjc49ce232005-02-25 13:03:03 +00005447 case 2: /* FST double-real */
5448 DIP("fstl %s\n", dis_buf);
5449 storeLE(mkexpr(addr), get_ST(0));
5450 break;
sewardj8d965312005-02-25 02:48:47 +00005451
5452 case 3: /* FSTP double-real */
5453 DIP("fstpl %s\n", dis_buf);
5454 storeLE(mkexpr(addr), get_ST(0));
5455 fp_pop();
5456 break;
5457
sewardjd20c8852005-01-20 20:04:07 +00005458//.. case 4: { /* FRSTOR m108 */
5459//.. /* Uses dirty helper:
5460//.. VexEmWarn x86g_do_FRSTOR ( VexGuestX86State*, Addr32 ) */
5461//.. IRTemp ew = newTemp(Ity_I32);
5462//.. IRDirty* d = unsafeIRDirty_0_N (
5463//.. 0/*regparms*/,
5464//.. "x86g_dirtyhelper_FRSTOR",
5465//.. &x86g_dirtyhelper_FRSTOR,
5466//.. mkIRExprVec_1( mkexpr(addr) )
5467//.. );
5468//.. d->needsBBP = True;
5469//.. d->tmp = ew;
5470//.. /* declare we're reading memory */
5471//.. d->mFx = Ifx_Read;
5472//.. d->mAddr = mkexpr(addr);
5473//.. d->mSize = 108;
5474//..
5475//.. /* declare we're writing guest state */
5476//.. d->nFxState = 5;
5477//..
5478//.. d->fxState[0].fx = Ifx_Write;
5479//.. d->fxState[0].offset = OFFB_FTOP;
5480//.. d->fxState[0].size = sizeof(UInt);
5481//..
5482//.. d->fxState[1].fx = Ifx_Write;
5483//.. d->fxState[1].offset = OFFB_FPREGS;
5484//.. d->fxState[1].size = 8 * sizeof(ULong);
5485//..
5486//.. d->fxState[2].fx = Ifx_Write;
5487//.. d->fxState[2].offset = OFFB_FPTAGS;
5488//.. d->fxState[2].size = 8 * sizeof(UChar);
5489//..
5490//.. d->fxState[3].fx = Ifx_Write;
5491//.. d->fxState[3].offset = OFFB_FPROUND;
5492//.. d->fxState[3].size = sizeof(UInt);
5493//..
5494//.. d->fxState[4].fx = Ifx_Write;
5495//.. d->fxState[4].offset = OFFB_FC3210;
5496//.. d->fxState[4].size = sizeof(UInt);
5497//..
5498//.. stmt( IRStmt_Dirty(d) );
5499//..
5500//.. /* ew contains any emulation warning we may need to
5501//.. issue. If needed, side-exit to the next insn,
5502//.. reporting the warning, so that Valgrind's dispatcher
5503//.. sees the warning. */
5504//.. put_emwarn( mkexpr(ew) );
5505//.. stmt(
5506//.. IRStmt_Exit(
5507//.. binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
5508//.. Ijk_EmWarn,
5509//.. IRConst_U32( ((Addr32)guest_eip_bbstart)+delta)
5510//.. )
5511//.. );
5512//..
5513//.. DIP("frstor %s\n", dis_buf);
5514//.. break;
5515//.. }
5516//..
5517//.. case 6: { /* FNSAVE m108 */
5518//.. /* Uses dirty helper:
5519//.. void x86g_do_FSAVE ( VexGuestX86State*, UInt ) */
5520//.. IRDirty* d = unsafeIRDirty_0_N (
5521//.. 0/*regparms*/,
5522//.. "x86g_dirtyhelper_FSAVE",
5523//.. &x86g_dirtyhelper_FSAVE,
5524//.. mkIRExprVec_1( mkexpr(addr) )
5525//.. );
5526//.. d->needsBBP = True;
5527//.. /* declare we're writing memory */
5528//.. d->mFx = Ifx_Write;
5529//.. d->mAddr = mkexpr(addr);
5530//.. d->mSize = 108;
5531//..
5532//.. /* declare we're reading guest state */
5533//.. d->nFxState = 5;
5534//..
5535//.. d->fxState[0].fx = Ifx_Read;
5536//.. d->fxState[0].offset = OFFB_FTOP;
5537//.. d->fxState[0].size = sizeof(UInt);
5538//..
5539//.. d->fxState[1].fx = Ifx_Read;
5540//.. d->fxState[1].offset = OFFB_FPREGS;
5541//.. d->fxState[1].size = 8 * sizeof(ULong);
5542//..
5543//.. d->fxState[2].fx = Ifx_Read;
5544//.. d->fxState[2].offset = OFFB_FPTAGS;
5545//.. d->fxState[2].size = 8 * sizeof(UChar);
5546//..
5547//.. d->fxState[3].fx = Ifx_Read;
5548//.. d->fxState[3].offset = OFFB_FPROUND;
5549//.. d->fxState[3].size = sizeof(UInt);
5550//..
5551//.. d->fxState[4].fx = Ifx_Read;
5552//.. d->fxState[4].offset = OFFB_FC3210;
5553//.. d->fxState[4].size = sizeof(UInt);
5554//..
5555//.. stmt( IRStmt_Dirty(d) );
5556//..
5557//.. DIP("fnsave %s\n", dis_buf);
5558//.. break;
5559//.. }
sewardj8d965312005-02-25 02:48:47 +00005560
sewardj7c2d2822006-03-07 00:22:02 +00005561 case 7: { /* FNSTSW m16 */
5562 IRExpr* sw = get_FPU_sw();
5563 vassert(typeOfIRExpr(irbb->tyenv, sw) == Ity_I16);
5564 storeLE( mkexpr(addr), sw );
5565 DIP("fnstsw %s\n", dis_buf);
5566 break;
5567 }
5568
sewardj8d965312005-02-25 02:48:47 +00005569 default:
sewardj901ed122005-02-27 13:25:31 +00005570 vex_printf("unhandled opc_aux = 0x%2x\n", gregLO3ofRM(modrm));
sewardj8d965312005-02-25 02:48:47 +00005571 vex_printf("first_opcode == 0xDD\n");
5572 goto decode_fail;
5573 }
5574 } else {
5575 delta++;
5576 switch (modrm) {
5577
sewardj6847d8c2005-05-12 19:21:55 +00005578 case 0xC0 ... 0xC7: /* FFREE %st(?) */
5579 r_dst = (UInt)modrm - 0xC0;
5580 DIP("ffree %%st(%u)\n", r_dst);
5581 put_ST_TAG ( r_dst, mkU8(0) );
5582 break;
5583
sewardjbfabcc42005-08-08 09:58:05 +00005584 case 0xD0 ... 0xD7: /* FST %st(0),%st(?) */
5585 r_dst = (UInt)modrm - 0xD0;
sewardjc7cd2142005-09-09 22:31:49 +00005586 DIP("fst %%st(0),%%st(%u)\n", r_dst);
sewardjbfabcc42005-08-08 09:58:05 +00005587 /* P4 manual says: "If the destination operand is a
5588 non-empty register, the invalid-operation exception
5589 is not generated. Hence put_ST_UNCHECKED. */
5590 put_ST_UNCHECKED(r_dst, get_ST(0));
5591 break;
sewardj8d965312005-02-25 02:48:47 +00005592
5593 case 0xD8 ... 0xDF: /* FSTP %st(0),%st(?) */
5594 r_dst = (UInt)modrm - 0xD8;
sewardj1027dc22005-02-26 01:55:02 +00005595 DIP("fstp %%st(0),%%st(%u)\n", r_dst);
sewardj8d965312005-02-25 02:48:47 +00005596 /* P4 manual says: "If the destination operand is a
5597 non-empty register, the invalid-operation exception
5598 is not generated. Hence put_ST_UNCHECKED. */
5599 put_ST_UNCHECKED(r_dst, get_ST(0));
5600 fp_pop();
5601 break;
5602
sewardjfb6c1792005-10-05 17:58:32 +00005603 case 0xE0 ... 0xE7: /* FUCOM %st(0),%st(?) */
5604 r_dst = (UInt)modrm - 0xE0;
sewardj62d05432005-10-29 22:30:47 +00005605 DIP("fucom %%st(0),%%st(%u)\n", r_dst);
sewardjfb6c1792005-10-05 17:58:32 +00005606 /* This forces C1 to zero, which isn't right. */
5607 put_C3210(
5608 unop(Iop_32Uto64,
5609 binop( Iop_And32,
5610 binop(Iop_Shl32,
5611 binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
5612 mkU8(8)),
5613 mkU32(0x4500)
5614 )));
5615 break;
5616
sewardj9fb2f472005-11-05 01:12:18 +00005617 case 0xE8 ... 0xEF: /* FUCOMP %st(0),%st(?) */
5618 r_dst = (UInt)modrm - 0xE8;
sewardj43f45732005-11-05 13:04:34 +00005619 DIP("fucomp %%st(0),%%st(%u)\n", r_dst);
sewardj9fb2f472005-11-05 01:12:18 +00005620 /* This forces C1 to zero, which isn't right. */
5621 put_C3210(
5622 unop(Iop_32Uto64,
5623 binop( Iop_And32,
5624 binop(Iop_Shl32,
5625 binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
5626 mkU8(8)),
5627 mkU32(0x4500)
5628 )));
5629 fp_pop();
5630 break;
sewardj8d965312005-02-25 02:48:47 +00005631
5632 default:
5633 goto decode_fail;
5634 }
5635 }
5636 }
5637
sewardj137015d2005-03-27 04:01:15 +00005638 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDE opcodes +-+-+-+-+-+-+-+ */
5639 else
5640 if (first_opcode == 0xDE) {
5641
5642 if (modrm < 0xC0) {
5643
sewardj6847d8c2005-05-12 19:21:55 +00005644 /* bits 5,4,3 are an opcode extension, and the modRM also
5645 specifies an address. */
5646 IROp fop;
5647 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
5648 delta += len;
5649
5650 switch (gregLO3ofRM(modrm)) {
5651
5652 case 0: /* FIADD m16int */ /* ST(0) += m16int */
5653 DIP("fiaddw %s\n", dis_buf);
5654 fop = Iop_AddF64;
5655 goto do_fop_m16;
5656
5657 case 1: /* FIMUL m16int */ /* ST(0) *= m16int */
5658 DIP("fimulw %s\n", dis_buf);
5659 fop = Iop_MulF64;
5660 goto do_fop_m16;
5661
5662 case 4: /* FISUB m16int */ /* ST(0) -= m16int */
5663 DIP("fisubw %s\n", dis_buf);
5664 fop = Iop_SubF64;
5665 goto do_fop_m16;
5666
5667 case 5: /* FISUBR m16int */ /* ST(0) = m16int - ST(0) */
5668 DIP("fisubrw %s\n", dis_buf);
5669 fop = Iop_SubF64;
5670 goto do_foprev_m16;
5671
5672 case 6: /* FIDIV m16int */ /* ST(0) /= m16int */
5673 DIP("fisubw %s\n", dis_buf);
5674 fop = Iop_DivF64;
5675 goto do_fop_m16;
5676
5677 case 7: /* FIDIVR m16int */ /* ST(0) = m16int / ST(0) */
5678 DIP("fidivrw %s\n", dis_buf);
5679 fop = Iop_DivF64;
5680 goto do_foprev_m16;
5681
5682 do_fop_m16:
5683 put_ST_UNCHECKED(0,
sewardj4796d662006-02-05 16:06:26 +00005684 triop(fop,
5685 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardj6847d8c2005-05-12 19:21:55 +00005686 get_ST(0),
5687 unop(Iop_I32toF64,
5688 unop(Iop_16Sto32,
5689 loadLE(Ity_I16, mkexpr(addr))))));
5690 break;
5691
5692 do_foprev_m16:
5693 put_ST_UNCHECKED(0,
sewardj4796d662006-02-05 16:06:26 +00005694 triop(fop,
5695 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardj6847d8c2005-05-12 19:21:55 +00005696 unop(Iop_I32toF64,
5697 unop(Iop_16Sto32,
5698 loadLE(Ity_I16, mkexpr(addr)))),
5699 get_ST(0)));
5700 break;
5701
5702 default:
5703 vex_printf("unhandled opc_aux = 0x%2x\n", gregLO3ofRM(modrm));
5704 vex_printf("first_opcode == 0xDE\n");
5705 goto decode_fail;
5706 }
sewardj137015d2005-03-27 04:01:15 +00005707
5708 } else {
5709
5710 delta++;
5711 switch (modrm) {
5712
5713 case 0xC0 ... 0xC7: /* FADDP %st(0),%st(?) */
5714 fp_do_op_ST_ST ( "add", Iop_AddF64, 0, modrm - 0xC0, True );
5715 break;
5716
5717 case 0xC8 ... 0xCF: /* FMULP %st(0),%st(?) */
5718 fp_do_op_ST_ST ( "mul", Iop_MulF64, 0, modrm - 0xC8, True );
5719 break;
5720
sewardjd20c8852005-01-20 20:04:07 +00005721//.. case 0xD9: /* FCOMPP %st(0),%st(1) */
5722//.. DIP("fuompp %%st(0),%%st(1)\n");
5723//.. /* This forces C1 to zero, which isn't right. */
5724//.. put_C3210(
5725//.. binop( Iop_And32,
5726//.. binop(Iop_Shl32,
5727//.. binop(Iop_CmpF64, get_ST(0), get_ST(1)),
5728//.. mkU8(8)),
5729//.. mkU32(0x4500)
5730//.. ));
5731//.. fp_pop();
5732//.. fp_pop();
5733//.. break;
sewardj137015d2005-03-27 04:01:15 +00005734
5735 case 0xE0 ... 0xE7: /* FSUBRP %st(0),%st(?) */
5736 fp_do_oprev_ST_ST ( "subr", Iop_SubF64, 0, modrm - 0xE0, True );
5737 break;
5738
5739 case 0xE8 ... 0xEF: /* FSUBP %st(0),%st(?) */
5740 fp_do_op_ST_ST ( "sub", Iop_SubF64, 0, modrm - 0xE8, True );
5741 break;
5742
5743 case 0xF0 ... 0xF7: /* FDIVRP %st(0),%st(?) */
5744 fp_do_oprev_ST_ST ( "divr", Iop_DivF64, 0, modrm - 0xF0, True );
5745 break;
5746
5747 case 0xF8 ... 0xFF: /* FDIVP %st(0),%st(?) */
5748 fp_do_op_ST_ST ( "div", Iop_DivF64, 0, modrm - 0xF8, True );
5749 break;
5750
5751 default:
5752 goto decode_fail;
5753 }
5754
5755 }
5756 }
sewardjc49ce232005-02-25 13:03:03 +00005757
5758 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDF opcodes +-+-+-+-+-+-+-+ */
5759 else
5760 if (first_opcode == 0xDF) {
5761
5762 if (modrm < 0xC0) {
5763
5764 /* bits 5,4,3 are an opcode extension, and the modRM also
5765 specifies an address. */
5766 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
5767 delta += len;
5768
sewardj901ed122005-02-27 13:25:31 +00005769 switch (gregLO3ofRM(modrm)) {
sewardjc49ce232005-02-25 13:03:03 +00005770
sewardj434e0692005-03-27 17:36:08 +00005771 case 0: /* FILD m16int */
5772 DIP("fildw %s\n", dis_buf);
5773 fp_push();
5774 put_ST(0, unop(Iop_I32toF64,
5775 unop(Iop_16Sto32,
5776 loadLE(Ity_I16, mkexpr(addr)))));
5777 break;
5778
sewardjd20c8852005-01-20 20:04:07 +00005779//.. case 2: /* FIST m16 */
5780//.. DIP("fistp %s\n", dis_buf);
5781//.. storeLE( mkexpr(addr),
5782//.. binop(Iop_F64toI16, get_roundingmode(), get_ST(0)) );
5783//.. break;
sewardj6847d8c2005-05-12 19:21:55 +00005784
sewardjd20c8852005-01-20 20:04:07 +00005785//.. case 3: /* FISTP m16 */
5786//.. DIP("fistps %s\n", dis_buf);
5787//.. storeLE( mkexpr(addr),
5788//.. binop(Iop_F64toI16, get_roundingmode(), get_ST(0)) );
5789//.. fp_pop();
5790//.. break;
sewardj37d52572005-02-25 14:22:12 +00005791
5792 case 5: /* FILD m64 */
5793 DIP("fildll %s\n", dis_buf);
5794 fp_push();
5795 put_ST(0, binop(Iop_I64toF64,
5796 get_roundingmode(),
5797 loadLE(Ity_I64, mkexpr(addr))));
5798 break;
5799
sewardj6847d8c2005-05-12 19:21:55 +00005800 case 7: /* FISTP m64 */
5801 DIP("fistpll %s\n", dis_buf);
5802 storeLE( mkexpr(addr),
5803 binop(Iop_F64toI64, get_roundingmode(), get_ST(0)) );
5804 fp_pop();
5805 break;
sewardjc49ce232005-02-25 13:03:03 +00005806
5807 default:
sewardj901ed122005-02-27 13:25:31 +00005808 vex_printf("unhandled opc_aux = 0x%2x\n", gregLO3ofRM(modrm));
sewardjc49ce232005-02-25 13:03:03 +00005809 vex_printf("first_opcode == 0xDF\n");
5810 goto decode_fail;
5811 }
5812
5813 } else {
5814
5815 delta++;
5816 switch (modrm) {
5817
5818 case 0xC0: /* FFREEP %st(0) */
5819 DIP("ffreep %%st(%d)\n", 0);
5820 put_ST_TAG ( 0, mkU8(0) );
5821 fp_pop();
5822 break;
5823
sewardj4f9847d2005-07-25 11:58:34 +00005824 case 0xE0: /* FNSTSW %ax */
5825 DIP("fnstsw %%ax\n");
5826 /* Invent a plausible-looking FPU status word value and
5827 dump it in %AX:
5828 ((ftop & 7) << 11) | (c3210 & 0x4700)
5829 */
5830 putIRegRAX(
5831 2,
5832 unop(Iop_32to16,
5833 binop(Iop_Or32,
5834 binop(Iop_Shl32,
5835 binop(Iop_And32, get_ftop(), mkU32(7)),
5836 mkU8(11)),
5837 binop(Iop_And32,
5838 unop(Iop_64to32, get_C3210()),
5839 mkU32(0x4700))
5840 )));
5841 break;
sewardj924215b2005-03-26 21:50:31 +00005842
5843 case 0xE8 ... 0xEF: /* FUCOMIP %st(0),%st(?) */
5844 fp_do_ucomi_ST0_STi( (UInt)modrm - 0xE8, True );
5845 break;
5846
sewardj48a89d82005-05-06 11:50:13 +00005847 case 0xF0 ... 0xF7: /* FCOMIP %st(0),%st(?) */
5848 /* not really right since COMIP != UCOMIP */
5849 fp_do_ucomi_ST0_STi( (UInt)modrm - 0xF0, True );
5850 break;
sewardjc49ce232005-02-25 13:03:03 +00005851
5852 default:
5853 goto decode_fail;
5854 }
5855 }
5856
5857 }
sewardj8d965312005-02-25 02:48:47 +00005858
5859 else
sewardj137015d2005-03-27 04:01:15 +00005860 goto decode_fail;
sewardj8d965312005-02-25 02:48:47 +00005861
5862 *decode_ok = True;
5863 return delta;
5864
5865 decode_fail:
5866 *decode_ok = False;
5867 return delta;
5868}
5869
5870
sewardj8711f662005-05-09 17:52:56 +00005871/*------------------------------------------------------------*/
5872/*--- ---*/
5873/*--- MMX INSTRUCTIONS ---*/
5874/*--- ---*/
5875/*------------------------------------------------------------*/
5876
5877/* Effect of MMX insns on x87 FPU state (table 11-2 of
5878 IA32 arch manual, volume 3):
5879
5880 Read from, or write to MMX register (viz, any insn except EMMS):
5881 * All tags set to Valid (non-empty) -- FPTAGS[i] := nonzero
5882 * FP stack pointer set to zero
5883
5884 EMMS:
5885 * All tags set to Invalid (empty) -- FPTAGS[i] := zero
5886 * FP stack pointer set to zero
5887*/
5888
5889static void do_MMX_preamble ( void )
5890{
5891 Int i;
5892 IRArray* descr = mkIRArray( OFFB_FPTAGS, Ity_I8, 8 );
5893 IRExpr* zero = mkU32(0);
5894 IRExpr* tag1 = mkU8(1);
5895 put_ftop(zero);
5896 for (i = 0; i < 8; i++)
5897 stmt( IRStmt_PutI( descr, zero, i, tag1 ) );
5898}
5899
5900static void do_EMMS_preamble ( void )
5901{
5902 Int i;
5903 IRArray* descr = mkIRArray( OFFB_FPTAGS, Ity_I8, 8 );
5904 IRExpr* zero = mkU32(0);
5905 IRExpr* tag0 = mkU8(0);
5906 put_ftop(zero);
5907 for (i = 0; i < 8; i++)
5908 stmt( IRStmt_PutI( descr, zero, i, tag0 ) );
5909}
5910
5911
5912static IRExpr* getMMXReg ( UInt archreg )
5913{
5914 vassert(archreg < 8);
5915 return IRExpr_Get( OFFB_FPREGS + 8 * archreg, Ity_I64 );
5916}
5917
5918
5919static void putMMXReg ( UInt archreg, IRExpr* e )
5920{
5921 vassert(archreg < 8);
5922 vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_I64);
5923 stmt( IRStmt_Put( OFFB_FPREGS + 8 * archreg, e ) );
5924}
5925
5926
5927/* Helper for non-shift MMX insns. Note this is incomplete in the
5928 sense that it does not first call do_MMX_preamble() -- that is the
5929 responsibility of its caller. */
5930
5931static
5932ULong dis_MMXop_regmem_to_reg ( Prefix pfx,
sewardj270def42005-07-03 01:03:01 +00005933 Long delta,
sewardj8711f662005-05-09 17:52:56 +00005934 UChar opc,
sewardjca673ab2005-05-11 10:03:08 +00005935 HChar* name,
sewardj8711f662005-05-09 17:52:56 +00005936 Bool show_granularity )
5937{
5938 HChar dis_buf[50];
5939 UChar modrm = getUChar(delta);
5940 Bool isReg = epartIsReg(modrm);
5941 IRExpr* argL = NULL;
5942 IRExpr* argR = NULL;
5943 IRExpr* argG = NULL;
5944 IRExpr* argE = NULL;
5945 IRTemp res = newTemp(Ity_I64);
5946
5947 Bool invG = False;
5948 IROp op = Iop_INVALID;
5949 void* hAddr = NULL;
sewardjca673ab2005-05-11 10:03:08 +00005950 HChar* hName = NULL;
sewardj8711f662005-05-09 17:52:56 +00005951 Bool eLeft = False;
5952
5953# define XXX(_name) do { hAddr = &_name; hName = #_name; } while (0)
5954
5955 switch (opc) {
5956 /* Original MMX ones */
5957 case 0xFC: op = Iop_Add8x8; break;
5958 case 0xFD: op = Iop_Add16x4; break;
5959 case 0xFE: op = Iop_Add32x2; break;
5960
5961 case 0xEC: op = Iop_QAdd8Sx8; break;
5962 case 0xED: op = Iop_QAdd16Sx4; break;
5963
5964 case 0xDC: op = Iop_QAdd8Ux8; break;
5965 case 0xDD: op = Iop_QAdd16Ux4; break;
5966
5967 case 0xF8: op = Iop_Sub8x8; break;
5968 case 0xF9: op = Iop_Sub16x4; break;
5969 case 0xFA: op = Iop_Sub32x2; break;
5970
5971 case 0xE8: op = Iop_QSub8Sx8; break;
5972 case 0xE9: op = Iop_QSub16Sx4; break;
5973
5974 case 0xD8: op = Iop_QSub8Ux8; break;
5975 case 0xD9: op = Iop_QSub16Ux4; break;
5976
5977 case 0xE5: op = Iop_MulHi16Sx4; break;
5978 case 0xD5: op = Iop_Mul16x4; break;
5979 case 0xF5: XXX(amd64g_calculate_mmx_pmaddwd); break;
5980
5981 case 0x74: op = Iop_CmpEQ8x8; break;
5982 case 0x75: op = Iop_CmpEQ16x4; break;
5983 case 0x76: op = Iop_CmpEQ32x2; break;
5984
5985 case 0x64: op = Iop_CmpGT8Sx8; break;
5986 case 0x65: op = Iop_CmpGT16Sx4; break;
5987 case 0x66: op = Iop_CmpGT32Sx2; break;
5988
5989 case 0x6B: op = Iop_QNarrow32Sx2; eLeft = True; break;
5990 case 0x63: op = Iop_QNarrow16Sx4; eLeft = True; break;
5991 case 0x67: op = Iop_QNarrow16Ux4; eLeft = True; break;
5992
5993 case 0x68: op = Iop_InterleaveHI8x8; eLeft = True; break;
5994 case 0x69: op = Iop_InterleaveHI16x4; eLeft = True; break;
5995 case 0x6A: op = Iop_InterleaveHI32x2; eLeft = True; break;
5996
5997 case 0x60: op = Iop_InterleaveLO8x8; eLeft = True; break;
5998 case 0x61: op = Iop_InterleaveLO16x4; eLeft = True; break;
5999 case 0x62: op = Iop_InterleaveLO32x2; eLeft = True; break;
6000
6001 case 0xDB: op = Iop_And64; break;
6002 case 0xDF: op = Iop_And64; invG = True; break;
6003 case 0xEB: op = Iop_Or64; break;
6004 case 0xEF: /* Possibly do better here if argL and argR are the
6005 same reg */
6006 op = Iop_Xor64; break;
6007
6008 /* Introduced in SSE1 */
6009 case 0xE0: op = Iop_Avg8Ux8; break;
6010 case 0xE3: op = Iop_Avg16Ux4; break;
6011 case 0xEE: op = Iop_Max16Sx4; break;
6012 case 0xDE: op = Iop_Max8Ux8; break;
6013 case 0xEA: op = Iop_Min16Sx4; break;
6014 case 0xDA: op = Iop_Min8Ux8; break;
6015 case 0xE4: op = Iop_MulHi16Ux4; break;
sewardja7ba8c42005-05-10 20:08:34 +00006016 case 0xF6: XXX(amd64g_calculate_mmx_psadbw); break;
sewardj8711f662005-05-09 17:52:56 +00006017
6018 /* Introduced in SSE2 */
6019 case 0xD4: op = Iop_Add64; break;
6020 case 0xFB: op = Iop_Sub64; break;
6021
6022 default:
6023 vex_printf("\n0x%x\n", (Int)opc);
6024 vpanic("dis_MMXop_regmem_to_reg");
6025 }
6026
6027# undef XXX
6028
6029 argG = getMMXReg(gregLO3ofRM(modrm));
6030 if (invG)
6031 argG = unop(Iop_Not64, argG);
6032
6033 if (isReg) {
6034 delta++;
6035 argE = getMMXReg(eregLO3ofRM(modrm));
6036 } else {
6037 Int len;
6038 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
6039 delta += len;
6040 argE = loadLE(Ity_I64, mkexpr(addr));
6041 }
6042
6043 if (eLeft) {
6044 argL = argE;
6045 argR = argG;
6046 } else {
6047 argL = argG;
6048 argR = argE;
6049 }
6050
6051 if (op != Iop_INVALID) {
6052 vassert(hName == NULL);
6053 vassert(hAddr == NULL);
6054 assign(res, binop(op, argL, argR));
6055 } else {
6056 vassert(hName != NULL);
6057 vassert(hAddr != NULL);
6058 assign( res,
6059 mkIRExprCCall(
6060 Ity_I64,
6061 0/*regparms*/, hName, hAddr,
6062 mkIRExprVec_2( argL, argR )
6063 )
6064 );
6065 }
6066
6067 putMMXReg( gregLO3ofRM(modrm), mkexpr(res) );
6068
6069 DIP("%s%s %s, %s\n",
6070 name, show_granularity ? nameMMXGran(opc & 3) : "",
6071 ( isReg ? nameMMXReg(eregLO3ofRM(modrm)) : dis_buf ),
6072 nameMMXReg(gregLO3ofRM(modrm)) );
6073
6074 return delta;
6075}
6076
6077
6078/* Vector by scalar shift of G by the amount specified at the bottom
6079 of E. This is a straight copy of dis_SSE_shiftG_byE. */
6080
sewardj270def42005-07-03 01:03:01 +00006081static ULong dis_MMX_shiftG_byE ( Prefix pfx, Long delta,
sewardj8711f662005-05-09 17:52:56 +00006082 HChar* opname, IROp op )
6083{
6084 HChar dis_buf[50];
6085 Int alen, size;
6086 IRTemp addr;
6087 Bool shl, shr, sar;
6088 UChar rm = getUChar(delta);
6089 IRTemp g0 = newTemp(Ity_I64);
6090 IRTemp g1 = newTemp(Ity_I64);
6091 IRTemp amt = newTemp(Ity_I64);
6092 IRTemp amt8 = newTemp(Ity_I8);
6093
6094 if (epartIsReg(rm)) {
6095 assign( amt, getMMXReg(eregLO3ofRM(rm)) );
6096 DIP("%s %s,%s\n", opname,
6097 nameMMXReg(eregLO3ofRM(rm)),
6098 nameMMXReg(gregLO3ofRM(rm)) );
6099 delta++;
6100 } else {
6101 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
6102 assign( amt, loadLE(Ity_I64, mkexpr(addr)) );
6103 DIP("%s %s,%s\n", opname,
6104 dis_buf,
6105 nameMMXReg(gregLO3ofRM(rm)) );
6106 delta += alen;
6107 }
6108 assign( g0, getMMXReg(gregLO3ofRM(rm)) );
6109 assign( amt8, unop(Iop_64to8, mkexpr(amt)) );
6110
6111 shl = shr = sar = False;
6112 size = 0;
6113 switch (op) {
6114 case Iop_ShlN16x4: shl = True; size = 32; break;
6115 case Iop_ShlN32x2: shl = True; size = 32; break;
6116 case Iop_Shl64: shl = True; size = 64; break;
6117 case Iop_ShrN16x4: shr = True; size = 16; break;
6118 case Iop_ShrN32x2: shr = True; size = 32; break;
6119 case Iop_Shr64: shr = True; size = 64; break;
6120 case Iop_SarN16x4: sar = True; size = 16; break;
6121 case Iop_SarN32x2: sar = True; size = 32; break;
6122 default: vassert(0);
6123 }
6124
6125 if (shl || shr) {
6126 assign(
6127 g1,
6128 IRExpr_Mux0X(
6129 unop(Iop_1Uto8,binop(Iop_CmpLT64U,mkexpr(amt),mkU64(size))),
6130 mkU64(0),
6131 binop(op, mkexpr(g0), mkexpr(amt8))
6132 )
6133 );
6134 } else
6135 if (sar) {
6136 assign(
6137 g1,
6138 IRExpr_Mux0X(
6139 unop(Iop_1Uto8,binop(Iop_CmpLT64U,mkexpr(amt),mkU64(size))),
6140 binop(op, mkexpr(g0), mkU8(size-1)),
6141 binop(op, mkexpr(g0), mkexpr(amt8))
6142 )
6143 );
6144 } else {
6145 vassert(0);
6146 }
6147
6148 putMMXReg( gregLO3ofRM(rm), mkexpr(g1) );
6149 return delta;
6150}
6151
6152
sewardj3d8107c2005-05-09 22:23:38 +00006153/* Vector by scalar shift of E by an immediate byte. This is a
6154 straight copy of dis_SSE_shiftE_imm. */
6155
6156static
sewardj270def42005-07-03 01:03:01 +00006157ULong dis_MMX_shiftE_imm ( Long delta, HChar* opname, IROp op )
sewardj3d8107c2005-05-09 22:23:38 +00006158{
6159 Bool shl, shr, sar;
6160 UChar rm = getUChar(delta);
6161 IRTemp e0 = newTemp(Ity_I64);
6162 IRTemp e1 = newTemp(Ity_I64);
6163 UChar amt, size;
6164 vassert(epartIsReg(rm));
6165 vassert(gregLO3ofRM(rm) == 2
6166 || gregLO3ofRM(rm) == 4 || gregLO3ofRM(rm) == 6);
sewardjca673ab2005-05-11 10:03:08 +00006167 amt = getUChar(delta+1);
sewardj3d8107c2005-05-09 22:23:38 +00006168 delta += 2;
6169 DIP("%s $%d,%s\n", opname,
6170 (Int)amt,
6171 nameMMXReg(eregLO3ofRM(rm)) );
6172
6173 assign( e0, getMMXReg(eregLO3ofRM(rm)) );
6174
6175 shl = shr = sar = False;
6176 size = 0;
6177 switch (op) {
6178 case Iop_ShlN16x4: shl = True; size = 16; break;
6179 case Iop_ShlN32x2: shl = True; size = 32; break;
6180 case Iop_Shl64: shl = True; size = 64; break;
6181 case Iop_SarN16x4: sar = True; size = 16; break;
6182 case Iop_SarN32x2: sar = True; size = 32; break;
6183 case Iop_ShrN16x4: shr = True; size = 16; break;
6184 case Iop_ShrN32x2: shr = True; size = 32; break;
6185 case Iop_Shr64: shr = True; size = 64; break;
6186 default: vassert(0);
6187 }
6188
6189 if (shl || shr) {
6190 assign( e1, amt >= size
6191 ? mkU64(0)
6192 : binop(op, mkexpr(e0), mkU8(amt))
6193 );
6194 } else
6195 if (sar) {
6196 assign( e1, amt >= size
6197 ? binop(op, mkexpr(e0), mkU8(size-1))
6198 : binop(op, mkexpr(e0), mkU8(amt))
6199 );
6200 } else {
6201 vassert(0);
6202 }
6203
6204 putMMXReg( eregLO3ofRM(rm), mkexpr(e1) );
6205 return delta;
6206}
sewardj8711f662005-05-09 17:52:56 +00006207
6208
6209/* Completely handle all MMX instructions except emms. */
6210
6211static
sewardj270def42005-07-03 01:03:01 +00006212ULong dis_MMX ( Bool* decode_ok, Prefix pfx, Int sz, Long delta )
sewardj8711f662005-05-09 17:52:56 +00006213{
6214 Int len;
6215 UChar modrm;
6216 HChar dis_buf[50];
6217 UChar opc = getUChar(delta);
6218 delta++;
6219
6220 /* dis_MMX handles all insns except emms. */
6221 do_MMX_preamble();
6222
6223 switch (opc) {
6224
sewardj3d8107c2005-05-09 22:23:38 +00006225 case 0x6E:
6226 if (sz == 4) {
6227 /* MOVD (src)ireg32-or-mem32 (E), (dst)mmxreg (G)*/
6228 modrm = getUChar(delta);
6229 if (epartIsReg(modrm)) {
6230 delta++;
6231 putMMXReg(
6232 gregLO3ofRM(modrm),
6233 binop( Iop_32HLto64,
6234 mkU32(0),
6235 getIReg32(eregOfRexRM(pfx,modrm)) ) );
6236 DIP("movd %s, %s\n",
6237 nameIReg32(eregOfRexRM(pfx,modrm)),
6238 nameMMXReg(gregLO3ofRM(modrm)));
6239 } else {
6240 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
6241 delta += len;
6242 putMMXReg(
6243 gregLO3ofRM(modrm),
6244 binop( Iop_32HLto64,
6245 mkU32(0),
6246 loadLE(Ity_I32, mkexpr(addr)) ) );
6247 DIP("movd %s, %s\n", dis_buf, nameMMXReg(gregLO3ofRM(modrm)));
6248 }
6249 }
6250 else
6251 if (sz == 8) {
6252 /* MOVD (src)ireg64-or-mem64 (E), (dst)mmxreg (G)*/
6253 modrm = getUChar(delta);
6254 if (epartIsReg(modrm)) {
6255 delta++;
6256 putMMXReg( gregLO3ofRM(modrm),
6257 getIReg64(eregOfRexRM(pfx,modrm)) );
6258 DIP("movd %s, %s\n",
6259 nameIReg64(eregOfRexRM(pfx,modrm)),
6260 nameMMXReg(gregLO3ofRM(modrm)));
6261 } else {
6262 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
6263 delta += len;
6264 putMMXReg( gregLO3ofRM(modrm),
6265 loadLE(Ity_I64, mkexpr(addr)) );
6266 DIP("movd{64} %s, %s\n", dis_buf, nameMMXReg(gregLO3ofRM(modrm)));
6267 }
6268 }
6269 else {
6270 goto mmx_decode_failure;
6271 }
6272 break;
6273
6274 case 0x7E:
6275 if (sz == 4) {
6276 /* MOVD (src)mmxreg (G), (dst)ireg32-or-mem32 (E) */
6277 modrm = getUChar(delta);
6278 if (epartIsReg(modrm)) {
6279 delta++;
6280 putIReg32( eregOfRexRM(pfx,modrm),
6281 unop(Iop_64to32, getMMXReg(gregLO3ofRM(modrm)) ) );
6282 DIP("movd %s, %s\n",
6283 nameMMXReg(gregLO3ofRM(modrm)),
6284 nameIReg32(eregOfRexRM(pfx,modrm)));
6285 } else {
6286 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
6287 delta += len;
6288 storeLE( mkexpr(addr),
6289 unop(Iop_64to32, getMMXReg(gregLO3ofRM(modrm)) ) );
6290 DIP("movd %s, %s\n", nameMMXReg(gregLO3ofRM(modrm)), dis_buf);
6291 }
6292 }
6293 else
6294 if (sz == 8) {
6295 /* MOVD (src)mmxreg (G), (dst)ireg64-or-mem64 (E) */
6296 modrm = getUChar(delta);
6297 if (epartIsReg(modrm)) {
6298 delta++;
6299 putIReg64( eregOfRexRM(pfx,modrm),
6300 getMMXReg(gregLO3ofRM(modrm)) );
6301 DIP("movd %s, %s\n",
6302 nameMMXReg(gregLO3ofRM(modrm)),
6303 nameIReg64(eregOfRexRM(pfx,modrm)));
6304 } else {
6305 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
6306 delta += len;
6307 storeLE( mkexpr(addr),
6308 getMMXReg(gregLO3ofRM(modrm)) );
6309 DIP("movd{64} %s, %s\n", nameMMXReg(gregLO3ofRM(modrm)), dis_buf);
6310 }
6311 } else {
6312 goto mmx_decode_failure;
6313 }
6314 break;
sewardj8711f662005-05-09 17:52:56 +00006315
6316 case 0x6F:
6317 /* MOVQ (src)mmxreg-or-mem, (dst)mmxreg */
6318 if (sz != 4)
6319 goto mmx_decode_failure;
6320 modrm = getUChar(delta);
6321 if (epartIsReg(modrm)) {
6322 delta++;
6323 putMMXReg( gregLO3ofRM(modrm), getMMXReg(eregLO3ofRM(modrm)) );
6324 DIP("movq %s, %s\n",
6325 nameMMXReg(eregLO3ofRM(modrm)),
6326 nameMMXReg(gregLO3ofRM(modrm)));
6327 } else {
6328 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
6329 delta += len;
6330 putMMXReg( gregLO3ofRM(modrm), loadLE(Ity_I64, mkexpr(addr)) );
6331 DIP("movq %s, %s\n",
6332 dis_buf, nameMMXReg(gregLO3ofRM(modrm)));
6333 }
6334 break;
6335
6336 case 0x7F:
6337 /* MOVQ (src)mmxreg, (dst)mmxreg-or-mem */
6338 if (sz != 4)
6339 goto mmx_decode_failure;
6340 modrm = getUChar(delta);
6341 if (epartIsReg(modrm)) {
6342 /* Fall through. The assembler doesn't appear to generate
6343 these. */
6344 goto mmx_decode_failure;
6345 } else {
6346 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
6347 delta += len;
6348 storeLE( mkexpr(addr), getMMXReg(gregLO3ofRM(modrm)) );
6349 DIP("mov(nt)q %s, %s\n",
6350 nameMMXReg(gregLO3ofRM(modrm)), dis_buf);
6351 }
6352 break;
6353
6354 case 0xFC:
6355 case 0xFD:
6356 case 0xFE: /* PADDgg (src)mmxreg-or-mem, (dst)mmxreg */
6357 if (sz != 4)
6358 goto mmx_decode_failure;
6359 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "padd", True );
6360 break;
6361
6362 case 0xEC:
6363 case 0xED: /* PADDSgg (src)mmxreg-or-mem, (dst)mmxreg */
6364 if (sz != 4)
6365 goto mmx_decode_failure;
6366 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "padds", True );
6367 break;
6368
6369 case 0xDC:
6370 case 0xDD: /* PADDUSgg (src)mmxreg-or-mem, (dst)mmxreg */
6371 if (sz != 4)
6372 goto mmx_decode_failure;
6373 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "paddus", True );
6374 break;
6375
6376 case 0xF8:
6377 case 0xF9:
6378 case 0xFA: /* PSUBgg (src)mmxreg-or-mem, (dst)mmxreg */
6379 if (sz != 4)
6380 goto mmx_decode_failure;
6381 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "psub", True );
6382 break;
6383
6384 case 0xE8:
6385 case 0xE9: /* PSUBSgg (src)mmxreg-or-mem, (dst)mmxreg */
6386 if (sz != 4)
6387 goto mmx_decode_failure;
6388 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "psubs", True );
6389 break;
6390
6391 case 0xD8:
6392 case 0xD9: /* PSUBUSgg (src)mmxreg-or-mem, (dst)mmxreg */
6393 if (sz != 4)
6394 goto mmx_decode_failure;
6395 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "psubus", True );
6396 break;
6397
6398 case 0xE5: /* PMULHW (src)mmxreg-or-mem, (dst)mmxreg */
6399 if (sz != 4)
6400 goto mmx_decode_failure;
6401 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "pmulhw", False );
6402 break;
6403
6404 case 0xD5: /* PMULLW (src)mmxreg-or-mem, (dst)mmxreg */
6405 if (sz != 4)
6406 goto mmx_decode_failure;
6407 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "pmullw", False );
6408 break;
6409
6410 case 0xF5: /* PMADDWD (src)mmxreg-or-mem, (dst)mmxreg */
6411 vassert(sz == 4);
6412 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "pmaddwd", False );
6413 break;
6414
6415 case 0x74:
6416 case 0x75:
6417 case 0x76: /* PCMPEQgg (src)mmxreg-or-mem, (dst)mmxreg */
6418 if (sz != 4)
6419 goto mmx_decode_failure;
6420 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "pcmpeq", True );
6421 break;
6422
6423 case 0x64:
6424 case 0x65:
6425 case 0x66: /* PCMPGTgg (src)mmxreg-or-mem, (dst)mmxreg */
6426 if (sz != 4)
6427 goto mmx_decode_failure;
6428 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "pcmpgt", True );
6429 break;
6430
6431 case 0x6B: /* PACKSSDW (src)mmxreg-or-mem, (dst)mmxreg */
6432 if (sz != 4)
6433 goto mmx_decode_failure;
6434 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "packssdw", False );
6435 break;
6436
6437 case 0x63: /* PACKSSWB (src)mmxreg-or-mem, (dst)mmxreg */
6438 if (sz != 4)
6439 goto mmx_decode_failure;
6440 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "packsswb", False );
6441 break;
6442
6443 case 0x67: /* PACKUSWB (src)mmxreg-or-mem, (dst)mmxreg */
6444 if (sz != 4)
6445 goto mmx_decode_failure;
6446 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "packuswb", False );
6447 break;
6448
6449 case 0x68:
6450 case 0x69:
6451 case 0x6A: /* PUNPCKHgg (src)mmxreg-or-mem, (dst)mmxreg */
6452 if (sz != 4)
6453 goto mmx_decode_failure;
6454 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "punpckh", True );
6455 break;
6456
6457 case 0x60:
6458 case 0x61:
6459 case 0x62: /* PUNPCKLgg (src)mmxreg-or-mem, (dst)mmxreg */
6460 if (sz != 4)
6461 goto mmx_decode_failure;
6462 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "punpckl", True );
6463 break;
6464
6465 case 0xDB: /* PAND (src)mmxreg-or-mem, (dst)mmxreg */
6466 if (sz != 4)
6467 goto mmx_decode_failure;
6468 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "pand", False );
6469 break;
6470
6471 case 0xDF: /* PANDN (src)mmxreg-or-mem, (dst)mmxreg */
6472 if (sz != 4)
6473 goto mmx_decode_failure;
6474 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "pandn", False );
6475 break;
6476
6477 case 0xEB: /* POR (src)mmxreg-or-mem, (dst)mmxreg */
6478 if (sz != 4)
6479 goto mmx_decode_failure;
6480 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "por", False );
6481 break;
6482
6483 case 0xEF: /* PXOR (src)mmxreg-or-mem, (dst)mmxreg */
6484 if (sz != 4)
6485 goto mmx_decode_failure;
6486 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "pxor", False );
6487 break;
6488
6489# define SHIFT_BY_REG(_name,_op) \
6490 delta = dis_MMX_shiftG_byE(pfx, delta, _name, _op); \
6491 break;
6492
6493 /* PSLLgg (src)mmxreg-or-mem, (dst)mmxreg */
6494 case 0xF1: SHIFT_BY_REG("psllw", Iop_ShlN16x4);
6495 case 0xF2: SHIFT_BY_REG("pslld", Iop_ShlN32x2);
6496 case 0xF3: SHIFT_BY_REG("psllq", Iop_Shl64);
6497
6498 /* PSRLgg (src)mmxreg-or-mem, (dst)mmxreg */
6499 case 0xD1: SHIFT_BY_REG("psrlw", Iop_ShrN16x4);
6500 case 0xD2: SHIFT_BY_REG("psrld", Iop_ShrN32x2);
6501 case 0xD3: SHIFT_BY_REG("psrlq", Iop_Shr64);
6502
6503 /* PSRAgg (src)mmxreg-or-mem, (dst)mmxreg */
6504 case 0xE1: SHIFT_BY_REG("psraw", Iop_SarN16x4);
6505 case 0xE2: SHIFT_BY_REG("psrad", Iop_SarN32x2);
6506
6507# undef SHIFT_BY_REG
sewardj3d8107c2005-05-09 22:23:38 +00006508
6509 case 0x71:
6510 case 0x72:
6511 case 0x73: {
6512 /* (sz==4): PSLLgg/PSRAgg/PSRLgg mmxreg by imm8 */
sewardjca673ab2005-05-11 10:03:08 +00006513 UChar byte2, subopc;
sewardj3d8107c2005-05-09 22:23:38 +00006514 if (sz != 4)
6515 goto mmx_decode_failure;
sewardjca673ab2005-05-11 10:03:08 +00006516 byte2 = getUChar(delta); /* amode / sub-opcode */
6517 subopc = toUChar( (byte2 >> 3) & 7 );
sewardj3d8107c2005-05-09 22:23:38 +00006518
6519# define SHIFT_BY_IMM(_name,_op) \
6520 do { delta = dis_MMX_shiftE_imm(delta,_name,_op); \
6521 } while (0)
6522
6523 if (subopc == 2 /*SRL*/ && opc == 0x71)
6524 SHIFT_BY_IMM("psrlw", Iop_ShrN16x4);
6525 else if (subopc == 2 /*SRL*/ && opc == 0x72)
6526 SHIFT_BY_IMM("psrld", Iop_ShrN32x2);
6527 else if (subopc == 2 /*SRL*/ && opc == 0x73)
6528 SHIFT_BY_IMM("psrlq", Iop_Shr64);
6529
6530 else if (subopc == 4 /*SAR*/ && opc == 0x71)
6531 SHIFT_BY_IMM("psraw", Iop_SarN16x4);
6532 else if (subopc == 4 /*SAR*/ && opc == 0x72)
6533 SHIFT_BY_IMM("psrad", Iop_SarN32x2);
6534
6535 else if (subopc == 6 /*SHL*/ && opc == 0x71)
6536 SHIFT_BY_IMM("psllw", Iop_ShlN16x4);
6537 else if (subopc == 6 /*SHL*/ && opc == 0x72)
6538 SHIFT_BY_IMM("pslld", Iop_ShlN32x2);
6539 else if (subopc == 6 /*SHL*/ && opc == 0x73)
6540 SHIFT_BY_IMM("psllq", Iop_Shl64);
6541
6542 else goto mmx_decode_failure;
6543
6544# undef SHIFT_BY_IMM
6545 break;
6546 }
sewardj8711f662005-05-09 17:52:56 +00006547
6548 /* --- MMX decode failure --- */
6549 default:
6550 mmx_decode_failure:
6551 *decode_ok = False;
6552 return delta; /* ignored */
6553
6554 }
6555
6556 *decode_ok = True;
6557 return delta;
6558}
6559
6560
sewardj33ef9c22005-11-04 20:05:57 +00006561/*------------------------------------------------------------*/
6562/*--- More misc arithmetic and other obscure insns. ---*/
6563/*------------------------------------------------------------*/
6564
6565/* Generate base << amt with vacated places filled with stuff
6566 from xtra. amt guaranteed in 0 .. 63. */
6567static
6568IRExpr* shiftL64_with_extras ( IRTemp base, IRTemp xtra, IRTemp amt )
6569{
6570 /* if amt == 0
6571 then base
6572 else (base << amt) | (xtra >>u (64-amt))
6573 */
6574 return
6575 IRExpr_Mux0X(
6576 mkexpr(amt),
6577 mkexpr(base),
6578 binop(Iop_Or64,
6579 binop(Iop_Shl64, mkexpr(base), mkexpr(amt)),
6580 binop(Iop_Shr64, mkexpr(xtra),
6581 binop(Iop_Sub8, mkU8(64), mkexpr(amt)))
6582 )
6583 );
6584}
6585
6586/* Generate base >>u amt with vacated places filled with stuff
6587 from xtra. amt guaranteed in 0 .. 63. */
6588static
6589IRExpr* shiftR64_with_extras ( IRTemp xtra, IRTemp base, IRTemp amt )
6590{
6591 /* if amt == 0
6592 then base
6593 else (base >>u amt) | (xtra << (64-amt))
6594 */
6595 return
6596 IRExpr_Mux0X(
6597 mkexpr(amt),
6598 mkexpr(base),
6599 binop(Iop_Or64,
6600 binop(Iop_Shr64, mkexpr(base), mkexpr(amt)),
6601 binop(Iop_Shl64, mkexpr(xtra),
6602 binop(Iop_Sub8, mkU8(64), mkexpr(amt)))
6603 )
6604 );
6605}
6606
6607/* Double length left and right shifts. Apparently only required in
6608 v-size (no b- variant). */
6609static
6610ULong dis_SHLRD_Gv_Ev ( Prefix pfx,
6611 Long delta, UChar modrm,
6612 Int sz,
6613 IRExpr* shift_amt,
6614 Bool amt_is_literal,
sewardjf5268432005-11-05 02:58:55 +00006615 HChar* shift_amt_txt,
sewardj33ef9c22005-11-04 20:05:57 +00006616 Bool left_shift )
6617{
6618 /* shift_amt :: Ity_I8 is the amount to shift. shift_amt_txt is used
6619 for printing it. And eip on entry points at the modrm byte. */
6620 Int len;
6621 HChar dis_buf[50];
6622
6623 IRType ty = szToITy(sz);
6624 IRTemp gsrc = newTemp(ty);
6625 IRTemp esrc = newTemp(ty);
6626 IRTemp addr = IRTemp_INVALID;
6627 IRTemp tmpSH = newTemp(Ity_I8);
6628 IRTemp tmpSS = newTemp(Ity_I8);
6629 IRTemp tmp64 = IRTemp_INVALID;
6630 IRTemp res64 = IRTemp_INVALID;
6631 IRTemp rss64 = IRTemp_INVALID;
6632 IRTemp resTy = IRTemp_INVALID;
6633 IRTemp rssTy = IRTemp_INVALID;
6634 Int mask = sz==8 ? 63 : 31;
6635
6636 vassert(sz == 2 || sz == 4 || sz == 8);
6637
6638 /* The E-part is the destination; this is shifted. The G-part
6639 supplies bits to be shifted into the E-part, but is not
6640 changed.
6641
6642 If shifting left, form a double-length word with E at the top
6643 and G at the bottom, and shift this left. The result is then in
6644 the high part.
6645
6646 If shifting right, form a double-length word with G at the top
6647 and E at the bottom, and shift this right. The result is then
6648 at the bottom. */
6649
6650 /* Fetch the operands. */
6651
6652 assign( gsrc, getIRegG(sz, pfx, modrm) );
6653
6654 if (epartIsReg(modrm)) {
6655 delta++;
6656 assign( esrc, getIRegE(sz, pfx, modrm) );
6657 DIP("sh%cd%c %s, %s, %s\n",
6658 ( left_shift ? 'l' : 'r' ), nameISize(sz),
6659 shift_amt_txt,
6660 nameIRegG(sz, pfx, modrm), nameIRegE(sz, pfx, modrm));
6661 } else {
sewardj75ce3652005-11-04 20:49:36 +00006662 addr = disAMode ( &len, pfx, delta, dis_buf,
6663 /* # bytes following amode */
6664 amt_is_literal ? 1 : 0 );
sewardj33ef9c22005-11-04 20:05:57 +00006665 delta += len;
6666 assign( esrc, loadLE(ty, mkexpr(addr)) );
6667 DIP("sh%cd%c %s, %s, %s\n",
6668 ( left_shift ? 'l' : 'r' ), nameISize(sz),
6669 shift_amt_txt,
6670 nameIRegG(sz, pfx, modrm), dis_buf);
6671 }
6672
6673 /* Calculate the masked shift amount (tmpSH), the masked subshift
6674 amount (tmpSS), the shifted value (res64) and the subshifted
6675 value (rss64). */
6676
6677 assign( tmpSH, binop(Iop_And8, shift_amt, mkU8(mask)) );
6678 assign( tmpSS, binop(Iop_And8,
6679 binop(Iop_Sub8, mkexpr(tmpSH), mkU8(1) ),
6680 mkU8(mask)));
6681
6682 tmp64 = newTemp(Ity_I64);
6683 res64 = newTemp(Ity_I64);
6684 rss64 = newTemp(Ity_I64);
6685
6686 if (sz == 2 || sz == 4) {
6687
6688 /* G is xtra; E is data */
6689 /* what a freaking nightmare: */
6690 if (sz == 4 && left_shift) {
6691 assign( tmp64, binop(Iop_32HLto64, mkexpr(esrc), mkexpr(gsrc)) );
6692 assign( res64,
6693 binop(Iop_Shr64,
6694 binop(Iop_Shl64, mkexpr(tmp64), mkexpr(tmpSH)),
6695 mkU8(32)) );
6696 assign( rss64,
6697 binop(Iop_Shr64,
6698 binop(Iop_Shl64, mkexpr(tmp64), mkexpr(tmpSS)),
6699 mkU8(32)) );
6700 }
6701 else
6702 if (sz == 4 && !left_shift) {
6703 assign( tmp64, binop(Iop_32HLto64, mkexpr(gsrc), mkexpr(esrc)) );
6704 assign( res64, binop(Iop_Shr64, mkexpr(tmp64), mkexpr(tmpSH)) );
6705 assign( rss64, binop(Iop_Shr64, mkexpr(tmp64), mkexpr(tmpSS)) );
6706 }
6707 else
6708 if (sz == 2 && left_shift) {
6709 assign( tmp64,
6710 binop(Iop_32HLto64,
6711 binop(Iop_16HLto32, mkexpr(esrc), mkexpr(gsrc)),
6712 binop(Iop_16HLto32, mkexpr(gsrc), mkexpr(gsrc))
6713 ));
6714 /* result formed by shifting [esrc'gsrc'gsrc'gsrc] */
6715 assign( res64,
6716 binop(Iop_Shr64,
6717 binop(Iop_Shl64, mkexpr(tmp64), mkexpr(tmpSH)),
6718 mkU8(48)) );
6719 /* subshift formed by shifting [esrc'0000'0000'0000] */
6720 assign( rss64,
6721 binop(Iop_Shr64,
6722 binop(Iop_Shl64,
6723 binop(Iop_Shl64, unop(Iop_16Uto64, mkexpr(esrc)),
6724 mkU8(48)),
6725 mkexpr(tmpSS)),
6726 mkU8(48)) );
6727 }
6728 else
6729 if (sz == 2 && !left_shift) {
6730 assign( tmp64,
6731 binop(Iop_32HLto64,
6732 binop(Iop_16HLto32, mkexpr(gsrc), mkexpr(gsrc)),
6733 binop(Iop_16HLto32, mkexpr(gsrc), mkexpr(esrc))
6734 ));
6735 /* result formed by shifting [gsrc'gsrc'gsrc'esrc] */
6736 assign( res64, binop(Iop_Shr64, mkexpr(tmp64), mkexpr(tmpSH)) );
6737 /* subshift formed by shifting [0000'0000'0000'esrc] */
6738 assign( rss64, binop(Iop_Shr64,
6739 unop(Iop_16Uto64, mkexpr(esrc)),
6740 mkexpr(tmpSS)) );
6741 }
6742
6743 } else {
6744
6745 vassert(sz == 8);
6746 if (left_shift) {
6747 assign( res64, shiftL64_with_extras( esrc, gsrc, tmpSH ));
6748 assign( rss64, shiftL64_with_extras( esrc, gsrc, tmpSS ));
6749 } else {
6750 assign( res64, shiftR64_with_extras( gsrc, esrc, tmpSH ));
6751 assign( rss64, shiftR64_with_extras( gsrc, esrc, tmpSS ));
6752 }
6753
6754 }
6755
6756 resTy = newTemp(ty);
6757 rssTy = newTemp(ty);
6758 assign( resTy, narrowTo(ty, mkexpr(res64)) );
6759 assign( rssTy, narrowTo(ty, mkexpr(rss64)) );
6760
6761 /* Put result back and write the flags thunk. */
6762 setFlags_DEP1_DEP2_shift ( left_shift ? Iop_Shl64 : Iop_Sar64,
6763 resTy, rssTy, ty, tmpSH );
6764
6765 if (epartIsReg(modrm)) {
6766 putIRegE(sz, pfx, modrm, mkexpr(resTy));
6767 } else {
6768 storeLE( mkexpr(addr), mkexpr(resTy) );
6769 }
6770
6771 if (amt_is_literal) delta++;
6772 return delta;
6773}
sewardj9ed16802005-08-24 10:46:19 +00006774
6775
6776/* Handle BT/BTS/BTR/BTC Gv, Ev. Apparently b-size is not
6777 required. */
6778
6779typedef enum { BtOpNone, BtOpSet, BtOpReset, BtOpComp } BtOp;
6780
6781static HChar* nameBtOp ( BtOp op )
6782{
6783 switch (op) {
6784 case BtOpNone: return "";
6785 case BtOpSet: return "s";
6786 case BtOpReset: return "r";
6787 case BtOpComp: return "c";
6788 default: vpanic("nameBtOp(amd64)");
6789 }
6790}
6791
6792
6793static
6794ULong dis_bt_G_E ( Prefix pfx, Int sz, Long delta, BtOp op )
6795{
6796 HChar dis_buf[50];
6797 UChar modrm;
6798 Int len;
6799 IRTemp t_fetched, t_bitno0, t_bitno1, t_bitno2, t_addr0,
6800 t_addr1, t_rsp, t_mask;
6801
6802 vassert(sz == 2 || sz == 4 || sz == 8);
6803
6804 t_fetched = t_bitno0 = t_bitno1 = t_bitno2
6805 = t_addr0 = t_addr1 = t_rsp = t_mask = IRTemp_INVALID;
6806
6807 t_fetched = newTemp(Ity_I8);
6808 t_bitno0 = newTemp(Ity_I64);
6809 t_bitno1 = newTemp(Ity_I64);
6810 t_bitno2 = newTemp(Ity_I8);
6811 t_addr1 = newTemp(Ity_I64);
6812 modrm = getUChar(delta);
6813
6814 assign( t_bitno0, widenSto64(getIRegG(sz, pfx, modrm)) );
6815
6816 if (epartIsReg(modrm)) {
6817 delta++;
6818 /* Get it onto the client's stack. */
6819 t_rsp = newTemp(Ity_I64);
6820 t_addr0 = newTemp(Ity_I64);
6821
6822 assign( t_rsp, binop(Iop_Sub64, getIReg64(R_RSP), mkU64(sz)) );
6823 putIReg64(R_RSP, mkexpr(t_rsp));
6824
6825 storeLE( mkexpr(t_rsp), getIRegE(sz, pfx, modrm) );
6826
6827 /* Make t_addr0 point at it. */
6828 assign( t_addr0, mkexpr(t_rsp) );
6829
6830 /* Mask out upper bits of the shift amount, since we're doing a
6831 reg. */
6832 assign( t_bitno1, binop(Iop_And64,
6833 mkexpr(t_bitno0),
6834 mkU64(sz == 8 ? 63 : sz == 4 ? 31 : 15)) );
6835
6836 } else {
6837 t_addr0 = disAMode ( &len, pfx, delta, dis_buf, 0 );
6838 delta += len;
6839 assign( t_bitno1, mkexpr(t_bitno0) );
6840 }
6841
6842 /* At this point: t_addr0 is the address being operated on. If it
6843 was a reg, we will have pushed it onto the client's stack.
6844 t_bitno1 is the bit number, suitably masked in the case of a
6845 reg. */
6846
6847 /* Now the main sequence. */
6848 assign( t_addr1,
6849 binop(Iop_Add64,
6850 mkexpr(t_addr0),
6851 binop(Iop_Sar64, mkexpr(t_bitno1), mkU8(3))) );
6852
6853 /* t_addr1 now holds effective address */
6854
6855 assign( t_bitno2,
6856 unop(Iop_64to8,
6857 binop(Iop_And64, mkexpr(t_bitno1), mkU64(7))) );
6858
6859 /* t_bitno2 contains offset of bit within byte */
6860
6861 if (op != BtOpNone) {
6862 t_mask = newTemp(Ity_I8);
6863 assign( t_mask, binop(Iop_Shl8, mkU8(1), mkexpr(t_bitno2)) );
6864 }
6865
6866 /* t_mask is now a suitable byte mask */
6867
6868 assign( t_fetched, loadLE(Ity_I8, mkexpr(t_addr1)) );
6869
6870 if (op != BtOpNone) {
6871 switch (op) {
6872 case BtOpSet:
6873 storeLE( mkexpr(t_addr1),
6874 binop(Iop_Or8, mkexpr(t_fetched),
6875 mkexpr(t_mask)) );
6876 break;
6877 case BtOpComp:
6878 storeLE( mkexpr(t_addr1),
6879 binop(Iop_Xor8, mkexpr(t_fetched),
6880 mkexpr(t_mask)) );
6881 break;
6882 case BtOpReset:
6883 storeLE( mkexpr(t_addr1),
6884 binop(Iop_And8, mkexpr(t_fetched),
6885 unop(Iop_Not8, mkexpr(t_mask))) );
6886 break;
6887 default:
6888 vpanic("dis_bt_G_E(amd64)");
6889 }
6890 }
6891
6892 /* Side effect done; now get selected bit into Carry flag */
6893 /* Flags: C=selected bit, O,S,Z,A,P undefined, so are set to zero. */
6894 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(AMD64G_CC_OP_COPY) ));
6895 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
6896 stmt( IRStmt_Put(
6897 OFFB_CC_DEP1,
6898 binop(Iop_And64,
6899 binop(Iop_Shr64,
6900 unop(Iop_8Uto64, mkexpr(t_fetched)),
6901 mkexpr(t_bitno2)),
6902 mkU64(1)))
6903 );
6904 /* Set NDEP even though it isn't used. This makes redundant-PUT
6905 elimination of previous stores to this field work better. */
6906 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU64(0) ));
6907
6908 /* Move reg operand from stack back to reg */
6909 if (epartIsReg(modrm)) {
6910 /* t_esp still points at it. */
sewardj25d23862006-05-12 17:47:21 +00006911 /* only write the reg if actually modifying it; doing otherwise
6912 zeroes the top half erroneously when doing btl due to
6913 standard zero-extend rule */
6914 if (op != BtOpNone)
6915 putIRegE(sz, pfx, modrm, loadLE(szToITy(sz), mkexpr(t_rsp)) );
sewardj9ed16802005-08-24 10:46:19 +00006916 putIReg64(R_RSP, binop(Iop_Add64, mkexpr(t_rsp), mkU64(sz)) );
6917 }
6918
6919 DIP("bt%s%c %s, %s\n",
6920 nameBtOp(op), nameISize(sz), nameIRegG(sz, pfx, modrm),
6921 ( epartIsReg(modrm) ? nameIRegE(sz, pfx, modrm) : dis_buf ) );
6922
6923 return delta;
6924}
sewardjf53b7352005-04-06 20:01:56 +00006925
6926
6927
6928/* Handle BSF/BSR. Only v-size seems necessary. */
6929static
sewardj270def42005-07-03 01:03:01 +00006930ULong dis_bs_E_G ( Prefix pfx, Int sz, Long delta, Bool fwds )
sewardjf53b7352005-04-06 20:01:56 +00006931{
6932 Bool isReg;
6933 UChar modrm;
6934 HChar dis_buf[50];
6935
6936 IRType ty = szToITy(sz);
6937 IRTemp src = newTemp(ty);
6938 IRTemp dst = newTemp(ty);
6939 IRTemp src64 = newTemp(Ity_I64);
6940 IRTemp dst64 = newTemp(Ity_I64);
6941 IRTemp src8 = newTemp(Ity_I8);
6942
6943 vassert(sz == 8 || sz == 4 || sz == 2);
6944
6945 modrm = getUChar(delta);
6946 isReg = epartIsReg(modrm);
6947 if (isReg) {
6948 delta++;
6949 assign( src, getIRegE(sz, pfx, modrm) );
6950 } else {
6951 Int len;
6952 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
6953 delta += len;
6954 assign( src, loadLE(ty, mkexpr(addr)) );
6955 }
6956
6957 DIP("bs%c%c %s, %s\n",
6958 fwds ? 'f' : 'r', nameISize(sz),
6959 ( isReg ? nameIRegE(sz, pfx, modrm) : dis_buf ),
6960 nameIRegG(sz, pfx, modrm));
6961
6962 /* First, widen src to 64 bits if it is not already. */
6963 assign( src64, widenUto64(mkexpr(src)) );
6964
6965 /* Generate an 8-bit expression which is zero iff the
6966 original is zero, and nonzero otherwise */
6967 assign( src8,
6968 unop(Iop_1Uto8,
6969 binop(Iop_CmpNE64,
6970 mkexpr(src64), mkU64(0))) );
6971
6972 /* Flags: Z is 1 iff source value is zero. All others
6973 are undefined -- we force them to zero. */
6974 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(AMD64G_CC_OP_COPY) ));
6975 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
6976 stmt( IRStmt_Put(
6977 OFFB_CC_DEP1,
6978 IRExpr_Mux0X( mkexpr(src8),
6979 /* src==0 */
6980 mkU64(AMD64G_CC_MASK_Z),
6981 /* src!=0 */
6982 mkU64(0)
6983 )
6984 ));
6985 /* Set NDEP even though it isn't used. This makes redundant-PUT
6986 elimination of previous stores to this field work better. */
6987 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU64(0) ));
6988
6989 /* Result: iff source value is zero, we can't use
6990 Iop_Clz64/Iop_Ctz64 as they have no defined result in that case.
6991 But anyway, amd64 semantics say the result is undefined in
6992 such situations. Hence handle the zero case specially. */
6993
6994 /* Bleh. What we compute:
6995
6996 bsf64: if src == 0 then {dst is unchanged}
6997 else Ctz64(src)
6998
6999 bsr64: if src == 0 then {dst is unchanged}
7000 else 63 - Clz64(src)
7001
7002 bsf32: if src == 0 then {dst is unchanged}
7003 else Ctz64(32Uto64(src))
7004
7005 bsr32: if src == 0 then {dst is unchanged}
7006 else 63 - Clz64(32Uto64(src))
7007
7008 bsf16: if src == 0 then {dst is unchanged}
7009 else Ctz64(32Uto64(16Uto32(src)))
7010
7011 bsr16: if src == 0 then {dst is unchanged}
7012 else 63 - Clz64(32Uto64(16Uto32(src)))
7013 */
7014
7015 /* The main computation, guarding against zero. */
7016 assign( dst64,
7017 IRExpr_Mux0X(
7018 mkexpr(src8),
7019 /* src == 0 -- leave dst unchanged */
7020 widenUto64( getIRegG( sz, pfx, modrm ) ),
7021 /* src != 0 */
7022 fwds ? unop(Iop_Ctz64, mkexpr(src64))
7023 : binop(Iop_Sub64,
7024 mkU64(63),
7025 unop(Iop_Clz64, mkexpr(src64)))
7026 )
7027 );
7028
7029 if (sz == 2)
sewardje58967e2005-04-27 11:50:56 +00007030 assign( dst, unop(Iop_64to16, mkexpr(dst64)) );
sewardjf53b7352005-04-06 20:01:56 +00007031 else
7032 if (sz == 4)
7033 assign( dst, unop(Iop_64to32, mkexpr(dst64)) );
7034 else
7035 assign( dst, mkexpr(dst64) );
7036
7037 /* dump result back */
7038 putIRegG( sz, pfx, modrm, mkexpr(dst) );
7039
7040 return delta;
7041}
sewardja6b93d12005-02-17 09:28:28 +00007042
7043
7044/* swap rAX with the reg specified by reg and REX.B */
7045static
sewardj5b470602005-02-27 13:10:48 +00007046void codegen_xchg_rAX_Reg ( Prefix pfx, Int sz, UInt regLo3 )
sewardja6b93d12005-02-17 09:28:28 +00007047{
7048 IRType ty = szToITy(sz);
7049 IRTemp t1 = newTemp(ty);
7050 IRTemp t2 = newTemp(ty);
sewardj2d4fcd52005-05-18 11:47:47 +00007051 vassert(sz == 4 || sz == 8);
sewardj5b470602005-02-27 13:10:48 +00007052 vassert(regLo3 < 8);
sewardj2d4fcd52005-05-18 11:47:47 +00007053 if (sz == 8) {
7054 assign( t1, getIReg64(R_RAX) );
7055 assign( t2, getIRegRexB(8, pfx, regLo3) );
7056 putIReg64( R_RAX, mkexpr(t2) );
7057 putIRegRexB(8, pfx, regLo3, mkexpr(t1) );
7058 } else {
7059 assign( t1, getIReg32(R_RAX) );
7060 assign( t2, getIRegRexB(4, pfx, regLo3) );
7061 putIReg32( R_RAX, mkexpr(t2) );
7062 putIRegRexB(4, pfx, regLo3, mkexpr(t1) );
7063 }
sewardja6b93d12005-02-17 09:28:28 +00007064 DIP("xchg%c %s, %s\n",
sewardj5b470602005-02-27 13:10:48 +00007065 nameISize(sz), nameIRegRAX(sz),
sewardj2d4fcd52005-05-18 11:47:47 +00007066 nameIRegRexB(sz,pfx, regLo3));
sewardja6b93d12005-02-17 09:28:28 +00007067}
7068
7069
sewardjd20c8852005-01-20 20:04:07 +00007070//.. static
7071//.. void codegen_SAHF ( void )
7072//.. {
7073//.. /* Set the flags to:
7074//.. (x86g_calculate_flags_all() & X86G_CC_MASK_O) -- retain the old O flag
7075//.. | (%AH & (X86G_CC_MASK_S|X86G_CC_MASK_Z|X86G_CC_MASK_A
7076//.. |X86G_CC_MASK_P|X86G_CC_MASK_C)
7077//.. */
7078//.. UInt mask_SZACP = X86G_CC_MASK_S|X86G_CC_MASK_Z|X86G_CC_MASK_A
7079//.. |X86G_CC_MASK_C|X86G_CC_MASK_P;
7080//.. IRTemp oldflags = newTemp(Ity_I32);
7081//.. assign( oldflags, mk_x86g_calculate_eflags_all() );
7082//.. stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
7083//.. stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
7084//.. stmt( IRStmt_Put( OFFB_CC_DEP1,
7085//.. binop(Iop_Or32,
7086//.. binop(Iop_And32, mkexpr(oldflags), mkU32(X86G_CC_MASK_O)),
7087//.. binop(Iop_And32,
7088//.. binop(Iop_Shr32, getIReg(4, R_EAX), mkU8(8)),
7089//.. mkU32(mask_SZACP))
7090//.. )
7091//.. ));
7092//.. }
7093//..
7094//..
7095//.. //-- static
7096//.. //-- void codegen_LAHF ( UCodeBlock* cb )
7097//.. //-- {
7098//.. //-- Int t = newTemp(cb);
7099//.. //--
7100//.. //-- /* Pushed arg is ignored, it just provides somewhere to put the
7101//.. //-- return value. */
7102//.. //-- uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, t);
7103//.. //-- uInstr0(cb, CALLM_S, 0);
7104//.. //-- uInstr1(cb, PUSH, 4, TempReg, t);
7105//.. //-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_LAHF));
7106//.. //-- uFlagsRWU(cb, FlagsSZACP, FlagsEmpty, FlagsEmpty);
7107//.. //-- uInstr1(cb, POP, 4, TempReg, t);
7108//.. //-- uInstr0(cb, CALLM_E, 0);
7109//.. //--
7110//.. //-- /* At this point, the %ah sub-register in %eax has been updated,
7111//.. //-- the rest is the same, so do a PUT of the whole thing. */
7112//.. //-- uInstr2(cb, PUT, 4, TempReg, t, ArchReg, R_EAX);
7113//.. //-- }
7114//.. //--
sewardja6b93d12005-02-17 09:28:28 +00007115
7116static
7117ULong dis_cmpxchg_G_E ( Prefix pfx,
7118 Int size,
sewardj270def42005-07-03 01:03:01 +00007119 Long delta0 )
sewardja6b93d12005-02-17 09:28:28 +00007120{
7121 HChar dis_buf[50];
7122 Int len;
7123
7124 IRType ty = szToITy(size);
7125 IRTemp acc = newTemp(ty);
7126 IRTemp src = newTemp(ty);
7127 IRTemp dest = newTemp(ty);
7128 IRTemp dest2 = newTemp(ty);
7129 IRTemp acc2 = newTemp(ty);
7130 IRTemp cond8 = newTemp(Ity_I8);
7131 IRTemp addr = IRTemp_INVALID;
7132 UChar rm = getUChar(delta0);
7133
7134 if (epartIsReg(rm)) {
sewardj5b470602005-02-27 13:10:48 +00007135 vassert(0); /* awaiting test case */
7136 assign( dest, getIRegE(size, pfx, rm) );
sewardja6b93d12005-02-17 09:28:28 +00007137 delta0++;
7138 DIP("cmpxchg%c %s,%s\n", nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00007139 nameIRegG(size,pfx,rm),
7140 nameIRegE(size,pfx,rm) );
sewardja6b93d12005-02-17 09:28:28 +00007141 } else {
7142 addr = disAMode ( &len, pfx, delta0, dis_buf, 0 );
7143 assign( dest, loadLE(ty, mkexpr(addr)) );
7144 delta0 += len;
7145 DIP("cmpxchg%c %s,%s\n", nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00007146 nameIRegG(size,pfx,rm), dis_buf);
sewardja6b93d12005-02-17 09:28:28 +00007147 }
7148
sewardj5b470602005-02-27 13:10:48 +00007149 assign( src, getIRegG(size, pfx, rm) );
7150 assign( acc, getIRegRAX(size) );
sewardja6b93d12005-02-17 09:28:28 +00007151 setFlags_DEP1_DEP2(Iop_Sub8, acc, dest, ty);
7152 assign( cond8, unop(Iop_1Uto8, mk_amd64g_calculate_condition(AMD64CondZ)) );
7153 assign( dest2, IRExpr_Mux0X(mkexpr(cond8), mkexpr(dest), mkexpr(src)) );
7154 assign( acc2, IRExpr_Mux0X(mkexpr(cond8), mkexpr(dest), mkexpr(acc)) );
sewardj5b470602005-02-27 13:10:48 +00007155 putIRegRAX(size, mkexpr(acc2));
sewardja6b93d12005-02-17 09:28:28 +00007156
7157 if (epartIsReg(rm)) {
sewardj5b470602005-02-27 13:10:48 +00007158 putIRegE(size, pfx, rm, mkexpr(dest2));
sewardja6b93d12005-02-17 09:28:28 +00007159 } else {
7160 storeLE( mkexpr(addr), mkexpr(dest2) );
7161 }
7162
7163 return delta0;
7164}
7165
7166
sewardjd20c8852005-01-20 20:04:07 +00007167//.. //-- static
7168//.. //-- Addr dis_cmpxchg8b ( UCodeBlock* cb,
7169//.. //-- UChar sorb,
7170//.. //-- Addr eip0 )
7171//.. //-- {
7172//.. //-- Int tal, tah, junkl, junkh, destl, desth, srcl, srch, accl, acch;
7173//.. //-- HChar dis_buf[50];
7174//.. //-- UChar rm;
7175//.. //-- UInt pair;
7176//.. //--
7177//.. //-- rm = getUChar(eip0);
7178//.. //-- accl = newTemp(cb);
7179//.. //-- acch = newTemp(cb);
7180//.. //-- srcl = newTemp(cb);
7181//.. //-- srch = newTemp(cb);
7182//.. //-- destl = newTemp(cb);
7183//.. //-- desth = newTemp(cb);
7184//.. //-- junkl = newTemp(cb);
7185//.. //-- junkh = newTemp(cb);
7186//.. //--
7187//.. //-- vg_assert(!epartIsReg(rm));
7188//.. //--
7189//.. //-- pair = disAMode ( cb, sorb, eip0, dis_buf );
7190//.. //-- tal = LOW24(pair);
7191//.. //-- tah = newTemp(cb);
7192//.. //-- uInstr2(cb, MOV, 4, TempReg, tal, TempReg, tah);
7193//.. //-- uInstr2(cb, ADD, 4, Literal, 0, TempReg, tah);
7194//.. //-- uLiteral(cb, 4);
7195//.. //-- eip0 += HI8(pair);
7196//.. //-- DIP("cmpxchg8b %s\n", dis_buf);
7197//.. //--
7198//.. //-- uInstr0(cb, CALLM_S, 0);
7199//.. //--
7200//.. //-- uInstr2(cb, LOAD, 4, TempReg, tah, TempReg, desth);
7201//.. //-- uInstr1(cb, PUSH, 4, TempReg, desth);
7202//.. //-- uInstr2(cb, LOAD, 4, TempReg, tal, TempReg, destl);
7203//.. //-- uInstr1(cb, PUSH, 4, TempReg, destl);
7204//.. //-- uInstr2(cb, GET, 4, ArchReg, R_ECX, TempReg, srch);
7205//.. //-- uInstr1(cb, PUSH, 4, TempReg, srch);
7206//.. //-- uInstr2(cb, GET, 4, ArchReg, R_EBX, TempReg, srcl);
7207//.. //-- uInstr1(cb, PUSH, 4, TempReg, srcl);
7208//.. //-- uInstr2(cb, GET, 4, ArchReg, R_EDX, TempReg, acch);
7209//.. //-- uInstr1(cb, PUSH, 4, TempReg, acch);
7210//.. //-- uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, accl);
7211//.. //-- uInstr1(cb, PUSH, 4, TempReg, accl);
7212//.. //--
7213//.. //-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_cmpxchg8b));
7214//.. //-- uFlagsRWU(cb, FlagsEmpty, FlagZ, FlagsEmpty);
7215//.. //--
7216//.. //-- uInstr1(cb, POP, 4, TempReg, accl);
7217//.. //-- uInstr2(cb, PUT, 4, TempReg, accl, ArchReg, R_EAX);
7218//.. //-- uInstr1(cb, POP, 4, TempReg, acch);
7219//.. //-- uInstr2(cb, PUT, 4, TempReg, acch, ArchReg, R_EDX);
7220//.. //-- uInstr1(cb, POP, 4, TempReg, srcl);
7221//.. //-- uInstr2(cb, PUT, 4, TempReg, srcl, ArchReg, R_EBX);
7222//.. //-- uInstr1(cb, POP, 4, TempReg, srch);
7223//.. //-- uInstr2(cb, PUT, 4, TempReg, srch, ArchReg, R_ECX);
7224//.. //-- uInstr1(cb, POP, 4, TempReg, destl);
7225//.. //-- uInstr2(cb, STORE, 4, TempReg, destl, TempReg, tal);
7226//.. //-- uInstr1(cb, POP, 4, TempReg, desth);
7227//.. //-- uInstr2(cb, STORE, 4, TempReg, desth, TempReg, tah);
7228//.. //--
7229//.. //-- uInstr0(cb, CALLM_E, 0);
7230//.. //--
7231//.. //-- return eip0;
7232//.. //-- }
sewardj3ca55a12005-01-27 16:06:23 +00007233
7234
7235/* Handle conditional move instructions of the form
7236 cmovcc E(reg-or-mem), G(reg)
7237
7238 E(src) is reg-or-mem
7239 G(dst) is reg.
7240
7241 If E is reg, --> GET %E, tmps
7242 GET %G, tmpd
7243 CMOVcc tmps, tmpd
7244 PUT tmpd, %G
7245
7246 If E is mem --> (getAddr E) -> tmpa
7247 LD (tmpa), tmps
7248 GET %G, tmpd
7249 CMOVcc tmps, tmpd
7250 PUT tmpd, %G
7251*/
7252static
7253ULong dis_cmov_E_G ( Prefix pfx,
7254 Int sz,
7255 AMD64Condcode cond,
sewardj270def42005-07-03 01:03:01 +00007256 Long delta0 )
sewardj3ca55a12005-01-27 16:06:23 +00007257{
sewardj8c332e22005-01-28 01:36:56 +00007258 UChar rm = getUChar(delta0);
sewardj3ca55a12005-01-27 16:06:23 +00007259 HChar dis_buf[50];
7260 Int len;
7261
7262 IRType ty = szToITy(sz);
7263 IRTemp tmps = newTemp(ty);
7264 IRTemp tmpd = newTemp(ty);
7265
7266 if (epartIsReg(rm)) {
sewardj5b470602005-02-27 13:10:48 +00007267 assign( tmps, getIRegE(sz, pfx, rm) );
7268 assign( tmpd, getIRegG(sz, pfx, rm) );
sewardj3ca55a12005-01-27 16:06:23 +00007269
sewardj5b470602005-02-27 13:10:48 +00007270 putIRegG( sz, pfx, rm,
sewardj3ca55a12005-01-27 16:06:23 +00007271 IRExpr_Mux0X( unop(Iop_1Uto8,
7272 mk_amd64g_calculate_condition(cond)),
7273 mkexpr(tmpd),
7274 mkexpr(tmps) )
7275 );
sewardje941eea2005-01-30 19:52:28 +00007276 DIP("cmov%s %s,%s\n", name_AMD64Condcode(cond),
sewardj5b470602005-02-27 13:10:48 +00007277 nameIRegE(sz,pfx,rm),
7278 nameIRegG(sz,pfx,rm));
sewardj3ca55a12005-01-27 16:06:23 +00007279 return 1+delta0;
7280 }
7281
7282 /* E refers to memory */
7283 {
sewardje1698952005-02-08 15:02:39 +00007284 IRTemp addr = disAMode ( &len, pfx, delta0, dis_buf, 0 );
sewardj3ca55a12005-01-27 16:06:23 +00007285 assign( tmps, loadLE(ty, mkexpr(addr)) );
sewardj5b470602005-02-27 13:10:48 +00007286 assign( tmpd, getIRegG(sz, pfx, rm) );
sewardj3ca55a12005-01-27 16:06:23 +00007287
sewardj5b470602005-02-27 13:10:48 +00007288 putIRegG( sz, pfx, rm,
sewardj3ca55a12005-01-27 16:06:23 +00007289 IRExpr_Mux0X( unop(Iop_1Uto8,
7290 mk_amd64g_calculate_condition(cond)),
7291 mkexpr(tmpd),
7292 mkexpr(tmps) )
7293 );
7294
sewardj7eaa7cf2005-01-31 18:55:22 +00007295 DIP("cmov%s %s,%s\n", name_AMD64Condcode(cond),
7296 dis_buf,
sewardj5b470602005-02-27 13:10:48 +00007297 nameIRegG(sz,pfx,rm));
sewardj3ca55a12005-01-27 16:06:23 +00007298 return len+delta0;
7299 }
7300}
7301
7302
sewardjb4fd2e72005-03-23 13:34:11 +00007303static
7304ULong dis_xadd_G_E ( /*OUT*/Bool* decode_ok,
sewardj270def42005-07-03 01:03:01 +00007305 Prefix pfx, Int sz, Long delta0 )
sewardjb4fd2e72005-03-23 13:34:11 +00007306{
7307 Int len;
7308 UChar rm = getUChar(delta0);
7309 HChar dis_buf[50];
7310
7311 IRType ty = szToITy(sz);
7312 IRTemp tmpd = newTemp(ty);
7313 IRTemp tmpt0 = newTemp(ty);
7314 IRTemp tmpt1 = newTemp(ty);
7315 *decode_ok = True;
7316
7317 if (epartIsReg(rm)) {
7318 *decode_ok = False;
7319 return delta0;
7320 } else {
7321 IRTemp addr = disAMode ( &len, pfx, delta0, dis_buf, 0 );
7322 assign( tmpd, loadLE(ty, mkexpr(addr)) );
7323 assign( tmpt0, getIRegG(sz, pfx, rm) );
7324 assign( tmpt1, binop(mkSizedOp(ty,Iop_Add8), mkexpr(tmpd), mkexpr(tmpt0)) );
7325 setFlags_DEP1_DEP2( Iop_Add8, tmpd, tmpt0, ty );
7326 storeLE( mkexpr(addr), mkexpr(tmpt1) );
7327 putIRegG(sz, pfx, rm, mkexpr(tmpd));
7328 DIP("xadd%c %s, %s\n",
7329 nameISize(sz), nameIRegG(sz,pfx,rm), dis_buf);
7330 return len+delta0;
7331 }
7332}
7333
sewardjd20c8852005-01-20 20:04:07 +00007334//.. /* Move 16 bits from Ew (ireg or mem) to G (a segment register). */
7335//..
7336//.. static
sewardj270def42005-07-03 01:03:01 +00007337//.. UInt dis_mov_Ew_Sw ( UChar sorb, Long delta0 )
sewardjd20c8852005-01-20 20:04:07 +00007338//.. {
7339//.. Int len;
7340//.. IRTemp addr;
sewardj8c332e22005-01-28 01:36:56 +00007341//.. UChar rm = getUChar(delta0);
sewardjd20c8852005-01-20 20:04:07 +00007342//.. HChar dis_buf[50];
7343//..
7344//.. if (epartIsReg(rm)) {
7345//.. putSReg( gregOfRM(rm), getIReg(2, eregOfRM(rm)) );
7346//.. DIP("movw %s,%s\n", nameIReg(2,eregOfRM(rm)), nameSReg(gregOfRM(rm)));
7347//.. return 1+delta0;
7348//.. } else {
7349//.. addr = disAMode ( &len, sorb, delta0, dis_buf );
7350//.. putSReg( gregOfRM(rm), loadLE(Ity_I16, mkexpr(addr)) );
7351//.. DIP("movw %s,%s\n", dis_buf, nameSReg(gregOfRM(rm)));
7352//.. return len+delta0;
7353//.. }
7354//.. }
7355//..
7356//.. /* Move 16 bits from G (a segment register) to Ew (ireg or mem). If
7357//.. dst is ireg and sz==4, zero out top half of it. */
7358//..
7359//.. static
7360//.. UInt dis_mov_Sw_Ew ( UChar sorb,
7361//.. Int sz,
7362//.. UInt delta0 )
7363//.. {
7364//.. Int len;
7365//.. IRTemp addr;
sewardj8c332e22005-01-28 01:36:56 +00007366//.. UChar rm = getUChar(delta0);
sewardjd20c8852005-01-20 20:04:07 +00007367//.. HChar dis_buf[50];
7368//..
7369//.. vassert(sz == 2 || sz == 4);
7370//..
7371//.. if (epartIsReg(rm)) {
7372//.. if (sz == 4)
7373//.. putIReg(4, eregOfRM(rm), unop(Iop_16Uto32, getSReg(gregOfRM(rm))));
7374//.. else
7375//.. putIReg(2, eregOfRM(rm), getSReg(gregOfRM(rm)));
7376//..
7377//.. DIP("mov %s,%s\n", nameSReg(gregOfRM(rm)), nameIReg(sz,eregOfRM(rm)));
7378//.. return 1+delta0;
7379//.. } else {
7380//.. addr = disAMode ( &len, sorb, delta0, dis_buf );
7381//.. storeLE( mkexpr(addr), getSReg(gregOfRM(rm)) );
7382//.. DIP("mov %s,%s\n", nameSReg(gregOfRM(rm)), dis_buf);
7383//.. return len+delta0;
7384//.. }
7385//.. }
7386//..
7387//..
7388//.. static
7389//.. void dis_push_segreg ( UInt sreg, Int sz )
7390//.. {
7391//.. IRTemp t1 = newTemp(Ity_I16);
7392//.. IRTemp ta = newTemp(Ity_I32);
7393//.. vassert(sz == 2 || sz == 4);
7394//..
7395//.. assign( t1, getSReg(sreg) );
7396//.. assign( ta, binop(Iop_Sub32, getIReg(4, R_ESP), mkU32(sz)) );
7397//.. putIReg(4, R_ESP, mkexpr(ta));
7398//.. storeLE( mkexpr(ta), mkexpr(t1) );
7399//..
7400//.. DIP("pushw %s\n", nameSReg(sreg));
7401//.. }
7402//..
7403//.. static
7404//.. void dis_pop_segreg ( UInt sreg, Int sz )
7405//.. {
7406//.. IRTemp t1 = newTemp(Ity_I16);
7407//.. IRTemp ta = newTemp(Ity_I32);
7408//.. vassert(sz == 2 || sz == 4);
7409//..
7410//.. assign( ta, getIReg(4, R_ESP) );
7411//.. assign( t1, loadLE(Ity_I16, mkexpr(ta)) );
7412//..
7413//.. putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(ta), mkU32(sz)) );
7414//.. putSReg( sreg, mkexpr(t1) );
7415//.. DIP("pop %s\n", nameSReg(sreg));
7416//.. }
sewardj2f959cc2005-01-26 01:19:35 +00007417
7418static
7419void dis_ret ( ULong d64 )
7420{
7421 IRTemp t1 = newTemp(Ity_I64);
7422 IRTemp t2 = newTemp(Ity_I64);
sewardj5a9ffab2005-05-12 17:55:01 +00007423 IRTemp t3 = newTemp(Ity_I64);
sewardj2f959cc2005-01-26 01:19:35 +00007424 assign(t1, getIReg64(R_RSP));
7425 assign(t2, loadLE(Ity_I64,mkexpr(t1)));
sewardj5a9ffab2005-05-12 17:55:01 +00007426 assign(t3, binop(Iop_Add64, mkexpr(t1), mkU64(8+d64)));
7427 putIReg64(R_RSP, mkexpr(t3));
7428 make_redzone_AbiHint(t3, "ret");
sewardj2f959cc2005-01-26 01:19:35 +00007429 jmp_treg(Ijk_Ret,t2);
7430}
7431
sewardj5b470602005-02-27 13:10:48 +00007432
sewardj1001dc42005-02-21 08:25:55 +00007433/*------------------------------------------------------------*/
7434/*--- SSE/SSE2/SSE3 helpers ---*/
7435/*------------------------------------------------------------*/
7436
7437/* Worker function; do not call directly.
7438 Handles full width G = G `op` E and G = (not G) `op` E.
7439*/
7440
sewardj8d965312005-02-25 02:48:47 +00007441static ULong dis_SSE_E_to_G_all_wrk (
sewardj270def42005-07-03 01:03:01 +00007442 Prefix pfx, Long delta,
sewardj8d965312005-02-25 02:48:47 +00007443 HChar* opname, IROp op,
7444 Bool invertG
7445 )
sewardj9da16972005-02-21 13:58:26 +00007446{
7447 HChar dis_buf[50];
7448 Int alen;
7449 IRTemp addr;
7450 UChar rm = getUChar(delta);
7451 IRExpr* gpart
7452 = invertG ? unop(Iop_NotV128, getXMMReg(gregOfRexRM(pfx,rm)))
7453 : getXMMReg(gregOfRexRM(pfx,rm));
7454 if (epartIsReg(rm)) {
7455 putXMMReg( gregOfRexRM(pfx,rm),
7456 binop(op, gpart,
7457 getXMMReg(eregOfRexRM(pfx,rm))) );
7458 DIP("%s %s,%s\n", opname,
7459 nameXMMReg(eregOfRexRM(pfx,rm)),
7460 nameXMMReg(gregOfRexRM(pfx,rm)) );
7461 return delta+1;
7462 } else {
7463 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
7464 putXMMReg( gregOfRexRM(pfx,rm),
7465 binop(op, gpart,
7466 loadLE(Ity_V128, mkexpr(addr))) );
7467 DIP("%s %s,%s\n", opname,
7468 dis_buf,
7469 nameXMMReg(gregOfRexRM(pfx,rm)) );
7470 return delta+alen;
7471 }
7472}
7473
7474
7475/* All lanes SSE binary operation, G = G `op` E. */
7476
7477static
sewardj270def42005-07-03 01:03:01 +00007478ULong dis_SSE_E_to_G_all ( Prefix pfx, Long delta,
sewardj8d965312005-02-25 02:48:47 +00007479 HChar* opname, IROp op )
sewardj9da16972005-02-21 13:58:26 +00007480{
7481 return dis_SSE_E_to_G_all_wrk( pfx, delta, opname, op, False );
7482}
7483
sewardj8d965312005-02-25 02:48:47 +00007484/* All lanes SSE binary operation, G = (not G) `op` E. */
7485
7486static
sewardj270def42005-07-03 01:03:01 +00007487ULong dis_SSE_E_to_G_all_invG ( Prefix pfx, Long delta,
sewardj8d965312005-02-25 02:48:47 +00007488 HChar* opname, IROp op )
7489{
7490 return dis_SSE_E_to_G_all_wrk( pfx, delta, opname, op, True );
7491}
7492
7493
7494/* Lowest 32-bit lane only SSE binary operation, G = G `op` E. */
7495
sewardj270def42005-07-03 01:03:01 +00007496static ULong dis_SSE_E_to_G_lo32 ( Prefix pfx, Long delta,
sewardj8d965312005-02-25 02:48:47 +00007497 HChar* opname, IROp op )
7498{
7499 HChar dis_buf[50];
7500 Int alen;
7501 IRTemp addr;
7502 UChar rm = getUChar(delta);
sewardj9c9ee3d2005-02-26 01:17:42 +00007503 IRExpr* gpart = getXMMReg(gregOfRexRM(pfx,rm));
sewardj8d965312005-02-25 02:48:47 +00007504 if (epartIsReg(rm)) {
sewardj9c9ee3d2005-02-26 01:17:42 +00007505 putXMMReg( gregOfRexRM(pfx,rm),
sewardj8d965312005-02-25 02:48:47 +00007506 binop(op, gpart,
7507 getXMMReg(eregOfRexRM(pfx,rm))) );
7508 DIP("%s %s,%s\n", opname,
7509 nameXMMReg(eregOfRexRM(pfx,rm)),
7510 nameXMMReg(gregOfRexRM(pfx,rm)) );
7511 return delta+1;
7512 } else {
7513 /* We can only do a 32-bit memory read, so the upper 3/4 of the
7514 E operand needs to be made simply of zeroes. */
7515 IRTemp epart = newTemp(Ity_V128);
7516 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
7517 assign( epart, unop( Iop_32UtoV128,
7518 loadLE(Ity_I32, mkexpr(addr))) );
7519 putXMMReg( gregOfRexRM(pfx,rm),
7520 binop(op, gpart, mkexpr(epart)) );
7521 DIP("%s %s,%s\n", opname,
7522 dis_buf,
7523 nameXMMReg(gregOfRexRM(pfx,rm)) );
7524 return delta+alen;
7525 }
7526}
sewardj1001dc42005-02-21 08:25:55 +00007527
7528
7529/* Lower 64-bit lane only SSE binary operation, G = G `op` E. */
7530
sewardj270def42005-07-03 01:03:01 +00007531static ULong dis_SSE_E_to_G_lo64 ( Prefix pfx, Long delta,
sewardj8d965312005-02-25 02:48:47 +00007532 HChar* opname, IROp op )
sewardj1001dc42005-02-21 08:25:55 +00007533{
7534 HChar dis_buf[50];
7535 Int alen;
7536 IRTemp addr;
7537 UChar rm = getUChar(delta);
7538 IRExpr* gpart = getXMMReg(gregOfRexRM(pfx,rm));
7539 if (epartIsReg(rm)) {
7540 putXMMReg( gregOfRexRM(pfx,rm),
7541 binop(op, gpart,
7542 getXMMReg(eregOfRexRM(pfx,rm))) );
7543 DIP("%s %s,%s\n", opname,
7544 nameXMMReg(eregOfRexRM(pfx,rm)),
7545 nameXMMReg(gregOfRexRM(pfx,rm)) );
7546 return delta+1;
7547 } else {
7548 /* We can only do a 64-bit memory read, so the upper half of the
7549 E operand needs to be made simply of zeroes. */
7550 IRTemp epart = newTemp(Ity_V128);
7551 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
7552 assign( epart, unop( Iop_64UtoV128,
7553 loadLE(Ity_I64, mkexpr(addr))) );
7554 putXMMReg( gregOfRexRM(pfx,rm),
7555 binop(op, gpart, mkexpr(epart)) );
7556 DIP("%s %s,%s\n", opname,
7557 dis_buf,
7558 nameXMMReg(gregOfRexRM(pfx,rm)) );
7559 return delta+alen;
7560 }
7561}
7562
7563
sewardja7ba8c42005-05-10 20:08:34 +00007564/* All lanes unary SSE operation, G = op(E). */
7565
7566static ULong dis_SSE_E_to_G_unary_all (
sewardj270def42005-07-03 01:03:01 +00007567 Prefix pfx, Long delta,
sewardja7ba8c42005-05-10 20:08:34 +00007568 HChar* opname, IROp op
7569 )
7570{
7571 HChar dis_buf[50];
7572 Int alen;
7573 IRTemp addr;
7574 UChar rm = getUChar(delta);
7575 if (epartIsReg(rm)) {
7576 putXMMReg( gregOfRexRM(pfx,rm),
7577 unop(op, getXMMReg(eregOfRexRM(pfx,rm))) );
7578 DIP("%s %s,%s\n", opname,
7579 nameXMMReg(eregOfRexRM(pfx,rm)),
7580 nameXMMReg(gregOfRexRM(pfx,rm)) );
7581 return delta+1;
7582 } else {
7583 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
7584 putXMMReg( gregOfRexRM(pfx,rm),
7585 unop(op, loadLE(Ity_V128, mkexpr(addr))) );
7586 DIP("%s %s,%s\n", opname,
7587 dis_buf,
7588 nameXMMReg(gregOfRexRM(pfx,rm)) );
7589 return delta+alen;
7590 }
7591}
7592
7593
7594/* Lowest 32-bit lane only unary SSE operation, G = op(E). */
7595
7596static ULong dis_SSE_E_to_G_unary_lo32 (
sewardj270def42005-07-03 01:03:01 +00007597 Prefix pfx, Long delta,
sewardja7ba8c42005-05-10 20:08:34 +00007598 HChar* opname, IROp op
7599 )
7600{
7601 /* First we need to get the old G value and patch the low 32 bits
7602 of the E operand into it. Then apply op and write back to G. */
7603 HChar dis_buf[50];
7604 Int alen;
7605 IRTemp addr;
7606 UChar rm = getUChar(delta);
7607 IRTemp oldG0 = newTemp(Ity_V128);
7608 IRTemp oldG1 = newTemp(Ity_V128);
7609
7610 assign( oldG0, getXMMReg(gregOfRexRM(pfx,rm)) );
7611
7612 if (epartIsReg(rm)) {
7613 assign( oldG1,
7614 binop( Iop_SetV128lo32,
7615 mkexpr(oldG0),
7616 getXMMRegLane32(eregOfRexRM(pfx,rm), 0)) );
7617 putXMMReg( gregOfRexRM(pfx,rm), unop(op, mkexpr(oldG1)) );
7618 DIP("%s %s,%s\n", opname,
7619 nameXMMReg(eregOfRexRM(pfx,rm)),
7620 nameXMMReg(gregOfRexRM(pfx,rm)) );
7621 return delta+1;
7622 } else {
7623 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
7624 assign( oldG1,
7625 binop( Iop_SetV128lo32,
7626 mkexpr(oldG0),
7627 loadLE(Ity_I32, mkexpr(addr)) ));
7628 putXMMReg( gregOfRexRM(pfx,rm), unop(op, mkexpr(oldG1)) );
7629 DIP("%s %s,%s\n", opname,
7630 dis_buf,
7631 nameXMMReg(gregOfRexRM(pfx,rm)) );
7632 return delta+alen;
7633 }
7634}
sewardj1001dc42005-02-21 08:25:55 +00007635
7636
7637/* Lowest 64-bit lane only unary SSE operation, G = op(E). */
7638
sewardj8d965312005-02-25 02:48:47 +00007639static ULong dis_SSE_E_to_G_unary_lo64 (
sewardj270def42005-07-03 01:03:01 +00007640 Prefix pfx, Long delta,
sewardj8d965312005-02-25 02:48:47 +00007641 HChar* opname, IROp op
7642 )
sewardj1001dc42005-02-21 08:25:55 +00007643{
7644 /* First we need to get the old G value and patch the low 64 bits
7645 of the E operand into it. Then apply op and write back to G. */
7646 HChar dis_buf[50];
7647 Int alen;
7648 IRTemp addr;
7649 UChar rm = getUChar(delta);
7650 IRTemp oldG0 = newTemp(Ity_V128);
7651 IRTemp oldG1 = newTemp(Ity_V128);
7652
7653 assign( oldG0, getXMMReg(gregOfRexRM(pfx,rm)) );
7654
7655 if (epartIsReg(rm)) {
7656 assign( oldG1,
7657 binop( Iop_SetV128lo64,
7658 mkexpr(oldG0),
7659 getXMMRegLane64(eregOfRexRM(pfx,rm), 0)) );
7660 putXMMReg( gregOfRexRM(pfx,rm), unop(op, mkexpr(oldG1)) );
7661 DIP("%s %s,%s\n", opname,
7662 nameXMMReg(eregOfRexRM(pfx,rm)),
7663 nameXMMReg(gregOfRexRM(pfx,rm)) );
7664 return delta+1;
7665 } else {
7666 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
7667 assign( oldG1,
7668 binop( Iop_SetV128lo64,
7669 mkexpr(oldG0),
7670 loadLE(Ity_I64, mkexpr(addr)) ));
7671 putXMMReg( gregOfRexRM(pfx,rm), unop(op, mkexpr(oldG1)) );
7672 DIP("%s %s,%s\n", opname,
7673 dis_buf,
7674 nameXMMReg(gregOfRexRM(pfx,rm)) );
7675 return delta+alen;
7676 }
7677}
7678
7679
sewardj09717342005-05-05 21:34:02 +00007680/* SSE integer binary operation:
7681 G = G `op` E (eLeft == False)
7682 G = E `op` G (eLeft == True)
7683*/
7684static ULong dis_SSEint_E_to_G(
sewardj270def42005-07-03 01:03:01 +00007685 Prefix pfx, Long delta,
sewardj09717342005-05-05 21:34:02 +00007686 HChar* opname, IROp op,
7687 Bool eLeft
7688 )
7689{
7690 HChar dis_buf[50];
7691 Int alen;
7692 IRTemp addr;
7693 UChar rm = getUChar(delta);
7694 IRExpr* gpart = getXMMReg(gregOfRexRM(pfx,rm));
7695 IRExpr* epart = NULL;
7696 if (epartIsReg(rm)) {
7697 epart = getXMMReg(eregOfRexRM(pfx,rm));
7698 DIP("%s %s,%s\n", opname,
7699 nameXMMReg(eregOfRexRM(pfx,rm)),
7700 nameXMMReg(gregOfRexRM(pfx,rm)) );
7701 delta += 1;
7702 } else {
7703 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
7704 epart = loadLE(Ity_V128, mkexpr(addr));
7705 DIP("%s %s,%s\n", opname,
7706 dis_buf,
7707 nameXMMReg(gregOfRexRM(pfx,rm)) );
7708 delta += alen;
7709 }
7710 putXMMReg( gregOfRexRM(pfx,rm),
7711 eLeft ? binop(op, epart, gpart)
7712 : binop(op, gpart, epart) );
7713 return delta;
7714}
sewardj8d965312005-02-25 02:48:47 +00007715
7716
7717/* Helper for doing SSE FP comparisons. */
7718
7719static void findSSECmpOp ( Bool* needNot, IROp* op,
7720 Int imm8, Bool all_lanes, Int sz )
7721{
7722 imm8 &= 7;
7723 *needNot = False;
7724 *op = Iop_INVALID;
7725 if (imm8 >= 4) {
7726 *needNot = True;
7727 imm8 -= 4;
7728 }
7729
7730 if (sz == 4 && all_lanes) {
7731 switch (imm8) {
7732 case 0: *op = Iop_CmpEQ32Fx4; return;
7733 case 1: *op = Iop_CmpLT32Fx4; return;
7734 case 2: *op = Iop_CmpLE32Fx4; return;
7735 case 3: *op = Iop_CmpUN32Fx4; return;
7736 default: break;
7737 }
7738 }
7739 if (sz == 4 && !all_lanes) {
7740 switch (imm8) {
7741 case 0: *op = Iop_CmpEQ32F0x4; return;
7742 case 1: *op = Iop_CmpLT32F0x4; return;
7743 case 2: *op = Iop_CmpLE32F0x4; return;
7744 case 3: *op = Iop_CmpUN32F0x4; return;
7745 default: break;
7746 }
7747 }
7748 if (sz == 8 && all_lanes) {
7749 switch (imm8) {
7750 case 0: *op = Iop_CmpEQ64Fx2; return;
7751 case 1: *op = Iop_CmpLT64Fx2; return;
7752 case 2: *op = Iop_CmpLE64Fx2; return;
7753 case 3: *op = Iop_CmpUN64Fx2; return;
7754 default: break;
7755 }
7756 }
7757 if (sz == 8 && !all_lanes) {
7758 switch (imm8) {
7759 case 0: *op = Iop_CmpEQ64F0x2; return;
7760 case 1: *op = Iop_CmpLT64F0x2; return;
7761 case 2: *op = Iop_CmpLE64F0x2; return;
7762 case 3: *op = Iop_CmpUN64F0x2; return;
7763 default: break;
7764 }
7765 }
7766 vpanic("findSSECmpOp(amd64,guest)");
7767}
7768
sewardjab9055b2006-01-01 13:17:38 +00007769/* Handles SSE 32F/64F comparisons. */
sewardj8d965312005-02-25 02:48:47 +00007770
sewardj270def42005-07-03 01:03:01 +00007771static ULong dis_SSEcmp_E_to_G ( Prefix pfx, Long delta,
sewardj8d965312005-02-25 02:48:47 +00007772 HChar* opname, Bool all_lanes, Int sz )
7773{
7774 HChar dis_buf[50];
7775 Int alen, imm8;
7776 IRTemp addr;
7777 Bool needNot = False;
7778 IROp op = Iop_INVALID;
7779 IRTemp plain = newTemp(Ity_V128);
7780 UChar rm = getUChar(delta);
7781 UShort mask = 0;
7782 vassert(sz == 4 || sz == 8);
7783 if (epartIsReg(rm)) {
7784 imm8 = getUChar(delta+1);
7785 findSSECmpOp(&needNot, &op, imm8, all_lanes, sz);
7786 assign( plain, binop(op, getXMMReg(gregOfRexRM(pfx,rm)),
7787 getXMMReg(eregOfRexRM(pfx,rm))) );
7788 delta += 2;
7789 DIP("%s $%d,%s,%s\n", opname,
7790 (Int)imm8,
7791 nameXMMReg(eregOfRexRM(pfx,rm)),
7792 nameXMMReg(gregOfRexRM(pfx,rm)) );
7793 } else {
7794 addr = disAMode ( &alen, pfx, delta, dis_buf, 1 );
7795 imm8 = getUChar(delta+alen);
7796 findSSECmpOp(&needNot, &op, imm8, all_lanes, sz);
sewardjab9055b2006-01-01 13:17:38 +00007797 assign( plain,
7798 binop(
7799 op,
7800 getXMMReg(gregOfRexRM(pfx,rm)),
7801 all_lanes ? loadLE(Ity_V128, mkexpr(addr))
7802 : sz == 8 ? unop( Iop_64UtoV128, loadLE(Ity_I64, mkexpr(addr)))
7803 : /*sz==4*/ unop( Iop_32UtoV128, loadLE(Ity_I32, mkexpr(addr)))
7804 )
7805 );
sewardj8d965312005-02-25 02:48:47 +00007806 delta += alen+1;
7807 DIP("%s $%d,%s,%s\n", opname,
7808 (Int)imm8,
7809 dis_buf,
7810 nameXMMReg(gregOfRexRM(pfx,rm)) );
7811 }
7812
7813 if (needNot && all_lanes) {
sewardj9c9ee3d2005-02-26 01:17:42 +00007814 putXMMReg( gregOfRexRM(pfx,rm),
sewardj8d965312005-02-25 02:48:47 +00007815 unop(Iop_NotV128, mkexpr(plain)) );
7816 }
7817 else
7818 if (needNot && !all_lanes) {
sewardj1027dc22005-02-26 01:55:02 +00007819 mask = toUShort(sz==4 ? 0x000F : 0x00FF);
sewardj8d965312005-02-25 02:48:47 +00007820 putXMMReg( gregOfRexRM(pfx,rm),
7821 binop(Iop_XorV128, mkexpr(plain), mkV128(mask)) );
7822 }
7823 else {
7824 putXMMReg( gregOfRexRM(pfx,rm), mkexpr(plain) );
7825 }
7826
7827 return delta;
7828}
7829
7830
sewardjadffcef2005-05-11 00:03:06 +00007831/* Vector by scalar shift of G by the amount specified at the bottom
7832 of E. */
7833
sewardj270def42005-07-03 01:03:01 +00007834static ULong dis_SSE_shiftG_byE ( Prefix pfx, Long delta,
sewardjadffcef2005-05-11 00:03:06 +00007835 HChar* opname, IROp op )
7836{
7837 HChar dis_buf[50];
7838 Int alen, size;
7839 IRTemp addr;
7840 Bool shl, shr, sar;
7841 UChar rm = getUChar(delta);
7842 IRTemp g0 = newTemp(Ity_V128);
7843 IRTemp g1 = newTemp(Ity_V128);
7844 IRTemp amt = newTemp(Ity_I32);
7845 IRTemp amt8 = newTemp(Ity_I8);
7846 if (epartIsReg(rm)) {
7847 assign( amt, getXMMRegLane32(eregOfRexRM(pfx,rm), 0) );
7848 DIP("%s %s,%s\n", opname,
7849 nameXMMReg(eregOfRexRM(pfx,rm)),
7850 nameXMMReg(gregOfRexRM(pfx,rm)) );
7851 delta++;
7852 } else {
7853 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
7854 assign( amt, loadLE(Ity_I32, mkexpr(addr)) );
7855 DIP("%s %s,%s\n", opname,
7856 dis_buf,
7857 nameXMMReg(gregOfRexRM(pfx,rm)) );
7858 delta += alen;
7859 }
7860 assign( g0, getXMMReg(gregOfRexRM(pfx,rm)) );
7861 assign( amt8, unop(Iop_32to8, mkexpr(amt)) );
7862
7863 shl = shr = sar = False;
7864 size = 0;
7865 switch (op) {
7866 case Iop_ShlN16x8: shl = True; size = 32; break;
7867 case Iop_ShlN32x4: shl = True; size = 32; break;
7868 case Iop_ShlN64x2: shl = True; size = 64; break;
7869 case Iop_SarN16x8: sar = True; size = 16; break;
7870 case Iop_SarN32x4: sar = True; size = 32; break;
7871 case Iop_ShrN16x8: shr = True; size = 16; break;
7872 case Iop_ShrN32x4: shr = True; size = 32; break;
7873 case Iop_ShrN64x2: shr = True; size = 64; break;
7874 default: vassert(0);
7875 }
7876
7877 if (shl || shr) {
7878 assign(
7879 g1,
7880 IRExpr_Mux0X(
7881 unop(Iop_1Uto8,
7882 binop(Iop_CmpLT64U, unop(Iop_32Uto64,mkexpr(amt)), mkU64(size))),
7883 mkV128(0x0000),
7884 binop(op, mkexpr(g0), mkexpr(amt8))
7885 )
7886 );
7887 } else
7888 if (sar) {
7889 assign(
7890 g1,
7891 IRExpr_Mux0X(
7892 unop(Iop_1Uto8,
7893 binop(Iop_CmpLT64U, unop(Iop_32Uto64,mkexpr(amt)), mkU64(size))),
7894 binop(op, mkexpr(g0), mkU8(size-1)),
7895 binop(op, mkexpr(g0), mkexpr(amt8))
7896 )
7897 );
7898 } else {
7899 vassert(0);
7900 }
7901
7902 putXMMReg( gregOfRexRM(pfx,rm), mkexpr(g1) );
7903 return delta;
7904}
sewardj09717342005-05-05 21:34:02 +00007905
7906
7907/* Vector by scalar shift of E by an immediate byte. */
7908
7909static
7910ULong dis_SSE_shiftE_imm ( Prefix pfx,
sewardj270def42005-07-03 01:03:01 +00007911 Long delta, HChar* opname, IROp op )
sewardj09717342005-05-05 21:34:02 +00007912{
7913 Bool shl, shr, sar;
7914 UChar rm = getUChar(delta);
7915 IRTemp e0 = newTemp(Ity_V128);
7916 IRTemp e1 = newTemp(Ity_V128);
7917 UChar amt, size;
7918 vassert(epartIsReg(rm));
7919 vassert(gregLO3ofRM(rm) == 2
7920 || gregLO3ofRM(rm) == 4 || gregLO3ofRM(rm) == 6);
sewardjca673ab2005-05-11 10:03:08 +00007921 amt = getUChar(delta+1);
sewardj09717342005-05-05 21:34:02 +00007922 delta += 2;
7923 DIP("%s $%d,%s\n", opname,
7924 (Int)amt,
7925 nameXMMReg(eregOfRexRM(pfx,rm)) );
7926 assign( e0, getXMMReg(eregOfRexRM(pfx,rm)) );
7927
7928 shl = shr = sar = False;
7929 size = 0;
7930 switch (op) {
7931 case Iop_ShlN16x8: shl = True; size = 16; break;
7932 case Iop_ShlN32x4: shl = True; size = 32; break;
7933 case Iop_ShlN64x2: shl = True; size = 64; break;
7934 case Iop_SarN16x8: sar = True; size = 16; break;
7935 case Iop_SarN32x4: sar = True; size = 32; break;
7936 case Iop_ShrN16x8: shr = True; size = 16; break;
7937 case Iop_ShrN32x4: shr = True; size = 32; break;
7938 case Iop_ShrN64x2: shr = True; size = 64; break;
7939 default: vassert(0);
7940 }
7941
7942 if (shl || shr) {
7943 assign( e1, amt >= size
7944 ? mkV128(0x0000)
7945 : binop(op, mkexpr(e0), mkU8(amt))
7946 );
7947 } else
7948 if (sar) {
7949 assign( e1, amt >= size
7950 ? binop(op, mkexpr(e0), mkU8(size-1))
7951 : binop(op, mkexpr(e0), mkU8(amt))
7952 );
7953 } else {
7954 vassert(0);
7955 }
7956
7957 putXMMReg( eregOfRexRM(pfx,rm), mkexpr(e1) );
7958 return delta;
7959}
sewardj1a01e652005-02-23 11:39:21 +00007960
7961
7962/* Get the current SSE rounding mode. */
7963
7964static IRExpr* /* :: Ity_I32 */ get_sse_roundingmode ( void )
7965{
7966 return
7967 unop( Iop_64to32,
7968 binop( Iop_And64,
7969 IRExpr_Get( OFFB_SSEROUND, Ity_I64 ),
7970 mkU64(3) ));
7971}
7972
sewardjbcbb9de2005-03-27 02:22:32 +00007973static void put_sse_roundingmode ( IRExpr* sseround )
7974{
7975 vassert(typeOfIRExpr(irbb->tyenv, sseround) == Ity_I32);
7976 stmt( IRStmt_Put( OFFB_SSEROUND,
7977 unop(Iop_32Uto64,sseround) ) );
7978}
7979
sewardja7ba8c42005-05-10 20:08:34 +00007980/* Break a 128-bit value up into four 32-bit ints. */
7981
7982static void breakup128to32s ( IRTemp t128,
7983 /*OUTs*/
7984 IRTemp* t3, IRTemp* t2,
7985 IRTemp* t1, IRTemp* t0 )
7986{
7987 IRTemp hi64 = newTemp(Ity_I64);
7988 IRTemp lo64 = newTemp(Ity_I64);
7989 assign( hi64, unop(Iop_V128HIto64, mkexpr(t128)) );
7990 assign( lo64, unop(Iop_V128to64, mkexpr(t128)) );
7991
7992 vassert(t0 && *t0 == IRTemp_INVALID);
7993 vassert(t1 && *t1 == IRTemp_INVALID);
7994 vassert(t2 && *t2 == IRTemp_INVALID);
7995 vassert(t3 && *t3 == IRTemp_INVALID);
7996
7997 *t0 = newTemp(Ity_I32);
7998 *t1 = newTemp(Ity_I32);
7999 *t2 = newTemp(Ity_I32);
8000 *t3 = newTemp(Ity_I32);
8001 assign( *t0, unop(Iop_64to32, mkexpr(lo64)) );
8002 assign( *t1, unop(Iop_64HIto32, mkexpr(lo64)) );
8003 assign( *t2, unop(Iop_64to32, mkexpr(hi64)) );
8004 assign( *t3, unop(Iop_64HIto32, mkexpr(hi64)) );
8005}
8006
8007/* Construct a 128-bit value from four 32-bit ints. */
8008
8009static IRExpr* mk128from32s ( IRTemp t3, IRTemp t2,
8010 IRTemp t1, IRTemp t0 )
8011{
8012 return
8013 binop( Iop_64HLtoV128,
8014 binop(Iop_32HLto64, mkexpr(t3), mkexpr(t2)),
8015 binop(Iop_32HLto64, mkexpr(t1), mkexpr(t0))
8016 );
8017}
8018
8019/* Break a 64-bit value up into four 16-bit ints. */
8020
8021static void breakup64to16s ( IRTemp t64,
8022 /*OUTs*/
8023 IRTemp* t3, IRTemp* t2,
8024 IRTemp* t1, IRTemp* t0 )
8025{
8026 IRTemp hi32 = newTemp(Ity_I32);
8027 IRTemp lo32 = newTemp(Ity_I32);
8028 assign( hi32, unop(Iop_64HIto32, mkexpr(t64)) );
8029 assign( lo32, unop(Iop_64to32, mkexpr(t64)) );
8030
8031 vassert(t0 && *t0 == IRTemp_INVALID);
8032 vassert(t1 && *t1 == IRTemp_INVALID);
8033 vassert(t2 && *t2 == IRTemp_INVALID);
8034 vassert(t3 && *t3 == IRTemp_INVALID);
8035
8036 *t0 = newTemp(Ity_I16);
8037 *t1 = newTemp(Ity_I16);
8038 *t2 = newTemp(Ity_I16);
8039 *t3 = newTemp(Ity_I16);
8040 assign( *t0, unop(Iop_32to16, mkexpr(lo32)) );
8041 assign( *t1, unop(Iop_32HIto16, mkexpr(lo32)) );
8042 assign( *t2, unop(Iop_32to16, mkexpr(hi32)) );
8043 assign( *t3, unop(Iop_32HIto16, mkexpr(hi32)) );
8044}
8045
8046/* Construct a 64-bit value from four 16-bit ints. */
8047
8048static IRExpr* mk64from16s ( IRTemp t3, IRTemp t2,
8049 IRTemp t1, IRTemp t0 )
8050{
8051 return
8052 binop( Iop_32HLto64,
8053 binop(Iop_16HLto32, mkexpr(t3), mkexpr(t2)),
8054 binop(Iop_16HLto32, mkexpr(t1), mkexpr(t0))
8055 );
8056}
sewardjdf0e0022005-01-25 15:48:43 +00008057
8058
8059/*------------------------------------------------------------*/
8060/*--- Disassemble a single instruction ---*/
8061/*------------------------------------------------------------*/
8062
sewardj9e6491a2005-07-02 19:24:10 +00008063/* Disassemble a single instruction into IR. The instruction is
8064 located in host memory at &guest_code[delta]. */
sewardjdf0e0022005-01-25 15:48:43 +00008065
sewardj9e6491a2005-07-02 19:24:10 +00008066static
8067DisResult disInstr_AMD64_WRK (
8068 Bool put_IP,
sewardjc716aea2006-01-17 01:48:46 +00008069 Bool (*resteerOkFn) ( /*opaque*/void*, Addr64 ),
8070 void* callback_opaque,
sewardj9e6491a2005-07-02 19:24:10 +00008071 Long delta64,
8072 VexArchInfo* archinfo
8073 )
sewardjdf0e0022005-01-25 15:48:43 +00008074{
8075 IRType ty;
sewardja7ba8c42005-05-10 20:08:34 +00008076 IRTemp addr, t0, t1, t2, t3, t4, t5, t6;
sewardjdf0e0022005-01-25 15:48:43 +00008077 Int alen;
sewardj7a240552005-01-28 21:37:12 +00008078 UChar opc, modrm, /*abyte,*/ pre;
sewardj1027dc22005-02-26 01:55:02 +00008079 Long d64;
sewardjdf0e0022005-01-25 15:48:43 +00008080 HChar dis_buf[50];
8081 Int am_sz, d_sz, n, n_prefixes;
sewardj9e6491a2005-07-02 19:24:10 +00008082 DisResult dres;
sewardja6b93d12005-02-17 09:28:28 +00008083 UChar* insn; /* used in SSE decoders */
sewardjdf0e0022005-01-25 15:48:43 +00008084
sewardj9e6491a2005-07-02 19:24:10 +00008085 /* The running delta */
8086 Long delta = delta64;
8087
sewardjdf0e0022005-01-25 15:48:43 +00008088 /* Holds eip at the start of the insn, so that we can print
8089 consistent error messages for unimplemented insns. */
sewardj270def42005-07-03 01:03:01 +00008090 Long delta_start = delta;
sewardjdf0e0022005-01-25 15:48:43 +00008091
8092 /* sz denotes the nominal data-op size of the insn; we change it to
8093 2 if an 0x66 prefix is seen and 8 if REX.W is 1. In case of
8094 conflict REX.W takes precedence. */
8095 Int sz = 4;
8096
sewardj3ca55a12005-01-27 16:06:23 +00008097 /* pfx holds the summary of prefixes. */
8098 Prefix pfx = PFX_EMPTY;
sewardjdf0e0022005-01-25 15:48:43 +00008099
sewardj9e6491a2005-07-02 19:24:10 +00008100 /* Set result defaults. */
8101 dres.whatNext = Dis_Continue;
8102 dres.len = 0;
8103 dres.continueAt = 0;
sewardjdf0e0022005-01-25 15:48:43 +00008104
sewardj9e6491a2005-07-02 19:24:10 +00008105 vassert(guest_RIP_next_assumed == 0);
8106 vassert(guest_RIP_next_mustcheck == False);
sewardj4b744762005-02-07 15:02:25 +00008107
sewardja7ba8c42005-05-10 20:08:34 +00008108 addr = t0 = t1 = t2 = t3 = t4 = t5 = t6 = IRTemp_INVALID;
sewardjdf0e0022005-01-25 15:48:43 +00008109
sewardj9e6491a2005-07-02 19:24:10 +00008110 DIP("\t0x%llx: ", guest_RIP_bbstart+delta);
8111
8112 /* We may be asked to update the guest RIP before going further. */
8113 if (put_IP)
8114 stmt( IRStmt_Put( OFFB_RIP, mkU64(guest_RIP_curr_instr)) );
sewardjdf0e0022005-01-25 15:48:43 +00008115
sewardjce02aa72006-01-12 12:27:58 +00008116 /* Spot "Special" instructions (see comment at top of file). */
sewardjdf0e0022005-01-25 15:48:43 +00008117 {
8118 UChar* code = (UChar*)(guest_code + delta);
sewardjce02aa72006-01-12 12:27:58 +00008119 /* Spot the 16-byte preamble:
8120 48C1C703 rolq $3, %rdi
8121 48C1C70D rolq $13, %rdi
8122 48C1C73D rolq $61, %rdi
8123 48C1C733 rolq $51, %rdi
sewardjdf0e0022005-01-25 15:48:43 +00008124 */
sewardjce02aa72006-01-12 12:27:58 +00008125 if (code[ 0] == 0x48 && code[ 1] == 0xC1 && code[ 2] == 0xC7
8126 && code[ 3] == 0x03 &&
8127 code[ 4] == 0x48 && code[ 5] == 0xC1 && code[ 6] == 0xC7
8128 && code[ 7] == 0x0D &&
8129 code[ 8] == 0x48 && code[ 9] == 0xC1 && code[10] == 0xC7
8130 && code[11] == 0x3D &&
8131 code[12] == 0x48 && code[13] == 0xC1 && code[14] == 0xC7
8132 && code[15] == 0x33) {
8133 /* Got a "Special" instruction preamble. Which one is it? */
8134 if (code[16] == 0x48 && code[17] == 0x87
8135 && code[18] == 0xDB /* xchgq %rbx,%rbx */) {
8136 /* %RDX = client_request ( %RAX ) */
8137 DIP("%%rdx = client_request ( %%rax )\n");
8138 delta += 19;
8139 jmp_lit(Ijk_ClientReq, guest_RIP_bbstart+delta);
8140 dres.whatNext = Dis_StopHere;
8141 goto decode_success;
8142 }
8143 else
8144 if (code[16] == 0x48 && code[17] == 0x87
8145 && code[18] == 0xC9 /* xchgq %rcx,%rcx */) {
8146 /* %RAX = guest_NRADDR */
8147 DIP("%%rax = guest_NRADDR\n");
8148 delta += 19;
8149 putIRegRAX(8, IRExpr_Get( OFFB_NRADDR, Ity_I64 ));
8150 goto decode_success;
8151 }
8152 else
8153 if (code[16] == 0x48 && code[17] == 0x87
8154 && code[18] == 0xD2 /* xchgq %rdx,%rdx */) {
8155 /* call-noredir *%RAX */
8156 DIP("call-noredir *%%rax\n");
8157 delta += 19;
8158 t1 = newTemp(Ity_I64);
8159 assign(t1, getIRegRAX(8));
8160 t2 = newTemp(Ity_I64);
8161 assign(t2, binop(Iop_Sub64, getIReg64(R_RSP), mkU64(8)));
8162 putIReg64(R_RSP, mkexpr(t2));
8163 storeLE( mkexpr(t2), mkU64(guest_RIP_bbstart+delta));
8164 jmp_treg(Ijk_NoRedir,t1);
8165 dres.whatNext = Dis_StopHere;
8166 goto decode_success;
8167 }
8168 /* We don't know what it is. */
8169 goto decode_failure;
8170 /*NOTREACHED*/
sewardjdf0e0022005-01-25 15:48:43 +00008171 }
8172 }
8173
8174 /* Eat prefixes, summarising the result in pfx and sz, and rejecting
8175 as many invalid combinations as possible. */
8176 n_prefixes = 0;
8177 while (True) {
8178 if (n_prefixes > 5) goto decode_failure;
sewardj8c332e22005-01-28 01:36:56 +00008179 pre = getUChar(delta);
sewardjdf0e0022005-01-25 15:48:43 +00008180 switch (pre) {
8181 case 0x66: pfx |= PFX_66; break;
8182 case 0x67: pfx |= PFX_ASO; break;
8183 case 0xF2: pfx |= PFX_F2; break;
8184 case 0xF3: pfx |= PFX_F3; break;
8185 case 0xF0: pfx |= PFX_LOCK; break;
8186 case 0x2E: pfx |= PFX_CS; break;
8187 case 0x3E: pfx |= PFX_DS; break;
8188 case 0x26: pfx |= PFX_ES; break;
8189 case 0x64: pfx |= PFX_FS; break;
8190 case 0x65: pfx |= PFX_GS; break;
8191 case 0x36: pfx |= PFX_SS; break;
8192 case 0x40 ... 0x4F:
8193 pfx |= PFX_REX;
8194 if (pre & (1<<3)) pfx |= PFX_REXW;
8195 if (pre & (1<<2)) pfx |= PFX_REXR;
8196 if (pre & (1<<1)) pfx |= PFX_REXX;
8197 if (pre & (1<<0)) pfx |= PFX_REXB;
8198 break;
8199 default:
8200 goto not_a_prefix;
8201 }
8202 n_prefixes++;
8203 delta++;
8204 }
8205
8206 not_a_prefix:
sewardjdf0e0022005-01-25 15:48:43 +00008207
sewardj42561ef2005-11-04 14:18:31 +00008208 /* Dump invalid combinations */
sewardjdf0e0022005-01-25 15:48:43 +00008209 n = 0;
8210 if (pfx & PFX_F2) n++;
8211 if (pfx & PFX_F3) n++;
sewardj3ca55a12005-01-27 16:06:23 +00008212 if (n > 1)
8213 goto decode_failure; /* can't have both */
sewardjdf0e0022005-01-25 15:48:43 +00008214
8215 n = 0;
8216 if (pfx & PFX_CS) n++;
8217 if (pfx & PFX_DS) n++;
8218 if (pfx & PFX_ES) n++;
8219 if (pfx & PFX_FS) n++;
8220 if (pfx & PFX_GS) n++;
8221 if (pfx & PFX_SS) n++;
sewardj3ca55a12005-01-27 16:06:23 +00008222 if (n > 1)
8223 goto decode_failure; /* multiple seg overrides == illegal */
sewardjdf0e0022005-01-25 15:48:43 +00008224
sewardj42561ef2005-11-04 14:18:31 +00008225 if (pfx & PFX_GS)
8226 goto decode_failure; /* legal, but unsupported right now */
8227
sewardjdf0e0022005-01-25 15:48:43 +00008228 /* Set up sz. */
8229 sz = 4;
8230 if (pfx & PFX_66) sz = 2;
8231 if ((pfx & PFX_REX) && (pfx & PFX_REXW)) sz = 8;
8232
sewardj9ff93bc2005-03-23 11:25:12 +00008233 /* Kludge re LOCK prefixes. We assume here that all code generated
8234 by Vex is going to be run in a single-threaded context, in other
8235 words that concurrent executions of Vex-generated translations
8236 will not happen. That is certainly the case for how the
8237 Valgrind-3.0 code line uses Vex. Given that assumption, it
8238 seems safe to ignore LOCK prefixes since there will never be any
8239 other thread running at the same time as this one. However, at
8240 least emit a memory fence on the basis that it would at least be
8241 prudent to flush any memory transactions from this thread as far
8242 as possible down the memory hierarchy. */
8243 if (pfx & PFX_LOCK) {
8244 /* vex_printf("vex amd64->IR: ignoring LOCK prefix on: ");
8245 insn_verbose = True; */
8246 stmt( IRStmt_MFence() );
sewardjdf0e0022005-01-25 15:48:43 +00008247 }
8248
sewardja6b93d12005-02-17 09:28:28 +00008249
8250 /* ---------------------------------------------------- */
sewardj09717342005-05-05 21:34:02 +00008251 /* --- The SSE/SSE2 decoder. --- */
sewardja6b93d12005-02-17 09:28:28 +00008252 /* ---------------------------------------------------- */
8253
8254 /* What did I do to deserve SSE ? Perhaps I was really bad in a
8255 previous life? */
8256
sewardj09717342005-05-05 21:34:02 +00008257 /* Note, this doesn't handle SSE3 right now. All amd64s support
8258 SSE2 as a minimum so there is no point distinguishing SSE1 vs
8259 SSE2. */
8260
sewardja6b93d12005-02-17 09:28:28 +00008261 insn = (UChar*)&guest_code[delta];
8262
sewardjd20c8852005-01-20 20:04:07 +00008263//.. /* Treat fxsave specially. It should be doable even on an SSE0
8264//.. (Pentium-II class) CPU. Hence be prepared to handle it on
8265//.. any subarchitecture variant.
8266//.. */
8267//..
8268//.. /* 0F AE /0 = FXSAVE m512 -- write x87 and SSE state to memory */
8269//.. if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xAE
8270//.. && !epartIsReg(insn[2]) && gregOfRM(insn[2]) == 0) {
sewardj8c332e22005-01-28 01:36:56 +00008271//.. modrm = getUChar(delta+2);
sewardjd20c8852005-01-20 20:04:07 +00008272//.. vassert(sz == 4);
8273//.. vassert(!epartIsReg(modrm));
8274//..
8275//.. addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8276//.. delta += 2+alen;
8277//..
8278//.. DIP("fxsave %s\n", dis_buf);
8279//..
8280//.. /* Uses dirty helper:
8281//.. void x86g_do_FXSAVE ( VexGuestX86State*, UInt ) */
8282//.. IRDirty* d = unsafeIRDirty_0_N (
8283//.. 0/*regparms*/,
8284//.. "x86g_dirtyhelper_FXSAVE",
8285//.. &x86g_dirtyhelper_FXSAVE,
8286//.. mkIRExprVec_1( mkexpr(addr) )
8287//.. );
8288//.. d->needsBBP = True;
8289//..
8290//.. /* declare we're writing memory */
8291//.. d->mFx = Ifx_Write;
8292//.. d->mAddr = mkexpr(addr);
8293//.. d->mSize = 512;
8294//..
8295//.. /* declare we're reading guest state */
8296//.. d->nFxState = 7;
8297//..
8298//.. d->fxState[0].fx = Ifx_Read;
8299//.. d->fxState[0].offset = OFFB_FTOP;
8300//.. d->fxState[0].size = sizeof(UInt);
8301//..
8302//.. d->fxState[1].fx = Ifx_Read;
8303//.. d->fxState[1].offset = OFFB_FPREGS;
8304//.. d->fxState[1].size = 8 * sizeof(ULong);
8305//..
8306//.. d->fxState[2].fx = Ifx_Read;
8307//.. d->fxState[2].offset = OFFB_FPTAGS;
8308//.. d->fxState[2].size = 8 * sizeof(UChar);
8309//..
8310//.. d->fxState[3].fx = Ifx_Read;
8311//.. d->fxState[3].offset = OFFB_FPROUND;
8312//.. d->fxState[3].size = sizeof(UInt);
8313//..
8314//.. d->fxState[4].fx = Ifx_Read;
8315//.. d->fxState[4].offset = OFFB_FC3210;
8316//.. d->fxState[4].size = sizeof(UInt);
8317//..
8318//.. d->fxState[5].fx = Ifx_Read;
8319//.. d->fxState[5].offset = OFFB_XMM0;
8320//.. d->fxState[5].size = 8 * sizeof(U128);
8321//..
8322//.. d->fxState[6].fx = Ifx_Read;
8323//.. d->fxState[6].offset = OFFB_SSEROUND;
8324//.. d->fxState[6].size = sizeof(UInt);
8325//..
8326//.. /* Be paranoid ... this assertion tries to ensure the 8 %xmm
8327//.. images are packed back-to-back. If not, the value of
8328//.. d->fxState[5].size is wrong. */
8329//.. vassert(16 == sizeof(U128));
8330//.. vassert(OFFB_XMM7 == (OFFB_XMM0 + 7 * 16));
8331//..
8332//.. stmt( IRStmt_Dirty(d) );
8333//..
8334//.. goto decode_success;
8335//.. }
8336//..
8337//.. /* ------ SSE decoder main ------ */
8338//..
8339//.. /* Skip parts of the decoder which don't apply given the stated
8340//.. guest subarchitecture. */
8341//.. if (subarch == VexSubArchX86_sse0)
8342//.. goto after_sse_decoders;
8343//..
8344//.. /* Otherwise we must be doing sse1 or sse2, so we can at least try
8345//.. for SSE1 here. */
sewardj432f8b62005-05-10 02:50:05 +00008346
8347 /* 0F 58 = ADDPS -- add 32Fx4 from R/M to R */
8348 if (haveNo66noF2noF3(pfx) && sz == 4
8349 && insn[0] == 0x0F && insn[1] == 0x58) {
8350 delta = dis_SSE_E_to_G_all( pfx, delta+2, "addps", Iop_Add32Fx4 );
8351 goto decode_success;
8352 }
sewardj8d965312005-02-25 02:48:47 +00008353
8354 /* F3 0F 58 = ADDSS -- add 32F0x4 from R/M to R */
8355 if (haveF3no66noF2(pfx) && sz == 4
8356 && insn[0] == 0x0F && insn[1] == 0x58) {
8357 delta = dis_SSE_E_to_G_lo32( pfx, delta+2, "addss", Iop_Add32F0x4 );
8358 goto decode_success;
8359 }
8360
sewardj3aba9eb2005-03-30 23:20:47 +00008361 /* 0F 55 = ANDNPS -- G = (not G) and E */
8362 if (haveNo66noF2noF3(pfx) && sz == 4
8363 && insn[0] == 0x0F && insn[1] == 0x55) {
8364 delta = dis_SSE_E_to_G_all_invG( pfx, delta+2, "andnps", Iop_AndV128 );
8365 goto decode_success;
8366 }
sewardj37d52572005-02-25 14:22:12 +00008367
8368 /* 0F 54 = ANDPS -- G = G and E */
8369 if (haveNo66noF2noF3(pfx) && sz == 4
8370 && insn[0] == 0x0F && insn[1] == 0x54) {
8371 delta = dis_SSE_E_to_G_all( pfx, delta+2, "andps", Iop_AndV128 );
8372 goto decode_success;
8373 }
8374
sewardj432f8b62005-05-10 02:50:05 +00008375 /* 0F C2 = CMPPS -- 32Fx4 comparison from R/M to R */
8376 if (haveNo66noF2noF3(pfx) && sz == 4
8377 && insn[0] == 0x0F && insn[1] == 0xC2) {
8378 delta = dis_SSEcmp_E_to_G( pfx, delta+2, "cmpps", True, 4 );
8379 goto decode_success;
8380 }
sewardj3aba9eb2005-03-30 23:20:47 +00008381
8382 /* F3 0F C2 = CMPSS -- 32F0x4 comparison from R/M to R */
8383 if (haveF3no66noF2(pfx) && sz == 4
8384 && insn[0] == 0x0F && insn[1] == 0xC2) {
8385 delta = dis_SSEcmp_E_to_G( pfx, delta+2, "cmpss", False, 4 );
8386 goto decode_success;
8387 }
sewardjc49ce232005-02-25 13:03:03 +00008388
8389 /* 0F 2F = COMISS -- 32F0x4 comparison G,E, and set ZCP */
8390 /* 0F 2E = UCOMISS -- 32F0x4 comparison G,E, and set ZCP */
8391 if (haveNo66noF2noF3(pfx) && sz == 4
8392 && insn[0] == 0x0F && (insn[1] == 0x2F || insn[1] == 0x2E)) {
8393 IRTemp argL = newTemp(Ity_F32);
8394 IRTemp argR = newTemp(Ity_F32);
8395 modrm = getUChar(delta+2);
8396 if (epartIsReg(modrm)) {
8397 assign( argR, getXMMRegLane32F( eregOfRexRM(pfx,modrm),
8398 0/*lowest lane*/ ) );
8399 delta += 2+1;
8400 DIP("%scomiss %s,%s\n", insn[1]==0x2E ? "u" : "",
8401 nameXMMReg(eregOfRexRM(pfx,modrm)),
8402 nameXMMReg(gregOfRexRM(pfx,modrm)) );
8403 } else {
8404 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8405 assign( argR, loadLE(Ity_F32, mkexpr(addr)) );
8406 delta += 2+alen;
8407 DIP("%scomiss %s,%s\n", insn[1]==0x2E ? "u" : "",
8408 dis_buf,
8409 nameXMMReg(gregOfRexRM(pfx,modrm)) );
8410 }
8411 assign( argL, getXMMRegLane32F( gregOfRexRM(pfx,modrm),
8412 0/*lowest lane*/ ) );
8413
8414 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(AMD64G_CC_OP_COPY) ));
8415 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
8416 stmt( IRStmt_Put(
8417 OFFB_CC_DEP1,
8418 binop( Iop_And64,
8419 unop( Iop_32Uto64,
8420 binop(Iop_CmpF64,
8421 unop(Iop_F32toF64,mkexpr(argL)),
8422 unop(Iop_F32toF64,mkexpr(argR)))),
8423 mkU64(0x45)
8424 )));
8425
8426 goto decode_success;
8427 }
8428
sewardj432f8b62005-05-10 02:50:05 +00008429 /* 0F 2A = CVTPI2PS -- convert 2 x I32 in mem/mmx to 2 x F32 in low
8430 half xmm */
8431 if (haveNo66noF2noF3(pfx) && sz == 4
8432 && insn[0] == 0x0F && insn[1] == 0x2A) {
8433 IRTemp arg64 = newTemp(Ity_I64);
8434 IRTemp rmode = newTemp(Ity_I32);
8435
8436 modrm = getUChar(delta+2);
8437 do_MMX_preamble();
8438 if (epartIsReg(modrm)) {
8439 assign( arg64, getMMXReg(eregLO3ofRM(modrm)) );
8440 delta += 2+1;
8441 DIP("cvtpi2ps %s,%s\n", nameMMXReg(eregLO3ofRM(modrm)),
8442 nameXMMReg(gregOfRexRM(pfx,modrm)));
8443 } else {
8444 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8445 assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
8446 delta += 2+alen;
8447 DIP("cvtpi2ps %s,%s\n", dis_buf,
8448 nameXMMReg(gregOfRexRM(pfx,modrm)) );
8449 }
8450
8451 assign( rmode, get_sse_roundingmode() );
8452
8453 putXMMRegLane32F(
8454 gregOfRexRM(pfx,modrm), 0,
8455 binop(Iop_F64toF32,
8456 mkexpr(rmode),
8457 unop(Iop_I32toF64,
8458 unop(Iop_64to32, mkexpr(arg64)) )) );
8459
8460 putXMMRegLane32F(
8461 gregOfRexRM(pfx,modrm), 1,
8462 binop(Iop_F64toF32,
8463 mkexpr(rmode),
8464 unop(Iop_I32toF64,
8465 unop(Iop_64HIto32, mkexpr(arg64)) )) );
8466
8467 goto decode_success;
8468 }
sewardj8d965312005-02-25 02:48:47 +00008469
8470 /* F3 0F 2A = CVTSI2SS
8471 -- sz==4: convert I32 in mem/ireg to F32 in low quarter xmm
8472 -- sz==8: convert I64 in mem/ireg to F32 in low quarter xmm */
8473 if (haveF3no66noF2(pfx) && (sz == 4 || sz == 8)
8474 && insn[0] == 0x0F && insn[1] == 0x2A) {
8475
8476 IRTemp rmode = newTemp(Ity_I32);
8477 assign( rmode, get_sse_roundingmode() );
8478 modrm = getUChar(delta+2);
8479
8480 if (sz == 4) {
8481 IRTemp arg32 = newTemp(Ity_I32);
8482 if (epartIsReg(modrm)) {
sewardj5b470602005-02-27 13:10:48 +00008483 assign( arg32, getIReg32(eregOfRexRM(pfx,modrm)) );
sewardj8d965312005-02-25 02:48:47 +00008484 delta += 2+1;
sewardj5b470602005-02-27 13:10:48 +00008485 DIP("cvtsi2ss %s,%s\n", nameIReg32(eregOfRexRM(pfx,modrm)),
sewardj8d965312005-02-25 02:48:47 +00008486 nameXMMReg(gregOfRexRM(pfx,modrm)));
8487 } else {
sewardj8d965312005-02-25 02:48:47 +00008488 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8489 assign( arg32, loadLE(Ity_I32, mkexpr(addr)) );
8490 delta += 2+alen;
8491 DIP("cvtsi2ss %s,%s\n", dis_buf,
8492 nameXMMReg(gregOfRexRM(pfx,modrm)) );
8493 }
8494 putXMMRegLane32F(
8495 gregOfRexRM(pfx,modrm), 0,
8496 binop(Iop_F64toF32,
8497 mkexpr(rmode),
8498 unop(Iop_I32toF64, mkexpr(arg32)) ) );
8499 } else {
8500 /* sz == 8 */
8501 IRTemp arg64 = newTemp(Ity_I64);
8502 if (epartIsReg(modrm)) {
sewardj5b470602005-02-27 13:10:48 +00008503 assign( arg64, getIReg64(eregOfRexRM(pfx,modrm)) );
sewardj8d965312005-02-25 02:48:47 +00008504 delta += 2+1;
sewardj5b470602005-02-27 13:10:48 +00008505 DIP("cvtsi2ssq %s,%s\n", nameIReg64(eregOfRexRM(pfx,modrm)),
sewardj8d965312005-02-25 02:48:47 +00008506 nameXMMReg(gregOfRexRM(pfx,modrm)));
8507 } else {
sewardj82c9f2f2005-03-02 16:05:13 +00008508 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8509 assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
8510 delta += 2+alen;
8511 DIP("cvtsi2ssq %s,%s\n", dis_buf,
8512 nameXMMReg(gregOfRexRM(pfx,modrm)) );
sewardj8d965312005-02-25 02:48:47 +00008513 }
8514 putXMMRegLane32F(
8515 gregOfRexRM(pfx,modrm), 0,
8516 binop(Iop_F64toF32,
8517 mkexpr(rmode),
8518 binop(Iop_I64toF64, mkexpr(rmode), mkexpr(arg64)) ) );
8519 }
8520
8521 goto decode_success;
8522 }
8523
sewardj432f8b62005-05-10 02:50:05 +00008524 /* 0F 2D = CVTPS2PI -- convert 2 x F32 in mem/low half xmm to 2 x
8525 I32 in mmx, according to prevailing SSE rounding mode */
sewardja7ba8c42005-05-10 20:08:34 +00008526 /* 0F 2C = CVTTPS2PI -- convert 2 x F32 in mem/low half xmm to 2 x
8527 I32 in mmx, rounding towards zero */
sewardj432f8b62005-05-10 02:50:05 +00008528 if (haveNo66noF2noF3(pfx) && sz == 4
sewardja7ba8c42005-05-10 20:08:34 +00008529 && insn[0] == 0x0F && (insn[1] == 0x2D || insn[1] == 0x2C)) {
sewardj432f8b62005-05-10 02:50:05 +00008530 IRTemp dst64 = newTemp(Ity_I64);
8531 IRTemp rmode = newTemp(Ity_I32);
8532 IRTemp f32lo = newTemp(Ity_F32);
8533 IRTemp f32hi = newTemp(Ity_F32);
8534 Bool r2zero = toBool(insn[1] == 0x2C);
8535
8536 do_MMX_preamble();
8537 modrm = getUChar(delta+2);
8538
8539 if (epartIsReg(modrm)) {
8540 delta += 2+1;
8541 assign(f32lo, getXMMRegLane32F(eregOfRexRM(pfx,modrm), 0));
8542 assign(f32hi, getXMMRegLane32F(eregOfRexRM(pfx,modrm), 1));
8543 DIP("cvt%sps2pi %s,%s\n", r2zero ? "t" : "",
8544 nameXMMReg(eregOfRexRM(pfx,modrm)),
8545 nameMMXReg(gregLO3ofRM(modrm)));
8546 } else {
8547 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8548 assign(f32lo, loadLE(Ity_F32, mkexpr(addr)));
8549 assign(f32hi, loadLE(Ity_F32, binop( Iop_Add64,
8550 mkexpr(addr),
8551 mkU64(4) )));
8552 delta += 2+alen;
8553 DIP("cvt%sps2pi %s,%s\n", r2zero ? "t" : "",
8554 dis_buf,
8555 nameMMXReg(gregLO3ofRM(modrm)));
8556 }
8557
8558 if (r2zero) {
8559 assign(rmode, mkU32((UInt)Irrm_ZERO) );
8560 } else {
8561 assign( rmode, get_sse_roundingmode() );
8562 }
8563
8564 assign(
8565 dst64,
8566 binop( Iop_32HLto64,
8567 binop( Iop_F64toI32,
8568 mkexpr(rmode),
8569 unop( Iop_F32toF64, mkexpr(f32hi) ) ),
8570 binop( Iop_F64toI32,
8571 mkexpr(rmode),
8572 unop( Iop_F32toF64, mkexpr(f32lo) ) )
8573 )
8574 );
8575
8576 putMMXReg(gregLO3ofRM(modrm), mkexpr(dst64));
8577 goto decode_success;
8578 }
8579
8580 /* F3 0F 2D = CVTSS2SI
8581 when sz==4 -- convert F32 in mem/low quarter xmm to I32 in ireg,
8582 according to prevailing SSE rounding mode
8583 when sz==8 -- convert F32 in mem/low quarter xmm to I64 in ireg,
8584 according to prevailing SSE rounding mode
8585 */
sewardj82c9f2f2005-03-02 16:05:13 +00008586 /* F3 0F 2C = CVTTSS2SI
8587 when sz==4 -- convert F32 in mem/low quarter xmm to I32 in ireg,
8588 truncating towards zero
8589 when sz==8 -- convert F32 in mem/low quarter xmm to I64 in ireg,
8590 truncating towards zero
8591 */
8592 if (haveF3no66noF2(pfx)
8593 && insn[0] == 0x0F
sewardj432f8b62005-05-10 02:50:05 +00008594 && (insn[1] == 0x2D || insn[1] == 0x2C)) {
sewardj82c9f2f2005-03-02 16:05:13 +00008595 IRTemp rmode = newTemp(Ity_I32);
8596 IRTemp f32lo = newTemp(Ity_F32);
8597 Bool r2zero = toBool(insn[1] == 0x2C);
8598 vassert(sz == 4 || sz == 8);
8599
8600 modrm = getUChar(delta+2);
8601 if (epartIsReg(modrm)) {
8602 delta += 2+1;
8603 assign(f32lo, getXMMRegLane32F(eregOfRexRM(pfx,modrm), 0));
8604 DIP("cvt%sss2si %s,%s\n", r2zero ? "t" : "",
8605 nameXMMReg(eregOfRexRM(pfx,modrm)),
8606 nameIReg(sz, gregOfRexRM(pfx,modrm), False));
8607 } else {
8608 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8609 assign(f32lo, loadLE(Ity_F32, mkexpr(addr)));
8610 delta += 2+alen;
8611 DIP("cvt%sss2si %s,%s\n", r2zero ? "t" : "",
8612 dis_buf,
8613 nameIReg(sz, gregOfRexRM(pfx,modrm), False));
8614 }
8615
8616 if (r2zero) {
8617 assign( rmode, mkU32((UInt)Irrm_ZERO) );
8618 } else {
8619 assign( rmode, get_sse_roundingmode() );
8620 }
8621
8622 if (sz == 4) {
8623 putIReg32( gregOfRexRM(pfx,modrm),
8624 binop( Iop_F64toI32,
8625 mkexpr(rmode),
8626 unop(Iop_F32toF64, mkexpr(f32lo))) );
8627 } else {
8628 putIReg64( gregOfRexRM(pfx,modrm),
8629 binop( Iop_F64toI64,
8630 mkexpr(rmode),
8631 unop(Iop_F32toF64, mkexpr(f32lo))) );
8632 }
8633
8634 goto decode_success;
8635 }
8636
sewardj432f8b62005-05-10 02:50:05 +00008637 /* 0F 5E = DIVPS -- div 32Fx4 from R/M to R */
8638 if (haveNo66noF2noF3(pfx) && sz == 4
8639 && insn[0] == 0x0F && insn[1] == 0x5E) {
8640 delta = dis_SSE_E_to_G_all( pfx, delta+2, "divps", Iop_Div32Fx4 );
8641 goto decode_success;
8642 }
sewardjc49ce232005-02-25 13:03:03 +00008643
8644 /* F3 0F 5E = DIVSS -- div 32F0x4 from R/M to R */
8645 if (haveF3no66noF2(pfx) && sz == 4
8646 && insn[0] == 0x0F && insn[1] == 0x5E) {
8647 delta = dis_SSE_E_to_G_lo32( pfx, delta+2, "divss", Iop_Div32F0x4 );
8648 goto decode_success;
8649 }
8650
sewardjbcbb9de2005-03-27 02:22:32 +00008651 /* 0F AE /2 = LDMXCSR m32 -- load %mxcsr */
8652 if (insn[0] == 0x0F && insn[1] == 0xAE
8653 && haveNo66noF2noF3(pfx)
8654 && !epartIsReg(insn[2]) && gregLO3ofRM(insn[2]) == 2) {
8655
8656 IRTemp t64 = newTemp(Ity_I64);
8657 IRTemp ew = newTemp(Ity_I32);
8658
8659 vassert(sz == 4);
8660 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8661 delta += 2+alen;
8662 DIP("ldmxcsr %s\n", dis_buf);
8663
8664 /* The only thing we observe in %mxcsr is the rounding mode.
8665 Therefore, pass the 32-bit value (SSE native-format control
8666 word) to a clean helper, getting back a 64-bit value, the
8667 lower half of which is the SSEROUND value to store, and the
8668 upper half of which is the emulation-warning token which may
8669 be generated.
8670 */
8671 /* ULong amd64h_check_ldmxcsr ( ULong ); */
8672 assign( t64, mkIRExprCCall(
8673 Ity_I64, 0/*regparms*/,
8674 "amd64g_check_ldmxcsr",
8675 &amd64g_check_ldmxcsr,
8676 mkIRExprVec_1(
8677 unop(Iop_32Uto64,
8678 loadLE(Ity_I32, mkexpr(addr))
8679 )
8680 )
8681 )
8682 );
8683
8684 put_sse_roundingmode( unop(Iop_64to32, mkexpr(t64)) );
8685 assign( ew, unop(Iop_64HIto32, mkexpr(t64) ) );
8686 put_emwarn( mkexpr(ew) );
8687 /* Finally, if an emulation warning was reported, side-exit to
8688 the next insn, reporting the warning, so that Valgrind's
8689 dispatcher sees the warning. */
8690 stmt(
8691 IRStmt_Exit(
8692 binop(Iop_CmpNE64, unop(Iop_32Uto64,mkexpr(ew)), mkU64(0)),
8693 Ijk_EmWarn,
sewardj9e6491a2005-07-02 19:24:10 +00008694 IRConst_U64(guest_RIP_bbstart+delta)
sewardjbcbb9de2005-03-27 02:22:32 +00008695 )
8696 );
8697 goto decode_success;
8698 }
8699
sewardj432f8b62005-05-10 02:50:05 +00008700 /* 0F 5F = MAXPS -- max 32Fx4 from R/M to R */
8701 if (haveNo66noF2noF3(pfx) && sz == 4
8702 && insn[0] == 0x0F && insn[1] == 0x5F) {
8703 delta = dis_SSE_E_to_G_all( pfx, delta+2, "maxps", Iop_Max32Fx4 );
8704 goto decode_success;
8705 }
sewardj37d52572005-02-25 14:22:12 +00008706
8707 /* F3 0F 5F = MAXSS -- max 32F0x4 from R/M to R */
8708 if (haveF3no66noF2(pfx) && sz == 4
8709 && insn[0] == 0x0F && insn[1] == 0x5F) {
8710 delta = dis_SSE_E_to_G_lo32( pfx, delta+2, "maxss", Iop_Max32F0x4 );
8711 goto decode_success;
8712 }
8713
sewardj432f8b62005-05-10 02:50:05 +00008714 /* 0F 5D = MINPS -- min 32Fx4 from R/M to R */
8715 if (haveNo66noF2noF3(pfx) && sz == 4
8716 && insn[0] == 0x0F && insn[1] == 0x5D) {
8717 delta = dis_SSE_E_to_G_all( pfx, delta+2, "minps", Iop_Min32Fx4 );
8718 goto decode_success;
8719 }
sewardj37d52572005-02-25 14:22:12 +00008720
8721 /* F3 0F 5D = MINSS -- min 32F0x4 from R/M to R */
8722 if (haveF3no66noF2(pfx) && sz == 4
8723 && insn[0] == 0x0F && insn[1] == 0x5D) {
8724 delta = dis_SSE_E_to_G_lo32( pfx, delta+2, "minss", Iop_Min32F0x4 );
8725 goto decode_success;
8726 }
sewardj8d965312005-02-25 02:48:47 +00008727
8728 /* 0F 28 = MOVAPS -- move from E (mem or xmm) to G (xmm). */
8729 /* 0F 10 = MOVUPS -- move from E (mem or xmm) to G (xmm). */
8730 if (haveNo66noF2noF3(pfx) && sz == 4
8731 && insn[0] == 0x0F && (insn[1] == 0x28 || insn[1] == 0x10)) {
8732 modrm = getUChar(delta+2);
8733 if (epartIsReg(modrm)) {
8734 putXMMReg( gregOfRexRM(pfx,modrm),
8735 getXMMReg( eregOfRexRM(pfx,modrm) ));
8736 DIP("mov[ua]ps %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
8737 nameXMMReg(gregOfRexRM(pfx,modrm)));
8738 delta += 2+1;
8739 } else {
8740 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8741 putXMMReg( gregOfRexRM(pfx,modrm),
8742 loadLE(Ity_V128, mkexpr(addr)) );
8743 DIP("mov[ua]ps %s,%s\n", dis_buf,
8744 nameXMMReg(gregOfRexRM(pfx,modrm)));
8745 delta += 2+alen;
8746 }
8747 goto decode_success;
8748 }
sewardj1001dc42005-02-21 08:25:55 +00008749
8750 /* 0F 29 = MOVAPS -- move from G (xmm) to E (mem or xmm). */
sewardj446d2672005-06-10 11:04:52 +00008751 /* 0F 11 = MOVUPS -- move from G (xmm) to E (mem or xmm). */
sewardj8d965312005-02-25 02:48:47 +00008752 if (haveNo66noF2noF3(pfx) && sz == 4
sewardj446d2672005-06-10 11:04:52 +00008753 && insn[0] == 0x0F && (insn[1] == 0x29 || insn[1] == 0x11)) {
sewardj1001dc42005-02-21 08:25:55 +00008754 modrm = getUChar(delta+2);
8755 if (epartIsReg(modrm)) {
8756 /* fall through; awaiting test case */
8757 } else {
8758 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8759 storeLE( mkexpr(addr), getXMMReg(gregOfRexRM(pfx,modrm)) );
sewardj446d2672005-06-10 11:04:52 +00008760 DIP("mov[ua]ps %s,%s\n", nameXMMReg(gregOfRexRM(pfx,modrm)),
8761 dis_buf );
sewardj1001dc42005-02-21 08:25:55 +00008762 delta += 2+alen;
8763 goto decode_success;
8764 }
8765 }
8766
sewardj432f8b62005-05-10 02:50:05 +00008767 /* 0F 16 = MOVHPS -- move from mem to high half of XMM. */
8768 /* 0F 16 = MOVLHPS -- move from lo half to hi half of XMM. */
8769 if (haveNo66noF2noF3(pfx) && sz == 4
8770 && insn[0] == 0x0F && insn[1] == 0x16) {
8771 modrm = getUChar(delta+2);
8772 if (epartIsReg(modrm)) {
8773 delta += 2+1;
8774 putXMMRegLane64( gregOfRexRM(pfx,modrm), 1/*upper lane*/,
8775 getXMMRegLane64( eregOfRexRM(pfx,modrm), 0 ) );
8776 DIP("movhps %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
8777 nameXMMReg(gregOfRexRM(pfx,modrm)));
8778 } else {
8779 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8780 delta += 2+alen;
8781 putXMMRegLane64( gregOfRexRM(pfx,modrm), 1/*upper lane*/,
8782 loadLE(Ity_I64, mkexpr(addr)) );
8783 DIP("movhps %s,%s\n", dis_buf,
8784 nameXMMReg( gregOfRexRM(pfx,modrm) ));
8785 }
8786 goto decode_success;
8787 }
8788
8789 /* 0F 17 = MOVHPS -- move from high half of XMM to mem. */
8790 if (haveNo66noF2noF3(pfx) && sz == 4
8791 && insn[0] == 0x0F && insn[1] == 0x17) {
8792 if (!epartIsReg(insn[2])) {
8793 delta += 2;
8794 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
8795 delta += alen;
8796 storeLE( mkexpr(addr),
8797 getXMMRegLane64( gregOfRexRM(pfx,insn[2]),
8798 1/*upper lane*/ ) );
8799 DIP("movhps %s,%s\n", nameXMMReg( gregOfRexRM(pfx,insn[2]) ),
8800 dis_buf);
8801 goto decode_success;
8802 }
8803 /* else fall through */
8804 }
8805
8806 /* 0F 12 = MOVLPS -- move from mem to low half of XMM. */
8807 /* OF 12 = MOVHLPS -- from from hi half to lo half of XMM. */
8808 if (haveNo66noF2noF3(pfx) && sz == 4
8809 && insn[0] == 0x0F && insn[1] == 0x12) {
8810 modrm = getUChar(delta+2);
8811 if (epartIsReg(modrm)) {
8812 delta += 2+1;
8813 putXMMRegLane64( gregOfRexRM(pfx,modrm),
8814 0/*lower lane*/,
8815 getXMMRegLane64( eregOfRexRM(pfx,modrm), 1 ));
8816 DIP("movhlps %s, %s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
8817 nameXMMReg(gregOfRexRM(pfx,modrm)));
8818 } else {
8819 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8820 delta += 2+alen;
8821 putXMMRegLane64( gregOfRexRM(pfx,modrm), 0/*lower lane*/,
8822 loadLE(Ity_I64, mkexpr(addr)) );
8823 DIP("movlps %s, %s\n",
8824 dis_buf, nameXMMReg( gregOfRexRM(pfx,modrm) ));
8825 }
8826 goto decode_success;
8827 }
8828
8829 /* 0F 13 = MOVLPS -- move from low half of XMM to mem. */
8830 if (haveNo66noF2noF3(pfx) && sz == 4
8831 && insn[0] == 0x0F && insn[1] == 0x13) {
8832 if (!epartIsReg(insn[2])) {
8833 delta += 2;
8834 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
8835 delta += alen;
8836 storeLE( mkexpr(addr),
8837 getXMMRegLane64( gregOfRexRM(pfx,insn[2]),
8838 0/*lower lane*/ ) );
8839 DIP("movlps %s, %s\n", nameXMMReg( gregOfRexRM(pfx,insn[2]) ),
8840 dis_buf);
8841 goto decode_success;
8842 }
8843 /* else fall through */
8844 }
8845
sewardja7ba8c42005-05-10 20:08:34 +00008846 /* 0F 50 = MOVMSKPS - move 4 sign bits from 4 x F32 in xmm(E)
8847 to 4 lowest bits of ireg(G) */
sewardjae84d782006-04-13 22:06:35 +00008848 if (haveNo66noF2noF3(pfx) && (sz == 4 || sz == 8)
sewardja7ba8c42005-05-10 20:08:34 +00008849 && insn[0] == 0x0F && insn[1] == 0x50) {
sewardjae84d782006-04-13 22:06:35 +00008850 /* sz == 8 is a kludge to handle insns with REX.W redundantly
8851 set to 1, which has been known to happen:
8852 4c 0f 50 d9 rex64X movmskps %xmm1,%r11d
8853 */
sewardja7ba8c42005-05-10 20:08:34 +00008854 modrm = getUChar(delta+2);
8855 if (epartIsReg(modrm)) {
8856 Int src;
8857 t0 = newTemp(Ity_I32);
8858 t1 = newTemp(Ity_I32);
8859 t2 = newTemp(Ity_I32);
8860 t3 = newTemp(Ity_I32);
8861 delta += 2+1;
8862 src = eregOfRexRM(pfx,modrm);
8863 assign( t0, binop( Iop_And32,
8864 binop(Iop_Shr32, getXMMRegLane32(src,0), mkU8(31)),
8865 mkU32(1) ));
8866 assign( t1, binop( Iop_And32,
8867 binop(Iop_Shr32, getXMMRegLane32(src,1), mkU8(30)),
8868 mkU32(2) ));
8869 assign( t2, binop( Iop_And32,
8870 binop(Iop_Shr32, getXMMRegLane32(src,2), mkU8(29)),
8871 mkU32(4) ));
8872 assign( t3, binop( Iop_And32,
8873 binop(Iop_Shr32, getXMMRegLane32(src,3), mkU8(28)),
8874 mkU32(8) ));
8875 putIReg32( gregOfRexRM(pfx,modrm),
8876 binop(Iop_Or32,
8877 binop(Iop_Or32, mkexpr(t0), mkexpr(t1)),
8878 binop(Iop_Or32, mkexpr(t2), mkexpr(t3))
8879 )
8880 );
8881 DIP("movmskps %s,%s\n", nameXMMReg(src),
8882 nameIReg32(gregOfRexRM(pfx,modrm)));
8883 goto decode_success;
8884 }
8885 /* else fall through */
8886 }
8887
sewardj612be432005-05-11 02:55:54 +00008888 /* 66 0F 2B = MOVNTPD -- for us, just a plain SSE store. */
sewardja7ba8c42005-05-10 20:08:34 +00008889 /* 0F 2B = MOVNTPS -- for us, just a plain SSE store. */
sewardj612be432005-05-11 02:55:54 +00008890 if ( ( (haveNo66noF2noF3(pfx) && sz == 4)
8891 || (have66noF2noF3(pfx) && sz == 2)
8892 )
8893 && insn[0] == 0x0F && insn[1] == 0x2B) {
sewardja7ba8c42005-05-10 20:08:34 +00008894 modrm = getUChar(delta+2);
8895 if (!epartIsReg(modrm)) {
8896 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8897 storeLE( mkexpr(addr), getXMMReg(gregOfRexRM(pfx,modrm)) );
sewardj612be432005-05-11 02:55:54 +00008898 DIP("movntp%s %s,%s\n", sz==2 ? "d" : "s",
8899 dis_buf,
8900 nameXMMReg(gregOfRexRM(pfx,modrm)));
sewardja7ba8c42005-05-10 20:08:34 +00008901 delta += 2+alen;
8902 goto decode_success;
8903 }
8904 /* else fall through */
8905 }
8906
8907 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8908 /* 0F E7 = MOVNTQ -- for us, just a plain MMX store. Note, the
8909 Intel manual does not say anything about the usual business of
8910 the FP reg tags getting trashed whenever an MMX insn happens.
8911 So we just leave them alone.
8912 */
8913 if (haveNo66noF2noF3(pfx) && sz == 4
8914 && insn[0] == 0x0F && insn[1] == 0xE7) {
8915 modrm = getUChar(delta+2);
8916 if (!epartIsReg(modrm)) {
8917 /* do_MMX_preamble(); Intel docs don't specify this */
8918 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8919 storeLE( mkexpr(addr), getMMXReg(gregLO3ofRM(modrm)) );
8920 DIP("movntq %s,%s\n", dis_buf,
8921 nameMMXReg(gregLO3ofRM(modrm)));
8922 delta += 2+alen;
8923 goto decode_success;
8924 }
8925 /* else fall through */
8926 }
sewardj8d965312005-02-25 02:48:47 +00008927
8928 /* F3 0F 10 = MOVSS -- move 32 bits from E (mem or lo 1/4 xmm) to G
8929 (lo 1/4 xmm). If E is mem, upper 3/4 of G is zeroed out. */
8930 if (haveF3no66noF2(pfx) && sz == 4
8931 && insn[0] == 0x0F && insn[1] == 0x10) {
8932 modrm = getUChar(delta+2);
8933 if (epartIsReg(modrm)) {
8934 putXMMRegLane32( gregOfRexRM(pfx,modrm), 0,
8935 getXMMRegLane32( eregOfRexRM(pfx,modrm), 0 ));
8936 DIP("movss %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
8937 nameXMMReg(gregOfRexRM(pfx,modrm)));
8938 delta += 2+1;
8939 } else {
8940 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8941 putXMMReg( gregOfRexRM(pfx,modrm), mkV128(0) );
8942 putXMMRegLane32( gregOfRexRM(pfx,modrm), 0,
8943 loadLE(Ity_I32, mkexpr(addr)) );
8944 DIP("movss %s,%s\n", dis_buf,
8945 nameXMMReg(gregOfRexRM(pfx,modrm)));
8946 delta += 2+alen;
8947 }
8948 goto decode_success;
8949 }
8950
8951 /* F3 0F 11 = MOVSS -- move 32 bits from G (lo 1/4 xmm) to E (mem
8952 or lo 1/4 xmm). */
8953 if (haveF3no66noF2(pfx) && sz == 4
8954 && insn[0] == 0x0F && insn[1] == 0x11) {
8955 modrm = getUChar(delta+2);
8956 if (epartIsReg(modrm)) {
8957 /* fall through, we don't yet have a test case */
8958 } else {
8959 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8960 storeLE( mkexpr(addr),
8961 getXMMRegLane32(gregOfRexRM(pfx,modrm), 0) );
8962 DIP("movss %s,%s\n", nameXMMReg(gregOfRexRM(pfx,modrm)),
8963 dis_buf);
8964 delta += 2+alen;
8965 goto decode_success;
8966 }
8967 }
8968
sewardj432f8b62005-05-10 02:50:05 +00008969 /* 0F 59 = MULPS -- mul 32Fx4 from R/M to R */
8970 if (haveNo66noF2noF3(pfx) && sz == 4
8971 && insn[0] == 0x0F && insn[1] == 0x59) {
8972 delta = dis_SSE_E_to_G_all( pfx, delta+2, "mulps", Iop_Mul32Fx4 );
8973 goto decode_success;
8974 }
sewardj8d965312005-02-25 02:48:47 +00008975
8976 /* F3 0F 59 = MULSS -- mul 32F0x4 from R/M to R */
8977 if (haveF3no66noF2(pfx) && sz == 4
8978 && insn[0] == 0x0F && insn[1] == 0x59) {
8979 delta = dis_SSE_E_to_G_lo32( pfx, delta+2, "mulss", Iop_Mul32F0x4 );
8980 goto decode_success;
8981 }
8982
sewardj3aba9eb2005-03-30 23:20:47 +00008983 /* 0F 56 = ORPS -- G = G and E */
8984 if (haveNo66noF2noF3(pfx) && sz == 4
8985 && insn[0] == 0x0F && insn[1] == 0x56) {
8986 delta = dis_SSE_E_to_G_all( pfx, delta+2, "orps", Iop_OrV128 );
8987 goto decode_success;
8988 }
8989
sewardja7ba8c42005-05-10 20:08:34 +00008990 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8991 /* 0F E0 = PAVGB -- 8x8 unsigned Packed Average, with rounding */
8992 if (haveNo66noF2noF3(pfx) && sz == 4
8993 && insn[0] == 0x0F && insn[1] == 0xE0) {
8994 do_MMX_preamble();
8995 delta = dis_MMXop_regmem_to_reg (
8996 pfx, delta+2, insn[1], "pavgb", False );
8997 goto decode_success;
8998 }
8999
9000 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9001 /* 0F E3 = PAVGW -- 16x4 unsigned Packed Average, with rounding */
9002 if (haveNo66noF2noF3(pfx) && sz == 4
9003 && insn[0] == 0x0F && insn[1] == 0xE3) {
9004 do_MMX_preamble();
9005 delta = dis_MMXop_regmem_to_reg (
9006 pfx, delta+2, insn[1], "pavgw", False );
9007 goto decode_success;
9008 }
9009
9010 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9011 /* 0F C5 = PEXTRW -- extract 16-bit field from mmx(E) and put
9012 zero-extend of it in ireg(G). */
9013 if (haveNo66noF2noF3(pfx) && sz == 4
9014 && insn[0] == 0x0F && insn[1] == 0xC5) {
9015 modrm = insn[2];
9016 if (epartIsReg(modrm)) {
9017 IRTemp sV = newTemp(Ity_I64);
9018 t5 = newTemp(Ity_I16);
9019 do_MMX_preamble();
9020 assign(sV, getMMXReg(eregLO3ofRM(modrm)));
9021 breakup64to16s( sV, &t3, &t2, &t1, &t0 );
9022 switch (insn[3] & 3) {
9023 case 0: assign(t5, mkexpr(t0)); break;
9024 case 1: assign(t5, mkexpr(t1)); break;
9025 case 2: assign(t5, mkexpr(t2)); break;
9026 case 3: assign(t5, mkexpr(t3)); break;
9027 default: vassert(0);
9028 }
9029 putIReg32(gregOfRexRM(pfx,modrm), unop(Iop_16Uto32, mkexpr(t5)));
9030 DIP("pextrw $%d,%s,%s\n",
9031 (Int)insn[3], nameMMXReg(eregLO3ofRM(modrm)),
9032 nameIReg32(gregOfRexRM(pfx,modrm)));
9033 delta += 4;
9034 goto decode_success;
9035 }
9036 /* else fall through */
9037 /* note, for anyone filling in the mem case: this insn has one
9038 byte after the amode and therefore you must pass 1 as the
9039 last arg to disAMode */
9040 }
9041
9042 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9043 /* 0F C4 = PINSRW -- get 16 bits from E(mem or low half ireg) and
9044 put it into the specified lane of mmx(G). */
9045 if (haveNo66noF2noF3(pfx) && sz == 4
9046 && insn[0] == 0x0F && insn[1] == 0xC4) {
9047 /* Use t0 .. t3 to hold the 4 original 16-bit lanes of the
9048 mmx reg. t4 is the new lane value. t5 is the original
9049 mmx value. t6 is the new mmx value. */
9050 Int lane;
9051 t4 = newTemp(Ity_I16);
9052 t5 = newTemp(Ity_I64);
9053 t6 = newTemp(Ity_I64);
9054 modrm = insn[2];
9055 do_MMX_preamble();
9056
9057 assign(t5, getMMXReg(gregLO3ofRM(modrm)));
9058 breakup64to16s( t5, &t3, &t2, &t1, &t0 );
9059
9060 if (epartIsReg(modrm)) {
9061 assign(t4, getIReg16(eregOfRexRM(pfx,modrm)));
9062 delta += 3+1;
9063 lane = insn[3+1-1];
9064 DIP("pinsrw $%d,%s,%s\n", (Int)lane,
9065 nameIReg16(eregOfRexRM(pfx,modrm)),
9066 nameMMXReg(gregLO3ofRM(modrm)));
9067 } else {
9068 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 1 );
9069 delta += 3+alen;
9070 lane = insn[3+alen-1];
9071 assign(t4, loadLE(Ity_I16, mkexpr(addr)));
9072 DIP("pinsrw $%d,%s,%s\n", (Int)lane,
9073 dis_buf,
9074 nameMMXReg(gregLO3ofRM(modrm)));
9075 }
9076
9077 switch (lane & 3) {
9078 case 0: assign(t6, mk64from16s(t3,t2,t1,t4)); break;
9079 case 1: assign(t6, mk64from16s(t3,t2,t4,t0)); break;
9080 case 2: assign(t6, mk64from16s(t3,t4,t1,t0)); break;
9081 case 3: assign(t6, mk64from16s(t4,t2,t1,t0)); break;
9082 default: vassert(0);
9083 }
9084 putMMXReg(gregLO3ofRM(modrm), mkexpr(t6));
9085 goto decode_success;
9086 }
9087
9088 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9089 /* 0F EE = PMAXSW -- 16x4 signed max */
9090 if (haveNo66noF2noF3(pfx) && sz == 4
9091 && insn[0] == 0x0F && insn[1] == 0xEE) {
9092 do_MMX_preamble();
9093 delta = dis_MMXop_regmem_to_reg (
9094 pfx, delta+2, insn[1], "pmaxsw", False );
9095 goto decode_success;
9096 }
9097
9098 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9099 /* 0F DE = PMAXUB -- 8x8 unsigned max */
9100 if (haveNo66noF2noF3(pfx) && sz == 4
9101 && insn[0] == 0x0F && insn[1] == 0xDE) {
9102 do_MMX_preamble();
9103 delta = dis_MMXop_regmem_to_reg (
9104 pfx, delta+2, insn[1], "pmaxub", False );
9105 goto decode_success;
9106 }
9107
9108 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9109 /* 0F EA = PMINSW -- 16x4 signed min */
9110 if (haveNo66noF2noF3(pfx) && sz == 4
9111 && insn[0] == 0x0F && insn[1] == 0xEA) {
9112 do_MMX_preamble();
9113 delta = dis_MMXop_regmem_to_reg (
9114 pfx, delta+2, insn[1], "pminsw", False );
9115 goto decode_success;
9116 }
9117
9118 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9119 /* 0F DA = PMINUB -- 8x8 unsigned min */
9120 if (haveNo66noF2noF3(pfx) && sz == 4
9121 && insn[0] == 0x0F && insn[1] == 0xDA) {
9122 do_MMX_preamble();
9123 delta = dis_MMXop_regmem_to_reg (
9124 pfx, delta+2, insn[1], "pminub", False );
9125 goto decode_success;
9126 }
9127
9128 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9129 /* 0F D7 = PMOVMSKB -- extract sign bits from each of 8 lanes in
9130 mmx(G), turn them into a byte, and put zero-extend of it in
9131 ireg(G). */
9132 if (haveNo66noF2noF3(pfx) && sz == 4
9133 && insn[0] == 0x0F && insn[1] == 0xD7) {
9134 modrm = insn[2];
9135 if (epartIsReg(modrm)) {
9136 do_MMX_preamble();
9137 t0 = newTemp(Ity_I64);
9138 t1 = newTemp(Ity_I64);
9139 assign(t0, getMMXReg(eregLO3ofRM(modrm)));
9140 assign(t1, mkIRExprCCall(
9141 Ity_I64, 0/*regparms*/,
9142 "amd64g_calculate_mmx_pmovmskb",
9143 &amd64g_calculate_mmx_pmovmskb,
9144 mkIRExprVec_1(mkexpr(t0))));
9145 putIReg32(gregOfRexRM(pfx,modrm), unop(Iop_64to32,mkexpr(t1)));
9146 DIP("pmovmskb %s,%s\n", nameMMXReg(eregLO3ofRM(modrm)),
9147 nameIReg32(gregOfRexRM(pfx,modrm)));
9148 delta += 3;
9149 goto decode_success;
9150 }
9151 /* else fall through */
9152 }
9153
9154 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9155 /* 0F E4 = PMULUH -- 16x4 hi-half of unsigned widening multiply */
9156 if (haveNo66noF2noF3(pfx) && sz == 4
9157 && insn[0] == 0x0F && insn[1] == 0xE4) {
9158 do_MMX_preamble();
9159 delta = dis_MMXop_regmem_to_reg (
9160 pfx, delta+2, insn[1], "pmuluh", False );
9161 goto decode_success;
9162 }
sewardja6b93d12005-02-17 09:28:28 +00009163
9164 /* 0F 18 /0 = PREFETCHNTA -- prefetch into caches, */
9165 /* 0F 18 /1 = PREFETCH0 -- with various different hints */
9166 /* 0F 18 /2 = PREFETCH1 */
9167 /* 0F 18 /3 = PREFETCH2 */
9168 if (insn[0] == 0x0F && insn[1] == 0x18
sewardjbcbb9de2005-03-27 02:22:32 +00009169 && haveNo66noF2noF3(pfx)
sewardja6b93d12005-02-17 09:28:28 +00009170 && !epartIsReg(insn[2])
sewardj901ed122005-02-27 13:25:31 +00009171 && gregLO3ofRM(insn[2]) >= 0 && gregLO3ofRM(insn[2]) <= 3) {
sewardja6b93d12005-02-17 09:28:28 +00009172 HChar* hintstr = "??";
9173
9174 modrm = getUChar(delta+2);
9175 vassert(!epartIsReg(modrm));
9176
9177 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9178 delta += 2+alen;
9179
sewardj901ed122005-02-27 13:25:31 +00009180 switch (gregLO3ofRM(modrm)) {
sewardja6b93d12005-02-17 09:28:28 +00009181 case 0: hintstr = "nta"; break;
9182 case 1: hintstr = "t0"; break;
9183 case 2: hintstr = "t1"; break;
9184 case 3: hintstr = "t2"; break;
9185 default: vassert(0);
9186 }
9187
9188 DIP("prefetch%s %s\n", hintstr, dis_buf);
9189 goto decode_success;
9190 }
9191
sewardja7ba8c42005-05-10 20:08:34 +00009192 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9193 /* 0F F6 = PSADBW -- sum of 8Ux8 absolute differences */
9194 if (haveNo66noF2noF3(pfx) && sz == 4
9195 && insn[0] == 0x0F && insn[1] == 0xF6) {
9196 do_MMX_preamble();
9197 delta = dis_MMXop_regmem_to_reg (
9198 pfx, delta+2, insn[1], "psadbw", False );
9199 goto decode_success;
9200 }
9201
9202 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9203 /* 0F 70 = PSHUFW -- rearrange 4x16 from E(mmx or mem) to G(mmx) */
9204 if (haveNo66noF2noF3(pfx) && sz == 4
9205 && insn[0] == 0x0F && insn[1] == 0x70) {
9206 Int order;
9207 IRTemp sV, dV, s3, s2, s1, s0;
9208 s3 = s2 = s1 = s0 = IRTemp_INVALID;
9209 sV = newTemp(Ity_I64);
9210 dV = newTemp(Ity_I64);
9211 do_MMX_preamble();
9212 modrm = insn[2];
9213 if (epartIsReg(modrm)) {
9214 assign( sV, getMMXReg(eregLO3ofRM(modrm)) );
9215 order = (Int)insn[3];
9216 delta += 2+2;
9217 DIP("pshufw $%d,%s,%s\n", order,
9218 nameMMXReg(eregLO3ofRM(modrm)),
9219 nameMMXReg(gregLO3ofRM(modrm)));
9220 } else {
9221 addr = disAMode ( &alen, pfx, delta+2, dis_buf,
9222 1/*extra byte after amode*/ );
9223 assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
9224 order = (Int)insn[2+alen];
9225 delta += 3+alen;
9226 DIP("pshufw $%d,%s,%s\n", order,
9227 dis_buf,
9228 nameMMXReg(gregLO3ofRM(modrm)));
9229 }
9230 breakup64to16s( sV, &s3, &s2, &s1, &s0 );
9231# define SEL(n) \
9232 ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
9233 assign(dV,
9234 mk64from16s( SEL((order>>6)&3), SEL((order>>4)&3),
9235 SEL((order>>2)&3), SEL((order>>0)&3) )
9236 );
9237 putMMXReg(gregLO3ofRM(modrm), mkexpr(dV));
9238# undef SEL
9239 goto decode_success;
9240 }
9241
9242 /* 0F 53 = RCPPS -- approx reciprocal 32Fx4 from R/M to R */
9243 if (haveNo66noF2noF3(pfx) && sz == 4
9244 && insn[0] == 0x0F && insn[1] == 0x53) {
9245 delta = dis_SSE_E_to_G_unary_all( pfx, delta+2,
9246 "rcpps", Iop_Recip32Fx4 );
9247 goto decode_success;
9248 }
9249
9250 /* F3 0F 53 = RCPSS -- approx reciprocal 32F0x4 from R/M to R */
9251 if (haveF3no66noF2(pfx) && sz == 4
9252 && insn[0] == 0x0F && insn[1] == 0x53) {
9253 delta = dis_SSE_E_to_G_unary_lo32( pfx, delta+2,
9254 "rcpss", Iop_Recip32F0x4 );
9255 goto decode_success;
9256 }
9257
9258 /* 0F 52 = RSQRTPS -- approx reciprocal sqrt 32Fx4 from R/M to R */
9259 if (haveNo66noF2noF3(pfx) && sz == 4
9260 && insn[0] == 0x0F && insn[1] == 0x52) {
9261 delta = dis_SSE_E_to_G_unary_all( pfx, delta+2,
9262 "rsqrtps", Iop_RSqrt32Fx4 );
9263 goto decode_success;
9264 }
9265
9266 /* F3 0F 52 = RSQRTSS -- approx reciprocal sqrt 32F0x4 from R/M to R */
9267 if (haveF3no66noF2(pfx) && sz == 4
9268 && insn[0] == 0x0F && insn[1] == 0x52) {
9269 delta = dis_SSE_E_to_G_unary_lo32( pfx, delta+2,
9270 "rsqrtss", Iop_RSqrt32F0x4 );
9271 goto decode_success;
9272 }
sewardjf53b7352005-04-06 20:01:56 +00009273
9274 /* 0F AE /7 = SFENCE -- flush pending operations to memory */
9275 if (haveNo66noF2noF3(pfx)
9276 && insn[0] == 0x0F && insn[1] == 0xAE
9277 && epartIsReg(insn[2]) && gregLO3ofRM(insn[2]) == 7
9278 && sz == 4) {
9279 delta += 3;
9280 /* Insert a memory fence. It's sometimes important that these
9281 are carried through to the generated code. */
9282 stmt( IRStmt_MFence() );
9283 DIP("sfence\n");
9284 goto decode_success;
9285 }
9286
sewardja7ba8c42005-05-10 20:08:34 +00009287 /* 0F C6 /r ib = SHUFPS -- shuffle packed F32s */
9288 if (haveNo66noF2noF3(pfx) && sz == 4
9289 && insn[0] == 0x0F && insn[1] == 0xC6) {
9290 Int select;
9291 IRTemp sV, dV;
9292 IRTemp s3, s2, s1, s0, d3, d2, d1, d0;
9293 sV = newTemp(Ity_V128);
9294 dV = newTemp(Ity_V128);
9295 s3 = s2 = s1 = s0 = d3 = d2 = d1 = d0 = IRTemp_INVALID;
9296 modrm = insn[2];
9297 assign( dV, getXMMReg(gregOfRexRM(pfx,modrm)) );
9298
9299 if (epartIsReg(modrm)) {
9300 assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
9301 select = (Int)insn[3];
9302 delta += 2+2;
9303 DIP("shufps $%d,%s,%s\n", select,
9304 nameXMMReg(eregOfRexRM(pfx,modrm)),
9305 nameXMMReg(gregOfRexRM(pfx,modrm)));
9306 } else {
9307 addr = disAMode ( &alen, pfx, delta+2, dis_buf,
9308 1/*byte at end of insn*/ );
9309 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
9310 select = (Int)insn[2+alen];
9311 delta += 3+alen;
9312 DIP("shufps $%d,%s,%s\n", select,
9313 dis_buf,
9314 nameXMMReg(gregOfRexRM(pfx,modrm)));
9315 }
9316
9317 breakup128to32s( dV, &d3, &d2, &d1, &d0 );
9318 breakup128to32s( sV, &s3, &s2, &s1, &s0 );
9319
9320# define SELD(n) ((n)==0 ? d0 : ((n)==1 ? d1 : ((n)==2 ? d2 : d3)))
9321# define SELS(n) ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
9322
9323 putXMMReg(
9324 gregOfRexRM(pfx,modrm),
9325 mk128from32s( SELS((select>>6)&3), SELS((select>>4)&3),
9326 SELD((select>>2)&3), SELD((select>>0)&3) )
9327 );
9328
9329# undef SELD
9330# undef SELS
9331
9332 goto decode_success;
9333 }
9334
9335 /* 0F 51 = SQRTPS -- approx sqrt 32Fx4 from R/M to R */
9336 if (haveNo66noF2noF3(pfx) && sz == 4
9337 && insn[0] == 0x0F && insn[1] == 0x51) {
9338 delta = dis_SSE_E_to_G_unary_all( pfx, delta+2,
9339 "sqrtps", Iop_Sqrt32Fx4 );
9340 goto decode_success;
9341 }
9342
9343 /* F3 0F 51 = SQRTSS -- approx sqrt 32F0x4 from R/M to R */
9344 if (haveF3no66noF2(pfx) && sz == 4
9345 && insn[0] == 0x0F && insn[1] == 0x51) {
9346 delta = dis_SSE_E_to_G_unary_lo32( pfx, delta+2,
9347 "sqrtss", Iop_Sqrt32F0x4 );
9348 goto decode_success;
9349 }
sewardjbcbb9de2005-03-27 02:22:32 +00009350
9351 /* 0F AE /3 = STMXCSR m32 -- store %mxcsr */
9352 if (insn[0] == 0x0F && insn[1] == 0xAE
9353 && haveNo66noF2noF3(pfx)
9354 && !epartIsReg(insn[2]) && gregLO3ofRM(insn[2]) == 3) {
9355
9356 vassert(sz == 4);
9357 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9358 delta += 2+alen;
9359
9360 /* Fake up a native SSE mxcsr word. The only thing it depends
9361 on is SSEROUND[1:0], so call a clean helper to cook it up.
9362 */
9363 /* ULong amd64h_create_mxcsr ( ULong sseround ) */
9364 DIP("stmxcsr %s\n", dis_buf);
9365 storeLE(
9366 mkexpr(addr),
9367 unop(Iop_64to32,
9368 mkIRExprCCall(
9369 Ity_I64, 0/*regp*/,
9370 "amd64g_create_mxcsr", &amd64g_create_mxcsr,
9371 mkIRExprVec_1( unop(Iop_32Uto64,get_sse_roundingmode()) )
9372 )
9373 )
9374 );
9375 goto decode_success;
9376 }
9377
sewardj432f8b62005-05-10 02:50:05 +00009378 /* 0F 5C = SUBPS -- sub 32Fx4 from R/M to R */
9379 if (haveNo66noF2noF3(pfx) && sz == 4
9380 && insn[0] == 0x0F && insn[1] == 0x5C) {
9381 delta = dis_SSE_E_to_G_all( pfx, delta+2, "subps", Iop_Sub32Fx4 );
9382 goto decode_success;
9383 }
sewardj8d965312005-02-25 02:48:47 +00009384
9385 /* F3 0F 5C = SUBSS -- sub 32F0x4 from R/M to R */
9386 if (haveF3no66noF2(pfx) && sz == 4
9387 && insn[0] == 0x0F && insn[1] == 0x5C) {
9388 delta = dis_SSE_E_to_G_lo32( pfx, delta+2, "subss", Iop_Sub32F0x4 );
9389 goto decode_success;
9390 }
9391
sewardja7ba8c42005-05-10 20:08:34 +00009392 /* 0F 15 = UNPCKHPS -- unpack and interleave high part F32s */
9393 /* 0F 14 = UNPCKLPS -- unpack and interleave low part F32s */
9394 /* These just appear to be special cases of SHUFPS */
9395 if (haveNo66noF2noF3(pfx) && sz == 4
9396 && insn[0] == 0x0F && (insn[1] == 0x15 || insn[1] == 0x14)) {
9397 IRTemp sV, dV;
9398 IRTemp s3, s2, s1, s0, d3, d2, d1, d0;
sewardjca673ab2005-05-11 10:03:08 +00009399 Bool hi = toBool(insn[1] == 0x15);
sewardja7ba8c42005-05-10 20:08:34 +00009400 sV = newTemp(Ity_V128);
9401 dV = newTemp(Ity_V128);
9402 s3 = s2 = s1 = s0 = d3 = d2 = d1 = d0 = IRTemp_INVALID;
9403 modrm = insn[2];
9404 assign( dV, getXMMReg(gregOfRexRM(pfx,modrm)) );
9405
9406 if (epartIsReg(modrm)) {
9407 assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
9408 delta += 2+1;
9409 DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
9410 nameXMMReg(eregOfRexRM(pfx,modrm)),
9411 nameXMMReg(gregOfRexRM(pfx,modrm)));
9412 } else {
9413 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9414 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
9415 delta += 2+alen;
9416 DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
9417 dis_buf,
9418 nameXMMReg(gregOfRexRM(pfx,modrm)));
9419 }
9420
9421 breakup128to32s( dV, &d3, &d2, &d1, &d0 );
9422 breakup128to32s( sV, &s3, &s2, &s1, &s0 );
9423
9424 if (hi) {
9425 putXMMReg( gregOfRexRM(pfx,modrm), mk128from32s( s3, d3, s2, d2 ) );
9426 } else {
9427 putXMMReg( gregOfRexRM(pfx,modrm), mk128from32s( s1, d1, s0, d0 ) );
9428 }
9429
9430 goto decode_success;
9431 }
sewardj8d965312005-02-25 02:48:47 +00009432
9433 /* 0F 57 = XORPS -- G = G and E */
9434 if (haveNo66noF2noF3(pfx) && sz == 4
9435 && insn[0] == 0x0F && insn[1] == 0x57) {
9436 delta = dis_SSE_E_to_G_all( pfx, delta+2, "xorps", Iop_XorV128 );
9437 goto decode_success;
9438 }
9439
sewardj5992bd02005-05-11 02:13:42 +00009440 /* ---------------------------------------------------- */
9441 /* --- end of the SSE decoder. --- */
9442 /* ---------------------------------------------------- */
9443
9444 /* ---------------------------------------------------- */
9445 /* --- start of the SSE2 decoder. --- */
9446 /* ---------------------------------------------------- */
sewardj4c328cf2005-05-05 12:05:54 +00009447
9448 /* 66 0F 58 = ADDPD -- add 32Fx4 from R/M to R */
9449 if (have66noF2noF3(pfx) && sz == 2
9450 && insn[0] == 0x0F && insn[1] == 0x58) {
9451 delta = dis_SSE_E_to_G_all( pfx, delta+2, "addpd", Iop_Add64Fx2 );
9452 goto decode_success;
9453 }
sewardj1001dc42005-02-21 08:25:55 +00009454
9455 /* F2 0F 58 = ADDSD -- add 64F0x2 from R/M to R */
9456 if (haveF2no66noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x58) {
9457 vassert(sz == 4);
9458 delta = dis_SSE_E_to_G_lo64( pfx, delta+2, "addsd", Iop_Add64F0x2 );
9459 goto decode_success;
9460 }
9461
sewardj8d965312005-02-25 02:48:47 +00009462 /* 66 0F 55 = ANDNPD -- G = (not G) and E */
9463 if (have66noF2noF3(pfx) && sz == 2
9464 && insn[0] == 0x0F && insn[1] == 0x55) {
9465 delta = dis_SSE_E_to_G_all_invG( pfx, delta+2, "andnpd", Iop_AndV128 );
9466 goto decode_success;
9467 }
sewardj1a01e652005-02-23 11:39:21 +00009468
9469 /* 66 0F 54 = ANDPD -- G = G and E */
9470 if (have66noF2noF3(pfx) && sz == 2
9471 && insn[0] == 0x0F && insn[1] == 0x54) {
9472 delta = dis_SSE_E_to_G_all( pfx, delta+2, "andpd", Iop_AndV128 );
9473 goto decode_success;
9474 }
9475
sewardj97628592005-05-10 22:42:54 +00009476 /* 66 0F C2 = CMPPD -- 64Fx2 comparison from R/M to R */
9477 if (have66noF2noF3(pfx) && sz == 2
9478 && insn[0] == 0x0F && insn[1] == 0xC2) {
9479 delta = dis_SSEcmp_E_to_G( pfx, delta+2, "cmppd", True, 8 );
9480 goto decode_success;
9481 }
sewardj8d965312005-02-25 02:48:47 +00009482
9483 /* F2 0F C2 = CMPSD -- 64F0x2 comparison from R/M to R */
9484 if (haveF2no66noF3(pfx) && sz == 4
9485 && insn[0] == 0x0F && insn[1] == 0xC2) {
9486 delta = dis_SSEcmp_E_to_G( pfx, delta+2, "cmpsd", False, 8 );
9487 goto decode_success;
9488 }
sewardj18303862005-02-21 12:36:54 +00009489
9490 /* 66 0F 2F = COMISD -- 64F0x2 comparison G,E, and set ZCP */
9491 /* 66 0F 2E = UCOMISD -- 64F0x2 comparison G,E, and set ZCP */
sewardjc49ce232005-02-25 13:03:03 +00009492 if (have66noF2noF3(pfx) && sz == 2
sewardj18303862005-02-21 12:36:54 +00009493 && insn[0] == 0x0F && (insn[1] == 0x2F || insn[1] == 0x2E)) {
9494 IRTemp argL = newTemp(Ity_F64);
9495 IRTemp argR = newTemp(Ity_F64);
9496 modrm = getUChar(delta+2);
9497 if (epartIsReg(modrm)) {
9498 assign( argR, getXMMRegLane64F( eregOfRexRM(pfx,modrm),
9499 0/*lowest lane*/ ) );
9500 delta += 2+1;
9501 DIP("%scomisd %s,%s\n", insn[1]==0x2E ? "u" : "",
9502 nameXMMReg(eregOfRexRM(pfx,modrm)),
9503 nameXMMReg(gregOfRexRM(pfx,modrm)) );
9504 } else {
9505 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9506 assign( argR, loadLE(Ity_F64, mkexpr(addr)) );
9507 delta += 2+alen;
9508 DIP("%scomisd %s,%s\n", insn[1]==0x2E ? "u" : "",
9509 dis_buf,
9510 nameXMMReg(gregOfRexRM(pfx,modrm)) );
9511 }
9512 assign( argL, getXMMRegLane64F( gregOfRexRM(pfx,modrm),
9513 0/*lowest lane*/ ) );
9514
9515 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(AMD64G_CC_OP_COPY) ));
9516 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
9517 stmt( IRStmt_Put(
9518 OFFB_CC_DEP1,
9519 binop( Iop_And64,
9520 unop( Iop_32Uto64,
9521 binop(Iop_CmpF64, mkexpr(argL), mkexpr(argR)) ),
9522 mkU64(0x45)
9523 )));
9524
9525 goto decode_success;
9526 }
9527
sewardj09717342005-05-05 21:34:02 +00009528 /* F3 0F E6 = CVTDQ2PD -- convert 2 x I32 in mem/lo half xmm to 2 x
9529 F64 in xmm(G) */
9530 if (haveF3no66noF2(pfx) && insn[0] == 0x0F && insn[1] == 0xE6) {
9531 IRTemp arg64 = newTemp(Ity_I64);
9532 if (sz != 4) goto decode_failure;
9533
9534 modrm = getUChar(delta+2);
9535 if (epartIsReg(modrm)) {
9536 assign( arg64, getXMMRegLane64(eregOfRexRM(pfx,modrm), 0) );
9537 delta += 2+1;
9538 DIP("cvtdq2pd %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
9539 nameXMMReg(gregOfRexRM(pfx,modrm)));
9540 } else {
9541 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9542 assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
9543 delta += 2+alen;
9544 DIP("cvtdq2pd %s,%s\n", dis_buf,
9545 nameXMMReg(gregOfRexRM(pfx,modrm)) );
9546 }
9547
9548 putXMMRegLane64F(
9549 gregOfRexRM(pfx,modrm), 0,
9550 unop(Iop_I32toF64, unop(Iop_64to32, mkexpr(arg64)))
9551 );
9552
9553 putXMMRegLane64F(
9554 gregOfRexRM(pfx,modrm), 1,
9555 unop(Iop_I32toF64, unop(Iop_64HIto32, mkexpr(arg64)))
9556 );
9557
9558 goto decode_success;
9559 }
9560
sewardj5992bd02005-05-11 02:13:42 +00009561 /* 0F 5B = CVTDQ2PS -- convert 4 x I32 in mem/xmm to 4 x F32 in
9562 xmm(G) */
9563 if (haveNo66noF2noF3(pfx) && sz == 4
9564 && insn[0] == 0x0F && insn[1] == 0x5B) {
sewardj09717342005-05-05 21:34:02 +00009565 IRTemp argV = newTemp(Ity_V128);
9566 IRTemp rmode = newTemp(Ity_I32);
sewardj09717342005-05-05 21:34:02 +00009567
9568 modrm = getUChar(delta+2);
9569 if (epartIsReg(modrm)) {
9570 assign( argV, getXMMReg(eregOfRexRM(pfx,modrm)) );
9571 delta += 2+1;
sewardj5992bd02005-05-11 02:13:42 +00009572 DIP("cvtdq2ps %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
sewardj09717342005-05-05 21:34:02 +00009573 nameXMMReg(gregOfRexRM(pfx,modrm)));
9574 } else {
9575 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
sewardj5992bd02005-05-11 02:13:42 +00009576 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
sewardj09717342005-05-05 21:34:02 +00009577 delta += 2+alen;
sewardj5992bd02005-05-11 02:13:42 +00009578 DIP("cvtdq2ps %s,%s\n", dis_buf,
sewardj09717342005-05-05 21:34:02 +00009579 nameXMMReg(gregOfRexRM(pfx,modrm)) );
9580 }
9581
9582 assign( rmode, get_sse_roundingmode() );
sewardj5992bd02005-05-11 02:13:42 +00009583 breakup128to32s( argV, &t3, &t2, &t1, &t0 );
9584
9585# define CVT(_t) binop( Iop_F64toF32, \
9586 mkexpr(rmode), \
9587 unop(Iop_I32toF64,mkexpr(_t)))
9588
9589 putXMMRegLane32F( gregOfRexRM(pfx,modrm), 3, CVT(t3) );
9590 putXMMRegLane32F( gregOfRexRM(pfx,modrm), 2, CVT(t2) );
9591 putXMMRegLane32F( gregOfRexRM(pfx,modrm), 1, CVT(t1) );
9592 putXMMRegLane32F( gregOfRexRM(pfx,modrm), 0, CVT(t0) );
9593
9594# undef CVT
9595
9596 goto decode_success;
9597 }
9598
9599 /* 66 0F E6 = CVTTPD2DQ -- convert 2 x F64 in mem/xmm to 2 x I32 in
9600 lo half xmm(G), and zero upper half, rounding towards zero */
9601 /* F2 0F E6 = CVTPD2DQ -- convert 2 x F64 in mem/xmm to 2 x I32 in
9602 lo half xmm(G), according to prevailing rounding mode, and zero
9603 upper half */
9604 if ( ( (haveF2no66noF3(pfx) && sz == 4)
9605 || (have66noF2noF3(pfx) && sz == 2)
9606 )
9607 && insn[0] == 0x0F && insn[1] == 0xE6) {
9608 IRTemp argV = newTemp(Ity_V128);
9609 IRTemp rmode = newTemp(Ity_I32);
9610 Bool r2zero = toBool(sz == 2);
9611
9612 modrm = getUChar(delta+2);
9613 if (epartIsReg(modrm)) {
9614 assign( argV, getXMMReg(eregOfRexRM(pfx,modrm)) );
9615 delta += 2+1;
9616 DIP("cvt%spd2dq %s,%s\n", r2zero ? "t" : "",
9617 nameXMMReg(eregOfRexRM(pfx,modrm)),
9618 nameXMMReg(gregOfRexRM(pfx,modrm)));
9619 } else {
9620 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9621 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
9622 delta += 2+alen;
9623 DIP("cvt%spd2dq %s,%s\n", r2zero ? "t" : "",
9624 dis_buf,
9625 nameXMMReg(gregOfRexRM(pfx,modrm)) );
9626 }
9627
9628 if (r2zero) {
9629 assign(rmode, mkU32((UInt)Irrm_ZERO) );
9630 } else {
9631 assign( rmode, get_sse_roundingmode() );
9632 }
9633
sewardj09717342005-05-05 21:34:02 +00009634 t0 = newTemp(Ity_F64);
9635 t1 = newTemp(Ity_F64);
9636 assign( t0, unop(Iop_ReinterpI64asF64,
9637 unop(Iop_V128to64, mkexpr(argV))) );
9638 assign( t1, unop(Iop_ReinterpI64asF64,
9639 unop(Iop_V128HIto64, mkexpr(argV))) );
9640
9641# define CVT(_t) binop( Iop_F64toI32, \
9642 mkexpr(rmode), \
9643 mkexpr(_t) )
9644
9645 putXMMRegLane32( gregOfRexRM(pfx,modrm), 3, mkU32(0) );
9646 putXMMRegLane32( gregOfRexRM(pfx,modrm), 2, mkU32(0) );
9647 putXMMRegLane32( gregOfRexRM(pfx,modrm), 1, CVT(t1) );
9648 putXMMRegLane32( gregOfRexRM(pfx,modrm), 0, CVT(t0) );
9649
9650# undef CVT
9651
9652 goto decode_success;
9653 }
9654
sewardj5992bd02005-05-11 02:13:42 +00009655 /* 66 0F 2D = CVTPD2PI -- convert 2 x F64 in mem/xmm to 2 x
9656 I32 in mmx, according to prevailing SSE rounding mode */
9657 /* 66 0F 2C = CVTTPD2PI -- convert 2 x F64 in mem/xmm to 2 x
9658 I32 in mmx, rounding towards zero */
9659 if (have66noF2noF3(pfx) && sz == 2
9660 && insn[0] == 0x0F && (insn[1] == 0x2D || insn[1] == 0x2C)) {
9661 IRTemp dst64 = newTemp(Ity_I64);
9662 IRTemp rmode = newTemp(Ity_I32);
9663 IRTemp f64lo = newTemp(Ity_F64);
9664 IRTemp f64hi = newTemp(Ity_F64);
sewardjca673ab2005-05-11 10:03:08 +00009665 Bool r2zero = toBool(insn[1] == 0x2C);
sewardj5992bd02005-05-11 02:13:42 +00009666
9667 do_MMX_preamble();
9668 modrm = getUChar(delta+2);
9669
9670 if (epartIsReg(modrm)) {
9671 delta += 2+1;
9672 assign(f64lo, getXMMRegLane64F(eregOfRexRM(pfx,modrm), 0));
9673 assign(f64hi, getXMMRegLane64F(eregOfRexRM(pfx,modrm), 1));
9674 DIP("cvt%spd2pi %s,%s\n", r2zero ? "t" : "",
9675 nameXMMReg(eregOfRexRM(pfx,modrm)),
9676 nameMMXReg(gregLO3ofRM(modrm)));
9677 } else {
9678 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9679 assign(f64lo, loadLE(Ity_F64, mkexpr(addr)));
9680 assign(f64hi, loadLE(Ity_F64, binop( Iop_Add64,
9681 mkexpr(addr),
9682 mkU64(8) )));
9683 delta += 2+alen;
9684 DIP("cvt%spf2pi %s,%s\n", r2zero ? "t" : "",
9685 dis_buf,
9686 nameMMXReg(gregLO3ofRM(modrm)));
9687 }
9688
9689 if (r2zero) {
9690 assign(rmode, mkU32((UInt)Irrm_ZERO) );
9691 } else {
9692 assign( rmode, get_sse_roundingmode() );
9693 }
9694
9695 assign(
9696 dst64,
9697 binop( Iop_32HLto64,
9698 binop( Iop_F64toI32, mkexpr(rmode), mkexpr(f64hi) ),
9699 binop( Iop_F64toI32, mkexpr(rmode), mkexpr(f64lo) )
9700 )
9701 );
9702
9703 putMMXReg(gregLO3ofRM(modrm), mkexpr(dst64));
9704 goto decode_success;
9705 }
9706
9707 /* 66 0F 5A = CVTPD2PS -- convert 2 x F64 in mem/xmm to 2 x F32 in
9708 lo half xmm(G), rounding according to prevailing SSE rounding
9709 mode, and zero upper half */
9710 /* Note, this is practically identical to CVTPD2DQ. It would have
9711 been nicer to merge them together, but the insn[] offsets differ
9712 by one. */
9713 if (have66noF2noF3(pfx) && sz == 2
9714 && insn[0] == 0x0F && insn[1] == 0x5A) {
9715 IRTemp argV = newTemp(Ity_V128);
9716 IRTemp rmode = newTemp(Ity_I32);
9717
9718 modrm = getUChar(delta+2);
9719 if (epartIsReg(modrm)) {
9720 assign( argV, getXMMReg(eregOfRexRM(pfx,modrm)) );
9721 delta += 2+1;
9722 DIP("cvtpd2ps %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
9723 nameXMMReg(gregOfRexRM(pfx,modrm)));
9724 } else {
9725 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9726 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
9727 delta += 2+alen;
9728 DIP("cvtpd2ps %s,%s\n", dis_buf,
9729 nameXMMReg(gregOfRexRM(pfx,modrm)) );
9730 }
9731
9732 assign( rmode, get_sse_roundingmode() );
9733 t0 = newTemp(Ity_F64);
9734 t1 = newTemp(Ity_F64);
9735 assign( t0, unop(Iop_ReinterpI64asF64,
9736 unop(Iop_V128to64, mkexpr(argV))) );
9737 assign( t1, unop(Iop_ReinterpI64asF64,
9738 unop(Iop_V128HIto64, mkexpr(argV))) );
9739
9740# define CVT(_t) binop( Iop_F64toF32, \
9741 mkexpr(rmode), \
9742 mkexpr(_t) )
9743
9744 putXMMRegLane32( gregOfRexRM(pfx,modrm), 3, mkU32(0) );
9745 putXMMRegLane32( gregOfRexRM(pfx,modrm), 2, mkU32(0) );
9746 putXMMRegLane32F( gregOfRexRM(pfx,modrm), 1, CVT(t1) );
9747 putXMMRegLane32F( gregOfRexRM(pfx,modrm), 0, CVT(t0) );
9748
9749# undef CVT
9750
9751 goto decode_success;
9752 }
9753
9754 /* 66 0F 2A = CVTPI2PD -- convert 2 x I32 in mem/mmx to 2 x F64 in
9755 xmm(G) */
9756 if (have66noF2noF3(pfx) && sz == 2
9757 && insn[0] == 0x0F && insn[1] == 0x2A) {
9758 IRTemp arg64 = newTemp(Ity_I64);
9759
9760 modrm = getUChar(delta+2);
9761 do_MMX_preamble();
9762 if (epartIsReg(modrm)) {
9763 assign( arg64, getMMXReg(eregLO3ofRM(modrm)) );
9764 delta += 2+1;
9765 DIP("cvtpi2pd %s,%s\n", nameMMXReg(eregLO3ofRM(modrm)),
9766 nameXMMReg(gregOfRexRM(pfx,modrm)));
9767 } else {
9768 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9769 assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
9770 delta += 2+alen;
9771 DIP("cvtpi2pd %s,%s\n", dis_buf,
9772 nameXMMReg(gregOfRexRM(pfx,modrm)) );
9773 }
9774
9775 putXMMRegLane64F(
9776 gregOfRexRM(pfx,modrm), 0,
9777 unop(Iop_I32toF64, unop(Iop_64to32, mkexpr(arg64)) )
9778 );
9779
9780 putXMMRegLane64F(
9781 gregOfRexRM(pfx,modrm), 1,
9782 unop(Iop_I32toF64, unop(Iop_64HIto32, mkexpr(arg64)) )
9783 );
9784
9785 goto decode_success;
9786 }
9787
9788 /* F3 0F 5B = CVTTPS2DQ -- convert 4 x F32 in mem/xmm to 4 x I32 in
9789 xmm(G), rounding towards zero */
9790 /* 66 0F 5B = CVTPS2DQ -- convert 4 x F32 in mem/xmm to 4 x I32 in
9791 xmm(G), as per the prevailing rounding mode */
9792 if ( ( (have66noF2noF3(pfx) && sz == 2)
9793 || (haveF3no66noF2(pfx) && sz == 4)
9794 )
9795 && insn[0] == 0x0F && insn[1] == 0x5B) {
9796 IRTemp argV = newTemp(Ity_V128);
9797 IRTemp rmode = newTemp(Ity_I32);
9798 Bool r2zero = toBool(sz == 4);
9799
9800 modrm = getUChar(delta+2);
9801 if (epartIsReg(modrm)) {
9802 assign( argV, getXMMReg(eregOfRexRM(pfx,modrm)) );
9803 delta += 2+1;
9804 DIP("cvtps2dq %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
9805 nameXMMReg(gregOfRexRM(pfx,modrm)));
9806 } else {
9807 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9808 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
9809 delta += 2+alen;
9810 DIP("cvtps2dq %s,%s\n", dis_buf,
9811 nameXMMReg(gregOfRexRM(pfx,modrm)) );
9812 }
9813
9814 if (r2zero) {
9815 assign( rmode, mkU32((UInt)Irrm_ZERO) );
9816 } else {
9817 assign( rmode, get_sse_roundingmode() );
9818 }
9819
9820 breakup128to32s( argV, &t3, &t2, &t1, &t0 );
9821
9822 /* This is less than ideal. If it turns out to be a performance
9823 bottleneck it can be improved. */
9824# define CVT(_t) \
9825 binop( Iop_F64toI32, \
9826 mkexpr(rmode), \
9827 unop( Iop_F32toF64, \
9828 unop( Iop_ReinterpI32asF32, mkexpr(_t))) )
9829
9830 putXMMRegLane32( gregOfRexRM(pfx,modrm), 3, CVT(t3) );
9831 putXMMRegLane32( gregOfRexRM(pfx,modrm), 2, CVT(t2) );
9832 putXMMRegLane32( gregOfRexRM(pfx,modrm), 1, CVT(t1) );
9833 putXMMRegLane32( gregOfRexRM(pfx,modrm), 0, CVT(t0) );
9834
9835# undef CVT
9836
9837 goto decode_success;
9838 }
9839
9840 /* 0F 5A = CVTPS2PD -- convert 2 x F32 in low half mem/xmm to 2 x
9841 F64 in xmm(G). */
9842 if (haveNo66noF2noF3(pfx) && sz == 4
9843 && insn[0] == 0x0F && insn[1] == 0x5A) {
9844 IRTemp f32lo = newTemp(Ity_F32);
9845 IRTemp f32hi = newTemp(Ity_F32);
9846
9847 modrm = getUChar(delta+2);
9848 if (epartIsReg(modrm)) {
9849 assign( f32lo, getXMMRegLane32F(eregOfRexRM(pfx,modrm), 0) );
9850 assign( f32hi, getXMMRegLane32F(eregOfRexRM(pfx,modrm), 1) );
9851 delta += 2+1;
9852 DIP("cvtps2pd %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
9853 nameXMMReg(gregOfRexRM(pfx,modrm)));
9854 } else {
9855 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9856 assign( f32lo, loadLE(Ity_F32, mkexpr(addr)) );
9857 assign( f32hi, loadLE(Ity_F32,
9858 binop(Iop_Add64,mkexpr(addr),mkU64(4))) );
9859 delta += 2+alen;
9860 DIP("cvtps2pd %s,%s\n", dis_buf,
9861 nameXMMReg(gregOfRexRM(pfx,modrm)) );
9862 }
9863
9864 putXMMRegLane64F( gregOfRexRM(pfx,modrm), 1,
9865 unop(Iop_F32toF64, mkexpr(f32hi)) );
9866 putXMMRegLane64F( gregOfRexRM(pfx,modrm), 0,
9867 unop(Iop_F32toF64, mkexpr(f32lo)) );
9868
9869 goto decode_success;
9870 }
9871
9872 /* F2 0F 2D = CVTSD2SI
9873 when sz==4 -- convert F64 in mem/low half xmm to I32 in ireg,
9874 according to prevailing SSE rounding mode
9875 when sz==8 -- convert F64 in mem/low half xmm to I64 in ireg,
9876 according to prevailing SSE rounding mode
9877 */
sewardj1a01e652005-02-23 11:39:21 +00009878 /* F2 0F 2C = CVTTSD2SI
9879 when sz==4 -- convert F64 in mem/low half xmm to I32 in ireg,
9880 truncating towards zero
9881 when sz==8 -- convert F64 in mem/low half xmm to I64 in ireg,
9882 truncating towards zero
9883 */
9884 if (haveF2no66noF3(pfx)
9885 && insn[0] == 0x0F
sewardj5992bd02005-05-11 02:13:42 +00009886 && (insn[1] == 0x2D || insn[1] == 0x2C)) {
sewardj1a01e652005-02-23 11:39:21 +00009887 IRTemp rmode = newTemp(Ity_I32);
9888 IRTemp f64lo = newTemp(Ity_F64);
sewardj1027dc22005-02-26 01:55:02 +00009889 Bool r2zero = toBool(insn[1] == 0x2C);
sewardj1a01e652005-02-23 11:39:21 +00009890 vassert(sz == 4 || sz == 8);
9891
9892 modrm = getUChar(delta+2);
9893 if (epartIsReg(modrm)) {
9894 delta += 2+1;
9895 assign(f64lo, getXMMRegLane64F(eregOfRexRM(pfx,modrm), 0));
9896 DIP("cvt%ssd2si %s,%s\n", r2zero ? "t" : "",
9897 nameXMMReg(eregOfRexRM(pfx,modrm)),
sewardj5b470602005-02-27 13:10:48 +00009898 nameIReg(sz, gregOfRexRM(pfx,modrm), False));
sewardj1a01e652005-02-23 11:39:21 +00009899 } else {
9900 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9901 assign(f64lo, loadLE(Ity_F64, mkexpr(addr)));
9902 delta += 2+alen;
9903 DIP("cvt%ssd2si %s,%s\n", r2zero ? "t" : "",
9904 dis_buf,
sewardj5b470602005-02-27 13:10:48 +00009905 nameIReg(sz, gregOfRexRM(pfx,modrm), False));
sewardj1a01e652005-02-23 11:39:21 +00009906 }
9907
9908 if (r2zero) {
9909 assign( rmode, mkU32((UInt)Irrm_ZERO) );
9910 } else {
9911 assign( rmode, get_sse_roundingmode() );
9912 }
9913
9914 if (sz == 4) {
sewardj5b470602005-02-27 13:10:48 +00009915 putIReg32( gregOfRexRM(pfx,modrm),
9916 binop( Iop_F64toI32, mkexpr(rmode), mkexpr(f64lo)) );
sewardj1a01e652005-02-23 11:39:21 +00009917 } else {
sewardj5b470602005-02-27 13:10:48 +00009918 putIReg64( gregOfRexRM(pfx,modrm),
9919 binop( Iop_F64toI64, mkexpr(rmode), mkexpr(f64lo)) );
sewardj1a01e652005-02-23 11:39:21 +00009920 }
9921
9922 goto decode_success;
9923 }
9924
sewardj8d965312005-02-25 02:48:47 +00009925 /* F2 0F 5A = CVTSD2SS -- convert F64 in mem/low half xmm to F32 in
9926 low 1/4 xmm(G), according to prevailing SSE rounding mode */
9927 if (haveF2no66noF3(pfx) && sz == 4
9928 && insn[0] == 0x0F && insn[1] == 0x5A) {
9929 IRTemp rmode = newTemp(Ity_I32);
9930 IRTemp f64lo = newTemp(Ity_F64);
9931 vassert(sz == 4);
9932
9933 modrm = getUChar(delta+2);
9934 if (epartIsReg(modrm)) {
9935 delta += 2+1;
9936 assign(f64lo, getXMMRegLane64F(eregOfRexRM(pfx,modrm), 0));
9937 DIP("cvtsd2ss %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
9938 nameXMMReg(gregOfRexRM(pfx,modrm)));
9939 } else {
9940 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9941 assign(f64lo, loadLE(Ity_F64, mkexpr(addr)));
9942 delta += 2+alen;
9943 DIP("cvtsd2ss %s,%s\n", dis_buf,
9944 nameXMMReg(gregOfRexRM(pfx,modrm)));
9945 }
9946
9947 assign( rmode, get_sse_roundingmode() );
9948 putXMMRegLane32F(
9949 gregOfRexRM(pfx,modrm), 0,
9950 binop( Iop_F64toF32, mkexpr(rmode), mkexpr(f64lo) )
9951 );
9952
9953 goto decode_success;
9954 }
sewardj1a01e652005-02-23 11:39:21 +00009955
9956 /* F2 0F 2A = CVTSI2SD
9957 when sz==4 -- convert I32 in mem/ireg to F64 in low half xmm
9958 when sz==8 -- convert I64 in mem/ireg to F64 in low half xmm
9959 */
sewardj8d965312005-02-25 02:48:47 +00009960 if (haveF2no66noF3(pfx) && (sz == 4 || sz == 8)
9961 && insn[0] == 0x0F && insn[1] == 0x2A) {
sewardj1a01e652005-02-23 11:39:21 +00009962 modrm = getUChar(delta+2);
9963
9964 if (sz == 4) {
9965 IRTemp arg32 = newTemp(Ity_I32);
9966 if (epartIsReg(modrm)) {
sewardj5b470602005-02-27 13:10:48 +00009967 assign( arg32, getIReg32(eregOfRexRM(pfx,modrm)) );
sewardj1a01e652005-02-23 11:39:21 +00009968 delta += 2+1;
sewardj5b470602005-02-27 13:10:48 +00009969 DIP("cvtsi2sd %s,%s\n", nameIReg32(eregOfRexRM(pfx,modrm)),
sewardj1a01e652005-02-23 11:39:21 +00009970 nameXMMReg(gregOfRexRM(pfx,modrm)));
9971 } else {
9972 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9973 assign( arg32, loadLE(Ity_I32, mkexpr(addr)) );
9974 delta += 2+alen;
9975 DIP("cvtsi2sd %s,%s\n", dis_buf,
9976 nameXMMReg(gregOfRexRM(pfx,modrm)) );
9977 }
9978 putXMMRegLane64F( gregOfRexRM(pfx,modrm), 0,
9979 unop(Iop_I32toF64, mkexpr(arg32))
9980 );
9981 } else {
9982 /* sz == 8 */
9983 IRTemp arg64 = newTemp(Ity_I64);
9984 if (epartIsReg(modrm)) {
sewardj5b470602005-02-27 13:10:48 +00009985 assign( arg64, getIReg64(eregOfRexRM(pfx,modrm)) );
sewardj1a01e652005-02-23 11:39:21 +00009986 delta += 2+1;
sewardj5b470602005-02-27 13:10:48 +00009987 DIP("cvtsi2sdq %s,%s\n", nameIReg64(eregOfRexRM(pfx,modrm)),
sewardj8d965312005-02-25 02:48:47 +00009988 nameXMMReg(gregOfRexRM(pfx,modrm)));
sewardj1a01e652005-02-23 11:39:21 +00009989 } else {
9990 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9991 assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
9992 delta += 2+alen;
sewardj8d965312005-02-25 02:48:47 +00009993 DIP("cvtsi2sdq %s,%s\n", dis_buf,
9994 nameXMMReg(gregOfRexRM(pfx,modrm)) );
sewardj1a01e652005-02-23 11:39:21 +00009995 }
9996 putXMMRegLane64F(
9997 gregOfRexRM(pfx,modrm),
9998 0,
9999 binop( Iop_I64toF64,
10000 get_sse_roundingmode(),
10001 mkexpr(arg64)
10002 )
10003 );
10004
10005 }
10006
10007 goto decode_success;
10008 }
10009
sewardjc49ce232005-02-25 13:03:03 +000010010 /* F3 0F 5A = CVTSS2SD -- convert F32 in mem/low 1/4 xmm to F64 in
10011 low half xmm(G) */
10012 if (haveF3no66noF2(pfx) && sz == 4
10013 && insn[0] == 0x0F && insn[1] == 0x5A) {
10014 IRTemp f32lo = newTemp(Ity_F32);
10015
10016 modrm = getUChar(delta+2);
10017 if (epartIsReg(modrm)) {
10018 delta += 2+1;
10019 assign(f32lo, getXMMRegLane32F(eregOfRexRM(pfx,modrm), 0));
10020 DIP("cvtss2sd %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
10021 nameXMMReg(gregOfRexRM(pfx,modrm)));
10022 } else {
10023 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10024 assign(f32lo, loadLE(Ity_F32, mkexpr(addr)));
10025 delta += 2+alen;
10026 DIP("cvtss2sd %s,%s\n", dis_buf,
10027 nameXMMReg(gregOfRexRM(pfx,modrm)));
10028 }
10029
10030 putXMMRegLane64F( gregOfRexRM(pfx,modrm), 0,
10031 unop( Iop_F32toF64, mkexpr(f32lo) ) );
10032
10033 goto decode_success;
10034 }
10035
sewardj5992bd02005-05-11 02:13:42 +000010036 /* 66 0F 5E = DIVPD -- div 64Fx2 from R/M to R */
10037 if (have66noF2noF3(pfx) && sz == 2
10038 && insn[0] == 0x0F && insn[1] == 0x5E) {
10039 delta = dis_SSE_E_to_G_all( pfx, delta+2, "divpd", Iop_Div64Fx2 );
10040 goto decode_success;
10041 }
sewardj1001dc42005-02-21 08:25:55 +000010042
10043 /* F2 0F 5E = DIVSD -- div 64F0x2 from R/M to R */
10044 if (haveF2no66noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x5E) {
10045 vassert(sz == 4);
10046 delta = dis_SSE_E_to_G_lo64( pfx, delta+2, "divsd", Iop_Div64F0x2 );
10047 goto decode_success;
10048 }
10049
sewardj5992bd02005-05-11 02:13:42 +000010050 /* 0F AE /5 = LFENCE -- flush pending operations to memory */
10051 /* 0F AE /6 = MFENCE -- flush pending operations to memory */
10052 if (haveNo66noF2noF3(pfx) && sz == 4
10053 && insn[0] == 0x0F && insn[1] == 0xAE
10054 && epartIsReg(insn[2])
10055 && (gregLO3ofRM(insn[2]) == 5 || gregLO3ofRM(insn[2]) == 6)) {
10056 delta += 3;
10057 /* Insert a memory fence. It's sometimes important that these
10058 are carried through to the generated code. */
10059 stmt( IRStmt_MFence() );
10060 DIP("%sfence\n", gregLO3ofRM(insn[2])==5 ? "l" : "m");
10061 goto decode_success;
10062 }
10063
10064 /* 66 0F 5F = MAXPD -- max 64Fx2 from R/M to R */
10065 if (have66noF2noF3(pfx) && sz == 2
10066 && insn[0] == 0x0F && insn[1] == 0x5F) {
10067 delta = dis_SSE_E_to_G_all( pfx, delta+2, "maxpd", Iop_Max64Fx2 );
10068 goto decode_success;
10069 }
sewardj1a01e652005-02-23 11:39:21 +000010070
10071 /* F2 0F 5F = MAXSD -- max 64F0x2 from R/M to R */
10072 if (haveF2no66noF3(pfx) && sz == 4
10073 && insn[0] == 0x0F && insn[1] == 0x5F) {
10074 delta = dis_SSE_E_to_G_lo64( pfx, delta+2, "maxsd", Iop_Max64F0x2 );
10075 goto decode_success;
10076 }
10077
sewardj5992bd02005-05-11 02:13:42 +000010078 /* 66 0F 5D = MINPD -- min 64Fx2 from R/M to R */
10079 if (have66noF2noF3(pfx) && sz == 2
10080 && insn[0] == 0x0F && insn[1] == 0x5D) {
10081 delta = dis_SSE_E_to_G_all( pfx, delta+2, "minpd", Iop_Min64Fx2 );
10082 goto decode_success;
10083 }
sewardjc49ce232005-02-25 13:03:03 +000010084
10085 /* F2 0F 5D = MINSD -- min 64F0x2 from R/M to R */
10086 if (haveF2no66noF3(pfx) && sz == 4
10087 && insn[0] == 0x0F && insn[1] == 0x5D) {
10088 delta = dis_SSE_E_to_G_lo64( pfx, delta+2, "minsd", Iop_Min64F0x2 );
10089 goto decode_success;
10090 }
sewardj8d965312005-02-25 02:48:47 +000010091
10092 /* 66 0F 28 = MOVAPD -- move from E (mem or xmm) to G (xmm). */
10093 /* 66 0F 10 = MOVUPD -- move from E (mem or xmm) to G (xmm). */
10094 /* 66 0F 6F = MOVDQA -- move from E (mem or xmm) to G (xmm). */
10095 if (have66noF2noF3(pfx) && sz == 2
10096 && insn[0] == 0x0F
10097 && (insn[1] == 0x28 || insn[1] == 0x10 || insn[1] == 0x6F)) {
10098 HChar* wot = insn[1]==0x28 ? "apd" :
10099 insn[1]==0x10 ? "upd" : "dqa";
10100 modrm = getUChar(delta+2);
10101 if (epartIsReg(modrm)) {
10102 putXMMReg( gregOfRexRM(pfx,modrm),
10103 getXMMReg( eregOfRexRM(pfx,modrm) ));
10104 DIP("mov%s %s,%s\n", wot, nameXMMReg(eregOfRexRM(pfx,modrm)),
10105 nameXMMReg(gregOfRexRM(pfx,modrm)));
10106 delta += 2+1;
10107 } else {
10108 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10109 putXMMReg( gregOfRexRM(pfx,modrm),
10110 loadLE(Ity_V128, mkexpr(addr)) );
10111 DIP("mov%s %s,%s\n", wot, dis_buf,
10112 nameXMMReg(gregOfRexRM(pfx,modrm)));
10113 delta += 2+alen;
10114 }
10115 goto decode_success;
10116 }
10117
sewardj4c328cf2005-05-05 12:05:54 +000010118 /* 66 0F 29 = MOVAPD -- move from G (xmm) to E (mem or xmm). */
sewardj240fd862005-11-01 18:59:38 +000010119 /* 66 0F 11 = MOVUPD -- move from G (xmm) to E (mem or xmm). */
10120 if (have66noF2noF3(pfx) && insn[0] == 0x0F
10121 && (insn[1] == 0x29 || insn[1] == 0x11)) {
sewardj4c328cf2005-05-05 12:05:54 +000010122 modrm = getUChar(delta+2);
10123 if (epartIsReg(modrm)) {
10124 /* fall through; awaiting test case */
10125 } else {
10126 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10127 storeLE( mkexpr(addr), getXMMReg(gregOfRexRM(pfx,modrm)) );
sewardj240fd862005-11-01 18:59:38 +000010128 DIP("mov[ua]pd %s,%s\n", nameXMMReg(gregOfRexRM(pfx,modrm)),
10129 dis_buf );
sewardj4c328cf2005-05-05 12:05:54 +000010130 delta += 2+alen;
10131 goto decode_success;
10132 }
10133 }
10134
sewardj09717342005-05-05 21:34:02 +000010135 /* 66 0F 6E = MOVD from ireg32/m32 to xmm lo 1/4, zeroing high 3/4 of xmm. */
10136 /* or from ireg64/m64 to xmm lo 1/2, zeroing high 1/2 of xmm. */
10137 if (have66noF2noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x6E) {
sewardj97628592005-05-10 22:42:54 +000010138 vassert(sz == 2 || sz == 8);
10139 if (sz == 2) sz = 4;
sewardj09717342005-05-05 21:34:02 +000010140 modrm = getUChar(delta+2);
10141 if (epartIsReg(modrm)) {
10142 delta += 2+1;
10143 if (sz == 4) {
sewardj09717342005-05-05 21:34:02 +000010144 putXMMReg(
10145 gregOfRexRM(pfx,modrm),
10146 unop( Iop_32UtoV128, getIReg32(eregOfRexRM(pfx,modrm)) )
10147 );
10148 DIP("movd %s, %s\n", nameIReg32(eregOfRexRM(pfx,modrm)),
10149 nameXMMReg(gregOfRexRM(pfx,modrm)));
10150 } else {
10151 putXMMReg(
10152 gregOfRexRM(pfx,modrm),
10153 unop( Iop_64UtoV128, getIReg64(eregOfRexRM(pfx,modrm)) )
10154 );
10155 DIP("movq %s, %s\n", nameIReg64(eregOfRexRM(pfx,modrm)),
10156 nameXMMReg(gregOfRexRM(pfx,modrm)));
10157 }
10158 } else {
10159 addr = disAMode( &alen, pfx, delta+2, dis_buf, 0 );
10160 delta += 2+alen;
10161 putXMMReg(
10162 gregOfRexRM(pfx,modrm),
10163 sz == 4
10164 ? unop( Iop_32UtoV128,loadLE(Ity_I32, mkexpr(addr)) )
10165 : unop( Iop_64UtoV128,loadLE(Ity_I64, mkexpr(addr)) )
10166 );
10167 DIP("mov%c %s, %s\n", sz == 4 ? 'd' : 'q', dis_buf,
10168 nameXMMReg(gregOfRexRM(pfx,modrm)));
10169 }
10170 goto decode_success;
10171 }
10172
10173 /* 66 0F 7E = MOVD from xmm low 1/4 to ireg32 or m32. */
10174 /* or from xmm low 1/2 to ireg64 or m64. */
10175 if (have66noF2noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x7E) {
10176 if (sz == 2) sz = 4;
10177 vassert(sz == 4 || sz == 8);
10178 modrm = getUChar(delta+2);
10179 if (epartIsReg(modrm)) {
10180 delta += 2+1;
10181 if (sz == 4) {
10182 putIReg32( eregOfRexRM(pfx,modrm),
10183 getXMMRegLane32(gregOfRexRM(pfx,modrm), 0) );
10184 DIP("movd %s, %s\n", nameXMMReg(gregOfRexRM(pfx,modrm)),
10185 nameIReg32(eregOfRexRM(pfx,modrm)));
10186 } else {
10187 putIReg64( eregOfRexRM(pfx,modrm),
10188 getXMMRegLane64(gregOfRexRM(pfx,modrm), 0) );
10189 DIP("movq %s, %s\n", nameXMMReg(gregOfRexRM(pfx,modrm)),
10190 nameIReg64(eregOfRexRM(pfx,modrm)));
10191 }
10192 } else {
10193 addr = disAMode( &alen, pfx, delta+2, dis_buf, 0 );
10194 delta += 2+alen;
10195 storeLE( mkexpr(addr),
10196 sz == 4
10197 ? getXMMRegLane32(gregOfRexRM(pfx,modrm),0)
10198 : getXMMRegLane64(gregOfRexRM(pfx,modrm),0) );
10199 DIP("mov%c %s, %s\n", sz == 4 ? 'd' : 'q',
10200 nameXMMReg(gregOfRexRM(pfx,modrm)), dis_buf);
10201 }
10202 goto decode_success;
10203 }
10204
10205 /* 66 0F 7F = MOVDQA -- move from G (xmm) to E (mem or xmm). */
10206 if (have66noF2noF3(pfx) && sz == 2
10207 && insn[0] == 0x0F && insn[1] == 0x7F) {
10208 modrm = getUChar(delta+2);
10209 if (epartIsReg(modrm)) {
10210 delta += 2+1;
10211 putXMMReg( eregOfRexRM(pfx,modrm),
10212 getXMMReg(gregOfRexRM(pfx,modrm)) );
10213 DIP("movdqa %s, %s\n", nameXMMReg(gregOfRexRM(pfx,modrm)),
10214 nameXMMReg(eregOfRexRM(pfx,modrm)));
10215 } else {
10216 addr = disAMode( &alen, pfx, delta+2, dis_buf, 0 );
10217 delta += 2+alen;
10218 storeLE( mkexpr(addr), getXMMReg(gregOfRexRM(pfx,modrm)) );
10219 DIP("movdqa %s, %s\n", nameXMMReg(gregOfRexRM(pfx,modrm)), dis_buf);
10220 }
10221 goto decode_success;
10222 }
10223
sewardj612be432005-05-11 02:55:54 +000010224 /* F3 0F 6F = MOVDQU -- move from E (mem or xmm) to G (xmm). */
10225 if (haveF3no66noF2(pfx) && sz == 4
10226 && insn[0] == 0x0F && insn[1] == 0x6F) {
10227 modrm = getUChar(delta+2);
10228 if (epartIsReg(modrm)) {
10229 putXMMReg( gregOfRexRM(pfx,modrm),
10230 getXMMReg( eregOfRexRM(pfx,modrm) ));
10231 DIP("movdqu %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
10232 nameXMMReg(gregOfRexRM(pfx,modrm)));
10233 delta += 2+1;
10234 } else {
10235 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10236 putXMMReg( gregOfRexRM(pfx,modrm),
10237 loadLE(Ity_V128, mkexpr(addr)) );
10238 DIP("movdqu %s,%s\n", dis_buf,
10239 nameXMMReg(gregOfRexRM(pfx,modrm)));
10240 delta += 2+alen;
10241 }
10242 goto decode_success;
10243 }
10244
10245 /* F3 0F 7F = MOVDQU -- move from G (xmm) to E (mem or xmm). */
10246 if (haveF3no66noF2(pfx) && sz == 4
10247 && insn[0] == 0x0F && insn[1] == 0x7F) {
10248 modrm = getUChar(delta+2);
10249 if (epartIsReg(modrm)) {
10250 goto decode_failure; /* awaiting test case */
10251 delta += 2+1;
10252 putXMMReg( eregOfRexRM(pfx,modrm),
10253 getXMMReg(gregOfRexRM(pfx,modrm)) );
10254 DIP("movdqu %s, %s\n", nameXMMReg(gregOfRexRM(pfx,modrm)),
10255 nameXMMReg(eregOfRexRM(pfx,modrm)));
10256 } else {
10257 addr = disAMode( &alen, pfx, delta+2, dis_buf, 0 );
10258 delta += 2+alen;
10259 storeLE( mkexpr(addr), getXMMReg(gregOfRexRM(pfx,modrm)) );
10260 DIP("movdqu %s, %s\n", nameXMMReg(gregOfRexRM(pfx,modrm)), dis_buf);
10261 }
10262 goto decode_success;
10263 }
10264
10265 /* F2 0F D6 = MOVDQ2Q -- move from E (lo half xmm, not mem) to G (mmx). */
10266 if (haveF2no66noF3(pfx) && sz == 4
10267 && insn[0] == 0x0F && insn[1] == 0xD6) {
10268 modrm = getUChar(delta+2);
10269 if (epartIsReg(modrm)) {
10270 do_MMX_preamble();
10271 putMMXReg( gregLO3ofRM(modrm),
10272 getXMMRegLane64( eregOfRexRM(pfx,modrm), 0 ));
10273 DIP("movdq2q %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
10274 nameMMXReg(gregLO3ofRM(modrm)));
10275 delta += 2+1;
10276 goto decode_success;
10277 } else {
10278 /* apparently no mem case for this insn */
10279 goto decode_failure;
10280 }
10281 }
sewardj4c328cf2005-05-05 12:05:54 +000010282
10283 /* 66 0F 16 = MOVHPD -- move from mem to high half of XMM. */
10284 /* These seems identical to MOVHPS. This instruction encoding is
10285 completely crazy. */
10286 if (have66noF2noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x16) {
10287 modrm = getUChar(delta+2);
10288 if (epartIsReg(modrm)) {
10289 /* fall through; apparently reg-reg is not possible */
10290 } else {
10291 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10292 delta += 2+alen;
10293 putXMMRegLane64( gregOfRexRM(pfx,modrm), 1/*upper lane*/,
10294 loadLE(Ity_I64, mkexpr(addr)) );
10295 DIP("movhpd %s,%s\n", dis_buf,
10296 nameXMMReg( gregOfRexRM(pfx,modrm) ));
10297 goto decode_success;
10298 }
10299 }
10300
10301 /* 66 0F 17 = MOVHPD -- move from high half of XMM to mem. */
10302 /* Again, this seems identical to MOVHPS. */
10303 if (have66noF2noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x17) {
10304 if (!epartIsReg(insn[2])) {
10305 delta += 2;
10306 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
10307 delta += alen;
10308 storeLE( mkexpr(addr),
10309 getXMMRegLane64( gregOfRexRM(pfx,insn[2]),
10310 1/*upper lane*/ ) );
10311 DIP("movhpd %s,%s\n", nameXMMReg( gregOfRexRM(pfx,insn[2]) ),
10312 dis_buf);
10313 goto decode_success;
10314 }
10315 /* else fall through */
10316 }
sewardj1001dc42005-02-21 08:25:55 +000010317
10318 /* 66 0F 12 = MOVLPD -- move from mem to low half of XMM. */
10319 /* Identical to MOVLPS ? */
10320 if (have66noF2noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x12) {
10321 modrm = getUChar(delta+2);
10322 if (epartIsReg(modrm)) {
10323 /* fall through; apparently reg-reg is not possible */
10324 } else {
10325 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10326 delta += 2+alen;
10327 putXMMRegLane64( gregOfRexRM(pfx,modrm),
10328 0/*lower lane*/,
10329 loadLE(Ity_I64, mkexpr(addr)) );
10330 DIP("movlpd %s, %s\n",
10331 dis_buf, nameXMMReg( gregOfRexRM(pfx,modrm) ));
10332 goto decode_success;
10333 }
10334 }
10335
sewardj4c328cf2005-05-05 12:05:54 +000010336 /* 66 0F 13 = MOVLPD -- move from low half of XMM to mem. */
10337 /* Identical to MOVLPS ? */
10338 if (have66noF2noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x13) {
10339 modrm = getUChar(delta+2);
10340 if (!epartIsReg(modrm)) {
10341 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10342 delta += 2+alen;
10343 storeLE( mkexpr(addr),
10344 getXMMRegLane64( gregOfRexRM(pfx,modrm),
10345 0/*lower lane*/ ) );
10346 DIP("movlpd %s, %s\n", nameXMMReg( gregOfRexRM(pfx,modrm) ),
10347 dis_buf);
10348 goto decode_success;
10349 }
10350 /* else fall through */
10351 }
10352
sewardj612be432005-05-11 02:55:54 +000010353 /* 66 0F 50 = MOVMSKPD - move 2 sign bits from 2 x F64 in xmm(E) to
10354 2 lowest bits of ireg(G) */
sewardjae84d782006-04-13 22:06:35 +000010355 if (have66noF2noF3(pfx) && (sz == 2 || sz == 8)
sewardj612be432005-05-11 02:55:54 +000010356 && insn[0] == 0x0F && insn[1] == 0x50) {
sewardjae84d782006-04-13 22:06:35 +000010357 /* sz == 8 is a kludge to handle insns with REX.W redundantly
10358 set to 1, which has been known to happen:
10359 66 4c 0f 50 d9 rex64X movmskpd %xmm1,%r11d
10360 */
sewardj612be432005-05-11 02:55:54 +000010361 modrm = getUChar(delta+2);
10362 if (epartIsReg(modrm)) {
10363 Int src;
10364 t0 = newTemp(Ity_I32);
10365 t1 = newTemp(Ity_I32);
10366 delta += 2+1;
10367 src = eregOfRexRM(pfx,modrm);
10368 assign( t0, binop( Iop_And32,
10369 binop(Iop_Shr32, getXMMRegLane32(src,1), mkU8(31)),
10370 mkU32(1) ));
10371 assign( t1, binop( Iop_And32,
10372 binop(Iop_Shr32, getXMMRegLane32(src,3), mkU8(30)),
10373 mkU32(2) ));
10374 putIReg32( gregOfRexRM(pfx,modrm),
10375 binop(Iop_Or32, mkexpr(t0), mkexpr(t1))
10376 );
10377 DIP("movmskpd %s,%s\n", nameXMMReg(src),
10378 nameIReg32(gregOfRexRM(pfx,modrm)));
10379 goto decode_success;
10380 }
10381 /* else fall through */
10382 goto decode_failure;
10383 }
10384
10385 /* 66 0F E7 = MOVNTDQ -- for us, just a plain SSE store. */
10386 if (have66noF2noF3(pfx) && sz == 2
10387 && insn[0] == 0x0F && insn[1] == 0xE7) {
10388 modrm = getUChar(delta+2);
10389 if (!epartIsReg(modrm)) {
10390 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10391 storeLE( mkexpr(addr), getXMMReg(gregOfRexRM(pfx,modrm)) );
10392 DIP("movntdq %s,%s\n", dis_buf,
10393 nameXMMReg(gregOfRexRM(pfx,modrm)));
10394 delta += 2+alen;
10395 goto decode_success;
10396 }
10397 /* else fall through */
10398 goto decode_failure;
10399 }
sewardjf53b7352005-04-06 20:01:56 +000010400
10401 /* 0F C3 = MOVNTI -- for us, just a plain ireg store. */
10402 if (haveNo66noF2noF3(pfx) &&
10403 insn[0] == 0x0F && insn[1] == 0xC3) {
10404 vassert(sz == 4 || sz == 8);
10405 modrm = getUChar(delta+2);
10406 if (!epartIsReg(modrm)) {
10407 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10408 storeLE( mkexpr(addr), getIRegG(sz, pfx, modrm) );
10409 DIP("movnti %s,%s\n", dis_buf,
10410 nameIRegG(sz, pfx, modrm));
10411 delta += 2+alen;
10412 goto decode_success;
10413 }
10414 /* else fall through */
10415 }
sewardj5cc00ff2005-03-27 04:48:32 +000010416
10417 /* 66 0F D6 = MOVQ -- move 64 bits from G (lo half xmm) to E (mem
10418 or lo half xmm). */
10419 if (have66noF2noF3(pfx) && insn[0] == 0x0F && insn[1] == 0xD6) {
10420 vassert(sz == 2);
10421 modrm = getUChar(delta+2);
10422 if (epartIsReg(modrm)) {
10423 /* fall through, awaiting test case */
sewardj94a48b22005-05-14 11:17:25 +000010424 /* dst: lo half copied, hi half zeroed */
sewardj5cc00ff2005-03-27 04:48:32 +000010425 } else {
10426 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10427 storeLE( mkexpr(addr),
10428 getXMMRegLane64( gregOfRexRM(pfx,modrm), 0 ));
10429 DIP("movq %s,%s\n", nameXMMReg(gregOfRexRM(pfx,modrm)), dis_buf );
10430 delta += 2+alen;
10431 goto decode_success;
10432 }
10433 }
10434
sewardj612be432005-05-11 02:55:54 +000010435 /* F3 0F D6 = MOVQ2DQ -- move from E (mmx) to G (lo half xmm, zero
10436 hi half). */
10437 if (haveF3no66noF2(pfx) && sz == 4
10438 && insn[0] == 0x0F && insn[1] == 0xD6) {
10439 modrm = getUChar(delta+2);
10440 if (epartIsReg(modrm)) {
10441 do_MMX_preamble();
10442 putXMMReg( gregOfRexRM(pfx,modrm),
10443 unop(Iop_64UtoV128, getMMXReg( eregLO3ofRM(modrm) )) );
10444 DIP("movq2dq %s,%s\n", nameMMXReg(eregLO3ofRM(modrm)),
10445 nameXMMReg(gregOfRexRM(pfx,modrm)));
10446 delta += 2+1;
10447 goto decode_success;
10448 } else {
10449 /* apparently no mem case for this insn */
10450 goto decode_failure;
10451 }
10452 }
10453
10454 /* F3 0F 7E = MOVQ -- move 64 bits from E (mem or lo half xmm) to
sewardj94a48b22005-05-14 11:17:25 +000010455 G (lo half xmm). Upper half of G is zeroed out. */
sewardj1001dc42005-02-21 08:25:55 +000010456 /* F2 0F 10 = MOVSD -- move 64 bits from E (mem or lo half xmm) to
10457 G (lo half xmm). If E is mem, upper half of G is zeroed out.
sewardj94a48b22005-05-14 11:17:25 +000010458 If E is reg, upper half of G is unchanged. */
sewardj612be432005-05-11 02:55:54 +000010459 if ( (haveF2no66noF3(pfx) && sz == 4
10460 && insn[0] == 0x0F && insn[1] == 0x10)
sewardj5cc00ff2005-03-27 04:48:32 +000010461 ||
sewardj612be432005-05-11 02:55:54 +000010462 (haveF3no66noF2(pfx) && sz == 4
10463 && insn[0] == 0x0F && insn[1] == 0x7E)
sewardj1001dc42005-02-21 08:25:55 +000010464 ) {
sewardj1001dc42005-02-21 08:25:55 +000010465 modrm = getUChar(delta+2);
10466 if (epartIsReg(modrm)) {
10467 putXMMRegLane64( gregOfRexRM(pfx,modrm), 0,
10468 getXMMRegLane64( eregOfRexRM(pfx,modrm), 0 ));
sewardj94a48b22005-05-14 11:17:25 +000010469 if (insn[1] == 0x7E/*MOVQ*/) {
10470 /* zero bits 127:64 */
10471 putXMMRegLane64( gregOfRexRM(pfx,modrm), 1, mkU64(0) );
10472 }
sewardj1001dc42005-02-21 08:25:55 +000010473 DIP("movsd %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
10474 nameXMMReg(gregOfRexRM(pfx,modrm)));
10475 delta += 2+1;
10476 } else {
10477 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10478 putXMMReg( gregOfRexRM(pfx,modrm), mkV128(0) );
10479 putXMMRegLane64( gregOfRexRM(pfx,modrm), 0,
10480 loadLE(Ity_I64, mkexpr(addr)) );
10481 DIP("movsd %s,%s\n", dis_buf,
10482 nameXMMReg(gregOfRexRM(pfx,modrm)));
10483 delta += 2+alen;
10484 }
10485 goto decode_success;
10486 }
10487
10488 /* F2 0F 11 = MOVSD -- move 64 bits from G (lo half xmm) to E (mem
10489 or lo half xmm). */
sewardj8d965312005-02-25 02:48:47 +000010490 if (haveF2no66noF3(pfx) && sz == 4
10491 && insn[0] == 0x0F && insn[1] == 0x11) {
sewardj1001dc42005-02-21 08:25:55 +000010492 modrm = getUChar(delta+2);
10493 if (epartIsReg(modrm)) {
10494 /* fall through, we don't yet have a test case */
10495 } else {
10496 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10497 storeLE( mkexpr(addr),
10498 getXMMRegLane64(gregOfRexRM(pfx,modrm), 0) );
10499 DIP("movsd %s,%s\n", nameXMMReg(gregOfRexRM(pfx,modrm)),
10500 dis_buf);
10501 delta += 2+alen;
10502 goto decode_success;
10503 }
10504 }
10505
sewardj4c328cf2005-05-05 12:05:54 +000010506 /* 66 0F 59 = MULPD -- mul 64Fx2 from R/M to R */
10507 if (have66noF2noF3(pfx) && sz == 2
10508 && insn[0] == 0x0F && insn[1] == 0x59) {
10509 delta = dis_SSE_E_to_G_all( pfx, delta+2, "mulpd", Iop_Mul64Fx2 );
10510 goto decode_success;
10511 }
sewardj1001dc42005-02-21 08:25:55 +000010512
10513 /* F2 0F 59 = MULSD -- mul 64F0x2 from R/M to R */
sewardj8d965312005-02-25 02:48:47 +000010514 if (haveF2no66noF3(pfx) && sz == 4
10515 && insn[0] == 0x0F && insn[1] == 0x59) {
sewardj1001dc42005-02-21 08:25:55 +000010516 delta = dis_SSE_E_to_G_lo64( pfx, delta+2, "mulsd", Iop_Mul64F0x2 );
10517 goto decode_success;
10518 }
10519
sewardj8d965312005-02-25 02:48:47 +000010520 /* 66 0F 56 = ORPD -- G = G and E */
10521 if (have66noF2noF3(pfx) && sz == 2
10522 && insn[0] == 0x0F && insn[1] == 0x56) {
10523 delta = dis_SSE_E_to_G_all( pfx, delta+2, "orpd", Iop_OrV128 );
10524 goto decode_success;
10525 }
10526
sewardj09717342005-05-05 21:34:02 +000010527 /* 66 0F C6 /r ib = SHUFPD -- shuffle packed F64s */
10528 if (have66noF2noF3(pfx) && sz == 2
10529 && insn[0] == 0x0F && insn[1] == 0xC6) {
10530 Int select;
10531 IRTemp sV = newTemp(Ity_V128);
10532 IRTemp dV = newTemp(Ity_V128);
10533 IRTemp s1 = newTemp(Ity_I64);
10534 IRTemp s0 = newTemp(Ity_I64);
10535 IRTemp d1 = newTemp(Ity_I64);
10536 IRTemp d0 = newTemp(Ity_I64);
10537
10538 modrm = insn[2];
10539 assign( dV, getXMMReg(gregOfRexRM(pfx,modrm)) );
10540
10541 if (epartIsReg(modrm)) {
10542 assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
10543 select = (Int)insn[3];
10544 delta += 2+2;
10545 DIP("shufpd $%d,%s,%s\n", select,
10546 nameXMMReg(eregOfRexRM(pfx,modrm)),
10547 nameXMMReg(gregOfRexRM(pfx,modrm)));
10548 } else {
10549 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 1 );
10550 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
10551 select = (Int)insn[2+alen];
10552 delta += 3+alen;
10553 DIP("shufpd $%d,%s,%s\n", select,
10554 dis_buf,
10555 nameXMMReg(gregOfRexRM(pfx,modrm)));
10556 }
10557
10558 assign( d1, unop(Iop_V128HIto64, mkexpr(dV)) );
10559 assign( d0, unop(Iop_V128to64, mkexpr(dV)) );
10560 assign( s1, unop(Iop_V128HIto64, mkexpr(sV)) );
10561 assign( s0, unop(Iop_V128to64, mkexpr(sV)) );
10562
10563# define SELD(n) mkexpr((n)==0 ? d0 : d1)
10564# define SELS(n) mkexpr((n)==0 ? s0 : s1)
10565
10566 putXMMReg(
10567 gregOfRexRM(pfx,modrm),
10568 binop(Iop_64HLtoV128, SELS((select>>1)&1), SELD((select>>0)&1) )
10569 );
10570
10571# undef SELD
10572# undef SELS
10573
10574 goto decode_success;
10575 }
10576
sewardj97628592005-05-10 22:42:54 +000010577 /* 66 0F 51 = SQRTPD -- approx sqrt 64Fx2 from R/M to R */
10578 if (have66noF2noF3(pfx) && sz == 2
10579 && insn[0] == 0x0F && insn[1] == 0x51) {
10580 delta = dis_SSE_E_to_G_unary_all( pfx, delta+2,
10581 "sqrtpd", Iop_Sqrt64Fx2 );
10582 goto decode_success;
10583 }
sewardj1001dc42005-02-21 08:25:55 +000010584
10585 /* F2 0F 51 = SQRTSD -- approx sqrt 64F0x2 from R/M to R */
10586 if (haveF2no66noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x51) {
10587 vassert(sz == 4);
10588 delta = dis_SSE_E_to_G_unary_lo64( pfx, delta+2,
10589 "sqrtsd", Iop_Sqrt64F0x2 );
10590 goto decode_success;
10591 }
10592
sewardj4c328cf2005-05-05 12:05:54 +000010593 /* 66 0F 5C = SUBPD -- sub 64Fx2 from R/M to R */
10594 if (have66noF2noF3(pfx) && sz == 2
10595 && insn[0] == 0x0F && insn[1] == 0x5C) {
10596 delta = dis_SSE_E_to_G_all( pfx, delta+2, "subpd", Iop_Sub64Fx2 );
10597 goto decode_success;
10598 }
sewardj1001dc42005-02-21 08:25:55 +000010599
10600 /* F2 0F 5C = SUBSD -- sub 64F0x2 from R/M to R */
10601 if (haveF2no66noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x5C) {
10602 vassert(sz == 4);
10603 delta = dis_SSE_E_to_G_lo64( pfx, delta+2, "subsd", Iop_Sub64F0x2 );
10604 goto decode_success;
10605 }
10606
sewardj1a01e652005-02-23 11:39:21 +000010607 /* 66 0F 15 = UNPCKHPD -- unpack and interleave high part F64s */
10608 /* 66 0F 14 = UNPCKLPD -- unpack and interleave low part F64s */
10609 /* These just appear to be special cases of SHUFPS */
10610 if (have66noF2noF3(pfx)
10611 && sz == 2 /* could be 8 if rex also present */
10612 && insn[0] == 0x0F && (insn[1] == 0x15 || insn[1] == 0x14)) {
10613 IRTemp s1 = newTemp(Ity_I64);
10614 IRTemp s0 = newTemp(Ity_I64);
10615 IRTemp d1 = newTemp(Ity_I64);
10616 IRTemp d0 = newTemp(Ity_I64);
10617 IRTemp sV = newTemp(Ity_V128);
10618 IRTemp dV = newTemp(Ity_V128);
sewardj1027dc22005-02-26 01:55:02 +000010619 Bool hi = toBool(insn[1] == 0x15);
sewardj1a01e652005-02-23 11:39:21 +000010620
10621 modrm = insn[2];
10622 assign( dV, getXMMReg(gregOfRexRM(pfx,modrm)) );
10623
10624 if (epartIsReg(modrm)) {
10625 assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
10626 delta += 2+1;
10627 DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
10628 nameXMMReg(eregOfRexRM(pfx,modrm)),
10629 nameXMMReg(gregOfRexRM(pfx,modrm)));
10630 } else {
10631 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10632 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
10633 delta += 2+alen;
10634 DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
10635 dis_buf,
10636 nameXMMReg(gregOfRexRM(pfx,modrm)));
10637 }
10638
10639 assign( d1, unop(Iop_V128HIto64, mkexpr(dV)) );
10640 assign( d0, unop(Iop_V128to64, mkexpr(dV)) );
10641 assign( s1, unop(Iop_V128HIto64, mkexpr(sV)) );
10642 assign( s0, unop(Iop_V128to64, mkexpr(sV)) );
10643
10644 if (hi) {
10645 putXMMReg( gregOfRexRM(pfx,modrm),
10646 binop(Iop_64HLtoV128, mkexpr(s1), mkexpr(d1)) );
10647 } else {
10648 putXMMReg( gregOfRexRM(pfx,modrm),
10649 binop(Iop_64HLtoV128, mkexpr(s0), mkexpr(d0)) );
10650 }
10651
10652 goto decode_success;
10653 }
sewardj9da16972005-02-21 13:58:26 +000010654
10655 /* 66 0F 57 = XORPD -- G = G xor E */
sewardj97628592005-05-10 22:42:54 +000010656 if (have66noF2noF3(pfx) && sz == 2
10657 && insn[0] == 0x0F && insn[1] == 0x57) {
sewardj9da16972005-02-21 13:58:26 +000010658 delta = dis_SSE_E_to_G_all( pfx, delta+2, "xorpd", Iop_XorV128 );
10659 goto decode_success;
10660 }
10661
sewardj97628592005-05-10 22:42:54 +000010662 /* 66 0F 6B = PACKSSDW */
10663 if (have66noF2noF3(pfx) && sz == 2
10664 && insn[0] == 0x0F && insn[1] == 0x6B) {
10665 delta = dis_SSEint_E_to_G( pfx, delta+2,
10666 "packssdw", Iop_QNarrow32Sx4, True );
10667 goto decode_success;
10668 }
10669
10670 /* 66 0F 63 = PACKSSWB */
10671 if (have66noF2noF3(pfx) && sz == 2
10672 && insn[0] == 0x0F && insn[1] == 0x63) {
10673 delta = dis_SSEint_E_to_G( pfx, delta+2,
10674 "packsswb", Iop_QNarrow16Sx8, True );
10675 goto decode_success;
10676 }
10677
10678 /* 66 0F 67 = PACKUSWB */
10679 if (have66noF2noF3(pfx) && sz == 2
10680 && insn[0] == 0x0F && insn[1] == 0x67) {
10681 delta = dis_SSEint_E_to_G( pfx, delta+2,
10682 "packuswb", Iop_QNarrow16Ux8, True );
10683 goto decode_success;
10684 }
10685
10686 /* 66 0F FC = PADDB */
10687 if (have66noF2noF3(pfx) && sz == 2
10688 && insn[0] == 0x0F && insn[1] == 0xFC) {
10689 delta = dis_SSEint_E_to_G( pfx, delta+2,
10690 "paddb", Iop_Add8x16, False );
10691 goto decode_success;
10692 }
10693
10694 /* 66 0F FE = PADDD */
10695 if (have66noF2noF3(pfx) && sz == 2
10696 && insn[0] == 0x0F && insn[1] == 0xFE) {
10697 delta = dis_SSEint_E_to_G( pfx, delta+2,
10698 "paddd", Iop_Add32x4, False );
10699 goto decode_success;
10700 }
sewardj8711f662005-05-09 17:52:56 +000010701
10702 /* ***--- this is an MMX class insn introduced in SSE2 ---*** */
10703 /* 0F D4 = PADDQ -- add 64x1 */
10704 if (haveNo66noF2noF3(pfx) && sz == 4
10705 && insn[0] == 0x0F && insn[1] == 0xD4) {
10706 do_MMX_preamble();
10707 delta = dis_MMXop_regmem_to_reg (
10708 pfx, delta+2, insn[1], "paddq", False );
10709 goto decode_success;
10710 }
sewardj09717342005-05-05 21:34:02 +000010711
10712 /* 66 0F D4 = PADDQ */
10713 if (have66noF2noF3(pfx) && sz == 2
10714 && insn[0] == 0x0F && insn[1] == 0xD4) {
10715 delta = dis_SSEint_E_to_G( pfx, delta+2,
10716 "paddq", Iop_Add64x2, False );
10717 goto decode_success;
10718 }
10719
sewardj5992bd02005-05-11 02:13:42 +000010720 /* 66 0F FD = PADDW */
10721 if (have66noF2noF3(pfx) && sz == 2
10722 && insn[0] == 0x0F && insn[1] == 0xFD) {
10723 delta = dis_SSEint_E_to_G( pfx, delta+2,
10724 "paddw", Iop_Add16x8, False );
10725 goto decode_success;
10726 }
10727
10728 /* 66 0F EC = PADDSB */
10729 if (have66noF2noF3(pfx) && sz == 2
10730 && insn[0] == 0x0F && insn[1] == 0xEC) {
10731 delta = dis_SSEint_E_to_G( pfx, delta+2,
10732 "paddsb", Iop_QAdd8Sx16, False );
10733 goto decode_success;
10734 }
10735
10736 /* 66 0F ED = PADDSW */
10737 if (have66noF2noF3(pfx) && sz == 2
10738 && insn[0] == 0x0F && insn[1] == 0xED) {
10739 delta = dis_SSEint_E_to_G( pfx, delta+2,
10740 "paddsw", Iop_QAdd16Sx8, False );
10741 goto decode_success;
10742 }
10743
10744 /* 66 0F DC = PADDUSB */
10745 if (have66noF2noF3(pfx) && sz == 2
10746 && insn[0] == 0x0F && insn[1] == 0xDC) {
10747 delta = dis_SSEint_E_to_G( pfx, delta+2,
10748 "paddusb", Iop_QAdd8Ux16, False );
10749 goto decode_success;
10750 }
10751
10752 /* 66 0F DD = PADDUSW */
10753 if (have66noF2noF3(pfx) && sz == 2
10754 && insn[0] == 0x0F && insn[1] == 0xDD) {
10755 delta = dis_SSEint_E_to_G( pfx, delta+2,
10756 "paddusw", Iop_QAdd16Ux8, False );
10757 goto decode_success;
10758 }
sewardj09717342005-05-05 21:34:02 +000010759
10760 /* 66 0F DB = PAND */
10761 if (have66noF2noF3(pfx) && sz == 2
10762 && insn[0] == 0x0F && insn[1] == 0xDB) {
10763 delta = dis_SSE_E_to_G_all( pfx, delta+2, "pand", Iop_AndV128 );
10764 goto decode_success;
10765 }
10766
sewardj5992bd02005-05-11 02:13:42 +000010767 /* 66 0F DF = PANDN */
10768 if (have66noF2noF3(pfx) && sz == 2
10769 && insn[0] == 0x0F && insn[1] == 0xDF) {
10770 delta = dis_SSE_E_to_G_all_invG( pfx, delta+2, "pandn", Iop_AndV128 );
10771 goto decode_success;
10772 }
10773
10774 /* 66 0F E0 = PAVGB */
10775 if (have66noF2noF3(pfx) && sz == 2
10776 && insn[0] == 0x0F && insn[1] == 0xE0) {
10777 delta = dis_SSEint_E_to_G( pfx, delta+2,
10778 "pavgb", Iop_Avg8Ux16, False );
10779 goto decode_success;
10780 }
10781
10782 /* 66 0F E3 = PAVGW */
10783 if (have66noF2noF3(pfx) && sz == 2
10784 && insn[0] == 0x0F && insn[1] == 0xE3) {
10785 delta = dis_SSEint_E_to_G( pfx, delta+2,
10786 "pavgw", Iop_Avg16Ux8, False );
10787 goto decode_success;
10788 }
10789
10790 /* 66 0F 74 = PCMPEQB */
10791 if (have66noF2noF3(pfx) && sz == 2
10792 && insn[0] == 0x0F && insn[1] == 0x74) {
10793 delta = dis_SSEint_E_to_G( pfx, delta+2,
10794 "pcmpeqb", Iop_CmpEQ8x16, False );
10795 goto decode_success;
10796 }
10797
10798 /* 66 0F 76 = PCMPEQD */
10799 if (have66noF2noF3(pfx) && sz == 2
10800 && insn[0] == 0x0F && insn[1] == 0x76) {
10801 delta = dis_SSEint_E_to_G( pfx, delta+2,
10802 "pcmpeqd", Iop_CmpEQ32x4, False );
10803 goto decode_success;
10804 }
10805
10806 /* 66 0F 75 = PCMPEQW */
10807 if (have66noF2noF3(pfx) && sz == 2
10808 && insn[0] == 0x0F && insn[1] == 0x75) {
10809 delta = dis_SSEint_E_to_G( pfx, delta+2,
10810 "pcmpeqw", Iop_CmpEQ16x8, False );
10811 goto decode_success;
10812 }
10813
10814 /* 66 0F 64 = PCMPGTB */
10815 if (have66noF2noF3(pfx) && sz == 2
10816 && insn[0] == 0x0F && insn[1] == 0x64) {
10817 delta = dis_SSEint_E_to_G( pfx, delta+2,
10818 "pcmpgtb", Iop_CmpGT8Sx16, False );
10819 goto decode_success;
10820 }
10821
10822 /* 66 0F 66 = PCMPGTD */
10823 if (have66noF2noF3(pfx) && sz == 2
10824 && insn[0] == 0x0F && insn[1] == 0x66) {
10825 delta = dis_SSEint_E_to_G( pfx, delta+2,
10826 "pcmpgtd", Iop_CmpGT32Sx4, False );
10827 goto decode_success;
10828 }
10829
10830 /* 66 0F 65 = PCMPGTW */
10831 if (have66noF2noF3(pfx) && sz == 2
10832 && insn[0] == 0x0F && insn[1] == 0x65) {
10833 delta = dis_SSEint_E_to_G( pfx, delta+2,
10834 "pcmpgtw", Iop_CmpGT16Sx8, False );
10835 goto decode_success;
10836 }
sewardj97628592005-05-10 22:42:54 +000010837
10838 /* 66 0F C5 = PEXTRW -- extract 16-bit field from xmm(E) and put
10839 zero-extend of it in ireg(G). */
10840 if (have66noF2noF3(pfx) && sz == 2
10841 && insn[0] == 0x0F && insn[1] == 0xC5) {
10842 modrm = insn[2];
10843 if (epartIsReg(modrm)) {
10844 t5 = newTemp(Ity_V128);
10845 t4 = newTemp(Ity_I16);
10846 assign(t5, getXMMReg(eregOfRexRM(pfx,modrm)));
10847 breakup128to32s( t5, &t3, &t2, &t1, &t0 );
10848 switch (insn[3] & 7) {
10849 case 0: assign(t4, unop(Iop_32to16, mkexpr(t0))); break;
10850 case 1: assign(t4, unop(Iop_32HIto16, mkexpr(t0))); break;
10851 case 2: assign(t4, unop(Iop_32to16, mkexpr(t1))); break;
10852 case 3: assign(t4, unop(Iop_32HIto16, mkexpr(t1))); break;
10853 case 4: assign(t4, unop(Iop_32to16, mkexpr(t2))); break;
10854 case 5: assign(t4, unop(Iop_32HIto16, mkexpr(t2))); break;
10855 case 6: assign(t4, unop(Iop_32to16, mkexpr(t3))); break;
10856 case 7: assign(t4, unop(Iop_32HIto16, mkexpr(t3))); break;
10857 default: vassert(0);
10858 }
10859 putIReg32(gregOfRexRM(pfx,modrm), unop(Iop_16Uto32, mkexpr(t4)));
10860 DIP("pextrw $%d,%s,%s\n",
10861 (Int)insn[3], nameXMMReg(eregOfRexRM(pfx,modrm)),
10862 nameIReg32(gregOfRexRM(pfx,modrm)));
10863 delta += 4;
10864 goto decode_success;
10865 }
10866 /* else fall through */
10867 /* note, if memory case is ever filled in, there is 1 byte after
10868 amode */
10869 }
10870
10871 /* 66 0F C4 = PINSRW -- get 16 bits from E(mem or low half ireg) and
10872 put it into the specified lane of xmm(G). */
10873 if (have66noF2noF3(pfx) && sz == 2
10874 && insn[0] == 0x0F && insn[1] == 0xC4) {
10875 Int lane;
10876 t4 = newTemp(Ity_I16);
10877 modrm = insn[2];
10878
10879 if (epartIsReg(modrm)) {
10880 assign(t4, getIReg16(eregOfRexRM(pfx,modrm)));
10881 delta += 3+1;
10882 lane = insn[3+1-1];
10883 DIP("pinsrw $%d,%s,%s\n", (Int)lane,
10884 nameIReg16(eregOfRexRM(pfx,modrm)),
10885 nameXMMReg(gregOfRexRM(pfx,modrm)));
10886 } else {
10887 addr = disAMode ( &alen, pfx, delta+2, dis_buf,
10888 1/*byte after the amode*/ );
10889 delta += 3+alen;
10890 lane = insn[3+alen-1];
10891 assign(t4, loadLE(Ity_I16, mkexpr(addr)));
10892 DIP("pinsrw $%d,%s,%s\n", (Int)lane,
10893 dis_buf,
10894 nameXMMReg(gregOfRexRM(pfx,modrm)));
10895 }
10896
10897 putXMMRegLane16( gregOfRexRM(pfx,modrm), lane & 7, mkexpr(t4) );
10898 goto decode_success;
10899 }
10900
sewardjdb859032006-04-08 16:15:53 +000010901 /* 66 0F F5 = PMADDWD -- Multiply and add packed integers from
10902 E(xmm or mem) to G(xmm) */
10903 if (have66noF2noF3(pfx) && sz == 2
10904 && insn[0] == 0x0F && insn[1] == 0xF5) {
10905 IRTemp s1V = newTemp(Ity_V128);
10906 IRTemp s2V = newTemp(Ity_V128);
10907 IRTemp dV = newTemp(Ity_V128);
10908 IRTemp s1Hi = newTemp(Ity_I64);
10909 IRTemp s1Lo = newTemp(Ity_I64);
10910 IRTemp s2Hi = newTemp(Ity_I64);
10911 IRTemp s2Lo = newTemp(Ity_I64);
10912 IRTemp dHi = newTemp(Ity_I64);
10913 IRTemp dLo = newTemp(Ity_I64);
10914 modrm = insn[2];
10915 if (epartIsReg(modrm)) {
10916 assign( s1V, getXMMReg(eregOfRexRM(pfx,modrm)) );
10917 delta += 2+1;
10918 DIP("pmaddwd %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
10919 nameXMMReg(gregOfRexRM(pfx,modrm)));
10920 } else {
10921 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10922 assign( s1V, loadLE(Ity_V128, mkexpr(addr)) );
10923 delta += 2+alen;
10924 DIP("pmaddwd %s,%s\n", dis_buf,
10925 nameXMMReg(gregOfRexRM(pfx,modrm)));
10926 }
10927 assign( s2V, getXMMReg(gregOfRexRM(pfx,modrm)) );
10928 assign( s1Hi, unop(Iop_V128HIto64, mkexpr(s1V)) );
10929 assign( s1Lo, unop(Iop_V128to64, mkexpr(s1V)) );
10930 assign( s2Hi, unop(Iop_V128HIto64, mkexpr(s2V)) );
10931 assign( s2Lo, unop(Iop_V128to64, mkexpr(s2V)) );
10932 assign( dHi, mkIRExprCCall(
10933 Ity_I64, 0/*regparms*/,
10934 "amd64g_calculate_mmx_pmaddwd",
10935 &amd64g_calculate_mmx_pmaddwd,
10936 mkIRExprVec_2( mkexpr(s1Hi), mkexpr(s2Hi))
10937 ));
10938 assign( dLo, mkIRExprCCall(
10939 Ity_I64, 0/*regparms*/,
10940 "amd64g_calculate_mmx_pmaddwd",
10941 &amd64g_calculate_mmx_pmaddwd,
10942 mkIRExprVec_2( mkexpr(s1Lo), mkexpr(s2Lo))
10943 ));
10944 assign( dV, binop(Iop_64HLtoV128, mkexpr(dHi), mkexpr(dLo))) ;
10945 putXMMReg(gregOfRexRM(pfx,modrm), mkexpr(dV));
10946 goto decode_success;
10947 }
10948
sewardjadffcef2005-05-11 00:03:06 +000010949 /* 66 0F EE = PMAXSW -- 16x8 signed max */
10950 if (have66noF2noF3(pfx) && sz == 2
10951 && insn[0] == 0x0F && insn[1] == 0xEE) {
10952 delta = dis_SSEint_E_to_G( pfx, delta+2,
10953 "pmaxsw", Iop_Max16Sx8, False );
10954 goto decode_success;
10955 }
10956
10957 /* 66 0F DE = PMAXUB -- 8x16 unsigned max */
10958 if (have66noF2noF3(pfx) && sz == 2
10959 && insn[0] == 0x0F && insn[1] == 0xDE) {
10960 delta = dis_SSEint_E_to_G( pfx, delta+2,
10961 "pmaxub", Iop_Max8Ux16, False );
10962 goto decode_success;
10963 }
10964
10965 /* 66 0F EA = PMINSW -- 16x8 signed min */
10966 if (have66noF2noF3(pfx) && sz == 2
10967 && insn[0] == 0x0F && insn[1] == 0xEA) {
10968 delta = dis_SSEint_E_to_G( pfx, delta+2,
10969 "pminsw", Iop_Min16Sx8, False );
10970 goto decode_success;
10971 }
10972
10973 /* 66 0F DA = PMINUB -- 8x16 unsigned min */
10974 if (have66noF2noF3(pfx) && sz == 2
10975 && insn[0] == 0x0F && insn[1] == 0xDA) {
10976 delta = dis_SSEint_E_to_G( pfx, delta+2,
10977 "pminub", Iop_Min8Ux16, False );
10978 goto decode_success;
10979 }
10980
10981 /* 66 0F D7 = PMOVMSKB -- extract sign bits from each of 16 lanes in
10982 xmm(E), turn them into a byte, and put zero-extend of it in
10983 ireg(G). Doing this directly is just too cumbersome; give up
10984 therefore and call a helper. */
10985 /* UInt x86g_calculate_sse_pmovmskb ( ULong w64hi, ULong w64lo ); */
10986 if (have66noF2noF3(pfx) && sz == 2
10987 && insn[0] == 0x0F && insn[1] == 0xD7) {
10988 modrm = insn[2];
10989 if (epartIsReg(modrm)) {
10990 t0 = newTemp(Ity_I64);
10991 t1 = newTemp(Ity_I64);
10992 assign(t0, getXMMRegLane64(eregOfRexRM(pfx,modrm), 0));
10993 assign(t1, getXMMRegLane64(eregOfRexRM(pfx,modrm), 1));
10994 t5 = newTemp(Ity_I64);
10995 assign(t5, mkIRExprCCall(
10996 Ity_I64, 0/*regparms*/,
10997 "amd64g_calculate_sse_pmovmskb",
10998 &amd64g_calculate_sse_pmovmskb,
10999 mkIRExprVec_2( mkexpr(t1), mkexpr(t0) )));
11000 putIReg32(gregOfRexRM(pfx,modrm), unop(Iop_64to32,mkexpr(t5)));
11001 DIP("pmovmskb %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
11002 nameIReg32(gregOfRexRM(pfx,modrm)));
11003 delta += 3;
11004 goto decode_success;
11005 }
11006 /* else fall through */
11007 }
11008
11009 /* 66 0F E4 = PMULHUW -- 16x8 hi-half of unsigned widening multiply */
11010 if (have66noF2noF3(pfx) && sz == 2
11011 && insn[0] == 0x0F && insn[1] == 0xE4) {
11012 delta = dis_SSEint_E_to_G( pfx, delta+2,
11013 "pmulhuw", Iop_MulHi16Ux8, False );
11014 goto decode_success;
11015 }
11016
11017 /* 66 0F E5 = PMULHW -- 16x8 hi-half of signed widening multiply */
11018 if (have66noF2noF3(pfx) && sz == 2
11019 && insn[0] == 0x0F && insn[1] == 0xE5) {
11020 delta = dis_SSEint_E_to_G( pfx, delta+2,
11021 "pmulhw", Iop_MulHi16Sx8, False );
11022 goto decode_success;
11023 }
11024
11025 /* 66 0F D5 = PMULHL -- 16x8 multiply */
11026 if (have66noF2noF3(pfx) && sz == 2
11027 && insn[0] == 0x0F && insn[1] == 0xD5) {
11028 delta = dis_SSEint_E_to_G( pfx, delta+2,
11029 "pmullw", Iop_Mul16x8, False );
11030 goto decode_success;
11031 }
11032
11033 /* ***--- this is an MMX class insn introduced in SSE2 ---*** */
11034 /* 0F F4 = PMULUDQ -- unsigned widening multiply of 32-lanes 0 x
11035 0 to form 64-bit result */
11036 if (haveNo66noF2noF3(pfx) && sz == 4
11037 && insn[0] == 0x0F && insn[1] == 0xF4) {
11038 IRTemp sV = newTemp(Ity_I64);
11039 IRTemp dV = newTemp(Ity_I64);
11040 t1 = newTemp(Ity_I32);
11041 t0 = newTemp(Ity_I32);
11042 modrm = insn[2];
11043
11044 do_MMX_preamble();
11045 assign( dV, getMMXReg(gregLO3ofRM(modrm)) );
11046
11047 if (epartIsReg(modrm)) {
11048 assign( sV, getMMXReg(eregLO3ofRM(modrm)) );
11049 delta += 2+1;
11050 DIP("pmuludq %s,%s\n", nameMMXReg(eregLO3ofRM(modrm)),
11051 nameMMXReg(gregLO3ofRM(modrm)));
11052 } else {
11053 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
11054 assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
11055 delta += 2+alen;
11056 DIP("pmuludq %s,%s\n", dis_buf,
11057 nameMMXReg(gregLO3ofRM(modrm)));
11058 }
11059
11060 assign( t0, unop(Iop_64to32, mkexpr(dV)) );
11061 assign( t1, unop(Iop_64to32, mkexpr(sV)) );
11062 putMMXReg( gregLO3ofRM(modrm),
11063 binop( Iop_MullU32, mkexpr(t0), mkexpr(t1) ) );
11064 goto decode_success;
11065 }
11066
11067 /* 66 0F F4 = PMULUDQ -- unsigned widening multiply of 32-lanes 0 x
11068 0 to form lower 64-bit half and lanes 2 x 2 to form upper 64-bit
11069 half */
11070 /* This is a really poor translation -- could be improved if
11071 performance critical */
11072 if (have66noF2noF3(pfx) && sz == 2
11073 && insn[0] == 0x0F && insn[1] == 0xF4) {
11074 IRTemp sV, dV;
11075 IRTemp s3, s2, s1, s0, d3, d2, d1, d0;
11076 sV = newTemp(Ity_V128);
11077 dV = newTemp(Ity_V128);
11078 s3 = s2 = s1 = s0 = d3 = d2 = d1 = d0 = IRTemp_INVALID;
11079 t1 = newTemp(Ity_I64);
11080 t0 = newTemp(Ity_I64);
11081 modrm = insn[2];
11082 assign( dV, getXMMReg(gregOfRexRM(pfx,modrm)) );
11083
11084 if (epartIsReg(modrm)) {
11085 assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
11086 delta += 2+1;
11087 DIP("pmuludq %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
11088 nameXMMReg(gregOfRexRM(pfx,modrm)));
11089 } else {
11090 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
11091 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
11092 delta += 2+alen;
11093 DIP("pmuludq %s,%s\n", dis_buf,
11094 nameXMMReg(gregOfRexRM(pfx,modrm)));
11095 }
11096
11097 breakup128to32s( dV, &d3, &d2, &d1, &d0 );
11098 breakup128to32s( sV, &s3, &s2, &s1, &s0 );
11099
11100 assign( t0, binop( Iop_MullU32, mkexpr(d0), mkexpr(s0)) );
11101 putXMMRegLane64( gregOfRexRM(pfx,modrm), 0, mkexpr(t0) );
11102 assign( t1, binop( Iop_MullU32, mkexpr(d2), mkexpr(s2)) );
11103 putXMMRegLane64( gregOfRexRM(pfx,modrm), 1, mkexpr(t1) );
11104 goto decode_success;
11105 }
sewardj09717342005-05-05 21:34:02 +000011106
11107 /* 66 0F EB = POR */
11108 if (have66noF2noF3(pfx) && sz == 2
11109 && insn[0] == 0x0F && insn[1] == 0xEB) {
11110 delta = dis_SSE_E_to_G_all( pfx, delta+2, "por", Iop_OrV128 );
11111 goto decode_success;
11112 }
11113
sewardj59e96c12006-07-24 08:51:16 +000011114 /* 66 0F F6 = PSADBW -- 2 x (8x8 -> 48 zeroes ++ u16) Sum Abs Diffs
11115 from E(xmm or mem) to G(xmm) */
11116 if (have66noF2noF3(pfx) && sz == 2
11117 && insn[0] == 0x0F && insn[1] == 0xF6) {
11118 IRTemp s1V = newTemp(Ity_V128);
11119 IRTemp s2V = newTemp(Ity_V128);
11120 IRTemp dV = newTemp(Ity_V128);
11121 IRTemp s1Hi = newTemp(Ity_I64);
11122 IRTemp s1Lo = newTemp(Ity_I64);
11123 IRTemp s2Hi = newTemp(Ity_I64);
11124 IRTemp s2Lo = newTemp(Ity_I64);
11125 IRTemp dHi = newTemp(Ity_I64);
11126 IRTemp dLo = newTemp(Ity_I64);
11127 modrm = insn[2];
11128 if (epartIsReg(modrm)) {
11129 assign( s1V, getXMMReg(eregOfRexRM(pfx,modrm)) );
11130 delta += 2+1;
11131 DIP("psadbw %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
11132 nameXMMReg(gregOfRexRM(pfx,modrm)));
11133 } else {
11134 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
11135 assign( s1V, loadLE(Ity_V128, mkexpr(addr)) );
11136 delta += 2+alen;
11137 DIP("psadbw %s,%s\n", dis_buf,
11138 nameXMMReg(gregOfRexRM(pfx,modrm)));
11139 }
11140 assign( s2V, getXMMReg(gregOfRexRM(pfx,modrm)) );
11141 assign( s1Hi, unop(Iop_V128HIto64, mkexpr(s1V)) );
11142 assign( s1Lo, unop(Iop_V128to64, mkexpr(s1V)) );
11143 assign( s2Hi, unop(Iop_V128HIto64, mkexpr(s2V)) );
11144 assign( s2Lo, unop(Iop_V128to64, mkexpr(s2V)) );
11145 assign( dHi, mkIRExprCCall(
11146 Ity_I64, 0/*regparms*/,
11147 "amd64g_calculate_mmx_psadbw",
11148 &amd64g_calculate_mmx_psadbw,
11149 mkIRExprVec_2( mkexpr(s1Hi), mkexpr(s2Hi))
11150 ));
11151 assign( dLo, mkIRExprCCall(
11152 Ity_I64, 0/*regparms*/,
11153 "amd64g_calculate_mmx_psadbw",
11154 &amd64g_calculate_mmx_psadbw,
11155 mkIRExprVec_2( mkexpr(s1Lo), mkexpr(s2Lo))
11156 ));
11157 assign( dV, binop(Iop_64HLtoV128, mkexpr(dHi), mkexpr(dLo))) ;
11158 putXMMReg(gregOfRexRM(pfx,modrm), mkexpr(dV));
11159 goto decode_success;
11160 }
11161
sewardjadffcef2005-05-11 00:03:06 +000011162 /* 66 0F 70 = PSHUFD -- rearrange 4x32 from E(xmm or mem) to G(xmm) */
11163 if (have66noF2noF3(pfx) && sz == 2
11164 && insn[0] == 0x0F && insn[1] == 0x70) {
11165 Int order;
11166 IRTemp sV, dV, s3, s2, s1, s0;
11167 s3 = s2 = s1 = s0 = IRTemp_INVALID;
11168 sV = newTemp(Ity_V128);
11169 dV = newTemp(Ity_V128);
11170 modrm = insn[2];
11171 if (epartIsReg(modrm)) {
11172 assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
11173 order = (Int)insn[3];
11174 delta += 3+1;
11175 DIP("pshufd $%d,%s,%s\n", order,
11176 nameXMMReg(eregOfRexRM(pfx,modrm)),
11177 nameXMMReg(gregOfRexRM(pfx,modrm)));
11178 } else {
11179 addr = disAMode ( &alen, pfx, delta+2, dis_buf,
11180 1/*byte after the amode*/ );
11181 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
11182 order = (Int)insn[2+alen];
11183 delta += 2+alen+1;
11184 DIP("pshufd $%d,%s,%s\n", order,
11185 dis_buf,
11186 nameXMMReg(gregOfRexRM(pfx,modrm)));
11187 }
11188 breakup128to32s( sV, &s3, &s2, &s1, &s0 );
11189
11190# define SEL(n) \
11191 ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
11192 assign(dV,
11193 mk128from32s( SEL((order>>6)&3), SEL((order>>4)&3),
11194 SEL((order>>2)&3), SEL((order>>0)&3) )
11195 );
11196 putXMMReg(gregOfRexRM(pfx,modrm), mkexpr(dV));
11197# undef SEL
11198 goto decode_success;
11199 }
11200
11201 /* F3 0F 70 = PSHUFHW -- rearrange upper half 4x16 from E(xmm or
11202 mem) to G(xmm), and copy lower half */
11203 if (haveF3no66noF2(pfx) && sz == 4
11204 && insn[0] == 0x0F && insn[1] == 0x70) {
11205 Int order;
11206 IRTemp sVhi, dVhi, sV, dV, s3, s2, s1, s0;
11207 s3 = s2 = s1 = s0 = IRTemp_INVALID;
11208 sV = newTemp(Ity_V128);
11209 dV = newTemp(Ity_V128);
11210 sVhi = newTemp(Ity_I64);
11211 dVhi = newTemp(Ity_I64);
11212 modrm = insn[2];
11213 if (epartIsReg(modrm)) {
11214 assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
11215 order = (Int)insn[3];
11216 delta += 3+1;
11217 DIP("pshufhw $%d,%s,%s\n", order,
11218 nameXMMReg(eregOfRexRM(pfx,modrm)),
11219 nameXMMReg(gregOfRexRM(pfx,modrm)));
11220 } else {
11221 addr = disAMode ( &alen, pfx, delta+2, dis_buf,
11222 1/*byte after the amode*/ );
11223 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
11224 order = (Int)insn[2+alen];
11225 delta += 2+alen+1;
11226 DIP("pshufhw $%d,%s,%s\n", order,
11227 dis_buf,
11228 nameXMMReg(gregOfRexRM(pfx,modrm)));
11229 }
11230 assign( sVhi, unop(Iop_V128HIto64, mkexpr(sV)) );
11231 breakup64to16s( sVhi, &s3, &s2, &s1, &s0 );
11232
11233# define SEL(n) \
11234 ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
11235 assign(dVhi,
11236 mk64from16s( SEL((order>>6)&3), SEL((order>>4)&3),
11237 SEL((order>>2)&3), SEL((order>>0)&3) )
11238 );
11239 assign(dV, binop( Iop_64HLtoV128,
11240 mkexpr(dVhi),
11241 unop(Iop_V128to64, mkexpr(sV))) );
11242 putXMMReg(gregOfRexRM(pfx,modrm), mkexpr(dV));
11243# undef SEL
11244 goto decode_success;
11245 }
11246
11247 /* F2 0F 70 = PSHUFLW -- rearrange lower half 4x16 from E(xmm or
11248 mem) to G(xmm), and copy upper half */
11249 if (haveF2no66noF3(pfx) && sz == 4
11250 && insn[0] == 0x0F && insn[1] == 0x70) {
11251 Int order;
11252 IRTemp sVlo, dVlo, sV, dV, s3, s2, s1, s0;
11253 s3 = s2 = s1 = s0 = IRTemp_INVALID;
11254 sV = newTemp(Ity_V128);
11255 dV = newTemp(Ity_V128);
11256 sVlo = newTemp(Ity_I64);
11257 dVlo = newTemp(Ity_I64);
11258 modrm = insn[2];
11259 if (epartIsReg(modrm)) {
11260 assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
11261 order = (Int)insn[3];
11262 delta += 3+1;
11263 DIP("pshuflw $%d,%s,%s\n", order,
11264 nameXMMReg(eregOfRexRM(pfx,modrm)),
11265 nameXMMReg(gregOfRexRM(pfx,modrm)));
11266 } else {
11267 addr = disAMode ( &alen, pfx, delta+2, dis_buf,
11268 1/*byte after the amode*/ );
11269 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
11270 order = (Int)insn[2+alen];
11271 delta += 2+alen+1;
11272 DIP("pshuflw $%d,%s,%s\n", order,
11273 dis_buf,
11274 nameXMMReg(gregOfRexRM(pfx,modrm)));
11275 }
11276 assign( sVlo, unop(Iop_V128to64, mkexpr(sV)) );
11277 breakup64to16s( sVlo, &s3, &s2, &s1, &s0 );
11278
11279# define SEL(n) \
11280 ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
11281 assign(dVlo,
11282 mk64from16s( SEL((order>>6)&3), SEL((order>>4)&3),
11283 SEL((order>>2)&3), SEL((order>>0)&3) )
11284 );
11285 assign(dV, binop( Iop_64HLtoV128,
11286 unop(Iop_V128HIto64, mkexpr(sV)),
11287 mkexpr(dVlo) ) );
11288 putXMMReg(gregOfRexRM(pfx,modrm), mkexpr(dV));
11289# undef SEL
11290 goto decode_success;
11291 }
11292
11293 /* 66 0F 72 /6 ib = PSLLD by immediate */
11294 if (have66noF2noF3(pfx) && sz == 2
11295 && insn[0] == 0x0F && insn[1] == 0x72
11296 && epartIsReg(insn[2])
11297 && gregLO3ofRM(insn[2]) == 6) {
11298 delta = dis_SSE_shiftE_imm( pfx, delta+2, "pslld", Iop_ShlN32x4 );
11299 goto decode_success;
11300 }
11301
11302 /* 66 0F F2 = PSLLD by E */
11303 if (have66noF2noF3(pfx) && sz == 2
11304 && insn[0] == 0x0F && insn[1] == 0xF2) {
11305 delta = dis_SSE_shiftG_byE( pfx, delta+2, "pslld", Iop_ShlN32x4 );
11306 goto decode_success;
11307 }
sewardj97628592005-05-10 22:42:54 +000011308
11309 /* 66 0F 73 /7 ib = PSLLDQ by immediate */
11310 /* note, if mem case ever filled in, 1 byte after amode */
11311 if (have66noF2noF3(pfx) && sz == 2
11312 && insn[0] == 0x0F && insn[1] == 0x73
11313 && epartIsReg(insn[2])
11314 && gregLO3ofRM(insn[2]) == 7) {
11315 IRTemp sV, dV, hi64, lo64, hi64r, lo64r;
11316 Int imm = (Int)insn[3];
11317 Int reg = eregOfRexRM(pfx,insn[2]);
11318 DIP("pslldq $%d,%s\n", imm, nameXMMReg(reg));
11319 vassert(imm >= 0 && imm <= 255);
11320 delta += 4;
11321
11322 sV = newTemp(Ity_V128);
11323 dV = newTemp(Ity_V128);
11324 hi64 = newTemp(Ity_I64);
11325 lo64 = newTemp(Ity_I64);
11326 hi64r = newTemp(Ity_I64);
11327 lo64r = newTemp(Ity_I64);
11328
11329 if (imm >= 16) {
11330 putXMMReg(reg, mkV128(0x0000));
11331 goto decode_success;
11332 }
11333
11334 assign( sV, getXMMReg(reg) );
11335 assign( hi64, unop(Iop_V128HIto64, mkexpr(sV)) );
11336 assign( lo64, unop(Iop_V128to64, mkexpr(sV)) );
11337
11338 if (imm == 0) {
11339 assign( lo64r, mkexpr(lo64) );
11340 assign( hi64r, mkexpr(hi64) );
11341 }
11342 else
11343 if (imm == 8) {
11344 assign( lo64r, mkU64(0) );
11345 assign( hi64r, mkexpr(lo64) );
11346 }
11347 else
11348 if (imm > 8) {
11349 assign( lo64r, mkU64(0) );
11350 assign( hi64r, binop( Iop_Shl64,
11351 mkexpr(lo64),
11352 mkU8( 8*(imm-8) ) ));
11353 } else {
11354 assign( lo64r, binop( Iop_Shl64,
11355 mkexpr(lo64),
11356 mkU8(8 * imm) ));
11357 assign( hi64r,
11358 binop( Iop_Or64,
11359 binop(Iop_Shl64, mkexpr(hi64),
11360 mkU8(8 * imm)),
11361 binop(Iop_Shr64, mkexpr(lo64),
11362 mkU8(8 * (8 - imm)) )
11363 )
11364 );
11365 }
11366 assign( dV, binop(Iop_64HLtoV128, mkexpr(hi64r), mkexpr(lo64r)) );
11367 putXMMReg(reg, mkexpr(dV));
11368 goto decode_success;
11369 }
11370
sewardjadffcef2005-05-11 00:03:06 +000011371 /* 66 0F 73 /6 ib = PSLLQ by immediate */
11372 if (have66noF2noF3(pfx) && sz == 2
11373 && insn[0] == 0x0F && insn[1] == 0x73
11374 && epartIsReg(insn[2])
11375 && gregLO3ofRM(insn[2]) == 6) {
11376 delta = dis_SSE_shiftE_imm( pfx, delta+2, "psllq", Iop_ShlN64x2 );
11377 goto decode_success;
11378 }
11379
11380 /* 66 0F F3 = PSLLQ by E */
11381 if (have66noF2noF3(pfx) && sz == 2
11382 && insn[0] == 0x0F && insn[1] == 0xF3) {
11383 delta = dis_SSE_shiftG_byE( pfx, delta+2, "psllq", Iop_ShlN64x2 );
11384 goto decode_success;
11385 }
11386
11387 /* 66 0F 71 /6 ib = PSLLW by immediate */
11388 if (have66noF2noF3(pfx) && sz == 2
11389 && insn[0] == 0x0F && insn[1] == 0x71
11390 && epartIsReg(insn[2])
11391 && gregLO3ofRM(insn[2]) == 6) {
11392 delta = dis_SSE_shiftE_imm( pfx, delta+2, "psllw", Iop_ShlN16x8 );
11393 goto decode_success;
11394 }
11395
11396 /* 66 0F F1 = PSLLW by E */
11397 if (have66noF2noF3(pfx) && sz == 2
11398 && insn[0] == 0x0F && insn[1] == 0xF1) {
11399 delta = dis_SSE_shiftG_byE( pfx, delta+2, "psllw", Iop_ShlN16x8 );
11400 goto decode_success;
11401 }
11402
11403 /* 66 0F 72 /4 ib = PSRAD by immediate */
11404 if (have66noF2noF3(pfx) && sz == 2
11405 && insn[0] == 0x0F && insn[1] == 0x72
11406 && epartIsReg(insn[2])
11407 && gregLO3ofRM(insn[2]) == 4) {
11408 delta = dis_SSE_shiftE_imm( pfx, delta+2, "psrad", Iop_SarN32x4 );
11409 goto decode_success;
11410 }
11411
11412 /* 66 0F E2 = PSRAD by E */
11413 if (have66noF2noF3(pfx) && sz == 2
11414 && insn[0] == 0x0F && insn[1] == 0xE2) {
11415 delta = dis_SSE_shiftG_byE( pfx, delta+2, "psrad", Iop_SarN32x4 );
11416 goto decode_success;
11417 }
11418
11419 /* 66 0F 71 /4 ib = PSRAW by immediate */
11420 if (have66noF2noF3(pfx) && sz == 2
11421 && insn[0] == 0x0F && insn[1] == 0x71
11422 && epartIsReg(insn[2])
11423 && gregLO3ofRM(insn[2]) == 4) {
11424 delta = dis_SSE_shiftE_imm( pfx, delta+2, "psraw", Iop_SarN16x8 );
11425 goto decode_success;
11426 }
11427
11428 /* 66 0F E1 = PSRAW by E */
11429 if (have66noF2noF3(pfx) && sz == 2
11430 && insn[0] == 0x0F && insn[1] == 0xE1) {
11431 delta = dis_SSE_shiftG_byE( pfx, delta+2, "psraw", Iop_SarN16x8 );
11432 goto decode_success;
11433 }
11434
11435 /* 66 0F 72 /2 ib = PSRLD by immediate */
11436 if (have66noF2noF3(pfx) && sz == 2
11437 && insn[0] == 0x0F && insn[1] == 0x72
11438 && epartIsReg(insn[2])
11439 && gregLO3ofRM(insn[2]) == 2) {
11440 delta = dis_SSE_shiftE_imm( pfx, delta+2, "psrld", Iop_ShrN32x4 );
11441 goto decode_success;
11442 }
11443
11444 /* 66 0F D2 = PSRLD by E */
11445 if (have66noF2noF3(pfx) && sz == 2
11446 && insn[0] == 0x0F && insn[1] == 0xD2) {
11447 delta = dis_SSE_shiftG_byE( pfx, delta+2, "psrld", Iop_ShrN32x4 );
11448 goto decode_success;
11449 }
sewardj97628592005-05-10 22:42:54 +000011450
11451 /* 66 0F 73 /3 ib = PSRLDQ by immediate */
11452 /* note, if mem case ever filled in, 1 byte after amode */
11453 if (have66noF2noF3(pfx) && sz == 2
11454 && insn[0] == 0x0F && insn[1] == 0x73
11455 && epartIsReg(insn[2])
11456 && gregLO3ofRM(insn[2]) == 3) {
11457 IRTemp sV, dV, hi64, lo64, hi64r, lo64r;
11458 Int imm = (Int)insn[3];
11459 Int reg = eregOfRexRM(pfx,insn[2]);
11460 DIP("psrldq $%d,%s\n", imm, nameXMMReg(reg));
11461 vassert(imm >= 0 && imm <= 255);
11462 delta += 4;
11463
11464 sV = newTemp(Ity_V128);
11465 dV = newTemp(Ity_V128);
11466 hi64 = newTemp(Ity_I64);
11467 lo64 = newTemp(Ity_I64);
11468 hi64r = newTemp(Ity_I64);
11469 lo64r = newTemp(Ity_I64);
11470
11471 if (imm >= 16) {
11472 putXMMReg(reg, mkV128(0x0000));
11473 goto decode_success;
11474 }
11475
11476 assign( sV, getXMMReg(reg) );
11477 assign( hi64, unop(Iop_V128HIto64, mkexpr(sV)) );
11478 assign( lo64, unop(Iop_V128to64, mkexpr(sV)) );
11479
11480 if (imm == 0) {
11481 assign( lo64r, mkexpr(lo64) );
11482 assign( hi64r, mkexpr(hi64) );
11483 }
11484 else
11485 if (imm == 8) {
11486 assign( hi64r, mkU64(0) );
11487 assign( lo64r, mkexpr(hi64) );
11488 }
11489 else
11490 if (imm > 8) {
11491 assign( hi64r, mkU64(0) );
11492 assign( lo64r, binop( Iop_Shr64,
11493 mkexpr(hi64),
11494 mkU8( 8*(imm-8) ) ));
11495 } else {
11496 assign( hi64r, binop( Iop_Shr64,
11497 mkexpr(hi64),
11498 mkU8(8 * imm) ));
11499 assign( lo64r,
11500 binop( Iop_Or64,
11501 binop(Iop_Shr64, mkexpr(lo64),
11502 mkU8(8 * imm)),
11503 binop(Iop_Shl64, mkexpr(hi64),
11504 mkU8(8 * (8 - imm)) )
11505 )
11506 );
11507 }
11508
11509 assign( dV, binop(Iop_64HLtoV128, mkexpr(hi64r), mkexpr(lo64r)) );
11510 putXMMReg(reg, mkexpr(dV));
11511 goto decode_success;
11512 }
sewardj09717342005-05-05 21:34:02 +000011513
11514 /* 66 0F 73 /2 ib = PSRLQ by immediate */
11515 if (have66noF2noF3(pfx) && sz == 2
11516 && insn[0] == 0x0F && insn[1] == 0x73
11517 && epartIsReg(insn[2])
11518 && gregLO3ofRM(insn[2]) == 2) {
11519 delta = dis_SSE_shiftE_imm( pfx, delta+2, "psrlq", Iop_ShrN64x2 );
11520 goto decode_success;
11521 }
11522
sewardjadffcef2005-05-11 00:03:06 +000011523 /* 66 0F D3 = PSRLQ by E */
11524 if (have66noF2noF3(pfx) && sz == 2
11525 && insn[0] == 0x0F && insn[1] == 0xD3) {
11526 delta = dis_SSE_shiftG_byE( pfx, delta+2, "psrlq", Iop_ShrN64x2 );
11527 goto decode_success;
11528 }
11529
11530 /* 66 0F 71 /2 ib = PSRLW by immediate */
11531 if (have66noF2noF3(pfx) && sz == 2
11532 && insn[0] == 0x0F && insn[1] == 0x71
11533 && epartIsReg(insn[2])
11534 && gregLO3ofRM(insn[2]) == 2) {
11535 delta = dis_SSE_shiftE_imm( pfx, delta+2, "psrlw", Iop_ShrN16x8 );
11536 goto decode_success;
11537 }
11538
11539 /* 66 0F D1 = PSRLW by E */
11540 if (have66noF2noF3(pfx) && sz == 2
11541 && insn[0] == 0x0F && insn[1] == 0xD1) {
11542 delta = dis_SSE_shiftG_byE( pfx, delta+2, "psrlw", Iop_ShrN16x8 );
11543 goto decode_success;
11544 }
sewardj97628592005-05-10 22:42:54 +000011545
11546 /* 66 0F F8 = PSUBB */
11547 if (have66noF2noF3(pfx) && sz == 2
11548 && insn[0] == 0x0F && insn[1] == 0xF8) {
11549 delta = dis_SSEint_E_to_G( pfx, delta+2,
11550 "psubb", Iop_Sub8x16, False );
11551 goto decode_success;
11552 }
11553
11554 /* 66 0F FA = PSUBD */
11555 if (have66noF2noF3(pfx) && sz == 2
11556 && insn[0] == 0x0F && insn[1] == 0xFA) {
11557 delta = dis_SSEint_E_to_G( pfx, delta+2,
11558 "psubd", Iop_Sub32x4, False );
11559 goto decode_success;
11560 }
sewardj8711f662005-05-09 17:52:56 +000011561
11562 /* ***--- this is an MMX class insn introduced in SSE2 ---*** */
11563 /* 0F FB = PSUBQ -- sub 64x1 */
11564 if (haveNo66noF2noF3(pfx) && sz == 4
11565 && insn[0] == 0x0F && insn[1] == 0xFB) {
11566 do_MMX_preamble();
11567 delta = dis_MMXop_regmem_to_reg (
11568 pfx, delta+2, insn[1], "psubq", False );
11569 goto decode_success;
11570 }
sewardj09717342005-05-05 21:34:02 +000011571
11572 /* 66 0F FB = PSUBQ */
11573 if (have66noF2noF3(pfx) && sz == 2
11574 && insn[0] == 0x0F && insn[1] == 0xFB) {
11575 delta = dis_SSEint_E_to_G( pfx, delta+2,
11576 "psubq", Iop_Sub64x2, False );
11577 goto decode_success;
11578 }
11579
sewardj97628592005-05-10 22:42:54 +000011580 /* 66 0F F9 = PSUBW */
11581 if (have66noF2noF3(pfx) && sz == 2
11582 && insn[0] == 0x0F && insn[1] == 0xF9) {
11583 delta = dis_SSEint_E_to_G( pfx, delta+2,
11584 "psubw", Iop_Sub16x8, False );
11585 goto decode_success;
11586 }
11587
11588 /* 66 0F E8 = PSUBSB */
11589 if (have66noF2noF3(pfx) && sz == 2
11590 && insn[0] == 0x0F && insn[1] == 0xE8) {
11591 delta = dis_SSEint_E_to_G( pfx, delta+2,
11592 "psubsb", Iop_QSub8Sx16, False );
11593 goto decode_success;
11594 }
11595
11596 /* 66 0F E9 = PSUBSW */
11597 if (have66noF2noF3(pfx) && sz == 2
11598 && insn[0] == 0x0F && insn[1] == 0xE9) {
11599 delta = dis_SSEint_E_to_G( pfx, delta+2,
11600 "psubsw", Iop_QSub16Sx8, False );
11601 goto decode_success;
11602 }
11603
11604 /* 66 0F D8 = PSUBSB */
11605 if (have66noF2noF3(pfx) && sz == 2
11606 && insn[0] == 0x0F && insn[1] == 0xD8) {
11607 delta = dis_SSEint_E_to_G( pfx, delta+2,
11608 "psubusb", Iop_QSub8Ux16, False );
11609 goto decode_success;
11610 }
11611
11612 /* 66 0F D9 = PSUBSW */
11613 if (have66noF2noF3(pfx) && sz == 2
11614 && insn[0] == 0x0F && insn[1] == 0xD9) {
11615 delta = dis_SSEint_E_to_G( pfx, delta+2,
11616 "psubusw", Iop_QSub16Ux8, False );
11617 goto decode_success;
11618 }
11619
11620 /* 66 0F 68 = PUNPCKHBW */
11621 if (have66noF2noF3(pfx) && sz == 2
11622 && insn[0] == 0x0F && insn[1] == 0x68) {
11623 delta = dis_SSEint_E_to_G( pfx, delta+2,
11624 "punpckhbw",
11625 Iop_InterleaveHI8x16, True );
11626 goto decode_success;
11627 }
11628
11629 /* 66 0F 6A = PUNPCKHDQ */
11630 if (have66noF2noF3(pfx) && sz == 2
11631 && insn[0] == 0x0F && insn[1] == 0x6A) {
11632 delta = dis_SSEint_E_to_G( pfx, delta+2,
11633 "punpckhdq",
11634 Iop_InterleaveHI32x4, True );
11635 goto decode_success;
11636 }
11637
11638 /* 66 0F 6D = PUNPCKHQDQ */
11639 if (have66noF2noF3(pfx) && sz == 2
11640 && insn[0] == 0x0F && insn[1] == 0x6D) {
11641 delta = dis_SSEint_E_to_G( pfx, delta+2,
11642 "punpckhqdq",
11643 Iop_InterleaveHI64x2, True );
11644 goto decode_success;
11645 }
11646
11647 /* 66 0F 69 = PUNPCKHWD */
11648 if (have66noF2noF3(pfx) && sz == 2
11649 && insn[0] == 0x0F && insn[1] == 0x69) {
11650 delta = dis_SSEint_E_to_G( pfx, delta+2,
11651 "punpckhwd",
11652 Iop_InterleaveHI16x8, True );
11653 goto decode_success;
11654 }
11655
11656 /* 66 0F 60 = PUNPCKLBW */
11657 if (have66noF2noF3(pfx) && sz == 2
11658 && insn[0] == 0x0F && insn[1] == 0x60) {
11659 delta = dis_SSEint_E_to_G( pfx, delta+2,
11660 "punpcklbw",
11661 Iop_InterleaveLO8x16, True );
11662 goto decode_success;
11663 }
11664
11665 /* 66 0F 62 = PUNPCKLDQ */
11666 if (have66noF2noF3(pfx) && sz == 2
11667 && insn[0] == 0x0F && insn[1] == 0x62) {
11668 delta = dis_SSEint_E_to_G( pfx, delta+2,
11669 "punpckldq",
11670 Iop_InterleaveLO32x4, True );
11671 goto decode_success;
11672 }
11673
11674 /* 66 0F 6C = PUNPCKLQDQ */
11675 if (have66noF2noF3(pfx) && sz == 2
11676 && insn[0] == 0x0F && insn[1] == 0x6C) {
11677 delta = dis_SSEint_E_to_G( pfx, delta+2,
11678 "punpcklqdq",
11679 Iop_InterleaveLO64x2, True );
11680 goto decode_success;
11681 }
11682
11683 /* 66 0F 61 = PUNPCKLWD */
11684 if (have66noF2noF3(pfx) && sz == 2
11685 && insn[0] == 0x0F && insn[1] == 0x61) {
11686 delta = dis_SSEint_E_to_G( pfx, delta+2,
11687 "punpcklwd",
11688 Iop_InterleaveLO16x8, True );
11689 goto decode_success;
11690 }
sewardj09717342005-05-05 21:34:02 +000011691
11692 /* 66 0F EF = PXOR */
11693 if (have66noF2noF3(pfx) && sz == 2
11694 && insn[0] == 0x0F && insn[1] == 0xEF) {
11695 delta = dis_SSE_E_to_G_all( pfx, delta+2, "pxor", Iop_XorV128 );
11696 goto decode_success;
11697 }
11698
sewardjd20c8852005-01-20 20:04:07 +000011699//.. //-- /* FXSAVE/FXRSTOR m32 -- load/store the FPU/MMX/SSE state. */
11700//.. //-- if (insn[0] == 0x0F && insn[1] == 0xAE
11701//.. //-- && (!epartIsReg(insn[2]))
11702//.. //-- && (gregOfRM(insn[2]) == 1 || gregOfRM(insn[2]) == 0) ) {
11703//.. //-- Bool store = gregOfRM(insn[2]) == 0;
11704//.. //-- vg_assert(sz == 4);
11705//.. //-- pair = disAMode ( cb, sorb, eip+2, dis_buf );
11706//.. //-- t1 = LOW24(pair);
11707//.. //-- eip += 2+HI8(pair);
11708//.. //-- uInstr3(cb, store ? SSE2a_MemWr : SSE2a_MemRd, 512,
11709//.. //-- Lit16, (((UShort)insn[0]) << 8) | (UShort)insn[1],
11710//.. //-- Lit16, (UShort)insn[2],
11711//.. //-- TempReg, t1 );
11712//.. //-- DIP("fx%s %s\n", store ? "save" : "rstor", dis_buf );
11713//.. //-- goto decode_success;
11714//.. //-- }
sewardj3e616e62006-01-07 22:58:54 +000011715
11716 /* 0F AE /7 = CLFLUSH -- flush cache line */
11717 if (haveNo66noF2noF3(pfx) && sz == 4
11718 && insn[0] == 0x0F && insn[1] == 0xAE
11719 && !epartIsReg(insn[2]) && gregLO3ofRM(insn[2]) == 7) {
11720
11721 /* This is something of a hack. We need to know the size of the
11722 cache line containing addr. Since we don't (easily), assume
11723 256 on the basis that no real cache would have a line that
11724 big. It's safe to invalidate more stuff than we need, just
11725 inefficient. */
11726 ULong lineszB = 256ULL;
11727
11728 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
11729 delta += 2+alen;
11730
11731 /* Round addr down to the start of the containing block. */
11732 stmt( IRStmt_Put(
11733 OFFB_TISTART,
11734 binop( Iop_And64,
11735 mkexpr(addr),
11736 mkU64( ~(lineszB-1) ))) );
11737
11738 stmt( IRStmt_Put(OFFB_TILEN, mkU64(lineszB) ) );
11739
11740 irbb->jumpkind = Ijk_TInval;
11741 irbb->next = mkU64(guest_RIP_bbstart+delta);
11742 dres.whatNext = Dis_StopHere;
11743
11744 DIP("clflush %s\n", dis_buf);
11745 goto decode_success;
11746 }
sewardjdf0e0022005-01-25 15:48:43 +000011747
11748
11749 /* ---------------------------------------------------- */
11750 /* --- end of the SSE/SSE2 decoder. --- */
11751 /* ---------------------------------------------------- */
11752
sewardj7a240552005-01-28 21:37:12 +000011753 /*after_sse_decoders:*/
sewardjdf0e0022005-01-25 15:48:43 +000011754
11755 /* Get the primary opcode. */
sewardj8c332e22005-01-28 01:36:56 +000011756 opc = getUChar(delta); delta++;
sewardjdf0e0022005-01-25 15:48:43 +000011757
11758 /* We get here if the current insn isn't SSE, or this CPU doesn't
11759 support SSE. */
11760
11761 switch (opc) {
11762
11763 /* ------------------------ Control flow --------------- */
11764
sewardjd20c8852005-01-20 20:04:07 +000011765//.. case 0xC2: /* RET imm16 */
11766//.. d32 = getUDisp16(delta);
11767//.. delta += 2;
11768//.. dis_ret(d32);
11769//.. whatNext = Dis_StopHere;
11770//.. DIP("ret %d\n", d32);
11771//.. break;
sewardj2f959cc2005-01-26 01:19:35 +000011772 case 0xC3: /* RET */
sewardj55dbb262005-01-28 16:36:51 +000011773 if (haveF2(pfx)) goto decode_failure;
11774 /* F3 is acceptable on AMD. */
sewardj2f959cc2005-01-26 01:19:35 +000011775 dis_ret(0);
sewardj9e6491a2005-07-02 19:24:10 +000011776 dres.whatNext = Dis_StopHere;
sewardje941eea2005-01-30 19:52:28 +000011777 DIP(haveF3(pfx) ? "rep ; ret\n" : "ret\n");
sewardj2f959cc2005-01-26 01:19:35 +000011778 break;
11779
sewardj3ca55a12005-01-27 16:06:23 +000011780 case 0xE8: /* CALL J4 */
11781 if (haveF2orF3(pfx)) goto decode_failure;
11782 d64 = getSDisp32(delta); delta += 4;
sewardj9e6491a2005-07-02 19:24:10 +000011783 d64 += (guest_RIP_bbstart+delta);
11784 /* (guest_RIP_bbstart+delta) == return-to addr, d64 == call-to addr */
sewardj3ca55a12005-01-27 16:06:23 +000011785 t1 = newTemp(Ity_I64);
11786 assign(t1, binop(Iop_Sub64, getIReg64(R_RSP), mkU64(8)));
11787 putIReg64(R_RSP, mkexpr(t1));
sewardj9e6491a2005-07-02 19:24:10 +000011788 storeLE( mkexpr(t1), mkU64(guest_RIP_bbstart+delta));
sewardj5a9ffab2005-05-12 17:55:01 +000011789 make_redzone_AbiHint(t1, "call-d32");
sewardjc716aea2006-01-17 01:48:46 +000011790 if (resteerOkFn( callback_opaque, (Addr64)d64) ) {
sewardj3ca55a12005-01-27 16:06:23 +000011791 /* follow into the call target. */
sewardj9e6491a2005-07-02 19:24:10 +000011792 dres.whatNext = Dis_Resteer;
11793 dres.continueAt = d64;
sewardj3ca55a12005-01-27 16:06:23 +000011794 } else {
11795 jmp_lit(Ijk_Call,d64);
sewardj9e6491a2005-07-02 19:24:10 +000011796 dres.whatNext = Dis_StopHere;
sewardj3ca55a12005-01-27 16:06:23 +000011797 }
11798 DIP("call 0x%llx\n",d64);
11799 break;
11800
sewardjd20c8852005-01-20 20:04:07 +000011801//.. //-- case 0xC8: /* ENTER */
11802//.. //-- d32 = getUDisp16(eip); eip += 2;
sewardj8c332e22005-01-28 01:36:56 +000011803//.. //-- abyte = getUChar(delta); delta++;
sewardjd20c8852005-01-20 20:04:07 +000011804//.. //--
11805//.. //-- vg_assert(sz == 4);
11806//.. //-- vg_assert(abyte == 0);
11807//.. //--
11808//.. //-- t1 = newTemp(cb); t2 = newTemp(cb);
11809//.. //-- uInstr2(cb, GET, sz, ArchReg, R_EBP, TempReg, t1);
11810//.. //-- uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t2);
11811//.. //-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
11812//.. //-- uLiteral(cb, sz);
11813//.. //-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
11814//.. //-- uInstr2(cb, STORE, 4, TempReg, t1, TempReg, t2);
11815//.. //-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_EBP);
11816//.. //-- if (d32) {
11817//.. //-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
11818//.. //-- uLiteral(cb, d32);
11819//.. //-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
11820//.. //-- }
11821//.. //-- DIP("enter 0x%x, 0x%x", d32, abyte);
11822//.. //-- break;
sewardje1698952005-02-08 15:02:39 +000011823
11824 case 0xC9: /* LEAVE */
11825 /* In 64-bit mode this defaults to a 64-bit operand size. There
11826 is no way to encode a 32-bit variant. Hence sz==4 but we do
11827 it as if sz=8. */
11828 if (sz != 4)
11829 goto decode_failure;
11830 t1 = newTemp(Ity_I64);
11831 t2 = newTemp(Ity_I64);
11832 assign(t1, getIReg64(R_RBP));
11833 /* First PUT RSP looks redundant, but need it because RSP must
11834 always be up-to-date for Memcheck to work... */
11835 putIReg64(R_RSP, mkexpr(t1));
11836 assign(t2, loadLE(Ity_I64,mkexpr(t1)));
11837 putIReg64(R_RBP, mkexpr(t2));
11838 putIReg64(R_RSP, binop(Iop_Add64, mkexpr(t1), mkU64(8)) );
11839 DIP("leave\n");
11840 break;
11841
sewardjd20c8852005-01-20 20:04:07 +000011842//.. //-- /* ---------------- Misc weird-ass insns --------------- */
11843//.. //--
11844//.. //-- case 0x27: /* DAA */
11845//.. //-- case 0x2F: /* DAS */
11846//.. //-- t1 = newTemp(cb);
11847//.. //-- uInstr2(cb, GET, 1, ArchReg, R_AL, TempReg, t1);
11848//.. //-- /* Widen %AL to 32 bits, so it's all defined when we push it. */
11849//.. //-- uInstr1(cb, WIDEN, 4, TempReg, t1);
11850//.. //-- uWiden(cb, 1, False);
11851//.. //-- uInstr0(cb, CALLM_S, 0);
11852//.. //-- uInstr1(cb, PUSH, 4, TempReg, t1);
11853//.. //-- uInstr1(cb, CALLM, 0, Lit16,
11854//.. //-- opc == 0x27 ? VGOFF_(helper_DAA) : VGOFF_(helper_DAS) );
11855//.. //-- uFlagsRWU(cb, FlagsAC, FlagsSZACP, FlagO);
11856//.. //-- uInstr1(cb, POP, 4, TempReg, t1);
11857//.. //-- uInstr0(cb, CALLM_E, 0);
11858//.. //-- uInstr2(cb, PUT, 1, TempReg, t1, ArchReg, R_AL);
11859//.. //-- DIP(opc == 0x27 ? "daa\n" : "das\n");
11860//.. //-- break;
11861//.. //--
11862//.. //-- case 0x37: /* AAA */
11863//.. //-- case 0x3F: /* AAS */
11864//.. //-- t1 = newTemp(cb);
11865//.. //-- uInstr2(cb, GET, 2, ArchReg, R_EAX, TempReg, t1);
11866//.. //-- /* Widen %AL to 32 bits, so it's all defined when we push it. */
11867//.. //-- uInstr1(cb, WIDEN, 4, TempReg, t1);
11868//.. //-- uWiden(cb, 2, False);
11869//.. //-- uInstr0(cb, CALLM_S, 0);
11870//.. //-- uInstr1(cb, PUSH, 4, TempReg, t1);
11871//.. //-- uInstr1(cb, CALLM, 0, Lit16,
11872//.. //-- opc == 0x37 ? VGOFF_(helper_AAA) : VGOFF_(helper_AAS) );
11873//.. //-- uFlagsRWU(cb, FlagA, FlagsAC, FlagsEmpty);
11874//.. //-- uInstr1(cb, POP, 4, TempReg, t1);
11875//.. //-- uInstr0(cb, CALLM_E, 0);
11876//.. //-- uInstr2(cb, PUT, 2, TempReg, t1, ArchReg, R_EAX);
11877//.. //-- DIP(opc == 0x37 ? "aaa\n" : "aas\n");
11878//.. //-- break;
11879//.. //--
11880//.. //-- case 0xD4: /* AAM */
11881//.. //-- case 0xD5: /* AAD */
sewardj8c332e22005-01-28 01:36:56 +000011882//.. //-- d32 = getUChar(delta); delta++;
sewardjd20c8852005-01-20 20:04:07 +000011883//.. //-- if (d32 != 10) VG_(core_panic)("disInstr: AAM/AAD but base not 10 !");
11884//.. //-- t1 = newTemp(cb);
11885//.. //-- uInstr2(cb, GET, 2, ArchReg, R_EAX, TempReg, t1);
11886//.. //-- /* Widen %AX to 32 bits, so it's all defined when we push it. */
11887//.. //-- uInstr1(cb, WIDEN, 4, TempReg, t1);
11888//.. //-- uWiden(cb, 2, False);
11889//.. //-- uInstr0(cb, CALLM_S, 0);
11890//.. //-- uInstr1(cb, PUSH, 4, TempReg, t1);
11891//.. //-- uInstr1(cb, CALLM, 0, Lit16,
11892//.. //-- opc == 0xD4 ? VGOFF_(helper_AAM) : VGOFF_(helper_AAD) );
11893//.. //-- uFlagsRWU(cb, FlagsEmpty, FlagsSZP, FlagsEmpty);
11894//.. //-- uInstr1(cb, POP, 4, TempReg, t1);
11895//.. //-- uInstr0(cb, CALLM_E, 0);
11896//.. //-- uInstr2(cb, PUT, 2, TempReg, t1, ArchReg, R_EAX);
11897//.. //-- DIP(opc == 0xD4 ? "aam\n" : "aad\n");
11898//.. //-- break;
sewardj3ca55a12005-01-27 16:06:23 +000011899
11900 /* ------------------------ CWD/CDQ -------------------- */
11901
11902 case 0x98: /* CBW */
11903 if (haveF2orF3(pfx)) goto decode_failure;
11904 if (sz == 8) {
sewardj5b470602005-02-27 13:10:48 +000011905 putIRegRAX( 8, unop(Iop_32Sto64, getIRegRAX(4)) );
sewardje941eea2005-01-30 19:52:28 +000011906 DIP(/*"cdqe\n"*/"cltq");
11907 break;
11908 }
sewardj3ca55a12005-01-27 16:06:23 +000011909 if (sz == 4) {
sewardj5b470602005-02-27 13:10:48 +000011910 putIRegRAX( 4, unop(Iop_16Sto32, getIRegRAX(2)) );
sewardj7eaa7cf2005-01-31 18:55:22 +000011911 DIP("cwtl\n");
sewardje941eea2005-01-30 19:52:28 +000011912 break;
11913 }
sewardj3ca55a12005-01-27 16:06:23 +000011914 if (sz == 2) {
sewardj5b470602005-02-27 13:10:48 +000011915 putIRegRAX( 2, unop(Iop_8Sto16, getIRegRAX(1)) );
sewardj3ca55a12005-01-27 16:06:23 +000011916 DIP("cbw\n");
sewardj7bc00082005-03-27 05:08:32 +000011917 break;
sewardj3ca55a12005-01-27 16:06:23 +000011918 }
sewardje941eea2005-01-30 19:52:28 +000011919 goto decode_failure;
sewardj3ca55a12005-01-27 16:06:23 +000011920
11921 case 0x99: /* CWD/CDQ/CQO */
11922 if (haveF2orF3(pfx)) goto decode_failure;
11923 vassert(sz == 2 || sz == 4 || sz == 8);
11924 ty = szToITy(sz);
sewardj5b470602005-02-27 13:10:48 +000011925 putIRegRDX( sz,
11926 binop(mkSizedOp(ty,Iop_Sar8),
11927 getIRegRAX(sz),
11928 mkU8(sz == 2 ? 15 : (sz == 4 ? 31 : 63))) );
sewardje941eea2005-01-30 19:52:28 +000011929 DIP(sz == 2 ? "cwd\n"
sewardj5b470602005-02-27 13:10:48 +000011930 : (sz == 4 ? /*"cdq\n"*/ "cltd\n"
11931 : "cqo\n"));
sewardj3ca55a12005-01-27 16:06:23 +000011932 break;
11933
sewardj8d965312005-02-25 02:48:47 +000011934 /* ------------------------ FPU ops -------------------- */
11935
sewardjd20c8852005-01-20 20:04:07 +000011936//.. case 0x9E: /* SAHF */
11937//.. codegen_SAHF();
11938//.. DIP("sahf\n");
11939//.. break;
11940//..
11941//.. //-- case 0x9F: /* LAHF */
11942//.. //-- codegen_LAHF ( cb );
11943//.. //-- DIP("lahf\n");
11944//.. //-- break;
11945//.. //--
sewardj6847d8c2005-05-12 19:21:55 +000011946 case 0x9B: /* FWAIT */
11947 /* ignore? */
11948 DIP("fwait\n");
11949 break;
sewardj8d965312005-02-25 02:48:47 +000011950
11951 case 0xD8:
11952 case 0xD9:
11953 case 0xDA:
11954 case 0xDB:
11955 case 0xDC:
11956 case 0xDD:
11957 case 0xDE:
11958 case 0xDF:
sewardj5b470602005-02-27 13:10:48 +000011959 if (haveF2orF3(pfx)) goto decode_failure;
sewardj8d965312005-02-25 02:48:47 +000011960 if (sz == 4 && haveNo66noF2noF3(pfx)) {
sewardj270def42005-07-03 01:03:01 +000011961 Long delta0 = delta;
11962 Bool decode_OK = False;
sewardj8d965312005-02-25 02:48:47 +000011963 delta = dis_FPU ( &decode_OK, pfx, delta );
11964 if (!decode_OK) {
11965 delta = delta0;
11966 goto decode_failure;
11967 }
11968 break;
11969 } else {
11970 goto decode_failure;
11971 }
11972
sewardj4fa325a2005-11-03 13:27:24 +000011973 /* ------------------------ INT ------------------------ */
11974
11975 case 0xCD: { /* INT imm8 */
11976 IRJumpKind jk = Ijk_Boring;
11977 if (have66orF2orF3(pfx)) goto decode_failure;
11978 d64 = getUChar(delta); delta++;
11979 switch (d64) {
11980 case 32: jk = Ijk_Sys_int32; break;
11981 default: goto decode_failure;
11982 }
11983 guest_RIP_next_mustcheck = True;
11984 guest_RIP_next_assumed = guest_RIP_bbstart + delta;
11985 jmp_lit(jk, guest_RIP_next_assumed);
11986 /* It's important that all ArchRegs carry their up-to-date value
11987 at this point. So we declare an end-of-block here, which
11988 forces any TempRegs caching ArchRegs to be flushed. */
11989 dres.whatNext = Dis_StopHere;
11990 DIP("int $0x%02x\n", (UInt)d64);
11991 break;
11992 }
11993
sewardjf8c37f72005-02-07 18:55:29 +000011994 /* ------------------------ Jcond, byte offset --------- */
11995
11996 case 0xEB: /* Jb (jump, byte offset) */
sewardj5b470602005-02-27 13:10:48 +000011997 if (haveF2orF3(pfx)) goto decode_failure;
sewardjf8c37f72005-02-07 18:55:29 +000011998 if (sz != 4)
11999 goto decode_failure; /* JRS added 2004 July 11 */
sewardj9e6491a2005-07-02 19:24:10 +000012000 d64 = (guest_RIP_bbstart+delta+1) + getSDisp8(delta);
sewardjf8c37f72005-02-07 18:55:29 +000012001 delta++;
sewardjc716aea2006-01-17 01:48:46 +000012002 if (resteerOkFn(callback_opaque,d64)) {
sewardj9e6491a2005-07-02 19:24:10 +000012003 dres.whatNext = Dis_Resteer;
12004 dres.continueAt = d64;
sewardjf8c37f72005-02-07 18:55:29 +000012005 } else {
12006 jmp_lit(Ijk_Boring,d64);
sewardj9e6491a2005-07-02 19:24:10 +000012007 dres.whatNext = Dis_StopHere;
sewardjf8c37f72005-02-07 18:55:29 +000012008 }
12009 DIP("jmp-8 0x%llx\n", d64);
12010 break;
sewardj1389d4d2005-01-28 13:46:29 +000012011
12012 case 0xE9: /* Jv (jump, 16/32 offset) */
sewardj5b470602005-02-27 13:10:48 +000012013 if (haveF2orF3(pfx)) goto decode_failure;
sewardjf8c37f72005-02-07 18:55:29 +000012014 if (sz != 4)
12015 goto decode_failure; /* JRS added 2004 July 11 */
sewardj9e6491a2005-07-02 19:24:10 +000012016 d64 = (guest_RIP_bbstart+delta+sz) + getSDisp(sz,delta);
sewardj1389d4d2005-01-28 13:46:29 +000012017 delta += sz;
sewardjc716aea2006-01-17 01:48:46 +000012018 if (resteerOkFn(callback_opaque,d64)) {
sewardj9e6491a2005-07-02 19:24:10 +000012019 dres.whatNext = Dis_Resteer;
12020 dres.continueAt = d64;
sewardj1389d4d2005-01-28 13:46:29 +000012021 } else {
12022 jmp_lit(Ijk_Boring,d64);
sewardj9e6491a2005-07-02 19:24:10 +000012023 dres.whatNext = Dis_StopHere;
sewardj1389d4d2005-01-28 13:46:29 +000012024 }
12025 DIP("jmp 0x%llx\n", d64);
12026 break;
12027
sewardjf8c37f72005-02-07 18:55:29 +000012028 case 0x70:
12029 case 0x71:
12030 case 0x72: /* JBb/JNAEb (jump below) */
12031 case 0x73: /* JNBb/JAEb (jump not below) */
12032 case 0x74: /* JZb/JEb (jump zero) */
12033 case 0x75: /* JNZb/JNEb (jump not zero) */
12034 case 0x76: /* JBEb/JNAb (jump below or equal) */
12035 case 0x77: /* JNBEb/JAb (jump not below or equal) */
12036 case 0x78: /* JSb (jump negative) */
12037 case 0x79: /* JSb (jump not negative) */
12038 case 0x7A: /* JP (jump parity even) */
12039 case 0x7B: /* JNP/JPO (jump parity odd) */
12040 case 0x7C: /* JLb/JNGEb (jump less) */
12041 case 0x7D: /* JGEb/JNLb (jump greater or equal) */
12042 case 0x7E: /* JLEb/JNGb (jump less or equal) */
12043 case 0x7F: /* JGb/JNLEb (jump greater) */
sewardj5b470602005-02-27 13:10:48 +000012044 if (haveF2orF3(pfx)) goto decode_failure;
sewardj9e6491a2005-07-02 19:24:10 +000012045 d64 = (guest_RIP_bbstart+delta+1) + getSDisp8(delta);
sewardjf8c37f72005-02-07 18:55:29 +000012046 delta++;
12047 jcc_01( (AMD64Condcode)(opc - 0x70),
sewardj9e6491a2005-07-02 19:24:10 +000012048 guest_RIP_bbstart+delta,
sewardjf8c37f72005-02-07 18:55:29 +000012049 d64 );
sewardj9e6491a2005-07-02 19:24:10 +000012050 dres.whatNext = Dis_StopHere;
sewardjf8c37f72005-02-07 18:55:29 +000012051 DIP("j%s-8 0x%llx\n", name_AMD64Condcode(opc - 0x70), d64);
12052 break;
12053
sewardjc01c1fa2005-11-04 14:34:52 +000012054 case 0xE3:
12055 /* JRCXZ or JECXZ, depending address size override. */
12056 if (have66orF2orF3(pfx)) goto decode_failure;
sewardjfdfa8862005-10-05 16:58:23 +000012057 d64 = (guest_RIP_bbstart+delta+1) + getSDisp8(delta);
12058 delta++;
sewardjc01c1fa2005-11-04 14:34:52 +000012059 if (haveASO(pfx)) {
12060 /* 32-bit */
12061 stmt( IRStmt_Exit( binop(Iop_CmpEQ64,
12062 unop(Iop_32Uto64, getIReg32(R_RCX)),
12063 mkU64(0)),
12064 Ijk_Boring,
12065 IRConst_U64(d64))
12066 );
12067 DIP("jecxz 0x%llx\n", d64);
12068 } else {
12069 /* 64-bit */
12070 stmt( IRStmt_Exit( binop(Iop_CmpEQ64,
12071 getIReg64(R_RCX),
12072 mkU64(0)),
12073 Ijk_Boring,
12074 IRConst_U64(d64))
12075 );
12076 DIP("jrcxz 0x%llx\n", d64);
12077 }
sewardjfdfa8862005-10-05 16:58:23 +000012078 break;
sewardj6359f812005-07-20 10:15:34 +000012079
sewardje8f65252005-08-23 23:44:35 +000012080 case 0xE0: /* LOOPNE disp8: decrement count, jump if count != 0 && ZF==0 */
12081 case 0xE1: /* LOOPE disp8: decrement count, jump if count != 0 && ZF==1 */
12082 case 0xE2: /* LOOP disp8: decrement count, jump if count != 0 */
12083 { /* The docs say this uses rCX as a count depending on the
12084 address size override, not the operand one. Since we don't
12085 handle address size overrides, I guess that means RCX. */
12086 IRExpr* zbit = NULL;
12087 IRExpr* count = NULL;
12088 IRExpr* cond = NULL;
12089 HChar* xtra = NULL;
12090
12091 if (have66orF2orF3(pfx) || haveASO(pfx)) goto decode_failure;
12092 d64 = guest_RIP_bbstart+delta+1 + getSDisp8(delta);
12093 delta++;
12094 putIReg64(R_RCX, binop(Iop_Sub64, getIReg64(R_RCX), mkU64(1)));
12095
12096 count = getIReg64(R_RCX);
12097 cond = binop(Iop_CmpNE64, count, mkU64(0));
12098 switch (opc) {
12099 case 0xE2:
12100 xtra = "";
12101 break;
12102 case 0xE1:
12103 xtra = "e";
12104 zbit = mk_amd64g_calculate_condition( AMD64CondZ );
12105 cond = mkAnd1(cond, zbit);
12106 break;
12107 case 0xE0:
12108 xtra = "ne";
12109 zbit = mk_amd64g_calculate_condition( AMD64CondNZ );
12110 cond = mkAnd1(cond, zbit);
12111 break;
12112 default:
12113 vassert(0);
12114 }
12115 stmt( IRStmt_Exit(cond, Ijk_Boring, IRConst_U64(d64)) );
12116
12117 DIP("loop%s 0x%llx\n", xtra, d64);
12118 break;
12119 }
sewardj32b2bbe2005-01-28 00:50:10 +000012120
12121 /* ------------------------ IMUL ----------------------- */
12122
12123 case 0x69: /* IMUL Iv, Ev, Gv */
sewardj5b470602005-02-27 13:10:48 +000012124 if (haveF2orF3(pfx)) goto decode_failure;
sewardj32b2bbe2005-01-28 00:50:10 +000012125 delta = dis_imul_I_E_G ( pfx, sz, delta, sz );
12126 break;
sewardj7de0d3c2005-02-13 02:26:41 +000012127 case 0x6B: /* IMUL Ib, Ev, Gv */
12128 delta = dis_imul_I_E_G ( pfx, sz, delta, 1 );
12129 break;
sewardj1389d4d2005-01-28 13:46:29 +000012130
12131 /* ------------------------ MOV ------------------------ */
12132
12133 case 0x88: /* MOV Gb,Eb */
sewardj5b470602005-02-27 13:10:48 +000012134 if (haveF2orF3(pfx)) goto decode_failure;
sewardj1389d4d2005-01-28 13:46:29 +000012135 delta = dis_mov_G_E(pfx, 1, delta);
12136 break;
12137
12138 case 0x89: /* MOV Gv,Ev */
sewardj5b470602005-02-27 13:10:48 +000012139 if (haveF2orF3(pfx)) goto decode_failure;
sewardj1389d4d2005-01-28 13:46:29 +000012140 delta = dis_mov_G_E(pfx, sz, delta);
12141 break;
12142
sewardjd0a12df2005-02-10 02:07:43 +000012143 case 0x8A: /* MOV Eb,Gb */
sewardj5b470602005-02-27 13:10:48 +000012144 if (haveF2orF3(pfx)) goto decode_failure;
sewardjd0a12df2005-02-10 02:07:43 +000012145 delta = dis_mov_E_G(pfx, 1, delta);
12146 break;
12147
sewardj1389d4d2005-01-28 13:46:29 +000012148 case 0x8B: /* MOV Ev,Gv */
sewardj5b470602005-02-27 13:10:48 +000012149 if (haveF2orF3(pfx)) goto decode_failure;
sewardj1389d4d2005-01-28 13:46:29 +000012150 delta = dis_mov_E_G(pfx, sz, delta);
12151 break;
12152
12153 case 0x8D: /* LEA M,Gv */
sewardj5b470602005-02-27 13:10:48 +000012154 if (haveF2orF3(pfx)) goto decode_failure;
sewardj1389d4d2005-01-28 13:46:29 +000012155 if (sz != 4 && sz != 8)
12156 goto decode_failure;
12157 modrm = getUChar(delta);
12158 if (epartIsReg(modrm))
12159 goto decode_failure;
12160 /* NOTE! this is the one place where a segment override prefix
12161 has no effect on the address calculation. Therefore we clear
12162 any segment override bits in pfx. */
sewardje1698952005-02-08 15:02:39 +000012163 addr = disAMode ( &alen, clearSegBits(pfx), delta, dis_buf, 0 );
sewardj1389d4d2005-01-28 13:46:29 +000012164 delta += alen;
12165 /* This is a hack. But it isn't clear that really doing the
12166 calculation at 32 bits is really worth it. Hence for leal,
12167 do the full 64-bit calculation and then truncate it. */
sewardj5b470602005-02-27 13:10:48 +000012168 putIRegG( sz, pfx, modrm,
sewardj1389d4d2005-01-28 13:46:29 +000012169 sz == 4
12170 ? unop(Iop_64to32, mkexpr(addr))
12171 : mkexpr(addr)
12172 );
12173 DIP("lea%c %s, %s\n", nameISize(sz), dis_buf,
sewardj5b470602005-02-27 13:10:48 +000012174 nameIRegG(sz,pfx,modrm));
sewardj1389d4d2005-01-28 13:46:29 +000012175 break;
12176
sewardjd20c8852005-01-20 20:04:07 +000012177//.. case 0x8C: /* MOV Sw,Ew -- MOV from a SEGMENT REGISTER */
12178//.. delta = dis_mov_Sw_Ew(sorb, sz, delta);
12179//.. break;
12180//..
12181//.. case 0x8E: /* MOV Ew,Sw -- MOV to a SEGMENT REGISTER */
12182//.. delta = dis_mov_Ew_Sw(sorb, delta);
12183//.. break;
sewardj2bd97d12005-08-02 21:27:25 +000012184
12185 case 0xA0: /* MOV Ob,AL */
12186 if (have66orF2orF3(pfx)) goto decode_failure;
12187 sz = 1;
12188 /* Fall through ... */
sewardj87277cb2005-08-01 13:03:32 +000012189 case 0xA1: /* MOV Ov,eAX */
sewardj2bd97d12005-08-02 21:27:25 +000012190 if (sz != 8 && sz != 4 && sz != 2 && sz != 1)
12191 goto decode_failure;
sewardj87277cb2005-08-01 13:03:32 +000012192 d64 = getDisp64(delta);
12193 delta += 8;
12194 ty = szToITy(sz);
12195 addr = newTemp(Ity_I64);
sewardj42561ef2005-11-04 14:18:31 +000012196 assign( addr, handleAddrOverrides(pfx, mkU64(d64)) );
sewardj87277cb2005-08-01 13:03:32 +000012197 putIRegRAX(sz, loadLE( ty, mkexpr(addr) ));
12198 DIP("mov%c %s0x%llx, %s\n", nameISize(sz),
12199 sorbTxt(pfx), d64,
12200 nameIRegRAX(sz));
12201 break;
12202
sewardj2bd97d12005-08-02 21:27:25 +000012203 case 0xA2: /* MOV AL,Ob */
12204 if (have66orF2orF3(pfx)) goto decode_failure;
12205 sz = 1;
12206 /* Fall through ... */
sewardj87277cb2005-08-01 13:03:32 +000012207 case 0xA3: /* MOV eAX,Ov */
sewardj2bd97d12005-08-02 21:27:25 +000012208 if (sz != 8 && sz != 4 && sz != 2 && sz != 1)
12209 goto decode_failure;
sewardj87277cb2005-08-01 13:03:32 +000012210 d64 = getDisp64(delta);
12211 delta += 8;
12212 ty = szToITy(sz);
12213 addr = newTemp(Ity_I64);
sewardj42561ef2005-11-04 14:18:31 +000012214 assign( addr, handleAddrOverrides(pfx, mkU64(d64)) );
sewardj87277cb2005-08-01 13:03:32 +000012215 storeLE( mkexpr(addr), getIRegRAX(sz) );
12216 DIP("mov%c %s, %s0x%llx\n", nameISize(sz), nameIRegRAX(sz),
12217 sorbTxt(pfx), d64);
12218 break;
sewardjb095fba2005-02-13 14:13:04 +000012219
sewardj8711f662005-05-09 17:52:56 +000012220 /* XXXX be careful here with moves to AH/BH/CH/DH */
sewardj007e9ec2005-03-23 11:36:48 +000012221 case 0xB0: /* MOV imm,AL */
12222 case 0xB1: /* MOV imm,CL */
sewardjb095fba2005-02-13 14:13:04 +000012223 case 0xB2: /* MOV imm,DL */
sewardj007e9ec2005-03-23 11:36:48 +000012224 case 0xB3: /* MOV imm,BL */
12225 case 0xB4: /* MOV imm,AH */
12226 case 0xB5: /* MOV imm,CH */
12227 case 0xB6: /* MOV imm,DH */
sewardj31eecde2005-03-23 03:39:55 +000012228 case 0xB7: /* MOV imm,BH */
sewardj5b470602005-02-27 13:10:48 +000012229 if (haveF2orF3(pfx)) goto decode_failure;
sewardjb095fba2005-02-13 14:13:04 +000012230 d64 = getUChar(delta);
12231 delta += 1;
sewardj5b470602005-02-27 13:10:48 +000012232 putIRegRexB(1, pfx, opc-0xB0, mkU8(d64));
12233 DIP("movb $%lld,%s\n", d64, nameIRegRexB(1,pfx,opc-0xB0));
sewardjb095fba2005-02-13 14:13:04 +000012234 break;
sewardj1389d4d2005-01-28 13:46:29 +000012235
12236 case 0xB8: /* MOV imm,eAX */
12237 case 0xB9: /* MOV imm,eCX */
12238 case 0xBA: /* MOV imm,eDX */
12239 case 0xBB: /* MOV imm,eBX */
12240 case 0xBC: /* MOV imm,eSP */
12241 case 0xBD: /* MOV imm,eBP */
12242 case 0xBE: /* MOV imm,eSI */
12243 case 0xBF: /* MOV imm,eDI */
sewardj03b07cc2005-01-31 18:09:43 +000012244 /* This is the one-and-only place where 64-bit literals are
12245 allowed in the instruction stream. */
sewardj5b470602005-02-27 13:10:48 +000012246 if (haveF2orF3(pfx)) goto decode_failure;
sewardj03b07cc2005-01-31 18:09:43 +000012247 if (sz == 8) {
12248 d64 = getDisp64(delta);
sewardj7eaa7cf2005-01-31 18:55:22 +000012249 delta += 8;
sewardj5b470602005-02-27 13:10:48 +000012250 putIRegRexB(8, pfx, opc-0xB8, mkU64(d64));
sewardj227458e2005-01-31 19:04:50 +000012251 DIP("movabsq $%lld,%s\n", (Long)d64,
sewardj5b470602005-02-27 13:10:48 +000012252 nameIRegRexB(8,pfx,opc-0xB8));
sewardj03b07cc2005-01-31 18:09:43 +000012253 } else {
12254 d64 = getSDisp(imin(4,sz),delta);
12255 delta += imin(4,sz);
sewardj5b470602005-02-27 13:10:48 +000012256 putIRegRexB(sz, pfx, opc-0xB8,
12257 mkU(szToITy(sz), d64 & mkSizeMask(sz)));
sewardj227458e2005-01-31 19:04:50 +000012258 DIP("mov%c $%lld,%s\n", nameISize(sz),
12259 (Long)d64,
sewardj5b470602005-02-27 13:10:48 +000012260 nameIRegRexB(sz,pfx,opc-0xB8));
sewardj03b07cc2005-01-31 18:09:43 +000012261 }
sewardj1389d4d2005-01-28 13:46:29 +000012262 break;
12263
12264 case 0xC6: /* MOV Ib,Eb */
12265 sz = 1;
12266 goto do_Mov_I_E;
12267 case 0xC7: /* MOV Iv,Ev */
12268 goto do_Mov_I_E;
12269
12270 do_Mov_I_E:
sewardj5b470602005-02-27 13:10:48 +000012271 if (haveF2orF3(pfx)) goto decode_failure;
sewardj1389d4d2005-01-28 13:46:29 +000012272 modrm = getUChar(delta);
12273 if (epartIsReg(modrm)) {
sewardj1389d4d2005-01-28 13:46:29 +000012274 delta++; /* mod/rm byte */
12275 d64 = getSDisp(imin(4,sz),delta);
12276 delta += imin(4,sz);
sewardj5b470602005-02-27 13:10:48 +000012277 putIRegE(sz, pfx, modrm,
12278 mkU(szToITy(sz), d64 & mkSizeMask(sz)));
sewardj227458e2005-01-31 19:04:50 +000012279 DIP("mov%c $%lld, %s\n", nameISize(sz),
12280 (Long)d64,
sewardj5b470602005-02-27 13:10:48 +000012281 nameIRegE(sz,pfx,modrm));
sewardj1389d4d2005-01-28 13:46:29 +000012282 } else {
sewardj5b470602005-02-27 13:10:48 +000012283 addr = disAMode ( &alen, pfx, delta, dis_buf,
12284 /*xtra*/imin(4,sz) );
sewardj1389d4d2005-01-28 13:46:29 +000012285 delta += alen;
sewardje941eea2005-01-30 19:52:28 +000012286 d64 = getSDisp(imin(4,sz),delta);
sewardj1389d4d2005-01-28 13:46:29 +000012287 delta += imin(4,sz);
sewardje941eea2005-01-30 19:52:28 +000012288 storeLE(mkexpr(addr),
12289 mkU(szToITy(sz), d64 & mkSizeMask(sz)));
sewardj227458e2005-01-31 19:04:50 +000012290 DIP("mov%c $%lld, %s\n", nameISize(sz), (Long)d64, dis_buf);
sewardj1389d4d2005-01-28 13:46:29 +000012291 }
12292 break;
12293
sewardj5e525292005-01-28 15:13:10 +000012294 /* ------------------------ MOVx ------------------------ */
12295
12296 case 0x63: /* MOVSX */
sewardj5b470602005-02-27 13:10:48 +000012297 if (haveF2orF3(pfx)) goto decode_failure;
sewardj5e525292005-01-28 15:13:10 +000012298 if (haveREX(pfx) && 1==getRexW(pfx)) {
12299 vassert(sz == 8);
12300 /* movsx r/m32 to r64 */
12301 modrm = getUChar(delta);
12302 if (epartIsReg(modrm)) {
12303 delta++;
sewardj5b470602005-02-27 13:10:48 +000012304 putIRegG(8, pfx, modrm,
sewardj5e525292005-01-28 15:13:10 +000012305 unop(Iop_32Sto64,
sewardj5b470602005-02-27 13:10:48 +000012306 getIRegE(4, pfx, modrm)));
sewardj5e525292005-01-28 15:13:10 +000012307 DIP("movslq %s,%s\n",
sewardj5b470602005-02-27 13:10:48 +000012308 nameIRegE(4, pfx, modrm),
12309 nameIRegG(8, pfx, modrm));
sewardj5e525292005-01-28 15:13:10 +000012310 break;
12311 } else {
sewardje1698952005-02-08 15:02:39 +000012312 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
sewardj5e525292005-01-28 15:13:10 +000012313 delta += alen;
sewardj5b470602005-02-27 13:10:48 +000012314 putIRegG(8, pfx, modrm,
sewardj5e525292005-01-28 15:13:10 +000012315 unop(Iop_32Sto64,
12316 loadLE(Ity_I32, mkexpr(addr))));
12317 DIP("movslq %s,%s\n", dis_buf,
sewardj5b470602005-02-27 13:10:48 +000012318 nameIRegG(8, pfx, modrm));
sewardj5e525292005-01-28 15:13:10 +000012319 break;
12320 }
12321 } else {
12322 goto decode_failure;
12323 }
12324
sewardj4c328cf2005-05-05 12:05:54 +000012325 /* ------------------------ opl imm, A ----------------- */
12326
12327 case 0x04: /* ADD Ib, AL */
12328 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000012329 delta = dis_op_imm_A( 1, False, Iop_Add8, True, delta, "add" );
sewardj4c328cf2005-05-05 12:05:54 +000012330 break;
sewardj03b07cc2005-01-31 18:09:43 +000012331 case 0x05: /* ADD Iv, eAX */
sewardj5b470602005-02-27 13:10:48 +000012332 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000012333 delta = dis_op_imm_A(sz, False, Iop_Add8, True, delta, "add" );
sewardj03b07cc2005-01-31 18:09:43 +000012334 break;
12335
sewardj007e9ec2005-03-23 11:36:48 +000012336 case 0x0C: /* OR Ib, AL */
12337 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000012338 delta = dis_op_imm_A( 1, False, Iop_Or8, True, delta, "or" );
sewardj007e9ec2005-03-23 11:36:48 +000012339 break;
sewardj03b07cc2005-01-31 18:09:43 +000012340 case 0x0D: /* OR Iv, eAX */
sewardj5b470602005-02-27 13:10:48 +000012341 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000012342 delta = dis_op_imm_A( sz, False, Iop_Or8, True, delta, "or" );
sewardj03b07cc2005-01-31 18:09:43 +000012343 break;
12344
sewardj41c01092005-07-23 13:50:32 +000012345 case 0x14: /* ADC Ib, AL */
12346 delta = dis_op_imm_A( 1, True, Iop_Add8, True, delta, "adc" );
12347 break;
sewardjd20c8852005-01-20 20:04:07 +000012348//.. //-- case 0x15: /* ADC Iv, eAX */
12349//.. //-- delta = dis_op_imm_A( sz, ADC, True, delta, "adc" );
12350//.. //-- break;
sewardj5fadaf92006-05-12 20:45:59 +000012351
12352 case 0x1C: /* SBB Ib, AL */
12353 if (haveF2orF3(pfx)) goto decode_failure;
12354 delta = dis_op_imm_A( 1, True, Iop_Sub8, True, delta, "sbb" );
12355 break;
sewardjd20c8852005-01-20 20:04:07 +000012356//.. //-- case 0x1D: /* SBB Iv, eAX */
12357//.. //-- delta = dis_op_imm_A( sz, SBB, True, delta, "sbb" );
12358//.. //-- break;
12359//.. //--
sewardj007e9ec2005-03-23 11:36:48 +000012360 case 0x24: /* AND Ib, AL */
12361 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000012362 delta = dis_op_imm_A( 1, False, Iop_And8, True, delta, "and" );
sewardj007e9ec2005-03-23 11:36:48 +000012363 break;
sewardj3ca55a12005-01-27 16:06:23 +000012364 case 0x25: /* AND Iv, eAX */
12365 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000012366 delta = dis_op_imm_A( sz, False, Iop_And8, True, delta, "and" );
sewardj3ca55a12005-01-27 16:06:23 +000012367 break;
12368
sewardj137015d2005-03-27 04:01:15 +000012369 case 0x2C: /* SUB Ib, AL */
12370 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000012371 delta = dis_op_imm_A(1, False, Iop_Sub8, True, delta, "sub" );
sewardj137015d2005-03-27 04:01:15 +000012372 break;
sewardj03b07cc2005-01-31 18:09:43 +000012373 case 0x2D: /* SUB Iv, eAX */
sewardj5b470602005-02-27 13:10:48 +000012374 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000012375 delta = dis_op_imm_A( sz, False, Iop_Sub8, True, delta, "sub" );
sewardj03b07cc2005-01-31 18:09:43 +000012376 break;
12377
sewardj8eb804f2005-05-18 10:22:47 +000012378 case 0x34: /* XOR Ib, AL */
12379 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000012380 delta = dis_op_imm_A( 1, False, Iop_Xor8, True, delta, "xor" );
sewardj8eb804f2005-05-18 10:22:47 +000012381 break;
sewardj85520e42005-02-19 15:22:38 +000012382 case 0x35: /* XOR Iv, eAX */
sewardj5b470602005-02-27 13:10:48 +000012383 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000012384 delta = dis_op_imm_A( sz, False, Iop_Xor8, True, delta, "xor" );
sewardj85520e42005-02-19 15:22:38 +000012385 break;
sewardj03b07cc2005-01-31 18:09:43 +000012386
12387 case 0x3C: /* CMP Ib, AL */
12388 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000012389 delta = dis_op_imm_A( 1, False, Iop_Sub8, False, delta, "cmp" );
sewardj03b07cc2005-01-31 18:09:43 +000012390 break;
sewardj354e5c62005-01-27 20:12:52 +000012391 case 0x3D: /* CMP Iv, eAX */
12392 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000012393 delta = dis_op_imm_A( sz, False, Iop_Sub8, False, delta, "cmp" );
sewardj354e5c62005-01-27 20:12:52 +000012394 break;
12395
sewardj118b23e2005-01-29 02:14:44 +000012396 case 0xA8: /* TEST Ib, AL */
sewardj03b07cc2005-01-31 18:09:43 +000012397 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000012398 delta = dis_op_imm_A( 1, False, Iop_And8, False, delta, "test" );
sewardj118b23e2005-01-29 02:14:44 +000012399 break;
12400 case 0xA9: /* TEST Iv, eAX */
sewardj03b07cc2005-01-31 18:09:43 +000012401 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000012402 delta = dis_op_imm_A( sz, False, Iop_And8, False, delta, "test" );
sewardj118b23e2005-01-29 02:14:44 +000012403 break;
12404
12405 /* ------------------------ opl Ev, Gv ----------------- */
12406
sewardj03b07cc2005-01-31 18:09:43 +000012407 case 0x02: /* ADD Eb,Gb */
12408 if (haveF2orF3(pfx)) goto decode_failure;
12409 delta = dis_op2_E_G ( pfx, False, Iop_Add8, True, 1, delta, "add" );
12410 break;
sewardjdf0e0022005-01-25 15:48:43 +000012411 case 0x03: /* ADD Ev,Gv */
sewardj3ca55a12005-01-27 16:06:23 +000012412 if (haveF2orF3(pfx)) goto decode_failure;
sewardjdf0e0022005-01-25 15:48:43 +000012413 delta = dis_op2_E_G ( pfx, False, Iop_Add8, True, sz, delta, "add" );
sewardjdf0e0022005-01-25 15:48:43 +000012414 break;
12415
sewardj03b07cc2005-01-31 18:09:43 +000012416 case 0x0A: /* OR Eb,Gb */
sewardj5b470602005-02-27 13:10:48 +000012417 if (haveF2orF3(pfx)) goto decode_failure;
sewardj03b07cc2005-01-31 18:09:43 +000012418 delta = dis_op2_E_G ( pfx, False, Iop_Or8, True, 1, delta, "or" );
12419 break;
12420 case 0x0B: /* OR Ev,Gv */
sewardj5b470602005-02-27 13:10:48 +000012421 if (haveF2orF3(pfx)) goto decode_failure;
sewardj03b07cc2005-01-31 18:09:43 +000012422 delta = dis_op2_E_G ( pfx, False, Iop_Or8, True, sz, delta, "or" );
12423 break;
12424//--
sewardjd20c8852005-01-20 20:04:07 +000012425//.. //-- case 0x12: /* ADC Eb,Gb */
12426//.. //-- delta = dis_op2_E_G ( sorb, True, ADC, True, 1, delta, "adc" );
12427//.. //-- break;
sewardj22cab062005-07-19 23:59:54 +000012428 case 0x13: /* ADC Ev,Gv */
12429 delta = dis_op2_E_G ( pfx, True, Iop_Add8, True, sz, delta, "adc" );
12430 break;
12431
sewardjd20c8852005-01-20 20:04:07 +000012432//.. //-- case 0x1A: /* SBB Eb,Gb */
12433//.. //-- delta = dis_op2_E_G ( sorb, True, SBB, True, 1, delta, "sbb" );
12434//.. //-- break;
sewardj7a06b852005-07-20 10:55:26 +000012435 case 0x1B: /* SBB Ev,Gv */
12436 delta = dis_op2_E_G ( pfx, True, Iop_Sub8, True, sz, delta, "sbb" );
12437 break;
sewardj03b07cc2005-01-31 18:09:43 +000012438
12439 case 0x22: /* AND Eb,Gb */
12440 if (haveF2orF3(pfx)) goto decode_failure;
12441 delta = dis_op2_E_G ( pfx, False, Iop_And8, True, 1, delta, "and" );
12442 break;
12443 case 0x23: /* AND Ev,Gv */
12444 if (haveF2orF3(pfx)) goto decode_failure;
12445 delta = dis_op2_E_G ( pfx, False, Iop_And8, True, sz, delta, "and" );
12446 break;
12447
12448 case 0x2A: /* SUB Eb,Gb */
12449 if (haveF2orF3(pfx)) goto decode_failure;
12450 delta = dis_op2_E_G ( pfx, False, Iop_Sub8, True, 1, delta, "sub" );
12451 break;
sewardj118b23e2005-01-29 02:14:44 +000012452 case 0x2B: /* SUB Ev,Gv */
sewardj03b07cc2005-01-31 18:09:43 +000012453 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000012454 delta = dis_op2_E_G ( pfx, False, Iop_Sub8, True, sz, delta, "sub" );
12455 break;
12456
sewardj03b07cc2005-01-31 18:09:43 +000012457 case 0x32: /* XOR Eb,Gb */
12458 if (haveF2orF3(pfx)) goto decode_failure;
12459 delta = dis_op2_E_G ( pfx, False, Iop_Xor8, True, 1, delta, "xor" );
12460 break;
12461 case 0x33: /* XOR Ev,Gv */
12462 if (haveF2orF3(pfx)) goto decode_failure;
12463 delta = dis_op2_E_G ( pfx, False, Iop_Xor8, True, sz, delta, "xor" );
12464 break;
12465
sewardjb095fba2005-02-13 14:13:04 +000012466 case 0x3A: /* CMP Eb,Gb */
12467 if (haveF2orF3(pfx)) goto decode_failure;
12468 delta = dis_op2_E_G ( pfx, False, Iop_Sub8, False, 1, delta, "cmp" );
12469 break;
sewardj354e5c62005-01-27 20:12:52 +000012470 case 0x3B: /* CMP Ev,Gv */
12471 if (haveF2orF3(pfx)) goto decode_failure;
12472 delta = dis_op2_E_G ( pfx, False, Iop_Sub8, False, sz, delta, "cmp" );
12473 break;
12474
sewardj118b23e2005-01-29 02:14:44 +000012475 case 0x84: /* TEST Eb,Gb */
sewardj03b07cc2005-01-31 18:09:43 +000012476 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000012477 delta = dis_op2_E_G ( pfx, False, Iop_And8, False, 1, delta, "test" );
12478 break;
12479 case 0x85: /* TEST Ev,Gv */
sewardj03b07cc2005-01-31 18:09:43 +000012480 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000012481 delta = dis_op2_E_G ( pfx, False, Iop_And8, False, sz, delta, "test" );
12482 break;
12483
12484 /* ------------------------ opl Gv, Ev ----------------- */
12485
sewardj85520e42005-02-19 15:22:38 +000012486 case 0x00: /* ADD Gb,Eb */
12487 if (haveF2orF3(pfx)) goto decode_failure;
12488 delta = dis_op2_G_E ( pfx, False, Iop_Add8, True, 1, delta, "add" );
12489 break;
sewardj3ca55a12005-01-27 16:06:23 +000012490 case 0x01: /* ADD Gv,Ev */
sewardj354e5c62005-01-27 20:12:52 +000012491 if (haveF2orF3(pfx)) goto decode_failure;
sewardj3ca55a12005-01-27 16:06:23 +000012492 delta = dis_op2_G_E ( pfx, False, Iop_Add8, True, sz, delta, "add" );
12493 break;
12494
sewardj03b07cc2005-01-31 18:09:43 +000012495 case 0x08: /* OR Gb,Eb */
12496 if (haveF2orF3(pfx)) goto decode_failure;
12497 delta = dis_op2_G_E ( pfx, False, Iop_Or8, True, 1, delta, "or" );
12498 break;
sewardj55dbb262005-01-28 16:36:51 +000012499 case 0x09: /* OR Gv,Ev */
12500 if (haveF2orF3(pfx)) goto decode_failure;
12501 delta = dis_op2_G_E ( pfx, False, Iop_Or8, True, sz, delta, "or" );
12502 break;
12503
sewardj85520e42005-02-19 15:22:38 +000012504 case 0x10: /* ADC Gb,Eb */
12505 if (haveF2orF3(pfx)) goto decode_failure;
12506 delta = dis_op2_G_E ( pfx, True, Iop_Add8, True, 1, delta, "adc" );
12507 break;
12508 case 0x11: /* ADC Gv,Ev */
12509 if (haveF2orF3(pfx)) goto decode_failure;
12510 delta = dis_op2_G_E ( pfx, True, Iop_Add8, True, sz, delta, "adc" );
12511 break;
12512
12513 case 0x18: /* SBB Gb,Eb */
12514 if (haveF2orF3(pfx)) goto decode_failure;
12515 delta = dis_op2_G_E ( pfx, True, Iop_Sub8, True, 1, delta, "sbb" );
12516 break;
sewardj03b07cc2005-01-31 18:09:43 +000012517 case 0x19: /* SBB Gv,Ev */
sewardja6b93d12005-02-17 09:28:28 +000012518 if (haveF2orF3(pfx)) goto decode_failure;
sewardj03b07cc2005-01-31 18:09:43 +000012519 delta = dis_op2_G_E ( pfx, True, Iop_Sub8, True, sz, delta, "sbb" );
12520 break;
12521
sewardj85520e42005-02-19 15:22:38 +000012522 case 0x20: /* AND Gb,Eb */
12523 if (haveF2orF3(pfx)) goto decode_failure;
12524 delta = dis_op2_G_E ( pfx, False, Iop_And8, True, 1, delta, "and" );
12525 break;
sewardj3ca55a12005-01-27 16:06:23 +000012526 case 0x21: /* AND Gv,Ev */
sewardj354e5c62005-01-27 20:12:52 +000012527 if (haveF2orF3(pfx)) goto decode_failure;
sewardj3ca55a12005-01-27 16:06:23 +000012528 delta = dis_op2_G_E ( pfx, False, Iop_And8, True, sz, delta, "and" );
12529 break;
sewardj03b07cc2005-01-31 18:09:43 +000012530
12531 case 0x28: /* SUB Gb,Eb */
12532 if (haveF2orF3(pfx)) goto decode_failure;
12533 delta = dis_op2_G_E ( pfx, False, Iop_Sub8, True, 1, delta, "sub" );
12534 break;
sewardj118b23e2005-01-29 02:14:44 +000012535 case 0x29: /* SUB Gv,Ev */
sewardj03b07cc2005-01-31 18:09:43 +000012536 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000012537 delta = dis_op2_G_E ( pfx, False, Iop_Sub8, True, sz, delta, "sub" );
12538 break;
12539
sewardjb095fba2005-02-13 14:13:04 +000012540 case 0x30: /* XOR Gb,Eb */
12541 if (haveF2orF3(pfx)) goto decode_failure;
12542 delta = dis_op2_G_E ( pfx, False, Iop_Xor8, True, 1, delta, "xor" );
12543 break;
sewardj118b23e2005-01-29 02:14:44 +000012544 case 0x31: /* XOR Gv,Ev */
sewardj03b07cc2005-01-31 18:09:43 +000012545 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000012546 delta = dis_op2_G_E ( pfx, False, Iop_Xor8, True, sz, delta, "xor" );
12547 break;
sewardj354e5c62005-01-27 20:12:52 +000012548
12549 case 0x38: /* CMP Gb,Eb */
12550 if (haveF2orF3(pfx)) goto decode_failure;
12551 delta = dis_op2_G_E ( pfx, False, Iop_Sub8, False, 1, delta, "cmp" );
12552 break;
12553 case 0x39: /* CMP Gv,Ev */
12554 if (haveF2orF3(pfx)) goto decode_failure;
12555 delta = dis_op2_G_E ( pfx, False, Iop_Sub8, False, sz, delta, "cmp" );
12556 break;
12557
sewardj55dbb262005-01-28 16:36:51 +000012558 /* ------------------------ POP ------------------------ */
12559
12560 case 0x58: /* POP eAX */
12561 case 0x59: /* POP eCX */
12562 case 0x5A: /* POP eDX */
12563 case 0x5B: /* POP eBX */
12564 case 0x5D: /* POP eBP */
12565 case 0x5E: /* POP eSI */
12566 case 0x5F: /* POP eDI */
12567 case 0x5C: /* POP eSP */
sewardj03b07cc2005-01-31 18:09:43 +000012568 if (haveF2orF3(pfx)) goto decode_failure;
sewardj55dbb262005-01-28 16:36:51 +000012569 vassert(sz == 2 || sz == 4 || sz == 8);
12570 if (sz == 4)
12571 sz = 8; /* there is no encoding for 32-bit pop in 64-bit mode */
12572 t1 = newTemp(szToITy(sz));
12573 t2 = newTemp(Ity_I64);
12574 assign(t2, getIReg64(R_RSP));
12575 assign(t1, loadLE(szToITy(sz),mkexpr(t2)));
12576 putIReg64(R_RSP, binop(Iop_Add64, mkexpr(t2), mkU64(sz)));
sewardj5b470602005-02-27 13:10:48 +000012577 putIRegRexB(sz, pfx, opc-0x58, mkexpr(t1));
12578 DIP("pop%c %s\n", nameISize(sz), nameIRegRexB(sz,pfx,opc-0x58));
sewardj55dbb262005-01-28 16:36:51 +000012579 break;
12580
sewardj85520e42005-02-19 15:22:38 +000012581 case 0x9D: /* POPF */
12582 /* Note. There is no encoding for a 32-bit popf in 64-bit mode.
12583 So sz==4 actually means sz==8. */
sewardj5b470602005-02-27 13:10:48 +000012584 if (haveF2orF3(pfx)) goto decode_failure;
sewardj85520e42005-02-19 15:22:38 +000012585 vassert(sz == 2 || sz == 4);
12586 if (sz == 4) sz = 8;
sewardj5b470602005-02-27 13:10:48 +000012587 if (sz != 8) goto decode_failure; // until we know a sz==2 test case exists
sewardj85520e42005-02-19 15:22:38 +000012588 t1 = newTemp(Ity_I64); t2 = newTemp(Ity_I64);
12589 assign(t2, getIReg64(R_RSP));
12590 assign(t1, widenUto64(loadLE(szToITy(sz),mkexpr(t2))));
12591 putIReg64(R_RSP, binop(Iop_Add64, mkexpr(t2), mkU64(sz)));
12592 /* t1 is the flag word. Mask out everything except OSZACP and
12593 set the flags thunk to AMD64G_CC_OP_COPY. */
12594 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(AMD64G_CC_OP_COPY) ));
12595 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
12596 stmt( IRStmt_Put( OFFB_CC_DEP1,
12597 binop(Iop_And64,
12598 mkexpr(t1),
12599 mkU64( AMD64G_CC_MASK_C | AMD64G_CC_MASK_P
12600 | AMD64G_CC_MASK_A | AMD64G_CC_MASK_Z
12601 | AMD64G_CC_MASK_S| AMD64G_CC_MASK_O )
12602 )
12603 )
12604 );
12605
12606 /* Also need to set the D flag, which is held in bit 10 of t1.
12607 If zero, put 1 in OFFB_DFLAG, else -1 in OFFB_DFLAG. */
12608 stmt( IRStmt_Put(
12609 OFFB_DFLAG,
12610 IRExpr_Mux0X(
12611 unop(Iop_32to8,
12612 unop(Iop_64to32,
12613 binop(Iop_And64,
12614 binop(Iop_Shr64, mkexpr(t1), mkU8(10)),
12615 mkU64(1)))),
12616 mkU64(1),
12617 mkU64(0xFFFFFFFFFFFFFFFFULL)))
12618 );
12619
12620 /* And set the ID flag */
12621 stmt( IRStmt_Put(
12622 OFFB_IDFLAG,
12623 IRExpr_Mux0X(
12624 unop(Iop_32to8,
12625 unop(Iop_64to32,
12626 binop(Iop_And64,
12627 binop(Iop_Shr64, mkexpr(t1), mkU8(21)),
12628 mkU64(1)))),
12629 mkU64(0),
12630 mkU64(1)))
12631 );
12632
12633 DIP("popf%c\n", nameISize(sz));
12634 break;
12635
sewardjd20c8852005-01-20 20:04:07 +000012636//.. case 0x61: /* POPA */
12637//.. /* This is almost certainly wrong for sz==2. So ... */
12638//.. if (sz != 4) goto decode_failure;
12639//..
12640//.. /* t5 is the old %ESP value. */
12641//.. t5 = newTemp(Ity_I32);
12642//.. assign( t5, getIReg(4, R_ESP) );
12643//..
12644//.. /* Reload all the registers, except %esp. */
12645//.. putIReg(4,R_EAX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(28)) ));
12646//.. putIReg(4,R_ECX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(24)) ));
12647//.. putIReg(4,R_EDX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(20)) ));
12648//.. putIReg(4,R_EBX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(16)) ));
12649//.. /* ignore saved %ESP */
12650//.. putIReg(4,R_EBP, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32( 8)) ));
12651//.. putIReg(4,R_ESI, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32( 4)) ));
12652//.. putIReg(4,R_EDI, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32( 0)) ));
12653//..
12654//.. /* and move %ESP back up */
12655//.. putIReg( 4, R_ESP, binop(Iop_Add32, mkexpr(t5), mkU32(8*4)) );
12656//..
12657//.. DIP("pusha%c\n", nameISize(sz));
12658//.. break;
sewardj432f8b62005-05-10 02:50:05 +000012659
12660 case 0x8F: { /* POPQ m64 / POPW m16 */
sewardj1bd14e72005-05-11 16:24:00 +000012661 Int len;
12662 UChar rm;
sewardj432f8b62005-05-10 02:50:05 +000012663 /* There is no encoding for 32-bit pop in 64-bit mode.
12664 So sz==4 actually means sz==8. */
12665 if (haveF2orF3(pfx)) goto decode_failure;
12666 vassert(sz == 2 || sz == 4);
12667 if (sz == 4) sz = 8;
12668 if (sz != 8) goto decode_failure; // until we know a sz==2 test case exists
12669
sewardj1bd14e72005-05-11 16:24:00 +000012670 rm = getUChar(delta);
sewardj432f8b62005-05-10 02:50:05 +000012671
12672 /* make sure this instruction is correct POP */
12673 if (epartIsReg(rm) || gregLO3ofRM(rm) != 0)
12674 goto decode_failure;
12675 /* and has correct size */
12676 vassert(sz == 8);
12677
12678 t1 = newTemp(Ity_I64);
12679 t3 = newTemp(Ity_I64);
12680 assign( t1, getIReg64(R_RSP) );
12681 assign( t3, loadLE(Ity_I64, mkexpr(t1)) );
12682
12683 /* Increase RSP; must be done before the STORE. Intel manual
12684 says: If the RSP register is used as a base register for
12685 addressing a destination operand in memory, the POP
12686 instruction computes the effective address of the operand
12687 after it increments the RSP register. */
12688 putIReg64(R_RSP, binop(Iop_Add64, mkexpr(t1), mkU64(sz)) );
12689
12690 addr = disAMode ( &len, pfx, delta, dis_buf, 0 );
12691 storeLE( mkexpr(addr), mkexpr(t3) );
12692
12693 DIP("popl %s\n", dis_buf);
12694
12695 delta += len;
12696 break;
12697 }
12698
sewardjd20c8852005-01-20 20:04:07 +000012699//.. //-- case 0x1F: /* POP %DS */
12700//.. //-- dis_pop_segreg( cb, R_DS, sz ); break;
12701//.. //-- case 0x07: /* POP %ES */
12702//.. //-- dis_pop_segreg( cb, R_ES, sz ); break;
12703//.. //-- case 0x17: /* POP %SS */
12704//.. //-- dis_pop_segreg( cb, R_SS, sz ); break;
sewardj55dbb262005-01-28 16:36:51 +000012705
12706 /* ------------------------ PUSH ----------------------- */
12707
12708 case 0x50: /* PUSH eAX */
12709 case 0x51: /* PUSH eCX */
12710 case 0x52: /* PUSH eDX */
12711 case 0x53: /* PUSH eBX */
12712 case 0x55: /* PUSH eBP */
12713 case 0x56: /* PUSH eSI */
12714 case 0x57: /* PUSH eDI */
12715 case 0x54: /* PUSH eSP */
12716 /* This is the Right Way, in that the value to be pushed is
12717 established before %rsp is changed, so that pushq %rsp
12718 correctly pushes the old value. */
sewardj03b07cc2005-01-31 18:09:43 +000012719 if (haveF2orF3(pfx)) goto decode_failure;
sewardj55dbb262005-01-28 16:36:51 +000012720 vassert(sz == 2 || sz == 4 || sz == 8);
12721 if (sz == 4)
12722 sz = 8; /* there is no encoding for 32-bit push in 64-bit mode */
12723 ty = sz==2 ? Ity_I16 : Ity_I64;
12724 t1 = newTemp(ty);
12725 t2 = newTemp(Ity_I64);
sewardj5b470602005-02-27 13:10:48 +000012726 assign(t1, getIRegRexB(sz, pfx, opc-0x50));
sewardj55dbb262005-01-28 16:36:51 +000012727 assign(t2, binop(Iop_Sub64, getIReg64(R_RSP), mkU64(sz)));
12728 putIReg64(R_RSP, mkexpr(t2) );
12729 storeLE(mkexpr(t2),mkexpr(t1));
sewardj5b470602005-02-27 13:10:48 +000012730 DIP("push%c %s\n", nameISize(sz), nameIRegRexB(sz,pfx,opc-0x50));
sewardj55dbb262005-01-28 16:36:51 +000012731 break;
12732
sewardja6b93d12005-02-17 09:28:28 +000012733 case 0x68: /* PUSH Iv */
sewardj5b470602005-02-27 13:10:48 +000012734 if (haveF2orF3(pfx)) goto decode_failure;
sewardja6b93d12005-02-17 09:28:28 +000012735 /* Note, sz==4 is not possible in 64-bit mode. Hence ... */
12736 if (sz == 4) sz = 8;
12737 d64 = getSDisp(imin(4,sz),delta);
12738 delta += imin(4,sz);
12739 goto do_push_I;
sewardj909c06d2005-02-19 22:47:41 +000012740 case 0x6A: /* PUSH Ib, sign-extended to sz */
sewardj5b470602005-02-27 13:10:48 +000012741 if (haveF2orF3(pfx)) goto decode_failure;
sewardj909c06d2005-02-19 22:47:41 +000012742 /* Note, sz==4 is not possible in 64-bit mode. Hence ... */
12743 if (sz == 4) sz = 8;
12744 d64 = getSDisp8(delta); delta += 1;
12745 goto do_push_I;
sewardja6b93d12005-02-17 09:28:28 +000012746 do_push_I:
12747 ty = szToITy(sz);
sewardj909c06d2005-02-19 22:47:41 +000012748 t1 = newTemp(Ity_I64);
12749 t2 = newTemp(ty);
sewardja6b93d12005-02-17 09:28:28 +000012750 assign( t1, binop(Iop_Sub64,getIReg64(R_RSP),mkU64(sz)) );
12751 putIReg64(R_RSP, mkexpr(t1) );
12752 storeLE( mkexpr(t1), mkU(ty,d64) );
sewardj1027dc22005-02-26 01:55:02 +000012753 DIP("push%c $%lld\n", nameISize(sz), (Long)d64);
sewardja6b93d12005-02-17 09:28:28 +000012754 break;
12755
sewardj85520e42005-02-19 15:22:38 +000012756 case 0x9C: /* PUSHF */ {
12757 /* Note. There is no encoding for a 32-bit pushf in 64-bit
12758 mode. So sz==4 actually means sz==8. */
sewardj5b470602005-02-27 13:10:48 +000012759 if (haveF2orF3(pfx)) goto decode_failure;
sewardj85520e42005-02-19 15:22:38 +000012760 vassert(sz == 2 || sz == 4);
12761 if (sz == 4) sz = 8;
sewardj5b470602005-02-27 13:10:48 +000012762 if (sz != 8) goto decode_failure; // until we know a sz==2 test case exists
sewardj85520e42005-02-19 15:22:38 +000012763
12764 t1 = newTemp(Ity_I64);
12765 assign( t1, binop(Iop_Sub64,getIReg64(R_RSP),mkU64(sz)) );
12766 putIReg64(R_RSP, mkexpr(t1) );
12767
12768 t2 = newTemp(Ity_I64);
12769 assign( t2, mk_amd64g_calculate_rflags_all() );
12770
12771 /* Patch in the D flag. This can simply be a copy of bit 10 of
12772 baseBlock[OFFB_DFLAG]. */
12773 t3 = newTemp(Ity_I64);
12774 assign( t3, binop(Iop_Or64,
12775 mkexpr(t2),
12776 binop(Iop_And64,
12777 IRExpr_Get(OFFB_DFLAG,Ity_I64),
12778 mkU64(1<<10)))
12779 );
12780
12781 /* And patch in the ID flag. */
12782 t4 = newTemp(Ity_I64);
12783 assign( t4, binop(Iop_Or64,
12784 mkexpr(t3),
12785 binop(Iop_And64,
12786 binop(Iop_Shl64, IRExpr_Get(OFFB_IDFLAG,Ity_I64),
12787 mkU8(21)),
12788 mkU64(1<<21)))
12789 );
12790
12791 /* if sz==2, the stored value needs to be narrowed. */
12792 if (sz == 2)
12793 storeLE( mkexpr(t1), unop(Iop_32to16,
12794 unop(Iop_64to32,mkexpr(t4))) );
12795 else
12796 storeLE( mkexpr(t1), mkexpr(t4) );
12797
12798 DIP("pushf%c\n", nameISize(sz));
12799 break;
12800 }
12801
sewardjd20c8852005-01-20 20:04:07 +000012802//.. case 0x60: /* PUSHA */
12803//.. /* This is almost certainly wrong for sz==2. So ... */
12804//.. if (sz != 4) goto decode_failure;
12805//..
12806//.. /* This is the Right Way, in that the value to be pushed is
12807//.. established before %esp is changed, so that pusha
12808//.. correctly pushes the old %esp value. New value of %esp is
12809//.. pushed at start. */
12810//.. /* t0 is the %ESP value we're going to push. */
12811//.. t0 = newTemp(Ity_I32);
12812//.. assign( t0, getIReg(4, R_ESP) );
12813//..
12814//.. /* t5 will be the new %ESP value. */
12815//.. t5 = newTemp(Ity_I32);
12816//.. assign( t5, binop(Iop_Sub32, mkexpr(t0), mkU32(8*4)) );
12817//..
12818//.. /* Update guest state before prodding memory. */
12819//.. putIReg(4, R_ESP, mkexpr(t5));
12820//..
12821//.. /* Dump all the registers. */
12822//.. storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(28)), getIReg(4,R_EAX) );
12823//.. storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(24)), getIReg(4,R_ECX) );
12824//.. storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(20)), getIReg(4,R_EDX) );
12825//.. storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(16)), getIReg(4,R_EBX) );
12826//.. storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(12)), mkexpr(t0) /*esp*/);
12827//.. storeLE( binop(Iop_Add32,mkexpr(t5),mkU32( 8)), getIReg(4,R_EBP) );
12828//.. storeLE( binop(Iop_Add32,mkexpr(t5),mkU32( 4)), getIReg(4,R_ESI) );
12829//.. storeLE( binop(Iop_Add32,mkexpr(t5),mkU32( 0)), getIReg(4,R_EDI) );
12830//..
12831//.. DIP("pusha%c\n", nameISize(sz));
12832//.. break;
12833//..
12834//..
12835//.. //-- case 0x0E: /* PUSH %CS */
12836//.. //-- dis_push_segreg( cb, R_CS, sz ); break;
12837//.. //-- case 0x1E: /* PUSH %DS */
12838//.. //-- dis_push_segreg( cb, R_DS, sz ); break;
12839//.. //-- case 0x06: /* PUSH %ES */
12840//.. //-- dis_push_segreg( cb, R_ES, sz ); break;
12841//.. //-- case 0x16: /* PUSH %SS */
12842//.. //-- dis_push_segreg( cb, R_SS, sz ); break;
12843//..
12844//.. /* ------------------------ SCAS et al ----------------- */
12845//..
12846//.. case 0xA4: /* MOVS, no REP prefix */
12847//.. case 0xA5:
12848//.. dis_string_op( dis_MOVS, ( opc == 0xA4 ? 1 : sz ), "movs", sorb );
12849//.. break;
12850//..
12851//.. case 0xA6: /* CMPSb, no REP prefix */
12852//.. //-- case 0xA7:
12853//.. dis_string_op( dis_CMPS, ( opc == 0xA6 ? 1 : sz ), "cmps", sorb );
12854//.. break;
12855//.. //--
sewardjd20c8852005-01-20 20:04:07 +000012856//.. //--
12857//.. //-- case 0xAC: /* LODS, no REP prefix */
12858//.. //-- case 0xAD:
12859//.. //-- dis_string_op( cb, dis_LODS, ( opc == 0xAC ? 1 : sz ), "lods", sorb );
12860//.. //-- break;
12861//..
12862//.. case 0xAE: /* SCAS, no REP prefix */
12863//.. case 0xAF:
12864//.. dis_string_op( dis_SCAS, ( opc == 0xAE ? 1 : sz ), "scas", sorb );
12865//.. break;
sewardjd0a12df2005-02-10 02:07:43 +000012866
12867
12868 case 0xFC: /* CLD */
sewardj5b470602005-02-27 13:10:48 +000012869 if (haveF2orF3(pfx)) goto decode_failure;
sewardjd0a12df2005-02-10 02:07:43 +000012870 stmt( IRStmt_Put( OFFB_DFLAG, mkU64(1)) );
12871 DIP("cld\n");
12872 break;
12873
sewardj909c06d2005-02-19 22:47:41 +000012874 case 0xFD: /* STD */
sewardj5b470602005-02-27 13:10:48 +000012875 if (haveF2orF3(pfx)) goto decode_failure;
sewardj909c06d2005-02-19 22:47:41 +000012876 stmt( IRStmt_Put( OFFB_DFLAG, mkU64(-1ULL)) );
12877 DIP("std\n");
12878 break;
12879
sewardj31804462006-05-12 20:15:33 +000012880 case 0xF8: /* CLC */
12881 case 0xF9: /* STC */
12882 case 0xF5: /* CMC */
12883 t0 = newTemp(Ity_I64);
12884 t1 = newTemp(Ity_I64);
12885 assign( t0, mk_amd64g_calculate_rflags_all() );
12886 switch (opc) {
12887 case 0xF8:
12888 assign( t1, binop(Iop_And64, mkexpr(t0),
12889 mkU64(~AMD64G_CC_MASK_C)));
12890 DIP("clc\n");
12891 break;
12892 case 0xF9:
12893 assign( t1, binop(Iop_Or64, mkexpr(t0),
12894 mkU64(AMD64G_CC_MASK_C)));
12895 DIP("stc\n");
12896 break;
12897 case 0xF5:
12898 assign( t1, binop(Iop_Xor64, mkexpr(t0),
12899 mkU64(AMD64G_CC_MASK_C)));
12900 DIP("cmc\n");
12901 break;
12902 default:
12903 vpanic("disInstr(x64)(clc/stc/cmc)");
12904 }
12905 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(AMD64G_CC_OP_COPY) ));
12906 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
12907 stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(t1) ));
12908 /* Set NDEP even though it isn't used. This makes redundant-PUT
12909 elimination of previous stores to this field work better. */
12910 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU64(0) ));
12911 break;
12912
sewardjd20c8852005-01-20 20:04:07 +000012913//.. /* REPNE prefix insn */
12914//.. case 0xF2: {
12915//.. Addr32 eip_orig = guest_eip_bbstart + delta - 1;
12916//.. vassert(sorb == 0);
sewardj8c332e22005-01-28 01:36:56 +000012917//.. abyte = getUChar(delta); delta++;
sewardjd20c8852005-01-20 20:04:07 +000012918//..
sewardj8c332e22005-01-28 01:36:56 +000012919//.. if (abyte == 0x66) { sz = 2; abyte = getUChar(delta); delta++; }
sewardjd20c8852005-01-20 20:04:07 +000012920//.. whatNext = Dis_StopHere;
12921//..
12922//.. switch (abyte) {
12923//.. /* According to the Intel manual, "repne movs" should never occur, but
12924//.. * in practice it has happened, so allow for it here... */
12925//.. case 0xA4: sz = 1; /* REPNE MOVS<sz> */
12926//.. goto decode_failure;
12927//.. //-- case 0xA5:
12928//.. // dis_REP_op ( CondNZ, dis_MOVS, sz, eip_orig,
12929//.. // guest_eip_bbstart+delta, "repne movs" );
12930//.. // break;
12931//.. //--
12932//.. //-- case 0xA6: sz = 1; /* REPNE CMPS<sz> */
12933//.. //-- case 0xA7:
12934//.. //-- dis_REP_op ( cb, CondNZ, dis_CMPS, sz, eip_orig, eip, "repne cmps" );
12935//.. //-- break;
12936//.. //--
12937//.. case 0xAE: sz = 1; /* REPNE SCAS<sz> */
12938//.. case 0xAF:
12939//.. dis_REP_op ( X86CondNZ, dis_SCAS, sz, eip_orig,
12940//.. guest_eip_bbstart+delta, "repne scas" );
12941//.. break;
12942//..
12943//.. default:
12944//.. goto decode_failure;
12945//.. }
12946//.. break;
12947//.. }
sewardjd0a12df2005-02-10 02:07:43 +000012948
sewardj909c06d2005-02-19 22:47:41 +000012949 /* ------ AE: SCAS variants ------ */
12950 case 0xAE:
12951 case 0xAF:
12952 /* F2 AE/AF: repne scasb/repne scas{w,l,q} */
sewardj42561ef2005-11-04 14:18:31 +000012953 if (haveASO(pfx))
12954 goto decode_failure;
sewardj85520e42005-02-19 15:22:38 +000012955 if (haveF2(pfx) && !haveF3(pfx)) {
12956 if (opc == 0xAE)
12957 sz = 1;
12958 dis_REP_op ( AMD64CondNZ, dis_SCAS, sz,
sewardj9e6491a2005-07-02 19:24:10 +000012959 guest_RIP_curr_instr,
12960 guest_RIP_bbstart+delta, "repne scas", pfx );
12961 dres.whatNext = Dis_StopHere;
sewardj85520e42005-02-19 15:22:38 +000012962 break;
12963 }
sewardj909c06d2005-02-19 22:47:41 +000012964 /* AE/AF: scasb/scas{w,l,q} */
12965 if (!haveF2(pfx) && !haveF3(pfx)) {
12966 if (opc == 0xAE)
12967 sz = 1;
12968 dis_string_op( dis_SCAS, sz, "scas", pfx );
12969 break;
12970 }
sewardj85520e42005-02-19 15:22:38 +000012971 goto decode_failure;
sewardjd0a12df2005-02-10 02:07:43 +000012972
sewardj909c06d2005-02-19 22:47:41 +000012973 /* ------ A6, A7: CMPS variants ------ */
12974 case 0xA6:
12975 case 0xA7:
12976 /* F3 A6/A7: repe cmps/rep cmps{w,l,q} */
sewardj42561ef2005-11-04 14:18:31 +000012977 if (haveASO(pfx))
12978 goto decode_failure;
sewardjd0a12df2005-02-10 02:07:43 +000012979 if (haveF3(pfx) && !haveF2(pfx)) {
12980 if (opc == 0xA6)
12981 sz = 1;
12982 dis_REP_op ( AMD64CondZ, dis_CMPS, sz,
sewardj9e6491a2005-07-02 19:24:10 +000012983 guest_RIP_curr_instr,
12984 guest_RIP_bbstart+delta, "repe cmps", pfx );
12985 dres.whatNext = Dis_StopHere;
sewardja6b93d12005-02-17 09:28:28 +000012986 break;
12987 }
12988 goto decode_failure;
12989
sewardj909c06d2005-02-19 22:47:41 +000012990 /* ------ AA, AB: STOS variants ------ */
12991 case 0xAA:
12992 case 0xAB:
12993 /* F3 AA/AB: rep stosb/rep stos{w,l,q} */
sewardj42561ef2005-11-04 14:18:31 +000012994 if (haveASO(pfx))
12995 goto decode_failure;
sewardja6b93d12005-02-17 09:28:28 +000012996 if (haveF3(pfx) && !haveF2(pfx)) {
sewardj909c06d2005-02-19 22:47:41 +000012997 if (opc == 0xAA)
12998 sz = 1;
sewardja6b93d12005-02-17 09:28:28 +000012999 dis_REP_op ( AMD64CondAlways, dis_STOS, sz,
sewardj9e6491a2005-07-02 19:24:10 +000013000 guest_RIP_curr_instr,
13001 guest_RIP_bbstart+delta, "rep stos", pfx );
13002 dres.whatNext = Dis_StopHere;
sewardj909c06d2005-02-19 22:47:41 +000013003 break;
13004 }
13005 /* AA/AB: stosb/stos{w,l,q} */
13006 if (!haveF3(pfx) && !haveF2(pfx)) {
13007 if (opc == 0xAA)
13008 sz = 1;
13009 dis_string_op( dis_STOS, sz, "stos", pfx );
sewardjd0a12df2005-02-10 02:07:43 +000013010 break;
13011 }
13012 goto decode_failure;
13013
sewardj909c06d2005-02-19 22:47:41 +000013014 /* ------ A4, A5: MOVS variants ------ */
13015 case 0xA4:
13016 case 0xA5:
13017 /* F3 A4: rep movsb */
sewardj42561ef2005-11-04 14:18:31 +000013018 if (haveASO(pfx))
13019 goto decode_failure;
sewardj909c06d2005-02-19 22:47:41 +000013020 if (haveF3(pfx) && !haveF2(pfx)) {
13021 if (opc == 0xA4)
13022 sz = 1;
13023 dis_REP_op ( AMD64CondAlways, dis_MOVS, sz,
sewardj9e6491a2005-07-02 19:24:10 +000013024 guest_RIP_curr_instr,
13025 guest_RIP_bbstart+delta, "rep movs", pfx );
13026 dres.whatNext = Dis_StopHere;
sewardj909c06d2005-02-19 22:47:41 +000013027 break;
13028 }
13029 /* A4: movsb */
13030 if (!haveF3(pfx) && !haveF2(pfx)) {
13031 if (opc == 0xA4)
13032 sz = 1;
13033 dis_string_op( dis_MOVS, sz, "movs", pfx );
13034 break;
13035 }
13036 goto decode_failure;
13037
sewardj7de0d3c2005-02-13 02:26:41 +000013038
13039 /* ------------------------ XCHG ----------------------- */
13040
sewardj1bf95982005-05-18 12:04:04 +000013041 case 0x86: /* XCHG Gb,Eb */
13042 sz = 1;
13043 /* Fall through ... */
sewardj7de0d3c2005-02-13 02:26:41 +000013044 case 0x87: /* XCHG Gv,Ev */
sewardj5b470602005-02-27 13:10:48 +000013045 if (haveF2orF3(pfx)) goto decode_failure;
sewardj7de0d3c2005-02-13 02:26:41 +000013046 modrm = getUChar(delta);
13047 ty = szToITy(sz);
13048 t1 = newTemp(ty); t2 = newTemp(ty);
13049 if (epartIsReg(modrm)) {
sewardj5b470602005-02-27 13:10:48 +000013050 assign(t1, getIRegE(sz, pfx, modrm));
13051 assign(t2, getIRegG(sz, pfx, modrm));
13052 putIRegG(sz, pfx, modrm, mkexpr(t1));
13053 putIRegE(sz, pfx, modrm, mkexpr(t2));
sewardj7de0d3c2005-02-13 02:26:41 +000013054 delta++;
13055 DIP("xchg%c %s, %s\n",
sewardj5b470602005-02-27 13:10:48 +000013056 nameISize(sz), nameIRegG(sz, pfx, modrm),
13057 nameIRegE(sz, pfx, modrm));
sewardj7de0d3c2005-02-13 02:26:41 +000013058 } else {
sewardj7de0d3c2005-02-13 02:26:41 +000013059 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
sewardj5b470602005-02-27 13:10:48 +000013060 assign( t1, loadLE(ty, mkexpr(addr)) );
13061 assign( t2, getIRegG(sz, pfx, modrm) );
sewardj7de0d3c2005-02-13 02:26:41 +000013062 storeLE( mkexpr(addr), mkexpr(t2) );
sewardj5b470602005-02-27 13:10:48 +000013063 putIRegG( sz, pfx, modrm, mkexpr(t1) );
sewardj7de0d3c2005-02-13 02:26:41 +000013064 delta += alen;
13065 DIP("xchg%c %s, %s\n", nameISize(sz),
sewardj5b470602005-02-27 13:10:48 +000013066 nameIRegG(sz, pfx, modrm), dis_buf);
sewardj7de0d3c2005-02-13 02:26:41 +000013067 }
13068 break;
sewardj118b23e2005-01-29 02:14:44 +000013069
13070 case 0x90: /* XCHG eAX,eAX */
sewardjc8b26352005-07-20 09:23:13 +000013071 /* detect and handle F3 90 (rep nop) specially */
13072 if (!have66(pfx) && !haveF2(pfx) && haveF3(pfx)) {
13073 DIP("rep nop (P4 pause)\n");
13074 /* "observe" the hint. The Vex client needs to be careful not
13075 to cause very long delays as a result, though. */
13076 jmp_lit(Ijk_Yield, guest_RIP_bbstart+delta);
13077 dres.whatNext = Dis_StopHere;
13078 break;
13079 }
sewardj2d4fcd52005-05-18 11:47:47 +000013080 /* detect and handle NOPs specially */
13081 if (/* F2/F3 probably change meaning completely */
13082 !haveF2orF3(pfx)
13083 /* If REX.B is 1, we're not exchanging rAX with itself */
13084 && getRexB(pfx)==0 ) {
13085 DIP("nop\n");
13086 break;
13087 }
13088 /* else fall through to normal case. */
sewardja6b93d12005-02-17 09:28:28 +000013089 case 0x91: /* XCHG rAX,rCX */
13090 case 0x92: /* XCHG rAX,rDX */
13091 case 0x93: /* XCHG rAX,rBX */
13092 case 0x94: /* XCHG rAX,rSP */
13093 case 0x95: /* XCHG rAX,rBP */
13094 case 0x96: /* XCHG rAX,rSI */
13095 case 0x97: /* XCHG rAX,rDI */
sewardj2d4fcd52005-05-18 11:47:47 +000013096
13097 /* guard against mutancy */
sewardja6b93d12005-02-17 09:28:28 +000013098 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2d4fcd52005-05-18 11:47:47 +000013099
13100 /* sz == 2 could legitimately happen, but we don't handle it yet */
13101 if (sz == 2) goto decode_failure; /* awaiting test case */
13102
sewardja6b93d12005-02-17 09:28:28 +000013103 codegen_xchg_rAX_Reg ( pfx, sz, opc - 0x90 );
13104 break;
13105
sewardjd20c8852005-01-20 20:04:07 +000013106//.. //-- /* ------------------------ XLAT ----------------------- */
13107//.. //--
13108//.. //-- case 0xD7: /* XLAT */
13109//.. //-- t1 = newTemp(cb); t2 = newTemp(cb);
13110//.. //-- uInstr2(cb, GET, sz, ArchReg, R_EBX, TempReg, t1); /* get eBX */
sewardj42561ef2005-11-04 14:18:31 +000013111//.. //-- handleAddrOverrides( cb, sorb, t1 ); /* make t1 DS:eBX */
sewardjd20c8852005-01-20 20:04:07 +000013112//.. //-- uInstr2(cb, GET, 1, ArchReg, R_AL, TempReg, t2); /* get AL */
13113//.. //-- /* Widen %AL to 32 bits, so it's all defined when we add it. */
13114//.. //-- uInstr1(cb, WIDEN, 4, TempReg, t2);
13115//.. //-- uWiden(cb, 1, False);
13116//.. //-- uInstr2(cb, ADD, sz, TempReg, t2, TempReg, t1); /* add AL to eBX */
13117//.. //-- uInstr2(cb, LOAD, 1, TempReg, t1, TempReg, t2); /* get byte at t1 into t2 */
13118//.. //-- uInstr2(cb, PUT, 1, TempReg, t2, ArchReg, R_AL); /* put byte into AL */
13119//.. //--
13120//.. //-- DIP("xlat%c [ebx]\n", nameISize(sz));
13121//.. //-- break;
13122//.. //--
13123//.. //-- /* ------------------------ IN / OUT ----------------------- */
13124//.. //--
13125//.. //-- case 0xE4: /* IN ib, %al */
13126//.. //-- case 0xE5: /* IN ib, %{e}ax */
13127//.. //-- case 0xEC: /* IN (%dx),%al */
13128//.. //-- case 0xED: /* IN (%dx),%{e}ax */
13129//.. //-- t1 = newTemp(cb);
13130//.. //-- t2 = newTemp(cb);
13131//.. //-- t3 = newTemp(cb);
13132//.. //--
13133//.. //-- uInstr0(cb, CALLM_S, 0);
13134//.. //-- /* operand size? */
13135//.. //-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t1);
13136//.. //-- uLiteral(cb, ( opc == 0xE4 || opc == 0xEC ) ? 1 : sz);
13137//.. //-- uInstr1(cb, PUSH, 4, TempReg, t1);
13138//.. //-- /* port number ? */
13139//.. //-- if ( opc == 0xE4 || opc == 0xE5 ) {
13140//.. //-- abyte = getUChar(eip); eip++;
13141//.. //-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
13142//.. //-- uLiteral(cb, abyte);
13143//.. //-- }
13144//.. //-- else
13145//.. //-- uInstr2(cb, GET, 4, ArchReg, R_EDX, TempReg, t2);
13146//.. //--
13147//.. //-- uInstr1(cb, PUSH, 4, TempReg, t2);
13148//.. //-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_IN));
13149//.. //-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
13150//.. //-- uInstr1(cb, POP, 4, TempReg, t2);
13151//.. //-- uInstr1(cb, CLEAR, 0, Lit16, 4);
13152//.. //-- uInstr0(cb, CALLM_E, 0);
13153//.. //-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_EAX);
13154//.. //-- if ( opc == 0xE4 || opc == 0xE5 ) {
13155//.. //-- DIP("in 0x%x, %%eax/%%ax/%%al\n", getUChar(eip-1) );
13156//.. //-- } else {
13157//.. //-- DIP("in (%%dx), %%eax/%%ax/%%al\n");
13158//.. //-- }
13159//.. //-- break;
13160//.. //-- case 0xE6: /* OUT %al,ib */
13161//.. //-- case 0xE7: /* OUT %{e}ax,ib */
13162//.. //-- case 0xEE: /* OUT %al,(%dx) */
13163//.. //-- case 0xEF: /* OUT %{e}ax,(%dx) */
13164//.. //-- t1 = newTemp(cb);
13165//.. //-- t2 = newTemp(cb);
13166//.. //-- t3 = newTemp(cb);
13167//.. //--
13168//.. //-- uInstr0(cb, CALLM_S, 0);
13169//.. //-- /* operand size? */
13170//.. //-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t1);
13171//.. //-- uLiteral(cb, ( opc == 0xE6 || opc == 0xEE ) ? 1 : sz);
13172//.. //-- uInstr1(cb, PUSH, 4, TempReg, t1);
13173//.. //-- /* port number ? */
13174//.. //-- if ( opc == 0xE6 || opc == 0xE7 ) {
13175//.. //-- abyte = getUChar(eip); eip++;
13176//.. //-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
13177//.. //-- uLiteral(cb, abyte);
13178//.. //-- }
13179//.. //-- else
13180//.. //-- uInstr2(cb, GET, 4, ArchReg, R_EDX, TempReg, t2);
13181//.. //-- uInstr1(cb, PUSH, 4, TempReg, t2);
13182//.. //-- uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, t3);
13183//.. //-- uInstr1(cb, PUSH, 4, TempReg, t3);
13184//.. //-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_OUT));
13185//.. //-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
13186//.. //-- uInstr1(cb, CLEAR, 0, Lit16, 12);
13187//.. //-- uInstr0(cb, CALLM_E, 0);
13188//.. //-- if ( opc == 0xE4 || opc == 0xE5 ) {
13189//.. //-- DIP("out %%eax/%%ax/%%al, 0x%x\n", getUChar(eip-1) );
13190//.. //-- } else {
13191//.. //-- DIP("out %%eax/%%ax/%%al, (%%dx)\n");
13192//.. //-- }
13193//.. //-- break;
sewardj3ca55a12005-01-27 16:06:23 +000013194
13195 /* ------------------------ (Grp1 extensions) ---------- */
13196
13197 case 0x80: /* Grp1 Ib,Eb */
sewardj5b470602005-02-27 13:10:48 +000013198 if (haveF2orF3(pfx)) goto decode_failure;
sewardj8c332e22005-01-28 01:36:56 +000013199 modrm = getUChar(delta);
sewardj3ca55a12005-01-27 16:06:23 +000013200 am_sz = lengthAMode(pfx,delta);
13201 sz = 1;
13202 d_sz = 1;
13203 d64 = getSDisp8(delta + am_sz);
13204 delta = dis_Grp1 ( pfx, delta, modrm, am_sz, d_sz, sz, d64 );
13205 break;
13206
13207 case 0x81: /* Grp1 Iv,Ev */
13208 if (haveF2orF3(pfx)) goto decode_failure;
sewardj8c332e22005-01-28 01:36:56 +000013209 modrm = getUChar(delta);
sewardj3ca55a12005-01-27 16:06:23 +000013210 am_sz = lengthAMode(pfx,delta);
13211 d_sz = imin(sz,4);
13212 d64 = getSDisp(d_sz, delta + am_sz);
13213 delta = dis_Grp1 ( pfx, delta, modrm, am_sz, d_sz, sz, d64 );
13214 break;
13215
13216 case 0x83: /* Grp1 Ib,Ev */
13217 if (haveF2orF3(pfx)) goto decode_failure;
sewardj8c332e22005-01-28 01:36:56 +000013218 modrm = getUChar(delta);
sewardj3ca55a12005-01-27 16:06:23 +000013219 am_sz = lengthAMode(pfx,delta);
13220 d_sz = 1;
13221 d64 = getSDisp8(delta + am_sz);
13222 delta = dis_Grp1 ( pfx, delta, modrm, am_sz, d_sz, sz, d64 );
13223 break;
13224
sewardj118b23e2005-01-29 02:14:44 +000013225 /* ------------------------ (Grp2 extensions) ---------- */
sewardj03b07cc2005-01-31 18:09:43 +000013226
sewardj118b23e2005-01-29 02:14:44 +000013227 case 0xC0: /* Grp2 Ib,Eb */
sewardj5b470602005-02-27 13:10:48 +000013228 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000013229 modrm = getUChar(delta);
13230 am_sz = lengthAMode(pfx,delta);
13231 d_sz = 1;
13232 d64 = getUChar(delta + am_sz);
13233 sz = 1;
13234 delta = dis_Grp2 ( pfx, delta, modrm, am_sz, d_sz, sz,
13235 mkU8(d64 & 0xFF), NULL );
13236 break;
sewardj03b07cc2005-01-31 18:09:43 +000013237
sewardj118b23e2005-01-29 02:14:44 +000013238 case 0xC1: /* Grp2 Ib,Ev */
sewardj5b470602005-02-27 13:10:48 +000013239 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000013240 modrm = getUChar(delta);
13241 am_sz = lengthAMode(pfx,delta);
13242 d_sz = 1;
13243 d64 = getUChar(delta + am_sz);
13244 delta = dis_Grp2 ( pfx, delta, modrm, am_sz, d_sz, sz,
13245 mkU8(d64 & 0xFF), NULL );
13246 break;
13247
sewardj03b07cc2005-01-31 18:09:43 +000013248 case 0xD0: /* Grp2 1,Eb */
sewardj5b470602005-02-27 13:10:48 +000013249 if (haveF2orF3(pfx)) goto decode_failure;
sewardj03b07cc2005-01-31 18:09:43 +000013250 modrm = getUChar(delta);
13251 am_sz = lengthAMode(pfx,delta);
13252 d_sz = 0;
13253 d64 = 1;
13254 sz = 1;
13255 delta = dis_Grp2 ( pfx, delta, modrm, am_sz, d_sz, sz,
13256 mkU8(d64), NULL );
13257 break;
sewardj118b23e2005-01-29 02:14:44 +000013258
13259 case 0xD1: /* Grp2 1,Ev */
sewardj5b470602005-02-27 13:10:48 +000013260 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000013261 modrm = getUChar(delta);
13262 am_sz = lengthAMode(pfx,delta);
13263 d_sz = 0;
13264 d64 = 1;
13265 delta = dis_Grp2 ( pfx, delta, modrm, am_sz, d_sz, sz,
13266 mkU8(d64), NULL );
13267 break;
13268
sewardj85520e42005-02-19 15:22:38 +000013269 case 0xD2: /* Grp2 CL,Eb */
sewardj5b470602005-02-27 13:10:48 +000013270 if (haveF2orF3(pfx)) goto decode_failure;
sewardj85520e42005-02-19 15:22:38 +000013271 modrm = getUChar(delta);
13272 am_sz = lengthAMode(pfx,delta);
13273 d_sz = 0;
13274 sz = 1;
13275 delta = dis_Grp2 ( pfx, delta, modrm, am_sz, d_sz, sz,
sewardj5b470602005-02-27 13:10:48 +000013276 getIRegCL(), "%cl" );
sewardj85520e42005-02-19 15:22:38 +000013277 break;
sewardj118b23e2005-01-29 02:14:44 +000013278
13279 case 0xD3: /* Grp2 CL,Ev */
sewardj5b470602005-02-27 13:10:48 +000013280 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000013281 modrm = getUChar(delta);
13282 am_sz = lengthAMode(pfx,delta);
13283 d_sz = 0;
13284 delta = dis_Grp2 ( pfx, delta, modrm, am_sz, d_sz, sz,
sewardj5b470602005-02-27 13:10:48 +000013285 getIRegCL(), "%cl" );
sewardj118b23e2005-01-29 02:14:44 +000013286 break;
sewardj32b2bbe2005-01-28 00:50:10 +000013287
13288 /* ------------------------ (Grp3 extensions) ---------- */
13289
sewardj118b23e2005-01-29 02:14:44 +000013290 case 0xF6: /* Grp3 Eb */
sewardj5b470602005-02-27 13:10:48 +000013291 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000013292 delta = dis_Grp3 ( pfx, 1, delta );
13293 break;
sewardj32b2bbe2005-01-28 00:50:10 +000013294 case 0xF7: /* Grp3 Ev */
sewardj5b470602005-02-27 13:10:48 +000013295 if (haveF2orF3(pfx)) goto decode_failure;
sewardj32b2bbe2005-01-28 00:50:10 +000013296 delta = dis_Grp3 ( pfx, sz, delta );
13297 break;
13298
sewardj03b07cc2005-01-31 18:09:43 +000013299 /* ------------------------ (Grp4 extensions) ---------- */
13300
13301 case 0xFE: /* Grp4 Eb */
sewardj5b470602005-02-27 13:10:48 +000013302 if (haveF2orF3(pfx)) goto decode_failure;
sewardj03b07cc2005-01-31 18:09:43 +000013303 delta = dis_Grp4 ( pfx, delta );
13304 break;
sewardj354e5c62005-01-27 20:12:52 +000013305
13306 /* ------------------------ (Grp5 extensions) ---------- */
13307
13308 case 0xFF: /* Grp5 Ev */
sewardj5b470602005-02-27 13:10:48 +000013309 if (haveF2orF3(pfx)) goto decode_failure;
sewardj9e6491a2005-07-02 19:24:10 +000013310 delta = dis_Grp5 ( pfx, sz, delta, &dres );
sewardj354e5c62005-01-27 20:12:52 +000013311 break;
sewardj3ca55a12005-01-27 16:06:23 +000013312
13313 /* ------------------------ Escapes to 2-byte opcodes -- */
13314
13315 case 0x0F: {
sewardj8c332e22005-01-28 01:36:56 +000013316 opc = getUChar(delta); delta++;
sewardj3ca55a12005-01-27 16:06:23 +000013317 switch (opc) {
13318
sewardj1d511802005-03-27 17:59:45 +000013319 /* =-=-=-=-=-=-=-=-=- Grp8 =-=-=-=-=-=-=-=-=-=-=-= */
13320
13321 case 0xBA: { /* Grp8 Ib,Ev */
13322 Bool decode_OK = False;
13323 if (haveF2orF3(pfx)) goto decode_failure;
13324 modrm = getUChar(delta);
13325 am_sz = lengthAMode(pfx,delta);
13326 d64 = getSDisp8(delta + am_sz);
13327 delta = dis_Grp8_Imm ( pfx, delta, modrm, am_sz, sz, d64,
13328 &decode_OK );
13329 if (!decode_OK)
13330 goto decode_failure;
13331 break;
13332 }
13333
sewardjf53b7352005-04-06 20:01:56 +000013334 /* =-=-=-=-=-=-=-=-=- BSF/BSR -=-=-=-=-=-=-=-=-=-= */
13335
13336 case 0xBC: /* BSF Gv,Ev */
13337 if (haveF2orF3(pfx)) goto decode_failure;
13338 delta = dis_bs_E_G ( pfx, sz, delta, True );
13339 break;
sewardj537cab02005-04-07 02:03:52 +000013340 case 0xBD: /* BSR Gv,Ev */
13341 if (haveF2orF3(pfx)) goto decode_failure;
13342 delta = dis_bs_E_G ( pfx, sz, delta, False );
13343 break;
sewardj82c9f2f2005-03-02 16:05:13 +000013344
13345 /* =-=-=-=-=-=-=-=-=- BSWAP -=-=-=-=-=-=-=-=-=-=-= */
13346
13347 case 0xC8: /* BSWAP %eax */
13348 case 0xC9:
13349 case 0xCA:
13350 case 0xCB:
13351 case 0xCC:
13352 case 0xCD:
13353 case 0xCE:
13354 case 0xCF: /* BSWAP %edi */
13355 if (haveF2orF3(pfx)) goto decode_failure;
13356 /* According to the AMD64 docs, this insn can have size 4 or
13357 8. */
13358 if (sz == 4) {
13359 t1 = newTemp(Ity_I32);
13360 t2 = newTemp(Ity_I32);
13361 assign( t1, getIRegRexB(4, pfx, opc-0xC8) );
13362 assign( t2,
13363 binop(Iop_Or32,
13364 binop(Iop_Shl32, mkexpr(t1), mkU8(24)),
13365 binop(Iop_Or32,
13366 binop(Iop_And32, binop(Iop_Shl32, mkexpr(t1), mkU8(8)),
13367 mkU32(0x00FF0000)),
13368 binop(Iop_Or32,
13369 binop(Iop_And32, binop(Iop_Shr32, mkexpr(t1), mkU8(8)),
13370 mkU32(0x0000FF00)),
13371 binop(Iop_And32, binop(Iop_Shr32, mkexpr(t1), mkU8(24)),
13372 mkU32(0x000000FF) )
13373 )))
13374 );
13375 putIRegRexB(4, pfx, opc-0xC8, mkexpr(t2));
13376 DIP("bswapl %s\n", nameIRegRexB(4, pfx, opc-0xC8));
13377 break;
sewardj98e9f342005-07-23 12:07:37 +000013378 }
13379 else if (sz == 8) {
13380 t1 = newTemp(Ity_I64);
13381 t2 = newTemp(Ity_I64);
13382 assign( t1, getIRegRexB(8, pfx, opc-0xC8) );
13383
13384# define LANE(_nn) \
13385 binop( Iop_Shl64, \
13386 binop( Iop_And64, \
13387 binop(Iop_Shr64, mkexpr(t1), \
13388 mkU8(8 * (7 - (_nn)))), \
13389 mkU64(0xFF)), \
13390 mkU8(8 * (_nn)))
13391
13392 assign(
13393 t2,
13394 binop(Iop_Or64,
13395 binop(Iop_Or64,
13396 binop(Iop_Or64,LANE(0),LANE(1)),
13397 binop(Iop_Or64,LANE(2),LANE(3))
13398 ),
13399 binop(Iop_Or64,
13400 binop(Iop_Or64,LANE(4),LANE(5)),
13401 binop(Iop_Or64,LANE(6),LANE(7))
13402 )
13403 )
13404 );
13405
13406# undef LANE
13407
13408 putIRegRexB(8, pfx, opc-0xC8, mkexpr(t2));
13409 DIP("bswapq %s\n", nameIRegRexB(8, pfx, opc-0xC8));
13410 break;
sewardj82c9f2f2005-03-02 16:05:13 +000013411 } else {
13412 goto decode_failure;
13413 }
13414
sewardj9ed16802005-08-24 10:46:19 +000013415 /* =-=-=-=-=-=-=-=-=- BT/BTS/BTR/BTC =-=-=-=-=-=-= */
13416
sewardja7690fb2005-10-05 17:19:11 +000013417 /* All of these are possible at sizes 2, 4 and 8, but until a
13418 size 2 test case shows up, only handle sizes 4 and 8. */
sewardj9ed16802005-08-24 10:46:19 +000013419
13420 case 0xA3: /* BT Gv,Ev */
13421 if (haveF2orF3(pfx)) goto decode_failure;
sewardj25d23862006-05-12 17:47:21 +000013422 if (sz != 8 && sz != 4 && sz != 2) goto decode_failure;
sewardj9ed16802005-08-24 10:46:19 +000013423 delta = dis_bt_G_E ( pfx, sz, delta, BtOpNone );
13424 break;
13425 case 0xB3: /* BTR Gv,Ev */
13426 if (haveF2orF3(pfx)) goto decode_failure;
sewardj25d23862006-05-12 17:47:21 +000013427 if (sz != 8 && sz != 4 && sz != 2) goto decode_failure;
sewardj9ed16802005-08-24 10:46:19 +000013428 delta = dis_bt_G_E ( pfx, sz, delta, BtOpReset );
13429 break;
13430 case 0xAB: /* BTS Gv,Ev */
13431 if (haveF2orF3(pfx)) goto decode_failure;
sewardj25d23862006-05-12 17:47:21 +000013432 if (sz != 8 && sz != 4 && sz != 2) goto decode_failure;
sewardj9ed16802005-08-24 10:46:19 +000013433 delta = dis_bt_G_E ( pfx, sz, delta, BtOpSet );
13434 break;
13435 case 0xBB: /* BTC Gv,Ev */
13436 if (haveF2orF3(pfx)) goto decode_failure;
sewardj25d23862006-05-12 17:47:21 +000013437 if (sz != 8 && sz != 4 && sz != 2) goto decode_failure;
sewardj9ed16802005-08-24 10:46:19 +000013438 delta = dis_bt_G_E ( pfx, sz, delta, BtOpComp );
13439 break;
sewardj3ca55a12005-01-27 16:06:23 +000013440
13441 /* =-=-=-=-=-=-=-=-=- CMOV =-=-=-=-=-=-=-=-=-=-=-= */
13442
13443 case 0x40:
13444 case 0x41:
13445 case 0x42: /* CMOVBb/CMOVNAEb (cmov below) */
13446 case 0x43: /* CMOVNBb/CMOVAEb (cmov not below) */
13447 case 0x44: /* CMOVZb/CMOVEb (cmov zero) */
13448 case 0x45: /* CMOVNZb/CMOVNEb (cmov not zero) */
13449 case 0x46: /* CMOVBEb/CMOVNAb (cmov below or equal) */
13450 case 0x47: /* CMOVNBEb/CMOVAb (cmov not below or equal) */
13451 case 0x48: /* CMOVSb (cmov negative) */
13452 case 0x49: /* CMOVSb (cmov not negative) */
13453 case 0x4A: /* CMOVP (cmov parity even) */
13454 case 0x4B: /* CMOVNP (cmov parity odd) */
13455 case 0x4C: /* CMOVLb/CMOVNGEb (cmov less) */
13456 case 0x4D: /* CMOVGEb/CMOVNLb (cmov greater or equal) */
13457 case 0x4E: /* CMOVLEb/CMOVNGb (cmov less or equal) */
13458 case 0x4F: /* CMOVGb/CMOVNLEb (cmov greater) */
sewardj5b470602005-02-27 13:10:48 +000013459 if (haveF2orF3(pfx)) goto decode_failure;
sewardj3ca55a12005-01-27 16:06:23 +000013460 delta = dis_cmov_E_G(pfx, sz, (AMD64Condcode)(opc - 0x40), delta);
13461 break;
13462
sewardja6b93d12005-02-17 09:28:28 +000013463 /* =-=-=-=-=-=-=-=-=- CMPXCHG -=-=-=-=-=-=-=-=-=-= */
13464
sewardjd20c8852005-01-20 20:04:07 +000013465//.. case 0xB0: /* CMPXCHG Gb,Eb */
13466//.. delta = dis_cmpxchg_G_E ( sorb, 1, delta );
13467//.. break;
sewardja6b93d12005-02-17 09:28:28 +000013468 case 0xB1: /* CMPXCHG Gv,Ev */
sewardj5b470602005-02-27 13:10:48 +000013469 if (haveF2orF3(pfx)) goto decode_failure;
sewardja6b93d12005-02-17 09:28:28 +000013470 delta = dis_cmpxchg_G_E ( pfx, sz, delta );
13471 break;
sewardjd20c8852005-01-20 20:04:07 +000013472//.. //-- case 0xC7: /* CMPXCHG8B Gv */
13473//.. //-- eip = dis_cmpxchg8b ( cb, sorb, eip );
13474//.. //-- break;
13475//.. //--
sewardjd0a12df2005-02-10 02:07:43 +000013476 /* =-=-=-=-=-=-=-=-=- CPUID -=-=-=-=-=-=-=-=-=-=-= */
13477
13478 case 0xA2: { /* CPUID */
13479 /* Uses dirty helper:
13480 void amd64g_dirtyhelper_CPUID ( VexGuestAMD64State* )
13481 declared to mod rax, wr rbx, rcx, rdx
13482 */
13483 IRDirty* d = NULL;
13484 HChar* fName = NULL;
13485 void* fAddr = NULL;
sewardj5b470602005-02-27 13:10:48 +000013486 if (haveF2orF3(pfx)) goto decode_failure;
sewardj5117ce12006-01-27 21:20:15 +000013487 if (archinfo->hwcaps == 0/*baseline, == SSE2*/) {
13488 fName = "amd64g_dirtyhelper_CPUID";
13489 fAddr = &amd64g_dirtyhelper_CPUID;
sewardjd0a12df2005-02-10 02:07:43 +000013490 }
sewardj5117ce12006-01-27 21:20:15 +000013491 else
13492 vpanic("disInstr(amd64)(cpuid)");
13493
sewardjd0a12df2005-02-10 02:07:43 +000013494 vassert(fName); vassert(fAddr);
13495 d = unsafeIRDirty_0_N ( 0/*regparms*/,
13496 fName, fAddr, mkIRExprVec_0() );
13497 /* declare guest state effects */
13498 d->needsBBP = True;
13499 d->nFxState = 4;
13500 d->fxState[0].fx = Ifx_Modify;
13501 d->fxState[0].offset = OFFB_RAX;
13502 d->fxState[0].size = 8;
13503 d->fxState[1].fx = Ifx_Write;
13504 d->fxState[1].offset = OFFB_RBX;
13505 d->fxState[1].size = 8;
13506 d->fxState[2].fx = Ifx_Write;
13507 d->fxState[2].offset = OFFB_RCX;
13508 d->fxState[2].size = 8;
13509 d->fxState[3].fx = Ifx_Write;
13510 d->fxState[3].offset = OFFB_RDX;
13511 d->fxState[3].size = 8;
13512 /* execute the dirty call, side-effecting guest state */
13513 stmt( IRStmt_Dirty(d) );
13514 /* CPUID is a serialising insn. So, just in case someone is
13515 using it as a memory fence ... */
13516 stmt( IRStmt_MFence() );
13517 DIP("cpuid\n");
13518 break;
13519 }
13520
sewardj5e525292005-01-28 15:13:10 +000013521 /* =-=-=-=-=-=-=-=-=- MOVZX, MOVSX =-=-=-=-=-=-=-= */
13522
13523 case 0xB6: /* MOVZXb Eb,Gv */
sewardj5b470602005-02-27 13:10:48 +000013524 if (haveF2orF3(pfx)) goto decode_failure;
sewardj5e525292005-01-28 15:13:10 +000013525 if (sz != 2 && sz != 4 && sz != 8)
13526 goto decode_failure;
13527 delta = dis_movx_E_G ( pfx, delta, 1, sz, False );
13528 break;
13529 case 0xB7: /* MOVZXw Ew,Gv */
sewardj5b470602005-02-27 13:10:48 +000013530 if (haveF2orF3(pfx)) goto decode_failure;
sewardj5e525292005-01-28 15:13:10 +000013531 if (sz != 4 && sz != 8)
13532 goto decode_failure;
13533 delta = dis_movx_E_G ( pfx, delta, 2, sz, False );
13534 break;
13535
sewardj03b07cc2005-01-31 18:09:43 +000013536 case 0xBE: /* MOVSXb Eb,Gv */
sewardj5b470602005-02-27 13:10:48 +000013537 if (haveF2orF3(pfx)) goto decode_failure;
sewardj82c9f2f2005-03-02 16:05:13 +000013538 if (sz != 2 && sz != 4 && sz != 8)
sewardj03b07cc2005-01-31 18:09:43 +000013539 goto decode_failure;
13540 delta = dis_movx_E_G ( pfx, delta, 1, sz, True );
13541 break;
13542 case 0xBF: /* MOVSXw Ew,Gv */
sewardj5b470602005-02-27 13:10:48 +000013543 if (haveF2orF3(pfx)) goto decode_failure;
sewardj03b07cc2005-01-31 18:09:43 +000013544 if (sz != 4 && sz != 8)
13545 goto decode_failure;
13546 delta = dis_movx_E_G ( pfx, delta, 2, sz, True );
13547 break;
13548
sewardjd20c8852005-01-20 20:04:07 +000013549//.. //-- /* =-=-=-=-=-=-=-=-=-=-= MOVNTI -=-=-=-=-=-=-=-=-= */
13550//.. //--
13551//.. //-- case 0xC3: /* MOVNTI Gv,Ev */
13552//.. //-- vg_assert(sz == 4);
13553//.. //-- modrm = getUChar(eip);
13554//.. //-- vg_assert(!epartIsReg(modrm));
13555//.. //-- t1 = newTemp(cb);
13556//.. //-- uInstr2(cb, GET, 4, ArchReg, gregOfRM(modrm), TempReg, t1);
13557//.. //-- pair = disAMode ( cb, sorb, eip, dis_buf );
13558//.. //-- t2 = LOW24(pair);
13559//.. //-- eip += HI8(pair);
13560//.. //-- uInstr2(cb, STORE, 4, TempReg, t1, TempReg, t2);
13561//.. //-- DIP("movnti %s,%s\n", nameIReg(4,gregOfRM(modrm)), dis_buf);
13562//.. //-- break;
sewardj32b2bbe2005-01-28 00:50:10 +000013563
13564 /* =-=-=-=-=-=-=-=-=- MUL/IMUL =-=-=-=-=-=-=-=-=-= */
13565
13566 case 0xAF: /* IMUL Ev, Gv */
sewardj5b470602005-02-27 13:10:48 +000013567 if (haveF2orF3(pfx)) goto decode_failure;
sewardj32b2bbe2005-01-28 00:50:10 +000013568 delta = dis_mul_E_G ( pfx, sz, delta );
13569 break;
13570
sewardj1389d4d2005-01-28 13:46:29 +000013571 /* =-=-=-=-=-=-=-=-=- Jcond d32 -=-=-=-=-=-=-=-=-= */
13572 case 0x80:
13573 case 0x81:
13574 case 0x82: /* JBb/JNAEb (jump below) */
13575 case 0x83: /* JNBb/JAEb (jump not below) */
13576 case 0x84: /* JZb/JEb (jump zero) */
13577 case 0x85: /* JNZb/JNEb (jump not zero) */
13578 case 0x86: /* JBEb/JNAb (jump below or equal) */
13579 case 0x87: /* JNBEb/JAb (jump not below or equal) */
13580 case 0x88: /* JSb (jump negative) */
13581 case 0x89: /* JSb (jump not negative) */
13582 case 0x8A: /* JP (jump parity even) */
13583 case 0x8B: /* JNP/JPO (jump parity odd) */
13584 case 0x8C: /* JLb/JNGEb (jump less) */
13585 case 0x8D: /* JGEb/JNLb (jump greater or equal) */
13586 case 0x8E: /* JLEb/JNGb (jump less or equal) */
13587 case 0x8F: /* JGb/JNLEb (jump greater) */
sewardj5b470602005-02-27 13:10:48 +000013588 if (haveF2orF3(pfx)) goto decode_failure;
sewardj9e6491a2005-07-02 19:24:10 +000013589 d64 = (guest_RIP_bbstart+delta+4) + getSDisp32(delta);
sewardj1389d4d2005-01-28 13:46:29 +000013590 delta += 4;
13591 jcc_01( (AMD64Condcode)(opc - 0x80),
sewardj9e6491a2005-07-02 19:24:10 +000013592 guest_RIP_bbstart+delta,
sewardj1389d4d2005-01-28 13:46:29 +000013593 d64 );
sewardj9e6491a2005-07-02 19:24:10 +000013594 dres.whatNext = Dis_StopHere;
sewardj1389d4d2005-01-28 13:46:29 +000013595 DIP("j%s-32 0x%llx\n", name_AMD64Condcode(opc - 0x80), d64);
13596 break;
13597
sewardjb04a47c2005-08-10 12:27:46 +000013598 /* =-=-=-=-=-=-=-=-=- PREFETCH =-=-=-=-=-=-=-=-=-= */
13599 case 0x0D: /* 0F 0D /0 -- prefetch mem8 */
13600 /* 0F 0D /1 -- prefetchw mem8 */
13601 if (have66orF2orF3(pfx)) goto decode_failure;
13602 modrm = getUChar(delta);
13603 if (epartIsReg(modrm)) goto decode_failure;
13604 if (gregLO3ofRM(modrm) != 0 && gregLO3ofRM(modrm) != 1)
13605 goto decode_failure;
13606
13607 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
13608 delta += alen;
13609
13610 switch (gregLO3ofRM(modrm)) {
13611 case 0: DIP("prefetch %s\n", dis_buf); break;
13612 case 1: DIP("prefetchw %s\n", dis_buf); break;
13613 default: vassert(0); /*NOTREACHED*/
13614 }
13615 break;
13616
sewardj31191072005-02-05 18:24:47 +000013617 /* =-=-=-=-=-=-=-=-=- RDTSC -=-=-=-=-=-=-=-=-=-=-= */
sewardjbc6af532005-08-23 23:16:51 +000013618 case 0x31: { /* RDTSC */
13619 IRTemp val = newTemp(Ity_I64);
13620 IRExpr** args = mkIRExprVec_0();
13621 IRDirty* d = unsafeIRDirty_1_N (
13622 val,
13623 0/*regparms*/,
13624 "amd64g_dirtyhelper_RDTSC",
13625 &amd64g_dirtyhelper_RDTSC,
13626 args
13627 );
13628 if (have66orF2orF3(pfx)) goto decode_failure;
13629 /* execute the dirty call, dumping the result in val. */
13630 stmt( IRStmt_Dirty(d) );
13631 putIRegRDX(4, unop(Iop_64HIto32, mkexpr(val)));
13632 putIRegRAX(4, unop(Iop_64to32, mkexpr(val)));
sewardj31191072005-02-05 18:24:47 +000013633 DIP("rdtsc\n");
13634 break;
sewardjbc6af532005-08-23 23:16:51 +000013635 }
sewardj31191072005-02-05 18:24:47 +000013636
sewardjd20c8852005-01-20 20:04:07 +000013637//.. /* =-=-=-=-=-=-=-=-=- PUSH/POP Sreg =-=-=-=-=-=-=-=-=-= */
13638//..
13639//.. case 0xA1: /* POP %FS */
13640//.. dis_pop_segreg( R_FS, sz ); break;
13641//.. case 0xA9: /* POP %GS */
13642//.. dis_pop_segreg( R_GS, sz ); break;
13643//..
13644//.. case 0xA0: /* PUSH %FS */
13645//.. dis_push_segreg( R_FS, sz ); break;
13646//.. case 0xA8: /* PUSH %GS */
13647//.. dis_push_segreg( R_GS, sz ); break;
sewardj118b23e2005-01-29 02:14:44 +000013648
13649 /* =-=-=-=-=-=-=-=-=- SETcc Eb =-=-=-=-=-=-=-=-=-= */
13650 case 0x90:
13651 case 0x91:
13652 case 0x92: /* set-Bb/set-NAEb (set if below) */
13653 case 0x93: /* set-NBb/set-AEb (set if not below) */
13654 case 0x94: /* set-Zb/set-Eb (set if zero) */
13655 case 0x95: /* set-NZb/set-NEb (set if not zero) */
13656 case 0x96: /* set-BEb/set-NAb (set if below or equal) */
13657 case 0x97: /* set-NBEb/set-Ab (set if not below or equal) */
13658 case 0x98: /* set-Sb (set if negative) */
13659 case 0x99: /* set-Sb (set if not negative) */
13660 case 0x9A: /* set-P (set if parity even) */
13661 case 0x9B: /* set-NP (set if parity odd) */
13662 case 0x9C: /* set-Lb/set-NGEb (set if less) */
13663 case 0x9D: /* set-GEb/set-NLb (set if greater or equal) */
13664 case 0x9E: /* set-LEb/set-NGb (set if less or equal) */
13665 case 0x9F: /* set-Gb/set-NLEb (set if greater) */
sewardj5b470602005-02-27 13:10:48 +000013666 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000013667 t1 = newTemp(Ity_I8);
13668 assign( t1, unop(Iop_1Uto8,mk_amd64g_calculate_condition(opc-0x90)) );
13669 modrm = getUChar(delta);
13670 if (epartIsReg(modrm)) {
13671 delta++;
sewardj5b470602005-02-27 13:10:48 +000013672 putIRegE(1, pfx, modrm, mkexpr(t1));
sewardj118b23e2005-01-29 02:14:44 +000013673 DIP("set%s %s\n", name_AMD64Condcode(opc-0x90),
sewardj5b470602005-02-27 13:10:48 +000013674 nameIRegE(1,pfx,modrm));
sewardj118b23e2005-01-29 02:14:44 +000013675 } else {
sewardj5cc00ff2005-03-27 04:48:32 +000013676 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
13677 delta += alen;
13678 storeLE( mkexpr(addr), mkexpr(t1) );
13679 DIP("set%s %s\n", name_AMD64Condcode(opc-0x90), dis_buf);
sewardj118b23e2005-01-29 02:14:44 +000013680 }
13681 break;
13682
sewardj33ef9c22005-11-04 20:05:57 +000013683 /* =-=-=-=-=-=-=-=-=- SHLD/SHRD -=-=-=-=-=-=-=-=-= */
13684
sewardj1287ab42006-05-12 21:03:48 +000013685 case 0xA4: /* SHLDv imm8,Gv,Ev */
13686 modrm = getUChar(delta);
13687 d64 = delta + lengthAMode(pfx, delta);
13688 vex_sprintf(dis_buf, "$%d", (Int)getUChar(d64));
13689 delta = dis_SHLRD_Gv_Ev (
13690 pfx, delta, modrm, sz,
13691 mkU8(getUChar(d64)), True, /* literal */
13692 dis_buf, True /* left */ );
13693 break;
sewardj33ef9c22005-11-04 20:05:57 +000013694 case 0xA5: /* SHLDv %cl,Gv,Ev */
13695 modrm = getUChar(delta);
13696 delta = dis_SHLRD_Gv_Ev (
13697 pfx, delta, modrm, sz,
13698 getIRegCL(), False, /* not literal */
13699 "%cl", True /* left */ );
13700 break;
13701
sewardj75ce3652005-11-04 20:49:36 +000013702 case 0xAC: /* SHRDv imm8,Gv,Ev */
13703 modrm = getUChar(delta);
13704 d64 = delta + lengthAMode(pfx, delta);
13705 vex_sprintf(dis_buf, "$%d", (Int)getUChar(d64));
13706 delta = dis_SHLRD_Gv_Ev (
13707 pfx, delta, modrm, sz,
13708 mkU8(getUChar(d64)), True, /* literal */
13709 dis_buf, False /* right */ );
13710 break;
sewardj33ef9c22005-11-04 20:05:57 +000013711 case 0xAD: /* SHRDv %cl,Gv,Ev */
13712 modrm = getUChar(delta);
13713 delta = dis_SHLRD_Gv_Ev (
13714 pfx, delta, modrm, sz,
13715 getIRegCL(), False, /* not literal */
13716 "%cl", False /* right */);
13717 break;
sewardje1698952005-02-08 15:02:39 +000013718
13719 /* =-=-=-=-=-=-=-=-=- SYSCALL -=-=-=-=-=-=-=-=-=-= */
13720 case 0x05: /* SYSCALL */
sewardj9e6491a2005-07-02 19:24:10 +000013721 guest_RIP_next_mustcheck = True;
13722 guest_RIP_next_assumed = guest_RIP_bbstart + delta;
13723 putIReg64( R_RCX, mkU64(guest_RIP_next_assumed) );
sewardje1698952005-02-08 15:02:39 +000013724 /* It's important that all guest state is up-to-date
13725 at this point. So we declare an end-of-block here, which
13726 forces any cached guest state to be flushed. */
sewardj4fa325a2005-11-03 13:27:24 +000013727 jmp_lit(Ijk_Sys_syscall, guest_RIP_next_assumed);
13728 dres.whatNext = Dis_StopHere;
13729 DIP("syscall\n");
13730 break;
sewardje1698952005-02-08 15:02:39 +000013731
sewardjb4fd2e72005-03-23 13:34:11 +000013732 /* =-=-=-=-=-=-=-=-=- XADD -=-=-=-=-=-=-=-=-=-= */
13733
sewardjd20c8852005-01-20 20:04:07 +000013734//.. //-- case 0xC0: /* XADD Gb,Eb */
13735//.. //-- eip = dis_xadd_G_E ( cb, sorb, 1, eip );
13736//.. //-- break;
sewardjb4fd2e72005-03-23 13:34:11 +000013737 case 0xC1: { /* XADD Gv,Ev */
13738 Bool decode_OK = False;
13739 delta = dis_xadd_G_E ( &decode_OK, pfx, sz, delta );
13740 if (!decode_OK)
13741 goto decode_failure;
13742 break;
13743 }
13744
sewardj8711f662005-05-09 17:52:56 +000013745 /* =-=-=-=-=-=-=-=-=- MMXery =-=-=-=-=-=-=-=-=-=-= */
13746
sewardj3d8107c2005-05-09 22:23:38 +000013747 case 0x71:
13748 case 0x72:
13749 case 0x73: /* PSLLgg/PSRAgg/PSRLgg mmxreg by imm8 */
13750
13751 case 0x6E: /* MOVD (src)ireg-or-mem, (dst)mmxreg */
13752 case 0x7E: /* MOVD (src)mmxreg, (dst)ireg-or-mem */
sewardj8711f662005-05-09 17:52:56 +000013753 case 0x7F: /* MOVQ (src)mmxreg, (dst)mmxreg-or-mem */
13754 case 0x6F: /* MOVQ (src)mmxreg-or-mem, (dst)mmxreg */
13755
13756 case 0xFC:
13757 case 0xFD:
13758 case 0xFE: /* PADDgg (src)mmxreg-or-mem, (dst)mmxreg */
13759
13760 case 0xEC:
13761 case 0xED: /* PADDSgg (src)mmxreg-or-mem, (dst)mmxreg */
13762
13763 case 0xDC:
13764 case 0xDD: /* PADDUSgg (src)mmxreg-or-mem, (dst)mmxreg */
13765
13766 case 0xF8:
13767 case 0xF9:
13768 case 0xFA: /* PSUBgg (src)mmxreg-or-mem, (dst)mmxreg */
13769
13770 case 0xE8:
13771 case 0xE9: /* PSUBSgg (src)mmxreg-or-mem, (dst)mmxreg */
13772
13773 case 0xD8:
13774 case 0xD9: /* PSUBUSgg (src)mmxreg-or-mem, (dst)mmxreg */
13775
13776 case 0xE5: /* PMULHW (src)mmxreg-or-mem, (dst)mmxreg */
13777 case 0xD5: /* PMULLW (src)mmxreg-or-mem, (dst)mmxreg */
13778
13779 case 0xF5: /* PMADDWD (src)mmxreg-or-mem, (dst)mmxreg */
13780
13781 case 0x74:
13782 case 0x75:
13783 case 0x76: /* PCMPEQgg (src)mmxreg-or-mem, (dst)mmxreg */
13784
13785 case 0x64:
13786 case 0x65:
13787 case 0x66: /* PCMPGTgg (src)mmxreg-or-mem, (dst)mmxreg */
13788
13789 case 0x6B: /* PACKSSDW (src)mmxreg-or-mem, (dst)mmxreg */
13790 case 0x63: /* PACKSSWB (src)mmxreg-or-mem, (dst)mmxreg */
13791 case 0x67: /* PACKUSWB (src)mmxreg-or-mem, (dst)mmxreg */
13792
13793 case 0x68:
13794 case 0x69:
13795 case 0x6A: /* PUNPCKHgg (src)mmxreg-or-mem, (dst)mmxreg */
13796
13797 case 0x60:
13798 case 0x61:
13799 case 0x62: /* PUNPCKLgg (src)mmxreg-or-mem, (dst)mmxreg */
13800
13801 case 0xDB: /* PAND (src)mmxreg-or-mem, (dst)mmxreg */
13802 case 0xDF: /* PANDN (src)mmxreg-or-mem, (dst)mmxreg */
13803 case 0xEB: /* POR (src)mmxreg-or-mem, (dst)mmxreg */
13804 case 0xEF: /* PXOR (src)mmxreg-or-mem, (dst)mmxreg */
13805
13806 case 0xF1: /* PSLLgg (src)mmxreg-or-mem, (dst)mmxreg */
13807 case 0xF2:
13808 case 0xF3:
13809
13810 case 0xD1: /* PSRLgg (src)mmxreg-or-mem, (dst)mmxreg */
13811 case 0xD2:
13812 case 0xD3:
13813
13814 case 0xE1: /* PSRAgg (src)mmxreg-or-mem, (dst)mmxreg */
13815 case 0xE2:
13816 {
sewardj270def42005-07-03 01:03:01 +000013817 Long delta0 = delta-1;
sewardj8711f662005-05-09 17:52:56 +000013818 Bool decode_OK = False;
13819
13820 /* If sz==2 this is SSE, and we assume sse idec has
13821 already spotted those cases by now. */
sewardj3d8107c2005-05-09 22:23:38 +000013822 if (sz != 4 && sz != 8)
sewardj8711f662005-05-09 17:52:56 +000013823 goto decode_failure;
13824 if (have66orF2orF3(pfx))
13825 goto decode_failure;
13826
13827 delta = dis_MMX ( &decode_OK, pfx, sz, delta-1 );
13828 if (!decode_OK) {
13829 delta = delta0;
13830 goto decode_failure;
13831 }
13832 break;
13833 }
13834
sewardjae84d782006-04-13 22:06:35 +000013835 case 0x0E: /* FEMMS */
sewardj8711f662005-05-09 17:52:56 +000013836 case 0x77: /* EMMS */
13837 if (sz != 4)
13838 goto decode_failure;
13839 do_EMMS_preamble();
sewardjae84d782006-04-13 22:06:35 +000013840 DIP("{f}emms\n");
sewardj8711f662005-05-09 17:52:56 +000013841 break;
sewardj3ca55a12005-01-27 16:06:23 +000013842
13843 /* =-=-=-=-=-=-=-=-=- unimp2 =-=-=-=-=-=-=-=-=-=-= */
13844
13845 default:
13846 goto decode_failure;
13847 } /* switch (opc) for the 2-byte opcodes */
13848 goto decode_success;
13849 } /* case 0x0F: of primary opcode */
sewardjdf0e0022005-01-25 15:48:43 +000013850
13851 /* ------------------------ ??? ------------------------ */
13852
13853 default:
13854 decode_failure:
13855 /* All decode failures end up here. */
13856 vex_printf("vex amd64->IR: unhandled instruction bytes: "
13857 "0x%x 0x%x 0x%x 0x%x\n",
sewardj8c332e22005-01-28 01:36:56 +000013858 (Int)getUChar(delta_start+0),
13859 (Int)getUChar(delta_start+1),
13860 (Int)getUChar(delta_start+2),
13861 (Int)getUChar(delta_start+3) );
sewardjdf0e0022005-01-25 15:48:43 +000013862
13863 /* Tell the dispatcher that this insn cannot be decoded, and so has
13864 not been executed, and (is currently) the next to be executed.
13865 RIP should be up-to-date since it made so at the start of each
13866 insn, but nevertheless be paranoid and update it again right
13867 now. */
sewardj9e6491a2005-07-02 19:24:10 +000013868 stmt( IRStmt_Put( OFFB_RIP, mkU64(guest_RIP_curr_instr) ) );
13869 jmp_lit(Ijk_NoDecode, guest_RIP_curr_instr);
13870 dres.whatNext = Dis_StopHere;
13871 dres.len = 0;
13872 return dres;
sewardjdf0e0022005-01-25 15:48:43 +000013873
13874 } /* switch (opc) for the main (primary) opcode switch. */
13875
13876 decode_success:
13877 /* All decode successes end up here. */
13878 DIP("\n");
sewardj9e6491a2005-07-02 19:24:10 +000013879 dres.len = (Int)toUInt(delta - delta_start);
13880 return dres;
sewardjdf0e0022005-01-25 15:48:43 +000013881}
13882
13883#undef DIP
13884#undef DIS
sewardjd20c8852005-01-20 20:04:07 +000013885
sewardj9e6491a2005-07-02 19:24:10 +000013886
13887/*------------------------------------------------------------*/
13888/*--- Top-level fn ---*/
13889/*------------------------------------------------------------*/
13890
13891/* Disassemble a single instruction into IR. The instruction
13892 is located in host memory at &guest_code[delta]. */
13893
13894DisResult disInstr_AMD64 ( IRBB* irbb_IN,
13895 Bool put_IP,
sewardjc716aea2006-01-17 01:48:46 +000013896 Bool (*resteerOkFn) ( void*, Addr64 ),
13897 void* callback_opaque,
sewardj9e6491a2005-07-02 19:24:10 +000013898 UChar* guest_code_IN,
13899 Long delta,
13900 Addr64 guest_IP,
sewardja5f55da2006-04-30 23:37:32 +000013901 VexArch guest_arch,
sewardj9e6491a2005-07-02 19:24:10 +000013902 VexArchInfo* archinfo,
13903 Bool host_bigendian_IN )
13904{
13905 DisResult dres;
13906
13907 /* Set globals (see top of this file) */
sewardja5f55da2006-04-30 23:37:32 +000013908 vassert(guest_arch == VexArchAMD64);
sewardj9e6491a2005-07-02 19:24:10 +000013909 guest_code = guest_code_IN;
13910 irbb = irbb_IN;
13911 host_is_bigendian = host_bigendian_IN;
13912 guest_RIP_curr_instr = guest_IP;
13913 guest_RIP_bbstart = guest_IP - delta;
13914
13915 /* We'll consult these after doing disInstr_AMD64_WRK. */
13916 guest_RIP_next_assumed = 0;
13917 guest_RIP_next_mustcheck = False;
13918
sewardjc716aea2006-01-17 01:48:46 +000013919 dres = disInstr_AMD64_WRK ( put_IP, resteerOkFn, callback_opaque,
sewardj9e6491a2005-07-02 19:24:10 +000013920 delta, archinfo );
13921
13922 /* If disInstr_AMD64_WRK tried to figure out the next rip, check it
13923 got it right. Failure of this assertion is serious and denotes
13924 a bug in disInstr. */
13925 if (guest_RIP_next_mustcheck
13926 && guest_RIP_next_assumed != guest_RIP_curr_instr + dres.len) {
13927 vex_printf("\n");
13928 vex_printf("assumed next %%rip = 0x%llx\n",
13929 guest_RIP_next_assumed );
13930 vex_printf(" actual next %%rip = 0x%llx\n",
13931 guest_RIP_curr_instr + dres.len );
13932 vpanic("bbToIR_AMD64: disInstr miscalculated next %rip");
13933 }
13934
13935 return dres;
13936}
13937
13938
13939
sewardjd20c8852005-01-20 20:04:07 +000013940/*--------------------------------------------------------------------*/
13941/*--- end guest-amd64/toIR.c ---*/
13942/*--------------------------------------------------------------------*/