blob: e811b158eba09ac507e821a9b639a732706bee73 [file] [log] [blame]
sewardjd20c8852005-01-20 20:04:07 +00001
2/*--------------------------------------------------------------------*/
3/*--- ---*/
4/*--- This file (guest-amd64/toIR.c) is ---*/
sewardjdbcfae72005-08-02 11:14:04 +00005/*--- Copyright (C) OpenWorks LLP. All rights reserved. ---*/
sewardjd20c8852005-01-20 20:04:07 +00006/*--- ---*/
7/*--------------------------------------------------------------------*/
8
9/*
10 This file is part of LibVEX, a library for dynamic binary
11 instrumentation and translation.
12
sewardj7bd6ffe2005-08-03 16:07:36 +000013 Copyright (C) 2004-2005 OpenWorks LLP. All rights reserved.
sewardjd20c8852005-01-20 20:04:07 +000014
sewardj7bd6ffe2005-08-03 16:07:36 +000015 This library is made available under a dual licensing scheme.
sewardjd20c8852005-01-20 20:04:07 +000016
sewardj7bd6ffe2005-08-03 16:07:36 +000017 If you link LibVEX against other code all of which is itself
18 licensed under the GNU General Public License, version 2 dated June
19 1991 ("GPL v2"), then you may use LibVEX under the terms of the GPL
20 v2, as appearing in the file LICENSE.GPL. If the file LICENSE.GPL
21 is missing, you can obtain a copy of the GPL v2 from the Free
22 Software Foundation Inc., 51 Franklin St, Fifth Floor, Boston, MA
23 02110-1301, USA.
24
25 For any other uses of LibVEX, you must first obtain a commercial
26 license from OpenWorks LLP. Please contact info@open-works.co.uk
27 for information about commercial licensing.
28
29 This software is provided by OpenWorks LLP "as is" and any express
30 or implied warranties, including, but not limited to, the implied
31 warranties of merchantability and fitness for a particular purpose
32 are disclaimed. In no event shall OpenWorks LLP be liable for any
33 direct, indirect, incidental, special, exemplary, or consequential
34 damages (including, but not limited to, procurement of substitute
35 goods or services; loss of use, data, or profits; or business
36 interruption) however caused and on any theory of liability,
37 whether in contract, strict liability, or tort (including
38 negligence or otherwise) arising in any way out of the use of this
39 software, even if advised of the possibility of such damage.
sewardjd20c8852005-01-20 20:04:07 +000040
41 Neither the names of the U.S. Department of Energy nor the
42 University of California nor the names of its contributors may be
43 used to endorse or promote products derived from this software
44 without prior written permission.
sewardjd20c8852005-01-20 20:04:07 +000045*/
46
sewardj9ff93bc2005-03-23 11:25:12 +000047/* LIMITATIONS:
48
49 LOCK prefix handling is only safe in the situation where
50 Vex-generated code is run single-threadedly. (This is not the same
51 as saying that Valgrind can't safely use Vex to run multithreaded
52 programs). See comment attached to LOCK prefix handling in
53 disInstr for details.
54*/
55
sewardj820611e2005-08-24 10:56:01 +000056/* TODO:
57
58 All Puts to CC_OP/CC_DEP1/CC_DEP2/CC_NDEP should really be checked
59 to ensure a 64-bit value is being written.
60
sewardjd20c8852005-01-20 20:04:07 +000061//.. x87 FP Limitations:
62//..
63//.. * all arithmetic done at 64 bits
64//..
65//.. * no FP exceptions, except for handling stack over/underflow
66//..
67//.. * FP rounding mode observed only for float->int conversions
68//.. and int->float conversions which could lose accuracy, and
69//.. for float-to-float rounding. For all other operations,
70//.. round-to-nearest is used, regardless.
71//..
72//.. * FP sin/cos/tan/sincos: C2 flag is always cleared. IOW the
73//.. simulation claims the argument is in-range (-2^63 <= arg <= 2^63)
74//.. even when it isn't.
75//..
76//.. * some of the FCOM cases could do with testing -- not convinced
77//.. that the args are the right way round.
78//..
79//.. * FSAVE does not re-initialise the FPU; it should do
80//..
81//.. * FINIT not only initialises the FPU environment, it also
82//.. zeroes all the FP registers. It should leave the registers
83//.. unchanged.
84//..
85//.. RDTSC returns zero, always.
86//..
87//.. SAHF should cause eflags[1] == 1, and in fact it produces 0. As
88//.. per Intel docs this bit has no meaning anyway. Since PUSHF is the
89//.. only way to observe eflags[1], a proper fix would be to make that
90//.. bit be set by PUSHF.
91//..
92//.. This module uses global variables and so is not MT-safe (if that
sewardj820611e2005-08-24 10:56:01 +000093//.. should ever become relevant).
94*/
sewardj44d494d2005-01-20 20:26:33 +000095
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) {
2639 vassert(0); /* awaiting test case */
2640 helper_SBB( size, dst1, dst0, src );
2641 storeLE(mkexpr(addr), mkexpr(dst1));
2642 } else {
2643 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
2644 if (isAddSub(op8))
2645 setFlags_DEP1_DEP2(op8, dst0, src, ty);
2646 else
2647 setFlags_DEP1(op8, dst1, ty);
2648 if (keep)
2649 storeLE(mkexpr(addr), mkexpr(dst1));
2650 }
2651
2652 DIP("%s%c %s,%s\n", t_amd64opc, nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00002653 nameIRegG(size,pfx,rm), dis_buf);
sewardj3ca55a12005-01-27 16:06:23 +00002654 return len+delta0;
2655 }
2656}
2657
2658
sewardj1389d4d2005-01-28 13:46:29 +00002659/* Handle move instructions of the form
2660 mov E, G meaning
2661 mov reg-or-mem, reg
2662 Is passed the a ptr to the modRM byte, and the data size. Returns
2663 the address advanced completely over this instruction.
2664
2665 E(src) is reg-or-mem
2666 G(dst) is reg.
2667
2668 If E is reg, --> GET %E, tmpv
2669 PUT tmpv, %G
2670
2671 If E is mem --> (getAddr E) -> tmpa
2672 LD (tmpa), tmpb
2673 PUT tmpb, %G
2674*/
2675static
2676ULong dis_mov_E_G ( Prefix pfx,
2677 Int size,
sewardj270def42005-07-03 01:03:01 +00002678 Long delta0 )
sewardj1389d4d2005-01-28 13:46:29 +00002679{
2680 Int len;
2681 UChar rm = getUChar(delta0);
2682 HChar dis_buf[50];
2683
2684 if (epartIsReg(rm)) {
sewardj5b470602005-02-27 13:10:48 +00002685 putIRegG(size, pfx, rm, getIRegE(size, pfx, rm));
sewardje941eea2005-01-30 19:52:28 +00002686 DIP("mov%c %s,%s\n", nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00002687 nameIRegE(size,pfx,rm),
2688 nameIRegG(size,pfx,rm));
sewardj1389d4d2005-01-28 13:46:29 +00002689 return 1+delta0;
2690 }
2691
2692 /* E refers to memory */
2693 {
sewardje1698952005-02-08 15:02:39 +00002694 IRTemp addr = disAMode ( &len, pfx, delta0, dis_buf, 0 );
sewardj5b470602005-02-27 13:10:48 +00002695 putIRegG(size, pfx, rm, loadLE(szToITy(size), mkexpr(addr)));
sewardj1389d4d2005-01-28 13:46:29 +00002696 DIP("mov%c %s,%s\n", nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00002697 dis_buf,
2698 nameIRegG(size,pfx,rm));
sewardj1389d4d2005-01-28 13:46:29 +00002699 return delta0+len;
2700 }
2701}
2702
2703
2704/* Handle move instructions of the form
2705 mov G, E meaning
2706 mov reg, reg-or-mem
2707 Is passed the a ptr to the modRM byte, and the data size. Returns
2708 the address advanced completely over this instruction.
2709
2710 G(src) is reg.
2711 E(dst) is reg-or-mem
2712
2713 If E is reg, --> GET %G, tmp
2714 PUT tmp, %E
2715
2716 If E is mem, --> (getAddr E) -> tmpa
2717 GET %G, tmpv
2718 ST tmpv, (tmpa)
2719*/
2720static
2721ULong dis_mov_G_E ( Prefix pfx,
2722 Int size,
sewardj270def42005-07-03 01:03:01 +00002723 Long delta0 )
sewardj1389d4d2005-01-28 13:46:29 +00002724{
2725 Int len;
2726 UChar rm = getUChar(delta0);
2727 HChar dis_buf[50];
2728
2729 if (epartIsReg(rm)) {
sewardj5b470602005-02-27 13:10:48 +00002730 putIRegE(size, pfx, rm, getIRegG(size, pfx, rm));
sewardje941eea2005-01-30 19:52:28 +00002731 DIP("mov%c %s,%s\n", nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00002732 nameIRegG(size,pfx,rm),
2733 nameIRegE(size,pfx,rm));
sewardj1389d4d2005-01-28 13:46:29 +00002734 return 1+delta0;
2735 }
2736
2737 /* E refers to memory */
2738 {
sewardje1698952005-02-08 15:02:39 +00002739 IRTemp addr = disAMode ( &len, pfx, delta0, dis_buf, 0 );
sewardj5b470602005-02-27 13:10:48 +00002740 storeLE( mkexpr(addr), getIRegG(size, pfx, rm) );
sewardj1389d4d2005-01-28 13:46:29 +00002741 DIP("mov%c %s,%s\n", nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00002742 nameIRegG(size,pfx,rm),
2743 dis_buf);
sewardj1389d4d2005-01-28 13:46:29 +00002744 return len+delta0;
2745 }
2746}
sewardj3ca55a12005-01-27 16:06:23 +00002747
2748
2749/* op $immediate, AL/AX/EAX/RAX. */
2750static
sewardj8c332e22005-01-28 01:36:56 +00002751ULong dis_op_imm_A ( Int size,
sewardj41c01092005-07-23 13:50:32 +00002752 Bool carrying,
sewardj8c332e22005-01-28 01:36:56 +00002753 IROp op8,
2754 Bool keep,
sewardj270def42005-07-03 01:03:01 +00002755 Long delta,
sewardj8c332e22005-01-28 01:36:56 +00002756 HChar* t_amd64opc )
sewardj3ca55a12005-01-27 16:06:23 +00002757{
2758 Int size4 = imin(size,4);
2759 IRType ty = szToITy(size);
2760 IRTemp dst0 = newTemp(ty);
2761 IRTemp src = newTemp(ty);
2762 IRTemp dst1 = newTemp(ty);
sewardj8c332e22005-01-28 01:36:56 +00002763 Long lit = getSDisp(size4,delta);
sewardj5b470602005-02-27 13:10:48 +00002764 assign(dst0, getIRegRAX(size));
sewardj1389d4d2005-01-28 13:46:29 +00002765 assign(src, mkU(ty,lit & mkSizeMask(size)));
sewardj41c01092005-07-23 13:50:32 +00002766
2767 if (isAddSub(op8) && !carrying) {
2768 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
sewardj3ca55a12005-01-27 16:06:23 +00002769 setFlags_DEP1_DEP2(op8, dst0, src, ty);
sewardj41c01092005-07-23 13:50:32 +00002770 }
sewardj3ca55a12005-01-27 16:06:23 +00002771 else
sewardj41c01092005-07-23 13:50:32 +00002772 if (isLogic(op8)) {
2773 vassert(!carrying);
2774 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
sewardj3ca55a12005-01-27 16:06:23 +00002775 setFlags_DEP1(op8, dst1, ty);
sewardj41c01092005-07-23 13:50:32 +00002776 }
sewardj3ca55a12005-01-27 16:06:23 +00002777 else
sewardj41c01092005-07-23 13:50:32 +00002778 if (op8 == Iop_Add8 && carrying) {
2779 helper_ADC( size, dst1, dst0, src );
2780 }
2781 else
2782 vpanic("dis_op_imm_A(amd64,guest)");
sewardj3ca55a12005-01-27 16:06:23 +00002783
2784 if (keep)
sewardj5b470602005-02-27 13:10:48 +00002785 putIRegRAX(size, mkexpr(dst1));
sewardj3ca55a12005-01-27 16:06:23 +00002786
2787 DIP("%s%c $%lld, %s\n", t_amd64opc, nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00002788 lit, nameIRegRAX(size));
sewardj3ca55a12005-01-27 16:06:23 +00002789 return delta+size4;
2790}
2791
2792
sewardj5e525292005-01-28 15:13:10 +00002793/* Sign- and Zero-extending moves. */
2794static
2795ULong dis_movx_E_G ( Prefix pfx,
sewardj270def42005-07-03 01:03:01 +00002796 Long delta, Int szs, Int szd, Bool sign_extend )
sewardj5e525292005-01-28 15:13:10 +00002797{
2798 UChar rm = getUChar(delta);
2799 if (epartIsReg(rm)) {
sewardj5b470602005-02-27 13:10:48 +00002800 putIRegG(szd, pfx, rm,
sewardj5e525292005-01-28 15:13:10 +00002801 doScalarWidening(
2802 szs,szd,sign_extend,
sewardj5b470602005-02-27 13:10:48 +00002803 getIRegE(szs,pfx,rm)));
sewardj5e525292005-01-28 15:13:10 +00002804 DIP("mov%c%c%c %s,%s\n", sign_extend ? 's' : 'z',
2805 nameISize(szs),
2806 nameISize(szd),
sewardj5b470602005-02-27 13:10:48 +00002807 nameIRegE(szs,pfx,rm),
2808 nameIRegG(szd,pfx,rm));
sewardj5e525292005-01-28 15:13:10 +00002809 return 1+delta;
2810 }
2811
2812 /* E refers to memory */
2813 {
2814 Int len;
2815 HChar dis_buf[50];
sewardje1698952005-02-08 15:02:39 +00002816 IRTemp addr = disAMode ( &len, pfx, delta, dis_buf, 0 );
sewardj5b470602005-02-27 13:10:48 +00002817 putIRegG(szd, pfx, rm,
sewardj5e525292005-01-28 15:13:10 +00002818 doScalarWidening(
2819 szs,szd,sign_extend,
2820 loadLE(szToITy(szs),mkexpr(addr))));
2821 DIP("mov%c%c%c %s,%s\n", sign_extend ? 's' : 'z',
2822 nameISize(szs),
2823 nameISize(szd),
2824 dis_buf,
sewardj5b470602005-02-27 13:10:48 +00002825 nameIRegG(szd,pfx,rm));
sewardj5e525292005-01-28 15:13:10 +00002826 return len+delta;
2827 }
2828}
sewardj32b2bbe2005-01-28 00:50:10 +00002829
2830
sewardj03b07cc2005-01-31 18:09:43 +00002831/* Generate code to divide ArchRegs RDX:RAX / EDX:EAX / DX:AX / AX by
2832 the 64 / 32 / 16 / 8 bit quantity in the given IRTemp. */
sewardj32b2bbe2005-01-28 00:50:10 +00002833static
2834void codegen_div ( Int sz, IRTemp t, Bool signed_divide )
2835{
sewardj03b07cc2005-01-31 18:09:43 +00002836 /* special-case the 64-bit case */
2837 if (sz == 8) {
2838 IROp op = signed_divide ? Iop_DivModS128to64
2839 : Iop_DivModU128to64;
sewardja6b93d12005-02-17 09:28:28 +00002840 IRTemp src128 = newTemp(Ity_I128);
2841 IRTemp dst128 = newTemp(Ity_I128);
sewardj03b07cc2005-01-31 18:09:43 +00002842 assign( src128, binop(Iop_64HLto128,
sewardja6b93d12005-02-17 09:28:28 +00002843 getIReg64(R_RDX),
2844 getIReg64(R_RAX)) );
sewardj03b07cc2005-01-31 18:09:43 +00002845 assign( dst128, binop(op, mkexpr(src128), mkexpr(t)) );
sewardja6b93d12005-02-17 09:28:28 +00002846 putIReg64( R_RAX, unop(Iop_128to64,mkexpr(dst128)) );
2847 putIReg64( R_RDX, unop(Iop_128HIto64,mkexpr(dst128)) );
sewardj03b07cc2005-01-31 18:09:43 +00002848 } else {
2849 IROp op = signed_divide ? Iop_DivModS64to32
2850 : Iop_DivModU64to32;
2851 IRTemp src64 = newTemp(Ity_I64);
2852 IRTemp dst64 = newTemp(Ity_I64);
2853 switch (sz) {
sewardj85520e42005-02-19 15:22:38 +00002854 case 4:
sewardj5b470602005-02-27 13:10:48 +00002855 assign( src64,
2856 binop(Iop_32HLto64, getIRegRDX(4), getIRegRAX(4)) );
2857 assign( dst64,
2858 binop(op, mkexpr(src64), mkexpr(t)) );
2859 putIRegRAX( 4, unop(Iop_64to32,mkexpr(dst64)) );
2860 putIRegRDX( 4, unop(Iop_64HIto32,mkexpr(dst64)) );
sewardj85520e42005-02-19 15:22:38 +00002861 break;
2862 case 2: {
2863 IROp widen3264 = signed_divide ? Iop_32Sto64 : Iop_32Uto64;
2864 IROp widen1632 = signed_divide ? Iop_16Sto32 : Iop_16Uto32;
2865 assign( src64, unop(widen3264,
2866 binop(Iop_16HLto32,
sewardj5b470602005-02-27 13:10:48 +00002867 getIRegRDX(2),
2868 getIRegRAX(2))) );
sewardj85520e42005-02-19 15:22:38 +00002869 assign( dst64, binop(op, mkexpr(src64), unop(widen1632,mkexpr(t))) );
sewardj5b470602005-02-27 13:10:48 +00002870 putIRegRAX( 2, unop(Iop_32to16,unop(Iop_64to32,mkexpr(dst64))) );
2871 putIRegRDX( 2, unop(Iop_32to16,unop(Iop_64HIto32,mkexpr(dst64))) );
sewardj85520e42005-02-19 15:22:38 +00002872 break;
2873 }
2874 case 1: {
2875 IROp widen3264 = signed_divide ? Iop_32Sto64 : Iop_32Uto64;
2876 IROp widen1632 = signed_divide ? Iop_16Sto32 : Iop_16Uto32;
2877 IROp widen816 = signed_divide ? Iop_8Sto16 : Iop_8Uto16;
2878 assign( src64, unop(widen3264,
sewardj5b470602005-02-27 13:10:48 +00002879 unop(widen1632, getIRegRAX(2))) );
sewardj85520e42005-02-19 15:22:38 +00002880 assign( dst64,
2881 binop(op, mkexpr(src64),
2882 unop(widen1632, unop(widen816, mkexpr(t)))) );
sewardj5b470602005-02-27 13:10:48 +00002883 putIRegRAX( 1, unop(Iop_16to8,
2884 unop(Iop_32to16,
2885 unop(Iop_64to32,mkexpr(dst64)))) );
2886 putIRegAH( unop(Iop_16to8,
2887 unop(Iop_32to16,
2888 unop(Iop_64HIto32,mkexpr(dst64)))) );
sewardj85520e42005-02-19 15:22:38 +00002889 break;
2890 }
2891 default:
2892 vpanic("codegen_div(amd64)");
sewardj03b07cc2005-01-31 18:09:43 +00002893 }
sewardj32b2bbe2005-01-28 00:50:10 +00002894 }
2895}
sewardj3ca55a12005-01-27 16:06:23 +00002896
2897static
sewardj8c332e22005-01-28 01:36:56 +00002898ULong dis_Grp1 ( Prefix pfx,
sewardj270def42005-07-03 01:03:01 +00002899 Long delta, UChar modrm,
sewardj227458e2005-01-31 19:04:50 +00002900 Int am_sz, Int d_sz, Int sz, Long d64 )
sewardj3ca55a12005-01-27 16:06:23 +00002901{
2902 Int len;
2903 HChar dis_buf[50];
2904 IRType ty = szToITy(sz);
2905 IRTemp dst1 = newTemp(ty);
2906 IRTemp src = newTemp(ty);
2907 IRTemp dst0 = newTemp(ty);
2908 IRTemp addr = IRTemp_INVALID;
2909 IROp op8 = Iop_INVALID;
sewardj1389d4d2005-01-28 13:46:29 +00002910 ULong mask = mkSizeMask(sz);
sewardj3ca55a12005-01-27 16:06:23 +00002911
sewardj901ed122005-02-27 13:25:31 +00002912 switch (gregLO3ofRM(modrm)) {
sewardj3ca55a12005-01-27 16:06:23 +00002913 case 0: op8 = Iop_Add8; break; case 1: op8 = Iop_Or8; break;
2914 case 2: break; // ADC
2915 case 3: break; // SBB
2916 case 4: op8 = Iop_And8; break; case 5: op8 = Iop_Sub8; break;
2917 case 6: op8 = Iop_Xor8; break; case 7: op8 = Iop_Sub8; break;
2918 default: vpanic("dis_Grp1(amd64): unhandled case");
2919 }
2920
2921 if (epartIsReg(modrm)) {
2922 vassert(am_sz == 1);
2923
sewardj5b470602005-02-27 13:10:48 +00002924 assign(dst0, getIRegE(sz,pfx,modrm));
sewardj227458e2005-01-31 19:04:50 +00002925 assign(src, mkU(ty,d64 & mask));
sewardj3ca55a12005-01-27 16:06:23 +00002926
sewardj901ed122005-02-27 13:25:31 +00002927 if (gregLO3ofRM(modrm) == 2 /* ADC */) {
sewardj3ca55a12005-01-27 16:06:23 +00002928 helper_ADC( sz, dst1, dst0, src );
2929 } else
sewardj901ed122005-02-27 13:25:31 +00002930 if (gregLO3ofRM(modrm) == 3 /* SBB */) {
sewardj3ca55a12005-01-27 16:06:23 +00002931 helper_SBB( sz, dst1, dst0, src );
2932 } else {
2933 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
2934 if (isAddSub(op8))
2935 setFlags_DEP1_DEP2(op8, dst0, src, ty);
2936 else
2937 setFlags_DEP1(op8, dst1, ty);
2938 }
2939
sewardj901ed122005-02-27 13:25:31 +00002940 if (gregLO3ofRM(modrm) < 7)
sewardj5b470602005-02-27 13:10:48 +00002941 putIRegE(sz, pfx, modrm, mkexpr(dst1));
sewardj3ca55a12005-01-27 16:06:23 +00002942
2943 delta += (am_sz + d_sz);
sewardje941eea2005-01-30 19:52:28 +00002944 DIP("%s%c $%lld, %s\n",
sewardj901ed122005-02-27 13:25:31 +00002945 nameGrp1(gregLO3ofRM(modrm)), nameISize(sz), d64,
sewardj5b470602005-02-27 13:10:48 +00002946 nameIRegE(sz,pfx,modrm));
sewardj3ca55a12005-01-27 16:06:23 +00002947 } else {
sewardje1698952005-02-08 15:02:39 +00002948 addr = disAMode ( &len, pfx, delta, dis_buf, /*xtra*/d_sz );
sewardj3ca55a12005-01-27 16:06:23 +00002949
2950 assign(dst0, loadLE(ty,mkexpr(addr)));
sewardj227458e2005-01-31 19:04:50 +00002951 assign(src, mkU(ty,d64 & mask));
sewardj3ca55a12005-01-27 16:06:23 +00002952
sewardj901ed122005-02-27 13:25:31 +00002953 if (gregLO3ofRM(modrm) == 2 /* ADC */) {
sewardj3ca55a12005-01-27 16:06:23 +00002954 helper_ADC( sz, dst1, dst0, src );
2955 } else
sewardj901ed122005-02-27 13:25:31 +00002956 if (gregLO3ofRM(modrm) == 3 /* SBB */) {
sewardj3ca55a12005-01-27 16:06:23 +00002957 helper_SBB( sz, dst1, dst0, src );
2958 } else {
2959 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
2960 if (isAddSub(op8))
2961 setFlags_DEP1_DEP2(op8, dst0, src, ty);
2962 else
2963 setFlags_DEP1(op8, dst1, ty);
2964 }
2965
sewardj901ed122005-02-27 13:25:31 +00002966 if (gregLO3ofRM(modrm) < 7)
sewardj3ca55a12005-01-27 16:06:23 +00002967 storeLE(mkexpr(addr), mkexpr(dst1));
2968
2969 delta += (len+d_sz);
sewardje941eea2005-01-30 19:52:28 +00002970 DIP("%s%c $%lld, %s\n",
sewardj901ed122005-02-27 13:25:31 +00002971 nameGrp1(gregLO3ofRM(modrm)), nameISize(sz),
sewardj227458e2005-01-31 19:04:50 +00002972 d64, dis_buf);
sewardj3ca55a12005-01-27 16:06:23 +00002973 }
2974 return delta;
2975}
2976
2977
sewardj118b23e2005-01-29 02:14:44 +00002978/* Group 2 extended opcodes. shift_expr must be an 8-bit typed
2979 expression. */
2980
2981static
2982ULong dis_Grp2 ( Prefix pfx,
sewardj270def42005-07-03 01:03:01 +00002983 Long delta, UChar modrm,
sewardj118b23e2005-01-29 02:14:44 +00002984 Int am_sz, Int d_sz, Int sz, IRExpr* shift_expr,
2985 HChar* shift_expr_txt )
2986{
2987 /* delta on entry points at the modrm byte. */
2988 HChar dis_buf[50];
2989 Int len;
2990 Bool isShift, isRotate, isRotateRC;
2991 IRType ty = szToITy(sz);
2992 IRTemp dst0 = newTemp(ty);
2993 IRTemp dst1 = newTemp(ty);
2994 IRTemp addr = IRTemp_INVALID;
2995
2996 vassert(sz == 1 || sz == 2 || sz == 4 || sz == 8);
2997
2998 /* Put value to shift/rotate in dst0. */
2999 if (epartIsReg(modrm)) {
sewardj5b470602005-02-27 13:10:48 +00003000 assign(dst0, getIRegE(sz, pfx, modrm));
sewardj118b23e2005-01-29 02:14:44 +00003001 delta += (am_sz + d_sz);
3002 } else {
sewardj3587c6b2005-08-14 00:09:58 +00003003 addr = disAMode ( &len, pfx, delta, dis_buf, /*xtra*/d_sz );
sewardj118b23e2005-01-29 02:14:44 +00003004 assign(dst0, loadLE(ty,mkexpr(addr)));
3005 delta += len + d_sz;
3006 }
3007
3008 isShift = False;
sewardj901ed122005-02-27 13:25:31 +00003009 switch (gregLO3ofRM(modrm)) { case 4: case 5: case 7: isShift = True; }
sewardj118b23e2005-01-29 02:14:44 +00003010
3011 isRotate = False;
sewardj901ed122005-02-27 13:25:31 +00003012 switch (gregLO3ofRM(modrm)) { case 0: case 1: isRotate = True; }
sewardj118b23e2005-01-29 02:14:44 +00003013
sewardj901ed122005-02-27 13:25:31 +00003014 isRotateRC = toBool(gregLO3ofRM(modrm) == 3);
sewardj118b23e2005-01-29 02:14:44 +00003015
3016 if (!isShift && !isRotate && !isRotateRC) {
sewardj901ed122005-02-27 13:25:31 +00003017 vex_printf("\ncase %d\n", gregLO3ofRM(modrm));
sewardj118b23e2005-01-29 02:14:44 +00003018 vpanic("dis_Grp2(Reg): unhandled case(amd64)");
3019 }
3020
3021 if (isRotateRC) {
sewardj112b0992005-07-23 13:19:32 +00003022 /* Call a helper; this insn is so ridiculous it does not deserve
3023 better. One problem is, the helper has to calculate both the
3024 new value and the new flags. This is more than 64 bits, and
3025 there is no way to return more than 64 bits from the helper.
3026 Hence the crude and obvious solution is to call it twice,
3027 using the sign of the sz field to indicate whether it is the
3028 value or rflags result we want.
3029 */
3030 IRExpr** argsVALUE;
3031 IRExpr** argsRFLAGS;
3032
3033 IRTemp new_value = newTemp(Ity_I64);
3034 IRTemp new_rflags = newTemp(Ity_I64);
3035 IRTemp old_rflags = newTemp(Ity_I64);
3036
3037 assign( old_rflags, widenUto64(mk_amd64g_calculate_rflags_all()) );
3038
3039 argsVALUE
3040 = mkIRExprVec_4( widenUto64(mkexpr(dst0)), /* thing to rotate */
3041 widenUto64(shift_expr), /* rotate amount */
3042 mkexpr(old_rflags),
3043 mkU64(sz) );
3044 assign( new_value,
3045 mkIRExprCCall(
3046 Ity_I64,
3047 0/*regparm*/,
3048 "amd64g_calculate_RCR", &amd64g_calculate_RCR,
3049 argsVALUE
3050 )
3051 );
3052
3053 argsRFLAGS
3054 = mkIRExprVec_4( widenUto64(mkexpr(dst0)), /* thing to rotate */
3055 widenUto64(shift_expr), /* rotate amount */
3056 mkexpr(old_rflags),
3057 mkU64(-sz) );
3058 assign( new_rflags,
3059 mkIRExprCCall(
3060 Ity_I64,
3061 0/*regparm*/,
3062 "amd64g_calculate_RCR", &amd64g_calculate_RCR,
3063 argsRFLAGS
3064 )
3065 );
3066
3067 assign( dst1, narrowTo(ty, mkexpr(new_value)) );
3068 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(AMD64G_CC_OP_COPY) ));
3069 stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(new_rflags) ));
3070 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
3071 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU64(0) ));
sewardj118b23e2005-01-29 02:14:44 +00003072 }
3073
sewardj112b0992005-07-23 13:19:32 +00003074 else
sewardj118b23e2005-01-29 02:14:44 +00003075 if (isShift) {
3076
3077 IRTemp pre64 = newTemp(Ity_I64);
3078 IRTemp res64 = newTemp(Ity_I64);
3079 IRTemp res64ss = newTemp(Ity_I64);
3080 IRTemp shift_amt = newTemp(Ity_I8);
sewardj1027dc22005-02-26 01:55:02 +00003081 UChar mask = toUChar(sz==8 ? 63 : 31);
sewardj118b23e2005-01-29 02:14:44 +00003082 IROp op64;
3083
sewardj901ed122005-02-27 13:25:31 +00003084 switch (gregLO3ofRM(modrm)) {
sewardj118b23e2005-01-29 02:14:44 +00003085 case 4: op64 = Iop_Shl64; break;
3086 case 5: op64 = Iop_Shr64; break;
3087 case 7: op64 = Iop_Sar64; break;
3088 default: vpanic("dis_Grp2:shift"); break;
3089 }
3090
3091 /* Widen the value to be shifted to 64 bits, do the shift, and
3092 narrow back down. This seems surprisingly long-winded, but
3093 unfortunately the AMD semantics requires that 8/16/32-bit
3094 shifts give defined results for shift values all the way up
sewardj03c96e82005-02-19 18:12:45 +00003095 to 32, and this seems the simplest way to do it. It has the
sewardj118b23e2005-01-29 02:14:44 +00003096 advantage that the only IR level shifts generated are of 64
3097 bit values, and the shift amount is guaranteed to be in the
3098 range 0 .. 63, thereby observing the IR semantics requiring
sewardj03c96e82005-02-19 18:12:45 +00003099 all shift values to be in the range 0 .. 2^word_size-1.
sewardj118b23e2005-01-29 02:14:44 +00003100
sewardj03c96e82005-02-19 18:12:45 +00003101 Therefore the shift amount is masked with 63 for 64-bit shifts
3102 and 31 for all others.
3103 */
3104 /* shift_amt = shift_expr & MASK, regardless of operation size */
3105 assign( shift_amt, binop(Iop_And8, shift_expr, mkU8(mask)) );
sewardj118b23e2005-01-29 02:14:44 +00003106
sewardj03c96e82005-02-19 18:12:45 +00003107 /* suitably widen the value to be shifted to 64 bits. */
sewardj118b23e2005-01-29 02:14:44 +00003108 assign( pre64, op64==Iop_Sar64 ? widenSto64(mkexpr(dst0))
3109 : widenUto64(mkexpr(dst0)) );
3110
3111 /* res64 = pre64 `shift` shift_amt */
3112 assign( res64, binop(op64, mkexpr(pre64), mkexpr(shift_amt)) );
3113
sewardj03c96e82005-02-19 18:12:45 +00003114 /* res64ss = pre64 `shift` ((shift_amt - 1) & MASK) */
sewardj118b23e2005-01-29 02:14:44 +00003115 assign( res64ss,
3116 binop(op64,
3117 mkexpr(pre64),
3118 binop(Iop_And8,
3119 binop(Iop_Sub8,
3120 mkexpr(shift_amt), mkU8(1)),
sewardj03c96e82005-02-19 18:12:45 +00003121 mkU8(mask))) );
sewardj118b23e2005-01-29 02:14:44 +00003122
3123 /* Build the flags thunk. */
3124 setFlags_DEP1_DEP2_shift(op64, res64, res64ss, ty, shift_amt);
3125
3126 /* Narrow the result back down. */
3127 assign( dst1, narrowTo(ty, mkexpr(res64)) );
3128
3129 } /* if (isShift) */
3130
3131 else
3132 if (isRotate) {
3133 Int ccOp = ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1
3134 : (ty==Ity_I32 ? 2 : 3));
sewardj901ed122005-02-27 13:25:31 +00003135 Bool left = toBool(gregLO3ofRM(modrm) == 0);
sewardj118b23e2005-01-29 02:14:44 +00003136 IRTemp rot_amt = newTemp(Ity_I8);
3137 IRTemp rot_amt64 = newTemp(Ity_I8);
3138 IRTemp oldFlags = newTemp(Ity_I64);
sewardj1027dc22005-02-26 01:55:02 +00003139 UChar mask = toUChar(sz==8 ? 63 : 31);
sewardj118b23e2005-01-29 02:14:44 +00003140
3141 /* rot_amt = shift_expr & mask */
3142 /* By masking the rotate amount thusly, the IR-level Shl/Shr
3143 expressions never shift beyond the word size and thus remain
3144 well defined. */
sewardj03c96e82005-02-19 18:12:45 +00003145 assign(rot_amt64, binop(Iop_And8, shift_expr, mkU8(mask)));
sewardj118b23e2005-01-29 02:14:44 +00003146
3147 if (ty == Ity_I64)
3148 assign(rot_amt, mkexpr(rot_amt64));
3149 else
3150 assign(rot_amt, binop(Iop_And8, mkexpr(rot_amt64), mkU8(8*sz-1)));
3151
3152 if (left) {
3153
3154 /* dst1 = (dst0 << rot_amt) | (dst0 >>u (wordsize-rot_amt)) */
3155 assign(dst1,
3156 binop( mkSizedOp(ty,Iop_Or8),
3157 binop( mkSizedOp(ty,Iop_Shl8),
3158 mkexpr(dst0),
3159 mkexpr(rot_amt)
3160 ),
3161 binop( mkSizedOp(ty,Iop_Shr8),
3162 mkexpr(dst0),
3163 binop(Iop_Sub8,mkU8(8*sz), mkexpr(rot_amt))
3164 )
3165 )
3166 );
3167 ccOp += AMD64G_CC_OP_ROLB;
3168
3169 } else { /* right */
3170
3171 /* dst1 = (dst0 >>u rot_amt) | (dst0 << (wordsize-rot_amt)) */
3172 assign(dst1,
3173 binop( mkSizedOp(ty,Iop_Or8),
3174 binop( mkSizedOp(ty,Iop_Shr8),
3175 mkexpr(dst0),
3176 mkexpr(rot_amt)
3177 ),
3178 binop( mkSizedOp(ty,Iop_Shl8),
3179 mkexpr(dst0),
3180 binop(Iop_Sub8,mkU8(8*sz), mkexpr(rot_amt))
3181 )
3182 )
3183 );
3184 ccOp += AMD64G_CC_OP_RORB;
3185
3186 }
3187
3188 /* dst1 now holds the rotated value. Build flag thunk. We
3189 need the resulting value for this, and the previous flags.
3190 Except don't set it if the rotate count is zero. */
3191
3192 assign(oldFlags, mk_amd64g_calculate_rflags_all());
3193
3194 /* CC_DEP1 is the rotated value. CC_NDEP is flags before. */
3195 stmt( IRStmt_Put( OFFB_CC_OP,
3196 IRExpr_Mux0X( mkexpr(rot_amt64),
3197 IRExpr_Get(OFFB_CC_OP,Ity_I64),
3198 mkU64(ccOp))) );
3199 stmt( IRStmt_Put( OFFB_CC_DEP1,
3200 IRExpr_Mux0X( mkexpr(rot_amt64),
3201 IRExpr_Get(OFFB_CC_DEP1,Ity_I64),
3202 widenUto64(mkexpr(dst1)))) );
3203 stmt( IRStmt_Put( OFFB_CC_DEP2,
3204 IRExpr_Mux0X( mkexpr(rot_amt64),
3205 IRExpr_Get(OFFB_CC_DEP2,Ity_I64),
3206 mkU64(0))) );
3207 stmt( IRStmt_Put( OFFB_CC_NDEP,
3208 IRExpr_Mux0X( mkexpr(rot_amt64),
3209 IRExpr_Get(OFFB_CC_NDEP,Ity_I64),
3210 mkexpr(oldFlags))) );
3211 } /* if (isRotate) */
3212
3213 /* Save result, and finish up. */
3214 if (epartIsReg(modrm)) {
sewardj5b470602005-02-27 13:10:48 +00003215 putIRegE(sz, pfx, modrm, mkexpr(dst1));
sewardj118b23e2005-01-29 02:14:44 +00003216 if (vex_traceflags & VEX_TRACE_FE) {
3217 vex_printf("%s%c ",
sewardj901ed122005-02-27 13:25:31 +00003218 nameGrp2(gregLO3ofRM(modrm)), nameISize(sz) );
sewardj118b23e2005-01-29 02:14:44 +00003219 if (shift_expr_txt)
3220 vex_printf("%s", shift_expr_txt);
3221 else
3222 ppIRExpr(shift_expr);
sewardj5b470602005-02-27 13:10:48 +00003223 vex_printf(", %s\n", nameIRegE(sz,pfx,modrm));
sewardj118b23e2005-01-29 02:14:44 +00003224 }
3225 } else {
3226 storeLE(mkexpr(addr), mkexpr(dst1));
3227 if (vex_traceflags & VEX_TRACE_FE) {
3228 vex_printf("%s%c ",
sewardj901ed122005-02-27 13:25:31 +00003229 nameGrp2(gregLO3ofRM(modrm)), nameISize(sz) );
sewardj118b23e2005-01-29 02:14:44 +00003230 if (shift_expr_txt)
3231 vex_printf("%s", shift_expr_txt);
3232 else
3233 ppIRExpr(shift_expr);
3234 vex_printf(", %s\n", dis_buf);
3235 }
3236 }
3237 return delta;
3238}
3239
3240
sewardj1d511802005-03-27 17:59:45 +00003241/* Group 8 extended opcodes (but BT/BTS/BTC/BTR only). */
3242static
3243ULong dis_Grp8_Imm ( Prefix pfx,
sewardj270def42005-07-03 01:03:01 +00003244 Long delta, UChar modrm,
sewardj1d511802005-03-27 17:59:45 +00003245 Int am_sz, Int sz, ULong src_val,
3246 Bool* decode_OK )
3247{
3248 /* src_val denotes a d8.
3249 And delta on entry points at the modrm byte. */
sewardj118b23e2005-01-29 02:14:44 +00003250
sewardj1d511802005-03-27 17:59:45 +00003251 IRType ty = szToITy(sz);
3252 IRTemp t2 = newTemp(Ity_I64);
3253 IRTemp t2m = newTemp(Ity_I64);
3254 IRTemp t_addr = IRTemp_INVALID;
3255 HChar dis_buf[50];
3256 ULong mask;
sewardj9b967672005-02-08 11:13:09 +00003257
sewardj1d511802005-03-27 17:59:45 +00003258 /* we're optimists :-) */
3259 *decode_OK = True;
3260
3261 /* Limit src_val -- the bit offset -- to something within a word.
3262 The Intel docs say that literal offsets larger than a word are
3263 masked in this way. */
3264 switch (sz) {
3265 case 2: src_val &= 15; break;
3266 case 4: src_val &= 31; break;
sewardj537cab02005-04-07 02:03:52 +00003267 case 8: src_val &= 63; break;
sewardj1d511802005-03-27 17:59:45 +00003268 default: *decode_OK = False; return delta;
3269 }
3270
3271 /* Invent a mask suitable for the operation. */
3272 switch (gregLO3ofRM(modrm)) {
sewardj74b4f892005-05-06 01:43:56 +00003273 case 4: /* BT */ mask = 0; break;
3274 case 5: /* BTS */ mask = 1ULL << src_val; break;
3275 case 6: /* BTR */ mask = ~(1ULL << src_val); break;
3276 case 7: /* BTC */ mask = 1ULL << src_val; break;
sewardj1d511802005-03-27 17:59:45 +00003277 /* If this needs to be extended, probably simplest to make a
3278 new function to handle the other cases (0 .. 3). The
3279 Intel docs do however not indicate any use for 0 .. 3, so
3280 we don't expect this to happen. */
3281 default: *decode_OK = False; return delta;
3282 }
3283
3284 /* Fetch the value to be tested and modified into t2, which is
3285 64-bits wide regardless of sz. */
3286 if (epartIsReg(modrm)) {
3287 vassert(am_sz == 1);
3288 assign( t2, widenUto64(getIRegE(sz, pfx, modrm)) );
3289 delta += (am_sz + 1);
3290 DIP("%s%c $0x%llx, %s\n", nameGrp8(gregLO3ofRM(modrm)),
3291 nameISize(sz),
3292 src_val, nameIRegE(sz,pfx,modrm));
3293 } else {
3294 Int len;
3295 t_addr = disAMode ( &len, pfx, delta, dis_buf, 1 );
3296 delta += (len+1);
3297 assign( t2, widenUto64(loadLE(ty, mkexpr(t_addr))) );
3298 DIP("%s%c $0x%llx, %s\n", nameGrp8(gregLO3ofRM(modrm)),
3299 nameISize(sz),
3300 src_val, dis_buf);
3301 }
3302
3303 /* Copy relevant bit from t2 into the carry flag. */
3304 /* Flags: C=selected bit, O,S,Z,A,P undefined, so are set to zero. */
3305 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(AMD64G_CC_OP_COPY) ));
3306 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
3307 stmt( IRStmt_Put(
3308 OFFB_CC_DEP1,
3309 binop(Iop_And64,
3310 binop(Iop_Shr64, mkexpr(t2), mkU8(src_val)),
3311 mkU64(1))
3312 ));
3313
3314 /* Compute the new value into t2m, if non-BT. */
3315 switch (gregLO3ofRM(modrm)) {
3316 case 4: /* BT */
3317 break;
3318 case 5: /* BTS */
3319 assign( t2m, binop(Iop_Or64, mkU64(mask), mkexpr(t2)) );
3320 break;
3321 case 6: /* BTR */
3322 assign( t2m, binop(Iop_And64, mkU64(mask), mkexpr(t2)) );
3323 break;
3324 case 7: /* BTC */
3325 assign( t2m, binop(Iop_Xor64, mkU64(mask), mkexpr(t2)) );
3326 break;
3327 default:
3328 vassert(0);
3329 }
3330
3331 /* Write the result back, if non-BT. */
3332 if (gregLO3ofRM(modrm) != 4 /* BT */) {
3333 if (epartIsReg(modrm)) {
3334 putIRegE(sz, pfx, modrm, narrowTo(ty, mkexpr(t2m)));
3335 } else {
3336 storeLE(mkexpr(t_addr), narrowTo(ty, mkexpr(t2m)));
3337 }
3338 }
3339
3340 return delta;
3341}
sewardj9b967672005-02-08 11:13:09 +00003342
3343
3344/* Signed/unsigned widening multiply. Generate IR to multiply the
3345 value in RAX/EAX/AX/AL by the given IRTemp, and park the result in
3346 RDX:RAX/EDX:EAX/DX:AX/AX.
3347*/
3348static void codegen_mulL_A_D ( Int sz, Bool syned,
sewardj1027dc22005-02-26 01:55:02 +00003349 IRTemp tmp, HChar* tmp_txt )
sewardj9b967672005-02-08 11:13:09 +00003350{
3351 IRType ty = szToITy(sz);
3352 IRTemp t1 = newTemp(ty);
3353
sewardj5b470602005-02-27 13:10:48 +00003354 assign( t1, getIRegRAX(sz) );
sewardj9b967672005-02-08 11:13:09 +00003355
3356 switch (ty) {
3357 case Ity_I64: {
3358 IRTemp res128 = newTemp(Ity_I128);
3359 IRTemp resHi = newTemp(Ity_I64);
3360 IRTemp resLo = newTemp(Ity_I64);
3361 IROp mulOp = syned ? Iop_MullS64 : Iop_MullU64;
sewardj8bdb89a2005-05-05 21:46:50 +00003362 UInt tBaseOp = syned ? AMD64G_CC_OP_SMULB : AMD64G_CC_OP_UMULB;
sewardj9b967672005-02-08 11:13:09 +00003363 setFlags_MUL ( Ity_I64, t1, tmp, tBaseOp );
3364 assign( res128, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
3365 assign( resHi, unop(Iop_128HIto64,mkexpr(res128)));
3366 assign( resLo, unop(Iop_128to64,mkexpr(res128)));
sewardj5b470602005-02-27 13:10:48 +00003367 putIReg64(R_RDX, mkexpr(resHi));
3368 putIReg64(R_RAX, mkexpr(resLo));
sewardj9b967672005-02-08 11:13:09 +00003369 break;
3370 }
sewardj85520e42005-02-19 15:22:38 +00003371 case Ity_I32: {
3372 IRTemp res64 = newTemp(Ity_I64);
3373 IRTemp resHi = newTemp(Ity_I32);
3374 IRTemp resLo = newTemp(Ity_I32);
3375 IROp mulOp = syned ? Iop_MullS32 : Iop_MullU32;
3376 UInt tBaseOp = syned ? AMD64G_CC_OP_SMULB : AMD64G_CC_OP_UMULB;
3377 setFlags_MUL ( Ity_I32, t1, tmp, tBaseOp );
3378 assign( res64, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
3379 assign( resHi, unop(Iop_64HIto32,mkexpr(res64)));
3380 assign( resLo, unop(Iop_64to32,mkexpr(res64)));
sewardj5b470602005-02-27 13:10:48 +00003381 putIRegRDX(4, mkexpr(resHi));
3382 putIRegRAX(4, mkexpr(resLo));
sewardj85520e42005-02-19 15:22:38 +00003383 break;
3384 }
3385 case Ity_I16: {
3386 IRTemp res32 = newTemp(Ity_I32);
3387 IRTemp resHi = newTemp(Ity_I16);
3388 IRTemp resLo = newTemp(Ity_I16);
3389 IROp mulOp = syned ? Iop_MullS16 : Iop_MullU16;
3390 UInt tBaseOp = syned ? AMD64G_CC_OP_SMULB : AMD64G_CC_OP_UMULB;
3391 setFlags_MUL ( Ity_I16, t1, tmp, tBaseOp );
3392 assign( res32, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
3393 assign( resHi, unop(Iop_32HIto16,mkexpr(res32)));
3394 assign( resLo, unop(Iop_32to16,mkexpr(res32)));
sewardj5b470602005-02-27 13:10:48 +00003395 putIRegRDX(2, mkexpr(resHi));
3396 putIRegRAX(2, mkexpr(resLo));
sewardj85520e42005-02-19 15:22:38 +00003397 break;
3398 }
3399 case Ity_I8: {
3400 IRTemp res16 = newTemp(Ity_I16);
3401 IRTemp resHi = newTemp(Ity_I8);
3402 IRTemp resLo = newTemp(Ity_I8);
3403 IROp mulOp = syned ? Iop_MullS8 : Iop_MullU8;
3404 UInt tBaseOp = syned ? AMD64G_CC_OP_SMULB : AMD64G_CC_OP_UMULB;
3405 setFlags_MUL ( Ity_I8, t1, tmp, tBaseOp );
3406 assign( res16, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
3407 assign( resHi, unop(Iop_16HIto8,mkexpr(res16)));
3408 assign( resLo, unop(Iop_16to8,mkexpr(res16)));
sewardj5b470602005-02-27 13:10:48 +00003409 putIRegRAX(2, mkexpr(res16));
sewardj85520e42005-02-19 15:22:38 +00003410 break;
3411 }
sewardj9b967672005-02-08 11:13:09 +00003412 default:
sewardj85520e42005-02-19 15:22:38 +00003413 ppIRType(ty);
sewardj9b967672005-02-08 11:13:09 +00003414 vpanic("codegen_mulL_A_D(amd64)");
3415 }
3416 DIP("%s%c %s\n", syned ? "imul" : "mul", nameISize(sz), tmp_txt);
3417}
sewardj32b2bbe2005-01-28 00:50:10 +00003418
3419
3420/* Group 3 extended opcodes. */
3421static
sewardj270def42005-07-03 01:03:01 +00003422ULong dis_Grp3 ( Prefix pfx, Int sz, Long delta )
sewardj32b2bbe2005-01-28 00:50:10 +00003423{
sewardj227458e2005-01-31 19:04:50 +00003424 Long d64;
sewardj32b2bbe2005-01-28 00:50:10 +00003425 UChar modrm;
3426 HChar dis_buf[50];
3427 Int len;
3428 IRTemp addr;
3429 IRType ty = szToITy(sz);
3430 IRTemp t1 = newTemp(ty);
sewardj55dbb262005-01-28 16:36:51 +00003431 IRTemp dst1, src, dst0;
sewardj8c332e22005-01-28 01:36:56 +00003432 modrm = getUChar(delta);
sewardj32b2bbe2005-01-28 00:50:10 +00003433 if (epartIsReg(modrm)) {
sewardj901ed122005-02-27 13:25:31 +00003434 switch (gregLO3ofRM(modrm)) {
sewardj118b23e2005-01-29 02:14:44 +00003435 case 0: { /* TEST */
3436 delta++;
3437 d64 = getSDisp(imin(4,sz), delta);
3438 delta += imin(4,sz);
3439 dst1 = newTemp(ty);
3440 assign(dst1, binop(mkSizedOp(ty,Iop_And8),
sewardj5b470602005-02-27 13:10:48 +00003441 getIRegE(sz,pfx,modrm),
sewardj03b07cc2005-01-31 18:09:43 +00003442 mkU(ty, d64 & mkSizeMask(sz))));
sewardj118b23e2005-01-29 02:14:44 +00003443 setFlags_DEP1( Iop_And8, dst1, ty );
sewardj7eaa7cf2005-01-31 18:55:22 +00003444 DIP("test%c $%lld, %s\n",
sewardj118b23e2005-01-29 02:14:44 +00003445 nameISize(sz), d64,
sewardj5b470602005-02-27 13:10:48 +00003446 nameIRegE(sz, pfx, modrm));
sewardj118b23e2005-01-29 02:14:44 +00003447 break;
3448 }
sewardj55dbb262005-01-28 16:36:51 +00003449 case 2: /* NOT */
3450 delta++;
sewardj5b470602005-02-27 13:10:48 +00003451 putIRegE(sz, pfx, modrm,
3452 unop(mkSizedOp(ty,Iop_Not8),
3453 getIRegE(sz, pfx, modrm)));
sewardj55dbb262005-01-28 16:36:51 +00003454 DIP("not%c %s\n", nameISize(sz),
sewardj5b470602005-02-27 13:10:48 +00003455 nameIRegE(sz, pfx, modrm));
sewardj55dbb262005-01-28 16:36:51 +00003456 break;
3457 case 3: /* NEG */
3458 delta++;
3459 dst0 = newTemp(ty);
3460 src = newTemp(ty);
3461 dst1 = newTemp(ty);
3462 assign(dst0, mkU(ty,0));
sewardj5b470602005-02-27 13:10:48 +00003463 assign(src, getIRegE(sz, pfx, modrm));
sewardj55dbb262005-01-28 16:36:51 +00003464 assign(dst1, binop(mkSizedOp(ty,Iop_Sub8), mkexpr(dst0), mkexpr(src)));
3465 setFlags_DEP1_DEP2(Iop_Sub8, dst0, src, ty);
sewardj5b470602005-02-27 13:10:48 +00003466 putIRegE(sz, pfx, modrm, mkexpr(dst1));
3467 DIP("neg%c %s\n", nameISize(sz), nameIRegE(sz, pfx, modrm));
sewardj55dbb262005-01-28 16:36:51 +00003468 break;
sewardj9b967672005-02-08 11:13:09 +00003469 case 4: /* MUL (unsigned widening) */
3470 delta++;
3471 src = newTemp(ty);
sewardj5b470602005-02-27 13:10:48 +00003472 assign(src, getIRegE(sz,pfx,modrm));
sewardj9b967672005-02-08 11:13:09 +00003473 codegen_mulL_A_D ( sz, False, src,
sewardj5b470602005-02-27 13:10:48 +00003474 nameIRegE(sz,pfx,modrm) );
sewardj9b967672005-02-08 11:13:09 +00003475 break;
sewardj85520e42005-02-19 15:22:38 +00003476 case 5: /* IMUL (signed widening) */
3477 delta++;
3478 src = newTemp(ty);
sewardj5b470602005-02-27 13:10:48 +00003479 assign(src, getIRegE(sz,pfx,modrm));
sewardj85520e42005-02-19 15:22:38 +00003480 codegen_mulL_A_D ( sz, True, src,
sewardj5b470602005-02-27 13:10:48 +00003481 nameIRegE(sz,pfx,modrm) );
sewardj85520e42005-02-19 15:22:38 +00003482 break;
sewardj03b07cc2005-01-31 18:09:43 +00003483 case 6: /* DIV */
3484 delta++;
sewardj5b470602005-02-27 13:10:48 +00003485 assign( t1, getIRegE(sz, pfx, modrm) );
sewardj03b07cc2005-01-31 18:09:43 +00003486 codegen_div ( sz, t1, False );
3487 DIP("div%c %s\n", nameISize(sz),
sewardj5b470602005-02-27 13:10:48 +00003488 nameIRegE(sz, pfx, modrm));
sewardj03b07cc2005-01-31 18:09:43 +00003489 break;
sewardj32b2bbe2005-01-28 00:50:10 +00003490 case 7: /* IDIV */
3491 delta++;
sewardj5b470602005-02-27 13:10:48 +00003492 assign( t1, getIRegE(sz, pfx, modrm) );
sewardj32b2bbe2005-01-28 00:50:10 +00003493 codegen_div ( sz, t1, True );
3494 DIP("idiv%c %s\n", nameISize(sz),
sewardj5b470602005-02-27 13:10:48 +00003495 nameIRegE(sz, pfx, modrm));
sewardj32b2bbe2005-01-28 00:50:10 +00003496 break;
3497 default:
3498 vex_printf(
sewardj901ed122005-02-27 13:25:31 +00003499 "unhandled Grp3(R) case %d\n", (Int)gregLO3ofRM(modrm));
sewardj32b2bbe2005-01-28 00:50:10 +00003500 vpanic("Grp3(amd64)");
3501 }
3502 } else {
sewardj7de0d3c2005-02-13 02:26:41 +00003503 addr = disAMode ( &len, pfx, delta, dis_buf,
3504 /* we have to inform disAMode of any immediate
3505 bytes used */
sewardj901ed122005-02-27 13:25:31 +00003506 gregLO3ofRM(modrm)==0/*TEST*/
sewardj7de0d3c2005-02-13 02:26:41 +00003507 ? imin(4,sz)
3508 : 0
3509 );
sewardj32b2bbe2005-01-28 00:50:10 +00003510 t1 = newTemp(ty);
3511 delta += len;
3512 assign(t1, loadLE(ty,mkexpr(addr)));
sewardj901ed122005-02-27 13:25:31 +00003513 switch (gregLO3ofRM(modrm)) {
sewardj03b07cc2005-01-31 18:09:43 +00003514 case 0: { /* TEST */
3515 d64 = getSDisp(imin(4,sz), delta);
3516 delta += imin(4,sz);
3517 dst1 = newTemp(ty);
3518 assign(dst1, binop(mkSizedOp(ty,Iop_And8),
3519 mkexpr(t1),
3520 mkU(ty, d64 & mkSizeMask(sz))));
3521 setFlags_DEP1( Iop_And8, dst1, ty );
3522 DIP("test%c $%lld, %s\n", nameISize(sz), d64, dis_buf);
3523 break;
3524 }
sewardj82c9f2f2005-03-02 16:05:13 +00003525 /* probably OK, but awaiting test case */
3526 case 2: /* NOT */
3527 storeLE( mkexpr(addr), unop(mkSizedOp(ty,Iop_Not8), mkexpr(t1)));
3528 DIP("not%c %s\n", nameISize(sz), dis_buf);
3529 break;
sewardj7de0d3c2005-02-13 02:26:41 +00003530 case 3: /* NEG */
3531 dst0 = newTemp(ty);
3532 src = newTemp(ty);
3533 dst1 = newTemp(ty);
3534 assign(dst0, mkU(ty,0));
3535 assign(src, mkexpr(t1));
3536 assign(dst1, binop(mkSizedOp(ty,Iop_Sub8), mkexpr(dst0), mkexpr(src)));
3537 setFlags_DEP1_DEP2(Iop_Sub8, dst0, src, ty);
3538 storeLE( mkexpr(addr), mkexpr(dst1) );
3539 DIP("neg%c %s\n", nameISize(sz), dis_buf);
3540 break;
sewardj31eecde2005-03-23 03:39:55 +00003541 case 4: /* MUL (unsigned widening) */
3542 codegen_mulL_A_D ( sz, False, t1, dis_buf );
3543 break;
sewardj3aba9eb2005-03-30 23:20:47 +00003544 case 5: /* IMUL */
3545 codegen_mulL_A_D ( sz, True, t1, dis_buf );
3546 break;
sewardj1001dc42005-02-21 08:25:55 +00003547 case 6: /* DIV */
3548 codegen_div ( sz, t1, False );
3549 DIP("div%c %s\n", nameISize(sz), dis_buf);
3550 break;
sewardj82c9f2f2005-03-02 16:05:13 +00003551 case 7: /* IDIV */
3552 codegen_div ( sz, t1, True );
3553 DIP("idiv%c %s\n", nameISize(sz), dis_buf);
3554 break;
sewardj32b2bbe2005-01-28 00:50:10 +00003555 default:
3556 vex_printf(
sewardj901ed122005-02-27 13:25:31 +00003557 "unhandled Grp3(M) case %d\n", (Int)gregLO3ofRM(modrm));
sewardj32b2bbe2005-01-28 00:50:10 +00003558 vpanic("Grp3(amd64)");
3559 }
3560 }
3561 return delta;
3562}
3563
3564
sewardj03b07cc2005-01-31 18:09:43 +00003565/* Group 4 extended opcodes. */
3566static
sewardj270def42005-07-03 01:03:01 +00003567ULong dis_Grp4 ( Prefix pfx, Long delta )
sewardj03b07cc2005-01-31 18:09:43 +00003568{
3569 Int alen;
3570 UChar modrm;
3571 HChar dis_buf[50];
3572 IRType ty = Ity_I8;
3573 IRTemp t1 = newTemp(ty);
3574 IRTemp t2 = newTemp(ty);
3575
3576 modrm = getUChar(delta);
3577 if (epartIsReg(modrm)) {
sewardj5b470602005-02-27 13:10:48 +00003578 assign(t1, getIRegE(1, pfx, modrm));
sewardj901ed122005-02-27 13:25:31 +00003579 switch (gregLO3ofRM(modrm)) {
sewardj85520e42005-02-19 15:22:38 +00003580 case 0: /* INC */
3581 assign(t2, binop(Iop_Add8, mkexpr(t1), mkU8(1)));
sewardj5b470602005-02-27 13:10:48 +00003582 putIRegE(1, pfx, modrm, mkexpr(t2));
sewardj85520e42005-02-19 15:22:38 +00003583 setFlags_INC_DEC( True, t2, ty );
3584 break;
sewardj03b07cc2005-01-31 18:09:43 +00003585 case 1: /* DEC */
3586 assign(t2, binop(Iop_Sub8, mkexpr(t1), mkU8(1)));
sewardj5b470602005-02-27 13:10:48 +00003587 putIRegE(1, pfx, modrm, mkexpr(t2));
sewardj03b07cc2005-01-31 18:09:43 +00003588 setFlags_INC_DEC( False, t2, ty );
3589 break;
3590 default:
3591 vex_printf(
sewardj901ed122005-02-27 13:25:31 +00003592 "unhandled Grp4(R) case %d\n", (Int)gregLO3ofRM(modrm));
sewardj03b07cc2005-01-31 18:09:43 +00003593 vpanic("Grp4(amd64,R)");
3594 }
3595 delta++;
sewardj901ed122005-02-27 13:25:31 +00003596 DIP("%sb %s\n", nameGrp4(gregLO3ofRM(modrm)),
sewardj5b470602005-02-27 13:10:48 +00003597 nameIRegE(1, pfx, modrm));
sewardj03b07cc2005-01-31 18:09:43 +00003598 } else {
sewardje1698952005-02-08 15:02:39 +00003599 IRTemp addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
sewardj03b07cc2005-01-31 18:09:43 +00003600 assign( t1, loadLE(ty, mkexpr(addr)) );
sewardj901ed122005-02-27 13:25:31 +00003601 switch (gregLO3ofRM(modrm)) {
sewardj007e9ec2005-03-23 11:36:48 +00003602 case 0: /* INC */
3603 assign(t2, binop(Iop_Add8, mkexpr(t1), mkU8(1)));
3604 storeLE( mkexpr(addr), mkexpr(t2) );
3605 setFlags_INC_DEC( True, t2, ty );
3606 break;
3607 case 1: /* DEC */
3608 assign(t2, binop(Iop_Sub8, mkexpr(t1), mkU8(1)));
3609 storeLE( mkexpr(addr), mkexpr(t2) );
3610 setFlags_INC_DEC( False, t2, ty );
3611 break;
sewardj03b07cc2005-01-31 18:09:43 +00003612 default:
3613 vex_printf(
sewardj901ed122005-02-27 13:25:31 +00003614 "unhandled Grp4(M) case %d\n", (Int)gregLO3ofRM(modrm));
sewardj03b07cc2005-01-31 18:09:43 +00003615 vpanic("Grp4(amd64,M)");
3616 }
3617 delta += alen;
sewardj901ed122005-02-27 13:25:31 +00003618 DIP("%sb %s\n", nameGrp4(gregLO3ofRM(modrm)), dis_buf);
sewardj03b07cc2005-01-31 18:09:43 +00003619 }
3620 return delta;
3621}
sewardj354e5c62005-01-27 20:12:52 +00003622
3623
3624/* Group 5 extended opcodes. */
3625static
sewardj270def42005-07-03 01:03:01 +00003626ULong dis_Grp5 ( Prefix pfx, Int sz, Long delta, DisResult* dres )
sewardj354e5c62005-01-27 20:12:52 +00003627{
3628 Int len;
3629 UChar modrm;
3630 HChar dis_buf[50];
3631 IRTemp addr = IRTemp_INVALID;
3632 IRType ty = szToITy(sz);
3633 IRTemp t1 = newTemp(ty);
3634 IRTemp t2 = IRTemp_INVALID;
sewardj03b07cc2005-01-31 18:09:43 +00003635 IRTemp t3 = IRTemp_INVALID;
sewardj7eaa7cf2005-01-31 18:55:22 +00003636 Bool showSz = True;
sewardj354e5c62005-01-27 20:12:52 +00003637
sewardj8c332e22005-01-28 01:36:56 +00003638 modrm = getUChar(delta);
sewardj354e5c62005-01-27 20:12:52 +00003639 if (epartIsReg(modrm)) {
sewardj5b470602005-02-27 13:10:48 +00003640 assign(t1, getIRegE(sz,pfx,modrm));
sewardj901ed122005-02-27 13:25:31 +00003641 switch (gregLO3ofRM(modrm)) {
sewardj32b2bbe2005-01-28 00:50:10 +00003642 case 0: /* INC */
3643 t2 = newTemp(ty);
3644 assign(t2, binop(mkSizedOp(ty,Iop_Add8),
3645 mkexpr(t1), mkU(ty,1)));
3646 setFlags_INC_DEC( True, t2, ty );
sewardj5b470602005-02-27 13:10:48 +00003647 putIRegE(sz,pfx,modrm, mkexpr(t2));
sewardj32b2bbe2005-01-28 00:50:10 +00003648 break;
3649 case 1: /* DEC */
3650 t2 = newTemp(ty);
3651 assign(t2, binop(mkSizedOp(ty,Iop_Sub8),
3652 mkexpr(t1), mkU(ty,1)));
3653 setFlags_INC_DEC( False, t2, ty );
sewardj5b470602005-02-27 13:10:48 +00003654 putIRegE(sz,pfx,modrm, mkexpr(t2));
sewardj32b2bbe2005-01-28 00:50:10 +00003655 break;
sewardj354e5c62005-01-27 20:12:52 +00003656 case 2: /* call Ev */
sewardj03b07cc2005-01-31 18:09:43 +00003657 /* Ignore any sz value and operate as if sz==8. */
sewardjb7bcdf92005-08-02 21:20:36 +00003658 vassert(sz == 4 || sz == 8);
sewardj03b07cc2005-01-31 18:09:43 +00003659 sz = 8;
3660 t3 = newTemp(Ity_I64);
sewardj5b470602005-02-27 13:10:48 +00003661 assign(t3, getIRegE(sz,pfx,modrm));
sewardj03b07cc2005-01-31 18:09:43 +00003662 t2 = newTemp(Ity_I64);
3663 assign(t2, binop(Iop_Sub64, getIReg64(R_RSP), mkU64(8)));
3664 putIReg64(R_RSP, mkexpr(t2));
sewardj9e6491a2005-07-02 19:24:10 +00003665 storeLE( mkexpr(t2), mkU64(guest_RIP_bbstart+delta+1));
sewardj5a9ffab2005-05-12 17:55:01 +00003666 make_redzone_AbiHint(t2, "call-Ev(reg)");
sewardj03b07cc2005-01-31 18:09:43 +00003667 jmp_treg(Ijk_Call,t3);
sewardj9e6491a2005-07-02 19:24:10 +00003668 dres->whatNext = Dis_StopHere;
sewardj7eaa7cf2005-01-31 18:55:22 +00003669 showSz = False;
sewardj354e5c62005-01-27 20:12:52 +00003670 break;
sewardj354e5c62005-01-27 20:12:52 +00003671 case 4: /* jmp Ev */
sewardj03b07cc2005-01-31 18:09:43 +00003672 /* Ignore any sz value and operate as if sz==8. */
sewardj0bfc6b62005-07-07 14:15:35 +00003673 vassert(sz == 4 || sz == 8);
sewardj03b07cc2005-01-31 18:09:43 +00003674 sz = 8;
3675 t3 = newTemp(Ity_I64);
sewardj5b470602005-02-27 13:10:48 +00003676 assign(t3, getIRegE(sz,pfx,modrm));
sewardj03b07cc2005-01-31 18:09:43 +00003677 jmp_treg(Ijk_Boring,t3);
sewardj9e6491a2005-07-02 19:24:10 +00003678 dres->whatNext = Dis_StopHere;
sewardj7eaa7cf2005-01-31 18:55:22 +00003679 showSz = False;
sewardj354e5c62005-01-27 20:12:52 +00003680 break;
sewardj354e5c62005-01-27 20:12:52 +00003681 default:
3682 vex_printf(
sewardj901ed122005-02-27 13:25:31 +00003683 "unhandled Grp5(R) case %d\n", (Int)gregLO3ofRM(modrm));
sewardj354e5c62005-01-27 20:12:52 +00003684 vpanic("Grp5(amd64)");
3685 }
3686 delta++;
sewardj901ed122005-02-27 13:25:31 +00003687 DIP("%s%c %s\n", nameGrp5(gregLO3ofRM(modrm)),
sewardj7eaa7cf2005-01-31 18:55:22 +00003688 showSz ? nameISize(sz) : ' ',
sewardj5b470602005-02-27 13:10:48 +00003689 nameIRegE(sz, pfx, modrm));
sewardj354e5c62005-01-27 20:12:52 +00003690 } else {
sewardje1698952005-02-08 15:02:39 +00003691 addr = disAMode ( &len, pfx, delta, dis_buf, 0 );
sewardj901ed122005-02-27 13:25:31 +00003692 if (gregLO3ofRM(modrm) != 2 && gregLO3ofRM(modrm) != 4
3693 && gregLO3ofRM(modrm) != 6) {
sewardj03b07cc2005-01-31 18:09:43 +00003694 assign(t1, loadLE(ty,mkexpr(addr)));
sewardj909c06d2005-02-19 22:47:41 +00003695 }
sewardj901ed122005-02-27 13:25:31 +00003696 switch (gregLO3ofRM(modrm)) {
sewardj354e5c62005-01-27 20:12:52 +00003697 case 0: /* INC */
sewardj354e5c62005-01-27 20:12:52 +00003698 t2 = newTemp(ty);
3699 assign(t2, binop(mkSizedOp(ty,Iop_Add8),
3700 mkexpr(t1), mkU(ty,1)));
3701 setFlags_INC_DEC( True, t2, ty );
3702 storeLE(mkexpr(addr),mkexpr(t2));
3703 break;
sewardj354e5c62005-01-27 20:12:52 +00003704 case 1: /* DEC */
3705 t2 = newTemp(ty);
3706 assign(t2, binop(mkSizedOp(ty,Iop_Sub8),
3707 mkexpr(t1), mkU(ty,1)));
3708 setFlags_INC_DEC( False, t2, ty );
3709 storeLE(mkexpr(addr),mkexpr(t2));
3710 break;
3711 case 2: /* call Ev */
sewardj03b07cc2005-01-31 18:09:43 +00003712 /* Ignore any sz value and operate as if sz==8. */
sewardj354e5c62005-01-27 20:12:52 +00003713 vassert(sz == 4);
sewardj7eaa7cf2005-01-31 18:55:22 +00003714 sz = 8;
sewardj03b07cc2005-01-31 18:09:43 +00003715 t3 = newTemp(Ity_I64);
3716 assign(t3, loadLE(Ity_I64,mkexpr(addr)));
3717 t2 = newTemp(Ity_I64);
3718 assign(t2, binop(Iop_Sub64, getIReg64(R_RSP), mkU64(8)));
3719 putIReg64(R_RSP, mkexpr(t2));
sewardj9e6491a2005-07-02 19:24:10 +00003720 storeLE( mkexpr(t2), mkU64(guest_RIP_bbstart+delta+len));
sewardj5a9ffab2005-05-12 17:55:01 +00003721 make_redzone_AbiHint(t2, "call-Ev(mem)");
sewardj03b07cc2005-01-31 18:09:43 +00003722 jmp_treg(Ijk_Call,t3);
sewardj9e6491a2005-07-02 19:24:10 +00003723 dres->whatNext = Dis_StopHere;
sewardj7eaa7cf2005-01-31 18:55:22 +00003724 showSz = False;
sewardj354e5c62005-01-27 20:12:52 +00003725 break;
sewardj354e5c62005-01-27 20:12:52 +00003726 case 4: /* JMP Ev */
sewardj03b07cc2005-01-31 18:09:43 +00003727 /* Ignore any sz value and operate as if sz==8. */
sewardj354e5c62005-01-27 20:12:52 +00003728 vassert(sz == 4);
sewardj7eaa7cf2005-01-31 18:55:22 +00003729 sz = 8;
sewardj03b07cc2005-01-31 18:09:43 +00003730 t3 = newTemp(Ity_I64);
3731 assign(t3, loadLE(Ity_I64,mkexpr(addr)));
3732 jmp_treg(Ijk_Boring,t3);
sewardj9e6491a2005-07-02 19:24:10 +00003733 dres->whatNext = Dis_StopHere;
sewardj7eaa7cf2005-01-31 18:55:22 +00003734 showSz = False;
sewardj354e5c62005-01-27 20:12:52 +00003735 break;
sewardj354e5c62005-01-27 20:12:52 +00003736 case 6: /* PUSH Ev */
sewardja6b93d12005-02-17 09:28:28 +00003737 /* There is no encoding for 32-bit operand size; hence ... */
3738 if (sz == 4) sz = 8;
3739 vassert(sz == 8 || sz == 2);
sewardj909c06d2005-02-19 22:47:41 +00003740 if (sz == 8) {
3741 t3 = newTemp(Ity_I64);
3742 assign(t3, loadLE(Ity_I64,mkexpr(addr)));
3743 t2 = newTemp(Ity_I64);
3744 assign( t2, binop(Iop_Sub64,getIReg64(R_RSP),mkU64(sz)) );
3745 putIReg64(R_RSP, mkexpr(t2) );
3746 storeLE( mkexpr(t2), mkexpr(t3) );
3747 break;
3748 } else {
3749 goto unhandled; /* awaiting test case */
3750 }
sewardj354e5c62005-01-27 20:12:52 +00003751 default:
sewardja6b93d12005-02-17 09:28:28 +00003752 unhandled:
sewardj354e5c62005-01-27 20:12:52 +00003753 vex_printf(
sewardj901ed122005-02-27 13:25:31 +00003754 "unhandled Grp5(M) case %d\n", (Int)gregLO3ofRM(modrm));
sewardj354e5c62005-01-27 20:12:52 +00003755 vpanic("Grp5(amd64)");
3756 }
3757 delta += len;
sewardj901ed122005-02-27 13:25:31 +00003758 DIP("%s%c %s\n", nameGrp5(gregLO3ofRM(modrm)),
sewardj7eaa7cf2005-01-31 18:55:22 +00003759 showSz ? nameISize(sz) : ' ',
3760 dis_buf);
sewardj354e5c62005-01-27 20:12:52 +00003761 }
3762 return delta;
3763}
3764
3765
sewardjd0a12df2005-02-10 02:07:43 +00003766/*------------------------------------------------------------*/
3767/*--- Disassembling string ops (including REP prefixes) ---*/
3768/*------------------------------------------------------------*/
3769
3770/* Code shared by all the string ops */
3771static
3772void dis_string_op_increment ( Int sz, IRTemp t_inc )
3773{
3774 UChar logSz;
3775 if (sz == 8 || sz == 4 || sz == 2) {
3776 logSz = 1;
3777 if (sz == 4) logSz = 2;
3778 if (sz == 8) logSz = 3;
3779 assign( t_inc,
3780 binop(Iop_Shl64, IRExpr_Get( OFFB_DFLAG, Ity_I64 ),
3781 mkU8(logSz) ) );
3782 } else {
3783 assign( t_inc,
3784 IRExpr_Get( OFFB_DFLAG, Ity_I64 ) );
3785 }
3786}
3787
sewardj909c06d2005-02-19 22:47:41 +00003788static
3789void dis_string_op( void (*dis_OP)( Int, IRTemp ),
3790 Int sz, HChar* name, Prefix pfx )
3791{
3792 IRTemp t_inc = newTemp(Ity_I64);
3793 /* Really we ought to inspect the override prefixes, but we don't.
3794 The following assertion catches any resulting sillyness. */
3795 vassert(pfx == clearSegBits(pfx));
3796 dis_string_op_increment(sz, t_inc);
3797 dis_OP( sz, t_inc );
3798 DIP("%s%c\n", name, nameISize(sz));
3799}
3800
3801static
3802void dis_MOVS ( Int sz, IRTemp t_inc )
3803{
3804 IRType ty = szToITy(sz);
3805 IRTemp td = newTemp(Ity_I64); /* RDI */
3806 IRTemp ts = newTemp(Ity_I64); /* RSI */
3807
3808 assign( td, getIReg64(R_RDI) );
3809 assign( ts, getIReg64(R_RSI) );
3810
3811 storeLE( mkexpr(td), loadLE(ty,mkexpr(ts)) );
3812
3813 putIReg64( R_RDI, binop(Iop_Add64, mkexpr(td), mkexpr(t_inc)) );
3814 putIReg64( R_RSI, binop(Iop_Add64, mkexpr(ts), mkexpr(t_inc)) );
3815}
3816
sewardjd20c8852005-01-20 20:04:07 +00003817//.. //-- static
3818//.. //-- void dis_LODS ( UCodeBlock* cb, Int sz, Int t_inc )
3819//.. //-- {
3820//.. //-- Int ta = newTemp(cb); /* EAX */
3821//.. //-- Int ts = newTemp(cb); /* ESI */
3822//.. //--
3823//.. //-- uInstr2(cb, GET, 4, ArchReg, R_ESI, TempReg, ts);
3824//.. //-- uInstr2(cb, LOAD, sz, TempReg, ts, TempReg, ta);
3825//.. //-- uInstr2(cb, PUT, sz, TempReg, ta, ArchReg, R_EAX);
3826//.. //--
3827//.. //-- uInstr2(cb, ADD, 4, TempReg, t_inc, TempReg, ts);
3828//.. //-- uInstr2(cb, PUT, 4, TempReg, ts, ArchReg, R_ESI);
3829//.. //-- }
sewardja6b93d12005-02-17 09:28:28 +00003830
3831static
3832void dis_STOS ( Int sz, IRTemp t_inc )
3833{
3834 IRType ty = szToITy(sz);
3835 IRTemp ta = newTemp(ty); /* rAX */
3836 IRTemp td = newTemp(Ity_I64); /* RDI */
3837
sewardj5b470602005-02-27 13:10:48 +00003838 assign( ta, getIRegRAX(sz) );
sewardja6b93d12005-02-17 09:28:28 +00003839
3840 assign( td, getIReg64(R_RDI) );
3841
3842 storeLE( mkexpr(td), mkexpr(ta) );
3843
3844 putIReg64( R_RDI, binop(Iop_Add64, mkexpr(td), mkexpr(t_inc)) );
3845}
sewardjd0a12df2005-02-10 02:07:43 +00003846
3847static
3848void dis_CMPS ( Int sz, IRTemp t_inc )
3849{
3850 IRType ty = szToITy(sz);
3851 IRTemp tdv = newTemp(ty); /* (RDI) */
3852 IRTemp tsv = newTemp(ty); /* (RSI) */
3853 IRTemp td = newTemp(Ity_I64); /* RDI */
3854 IRTemp ts = newTemp(Ity_I64); /* RSI */
3855
3856 assign( td, getIReg64(R_RDI) );
3857
3858 assign( ts, getIReg64(R_RSI) );
3859
3860 assign( tdv, loadLE(ty,mkexpr(td)) );
3861
3862 assign( tsv, loadLE(ty,mkexpr(ts)) );
3863
3864 setFlags_DEP1_DEP2 ( Iop_Sub8, tsv, tdv, ty );
3865
3866 putIReg64(R_RDI, binop(Iop_Add64, mkexpr(td), mkexpr(t_inc)) );
3867
3868 putIReg64(R_RSI, binop(Iop_Add64, mkexpr(ts), mkexpr(t_inc)) );
3869}
3870
sewardj85520e42005-02-19 15:22:38 +00003871static
3872void dis_SCAS ( Int sz, IRTemp t_inc )
3873{
3874 IRType ty = szToITy(sz);
3875 IRTemp ta = newTemp(ty); /* rAX */
3876 IRTemp td = newTemp(Ity_I64); /* RDI */
3877 IRTemp tdv = newTemp(ty); /* (RDI) */
3878
sewardj5b470602005-02-27 13:10:48 +00003879 assign( ta, getIRegRAX(sz) );
sewardj85520e42005-02-19 15:22:38 +00003880
3881 assign( td, getIReg64(R_RDI) );
3882
3883 assign( tdv, loadLE(ty,mkexpr(td)) );
3884
3885 setFlags_DEP1_DEP2 ( Iop_Sub8, ta, tdv, ty );
3886
3887 putIReg64(R_RDI, binop(Iop_Add64, mkexpr(td), mkexpr(t_inc)) );
3888}
sewardjd0a12df2005-02-10 02:07:43 +00003889
3890
3891/* Wrap the appropriate string op inside a REP/REPE/REPNE. We assume
3892 the insn is the last one in the basic block, and so emit a jump to
3893 the next insn, rather than just falling through. */
3894static
3895void dis_REP_op ( AMD64Condcode cond,
3896 void (*dis_OP)(Int, IRTemp),
sewardj909c06d2005-02-19 22:47:41 +00003897 Int sz, Addr64 rip, Addr64 rip_next, HChar* name,
3898 Prefix pfx )
sewardjd0a12df2005-02-10 02:07:43 +00003899{
3900 IRTemp t_inc = newTemp(Ity_I64);
3901 IRTemp tc = newTemp(Ity_I64); /* RCX */
3902
sewardj909c06d2005-02-19 22:47:41 +00003903 /* Really we ought to inspect the override prefixes, but we don't.
3904 The following assertion catches any resulting sillyness. */
3905 vassert(pfx == clearSegBits(pfx));
3906
sewardjd0a12df2005-02-10 02:07:43 +00003907 assign( tc, getIReg64(R_RCX) );
3908
3909 stmt( IRStmt_Exit( binop(Iop_CmpEQ64,mkexpr(tc),mkU64(0)),
3910 Ijk_Boring,
3911 IRConst_U64(rip_next) ) );
3912
3913 putIReg64(R_RCX, binop(Iop_Sub64, mkexpr(tc), mkU64(1)) );
3914
3915 dis_string_op_increment(sz, t_inc);
3916 dis_OP (sz, t_inc);
3917
3918 if (cond == AMD64CondAlways) {
3919 jmp_lit(Ijk_Boring,rip);
3920 } else {
3921 stmt( IRStmt_Exit( mk_amd64g_calculate_condition(cond),
3922 Ijk_Boring,
3923 IRConst_U64(rip) ) );
3924 jmp_lit(Ijk_Boring,rip_next);
3925 }
3926 DIP("%s%c\n", name, nameISize(sz));
3927}
sewardj32b2bbe2005-01-28 00:50:10 +00003928
3929
3930/*------------------------------------------------------------*/
3931/*--- Arithmetic, etc. ---*/
3932/*------------------------------------------------------------*/
3933
3934/* IMUL E, G. Supplied eip points to the modR/M byte. */
3935static
3936ULong dis_mul_E_G ( Prefix pfx,
3937 Int size,
sewardj270def42005-07-03 01:03:01 +00003938 Long delta0 )
sewardj32b2bbe2005-01-28 00:50:10 +00003939{
3940 Int alen;
3941 HChar dis_buf[50];
sewardj8c332e22005-01-28 01:36:56 +00003942 UChar rm = getUChar(delta0);
sewardj32b2bbe2005-01-28 00:50:10 +00003943 IRType ty = szToITy(size);
3944 IRTemp te = newTemp(ty);
3945 IRTemp tg = newTemp(ty);
3946 IRTemp resLo = newTemp(ty);
3947
sewardj5b470602005-02-27 13:10:48 +00003948 assign( tg, getIRegG(size, pfx, rm) );
sewardj32b2bbe2005-01-28 00:50:10 +00003949 if (epartIsReg(rm)) {
sewardj5b470602005-02-27 13:10:48 +00003950 assign( te, getIRegE(size, pfx, rm) );
sewardj32b2bbe2005-01-28 00:50:10 +00003951 } else {
sewardje1698952005-02-08 15:02:39 +00003952 IRTemp addr = disAMode( &alen, pfx, delta0, dis_buf, 0 );
sewardj32b2bbe2005-01-28 00:50:10 +00003953 assign( te, loadLE(ty,mkexpr(addr)) );
3954 }
3955
3956 setFlags_MUL ( ty, te, tg, AMD64G_CC_OP_SMULB );
3957
3958 assign( resLo, binop( mkSizedOp(ty, Iop_Mul8), mkexpr(te), mkexpr(tg) ) );
3959
sewardj5b470602005-02-27 13:10:48 +00003960 putIRegG(size, pfx, rm, mkexpr(resLo) );
sewardj32b2bbe2005-01-28 00:50:10 +00003961
3962 if (epartIsReg(rm)) {
3963 DIP("imul%c %s, %s\n", nameISize(size),
sewardj901ed122005-02-27 13:25:31 +00003964 nameIRegE(size,pfx,rm),
3965 nameIRegG(size,pfx,rm));
sewardj32b2bbe2005-01-28 00:50:10 +00003966 return 1+delta0;
3967 } else {
3968 DIP("imul%c %s, %s\n", nameISize(size),
3969 dis_buf,
sewardj901ed122005-02-27 13:25:31 +00003970 nameIRegG(size,pfx,rm));
sewardj32b2bbe2005-01-28 00:50:10 +00003971 return alen+delta0;
3972 }
3973}
3974
3975
3976/* IMUL I * E -> G. Supplied rip points to the modR/M byte. */
3977static
3978ULong dis_imul_I_E_G ( Prefix pfx,
3979 Int size,
sewardj270def42005-07-03 01:03:01 +00003980 Long delta,
sewardj32b2bbe2005-01-28 00:50:10 +00003981 Int litsize )
3982{
3983 Long d64;
3984 Int alen;
3985 HChar dis_buf[50];
sewardj8c332e22005-01-28 01:36:56 +00003986 UChar rm = getUChar(delta);
sewardj32b2bbe2005-01-28 00:50:10 +00003987 IRType ty = szToITy(size);
3988 IRTemp te = newTemp(ty);
3989 IRTemp tl = newTemp(ty);
3990 IRTemp resLo = newTemp(ty);
3991
sewardj85520e42005-02-19 15:22:38 +00003992 vassert(/*size == 1 ||*/ size == 2 || size == 4 || size == 8);
sewardj32b2bbe2005-01-28 00:50:10 +00003993
3994 if (epartIsReg(rm)) {
sewardj5b470602005-02-27 13:10:48 +00003995 assign(te, getIRegE(size, pfx, rm));
sewardj32b2bbe2005-01-28 00:50:10 +00003996 delta++;
3997 } else {
sewardj7de0d3c2005-02-13 02:26:41 +00003998 IRTemp addr = disAMode( &alen, pfx, delta, dis_buf,
3999 imin(4,litsize) );
sewardj32b2bbe2005-01-28 00:50:10 +00004000 assign(te, loadLE(ty, mkexpr(addr)));
4001 delta += alen;
4002 }
4003 d64 = getSDisp(imin(4,litsize),delta);
4004 delta += imin(4,litsize);
4005
sewardj1389d4d2005-01-28 13:46:29 +00004006 d64 &= mkSizeMask(size);
sewardj32b2bbe2005-01-28 00:50:10 +00004007 assign(tl, mkU(ty,d64));
4008
4009 assign( resLo, binop( mkSizedOp(ty, Iop_Mul8), mkexpr(te), mkexpr(tl) ));
4010
4011 setFlags_MUL ( ty, te, tl, AMD64G_CC_OP_SMULB );
4012
sewardj5b470602005-02-27 13:10:48 +00004013 putIRegG(size, pfx, rm, mkexpr(resLo));
sewardj32b2bbe2005-01-28 00:50:10 +00004014
4015 DIP("imul%c $%lld, %s, %s\n",
4016 nameISize(size), d64,
sewardj5b470602005-02-27 13:10:48 +00004017 ( epartIsReg(rm) ? nameIRegE(size,pfx,rm) : dis_buf ),
4018 nameIRegG(size,pfx,rm) );
sewardj32b2bbe2005-01-28 00:50:10 +00004019 return delta;
4020}
4021
4022
sewardjbcbb9de2005-03-27 02:22:32 +00004023/*------------------------------------------------------------*/
4024/*--- ---*/
4025/*--- x87 FLOATING POINT INSTRUCTIONS ---*/
4026/*--- ---*/
4027/*------------------------------------------------------------*/
4028
4029/* --- Helper functions for dealing with the register stack. --- */
4030
4031/* --- Set the emulation-warning pseudo-register. --- */
4032
4033static void put_emwarn ( IRExpr* e /* :: Ity_I32 */ )
4034{
4035 vassert(typeOfIRExpr(irbb->tyenv, e) == Ity_I32);
4036 stmt( IRStmt_Put( OFFB_EMWARN, e ) );
4037}
sewardj8d965312005-02-25 02:48:47 +00004038
4039/* --- Produce an IRExpr* denoting a 64-bit QNaN. --- */
4040
4041static IRExpr* mkQNaN64 ( void )
4042{
4043 /* QNaN is 0 2047 1 0(51times)
4044 == 0b 11111111111b 1 0(51times)
4045 == 0x7FF8 0000 0000 0000
4046 */
4047 return IRExpr_Const(IRConst_F64i(0x7FF8000000000000ULL));
4048}
4049
4050/* --------- Get/put the top-of-stack pointer :: Ity_I32 --------- */
4051
4052static IRExpr* get_ftop ( void )
4053{
4054 return IRExpr_Get( OFFB_FTOP, Ity_I32 );
4055}
4056
4057static void put_ftop ( IRExpr* e )
4058{
4059 vassert(typeOfIRExpr(irbb->tyenv, e) == Ity_I32);
4060 stmt( IRStmt_Put( OFFB_FTOP, e ) );
4061}
4062
sewardj25a85812005-05-08 23:03:48 +00004063/* --------- Get/put the C3210 bits. --------- */
4064
4065static IRExpr* /* :: Ity_I64 */ get_C3210 ( void )
4066{
4067 return IRExpr_Get( OFFB_FC3210, Ity_I64 );
4068}
4069
4070static void put_C3210 ( IRExpr* e /* :: Ity_I64 */ )
4071{
4072 vassert(typeOfIRExpr(irbb->tyenv, e) == Ity_I64);
4073 stmt( IRStmt_Put( OFFB_FC3210, e ) );
4074}
sewardjc49ce232005-02-25 13:03:03 +00004075
4076/* --------- Get/put the FPU rounding mode. --------- */
4077static IRExpr* /* :: Ity_I32 */ get_fpround ( void )
4078{
4079 return unop(Iop_64to32, IRExpr_Get( OFFB_FPROUND, Ity_I64 ));
4080}
4081
sewardj5e205372005-05-09 02:57:08 +00004082static void put_fpround ( IRExpr* /* :: Ity_I32 */ e )
4083{
4084 vassert(typeOfIRExpr(irbb->tyenv, e) == Ity_I32);
4085 stmt( IRStmt_Put( OFFB_FPROUND, unop(Iop_32Uto64,e) ) );
4086}
sewardjc49ce232005-02-25 13:03:03 +00004087
4088
4089/* --------- Synthesise a 2-bit FPU rounding mode. --------- */
4090/* Produces a value in 0 .. 3, which is encoded as per the type
4091 IRRoundingMode. Since the guest_FPROUND value is also encoded as
4092 per IRRoundingMode, we merely need to get it and mask it for
4093 safety.
4094*/
4095static IRExpr* /* :: Ity_I32 */ get_roundingmode ( void )
4096{
4097 return binop( Iop_And32, get_fpround(), mkU32(3) );
4098}
sewardj8d965312005-02-25 02:48:47 +00004099
sewardj4796d662006-02-05 16:06:26 +00004100static IRExpr* /* :: Ity_I32 */ get_FAKE_roundingmode ( void )
4101{
4102 return mkU32(Irrm_NEAREST);
4103}
4104
sewardj8d965312005-02-25 02:48:47 +00004105
4106/* --------- Get/set FP register tag bytes. --------- */
4107
4108/* Given i, and some expression e, generate 'ST_TAG(i) = e'. */
4109
4110static void put_ST_TAG ( Int i, IRExpr* value )
4111{
4112 IRArray* descr;
4113 vassert(typeOfIRExpr(irbb->tyenv, value) == Ity_I8);
4114 descr = mkIRArray( OFFB_FPTAGS, Ity_I8, 8 );
4115 stmt( IRStmt_PutI( descr, get_ftop(), i, value ) );
4116}
4117
4118/* Given i, generate an expression yielding 'ST_TAG(i)'. This will be
4119 zero to indicate "Empty" and nonzero to indicate "NonEmpty". */
4120
4121static IRExpr* get_ST_TAG ( Int i )
4122{
4123 IRArray* descr = mkIRArray( OFFB_FPTAGS, Ity_I8, 8 );
4124 return IRExpr_GetI( descr, get_ftop(), i );
4125}
4126
4127
4128/* --------- Get/set FP registers. --------- */
4129
4130/* Given i, and some expression e, emit 'ST(i) = e' and set the
4131 register's tag to indicate the register is full. The previous
4132 state of the register is not checked. */
4133
4134static void put_ST_UNCHECKED ( Int i, IRExpr* value )
4135{
4136 IRArray* descr;
4137 vassert(typeOfIRExpr(irbb->tyenv, value) == Ity_F64);
4138 descr = mkIRArray( OFFB_FPREGS, Ity_F64, 8 );
4139 stmt( IRStmt_PutI( descr, get_ftop(), i, value ) );
4140 /* Mark the register as in-use. */
4141 put_ST_TAG(i, mkU8(1));
4142}
4143
4144/* Given i, and some expression e, emit
4145 ST(i) = is_full(i) ? NaN : e
4146 and set the tag accordingly.
4147*/
4148
4149static void put_ST ( Int i, IRExpr* value )
4150{
4151 put_ST_UNCHECKED( i,
4152 IRExpr_Mux0X( get_ST_TAG(i),
4153 /* 0 means empty */
4154 value,
4155 /* non-0 means full */
4156 mkQNaN64()
4157 )
4158 );
4159}
4160
4161
4162/* Given i, generate an expression yielding 'ST(i)'. */
4163
4164static IRExpr* get_ST_UNCHECKED ( Int i )
4165{
4166 IRArray* descr = mkIRArray( OFFB_FPREGS, Ity_F64, 8 );
4167 return IRExpr_GetI( descr, get_ftop(), i );
4168}
4169
4170
4171/* Given i, generate an expression yielding
4172 is_full(i) ? ST(i) : NaN
4173*/
4174
4175static IRExpr* get_ST ( Int i )
4176{
4177 return
4178 IRExpr_Mux0X( get_ST_TAG(i),
4179 /* 0 means empty */
4180 mkQNaN64(),
4181 /* non-0 means full */
4182 get_ST_UNCHECKED(i));
4183}
4184
4185
4186/* Adjust FTOP downwards by one register. */
4187
4188static void fp_push ( void )
4189{
4190 put_ftop( binop(Iop_Sub32, get_ftop(), mkU32(1)) );
4191}
4192
4193/* Adjust FTOP upwards by one register, and mark the vacated register
4194 as empty. */
4195
4196static void fp_pop ( void )
4197{
4198 put_ST_TAG(0, mkU8(0));
4199 put_ftop( binop(Iop_Add32, get_ftop(), mkU32(1)) );
4200}
4201
sewardj25a85812005-05-08 23:03:48 +00004202/* Clear the C2 bit of the FPU status register, for
4203 sin/cos/tan/sincos. */
4204
4205static void clear_C2 ( void )
4206{
4207 put_C3210( binop(Iop_And64, get_C3210(), mkU64(~AMD64G_FC_MASK_C2)) );
4208}
sewardj48a89d82005-05-06 11:50:13 +00004209
sewardj7c2d2822006-03-07 00:22:02 +00004210/* Invent a plausible-looking FPU status word value:
4211 ((ftop & 7) << 11) | (c3210 & 0x4700)
4212 */
4213static IRExpr* get_FPU_sw ( void )
4214{
4215 return
4216 unop(Iop_32to16,
4217 binop(Iop_Or32,
4218 binop(Iop_Shl32,
4219 binop(Iop_And32, get_ftop(), mkU32(7)),
4220 mkU8(11)),
4221 binop(Iop_And32, unop(Iop_64to32, get_C3210()),
4222 mkU32(0x4700))
4223 ));
4224}
4225
sewardj48a89d82005-05-06 11:50:13 +00004226
4227/* ------------------------------------------------------- */
4228/* Given all that stack-mangling junk, we can now go ahead
4229 and describe FP instructions.
4230*/
4231
4232/* ST(0) = ST(0) `op` mem64/32(addr)
4233 Need to check ST(0)'s tag on read, but not on write.
4234*/
4235static
sewardjca673ab2005-05-11 10:03:08 +00004236void fp_do_op_mem_ST_0 ( IRTemp addr, HChar* op_txt, HChar* dis_buf,
sewardj48a89d82005-05-06 11:50:13 +00004237 IROp op, Bool dbl )
4238{
4239 DIP("f%s%c %s\n", op_txt, dbl?'l':'s', dis_buf);
4240 if (dbl) {
4241 put_ST_UNCHECKED(0,
sewardj4796d662006-02-05 16:06:26 +00004242 triop( op,
4243 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardj48a89d82005-05-06 11:50:13 +00004244 get_ST(0),
4245 loadLE(Ity_F64,mkexpr(addr))
4246 ));
4247 } else {
4248 put_ST_UNCHECKED(0,
sewardj4796d662006-02-05 16:06:26 +00004249 triop( op,
4250 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardj48a89d82005-05-06 11:50:13 +00004251 get_ST(0),
4252 unop(Iop_F32toF64, loadLE(Ity_F32,mkexpr(addr)))
4253 ));
4254 }
4255}
sewardj7bc00082005-03-27 05:08:32 +00004256
4257
4258/* ST(0) = mem64/32(addr) `op` ST(0)
4259 Need to check ST(0)'s tag on read, but not on write.
4260*/
4261static
4262void fp_do_oprev_mem_ST_0 ( IRTemp addr, HChar* op_txt, HChar* dis_buf,
4263 IROp op, Bool dbl )
4264{
4265 DIP("f%s%c %s\n", op_txt, dbl?'l':'s', dis_buf);
4266 if (dbl) {
4267 put_ST_UNCHECKED(0,
sewardj4796d662006-02-05 16:06:26 +00004268 triop( op,
4269 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardj7bc00082005-03-27 05:08:32 +00004270 loadLE(Ity_F64,mkexpr(addr)),
4271 get_ST(0)
4272 ));
4273 } else {
4274 put_ST_UNCHECKED(0,
sewardj4796d662006-02-05 16:06:26 +00004275 triop( op,
4276 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardj7bc00082005-03-27 05:08:32 +00004277 unop(Iop_F32toF64, loadLE(Ity_F32,mkexpr(addr))),
4278 get_ST(0)
4279 ));
4280 }
4281}
sewardj37d52572005-02-25 14:22:12 +00004282
4283
4284/* ST(dst) = ST(dst) `op` ST(src).
4285 Check dst and src tags when reading but not on write.
4286*/
4287static
4288void fp_do_op_ST_ST ( HChar* op_txt, IROp op, UInt st_src, UInt st_dst,
4289 Bool pop_after )
4290{
sewardj1027dc22005-02-26 01:55:02 +00004291 DIP("f%s%s st(%u), st(%u)\n", op_txt, pop_after?"p":"", st_src, st_dst );
sewardj37d52572005-02-25 14:22:12 +00004292 put_ST_UNCHECKED(
4293 st_dst,
sewardj4796d662006-02-05 16:06:26 +00004294 triop( op,
4295 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4296 get_ST(st_dst),
4297 get_ST(st_src) )
sewardj37d52572005-02-25 14:22:12 +00004298 );
4299 if (pop_after)
4300 fp_pop();
4301}
4302
sewardj137015d2005-03-27 04:01:15 +00004303/* ST(dst) = ST(src) `op` ST(dst).
4304 Check dst and src tags when reading but not on write.
4305*/
4306static
4307void fp_do_oprev_ST_ST ( HChar* op_txt, IROp op, UInt st_src, UInt st_dst,
4308 Bool pop_after )
4309{
4310 DIP("f%s%s st(%u), st(%u)\n", op_txt, pop_after?"p":"", st_src, st_dst );
4311 put_ST_UNCHECKED(
4312 st_dst,
sewardj4796d662006-02-05 16:06:26 +00004313 triop( op,
4314 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4315 get_ST(st_src),
4316 get_ST(st_dst) )
sewardj137015d2005-03-27 04:01:15 +00004317 );
4318 if (pop_after)
4319 fp_pop();
4320}
sewardjc49ce232005-02-25 13:03:03 +00004321
4322/* %rflags(Z,P,C) = UCOMI( st(0), st(i) ) */
4323static void fp_do_ucomi_ST0_STi ( UInt i, Bool pop_after )
4324{
sewardj1027dc22005-02-26 01:55:02 +00004325 DIP("fucomi%s %%st(0),%%st(%u)\n", pop_after ? "p" : "", i);
sewardjc49ce232005-02-25 13:03:03 +00004326 /* This is a bit of a hack (and isn't really right). It sets
4327 Z,P,C,O correctly, but forces A and S to zero, whereas the Intel
4328 documentation implies A and S are unchanged.
4329 */
4330 /* It's also fishy in that it is used both for COMIP and
4331 UCOMIP, and they aren't the same (although similar). */
4332 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(AMD64G_CC_OP_COPY) ));
4333 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
4334 stmt( IRStmt_Put(
4335 OFFB_CC_DEP1,
4336 binop( Iop_And64,
4337 unop( Iop_32Uto64,
4338 binop(Iop_CmpF64, get_ST(0), get_ST(i))),
4339 mkU64(0x45)
4340 )));
4341 if (pop_after)
4342 fp_pop();
4343}
sewardj8d965312005-02-25 02:48:47 +00004344
4345
4346static
sewardjb4fd2e72005-03-23 13:34:11 +00004347ULong dis_FPU ( /*OUT*/Bool* decode_ok,
sewardj270def42005-07-03 01:03:01 +00004348 Prefix pfx, Long delta )
sewardj8d965312005-02-25 02:48:47 +00004349{
4350 Int len;
4351 UInt r_src, r_dst;
4352 HChar dis_buf[50];
4353 IRTemp t1, t2;
4354
4355 /* On entry, delta points at the second byte of the insn (the modrm
4356 byte).*/
4357 UChar first_opcode = getUChar(delta-1);
4358 UChar modrm = getUChar(delta+0);
4359
sewardj37d52572005-02-25 14:22:12 +00004360 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xD8 opcodes +-+-+-+-+-+-+-+ */
4361
4362 if (first_opcode == 0xD8) {
4363 if (modrm < 0xC0) {
4364
4365 /* bits 5,4,3 are an opcode extension, and the modRM also
4366 specifies an address. */
sewardj7bc00082005-03-27 05:08:32 +00004367 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
4368 delta += len;
sewardj37d52572005-02-25 14:22:12 +00004369
sewardj901ed122005-02-27 13:25:31 +00004370 switch (gregLO3ofRM(modrm)) {
sewardj37d52572005-02-25 14:22:12 +00004371
sewardj48a89d82005-05-06 11:50:13 +00004372 case 0: /* FADD single-real */
4373 fp_do_op_mem_ST_0 ( addr, "add", dis_buf, Iop_AddF64, False );
4374 break;
4375
sewardje6939f02005-05-07 01:01:24 +00004376 case 1: /* FMUL single-real */
4377 fp_do_op_mem_ST_0 ( addr, "mul", dis_buf, Iop_MulF64, False );
4378 break;
4379
sewardjd20c8852005-01-20 20:04:07 +00004380//.. case 2: /* FCOM single-real */
4381//.. DIP("fcoms %s\n", dis_buf);
4382//.. /* This forces C1 to zero, which isn't right. */
4383//.. put_C3210(
4384//.. binop( Iop_And32,
4385//.. binop(Iop_Shl32,
4386//.. binop(Iop_CmpF64,
4387//.. get_ST(0),
4388//.. unop(Iop_F32toF64,
4389//.. loadLE(Ity_F32,mkexpr(addr)))),
4390//.. mkU8(8)),
4391//.. mkU32(0x4500)
4392//.. ));
4393//.. break;
4394//..
4395//.. case 3: /* FCOMP single-real */
4396//.. DIP("fcomps %s\n", dis_buf);
4397//.. /* This forces C1 to zero, which isn't right. */
4398//.. put_C3210(
4399//.. binop( Iop_And32,
4400//.. binop(Iop_Shl32,
4401//.. binop(Iop_CmpF64,
4402//.. get_ST(0),
4403//.. unop(Iop_F32toF64,
4404//.. loadLE(Ity_F32,mkexpr(addr)))),
4405//.. mkU8(8)),
4406//.. mkU32(0x4500)
4407//.. ));
4408//.. fp_pop();
4409//.. break;
sewardje6939f02005-05-07 01:01:24 +00004410
4411 case 4: /* FSUB single-real */
4412 fp_do_op_mem_ST_0 ( addr, "sub", dis_buf, Iop_SubF64, False );
4413 break;
sewardj7bc00082005-03-27 05:08:32 +00004414
4415 case 5: /* FSUBR single-real */
4416 fp_do_oprev_mem_ST_0 ( addr, "subr", dis_buf, Iop_SubF64, False );
4417 break;
4418
sewardje6939f02005-05-07 01:01:24 +00004419 case 6: /* FDIV single-real */
4420 fp_do_op_mem_ST_0 ( addr, "div", dis_buf, Iop_DivF64, False );
4421 break;
4422
4423 case 7: /* FDIVR single-real */
4424 fp_do_oprev_mem_ST_0 ( addr, "divr", dis_buf, Iop_DivF64, False );
4425 break;
sewardj37d52572005-02-25 14:22:12 +00004426
4427 default:
sewardj901ed122005-02-27 13:25:31 +00004428 vex_printf("unhandled opc_aux = 0x%2x\n", gregLO3ofRM(modrm));
sewardj37d52572005-02-25 14:22:12 +00004429 vex_printf("first_opcode == 0xD8\n");
4430 goto decode_fail;
4431 }
4432 } else {
4433 delta++;
4434 switch (modrm) {
4435
4436 case 0xC0 ... 0xC7: /* FADD %st(?),%st(0) */
4437 fp_do_op_ST_ST ( "add", Iop_AddF64, modrm - 0xC0, 0, False );
4438 break;
4439
sewardj137015d2005-03-27 04:01:15 +00004440 case 0xC8 ... 0xCF: /* FMUL %st(?),%st(0) */
4441 fp_do_op_ST_ST ( "mul", Iop_MulF64, modrm - 0xC8, 0, False );
4442 break;
4443
sewardjd20c8852005-01-20 20:04:07 +00004444//.. #if 1
4445//.. /* Dunno if this is right */
4446//.. case 0xD0 ... 0xD7: /* FCOM %st(?),%st(0) */
4447//.. r_dst = (UInt)modrm - 0xD0;
4448//.. DIP("fcom %%st(0),%%st(%d)\n", r_dst);
4449//.. /* This forces C1 to zero, which isn't right. */
4450//.. put_C3210(
4451//.. binop( Iop_And32,
4452//.. binop(Iop_Shl32,
4453//.. binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
4454//.. mkU8(8)),
4455//.. mkU32(0x4500)
4456//.. ));
4457//.. break;
4458//.. #endif
4459//.. #if 1
4460//.. /* Dunno if this is right */
4461//.. case 0xD8 ... 0xDF: /* FCOMP %st(?),%st(0) */
4462//.. r_dst = (UInt)modrm - 0xD8;
4463//.. DIP("fcomp %%st(0),%%st(%d)\n", r_dst);
4464//.. /* This forces C1 to zero, which isn't right. */
4465//.. put_C3210(
4466//.. binop( Iop_And32,
4467//.. binop(Iop_Shl32,
4468//.. binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
4469//.. mkU8(8)),
4470//.. mkU32(0x4500)
4471//.. ));
4472//.. fp_pop();
4473//.. break;
4474//.. #endif
sewardj137015d2005-03-27 04:01:15 +00004475 case 0xE0 ... 0xE7: /* FSUB %st(?),%st(0) */
4476 fp_do_op_ST_ST ( "sub", Iop_SubF64, modrm - 0xE0, 0, False );
4477 break;
4478
sewardje6939f02005-05-07 01:01:24 +00004479 case 0xE8 ... 0xEF: /* FSUBR %st(?),%st(0) */
4480 fp_do_oprev_ST_ST ( "subr", Iop_SubF64, modrm - 0xE8, 0, False );
4481 break;
sewardj137015d2005-03-27 04:01:15 +00004482
4483 case 0xF0 ... 0xF7: /* FDIV %st(?),%st(0) */
4484 fp_do_op_ST_ST ( "div", Iop_DivF64, modrm - 0xF0, 0, False );
4485 break;
4486
sewardj48a89d82005-05-06 11:50:13 +00004487 case 0xF8 ... 0xFF: /* FDIVR %st(?),%st(0) */
4488 fp_do_oprev_ST_ST ( "divr", Iop_DivF64, modrm - 0xF8, 0, False );
4489 break;
sewardj37d52572005-02-25 14:22:12 +00004490
4491 default:
4492 goto decode_fail;
4493 }
4494 }
4495 }
sewardj8d965312005-02-25 02:48:47 +00004496
4497 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xD9 opcodes +-+-+-+-+-+-+-+ */
sewardj37d52572005-02-25 14:22:12 +00004498 else
sewardj8d965312005-02-25 02:48:47 +00004499 if (first_opcode == 0xD9) {
4500 if (modrm < 0xC0) {
4501
4502 /* bits 5,4,3 are an opcode extension, and the modRM also
4503 specifies an address. */
4504 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
4505 delta += len;
4506
sewardj901ed122005-02-27 13:25:31 +00004507 switch (gregLO3ofRM(modrm)) {
sewardj8d965312005-02-25 02:48:47 +00004508
sewardjc49ce232005-02-25 13:03:03 +00004509 case 0: /* FLD single-real */
4510 DIP("flds %s\n", dis_buf);
4511 fp_push();
4512 put_ST(0, unop(Iop_F32toF64,
4513 loadLE(Ity_F32, mkexpr(addr))));
4514 break;
4515
4516 case 2: /* FST single-real */
4517 DIP("fsts %s\n", dis_buf);
4518 storeLE(mkexpr(addr),
4519 binop(Iop_F64toF32, get_roundingmode(), get_ST(0)));
4520 break;
4521
4522 case 3: /* FSTP single-real */
4523 DIP("fstps %s\n", dis_buf);
4524 storeLE(mkexpr(addr),
4525 binop(Iop_F64toF32, get_roundingmode(), get_ST(0)));
4526 fp_pop();
4527 break;
4528
sewardj4017a3b2005-06-13 12:17:27 +00004529 case 4: { /* FLDENV m28 */
4530 /* Uses dirty helper:
4531 VexEmWarn amd64g_do_FLDENV ( VexGuestX86State*, HWord ) */
4532 IRTemp ew = newTemp(Ity_I32);
4533 IRTemp w64 = newTemp(Ity_I64);
4534 IRDirty* d = unsafeIRDirty_0_N (
4535 0/*regparms*/,
4536 "amd64g_dirtyhelper_FLDENV",
4537 &amd64g_dirtyhelper_FLDENV,
4538 mkIRExprVec_1( mkexpr(addr) )
4539 );
4540 d->needsBBP = True;
4541 d->tmp = w64;
4542 /* declare we're reading memory */
4543 d->mFx = Ifx_Read;
4544 d->mAddr = mkexpr(addr);
4545 d->mSize = 28;
4546
4547 /* declare we're writing guest state */
4548 d->nFxState = 4;
4549
4550 d->fxState[0].fx = Ifx_Write;
4551 d->fxState[0].offset = OFFB_FTOP;
4552 d->fxState[0].size = sizeof(UInt);
4553
4554 d->fxState[1].fx = Ifx_Write;
4555 d->fxState[1].offset = OFFB_FPTAGS;
4556 d->fxState[1].size = 8 * sizeof(UChar);
4557
4558 d->fxState[2].fx = Ifx_Write;
4559 d->fxState[2].offset = OFFB_FPROUND;
4560 d->fxState[2].size = sizeof(ULong);
4561
4562 d->fxState[3].fx = Ifx_Write;
4563 d->fxState[3].offset = OFFB_FC3210;
4564 d->fxState[3].size = sizeof(ULong);
4565
4566 stmt( IRStmt_Dirty(d) );
4567
4568 /* ew contains any emulation warning we may need to
4569 issue. If needed, side-exit to the next insn,
4570 reporting the warning, so that Valgrind's dispatcher
4571 sees the warning. */
4572 assign(ew, unop(Iop_64to32,mkexpr(w64)) );
4573 put_emwarn( mkexpr(ew) );
4574 stmt(
4575 IRStmt_Exit(
4576 binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
4577 Ijk_EmWarn,
sewardj9e6491a2005-07-02 19:24:10 +00004578 IRConst_U64( guest_RIP_bbstart+delta )
sewardj4017a3b2005-06-13 12:17:27 +00004579 )
4580 );
4581
4582 DIP("fldenv %s\n", dis_buf);
4583 break;
4584 }
sewardj5e205372005-05-09 02:57:08 +00004585
4586 case 5: {/* FLDCW */
4587 /* The only thing we observe in the control word is the
4588 rounding mode. Therefore, pass the 16-bit value
4589 (x87 native-format control word) to a clean helper,
4590 getting back a 64-bit value, the lower half of which
4591 is the FPROUND value to store, and the upper half of
4592 which is the emulation-warning token which may be
4593 generated.
4594 */
4595 /* ULong amd64h_check_fldcw ( ULong ); */
4596 IRTemp t64 = newTemp(Ity_I64);
4597 IRTemp ew = newTemp(Ity_I32);
4598 DIP("fldcw %s\n", dis_buf);
4599 assign( t64, mkIRExprCCall(
4600 Ity_I64, 0/*regparms*/,
4601 "amd64g_check_fldcw",
4602 &amd64g_check_fldcw,
4603 mkIRExprVec_1(
4604 unop( Iop_16Uto64,
4605 loadLE(Ity_I16, mkexpr(addr)))
4606 )
4607 )
4608 );
4609
4610 put_fpround( unop(Iop_64to32, mkexpr(t64)) );
4611 assign( ew, unop(Iop_64HIto32, mkexpr(t64) ) );
4612 put_emwarn( mkexpr(ew) );
4613 /* Finally, if an emulation warning was reported,
4614 side-exit to the next insn, reporting the warning,
4615 so that Valgrind's dispatcher sees the warning. */
4616 stmt(
4617 IRStmt_Exit(
4618 binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
4619 Ijk_EmWarn,
sewardj9e6491a2005-07-02 19:24:10 +00004620 IRConst_U64( guest_RIP_bbstart+delta )
sewardj5e205372005-05-09 02:57:08 +00004621 )
4622 );
4623 break;
4624 }
4625
sewardj4017a3b2005-06-13 12:17:27 +00004626 case 6: { /* FNSTENV m28 */
4627 /* Uses dirty helper:
4628 void amd64g_do_FSTENV ( VexGuestAMD64State*, HWord ) */
4629 IRDirty* d = unsafeIRDirty_0_N (
4630 0/*regparms*/,
4631 "amd64g_dirtyhelper_FSTENV",
4632 &amd64g_dirtyhelper_FSTENV,
4633 mkIRExprVec_1( mkexpr(addr) )
4634 );
4635 d->needsBBP = True;
4636 /* declare we're writing memory */
4637 d->mFx = Ifx_Write;
4638 d->mAddr = mkexpr(addr);
4639 d->mSize = 28;
4640
4641 /* declare we're reading guest state */
4642 d->nFxState = 4;
4643
4644 d->fxState[0].fx = Ifx_Read;
4645 d->fxState[0].offset = OFFB_FTOP;
4646 d->fxState[0].size = sizeof(UInt);
4647
4648 d->fxState[1].fx = Ifx_Read;
4649 d->fxState[1].offset = OFFB_FPTAGS;
4650 d->fxState[1].size = 8 * sizeof(UChar);
4651
4652 d->fxState[2].fx = Ifx_Read;
4653 d->fxState[2].offset = OFFB_FPROUND;
4654 d->fxState[2].size = sizeof(ULong);
4655
4656 d->fxState[3].fx = Ifx_Read;
4657 d->fxState[3].offset = OFFB_FC3210;
4658 d->fxState[3].size = sizeof(ULong);
4659
4660 stmt( IRStmt_Dirty(d) );
4661
4662 DIP("fnstenv %s\n", dis_buf);
4663 break;
4664 }
sewardj5e205372005-05-09 02:57:08 +00004665
4666 case 7: /* FNSTCW */
4667 /* Fake up a native x87 FPU control word. The only
4668 thing it depends on is FPROUND[1:0], so call a clean
4669 helper to cook it up. */
sewardj4017a3b2005-06-13 12:17:27 +00004670 /* ULong amd64g_create_fpucw ( ULong fpround ) */
sewardj5e205372005-05-09 02:57:08 +00004671 DIP("fnstcw %s\n", dis_buf);
4672 storeLE(
4673 mkexpr(addr),
4674 unop( Iop_64to16,
4675 mkIRExprCCall(
4676 Ity_I64, 0/*regp*/,
4677 "amd64g_create_fpucw", &amd64g_create_fpucw,
4678 mkIRExprVec_1( unop(Iop_32Uto64, get_fpround()) )
4679 )
4680 )
4681 );
4682 break;
sewardj8d965312005-02-25 02:48:47 +00004683
4684 default:
sewardj901ed122005-02-27 13:25:31 +00004685 vex_printf("unhandled opc_aux = 0x%2x\n", gregLO3ofRM(modrm));
sewardj8d965312005-02-25 02:48:47 +00004686 vex_printf("first_opcode == 0xD9\n");
4687 goto decode_fail;
4688 }
4689
4690 } else {
4691 delta++;
4692 switch (modrm) {
4693
sewardjc49ce232005-02-25 13:03:03 +00004694 case 0xC0 ... 0xC7: /* FLD %st(?) */
4695 r_src = (UInt)modrm - 0xC0;
sewardj1027dc22005-02-26 01:55:02 +00004696 DIP("fld %%st(%u)\n", r_src);
sewardjc49ce232005-02-25 13:03:03 +00004697 t1 = newTemp(Ity_F64);
4698 assign(t1, get_ST(r_src));
4699 fp_push();
4700 put_ST(0, mkexpr(t1));
4701 break;
sewardj8d965312005-02-25 02:48:47 +00004702
4703 case 0xC8 ... 0xCF: /* FXCH %st(?) */
4704 r_src = (UInt)modrm - 0xC8;
sewardj1027dc22005-02-26 01:55:02 +00004705 DIP("fxch %%st(%u)\n", r_src);
sewardj8d965312005-02-25 02:48:47 +00004706 t1 = newTemp(Ity_F64);
4707 t2 = newTemp(Ity_F64);
4708 assign(t1, get_ST(0));
4709 assign(t2, get_ST(r_src));
4710 put_ST_UNCHECKED(0, mkexpr(t2));
4711 put_ST_UNCHECKED(r_src, mkexpr(t1));
4712 break;
4713
4714 case 0xE0: /* FCHS */
4715 DIP("fchs\n");
4716 put_ST_UNCHECKED(0, unop(Iop_NegF64, get_ST(0)));
4717 break;
4718
sewardj137015d2005-03-27 04:01:15 +00004719 case 0xE1: /* FABS */
4720 DIP("fabs\n");
4721 put_ST_UNCHECKED(0, unop(Iop_AbsF64, get_ST(0)));
4722 break;
4723
sewardj4f9847d2005-07-25 11:58:34 +00004724 case 0xE5: { /* FXAM */
4725 /* This is an interesting one. It examines %st(0),
4726 regardless of whether the tag says it's empty or not.
4727 Here, just pass both the tag (in our format) and the
4728 value (as a double, actually a ULong) to a helper
4729 function. */
4730 IRExpr** args
4731 = mkIRExprVec_2( unop(Iop_8Uto64, get_ST_TAG(0)),
4732 unop(Iop_ReinterpF64asI64,
4733 get_ST_UNCHECKED(0)) );
4734 put_C3210(mkIRExprCCall(
4735 Ity_I64,
4736 0/*regparm*/,
4737 "amd64g_calculate_FXAM", &amd64g_calculate_FXAM,
4738 args
4739 ));
4740 DIP("fxam\n");
4741 break;
4742 }
sewardjc49ce232005-02-25 13:03:03 +00004743
4744 case 0xE8: /* FLD1 */
4745 DIP("fld1\n");
4746 fp_push();
4747 /* put_ST(0, IRExpr_Const(IRConst_F64(1.0))); */
4748 put_ST(0, IRExpr_Const(IRConst_F64i(0x3ff0000000000000ULL)));
4749 break;
4750
sewardj6847d8c2005-05-12 19:21:55 +00004751 case 0xE9: /* FLDL2T */
4752 DIP("fldl2t\n");
4753 fp_push();
4754 /* put_ST(0, IRExpr_Const(IRConst_F64(3.32192809488736234781))); */
4755 put_ST(0, IRExpr_Const(IRConst_F64i(0x400a934f0979a371ULL)));
4756 break;
4757
4758 case 0xEA: /* FLDL2E */
4759 DIP("fldl2e\n");
4760 fp_push();
4761 /* put_ST(0, IRExpr_Const(IRConst_F64(1.44269504088896340739))); */
4762 put_ST(0, IRExpr_Const(IRConst_F64i(0x3ff71547652b82feULL)));
4763 break;
4764
4765 case 0xEB: /* FLDPI */
4766 DIP("fldpi\n");
4767 fp_push();
4768 /* put_ST(0, IRExpr_Const(IRConst_F64(3.14159265358979323851))); */
4769 put_ST(0, IRExpr_Const(IRConst_F64i(0x400921fb54442d18ULL)));
4770 break;
4771
4772 case 0xEC: /* FLDLG2 */
4773 DIP("fldlg2\n");
4774 fp_push();
4775 /* put_ST(0, IRExpr_Const(IRConst_F64(0.301029995663981143))); */
4776 put_ST(0, IRExpr_Const(IRConst_F64i(0x3fd34413509f79ffULL)));
4777 break;
4778
4779 case 0xED: /* FLDLN2 */
4780 DIP("fldln2\n");
4781 fp_push();
4782 /* put_ST(0, IRExpr_Const(IRConst_F64(0.69314718055994530942))); */
4783 put_ST(0, IRExpr_Const(IRConst_F64i(0x3fe62e42fefa39efULL)));
4784 break;
sewardjc49ce232005-02-25 13:03:03 +00004785
4786 case 0xEE: /* FLDZ */
4787 DIP("fldz\n");
4788 fp_push();
4789 /* put_ST(0, IRExpr_Const(IRConst_F64(0.0))); */
4790 put_ST(0, IRExpr_Const(IRConst_F64i(0x0000000000000000ULL)));
4791 break;
4792
sewardj25a85812005-05-08 23:03:48 +00004793 case 0xF0: /* F2XM1 */
4794 DIP("f2xm1\n");
sewardj4796d662006-02-05 16:06:26 +00004795 put_ST_UNCHECKED(0,
4796 binop(Iop_2xm1F64,
4797 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4798 get_ST(0)));
sewardj25a85812005-05-08 23:03:48 +00004799 break;
4800
4801 case 0xF1: /* FYL2X */
4802 DIP("fyl2x\n");
sewardj4796d662006-02-05 16:06:26 +00004803 put_ST_UNCHECKED(1,
4804 triop(Iop_Yl2xF64,
4805 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4806 get_ST(1),
4807 get_ST(0)));
sewardj25a85812005-05-08 23:03:48 +00004808 fp_pop();
4809 break;
4810
sewardj5e205372005-05-09 02:57:08 +00004811 case 0xF2: /* FPTAN */
4812 DIP("ftan\n");
sewardj4796d662006-02-05 16:06:26 +00004813 put_ST_UNCHECKED(0,
4814 binop(Iop_TanF64,
4815 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4816 get_ST(0)));
sewardj5e205372005-05-09 02:57:08 +00004817 fp_push();
4818 put_ST(0, IRExpr_Const(IRConst_F64(1.0)));
4819 clear_C2(); /* HACK */
4820 break;
sewardj25a85812005-05-08 23:03:48 +00004821
4822 case 0xF3: /* FPATAN */
4823 DIP("fpatan\n");
sewardj4796d662006-02-05 16:06:26 +00004824 put_ST_UNCHECKED(1,
4825 triop(Iop_AtanF64,
4826 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4827 get_ST(1),
4828 get_ST(0)));
sewardj25a85812005-05-08 23:03:48 +00004829 fp_pop();
4830 break;
4831
sewardj879cee02006-03-07 01:15:50 +00004832 case 0xF4: { /* FXTRACT */
4833 IRTemp argF = newTemp(Ity_F64);
4834 IRTemp sigF = newTemp(Ity_F64);
4835 IRTemp expF = newTemp(Ity_F64);
4836 IRTemp argI = newTemp(Ity_I64);
4837 IRTemp sigI = newTemp(Ity_I64);
4838 IRTemp expI = newTemp(Ity_I64);
4839 DIP("fxtract\n");
4840 assign( argF, get_ST(0) );
4841 assign( argI, unop(Iop_ReinterpF64asI64, mkexpr(argF)));
4842 assign( sigI,
4843 mkIRExprCCall(
4844 Ity_I64, 0/*regparms*/,
4845 "x86amd64g_calculate_FXTRACT",
4846 &x86amd64g_calculate_FXTRACT,
4847 mkIRExprVec_2( mkexpr(argI),
4848 mkIRExpr_HWord(0)/*sig*/ ))
4849 );
4850 assign( expI,
4851 mkIRExprCCall(
4852 Ity_I64, 0/*regparms*/,
4853 "x86amd64g_calculate_FXTRACT",
4854 &x86amd64g_calculate_FXTRACT,
4855 mkIRExprVec_2( mkexpr(argI),
4856 mkIRExpr_HWord(1)/*exp*/ ))
4857 );
4858 assign( sigF, unop(Iop_ReinterpI64asF64, mkexpr(sigI)) );
4859 assign( expF, unop(Iop_ReinterpI64asF64, mkexpr(expI)) );
4860 /* exponent */
4861 put_ST_UNCHECKED(0, mkexpr(expF) );
4862 fp_push();
4863 /* significand */
4864 put_ST(0, mkexpr(sigF) );
4865 break;
4866 }
4867
sewardjd20c8852005-01-20 20:04:07 +00004868//.. case 0xF5: { /* FPREM1 -- IEEE compliant */
4869//.. IRTemp a1 = newTemp(Ity_F64);
4870//.. IRTemp a2 = newTemp(Ity_F64);
4871//.. DIP("fprem1\n");
4872//.. /* Do FPREM1 twice, once to get the remainder, and once
4873//.. to get the C3210 flag values. */
4874//.. assign( a1, get_ST(0) );
4875//.. assign( a2, get_ST(1) );
4876//.. put_ST_UNCHECKED(0, binop(Iop_PRem1F64,
4877//.. mkexpr(a1), mkexpr(a2)));
4878//.. put_C3210( binop(Iop_PRem1C3210F64, mkexpr(a1), mkexpr(a2)) );
4879//.. break;
4880//.. }
sewardj6847d8c2005-05-12 19:21:55 +00004881
4882 case 0xF7: /* FINCSTP */
4883 DIP("fincstp\n");
4884 put_ftop( binop(Iop_Add32, get_ftop(), mkU32(1)) );
4885 break;
4886
sewardjd20c8852005-01-20 20:04:07 +00004887//.. case 0xF8: { /* FPREM -- not IEEE compliant */
4888//.. IRTemp a1 = newTemp(Ity_F64);
4889//.. IRTemp a2 = newTemp(Ity_F64);
4890//.. DIP("fprem\n");
4891//.. /* Do FPREM twice, once to get the remainder, and once
4892//.. to get the C3210 flag values. */
4893//.. assign( a1, get_ST(0) );
4894//.. assign( a2, get_ST(1) );
4895//.. put_ST_UNCHECKED(0, binop(Iop_PRemF64,
4896//.. mkexpr(a1), mkexpr(a2)));
4897//.. put_C3210( binop(Iop_PRemC3210F64, mkexpr(a1), mkexpr(a2)) );
4898//.. break;
4899//.. }
4900//..
sewardj5e205372005-05-09 02:57:08 +00004901 case 0xF9: /* FYL2XP1 */
4902 DIP("fyl2xp1\n");
sewardj4796d662006-02-05 16:06:26 +00004903 put_ST_UNCHECKED(1,
4904 triop(Iop_Yl2xp1F64,
4905 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4906 get_ST(1),
4907 get_ST(0)));
sewardj5e205372005-05-09 02:57:08 +00004908 fp_pop();
4909 break;
sewardje6939f02005-05-07 01:01:24 +00004910
4911 case 0xFA: /* FSQRT */
4912 DIP("fsqrt\n");
sewardj4796d662006-02-05 16:06:26 +00004913 put_ST_UNCHECKED(0,
4914 binop(Iop_SqrtF64,
4915 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4916 get_ST(0)));
sewardje6939f02005-05-07 01:01:24 +00004917 break;
4918
sewardj25a85812005-05-08 23:03:48 +00004919 case 0xFB: { /* FSINCOS */
4920 IRTemp a1 = newTemp(Ity_F64);
4921 assign( a1, get_ST(0) );
4922 DIP("fsincos\n");
sewardj4796d662006-02-05 16:06:26 +00004923 put_ST_UNCHECKED(0,
4924 binop(Iop_SinF64,
4925 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4926 mkexpr(a1)));
sewardj25a85812005-05-08 23:03:48 +00004927 fp_push();
sewardj4796d662006-02-05 16:06:26 +00004928 put_ST(0,
4929 binop(Iop_CosF64,
4930 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4931 mkexpr(a1)));
sewardj25a85812005-05-08 23:03:48 +00004932 clear_C2(); /* HACK */
4933 break;
4934 }
4935
4936 case 0xFC: /* FRNDINT */
4937 DIP("frndint\n");
4938 put_ST_UNCHECKED(0,
sewardjb183b852006-02-03 16:08:03 +00004939 binop(Iop_RoundF64toInt, get_roundingmode(), get_ST(0)) );
sewardj25a85812005-05-08 23:03:48 +00004940 break;
4941
4942 case 0xFD: /* FSCALE */
4943 DIP("fscale\n");
sewardj4796d662006-02-05 16:06:26 +00004944 put_ST_UNCHECKED(0,
4945 triop(Iop_ScaleF64,
4946 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4947 get_ST(0),
4948 get_ST(1)));
sewardj25a85812005-05-08 23:03:48 +00004949 break;
4950
4951 case 0xFE: /* FSIN */
4952 DIP("fsin\n");
sewardj4796d662006-02-05 16:06:26 +00004953 put_ST_UNCHECKED(0,
4954 binop(Iop_SinF64,
4955 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4956 get_ST(0)));
sewardj25a85812005-05-08 23:03:48 +00004957 clear_C2(); /* HACK */
4958 break;
4959
4960 case 0xFF: /* FCOS */
4961 DIP("fcos\n");
sewardj4796d662006-02-05 16:06:26 +00004962 put_ST_UNCHECKED(0,
4963 binop(Iop_CosF64,
4964 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4965 get_ST(0)));
sewardj25a85812005-05-08 23:03:48 +00004966 clear_C2(); /* HACK */
4967 break;
sewardj8d965312005-02-25 02:48:47 +00004968
4969 default:
4970 goto decode_fail;
4971 }
4972 }
4973 }
4974
4975 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDA opcodes +-+-+-+-+-+-+-+ */
4976 else
4977 if (first_opcode == 0xDA) {
4978
4979 if (modrm < 0xC0) {
4980
4981 /* bits 5,4,3 are an opcode extension, and the modRM also
4982 specifies an address. */
sewardj6847d8c2005-05-12 19:21:55 +00004983 IROp fop;
4984 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
sewardj8d965312005-02-25 02:48:47 +00004985 delta += len;
sewardj901ed122005-02-27 13:25:31 +00004986 switch (gregLO3ofRM(modrm)) {
sewardj8d965312005-02-25 02:48:47 +00004987
sewardj6847d8c2005-05-12 19:21:55 +00004988 case 0: /* FIADD m32int */ /* ST(0) += m32int */
4989 DIP("fiaddl %s\n", dis_buf);
4990 fop = Iop_AddF64;
4991 goto do_fop_m32;
4992
4993 case 1: /* FIMUL m32int */ /* ST(0) *= m32int */
4994 DIP("fimull %s\n", dis_buf);
4995 fop = Iop_MulF64;
4996 goto do_fop_m32;
4997
4998 case 4: /* FISUB m32int */ /* ST(0) -= m32int */
4999 DIP("fisubl %s\n", dis_buf);
5000 fop = Iop_SubF64;
5001 goto do_fop_m32;
5002
5003 case 5: /* FISUBR m32int */ /* ST(0) = m32int - ST(0) */
5004 DIP("fisubrl %s\n", dis_buf);
5005 fop = Iop_SubF64;
5006 goto do_foprev_m32;
5007
5008 case 6: /* FIDIV m32int */ /* ST(0) /= m32int */
5009 DIP("fisubl %s\n", dis_buf);
5010 fop = Iop_DivF64;
5011 goto do_fop_m32;
5012
5013 case 7: /* FIDIVR m32int */ /* ST(0) = m32int / ST(0) */
5014 DIP("fidivrl %s\n", dis_buf);
5015 fop = Iop_DivF64;
5016 goto do_foprev_m32;
5017
5018 do_fop_m32:
5019 put_ST_UNCHECKED(0,
sewardj4796d662006-02-05 16:06:26 +00005020 triop(fop,
5021 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardj6847d8c2005-05-12 19:21:55 +00005022 get_ST(0),
5023 unop(Iop_I32toF64,
5024 loadLE(Ity_I32, mkexpr(addr)))));
5025 break;
5026
5027 do_foprev_m32:
5028 put_ST_UNCHECKED(0,
sewardj4796d662006-02-05 16:06:26 +00005029 triop(fop,
5030 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardj6847d8c2005-05-12 19:21:55 +00005031 unop(Iop_I32toF64,
5032 loadLE(Ity_I32, mkexpr(addr))),
5033 get_ST(0)));
5034 break;
sewardj8d965312005-02-25 02:48:47 +00005035
5036 default:
sewardj901ed122005-02-27 13:25:31 +00005037 vex_printf("unhandled opc_aux = 0x%2x\n", gregLO3ofRM(modrm));
sewardj8d965312005-02-25 02:48:47 +00005038 vex_printf("first_opcode == 0xDA\n");
5039 goto decode_fail;
5040 }
5041
5042 } else {
5043
5044 delta++;
5045 switch (modrm) {
5046
sewardj48a89d82005-05-06 11:50:13 +00005047 case 0xC0 ... 0xC7: /* FCMOVB ST(i), ST(0) */
5048 r_src = (UInt)modrm - 0xC0;
sewardjca673ab2005-05-11 10:03:08 +00005049 DIP("fcmovb %%st(%u), %%st(0)\n", r_src);
sewardj48a89d82005-05-06 11:50:13 +00005050 put_ST_UNCHECKED(0,
5051 IRExpr_Mux0X(
5052 unop(Iop_1Uto8,
5053 mk_amd64g_calculate_condition(AMD64CondB)),
5054 get_ST(0), get_ST(r_src)) );
5055 break;
sewardj8d965312005-02-25 02:48:47 +00005056
5057 case 0xC8 ... 0xCF: /* FCMOVE(Z) ST(i), ST(0) */
5058 r_src = (UInt)modrm - 0xC8;
sewardj1027dc22005-02-26 01:55:02 +00005059 DIP("fcmovz %%st(%u), %%st(0)\n", r_src);
sewardj8d965312005-02-25 02:48:47 +00005060 put_ST_UNCHECKED(0,
5061 IRExpr_Mux0X(
5062 unop(Iop_1Uto8,
5063 mk_amd64g_calculate_condition(AMD64CondZ)),
5064 get_ST(0), get_ST(r_src)) );
5065 break;
5066
sewardj37d52572005-02-25 14:22:12 +00005067 case 0xD0 ... 0xD7: /* FCMOVBE ST(i), ST(0) */
5068 r_src = (UInt)modrm - 0xD0;
sewardj1027dc22005-02-26 01:55:02 +00005069 DIP("fcmovbe %%st(%u), %%st(0)\n", r_src);
sewardj37d52572005-02-25 14:22:12 +00005070 put_ST_UNCHECKED(0,
5071 IRExpr_Mux0X(
5072 unop(Iop_1Uto8,
5073 mk_amd64g_calculate_condition(AMD64CondBE)),
5074 get_ST(0), get_ST(r_src)) );
5075 break;
5076
sewardj25a85812005-05-08 23:03:48 +00005077 case 0xD8 ... 0xDF: /* FCMOVU ST(i), ST(0) */
5078 r_src = (UInt)modrm - 0xD8;
5079 DIP("fcmovu %%st(%u), %%st(0)\n", r_src);
5080 put_ST_UNCHECKED(0,
5081 IRExpr_Mux0X(
5082 unop(Iop_1Uto8,
5083 mk_amd64g_calculate_condition(AMD64CondP)),
5084 get_ST(0), get_ST(r_src)) );
5085 break;
5086
sewardjd20c8852005-01-20 20:04:07 +00005087//.. case 0xE9: /* FUCOMPP %st(0),%st(1) */
5088//.. DIP("fucompp %%st(0),%%st(1)\n");
5089//.. /* This forces C1 to zero, which isn't right. */
5090//.. put_C3210(
5091//.. binop( Iop_And32,
5092//.. binop(Iop_Shl32,
5093//.. binop(Iop_CmpF64, get_ST(0), get_ST(1)),
5094//.. mkU8(8)),
5095//.. mkU32(0x4500)
5096//.. ));
5097//.. fp_pop();
5098//.. fp_pop();
5099//.. break;
sewardj8d965312005-02-25 02:48:47 +00005100
5101 default:
5102 goto decode_fail;
5103 }
5104
5105 }
5106 }
5107
sewardjc49ce232005-02-25 13:03:03 +00005108 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDB opcodes +-+-+-+-+-+-+-+ */
5109 else
5110 if (first_opcode == 0xDB) {
5111 if (modrm < 0xC0) {
5112
5113 /* bits 5,4,3 are an opcode extension, and the modRM also
5114 specifies an address. */
5115 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
5116 delta += len;
5117
sewardj901ed122005-02-27 13:25:31 +00005118 switch (gregLO3ofRM(modrm)) {
sewardjc49ce232005-02-25 13:03:03 +00005119
sewardj5cc00ff2005-03-27 04:48:32 +00005120 case 0: /* FILD m32int */
5121 DIP("fildl %s\n", dis_buf);
5122 fp_push();
5123 put_ST(0, unop(Iop_I32toF64,
5124 loadLE(Ity_I32, mkexpr(addr))));
5125 break;
5126
sewardj6847d8c2005-05-12 19:21:55 +00005127 case 2: /* FIST m32 */
5128 DIP("fistl %s\n", dis_buf);
5129 storeLE( mkexpr(addr),
5130 binop(Iop_F64toI32, get_roundingmode(), get_ST(0)) );
5131 break;
sewardj37d52572005-02-25 14:22:12 +00005132
5133 case 3: /* FISTP m32 */
5134 DIP("fistpl %s\n", dis_buf);
5135 storeLE( mkexpr(addr),
5136 binop(Iop_F64toI32, get_roundingmode(), get_ST(0)) );
5137 fp_pop();
5138 break;
5139
sewardj924215b2005-03-26 21:50:31 +00005140 case 5: { /* FLD extended-real */
5141 /* Uses dirty helper:
5142 ULong amd64g_loadF80le ( ULong )
5143 addr holds the address. First, do a dirty call to
5144 get hold of the data. */
5145 IRTemp val = newTemp(Ity_I64);
5146 IRExpr** args = mkIRExprVec_1 ( mkexpr(addr) );
5147
5148 IRDirty* d = unsafeIRDirty_1_N (
5149 val,
5150 0/*regparms*/,
sewardj8707fef2005-08-23 23:26:37 +00005151 "amd64g_dirtyhelper_loadF80le",
5152 &amd64g_dirtyhelper_loadF80le,
sewardj924215b2005-03-26 21:50:31 +00005153 args
5154 );
5155 /* declare that we're reading memory */
5156 d->mFx = Ifx_Read;
5157 d->mAddr = mkexpr(addr);
5158 d->mSize = 10;
5159
5160 /* execute the dirty call, dumping the result in val. */
5161 stmt( IRStmt_Dirty(d) );
5162 fp_push();
5163 put_ST(0, unop(Iop_ReinterpI64asF64, mkexpr(val)));
5164
5165 DIP("fldt %s\n", dis_buf);
5166 break;
5167 }
5168
5169 case 7: { /* FSTP extended-real */
5170 /* Uses dirty helper:
5171 void amd64g_storeF80le ( ULong addr, ULong data )
5172 */
5173 IRExpr** args
5174 = mkIRExprVec_2( mkexpr(addr),
5175 unop(Iop_ReinterpF64asI64, get_ST(0)) );
5176
5177 IRDirty* d = unsafeIRDirty_0_N (
5178 0/*regparms*/,
sewardj8707fef2005-08-23 23:26:37 +00005179 "amd64g_dirtyhelper_storeF80le",
5180 &amd64g_dirtyhelper_storeF80le,
sewardj924215b2005-03-26 21:50:31 +00005181 args
5182 );
5183 /* declare we're writing memory */
5184 d->mFx = Ifx_Write;
5185 d->mAddr = mkexpr(addr);
5186 d->mSize = 10;
5187
5188 /* execute the dirty call. */
5189 stmt( IRStmt_Dirty(d) );
5190 fp_pop();
5191
5192 DIP("fstpt\n %s", dis_buf);
5193 break;
5194 }
sewardjc49ce232005-02-25 13:03:03 +00005195
5196 default:
sewardj901ed122005-02-27 13:25:31 +00005197 vex_printf("unhandled opc_aux = 0x%2x\n", gregLO3ofRM(modrm));
sewardjc49ce232005-02-25 13:03:03 +00005198 vex_printf("first_opcode == 0xDB\n");
5199 goto decode_fail;
5200 }
5201
5202 } else {
5203
5204 delta++;
5205 switch (modrm) {
5206
sewardj48a89d82005-05-06 11:50:13 +00005207 case 0xC0 ... 0xC7: /* FCMOVNB ST(i), ST(0) */
5208 r_src = (UInt)modrm - 0xC0;
sewardjca673ab2005-05-11 10:03:08 +00005209 DIP("fcmovnb %%st(%u), %%st(0)\n", r_src);
sewardj48a89d82005-05-06 11:50:13 +00005210 put_ST_UNCHECKED(0,
5211 IRExpr_Mux0X(
5212 unop(Iop_1Uto8,
5213 mk_amd64g_calculate_condition(AMD64CondNB)),
5214 get_ST(0), get_ST(r_src)) );
5215 break;
sewardj924215b2005-03-26 21:50:31 +00005216
5217 case 0xC8 ... 0xCF: /* FCMOVNE(NZ) ST(i), ST(0) */
5218 r_src = (UInt)modrm - 0xC8;
sewardj40e144d2005-03-28 00:46:27 +00005219 DIP("fcmovnz %%st(%u), %%st(0)\n", r_src);
sewardj137015d2005-03-27 04:01:15 +00005220 put_ST_UNCHECKED(
5221 0,
5222 IRExpr_Mux0X(
5223 unop(Iop_1Uto8,
5224 mk_amd64g_calculate_condition(AMD64CondNZ)),
5225 get_ST(0),
5226 get_ST(r_src)
5227 )
5228 );
sewardj924215b2005-03-26 21:50:31 +00005229 break;
5230
sewardj137015d2005-03-27 04:01:15 +00005231 case 0xD0 ... 0xD7: /* FCMOVNBE ST(i), ST(0) */
5232 r_src = (UInt)modrm - 0xD0;
sewardj40e144d2005-03-28 00:46:27 +00005233 DIP("fcmovnbe %%st(%u), %%st(0)\n", r_src);
sewardj137015d2005-03-27 04:01:15 +00005234 put_ST_UNCHECKED(
5235 0,
5236 IRExpr_Mux0X(
5237 unop(Iop_1Uto8,
5238 mk_amd64g_calculate_condition(AMD64CondNBE)),
5239 get_ST(0),
5240 get_ST(r_src)
5241 )
5242 );
5243 break;
5244
sewardj3368e102006-03-06 19:05:07 +00005245 case 0xD8 ... 0xDF: /* FCMOVNU ST(i), ST(0) */
5246 r_src = (UInt)modrm - 0xD8;
5247 DIP("fcmovnu %%st(%u), %%st(0)\n", r_src);
5248 put_ST_UNCHECKED(
5249 0,
5250 IRExpr_Mux0X(
5251 unop(Iop_1Uto8,
5252 mk_amd64g_calculate_condition(AMD64CondNP)),
5253 get_ST(0),
5254 get_ST(r_src)
5255 )
5256 );
5257 break;
5258
sewardj4e1a1e92005-05-25 00:44:13 +00005259 case 0xE2:
5260 DIP("fnclex\n");
5261 break;
5262
sewardj0585a032005-11-05 02:55:06 +00005263 case 0xE3: {
5264 /* Uses dirty helper:
5265 void amd64g_do_FINIT ( VexGuestAMD64State* ) */
5266 IRDirty* d = unsafeIRDirty_0_N (
5267 0/*regparms*/,
5268 "amd64g_dirtyhelper_FINIT",
5269 &amd64g_dirtyhelper_FINIT,
5270 mkIRExprVec_0()
5271 );
5272 d->needsBBP = True;
5273
5274 /* declare we're writing guest state */
5275 d->nFxState = 5;
5276
5277 d->fxState[0].fx = Ifx_Write;
5278 d->fxState[0].offset = OFFB_FTOP;
5279 d->fxState[0].size = sizeof(UInt);
5280
5281 d->fxState[1].fx = Ifx_Write;
5282 d->fxState[1].offset = OFFB_FPREGS;
5283 d->fxState[1].size = 8 * sizeof(ULong);
5284
5285 d->fxState[2].fx = Ifx_Write;
5286 d->fxState[2].offset = OFFB_FPTAGS;
5287 d->fxState[2].size = 8 * sizeof(UChar);
5288
5289 d->fxState[3].fx = Ifx_Write;
5290 d->fxState[3].offset = OFFB_FPROUND;
5291 d->fxState[3].size = sizeof(ULong);
5292
5293 d->fxState[4].fx = Ifx_Write;
5294 d->fxState[4].offset = OFFB_FC3210;
5295 d->fxState[4].size = sizeof(ULong);
5296
5297 stmt( IRStmt_Dirty(d) );
5298
5299 DIP("fninit\n");
5300 break;
5301 }
sewardjc49ce232005-02-25 13:03:03 +00005302
5303 case 0xE8 ... 0xEF: /* FUCOMI %st(0),%st(?) */
5304 fp_do_ucomi_ST0_STi( (UInt)modrm - 0xE8, False );
5305 break;
5306
sewardj48a89d82005-05-06 11:50:13 +00005307 case 0xF0 ... 0xF7: /* FCOMI %st(0),%st(?) */
5308 fp_do_ucomi_ST0_STi( (UInt)modrm - 0xF0, False );
5309 break;
sewardjc49ce232005-02-25 13:03:03 +00005310
5311 default:
5312 goto decode_fail;
5313 }
5314 }
5315 }
5316
sewardj137015d2005-03-27 04:01:15 +00005317 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDC opcodes +-+-+-+-+-+-+-+ */
5318 else
5319 if (first_opcode == 0xDC) {
5320 if (modrm < 0xC0) {
5321
sewardj434e0692005-03-27 17:36:08 +00005322 /* bits 5,4,3 are an opcode extension, and the modRM also
5323 specifies an address. */
5324 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
5325 delta += len;
5326
5327 switch (gregLO3ofRM(modrm)) {
5328
sewardje6939f02005-05-07 01:01:24 +00005329 case 0: /* FADD double-real */
5330 fp_do_op_mem_ST_0 ( addr, "add", dis_buf, Iop_AddF64, True );
5331 break;
5332
5333 case 1: /* FMUL double-real */
5334 fp_do_op_mem_ST_0 ( addr, "mul", dis_buf, Iop_MulF64, True );
5335 break;
5336
sewardjd20c8852005-01-20 20:04:07 +00005337//.. case 2: /* FCOM double-real */
5338//.. DIP("fcoml %s\n", dis_buf);
5339//.. /* This forces C1 to zero, which isn't right. */
5340//.. put_C3210(
5341//.. binop( Iop_And32,
5342//.. binop(Iop_Shl32,
5343//.. binop(Iop_CmpF64,
5344//.. get_ST(0),
5345//.. loadLE(Ity_F64,mkexpr(addr))),
5346//.. mkU8(8)),
5347//.. mkU32(0x4500)
5348//.. ));
5349//.. break;
sewardj566d2c72005-08-10 11:43:42 +00005350
5351 case 3: /* FCOMP double-real */
5352 DIP("fcompl %s\n", dis_buf);
5353 /* This forces C1 to zero, which isn't right. */
5354 put_C3210(
5355 unop(Iop_32Uto64,
5356 binop( Iop_And32,
5357 binop(Iop_Shl32,
5358 binop(Iop_CmpF64,
5359 get_ST(0),
5360 loadLE(Ity_F64,mkexpr(addr))),
5361 mkU8(8)),
5362 mkU32(0x4500)
5363 )));
5364 fp_pop();
5365 break;
sewardje6939f02005-05-07 01:01:24 +00005366
5367 case 4: /* FSUB double-real */
5368 fp_do_op_mem_ST_0 ( addr, "sub", dis_buf, Iop_SubF64, True );
5369 break;
sewardj434e0692005-03-27 17:36:08 +00005370
5371 case 5: /* FSUBR double-real */
5372 fp_do_oprev_mem_ST_0 ( addr, "subr", dis_buf, Iop_SubF64, True );
5373 break;
5374
sewardje6939f02005-05-07 01:01:24 +00005375 case 6: /* FDIV double-real */
5376 fp_do_op_mem_ST_0 ( addr, "div", dis_buf, Iop_DivF64, True );
5377 break;
5378
5379 case 7: /* FDIVR double-real */
5380 fp_do_oprev_mem_ST_0 ( addr, "divr", dis_buf, Iop_DivF64, True );
5381 break;
sewardj434e0692005-03-27 17:36:08 +00005382
5383 default:
5384 vex_printf("unhandled opc_aux = 0x%2x\n", gregLO3ofRM(modrm));
5385 vex_printf("first_opcode == 0xDC\n");
5386 goto decode_fail;
5387 }
sewardj137015d2005-03-27 04:01:15 +00005388
5389 } else {
5390
5391 delta++;
5392 switch (modrm) {
5393
5394 case 0xC0 ... 0xC7: /* FADD %st(0),%st(?) */
5395 fp_do_op_ST_ST ( "add", Iop_AddF64, 0, modrm - 0xC0, False );
5396 break;
5397
sewardj7bc00082005-03-27 05:08:32 +00005398 case 0xC8 ... 0xCF: /* FMUL %st(0),%st(?) */
5399 fp_do_op_ST_ST ( "mul", Iop_MulF64, 0, modrm - 0xC8, False );
5400 break;
5401
sewardj434e0692005-03-27 17:36:08 +00005402 case 0xE0 ... 0xE7: /* FSUBR %st(0),%st(?) */
5403 fp_do_oprev_ST_ST ( "subr", Iop_SubF64, 0, modrm - 0xE0, False );
5404 break;
5405
sewardje6939f02005-05-07 01:01:24 +00005406 case 0xE8 ... 0xEF: /* FSUB %st(0),%st(?) */
5407 fp_do_op_ST_ST ( "sub", Iop_SubF64, 0, modrm - 0xE8, False );
5408 break;
5409
5410 case 0xF0 ... 0xF7: /* FDIVR %st(0),%st(?) */
5411 fp_do_oprev_ST_ST ( "divr", Iop_DivF64, 0, modrm - 0xF0, False );
5412 break;
sewardj137015d2005-03-27 04:01:15 +00005413
5414 case 0xF8 ... 0xFF: /* FDIV %st(0),%st(?) */
5415 fp_do_op_ST_ST ( "div", Iop_DivF64, 0, modrm - 0xF8, False );
5416 break;
5417
5418 default:
5419 goto decode_fail;
5420 }
5421
5422 }
5423 }
sewardj8d965312005-02-25 02:48:47 +00005424
5425 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDD opcodes +-+-+-+-+-+-+-+ */
5426 else
5427 if (first_opcode == 0xDD) {
5428
5429 if (modrm < 0xC0) {
5430
5431 /* bits 5,4,3 are an opcode extension, and the modRM also
5432 specifies an address. */
5433 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
5434 delta += len;
5435
sewardj901ed122005-02-27 13:25:31 +00005436 switch (gregLO3ofRM(modrm)) {
sewardj8d965312005-02-25 02:48:47 +00005437
5438 case 0: /* FLD double-real */
5439 DIP("fldl %s\n", dis_buf);
5440 fp_push();
sewardjaf1ceca2005-06-30 23:31:27 +00005441 put_ST(0, loadLE(Ity_F64, mkexpr(addr)));
sewardj8d965312005-02-25 02:48:47 +00005442 break;
5443
sewardjc49ce232005-02-25 13:03:03 +00005444 case 2: /* FST double-real */
5445 DIP("fstl %s\n", dis_buf);
5446 storeLE(mkexpr(addr), get_ST(0));
5447 break;
sewardj8d965312005-02-25 02:48:47 +00005448
5449 case 3: /* FSTP double-real */
5450 DIP("fstpl %s\n", dis_buf);
5451 storeLE(mkexpr(addr), get_ST(0));
5452 fp_pop();
5453 break;
5454
sewardjd20c8852005-01-20 20:04:07 +00005455//.. case 4: { /* FRSTOR m108 */
5456//.. /* Uses dirty helper:
5457//.. VexEmWarn x86g_do_FRSTOR ( VexGuestX86State*, Addr32 ) */
5458//.. IRTemp ew = newTemp(Ity_I32);
5459//.. IRDirty* d = unsafeIRDirty_0_N (
5460//.. 0/*regparms*/,
5461//.. "x86g_dirtyhelper_FRSTOR",
5462//.. &x86g_dirtyhelper_FRSTOR,
5463//.. mkIRExprVec_1( mkexpr(addr) )
5464//.. );
5465//.. d->needsBBP = True;
5466//.. d->tmp = ew;
5467//.. /* declare we're reading memory */
5468//.. d->mFx = Ifx_Read;
5469//.. d->mAddr = mkexpr(addr);
5470//.. d->mSize = 108;
5471//..
5472//.. /* declare we're writing guest state */
5473//.. d->nFxState = 5;
5474//..
5475//.. d->fxState[0].fx = Ifx_Write;
5476//.. d->fxState[0].offset = OFFB_FTOP;
5477//.. d->fxState[0].size = sizeof(UInt);
5478//..
5479//.. d->fxState[1].fx = Ifx_Write;
5480//.. d->fxState[1].offset = OFFB_FPREGS;
5481//.. d->fxState[1].size = 8 * sizeof(ULong);
5482//..
5483//.. d->fxState[2].fx = Ifx_Write;
5484//.. d->fxState[2].offset = OFFB_FPTAGS;
5485//.. d->fxState[2].size = 8 * sizeof(UChar);
5486//..
5487//.. d->fxState[3].fx = Ifx_Write;
5488//.. d->fxState[3].offset = OFFB_FPROUND;
5489//.. d->fxState[3].size = sizeof(UInt);
5490//..
5491//.. d->fxState[4].fx = Ifx_Write;
5492//.. d->fxState[4].offset = OFFB_FC3210;
5493//.. d->fxState[4].size = sizeof(UInt);
5494//..
5495//.. stmt( IRStmt_Dirty(d) );
5496//..
5497//.. /* ew contains any emulation warning we may need to
5498//.. issue. If needed, side-exit to the next insn,
5499//.. reporting the warning, so that Valgrind's dispatcher
5500//.. sees the warning. */
5501//.. put_emwarn( mkexpr(ew) );
5502//.. stmt(
5503//.. IRStmt_Exit(
5504//.. binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
5505//.. Ijk_EmWarn,
5506//.. IRConst_U32( ((Addr32)guest_eip_bbstart)+delta)
5507//.. )
5508//.. );
5509//..
5510//.. DIP("frstor %s\n", dis_buf);
5511//.. break;
5512//.. }
5513//..
5514//.. case 6: { /* FNSAVE m108 */
5515//.. /* Uses dirty helper:
5516//.. void x86g_do_FSAVE ( VexGuestX86State*, UInt ) */
5517//.. IRDirty* d = unsafeIRDirty_0_N (
5518//.. 0/*regparms*/,
5519//.. "x86g_dirtyhelper_FSAVE",
5520//.. &x86g_dirtyhelper_FSAVE,
5521//.. mkIRExprVec_1( mkexpr(addr) )
5522//.. );
5523//.. d->needsBBP = True;
5524//.. /* declare we're writing memory */
5525//.. d->mFx = Ifx_Write;
5526//.. d->mAddr = mkexpr(addr);
5527//.. d->mSize = 108;
5528//..
5529//.. /* declare we're reading guest state */
5530//.. d->nFxState = 5;
5531//..
5532//.. d->fxState[0].fx = Ifx_Read;
5533//.. d->fxState[0].offset = OFFB_FTOP;
5534//.. d->fxState[0].size = sizeof(UInt);
5535//..
5536//.. d->fxState[1].fx = Ifx_Read;
5537//.. d->fxState[1].offset = OFFB_FPREGS;
5538//.. d->fxState[1].size = 8 * sizeof(ULong);
5539//..
5540//.. d->fxState[2].fx = Ifx_Read;
5541//.. d->fxState[2].offset = OFFB_FPTAGS;
5542//.. d->fxState[2].size = 8 * sizeof(UChar);
5543//..
5544//.. d->fxState[3].fx = Ifx_Read;
5545//.. d->fxState[3].offset = OFFB_FPROUND;
5546//.. d->fxState[3].size = sizeof(UInt);
5547//..
5548//.. d->fxState[4].fx = Ifx_Read;
5549//.. d->fxState[4].offset = OFFB_FC3210;
5550//.. d->fxState[4].size = sizeof(UInt);
5551//..
5552//.. stmt( IRStmt_Dirty(d) );
5553//..
5554//.. DIP("fnsave %s\n", dis_buf);
5555//.. break;
5556//.. }
sewardj8d965312005-02-25 02:48:47 +00005557
sewardj7c2d2822006-03-07 00:22:02 +00005558 case 7: { /* FNSTSW m16 */
5559 IRExpr* sw = get_FPU_sw();
5560 vassert(typeOfIRExpr(irbb->tyenv, sw) == Ity_I16);
5561 storeLE( mkexpr(addr), sw );
5562 DIP("fnstsw %s\n", dis_buf);
5563 break;
5564 }
5565
sewardj8d965312005-02-25 02:48:47 +00005566 default:
sewardj901ed122005-02-27 13:25:31 +00005567 vex_printf("unhandled opc_aux = 0x%2x\n", gregLO3ofRM(modrm));
sewardj8d965312005-02-25 02:48:47 +00005568 vex_printf("first_opcode == 0xDD\n");
5569 goto decode_fail;
5570 }
5571 } else {
5572 delta++;
5573 switch (modrm) {
5574
sewardj6847d8c2005-05-12 19:21:55 +00005575 case 0xC0 ... 0xC7: /* FFREE %st(?) */
5576 r_dst = (UInt)modrm - 0xC0;
5577 DIP("ffree %%st(%u)\n", r_dst);
5578 put_ST_TAG ( r_dst, mkU8(0) );
5579 break;
5580
sewardjbfabcc42005-08-08 09:58:05 +00005581 case 0xD0 ... 0xD7: /* FST %st(0),%st(?) */
5582 r_dst = (UInt)modrm - 0xD0;
sewardjc7cd2142005-09-09 22:31:49 +00005583 DIP("fst %%st(0),%%st(%u)\n", r_dst);
sewardjbfabcc42005-08-08 09:58:05 +00005584 /* P4 manual says: "If the destination operand is a
5585 non-empty register, the invalid-operation exception
5586 is not generated. Hence put_ST_UNCHECKED. */
5587 put_ST_UNCHECKED(r_dst, get_ST(0));
5588 break;
sewardj8d965312005-02-25 02:48:47 +00005589
5590 case 0xD8 ... 0xDF: /* FSTP %st(0),%st(?) */
5591 r_dst = (UInt)modrm - 0xD8;
sewardj1027dc22005-02-26 01:55:02 +00005592 DIP("fstp %%st(0),%%st(%u)\n", r_dst);
sewardj8d965312005-02-25 02:48:47 +00005593 /* P4 manual says: "If the destination operand is a
5594 non-empty register, the invalid-operation exception
5595 is not generated. Hence put_ST_UNCHECKED. */
5596 put_ST_UNCHECKED(r_dst, get_ST(0));
5597 fp_pop();
5598 break;
5599
sewardjfb6c1792005-10-05 17:58:32 +00005600 case 0xE0 ... 0xE7: /* FUCOM %st(0),%st(?) */
5601 r_dst = (UInt)modrm - 0xE0;
sewardj62d05432005-10-29 22:30:47 +00005602 DIP("fucom %%st(0),%%st(%u)\n", r_dst);
sewardjfb6c1792005-10-05 17:58:32 +00005603 /* This forces C1 to zero, which isn't right. */
5604 put_C3210(
5605 unop(Iop_32Uto64,
5606 binop( Iop_And32,
5607 binop(Iop_Shl32,
5608 binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
5609 mkU8(8)),
5610 mkU32(0x4500)
5611 )));
5612 break;
5613
sewardj9fb2f472005-11-05 01:12:18 +00005614 case 0xE8 ... 0xEF: /* FUCOMP %st(0),%st(?) */
5615 r_dst = (UInt)modrm - 0xE8;
sewardj43f45732005-11-05 13:04:34 +00005616 DIP("fucomp %%st(0),%%st(%u)\n", r_dst);
sewardj9fb2f472005-11-05 01:12:18 +00005617 /* This forces C1 to zero, which isn't right. */
5618 put_C3210(
5619 unop(Iop_32Uto64,
5620 binop( Iop_And32,
5621 binop(Iop_Shl32,
5622 binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
5623 mkU8(8)),
5624 mkU32(0x4500)
5625 )));
5626 fp_pop();
5627 break;
sewardj8d965312005-02-25 02:48:47 +00005628
5629 default:
5630 goto decode_fail;
5631 }
5632 }
5633 }
5634
sewardj137015d2005-03-27 04:01:15 +00005635 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDE opcodes +-+-+-+-+-+-+-+ */
5636 else
5637 if (first_opcode == 0xDE) {
5638
5639 if (modrm < 0xC0) {
5640
sewardj6847d8c2005-05-12 19:21:55 +00005641 /* bits 5,4,3 are an opcode extension, and the modRM also
5642 specifies an address. */
5643 IROp fop;
5644 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
5645 delta += len;
5646
5647 switch (gregLO3ofRM(modrm)) {
5648
5649 case 0: /* FIADD m16int */ /* ST(0) += m16int */
5650 DIP("fiaddw %s\n", dis_buf);
5651 fop = Iop_AddF64;
5652 goto do_fop_m16;
5653
5654 case 1: /* FIMUL m16int */ /* ST(0) *= m16int */
5655 DIP("fimulw %s\n", dis_buf);
5656 fop = Iop_MulF64;
5657 goto do_fop_m16;
5658
5659 case 4: /* FISUB m16int */ /* ST(0) -= m16int */
5660 DIP("fisubw %s\n", dis_buf);
5661 fop = Iop_SubF64;
5662 goto do_fop_m16;
5663
5664 case 5: /* FISUBR m16int */ /* ST(0) = m16int - ST(0) */
5665 DIP("fisubrw %s\n", dis_buf);
5666 fop = Iop_SubF64;
5667 goto do_foprev_m16;
5668
5669 case 6: /* FIDIV m16int */ /* ST(0) /= m16int */
5670 DIP("fisubw %s\n", dis_buf);
5671 fop = Iop_DivF64;
5672 goto do_fop_m16;
5673
5674 case 7: /* FIDIVR m16int */ /* ST(0) = m16int / ST(0) */
5675 DIP("fidivrw %s\n", dis_buf);
5676 fop = Iop_DivF64;
5677 goto do_foprev_m16;
5678
5679 do_fop_m16:
5680 put_ST_UNCHECKED(0,
sewardj4796d662006-02-05 16:06:26 +00005681 triop(fop,
5682 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardj6847d8c2005-05-12 19:21:55 +00005683 get_ST(0),
5684 unop(Iop_I32toF64,
5685 unop(Iop_16Sto32,
5686 loadLE(Ity_I16, mkexpr(addr))))));
5687 break;
5688
5689 do_foprev_m16:
5690 put_ST_UNCHECKED(0,
sewardj4796d662006-02-05 16:06:26 +00005691 triop(fop,
5692 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardj6847d8c2005-05-12 19:21:55 +00005693 unop(Iop_I32toF64,
5694 unop(Iop_16Sto32,
5695 loadLE(Ity_I16, mkexpr(addr)))),
5696 get_ST(0)));
5697 break;
5698
5699 default:
5700 vex_printf("unhandled opc_aux = 0x%2x\n", gregLO3ofRM(modrm));
5701 vex_printf("first_opcode == 0xDE\n");
5702 goto decode_fail;
5703 }
sewardj137015d2005-03-27 04:01:15 +00005704
5705 } else {
5706
5707 delta++;
5708 switch (modrm) {
5709
5710 case 0xC0 ... 0xC7: /* FADDP %st(0),%st(?) */
5711 fp_do_op_ST_ST ( "add", Iop_AddF64, 0, modrm - 0xC0, True );
5712 break;
5713
5714 case 0xC8 ... 0xCF: /* FMULP %st(0),%st(?) */
5715 fp_do_op_ST_ST ( "mul", Iop_MulF64, 0, modrm - 0xC8, True );
5716 break;
5717
sewardjd20c8852005-01-20 20:04:07 +00005718//.. case 0xD9: /* FCOMPP %st(0),%st(1) */
5719//.. DIP("fuompp %%st(0),%%st(1)\n");
5720//.. /* This forces C1 to zero, which isn't right. */
5721//.. put_C3210(
5722//.. binop( Iop_And32,
5723//.. binop(Iop_Shl32,
5724//.. binop(Iop_CmpF64, get_ST(0), get_ST(1)),
5725//.. mkU8(8)),
5726//.. mkU32(0x4500)
5727//.. ));
5728//.. fp_pop();
5729//.. fp_pop();
5730//.. break;
sewardj137015d2005-03-27 04:01:15 +00005731
5732 case 0xE0 ... 0xE7: /* FSUBRP %st(0),%st(?) */
5733 fp_do_oprev_ST_ST ( "subr", Iop_SubF64, 0, modrm - 0xE0, True );
5734 break;
5735
5736 case 0xE8 ... 0xEF: /* FSUBP %st(0),%st(?) */
5737 fp_do_op_ST_ST ( "sub", Iop_SubF64, 0, modrm - 0xE8, True );
5738 break;
5739
5740 case 0xF0 ... 0xF7: /* FDIVRP %st(0),%st(?) */
5741 fp_do_oprev_ST_ST ( "divr", Iop_DivF64, 0, modrm - 0xF0, True );
5742 break;
5743
5744 case 0xF8 ... 0xFF: /* FDIVP %st(0),%st(?) */
5745 fp_do_op_ST_ST ( "div", Iop_DivF64, 0, modrm - 0xF8, True );
5746 break;
5747
5748 default:
5749 goto decode_fail;
5750 }
5751
5752 }
5753 }
sewardjc49ce232005-02-25 13:03:03 +00005754
5755 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDF opcodes +-+-+-+-+-+-+-+ */
5756 else
5757 if (first_opcode == 0xDF) {
5758
5759 if (modrm < 0xC0) {
5760
5761 /* bits 5,4,3 are an opcode extension, and the modRM also
5762 specifies an address. */
5763 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
5764 delta += len;
5765
sewardj901ed122005-02-27 13:25:31 +00005766 switch (gregLO3ofRM(modrm)) {
sewardjc49ce232005-02-25 13:03:03 +00005767
sewardj434e0692005-03-27 17:36:08 +00005768 case 0: /* FILD m16int */
5769 DIP("fildw %s\n", dis_buf);
5770 fp_push();
5771 put_ST(0, unop(Iop_I32toF64,
5772 unop(Iop_16Sto32,
5773 loadLE(Ity_I16, mkexpr(addr)))));
5774 break;
5775
sewardjd20c8852005-01-20 20:04:07 +00005776//.. case 2: /* FIST m16 */
5777//.. DIP("fistp %s\n", dis_buf);
5778//.. storeLE( mkexpr(addr),
5779//.. binop(Iop_F64toI16, get_roundingmode(), get_ST(0)) );
5780//.. break;
sewardj6847d8c2005-05-12 19:21:55 +00005781
sewardjd20c8852005-01-20 20:04:07 +00005782//.. case 3: /* FISTP m16 */
5783//.. DIP("fistps %s\n", dis_buf);
5784//.. storeLE( mkexpr(addr),
5785//.. binop(Iop_F64toI16, get_roundingmode(), get_ST(0)) );
5786//.. fp_pop();
5787//.. break;
sewardj37d52572005-02-25 14:22:12 +00005788
5789 case 5: /* FILD m64 */
5790 DIP("fildll %s\n", dis_buf);
5791 fp_push();
5792 put_ST(0, binop(Iop_I64toF64,
5793 get_roundingmode(),
5794 loadLE(Ity_I64, mkexpr(addr))));
5795 break;
5796
sewardj6847d8c2005-05-12 19:21:55 +00005797 case 7: /* FISTP m64 */
5798 DIP("fistpll %s\n", dis_buf);
5799 storeLE( mkexpr(addr),
5800 binop(Iop_F64toI64, get_roundingmode(), get_ST(0)) );
5801 fp_pop();
5802 break;
sewardjc49ce232005-02-25 13:03:03 +00005803
5804 default:
sewardj901ed122005-02-27 13:25:31 +00005805 vex_printf("unhandled opc_aux = 0x%2x\n", gregLO3ofRM(modrm));
sewardjc49ce232005-02-25 13:03:03 +00005806 vex_printf("first_opcode == 0xDF\n");
5807 goto decode_fail;
5808 }
5809
5810 } else {
5811
5812 delta++;
5813 switch (modrm) {
5814
5815 case 0xC0: /* FFREEP %st(0) */
5816 DIP("ffreep %%st(%d)\n", 0);
5817 put_ST_TAG ( 0, mkU8(0) );
5818 fp_pop();
5819 break;
5820
sewardj4f9847d2005-07-25 11:58:34 +00005821 case 0xE0: /* FNSTSW %ax */
5822 DIP("fnstsw %%ax\n");
5823 /* Invent a plausible-looking FPU status word value and
5824 dump it in %AX:
5825 ((ftop & 7) << 11) | (c3210 & 0x4700)
5826 */
5827 putIRegRAX(
5828 2,
5829 unop(Iop_32to16,
5830 binop(Iop_Or32,
5831 binop(Iop_Shl32,
5832 binop(Iop_And32, get_ftop(), mkU32(7)),
5833 mkU8(11)),
5834 binop(Iop_And32,
5835 unop(Iop_64to32, get_C3210()),
5836 mkU32(0x4700))
5837 )));
5838 break;
sewardj924215b2005-03-26 21:50:31 +00005839
5840 case 0xE8 ... 0xEF: /* FUCOMIP %st(0),%st(?) */
5841 fp_do_ucomi_ST0_STi( (UInt)modrm - 0xE8, True );
5842 break;
5843
sewardj48a89d82005-05-06 11:50:13 +00005844 case 0xF0 ... 0xF7: /* FCOMIP %st(0),%st(?) */
5845 /* not really right since COMIP != UCOMIP */
5846 fp_do_ucomi_ST0_STi( (UInt)modrm - 0xF0, True );
5847 break;
sewardjc49ce232005-02-25 13:03:03 +00005848
5849 default:
5850 goto decode_fail;
5851 }
5852 }
5853
5854 }
sewardj8d965312005-02-25 02:48:47 +00005855
5856 else
sewardj137015d2005-03-27 04:01:15 +00005857 goto decode_fail;
sewardj8d965312005-02-25 02:48:47 +00005858
5859 *decode_ok = True;
5860 return delta;
5861
5862 decode_fail:
5863 *decode_ok = False;
5864 return delta;
5865}
5866
5867
sewardj8711f662005-05-09 17:52:56 +00005868/*------------------------------------------------------------*/
5869/*--- ---*/
5870/*--- MMX INSTRUCTIONS ---*/
5871/*--- ---*/
5872/*------------------------------------------------------------*/
5873
5874/* Effect of MMX insns on x87 FPU state (table 11-2 of
5875 IA32 arch manual, volume 3):
5876
5877 Read from, or write to MMX register (viz, any insn except EMMS):
5878 * All tags set to Valid (non-empty) -- FPTAGS[i] := nonzero
5879 * FP stack pointer set to zero
5880
5881 EMMS:
5882 * All tags set to Invalid (empty) -- FPTAGS[i] := zero
5883 * FP stack pointer set to zero
5884*/
5885
5886static void do_MMX_preamble ( void )
5887{
5888 Int i;
5889 IRArray* descr = mkIRArray( OFFB_FPTAGS, Ity_I8, 8 );
5890 IRExpr* zero = mkU32(0);
5891 IRExpr* tag1 = mkU8(1);
5892 put_ftop(zero);
5893 for (i = 0; i < 8; i++)
5894 stmt( IRStmt_PutI( descr, zero, i, tag1 ) );
5895}
5896
5897static void do_EMMS_preamble ( void )
5898{
5899 Int i;
5900 IRArray* descr = mkIRArray( OFFB_FPTAGS, Ity_I8, 8 );
5901 IRExpr* zero = mkU32(0);
5902 IRExpr* tag0 = mkU8(0);
5903 put_ftop(zero);
5904 for (i = 0; i < 8; i++)
5905 stmt( IRStmt_PutI( descr, zero, i, tag0 ) );
5906}
5907
5908
5909static IRExpr* getMMXReg ( UInt archreg )
5910{
5911 vassert(archreg < 8);
5912 return IRExpr_Get( OFFB_FPREGS + 8 * archreg, Ity_I64 );
5913}
5914
5915
5916static void putMMXReg ( UInt archreg, IRExpr* e )
5917{
5918 vassert(archreg < 8);
5919 vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_I64);
5920 stmt( IRStmt_Put( OFFB_FPREGS + 8 * archreg, e ) );
5921}
5922
5923
5924/* Helper for non-shift MMX insns. Note this is incomplete in the
5925 sense that it does not first call do_MMX_preamble() -- that is the
5926 responsibility of its caller. */
5927
5928static
5929ULong dis_MMXop_regmem_to_reg ( Prefix pfx,
sewardj270def42005-07-03 01:03:01 +00005930 Long delta,
sewardj8711f662005-05-09 17:52:56 +00005931 UChar opc,
sewardjca673ab2005-05-11 10:03:08 +00005932 HChar* name,
sewardj8711f662005-05-09 17:52:56 +00005933 Bool show_granularity )
5934{
5935 HChar dis_buf[50];
5936 UChar modrm = getUChar(delta);
5937 Bool isReg = epartIsReg(modrm);
5938 IRExpr* argL = NULL;
5939 IRExpr* argR = NULL;
5940 IRExpr* argG = NULL;
5941 IRExpr* argE = NULL;
5942 IRTemp res = newTemp(Ity_I64);
5943
5944 Bool invG = False;
5945 IROp op = Iop_INVALID;
5946 void* hAddr = NULL;
sewardjca673ab2005-05-11 10:03:08 +00005947 HChar* hName = NULL;
sewardj8711f662005-05-09 17:52:56 +00005948 Bool eLeft = False;
5949
5950# define XXX(_name) do { hAddr = &_name; hName = #_name; } while (0)
5951
5952 switch (opc) {
5953 /* Original MMX ones */
5954 case 0xFC: op = Iop_Add8x8; break;
5955 case 0xFD: op = Iop_Add16x4; break;
5956 case 0xFE: op = Iop_Add32x2; break;
5957
5958 case 0xEC: op = Iop_QAdd8Sx8; break;
5959 case 0xED: op = Iop_QAdd16Sx4; break;
5960
5961 case 0xDC: op = Iop_QAdd8Ux8; break;
5962 case 0xDD: op = Iop_QAdd16Ux4; break;
5963
5964 case 0xF8: op = Iop_Sub8x8; break;
5965 case 0xF9: op = Iop_Sub16x4; break;
5966 case 0xFA: op = Iop_Sub32x2; break;
5967
5968 case 0xE8: op = Iop_QSub8Sx8; break;
5969 case 0xE9: op = Iop_QSub16Sx4; break;
5970
5971 case 0xD8: op = Iop_QSub8Ux8; break;
5972 case 0xD9: op = Iop_QSub16Ux4; break;
5973
5974 case 0xE5: op = Iop_MulHi16Sx4; break;
5975 case 0xD5: op = Iop_Mul16x4; break;
5976 case 0xF5: XXX(amd64g_calculate_mmx_pmaddwd); break;
5977
5978 case 0x74: op = Iop_CmpEQ8x8; break;
5979 case 0x75: op = Iop_CmpEQ16x4; break;
5980 case 0x76: op = Iop_CmpEQ32x2; break;
5981
5982 case 0x64: op = Iop_CmpGT8Sx8; break;
5983 case 0x65: op = Iop_CmpGT16Sx4; break;
5984 case 0x66: op = Iop_CmpGT32Sx2; break;
5985
5986 case 0x6B: op = Iop_QNarrow32Sx2; eLeft = True; break;
5987 case 0x63: op = Iop_QNarrow16Sx4; eLeft = True; break;
5988 case 0x67: op = Iop_QNarrow16Ux4; eLeft = True; break;
5989
5990 case 0x68: op = Iop_InterleaveHI8x8; eLeft = True; break;
5991 case 0x69: op = Iop_InterleaveHI16x4; eLeft = True; break;
5992 case 0x6A: op = Iop_InterleaveHI32x2; eLeft = True; break;
5993
5994 case 0x60: op = Iop_InterleaveLO8x8; eLeft = True; break;
5995 case 0x61: op = Iop_InterleaveLO16x4; eLeft = True; break;
5996 case 0x62: op = Iop_InterleaveLO32x2; eLeft = True; break;
5997
5998 case 0xDB: op = Iop_And64; break;
5999 case 0xDF: op = Iop_And64; invG = True; break;
6000 case 0xEB: op = Iop_Or64; break;
6001 case 0xEF: /* Possibly do better here if argL and argR are the
6002 same reg */
6003 op = Iop_Xor64; break;
6004
6005 /* Introduced in SSE1 */
6006 case 0xE0: op = Iop_Avg8Ux8; break;
6007 case 0xE3: op = Iop_Avg16Ux4; break;
6008 case 0xEE: op = Iop_Max16Sx4; break;
6009 case 0xDE: op = Iop_Max8Ux8; break;
6010 case 0xEA: op = Iop_Min16Sx4; break;
6011 case 0xDA: op = Iop_Min8Ux8; break;
6012 case 0xE4: op = Iop_MulHi16Ux4; break;
sewardja7ba8c42005-05-10 20:08:34 +00006013 case 0xF6: XXX(amd64g_calculate_mmx_psadbw); break;
sewardj8711f662005-05-09 17:52:56 +00006014
6015 /* Introduced in SSE2 */
6016 case 0xD4: op = Iop_Add64; break;
6017 case 0xFB: op = Iop_Sub64; break;
6018
6019 default:
6020 vex_printf("\n0x%x\n", (Int)opc);
6021 vpanic("dis_MMXop_regmem_to_reg");
6022 }
6023
6024# undef XXX
6025
6026 argG = getMMXReg(gregLO3ofRM(modrm));
6027 if (invG)
6028 argG = unop(Iop_Not64, argG);
6029
6030 if (isReg) {
6031 delta++;
6032 argE = getMMXReg(eregLO3ofRM(modrm));
6033 } else {
6034 Int len;
6035 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
6036 delta += len;
6037 argE = loadLE(Ity_I64, mkexpr(addr));
6038 }
6039
6040 if (eLeft) {
6041 argL = argE;
6042 argR = argG;
6043 } else {
6044 argL = argG;
6045 argR = argE;
6046 }
6047
6048 if (op != Iop_INVALID) {
6049 vassert(hName == NULL);
6050 vassert(hAddr == NULL);
6051 assign(res, binop(op, argL, argR));
6052 } else {
6053 vassert(hName != NULL);
6054 vassert(hAddr != NULL);
6055 assign( res,
6056 mkIRExprCCall(
6057 Ity_I64,
6058 0/*regparms*/, hName, hAddr,
6059 mkIRExprVec_2( argL, argR )
6060 )
6061 );
6062 }
6063
6064 putMMXReg( gregLO3ofRM(modrm), mkexpr(res) );
6065
6066 DIP("%s%s %s, %s\n",
6067 name, show_granularity ? nameMMXGran(opc & 3) : "",
6068 ( isReg ? nameMMXReg(eregLO3ofRM(modrm)) : dis_buf ),
6069 nameMMXReg(gregLO3ofRM(modrm)) );
6070
6071 return delta;
6072}
6073
6074
6075/* Vector by scalar shift of G by the amount specified at the bottom
6076 of E. This is a straight copy of dis_SSE_shiftG_byE. */
6077
sewardj270def42005-07-03 01:03:01 +00006078static ULong dis_MMX_shiftG_byE ( Prefix pfx, Long delta,
sewardj8711f662005-05-09 17:52:56 +00006079 HChar* opname, IROp op )
6080{
6081 HChar dis_buf[50];
6082 Int alen, size;
6083 IRTemp addr;
6084 Bool shl, shr, sar;
6085 UChar rm = getUChar(delta);
6086 IRTemp g0 = newTemp(Ity_I64);
6087 IRTemp g1 = newTemp(Ity_I64);
6088 IRTemp amt = newTemp(Ity_I64);
6089 IRTemp amt8 = newTemp(Ity_I8);
6090
6091 if (epartIsReg(rm)) {
6092 assign( amt, getMMXReg(eregLO3ofRM(rm)) );
6093 DIP("%s %s,%s\n", opname,
6094 nameMMXReg(eregLO3ofRM(rm)),
6095 nameMMXReg(gregLO3ofRM(rm)) );
6096 delta++;
6097 } else {
6098 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
6099 assign( amt, loadLE(Ity_I64, mkexpr(addr)) );
6100 DIP("%s %s,%s\n", opname,
6101 dis_buf,
6102 nameMMXReg(gregLO3ofRM(rm)) );
6103 delta += alen;
6104 }
6105 assign( g0, getMMXReg(gregLO3ofRM(rm)) );
6106 assign( amt8, unop(Iop_64to8, mkexpr(amt)) );
6107
6108 shl = shr = sar = False;
6109 size = 0;
6110 switch (op) {
6111 case Iop_ShlN16x4: shl = True; size = 32; break;
6112 case Iop_ShlN32x2: shl = True; size = 32; break;
6113 case Iop_Shl64: shl = True; size = 64; break;
6114 case Iop_ShrN16x4: shr = True; size = 16; break;
6115 case Iop_ShrN32x2: shr = True; size = 32; break;
6116 case Iop_Shr64: shr = True; size = 64; break;
6117 case Iop_SarN16x4: sar = True; size = 16; break;
6118 case Iop_SarN32x2: sar = True; size = 32; break;
6119 default: vassert(0);
6120 }
6121
6122 if (shl || shr) {
6123 assign(
6124 g1,
6125 IRExpr_Mux0X(
6126 unop(Iop_1Uto8,binop(Iop_CmpLT64U,mkexpr(amt),mkU64(size))),
6127 mkU64(0),
6128 binop(op, mkexpr(g0), mkexpr(amt8))
6129 )
6130 );
6131 } else
6132 if (sar) {
6133 assign(
6134 g1,
6135 IRExpr_Mux0X(
6136 unop(Iop_1Uto8,binop(Iop_CmpLT64U,mkexpr(amt),mkU64(size))),
6137 binop(op, mkexpr(g0), mkU8(size-1)),
6138 binop(op, mkexpr(g0), mkexpr(amt8))
6139 )
6140 );
6141 } else {
6142 vassert(0);
6143 }
6144
6145 putMMXReg( gregLO3ofRM(rm), mkexpr(g1) );
6146 return delta;
6147}
6148
6149
sewardj3d8107c2005-05-09 22:23:38 +00006150/* Vector by scalar shift of E by an immediate byte. This is a
6151 straight copy of dis_SSE_shiftE_imm. */
6152
6153static
sewardj270def42005-07-03 01:03:01 +00006154ULong dis_MMX_shiftE_imm ( Long delta, HChar* opname, IROp op )
sewardj3d8107c2005-05-09 22:23:38 +00006155{
6156 Bool shl, shr, sar;
6157 UChar rm = getUChar(delta);
6158 IRTemp e0 = newTemp(Ity_I64);
6159 IRTemp e1 = newTemp(Ity_I64);
6160 UChar amt, size;
6161 vassert(epartIsReg(rm));
6162 vassert(gregLO3ofRM(rm) == 2
6163 || gregLO3ofRM(rm) == 4 || gregLO3ofRM(rm) == 6);
sewardjca673ab2005-05-11 10:03:08 +00006164 amt = getUChar(delta+1);
sewardj3d8107c2005-05-09 22:23:38 +00006165 delta += 2;
6166 DIP("%s $%d,%s\n", opname,
6167 (Int)amt,
6168 nameMMXReg(eregLO3ofRM(rm)) );
6169
6170 assign( e0, getMMXReg(eregLO3ofRM(rm)) );
6171
6172 shl = shr = sar = False;
6173 size = 0;
6174 switch (op) {
6175 case Iop_ShlN16x4: shl = True; size = 16; break;
6176 case Iop_ShlN32x2: shl = True; size = 32; break;
6177 case Iop_Shl64: shl = True; size = 64; break;
6178 case Iop_SarN16x4: sar = True; size = 16; break;
6179 case Iop_SarN32x2: sar = True; size = 32; break;
6180 case Iop_ShrN16x4: shr = True; size = 16; break;
6181 case Iop_ShrN32x2: shr = True; size = 32; break;
6182 case Iop_Shr64: shr = True; size = 64; break;
6183 default: vassert(0);
6184 }
6185
6186 if (shl || shr) {
6187 assign( e1, amt >= size
6188 ? mkU64(0)
6189 : binop(op, mkexpr(e0), mkU8(amt))
6190 );
6191 } else
6192 if (sar) {
6193 assign( e1, amt >= size
6194 ? binop(op, mkexpr(e0), mkU8(size-1))
6195 : binop(op, mkexpr(e0), mkU8(amt))
6196 );
6197 } else {
6198 vassert(0);
6199 }
6200
6201 putMMXReg( eregLO3ofRM(rm), mkexpr(e1) );
6202 return delta;
6203}
sewardj8711f662005-05-09 17:52:56 +00006204
6205
6206/* Completely handle all MMX instructions except emms. */
6207
6208static
sewardj270def42005-07-03 01:03:01 +00006209ULong dis_MMX ( Bool* decode_ok, Prefix pfx, Int sz, Long delta )
sewardj8711f662005-05-09 17:52:56 +00006210{
6211 Int len;
6212 UChar modrm;
6213 HChar dis_buf[50];
6214 UChar opc = getUChar(delta);
6215 delta++;
6216
6217 /* dis_MMX handles all insns except emms. */
6218 do_MMX_preamble();
6219
6220 switch (opc) {
6221
sewardj3d8107c2005-05-09 22:23:38 +00006222 case 0x6E:
6223 if (sz == 4) {
6224 /* MOVD (src)ireg32-or-mem32 (E), (dst)mmxreg (G)*/
6225 modrm = getUChar(delta);
6226 if (epartIsReg(modrm)) {
6227 delta++;
6228 putMMXReg(
6229 gregLO3ofRM(modrm),
6230 binop( Iop_32HLto64,
6231 mkU32(0),
6232 getIReg32(eregOfRexRM(pfx,modrm)) ) );
6233 DIP("movd %s, %s\n",
6234 nameIReg32(eregOfRexRM(pfx,modrm)),
6235 nameMMXReg(gregLO3ofRM(modrm)));
6236 } else {
6237 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
6238 delta += len;
6239 putMMXReg(
6240 gregLO3ofRM(modrm),
6241 binop( Iop_32HLto64,
6242 mkU32(0),
6243 loadLE(Ity_I32, mkexpr(addr)) ) );
6244 DIP("movd %s, %s\n", dis_buf, nameMMXReg(gregLO3ofRM(modrm)));
6245 }
6246 }
6247 else
6248 if (sz == 8) {
6249 /* MOVD (src)ireg64-or-mem64 (E), (dst)mmxreg (G)*/
6250 modrm = getUChar(delta);
6251 if (epartIsReg(modrm)) {
6252 delta++;
6253 putMMXReg( gregLO3ofRM(modrm),
6254 getIReg64(eregOfRexRM(pfx,modrm)) );
6255 DIP("movd %s, %s\n",
6256 nameIReg64(eregOfRexRM(pfx,modrm)),
6257 nameMMXReg(gregLO3ofRM(modrm)));
6258 } else {
6259 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
6260 delta += len;
6261 putMMXReg( gregLO3ofRM(modrm),
6262 loadLE(Ity_I64, mkexpr(addr)) );
6263 DIP("movd{64} %s, %s\n", dis_buf, nameMMXReg(gregLO3ofRM(modrm)));
6264 }
6265 }
6266 else {
6267 goto mmx_decode_failure;
6268 }
6269 break;
6270
6271 case 0x7E:
6272 if (sz == 4) {
6273 /* MOVD (src)mmxreg (G), (dst)ireg32-or-mem32 (E) */
6274 modrm = getUChar(delta);
6275 if (epartIsReg(modrm)) {
6276 delta++;
6277 putIReg32( eregOfRexRM(pfx,modrm),
6278 unop(Iop_64to32, getMMXReg(gregLO3ofRM(modrm)) ) );
6279 DIP("movd %s, %s\n",
6280 nameMMXReg(gregLO3ofRM(modrm)),
6281 nameIReg32(eregOfRexRM(pfx,modrm)));
6282 } else {
6283 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
6284 delta += len;
6285 storeLE( mkexpr(addr),
6286 unop(Iop_64to32, getMMXReg(gregLO3ofRM(modrm)) ) );
6287 DIP("movd %s, %s\n", nameMMXReg(gregLO3ofRM(modrm)), dis_buf);
6288 }
6289 }
6290 else
6291 if (sz == 8) {
6292 /* MOVD (src)mmxreg (G), (dst)ireg64-or-mem64 (E) */
6293 modrm = getUChar(delta);
6294 if (epartIsReg(modrm)) {
6295 delta++;
6296 putIReg64( eregOfRexRM(pfx,modrm),
6297 getMMXReg(gregLO3ofRM(modrm)) );
6298 DIP("movd %s, %s\n",
6299 nameMMXReg(gregLO3ofRM(modrm)),
6300 nameIReg64(eregOfRexRM(pfx,modrm)));
6301 } else {
6302 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
6303 delta += len;
6304 storeLE( mkexpr(addr),
6305 getMMXReg(gregLO3ofRM(modrm)) );
6306 DIP("movd{64} %s, %s\n", nameMMXReg(gregLO3ofRM(modrm)), dis_buf);
6307 }
6308 } else {
6309 goto mmx_decode_failure;
6310 }
6311 break;
sewardj8711f662005-05-09 17:52:56 +00006312
6313 case 0x6F:
6314 /* MOVQ (src)mmxreg-or-mem, (dst)mmxreg */
6315 if (sz != 4)
6316 goto mmx_decode_failure;
6317 modrm = getUChar(delta);
6318 if (epartIsReg(modrm)) {
6319 delta++;
6320 putMMXReg( gregLO3ofRM(modrm), getMMXReg(eregLO3ofRM(modrm)) );
6321 DIP("movq %s, %s\n",
6322 nameMMXReg(eregLO3ofRM(modrm)),
6323 nameMMXReg(gregLO3ofRM(modrm)));
6324 } else {
6325 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
6326 delta += len;
6327 putMMXReg( gregLO3ofRM(modrm), loadLE(Ity_I64, mkexpr(addr)) );
6328 DIP("movq %s, %s\n",
6329 dis_buf, nameMMXReg(gregLO3ofRM(modrm)));
6330 }
6331 break;
6332
6333 case 0x7F:
6334 /* MOVQ (src)mmxreg, (dst)mmxreg-or-mem */
6335 if (sz != 4)
6336 goto mmx_decode_failure;
6337 modrm = getUChar(delta);
6338 if (epartIsReg(modrm)) {
6339 /* Fall through. The assembler doesn't appear to generate
6340 these. */
6341 goto mmx_decode_failure;
6342 } else {
6343 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
6344 delta += len;
6345 storeLE( mkexpr(addr), getMMXReg(gregLO3ofRM(modrm)) );
6346 DIP("mov(nt)q %s, %s\n",
6347 nameMMXReg(gregLO3ofRM(modrm)), dis_buf);
6348 }
6349 break;
6350
6351 case 0xFC:
6352 case 0xFD:
6353 case 0xFE: /* PADDgg (src)mmxreg-or-mem, (dst)mmxreg */
6354 if (sz != 4)
6355 goto mmx_decode_failure;
6356 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "padd", True );
6357 break;
6358
6359 case 0xEC:
6360 case 0xED: /* PADDSgg (src)mmxreg-or-mem, (dst)mmxreg */
6361 if (sz != 4)
6362 goto mmx_decode_failure;
6363 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "padds", True );
6364 break;
6365
6366 case 0xDC:
6367 case 0xDD: /* PADDUSgg (src)mmxreg-or-mem, (dst)mmxreg */
6368 if (sz != 4)
6369 goto mmx_decode_failure;
6370 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "paddus", True );
6371 break;
6372
6373 case 0xF8:
6374 case 0xF9:
6375 case 0xFA: /* PSUBgg (src)mmxreg-or-mem, (dst)mmxreg */
6376 if (sz != 4)
6377 goto mmx_decode_failure;
6378 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "psub", True );
6379 break;
6380
6381 case 0xE8:
6382 case 0xE9: /* PSUBSgg (src)mmxreg-or-mem, (dst)mmxreg */
6383 if (sz != 4)
6384 goto mmx_decode_failure;
6385 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "psubs", True );
6386 break;
6387
6388 case 0xD8:
6389 case 0xD9: /* PSUBUSgg (src)mmxreg-or-mem, (dst)mmxreg */
6390 if (sz != 4)
6391 goto mmx_decode_failure;
6392 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "psubus", True );
6393 break;
6394
6395 case 0xE5: /* PMULHW (src)mmxreg-or-mem, (dst)mmxreg */
6396 if (sz != 4)
6397 goto mmx_decode_failure;
6398 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "pmulhw", False );
6399 break;
6400
6401 case 0xD5: /* PMULLW (src)mmxreg-or-mem, (dst)mmxreg */
6402 if (sz != 4)
6403 goto mmx_decode_failure;
6404 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "pmullw", False );
6405 break;
6406
6407 case 0xF5: /* PMADDWD (src)mmxreg-or-mem, (dst)mmxreg */
6408 vassert(sz == 4);
6409 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "pmaddwd", False );
6410 break;
6411
6412 case 0x74:
6413 case 0x75:
6414 case 0x76: /* PCMPEQgg (src)mmxreg-or-mem, (dst)mmxreg */
6415 if (sz != 4)
6416 goto mmx_decode_failure;
6417 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "pcmpeq", True );
6418 break;
6419
6420 case 0x64:
6421 case 0x65:
6422 case 0x66: /* PCMPGTgg (src)mmxreg-or-mem, (dst)mmxreg */
6423 if (sz != 4)
6424 goto mmx_decode_failure;
6425 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "pcmpgt", True );
6426 break;
6427
6428 case 0x6B: /* PACKSSDW (src)mmxreg-or-mem, (dst)mmxreg */
6429 if (sz != 4)
6430 goto mmx_decode_failure;
6431 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "packssdw", False );
6432 break;
6433
6434 case 0x63: /* PACKSSWB (src)mmxreg-or-mem, (dst)mmxreg */
6435 if (sz != 4)
6436 goto mmx_decode_failure;
6437 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "packsswb", False );
6438 break;
6439
6440 case 0x67: /* PACKUSWB (src)mmxreg-or-mem, (dst)mmxreg */
6441 if (sz != 4)
6442 goto mmx_decode_failure;
6443 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "packuswb", False );
6444 break;
6445
6446 case 0x68:
6447 case 0x69:
6448 case 0x6A: /* PUNPCKHgg (src)mmxreg-or-mem, (dst)mmxreg */
6449 if (sz != 4)
6450 goto mmx_decode_failure;
6451 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "punpckh", True );
6452 break;
6453
6454 case 0x60:
6455 case 0x61:
6456 case 0x62: /* PUNPCKLgg (src)mmxreg-or-mem, (dst)mmxreg */
6457 if (sz != 4)
6458 goto mmx_decode_failure;
6459 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "punpckl", True );
6460 break;
6461
6462 case 0xDB: /* PAND (src)mmxreg-or-mem, (dst)mmxreg */
6463 if (sz != 4)
6464 goto mmx_decode_failure;
6465 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "pand", False );
6466 break;
6467
6468 case 0xDF: /* PANDN (src)mmxreg-or-mem, (dst)mmxreg */
6469 if (sz != 4)
6470 goto mmx_decode_failure;
6471 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "pandn", False );
6472 break;
6473
6474 case 0xEB: /* POR (src)mmxreg-or-mem, (dst)mmxreg */
6475 if (sz != 4)
6476 goto mmx_decode_failure;
6477 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "por", False );
6478 break;
6479
6480 case 0xEF: /* PXOR (src)mmxreg-or-mem, (dst)mmxreg */
6481 if (sz != 4)
6482 goto mmx_decode_failure;
6483 delta = dis_MMXop_regmem_to_reg ( pfx, delta, opc, "pxor", False );
6484 break;
6485
6486# define SHIFT_BY_REG(_name,_op) \
6487 delta = dis_MMX_shiftG_byE(pfx, delta, _name, _op); \
6488 break;
6489
6490 /* PSLLgg (src)mmxreg-or-mem, (dst)mmxreg */
6491 case 0xF1: SHIFT_BY_REG("psllw", Iop_ShlN16x4);
6492 case 0xF2: SHIFT_BY_REG("pslld", Iop_ShlN32x2);
6493 case 0xF3: SHIFT_BY_REG("psllq", Iop_Shl64);
6494
6495 /* PSRLgg (src)mmxreg-or-mem, (dst)mmxreg */
6496 case 0xD1: SHIFT_BY_REG("psrlw", Iop_ShrN16x4);
6497 case 0xD2: SHIFT_BY_REG("psrld", Iop_ShrN32x2);
6498 case 0xD3: SHIFT_BY_REG("psrlq", Iop_Shr64);
6499
6500 /* PSRAgg (src)mmxreg-or-mem, (dst)mmxreg */
6501 case 0xE1: SHIFT_BY_REG("psraw", Iop_SarN16x4);
6502 case 0xE2: SHIFT_BY_REG("psrad", Iop_SarN32x2);
6503
6504# undef SHIFT_BY_REG
sewardj3d8107c2005-05-09 22:23:38 +00006505
6506 case 0x71:
6507 case 0x72:
6508 case 0x73: {
6509 /* (sz==4): PSLLgg/PSRAgg/PSRLgg mmxreg by imm8 */
sewardjca673ab2005-05-11 10:03:08 +00006510 UChar byte2, subopc;
sewardj3d8107c2005-05-09 22:23:38 +00006511 if (sz != 4)
6512 goto mmx_decode_failure;
sewardjca673ab2005-05-11 10:03:08 +00006513 byte2 = getUChar(delta); /* amode / sub-opcode */
6514 subopc = toUChar( (byte2 >> 3) & 7 );
sewardj3d8107c2005-05-09 22:23:38 +00006515
6516# define SHIFT_BY_IMM(_name,_op) \
6517 do { delta = dis_MMX_shiftE_imm(delta,_name,_op); \
6518 } while (0)
6519
6520 if (subopc == 2 /*SRL*/ && opc == 0x71)
6521 SHIFT_BY_IMM("psrlw", Iop_ShrN16x4);
6522 else if (subopc == 2 /*SRL*/ && opc == 0x72)
6523 SHIFT_BY_IMM("psrld", Iop_ShrN32x2);
6524 else if (subopc == 2 /*SRL*/ && opc == 0x73)
6525 SHIFT_BY_IMM("psrlq", Iop_Shr64);
6526
6527 else if (subopc == 4 /*SAR*/ && opc == 0x71)
6528 SHIFT_BY_IMM("psraw", Iop_SarN16x4);
6529 else if (subopc == 4 /*SAR*/ && opc == 0x72)
6530 SHIFT_BY_IMM("psrad", Iop_SarN32x2);
6531
6532 else if (subopc == 6 /*SHL*/ && opc == 0x71)
6533 SHIFT_BY_IMM("psllw", Iop_ShlN16x4);
6534 else if (subopc == 6 /*SHL*/ && opc == 0x72)
6535 SHIFT_BY_IMM("pslld", Iop_ShlN32x2);
6536 else if (subopc == 6 /*SHL*/ && opc == 0x73)
6537 SHIFT_BY_IMM("psllq", Iop_Shl64);
6538
6539 else goto mmx_decode_failure;
6540
6541# undef SHIFT_BY_IMM
6542 break;
6543 }
sewardj8711f662005-05-09 17:52:56 +00006544
6545 /* --- MMX decode failure --- */
6546 default:
6547 mmx_decode_failure:
6548 *decode_ok = False;
6549 return delta; /* ignored */
6550
6551 }
6552
6553 *decode_ok = True;
6554 return delta;
6555}
6556
6557
sewardj33ef9c22005-11-04 20:05:57 +00006558/*------------------------------------------------------------*/
6559/*--- More misc arithmetic and other obscure insns. ---*/
6560/*------------------------------------------------------------*/
6561
6562/* Generate base << amt with vacated places filled with stuff
6563 from xtra. amt guaranteed in 0 .. 63. */
6564static
6565IRExpr* shiftL64_with_extras ( IRTemp base, IRTemp xtra, IRTemp amt )
6566{
6567 /* if amt == 0
6568 then base
6569 else (base << amt) | (xtra >>u (64-amt))
6570 */
6571 return
6572 IRExpr_Mux0X(
6573 mkexpr(amt),
6574 mkexpr(base),
6575 binop(Iop_Or64,
6576 binop(Iop_Shl64, mkexpr(base), mkexpr(amt)),
6577 binop(Iop_Shr64, mkexpr(xtra),
6578 binop(Iop_Sub8, mkU8(64), mkexpr(amt)))
6579 )
6580 );
6581}
6582
6583/* Generate base >>u amt with vacated places filled with stuff
6584 from xtra. amt guaranteed in 0 .. 63. */
6585static
6586IRExpr* shiftR64_with_extras ( IRTemp xtra, IRTemp base, IRTemp amt )
6587{
6588 /* if amt == 0
6589 then base
6590 else (base >>u amt) | (xtra << (64-amt))
6591 */
6592 return
6593 IRExpr_Mux0X(
6594 mkexpr(amt),
6595 mkexpr(base),
6596 binop(Iop_Or64,
6597 binop(Iop_Shr64, mkexpr(base), mkexpr(amt)),
6598 binop(Iop_Shl64, mkexpr(xtra),
6599 binop(Iop_Sub8, mkU8(64), mkexpr(amt)))
6600 )
6601 );
6602}
6603
6604/* Double length left and right shifts. Apparently only required in
6605 v-size (no b- variant). */
6606static
6607ULong dis_SHLRD_Gv_Ev ( Prefix pfx,
6608 Long delta, UChar modrm,
6609 Int sz,
6610 IRExpr* shift_amt,
6611 Bool amt_is_literal,
sewardjf5268432005-11-05 02:58:55 +00006612 HChar* shift_amt_txt,
sewardj33ef9c22005-11-04 20:05:57 +00006613 Bool left_shift )
6614{
6615 /* shift_amt :: Ity_I8 is the amount to shift. shift_amt_txt is used
6616 for printing it. And eip on entry points at the modrm byte. */
6617 Int len;
6618 HChar dis_buf[50];
6619
6620 IRType ty = szToITy(sz);
6621 IRTemp gsrc = newTemp(ty);
6622 IRTemp esrc = newTemp(ty);
6623 IRTemp addr = IRTemp_INVALID;
6624 IRTemp tmpSH = newTemp(Ity_I8);
6625 IRTemp tmpSS = newTemp(Ity_I8);
6626 IRTemp tmp64 = IRTemp_INVALID;
6627 IRTemp res64 = IRTemp_INVALID;
6628 IRTemp rss64 = IRTemp_INVALID;
6629 IRTemp resTy = IRTemp_INVALID;
6630 IRTemp rssTy = IRTemp_INVALID;
6631 Int mask = sz==8 ? 63 : 31;
6632
6633 vassert(sz == 2 || sz == 4 || sz == 8);
6634
6635 /* The E-part is the destination; this is shifted. The G-part
6636 supplies bits to be shifted into the E-part, but is not
6637 changed.
6638
6639 If shifting left, form a double-length word with E at the top
6640 and G at the bottom, and shift this left. The result is then in
6641 the high part.
6642
6643 If shifting right, form a double-length word with G at the top
6644 and E at the bottom, and shift this right. The result is then
6645 at the bottom. */
6646
6647 /* Fetch the operands. */
6648
6649 assign( gsrc, getIRegG(sz, pfx, modrm) );
6650
6651 if (epartIsReg(modrm)) {
6652 delta++;
6653 assign( esrc, getIRegE(sz, pfx, modrm) );
6654 DIP("sh%cd%c %s, %s, %s\n",
6655 ( left_shift ? 'l' : 'r' ), nameISize(sz),
6656 shift_amt_txt,
6657 nameIRegG(sz, pfx, modrm), nameIRegE(sz, pfx, modrm));
6658 } else {
sewardj75ce3652005-11-04 20:49:36 +00006659 addr = disAMode ( &len, pfx, delta, dis_buf,
6660 /* # bytes following amode */
6661 amt_is_literal ? 1 : 0 );
sewardj33ef9c22005-11-04 20:05:57 +00006662 delta += len;
6663 assign( esrc, loadLE(ty, mkexpr(addr)) );
6664 DIP("sh%cd%c %s, %s, %s\n",
6665 ( left_shift ? 'l' : 'r' ), nameISize(sz),
6666 shift_amt_txt,
6667 nameIRegG(sz, pfx, modrm), dis_buf);
6668 }
6669
6670 /* Calculate the masked shift amount (tmpSH), the masked subshift
6671 amount (tmpSS), the shifted value (res64) and the subshifted
6672 value (rss64). */
6673
6674 assign( tmpSH, binop(Iop_And8, shift_amt, mkU8(mask)) );
6675 assign( tmpSS, binop(Iop_And8,
6676 binop(Iop_Sub8, mkexpr(tmpSH), mkU8(1) ),
6677 mkU8(mask)));
6678
6679 tmp64 = newTemp(Ity_I64);
6680 res64 = newTemp(Ity_I64);
6681 rss64 = newTemp(Ity_I64);
6682
6683 if (sz == 2 || sz == 4) {
6684
6685 /* G is xtra; E is data */
6686 /* what a freaking nightmare: */
6687 if (sz == 4 && left_shift) {
6688 assign( tmp64, binop(Iop_32HLto64, mkexpr(esrc), mkexpr(gsrc)) );
6689 assign( res64,
6690 binop(Iop_Shr64,
6691 binop(Iop_Shl64, mkexpr(tmp64), mkexpr(tmpSH)),
6692 mkU8(32)) );
6693 assign( rss64,
6694 binop(Iop_Shr64,
6695 binop(Iop_Shl64, mkexpr(tmp64), mkexpr(tmpSS)),
6696 mkU8(32)) );
6697 }
6698 else
6699 if (sz == 4 && !left_shift) {
6700 assign( tmp64, binop(Iop_32HLto64, mkexpr(gsrc), mkexpr(esrc)) );
6701 assign( res64, binop(Iop_Shr64, mkexpr(tmp64), mkexpr(tmpSH)) );
6702 assign( rss64, binop(Iop_Shr64, mkexpr(tmp64), mkexpr(tmpSS)) );
6703 }
6704 else
6705 if (sz == 2 && left_shift) {
6706 assign( tmp64,
6707 binop(Iop_32HLto64,
6708 binop(Iop_16HLto32, mkexpr(esrc), mkexpr(gsrc)),
6709 binop(Iop_16HLto32, mkexpr(gsrc), mkexpr(gsrc))
6710 ));
6711 /* result formed by shifting [esrc'gsrc'gsrc'gsrc] */
6712 assign( res64,
6713 binop(Iop_Shr64,
6714 binop(Iop_Shl64, mkexpr(tmp64), mkexpr(tmpSH)),
6715 mkU8(48)) );
6716 /* subshift formed by shifting [esrc'0000'0000'0000] */
6717 assign( rss64,
6718 binop(Iop_Shr64,
6719 binop(Iop_Shl64,
6720 binop(Iop_Shl64, unop(Iop_16Uto64, mkexpr(esrc)),
6721 mkU8(48)),
6722 mkexpr(tmpSS)),
6723 mkU8(48)) );
6724 }
6725 else
6726 if (sz == 2 && !left_shift) {
6727 assign( tmp64,
6728 binop(Iop_32HLto64,
6729 binop(Iop_16HLto32, mkexpr(gsrc), mkexpr(gsrc)),
6730 binop(Iop_16HLto32, mkexpr(gsrc), mkexpr(esrc))
6731 ));
6732 /* result formed by shifting [gsrc'gsrc'gsrc'esrc] */
6733 assign( res64, binop(Iop_Shr64, mkexpr(tmp64), mkexpr(tmpSH)) );
6734 /* subshift formed by shifting [0000'0000'0000'esrc] */
6735 assign( rss64, binop(Iop_Shr64,
6736 unop(Iop_16Uto64, mkexpr(esrc)),
6737 mkexpr(tmpSS)) );
6738 }
6739
6740 } else {
6741
6742 vassert(sz == 8);
6743 if (left_shift) {
6744 assign( res64, shiftL64_with_extras( esrc, gsrc, tmpSH ));
6745 assign( rss64, shiftL64_with_extras( esrc, gsrc, tmpSS ));
6746 } else {
6747 assign( res64, shiftR64_with_extras( gsrc, esrc, tmpSH ));
6748 assign( rss64, shiftR64_with_extras( gsrc, esrc, tmpSS ));
6749 }
6750
6751 }
6752
6753 resTy = newTemp(ty);
6754 rssTy = newTemp(ty);
6755 assign( resTy, narrowTo(ty, mkexpr(res64)) );
6756 assign( rssTy, narrowTo(ty, mkexpr(rss64)) );
6757
6758 /* Put result back and write the flags thunk. */
6759 setFlags_DEP1_DEP2_shift ( left_shift ? Iop_Shl64 : Iop_Sar64,
6760 resTy, rssTy, ty, tmpSH );
6761
6762 if (epartIsReg(modrm)) {
6763 putIRegE(sz, pfx, modrm, mkexpr(resTy));
6764 } else {
6765 storeLE( mkexpr(addr), mkexpr(resTy) );
6766 }
6767
6768 if (amt_is_literal) delta++;
6769 return delta;
6770}
sewardj9ed16802005-08-24 10:46:19 +00006771
6772
6773/* Handle BT/BTS/BTR/BTC Gv, Ev. Apparently b-size is not
6774 required. */
6775
6776typedef enum { BtOpNone, BtOpSet, BtOpReset, BtOpComp } BtOp;
6777
6778static HChar* nameBtOp ( BtOp op )
6779{
6780 switch (op) {
6781 case BtOpNone: return "";
6782 case BtOpSet: return "s";
6783 case BtOpReset: return "r";
6784 case BtOpComp: return "c";
6785 default: vpanic("nameBtOp(amd64)");
6786 }
6787}
6788
6789
6790static
6791ULong dis_bt_G_E ( Prefix pfx, Int sz, Long delta, BtOp op )
6792{
6793 HChar dis_buf[50];
6794 UChar modrm;
6795 Int len;
6796 IRTemp t_fetched, t_bitno0, t_bitno1, t_bitno2, t_addr0,
6797 t_addr1, t_rsp, t_mask;
6798
6799 vassert(sz == 2 || sz == 4 || sz == 8);
6800
6801 t_fetched = t_bitno0 = t_bitno1 = t_bitno2
6802 = t_addr0 = t_addr1 = t_rsp = t_mask = IRTemp_INVALID;
6803
6804 t_fetched = newTemp(Ity_I8);
6805 t_bitno0 = newTemp(Ity_I64);
6806 t_bitno1 = newTemp(Ity_I64);
6807 t_bitno2 = newTemp(Ity_I8);
6808 t_addr1 = newTemp(Ity_I64);
6809 modrm = getUChar(delta);
6810
6811 assign( t_bitno0, widenSto64(getIRegG(sz, pfx, modrm)) );
6812
6813 if (epartIsReg(modrm)) {
6814 delta++;
6815 /* Get it onto the client's stack. */
6816 t_rsp = newTemp(Ity_I64);
6817 t_addr0 = newTemp(Ity_I64);
6818
6819 assign( t_rsp, binop(Iop_Sub64, getIReg64(R_RSP), mkU64(sz)) );
6820 putIReg64(R_RSP, mkexpr(t_rsp));
6821
6822 storeLE( mkexpr(t_rsp), getIRegE(sz, pfx, modrm) );
6823
6824 /* Make t_addr0 point at it. */
6825 assign( t_addr0, mkexpr(t_rsp) );
6826
6827 /* Mask out upper bits of the shift amount, since we're doing a
6828 reg. */
6829 assign( t_bitno1, binop(Iop_And64,
6830 mkexpr(t_bitno0),
6831 mkU64(sz == 8 ? 63 : sz == 4 ? 31 : 15)) );
6832
6833 } else {
6834 t_addr0 = disAMode ( &len, pfx, delta, dis_buf, 0 );
6835 delta += len;
6836 assign( t_bitno1, mkexpr(t_bitno0) );
6837 }
6838
6839 /* At this point: t_addr0 is the address being operated on. If it
6840 was a reg, we will have pushed it onto the client's stack.
6841 t_bitno1 is the bit number, suitably masked in the case of a
6842 reg. */
6843
6844 /* Now the main sequence. */
6845 assign( t_addr1,
6846 binop(Iop_Add64,
6847 mkexpr(t_addr0),
6848 binop(Iop_Sar64, mkexpr(t_bitno1), mkU8(3))) );
6849
6850 /* t_addr1 now holds effective address */
6851
6852 assign( t_bitno2,
6853 unop(Iop_64to8,
6854 binop(Iop_And64, mkexpr(t_bitno1), mkU64(7))) );
6855
6856 /* t_bitno2 contains offset of bit within byte */
6857
6858 if (op != BtOpNone) {
6859 t_mask = newTemp(Ity_I8);
6860 assign( t_mask, binop(Iop_Shl8, mkU8(1), mkexpr(t_bitno2)) );
6861 }
6862
6863 /* t_mask is now a suitable byte mask */
6864
6865 assign( t_fetched, loadLE(Ity_I8, mkexpr(t_addr1)) );
6866
6867 if (op != BtOpNone) {
6868 switch (op) {
6869 case BtOpSet:
6870 storeLE( mkexpr(t_addr1),
6871 binop(Iop_Or8, mkexpr(t_fetched),
6872 mkexpr(t_mask)) );
6873 break;
6874 case BtOpComp:
6875 storeLE( mkexpr(t_addr1),
6876 binop(Iop_Xor8, mkexpr(t_fetched),
6877 mkexpr(t_mask)) );
6878 break;
6879 case BtOpReset:
6880 storeLE( mkexpr(t_addr1),
6881 binop(Iop_And8, mkexpr(t_fetched),
6882 unop(Iop_Not8, mkexpr(t_mask))) );
6883 break;
6884 default:
6885 vpanic("dis_bt_G_E(amd64)");
6886 }
6887 }
6888
6889 /* Side effect done; now get selected bit into Carry flag */
6890 /* Flags: C=selected bit, O,S,Z,A,P undefined, so are set to zero. */
6891 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(AMD64G_CC_OP_COPY) ));
6892 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
6893 stmt( IRStmt_Put(
6894 OFFB_CC_DEP1,
6895 binop(Iop_And64,
6896 binop(Iop_Shr64,
6897 unop(Iop_8Uto64, mkexpr(t_fetched)),
6898 mkexpr(t_bitno2)),
6899 mkU64(1)))
6900 );
6901 /* Set NDEP even though it isn't used. This makes redundant-PUT
6902 elimination of previous stores to this field work better. */
6903 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU64(0) ));
6904
6905 /* Move reg operand from stack back to reg */
6906 if (epartIsReg(modrm)) {
6907 /* t_esp still points at it. */
sewardj25d23862006-05-12 17:47:21 +00006908 /* only write the reg if actually modifying it; doing otherwise
6909 zeroes the top half erroneously when doing btl due to
6910 standard zero-extend rule */
6911 if (op != BtOpNone)
6912 putIRegE(sz, pfx, modrm, loadLE(szToITy(sz), mkexpr(t_rsp)) );
sewardj9ed16802005-08-24 10:46:19 +00006913 putIReg64(R_RSP, binop(Iop_Add64, mkexpr(t_rsp), mkU64(sz)) );
6914 }
6915
6916 DIP("bt%s%c %s, %s\n",
6917 nameBtOp(op), nameISize(sz), nameIRegG(sz, pfx, modrm),
6918 ( epartIsReg(modrm) ? nameIRegE(sz, pfx, modrm) : dis_buf ) );
6919
6920 return delta;
6921}
sewardjf53b7352005-04-06 20:01:56 +00006922
6923
6924
6925/* Handle BSF/BSR. Only v-size seems necessary. */
6926static
sewardj270def42005-07-03 01:03:01 +00006927ULong dis_bs_E_G ( Prefix pfx, Int sz, Long delta, Bool fwds )
sewardjf53b7352005-04-06 20:01:56 +00006928{
6929 Bool isReg;
6930 UChar modrm;
6931 HChar dis_buf[50];
6932
6933 IRType ty = szToITy(sz);
6934 IRTemp src = newTemp(ty);
6935 IRTemp dst = newTemp(ty);
6936 IRTemp src64 = newTemp(Ity_I64);
6937 IRTemp dst64 = newTemp(Ity_I64);
6938 IRTemp src8 = newTemp(Ity_I8);
6939
6940 vassert(sz == 8 || sz == 4 || sz == 2);
6941
6942 modrm = getUChar(delta);
6943 isReg = epartIsReg(modrm);
6944 if (isReg) {
6945 delta++;
6946 assign( src, getIRegE(sz, pfx, modrm) );
6947 } else {
6948 Int len;
6949 IRTemp addr = disAMode( &len, pfx, delta, dis_buf, 0 );
6950 delta += len;
6951 assign( src, loadLE(ty, mkexpr(addr)) );
6952 }
6953
6954 DIP("bs%c%c %s, %s\n",
6955 fwds ? 'f' : 'r', nameISize(sz),
6956 ( isReg ? nameIRegE(sz, pfx, modrm) : dis_buf ),
6957 nameIRegG(sz, pfx, modrm));
6958
6959 /* First, widen src to 64 bits if it is not already. */
6960 assign( src64, widenUto64(mkexpr(src)) );
6961
6962 /* Generate an 8-bit expression which is zero iff the
6963 original is zero, and nonzero otherwise */
6964 assign( src8,
6965 unop(Iop_1Uto8,
6966 binop(Iop_CmpNE64,
6967 mkexpr(src64), mkU64(0))) );
6968
6969 /* Flags: Z is 1 iff source value is zero. All others
6970 are undefined -- we force them to zero. */
6971 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(AMD64G_CC_OP_COPY) ));
6972 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
6973 stmt( IRStmt_Put(
6974 OFFB_CC_DEP1,
6975 IRExpr_Mux0X( mkexpr(src8),
6976 /* src==0 */
6977 mkU64(AMD64G_CC_MASK_Z),
6978 /* src!=0 */
6979 mkU64(0)
6980 )
6981 ));
6982 /* Set NDEP even though it isn't used. This makes redundant-PUT
6983 elimination of previous stores to this field work better. */
6984 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU64(0) ));
6985
6986 /* Result: iff source value is zero, we can't use
6987 Iop_Clz64/Iop_Ctz64 as they have no defined result in that case.
6988 But anyway, amd64 semantics say the result is undefined in
6989 such situations. Hence handle the zero case specially. */
6990
6991 /* Bleh. What we compute:
6992
6993 bsf64: if src == 0 then {dst is unchanged}
6994 else Ctz64(src)
6995
6996 bsr64: if src == 0 then {dst is unchanged}
6997 else 63 - Clz64(src)
6998
6999 bsf32: if src == 0 then {dst is unchanged}
7000 else Ctz64(32Uto64(src))
7001
7002 bsr32: if src == 0 then {dst is unchanged}
7003 else 63 - Clz64(32Uto64(src))
7004
7005 bsf16: if src == 0 then {dst is unchanged}
7006 else Ctz64(32Uto64(16Uto32(src)))
7007
7008 bsr16: if src == 0 then {dst is unchanged}
7009 else 63 - Clz64(32Uto64(16Uto32(src)))
7010 */
7011
7012 /* The main computation, guarding against zero. */
7013 assign( dst64,
7014 IRExpr_Mux0X(
7015 mkexpr(src8),
7016 /* src == 0 -- leave dst unchanged */
7017 widenUto64( getIRegG( sz, pfx, modrm ) ),
7018 /* src != 0 */
7019 fwds ? unop(Iop_Ctz64, mkexpr(src64))
7020 : binop(Iop_Sub64,
7021 mkU64(63),
7022 unop(Iop_Clz64, mkexpr(src64)))
7023 )
7024 );
7025
7026 if (sz == 2)
sewardje58967e2005-04-27 11:50:56 +00007027 assign( dst, unop(Iop_64to16, mkexpr(dst64)) );
sewardjf53b7352005-04-06 20:01:56 +00007028 else
7029 if (sz == 4)
7030 assign( dst, unop(Iop_64to32, mkexpr(dst64)) );
7031 else
7032 assign( dst, mkexpr(dst64) );
7033
7034 /* dump result back */
7035 putIRegG( sz, pfx, modrm, mkexpr(dst) );
7036
7037 return delta;
7038}
sewardja6b93d12005-02-17 09:28:28 +00007039
7040
7041/* swap rAX with the reg specified by reg and REX.B */
7042static
sewardj5b470602005-02-27 13:10:48 +00007043void codegen_xchg_rAX_Reg ( Prefix pfx, Int sz, UInt regLo3 )
sewardja6b93d12005-02-17 09:28:28 +00007044{
7045 IRType ty = szToITy(sz);
7046 IRTemp t1 = newTemp(ty);
7047 IRTemp t2 = newTemp(ty);
sewardj2d4fcd52005-05-18 11:47:47 +00007048 vassert(sz == 4 || sz == 8);
sewardj5b470602005-02-27 13:10:48 +00007049 vassert(regLo3 < 8);
sewardj2d4fcd52005-05-18 11:47:47 +00007050 if (sz == 8) {
7051 assign( t1, getIReg64(R_RAX) );
7052 assign( t2, getIRegRexB(8, pfx, regLo3) );
7053 putIReg64( R_RAX, mkexpr(t2) );
7054 putIRegRexB(8, pfx, regLo3, mkexpr(t1) );
7055 } else {
7056 assign( t1, getIReg32(R_RAX) );
7057 assign( t2, getIRegRexB(4, pfx, regLo3) );
7058 putIReg32( R_RAX, mkexpr(t2) );
7059 putIRegRexB(4, pfx, regLo3, mkexpr(t1) );
7060 }
sewardja6b93d12005-02-17 09:28:28 +00007061 DIP("xchg%c %s, %s\n",
sewardj5b470602005-02-27 13:10:48 +00007062 nameISize(sz), nameIRegRAX(sz),
sewardj2d4fcd52005-05-18 11:47:47 +00007063 nameIRegRexB(sz,pfx, regLo3));
sewardja6b93d12005-02-17 09:28:28 +00007064}
7065
7066
sewardjd20c8852005-01-20 20:04:07 +00007067//.. static
7068//.. void codegen_SAHF ( void )
7069//.. {
7070//.. /* Set the flags to:
7071//.. (x86g_calculate_flags_all() & X86G_CC_MASK_O) -- retain the old O flag
7072//.. | (%AH & (X86G_CC_MASK_S|X86G_CC_MASK_Z|X86G_CC_MASK_A
7073//.. |X86G_CC_MASK_P|X86G_CC_MASK_C)
7074//.. */
7075//.. UInt mask_SZACP = X86G_CC_MASK_S|X86G_CC_MASK_Z|X86G_CC_MASK_A
7076//.. |X86G_CC_MASK_C|X86G_CC_MASK_P;
7077//.. IRTemp oldflags = newTemp(Ity_I32);
7078//.. assign( oldflags, mk_x86g_calculate_eflags_all() );
7079//.. stmt( IRStmt_Put( OFFB_CC_OP, mkU32(X86G_CC_OP_COPY) ));
7080//.. stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
7081//.. stmt( IRStmt_Put( OFFB_CC_DEP1,
7082//.. binop(Iop_Or32,
7083//.. binop(Iop_And32, mkexpr(oldflags), mkU32(X86G_CC_MASK_O)),
7084//.. binop(Iop_And32,
7085//.. binop(Iop_Shr32, getIReg(4, R_EAX), mkU8(8)),
7086//.. mkU32(mask_SZACP))
7087//.. )
7088//.. ));
7089//.. }
7090//..
7091//..
7092//.. //-- static
7093//.. //-- void codegen_LAHF ( UCodeBlock* cb )
7094//.. //-- {
7095//.. //-- Int t = newTemp(cb);
7096//.. //--
7097//.. //-- /* Pushed arg is ignored, it just provides somewhere to put the
7098//.. //-- return value. */
7099//.. //-- uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, t);
7100//.. //-- uInstr0(cb, CALLM_S, 0);
7101//.. //-- uInstr1(cb, PUSH, 4, TempReg, t);
7102//.. //-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_LAHF));
7103//.. //-- uFlagsRWU(cb, FlagsSZACP, FlagsEmpty, FlagsEmpty);
7104//.. //-- uInstr1(cb, POP, 4, TempReg, t);
7105//.. //-- uInstr0(cb, CALLM_E, 0);
7106//.. //--
7107//.. //-- /* At this point, the %ah sub-register in %eax has been updated,
7108//.. //-- the rest is the same, so do a PUT of the whole thing. */
7109//.. //-- uInstr2(cb, PUT, 4, TempReg, t, ArchReg, R_EAX);
7110//.. //-- }
7111//.. //--
sewardja6b93d12005-02-17 09:28:28 +00007112
7113static
7114ULong dis_cmpxchg_G_E ( Prefix pfx,
7115 Int size,
sewardj270def42005-07-03 01:03:01 +00007116 Long delta0 )
sewardja6b93d12005-02-17 09:28:28 +00007117{
7118 HChar dis_buf[50];
7119 Int len;
7120
7121 IRType ty = szToITy(size);
7122 IRTemp acc = newTemp(ty);
7123 IRTemp src = newTemp(ty);
7124 IRTemp dest = newTemp(ty);
7125 IRTemp dest2 = newTemp(ty);
7126 IRTemp acc2 = newTemp(ty);
7127 IRTemp cond8 = newTemp(Ity_I8);
7128 IRTemp addr = IRTemp_INVALID;
7129 UChar rm = getUChar(delta0);
7130
7131 if (epartIsReg(rm)) {
sewardj5b470602005-02-27 13:10:48 +00007132 vassert(0); /* awaiting test case */
7133 assign( dest, getIRegE(size, pfx, rm) );
sewardja6b93d12005-02-17 09:28:28 +00007134 delta0++;
7135 DIP("cmpxchg%c %s,%s\n", nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00007136 nameIRegG(size,pfx,rm),
7137 nameIRegE(size,pfx,rm) );
sewardja6b93d12005-02-17 09:28:28 +00007138 } else {
7139 addr = disAMode ( &len, pfx, delta0, dis_buf, 0 );
7140 assign( dest, loadLE(ty, mkexpr(addr)) );
7141 delta0 += len;
7142 DIP("cmpxchg%c %s,%s\n", nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00007143 nameIRegG(size,pfx,rm), dis_buf);
sewardja6b93d12005-02-17 09:28:28 +00007144 }
7145
sewardj5b470602005-02-27 13:10:48 +00007146 assign( src, getIRegG(size, pfx, rm) );
7147 assign( acc, getIRegRAX(size) );
sewardja6b93d12005-02-17 09:28:28 +00007148 setFlags_DEP1_DEP2(Iop_Sub8, acc, dest, ty);
7149 assign( cond8, unop(Iop_1Uto8, mk_amd64g_calculate_condition(AMD64CondZ)) );
7150 assign( dest2, IRExpr_Mux0X(mkexpr(cond8), mkexpr(dest), mkexpr(src)) );
7151 assign( acc2, IRExpr_Mux0X(mkexpr(cond8), mkexpr(dest), mkexpr(acc)) );
sewardj5b470602005-02-27 13:10:48 +00007152 putIRegRAX(size, mkexpr(acc2));
sewardja6b93d12005-02-17 09:28:28 +00007153
7154 if (epartIsReg(rm)) {
sewardj5b470602005-02-27 13:10:48 +00007155 putIRegE(size, pfx, rm, mkexpr(dest2));
sewardja6b93d12005-02-17 09:28:28 +00007156 } else {
7157 storeLE( mkexpr(addr), mkexpr(dest2) );
7158 }
7159
7160 return delta0;
7161}
7162
7163
sewardjd20c8852005-01-20 20:04:07 +00007164//.. //-- static
7165//.. //-- Addr dis_cmpxchg8b ( UCodeBlock* cb,
7166//.. //-- UChar sorb,
7167//.. //-- Addr eip0 )
7168//.. //-- {
7169//.. //-- Int tal, tah, junkl, junkh, destl, desth, srcl, srch, accl, acch;
7170//.. //-- HChar dis_buf[50];
7171//.. //-- UChar rm;
7172//.. //-- UInt pair;
7173//.. //--
7174//.. //-- rm = getUChar(eip0);
7175//.. //-- accl = newTemp(cb);
7176//.. //-- acch = newTemp(cb);
7177//.. //-- srcl = newTemp(cb);
7178//.. //-- srch = newTemp(cb);
7179//.. //-- destl = newTemp(cb);
7180//.. //-- desth = newTemp(cb);
7181//.. //-- junkl = newTemp(cb);
7182//.. //-- junkh = newTemp(cb);
7183//.. //--
7184//.. //-- vg_assert(!epartIsReg(rm));
7185//.. //--
7186//.. //-- pair = disAMode ( cb, sorb, eip0, dis_buf );
7187//.. //-- tal = LOW24(pair);
7188//.. //-- tah = newTemp(cb);
7189//.. //-- uInstr2(cb, MOV, 4, TempReg, tal, TempReg, tah);
7190//.. //-- uInstr2(cb, ADD, 4, Literal, 0, TempReg, tah);
7191//.. //-- uLiteral(cb, 4);
7192//.. //-- eip0 += HI8(pair);
7193//.. //-- DIP("cmpxchg8b %s\n", dis_buf);
7194//.. //--
7195//.. //-- uInstr0(cb, CALLM_S, 0);
7196//.. //--
7197//.. //-- uInstr2(cb, LOAD, 4, TempReg, tah, TempReg, desth);
7198//.. //-- uInstr1(cb, PUSH, 4, TempReg, desth);
7199//.. //-- uInstr2(cb, LOAD, 4, TempReg, tal, TempReg, destl);
7200//.. //-- uInstr1(cb, PUSH, 4, TempReg, destl);
7201//.. //-- uInstr2(cb, GET, 4, ArchReg, R_ECX, TempReg, srch);
7202//.. //-- uInstr1(cb, PUSH, 4, TempReg, srch);
7203//.. //-- uInstr2(cb, GET, 4, ArchReg, R_EBX, TempReg, srcl);
7204//.. //-- uInstr1(cb, PUSH, 4, TempReg, srcl);
7205//.. //-- uInstr2(cb, GET, 4, ArchReg, R_EDX, TempReg, acch);
7206//.. //-- uInstr1(cb, PUSH, 4, TempReg, acch);
7207//.. //-- uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, accl);
7208//.. //-- uInstr1(cb, PUSH, 4, TempReg, accl);
7209//.. //--
7210//.. //-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_cmpxchg8b));
7211//.. //-- uFlagsRWU(cb, FlagsEmpty, FlagZ, FlagsEmpty);
7212//.. //--
7213//.. //-- uInstr1(cb, POP, 4, TempReg, accl);
7214//.. //-- uInstr2(cb, PUT, 4, TempReg, accl, ArchReg, R_EAX);
7215//.. //-- uInstr1(cb, POP, 4, TempReg, acch);
7216//.. //-- uInstr2(cb, PUT, 4, TempReg, acch, ArchReg, R_EDX);
7217//.. //-- uInstr1(cb, POP, 4, TempReg, srcl);
7218//.. //-- uInstr2(cb, PUT, 4, TempReg, srcl, ArchReg, R_EBX);
7219//.. //-- uInstr1(cb, POP, 4, TempReg, srch);
7220//.. //-- uInstr2(cb, PUT, 4, TempReg, srch, ArchReg, R_ECX);
7221//.. //-- uInstr1(cb, POP, 4, TempReg, destl);
7222//.. //-- uInstr2(cb, STORE, 4, TempReg, destl, TempReg, tal);
7223//.. //-- uInstr1(cb, POP, 4, TempReg, desth);
7224//.. //-- uInstr2(cb, STORE, 4, TempReg, desth, TempReg, tah);
7225//.. //--
7226//.. //-- uInstr0(cb, CALLM_E, 0);
7227//.. //--
7228//.. //-- return eip0;
7229//.. //-- }
sewardj3ca55a12005-01-27 16:06:23 +00007230
7231
7232/* Handle conditional move instructions of the form
7233 cmovcc E(reg-or-mem), G(reg)
7234
7235 E(src) is reg-or-mem
7236 G(dst) is reg.
7237
7238 If E is reg, --> GET %E, tmps
7239 GET %G, tmpd
7240 CMOVcc tmps, tmpd
7241 PUT tmpd, %G
7242
7243 If E is mem --> (getAddr E) -> tmpa
7244 LD (tmpa), tmps
7245 GET %G, tmpd
7246 CMOVcc tmps, tmpd
7247 PUT tmpd, %G
7248*/
7249static
7250ULong dis_cmov_E_G ( Prefix pfx,
7251 Int sz,
7252 AMD64Condcode cond,
sewardj270def42005-07-03 01:03:01 +00007253 Long delta0 )
sewardj3ca55a12005-01-27 16:06:23 +00007254{
sewardj8c332e22005-01-28 01:36:56 +00007255 UChar rm = getUChar(delta0);
sewardj3ca55a12005-01-27 16:06:23 +00007256 HChar dis_buf[50];
7257 Int len;
7258
7259 IRType ty = szToITy(sz);
7260 IRTemp tmps = newTemp(ty);
7261 IRTemp tmpd = newTemp(ty);
7262
7263 if (epartIsReg(rm)) {
sewardj5b470602005-02-27 13:10:48 +00007264 assign( tmps, getIRegE(sz, pfx, rm) );
7265 assign( tmpd, getIRegG(sz, pfx, rm) );
sewardj3ca55a12005-01-27 16:06:23 +00007266
sewardj5b470602005-02-27 13:10:48 +00007267 putIRegG( sz, pfx, rm,
sewardj3ca55a12005-01-27 16:06:23 +00007268 IRExpr_Mux0X( unop(Iop_1Uto8,
7269 mk_amd64g_calculate_condition(cond)),
7270 mkexpr(tmpd),
7271 mkexpr(tmps) )
7272 );
sewardje941eea2005-01-30 19:52:28 +00007273 DIP("cmov%s %s,%s\n", name_AMD64Condcode(cond),
sewardj5b470602005-02-27 13:10:48 +00007274 nameIRegE(sz,pfx,rm),
7275 nameIRegG(sz,pfx,rm));
sewardj3ca55a12005-01-27 16:06:23 +00007276 return 1+delta0;
7277 }
7278
7279 /* E refers to memory */
7280 {
sewardje1698952005-02-08 15:02:39 +00007281 IRTemp addr = disAMode ( &len, pfx, delta0, dis_buf, 0 );
sewardj3ca55a12005-01-27 16:06:23 +00007282 assign( tmps, loadLE(ty, mkexpr(addr)) );
sewardj5b470602005-02-27 13:10:48 +00007283 assign( tmpd, getIRegG(sz, pfx, rm) );
sewardj3ca55a12005-01-27 16:06:23 +00007284
sewardj5b470602005-02-27 13:10:48 +00007285 putIRegG( sz, pfx, rm,
sewardj3ca55a12005-01-27 16:06:23 +00007286 IRExpr_Mux0X( unop(Iop_1Uto8,
7287 mk_amd64g_calculate_condition(cond)),
7288 mkexpr(tmpd),
7289 mkexpr(tmps) )
7290 );
7291
sewardj7eaa7cf2005-01-31 18:55:22 +00007292 DIP("cmov%s %s,%s\n", name_AMD64Condcode(cond),
7293 dis_buf,
sewardj5b470602005-02-27 13:10:48 +00007294 nameIRegG(sz,pfx,rm));
sewardj3ca55a12005-01-27 16:06:23 +00007295 return len+delta0;
7296 }
7297}
7298
7299
sewardjb4fd2e72005-03-23 13:34:11 +00007300static
7301ULong dis_xadd_G_E ( /*OUT*/Bool* decode_ok,
sewardj270def42005-07-03 01:03:01 +00007302 Prefix pfx, Int sz, Long delta0 )
sewardjb4fd2e72005-03-23 13:34:11 +00007303{
7304 Int len;
7305 UChar rm = getUChar(delta0);
7306 HChar dis_buf[50];
7307
7308 IRType ty = szToITy(sz);
7309 IRTemp tmpd = newTemp(ty);
7310 IRTemp tmpt0 = newTemp(ty);
7311 IRTemp tmpt1 = newTemp(ty);
7312 *decode_ok = True;
7313
7314 if (epartIsReg(rm)) {
7315 *decode_ok = False;
7316 return delta0;
7317 } else {
7318 IRTemp addr = disAMode ( &len, pfx, delta0, dis_buf, 0 );
7319 assign( tmpd, loadLE(ty, mkexpr(addr)) );
7320 assign( tmpt0, getIRegG(sz, pfx, rm) );
7321 assign( tmpt1, binop(mkSizedOp(ty,Iop_Add8), mkexpr(tmpd), mkexpr(tmpt0)) );
7322 setFlags_DEP1_DEP2( Iop_Add8, tmpd, tmpt0, ty );
7323 storeLE( mkexpr(addr), mkexpr(tmpt1) );
7324 putIRegG(sz, pfx, rm, mkexpr(tmpd));
7325 DIP("xadd%c %s, %s\n",
7326 nameISize(sz), nameIRegG(sz,pfx,rm), dis_buf);
7327 return len+delta0;
7328 }
7329}
7330
sewardjd20c8852005-01-20 20:04:07 +00007331//.. /* Move 16 bits from Ew (ireg or mem) to G (a segment register). */
7332//..
7333//.. static
sewardj270def42005-07-03 01:03:01 +00007334//.. UInt dis_mov_Ew_Sw ( UChar sorb, Long delta0 )
sewardjd20c8852005-01-20 20:04:07 +00007335//.. {
7336//.. Int len;
7337//.. IRTemp addr;
sewardj8c332e22005-01-28 01:36:56 +00007338//.. UChar rm = getUChar(delta0);
sewardjd20c8852005-01-20 20:04:07 +00007339//.. HChar dis_buf[50];
7340//..
7341//.. if (epartIsReg(rm)) {
7342//.. putSReg( gregOfRM(rm), getIReg(2, eregOfRM(rm)) );
7343//.. DIP("movw %s,%s\n", nameIReg(2,eregOfRM(rm)), nameSReg(gregOfRM(rm)));
7344//.. return 1+delta0;
7345//.. } else {
7346//.. addr = disAMode ( &len, sorb, delta0, dis_buf );
7347//.. putSReg( gregOfRM(rm), loadLE(Ity_I16, mkexpr(addr)) );
7348//.. DIP("movw %s,%s\n", dis_buf, nameSReg(gregOfRM(rm)));
7349//.. return len+delta0;
7350//.. }
7351//.. }
7352//..
7353//.. /* Move 16 bits from G (a segment register) to Ew (ireg or mem). If
7354//.. dst is ireg and sz==4, zero out top half of it. */
7355//..
7356//.. static
7357//.. UInt dis_mov_Sw_Ew ( UChar sorb,
7358//.. Int sz,
7359//.. UInt delta0 )
7360//.. {
7361//.. Int len;
7362//.. IRTemp addr;
sewardj8c332e22005-01-28 01:36:56 +00007363//.. UChar rm = getUChar(delta0);
sewardjd20c8852005-01-20 20:04:07 +00007364//.. HChar dis_buf[50];
7365//..
7366//.. vassert(sz == 2 || sz == 4);
7367//..
7368//.. if (epartIsReg(rm)) {
7369//.. if (sz == 4)
7370//.. putIReg(4, eregOfRM(rm), unop(Iop_16Uto32, getSReg(gregOfRM(rm))));
7371//.. else
7372//.. putIReg(2, eregOfRM(rm), getSReg(gregOfRM(rm)));
7373//..
7374//.. DIP("mov %s,%s\n", nameSReg(gregOfRM(rm)), nameIReg(sz,eregOfRM(rm)));
7375//.. return 1+delta0;
7376//.. } else {
7377//.. addr = disAMode ( &len, sorb, delta0, dis_buf );
7378//.. storeLE( mkexpr(addr), getSReg(gregOfRM(rm)) );
7379//.. DIP("mov %s,%s\n", nameSReg(gregOfRM(rm)), dis_buf);
7380//.. return len+delta0;
7381//.. }
7382//.. }
7383//..
7384//..
7385//.. static
7386//.. void dis_push_segreg ( UInt sreg, Int sz )
7387//.. {
7388//.. IRTemp t1 = newTemp(Ity_I16);
7389//.. IRTemp ta = newTemp(Ity_I32);
7390//.. vassert(sz == 2 || sz == 4);
7391//..
7392//.. assign( t1, getSReg(sreg) );
7393//.. assign( ta, binop(Iop_Sub32, getIReg(4, R_ESP), mkU32(sz)) );
7394//.. putIReg(4, R_ESP, mkexpr(ta));
7395//.. storeLE( mkexpr(ta), mkexpr(t1) );
7396//..
7397//.. DIP("pushw %s\n", nameSReg(sreg));
7398//.. }
7399//..
7400//.. static
7401//.. void dis_pop_segreg ( UInt sreg, Int sz )
7402//.. {
7403//.. IRTemp t1 = newTemp(Ity_I16);
7404//.. IRTemp ta = newTemp(Ity_I32);
7405//.. vassert(sz == 2 || sz == 4);
7406//..
7407//.. assign( ta, getIReg(4, R_ESP) );
7408//.. assign( t1, loadLE(Ity_I16, mkexpr(ta)) );
7409//..
7410//.. putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(ta), mkU32(sz)) );
7411//.. putSReg( sreg, mkexpr(t1) );
7412//.. DIP("pop %s\n", nameSReg(sreg));
7413//.. }
sewardj2f959cc2005-01-26 01:19:35 +00007414
7415static
7416void dis_ret ( ULong d64 )
7417{
7418 IRTemp t1 = newTemp(Ity_I64);
7419 IRTemp t2 = newTemp(Ity_I64);
sewardj5a9ffab2005-05-12 17:55:01 +00007420 IRTemp t3 = newTemp(Ity_I64);
sewardj2f959cc2005-01-26 01:19:35 +00007421 assign(t1, getIReg64(R_RSP));
7422 assign(t2, loadLE(Ity_I64,mkexpr(t1)));
sewardj5a9ffab2005-05-12 17:55:01 +00007423 assign(t3, binop(Iop_Add64, mkexpr(t1), mkU64(8+d64)));
7424 putIReg64(R_RSP, mkexpr(t3));
7425 make_redzone_AbiHint(t3, "ret");
sewardj2f959cc2005-01-26 01:19:35 +00007426 jmp_treg(Ijk_Ret,t2);
7427}
7428
sewardj5b470602005-02-27 13:10:48 +00007429
sewardj1001dc42005-02-21 08:25:55 +00007430/*------------------------------------------------------------*/
7431/*--- SSE/SSE2/SSE3 helpers ---*/
7432/*------------------------------------------------------------*/
7433
7434/* Worker function; do not call directly.
7435 Handles full width G = G `op` E and G = (not G) `op` E.
7436*/
7437
sewardj8d965312005-02-25 02:48:47 +00007438static ULong dis_SSE_E_to_G_all_wrk (
sewardj270def42005-07-03 01:03:01 +00007439 Prefix pfx, Long delta,
sewardj8d965312005-02-25 02:48:47 +00007440 HChar* opname, IROp op,
7441 Bool invertG
7442 )
sewardj9da16972005-02-21 13:58:26 +00007443{
7444 HChar dis_buf[50];
7445 Int alen;
7446 IRTemp addr;
7447 UChar rm = getUChar(delta);
7448 IRExpr* gpart
7449 = invertG ? unop(Iop_NotV128, getXMMReg(gregOfRexRM(pfx,rm)))
7450 : getXMMReg(gregOfRexRM(pfx,rm));
7451 if (epartIsReg(rm)) {
7452 putXMMReg( gregOfRexRM(pfx,rm),
7453 binop(op, gpart,
7454 getXMMReg(eregOfRexRM(pfx,rm))) );
7455 DIP("%s %s,%s\n", opname,
7456 nameXMMReg(eregOfRexRM(pfx,rm)),
7457 nameXMMReg(gregOfRexRM(pfx,rm)) );
7458 return delta+1;
7459 } else {
7460 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
7461 putXMMReg( gregOfRexRM(pfx,rm),
7462 binop(op, gpart,
7463 loadLE(Ity_V128, mkexpr(addr))) );
7464 DIP("%s %s,%s\n", opname,
7465 dis_buf,
7466 nameXMMReg(gregOfRexRM(pfx,rm)) );
7467 return delta+alen;
7468 }
7469}
7470
7471
7472/* All lanes SSE binary operation, G = G `op` E. */
7473
7474static
sewardj270def42005-07-03 01:03:01 +00007475ULong dis_SSE_E_to_G_all ( Prefix pfx, Long delta,
sewardj8d965312005-02-25 02:48:47 +00007476 HChar* opname, IROp op )
sewardj9da16972005-02-21 13:58:26 +00007477{
7478 return dis_SSE_E_to_G_all_wrk( pfx, delta, opname, op, False );
7479}
7480
sewardj8d965312005-02-25 02:48:47 +00007481/* All lanes SSE binary operation, G = (not G) `op` E. */
7482
7483static
sewardj270def42005-07-03 01:03:01 +00007484ULong dis_SSE_E_to_G_all_invG ( Prefix pfx, Long delta,
sewardj8d965312005-02-25 02:48:47 +00007485 HChar* opname, IROp op )
7486{
7487 return dis_SSE_E_to_G_all_wrk( pfx, delta, opname, op, True );
7488}
7489
7490
7491/* Lowest 32-bit lane only SSE binary operation, G = G `op` E. */
7492
sewardj270def42005-07-03 01:03:01 +00007493static ULong dis_SSE_E_to_G_lo32 ( Prefix pfx, Long delta,
sewardj8d965312005-02-25 02:48:47 +00007494 HChar* opname, IROp op )
7495{
7496 HChar dis_buf[50];
7497 Int alen;
7498 IRTemp addr;
7499 UChar rm = getUChar(delta);
sewardj9c9ee3d2005-02-26 01:17:42 +00007500 IRExpr* gpart = getXMMReg(gregOfRexRM(pfx,rm));
sewardj8d965312005-02-25 02:48:47 +00007501 if (epartIsReg(rm)) {
sewardj9c9ee3d2005-02-26 01:17:42 +00007502 putXMMReg( gregOfRexRM(pfx,rm),
sewardj8d965312005-02-25 02:48:47 +00007503 binop(op, gpart,
7504 getXMMReg(eregOfRexRM(pfx,rm))) );
7505 DIP("%s %s,%s\n", opname,
7506 nameXMMReg(eregOfRexRM(pfx,rm)),
7507 nameXMMReg(gregOfRexRM(pfx,rm)) );
7508 return delta+1;
7509 } else {
7510 /* We can only do a 32-bit memory read, so the upper 3/4 of the
7511 E operand needs to be made simply of zeroes. */
7512 IRTemp epart = newTemp(Ity_V128);
7513 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
7514 assign( epart, unop( Iop_32UtoV128,
7515 loadLE(Ity_I32, mkexpr(addr))) );
7516 putXMMReg( gregOfRexRM(pfx,rm),
7517 binop(op, gpart, mkexpr(epart)) );
7518 DIP("%s %s,%s\n", opname,
7519 dis_buf,
7520 nameXMMReg(gregOfRexRM(pfx,rm)) );
7521 return delta+alen;
7522 }
7523}
sewardj1001dc42005-02-21 08:25:55 +00007524
7525
7526/* Lower 64-bit lane only SSE binary operation, G = G `op` E. */
7527
sewardj270def42005-07-03 01:03:01 +00007528static ULong dis_SSE_E_to_G_lo64 ( Prefix pfx, Long delta,
sewardj8d965312005-02-25 02:48:47 +00007529 HChar* opname, IROp op )
sewardj1001dc42005-02-21 08:25:55 +00007530{
7531 HChar dis_buf[50];
7532 Int alen;
7533 IRTemp addr;
7534 UChar rm = getUChar(delta);
7535 IRExpr* gpart = getXMMReg(gregOfRexRM(pfx,rm));
7536 if (epartIsReg(rm)) {
7537 putXMMReg( gregOfRexRM(pfx,rm),
7538 binop(op, gpart,
7539 getXMMReg(eregOfRexRM(pfx,rm))) );
7540 DIP("%s %s,%s\n", opname,
7541 nameXMMReg(eregOfRexRM(pfx,rm)),
7542 nameXMMReg(gregOfRexRM(pfx,rm)) );
7543 return delta+1;
7544 } else {
7545 /* We can only do a 64-bit memory read, so the upper half of the
7546 E operand needs to be made simply of zeroes. */
7547 IRTemp epart = newTemp(Ity_V128);
7548 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
7549 assign( epart, unop( Iop_64UtoV128,
7550 loadLE(Ity_I64, mkexpr(addr))) );
7551 putXMMReg( gregOfRexRM(pfx,rm),
7552 binop(op, gpart, mkexpr(epart)) );
7553 DIP("%s %s,%s\n", opname,
7554 dis_buf,
7555 nameXMMReg(gregOfRexRM(pfx,rm)) );
7556 return delta+alen;
7557 }
7558}
7559
7560
sewardja7ba8c42005-05-10 20:08:34 +00007561/* All lanes unary SSE operation, G = op(E). */
7562
7563static ULong dis_SSE_E_to_G_unary_all (
sewardj270def42005-07-03 01:03:01 +00007564 Prefix pfx, Long delta,
sewardja7ba8c42005-05-10 20:08:34 +00007565 HChar* opname, IROp op
7566 )
7567{
7568 HChar dis_buf[50];
7569 Int alen;
7570 IRTemp addr;
7571 UChar rm = getUChar(delta);
7572 if (epartIsReg(rm)) {
7573 putXMMReg( gregOfRexRM(pfx,rm),
7574 unop(op, getXMMReg(eregOfRexRM(pfx,rm))) );
7575 DIP("%s %s,%s\n", opname,
7576 nameXMMReg(eregOfRexRM(pfx,rm)),
7577 nameXMMReg(gregOfRexRM(pfx,rm)) );
7578 return delta+1;
7579 } else {
7580 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
7581 putXMMReg( gregOfRexRM(pfx,rm),
7582 unop(op, loadLE(Ity_V128, mkexpr(addr))) );
7583 DIP("%s %s,%s\n", opname,
7584 dis_buf,
7585 nameXMMReg(gregOfRexRM(pfx,rm)) );
7586 return delta+alen;
7587 }
7588}
7589
7590
7591/* Lowest 32-bit lane only unary SSE operation, G = op(E). */
7592
7593static ULong dis_SSE_E_to_G_unary_lo32 (
sewardj270def42005-07-03 01:03:01 +00007594 Prefix pfx, Long delta,
sewardja7ba8c42005-05-10 20:08:34 +00007595 HChar* opname, IROp op
7596 )
7597{
7598 /* First we need to get the old G value and patch the low 32 bits
7599 of the E operand into it. Then apply op and write back to G. */
7600 HChar dis_buf[50];
7601 Int alen;
7602 IRTemp addr;
7603 UChar rm = getUChar(delta);
7604 IRTemp oldG0 = newTemp(Ity_V128);
7605 IRTemp oldG1 = newTemp(Ity_V128);
7606
7607 assign( oldG0, getXMMReg(gregOfRexRM(pfx,rm)) );
7608
7609 if (epartIsReg(rm)) {
7610 assign( oldG1,
7611 binop( Iop_SetV128lo32,
7612 mkexpr(oldG0),
7613 getXMMRegLane32(eregOfRexRM(pfx,rm), 0)) );
7614 putXMMReg( gregOfRexRM(pfx,rm), unop(op, mkexpr(oldG1)) );
7615 DIP("%s %s,%s\n", opname,
7616 nameXMMReg(eregOfRexRM(pfx,rm)),
7617 nameXMMReg(gregOfRexRM(pfx,rm)) );
7618 return delta+1;
7619 } else {
7620 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
7621 assign( oldG1,
7622 binop( Iop_SetV128lo32,
7623 mkexpr(oldG0),
7624 loadLE(Ity_I32, mkexpr(addr)) ));
7625 putXMMReg( gregOfRexRM(pfx,rm), unop(op, mkexpr(oldG1)) );
7626 DIP("%s %s,%s\n", opname,
7627 dis_buf,
7628 nameXMMReg(gregOfRexRM(pfx,rm)) );
7629 return delta+alen;
7630 }
7631}
sewardj1001dc42005-02-21 08:25:55 +00007632
7633
7634/* Lowest 64-bit lane only unary SSE operation, G = op(E). */
7635
sewardj8d965312005-02-25 02:48:47 +00007636static ULong dis_SSE_E_to_G_unary_lo64 (
sewardj270def42005-07-03 01:03:01 +00007637 Prefix pfx, Long delta,
sewardj8d965312005-02-25 02:48:47 +00007638 HChar* opname, IROp op
7639 )
sewardj1001dc42005-02-21 08:25:55 +00007640{
7641 /* First we need to get the old G value and patch the low 64 bits
7642 of the E operand into it. Then apply op and write back to G. */
7643 HChar dis_buf[50];
7644 Int alen;
7645 IRTemp addr;
7646 UChar rm = getUChar(delta);
7647 IRTemp oldG0 = newTemp(Ity_V128);
7648 IRTemp oldG1 = newTemp(Ity_V128);
7649
7650 assign( oldG0, getXMMReg(gregOfRexRM(pfx,rm)) );
7651
7652 if (epartIsReg(rm)) {
7653 assign( oldG1,
7654 binop( Iop_SetV128lo64,
7655 mkexpr(oldG0),
7656 getXMMRegLane64(eregOfRexRM(pfx,rm), 0)) );
7657 putXMMReg( gregOfRexRM(pfx,rm), unop(op, mkexpr(oldG1)) );
7658 DIP("%s %s,%s\n", opname,
7659 nameXMMReg(eregOfRexRM(pfx,rm)),
7660 nameXMMReg(gregOfRexRM(pfx,rm)) );
7661 return delta+1;
7662 } else {
7663 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
7664 assign( oldG1,
7665 binop( Iop_SetV128lo64,
7666 mkexpr(oldG0),
7667 loadLE(Ity_I64, mkexpr(addr)) ));
7668 putXMMReg( gregOfRexRM(pfx,rm), unop(op, mkexpr(oldG1)) );
7669 DIP("%s %s,%s\n", opname,
7670 dis_buf,
7671 nameXMMReg(gregOfRexRM(pfx,rm)) );
7672 return delta+alen;
7673 }
7674}
7675
7676
sewardj09717342005-05-05 21:34:02 +00007677/* SSE integer binary operation:
7678 G = G `op` E (eLeft == False)
7679 G = E `op` G (eLeft == True)
7680*/
7681static ULong dis_SSEint_E_to_G(
sewardj270def42005-07-03 01:03:01 +00007682 Prefix pfx, Long delta,
sewardj09717342005-05-05 21:34:02 +00007683 HChar* opname, IROp op,
7684 Bool eLeft
7685 )
7686{
7687 HChar dis_buf[50];
7688 Int alen;
7689 IRTemp addr;
7690 UChar rm = getUChar(delta);
7691 IRExpr* gpart = getXMMReg(gregOfRexRM(pfx,rm));
7692 IRExpr* epart = NULL;
7693 if (epartIsReg(rm)) {
7694 epart = getXMMReg(eregOfRexRM(pfx,rm));
7695 DIP("%s %s,%s\n", opname,
7696 nameXMMReg(eregOfRexRM(pfx,rm)),
7697 nameXMMReg(gregOfRexRM(pfx,rm)) );
7698 delta += 1;
7699 } else {
7700 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
7701 epart = loadLE(Ity_V128, mkexpr(addr));
7702 DIP("%s %s,%s\n", opname,
7703 dis_buf,
7704 nameXMMReg(gregOfRexRM(pfx,rm)) );
7705 delta += alen;
7706 }
7707 putXMMReg( gregOfRexRM(pfx,rm),
7708 eLeft ? binop(op, epart, gpart)
7709 : binop(op, gpart, epart) );
7710 return delta;
7711}
sewardj8d965312005-02-25 02:48:47 +00007712
7713
7714/* Helper for doing SSE FP comparisons. */
7715
7716static void findSSECmpOp ( Bool* needNot, IROp* op,
7717 Int imm8, Bool all_lanes, Int sz )
7718{
7719 imm8 &= 7;
7720 *needNot = False;
7721 *op = Iop_INVALID;
7722 if (imm8 >= 4) {
7723 *needNot = True;
7724 imm8 -= 4;
7725 }
7726
7727 if (sz == 4 && all_lanes) {
7728 switch (imm8) {
7729 case 0: *op = Iop_CmpEQ32Fx4; return;
7730 case 1: *op = Iop_CmpLT32Fx4; return;
7731 case 2: *op = Iop_CmpLE32Fx4; return;
7732 case 3: *op = Iop_CmpUN32Fx4; return;
7733 default: break;
7734 }
7735 }
7736 if (sz == 4 && !all_lanes) {
7737 switch (imm8) {
7738 case 0: *op = Iop_CmpEQ32F0x4; return;
7739 case 1: *op = Iop_CmpLT32F0x4; return;
7740 case 2: *op = Iop_CmpLE32F0x4; return;
7741 case 3: *op = Iop_CmpUN32F0x4; return;
7742 default: break;
7743 }
7744 }
7745 if (sz == 8 && all_lanes) {
7746 switch (imm8) {
7747 case 0: *op = Iop_CmpEQ64Fx2; return;
7748 case 1: *op = Iop_CmpLT64Fx2; return;
7749 case 2: *op = Iop_CmpLE64Fx2; return;
7750 case 3: *op = Iop_CmpUN64Fx2; return;
7751 default: break;
7752 }
7753 }
7754 if (sz == 8 && !all_lanes) {
7755 switch (imm8) {
7756 case 0: *op = Iop_CmpEQ64F0x2; return;
7757 case 1: *op = Iop_CmpLT64F0x2; return;
7758 case 2: *op = Iop_CmpLE64F0x2; return;
7759 case 3: *op = Iop_CmpUN64F0x2; return;
7760 default: break;
7761 }
7762 }
7763 vpanic("findSSECmpOp(amd64,guest)");
7764}
7765
sewardjab9055b2006-01-01 13:17:38 +00007766/* Handles SSE 32F/64F comparisons. */
sewardj8d965312005-02-25 02:48:47 +00007767
sewardj270def42005-07-03 01:03:01 +00007768static ULong dis_SSEcmp_E_to_G ( Prefix pfx, Long delta,
sewardj8d965312005-02-25 02:48:47 +00007769 HChar* opname, Bool all_lanes, Int sz )
7770{
7771 HChar dis_buf[50];
7772 Int alen, imm8;
7773 IRTemp addr;
7774 Bool needNot = False;
7775 IROp op = Iop_INVALID;
7776 IRTemp plain = newTemp(Ity_V128);
7777 UChar rm = getUChar(delta);
7778 UShort mask = 0;
7779 vassert(sz == 4 || sz == 8);
7780 if (epartIsReg(rm)) {
7781 imm8 = getUChar(delta+1);
7782 findSSECmpOp(&needNot, &op, imm8, all_lanes, sz);
7783 assign( plain, binop(op, getXMMReg(gregOfRexRM(pfx,rm)),
7784 getXMMReg(eregOfRexRM(pfx,rm))) );
7785 delta += 2;
7786 DIP("%s $%d,%s,%s\n", opname,
7787 (Int)imm8,
7788 nameXMMReg(eregOfRexRM(pfx,rm)),
7789 nameXMMReg(gregOfRexRM(pfx,rm)) );
7790 } else {
7791 addr = disAMode ( &alen, pfx, delta, dis_buf, 1 );
7792 imm8 = getUChar(delta+alen);
7793 findSSECmpOp(&needNot, &op, imm8, all_lanes, sz);
sewardjab9055b2006-01-01 13:17:38 +00007794 assign( plain,
7795 binop(
7796 op,
7797 getXMMReg(gregOfRexRM(pfx,rm)),
7798 all_lanes ? loadLE(Ity_V128, mkexpr(addr))
7799 : sz == 8 ? unop( Iop_64UtoV128, loadLE(Ity_I64, mkexpr(addr)))
7800 : /*sz==4*/ unop( Iop_32UtoV128, loadLE(Ity_I32, mkexpr(addr)))
7801 )
7802 );
sewardj8d965312005-02-25 02:48:47 +00007803 delta += alen+1;
7804 DIP("%s $%d,%s,%s\n", opname,
7805 (Int)imm8,
7806 dis_buf,
7807 nameXMMReg(gregOfRexRM(pfx,rm)) );
7808 }
7809
7810 if (needNot && all_lanes) {
sewardj9c9ee3d2005-02-26 01:17:42 +00007811 putXMMReg( gregOfRexRM(pfx,rm),
sewardj8d965312005-02-25 02:48:47 +00007812 unop(Iop_NotV128, mkexpr(plain)) );
7813 }
7814 else
7815 if (needNot && !all_lanes) {
sewardj1027dc22005-02-26 01:55:02 +00007816 mask = toUShort(sz==4 ? 0x000F : 0x00FF);
sewardj8d965312005-02-25 02:48:47 +00007817 putXMMReg( gregOfRexRM(pfx,rm),
7818 binop(Iop_XorV128, mkexpr(plain), mkV128(mask)) );
7819 }
7820 else {
7821 putXMMReg( gregOfRexRM(pfx,rm), mkexpr(plain) );
7822 }
7823
7824 return delta;
7825}
7826
7827
sewardjadffcef2005-05-11 00:03:06 +00007828/* Vector by scalar shift of G by the amount specified at the bottom
7829 of E. */
7830
sewardj270def42005-07-03 01:03:01 +00007831static ULong dis_SSE_shiftG_byE ( Prefix pfx, Long delta,
sewardjadffcef2005-05-11 00:03:06 +00007832 HChar* opname, IROp op )
7833{
7834 HChar dis_buf[50];
7835 Int alen, size;
7836 IRTemp addr;
7837 Bool shl, shr, sar;
7838 UChar rm = getUChar(delta);
7839 IRTemp g0 = newTemp(Ity_V128);
7840 IRTemp g1 = newTemp(Ity_V128);
7841 IRTemp amt = newTemp(Ity_I32);
7842 IRTemp amt8 = newTemp(Ity_I8);
7843 if (epartIsReg(rm)) {
7844 assign( amt, getXMMRegLane32(eregOfRexRM(pfx,rm), 0) );
7845 DIP("%s %s,%s\n", opname,
7846 nameXMMReg(eregOfRexRM(pfx,rm)),
7847 nameXMMReg(gregOfRexRM(pfx,rm)) );
7848 delta++;
7849 } else {
7850 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
7851 assign( amt, loadLE(Ity_I32, mkexpr(addr)) );
7852 DIP("%s %s,%s\n", opname,
7853 dis_buf,
7854 nameXMMReg(gregOfRexRM(pfx,rm)) );
7855 delta += alen;
7856 }
7857 assign( g0, getXMMReg(gregOfRexRM(pfx,rm)) );
7858 assign( amt8, unop(Iop_32to8, mkexpr(amt)) );
7859
7860 shl = shr = sar = False;
7861 size = 0;
7862 switch (op) {
7863 case Iop_ShlN16x8: shl = True; size = 32; break;
7864 case Iop_ShlN32x4: shl = True; size = 32; break;
7865 case Iop_ShlN64x2: shl = True; size = 64; break;
7866 case Iop_SarN16x8: sar = True; size = 16; break;
7867 case Iop_SarN32x4: sar = True; size = 32; break;
7868 case Iop_ShrN16x8: shr = True; size = 16; break;
7869 case Iop_ShrN32x4: shr = True; size = 32; break;
7870 case Iop_ShrN64x2: shr = True; size = 64; break;
7871 default: vassert(0);
7872 }
7873
7874 if (shl || shr) {
7875 assign(
7876 g1,
7877 IRExpr_Mux0X(
7878 unop(Iop_1Uto8,
7879 binop(Iop_CmpLT64U, unop(Iop_32Uto64,mkexpr(amt)), mkU64(size))),
7880 mkV128(0x0000),
7881 binop(op, mkexpr(g0), mkexpr(amt8))
7882 )
7883 );
7884 } else
7885 if (sar) {
7886 assign(
7887 g1,
7888 IRExpr_Mux0X(
7889 unop(Iop_1Uto8,
7890 binop(Iop_CmpLT64U, unop(Iop_32Uto64,mkexpr(amt)), mkU64(size))),
7891 binop(op, mkexpr(g0), mkU8(size-1)),
7892 binop(op, mkexpr(g0), mkexpr(amt8))
7893 )
7894 );
7895 } else {
7896 vassert(0);
7897 }
7898
7899 putXMMReg( gregOfRexRM(pfx,rm), mkexpr(g1) );
7900 return delta;
7901}
sewardj09717342005-05-05 21:34:02 +00007902
7903
7904/* Vector by scalar shift of E by an immediate byte. */
7905
7906static
7907ULong dis_SSE_shiftE_imm ( Prefix pfx,
sewardj270def42005-07-03 01:03:01 +00007908 Long delta, HChar* opname, IROp op )
sewardj09717342005-05-05 21:34:02 +00007909{
7910 Bool shl, shr, sar;
7911 UChar rm = getUChar(delta);
7912 IRTemp e0 = newTemp(Ity_V128);
7913 IRTemp e1 = newTemp(Ity_V128);
7914 UChar amt, size;
7915 vassert(epartIsReg(rm));
7916 vassert(gregLO3ofRM(rm) == 2
7917 || gregLO3ofRM(rm) == 4 || gregLO3ofRM(rm) == 6);
sewardjca673ab2005-05-11 10:03:08 +00007918 amt = getUChar(delta+1);
sewardj09717342005-05-05 21:34:02 +00007919 delta += 2;
7920 DIP("%s $%d,%s\n", opname,
7921 (Int)amt,
7922 nameXMMReg(eregOfRexRM(pfx,rm)) );
7923 assign( e0, getXMMReg(eregOfRexRM(pfx,rm)) );
7924
7925 shl = shr = sar = False;
7926 size = 0;
7927 switch (op) {
7928 case Iop_ShlN16x8: shl = True; size = 16; break;
7929 case Iop_ShlN32x4: shl = True; size = 32; break;
7930 case Iop_ShlN64x2: shl = True; size = 64; break;
7931 case Iop_SarN16x8: sar = True; size = 16; break;
7932 case Iop_SarN32x4: sar = True; size = 32; break;
7933 case Iop_ShrN16x8: shr = True; size = 16; break;
7934 case Iop_ShrN32x4: shr = True; size = 32; break;
7935 case Iop_ShrN64x2: shr = True; size = 64; break;
7936 default: vassert(0);
7937 }
7938
7939 if (shl || shr) {
7940 assign( e1, amt >= size
7941 ? mkV128(0x0000)
7942 : binop(op, mkexpr(e0), mkU8(amt))
7943 );
7944 } else
7945 if (sar) {
7946 assign( e1, amt >= size
7947 ? binop(op, mkexpr(e0), mkU8(size-1))
7948 : binop(op, mkexpr(e0), mkU8(amt))
7949 );
7950 } else {
7951 vassert(0);
7952 }
7953
7954 putXMMReg( eregOfRexRM(pfx,rm), mkexpr(e1) );
7955 return delta;
7956}
sewardj1a01e652005-02-23 11:39:21 +00007957
7958
7959/* Get the current SSE rounding mode. */
7960
7961static IRExpr* /* :: Ity_I32 */ get_sse_roundingmode ( void )
7962{
7963 return
7964 unop( Iop_64to32,
7965 binop( Iop_And64,
7966 IRExpr_Get( OFFB_SSEROUND, Ity_I64 ),
7967 mkU64(3) ));
7968}
7969
sewardjbcbb9de2005-03-27 02:22:32 +00007970static void put_sse_roundingmode ( IRExpr* sseround )
7971{
7972 vassert(typeOfIRExpr(irbb->tyenv, sseround) == Ity_I32);
7973 stmt( IRStmt_Put( OFFB_SSEROUND,
7974 unop(Iop_32Uto64,sseround) ) );
7975}
7976
sewardja7ba8c42005-05-10 20:08:34 +00007977/* Break a 128-bit value up into four 32-bit ints. */
7978
7979static void breakup128to32s ( IRTemp t128,
7980 /*OUTs*/
7981 IRTemp* t3, IRTemp* t2,
7982 IRTemp* t1, IRTemp* t0 )
7983{
7984 IRTemp hi64 = newTemp(Ity_I64);
7985 IRTemp lo64 = newTemp(Ity_I64);
7986 assign( hi64, unop(Iop_V128HIto64, mkexpr(t128)) );
7987 assign( lo64, unop(Iop_V128to64, mkexpr(t128)) );
7988
7989 vassert(t0 && *t0 == IRTemp_INVALID);
7990 vassert(t1 && *t1 == IRTemp_INVALID);
7991 vassert(t2 && *t2 == IRTemp_INVALID);
7992 vassert(t3 && *t3 == IRTemp_INVALID);
7993
7994 *t0 = newTemp(Ity_I32);
7995 *t1 = newTemp(Ity_I32);
7996 *t2 = newTemp(Ity_I32);
7997 *t3 = newTemp(Ity_I32);
7998 assign( *t0, unop(Iop_64to32, mkexpr(lo64)) );
7999 assign( *t1, unop(Iop_64HIto32, mkexpr(lo64)) );
8000 assign( *t2, unop(Iop_64to32, mkexpr(hi64)) );
8001 assign( *t3, unop(Iop_64HIto32, mkexpr(hi64)) );
8002}
8003
8004/* Construct a 128-bit value from four 32-bit ints. */
8005
8006static IRExpr* mk128from32s ( IRTemp t3, IRTemp t2,
8007 IRTemp t1, IRTemp t0 )
8008{
8009 return
8010 binop( Iop_64HLtoV128,
8011 binop(Iop_32HLto64, mkexpr(t3), mkexpr(t2)),
8012 binop(Iop_32HLto64, mkexpr(t1), mkexpr(t0))
8013 );
8014}
8015
8016/* Break a 64-bit value up into four 16-bit ints. */
8017
8018static void breakup64to16s ( IRTemp t64,
8019 /*OUTs*/
8020 IRTemp* t3, IRTemp* t2,
8021 IRTemp* t1, IRTemp* t0 )
8022{
8023 IRTemp hi32 = newTemp(Ity_I32);
8024 IRTemp lo32 = newTemp(Ity_I32);
8025 assign( hi32, unop(Iop_64HIto32, mkexpr(t64)) );
8026 assign( lo32, unop(Iop_64to32, mkexpr(t64)) );
8027
8028 vassert(t0 && *t0 == IRTemp_INVALID);
8029 vassert(t1 && *t1 == IRTemp_INVALID);
8030 vassert(t2 && *t2 == IRTemp_INVALID);
8031 vassert(t3 && *t3 == IRTemp_INVALID);
8032
8033 *t0 = newTemp(Ity_I16);
8034 *t1 = newTemp(Ity_I16);
8035 *t2 = newTemp(Ity_I16);
8036 *t3 = newTemp(Ity_I16);
8037 assign( *t0, unop(Iop_32to16, mkexpr(lo32)) );
8038 assign( *t1, unop(Iop_32HIto16, mkexpr(lo32)) );
8039 assign( *t2, unop(Iop_32to16, mkexpr(hi32)) );
8040 assign( *t3, unop(Iop_32HIto16, mkexpr(hi32)) );
8041}
8042
8043/* Construct a 64-bit value from four 16-bit ints. */
8044
8045static IRExpr* mk64from16s ( IRTemp t3, IRTemp t2,
8046 IRTemp t1, IRTemp t0 )
8047{
8048 return
8049 binop( Iop_32HLto64,
8050 binop(Iop_16HLto32, mkexpr(t3), mkexpr(t2)),
8051 binop(Iop_16HLto32, mkexpr(t1), mkexpr(t0))
8052 );
8053}
sewardjdf0e0022005-01-25 15:48:43 +00008054
8055
8056/*------------------------------------------------------------*/
8057/*--- Disassemble a single instruction ---*/
8058/*------------------------------------------------------------*/
8059
sewardj9e6491a2005-07-02 19:24:10 +00008060/* Disassemble a single instruction into IR. The instruction is
8061 located in host memory at &guest_code[delta]. */
sewardjdf0e0022005-01-25 15:48:43 +00008062
sewardj9e6491a2005-07-02 19:24:10 +00008063static
8064DisResult disInstr_AMD64_WRK (
8065 Bool put_IP,
sewardjc716aea2006-01-17 01:48:46 +00008066 Bool (*resteerOkFn) ( /*opaque*/void*, Addr64 ),
8067 void* callback_opaque,
sewardj9e6491a2005-07-02 19:24:10 +00008068 Long delta64,
8069 VexArchInfo* archinfo
8070 )
sewardjdf0e0022005-01-25 15:48:43 +00008071{
8072 IRType ty;
sewardja7ba8c42005-05-10 20:08:34 +00008073 IRTemp addr, t0, t1, t2, t3, t4, t5, t6;
sewardjdf0e0022005-01-25 15:48:43 +00008074 Int alen;
sewardj7a240552005-01-28 21:37:12 +00008075 UChar opc, modrm, /*abyte,*/ pre;
sewardj1027dc22005-02-26 01:55:02 +00008076 Long d64;
sewardjdf0e0022005-01-25 15:48:43 +00008077 HChar dis_buf[50];
8078 Int am_sz, d_sz, n, n_prefixes;
sewardj9e6491a2005-07-02 19:24:10 +00008079 DisResult dres;
sewardja6b93d12005-02-17 09:28:28 +00008080 UChar* insn; /* used in SSE decoders */
sewardjdf0e0022005-01-25 15:48:43 +00008081
sewardj9e6491a2005-07-02 19:24:10 +00008082 /* The running delta */
8083 Long delta = delta64;
8084
sewardjdf0e0022005-01-25 15:48:43 +00008085 /* Holds eip at the start of the insn, so that we can print
8086 consistent error messages for unimplemented insns. */
sewardj270def42005-07-03 01:03:01 +00008087 Long delta_start = delta;
sewardjdf0e0022005-01-25 15:48:43 +00008088
8089 /* sz denotes the nominal data-op size of the insn; we change it to
8090 2 if an 0x66 prefix is seen and 8 if REX.W is 1. In case of
8091 conflict REX.W takes precedence. */
8092 Int sz = 4;
8093
sewardj3ca55a12005-01-27 16:06:23 +00008094 /* pfx holds the summary of prefixes. */
8095 Prefix pfx = PFX_EMPTY;
sewardjdf0e0022005-01-25 15:48:43 +00008096
sewardj9e6491a2005-07-02 19:24:10 +00008097 /* Set result defaults. */
8098 dres.whatNext = Dis_Continue;
8099 dres.len = 0;
8100 dres.continueAt = 0;
sewardjdf0e0022005-01-25 15:48:43 +00008101
sewardj9e6491a2005-07-02 19:24:10 +00008102 vassert(guest_RIP_next_assumed == 0);
8103 vassert(guest_RIP_next_mustcheck == False);
sewardj4b744762005-02-07 15:02:25 +00008104
sewardja7ba8c42005-05-10 20:08:34 +00008105 addr = t0 = t1 = t2 = t3 = t4 = t5 = t6 = IRTemp_INVALID;
sewardjdf0e0022005-01-25 15:48:43 +00008106
sewardj9e6491a2005-07-02 19:24:10 +00008107 DIP("\t0x%llx: ", guest_RIP_bbstart+delta);
8108
8109 /* We may be asked to update the guest RIP before going further. */
8110 if (put_IP)
8111 stmt( IRStmt_Put( OFFB_RIP, mkU64(guest_RIP_curr_instr)) );
sewardjdf0e0022005-01-25 15:48:43 +00008112
sewardjce02aa72006-01-12 12:27:58 +00008113 /* Spot "Special" instructions (see comment at top of file). */
sewardjdf0e0022005-01-25 15:48:43 +00008114 {
8115 UChar* code = (UChar*)(guest_code + delta);
sewardjce02aa72006-01-12 12:27:58 +00008116 /* Spot the 16-byte preamble:
8117 48C1C703 rolq $3, %rdi
8118 48C1C70D rolq $13, %rdi
8119 48C1C73D rolq $61, %rdi
8120 48C1C733 rolq $51, %rdi
sewardjdf0e0022005-01-25 15:48:43 +00008121 */
sewardjce02aa72006-01-12 12:27:58 +00008122 if (code[ 0] == 0x48 && code[ 1] == 0xC1 && code[ 2] == 0xC7
8123 && code[ 3] == 0x03 &&
8124 code[ 4] == 0x48 && code[ 5] == 0xC1 && code[ 6] == 0xC7
8125 && code[ 7] == 0x0D &&
8126 code[ 8] == 0x48 && code[ 9] == 0xC1 && code[10] == 0xC7
8127 && code[11] == 0x3D &&
8128 code[12] == 0x48 && code[13] == 0xC1 && code[14] == 0xC7
8129 && code[15] == 0x33) {
8130 /* Got a "Special" instruction preamble. Which one is it? */
8131 if (code[16] == 0x48 && code[17] == 0x87
8132 && code[18] == 0xDB /* xchgq %rbx,%rbx */) {
8133 /* %RDX = client_request ( %RAX ) */
8134 DIP("%%rdx = client_request ( %%rax )\n");
8135 delta += 19;
8136 jmp_lit(Ijk_ClientReq, guest_RIP_bbstart+delta);
8137 dres.whatNext = Dis_StopHere;
8138 goto decode_success;
8139 }
8140 else
8141 if (code[16] == 0x48 && code[17] == 0x87
8142 && code[18] == 0xC9 /* xchgq %rcx,%rcx */) {
8143 /* %RAX = guest_NRADDR */
8144 DIP("%%rax = guest_NRADDR\n");
8145 delta += 19;
8146 putIRegRAX(8, IRExpr_Get( OFFB_NRADDR, Ity_I64 ));
8147 goto decode_success;
8148 }
8149 else
8150 if (code[16] == 0x48 && code[17] == 0x87
8151 && code[18] == 0xD2 /* xchgq %rdx,%rdx */) {
8152 /* call-noredir *%RAX */
8153 DIP("call-noredir *%%rax\n");
8154 delta += 19;
8155 t1 = newTemp(Ity_I64);
8156 assign(t1, getIRegRAX(8));
8157 t2 = newTemp(Ity_I64);
8158 assign(t2, binop(Iop_Sub64, getIReg64(R_RSP), mkU64(8)));
8159 putIReg64(R_RSP, mkexpr(t2));
8160 storeLE( mkexpr(t2), mkU64(guest_RIP_bbstart+delta));
8161 jmp_treg(Ijk_NoRedir,t1);
8162 dres.whatNext = Dis_StopHere;
8163 goto decode_success;
8164 }
8165 /* We don't know what it is. */
8166 goto decode_failure;
8167 /*NOTREACHED*/
sewardjdf0e0022005-01-25 15:48:43 +00008168 }
8169 }
8170
8171 /* Eat prefixes, summarising the result in pfx and sz, and rejecting
8172 as many invalid combinations as possible. */
8173 n_prefixes = 0;
8174 while (True) {
8175 if (n_prefixes > 5) goto decode_failure;
sewardj8c332e22005-01-28 01:36:56 +00008176 pre = getUChar(delta);
sewardjdf0e0022005-01-25 15:48:43 +00008177 switch (pre) {
8178 case 0x66: pfx |= PFX_66; break;
8179 case 0x67: pfx |= PFX_ASO; break;
8180 case 0xF2: pfx |= PFX_F2; break;
8181 case 0xF3: pfx |= PFX_F3; break;
8182 case 0xF0: pfx |= PFX_LOCK; break;
8183 case 0x2E: pfx |= PFX_CS; break;
8184 case 0x3E: pfx |= PFX_DS; break;
8185 case 0x26: pfx |= PFX_ES; break;
8186 case 0x64: pfx |= PFX_FS; break;
8187 case 0x65: pfx |= PFX_GS; break;
8188 case 0x36: pfx |= PFX_SS; break;
8189 case 0x40 ... 0x4F:
8190 pfx |= PFX_REX;
8191 if (pre & (1<<3)) pfx |= PFX_REXW;
8192 if (pre & (1<<2)) pfx |= PFX_REXR;
8193 if (pre & (1<<1)) pfx |= PFX_REXX;
8194 if (pre & (1<<0)) pfx |= PFX_REXB;
8195 break;
8196 default:
8197 goto not_a_prefix;
8198 }
8199 n_prefixes++;
8200 delta++;
8201 }
8202
8203 not_a_prefix:
sewardjdf0e0022005-01-25 15:48:43 +00008204
sewardj42561ef2005-11-04 14:18:31 +00008205 /* Dump invalid combinations */
sewardjdf0e0022005-01-25 15:48:43 +00008206 n = 0;
8207 if (pfx & PFX_F2) n++;
8208 if (pfx & PFX_F3) n++;
sewardj3ca55a12005-01-27 16:06:23 +00008209 if (n > 1)
8210 goto decode_failure; /* can't have both */
sewardjdf0e0022005-01-25 15:48:43 +00008211
8212 n = 0;
8213 if (pfx & PFX_CS) n++;
8214 if (pfx & PFX_DS) n++;
8215 if (pfx & PFX_ES) n++;
8216 if (pfx & PFX_FS) n++;
8217 if (pfx & PFX_GS) n++;
8218 if (pfx & PFX_SS) n++;
sewardj3ca55a12005-01-27 16:06:23 +00008219 if (n > 1)
8220 goto decode_failure; /* multiple seg overrides == illegal */
sewardjdf0e0022005-01-25 15:48:43 +00008221
sewardj42561ef2005-11-04 14:18:31 +00008222 if (pfx & PFX_GS)
8223 goto decode_failure; /* legal, but unsupported right now */
8224
sewardjdf0e0022005-01-25 15:48:43 +00008225 /* Set up sz. */
8226 sz = 4;
8227 if (pfx & PFX_66) sz = 2;
8228 if ((pfx & PFX_REX) && (pfx & PFX_REXW)) sz = 8;
8229
sewardj9ff93bc2005-03-23 11:25:12 +00008230 /* Kludge re LOCK prefixes. We assume here that all code generated
8231 by Vex is going to be run in a single-threaded context, in other
8232 words that concurrent executions of Vex-generated translations
8233 will not happen. That is certainly the case for how the
8234 Valgrind-3.0 code line uses Vex. Given that assumption, it
8235 seems safe to ignore LOCK prefixes since there will never be any
8236 other thread running at the same time as this one. However, at
8237 least emit a memory fence on the basis that it would at least be
8238 prudent to flush any memory transactions from this thread as far
8239 as possible down the memory hierarchy. */
8240 if (pfx & PFX_LOCK) {
8241 /* vex_printf("vex amd64->IR: ignoring LOCK prefix on: ");
8242 insn_verbose = True; */
8243 stmt( IRStmt_MFence() );
sewardjdf0e0022005-01-25 15:48:43 +00008244 }
8245
sewardja6b93d12005-02-17 09:28:28 +00008246
8247 /* ---------------------------------------------------- */
sewardj09717342005-05-05 21:34:02 +00008248 /* --- The SSE/SSE2 decoder. --- */
sewardja6b93d12005-02-17 09:28:28 +00008249 /* ---------------------------------------------------- */
8250
8251 /* What did I do to deserve SSE ? Perhaps I was really bad in a
8252 previous life? */
8253
sewardj09717342005-05-05 21:34:02 +00008254 /* Note, this doesn't handle SSE3 right now. All amd64s support
8255 SSE2 as a minimum so there is no point distinguishing SSE1 vs
8256 SSE2. */
8257
sewardja6b93d12005-02-17 09:28:28 +00008258 insn = (UChar*)&guest_code[delta];
8259
sewardjd20c8852005-01-20 20:04:07 +00008260//.. /* Treat fxsave specially. It should be doable even on an SSE0
8261//.. (Pentium-II class) CPU. Hence be prepared to handle it on
8262//.. any subarchitecture variant.
8263//.. */
8264//..
8265//.. /* 0F AE /0 = FXSAVE m512 -- write x87 and SSE state to memory */
8266//.. if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xAE
8267//.. && !epartIsReg(insn[2]) && gregOfRM(insn[2]) == 0) {
sewardj8c332e22005-01-28 01:36:56 +00008268//.. modrm = getUChar(delta+2);
sewardjd20c8852005-01-20 20:04:07 +00008269//.. vassert(sz == 4);
8270//.. vassert(!epartIsReg(modrm));
8271//..
8272//.. addr = disAMode ( &alen, sorb, delta+2, dis_buf );
8273//.. delta += 2+alen;
8274//..
8275//.. DIP("fxsave %s\n", dis_buf);
8276//..
8277//.. /* Uses dirty helper:
8278//.. void x86g_do_FXSAVE ( VexGuestX86State*, UInt ) */
8279//.. IRDirty* d = unsafeIRDirty_0_N (
8280//.. 0/*regparms*/,
8281//.. "x86g_dirtyhelper_FXSAVE",
8282//.. &x86g_dirtyhelper_FXSAVE,
8283//.. mkIRExprVec_1( mkexpr(addr) )
8284//.. );
8285//.. d->needsBBP = True;
8286//..
8287//.. /* declare we're writing memory */
8288//.. d->mFx = Ifx_Write;
8289//.. d->mAddr = mkexpr(addr);
8290//.. d->mSize = 512;
8291//..
8292//.. /* declare we're reading guest state */
8293//.. d->nFxState = 7;
8294//..
8295//.. d->fxState[0].fx = Ifx_Read;
8296//.. d->fxState[0].offset = OFFB_FTOP;
8297//.. d->fxState[0].size = sizeof(UInt);
8298//..
8299//.. d->fxState[1].fx = Ifx_Read;
8300//.. d->fxState[1].offset = OFFB_FPREGS;
8301//.. d->fxState[1].size = 8 * sizeof(ULong);
8302//..
8303//.. d->fxState[2].fx = Ifx_Read;
8304//.. d->fxState[2].offset = OFFB_FPTAGS;
8305//.. d->fxState[2].size = 8 * sizeof(UChar);
8306//..
8307//.. d->fxState[3].fx = Ifx_Read;
8308//.. d->fxState[3].offset = OFFB_FPROUND;
8309//.. d->fxState[3].size = sizeof(UInt);
8310//..
8311//.. d->fxState[4].fx = Ifx_Read;
8312//.. d->fxState[4].offset = OFFB_FC3210;
8313//.. d->fxState[4].size = sizeof(UInt);
8314//..
8315//.. d->fxState[5].fx = Ifx_Read;
8316//.. d->fxState[5].offset = OFFB_XMM0;
8317//.. d->fxState[5].size = 8 * sizeof(U128);
8318//..
8319//.. d->fxState[6].fx = Ifx_Read;
8320//.. d->fxState[6].offset = OFFB_SSEROUND;
8321//.. d->fxState[6].size = sizeof(UInt);
8322//..
8323//.. /* Be paranoid ... this assertion tries to ensure the 8 %xmm
8324//.. images are packed back-to-back. If not, the value of
8325//.. d->fxState[5].size is wrong. */
8326//.. vassert(16 == sizeof(U128));
8327//.. vassert(OFFB_XMM7 == (OFFB_XMM0 + 7 * 16));
8328//..
8329//.. stmt( IRStmt_Dirty(d) );
8330//..
8331//.. goto decode_success;
8332//.. }
8333//..
8334//.. /* ------ SSE decoder main ------ */
8335//..
8336//.. /* Skip parts of the decoder which don't apply given the stated
8337//.. guest subarchitecture. */
8338//.. if (subarch == VexSubArchX86_sse0)
8339//.. goto after_sse_decoders;
8340//..
8341//.. /* Otherwise we must be doing sse1 or sse2, so we can at least try
8342//.. for SSE1 here. */
sewardj432f8b62005-05-10 02:50:05 +00008343
8344 /* 0F 58 = ADDPS -- add 32Fx4 from R/M to R */
8345 if (haveNo66noF2noF3(pfx) && sz == 4
8346 && insn[0] == 0x0F && insn[1] == 0x58) {
8347 delta = dis_SSE_E_to_G_all( pfx, delta+2, "addps", Iop_Add32Fx4 );
8348 goto decode_success;
8349 }
sewardj8d965312005-02-25 02:48:47 +00008350
8351 /* F3 0F 58 = ADDSS -- add 32F0x4 from R/M to R */
8352 if (haveF3no66noF2(pfx) && sz == 4
8353 && insn[0] == 0x0F && insn[1] == 0x58) {
8354 delta = dis_SSE_E_to_G_lo32( pfx, delta+2, "addss", Iop_Add32F0x4 );
8355 goto decode_success;
8356 }
8357
sewardj3aba9eb2005-03-30 23:20:47 +00008358 /* 0F 55 = ANDNPS -- G = (not G) and E */
8359 if (haveNo66noF2noF3(pfx) && sz == 4
8360 && insn[0] == 0x0F && insn[1] == 0x55) {
8361 delta = dis_SSE_E_to_G_all_invG( pfx, delta+2, "andnps", Iop_AndV128 );
8362 goto decode_success;
8363 }
sewardj37d52572005-02-25 14:22:12 +00008364
8365 /* 0F 54 = ANDPS -- G = G and E */
8366 if (haveNo66noF2noF3(pfx) && sz == 4
8367 && insn[0] == 0x0F && insn[1] == 0x54) {
8368 delta = dis_SSE_E_to_G_all( pfx, delta+2, "andps", Iop_AndV128 );
8369 goto decode_success;
8370 }
8371
sewardj432f8b62005-05-10 02:50:05 +00008372 /* 0F C2 = CMPPS -- 32Fx4 comparison from R/M to R */
8373 if (haveNo66noF2noF3(pfx) && sz == 4
8374 && insn[0] == 0x0F && insn[1] == 0xC2) {
8375 delta = dis_SSEcmp_E_to_G( pfx, delta+2, "cmpps", True, 4 );
8376 goto decode_success;
8377 }
sewardj3aba9eb2005-03-30 23:20:47 +00008378
8379 /* F3 0F C2 = CMPSS -- 32F0x4 comparison from R/M to R */
8380 if (haveF3no66noF2(pfx) && sz == 4
8381 && insn[0] == 0x0F && insn[1] == 0xC2) {
8382 delta = dis_SSEcmp_E_to_G( pfx, delta+2, "cmpss", False, 4 );
8383 goto decode_success;
8384 }
sewardjc49ce232005-02-25 13:03:03 +00008385
8386 /* 0F 2F = COMISS -- 32F0x4 comparison G,E, and set ZCP */
8387 /* 0F 2E = UCOMISS -- 32F0x4 comparison G,E, and set ZCP */
8388 if (haveNo66noF2noF3(pfx) && sz == 4
8389 && insn[0] == 0x0F && (insn[1] == 0x2F || insn[1] == 0x2E)) {
8390 IRTemp argL = newTemp(Ity_F32);
8391 IRTemp argR = newTemp(Ity_F32);
8392 modrm = getUChar(delta+2);
8393 if (epartIsReg(modrm)) {
8394 assign( argR, getXMMRegLane32F( eregOfRexRM(pfx,modrm),
8395 0/*lowest lane*/ ) );
8396 delta += 2+1;
8397 DIP("%scomiss %s,%s\n", insn[1]==0x2E ? "u" : "",
8398 nameXMMReg(eregOfRexRM(pfx,modrm)),
8399 nameXMMReg(gregOfRexRM(pfx,modrm)) );
8400 } else {
8401 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8402 assign( argR, loadLE(Ity_F32, mkexpr(addr)) );
8403 delta += 2+alen;
8404 DIP("%scomiss %s,%s\n", insn[1]==0x2E ? "u" : "",
8405 dis_buf,
8406 nameXMMReg(gregOfRexRM(pfx,modrm)) );
8407 }
8408 assign( argL, getXMMRegLane32F( gregOfRexRM(pfx,modrm),
8409 0/*lowest lane*/ ) );
8410
8411 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(AMD64G_CC_OP_COPY) ));
8412 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
8413 stmt( IRStmt_Put(
8414 OFFB_CC_DEP1,
8415 binop( Iop_And64,
8416 unop( Iop_32Uto64,
8417 binop(Iop_CmpF64,
8418 unop(Iop_F32toF64,mkexpr(argL)),
8419 unop(Iop_F32toF64,mkexpr(argR)))),
8420 mkU64(0x45)
8421 )));
8422
8423 goto decode_success;
8424 }
8425
sewardj432f8b62005-05-10 02:50:05 +00008426 /* 0F 2A = CVTPI2PS -- convert 2 x I32 in mem/mmx to 2 x F32 in low
8427 half xmm */
8428 if (haveNo66noF2noF3(pfx) && sz == 4
8429 && insn[0] == 0x0F && insn[1] == 0x2A) {
8430 IRTemp arg64 = newTemp(Ity_I64);
8431 IRTemp rmode = newTemp(Ity_I32);
8432
8433 modrm = getUChar(delta+2);
8434 do_MMX_preamble();
8435 if (epartIsReg(modrm)) {
8436 assign( arg64, getMMXReg(eregLO3ofRM(modrm)) );
8437 delta += 2+1;
8438 DIP("cvtpi2ps %s,%s\n", nameMMXReg(eregLO3ofRM(modrm)),
8439 nameXMMReg(gregOfRexRM(pfx,modrm)));
8440 } else {
8441 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8442 assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
8443 delta += 2+alen;
8444 DIP("cvtpi2ps %s,%s\n", dis_buf,
8445 nameXMMReg(gregOfRexRM(pfx,modrm)) );
8446 }
8447
8448 assign( rmode, get_sse_roundingmode() );
8449
8450 putXMMRegLane32F(
8451 gregOfRexRM(pfx,modrm), 0,
8452 binop(Iop_F64toF32,
8453 mkexpr(rmode),
8454 unop(Iop_I32toF64,
8455 unop(Iop_64to32, mkexpr(arg64)) )) );
8456
8457 putXMMRegLane32F(
8458 gregOfRexRM(pfx,modrm), 1,
8459 binop(Iop_F64toF32,
8460 mkexpr(rmode),
8461 unop(Iop_I32toF64,
8462 unop(Iop_64HIto32, mkexpr(arg64)) )) );
8463
8464 goto decode_success;
8465 }
sewardj8d965312005-02-25 02:48:47 +00008466
8467 /* F3 0F 2A = CVTSI2SS
8468 -- sz==4: convert I32 in mem/ireg to F32 in low quarter xmm
8469 -- sz==8: convert I64 in mem/ireg to F32 in low quarter xmm */
8470 if (haveF3no66noF2(pfx) && (sz == 4 || sz == 8)
8471 && insn[0] == 0x0F && insn[1] == 0x2A) {
8472
8473 IRTemp rmode = newTemp(Ity_I32);
8474 assign( rmode, get_sse_roundingmode() );
8475 modrm = getUChar(delta+2);
8476
8477 if (sz == 4) {
8478 IRTemp arg32 = newTemp(Ity_I32);
8479 if (epartIsReg(modrm)) {
sewardj5b470602005-02-27 13:10:48 +00008480 assign( arg32, getIReg32(eregOfRexRM(pfx,modrm)) );
sewardj8d965312005-02-25 02:48:47 +00008481 delta += 2+1;
sewardj5b470602005-02-27 13:10:48 +00008482 DIP("cvtsi2ss %s,%s\n", nameIReg32(eregOfRexRM(pfx,modrm)),
sewardj8d965312005-02-25 02:48:47 +00008483 nameXMMReg(gregOfRexRM(pfx,modrm)));
8484 } else {
sewardj8d965312005-02-25 02:48:47 +00008485 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8486 assign( arg32, loadLE(Ity_I32, mkexpr(addr)) );
8487 delta += 2+alen;
8488 DIP("cvtsi2ss %s,%s\n", dis_buf,
8489 nameXMMReg(gregOfRexRM(pfx,modrm)) );
8490 }
8491 putXMMRegLane32F(
8492 gregOfRexRM(pfx,modrm), 0,
8493 binop(Iop_F64toF32,
8494 mkexpr(rmode),
8495 unop(Iop_I32toF64, mkexpr(arg32)) ) );
8496 } else {
8497 /* sz == 8 */
8498 IRTemp arg64 = newTemp(Ity_I64);
8499 if (epartIsReg(modrm)) {
sewardj5b470602005-02-27 13:10:48 +00008500 assign( arg64, getIReg64(eregOfRexRM(pfx,modrm)) );
sewardj8d965312005-02-25 02:48:47 +00008501 delta += 2+1;
sewardj5b470602005-02-27 13:10:48 +00008502 DIP("cvtsi2ssq %s,%s\n", nameIReg64(eregOfRexRM(pfx,modrm)),
sewardj8d965312005-02-25 02:48:47 +00008503 nameXMMReg(gregOfRexRM(pfx,modrm)));
8504 } else {
sewardj82c9f2f2005-03-02 16:05:13 +00008505 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8506 assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
8507 delta += 2+alen;
8508 DIP("cvtsi2ssq %s,%s\n", dis_buf,
8509 nameXMMReg(gregOfRexRM(pfx,modrm)) );
sewardj8d965312005-02-25 02:48:47 +00008510 }
8511 putXMMRegLane32F(
8512 gregOfRexRM(pfx,modrm), 0,
8513 binop(Iop_F64toF32,
8514 mkexpr(rmode),
8515 binop(Iop_I64toF64, mkexpr(rmode), mkexpr(arg64)) ) );
8516 }
8517
8518 goto decode_success;
8519 }
8520
sewardj432f8b62005-05-10 02:50:05 +00008521 /* 0F 2D = CVTPS2PI -- convert 2 x F32 in mem/low half xmm to 2 x
8522 I32 in mmx, according to prevailing SSE rounding mode */
sewardja7ba8c42005-05-10 20:08:34 +00008523 /* 0F 2C = CVTTPS2PI -- convert 2 x F32 in mem/low half xmm to 2 x
8524 I32 in mmx, rounding towards zero */
sewardj432f8b62005-05-10 02:50:05 +00008525 if (haveNo66noF2noF3(pfx) && sz == 4
sewardja7ba8c42005-05-10 20:08:34 +00008526 && insn[0] == 0x0F && (insn[1] == 0x2D || insn[1] == 0x2C)) {
sewardj432f8b62005-05-10 02:50:05 +00008527 IRTemp dst64 = newTemp(Ity_I64);
8528 IRTemp rmode = newTemp(Ity_I32);
8529 IRTemp f32lo = newTemp(Ity_F32);
8530 IRTemp f32hi = newTemp(Ity_F32);
8531 Bool r2zero = toBool(insn[1] == 0x2C);
8532
8533 do_MMX_preamble();
8534 modrm = getUChar(delta+2);
8535
8536 if (epartIsReg(modrm)) {
8537 delta += 2+1;
8538 assign(f32lo, getXMMRegLane32F(eregOfRexRM(pfx,modrm), 0));
8539 assign(f32hi, getXMMRegLane32F(eregOfRexRM(pfx,modrm), 1));
8540 DIP("cvt%sps2pi %s,%s\n", r2zero ? "t" : "",
8541 nameXMMReg(eregOfRexRM(pfx,modrm)),
8542 nameMMXReg(gregLO3ofRM(modrm)));
8543 } else {
8544 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8545 assign(f32lo, loadLE(Ity_F32, mkexpr(addr)));
8546 assign(f32hi, loadLE(Ity_F32, binop( Iop_Add64,
8547 mkexpr(addr),
8548 mkU64(4) )));
8549 delta += 2+alen;
8550 DIP("cvt%sps2pi %s,%s\n", r2zero ? "t" : "",
8551 dis_buf,
8552 nameMMXReg(gregLO3ofRM(modrm)));
8553 }
8554
8555 if (r2zero) {
8556 assign(rmode, mkU32((UInt)Irrm_ZERO) );
8557 } else {
8558 assign( rmode, get_sse_roundingmode() );
8559 }
8560
8561 assign(
8562 dst64,
8563 binop( Iop_32HLto64,
8564 binop( Iop_F64toI32,
8565 mkexpr(rmode),
8566 unop( Iop_F32toF64, mkexpr(f32hi) ) ),
8567 binop( Iop_F64toI32,
8568 mkexpr(rmode),
8569 unop( Iop_F32toF64, mkexpr(f32lo) ) )
8570 )
8571 );
8572
8573 putMMXReg(gregLO3ofRM(modrm), mkexpr(dst64));
8574 goto decode_success;
8575 }
8576
8577 /* F3 0F 2D = CVTSS2SI
8578 when sz==4 -- convert F32 in mem/low quarter xmm to I32 in ireg,
8579 according to prevailing SSE rounding mode
8580 when sz==8 -- convert F32 in mem/low quarter xmm to I64 in ireg,
8581 according to prevailing SSE rounding mode
8582 */
sewardj82c9f2f2005-03-02 16:05:13 +00008583 /* F3 0F 2C = CVTTSS2SI
8584 when sz==4 -- convert F32 in mem/low quarter xmm to I32 in ireg,
8585 truncating towards zero
8586 when sz==8 -- convert F32 in mem/low quarter xmm to I64 in ireg,
8587 truncating towards zero
8588 */
8589 if (haveF3no66noF2(pfx)
8590 && insn[0] == 0x0F
sewardj432f8b62005-05-10 02:50:05 +00008591 && (insn[1] == 0x2D || insn[1] == 0x2C)) {
sewardj82c9f2f2005-03-02 16:05:13 +00008592 IRTemp rmode = newTemp(Ity_I32);
8593 IRTemp f32lo = newTemp(Ity_F32);
8594 Bool r2zero = toBool(insn[1] == 0x2C);
8595 vassert(sz == 4 || sz == 8);
8596
8597 modrm = getUChar(delta+2);
8598 if (epartIsReg(modrm)) {
8599 delta += 2+1;
8600 assign(f32lo, getXMMRegLane32F(eregOfRexRM(pfx,modrm), 0));
8601 DIP("cvt%sss2si %s,%s\n", r2zero ? "t" : "",
8602 nameXMMReg(eregOfRexRM(pfx,modrm)),
8603 nameIReg(sz, gregOfRexRM(pfx,modrm), False));
8604 } else {
8605 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8606 assign(f32lo, loadLE(Ity_F32, mkexpr(addr)));
8607 delta += 2+alen;
8608 DIP("cvt%sss2si %s,%s\n", r2zero ? "t" : "",
8609 dis_buf,
8610 nameIReg(sz, gregOfRexRM(pfx,modrm), False));
8611 }
8612
8613 if (r2zero) {
8614 assign( rmode, mkU32((UInt)Irrm_ZERO) );
8615 } else {
8616 assign( rmode, get_sse_roundingmode() );
8617 }
8618
8619 if (sz == 4) {
8620 putIReg32( gregOfRexRM(pfx,modrm),
8621 binop( Iop_F64toI32,
8622 mkexpr(rmode),
8623 unop(Iop_F32toF64, mkexpr(f32lo))) );
8624 } else {
8625 putIReg64( gregOfRexRM(pfx,modrm),
8626 binop( Iop_F64toI64,
8627 mkexpr(rmode),
8628 unop(Iop_F32toF64, mkexpr(f32lo))) );
8629 }
8630
8631 goto decode_success;
8632 }
8633
sewardj432f8b62005-05-10 02:50:05 +00008634 /* 0F 5E = DIVPS -- div 32Fx4 from R/M to R */
8635 if (haveNo66noF2noF3(pfx) && sz == 4
8636 && insn[0] == 0x0F && insn[1] == 0x5E) {
8637 delta = dis_SSE_E_to_G_all( pfx, delta+2, "divps", Iop_Div32Fx4 );
8638 goto decode_success;
8639 }
sewardjc49ce232005-02-25 13:03:03 +00008640
8641 /* F3 0F 5E = DIVSS -- div 32F0x4 from R/M to R */
8642 if (haveF3no66noF2(pfx) && sz == 4
8643 && insn[0] == 0x0F && insn[1] == 0x5E) {
8644 delta = dis_SSE_E_to_G_lo32( pfx, delta+2, "divss", Iop_Div32F0x4 );
8645 goto decode_success;
8646 }
8647
sewardjbcbb9de2005-03-27 02:22:32 +00008648 /* 0F AE /2 = LDMXCSR m32 -- load %mxcsr */
8649 if (insn[0] == 0x0F && insn[1] == 0xAE
8650 && haveNo66noF2noF3(pfx)
8651 && !epartIsReg(insn[2]) && gregLO3ofRM(insn[2]) == 2) {
8652
8653 IRTemp t64 = newTemp(Ity_I64);
8654 IRTemp ew = newTemp(Ity_I32);
8655
8656 vassert(sz == 4);
8657 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8658 delta += 2+alen;
8659 DIP("ldmxcsr %s\n", dis_buf);
8660
8661 /* The only thing we observe in %mxcsr is the rounding mode.
8662 Therefore, pass the 32-bit value (SSE native-format control
8663 word) to a clean helper, getting back a 64-bit value, the
8664 lower half of which is the SSEROUND value to store, and the
8665 upper half of which is the emulation-warning token which may
8666 be generated.
8667 */
8668 /* ULong amd64h_check_ldmxcsr ( ULong ); */
8669 assign( t64, mkIRExprCCall(
8670 Ity_I64, 0/*regparms*/,
8671 "amd64g_check_ldmxcsr",
8672 &amd64g_check_ldmxcsr,
8673 mkIRExprVec_1(
8674 unop(Iop_32Uto64,
8675 loadLE(Ity_I32, mkexpr(addr))
8676 )
8677 )
8678 )
8679 );
8680
8681 put_sse_roundingmode( unop(Iop_64to32, mkexpr(t64)) );
8682 assign( ew, unop(Iop_64HIto32, mkexpr(t64) ) );
8683 put_emwarn( mkexpr(ew) );
8684 /* Finally, if an emulation warning was reported, side-exit to
8685 the next insn, reporting the warning, so that Valgrind's
8686 dispatcher sees the warning. */
8687 stmt(
8688 IRStmt_Exit(
8689 binop(Iop_CmpNE64, unop(Iop_32Uto64,mkexpr(ew)), mkU64(0)),
8690 Ijk_EmWarn,
sewardj9e6491a2005-07-02 19:24:10 +00008691 IRConst_U64(guest_RIP_bbstart+delta)
sewardjbcbb9de2005-03-27 02:22:32 +00008692 )
8693 );
8694 goto decode_success;
8695 }
8696
sewardj432f8b62005-05-10 02:50:05 +00008697 /* 0F 5F = MAXPS -- max 32Fx4 from R/M to R */
8698 if (haveNo66noF2noF3(pfx) && sz == 4
8699 && insn[0] == 0x0F && insn[1] == 0x5F) {
8700 delta = dis_SSE_E_to_G_all( pfx, delta+2, "maxps", Iop_Max32Fx4 );
8701 goto decode_success;
8702 }
sewardj37d52572005-02-25 14:22:12 +00008703
8704 /* F3 0F 5F = MAXSS -- max 32F0x4 from R/M to R */
8705 if (haveF3no66noF2(pfx) && sz == 4
8706 && insn[0] == 0x0F && insn[1] == 0x5F) {
8707 delta = dis_SSE_E_to_G_lo32( pfx, delta+2, "maxss", Iop_Max32F0x4 );
8708 goto decode_success;
8709 }
8710
sewardj432f8b62005-05-10 02:50:05 +00008711 /* 0F 5D = MINPS -- min 32Fx4 from R/M to R */
8712 if (haveNo66noF2noF3(pfx) && sz == 4
8713 && insn[0] == 0x0F && insn[1] == 0x5D) {
8714 delta = dis_SSE_E_to_G_all( pfx, delta+2, "minps", Iop_Min32Fx4 );
8715 goto decode_success;
8716 }
sewardj37d52572005-02-25 14:22:12 +00008717
8718 /* F3 0F 5D = MINSS -- min 32F0x4 from R/M to R */
8719 if (haveF3no66noF2(pfx) && sz == 4
8720 && insn[0] == 0x0F && insn[1] == 0x5D) {
8721 delta = dis_SSE_E_to_G_lo32( pfx, delta+2, "minss", Iop_Min32F0x4 );
8722 goto decode_success;
8723 }
sewardj8d965312005-02-25 02:48:47 +00008724
8725 /* 0F 28 = MOVAPS -- move from E (mem or xmm) to G (xmm). */
8726 /* 0F 10 = MOVUPS -- move from E (mem or xmm) to G (xmm). */
8727 if (haveNo66noF2noF3(pfx) && sz == 4
8728 && insn[0] == 0x0F && (insn[1] == 0x28 || insn[1] == 0x10)) {
8729 modrm = getUChar(delta+2);
8730 if (epartIsReg(modrm)) {
8731 putXMMReg( gregOfRexRM(pfx,modrm),
8732 getXMMReg( eregOfRexRM(pfx,modrm) ));
8733 DIP("mov[ua]ps %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
8734 nameXMMReg(gregOfRexRM(pfx,modrm)));
8735 delta += 2+1;
8736 } else {
8737 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8738 putXMMReg( gregOfRexRM(pfx,modrm),
8739 loadLE(Ity_V128, mkexpr(addr)) );
8740 DIP("mov[ua]ps %s,%s\n", dis_buf,
8741 nameXMMReg(gregOfRexRM(pfx,modrm)));
8742 delta += 2+alen;
8743 }
8744 goto decode_success;
8745 }
sewardj1001dc42005-02-21 08:25:55 +00008746
8747 /* 0F 29 = MOVAPS -- move from G (xmm) to E (mem or xmm). */
sewardj446d2672005-06-10 11:04:52 +00008748 /* 0F 11 = MOVUPS -- move from G (xmm) to E (mem or xmm). */
sewardj8d965312005-02-25 02:48:47 +00008749 if (haveNo66noF2noF3(pfx) && sz == 4
sewardj446d2672005-06-10 11:04:52 +00008750 && insn[0] == 0x0F && (insn[1] == 0x29 || insn[1] == 0x11)) {
sewardj1001dc42005-02-21 08:25:55 +00008751 modrm = getUChar(delta+2);
8752 if (epartIsReg(modrm)) {
8753 /* fall through; awaiting test case */
8754 } else {
8755 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8756 storeLE( mkexpr(addr), getXMMReg(gregOfRexRM(pfx,modrm)) );
sewardj446d2672005-06-10 11:04:52 +00008757 DIP("mov[ua]ps %s,%s\n", nameXMMReg(gregOfRexRM(pfx,modrm)),
8758 dis_buf );
sewardj1001dc42005-02-21 08:25:55 +00008759 delta += 2+alen;
8760 goto decode_success;
8761 }
8762 }
8763
sewardj432f8b62005-05-10 02:50:05 +00008764 /* 0F 16 = MOVHPS -- move from mem to high half of XMM. */
8765 /* 0F 16 = MOVLHPS -- move from lo half to hi half of XMM. */
8766 if (haveNo66noF2noF3(pfx) && sz == 4
8767 && insn[0] == 0x0F && insn[1] == 0x16) {
8768 modrm = getUChar(delta+2);
8769 if (epartIsReg(modrm)) {
8770 delta += 2+1;
8771 putXMMRegLane64( gregOfRexRM(pfx,modrm), 1/*upper lane*/,
8772 getXMMRegLane64( eregOfRexRM(pfx,modrm), 0 ) );
8773 DIP("movhps %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
8774 nameXMMReg(gregOfRexRM(pfx,modrm)));
8775 } else {
8776 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8777 delta += 2+alen;
8778 putXMMRegLane64( gregOfRexRM(pfx,modrm), 1/*upper lane*/,
8779 loadLE(Ity_I64, mkexpr(addr)) );
8780 DIP("movhps %s,%s\n", dis_buf,
8781 nameXMMReg( gregOfRexRM(pfx,modrm) ));
8782 }
8783 goto decode_success;
8784 }
8785
8786 /* 0F 17 = MOVHPS -- move from high half of XMM to mem. */
8787 if (haveNo66noF2noF3(pfx) && sz == 4
8788 && insn[0] == 0x0F && insn[1] == 0x17) {
8789 if (!epartIsReg(insn[2])) {
8790 delta += 2;
8791 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
8792 delta += alen;
8793 storeLE( mkexpr(addr),
8794 getXMMRegLane64( gregOfRexRM(pfx,insn[2]),
8795 1/*upper lane*/ ) );
8796 DIP("movhps %s,%s\n", nameXMMReg( gregOfRexRM(pfx,insn[2]) ),
8797 dis_buf);
8798 goto decode_success;
8799 }
8800 /* else fall through */
8801 }
8802
8803 /* 0F 12 = MOVLPS -- move from mem to low half of XMM. */
8804 /* OF 12 = MOVHLPS -- from from hi half to lo half of XMM. */
8805 if (haveNo66noF2noF3(pfx) && sz == 4
8806 && insn[0] == 0x0F && insn[1] == 0x12) {
8807 modrm = getUChar(delta+2);
8808 if (epartIsReg(modrm)) {
8809 delta += 2+1;
8810 putXMMRegLane64( gregOfRexRM(pfx,modrm),
8811 0/*lower lane*/,
8812 getXMMRegLane64( eregOfRexRM(pfx,modrm), 1 ));
8813 DIP("movhlps %s, %s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
8814 nameXMMReg(gregOfRexRM(pfx,modrm)));
8815 } else {
8816 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8817 delta += 2+alen;
8818 putXMMRegLane64( gregOfRexRM(pfx,modrm), 0/*lower lane*/,
8819 loadLE(Ity_I64, mkexpr(addr)) );
8820 DIP("movlps %s, %s\n",
8821 dis_buf, nameXMMReg( gregOfRexRM(pfx,modrm) ));
8822 }
8823 goto decode_success;
8824 }
8825
8826 /* 0F 13 = MOVLPS -- move from low half of XMM to mem. */
8827 if (haveNo66noF2noF3(pfx) && sz == 4
8828 && insn[0] == 0x0F && insn[1] == 0x13) {
8829 if (!epartIsReg(insn[2])) {
8830 delta += 2;
8831 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
8832 delta += alen;
8833 storeLE( mkexpr(addr),
8834 getXMMRegLane64( gregOfRexRM(pfx,insn[2]),
8835 0/*lower lane*/ ) );
8836 DIP("movlps %s, %s\n", nameXMMReg( gregOfRexRM(pfx,insn[2]) ),
8837 dis_buf);
8838 goto decode_success;
8839 }
8840 /* else fall through */
8841 }
8842
sewardja7ba8c42005-05-10 20:08:34 +00008843 /* 0F 50 = MOVMSKPS - move 4 sign bits from 4 x F32 in xmm(E)
8844 to 4 lowest bits of ireg(G) */
sewardjae84d782006-04-13 22:06:35 +00008845 if (haveNo66noF2noF3(pfx) && (sz == 4 || sz == 8)
sewardja7ba8c42005-05-10 20:08:34 +00008846 && insn[0] == 0x0F && insn[1] == 0x50) {
sewardjae84d782006-04-13 22:06:35 +00008847 /* sz == 8 is a kludge to handle insns with REX.W redundantly
8848 set to 1, which has been known to happen:
8849 4c 0f 50 d9 rex64X movmskps %xmm1,%r11d
8850 */
sewardja7ba8c42005-05-10 20:08:34 +00008851 modrm = getUChar(delta+2);
8852 if (epartIsReg(modrm)) {
8853 Int src;
8854 t0 = newTemp(Ity_I32);
8855 t1 = newTemp(Ity_I32);
8856 t2 = newTemp(Ity_I32);
8857 t3 = newTemp(Ity_I32);
8858 delta += 2+1;
8859 src = eregOfRexRM(pfx,modrm);
8860 assign( t0, binop( Iop_And32,
8861 binop(Iop_Shr32, getXMMRegLane32(src,0), mkU8(31)),
8862 mkU32(1) ));
8863 assign( t1, binop( Iop_And32,
8864 binop(Iop_Shr32, getXMMRegLane32(src,1), mkU8(30)),
8865 mkU32(2) ));
8866 assign( t2, binop( Iop_And32,
8867 binop(Iop_Shr32, getXMMRegLane32(src,2), mkU8(29)),
8868 mkU32(4) ));
8869 assign( t3, binop( Iop_And32,
8870 binop(Iop_Shr32, getXMMRegLane32(src,3), mkU8(28)),
8871 mkU32(8) ));
8872 putIReg32( gregOfRexRM(pfx,modrm),
8873 binop(Iop_Or32,
8874 binop(Iop_Or32, mkexpr(t0), mkexpr(t1)),
8875 binop(Iop_Or32, mkexpr(t2), mkexpr(t3))
8876 )
8877 );
8878 DIP("movmskps %s,%s\n", nameXMMReg(src),
8879 nameIReg32(gregOfRexRM(pfx,modrm)));
8880 goto decode_success;
8881 }
8882 /* else fall through */
8883 }
8884
sewardj612be432005-05-11 02:55:54 +00008885 /* 66 0F 2B = MOVNTPD -- for us, just a plain SSE store. */
sewardja7ba8c42005-05-10 20:08:34 +00008886 /* 0F 2B = MOVNTPS -- for us, just a plain SSE store. */
sewardj612be432005-05-11 02:55:54 +00008887 if ( ( (haveNo66noF2noF3(pfx) && sz == 4)
8888 || (have66noF2noF3(pfx) && sz == 2)
8889 )
8890 && insn[0] == 0x0F && insn[1] == 0x2B) {
sewardja7ba8c42005-05-10 20:08:34 +00008891 modrm = getUChar(delta+2);
8892 if (!epartIsReg(modrm)) {
8893 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8894 storeLE( mkexpr(addr), getXMMReg(gregOfRexRM(pfx,modrm)) );
sewardj612be432005-05-11 02:55:54 +00008895 DIP("movntp%s %s,%s\n", sz==2 ? "d" : "s",
8896 dis_buf,
8897 nameXMMReg(gregOfRexRM(pfx,modrm)));
sewardja7ba8c42005-05-10 20:08:34 +00008898 delta += 2+alen;
8899 goto decode_success;
8900 }
8901 /* else fall through */
8902 }
8903
8904 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8905 /* 0F E7 = MOVNTQ -- for us, just a plain MMX store. Note, the
8906 Intel manual does not say anything about the usual business of
8907 the FP reg tags getting trashed whenever an MMX insn happens.
8908 So we just leave them alone.
8909 */
8910 if (haveNo66noF2noF3(pfx) && sz == 4
8911 && insn[0] == 0x0F && insn[1] == 0xE7) {
8912 modrm = getUChar(delta+2);
8913 if (!epartIsReg(modrm)) {
8914 /* do_MMX_preamble(); Intel docs don't specify this */
8915 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8916 storeLE( mkexpr(addr), getMMXReg(gregLO3ofRM(modrm)) );
8917 DIP("movntq %s,%s\n", dis_buf,
8918 nameMMXReg(gregLO3ofRM(modrm)));
8919 delta += 2+alen;
8920 goto decode_success;
8921 }
8922 /* else fall through */
8923 }
sewardj8d965312005-02-25 02:48:47 +00008924
8925 /* F3 0F 10 = MOVSS -- move 32 bits from E (mem or lo 1/4 xmm) to G
8926 (lo 1/4 xmm). If E is mem, upper 3/4 of G is zeroed out. */
8927 if (haveF3no66noF2(pfx) && sz == 4
8928 && insn[0] == 0x0F && insn[1] == 0x10) {
8929 modrm = getUChar(delta+2);
8930 if (epartIsReg(modrm)) {
8931 putXMMRegLane32( gregOfRexRM(pfx,modrm), 0,
8932 getXMMRegLane32( eregOfRexRM(pfx,modrm), 0 ));
8933 DIP("movss %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
8934 nameXMMReg(gregOfRexRM(pfx,modrm)));
8935 delta += 2+1;
8936 } else {
8937 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8938 putXMMReg( gregOfRexRM(pfx,modrm), mkV128(0) );
8939 putXMMRegLane32( gregOfRexRM(pfx,modrm), 0,
8940 loadLE(Ity_I32, mkexpr(addr)) );
8941 DIP("movss %s,%s\n", dis_buf,
8942 nameXMMReg(gregOfRexRM(pfx,modrm)));
8943 delta += 2+alen;
8944 }
8945 goto decode_success;
8946 }
8947
8948 /* F3 0F 11 = MOVSS -- move 32 bits from G (lo 1/4 xmm) to E (mem
8949 or lo 1/4 xmm). */
8950 if (haveF3no66noF2(pfx) && sz == 4
8951 && insn[0] == 0x0F && insn[1] == 0x11) {
8952 modrm = getUChar(delta+2);
8953 if (epartIsReg(modrm)) {
8954 /* fall through, we don't yet have a test case */
8955 } else {
8956 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
8957 storeLE( mkexpr(addr),
8958 getXMMRegLane32(gregOfRexRM(pfx,modrm), 0) );
8959 DIP("movss %s,%s\n", nameXMMReg(gregOfRexRM(pfx,modrm)),
8960 dis_buf);
8961 delta += 2+alen;
8962 goto decode_success;
8963 }
8964 }
8965
sewardj432f8b62005-05-10 02:50:05 +00008966 /* 0F 59 = MULPS -- mul 32Fx4 from R/M to R */
8967 if (haveNo66noF2noF3(pfx) && sz == 4
8968 && insn[0] == 0x0F && insn[1] == 0x59) {
8969 delta = dis_SSE_E_to_G_all( pfx, delta+2, "mulps", Iop_Mul32Fx4 );
8970 goto decode_success;
8971 }
sewardj8d965312005-02-25 02:48:47 +00008972
8973 /* F3 0F 59 = MULSS -- mul 32F0x4 from R/M to R */
8974 if (haveF3no66noF2(pfx) && sz == 4
8975 && insn[0] == 0x0F && insn[1] == 0x59) {
8976 delta = dis_SSE_E_to_G_lo32( pfx, delta+2, "mulss", Iop_Mul32F0x4 );
8977 goto decode_success;
8978 }
8979
sewardj3aba9eb2005-03-30 23:20:47 +00008980 /* 0F 56 = ORPS -- G = G and E */
8981 if (haveNo66noF2noF3(pfx) && sz == 4
8982 && insn[0] == 0x0F && insn[1] == 0x56) {
8983 delta = dis_SSE_E_to_G_all( pfx, delta+2, "orps", Iop_OrV128 );
8984 goto decode_success;
8985 }
8986
sewardja7ba8c42005-05-10 20:08:34 +00008987 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8988 /* 0F E0 = PAVGB -- 8x8 unsigned Packed Average, with rounding */
8989 if (haveNo66noF2noF3(pfx) && sz == 4
8990 && insn[0] == 0x0F && insn[1] == 0xE0) {
8991 do_MMX_preamble();
8992 delta = dis_MMXop_regmem_to_reg (
8993 pfx, delta+2, insn[1], "pavgb", False );
8994 goto decode_success;
8995 }
8996
8997 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
8998 /* 0F E3 = PAVGW -- 16x4 unsigned Packed Average, with rounding */
8999 if (haveNo66noF2noF3(pfx) && sz == 4
9000 && insn[0] == 0x0F && insn[1] == 0xE3) {
9001 do_MMX_preamble();
9002 delta = dis_MMXop_regmem_to_reg (
9003 pfx, delta+2, insn[1], "pavgw", False );
9004 goto decode_success;
9005 }
9006
9007 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9008 /* 0F C5 = PEXTRW -- extract 16-bit field from mmx(E) and put
9009 zero-extend of it in ireg(G). */
9010 if (haveNo66noF2noF3(pfx) && sz == 4
9011 && insn[0] == 0x0F && insn[1] == 0xC5) {
9012 modrm = insn[2];
9013 if (epartIsReg(modrm)) {
9014 IRTemp sV = newTemp(Ity_I64);
9015 t5 = newTemp(Ity_I16);
9016 do_MMX_preamble();
9017 assign(sV, getMMXReg(eregLO3ofRM(modrm)));
9018 breakup64to16s( sV, &t3, &t2, &t1, &t0 );
9019 switch (insn[3] & 3) {
9020 case 0: assign(t5, mkexpr(t0)); break;
9021 case 1: assign(t5, mkexpr(t1)); break;
9022 case 2: assign(t5, mkexpr(t2)); break;
9023 case 3: assign(t5, mkexpr(t3)); break;
9024 default: vassert(0);
9025 }
9026 putIReg32(gregOfRexRM(pfx,modrm), unop(Iop_16Uto32, mkexpr(t5)));
9027 DIP("pextrw $%d,%s,%s\n",
9028 (Int)insn[3], nameMMXReg(eregLO3ofRM(modrm)),
9029 nameIReg32(gregOfRexRM(pfx,modrm)));
9030 delta += 4;
9031 goto decode_success;
9032 }
9033 /* else fall through */
9034 /* note, for anyone filling in the mem case: this insn has one
9035 byte after the amode and therefore you must pass 1 as the
9036 last arg to disAMode */
9037 }
9038
9039 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9040 /* 0F C4 = PINSRW -- get 16 bits from E(mem or low half ireg) and
9041 put it into the specified lane of mmx(G). */
9042 if (haveNo66noF2noF3(pfx) && sz == 4
9043 && insn[0] == 0x0F && insn[1] == 0xC4) {
9044 /* Use t0 .. t3 to hold the 4 original 16-bit lanes of the
9045 mmx reg. t4 is the new lane value. t5 is the original
9046 mmx value. t6 is the new mmx value. */
9047 Int lane;
9048 t4 = newTemp(Ity_I16);
9049 t5 = newTemp(Ity_I64);
9050 t6 = newTemp(Ity_I64);
9051 modrm = insn[2];
9052 do_MMX_preamble();
9053
9054 assign(t5, getMMXReg(gregLO3ofRM(modrm)));
9055 breakup64to16s( t5, &t3, &t2, &t1, &t0 );
9056
9057 if (epartIsReg(modrm)) {
9058 assign(t4, getIReg16(eregOfRexRM(pfx,modrm)));
9059 delta += 3+1;
9060 lane = insn[3+1-1];
9061 DIP("pinsrw $%d,%s,%s\n", (Int)lane,
9062 nameIReg16(eregOfRexRM(pfx,modrm)),
9063 nameMMXReg(gregLO3ofRM(modrm)));
9064 } else {
9065 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 1 );
9066 delta += 3+alen;
9067 lane = insn[3+alen-1];
9068 assign(t4, loadLE(Ity_I16, mkexpr(addr)));
9069 DIP("pinsrw $%d,%s,%s\n", (Int)lane,
9070 dis_buf,
9071 nameMMXReg(gregLO3ofRM(modrm)));
9072 }
9073
9074 switch (lane & 3) {
9075 case 0: assign(t6, mk64from16s(t3,t2,t1,t4)); break;
9076 case 1: assign(t6, mk64from16s(t3,t2,t4,t0)); break;
9077 case 2: assign(t6, mk64from16s(t3,t4,t1,t0)); break;
9078 case 3: assign(t6, mk64from16s(t4,t2,t1,t0)); break;
9079 default: vassert(0);
9080 }
9081 putMMXReg(gregLO3ofRM(modrm), mkexpr(t6));
9082 goto decode_success;
9083 }
9084
9085 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9086 /* 0F EE = PMAXSW -- 16x4 signed max */
9087 if (haveNo66noF2noF3(pfx) && sz == 4
9088 && insn[0] == 0x0F && insn[1] == 0xEE) {
9089 do_MMX_preamble();
9090 delta = dis_MMXop_regmem_to_reg (
9091 pfx, delta+2, insn[1], "pmaxsw", False );
9092 goto decode_success;
9093 }
9094
9095 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9096 /* 0F DE = PMAXUB -- 8x8 unsigned max */
9097 if (haveNo66noF2noF3(pfx) && sz == 4
9098 && insn[0] == 0x0F && insn[1] == 0xDE) {
9099 do_MMX_preamble();
9100 delta = dis_MMXop_regmem_to_reg (
9101 pfx, delta+2, insn[1], "pmaxub", False );
9102 goto decode_success;
9103 }
9104
9105 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9106 /* 0F EA = PMINSW -- 16x4 signed min */
9107 if (haveNo66noF2noF3(pfx) && sz == 4
9108 && insn[0] == 0x0F && insn[1] == 0xEA) {
9109 do_MMX_preamble();
9110 delta = dis_MMXop_regmem_to_reg (
9111 pfx, delta+2, insn[1], "pminsw", False );
9112 goto decode_success;
9113 }
9114
9115 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9116 /* 0F DA = PMINUB -- 8x8 unsigned min */
9117 if (haveNo66noF2noF3(pfx) && sz == 4
9118 && insn[0] == 0x0F && insn[1] == 0xDA) {
9119 do_MMX_preamble();
9120 delta = dis_MMXop_regmem_to_reg (
9121 pfx, delta+2, insn[1], "pminub", False );
9122 goto decode_success;
9123 }
9124
9125 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9126 /* 0F D7 = PMOVMSKB -- extract sign bits from each of 8 lanes in
9127 mmx(G), turn them into a byte, and put zero-extend of it in
9128 ireg(G). */
9129 if (haveNo66noF2noF3(pfx) && sz == 4
9130 && insn[0] == 0x0F && insn[1] == 0xD7) {
9131 modrm = insn[2];
9132 if (epartIsReg(modrm)) {
9133 do_MMX_preamble();
9134 t0 = newTemp(Ity_I64);
9135 t1 = newTemp(Ity_I64);
9136 assign(t0, getMMXReg(eregLO3ofRM(modrm)));
9137 assign(t1, mkIRExprCCall(
9138 Ity_I64, 0/*regparms*/,
9139 "amd64g_calculate_mmx_pmovmskb",
9140 &amd64g_calculate_mmx_pmovmskb,
9141 mkIRExprVec_1(mkexpr(t0))));
9142 putIReg32(gregOfRexRM(pfx,modrm), unop(Iop_64to32,mkexpr(t1)));
9143 DIP("pmovmskb %s,%s\n", nameMMXReg(eregLO3ofRM(modrm)),
9144 nameIReg32(gregOfRexRM(pfx,modrm)));
9145 delta += 3;
9146 goto decode_success;
9147 }
9148 /* else fall through */
9149 }
9150
9151 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9152 /* 0F E4 = PMULUH -- 16x4 hi-half of unsigned widening multiply */
9153 if (haveNo66noF2noF3(pfx) && sz == 4
9154 && insn[0] == 0x0F && insn[1] == 0xE4) {
9155 do_MMX_preamble();
9156 delta = dis_MMXop_regmem_to_reg (
9157 pfx, delta+2, insn[1], "pmuluh", False );
9158 goto decode_success;
9159 }
sewardja6b93d12005-02-17 09:28:28 +00009160
9161 /* 0F 18 /0 = PREFETCHNTA -- prefetch into caches, */
9162 /* 0F 18 /1 = PREFETCH0 -- with various different hints */
9163 /* 0F 18 /2 = PREFETCH1 */
9164 /* 0F 18 /3 = PREFETCH2 */
9165 if (insn[0] == 0x0F && insn[1] == 0x18
sewardjbcbb9de2005-03-27 02:22:32 +00009166 && haveNo66noF2noF3(pfx)
sewardja6b93d12005-02-17 09:28:28 +00009167 && !epartIsReg(insn[2])
sewardj901ed122005-02-27 13:25:31 +00009168 && gregLO3ofRM(insn[2]) >= 0 && gregLO3ofRM(insn[2]) <= 3) {
sewardja6b93d12005-02-17 09:28:28 +00009169 HChar* hintstr = "??";
9170
9171 modrm = getUChar(delta+2);
9172 vassert(!epartIsReg(modrm));
9173
9174 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9175 delta += 2+alen;
9176
sewardj901ed122005-02-27 13:25:31 +00009177 switch (gregLO3ofRM(modrm)) {
sewardja6b93d12005-02-17 09:28:28 +00009178 case 0: hintstr = "nta"; break;
9179 case 1: hintstr = "t0"; break;
9180 case 2: hintstr = "t1"; break;
9181 case 3: hintstr = "t2"; break;
9182 default: vassert(0);
9183 }
9184
9185 DIP("prefetch%s %s\n", hintstr, dis_buf);
9186 goto decode_success;
9187 }
9188
sewardja7ba8c42005-05-10 20:08:34 +00009189 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9190 /* 0F F6 = PSADBW -- sum of 8Ux8 absolute differences */
9191 if (haveNo66noF2noF3(pfx) && sz == 4
9192 && insn[0] == 0x0F && insn[1] == 0xF6) {
9193 do_MMX_preamble();
9194 delta = dis_MMXop_regmem_to_reg (
9195 pfx, delta+2, insn[1], "psadbw", False );
9196 goto decode_success;
9197 }
9198
9199 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9200 /* 0F 70 = PSHUFW -- rearrange 4x16 from E(mmx or mem) to G(mmx) */
9201 if (haveNo66noF2noF3(pfx) && sz == 4
9202 && insn[0] == 0x0F && insn[1] == 0x70) {
9203 Int order;
9204 IRTemp sV, dV, s3, s2, s1, s0;
9205 s3 = s2 = s1 = s0 = IRTemp_INVALID;
9206 sV = newTemp(Ity_I64);
9207 dV = newTemp(Ity_I64);
9208 do_MMX_preamble();
9209 modrm = insn[2];
9210 if (epartIsReg(modrm)) {
9211 assign( sV, getMMXReg(eregLO3ofRM(modrm)) );
9212 order = (Int)insn[3];
9213 delta += 2+2;
9214 DIP("pshufw $%d,%s,%s\n", order,
9215 nameMMXReg(eregLO3ofRM(modrm)),
9216 nameMMXReg(gregLO3ofRM(modrm)));
9217 } else {
9218 addr = disAMode ( &alen, pfx, delta+2, dis_buf,
9219 1/*extra byte after amode*/ );
9220 assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
9221 order = (Int)insn[2+alen];
9222 delta += 3+alen;
9223 DIP("pshufw $%d,%s,%s\n", order,
9224 dis_buf,
9225 nameMMXReg(gregLO3ofRM(modrm)));
9226 }
9227 breakup64to16s( sV, &s3, &s2, &s1, &s0 );
9228# define SEL(n) \
9229 ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
9230 assign(dV,
9231 mk64from16s( SEL((order>>6)&3), SEL((order>>4)&3),
9232 SEL((order>>2)&3), SEL((order>>0)&3) )
9233 );
9234 putMMXReg(gregLO3ofRM(modrm), mkexpr(dV));
9235# undef SEL
9236 goto decode_success;
9237 }
9238
9239 /* 0F 53 = RCPPS -- approx reciprocal 32Fx4 from R/M to R */
9240 if (haveNo66noF2noF3(pfx) && sz == 4
9241 && insn[0] == 0x0F && insn[1] == 0x53) {
9242 delta = dis_SSE_E_to_G_unary_all( pfx, delta+2,
9243 "rcpps", Iop_Recip32Fx4 );
9244 goto decode_success;
9245 }
9246
9247 /* F3 0F 53 = RCPSS -- approx reciprocal 32F0x4 from R/M to R */
9248 if (haveF3no66noF2(pfx) && sz == 4
9249 && insn[0] == 0x0F && insn[1] == 0x53) {
9250 delta = dis_SSE_E_to_G_unary_lo32( pfx, delta+2,
9251 "rcpss", Iop_Recip32F0x4 );
9252 goto decode_success;
9253 }
9254
9255 /* 0F 52 = RSQRTPS -- approx reciprocal sqrt 32Fx4 from R/M to R */
9256 if (haveNo66noF2noF3(pfx) && sz == 4
9257 && insn[0] == 0x0F && insn[1] == 0x52) {
9258 delta = dis_SSE_E_to_G_unary_all( pfx, delta+2,
9259 "rsqrtps", Iop_RSqrt32Fx4 );
9260 goto decode_success;
9261 }
9262
9263 /* F3 0F 52 = RSQRTSS -- approx reciprocal sqrt 32F0x4 from R/M to R */
9264 if (haveF3no66noF2(pfx) && sz == 4
9265 && insn[0] == 0x0F && insn[1] == 0x52) {
9266 delta = dis_SSE_E_to_G_unary_lo32( pfx, delta+2,
9267 "rsqrtss", Iop_RSqrt32F0x4 );
9268 goto decode_success;
9269 }
sewardjf53b7352005-04-06 20:01:56 +00009270
9271 /* 0F AE /7 = SFENCE -- flush pending operations to memory */
9272 if (haveNo66noF2noF3(pfx)
9273 && insn[0] == 0x0F && insn[1] == 0xAE
9274 && epartIsReg(insn[2]) && gregLO3ofRM(insn[2]) == 7
9275 && sz == 4) {
9276 delta += 3;
9277 /* Insert a memory fence. It's sometimes important that these
9278 are carried through to the generated code. */
9279 stmt( IRStmt_MFence() );
9280 DIP("sfence\n");
9281 goto decode_success;
9282 }
9283
sewardja7ba8c42005-05-10 20:08:34 +00009284 /* 0F C6 /r ib = SHUFPS -- shuffle packed F32s */
9285 if (haveNo66noF2noF3(pfx) && sz == 4
9286 && insn[0] == 0x0F && insn[1] == 0xC6) {
9287 Int select;
9288 IRTemp sV, dV;
9289 IRTemp s3, s2, s1, s0, d3, d2, d1, d0;
9290 sV = newTemp(Ity_V128);
9291 dV = newTemp(Ity_V128);
9292 s3 = s2 = s1 = s0 = d3 = d2 = d1 = d0 = IRTemp_INVALID;
9293 modrm = insn[2];
9294 assign( dV, getXMMReg(gregOfRexRM(pfx,modrm)) );
9295
9296 if (epartIsReg(modrm)) {
9297 assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
9298 select = (Int)insn[3];
9299 delta += 2+2;
9300 DIP("shufps $%d,%s,%s\n", select,
9301 nameXMMReg(eregOfRexRM(pfx,modrm)),
9302 nameXMMReg(gregOfRexRM(pfx,modrm)));
9303 } else {
9304 addr = disAMode ( &alen, pfx, delta+2, dis_buf,
9305 1/*byte at end of insn*/ );
9306 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
9307 select = (Int)insn[2+alen];
9308 delta += 3+alen;
9309 DIP("shufps $%d,%s,%s\n", select,
9310 dis_buf,
9311 nameXMMReg(gregOfRexRM(pfx,modrm)));
9312 }
9313
9314 breakup128to32s( dV, &d3, &d2, &d1, &d0 );
9315 breakup128to32s( sV, &s3, &s2, &s1, &s0 );
9316
9317# define SELD(n) ((n)==0 ? d0 : ((n)==1 ? d1 : ((n)==2 ? d2 : d3)))
9318# define SELS(n) ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
9319
9320 putXMMReg(
9321 gregOfRexRM(pfx,modrm),
9322 mk128from32s( SELS((select>>6)&3), SELS((select>>4)&3),
9323 SELD((select>>2)&3), SELD((select>>0)&3) )
9324 );
9325
9326# undef SELD
9327# undef SELS
9328
9329 goto decode_success;
9330 }
9331
9332 /* 0F 51 = SQRTPS -- approx sqrt 32Fx4 from R/M to R */
9333 if (haveNo66noF2noF3(pfx) && sz == 4
9334 && insn[0] == 0x0F && insn[1] == 0x51) {
9335 delta = dis_SSE_E_to_G_unary_all( pfx, delta+2,
9336 "sqrtps", Iop_Sqrt32Fx4 );
9337 goto decode_success;
9338 }
9339
9340 /* F3 0F 51 = SQRTSS -- approx sqrt 32F0x4 from R/M to R */
9341 if (haveF3no66noF2(pfx) && sz == 4
9342 && insn[0] == 0x0F && insn[1] == 0x51) {
9343 delta = dis_SSE_E_to_G_unary_lo32( pfx, delta+2,
9344 "sqrtss", Iop_Sqrt32F0x4 );
9345 goto decode_success;
9346 }
sewardjbcbb9de2005-03-27 02:22:32 +00009347
9348 /* 0F AE /3 = STMXCSR m32 -- store %mxcsr */
9349 if (insn[0] == 0x0F && insn[1] == 0xAE
9350 && haveNo66noF2noF3(pfx)
9351 && !epartIsReg(insn[2]) && gregLO3ofRM(insn[2]) == 3) {
9352
9353 vassert(sz == 4);
9354 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9355 delta += 2+alen;
9356
9357 /* Fake up a native SSE mxcsr word. The only thing it depends
9358 on is SSEROUND[1:0], so call a clean helper to cook it up.
9359 */
9360 /* ULong amd64h_create_mxcsr ( ULong sseround ) */
9361 DIP("stmxcsr %s\n", dis_buf);
9362 storeLE(
9363 mkexpr(addr),
9364 unop(Iop_64to32,
9365 mkIRExprCCall(
9366 Ity_I64, 0/*regp*/,
9367 "amd64g_create_mxcsr", &amd64g_create_mxcsr,
9368 mkIRExprVec_1( unop(Iop_32Uto64,get_sse_roundingmode()) )
9369 )
9370 )
9371 );
9372 goto decode_success;
9373 }
9374
sewardj432f8b62005-05-10 02:50:05 +00009375 /* 0F 5C = SUBPS -- sub 32Fx4 from R/M to R */
9376 if (haveNo66noF2noF3(pfx) && sz == 4
9377 && insn[0] == 0x0F && insn[1] == 0x5C) {
9378 delta = dis_SSE_E_to_G_all( pfx, delta+2, "subps", Iop_Sub32Fx4 );
9379 goto decode_success;
9380 }
sewardj8d965312005-02-25 02:48:47 +00009381
9382 /* F3 0F 5C = SUBSS -- sub 32F0x4 from R/M to R */
9383 if (haveF3no66noF2(pfx) && sz == 4
9384 && insn[0] == 0x0F && insn[1] == 0x5C) {
9385 delta = dis_SSE_E_to_G_lo32( pfx, delta+2, "subss", Iop_Sub32F0x4 );
9386 goto decode_success;
9387 }
9388
sewardja7ba8c42005-05-10 20:08:34 +00009389 /* 0F 15 = UNPCKHPS -- unpack and interleave high part F32s */
9390 /* 0F 14 = UNPCKLPS -- unpack and interleave low part F32s */
9391 /* These just appear to be special cases of SHUFPS */
9392 if (haveNo66noF2noF3(pfx) && sz == 4
9393 && insn[0] == 0x0F && (insn[1] == 0x15 || insn[1] == 0x14)) {
9394 IRTemp sV, dV;
9395 IRTemp s3, s2, s1, s0, d3, d2, d1, d0;
sewardjca673ab2005-05-11 10:03:08 +00009396 Bool hi = toBool(insn[1] == 0x15);
sewardja7ba8c42005-05-10 20:08:34 +00009397 sV = newTemp(Ity_V128);
9398 dV = newTemp(Ity_V128);
9399 s3 = s2 = s1 = s0 = d3 = d2 = d1 = d0 = IRTemp_INVALID;
9400 modrm = insn[2];
9401 assign( dV, getXMMReg(gregOfRexRM(pfx,modrm)) );
9402
9403 if (epartIsReg(modrm)) {
9404 assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
9405 delta += 2+1;
9406 DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
9407 nameXMMReg(eregOfRexRM(pfx,modrm)),
9408 nameXMMReg(gregOfRexRM(pfx,modrm)));
9409 } else {
9410 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9411 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
9412 delta += 2+alen;
9413 DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
9414 dis_buf,
9415 nameXMMReg(gregOfRexRM(pfx,modrm)));
9416 }
9417
9418 breakup128to32s( dV, &d3, &d2, &d1, &d0 );
9419 breakup128to32s( sV, &s3, &s2, &s1, &s0 );
9420
9421 if (hi) {
9422 putXMMReg( gregOfRexRM(pfx,modrm), mk128from32s( s3, d3, s2, d2 ) );
9423 } else {
9424 putXMMReg( gregOfRexRM(pfx,modrm), mk128from32s( s1, d1, s0, d0 ) );
9425 }
9426
9427 goto decode_success;
9428 }
sewardj8d965312005-02-25 02:48:47 +00009429
9430 /* 0F 57 = XORPS -- G = G and E */
9431 if (haveNo66noF2noF3(pfx) && sz == 4
9432 && insn[0] == 0x0F && insn[1] == 0x57) {
9433 delta = dis_SSE_E_to_G_all( pfx, delta+2, "xorps", Iop_XorV128 );
9434 goto decode_success;
9435 }
9436
sewardj5992bd02005-05-11 02:13:42 +00009437 /* ---------------------------------------------------- */
9438 /* --- end of the SSE decoder. --- */
9439 /* ---------------------------------------------------- */
9440
9441 /* ---------------------------------------------------- */
9442 /* --- start of the SSE2 decoder. --- */
9443 /* ---------------------------------------------------- */
sewardj4c328cf2005-05-05 12:05:54 +00009444
9445 /* 66 0F 58 = ADDPD -- add 32Fx4 from R/M to R */
9446 if (have66noF2noF3(pfx) && sz == 2
9447 && insn[0] == 0x0F && insn[1] == 0x58) {
9448 delta = dis_SSE_E_to_G_all( pfx, delta+2, "addpd", Iop_Add64Fx2 );
9449 goto decode_success;
9450 }
sewardj1001dc42005-02-21 08:25:55 +00009451
9452 /* F2 0F 58 = ADDSD -- add 64F0x2 from R/M to R */
9453 if (haveF2no66noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x58) {
9454 vassert(sz == 4);
9455 delta = dis_SSE_E_to_G_lo64( pfx, delta+2, "addsd", Iop_Add64F0x2 );
9456 goto decode_success;
9457 }
9458
sewardj8d965312005-02-25 02:48:47 +00009459 /* 66 0F 55 = ANDNPD -- G = (not G) and E */
9460 if (have66noF2noF3(pfx) && sz == 2
9461 && insn[0] == 0x0F && insn[1] == 0x55) {
9462 delta = dis_SSE_E_to_G_all_invG( pfx, delta+2, "andnpd", Iop_AndV128 );
9463 goto decode_success;
9464 }
sewardj1a01e652005-02-23 11:39:21 +00009465
9466 /* 66 0F 54 = ANDPD -- G = G and E */
9467 if (have66noF2noF3(pfx) && sz == 2
9468 && insn[0] == 0x0F && insn[1] == 0x54) {
9469 delta = dis_SSE_E_to_G_all( pfx, delta+2, "andpd", Iop_AndV128 );
9470 goto decode_success;
9471 }
9472
sewardj97628592005-05-10 22:42:54 +00009473 /* 66 0F C2 = CMPPD -- 64Fx2 comparison from R/M to R */
9474 if (have66noF2noF3(pfx) && sz == 2
9475 && insn[0] == 0x0F && insn[1] == 0xC2) {
9476 delta = dis_SSEcmp_E_to_G( pfx, delta+2, "cmppd", True, 8 );
9477 goto decode_success;
9478 }
sewardj8d965312005-02-25 02:48:47 +00009479
9480 /* F2 0F C2 = CMPSD -- 64F0x2 comparison from R/M to R */
9481 if (haveF2no66noF3(pfx) && sz == 4
9482 && insn[0] == 0x0F && insn[1] == 0xC2) {
9483 delta = dis_SSEcmp_E_to_G( pfx, delta+2, "cmpsd", False, 8 );
9484 goto decode_success;
9485 }
sewardj18303862005-02-21 12:36:54 +00009486
9487 /* 66 0F 2F = COMISD -- 64F0x2 comparison G,E, and set ZCP */
9488 /* 66 0F 2E = UCOMISD -- 64F0x2 comparison G,E, and set ZCP */
sewardjc49ce232005-02-25 13:03:03 +00009489 if (have66noF2noF3(pfx) && sz == 2
sewardj18303862005-02-21 12:36:54 +00009490 && insn[0] == 0x0F && (insn[1] == 0x2F || insn[1] == 0x2E)) {
9491 IRTemp argL = newTemp(Ity_F64);
9492 IRTemp argR = newTemp(Ity_F64);
9493 modrm = getUChar(delta+2);
9494 if (epartIsReg(modrm)) {
9495 assign( argR, getXMMRegLane64F( eregOfRexRM(pfx,modrm),
9496 0/*lowest lane*/ ) );
9497 delta += 2+1;
9498 DIP("%scomisd %s,%s\n", insn[1]==0x2E ? "u" : "",
9499 nameXMMReg(eregOfRexRM(pfx,modrm)),
9500 nameXMMReg(gregOfRexRM(pfx,modrm)) );
9501 } else {
9502 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9503 assign( argR, loadLE(Ity_F64, mkexpr(addr)) );
9504 delta += 2+alen;
9505 DIP("%scomisd %s,%s\n", insn[1]==0x2E ? "u" : "",
9506 dis_buf,
9507 nameXMMReg(gregOfRexRM(pfx,modrm)) );
9508 }
9509 assign( argL, getXMMRegLane64F( gregOfRexRM(pfx,modrm),
9510 0/*lowest lane*/ ) );
9511
9512 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(AMD64G_CC_OP_COPY) ));
9513 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
9514 stmt( IRStmt_Put(
9515 OFFB_CC_DEP1,
9516 binop( Iop_And64,
9517 unop( Iop_32Uto64,
9518 binop(Iop_CmpF64, mkexpr(argL), mkexpr(argR)) ),
9519 mkU64(0x45)
9520 )));
9521
9522 goto decode_success;
9523 }
9524
sewardj09717342005-05-05 21:34:02 +00009525 /* F3 0F E6 = CVTDQ2PD -- convert 2 x I32 in mem/lo half xmm to 2 x
9526 F64 in xmm(G) */
9527 if (haveF3no66noF2(pfx) && insn[0] == 0x0F && insn[1] == 0xE6) {
9528 IRTemp arg64 = newTemp(Ity_I64);
9529 if (sz != 4) goto decode_failure;
9530
9531 modrm = getUChar(delta+2);
9532 if (epartIsReg(modrm)) {
9533 assign( arg64, getXMMRegLane64(eregOfRexRM(pfx,modrm), 0) );
9534 delta += 2+1;
9535 DIP("cvtdq2pd %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
9536 nameXMMReg(gregOfRexRM(pfx,modrm)));
9537 } else {
9538 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9539 assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
9540 delta += 2+alen;
9541 DIP("cvtdq2pd %s,%s\n", dis_buf,
9542 nameXMMReg(gregOfRexRM(pfx,modrm)) );
9543 }
9544
9545 putXMMRegLane64F(
9546 gregOfRexRM(pfx,modrm), 0,
9547 unop(Iop_I32toF64, unop(Iop_64to32, mkexpr(arg64)))
9548 );
9549
9550 putXMMRegLane64F(
9551 gregOfRexRM(pfx,modrm), 1,
9552 unop(Iop_I32toF64, unop(Iop_64HIto32, mkexpr(arg64)))
9553 );
9554
9555 goto decode_success;
9556 }
9557
sewardj5992bd02005-05-11 02:13:42 +00009558 /* 0F 5B = CVTDQ2PS -- convert 4 x I32 in mem/xmm to 4 x F32 in
9559 xmm(G) */
9560 if (haveNo66noF2noF3(pfx) && sz == 4
9561 && insn[0] == 0x0F && insn[1] == 0x5B) {
sewardj09717342005-05-05 21:34:02 +00009562 IRTemp argV = newTemp(Ity_V128);
9563 IRTemp rmode = newTemp(Ity_I32);
sewardj09717342005-05-05 21:34:02 +00009564
9565 modrm = getUChar(delta+2);
9566 if (epartIsReg(modrm)) {
9567 assign( argV, getXMMReg(eregOfRexRM(pfx,modrm)) );
9568 delta += 2+1;
sewardj5992bd02005-05-11 02:13:42 +00009569 DIP("cvtdq2ps %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
sewardj09717342005-05-05 21:34:02 +00009570 nameXMMReg(gregOfRexRM(pfx,modrm)));
9571 } else {
9572 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
sewardj5992bd02005-05-11 02:13:42 +00009573 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
sewardj09717342005-05-05 21:34:02 +00009574 delta += 2+alen;
sewardj5992bd02005-05-11 02:13:42 +00009575 DIP("cvtdq2ps %s,%s\n", dis_buf,
sewardj09717342005-05-05 21:34:02 +00009576 nameXMMReg(gregOfRexRM(pfx,modrm)) );
9577 }
9578
9579 assign( rmode, get_sse_roundingmode() );
sewardj5992bd02005-05-11 02:13:42 +00009580 breakup128to32s( argV, &t3, &t2, &t1, &t0 );
9581
9582# define CVT(_t) binop( Iop_F64toF32, \
9583 mkexpr(rmode), \
9584 unop(Iop_I32toF64,mkexpr(_t)))
9585
9586 putXMMRegLane32F( gregOfRexRM(pfx,modrm), 3, CVT(t3) );
9587 putXMMRegLane32F( gregOfRexRM(pfx,modrm), 2, CVT(t2) );
9588 putXMMRegLane32F( gregOfRexRM(pfx,modrm), 1, CVT(t1) );
9589 putXMMRegLane32F( gregOfRexRM(pfx,modrm), 0, CVT(t0) );
9590
9591# undef CVT
9592
9593 goto decode_success;
9594 }
9595
9596 /* 66 0F E6 = CVTTPD2DQ -- convert 2 x F64 in mem/xmm to 2 x I32 in
9597 lo half xmm(G), and zero upper half, rounding towards zero */
9598 /* F2 0F E6 = CVTPD2DQ -- convert 2 x F64 in mem/xmm to 2 x I32 in
9599 lo half xmm(G), according to prevailing rounding mode, and zero
9600 upper half */
9601 if ( ( (haveF2no66noF3(pfx) && sz == 4)
9602 || (have66noF2noF3(pfx) && sz == 2)
9603 )
9604 && insn[0] == 0x0F && insn[1] == 0xE6) {
9605 IRTemp argV = newTemp(Ity_V128);
9606 IRTemp rmode = newTemp(Ity_I32);
9607 Bool r2zero = toBool(sz == 2);
9608
9609 modrm = getUChar(delta+2);
9610 if (epartIsReg(modrm)) {
9611 assign( argV, getXMMReg(eregOfRexRM(pfx,modrm)) );
9612 delta += 2+1;
9613 DIP("cvt%spd2dq %s,%s\n", r2zero ? "t" : "",
9614 nameXMMReg(eregOfRexRM(pfx,modrm)),
9615 nameXMMReg(gregOfRexRM(pfx,modrm)));
9616 } else {
9617 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9618 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
9619 delta += 2+alen;
9620 DIP("cvt%spd2dq %s,%s\n", r2zero ? "t" : "",
9621 dis_buf,
9622 nameXMMReg(gregOfRexRM(pfx,modrm)) );
9623 }
9624
9625 if (r2zero) {
9626 assign(rmode, mkU32((UInt)Irrm_ZERO) );
9627 } else {
9628 assign( rmode, get_sse_roundingmode() );
9629 }
9630
sewardj09717342005-05-05 21:34:02 +00009631 t0 = newTemp(Ity_F64);
9632 t1 = newTemp(Ity_F64);
9633 assign( t0, unop(Iop_ReinterpI64asF64,
9634 unop(Iop_V128to64, mkexpr(argV))) );
9635 assign( t1, unop(Iop_ReinterpI64asF64,
9636 unop(Iop_V128HIto64, mkexpr(argV))) );
9637
9638# define CVT(_t) binop( Iop_F64toI32, \
9639 mkexpr(rmode), \
9640 mkexpr(_t) )
9641
9642 putXMMRegLane32( gregOfRexRM(pfx,modrm), 3, mkU32(0) );
9643 putXMMRegLane32( gregOfRexRM(pfx,modrm), 2, mkU32(0) );
9644 putXMMRegLane32( gregOfRexRM(pfx,modrm), 1, CVT(t1) );
9645 putXMMRegLane32( gregOfRexRM(pfx,modrm), 0, CVT(t0) );
9646
9647# undef CVT
9648
9649 goto decode_success;
9650 }
9651
sewardj5992bd02005-05-11 02:13:42 +00009652 /* 66 0F 2D = CVTPD2PI -- convert 2 x F64 in mem/xmm to 2 x
9653 I32 in mmx, according to prevailing SSE rounding mode */
9654 /* 66 0F 2C = CVTTPD2PI -- convert 2 x F64 in mem/xmm to 2 x
9655 I32 in mmx, rounding towards zero */
9656 if (have66noF2noF3(pfx) && sz == 2
9657 && insn[0] == 0x0F && (insn[1] == 0x2D || insn[1] == 0x2C)) {
9658 IRTemp dst64 = newTemp(Ity_I64);
9659 IRTemp rmode = newTemp(Ity_I32);
9660 IRTemp f64lo = newTemp(Ity_F64);
9661 IRTemp f64hi = newTemp(Ity_F64);
sewardjca673ab2005-05-11 10:03:08 +00009662 Bool r2zero = toBool(insn[1] == 0x2C);
sewardj5992bd02005-05-11 02:13:42 +00009663
9664 do_MMX_preamble();
9665 modrm = getUChar(delta+2);
9666
9667 if (epartIsReg(modrm)) {
9668 delta += 2+1;
9669 assign(f64lo, getXMMRegLane64F(eregOfRexRM(pfx,modrm), 0));
9670 assign(f64hi, getXMMRegLane64F(eregOfRexRM(pfx,modrm), 1));
9671 DIP("cvt%spd2pi %s,%s\n", r2zero ? "t" : "",
9672 nameXMMReg(eregOfRexRM(pfx,modrm)),
9673 nameMMXReg(gregLO3ofRM(modrm)));
9674 } else {
9675 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9676 assign(f64lo, loadLE(Ity_F64, mkexpr(addr)));
9677 assign(f64hi, loadLE(Ity_F64, binop( Iop_Add64,
9678 mkexpr(addr),
9679 mkU64(8) )));
9680 delta += 2+alen;
9681 DIP("cvt%spf2pi %s,%s\n", r2zero ? "t" : "",
9682 dis_buf,
9683 nameMMXReg(gregLO3ofRM(modrm)));
9684 }
9685
9686 if (r2zero) {
9687 assign(rmode, mkU32((UInt)Irrm_ZERO) );
9688 } else {
9689 assign( rmode, get_sse_roundingmode() );
9690 }
9691
9692 assign(
9693 dst64,
9694 binop( Iop_32HLto64,
9695 binop( Iop_F64toI32, mkexpr(rmode), mkexpr(f64hi) ),
9696 binop( Iop_F64toI32, mkexpr(rmode), mkexpr(f64lo) )
9697 )
9698 );
9699
9700 putMMXReg(gregLO3ofRM(modrm), mkexpr(dst64));
9701 goto decode_success;
9702 }
9703
9704 /* 66 0F 5A = CVTPD2PS -- convert 2 x F64 in mem/xmm to 2 x F32 in
9705 lo half xmm(G), rounding according to prevailing SSE rounding
9706 mode, and zero upper half */
9707 /* Note, this is practically identical to CVTPD2DQ. It would have
9708 been nicer to merge them together, but the insn[] offsets differ
9709 by one. */
9710 if (have66noF2noF3(pfx) && sz == 2
9711 && insn[0] == 0x0F && insn[1] == 0x5A) {
9712 IRTemp argV = newTemp(Ity_V128);
9713 IRTemp rmode = newTemp(Ity_I32);
9714
9715 modrm = getUChar(delta+2);
9716 if (epartIsReg(modrm)) {
9717 assign( argV, getXMMReg(eregOfRexRM(pfx,modrm)) );
9718 delta += 2+1;
9719 DIP("cvtpd2ps %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
9720 nameXMMReg(gregOfRexRM(pfx,modrm)));
9721 } else {
9722 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9723 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
9724 delta += 2+alen;
9725 DIP("cvtpd2ps %s,%s\n", dis_buf,
9726 nameXMMReg(gregOfRexRM(pfx,modrm)) );
9727 }
9728
9729 assign( rmode, get_sse_roundingmode() );
9730 t0 = newTemp(Ity_F64);
9731 t1 = newTemp(Ity_F64);
9732 assign( t0, unop(Iop_ReinterpI64asF64,
9733 unop(Iop_V128to64, mkexpr(argV))) );
9734 assign( t1, unop(Iop_ReinterpI64asF64,
9735 unop(Iop_V128HIto64, mkexpr(argV))) );
9736
9737# define CVT(_t) binop( Iop_F64toF32, \
9738 mkexpr(rmode), \
9739 mkexpr(_t) )
9740
9741 putXMMRegLane32( gregOfRexRM(pfx,modrm), 3, mkU32(0) );
9742 putXMMRegLane32( gregOfRexRM(pfx,modrm), 2, mkU32(0) );
9743 putXMMRegLane32F( gregOfRexRM(pfx,modrm), 1, CVT(t1) );
9744 putXMMRegLane32F( gregOfRexRM(pfx,modrm), 0, CVT(t0) );
9745
9746# undef CVT
9747
9748 goto decode_success;
9749 }
9750
9751 /* 66 0F 2A = CVTPI2PD -- convert 2 x I32 in mem/mmx to 2 x F64 in
9752 xmm(G) */
9753 if (have66noF2noF3(pfx) && sz == 2
9754 && insn[0] == 0x0F && insn[1] == 0x2A) {
9755 IRTemp arg64 = newTemp(Ity_I64);
9756
9757 modrm = getUChar(delta+2);
9758 do_MMX_preamble();
9759 if (epartIsReg(modrm)) {
9760 assign( arg64, getMMXReg(eregLO3ofRM(modrm)) );
9761 delta += 2+1;
9762 DIP("cvtpi2pd %s,%s\n", nameMMXReg(eregLO3ofRM(modrm)),
9763 nameXMMReg(gregOfRexRM(pfx,modrm)));
9764 } else {
9765 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9766 assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
9767 delta += 2+alen;
9768 DIP("cvtpi2pd %s,%s\n", dis_buf,
9769 nameXMMReg(gregOfRexRM(pfx,modrm)) );
9770 }
9771
9772 putXMMRegLane64F(
9773 gregOfRexRM(pfx,modrm), 0,
9774 unop(Iop_I32toF64, unop(Iop_64to32, mkexpr(arg64)) )
9775 );
9776
9777 putXMMRegLane64F(
9778 gregOfRexRM(pfx,modrm), 1,
9779 unop(Iop_I32toF64, unop(Iop_64HIto32, mkexpr(arg64)) )
9780 );
9781
9782 goto decode_success;
9783 }
9784
9785 /* F3 0F 5B = CVTTPS2DQ -- convert 4 x F32 in mem/xmm to 4 x I32 in
9786 xmm(G), rounding towards zero */
9787 /* 66 0F 5B = CVTPS2DQ -- convert 4 x F32 in mem/xmm to 4 x I32 in
9788 xmm(G), as per the prevailing rounding mode */
9789 if ( ( (have66noF2noF3(pfx) && sz == 2)
9790 || (haveF3no66noF2(pfx) && sz == 4)
9791 )
9792 && insn[0] == 0x0F && insn[1] == 0x5B) {
9793 IRTemp argV = newTemp(Ity_V128);
9794 IRTemp rmode = newTemp(Ity_I32);
9795 Bool r2zero = toBool(sz == 4);
9796
9797 modrm = getUChar(delta+2);
9798 if (epartIsReg(modrm)) {
9799 assign( argV, getXMMReg(eregOfRexRM(pfx,modrm)) );
9800 delta += 2+1;
9801 DIP("cvtps2dq %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
9802 nameXMMReg(gregOfRexRM(pfx,modrm)));
9803 } else {
9804 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9805 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
9806 delta += 2+alen;
9807 DIP("cvtps2dq %s,%s\n", dis_buf,
9808 nameXMMReg(gregOfRexRM(pfx,modrm)) );
9809 }
9810
9811 if (r2zero) {
9812 assign( rmode, mkU32((UInt)Irrm_ZERO) );
9813 } else {
9814 assign( rmode, get_sse_roundingmode() );
9815 }
9816
9817 breakup128to32s( argV, &t3, &t2, &t1, &t0 );
9818
9819 /* This is less than ideal. If it turns out to be a performance
9820 bottleneck it can be improved. */
9821# define CVT(_t) \
9822 binop( Iop_F64toI32, \
9823 mkexpr(rmode), \
9824 unop( Iop_F32toF64, \
9825 unop( Iop_ReinterpI32asF32, mkexpr(_t))) )
9826
9827 putXMMRegLane32( gregOfRexRM(pfx,modrm), 3, CVT(t3) );
9828 putXMMRegLane32( gregOfRexRM(pfx,modrm), 2, CVT(t2) );
9829 putXMMRegLane32( gregOfRexRM(pfx,modrm), 1, CVT(t1) );
9830 putXMMRegLane32( gregOfRexRM(pfx,modrm), 0, CVT(t0) );
9831
9832# undef CVT
9833
9834 goto decode_success;
9835 }
9836
9837 /* 0F 5A = CVTPS2PD -- convert 2 x F32 in low half mem/xmm to 2 x
9838 F64 in xmm(G). */
9839 if (haveNo66noF2noF3(pfx) && sz == 4
9840 && insn[0] == 0x0F && insn[1] == 0x5A) {
9841 IRTemp f32lo = newTemp(Ity_F32);
9842 IRTemp f32hi = newTemp(Ity_F32);
9843
9844 modrm = getUChar(delta+2);
9845 if (epartIsReg(modrm)) {
9846 assign( f32lo, getXMMRegLane32F(eregOfRexRM(pfx,modrm), 0) );
9847 assign( f32hi, getXMMRegLane32F(eregOfRexRM(pfx,modrm), 1) );
9848 delta += 2+1;
9849 DIP("cvtps2pd %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
9850 nameXMMReg(gregOfRexRM(pfx,modrm)));
9851 } else {
9852 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9853 assign( f32lo, loadLE(Ity_F32, mkexpr(addr)) );
9854 assign( f32hi, loadLE(Ity_F32,
9855 binop(Iop_Add64,mkexpr(addr),mkU64(4))) );
9856 delta += 2+alen;
9857 DIP("cvtps2pd %s,%s\n", dis_buf,
9858 nameXMMReg(gregOfRexRM(pfx,modrm)) );
9859 }
9860
9861 putXMMRegLane64F( gregOfRexRM(pfx,modrm), 1,
9862 unop(Iop_F32toF64, mkexpr(f32hi)) );
9863 putXMMRegLane64F( gregOfRexRM(pfx,modrm), 0,
9864 unop(Iop_F32toF64, mkexpr(f32lo)) );
9865
9866 goto decode_success;
9867 }
9868
9869 /* F2 0F 2D = CVTSD2SI
9870 when sz==4 -- convert F64 in mem/low half xmm to I32 in ireg,
9871 according to prevailing SSE rounding mode
9872 when sz==8 -- convert F64 in mem/low half xmm to I64 in ireg,
9873 according to prevailing SSE rounding mode
9874 */
sewardj1a01e652005-02-23 11:39:21 +00009875 /* F2 0F 2C = CVTTSD2SI
9876 when sz==4 -- convert F64 in mem/low half xmm to I32 in ireg,
9877 truncating towards zero
9878 when sz==8 -- convert F64 in mem/low half xmm to I64 in ireg,
9879 truncating towards zero
9880 */
9881 if (haveF2no66noF3(pfx)
9882 && insn[0] == 0x0F
sewardj5992bd02005-05-11 02:13:42 +00009883 && (insn[1] == 0x2D || insn[1] == 0x2C)) {
sewardj1a01e652005-02-23 11:39:21 +00009884 IRTemp rmode = newTemp(Ity_I32);
9885 IRTemp f64lo = newTemp(Ity_F64);
sewardj1027dc22005-02-26 01:55:02 +00009886 Bool r2zero = toBool(insn[1] == 0x2C);
sewardj1a01e652005-02-23 11:39:21 +00009887 vassert(sz == 4 || sz == 8);
9888
9889 modrm = getUChar(delta+2);
9890 if (epartIsReg(modrm)) {
9891 delta += 2+1;
9892 assign(f64lo, getXMMRegLane64F(eregOfRexRM(pfx,modrm), 0));
9893 DIP("cvt%ssd2si %s,%s\n", r2zero ? "t" : "",
9894 nameXMMReg(eregOfRexRM(pfx,modrm)),
sewardj5b470602005-02-27 13:10:48 +00009895 nameIReg(sz, gregOfRexRM(pfx,modrm), False));
sewardj1a01e652005-02-23 11:39:21 +00009896 } else {
9897 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9898 assign(f64lo, loadLE(Ity_F64, mkexpr(addr)));
9899 delta += 2+alen;
9900 DIP("cvt%ssd2si %s,%s\n", r2zero ? "t" : "",
9901 dis_buf,
sewardj5b470602005-02-27 13:10:48 +00009902 nameIReg(sz, gregOfRexRM(pfx,modrm), False));
sewardj1a01e652005-02-23 11:39:21 +00009903 }
9904
9905 if (r2zero) {
9906 assign( rmode, mkU32((UInt)Irrm_ZERO) );
9907 } else {
9908 assign( rmode, get_sse_roundingmode() );
9909 }
9910
9911 if (sz == 4) {
sewardj5b470602005-02-27 13:10:48 +00009912 putIReg32( gregOfRexRM(pfx,modrm),
9913 binop( Iop_F64toI32, mkexpr(rmode), mkexpr(f64lo)) );
sewardj1a01e652005-02-23 11:39:21 +00009914 } else {
sewardj5b470602005-02-27 13:10:48 +00009915 putIReg64( gregOfRexRM(pfx,modrm),
9916 binop( Iop_F64toI64, mkexpr(rmode), mkexpr(f64lo)) );
sewardj1a01e652005-02-23 11:39:21 +00009917 }
9918
9919 goto decode_success;
9920 }
9921
sewardj8d965312005-02-25 02:48:47 +00009922 /* F2 0F 5A = CVTSD2SS -- convert F64 in mem/low half xmm to F32 in
9923 low 1/4 xmm(G), according to prevailing SSE rounding mode */
9924 if (haveF2no66noF3(pfx) && sz == 4
9925 && insn[0] == 0x0F && insn[1] == 0x5A) {
9926 IRTemp rmode = newTemp(Ity_I32);
9927 IRTemp f64lo = newTemp(Ity_F64);
9928 vassert(sz == 4);
9929
9930 modrm = getUChar(delta+2);
9931 if (epartIsReg(modrm)) {
9932 delta += 2+1;
9933 assign(f64lo, getXMMRegLane64F(eregOfRexRM(pfx,modrm), 0));
9934 DIP("cvtsd2ss %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
9935 nameXMMReg(gregOfRexRM(pfx,modrm)));
9936 } else {
9937 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9938 assign(f64lo, loadLE(Ity_F64, mkexpr(addr)));
9939 delta += 2+alen;
9940 DIP("cvtsd2ss %s,%s\n", dis_buf,
9941 nameXMMReg(gregOfRexRM(pfx,modrm)));
9942 }
9943
9944 assign( rmode, get_sse_roundingmode() );
9945 putXMMRegLane32F(
9946 gregOfRexRM(pfx,modrm), 0,
9947 binop( Iop_F64toF32, mkexpr(rmode), mkexpr(f64lo) )
9948 );
9949
9950 goto decode_success;
9951 }
sewardj1a01e652005-02-23 11:39:21 +00009952
9953 /* F2 0F 2A = CVTSI2SD
9954 when sz==4 -- convert I32 in mem/ireg to F64 in low half xmm
9955 when sz==8 -- convert I64 in mem/ireg to F64 in low half xmm
9956 */
sewardj8d965312005-02-25 02:48:47 +00009957 if (haveF2no66noF3(pfx) && (sz == 4 || sz == 8)
9958 && insn[0] == 0x0F && insn[1] == 0x2A) {
sewardj1a01e652005-02-23 11:39:21 +00009959 modrm = getUChar(delta+2);
9960
9961 if (sz == 4) {
9962 IRTemp arg32 = newTemp(Ity_I32);
9963 if (epartIsReg(modrm)) {
sewardj5b470602005-02-27 13:10:48 +00009964 assign( arg32, getIReg32(eregOfRexRM(pfx,modrm)) );
sewardj1a01e652005-02-23 11:39:21 +00009965 delta += 2+1;
sewardj5b470602005-02-27 13:10:48 +00009966 DIP("cvtsi2sd %s,%s\n", nameIReg32(eregOfRexRM(pfx,modrm)),
sewardj1a01e652005-02-23 11:39:21 +00009967 nameXMMReg(gregOfRexRM(pfx,modrm)));
9968 } else {
9969 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9970 assign( arg32, loadLE(Ity_I32, mkexpr(addr)) );
9971 delta += 2+alen;
9972 DIP("cvtsi2sd %s,%s\n", dis_buf,
9973 nameXMMReg(gregOfRexRM(pfx,modrm)) );
9974 }
9975 putXMMRegLane64F( gregOfRexRM(pfx,modrm), 0,
9976 unop(Iop_I32toF64, mkexpr(arg32))
9977 );
9978 } else {
9979 /* sz == 8 */
9980 IRTemp arg64 = newTemp(Ity_I64);
9981 if (epartIsReg(modrm)) {
sewardj5b470602005-02-27 13:10:48 +00009982 assign( arg64, getIReg64(eregOfRexRM(pfx,modrm)) );
sewardj1a01e652005-02-23 11:39:21 +00009983 delta += 2+1;
sewardj5b470602005-02-27 13:10:48 +00009984 DIP("cvtsi2sdq %s,%s\n", nameIReg64(eregOfRexRM(pfx,modrm)),
sewardj8d965312005-02-25 02:48:47 +00009985 nameXMMReg(gregOfRexRM(pfx,modrm)));
sewardj1a01e652005-02-23 11:39:21 +00009986 } else {
9987 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
9988 assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
9989 delta += 2+alen;
sewardj8d965312005-02-25 02:48:47 +00009990 DIP("cvtsi2sdq %s,%s\n", dis_buf,
9991 nameXMMReg(gregOfRexRM(pfx,modrm)) );
sewardj1a01e652005-02-23 11:39:21 +00009992 }
9993 putXMMRegLane64F(
9994 gregOfRexRM(pfx,modrm),
9995 0,
9996 binop( Iop_I64toF64,
9997 get_sse_roundingmode(),
9998 mkexpr(arg64)
9999 )
10000 );
10001
10002 }
10003
10004 goto decode_success;
10005 }
10006
sewardjc49ce232005-02-25 13:03:03 +000010007 /* F3 0F 5A = CVTSS2SD -- convert F32 in mem/low 1/4 xmm to F64 in
10008 low half xmm(G) */
10009 if (haveF3no66noF2(pfx) && sz == 4
10010 && insn[0] == 0x0F && insn[1] == 0x5A) {
10011 IRTemp f32lo = newTemp(Ity_F32);
10012
10013 modrm = getUChar(delta+2);
10014 if (epartIsReg(modrm)) {
10015 delta += 2+1;
10016 assign(f32lo, getXMMRegLane32F(eregOfRexRM(pfx,modrm), 0));
10017 DIP("cvtss2sd %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
10018 nameXMMReg(gregOfRexRM(pfx,modrm)));
10019 } else {
10020 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10021 assign(f32lo, loadLE(Ity_F32, mkexpr(addr)));
10022 delta += 2+alen;
10023 DIP("cvtss2sd %s,%s\n", dis_buf,
10024 nameXMMReg(gregOfRexRM(pfx,modrm)));
10025 }
10026
10027 putXMMRegLane64F( gregOfRexRM(pfx,modrm), 0,
10028 unop( Iop_F32toF64, mkexpr(f32lo) ) );
10029
10030 goto decode_success;
10031 }
10032
sewardj5992bd02005-05-11 02:13:42 +000010033 /* 66 0F 5E = DIVPD -- div 64Fx2 from R/M to R */
10034 if (have66noF2noF3(pfx) && sz == 2
10035 && insn[0] == 0x0F && insn[1] == 0x5E) {
10036 delta = dis_SSE_E_to_G_all( pfx, delta+2, "divpd", Iop_Div64Fx2 );
10037 goto decode_success;
10038 }
sewardj1001dc42005-02-21 08:25:55 +000010039
10040 /* F2 0F 5E = DIVSD -- div 64F0x2 from R/M to R */
10041 if (haveF2no66noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x5E) {
10042 vassert(sz == 4);
10043 delta = dis_SSE_E_to_G_lo64( pfx, delta+2, "divsd", Iop_Div64F0x2 );
10044 goto decode_success;
10045 }
10046
sewardj5992bd02005-05-11 02:13:42 +000010047 /* 0F AE /5 = LFENCE -- flush pending operations to memory */
10048 /* 0F AE /6 = MFENCE -- flush pending operations to memory */
10049 if (haveNo66noF2noF3(pfx) && sz == 4
10050 && insn[0] == 0x0F && insn[1] == 0xAE
10051 && epartIsReg(insn[2])
10052 && (gregLO3ofRM(insn[2]) == 5 || gregLO3ofRM(insn[2]) == 6)) {
10053 delta += 3;
10054 /* Insert a memory fence. It's sometimes important that these
10055 are carried through to the generated code. */
10056 stmt( IRStmt_MFence() );
10057 DIP("%sfence\n", gregLO3ofRM(insn[2])==5 ? "l" : "m");
10058 goto decode_success;
10059 }
10060
10061 /* 66 0F 5F = MAXPD -- max 64Fx2 from R/M to R */
10062 if (have66noF2noF3(pfx) && sz == 2
10063 && insn[0] == 0x0F && insn[1] == 0x5F) {
10064 delta = dis_SSE_E_to_G_all( pfx, delta+2, "maxpd", Iop_Max64Fx2 );
10065 goto decode_success;
10066 }
sewardj1a01e652005-02-23 11:39:21 +000010067
10068 /* F2 0F 5F = MAXSD -- max 64F0x2 from R/M to R */
10069 if (haveF2no66noF3(pfx) && sz == 4
10070 && insn[0] == 0x0F && insn[1] == 0x5F) {
10071 delta = dis_SSE_E_to_G_lo64( pfx, delta+2, "maxsd", Iop_Max64F0x2 );
10072 goto decode_success;
10073 }
10074
sewardj5992bd02005-05-11 02:13:42 +000010075 /* 66 0F 5D = MINPD -- min 64Fx2 from R/M to R */
10076 if (have66noF2noF3(pfx) && sz == 2
10077 && insn[0] == 0x0F && insn[1] == 0x5D) {
10078 delta = dis_SSE_E_to_G_all( pfx, delta+2, "minpd", Iop_Min64Fx2 );
10079 goto decode_success;
10080 }
sewardjc49ce232005-02-25 13:03:03 +000010081
10082 /* F2 0F 5D = MINSD -- min 64F0x2 from R/M to R */
10083 if (haveF2no66noF3(pfx) && sz == 4
10084 && insn[0] == 0x0F && insn[1] == 0x5D) {
10085 delta = dis_SSE_E_to_G_lo64( pfx, delta+2, "minsd", Iop_Min64F0x2 );
10086 goto decode_success;
10087 }
sewardj8d965312005-02-25 02:48:47 +000010088
10089 /* 66 0F 28 = MOVAPD -- move from E (mem or xmm) to G (xmm). */
10090 /* 66 0F 10 = MOVUPD -- move from E (mem or xmm) to G (xmm). */
10091 /* 66 0F 6F = MOVDQA -- move from E (mem or xmm) to G (xmm). */
10092 if (have66noF2noF3(pfx) && sz == 2
10093 && insn[0] == 0x0F
10094 && (insn[1] == 0x28 || insn[1] == 0x10 || insn[1] == 0x6F)) {
10095 HChar* wot = insn[1]==0x28 ? "apd" :
10096 insn[1]==0x10 ? "upd" : "dqa";
10097 modrm = getUChar(delta+2);
10098 if (epartIsReg(modrm)) {
10099 putXMMReg( gregOfRexRM(pfx,modrm),
10100 getXMMReg( eregOfRexRM(pfx,modrm) ));
10101 DIP("mov%s %s,%s\n", wot, nameXMMReg(eregOfRexRM(pfx,modrm)),
10102 nameXMMReg(gregOfRexRM(pfx,modrm)));
10103 delta += 2+1;
10104 } else {
10105 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10106 putXMMReg( gregOfRexRM(pfx,modrm),
10107 loadLE(Ity_V128, mkexpr(addr)) );
10108 DIP("mov%s %s,%s\n", wot, dis_buf,
10109 nameXMMReg(gregOfRexRM(pfx,modrm)));
10110 delta += 2+alen;
10111 }
10112 goto decode_success;
10113 }
10114
sewardj4c328cf2005-05-05 12:05:54 +000010115 /* 66 0F 29 = MOVAPD -- move from G (xmm) to E (mem or xmm). */
sewardj240fd862005-11-01 18:59:38 +000010116 /* 66 0F 11 = MOVUPD -- move from G (xmm) to E (mem or xmm). */
10117 if (have66noF2noF3(pfx) && insn[0] == 0x0F
10118 && (insn[1] == 0x29 || insn[1] == 0x11)) {
sewardj4c328cf2005-05-05 12:05:54 +000010119 modrm = getUChar(delta+2);
10120 if (epartIsReg(modrm)) {
10121 /* fall through; awaiting test case */
10122 } else {
10123 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10124 storeLE( mkexpr(addr), getXMMReg(gregOfRexRM(pfx,modrm)) );
sewardj240fd862005-11-01 18:59:38 +000010125 DIP("mov[ua]pd %s,%s\n", nameXMMReg(gregOfRexRM(pfx,modrm)),
10126 dis_buf );
sewardj4c328cf2005-05-05 12:05:54 +000010127 delta += 2+alen;
10128 goto decode_success;
10129 }
10130 }
10131
sewardj09717342005-05-05 21:34:02 +000010132 /* 66 0F 6E = MOVD from ireg32/m32 to xmm lo 1/4, zeroing high 3/4 of xmm. */
10133 /* or from ireg64/m64 to xmm lo 1/2, zeroing high 1/2 of xmm. */
10134 if (have66noF2noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x6E) {
sewardj97628592005-05-10 22:42:54 +000010135 vassert(sz == 2 || sz == 8);
10136 if (sz == 2) sz = 4;
sewardj09717342005-05-05 21:34:02 +000010137 modrm = getUChar(delta+2);
10138 if (epartIsReg(modrm)) {
10139 delta += 2+1;
10140 if (sz == 4) {
sewardj09717342005-05-05 21:34:02 +000010141 putXMMReg(
10142 gregOfRexRM(pfx,modrm),
10143 unop( Iop_32UtoV128, getIReg32(eregOfRexRM(pfx,modrm)) )
10144 );
10145 DIP("movd %s, %s\n", nameIReg32(eregOfRexRM(pfx,modrm)),
10146 nameXMMReg(gregOfRexRM(pfx,modrm)));
10147 } else {
10148 putXMMReg(
10149 gregOfRexRM(pfx,modrm),
10150 unop( Iop_64UtoV128, getIReg64(eregOfRexRM(pfx,modrm)) )
10151 );
10152 DIP("movq %s, %s\n", nameIReg64(eregOfRexRM(pfx,modrm)),
10153 nameXMMReg(gregOfRexRM(pfx,modrm)));
10154 }
10155 } else {
10156 addr = disAMode( &alen, pfx, delta+2, dis_buf, 0 );
10157 delta += 2+alen;
10158 putXMMReg(
10159 gregOfRexRM(pfx,modrm),
10160 sz == 4
10161 ? unop( Iop_32UtoV128,loadLE(Ity_I32, mkexpr(addr)) )
10162 : unop( Iop_64UtoV128,loadLE(Ity_I64, mkexpr(addr)) )
10163 );
10164 DIP("mov%c %s, %s\n", sz == 4 ? 'd' : 'q', dis_buf,
10165 nameXMMReg(gregOfRexRM(pfx,modrm)));
10166 }
10167 goto decode_success;
10168 }
10169
10170 /* 66 0F 7E = MOVD from xmm low 1/4 to ireg32 or m32. */
10171 /* or from xmm low 1/2 to ireg64 or m64. */
10172 if (have66noF2noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x7E) {
10173 if (sz == 2) sz = 4;
10174 vassert(sz == 4 || sz == 8);
10175 modrm = getUChar(delta+2);
10176 if (epartIsReg(modrm)) {
10177 delta += 2+1;
10178 if (sz == 4) {
10179 putIReg32( eregOfRexRM(pfx,modrm),
10180 getXMMRegLane32(gregOfRexRM(pfx,modrm), 0) );
10181 DIP("movd %s, %s\n", nameXMMReg(gregOfRexRM(pfx,modrm)),
10182 nameIReg32(eregOfRexRM(pfx,modrm)));
10183 } else {
10184 putIReg64( eregOfRexRM(pfx,modrm),
10185 getXMMRegLane64(gregOfRexRM(pfx,modrm), 0) );
10186 DIP("movq %s, %s\n", nameXMMReg(gregOfRexRM(pfx,modrm)),
10187 nameIReg64(eregOfRexRM(pfx,modrm)));
10188 }
10189 } else {
10190 addr = disAMode( &alen, pfx, delta+2, dis_buf, 0 );
10191 delta += 2+alen;
10192 storeLE( mkexpr(addr),
10193 sz == 4
10194 ? getXMMRegLane32(gregOfRexRM(pfx,modrm),0)
10195 : getXMMRegLane64(gregOfRexRM(pfx,modrm),0) );
10196 DIP("mov%c %s, %s\n", sz == 4 ? 'd' : 'q',
10197 nameXMMReg(gregOfRexRM(pfx,modrm)), dis_buf);
10198 }
10199 goto decode_success;
10200 }
10201
10202 /* 66 0F 7F = MOVDQA -- move from G (xmm) to E (mem or xmm). */
10203 if (have66noF2noF3(pfx) && sz == 2
10204 && insn[0] == 0x0F && insn[1] == 0x7F) {
10205 modrm = getUChar(delta+2);
10206 if (epartIsReg(modrm)) {
10207 delta += 2+1;
10208 putXMMReg( eregOfRexRM(pfx,modrm),
10209 getXMMReg(gregOfRexRM(pfx,modrm)) );
10210 DIP("movdqa %s, %s\n", nameXMMReg(gregOfRexRM(pfx,modrm)),
10211 nameXMMReg(eregOfRexRM(pfx,modrm)));
10212 } else {
10213 addr = disAMode( &alen, pfx, delta+2, dis_buf, 0 );
10214 delta += 2+alen;
10215 storeLE( mkexpr(addr), getXMMReg(gregOfRexRM(pfx,modrm)) );
10216 DIP("movdqa %s, %s\n", nameXMMReg(gregOfRexRM(pfx,modrm)), dis_buf);
10217 }
10218 goto decode_success;
10219 }
10220
sewardj612be432005-05-11 02:55:54 +000010221 /* F3 0F 6F = MOVDQU -- move from E (mem or xmm) to G (xmm). */
10222 if (haveF3no66noF2(pfx) && sz == 4
10223 && insn[0] == 0x0F && insn[1] == 0x6F) {
10224 modrm = getUChar(delta+2);
10225 if (epartIsReg(modrm)) {
10226 putXMMReg( gregOfRexRM(pfx,modrm),
10227 getXMMReg( eregOfRexRM(pfx,modrm) ));
10228 DIP("movdqu %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
10229 nameXMMReg(gregOfRexRM(pfx,modrm)));
10230 delta += 2+1;
10231 } else {
10232 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10233 putXMMReg( gregOfRexRM(pfx,modrm),
10234 loadLE(Ity_V128, mkexpr(addr)) );
10235 DIP("movdqu %s,%s\n", dis_buf,
10236 nameXMMReg(gregOfRexRM(pfx,modrm)));
10237 delta += 2+alen;
10238 }
10239 goto decode_success;
10240 }
10241
10242 /* F3 0F 7F = MOVDQU -- move from G (xmm) to E (mem or xmm). */
10243 if (haveF3no66noF2(pfx) && sz == 4
10244 && insn[0] == 0x0F && insn[1] == 0x7F) {
10245 modrm = getUChar(delta+2);
10246 if (epartIsReg(modrm)) {
10247 goto decode_failure; /* awaiting test case */
10248 delta += 2+1;
10249 putXMMReg( eregOfRexRM(pfx,modrm),
10250 getXMMReg(gregOfRexRM(pfx,modrm)) );
10251 DIP("movdqu %s, %s\n", nameXMMReg(gregOfRexRM(pfx,modrm)),
10252 nameXMMReg(eregOfRexRM(pfx,modrm)));
10253 } else {
10254 addr = disAMode( &alen, pfx, delta+2, dis_buf, 0 );
10255 delta += 2+alen;
10256 storeLE( mkexpr(addr), getXMMReg(gregOfRexRM(pfx,modrm)) );
10257 DIP("movdqu %s, %s\n", nameXMMReg(gregOfRexRM(pfx,modrm)), dis_buf);
10258 }
10259 goto decode_success;
10260 }
10261
10262 /* F2 0F D6 = MOVDQ2Q -- move from E (lo half xmm, not mem) to G (mmx). */
10263 if (haveF2no66noF3(pfx) && sz == 4
10264 && insn[0] == 0x0F && insn[1] == 0xD6) {
10265 modrm = getUChar(delta+2);
10266 if (epartIsReg(modrm)) {
10267 do_MMX_preamble();
10268 putMMXReg( gregLO3ofRM(modrm),
10269 getXMMRegLane64( eregOfRexRM(pfx,modrm), 0 ));
10270 DIP("movdq2q %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
10271 nameMMXReg(gregLO3ofRM(modrm)));
10272 delta += 2+1;
10273 goto decode_success;
10274 } else {
10275 /* apparently no mem case for this insn */
10276 goto decode_failure;
10277 }
10278 }
sewardj4c328cf2005-05-05 12:05:54 +000010279
10280 /* 66 0F 16 = MOVHPD -- move from mem to high half of XMM. */
10281 /* These seems identical to MOVHPS. This instruction encoding is
10282 completely crazy. */
10283 if (have66noF2noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x16) {
10284 modrm = getUChar(delta+2);
10285 if (epartIsReg(modrm)) {
10286 /* fall through; apparently reg-reg is not possible */
10287 } else {
10288 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10289 delta += 2+alen;
10290 putXMMRegLane64( gregOfRexRM(pfx,modrm), 1/*upper lane*/,
10291 loadLE(Ity_I64, mkexpr(addr)) );
10292 DIP("movhpd %s,%s\n", dis_buf,
10293 nameXMMReg( gregOfRexRM(pfx,modrm) ));
10294 goto decode_success;
10295 }
10296 }
10297
10298 /* 66 0F 17 = MOVHPD -- move from high half of XMM to mem. */
10299 /* Again, this seems identical to MOVHPS. */
10300 if (have66noF2noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x17) {
10301 if (!epartIsReg(insn[2])) {
10302 delta += 2;
10303 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
10304 delta += alen;
10305 storeLE( mkexpr(addr),
10306 getXMMRegLane64( gregOfRexRM(pfx,insn[2]),
10307 1/*upper lane*/ ) );
10308 DIP("movhpd %s,%s\n", nameXMMReg( gregOfRexRM(pfx,insn[2]) ),
10309 dis_buf);
10310 goto decode_success;
10311 }
10312 /* else fall through */
10313 }
sewardj1001dc42005-02-21 08:25:55 +000010314
10315 /* 66 0F 12 = MOVLPD -- move from mem to low half of XMM. */
10316 /* Identical to MOVLPS ? */
10317 if (have66noF2noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x12) {
10318 modrm = getUChar(delta+2);
10319 if (epartIsReg(modrm)) {
10320 /* fall through; apparently reg-reg is not possible */
10321 } else {
10322 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10323 delta += 2+alen;
10324 putXMMRegLane64( gregOfRexRM(pfx,modrm),
10325 0/*lower lane*/,
10326 loadLE(Ity_I64, mkexpr(addr)) );
10327 DIP("movlpd %s, %s\n",
10328 dis_buf, nameXMMReg( gregOfRexRM(pfx,modrm) ));
10329 goto decode_success;
10330 }
10331 }
10332
sewardj4c328cf2005-05-05 12:05:54 +000010333 /* 66 0F 13 = MOVLPD -- move from low half of XMM to mem. */
10334 /* Identical to MOVLPS ? */
10335 if (have66noF2noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x13) {
10336 modrm = getUChar(delta+2);
10337 if (!epartIsReg(modrm)) {
10338 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10339 delta += 2+alen;
10340 storeLE( mkexpr(addr),
10341 getXMMRegLane64( gregOfRexRM(pfx,modrm),
10342 0/*lower lane*/ ) );
10343 DIP("movlpd %s, %s\n", nameXMMReg( gregOfRexRM(pfx,modrm) ),
10344 dis_buf);
10345 goto decode_success;
10346 }
10347 /* else fall through */
10348 }
10349
sewardj612be432005-05-11 02:55:54 +000010350 /* 66 0F 50 = MOVMSKPD - move 2 sign bits from 2 x F64 in xmm(E) to
10351 2 lowest bits of ireg(G) */
sewardjae84d782006-04-13 22:06:35 +000010352 if (have66noF2noF3(pfx) && (sz == 2 || sz == 8)
sewardj612be432005-05-11 02:55:54 +000010353 && insn[0] == 0x0F && insn[1] == 0x50) {
sewardjae84d782006-04-13 22:06:35 +000010354 /* sz == 8 is a kludge to handle insns with REX.W redundantly
10355 set to 1, which has been known to happen:
10356 66 4c 0f 50 d9 rex64X movmskpd %xmm1,%r11d
10357 */
sewardj612be432005-05-11 02:55:54 +000010358 modrm = getUChar(delta+2);
10359 if (epartIsReg(modrm)) {
10360 Int src;
10361 t0 = newTemp(Ity_I32);
10362 t1 = newTemp(Ity_I32);
10363 delta += 2+1;
10364 src = eregOfRexRM(pfx,modrm);
10365 assign( t0, binop( Iop_And32,
10366 binop(Iop_Shr32, getXMMRegLane32(src,1), mkU8(31)),
10367 mkU32(1) ));
10368 assign( t1, binop( Iop_And32,
10369 binop(Iop_Shr32, getXMMRegLane32(src,3), mkU8(30)),
10370 mkU32(2) ));
10371 putIReg32( gregOfRexRM(pfx,modrm),
10372 binop(Iop_Or32, mkexpr(t0), mkexpr(t1))
10373 );
10374 DIP("movmskpd %s,%s\n", nameXMMReg(src),
10375 nameIReg32(gregOfRexRM(pfx,modrm)));
10376 goto decode_success;
10377 }
10378 /* else fall through */
10379 goto decode_failure;
10380 }
10381
10382 /* 66 0F E7 = MOVNTDQ -- for us, just a plain SSE store. */
10383 if (have66noF2noF3(pfx) && sz == 2
10384 && insn[0] == 0x0F && insn[1] == 0xE7) {
10385 modrm = getUChar(delta+2);
10386 if (!epartIsReg(modrm)) {
10387 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10388 storeLE( mkexpr(addr), getXMMReg(gregOfRexRM(pfx,modrm)) );
10389 DIP("movntdq %s,%s\n", dis_buf,
10390 nameXMMReg(gregOfRexRM(pfx,modrm)));
10391 delta += 2+alen;
10392 goto decode_success;
10393 }
10394 /* else fall through */
10395 goto decode_failure;
10396 }
sewardjf53b7352005-04-06 20:01:56 +000010397
10398 /* 0F C3 = MOVNTI -- for us, just a plain ireg store. */
10399 if (haveNo66noF2noF3(pfx) &&
10400 insn[0] == 0x0F && insn[1] == 0xC3) {
10401 vassert(sz == 4 || sz == 8);
10402 modrm = getUChar(delta+2);
10403 if (!epartIsReg(modrm)) {
10404 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10405 storeLE( mkexpr(addr), getIRegG(sz, pfx, modrm) );
10406 DIP("movnti %s,%s\n", dis_buf,
10407 nameIRegG(sz, pfx, modrm));
10408 delta += 2+alen;
10409 goto decode_success;
10410 }
10411 /* else fall through */
10412 }
sewardj5cc00ff2005-03-27 04:48:32 +000010413
10414 /* 66 0F D6 = MOVQ -- move 64 bits from G (lo half xmm) to E (mem
10415 or lo half xmm). */
10416 if (have66noF2noF3(pfx) && insn[0] == 0x0F && insn[1] == 0xD6) {
10417 vassert(sz == 2);
10418 modrm = getUChar(delta+2);
10419 if (epartIsReg(modrm)) {
10420 /* fall through, awaiting test case */
sewardj94a48b22005-05-14 11:17:25 +000010421 /* dst: lo half copied, hi half zeroed */
sewardj5cc00ff2005-03-27 04:48:32 +000010422 } else {
10423 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10424 storeLE( mkexpr(addr),
10425 getXMMRegLane64( gregOfRexRM(pfx,modrm), 0 ));
10426 DIP("movq %s,%s\n", nameXMMReg(gregOfRexRM(pfx,modrm)), dis_buf );
10427 delta += 2+alen;
10428 goto decode_success;
10429 }
10430 }
10431
sewardj612be432005-05-11 02:55:54 +000010432 /* F3 0F D6 = MOVQ2DQ -- move from E (mmx) to G (lo half xmm, zero
10433 hi half). */
10434 if (haveF3no66noF2(pfx) && sz == 4
10435 && insn[0] == 0x0F && insn[1] == 0xD6) {
10436 modrm = getUChar(delta+2);
10437 if (epartIsReg(modrm)) {
10438 do_MMX_preamble();
10439 putXMMReg( gregOfRexRM(pfx,modrm),
10440 unop(Iop_64UtoV128, getMMXReg( eregLO3ofRM(modrm) )) );
10441 DIP("movq2dq %s,%s\n", nameMMXReg(eregLO3ofRM(modrm)),
10442 nameXMMReg(gregOfRexRM(pfx,modrm)));
10443 delta += 2+1;
10444 goto decode_success;
10445 } else {
10446 /* apparently no mem case for this insn */
10447 goto decode_failure;
10448 }
10449 }
10450
10451 /* F3 0F 7E = MOVQ -- move 64 bits from E (mem or lo half xmm) to
sewardj94a48b22005-05-14 11:17:25 +000010452 G (lo half xmm). Upper half of G is zeroed out. */
sewardj1001dc42005-02-21 08:25:55 +000010453 /* F2 0F 10 = MOVSD -- move 64 bits from E (mem or lo half xmm) to
10454 G (lo half xmm). If E is mem, upper half of G is zeroed out.
sewardj94a48b22005-05-14 11:17:25 +000010455 If E is reg, upper half of G is unchanged. */
sewardj612be432005-05-11 02:55:54 +000010456 if ( (haveF2no66noF3(pfx) && sz == 4
10457 && insn[0] == 0x0F && insn[1] == 0x10)
sewardj5cc00ff2005-03-27 04:48:32 +000010458 ||
sewardj612be432005-05-11 02:55:54 +000010459 (haveF3no66noF2(pfx) && sz == 4
10460 && insn[0] == 0x0F && insn[1] == 0x7E)
sewardj1001dc42005-02-21 08:25:55 +000010461 ) {
sewardj1001dc42005-02-21 08:25:55 +000010462 modrm = getUChar(delta+2);
10463 if (epartIsReg(modrm)) {
10464 putXMMRegLane64( gregOfRexRM(pfx,modrm), 0,
10465 getXMMRegLane64( eregOfRexRM(pfx,modrm), 0 ));
sewardj94a48b22005-05-14 11:17:25 +000010466 if (insn[1] == 0x7E/*MOVQ*/) {
10467 /* zero bits 127:64 */
10468 putXMMRegLane64( gregOfRexRM(pfx,modrm), 1, mkU64(0) );
10469 }
sewardj1001dc42005-02-21 08:25:55 +000010470 DIP("movsd %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
10471 nameXMMReg(gregOfRexRM(pfx,modrm)));
10472 delta += 2+1;
10473 } else {
10474 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10475 putXMMReg( gregOfRexRM(pfx,modrm), mkV128(0) );
10476 putXMMRegLane64( gregOfRexRM(pfx,modrm), 0,
10477 loadLE(Ity_I64, mkexpr(addr)) );
10478 DIP("movsd %s,%s\n", dis_buf,
10479 nameXMMReg(gregOfRexRM(pfx,modrm)));
10480 delta += 2+alen;
10481 }
10482 goto decode_success;
10483 }
10484
10485 /* F2 0F 11 = MOVSD -- move 64 bits from G (lo half xmm) to E (mem
10486 or lo half xmm). */
sewardj8d965312005-02-25 02:48:47 +000010487 if (haveF2no66noF3(pfx) && sz == 4
10488 && insn[0] == 0x0F && insn[1] == 0x11) {
sewardj1001dc42005-02-21 08:25:55 +000010489 modrm = getUChar(delta+2);
10490 if (epartIsReg(modrm)) {
10491 /* fall through, we don't yet have a test case */
10492 } else {
10493 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10494 storeLE( mkexpr(addr),
10495 getXMMRegLane64(gregOfRexRM(pfx,modrm), 0) );
10496 DIP("movsd %s,%s\n", nameXMMReg(gregOfRexRM(pfx,modrm)),
10497 dis_buf);
10498 delta += 2+alen;
10499 goto decode_success;
10500 }
10501 }
10502
sewardj4c328cf2005-05-05 12:05:54 +000010503 /* 66 0F 59 = MULPD -- mul 64Fx2 from R/M to R */
10504 if (have66noF2noF3(pfx) && sz == 2
10505 && insn[0] == 0x0F && insn[1] == 0x59) {
10506 delta = dis_SSE_E_to_G_all( pfx, delta+2, "mulpd", Iop_Mul64Fx2 );
10507 goto decode_success;
10508 }
sewardj1001dc42005-02-21 08:25:55 +000010509
10510 /* F2 0F 59 = MULSD -- mul 64F0x2 from R/M to R */
sewardj8d965312005-02-25 02:48:47 +000010511 if (haveF2no66noF3(pfx) && sz == 4
10512 && insn[0] == 0x0F && insn[1] == 0x59) {
sewardj1001dc42005-02-21 08:25:55 +000010513 delta = dis_SSE_E_to_G_lo64( pfx, delta+2, "mulsd", Iop_Mul64F0x2 );
10514 goto decode_success;
10515 }
10516
sewardj8d965312005-02-25 02:48:47 +000010517 /* 66 0F 56 = ORPD -- G = G and E */
10518 if (have66noF2noF3(pfx) && sz == 2
10519 && insn[0] == 0x0F && insn[1] == 0x56) {
10520 delta = dis_SSE_E_to_G_all( pfx, delta+2, "orpd", Iop_OrV128 );
10521 goto decode_success;
10522 }
10523
sewardj09717342005-05-05 21:34:02 +000010524 /* 66 0F C6 /r ib = SHUFPD -- shuffle packed F64s */
10525 if (have66noF2noF3(pfx) && sz == 2
10526 && insn[0] == 0x0F && insn[1] == 0xC6) {
10527 Int select;
10528 IRTemp sV = newTemp(Ity_V128);
10529 IRTemp dV = newTemp(Ity_V128);
10530 IRTemp s1 = newTemp(Ity_I64);
10531 IRTemp s0 = newTemp(Ity_I64);
10532 IRTemp d1 = newTemp(Ity_I64);
10533 IRTemp d0 = newTemp(Ity_I64);
10534
10535 modrm = insn[2];
10536 assign( dV, getXMMReg(gregOfRexRM(pfx,modrm)) );
10537
10538 if (epartIsReg(modrm)) {
10539 assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
10540 select = (Int)insn[3];
10541 delta += 2+2;
10542 DIP("shufpd $%d,%s,%s\n", select,
10543 nameXMMReg(eregOfRexRM(pfx,modrm)),
10544 nameXMMReg(gregOfRexRM(pfx,modrm)));
10545 } else {
10546 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 1 );
10547 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
10548 select = (Int)insn[2+alen];
10549 delta += 3+alen;
10550 DIP("shufpd $%d,%s,%s\n", select,
10551 dis_buf,
10552 nameXMMReg(gregOfRexRM(pfx,modrm)));
10553 }
10554
10555 assign( d1, unop(Iop_V128HIto64, mkexpr(dV)) );
10556 assign( d0, unop(Iop_V128to64, mkexpr(dV)) );
10557 assign( s1, unop(Iop_V128HIto64, mkexpr(sV)) );
10558 assign( s0, unop(Iop_V128to64, mkexpr(sV)) );
10559
10560# define SELD(n) mkexpr((n)==0 ? d0 : d1)
10561# define SELS(n) mkexpr((n)==0 ? s0 : s1)
10562
10563 putXMMReg(
10564 gregOfRexRM(pfx,modrm),
10565 binop(Iop_64HLtoV128, SELS((select>>1)&1), SELD((select>>0)&1) )
10566 );
10567
10568# undef SELD
10569# undef SELS
10570
10571 goto decode_success;
10572 }
10573
sewardj97628592005-05-10 22:42:54 +000010574 /* 66 0F 51 = SQRTPD -- approx sqrt 64Fx2 from R/M to R */
10575 if (have66noF2noF3(pfx) && sz == 2
10576 && insn[0] == 0x0F && insn[1] == 0x51) {
10577 delta = dis_SSE_E_to_G_unary_all( pfx, delta+2,
10578 "sqrtpd", Iop_Sqrt64Fx2 );
10579 goto decode_success;
10580 }
sewardj1001dc42005-02-21 08:25:55 +000010581
10582 /* F2 0F 51 = SQRTSD -- approx sqrt 64F0x2 from R/M to R */
10583 if (haveF2no66noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x51) {
10584 vassert(sz == 4);
10585 delta = dis_SSE_E_to_G_unary_lo64( pfx, delta+2,
10586 "sqrtsd", Iop_Sqrt64F0x2 );
10587 goto decode_success;
10588 }
10589
sewardj4c328cf2005-05-05 12:05:54 +000010590 /* 66 0F 5C = SUBPD -- sub 64Fx2 from R/M to R */
10591 if (have66noF2noF3(pfx) && sz == 2
10592 && insn[0] == 0x0F && insn[1] == 0x5C) {
10593 delta = dis_SSE_E_to_G_all( pfx, delta+2, "subpd", Iop_Sub64Fx2 );
10594 goto decode_success;
10595 }
sewardj1001dc42005-02-21 08:25:55 +000010596
10597 /* F2 0F 5C = SUBSD -- sub 64F0x2 from R/M to R */
10598 if (haveF2no66noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x5C) {
10599 vassert(sz == 4);
10600 delta = dis_SSE_E_to_G_lo64( pfx, delta+2, "subsd", Iop_Sub64F0x2 );
10601 goto decode_success;
10602 }
10603
sewardj1a01e652005-02-23 11:39:21 +000010604 /* 66 0F 15 = UNPCKHPD -- unpack and interleave high part F64s */
10605 /* 66 0F 14 = UNPCKLPD -- unpack and interleave low part F64s */
10606 /* These just appear to be special cases of SHUFPS */
10607 if (have66noF2noF3(pfx)
10608 && sz == 2 /* could be 8 if rex also present */
10609 && insn[0] == 0x0F && (insn[1] == 0x15 || insn[1] == 0x14)) {
10610 IRTemp s1 = newTemp(Ity_I64);
10611 IRTemp s0 = newTemp(Ity_I64);
10612 IRTemp d1 = newTemp(Ity_I64);
10613 IRTemp d0 = newTemp(Ity_I64);
10614 IRTemp sV = newTemp(Ity_V128);
10615 IRTemp dV = newTemp(Ity_V128);
sewardj1027dc22005-02-26 01:55:02 +000010616 Bool hi = toBool(insn[1] == 0x15);
sewardj1a01e652005-02-23 11:39:21 +000010617
10618 modrm = insn[2];
10619 assign( dV, getXMMReg(gregOfRexRM(pfx,modrm)) );
10620
10621 if (epartIsReg(modrm)) {
10622 assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
10623 delta += 2+1;
10624 DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
10625 nameXMMReg(eregOfRexRM(pfx,modrm)),
10626 nameXMMReg(gregOfRexRM(pfx,modrm)));
10627 } else {
10628 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10629 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
10630 delta += 2+alen;
10631 DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
10632 dis_buf,
10633 nameXMMReg(gregOfRexRM(pfx,modrm)));
10634 }
10635
10636 assign( d1, unop(Iop_V128HIto64, mkexpr(dV)) );
10637 assign( d0, unop(Iop_V128to64, mkexpr(dV)) );
10638 assign( s1, unop(Iop_V128HIto64, mkexpr(sV)) );
10639 assign( s0, unop(Iop_V128to64, mkexpr(sV)) );
10640
10641 if (hi) {
10642 putXMMReg( gregOfRexRM(pfx,modrm),
10643 binop(Iop_64HLtoV128, mkexpr(s1), mkexpr(d1)) );
10644 } else {
10645 putXMMReg( gregOfRexRM(pfx,modrm),
10646 binop(Iop_64HLtoV128, mkexpr(s0), mkexpr(d0)) );
10647 }
10648
10649 goto decode_success;
10650 }
sewardj9da16972005-02-21 13:58:26 +000010651
10652 /* 66 0F 57 = XORPD -- G = G xor E */
sewardj97628592005-05-10 22:42:54 +000010653 if (have66noF2noF3(pfx) && sz == 2
10654 && insn[0] == 0x0F && insn[1] == 0x57) {
sewardj9da16972005-02-21 13:58:26 +000010655 delta = dis_SSE_E_to_G_all( pfx, delta+2, "xorpd", Iop_XorV128 );
10656 goto decode_success;
10657 }
10658
sewardj97628592005-05-10 22:42:54 +000010659 /* 66 0F 6B = PACKSSDW */
10660 if (have66noF2noF3(pfx) && sz == 2
10661 && insn[0] == 0x0F && insn[1] == 0x6B) {
10662 delta = dis_SSEint_E_to_G( pfx, delta+2,
10663 "packssdw", Iop_QNarrow32Sx4, True );
10664 goto decode_success;
10665 }
10666
10667 /* 66 0F 63 = PACKSSWB */
10668 if (have66noF2noF3(pfx) && sz == 2
10669 && insn[0] == 0x0F && insn[1] == 0x63) {
10670 delta = dis_SSEint_E_to_G( pfx, delta+2,
10671 "packsswb", Iop_QNarrow16Sx8, True );
10672 goto decode_success;
10673 }
10674
10675 /* 66 0F 67 = PACKUSWB */
10676 if (have66noF2noF3(pfx) && sz == 2
10677 && insn[0] == 0x0F && insn[1] == 0x67) {
10678 delta = dis_SSEint_E_to_G( pfx, delta+2,
10679 "packuswb", Iop_QNarrow16Ux8, True );
10680 goto decode_success;
10681 }
10682
10683 /* 66 0F FC = PADDB */
10684 if (have66noF2noF3(pfx) && sz == 2
10685 && insn[0] == 0x0F && insn[1] == 0xFC) {
10686 delta = dis_SSEint_E_to_G( pfx, delta+2,
10687 "paddb", Iop_Add8x16, False );
10688 goto decode_success;
10689 }
10690
10691 /* 66 0F FE = PADDD */
10692 if (have66noF2noF3(pfx) && sz == 2
10693 && insn[0] == 0x0F && insn[1] == 0xFE) {
10694 delta = dis_SSEint_E_to_G( pfx, delta+2,
10695 "paddd", Iop_Add32x4, False );
10696 goto decode_success;
10697 }
sewardj8711f662005-05-09 17:52:56 +000010698
10699 /* ***--- this is an MMX class insn introduced in SSE2 ---*** */
10700 /* 0F D4 = PADDQ -- add 64x1 */
10701 if (haveNo66noF2noF3(pfx) && sz == 4
10702 && insn[0] == 0x0F && insn[1] == 0xD4) {
10703 do_MMX_preamble();
10704 delta = dis_MMXop_regmem_to_reg (
10705 pfx, delta+2, insn[1], "paddq", False );
10706 goto decode_success;
10707 }
sewardj09717342005-05-05 21:34:02 +000010708
10709 /* 66 0F D4 = PADDQ */
10710 if (have66noF2noF3(pfx) && sz == 2
10711 && insn[0] == 0x0F && insn[1] == 0xD4) {
10712 delta = dis_SSEint_E_to_G( pfx, delta+2,
10713 "paddq", Iop_Add64x2, False );
10714 goto decode_success;
10715 }
10716
sewardj5992bd02005-05-11 02:13:42 +000010717 /* 66 0F FD = PADDW */
10718 if (have66noF2noF3(pfx) && sz == 2
10719 && insn[0] == 0x0F && insn[1] == 0xFD) {
10720 delta = dis_SSEint_E_to_G( pfx, delta+2,
10721 "paddw", Iop_Add16x8, False );
10722 goto decode_success;
10723 }
10724
10725 /* 66 0F EC = PADDSB */
10726 if (have66noF2noF3(pfx) && sz == 2
10727 && insn[0] == 0x0F && insn[1] == 0xEC) {
10728 delta = dis_SSEint_E_to_G( pfx, delta+2,
10729 "paddsb", Iop_QAdd8Sx16, False );
10730 goto decode_success;
10731 }
10732
10733 /* 66 0F ED = PADDSW */
10734 if (have66noF2noF3(pfx) && sz == 2
10735 && insn[0] == 0x0F && insn[1] == 0xED) {
10736 delta = dis_SSEint_E_to_G( pfx, delta+2,
10737 "paddsw", Iop_QAdd16Sx8, False );
10738 goto decode_success;
10739 }
10740
10741 /* 66 0F DC = PADDUSB */
10742 if (have66noF2noF3(pfx) && sz == 2
10743 && insn[0] == 0x0F && insn[1] == 0xDC) {
10744 delta = dis_SSEint_E_to_G( pfx, delta+2,
10745 "paddusb", Iop_QAdd8Ux16, False );
10746 goto decode_success;
10747 }
10748
10749 /* 66 0F DD = PADDUSW */
10750 if (have66noF2noF3(pfx) && sz == 2
10751 && insn[0] == 0x0F && insn[1] == 0xDD) {
10752 delta = dis_SSEint_E_to_G( pfx, delta+2,
10753 "paddusw", Iop_QAdd16Ux8, False );
10754 goto decode_success;
10755 }
sewardj09717342005-05-05 21:34:02 +000010756
10757 /* 66 0F DB = PAND */
10758 if (have66noF2noF3(pfx) && sz == 2
10759 && insn[0] == 0x0F && insn[1] == 0xDB) {
10760 delta = dis_SSE_E_to_G_all( pfx, delta+2, "pand", Iop_AndV128 );
10761 goto decode_success;
10762 }
10763
sewardj5992bd02005-05-11 02:13:42 +000010764 /* 66 0F DF = PANDN */
10765 if (have66noF2noF3(pfx) && sz == 2
10766 && insn[0] == 0x0F && insn[1] == 0xDF) {
10767 delta = dis_SSE_E_to_G_all_invG( pfx, delta+2, "pandn", Iop_AndV128 );
10768 goto decode_success;
10769 }
10770
10771 /* 66 0F E0 = PAVGB */
10772 if (have66noF2noF3(pfx) && sz == 2
10773 && insn[0] == 0x0F && insn[1] == 0xE0) {
10774 delta = dis_SSEint_E_to_G( pfx, delta+2,
10775 "pavgb", Iop_Avg8Ux16, False );
10776 goto decode_success;
10777 }
10778
10779 /* 66 0F E3 = PAVGW */
10780 if (have66noF2noF3(pfx) && sz == 2
10781 && insn[0] == 0x0F && insn[1] == 0xE3) {
10782 delta = dis_SSEint_E_to_G( pfx, delta+2,
10783 "pavgw", Iop_Avg16Ux8, False );
10784 goto decode_success;
10785 }
10786
10787 /* 66 0F 74 = PCMPEQB */
10788 if (have66noF2noF3(pfx) && sz == 2
10789 && insn[0] == 0x0F && insn[1] == 0x74) {
10790 delta = dis_SSEint_E_to_G( pfx, delta+2,
10791 "pcmpeqb", Iop_CmpEQ8x16, False );
10792 goto decode_success;
10793 }
10794
10795 /* 66 0F 76 = PCMPEQD */
10796 if (have66noF2noF3(pfx) && sz == 2
10797 && insn[0] == 0x0F && insn[1] == 0x76) {
10798 delta = dis_SSEint_E_to_G( pfx, delta+2,
10799 "pcmpeqd", Iop_CmpEQ32x4, False );
10800 goto decode_success;
10801 }
10802
10803 /* 66 0F 75 = PCMPEQW */
10804 if (have66noF2noF3(pfx) && sz == 2
10805 && insn[0] == 0x0F && insn[1] == 0x75) {
10806 delta = dis_SSEint_E_to_G( pfx, delta+2,
10807 "pcmpeqw", Iop_CmpEQ16x8, False );
10808 goto decode_success;
10809 }
10810
10811 /* 66 0F 64 = PCMPGTB */
10812 if (have66noF2noF3(pfx) && sz == 2
10813 && insn[0] == 0x0F && insn[1] == 0x64) {
10814 delta = dis_SSEint_E_to_G( pfx, delta+2,
10815 "pcmpgtb", Iop_CmpGT8Sx16, False );
10816 goto decode_success;
10817 }
10818
10819 /* 66 0F 66 = PCMPGTD */
10820 if (have66noF2noF3(pfx) && sz == 2
10821 && insn[0] == 0x0F && insn[1] == 0x66) {
10822 delta = dis_SSEint_E_to_G( pfx, delta+2,
10823 "pcmpgtd", Iop_CmpGT32Sx4, False );
10824 goto decode_success;
10825 }
10826
10827 /* 66 0F 65 = PCMPGTW */
10828 if (have66noF2noF3(pfx) && sz == 2
10829 && insn[0] == 0x0F && insn[1] == 0x65) {
10830 delta = dis_SSEint_E_to_G( pfx, delta+2,
10831 "pcmpgtw", Iop_CmpGT16Sx8, False );
10832 goto decode_success;
10833 }
sewardj97628592005-05-10 22:42:54 +000010834
10835 /* 66 0F C5 = PEXTRW -- extract 16-bit field from xmm(E) and put
10836 zero-extend of it in ireg(G). */
10837 if (have66noF2noF3(pfx) && sz == 2
10838 && insn[0] == 0x0F && insn[1] == 0xC5) {
10839 modrm = insn[2];
10840 if (epartIsReg(modrm)) {
10841 t5 = newTemp(Ity_V128);
10842 t4 = newTemp(Ity_I16);
10843 assign(t5, getXMMReg(eregOfRexRM(pfx,modrm)));
10844 breakup128to32s( t5, &t3, &t2, &t1, &t0 );
10845 switch (insn[3] & 7) {
10846 case 0: assign(t4, unop(Iop_32to16, mkexpr(t0))); break;
10847 case 1: assign(t4, unop(Iop_32HIto16, mkexpr(t0))); break;
10848 case 2: assign(t4, unop(Iop_32to16, mkexpr(t1))); break;
10849 case 3: assign(t4, unop(Iop_32HIto16, mkexpr(t1))); break;
10850 case 4: assign(t4, unop(Iop_32to16, mkexpr(t2))); break;
10851 case 5: assign(t4, unop(Iop_32HIto16, mkexpr(t2))); break;
10852 case 6: assign(t4, unop(Iop_32to16, mkexpr(t3))); break;
10853 case 7: assign(t4, unop(Iop_32HIto16, mkexpr(t3))); break;
10854 default: vassert(0);
10855 }
10856 putIReg32(gregOfRexRM(pfx,modrm), unop(Iop_16Uto32, mkexpr(t4)));
10857 DIP("pextrw $%d,%s,%s\n",
10858 (Int)insn[3], nameXMMReg(eregOfRexRM(pfx,modrm)),
10859 nameIReg32(gregOfRexRM(pfx,modrm)));
10860 delta += 4;
10861 goto decode_success;
10862 }
10863 /* else fall through */
10864 /* note, if memory case is ever filled in, there is 1 byte after
10865 amode */
10866 }
10867
10868 /* 66 0F C4 = PINSRW -- get 16 bits from E(mem or low half ireg) and
10869 put it into the specified lane of xmm(G). */
10870 if (have66noF2noF3(pfx) && sz == 2
10871 && insn[0] == 0x0F && insn[1] == 0xC4) {
10872 Int lane;
10873 t4 = newTemp(Ity_I16);
10874 modrm = insn[2];
10875
10876 if (epartIsReg(modrm)) {
10877 assign(t4, getIReg16(eregOfRexRM(pfx,modrm)));
10878 delta += 3+1;
10879 lane = insn[3+1-1];
10880 DIP("pinsrw $%d,%s,%s\n", (Int)lane,
10881 nameIReg16(eregOfRexRM(pfx,modrm)),
10882 nameXMMReg(gregOfRexRM(pfx,modrm)));
10883 } else {
10884 addr = disAMode ( &alen, pfx, delta+2, dis_buf,
10885 1/*byte after the amode*/ );
10886 delta += 3+alen;
10887 lane = insn[3+alen-1];
10888 assign(t4, loadLE(Ity_I16, mkexpr(addr)));
10889 DIP("pinsrw $%d,%s,%s\n", (Int)lane,
10890 dis_buf,
10891 nameXMMReg(gregOfRexRM(pfx,modrm)));
10892 }
10893
10894 putXMMRegLane16( gregOfRexRM(pfx,modrm), lane & 7, mkexpr(t4) );
10895 goto decode_success;
10896 }
10897
sewardjdb859032006-04-08 16:15:53 +000010898 /* 66 0F F5 = PMADDWD -- Multiply and add packed integers from
10899 E(xmm or mem) to G(xmm) */
10900 if (have66noF2noF3(pfx) && sz == 2
10901 && insn[0] == 0x0F && insn[1] == 0xF5) {
10902 IRTemp s1V = newTemp(Ity_V128);
10903 IRTemp s2V = newTemp(Ity_V128);
10904 IRTemp dV = newTemp(Ity_V128);
10905 IRTemp s1Hi = newTemp(Ity_I64);
10906 IRTemp s1Lo = newTemp(Ity_I64);
10907 IRTemp s2Hi = newTemp(Ity_I64);
10908 IRTemp s2Lo = newTemp(Ity_I64);
10909 IRTemp dHi = newTemp(Ity_I64);
10910 IRTemp dLo = newTemp(Ity_I64);
10911 modrm = insn[2];
10912 if (epartIsReg(modrm)) {
10913 assign( s1V, getXMMReg(eregOfRexRM(pfx,modrm)) );
10914 delta += 2+1;
10915 DIP("pmaddwd %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
10916 nameXMMReg(gregOfRexRM(pfx,modrm)));
10917 } else {
10918 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
10919 assign( s1V, loadLE(Ity_V128, mkexpr(addr)) );
10920 delta += 2+alen;
10921 DIP("pmaddwd %s,%s\n", dis_buf,
10922 nameXMMReg(gregOfRexRM(pfx,modrm)));
10923 }
10924 assign( s2V, getXMMReg(gregOfRexRM(pfx,modrm)) );
10925 assign( s1Hi, unop(Iop_V128HIto64, mkexpr(s1V)) );
10926 assign( s1Lo, unop(Iop_V128to64, mkexpr(s1V)) );
10927 assign( s2Hi, unop(Iop_V128HIto64, mkexpr(s2V)) );
10928 assign( s2Lo, unop(Iop_V128to64, mkexpr(s2V)) );
10929 assign( dHi, mkIRExprCCall(
10930 Ity_I64, 0/*regparms*/,
10931 "amd64g_calculate_mmx_pmaddwd",
10932 &amd64g_calculate_mmx_pmaddwd,
10933 mkIRExprVec_2( mkexpr(s1Hi), mkexpr(s2Hi))
10934 ));
10935 assign( dLo, mkIRExprCCall(
10936 Ity_I64, 0/*regparms*/,
10937 "amd64g_calculate_mmx_pmaddwd",
10938 &amd64g_calculate_mmx_pmaddwd,
10939 mkIRExprVec_2( mkexpr(s1Lo), mkexpr(s2Lo))
10940 ));
10941 assign( dV, binop(Iop_64HLtoV128, mkexpr(dHi), mkexpr(dLo))) ;
10942 putXMMReg(gregOfRexRM(pfx,modrm), mkexpr(dV));
10943 goto decode_success;
10944 }
10945
sewardjadffcef2005-05-11 00:03:06 +000010946 /* 66 0F EE = PMAXSW -- 16x8 signed max */
10947 if (have66noF2noF3(pfx) && sz == 2
10948 && insn[0] == 0x0F && insn[1] == 0xEE) {
10949 delta = dis_SSEint_E_to_G( pfx, delta+2,
10950 "pmaxsw", Iop_Max16Sx8, False );
10951 goto decode_success;
10952 }
10953
10954 /* 66 0F DE = PMAXUB -- 8x16 unsigned max */
10955 if (have66noF2noF3(pfx) && sz == 2
10956 && insn[0] == 0x0F && insn[1] == 0xDE) {
10957 delta = dis_SSEint_E_to_G( pfx, delta+2,
10958 "pmaxub", Iop_Max8Ux16, False );
10959 goto decode_success;
10960 }
10961
10962 /* 66 0F EA = PMINSW -- 16x8 signed min */
10963 if (have66noF2noF3(pfx) && sz == 2
10964 && insn[0] == 0x0F && insn[1] == 0xEA) {
10965 delta = dis_SSEint_E_to_G( pfx, delta+2,
10966 "pminsw", Iop_Min16Sx8, False );
10967 goto decode_success;
10968 }
10969
10970 /* 66 0F DA = PMINUB -- 8x16 unsigned min */
10971 if (have66noF2noF3(pfx) && sz == 2
10972 && insn[0] == 0x0F && insn[1] == 0xDA) {
10973 delta = dis_SSEint_E_to_G( pfx, delta+2,
10974 "pminub", Iop_Min8Ux16, False );
10975 goto decode_success;
10976 }
10977
10978 /* 66 0F D7 = PMOVMSKB -- extract sign bits from each of 16 lanes in
10979 xmm(E), turn them into a byte, and put zero-extend of it in
10980 ireg(G). Doing this directly is just too cumbersome; give up
10981 therefore and call a helper. */
10982 /* UInt x86g_calculate_sse_pmovmskb ( ULong w64hi, ULong w64lo ); */
10983 if (have66noF2noF3(pfx) && sz == 2
10984 && insn[0] == 0x0F && insn[1] == 0xD7) {
10985 modrm = insn[2];
10986 if (epartIsReg(modrm)) {
10987 t0 = newTemp(Ity_I64);
10988 t1 = newTemp(Ity_I64);
10989 assign(t0, getXMMRegLane64(eregOfRexRM(pfx,modrm), 0));
10990 assign(t1, getXMMRegLane64(eregOfRexRM(pfx,modrm), 1));
10991 t5 = newTemp(Ity_I64);
10992 assign(t5, mkIRExprCCall(
10993 Ity_I64, 0/*regparms*/,
10994 "amd64g_calculate_sse_pmovmskb",
10995 &amd64g_calculate_sse_pmovmskb,
10996 mkIRExprVec_2( mkexpr(t1), mkexpr(t0) )));
10997 putIReg32(gregOfRexRM(pfx,modrm), unop(Iop_64to32,mkexpr(t5)));
10998 DIP("pmovmskb %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
10999 nameIReg32(gregOfRexRM(pfx,modrm)));
11000 delta += 3;
11001 goto decode_success;
11002 }
11003 /* else fall through */
11004 }
11005
11006 /* 66 0F E4 = PMULHUW -- 16x8 hi-half of unsigned widening multiply */
11007 if (have66noF2noF3(pfx) && sz == 2
11008 && insn[0] == 0x0F && insn[1] == 0xE4) {
11009 delta = dis_SSEint_E_to_G( pfx, delta+2,
11010 "pmulhuw", Iop_MulHi16Ux8, False );
11011 goto decode_success;
11012 }
11013
11014 /* 66 0F E5 = PMULHW -- 16x8 hi-half of signed widening multiply */
11015 if (have66noF2noF3(pfx) && sz == 2
11016 && insn[0] == 0x0F && insn[1] == 0xE5) {
11017 delta = dis_SSEint_E_to_G( pfx, delta+2,
11018 "pmulhw", Iop_MulHi16Sx8, False );
11019 goto decode_success;
11020 }
11021
11022 /* 66 0F D5 = PMULHL -- 16x8 multiply */
11023 if (have66noF2noF3(pfx) && sz == 2
11024 && insn[0] == 0x0F && insn[1] == 0xD5) {
11025 delta = dis_SSEint_E_to_G( pfx, delta+2,
11026 "pmullw", Iop_Mul16x8, False );
11027 goto decode_success;
11028 }
11029
11030 /* ***--- this is an MMX class insn introduced in SSE2 ---*** */
11031 /* 0F F4 = PMULUDQ -- unsigned widening multiply of 32-lanes 0 x
11032 0 to form 64-bit result */
11033 if (haveNo66noF2noF3(pfx) && sz == 4
11034 && insn[0] == 0x0F && insn[1] == 0xF4) {
11035 IRTemp sV = newTemp(Ity_I64);
11036 IRTemp dV = newTemp(Ity_I64);
11037 t1 = newTemp(Ity_I32);
11038 t0 = newTemp(Ity_I32);
11039 modrm = insn[2];
11040
11041 do_MMX_preamble();
11042 assign( dV, getMMXReg(gregLO3ofRM(modrm)) );
11043
11044 if (epartIsReg(modrm)) {
11045 assign( sV, getMMXReg(eregLO3ofRM(modrm)) );
11046 delta += 2+1;
11047 DIP("pmuludq %s,%s\n", nameMMXReg(eregLO3ofRM(modrm)),
11048 nameMMXReg(gregLO3ofRM(modrm)));
11049 } else {
11050 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
11051 assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
11052 delta += 2+alen;
11053 DIP("pmuludq %s,%s\n", dis_buf,
11054 nameMMXReg(gregLO3ofRM(modrm)));
11055 }
11056
11057 assign( t0, unop(Iop_64to32, mkexpr(dV)) );
11058 assign( t1, unop(Iop_64to32, mkexpr(sV)) );
11059 putMMXReg( gregLO3ofRM(modrm),
11060 binop( Iop_MullU32, mkexpr(t0), mkexpr(t1) ) );
11061 goto decode_success;
11062 }
11063
11064 /* 66 0F F4 = PMULUDQ -- unsigned widening multiply of 32-lanes 0 x
11065 0 to form lower 64-bit half and lanes 2 x 2 to form upper 64-bit
11066 half */
11067 /* This is a really poor translation -- could be improved if
11068 performance critical */
11069 if (have66noF2noF3(pfx) && sz == 2
11070 && insn[0] == 0x0F && insn[1] == 0xF4) {
11071 IRTemp sV, dV;
11072 IRTemp s3, s2, s1, s0, d3, d2, d1, d0;
11073 sV = newTemp(Ity_V128);
11074 dV = newTemp(Ity_V128);
11075 s3 = s2 = s1 = s0 = d3 = d2 = d1 = d0 = IRTemp_INVALID;
11076 t1 = newTemp(Ity_I64);
11077 t0 = newTemp(Ity_I64);
11078 modrm = insn[2];
11079 assign( dV, getXMMReg(gregOfRexRM(pfx,modrm)) );
11080
11081 if (epartIsReg(modrm)) {
11082 assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
11083 delta += 2+1;
11084 DIP("pmuludq %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
11085 nameXMMReg(gregOfRexRM(pfx,modrm)));
11086 } else {
11087 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
11088 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
11089 delta += 2+alen;
11090 DIP("pmuludq %s,%s\n", dis_buf,
11091 nameXMMReg(gregOfRexRM(pfx,modrm)));
11092 }
11093
11094 breakup128to32s( dV, &d3, &d2, &d1, &d0 );
11095 breakup128to32s( sV, &s3, &s2, &s1, &s0 );
11096
11097 assign( t0, binop( Iop_MullU32, mkexpr(d0), mkexpr(s0)) );
11098 putXMMRegLane64( gregOfRexRM(pfx,modrm), 0, mkexpr(t0) );
11099 assign( t1, binop( Iop_MullU32, mkexpr(d2), mkexpr(s2)) );
11100 putXMMRegLane64( gregOfRexRM(pfx,modrm), 1, mkexpr(t1) );
11101 goto decode_success;
11102 }
sewardj09717342005-05-05 21:34:02 +000011103
11104 /* 66 0F EB = POR */
11105 if (have66noF2noF3(pfx) && sz == 2
11106 && insn[0] == 0x0F && insn[1] == 0xEB) {
11107 delta = dis_SSE_E_to_G_all( pfx, delta+2, "por", Iop_OrV128 );
11108 goto decode_success;
11109 }
11110
sewardjadffcef2005-05-11 00:03:06 +000011111 /* 66 0F 70 = PSHUFD -- rearrange 4x32 from E(xmm or mem) to G(xmm) */
11112 if (have66noF2noF3(pfx) && sz == 2
11113 && insn[0] == 0x0F && insn[1] == 0x70) {
11114 Int order;
11115 IRTemp sV, dV, s3, s2, s1, s0;
11116 s3 = s2 = s1 = s0 = IRTemp_INVALID;
11117 sV = newTemp(Ity_V128);
11118 dV = newTemp(Ity_V128);
11119 modrm = insn[2];
11120 if (epartIsReg(modrm)) {
11121 assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
11122 order = (Int)insn[3];
11123 delta += 3+1;
11124 DIP("pshufd $%d,%s,%s\n", order,
11125 nameXMMReg(eregOfRexRM(pfx,modrm)),
11126 nameXMMReg(gregOfRexRM(pfx,modrm)));
11127 } else {
11128 addr = disAMode ( &alen, pfx, delta+2, dis_buf,
11129 1/*byte after the amode*/ );
11130 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
11131 order = (Int)insn[2+alen];
11132 delta += 2+alen+1;
11133 DIP("pshufd $%d,%s,%s\n", order,
11134 dis_buf,
11135 nameXMMReg(gregOfRexRM(pfx,modrm)));
11136 }
11137 breakup128to32s( sV, &s3, &s2, &s1, &s0 );
11138
11139# define SEL(n) \
11140 ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
11141 assign(dV,
11142 mk128from32s( SEL((order>>6)&3), SEL((order>>4)&3),
11143 SEL((order>>2)&3), SEL((order>>0)&3) )
11144 );
11145 putXMMReg(gregOfRexRM(pfx,modrm), mkexpr(dV));
11146# undef SEL
11147 goto decode_success;
11148 }
11149
11150 /* F3 0F 70 = PSHUFHW -- rearrange upper half 4x16 from E(xmm or
11151 mem) to G(xmm), and copy lower half */
11152 if (haveF3no66noF2(pfx) && sz == 4
11153 && insn[0] == 0x0F && insn[1] == 0x70) {
11154 Int order;
11155 IRTemp sVhi, dVhi, sV, dV, s3, s2, s1, s0;
11156 s3 = s2 = s1 = s0 = IRTemp_INVALID;
11157 sV = newTemp(Ity_V128);
11158 dV = newTemp(Ity_V128);
11159 sVhi = newTemp(Ity_I64);
11160 dVhi = newTemp(Ity_I64);
11161 modrm = insn[2];
11162 if (epartIsReg(modrm)) {
11163 assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
11164 order = (Int)insn[3];
11165 delta += 3+1;
11166 DIP("pshufhw $%d,%s,%s\n", order,
11167 nameXMMReg(eregOfRexRM(pfx,modrm)),
11168 nameXMMReg(gregOfRexRM(pfx,modrm)));
11169 } else {
11170 addr = disAMode ( &alen, pfx, delta+2, dis_buf,
11171 1/*byte after the amode*/ );
11172 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
11173 order = (Int)insn[2+alen];
11174 delta += 2+alen+1;
11175 DIP("pshufhw $%d,%s,%s\n", order,
11176 dis_buf,
11177 nameXMMReg(gregOfRexRM(pfx,modrm)));
11178 }
11179 assign( sVhi, unop(Iop_V128HIto64, mkexpr(sV)) );
11180 breakup64to16s( sVhi, &s3, &s2, &s1, &s0 );
11181
11182# define SEL(n) \
11183 ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
11184 assign(dVhi,
11185 mk64from16s( SEL((order>>6)&3), SEL((order>>4)&3),
11186 SEL((order>>2)&3), SEL((order>>0)&3) )
11187 );
11188 assign(dV, binop( Iop_64HLtoV128,
11189 mkexpr(dVhi),
11190 unop(Iop_V128to64, mkexpr(sV))) );
11191 putXMMReg(gregOfRexRM(pfx,modrm), mkexpr(dV));
11192# undef SEL
11193 goto decode_success;
11194 }
11195
11196 /* F2 0F 70 = PSHUFLW -- rearrange lower half 4x16 from E(xmm or
11197 mem) to G(xmm), and copy upper half */
11198 if (haveF2no66noF3(pfx) && sz == 4
11199 && insn[0] == 0x0F && insn[1] == 0x70) {
11200 Int order;
11201 IRTemp sVlo, dVlo, sV, dV, s3, s2, s1, s0;
11202 s3 = s2 = s1 = s0 = IRTemp_INVALID;
11203 sV = newTemp(Ity_V128);
11204 dV = newTemp(Ity_V128);
11205 sVlo = newTemp(Ity_I64);
11206 dVlo = newTemp(Ity_I64);
11207 modrm = insn[2];
11208 if (epartIsReg(modrm)) {
11209 assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
11210 order = (Int)insn[3];
11211 delta += 3+1;
11212 DIP("pshuflw $%d,%s,%s\n", order,
11213 nameXMMReg(eregOfRexRM(pfx,modrm)),
11214 nameXMMReg(gregOfRexRM(pfx,modrm)));
11215 } else {
11216 addr = disAMode ( &alen, pfx, delta+2, dis_buf,
11217 1/*byte after the amode*/ );
11218 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
11219 order = (Int)insn[2+alen];
11220 delta += 2+alen+1;
11221 DIP("pshuflw $%d,%s,%s\n", order,
11222 dis_buf,
11223 nameXMMReg(gregOfRexRM(pfx,modrm)));
11224 }
11225 assign( sVlo, unop(Iop_V128to64, mkexpr(sV)) );
11226 breakup64to16s( sVlo, &s3, &s2, &s1, &s0 );
11227
11228# define SEL(n) \
11229 ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
11230 assign(dVlo,
11231 mk64from16s( SEL((order>>6)&3), SEL((order>>4)&3),
11232 SEL((order>>2)&3), SEL((order>>0)&3) )
11233 );
11234 assign(dV, binop( Iop_64HLtoV128,
11235 unop(Iop_V128HIto64, mkexpr(sV)),
11236 mkexpr(dVlo) ) );
11237 putXMMReg(gregOfRexRM(pfx,modrm), mkexpr(dV));
11238# undef SEL
11239 goto decode_success;
11240 }
11241
11242 /* 66 0F 72 /6 ib = PSLLD by immediate */
11243 if (have66noF2noF3(pfx) && sz == 2
11244 && insn[0] == 0x0F && insn[1] == 0x72
11245 && epartIsReg(insn[2])
11246 && gregLO3ofRM(insn[2]) == 6) {
11247 delta = dis_SSE_shiftE_imm( pfx, delta+2, "pslld", Iop_ShlN32x4 );
11248 goto decode_success;
11249 }
11250
11251 /* 66 0F F2 = PSLLD by E */
11252 if (have66noF2noF3(pfx) && sz == 2
11253 && insn[0] == 0x0F && insn[1] == 0xF2) {
11254 delta = dis_SSE_shiftG_byE( pfx, delta+2, "pslld", Iop_ShlN32x4 );
11255 goto decode_success;
11256 }
sewardj97628592005-05-10 22:42:54 +000011257
11258 /* 66 0F 73 /7 ib = PSLLDQ by immediate */
11259 /* note, if mem case ever filled in, 1 byte after amode */
11260 if (have66noF2noF3(pfx) && sz == 2
11261 && insn[0] == 0x0F && insn[1] == 0x73
11262 && epartIsReg(insn[2])
11263 && gregLO3ofRM(insn[2]) == 7) {
11264 IRTemp sV, dV, hi64, lo64, hi64r, lo64r;
11265 Int imm = (Int)insn[3];
11266 Int reg = eregOfRexRM(pfx,insn[2]);
11267 DIP("pslldq $%d,%s\n", imm, nameXMMReg(reg));
11268 vassert(imm >= 0 && imm <= 255);
11269 delta += 4;
11270
11271 sV = newTemp(Ity_V128);
11272 dV = newTemp(Ity_V128);
11273 hi64 = newTemp(Ity_I64);
11274 lo64 = newTemp(Ity_I64);
11275 hi64r = newTemp(Ity_I64);
11276 lo64r = newTemp(Ity_I64);
11277
11278 if (imm >= 16) {
11279 putXMMReg(reg, mkV128(0x0000));
11280 goto decode_success;
11281 }
11282
11283 assign( sV, getXMMReg(reg) );
11284 assign( hi64, unop(Iop_V128HIto64, mkexpr(sV)) );
11285 assign( lo64, unop(Iop_V128to64, mkexpr(sV)) );
11286
11287 if (imm == 0) {
11288 assign( lo64r, mkexpr(lo64) );
11289 assign( hi64r, mkexpr(hi64) );
11290 }
11291 else
11292 if (imm == 8) {
11293 assign( lo64r, mkU64(0) );
11294 assign( hi64r, mkexpr(lo64) );
11295 }
11296 else
11297 if (imm > 8) {
11298 assign( lo64r, mkU64(0) );
11299 assign( hi64r, binop( Iop_Shl64,
11300 mkexpr(lo64),
11301 mkU8( 8*(imm-8) ) ));
11302 } else {
11303 assign( lo64r, binop( Iop_Shl64,
11304 mkexpr(lo64),
11305 mkU8(8 * imm) ));
11306 assign( hi64r,
11307 binop( Iop_Or64,
11308 binop(Iop_Shl64, mkexpr(hi64),
11309 mkU8(8 * imm)),
11310 binop(Iop_Shr64, mkexpr(lo64),
11311 mkU8(8 * (8 - imm)) )
11312 )
11313 );
11314 }
11315 assign( dV, binop(Iop_64HLtoV128, mkexpr(hi64r), mkexpr(lo64r)) );
11316 putXMMReg(reg, mkexpr(dV));
11317 goto decode_success;
11318 }
11319
sewardjadffcef2005-05-11 00:03:06 +000011320 /* 66 0F 73 /6 ib = PSLLQ by immediate */
11321 if (have66noF2noF3(pfx) && sz == 2
11322 && insn[0] == 0x0F && insn[1] == 0x73
11323 && epartIsReg(insn[2])
11324 && gregLO3ofRM(insn[2]) == 6) {
11325 delta = dis_SSE_shiftE_imm( pfx, delta+2, "psllq", Iop_ShlN64x2 );
11326 goto decode_success;
11327 }
11328
11329 /* 66 0F F3 = PSLLQ by E */
11330 if (have66noF2noF3(pfx) && sz == 2
11331 && insn[0] == 0x0F && insn[1] == 0xF3) {
11332 delta = dis_SSE_shiftG_byE( pfx, delta+2, "psllq", Iop_ShlN64x2 );
11333 goto decode_success;
11334 }
11335
11336 /* 66 0F 71 /6 ib = PSLLW by immediate */
11337 if (have66noF2noF3(pfx) && sz == 2
11338 && insn[0] == 0x0F && insn[1] == 0x71
11339 && epartIsReg(insn[2])
11340 && gregLO3ofRM(insn[2]) == 6) {
11341 delta = dis_SSE_shiftE_imm( pfx, delta+2, "psllw", Iop_ShlN16x8 );
11342 goto decode_success;
11343 }
11344
11345 /* 66 0F F1 = PSLLW by E */
11346 if (have66noF2noF3(pfx) && sz == 2
11347 && insn[0] == 0x0F && insn[1] == 0xF1) {
11348 delta = dis_SSE_shiftG_byE( pfx, delta+2, "psllw", Iop_ShlN16x8 );
11349 goto decode_success;
11350 }
11351
11352 /* 66 0F 72 /4 ib = PSRAD by immediate */
11353 if (have66noF2noF3(pfx) && sz == 2
11354 && insn[0] == 0x0F && insn[1] == 0x72
11355 && epartIsReg(insn[2])
11356 && gregLO3ofRM(insn[2]) == 4) {
11357 delta = dis_SSE_shiftE_imm( pfx, delta+2, "psrad", Iop_SarN32x4 );
11358 goto decode_success;
11359 }
11360
11361 /* 66 0F E2 = PSRAD by E */
11362 if (have66noF2noF3(pfx) && sz == 2
11363 && insn[0] == 0x0F && insn[1] == 0xE2) {
11364 delta = dis_SSE_shiftG_byE( pfx, delta+2, "psrad", Iop_SarN32x4 );
11365 goto decode_success;
11366 }
11367
11368 /* 66 0F 71 /4 ib = PSRAW by immediate */
11369 if (have66noF2noF3(pfx) && sz == 2
11370 && insn[0] == 0x0F && insn[1] == 0x71
11371 && epartIsReg(insn[2])
11372 && gregLO3ofRM(insn[2]) == 4) {
11373 delta = dis_SSE_shiftE_imm( pfx, delta+2, "psraw", Iop_SarN16x8 );
11374 goto decode_success;
11375 }
11376
11377 /* 66 0F E1 = PSRAW by E */
11378 if (have66noF2noF3(pfx) && sz == 2
11379 && insn[0] == 0x0F && insn[1] == 0xE1) {
11380 delta = dis_SSE_shiftG_byE( pfx, delta+2, "psraw", Iop_SarN16x8 );
11381 goto decode_success;
11382 }
11383
11384 /* 66 0F 72 /2 ib = PSRLD by immediate */
11385 if (have66noF2noF3(pfx) && sz == 2
11386 && insn[0] == 0x0F && insn[1] == 0x72
11387 && epartIsReg(insn[2])
11388 && gregLO3ofRM(insn[2]) == 2) {
11389 delta = dis_SSE_shiftE_imm( pfx, delta+2, "psrld", Iop_ShrN32x4 );
11390 goto decode_success;
11391 }
11392
11393 /* 66 0F D2 = PSRLD by E */
11394 if (have66noF2noF3(pfx) && sz == 2
11395 && insn[0] == 0x0F && insn[1] == 0xD2) {
11396 delta = dis_SSE_shiftG_byE( pfx, delta+2, "psrld", Iop_ShrN32x4 );
11397 goto decode_success;
11398 }
sewardj97628592005-05-10 22:42:54 +000011399
11400 /* 66 0F 73 /3 ib = PSRLDQ by immediate */
11401 /* note, if mem case ever filled in, 1 byte after amode */
11402 if (have66noF2noF3(pfx) && sz == 2
11403 && insn[0] == 0x0F && insn[1] == 0x73
11404 && epartIsReg(insn[2])
11405 && gregLO3ofRM(insn[2]) == 3) {
11406 IRTemp sV, dV, hi64, lo64, hi64r, lo64r;
11407 Int imm = (Int)insn[3];
11408 Int reg = eregOfRexRM(pfx,insn[2]);
11409 DIP("psrldq $%d,%s\n", imm, nameXMMReg(reg));
11410 vassert(imm >= 0 && imm <= 255);
11411 delta += 4;
11412
11413 sV = newTemp(Ity_V128);
11414 dV = newTemp(Ity_V128);
11415 hi64 = newTemp(Ity_I64);
11416 lo64 = newTemp(Ity_I64);
11417 hi64r = newTemp(Ity_I64);
11418 lo64r = newTemp(Ity_I64);
11419
11420 if (imm >= 16) {
11421 putXMMReg(reg, mkV128(0x0000));
11422 goto decode_success;
11423 }
11424
11425 assign( sV, getXMMReg(reg) );
11426 assign( hi64, unop(Iop_V128HIto64, mkexpr(sV)) );
11427 assign( lo64, unop(Iop_V128to64, mkexpr(sV)) );
11428
11429 if (imm == 0) {
11430 assign( lo64r, mkexpr(lo64) );
11431 assign( hi64r, mkexpr(hi64) );
11432 }
11433 else
11434 if (imm == 8) {
11435 assign( hi64r, mkU64(0) );
11436 assign( lo64r, mkexpr(hi64) );
11437 }
11438 else
11439 if (imm > 8) {
11440 assign( hi64r, mkU64(0) );
11441 assign( lo64r, binop( Iop_Shr64,
11442 mkexpr(hi64),
11443 mkU8( 8*(imm-8) ) ));
11444 } else {
11445 assign( hi64r, binop( Iop_Shr64,
11446 mkexpr(hi64),
11447 mkU8(8 * imm) ));
11448 assign( lo64r,
11449 binop( Iop_Or64,
11450 binop(Iop_Shr64, mkexpr(lo64),
11451 mkU8(8 * imm)),
11452 binop(Iop_Shl64, mkexpr(hi64),
11453 mkU8(8 * (8 - imm)) )
11454 )
11455 );
11456 }
11457
11458 assign( dV, binop(Iop_64HLtoV128, mkexpr(hi64r), mkexpr(lo64r)) );
11459 putXMMReg(reg, mkexpr(dV));
11460 goto decode_success;
11461 }
sewardj09717342005-05-05 21:34:02 +000011462
11463 /* 66 0F 73 /2 ib = PSRLQ by immediate */
11464 if (have66noF2noF3(pfx) && sz == 2
11465 && insn[0] == 0x0F && insn[1] == 0x73
11466 && epartIsReg(insn[2])
11467 && gregLO3ofRM(insn[2]) == 2) {
11468 delta = dis_SSE_shiftE_imm( pfx, delta+2, "psrlq", Iop_ShrN64x2 );
11469 goto decode_success;
11470 }
11471
sewardjadffcef2005-05-11 00:03:06 +000011472 /* 66 0F D3 = PSRLQ by E */
11473 if (have66noF2noF3(pfx) && sz == 2
11474 && insn[0] == 0x0F && insn[1] == 0xD3) {
11475 delta = dis_SSE_shiftG_byE( pfx, delta+2, "psrlq", Iop_ShrN64x2 );
11476 goto decode_success;
11477 }
11478
11479 /* 66 0F 71 /2 ib = PSRLW by immediate */
11480 if (have66noF2noF3(pfx) && sz == 2
11481 && insn[0] == 0x0F && insn[1] == 0x71
11482 && epartIsReg(insn[2])
11483 && gregLO3ofRM(insn[2]) == 2) {
11484 delta = dis_SSE_shiftE_imm( pfx, delta+2, "psrlw", Iop_ShrN16x8 );
11485 goto decode_success;
11486 }
11487
11488 /* 66 0F D1 = PSRLW by E */
11489 if (have66noF2noF3(pfx) && sz == 2
11490 && insn[0] == 0x0F && insn[1] == 0xD1) {
11491 delta = dis_SSE_shiftG_byE( pfx, delta+2, "psrlw", Iop_ShrN16x8 );
11492 goto decode_success;
11493 }
sewardj97628592005-05-10 22:42:54 +000011494
11495 /* 66 0F F8 = PSUBB */
11496 if (have66noF2noF3(pfx) && sz == 2
11497 && insn[0] == 0x0F && insn[1] == 0xF8) {
11498 delta = dis_SSEint_E_to_G( pfx, delta+2,
11499 "psubb", Iop_Sub8x16, False );
11500 goto decode_success;
11501 }
11502
11503 /* 66 0F FA = PSUBD */
11504 if (have66noF2noF3(pfx) && sz == 2
11505 && insn[0] == 0x0F && insn[1] == 0xFA) {
11506 delta = dis_SSEint_E_to_G( pfx, delta+2,
11507 "psubd", Iop_Sub32x4, False );
11508 goto decode_success;
11509 }
sewardj8711f662005-05-09 17:52:56 +000011510
11511 /* ***--- this is an MMX class insn introduced in SSE2 ---*** */
11512 /* 0F FB = PSUBQ -- sub 64x1 */
11513 if (haveNo66noF2noF3(pfx) && sz == 4
11514 && insn[0] == 0x0F && insn[1] == 0xFB) {
11515 do_MMX_preamble();
11516 delta = dis_MMXop_regmem_to_reg (
11517 pfx, delta+2, insn[1], "psubq", False );
11518 goto decode_success;
11519 }
sewardj09717342005-05-05 21:34:02 +000011520
11521 /* 66 0F FB = PSUBQ */
11522 if (have66noF2noF3(pfx) && sz == 2
11523 && insn[0] == 0x0F && insn[1] == 0xFB) {
11524 delta = dis_SSEint_E_to_G( pfx, delta+2,
11525 "psubq", Iop_Sub64x2, False );
11526 goto decode_success;
11527 }
11528
sewardj97628592005-05-10 22:42:54 +000011529 /* 66 0F F9 = PSUBW */
11530 if (have66noF2noF3(pfx) && sz == 2
11531 && insn[0] == 0x0F && insn[1] == 0xF9) {
11532 delta = dis_SSEint_E_to_G( pfx, delta+2,
11533 "psubw", Iop_Sub16x8, False );
11534 goto decode_success;
11535 }
11536
11537 /* 66 0F E8 = PSUBSB */
11538 if (have66noF2noF3(pfx) && sz == 2
11539 && insn[0] == 0x0F && insn[1] == 0xE8) {
11540 delta = dis_SSEint_E_to_G( pfx, delta+2,
11541 "psubsb", Iop_QSub8Sx16, False );
11542 goto decode_success;
11543 }
11544
11545 /* 66 0F E9 = PSUBSW */
11546 if (have66noF2noF3(pfx) && sz == 2
11547 && insn[0] == 0x0F && insn[1] == 0xE9) {
11548 delta = dis_SSEint_E_to_G( pfx, delta+2,
11549 "psubsw", Iop_QSub16Sx8, False );
11550 goto decode_success;
11551 }
11552
11553 /* 66 0F D8 = PSUBSB */
11554 if (have66noF2noF3(pfx) && sz == 2
11555 && insn[0] == 0x0F && insn[1] == 0xD8) {
11556 delta = dis_SSEint_E_to_G( pfx, delta+2,
11557 "psubusb", Iop_QSub8Ux16, False );
11558 goto decode_success;
11559 }
11560
11561 /* 66 0F D9 = PSUBSW */
11562 if (have66noF2noF3(pfx) && sz == 2
11563 && insn[0] == 0x0F && insn[1] == 0xD9) {
11564 delta = dis_SSEint_E_to_G( pfx, delta+2,
11565 "psubusw", Iop_QSub16Ux8, False );
11566 goto decode_success;
11567 }
11568
11569 /* 66 0F 68 = PUNPCKHBW */
11570 if (have66noF2noF3(pfx) && sz == 2
11571 && insn[0] == 0x0F && insn[1] == 0x68) {
11572 delta = dis_SSEint_E_to_G( pfx, delta+2,
11573 "punpckhbw",
11574 Iop_InterleaveHI8x16, True );
11575 goto decode_success;
11576 }
11577
11578 /* 66 0F 6A = PUNPCKHDQ */
11579 if (have66noF2noF3(pfx) && sz == 2
11580 && insn[0] == 0x0F && insn[1] == 0x6A) {
11581 delta = dis_SSEint_E_to_G( pfx, delta+2,
11582 "punpckhdq",
11583 Iop_InterleaveHI32x4, True );
11584 goto decode_success;
11585 }
11586
11587 /* 66 0F 6D = PUNPCKHQDQ */
11588 if (have66noF2noF3(pfx) && sz == 2
11589 && insn[0] == 0x0F && insn[1] == 0x6D) {
11590 delta = dis_SSEint_E_to_G( pfx, delta+2,
11591 "punpckhqdq",
11592 Iop_InterleaveHI64x2, True );
11593 goto decode_success;
11594 }
11595
11596 /* 66 0F 69 = PUNPCKHWD */
11597 if (have66noF2noF3(pfx) && sz == 2
11598 && insn[0] == 0x0F && insn[1] == 0x69) {
11599 delta = dis_SSEint_E_to_G( pfx, delta+2,
11600 "punpckhwd",
11601 Iop_InterleaveHI16x8, True );
11602 goto decode_success;
11603 }
11604
11605 /* 66 0F 60 = PUNPCKLBW */
11606 if (have66noF2noF3(pfx) && sz == 2
11607 && insn[0] == 0x0F && insn[1] == 0x60) {
11608 delta = dis_SSEint_E_to_G( pfx, delta+2,
11609 "punpcklbw",
11610 Iop_InterleaveLO8x16, True );
11611 goto decode_success;
11612 }
11613
11614 /* 66 0F 62 = PUNPCKLDQ */
11615 if (have66noF2noF3(pfx) && sz == 2
11616 && insn[0] == 0x0F && insn[1] == 0x62) {
11617 delta = dis_SSEint_E_to_G( pfx, delta+2,
11618 "punpckldq",
11619 Iop_InterleaveLO32x4, True );
11620 goto decode_success;
11621 }
11622
11623 /* 66 0F 6C = PUNPCKLQDQ */
11624 if (have66noF2noF3(pfx) && sz == 2
11625 && insn[0] == 0x0F && insn[1] == 0x6C) {
11626 delta = dis_SSEint_E_to_G( pfx, delta+2,
11627 "punpcklqdq",
11628 Iop_InterleaveLO64x2, True );
11629 goto decode_success;
11630 }
11631
11632 /* 66 0F 61 = PUNPCKLWD */
11633 if (have66noF2noF3(pfx) && sz == 2
11634 && insn[0] == 0x0F && insn[1] == 0x61) {
11635 delta = dis_SSEint_E_to_G( pfx, delta+2,
11636 "punpcklwd",
11637 Iop_InterleaveLO16x8, True );
11638 goto decode_success;
11639 }
sewardj09717342005-05-05 21:34:02 +000011640
11641 /* 66 0F EF = PXOR */
11642 if (have66noF2noF3(pfx) && sz == 2
11643 && insn[0] == 0x0F && insn[1] == 0xEF) {
11644 delta = dis_SSE_E_to_G_all( pfx, delta+2, "pxor", Iop_XorV128 );
11645 goto decode_success;
11646 }
11647
sewardjd20c8852005-01-20 20:04:07 +000011648//.. //-- /* FXSAVE/FXRSTOR m32 -- load/store the FPU/MMX/SSE state. */
11649//.. //-- if (insn[0] == 0x0F && insn[1] == 0xAE
11650//.. //-- && (!epartIsReg(insn[2]))
11651//.. //-- && (gregOfRM(insn[2]) == 1 || gregOfRM(insn[2]) == 0) ) {
11652//.. //-- Bool store = gregOfRM(insn[2]) == 0;
11653//.. //-- vg_assert(sz == 4);
11654//.. //-- pair = disAMode ( cb, sorb, eip+2, dis_buf );
11655//.. //-- t1 = LOW24(pair);
11656//.. //-- eip += 2+HI8(pair);
11657//.. //-- uInstr3(cb, store ? SSE2a_MemWr : SSE2a_MemRd, 512,
11658//.. //-- Lit16, (((UShort)insn[0]) << 8) | (UShort)insn[1],
11659//.. //-- Lit16, (UShort)insn[2],
11660//.. //-- TempReg, t1 );
11661//.. //-- DIP("fx%s %s\n", store ? "save" : "rstor", dis_buf );
11662//.. //-- goto decode_success;
11663//.. //-- }
sewardj3e616e62006-01-07 22:58:54 +000011664
11665 /* 0F AE /7 = CLFLUSH -- flush cache line */
11666 if (haveNo66noF2noF3(pfx) && sz == 4
11667 && insn[0] == 0x0F && insn[1] == 0xAE
11668 && !epartIsReg(insn[2]) && gregLO3ofRM(insn[2]) == 7) {
11669
11670 /* This is something of a hack. We need to know the size of the
11671 cache line containing addr. Since we don't (easily), assume
11672 256 on the basis that no real cache would have a line that
11673 big. It's safe to invalidate more stuff than we need, just
11674 inefficient. */
11675 ULong lineszB = 256ULL;
11676
11677 addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 );
11678 delta += 2+alen;
11679
11680 /* Round addr down to the start of the containing block. */
11681 stmt( IRStmt_Put(
11682 OFFB_TISTART,
11683 binop( Iop_And64,
11684 mkexpr(addr),
11685 mkU64( ~(lineszB-1) ))) );
11686
11687 stmt( IRStmt_Put(OFFB_TILEN, mkU64(lineszB) ) );
11688
11689 irbb->jumpkind = Ijk_TInval;
11690 irbb->next = mkU64(guest_RIP_bbstart+delta);
11691 dres.whatNext = Dis_StopHere;
11692
11693 DIP("clflush %s\n", dis_buf);
11694 goto decode_success;
11695 }
sewardjdf0e0022005-01-25 15:48:43 +000011696
11697
11698 /* ---------------------------------------------------- */
11699 /* --- end of the SSE/SSE2 decoder. --- */
11700 /* ---------------------------------------------------- */
11701
sewardj7a240552005-01-28 21:37:12 +000011702 /*after_sse_decoders:*/
sewardjdf0e0022005-01-25 15:48:43 +000011703
11704 /* Get the primary opcode. */
sewardj8c332e22005-01-28 01:36:56 +000011705 opc = getUChar(delta); delta++;
sewardjdf0e0022005-01-25 15:48:43 +000011706
11707 /* We get here if the current insn isn't SSE, or this CPU doesn't
11708 support SSE. */
11709
11710 switch (opc) {
11711
11712 /* ------------------------ Control flow --------------- */
11713
sewardjd20c8852005-01-20 20:04:07 +000011714//.. case 0xC2: /* RET imm16 */
11715//.. d32 = getUDisp16(delta);
11716//.. delta += 2;
11717//.. dis_ret(d32);
11718//.. whatNext = Dis_StopHere;
11719//.. DIP("ret %d\n", d32);
11720//.. break;
sewardj2f959cc2005-01-26 01:19:35 +000011721 case 0xC3: /* RET */
sewardj55dbb262005-01-28 16:36:51 +000011722 if (haveF2(pfx)) goto decode_failure;
11723 /* F3 is acceptable on AMD. */
sewardj2f959cc2005-01-26 01:19:35 +000011724 dis_ret(0);
sewardj9e6491a2005-07-02 19:24:10 +000011725 dres.whatNext = Dis_StopHere;
sewardje941eea2005-01-30 19:52:28 +000011726 DIP(haveF3(pfx) ? "rep ; ret\n" : "ret\n");
sewardj2f959cc2005-01-26 01:19:35 +000011727 break;
11728
sewardj3ca55a12005-01-27 16:06:23 +000011729 case 0xE8: /* CALL J4 */
11730 if (haveF2orF3(pfx)) goto decode_failure;
11731 d64 = getSDisp32(delta); delta += 4;
sewardj9e6491a2005-07-02 19:24:10 +000011732 d64 += (guest_RIP_bbstart+delta);
11733 /* (guest_RIP_bbstart+delta) == return-to addr, d64 == call-to addr */
sewardj3ca55a12005-01-27 16:06:23 +000011734 t1 = newTemp(Ity_I64);
11735 assign(t1, binop(Iop_Sub64, getIReg64(R_RSP), mkU64(8)));
11736 putIReg64(R_RSP, mkexpr(t1));
sewardj9e6491a2005-07-02 19:24:10 +000011737 storeLE( mkexpr(t1), mkU64(guest_RIP_bbstart+delta));
sewardj5a9ffab2005-05-12 17:55:01 +000011738 make_redzone_AbiHint(t1, "call-d32");
sewardjc716aea2006-01-17 01:48:46 +000011739 if (resteerOkFn( callback_opaque, (Addr64)d64) ) {
sewardj3ca55a12005-01-27 16:06:23 +000011740 /* follow into the call target. */
sewardj9e6491a2005-07-02 19:24:10 +000011741 dres.whatNext = Dis_Resteer;
11742 dres.continueAt = d64;
sewardj3ca55a12005-01-27 16:06:23 +000011743 } else {
11744 jmp_lit(Ijk_Call,d64);
sewardj9e6491a2005-07-02 19:24:10 +000011745 dres.whatNext = Dis_StopHere;
sewardj3ca55a12005-01-27 16:06:23 +000011746 }
11747 DIP("call 0x%llx\n",d64);
11748 break;
11749
sewardjd20c8852005-01-20 20:04:07 +000011750//.. //-- case 0xC8: /* ENTER */
11751//.. //-- d32 = getUDisp16(eip); eip += 2;
sewardj8c332e22005-01-28 01:36:56 +000011752//.. //-- abyte = getUChar(delta); delta++;
sewardjd20c8852005-01-20 20:04:07 +000011753//.. //--
11754//.. //-- vg_assert(sz == 4);
11755//.. //-- vg_assert(abyte == 0);
11756//.. //--
11757//.. //-- t1 = newTemp(cb); t2 = newTemp(cb);
11758//.. //-- uInstr2(cb, GET, sz, ArchReg, R_EBP, TempReg, t1);
11759//.. //-- uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t2);
11760//.. //-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
11761//.. //-- uLiteral(cb, sz);
11762//.. //-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
11763//.. //-- uInstr2(cb, STORE, 4, TempReg, t1, TempReg, t2);
11764//.. //-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_EBP);
11765//.. //-- if (d32) {
11766//.. //-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
11767//.. //-- uLiteral(cb, d32);
11768//.. //-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
11769//.. //-- }
11770//.. //-- DIP("enter 0x%x, 0x%x", d32, abyte);
11771//.. //-- break;
sewardje1698952005-02-08 15:02:39 +000011772
11773 case 0xC9: /* LEAVE */
11774 /* In 64-bit mode this defaults to a 64-bit operand size. There
11775 is no way to encode a 32-bit variant. Hence sz==4 but we do
11776 it as if sz=8. */
11777 if (sz != 4)
11778 goto decode_failure;
11779 t1 = newTemp(Ity_I64);
11780 t2 = newTemp(Ity_I64);
11781 assign(t1, getIReg64(R_RBP));
11782 /* First PUT RSP looks redundant, but need it because RSP must
11783 always be up-to-date for Memcheck to work... */
11784 putIReg64(R_RSP, mkexpr(t1));
11785 assign(t2, loadLE(Ity_I64,mkexpr(t1)));
11786 putIReg64(R_RBP, mkexpr(t2));
11787 putIReg64(R_RSP, binop(Iop_Add64, mkexpr(t1), mkU64(8)) );
11788 DIP("leave\n");
11789 break;
11790
sewardjd20c8852005-01-20 20:04:07 +000011791//.. //-- /* ---------------- Misc weird-ass insns --------------- */
11792//.. //--
11793//.. //-- case 0x27: /* DAA */
11794//.. //-- case 0x2F: /* DAS */
11795//.. //-- t1 = newTemp(cb);
11796//.. //-- uInstr2(cb, GET, 1, ArchReg, R_AL, TempReg, t1);
11797//.. //-- /* Widen %AL to 32 bits, so it's all defined when we push it. */
11798//.. //-- uInstr1(cb, WIDEN, 4, TempReg, t1);
11799//.. //-- uWiden(cb, 1, False);
11800//.. //-- uInstr0(cb, CALLM_S, 0);
11801//.. //-- uInstr1(cb, PUSH, 4, TempReg, t1);
11802//.. //-- uInstr1(cb, CALLM, 0, Lit16,
11803//.. //-- opc == 0x27 ? VGOFF_(helper_DAA) : VGOFF_(helper_DAS) );
11804//.. //-- uFlagsRWU(cb, FlagsAC, FlagsSZACP, FlagO);
11805//.. //-- uInstr1(cb, POP, 4, TempReg, t1);
11806//.. //-- uInstr0(cb, CALLM_E, 0);
11807//.. //-- uInstr2(cb, PUT, 1, TempReg, t1, ArchReg, R_AL);
11808//.. //-- DIP(opc == 0x27 ? "daa\n" : "das\n");
11809//.. //-- break;
11810//.. //--
11811//.. //-- case 0x37: /* AAA */
11812//.. //-- case 0x3F: /* AAS */
11813//.. //-- t1 = newTemp(cb);
11814//.. //-- uInstr2(cb, GET, 2, ArchReg, R_EAX, TempReg, t1);
11815//.. //-- /* Widen %AL to 32 bits, so it's all defined when we push it. */
11816//.. //-- uInstr1(cb, WIDEN, 4, TempReg, t1);
11817//.. //-- uWiden(cb, 2, False);
11818//.. //-- uInstr0(cb, CALLM_S, 0);
11819//.. //-- uInstr1(cb, PUSH, 4, TempReg, t1);
11820//.. //-- uInstr1(cb, CALLM, 0, Lit16,
11821//.. //-- opc == 0x37 ? VGOFF_(helper_AAA) : VGOFF_(helper_AAS) );
11822//.. //-- uFlagsRWU(cb, FlagA, FlagsAC, FlagsEmpty);
11823//.. //-- uInstr1(cb, POP, 4, TempReg, t1);
11824//.. //-- uInstr0(cb, CALLM_E, 0);
11825//.. //-- uInstr2(cb, PUT, 2, TempReg, t1, ArchReg, R_EAX);
11826//.. //-- DIP(opc == 0x37 ? "aaa\n" : "aas\n");
11827//.. //-- break;
11828//.. //--
11829//.. //-- case 0xD4: /* AAM */
11830//.. //-- case 0xD5: /* AAD */
sewardj8c332e22005-01-28 01:36:56 +000011831//.. //-- d32 = getUChar(delta); delta++;
sewardjd20c8852005-01-20 20:04:07 +000011832//.. //-- if (d32 != 10) VG_(core_panic)("disInstr: AAM/AAD but base not 10 !");
11833//.. //-- t1 = newTemp(cb);
11834//.. //-- uInstr2(cb, GET, 2, ArchReg, R_EAX, TempReg, t1);
11835//.. //-- /* Widen %AX to 32 bits, so it's all defined when we push it. */
11836//.. //-- uInstr1(cb, WIDEN, 4, TempReg, t1);
11837//.. //-- uWiden(cb, 2, False);
11838//.. //-- uInstr0(cb, CALLM_S, 0);
11839//.. //-- uInstr1(cb, PUSH, 4, TempReg, t1);
11840//.. //-- uInstr1(cb, CALLM, 0, Lit16,
11841//.. //-- opc == 0xD4 ? VGOFF_(helper_AAM) : VGOFF_(helper_AAD) );
11842//.. //-- uFlagsRWU(cb, FlagsEmpty, FlagsSZP, FlagsEmpty);
11843//.. //-- uInstr1(cb, POP, 4, TempReg, t1);
11844//.. //-- uInstr0(cb, CALLM_E, 0);
11845//.. //-- uInstr2(cb, PUT, 2, TempReg, t1, ArchReg, R_EAX);
11846//.. //-- DIP(opc == 0xD4 ? "aam\n" : "aad\n");
11847//.. //-- break;
sewardj3ca55a12005-01-27 16:06:23 +000011848
11849 /* ------------------------ CWD/CDQ -------------------- */
11850
11851 case 0x98: /* CBW */
11852 if (haveF2orF3(pfx)) goto decode_failure;
11853 if (sz == 8) {
sewardj5b470602005-02-27 13:10:48 +000011854 putIRegRAX( 8, unop(Iop_32Sto64, getIRegRAX(4)) );
sewardje941eea2005-01-30 19:52:28 +000011855 DIP(/*"cdqe\n"*/"cltq");
11856 break;
11857 }
sewardj3ca55a12005-01-27 16:06:23 +000011858 if (sz == 4) {
sewardj5b470602005-02-27 13:10:48 +000011859 putIRegRAX( 4, unop(Iop_16Sto32, getIRegRAX(2)) );
sewardj7eaa7cf2005-01-31 18:55:22 +000011860 DIP("cwtl\n");
sewardje941eea2005-01-30 19:52:28 +000011861 break;
11862 }
sewardj3ca55a12005-01-27 16:06:23 +000011863 if (sz == 2) {
sewardj5b470602005-02-27 13:10:48 +000011864 putIRegRAX( 2, unop(Iop_8Sto16, getIRegRAX(1)) );
sewardj3ca55a12005-01-27 16:06:23 +000011865 DIP("cbw\n");
sewardj7bc00082005-03-27 05:08:32 +000011866 break;
sewardj3ca55a12005-01-27 16:06:23 +000011867 }
sewardje941eea2005-01-30 19:52:28 +000011868 goto decode_failure;
sewardj3ca55a12005-01-27 16:06:23 +000011869
11870 case 0x99: /* CWD/CDQ/CQO */
11871 if (haveF2orF3(pfx)) goto decode_failure;
11872 vassert(sz == 2 || sz == 4 || sz == 8);
11873 ty = szToITy(sz);
sewardj5b470602005-02-27 13:10:48 +000011874 putIRegRDX( sz,
11875 binop(mkSizedOp(ty,Iop_Sar8),
11876 getIRegRAX(sz),
11877 mkU8(sz == 2 ? 15 : (sz == 4 ? 31 : 63))) );
sewardje941eea2005-01-30 19:52:28 +000011878 DIP(sz == 2 ? "cwd\n"
sewardj5b470602005-02-27 13:10:48 +000011879 : (sz == 4 ? /*"cdq\n"*/ "cltd\n"
11880 : "cqo\n"));
sewardj3ca55a12005-01-27 16:06:23 +000011881 break;
11882
sewardj8d965312005-02-25 02:48:47 +000011883 /* ------------------------ FPU ops -------------------- */
11884
sewardjd20c8852005-01-20 20:04:07 +000011885//.. case 0x9E: /* SAHF */
11886//.. codegen_SAHF();
11887//.. DIP("sahf\n");
11888//.. break;
11889//..
11890//.. //-- case 0x9F: /* LAHF */
11891//.. //-- codegen_LAHF ( cb );
11892//.. //-- DIP("lahf\n");
11893//.. //-- break;
11894//.. //--
sewardj6847d8c2005-05-12 19:21:55 +000011895 case 0x9B: /* FWAIT */
11896 /* ignore? */
11897 DIP("fwait\n");
11898 break;
sewardj8d965312005-02-25 02:48:47 +000011899
11900 case 0xD8:
11901 case 0xD9:
11902 case 0xDA:
11903 case 0xDB:
11904 case 0xDC:
11905 case 0xDD:
11906 case 0xDE:
11907 case 0xDF:
sewardj5b470602005-02-27 13:10:48 +000011908 if (haveF2orF3(pfx)) goto decode_failure;
sewardj8d965312005-02-25 02:48:47 +000011909 if (sz == 4 && haveNo66noF2noF3(pfx)) {
sewardj270def42005-07-03 01:03:01 +000011910 Long delta0 = delta;
11911 Bool decode_OK = False;
sewardj8d965312005-02-25 02:48:47 +000011912 delta = dis_FPU ( &decode_OK, pfx, delta );
11913 if (!decode_OK) {
11914 delta = delta0;
11915 goto decode_failure;
11916 }
11917 break;
11918 } else {
11919 goto decode_failure;
11920 }
11921
sewardj4fa325a2005-11-03 13:27:24 +000011922 /* ------------------------ INT ------------------------ */
11923
11924 case 0xCD: { /* INT imm8 */
11925 IRJumpKind jk = Ijk_Boring;
11926 if (have66orF2orF3(pfx)) goto decode_failure;
11927 d64 = getUChar(delta); delta++;
11928 switch (d64) {
11929 case 32: jk = Ijk_Sys_int32; break;
11930 default: goto decode_failure;
11931 }
11932 guest_RIP_next_mustcheck = True;
11933 guest_RIP_next_assumed = guest_RIP_bbstart + delta;
11934 jmp_lit(jk, guest_RIP_next_assumed);
11935 /* It's important that all ArchRegs carry their up-to-date value
11936 at this point. So we declare an end-of-block here, which
11937 forces any TempRegs caching ArchRegs to be flushed. */
11938 dres.whatNext = Dis_StopHere;
11939 DIP("int $0x%02x\n", (UInt)d64);
11940 break;
11941 }
11942
sewardjf8c37f72005-02-07 18:55:29 +000011943 /* ------------------------ Jcond, byte offset --------- */
11944
11945 case 0xEB: /* Jb (jump, byte offset) */
sewardj5b470602005-02-27 13:10:48 +000011946 if (haveF2orF3(pfx)) goto decode_failure;
sewardjf8c37f72005-02-07 18:55:29 +000011947 if (sz != 4)
11948 goto decode_failure; /* JRS added 2004 July 11 */
sewardj9e6491a2005-07-02 19:24:10 +000011949 d64 = (guest_RIP_bbstart+delta+1) + getSDisp8(delta);
sewardjf8c37f72005-02-07 18:55:29 +000011950 delta++;
sewardjc716aea2006-01-17 01:48:46 +000011951 if (resteerOkFn(callback_opaque,d64)) {
sewardj9e6491a2005-07-02 19:24:10 +000011952 dres.whatNext = Dis_Resteer;
11953 dres.continueAt = d64;
sewardjf8c37f72005-02-07 18:55:29 +000011954 } else {
11955 jmp_lit(Ijk_Boring,d64);
sewardj9e6491a2005-07-02 19:24:10 +000011956 dres.whatNext = Dis_StopHere;
sewardjf8c37f72005-02-07 18:55:29 +000011957 }
11958 DIP("jmp-8 0x%llx\n", d64);
11959 break;
sewardj1389d4d2005-01-28 13:46:29 +000011960
11961 case 0xE9: /* Jv (jump, 16/32 offset) */
sewardj5b470602005-02-27 13:10:48 +000011962 if (haveF2orF3(pfx)) goto decode_failure;
sewardjf8c37f72005-02-07 18:55:29 +000011963 if (sz != 4)
11964 goto decode_failure; /* JRS added 2004 July 11 */
sewardj9e6491a2005-07-02 19:24:10 +000011965 d64 = (guest_RIP_bbstart+delta+sz) + getSDisp(sz,delta);
sewardj1389d4d2005-01-28 13:46:29 +000011966 delta += sz;
sewardjc716aea2006-01-17 01:48:46 +000011967 if (resteerOkFn(callback_opaque,d64)) {
sewardj9e6491a2005-07-02 19:24:10 +000011968 dres.whatNext = Dis_Resteer;
11969 dres.continueAt = d64;
sewardj1389d4d2005-01-28 13:46:29 +000011970 } else {
11971 jmp_lit(Ijk_Boring,d64);
sewardj9e6491a2005-07-02 19:24:10 +000011972 dres.whatNext = Dis_StopHere;
sewardj1389d4d2005-01-28 13:46:29 +000011973 }
11974 DIP("jmp 0x%llx\n", d64);
11975 break;
11976
sewardjf8c37f72005-02-07 18:55:29 +000011977 case 0x70:
11978 case 0x71:
11979 case 0x72: /* JBb/JNAEb (jump below) */
11980 case 0x73: /* JNBb/JAEb (jump not below) */
11981 case 0x74: /* JZb/JEb (jump zero) */
11982 case 0x75: /* JNZb/JNEb (jump not zero) */
11983 case 0x76: /* JBEb/JNAb (jump below or equal) */
11984 case 0x77: /* JNBEb/JAb (jump not below or equal) */
11985 case 0x78: /* JSb (jump negative) */
11986 case 0x79: /* JSb (jump not negative) */
11987 case 0x7A: /* JP (jump parity even) */
11988 case 0x7B: /* JNP/JPO (jump parity odd) */
11989 case 0x7C: /* JLb/JNGEb (jump less) */
11990 case 0x7D: /* JGEb/JNLb (jump greater or equal) */
11991 case 0x7E: /* JLEb/JNGb (jump less or equal) */
11992 case 0x7F: /* JGb/JNLEb (jump greater) */
sewardj5b470602005-02-27 13:10:48 +000011993 if (haveF2orF3(pfx)) goto decode_failure;
sewardj9e6491a2005-07-02 19:24:10 +000011994 d64 = (guest_RIP_bbstart+delta+1) + getSDisp8(delta);
sewardjf8c37f72005-02-07 18:55:29 +000011995 delta++;
11996 jcc_01( (AMD64Condcode)(opc - 0x70),
sewardj9e6491a2005-07-02 19:24:10 +000011997 guest_RIP_bbstart+delta,
sewardjf8c37f72005-02-07 18:55:29 +000011998 d64 );
sewardj9e6491a2005-07-02 19:24:10 +000011999 dres.whatNext = Dis_StopHere;
sewardjf8c37f72005-02-07 18:55:29 +000012000 DIP("j%s-8 0x%llx\n", name_AMD64Condcode(opc - 0x70), d64);
12001 break;
12002
sewardjc01c1fa2005-11-04 14:34:52 +000012003 case 0xE3:
12004 /* JRCXZ or JECXZ, depending address size override. */
12005 if (have66orF2orF3(pfx)) goto decode_failure;
sewardjfdfa8862005-10-05 16:58:23 +000012006 d64 = (guest_RIP_bbstart+delta+1) + getSDisp8(delta);
12007 delta++;
sewardjc01c1fa2005-11-04 14:34:52 +000012008 if (haveASO(pfx)) {
12009 /* 32-bit */
12010 stmt( IRStmt_Exit( binop(Iop_CmpEQ64,
12011 unop(Iop_32Uto64, getIReg32(R_RCX)),
12012 mkU64(0)),
12013 Ijk_Boring,
12014 IRConst_U64(d64))
12015 );
12016 DIP("jecxz 0x%llx\n", d64);
12017 } else {
12018 /* 64-bit */
12019 stmt( IRStmt_Exit( binop(Iop_CmpEQ64,
12020 getIReg64(R_RCX),
12021 mkU64(0)),
12022 Ijk_Boring,
12023 IRConst_U64(d64))
12024 );
12025 DIP("jrcxz 0x%llx\n", d64);
12026 }
sewardjfdfa8862005-10-05 16:58:23 +000012027 break;
sewardj6359f812005-07-20 10:15:34 +000012028
sewardje8f65252005-08-23 23:44:35 +000012029 case 0xE0: /* LOOPNE disp8: decrement count, jump if count != 0 && ZF==0 */
12030 case 0xE1: /* LOOPE disp8: decrement count, jump if count != 0 && ZF==1 */
12031 case 0xE2: /* LOOP disp8: decrement count, jump if count != 0 */
12032 { /* The docs say this uses rCX as a count depending on the
12033 address size override, not the operand one. Since we don't
12034 handle address size overrides, I guess that means RCX. */
12035 IRExpr* zbit = NULL;
12036 IRExpr* count = NULL;
12037 IRExpr* cond = NULL;
12038 HChar* xtra = NULL;
12039
12040 if (have66orF2orF3(pfx) || haveASO(pfx)) goto decode_failure;
12041 d64 = guest_RIP_bbstart+delta+1 + getSDisp8(delta);
12042 delta++;
12043 putIReg64(R_RCX, binop(Iop_Sub64, getIReg64(R_RCX), mkU64(1)));
12044
12045 count = getIReg64(R_RCX);
12046 cond = binop(Iop_CmpNE64, count, mkU64(0));
12047 switch (opc) {
12048 case 0xE2:
12049 xtra = "";
12050 break;
12051 case 0xE1:
12052 xtra = "e";
12053 zbit = mk_amd64g_calculate_condition( AMD64CondZ );
12054 cond = mkAnd1(cond, zbit);
12055 break;
12056 case 0xE0:
12057 xtra = "ne";
12058 zbit = mk_amd64g_calculate_condition( AMD64CondNZ );
12059 cond = mkAnd1(cond, zbit);
12060 break;
12061 default:
12062 vassert(0);
12063 }
12064 stmt( IRStmt_Exit(cond, Ijk_Boring, IRConst_U64(d64)) );
12065
12066 DIP("loop%s 0x%llx\n", xtra, d64);
12067 break;
12068 }
sewardj32b2bbe2005-01-28 00:50:10 +000012069
12070 /* ------------------------ IMUL ----------------------- */
12071
12072 case 0x69: /* IMUL Iv, Ev, Gv */
sewardj5b470602005-02-27 13:10:48 +000012073 if (haveF2orF3(pfx)) goto decode_failure;
sewardj32b2bbe2005-01-28 00:50:10 +000012074 delta = dis_imul_I_E_G ( pfx, sz, delta, sz );
12075 break;
sewardj7de0d3c2005-02-13 02:26:41 +000012076 case 0x6B: /* IMUL Ib, Ev, Gv */
12077 delta = dis_imul_I_E_G ( pfx, sz, delta, 1 );
12078 break;
sewardj1389d4d2005-01-28 13:46:29 +000012079
12080 /* ------------------------ MOV ------------------------ */
12081
12082 case 0x88: /* MOV Gb,Eb */
sewardj5b470602005-02-27 13:10:48 +000012083 if (haveF2orF3(pfx)) goto decode_failure;
sewardj1389d4d2005-01-28 13:46:29 +000012084 delta = dis_mov_G_E(pfx, 1, delta);
12085 break;
12086
12087 case 0x89: /* MOV Gv,Ev */
sewardj5b470602005-02-27 13:10:48 +000012088 if (haveF2orF3(pfx)) goto decode_failure;
sewardj1389d4d2005-01-28 13:46:29 +000012089 delta = dis_mov_G_E(pfx, sz, delta);
12090 break;
12091
sewardjd0a12df2005-02-10 02:07:43 +000012092 case 0x8A: /* MOV Eb,Gb */
sewardj5b470602005-02-27 13:10:48 +000012093 if (haveF2orF3(pfx)) goto decode_failure;
sewardjd0a12df2005-02-10 02:07:43 +000012094 delta = dis_mov_E_G(pfx, 1, delta);
12095 break;
12096
sewardj1389d4d2005-01-28 13:46:29 +000012097 case 0x8B: /* MOV Ev,Gv */
sewardj5b470602005-02-27 13:10:48 +000012098 if (haveF2orF3(pfx)) goto decode_failure;
sewardj1389d4d2005-01-28 13:46:29 +000012099 delta = dis_mov_E_G(pfx, sz, delta);
12100 break;
12101
12102 case 0x8D: /* LEA M,Gv */
sewardj5b470602005-02-27 13:10:48 +000012103 if (haveF2orF3(pfx)) goto decode_failure;
sewardj1389d4d2005-01-28 13:46:29 +000012104 if (sz != 4 && sz != 8)
12105 goto decode_failure;
12106 modrm = getUChar(delta);
12107 if (epartIsReg(modrm))
12108 goto decode_failure;
12109 /* NOTE! this is the one place where a segment override prefix
12110 has no effect on the address calculation. Therefore we clear
12111 any segment override bits in pfx. */
sewardje1698952005-02-08 15:02:39 +000012112 addr = disAMode ( &alen, clearSegBits(pfx), delta, dis_buf, 0 );
sewardj1389d4d2005-01-28 13:46:29 +000012113 delta += alen;
12114 /* This is a hack. But it isn't clear that really doing the
12115 calculation at 32 bits is really worth it. Hence for leal,
12116 do the full 64-bit calculation and then truncate it. */
sewardj5b470602005-02-27 13:10:48 +000012117 putIRegG( sz, pfx, modrm,
sewardj1389d4d2005-01-28 13:46:29 +000012118 sz == 4
12119 ? unop(Iop_64to32, mkexpr(addr))
12120 : mkexpr(addr)
12121 );
12122 DIP("lea%c %s, %s\n", nameISize(sz), dis_buf,
sewardj5b470602005-02-27 13:10:48 +000012123 nameIRegG(sz,pfx,modrm));
sewardj1389d4d2005-01-28 13:46:29 +000012124 break;
12125
sewardjd20c8852005-01-20 20:04:07 +000012126//.. case 0x8C: /* MOV Sw,Ew -- MOV from a SEGMENT REGISTER */
12127//.. delta = dis_mov_Sw_Ew(sorb, sz, delta);
12128//.. break;
12129//..
12130//.. case 0x8E: /* MOV Ew,Sw -- MOV to a SEGMENT REGISTER */
12131//.. delta = dis_mov_Ew_Sw(sorb, delta);
12132//.. break;
sewardj2bd97d12005-08-02 21:27:25 +000012133
12134 case 0xA0: /* MOV Ob,AL */
12135 if (have66orF2orF3(pfx)) goto decode_failure;
12136 sz = 1;
12137 /* Fall through ... */
sewardj87277cb2005-08-01 13:03:32 +000012138 case 0xA1: /* MOV Ov,eAX */
sewardj2bd97d12005-08-02 21:27:25 +000012139 if (sz != 8 && sz != 4 && sz != 2 && sz != 1)
12140 goto decode_failure;
sewardj87277cb2005-08-01 13:03:32 +000012141 d64 = getDisp64(delta);
12142 delta += 8;
12143 ty = szToITy(sz);
12144 addr = newTemp(Ity_I64);
sewardj42561ef2005-11-04 14:18:31 +000012145 assign( addr, handleAddrOverrides(pfx, mkU64(d64)) );
sewardj87277cb2005-08-01 13:03:32 +000012146 putIRegRAX(sz, loadLE( ty, mkexpr(addr) ));
12147 DIP("mov%c %s0x%llx, %s\n", nameISize(sz),
12148 sorbTxt(pfx), d64,
12149 nameIRegRAX(sz));
12150 break;
12151
sewardj2bd97d12005-08-02 21:27:25 +000012152 case 0xA2: /* MOV AL,Ob */
12153 if (have66orF2orF3(pfx)) goto decode_failure;
12154 sz = 1;
12155 /* Fall through ... */
sewardj87277cb2005-08-01 13:03:32 +000012156 case 0xA3: /* MOV eAX,Ov */
sewardj2bd97d12005-08-02 21:27:25 +000012157 if (sz != 8 && sz != 4 && sz != 2 && sz != 1)
12158 goto decode_failure;
sewardj87277cb2005-08-01 13:03:32 +000012159 d64 = getDisp64(delta);
12160 delta += 8;
12161 ty = szToITy(sz);
12162 addr = newTemp(Ity_I64);
sewardj42561ef2005-11-04 14:18:31 +000012163 assign( addr, handleAddrOverrides(pfx, mkU64(d64)) );
sewardj87277cb2005-08-01 13:03:32 +000012164 storeLE( mkexpr(addr), getIRegRAX(sz) );
12165 DIP("mov%c %s, %s0x%llx\n", nameISize(sz), nameIRegRAX(sz),
12166 sorbTxt(pfx), d64);
12167 break;
sewardjb095fba2005-02-13 14:13:04 +000012168
sewardj8711f662005-05-09 17:52:56 +000012169 /* XXXX be careful here with moves to AH/BH/CH/DH */
sewardj007e9ec2005-03-23 11:36:48 +000012170 case 0xB0: /* MOV imm,AL */
12171 case 0xB1: /* MOV imm,CL */
sewardjb095fba2005-02-13 14:13:04 +000012172 case 0xB2: /* MOV imm,DL */
sewardj007e9ec2005-03-23 11:36:48 +000012173 case 0xB3: /* MOV imm,BL */
12174 case 0xB4: /* MOV imm,AH */
12175 case 0xB5: /* MOV imm,CH */
12176 case 0xB6: /* MOV imm,DH */
sewardj31eecde2005-03-23 03:39:55 +000012177 case 0xB7: /* MOV imm,BH */
sewardj5b470602005-02-27 13:10:48 +000012178 if (haveF2orF3(pfx)) goto decode_failure;
sewardjb095fba2005-02-13 14:13:04 +000012179 d64 = getUChar(delta);
12180 delta += 1;
sewardj5b470602005-02-27 13:10:48 +000012181 putIRegRexB(1, pfx, opc-0xB0, mkU8(d64));
12182 DIP("movb $%lld,%s\n", d64, nameIRegRexB(1,pfx,opc-0xB0));
sewardjb095fba2005-02-13 14:13:04 +000012183 break;
sewardj1389d4d2005-01-28 13:46:29 +000012184
12185 case 0xB8: /* MOV imm,eAX */
12186 case 0xB9: /* MOV imm,eCX */
12187 case 0xBA: /* MOV imm,eDX */
12188 case 0xBB: /* MOV imm,eBX */
12189 case 0xBC: /* MOV imm,eSP */
12190 case 0xBD: /* MOV imm,eBP */
12191 case 0xBE: /* MOV imm,eSI */
12192 case 0xBF: /* MOV imm,eDI */
sewardj03b07cc2005-01-31 18:09:43 +000012193 /* This is the one-and-only place where 64-bit literals are
12194 allowed in the instruction stream. */
sewardj5b470602005-02-27 13:10:48 +000012195 if (haveF2orF3(pfx)) goto decode_failure;
sewardj03b07cc2005-01-31 18:09:43 +000012196 if (sz == 8) {
12197 d64 = getDisp64(delta);
sewardj7eaa7cf2005-01-31 18:55:22 +000012198 delta += 8;
sewardj5b470602005-02-27 13:10:48 +000012199 putIRegRexB(8, pfx, opc-0xB8, mkU64(d64));
sewardj227458e2005-01-31 19:04:50 +000012200 DIP("movabsq $%lld,%s\n", (Long)d64,
sewardj5b470602005-02-27 13:10:48 +000012201 nameIRegRexB(8,pfx,opc-0xB8));
sewardj03b07cc2005-01-31 18:09:43 +000012202 } else {
12203 d64 = getSDisp(imin(4,sz),delta);
12204 delta += imin(4,sz);
sewardj5b470602005-02-27 13:10:48 +000012205 putIRegRexB(sz, pfx, opc-0xB8,
12206 mkU(szToITy(sz), d64 & mkSizeMask(sz)));
sewardj227458e2005-01-31 19:04:50 +000012207 DIP("mov%c $%lld,%s\n", nameISize(sz),
12208 (Long)d64,
sewardj5b470602005-02-27 13:10:48 +000012209 nameIRegRexB(sz,pfx,opc-0xB8));
sewardj03b07cc2005-01-31 18:09:43 +000012210 }
sewardj1389d4d2005-01-28 13:46:29 +000012211 break;
12212
12213 case 0xC6: /* MOV Ib,Eb */
12214 sz = 1;
12215 goto do_Mov_I_E;
12216 case 0xC7: /* MOV Iv,Ev */
12217 goto do_Mov_I_E;
12218
12219 do_Mov_I_E:
sewardj5b470602005-02-27 13:10:48 +000012220 if (haveF2orF3(pfx)) goto decode_failure;
sewardj1389d4d2005-01-28 13:46:29 +000012221 modrm = getUChar(delta);
12222 if (epartIsReg(modrm)) {
sewardj1389d4d2005-01-28 13:46:29 +000012223 delta++; /* mod/rm byte */
12224 d64 = getSDisp(imin(4,sz),delta);
12225 delta += imin(4,sz);
sewardj5b470602005-02-27 13:10:48 +000012226 putIRegE(sz, pfx, modrm,
12227 mkU(szToITy(sz), d64 & mkSizeMask(sz)));
sewardj227458e2005-01-31 19:04:50 +000012228 DIP("mov%c $%lld, %s\n", nameISize(sz),
12229 (Long)d64,
sewardj5b470602005-02-27 13:10:48 +000012230 nameIRegE(sz,pfx,modrm));
sewardj1389d4d2005-01-28 13:46:29 +000012231 } else {
sewardj5b470602005-02-27 13:10:48 +000012232 addr = disAMode ( &alen, pfx, delta, dis_buf,
12233 /*xtra*/imin(4,sz) );
sewardj1389d4d2005-01-28 13:46:29 +000012234 delta += alen;
sewardje941eea2005-01-30 19:52:28 +000012235 d64 = getSDisp(imin(4,sz),delta);
sewardj1389d4d2005-01-28 13:46:29 +000012236 delta += imin(4,sz);
sewardje941eea2005-01-30 19:52:28 +000012237 storeLE(mkexpr(addr),
12238 mkU(szToITy(sz), d64 & mkSizeMask(sz)));
sewardj227458e2005-01-31 19:04:50 +000012239 DIP("mov%c $%lld, %s\n", nameISize(sz), (Long)d64, dis_buf);
sewardj1389d4d2005-01-28 13:46:29 +000012240 }
12241 break;
12242
sewardj5e525292005-01-28 15:13:10 +000012243 /* ------------------------ MOVx ------------------------ */
12244
12245 case 0x63: /* MOVSX */
sewardj5b470602005-02-27 13:10:48 +000012246 if (haveF2orF3(pfx)) goto decode_failure;
sewardj5e525292005-01-28 15:13:10 +000012247 if (haveREX(pfx) && 1==getRexW(pfx)) {
12248 vassert(sz == 8);
12249 /* movsx r/m32 to r64 */
12250 modrm = getUChar(delta);
12251 if (epartIsReg(modrm)) {
12252 delta++;
sewardj5b470602005-02-27 13:10:48 +000012253 putIRegG(8, pfx, modrm,
sewardj5e525292005-01-28 15:13:10 +000012254 unop(Iop_32Sto64,
sewardj5b470602005-02-27 13:10:48 +000012255 getIRegE(4, pfx, modrm)));
sewardj5e525292005-01-28 15:13:10 +000012256 DIP("movslq %s,%s\n",
sewardj5b470602005-02-27 13:10:48 +000012257 nameIRegE(4, pfx, modrm),
12258 nameIRegG(8, pfx, modrm));
sewardj5e525292005-01-28 15:13:10 +000012259 break;
12260 } else {
sewardje1698952005-02-08 15:02:39 +000012261 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
sewardj5e525292005-01-28 15:13:10 +000012262 delta += alen;
sewardj5b470602005-02-27 13:10:48 +000012263 putIRegG(8, pfx, modrm,
sewardj5e525292005-01-28 15:13:10 +000012264 unop(Iop_32Sto64,
12265 loadLE(Ity_I32, mkexpr(addr))));
12266 DIP("movslq %s,%s\n", dis_buf,
sewardj5b470602005-02-27 13:10:48 +000012267 nameIRegG(8, pfx, modrm));
sewardj5e525292005-01-28 15:13:10 +000012268 break;
12269 }
12270 } else {
12271 goto decode_failure;
12272 }
12273
sewardj4c328cf2005-05-05 12:05:54 +000012274 /* ------------------------ opl imm, A ----------------- */
12275
12276 case 0x04: /* ADD Ib, AL */
12277 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000012278 delta = dis_op_imm_A( 1, False, Iop_Add8, True, delta, "add" );
sewardj4c328cf2005-05-05 12:05:54 +000012279 break;
sewardj03b07cc2005-01-31 18:09:43 +000012280 case 0x05: /* ADD Iv, eAX */
sewardj5b470602005-02-27 13:10:48 +000012281 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000012282 delta = dis_op_imm_A(sz, False, Iop_Add8, True, delta, "add" );
sewardj03b07cc2005-01-31 18:09:43 +000012283 break;
12284
sewardj007e9ec2005-03-23 11:36:48 +000012285 case 0x0C: /* OR Ib, AL */
12286 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000012287 delta = dis_op_imm_A( 1, False, Iop_Or8, True, delta, "or" );
sewardj007e9ec2005-03-23 11:36:48 +000012288 break;
sewardj03b07cc2005-01-31 18:09:43 +000012289 case 0x0D: /* OR Iv, eAX */
sewardj5b470602005-02-27 13:10:48 +000012290 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000012291 delta = dis_op_imm_A( sz, False, Iop_Or8, True, delta, "or" );
sewardj03b07cc2005-01-31 18:09:43 +000012292 break;
12293
sewardj41c01092005-07-23 13:50:32 +000012294 case 0x14: /* ADC Ib, AL */
12295 delta = dis_op_imm_A( 1, True, Iop_Add8, True, delta, "adc" );
12296 break;
sewardjd20c8852005-01-20 20:04:07 +000012297//.. //-- case 0x15: /* ADC Iv, eAX */
12298//.. //-- delta = dis_op_imm_A( sz, ADC, True, delta, "adc" );
12299//.. //-- break;
12300//.. //--
12301//.. //-- case 0x1C: /* SBB Ib, AL */
12302//.. //-- delta = dis_op_imm_A( 1, SBB, True, delta, "sbb" );
12303//.. //-- break;
12304//.. //-- case 0x1D: /* SBB Iv, eAX */
12305//.. //-- delta = dis_op_imm_A( sz, SBB, True, delta, "sbb" );
12306//.. //-- break;
12307//.. //--
sewardj007e9ec2005-03-23 11:36:48 +000012308 case 0x24: /* AND Ib, AL */
12309 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000012310 delta = dis_op_imm_A( 1, False, Iop_And8, True, delta, "and" );
sewardj007e9ec2005-03-23 11:36:48 +000012311 break;
sewardj3ca55a12005-01-27 16:06:23 +000012312 case 0x25: /* AND Iv, eAX */
12313 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000012314 delta = dis_op_imm_A( sz, False, Iop_And8, True, delta, "and" );
sewardj3ca55a12005-01-27 16:06:23 +000012315 break;
12316
sewardj137015d2005-03-27 04:01:15 +000012317 case 0x2C: /* SUB Ib, AL */
12318 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000012319 delta = dis_op_imm_A(1, False, Iop_Sub8, True, delta, "sub" );
sewardj137015d2005-03-27 04:01:15 +000012320 break;
sewardj03b07cc2005-01-31 18:09:43 +000012321 case 0x2D: /* SUB Iv, eAX */
sewardj5b470602005-02-27 13:10:48 +000012322 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000012323 delta = dis_op_imm_A( sz, False, Iop_Sub8, True, delta, "sub" );
sewardj03b07cc2005-01-31 18:09:43 +000012324 break;
12325
sewardj8eb804f2005-05-18 10:22:47 +000012326 case 0x34: /* XOR Ib, AL */
12327 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000012328 delta = dis_op_imm_A( 1, False, Iop_Xor8, True, delta, "xor" );
sewardj8eb804f2005-05-18 10:22:47 +000012329 break;
sewardj85520e42005-02-19 15:22:38 +000012330 case 0x35: /* XOR Iv, eAX */
sewardj5b470602005-02-27 13:10:48 +000012331 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000012332 delta = dis_op_imm_A( sz, False, Iop_Xor8, True, delta, "xor" );
sewardj85520e42005-02-19 15:22:38 +000012333 break;
sewardj03b07cc2005-01-31 18:09:43 +000012334
12335 case 0x3C: /* CMP Ib, AL */
12336 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000012337 delta = dis_op_imm_A( 1, False, Iop_Sub8, False, delta, "cmp" );
sewardj03b07cc2005-01-31 18:09:43 +000012338 break;
sewardj354e5c62005-01-27 20:12:52 +000012339 case 0x3D: /* CMP Iv, eAX */
12340 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000012341 delta = dis_op_imm_A( sz, False, Iop_Sub8, False, delta, "cmp" );
sewardj354e5c62005-01-27 20:12:52 +000012342 break;
12343
sewardj118b23e2005-01-29 02:14:44 +000012344 case 0xA8: /* TEST Ib, AL */
sewardj03b07cc2005-01-31 18:09:43 +000012345 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000012346 delta = dis_op_imm_A( 1, False, Iop_And8, False, delta, "test" );
sewardj118b23e2005-01-29 02:14:44 +000012347 break;
12348 case 0xA9: /* TEST Iv, eAX */
sewardj03b07cc2005-01-31 18:09:43 +000012349 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000012350 delta = dis_op_imm_A( sz, False, Iop_And8, False, delta, "test" );
sewardj118b23e2005-01-29 02:14:44 +000012351 break;
12352
12353 /* ------------------------ opl Ev, Gv ----------------- */
12354
sewardj03b07cc2005-01-31 18:09:43 +000012355 case 0x02: /* ADD Eb,Gb */
12356 if (haveF2orF3(pfx)) goto decode_failure;
12357 delta = dis_op2_E_G ( pfx, False, Iop_Add8, True, 1, delta, "add" );
12358 break;
sewardjdf0e0022005-01-25 15:48:43 +000012359 case 0x03: /* ADD Ev,Gv */
sewardj3ca55a12005-01-27 16:06:23 +000012360 if (haveF2orF3(pfx)) goto decode_failure;
sewardjdf0e0022005-01-25 15:48:43 +000012361 delta = dis_op2_E_G ( pfx, False, Iop_Add8, True, sz, delta, "add" );
sewardjdf0e0022005-01-25 15:48:43 +000012362 break;
12363
sewardj03b07cc2005-01-31 18:09:43 +000012364 case 0x0A: /* OR Eb,Gb */
sewardj5b470602005-02-27 13:10:48 +000012365 if (haveF2orF3(pfx)) goto decode_failure;
sewardj03b07cc2005-01-31 18:09:43 +000012366 delta = dis_op2_E_G ( pfx, False, Iop_Or8, True, 1, delta, "or" );
12367 break;
12368 case 0x0B: /* OR Ev,Gv */
sewardj5b470602005-02-27 13:10:48 +000012369 if (haveF2orF3(pfx)) goto decode_failure;
sewardj03b07cc2005-01-31 18:09:43 +000012370 delta = dis_op2_E_G ( pfx, False, Iop_Or8, True, sz, delta, "or" );
12371 break;
12372//--
sewardjd20c8852005-01-20 20:04:07 +000012373//.. //-- case 0x12: /* ADC Eb,Gb */
12374//.. //-- delta = dis_op2_E_G ( sorb, True, ADC, True, 1, delta, "adc" );
12375//.. //-- break;
sewardj22cab062005-07-19 23:59:54 +000012376 case 0x13: /* ADC Ev,Gv */
12377 delta = dis_op2_E_G ( pfx, True, Iop_Add8, True, sz, delta, "adc" );
12378 break;
12379
sewardjd20c8852005-01-20 20:04:07 +000012380//.. //-- case 0x1A: /* SBB Eb,Gb */
12381//.. //-- delta = dis_op2_E_G ( sorb, True, SBB, True, 1, delta, "sbb" );
12382//.. //-- break;
sewardj7a06b852005-07-20 10:55:26 +000012383 case 0x1B: /* SBB Ev,Gv */
12384 delta = dis_op2_E_G ( pfx, True, Iop_Sub8, True, sz, delta, "sbb" );
12385 break;
sewardj03b07cc2005-01-31 18:09:43 +000012386
12387 case 0x22: /* AND Eb,Gb */
12388 if (haveF2orF3(pfx)) goto decode_failure;
12389 delta = dis_op2_E_G ( pfx, False, Iop_And8, True, 1, delta, "and" );
12390 break;
12391 case 0x23: /* AND Ev,Gv */
12392 if (haveF2orF3(pfx)) goto decode_failure;
12393 delta = dis_op2_E_G ( pfx, False, Iop_And8, True, sz, delta, "and" );
12394 break;
12395
12396 case 0x2A: /* SUB Eb,Gb */
12397 if (haveF2orF3(pfx)) goto decode_failure;
12398 delta = dis_op2_E_G ( pfx, False, Iop_Sub8, True, 1, delta, "sub" );
12399 break;
sewardj118b23e2005-01-29 02:14:44 +000012400 case 0x2B: /* SUB Ev,Gv */
sewardj03b07cc2005-01-31 18:09:43 +000012401 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000012402 delta = dis_op2_E_G ( pfx, False, Iop_Sub8, True, sz, delta, "sub" );
12403 break;
12404
sewardj03b07cc2005-01-31 18:09:43 +000012405 case 0x32: /* XOR Eb,Gb */
12406 if (haveF2orF3(pfx)) goto decode_failure;
12407 delta = dis_op2_E_G ( pfx, False, Iop_Xor8, True, 1, delta, "xor" );
12408 break;
12409 case 0x33: /* XOR Ev,Gv */
12410 if (haveF2orF3(pfx)) goto decode_failure;
12411 delta = dis_op2_E_G ( pfx, False, Iop_Xor8, True, sz, delta, "xor" );
12412 break;
12413
sewardjb095fba2005-02-13 14:13:04 +000012414 case 0x3A: /* CMP Eb,Gb */
12415 if (haveF2orF3(pfx)) goto decode_failure;
12416 delta = dis_op2_E_G ( pfx, False, Iop_Sub8, False, 1, delta, "cmp" );
12417 break;
sewardj354e5c62005-01-27 20:12:52 +000012418 case 0x3B: /* CMP Ev,Gv */
12419 if (haveF2orF3(pfx)) goto decode_failure;
12420 delta = dis_op2_E_G ( pfx, False, Iop_Sub8, False, sz, delta, "cmp" );
12421 break;
12422
sewardj118b23e2005-01-29 02:14:44 +000012423 case 0x84: /* TEST Eb,Gb */
sewardj03b07cc2005-01-31 18:09:43 +000012424 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000012425 delta = dis_op2_E_G ( pfx, False, Iop_And8, False, 1, delta, "test" );
12426 break;
12427 case 0x85: /* TEST Ev,Gv */
sewardj03b07cc2005-01-31 18:09:43 +000012428 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000012429 delta = dis_op2_E_G ( pfx, False, Iop_And8, False, sz, delta, "test" );
12430 break;
12431
12432 /* ------------------------ opl Gv, Ev ----------------- */
12433
sewardj85520e42005-02-19 15:22:38 +000012434 case 0x00: /* ADD Gb,Eb */
12435 if (haveF2orF3(pfx)) goto decode_failure;
12436 delta = dis_op2_G_E ( pfx, False, Iop_Add8, True, 1, delta, "add" );
12437 break;
sewardj3ca55a12005-01-27 16:06:23 +000012438 case 0x01: /* ADD Gv,Ev */
sewardj354e5c62005-01-27 20:12:52 +000012439 if (haveF2orF3(pfx)) goto decode_failure;
sewardj3ca55a12005-01-27 16:06:23 +000012440 delta = dis_op2_G_E ( pfx, False, Iop_Add8, True, sz, delta, "add" );
12441 break;
12442
sewardj03b07cc2005-01-31 18:09:43 +000012443 case 0x08: /* OR Gb,Eb */
12444 if (haveF2orF3(pfx)) goto decode_failure;
12445 delta = dis_op2_G_E ( pfx, False, Iop_Or8, True, 1, delta, "or" );
12446 break;
sewardj55dbb262005-01-28 16:36:51 +000012447 case 0x09: /* OR Gv,Ev */
12448 if (haveF2orF3(pfx)) goto decode_failure;
12449 delta = dis_op2_G_E ( pfx, False, Iop_Or8, True, sz, delta, "or" );
12450 break;
12451
sewardj85520e42005-02-19 15:22:38 +000012452 case 0x10: /* ADC Gb,Eb */
12453 if (haveF2orF3(pfx)) goto decode_failure;
12454 delta = dis_op2_G_E ( pfx, True, Iop_Add8, True, 1, delta, "adc" );
12455 break;
12456 case 0x11: /* ADC Gv,Ev */
12457 if (haveF2orF3(pfx)) goto decode_failure;
12458 delta = dis_op2_G_E ( pfx, True, Iop_Add8, True, sz, delta, "adc" );
12459 break;
12460
12461 case 0x18: /* SBB Gb,Eb */
12462 if (haveF2orF3(pfx)) goto decode_failure;
12463 delta = dis_op2_G_E ( pfx, True, Iop_Sub8, True, 1, delta, "sbb" );
12464 break;
sewardj03b07cc2005-01-31 18:09:43 +000012465 case 0x19: /* SBB Gv,Ev */
sewardja6b93d12005-02-17 09:28:28 +000012466 if (haveF2orF3(pfx)) goto decode_failure;
sewardj03b07cc2005-01-31 18:09:43 +000012467 delta = dis_op2_G_E ( pfx, True, Iop_Sub8, True, sz, delta, "sbb" );
12468 break;
12469
sewardj85520e42005-02-19 15:22:38 +000012470 case 0x20: /* AND Gb,Eb */
12471 if (haveF2orF3(pfx)) goto decode_failure;
12472 delta = dis_op2_G_E ( pfx, False, Iop_And8, True, 1, delta, "and" );
12473 break;
sewardj3ca55a12005-01-27 16:06:23 +000012474 case 0x21: /* AND Gv,Ev */
sewardj354e5c62005-01-27 20:12:52 +000012475 if (haveF2orF3(pfx)) goto decode_failure;
sewardj3ca55a12005-01-27 16:06:23 +000012476 delta = dis_op2_G_E ( pfx, False, Iop_And8, True, sz, delta, "and" );
12477 break;
sewardj03b07cc2005-01-31 18:09:43 +000012478
12479 case 0x28: /* SUB Gb,Eb */
12480 if (haveF2orF3(pfx)) goto decode_failure;
12481 delta = dis_op2_G_E ( pfx, False, Iop_Sub8, True, 1, delta, "sub" );
12482 break;
sewardj118b23e2005-01-29 02:14:44 +000012483 case 0x29: /* SUB Gv,Ev */
sewardj03b07cc2005-01-31 18:09:43 +000012484 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000012485 delta = dis_op2_G_E ( pfx, False, Iop_Sub8, True, sz, delta, "sub" );
12486 break;
12487
sewardjb095fba2005-02-13 14:13:04 +000012488 case 0x30: /* XOR Gb,Eb */
12489 if (haveF2orF3(pfx)) goto decode_failure;
12490 delta = dis_op2_G_E ( pfx, False, Iop_Xor8, True, 1, delta, "xor" );
12491 break;
sewardj118b23e2005-01-29 02:14:44 +000012492 case 0x31: /* XOR Gv,Ev */
sewardj03b07cc2005-01-31 18:09:43 +000012493 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000012494 delta = dis_op2_G_E ( pfx, False, Iop_Xor8, True, sz, delta, "xor" );
12495 break;
sewardj354e5c62005-01-27 20:12:52 +000012496
12497 case 0x38: /* CMP Gb,Eb */
12498 if (haveF2orF3(pfx)) goto decode_failure;
12499 delta = dis_op2_G_E ( pfx, False, Iop_Sub8, False, 1, delta, "cmp" );
12500 break;
12501 case 0x39: /* CMP Gv,Ev */
12502 if (haveF2orF3(pfx)) goto decode_failure;
12503 delta = dis_op2_G_E ( pfx, False, Iop_Sub8, False, sz, delta, "cmp" );
12504 break;
12505
sewardj55dbb262005-01-28 16:36:51 +000012506 /* ------------------------ POP ------------------------ */
12507
12508 case 0x58: /* POP eAX */
12509 case 0x59: /* POP eCX */
12510 case 0x5A: /* POP eDX */
12511 case 0x5B: /* POP eBX */
12512 case 0x5D: /* POP eBP */
12513 case 0x5E: /* POP eSI */
12514 case 0x5F: /* POP eDI */
12515 case 0x5C: /* POP eSP */
sewardj03b07cc2005-01-31 18:09:43 +000012516 if (haveF2orF3(pfx)) goto decode_failure;
sewardj55dbb262005-01-28 16:36:51 +000012517 vassert(sz == 2 || sz == 4 || sz == 8);
12518 if (sz == 4)
12519 sz = 8; /* there is no encoding for 32-bit pop in 64-bit mode */
12520 t1 = newTemp(szToITy(sz));
12521 t2 = newTemp(Ity_I64);
12522 assign(t2, getIReg64(R_RSP));
12523 assign(t1, loadLE(szToITy(sz),mkexpr(t2)));
12524 putIReg64(R_RSP, binop(Iop_Add64, mkexpr(t2), mkU64(sz)));
sewardj5b470602005-02-27 13:10:48 +000012525 putIRegRexB(sz, pfx, opc-0x58, mkexpr(t1));
12526 DIP("pop%c %s\n", nameISize(sz), nameIRegRexB(sz,pfx,opc-0x58));
sewardj55dbb262005-01-28 16:36:51 +000012527 break;
12528
sewardj85520e42005-02-19 15:22:38 +000012529 case 0x9D: /* POPF */
12530 /* Note. There is no encoding for a 32-bit popf in 64-bit mode.
12531 So sz==4 actually means sz==8. */
sewardj5b470602005-02-27 13:10:48 +000012532 if (haveF2orF3(pfx)) goto decode_failure;
sewardj85520e42005-02-19 15:22:38 +000012533 vassert(sz == 2 || sz == 4);
12534 if (sz == 4) sz = 8;
sewardj5b470602005-02-27 13:10:48 +000012535 if (sz != 8) goto decode_failure; // until we know a sz==2 test case exists
sewardj85520e42005-02-19 15:22:38 +000012536 t1 = newTemp(Ity_I64); t2 = newTemp(Ity_I64);
12537 assign(t2, getIReg64(R_RSP));
12538 assign(t1, widenUto64(loadLE(szToITy(sz),mkexpr(t2))));
12539 putIReg64(R_RSP, binop(Iop_Add64, mkexpr(t2), mkU64(sz)));
12540 /* t1 is the flag word. Mask out everything except OSZACP and
12541 set the flags thunk to AMD64G_CC_OP_COPY. */
12542 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(AMD64G_CC_OP_COPY) ));
12543 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
12544 stmt( IRStmt_Put( OFFB_CC_DEP1,
12545 binop(Iop_And64,
12546 mkexpr(t1),
12547 mkU64( AMD64G_CC_MASK_C | AMD64G_CC_MASK_P
12548 | AMD64G_CC_MASK_A | AMD64G_CC_MASK_Z
12549 | AMD64G_CC_MASK_S| AMD64G_CC_MASK_O )
12550 )
12551 )
12552 );
12553
12554 /* Also need to set the D flag, which is held in bit 10 of t1.
12555 If zero, put 1 in OFFB_DFLAG, else -1 in OFFB_DFLAG. */
12556 stmt( IRStmt_Put(
12557 OFFB_DFLAG,
12558 IRExpr_Mux0X(
12559 unop(Iop_32to8,
12560 unop(Iop_64to32,
12561 binop(Iop_And64,
12562 binop(Iop_Shr64, mkexpr(t1), mkU8(10)),
12563 mkU64(1)))),
12564 mkU64(1),
12565 mkU64(0xFFFFFFFFFFFFFFFFULL)))
12566 );
12567
12568 /* And set the ID flag */
12569 stmt( IRStmt_Put(
12570 OFFB_IDFLAG,
12571 IRExpr_Mux0X(
12572 unop(Iop_32to8,
12573 unop(Iop_64to32,
12574 binop(Iop_And64,
12575 binop(Iop_Shr64, mkexpr(t1), mkU8(21)),
12576 mkU64(1)))),
12577 mkU64(0),
12578 mkU64(1)))
12579 );
12580
12581 DIP("popf%c\n", nameISize(sz));
12582 break;
12583
sewardjd20c8852005-01-20 20:04:07 +000012584//.. case 0x61: /* POPA */
12585//.. /* This is almost certainly wrong for sz==2. So ... */
12586//.. if (sz != 4) goto decode_failure;
12587//..
12588//.. /* t5 is the old %ESP value. */
12589//.. t5 = newTemp(Ity_I32);
12590//.. assign( t5, getIReg(4, R_ESP) );
12591//..
12592//.. /* Reload all the registers, except %esp. */
12593//.. putIReg(4,R_EAX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(28)) ));
12594//.. putIReg(4,R_ECX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(24)) ));
12595//.. putIReg(4,R_EDX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(20)) ));
12596//.. putIReg(4,R_EBX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(16)) ));
12597//.. /* ignore saved %ESP */
12598//.. putIReg(4,R_EBP, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32( 8)) ));
12599//.. putIReg(4,R_ESI, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32( 4)) ));
12600//.. putIReg(4,R_EDI, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32( 0)) ));
12601//..
12602//.. /* and move %ESP back up */
12603//.. putIReg( 4, R_ESP, binop(Iop_Add32, mkexpr(t5), mkU32(8*4)) );
12604//..
12605//.. DIP("pusha%c\n", nameISize(sz));
12606//.. break;
sewardj432f8b62005-05-10 02:50:05 +000012607
12608 case 0x8F: { /* POPQ m64 / POPW m16 */
sewardj1bd14e72005-05-11 16:24:00 +000012609 Int len;
12610 UChar rm;
sewardj432f8b62005-05-10 02:50:05 +000012611 /* There is no encoding for 32-bit pop in 64-bit mode.
12612 So sz==4 actually means sz==8. */
12613 if (haveF2orF3(pfx)) goto decode_failure;
12614 vassert(sz == 2 || sz == 4);
12615 if (sz == 4) sz = 8;
12616 if (sz != 8) goto decode_failure; // until we know a sz==2 test case exists
12617
sewardj1bd14e72005-05-11 16:24:00 +000012618 rm = getUChar(delta);
sewardj432f8b62005-05-10 02:50:05 +000012619
12620 /* make sure this instruction is correct POP */
12621 if (epartIsReg(rm) || gregLO3ofRM(rm) != 0)
12622 goto decode_failure;
12623 /* and has correct size */
12624 vassert(sz == 8);
12625
12626 t1 = newTemp(Ity_I64);
12627 t3 = newTemp(Ity_I64);
12628 assign( t1, getIReg64(R_RSP) );
12629 assign( t3, loadLE(Ity_I64, mkexpr(t1)) );
12630
12631 /* Increase RSP; must be done before the STORE. Intel manual
12632 says: If the RSP register is used as a base register for
12633 addressing a destination operand in memory, the POP
12634 instruction computes the effective address of the operand
12635 after it increments the RSP register. */
12636 putIReg64(R_RSP, binop(Iop_Add64, mkexpr(t1), mkU64(sz)) );
12637
12638 addr = disAMode ( &len, pfx, delta, dis_buf, 0 );
12639 storeLE( mkexpr(addr), mkexpr(t3) );
12640
12641 DIP("popl %s\n", dis_buf);
12642
12643 delta += len;
12644 break;
12645 }
12646
sewardjd20c8852005-01-20 20:04:07 +000012647//.. //-- case 0x1F: /* POP %DS */
12648//.. //-- dis_pop_segreg( cb, R_DS, sz ); break;
12649//.. //-- case 0x07: /* POP %ES */
12650//.. //-- dis_pop_segreg( cb, R_ES, sz ); break;
12651//.. //-- case 0x17: /* POP %SS */
12652//.. //-- dis_pop_segreg( cb, R_SS, sz ); break;
sewardj55dbb262005-01-28 16:36:51 +000012653
12654 /* ------------------------ PUSH ----------------------- */
12655
12656 case 0x50: /* PUSH eAX */
12657 case 0x51: /* PUSH eCX */
12658 case 0x52: /* PUSH eDX */
12659 case 0x53: /* PUSH eBX */
12660 case 0x55: /* PUSH eBP */
12661 case 0x56: /* PUSH eSI */
12662 case 0x57: /* PUSH eDI */
12663 case 0x54: /* PUSH eSP */
12664 /* This is the Right Way, in that the value to be pushed is
12665 established before %rsp is changed, so that pushq %rsp
12666 correctly pushes the old value. */
sewardj03b07cc2005-01-31 18:09:43 +000012667 if (haveF2orF3(pfx)) goto decode_failure;
sewardj55dbb262005-01-28 16:36:51 +000012668 vassert(sz == 2 || sz == 4 || sz == 8);
12669 if (sz == 4)
12670 sz = 8; /* there is no encoding for 32-bit push in 64-bit mode */
12671 ty = sz==2 ? Ity_I16 : Ity_I64;
12672 t1 = newTemp(ty);
12673 t2 = newTemp(Ity_I64);
sewardj5b470602005-02-27 13:10:48 +000012674 assign(t1, getIRegRexB(sz, pfx, opc-0x50));
sewardj55dbb262005-01-28 16:36:51 +000012675 assign(t2, binop(Iop_Sub64, getIReg64(R_RSP), mkU64(sz)));
12676 putIReg64(R_RSP, mkexpr(t2) );
12677 storeLE(mkexpr(t2),mkexpr(t1));
sewardj5b470602005-02-27 13:10:48 +000012678 DIP("push%c %s\n", nameISize(sz), nameIRegRexB(sz,pfx,opc-0x50));
sewardj55dbb262005-01-28 16:36:51 +000012679 break;
12680
sewardja6b93d12005-02-17 09:28:28 +000012681 case 0x68: /* PUSH Iv */
sewardj5b470602005-02-27 13:10:48 +000012682 if (haveF2orF3(pfx)) goto decode_failure;
sewardja6b93d12005-02-17 09:28:28 +000012683 /* Note, sz==4 is not possible in 64-bit mode. Hence ... */
12684 if (sz == 4) sz = 8;
12685 d64 = getSDisp(imin(4,sz),delta);
12686 delta += imin(4,sz);
12687 goto do_push_I;
sewardj909c06d2005-02-19 22:47:41 +000012688 case 0x6A: /* PUSH Ib, sign-extended to sz */
sewardj5b470602005-02-27 13:10:48 +000012689 if (haveF2orF3(pfx)) goto decode_failure;
sewardj909c06d2005-02-19 22:47:41 +000012690 /* Note, sz==4 is not possible in 64-bit mode. Hence ... */
12691 if (sz == 4) sz = 8;
12692 d64 = getSDisp8(delta); delta += 1;
12693 goto do_push_I;
sewardja6b93d12005-02-17 09:28:28 +000012694 do_push_I:
12695 ty = szToITy(sz);
sewardj909c06d2005-02-19 22:47:41 +000012696 t1 = newTemp(Ity_I64);
12697 t2 = newTemp(ty);
sewardja6b93d12005-02-17 09:28:28 +000012698 assign( t1, binop(Iop_Sub64,getIReg64(R_RSP),mkU64(sz)) );
12699 putIReg64(R_RSP, mkexpr(t1) );
12700 storeLE( mkexpr(t1), mkU(ty,d64) );
sewardj1027dc22005-02-26 01:55:02 +000012701 DIP("push%c $%lld\n", nameISize(sz), (Long)d64);
sewardja6b93d12005-02-17 09:28:28 +000012702 break;
12703
sewardj85520e42005-02-19 15:22:38 +000012704 case 0x9C: /* PUSHF */ {
12705 /* Note. There is no encoding for a 32-bit pushf in 64-bit
12706 mode. So sz==4 actually means sz==8. */
sewardj5b470602005-02-27 13:10:48 +000012707 if (haveF2orF3(pfx)) goto decode_failure;
sewardj85520e42005-02-19 15:22:38 +000012708 vassert(sz == 2 || sz == 4);
12709 if (sz == 4) sz = 8;
sewardj5b470602005-02-27 13:10:48 +000012710 if (sz != 8) goto decode_failure; // until we know a sz==2 test case exists
sewardj85520e42005-02-19 15:22:38 +000012711
12712 t1 = newTemp(Ity_I64);
12713 assign( t1, binop(Iop_Sub64,getIReg64(R_RSP),mkU64(sz)) );
12714 putIReg64(R_RSP, mkexpr(t1) );
12715
12716 t2 = newTemp(Ity_I64);
12717 assign( t2, mk_amd64g_calculate_rflags_all() );
12718
12719 /* Patch in the D flag. This can simply be a copy of bit 10 of
12720 baseBlock[OFFB_DFLAG]. */
12721 t3 = newTemp(Ity_I64);
12722 assign( t3, binop(Iop_Or64,
12723 mkexpr(t2),
12724 binop(Iop_And64,
12725 IRExpr_Get(OFFB_DFLAG,Ity_I64),
12726 mkU64(1<<10)))
12727 );
12728
12729 /* And patch in the ID flag. */
12730 t4 = newTemp(Ity_I64);
12731 assign( t4, binop(Iop_Or64,
12732 mkexpr(t3),
12733 binop(Iop_And64,
12734 binop(Iop_Shl64, IRExpr_Get(OFFB_IDFLAG,Ity_I64),
12735 mkU8(21)),
12736 mkU64(1<<21)))
12737 );
12738
12739 /* if sz==2, the stored value needs to be narrowed. */
12740 if (sz == 2)
12741 storeLE( mkexpr(t1), unop(Iop_32to16,
12742 unop(Iop_64to32,mkexpr(t4))) );
12743 else
12744 storeLE( mkexpr(t1), mkexpr(t4) );
12745
12746 DIP("pushf%c\n", nameISize(sz));
12747 break;
12748 }
12749
sewardjd20c8852005-01-20 20:04:07 +000012750//.. case 0x60: /* PUSHA */
12751//.. /* This is almost certainly wrong for sz==2. So ... */
12752//.. if (sz != 4) goto decode_failure;
12753//..
12754//.. /* This is the Right Way, in that the value to be pushed is
12755//.. established before %esp is changed, so that pusha
12756//.. correctly pushes the old %esp value. New value of %esp is
12757//.. pushed at start. */
12758//.. /* t0 is the %ESP value we're going to push. */
12759//.. t0 = newTemp(Ity_I32);
12760//.. assign( t0, getIReg(4, R_ESP) );
12761//..
12762//.. /* t5 will be the new %ESP value. */
12763//.. t5 = newTemp(Ity_I32);
12764//.. assign( t5, binop(Iop_Sub32, mkexpr(t0), mkU32(8*4)) );
12765//..
12766//.. /* Update guest state before prodding memory. */
12767//.. putIReg(4, R_ESP, mkexpr(t5));
12768//..
12769//.. /* Dump all the registers. */
12770//.. storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(28)), getIReg(4,R_EAX) );
12771//.. storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(24)), getIReg(4,R_ECX) );
12772//.. storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(20)), getIReg(4,R_EDX) );
12773//.. storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(16)), getIReg(4,R_EBX) );
12774//.. storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(12)), mkexpr(t0) /*esp*/);
12775//.. storeLE( binop(Iop_Add32,mkexpr(t5),mkU32( 8)), getIReg(4,R_EBP) );
12776//.. storeLE( binop(Iop_Add32,mkexpr(t5),mkU32( 4)), getIReg(4,R_ESI) );
12777//.. storeLE( binop(Iop_Add32,mkexpr(t5),mkU32( 0)), getIReg(4,R_EDI) );
12778//..
12779//.. DIP("pusha%c\n", nameISize(sz));
12780//.. break;
12781//..
12782//..
12783//.. //-- case 0x0E: /* PUSH %CS */
12784//.. //-- dis_push_segreg( cb, R_CS, sz ); break;
12785//.. //-- case 0x1E: /* PUSH %DS */
12786//.. //-- dis_push_segreg( cb, R_DS, sz ); break;
12787//.. //-- case 0x06: /* PUSH %ES */
12788//.. //-- dis_push_segreg( cb, R_ES, sz ); break;
12789//.. //-- case 0x16: /* PUSH %SS */
12790//.. //-- dis_push_segreg( cb, R_SS, sz ); break;
12791//..
12792//.. /* ------------------------ SCAS et al ----------------- */
12793//..
12794//.. case 0xA4: /* MOVS, no REP prefix */
12795//.. case 0xA5:
12796//.. dis_string_op( dis_MOVS, ( opc == 0xA4 ? 1 : sz ), "movs", sorb );
12797//.. break;
12798//..
12799//.. case 0xA6: /* CMPSb, no REP prefix */
12800//.. //-- case 0xA7:
12801//.. dis_string_op( dis_CMPS, ( opc == 0xA6 ? 1 : sz ), "cmps", sorb );
12802//.. break;
12803//.. //--
sewardjd20c8852005-01-20 20:04:07 +000012804//.. //--
12805//.. //-- case 0xAC: /* LODS, no REP prefix */
12806//.. //-- case 0xAD:
12807//.. //-- dis_string_op( cb, dis_LODS, ( opc == 0xAC ? 1 : sz ), "lods", sorb );
12808//.. //-- break;
12809//..
12810//.. case 0xAE: /* SCAS, no REP prefix */
12811//.. case 0xAF:
12812//.. dis_string_op( dis_SCAS, ( opc == 0xAE ? 1 : sz ), "scas", sorb );
12813//.. break;
sewardjd0a12df2005-02-10 02:07:43 +000012814
12815
12816 case 0xFC: /* CLD */
sewardj5b470602005-02-27 13:10:48 +000012817 if (haveF2orF3(pfx)) goto decode_failure;
sewardjd0a12df2005-02-10 02:07:43 +000012818 stmt( IRStmt_Put( OFFB_DFLAG, mkU64(1)) );
12819 DIP("cld\n");
12820 break;
12821
sewardj909c06d2005-02-19 22:47:41 +000012822 case 0xFD: /* STD */
sewardj5b470602005-02-27 13:10:48 +000012823 if (haveF2orF3(pfx)) goto decode_failure;
sewardj909c06d2005-02-19 22:47:41 +000012824 stmt( IRStmt_Put( OFFB_DFLAG, mkU64(-1ULL)) );
12825 DIP("std\n");
12826 break;
12827
sewardj31804462006-05-12 20:15:33 +000012828 case 0xF8: /* CLC */
12829 case 0xF9: /* STC */
12830 case 0xF5: /* CMC */
12831 t0 = newTemp(Ity_I64);
12832 t1 = newTemp(Ity_I64);
12833 assign( t0, mk_amd64g_calculate_rflags_all() );
12834 switch (opc) {
12835 case 0xF8:
12836 assign( t1, binop(Iop_And64, mkexpr(t0),
12837 mkU64(~AMD64G_CC_MASK_C)));
12838 DIP("clc\n");
12839 break;
12840 case 0xF9:
12841 assign( t1, binop(Iop_Or64, mkexpr(t0),
12842 mkU64(AMD64G_CC_MASK_C)));
12843 DIP("stc\n");
12844 break;
12845 case 0xF5:
12846 assign( t1, binop(Iop_Xor64, mkexpr(t0),
12847 mkU64(AMD64G_CC_MASK_C)));
12848 DIP("cmc\n");
12849 break;
12850 default:
12851 vpanic("disInstr(x64)(clc/stc/cmc)");
12852 }
12853 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(AMD64G_CC_OP_COPY) ));
12854 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
12855 stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(t1) ));
12856 /* Set NDEP even though it isn't used. This makes redundant-PUT
12857 elimination of previous stores to this field work better. */
12858 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU64(0) ));
12859 break;
12860
sewardjd20c8852005-01-20 20:04:07 +000012861//.. /* REPNE prefix insn */
12862//.. case 0xF2: {
12863//.. Addr32 eip_orig = guest_eip_bbstart + delta - 1;
12864//.. vassert(sorb == 0);
sewardj8c332e22005-01-28 01:36:56 +000012865//.. abyte = getUChar(delta); delta++;
sewardjd20c8852005-01-20 20:04:07 +000012866//..
sewardj8c332e22005-01-28 01:36:56 +000012867//.. if (abyte == 0x66) { sz = 2; abyte = getUChar(delta); delta++; }
sewardjd20c8852005-01-20 20:04:07 +000012868//.. whatNext = Dis_StopHere;
12869//..
12870//.. switch (abyte) {
12871//.. /* According to the Intel manual, "repne movs" should never occur, but
12872//.. * in practice it has happened, so allow for it here... */
12873//.. case 0xA4: sz = 1; /* REPNE MOVS<sz> */
12874//.. goto decode_failure;
12875//.. //-- case 0xA5:
12876//.. // dis_REP_op ( CondNZ, dis_MOVS, sz, eip_orig,
12877//.. // guest_eip_bbstart+delta, "repne movs" );
12878//.. // break;
12879//.. //--
12880//.. //-- case 0xA6: sz = 1; /* REPNE CMPS<sz> */
12881//.. //-- case 0xA7:
12882//.. //-- dis_REP_op ( cb, CondNZ, dis_CMPS, sz, eip_orig, eip, "repne cmps" );
12883//.. //-- break;
12884//.. //--
12885//.. case 0xAE: sz = 1; /* REPNE SCAS<sz> */
12886//.. case 0xAF:
12887//.. dis_REP_op ( X86CondNZ, dis_SCAS, sz, eip_orig,
12888//.. guest_eip_bbstart+delta, "repne scas" );
12889//.. break;
12890//..
12891//.. default:
12892//.. goto decode_failure;
12893//.. }
12894//.. break;
12895//.. }
sewardjd0a12df2005-02-10 02:07:43 +000012896
sewardj909c06d2005-02-19 22:47:41 +000012897 /* ------ AE: SCAS variants ------ */
12898 case 0xAE:
12899 case 0xAF:
12900 /* F2 AE/AF: repne scasb/repne scas{w,l,q} */
sewardj42561ef2005-11-04 14:18:31 +000012901 if (haveASO(pfx))
12902 goto decode_failure;
sewardj85520e42005-02-19 15:22:38 +000012903 if (haveF2(pfx) && !haveF3(pfx)) {
12904 if (opc == 0xAE)
12905 sz = 1;
12906 dis_REP_op ( AMD64CondNZ, dis_SCAS, sz,
sewardj9e6491a2005-07-02 19:24:10 +000012907 guest_RIP_curr_instr,
12908 guest_RIP_bbstart+delta, "repne scas", pfx );
12909 dres.whatNext = Dis_StopHere;
sewardj85520e42005-02-19 15:22:38 +000012910 break;
12911 }
sewardj909c06d2005-02-19 22:47:41 +000012912 /* AE/AF: scasb/scas{w,l,q} */
12913 if (!haveF2(pfx) && !haveF3(pfx)) {
12914 if (opc == 0xAE)
12915 sz = 1;
12916 dis_string_op( dis_SCAS, sz, "scas", pfx );
12917 break;
12918 }
sewardj85520e42005-02-19 15:22:38 +000012919 goto decode_failure;
sewardjd0a12df2005-02-10 02:07:43 +000012920
sewardj909c06d2005-02-19 22:47:41 +000012921 /* ------ A6, A7: CMPS variants ------ */
12922 case 0xA6:
12923 case 0xA7:
12924 /* F3 A6/A7: repe cmps/rep cmps{w,l,q} */
sewardj42561ef2005-11-04 14:18:31 +000012925 if (haveASO(pfx))
12926 goto decode_failure;
sewardjd0a12df2005-02-10 02:07:43 +000012927 if (haveF3(pfx) && !haveF2(pfx)) {
12928 if (opc == 0xA6)
12929 sz = 1;
12930 dis_REP_op ( AMD64CondZ, dis_CMPS, sz,
sewardj9e6491a2005-07-02 19:24:10 +000012931 guest_RIP_curr_instr,
12932 guest_RIP_bbstart+delta, "repe cmps", pfx );
12933 dres.whatNext = Dis_StopHere;
sewardja6b93d12005-02-17 09:28:28 +000012934 break;
12935 }
12936 goto decode_failure;
12937
sewardj909c06d2005-02-19 22:47:41 +000012938 /* ------ AA, AB: STOS variants ------ */
12939 case 0xAA:
12940 case 0xAB:
12941 /* F3 AA/AB: rep stosb/rep stos{w,l,q} */
sewardj42561ef2005-11-04 14:18:31 +000012942 if (haveASO(pfx))
12943 goto decode_failure;
sewardja6b93d12005-02-17 09:28:28 +000012944 if (haveF3(pfx) && !haveF2(pfx)) {
sewardj909c06d2005-02-19 22:47:41 +000012945 if (opc == 0xAA)
12946 sz = 1;
sewardja6b93d12005-02-17 09:28:28 +000012947 dis_REP_op ( AMD64CondAlways, dis_STOS, sz,
sewardj9e6491a2005-07-02 19:24:10 +000012948 guest_RIP_curr_instr,
12949 guest_RIP_bbstart+delta, "rep stos", pfx );
12950 dres.whatNext = Dis_StopHere;
sewardj909c06d2005-02-19 22:47:41 +000012951 break;
12952 }
12953 /* AA/AB: stosb/stos{w,l,q} */
12954 if (!haveF3(pfx) && !haveF2(pfx)) {
12955 if (opc == 0xAA)
12956 sz = 1;
12957 dis_string_op( dis_STOS, sz, "stos", pfx );
sewardjd0a12df2005-02-10 02:07:43 +000012958 break;
12959 }
12960 goto decode_failure;
12961
sewardj909c06d2005-02-19 22:47:41 +000012962 /* ------ A4, A5: MOVS variants ------ */
12963 case 0xA4:
12964 case 0xA5:
12965 /* F3 A4: rep movsb */
sewardj42561ef2005-11-04 14:18:31 +000012966 if (haveASO(pfx))
12967 goto decode_failure;
sewardj909c06d2005-02-19 22:47:41 +000012968 if (haveF3(pfx) && !haveF2(pfx)) {
12969 if (opc == 0xA4)
12970 sz = 1;
12971 dis_REP_op ( AMD64CondAlways, dis_MOVS, sz,
sewardj9e6491a2005-07-02 19:24:10 +000012972 guest_RIP_curr_instr,
12973 guest_RIP_bbstart+delta, "rep movs", pfx );
12974 dres.whatNext = Dis_StopHere;
sewardj909c06d2005-02-19 22:47:41 +000012975 break;
12976 }
12977 /* A4: movsb */
12978 if (!haveF3(pfx) && !haveF2(pfx)) {
12979 if (opc == 0xA4)
12980 sz = 1;
12981 dis_string_op( dis_MOVS, sz, "movs", pfx );
12982 break;
12983 }
12984 goto decode_failure;
12985
sewardj7de0d3c2005-02-13 02:26:41 +000012986
12987 /* ------------------------ XCHG ----------------------- */
12988
sewardj1bf95982005-05-18 12:04:04 +000012989 case 0x86: /* XCHG Gb,Eb */
12990 sz = 1;
12991 /* Fall through ... */
sewardj7de0d3c2005-02-13 02:26:41 +000012992 case 0x87: /* XCHG Gv,Ev */
sewardj5b470602005-02-27 13:10:48 +000012993 if (haveF2orF3(pfx)) goto decode_failure;
sewardj7de0d3c2005-02-13 02:26:41 +000012994 modrm = getUChar(delta);
12995 ty = szToITy(sz);
12996 t1 = newTemp(ty); t2 = newTemp(ty);
12997 if (epartIsReg(modrm)) {
sewardj5b470602005-02-27 13:10:48 +000012998 assign(t1, getIRegE(sz, pfx, modrm));
12999 assign(t2, getIRegG(sz, pfx, modrm));
13000 putIRegG(sz, pfx, modrm, mkexpr(t1));
13001 putIRegE(sz, pfx, modrm, mkexpr(t2));
sewardj7de0d3c2005-02-13 02:26:41 +000013002 delta++;
13003 DIP("xchg%c %s, %s\n",
sewardj5b470602005-02-27 13:10:48 +000013004 nameISize(sz), nameIRegG(sz, pfx, modrm),
13005 nameIRegE(sz, pfx, modrm));
sewardj7de0d3c2005-02-13 02:26:41 +000013006 } else {
sewardj7de0d3c2005-02-13 02:26:41 +000013007 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
sewardj5b470602005-02-27 13:10:48 +000013008 assign( t1, loadLE(ty, mkexpr(addr)) );
13009 assign( t2, getIRegG(sz, pfx, modrm) );
sewardj7de0d3c2005-02-13 02:26:41 +000013010 storeLE( mkexpr(addr), mkexpr(t2) );
sewardj5b470602005-02-27 13:10:48 +000013011 putIRegG( sz, pfx, modrm, mkexpr(t1) );
sewardj7de0d3c2005-02-13 02:26:41 +000013012 delta += alen;
13013 DIP("xchg%c %s, %s\n", nameISize(sz),
sewardj5b470602005-02-27 13:10:48 +000013014 nameIRegG(sz, pfx, modrm), dis_buf);
sewardj7de0d3c2005-02-13 02:26:41 +000013015 }
13016 break;
sewardj118b23e2005-01-29 02:14:44 +000013017
13018 case 0x90: /* XCHG eAX,eAX */
sewardjc8b26352005-07-20 09:23:13 +000013019 /* detect and handle F3 90 (rep nop) specially */
13020 if (!have66(pfx) && !haveF2(pfx) && haveF3(pfx)) {
13021 DIP("rep nop (P4 pause)\n");
13022 /* "observe" the hint. The Vex client needs to be careful not
13023 to cause very long delays as a result, though. */
13024 jmp_lit(Ijk_Yield, guest_RIP_bbstart+delta);
13025 dres.whatNext = Dis_StopHere;
13026 break;
13027 }
sewardj2d4fcd52005-05-18 11:47:47 +000013028 /* detect and handle NOPs specially */
13029 if (/* F2/F3 probably change meaning completely */
13030 !haveF2orF3(pfx)
13031 /* If REX.B is 1, we're not exchanging rAX with itself */
13032 && getRexB(pfx)==0 ) {
13033 DIP("nop\n");
13034 break;
13035 }
13036 /* else fall through to normal case. */
sewardja6b93d12005-02-17 09:28:28 +000013037 case 0x91: /* XCHG rAX,rCX */
13038 case 0x92: /* XCHG rAX,rDX */
13039 case 0x93: /* XCHG rAX,rBX */
13040 case 0x94: /* XCHG rAX,rSP */
13041 case 0x95: /* XCHG rAX,rBP */
13042 case 0x96: /* XCHG rAX,rSI */
13043 case 0x97: /* XCHG rAX,rDI */
sewardj2d4fcd52005-05-18 11:47:47 +000013044
13045 /* guard against mutancy */
sewardja6b93d12005-02-17 09:28:28 +000013046 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2d4fcd52005-05-18 11:47:47 +000013047
13048 /* sz == 2 could legitimately happen, but we don't handle it yet */
13049 if (sz == 2) goto decode_failure; /* awaiting test case */
13050
sewardja6b93d12005-02-17 09:28:28 +000013051 codegen_xchg_rAX_Reg ( pfx, sz, opc - 0x90 );
13052 break;
13053
sewardjd20c8852005-01-20 20:04:07 +000013054//.. //-- /* ------------------------ XLAT ----------------------- */
13055//.. //--
13056//.. //-- case 0xD7: /* XLAT */
13057//.. //-- t1 = newTemp(cb); t2 = newTemp(cb);
13058//.. //-- uInstr2(cb, GET, sz, ArchReg, R_EBX, TempReg, t1); /* get eBX */
sewardj42561ef2005-11-04 14:18:31 +000013059//.. //-- handleAddrOverrides( cb, sorb, t1 ); /* make t1 DS:eBX */
sewardjd20c8852005-01-20 20:04:07 +000013060//.. //-- uInstr2(cb, GET, 1, ArchReg, R_AL, TempReg, t2); /* get AL */
13061//.. //-- /* Widen %AL to 32 bits, so it's all defined when we add it. */
13062//.. //-- uInstr1(cb, WIDEN, 4, TempReg, t2);
13063//.. //-- uWiden(cb, 1, False);
13064//.. //-- uInstr2(cb, ADD, sz, TempReg, t2, TempReg, t1); /* add AL to eBX */
13065//.. //-- uInstr2(cb, LOAD, 1, TempReg, t1, TempReg, t2); /* get byte at t1 into t2 */
13066//.. //-- uInstr2(cb, PUT, 1, TempReg, t2, ArchReg, R_AL); /* put byte into AL */
13067//.. //--
13068//.. //-- DIP("xlat%c [ebx]\n", nameISize(sz));
13069//.. //-- break;
13070//.. //--
13071//.. //-- /* ------------------------ IN / OUT ----------------------- */
13072//.. //--
13073//.. //-- case 0xE4: /* IN ib, %al */
13074//.. //-- case 0xE5: /* IN ib, %{e}ax */
13075//.. //-- case 0xEC: /* IN (%dx),%al */
13076//.. //-- case 0xED: /* IN (%dx),%{e}ax */
13077//.. //-- t1 = newTemp(cb);
13078//.. //-- t2 = newTemp(cb);
13079//.. //-- t3 = newTemp(cb);
13080//.. //--
13081//.. //-- uInstr0(cb, CALLM_S, 0);
13082//.. //-- /* operand size? */
13083//.. //-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t1);
13084//.. //-- uLiteral(cb, ( opc == 0xE4 || opc == 0xEC ) ? 1 : sz);
13085//.. //-- uInstr1(cb, PUSH, 4, TempReg, t1);
13086//.. //-- /* port number ? */
13087//.. //-- if ( opc == 0xE4 || opc == 0xE5 ) {
13088//.. //-- abyte = getUChar(eip); eip++;
13089//.. //-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
13090//.. //-- uLiteral(cb, abyte);
13091//.. //-- }
13092//.. //-- else
13093//.. //-- uInstr2(cb, GET, 4, ArchReg, R_EDX, TempReg, t2);
13094//.. //--
13095//.. //-- uInstr1(cb, PUSH, 4, TempReg, t2);
13096//.. //-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_IN));
13097//.. //-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
13098//.. //-- uInstr1(cb, POP, 4, TempReg, t2);
13099//.. //-- uInstr1(cb, CLEAR, 0, Lit16, 4);
13100//.. //-- uInstr0(cb, CALLM_E, 0);
13101//.. //-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_EAX);
13102//.. //-- if ( opc == 0xE4 || opc == 0xE5 ) {
13103//.. //-- DIP("in 0x%x, %%eax/%%ax/%%al\n", getUChar(eip-1) );
13104//.. //-- } else {
13105//.. //-- DIP("in (%%dx), %%eax/%%ax/%%al\n");
13106//.. //-- }
13107//.. //-- break;
13108//.. //-- case 0xE6: /* OUT %al,ib */
13109//.. //-- case 0xE7: /* OUT %{e}ax,ib */
13110//.. //-- case 0xEE: /* OUT %al,(%dx) */
13111//.. //-- case 0xEF: /* OUT %{e}ax,(%dx) */
13112//.. //-- t1 = newTemp(cb);
13113//.. //-- t2 = newTemp(cb);
13114//.. //-- t3 = newTemp(cb);
13115//.. //--
13116//.. //-- uInstr0(cb, CALLM_S, 0);
13117//.. //-- /* operand size? */
13118//.. //-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t1);
13119//.. //-- uLiteral(cb, ( opc == 0xE6 || opc == 0xEE ) ? 1 : sz);
13120//.. //-- uInstr1(cb, PUSH, 4, TempReg, t1);
13121//.. //-- /* port number ? */
13122//.. //-- if ( opc == 0xE6 || opc == 0xE7 ) {
13123//.. //-- abyte = getUChar(eip); eip++;
13124//.. //-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
13125//.. //-- uLiteral(cb, abyte);
13126//.. //-- }
13127//.. //-- else
13128//.. //-- uInstr2(cb, GET, 4, ArchReg, R_EDX, TempReg, t2);
13129//.. //-- uInstr1(cb, PUSH, 4, TempReg, t2);
13130//.. //-- uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, t3);
13131//.. //-- uInstr1(cb, PUSH, 4, TempReg, t3);
13132//.. //-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_OUT));
13133//.. //-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
13134//.. //-- uInstr1(cb, CLEAR, 0, Lit16, 12);
13135//.. //-- uInstr0(cb, CALLM_E, 0);
13136//.. //-- if ( opc == 0xE4 || opc == 0xE5 ) {
13137//.. //-- DIP("out %%eax/%%ax/%%al, 0x%x\n", getUChar(eip-1) );
13138//.. //-- } else {
13139//.. //-- DIP("out %%eax/%%ax/%%al, (%%dx)\n");
13140//.. //-- }
13141//.. //-- break;
sewardj3ca55a12005-01-27 16:06:23 +000013142
13143 /* ------------------------ (Grp1 extensions) ---------- */
13144
13145 case 0x80: /* Grp1 Ib,Eb */
sewardj5b470602005-02-27 13:10:48 +000013146 if (haveF2orF3(pfx)) goto decode_failure;
sewardj8c332e22005-01-28 01:36:56 +000013147 modrm = getUChar(delta);
sewardj3ca55a12005-01-27 16:06:23 +000013148 am_sz = lengthAMode(pfx,delta);
13149 sz = 1;
13150 d_sz = 1;
13151 d64 = getSDisp8(delta + am_sz);
13152 delta = dis_Grp1 ( pfx, delta, modrm, am_sz, d_sz, sz, d64 );
13153 break;
13154
13155 case 0x81: /* Grp1 Iv,Ev */
13156 if (haveF2orF3(pfx)) goto decode_failure;
sewardj8c332e22005-01-28 01:36:56 +000013157 modrm = getUChar(delta);
sewardj3ca55a12005-01-27 16:06:23 +000013158 am_sz = lengthAMode(pfx,delta);
13159 d_sz = imin(sz,4);
13160 d64 = getSDisp(d_sz, delta + am_sz);
13161 delta = dis_Grp1 ( pfx, delta, modrm, am_sz, d_sz, sz, d64 );
13162 break;
13163
13164 case 0x83: /* Grp1 Ib,Ev */
13165 if (haveF2orF3(pfx)) goto decode_failure;
sewardj8c332e22005-01-28 01:36:56 +000013166 modrm = getUChar(delta);
sewardj3ca55a12005-01-27 16:06:23 +000013167 am_sz = lengthAMode(pfx,delta);
13168 d_sz = 1;
13169 d64 = getSDisp8(delta + am_sz);
13170 delta = dis_Grp1 ( pfx, delta, modrm, am_sz, d_sz, sz, d64 );
13171 break;
13172
sewardj118b23e2005-01-29 02:14:44 +000013173 /* ------------------------ (Grp2 extensions) ---------- */
sewardj03b07cc2005-01-31 18:09:43 +000013174
sewardj118b23e2005-01-29 02:14:44 +000013175 case 0xC0: /* Grp2 Ib,Eb */
sewardj5b470602005-02-27 13:10:48 +000013176 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000013177 modrm = getUChar(delta);
13178 am_sz = lengthAMode(pfx,delta);
13179 d_sz = 1;
13180 d64 = getUChar(delta + am_sz);
13181 sz = 1;
13182 delta = dis_Grp2 ( pfx, delta, modrm, am_sz, d_sz, sz,
13183 mkU8(d64 & 0xFF), NULL );
13184 break;
sewardj03b07cc2005-01-31 18:09:43 +000013185
sewardj118b23e2005-01-29 02:14:44 +000013186 case 0xC1: /* Grp2 Ib,Ev */
sewardj5b470602005-02-27 13:10:48 +000013187 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000013188 modrm = getUChar(delta);
13189 am_sz = lengthAMode(pfx,delta);
13190 d_sz = 1;
13191 d64 = getUChar(delta + am_sz);
13192 delta = dis_Grp2 ( pfx, delta, modrm, am_sz, d_sz, sz,
13193 mkU8(d64 & 0xFF), NULL );
13194 break;
13195
sewardj03b07cc2005-01-31 18:09:43 +000013196 case 0xD0: /* Grp2 1,Eb */
sewardj5b470602005-02-27 13:10:48 +000013197 if (haveF2orF3(pfx)) goto decode_failure;
sewardj03b07cc2005-01-31 18:09:43 +000013198 modrm = getUChar(delta);
13199 am_sz = lengthAMode(pfx,delta);
13200 d_sz = 0;
13201 d64 = 1;
13202 sz = 1;
13203 delta = dis_Grp2 ( pfx, delta, modrm, am_sz, d_sz, sz,
13204 mkU8(d64), NULL );
13205 break;
sewardj118b23e2005-01-29 02:14:44 +000013206
13207 case 0xD1: /* Grp2 1,Ev */
sewardj5b470602005-02-27 13:10:48 +000013208 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000013209 modrm = getUChar(delta);
13210 am_sz = lengthAMode(pfx,delta);
13211 d_sz = 0;
13212 d64 = 1;
13213 delta = dis_Grp2 ( pfx, delta, modrm, am_sz, d_sz, sz,
13214 mkU8(d64), NULL );
13215 break;
13216
sewardj85520e42005-02-19 15:22:38 +000013217 case 0xD2: /* Grp2 CL,Eb */
sewardj5b470602005-02-27 13:10:48 +000013218 if (haveF2orF3(pfx)) goto decode_failure;
sewardj85520e42005-02-19 15:22:38 +000013219 modrm = getUChar(delta);
13220 am_sz = lengthAMode(pfx,delta);
13221 d_sz = 0;
13222 sz = 1;
13223 delta = dis_Grp2 ( pfx, delta, modrm, am_sz, d_sz, sz,
sewardj5b470602005-02-27 13:10:48 +000013224 getIRegCL(), "%cl" );
sewardj85520e42005-02-19 15:22:38 +000013225 break;
sewardj118b23e2005-01-29 02:14:44 +000013226
13227 case 0xD3: /* Grp2 CL,Ev */
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 = 0;
13232 delta = dis_Grp2 ( pfx, delta, modrm, am_sz, d_sz, sz,
sewardj5b470602005-02-27 13:10:48 +000013233 getIRegCL(), "%cl" );
sewardj118b23e2005-01-29 02:14:44 +000013234 break;
sewardj32b2bbe2005-01-28 00:50:10 +000013235
13236 /* ------------------------ (Grp3 extensions) ---------- */
13237
sewardj118b23e2005-01-29 02:14:44 +000013238 case 0xF6: /* Grp3 Eb */
sewardj5b470602005-02-27 13:10:48 +000013239 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000013240 delta = dis_Grp3 ( pfx, 1, delta );
13241 break;
sewardj32b2bbe2005-01-28 00:50:10 +000013242 case 0xF7: /* Grp3 Ev */
sewardj5b470602005-02-27 13:10:48 +000013243 if (haveF2orF3(pfx)) goto decode_failure;
sewardj32b2bbe2005-01-28 00:50:10 +000013244 delta = dis_Grp3 ( pfx, sz, delta );
13245 break;
13246
sewardj03b07cc2005-01-31 18:09:43 +000013247 /* ------------------------ (Grp4 extensions) ---------- */
13248
13249 case 0xFE: /* Grp4 Eb */
sewardj5b470602005-02-27 13:10:48 +000013250 if (haveF2orF3(pfx)) goto decode_failure;
sewardj03b07cc2005-01-31 18:09:43 +000013251 delta = dis_Grp4 ( pfx, delta );
13252 break;
sewardj354e5c62005-01-27 20:12:52 +000013253
13254 /* ------------------------ (Grp5 extensions) ---------- */
13255
13256 case 0xFF: /* Grp5 Ev */
sewardj5b470602005-02-27 13:10:48 +000013257 if (haveF2orF3(pfx)) goto decode_failure;
sewardj9e6491a2005-07-02 19:24:10 +000013258 delta = dis_Grp5 ( pfx, sz, delta, &dres );
sewardj354e5c62005-01-27 20:12:52 +000013259 break;
sewardj3ca55a12005-01-27 16:06:23 +000013260
13261 /* ------------------------ Escapes to 2-byte opcodes -- */
13262
13263 case 0x0F: {
sewardj8c332e22005-01-28 01:36:56 +000013264 opc = getUChar(delta); delta++;
sewardj3ca55a12005-01-27 16:06:23 +000013265 switch (opc) {
13266
sewardj1d511802005-03-27 17:59:45 +000013267 /* =-=-=-=-=-=-=-=-=- Grp8 =-=-=-=-=-=-=-=-=-=-=-= */
13268
13269 case 0xBA: { /* Grp8 Ib,Ev */
13270 Bool decode_OK = False;
13271 if (haveF2orF3(pfx)) goto decode_failure;
13272 modrm = getUChar(delta);
13273 am_sz = lengthAMode(pfx,delta);
13274 d64 = getSDisp8(delta + am_sz);
13275 delta = dis_Grp8_Imm ( pfx, delta, modrm, am_sz, sz, d64,
13276 &decode_OK );
13277 if (!decode_OK)
13278 goto decode_failure;
13279 break;
13280 }
13281
sewardjf53b7352005-04-06 20:01:56 +000013282 /* =-=-=-=-=-=-=-=-=- BSF/BSR -=-=-=-=-=-=-=-=-=-= */
13283
13284 case 0xBC: /* BSF Gv,Ev */
13285 if (haveF2orF3(pfx)) goto decode_failure;
13286 delta = dis_bs_E_G ( pfx, sz, delta, True );
13287 break;
sewardj537cab02005-04-07 02:03:52 +000013288 case 0xBD: /* BSR Gv,Ev */
13289 if (haveF2orF3(pfx)) goto decode_failure;
13290 delta = dis_bs_E_G ( pfx, sz, delta, False );
13291 break;
sewardj82c9f2f2005-03-02 16:05:13 +000013292
13293 /* =-=-=-=-=-=-=-=-=- BSWAP -=-=-=-=-=-=-=-=-=-=-= */
13294
13295 case 0xC8: /* BSWAP %eax */
13296 case 0xC9:
13297 case 0xCA:
13298 case 0xCB:
13299 case 0xCC:
13300 case 0xCD:
13301 case 0xCE:
13302 case 0xCF: /* BSWAP %edi */
13303 if (haveF2orF3(pfx)) goto decode_failure;
13304 /* According to the AMD64 docs, this insn can have size 4 or
13305 8. */
13306 if (sz == 4) {
13307 t1 = newTemp(Ity_I32);
13308 t2 = newTemp(Ity_I32);
13309 assign( t1, getIRegRexB(4, pfx, opc-0xC8) );
13310 assign( t2,
13311 binop(Iop_Or32,
13312 binop(Iop_Shl32, mkexpr(t1), mkU8(24)),
13313 binop(Iop_Or32,
13314 binop(Iop_And32, binop(Iop_Shl32, mkexpr(t1), mkU8(8)),
13315 mkU32(0x00FF0000)),
13316 binop(Iop_Or32,
13317 binop(Iop_And32, binop(Iop_Shr32, mkexpr(t1), mkU8(8)),
13318 mkU32(0x0000FF00)),
13319 binop(Iop_And32, binop(Iop_Shr32, mkexpr(t1), mkU8(24)),
13320 mkU32(0x000000FF) )
13321 )))
13322 );
13323 putIRegRexB(4, pfx, opc-0xC8, mkexpr(t2));
13324 DIP("bswapl %s\n", nameIRegRexB(4, pfx, opc-0xC8));
13325 break;
sewardj98e9f342005-07-23 12:07:37 +000013326 }
13327 else if (sz == 8) {
13328 t1 = newTemp(Ity_I64);
13329 t2 = newTemp(Ity_I64);
13330 assign( t1, getIRegRexB(8, pfx, opc-0xC8) );
13331
13332# define LANE(_nn) \
13333 binop( Iop_Shl64, \
13334 binop( Iop_And64, \
13335 binop(Iop_Shr64, mkexpr(t1), \
13336 mkU8(8 * (7 - (_nn)))), \
13337 mkU64(0xFF)), \
13338 mkU8(8 * (_nn)))
13339
13340 assign(
13341 t2,
13342 binop(Iop_Or64,
13343 binop(Iop_Or64,
13344 binop(Iop_Or64,LANE(0),LANE(1)),
13345 binop(Iop_Or64,LANE(2),LANE(3))
13346 ),
13347 binop(Iop_Or64,
13348 binop(Iop_Or64,LANE(4),LANE(5)),
13349 binop(Iop_Or64,LANE(6),LANE(7))
13350 )
13351 )
13352 );
13353
13354# undef LANE
13355
13356 putIRegRexB(8, pfx, opc-0xC8, mkexpr(t2));
13357 DIP("bswapq %s\n", nameIRegRexB(8, pfx, opc-0xC8));
13358 break;
sewardj82c9f2f2005-03-02 16:05:13 +000013359 } else {
13360 goto decode_failure;
13361 }
13362
sewardj9ed16802005-08-24 10:46:19 +000013363 /* =-=-=-=-=-=-=-=-=- BT/BTS/BTR/BTC =-=-=-=-=-=-= */
13364
sewardja7690fb2005-10-05 17:19:11 +000013365 /* All of these are possible at sizes 2, 4 and 8, but until a
13366 size 2 test case shows up, only handle sizes 4 and 8. */
sewardj9ed16802005-08-24 10:46:19 +000013367
13368 case 0xA3: /* BT Gv,Ev */
13369 if (haveF2orF3(pfx)) goto decode_failure;
sewardj25d23862006-05-12 17:47:21 +000013370 if (sz != 8 && sz != 4 && sz != 2) goto decode_failure;
sewardj9ed16802005-08-24 10:46:19 +000013371 delta = dis_bt_G_E ( pfx, sz, delta, BtOpNone );
13372 break;
13373 case 0xB3: /* BTR Gv,Ev */
13374 if (haveF2orF3(pfx)) goto decode_failure;
sewardj25d23862006-05-12 17:47:21 +000013375 if (sz != 8 && sz != 4 && sz != 2) goto decode_failure;
sewardj9ed16802005-08-24 10:46:19 +000013376 delta = dis_bt_G_E ( pfx, sz, delta, BtOpReset );
13377 break;
13378 case 0xAB: /* BTS Gv,Ev */
13379 if (haveF2orF3(pfx)) goto decode_failure;
sewardj25d23862006-05-12 17:47:21 +000013380 if (sz != 8 && sz != 4 && sz != 2) goto decode_failure;
sewardj9ed16802005-08-24 10:46:19 +000013381 delta = dis_bt_G_E ( pfx, sz, delta, BtOpSet );
13382 break;
13383 case 0xBB: /* BTC Gv,Ev */
13384 if (haveF2orF3(pfx)) goto decode_failure;
sewardj25d23862006-05-12 17:47:21 +000013385 if (sz != 8 && sz != 4 && sz != 2) goto decode_failure;
sewardj9ed16802005-08-24 10:46:19 +000013386 delta = dis_bt_G_E ( pfx, sz, delta, BtOpComp );
13387 break;
sewardj3ca55a12005-01-27 16:06:23 +000013388
13389 /* =-=-=-=-=-=-=-=-=- CMOV =-=-=-=-=-=-=-=-=-=-=-= */
13390
13391 case 0x40:
13392 case 0x41:
13393 case 0x42: /* CMOVBb/CMOVNAEb (cmov below) */
13394 case 0x43: /* CMOVNBb/CMOVAEb (cmov not below) */
13395 case 0x44: /* CMOVZb/CMOVEb (cmov zero) */
13396 case 0x45: /* CMOVNZb/CMOVNEb (cmov not zero) */
13397 case 0x46: /* CMOVBEb/CMOVNAb (cmov below or equal) */
13398 case 0x47: /* CMOVNBEb/CMOVAb (cmov not below or equal) */
13399 case 0x48: /* CMOVSb (cmov negative) */
13400 case 0x49: /* CMOVSb (cmov not negative) */
13401 case 0x4A: /* CMOVP (cmov parity even) */
13402 case 0x4B: /* CMOVNP (cmov parity odd) */
13403 case 0x4C: /* CMOVLb/CMOVNGEb (cmov less) */
13404 case 0x4D: /* CMOVGEb/CMOVNLb (cmov greater or equal) */
13405 case 0x4E: /* CMOVLEb/CMOVNGb (cmov less or equal) */
13406 case 0x4F: /* CMOVGb/CMOVNLEb (cmov greater) */
sewardj5b470602005-02-27 13:10:48 +000013407 if (haveF2orF3(pfx)) goto decode_failure;
sewardj3ca55a12005-01-27 16:06:23 +000013408 delta = dis_cmov_E_G(pfx, sz, (AMD64Condcode)(opc - 0x40), delta);
13409 break;
13410
sewardja6b93d12005-02-17 09:28:28 +000013411 /* =-=-=-=-=-=-=-=-=- CMPXCHG -=-=-=-=-=-=-=-=-=-= */
13412
sewardjd20c8852005-01-20 20:04:07 +000013413//.. case 0xB0: /* CMPXCHG Gb,Eb */
13414//.. delta = dis_cmpxchg_G_E ( sorb, 1, delta );
13415//.. break;
sewardja6b93d12005-02-17 09:28:28 +000013416 case 0xB1: /* CMPXCHG Gv,Ev */
sewardj5b470602005-02-27 13:10:48 +000013417 if (haveF2orF3(pfx)) goto decode_failure;
sewardja6b93d12005-02-17 09:28:28 +000013418 delta = dis_cmpxchg_G_E ( pfx, sz, delta );
13419 break;
sewardjd20c8852005-01-20 20:04:07 +000013420//.. //-- case 0xC7: /* CMPXCHG8B Gv */
13421//.. //-- eip = dis_cmpxchg8b ( cb, sorb, eip );
13422//.. //-- break;
13423//.. //--
sewardjd0a12df2005-02-10 02:07:43 +000013424 /* =-=-=-=-=-=-=-=-=- CPUID -=-=-=-=-=-=-=-=-=-=-= */
13425
13426 case 0xA2: { /* CPUID */
13427 /* Uses dirty helper:
13428 void amd64g_dirtyhelper_CPUID ( VexGuestAMD64State* )
13429 declared to mod rax, wr rbx, rcx, rdx
13430 */
13431 IRDirty* d = NULL;
13432 HChar* fName = NULL;
13433 void* fAddr = NULL;
sewardj5b470602005-02-27 13:10:48 +000013434 if (haveF2orF3(pfx)) goto decode_failure;
sewardj5117ce12006-01-27 21:20:15 +000013435 if (archinfo->hwcaps == 0/*baseline, == SSE2*/) {
13436 fName = "amd64g_dirtyhelper_CPUID";
13437 fAddr = &amd64g_dirtyhelper_CPUID;
sewardjd0a12df2005-02-10 02:07:43 +000013438 }
sewardj5117ce12006-01-27 21:20:15 +000013439 else
13440 vpanic("disInstr(amd64)(cpuid)");
13441
sewardjd0a12df2005-02-10 02:07:43 +000013442 vassert(fName); vassert(fAddr);
13443 d = unsafeIRDirty_0_N ( 0/*regparms*/,
13444 fName, fAddr, mkIRExprVec_0() );
13445 /* declare guest state effects */
13446 d->needsBBP = True;
13447 d->nFxState = 4;
13448 d->fxState[0].fx = Ifx_Modify;
13449 d->fxState[0].offset = OFFB_RAX;
13450 d->fxState[0].size = 8;
13451 d->fxState[1].fx = Ifx_Write;
13452 d->fxState[1].offset = OFFB_RBX;
13453 d->fxState[1].size = 8;
13454 d->fxState[2].fx = Ifx_Write;
13455 d->fxState[2].offset = OFFB_RCX;
13456 d->fxState[2].size = 8;
13457 d->fxState[3].fx = Ifx_Write;
13458 d->fxState[3].offset = OFFB_RDX;
13459 d->fxState[3].size = 8;
13460 /* execute the dirty call, side-effecting guest state */
13461 stmt( IRStmt_Dirty(d) );
13462 /* CPUID is a serialising insn. So, just in case someone is
13463 using it as a memory fence ... */
13464 stmt( IRStmt_MFence() );
13465 DIP("cpuid\n");
13466 break;
13467 }
13468
sewardj5e525292005-01-28 15:13:10 +000013469 /* =-=-=-=-=-=-=-=-=- MOVZX, MOVSX =-=-=-=-=-=-=-= */
13470
13471 case 0xB6: /* MOVZXb Eb,Gv */
sewardj5b470602005-02-27 13:10:48 +000013472 if (haveF2orF3(pfx)) goto decode_failure;
sewardj5e525292005-01-28 15:13:10 +000013473 if (sz != 2 && sz != 4 && sz != 8)
13474 goto decode_failure;
13475 delta = dis_movx_E_G ( pfx, delta, 1, sz, False );
13476 break;
13477 case 0xB7: /* MOVZXw Ew,Gv */
sewardj5b470602005-02-27 13:10:48 +000013478 if (haveF2orF3(pfx)) goto decode_failure;
sewardj5e525292005-01-28 15:13:10 +000013479 if (sz != 4 && sz != 8)
13480 goto decode_failure;
13481 delta = dis_movx_E_G ( pfx, delta, 2, sz, False );
13482 break;
13483
sewardj03b07cc2005-01-31 18:09:43 +000013484 case 0xBE: /* MOVSXb Eb,Gv */
sewardj5b470602005-02-27 13:10:48 +000013485 if (haveF2orF3(pfx)) goto decode_failure;
sewardj82c9f2f2005-03-02 16:05:13 +000013486 if (sz != 2 && sz != 4 && sz != 8)
sewardj03b07cc2005-01-31 18:09:43 +000013487 goto decode_failure;
13488 delta = dis_movx_E_G ( pfx, delta, 1, sz, True );
13489 break;
13490 case 0xBF: /* MOVSXw Ew,Gv */
sewardj5b470602005-02-27 13:10:48 +000013491 if (haveF2orF3(pfx)) goto decode_failure;
sewardj03b07cc2005-01-31 18:09:43 +000013492 if (sz != 4 && sz != 8)
13493 goto decode_failure;
13494 delta = dis_movx_E_G ( pfx, delta, 2, sz, True );
13495 break;
13496
sewardjd20c8852005-01-20 20:04:07 +000013497//.. //-- /* =-=-=-=-=-=-=-=-=-=-= MOVNTI -=-=-=-=-=-=-=-=-= */
13498//.. //--
13499//.. //-- case 0xC3: /* MOVNTI Gv,Ev */
13500//.. //-- vg_assert(sz == 4);
13501//.. //-- modrm = getUChar(eip);
13502//.. //-- vg_assert(!epartIsReg(modrm));
13503//.. //-- t1 = newTemp(cb);
13504//.. //-- uInstr2(cb, GET, 4, ArchReg, gregOfRM(modrm), TempReg, t1);
13505//.. //-- pair = disAMode ( cb, sorb, eip, dis_buf );
13506//.. //-- t2 = LOW24(pair);
13507//.. //-- eip += HI8(pair);
13508//.. //-- uInstr2(cb, STORE, 4, TempReg, t1, TempReg, t2);
13509//.. //-- DIP("movnti %s,%s\n", nameIReg(4,gregOfRM(modrm)), dis_buf);
13510//.. //-- break;
sewardj32b2bbe2005-01-28 00:50:10 +000013511
13512 /* =-=-=-=-=-=-=-=-=- MUL/IMUL =-=-=-=-=-=-=-=-=-= */
13513
13514 case 0xAF: /* IMUL Ev, Gv */
sewardj5b470602005-02-27 13:10:48 +000013515 if (haveF2orF3(pfx)) goto decode_failure;
sewardj32b2bbe2005-01-28 00:50:10 +000013516 delta = dis_mul_E_G ( pfx, sz, delta );
13517 break;
13518
sewardj1389d4d2005-01-28 13:46:29 +000013519 /* =-=-=-=-=-=-=-=-=- Jcond d32 -=-=-=-=-=-=-=-=-= */
13520 case 0x80:
13521 case 0x81:
13522 case 0x82: /* JBb/JNAEb (jump below) */
13523 case 0x83: /* JNBb/JAEb (jump not below) */
13524 case 0x84: /* JZb/JEb (jump zero) */
13525 case 0x85: /* JNZb/JNEb (jump not zero) */
13526 case 0x86: /* JBEb/JNAb (jump below or equal) */
13527 case 0x87: /* JNBEb/JAb (jump not below or equal) */
13528 case 0x88: /* JSb (jump negative) */
13529 case 0x89: /* JSb (jump not negative) */
13530 case 0x8A: /* JP (jump parity even) */
13531 case 0x8B: /* JNP/JPO (jump parity odd) */
13532 case 0x8C: /* JLb/JNGEb (jump less) */
13533 case 0x8D: /* JGEb/JNLb (jump greater or equal) */
13534 case 0x8E: /* JLEb/JNGb (jump less or equal) */
13535 case 0x8F: /* JGb/JNLEb (jump greater) */
sewardj5b470602005-02-27 13:10:48 +000013536 if (haveF2orF3(pfx)) goto decode_failure;
sewardj9e6491a2005-07-02 19:24:10 +000013537 d64 = (guest_RIP_bbstart+delta+4) + getSDisp32(delta);
sewardj1389d4d2005-01-28 13:46:29 +000013538 delta += 4;
13539 jcc_01( (AMD64Condcode)(opc - 0x80),
sewardj9e6491a2005-07-02 19:24:10 +000013540 guest_RIP_bbstart+delta,
sewardj1389d4d2005-01-28 13:46:29 +000013541 d64 );
sewardj9e6491a2005-07-02 19:24:10 +000013542 dres.whatNext = Dis_StopHere;
sewardj1389d4d2005-01-28 13:46:29 +000013543 DIP("j%s-32 0x%llx\n", name_AMD64Condcode(opc - 0x80), d64);
13544 break;
13545
sewardjb04a47c2005-08-10 12:27:46 +000013546 /* =-=-=-=-=-=-=-=-=- PREFETCH =-=-=-=-=-=-=-=-=-= */
13547 case 0x0D: /* 0F 0D /0 -- prefetch mem8 */
13548 /* 0F 0D /1 -- prefetchw mem8 */
13549 if (have66orF2orF3(pfx)) goto decode_failure;
13550 modrm = getUChar(delta);
13551 if (epartIsReg(modrm)) goto decode_failure;
13552 if (gregLO3ofRM(modrm) != 0 && gregLO3ofRM(modrm) != 1)
13553 goto decode_failure;
13554
13555 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
13556 delta += alen;
13557
13558 switch (gregLO3ofRM(modrm)) {
13559 case 0: DIP("prefetch %s\n", dis_buf); break;
13560 case 1: DIP("prefetchw %s\n", dis_buf); break;
13561 default: vassert(0); /*NOTREACHED*/
13562 }
13563 break;
13564
sewardj31191072005-02-05 18:24:47 +000013565 /* =-=-=-=-=-=-=-=-=- RDTSC -=-=-=-=-=-=-=-=-=-=-= */
sewardjbc6af532005-08-23 23:16:51 +000013566 case 0x31: { /* RDTSC */
13567 IRTemp val = newTemp(Ity_I64);
13568 IRExpr** args = mkIRExprVec_0();
13569 IRDirty* d = unsafeIRDirty_1_N (
13570 val,
13571 0/*regparms*/,
13572 "amd64g_dirtyhelper_RDTSC",
13573 &amd64g_dirtyhelper_RDTSC,
13574 args
13575 );
13576 if (have66orF2orF3(pfx)) goto decode_failure;
13577 /* execute the dirty call, dumping the result in val. */
13578 stmt( IRStmt_Dirty(d) );
13579 putIRegRDX(4, unop(Iop_64HIto32, mkexpr(val)));
13580 putIRegRAX(4, unop(Iop_64to32, mkexpr(val)));
sewardj31191072005-02-05 18:24:47 +000013581 DIP("rdtsc\n");
13582 break;
sewardjbc6af532005-08-23 23:16:51 +000013583 }
sewardj31191072005-02-05 18:24:47 +000013584
sewardjd20c8852005-01-20 20:04:07 +000013585//.. /* =-=-=-=-=-=-=-=-=- PUSH/POP Sreg =-=-=-=-=-=-=-=-=-= */
13586//..
13587//.. case 0xA1: /* POP %FS */
13588//.. dis_pop_segreg( R_FS, sz ); break;
13589//.. case 0xA9: /* POP %GS */
13590//.. dis_pop_segreg( R_GS, sz ); break;
13591//..
13592//.. case 0xA0: /* PUSH %FS */
13593//.. dis_push_segreg( R_FS, sz ); break;
13594//.. case 0xA8: /* PUSH %GS */
13595//.. dis_push_segreg( R_GS, sz ); break;
sewardj118b23e2005-01-29 02:14:44 +000013596
13597 /* =-=-=-=-=-=-=-=-=- SETcc Eb =-=-=-=-=-=-=-=-=-= */
13598 case 0x90:
13599 case 0x91:
13600 case 0x92: /* set-Bb/set-NAEb (set if below) */
13601 case 0x93: /* set-NBb/set-AEb (set if not below) */
13602 case 0x94: /* set-Zb/set-Eb (set if zero) */
13603 case 0x95: /* set-NZb/set-NEb (set if not zero) */
13604 case 0x96: /* set-BEb/set-NAb (set if below or equal) */
13605 case 0x97: /* set-NBEb/set-Ab (set if not below or equal) */
13606 case 0x98: /* set-Sb (set if negative) */
13607 case 0x99: /* set-Sb (set if not negative) */
13608 case 0x9A: /* set-P (set if parity even) */
13609 case 0x9B: /* set-NP (set if parity odd) */
13610 case 0x9C: /* set-Lb/set-NGEb (set if less) */
13611 case 0x9D: /* set-GEb/set-NLb (set if greater or equal) */
13612 case 0x9E: /* set-LEb/set-NGb (set if less or equal) */
13613 case 0x9F: /* set-Gb/set-NLEb (set if greater) */
sewardj5b470602005-02-27 13:10:48 +000013614 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000013615 t1 = newTemp(Ity_I8);
13616 assign( t1, unop(Iop_1Uto8,mk_amd64g_calculate_condition(opc-0x90)) );
13617 modrm = getUChar(delta);
13618 if (epartIsReg(modrm)) {
13619 delta++;
sewardj5b470602005-02-27 13:10:48 +000013620 putIRegE(1, pfx, modrm, mkexpr(t1));
sewardj118b23e2005-01-29 02:14:44 +000013621 DIP("set%s %s\n", name_AMD64Condcode(opc-0x90),
sewardj5b470602005-02-27 13:10:48 +000013622 nameIRegE(1,pfx,modrm));
sewardj118b23e2005-01-29 02:14:44 +000013623 } else {
sewardj5cc00ff2005-03-27 04:48:32 +000013624 addr = disAMode ( &alen, pfx, delta, dis_buf, 0 );
13625 delta += alen;
13626 storeLE( mkexpr(addr), mkexpr(t1) );
13627 DIP("set%s %s\n", name_AMD64Condcode(opc-0x90), dis_buf);
sewardj118b23e2005-01-29 02:14:44 +000013628 }
13629 break;
13630
sewardj33ef9c22005-11-04 20:05:57 +000013631 /* =-=-=-=-=-=-=-=-=- SHLD/SHRD -=-=-=-=-=-=-=-=-= */
13632
sewardjd20c8852005-01-20 20:04:07 +000013633//.. case 0xA4: /* SHLDv imm8,Gv,Ev */
sewardj8c332e22005-01-28 01:36:56 +000013634//.. modrm = getUChar(delta);
sewardjd20c8852005-01-20 20:04:07 +000013635//.. d32 = delta + lengthAMode(delta);
13636//.. vex_sprintf(dis_buf, "$%d", delta);
13637//.. delta = dis_SHLRD_Gv_Ev (
13638//.. sorb, delta, modrm, sz,
sewardj8c332e22005-01-28 01:36:56 +000013639//.. mkU8(getUChar(d32)), True, /* literal */
sewardjd20c8852005-01-20 20:04:07 +000013640//.. dis_buf, True );
13641//.. break;
sewardj33ef9c22005-11-04 20:05:57 +000013642 case 0xA5: /* SHLDv %cl,Gv,Ev */
13643 modrm = getUChar(delta);
13644 delta = dis_SHLRD_Gv_Ev (
13645 pfx, delta, modrm, sz,
13646 getIRegCL(), False, /* not literal */
13647 "%cl", True /* left */ );
13648 break;
13649
sewardj75ce3652005-11-04 20:49:36 +000013650 case 0xAC: /* SHRDv imm8,Gv,Ev */
13651 modrm = getUChar(delta);
13652 d64 = delta + lengthAMode(pfx, delta);
13653 vex_sprintf(dis_buf, "$%d", (Int)getUChar(d64));
13654 delta = dis_SHLRD_Gv_Ev (
13655 pfx, delta, modrm, sz,
13656 mkU8(getUChar(d64)), True, /* literal */
13657 dis_buf, False /* right */ );
13658 break;
sewardj33ef9c22005-11-04 20:05:57 +000013659 case 0xAD: /* SHRDv %cl,Gv,Ev */
13660 modrm = getUChar(delta);
13661 delta = dis_SHLRD_Gv_Ev (
13662 pfx, delta, modrm, sz,
13663 getIRegCL(), False, /* not literal */
13664 "%cl", False /* right */);
13665 break;
sewardje1698952005-02-08 15:02:39 +000013666
13667 /* =-=-=-=-=-=-=-=-=- SYSCALL -=-=-=-=-=-=-=-=-=-= */
13668 case 0x05: /* SYSCALL */
sewardj9e6491a2005-07-02 19:24:10 +000013669 guest_RIP_next_mustcheck = True;
13670 guest_RIP_next_assumed = guest_RIP_bbstart + delta;
13671 putIReg64( R_RCX, mkU64(guest_RIP_next_assumed) );
sewardje1698952005-02-08 15:02:39 +000013672 /* It's important that all guest state is up-to-date
13673 at this point. So we declare an end-of-block here, which
13674 forces any cached guest state to be flushed. */
sewardj4fa325a2005-11-03 13:27:24 +000013675 jmp_lit(Ijk_Sys_syscall, guest_RIP_next_assumed);
13676 dres.whatNext = Dis_StopHere;
13677 DIP("syscall\n");
13678 break;
sewardje1698952005-02-08 15:02:39 +000013679
sewardjb4fd2e72005-03-23 13:34:11 +000013680 /* =-=-=-=-=-=-=-=-=- XADD -=-=-=-=-=-=-=-=-=-= */
13681
sewardjd20c8852005-01-20 20:04:07 +000013682//.. //-- case 0xC0: /* XADD Gb,Eb */
13683//.. //-- eip = dis_xadd_G_E ( cb, sorb, 1, eip );
13684//.. //-- break;
sewardjb4fd2e72005-03-23 13:34:11 +000013685 case 0xC1: { /* XADD Gv,Ev */
13686 Bool decode_OK = False;
13687 delta = dis_xadd_G_E ( &decode_OK, pfx, sz, delta );
13688 if (!decode_OK)
13689 goto decode_failure;
13690 break;
13691 }
13692
sewardj8711f662005-05-09 17:52:56 +000013693 /* =-=-=-=-=-=-=-=-=- MMXery =-=-=-=-=-=-=-=-=-=-= */
13694
sewardj3d8107c2005-05-09 22:23:38 +000013695 case 0x71:
13696 case 0x72:
13697 case 0x73: /* PSLLgg/PSRAgg/PSRLgg mmxreg by imm8 */
13698
13699 case 0x6E: /* MOVD (src)ireg-or-mem, (dst)mmxreg */
13700 case 0x7E: /* MOVD (src)mmxreg, (dst)ireg-or-mem */
sewardj8711f662005-05-09 17:52:56 +000013701 case 0x7F: /* MOVQ (src)mmxreg, (dst)mmxreg-or-mem */
13702 case 0x6F: /* MOVQ (src)mmxreg-or-mem, (dst)mmxreg */
13703
13704 case 0xFC:
13705 case 0xFD:
13706 case 0xFE: /* PADDgg (src)mmxreg-or-mem, (dst)mmxreg */
13707
13708 case 0xEC:
13709 case 0xED: /* PADDSgg (src)mmxreg-or-mem, (dst)mmxreg */
13710
13711 case 0xDC:
13712 case 0xDD: /* PADDUSgg (src)mmxreg-or-mem, (dst)mmxreg */
13713
13714 case 0xF8:
13715 case 0xF9:
13716 case 0xFA: /* PSUBgg (src)mmxreg-or-mem, (dst)mmxreg */
13717
13718 case 0xE8:
13719 case 0xE9: /* PSUBSgg (src)mmxreg-or-mem, (dst)mmxreg */
13720
13721 case 0xD8:
13722 case 0xD9: /* PSUBUSgg (src)mmxreg-or-mem, (dst)mmxreg */
13723
13724 case 0xE5: /* PMULHW (src)mmxreg-or-mem, (dst)mmxreg */
13725 case 0xD5: /* PMULLW (src)mmxreg-or-mem, (dst)mmxreg */
13726
13727 case 0xF5: /* PMADDWD (src)mmxreg-or-mem, (dst)mmxreg */
13728
13729 case 0x74:
13730 case 0x75:
13731 case 0x76: /* PCMPEQgg (src)mmxreg-or-mem, (dst)mmxreg */
13732
13733 case 0x64:
13734 case 0x65:
13735 case 0x66: /* PCMPGTgg (src)mmxreg-or-mem, (dst)mmxreg */
13736
13737 case 0x6B: /* PACKSSDW (src)mmxreg-or-mem, (dst)mmxreg */
13738 case 0x63: /* PACKSSWB (src)mmxreg-or-mem, (dst)mmxreg */
13739 case 0x67: /* PACKUSWB (src)mmxreg-or-mem, (dst)mmxreg */
13740
13741 case 0x68:
13742 case 0x69:
13743 case 0x6A: /* PUNPCKHgg (src)mmxreg-or-mem, (dst)mmxreg */
13744
13745 case 0x60:
13746 case 0x61:
13747 case 0x62: /* PUNPCKLgg (src)mmxreg-or-mem, (dst)mmxreg */
13748
13749 case 0xDB: /* PAND (src)mmxreg-or-mem, (dst)mmxreg */
13750 case 0xDF: /* PANDN (src)mmxreg-or-mem, (dst)mmxreg */
13751 case 0xEB: /* POR (src)mmxreg-or-mem, (dst)mmxreg */
13752 case 0xEF: /* PXOR (src)mmxreg-or-mem, (dst)mmxreg */
13753
13754 case 0xF1: /* PSLLgg (src)mmxreg-or-mem, (dst)mmxreg */
13755 case 0xF2:
13756 case 0xF3:
13757
13758 case 0xD1: /* PSRLgg (src)mmxreg-or-mem, (dst)mmxreg */
13759 case 0xD2:
13760 case 0xD3:
13761
13762 case 0xE1: /* PSRAgg (src)mmxreg-or-mem, (dst)mmxreg */
13763 case 0xE2:
13764 {
sewardj270def42005-07-03 01:03:01 +000013765 Long delta0 = delta-1;
sewardj8711f662005-05-09 17:52:56 +000013766 Bool decode_OK = False;
13767
13768 /* If sz==2 this is SSE, and we assume sse idec has
13769 already spotted those cases by now. */
sewardj3d8107c2005-05-09 22:23:38 +000013770 if (sz != 4 && sz != 8)
sewardj8711f662005-05-09 17:52:56 +000013771 goto decode_failure;
13772 if (have66orF2orF3(pfx))
13773 goto decode_failure;
13774
13775 delta = dis_MMX ( &decode_OK, pfx, sz, delta-1 );
13776 if (!decode_OK) {
13777 delta = delta0;
13778 goto decode_failure;
13779 }
13780 break;
13781 }
13782
sewardjae84d782006-04-13 22:06:35 +000013783 case 0x0E: /* FEMMS */
sewardj8711f662005-05-09 17:52:56 +000013784 case 0x77: /* EMMS */
13785 if (sz != 4)
13786 goto decode_failure;
13787 do_EMMS_preamble();
sewardjae84d782006-04-13 22:06:35 +000013788 DIP("{f}emms\n");
sewardj8711f662005-05-09 17:52:56 +000013789 break;
sewardj3ca55a12005-01-27 16:06:23 +000013790
13791 /* =-=-=-=-=-=-=-=-=- unimp2 =-=-=-=-=-=-=-=-=-=-= */
13792
13793 default:
13794 goto decode_failure;
13795 } /* switch (opc) for the 2-byte opcodes */
13796 goto decode_success;
13797 } /* case 0x0F: of primary opcode */
sewardjdf0e0022005-01-25 15:48:43 +000013798
13799 /* ------------------------ ??? ------------------------ */
13800
13801 default:
13802 decode_failure:
13803 /* All decode failures end up here. */
13804 vex_printf("vex amd64->IR: unhandled instruction bytes: "
13805 "0x%x 0x%x 0x%x 0x%x\n",
sewardj8c332e22005-01-28 01:36:56 +000013806 (Int)getUChar(delta_start+0),
13807 (Int)getUChar(delta_start+1),
13808 (Int)getUChar(delta_start+2),
13809 (Int)getUChar(delta_start+3) );
sewardjdf0e0022005-01-25 15:48:43 +000013810
13811 /* Tell the dispatcher that this insn cannot be decoded, and so has
13812 not been executed, and (is currently) the next to be executed.
13813 RIP should be up-to-date since it made so at the start of each
13814 insn, but nevertheless be paranoid and update it again right
13815 now. */
sewardj9e6491a2005-07-02 19:24:10 +000013816 stmt( IRStmt_Put( OFFB_RIP, mkU64(guest_RIP_curr_instr) ) );
13817 jmp_lit(Ijk_NoDecode, guest_RIP_curr_instr);
13818 dres.whatNext = Dis_StopHere;
13819 dres.len = 0;
13820 return dres;
sewardjdf0e0022005-01-25 15:48:43 +000013821
13822 } /* switch (opc) for the main (primary) opcode switch. */
13823
13824 decode_success:
13825 /* All decode successes end up here. */
13826 DIP("\n");
sewardj9e6491a2005-07-02 19:24:10 +000013827 dres.len = (Int)toUInt(delta - delta_start);
13828 return dres;
sewardjdf0e0022005-01-25 15:48:43 +000013829}
13830
13831#undef DIP
13832#undef DIS
sewardjd20c8852005-01-20 20:04:07 +000013833
sewardj9e6491a2005-07-02 19:24:10 +000013834
13835/*------------------------------------------------------------*/
13836/*--- Top-level fn ---*/
13837/*------------------------------------------------------------*/
13838
13839/* Disassemble a single instruction into IR. The instruction
13840 is located in host memory at &guest_code[delta]. */
13841
13842DisResult disInstr_AMD64 ( IRBB* irbb_IN,
13843 Bool put_IP,
sewardjc716aea2006-01-17 01:48:46 +000013844 Bool (*resteerOkFn) ( void*, Addr64 ),
13845 void* callback_opaque,
sewardj9e6491a2005-07-02 19:24:10 +000013846 UChar* guest_code_IN,
13847 Long delta,
13848 Addr64 guest_IP,
sewardja5f55da2006-04-30 23:37:32 +000013849 VexArch guest_arch,
sewardj9e6491a2005-07-02 19:24:10 +000013850 VexArchInfo* archinfo,
13851 Bool host_bigendian_IN )
13852{
13853 DisResult dres;
13854
13855 /* Set globals (see top of this file) */
sewardja5f55da2006-04-30 23:37:32 +000013856 vassert(guest_arch == VexArchAMD64);
sewardj9e6491a2005-07-02 19:24:10 +000013857 guest_code = guest_code_IN;
13858 irbb = irbb_IN;
13859 host_is_bigendian = host_bigendian_IN;
13860 guest_RIP_curr_instr = guest_IP;
13861 guest_RIP_bbstart = guest_IP - delta;
13862
13863 /* We'll consult these after doing disInstr_AMD64_WRK. */
13864 guest_RIP_next_assumed = 0;
13865 guest_RIP_next_mustcheck = False;
13866
sewardjc716aea2006-01-17 01:48:46 +000013867 dres = disInstr_AMD64_WRK ( put_IP, resteerOkFn, callback_opaque,
sewardj9e6491a2005-07-02 19:24:10 +000013868 delta, archinfo );
13869
13870 /* If disInstr_AMD64_WRK tried to figure out the next rip, check it
13871 got it right. Failure of this assertion is serious and denotes
13872 a bug in disInstr. */
13873 if (guest_RIP_next_mustcheck
13874 && guest_RIP_next_assumed != guest_RIP_curr_instr + dres.len) {
13875 vex_printf("\n");
13876 vex_printf("assumed next %%rip = 0x%llx\n",
13877 guest_RIP_next_assumed );
13878 vex_printf(" actual next %%rip = 0x%llx\n",
13879 guest_RIP_curr_instr + dres.len );
13880 vpanic("bbToIR_AMD64: disInstr miscalculated next %rip");
13881 }
13882
13883 return dres;
13884}
13885
13886
13887
sewardjd20c8852005-01-20 20:04:07 +000013888/*--------------------------------------------------------------------*/
13889/*--- end guest-amd64/toIR.c ---*/
13890/*--------------------------------------------------------------------*/