blob: 16782313a5cabb3b1b475db98dcb1cefd9c1ef81 [file] [log] [blame]
sewardjd20c8852005-01-20 20:04:07 +00001
2/*--------------------------------------------------------------------*/
3/*--- ---*/
sewardjcef7d3e2009-07-02 12:21:59 +00004/*--- 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
sewardjcef7d3e2009-07-02 12:21:59 +000013 Copyright (C) 2004-2009 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
sewardje9d8a262009-07-01 08:06:34 +000047/* Translates AMD64 code to IR. */
sewardj9ff93bc2005-03-23 11:25:12 +000048
sewardj820611e2005-08-24 10:56:01 +000049/* TODO:
50
51 All Puts to CC_OP/CC_DEP1/CC_DEP2/CC_NDEP should really be checked
52 to ensure a 64-bit value is being written.
53
sewardje9d8a262009-07-01 08:06:34 +000054 x87 FP Limitations:
55
56 * all arithmetic done at 64 bits
57
58 * no FP exceptions, except for handling stack over/underflow
59
60 * FP rounding mode observed only for float->int conversions and
61 int->float conversions which could lose accuracy, and for
62 float-to-float rounding. For all other operations,
63 round-to-nearest is used, regardless.
64
65 * FP sin/cos/tan/sincos: C2 flag is always cleared. IOW the
66 simulation claims the argument is in-range (-2^63 <= arg <= 2^63)
67 even when it isn't.
68
69 * some of the FCOM cases could do with testing -- not convinced
70 that the args are the right way round.
71
72 * FSAVE does not re-initialise the FPU; it should do
73
74 * FINIT not only initialises the FPU environment, it also zeroes
75 all the FP registers. It should leave the registers unchanged.
76
77 RDTSC returns zero, always.
78
79 SAHF should cause eflags[1] == 1, and in fact it produces 0. As
80 per Intel docs this bit has no meaning anyway. Since PUSHF is the
81 only way to observe eflags[1], a proper fix would be to make that
82 bit be set by PUSHF.
83
84 This module uses global variables and so is not MT-safe (if that
85 should ever become relevant).
sewardj820611e2005-08-24 10:56:01 +000086*/
sewardj44d494d2005-01-20 20:26:33 +000087
sewardj42561ef2005-11-04 14:18:31 +000088/* Notes re address size overrides (0x67).
89
90 According to the AMD documentation (24594 Rev 3.09, Sept 2003,
91 "AMD64 Architecture Programmer's Manual Volume 3: General-Purpose
92 and System Instructions"), Section 1.2.3 ("Address-Size Override
93 Prefix"):
94
95 0x67 applies to all explicit memory references, causing the top
96 32 bits of the effective address to become zero.
97
98 0x67 has no effect on stack references (push/pop); these always
99 use a 64-bit address.
100
101 0x67 changes the interpretation of instructions which implicitly
102 reference RCX/RSI/RDI, so that in fact ECX/ESI/EDI are used
103 instead. These are:
104
105 cmp{s,sb,sw,sd,sq}
106 in{s,sb,sw,sd}
107 jcxz, jecxz, jrcxz
108 lod{s,sb,sw,sd,sq}
109 loop{,e,bz,be,z}
110 mov{s,sb,sw,sd,sq}
111 out{s,sb,sw,sd}
112 rep{,e,ne,nz}
113 sca{s,sb,sw,sd,sq}
114 sto{s,sb,sw,sd,sq}
115 xlat{,b} */
116
sewardjce02aa72006-01-12 12:27:58 +0000117/* "Special" instructions.
118
119 This instruction decoder can decode three special instructions
120 which mean nothing natively (are no-ops as far as regs/mem are
121 concerned) but have meaning for supporting Valgrind. A special
122 instruction is flagged by the 16-byte preamble 48C1C703 48C1C70D
123 48C1C73D 48C1C733 (in the standard interpretation, that means: rolq
124 $3, %rdi; rolq $13, %rdi; rolq $61, %rdi; rolq $51, %rdi).
125 Following that, one of the following 3 are allowed (standard
126 interpretation in parentheses):
127
128 4887DB (xchgq %rbx,%rbx) %RDX = client_request ( %RAX )
129 4887C9 (xchgq %rcx,%rcx) %RAX = guest_NRADDR
130 4887D2 (xchgq %rdx,%rdx) call-noredir *%RAX
131
132 Any other bytes following the 16-byte preamble are illegal and
133 constitute a failure in instruction decoding. This all assumes
134 that the preamble will never occur except in specific code
135 fragments designed for Valgrind to catch.
136
sewardje9d8a262009-07-01 08:06:34 +0000137 No prefixes may precede a "Special" instruction.
138*/
sewardjce02aa72006-01-12 12:27:58 +0000139
sewardje9d8a262009-07-01 08:06:34 +0000140/* casLE (implementation of lock-prefixed insns) and rep-prefixed
141 insns: the side-exit back to the start of the insn is done with
142 Ijk_Boring. This is quite wrong, it should be done with
143 Ijk_NoRedir, since otherwise the side exit, which is intended to
144 restart the instruction for whatever reason, could go somewhere
145 entirely else. Doing it right (with Ijk_NoRedir jumps) would make
146 no-redir jumps performance critical, at least for rep-prefixed
147 instructions, since all iterations thereof would involve such a
148 jump. It's not such a big deal with casLE since the side exit is
149 only taken if the CAS fails, that is, the location is contended,
150 which is relatively unlikely.
sewardj1fb8c922009-07-12 12:56:53 +0000151
152 Note also, the test for CAS success vs failure is done using
153 Iop_CasCmp{EQ,NE}{8,16,32,64} rather than the ordinary
154 Iop_Cmp{EQ,NE} equivalents. This is so as to tell Memcheck that it
155 shouldn't definedness-check these comparisons. See
156 COMMENT_ON_CasCmpEQ in memcheck/mc_translate.c for
157 background/rationale.
sewardje9d8a262009-07-01 08:06:34 +0000158*/
159
160/* LOCK prefixed instructions. These are translated using IR-level
161 CAS statements (IRCAS) and are believed to preserve atomicity, even
162 from the point of view of some other process racing against a
163 simulated one (presumably they communicate via a shared memory
164 segment).
165
166 Handlers which are aware of LOCK prefixes are:
167 dis_op2_G_E (add, or, adc, sbb, and, sub, xor)
168 dis_cmpxchg_G_E (cmpxchg)
169 dis_Grp1 (add, or, adc, sbb, and, sub, xor)
170 dis_Grp3 (not, neg)
171 dis_Grp4 (inc, dec)
172 dis_Grp5 (inc, dec)
173 dis_Grp8_Imm (bts, btc, btr)
174 dis_bt_G_E (bts, btc, btr)
175 dis_xadd_G_E (xadd)
176*/
177
sewardj44d494d2005-01-20 20:26:33 +0000178
179#include "libvex_basictypes.h"
180#include "libvex_ir.h"
181#include "libvex.h"
182#include "libvex_guest_amd64.h"
183
sewardjcef7d3e2009-07-02 12:21:59 +0000184#include "main_util.h"
185#include "main_globals.h"
186#include "guest_generic_bb_to_IR.h"
187#include "guest_generic_x87.h"
188#include "guest_amd64_defs.h"
sewardj44d494d2005-01-20 20:26:33 +0000189
190
sewardjecb94892005-01-21 14:26:37 +0000191/*------------------------------------------------------------*/
192/*--- Globals ---*/
193/*------------------------------------------------------------*/
194
sewardj9e6491a2005-07-02 19:24:10 +0000195/* These are set at the start of the translation of an insn, right
196 down in disInstr_AMD64, so that we don't have to pass them around
197 endlessly. They are all constant during the translation of any
198 given insn. */
sewardj4b744762005-02-07 15:02:25 +0000199
sewardjecb94892005-01-21 14:26:37 +0000200/* These are set at the start of the translation of a BB, so
201 that we don't have to pass them around endlessly. */
202
203/* We need to know this to do sub-register accesses correctly. */
sewardjecb94892005-01-21 14:26:37 +0000204static Bool host_is_bigendian;
205
sewardj9e6491a2005-07-02 19:24:10 +0000206/* Pointer to the guest code area (points to start of BB, not to the
207 insn being processed). */
sewardjb3a04292005-01-21 20:33:44 +0000208static UChar* guest_code;
209
sewardjdf0e0022005-01-25 15:48:43 +0000210/* The guest address corresponding to guest_code[0]. */
sewardj9e6491a2005-07-02 19:24:10 +0000211static Addr64 guest_RIP_bbstart;
sewardj4b744762005-02-07 15:02:25 +0000212
sewardjb3a04292005-01-21 20:33:44 +0000213/* The guest address for the instruction currently being
214 translated. */
sewardj9e6491a2005-07-02 19:24:10 +0000215static Addr64 guest_RIP_curr_instr;
sewardjecb94892005-01-21 14:26:37 +0000216
sewardjdd40fdf2006-12-24 02:20:24 +0000217/* The IRSB* into which we're generating code. */
218static IRSB* irsb;
sewardjecb94892005-01-21 14:26:37 +0000219
sewardj4b744762005-02-07 15:02:25 +0000220/* For ensuring that %rip-relative addressing is done right. A read
221 of %rip generates the address of the next instruction. It may be
222 that we don't conveniently know that inside disAMode(). For sanity
223 checking, if the next insn %rip is needed, we make a guess at what
224 it is, record that guess here, and set the accompanying Bool to
225 indicate that -- after this insn's decode is finished -- that guess
226 needs to be checked. */
227
228/* At the start of each insn decode, is set to (0, False).
229 After the decode, if _mustcheck is now True, _assumed is
230 checked. */
231
sewardj9e6491a2005-07-02 19:24:10 +0000232static Addr64 guest_RIP_next_assumed;
233static Bool guest_RIP_next_mustcheck;
sewardj4b744762005-02-07 15:02:25 +0000234
235
sewardjecb94892005-01-21 14:26:37 +0000236/*------------------------------------------------------------*/
237/*--- Helpers for constructing IR. ---*/
238/*------------------------------------------------------------*/
239
sewardjb3a04292005-01-21 20:33:44 +0000240/* Generate a new temporary of the given type. */
241static IRTemp newTemp ( IRType ty )
242{
sewardj496a58d2005-03-20 18:44:44 +0000243 vassert(isPlausibleIRType(ty));
sewardjdd40fdf2006-12-24 02:20:24 +0000244 return newIRTemp( irsb->tyenv, ty );
sewardjb3a04292005-01-21 20:33:44 +0000245}
246
sewardjdd40fdf2006-12-24 02:20:24 +0000247/* Add a statement to the list held by "irsb". */
sewardjecb94892005-01-21 14:26:37 +0000248static void stmt ( IRStmt* st )
249{
sewardjdd40fdf2006-12-24 02:20:24 +0000250 addStmtToIRSB( irsb, st );
sewardjecb94892005-01-21 14:26:37 +0000251}
sewardjb3a04292005-01-21 20:33:44 +0000252
253/* Generate a statement "dst := e". */
254static void assign ( IRTemp dst, IRExpr* e )
255{
sewardjdd40fdf2006-12-24 02:20:24 +0000256 stmt( IRStmt_WrTmp(dst, e) );
sewardjb3a04292005-01-21 20:33:44 +0000257}
258
sewardjecb94892005-01-21 14:26:37 +0000259static IRExpr* unop ( IROp op, IRExpr* a )
260{
261 return IRExpr_Unop(op, a);
262}
263
sewardjb3a04292005-01-21 20:33:44 +0000264static IRExpr* binop ( IROp op, IRExpr* a1, IRExpr* a2 )
265{
266 return IRExpr_Binop(op, a1, a2);
267}
268
sewardj4796d662006-02-05 16:06:26 +0000269static IRExpr* triop ( IROp op, IRExpr* a1, IRExpr* a2, IRExpr* a3 )
270{
271 return IRExpr_Triop(op, a1, a2, a3);
272}
273
sewardjdf0e0022005-01-25 15:48:43 +0000274static IRExpr* mkexpr ( IRTemp tmp )
275{
sewardjdd40fdf2006-12-24 02:20:24 +0000276 return IRExpr_RdTmp(tmp);
sewardjdf0e0022005-01-25 15:48:43 +0000277}
sewardjb3a04292005-01-21 20:33:44 +0000278
sewardj3ca55a12005-01-27 16:06:23 +0000279static IRExpr* mkU8 ( ULong i )
sewardjb3a04292005-01-21 20:33:44 +0000280{
281 vassert(i < 256);
sewardj3ca55a12005-01-27 16:06:23 +0000282 return IRExpr_Const(IRConst_U8( (UChar)i ));
sewardjb3a04292005-01-21 20:33:44 +0000283}
284
sewardj5e525292005-01-28 15:13:10 +0000285static IRExpr* mkU16 ( ULong i )
286{
287 vassert(i < 0x10000ULL);
288 return IRExpr_Const(IRConst_U16( (UShort)i ));
289}
sewardj3ca55a12005-01-27 16:06:23 +0000290
291static IRExpr* mkU32 ( ULong i )
292{
293 vassert(i < 0x100000000ULL);
294 return IRExpr_Const(IRConst_U32( (UInt)i ));
295}
sewardjb3a04292005-01-21 20:33:44 +0000296
297static IRExpr* mkU64 ( ULong i )
298{
299 return IRExpr_Const(IRConst_U64(i));
300}
sewardjecb94892005-01-21 14:26:37 +0000301
sewardj3ca55a12005-01-27 16:06:23 +0000302static IRExpr* mkU ( IRType ty, ULong i )
303{
304 switch (ty) {
305 case Ity_I8: return mkU8(i);
sewardj5e525292005-01-28 15:13:10 +0000306 case Ity_I16: return mkU16(i);
sewardj3ca55a12005-01-27 16:06:23 +0000307 case Ity_I32: return mkU32(i);
308 case Ity_I64: return mkU64(i);
309 default: vpanic("mkU(amd64)");
310 }
311}
312
sewardj5e525292005-01-28 15:13:10 +0000313static void storeLE ( IRExpr* addr, IRExpr* data )
314{
sewardje768e922009-11-26 17:17:37 +0000315 stmt( IRStmt_Store(Iend_LE, addr, data) );
sewardj5e525292005-01-28 15:13:10 +0000316}
317
sewardje768e922009-11-26 17:17:37 +0000318static IRExpr* loadLE ( IRType ty, IRExpr* addr )
sewardj5e525292005-01-28 15:13:10 +0000319{
sewardje768e922009-11-26 17:17:37 +0000320 return IRExpr_Load(Iend_LE, ty, addr);
sewardj5e525292005-01-28 15:13:10 +0000321}
322
323static IROp mkSizedOp ( IRType ty, IROp op8 )
324{
325 vassert(op8 == Iop_Add8 || op8 == Iop_Sub8
326 || op8 == Iop_Mul8
327 || op8 == Iop_Or8 || op8 == Iop_And8 || op8 == Iop_Xor8
328 || op8 == Iop_Shl8 || op8 == Iop_Shr8 || op8 == Iop_Sar8
329 || op8 == Iop_CmpEQ8 || op8 == Iop_CmpNE8
sewardj1fb8c922009-07-12 12:56:53 +0000330 || op8 == Iop_CasCmpNE8
sewardj5e525292005-01-28 15:13:10 +0000331 || op8 == Iop_Not8 );
332 switch (ty) {
333 case Ity_I8: return 0 +op8;
334 case Ity_I16: return 1 +op8;
335 case Ity_I32: return 2 +op8;
336 case Ity_I64: return 3 +op8;
337 default: vpanic("mkSizedOp(amd64)");
338 }
339}
340
341static
342IRExpr* doScalarWidening ( Int szSmall, Int szBig, Bool signd, IRExpr* src )
343{
344 if (szSmall == 1 && szBig == 4) {
345 return unop(signd ? Iop_8Sto32 : Iop_8Uto32, src);
346 }
347 if (szSmall == 1 && szBig == 2) {
348 return unop(signd ? Iop_8Sto16 : Iop_8Uto16, src);
349 }
350 if (szSmall == 2 && szBig == 4) {
351 return unop(signd ? Iop_16Sto32 : Iop_16Uto32, src);
352 }
353 if (szSmall == 1 && szBig == 8 && !signd) {
sewardje58967e2005-04-27 11:50:56 +0000354 return unop(Iop_8Uto64, src);
sewardj5e525292005-01-28 15:13:10 +0000355 }
sewardj03b07cc2005-01-31 18:09:43 +0000356 if (szSmall == 1 && szBig == 8 && signd) {
sewardje58967e2005-04-27 11:50:56 +0000357 return unop(Iop_8Sto64, src);
sewardj03b07cc2005-01-31 18:09:43 +0000358 }
sewardj5e525292005-01-28 15:13:10 +0000359 if (szSmall == 2 && szBig == 8 && !signd) {
sewardje58967e2005-04-27 11:50:56 +0000360 return unop(Iop_16Uto64, src);
sewardj5e525292005-01-28 15:13:10 +0000361 }
sewardj03b07cc2005-01-31 18:09:43 +0000362 if (szSmall == 2 && szBig == 8 && signd) {
sewardje58967e2005-04-27 11:50:56 +0000363 return unop(Iop_16Sto64, src);
sewardj03b07cc2005-01-31 18:09:43 +0000364 }
sewardj5e525292005-01-28 15:13:10 +0000365 vpanic("doScalarWidening(amd64)");
366}
367
368
sewardjecb94892005-01-21 14:26:37 +0000369
370/*------------------------------------------------------------*/
371/*--- Debugging output ---*/
372/*------------------------------------------------------------*/
373
sewardjb3a04292005-01-21 20:33:44 +0000374/* Bomb out if we can't handle something. */
375__attribute__ ((noreturn))
376static void unimplemented ( HChar* str )
377{
378 vex_printf("amd64toIR: unimplemented feature\n");
379 vpanic(str);
380}
381
sewardjecb94892005-01-21 14:26:37 +0000382#define DIP(format, args...) \
sewardj9e6491a2005-07-02 19:24:10 +0000383 if (vex_traceflags & VEX_TRACE_FE) \
sewardjecb94892005-01-21 14:26:37 +0000384 vex_printf(format, ## args)
385
386#define DIS(buf, format, args...) \
sewardj9e6491a2005-07-02 19:24:10 +0000387 if (vex_traceflags & VEX_TRACE_FE) \
sewardjecb94892005-01-21 14:26:37 +0000388 vex_sprintf(buf, format, ## args)
389
390
391/*------------------------------------------------------------*/
392/*--- Offsets of various parts of the amd64 guest state. ---*/
393/*------------------------------------------------------------*/
394
395#define OFFB_RAX offsetof(VexGuestAMD64State,guest_RAX)
396#define OFFB_RBX offsetof(VexGuestAMD64State,guest_RBX)
397#define OFFB_RCX offsetof(VexGuestAMD64State,guest_RCX)
398#define OFFB_RDX offsetof(VexGuestAMD64State,guest_RDX)
399#define OFFB_RSP offsetof(VexGuestAMD64State,guest_RSP)
400#define OFFB_RBP offsetof(VexGuestAMD64State,guest_RBP)
401#define OFFB_RSI offsetof(VexGuestAMD64State,guest_RSI)
402#define OFFB_RDI offsetof(VexGuestAMD64State,guest_RDI)
403#define OFFB_R8 offsetof(VexGuestAMD64State,guest_R8)
404#define OFFB_R9 offsetof(VexGuestAMD64State,guest_R9)
405#define OFFB_R10 offsetof(VexGuestAMD64State,guest_R10)
406#define OFFB_R11 offsetof(VexGuestAMD64State,guest_R11)
407#define OFFB_R12 offsetof(VexGuestAMD64State,guest_R12)
408#define OFFB_R13 offsetof(VexGuestAMD64State,guest_R13)
409#define OFFB_R14 offsetof(VexGuestAMD64State,guest_R14)
410#define OFFB_R15 offsetof(VexGuestAMD64State,guest_R15)
411
412#define OFFB_RIP offsetof(VexGuestAMD64State,guest_RIP)
413
sewardja6b93d12005-02-17 09:28:28 +0000414#define OFFB_FS_ZERO offsetof(VexGuestAMD64State,guest_FS_ZERO)
sewardjd660d412008-12-03 21:29:59 +0000415#define OFFB_GS_0x60 offsetof(VexGuestAMD64State,guest_GS_0x60)
sewardja6b93d12005-02-17 09:28:28 +0000416
sewardjecb94892005-01-21 14:26:37 +0000417#define OFFB_CC_OP offsetof(VexGuestAMD64State,guest_CC_OP)
418#define OFFB_CC_DEP1 offsetof(VexGuestAMD64State,guest_CC_DEP1)
419#define OFFB_CC_DEP2 offsetof(VexGuestAMD64State,guest_CC_DEP2)
420#define OFFB_CC_NDEP offsetof(VexGuestAMD64State,guest_CC_NDEP)
421
sewardj8d965312005-02-25 02:48:47 +0000422#define OFFB_FPREGS offsetof(VexGuestAMD64State,guest_FPREG[0])
423#define OFFB_FPTAGS offsetof(VexGuestAMD64State,guest_FPTAG[0])
sewardjd0a12df2005-02-10 02:07:43 +0000424#define OFFB_DFLAG offsetof(VexGuestAMD64State,guest_DFLAG)
sewardj85520e42005-02-19 15:22:38 +0000425#define OFFB_IDFLAG offsetof(VexGuestAMD64State,guest_IDFLAG)
sewardj8d965312005-02-25 02:48:47 +0000426#define OFFB_FTOP offsetof(VexGuestAMD64State,guest_FTOP)
sewardj25a85812005-05-08 23:03:48 +0000427#define OFFB_FC3210 offsetof(VexGuestAMD64State,guest_FC3210)
sewardjc49ce232005-02-25 13:03:03 +0000428#define OFFB_FPROUND offsetof(VexGuestAMD64State,guest_FPROUND)
sewardjd20c8852005-01-20 20:04:07 +0000429//..
430//.. #define OFFB_CS offsetof(VexGuestX86State,guest_CS)
431//.. #define OFFB_DS offsetof(VexGuestX86State,guest_DS)
432//.. #define OFFB_ES offsetof(VexGuestX86State,guest_ES)
433//.. #define OFFB_FS offsetof(VexGuestX86State,guest_FS)
434//.. #define OFFB_GS offsetof(VexGuestX86State,guest_GS)
435//.. #define OFFB_SS offsetof(VexGuestX86State,guest_SS)
436//.. #define OFFB_LDT offsetof(VexGuestX86State,guest_LDT)
437//.. #define OFFB_GDT offsetof(VexGuestX86State,guest_GDT)
sewardj1001dc42005-02-21 08:25:55 +0000438
439#define OFFB_SSEROUND offsetof(VexGuestAMD64State,guest_SSEROUND)
440#define OFFB_XMM0 offsetof(VexGuestAMD64State,guest_XMM0)
441#define OFFB_XMM1 offsetof(VexGuestAMD64State,guest_XMM1)
442#define OFFB_XMM2 offsetof(VexGuestAMD64State,guest_XMM2)
443#define OFFB_XMM3 offsetof(VexGuestAMD64State,guest_XMM3)
444#define OFFB_XMM4 offsetof(VexGuestAMD64State,guest_XMM4)
445#define OFFB_XMM5 offsetof(VexGuestAMD64State,guest_XMM5)
446#define OFFB_XMM6 offsetof(VexGuestAMD64State,guest_XMM6)
447#define OFFB_XMM7 offsetof(VexGuestAMD64State,guest_XMM7)
448#define OFFB_XMM8 offsetof(VexGuestAMD64State,guest_XMM8)
449#define OFFB_XMM9 offsetof(VexGuestAMD64State,guest_XMM9)
450#define OFFB_XMM10 offsetof(VexGuestAMD64State,guest_XMM10)
451#define OFFB_XMM11 offsetof(VexGuestAMD64State,guest_XMM11)
452#define OFFB_XMM12 offsetof(VexGuestAMD64State,guest_XMM12)
453#define OFFB_XMM13 offsetof(VexGuestAMD64State,guest_XMM13)
454#define OFFB_XMM14 offsetof(VexGuestAMD64State,guest_XMM14)
455#define OFFB_XMM15 offsetof(VexGuestAMD64State,guest_XMM15)
456
sewardjbcbb9de2005-03-27 02:22:32 +0000457#define OFFB_EMWARN offsetof(VexGuestAMD64State,guest_EMWARN)
sewardj3e616e62006-01-07 22:58:54 +0000458#define OFFB_TISTART offsetof(VexGuestAMD64State,guest_TISTART)
459#define OFFB_TILEN offsetof(VexGuestAMD64State,guest_TILEN)
sewardjdf0e0022005-01-25 15:48:43 +0000460
sewardjce02aa72006-01-12 12:27:58 +0000461#define OFFB_NRADDR offsetof(VexGuestAMD64State,guest_NRADDR)
462
sewardjdf0e0022005-01-25 15:48:43 +0000463
464/*------------------------------------------------------------*/
sewardjecb94892005-01-21 14:26:37 +0000465/*--- Helper bits and pieces for deconstructing the ---*/
466/*--- amd64 insn stream. ---*/
467/*------------------------------------------------------------*/
468
469/* This is the AMD64 register encoding -- integer regs. */
470#define R_RAX 0
471#define R_RCX 1
472#define R_RDX 2
473#define R_RBX 3
474#define R_RSP 4
475#define R_RBP 5
476#define R_RSI 6
477#define R_RDI 7
478#define R_R8 8
479#define R_R9 9
480#define R_R10 10
481#define R_R11 11
482#define R_R12 12
483#define R_R13 13
484#define R_R14 14
485#define R_R15 15
486
sewardjd20c8852005-01-20 20:04:07 +0000487//.. #define R_AL (0+R_EAX)
488//.. #define R_AH (4+R_EAX)
sewardjecb94892005-01-21 14:26:37 +0000489
490/* This is the Intel register encoding -- segment regs. */
491#define R_ES 0
492#define R_CS 1
493#define R_SS 2
494#define R_DS 3
495#define R_FS 4
496#define R_GS 5
497
498
sewardjb3a04292005-01-21 20:33:44 +0000499/* Various simple conversions */
500
501static ULong extend_s_8to64 ( UChar x )
502{
503 return (ULong)((((Long)x) << 56) >> 56);
504}
505
506static ULong extend_s_16to64 ( UShort x )
507{
508 return (ULong)((((Long)x) << 48) >> 48);
509}
510
511static ULong extend_s_32to64 ( UInt x )
512{
513 return (ULong)((((Long)x) << 32) >> 32);
514}
515
sewardjdf0e0022005-01-25 15:48:43 +0000516/* Figure out whether the mod and rm parts of a modRM byte refer to a
517 register or memory. If so, the byte will have the form 11XXXYYY,
518 where YYY is the register number. */
sewardj5b470602005-02-27 13:10:48 +0000519inline
sewardjdf0e0022005-01-25 15:48:43 +0000520static Bool epartIsReg ( UChar mod_reg_rm )
521{
sewardj7a240552005-01-28 21:37:12 +0000522 return toBool(0xC0 == (mod_reg_rm & 0xC0));
sewardjdf0e0022005-01-25 15:48:43 +0000523}
524
sewardj901ed122005-02-27 13:25:31 +0000525/* Extract the 'g' field from a modRM byte. This only produces 3
526 bits, which is not a complete register number. You should avoid
527 this function if at all possible. */
528inline
529static Int gregLO3ofRM ( UChar mod_reg_rm )
sewardjdf0e0022005-01-25 15:48:43 +0000530{
531 return (Int)( (mod_reg_rm >> 3) & 7 );
532}
533
sewardj8711f662005-05-09 17:52:56 +0000534/* Ditto the 'e' field of a modRM byte. */
535inline
536static Int eregLO3ofRM ( UChar mod_reg_rm )
537{
538 return (Int)(mod_reg_rm & 0x7);
539}
540
sewardjdf0e0022005-01-25 15:48:43 +0000541/* Get a 8/16/32-bit unsigned value out of the insn stream. */
542
sewardj270def42005-07-03 01:03:01 +0000543static UChar getUChar ( Long delta )
sewardjdf0e0022005-01-25 15:48:43 +0000544{
sewardj8c332e22005-01-28 01:36:56 +0000545 UChar v = guest_code[delta+0];
546 return v;
sewardjdf0e0022005-01-25 15:48:43 +0000547}
548
sewardj47c2d4d2006-11-14 17:50:16 +0000549static UInt getUDisp16 ( Long delta )
550{
551 UInt v = guest_code[delta+1]; v <<= 8;
552 v |= guest_code[delta+0];
553 return v & 0xFFFF;
554}
555
sewardj270def42005-07-03 01:03:01 +0000556//.. static UInt getUDisp ( Int size, Long delta )
sewardjd20c8852005-01-20 20:04:07 +0000557//.. {
558//.. switch (size) {
559//.. case 4: return getUDisp32(delta);
560//.. case 2: return getUDisp16(delta);
561//.. case 1: return getUChar(delta);
562//.. default: vpanic("getUDisp(x86)");
563//.. }
564//.. return 0; /*notreached*/
565//.. }
sewardjb3a04292005-01-21 20:33:44 +0000566
567
568/* Get a byte value out of the insn stream and sign-extend to 64
569 bits. */
sewardj270def42005-07-03 01:03:01 +0000570static Long getSDisp8 ( Long delta )
sewardjb3a04292005-01-21 20:33:44 +0000571{
572 return extend_s_8to64( guest_code[delta] );
573}
574
sewardj5e525292005-01-28 15:13:10 +0000575/* Get a 16-bit value out of the insn stream and sign-extend to 64
576 bits. */
sewardj270def42005-07-03 01:03:01 +0000577static Long getSDisp16 ( Long delta )
sewardj5e525292005-01-28 15:13:10 +0000578{
sewardj118b23e2005-01-29 02:14:44 +0000579 UInt v = guest_code[delta+1]; v <<= 8;
sewardj5e525292005-01-28 15:13:10 +0000580 v |= guest_code[delta+0];
sewardj118b23e2005-01-29 02:14:44 +0000581 return extend_s_16to64( (UShort)v );
sewardj5e525292005-01-28 15:13:10 +0000582}
583
sewardjb3a04292005-01-21 20:33:44 +0000584/* Get a 32-bit value out of the insn stream and sign-extend to 64
585 bits. */
sewardj270def42005-07-03 01:03:01 +0000586static Long getSDisp32 ( Long delta )
sewardjb3a04292005-01-21 20:33:44 +0000587{
588 UInt v = guest_code[delta+3]; v <<= 8;
589 v |= guest_code[delta+2]; v <<= 8;
590 v |= guest_code[delta+1]; v <<= 8;
591 v |= guest_code[delta+0];
592 return extend_s_32to64( v );
593}
594
sewardj03b07cc2005-01-31 18:09:43 +0000595/* Get a 64-bit value out of the insn stream. */
sewardj270def42005-07-03 01:03:01 +0000596static Long getDisp64 ( Long delta )
sewardj03b07cc2005-01-31 18:09:43 +0000597{
sewardj7eaa7cf2005-01-31 18:55:22 +0000598 ULong v = 0;
sewardj03b07cc2005-01-31 18:09:43 +0000599 v |= guest_code[delta+7]; v <<= 8;
600 v |= guest_code[delta+6]; v <<= 8;
601 v |= guest_code[delta+5]; v <<= 8;
602 v |= guest_code[delta+4]; v <<= 8;
603 v |= guest_code[delta+3]; v <<= 8;
604 v |= guest_code[delta+2]; v <<= 8;
605 v |= guest_code[delta+1]; v <<= 8;
606 v |= guest_code[delta+0];
607 return v;
608}
609
sewardj3ca55a12005-01-27 16:06:23 +0000610/* Note: because AMD64 doesn't allow 64-bit literals, it is an error
611 if this is called with size==8. Should not happen. */
sewardj270def42005-07-03 01:03:01 +0000612static Long getSDisp ( Int size, Long delta )
sewardj3ca55a12005-01-27 16:06:23 +0000613{
614 switch (size) {
615 case 4: return getSDisp32(delta);
sewardj5e525292005-01-28 15:13:10 +0000616 case 2: return getSDisp16(delta);
sewardj3ca55a12005-01-27 16:06:23 +0000617 case 1: return getSDisp8(delta);
618 default: vpanic("getSDisp(amd64)");
619 }
620}
621
sewardj1389d4d2005-01-28 13:46:29 +0000622static ULong mkSizeMask ( Int sz )
sewardj3ca55a12005-01-27 16:06:23 +0000623{
624 switch (sz) {
sewardj1389d4d2005-01-28 13:46:29 +0000625 case 1: return 0x00000000000000FFULL;
626 case 2: return 0x000000000000FFFFULL;
627 case 4: return 0x00000000FFFFFFFFULL;
sewardj3ca55a12005-01-27 16:06:23 +0000628 case 8: return 0xFFFFFFFFFFFFFFFFULL;
629 default: vpanic("mkSzMask(amd64)");
630 }
631}
632
633static Int imin ( Int a, Int b )
634{
635 return (a < b) ? a : b;
636}
sewardjecb94892005-01-21 14:26:37 +0000637
sewardj5b470602005-02-27 13:10:48 +0000638static IRType szToITy ( Int n )
639{
640 switch (n) {
641 case 1: return Ity_I8;
642 case 2: return Ity_I16;
643 case 4: return Ity_I32;
644 case 8: return Ity_I64;
sewardjf53b7352005-04-06 20:01:56 +0000645 default: vex_printf("\nszToITy(%d)\n", n);
646 vpanic("szToITy(amd64)");
sewardj5b470602005-02-27 13:10:48 +0000647 }
648}
649
sewardjecb94892005-01-21 14:26:37 +0000650
651/*------------------------------------------------------------*/
652/*--- For dealing with prefixes. ---*/
653/*------------------------------------------------------------*/
654
655/* The idea is to pass around an int holding a bitmask summarising
656 info from the prefixes seen on the current instruction, including
657 info from the REX byte. This info is used in various places, but
658 most especially when making sense of register fields in
659 instructions.
660
661 The top 16 bits of the prefix are 0x3141, just as a hacky way
662 to ensure it really is a valid prefix.
sewardjdf0e0022005-01-25 15:48:43 +0000663
664 Things you can safely assume about a well-formed prefix:
665 * at most one segment-override bit (CS,DS,ES,FS,GS,SS) is set.
sewardj5b470602005-02-27 13:10:48 +0000666 * if REX is not present then REXW,REXR,REXX,REXB will read
667 as zero.
sewardjdf0e0022005-01-25 15:48:43 +0000668 * F2 and F3 will not both be 1.
sewardjecb94892005-01-21 14:26:37 +0000669*/
670
671typedef UInt Prefix;
672
sewardj3ca55a12005-01-27 16:06:23 +0000673#define PFX_ASO (1<<0) /* address-size override present (0x67) */
674#define PFX_66 (1<<1) /* operand-size override-to-16 present (0x66) */
675#define PFX_REX (1<<2) /* REX byte present (0x40 to 0x4F) */
676#define PFX_REXW (1<<3) /* REX W bit, if REX present, else 0 */
677#define PFX_REXR (1<<4) /* REX R bit, if REX present, else 0 */
678#define PFX_REXX (1<<5) /* REX X bit, if REX present, else 0 */
679#define PFX_REXB (1<<6) /* REX B bit, if REX present, else 0 */
680#define PFX_LOCK (1<<7) /* bus LOCK prefix present (0xF0) */
681#define PFX_F2 (1<<8) /* REP/REPE/REPZ prefix present (0xF2) */
682#define PFX_F3 (1<<9) /* REPNE/REPNZ prefix present (0xF3) */
683#define PFX_CS (1<<10) /* CS segment prefix present (0x2E) */
684#define PFX_DS (1<<11) /* DS segment prefix present (0x3E) */
685#define PFX_ES (1<<12) /* ES segment prefix present (0x26) */
686#define PFX_FS (1<<13) /* FS segment prefix present (0x64) */
687#define PFX_GS (1<<14) /* GS segment prefix present (0x65) */
688#define PFX_SS (1<<15) /* SS segment prefix present (0x36) */
689
690#define PFX_EMPTY 0x31410000
sewardjecb94892005-01-21 14:26:37 +0000691
sewardjb3a04292005-01-21 20:33:44 +0000692static Bool IS_VALID_PFX ( Prefix pfx ) {
sewardj7a240552005-01-28 21:37:12 +0000693 return toBool((pfx & 0xFFFF0000) == PFX_EMPTY);
sewardjecb94892005-01-21 14:26:37 +0000694}
695
sewardjb3a04292005-01-21 20:33:44 +0000696static Bool haveREX ( Prefix pfx ) {
sewardj7a240552005-01-28 21:37:12 +0000697 return toBool(pfx & PFX_REX);
sewardjecb94892005-01-21 14:26:37 +0000698}
699
sewardj5e525292005-01-28 15:13:10 +0000700static Int getRexW ( Prefix pfx ) {
701 return (pfx & PFX_REXW) ? 1 : 0;
702}
sewardj901ed122005-02-27 13:25:31 +0000703/* Apparently unused.
sewardjdf0e0022005-01-25 15:48:43 +0000704static Int getRexR ( Prefix pfx ) {
705 return (pfx & PFX_REXR) ? 1 : 0;
706}
sewardj901ed122005-02-27 13:25:31 +0000707*/
sewardj5b470602005-02-27 13:10:48 +0000708static Int getRexX ( Prefix pfx ) {
709 return (pfx & PFX_REXX) ? 1 : 0;
710}
sewardjdf0e0022005-01-25 15:48:43 +0000711static Int getRexB ( Prefix pfx ) {
712 return (pfx & PFX_REXB) ? 1 : 0;
713}
714
sewardj3ca55a12005-01-27 16:06:23 +0000715/* Check a prefix doesn't have F2 or F3 set in it, since usually that
716 completely changes what instruction it really is. */
717static Bool haveF2orF3 ( Prefix pfx ) {
sewardj7a240552005-01-28 21:37:12 +0000718 return toBool((pfx & (PFX_F2|PFX_F3)) > 0);
sewardj3ca55a12005-01-27 16:06:23 +0000719}
sewardj55dbb262005-01-28 16:36:51 +0000720static Bool haveF2 ( Prefix pfx ) {
sewardj7a240552005-01-28 21:37:12 +0000721 return toBool((pfx & PFX_F2) > 0);
sewardj55dbb262005-01-28 16:36:51 +0000722}
723static Bool haveF3 ( Prefix pfx ) {
sewardj7a240552005-01-28 21:37:12 +0000724 return toBool((pfx & PFX_F3) > 0);
sewardj55dbb262005-01-28 16:36:51 +0000725}
sewardj6359f812005-07-20 10:15:34 +0000726
sewardjc8b26352005-07-20 09:23:13 +0000727static Bool have66 ( Prefix pfx ) {
728 return toBool((pfx & PFX_66) > 0);
729}
sewardj6359f812005-07-20 10:15:34 +0000730static Bool haveASO ( Prefix pfx ) {
731 return toBool((pfx & PFX_ASO) > 0);
732}
sewardjecb94892005-01-21 14:26:37 +0000733
sewardj1001dc42005-02-21 08:25:55 +0000734/* Return True iff pfx has 66 set and F2 and F3 clear */
735static Bool have66noF2noF3 ( Prefix pfx )
736{
737 return
sewardj8d965312005-02-25 02:48:47 +0000738 toBool((pfx & (PFX_66|PFX_F2|PFX_F3)) == PFX_66);
sewardj1001dc42005-02-21 08:25:55 +0000739}
740
741/* Return True iff pfx has F2 set and 66 and F3 clear */
742static Bool haveF2no66noF3 ( Prefix pfx )
743{
744 return
sewardj8d965312005-02-25 02:48:47 +0000745 toBool((pfx & (PFX_66|PFX_F2|PFX_F3)) == PFX_F2);
746}
747
748/* Return True iff pfx has F3 set and 66 and F2 clear */
749static Bool haveF3no66noF2 ( Prefix pfx )
750{
751 return
752 toBool((pfx & (PFX_66|PFX_F2|PFX_F3)) == PFX_F3);
sewardj1001dc42005-02-21 08:25:55 +0000753}
754
755/* Return True iff pfx has 66, F2 and F3 clear */
756static Bool haveNo66noF2noF3 ( Prefix pfx )
757{
758 return
sewardj8d965312005-02-25 02:48:47 +0000759 toBool((pfx & (PFX_66|PFX_F2|PFX_F3)) == 0);
sewardj1001dc42005-02-21 08:25:55 +0000760}
761
sewardj8711f662005-05-09 17:52:56 +0000762/* Return True iff pfx has any of 66, F2 and F3 set */
763static Bool have66orF2orF3 ( Prefix pfx )
764{
sewardjca673ab2005-05-11 10:03:08 +0000765 return toBool( ! haveNo66noF2noF3(pfx) );
sewardj8711f662005-05-09 17:52:56 +0000766}
767
sewardj47c2d4d2006-11-14 17:50:16 +0000768/* Return True iff pfx has 66 or F2 set */
769static Bool have66orF2 ( Prefix pfx )
770{
771 return toBool((pfx & (PFX_66|PFX_F2)) > 0);
772}
773
sewardj1389d4d2005-01-28 13:46:29 +0000774/* Clear all the segment-override bits in a prefix. */
775static Prefix clearSegBits ( Prefix p )
776{
sewardj1001dc42005-02-21 08:25:55 +0000777 return
778 p & ~(PFX_CS | PFX_DS | PFX_ES | PFX_FS | PFX_GS | PFX_SS);
779}
780
sewardj1389d4d2005-01-28 13:46:29 +0000781
sewardjecb94892005-01-21 14:26:37 +0000782/*------------------------------------------------------------*/
sewardj5b470602005-02-27 13:10:48 +0000783/*--- For dealing with integer registers ---*/
sewardjecb94892005-01-21 14:26:37 +0000784/*------------------------------------------------------------*/
785
sewardj5b470602005-02-27 13:10:48 +0000786/* This is somewhat complex. The rules are:
787
788 For 64, 32 and 16 bit register references, the e or g fields in the
789 modrm bytes supply the low 3 bits of the register number. The
790 fourth (most-significant) bit of the register number is supplied by
791 the REX byte, if it is present; else that bit is taken to be zero.
792
793 The REX.R bit supplies the high bit corresponding to the g register
794 field, and the REX.B bit supplies the high bit corresponding to the
795 e register field (when the mod part of modrm indicates that modrm's
796 e component refers to a register and not to memory).
797
798 The REX.X bit supplies a high register bit for certain registers
799 in SIB address modes, and is generally rarely used.
800
801 For 8 bit register references, the presence of the REX byte itself
802 has significance. If there is no REX present, then the 3-bit
803 number extracted from the modrm e or g field is treated as an index
804 into the sequence %al %cl %dl %bl %ah %ch %dh %bh -- that is, the
805 old x86 encoding scheme.
806
807 But if there is a REX present, the register reference is
808 interpreted in the same way as for 64/32/16-bit references: a high
809 bit is extracted from REX, giving a 4-bit number, and the denoted
810 register is the lowest 8 bits of the 16 integer registers denoted
811 by the number. In particular, values 3 through 7 of this sequence
812 do not refer to %ah %ch %dh %bh but instead to the lowest 8 bits of
813 %rsp %rbp %rsi %rdi.
814
815 The REX.W bit has no bearing at all on register numbers. Instead
816 its presence indicates that the operand size is to be overridden
817 from its default value (32 bits) to 64 bits instead. This is in
818 the same fashion that an 0x66 prefix indicates the operand size is
819 to be overridden from 32 bits down to 16 bits. When both REX.W and
820 0x66 are present there is a conflict, and REX.W takes precedence.
821
822 Rather than try to handle this complexity using a single huge
823 function, several smaller ones are provided. The aim is to make it
824 as difficult as possible to screw up register decoding in a subtle
825 and hard-to-track-down way.
826
827 Because these routines fish around in the host's memory (that is,
828 in the guest state area) for sub-parts of guest registers, their
829 correctness depends on the host's endianness. So far these
830 routines only work for little-endian hosts. Those for which
831 endianness is important have assertions to ensure sanity.
832*/
sewardjecb94892005-01-21 14:26:37 +0000833
834
sewardj5b470602005-02-27 13:10:48 +0000835/* About the simplest question you can ask: where do the 64-bit
836 integer registers live (in the guest state) ? */
sewardjecb94892005-01-21 14:26:37 +0000837
sewardj3ca55a12005-01-27 16:06:23 +0000838static Int integerGuestReg64Offset ( UInt reg )
sewardjb3a04292005-01-21 20:33:44 +0000839{
840 switch (reg) {
841 case R_RAX: return OFFB_RAX;
842 case R_RCX: return OFFB_RCX;
843 case R_RDX: return OFFB_RDX;
844 case R_RBX: return OFFB_RBX;
845 case R_RSP: return OFFB_RSP;
846 case R_RBP: return OFFB_RBP;
847 case R_RSI: return OFFB_RSI;
848 case R_RDI: return OFFB_RDI;
849 case R_R8: return OFFB_R8;
850 case R_R9: return OFFB_R9;
851 case R_R10: return OFFB_R10;
852 case R_R11: return OFFB_R11;
853 case R_R12: return OFFB_R12;
854 case R_R13: return OFFB_R13;
855 case R_R14: return OFFB_R14;
856 case R_R15: return OFFB_R15;
857 default: vpanic("integerGuestReg64Offset(amd64)");
858 }
859}
860
861
sewardj5b470602005-02-27 13:10:48 +0000862/* Produce the name of an integer register, for printing purposes.
863 reg is a number in the range 0 .. 15 that has been generated from a
864 3-bit reg-field number and a REX extension bit. irregular denotes
865 the case where sz==1 and no REX byte is present. */
sewardjecb94892005-01-21 14:26:37 +0000866
867static
sewardj5b470602005-02-27 13:10:48 +0000868HChar* nameIReg ( Int sz, UInt reg, Bool irregular )
sewardjecb94892005-01-21 14:26:37 +0000869{
sewardjecb94892005-01-21 14:26:37 +0000870 static HChar* ireg64_names[16]
871 = { "%rax", "%rcx", "%rdx", "%rbx", "%rsp", "%rbp", "%rsi", "%rdi",
872 "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15" };
873 static HChar* ireg32_names[16]
874 = { "%eax", "%ecx", "%edx", "%ebx", "%esp", "%ebp", "%esi", "%edi",
875 "%r8d", "%r9d", "%r10d","%r11d","%r12d","%r13d","%r14d","%r15d" };
876 static HChar* ireg16_names[16]
877 = { "%ax", "%cx", "%dx", "%bx", "%sp", "%bp", "%si", "%di",
878 "%r8w", "%r9w", "%r10w","%r11w","%r12w","%r13w","%r14w","%r15w" };
879 static HChar* ireg8_names[16]
880 = { "%al", "%cl", "%dl", "%bl", "%spl", "%bpl", "%sil", "%dil",
881 "%r8b", "%r9b", "%r10b","%r11b","%r12b","%r13b","%r14b","%r15b" };
sewardj5b470602005-02-27 13:10:48 +0000882 static HChar* ireg8_irregular[8]
sewardjecb94892005-01-21 14:26:37 +0000883 = { "%al", "%cl", "%dl", "%bl", "%ah", "%ch", "%dh", "%bh" };
884
sewardj5b470602005-02-27 13:10:48 +0000885 vassert(reg < 16);
886 if (sz == 1) {
887 if (irregular)
888 vassert(reg < 8);
889 } else {
890 vassert(irregular == False);
891 }
sewardjecb94892005-01-21 14:26:37 +0000892
893 switch (sz) {
sewardj5b470602005-02-27 13:10:48 +0000894 case 8: return ireg64_names[reg];
895 case 4: return ireg32_names[reg];
896 case 2: return ireg16_names[reg];
897 case 1: if (irregular) {
898 return ireg8_irregular[reg];
899 } else {
900 return ireg8_names[reg];
901 }
902 default: vpanic("nameIReg(amd64)");
sewardjecb94892005-01-21 14:26:37 +0000903 }
sewardjecb94892005-01-21 14:26:37 +0000904}
905
sewardj5b470602005-02-27 13:10:48 +0000906/* Using the same argument conventions as nameIReg, produce the
907 guest state offset of an integer register. */
sewardjb3a04292005-01-21 20:33:44 +0000908
sewardjecb94892005-01-21 14:26:37 +0000909static
sewardj5b470602005-02-27 13:10:48 +0000910Int offsetIReg ( Int sz, UInt reg, Bool irregular )
sewardjecb94892005-01-21 14:26:37 +0000911{
sewardj5b470602005-02-27 13:10:48 +0000912 vassert(reg < 16);
913 if (sz == 1) {
914 if (irregular)
915 vassert(reg < 8);
916 } else {
917 vassert(irregular == False);
sewardjecb94892005-01-21 14:26:37 +0000918 }
sewardj5b470602005-02-27 13:10:48 +0000919
920 /* Deal with irregular case -- sz==1 and no REX present */
921 if (sz == 1 && irregular) {
922 switch (reg) {
923 case R_RSP: return 1+ OFFB_RAX;
924 case R_RBP: return 1+ OFFB_RCX;
925 case R_RSI: return 1+ OFFB_RDX;
926 case R_RDI: return 1+ OFFB_RBX;
927 default: break; /* use the normal case */
928 }
sewardjecb94892005-01-21 14:26:37 +0000929 }
sewardj5b470602005-02-27 13:10:48 +0000930
931 /* Normal case */
932 return integerGuestReg64Offset(reg);
sewardjecb94892005-01-21 14:26:37 +0000933}
934
935
sewardj5b470602005-02-27 13:10:48 +0000936/* Read the %CL register :: Ity_I8, for shift/rotate operations. */
937
938static IRExpr* getIRegCL ( void )
939{
940 vassert(!host_is_bigendian);
941 return IRExpr_Get( OFFB_RCX, Ity_I8 );
942}
943
944
945/* Write to the %AH register. */
946
947static void putIRegAH ( IRExpr* e )
948{
949 vassert(!host_is_bigendian);
sewardjdd40fdf2006-12-24 02:20:24 +0000950 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I8);
sewardj5b470602005-02-27 13:10:48 +0000951 stmt( IRStmt_Put( OFFB_RAX+1, e ) );
952}
953
954
955/* Read/write various widths of %RAX, as it has various
956 special-purpose uses. */
957
958static HChar* nameIRegRAX ( Int sz )
959{
960 switch (sz) {
961 case 1: return "%al";
962 case 2: return "%ax";
963 case 4: return "%eax";
964 case 8: return "%rax";
965 default: vpanic("nameIRegRAX(amd64)");
966 }
967}
968
969static IRExpr* getIRegRAX ( Int sz )
970{
971 vassert(!host_is_bigendian);
972 switch (sz) {
973 case 1: return IRExpr_Get( OFFB_RAX, Ity_I8 );
974 case 2: return IRExpr_Get( OFFB_RAX, Ity_I16 );
sewardjef425db2010-01-11 10:46:18 +0000975 case 4: return unop(Iop_64to32, IRExpr_Get( OFFB_RAX, Ity_I64 ));
sewardj5b470602005-02-27 13:10:48 +0000976 case 8: return IRExpr_Get( OFFB_RAX, Ity_I64 );
977 default: vpanic("getIRegRAX(amd64)");
978 }
979}
980
981static void putIRegRAX ( Int sz, IRExpr* e )
982{
sewardjdd40fdf2006-12-24 02:20:24 +0000983 IRType ty = typeOfIRExpr(irsb->tyenv, e);
sewardj5b470602005-02-27 13:10:48 +0000984 vassert(!host_is_bigendian);
985 switch (sz) {
986 case 8: vassert(ty == Ity_I64);
987 stmt( IRStmt_Put( OFFB_RAX, e ));
988 break;
989 case 4: vassert(ty == Ity_I32);
990 stmt( IRStmt_Put( OFFB_RAX, unop(Iop_32Uto64,e) ));
991 break;
992 case 2: vassert(ty == Ity_I16);
993 stmt( IRStmt_Put( OFFB_RAX, e ));
994 break;
995 case 1: vassert(ty == Ity_I8);
996 stmt( IRStmt_Put( OFFB_RAX, e ));
997 break;
998 default: vpanic("putIRegRAX(amd64)");
999 }
1000}
1001
1002
1003/* Read/write various widths of %RDX, as it has various
1004 special-purpose uses. */
1005
sewardjbb4396c2007-11-20 17:29:08 +00001006static HChar* nameIRegRDX ( Int sz )
1007{
1008 switch (sz) {
1009 case 1: return "%dl";
1010 case 2: return "%dx";
1011 case 4: return "%edx";
1012 case 8: return "%rdx";
1013 default: vpanic("nameIRegRDX(amd64)");
1014 }
1015}
1016
sewardj5b470602005-02-27 13:10:48 +00001017static IRExpr* getIRegRDX ( Int sz )
1018{
1019 vassert(!host_is_bigendian);
1020 switch (sz) {
1021 case 1: return IRExpr_Get( OFFB_RDX, Ity_I8 );
1022 case 2: return IRExpr_Get( OFFB_RDX, Ity_I16 );
sewardjef425db2010-01-11 10:46:18 +00001023 case 4: return unop(Iop_64to32, IRExpr_Get( OFFB_RDX, Ity_I64 ));
sewardj5b470602005-02-27 13:10:48 +00001024 case 8: return IRExpr_Get( OFFB_RDX, Ity_I64 );
1025 default: vpanic("getIRegRDX(amd64)");
1026 }
1027}
1028
1029static void putIRegRDX ( Int sz, IRExpr* e )
1030{
1031 vassert(!host_is_bigendian);
sewardjdd40fdf2006-12-24 02:20:24 +00001032 vassert(typeOfIRExpr(irsb->tyenv, e) == szToITy(sz));
sewardj5b470602005-02-27 13:10:48 +00001033 switch (sz) {
1034 case 8: stmt( IRStmt_Put( OFFB_RDX, e ));
1035 break;
1036 case 4: stmt( IRStmt_Put( OFFB_RDX, unop(Iop_32Uto64,e) ));
1037 break;
1038 case 2: stmt( IRStmt_Put( OFFB_RDX, e ));
1039 break;
1040 case 1: stmt( IRStmt_Put( OFFB_RDX, e ));
1041 break;
1042 default: vpanic("putIRegRDX(amd64)");
1043 }
1044}
1045
1046
1047/* Simplistic functions to deal with the integer registers as a
1048 straightforward bank of 16 64-bit regs. */
sewardjb3a04292005-01-21 20:33:44 +00001049
1050static IRExpr* getIReg64 ( UInt regno )
1051{
1052 return IRExpr_Get( integerGuestReg64Offset(regno),
1053 Ity_I64 );
1054}
1055
sewardj2f959cc2005-01-26 01:19:35 +00001056static void putIReg64 ( UInt regno, IRExpr* e )
1057{
sewardjdd40fdf2006-12-24 02:20:24 +00001058 vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_I64);
sewardj2f959cc2005-01-26 01:19:35 +00001059 stmt( IRStmt_Put( integerGuestReg64Offset(regno), e ) );
1060}
1061
sewardjb3a04292005-01-21 20:33:44 +00001062static HChar* nameIReg64 ( UInt regno )
1063{
sewardj5b470602005-02-27 13:10:48 +00001064 return nameIReg( 8, regno, False );
sewardjb3a04292005-01-21 20:33:44 +00001065}
sewardj5b470602005-02-27 13:10:48 +00001066
1067
1068/* Simplistic functions to deal with the lower halves of integer
1069 registers as a straightforward bank of 16 32-bit regs. */
1070
1071static IRExpr* getIReg32 ( UInt regno )
1072{
1073 vassert(!host_is_bigendian);
sewardjef425db2010-01-11 10:46:18 +00001074 return unop(Iop_64to32,
1075 IRExpr_Get( integerGuestReg64Offset(regno),
1076 Ity_I64 ));
sewardj5b470602005-02-27 13:10:48 +00001077}
1078
1079static void putIReg32 ( UInt regno, IRExpr* e )
1080{
sewardjdd40fdf2006-12-24 02:20:24 +00001081 vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_I32);
sewardj5b470602005-02-27 13:10:48 +00001082 stmt( IRStmt_Put( integerGuestReg64Offset(regno),
1083 unop(Iop_32Uto64,e) ) );
1084}
1085
1086static HChar* nameIReg32 ( UInt regno )
1087{
1088 return nameIReg( 4, regno, False );
1089}
1090
1091
sewardja7ba8c42005-05-10 20:08:34 +00001092/* Simplistic functions to deal with the lower quarters of integer
1093 registers as a straightforward bank of 16 16-bit regs. */
1094
1095static IRExpr* getIReg16 ( UInt regno )
1096{
1097 vassert(!host_is_bigendian);
1098 return IRExpr_Get( integerGuestReg64Offset(regno),
1099 Ity_I16 );
1100}
1101
1102static HChar* nameIReg16 ( UInt regno )
1103{
1104 return nameIReg( 2, regno, False );
1105}
1106
1107
sewardj5b470602005-02-27 13:10:48 +00001108/* Sometimes what we know is a 3-bit register number, a REX byte, and
1109 which field of the REX byte is to be used to extend to a 4-bit
1110 number. These functions cater for that situation.
1111*/
1112static IRExpr* getIReg64rexX ( Prefix pfx, UInt lo3bits )
1113{
1114 vassert(lo3bits < 8);
1115 vassert(IS_VALID_PFX(pfx));
1116 return getIReg64( lo3bits | (getRexX(pfx) << 3) );
1117}
1118
1119static HChar* nameIReg64rexX ( Prefix pfx, UInt lo3bits )
1120{
1121 vassert(lo3bits < 8);
1122 vassert(IS_VALID_PFX(pfx));
1123 return nameIReg( 8, lo3bits | (getRexX(pfx) << 3), False );
1124}
1125
1126static HChar* nameIRegRexB ( Int sz, Prefix pfx, UInt lo3bits )
1127{
1128 vassert(lo3bits < 8);
1129 vassert(IS_VALID_PFX(pfx));
1130 vassert(sz == 8 || sz == 4 || sz == 2 || sz == 1);
1131 return nameIReg( sz, lo3bits | (getRexB(pfx) << 3),
sewardj397f88b2005-02-27 13:39:25 +00001132 toBool(sz==1 && !haveREX(pfx)) );
sewardj5b470602005-02-27 13:10:48 +00001133}
1134
1135static IRExpr* getIRegRexB ( Int sz, Prefix pfx, UInt lo3bits )
1136{
1137 vassert(lo3bits < 8);
1138 vassert(IS_VALID_PFX(pfx));
1139 vassert(sz == 8 || sz == 4 || sz == 2 || sz == 1);
sewardjef425db2010-01-11 10:46:18 +00001140 if (sz == 4) {
1141 sz = 8;
1142 return unop(Iop_64to32,
1143 IRExpr_Get(
1144 offsetIReg( sz, lo3bits | (getRexB(pfx) << 3),
1145 toBool(sz==1 && !haveREX(pfx)) ),
1146 szToITy(sz)
1147 )
1148 );
1149 } else {
1150 return IRExpr_Get(
1151 offsetIReg( sz, lo3bits | (getRexB(pfx) << 3),
1152 toBool(sz==1 && !haveREX(pfx)) ),
1153 szToITy(sz)
1154 );
1155 }
sewardj5b470602005-02-27 13:10:48 +00001156}
1157
1158static void putIRegRexB ( Int sz, Prefix pfx, UInt lo3bits, IRExpr* e )
1159{
1160 vassert(lo3bits < 8);
1161 vassert(IS_VALID_PFX(pfx));
sewardj98e9f342005-07-23 12:07:37 +00001162 vassert(sz == 8 || sz == 4 || sz == 2 || sz == 1);
sewardjdd40fdf2006-12-24 02:20:24 +00001163 vassert(typeOfIRExpr(irsb->tyenv, e) == szToITy(sz));
sewardj5b470602005-02-27 13:10:48 +00001164 stmt( IRStmt_Put(
1165 offsetIReg( sz, lo3bits | (getRexB(pfx) << 3),
sewardj397f88b2005-02-27 13:39:25 +00001166 toBool(sz==1 && !haveREX(pfx)) ),
sewardj5b470602005-02-27 13:10:48 +00001167 sz==4 ? unop(Iop_32Uto64,e) : e
1168 ));
1169}
1170
1171
1172/* Functions for getting register numbers from modrm bytes and REX
1173 when we don't have to consider the complexities of integer subreg
1174 accesses.
1175*/
1176/* Extract the g reg field from a modRM byte, and augment it using the
1177 REX.R bit from the supplied REX byte. The R bit usually is
1178 associated with the g register field.
1179*/
1180static UInt gregOfRexRM ( Prefix pfx, UChar mod_reg_rm )
1181{
1182 Int reg = (Int)( (mod_reg_rm >> 3) & 7 );
1183 reg += (pfx & PFX_REXR) ? 8 : 0;
1184 return reg;
1185}
1186
1187/* Extract the e reg field from a modRM byte, and augment it using the
1188 REX.B bit from the supplied REX byte. The B bit usually is
1189 associated with the e register field (when modrm indicates e is a
1190 register, that is).
1191*/
1192static UInt eregOfRexRM ( Prefix pfx, UChar mod_reg_rm )
1193{
1194 Int rm;
1195 vassert(epartIsReg(mod_reg_rm));
1196 rm = (Int)(mod_reg_rm & 0x7);
1197 rm += (pfx & PFX_REXB) ? 8 : 0;
1198 return rm;
1199}
1200
1201
1202/* General functions for dealing with integer register access. */
1203
1204/* Produce the guest state offset for a reference to the 'g' register
1205 field in a modrm byte, taking into account REX (or its absence),
1206 and the size of the access.
1207*/
1208static UInt offsetIRegG ( Int sz, Prefix pfx, UChar mod_reg_rm )
1209{
1210 UInt reg;
1211 vassert(!host_is_bigendian);
1212 vassert(IS_VALID_PFX(pfx));
1213 vassert(sz == 8 || sz == 4 || sz == 2 || sz == 1);
1214 reg = gregOfRexRM( pfx, mod_reg_rm );
sewardj397f88b2005-02-27 13:39:25 +00001215 return offsetIReg( sz, reg, toBool(sz == 1 && !haveREX(pfx)) );
sewardj5b470602005-02-27 13:10:48 +00001216}
1217
1218static
1219IRExpr* getIRegG ( Int sz, Prefix pfx, UChar mod_reg_rm )
1220{
sewardjef425db2010-01-11 10:46:18 +00001221 if (sz == 4) {
1222 sz = 8;
1223 return unop(Iop_64to32,
1224 IRExpr_Get( offsetIRegG( sz, pfx, mod_reg_rm ),
1225 szToITy(sz) ));
1226 } else {
1227 return IRExpr_Get( offsetIRegG( sz, pfx, mod_reg_rm ),
1228 szToITy(sz) );
1229 }
sewardj5b470602005-02-27 13:10:48 +00001230}
1231
1232static
1233void putIRegG ( Int sz, Prefix pfx, UChar mod_reg_rm, IRExpr* e )
1234{
sewardjdd40fdf2006-12-24 02:20:24 +00001235 vassert(typeOfIRExpr(irsb->tyenv,e) == szToITy(sz));
sewardj5b470602005-02-27 13:10:48 +00001236 if (sz == 4) {
1237 e = unop(Iop_32Uto64,e);
1238 }
1239 stmt( IRStmt_Put( offsetIRegG( sz, pfx, mod_reg_rm ), e ) );
1240}
1241
1242static
1243HChar* nameIRegG ( Int sz, Prefix pfx, UChar mod_reg_rm )
1244{
1245 return nameIReg( sz, gregOfRexRM(pfx,mod_reg_rm),
sewardj397f88b2005-02-27 13:39:25 +00001246 toBool(sz==1 && !haveREX(pfx)) );
sewardj5b470602005-02-27 13:10:48 +00001247}
1248
1249
1250/* Produce the guest state offset for a reference to the 'e' register
1251 field in a modrm byte, taking into account REX (or its absence),
1252 and the size of the access. eregOfRexRM will assert if mod_reg_rm
1253 denotes a memory access rather than a register access.
1254*/
1255static UInt offsetIRegE ( Int sz, Prefix pfx, UChar mod_reg_rm )
1256{
1257 UInt reg;
1258 vassert(!host_is_bigendian);
1259 vassert(IS_VALID_PFX(pfx));
1260 vassert(sz == 8 || sz == 4 || sz == 2 || sz == 1);
1261 reg = eregOfRexRM( pfx, mod_reg_rm );
sewardj397f88b2005-02-27 13:39:25 +00001262 return offsetIReg( sz, reg, toBool(sz == 1 && !haveREX(pfx)) );
sewardj5b470602005-02-27 13:10:48 +00001263}
1264
1265static
1266IRExpr* getIRegE ( Int sz, Prefix pfx, UChar mod_reg_rm )
1267{
sewardjef425db2010-01-11 10:46:18 +00001268 if (sz == 4) {
1269 sz = 8;
1270 return unop(Iop_64to32,
1271 IRExpr_Get( offsetIRegE( sz, pfx, mod_reg_rm ),
1272 szToITy(sz) ));
1273 } else {
1274 return IRExpr_Get( offsetIRegE( sz, pfx, mod_reg_rm ),
1275 szToITy(sz) );
1276 }
sewardj5b470602005-02-27 13:10:48 +00001277}
1278
1279static
1280void putIRegE ( Int sz, Prefix pfx, UChar mod_reg_rm, IRExpr* e )
1281{
sewardjdd40fdf2006-12-24 02:20:24 +00001282 vassert(typeOfIRExpr(irsb->tyenv,e) == szToITy(sz));
sewardj5b470602005-02-27 13:10:48 +00001283 if (sz == 4) {
1284 e = unop(Iop_32Uto64,e);
1285 }
1286 stmt( IRStmt_Put( offsetIRegE( sz, pfx, mod_reg_rm ), e ) );
1287}
1288
1289static
1290HChar* nameIRegE ( Int sz, Prefix pfx, UChar mod_reg_rm )
1291{
1292 return nameIReg( sz, eregOfRexRM(pfx,mod_reg_rm),
sewardj397f88b2005-02-27 13:39:25 +00001293 toBool(sz==1 && !haveREX(pfx)) );
sewardj5b470602005-02-27 13:10:48 +00001294}
1295
1296
1297/*------------------------------------------------------------*/
1298/*--- For dealing with XMM registers ---*/
1299/*------------------------------------------------------------*/
sewardjecb94892005-01-21 14:26:37 +00001300
sewardjd20c8852005-01-20 20:04:07 +00001301//.. static Int segmentGuestRegOffset ( UInt sreg )
1302//.. {
1303//.. switch (sreg) {
1304//.. case R_ES: return OFFB_ES;
1305//.. case R_CS: return OFFB_CS;
1306//.. case R_SS: return OFFB_SS;
1307//.. case R_DS: return OFFB_DS;
1308//.. case R_FS: return OFFB_FS;
1309//.. case R_GS: return OFFB_GS;
1310//.. default: vpanic("segmentGuestRegOffset(x86)");
1311//.. }
1312//.. }
sewardj1001dc42005-02-21 08:25:55 +00001313
1314static Int xmmGuestRegOffset ( UInt xmmreg )
1315{
1316 switch (xmmreg) {
1317 case 0: return OFFB_XMM0;
1318 case 1: return OFFB_XMM1;
1319 case 2: return OFFB_XMM2;
1320 case 3: return OFFB_XMM3;
1321 case 4: return OFFB_XMM4;
1322 case 5: return OFFB_XMM5;
1323 case 6: return OFFB_XMM6;
1324 case 7: return OFFB_XMM7;
1325 case 8: return OFFB_XMM8;
1326 case 9: return OFFB_XMM9;
1327 case 10: return OFFB_XMM10;
1328 case 11: return OFFB_XMM11;
1329 case 12: return OFFB_XMM12;
1330 case 13: return OFFB_XMM13;
1331 case 14: return OFFB_XMM14;
1332 case 15: return OFFB_XMM15;
1333 default: vpanic("xmmGuestRegOffset(amd64)");
1334 }
1335}
1336
sewardj97628592005-05-10 22:42:54 +00001337/* Lanes of vector registers are always numbered from zero being the
1338 least significant lane (rightmost in the register). */
1339
1340static Int xmmGuestRegLane16offset ( UInt xmmreg, Int laneno )
1341{
1342 /* Correct for little-endian host only. */
1343 vassert(!host_is_bigendian);
1344 vassert(laneno >= 0 && laneno < 8);
1345 return xmmGuestRegOffset( xmmreg ) + 2 * laneno;
1346}
sewardj8d965312005-02-25 02:48:47 +00001347
1348static Int xmmGuestRegLane32offset ( UInt xmmreg, Int laneno )
1349{
1350 /* Correct for little-endian host only. */
1351 vassert(!host_is_bigendian);
1352 vassert(laneno >= 0 && laneno < 4);
1353 return xmmGuestRegOffset( xmmreg ) + 4 * laneno;
1354}
sewardj1001dc42005-02-21 08:25:55 +00001355
1356static Int xmmGuestRegLane64offset ( UInt xmmreg, Int laneno )
1357{
1358 /* Correct for little-endian host only. */
1359 vassert(!host_is_bigendian);
1360 vassert(laneno >= 0 && laneno < 2);
1361 return xmmGuestRegOffset( xmmreg ) + 8 * laneno;
1362}
1363
sewardjd20c8852005-01-20 20:04:07 +00001364//.. static IRExpr* getSReg ( UInt sreg )
1365//.. {
1366//.. return IRExpr_Get( segmentGuestRegOffset(sreg), Ity_I16 );
1367//.. }
1368//..
1369//.. static void putSReg ( UInt sreg, IRExpr* e )
1370//.. {
sewardjdd40fdf2006-12-24 02:20:24 +00001371//.. vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_I16);
sewardjd20c8852005-01-20 20:04:07 +00001372//.. stmt( IRStmt_Put( segmentGuestRegOffset(sreg), e ) );
1373//.. }
sewardj1001dc42005-02-21 08:25:55 +00001374
1375static IRExpr* getXMMReg ( UInt xmmreg )
1376{
1377 return IRExpr_Get( xmmGuestRegOffset(xmmreg), Ity_V128 );
1378}
1379
1380static IRExpr* getXMMRegLane64 ( UInt xmmreg, Int laneno )
1381{
1382 return IRExpr_Get( xmmGuestRegLane64offset(xmmreg,laneno), Ity_I64 );
1383}
1384
sewardj18303862005-02-21 12:36:54 +00001385static IRExpr* getXMMRegLane64F ( UInt xmmreg, Int laneno )
1386{
1387 return IRExpr_Get( xmmGuestRegLane64offset(xmmreg,laneno), Ity_F64 );
1388}
1389
sewardj8d965312005-02-25 02:48:47 +00001390static IRExpr* getXMMRegLane32 ( UInt xmmreg, Int laneno )
1391{
1392 return IRExpr_Get( xmmGuestRegLane32offset(xmmreg,laneno), Ity_I32 );
1393}
1394
sewardjc49ce232005-02-25 13:03:03 +00001395static IRExpr* getXMMRegLane32F ( UInt xmmreg, Int laneno )
1396{
1397 return IRExpr_Get( xmmGuestRegLane32offset(xmmreg,laneno), Ity_F32 );
1398}
sewardj1001dc42005-02-21 08:25:55 +00001399
de5a70f5c2010-04-01 23:08:59 +00001400static IRExpr* getXMMRegLane16 ( UInt xmmreg, Int laneno )
1401{
1402 return IRExpr_Get( xmmGuestRegLane16offset(xmmreg,laneno), Ity_I16 );
1403}
1404
sewardj1001dc42005-02-21 08:25:55 +00001405static void putXMMReg ( UInt xmmreg, IRExpr* e )
1406{
sewardjdd40fdf2006-12-24 02:20:24 +00001407 vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_V128);
sewardj1001dc42005-02-21 08:25:55 +00001408 stmt( IRStmt_Put( xmmGuestRegOffset(xmmreg), e ) );
1409}
1410
1411static void putXMMRegLane64 ( UInt xmmreg, Int laneno, IRExpr* e )
1412{
sewardjdd40fdf2006-12-24 02:20:24 +00001413 vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_I64);
sewardj1001dc42005-02-21 08:25:55 +00001414 stmt( IRStmt_Put( xmmGuestRegLane64offset(xmmreg,laneno), e ) );
1415}
1416
sewardj1a01e652005-02-23 11:39:21 +00001417static void putXMMRegLane64F ( UInt xmmreg, Int laneno, IRExpr* e )
1418{
sewardjdd40fdf2006-12-24 02:20:24 +00001419 vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_F64);
sewardj1a01e652005-02-23 11:39:21 +00001420 stmt( IRStmt_Put( xmmGuestRegLane64offset(xmmreg,laneno), e ) );
1421}
1422
sewardj8d965312005-02-25 02:48:47 +00001423static void putXMMRegLane32F ( UInt xmmreg, Int laneno, IRExpr* e )
1424{
sewardjdd40fdf2006-12-24 02:20:24 +00001425 vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_F32);
sewardj8d965312005-02-25 02:48:47 +00001426 stmt( IRStmt_Put( xmmGuestRegLane32offset(xmmreg,laneno), e ) );
1427}
1428
1429static void putXMMRegLane32 ( UInt xmmreg, Int laneno, IRExpr* e )
1430{
sewardjdd40fdf2006-12-24 02:20:24 +00001431 vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_I32);
sewardj8d965312005-02-25 02:48:47 +00001432 stmt( IRStmt_Put( xmmGuestRegLane32offset(xmmreg,laneno), e ) );
1433}
1434
sewardj97628592005-05-10 22:42:54 +00001435static void putXMMRegLane16 ( UInt xmmreg, Int laneno, IRExpr* e )
1436{
sewardjdd40fdf2006-12-24 02:20:24 +00001437 vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_I16);
sewardj97628592005-05-10 22:42:54 +00001438 stmt( IRStmt_Put( xmmGuestRegLane16offset(xmmreg,laneno), e ) );
1439}
sewardj3ca55a12005-01-27 16:06:23 +00001440
sewardj1001dc42005-02-21 08:25:55 +00001441static IRExpr* mkV128 ( UShort mask )
1442{
1443 return IRExpr_Const(IRConst_V128(mask));
1444}
sewardjdf0e0022005-01-25 15:48:43 +00001445
sewardje8f65252005-08-23 23:44:35 +00001446static IRExpr* mkAnd1 ( IRExpr* x, IRExpr* y )
1447{
sewardjdd40fdf2006-12-24 02:20:24 +00001448 vassert(typeOfIRExpr(irsb->tyenv,x) == Ity_I1);
1449 vassert(typeOfIRExpr(irsb->tyenv,y) == Ity_I1);
sewardje8f65252005-08-23 23:44:35 +00001450 return unop(Iop_64to1,
1451 binop(Iop_And64,
1452 unop(Iop_1Uto64,x),
1453 unop(Iop_1Uto64,y)));
1454}
1455
sewardje9d8a262009-07-01 08:06:34 +00001456/* Generate a compare-and-swap operation, operating on memory at
1457 'addr'. The expected value is 'expVal' and the new value is
1458 'newVal'. If the operation fails, then transfer control (with a
1459 no-redir jump (XXX no -- see comment at top of this file)) to
1460 'restart_point', which is presumably the address of the guest
1461 instruction again -- retrying, essentially. */
1462static void casLE ( IRExpr* addr, IRExpr* expVal, IRExpr* newVal,
1463 Addr64 restart_point )
1464{
1465 IRCAS* cas;
1466 IRType tyE = typeOfIRExpr(irsb->tyenv, expVal);
1467 IRType tyN = typeOfIRExpr(irsb->tyenv, newVal);
1468 IRTemp oldTmp = newTemp(tyE);
1469 IRTemp expTmp = newTemp(tyE);
1470 vassert(tyE == tyN);
1471 vassert(tyE == Ity_I64 || tyE == Ity_I32
1472 || tyE == Ity_I16 || tyE == Ity_I8);
1473 assign(expTmp, expVal);
1474 cas = mkIRCAS( IRTemp_INVALID, oldTmp, Iend_LE, addr,
1475 NULL, mkexpr(expTmp), NULL, newVal );
1476 stmt( IRStmt_CAS(cas) );
1477 stmt( IRStmt_Exit(
sewardj1fb8c922009-07-12 12:56:53 +00001478 binop( mkSizedOp(tyE,Iop_CasCmpNE8),
1479 mkexpr(oldTmp), mkexpr(expTmp) ),
sewardje9d8a262009-07-01 08:06:34 +00001480 Ijk_Boring, /*Ijk_NoRedir*/
1481 IRConst_U64( restart_point )
1482 ));
1483}
1484
sewardj5b470602005-02-27 13:10:48 +00001485
sewardj118b23e2005-01-29 02:14:44 +00001486/*------------------------------------------------------------*/
sewardje8f65252005-08-23 23:44:35 +00001487/*--- Helpers for %rflags. ---*/
sewardj118b23e2005-01-29 02:14:44 +00001488/*------------------------------------------------------------*/
1489
1490/* -------------- Evaluating the flags-thunk. -------------- */
1491
1492/* Build IR to calculate all the eflags from stored
1493 CC_OP/CC_DEP1/CC_DEP2/CC_NDEP. Returns an expression ::
1494 Ity_I64. */
1495static IRExpr* mk_amd64g_calculate_rflags_all ( void )
1496{
1497 IRExpr** args
1498 = mkIRExprVec_4( IRExpr_Get(OFFB_CC_OP, Ity_I64),
1499 IRExpr_Get(OFFB_CC_DEP1, Ity_I64),
1500 IRExpr_Get(OFFB_CC_DEP2, Ity_I64),
1501 IRExpr_Get(OFFB_CC_NDEP, Ity_I64) );
1502 IRExpr* call
1503 = mkIRExprCCall(
1504 Ity_I64,
1505 0/*regparm*/,
1506 "amd64g_calculate_rflags_all", &amd64g_calculate_rflags_all,
1507 args
1508 );
1509 /* Exclude OP and NDEP from definedness checking. We're only
1510 interested in DEP1 and DEP2. */
1511 call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<3);
1512 return call;
1513}
sewardj3ca55a12005-01-27 16:06:23 +00001514
1515/* Build IR to calculate some particular condition from stored
1516 CC_OP/CC_DEP1/CC_DEP2/CC_NDEP. Returns an expression ::
1517 Ity_Bit. */
1518static IRExpr* mk_amd64g_calculate_condition ( AMD64Condcode cond )
1519{
1520 IRExpr** args
1521 = mkIRExprVec_5( mkU64(cond),
1522 IRExpr_Get(OFFB_CC_OP, Ity_I64),
1523 IRExpr_Get(OFFB_CC_DEP1, Ity_I64),
1524 IRExpr_Get(OFFB_CC_DEP2, Ity_I64),
1525 IRExpr_Get(OFFB_CC_NDEP, Ity_I64) );
1526 IRExpr* call
1527 = mkIRExprCCall(
1528 Ity_I64,
1529 0/*regparm*/,
1530 "amd64g_calculate_condition", &amd64g_calculate_condition,
1531 args
1532 );
1533 /* Exclude the requested condition, OP and NDEP from definedness
1534 checking. We're only interested in DEP1 and DEP2. */
1535 call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<1) | (1<<4);
sewardje58967e2005-04-27 11:50:56 +00001536 return unop(Iop_64to1, call);
sewardj3ca55a12005-01-27 16:06:23 +00001537}
sewardjdf0e0022005-01-25 15:48:43 +00001538
1539/* Build IR to calculate just the carry flag from stored
1540 CC_OP/CC_DEP1/CC_DEP2/CC_NDEP. Returns an expression :: Ity_I64. */
1541static IRExpr* mk_amd64g_calculate_rflags_c ( void )
1542{
1543 IRExpr** args
1544 = mkIRExprVec_4( IRExpr_Get(OFFB_CC_OP, Ity_I64),
1545 IRExpr_Get(OFFB_CC_DEP1, Ity_I64),
1546 IRExpr_Get(OFFB_CC_DEP2, Ity_I64),
1547 IRExpr_Get(OFFB_CC_NDEP, Ity_I64) );
1548 IRExpr* call
1549 = mkIRExprCCall(
1550 Ity_I64,
1551 0/*regparm*/,
1552 "amd64g_calculate_rflags_c", &amd64g_calculate_rflags_c,
1553 args
1554 );
1555 /* Exclude OP and NDEP from definedness checking. We're only
1556 interested in DEP1 and DEP2. */
1557 call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<3);
1558 return call;
1559}
1560
1561
1562/* -------------- Building the flags-thunk. -------------- */
1563
1564/* The machinery in this section builds the flag-thunk following a
1565 flag-setting operation. Hence the various setFlags_* functions.
1566*/
1567
1568static Bool isAddSub ( IROp op8 )
1569{
sewardj7a240552005-01-28 21:37:12 +00001570 return toBool(op8 == Iop_Add8 || op8 == Iop_Sub8);
sewardjdf0e0022005-01-25 15:48:43 +00001571}
1572
sewardj3ca55a12005-01-27 16:06:23 +00001573static Bool isLogic ( IROp op8 )
1574{
sewardj7a240552005-01-28 21:37:12 +00001575 return toBool(op8 == Iop_And8 || op8 == Iop_Or8 || op8 == Iop_Xor8);
sewardj3ca55a12005-01-27 16:06:23 +00001576}
sewardjdf0e0022005-01-25 15:48:43 +00001577
1578/* U-widen 8/16/32/64 bit int expr to 64. */
1579static IRExpr* widenUto64 ( IRExpr* e )
1580{
sewardjdd40fdf2006-12-24 02:20:24 +00001581 switch (typeOfIRExpr(irsb->tyenv,e)) {
sewardjdf0e0022005-01-25 15:48:43 +00001582 case Ity_I64: return e;
1583 case Ity_I32: return unop(Iop_32Uto64, e);
sewardje58967e2005-04-27 11:50:56 +00001584 case Ity_I16: return unop(Iop_16Uto64, e);
1585 case Ity_I8: return unop(Iop_8Uto64, e);
sewardj118b23e2005-01-29 02:14:44 +00001586 default: vpanic("widenUto64");
sewardjdf0e0022005-01-25 15:48:43 +00001587 }
1588}
1589
sewardj118b23e2005-01-29 02:14:44 +00001590/* S-widen 8/16/32/64 bit int expr to 32. */
1591static IRExpr* widenSto64 ( IRExpr* e )
1592{
sewardjdd40fdf2006-12-24 02:20:24 +00001593 switch (typeOfIRExpr(irsb->tyenv,e)) {
sewardj118b23e2005-01-29 02:14:44 +00001594 case Ity_I64: return e;
1595 case Ity_I32: return unop(Iop_32Sto64, e);
sewardje58967e2005-04-27 11:50:56 +00001596 case Ity_I16: return unop(Iop_16Sto64, e);
1597 case Ity_I8: return unop(Iop_8Sto64, e);
sewardj118b23e2005-01-29 02:14:44 +00001598 default: vpanic("widenSto64");
1599 }
1600}
sewardjdf0e0022005-01-25 15:48:43 +00001601
1602/* Narrow 8/16/32/64 bit int expr to 8/16/32/64. Clearly only some
1603 of these combinations make sense. */
1604static IRExpr* narrowTo ( IRType dst_ty, IRExpr* e )
1605{
sewardjdd40fdf2006-12-24 02:20:24 +00001606 IRType src_ty = typeOfIRExpr(irsb->tyenv,e);
sewardjdf0e0022005-01-25 15:48:43 +00001607 if (src_ty == dst_ty)
1608 return e;
1609 if (src_ty == Ity_I32 && dst_ty == Ity_I16)
1610 return unop(Iop_32to16, e);
1611 if (src_ty == Ity_I32 && dst_ty == Ity_I8)
1612 return unop(Iop_32to8, e);
sewardj118b23e2005-01-29 02:14:44 +00001613 if (src_ty == Ity_I64 && dst_ty == Ity_I32)
1614 return unop(Iop_64to32, e);
1615 if (src_ty == Ity_I64 && dst_ty == Ity_I16)
sewardje58967e2005-04-27 11:50:56 +00001616 return unop(Iop_64to16, e);
sewardj03b07cc2005-01-31 18:09:43 +00001617 if (src_ty == Ity_I64 && dst_ty == Ity_I8)
sewardje58967e2005-04-27 11:50:56 +00001618 return unop(Iop_64to8, e);
sewardjdf0e0022005-01-25 15:48:43 +00001619
1620 vex_printf("\nsrc, dst tys are: ");
1621 ppIRType(src_ty);
1622 vex_printf(", ");
1623 ppIRType(dst_ty);
1624 vex_printf("\n");
1625 vpanic("narrowTo(amd64)");
1626}
1627
1628
1629/* Set the flags thunk OP, DEP1 and DEP2 fields. The supplied op is
1630 auto-sized up to the real op. */
1631
1632static
1633void setFlags_DEP1_DEP2 ( IROp op8, IRTemp dep1, IRTemp dep2, IRType ty )
1634{
1635 Int ccOp = 0;
1636 switch (ty) {
1637 case Ity_I8: ccOp = 0; break;
1638 case Ity_I16: ccOp = 1; break;
1639 case Ity_I32: ccOp = 2; break;
1640 case Ity_I64: ccOp = 3; break;
1641 default: vassert(0);
1642 }
1643 switch (op8) {
1644 case Iop_Add8: ccOp += AMD64G_CC_OP_ADDB; break;
1645 case Iop_Sub8: ccOp += AMD64G_CC_OP_SUBB; break;
1646 default: ppIROp(op8);
1647 vpanic("setFlags_DEP1_DEP2(amd64)");
1648 }
1649 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(ccOp)) );
1650 stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto64(mkexpr(dep1))) );
1651 stmt( IRStmt_Put( OFFB_CC_DEP2, widenUto64(mkexpr(dep2))) );
1652}
1653
1654
1655/* Set the OP and DEP1 fields only, and write zero to DEP2. */
1656
1657static
1658void setFlags_DEP1 ( IROp op8, IRTemp dep1, IRType ty )
1659{
1660 Int ccOp = 0;
1661 switch (ty) {
1662 case Ity_I8: ccOp = 0; break;
1663 case Ity_I16: ccOp = 1; break;
1664 case Ity_I32: ccOp = 2; break;
1665 case Ity_I64: ccOp = 3; break;
1666 default: vassert(0);
1667 }
1668 switch (op8) {
1669 case Iop_Or8:
1670 case Iop_And8:
1671 case Iop_Xor8: ccOp += AMD64G_CC_OP_LOGICB; break;
1672 default: ppIROp(op8);
1673 vpanic("setFlags_DEP1(amd64)");
1674 }
1675 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(ccOp)) );
1676 stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto64(mkexpr(dep1))) );
1677 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0)) );
1678}
1679
1680
sewardj118b23e2005-01-29 02:14:44 +00001681/* For shift operations, we put in the result and the undershifted
1682 result. Except if the shift amount is zero, the thunk is left
1683 unchanged. */
1684
1685static void setFlags_DEP1_DEP2_shift ( IROp op64,
1686 IRTemp res,
1687 IRTemp resUS,
1688 IRType ty,
1689 IRTemp guard )
1690{
1691 Int ccOp = 0;
1692 switch (ty) {
1693 case Ity_I8: ccOp = 0; break;
1694 case Ity_I16: ccOp = 1; break;
1695 case Ity_I32: ccOp = 2; break;
1696 case Ity_I64: ccOp = 3; break;
1697 default: vassert(0);
1698 }
1699
1700 vassert(guard);
1701
1702 /* Both kinds of right shifts are handled by the same thunk
1703 operation. */
1704 switch (op64) {
1705 case Iop_Shr64:
1706 case Iop_Sar64: ccOp += AMD64G_CC_OP_SHRB; break;
1707 case Iop_Shl64: ccOp += AMD64G_CC_OP_SHLB; break;
1708 default: ppIROp(op64);
1709 vpanic("setFlags_DEP1_DEP2_shift(amd64)");
1710 }
1711
1712 /* DEP1 contains the result, DEP2 contains the undershifted value. */
1713 stmt( IRStmt_Put( OFFB_CC_OP,
1714 IRExpr_Mux0X( mkexpr(guard),
1715 IRExpr_Get(OFFB_CC_OP,Ity_I64),
1716 mkU64(ccOp))) );
1717 stmt( IRStmt_Put( OFFB_CC_DEP1,
1718 IRExpr_Mux0X( mkexpr(guard),
1719 IRExpr_Get(OFFB_CC_DEP1,Ity_I64),
1720 widenUto64(mkexpr(res)))) );
1721 stmt( IRStmt_Put( OFFB_CC_DEP2,
1722 IRExpr_Mux0X( mkexpr(guard),
1723 IRExpr_Get(OFFB_CC_DEP2,Ity_I64),
1724 widenUto64(mkexpr(resUS)))) );
1725}
sewardj354e5c62005-01-27 20:12:52 +00001726
1727
1728/* For the inc/dec case, we store in DEP1 the result value and in NDEP
1729 the former value of the carry flag, which unfortunately we have to
1730 compute. */
1731
1732static void setFlags_INC_DEC ( Bool inc, IRTemp res, IRType ty )
1733{
1734 Int ccOp = inc ? AMD64G_CC_OP_INCB : AMD64G_CC_OP_DECB;
1735
1736 switch (ty) {
1737 case Ity_I8: ccOp += 0; break;
1738 case Ity_I16: ccOp += 1; break;
1739 case Ity_I32: ccOp += 2; break;
1740 case Ity_I64: ccOp += 3; break;
1741 default: vassert(0);
1742 }
1743
1744 /* This has to come first, because calculating the C flag
1745 may require reading all four thunk fields. */
1746 stmt( IRStmt_Put( OFFB_CC_NDEP, mk_amd64g_calculate_rflags_c()) );
1747 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(ccOp)) );
sewardj478646f2008-05-01 20:13:04 +00001748 stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto64(mkexpr(res))) );
sewardj354e5c62005-01-27 20:12:52 +00001749 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0)) );
1750}
1751
1752
sewardj32b2bbe2005-01-28 00:50:10 +00001753/* Multiplies are pretty much like add and sub: DEP1 and DEP2 hold the
1754 two arguments. */
1755
1756static
1757void setFlags_MUL ( IRType ty, IRTemp arg1, IRTemp arg2, ULong base_op )
1758{
1759 switch (ty) {
1760 case Ity_I8:
1761 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(base_op+0) ) );
1762 break;
1763 case Ity_I16:
1764 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(base_op+1) ) );
1765 break;
1766 case Ity_I32:
1767 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(base_op+2) ) );
1768 break;
1769 case Ity_I64:
1770 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(base_op+3) ) );
1771 break;
1772 default:
1773 vpanic("setFlags_MUL(amd64)");
1774 }
1775 stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto64(mkexpr(arg1)) ));
1776 stmt( IRStmt_Put( OFFB_CC_DEP2, widenUto64(mkexpr(arg2)) ));
1777}
sewardj3ca55a12005-01-27 16:06:23 +00001778
1779
1780/* -------------- Condition codes. -------------- */
1781
1782/* Condition codes, using the AMD encoding. */
1783
sewardj8c332e22005-01-28 01:36:56 +00001784static HChar* name_AMD64Condcode ( AMD64Condcode cond )
sewardj3ca55a12005-01-27 16:06:23 +00001785{
1786 switch (cond) {
1787 case AMD64CondO: return "o";
1788 case AMD64CondNO: return "no";
1789 case AMD64CondB: return "b";
sewardje941eea2005-01-30 19:52:28 +00001790 case AMD64CondNB: return "ae"; /*"nb";*/
1791 case AMD64CondZ: return "e"; /*"z";*/
1792 case AMD64CondNZ: return "ne"; /*"nz";*/
sewardj3ca55a12005-01-27 16:06:23 +00001793 case AMD64CondBE: return "be";
sewardje941eea2005-01-30 19:52:28 +00001794 case AMD64CondNBE: return "a"; /*"nbe";*/
sewardj3ca55a12005-01-27 16:06:23 +00001795 case AMD64CondS: return "s";
1796 case AMD64CondNS: return "ns";
1797 case AMD64CondP: return "p";
1798 case AMD64CondNP: return "np";
1799 case AMD64CondL: return "l";
sewardje941eea2005-01-30 19:52:28 +00001800 case AMD64CondNL: return "ge"; /*"nl";*/
sewardj3ca55a12005-01-27 16:06:23 +00001801 case AMD64CondLE: return "le";
sewardje941eea2005-01-30 19:52:28 +00001802 case AMD64CondNLE: return "g"; /*"nle";*/
sewardj3ca55a12005-01-27 16:06:23 +00001803 case AMD64CondAlways: return "ALWAYS";
1804 default: vpanic("name_AMD64Condcode");
1805 }
1806}
1807
sewardj1389d4d2005-01-28 13:46:29 +00001808static
1809AMD64Condcode positiveIse_AMD64Condcode ( AMD64Condcode cond,
1810 /*OUT*/Bool* needInvert )
1811{
1812 vassert(cond >= AMD64CondO && cond <= AMD64CondNLE);
1813 if (cond & 1) {
1814 *needInvert = True;
1815 return cond-1;
1816 } else {
1817 *needInvert = False;
1818 return cond;
1819 }
1820}
sewardjdf0e0022005-01-25 15:48:43 +00001821
1822
1823/* -------------- Helpers for ADD/SUB with carry. -------------- */
1824
1825/* Given ta1, ta2 and tres, compute tres = ADC(ta1,ta2) and set flags
1826 appropriately.
sewardje9d8a262009-07-01 08:06:34 +00001827
1828 Optionally, generate a store for the 'tres' value. This can either
1829 be a normal store, or it can be a cas-with-possible-failure style
1830 store:
1831
1832 if taddr is IRTemp_INVALID, then no store is generated.
1833
1834 if taddr is not IRTemp_INVALID, then a store (using taddr as
1835 the address) is generated:
1836
1837 if texpVal is IRTemp_INVALID then a normal store is
1838 generated, and restart_point must be zero (it is irrelevant).
1839
1840 if texpVal is not IRTemp_INVALID then a cas-style store is
1841 generated. texpVal is the expected value, restart_point
1842 is the restart point if the store fails, and texpVal must
1843 have the same type as tres.
1844
sewardjdf0e0022005-01-25 15:48:43 +00001845*/
1846static void helper_ADC ( Int sz,
sewardje9d8a262009-07-01 08:06:34 +00001847 IRTemp tres, IRTemp ta1, IRTemp ta2,
1848 /* info about optional store: */
1849 IRTemp taddr, IRTemp texpVal, Addr32 restart_point )
sewardjdf0e0022005-01-25 15:48:43 +00001850{
1851 UInt thunkOp;
1852 IRType ty = szToITy(sz);
1853 IRTemp oldc = newTemp(Ity_I64);
1854 IRTemp oldcn = newTemp(ty);
1855 IROp plus = mkSizedOp(ty, Iop_Add8);
1856 IROp xor = mkSizedOp(ty, Iop_Xor8);
1857
sewardje9d8a262009-07-01 08:06:34 +00001858 vassert(typeOfIRTemp(irsb->tyenv, tres) == ty);
1859
sewardjdf0e0022005-01-25 15:48:43 +00001860 switch (sz) {
1861 case 8: thunkOp = AMD64G_CC_OP_ADCQ; break;
1862 case 4: thunkOp = AMD64G_CC_OP_ADCL; break;
1863 case 2: thunkOp = AMD64G_CC_OP_ADCW; break;
1864 case 1: thunkOp = AMD64G_CC_OP_ADCB; break;
1865 default: vassert(0);
1866 }
1867
1868 /* oldc = old carry flag, 0 or 1 */
1869 assign( oldc, binop(Iop_And64,
1870 mk_amd64g_calculate_rflags_c(),
1871 mkU64(1)) );
1872
1873 assign( oldcn, narrowTo(ty, mkexpr(oldc)) );
1874
1875 assign( tres, binop(plus,
1876 binop(plus,mkexpr(ta1),mkexpr(ta2)),
1877 mkexpr(oldcn)) );
1878
sewardje9d8a262009-07-01 08:06:34 +00001879 /* Possibly generate a store of 'tres' to 'taddr'. See comment at
1880 start of this function. */
1881 if (taddr != IRTemp_INVALID) {
1882 if (texpVal == IRTemp_INVALID) {
1883 vassert(restart_point == 0);
1884 storeLE( mkexpr(taddr), mkexpr(tres) );
1885 } else {
1886 vassert(typeOfIRTemp(irsb->tyenv, texpVal) == ty);
1887 /* .. and hence 'texpVal' has the same type as 'tres'. */
1888 casLE( mkexpr(taddr),
1889 mkexpr(texpVal), mkexpr(tres), restart_point );
1890 }
1891 }
1892
sewardjdf0e0022005-01-25 15:48:43 +00001893 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(thunkOp) ) );
sewardj820611e2005-08-24 10:56:01 +00001894 stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto64(mkexpr(ta1)) ));
1895 stmt( IRStmt_Put( OFFB_CC_DEP2, widenUto64(binop(xor, mkexpr(ta2),
1896 mkexpr(oldcn)) )) );
sewardjdf0e0022005-01-25 15:48:43 +00001897 stmt( IRStmt_Put( OFFB_CC_NDEP, mkexpr(oldc) ) );
1898}
1899
1900
1901/* Given ta1, ta2 and tres, compute tres = SBB(ta1,ta2) and set flags
sewardje9d8a262009-07-01 08:06:34 +00001902 appropriately. As with helper_ADC, possibly generate a store of
1903 the result -- see comments on helper_ADC for details.
sewardjdf0e0022005-01-25 15:48:43 +00001904*/
1905static void helper_SBB ( Int sz,
sewardje9d8a262009-07-01 08:06:34 +00001906 IRTemp tres, IRTemp ta1, IRTemp ta2,
1907 /* info about optional store: */
1908 IRTemp taddr, IRTemp texpVal, Addr32 restart_point )
sewardjdf0e0022005-01-25 15:48:43 +00001909{
1910 UInt thunkOp;
1911 IRType ty = szToITy(sz);
1912 IRTemp oldc = newTemp(Ity_I64);
1913 IRTemp oldcn = newTemp(ty);
1914 IROp minus = mkSizedOp(ty, Iop_Sub8);
1915 IROp xor = mkSizedOp(ty, Iop_Xor8);
1916
sewardje9d8a262009-07-01 08:06:34 +00001917 vassert(typeOfIRTemp(irsb->tyenv, tres) == ty);
1918
sewardjdf0e0022005-01-25 15:48:43 +00001919 switch (sz) {
1920 case 8: thunkOp = AMD64G_CC_OP_SBBQ; break;
1921 case 4: thunkOp = AMD64G_CC_OP_SBBL; break;
1922 case 2: thunkOp = AMD64G_CC_OP_SBBW; break;
1923 case 1: thunkOp = AMD64G_CC_OP_SBBB; break;
1924 default: vassert(0);
1925 }
1926
1927 /* oldc = old carry flag, 0 or 1 */
1928 assign( oldc, binop(Iop_And64,
1929 mk_amd64g_calculate_rflags_c(),
1930 mkU64(1)) );
1931
1932 assign( oldcn, narrowTo(ty, mkexpr(oldc)) );
1933
1934 assign( tres, binop(minus,
1935 binop(minus,mkexpr(ta1),mkexpr(ta2)),
1936 mkexpr(oldcn)) );
1937
sewardje9d8a262009-07-01 08:06:34 +00001938 /* Possibly generate a store of 'tres' to 'taddr'. See comment at
1939 start of this function. */
1940 if (taddr != IRTemp_INVALID) {
1941 if (texpVal == IRTemp_INVALID) {
1942 vassert(restart_point == 0);
1943 storeLE( mkexpr(taddr), mkexpr(tres) );
1944 } else {
1945 vassert(typeOfIRTemp(irsb->tyenv, texpVal) == ty);
1946 /* .. and hence 'texpVal' has the same type as 'tres'. */
1947 casLE( mkexpr(taddr),
1948 mkexpr(texpVal), mkexpr(tres), restart_point );
1949 }
1950 }
1951
sewardjdf0e0022005-01-25 15:48:43 +00001952 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(thunkOp) ) );
sewardj820611e2005-08-24 10:56:01 +00001953 stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto64(mkexpr(ta1) )) );
1954 stmt( IRStmt_Put( OFFB_CC_DEP2, widenUto64(binop(xor, mkexpr(ta2),
1955 mkexpr(oldcn)) )) );
sewardjdf0e0022005-01-25 15:48:43 +00001956 stmt( IRStmt_Put( OFFB_CC_NDEP, mkexpr(oldc) ) );
1957}
1958
1959
sewardj3ca55a12005-01-27 16:06:23 +00001960/* -------------- Helpers for disassembly printing. -------------- */
1961
1962static HChar* nameGrp1 ( Int opc_aux )
1963{
1964 static HChar* grp1_names[8]
1965 = { "add", "or", "adc", "sbb", "and", "sub", "xor", "cmp" };
1966 if (opc_aux < 0 || opc_aux > 7) vpanic("nameGrp1(amd64)");
1967 return grp1_names[opc_aux];
1968}
1969
sewardj118b23e2005-01-29 02:14:44 +00001970static HChar* nameGrp2 ( Int opc_aux )
1971{
1972 static HChar* grp2_names[8]
1973 = { "rol", "ror", "rcl", "rcr", "shl", "shr", "shl", "sar" };
sewardje941eea2005-01-30 19:52:28 +00001974 if (opc_aux < 0 || opc_aux > 7) vpanic("nameGrp2(amd64)");
sewardj118b23e2005-01-29 02:14:44 +00001975 return grp2_names[opc_aux];
1976}
1977
sewardj03b07cc2005-01-31 18:09:43 +00001978static HChar* nameGrp4 ( Int opc_aux )
1979{
1980 static HChar* grp4_names[8]
1981 = { "inc", "dec", "???", "???", "???", "???", "???", "???" };
1982 if (opc_aux < 0 || opc_aux > 1) vpanic("nameGrp4(amd64)");
1983 return grp4_names[opc_aux];
1984}
sewardj354e5c62005-01-27 20:12:52 +00001985
1986static HChar* nameGrp5 ( Int opc_aux )
1987{
1988 static HChar* grp5_names[8]
1989 = { "inc", "dec", "call*", "call*", "jmp*", "jmp*", "push", "???" };
1990 if (opc_aux < 0 || opc_aux > 6) vpanic("nameGrp5(amd64)");
1991 return grp5_names[opc_aux];
1992}
1993
sewardj1d511802005-03-27 17:59:45 +00001994static HChar* nameGrp8 ( Int opc_aux )
1995{
1996 static HChar* grp8_names[8]
1997 = { "???", "???", "???", "???", "bt", "bts", "btr", "btc" };
1998 if (opc_aux < 4 || opc_aux > 7) vpanic("nameGrp8(amd64)");
1999 return grp8_names[opc_aux];
2000}
2001
sewardjd20c8852005-01-20 20:04:07 +00002002//.. static HChar* nameSReg ( UInt sreg )
2003//.. {
2004//.. switch (sreg) {
2005//.. case R_ES: return "%es";
2006//.. case R_CS: return "%cs";
2007//.. case R_SS: return "%ss";
2008//.. case R_DS: return "%ds";
2009//.. case R_FS: return "%fs";
2010//.. case R_GS: return "%gs";
2011//.. default: vpanic("nameSReg(x86)");
2012//.. }
2013//.. }
sewardj8711f662005-05-09 17:52:56 +00002014
2015static HChar* nameMMXReg ( Int mmxreg )
2016{
2017 static HChar* mmx_names[8]
2018 = { "%mm0", "%mm1", "%mm2", "%mm3", "%mm4", "%mm5", "%mm6", "%mm7" };
2019 if (mmxreg < 0 || mmxreg > 7) vpanic("nameMMXReg(amd64,guest)");
2020 return mmx_names[mmxreg];
2021}
sewardj1001dc42005-02-21 08:25:55 +00002022
2023static HChar* nameXMMReg ( Int xmmreg )
2024{
2025 static HChar* xmm_names[16]
2026 = { "%xmm0", "%xmm1", "%xmm2", "%xmm3",
2027 "%xmm4", "%xmm5", "%xmm6", "%xmm7",
2028 "%xmm8", "%xmm9", "%xmm10", "%xmm11",
2029 "%xmm12", "%xmm13", "%xmm14", "%xmm15" };
2030 if (xmmreg < 0 || xmmreg > 15) vpanic("nameXMMReg(amd64)");
2031 return xmm_names[xmmreg];
2032}
2033
sewardjca673ab2005-05-11 10:03:08 +00002034static HChar* nameMMXGran ( Int gran )
sewardj8711f662005-05-09 17:52:56 +00002035{
2036 switch (gran) {
2037 case 0: return "b";
2038 case 1: return "w";
2039 case 2: return "d";
2040 case 3: return "q";
2041 default: vpanic("nameMMXGran(amd64,guest)");
2042 }
2043}
sewardjdf0e0022005-01-25 15:48:43 +00002044
sewardj8c332e22005-01-28 01:36:56 +00002045static HChar nameISize ( Int size )
sewardjdf0e0022005-01-25 15:48:43 +00002046{
2047 switch (size) {
2048 case 8: return 'q';
2049 case 4: return 'l';
2050 case 2: return 'w';
2051 case 1: return 'b';
2052 default: vpanic("nameISize(amd64)");
2053 }
2054}
2055
2056
2057/*------------------------------------------------------------*/
2058/*--- JMP helpers ---*/
2059/*------------------------------------------------------------*/
2060
2061static void jmp_lit( IRJumpKind kind, Addr64 d64 )
2062{
sewardjdd40fdf2006-12-24 02:20:24 +00002063 irsb->next = mkU64(d64);
2064 irsb->jumpkind = kind;
sewardjdf0e0022005-01-25 15:48:43 +00002065}
2066
sewardj2f959cc2005-01-26 01:19:35 +00002067static void jmp_treg( IRJumpKind kind, IRTemp t )
2068{
sewardjdd40fdf2006-12-24 02:20:24 +00002069 irsb->next = mkexpr(t);
2070 irsb->jumpkind = kind;
sewardj2f959cc2005-01-26 01:19:35 +00002071}
2072
sewardj1389d4d2005-01-28 13:46:29 +00002073static
2074void jcc_01 ( AMD64Condcode cond, Addr64 d64_false, Addr64 d64_true )
2075{
2076 Bool invert;
2077 AMD64Condcode condPos;
2078 condPos = positiveIse_AMD64Condcode ( cond, &invert );
2079 if (invert) {
2080 stmt( IRStmt_Exit( mk_amd64g_calculate_condition(condPos),
2081 Ijk_Boring,
2082 IRConst_U64(d64_false) ) );
sewardjdd40fdf2006-12-24 02:20:24 +00002083 irsb->next = mkU64(d64_true);
2084 irsb->jumpkind = Ijk_Boring;
sewardj1389d4d2005-01-28 13:46:29 +00002085 } else {
2086 stmt( IRStmt_Exit( mk_amd64g_calculate_condition(condPos),
2087 Ijk_Boring,
2088 IRConst_U64(d64_true) ) );
sewardjdd40fdf2006-12-24 02:20:24 +00002089 irsb->next = mkU64(d64_false);
2090 irsb->jumpkind = Ijk_Boring;
sewardj1389d4d2005-01-28 13:46:29 +00002091 }
2092}
sewardjb3a04292005-01-21 20:33:44 +00002093
sewardj478646f2008-05-01 20:13:04 +00002094/* Let new_rsp be the %rsp value after a call/return. Let nia be the
2095 guest address of the next instruction to be executed.
2096
2097 This function generates an AbiHint to say that -128(%rsp)
2098 .. -1(%rsp) should now be regarded as uninitialised.
sewardj5a9ffab2005-05-12 17:55:01 +00002099*/
sewardjaca070a2006-10-17 00:28:22 +00002100static
sewardj478646f2008-05-01 20:13:04 +00002101void make_redzone_AbiHint ( VexAbiInfo* vbi,
2102 IRTemp new_rsp, IRTemp nia, HChar* who )
sewardj5a9ffab2005-05-12 17:55:01 +00002103{
sewardjdd40fdf2006-12-24 02:20:24 +00002104 Int szB = vbi->guest_stack_redzone_size;
sewardjaca070a2006-10-17 00:28:22 +00002105 vassert(szB >= 0);
2106
2107 /* A bit of a kludge. Currently the only AbI we've guested AMD64
2108 for is ELF. So just check it's the expected 128 value
2109 (paranoia). */
2110 vassert(szB == 128);
2111
sewardj5a9ffab2005-05-12 17:55:01 +00002112 if (0) vex_printf("AbiHint: %s\n", who);
sewardjdd40fdf2006-12-24 02:20:24 +00002113 vassert(typeOfIRTemp(irsb->tyenv, new_rsp) == Ity_I64);
sewardj478646f2008-05-01 20:13:04 +00002114 vassert(typeOfIRTemp(irsb->tyenv, nia) == Ity_I64);
sewardjaca070a2006-10-17 00:28:22 +00002115 if (szB > 0)
2116 stmt( IRStmt_AbiHint(
2117 binop(Iop_Sub64, mkexpr(new_rsp), mkU64(szB)),
sewardj478646f2008-05-01 20:13:04 +00002118 szB,
2119 mkexpr(nia)
sewardjaca070a2006-10-17 00:28:22 +00002120 ));
sewardj5a9ffab2005-05-12 17:55:01 +00002121}
2122
sewardjb3a04292005-01-21 20:33:44 +00002123
2124/*------------------------------------------------------------*/
2125/*--- Disassembling addressing modes ---*/
2126/*------------------------------------------------------------*/
2127
2128static
sewardjc4356f02007-11-09 21:15:04 +00002129HChar* segRegTxt ( Prefix pfx )
sewardjb3a04292005-01-21 20:33:44 +00002130{
2131 if (pfx & PFX_CS) return "%cs:";
2132 if (pfx & PFX_DS) return "%ds:";
2133 if (pfx & PFX_ES) return "%es:";
2134 if (pfx & PFX_FS) return "%fs:";
2135 if (pfx & PFX_GS) return "%gs:";
2136 if (pfx & PFX_SS) return "%ss:";
2137 return ""; /* no override */
2138}
2139
2140
2141/* 'virtual' is an IRExpr* holding a virtual address. Convert it to a
2142 linear address by adding any required segment override as indicated
sewardj42561ef2005-11-04 14:18:31 +00002143 by sorb, and also dealing with any address size override
2144 present. */
sewardjb3a04292005-01-21 20:33:44 +00002145static
sewardj2e28ac42008-12-04 00:05:12 +00002146IRExpr* handleAddrOverrides ( VexAbiInfo* vbi,
2147 Prefix pfx, IRExpr* virtual )
sewardjb3a04292005-01-21 20:33:44 +00002148{
sewardj42561ef2005-11-04 14:18:31 +00002149 /* --- segment overrides --- */
sewardja6b93d12005-02-17 09:28:28 +00002150 if (pfx & PFX_FS) {
sewardj2e28ac42008-12-04 00:05:12 +00002151 if (vbi->guest_amd64_assume_fs_is_zero) {
2152 /* Note that this is a linux-kernel specific hack that relies
2153 on the assumption that %fs is always zero. */
2154 /* return virtual + guest_FS_ZERO. */
2155 virtual = binop(Iop_Add64, virtual,
2156 IRExpr_Get(OFFB_FS_ZERO, Ity_I64));
2157 } else {
2158 unimplemented("amd64 %fs segment override");
2159 }
sewardja6b93d12005-02-17 09:28:28 +00002160 }
sewardjb3a04292005-01-21 20:33:44 +00002161
sewardja6b93d12005-02-17 09:28:28 +00002162 if (pfx & PFX_GS) {
sewardj2e28ac42008-12-04 00:05:12 +00002163 if (vbi->guest_amd64_assume_gs_is_0x60) {
2164 /* Note that this is a darwin-kernel specific hack that relies
2165 on the assumption that %gs is always 0x60. */
2166 /* return virtual + guest_GS_0x60. */
2167 virtual = binop(Iop_Add64, virtual,
2168 IRExpr_Get(OFFB_GS_0x60, Ity_I64));
2169 } else {
2170 unimplemented("amd64 %gs segment override");
2171 }
sewardja6b93d12005-02-17 09:28:28 +00002172 }
2173
2174 /* cs, ds, es and ss are simply ignored in 64-bit mode. */
sewardj42561ef2005-11-04 14:18:31 +00002175
2176 /* --- address size override --- */
2177 if (haveASO(pfx))
2178 virtual = unop(Iop_32Uto64, unop(Iop_64to32, virtual));
2179
sewardja6b93d12005-02-17 09:28:28 +00002180 return virtual;
sewardjb3a04292005-01-21 20:33:44 +00002181}
sewardja6b93d12005-02-17 09:28:28 +00002182
sewardjd20c8852005-01-20 20:04:07 +00002183//.. {
2184//.. Int sreg;
2185//.. IRType hWordTy;
2186//.. IRTemp ldt_ptr, gdt_ptr, seg_selector, r64;
2187//..
2188//.. if (sorb == 0)
2189//.. /* the common case - no override */
2190//.. return virtual;
2191//..
2192//.. switch (sorb) {
2193//.. case 0x3E: sreg = R_DS; break;
2194//.. case 0x26: sreg = R_ES; break;
2195//.. case 0x64: sreg = R_FS; break;
2196//.. case 0x65: sreg = R_GS; break;
sewardj42561ef2005-11-04 14:18:31 +00002197//.. default: vpanic("handleAddrOverrides(x86,guest)");
sewardjd20c8852005-01-20 20:04:07 +00002198//.. }
2199//..
2200//.. hWordTy = sizeof(HWord)==4 ? Ity_I32 : Ity_I64;
2201//..
2202//.. seg_selector = newTemp(Ity_I32);
2203//.. ldt_ptr = newTemp(hWordTy);
2204//.. gdt_ptr = newTemp(hWordTy);
2205//.. r64 = newTemp(Ity_I64);
2206//..
2207//.. assign( seg_selector, unop(Iop_16Uto32, getSReg(sreg)) );
2208//.. assign( ldt_ptr, IRExpr_Get( OFFB_LDT, hWordTy ));
2209//.. assign( gdt_ptr, IRExpr_Get( OFFB_GDT, hWordTy ));
2210//..
2211//.. /*
2212//.. Call this to do the translation and limit checks:
2213//.. ULong x86g_use_seg_selector ( HWord ldt, HWord gdt,
2214//.. UInt seg_selector, UInt virtual_addr )
2215//.. */
2216//.. assign(
2217//.. r64,
2218//.. mkIRExprCCall(
2219//.. Ity_I64,
2220//.. 0/*regparms*/,
2221//.. "x86g_use_seg_selector",
2222//.. &x86g_use_seg_selector,
2223//.. mkIRExprVec_4( mkexpr(ldt_ptr), mkexpr(gdt_ptr),
2224//.. mkexpr(seg_selector), virtual)
2225//.. )
2226//.. );
2227//..
2228//.. /* If the high 32 of the result are non-zero, there was a
2229//.. failure in address translation. In which case, make a
2230//.. quick exit.
2231//.. */
2232//.. stmt(
2233//.. IRStmt_Exit(
2234//.. binop(Iop_CmpNE32, unop(Iop_64HIto32, mkexpr(r64)), mkU32(0)),
2235//.. Ijk_MapFail,
2236//.. IRConst_U32( guest_eip_curr_instr )
2237//.. )
2238//.. );
2239//..
2240//.. /* otherwise, here's the translated result. */
2241//.. return unop(Iop_64to32, mkexpr(r64));
2242//.. }
sewardjb3a04292005-01-21 20:33:44 +00002243
2244
2245/* Generate IR to calculate an address indicated by a ModRM and
2246 following SIB bytes. The expression, and the number of bytes in
2247 the address mode, are returned (the latter in *len). Note that
2248 this fn should not be called if the R/M part of the address denotes
2249 a register instead of memory. If print_codegen is true, text of
2250 the addressing mode is placed in buf.
2251
2252 The computed address is stored in a new tempreg, and the
sewardje1698952005-02-08 15:02:39 +00002253 identity of the tempreg is returned.
2254
2255 extra_bytes holds the number of bytes after the amode, as supplied
2256 by the caller. This is needed to make sense of %rip-relative
2257 addresses. Note that the value that *len is set to is only the
2258 length of the amode itself and does not include the value supplied
sewardj09717342005-05-05 21:34:02 +00002259 in extra_bytes.
sewardje1698952005-02-08 15:02:39 +00002260 */
sewardjb3a04292005-01-21 20:33:44 +00002261
2262static IRTemp disAMode_copy2tmp ( IRExpr* addr64 )
2263{
2264 IRTemp tmp = newTemp(Ity_I64);
2265 assign( tmp, addr64 );
2266 return tmp;
2267}
2268
2269static
sewardj2e28ac42008-12-04 00:05:12 +00002270IRTemp disAMode ( /*OUT*/Int* len,
2271 VexAbiInfo* vbi, Prefix pfx, Long delta,
2272 /*OUT*/HChar* buf, Int extra_bytes )
sewardjb3a04292005-01-21 20:33:44 +00002273{
sewardj8c332e22005-01-28 01:36:56 +00002274 UChar mod_reg_rm = getUChar(delta);
sewardjb3a04292005-01-21 20:33:44 +00002275 delta++;
2276
2277 buf[0] = (UChar)0;
sewardje1698952005-02-08 15:02:39 +00002278 vassert(extra_bytes >= 0 && extra_bytes < 10);
sewardjb3a04292005-01-21 20:33:44 +00002279
2280 /* squeeze out the reg field from mod_reg_rm, since a 256-entry
2281 jump table seems a bit excessive.
2282 */
sewardj7a240552005-01-28 21:37:12 +00002283 mod_reg_rm &= 0xC7; /* is now XX000YYY */
sewardj1027dc22005-02-26 01:55:02 +00002284 mod_reg_rm = toUChar(mod_reg_rm | (mod_reg_rm >> 3));
2285 /* is now XX0XXYYY */
sewardj7a240552005-01-28 21:37:12 +00002286 mod_reg_rm &= 0x1F; /* is now 000XXYYY */
sewardjb3a04292005-01-21 20:33:44 +00002287 switch (mod_reg_rm) {
2288
2289 /* REX.B==0: (%rax) .. (%rdi), not including (%rsp) or (%rbp).
2290 REX.B==1: (%r8) .. (%r15), not including (%r12) or (%r13).
2291 */
2292 case 0x00: case 0x01: case 0x02: case 0x03:
2293 /* ! 04 */ /* ! 05 */ case 0x06: case 0x07:
sewardj1027dc22005-02-26 01:55:02 +00002294 { UChar rm = toUChar(mod_reg_rm & 7);
sewardjc4356f02007-11-09 21:15:04 +00002295 DIS(buf, "%s(%s)", segRegTxt(pfx), nameIRegRexB(8,pfx,rm));
sewardjb3a04292005-01-21 20:33:44 +00002296 *len = 1;
2297 return disAMode_copy2tmp(
sewardj2e28ac42008-12-04 00:05:12 +00002298 handleAddrOverrides(vbi, pfx, getIRegRexB(8,pfx,rm)));
sewardjb3a04292005-01-21 20:33:44 +00002299 }
2300
2301 /* REX.B==0: d8(%rax) ... d8(%rdi), not including d8(%rsp)
2302 REX.B==1: d8(%r8) ... d8(%r15), not including d8(%r12)
2303 */
2304 case 0x08: case 0x09: case 0x0A: case 0x0B:
2305 /* ! 0C */ case 0x0D: case 0x0E: case 0x0F:
sewardj1027dc22005-02-26 01:55:02 +00002306 { UChar rm = toUChar(mod_reg_rm & 7);
sewardj8c332e22005-01-28 01:36:56 +00002307 Long d = getSDisp8(delta);
sewardj7eaa7cf2005-01-31 18:55:22 +00002308 if (d == 0) {
sewardjc4356f02007-11-09 21:15:04 +00002309 DIS(buf, "%s(%s)", segRegTxt(pfx), nameIRegRexB(8,pfx,rm));
sewardj7eaa7cf2005-01-31 18:55:22 +00002310 } else {
sewardjc4356f02007-11-09 21:15:04 +00002311 DIS(buf, "%s%lld(%s)", segRegTxt(pfx), d, nameIRegRexB(8,pfx,rm));
sewardj7eaa7cf2005-01-31 18:55:22 +00002312 }
sewardjb3a04292005-01-21 20:33:44 +00002313 *len = 2;
2314 return disAMode_copy2tmp(
sewardj2e28ac42008-12-04 00:05:12 +00002315 handleAddrOverrides(vbi, pfx,
sewardj5b470602005-02-27 13:10:48 +00002316 binop(Iop_Add64,getIRegRexB(8,pfx,rm),mkU64(d))));
sewardjb3a04292005-01-21 20:33:44 +00002317 }
2318
2319 /* REX.B==0: d32(%rax) ... d32(%rdi), not including d32(%rsp)
2320 REX.B==1: d32(%r8) ... d32(%r15), not including d32(%r12)
2321 */
2322 case 0x10: case 0x11: case 0x12: case 0x13:
2323 /* ! 14 */ case 0x15: case 0x16: case 0x17:
sewardj1027dc22005-02-26 01:55:02 +00002324 { UChar rm = toUChar(mod_reg_rm & 7);
sewardj227458e2005-01-31 19:04:50 +00002325 Long d = getSDisp32(delta);
sewardjc4356f02007-11-09 21:15:04 +00002326 DIS(buf, "%s%lld(%s)", segRegTxt(pfx), d, nameIRegRexB(8,pfx,rm));
sewardjb3a04292005-01-21 20:33:44 +00002327 *len = 5;
2328 return disAMode_copy2tmp(
sewardj2e28ac42008-12-04 00:05:12 +00002329 handleAddrOverrides(vbi, pfx,
sewardj5b470602005-02-27 13:10:48 +00002330 binop(Iop_Add64,getIRegRexB(8,pfx,rm),mkU64(d))));
sewardjb3a04292005-01-21 20:33:44 +00002331 }
2332
2333 /* REX.B==0: a register, %rax .. %rdi. This shouldn't happen. */
2334 /* REX.B==1: a register, %r8 .. %r16. This shouldn't happen. */
2335 case 0x18: case 0x19: case 0x1A: case 0x1B:
2336 case 0x1C: case 0x1D: case 0x1E: case 0x1F:
sewardj354e5c62005-01-27 20:12:52 +00002337 vpanic("disAMode(amd64): not an addr!");
sewardjb3a04292005-01-21 20:33:44 +00002338
sewardj9e6491a2005-07-02 19:24:10 +00002339 /* RIP + disp32. This assumes that guest_RIP_curr_instr is set
sewardjb3a04292005-01-21 20:33:44 +00002340 correctly at the start of handling each instruction. */
2341 case 0x05:
sewardj227458e2005-01-31 19:04:50 +00002342 { Long d = getSDisp32(delta);
sewardjb3a04292005-01-21 20:33:44 +00002343 *len = 5;
sewardjc4356f02007-11-09 21:15:04 +00002344 DIS(buf, "%s%lld(%%rip)", segRegTxt(pfx), d);
sewardj4b744762005-02-07 15:02:25 +00002345 /* We need to know the next instruction's start address.
2346 Try and figure out what it is, record the guess, and ask
2347 the top-level driver logic (bbToIR_AMD64) to check we
2348 guessed right, after the instruction is completely
2349 decoded. */
sewardj9e6491a2005-07-02 19:24:10 +00002350 guest_RIP_next_mustcheck = True;
2351 guest_RIP_next_assumed = guest_RIP_bbstart
sewardje1698952005-02-08 15:02:39 +00002352 + delta+4 + extra_bytes;
sewardjb3a04292005-01-21 20:33:44 +00002353 return disAMode_copy2tmp(
sewardj2e28ac42008-12-04 00:05:12 +00002354 handleAddrOverrides(vbi, pfx,
sewardj9e6491a2005-07-02 19:24:10 +00002355 binop(Iop_Add64, mkU64(guest_RIP_next_assumed),
sewardjb3a04292005-01-21 20:33:44 +00002356 mkU64(d))));
2357 }
sewardj3ca55a12005-01-27 16:06:23 +00002358
sewardj2f959cc2005-01-26 01:19:35 +00002359 case 0x04: {
2360 /* SIB, with no displacement. Special cases:
sewardj3ca55a12005-01-27 16:06:23 +00002361 -- %rsp cannot act as an index value.
2362 If index_r indicates %rsp, zero is used for the index.
2363 -- when mod is zero and base indicates RBP or R13, base is
2364 instead a 32-bit sign-extended literal.
sewardj2f959cc2005-01-26 01:19:35 +00002365 It's all madness, I tell you. Extract %index, %base and
2366 scale from the SIB byte. The value denoted is then:
sewardj3ca55a12005-01-27 16:06:23 +00002367 | %index == %RSP && (%base == %RBP || %base == %R13)
sewardj2f959cc2005-01-26 01:19:35 +00002368 = d32 following SIB byte
sewardj3ca55a12005-01-27 16:06:23 +00002369 | %index == %RSP && !(%base == %RBP || %base == %R13)
sewardj2f959cc2005-01-26 01:19:35 +00002370 = %base
sewardj3ca55a12005-01-27 16:06:23 +00002371 | %index != %RSP && (%base == %RBP || %base == %R13)
sewardj2f959cc2005-01-26 01:19:35 +00002372 = d32 following SIB byte + (%index << scale)
sewardj3ca55a12005-01-27 16:06:23 +00002373 | %index != %RSP && !(%base == %RBP || %base == %R13)
sewardj2f959cc2005-01-26 01:19:35 +00002374 = %base + (%index << scale)
2375 */
sewardj8c332e22005-01-28 01:36:56 +00002376 UChar sib = getUChar(delta);
sewardj1027dc22005-02-26 01:55:02 +00002377 UChar scale = toUChar((sib >> 6) & 3);
2378 UChar index_r = toUChar((sib >> 3) & 7);
2379 UChar base_r = toUChar(sib & 7);
sewardj3ca55a12005-01-27 16:06:23 +00002380 /* correct since #(R13) == 8 + #(RBP) */
sewardj7a240552005-01-28 21:37:12 +00002381 Bool base_is_BPor13 = toBool(base_r == R_RBP);
2382 Bool index_is_SP = toBool(index_r == R_RSP && 0==getRexX(pfx));
sewardj2f959cc2005-01-26 01:19:35 +00002383 delta++;
sewardjb3a04292005-01-21 20:33:44 +00002384
sewardj3ca55a12005-01-27 16:06:23 +00002385 if ((!index_is_SP) && (!base_is_BPor13)) {
sewardje941eea2005-01-30 19:52:28 +00002386 if (scale == 0) {
sewardjc4356f02007-11-09 21:15:04 +00002387 DIS(buf, "%s(%s,%s)", segRegTxt(pfx),
sewardj5b470602005-02-27 13:10:48 +00002388 nameIRegRexB(8,pfx,base_r),
2389 nameIReg64rexX(pfx,index_r));
sewardje941eea2005-01-30 19:52:28 +00002390 } else {
sewardjc4356f02007-11-09 21:15:04 +00002391 DIS(buf, "%s(%s,%s,%d)", segRegTxt(pfx),
sewardj5b470602005-02-27 13:10:48 +00002392 nameIRegRexB(8,pfx,base_r),
2393 nameIReg64rexX(pfx,index_r), 1<<scale);
sewardje941eea2005-01-30 19:52:28 +00002394 }
sewardj2f959cc2005-01-26 01:19:35 +00002395 *len = 2;
sewardj2f959cc2005-01-26 01:19:35 +00002396 return
2397 disAMode_copy2tmp(
sewardj2e28ac42008-12-04 00:05:12 +00002398 handleAddrOverrides(vbi, pfx,
sewardj3ca55a12005-01-27 16:06:23 +00002399 binop(Iop_Add64,
sewardj5b470602005-02-27 13:10:48 +00002400 getIRegRexB(8,pfx,base_r),
2401 binop(Iop_Shl64, getIReg64rexX(pfx,index_r),
sewardj2f959cc2005-01-26 01:19:35 +00002402 mkU8(scale)))));
2403 }
2404
sewardj3ca55a12005-01-27 16:06:23 +00002405 if ((!index_is_SP) && base_is_BPor13) {
sewardj227458e2005-01-31 19:04:50 +00002406 Long d = getSDisp32(delta);
sewardjc4356f02007-11-09 21:15:04 +00002407 DIS(buf, "%s%lld(,%s,%d)", segRegTxt(pfx), d,
sewardj5b470602005-02-27 13:10:48 +00002408 nameIReg64rexX(pfx,index_r), 1<<scale);
sewardj2f959cc2005-01-26 01:19:35 +00002409 *len = 6;
sewardj2f959cc2005-01-26 01:19:35 +00002410 return
2411 disAMode_copy2tmp(
sewardj2e28ac42008-12-04 00:05:12 +00002412 handleAddrOverrides(vbi, pfx,
sewardj3ca55a12005-01-27 16:06:23 +00002413 binop(Iop_Add64,
sewardj5b470602005-02-27 13:10:48 +00002414 binop(Iop_Shl64, getIReg64rexX(pfx,index_r),
sewardj3ca55a12005-01-27 16:06:23 +00002415 mkU8(scale)),
2416 mkU64(d))));
sewardj2f959cc2005-01-26 01:19:35 +00002417 }
2418
sewardj3ca55a12005-01-27 16:06:23 +00002419 if (index_is_SP && (!base_is_BPor13)) {
sewardjc4356f02007-11-09 21:15:04 +00002420 DIS(buf, "%s(%s)", segRegTxt(pfx), nameIRegRexB(8,pfx,base_r));
sewardj2f959cc2005-01-26 01:19:35 +00002421 *len = 2;
sewardj2f959cc2005-01-26 01:19:35 +00002422 return disAMode_copy2tmp(
sewardj2e28ac42008-12-04 00:05:12 +00002423 handleAddrOverrides(vbi, pfx, getIRegRexB(8,pfx,base_r)));
sewardj2f959cc2005-01-26 01:19:35 +00002424 }
2425
sewardj3ca55a12005-01-27 16:06:23 +00002426 if (index_is_SP && base_is_BPor13) {
sewardj227458e2005-01-31 19:04:50 +00002427 Long d = getSDisp32(delta);
sewardjc4356f02007-11-09 21:15:04 +00002428 DIS(buf, "%s%lld", segRegTxt(pfx), d);
sewardj2f959cc2005-01-26 01:19:35 +00002429 *len = 6;
sewardj2f959cc2005-01-26 01:19:35 +00002430 return disAMode_copy2tmp(
sewardj2e28ac42008-12-04 00:05:12 +00002431 handleAddrOverrides(vbi, pfx, mkU64(d)));
sewardj2f959cc2005-01-26 01:19:35 +00002432 }
2433
2434 vassert(0);
2435 }
sewardj3ca55a12005-01-27 16:06:23 +00002436
sewardj2f959cc2005-01-26 01:19:35 +00002437 /* SIB, with 8-bit displacement. Special cases:
2438 -- %esp cannot act as an index value.
2439 If index_r indicates %esp, zero is used for the index.
2440 Denoted value is:
2441 | %index == %ESP
2442 = d8 + %base
2443 | %index != %ESP
2444 = d8 + %base + (%index << scale)
2445 */
2446 case 0x0C: {
sewardj8c332e22005-01-28 01:36:56 +00002447 UChar sib = getUChar(delta);
sewardj1027dc22005-02-26 01:55:02 +00002448 UChar scale = toUChar((sib >> 6) & 3);
2449 UChar index_r = toUChar((sib >> 3) & 7);
2450 UChar base_r = toUChar(sib & 7);
sewardj8c332e22005-01-28 01:36:56 +00002451 Long d = getSDisp8(delta+1);
sewardj2f959cc2005-01-26 01:19:35 +00002452
sewardj3ca55a12005-01-27 16:06:23 +00002453 if (index_r == R_RSP && 0==getRexX(pfx)) {
sewardjc4356f02007-11-09 21:15:04 +00002454 DIS(buf, "%s%lld(%s)", segRegTxt(pfx),
sewardj5b470602005-02-27 13:10:48 +00002455 d, nameIRegRexB(8,pfx,base_r));
sewardj2f959cc2005-01-26 01:19:35 +00002456 *len = 3;
sewardj2f959cc2005-01-26 01:19:35 +00002457 return disAMode_copy2tmp(
sewardj2e28ac42008-12-04 00:05:12 +00002458 handleAddrOverrides(vbi, pfx,
sewardj5b470602005-02-27 13:10:48 +00002459 binop(Iop_Add64, getIRegRexB(8,pfx,base_r), mkU64(d)) ));
sewardj2f959cc2005-01-26 01:19:35 +00002460 } else {
sewardje941eea2005-01-30 19:52:28 +00002461 if (scale == 0) {
sewardjc4356f02007-11-09 21:15:04 +00002462 DIS(buf, "%s%lld(%s,%s)", segRegTxt(pfx), d,
sewardj5b470602005-02-27 13:10:48 +00002463 nameIRegRexB(8,pfx,base_r),
2464 nameIReg64rexX(pfx,index_r));
sewardje941eea2005-01-30 19:52:28 +00002465 } else {
sewardjc4356f02007-11-09 21:15:04 +00002466 DIS(buf, "%s%lld(%s,%s,%d)", segRegTxt(pfx), d,
sewardj5b470602005-02-27 13:10:48 +00002467 nameIRegRexB(8,pfx,base_r),
2468 nameIReg64rexX(pfx,index_r), 1<<scale);
sewardje941eea2005-01-30 19:52:28 +00002469 }
sewardj2f959cc2005-01-26 01:19:35 +00002470 *len = 3;
sewardj2f959cc2005-01-26 01:19:35 +00002471 return
2472 disAMode_copy2tmp(
sewardj2e28ac42008-12-04 00:05:12 +00002473 handleAddrOverrides(vbi, pfx,
sewardj3ca55a12005-01-27 16:06:23 +00002474 binop(Iop_Add64,
2475 binop(Iop_Add64,
sewardj5b470602005-02-27 13:10:48 +00002476 getIRegRexB(8,pfx,base_r),
sewardj3ca55a12005-01-27 16:06:23 +00002477 binop(Iop_Shl64,
sewardj5b470602005-02-27 13:10:48 +00002478 getIReg64rexX(pfx,index_r), mkU8(scale))),
sewardj3ca55a12005-01-27 16:06:23 +00002479 mkU64(d))));
sewardj2f959cc2005-01-26 01:19:35 +00002480 }
sewardj3ca55a12005-01-27 16:06:23 +00002481 vassert(0); /*NOTREACHED*/
sewardj2f959cc2005-01-26 01:19:35 +00002482 }
sewardj3ca55a12005-01-27 16:06:23 +00002483
sewardj2f959cc2005-01-26 01:19:35 +00002484 /* SIB, with 32-bit displacement. Special cases:
2485 -- %rsp cannot act as an index value.
2486 If index_r indicates %rsp, zero is used for the index.
2487 Denoted value is:
2488 | %index == %RSP
2489 = d32 + %base
2490 | %index != %RSP
2491 = d32 + %base + (%index << scale)
2492 */
2493 case 0x14: {
sewardj8c332e22005-01-28 01:36:56 +00002494 UChar sib = getUChar(delta);
sewardj1027dc22005-02-26 01:55:02 +00002495 UChar scale = toUChar((sib >> 6) & 3);
2496 UChar index_r = toUChar((sib >> 3) & 7);
2497 UChar base_r = toUChar(sib & 7);
sewardj8c332e22005-01-28 01:36:56 +00002498 Long d = getSDisp32(delta+1);
sewardj2f959cc2005-01-26 01:19:35 +00002499
2500 if (index_r == R_RSP && 0==getRexX(pfx)) {
sewardjc4356f02007-11-09 21:15:04 +00002501 DIS(buf, "%s%lld(%s)", segRegTxt(pfx),
sewardj5b470602005-02-27 13:10:48 +00002502 d, nameIRegRexB(8,pfx,base_r));
sewardj2f959cc2005-01-26 01:19:35 +00002503 *len = 6;
sewardj2f959cc2005-01-26 01:19:35 +00002504 return disAMode_copy2tmp(
sewardj2e28ac42008-12-04 00:05:12 +00002505 handleAddrOverrides(vbi, pfx,
sewardj5b470602005-02-27 13:10:48 +00002506 binop(Iop_Add64, getIRegRexB(8,pfx,base_r), mkU64(d)) ));
sewardj2f959cc2005-01-26 01:19:35 +00002507 } else {
sewardje941eea2005-01-30 19:52:28 +00002508 if (scale == 0) {
sewardjc4356f02007-11-09 21:15:04 +00002509 DIS(buf, "%s%lld(%s,%s)", segRegTxt(pfx), d,
sewardj5b470602005-02-27 13:10:48 +00002510 nameIRegRexB(8,pfx,base_r),
2511 nameIReg64rexX(pfx,index_r));
sewardje941eea2005-01-30 19:52:28 +00002512 } else {
sewardjc4356f02007-11-09 21:15:04 +00002513 DIS(buf, "%s%lld(%s,%s,%d)", segRegTxt(pfx), d,
sewardj5b470602005-02-27 13:10:48 +00002514 nameIRegRexB(8,pfx,base_r),
2515 nameIReg64rexX(pfx,index_r), 1<<scale);
sewardje941eea2005-01-30 19:52:28 +00002516 }
sewardj2f959cc2005-01-26 01:19:35 +00002517 *len = 6;
2518 return
2519 disAMode_copy2tmp(
sewardj2e28ac42008-12-04 00:05:12 +00002520 handleAddrOverrides(vbi, pfx,
sewardj2f959cc2005-01-26 01:19:35 +00002521 binop(Iop_Add64,
2522 binop(Iop_Add64,
sewardj5b470602005-02-27 13:10:48 +00002523 getIRegRexB(8,pfx,base_r),
sewardj2f959cc2005-01-26 01:19:35 +00002524 binop(Iop_Shl64,
sewardj5b470602005-02-27 13:10:48 +00002525 getIReg64rexX(pfx,index_r), mkU8(scale))),
sewardj2f959cc2005-01-26 01:19:35 +00002526 mkU64(d))));
2527 }
sewardj3ca55a12005-01-27 16:06:23 +00002528 vassert(0); /*NOTREACHED*/
sewardj2f959cc2005-01-26 01:19:35 +00002529 }
2530
sewardjb3a04292005-01-21 20:33:44 +00002531 default:
2532 vpanic("disAMode(amd64)");
2533 return 0; /*notreached*/
2534 }
2535}
2536
2537
sewardj3ca55a12005-01-27 16:06:23 +00002538/* Figure out the number of (insn-stream) bytes constituting the amode
2539 beginning at delta. Is useful for getting hold of literals beyond
2540 the end of the amode before it has been disassembled. */
2541
sewardj270def42005-07-03 01:03:01 +00002542static UInt lengthAMode ( Prefix pfx, Long delta )
sewardj3ca55a12005-01-27 16:06:23 +00002543{
sewardj8c332e22005-01-28 01:36:56 +00002544 UChar mod_reg_rm = getUChar(delta);
sewardj3ca55a12005-01-27 16:06:23 +00002545 delta++;
2546
2547 /* squeeze out the reg field from mod_reg_rm, since a 256-entry
2548 jump table seems a bit excessive.
2549 */
sewardj7a240552005-01-28 21:37:12 +00002550 mod_reg_rm &= 0xC7; /* is now XX000YYY */
sewardj1027dc22005-02-26 01:55:02 +00002551 mod_reg_rm = toUChar(mod_reg_rm | (mod_reg_rm >> 3));
2552 /* is now XX0XXYYY */
sewardj7a240552005-01-28 21:37:12 +00002553 mod_reg_rm &= 0x1F; /* is now 000XXYYY */
sewardj3ca55a12005-01-27 16:06:23 +00002554 switch (mod_reg_rm) {
2555
2556 /* REX.B==0: (%rax) .. (%rdi), not including (%rsp) or (%rbp).
2557 REX.B==1: (%r8) .. (%r15), not including (%r12) or (%r13).
2558 */
2559 case 0x00: case 0x01: case 0x02: case 0x03:
2560 /* ! 04 */ /* ! 05 */ case 0x06: case 0x07:
sewardj3ca55a12005-01-27 16:06:23 +00002561 return 1;
2562
2563 /* REX.B==0: d8(%rax) ... d8(%rdi), not including d8(%rsp)
2564 REX.B==1: d8(%r8) ... d8(%r15), not including d8(%r12)
2565 */
2566 case 0x08: case 0x09: case 0x0A: case 0x0B:
2567 /* ! 0C */ case 0x0D: case 0x0E: case 0x0F:
sewardj3ca55a12005-01-27 16:06:23 +00002568 return 2;
2569
2570 /* REX.B==0: d32(%rax) ... d32(%rdi), not including d32(%rsp)
2571 REX.B==1: d32(%r8) ... d32(%r15), not including d32(%r12)
2572 */
2573 case 0x10: case 0x11: case 0x12: case 0x13:
2574 /* ! 14 */ case 0x15: case 0x16: case 0x17:
sewardj3ca55a12005-01-27 16:06:23 +00002575 return 5;
2576
2577 /* REX.B==0: a register, %rax .. %rdi. This shouldn't happen. */
2578 /* REX.B==1: a register, %r8 .. %r16. This shouldn't happen. */
2579 /* Not an address, but still handled. */
2580 case 0x18: case 0x19: case 0x1A: case 0x1B:
2581 case 0x1C: case 0x1D: case 0x1E: case 0x1F:
2582 return 1;
2583
2584 /* RIP + disp32. */
2585 case 0x05:
sewardj3ca55a12005-01-27 16:06:23 +00002586 return 5;
2587
2588 case 0x04: {
2589 /* SIB, with no displacement. */
sewardj8c332e22005-01-28 01:36:56 +00002590 UChar sib = getUChar(delta);
sewardj1027dc22005-02-26 01:55:02 +00002591 UChar base_r = toUChar(sib & 7);
sewardj3ca55a12005-01-27 16:06:23 +00002592 /* correct since #(R13) == 8 + #(RBP) */
sewardj7a240552005-01-28 21:37:12 +00002593 Bool base_is_BPor13 = toBool(base_r == R_RBP);
sewardj3ca55a12005-01-27 16:06:23 +00002594
2595 if (base_is_BPor13) {
sewardj3ca55a12005-01-27 16:06:23 +00002596 return 6;
2597 } else {
sewardj3ca55a12005-01-27 16:06:23 +00002598 return 2;
2599 }
2600 }
2601
2602 /* SIB, with 8-bit displacement. */
2603 case 0x0C:
2604 return 3;
2605
2606 /* SIB, with 32-bit displacement. */
2607 case 0x14:
2608 return 6;
2609
2610 default:
2611 vpanic("lengthAMode(amd64)");
2612 return 0; /*notreached*/
2613 }
2614}
2615
2616
sewardjdf0e0022005-01-25 15:48:43 +00002617/*------------------------------------------------------------*/
2618/*--- Disassembling common idioms ---*/
2619/*------------------------------------------------------------*/
2620
sewardjdf0e0022005-01-25 15:48:43 +00002621/* Handle binary integer instructions of the form
2622 op E, G meaning
2623 op reg-or-mem, reg
2624 Is passed the a ptr to the modRM byte, the actual operation, and the
2625 data size. Returns the address advanced completely over this
2626 instruction.
2627
2628 E(src) is reg-or-mem
2629 G(dst) is reg.
2630
2631 If E is reg, --> GET %G, tmp
2632 OP %E, tmp
2633 PUT tmp, %G
2634
2635 If E is mem and OP is not reversible,
2636 --> (getAddr E) -> tmpa
2637 LD (tmpa), tmpa
2638 GET %G, tmp2
2639 OP tmpa, tmp2
2640 PUT tmp2, %G
2641
2642 If E is mem and OP is reversible
2643 --> (getAddr E) -> tmpa
2644 LD (tmpa), tmpa
2645 OP %G, tmpa
2646 PUT tmpa, %G
2647*/
2648static
sewardj2e28ac42008-12-04 00:05:12 +00002649ULong dis_op2_E_G ( VexAbiInfo* vbi,
2650 Prefix pfx,
sewardjdf0e0022005-01-25 15:48:43 +00002651 Bool addSubCarry,
2652 IROp op8,
2653 Bool keep,
2654 Int size,
sewardj270def42005-07-03 01:03:01 +00002655 Long delta0,
sewardj8c332e22005-01-28 01:36:56 +00002656 HChar* t_amd64opc )
sewardjdf0e0022005-01-25 15:48:43 +00002657{
2658 HChar dis_buf[50];
2659 Int len;
2660 IRType ty = szToITy(size);
2661 IRTemp dst1 = newTemp(ty);
2662 IRTemp src = newTemp(ty);
2663 IRTemp dst0 = newTemp(ty);
2664 UChar rm = getUChar(delta0);
2665 IRTemp addr = IRTemp_INVALID;
2666
2667 /* addSubCarry == True indicates the intended operation is
2668 add-with-carry or subtract-with-borrow. */
2669 if (addSubCarry) {
2670 vassert(op8 == Iop_Add8 || op8 == Iop_Sub8);
2671 vassert(keep);
2672 }
2673
2674 if (epartIsReg(rm)) {
sewardjdf0e0022005-01-25 15:48:43 +00002675 /* Specially handle XOR reg,reg, because that doesn't really
2676 depend on reg, and doing the obvious thing potentially
2677 generates a spurious value check failure due to the bogus
2678 dependency. */
sewardj5b470602005-02-27 13:10:48 +00002679 if ((op8 == Iop_Xor8 || (op8 == Iop_Sub8 && addSubCarry))
2680 && offsetIRegG(size,pfx,rm) == offsetIRegE(size,pfx,rm)) {
sewardj4f9847d2005-07-25 11:58:34 +00002681 if (False && op8 == Iop_Sub8)
sewardj5b470602005-02-27 13:10:48 +00002682 vex_printf("vex amd64->IR: sbb %%r,%%r optimisation(1)\n");
2683 putIRegG(size,pfx,rm, mkU(ty,0));
sewardjdf0e0022005-01-25 15:48:43 +00002684 }
sewardj5b470602005-02-27 13:10:48 +00002685
2686 assign( dst0, getIRegG(size,pfx,rm) );
2687 assign( src, getIRegE(size,pfx,rm) );
sewardjdf0e0022005-01-25 15:48:43 +00002688
2689 if (addSubCarry && op8 == Iop_Add8) {
sewardje9d8a262009-07-01 08:06:34 +00002690 helper_ADC( size, dst1, dst0, src,
2691 /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
sewardj5b470602005-02-27 13:10:48 +00002692 putIRegG(size, pfx, rm, mkexpr(dst1));
sewardjdf0e0022005-01-25 15:48:43 +00002693 } else
2694 if (addSubCarry && op8 == Iop_Sub8) {
sewardje9d8a262009-07-01 08:06:34 +00002695 helper_SBB( size, dst1, dst0, src,
2696 /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
sewardj5b470602005-02-27 13:10:48 +00002697 putIRegG(size, pfx, rm, mkexpr(dst1));
sewardjdf0e0022005-01-25 15:48:43 +00002698 } else {
2699 assign( dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
2700 if (isAddSub(op8))
2701 setFlags_DEP1_DEP2(op8, dst0, src, ty);
2702 else
2703 setFlags_DEP1(op8, dst1, ty);
2704 if (keep)
sewardj5b470602005-02-27 13:10:48 +00002705 putIRegG(size, pfx, rm, mkexpr(dst1));
sewardjdf0e0022005-01-25 15:48:43 +00002706 }
2707
2708 DIP("%s%c %s,%s\n", t_amd64opc, nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00002709 nameIRegE(size,pfx,rm),
2710 nameIRegG(size,pfx,rm));
sewardjdf0e0022005-01-25 15:48:43 +00002711 return 1+delta0;
2712 } else {
2713 /* E refers to memory */
sewardj2e28ac42008-12-04 00:05:12 +00002714 addr = disAMode ( &len, vbi, pfx, delta0, dis_buf, 0 );
sewardj5b470602005-02-27 13:10:48 +00002715 assign( dst0, getIRegG(size,pfx,rm) );
sewardjdf0e0022005-01-25 15:48:43 +00002716 assign( src, loadLE(szToITy(size), mkexpr(addr)) );
2717
2718 if (addSubCarry && op8 == Iop_Add8) {
sewardje9d8a262009-07-01 08:06:34 +00002719 helper_ADC( size, dst1, dst0, src,
2720 /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
sewardj5b470602005-02-27 13:10:48 +00002721 putIRegG(size, pfx, rm, mkexpr(dst1));
sewardjdf0e0022005-01-25 15:48:43 +00002722 } else
2723 if (addSubCarry && op8 == Iop_Sub8) {
sewardje9d8a262009-07-01 08:06:34 +00002724 helper_SBB( size, dst1, dst0, src,
2725 /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
sewardj5b470602005-02-27 13:10:48 +00002726 putIRegG(size, pfx, rm, mkexpr(dst1));
sewardjdf0e0022005-01-25 15:48:43 +00002727 } else {
2728 assign( dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
2729 if (isAddSub(op8))
2730 setFlags_DEP1_DEP2(op8, dst0, src, ty);
2731 else
2732 setFlags_DEP1(op8, dst1, ty);
2733 if (keep)
sewardj5b470602005-02-27 13:10:48 +00002734 putIRegG(size, pfx, rm, mkexpr(dst1));
sewardjdf0e0022005-01-25 15:48:43 +00002735 }
2736
2737 DIP("%s%c %s,%s\n", t_amd64opc, nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00002738 dis_buf, nameIRegG(size, pfx, rm));
sewardjdf0e0022005-01-25 15:48:43 +00002739 return len+delta0;
2740 }
2741}
2742
2743
2744
sewardj3ca55a12005-01-27 16:06:23 +00002745/* Handle binary integer instructions of the form
2746 op G, E meaning
2747 op reg, reg-or-mem
2748 Is passed the a ptr to the modRM byte, the actual operation, and the
2749 data size. Returns the address advanced completely over this
2750 instruction.
2751
2752 G(src) is reg.
2753 E(dst) is reg-or-mem
2754
2755 If E is reg, --> GET %E, tmp
2756 OP %G, tmp
2757 PUT tmp, %E
2758
2759 If E is mem, --> (getAddr E) -> tmpa
2760 LD (tmpa), tmpv
2761 OP %G, tmpv
2762 ST tmpv, (tmpa)
2763*/
2764static
sewardj2e28ac42008-12-04 00:05:12 +00002765ULong dis_op2_G_E ( VexAbiInfo* vbi,
2766 Prefix pfx,
sewardj8c332e22005-01-28 01:36:56 +00002767 Bool addSubCarry,
2768 IROp op8,
2769 Bool keep,
2770 Int size,
sewardj270def42005-07-03 01:03:01 +00002771 Long delta0,
sewardj8c332e22005-01-28 01:36:56 +00002772 HChar* t_amd64opc )
sewardj3ca55a12005-01-27 16:06:23 +00002773{
2774 HChar dis_buf[50];
2775 Int len;
2776 IRType ty = szToITy(size);
2777 IRTemp dst1 = newTemp(ty);
2778 IRTemp src = newTemp(ty);
2779 IRTemp dst0 = newTemp(ty);
sewardj8c332e22005-01-28 01:36:56 +00002780 UChar rm = getUChar(delta0);
sewardj3ca55a12005-01-27 16:06:23 +00002781 IRTemp addr = IRTemp_INVALID;
2782
2783 /* addSubCarry == True indicates the intended operation is
2784 add-with-carry or subtract-with-borrow. */
2785 if (addSubCarry) {
2786 vassert(op8 == Iop_Add8 || op8 == Iop_Sub8);
2787 vassert(keep);
2788 }
2789
2790 if (epartIsReg(rm)) {
2791 /* Specially handle XOR reg,reg, because that doesn't really
2792 depend on reg, and doing the obvious thing potentially
2793 generates a spurious value check failure due to the bogus
sewardj5b470602005-02-27 13:10:48 +00002794 dependency. Ditto SBB reg,reg. */
2795 if ((op8 == Iop_Xor8 || (op8 == Iop_Sub8 && addSubCarry))
2796 && offsetIRegG(size,pfx,rm) == offsetIRegE(size,pfx,rm)) {
2797 putIRegE(size,pfx,rm, mkU(ty,0));
sewardj3ca55a12005-01-27 16:06:23 +00002798 }
sewardj5b470602005-02-27 13:10:48 +00002799
2800 assign(dst0, getIRegE(size,pfx,rm));
2801 assign(src, getIRegG(size,pfx,rm));
sewardj3ca55a12005-01-27 16:06:23 +00002802
2803 if (addSubCarry && op8 == Iop_Add8) {
sewardje9d8a262009-07-01 08:06:34 +00002804 helper_ADC( size, dst1, dst0, src,
2805 /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
sewardj5b470602005-02-27 13:10:48 +00002806 putIRegE(size, pfx, rm, mkexpr(dst1));
sewardj3ca55a12005-01-27 16:06:23 +00002807 } else
2808 if (addSubCarry && op8 == Iop_Sub8) {
sewardje9d8a262009-07-01 08:06:34 +00002809 helper_SBB( size, dst1, dst0, src,
2810 /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
sewardj5b470602005-02-27 13:10:48 +00002811 putIRegE(size, pfx, rm, mkexpr(dst1));
sewardj3ca55a12005-01-27 16:06:23 +00002812 } else {
2813 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
2814 if (isAddSub(op8))
2815 setFlags_DEP1_DEP2(op8, dst0, src, ty);
2816 else
2817 setFlags_DEP1(op8, dst1, ty);
2818 if (keep)
sewardj5b470602005-02-27 13:10:48 +00002819 putIRegE(size, pfx, rm, mkexpr(dst1));
sewardj3ca55a12005-01-27 16:06:23 +00002820 }
2821
2822 DIP("%s%c %s,%s\n", t_amd64opc, nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00002823 nameIRegG(size,pfx,rm),
2824 nameIRegE(size,pfx,rm));
sewardj3ca55a12005-01-27 16:06:23 +00002825 return 1+delta0;
2826 }
2827
2828 /* E refers to memory */
2829 {
sewardj2e28ac42008-12-04 00:05:12 +00002830 addr = disAMode ( &len, vbi, pfx, delta0, dis_buf, 0 );
sewardj3ca55a12005-01-27 16:06:23 +00002831 assign(dst0, loadLE(ty,mkexpr(addr)));
sewardj5b470602005-02-27 13:10:48 +00002832 assign(src, getIRegG(size,pfx,rm));
sewardj3ca55a12005-01-27 16:06:23 +00002833
2834 if (addSubCarry && op8 == Iop_Add8) {
sewardje9d8a262009-07-01 08:06:34 +00002835 if (pfx & PFX_LOCK) {
2836 /* cas-style store */
2837 helper_ADC( size, dst1, dst0, src,
2838 /*store*/addr, dst0/*expVal*/, guest_RIP_curr_instr );
2839 } else {
2840 /* normal store */
2841 helper_ADC( size, dst1, dst0, src,
2842 /*store*/addr, IRTemp_INVALID, 0 );
2843 }
sewardj3ca55a12005-01-27 16:06:23 +00002844 } else
2845 if (addSubCarry && op8 == Iop_Sub8) {
sewardje9d8a262009-07-01 08:06:34 +00002846 if (pfx & PFX_LOCK) {
2847 /* cas-style store */
2848 helper_SBB( size, dst1, dst0, src,
2849 /*store*/addr, dst0/*expVal*/, guest_RIP_curr_instr );
2850 } else {
2851 /* normal store */
2852 helper_SBB( size, dst1, dst0, src,
2853 /*store*/addr, IRTemp_INVALID, 0 );
2854 }
sewardj3ca55a12005-01-27 16:06:23 +00002855 } else {
2856 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
sewardje9d8a262009-07-01 08:06:34 +00002857 if (keep) {
2858 if (pfx & PFX_LOCK) {
2859 if (0) vex_printf("locked case\n" );
2860 casLE( mkexpr(addr),
2861 mkexpr(dst0)/*expval*/,
2862 mkexpr(dst1)/*newval*/, guest_RIP_curr_instr );
2863 } else {
2864 if (0) vex_printf("nonlocked case\n");
2865 storeLE(mkexpr(addr), mkexpr(dst1));
2866 }
2867 }
sewardj3ca55a12005-01-27 16:06:23 +00002868 if (isAddSub(op8))
2869 setFlags_DEP1_DEP2(op8, dst0, src, ty);
2870 else
2871 setFlags_DEP1(op8, dst1, ty);
sewardj3ca55a12005-01-27 16:06:23 +00002872 }
2873
2874 DIP("%s%c %s,%s\n", t_amd64opc, nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00002875 nameIRegG(size,pfx,rm), dis_buf);
sewardj3ca55a12005-01-27 16:06:23 +00002876 return len+delta0;
2877 }
2878}
2879
2880
sewardj1389d4d2005-01-28 13:46:29 +00002881/* Handle move instructions of the form
2882 mov E, G meaning
2883 mov reg-or-mem, reg
2884 Is passed the a ptr to the modRM byte, and the data size. Returns
2885 the address advanced completely over this instruction.
2886
2887 E(src) is reg-or-mem
2888 G(dst) is reg.
2889
2890 If E is reg, --> GET %E, tmpv
2891 PUT tmpv, %G
2892
2893 If E is mem --> (getAddr E) -> tmpa
2894 LD (tmpa), tmpb
2895 PUT tmpb, %G
2896*/
2897static
sewardj2e28ac42008-12-04 00:05:12 +00002898ULong dis_mov_E_G ( VexAbiInfo* vbi,
2899 Prefix pfx,
sewardj1389d4d2005-01-28 13:46:29 +00002900 Int size,
sewardj270def42005-07-03 01:03:01 +00002901 Long delta0 )
sewardj1389d4d2005-01-28 13:46:29 +00002902{
2903 Int len;
2904 UChar rm = getUChar(delta0);
2905 HChar dis_buf[50];
2906
2907 if (epartIsReg(rm)) {
sewardj5b470602005-02-27 13:10:48 +00002908 putIRegG(size, pfx, rm, getIRegE(size, pfx, rm));
sewardje941eea2005-01-30 19:52:28 +00002909 DIP("mov%c %s,%s\n", nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00002910 nameIRegE(size,pfx,rm),
2911 nameIRegG(size,pfx,rm));
sewardj1389d4d2005-01-28 13:46:29 +00002912 return 1+delta0;
2913 }
2914
2915 /* E refers to memory */
2916 {
sewardj2e28ac42008-12-04 00:05:12 +00002917 IRTemp addr = disAMode ( &len, vbi, pfx, delta0, dis_buf, 0 );
sewardj5b470602005-02-27 13:10:48 +00002918 putIRegG(size, pfx, rm, loadLE(szToITy(size), mkexpr(addr)));
sewardj1389d4d2005-01-28 13:46:29 +00002919 DIP("mov%c %s,%s\n", nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00002920 dis_buf,
2921 nameIRegG(size,pfx,rm));
sewardj1389d4d2005-01-28 13:46:29 +00002922 return delta0+len;
2923 }
2924}
2925
2926
2927/* Handle move instructions of the form
2928 mov G, E meaning
2929 mov reg, reg-or-mem
2930 Is passed the a ptr to the modRM byte, and the data size. Returns
2931 the address advanced completely over this instruction.
2932
2933 G(src) is reg.
2934 E(dst) is reg-or-mem
2935
2936 If E is reg, --> GET %G, tmp
2937 PUT tmp, %E
2938
2939 If E is mem, --> (getAddr E) -> tmpa
2940 GET %G, tmpv
2941 ST tmpv, (tmpa)
2942*/
2943static
sewardj2e28ac42008-12-04 00:05:12 +00002944ULong dis_mov_G_E ( VexAbiInfo* vbi,
2945 Prefix pfx,
sewardj1389d4d2005-01-28 13:46:29 +00002946 Int size,
sewardj270def42005-07-03 01:03:01 +00002947 Long delta0 )
sewardj1389d4d2005-01-28 13:46:29 +00002948{
2949 Int len;
2950 UChar rm = getUChar(delta0);
2951 HChar dis_buf[50];
2952
2953 if (epartIsReg(rm)) {
sewardj5b470602005-02-27 13:10:48 +00002954 putIRegE(size, pfx, rm, getIRegG(size, pfx, rm));
sewardje941eea2005-01-30 19:52:28 +00002955 DIP("mov%c %s,%s\n", nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00002956 nameIRegG(size,pfx,rm),
2957 nameIRegE(size,pfx,rm));
sewardj1389d4d2005-01-28 13:46:29 +00002958 return 1+delta0;
2959 }
2960
2961 /* E refers to memory */
2962 {
sewardj2e28ac42008-12-04 00:05:12 +00002963 IRTemp addr = disAMode ( &len, vbi, pfx, delta0, dis_buf, 0 );
sewardj5b470602005-02-27 13:10:48 +00002964 storeLE( mkexpr(addr), getIRegG(size, pfx, rm) );
sewardj1389d4d2005-01-28 13:46:29 +00002965 DIP("mov%c %s,%s\n", nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00002966 nameIRegG(size,pfx,rm),
2967 dis_buf);
sewardj1389d4d2005-01-28 13:46:29 +00002968 return len+delta0;
2969 }
2970}
sewardj3ca55a12005-01-27 16:06:23 +00002971
2972
2973/* op $immediate, AL/AX/EAX/RAX. */
2974static
sewardj8c332e22005-01-28 01:36:56 +00002975ULong dis_op_imm_A ( Int size,
sewardj41c01092005-07-23 13:50:32 +00002976 Bool carrying,
sewardj8c332e22005-01-28 01:36:56 +00002977 IROp op8,
2978 Bool keep,
sewardj270def42005-07-03 01:03:01 +00002979 Long delta,
sewardj8c332e22005-01-28 01:36:56 +00002980 HChar* t_amd64opc )
sewardj3ca55a12005-01-27 16:06:23 +00002981{
2982 Int size4 = imin(size,4);
2983 IRType ty = szToITy(size);
2984 IRTemp dst0 = newTemp(ty);
2985 IRTemp src = newTemp(ty);
2986 IRTemp dst1 = newTemp(ty);
sewardj8c332e22005-01-28 01:36:56 +00002987 Long lit = getSDisp(size4,delta);
sewardj5b470602005-02-27 13:10:48 +00002988 assign(dst0, getIRegRAX(size));
sewardj1389d4d2005-01-28 13:46:29 +00002989 assign(src, mkU(ty,lit & mkSizeMask(size)));
sewardj41c01092005-07-23 13:50:32 +00002990
2991 if (isAddSub(op8) && !carrying) {
2992 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
sewardj3ca55a12005-01-27 16:06:23 +00002993 setFlags_DEP1_DEP2(op8, dst0, src, ty);
sewardj41c01092005-07-23 13:50:32 +00002994 }
sewardj3ca55a12005-01-27 16:06:23 +00002995 else
sewardj41c01092005-07-23 13:50:32 +00002996 if (isLogic(op8)) {
2997 vassert(!carrying);
2998 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
sewardj3ca55a12005-01-27 16:06:23 +00002999 setFlags_DEP1(op8, dst1, ty);
sewardj41c01092005-07-23 13:50:32 +00003000 }
sewardj3ca55a12005-01-27 16:06:23 +00003001 else
sewardj41c01092005-07-23 13:50:32 +00003002 if (op8 == Iop_Add8 && carrying) {
sewardje9d8a262009-07-01 08:06:34 +00003003 helper_ADC( size, dst1, dst0, src,
3004 /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
sewardj41c01092005-07-23 13:50:32 +00003005 }
3006 else
sewardj5fadaf92006-05-12 20:45:59 +00003007 if (op8 == Iop_Sub8 && carrying) {
sewardje9d8a262009-07-01 08:06:34 +00003008 helper_SBB( size, dst1, dst0, src,
3009 /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
sewardj5fadaf92006-05-12 20:45:59 +00003010 }
3011 else
sewardj41c01092005-07-23 13:50:32 +00003012 vpanic("dis_op_imm_A(amd64,guest)");
sewardj3ca55a12005-01-27 16:06:23 +00003013
3014 if (keep)
sewardj5b470602005-02-27 13:10:48 +00003015 putIRegRAX(size, mkexpr(dst1));
sewardj3ca55a12005-01-27 16:06:23 +00003016
3017 DIP("%s%c $%lld, %s\n", t_amd64opc, nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00003018 lit, nameIRegRAX(size));
sewardj3ca55a12005-01-27 16:06:23 +00003019 return delta+size4;
3020}
3021
3022
sewardj5e525292005-01-28 15:13:10 +00003023/* Sign- and Zero-extending moves. */
3024static
sewardj2e28ac42008-12-04 00:05:12 +00003025ULong dis_movx_E_G ( VexAbiInfo* vbi,
3026 Prefix pfx,
sewardj270def42005-07-03 01:03:01 +00003027 Long delta, Int szs, Int szd, Bool sign_extend )
sewardj5e525292005-01-28 15:13:10 +00003028{
3029 UChar rm = getUChar(delta);
3030 if (epartIsReg(rm)) {
sewardj5b470602005-02-27 13:10:48 +00003031 putIRegG(szd, pfx, rm,
sewardj5e525292005-01-28 15:13:10 +00003032 doScalarWidening(
3033 szs,szd,sign_extend,
sewardj5b470602005-02-27 13:10:48 +00003034 getIRegE(szs,pfx,rm)));
sewardj5e525292005-01-28 15:13:10 +00003035 DIP("mov%c%c%c %s,%s\n", sign_extend ? 's' : 'z',
3036 nameISize(szs),
3037 nameISize(szd),
sewardj5b470602005-02-27 13:10:48 +00003038 nameIRegE(szs,pfx,rm),
3039 nameIRegG(szd,pfx,rm));
sewardj5e525292005-01-28 15:13:10 +00003040 return 1+delta;
3041 }
3042
3043 /* E refers to memory */
3044 {
3045 Int len;
3046 HChar dis_buf[50];
sewardj2e28ac42008-12-04 00:05:12 +00003047 IRTemp addr = disAMode ( &len, vbi, pfx, delta, dis_buf, 0 );
sewardj5b470602005-02-27 13:10:48 +00003048 putIRegG(szd, pfx, rm,
sewardj5e525292005-01-28 15:13:10 +00003049 doScalarWidening(
3050 szs,szd,sign_extend,
3051 loadLE(szToITy(szs),mkexpr(addr))));
3052 DIP("mov%c%c%c %s,%s\n", sign_extend ? 's' : 'z',
3053 nameISize(szs),
3054 nameISize(szd),
3055 dis_buf,
sewardj5b470602005-02-27 13:10:48 +00003056 nameIRegG(szd,pfx,rm));
sewardj5e525292005-01-28 15:13:10 +00003057 return len+delta;
3058 }
3059}
sewardj32b2bbe2005-01-28 00:50:10 +00003060
3061
sewardj03b07cc2005-01-31 18:09:43 +00003062/* Generate code to divide ArchRegs RDX:RAX / EDX:EAX / DX:AX / AX by
3063 the 64 / 32 / 16 / 8 bit quantity in the given IRTemp. */
sewardj32b2bbe2005-01-28 00:50:10 +00003064static
3065void codegen_div ( Int sz, IRTemp t, Bool signed_divide )
3066{
sewardj03b07cc2005-01-31 18:09:43 +00003067 /* special-case the 64-bit case */
3068 if (sz == 8) {
3069 IROp op = signed_divide ? Iop_DivModS128to64
3070 : Iop_DivModU128to64;
sewardja6b93d12005-02-17 09:28:28 +00003071 IRTemp src128 = newTemp(Ity_I128);
3072 IRTemp dst128 = newTemp(Ity_I128);
sewardj03b07cc2005-01-31 18:09:43 +00003073 assign( src128, binop(Iop_64HLto128,
sewardja6b93d12005-02-17 09:28:28 +00003074 getIReg64(R_RDX),
3075 getIReg64(R_RAX)) );
sewardj03b07cc2005-01-31 18:09:43 +00003076 assign( dst128, binop(op, mkexpr(src128), mkexpr(t)) );
sewardja6b93d12005-02-17 09:28:28 +00003077 putIReg64( R_RAX, unop(Iop_128to64,mkexpr(dst128)) );
3078 putIReg64( R_RDX, unop(Iop_128HIto64,mkexpr(dst128)) );
sewardj03b07cc2005-01-31 18:09:43 +00003079 } else {
3080 IROp op = signed_divide ? Iop_DivModS64to32
3081 : Iop_DivModU64to32;
3082 IRTemp src64 = newTemp(Ity_I64);
3083 IRTemp dst64 = newTemp(Ity_I64);
3084 switch (sz) {
sewardj85520e42005-02-19 15:22:38 +00003085 case 4:
sewardj5b470602005-02-27 13:10:48 +00003086 assign( src64,
3087 binop(Iop_32HLto64, getIRegRDX(4), getIRegRAX(4)) );
3088 assign( dst64,
3089 binop(op, mkexpr(src64), mkexpr(t)) );
3090 putIRegRAX( 4, unop(Iop_64to32,mkexpr(dst64)) );
3091 putIRegRDX( 4, unop(Iop_64HIto32,mkexpr(dst64)) );
sewardj85520e42005-02-19 15:22:38 +00003092 break;
3093 case 2: {
3094 IROp widen3264 = signed_divide ? Iop_32Sto64 : Iop_32Uto64;
3095 IROp widen1632 = signed_divide ? Iop_16Sto32 : Iop_16Uto32;
3096 assign( src64, unop(widen3264,
3097 binop(Iop_16HLto32,
sewardj5b470602005-02-27 13:10:48 +00003098 getIRegRDX(2),
3099 getIRegRAX(2))) );
sewardj85520e42005-02-19 15:22:38 +00003100 assign( dst64, binop(op, mkexpr(src64), unop(widen1632,mkexpr(t))) );
sewardj5b470602005-02-27 13:10:48 +00003101 putIRegRAX( 2, unop(Iop_32to16,unop(Iop_64to32,mkexpr(dst64))) );
3102 putIRegRDX( 2, unop(Iop_32to16,unop(Iop_64HIto32,mkexpr(dst64))) );
sewardj85520e42005-02-19 15:22:38 +00003103 break;
3104 }
3105 case 1: {
3106 IROp widen3264 = signed_divide ? Iop_32Sto64 : Iop_32Uto64;
3107 IROp widen1632 = signed_divide ? Iop_16Sto32 : Iop_16Uto32;
3108 IROp widen816 = signed_divide ? Iop_8Sto16 : Iop_8Uto16;
3109 assign( src64, unop(widen3264,
sewardj5b470602005-02-27 13:10:48 +00003110 unop(widen1632, getIRegRAX(2))) );
sewardj85520e42005-02-19 15:22:38 +00003111 assign( dst64,
3112 binop(op, mkexpr(src64),
3113 unop(widen1632, unop(widen816, mkexpr(t)))) );
sewardj5b470602005-02-27 13:10:48 +00003114 putIRegRAX( 1, unop(Iop_16to8,
3115 unop(Iop_32to16,
3116 unop(Iop_64to32,mkexpr(dst64)))) );
3117 putIRegAH( unop(Iop_16to8,
3118 unop(Iop_32to16,
3119 unop(Iop_64HIto32,mkexpr(dst64)))) );
sewardj85520e42005-02-19 15:22:38 +00003120 break;
3121 }
3122 default:
3123 vpanic("codegen_div(amd64)");
sewardj03b07cc2005-01-31 18:09:43 +00003124 }
sewardj32b2bbe2005-01-28 00:50:10 +00003125 }
3126}
sewardj3ca55a12005-01-27 16:06:23 +00003127
3128static
sewardj2e28ac42008-12-04 00:05:12 +00003129ULong dis_Grp1 ( VexAbiInfo* vbi,
3130 Prefix pfx,
sewardj270def42005-07-03 01:03:01 +00003131 Long delta, UChar modrm,
sewardj227458e2005-01-31 19:04:50 +00003132 Int am_sz, Int d_sz, Int sz, Long d64 )
sewardj3ca55a12005-01-27 16:06:23 +00003133{
3134 Int len;
3135 HChar dis_buf[50];
3136 IRType ty = szToITy(sz);
3137 IRTemp dst1 = newTemp(ty);
3138 IRTemp src = newTemp(ty);
3139 IRTemp dst0 = newTemp(ty);
3140 IRTemp addr = IRTemp_INVALID;
3141 IROp op8 = Iop_INVALID;
sewardj1389d4d2005-01-28 13:46:29 +00003142 ULong mask = mkSizeMask(sz);
sewardj3ca55a12005-01-27 16:06:23 +00003143
sewardj901ed122005-02-27 13:25:31 +00003144 switch (gregLO3ofRM(modrm)) {
sewardj3ca55a12005-01-27 16:06:23 +00003145 case 0: op8 = Iop_Add8; break; case 1: op8 = Iop_Or8; break;
3146 case 2: break; // ADC
3147 case 3: break; // SBB
3148 case 4: op8 = Iop_And8; break; case 5: op8 = Iop_Sub8; break;
3149 case 6: op8 = Iop_Xor8; break; case 7: op8 = Iop_Sub8; break;
sewardjfd4203c2007-03-21 00:21:56 +00003150 /*NOTREACHED*/
sewardj3ca55a12005-01-27 16:06:23 +00003151 default: vpanic("dis_Grp1(amd64): unhandled case");
3152 }
3153
3154 if (epartIsReg(modrm)) {
3155 vassert(am_sz == 1);
3156
sewardj5b470602005-02-27 13:10:48 +00003157 assign(dst0, getIRegE(sz,pfx,modrm));
sewardj227458e2005-01-31 19:04:50 +00003158 assign(src, mkU(ty,d64 & mask));
sewardj3ca55a12005-01-27 16:06:23 +00003159
sewardj901ed122005-02-27 13:25:31 +00003160 if (gregLO3ofRM(modrm) == 2 /* ADC */) {
sewardje9d8a262009-07-01 08:06:34 +00003161 helper_ADC( sz, dst1, dst0, src,
3162 /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
sewardj3ca55a12005-01-27 16:06:23 +00003163 } else
sewardj901ed122005-02-27 13:25:31 +00003164 if (gregLO3ofRM(modrm) == 3 /* SBB */) {
sewardje9d8a262009-07-01 08:06:34 +00003165 helper_SBB( sz, dst1, dst0, src,
3166 /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
sewardj3ca55a12005-01-27 16:06:23 +00003167 } else {
3168 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
3169 if (isAddSub(op8))
3170 setFlags_DEP1_DEP2(op8, dst0, src, ty);
3171 else
3172 setFlags_DEP1(op8, dst1, ty);
3173 }
3174
sewardj901ed122005-02-27 13:25:31 +00003175 if (gregLO3ofRM(modrm) < 7)
sewardj5b470602005-02-27 13:10:48 +00003176 putIRegE(sz, pfx, modrm, mkexpr(dst1));
sewardj3ca55a12005-01-27 16:06:23 +00003177
3178 delta += (am_sz + d_sz);
sewardje941eea2005-01-30 19:52:28 +00003179 DIP("%s%c $%lld, %s\n",
sewardj901ed122005-02-27 13:25:31 +00003180 nameGrp1(gregLO3ofRM(modrm)), nameISize(sz), d64,
sewardj5b470602005-02-27 13:10:48 +00003181 nameIRegE(sz,pfx,modrm));
sewardj3ca55a12005-01-27 16:06:23 +00003182 } else {
sewardj2e28ac42008-12-04 00:05:12 +00003183 addr = disAMode ( &len, vbi, pfx, delta, dis_buf, /*xtra*/d_sz );
sewardj3ca55a12005-01-27 16:06:23 +00003184
3185 assign(dst0, loadLE(ty,mkexpr(addr)));
sewardj227458e2005-01-31 19:04:50 +00003186 assign(src, mkU(ty,d64 & mask));
sewardj3ca55a12005-01-27 16:06:23 +00003187
sewardj901ed122005-02-27 13:25:31 +00003188 if (gregLO3ofRM(modrm) == 2 /* ADC */) {
sewardje9d8a262009-07-01 08:06:34 +00003189 if (pfx & PFX_LOCK) {
3190 /* cas-style store */
3191 helper_ADC( sz, dst1, dst0, src,
3192 /*store*/addr, dst0/*expVal*/, guest_RIP_curr_instr );
3193 } else {
3194 /* normal store */
3195 helper_ADC( sz, dst1, dst0, src,
3196 /*store*/addr, IRTemp_INVALID, 0 );
3197 }
sewardj3ca55a12005-01-27 16:06:23 +00003198 } else
sewardj901ed122005-02-27 13:25:31 +00003199 if (gregLO3ofRM(modrm) == 3 /* SBB */) {
sewardje9d8a262009-07-01 08:06:34 +00003200 if (pfx & PFX_LOCK) {
3201 /* cas-style store */
3202 helper_SBB( sz, dst1, dst0, src,
3203 /*store*/addr, dst0/*expVal*/, guest_RIP_curr_instr );
3204 } else {
3205 /* normal store */
3206 helper_SBB( sz, dst1, dst0, src,
3207 /*store*/addr, IRTemp_INVALID, 0 );
3208 }
sewardj3ca55a12005-01-27 16:06:23 +00003209 } else {
3210 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
sewardje9d8a262009-07-01 08:06:34 +00003211 if (gregLO3ofRM(modrm) < 7) {
3212 if (pfx & PFX_LOCK) {
3213 casLE( mkexpr(addr), mkexpr(dst0)/*expVal*/,
3214 mkexpr(dst1)/*newVal*/,
3215 guest_RIP_curr_instr );
3216 } else {
3217 storeLE(mkexpr(addr), mkexpr(dst1));
3218 }
3219 }
sewardj3ca55a12005-01-27 16:06:23 +00003220 if (isAddSub(op8))
3221 setFlags_DEP1_DEP2(op8, dst0, src, ty);
3222 else
3223 setFlags_DEP1(op8, dst1, ty);
3224 }
3225
sewardj3ca55a12005-01-27 16:06:23 +00003226 delta += (len+d_sz);
sewardje941eea2005-01-30 19:52:28 +00003227 DIP("%s%c $%lld, %s\n",
sewardj901ed122005-02-27 13:25:31 +00003228 nameGrp1(gregLO3ofRM(modrm)), nameISize(sz),
sewardj227458e2005-01-31 19:04:50 +00003229 d64, dis_buf);
sewardj3ca55a12005-01-27 16:06:23 +00003230 }
3231 return delta;
3232}
3233
3234
sewardj118b23e2005-01-29 02:14:44 +00003235/* Group 2 extended opcodes. shift_expr must be an 8-bit typed
3236 expression. */
3237
3238static
sewardj2e28ac42008-12-04 00:05:12 +00003239ULong dis_Grp2 ( VexAbiInfo* vbi,
3240 Prefix pfx,
sewardj270def42005-07-03 01:03:01 +00003241 Long delta, UChar modrm,
sewardj118b23e2005-01-29 02:14:44 +00003242 Int am_sz, Int d_sz, Int sz, IRExpr* shift_expr,
sewardjfd4203c2007-03-21 00:21:56 +00003243 HChar* shift_expr_txt, Bool* decode_OK )
sewardj118b23e2005-01-29 02:14:44 +00003244{
3245 /* delta on entry points at the modrm byte. */
3246 HChar dis_buf[50];
3247 Int len;
sewardjb5e5c6d2007-01-12 20:29:01 +00003248 Bool isShift, isRotate, isRotateC;
sewardj118b23e2005-01-29 02:14:44 +00003249 IRType ty = szToITy(sz);
3250 IRTemp dst0 = newTemp(ty);
3251 IRTemp dst1 = newTemp(ty);
3252 IRTemp addr = IRTemp_INVALID;
3253
sewardjfd4203c2007-03-21 00:21:56 +00003254 *decode_OK = True;
3255
sewardj118b23e2005-01-29 02:14:44 +00003256 vassert(sz == 1 || sz == 2 || sz == 4 || sz == 8);
3257
3258 /* Put value to shift/rotate in dst0. */
3259 if (epartIsReg(modrm)) {
sewardj5b470602005-02-27 13:10:48 +00003260 assign(dst0, getIRegE(sz, pfx, modrm));
sewardj118b23e2005-01-29 02:14:44 +00003261 delta += (am_sz + d_sz);
3262 } else {
sewardj2e28ac42008-12-04 00:05:12 +00003263 addr = disAMode ( &len, vbi, pfx, delta, dis_buf, /*xtra*/d_sz );
sewardj118b23e2005-01-29 02:14:44 +00003264 assign(dst0, loadLE(ty,mkexpr(addr)));
3265 delta += len + d_sz;
3266 }
3267
3268 isShift = False;
sewardj901ed122005-02-27 13:25:31 +00003269 switch (gregLO3ofRM(modrm)) { case 4: case 5: case 7: isShift = True; }
sewardj118b23e2005-01-29 02:14:44 +00003270
3271 isRotate = False;
sewardj901ed122005-02-27 13:25:31 +00003272 switch (gregLO3ofRM(modrm)) { case 0: case 1: isRotate = True; }
sewardj118b23e2005-01-29 02:14:44 +00003273
sewardjb5e5c6d2007-01-12 20:29:01 +00003274 isRotateC = False;
3275 switch (gregLO3ofRM(modrm)) { case 2: case 3: isRotateC = True; }
sewardj118b23e2005-01-29 02:14:44 +00003276
sewardjfd4203c2007-03-21 00:21:56 +00003277 if (gregLO3ofRM(modrm) == 6) {
3278 *decode_OK = False;
3279 return delta;
3280 }
3281
sewardjb5e5c6d2007-01-12 20:29:01 +00003282 if (!isShift && !isRotate && !isRotateC) {
sewardjfd4203c2007-03-21 00:21:56 +00003283 /*NOTREACHED*/
sewardj118b23e2005-01-29 02:14:44 +00003284 vpanic("dis_Grp2(Reg): unhandled case(amd64)");
3285 }
3286
sewardjb5e5c6d2007-01-12 20:29:01 +00003287 if (isRotateC) {
sewardj112b0992005-07-23 13:19:32 +00003288 /* Call a helper; this insn is so ridiculous it does not deserve
3289 better. One problem is, the helper has to calculate both the
3290 new value and the new flags. This is more than 64 bits, and
3291 there is no way to return more than 64 bits from the helper.
3292 Hence the crude and obvious solution is to call it twice,
3293 using the sign of the sz field to indicate whether it is the
3294 value or rflags result we want.
3295 */
sewardjb5e5c6d2007-01-12 20:29:01 +00003296 Bool left = toBool(gregLO3ofRM(modrm) == 2);
sewardj112b0992005-07-23 13:19:32 +00003297 IRExpr** argsVALUE;
3298 IRExpr** argsRFLAGS;
3299
3300 IRTemp new_value = newTemp(Ity_I64);
3301 IRTemp new_rflags = newTemp(Ity_I64);
3302 IRTemp old_rflags = newTemp(Ity_I64);
3303
3304 assign( old_rflags, widenUto64(mk_amd64g_calculate_rflags_all()) );
3305
3306 argsVALUE
3307 = mkIRExprVec_4( widenUto64(mkexpr(dst0)), /* thing to rotate */
3308 widenUto64(shift_expr), /* rotate amount */
3309 mkexpr(old_rflags),
3310 mkU64(sz) );
3311 assign( new_value,
3312 mkIRExprCCall(
3313 Ity_I64,
3314 0/*regparm*/,
sewardjb5e5c6d2007-01-12 20:29:01 +00003315 left ? "amd64g_calculate_RCL" : "amd64g_calculate_RCR",
3316 left ? &amd64g_calculate_RCL : &amd64g_calculate_RCR,
sewardj112b0992005-07-23 13:19:32 +00003317 argsVALUE
3318 )
3319 );
3320
3321 argsRFLAGS
3322 = mkIRExprVec_4( widenUto64(mkexpr(dst0)), /* thing to rotate */
3323 widenUto64(shift_expr), /* rotate amount */
3324 mkexpr(old_rflags),
3325 mkU64(-sz) );
3326 assign( new_rflags,
3327 mkIRExprCCall(
3328 Ity_I64,
3329 0/*regparm*/,
sewardjb5e5c6d2007-01-12 20:29:01 +00003330 left ? "amd64g_calculate_RCL" : "amd64g_calculate_RCR",
3331 left ? &amd64g_calculate_RCL : &amd64g_calculate_RCR,
sewardj112b0992005-07-23 13:19:32 +00003332 argsRFLAGS
3333 )
3334 );
3335
3336 assign( dst1, narrowTo(ty, mkexpr(new_value)) );
3337 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(AMD64G_CC_OP_COPY) ));
3338 stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(new_rflags) ));
3339 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
3340 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU64(0) ));
sewardj118b23e2005-01-29 02:14:44 +00003341 }
3342
sewardj112b0992005-07-23 13:19:32 +00003343 else
sewardj118b23e2005-01-29 02:14:44 +00003344 if (isShift) {
3345
3346 IRTemp pre64 = newTemp(Ity_I64);
3347 IRTemp res64 = newTemp(Ity_I64);
3348 IRTemp res64ss = newTemp(Ity_I64);
3349 IRTemp shift_amt = newTemp(Ity_I8);
sewardj1027dc22005-02-26 01:55:02 +00003350 UChar mask = toUChar(sz==8 ? 63 : 31);
sewardj118b23e2005-01-29 02:14:44 +00003351 IROp op64;
3352
sewardj901ed122005-02-27 13:25:31 +00003353 switch (gregLO3ofRM(modrm)) {
sewardj118b23e2005-01-29 02:14:44 +00003354 case 4: op64 = Iop_Shl64; break;
3355 case 5: op64 = Iop_Shr64; break;
3356 case 7: op64 = Iop_Sar64; break;
sewardjfd4203c2007-03-21 00:21:56 +00003357 /*NOTREACHED*/
sewardj118b23e2005-01-29 02:14:44 +00003358 default: vpanic("dis_Grp2:shift"); break;
3359 }
3360
3361 /* Widen the value to be shifted to 64 bits, do the shift, and
3362 narrow back down. This seems surprisingly long-winded, but
3363 unfortunately the AMD semantics requires that 8/16/32-bit
3364 shifts give defined results for shift values all the way up
sewardj03c96e82005-02-19 18:12:45 +00003365 to 32, and this seems the simplest way to do it. It has the
sewardj118b23e2005-01-29 02:14:44 +00003366 advantage that the only IR level shifts generated are of 64
3367 bit values, and the shift amount is guaranteed to be in the
3368 range 0 .. 63, thereby observing the IR semantics requiring
sewardj03c96e82005-02-19 18:12:45 +00003369 all shift values to be in the range 0 .. 2^word_size-1.
sewardj118b23e2005-01-29 02:14:44 +00003370
sewardj03c96e82005-02-19 18:12:45 +00003371 Therefore the shift amount is masked with 63 for 64-bit shifts
3372 and 31 for all others.
3373 */
3374 /* shift_amt = shift_expr & MASK, regardless of operation size */
3375 assign( shift_amt, binop(Iop_And8, shift_expr, mkU8(mask)) );
sewardj118b23e2005-01-29 02:14:44 +00003376
sewardj03c96e82005-02-19 18:12:45 +00003377 /* suitably widen the value to be shifted to 64 bits. */
sewardj118b23e2005-01-29 02:14:44 +00003378 assign( pre64, op64==Iop_Sar64 ? widenSto64(mkexpr(dst0))
3379 : widenUto64(mkexpr(dst0)) );
3380
3381 /* res64 = pre64 `shift` shift_amt */
3382 assign( res64, binop(op64, mkexpr(pre64), mkexpr(shift_amt)) );
3383
sewardj03c96e82005-02-19 18:12:45 +00003384 /* res64ss = pre64 `shift` ((shift_amt - 1) & MASK) */
sewardj118b23e2005-01-29 02:14:44 +00003385 assign( res64ss,
3386 binop(op64,
3387 mkexpr(pre64),
3388 binop(Iop_And8,
3389 binop(Iop_Sub8,
3390 mkexpr(shift_amt), mkU8(1)),
sewardj03c96e82005-02-19 18:12:45 +00003391 mkU8(mask))) );
sewardj118b23e2005-01-29 02:14:44 +00003392
3393 /* Build the flags thunk. */
3394 setFlags_DEP1_DEP2_shift(op64, res64, res64ss, ty, shift_amt);
3395
3396 /* Narrow the result back down. */
3397 assign( dst1, narrowTo(ty, mkexpr(res64)) );
3398
3399 } /* if (isShift) */
3400
3401 else
3402 if (isRotate) {
3403 Int ccOp = ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1
3404 : (ty==Ity_I32 ? 2 : 3));
sewardj901ed122005-02-27 13:25:31 +00003405 Bool left = toBool(gregLO3ofRM(modrm) == 0);
sewardj118b23e2005-01-29 02:14:44 +00003406 IRTemp rot_amt = newTemp(Ity_I8);
3407 IRTemp rot_amt64 = newTemp(Ity_I8);
3408 IRTemp oldFlags = newTemp(Ity_I64);
sewardj1027dc22005-02-26 01:55:02 +00003409 UChar mask = toUChar(sz==8 ? 63 : 31);
sewardj118b23e2005-01-29 02:14:44 +00003410
3411 /* rot_amt = shift_expr & mask */
3412 /* By masking the rotate amount thusly, the IR-level Shl/Shr
3413 expressions never shift beyond the word size and thus remain
3414 well defined. */
sewardj03c96e82005-02-19 18:12:45 +00003415 assign(rot_amt64, binop(Iop_And8, shift_expr, mkU8(mask)));
sewardj118b23e2005-01-29 02:14:44 +00003416
3417 if (ty == Ity_I64)
3418 assign(rot_amt, mkexpr(rot_amt64));
3419 else
3420 assign(rot_amt, binop(Iop_And8, mkexpr(rot_amt64), mkU8(8*sz-1)));
3421
3422 if (left) {
3423
3424 /* dst1 = (dst0 << rot_amt) | (dst0 >>u (wordsize-rot_amt)) */
3425 assign(dst1,
3426 binop( mkSizedOp(ty,Iop_Or8),
3427 binop( mkSizedOp(ty,Iop_Shl8),
3428 mkexpr(dst0),
3429 mkexpr(rot_amt)
3430 ),
3431 binop( mkSizedOp(ty,Iop_Shr8),
3432 mkexpr(dst0),
3433 binop(Iop_Sub8,mkU8(8*sz), mkexpr(rot_amt))
3434 )
3435 )
3436 );
3437 ccOp += AMD64G_CC_OP_ROLB;
3438
3439 } else { /* right */
3440
3441 /* dst1 = (dst0 >>u rot_amt) | (dst0 << (wordsize-rot_amt)) */
3442 assign(dst1,
3443 binop( mkSizedOp(ty,Iop_Or8),
3444 binop( mkSizedOp(ty,Iop_Shr8),
3445 mkexpr(dst0),
3446 mkexpr(rot_amt)
3447 ),
3448 binop( mkSizedOp(ty,Iop_Shl8),
3449 mkexpr(dst0),
3450 binop(Iop_Sub8,mkU8(8*sz), mkexpr(rot_amt))
3451 )
3452 )
3453 );
3454 ccOp += AMD64G_CC_OP_RORB;
3455
3456 }
3457
3458 /* dst1 now holds the rotated value. Build flag thunk. We
3459 need the resulting value for this, and the previous flags.
3460 Except don't set it if the rotate count is zero. */
3461
3462 assign(oldFlags, mk_amd64g_calculate_rflags_all());
3463
3464 /* CC_DEP1 is the rotated value. CC_NDEP is flags before. */
3465 stmt( IRStmt_Put( OFFB_CC_OP,
3466 IRExpr_Mux0X( mkexpr(rot_amt64),
3467 IRExpr_Get(OFFB_CC_OP,Ity_I64),
3468 mkU64(ccOp))) );
3469 stmt( IRStmt_Put( OFFB_CC_DEP1,
3470 IRExpr_Mux0X( mkexpr(rot_amt64),
3471 IRExpr_Get(OFFB_CC_DEP1,Ity_I64),
3472 widenUto64(mkexpr(dst1)))) );
3473 stmt( IRStmt_Put( OFFB_CC_DEP2,
3474 IRExpr_Mux0X( mkexpr(rot_amt64),
3475 IRExpr_Get(OFFB_CC_DEP2,Ity_I64),
3476 mkU64(0))) );
3477 stmt( IRStmt_Put( OFFB_CC_NDEP,
3478 IRExpr_Mux0X( mkexpr(rot_amt64),
3479 IRExpr_Get(OFFB_CC_NDEP,Ity_I64),
3480 mkexpr(oldFlags))) );
3481 } /* if (isRotate) */
3482
3483 /* Save result, and finish up. */
3484 if (epartIsReg(modrm)) {
sewardj5b470602005-02-27 13:10:48 +00003485 putIRegE(sz, pfx, modrm, mkexpr(dst1));
sewardj118b23e2005-01-29 02:14:44 +00003486 if (vex_traceflags & VEX_TRACE_FE) {
3487 vex_printf("%s%c ",
sewardj901ed122005-02-27 13:25:31 +00003488 nameGrp2(gregLO3ofRM(modrm)), nameISize(sz) );
sewardj118b23e2005-01-29 02:14:44 +00003489 if (shift_expr_txt)
3490 vex_printf("%s", shift_expr_txt);
3491 else
3492 ppIRExpr(shift_expr);
sewardj5b470602005-02-27 13:10:48 +00003493 vex_printf(", %s\n", nameIRegE(sz,pfx,modrm));
sewardj118b23e2005-01-29 02:14:44 +00003494 }
3495 } else {
3496 storeLE(mkexpr(addr), mkexpr(dst1));
3497 if (vex_traceflags & VEX_TRACE_FE) {
3498 vex_printf("%s%c ",
sewardj901ed122005-02-27 13:25:31 +00003499 nameGrp2(gregLO3ofRM(modrm)), nameISize(sz) );
sewardj118b23e2005-01-29 02:14:44 +00003500 if (shift_expr_txt)
3501 vex_printf("%s", shift_expr_txt);
3502 else
3503 ppIRExpr(shift_expr);
3504 vex_printf(", %s\n", dis_buf);
3505 }
3506 }
3507 return delta;
3508}
3509
3510
sewardj1d511802005-03-27 17:59:45 +00003511/* Group 8 extended opcodes (but BT/BTS/BTC/BTR only). */
3512static
sewardj2e28ac42008-12-04 00:05:12 +00003513ULong dis_Grp8_Imm ( VexAbiInfo* vbi,
3514 Prefix pfx,
sewardj270def42005-07-03 01:03:01 +00003515 Long delta, UChar modrm,
sewardj1d511802005-03-27 17:59:45 +00003516 Int am_sz, Int sz, ULong src_val,
3517 Bool* decode_OK )
3518{
3519 /* src_val denotes a d8.
3520 And delta on entry points at the modrm byte. */
sewardj118b23e2005-01-29 02:14:44 +00003521
sewardj1d511802005-03-27 17:59:45 +00003522 IRType ty = szToITy(sz);
3523 IRTemp t2 = newTemp(Ity_I64);
3524 IRTemp t2m = newTemp(Ity_I64);
3525 IRTemp t_addr = IRTemp_INVALID;
3526 HChar dis_buf[50];
3527 ULong mask;
sewardj9b967672005-02-08 11:13:09 +00003528
sewardj1d511802005-03-27 17:59:45 +00003529 /* we're optimists :-) */
3530 *decode_OK = True;
3531
3532 /* Limit src_val -- the bit offset -- to something within a word.
3533 The Intel docs say that literal offsets larger than a word are
3534 masked in this way. */
3535 switch (sz) {
3536 case 2: src_val &= 15; break;
3537 case 4: src_val &= 31; break;
sewardj537cab02005-04-07 02:03:52 +00003538 case 8: src_val &= 63; break;
sewardj1d511802005-03-27 17:59:45 +00003539 default: *decode_OK = False; return delta;
3540 }
3541
3542 /* Invent a mask suitable for the operation. */
3543 switch (gregLO3ofRM(modrm)) {
sewardj74b4f892005-05-06 01:43:56 +00003544 case 4: /* BT */ mask = 0; break;
3545 case 5: /* BTS */ mask = 1ULL << src_val; break;
3546 case 6: /* BTR */ mask = ~(1ULL << src_val); break;
3547 case 7: /* BTC */ mask = 1ULL << src_val; break;
sewardj1d511802005-03-27 17:59:45 +00003548 /* If this needs to be extended, probably simplest to make a
3549 new function to handle the other cases (0 .. 3). The
3550 Intel docs do however not indicate any use for 0 .. 3, so
3551 we don't expect this to happen. */
3552 default: *decode_OK = False; return delta;
3553 }
3554
3555 /* Fetch the value to be tested and modified into t2, which is
3556 64-bits wide regardless of sz. */
3557 if (epartIsReg(modrm)) {
3558 vassert(am_sz == 1);
3559 assign( t2, widenUto64(getIRegE(sz, pfx, modrm)) );
3560 delta += (am_sz + 1);
3561 DIP("%s%c $0x%llx, %s\n", nameGrp8(gregLO3ofRM(modrm)),
3562 nameISize(sz),
3563 src_val, nameIRegE(sz,pfx,modrm));
3564 } else {
3565 Int len;
sewardj2e28ac42008-12-04 00:05:12 +00003566 t_addr = disAMode ( &len, vbi, pfx, delta, dis_buf, 1 );
sewardj1d511802005-03-27 17:59:45 +00003567 delta += (len+1);
3568 assign( t2, widenUto64(loadLE(ty, mkexpr(t_addr))) );
3569 DIP("%s%c $0x%llx, %s\n", nameGrp8(gregLO3ofRM(modrm)),
3570 nameISize(sz),
3571 src_val, dis_buf);
3572 }
3573
sewardj1d511802005-03-27 17:59:45 +00003574 /* Compute the new value into t2m, if non-BT. */
3575 switch (gregLO3ofRM(modrm)) {
3576 case 4: /* BT */
3577 break;
3578 case 5: /* BTS */
3579 assign( t2m, binop(Iop_Or64, mkU64(mask), mkexpr(t2)) );
3580 break;
3581 case 6: /* BTR */
3582 assign( t2m, binop(Iop_And64, mkU64(mask), mkexpr(t2)) );
3583 break;
3584 case 7: /* BTC */
3585 assign( t2m, binop(Iop_Xor64, mkU64(mask), mkexpr(t2)) );
3586 break;
3587 default:
sewardje9d8a262009-07-01 08:06:34 +00003588 /*NOTREACHED*/ /*the previous switch guards this*/
sewardj1d511802005-03-27 17:59:45 +00003589 vassert(0);
3590 }
3591
3592 /* Write the result back, if non-BT. */
3593 if (gregLO3ofRM(modrm) != 4 /* BT */) {
3594 if (epartIsReg(modrm)) {
3595 putIRegE(sz, pfx, modrm, narrowTo(ty, mkexpr(t2m)));
3596 } else {
sewardje9d8a262009-07-01 08:06:34 +00003597 if (pfx & PFX_LOCK) {
3598 casLE( mkexpr(t_addr),
3599 narrowTo(ty, mkexpr(t2))/*expd*/,
3600 narrowTo(ty, mkexpr(t2m))/*new*/,
3601 guest_RIP_curr_instr );
3602 } else {
3603 storeLE(mkexpr(t_addr), narrowTo(ty, mkexpr(t2m)));
3604 }
sewardj1d511802005-03-27 17:59:45 +00003605 }
3606 }
3607
sewardje9d8a262009-07-01 08:06:34 +00003608 /* Copy relevant bit from t2 into the carry flag. */
3609 /* Flags: C=selected bit, O,S,Z,A,P undefined, so are set to zero. */
3610 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(AMD64G_CC_OP_COPY) ));
3611 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
3612 stmt( IRStmt_Put(
3613 OFFB_CC_DEP1,
3614 binop(Iop_And64,
3615 binop(Iop_Shr64, mkexpr(t2), mkU8(src_val)),
3616 mkU64(1))
3617 ));
3618 /* Set NDEP even though it isn't used. This makes redundant-PUT
3619 elimination of previous stores to this field work better. */
3620 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU64(0) ));
3621
sewardj1d511802005-03-27 17:59:45 +00003622 return delta;
3623}
sewardj9b967672005-02-08 11:13:09 +00003624
3625
3626/* Signed/unsigned widening multiply. Generate IR to multiply the
3627 value in RAX/EAX/AX/AL by the given IRTemp, and park the result in
3628 RDX:RAX/EDX:EAX/DX:AX/AX.
3629*/
3630static void codegen_mulL_A_D ( Int sz, Bool syned,
sewardj1027dc22005-02-26 01:55:02 +00003631 IRTemp tmp, HChar* tmp_txt )
sewardj9b967672005-02-08 11:13:09 +00003632{
3633 IRType ty = szToITy(sz);
3634 IRTemp t1 = newTemp(ty);
3635
sewardj5b470602005-02-27 13:10:48 +00003636 assign( t1, getIRegRAX(sz) );
sewardj9b967672005-02-08 11:13:09 +00003637
3638 switch (ty) {
3639 case Ity_I64: {
3640 IRTemp res128 = newTemp(Ity_I128);
3641 IRTemp resHi = newTemp(Ity_I64);
3642 IRTemp resLo = newTemp(Ity_I64);
3643 IROp mulOp = syned ? Iop_MullS64 : Iop_MullU64;
sewardj8bdb89a2005-05-05 21:46:50 +00003644 UInt tBaseOp = syned ? AMD64G_CC_OP_SMULB : AMD64G_CC_OP_UMULB;
sewardj9b967672005-02-08 11:13:09 +00003645 setFlags_MUL ( Ity_I64, t1, tmp, tBaseOp );
3646 assign( res128, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
3647 assign( resHi, unop(Iop_128HIto64,mkexpr(res128)));
3648 assign( resLo, unop(Iop_128to64,mkexpr(res128)));
sewardj5b470602005-02-27 13:10:48 +00003649 putIReg64(R_RDX, mkexpr(resHi));
3650 putIReg64(R_RAX, mkexpr(resLo));
sewardj9b967672005-02-08 11:13:09 +00003651 break;
3652 }
sewardj85520e42005-02-19 15:22:38 +00003653 case Ity_I32: {
3654 IRTemp res64 = newTemp(Ity_I64);
3655 IRTemp resHi = newTemp(Ity_I32);
3656 IRTemp resLo = newTemp(Ity_I32);
3657 IROp mulOp = syned ? Iop_MullS32 : Iop_MullU32;
3658 UInt tBaseOp = syned ? AMD64G_CC_OP_SMULB : AMD64G_CC_OP_UMULB;
3659 setFlags_MUL ( Ity_I32, t1, tmp, tBaseOp );
3660 assign( res64, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
3661 assign( resHi, unop(Iop_64HIto32,mkexpr(res64)));
3662 assign( resLo, unop(Iop_64to32,mkexpr(res64)));
sewardj5b470602005-02-27 13:10:48 +00003663 putIRegRDX(4, mkexpr(resHi));
3664 putIRegRAX(4, mkexpr(resLo));
sewardj85520e42005-02-19 15:22:38 +00003665 break;
3666 }
3667 case Ity_I16: {
3668 IRTemp res32 = newTemp(Ity_I32);
3669 IRTemp resHi = newTemp(Ity_I16);
3670 IRTemp resLo = newTemp(Ity_I16);
3671 IROp mulOp = syned ? Iop_MullS16 : Iop_MullU16;
3672 UInt tBaseOp = syned ? AMD64G_CC_OP_SMULB : AMD64G_CC_OP_UMULB;
3673 setFlags_MUL ( Ity_I16, t1, tmp, tBaseOp );
3674 assign( res32, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
3675 assign( resHi, unop(Iop_32HIto16,mkexpr(res32)));
3676 assign( resLo, unop(Iop_32to16,mkexpr(res32)));
sewardj5b470602005-02-27 13:10:48 +00003677 putIRegRDX(2, mkexpr(resHi));
3678 putIRegRAX(2, mkexpr(resLo));
sewardj85520e42005-02-19 15:22:38 +00003679 break;
3680 }
3681 case Ity_I8: {
3682 IRTemp res16 = newTemp(Ity_I16);
3683 IRTemp resHi = newTemp(Ity_I8);
3684 IRTemp resLo = newTemp(Ity_I8);
3685 IROp mulOp = syned ? Iop_MullS8 : Iop_MullU8;
3686 UInt tBaseOp = syned ? AMD64G_CC_OP_SMULB : AMD64G_CC_OP_UMULB;
3687 setFlags_MUL ( Ity_I8, t1, tmp, tBaseOp );
3688 assign( res16, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
3689 assign( resHi, unop(Iop_16HIto8,mkexpr(res16)));
3690 assign( resLo, unop(Iop_16to8,mkexpr(res16)));
sewardj5b470602005-02-27 13:10:48 +00003691 putIRegRAX(2, mkexpr(res16));
sewardj85520e42005-02-19 15:22:38 +00003692 break;
3693 }
sewardj9b967672005-02-08 11:13:09 +00003694 default:
sewardj85520e42005-02-19 15:22:38 +00003695 ppIRType(ty);
sewardj9b967672005-02-08 11:13:09 +00003696 vpanic("codegen_mulL_A_D(amd64)");
3697 }
3698 DIP("%s%c %s\n", syned ? "imul" : "mul", nameISize(sz), tmp_txt);
3699}
sewardj32b2bbe2005-01-28 00:50:10 +00003700
3701
3702/* Group 3 extended opcodes. */
3703static
sewardj2e28ac42008-12-04 00:05:12 +00003704ULong dis_Grp3 ( VexAbiInfo* vbi,
3705 Prefix pfx, Int sz, Long delta, Bool* decode_OK )
sewardj32b2bbe2005-01-28 00:50:10 +00003706{
sewardj227458e2005-01-31 19:04:50 +00003707 Long d64;
sewardj32b2bbe2005-01-28 00:50:10 +00003708 UChar modrm;
3709 HChar dis_buf[50];
3710 Int len;
3711 IRTemp addr;
3712 IRType ty = szToITy(sz);
3713 IRTemp t1 = newTemp(ty);
sewardj55dbb262005-01-28 16:36:51 +00003714 IRTemp dst1, src, dst0;
sewardjfd4203c2007-03-21 00:21:56 +00003715 *decode_OK = True;
sewardj8c332e22005-01-28 01:36:56 +00003716 modrm = getUChar(delta);
sewardj32b2bbe2005-01-28 00:50:10 +00003717 if (epartIsReg(modrm)) {
sewardj901ed122005-02-27 13:25:31 +00003718 switch (gregLO3ofRM(modrm)) {
sewardj118b23e2005-01-29 02:14:44 +00003719 case 0: { /* TEST */
3720 delta++;
3721 d64 = getSDisp(imin(4,sz), delta);
3722 delta += imin(4,sz);
3723 dst1 = newTemp(ty);
3724 assign(dst1, binop(mkSizedOp(ty,Iop_And8),
sewardj5b470602005-02-27 13:10:48 +00003725 getIRegE(sz,pfx,modrm),
sewardj03b07cc2005-01-31 18:09:43 +00003726 mkU(ty, d64 & mkSizeMask(sz))));
sewardj118b23e2005-01-29 02:14:44 +00003727 setFlags_DEP1( Iop_And8, dst1, ty );
sewardj7eaa7cf2005-01-31 18:55:22 +00003728 DIP("test%c $%lld, %s\n",
sewardj118b23e2005-01-29 02:14:44 +00003729 nameISize(sz), d64,
sewardj5b470602005-02-27 13:10:48 +00003730 nameIRegE(sz, pfx, modrm));
sewardj118b23e2005-01-29 02:14:44 +00003731 break;
3732 }
sewardjfd4203c2007-03-21 00:21:56 +00003733 case 1:
3734 *decode_OK = False;
3735 return delta;
sewardj55dbb262005-01-28 16:36:51 +00003736 case 2: /* NOT */
3737 delta++;
sewardj5b470602005-02-27 13:10:48 +00003738 putIRegE(sz, pfx, modrm,
3739 unop(mkSizedOp(ty,Iop_Not8),
3740 getIRegE(sz, pfx, modrm)));
sewardj55dbb262005-01-28 16:36:51 +00003741 DIP("not%c %s\n", nameISize(sz),
sewardj5b470602005-02-27 13:10:48 +00003742 nameIRegE(sz, pfx, modrm));
sewardj55dbb262005-01-28 16:36:51 +00003743 break;
3744 case 3: /* NEG */
3745 delta++;
3746 dst0 = newTemp(ty);
3747 src = newTemp(ty);
3748 dst1 = newTemp(ty);
3749 assign(dst0, mkU(ty,0));
sewardj5b470602005-02-27 13:10:48 +00003750 assign(src, getIRegE(sz, pfx, modrm));
sewardj2e28ac42008-12-04 00:05:12 +00003751 assign(dst1, binop(mkSizedOp(ty,Iop_Sub8), mkexpr(dst0),
3752 mkexpr(src)));
sewardj55dbb262005-01-28 16:36:51 +00003753 setFlags_DEP1_DEP2(Iop_Sub8, dst0, src, ty);
sewardj5b470602005-02-27 13:10:48 +00003754 putIRegE(sz, pfx, modrm, mkexpr(dst1));
3755 DIP("neg%c %s\n", nameISize(sz), nameIRegE(sz, pfx, modrm));
sewardj55dbb262005-01-28 16:36:51 +00003756 break;
sewardj9b967672005-02-08 11:13:09 +00003757 case 4: /* MUL (unsigned widening) */
3758 delta++;
3759 src = newTemp(ty);
sewardj5b470602005-02-27 13:10:48 +00003760 assign(src, getIRegE(sz,pfx,modrm));
sewardj9b967672005-02-08 11:13:09 +00003761 codegen_mulL_A_D ( sz, False, src,
sewardj5b470602005-02-27 13:10:48 +00003762 nameIRegE(sz,pfx,modrm) );
sewardj9b967672005-02-08 11:13:09 +00003763 break;
sewardj85520e42005-02-19 15:22:38 +00003764 case 5: /* IMUL (signed widening) */
3765 delta++;
3766 src = newTemp(ty);
sewardj5b470602005-02-27 13:10:48 +00003767 assign(src, getIRegE(sz,pfx,modrm));
sewardj85520e42005-02-19 15:22:38 +00003768 codegen_mulL_A_D ( sz, True, src,
sewardj5b470602005-02-27 13:10:48 +00003769 nameIRegE(sz,pfx,modrm) );
sewardj85520e42005-02-19 15:22:38 +00003770 break;
sewardj03b07cc2005-01-31 18:09:43 +00003771 case 6: /* DIV */
3772 delta++;
sewardj5b470602005-02-27 13:10:48 +00003773 assign( t1, getIRegE(sz, pfx, modrm) );
sewardj03b07cc2005-01-31 18:09:43 +00003774 codegen_div ( sz, t1, False );
3775 DIP("div%c %s\n", nameISize(sz),
sewardj5b470602005-02-27 13:10:48 +00003776 nameIRegE(sz, pfx, modrm));
sewardj03b07cc2005-01-31 18:09:43 +00003777 break;
sewardj32b2bbe2005-01-28 00:50:10 +00003778 case 7: /* IDIV */
3779 delta++;
sewardj5b470602005-02-27 13:10:48 +00003780 assign( t1, getIRegE(sz, pfx, modrm) );
sewardj32b2bbe2005-01-28 00:50:10 +00003781 codegen_div ( sz, t1, True );
3782 DIP("idiv%c %s\n", nameISize(sz),
sewardj5b470602005-02-27 13:10:48 +00003783 nameIRegE(sz, pfx, modrm));
sewardj32b2bbe2005-01-28 00:50:10 +00003784 break;
3785 default:
sewardjfd4203c2007-03-21 00:21:56 +00003786 /*NOTREACHED*/
3787 vpanic("Grp3(amd64,R)");
sewardj32b2bbe2005-01-28 00:50:10 +00003788 }
3789 } else {
sewardj2e28ac42008-12-04 00:05:12 +00003790 addr = disAMode ( &len, vbi, pfx, delta, dis_buf,
sewardj7de0d3c2005-02-13 02:26:41 +00003791 /* we have to inform disAMode of any immediate
3792 bytes used */
sewardj901ed122005-02-27 13:25:31 +00003793 gregLO3ofRM(modrm)==0/*TEST*/
sewardj7de0d3c2005-02-13 02:26:41 +00003794 ? imin(4,sz)
3795 : 0
3796 );
sewardj32b2bbe2005-01-28 00:50:10 +00003797 t1 = newTemp(ty);
3798 delta += len;
3799 assign(t1, loadLE(ty,mkexpr(addr)));
sewardj901ed122005-02-27 13:25:31 +00003800 switch (gregLO3ofRM(modrm)) {
sewardj03b07cc2005-01-31 18:09:43 +00003801 case 0: { /* TEST */
3802 d64 = getSDisp(imin(4,sz), delta);
3803 delta += imin(4,sz);
3804 dst1 = newTemp(ty);
3805 assign(dst1, binop(mkSizedOp(ty,Iop_And8),
3806 mkexpr(t1),
3807 mkU(ty, d64 & mkSizeMask(sz))));
3808 setFlags_DEP1( Iop_And8, dst1, ty );
3809 DIP("test%c $%lld, %s\n", nameISize(sz), d64, dis_buf);
3810 break;
3811 }
sewardjfd4203c2007-03-21 00:21:56 +00003812 case 1:
3813 *decode_OK = False;
3814 return delta;
sewardj82c9f2f2005-03-02 16:05:13 +00003815 case 2: /* NOT */
sewardje9d8a262009-07-01 08:06:34 +00003816 dst1 = newTemp(ty);
3817 assign(dst1, unop(mkSizedOp(ty,Iop_Not8), mkexpr(t1)));
3818 if (pfx & PFX_LOCK) {
3819 casLE( mkexpr(addr), mkexpr(t1)/*expd*/, mkexpr(dst1)/*new*/,
3820 guest_RIP_curr_instr );
3821 } else {
3822 storeLE( mkexpr(addr), mkexpr(dst1) );
3823 }
sewardj82c9f2f2005-03-02 16:05:13 +00003824 DIP("not%c %s\n", nameISize(sz), dis_buf);
3825 break;
sewardj7de0d3c2005-02-13 02:26:41 +00003826 case 3: /* NEG */
3827 dst0 = newTemp(ty);
3828 src = newTemp(ty);
3829 dst1 = newTemp(ty);
3830 assign(dst0, mkU(ty,0));
3831 assign(src, mkexpr(t1));
sewardj2e28ac42008-12-04 00:05:12 +00003832 assign(dst1, binop(mkSizedOp(ty,Iop_Sub8), mkexpr(dst0),
3833 mkexpr(src)));
sewardje9d8a262009-07-01 08:06:34 +00003834 if (pfx & PFX_LOCK) {
3835 casLE( mkexpr(addr), mkexpr(t1)/*expd*/, mkexpr(dst1)/*new*/,
3836 guest_RIP_curr_instr );
3837 } else {
3838 storeLE( mkexpr(addr), mkexpr(dst1) );
3839 }
sewardj7de0d3c2005-02-13 02:26:41 +00003840 setFlags_DEP1_DEP2(Iop_Sub8, dst0, src, ty);
sewardj7de0d3c2005-02-13 02:26:41 +00003841 DIP("neg%c %s\n", nameISize(sz), dis_buf);
3842 break;
sewardj31eecde2005-03-23 03:39:55 +00003843 case 4: /* MUL (unsigned widening) */
3844 codegen_mulL_A_D ( sz, False, t1, dis_buf );
3845 break;
sewardj3aba9eb2005-03-30 23:20:47 +00003846 case 5: /* IMUL */
3847 codegen_mulL_A_D ( sz, True, t1, dis_buf );
3848 break;
sewardj1001dc42005-02-21 08:25:55 +00003849 case 6: /* DIV */
3850 codegen_div ( sz, t1, False );
3851 DIP("div%c %s\n", nameISize(sz), dis_buf);
3852 break;
sewardj82c9f2f2005-03-02 16:05:13 +00003853 case 7: /* IDIV */
3854 codegen_div ( sz, t1, True );
3855 DIP("idiv%c %s\n", nameISize(sz), dis_buf);
3856 break;
sewardj32b2bbe2005-01-28 00:50:10 +00003857 default:
sewardjfd4203c2007-03-21 00:21:56 +00003858 /*NOTREACHED*/
3859 vpanic("Grp3(amd64,M)");
sewardj32b2bbe2005-01-28 00:50:10 +00003860 }
3861 }
3862 return delta;
3863}
3864
3865
sewardj03b07cc2005-01-31 18:09:43 +00003866/* Group 4 extended opcodes. */
3867static
sewardj2e28ac42008-12-04 00:05:12 +00003868ULong dis_Grp4 ( VexAbiInfo* vbi,
3869 Prefix pfx, Long delta, Bool* decode_OK )
sewardj03b07cc2005-01-31 18:09:43 +00003870{
3871 Int alen;
3872 UChar modrm;
3873 HChar dis_buf[50];
3874 IRType ty = Ity_I8;
3875 IRTemp t1 = newTemp(ty);
3876 IRTemp t2 = newTemp(ty);
3877
sewardjfd4203c2007-03-21 00:21:56 +00003878 *decode_OK = True;
3879
sewardj03b07cc2005-01-31 18:09:43 +00003880 modrm = getUChar(delta);
3881 if (epartIsReg(modrm)) {
sewardj5b470602005-02-27 13:10:48 +00003882 assign(t1, getIRegE(1, pfx, modrm));
sewardj901ed122005-02-27 13:25:31 +00003883 switch (gregLO3ofRM(modrm)) {
sewardj85520e42005-02-19 15:22:38 +00003884 case 0: /* INC */
3885 assign(t2, binop(Iop_Add8, mkexpr(t1), mkU8(1)));
sewardj5b470602005-02-27 13:10:48 +00003886 putIRegE(1, pfx, modrm, mkexpr(t2));
sewardj85520e42005-02-19 15:22:38 +00003887 setFlags_INC_DEC( True, t2, ty );
3888 break;
sewardj03b07cc2005-01-31 18:09:43 +00003889 case 1: /* DEC */
3890 assign(t2, binop(Iop_Sub8, mkexpr(t1), mkU8(1)));
sewardj5b470602005-02-27 13:10:48 +00003891 putIRegE(1, pfx, modrm, mkexpr(t2));
sewardj03b07cc2005-01-31 18:09:43 +00003892 setFlags_INC_DEC( False, t2, ty );
3893 break;
3894 default:
sewardjfd4203c2007-03-21 00:21:56 +00003895 *decode_OK = False;
3896 return delta;
sewardj03b07cc2005-01-31 18:09:43 +00003897 }
3898 delta++;
sewardj901ed122005-02-27 13:25:31 +00003899 DIP("%sb %s\n", nameGrp4(gregLO3ofRM(modrm)),
sewardj5b470602005-02-27 13:10:48 +00003900 nameIRegE(1, pfx, modrm));
sewardj03b07cc2005-01-31 18:09:43 +00003901 } else {
sewardj2e28ac42008-12-04 00:05:12 +00003902 IRTemp addr = disAMode ( &alen, vbi, pfx, delta, dis_buf, 0 );
sewardj03b07cc2005-01-31 18:09:43 +00003903 assign( t1, loadLE(ty, mkexpr(addr)) );
sewardj901ed122005-02-27 13:25:31 +00003904 switch (gregLO3ofRM(modrm)) {
sewardj007e9ec2005-03-23 11:36:48 +00003905 case 0: /* INC */
3906 assign(t2, binop(Iop_Add8, mkexpr(t1), mkU8(1)));
sewardje9d8a262009-07-01 08:06:34 +00003907 if (pfx & PFX_LOCK) {
3908 casLE( mkexpr(addr), mkexpr(t1)/*expd*/, mkexpr(t2)/*new*/,
3909 guest_RIP_curr_instr );
3910 } else {
3911 storeLE( mkexpr(addr), mkexpr(t2) );
3912 }
sewardj007e9ec2005-03-23 11:36:48 +00003913 setFlags_INC_DEC( True, t2, ty );
3914 break;
3915 case 1: /* DEC */
3916 assign(t2, binop(Iop_Sub8, mkexpr(t1), mkU8(1)));
sewardje9d8a262009-07-01 08:06:34 +00003917 if (pfx & PFX_LOCK) {
3918 casLE( mkexpr(addr), mkexpr(t1)/*expd*/, mkexpr(t2)/*new*/,
3919 guest_RIP_curr_instr );
3920 } else {
3921 storeLE( mkexpr(addr), mkexpr(t2) );
3922 }
sewardj007e9ec2005-03-23 11:36:48 +00003923 setFlags_INC_DEC( False, t2, ty );
3924 break;
sewardj03b07cc2005-01-31 18:09:43 +00003925 default:
sewardjfd4203c2007-03-21 00:21:56 +00003926 *decode_OK = False;
3927 return delta;
sewardj03b07cc2005-01-31 18:09:43 +00003928 }
3929 delta += alen;
sewardj901ed122005-02-27 13:25:31 +00003930 DIP("%sb %s\n", nameGrp4(gregLO3ofRM(modrm)), dis_buf);
sewardj03b07cc2005-01-31 18:09:43 +00003931 }
3932 return delta;
3933}
sewardj354e5c62005-01-27 20:12:52 +00003934
3935
3936/* Group 5 extended opcodes. */
3937static
sewardjdd40fdf2006-12-24 02:20:24 +00003938ULong dis_Grp5 ( VexAbiInfo* vbi,
sewardjfd4203c2007-03-21 00:21:56 +00003939 Prefix pfx, Int sz, Long delta,
3940 DisResult* dres, Bool* decode_OK )
sewardj354e5c62005-01-27 20:12:52 +00003941{
3942 Int len;
3943 UChar modrm;
3944 HChar dis_buf[50];
3945 IRTemp addr = IRTemp_INVALID;
3946 IRType ty = szToITy(sz);
3947 IRTemp t1 = newTemp(ty);
3948 IRTemp t2 = IRTemp_INVALID;
sewardj03b07cc2005-01-31 18:09:43 +00003949 IRTemp t3 = IRTemp_INVALID;
sewardj7eaa7cf2005-01-31 18:55:22 +00003950 Bool showSz = True;
sewardj354e5c62005-01-27 20:12:52 +00003951
sewardjfd4203c2007-03-21 00:21:56 +00003952 *decode_OK = True;
3953
sewardj8c332e22005-01-28 01:36:56 +00003954 modrm = getUChar(delta);
sewardj354e5c62005-01-27 20:12:52 +00003955 if (epartIsReg(modrm)) {
sewardj5b470602005-02-27 13:10:48 +00003956 assign(t1, getIRegE(sz,pfx,modrm));
sewardj901ed122005-02-27 13:25:31 +00003957 switch (gregLO3ofRM(modrm)) {
sewardj32b2bbe2005-01-28 00:50:10 +00003958 case 0: /* INC */
3959 t2 = newTemp(ty);
3960 assign(t2, binop(mkSizedOp(ty,Iop_Add8),
3961 mkexpr(t1), mkU(ty,1)));
3962 setFlags_INC_DEC( True, t2, ty );
sewardj5b470602005-02-27 13:10:48 +00003963 putIRegE(sz,pfx,modrm, mkexpr(t2));
sewardj32b2bbe2005-01-28 00:50:10 +00003964 break;
3965 case 1: /* DEC */
3966 t2 = newTemp(ty);
3967 assign(t2, binop(mkSizedOp(ty,Iop_Sub8),
3968 mkexpr(t1), mkU(ty,1)));
3969 setFlags_INC_DEC( False, t2, ty );
sewardj5b470602005-02-27 13:10:48 +00003970 putIRegE(sz,pfx,modrm, mkexpr(t2));
sewardj32b2bbe2005-01-28 00:50:10 +00003971 break;
sewardj354e5c62005-01-27 20:12:52 +00003972 case 2: /* call Ev */
sewardj03b07cc2005-01-31 18:09:43 +00003973 /* Ignore any sz value and operate as if sz==8. */
sewardjd7a544b2007-11-19 00:39:23 +00003974 if (!(sz == 4 || sz == 8)) goto unhandled;
sewardj03b07cc2005-01-31 18:09:43 +00003975 sz = 8;
3976 t3 = newTemp(Ity_I64);
sewardj5b470602005-02-27 13:10:48 +00003977 assign(t3, getIRegE(sz,pfx,modrm));
sewardj03b07cc2005-01-31 18:09:43 +00003978 t2 = newTemp(Ity_I64);
3979 assign(t2, binop(Iop_Sub64, getIReg64(R_RSP), mkU64(8)));
3980 putIReg64(R_RSP, mkexpr(t2));
sewardj9e6491a2005-07-02 19:24:10 +00003981 storeLE( mkexpr(t2), mkU64(guest_RIP_bbstart+delta+1));
sewardj478646f2008-05-01 20:13:04 +00003982 make_redzone_AbiHint(vbi, t2, t3/*nia*/, "call-Ev(reg)");
sewardj03b07cc2005-01-31 18:09:43 +00003983 jmp_treg(Ijk_Call,t3);
sewardj9e6491a2005-07-02 19:24:10 +00003984 dres->whatNext = Dis_StopHere;
sewardj7eaa7cf2005-01-31 18:55:22 +00003985 showSz = False;
sewardj354e5c62005-01-27 20:12:52 +00003986 break;
sewardj354e5c62005-01-27 20:12:52 +00003987 case 4: /* jmp Ev */
sewardj03b07cc2005-01-31 18:09:43 +00003988 /* Ignore any sz value and operate as if sz==8. */
sewardjd7a544b2007-11-19 00:39:23 +00003989 if (!(sz == 4 || sz == 8)) goto unhandled;
sewardj03b07cc2005-01-31 18:09:43 +00003990 sz = 8;
3991 t3 = newTemp(Ity_I64);
sewardj5b470602005-02-27 13:10:48 +00003992 assign(t3, getIRegE(sz,pfx,modrm));
sewardj03b07cc2005-01-31 18:09:43 +00003993 jmp_treg(Ijk_Boring,t3);
sewardj9e6491a2005-07-02 19:24:10 +00003994 dres->whatNext = Dis_StopHere;
sewardj7eaa7cf2005-01-31 18:55:22 +00003995 showSz = False;
sewardj354e5c62005-01-27 20:12:52 +00003996 break;
sewardj354e5c62005-01-27 20:12:52 +00003997 default:
sewardjfd4203c2007-03-21 00:21:56 +00003998 *decode_OK = False;
3999 return delta;
sewardj354e5c62005-01-27 20:12:52 +00004000 }
4001 delta++;
sewardj901ed122005-02-27 13:25:31 +00004002 DIP("%s%c %s\n", nameGrp5(gregLO3ofRM(modrm)),
sewardj7eaa7cf2005-01-31 18:55:22 +00004003 showSz ? nameISize(sz) : ' ',
sewardj5b470602005-02-27 13:10:48 +00004004 nameIRegE(sz, pfx, modrm));
sewardj354e5c62005-01-27 20:12:52 +00004005 } else {
sewardj2e28ac42008-12-04 00:05:12 +00004006 addr = disAMode ( &len, vbi, pfx, delta, dis_buf, 0 );
sewardj901ed122005-02-27 13:25:31 +00004007 if (gregLO3ofRM(modrm) != 2 && gregLO3ofRM(modrm) != 4
4008 && gregLO3ofRM(modrm) != 6) {
sewardj03b07cc2005-01-31 18:09:43 +00004009 assign(t1, loadLE(ty,mkexpr(addr)));
sewardj909c06d2005-02-19 22:47:41 +00004010 }
sewardj901ed122005-02-27 13:25:31 +00004011 switch (gregLO3ofRM(modrm)) {
sewardj354e5c62005-01-27 20:12:52 +00004012 case 0: /* INC */
sewardj354e5c62005-01-27 20:12:52 +00004013 t2 = newTemp(ty);
4014 assign(t2, binop(mkSizedOp(ty,Iop_Add8),
4015 mkexpr(t1), mkU(ty,1)));
sewardje9d8a262009-07-01 08:06:34 +00004016 if (pfx & PFX_LOCK) {
4017 casLE( mkexpr(addr),
4018 mkexpr(t1), mkexpr(t2), guest_RIP_curr_instr );
4019 } else {
4020 storeLE(mkexpr(addr),mkexpr(t2));
4021 }
sewardj354e5c62005-01-27 20:12:52 +00004022 setFlags_INC_DEC( True, t2, ty );
sewardj354e5c62005-01-27 20:12:52 +00004023 break;
sewardj354e5c62005-01-27 20:12:52 +00004024 case 1: /* DEC */
4025 t2 = newTemp(ty);
4026 assign(t2, binop(mkSizedOp(ty,Iop_Sub8),
4027 mkexpr(t1), mkU(ty,1)));
sewardje9d8a262009-07-01 08:06:34 +00004028 if (pfx & PFX_LOCK) {
4029 casLE( mkexpr(addr),
4030 mkexpr(t1), mkexpr(t2), guest_RIP_curr_instr );
4031 } else {
4032 storeLE(mkexpr(addr),mkexpr(t2));
4033 }
sewardj354e5c62005-01-27 20:12:52 +00004034 setFlags_INC_DEC( False, t2, ty );
sewardj354e5c62005-01-27 20:12:52 +00004035 break;
4036 case 2: /* call Ev */
sewardj03b07cc2005-01-31 18:09:43 +00004037 /* Ignore any sz value and operate as if sz==8. */
sewardjd7a544b2007-11-19 00:39:23 +00004038 if (!(sz == 4 || sz == 8)) goto unhandled;
sewardj7eaa7cf2005-01-31 18:55:22 +00004039 sz = 8;
sewardj03b07cc2005-01-31 18:09:43 +00004040 t3 = newTemp(Ity_I64);
4041 assign(t3, loadLE(Ity_I64,mkexpr(addr)));
4042 t2 = newTemp(Ity_I64);
4043 assign(t2, binop(Iop_Sub64, getIReg64(R_RSP), mkU64(8)));
4044 putIReg64(R_RSP, mkexpr(t2));
sewardj9e6491a2005-07-02 19:24:10 +00004045 storeLE( mkexpr(t2), mkU64(guest_RIP_bbstart+delta+len));
sewardj478646f2008-05-01 20:13:04 +00004046 make_redzone_AbiHint(vbi, t2, t3/*nia*/, "call-Ev(mem)");
sewardj03b07cc2005-01-31 18:09:43 +00004047 jmp_treg(Ijk_Call,t3);
sewardj9e6491a2005-07-02 19:24:10 +00004048 dres->whatNext = Dis_StopHere;
sewardj7eaa7cf2005-01-31 18:55:22 +00004049 showSz = False;
sewardj354e5c62005-01-27 20:12:52 +00004050 break;
sewardj354e5c62005-01-27 20:12:52 +00004051 case 4: /* JMP Ev */
sewardj03b07cc2005-01-31 18:09:43 +00004052 /* Ignore any sz value and operate as if sz==8. */
sewardjd7a544b2007-11-19 00:39:23 +00004053 if (!(sz == 4 || sz == 8)) goto unhandled;
sewardj7eaa7cf2005-01-31 18:55:22 +00004054 sz = 8;
sewardj03b07cc2005-01-31 18:09:43 +00004055 t3 = newTemp(Ity_I64);
4056 assign(t3, loadLE(Ity_I64,mkexpr(addr)));
4057 jmp_treg(Ijk_Boring,t3);
sewardj9e6491a2005-07-02 19:24:10 +00004058 dres->whatNext = Dis_StopHere;
sewardj7eaa7cf2005-01-31 18:55:22 +00004059 showSz = False;
sewardj354e5c62005-01-27 20:12:52 +00004060 break;
sewardj354e5c62005-01-27 20:12:52 +00004061 case 6: /* PUSH Ev */
sewardja6b93d12005-02-17 09:28:28 +00004062 /* There is no encoding for 32-bit operand size; hence ... */
4063 if (sz == 4) sz = 8;
sewardjd7a544b2007-11-19 00:39:23 +00004064 if (!(sz == 8 || sz == 2)) goto unhandled;
sewardj909c06d2005-02-19 22:47:41 +00004065 if (sz == 8) {
4066 t3 = newTemp(Ity_I64);
4067 assign(t3, loadLE(Ity_I64,mkexpr(addr)));
4068 t2 = newTemp(Ity_I64);
4069 assign( t2, binop(Iop_Sub64,getIReg64(R_RSP),mkU64(sz)) );
4070 putIReg64(R_RSP, mkexpr(t2) );
4071 storeLE( mkexpr(t2), mkexpr(t3) );
4072 break;
4073 } else {
4074 goto unhandled; /* awaiting test case */
4075 }
sewardj354e5c62005-01-27 20:12:52 +00004076 default:
sewardja6b93d12005-02-17 09:28:28 +00004077 unhandled:
sewardjfd4203c2007-03-21 00:21:56 +00004078 *decode_OK = False;
4079 return delta;
sewardj354e5c62005-01-27 20:12:52 +00004080 }
4081 delta += len;
sewardj901ed122005-02-27 13:25:31 +00004082 DIP("%s%c %s\n", nameGrp5(gregLO3ofRM(modrm)),
sewardj7eaa7cf2005-01-31 18:55:22 +00004083 showSz ? nameISize(sz) : ' ',
4084 dis_buf);
sewardj354e5c62005-01-27 20:12:52 +00004085 }
4086 return delta;
4087}
4088
4089
sewardjd0a12df2005-02-10 02:07:43 +00004090/*------------------------------------------------------------*/
4091/*--- Disassembling string ops (including REP prefixes) ---*/
4092/*------------------------------------------------------------*/
4093
4094/* Code shared by all the string ops */
4095static
4096void dis_string_op_increment ( Int sz, IRTemp t_inc )
4097{
4098 UChar logSz;
4099 if (sz == 8 || sz == 4 || sz == 2) {
4100 logSz = 1;
4101 if (sz == 4) logSz = 2;
4102 if (sz == 8) logSz = 3;
4103 assign( t_inc,
4104 binop(Iop_Shl64, IRExpr_Get( OFFB_DFLAG, Ity_I64 ),
4105 mkU8(logSz) ) );
4106 } else {
4107 assign( t_inc,
4108 IRExpr_Get( OFFB_DFLAG, Ity_I64 ) );
4109 }
4110}
4111
sewardj909c06d2005-02-19 22:47:41 +00004112static
4113void dis_string_op( void (*dis_OP)( Int, IRTemp ),
4114 Int sz, HChar* name, Prefix pfx )
4115{
4116 IRTemp t_inc = newTemp(Ity_I64);
4117 /* Really we ought to inspect the override prefixes, but we don't.
4118 The following assertion catches any resulting sillyness. */
4119 vassert(pfx == clearSegBits(pfx));
4120 dis_string_op_increment(sz, t_inc);
4121 dis_OP( sz, t_inc );
4122 DIP("%s%c\n", name, nameISize(sz));
4123}
4124
4125static
4126void dis_MOVS ( Int sz, IRTemp t_inc )
4127{
4128 IRType ty = szToITy(sz);
4129 IRTemp td = newTemp(Ity_I64); /* RDI */
4130 IRTemp ts = newTemp(Ity_I64); /* RSI */
4131
4132 assign( td, getIReg64(R_RDI) );
4133 assign( ts, getIReg64(R_RSI) );
4134
4135 storeLE( mkexpr(td), loadLE(ty,mkexpr(ts)) );
4136
4137 putIReg64( R_RDI, binop(Iop_Add64, mkexpr(td), mkexpr(t_inc)) );
4138 putIReg64( R_RSI, binop(Iop_Add64, mkexpr(ts), mkexpr(t_inc)) );
4139}
4140
sewardj0f99be62009-07-22 09:29:13 +00004141static
4142void dis_LODS ( Int sz, IRTemp t_inc )
4143{
4144 IRType ty = szToITy(sz);
4145 IRTemp ts = newTemp(Ity_I64); /* RSI */
4146
4147 assign( ts, getIReg64(R_RSI) );
4148
4149 putIRegRAX ( sz, loadLE(ty, mkexpr(ts)) );
4150
4151 putIReg64( R_RSI, binop(Iop_Add64, mkexpr(ts), mkexpr(t_inc)) );
4152}
sewardja6b93d12005-02-17 09:28:28 +00004153
4154static
4155void dis_STOS ( Int sz, IRTemp t_inc )
4156{
4157 IRType ty = szToITy(sz);
4158 IRTemp ta = newTemp(ty); /* rAX */
4159 IRTemp td = newTemp(Ity_I64); /* RDI */
4160
sewardj5b470602005-02-27 13:10:48 +00004161 assign( ta, getIRegRAX(sz) );
sewardja6b93d12005-02-17 09:28:28 +00004162
4163 assign( td, getIReg64(R_RDI) );
4164
4165 storeLE( mkexpr(td), mkexpr(ta) );
4166
4167 putIReg64( R_RDI, binop(Iop_Add64, mkexpr(td), mkexpr(t_inc)) );
4168}
sewardjd0a12df2005-02-10 02:07:43 +00004169
4170static
4171void dis_CMPS ( Int sz, IRTemp t_inc )
4172{
4173 IRType ty = szToITy(sz);
4174 IRTemp tdv = newTemp(ty); /* (RDI) */
4175 IRTemp tsv = newTemp(ty); /* (RSI) */
4176 IRTemp td = newTemp(Ity_I64); /* RDI */
4177 IRTemp ts = newTemp(Ity_I64); /* RSI */
4178
4179 assign( td, getIReg64(R_RDI) );
4180
4181 assign( ts, getIReg64(R_RSI) );
4182
4183 assign( tdv, loadLE(ty,mkexpr(td)) );
4184
4185 assign( tsv, loadLE(ty,mkexpr(ts)) );
4186
4187 setFlags_DEP1_DEP2 ( Iop_Sub8, tsv, tdv, ty );
4188
4189 putIReg64(R_RDI, binop(Iop_Add64, mkexpr(td), mkexpr(t_inc)) );
4190
4191 putIReg64(R_RSI, binop(Iop_Add64, mkexpr(ts), mkexpr(t_inc)) );
4192}
4193
sewardj85520e42005-02-19 15:22:38 +00004194static
4195void dis_SCAS ( Int sz, IRTemp t_inc )
4196{
4197 IRType ty = szToITy(sz);
4198 IRTemp ta = newTemp(ty); /* rAX */
4199 IRTemp td = newTemp(Ity_I64); /* RDI */
4200 IRTemp tdv = newTemp(ty); /* (RDI) */
4201
sewardj5b470602005-02-27 13:10:48 +00004202 assign( ta, getIRegRAX(sz) );
sewardj85520e42005-02-19 15:22:38 +00004203
4204 assign( td, getIReg64(R_RDI) );
4205
4206 assign( tdv, loadLE(ty,mkexpr(td)) );
4207
4208 setFlags_DEP1_DEP2 ( Iop_Sub8, ta, tdv, ty );
4209
4210 putIReg64(R_RDI, binop(Iop_Add64, mkexpr(td), mkexpr(t_inc)) );
4211}
sewardjd0a12df2005-02-10 02:07:43 +00004212
4213
4214/* Wrap the appropriate string op inside a REP/REPE/REPNE. We assume
4215 the insn is the last one in the basic block, and so emit a jump to
4216 the next insn, rather than just falling through. */
4217static
4218void dis_REP_op ( AMD64Condcode cond,
4219 void (*dis_OP)(Int, IRTemp),
sewardj909c06d2005-02-19 22:47:41 +00004220 Int sz, Addr64 rip, Addr64 rip_next, HChar* name,
4221 Prefix pfx )
sewardjd0a12df2005-02-10 02:07:43 +00004222{
4223 IRTemp t_inc = newTemp(Ity_I64);
4224 IRTemp tc = newTemp(Ity_I64); /* RCX */
4225
sewardj909c06d2005-02-19 22:47:41 +00004226 /* Really we ought to inspect the override prefixes, but we don't.
4227 The following assertion catches any resulting sillyness. */
4228 vassert(pfx == clearSegBits(pfx));
4229
sewardjd0a12df2005-02-10 02:07:43 +00004230 assign( tc, getIReg64(R_RCX) );
4231
4232 stmt( IRStmt_Exit( binop(Iop_CmpEQ64,mkexpr(tc),mkU64(0)),
4233 Ijk_Boring,
4234 IRConst_U64(rip_next) ) );
4235
4236 putIReg64(R_RCX, binop(Iop_Sub64, mkexpr(tc), mkU64(1)) );
4237
4238 dis_string_op_increment(sz, t_inc);
4239 dis_OP (sz, t_inc);
4240
4241 if (cond == AMD64CondAlways) {
4242 jmp_lit(Ijk_Boring,rip);
4243 } else {
4244 stmt( IRStmt_Exit( mk_amd64g_calculate_condition(cond),
4245 Ijk_Boring,
4246 IRConst_U64(rip) ) );
4247 jmp_lit(Ijk_Boring,rip_next);
4248 }
4249 DIP("%s%c\n", name, nameISize(sz));
4250}
sewardj32b2bbe2005-01-28 00:50:10 +00004251
4252
4253/*------------------------------------------------------------*/
4254/*--- Arithmetic, etc. ---*/
4255/*------------------------------------------------------------*/
4256
4257/* IMUL E, G. Supplied eip points to the modR/M byte. */
4258static
sewardj2e28ac42008-12-04 00:05:12 +00004259ULong dis_mul_E_G ( VexAbiInfo* vbi,
4260 Prefix pfx,
sewardj32b2bbe2005-01-28 00:50:10 +00004261 Int size,
sewardj270def42005-07-03 01:03:01 +00004262 Long delta0 )
sewardj32b2bbe2005-01-28 00:50:10 +00004263{
4264 Int alen;
4265 HChar dis_buf[50];
sewardj8c332e22005-01-28 01:36:56 +00004266 UChar rm = getUChar(delta0);
sewardj32b2bbe2005-01-28 00:50:10 +00004267 IRType ty = szToITy(size);
4268 IRTemp te = newTemp(ty);
4269 IRTemp tg = newTemp(ty);
4270 IRTemp resLo = newTemp(ty);
4271
sewardj5b470602005-02-27 13:10:48 +00004272 assign( tg, getIRegG(size, pfx, rm) );
sewardj32b2bbe2005-01-28 00:50:10 +00004273 if (epartIsReg(rm)) {
sewardj5b470602005-02-27 13:10:48 +00004274 assign( te, getIRegE(size, pfx, rm) );
sewardj32b2bbe2005-01-28 00:50:10 +00004275 } else {
sewardj2e28ac42008-12-04 00:05:12 +00004276 IRTemp addr = disAMode( &alen, vbi, pfx, delta0, dis_buf, 0 );
sewardj32b2bbe2005-01-28 00:50:10 +00004277 assign( te, loadLE(ty,mkexpr(addr)) );
4278 }
4279
4280 setFlags_MUL ( ty, te, tg, AMD64G_CC_OP_SMULB );
4281
4282 assign( resLo, binop( mkSizedOp(ty, Iop_Mul8), mkexpr(te), mkexpr(tg) ) );
4283
sewardj5b470602005-02-27 13:10:48 +00004284 putIRegG(size, pfx, rm, mkexpr(resLo) );
sewardj32b2bbe2005-01-28 00:50:10 +00004285
4286 if (epartIsReg(rm)) {
4287 DIP("imul%c %s, %s\n", nameISize(size),
sewardj901ed122005-02-27 13:25:31 +00004288 nameIRegE(size,pfx,rm),
4289 nameIRegG(size,pfx,rm));
sewardj32b2bbe2005-01-28 00:50:10 +00004290 return 1+delta0;
4291 } else {
4292 DIP("imul%c %s, %s\n", nameISize(size),
4293 dis_buf,
sewardj901ed122005-02-27 13:25:31 +00004294 nameIRegG(size,pfx,rm));
sewardj32b2bbe2005-01-28 00:50:10 +00004295 return alen+delta0;
4296 }
4297}
4298
4299
4300/* IMUL I * E -> G. Supplied rip points to the modR/M byte. */
4301static
sewardj2e28ac42008-12-04 00:05:12 +00004302ULong dis_imul_I_E_G ( VexAbiInfo* vbi,
4303 Prefix pfx,
sewardj32b2bbe2005-01-28 00:50:10 +00004304 Int size,
sewardj270def42005-07-03 01:03:01 +00004305 Long delta,
sewardj32b2bbe2005-01-28 00:50:10 +00004306 Int litsize )
4307{
4308 Long d64;
4309 Int alen;
4310 HChar dis_buf[50];
sewardj8c332e22005-01-28 01:36:56 +00004311 UChar rm = getUChar(delta);
sewardj32b2bbe2005-01-28 00:50:10 +00004312 IRType ty = szToITy(size);
4313 IRTemp te = newTemp(ty);
4314 IRTemp tl = newTemp(ty);
4315 IRTemp resLo = newTemp(ty);
4316
sewardj85520e42005-02-19 15:22:38 +00004317 vassert(/*size == 1 ||*/ size == 2 || size == 4 || size == 8);
sewardj32b2bbe2005-01-28 00:50:10 +00004318
4319 if (epartIsReg(rm)) {
sewardj5b470602005-02-27 13:10:48 +00004320 assign(te, getIRegE(size, pfx, rm));
sewardj32b2bbe2005-01-28 00:50:10 +00004321 delta++;
4322 } else {
sewardj2e28ac42008-12-04 00:05:12 +00004323 IRTemp addr = disAMode( &alen, vbi, pfx, delta, dis_buf,
sewardj7de0d3c2005-02-13 02:26:41 +00004324 imin(4,litsize) );
sewardj32b2bbe2005-01-28 00:50:10 +00004325 assign(te, loadLE(ty, mkexpr(addr)));
4326 delta += alen;
4327 }
4328 d64 = getSDisp(imin(4,litsize),delta);
4329 delta += imin(4,litsize);
4330
sewardj1389d4d2005-01-28 13:46:29 +00004331 d64 &= mkSizeMask(size);
sewardj32b2bbe2005-01-28 00:50:10 +00004332 assign(tl, mkU(ty,d64));
4333
4334 assign( resLo, binop( mkSizedOp(ty, Iop_Mul8), mkexpr(te), mkexpr(tl) ));
4335
4336 setFlags_MUL ( ty, te, tl, AMD64G_CC_OP_SMULB );
4337
sewardj5b470602005-02-27 13:10:48 +00004338 putIRegG(size, pfx, rm, mkexpr(resLo));
sewardj32b2bbe2005-01-28 00:50:10 +00004339
4340 DIP("imul%c $%lld, %s, %s\n",
4341 nameISize(size), d64,
sewardj5b470602005-02-27 13:10:48 +00004342 ( epartIsReg(rm) ? nameIRegE(size,pfx,rm) : dis_buf ),
4343 nameIRegG(size,pfx,rm) );
sewardj32b2bbe2005-01-28 00:50:10 +00004344 return delta;
4345}
4346
4347
sewardjbcbb9de2005-03-27 02:22:32 +00004348/*------------------------------------------------------------*/
4349/*--- ---*/
4350/*--- x87 FLOATING POINT INSTRUCTIONS ---*/
4351/*--- ---*/
4352/*------------------------------------------------------------*/
4353
4354/* --- Helper functions for dealing with the register stack. --- */
4355
4356/* --- Set the emulation-warning pseudo-register. --- */
4357
4358static void put_emwarn ( IRExpr* e /* :: Ity_I32 */ )
4359{
sewardjdd40fdf2006-12-24 02:20:24 +00004360 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I32);
sewardjbcbb9de2005-03-27 02:22:32 +00004361 stmt( IRStmt_Put( OFFB_EMWARN, e ) );
4362}
sewardj8d965312005-02-25 02:48:47 +00004363
4364/* --- Produce an IRExpr* denoting a 64-bit QNaN. --- */
4365
4366static IRExpr* mkQNaN64 ( void )
4367{
4368 /* QNaN is 0 2047 1 0(51times)
4369 == 0b 11111111111b 1 0(51times)
4370 == 0x7FF8 0000 0000 0000
4371 */
4372 return IRExpr_Const(IRConst_F64i(0x7FF8000000000000ULL));
4373}
4374
4375/* --------- Get/put the top-of-stack pointer :: Ity_I32 --------- */
4376
4377static IRExpr* get_ftop ( void )
4378{
4379 return IRExpr_Get( OFFB_FTOP, Ity_I32 );
4380}
4381
4382static void put_ftop ( IRExpr* e )
4383{
sewardjdd40fdf2006-12-24 02:20:24 +00004384 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I32);
sewardj8d965312005-02-25 02:48:47 +00004385 stmt( IRStmt_Put( OFFB_FTOP, e ) );
4386}
4387
sewardj25a85812005-05-08 23:03:48 +00004388/* --------- Get/put the C3210 bits. --------- */
4389
4390static IRExpr* /* :: Ity_I64 */ get_C3210 ( void )
4391{
4392 return IRExpr_Get( OFFB_FC3210, Ity_I64 );
4393}
4394
4395static void put_C3210 ( IRExpr* e /* :: Ity_I64 */ )
4396{
sewardjdd40fdf2006-12-24 02:20:24 +00004397 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I64);
sewardj25a85812005-05-08 23:03:48 +00004398 stmt( IRStmt_Put( OFFB_FC3210, e ) );
4399}
sewardjc49ce232005-02-25 13:03:03 +00004400
4401/* --------- Get/put the FPU rounding mode. --------- */
4402static IRExpr* /* :: Ity_I32 */ get_fpround ( void )
4403{
4404 return unop(Iop_64to32, IRExpr_Get( OFFB_FPROUND, Ity_I64 ));
4405}
4406
sewardj5e205372005-05-09 02:57:08 +00004407static void put_fpround ( IRExpr* /* :: Ity_I32 */ e )
4408{
sewardjdd40fdf2006-12-24 02:20:24 +00004409 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I32);
sewardj5e205372005-05-09 02:57:08 +00004410 stmt( IRStmt_Put( OFFB_FPROUND, unop(Iop_32Uto64,e) ) );
4411}
sewardjc49ce232005-02-25 13:03:03 +00004412
4413
4414/* --------- Synthesise a 2-bit FPU rounding mode. --------- */
4415/* Produces a value in 0 .. 3, which is encoded as per the type
4416 IRRoundingMode. Since the guest_FPROUND value is also encoded as
4417 per IRRoundingMode, we merely need to get it and mask it for
4418 safety.
4419*/
4420static IRExpr* /* :: Ity_I32 */ get_roundingmode ( void )
4421{
4422 return binop( Iop_And32, get_fpround(), mkU32(3) );
4423}
sewardj8d965312005-02-25 02:48:47 +00004424
sewardj4796d662006-02-05 16:06:26 +00004425static IRExpr* /* :: Ity_I32 */ get_FAKE_roundingmode ( void )
4426{
4427 return mkU32(Irrm_NEAREST);
4428}
4429
sewardj8d965312005-02-25 02:48:47 +00004430
4431/* --------- Get/set FP register tag bytes. --------- */
4432
4433/* Given i, and some expression e, generate 'ST_TAG(i) = e'. */
4434
4435static void put_ST_TAG ( Int i, IRExpr* value )
4436{
sewardjdd40fdf2006-12-24 02:20:24 +00004437 IRRegArray* descr;
4438 vassert(typeOfIRExpr(irsb->tyenv, value) == Ity_I8);
4439 descr = mkIRRegArray( OFFB_FPTAGS, Ity_I8, 8 );
sewardj8d965312005-02-25 02:48:47 +00004440 stmt( IRStmt_PutI( descr, get_ftop(), i, value ) );
4441}
4442
4443/* Given i, generate an expression yielding 'ST_TAG(i)'. This will be
4444 zero to indicate "Empty" and nonzero to indicate "NonEmpty". */
4445
4446static IRExpr* get_ST_TAG ( Int i )
4447{
sewardjdd40fdf2006-12-24 02:20:24 +00004448 IRRegArray* descr = mkIRRegArray( OFFB_FPTAGS, Ity_I8, 8 );
sewardj8d965312005-02-25 02:48:47 +00004449 return IRExpr_GetI( descr, get_ftop(), i );
4450}
4451
4452
4453/* --------- Get/set FP registers. --------- */
4454
4455/* Given i, and some expression e, emit 'ST(i) = e' and set the
4456 register's tag to indicate the register is full. The previous
4457 state of the register is not checked. */
4458
4459static void put_ST_UNCHECKED ( Int i, IRExpr* value )
4460{
sewardjdd40fdf2006-12-24 02:20:24 +00004461 IRRegArray* descr;
4462 vassert(typeOfIRExpr(irsb->tyenv, value) == Ity_F64);
4463 descr = mkIRRegArray( OFFB_FPREGS, Ity_F64, 8 );
sewardj8d965312005-02-25 02:48:47 +00004464 stmt( IRStmt_PutI( descr, get_ftop(), i, value ) );
4465 /* Mark the register as in-use. */
4466 put_ST_TAG(i, mkU8(1));
4467}
4468
4469/* Given i, and some expression e, emit
4470 ST(i) = is_full(i) ? NaN : e
4471 and set the tag accordingly.
4472*/
4473
4474static void put_ST ( Int i, IRExpr* value )
4475{
4476 put_ST_UNCHECKED( i,
4477 IRExpr_Mux0X( get_ST_TAG(i),
4478 /* 0 means empty */
4479 value,
4480 /* non-0 means full */
4481 mkQNaN64()
4482 )
4483 );
4484}
4485
4486
4487/* Given i, generate an expression yielding 'ST(i)'. */
4488
4489static IRExpr* get_ST_UNCHECKED ( Int i )
4490{
sewardjdd40fdf2006-12-24 02:20:24 +00004491 IRRegArray* descr = mkIRRegArray( OFFB_FPREGS, Ity_F64, 8 );
sewardj8d965312005-02-25 02:48:47 +00004492 return IRExpr_GetI( descr, get_ftop(), i );
4493}
4494
4495
4496/* Given i, generate an expression yielding
4497 is_full(i) ? ST(i) : NaN
4498*/
4499
4500static IRExpr* get_ST ( Int i )
4501{
4502 return
4503 IRExpr_Mux0X( get_ST_TAG(i),
4504 /* 0 means empty */
4505 mkQNaN64(),
4506 /* non-0 means full */
4507 get_ST_UNCHECKED(i));
4508}
4509
4510
4511/* Adjust FTOP downwards by one register. */
4512
4513static void fp_push ( void )
4514{
4515 put_ftop( binop(Iop_Sub32, get_ftop(), mkU32(1)) );
4516}
4517
4518/* Adjust FTOP upwards by one register, and mark the vacated register
4519 as empty. */
4520
4521static void fp_pop ( void )
4522{
4523 put_ST_TAG(0, mkU8(0));
4524 put_ftop( binop(Iop_Add32, get_ftop(), mkU32(1)) );
4525}
4526
sewardj25a85812005-05-08 23:03:48 +00004527/* Clear the C2 bit of the FPU status register, for
4528 sin/cos/tan/sincos. */
4529
4530static void clear_C2 ( void )
4531{
4532 put_C3210( binop(Iop_And64, get_C3210(), mkU64(~AMD64G_FC_MASK_C2)) );
4533}
sewardj48a89d82005-05-06 11:50:13 +00004534
sewardj7c2d2822006-03-07 00:22:02 +00004535/* Invent a plausible-looking FPU status word value:
4536 ((ftop & 7) << 11) | (c3210 & 0x4700)
4537 */
4538static IRExpr* get_FPU_sw ( void )
4539{
4540 return
4541 unop(Iop_32to16,
4542 binop(Iop_Or32,
4543 binop(Iop_Shl32,
4544 binop(Iop_And32, get_ftop(), mkU32(7)),
4545 mkU8(11)),
4546 binop(Iop_And32, unop(Iop_64to32, get_C3210()),
4547 mkU32(0x4700))
4548 ));
4549}
4550
sewardj48a89d82005-05-06 11:50:13 +00004551
4552/* ------------------------------------------------------- */
4553/* Given all that stack-mangling junk, we can now go ahead
4554 and describe FP instructions.
4555*/
4556
4557/* ST(0) = ST(0) `op` mem64/32(addr)
4558 Need to check ST(0)'s tag on read, but not on write.
4559*/
4560static
sewardjca673ab2005-05-11 10:03:08 +00004561void fp_do_op_mem_ST_0 ( IRTemp addr, HChar* op_txt, HChar* dis_buf,
sewardj48a89d82005-05-06 11:50:13 +00004562 IROp op, Bool dbl )
4563{
4564 DIP("f%s%c %s\n", op_txt, dbl?'l':'s', dis_buf);
4565 if (dbl) {
4566 put_ST_UNCHECKED(0,
sewardj4796d662006-02-05 16:06:26 +00004567 triop( op,
4568 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardj48a89d82005-05-06 11:50:13 +00004569 get_ST(0),
4570 loadLE(Ity_F64,mkexpr(addr))
4571 ));
4572 } else {
4573 put_ST_UNCHECKED(0,
sewardj4796d662006-02-05 16:06:26 +00004574 triop( op,
4575 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardj48a89d82005-05-06 11:50:13 +00004576 get_ST(0),
4577 unop(Iop_F32toF64, loadLE(Ity_F32,mkexpr(addr)))
4578 ));
4579 }
4580}
sewardj7bc00082005-03-27 05:08:32 +00004581
4582
4583/* ST(0) = mem64/32(addr) `op` ST(0)
4584 Need to check ST(0)'s tag on read, but not on write.
4585*/
4586static
4587void fp_do_oprev_mem_ST_0 ( IRTemp addr, HChar* op_txt, HChar* dis_buf,
4588 IROp op, Bool dbl )
4589{
4590 DIP("f%s%c %s\n", op_txt, dbl?'l':'s', dis_buf);
4591 if (dbl) {
4592 put_ST_UNCHECKED(0,
sewardj4796d662006-02-05 16:06:26 +00004593 triop( op,
4594 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardj7bc00082005-03-27 05:08:32 +00004595 loadLE(Ity_F64,mkexpr(addr)),
4596 get_ST(0)
4597 ));
4598 } else {
4599 put_ST_UNCHECKED(0,
sewardj4796d662006-02-05 16:06:26 +00004600 triop( op,
4601 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardj7bc00082005-03-27 05:08:32 +00004602 unop(Iop_F32toF64, loadLE(Ity_F32,mkexpr(addr))),
4603 get_ST(0)
4604 ));
4605 }
4606}
sewardj37d52572005-02-25 14:22:12 +00004607
4608
4609/* ST(dst) = ST(dst) `op` ST(src).
4610 Check dst and src tags when reading but not on write.
4611*/
4612static
4613void fp_do_op_ST_ST ( HChar* op_txt, IROp op, UInt st_src, UInt st_dst,
4614 Bool pop_after )
4615{
sewardj1027dc22005-02-26 01:55:02 +00004616 DIP("f%s%s st(%u), st(%u)\n", op_txt, pop_after?"p":"", st_src, st_dst );
sewardj37d52572005-02-25 14:22:12 +00004617 put_ST_UNCHECKED(
4618 st_dst,
sewardj4796d662006-02-05 16:06:26 +00004619 triop( op,
4620 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4621 get_ST(st_dst),
4622 get_ST(st_src) )
sewardj37d52572005-02-25 14:22:12 +00004623 );
4624 if (pop_after)
4625 fp_pop();
4626}
4627
sewardj137015d2005-03-27 04:01:15 +00004628/* ST(dst) = ST(src) `op` ST(dst).
4629 Check dst and src tags when reading but not on write.
4630*/
4631static
4632void fp_do_oprev_ST_ST ( HChar* op_txt, IROp op, UInt st_src, UInt st_dst,
4633 Bool pop_after )
4634{
4635 DIP("f%s%s st(%u), st(%u)\n", op_txt, pop_after?"p":"", st_src, st_dst );
4636 put_ST_UNCHECKED(
4637 st_dst,
sewardj4796d662006-02-05 16:06:26 +00004638 triop( op,
4639 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4640 get_ST(st_src),
4641 get_ST(st_dst) )
sewardj137015d2005-03-27 04:01:15 +00004642 );
4643 if (pop_after)
4644 fp_pop();
4645}
sewardjc49ce232005-02-25 13:03:03 +00004646
4647/* %rflags(Z,P,C) = UCOMI( st(0), st(i) ) */
4648static void fp_do_ucomi_ST0_STi ( UInt i, Bool pop_after )
4649{
sewardj1027dc22005-02-26 01:55:02 +00004650 DIP("fucomi%s %%st(0),%%st(%u)\n", pop_after ? "p" : "", i);
sewardjc49ce232005-02-25 13:03:03 +00004651 /* This is a bit of a hack (and isn't really right). It sets
4652 Z,P,C,O correctly, but forces A and S to zero, whereas the Intel
4653 documentation implies A and S are unchanged.
4654 */
4655 /* It's also fishy in that it is used both for COMIP and
4656 UCOMIP, and they aren't the same (although similar). */
4657 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(AMD64G_CC_OP_COPY) ));
4658 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
4659 stmt( IRStmt_Put(
4660 OFFB_CC_DEP1,
4661 binop( Iop_And64,
4662 unop( Iop_32Uto64,
4663 binop(Iop_CmpF64, get_ST(0), get_ST(i))),
4664 mkU64(0x45)
4665 )));
4666 if (pop_after)
4667 fp_pop();
4668}
sewardj8d965312005-02-25 02:48:47 +00004669
4670
sewardjb707d102007-07-11 22:49:26 +00004671/* returns
4672 32to16( if e32 <s -32768 || e32 >s 32767 then -32768 else e32 )
4673*/
4674static IRExpr* x87ishly_qnarrow_32_to_16 ( IRExpr* e32 )
4675{
4676 IRTemp t32 = newTemp(Ity_I32);
4677 assign( t32, e32 );
4678 return
4679 IRExpr_Mux0X(
4680 unop(Iop_1Uto8,
4681 binop(Iop_CmpLT64U,
4682 unop(Iop_32Uto64,
4683 binop(Iop_Add32, mkexpr(t32), mkU32(32768))),
4684 mkU64(65536))),
4685 mkU16( 0x8000 ),
4686 unop(Iop_32to16, mkexpr(t32)));
4687}
4688
4689
sewardj8d965312005-02-25 02:48:47 +00004690static
sewardjb4fd2e72005-03-23 13:34:11 +00004691ULong dis_FPU ( /*OUT*/Bool* decode_ok,
sewardj2e28ac42008-12-04 00:05:12 +00004692 VexAbiInfo* vbi, Prefix pfx, Long delta )
sewardj8d965312005-02-25 02:48:47 +00004693{
4694 Int len;
4695 UInt r_src, r_dst;
4696 HChar dis_buf[50];
4697 IRTemp t1, t2;
4698
4699 /* On entry, delta points at the second byte of the insn (the modrm
4700 byte).*/
4701 UChar first_opcode = getUChar(delta-1);
4702 UChar modrm = getUChar(delta+0);
4703
sewardj37d52572005-02-25 14:22:12 +00004704 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xD8 opcodes +-+-+-+-+-+-+-+ */
4705
4706 if (first_opcode == 0xD8) {
4707 if (modrm < 0xC0) {
4708
4709 /* bits 5,4,3 are an opcode extension, and the modRM also
4710 specifies an address. */
sewardj2e28ac42008-12-04 00:05:12 +00004711 IRTemp addr = disAMode( &len, vbi, pfx, delta, dis_buf, 0 );
sewardj7bc00082005-03-27 05:08:32 +00004712 delta += len;
sewardj37d52572005-02-25 14:22:12 +00004713
sewardj901ed122005-02-27 13:25:31 +00004714 switch (gregLO3ofRM(modrm)) {
sewardj37d52572005-02-25 14:22:12 +00004715
sewardj48a89d82005-05-06 11:50:13 +00004716 case 0: /* FADD single-real */
4717 fp_do_op_mem_ST_0 ( addr, "add", dis_buf, Iop_AddF64, False );
4718 break;
4719
sewardje6939f02005-05-07 01:01:24 +00004720 case 1: /* FMUL single-real */
4721 fp_do_op_mem_ST_0 ( addr, "mul", dis_buf, Iop_MulF64, False );
4722 break;
4723
sewardjd20c8852005-01-20 20:04:07 +00004724//.. case 2: /* FCOM single-real */
4725//.. DIP("fcoms %s\n", dis_buf);
4726//.. /* This forces C1 to zero, which isn't right. */
4727//.. put_C3210(
4728//.. binop( Iop_And32,
4729//.. binop(Iop_Shl32,
4730//.. binop(Iop_CmpF64,
4731//.. get_ST(0),
4732//.. unop(Iop_F32toF64,
4733//.. loadLE(Ity_F32,mkexpr(addr)))),
4734//.. mkU8(8)),
4735//.. mkU32(0x4500)
4736//.. ));
4737//.. break;
4738//..
4739//.. case 3: /* FCOMP single-real */
4740//.. DIP("fcomps %s\n", dis_buf);
4741//.. /* This forces C1 to zero, which isn't right. */
4742//.. put_C3210(
4743//.. binop( Iop_And32,
4744//.. binop(Iop_Shl32,
4745//.. binop(Iop_CmpF64,
4746//.. get_ST(0),
4747//.. unop(Iop_F32toF64,
4748//.. loadLE(Ity_F32,mkexpr(addr)))),
4749//.. mkU8(8)),
4750//.. mkU32(0x4500)
4751//.. ));
4752//.. fp_pop();
4753//.. break;
sewardje6939f02005-05-07 01:01:24 +00004754
4755 case 4: /* FSUB single-real */
4756 fp_do_op_mem_ST_0 ( addr, "sub", dis_buf, Iop_SubF64, False );
4757 break;
sewardj7bc00082005-03-27 05:08:32 +00004758
4759 case 5: /* FSUBR single-real */
4760 fp_do_oprev_mem_ST_0 ( addr, "subr", dis_buf, Iop_SubF64, False );
4761 break;
4762
sewardje6939f02005-05-07 01:01:24 +00004763 case 6: /* FDIV single-real */
4764 fp_do_op_mem_ST_0 ( addr, "div", dis_buf, Iop_DivF64, False );
4765 break;
4766
4767 case 7: /* FDIVR single-real */
4768 fp_do_oprev_mem_ST_0 ( addr, "divr", dis_buf, Iop_DivF64, False );
4769 break;
sewardj37d52572005-02-25 14:22:12 +00004770
4771 default:
sewardj901ed122005-02-27 13:25:31 +00004772 vex_printf("unhandled opc_aux = 0x%2x\n", gregLO3ofRM(modrm));
sewardj37d52572005-02-25 14:22:12 +00004773 vex_printf("first_opcode == 0xD8\n");
4774 goto decode_fail;
4775 }
4776 } else {
4777 delta++;
4778 switch (modrm) {
4779
4780 case 0xC0 ... 0xC7: /* FADD %st(?),%st(0) */
4781 fp_do_op_ST_ST ( "add", Iop_AddF64, modrm - 0xC0, 0, False );
4782 break;
4783
sewardj137015d2005-03-27 04:01:15 +00004784 case 0xC8 ... 0xCF: /* FMUL %st(?),%st(0) */
4785 fp_do_op_ST_ST ( "mul", Iop_MulF64, modrm - 0xC8, 0, False );
4786 break;
4787
sewardj1859ecd2007-02-23 08:48:22 +00004788 /* Dunno if this is right */
4789 case 0xD0 ... 0xD7: /* FCOM %st(?),%st(0) */
4790 r_dst = (UInt)modrm - 0xD0;
4791 DIP("fcom %%st(0),%%st(%d)\n", r_dst);
4792 /* This forces C1 to zero, which isn't right. */
4793 put_C3210(
4794 unop(Iop_32Uto64,
4795 binop( Iop_And32,
4796 binop(Iop_Shl32,
4797 binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
4798 mkU8(8)),
4799 mkU32(0x4500)
4800 )));
4801 break;
4802
sewardj90e2e4b2007-05-04 09:41:24 +00004803 /* Dunno if this is right */
4804 case 0xD8 ... 0xDF: /* FCOMP %st(?),%st(0) */
4805 r_dst = (UInt)modrm - 0xD8;
4806 DIP("fcomp %%st(0),%%st(%d)\n", r_dst);
4807 /* This forces C1 to zero, which isn't right. */
4808 put_C3210(
4809 unop(Iop_32Uto64,
4810 binop( Iop_And32,
4811 binop(Iop_Shl32,
4812 binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
4813 mkU8(8)),
4814 mkU32(0x4500)
4815 )));
4816 fp_pop();
4817 break;
4818
sewardj137015d2005-03-27 04:01:15 +00004819 case 0xE0 ... 0xE7: /* FSUB %st(?),%st(0) */
4820 fp_do_op_ST_ST ( "sub", Iop_SubF64, modrm - 0xE0, 0, False );
4821 break;
4822
sewardje6939f02005-05-07 01:01:24 +00004823 case 0xE8 ... 0xEF: /* FSUBR %st(?),%st(0) */
4824 fp_do_oprev_ST_ST ( "subr", Iop_SubF64, modrm - 0xE8, 0, False );
4825 break;
sewardj137015d2005-03-27 04:01:15 +00004826
4827 case 0xF0 ... 0xF7: /* FDIV %st(?),%st(0) */
4828 fp_do_op_ST_ST ( "div", Iop_DivF64, modrm - 0xF0, 0, False );
4829 break;
4830
sewardj48a89d82005-05-06 11:50:13 +00004831 case 0xF8 ... 0xFF: /* FDIVR %st(?),%st(0) */
4832 fp_do_oprev_ST_ST ( "divr", Iop_DivF64, modrm - 0xF8, 0, False );
4833 break;
sewardj37d52572005-02-25 14:22:12 +00004834
4835 default:
4836 goto decode_fail;
4837 }
4838 }
4839 }
sewardj8d965312005-02-25 02:48:47 +00004840
4841 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xD9 opcodes +-+-+-+-+-+-+-+ */
sewardj37d52572005-02-25 14:22:12 +00004842 else
sewardj8d965312005-02-25 02:48:47 +00004843 if (first_opcode == 0xD9) {
4844 if (modrm < 0xC0) {
4845
4846 /* bits 5,4,3 are an opcode extension, and the modRM also
4847 specifies an address. */
sewardj2e28ac42008-12-04 00:05:12 +00004848 IRTemp addr = disAMode( &len, vbi, pfx, delta, dis_buf, 0 );
sewardj8d965312005-02-25 02:48:47 +00004849 delta += len;
4850
sewardj901ed122005-02-27 13:25:31 +00004851 switch (gregLO3ofRM(modrm)) {
sewardj8d965312005-02-25 02:48:47 +00004852
sewardjc49ce232005-02-25 13:03:03 +00004853 case 0: /* FLD single-real */
4854 DIP("flds %s\n", dis_buf);
4855 fp_push();
4856 put_ST(0, unop(Iop_F32toF64,
4857 loadLE(Ity_F32, mkexpr(addr))));
4858 break;
4859
4860 case 2: /* FST single-real */
4861 DIP("fsts %s\n", dis_buf);
4862 storeLE(mkexpr(addr),
4863 binop(Iop_F64toF32, get_roundingmode(), get_ST(0)));
4864 break;
4865
4866 case 3: /* FSTP single-real */
4867 DIP("fstps %s\n", dis_buf);
4868 storeLE(mkexpr(addr),
4869 binop(Iop_F64toF32, get_roundingmode(), get_ST(0)));
4870 fp_pop();
4871 break;
4872
sewardj4017a3b2005-06-13 12:17:27 +00004873 case 4: { /* FLDENV m28 */
4874 /* Uses dirty helper:
4875 VexEmWarn amd64g_do_FLDENV ( VexGuestX86State*, HWord ) */
4876 IRTemp ew = newTemp(Ity_I32);
4877 IRTemp w64 = newTemp(Ity_I64);
4878 IRDirty* d = unsafeIRDirty_0_N (
4879 0/*regparms*/,
4880 "amd64g_dirtyhelper_FLDENV",
4881 &amd64g_dirtyhelper_FLDENV,
4882 mkIRExprVec_1( mkexpr(addr) )
4883 );
4884 d->needsBBP = True;
4885 d->tmp = w64;
4886 /* declare we're reading memory */
4887 d->mFx = Ifx_Read;
4888 d->mAddr = mkexpr(addr);
4889 d->mSize = 28;
4890
4891 /* declare we're writing guest state */
4892 d->nFxState = 4;
4893
4894 d->fxState[0].fx = Ifx_Write;
4895 d->fxState[0].offset = OFFB_FTOP;
4896 d->fxState[0].size = sizeof(UInt);
4897
4898 d->fxState[1].fx = Ifx_Write;
4899 d->fxState[1].offset = OFFB_FPTAGS;
4900 d->fxState[1].size = 8 * sizeof(UChar);
4901
4902 d->fxState[2].fx = Ifx_Write;
4903 d->fxState[2].offset = OFFB_FPROUND;
4904 d->fxState[2].size = sizeof(ULong);
4905
4906 d->fxState[3].fx = Ifx_Write;
4907 d->fxState[3].offset = OFFB_FC3210;
4908 d->fxState[3].size = sizeof(ULong);
4909
4910 stmt( IRStmt_Dirty(d) );
4911
4912 /* ew contains any emulation warning we may need to
4913 issue. If needed, side-exit to the next insn,
4914 reporting the warning, so that Valgrind's dispatcher
4915 sees the warning. */
4916 assign(ew, unop(Iop_64to32,mkexpr(w64)) );
4917 put_emwarn( mkexpr(ew) );
4918 stmt(
4919 IRStmt_Exit(
4920 binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
4921 Ijk_EmWarn,
sewardj9e6491a2005-07-02 19:24:10 +00004922 IRConst_U64( guest_RIP_bbstart+delta )
sewardj4017a3b2005-06-13 12:17:27 +00004923 )
4924 );
4925
4926 DIP("fldenv %s\n", dis_buf);
4927 break;
4928 }
sewardj5e205372005-05-09 02:57:08 +00004929
4930 case 5: {/* FLDCW */
4931 /* The only thing we observe in the control word is the
4932 rounding mode. Therefore, pass the 16-bit value
4933 (x87 native-format control word) to a clean helper,
4934 getting back a 64-bit value, the lower half of which
4935 is the FPROUND value to store, and the upper half of
4936 which is the emulation-warning token which may be
4937 generated.
4938 */
4939 /* ULong amd64h_check_fldcw ( ULong ); */
4940 IRTemp t64 = newTemp(Ity_I64);
4941 IRTemp ew = newTemp(Ity_I32);
4942 DIP("fldcw %s\n", dis_buf);
4943 assign( t64, mkIRExprCCall(
4944 Ity_I64, 0/*regparms*/,
4945 "amd64g_check_fldcw",
4946 &amd64g_check_fldcw,
4947 mkIRExprVec_1(
4948 unop( Iop_16Uto64,
4949 loadLE(Ity_I16, mkexpr(addr)))
4950 )
4951 )
4952 );
4953
4954 put_fpround( unop(Iop_64to32, mkexpr(t64)) );
4955 assign( ew, unop(Iop_64HIto32, mkexpr(t64) ) );
4956 put_emwarn( mkexpr(ew) );
4957 /* Finally, if an emulation warning was reported,
4958 side-exit to the next insn, reporting the warning,
4959 so that Valgrind's dispatcher sees the warning. */
4960 stmt(
4961 IRStmt_Exit(
4962 binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
4963 Ijk_EmWarn,
sewardj9e6491a2005-07-02 19:24:10 +00004964 IRConst_U64( guest_RIP_bbstart+delta )
sewardj5e205372005-05-09 02:57:08 +00004965 )
4966 );
4967 break;
4968 }
4969
sewardj4017a3b2005-06-13 12:17:27 +00004970 case 6: { /* FNSTENV m28 */
4971 /* Uses dirty helper:
4972 void amd64g_do_FSTENV ( VexGuestAMD64State*, HWord ) */
4973 IRDirty* d = unsafeIRDirty_0_N (
4974 0/*regparms*/,
4975 "amd64g_dirtyhelper_FSTENV",
4976 &amd64g_dirtyhelper_FSTENV,
4977 mkIRExprVec_1( mkexpr(addr) )
4978 );
4979 d->needsBBP = True;
4980 /* declare we're writing memory */
4981 d->mFx = Ifx_Write;
4982 d->mAddr = mkexpr(addr);
4983 d->mSize = 28;
4984
4985 /* declare we're reading guest state */
4986 d->nFxState = 4;
4987
4988 d->fxState[0].fx = Ifx_Read;
4989 d->fxState[0].offset = OFFB_FTOP;
4990 d->fxState[0].size = sizeof(UInt);
4991
4992 d->fxState[1].fx = Ifx_Read;
4993 d->fxState[1].offset = OFFB_FPTAGS;
4994 d->fxState[1].size = 8 * sizeof(UChar);
4995
4996 d->fxState[2].fx = Ifx_Read;
4997 d->fxState[2].offset = OFFB_FPROUND;
4998 d->fxState[2].size = sizeof(ULong);
4999
5000 d->fxState[3].fx = Ifx_Read;
5001 d->fxState[3].offset = OFFB_FC3210;
5002 d->fxState[3].size = sizeof(ULong);
5003
5004 stmt( IRStmt_Dirty(d) );
5005
5006 DIP("fnstenv %s\n", dis_buf);
5007 break;
5008 }
sewardj5e205372005-05-09 02:57:08 +00005009
5010 case 7: /* FNSTCW */
5011 /* Fake up a native x87 FPU control word. The only
5012 thing it depends on is FPROUND[1:0], so call a clean
5013 helper to cook it up. */
sewardj4017a3b2005-06-13 12:17:27 +00005014 /* ULong amd64g_create_fpucw ( ULong fpround ) */
sewardj5e205372005-05-09 02:57:08 +00005015 DIP("fnstcw %s\n", dis_buf);
5016 storeLE(
5017 mkexpr(addr),
5018 unop( Iop_64to16,
5019 mkIRExprCCall(
5020 Ity_I64, 0/*regp*/,
5021 "amd64g_create_fpucw", &amd64g_create_fpucw,
5022 mkIRExprVec_1( unop(Iop_32Uto64, get_fpround()) )
5023 )
5024 )
5025 );
5026 break;
sewardj8d965312005-02-25 02:48:47 +00005027
5028 default:
sewardj901ed122005-02-27 13:25:31 +00005029 vex_printf("unhandled opc_aux = 0x%2x\n", gregLO3ofRM(modrm));
sewardj8d965312005-02-25 02:48:47 +00005030 vex_printf("first_opcode == 0xD9\n");
5031 goto decode_fail;
5032 }
5033
5034 } else {
5035 delta++;
5036 switch (modrm) {
5037
sewardjc49ce232005-02-25 13:03:03 +00005038 case 0xC0 ... 0xC7: /* FLD %st(?) */
5039 r_src = (UInt)modrm - 0xC0;
sewardj1027dc22005-02-26 01:55:02 +00005040 DIP("fld %%st(%u)\n", r_src);
sewardjc49ce232005-02-25 13:03:03 +00005041 t1 = newTemp(Ity_F64);
5042 assign(t1, get_ST(r_src));
5043 fp_push();
5044 put_ST(0, mkexpr(t1));
5045 break;
sewardj8d965312005-02-25 02:48:47 +00005046
5047 case 0xC8 ... 0xCF: /* FXCH %st(?) */
5048 r_src = (UInt)modrm - 0xC8;
sewardj1027dc22005-02-26 01:55:02 +00005049 DIP("fxch %%st(%u)\n", r_src);
sewardj8d965312005-02-25 02:48:47 +00005050 t1 = newTemp(Ity_F64);
5051 t2 = newTemp(Ity_F64);
5052 assign(t1, get_ST(0));
5053 assign(t2, get_ST(r_src));
5054 put_ST_UNCHECKED(0, mkexpr(t2));
5055 put_ST_UNCHECKED(r_src, mkexpr(t1));
5056 break;
5057
5058 case 0xE0: /* FCHS */
5059 DIP("fchs\n");
5060 put_ST_UNCHECKED(0, unop(Iop_NegF64, get_ST(0)));
5061 break;
5062
sewardj137015d2005-03-27 04:01:15 +00005063 case 0xE1: /* FABS */
5064 DIP("fabs\n");
5065 put_ST_UNCHECKED(0, unop(Iop_AbsF64, get_ST(0)));
5066 break;
5067
sewardj4f9847d2005-07-25 11:58:34 +00005068 case 0xE5: { /* FXAM */
5069 /* This is an interesting one. It examines %st(0),
5070 regardless of whether the tag says it's empty or not.
5071 Here, just pass both the tag (in our format) and the
5072 value (as a double, actually a ULong) to a helper
5073 function. */
5074 IRExpr** args
5075 = mkIRExprVec_2( unop(Iop_8Uto64, get_ST_TAG(0)),
5076 unop(Iop_ReinterpF64asI64,
5077 get_ST_UNCHECKED(0)) );
5078 put_C3210(mkIRExprCCall(
5079 Ity_I64,
5080 0/*regparm*/,
5081 "amd64g_calculate_FXAM", &amd64g_calculate_FXAM,
5082 args
5083 ));
5084 DIP("fxam\n");
5085 break;
5086 }
sewardjc49ce232005-02-25 13:03:03 +00005087
5088 case 0xE8: /* FLD1 */
5089 DIP("fld1\n");
5090 fp_push();
5091 /* put_ST(0, IRExpr_Const(IRConst_F64(1.0))); */
5092 put_ST(0, IRExpr_Const(IRConst_F64i(0x3ff0000000000000ULL)));
5093 break;
5094
sewardj6847d8c2005-05-12 19:21:55 +00005095 case 0xE9: /* FLDL2T */
5096 DIP("fldl2t\n");
5097 fp_push();
5098 /* put_ST(0, IRExpr_Const(IRConst_F64(3.32192809488736234781))); */
5099 put_ST(0, IRExpr_Const(IRConst_F64i(0x400a934f0979a371ULL)));
5100 break;
5101
5102 case 0xEA: /* FLDL2E */
5103 DIP("fldl2e\n");
5104 fp_push();
5105 /* put_ST(0, IRExpr_Const(IRConst_F64(1.44269504088896340739))); */
5106 put_ST(0, IRExpr_Const(IRConst_F64i(0x3ff71547652b82feULL)));
5107 break;
5108
5109 case 0xEB: /* FLDPI */
5110 DIP("fldpi\n");
5111 fp_push();
5112 /* put_ST(0, IRExpr_Const(IRConst_F64(3.14159265358979323851))); */
5113 put_ST(0, IRExpr_Const(IRConst_F64i(0x400921fb54442d18ULL)));
5114 break;
5115
5116 case 0xEC: /* FLDLG2 */
5117 DIP("fldlg2\n");
5118 fp_push();
5119 /* put_ST(0, IRExpr_Const(IRConst_F64(0.301029995663981143))); */
5120 put_ST(0, IRExpr_Const(IRConst_F64i(0x3fd34413509f79ffULL)));
5121 break;
5122
5123 case 0xED: /* FLDLN2 */
5124 DIP("fldln2\n");
5125 fp_push();
5126 /* put_ST(0, IRExpr_Const(IRConst_F64(0.69314718055994530942))); */
5127 put_ST(0, IRExpr_Const(IRConst_F64i(0x3fe62e42fefa39efULL)));
5128 break;
sewardjc49ce232005-02-25 13:03:03 +00005129
5130 case 0xEE: /* FLDZ */
5131 DIP("fldz\n");
5132 fp_push();
5133 /* put_ST(0, IRExpr_Const(IRConst_F64(0.0))); */
5134 put_ST(0, IRExpr_Const(IRConst_F64i(0x0000000000000000ULL)));
5135 break;
5136
sewardj25a85812005-05-08 23:03:48 +00005137 case 0xF0: /* F2XM1 */
5138 DIP("f2xm1\n");
sewardj4796d662006-02-05 16:06:26 +00005139 put_ST_UNCHECKED(0,
5140 binop(Iop_2xm1F64,
5141 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
5142 get_ST(0)));
sewardj25a85812005-05-08 23:03:48 +00005143 break;
5144
5145 case 0xF1: /* FYL2X */
5146 DIP("fyl2x\n");
sewardj4796d662006-02-05 16:06:26 +00005147 put_ST_UNCHECKED(1,
5148 triop(Iop_Yl2xF64,
5149 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
5150 get_ST(1),
5151 get_ST(0)));
sewardj25a85812005-05-08 23:03:48 +00005152 fp_pop();
5153 break;
5154
sewardj5e205372005-05-09 02:57:08 +00005155 case 0xF2: /* FPTAN */
5156 DIP("ftan\n");
sewardj4796d662006-02-05 16:06:26 +00005157 put_ST_UNCHECKED(0,
5158 binop(Iop_TanF64,
5159 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
5160 get_ST(0)));
sewardj5e205372005-05-09 02:57:08 +00005161 fp_push();
5162 put_ST(0, IRExpr_Const(IRConst_F64(1.0)));
5163 clear_C2(); /* HACK */
5164 break;
sewardj25a85812005-05-08 23:03:48 +00005165
5166 case 0xF3: /* FPATAN */
5167 DIP("fpatan\n");
sewardj4796d662006-02-05 16:06:26 +00005168 put_ST_UNCHECKED(1,
5169 triop(Iop_AtanF64,
5170 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
5171 get_ST(1),
5172 get_ST(0)));
sewardj25a85812005-05-08 23:03:48 +00005173 fp_pop();
5174 break;
5175
sewardj879cee02006-03-07 01:15:50 +00005176 case 0xF4: { /* FXTRACT */
5177 IRTemp argF = newTemp(Ity_F64);
5178 IRTemp sigF = newTemp(Ity_F64);
5179 IRTemp expF = newTemp(Ity_F64);
5180 IRTemp argI = newTemp(Ity_I64);
5181 IRTemp sigI = newTemp(Ity_I64);
5182 IRTemp expI = newTemp(Ity_I64);
5183 DIP("fxtract\n");
5184 assign( argF, get_ST(0) );
5185 assign( argI, unop(Iop_ReinterpF64asI64, mkexpr(argF)));
5186 assign( sigI,
5187 mkIRExprCCall(
5188 Ity_I64, 0/*regparms*/,
5189 "x86amd64g_calculate_FXTRACT",
5190 &x86amd64g_calculate_FXTRACT,
5191 mkIRExprVec_2( mkexpr(argI),
5192 mkIRExpr_HWord(0)/*sig*/ ))
5193 );
5194 assign( expI,
5195 mkIRExprCCall(
5196 Ity_I64, 0/*regparms*/,
5197 "x86amd64g_calculate_FXTRACT",
5198 &x86amd64g_calculate_FXTRACT,
5199 mkIRExprVec_2( mkexpr(argI),
5200 mkIRExpr_HWord(1)/*exp*/ ))
5201 );
5202 assign( sigF, unop(Iop_ReinterpI64asF64, mkexpr(sigI)) );
5203 assign( expF, unop(Iop_ReinterpI64asF64, mkexpr(expI)) );
5204 /* exponent */
5205 put_ST_UNCHECKED(0, mkexpr(expF) );
5206 fp_push();
5207 /* significand */
5208 put_ST(0, mkexpr(sigF) );
5209 break;
5210 }
5211
sewardj4970e4e2008-10-11 10:07:55 +00005212 case 0xF5: { /* FPREM1 -- IEEE compliant */
5213 IRTemp a1 = newTemp(Ity_F64);
5214 IRTemp a2 = newTemp(Ity_F64);
5215 DIP("fprem1\n");
5216 /* Do FPREM1 twice, once to get the remainder, and once
5217 to get the C3210 flag values. */
5218 assign( a1, get_ST(0) );
5219 assign( a2, get_ST(1) );
5220 put_ST_UNCHECKED(0,
5221 triop(Iop_PRem1F64,
5222 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
5223 mkexpr(a1),
5224 mkexpr(a2)));
5225 put_C3210(
5226 unop(Iop_32Uto64,
5227 triop(Iop_PRem1C3210F64,
5228 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
5229 mkexpr(a1),
5230 mkexpr(a2)) ));
5231 break;
5232 }
sewardj6847d8c2005-05-12 19:21:55 +00005233
5234 case 0xF7: /* FINCSTP */
5235 DIP("fincstp\n");
5236 put_ftop( binop(Iop_Add32, get_ftop(), mkU32(1)) );
5237 break;
5238
sewardjf4c803b2006-09-11 11:07:34 +00005239 case 0xF8: { /* FPREM -- not IEEE compliant */
5240 IRTemp a1 = newTemp(Ity_F64);
5241 IRTemp a2 = newTemp(Ity_F64);
5242 DIP("fprem\n");
5243 /* Do FPREM twice, once to get the remainder, and once
5244 to get the C3210 flag values. */
5245 assign( a1, get_ST(0) );
5246 assign( a2, get_ST(1) );
5247 put_ST_UNCHECKED(0,
5248 triop(Iop_PRemF64,
5249 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
5250 mkexpr(a1),
5251 mkexpr(a2)));
5252 put_C3210(
5253 unop(Iop_32Uto64,
5254 triop(Iop_PRemC3210F64,
5255 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
5256 mkexpr(a1),
5257 mkexpr(a2)) ));
5258 break;
5259 }
5260
sewardj5e205372005-05-09 02:57:08 +00005261 case 0xF9: /* FYL2XP1 */
5262 DIP("fyl2xp1\n");
sewardj4796d662006-02-05 16:06:26 +00005263 put_ST_UNCHECKED(1,
5264 triop(Iop_Yl2xp1F64,
5265 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
5266 get_ST(1),
5267 get_ST(0)));
sewardj5e205372005-05-09 02:57:08 +00005268 fp_pop();
5269 break;
sewardje6939f02005-05-07 01:01:24 +00005270
5271 case 0xFA: /* FSQRT */
5272 DIP("fsqrt\n");
sewardj4796d662006-02-05 16:06:26 +00005273 put_ST_UNCHECKED(0,
5274 binop(Iop_SqrtF64,
5275 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
5276 get_ST(0)));
sewardje6939f02005-05-07 01:01:24 +00005277 break;
5278
sewardj25a85812005-05-08 23:03:48 +00005279 case 0xFB: { /* FSINCOS */
5280 IRTemp a1 = newTemp(Ity_F64);
5281 assign( a1, get_ST(0) );
5282 DIP("fsincos\n");
sewardj4796d662006-02-05 16:06:26 +00005283 put_ST_UNCHECKED(0,
5284 binop(Iop_SinF64,
5285 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
5286 mkexpr(a1)));
sewardj25a85812005-05-08 23:03:48 +00005287 fp_push();
sewardj4796d662006-02-05 16:06:26 +00005288 put_ST(0,
5289 binop(Iop_CosF64,
5290 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
5291 mkexpr(a1)));
sewardj25a85812005-05-08 23:03:48 +00005292 clear_C2(); /* HACK */
5293 break;
5294 }
5295
5296 case 0xFC: /* FRNDINT */
5297 DIP("frndint\n");
5298 put_ST_UNCHECKED(0,
sewardjb183b852006-02-03 16:08:03 +00005299 binop(Iop_RoundF64toInt, get_roundingmode(), get_ST(0)) );
sewardj25a85812005-05-08 23:03:48 +00005300 break;
5301
5302 case 0xFD: /* FSCALE */
5303 DIP("fscale\n");
sewardj4796d662006-02-05 16:06:26 +00005304 put_ST_UNCHECKED(0,
5305 triop(Iop_ScaleF64,
5306 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
5307 get_ST(0),
5308 get_ST(1)));
sewardj25a85812005-05-08 23:03:48 +00005309 break;
5310
5311 case 0xFE: /* FSIN */
5312 DIP("fsin\n");
sewardj4796d662006-02-05 16:06:26 +00005313 put_ST_UNCHECKED(0,
5314 binop(Iop_SinF64,
5315 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
5316 get_ST(0)));
sewardj25a85812005-05-08 23:03:48 +00005317 clear_C2(); /* HACK */
5318 break;
5319
5320 case 0xFF: /* FCOS */
5321 DIP("fcos\n");
sewardj4796d662006-02-05 16:06:26 +00005322 put_ST_UNCHECKED(0,
5323 binop(Iop_CosF64,
5324 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
5325 get_ST(0)));
sewardj25a85812005-05-08 23:03:48 +00005326 clear_C2(); /* HACK */
5327 break;
sewardj8d965312005-02-25 02:48:47 +00005328
5329 default:
5330 goto decode_fail;
5331 }
5332 }
5333 }
5334
5335 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDA opcodes +-+-+-+-+-+-+-+ */
5336 else
5337 if (first_opcode == 0xDA) {
5338
5339 if (modrm < 0xC0) {
5340
5341 /* bits 5,4,3 are an opcode extension, and the modRM also
5342 specifies an address. */
sewardj6847d8c2005-05-12 19:21:55 +00005343 IROp fop;
sewardj2e28ac42008-12-04 00:05:12 +00005344 IRTemp addr = disAMode( &len, vbi, pfx, delta, dis_buf, 0 );
sewardj8d965312005-02-25 02:48:47 +00005345 delta += len;
sewardj901ed122005-02-27 13:25:31 +00005346 switch (gregLO3ofRM(modrm)) {
sewardj8d965312005-02-25 02:48:47 +00005347
sewardj6847d8c2005-05-12 19:21:55 +00005348 case 0: /* FIADD m32int */ /* ST(0) += m32int */
5349 DIP("fiaddl %s\n", dis_buf);
5350 fop = Iop_AddF64;
5351 goto do_fop_m32;
5352
5353 case 1: /* FIMUL m32int */ /* ST(0) *= m32int */
5354 DIP("fimull %s\n", dis_buf);
5355 fop = Iop_MulF64;
5356 goto do_fop_m32;
5357
5358 case 4: /* FISUB m32int */ /* ST(0) -= m32int */
5359 DIP("fisubl %s\n", dis_buf);
5360 fop = Iop_SubF64;
5361 goto do_fop_m32;
5362
5363 case 5: /* FISUBR m32int */ /* ST(0) = m32int - ST(0) */
5364 DIP("fisubrl %s\n", dis_buf);
5365 fop = Iop_SubF64;
5366 goto do_foprev_m32;
5367
5368 case 6: /* FIDIV m32int */ /* ST(0) /= m32int */
5369 DIP("fisubl %s\n", dis_buf);
5370 fop = Iop_DivF64;
5371 goto do_fop_m32;
5372
5373 case 7: /* FIDIVR m32int */ /* ST(0) = m32int / ST(0) */
5374 DIP("fidivrl %s\n", dis_buf);
5375 fop = Iop_DivF64;
5376 goto do_foprev_m32;
5377
5378 do_fop_m32:
5379 put_ST_UNCHECKED(0,
sewardj4796d662006-02-05 16:06:26 +00005380 triop(fop,
5381 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardj6847d8c2005-05-12 19:21:55 +00005382 get_ST(0),
sewardj6c299f32009-12-31 18:00:12 +00005383 unop(Iop_I32StoF64,
sewardj6847d8c2005-05-12 19:21:55 +00005384 loadLE(Ity_I32, mkexpr(addr)))));
5385 break;
5386
5387 do_foprev_m32:
5388 put_ST_UNCHECKED(0,
sewardj4796d662006-02-05 16:06:26 +00005389 triop(fop,
5390 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardj6c299f32009-12-31 18:00:12 +00005391 unop(Iop_I32StoF64,
sewardj6847d8c2005-05-12 19:21:55 +00005392 loadLE(Ity_I32, mkexpr(addr))),
5393 get_ST(0)));
5394 break;
sewardj8d965312005-02-25 02:48:47 +00005395
5396 default:
sewardj901ed122005-02-27 13:25:31 +00005397 vex_printf("unhandled opc_aux = 0x%2x\n", gregLO3ofRM(modrm));
sewardj8d965312005-02-25 02:48:47 +00005398 vex_printf("first_opcode == 0xDA\n");
5399 goto decode_fail;
5400 }
5401
5402 } else {
5403
5404 delta++;
5405 switch (modrm) {
5406
sewardj48a89d82005-05-06 11:50:13 +00005407 case 0xC0 ... 0xC7: /* FCMOVB ST(i), ST(0) */
5408 r_src = (UInt)modrm - 0xC0;
sewardjca673ab2005-05-11 10:03:08 +00005409 DIP("fcmovb %%st(%u), %%st(0)\n", r_src);
sewardj48a89d82005-05-06 11:50:13 +00005410 put_ST_UNCHECKED(0,
5411 IRExpr_Mux0X(
5412 unop(Iop_1Uto8,
5413 mk_amd64g_calculate_condition(AMD64CondB)),
5414 get_ST(0), get_ST(r_src)) );
5415 break;
sewardj8d965312005-02-25 02:48:47 +00005416
5417 case 0xC8 ... 0xCF: /* FCMOVE(Z) ST(i), ST(0) */
5418 r_src = (UInt)modrm - 0xC8;
sewardj1027dc22005-02-26 01:55:02 +00005419 DIP("fcmovz %%st(%u), %%st(0)\n", r_src);
sewardj8d965312005-02-25 02:48:47 +00005420 put_ST_UNCHECKED(0,
5421 IRExpr_Mux0X(
5422 unop(Iop_1Uto8,
5423 mk_amd64g_calculate_condition(AMD64CondZ)),
5424 get_ST(0), get_ST(r_src)) );
5425 break;
5426
sewardj37d52572005-02-25 14:22:12 +00005427 case 0xD0 ... 0xD7: /* FCMOVBE ST(i), ST(0) */
5428 r_src = (UInt)modrm - 0xD0;
sewardj1027dc22005-02-26 01:55:02 +00005429 DIP("fcmovbe %%st(%u), %%st(0)\n", r_src);
sewardj37d52572005-02-25 14:22:12 +00005430 put_ST_UNCHECKED(0,
5431 IRExpr_Mux0X(
5432 unop(Iop_1Uto8,
5433 mk_amd64g_calculate_condition(AMD64CondBE)),
5434 get_ST(0), get_ST(r_src)) );
5435 break;
5436
sewardj25a85812005-05-08 23:03:48 +00005437 case 0xD8 ... 0xDF: /* FCMOVU ST(i), ST(0) */
5438 r_src = (UInt)modrm - 0xD8;
5439 DIP("fcmovu %%st(%u), %%st(0)\n", r_src);
5440 put_ST_UNCHECKED(0,
5441 IRExpr_Mux0X(
5442 unop(Iop_1Uto8,
5443 mk_amd64g_calculate_condition(AMD64CondP)),
5444 get_ST(0), get_ST(r_src)) );
5445 break;
5446
sewardje7f277a2008-04-28 21:05:33 +00005447 case 0xE9: /* FUCOMPP %st(0),%st(1) */
5448 DIP("fucompp %%st(0),%%st(1)\n");
5449 /* This forces C1 to zero, which isn't right. */
5450 put_C3210(
5451 unop(Iop_32Uto64,
5452 binop( Iop_And32,
5453 binop(Iop_Shl32,
5454 binop(Iop_CmpF64, get_ST(0), get_ST(1)),
5455 mkU8(8)),
5456 mkU32(0x4500)
5457 )));
5458 fp_pop();
5459 fp_pop();
5460 break;
sewardj8d965312005-02-25 02:48:47 +00005461
5462 default:
5463 goto decode_fail;
5464 }
5465
5466 }
5467 }
5468
sewardjc49ce232005-02-25 13:03:03 +00005469 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDB opcodes +-+-+-+-+-+-+-+ */
5470 else
5471 if (first_opcode == 0xDB) {
5472 if (modrm < 0xC0) {
5473
5474 /* bits 5,4,3 are an opcode extension, and the modRM also
5475 specifies an address. */
sewardj2e28ac42008-12-04 00:05:12 +00005476 IRTemp addr = disAMode( &len, vbi, pfx, delta, dis_buf, 0 );
sewardjc49ce232005-02-25 13:03:03 +00005477 delta += len;
5478
sewardj901ed122005-02-27 13:25:31 +00005479 switch (gregLO3ofRM(modrm)) {
sewardjc49ce232005-02-25 13:03:03 +00005480
sewardj5cc00ff2005-03-27 04:48:32 +00005481 case 0: /* FILD m32int */
5482 DIP("fildl %s\n", dis_buf);
5483 fp_push();
sewardj6c299f32009-12-31 18:00:12 +00005484 put_ST(0, unop(Iop_I32StoF64,
sewardj5cc00ff2005-03-27 04:48:32 +00005485 loadLE(Ity_I32, mkexpr(addr))));
5486 break;
5487
sewardjfcf21f32006-08-04 14:51:19 +00005488 case 1: /* FISTTPL m32 (SSE3) */
5489 DIP("fisttpl %s\n", dis_buf);
5490 storeLE( mkexpr(addr),
sewardj6c299f32009-12-31 18:00:12 +00005491 binop(Iop_F64toI32S, mkU32(Irrm_ZERO), get_ST(0)) );
sewardjfcf21f32006-08-04 14:51:19 +00005492 fp_pop();
5493 break;
5494
sewardj6847d8c2005-05-12 19:21:55 +00005495 case 2: /* FIST m32 */
5496 DIP("fistl %s\n", dis_buf);
5497 storeLE( mkexpr(addr),
sewardj6c299f32009-12-31 18:00:12 +00005498 binop(Iop_F64toI32S, get_roundingmode(), get_ST(0)) );
sewardj6847d8c2005-05-12 19:21:55 +00005499 break;
sewardj37d52572005-02-25 14:22:12 +00005500
5501 case 3: /* FISTP m32 */
5502 DIP("fistpl %s\n", dis_buf);
5503 storeLE( mkexpr(addr),
sewardj6c299f32009-12-31 18:00:12 +00005504 binop(Iop_F64toI32S, get_roundingmode(), get_ST(0)) );
sewardj37d52572005-02-25 14:22:12 +00005505 fp_pop();
5506 break;
5507
sewardj924215b2005-03-26 21:50:31 +00005508 case 5: { /* FLD extended-real */
5509 /* Uses dirty helper:
5510 ULong amd64g_loadF80le ( ULong )
5511 addr holds the address. First, do a dirty call to
5512 get hold of the data. */
5513 IRTemp val = newTemp(Ity_I64);
5514 IRExpr** args = mkIRExprVec_1 ( mkexpr(addr) );
5515
5516 IRDirty* d = unsafeIRDirty_1_N (
5517 val,
5518 0/*regparms*/,
sewardj8707fef2005-08-23 23:26:37 +00005519 "amd64g_dirtyhelper_loadF80le",
5520 &amd64g_dirtyhelper_loadF80le,
sewardj924215b2005-03-26 21:50:31 +00005521 args
5522 );
5523 /* declare that we're reading memory */
5524 d->mFx = Ifx_Read;
5525 d->mAddr = mkexpr(addr);
5526 d->mSize = 10;
5527
5528 /* execute the dirty call, dumping the result in val. */
5529 stmt( IRStmt_Dirty(d) );
5530 fp_push();
5531 put_ST(0, unop(Iop_ReinterpI64asF64, mkexpr(val)));
5532
5533 DIP("fldt %s\n", dis_buf);
5534 break;
5535 }
5536
5537 case 7: { /* FSTP extended-real */
5538 /* Uses dirty helper:
5539 void amd64g_storeF80le ( ULong addr, ULong data )
5540 */
5541 IRExpr** args
5542 = mkIRExprVec_2( mkexpr(addr),
5543 unop(Iop_ReinterpF64asI64, get_ST(0)) );
5544
5545 IRDirty* d = unsafeIRDirty_0_N (
5546 0/*regparms*/,
sewardj8707fef2005-08-23 23:26:37 +00005547 "amd64g_dirtyhelper_storeF80le",
5548 &amd64g_dirtyhelper_storeF80le,
sewardj924215b2005-03-26 21:50:31 +00005549 args
5550 );
5551 /* declare we're writing memory */
5552 d->mFx = Ifx_Write;
5553 d->mAddr = mkexpr(addr);
5554 d->mSize = 10;
5555
5556 /* execute the dirty call. */
5557 stmt( IRStmt_Dirty(d) );
5558 fp_pop();
5559
5560 DIP("fstpt\n %s", dis_buf);
5561 break;
5562 }
sewardjc49ce232005-02-25 13:03:03 +00005563
5564 default:
sewardj901ed122005-02-27 13:25:31 +00005565 vex_printf("unhandled opc_aux = 0x%2x\n", gregLO3ofRM(modrm));
sewardjc49ce232005-02-25 13:03:03 +00005566 vex_printf("first_opcode == 0xDB\n");
5567 goto decode_fail;
5568 }
5569
5570 } else {
5571
5572 delta++;
5573 switch (modrm) {
5574
sewardj48a89d82005-05-06 11:50:13 +00005575 case 0xC0 ... 0xC7: /* FCMOVNB ST(i), ST(0) */
5576 r_src = (UInt)modrm - 0xC0;
sewardjca673ab2005-05-11 10:03:08 +00005577 DIP("fcmovnb %%st(%u), %%st(0)\n", r_src);
sewardj48a89d82005-05-06 11:50:13 +00005578 put_ST_UNCHECKED(0,
5579 IRExpr_Mux0X(
5580 unop(Iop_1Uto8,
5581 mk_amd64g_calculate_condition(AMD64CondNB)),
5582 get_ST(0), get_ST(r_src)) );
5583 break;
sewardj924215b2005-03-26 21:50:31 +00005584
5585 case 0xC8 ... 0xCF: /* FCMOVNE(NZ) ST(i), ST(0) */
5586 r_src = (UInt)modrm - 0xC8;
sewardj40e144d2005-03-28 00:46:27 +00005587 DIP("fcmovnz %%st(%u), %%st(0)\n", r_src);
sewardj137015d2005-03-27 04:01:15 +00005588 put_ST_UNCHECKED(
5589 0,
5590 IRExpr_Mux0X(
5591 unop(Iop_1Uto8,
5592 mk_amd64g_calculate_condition(AMD64CondNZ)),
5593 get_ST(0),
5594 get_ST(r_src)
5595 )
5596 );
sewardj924215b2005-03-26 21:50:31 +00005597 break;
5598
sewardj137015d2005-03-27 04:01:15 +00005599 case 0xD0 ... 0xD7: /* FCMOVNBE ST(i), ST(0) */
5600 r_src = (UInt)modrm - 0xD0;
sewardj40e144d2005-03-28 00:46:27 +00005601 DIP("fcmovnbe %%st(%u), %%st(0)\n", r_src);
sewardj137015d2005-03-27 04:01:15 +00005602 put_ST_UNCHECKED(
5603 0,
5604 IRExpr_Mux0X(
5605 unop(Iop_1Uto8,
5606 mk_amd64g_calculate_condition(AMD64CondNBE)),
5607 get_ST(0),
5608 get_ST(r_src)
5609 )
5610 );
5611 break;
5612
sewardj3368e102006-03-06 19:05:07 +00005613 case 0xD8 ... 0xDF: /* FCMOVNU ST(i), ST(0) */
5614 r_src = (UInt)modrm - 0xD8;
5615 DIP("fcmovnu %%st(%u), %%st(0)\n", r_src);
5616 put_ST_UNCHECKED(
5617 0,
5618 IRExpr_Mux0X(
5619 unop(Iop_1Uto8,
5620 mk_amd64g_calculate_condition(AMD64CondNP)),
5621 get_ST(0),
5622 get_ST(r_src)
5623 )
5624 );
5625 break;
5626
sewardj4e1a1e92005-05-25 00:44:13 +00005627 case 0xE2:
5628 DIP("fnclex\n");
5629 break;
5630
sewardj0585a032005-11-05 02:55:06 +00005631 case 0xE3: {
5632 /* Uses dirty helper:
5633 void amd64g_do_FINIT ( VexGuestAMD64State* ) */
5634 IRDirty* d = unsafeIRDirty_0_N (
5635 0/*regparms*/,
5636 "amd64g_dirtyhelper_FINIT",
5637 &amd64g_dirtyhelper_FINIT,
5638 mkIRExprVec_0()
5639 );
5640 d->needsBBP = True;
5641
5642 /* declare we're writing guest state */
5643 d->nFxState = 5;
5644
5645 d->fxState[0].fx = Ifx_Write;
5646 d->fxState[0].offset = OFFB_FTOP;
5647 d->fxState[0].size = sizeof(UInt);
5648
5649 d->fxState[1].fx = Ifx_Write;
5650 d->fxState[1].offset = OFFB_FPREGS;
5651 d->fxState[1].size = 8 * sizeof(ULong);
5652
5653 d->fxState[2].fx = Ifx_Write;
5654 d->fxState[2].offset = OFFB_FPTAGS;
5655 d->fxState[2].size = 8 * sizeof(UChar);
5656
5657 d->fxState[3].fx = Ifx_Write;
5658 d->fxState[3].offset = OFFB_FPROUND;
5659 d->fxState[3].size = sizeof(ULong);
5660
5661 d->fxState[4].fx = Ifx_Write;
5662 d->fxState[4].offset = OFFB_FC3210;
5663 d->fxState[4].size = sizeof(ULong);
5664
5665 stmt( IRStmt_Dirty(d) );
5666
5667 DIP("fninit\n");
5668 break;
5669 }
sewardjc49ce232005-02-25 13:03:03 +00005670
5671 case 0xE8 ... 0xEF: /* FUCOMI %st(0),%st(?) */
5672 fp_do_ucomi_ST0_STi( (UInt)modrm - 0xE8, False );
5673 break;
5674
sewardj48a89d82005-05-06 11:50:13 +00005675 case 0xF0 ... 0xF7: /* FCOMI %st(0),%st(?) */
5676 fp_do_ucomi_ST0_STi( (UInt)modrm - 0xF0, False );
5677 break;
sewardjc49ce232005-02-25 13:03:03 +00005678
5679 default:
5680 goto decode_fail;
5681 }
5682 }
5683 }
5684
sewardj137015d2005-03-27 04:01:15 +00005685 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDC opcodes +-+-+-+-+-+-+-+ */
5686 else
5687 if (first_opcode == 0xDC) {
5688 if (modrm < 0xC0) {
5689
sewardj434e0692005-03-27 17:36:08 +00005690 /* bits 5,4,3 are an opcode extension, and the modRM also
5691 specifies an address. */
sewardj2e28ac42008-12-04 00:05:12 +00005692 IRTemp addr = disAMode( &len, vbi, pfx, delta, dis_buf, 0 );
sewardj434e0692005-03-27 17:36:08 +00005693 delta += len;
5694
5695 switch (gregLO3ofRM(modrm)) {
5696
sewardje6939f02005-05-07 01:01:24 +00005697 case 0: /* FADD double-real */
5698 fp_do_op_mem_ST_0 ( addr, "add", dis_buf, Iop_AddF64, True );
5699 break;
5700
5701 case 1: /* FMUL double-real */
5702 fp_do_op_mem_ST_0 ( addr, "mul", dis_buf, Iop_MulF64, True );
5703 break;
5704
sewardjd20c8852005-01-20 20:04:07 +00005705//.. case 2: /* FCOM double-real */
5706//.. DIP("fcoml %s\n", dis_buf);
5707//.. /* This forces C1 to zero, which isn't right. */
5708//.. put_C3210(
5709//.. binop( Iop_And32,
5710//.. binop(Iop_Shl32,
5711//.. binop(Iop_CmpF64,
5712//.. get_ST(0),
5713//.. loadLE(Ity_F64,mkexpr(addr))),
5714//.. mkU8(8)),
5715//.. mkU32(0x4500)
5716//.. ));
5717//.. break;
sewardj566d2c72005-08-10 11:43:42 +00005718
5719 case 3: /* FCOMP double-real */
5720 DIP("fcompl %s\n", dis_buf);
5721 /* This forces C1 to zero, which isn't right. */
5722 put_C3210(
5723 unop(Iop_32Uto64,
5724 binop( Iop_And32,
5725 binop(Iop_Shl32,
5726 binop(Iop_CmpF64,
5727 get_ST(0),
5728 loadLE(Ity_F64,mkexpr(addr))),
5729 mkU8(8)),
5730 mkU32(0x4500)
5731 )));
5732 fp_pop();
5733 break;
sewardje6939f02005-05-07 01:01:24 +00005734
5735 case 4: /* FSUB double-real */
5736 fp_do_op_mem_ST_0 ( addr, "sub", dis_buf, Iop_SubF64, True );
5737 break;
sewardj434e0692005-03-27 17:36:08 +00005738
5739 case 5: /* FSUBR double-real */
5740 fp_do_oprev_mem_ST_0 ( addr, "subr", dis_buf, Iop_SubF64, True );
5741 break;
5742
sewardje6939f02005-05-07 01:01:24 +00005743 case 6: /* FDIV double-real */
5744 fp_do_op_mem_ST_0 ( addr, "div", dis_buf, Iop_DivF64, True );
5745 break;
5746
5747 case 7: /* FDIVR double-real */
5748 fp_do_oprev_mem_ST_0 ( addr, "divr", dis_buf, Iop_DivF64, True );
5749 break;
sewardj434e0692005-03-27 17:36:08 +00005750
5751 default:
5752 vex_printf("unhandled opc_aux = 0x%2x\n", gregLO3ofRM(modrm));
5753 vex_printf("first_opcode == 0xDC\n");
5754 goto decode_fail;
5755 }
sewardj137015d2005-03-27 04:01:15 +00005756
5757 } else {
5758
5759 delta++;
5760 switch (modrm) {
5761
5762 case 0xC0 ... 0xC7: /* FADD %st(0),%st(?) */
5763 fp_do_op_ST_ST ( "add", Iop_AddF64, 0, modrm - 0xC0, False );
5764 break;
5765
sewardj7bc00082005-03-27 05:08:32 +00005766 case 0xC8 ... 0xCF: /* FMUL %st(0),%st(?) */
5767 fp_do_op_ST_ST ( "mul", Iop_MulF64, 0, modrm - 0xC8, False );
5768 break;
5769
sewardj434e0692005-03-27 17:36:08 +00005770 case 0xE0 ... 0xE7: /* FSUBR %st(0),%st(?) */
5771 fp_do_oprev_ST_ST ( "subr", Iop_SubF64, 0, modrm - 0xE0, False );
5772 break;
5773
sewardje6939f02005-05-07 01:01:24 +00005774 case 0xE8 ... 0xEF: /* FSUB %st(0),%st(?) */
5775 fp_do_op_ST_ST ( "sub", Iop_SubF64, 0, modrm - 0xE8, False );
5776 break;
5777
5778 case 0xF0 ... 0xF7: /* FDIVR %st(0),%st(?) */
5779 fp_do_oprev_ST_ST ( "divr", Iop_DivF64, 0, modrm - 0xF0, False );
5780 break;
sewardj137015d2005-03-27 04:01:15 +00005781
5782 case 0xF8 ... 0xFF: /* FDIV %st(0),%st(?) */
5783 fp_do_op_ST_ST ( "div", Iop_DivF64, 0, modrm - 0xF8, False );
5784 break;
5785
5786 default:
5787 goto decode_fail;
5788 }
5789
5790 }
5791 }
sewardj8d965312005-02-25 02:48:47 +00005792
5793 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDD opcodes +-+-+-+-+-+-+-+ */
5794 else
5795 if (first_opcode == 0xDD) {
5796
5797 if (modrm < 0xC0) {
5798
5799 /* bits 5,4,3 are an opcode extension, and the modRM also
5800 specifies an address. */
sewardj2e28ac42008-12-04 00:05:12 +00005801 IRTemp addr = disAMode( &len, vbi, pfx, delta, dis_buf, 0 );
sewardj8d965312005-02-25 02:48:47 +00005802 delta += len;
5803
sewardj901ed122005-02-27 13:25:31 +00005804 switch (gregLO3ofRM(modrm)) {
sewardj8d965312005-02-25 02:48:47 +00005805
5806 case 0: /* FLD double-real */
5807 DIP("fldl %s\n", dis_buf);
5808 fp_push();
sewardjaf1ceca2005-06-30 23:31:27 +00005809 put_ST(0, loadLE(Ity_F64, mkexpr(addr)));
sewardj8d965312005-02-25 02:48:47 +00005810 break;
5811
sewardjfcf21f32006-08-04 14:51:19 +00005812 case 1: /* FISTTPQ m64 (SSE3) */
5813 DIP("fistppll %s\n", dis_buf);
5814 storeLE( mkexpr(addr),
sewardj6c299f32009-12-31 18:00:12 +00005815 binop(Iop_F64toI64S, mkU32(Irrm_ZERO), get_ST(0)) );
sewardjfcf21f32006-08-04 14:51:19 +00005816 fp_pop();
5817 break;
5818
sewardjc49ce232005-02-25 13:03:03 +00005819 case 2: /* FST double-real */
5820 DIP("fstl %s\n", dis_buf);
5821 storeLE(mkexpr(addr), get_ST(0));
5822 break;
sewardj8d965312005-02-25 02:48:47 +00005823
5824 case 3: /* FSTP double-real */
5825 DIP("fstpl %s\n", dis_buf);
5826 storeLE(mkexpr(addr), get_ST(0));
5827 fp_pop();
5828 break;
5829
sewardjd20c8852005-01-20 20:04:07 +00005830//.. case 4: { /* FRSTOR m108 */
5831//.. /* Uses dirty helper:
5832//.. VexEmWarn x86g_do_FRSTOR ( VexGuestX86State*, Addr32 ) */
5833//.. IRTemp ew = newTemp(Ity_I32);
5834//.. IRDirty* d = unsafeIRDirty_0_N (
5835//.. 0/*regparms*/,
5836//.. "x86g_dirtyhelper_FRSTOR",
5837//.. &x86g_dirtyhelper_FRSTOR,
5838//.. mkIRExprVec_1( mkexpr(addr) )
5839//.. );
5840//.. d->needsBBP = True;
5841//.. d->tmp = ew;
5842//.. /* declare we're reading memory */
5843//.. d->mFx = Ifx_Read;
5844//.. d->mAddr = mkexpr(addr);
5845//.. d->mSize = 108;
5846//..
5847//.. /* declare we're writing guest state */
5848//.. d->nFxState = 5;
5849//..
5850//.. d->fxState[0].fx = Ifx_Write;
5851//.. d->fxState[0].offset = OFFB_FTOP;
5852//.. d->fxState[0].size = sizeof(UInt);
5853//..
5854//.. d->fxState[1].fx = Ifx_Write;
5855//.. d->fxState[1].offset = OFFB_FPREGS;
5856//.. d->fxState[1].size = 8 * sizeof(ULong);
5857//..
5858//.. d->fxState[2].fx = Ifx_Write;
5859//.. d->fxState[2].offset = OFFB_FPTAGS;
5860//.. d->fxState[2].size = 8 * sizeof(UChar);
5861//..
5862//.. d->fxState[3].fx = Ifx_Write;
5863//.. d->fxState[3].offset = OFFB_FPROUND;
5864//.. d->fxState[3].size = sizeof(UInt);
5865//..
5866//.. d->fxState[4].fx = Ifx_Write;
5867//.. d->fxState[4].offset = OFFB_FC3210;
5868//.. d->fxState[4].size = sizeof(UInt);
5869//..
5870//.. stmt( IRStmt_Dirty(d) );
5871//..
5872//.. /* ew contains any emulation warning we may need to
5873//.. issue. If needed, side-exit to the next insn,
5874//.. reporting the warning, so that Valgrind's dispatcher
5875//.. sees the warning. */
5876//.. put_emwarn( mkexpr(ew) );
5877//.. stmt(
5878//.. IRStmt_Exit(
5879//.. binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
5880//.. Ijk_EmWarn,
5881//.. IRConst_U32( ((Addr32)guest_eip_bbstart)+delta)
5882//.. )
5883//.. );
5884//..
5885//.. DIP("frstor %s\n", dis_buf);
5886//.. break;
5887//.. }
5888//..
5889//.. case 6: { /* FNSAVE m108 */
5890//.. /* Uses dirty helper:
5891//.. void x86g_do_FSAVE ( VexGuestX86State*, UInt ) */
5892//.. IRDirty* d = unsafeIRDirty_0_N (
5893//.. 0/*regparms*/,
5894//.. "x86g_dirtyhelper_FSAVE",
5895//.. &x86g_dirtyhelper_FSAVE,
5896//.. mkIRExprVec_1( mkexpr(addr) )
5897//.. );
5898//.. d->needsBBP = True;
5899//.. /* declare we're writing memory */
5900//.. d->mFx = Ifx_Write;
5901//.. d->mAddr = mkexpr(addr);
5902//.. d->mSize = 108;
5903//..
5904//.. /* declare we're reading guest state */
5905//.. d->nFxState = 5;
5906//..
5907//.. d->fxState[0].fx = Ifx_Read;
5908//.. d->fxState[0].offset = OFFB_FTOP;
5909//.. d->fxState[0].size = sizeof(UInt);
5910//..
5911//.. d->fxState[1].fx = Ifx_Read;
5912//.. d->fxState[1].offset = OFFB_FPREGS;
5913//.. d->fxState[1].size = 8 * sizeof(ULong);
5914//..
5915//.. d->fxState[2].fx = Ifx_Read;
5916//.. d->fxState[2].offset = OFFB_FPTAGS;
5917//.. d->fxState[2].size = 8 * sizeof(UChar);
5918//..
5919//.. d->fxState[3].fx = Ifx_Read;
5920//.. d->fxState[3].offset = OFFB_FPROUND;
5921//.. d->fxState[3].size = sizeof(UInt);
5922//..
5923//.. d->fxState[4].fx = Ifx_Read;
5924//.. d->fxState[4].offset = OFFB_FC3210;
5925//.. d->fxState[4].size = sizeof(UInt);
5926//..
5927//.. stmt( IRStmt_Dirty(d) );
5928//..
5929//.. DIP("fnsave %s\n", dis_buf);
5930//.. break;
5931//.. }
sewardj8d965312005-02-25 02:48:47 +00005932
sewardj7c2d2822006-03-07 00:22:02 +00005933 case 7: { /* FNSTSW m16 */
5934 IRExpr* sw = get_FPU_sw();
sewardjdd40fdf2006-12-24 02:20:24 +00005935 vassert(typeOfIRExpr(irsb->tyenv, sw) == Ity_I16);
sewardj7c2d2822006-03-07 00:22:02 +00005936 storeLE( mkexpr(addr), sw );
5937 DIP("fnstsw %s\n", dis_buf);
5938 break;
5939 }
5940
sewardj8d965312005-02-25 02:48:47 +00005941 default:
sewardj901ed122005-02-27 13:25:31 +00005942 vex_printf("unhandled opc_aux = 0x%2x\n", gregLO3ofRM(modrm));
sewardj8d965312005-02-25 02:48:47 +00005943 vex_printf("first_opcode == 0xDD\n");
5944 goto decode_fail;
5945 }
5946 } else {
5947 delta++;
5948 switch (modrm) {
5949
sewardj6847d8c2005-05-12 19:21:55 +00005950 case 0xC0 ... 0xC7: /* FFREE %st(?) */
5951 r_dst = (UInt)modrm - 0xC0;
5952 DIP("ffree %%st(%u)\n", r_dst);
5953 put_ST_TAG ( r_dst, mkU8(0) );
5954 break;
5955
sewardjbfabcc42005-08-08 09:58:05 +00005956 case 0xD0 ... 0xD7: /* FST %st(0),%st(?) */
5957 r_dst = (UInt)modrm - 0xD0;
sewardjc7cd2142005-09-09 22:31:49 +00005958 DIP("fst %%st(0),%%st(%u)\n", r_dst);
sewardjbfabcc42005-08-08 09:58:05 +00005959 /* P4 manual says: "If the destination operand is a
5960 non-empty register, the invalid-operation exception
5961 is not generated. Hence put_ST_UNCHECKED. */
5962 put_ST_UNCHECKED(r_dst, get_ST(0));
5963 break;
sewardj8d965312005-02-25 02:48:47 +00005964
5965 case 0xD8 ... 0xDF: /* FSTP %st(0),%st(?) */
5966 r_dst = (UInt)modrm - 0xD8;
sewardj1027dc22005-02-26 01:55:02 +00005967 DIP("fstp %%st(0),%%st(%u)\n", r_dst);
sewardj8d965312005-02-25 02:48:47 +00005968 /* P4 manual says: "If the destination operand is a
5969 non-empty register, the invalid-operation exception
5970 is not generated. Hence put_ST_UNCHECKED. */
5971 put_ST_UNCHECKED(r_dst, get_ST(0));
5972 fp_pop();
5973 break;
5974
sewardjfb6c1792005-10-05 17:58:32 +00005975 case 0xE0 ... 0xE7: /* FUCOM %st(0),%st(?) */
5976 r_dst = (UInt)modrm - 0xE0;
sewardj62d05432005-10-29 22:30:47 +00005977 DIP("fucom %%st(0),%%st(%u)\n", r_dst);
sewardjfb6c1792005-10-05 17:58:32 +00005978 /* This forces C1 to zero, which isn't right. */
5979 put_C3210(
5980 unop(Iop_32Uto64,
5981 binop( Iop_And32,
5982 binop(Iop_Shl32,
5983 binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
5984 mkU8(8)),
5985 mkU32(0x4500)
5986 )));
5987 break;
5988
sewardj9fb2f472005-11-05 01:12:18 +00005989 case 0xE8 ... 0xEF: /* FUCOMP %st(0),%st(?) */
5990 r_dst = (UInt)modrm - 0xE8;
sewardj43f45732005-11-05 13:04:34 +00005991 DIP("fucomp %%st(0),%%st(%u)\n", r_dst);
sewardj9fb2f472005-11-05 01:12:18 +00005992 /* This forces C1 to zero, which isn't right. */
5993 put_C3210(
5994 unop(Iop_32Uto64,
5995 binop( Iop_And32,
5996 binop(Iop_Shl32,
5997 binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
5998 mkU8(8)),
5999 mkU32(0x4500)
6000 )));
6001 fp_pop();
6002 break;
sewardj8d965312005-02-25 02:48:47 +00006003
6004 default:
6005 goto decode_fail;
6006 }
6007 }
6008 }
6009
sewardj137015d2005-03-27 04:01:15 +00006010 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDE opcodes +-+-+-+-+-+-+-+ */
6011 else
6012 if (first_opcode == 0xDE) {
6013
6014 if (modrm < 0xC0) {
6015
sewardj6847d8c2005-05-12 19:21:55 +00006016 /* bits 5,4,3 are an opcode extension, and the modRM also
6017 specifies an address. */
6018 IROp fop;
sewardj2e28ac42008-12-04 00:05:12 +00006019 IRTemp addr = disAMode( &len, vbi, pfx, delta, dis_buf, 0 );
sewardj6847d8c2005-05-12 19:21:55 +00006020 delta += len;
6021
6022 switch (gregLO3ofRM(modrm)) {
6023
6024 case 0: /* FIADD m16int */ /* ST(0) += m16int */
6025 DIP("fiaddw %s\n", dis_buf);
6026 fop = Iop_AddF64;
6027 goto do_fop_m16;
6028
6029 case 1: /* FIMUL m16int */ /* ST(0) *= m16int */
6030 DIP("fimulw %s\n", dis_buf);
6031 fop = Iop_MulF64;
6032 goto do_fop_m16;
6033
6034 case 4: /* FISUB m16int */ /* ST(0) -= m16int */
6035 DIP("fisubw %s\n", dis_buf);
6036 fop = Iop_SubF64;
6037 goto do_fop_m16;
6038
6039 case 5: /* FISUBR m16int */ /* ST(0) = m16int - ST(0) */
6040 DIP("fisubrw %s\n", dis_buf);
6041 fop = Iop_SubF64;
6042 goto do_foprev_m16;
6043
6044 case 6: /* FIDIV m16int */ /* ST(0) /= m16int */
6045 DIP("fisubw %s\n", dis_buf);
6046 fop = Iop_DivF64;
6047 goto do_fop_m16;
6048
6049 case 7: /* FIDIVR m16int */ /* ST(0) = m16int / ST(0) */
6050 DIP("fidivrw %s\n", dis_buf);
6051 fop = Iop_DivF64;
6052 goto do_foprev_m16;
6053
6054 do_fop_m16:
6055 put_ST_UNCHECKED(0,
sewardj4796d662006-02-05 16:06:26 +00006056 triop(fop,
6057 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardj6847d8c2005-05-12 19:21:55 +00006058 get_ST(0),
sewardj6c299f32009-12-31 18:00:12 +00006059 unop(Iop_I32StoF64,
sewardj6847d8c2005-05-12 19:21:55 +00006060 unop(Iop_16Sto32,
6061 loadLE(Ity_I16, mkexpr(addr))))));
6062 break;
6063
6064 do_foprev_m16:
6065 put_ST_UNCHECKED(0,
sewardj4796d662006-02-05 16:06:26 +00006066 triop(fop,
6067 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardj6c299f32009-12-31 18:00:12 +00006068 unop(Iop_I32StoF64,
sewardj6847d8c2005-05-12 19:21:55 +00006069 unop(Iop_16Sto32,
6070 loadLE(Ity_I16, mkexpr(addr)))),
6071 get_ST(0)));
6072 break;
6073
6074 default:
6075 vex_printf("unhandled opc_aux = 0x%2x\n", gregLO3ofRM(modrm));
6076 vex_printf("first_opcode == 0xDE\n");
6077 goto decode_fail;
6078 }
sewardj137015d2005-03-27 04:01:15 +00006079
6080 } else {
6081
6082 delta++;
6083 switch (modrm) {
6084
6085 case 0xC0 ... 0xC7: /* FADDP %st(0),%st(?) */
6086 fp_do_op_ST_ST ( "add", Iop_AddF64, 0, modrm - 0xC0, True );
6087 break;
6088
6089 case 0xC8 ... 0xCF: /* FMULP %st(0),%st(?) */
6090 fp_do_op_ST_ST ( "mul", Iop_MulF64, 0, modrm - 0xC8, True );
6091 break;
6092
sewardj1859ecd2007-02-23 08:48:22 +00006093 case 0xD9: /* FCOMPP %st(0),%st(1) */
6094 DIP("fcompp %%st(0),%%st(1)\n");
6095 /* This forces C1 to zero, which isn't right. */
6096 put_C3210(
6097 unop(Iop_32Uto64,
6098 binop( Iop_And32,
6099 binop(Iop_Shl32,
6100 binop(Iop_CmpF64, get_ST(0), get_ST(1)),
6101 mkU8(8)),
6102 mkU32(0x4500)
6103 )));
6104 fp_pop();
6105 fp_pop();
6106 break;
sewardj137015d2005-03-27 04:01:15 +00006107
6108 case 0xE0 ... 0xE7: /* FSUBRP %st(0),%st(?) */
6109 fp_do_oprev_ST_ST ( "subr", Iop_SubF64, 0, modrm - 0xE0, True );
6110 break;
6111
6112 case 0xE8 ... 0xEF: /* FSUBP %st(0),%st(?) */
6113 fp_do_op_ST_ST ( "sub", Iop_SubF64, 0, modrm - 0xE8, True );
6114 break;
6115
6116 case 0xF0 ... 0xF7: /* FDIVRP %st(0),%st(?) */
6117 fp_do_oprev_ST_ST ( "divr", Iop_DivF64, 0, modrm - 0xF0, True );
6118 break;
6119
6120 case 0xF8 ... 0xFF: /* FDIVP %st(0),%st(?) */
6121 fp_do_op_ST_ST ( "div", Iop_DivF64, 0, modrm - 0xF8, True );
6122 break;
6123
6124 default:
6125 goto decode_fail;
6126 }
6127
6128 }
6129 }
sewardjc49ce232005-02-25 13:03:03 +00006130
6131 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDF opcodes +-+-+-+-+-+-+-+ */
6132 else
6133 if (first_opcode == 0xDF) {
6134
6135 if (modrm < 0xC0) {
6136
6137 /* bits 5,4,3 are an opcode extension, and the modRM also
6138 specifies an address. */
sewardj2e28ac42008-12-04 00:05:12 +00006139 IRTemp addr = disAMode( &len, vbi, pfx, delta, dis_buf, 0 );
sewardjc49ce232005-02-25 13:03:03 +00006140 delta += len;
6141
sewardj901ed122005-02-27 13:25:31 +00006142 switch (gregLO3ofRM(modrm)) {
sewardjc49ce232005-02-25 13:03:03 +00006143
sewardj434e0692005-03-27 17:36:08 +00006144 case 0: /* FILD m16int */
6145 DIP("fildw %s\n", dis_buf);
6146 fp_push();
sewardj6c299f32009-12-31 18:00:12 +00006147 put_ST(0, unop(Iop_I32StoF64,
sewardj434e0692005-03-27 17:36:08 +00006148 unop(Iop_16Sto32,
6149 loadLE(Ity_I16, mkexpr(addr)))));
6150 break;
6151
sewardjfcf21f32006-08-04 14:51:19 +00006152 case 1: /* FISTTPS m16 (SSE3) */
6153 DIP("fisttps %s\n", dis_buf);
6154 storeLE( mkexpr(addr),
sewardjb707d102007-07-11 22:49:26 +00006155 x87ishly_qnarrow_32_to_16(
sewardj6c299f32009-12-31 18:00:12 +00006156 binop(Iop_F64toI32S, mkU32(Irrm_ZERO), get_ST(0)) ));
sewardjfcf21f32006-08-04 14:51:19 +00006157 fp_pop();
6158 break;
6159
sewardjd20c8852005-01-20 20:04:07 +00006160//.. case 2: /* FIST m16 */
6161//.. DIP("fistp %s\n", dis_buf);
6162//.. storeLE( mkexpr(addr),
6163//.. binop(Iop_F64toI16, get_roundingmode(), get_ST(0)) );
6164//.. break;
sewardj6847d8c2005-05-12 19:21:55 +00006165
sewardjb707d102007-07-11 22:49:26 +00006166 case 3: /* FISTP m16 */
6167 DIP("fistps %s\n", dis_buf);
6168 storeLE( mkexpr(addr),
6169 x87ishly_qnarrow_32_to_16(
sewardj6c299f32009-12-31 18:00:12 +00006170 binop(Iop_F64toI32S, get_roundingmode(), get_ST(0)) ));
sewardjb707d102007-07-11 22:49:26 +00006171 fp_pop();
6172 break;
sewardj37d52572005-02-25 14:22:12 +00006173
6174 case 5: /* FILD m64 */
6175 DIP("fildll %s\n", dis_buf);
6176 fp_push();
sewardj6c299f32009-12-31 18:00:12 +00006177 put_ST(0, binop(Iop_I64StoF64,
sewardj37d52572005-02-25 14:22:12 +00006178 get_roundingmode(),
6179 loadLE(Ity_I64, mkexpr(addr))));
6180 break;
6181
sewardj6847d8c2005-05-12 19:21:55 +00006182 case 7: /* FISTP m64 */
6183 DIP("fistpll %s\n", dis_buf);
6184 storeLE( mkexpr(addr),
sewardj6c299f32009-12-31 18:00:12 +00006185 binop(Iop_F64toI64S, get_roundingmode(), get_ST(0)) );
sewardj6847d8c2005-05-12 19:21:55 +00006186 fp_pop();
6187 break;
sewardjc49ce232005-02-25 13:03:03 +00006188
6189 default:
sewardj901ed122005-02-27 13:25:31 +00006190 vex_printf("unhandled opc_aux = 0x%2x\n", gregLO3ofRM(modrm));
sewardjc49ce232005-02-25 13:03:03 +00006191 vex_printf("first_opcode == 0xDF\n");
6192 goto decode_fail;
6193 }
6194
6195 } else {
6196
6197 delta++;
6198 switch (modrm) {
6199
6200 case 0xC0: /* FFREEP %st(0) */
6201 DIP("ffreep %%st(%d)\n", 0);
6202 put_ST_TAG ( 0, mkU8(0) );
6203 fp_pop();
6204 break;
6205
sewardj4f9847d2005-07-25 11:58:34 +00006206 case 0xE0: /* FNSTSW %ax */
6207 DIP("fnstsw %%ax\n");
6208 /* Invent a plausible-looking FPU status word value and
6209 dump it in %AX:
6210 ((ftop & 7) << 11) | (c3210 & 0x4700)
6211 */
6212 putIRegRAX(
6213 2,
6214 unop(Iop_32to16,
6215 binop(Iop_Or32,
6216 binop(Iop_Shl32,
6217 binop(Iop_And32, get_ftop(), mkU32(7)),
6218 mkU8(11)),
6219 binop(Iop_And32,
6220 unop(Iop_64to32, get_C3210()),
6221 mkU32(0x4700))
6222 )));
6223 break;
sewardj924215b2005-03-26 21:50:31 +00006224
6225 case 0xE8 ... 0xEF: /* FUCOMIP %st(0),%st(?) */
6226 fp_do_ucomi_ST0_STi( (UInt)modrm - 0xE8, True );
6227 break;
6228
sewardj48a89d82005-05-06 11:50:13 +00006229 case 0xF0 ... 0xF7: /* FCOMIP %st(0),%st(?) */
6230 /* not really right since COMIP != UCOMIP */
6231 fp_do_ucomi_ST0_STi( (UInt)modrm - 0xF0, True );
6232 break;
sewardjc49ce232005-02-25 13:03:03 +00006233
6234 default:
6235 goto decode_fail;
6236 }
6237 }
6238
6239 }
sewardj8d965312005-02-25 02:48:47 +00006240
6241 else
sewardj137015d2005-03-27 04:01:15 +00006242 goto decode_fail;
sewardj8d965312005-02-25 02:48:47 +00006243
6244 *decode_ok = True;
6245 return delta;
6246
6247 decode_fail:
6248 *decode_ok = False;
6249 return delta;
6250}
6251
6252
sewardj8711f662005-05-09 17:52:56 +00006253/*------------------------------------------------------------*/
6254/*--- ---*/
6255/*--- MMX INSTRUCTIONS ---*/
6256/*--- ---*/
6257/*------------------------------------------------------------*/
6258
6259/* Effect of MMX insns on x87 FPU state (table 11-2 of
6260 IA32 arch manual, volume 3):
6261
6262 Read from, or write to MMX register (viz, any insn except EMMS):
6263 * All tags set to Valid (non-empty) -- FPTAGS[i] := nonzero
6264 * FP stack pointer set to zero
6265
6266 EMMS:
6267 * All tags set to Invalid (empty) -- FPTAGS[i] := zero
6268 * FP stack pointer set to zero
6269*/
6270
6271static void do_MMX_preamble ( void )
6272{
sewardjdd40fdf2006-12-24 02:20:24 +00006273 Int i;
6274 IRRegArray* descr = mkIRRegArray( OFFB_FPTAGS, Ity_I8, 8 );
6275 IRExpr* zero = mkU32(0);
6276 IRExpr* tag1 = mkU8(1);
sewardj8711f662005-05-09 17:52:56 +00006277 put_ftop(zero);
6278 for (i = 0; i < 8; i++)
6279 stmt( IRStmt_PutI( descr, zero, i, tag1 ) );
6280}
6281
6282static void do_EMMS_preamble ( void )
6283{
sewardjdd40fdf2006-12-24 02:20:24 +00006284 Int i;
6285 IRRegArray* descr = mkIRRegArray( OFFB_FPTAGS, Ity_I8, 8 );
6286 IRExpr* zero = mkU32(0);
6287 IRExpr* tag0 = mkU8(0);
sewardj8711f662005-05-09 17:52:56 +00006288 put_ftop(zero);
6289 for (i = 0; i < 8; i++)
6290 stmt( IRStmt_PutI( descr, zero, i, tag0 ) );
6291}
6292
6293
6294static IRExpr* getMMXReg ( UInt archreg )
6295{
6296 vassert(archreg < 8);
6297 return IRExpr_Get( OFFB_FPREGS + 8 * archreg, Ity_I64 );
6298}
6299
6300
6301static void putMMXReg ( UInt archreg, IRExpr* e )
6302{
6303 vassert(archreg < 8);
sewardjdd40fdf2006-12-24 02:20:24 +00006304 vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_I64);
sewardj8711f662005-05-09 17:52:56 +00006305 stmt( IRStmt_Put( OFFB_FPREGS + 8 * archreg, e ) );
6306}
6307
6308
6309/* Helper for non-shift MMX insns. Note this is incomplete in the
6310 sense that it does not first call do_MMX_preamble() -- that is the
6311 responsibility of its caller. */
6312
6313static
sewardj2e28ac42008-12-04 00:05:12 +00006314ULong dis_MMXop_regmem_to_reg ( VexAbiInfo* vbi,
6315 Prefix pfx,
6316 Long delta,
6317 UChar opc,
6318 HChar* name,
6319 Bool show_granularity )
sewardj8711f662005-05-09 17:52:56 +00006320{
6321 HChar dis_buf[50];
6322 UChar modrm = getUChar(delta);
6323 Bool isReg = epartIsReg(modrm);
6324 IRExpr* argL = NULL;
6325 IRExpr* argR = NULL;
6326 IRExpr* argG = NULL;
6327 IRExpr* argE = NULL;
6328 IRTemp res = newTemp(Ity_I64);
6329
6330 Bool invG = False;
6331 IROp op = Iop_INVALID;
6332 void* hAddr = NULL;
sewardjca673ab2005-05-11 10:03:08 +00006333 HChar* hName = NULL;
sewardj8711f662005-05-09 17:52:56 +00006334 Bool eLeft = False;
6335
6336# define XXX(_name) do { hAddr = &_name; hName = #_name; } while (0)
6337
6338 switch (opc) {
6339 /* Original MMX ones */
6340 case 0xFC: op = Iop_Add8x8; break;
6341 case 0xFD: op = Iop_Add16x4; break;
6342 case 0xFE: op = Iop_Add32x2; break;
6343
6344 case 0xEC: op = Iop_QAdd8Sx8; break;
6345 case 0xED: op = Iop_QAdd16Sx4; break;
6346
6347 case 0xDC: op = Iop_QAdd8Ux8; break;
6348 case 0xDD: op = Iop_QAdd16Ux4; break;
6349
6350 case 0xF8: op = Iop_Sub8x8; break;
6351 case 0xF9: op = Iop_Sub16x4; break;
6352 case 0xFA: op = Iop_Sub32x2; break;
6353
6354 case 0xE8: op = Iop_QSub8Sx8; break;
6355 case 0xE9: op = Iop_QSub16Sx4; break;
6356
6357 case 0xD8: op = Iop_QSub8Ux8; break;
6358 case 0xD9: op = Iop_QSub16Ux4; break;
6359
6360 case 0xE5: op = Iop_MulHi16Sx4; break;
6361 case 0xD5: op = Iop_Mul16x4; break;
6362 case 0xF5: XXX(amd64g_calculate_mmx_pmaddwd); break;
6363
6364 case 0x74: op = Iop_CmpEQ8x8; break;
6365 case 0x75: op = Iop_CmpEQ16x4; break;
6366 case 0x76: op = Iop_CmpEQ32x2; break;
6367
6368 case 0x64: op = Iop_CmpGT8Sx8; break;
6369 case 0x65: op = Iop_CmpGT16Sx4; break;
6370 case 0x66: op = Iop_CmpGT32Sx2; break;
6371
6372 case 0x6B: op = Iop_QNarrow32Sx2; eLeft = True; break;
6373 case 0x63: op = Iop_QNarrow16Sx4; eLeft = True; break;
6374 case 0x67: op = Iop_QNarrow16Ux4; eLeft = True; break;
6375
6376 case 0x68: op = Iop_InterleaveHI8x8; eLeft = True; break;
6377 case 0x69: op = Iop_InterleaveHI16x4; eLeft = True; break;
6378 case 0x6A: op = Iop_InterleaveHI32x2; eLeft = True; break;
6379
6380 case 0x60: op = Iop_InterleaveLO8x8; eLeft = True; break;
6381 case 0x61: op = Iop_InterleaveLO16x4; eLeft = True; break;
6382 case 0x62: op = Iop_InterleaveLO32x2; eLeft = True; break;
6383
6384 case 0xDB: op = Iop_And64; break;
6385 case 0xDF: op = Iop_And64; invG = True; break;
6386 case 0xEB: op = Iop_Or64; break;
6387 case 0xEF: /* Possibly do better here if argL and argR are the
6388 same reg */
6389 op = Iop_Xor64; break;
6390
6391 /* Introduced in SSE1 */
6392 case 0xE0: op = Iop_Avg8Ux8; break;
6393 case 0xE3: op = Iop_Avg16Ux4; break;
6394 case 0xEE: op = Iop_Max16Sx4; break;
6395 case 0xDE: op = Iop_Max8Ux8; break;
6396 case 0xEA: op = Iop_Min16Sx4; break;
6397 case 0xDA: op = Iop_Min8Ux8; break;
6398 case 0xE4: op = Iop_MulHi16Ux4; break;
sewardja7ba8c42005-05-10 20:08:34 +00006399 case 0xF6: XXX(amd64g_calculate_mmx_psadbw); break;
sewardj8711f662005-05-09 17:52:56 +00006400
6401 /* Introduced in SSE2 */
6402 case 0xD4: op = Iop_Add64; break;
6403 case 0xFB: op = Iop_Sub64; break;
6404
6405 default:
6406 vex_printf("\n0x%x\n", (Int)opc);
6407 vpanic("dis_MMXop_regmem_to_reg");
6408 }
6409
6410# undef XXX
6411
6412 argG = getMMXReg(gregLO3ofRM(modrm));
6413 if (invG)
6414 argG = unop(Iop_Not64, argG);
6415
6416 if (isReg) {
6417 delta++;
6418 argE = getMMXReg(eregLO3ofRM(modrm));
6419 } else {
6420 Int len;
sewardj2e28ac42008-12-04 00:05:12 +00006421 IRTemp addr = disAMode( &len, vbi, pfx, delta, dis_buf, 0 );
sewardj8711f662005-05-09 17:52:56 +00006422 delta += len;
6423 argE = loadLE(Ity_I64, mkexpr(addr));
6424 }
6425
6426 if (eLeft) {
6427 argL = argE;
6428 argR = argG;
6429 } else {
6430 argL = argG;
6431 argR = argE;
6432 }
6433
6434 if (op != Iop_INVALID) {
6435 vassert(hName == NULL);
6436 vassert(hAddr == NULL);
6437 assign(res, binop(op, argL, argR));
6438 } else {
6439 vassert(hName != NULL);
6440 vassert(hAddr != NULL);
6441 assign( res,
6442 mkIRExprCCall(
6443 Ity_I64,
6444 0/*regparms*/, hName, hAddr,
6445 mkIRExprVec_2( argL, argR )
6446 )
6447 );
6448 }
6449
6450 putMMXReg( gregLO3ofRM(modrm), mkexpr(res) );
6451
6452 DIP("%s%s %s, %s\n",
6453 name, show_granularity ? nameMMXGran(opc & 3) : "",
6454 ( isReg ? nameMMXReg(eregLO3ofRM(modrm)) : dis_buf ),
6455 nameMMXReg(gregLO3ofRM(modrm)) );
6456
6457 return delta;
6458}
6459
6460
6461/* Vector by scalar shift of G by the amount specified at the bottom
6462 of E. This is a straight copy of dis_SSE_shiftG_byE. */
6463
sewardj2e28ac42008-12-04 00:05:12 +00006464static ULong dis_MMX_shiftG_byE ( VexAbiInfo* vbi,
6465 Prefix pfx, Long delta,
sewardj8711f662005-05-09 17:52:56 +00006466 HChar* opname, IROp op )
6467{
6468 HChar dis_buf[50];
6469 Int alen, size;
6470 IRTemp addr;
6471 Bool shl, shr, sar;
6472 UChar rm = getUChar(delta);
6473 IRTemp g0 = newTemp(Ity_I64);
6474 IRTemp g1 = newTemp(Ity_I64);
6475 IRTemp amt = newTemp(Ity_I64);
6476 IRTemp amt8 = newTemp(Ity_I8);
6477
6478 if (epartIsReg(rm)) {
6479 assign( amt, getMMXReg(eregLO3ofRM(rm)) );
6480 DIP("%s %s,%s\n", opname,
6481 nameMMXReg(eregLO3ofRM(rm)),
6482 nameMMXReg(gregLO3ofRM(rm)) );
6483 delta++;
6484 } else {
sewardj2e28ac42008-12-04 00:05:12 +00006485 addr = disAMode ( &alen, vbi, pfx, delta, dis_buf, 0 );
sewardj8711f662005-05-09 17:52:56 +00006486 assign( amt, loadLE(Ity_I64, mkexpr(addr)) );
6487 DIP("%s %s,%s\n", opname,
6488 dis_buf,
6489 nameMMXReg(gregLO3ofRM(rm)) );
6490 delta += alen;
6491 }
6492 assign( g0, getMMXReg(gregLO3ofRM(rm)) );
6493 assign( amt8, unop(Iop_64to8, mkexpr(amt)) );
6494
6495 shl = shr = sar = False;
6496 size = 0;
6497 switch (op) {
6498 case Iop_ShlN16x4: shl = True; size = 32; break;
6499 case Iop_ShlN32x2: shl = True; size = 32; break;
6500 case Iop_Shl64: shl = True; size = 64; break;
6501 case Iop_ShrN16x4: shr = True; size = 16; break;
6502 case Iop_ShrN32x2: shr = True; size = 32; break;
6503 case Iop_Shr64: shr = True; size = 64; break;
6504 case Iop_SarN16x4: sar = True; size = 16; break;
6505 case Iop_SarN32x2: sar = True; size = 32; break;
6506 default: vassert(0);
6507 }
6508
6509 if (shl || shr) {
6510 assign(
6511 g1,
6512 IRExpr_Mux0X(
6513 unop(Iop_1Uto8,binop(Iop_CmpLT64U,mkexpr(amt),mkU64(size))),
6514 mkU64(0),
6515 binop(op, mkexpr(g0), mkexpr(amt8))
6516 )
6517 );
6518 } else
6519 if (sar) {
6520 assign(
6521 g1,
6522 IRExpr_Mux0X(
6523 unop(Iop_1Uto8,binop(Iop_CmpLT64U,mkexpr(amt),mkU64(size))),
6524 binop(op, mkexpr(g0), mkU8(size-1)),
6525 binop(op, mkexpr(g0), mkexpr(amt8))
6526 )
6527 );
6528 } else {
6529 vassert(0);
6530 }
6531
6532 putMMXReg( gregLO3ofRM(rm), mkexpr(g1) );
6533 return delta;
6534}
6535
6536
sewardj3d8107c2005-05-09 22:23:38 +00006537/* Vector by scalar shift of E by an immediate byte. This is a
6538 straight copy of dis_SSE_shiftE_imm. */
6539
6540static
sewardj270def42005-07-03 01:03:01 +00006541ULong dis_MMX_shiftE_imm ( Long delta, HChar* opname, IROp op )
sewardj3d8107c2005-05-09 22:23:38 +00006542{
6543 Bool shl, shr, sar;
6544 UChar rm = getUChar(delta);
6545 IRTemp e0 = newTemp(Ity_I64);
6546 IRTemp e1 = newTemp(Ity_I64);
6547 UChar amt, size;
6548 vassert(epartIsReg(rm));
6549 vassert(gregLO3ofRM(rm) == 2
6550 || gregLO3ofRM(rm) == 4 || gregLO3ofRM(rm) == 6);
sewardjca673ab2005-05-11 10:03:08 +00006551 amt = getUChar(delta+1);
sewardj3d8107c2005-05-09 22:23:38 +00006552 delta += 2;
6553 DIP("%s $%d,%s\n", opname,
6554 (Int)amt,
6555 nameMMXReg(eregLO3ofRM(rm)) );
6556
6557 assign( e0, getMMXReg(eregLO3ofRM(rm)) );
6558
6559 shl = shr = sar = False;
6560 size = 0;
6561 switch (op) {
6562 case Iop_ShlN16x4: shl = True; size = 16; break;
6563 case Iop_ShlN32x2: shl = True; size = 32; break;
6564 case Iop_Shl64: shl = True; size = 64; break;
6565 case Iop_SarN16x4: sar = True; size = 16; break;
6566 case Iop_SarN32x2: sar = True; size = 32; break;
6567 case Iop_ShrN16x4: shr = True; size = 16; break;
6568 case Iop_ShrN32x2: shr = True; size = 32; break;
6569 case Iop_Shr64: shr = True; size = 64; break;
6570 default: vassert(0);
6571 }
6572
6573 if (shl || shr) {
6574 assign( e1, amt >= size
6575 ? mkU64(0)
6576 : binop(op, mkexpr(e0), mkU8(amt))
6577 );
6578 } else
6579 if (sar) {
6580 assign( e1, amt >= size
6581 ? binop(op, mkexpr(e0), mkU8(size-1))
6582 : binop(op, mkexpr(e0), mkU8(amt))
6583 );
6584 } else {
6585 vassert(0);
6586 }
6587
6588 putMMXReg( eregLO3ofRM(rm), mkexpr(e1) );
6589 return delta;
6590}
sewardj8711f662005-05-09 17:52:56 +00006591
6592
6593/* Completely handle all MMX instructions except emms. */
6594
6595static
sewardj2e28ac42008-12-04 00:05:12 +00006596ULong dis_MMX ( Bool* decode_ok,
6597 VexAbiInfo* vbi, Prefix pfx, Int sz, Long delta )
sewardj8711f662005-05-09 17:52:56 +00006598{
6599 Int len;
6600 UChar modrm;
6601 HChar dis_buf[50];
6602 UChar opc = getUChar(delta);
6603 delta++;
6604
6605 /* dis_MMX handles all insns except emms. */
6606 do_MMX_preamble();
6607
6608 switch (opc) {
6609
sewardj3d8107c2005-05-09 22:23:38 +00006610 case 0x6E:
6611 if (sz == 4) {
6612 /* MOVD (src)ireg32-or-mem32 (E), (dst)mmxreg (G)*/
6613 modrm = getUChar(delta);
6614 if (epartIsReg(modrm)) {
6615 delta++;
6616 putMMXReg(
6617 gregLO3ofRM(modrm),
6618 binop( Iop_32HLto64,
6619 mkU32(0),
6620 getIReg32(eregOfRexRM(pfx,modrm)) ) );
6621 DIP("movd %s, %s\n",
6622 nameIReg32(eregOfRexRM(pfx,modrm)),
6623 nameMMXReg(gregLO3ofRM(modrm)));
6624 } else {
sewardj2e28ac42008-12-04 00:05:12 +00006625 IRTemp addr = disAMode( &len, vbi, pfx, delta, dis_buf, 0 );
sewardj3d8107c2005-05-09 22:23:38 +00006626 delta += len;
6627 putMMXReg(
6628 gregLO3ofRM(modrm),
6629 binop( Iop_32HLto64,
6630 mkU32(0),
6631 loadLE(Ity_I32, mkexpr(addr)) ) );
6632 DIP("movd %s, %s\n", dis_buf, nameMMXReg(gregLO3ofRM(modrm)));
6633 }
6634 }
6635 else
6636 if (sz == 8) {
6637 /* MOVD (src)ireg64-or-mem64 (E), (dst)mmxreg (G)*/
6638 modrm = getUChar(delta);
6639 if (epartIsReg(modrm)) {
6640 delta++;
6641 putMMXReg( gregLO3ofRM(modrm),
6642 getIReg64(eregOfRexRM(pfx,modrm)) );
6643 DIP("movd %s, %s\n",
6644 nameIReg64(eregOfRexRM(pfx,modrm)),
6645 nameMMXReg(gregLO3ofRM(modrm)));
6646 } else {
sewardj2e28ac42008-12-04 00:05:12 +00006647 IRTemp addr = disAMode( &len, vbi, pfx, delta, dis_buf, 0 );
sewardj3d8107c2005-05-09 22:23:38 +00006648 delta += len;
6649 putMMXReg( gregLO3ofRM(modrm),
6650 loadLE(Ity_I64, mkexpr(addr)) );
6651 DIP("movd{64} %s, %s\n", dis_buf, nameMMXReg(gregLO3ofRM(modrm)));
6652 }
6653 }
6654 else {
6655 goto mmx_decode_failure;
6656 }
6657 break;
6658
6659 case 0x7E:
6660 if (sz == 4) {
6661 /* MOVD (src)mmxreg (G), (dst)ireg32-or-mem32 (E) */
6662 modrm = getUChar(delta);
6663 if (epartIsReg(modrm)) {
6664 delta++;
6665 putIReg32( eregOfRexRM(pfx,modrm),
6666 unop(Iop_64to32, getMMXReg(gregLO3ofRM(modrm)) ) );
6667 DIP("movd %s, %s\n",
6668 nameMMXReg(gregLO3ofRM(modrm)),
6669 nameIReg32(eregOfRexRM(pfx,modrm)));
6670 } else {
sewardj2e28ac42008-12-04 00:05:12 +00006671 IRTemp addr = disAMode( &len, vbi, pfx, delta, dis_buf, 0 );
sewardj3d8107c2005-05-09 22:23:38 +00006672 delta += len;
6673 storeLE( mkexpr(addr),
6674 unop(Iop_64to32, getMMXReg(gregLO3ofRM(modrm)) ) );
6675 DIP("movd %s, %s\n", nameMMXReg(gregLO3ofRM(modrm)), dis_buf);
6676 }
6677 }
6678 else
6679 if (sz == 8) {
6680 /* MOVD (src)mmxreg (G), (dst)ireg64-or-mem64 (E) */
6681 modrm = getUChar(delta);
6682 if (epartIsReg(modrm)) {
6683 delta++;
6684 putIReg64( eregOfRexRM(pfx,modrm),
6685 getMMXReg(gregLO3ofRM(modrm)) );
6686 DIP("movd %s, %s\n",
6687 nameMMXReg(gregLO3ofRM(modrm)),
6688 nameIReg64(eregOfRexRM(pfx,modrm)));
6689 } else {
sewardj2e28ac42008-12-04 00:05:12 +00006690 IRTemp addr = disAMode( &len, vbi, pfx, delta, dis_buf, 0 );
sewardj3d8107c2005-05-09 22:23:38 +00006691 delta += len;
6692 storeLE( mkexpr(addr),
6693 getMMXReg(gregLO3ofRM(modrm)) );
6694 DIP("movd{64} %s, %s\n", nameMMXReg(gregLO3ofRM(modrm)), dis_buf);
6695 }
6696 } else {
6697 goto mmx_decode_failure;
6698 }
6699 break;
sewardj8711f662005-05-09 17:52:56 +00006700
6701 case 0x6F:
6702 /* MOVQ (src)mmxreg-or-mem, (dst)mmxreg */
sewardj7bdd1bc2008-12-13 16:49:46 +00006703 if (sz != 4
6704 && /*ignore redundant REX.W*/!(sz==8 && haveNo66noF2noF3(pfx)))
sewardj8711f662005-05-09 17:52:56 +00006705 goto mmx_decode_failure;
6706 modrm = getUChar(delta);
6707 if (epartIsReg(modrm)) {
6708 delta++;
6709 putMMXReg( gregLO3ofRM(modrm), getMMXReg(eregLO3ofRM(modrm)) );
6710 DIP("movq %s, %s\n",
6711 nameMMXReg(eregLO3ofRM(modrm)),
6712 nameMMXReg(gregLO3ofRM(modrm)));
6713 } else {
sewardj2e28ac42008-12-04 00:05:12 +00006714 IRTemp addr = disAMode( &len, vbi, pfx, delta, dis_buf, 0 );
sewardj8711f662005-05-09 17:52:56 +00006715 delta += len;
6716 putMMXReg( gregLO3ofRM(modrm), loadLE(Ity_I64, mkexpr(addr)) );
6717 DIP("movq %s, %s\n",
6718 dis_buf, nameMMXReg(gregLO3ofRM(modrm)));
6719 }
6720 break;
6721
6722 case 0x7F:
6723 /* MOVQ (src)mmxreg, (dst)mmxreg-or-mem */
sewardj7bdd1bc2008-12-13 16:49:46 +00006724 if (sz != 4
6725 && /*ignore redundant REX.W*/!(sz==8 && haveNo66noF2noF3(pfx)))
sewardj8711f662005-05-09 17:52:56 +00006726 goto mmx_decode_failure;
6727 modrm = getUChar(delta);
6728 if (epartIsReg(modrm)) {
6729 /* Fall through. The assembler doesn't appear to generate
6730 these. */
6731 goto mmx_decode_failure;
6732 } else {
sewardj2e28ac42008-12-04 00:05:12 +00006733 IRTemp addr = disAMode( &len, vbi, pfx, delta, dis_buf, 0 );
sewardj8711f662005-05-09 17:52:56 +00006734 delta += len;
6735 storeLE( mkexpr(addr), getMMXReg(gregLO3ofRM(modrm)) );
6736 DIP("mov(nt)q %s, %s\n",
6737 nameMMXReg(gregLO3ofRM(modrm)), dis_buf);
6738 }
6739 break;
6740
6741 case 0xFC:
6742 case 0xFD:
6743 case 0xFE: /* PADDgg (src)mmxreg-or-mem, (dst)mmxreg */
6744 if (sz != 4)
6745 goto mmx_decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +00006746 delta = dis_MMXop_regmem_to_reg ( vbi, pfx, delta, opc, "padd", True );
sewardj8711f662005-05-09 17:52:56 +00006747 break;
6748
6749 case 0xEC:
6750 case 0xED: /* PADDSgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj7bdd1bc2008-12-13 16:49:46 +00006751 if (sz != 4
6752 && /*ignore redundant REX.W*/!(sz==8 && haveNo66noF2noF3(pfx)))
sewardj8711f662005-05-09 17:52:56 +00006753 goto mmx_decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +00006754 delta = dis_MMXop_regmem_to_reg ( vbi, pfx, delta, opc, "padds", True );
sewardj8711f662005-05-09 17:52:56 +00006755 break;
6756
6757 case 0xDC:
6758 case 0xDD: /* PADDUSgg (src)mmxreg-or-mem, (dst)mmxreg */
6759 if (sz != 4)
6760 goto mmx_decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +00006761 delta = dis_MMXop_regmem_to_reg ( vbi, pfx, delta, opc, "paddus", True );
sewardj8711f662005-05-09 17:52:56 +00006762 break;
6763
6764 case 0xF8:
6765 case 0xF9:
6766 case 0xFA: /* PSUBgg (src)mmxreg-or-mem, (dst)mmxreg */
6767 if (sz != 4)
6768 goto mmx_decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +00006769 delta = dis_MMXop_regmem_to_reg ( vbi, pfx, delta, opc, "psub", True );
sewardj8711f662005-05-09 17:52:56 +00006770 break;
6771
6772 case 0xE8:
6773 case 0xE9: /* PSUBSgg (src)mmxreg-or-mem, (dst)mmxreg */
6774 if (sz != 4)
6775 goto mmx_decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +00006776 delta = dis_MMXop_regmem_to_reg ( vbi, pfx, delta, opc, "psubs", True );
sewardj8711f662005-05-09 17:52:56 +00006777 break;
6778
6779 case 0xD8:
6780 case 0xD9: /* PSUBUSgg (src)mmxreg-or-mem, (dst)mmxreg */
6781 if (sz != 4)
6782 goto mmx_decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +00006783 delta = dis_MMXop_regmem_to_reg ( vbi, pfx, delta, opc, "psubus", True );
sewardj8711f662005-05-09 17:52:56 +00006784 break;
6785
6786 case 0xE5: /* PMULHW (src)mmxreg-or-mem, (dst)mmxreg */
6787 if (sz != 4)
6788 goto mmx_decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +00006789 delta = dis_MMXop_regmem_to_reg ( vbi, pfx, delta, opc, "pmulhw", False );
sewardj8711f662005-05-09 17:52:56 +00006790 break;
6791
6792 case 0xD5: /* PMULLW (src)mmxreg-or-mem, (dst)mmxreg */
6793 if (sz != 4)
6794 goto mmx_decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +00006795 delta = dis_MMXop_regmem_to_reg ( vbi, pfx, delta, opc, "pmullw", False );
sewardj8711f662005-05-09 17:52:56 +00006796 break;
6797
6798 case 0xF5: /* PMADDWD (src)mmxreg-or-mem, (dst)mmxreg */
6799 vassert(sz == 4);
sewardj2e28ac42008-12-04 00:05:12 +00006800 delta = dis_MMXop_regmem_to_reg ( vbi, pfx, delta, opc, "pmaddwd", False );
sewardj8711f662005-05-09 17:52:56 +00006801 break;
6802
6803 case 0x74:
6804 case 0x75:
6805 case 0x76: /* PCMPEQgg (src)mmxreg-or-mem, (dst)mmxreg */
6806 if (sz != 4)
6807 goto mmx_decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +00006808 delta = dis_MMXop_regmem_to_reg ( vbi, pfx, delta, opc, "pcmpeq", True );
sewardj8711f662005-05-09 17:52:56 +00006809 break;
6810
6811 case 0x64:
6812 case 0x65:
6813 case 0x66: /* PCMPGTgg (src)mmxreg-or-mem, (dst)mmxreg */
6814 if (sz != 4)
6815 goto mmx_decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +00006816 delta = dis_MMXop_regmem_to_reg ( vbi, pfx, delta, opc, "pcmpgt", True );
sewardj8711f662005-05-09 17:52:56 +00006817 break;
6818
6819 case 0x6B: /* PACKSSDW (src)mmxreg-or-mem, (dst)mmxreg */
6820 if (sz != 4)
6821 goto mmx_decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +00006822 delta = dis_MMXop_regmem_to_reg ( vbi, pfx, delta, opc, "packssdw", False );
sewardj8711f662005-05-09 17:52:56 +00006823 break;
6824
6825 case 0x63: /* PACKSSWB (src)mmxreg-or-mem, (dst)mmxreg */
6826 if (sz != 4)
6827 goto mmx_decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +00006828 delta = dis_MMXop_regmem_to_reg ( vbi, pfx, delta, opc, "packsswb", False );
sewardj8711f662005-05-09 17:52:56 +00006829 break;
6830
6831 case 0x67: /* PACKUSWB (src)mmxreg-or-mem, (dst)mmxreg */
6832 if (sz != 4)
6833 goto mmx_decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +00006834 delta = dis_MMXop_regmem_to_reg ( vbi, pfx, delta, opc, "packuswb", False );
sewardj8711f662005-05-09 17:52:56 +00006835 break;
6836
6837 case 0x68:
6838 case 0x69:
6839 case 0x6A: /* PUNPCKHgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj23063322009-01-24 10:34:19 +00006840 if (sz != 4
6841 && /*ignore redundant REX.W*/!(sz==8 && haveNo66noF2noF3(pfx)))
sewardj8711f662005-05-09 17:52:56 +00006842 goto mmx_decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +00006843 delta = dis_MMXop_regmem_to_reg ( vbi, pfx, delta, opc, "punpckh", True );
sewardj8711f662005-05-09 17:52:56 +00006844 break;
6845
6846 case 0x60:
6847 case 0x61:
6848 case 0x62: /* PUNPCKLgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj7bdd1bc2008-12-13 16:49:46 +00006849 if (sz != 4
6850 && /*ignore redundant REX.W*/!(sz==8 && haveNo66noF2noF3(pfx)))
sewardj8711f662005-05-09 17:52:56 +00006851 goto mmx_decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +00006852 delta = dis_MMXop_regmem_to_reg ( vbi, pfx, delta, opc, "punpckl", True );
sewardj8711f662005-05-09 17:52:56 +00006853 break;
6854
6855 case 0xDB: /* PAND (src)mmxreg-or-mem, (dst)mmxreg */
6856 if (sz != 4)
6857 goto mmx_decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +00006858 delta = dis_MMXop_regmem_to_reg ( vbi, pfx, delta, opc, "pand", False );
sewardj8711f662005-05-09 17:52:56 +00006859 break;
6860
6861 case 0xDF: /* PANDN (src)mmxreg-or-mem, (dst)mmxreg */
6862 if (sz != 4)
6863 goto mmx_decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +00006864 delta = dis_MMXop_regmem_to_reg ( vbi, pfx, delta, opc, "pandn", False );
sewardj8711f662005-05-09 17:52:56 +00006865 break;
6866
6867 case 0xEB: /* POR (src)mmxreg-or-mem, (dst)mmxreg */
6868 if (sz != 4)
6869 goto mmx_decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +00006870 delta = dis_MMXop_regmem_to_reg ( vbi, pfx, delta, opc, "por", False );
sewardj8711f662005-05-09 17:52:56 +00006871 break;
6872
6873 case 0xEF: /* PXOR (src)mmxreg-or-mem, (dst)mmxreg */
6874 if (sz != 4)
6875 goto mmx_decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +00006876 delta = dis_MMXop_regmem_to_reg ( vbi, pfx, delta, opc, "pxor", False );
sewardj8711f662005-05-09 17:52:56 +00006877 break;
6878
sewardj2e28ac42008-12-04 00:05:12 +00006879# define SHIFT_BY_REG(_name,_op) \
6880 delta = dis_MMX_shiftG_byE(vbi, pfx, delta, _name, _op); \
sewardj8711f662005-05-09 17:52:56 +00006881 break;
6882
6883 /* PSLLgg (src)mmxreg-or-mem, (dst)mmxreg */
6884 case 0xF1: SHIFT_BY_REG("psllw", Iop_ShlN16x4);
6885 case 0xF2: SHIFT_BY_REG("pslld", Iop_ShlN32x2);
6886 case 0xF3: SHIFT_BY_REG("psllq", Iop_Shl64);
6887
6888 /* PSRLgg (src)mmxreg-or-mem, (dst)mmxreg */
6889 case 0xD1: SHIFT_BY_REG("psrlw", Iop_ShrN16x4);
6890 case 0xD2: SHIFT_BY_REG("psrld", Iop_ShrN32x2);
6891 case 0xD3: SHIFT_BY_REG("psrlq", Iop_Shr64);
6892
6893 /* PSRAgg (src)mmxreg-or-mem, (dst)mmxreg */
6894 case 0xE1: SHIFT_BY_REG("psraw", Iop_SarN16x4);
6895 case 0xE2: SHIFT_BY_REG("psrad", Iop_SarN32x2);
6896
6897# undef SHIFT_BY_REG
sewardj3d8107c2005-05-09 22:23:38 +00006898
6899 case 0x71:
6900 case 0x72:
6901 case 0x73: {
6902 /* (sz==4): PSLLgg/PSRAgg/PSRLgg mmxreg by imm8 */
sewardjca673ab2005-05-11 10:03:08 +00006903 UChar byte2, subopc;
sewardj3d8107c2005-05-09 22:23:38 +00006904 if (sz != 4)
6905 goto mmx_decode_failure;
sewardjca673ab2005-05-11 10:03:08 +00006906 byte2 = getUChar(delta); /* amode / sub-opcode */
6907 subopc = toUChar( (byte2 >> 3) & 7 );
sewardj3d8107c2005-05-09 22:23:38 +00006908
6909# define SHIFT_BY_IMM(_name,_op) \
6910 do { delta = dis_MMX_shiftE_imm(delta,_name,_op); \
6911 } while (0)
6912
6913 if (subopc == 2 /*SRL*/ && opc == 0x71)
6914 SHIFT_BY_IMM("psrlw", Iop_ShrN16x4);
6915 else if (subopc == 2 /*SRL*/ && opc == 0x72)
6916 SHIFT_BY_IMM("psrld", Iop_ShrN32x2);
6917 else if (subopc == 2 /*SRL*/ && opc == 0x73)
6918 SHIFT_BY_IMM("psrlq", Iop_Shr64);
6919
6920 else if (subopc == 4 /*SAR*/ && opc == 0x71)
6921 SHIFT_BY_IMM("psraw", Iop_SarN16x4);
6922 else if (subopc == 4 /*SAR*/ && opc == 0x72)
6923 SHIFT_BY_IMM("psrad", Iop_SarN32x2);
6924
6925 else if (subopc == 6 /*SHL*/ && opc == 0x71)
6926 SHIFT_BY_IMM("psllw", Iop_ShlN16x4);
6927 else if (subopc == 6 /*SHL*/ && opc == 0x72)
6928 SHIFT_BY_IMM("pslld", Iop_ShlN32x2);
6929 else if (subopc == 6 /*SHL*/ && opc == 0x73)
6930 SHIFT_BY_IMM("psllq", Iop_Shl64);
6931
6932 else goto mmx_decode_failure;
6933
6934# undef SHIFT_BY_IMM
6935 break;
6936 }
sewardj8711f662005-05-09 17:52:56 +00006937
sewardj02f79f12007-09-01 18:59:53 +00006938 case 0xF7: {
6939 IRTemp addr = newTemp(Ity_I64);
6940 IRTemp regD = newTemp(Ity_I64);
6941 IRTemp regM = newTemp(Ity_I64);
6942 IRTemp mask = newTemp(Ity_I64);
6943 IRTemp olddata = newTemp(Ity_I64);
6944 IRTemp newdata = newTemp(Ity_I64);
6945
6946 modrm = getUChar(delta);
6947 if (sz != 4 || (!epartIsReg(modrm)))
6948 goto mmx_decode_failure;
6949 delta++;
6950
sewardj2e28ac42008-12-04 00:05:12 +00006951 assign( addr, handleAddrOverrides( vbi, pfx, getIReg64(R_RDI) ));
sewardj02f79f12007-09-01 18:59:53 +00006952 assign( regM, getMMXReg( eregLO3ofRM(modrm) ));
6953 assign( regD, getMMXReg( gregLO3ofRM(modrm) ));
6954 assign( mask, binop(Iop_SarN8x8, mkexpr(regM), mkU8(7)) );
6955 assign( olddata, loadLE( Ity_I64, mkexpr(addr) ));
6956 assign( newdata,
6957 binop(Iop_Or64,
6958 binop(Iop_And64,
6959 mkexpr(regD),
6960 mkexpr(mask) ),
6961 binop(Iop_And64,
6962 mkexpr(olddata),
6963 unop(Iop_Not64, mkexpr(mask)))) );
6964 storeLE( mkexpr(addr), mkexpr(newdata) );
6965 DIP("maskmovq %s,%s\n", nameMMXReg( eregLO3ofRM(modrm) ),
6966 nameMMXReg( gregLO3ofRM(modrm) ) );
6967 break;
6968 }
6969
sewardj8711f662005-05-09 17:52:56 +00006970 /* --- MMX decode failure --- */
6971 default:
6972 mmx_decode_failure:
6973 *decode_ok = False;
6974 return delta; /* ignored */
6975
6976 }
6977
6978 *decode_ok = True;
6979 return delta;
6980}
6981
6982
sewardj33ef9c22005-11-04 20:05:57 +00006983/*------------------------------------------------------------*/
6984/*--- More misc arithmetic and other obscure insns. ---*/
6985/*------------------------------------------------------------*/
6986
6987/* Generate base << amt with vacated places filled with stuff
6988 from xtra. amt guaranteed in 0 .. 63. */
6989static
6990IRExpr* shiftL64_with_extras ( IRTemp base, IRTemp xtra, IRTemp amt )
6991{
6992 /* if amt == 0
6993 then base
6994 else (base << amt) | (xtra >>u (64-amt))
6995 */
6996 return
6997 IRExpr_Mux0X(
6998 mkexpr(amt),
6999 mkexpr(base),
7000 binop(Iop_Or64,
7001 binop(Iop_Shl64, mkexpr(base), mkexpr(amt)),
7002 binop(Iop_Shr64, mkexpr(xtra),
7003 binop(Iop_Sub8, mkU8(64), mkexpr(amt)))
7004 )
7005 );
7006}
7007
7008/* Generate base >>u amt with vacated places filled with stuff
7009 from xtra. amt guaranteed in 0 .. 63. */
7010static
7011IRExpr* shiftR64_with_extras ( IRTemp xtra, IRTemp base, IRTemp amt )
7012{
7013 /* if amt == 0
7014 then base
7015 else (base >>u amt) | (xtra << (64-amt))
7016 */
7017 return
7018 IRExpr_Mux0X(
7019 mkexpr(amt),
7020 mkexpr(base),
7021 binop(Iop_Or64,
7022 binop(Iop_Shr64, mkexpr(base), mkexpr(amt)),
7023 binop(Iop_Shl64, mkexpr(xtra),
7024 binop(Iop_Sub8, mkU8(64), mkexpr(amt)))
7025 )
7026 );
7027}
7028
7029/* Double length left and right shifts. Apparently only required in
7030 v-size (no b- variant). */
7031static
sewardj2e28ac42008-12-04 00:05:12 +00007032ULong dis_SHLRD_Gv_Ev ( VexAbiInfo* vbi,
7033 Prefix pfx,
sewardj33ef9c22005-11-04 20:05:57 +00007034 Long delta, UChar modrm,
7035 Int sz,
7036 IRExpr* shift_amt,
7037 Bool amt_is_literal,
sewardjf5268432005-11-05 02:58:55 +00007038 HChar* shift_amt_txt,
sewardj33ef9c22005-11-04 20:05:57 +00007039 Bool left_shift )
7040{
7041 /* shift_amt :: Ity_I8 is the amount to shift. shift_amt_txt is used
7042 for printing it. And eip on entry points at the modrm byte. */
7043 Int len;
7044 HChar dis_buf[50];
7045
7046 IRType ty = szToITy(sz);
7047 IRTemp gsrc = newTemp(ty);
7048 IRTemp esrc = newTemp(ty);
7049 IRTemp addr = IRTemp_INVALID;
7050 IRTemp tmpSH = newTemp(Ity_I8);
7051 IRTemp tmpSS = newTemp(Ity_I8);
7052 IRTemp tmp64 = IRTemp_INVALID;
7053 IRTemp res64 = IRTemp_INVALID;
7054 IRTemp rss64 = IRTemp_INVALID;
7055 IRTemp resTy = IRTemp_INVALID;
7056 IRTemp rssTy = IRTemp_INVALID;
7057 Int mask = sz==8 ? 63 : 31;
7058
7059 vassert(sz == 2 || sz == 4 || sz == 8);
7060
7061 /* The E-part is the destination; this is shifted. The G-part
7062 supplies bits to be shifted into the E-part, but is not
7063 changed.
7064
7065 If shifting left, form a double-length word with E at the top
7066 and G at the bottom, and shift this left. The result is then in
7067 the high part.
7068
7069 If shifting right, form a double-length word with G at the top
7070 and E at the bottom, and shift this right. The result is then
7071 at the bottom. */
7072
7073 /* Fetch the operands. */
7074
7075 assign( gsrc, getIRegG(sz, pfx, modrm) );
7076
7077 if (epartIsReg(modrm)) {
7078 delta++;
7079 assign( esrc, getIRegE(sz, pfx, modrm) );
7080 DIP("sh%cd%c %s, %s, %s\n",
7081 ( left_shift ? 'l' : 'r' ), nameISize(sz),
7082 shift_amt_txt,
7083 nameIRegG(sz, pfx, modrm), nameIRegE(sz, pfx, modrm));
7084 } else {
sewardj2e28ac42008-12-04 00:05:12 +00007085 addr = disAMode ( &len, vbi, pfx, delta, dis_buf,
sewardj75ce3652005-11-04 20:49:36 +00007086 /* # bytes following amode */
7087 amt_is_literal ? 1 : 0 );
sewardj33ef9c22005-11-04 20:05:57 +00007088 delta += len;
7089 assign( esrc, loadLE(ty, mkexpr(addr)) );
7090 DIP("sh%cd%c %s, %s, %s\n",
7091 ( left_shift ? 'l' : 'r' ), nameISize(sz),
7092 shift_amt_txt,
7093 nameIRegG(sz, pfx, modrm), dis_buf);
7094 }
7095
7096 /* Calculate the masked shift amount (tmpSH), the masked subshift
7097 amount (tmpSS), the shifted value (res64) and the subshifted
7098 value (rss64). */
7099
7100 assign( tmpSH, binop(Iop_And8, shift_amt, mkU8(mask)) );
7101 assign( tmpSS, binop(Iop_And8,
7102 binop(Iop_Sub8, mkexpr(tmpSH), mkU8(1) ),
7103 mkU8(mask)));
7104
7105 tmp64 = newTemp(Ity_I64);
7106 res64 = newTemp(Ity_I64);
7107 rss64 = newTemp(Ity_I64);
7108
7109 if (sz == 2 || sz == 4) {
7110
7111 /* G is xtra; E is data */
7112 /* what a freaking nightmare: */
7113 if (sz == 4 && left_shift) {
7114 assign( tmp64, binop(Iop_32HLto64, mkexpr(esrc), mkexpr(gsrc)) );
7115 assign( res64,
7116 binop(Iop_Shr64,
7117 binop(Iop_Shl64, mkexpr(tmp64), mkexpr(tmpSH)),
7118 mkU8(32)) );
7119 assign( rss64,
7120 binop(Iop_Shr64,
7121 binop(Iop_Shl64, mkexpr(tmp64), mkexpr(tmpSS)),
7122 mkU8(32)) );
7123 }
7124 else
7125 if (sz == 4 && !left_shift) {
7126 assign( tmp64, binop(Iop_32HLto64, mkexpr(gsrc), mkexpr(esrc)) );
7127 assign( res64, binop(Iop_Shr64, mkexpr(tmp64), mkexpr(tmpSH)) );
7128 assign( rss64, binop(Iop_Shr64, mkexpr(tmp64), mkexpr(tmpSS)) );
7129 }
7130 else
7131 if (sz == 2 && left_shift) {
7132 assign( tmp64,
7133 binop(Iop_32HLto64,
7134 binop(Iop_16HLto32, mkexpr(esrc), mkexpr(gsrc)),
7135 binop(Iop_16HLto32, mkexpr(gsrc), mkexpr(gsrc))
7136 ));
7137 /* result formed by shifting [esrc'gsrc'gsrc'gsrc] */
7138 assign( res64,
7139 binop(Iop_Shr64,
7140 binop(Iop_Shl64, mkexpr(tmp64), mkexpr(tmpSH)),
7141 mkU8(48)) );
7142 /* subshift formed by shifting [esrc'0000'0000'0000] */
7143 assign( rss64,
7144 binop(Iop_Shr64,
7145 binop(Iop_Shl64,
7146 binop(Iop_Shl64, unop(Iop_16Uto64, mkexpr(esrc)),
7147 mkU8(48)),
7148 mkexpr(tmpSS)),
7149 mkU8(48)) );
7150 }
7151 else
7152 if (sz == 2 && !left_shift) {
7153 assign( tmp64,
7154 binop(Iop_32HLto64,
7155 binop(Iop_16HLto32, mkexpr(gsrc), mkexpr(gsrc)),
7156 binop(Iop_16HLto32, mkexpr(gsrc), mkexpr(esrc))
7157 ));
7158 /* result formed by shifting [gsrc'gsrc'gsrc'esrc] */
7159 assign( res64, binop(Iop_Shr64, mkexpr(tmp64), mkexpr(tmpSH)) );
7160 /* subshift formed by shifting [0000'0000'0000'esrc] */
7161 assign( rss64, binop(Iop_Shr64,
7162 unop(Iop_16Uto64, mkexpr(esrc)),
7163 mkexpr(tmpSS)) );
7164 }
7165
7166 } else {
7167
7168 vassert(sz == 8);
7169 if (left_shift) {
7170 assign( res64, shiftL64_with_extras( esrc, gsrc, tmpSH ));
7171 assign( rss64, shiftL64_with_extras( esrc, gsrc, tmpSS ));
7172 } else {
7173 assign( res64, shiftR64_with_extras( gsrc, esrc, tmpSH ));
7174 assign( rss64, shiftR64_with_extras( gsrc, esrc, tmpSS ));
7175 }
7176
7177 }
7178
7179 resTy = newTemp(ty);
7180 rssTy = newTemp(ty);
7181 assign( resTy, narrowTo(ty, mkexpr(res64)) );
7182 assign( rssTy, narrowTo(ty, mkexpr(rss64)) );
7183
7184 /* Put result back and write the flags thunk. */
7185 setFlags_DEP1_DEP2_shift ( left_shift ? Iop_Shl64 : Iop_Sar64,
7186 resTy, rssTy, ty, tmpSH );
7187
7188 if (epartIsReg(modrm)) {
7189 putIRegE(sz, pfx, modrm, mkexpr(resTy));
7190 } else {
7191 storeLE( mkexpr(addr), mkexpr(resTy) );
7192 }
7193
7194 if (amt_is_literal) delta++;
7195 return delta;
7196}
sewardj9ed16802005-08-24 10:46:19 +00007197
7198
7199/* Handle BT/BTS/BTR/BTC Gv, Ev. Apparently b-size is not
7200 required. */
7201
7202typedef enum { BtOpNone, BtOpSet, BtOpReset, BtOpComp } BtOp;
7203
7204static HChar* nameBtOp ( BtOp op )
7205{
7206 switch (op) {
7207 case BtOpNone: return "";
7208 case BtOpSet: return "s";
7209 case BtOpReset: return "r";
7210 case BtOpComp: return "c";
7211 default: vpanic("nameBtOp(amd64)");
7212 }
7213}
7214
7215
7216static
sewardj2e28ac42008-12-04 00:05:12 +00007217ULong dis_bt_G_E ( VexAbiInfo* vbi,
7218 Prefix pfx, Int sz, Long delta, BtOp op )
sewardj9ed16802005-08-24 10:46:19 +00007219{
7220 HChar dis_buf[50];
7221 UChar modrm;
7222 Int len;
7223 IRTemp t_fetched, t_bitno0, t_bitno1, t_bitno2, t_addr0,
sewardje9d8a262009-07-01 08:06:34 +00007224 t_addr1, t_rsp, t_mask, t_new;
sewardj9ed16802005-08-24 10:46:19 +00007225
7226 vassert(sz == 2 || sz == 4 || sz == 8);
7227
7228 t_fetched = t_bitno0 = t_bitno1 = t_bitno2
sewardje9d8a262009-07-01 08:06:34 +00007229 = t_addr0 = t_addr1 = t_rsp
7230 = t_mask = t_new = IRTemp_INVALID;
sewardj9ed16802005-08-24 10:46:19 +00007231
7232 t_fetched = newTemp(Ity_I8);
sewardje9d8a262009-07-01 08:06:34 +00007233 t_new = newTemp(Ity_I8);
sewardj9ed16802005-08-24 10:46:19 +00007234 t_bitno0 = newTemp(Ity_I64);
7235 t_bitno1 = newTemp(Ity_I64);
7236 t_bitno2 = newTemp(Ity_I8);
7237 t_addr1 = newTemp(Ity_I64);
7238 modrm = getUChar(delta);
7239
7240 assign( t_bitno0, widenSto64(getIRegG(sz, pfx, modrm)) );
7241
7242 if (epartIsReg(modrm)) {
7243 delta++;
7244 /* Get it onto the client's stack. */
7245 t_rsp = newTemp(Ity_I64);
7246 t_addr0 = newTemp(Ity_I64);
7247
7248 assign( t_rsp, binop(Iop_Sub64, getIReg64(R_RSP), mkU64(sz)) );
7249 putIReg64(R_RSP, mkexpr(t_rsp));
7250
7251 storeLE( mkexpr(t_rsp), getIRegE(sz, pfx, modrm) );
7252
7253 /* Make t_addr0 point at it. */
7254 assign( t_addr0, mkexpr(t_rsp) );
7255
7256 /* Mask out upper bits of the shift amount, since we're doing a
7257 reg. */
7258 assign( t_bitno1, binop(Iop_And64,
7259 mkexpr(t_bitno0),
7260 mkU64(sz == 8 ? 63 : sz == 4 ? 31 : 15)) );
7261
7262 } else {
sewardj2e28ac42008-12-04 00:05:12 +00007263 t_addr0 = disAMode ( &len, vbi, pfx, delta, dis_buf, 0 );
sewardj9ed16802005-08-24 10:46:19 +00007264 delta += len;
7265 assign( t_bitno1, mkexpr(t_bitno0) );
7266 }
7267
7268 /* At this point: t_addr0 is the address being operated on. If it
7269 was a reg, we will have pushed it onto the client's stack.
7270 t_bitno1 is the bit number, suitably masked in the case of a
7271 reg. */
7272
7273 /* Now the main sequence. */
7274 assign( t_addr1,
7275 binop(Iop_Add64,
7276 mkexpr(t_addr0),
7277 binop(Iop_Sar64, mkexpr(t_bitno1), mkU8(3))) );
7278
7279 /* t_addr1 now holds effective address */
7280
7281 assign( t_bitno2,
7282 unop(Iop_64to8,
7283 binop(Iop_And64, mkexpr(t_bitno1), mkU64(7))) );
7284
7285 /* t_bitno2 contains offset of bit within byte */
7286
7287 if (op != BtOpNone) {
7288 t_mask = newTemp(Ity_I8);
7289 assign( t_mask, binop(Iop_Shl8, mkU8(1), mkexpr(t_bitno2)) );
7290 }
7291
7292 /* t_mask is now a suitable byte mask */
7293
7294 assign( t_fetched, loadLE(Ity_I8, mkexpr(t_addr1)) );
7295
7296 if (op != BtOpNone) {
7297 switch (op) {
sewardje9d8a262009-07-01 08:06:34 +00007298 case BtOpSet:
7299 assign( t_new,
7300 binop(Iop_Or8, mkexpr(t_fetched), mkexpr(t_mask)) );
sewardj9ed16802005-08-24 10:46:19 +00007301 break;
sewardje9d8a262009-07-01 08:06:34 +00007302 case BtOpComp:
7303 assign( t_new,
7304 binop(Iop_Xor8, mkexpr(t_fetched), mkexpr(t_mask)) );
sewardj9ed16802005-08-24 10:46:19 +00007305 break;
sewardje9d8a262009-07-01 08:06:34 +00007306 case BtOpReset:
7307 assign( t_new,
7308 binop(Iop_And8, mkexpr(t_fetched),
7309 unop(Iop_Not8, mkexpr(t_mask))) );
sewardj9ed16802005-08-24 10:46:19 +00007310 break;
7311 default:
7312 vpanic("dis_bt_G_E(amd64)");
7313 }
sewardje9d8a262009-07-01 08:06:34 +00007314 if ((pfx & PFX_LOCK) && !epartIsReg(modrm)) {
7315 casLE( mkexpr(t_addr1), mkexpr(t_fetched)/*expd*/,
7316 mkexpr(t_new)/*new*/,
7317 guest_RIP_curr_instr );
7318 } else {
7319 storeLE( mkexpr(t_addr1), mkexpr(t_new) );
7320 }
sewardj9ed16802005-08-24 10:46:19 +00007321 }
sewardje9d8a262009-07-01 08:06:34 +00007322
sewardj9ed16802005-08-24 10:46:19 +00007323 /* Side effect done; now get selected bit into Carry flag */
7324 /* Flags: C=selected bit, O,S,Z,A,P undefined, so are set to zero. */
7325 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(AMD64G_CC_OP_COPY) ));
7326 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
7327 stmt( IRStmt_Put(
7328 OFFB_CC_DEP1,
7329 binop(Iop_And64,
7330 binop(Iop_Shr64,
7331 unop(Iop_8Uto64, mkexpr(t_fetched)),
7332 mkexpr(t_bitno2)),
7333 mkU64(1)))
7334 );
7335 /* Set NDEP even though it isn't used. This makes redundant-PUT
7336 elimination of previous stores to this field work better. */
7337 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU64(0) ));
7338
7339 /* Move reg operand from stack back to reg */
7340 if (epartIsReg(modrm)) {
sewardje9d8a262009-07-01 08:06:34 +00007341 /* t_rsp still points at it. */
sewardj25d23862006-05-12 17:47:21 +00007342 /* only write the reg if actually modifying it; doing otherwise
7343 zeroes the top half erroneously when doing btl due to
7344 standard zero-extend rule */
sewardje9d8a262009-07-01 08:06:34 +00007345 if (op != BtOpNone)
sewardj25d23862006-05-12 17:47:21 +00007346 putIRegE(sz, pfx, modrm, loadLE(szToITy(sz), mkexpr(t_rsp)) );
sewardj9ed16802005-08-24 10:46:19 +00007347 putIReg64(R_RSP, binop(Iop_Add64, mkexpr(t_rsp), mkU64(sz)) );
7348 }
7349
7350 DIP("bt%s%c %s, %s\n",
7351 nameBtOp(op), nameISize(sz), nameIRegG(sz, pfx, modrm),
7352 ( epartIsReg(modrm) ? nameIRegE(sz, pfx, modrm) : dis_buf ) );
7353
7354 return delta;
7355}
sewardjf53b7352005-04-06 20:01:56 +00007356
7357
7358
7359/* Handle BSF/BSR. Only v-size seems necessary. */
7360static
sewardj2e28ac42008-12-04 00:05:12 +00007361ULong dis_bs_E_G ( VexAbiInfo* vbi,
7362 Prefix pfx, Int sz, Long delta, Bool fwds )
sewardjf53b7352005-04-06 20:01:56 +00007363{
7364 Bool isReg;
7365 UChar modrm;
7366 HChar dis_buf[50];
7367
7368 IRType ty = szToITy(sz);
7369 IRTemp src = newTemp(ty);
7370 IRTemp dst = newTemp(ty);
7371 IRTemp src64 = newTemp(Ity_I64);
7372 IRTemp dst64 = newTemp(Ity_I64);
7373 IRTemp src8 = newTemp(Ity_I8);
7374
7375 vassert(sz == 8 || sz == 4 || sz == 2);
7376
7377 modrm = getUChar(delta);
7378 isReg = epartIsReg(modrm);
7379 if (isReg) {
7380 delta++;
7381 assign( src, getIRegE(sz, pfx, modrm) );
7382 } else {
7383 Int len;
sewardj2e28ac42008-12-04 00:05:12 +00007384 IRTemp addr = disAMode( &len, vbi, pfx, delta, dis_buf, 0 );
sewardjf53b7352005-04-06 20:01:56 +00007385 delta += len;
7386 assign( src, loadLE(ty, mkexpr(addr)) );
7387 }
7388
7389 DIP("bs%c%c %s, %s\n",
7390 fwds ? 'f' : 'r', nameISize(sz),
7391 ( isReg ? nameIRegE(sz, pfx, modrm) : dis_buf ),
7392 nameIRegG(sz, pfx, modrm));
7393
7394 /* First, widen src to 64 bits if it is not already. */
7395 assign( src64, widenUto64(mkexpr(src)) );
7396
7397 /* Generate an 8-bit expression which is zero iff the
7398 original is zero, and nonzero otherwise */
7399 assign( src8,
7400 unop(Iop_1Uto8,
7401 binop(Iop_CmpNE64,
7402 mkexpr(src64), mkU64(0))) );
7403
7404 /* Flags: Z is 1 iff source value is zero. All others
7405 are undefined -- we force them to zero. */
7406 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(AMD64G_CC_OP_COPY) ));
7407 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
7408 stmt( IRStmt_Put(
7409 OFFB_CC_DEP1,
7410 IRExpr_Mux0X( mkexpr(src8),
7411 /* src==0 */
7412 mkU64(AMD64G_CC_MASK_Z),
7413 /* src!=0 */
7414 mkU64(0)
7415 )
7416 ));
7417 /* Set NDEP even though it isn't used. This makes redundant-PUT
7418 elimination of previous stores to this field work better. */
7419 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU64(0) ));
7420
7421 /* Result: iff source value is zero, we can't use
7422 Iop_Clz64/Iop_Ctz64 as they have no defined result in that case.
7423 But anyway, amd64 semantics say the result is undefined in
7424 such situations. Hence handle the zero case specially. */
7425
7426 /* Bleh. What we compute:
7427
7428 bsf64: if src == 0 then {dst is unchanged}
7429 else Ctz64(src)
7430
7431 bsr64: if src == 0 then {dst is unchanged}
7432 else 63 - Clz64(src)
7433
7434 bsf32: if src == 0 then {dst is unchanged}
7435 else Ctz64(32Uto64(src))
7436
7437 bsr32: if src == 0 then {dst is unchanged}
7438 else 63 - Clz64(32Uto64(src))
7439
7440 bsf16: if src == 0 then {dst is unchanged}
7441 else Ctz64(32Uto64(16Uto32(src)))
7442
7443 bsr16: if src == 0 then {dst is unchanged}
7444 else 63 - Clz64(32Uto64(16Uto32(src)))
7445 */
7446
7447 /* The main computation, guarding against zero. */
7448 assign( dst64,
7449 IRExpr_Mux0X(
7450 mkexpr(src8),
7451 /* src == 0 -- leave dst unchanged */
7452 widenUto64( getIRegG( sz, pfx, modrm ) ),
7453 /* src != 0 */
7454 fwds ? unop(Iop_Ctz64, mkexpr(src64))
7455 : binop(Iop_Sub64,
7456 mkU64(63),
7457 unop(Iop_Clz64, mkexpr(src64)))
7458 )
7459 );
7460
7461 if (sz == 2)
sewardje58967e2005-04-27 11:50:56 +00007462 assign( dst, unop(Iop_64to16, mkexpr(dst64)) );
sewardjf53b7352005-04-06 20:01:56 +00007463 else
7464 if (sz == 4)
7465 assign( dst, unop(Iop_64to32, mkexpr(dst64)) );
7466 else
7467 assign( dst, mkexpr(dst64) );
7468
7469 /* dump result back */
7470 putIRegG( sz, pfx, modrm, mkexpr(dst) );
7471
7472 return delta;
7473}
sewardja6b93d12005-02-17 09:28:28 +00007474
7475
7476/* swap rAX with the reg specified by reg and REX.B */
7477static
sewardj5b470602005-02-27 13:10:48 +00007478void codegen_xchg_rAX_Reg ( Prefix pfx, Int sz, UInt regLo3 )
sewardja6b93d12005-02-17 09:28:28 +00007479{
7480 IRType ty = szToITy(sz);
7481 IRTemp t1 = newTemp(ty);
7482 IRTemp t2 = newTemp(ty);
sewardj2d4fcd52005-05-18 11:47:47 +00007483 vassert(sz == 4 || sz == 8);
sewardj5b470602005-02-27 13:10:48 +00007484 vassert(regLo3 < 8);
sewardj2d4fcd52005-05-18 11:47:47 +00007485 if (sz == 8) {
7486 assign( t1, getIReg64(R_RAX) );
7487 assign( t2, getIRegRexB(8, pfx, regLo3) );
7488 putIReg64( R_RAX, mkexpr(t2) );
7489 putIRegRexB(8, pfx, regLo3, mkexpr(t1) );
7490 } else {
7491 assign( t1, getIReg32(R_RAX) );
7492 assign( t2, getIRegRexB(4, pfx, regLo3) );
7493 putIReg32( R_RAX, mkexpr(t2) );
7494 putIRegRexB(4, pfx, regLo3, mkexpr(t1) );
7495 }
sewardja6b93d12005-02-17 09:28:28 +00007496 DIP("xchg%c %s, %s\n",
sewardj5b470602005-02-27 13:10:48 +00007497 nameISize(sz), nameIRegRAX(sz),
sewardj2d4fcd52005-05-18 11:47:47 +00007498 nameIRegRexB(sz,pfx, regLo3));
sewardja6b93d12005-02-17 09:28:28 +00007499}
7500
7501
sewardj905edbd2007-04-07 12:25:37 +00007502static
7503void codegen_SAHF ( void )
7504{
7505 /* Set the flags to:
7506 (amd64g_calculate_flags_all() & AMD64G_CC_MASK_O)
7507 -- retain the old O flag
7508 | (%AH & (AMD64G_CC_MASK_S|AMD64G_CC_MASK_Z|AMD64G_CC_MASK_A
7509 |AMD64G_CC_MASK_P|AMD64G_CC_MASK_C)
7510 */
7511 ULong mask_SZACP = AMD64G_CC_MASK_S|AMD64G_CC_MASK_Z|AMD64G_CC_MASK_A
7512 |AMD64G_CC_MASK_C|AMD64G_CC_MASK_P;
7513 IRTemp oldflags = newTemp(Ity_I64);
7514 assign( oldflags, mk_amd64g_calculate_rflags_all() );
7515 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(AMD64G_CC_OP_COPY) ));
7516 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU64(0) ));
7517 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
7518 stmt( IRStmt_Put( OFFB_CC_DEP1,
7519 binop(Iop_Or64,
7520 binop(Iop_And64, mkexpr(oldflags), mkU64(AMD64G_CC_MASK_O)),
7521 binop(Iop_And64,
7522 binop(Iop_Shr64, getIReg64(R_RAX), mkU8(8)),
7523 mkU64(mask_SZACP))
7524 )
7525 ));
7526}
7527
7528
7529static
7530void codegen_LAHF ( void )
7531{
7532 /* AH <- EFLAGS(SF:ZF:0:AF:0:PF:1:CF) */
7533 IRExpr* rax_with_hole;
7534 IRExpr* new_byte;
7535 IRExpr* new_rax;
7536 ULong mask_SZACP = AMD64G_CC_MASK_S|AMD64G_CC_MASK_Z|AMD64G_CC_MASK_A
7537 |AMD64G_CC_MASK_C|AMD64G_CC_MASK_P;
7538
7539 IRTemp flags = newTemp(Ity_I64);
7540 assign( flags, mk_amd64g_calculate_rflags_all() );
7541
7542 rax_with_hole
7543 = binop(Iop_And64, getIReg64(R_RAX), mkU64(~0xFF00ULL));
7544 new_byte
7545 = binop(Iop_Or64, binop(Iop_And64, mkexpr(flags), mkU64(mask_SZACP)),
7546 mkU64(1<<1));
7547 new_rax
7548 = binop(Iop_Or64, rax_with_hole,
7549 binop(Iop_Shl64, new_byte, mkU8(8)));
7550 putIReg64(R_RAX, new_rax);
7551}
7552
sewardja6b93d12005-02-17 09:28:28 +00007553
7554static
sewardjd0aa0a52006-08-17 01:20:01 +00007555ULong dis_cmpxchg_G_E ( /*OUT*/Bool* ok,
sewardj2e28ac42008-12-04 00:05:12 +00007556 VexAbiInfo* vbi,
sewardjd0aa0a52006-08-17 01:20:01 +00007557 Prefix pfx,
7558 Int size,
7559 Long delta0 )
sewardja6b93d12005-02-17 09:28:28 +00007560{
7561 HChar dis_buf[50];
7562 Int len;
7563
7564 IRType ty = szToITy(size);
7565 IRTemp acc = newTemp(ty);
7566 IRTemp src = newTemp(ty);
7567 IRTemp dest = newTemp(ty);
7568 IRTemp dest2 = newTemp(ty);
7569 IRTemp acc2 = newTemp(ty);
7570 IRTemp cond8 = newTemp(Ity_I8);
7571 IRTemp addr = IRTemp_INVALID;
7572 UChar rm = getUChar(delta0);
7573
sewardje9d8a262009-07-01 08:06:34 +00007574 /* There are 3 cases to consider:
7575
7576 reg-reg: ignore any lock prefix, generate sequence based
7577 on Mux0X
7578
7579 reg-mem, not locked: ignore any lock prefix, generate sequence
7580 based on Mux0X
7581
7582 reg-mem, locked: use IRCAS
7583 */
7584
sewardja6b93d12005-02-17 09:28:28 +00007585 if (epartIsReg(rm)) {
sewardje9d8a262009-07-01 08:06:34 +00007586 /* case 1 */
sewardjd0aa0a52006-08-17 01:20:01 +00007587 *ok = False;
7588 return delta0;
7589 /* awaiting test case */
sewardj5b470602005-02-27 13:10:48 +00007590 assign( dest, getIRegE(size, pfx, rm) );
sewardja6b93d12005-02-17 09:28:28 +00007591 delta0++;
sewardje9d8a262009-07-01 08:06:34 +00007592 assign( src, getIRegG(size, pfx, rm) );
7593 assign( acc, getIRegRAX(size) );
7594 setFlags_DEP1_DEP2(Iop_Sub8, acc, dest, ty);
7595 assign( cond8, unop(Iop_1Uto8, mk_amd64g_calculate_condition(AMD64CondZ)) );
7596 assign( dest2, IRExpr_Mux0X(mkexpr(cond8), mkexpr(dest), mkexpr(src)) );
7597 assign( acc2, IRExpr_Mux0X(mkexpr(cond8), mkexpr(dest), mkexpr(acc)) );
7598 putIRegRAX(size, mkexpr(acc2));
7599 putIRegE(size, pfx, rm, mkexpr(dest2));
sewardja6b93d12005-02-17 09:28:28 +00007600 DIP("cmpxchg%c %s,%s\n", nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00007601 nameIRegG(size,pfx,rm),
7602 nameIRegE(size,pfx,rm) );
sewardje9d8a262009-07-01 08:06:34 +00007603 }
7604 else if (!epartIsReg(rm) && !(pfx & PFX_LOCK)) {
7605 /* case 2 */
sewardj2e28ac42008-12-04 00:05:12 +00007606 addr = disAMode ( &len, vbi, pfx, delta0, dis_buf, 0 );
sewardja6b93d12005-02-17 09:28:28 +00007607 assign( dest, loadLE(ty, mkexpr(addr)) );
7608 delta0 += len;
sewardje9d8a262009-07-01 08:06:34 +00007609 assign( src, getIRegG(size, pfx, rm) );
7610 assign( acc, getIRegRAX(size) );
7611 setFlags_DEP1_DEP2(Iop_Sub8, acc, dest, ty);
7612 assign( cond8, unop(Iop_1Uto8, mk_amd64g_calculate_condition(AMD64CondZ)) );
7613 assign( dest2, IRExpr_Mux0X(mkexpr(cond8), mkexpr(dest), mkexpr(src)) );
7614 assign( acc2, IRExpr_Mux0X(mkexpr(cond8), mkexpr(dest), mkexpr(acc)) );
7615 putIRegRAX(size, mkexpr(acc2));
7616 storeLE( mkexpr(addr), mkexpr(dest2) );
sewardja6b93d12005-02-17 09:28:28 +00007617 DIP("cmpxchg%c %s,%s\n", nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00007618 nameIRegG(size,pfx,rm), dis_buf);
sewardja6b93d12005-02-17 09:28:28 +00007619 }
sewardje9d8a262009-07-01 08:06:34 +00007620 else if (!epartIsReg(rm) && (pfx & PFX_LOCK)) {
7621 /* case 3 */
7622 /* src is new value. acc is expected value. dest is old value.
7623 Compute success from the output of the IRCAS, and steer the
7624 new value for RAX accordingly: in case of success, RAX is
7625 unchanged. */
7626 addr = disAMode ( &len, vbi, pfx, delta0, dis_buf, 0 );
7627 delta0 += len;
7628 assign( src, getIRegG(size, pfx, rm) );
7629 assign( acc, getIRegRAX(size) );
7630 stmt( IRStmt_CAS(
7631 mkIRCAS( IRTemp_INVALID, dest, Iend_LE, mkexpr(addr),
7632 NULL, mkexpr(acc), NULL, mkexpr(src) )
7633 ));
7634 setFlags_DEP1_DEP2(Iop_Sub8, acc, dest, ty);
7635 assign( cond8, unop(Iop_1Uto8, mk_amd64g_calculate_condition(AMD64CondZ)) );
7636 assign( acc2, IRExpr_Mux0X(mkexpr(cond8), mkexpr(dest), mkexpr(acc)) );
7637 putIRegRAX(size, mkexpr(acc2));
sewardj40d1d212009-07-12 13:01:17 +00007638 DIP("cmpxchg%c %s,%s\n", nameISize(size),
7639 nameIRegG(size,pfx,rm), dis_buf);
sewardja6b93d12005-02-17 09:28:28 +00007640 }
sewardje9d8a262009-07-01 08:06:34 +00007641 else vassert(0);
sewardja6b93d12005-02-17 09:28:28 +00007642
sewardjd0aa0a52006-08-17 01:20:01 +00007643 *ok = True;
sewardja6b93d12005-02-17 09:28:28 +00007644 return delta0;
7645}
7646
sewardj3ca55a12005-01-27 16:06:23 +00007647
7648/* Handle conditional move instructions of the form
7649 cmovcc E(reg-or-mem), G(reg)
7650
7651 E(src) is reg-or-mem
7652 G(dst) is reg.
7653
7654 If E is reg, --> GET %E, tmps
7655 GET %G, tmpd
7656 CMOVcc tmps, tmpd
7657 PUT tmpd, %G
7658
7659 If E is mem --> (getAddr E) -> tmpa
7660 LD (tmpa), tmps
7661 GET %G, tmpd
7662 CMOVcc tmps, tmpd
7663 PUT tmpd, %G
7664*/
7665static
sewardj2e28ac42008-12-04 00:05:12 +00007666ULong dis_cmov_E_G ( VexAbiInfo* vbi,
7667 Prefix pfx,
sewardj3ca55a12005-01-27 16:06:23 +00007668 Int sz,
7669 AMD64Condcode cond,
sewardj270def42005-07-03 01:03:01 +00007670 Long delta0 )
sewardj3ca55a12005-01-27 16:06:23 +00007671{
sewardj8c332e22005-01-28 01:36:56 +00007672 UChar rm = getUChar(delta0);
sewardj3ca55a12005-01-27 16:06:23 +00007673 HChar dis_buf[50];
7674 Int len;
7675
7676 IRType ty = szToITy(sz);
7677 IRTemp tmps = newTemp(ty);
7678 IRTemp tmpd = newTemp(ty);
7679
7680 if (epartIsReg(rm)) {
sewardj5b470602005-02-27 13:10:48 +00007681 assign( tmps, getIRegE(sz, pfx, rm) );
7682 assign( tmpd, getIRegG(sz, pfx, rm) );
sewardj3ca55a12005-01-27 16:06:23 +00007683
sewardj5b470602005-02-27 13:10:48 +00007684 putIRegG( sz, pfx, rm,
sewardj3ca55a12005-01-27 16:06:23 +00007685 IRExpr_Mux0X( unop(Iop_1Uto8,
7686 mk_amd64g_calculate_condition(cond)),
7687 mkexpr(tmpd),
7688 mkexpr(tmps) )
7689 );
sewardje941eea2005-01-30 19:52:28 +00007690 DIP("cmov%s %s,%s\n", name_AMD64Condcode(cond),
sewardj5b470602005-02-27 13:10:48 +00007691 nameIRegE(sz,pfx,rm),
7692 nameIRegG(sz,pfx,rm));
sewardj3ca55a12005-01-27 16:06:23 +00007693 return 1+delta0;
7694 }
7695
7696 /* E refers to memory */
7697 {
sewardj2e28ac42008-12-04 00:05:12 +00007698 IRTemp addr = disAMode ( &len, vbi, pfx, delta0, dis_buf, 0 );
sewardj3ca55a12005-01-27 16:06:23 +00007699 assign( tmps, loadLE(ty, mkexpr(addr)) );
sewardj5b470602005-02-27 13:10:48 +00007700 assign( tmpd, getIRegG(sz, pfx, rm) );
sewardj3ca55a12005-01-27 16:06:23 +00007701
sewardj5b470602005-02-27 13:10:48 +00007702 putIRegG( sz, pfx, rm,
sewardj3ca55a12005-01-27 16:06:23 +00007703 IRExpr_Mux0X( unop(Iop_1Uto8,
7704 mk_amd64g_calculate_condition(cond)),
7705 mkexpr(tmpd),
7706 mkexpr(tmps) )
7707 );
7708
sewardj7eaa7cf2005-01-31 18:55:22 +00007709 DIP("cmov%s %s,%s\n", name_AMD64Condcode(cond),
7710 dis_buf,
sewardj5b470602005-02-27 13:10:48 +00007711 nameIRegG(sz,pfx,rm));
sewardj3ca55a12005-01-27 16:06:23 +00007712 return len+delta0;
7713 }
7714}
7715
7716
sewardjb4fd2e72005-03-23 13:34:11 +00007717static
7718ULong dis_xadd_G_E ( /*OUT*/Bool* decode_ok,
sewardj2e28ac42008-12-04 00:05:12 +00007719 VexAbiInfo* vbi,
sewardj270def42005-07-03 01:03:01 +00007720 Prefix pfx, Int sz, Long delta0 )
sewardjb4fd2e72005-03-23 13:34:11 +00007721{
7722 Int len;
7723 UChar rm = getUChar(delta0);
7724 HChar dis_buf[50];
7725
7726 IRType ty = szToITy(sz);
7727 IRTemp tmpd = newTemp(ty);
7728 IRTemp tmpt0 = newTemp(ty);
7729 IRTemp tmpt1 = newTemp(ty);
sewardje9d8a262009-07-01 08:06:34 +00007730
7731 /* There are 3 cases to consider:
7732
7733 reg-reg: currently unhandled
7734
7735 reg-mem, not locked: ignore any lock prefix, generate 'naive'
7736 (non-atomic) sequence
7737
7738 reg-mem, locked: use IRCAS
7739 */
sewardjb4fd2e72005-03-23 13:34:11 +00007740
7741 if (epartIsReg(rm)) {
sewardje9d8a262009-07-01 08:06:34 +00007742 /* case 1 */
sewardjb4fd2e72005-03-23 13:34:11 +00007743 *decode_ok = False;
7744 return delta0;
sewardje9d8a262009-07-01 08:06:34 +00007745 /* Currently we don't handle xadd_G_E with register operand. */
7746 }
7747 else if (!epartIsReg(rm) && !(pfx & PFX_LOCK)) {
7748 /* case 2 */
sewardj2e28ac42008-12-04 00:05:12 +00007749 IRTemp addr = disAMode ( &len, vbi, pfx, delta0, dis_buf, 0 );
sewardjb4fd2e72005-03-23 13:34:11 +00007750 assign( tmpd, loadLE(ty, mkexpr(addr)) );
7751 assign( tmpt0, getIRegG(sz, pfx, rm) );
sewardje9d8a262009-07-01 08:06:34 +00007752 assign( tmpt1, binop(mkSizedOp(ty,Iop_Add8),
7753 mkexpr(tmpd), mkexpr(tmpt0)) );
sewardjb4fd2e72005-03-23 13:34:11 +00007754 setFlags_DEP1_DEP2( Iop_Add8, tmpd, tmpt0, ty );
7755 storeLE( mkexpr(addr), mkexpr(tmpt1) );
7756 putIRegG(sz, pfx, rm, mkexpr(tmpd));
7757 DIP("xadd%c %s, %s\n",
7758 nameISize(sz), nameIRegG(sz,pfx,rm), dis_buf);
sewardje9d8a262009-07-01 08:06:34 +00007759 *decode_ok = True;
sewardjb4fd2e72005-03-23 13:34:11 +00007760 return len+delta0;
7761 }
sewardje9d8a262009-07-01 08:06:34 +00007762 else if (!epartIsReg(rm) && (pfx & PFX_LOCK)) {
7763 /* case 3 */
7764 IRTemp addr = disAMode ( &len, vbi, pfx, delta0, dis_buf, 0 );
7765 assign( tmpd, loadLE(ty, mkexpr(addr)) );
7766 assign( tmpt0, getIRegG(sz, pfx, rm) );
7767 assign( tmpt1, binop(mkSizedOp(ty,Iop_Add8),
7768 mkexpr(tmpd), mkexpr(tmpt0)) );
7769 casLE( mkexpr(addr), mkexpr(tmpd)/*expVal*/,
7770 mkexpr(tmpt1)/*newVal*/, guest_RIP_curr_instr );
7771 setFlags_DEP1_DEP2( Iop_Add8, tmpd, tmpt0, ty );
7772 putIRegG(sz, pfx, rm, mkexpr(tmpd));
7773 DIP("xadd%c %s, %s\n",
7774 nameISize(sz), nameIRegG(sz,pfx,rm), dis_buf);
7775 *decode_ok = True;
7776 return len+delta0;
7777 }
7778 /*UNREACHED*/
7779 vassert(0);
sewardjb4fd2e72005-03-23 13:34:11 +00007780}
7781
sewardjd20c8852005-01-20 20:04:07 +00007782//.. /* Move 16 bits from Ew (ireg or mem) to G (a segment register). */
7783//..
7784//.. static
sewardj270def42005-07-03 01:03:01 +00007785//.. UInt dis_mov_Ew_Sw ( UChar sorb, Long delta0 )
sewardjd20c8852005-01-20 20:04:07 +00007786//.. {
7787//.. Int len;
7788//.. IRTemp addr;
sewardj8c332e22005-01-28 01:36:56 +00007789//.. UChar rm = getUChar(delta0);
sewardjd20c8852005-01-20 20:04:07 +00007790//.. HChar dis_buf[50];
7791//..
7792//.. if (epartIsReg(rm)) {
7793//.. putSReg( gregOfRM(rm), getIReg(2, eregOfRM(rm)) );
7794//.. DIP("movw %s,%s\n", nameIReg(2,eregOfRM(rm)), nameSReg(gregOfRM(rm)));
7795//.. return 1+delta0;
7796//.. } else {
7797//.. addr = disAMode ( &len, sorb, delta0, dis_buf );
7798//.. putSReg( gregOfRM(rm), loadLE(Ity_I16, mkexpr(addr)) );
7799//.. DIP("movw %s,%s\n", dis_buf, nameSReg(gregOfRM(rm)));
7800//.. return len+delta0;
7801//.. }
7802//.. }
7803//..
7804//.. /* Move 16 bits from G (a segment register) to Ew (ireg or mem). If
7805//.. dst is ireg and sz==4, zero out top half of it. */
7806//..
7807//.. static
7808//.. UInt dis_mov_Sw_Ew ( UChar sorb,
7809//.. Int sz,
7810//.. UInt delta0 )
7811//.. {
7812//.. Int len;
7813//.. IRTemp addr;
sewardj8c332e22005-01-28 01:36:56 +00007814//.. UChar rm = getUChar(delta0);
sewardjd20c8852005-01-20 20:04:07 +00007815//.. HChar dis_buf[50];
7816//..
7817//.. vassert(sz == 2 || sz == 4);
7818//..
7819//.. if (epartIsReg(rm)) {
7820//.. if (sz == 4)
7821//.. putIReg(4, eregOfRM(rm), unop(Iop_16Uto32, getSReg(gregOfRM(rm))));
7822//.. else
7823//.. putIReg(2, eregOfRM(rm), getSReg(gregOfRM(rm)));
7824//..
7825//.. DIP("mov %s,%s\n", nameSReg(gregOfRM(rm)), nameIReg(sz,eregOfRM(rm)));
7826//.. return 1+delta0;
7827//.. } else {
7828//.. addr = disAMode ( &len, sorb, delta0, dis_buf );
7829//.. storeLE( mkexpr(addr), getSReg(gregOfRM(rm)) );
7830//.. DIP("mov %s,%s\n", nameSReg(gregOfRM(rm)), dis_buf);
7831//.. return len+delta0;
7832//.. }
7833//.. }
7834//..
7835//..
7836//.. static
7837//.. void dis_push_segreg ( UInt sreg, Int sz )
7838//.. {
7839//.. IRTemp t1 = newTemp(Ity_I16);
7840//.. IRTemp ta = newTemp(Ity_I32);
7841//.. vassert(sz == 2 || sz == 4);
7842//..
7843//.. assign( t1, getSReg(sreg) );
7844//.. assign( ta, binop(Iop_Sub32, getIReg(4, R_ESP), mkU32(sz)) );
7845//.. putIReg(4, R_ESP, mkexpr(ta));
7846//.. storeLE( mkexpr(ta), mkexpr(t1) );
7847//..
7848//.. DIP("pushw %s\n", nameSReg(sreg));
7849//.. }
7850//..
7851//.. static
7852//.. void dis_pop_segreg ( UInt sreg, Int sz )
7853//.. {
7854//.. IRTemp t1 = newTemp(Ity_I16);
7855//.. IRTemp ta = newTemp(Ity_I32);
7856//.. vassert(sz == 2 || sz == 4);
7857//..
7858//.. assign( ta, getIReg(4, R_ESP) );
7859//.. assign( t1, loadLE(Ity_I16, mkexpr(ta)) );
7860//..
7861//.. putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(ta), mkU32(sz)) );
7862//.. putSReg( sreg, mkexpr(t1) );
7863//.. DIP("pop %s\n", nameSReg(sreg));
7864//.. }
sewardj2f959cc2005-01-26 01:19:35 +00007865
7866static
sewardjdd40fdf2006-12-24 02:20:24 +00007867void dis_ret ( VexAbiInfo* vbi, ULong d64 )
sewardj2f959cc2005-01-26 01:19:35 +00007868{
7869 IRTemp t1 = newTemp(Ity_I64);
7870 IRTemp t2 = newTemp(Ity_I64);
sewardj5a9ffab2005-05-12 17:55:01 +00007871 IRTemp t3 = newTemp(Ity_I64);
sewardj2f959cc2005-01-26 01:19:35 +00007872 assign(t1, getIReg64(R_RSP));
7873 assign(t2, loadLE(Ity_I64,mkexpr(t1)));
sewardj5a9ffab2005-05-12 17:55:01 +00007874 assign(t3, binop(Iop_Add64, mkexpr(t1), mkU64(8+d64)));
7875 putIReg64(R_RSP, mkexpr(t3));
sewardj478646f2008-05-01 20:13:04 +00007876 make_redzone_AbiHint(vbi, t3, t2/*nia*/, "ret");
sewardj2f959cc2005-01-26 01:19:35 +00007877 jmp_treg(Ijk_Ret,t2);
7878}
7879
sewardj5b470602005-02-27 13:10:48 +00007880
sewardj1001dc42005-02-21 08:25:55 +00007881/*------------------------------------------------------------*/
7882/*--- SSE/SSE2/SSE3 helpers ---*/
7883/*------------------------------------------------------------*/
7884
7885/* Worker function; do not call directly.
7886 Handles full width G = G `op` E and G = (not G) `op` E.
7887*/
7888
sewardj8d965312005-02-25 02:48:47 +00007889static ULong dis_SSE_E_to_G_all_wrk (
sewardj2e28ac42008-12-04 00:05:12 +00007890 VexAbiInfo* vbi,
sewardj270def42005-07-03 01:03:01 +00007891 Prefix pfx, Long delta,
sewardj8d965312005-02-25 02:48:47 +00007892 HChar* opname, IROp op,
7893 Bool invertG
7894 )
sewardj9da16972005-02-21 13:58:26 +00007895{
7896 HChar dis_buf[50];
7897 Int alen;
7898 IRTemp addr;
7899 UChar rm = getUChar(delta);
7900 IRExpr* gpart
7901 = invertG ? unop(Iop_NotV128, getXMMReg(gregOfRexRM(pfx,rm)))
7902 : getXMMReg(gregOfRexRM(pfx,rm));
7903 if (epartIsReg(rm)) {
7904 putXMMReg( gregOfRexRM(pfx,rm),
7905 binop(op, gpart,
7906 getXMMReg(eregOfRexRM(pfx,rm))) );
7907 DIP("%s %s,%s\n", opname,
7908 nameXMMReg(eregOfRexRM(pfx,rm)),
7909 nameXMMReg(gregOfRexRM(pfx,rm)) );
7910 return delta+1;
7911 } else {
sewardj2e28ac42008-12-04 00:05:12 +00007912 addr = disAMode ( &alen, vbi, pfx, delta, dis_buf, 0 );
sewardj9da16972005-02-21 13:58:26 +00007913 putXMMReg( gregOfRexRM(pfx,rm),
7914 binop(op, gpart,
7915 loadLE(Ity_V128, mkexpr(addr))) );
7916 DIP("%s %s,%s\n", opname,
7917 dis_buf,
7918 nameXMMReg(gregOfRexRM(pfx,rm)) );
7919 return delta+alen;
7920 }
7921}
7922
7923
7924/* All lanes SSE binary operation, G = G `op` E. */
7925
7926static
sewardj2e28ac42008-12-04 00:05:12 +00007927ULong dis_SSE_E_to_G_all ( VexAbiInfo* vbi,
7928 Prefix pfx, Long delta,
sewardj8d965312005-02-25 02:48:47 +00007929 HChar* opname, IROp op )
sewardj9da16972005-02-21 13:58:26 +00007930{
sewardj2e28ac42008-12-04 00:05:12 +00007931 return dis_SSE_E_to_G_all_wrk( vbi, pfx, delta, opname, op, False );
sewardj9da16972005-02-21 13:58:26 +00007932}
7933
sewardj8d965312005-02-25 02:48:47 +00007934/* All lanes SSE binary operation, G = (not G) `op` E. */
7935
7936static
sewardj2e28ac42008-12-04 00:05:12 +00007937ULong dis_SSE_E_to_G_all_invG ( VexAbiInfo* vbi,
7938 Prefix pfx, Long delta,
sewardj8d965312005-02-25 02:48:47 +00007939 HChar* opname, IROp op )
7940{
sewardj2e28ac42008-12-04 00:05:12 +00007941 return dis_SSE_E_to_G_all_wrk( vbi, pfx, delta, opname, op, True );
sewardj8d965312005-02-25 02:48:47 +00007942}
7943
7944
7945/* Lowest 32-bit lane only SSE binary operation, G = G `op` E. */
7946
sewardj2e28ac42008-12-04 00:05:12 +00007947static ULong dis_SSE_E_to_G_lo32 ( VexAbiInfo* vbi,
7948 Prefix pfx, Long delta,
sewardj8d965312005-02-25 02:48:47 +00007949 HChar* opname, IROp op )
7950{
7951 HChar dis_buf[50];
7952 Int alen;
7953 IRTemp addr;
7954 UChar rm = getUChar(delta);
sewardj9c9ee3d2005-02-26 01:17:42 +00007955 IRExpr* gpart = getXMMReg(gregOfRexRM(pfx,rm));
sewardj8d965312005-02-25 02:48:47 +00007956 if (epartIsReg(rm)) {
sewardj9c9ee3d2005-02-26 01:17:42 +00007957 putXMMReg( gregOfRexRM(pfx,rm),
sewardj8d965312005-02-25 02:48:47 +00007958 binop(op, gpart,
7959 getXMMReg(eregOfRexRM(pfx,rm))) );
7960 DIP("%s %s,%s\n", opname,
7961 nameXMMReg(eregOfRexRM(pfx,rm)),
7962 nameXMMReg(gregOfRexRM(pfx,rm)) );
7963 return delta+1;
7964 } else {
7965 /* We can only do a 32-bit memory read, so the upper 3/4 of the
7966 E operand needs to be made simply of zeroes. */
7967 IRTemp epart = newTemp(Ity_V128);
sewardj2e28ac42008-12-04 00:05:12 +00007968 addr = disAMode ( &alen, vbi, pfx, delta, dis_buf, 0 );
sewardj8d965312005-02-25 02:48:47 +00007969 assign( epart, unop( Iop_32UtoV128,
7970 loadLE(Ity_I32, mkexpr(addr))) );
7971 putXMMReg( gregOfRexRM(pfx,rm),
7972 binop(op, gpart, mkexpr(epart)) );
7973 DIP("%s %s,%s\n", opname,
7974 dis_buf,
7975 nameXMMReg(gregOfRexRM(pfx,rm)) );
7976 return delta+alen;
7977 }
7978}
sewardj1001dc42005-02-21 08:25:55 +00007979
7980
7981/* Lower 64-bit lane only SSE binary operation, G = G `op` E. */
7982
sewardj2e28ac42008-12-04 00:05:12 +00007983static ULong dis_SSE_E_to_G_lo64 ( VexAbiInfo* vbi,
7984 Prefix pfx, Long delta,
sewardj8d965312005-02-25 02:48:47 +00007985 HChar* opname, IROp op )
sewardj1001dc42005-02-21 08:25:55 +00007986{
7987 HChar dis_buf[50];
7988 Int alen;
7989 IRTemp addr;
7990 UChar rm = getUChar(delta);
7991 IRExpr* gpart = getXMMReg(gregOfRexRM(pfx,rm));
7992 if (epartIsReg(rm)) {
7993 putXMMReg( gregOfRexRM(pfx,rm),
7994 binop(op, gpart,
7995 getXMMReg(eregOfRexRM(pfx,rm))) );
7996 DIP("%s %s,%s\n", opname,
7997 nameXMMReg(eregOfRexRM(pfx,rm)),
7998 nameXMMReg(gregOfRexRM(pfx,rm)) );
7999 return delta+1;
8000 } else {
8001 /* We can only do a 64-bit memory read, so the upper half of the
8002 E operand needs to be made simply of zeroes. */
8003 IRTemp epart = newTemp(Ity_V128);
sewardj2e28ac42008-12-04 00:05:12 +00008004 addr = disAMode ( &alen, vbi, pfx, delta, dis_buf, 0 );
sewardj1001dc42005-02-21 08:25:55 +00008005 assign( epart, unop( Iop_64UtoV128,
8006 loadLE(Ity_I64, mkexpr(addr))) );
8007 putXMMReg( gregOfRexRM(pfx,rm),
8008 binop(op, gpart, mkexpr(epart)) );
8009 DIP("%s %s,%s\n", opname,
8010 dis_buf,
8011 nameXMMReg(gregOfRexRM(pfx,rm)) );
8012 return delta+alen;
8013 }
8014}
8015
8016
sewardja7ba8c42005-05-10 20:08:34 +00008017/* All lanes unary SSE operation, G = op(E). */
8018
8019static ULong dis_SSE_E_to_G_unary_all (
sewardj2e28ac42008-12-04 00:05:12 +00008020 VexAbiInfo* vbi,
sewardj270def42005-07-03 01:03:01 +00008021 Prefix pfx, Long delta,
sewardja7ba8c42005-05-10 20:08:34 +00008022 HChar* opname, IROp op
8023 )
8024{
8025 HChar dis_buf[50];
8026 Int alen;
8027 IRTemp addr;
8028 UChar rm = getUChar(delta);
8029 if (epartIsReg(rm)) {
8030 putXMMReg( gregOfRexRM(pfx,rm),
8031 unop(op, getXMMReg(eregOfRexRM(pfx,rm))) );
8032 DIP("%s %s,%s\n", opname,
8033 nameXMMReg(eregOfRexRM(pfx,rm)),
8034 nameXMMReg(gregOfRexRM(pfx,rm)) );
8035 return delta+1;
8036 } else {
sewardj2e28ac42008-12-04 00:05:12 +00008037 addr = disAMode ( &alen, vbi, pfx, delta, dis_buf, 0 );
sewardja7ba8c42005-05-10 20:08:34 +00008038 putXMMReg( gregOfRexRM(pfx,rm),
8039 unop(op, loadLE(Ity_V128, mkexpr(addr))) );
8040 DIP("%s %s,%s\n", opname,
8041 dis_buf,
8042 nameXMMReg(gregOfRexRM(pfx,rm)) );
8043 return delta+alen;
8044 }
8045}
8046
8047
8048/* Lowest 32-bit lane only unary SSE operation, G = op(E). */
8049
8050static ULong dis_SSE_E_to_G_unary_lo32 (
sewardj2e28ac42008-12-04 00:05:12 +00008051 VexAbiInfo* vbi,
sewardj270def42005-07-03 01:03:01 +00008052 Prefix pfx, Long delta,
sewardja7ba8c42005-05-10 20:08:34 +00008053 HChar* opname, IROp op
8054 )
8055{
8056 /* First we need to get the old G value and patch the low 32 bits
8057 of the E operand into it. Then apply op and write back to G. */
8058 HChar dis_buf[50];
8059 Int alen;
8060 IRTemp addr;
8061 UChar rm = getUChar(delta);
8062 IRTemp oldG0 = newTemp(Ity_V128);
8063 IRTemp oldG1 = newTemp(Ity_V128);
8064
8065 assign( oldG0, getXMMReg(gregOfRexRM(pfx,rm)) );
8066
8067 if (epartIsReg(rm)) {
8068 assign( oldG1,
8069 binop( Iop_SetV128lo32,
8070 mkexpr(oldG0),
8071 getXMMRegLane32(eregOfRexRM(pfx,rm), 0)) );
8072 putXMMReg( gregOfRexRM(pfx,rm), unop(op, mkexpr(oldG1)) );
8073 DIP("%s %s,%s\n", opname,
8074 nameXMMReg(eregOfRexRM(pfx,rm)),
8075 nameXMMReg(gregOfRexRM(pfx,rm)) );
8076 return delta+1;
8077 } else {
sewardj2e28ac42008-12-04 00:05:12 +00008078 addr = disAMode ( &alen, vbi, pfx, delta, dis_buf, 0 );
sewardja7ba8c42005-05-10 20:08:34 +00008079 assign( oldG1,
8080 binop( Iop_SetV128lo32,
8081 mkexpr(oldG0),
8082 loadLE(Ity_I32, mkexpr(addr)) ));
8083 putXMMReg( gregOfRexRM(pfx,rm), unop(op, mkexpr(oldG1)) );
8084 DIP("%s %s,%s\n", opname,
8085 dis_buf,
8086 nameXMMReg(gregOfRexRM(pfx,rm)) );
8087 return delta+alen;
8088 }
8089}
sewardj1001dc42005-02-21 08:25:55 +00008090
8091
8092/* Lowest 64-bit lane only unary SSE operation, G = op(E). */
8093
sewardj8d965312005-02-25 02:48:47 +00008094static ULong dis_SSE_E_to_G_unary_lo64 (
sewardj2e28ac42008-12-04 00:05:12 +00008095 VexAbiInfo* vbi,
sewardj270def42005-07-03 01:03:01 +00008096 Prefix pfx, Long delta,
sewardj8d965312005-02-25 02:48:47 +00008097 HChar* opname, IROp op
8098 )
sewardj1001dc42005-02-21 08:25:55 +00008099{
8100 /* First we need to get the old G value and patch the low 64 bits
8101 of the E operand into it. Then apply op and write back to G. */
8102 HChar dis_buf[50];
8103 Int alen;
8104 IRTemp addr;
8105 UChar rm = getUChar(delta);
8106 IRTemp oldG0 = newTemp(Ity_V128);
8107 IRTemp oldG1 = newTemp(Ity_V128);
8108
8109 assign( oldG0, getXMMReg(gregOfRexRM(pfx,rm)) );
8110
8111 if (epartIsReg(rm)) {
8112 assign( oldG1,
8113 binop( Iop_SetV128lo64,
8114 mkexpr(oldG0),
8115 getXMMRegLane64(eregOfRexRM(pfx,rm), 0)) );
8116 putXMMReg( gregOfRexRM(pfx,rm), unop(op, mkexpr(oldG1)) );
8117 DIP("%s %s,%s\n", opname,
8118 nameXMMReg(eregOfRexRM(pfx,rm)),
8119 nameXMMReg(gregOfRexRM(pfx,rm)) );
8120 return delta+1;
8121 } else {
sewardj2e28ac42008-12-04 00:05:12 +00008122 addr = disAMode ( &alen, vbi, pfx, delta, dis_buf, 0 );
sewardj1001dc42005-02-21 08:25:55 +00008123 assign( oldG1,
8124 binop( Iop_SetV128lo64,
8125 mkexpr(oldG0),
8126 loadLE(Ity_I64, mkexpr(addr)) ));
8127 putXMMReg( gregOfRexRM(pfx,rm), unop(op, mkexpr(oldG1)) );
8128 DIP("%s %s,%s\n", opname,
8129 dis_buf,
8130 nameXMMReg(gregOfRexRM(pfx,rm)) );
8131 return delta+alen;
8132 }
8133}
8134
8135
sewardj09717342005-05-05 21:34:02 +00008136/* SSE integer binary operation:
8137 G = G `op` E (eLeft == False)
8138 G = E `op` G (eLeft == True)
8139*/
8140static ULong dis_SSEint_E_to_G(
sewardj2e28ac42008-12-04 00:05:12 +00008141 VexAbiInfo* vbi,
sewardj270def42005-07-03 01:03:01 +00008142 Prefix pfx, Long delta,
sewardj09717342005-05-05 21:34:02 +00008143 HChar* opname, IROp op,
8144 Bool eLeft
8145 )
8146{
8147 HChar dis_buf[50];
8148 Int alen;
8149 IRTemp addr;
8150 UChar rm = getUChar(delta);
8151 IRExpr* gpart = getXMMReg(gregOfRexRM(pfx,rm));
8152 IRExpr* epart = NULL;
8153 if (epartIsReg(rm)) {
8154 epart = getXMMReg(eregOfRexRM(pfx,rm));
8155 DIP("%s %s,%s\n", opname,
8156 nameXMMReg(eregOfRexRM(pfx,rm)),
8157 nameXMMReg(gregOfRexRM(pfx,rm)) );
8158 delta += 1;
8159 } else {
sewardj2e28ac42008-12-04 00:05:12 +00008160 addr = disAMode ( &alen, vbi, pfx, delta, dis_buf, 0 );
sewardj09717342005-05-05 21:34:02 +00008161 epart = loadLE(Ity_V128, mkexpr(addr));
8162 DIP("%s %s,%s\n", opname,
8163 dis_buf,
8164 nameXMMReg(gregOfRexRM(pfx,rm)) );
8165 delta += alen;
8166 }
8167 putXMMReg( gregOfRexRM(pfx,rm),
8168 eLeft ? binop(op, epart, gpart)
8169 : binop(op, gpart, epart) );
8170 return delta;
8171}
sewardj8d965312005-02-25 02:48:47 +00008172
8173
8174/* Helper for doing SSE FP comparisons. */
8175
8176static void findSSECmpOp ( Bool* needNot, IROp* op,
8177 Int imm8, Bool all_lanes, Int sz )
8178{
8179 imm8 &= 7;
8180 *needNot = False;
8181 *op = Iop_INVALID;
8182 if (imm8 >= 4) {
8183 *needNot = True;
8184 imm8 -= 4;
8185 }
8186
8187 if (sz == 4 && all_lanes) {
8188 switch (imm8) {
8189 case 0: *op = Iop_CmpEQ32Fx4; return;
8190 case 1: *op = Iop_CmpLT32Fx4; return;
8191 case 2: *op = Iop_CmpLE32Fx4; return;
8192 case 3: *op = Iop_CmpUN32Fx4; return;
8193 default: break;
8194 }
8195 }
8196 if (sz == 4 && !all_lanes) {
8197 switch (imm8) {
8198 case 0: *op = Iop_CmpEQ32F0x4; return;
8199 case 1: *op = Iop_CmpLT32F0x4; return;
8200 case 2: *op = Iop_CmpLE32F0x4; return;
8201 case 3: *op = Iop_CmpUN32F0x4; return;
8202 default: break;
8203 }
8204 }
8205 if (sz == 8 && all_lanes) {
8206 switch (imm8) {
8207 case 0: *op = Iop_CmpEQ64Fx2; return;
8208 case 1: *op = Iop_CmpLT64Fx2; return;
8209 case 2: *op = Iop_CmpLE64Fx2; return;
8210 case 3: *op = Iop_CmpUN64Fx2; return;
8211 default: break;
8212 }
8213 }
8214 if (sz == 8 && !all_lanes) {
8215 switch (imm8) {
8216 case 0: *op = Iop_CmpEQ64F0x2; return;
8217 case 1: *op = Iop_CmpLT64F0x2; return;
8218 case 2: *op = Iop_CmpLE64F0x2; return;
8219 case 3: *op = Iop_CmpUN64F0x2; return;
8220 default: break;
8221 }
8222 }
8223 vpanic("findSSECmpOp(amd64,guest)");
8224}
8225
sewardjab9055b2006-01-01 13:17:38 +00008226/* Handles SSE 32F/64F comparisons. */
sewardj8d965312005-02-25 02:48:47 +00008227
sewardj2e28ac42008-12-04 00:05:12 +00008228static ULong dis_SSEcmp_E_to_G ( VexAbiInfo* vbi,
8229 Prefix pfx, Long delta,
sewardj8d965312005-02-25 02:48:47 +00008230 HChar* opname, Bool all_lanes, Int sz )
8231{
8232 HChar dis_buf[50];
8233 Int alen, imm8;
8234 IRTemp addr;
8235 Bool needNot = False;
8236 IROp op = Iop_INVALID;
8237 IRTemp plain = newTemp(Ity_V128);
8238 UChar rm = getUChar(delta);
8239 UShort mask = 0;
8240 vassert(sz == 4 || sz == 8);
8241 if (epartIsReg(rm)) {
8242 imm8 = getUChar(delta+1);
8243 findSSECmpOp(&needNot, &op, imm8, all_lanes, sz);
8244 assign( plain, binop(op, getXMMReg(gregOfRexRM(pfx,rm)),
8245 getXMMReg(eregOfRexRM(pfx,rm))) );
8246 delta += 2;
8247 DIP("%s $%d,%s,%s\n", opname,
8248 (Int)imm8,
8249 nameXMMReg(eregOfRexRM(pfx,rm)),
8250 nameXMMReg(gregOfRexRM(pfx,rm)) );
8251 } else {
sewardj2e28ac42008-12-04 00:05:12 +00008252 addr = disAMode ( &alen, vbi, pfx, delta, dis_buf, 1 );
sewardj8d965312005-02-25 02:48:47 +00008253 imm8 = getUChar(delta+alen);
8254 findSSECmpOp(&needNot, &op, imm8, all_lanes, sz);
sewardjab9055b2006-01-01 13:17:38 +00008255 assign( plain,
8256 binop(
8257 op,
8258 getXMMReg(gregOfRexRM(pfx,rm)),
8259 all_lanes ? loadLE(Ity_V128, mkexpr(addr))
8260 : sz == 8 ? unop( Iop_64UtoV128, loadLE(Ity_I64, mkexpr(addr)))
8261 : /*sz==4*/ unop( Iop_32UtoV128, loadLE(Ity_I32, mkexpr(addr)))
8262 )
8263 );
sewardj8d965312005-02-25 02:48:47 +00008264 delta += alen+1;
8265 DIP("%s $%d,%s,%s\n", opname,
8266 (Int)imm8,
8267 dis_buf,
8268 nameXMMReg(gregOfRexRM(pfx,rm)) );
8269 }
8270
8271 if (needNot && all_lanes) {
sewardj9c9ee3d2005-02-26 01:17:42 +00008272 putXMMReg( gregOfRexRM(pfx,rm),
sewardj8d965312005-02-25 02:48:47 +00008273 unop(Iop_NotV128, mkexpr(plain)) );
8274 }
8275 else
8276 if (needNot && !all_lanes) {
sewardj1027dc22005-02-26 01:55:02 +00008277 mask = toUShort(sz==4 ? 0x000F : 0x00FF);
sewardj8d965312005-02-25 02:48:47 +00008278 putXMMReg( gregOfRexRM(pfx,rm),
8279 binop(Iop_XorV128, mkexpr(plain), mkV128(mask)) );
8280 }
8281 else {
8282 putXMMReg( gregOfRexRM(pfx,rm), mkexpr(plain) );
8283 }
8284
8285 return delta;
8286}
8287
8288
sewardjadffcef2005-05-11 00:03:06 +00008289/* Vector by scalar shift of G by the amount specified at the bottom
8290 of E. */
8291
sewardj2e28ac42008-12-04 00:05:12 +00008292static ULong dis_SSE_shiftG_byE ( VexAbiInfo* vbi,
8293 Prefix pfx, Long delta,
sewardjadffcef2005-05-11 00:03:06 +00008294 HChar* opname, IROp op )
8295{
8296 HChar dis_buf[50];
8297 Int alen, size;
8298 IRTemp addr;
8299 Bool shl, shr, sar;
8300 UChar rm = getUChar(delta);
8301 IRTemp g0 = newTemp(Ity_V128);
8302 IRTemp g1 = newTemp(Ity_V128);
8303 IRTemp amt = newTemp(Ity_I32);
8304 IRTemp amt8 = newTemp(Ity_I8);
8305 if (epartIsReg(rm)) {
8306 assign( amt, getXMMRegLane32(eregOfRexRM(pfx,rm), 0) );
8307 DIP("%s %s,%s\n", opname,
8308 nameXMMReg(eregOfRexRM(pfx,rm)),
8309 nameXMMReg(gregOfRexRM(pfx,rm)) );
8310 delta++;
8311 } else {
sewardj2e28ac42008-12-04 00:05:12 +00008312 addr = disAMode ( &alen, vbi, pfx, delta, dis_buf, 0 );
sewardjadffcef2005-05-11 00:03:06 +00008313 assign( amt, loadLE(Ity_I32, mkexpr(addr)) );
8314 DIP("%s %s,%s\n", opname,
8315 dis_buf,
8316 nameXMMReg(gregOfRexRM(pfx,rm)) );
8317 delta += alen;
8318 }
8319 assign( g0, getXMMReg(gregOfRexRM(pfx,rm)) );
8320 assign( amt8, unop(Iop_32to8, mkexpr(amt)) );
8321
8322 shl = shr = sar = False;
8323 size = 0;
8324 switch (op) {
8325 case Iop_ShlN16x8: shl = True; size = 32; break;
8326 case Iop_ShlN32x4: shl = True; size = 32; break;
8327 case Iop_ShlN64x2: shl = True; size = 64; break;
8328 case Iop_SarN16x8: sar = True; size = 16; break;
8329 case Iop_SarN32x4: sar = True; size = 32; break;
8330 case Iop_ShrN16x8: shr = True; size = 16; break;
8331 case Iop_ShrN32x4: shr = True; size = 32; break;
8332 case Iop_ShrN64x2: shr = True; size = 64; break;
8333 default: vassert(0);
8334 }
8335
8336 if (shl || shr) {
8337 assign(
8338 g1,
8339 IRExpr_Mux0X(
8340 unop(Iop_1Uto8,
8341 binop(Iop_CmpLT64U, unop(Iop_32Uto64,mkexpr(amt)), mkU64(size))),
8342 mkV128(0x0000),
8343 binop(op, mkexpr(g0), mkexpr(amt8))
8344 )
8345 );
8346 } else
8347 if (sar) {
8348 assign(
8349 g1,
8350 IRExpr_Mux0X(
8351 unop(Iop_1Uto8,
8352 binop(Iop_CmpLT64U, unop(Iop_32Uto64,mkexpr(amt)), mkU64(size))),
8353 binop(op, mkexpr(g0), mkU8(size-1)),
8354 binop(op, mkexpr(g0), mkexpr(amt8))
8355 )
8356 );
8357 } else {
8358 vassert(0);
8359 }
8360
8361 putXMMReg( gregOfRexRM(pfx,rm), mkexpr(g1) );
8362 return delta;
8363}
sewardj09717342005-05-05 21:34:02 +00008364
8365
8366/* Vector by scalar shift of E by an immediate byte. */
8367
8368static
8369ULong dis_SSE_shiftE_imm ( Prefix pfx,
sewardj270def42005-07-03 01:03:01 +00008370 Long delta, HChar* opname, IROp op )
sewardj09717342005-05-05 21:34:02 +00008371{
8372 Bool shl, shr, sar;
8373 UChar rm = getUChar(delta);
8374 IRTemp e0 = newTemp(Ity_V128);
8375 IRTemp e1 = newTemp(Ity_V128);
8376 UChar amt, size;
8377 vassert(epartIsReg(rm));
8378 vassert(gregLO3ofRM(rm) == 2
8379 || gregLO3ofRM(rm) == 4 || gregLO3ofRM(rm) == 6);
sewardjca673ab2005-05-11 10:03:08 +00008380 amt = getUChar(delta+1);
sewardj09717342005-05-05 21:34:02 +00008381 delta += 2;
8382 DIP("%s $%d,%s\n", opname,
8383 (Int)amt,
8384 nameXMMReg(eregOfRexRM(pfx,rm)) );
8385 assign( e0, getXMMReg(eregOfRexRM(pfx,rm)) );
8386
8387 shl = shr = sar = False;
8388 size = 0;
8389 switch (op) {
8390 case Iop_ShlN16x8: shl = True; size = 16; break;
8391 case Iop_ShlN32x4: shl = True; size = 32; break;
8392 case Iop_ShlN64x2: shl = True; size = 64; break;
8393 case Iop_SarN16x8: sar = True; size = 16; break;
8394 case Iop_SarN32x4: sar = True; size = 32; break;
8395 case Iop_ShrN16x8: shr = True; size = 16; break;
8396 case Iop_ShrN32x4: shr = True; size = 32; break;
8397 case Iop_ShrN64x2: shr = True; size = 64; break;
8398 default: vassert(0);
8399 }
8400
8401 if (shl || shr) {
8402 assign( e1, amt >= size
8403 ? mkV128(0x0000)
8404 : binop(op, mkexpr(e0), mkU8(amt))
8405 );
8406 } else
8407 if (sar) {
8408 assign( e1, amt >= size
8409 ? binop(op, mkexpr(e0), mkU8(size-1))
8410 : binop(op, mkexpr(e0), mkU8(amt))
8411 );
8412 } else {
8413 vassert(0);
8414 }
8415
8416 putXMMReg( eregOfRexRM(pfx,rm), mkexpr(e1) );
8417 return delta;
8418}
sewardj1a01e652005-02-23 11:39:21 +00008419
8420
8421/* Get the current SSE rounding mode. */
8422
8423static IRExpr* /* :: Ity_I32 */ get_sse_roundingmode ( void )
8424{
8425 return
8426 unop( Iop_64to32,
8427 binop( Iop_And64,
8428 IRExpr_Get( OFFB_SSEROUND, Ity_I64 ),
8429 mkU64(3) ));
8430}
8431
sewardjbcbb9de2005-03-27 02:22:32 +00008432static void put_sse_roundingmode ( IRExpr* sseround )
8433{
sewardjdd40fdf2006-12-24 02:20:24 +00008434 vassert(typeOfIRExpr(irsb->tyenv, sseround) == Ity_I32);
sewardjbcbb9de2005-03-27 02:22:32 +00008435 stmt( IRStmt_Put( OFFB_SSEROUND,
8436 unop(Iop_32Uto64,sseround) ) );
8437}
8438
sewardja7ba8c42005-05-10 20:08:34 +00008439/* Break a 128-bit value up into four 32-bit ints. */
8440
8441static void breakup128to32s ( IRTemp t128,
8442 /*OUTs*/
8443 IRTemp* t3, IRTemp* t2,
8444 IRTemp* t1, IRTemp* t0 )
8445{
8446 IRTemp hi64 = newTemp(Ity_I64);
8447 IRTemp lo64 = newTemp(Ity_I64);
8448 assign( hi64, unop(Iop_V128HIto64, mkexpr(t128)) );
8449 assign( lo64, unop(Iop_V128to64, mkexpr(t128)) );
8450
8451 vassert(t0 && *t0 == IRTemp_INVALID);
8452 vassert(t1 && *t1 == IRTemp_INVALID);
8453 vassert(t2 && *t2 == IRTemp_INVALID);
8454 vassert(t3 && *t3 == IRTemp_INVALID);
8455
8456 *t0 = newTemp(Ity_I32);
8457 *t1 = newTemp(Ity_I32);
8458 *t2 = newTemp(Ity_I32);
8459 *t3 = newTemp(Ity_I32);
8460 assign( *t0, unop(Iop_64to32, mkexpr(lo64)) );
8461 assign( *t1, unop(Iop_64HIto32, mkexpr(lo64)) );
8462 assign( *t2, unop(Iop_64to32, mkexpr(hi64)) );
8463 assign( *t3, unop(Iop_64HIto32, mkexpr(hi64)) );
8464}
8465
8466/* Construct a 128-bit value from four 32-bit ints. */
8467
8468static IRExpr* mk128from32s ( IRTemp t3, IRTemp t2,
8469 IRTemp t1, IRTemp t0 )
8470{
8471 return
8472 binop( Iop_64HLtoV128,
8473 binop(Iop_32HLto64, mkexpr(t3), mkexpr(t2)),
8474 binop(Iop_32HLto64, mkexpr(t1), mkexpr(t0))
8475 );
8476}
8477
8478/* Break a 64-bit value up into four 16-bit ints. */
8479
8480static void breakup64to16s ( IRTemp t64,
8481 /*OUTs*/
8482 IRTemp* t3, IRTemp* t2,
8483 IRTemp* t1, IRTemp* t0 )
8484{
8485 IRTemp hi32 = newTemp(Ity_I32);
8486 IRTemp lo32 = newTemp(Ity_I32);
8487 assign( hi32, unop(Iop_64HIto32, mkexpr(t64)) );
8488 assign( lo32, unop(Iop_64to32, mkexpr(t64)) );
8489
8490 vassert(t0 && *t0 == IRTemp_INVALID);
8491 vassert(t1 && *t1 == IRTemp_INVALID);
8492 vassert(t2 && *t2 == IRTemp_INVALID);
8493 vassert(t3 && *t3 == IRTemp_INVALID);
8494
8495 *t0 = newTemp(Ity_I16);
8496 *t1 = newTemp(Ity_I16);
8497 *t2 = newTemp(Ity_I16);
8498 *t3 = newTemp(Ity_I16);
8499 assign( *t0, unop(Iop_32to16, mkexpr(lo32)) );
8500 assign( *t1, unop(Iop_32HIto16, mkexpr(lo32)) );
8501 assign( *t2, unop(Iop_32to16, mkexpr(hi32)) );
8502 assign( *t3, unop(Iop_32HIto16, mkexpr(hi32)) );
8503}
8504
8505/* Construct a 64-bit value from four 16-bit ints. */
8506
8507static IRExpr* mk64from16s ( IRTemp t3, IRTemp t2,
8508 IRTemp t1, IRTemp t0 )
8509{
8510 return
8511 binop( Iop_32HLto64,
8512 binop(Iop_16HLto32, mkexpr(t3), mkexpr(t2)),
8513 binop(Iop_16HLto32, mkexpr(t1), mkexpr(t0))
8514 );
8515}
sewardjdf0e0022005-01-25 15:48:43 +00008516
8517
sewardjd166e282008-02-06 11:42:45 +00008518/* Helper for the SSSE3 (not SSE3) PMULHRSW insns. Given two 64-bit
8519 values (aa,bb), computes, for each of the 4 16-bit lanes:
8520
8521 (((aa_lane *s32 bb_lane) >>u 14) + 1) >>u 1
8522*/
8523static IRExpr* dis_PMULHRSW_helper ( IRExpr* aax, IRExpr* bbx )
8524{
8525 IRTemp aa = newTemp(Ity_I64);
8526 IRTemp bb = newTemp(Ity_I64);
8527 IRTemp aahi32s = newTemp(Ity_I64);
8528 IRTemp aalo32s = newTemp(Ity_I64);
8529 IRTemp bbhi32s = newTemp(Ity_I64);
8530 IRTemp bblo32s = newTemp(Ity_I64);
8531 IRTemp rHi = newTemp(Ity_I64);
8532 IRTemp rLo = newTemp(Ity_I64);
8533 IRTemp one32x2 = newTemp(Ity_I64);
8534 assign(aa, aax);
8535 assign(bb, bbx);
8536 assign( aahi32s,
8537 binop(Iop_SarN32x2,
8538 binop(Iop_InterleaveHI16x4, mkexpr(aa), mkexpr(aa)),
8539 mkU8(16) ));
8540 assign( aalo32s,
8541 binop(Iop_SarN32x2,
8542 binop(Iop_InterleaveLO16x4, mkexpr(aa), mkexpr(aa)),
8543 mkU8(16) ));
8544 assign( bbhi32s,
8545 binop(Iop_SarN32x2,
8546 binop(Iop_InterleaveHI16x4, mkexpr(bb), mkexpr(bb)),
8547 mkU8(16) ));
8548 assign( bblo32s,
8549 binop(Iop_SarN32x2,
8550 binop(Iop_InterleaveLO16x4, mkexpr(bb), mkexpr(bb)),
8551 mkU8(16) ));
8552 assign(one32x2, mkU64( (1ULL << 32) + 1 ));
8553 assign(
8554 rHi,
8555 binop(
8556 Iop_ShrN32x2,
8557 binop(
8558 Iop_Add32x2,
8559 binop(
8560 Iop_ShrN32x2,
8561 binop(Iop_Mul32x2, mkexpr(aahi32s), mkexpr(bbhi32s)),
8562 mkU8(14)
8563 ),
8564 mkexpr(one32x2)
8565 ),
8566 mkU8(1)
8567 )
8568 );
8569 assign(
8570 rLo,
8571 binop(
8572 Iop_ShrN32x2,
8573 binop(
8574 Iop_Add32x2,
8575 binop(
8576 Iop_ShrN32x2,
8577 binop(Iop_Mul32x2, mkexpr(aalo32s), mkexpr(bblo32s)),
8578 mkU8(14)
8579 ),
8580 mkexpr(one32x2)
8581 ),
8582 mkU8(1)
8583 )
8584 );
8585 return
8586 binop(Iop_CatEvenLanes16x4, mkexpr(rHi), mkexpr(rLo));
8587}
8588
8589/* Helper for the SSSE3 (not SSE3) PSIGN{B,W,D} insns. Given two 64-bit
8590 values (aa,bb), computes, for each lane:
8591
8592 if aa_lane < 0 then - bb_lane
8593 else if aa_lane > 0 then bb_lane
8594 else 0
8595*/
8596static IRExpr* dis_PSIGN_helper ( IRExpr* aax, IRExpr* bbx, Int laneszB )
8597{
8598 IRTemp aa = newTemp(Ity_I64);
8599 IRTemp bb = newTemp(Ity_I64);
8600 IRTemp zero = newTemp(Ity_I64);
8601 IRTemp bbNeg = newTemp(Ity_I64);
8602 IRTemp negMask = newTemp(Ity_I64);
8603 IRTemp posMask = newTemp(Ity_I64);
8604 IROp opSub = Iop_INVALID;
8605 IROp opCmpGTS = Iop_INVALID;
8606
8607 switch (laneszB) {
8608 case 1: opSub = Iop_Sub8x8; opCmpGTS = Iop_CmpGT8Sx8; break;
8609 case 2: opSub = Iop_Sub16x4; opCmpGTS = Iop_CmpGT16Sx4; break;
8610 case 4: opSub = Iop_Sub32x2; opCmpGTS = Iop_CmpGT32Sx2; break;
8611 default: vassert(0);
8612 }
8613
8614 assign( aa, aax );
8615 assign( bb, bbx );
8616 assign( zero, mkU64(0) );
8617 assign( bbNeg, binop(opSub, mkexpr(zero), mkexpr(bb)) );
8618 assign( negMask, binop(opCmpGTS, mkexpr(zero), mkexpr(aa)) );
8619 assign( posMask, binop(opCmpGTS, mkexpr(aa), mkexpr(zero)) );
8620
8621 return
8622 binop(Iop_Or64,
8623 binop(Iop_And64, mkexpr(bb), mkexpr(posMask)),
8624 binop(Iop_And64, mkexpr(bbNeg), mkexpr(negMask)) );
8625
8626}
8627
8628/* Helper for the SSSE3 (not SSE3) PABS{B,W,D} insns. Given a 64-bit
8629 value aa, computes, for each lane
8630
8631 if aa < 0 then -aa else aa
8632
8633 Note that the result is interpreted as unsigned, so that the
8634 absolute value of the most negative signed input can be
8635 represented.
8636*/
8637static IRExpr* dis_PABS_helper ( IRExpr* aax, Int laneszB )
8638{
8639 IRTemp aa = newTemp(Ity_I64);
8640 IRTemp zero = newTemp(Ity_I64);
8641 IRTemp aaNeg = newTemp(Ity_I64);
8642 IRTemp negMask = newTemp(Ity_I64);
8643 IRTemp posMask = newTemp(Ity_I64);
8644 IROp opSub = Iop_INVALID;
8645 IROp opSarN = Iop_INVALID;
8646
8647 switch (laneszB) {
8648 case 1: opSub = Iop_Sub8x8; opSarN = Iop_SarN8x8; break;
8649 case 2: opSub = Iop_Sub16x4; opSarN = Iop_SarN16x4; break;
8650 case 4: opSub = Iop_Sub32x2; opSarN = Iop_SarN32x2; break;
8651 default: vassert(0);
8652 }
8653
8654 assign( aa, aax );
8655 assign( negMask, binop(opSarN, mkexpr(aa), mkU8(8*laneszB-1)) );
8656 assign( posMask, unop(Iop_Not64, mkexpr(negMask)) );
8657 assign( zero, mkU64(0) );
8658 assign( aaNeg, binop(opSub, mkexpr(zero), mkexpr(aa)) );
8659 return
8660 binop(Iop_Or64,
8661 binop(Iop_And64, mkexpr(aa), mkexpr(posMask)),
8662 binop(Iop_And64, mkexpr(aaNeg), mkexpr(negMask)) );
8663}
8664
8665static IRExpr* dis_PALIGNR_XMM_helper ( IRTemp hi64,
8666 IRTemp lo64, Long byteShift )
8667{
8668 vassert(byteShift >= 1 && byteShift <= 7);
8669 return
8670 binop(Iop_Or64,
8671 binop(Iop_Shl64, mkexpr(hi64), mkU8(8*(8-byteShift))),
8672 binop(Iop_Shr64, mkexpr(lo64), mkU8(8*byteShift))
8673 );
8674}
8675
sewardj150c9cd2008-02-09 01:16:02 +00008676/* Generate a SIGSEGV followed by a restart of the current instruction
8677 if effective_addr is not 16-aligned. This is required behaviour
8678 for some SSE3 instructions and all 128-bit SSSE3 instructions.
8679 This assumes that guest_RIP_curr_instr is set correctly! */
8680static void gen_SEGV_if_not_16_aligned ( IRTemp effective_addr )
8681{
8682 stmt(
8683 IRStmt_Exit(
8684 binop(Iop_CmpNE64,
8685 binop(Iop_And64,mkexpr(effective_addr),mkU64(0xF)),
8686 mkU64(0)),
8687 Ijk_SigSEGV,
8688 IRConst_U64(guest_RIP_curr_instr)
8689 )
8690 );
8691}
8692
sewardjd166e282008-02-06 11:42:45 +00008693
sewardjc4356f02007-11-09 21:15:04 +00008694/* Helper for deciding whether a given insn (starting at the opcode
8695 byte) may validly be used with a LOCK prefix. The following insns
8696 may be used with LOCK when their destination operand is in memory.
sewardje9d8a262009-07-01 08:06:34 +00008697 AFAICS this is exactly the same for both 32-bit and 64-bit mode.
sewardjc4356f02007-11-09 21:15:04 +00008698
sewardje9d8a262009-07-01 08:06:34 +00008699 ADD 80 /0, 81 /0, 82 /0, 83 /0, 00, 01
8700 OR 80 /1, 81 /1, 82 /x, 83 /1, 08, 09
8701 ADC 80 /2, 81 /2, 82 /2, 83 /2, 10, 11
8702 SBB 81 /3, 81 /3, 82 /x, 83 /3, 18, 19
8703 AND 80 /4, 81 /4, 82 /x, 83 /4, 20, 21
8704 SUB 80 /5, 81 /5, 82 /x, 83 /5, 28, 29
8705 XOR 80 /6, 81 /6, 82 /x, 83 /6, 30, 31
sewardjc4356f02007-11-09 21:15:04 +00008706
8707 DEC FE /1, FF /1
8708 INC FE /0, FF /0
8709
8710 NEG F6 /3, F7 /3
8711 NOT F6 /2, F7 /2
8712
sewardje9d8a262009-07-01 08:06:34 +00008713 XCHG 86, 87
sewardjc4356f02007-11-09 21:15:04 +00008714
8715 BTC 0F BB, 0F BA /7
8716 BTR 0F B3, 0F BA /6
8717 BTS 0F AB, 0F BA /5
8718
8719 CMPXCHG 0F B0, 0F B1
8720 CMPXCHG8B 0F C7 /1
8721
8722 XADD 0F C0, 0F C1
sewardje9d8a262009-07-01 08:06:34 +00008723
8724 ------------------------------
8725
8726 80 /0 = addb $imm8, rm8
8727 81 /0 = addl $imm32, rm32 and addw $imm16, rm16
8728 82 /0 = addb $imm8, rm8
8729 83 /0 = addl $simm8, rm32 and addw $simm8, rm16
8730
8731 00 = addb r8, rm8
8732 01 = addl r32, rm32 and addw r16, rm16
8733
8734 Same for ADD OR ADC SBB AND SUB XOR
8735
8736 FE /1 = dec rm8
8737 FF /1 = dec rm32 and dec rm16
8738
8739 FE /0 = inc rm8
8740 FF /0 = inc rm32 and inc rm16
8741
8742 F6 /3 = neg rm8
8743 F7 /3 = neg rm32 and neg rm16
8744
8745 F6 /2 = not rm8
8746 F7 /2 = not rm32 and not rm16
8747
8748 0F BB = btcw r16, rm16 and btcl r32, rm32
8749 OF BA /7 = btcw $imm8, rm16 and btcw $imm8, rm32
8750
8751 Same for BTS, BTR
sewardjc4356f02007-11-09 21:15:04 +00008752*/
8753static Bool can_be_used_with_LOCK_prefix ( UChar* opc )
8754{
8755 switch (opc[0]) {
sewardje9d8a262009-07-01 08:06:34 +00008756 case 0x00: case 0x01: case 0x08: case 0x09:
8757 case 0x10: case 0x11: case 0x18: case 0x19:
8758 case 0x20: case 0x21: case 0x28: case 0x29:
8759 case 0x30: case 0x31:
8760 if (!epartIsReg(opc[1]))
8761 return True;
8762 break;
sewardjc4356f02007-11-09 21:15:04 +00008763
sewardje9d8a262009-07-01 08:06:34 +00008764 case 0x80: case 0x81: case 0x82: case 0x83:
8765 if (gregLO3ofRM(opc[1]) >= 0 && gregLO3ofRM(opc[1]) <= 6
8766 && !epartIsReg(opc[1]))
sewardjc4356f02007-11-09 21:15:04 +00008767 return True;
8768 break;
8769
8770 case 0xFE: case 0xFF:
sewardje9d8a262009-07-01 08:06:34 +00008771 if (gregLO3ofRM(opc[1]) >= 0 && gregLO3ofRM(opc[1]) <= 1
8772 && !epartIsReg(opc[1]))
sewardjc4356f02007-11-09 21:15:04 +00008773 return True;
8774 break;
8775
8776 case 0xF6: case 0xF7:
sewardje9d8a262009-07-01 08:06:34 +00008777 if (gregLO3ofRM(opc[1]) >= 2 && gregLO3ofRM(opc[1]) <= 3
8778 && !epartIsReg(opc[1]))
sewardjc4356f02007-11-09 21:15:04 +00008779 return True;
8780 break;
8781
8782 case 0x86: case 0x87:
sewardje9d8a262009-07-01 08:06:34 +00008783 if (!epartIsReg(opc[1]))
8784 return True;
8785 break;
sewardjc4356f02007-11-09 21:15:04 +00008786
8787 case 0x0F: {
8788 switch (opc[1]) {
8789 case 0xBB: case 0xB3: case 0xAB:
sewardje9d8a262009-07-01 08:06:34 +00008790 if (!epartIsReg(opc[2]))
8791 return True;
8792 break;
sewardjc4356f02007-11-09 21:15:04 +00008793 case 0xBA:
sewardje9d8a262009-07-01 08:06:34 +00008794 if (gregLO3ofRM(opc[2]) >= 5 && gregLO3ofRM(opc[2]) <= 7
8795 && !epartIsReg(opc[2]))
sewardjc4356f02007-11-09 21:15:04 +00008796 return True;
8797 break;
8798 case 0xB0: case 0xB1:
sewardje9d8a262009-07-01 08:06:34 +00008799 if (!epartIsReg(opc[2]))
8800 return True;
8801 break;
sewardjc4356f02007-11-09 21:15:04 +00008802 case 0xC7:
sewardje9d8a262009-07-01 08:06:34 +00008803 if (gregLO3ofRM(opc[2]) == 1 && !epartIsReg(opc[2]) )
sewardjc4356f02007-11-09 21:15:04 +00008804 return True;
8805 break;
8806 case 0xC0: case 0xC1:
sewardje9d8a262009-07-01 08:06:34 +00008807 if (!epartIsReg(opc[2]))
8808 return True;
8809 break;
sewardjc4356f02007-11-09 21:15:04 +00008810 default:
8811 break;
8812 } /* switch (opc[1]) */
8813 break;
8814 }
8815
8816 default:
8817 break;
8818 } /* switch (opc[0]) */
8819
8820 return False;
8821}
8822
8823
sewardjdf0e0022005-01-25 15:48:43 +00008824/*------------------------------------------------------------*/
8825/*--- Disassemble a single instruction ---*/
8826/*------------------------------------------------------------*/
8827
sewardj9e6491a2005-07-02 19:24:10 +00008828/* Disassemble a single instruction into IR. The instruction is
8829 located in host memory at &guest_code[delta]. */
sewardjdf0e0022005-01-25 15:48:43 +00008830
sewardj9e6491a2005-07-02 19:24:10 +00008831static
8832DisResult disInstr_AMD64_WRK (
sewardje9d8a262009-07-01 08:06:34 +00008833 /*OUT*/Bool* expect_CAS,
sewardj9e6491a2005-07-02 19:24:10 +00008834 Bool put_IP,
sewardjc716aea2006-01-17 01:48:46 +00008835 Bool (*resteerOkFn) ( /*opaque*/void*, Addr64 ),
sewardj984d9b12010-01-15 10:53:21 +00008836 Bool resteerCisOk,
sewardjc716aea2006-01-17 01:48:46 +00008837 void* callback_opaque,
sewardj9e6491a2005-07-02 19:24:10 +00008838 Long delta64,
sewardjaca070a2006-10-17 00:28:22 +00008839 VexArchInfo* archinfo,
sewardj2e28ac42008-12-04 00:05:12 +00008840 VexAbiInfo* vbi
sewardj9e6491a2005-07-02 19:24:10 +00008841 )
sewardjdf0e0022005-01-25 15:48:43 +00008842{
8843 IRType ty;
sewardja7ba8c42005-05-10 20:08:34 +00008844 IRTemp addr, t0, t1, t2, t3, t4, t5, t6;
sewardjdf0e0022005-01-25 15:48:43 +00008845 Int alen;
sewardjbb4396c2007-11-20 17:29:08 +00008846 UChar opc, modrm, abyte, pre;
sewardj1027dc22005-02-26 01:55:02 +00008847 Long d64;
sewardjdf0e0022005-01-25 15:48:43 +00008848 HChar dis_buf[50];
8849 Int am_sz, d_sz, n, n_prefixes;
sewardj9e6491a2005-07-02 19:24:10 +00008850 DisResult dres;
sewardja6b93d12005-02-17 09:28:28 +00008851 UChar* insn; /* used in SSE decoders */
sewardjdf0e0022005-01-25 15:48:43 +00008852
sewardj9e6491a2005-07-02 19:24:10 +00008853 /* The running delta */
8854 Long delta = delta64;
8855
sewardjdf0e0022005-01-25 15:48:43 +00008856 /* Holds eip at the start of the insn, so that we can print
8857 consistent error messages for unimplemented insns. */
sewardj270def42005-07-03 01:03:01 +00008858 Long delta_start = delta;
sewardjdf0e0022005-01-25 15:48:43 +00008859
8860 /* sz denotes the nominal data-op size of the insn; we change it to
8861 2 if an 0x66 prefix is seen and 8 if REX.W is 1. In case of
8862 conflict REX.W takes precedence. */
8863 Int sz = 4;
8864
sewardj3ca55a12005-01-27 16:06:23 +00008865 /* pfx holds the summary of prefixes. */
8866 Prefix pfx = PFX_EMPTY;
sewardjdf0e0022005-01-25 15:48:43 +00008867
sewardj9e6491a2005-07-02 19:24:10 +00008868 /* Set result defaults. */
8869 dres.whatNext = Dis_Continue;
8870 dres.len = 0;
8871 dres.continueAt = 0;
sewardjdf0e0022005-01-25 15:48:43 +00008872
sewardje9d8a262009-07-01 08:06:34 +00008873 *expect_CAS = False;
8874
sewardj9e6491a2005-07-02 19:24:10 +00008875 vassert(guest_RIP_next_assumed == 0);
8876 vassert(guest_RIP_next_mustcheck == False);
sewardj4b744762005-02-07 15:02:25 +00008877
sewardja7ba8c42005-05-10 20:08:34 +00008878 addr = t0 = t1 = t2 = t3 = t4 = t5 = t6 = IRTemp_INVALID;
sewardjdf0e0022005-01-25 15:48:43 +00008879
sewardj9e6491a2005-07-02 19:24:10 +00008880 DIP("\t0x%llx: ", guest_RIP_bbstart+delta);
8881
8882 /* We may be asked to update the guest RIP before going further. */
8883 if (put_IP)
8884 stmt( IRStmt_Put( OFFB_RIP, mkU64(guest_RIP_curr_instr)) );
sewardjdf0e0022005-01-25 15:48:43 +00008885
sewardjce02aa72006-01-12 12:27:58 +00008886 /* Spot "Special" instructions (see comment at top of file). */
sewardjdf0e0022005-01-25 15:48:43 +00008887 {
8888 UChar* code = (UChar*)(guest_code + delta);
sewardjce02aa72006-01-12 12:27:58 +00008889 /* Spot the 16-byte preamble:
8890 48C1C703 rolq $3, %rdi
8891 48C1C70D rolq $13, %rdi
8892 48C1C73D rolq $61, %rdi
8893 48C1C733 rolq $51, %rdi
sewardjdf0e0022005-01-25 15:48:43 +00008894 */
sewardjce02aa72006-01-12 12:27:58 +00008895 if (code[ 0] == 0x48 && code[ 1] == 0xC1 && code[ 2] == 0xC7
8896 && code[ 3] == 0x03 &&
8897 code[ 4] == 0x48 && code[ 5] == 0xC1 && code[ 6] == 0xC7
8898 && code[ 7] == 0x0D &&
8899 code[ 8] == 0x48 && code[ 9] == 0xC1 && code[10] == 0xC7
8900 && code[11] == 0x3D &&
8901 code[12] == 0x48 && code[13] == 0xC1 && code[14] == 0xC7
8902 && code[15] == 0x33) {
8903 /* Got a "Special" instruction preamble. Which one is it? */
8904 if (code[16] == 0x48 && code[17] == 0x87
8905 && code[18] == 0xDB /* xchgq %rbx,%rbx */) {
8906 /* %RDX = client_request ( %RAX ) */
8907 DIP("%%rdx = client_request ( %%rax )\n");
8908 delta += 19;
8909 jmp_lit(Ijk_ClientReq, guest_RIP_bbstart+delta);
8910 dres.whatNext = Dis_StopHere;
8911 goto decode_success;
8912 }
8913 else
8914 if (code[16] == 0x48 && code[17] == 0x87
8915 && code[18] == 0xC9 /* xchgq %rcx,%rcx */) {
8916 /* %RAX = guest_NRADDR */
8917 DIP("%%rax = guest_NRADDR\n");
8918 delta += 19;
8919 putIRegRAX(8, IRExpr_Get( OFFB_NRADDR, Ity_I64 ));
8920 goto decode_success;
8921 }
8922 else
8923 if (code[16] == 0x48 && code[17] == 0x87
8924 && code[18] == 0xD2 /* xchgq %rdx,%rdx */) {
8925 /* call-noredir *%RAX */
8926 DIP("call-noredir *%%rax\n");
8927 delta += 19;
8928 t1 = newTemp(Ity_I64);
8929 assign(t1, getIRegRAX(8));
8930 t2 = newTemp(Ity_I64);
8931 assign(t2, binop(Iop_Sub64, getIReg64(R_RSP), mkU64(8)));
8932 putIReg64(R_RSP, mkexpr(t2));
8933 storeLE( mkexpr(t2), mkU64(guest_RIP_bbstart+delta));
8934 jmp_treg(Ijk_NoRedir,t1);
8935 dres.whatNext = Dis_StopHere;
8936 goto decode_success;
8937 }
8938 /* We don't know what it is. */
8939 goto decode_failure;
8940 /*NOTREACHED*/
sewardjdf0e0022005-01-25 15:48:43 +00008941 }
8942 }
8943
8944 /* Eat prefixes, summarising the result in pfx and sz, and rejecting
8945 as many invalid combinations as possible. */
8946 n_prefixes = 0;
8947 while (True) {
sewardj54477e32007-08-23 18:53:59 +00008948 if (n_prefixes > 7) goto decode_failure;
sewardj8c332e22005-01-28 01:36:56 +00008949 pre = getUChar(delta);
sewardjdf0e0022005-01-25 15:48:43 +00008950 switch (pre) {
8951 case 0x66: pfx |= PFX_66; break;
8952 case 0x67: pfx |= PFX_ASO; break;
8953 case 0xF2: pfx |= PFX_F2; break;
8954 case 0xF3: pfx |= PFX_F3; break;
sewardje9d8a262009-07-01 08:06:34 +00008955 case 0xF0: pfx |= PFX_LOCK; *expect_CAS = True; break;
sewardjdf0e0022005-01-25 15:48:43 +00008956 case 0x2E: pfx |= PFX_CS; break;
8957 case 0x3E: pfx |= PFX_DS; break;
8958 case 0x26: pfx |= PFX_ES; break;
8959 case 0x64: pfx |= PFX_FS; break;
8960 case 0x65: pfx |= PFX_GS; break;
8961 case 0x36: pfx |= PFX_SS; break;
8962 case 0x40 ... 0x4F:
8963 pfx |= PFX_REX;
8964 if (pre & (1<<3)) pfx |= PFX_REXW;
8965 if (pre & (1<<2)) pfx |= PFX_REXR;
8966 if (pre & (1<<1)) pfx |= PFX_REXX;
8967 if (pre & (1<<0)) pfx |= PFX_REXB;
8968 break;
8969 default:
8970 goto not_a_prefix;
8971 }
8972 n_prefixes++;
8973 delta++;
8974 }
8975
8976 not_a_prefix:
sewardjdf0e0022005-01-25 15:48:43 +00008977
sewardj42561ef2005-11-04 14:18:31 +00008978 /* Dump invalid combinations */
sewardjdf0e0022005-01-25 15:48:43 +00008979 n = 0;
8980 if (pfx & PFX_F2) n++;
8981 if (pfx & PFX_F3) n++;
sewardj3ca55a12005-01-27 16:06:23 +00008982 if (n > 1)
8983 goto decode_failure; /* can't have both */
sewardjdf0e0022005-01-25 15:48:43 +00008984
8985 n = 0;
8986 if (pfx & PFX_CS) n++;
8987 if (pfx & PFX_DS) n++;
8988 if (pfx & PFX_ES) n++;
8989 if (pfx & PFX_FS) n++;
8990 if (pfx & PFX_GS) n++;
8991 if (pfx & PFX_SS) n++;
sewardj3ca55a12005-01-27 16:06:23 +00008992 if (n > 1)
8993 goto decode_failure; /* multiple seg overrides == illegal */
sewardjdf0e0022005-01-25 15:48:43 +00008994
sewardjceccb292009-01-22 20:40:22 +00008995 /* We have a %fs prefix. Reject it if there's no evidence in 'vbi'
8996 that we should accept it. */
8997 if ((pfx & PFX_FS) && !vbi->guest_amd64_assume_fs_is_zero)
8998 goto decode_failure;
8999
9000 /* Ditto for %gs prefixes. */
9001 if ((pfx & PFX_GS) && !vbi->guest_amd64_assume_gs_is_0x60)
9002 goto decode_failure;
sewardj42561ef2005-11-04 14:18:31 +00009003
sewardjdf0e0022005-01-25 15:48:43 +00009004 /* Set up sz. */
9005 sz = 4;
9006 if (pfx & PFX_66) sz = 2;
9007 if ((pfx & PFX_REX) && (pfx & PFX_REXW)) sz = 8;
9008
sewardje9d8a262009-07-01 08:06:34 +00009009 /* Now we should be looking at the primary opcode byte or the
9010 leading F2 or F3. Check that any LOCK prefix is actually
9011 allowed. */
sewardjc4356f02007-11-09 21:15:04 +00009012
sewardj9ff93bc2005-03-23 11:25:12 +00009013 if (pfx & PFX_LOCK) {
sewardjc4356f02007-11-09 21:15:04 +00009014 if (can_be_used_with_LOCK_prefix( (UChar*)&guest_code[delta] )) {
sewardjc4356f02007-11-09 21:15:04 +00009015 DIP("lock ");
9016 } else {
sewardje9d8a262009-07-01 08:06:34 +00009017 *expect_CAS = False;
sewardjc4356f02007-11-09 21:15:04 +00009018 goto decode_failure;
9019 }
sewardjdf0e0022005-01-25 15:48:43 +00009020 }
9021
sewardja6b93d12005-02-17 09:28:28 +00009022
9023 /* ---------------------------------------------------- */
sewardj09717342005-05-05 21:34:02 +00009024 /* --- The SSE/SSE2 decoder. --- */
sewardja6b93d12005-02-17 09:28:28 +00009025 /* ---------------------------------------------------- */
9026
9027 /* What did I do to deserve SSE ? Perhaps I was really bad in a
9028 previous life? */
9029
sewardj09717342005-05-05 21:34:02 +00009030 /* Note, this doesn't handle SSE3 right now. All amd64s support
9031 SSE2 as a minimum so there is no point distinguishing SSE1 vs
9032 SSE2. */
9033
sewardja6b93d12005-02-17 09:28:28 +00009034 insn = (UChar*)&guest_code[delta];
9035
sewardj5abcfe62007-01-10 04:59:33 +00009036 /* FXSAVE is spuriously at the start here only because it is
9037 thusly placed in guest-x86/toIR.c. */
9038
9039 /* 0F AE /0 = FXSAVE m512 -- write x87 and SSE state to memory.
9040 Note that REX.W 0F AE /0 writes a slightly different format and
9041 we don't handle that here. */
9042 if (haveNo66noF2noF3(pfx) && sz == 4
9043 && insn[0] == 0x0F && insn[1] == 0xAE
9044 && !epartIsReg(insn[2]) && gregOfRexRM(pfx,insn[2]) == 0) {
9045 IRDirty* d;
9046 modrm = getUChar(delta+2);
9047 vassert(sz == 4);
9048 vassert(!epartIsReg(modrm));
9049 /* REX.W must not be set. That should be assured us by sz == 4
9050 above. */
9051 vassert(!(pfx & PFX_REXW));
9052
sewardj2e28ac42008-12-04 00:05:12 +00009053 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj5abcfe62007-01-10 04:59:33 +00009054 delta += 2+alen;
9055
9056 DIP("fxsave %s\n", dis_buf);
9057
9058 /* Uses dirty helper:
9059 void amd64g_do_FXSAVE ( VexGuestAMD64State*, UInt ) */
9060 d = unsafeIRDirty_0_N (
9061 0/*regparms*/,
9062 "amd64g_dirtyhelper_FXSAVE",
9063 &amd64g_dirtyhelper_FXSAVE,
9064 mkIRExprVec_1( mkexpr(addr) )
9065 );
9066 d->needsBBP = True;
9067
9068 /* declare we're writing memory */
9069 d->mFx = Ifx_Write;
9070 d->mAddr = mkexpr(addr);
9071 d->mSize = 512;
9072
9073 /* declare we're reading guest state */
9074 d->nFxState = 7;
9075
9076 d->fxState[0].fx = Ifx_Read;
9077 d->fxState[0].offset = OFFB_FTOP;
9078 d->fxState[0].size = sizeof(UInt);
9079
9080 d->fxState[1].fx = Ifx_Read;
9081 d->fxState[1].offset = OFFB_FPREGS;
9082 d->fxState[1].size = 8 * sizeof(ULong);
9083
9084 d->fxState[2].fx = Ifx_Read;
9085 d->fxState[2].offset = OFFB_FPTAGS;
9086 d->fxState[2].size = 8 * sizeof(UChar);
9087
9088 d->fxState[3].fx = Ifx_Read;
9089 d->fxState[3].offset = OFFB_FPROUND;
9090 d->fxState[3].size = sizeof(ULong);
9091
9092 d->fxState[4].fx = Ifx_Read;
9093 d->fxState[4].offset = OFFB_FC3210;
9094 d->fxState[4].size = sizeof(ULong);
9095
9096 d->fxState[5].fx = Ifx_Read;
9097 d->fxState[5].offset = OFFB_XMM0;
9098 d->fxState[5].size = 16 * sizeof(U128);
9099
9100 d->fxState[6].fx = Ifx_Read;
9101 d->fxState[6].offset = OFFB_SSEROUND;
9102 d->fxState[6].size = sizeof(ULong);
9103
9104 /* Be paranoid ... this assertion tries to ensure the 16 %xmm
9105 images are packed back-to-back. If not, the value of
9106 d->fxState[5].size is wrong. */
9107 vassert(16 == sizeof(U128));
9108 vassert(OFFB_XMM15 == (OFFB_XMM0 + 15 * 16));
9109
9110 stmt( IRStmt_Dirty(d) );
9111
9112 goto decode_success;
9113 }
9114
9115 /* ------ SSE decoder main ------ */
sewardj432f8b62005-05-10 02:50:05 +00009116
9117 /* 0F 58 = ADDPS -- add 32Fx4 from R/M to R */
9118 if (haveNo66noF2noF3(pfx) && sz == 4
9119 && insn[0] == 0x0F && insn[1] == 0x58) {
sewardj2e28ac42008-12-04 00:05:12 +00009120 delta = dis_SSE_E_to_G_all( vbi, pfx, delta+2, "addps", Iop_Add32Fx4 );
sewardj432f8b62005-05-10 02:50:05 +00009121 goto decode_success;
9122 }
sewardj8d965312005-02-25 02:48:47 +00009123
9124 /* F3 0F 58 = ADDSS -- add 32F0x4 from R/M to R */
9125 if (haveF3no66noF2(pfx) && sz == 4
9126 && insn[0] == 0x0F && insn[1] == 0x58) {
sewardj2e28ac42008-12-04 00:05:12 +00009127 delta = dis_SSE_E_to_G_lo32( vbi, pfx, delta+2, "addss", Iop_Add32F0x4 );
sewardj8d965312005-02-25 02:48:47 +00009128 goto decode_success;
9129 }
9130
sewardj3aba9eb2005-03-30 23:20:47 +00009131 /* 0F 55 = ANDNPS -- G = (not G) and E */
9132 if (haveNo66noF2noF3(pfx) && sz == 4
9133 && insn[0] == 0x0F && insn[1] == 0x55) {
sewardj2e28ac42008-12-04 00:05:12 +00009134 delta = dis_SSE_E_to_G_all_invG( vbi, pfx, delta+2, "andnps", Iop_AndV128 );
sewardj3aba9eb2005-03-30 23:20:47 +00009135 goto decode_success;
9136 }
sewardj37d52572005-02-25 14:22:12 +00009137
9138 /* 0F 54 = ANDPS -- G = G and E */
9139 if (haveNo66noF2noF3(pfx) && sz == 4
9140 && insn[0] == 0x0F && insn[1] == 0x54) {
sewardj2e28ac42008-12-04 00:05:12 +00009141 delta = dis_SSE_E_to_G_all( vbi, pfx, delta+2, "andps", Iop_AndV128 );
sewardj37d52572005-02-25 14:22:12 +00009142 goto decode_success;
9143 }
9144
sewardj432f8b62005-05-10 02:50:05 +00009145 /* 0F C2 = CMPPS -- 32Fx4 comparison from R/M to R */
9146 if (haveNo66noF2noF3(pfx) && sz == 4
9147 && insn[0] == 0x0F && insn[1] == 0xC2) {
sewardj2e28ac42008-12-04 00:05:12 +00009148 delta = dis_SSEcmp_E_to_G( vbi, pfx, delta+2, "cmpps", True, 4 );
sewardj432f8b62005-05-10 02:50:05 +00009149 goto decode_success;
9150 }
sewardj3aba9eb2005-03-30 23:20:47 +00009151
9152 /* F3 0F C2 = CMPSS -- 32F0x4 comparison from R/M to R */
9153 if (haveF3no66noF2(pfx) && sz == 4
9154 && insn[0] == 0x0F && insn[1] == 0xC2) {
sewardj2e28ac42008-12-04 00:05:12 +00009155 delta = dis_SSEcmp_E_to_G( vbi, pfx, delta+2, "cmpss", False, 4 );
sewardj3aba9eb2005-03-30 23:20:47 +00009156 goto decode_success;
9157 }
sewardjc49ce232005-02-25 13:03:03 +00009158
9159 /* 0F 2F = COMISS -- 32F0x4 comparison G,E, and set ZCP */
9160 /* 0F 2E = UCOMISS -- 32F0x4 comparison G,E, and set ZCP */
9161 if (haveNo66noF2noF3(pfx) && sz == 4
9162 && insn[0] == 0x0F && (insn[1] == 0x2F || insn[1] == 0x2E)) {
9163 IRTemp argL = newTemp(Ity_F32);
9164 IRTemp argR = newTemp(Ity_F32);
9165 modrm = getUChar(delta+2);
9166 if (epartIsReg(modrm)) {
9167 assign( argR, getXMMRegLane32F( eregOfRexRM(pfx,modrm),
9168 0/*lowest lane*/ ) );
9169 delta += 2+1;
9170 DIP("%scomiss %s,%s\n", insn[1]==0x2E ? "u" : "",
9171 nameXMMReg(eregOfRexRM(pfx,modrm)),
9172 nameXMMReg(gregOfRexRM(pfx,modrm)) );
9173 } else {
sewardj2e28ac42008-12-04 00:05:12 +00009174 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardjc49ce232005-02-25 13:03:03 +00009175 assign( argR, loadLE(Ity_F32, mkexpr(addr)) );
9176 delta += 2+alen;
9177 DIP("%scomiss %s,%s\n", insn[1]==0x2E ? "u" : "",
9178 dis_buf,
9179 nameXMMReg(gregOfRexRM(pfx,modrm)) );
9180 }
9181 assign( argL, getXMMRegLane32F( gregOfRexRM(pfx,modrm),
9182 0/*lowest lane*/ ) );
9183
9184 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(AMD64G_CC_OP_COPY) ));
9185 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
9186 stmt( IRStmt_Put(
9187 OFFB_CC_DEP1,
9188 binop( Iop_And64,
9189 unop( Iop_32Uto64,
9190 binop(Iop_CmpF64,
9191 unop(Iop_F32toF64,mkexpr(argL)),
9192 unop(Iop_F32toF64,mkexpr(argR)))),
9193 mkU64(0x45)
9194 )));
9195
9196 goto decode_success;
9197 }
9198
sewardj432f8b62005-05-10 02:50:05 +00009199 /* 0F 2A = CVTPI2PS -- convert 2 x I32 in mem/mmx to 2 x F32 in low
9200 half xmm */
9201 if (haveNo66noF2noF3(pfx) && sz == 4
9202 && insn[0] == 0x0F && insn[1] == 0x2A) {
9203 IRTemp arg64 = newTemp(Ity_I64);
9204 IRTemp rmode = newTemp(Ity_I32);
9205
9206 modrm = getUChar(delta+2);
9207 do_MMX_preamble();
9208 if (epartIsReg(modrm)) {
9209 assign( arg64, getMMXReg(eregLO3ofRM(modrm)) );
9210 delta += 2+1;
9211 DIP("cvtpi2ps %s,%s\n", nameMMXReg(eregLO3ofRM(modrm)),
9212 nameXMMReg(gregOfRexRM(pfx,modrm)));
9213 } else {
sewardj2e28ac42008-12-04 00:05:12 +00009214 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj432f8b62005-05-10 02:50:05 +00009215 assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
9216 delta += 2+alen;
9217 DIP("cvtpi2ps %s,%s\n", dis_buf,
9218 nameXMMReg(gregOfRexRM(pfx,modrm)) );
9219 }
9220
9221 assign( rmode, get_sse_roundingmode() );
9222
9223 putXMMRegLane32F(
9224 gregOfRexRM(pfx,modrm), 0,
9225 binop(Iop_F64toF32,
9226 mkexpr(rmode),
sewardj6c299f32009-12-31 18:00:12 +00009227 unop(Iop_I32StoF64,
sewardj432f8b62005-05-10 02:50:05 +00009228 unop(Iop_64to32, mkexpr(arg64)) )) );
9229
9230 putXMMRegLane32F(
9231 gregOfRexRM(pfx,modrm), 1,
9232 binop(Iop_F64toF32,
9233 mkexpr(rmode),
sewardj6c299f32009-12-31 18:00:12 +00009234 unop(Iop_I32StoF64,
sewardj432f8b62005-05-10 02:50:05 +00009235 unop(Iop_64HIto32, mkexpr(arg64)) )) );
9236
9237 goto decode_success;
9238 }
sewardj8d965312005-02-25 02:48:47 +00009239
9240 /* F3 0F 2A = CVTSI2SS
9241 -- sz==4: convert I32 in mem/ireg to F32 in low quarter xmm
9242 -- sz==8: convert I64 in mem/ireg to F32 in low quarter xmm */
9243 if (haveF3no66noF2(pfx) && (sz == 4 || sz == 8)
9244 && insn[0] == 0x0F && insn[1] == 0x2A) {
9245
9246 IRTemp rmode = newTemp(Ity_I32);
9247 assign( rmode, get_sse_roundingmode() );
9248 modrm = getUChar(delta+2);
9249
9250 if (sz == 4) {
9251 IRTemp arg32 = newTemp(Ity_I32);
9252 if (epartIsReg(modrm)) {
sewardj5b470602005-02-27 13:10:48 +00009253 assign( arg32, getIReg32(eregOfRexRM(pfx,modrm)) );
sewardj8d965312005-02-25 02:48:47 +00009254 delta += 2+1;
sewardj5b470602005-02-27 13:10:48 +00009255 DIP("cvtsi2ss %s,%s\n", nameIReg32(eregOfRexRM(pfx,modrm)),
sewardj8d965312005-02-25 02:48:47 +00009256 nameXMMReg(gregOfRexRM(pfx,modrm)));
9257 } else {
sewardj2e28ac42008-12-04 00:05:12 +00009258 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj8d965312005-02-25 02:48:47 +00009259 assign( arg32, loadLE(Ity_I32, mkexpr(addr)) );
9260 delta += 2+alen;
9261 DIP("cvtsi2ss %s,%s\n", dis_buf,
9262 nameXMMReg(gregOfRexRM(pfx,modrm)) );
9263 }
9264 putXMMRegLane32F(
9265 gregOfRexRM(pfx,modrm), 0,
9266 binop(Iop_F64toF32,
9267 mkexpr(rmode),
sewardj6c299f32009-12-31 18:00:12 +00009268 unop(Iop_I32StoF64, mkexpr(arg32)) ) );
sewardj8d965312005-02-25 02:48:47 +00009269 } else {
9270 /* sz == 8 */
9271 IRTemp arg64 = newTemp(Ity_I64);
9272 if (epartIsReg(modrm)) {
sewardj5b470602005-02-27 13:10:48 +00009273 assign( arg64, getIReg64(eregOfRexRM(pfx,modrm)) );
sewardj8d965312005-02-25 02:48:47 +00009274 delta += 2+1;
sewardj5b470602005-02-27 13:10:48 +00009275 DIP("cvtsi2ssq %s,%s\n", nameIReg64(eregOfRexRM(pfx,modrm)),
sewardj8d965312005-02-25 02:48:47 +00009276 nameXMMReg(gregOfRexRM(pfx,modrm)));
9277 } else {
sewardj2e28ac42008-12-04 00:05:12 +00009278 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj82c9f2f2005-03-02 16:05:13 +00009279 assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
9280 delta += 2+alen;
9281 DIP("cvtsi2ssq %s,%s\n", dis_buf,
9282 nameXMMReg(gregOfRexRM(pfx,modrm)) );
sewardj8d965312005-02-25 02:48:47 +00009283 }
9284 putXMMRegLane32F(
9285 gregOfRexRM(pfx,modrm), 0,
9286 binop(Iop_F64toF32,
9287 mkexpr(rmode),
sewardj6c299f32009-12-31 18:00:12 +00009288 binop(Iop_I64StoF64, mkexpr(rmode), mkexpr(arg64)) ) );
sewardj8d965312005-02-25 02:48:47 +00009289 }
9290
9291 goto decode_success;
9292 }
9293
sewardj432f8b62005-05-10 02:50:05 +00009294 /* 0F 2D = CVTPS2PI -- convert 2 x F32 in mem/low half xmm to 2 x
9295 I32 in mmx, according to prevailing SSE rounding mode */
sewardja7ba8c42005-05-10 20:08:34 +00009296 /* 0F 2C = CVTTPS2PI -- convert 2 x F32 in mem/low half xmm to 2 x
9297 I32 in mmx, rounding towards zero */
sewardj432f8b62005-05-10 02:50:05 +00009298 if (haveNo66noF2noF3(pfx) && sz == 4
sewardja7ba8c42005-05-10 20:08:34 +00009299 && insn[0] == 0x0F && (insn[1] == 0x2D || insn[1] == 0x2C)) {
sewardj432f8b62005-05-10 02:50:05 +00009300 IRTemp dst64 = newTemp(Ity_I64);
9301 IRTemp rmode = newTemp(Ity_I32);
9302 IRTemp f32lo = newTemp(Ity_F32);
9303 IRTemp f32hi = newTemp(Ity_F32);
9304 Bool r2zero = toBool(insn[1] == 0x2C);
9305
9306 do_MMX_preamble();
9307 modrm = getUChar(delta+2);
9308
9309 if (epartIsReg(modrm)) {
9310 delta += 2+1;
9311 assign(f32lo, getXMMRegLane32F(eregOfRexRM(pfx,modrm), 0));
9312 assign(f32hi, getXMMRegLane32F(eregOfRexRM(pfx,modrm), 1));
9313 DIP("cvt%sps2pi %s,%s\n", r2zero ? "t" : "",
9314 nameXMMReg(eregOfRexRM(pfx,modrm)),
9315 nameMMXReg(gregLO3ofRM(modrm)));
9316 } else {
sewardj2e28ac42008-12-04 00:05:12 +00009317 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj432f8b62005-05-10 02:50:05 +00009318 assign(f32lo, loadLE(Ity_F32, mkexpr(addr)));
9319 assign(f32hi, loadLE(Ity_F32, binop( Iop_Add64,
9320 mkexpr(addr),
9321 mkU64(4) )));
9322 delta += 2+alen;
9323 DIP("cvt%sps2pi %s,%s\n", r2zero ? "t" : "",
9324 dis_buf,
9325 nameMMXReg(gregLO3ofRM(modrm)));
9326 }
9327
9328 if (r2zero) {
9329 assign(rmode, mkU32((UInt)Irrm_ZERO) );
9330 } else {
9331 assign( rmode, get_sse_roundingmode() );
9332 }
9333
9334 assign(
9335 dst64,
9336 binop( Iop_32HLto64,
sewardj6c299f32009-12-31 18:00:12 +00009337 binop( Iop_F64toI32S,
sewardj432f8b62005-05-10 02:50:05 +00009338 mkexpr(rmode),
9339 unop( Iop_F32toF64, mkexpr(f32hi) ) ),
sewardj6c299f32009-12-31 18:00:12 +00009340 binop( Iop_F64toI32S,
sewardj432f8b62005-05-10 02:50:05 +00009341 mkexpr(rmode),
9342 unop( Iop_F32toF64, mkexpr(f32lo) ) )
9343 )
9344 );
9345
9346 putMMXReg(gregLO3ofRM(modrm), mkexpr(dst64));
9347 goto decode_success;
9348 }
9349
9350 /* F3 0F 2D = CVTSS2SI
9351 when sz==4 -- convert F32 in mem/low quarter xmm to I32 in ireg,
9352 according to prevailing SSE rounding mode
9353 when sz==8 -- convert F32 in mem/low quarter xmm to I64 in ireg,
9354 according to prevailing SSE rounding mode
9355 */
sewardj82c9f2f2005-03-02 16:05:13 +00009356 /* F3 0F 2C = CVTTSS2SI
9357 when sz==4 -- convert F32 in mem/low quarter xmm to I32 in ireg,
9358 truncating towards zero
9359 when sz==8 -- convert F32 in mem/low quarter xmm to I64 in ireg,
9360 truncating towards zero
9361 */
9362 if (haveF3no66noF2(pfx)
9363 && insn[0] == 0x0F
sewardj432f8b62005-05-10 02:50:05 +00009364 && (insn[1] == 0x2D || insn[1] == 0x2C)) {
sewardj82c9f2f2005-03-02 16:05:13 +00009365 IRTemp rmode = newTemp(Ity_I32);
9366 IRTemp f32lo = newTemp(Ity_F32);
9367 Bool r2zero = toBool(insn[1] == 0x2C);
9368 vassert(sz == 4 || sz == 8);
9369
9370 modrm = getUChar(delta+2);
9371 if (epartIsReg(modrm)) {
9372 delta += 2+1;
9373 assign(f32lo, getXMMRegLane32F(eregOfRexRM(pfx,modrm), 0));
9374 DIP("cvt%sss2si %s,%s\n", r2zero ? "t" : "",
9375 nameXMMReg(eregOfRexRM(pfx,modrm)),
9376 nameIReg(sz, gregOfRexRM(pfx,modrm), False));
9377 } else {
sewardj2e28ac42008-12-04 00:05:12 +00009378 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj82c9f2f2005-03-02 16:05:13 +00009379 assign(f32lo, loadLE(Ity_F32, mkexpr(addr)));
9380 delta += 2+alen;
9381 DIP("cvt%sss2si %s,%s\n", r2zero ? "t" : "",
9382 dis_buf,
9383 nameIReg(sz, gregOfRexRM(pfx,modrm), False));
9384 }
9385
9386 if (r2zero) {
9387 assign( rmode, mkU32((UInt)Irrm_ZERO) );
9388 } else {
9389 assign( rmode, get_sse_roundingmode() );
9390 }
9391
9392 if (sz == 4) {
9393 putIReg32( gregOfRexRM(pfx,modrm),
sewardj6c299f32009-12-31 18:00:12 +00009394 binop( Iop_F64toI32S,
sewardj82c9f2f2005-03-02 16:05:13 +00009395 mkexpr(rmode),
9396 unop(Iop_F32toF64, mkexpr(f32lo))) );
9397 } else {
9398 putIReg64( gregOfRexRM(pfx,modrm),
sewardj6c299f32009-12-31 18:00:12 +00009399 binop( Iop_F64toI64S,
sewardj82c9f2f2005-03-02 16:05:13 +00009400 mkexpr(rmode),
9401 unop(Iop_F32toF64, mkexpr(f32lo))) );
9402 }
9403
9404 goto decode_success;
9405 }
9406
sewardj432f8b62005-05-10 02:50:05 +00009407 /* 0F 5E = DIVPS -- div 32Fx4 from R/M to R */
9408 if (haveNo66noF2noF3(pfx) && sz == 4
9409 && insn[0] == 0x0F && insn[1] == 0x5E) {
sewardj2e28ac42008-12-04 00:05:12 +00009410 delta = dis_SSE_E_to_G_all( vbi, pfx, delta+2, "divps", Iop_Div32Fx4 );
sewardj432f8b62005-05-10 02:50:05 +00009411 goto decode_success;
9412 }
sewardjc49ce232005-02-25 13:03:03 +00009413
9414 /* F3 0F 5E = DIVSS -- div 32F0x4 from R/M to R */
9415 if (haveF3no66noF2(pfx) && sz == 4
9416 && insn[0] == 0x0F && insn[1] == 0x5E) {
sewardj2e28ac42008-12-04 00:05:12 +00009417 delta = dis_SSE_E_to_G_lo32( vbi, pfx, delta+2, "divss", Iop_Div32F0x4 );
sewardjc49ce232005-02-25 13:03:03 +00009418 goto decode_success;
9419 }
9420
sewardjbcbb9de2005-03-27 02:22:32 +00009421 /* 0F AE /2 = LDMXCSR m32 -- load %mxcsr */
9422 if (insn[0] == 0x0F && insn[1] == 0xAE
9423 && haveNo66noF2noF3(pfx)
9424 && !epartIsReg(insn[2]) && gregLO3ofRM(insn[2]) == 2) {
9425
9426 IRTemp t64 = newTemp(Ity_I64);
9427 IRTemp ew = newTemp(Ity_I32);
9428
9429 vassert(sz == 4);
sewardj2e28ac42008-12-04 00:05:12 +00009430 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardjbcbb9de2005-03-27 02:22:32 +00009431 delta += 2+alen;
9432 DIP("ldmxcsr %s\n", dis_buf);
9433
9434 /* The only thing we observe in %mxcsr is the rounding mode.
9435 Therefore, pass the 32-bit value (SSE native-format control
9436 word) to a clean helper, getting back a 64-bit value, the
9437 lower half of which is the SSEROUND value to store, and the
9438 upper half of which is the emulation-warning token which may
9439 be generated.
9440 */
9441 /* ULong amd64h_check_ldmxcsr ( ULong ); */
9442 assign( t64, mkIRExprCCall(
9443 Ity_I64, 0/*regparms*/,
9444 "amd64g_check_ldmxcsr",
9445 &amd64g_check_ldmxcsr,
9446 mkIRExprVec_1(
9447 unop(Iop_32Uto64,
9448 loadLE(Ity_I32, mkexpr(addr))
9449 )
9450 )
9451 )
9452 );
9453
9454 put_sse_roundingmode( unop(Iop_64to32, mkexpr(t64)) );
9455 assign( ew, unop(Iop_64HIto32, mkexpr(t64) ) );
9456 put_emwarn( mkexpr(ew) );
9457 /* Finally, if an emulation warning was reported, side-exit to
9458 the next insn, reporting the warning, so that Valgrind's
9459 dispatcher sees the warning. */
9460 stmt(
9461 IRStmt_Exit(
9462 binop(Iop_CmpNE64, unop(Iop_32Uto64,mkexpr(ew)), mkU64(0)),
9463 Ijk_EmWarn,
sewardj9e6491a2005-07-02 19:24:10 +00009464 IRConst_U64(guest_RIP_bbstart+delta)
sewardjbcbb9de2005-03-27 02:22:32 +00009465 )
9466 );
9467 goto decode_success;
9468 }
9469
sewardj02f79f12007-09-01 18:59:53 +00009470 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9471 /* 0F F7 = MASKMOVQ -- 8x8 masked store */
9472 if (haveNo66noF2noF3(pfx) && sz == 4
9473 && insn[0] == 0x0F && insn[1] == 0xF7) {
9474 Bool ok = False;
sewardj2e28ac42008-12-04 00:05:12 +00009475 delta = dis_MMX( &ok, vbi, pfx, sz, delta+1 );
sewardj02f79f12007-09-01 18:59:53 +00009476 if (!ok)
9477 goto decode_failure;
9478 goto decode_success;
9479 }
9480
sewardj432f8b62005-05-10 02:50:05 +00009481 /* 0F 5F = MAXPS -- max 32Fx4 from R/M to R */
9482 if (haveNo66noF2noF3(pfx) && sz == 4
9483 && insn[0] == 0x0F && insn[1] == 0x5F) {
sewardj2e28ac42008-12-04 00:05:12 +00009484 delta = dis_SSE_E_to_G_all( vbi, pfx, delta+2, "maxps", Iop_Max32Fx4 );
sewardj432f8b62005-05-10 02:50:05 +00009485 goto decode_success;
9486 }
sewardj37d52572005-02-25 14:22:12 +00009487
9488 /* F3 0F 5F = MAXSS -- max 32F0x4 from R/M to R */
9489 if (haveF3no66noF2(pfx) && sz == 4
9490 && insn[0] == 0x0F && insn[1] == 0x5F) {
sewardj2e28ac42008-12-04 00:05:12 +00009491 delta = dis_SSE_E_to_G_lo32( vbi, pfx, delta+2, "maxss", Iop_Max32F0x4 );
sewardj37d52572005-02-25 14:22:12 +00009492 goto decode_success;
9493 }
9494
sewardj432f8b62005-05-10 02:50:05 +00009495 /* 0F 5D = MINPS -- min 32Fx4 from R/M to R */
9496 if (haveNo66noF2noF3(pfx) && sz == 4
9497 && insn[0] == 0x0F && insn[1] == 0x5D) {
sewardj2e28ac42008-12-04 00:05:12 +00009498 delta = dis_SSE_E_to_G_all( vbi, pfx, delta+2, "minps", Iop_Min32Fx4 );
sewardj432f8b62005-05-10 02:50:05 +00009499 goto decode_success;
9500 }
sewardj37d52572005-02-25 14:22:12 +00009501
9502 /* F3 0F 5D = MINSS -- min 32F0x4 from R/M to R */
9503 if (haveF3no66noF2(pfx) && sz == 4
9504 && insn[0] == 0x0F && insn[1] == 0x5D) {
sewardj2e28ac42008-12-04 00:05:12 +00009505 delta = dis_SSE_E_to_G_lo32( vbi, pfx, delta+2, "minss", Iop_Min32F0x4 );
sewardj37d52572005-02-25 14:22:12 +00009506 goto decode_success;
9507 }
sewardj8d965312005-02-25 02:48:47 +00009508
9509 /* 0F 28 = MOVAPS -- move from E (mem or xmm) to G (xmm). */
9510 /* 0F 10 = MOVUPS -- move from E (mem or xmm) to G (xmm). */
sewardjb4bf5882007-11-06 20:39:17 +00009511 if (haveNo66noF2noF3(pfx)
9512 && (sz == 4 || /* ignore redundant REX.W */ sz == 8)
sewardj8d965312005-02-25 02:48:47 +00009513 && insn[0] == 0x0F && (insn[1] == 0x28 || insn[1] == 0x10)) {
9514 modrm = getUChar(delta+2);
9515 if (epartIsReg(modrm)) {
9516 putXMMReg( gregOfRexRM(pfx,modrm),
9517 getXMMReg( eregOfRexRM(pfx,modrm) ));
9518 DIP("mov[ua]ps %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
9519 nameXMMReg(gregOfRexRM(pfx,modrm)));
9520 delta += 2+1;
9521 } else {
sewardj2e28ac42008-12-04 00:05:12 +00009522 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj8d965312005-02-25 02:48:47 +00009523 putXMMReg( gregOfRexRM(pfx,modrm),
9524 loadLE(Ity_V128, mkexpr(addr)) );
9525 DIP("mov[ua]ps %s,%s\n", dis_buf,
9526 nameXMMReg(gregOfRexRM(pfx,modrm)));
9527 delta += 2+alen;
9528 }
9529 goto decode_success;
9530 }
sewardj1001dc42005-02-21 08:25:55 +00009531
9532 /* 0F 29 = MOVAPS -- move from G (xmm) to E (mem or xmm). */
sewardj446d2672005-06-10 11:04:52 +00009533 /* 0F 11 = MOVUPS -- move from G (xmm) to E (mem or xmm). */
sewardjb4bf5882007-11-06 20:39:17 +00009534 if (haveNo66noF2noF3(pfx)
9535 && (sz == 4 || /* ignore redundant REX.W */ sz == 8)
sewardj446d2672005-06-10 11:04:52 +00009536 && insn[0] == 0x0F && (insn[1] == 0x29 || insn[1] == 0x11)) {
sewardj1001dc42005-02-21 08:25:55 +00009537 modrm = getUChar(delta+2);
9538 if (epartIsReg(modrm)) {
9539 /* fall through; awaiting test case */
9540 } else {
sewardj2e28ac42008-12-04 00:05:12 +00009541 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj1001dc42005-02-21 08:25:55 +00009542 storeLE( mkexpr(addr), getXMMReg(gregOfRexRM(pfx,modrm)) );
sewardj446d2672005-06-10 11:04:52 +00009543 DIP("mov[ua]ps %s,%s\n", nameXMMReg(gregOfRexRM(pfx,modrm)),
9544 dis_buf );
sewardj1001dc42005-02-21 08:25:55 +00009545 delta += 2+alen;
9546 goto decode_success;
9547 }
9548 }
9549
sewardj432f8b62005-05-10 02:50:05 +00009550 /* 0F 16 = MOVHPS -- move from mem to high half of XMM. */
9551 /* 0F 16 = MOVLHPS -- move from lo half to hi half of XMM. */
sewardjb4bf5882007-11-06 20:39:17 +00009552 if (haveNo66noF2noF3(pfx)
9553 && (sz == 4 || /* ignore redundant REX.W */ sz == 8)
sewardj432f8b62005-05-10 02:50:05 +00009554 && insn[0] == 0x0F && insn[1] == 0x16) {
9555 modrm = getUChar(delta+2);
9556 if (epartIsReg(modrm)) {
9557 delta += 2+1;
9558 putXMMRegLane64( gregOfRexRM(pfx,modrm), 1/*upper lane*/,
9559 getXMMRegLane64( eregOfRexRM(pfx,modrm), 0 ) );
9560 DIP("movhps %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
9561 nameXMMReg(gregOfRexRM(pfx,modrm)));
9562 } else {
sewardj2e28ac42008-12-04 00:05:12 +00009563 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj432f8b62005-05-10 02:50:05 +00009564 delta += 2+alen;
9565 putXMMRegLane64( gregOfRexRM(pfx,modrm), 1/*upper lane*/,
9566 loadLE(Ity_I64, mkexpr(addr)) );
9567 DIP("movhps %s,%s\n", dis_buf,
9568 nameXMMReg( gregOfRexRM(pfx,modrm) ));
9569 }
9570 goto decode_success;
9571 }
9572
9573 /* 0F 17 = MOVHPS -- move from high half of XMM to mem. */
sewardjb4bf5882007-11-06 20:39:17 +00009574 if (haveNo66noF2noF3(pfx)
9575 && (sz == 4 || /* ignore redundant REX.W */ sz == 8)
sewardj432f8b62005-05-10 02:50:05 +00009576 && insn[0] == 0x0F && insn[1] == 0x17) {
9577 if (!epartIsReg(insn[2])) {
9578 delta += 2;
sewardj2e28ac42008-12-04 00:05:12 +00009579 addr = disAMode ( &alen, vbi, pfx, delta, dis_buf, 0 );
sewardj432f8b62005-05-10 02:50:05 +00009580 delta += alen;
9581 storeLE( mkexpr(addr),
9582 getXMMRegLane64( gregOfRexRM(pfx,insn[2]),
9583 1/*upper lane*/ ) );
9584 DIP("movhps %s,%s\n", nameXMMReg( gregOfRexRM(pfx,insn[2]) ),
9585 dis_buf);
9586 goto decode_success;
9587 }
9588 /* else fall through */
9589 }
9590
9591 /* 0F 12 = MOVLPS -- move from mem to low half of XMM. */
9592 /* OF 12 = MOVHLPS -- from from hi half to lo half of XMM. */
sewardjb4bf5882007-11-06 20:39:17 +00009593 if (haveNo66noF2noF3(pfx)
9594 && (sz == 4 || /* ignore redundant REX.W */ sz == 8)
sewardj432f8b62005-05-10 02:50:05 +00009595 && insn[0] == 0x0F && insn[1] == 0x12) {
9596 modrm = getUChar(delta+2);
9597 if (epartIsReg(modrm)) {
9598 delta += 2+1;
9599 putXMMRegLane64( gregOfRexRM(pfx,modrm),
9600 0/*lower lane*/,
9601 getXMMRegLane64( eregOfRexRM(pfx,modrm), 1 ));
9602 DIP("movhlps %s, %s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
9603 nameXMMReg(gregOfRexRM(pfx,modrm)));
9604 } else {
sewardj2e28ac42008-12-04 00:05:12 +00009605 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj432f8b62005-05-10 02:50:05 +00009606 delta += 2+alen;
9607 putXMMRegLane64( gregOfRexRM(pfx,modrm), 0/*lower lane*/,
9608 loadLE(Ity_I64, mkexpr(addr)) );
9609 DIP("movlps %s, %s\n",
9610 dis_buf, nameXMMReg( gregOfRexRM(pfx,modrm) ));
9611 }
9612 goto decode_success;
9613 }
9614
9615 /* 0F 13 = MOVLPS -- move from low half of XMM to mem. */
sewardjb4bf5882007-11-06 20:39:17 +00009616 if (haveNo66noF2noF3(pfx)
9617 && (sz == 4 || /* ignore redundant REX.W */ sz == 8)
sewardj432f8b62005-05-10 02:50:05 +00009618 && insn[0] == 0x0F && insn[1] == 0x13) {
9619 if (!epartIsReg(insn[2])) {
9620 delta += 2;
sewardj2e28ac42008-12-04 00:05:12 +00009621 addr = disAMode ( &alen, vbi, pfx, delta, dis_buf, 0 );
sewardj432f8b62005-05-10 02:50:05 +00009622 delta += alen;
9623 storeLE( mkexpr(addr),
9624 getXMMRegLane64( gregOfRexRM(pfx,insn[2]),
9625 0/*lower lane*/ ) );
9626 DIP("movlps %s, %s\n", nameXMMReg( gregOfRexRM(pfx,insn[2]) ),
9627 dis_buf);
9628 goto decode_success;
9629 }
9630 /* else fall through */
9631 }
9632
sewardja7ba8c42005-05-10 20:08:34 +00009633 /* 0F 50 = MOVMSKPS - move 4 sign bits from 4 x F32 in xmm(E)
9634 to 4 lowest bits of ireg(G) */
sewardjae84d782006-04-13 22:06:35 +00009635 if (haveNo66noF2noF3(pfx) && (sz == 4 || sz == 8)
sewardja7ba8c42005-05-10 20:08:34 +00009636 && insn[0] == 0x0F && insn[1] == 0x50) {
sewardjae84d782006-04-13 22:06:35 +00009637 /* sz == 8 is a kludge to handle insns with REX.W redundantly
9638 set to 1, which has been known to happen:
sewardjb4bf5882007-11-06 20:39:17 +00009639
sewardjae84d782006-04-13 22:06:35 +00009640 4c 0f 50 d9 rex64X movmskps %xmm1,%r11d
sewardjb4bf5882007-11-06 20:39:17 +00009641
9642 20071106: Intel docs say that REX.W isn't redundant: when
9643 present, a 64-bit register is written; when not present, only
9644 the 32-bit half is written. However, testing on a Core2
9645 machine suggests the entire 64 bit register is written
9646 irrespective of the status of REX.W. That could be because
9647 of the default rule that says "if the lower half of a 32-bit
9648 register is written, the upper half is zeroed". By using
9649 putIReg32 here we inadvertantly produce the same behaviour as
9650 the Core2, for the same reason -- putIReg32 implements said
9651 rule.
9652
9653 AMD docs give no indication that REX.W is even valid for this
9654 insn. */
sewardja7ba8c42005-05-10 20:08:34 +00009655 modrm = getUChar(delta+2);
9656 if (epartIsReg(modrm)) {
9657 Int src;
9658 t0 = newTemp(Ity_I32);
9659 t1 = newTemp(Ity_I32);
9660 t2 = newTemp(Ity_I32);
9661 t3 = newTemp(Ity_I32);
9662 delta += 2+1;
9663 src = eregOfRexRM(pfx,modrm);
9664 assign( t0, binop( Iop_And32,
9665 binop(Iop_Shr32, getXMMRegLane32(src,0), mkU8(31)),
9666 mkU32(1) ));
9667 assign( t1, binop( Iop_And32,
9668 binop(Iop_Shr32, getXMMRegLane32(src,1), mkU8(30)),
9669 mkU32(2) ));
9670 assign( t2, binop( Iop_And32,
9671 binop(Iop_Shr32, getXMMRegLane32(src,2), mkU8(29)),
9672 mkU32(4) ));
9673 assign( t3, binop( Iop_And32,
9674 binop(Iop_Shr32, getXMMRegLane32(src,3), mkU8(28)),
9675 mkU32(8) ));
9676 putIReg32( gregOfRexRM(pfx,modrm),
9677 binop(Iop_Or32,
9678 binop(Iop_Or32, mkexpr(t0), mkexpr(t1)),
9679 binop(Iop_Or32, mkexpr(t2), mkexpr(t3))
9680 )
9681 );
9682 DIP("movmskps %s,%s\n", nameXMMReg(src),
9683 nameIReg32(gregOfRexRM(pfx,modrm)));
9684 goto decode_success;
9685 }
9686 /* else fall through */
9687 }
9688
sewardj612be432005-05-11 02:55:54 +00009689 /* 66 0F 2B = MOVNTPD -- for us, just a plain SSE store. */
sewardja7ba8c42005-05-10 20:08:34 +00009690 /* 0F 2B = MOVNTPS -- for us, just a plain SSE store. */
sewardj612be432005-05-11 02:55:54 +00009691 if ( ( (haveNo66noF2noF3(pfx) && sz == 4)
9692 || (have66noF2noF3(pfx) && sz == 2)
9693 )
9694 && insn[0] == 0x0F && insn[1] == 0x2B) {
sewardja7ba8c42005-05-10 20:08:34 +00009695 modrm = getUChar(delta+2);
9696 if (!epartIsReg(modrm)) {
sewardj2e28ac42008-12-04 00:05:12 +00009697 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardja7ba8c42005-05-10 20:08:34 +00009698 storeLE( mkexpr(addr), getXMMReg(gregOfRexRM(pfx,modrm)) );
sewardj612be432005-05-11 02:55:54 +00009699 DIP("movntp%s %s,%s\n", sz==2 ? "d" : "s",
9700 dis_buf,
9701 nameXMMReg(gregOfRexRM(pfx,modrm)));
sewardja7ba8c42005-05-10 20:08:34 +00009702 delta += 2+alen;
9703 goto decode_success;
9704 }
9705 /* else fall through */
9706 }
9707
9708 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9709 /* 0F E7 = MOVNTQ -- for us, just a plain MMX store. Note, the
9710 Intel manual does not say anything about the usual business of
9711 the FP reg tags getting trashed whenever an MMX insn happens.
9712 So we just leave them alone.
9713 */
9714 if (haveNo66noF2noF3(pfx) && sz == 4
9715 && insn[0] == 0x0F && insn[1] == 0xE7) {
9716 modrm = getUChar(delta+2);
9717 if (!epartIsReg(modrm)) {
9718 /* do_MMX_preamble(); Intel docs don't specify this */
sewardj2e28ac42008-12-04 00:05:12 +00009719 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardja7ba8c42005-05-10 20:08:34 +00009720 storeLE( mkexpr(addr), getMMXReg(gregLO3ofRM(modrm)) );
9721 DIP("movntq %s,%s\n", dis_buf,
9722 nameMMXReg(gregLO3ofRM(modrm)));
9723 delta += 2+alen;
9724 goto decode_success;
9725 }
9726 /* else fall through */
9727 }
sewardj8d965312005-02-25 02:48:47 +00009728
9729 /* F3 0F 10 = MOVSS -- move 32 bits from E (mem or lo 1/4 xmm) to G
9730 (lo 1/4 xmm). If E is mem, upper 3/4 of G is zeroed out. */
sewardjb4bf5882007-11-06 20:39:17 +00009731 if (haveF3no66noF2(pfx)
sewardj7bdd1bc2008-12-13 16:49:46 +00009732 && (sz == 4 || /* ignore redundant REX.W */ sz == 8)
sewardj8d965312005-02-25 02:48:47 +00009733 && insn[0] == 0x0F && insn[1] == 0x10) {
9734 modrm = getUChar(delta+2);
9735 if (epartIsReg(modrm)) {
9736 putXMMRegLane32( gregOfRexRM(pfx,modrm), 0,
9737 getXMMRegLane32( eregOfRexRM(pfx,modrm), 0 ));
9738 DIP("movss %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
9739 nameXMMReg(gregOfRexRM(pfx,modrm)));
9740 delta += 2+1;
9741 } else {
sewardj2e28ac42008-12-04 00:05:12 +00009742 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj8d965312005-02-25 02:48:47 +00009743 putXMMReg( gregOfRexRM(pfx,modrm), mkV128(0) );
9744 putXMMRegLane32( gregOfRexRM(pfx,modrm), 0,
9745 loadLE(Ity_I32, mkexpr(addr)) );
9746 DIP("movss %s,%s\n", dis_buf,
9747 nameXMMReg(gregOfRexRM(pfx,modrm)));
9748 delta += 2+alen;
9749 }
9750 goto decode_success;
9751 }
9752
9753 /* F3 0F 11 = MOVSS -- move 32 bits from G (lo 1/4 xmm) to E (mem
9754 or lo 1/4 xmm). */
9755 if (haveF3no66noF2(pfx) && sz == 4
9756 && insn[0] == 0x0F && insn[1] == 0x11) {
9757 modrm = getUChar(delta+2);
9758 if (epartIsReg(modrm)) {
9759 /* fall through, we don't yet have a test case */
9760 } else {
sewardj2e28ac42008-12-04 00:05:12 +00009761 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj8d965312005-02-25 02:48:47 +00009762 storeLE( mkexpr(addr),
9763 getXMMRegLane32(gregOfRexRM(pfx,modrm), 0) );
9764 DIP("movss %s,%s\n", nameXMMReg(gregOfRexRM(pfx,modrm)),
9765 dis_buf);
9766 delta += 2+alen;
9767 goto decode_success;
9768 }
9769 }
9770
sewardj432f8b62005-05-10 02:50:05 +00009771 /* 0F 59 = MULPS -- mul 32Fx4 from R/M to R */
9772 if (haveNo66noF2noF3(pfx) && sz == 4
9773 && insn[0] == 0x0F && insn[1] == 0x59) {
sewardj2e28ac42008-12-04 00:05:12 +00009774 delta = dis_SSE_E_to_G_all( vbi, pfx, delta+2, "mulps", Iop_Mul32Fx4 );
sewardj432f8b62005-05-10 02:50:05 +00009775 goto decode_success;
9776 }
sewardj8d965312005-02-25 02:48:47 +00009777
9778 /* F3 0F 59 = MULSS -- mul 32F0x4 from R/M to R */
9779 if (haveF3no66noF2(pfx) && sz == 4
9780 && insn[0] == 0x0F && insn[1] == 0x59) {
sewardj2e28ac42008-12-04 00:05:12 +00009781 delta = dis_SSE_E_to_G_lo32( vbi, pfx, delta+2, "mulss", Iop_Mul32F0x4 );
sewardj8d965312005-02-25 02:48:47 +00009782 goto decode_success;
9783 }
9784
sewardj3aba9eb2005-03-30 23:20:47 +00009785 /* 0F 56 = ORPS -- G = G and E */
9786 if (haveNo66noF2noF3(pfx) && sz == 4
9787 && insn[0] == 0x0F && insn[1] == 0x56) {
sewardj2e28ac42008-12-04 00:05:12 +00009788 delta = dis_SSE_E_to_G_all( vbi, pfx, delta+2, "orps", Iop_OrV128 );
sewardj3aba9eb2005-03-30 23:20:47 +00009789 goto decode_success;
9790 }
9791
sewardja7ba8c42005-05-10 20:08:34 +00009792 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9793 /* 0F E0 = PAVGB -- 8x8 unsigned Packed Average, with rounding */
9794 if (haveNo66noF2noF3(pfx) && sz == 4
9795 && insn[0] == 0x0F && insn[1] == 0xE0) {
9796 do_MMX_preamble();
9797 delta = dis_MMXop_regmem_to_reg (
sewardj2e28ac42008-12-04 00:05:12 +00009798 vbi, pfx, delta+2, insn[1], "pavgb", False );
sewardja7ba8c42005-05-10 20:08:34 +00009799 goto decode_success;
9800 }
9801
9802 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9803 /* 0F E3 = PAVGW -- 16x4 unsigned Packed Average, with rounding */
9804 if (haveNo66noF2noF3(pfx) && sz == 4
9805 && insn[0] == 0x0F && insn[1] == 0xE3) {
9806 do_MMX_preamble();
9807 delta = dis_MMXop_regmem_to_reg (
sewardj2e28ac42008-12-04 00:05:12 +00009808 vbi, pfx, delta+2, insn[1], "pavgw", False );
sewardja7ba8c42005-05-10 20:08:34 +00009809 goto decode_success;
9810 }
9811
9812 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9813 /* 0F C5 = PEXTRW -- extract 16-bit field from mmx(E) and put
9814 zero-extend of it in ireg(G). */
sewardj9e234f62006-09-11 14:37:27 +00009815 if (haveNo66noF2noF3(pfx) && (sz == 4 || sz == 8)
sewardja7ba8c42005-05-10 20:08:34 +00009816 && insn[0] == 0x0F && insn[1] == 0xC5) {
9817 modrm = insn[2];
9818 if (epartIsReg(modrm)) {
9819 IRTemp sV = newTemp(Ity_I64);
9820 t5 = newTemp(Ity_I16);
9821 do_MMX_preamble();
9822 assign(sV, getMMXReg(eregLO3ofRM(modrm)));
9823 breakup64to16s( sV, &t3, &t2, &t1, &t0 );
9824 switch (insn[3] & 3) {
9825 case 0: assign(t5, mkexpr(t0)); break;
9826 case 1: assign(t5, mkexpr(t1)); break;
9827 case 2: assign(t5, mkexpr(t2)); break;
9828 case 3: assign(t5, mkexpr(t3)); break;
9829 default: vassert(0);
9830 }
sewardj9e234f62006-09-11 14:37:27 +00009831 if (sz == 8)
9832 putIReg64(gregOfRexRM(pfx,modrm), unop(Iop_16Uto64, mkexpr(t5)));
9833 else
9834 putIReg32(gregOfRexRM(pfx,modrm), unop(Iop_16Uto32, mkexpr(t5)));
sewardja7ba8c42005-05-10 20:08:34 +00009835 DIP("pextrw $%d,%s,%s\n",
9836 (Int)insn[3], nameMMXReg(eregLO3ofRM(modrm)),
sewardj9e234f62006-09-11 14:37:27 +00009837 sz==8 ? nameIReg64(gregOfRexRM(pfx,modrm))
9838 : nameIReg32(gregOfRexRM(pfx,modrm))
9839 );
sewardja7ba8c42005-05-10 20:08:34 +00009840 delta += 4;
9841 goto decode_success;
9842 }
9843 /* else fall through */
9844 /* note, for anyone filling in the mem case: this insn has one
9845 byte after the amode and therefore you must pass 1 as the
9846 last arg to disAMode */
9847 }
9848
9849 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9850 /* 0F C4 = PINSRW -- get 16 bits from E(mem or low half ireg) and
9851 put it into the specified lane of mmx(G). */
9852 if (haveNo66noF2noF3(pfx) && sz == 4
9853 && insn[0] == 0x0F && insn[1] == 0xC4) {
9854 /* Use t0 .. t3 to hold the 4 original 16-bit lanes of the
9855 mmx reg. t4 is the new lane value. t5 is the original
9856 mmx value. t6 is the new mmx value. */
9857 Int lane;
9858 t4 = newTemp(Ity_I16);
9859 t5 = newTemp(Ity_I64);
9860 t6 = newTemp(Ity_I64);
9861 modrm = insn[2];
9862 do_MMX_preamble();
9863
9864 assign(t5, getMMXReg(gregLO3ofRM(modrm)));
9865 breakup64to16s( t5, &t3, &t2, &t1, &t0 );
9866
9867 if (epartIsReg(modrm)) {
9868 assign(t4, getIReg16(eregOfRexRM(pfx,modrm)));
9869 delta += 3+1;
9870 lane = insn[3+1-1];
9871 DIP("pinsrw $%d,%s,%s\n", (Int)lane,
9872 nameIReg16(eregOfRexRM(pfx,modrm)),
9873 nameMMXReg(gregLO3ofRM(modrm)));
9874 } else {
sewardj2e28ac42008-12-04 00:05:12 +00009875 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 1 );
sewardja7ba8c42005-05-10 20:08:34 +00009876 delta += 3+alen;
9877 lane = insn[3+alen-1];
9878 assign(t4, loadLE(Ity_I16, mkexpr(addr)));
9879 DIP("pinsrw $%d,%s,%s\n", (Int)lane,
9880 dis_buf,
9881 nameMMXReg(gregLO3ofRM(modrm)));
9882 }
9883
9884 switch (lane & 3) {
9885 case 0: assign(t6, mk64from16s(t3,t2,t1,t4)); break;
9886 case 1: assign(t6, mk64from16s(t3,t2,t4,t0)); break;
9887 case 2: assign(t6, mk64from16s(t3,t4,t1,t0)); break;
9888 case 3: assign(t6, mk64from16s(t4,t2,t1,t0)); break;
9889 default: vassert(0);
9890 }
9891 putMMXReg(gregLO3ofRM(modrm), mkexpr(t6));
9892 goto decode_success;
9893 }
9894
9895 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9896 /* 0F EE = PMAXSW -- 16x4 signed max */
9897 if (haveNo66noF2noF3(pfx) && sz == 4
9898 && insn[0] == 0x0F && insn[1] == 0xEE) {
9899 do_MMX_preamble();
9900 delta = dis_MMXop_regmem_to_reg (
sewardj2e28ac42008-12-04 00:05:12 +00009901 vbi, pfx, delta+2, insn[1], "pmaxsw", False );
sewardja7ba8c42005-05-10 20:08:34 +00009902 goto decode_success;
9903 }
9904
9905 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9906 /* 0F DE = PMAXUB -- 8x8 unsigned max */
9907 if (haveNo66noF2noF3(pfx) && sz == 4
9908 && insn[0] == 0x0F && insn[1] == 0xDE) {
9909 do_MMX_preamble();
9910 delta = dis_MMXop_regmem_to_reg (
sewardj2e28ac42008-12-04 00:05:12 +00009911 vbi, pfx, delta+2, insn[1], "pmaxub", False );
sewardja7ba8c42005-05-10 20:08:34 +00009912 goto decode_success;
9913 }
9914
9915 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9916 /* 0F EA = PMINSW -- 16x4 signed min */
9917 if (haveNo66noF2noF3(pfx) && sz == 4
9918 && insn[0] == 0x0F && insn[1] == 0xEA) {
9919 do_MMX_preamble();
9920 delta = dis_MMXop_regmem_to_reg (
sewardj2e28ac42008-12-04 00:05:12 +00009921 vbi, pfx, delta+2, insn[1], "pminsw", False );
sewardja7ba8c42005-05-10 20:08:34 +00009922 goto decode_success;
9923 }
9924
9925 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9926 /* 0F DA = PMINUB -- 8x8 unsigned min */
9927 if (haveNo66noF2noF3(pfx) && sz == 4
9928 && insn[0] == 0x0F && insn[1] == 0xDA) {
9929 do_MMX_preamble();
9930 delta = dis_MMXop_regmem_to_reg (
sewardj2e28ac42008-12-04 00:05:12 +00009931 vbi, pfx, delta+2, insn[1], "pminub", False );
sewardja7ba8c42005-05-10 20:08:34 +00009932 goto decode_success;
9933 }
9934
9935 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9936 /* 0F D7 = PMOVMSKB -- extract sign bits from each of 8 lanes in
9937 mmx(G), turn them into a byte, and put zero-extend of it in
9938 ireg(G). */
9939 if (haveNo66noF2noF3(pfx) && sz == 4
9940 && insn[0] == 0x0F && insn[1] == 0xD7) {
9941 modrm = insn[2];
9942 if (epartIsReg(modrm)) {
9943 do_MMX_preamble();
9944 t0 = newTemp(Ity_I64);
9945 t1 = newTemp(Ity_I64);
9946 assign(t0, getMMXReg(eregLO3ofRM(modrm)));
9947 assign(t1, mkIRExprCCall(
9948 Ity_I64, 0/*regparms*/,
9949 "amd64g_calculate_mmx_pmovmskb",
9950 &amd64g_calculate_mmx_pmovmskb,
9951 mkIRExprVec_1(mkexpr(t0))));
9952 putIReg32(gregOfRexRM(pfx,modrm), unop(Iop_64to32,mkexpr(t1)));
9953 DIP("pmovmskb %s,%s\n", nameMMXReg(eregLO3ofRM(modrm)),
9954 nameIReg32(gregOfRexRM(pfx,modrm)));
9955 delta += 3;
9956 goto decode_success;
9957 }
9958 /* else fall through */
9959 }
9960
9961 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9962 /* 0F E4 = PMULUH -- 16x4 hi-half of unsigned widening multiply */
9963 if (haveNo66noF2noF3(pfx) && sz == 4
9964 && insn[0] == 0x0F && insn[1] == 0xE4) {
9965 do_MMX_preamble();
9966 delta = dis_MMXop_regmem_to_reg (
sewardj2e28ac42008-12-04 00:05:12 +00009967 vbi, pfx, delta+2, insn[1], "pmuluh", False );
sewardja7ba8c42005-05-10 20:08:34 +00009968 goto decode_success;
9969 }
sewardja6b93d12005-02-17 09:28:28 +00009970
9971 /* 0F 18 /0 = PREFETCHNTA -- prefetch into caches, */
9972 /* 0F 18 /1 = PREFETCH0 -- with various different hints */
9973 /* 0F 18 /2 = PREFETCH1 */
9974 /* 0F 18 /3 = PREFETCH2 */
9975 if (insn[0] == 0x0F && insn[1] == 0x18
sewardjbcbb9de2005-03-27 02:22:32 +00009976 && haveNo66noF2noF3(pfx)
sewardja6b93d12005-02-17 09:28:28 +00009977 && !epartIsReg(insn[2])
sewardj901ed122005-02-27 13:25:31 +00009978 && gregLO3ofRM(insn[2]) >= 0 && gregLO3ofRM(insn[2]) <= 3) {
sewardja6b93d12005-02-17 09:28:28 +00009979 HChar* hintstr = "??";
9980
9981 modrm = getUChar(delta+2);
9982 vassert(!epartIsReg(modrm));
9983
sewardj2e28ac42008-12-04 00:05:12 +00009984 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardja6b93d12005-02-17 09:28:28 +00009985 delta += 2+alen;
9986
sewardj901ed122005-02-27 13:25:31 +00009987 switch (gregLO3ofRM(modrm)) {
sewardja6b93d12005-02-17 09:28:28 +00009988 case 0: hintstr = "nta"; break;
9989 case 1: hintstr = "t0"; break;
9990 case 2: hintstr = "t1"; break;
9991 case 3: hintstr = "t2"; break;
9992 default: vassert(0);
9993 }
9994
9995 DIP("prefetch%s %s\n", hintstr, dis_buf);
9996 goto decode_success;
9997 }
9998
sewardja7ba8c42005-05-10 20:08:34 +00009999 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
10000 /* 0F F6 = PSADBW -- sum of 8Ux8 absolute differences */
10001 if (haveNo66noF2noF3(pfx) && sz == 4
10002 && insn[0] == 0x0F && insn[1] == 0xF6) {
10003 do_MMX_preamble();
10004 delta = dis_MMXop_regmem_to_reg (
sewardj2e28ac42008-12-04 00:05:12 +000010005 vbi, pfx, delta+2, insn[1], "psadbw", False );
sewardja7ba8c42005-05-10 20:08:34 +000010006 goto decode_success;
10007 }
10008
10009 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
10010 /* 0F 70 = PSHUFW -- rearrange 4x16 from E(mmx or mem) to G(mmx) */
10011 if (haveNo66noF2noF3(pfx) && sz == 4
10012 && insn[0] == 0x0F && insn[1] == 0x70) {
10013 Int order;
10014 IRTemp sV, dV, s3, s2, s1, s0;
10015 s3 = s2 = s1 = s0 = IRTemp_INVALID;
10016 sV = newTemp(Ity_I64);
10017 dV = newTemp(Ity_I64);
10018 do_MMX_preamble();
10019 modrm = insn[2];
10020 if (epartIsReg(modrm)) {
10021 assign( sV, getMMXReg(eregLO3ofRM(modrm)) );
10022 order = (Int)insn[3];
10023 delta += 2+2;
10024 DIP("pshufw $%d,%s,%s\n", order,
10025 nameMMXReg(eregLO3ofRM(modrm)),
10026 nameMMXReg(gregLO3ofRM(modrm)));
10027 } else {
sewardj2e28ac42008-12-04 00:05:12 +000010028 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf,
sewardja7ba8c42005-05-10 20:08:34 +000010029 1/*extra byte after amode*/ );
10030 assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
10031 order = (Int)insn[2+alen];
10032 delta += 3+alen;
10033 DIP("pshufw $%d,%s,%s\n", order,
10034 dis_buf,
10035 nameMMXReg(gregLO3ofRM(modrm)));
10036 }
10037 breakup64to16s( sV, &s3, &s2, &s1, &s0 );
10038# define SEL(n) \
10039 ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
10040 assign(dV,
10041 mk64from16s( SEL((order>>6)&3), SEL((order>>4)&3),
10042 SEL((order>>2)&3), SEL((order>>0)&3) )
10043 );
10044 putMMXReg(gregLO3ofRM(modrm), mkexpr(dV));
10045# undef SEL
10046 goto decode_success;
10047 }
10048
10049 /* 0F 53 = RCPPS -- approx reciprocal 32Fx4 from R/M to R */
10050 if (haveNo66noF2noF3(pfx) && sz == 4
10051 && insn[0] == 0x0F && insn[1] == 0x53) {
sewardj2e28ac42008-12-04 00:05:12 +000010052 delta = dis_SSE_E_to_G_unary_all( vbi, pfx, delta+2,
sewardja7ba8c42005-05-10 20:08:34 +000010053 "rcpps", Iop_Recip32Fx4 );
10054 goto decode_success;
10055 }
10056
10057 /* F3 0F 53 = RCPSS -- approx reciprocal 32F0x4 from R/M to R */
10058 if (haveF3no66noF2(pfx) && sz == 4
10059 && insn[0] == 0x0F && insn[1] == 0x53) {
sewardj2e28ac42008-12-04 00:05:12 +000010060 delta = dis_SSE_E_to_G_unary_lo32( vbi, pfx, delta+2,
sewardja7ba8c42005-05-10 20:08:34 +000010061 "rcpss", Iop_Recip32F0x4 );
10062 goto decode_success;
10063 }
10064
10065 /* 0F 52 = RSQRTPS -- approx reciprocal sqrt 32Fx4 from R/M to R */
10066 if (haveNo66noF2noF3(pfx) && sz == 4
10067 && insn[0] == 0x0F && insn[1] == 0x52) {
sewardj2e28ac42008-12-04 00:05:12 +000010068 delta = dis_SSE_E_to_G_unary_all( vbi, pfx, delta+2,
sewardja7ba8c42005-05-10 20:08:34 +000010069 "rsqrtps", Iop_RSqrt32Fx4 );
10070 goto decode_success;
10071 }
10072
10073 /* F3 0F 52 = RSQRTSS -- approx reciprocal sqrt 32F0x4 from R/M to R */
10074 if (haveF3no66noF2(pfx) && sz == 4
10075 && insn[0] == 0x0F && insn[1] == 0x52) {
sewardj2e28ac42008-12-04 00:05:12 +000010076 delta = dis_SSE_E_to_G_unary_lo32( vbi, pfx, delta+2,
sewardja7ba8c42005-05-10 20:08:34 +000010077 "rsqrtss", Iop_RSqrt32F0x4 );
10078 goto decode_success;
10079 }
sewardjf53b7352005-04-06 20:01:56 +000010080
10081 /* 0F AE /7 = SFENCE -- flush pending operations to memory */
10082 if (haveNo66noF2noF3(pfx)
10083 && insn[0] == 0x0F && insn[1] == 0xAE
10084 && epartIsReg(insn[2]) && gregLO3ofRM(insn[2]) == 7
10085 && sz == 4) {
10086 delta += 3;
10087 /* Insert a memory fence. It's sometimes important that these
10088 are carried through to the generated code. */
sewardjc4356f02007-11-09 21:15:04 +000010089 stmt( IRStmt_MBE(Imbe_Fence) );
sewardjf53b7352005-04-06 20:01:56 +000010090 DIP("sfence\n");
10091 goto decode_success;
10092 }
10093
sewardja7ba8c42005-05-10 20:08:34 +000010094 /* 0F C6 /r ib = SHUFPS -- shuffle packed F32s */
10095 if (haveNo66noF2noF3(pfx) && sz == 4
10096 && insn[0] == 0x0F && insn[1] == 0xC6) {
10097 Int select;
10098 IRTemp sV, dV;
10099 IRTemp s3, s2, s1, s0, d3, d2, d1, d0;
10100 sV = newTemp(Ity_V128);
10101 dV = newTemp(Ity_V128);
10102 s3 = s2 = s1 = s0 = d3 = d2 = d1 = d0 = IRTemp_INVALID;
10103 modrm = insn[2];
10104 assign( dV, getXMMReg(gregOfRexRM(pfx,modrm)) );
10105
10106 if (epartIsReg(modrm)) {
10107 assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
10108 select = (Int)insn[3];
10109 delta += 2+2;
10110 DIP("shufps $%d,%s,%s\n", select,
10111 nameXMMReg(eregOfRexRM(pfx,modrm)),
10112 nameXMMReg(gregOfRexRM(pfx,modrm)));
10113 } else {
sewardj2e28ac42008-12-04 00:05:12 +000010114 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf,
sewardja7ba8c42005-05-10 20:08:34 +000010115 1/*byte at end of insn*/ );
10116 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
10117 select = (Int)insn[2+alen];
10118 delta += 3+alen;
10119 DIP("shufps $%d,%s,%s\n", select,
10120 dis_buf,
10121 nameXMMReg(gregOfRexRM(pfx,modrm)));
10122 }
10123
10124 breakup128to32s( dV, &d3, &d2, &d1, &d0 );
10125 breakup128to32s( sV, &s3, &s2, &s1, &s0 );
10126
10127# define SELD(n) ((n)==0 ? d0 : ((n)==1 ? d1 : ((n)==2 ? d2 : d3)))
10128# define SELS(n) ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
10129
10130 putXMMReg(
10131 gregOfRexRM(pfx,modrm),
10132 mk128from32s( SELS((select>>6)&3), SELS((select>>4)&3),
10133 SELD((select>>2)&3), SELD((select>>0)&3) )
10134 );
10135
10136# undef SELD
10137# undef SELS
10138
10139 goto decode_success;
10140 }
10141
10142 /* 0F 51 = SQRTPS -- approx sqrt 32Fx4 from R/M to R */
10143 if (haveNo66noF2noF3(pfx) && sz == 4
10144 && insn[0] == 0x0F && insn[1] == 0x51) {
sewardj2e28ac42008-12-04 00:05:12 +000010145 delta = dis_SSE_E_to_G_unary_all( vbi, pfx, delta+2,
sewardja7ba8c42005-05-10 20:08:34 +000010146 "sqrtps", Iop_Sqrt32Fx4 );
10147 goto decode_success;
10148 }
10149
10150 /* F3 0F 51 = SQRTSS -- approx sqrt 32F0x4 from R/M to R */
10151 if (haveF3no66noF2(pfx) && sz == 4
10152 && insn[0] == 0x0F && insn[1] == 0x51) {
sewardj2e28ac42008-12-04 00:05:12 +000010153 delta = dis_SSE_E_to_G_unary_lo32( vbi, pfx, delta+2,
sewardja7ba8c42005-05-10 20:08:34 +000010154 "sqrtss", Iop_Sqrt32F0x4 );
10155 goto decode_success;
10156 }
sewardjbcbb9de2005-03-27 02:22:32 +000010157
10158 /* 0F AE /3 = STMXCSR m32 -- store %mxcsr */
10159 if (insn[0] == 0x0F && insn[1] == 0xAE
10160 && haveNo66noF2noF3(pfx)
10161 && !epartIsReg(insn[2]) && gregLO3ofRM(insn[2]) == 3) {
10162
10163 vassert(sz == 4);
sewardj2e28ac42008-12-04 00:05:12 +000010164 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardjbcbb9de2005-03-27 02:22:32 +000010165 delta += 2+alen;
10166
10167 /* Fake up a native SSE mxcsr word. The only thing it depends
10168 on is SSEROUND[1:0], so call a clean helper to cook it up.
10169 */
10170 /* ULong amd64h_create_mxcsr ( ULong sseround ) */
10171 DIP("stmxcsr %s\n", dis_buf);
10172 storeLE(
10173 mkexpr(addr),
10174 unop(Iop_64to32,
10175 mkIRExprCCall(
10176 Ity_I64, 0/*regp*/,
10177 "amd64g_create_mxcsr", &amd64g_create_mxcsr,
10178 mkIRExprVec_1( unop(Iop_32Uto64,get_sse_roundingmode()) )
10179 )
10180 )
10181 );
10182 goto decode_success;
10183 }
10184
sewardj432f8b62005-05-10 02:50:05 +000010185 /* 0F 5C = SUBPS -- sub 32Fx4 from R/M to R */
10186 if (haveNo66noF2noF3(pfx) && sz == 4
10187 && insn[0] == 0x0F && insn[1] == 0x5C) {
sewardj2e28ac42008-12-04 00:05:12 +000010188 delta = dis_SSE_E_to_G_all( vbi, pfx, delta+2, "subps", Iop_Sub32Fx4 );
sewardj432f8b62005-05-10 02:50:05 +000010189 goto decode_success;
10190 }
sewardj8d965312005-02-25 02:48:47 +000010191
10192 /* F3 0F 5C = SUBSS -- sub 32F0x4 from R/M to R */
10193 if (haveF3no66noF2(pfx) && sz == 4
10194 && insn[0] == 0x0F && insn[1] == 0x5C) {
sewardj2e28ac42008-12-04 00:05:12 +000010195 delta = dis_SSE_E_to_G_lo32( vbi, pfx, delta+2, "subss", Iop_Sub32F0x4 );
sewardj8d965312005-02-25 02:48:47 +000010196 goto decode_success;
10197 }
10198
sewardja7ba8c42005-05-10 20:08:34 +000010199 /* 0F 15 = UNPCKHPS -- unpack and interleave high part F32s */
10200 /* 0F 14 = UNPCKLPS -- unpack and interleave low part F32s */
10201 /* These just appear to be special cases of SHUFPS */
10202 if (haveNo66noF2noF3(pfx) && sz == 4
10203 && insn[0] == 0x0F && (insn[1] == 0x15 || insn[1] == 0x14)) {
10204 IRTemp sV, dV;
10205 IRTemp s3, s2, s1, s0, d3, d2, d1, d0;
sewardjca673ab2005-05-11 10:03:08 +000010206 Bool hi = toBool(insn[1] == 0x15);
sewardja7ba8c42005-05-10 20:08:34 +000010207 sV = newTemp(Ity_V128);
10208 dV = newTemp(Ity_V128);
10209 s3 = s2 = s1 = s0 = d3 = d2 = d1 = d0 = IRTemp_INVALID;
10210 modrm = insn[2];
10211 assign( dV, getXMMReg(gregOfRexRM(pfx,modrm)) );
10212
10213 if (epartIsReg(modrm)) {
10214 assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
10215 delta += 2+1;
10216 DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
10217 nameXMMReg(eregOfRexRM(pfx,modrm)),
10218 nameXMMReg(gregOfRexRM(pfx,modrm)));
10219 } else {
sewardj2e28ac42008-12-04 00:05:12 +000010220 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardja7ba8c42005-05-10 20:08:34 +000010221 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
10222 delta += 2+alen;
10223 DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
10224 dis_buf,
10225 nameXMMReg(gregOfRexRM(pfx,modrm)));
10226 }
10227
10228 breakup128to32s( dV, &d3, &d2, &d1, &d0 );
10229 breakup128to32s( sV, &s3, &s2, &s1, &s0 );
10230
10231 if (hi) {
10232 putXMMReg( gregOfRexRM(pfx,modrm), mk128from32s( s3, d3, s2, d2 ) );
10233 } else {
10234 putXMMReg( gregOfRexRM(pfx,modrm), mk128from32s( s1, d1, s0, d0 ) );
10235 }
10236
10237 goto decode_success;
10238 }
sewardj8d965312005-02-25 02:48:47 +000010239
10240 /* 0F 57 = XORPS -- G = G and E */
10241 if (haveNo66noF2noF3(pfx) && sz == 4
10242 && insn[0] == 0x0F && insn[1] == 0x57) {
sewardj2e28ac42008-12-04 00:05:12 +000010243 delta = dis_SSE_E_to_G_all( vbi, pfx, delta+2, "xorps", Iop_XorV128 );
sewardj8d965312005-02-25 02:48:47 +000010244 goto decode_success;
10245 }
10246
sewardj5992bd02005-05-11 02:13:42 +000010247 /* ---------------------------------------------------- */
10248 /* --- end of the SSE decoder. --- */
10249 /* ---------------------------------------------------- */
10250
10251 /* ---------------------------------------------------- */
10252 /* --- start of the SSE2 decoder. --- */
10253 /* ---------------------------------------------------- */
sewardj4c328cf2005-05-05 12:05:54 +000010254
10255 /* 66 0F 58 = ADDPD -- add 32Fx4 from R/M to R */
sewardjb4bf5882007-11-06 20:39:17 +000010256 if (have66noF2noF3(pfx)
10257 && (sz == 2 || /* ignore redundant REX.W */ sz == 8)
sewardj4c328cf2005-05-05 12:05:54 +000010258 && insn[0] == 0x0F && insn[1] == 0x58) {
sewardj2e28ac42008-12-04 00:05:12 +000010259 delta = dis_SSE_E_to_G_all( vbi, pfx, delta+2, "addpd", Iop_Add64Fx2 );
sewardj4c328cf2005-05-05 12:05:54 +000010260 goto decode_success;
10261 }
sewardj1001dc42005-02-21 08:25:55 +000010262
10263 /* F2 0F 58 = ADDSD -- add 64F0x2 from R/M to R */
sewardjb4bf5882007-11-06 20:39:17 +000010264 if (haveF2no66noF3(pfx)
10265 && (sz == 4 || /* ignore redundant REX.W */ sz == 8)
10266 && insn[0] == 0x0F && insn[1] == 0x58) {
sewardj2e28ac42008-12-04 00:05:12 +000010267 delta = dis_SSE_E_to_G_lo64( vbi, pfx, delta+2, "addsd", Iop_Add64F0x2 );
sewardj1001dc42005-02-21 08:25:55 +000010268 goto decode_success;
10269 }
10270
sewardj8d965312005-02-25 02:48:47 +000010271 /* 66 0F 55 = ANDNPD -- G = (not G) and E */
10272 if (have66noF2noF3(pfx) && sz == 2
10273 && insn[0] == 0x0F && insn[1] == 0x55) {
sewardj2e28ac42008-12-04 00:05:12 +000010274 delta = dis_SSE_E_to_G_all_invG( vbi, pfx, delta+2, "andnpd", Iop_AndV128 );
sewardj8d965312005-02-25 02:48:47 +000010275 goto decode_success;
10276 }
sewardj1a01e652005-02-23 11:39:21 +000010277
10278 /* 66 0F 54 = ANDPD -- G = G and E */
10279 if (have66noF2noF3(pfx) && sz == 2
10280 && insn[0] == 0x0F && insn[1] == 0x54) {
sewardj2e28ac42008-12-04 00:05:12 +000010281 delta = dis_SSE_E_to_G_all( vbi, pfx, delta+2, "andpd", Iop_AndV128 );
sewardj1a01e652005-02-23 11:39:21 +000010282 goto decode_success;
10283 }
10284
sewardj97628592005-05-10 22:42:54 +000010285 /* 66 0F C2 = CMPPD -- 64Fx2 comparison from R/M to R */
10286 if (have66noF2noF3(pfx) && sz == 2
10287 && insn[0] == 0x0F && insn[1] == 0xC2) {
sewardj2e28ac42008-12-04 00:05:12 +000010288 delta = dis_SSEcmp_E_to_G( vbi, pfx, delta+2, "cmppd", True, 8 );
sewardj97628592005-05-10 22:42:54 +000010289 goto decode_success;
10290 }
sewardj8d965312005-02-25 02:48:47 +000010291
10292 /* F2 0F C2 = CMPSD -- 64F0x2 comparison from R/M to R */
10293 if (haveF2no66noF3(pfx) && sz == 4
10294 && insn[0] == 0x0F && insn[1] == 0xC2) {
sewardj2e28ac42008-12-04 00:05:12 +000010295 delta = dis_SSEcmp_E_to_G( vbi, pfx, delta+2, "cmpsd", False, 8 );
sewardj8d965312005-02-25 02:48:47 +000010296 goto decode_success;
10297 }
sewardj18303862005-02-21 12:36:54 +000010298
10299 /* 66 0F 2F = COMISD -- 64F0x2 comparison G,E, and set ZCP */
10300 /* 66 0F 2E = UCOMISD -- 64F0x2 comparison G,E, and set ZCP */
sewardjc49ce232005-02-25 13:03:03 +000010301 if (have66noF2noF3(pfx) && sz == 2
sewardj18303862005-02-21 12:36:54 +000010302 && insn[0] == 0x0F && (insn[1] == 0x2F || insn[1] == 0x2E)) {
10303 IRTemp argL = newTemp(Ity_F64);
10304 IRTemp argR = newTemp(Ity_F64);
10305 modrm = getUChar(delta+2);
10306 if (epartIsReg(modrm)) {
10307 assign( argR, getXMMRegLane64F( eregOfRexRM(pfx,modrm),
10308 0/*lowest lane*/ ) );
10309 delta += 2+1;
10310 DIP("%scomisd %s,%s\n", insn[1]==0x2E ? "u" : "",
10311 nameXMMReg(eregOfRexRM(pfx,modrm)),
10312 nameXMMReg(gregOfRexRM(pfx,modrm)) );
10313 } else {
sewardj2e28ac42008-12-04 00:05:12 +000010314 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj18303862005-02-21 12:36:54 +000010315 assign( argR, loadLE(Ity_F64, mkexpr(addr)) );
10316 delta += 2+alen;
10317 DIP("%scomisd %s,%s\n", insn[1]==0x2E ? "u" : "",
10318 dis_buf,
10319 nameXMMReg(gregOfRexRM(pfx,modrm)) );
10320 }
10321 assign( argL, getXMMRegLane64F( gregOfRexRM(pfx,modrm),
10322 0/*lowest lane*/ ) );
10323
10324 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(AMD64G_CC_OP_COPY) ));
10325 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
10326 stmt( IRStmt_Put(
10327 OFFB_CC_DEP1,
10328 binop( Iop_And64,
10329 unop( Iop_32Uto64,
10330 binop(Iop_CmpF64, mkexpr(argL), mkexpr(argR)) ),
10331 mkU64(0x45)
10332 )));
10333
10334 goto decode_success;
10335 }
10336
sewardj09717342005-05-05 21:34:02 +000010337 /* F3 0F E6 = CVTDQ2PD -- convert 2 x I32 in mem/lo half xmm to 2 x
10338 F64 in xmm(G) */
10339 if (haveF3no66noF2(pfx) && insn[0] == 0x0F && insn[1] == 0xE6) {
10340 IRTemp arg64 = newTemp(Ity_I64);
10341 if (sz != 4) goto decode_failure;
10342
10343 modrm = getUChar(delta+2);
10344 if (epartIsReg(modrm)) {
10345 assign( arg64, getXMMRegLane64(eregOfRexRM(pfx,modrm), 0) );
10346 delta += 2+1;
10347 DIP("cvtdq2pd %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
10348 nameXMMReg(gregOfRexRM(pfx,modrm)));
10349 } else {
sewardj2e28ac42008-12-04 00:05:12 +000010350 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj09717342005-05-05 21:34:02 +000010351 assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
10352 delta += 2+alen;
10353 DIP("cvtdq2pd %s,%s\n", dis_buf,
10354 nameXMMReg(gregOfRexRM(pfx,modrm)) );
10355 }
10356
10357 putXMMRegLane64F(
10358 gregOfRexRM(pfx,modrm), 0,
sewardj6c299f32009-12-31 18:00:12 +000010359 unop(Iop_I32StoF64, unop(Iop_64to32, mkexpr(arg64)))
sewardj09717342005-05-05 21:34:02 +000010360 );
10361
10362 putXMMRegLane64F(
10363 gregOfRexRM(pfx,modrm), 1,
sewardj6c299f32009-12-31 18:00:12 +000010364 unop(Iop_I32StoF64, unop(Iop_64HIto32, mkexpr(arg64)))
sewardj09717342005-05-05 21:34:02 +000010365 );
10366
10367 goto decode_success;
10368 }
10369
sewardj5992bd02005-05-11 02:13:42 +000010370 /* 0F 5B = CVTDQ2PS -- convert 4 x I32 in mem/xmm to 4 x F32 in
10371 xmm(G) */
10372 if (haveNo66noF2noF3(pfx) && sz == 4
10373 && insn[0] == 0x0F && insn[1] == 0x5B) {
sewardj09717342005-05-05 21:34:02 +000010374 IRTemp argV = newTemp(Ity_V128);
10375 IRTemp rmode = newTemp(Ity_I32);
sewardj09717342005-05-05 21:34:02 +000010376
10377 modrm = getUChar(delta+2);
10378 if (epartIsReg(modrm)) {
10379 assign( argV, getXMMReg(eregOfRexRM(pfx,modrm)) );
10380 delta += 2+1;
sewardj5992bd02005-05-11 02:13:42 +000010381 DIP("cvtdq2ps %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
sewardj09717342005-05-05 21:34:02 +000010382 nameXMMReg(gregOfRexRM(pfx,modrm)));
10383 } else {
sewardj2e28ac42008-12-04 00:05:12 +000010384 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj5992bd02005-05-11 02:13:42 +000010385 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
sewardj09717342005-05-05 21:34:02 +000010386 delta += 2+alen;
sewardj5992bd02005-05-11 02:13:42 +000010387 DIP("cvtdq2ps %s,%s\n", dis_buf,
sewardj09717342005-05-05 21:34:02 +000010388 nameXMMReg(gregOfRexRM(pfx,modrm)) );
10389 }
10390
10391 assign( rmode, get_sse_roundingmode() );
sewardj5992bd02005-05-11 02:13:42 +000010392 breakup128to32s( argV, &t3, &t2, &t1, &t0 );
10393
10394# define CVT(_t) binop( Iop_F64toF32, \
10395 mkexpr(rmode), \
sewardj6c299f32009-12-31 18:00:12 +000010396 unop(Iop_I32StoF64,mkexpr(_t)))
sewardj5992bd02005-05-11 02:13:42 +000010397
10398 putXMMRegLane32F( gregOfRexRM(pfx,modrm), 3, CVT(t3) );
10399 putXMMRegLane32F( gregOfRexRM(pfx,modrm), 2, CVT(t2) );
10400 putXMMRegLane32F( gregOfRexRM(pfx,modrm), 1, CVT(t1) );
10401 putXMMRegLane32F( gregOfRexRM(pfx,modrm), 0, CVT(t0) );
10402
10403# undef CVT
10404
10405 goto decode_success;
10406 }
10407
10408 /* 66 0F E6 = CVTTPD2DQ -- convert 2 x F64 in mem/xmm to 2 x I32 in
10409 lo half xmm(G), and zero upper half, rounding towards zero */
10410 /* F2 0F E6 = CVTPD2DQ -- convert 2 x F64 in mem/xmm to 2 x I32 in
10411 lo half xmm(G), according to prevailing rounding mode, and zero
10412 upper half */
10413 if ( ( (haveF2no66noF3(pfx) && sz == 4)
10414 || (have66noF2noF3(pfx) && sz == 2)
10415 )
10416 && insn[0] == 0x0F && insn[1] == 0xE6) {
10417 IRTemp argV = newTemp(Ity_V128);
10418 IRTemp rmode = newTemp(Ity_I32);
10419 Bool r2zero = toBool(sz == 2);
10420
10421 modrm = getUChar(delta+2);
10422 if (epartIsReg(modrm)) {
10423 assign( argV, getXMMReg(eregOfRexRM(pfx,modrm)) );
10424 delta += 2+1;
10425 DIP("cvt%spd2dq %s,%s\n", r2zero ? "t" : "",
10426 nameXMMReg(eregOfRexRM(pfx,modrm)),
10427 nameXMMReg(gregOfRexRM(pfx,modrm)));
10428 } else {
sewardj2e28ac42008-12-04 00:05:12 +000010429 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj5992bd02005-05-11 02:13:42 +000010430 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
10431 delta += 2+alen;
10432 DIP("cvt%spd2dq %s,%s\n", r2zero ? "t" : "",
10433 dis_buf,
10434 nameXMMReg(gregOfRexRM(pfx,modrm)) );
10435 }
10436
10437 if (r2zero) {
10438 assign(rmode, mkU32((UInt)Irrm_ZERO) );
10439 } else {
10440 assign( rmode, get_sse_roundingmode() );
10441 }
10442
sewardj09717342005-05-05 21:34:02 +000010443 t0 = newTemp(Ity_F64);
10444 t1 = newTemp(Ity_F64);
10445 assign( t0, unop(Iop_ReinterpI64asF64,
10446 unop(Iop_V128to64, mkexpr(argV))) );
10447 assign( t1, unop(Iop_ReinterpI64asF64,
10448 unop(Iop_V128HIto64, mkexpr(argV))) );
10449
sewardj6c299f32009-12-31 18:00:12 +000010450# define CVT(_t) binop( Iop_F64toI32S, \
sewardj09717342005-05-05 21:34:02 +000010451 mkexpr(rmode), \
10452 mkexpr(_t) )
10453
10454 putXMMRegLane32( gregOfRexRM(pfx,modrm), 3, mkU32(0) );
10455 putXMMRegLane32( gregOfRexRM(pfx,modrm), 2, mkU32(0) );
10456 putXMMRegLane32( gregOfRexRM(pfx,modrm), 1, CVT(t1) );
10457 putXMMRegLane32( gregOfRexRM(pfx,modrm), 0, CVT(t0) );
10458
10459# undef CVT
10460
10461 goto decode_success;
10462 }
10463
sewardj5992bd02005-05-11 02:13:42 +000010464 /* 66 0F 2D = CVTPD2PI -- convert 2 x F64 in mem/xmm to 2 x
10465 I32 in mmx, according to prevailing SSE rounding mode */
10466 /* 66 0F 2C = CVTTPD2PI -- convert 2 x F64 in mem/xmm to 2 x
10467 I32 in mmx, rounding towards zero */
10468 if (have66noF2noF3(pfx) && sz == 2
10469 && insn[0] == 0x0F && (insn[1] == 0x2D || insn[1] == 0x2C)) {
10470 IRTemp dst64 = newTemp(Ity_I64);
10471 IRTemp rmode = newTemp(Ity_I32);
10472 IRTemp f64lo = newTemp(Ity_F64);
10473 IRTemp f64hi = newTemp(Ity_F64);
sewardjca673ab2005-05-11 10:03:08 +000010474 Bool r2zero = toBool(insn[1] == 0x2C);
sewardj5992bd02005-05-11 02:13:42 +000010475
10476 do_MMX_preamble();
10477 modrm = getUChar(delta+2);
10478
10479 if (epartIsReg(modrm)) {
10480 delta += 2+1;
10481 assign(f64lo, getXMMRegLane64F(eregOfRexRM(pfx,modrm), 0));
10482 assign(f64hi, getXMMRegLane64F(eregOfRexRM(pfx,modrm), 1));
10483 DIP("cvt%spd2pi %s,%s\n", r2zero ? "t" : "",
10484 nameXMMReg(eregOfRexRM(pfx,modrm)),
10485 nameMMXReg(gregLO3ofRM(modrm)));
10486 } else {
sewardj2e28ac42008-12-04 00:05:12 +000010487 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj5992bd02005-05-11 02:13:42 +000010488 assign(f64lo, loadLE(Ity_F64, mkexpr(addr)));
10489 assign(f64hi, loadLE(Ity_F64, binop( Iop_Add64,
10490 mkexpr(addr),
10491 mkU64(8) )));
10492 delta += 2+alen;
10493 DIP("cvt%spf2pi %s,%s\n", r2zero ? "t" : "",
10494 dis_buf,
10495 nameMMXReg(gregLO3ofRM(modrm)));
10496 }
10497
10498 if (r2zero) {
10499 assign(rmode, mkU32((UInt)Irrm_ZERO) );
10500 } else {
10501 assign( rmode, get_sse_roundingmode() );
10502 }
10503
10504 assign(
10505 dst64,
10506 binop( Iop_32HLto64,
sewardj6c299f32009-12-31 18:00:12 +000010507 binop( Iop_F64toI32S, mkexpr(rmode), mkexpr(f64hi) ),
10508 binop( Iop_F64toI32S, mkexpr(rmode), mkexpr(f64lo) )
sewardj5992bd02005-05-11 02:13:42 +000010509 )
10510 );
10511
10512 putMMXReg(gregLO3ofRM(modrm), mkexpr(dst64));
10513 goto decode_success;
10514 }
10515
10516 /* 66 0F 5A = CVTPD2PS -- convert 2 x F64 in mem/xmm to 2 x F32 in
10517 lo half xmm(G), rounding according to prevailing SSE rounding
10518 mode, and zero upper half */
10519 /* Note, this is practically identical to CVTPD2DQ. It would have
10520 been nicer to merge them together, but the insn[] offsets differ
10521 by one. */
10522 if (have66noF2noF3(pfx) && sz == 2
10523 && insn[0] == 0x0F && insn[1] == 0x5A) {
10524 IRTemp argV = newTemp(Ity_V128);
10525 IRTemp rmode = newTemp(Ity_I32);
10526
10527 modrm = getUChar(delta+2);
10528 if (epartIsReg(modrm)) {
10529 assign( argV, getXMMReg(eregOfRexRM(pfx,modrm)) );
10530 delta += 2+1;
10531 DIP("cvtpd2ps %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
10532 nameXMMReg(gregOfRexRM(pfx,modrm)));
10533 } else {
sewardj2e28ac42008-12-04 00:05:12 +000010534 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj5992bd02005-05-11 02:13:42 +000010535 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
10536 delta += 2+alen;
10537 DIP("cvtpd2ps %s,%s\n", dis_buf,
10538 nameXMMReg(gregOfRexRM(pfx,modrm)) );
10539 }
10540
10541 assign( rmode, get_sse_roundingmode() );
10542 t0 = newTemp(Ity_F64);
10543 t1 = newTemp(Ity_F64);
10544 assign( t0, unop(Iop_ReinterpI64asF64,
10545 unop(Iop_V128to64, mkexpr(argV))) );
10546 assign( t1, unop(Iop_ReinterpI64asF64,
10547 unop(Iop_V128HIto64, mkexpr(argV))) );
10548
10549# define CVT(_t) binop( Iop_F64toF32, \
10550 mkexpr(rmode), \
10551 mkexpr(_t) )
10552
10553 putXMMRegLane32( gregOfRexRM(pfx,modrm), 3, mkU32(0) );
10554 putXMMRegLane32( gregOfRexRM(pfx,modrm), 2, mkU32(0) );
10555 putXMMRegLane32F( gregOfRexRM(pfx,modrm), 1, CVT(t1) );
10556 putXMMRegLane32F( gregOfRexRM(pfx,modrm), 0, CVT(t0) );
10557
10558# undef CVT
10559
10560 goto decode_success;
10561 }
10562
10563 /* 66 0F 2A = CVTPI2PD -- convert 2 x I32 in mem/mmx to 2 x F64 in
10564 xmm(G) */
10565 if (have66noF2noF3(pfx) && sz == 2
10566 && insn[0] == 0x0F && insn[1] == 0x2A) {
10567 IRTemp arg64 = newTemp(Ity_I64);
10568
10569 modrm = getUChar(delta+2);
sewardj5992bd02005-05-11 02:13:42 +000010570 if (epartIsReg(modrm)) {
sewardj30a20e92010-02-21 20:40:53 +000010571 /* Only switch to MMX mode if the source is a MMX register.
10572 This is inconsistent with all other instructions which
10573 convert between XMM and (M64 or MMX), which always switch
10574 to MMX mode even if 64-bit operand is M64 and not MMX. At
10575 least, that's what the Intel docs seem to me to say.
10576 Fixes #210264. */
10577 do_MMX_preamble();
sewardj5992bd02005-05-11 02:13:42 +000010578 assign( arg64, getMMXReg(eregLO3ofRM(modrm)) );
10579 delta += 2+1;
10580 DIP("cvtpi2pd %s,%s\n", nameMMXReg(eregLO3ofRM(modrm)),
10581 nameXMMReg(gregOfRexRM(pfx,modrm)));
10582 } else {
sewardj2e28ac42008-12-04 00:05:12 +000010583 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj5992bd02005-05-11 02:13:42 +000010584 assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
10585 delta += 2+alen;
10586 DIP("cvtpi2pd %s,%s\n", dis_buf,
10587 nameXMMReg(gregOfRexRM(pfx,modrm)) );
10588 }
10589
10590 putXMMRegLane64F(
10591 gregOfRexRM(pfx,modrm), 0,
sewardj6c299f32009-12-31 18:00:12 +000010592 unop(Iop_I32StoF64, unop(Iop_64to32, mkexpr(arg64)) )
sewardj5992bd02005-05-11 02:13:42 +000010593 );
10594
10595 putXMMRegLane64F(
10596 gregOfRexRM(pfx,modrm), 1,
sewardj6c299f32009-12-31 18:00:12 +000010597 unop(Iop_I32StoF64, unop(Iop_64HIto32, mkexpr(arg64)) )
sewardj5992bd02005-05-11 02:13:42 +000010598 );
10599
10600 goto decode_success;
10601 }
10602
10603 /* F3 0F 5B = CVTTPS2DQ -- convert 4 x F32 in mem/xmm to 4 x I32 in
10604 xmm(G), rounding towards zero */
10605 /* 66 0F 5B = CVTPS2DQ -- convert 4 x F32 in mem/xmm to 4 x I32 in
10606 xmm(G), as per the prevailing rounding mode */
10607 if ( ( (have66noF2noF3(pfx) && sz == 2)
10608 || (haveF3no66noF2(pfx) && sz == 4)
10609 )
10610 && insn[0] == 0x0F && insn[1] == 0x5B) {
10611 IRTemp argV = newTemp(Ity_V128);
10612 IRTemp rmode = newTemp(Ity_I32);
10613 Bool r2zero = toBool(sz == 4);
10614
10615 modrm = getUChar(delta+2);
10616 if (epartIsReg(modrm)) {
10617 assign( argV, getXMMReg(eregOfRexRM(pfx,modrm)) );
10618 delta += 2+1;
10619 DIP("cvtps2dq %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
10620 nameXMMReg(gregOfRexRM(pfx,modrm)));
10621 } else {
sewardj2e28ac42008-12-04 00:05:12 +000010622 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj5992bd02005-05-11 02:13:42 +000010623 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
10624 delta += 2+alen;
10625 DIP("cvtps2dq %s,%s\n", dis_buf,
10626 nameXMMReg(gregOfRexRM(pfx,modrm)) );
10627 }
10628
10629 if (r2zero) {
10630 assign( rmode, mkU32((UInt)Irrm_ZERO) );
10631 } else {
10632 assign( rmode, get_sse_roundingmode() );
10633 }
10634
10635 breakup128to32s( argV, &t3, &t2, &t1, &t0 );
10636
10637 /* This is less than ideal. If it turns out to be a performance
10638 bottleneck it can be improved. */
10639# define CVT(_t) \
sewardj6c299f32009-12-31 18:00:12 +000010640 binop( Iop_F64toI32S, \
sewardj5992bd02005-05-11 02:13:42 +000010641 mkexpr(rmode), \
10642 unop( Iop_F32toF64, \
10643 unop( Iop_ReinterpI32asF32, mkexpr(_t))) )
10644
10645 putXMMRegLane32( gregOfRexRM(pfx,modrm), 3, CVT(t3) );
10646 putXMMRegLane32( gregOfRexRM(pfx,modrm), 2, CVT(t2) );
10647 putXMMRegLane32( gregOfRexRM(pfx,modrm), 1, CVT(t1) );
10648 putXMMRegLane32( gregOfRexRM(pfx,modrm), 0, CVT(t0) );
10649
10650# undef CVT
10651
10652 goto decode_success;
10653 }
10654
10655 /* 0F 5A = CVTPS2PD -- convert 2 x F32 in low half mem/xmm to 2 x
10656 F64 in xmm(G). */
10657 if (haveNo66noF2noF3(pfx) && sz == 4
10658 && insn[0] == 0x0F && insn[1] == 0x5A) {
10659 IRTemp f32lo = newTemp(Ity_F32);
10660 IRTemp f32hi = newTemp(Ity_F32);
10661
10662 modrm = getUChar(delta+2);
10663 if (epartIsReg(modrm)) {
10664 assign( f32lo, getXMMRegLane32F(eregOfRexRM(pfx,modrm), 0) );
10665 assign( f32hi, getXMMRegLane32F(eregOfRexRM(pfx,modrm), 1) );
10666 delta += 2+1;
10667 DIP("cvtps2pd %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
10668 nameXMMReg(gregOfRexRM(pfx,modrm)));
10669 } else {
sewardj2e28ac42008-12-04 00:05:12 +000010670 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj5992bd02005-05-11 02:13:42 +000010671 assign( f32lo, loadLE(Ity_F32, mkexpr(addr)) );
10672 assign( f32hi, loadLE(Ity_F32,
10673 binop(Iop_Add64,mkexpr(addr),mkU64(4))) );
10674 delta += 2+alen;
10675 DIP("cvtps2pd %s,%s\n", dis_buf,
10676 nameXMMReg(gregOfRexRM(pfx,modrm)) );
10677 }
10678
10679 putXMMRegLane64F( gregOfRexRM(pfx,modrm), 1,
10680 unop(Iop_F32toF64, mkexpr(f32hi)) );
10681 putXMMRegLane64F( gregOfRexRM(pfx,modrm), 0,
10682 unop(Iop_F32toF64, mkexpr(f32lo)) );
10683
10684 goto decode_success;
10685 }
10686
10687 /* F2 0F 2D = CVTSD2SI
10688 when sz==4 -- convert F64 in mem/low half xmm to I32 in ireg,
10689 according to prevailing SSE rounding mode
10690 when sz==8 -- convert F64 in mem/low half xmm to I64 in ireg,
10691 according to prevailing SSE rounding mode
10692 */
sewardj1a01e652005-02-23 11:39:21 +000010693 /* F2 0F 2C = CVTTSD2SI
10694 when sz==4 -- convert F64 in mem/low half xmm to I32 in ireg,
10695 truncating towards zero
10696 when sz==8 -- convert F64 in mem/low half xmm to I64 in ireg,
10697 truncating towards zero
10698 */
10699 if (haveF2no66noF3(pfx)
10700 && insn[0] == 0x0F
sewardj5992bd02005-05-11 02:13:42 +000010701 && (insn[1] == 0x2D || insn[1] == 0x2C)) {
sewardj1a01e652005-02-23 11:39:21 +000010702 IRTemp rmode = newTemp(Ity_I32);
10703 IRTemp f64lo = newTemp(Ity_F64);
sewardj1027dc22005-02-26 01:55:02 +000010704 Bool r2zero = toBool(insn[1] == 0x2C);
sewardj1a01e652005-02-23 11:39:21 +000010705 vassert(sz == 4 || sz == 8);
10706
10707 modrm = getUChar(delta+2);
10708 if (epartIsReg(modrm)) {
10709 delta += 2+1;
10710 assign(f64lo, getXMMRegLane64F(eregOfRexRM(pfx,modrm), 0));
10711 DIP("cvt%ssd2si %s,%s\n", r2zero ? "t" : "",
10712 nameXMMReg(eregOfRexRM(pfx,modrm)),
sewardj5b470602005-02-27 13:10:48 +000010713 nameIReg(sz, gregOfRexRM(pfx,modrm), False));
sewardj1a01e652005-02-23 11:39:21 +000010714 } else {
sewardj2e28ac42008-12-04 00:05:12 +000010715 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj1a01e652005-02-23 11:39:21 +000010716 assign(f64lo, loadLE(Ity_F64, mkexpr(addr)));
10717 delta += 2+alen;
10718 DIP("cvt%ssd2si %s,%s\n", r2zero ? "t" : "",
10719 dis_buf,
sewardj5b470602005-02-27 13:10:48 +000010720 nameIReg(sz, gregOfRexRM(pfx,modrm), False));
sewardj1a01e652005-02-23 11:39:21 +000010721 }
10722
10723 if (r2zero) {
10724 assign( rmode, mkU32((UInt)Irrm_ZERO) );
10725 } else {
10726 assign( rmode, get_sse_roundingmode() );
10727 }
10728
10729 if (sz == 4) {
sewardj5b470602005-02-27 13:10:48 +000010730 putIReg32( gregOfRexRM(pfx,modrm),
sewardj6c299f32009-12-31 18:00:12 +000010731 binop( Iop_F64toI32S, mkexpr(rmode), mkexpr(f64lo)) );
sewardj1a01e652005-02-23 11:39:21 +000010732 } else {
sewardj5b470602005-02-27 13:10:48 +000010733 putIReg64( gregOfRexRM(pfx,modrm),
sewardj6c299f32009-12-31 18:00:12 +000010734 binop( Iop_F64toI64S, mkexpr(rmode), mkexpr(f64lo)) );
sewardj1a01e652005-02-23 11:39:21 +000010735 }
10736
10737 goto decode_success;
10738 }
10739
sewardj8d965312005-02-25 02:48:47 +000010740 /* F2 0F 5A = CVTSD2SS -- convert F64 in mem/low half xmm to F32 in
10741 low 1/4 xmm(G), according to prevailing SSE rounding mode */
10742 if (haveF2no66noF3(pfx) && sz == 4
10743 && insn[0] == 0x0F && insn[1] == 0x5A) {
10744 IRTemp rmode = newTemp(Ity_I32);
10745 IRTemp f64lo = newTemp(Ity_F64);
10746 vassert(sz == 4);
10747
10748 modrm = getUChar(delta+2);
10749 if (epartIsReg(modrm)) {
10750 delta += 2+1;
10751 assign(f64lo, getXMMRegLane64F(eregOfRexRM(pfx,modrm), 0));
10752 DIP("cvtsd2ss %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
10753 nameXMMReg(gregOfRexRM(pfx,modrm)));
10754 } else {
sewardj2e28ac42008-12-04 00:05:12 +000010755 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj8d965312005-02-25 02:48:47 +000010756 assign(f64lo, loadLE(Ity_F64, mkexpr(addr)));
10757 delta += 2+alen;
10758 DIP("cvtsd2ss %s,%s\n", dis_buf,
10759 nameXMMReg(gregOfRexRM(pfx,modrm)));
10760 }
10761
10762 assign( rmode, get_sse_roundingmode() );
10763 putXMMRegLane32F(
10764 gregOfRexRM(pfx,modrm), 0,
10765 binop( Iop_F64toF32, mkexpr(rmode), mkexpr(f64lo) )
10766 );
10767
10768 goto decode_success;
10769 }
sewardj1a01e652005-02-23 11:39:21 +000010770
10771 /* F2 0F 2A = CVTSI2SD
10772 when sz==4 -- convert I32 in mem/ireg to F64 in low half xmm
10773 when sz==8 -- convert I64 in mem/ireg to F64 in low half xmm
10774 */
sewardj8d965312005-02-25 02:48:47 +000010775 if (haveF2no66noF3(pfx) && (sz == 4 || sz == 8)
10776 && insn[0] == 0x0F && insn[1] == 0x2A) {
sewardj1a01e652005-02-23 11:39:21 +000010777 modrm = getUChar(delta+2);
10778
10779 if (sz == 4) {
10780 IRTemp arg32 = newTemp(Ity_I32);
10781 if (epartIsReg(modrm)) {
sewardj5b470602005-02-27 13:10:48 +000010782 assign( arg32, getIReg32(eregOfRexRM(pfx,modrm)) );
sewardj1a01e652005-02-23 11:39:21 +000010783 delta += 2+1;
sewardj5b470602005-02-27 13:10:48 +000010784 DIP("cvtsi2sd %s,%s\n", nameIReg32(eregOfRexRM(pfx,modrm)),
sewardj1a01e652005-02-23 11:39:21 +000010785 nameXMMReg(gregOfRexRM(pfx,modrm)));
10786 } else {
sewardj2e28ac42008-12-04 00:05:12 +000010787 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj1a01e652005-02-23 11:39:21 +000010788 assign( arg32, loadLE(Ity_I32, mkexpr(addr)) );
10789 delta += 2+alen;
10790 DIP("cvtsi2sd %s,%s\n", dis_buf,
10791 nameXMMReg(gregOfRexRM(pfx,modrm)) );
10792 }
10793 putXMMRegLane64F( gregOfRexRM(pfx,modrm), 0,
sewardj6c299f32009-12-31 18:00:12 +000010794 unop(Iop_I32StoF64, mkexpr(arg32))
sewardj1a01e652005-02-23 11:39:21 +000010795 );
10796 } else {
10797 /* sz == 8 */
10798 IRTemp arg64 = newTemp(Ity_I64);
10799 if (epartIsReg(modrm)) {
sewardj5b470602005-02-27 13:10:48 +000010800 assign( arg64, getIReg64(eregOfRexRM(pfx,modrm)) );
sewardj1a01e652005-02-23 11:39:21 +000010801 delta += 2+1;
sewardj5b470602005-02-27 13:10:48 +000010802 DIP("cvtsi2sdq %s,%s\n", nameIReg64(eregOfRexRM(pfx,modrm)),
sewardj8d965312005-02-25 02:48:47 +000010803 nameXMMReg(gregOfRexRM(pfx,modrm)));
sewardj1a01e652005-02-23 11:39:21 +000010804 } else {
sewardj2e28ac42008-12-04 00:05:12 +000010805 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj1a01e652005-02-23 11:39:21 +000010806 assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
10807 delta += 2+alen;
sewardj8d965312005-02-25 02:48:47 +000010808 DIP("cvtsi2sdq %s,%s\n", dis_buf,
10809 nameXMMReg(gregOfRexRM(pfx,modrm)) );
sewardj1a01e652005-02-23 11:39:21 +000010810 }
10811 putXMMRegLane64F(
10812 gregOfRexRM(pfx,modrm),
10813 0,
sewardj6c299f32009-12-31 18:00:12 +000010814 binop( Iop_I64StoF64,
sewardj1a01e652005-02-23 11:39:21 +000010815 get_sse_roundingmode(),
10816 mkexpr(arg64)
10817 )
10818 );
10819
10820 }
10821
10822 goto decode_success;
10823 }
10824
sewardjc49ce232005-02-25 13:03:03 +000010825 /* F3 0F 5A = CVTSS2SD -- convert F32 in mem/low 1/4 xmm to F64 in
10826 low half xmm(G) */
10827 if (haveF3no66noF2(pfx) && sz == 4
10828 && insn[0] == 0x0F && insn[1] == 0x5A) {
10829 IRTemp f32lo = newTemp(Ity_F32);
10830
10831 modrm = getUChar(delta+2);
10832 if (epartIsReg(modrm)) {
10833 delta += 2+1;
10834 assign(f32lo, getXMMRegLane32F(eregOfRexRM(pfx,modrm), 0));
10835 DIP("cvtss2sd %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
10836 nameXMMReg(gregOfRexRM(pfx,modrm)));
10837 } else {
sewardj2e28ac42008-12-04 00:05:12 +000010838 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardjc49ce232005-02-25 13:03:03 +000010839 assign(f32lo, loadLE(Ity_F32, mkexpr(addr)));
10840 delta += 2+alen;
10841 DIP("cvtss2sd %s,%s\n", dis_buf,
10842 nameXMMReg(gregOfRexRM(pfx,modrm)));
10843 }
10844
10845 putXMMRegLane64F( gregOfRexRM(pfx,modrm), 0,
10846 unop( Iop_F32toF64, mkexpr(f32lo) ) );
10847
10848 goto decode_success;
10849 }
10850
sewardj5992bd02005-05-11 02:13:42 +000010851 /* 66 0F 5E = DIVPD -- div 64Fx2 from R/M to R */
10852 if (have66noF2noF3(pfx) && sz == 2
10853 && insn[0] == 0x0F && insn[1] == 0x5E) {
sewardj2e28ac42008-12-04 00:05:12 +000010854 delta = dis_SSE_E_to_G_all( vbi, pfx, delta+2, "divpd", Iop_Div64Fx2 );
sewardj5992bd02005-05-11 02:13:42 +000010855 goto decode_success;
10856 }
sewardj1001dc42005-02-21 08:25:55 +000010857
10858 /* F2 0F 5E = DIVSD -- div 64F0x2 from R/M to R */
10859 if (haveF2no66noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x5E) {
10860 vassert(sz == 4);
sewardj2e28ac42008-12-04 00:05:12 +000010861 delta = dis_SSE_E_to_G_lo64( vbi, pfx, delta+2, "divsd", Iop_Div64F0x2 );
sewardj1001dc42005-02-21 08:25:55 +000010862 goto decode_success;
10863 }
10864
sewardj5992bd02005-05-11 02:13:42 +000010865 /* 0F AE /5 = LFENCE -- flush pending operations to memory */
10866 /* 0F AE /6 = MFENCE -- flush pending operations to memory */
10867 if (haveNo66noF2noF3(pfx) && sz == 4
10868 && insn[0] == 0x0F && insn[1] == 0xAE
10869 && epartIsReg(insn[2])
10870 && (gregLO3ofRM(insn[2]) == 5 || gregLO3ofRM(insn[2]) == 6)) {
10871 delta += 3;
10872 /* Insert a memory fence. It's sometimes important that these
10873 are carried through to the generated code. */
sewardjc4356f02007-11-09 21:15:04 +000010874 stmt( IRStmt_MBE(Imbe_Fence) );
sewardj5992bd02005-05-11 02:13:42 +000010875 DIP("%sfence\n", gregLO3ofRM(insn[2])==5 ? "l" : "m");
10876 goto decode_success;
10877 }
10878
10879 /* 66 0F 5F = MAXPD -- max 64Fx2 from R/M to R */
10880 if (have66noF2noF3(pfx) && sz == 2
10881 && insn[0] == 0x0F && insn[1] == 0x5F) {
sewardj2e28ac42008-12-04 00:05:12 +000010882 delta = dis_SSE_E_to_G_all( vbi, pfx, delta+2, "maxpd", Iop_Max64Fx2 );
sewardj5992bd02005-05-11 02:13:42 +000010883 goto decode_success;
10884 }
sewardj1a01e652005-02-23 11:39:21 +000010885
10886 /* F2 0F 5F = MAXSD -- max 64F0x2 from R/M to R */
10887 if (haveF2no66noF3(pfx) && sz == 4
10888 && insn[0] == 0x0F && insn[1] == 0x5F) {
sewardj2e28ac42008-12-04 00:05:12 +000010889 delta = dis_SSE_E_to_G_lo64( vbi, pfx, delta+2, "maxsd", Iop_Max64F0x2 );
sewardj1a01e652005-02-23 11:39:21 +000010890 goto decode_success;
10891 }
10892
sewardj5992bd02005-05-11 02:13:42 +000010893 /* 66 0F 5D = MINPD -- min 64Fx2 from R/M to R */
10894 if (have66noF2noF3(pfx) && sz == 2
10895 && insn[0] == 0x0F && insn[1] == 0x5D) {
sewardj2e28ac42008-12-04 00:05:12 +000010896 delta = dis_SSE_E_to_G_all( vbi, pfx, delta+2, "minpd", Iop_Min64Fx2 );
sewardj5992bd02005-05-11 02:13:42 +000010897 goto decode_success;
10898 }
sewardjc49ce232005-02-25 13:03:03 +000010899
10900 /* F2 0F 5D = MINSD -- min 64F0x2 from R/M to R */
10901 if (haveF2no66noF3(pfx) && sz == 4
10902 && insn[0] == 0x0F && insn[1] == 0x5D) {
sewardj2e28ac42008-12-04 00:05:12 +000010903 delta = dis_SSE_E_to_G_lo64( vbi, pfx, delta+2, "minsd", Iop_Min64F0x2 );
sewardjc49ce232005-02-25 13:03:03 +000010904 goto decode_success;
10905 }
sewardj8d965312005-02-25 02:48:47 +000010906
10907 /* 66 0F 28 = MOVAPD -- move from E (mem or xmm) to G (xmm). */
10908 /* 66 0F 10 = MOVUPD -- move from E (mem or xmm) to G (xmm). */
10909 /* 66 0F 6F = MOVDQA -- move from E (mem or xmm) to G (xmm). */
sewardjb4bf5882007-11-06 20:39:17 +000010910 if (have66noF2noF3(pfx)
10911 && (sz == 2 || /* ignore redundant REX.W */ sz == 8)
sewardj8d965312005-02-25 02:48:47 +000010912 && insn[0] == 0x0F
10913 && (insn[1] == 0x28 || insn[1] == 0x10 || insn[1] == 0x6F)) {
10914 HChar* wot = insn[1]==0x28 ? "apd" :
10915 insn[1]==0x10 ? "upd" : "dqa";
10916 modrm = getUChar(delta+2);
10917 if (epartIsReg(modrm)) {
10918 putXMMReg( gregOfRexRM(pfx,modrm),
10919 getXMMReg( eregOfRexRM(pfx,modrm) ));
10920 DIP("mov%s %s,%s\n", wot, nameXMMReg(eregOfRexRM(pfx,modrm)),
10921 nameXMMReg(gregOfRexRM(pfx,modrm)));
10922 delta += 2+1;
10923 } else {
sewardj2e28ac42008-12-04 00:05:12 +000010924 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj8d965312005-02-25 02:48:47 +000010925 putXMMReg( gregOfRexRM(pfx,modrm),
10926 loadLE(Ity_V128, mkexpr(addr)) );
10927 DIP("mov%s %s,%s\n", wot, dis_buf,
10928 nameXMMReg(gregOfRexRM(pfx,modrm)));
10929 delta += 2+alen;
10930 }
10931 goto decode_success;
10932 }
10933
sewardj4c328cf2005-05-05 12:05:54 +000010934 /* 66 0F 29 = MOVAPD -- move from G (xmm) to E (mem or xmm). */
sewardj240fd862005-11-01 18:59:38 +000010935 /* 66 0F 11 = MOVUPD -- move from G (xmm) to E (mem or xmm). */
10936 if (have66noF2noF3(pfx) && insn[0] == 0x0F
10937 && (insn[1] == 0x29 || insn[1] == 0x11)) {
sewardj4c328cf2005-05-05 12:05:54 +000010938 modrm = getUChar(delta+2);
10939 if (epartIsReg(modrm)) {
10940 /* fall through; awaiting test case */
10941 } else {
sewardj2e28ac42008-12-04 00:05:12 +000010942 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj4c328cf2005-05-05 12:05:54 +000010943 storeLE( mkexpr(addr), getXMMReg(gregOfRexRM(pfx,modrm)) );
sewardj240fd862005-11-01 18:59:38 +000010944 DIP("mov[ua]pd %s,%s\n", nameXMMReg(gregOfRexRM(pfx,modrm)),
10945 dis_buf );
sewardj4c328cf2005-05-05 12:05:54 +000010946 delta += 2+alen;
10947 goto decode_success;
10948 }
10949 }
10950
sewardj09717342005-05-05 21:34:02 +000010951 /* 66 0F 6E = MOVD from ireg32/m32 to xmm lo 1/4, zeroing high 3/4 of xmm. */
10952 /* or from ireg64/m64 to xmm lo 1/2, zeroing high 1/2 of xmm. */
10953 if (have66noF2noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x6E) {
sewardj97628592005-05-10 22:42:54 +000010954 vassert(sz == 2 || sz == 8);
10955 if (sz == 2) sz = 4;
sewardj09717342005-05-05 21:34:02 +000010956 modrm = getUChar(delta+2);
10957 if (epartIsReg(modrm)) {
10958 delta += 2+1;
10959 if (sz == 4) {
sewardj09717342005-05-05 21:34:02 +000010960 putXMMReg(
10961 gregOfRexRM(pfx,modrm),
10962 unop( Iop_32UtoV128, getIReg32(eregOfRexRM(pfx,modrm)) )
10963 );
10964 DIP("movd %s, %s\n", nameIReg32(eregOfRexRM(pfx,modrm)),
10965 nameXMMReg(gregOfRexRM(pfx,modrm)));
10966 } else {
10967 putXMMReg(
10968 gregOfRexRM(pfx,modrm),
10969 unop( Iop_64UtoV128, getIReg64(eregOfRexRM(pfx,modrm)) )
10970 );
10971 DIP("movq %s, %s\n", nameIReg64(eregOfRexRM(pfx,modrm)),
10972 nameXMMReg(gregOfRexRM(pfx,modrm)));
10973 }
10974 } else {
sewardj2e28ac42008-12-04 00:05:12 +000010975 addr = disAMode( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj09717342005-05-05 21:34:02 +000010976 delta += 2+alen;
10977 putXMMReg(
10978 gregOfRexRM(pfx,modrm),
10979 sz == 4
10980 ? unop( Iop_32UtoV128,loadLE(Ity_I32, mkexpr(addr)) )
10981 : unop( Iop_64UtoV128,loadLE(Ity_I64, mkexpr(addr)) )
10982 );
10983 DIP("mov%c %s, %s\n", sz == 4 ? 'd' : 'q', dis_buf,
10984 nameXMMReg(gregOfRexRM(pfx,modrm)));
10985 }
10986 goto decode_success;
10987 }
10988
10989 /* 66 0F 7E = MOVD from xmm low 1/4 to ireg32 or m32. */
10990 /* or from xmm low 1/2 to ireg64 or m64. */
10991 if (have66noF2noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x7E) {
10992 if (sz == 2) sz = 4;
10993 vassert(sz == 4 || sz == 8);
10994 modrm = getUChar(delta+2);
10995 if (epartIsReg(modrm)) {
10996 delta += 2+1;
10997 if (sz == 4) {
10998 putIReg32( eregOfRexRM(pfx,modrm),
10999 getXMMRegLane32(gregOfRexRM(pfx,modrm), 0) );
11000 DIP("movd %s, %s\n", nameXMMReg(gregOfRexRM(pfx,modrm)),
11001 nameIReg32(eregOfRexRM(pfx,modrm)));
11002 } else {
11003 putIReg64( eregOfRexRM(pfx,modrm),
11004 getXMMRegLane64(gregOfRexRM(pfx,modrm), 0) );
11005 DIP("movq %s, %s\n", nameXMMReg(gregOfRexRM(pfx,modrm)),
11006 nameIReg64(eregOfRexRM(pfx,modrm)));
11007 }
11008 } else {
sewardj2e28ac42008-12-04 00:05:12 +000011009 addr = disAMode( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj09717342005-05-05 21:34:02 +000011010 delta += 2+alen;
11011 storeLE( mkexpr(addr),
11012 sz == 4
11013 ? getXMMRegLane32(gregOfRexRM(pfx,modrm),0)
11014 : getXMMRegLane64(gregOfRexRM(pfx,modrm),0) );
11015 DIP("mov%c %s, %s\n", sz == 4 ? 'd' : 'q',
11016 nameXMMReg(gregOfRexRM(pfx,modrm)), dis_buf);
11017 }
11018 goto decode_success;
11019 }
11020
11021 /* 66 0F 7F = MOVDQA -- move from G (xmm) to E (mem or xmm). */
11022 if (have66noF2noF3(pfx) && sz == 2
11023 && insn[0] == 0x0F && insn[1] == 0x7F) {
11024 modrm = getUChar(delta+2);
11025 if (epartIsReg(modrm)) {
11026 delta += 2+1;
11027 putXMMReg( eregOfRexRM(pfx,modrm),
11028 getXMMReg(gregOfRexRM(pfx,modrm)) );
11029 DIP("movdqa %s, %s\n", nameXMMReg(gregOfRexRM(pfx,modrm)),
11030 nameXMMReg(eregOfRexRM(pfx,modrm)));
11031 } else {
sewardj2e28ac42008-12-04 00:05:12 +000011032 addr = disAMode( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj09717342005-05-05 21:34:02 +000011033 delta += 2+alen;
11034 storeLE( mkexpr(addr), getXMMReg(gregOfRexRM(pfx,modrm)) );
11035 DIP("movdqa %s, %s\n", nameXMMReg(gregOfRexRM(pfx,modrm)), dis_buf);
11036 }
11037 goto decode_success;
11038 }
11039
sewardj612be432005-05-11 02:55:54 +000011040 /* F3 0F 6F = MOVDQU -- move from E (mem or xmm) to G (xmm). */
11041 if (haveF3no66noF2(pfx) && sz == 4
11042 && insn[0] == 0x0F && insn[1] == 0x6F) {
11043 modrm = getUChar(delta+2);
11044 if (epartIsReg(modrm)) {
11045 putXMMReg( gregOfRexRM(pfx,modrm),
11046 getXMMReg( eregOfRexRM(pfx,modrm) ));
11047 DIP("movdqu %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
11048 nameXMMReg(gregOfRexRM(pfx,modrm)));
11049 delta += 2+1;
11050 } else {
sewardj2e28ac42008-12-04 00:05:12 +000011051 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj612be432005-05-11 02:55:54 +000011052 putXMMReg( gregOfRexRM(pfx,modrm),
11053 loadLE(Ity_V128, mkexpr(addr)) );
11054 DIP("movdqu %s,%s\n", dis_buf,
11055 nameXMMReg(gregOfRexRM(pfx,modrm)));
11056 delta += 2+alen;
11057 }
11058 goto decode_success;
11059 }
11060
11061 /* F3 0F 7F = MOVDQU -- move from G (xmm) to E (mem or xmm). */
11062 if (haveF3no66noF2(pfx) && sz == 4
11063 && insn[0] == 0x0F && insn[1] == 0x7F) {
11064 modrm = getUChar(delta+2);
11065 if (epartIsReg(modrm)) {
11066 goto decode_failure; /* awaiting test case */
11067 delta += 2+1;
11068 putXMMReg( eregOfRexRM(pfx,modrm),
11069 getXMMReg(gregOfRexRM(pfx,modrm)) );
11070 DIP("movdqu %s, %s\n", nameXMMReg(gregOfRexRM(pfx,modrm)),
11071 nameXMMReg(eregOfRexRM(pfx,modrm)));
11072 } else {
sewardj2e28ac42008-12-04 00:05:12 +000011073 addr = disAMode( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj612be432005-05-11 02:55:54 +000011074 delta += 2+alen;
11075 storeLE( mkexpr(addr), getXMMReg(gregOfRexRM(pfx,modrm)) );
11076 DIP("movdqu %s, %s\n", nameXMMReg(gregOfRexRM(pfx,modrm)), dis_buf);
11077 }
11078 goto decode_success;
11079 }
11080
11081 /* F2 0F D6 = MOVDQ2Q -- move from E (lo half xmm, not mem) to G (mmx). */
11082 if (haveF2no66noF3(pfx) && sz == 4
11083 && insn[0] == 0x0F && insn[1] == 0xD6) {
11084 modrm = getUChar(delta+2);
11085 if (epartIsReg(modrm)) {
11086 do_MMX_preamble();
11087 putMMXReg( gregLO3ofRM(modrm),
11088 getXMMRegLane64( eregOfRexRM(pfx,modrm), 0 ));
11089 DIP("movdq2q %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
11090 nameMMXReg(gregLO3ofRM(modrm)));
11091 delta += 2+1;
11092 goto decode_success;
11093 } else {
11094 /* apparently no mem case for this insn */
11095 goto decode_failure;
11096 }
11097 }
sewardj4c328cf2005-05-05 12:05:54 +000011098
11099 /* 66 0F 16 = MOVHPD -- move from mem to high half of XMM. */
11100 /* These seems identical to MOVHPS. This instruction encoding is
11101 completely crazy. */
11102 if (have66noF2noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x16) {
11103 modrm = getUChar(delta+2);
11104 if (epartIsReg(modrm)) {
11105 /* fall through; apparently reg-reg is not possible */
11106 } else {
sewardj2e28ac42008-12-04 00:05:12 +000011107 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj4c328cf2005-05-05 12:05:54 +000011108 delta += 2+alen;
11109 putXMMRegLane64( gregOfRexRM(pfx,modrm), 1/*upper lane*/,
11110 loadLE(Ity_I64, mkexpr(addr)) );
11111 DIP("movhpd %s,%s\n", dis_buf,
11112 nameXMMReg( gregOfRexRM(pfx,modrm) ));
11113 goto decode_success;
11114 }
11115 }
11116
11117 /* 66 0F 17 = MOVHPD -- move from high half of XMM to mem. */
11118 /* Again, this seems identical to MOVHPS. */
11119 if (have66noF2noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x17) {
11120 if (!epartIsReg(insn[2])) {
11121 delta += 2;
sewardj2e28ac42008-12-04 00:05:12 +000011122 addr = disAMode ( &alen, vbi, pfx, delta, dis_buf, 0 );
sewardj4c328cf2005-05-05 12:05:54 +000011123 delta += alen;
11124 storeLE( mkexpr(addr),
11125 getXMMRegLane64( gregOfRexRM(pfx,insn[2]),
11126 1/*upper lane*/ ) );
11127 DIP("movhpd %s,%s\n", nameXMMReg( gregOfRexRM(pfx,insn[2]) ),
11128 dis_buf);
11129 goto decode_success;
11130 }
11131 /* else fall through */
11132 }
sewardj1001dc42005-02-21 08:25:55 +000011133
11134 /* 66 0F 12 = MOVLPD -- move from mem to low half of XMM. */
11135 /* Identical to MOVLPS ? */
11136 if (have66noF2noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x12) {
11137 modrm = getUChar(delta+2);
11138 if (epartIsReg(modrm)) {
11139 /* fall through; apparently reg-reg is not possible */
11140 } else {
sewardj2e28ac42008-12-04 00:05:12 +000011141 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj1001dc42005-02-21 08:25:55 +000011142 delta += 2+alen;
11143 putXMMRegLane64( gregOfRexRM(pfx,modrm),
11144 0/*lower lane*/,
11145 loadLE(Ity_I64, mkexpr(addr)) );
11146 DIP("movlpd %s, %s\n",
11147 dis_buf, nameXMMReg( gregOfRexRM(pfx,modrm) ));
11148 goto decode_success;
11149 }
11150 }
11151
sewardj4c328cf2005-05-05 12:05:54 +000011152 /* 66 0F 13 = MOVLPD -- move from low half of XMM to mem. */
11153 /* Identical to MOVLPS ? */
11154 if (have66noF2noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x13) {
11155 modrm = getUChar(delta+2);
11156 if (!epartIsReg(modrm)) {
sewardj2e28ac42008-12-04 00:05:12 +000011157 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj4c328cf2005-05-05 12:05:54 +000011158 delta += 2+alen;
11159 storeLE( mkexpr(addr),
11160 getXMMRegLane64( gregOfRexRM(pfx,modrm),
11161 0/*lower lane*/ ) );
11162 DIP("movlpd %s, %s\n", nameXMMReg( gregOfRexRM(pfx,modrm) ),
11163 dis_buf);
11164 goto decode_success;
11165 }
11166 /* else fall through */
11167 }
11168
sewardj612be432005-05-11 02:55:54 +000011169 /* 66 0F 50 = MOVMSKPD - move 2 sign bits from 2 x F64 in xmm(E) to
11170 2 lowest bits of ireg(G) */
sewardjae84d782006-04-13 22:06:35 +000011171 if (have66noF2noF3(pfx) && (sz == 2 || sz == 8)
sewardj612be432005-05-11 02:55:54 +000011172 && insn[0] == 0x0F && insn[1] == 0x50) {
sewardjae84d782006-04-13 22:06:35 +000011173 /* sz == 8 is a kludge to handle insns with REX.W redundantly
11174 set to 1, which has been known to happen:
11175 66 4c 0f 50 d9 rex64X movmskpd %xmm1,%r11d
sewardjb4bf5882007-11-06 20:39:17 +000011176 20071106: see further comments on MOVMSKPS implementation above.
sewardjae84d782006-04-13 22:06:35 +000011177 */
sewardj612be432005-05-11 02:55:54 +000011178 modrm = getUChar(delta+2);
11179 if (epartIsReg(modrm)) {
11180 Int src;
11181 t0 = newTemp(Ity_I32);
11182 t1 = newTemp(Ity_I32);
11183 delta += 2+1;
11184 src = eregOfRexRM(pfx,modrm);
11185 assign( t0, binop( Iop_And32,
11186 binop(Iop_Shr32, getXMMRegLane32(src,1), mkU8(31)),
11187 mkU32(1) ));
11188 assign( t1, binop( Iop_And32,
11189 binop(Iop_Shr32, getXMMRegLane32(src,3), mkU8(30)),
11190 mkU32(2) ));
11191 putIReg32( gregOfRexRM(pfx,modrm),
11192 binop(Iop_Or32, mkexpr(t0), mkexpr(t1))
11193 );
11194 DIP("movmskpd %s,%s\n", nameXMMReg(src),
11195 nameIReg32(gregOfRexRM(pfx,modrm)));
11196 goto decode_success;
11197 }
11198 /* else fall through */
11199 goto decode_failure;
11200 }
11201
sewardj02f79f12007-09-01 18:59:53 +000011202 /* 66 0F F7 = MASKMOVDQU -- store selected bytes of double quadword */
11203 if (have66noF2noF3(pfx) && sz == 2
11204 && insn[0] == 0x0F && insn[1] == 0xF7) {
11205 modrm = getUChar(delta+2);
11206 if (epartIsReg(modrm)) {
11207 IRTemp regD = newTemp(Ity_V128);
11208 IRTemp mask = newTemp(Ity_V128);
11209 IRTemp olddata = newTemp(Ity_V128);
11210 IRTemp newdata = newTemp(Ity_V128);
11211 addr = newTemp(Ity_I64);
11212
sewardj2e28ac42008-12-04 00:05:12 +000011213 assign( addr, handleAddrOverrides( vbi, pfx, getIReg64(R_RDI) ));
sewardj02f79f12007-09-01 18:59:53 +000011214 assign( regD, getXMMReg( gregOfRexRM(pfx,modrm) ));
11215
11216 /* Unfortunately can't do the obvious thing with SarN8x16
11217 here since that can't be re-emitted as SSE2 code - no such
11218 insn. */
11219 assign(
11220 mask,
11221 binop(Iop_64HLtoV128,
11222 binop(Iop_SarN8x8,
11223 getXMMRegLane64( eregOfRexRM(pfx,modrm), 1 ),
11224 mkU8(7) ),
11225 binop(Iop_SarN8x8,
11226 getXMMRegLane64( eregOfRexRM(pfx,modrm), 0 ),
11227 mkU8(7) ) ));
11228 assign( olddata, loadLE( Ity_V128, mkexpr(addr) ));
11229 assign( newdata,
11230 binop(Iop_OrV128,
11231 binop(Iop_AndV128,
11232 mkexpr(regD),
11233 mkexpr(mask) ),
11234 binop(Iop_AndV128,
11235 mkexpr(olddata),
11236 unop(Iop_NotV128, mkexpr(mask)))) );
11237 storeLE( mkexpr(addr), mkexpr(newdata) );
11238
11239 delta += 2+1;
11240 DIP("maskmovdqu %s,%s\n", nameXMMReg( eregOfRexRM(pfx,modrm) ),
11241 nameXMMReg( gregOfRexRM(pfx,modrm) ) );
11242 goto decode_success;
11243 }
11244 /* else fall through */
11245 }
11246
sewardj612be432005-05-11 02:55:54 +000011247 /* 66 0F E7 = MOVNTDQ -- for us, just a plain SSE store. */
11248 if (have66noF2noF3(pfx) && sz == 2
11249 && insn[0] == 0x0F && insn[1] == 0xE7) {
11250 modrm = getUChar(delta+2);
11251 if (!epartIsReg(modrm)) {
sewardj2e28ac42008-12-04 00:05:12 +000011252 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj612be432005-05-11 02:55:54 +000011253 storeLE( mkexpr(addr), getXMMReg(gregOfRexRM(pfx,modrm)) );
11254 DIP("movntdq %s,%s\n", dis_buf,
11255 nameXMMReg(gregOfRexRM(pfx,modrm)));
11256 delta += 2+alen;
11257 goto decode_success;
11258 }
11259 /* else fall through */
11260 goto decode_failure;
11261 }
sewardjf53b7352005-04-06 20:01:56 +000011262
11263 /* 0F C3 = MOVNTI -- for us, just a plain ireg store. */
11264 if (haveNo66noF2noF3(pfx) &&
11265 insn[0] == 0x0F && insn[1] == 0xC3) {
11266 vassert(sz == 4 || sz == 8);
11267 modrm = getUChar(delta+2);
11268 if (!epartIsReg(modrm)) {
sewardj2e28ac42008-12-04 00:05:12 +000011269 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardjf53b7352005-04-06 20:01:56 +000011270 storeLE( mkexpr(addr), getIRegG(sz, pfx, modrm) );
11271 DIP("movnti %s,%s\n", dis_buf,
11272 nameIRegG(sz, pfx, modrm));
11273 delta += 2+alen;
11274 goto decode_success;
11275 }
11276 /* else fall through */
11277 }
sewardj5cc00ff2005-03-27 04:48:32 +000011278
11279 /* 66 0F D6 = MOVQ -- move 64 bits from G (lo half xmm) to E (mem
11280 or lo half xmm). */
sewardjb4bf5882007-11-06 20:39:17 +000011281 if (have66noF2noF3(pfx)
11282 && (sz == 2 || /* ignore redundant REX.W */ sz == 8)
11283 && insn[0] == 0x0F && insn[1] == 0xD6) {
sewardj5cc00ff2005-03-27 04:48:32 +000011284 modrm = getUChar(delta+2);
11285 if (epartIsReg(modrm)) {
11286 /* fall through, awaiting test case */
sewardj94a48b22005-05-14 11:17:25 +000011287 /* dst: lo half copied, hi half zeroed */
sewardj5cc00ff2005-03-27 04:48:32 +000011288 } else {
sewardj2e28ac42008-12-04 00:05:12 +000011289 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj5cc00ff2005-03-27 04:48:32 +000011290 storeLE( mkexpr(addr),
11291 getXMMRegLane64( gregOfRexRM(pfx,modrm), 0 ));
11292 DIP("movq %s,%s\n", nameXMMReg(gregOfRexRM(pfx,modrm)), dis_buf );
11293 delta += 2+alen;
11294 goto decode_success;
11295 }
11296 }
11297
sewardj612be432005-05-11 02:55:54 +000011298 /* F3 0F D6 = MOVQ2DQ -- move from E (mmx) to G (lo half xmm, zero
11299 hi half). */
11300 if (haveF3no66noF2(pfx) && sz == 4
11301 && insn[0] == 0x0F && insn[1] == 0xD6) {
11302 modrm = getUChar(delta+2);
11303 if (epartIsReg(modrm)) {
11304 do_MMX_preamble();
11305 putXMMReg( gregOfRexRM(pfx,modrm),
11306 unop(Iop_64UtoV128, getMMXReg( eregLO3ofRM(modrm) )) );
11307 DIP("movq2dq %s,%s\n", nameMMXReg(eregLO3ofRM(modrm)),
11308 nameXMMReg(gregOfRexRM(pfx,modrm)));
11309 delta += 2+1;
11310 goto decode_success;
11311 } else {
11312 /* apparently no mem case for this insn */
11313 goto decode_failure;
11314 }
11315 }
11316
11317 /* F3 0F 7E = MOVQ -- move 64 bits from E (mem or lo half xmm) to
sewardj94a48b22005-05-14 11:17:25 +000011318 G (lo half xmm). Upper half of G is zeroed out. */
sewardj1001dc42005-02-21 08:25:55 +000011319 /* F2 0F 10 = MOVSD -- move 64 bits from E (mem or lo half xmm) to
11320 G (lo half xmm). If E is mem, upper half of G is zeroed out.
sewardj94a48b22005-05-14 11:17:25 +000011321 If E is reg, upper half of G is unchanged. */
sewardjb4bf5882007-11-06 20:39:17 +000011322 if ( (haveF2no66noF3(pfx)
11323 && (sz == 4 || /* ignore redundant REX.W */ sz == 8)
sewardj612be432005-05-11 02:55:54 +000011324 && insn[0] == 0x0F && insn[1] == 0x10)
sewardj5cc00ff2005-03-27 04:48:32 +000011325 ||
sewardjb4bf5882007-11-06 20:39:17 +000011326 (haveF3no66noF2(pfx)
11327 && (sz == 4 || /* ignore redundant REX.W */ sz == 8)
sewardj612be432005-05-11 02:55:54 +000011328 && insn[0] == 0x0F && insn[1] == 0x7E)
sewardj1001dc42005-02-21 08:25:55 +000011329 ) {
sewardj1001dc42005-02-21 08:25:55 +000011330 modrm = getUChar(delta+2);
11331 if (epartIsReg(modrm)) {
11332 putXMMRegLane64( gregOfRexRM(pfx,modrm), 0,
11333 getXMMRegLane64( eregOfRexRM(pfx,modrm), 0 ));
sewardj94a48b22005-05-14 11:17:25 +000011334 if (insn[1] == 0x7E/*MOVQ*/) {
11335 /* zero bits 127:64 */
11336 putXMMRegLane64( gregOfRexRM(pfx,modrm), 1, mkU64(0) );
11337 }
sewardj1001dc42005-02-21 08:25:55 +000011338 DIP("movsd %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
11339 nameXMMReg(gregOfRexRM(pfx,modrm)));
11340 delta += 2+1;
11341 } else {
sewardj2e28ac42008-12-04 00:05:12 +000011342 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj1001dc42005-02-21 08:25:55 +000011343 putXMMReg( gregOfRexRM(pfx,modrm), mkV128(0) );
11344 putXMMRegLane64( gregOfRexRM(pfx,modrm), 0,
11345 loadLE(Ity_I64, mkexpr(addr)) );
11346 DIP("movsd %s,%s\n", dis_buf,
11347 nameXMMReg(gregOfRexRM(pfx,modrm)));
11348 delta += 2+alen;
11349 }
11350 goto decode_success;
11351 }
11352
11353 /* F2 0F 11 = MOVSD -- move 64 bits from G (lo half xmm) to E (mem
11354 or lo half xmm). */
sewardjb4bf5882007-11-06 20:39:17 +000011355 if (haveF2no66noF3(pfx)
11356 && (sz == 4 || /* ignore redundant REX.W */ sz == 8)
sewardj8d965312005-02-25 02:48:47 +000011357 && insn[0] == 0x0F && insn[1] == 0x11) {
sewardj1001dc42005-02-21 08:25:55 +000011358 modrm = getUChar(delta+2);
11359 if (epartIsReg(modrm)) {
sewardje5e837c2008-11-04 11:31:44 +000011360 putXMMRegLane64( eregOfRexRM(pfx,modrm), 0,
11361 getXMMRegLane64( gregOfRexRM(pfx,modrm), 0 ));
11362 DIP("movsd %s,%s\n", nameXMMReg(gregOfRexRM(pfx,modrm)),
11363 nameXMMReg(eregOfRexRM(pfx,modrm)));
11364 delta += 2+1;
sewardj1001dc42005-02-21 08:25:55 +000011365 } else {
sewardj2e28ac42008-12-04 00:05:12 +000011366 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj1001dc42005-02-21 08:25:55 +000011367 storeLE( mkexpr(addr),
11368 getXMMRegLane64(gregOfRexRM(pfx,modrm), 0) );
11369 DIP("movsd %s,%s\n", nameXMMReg(gregOfRexRM(pfx,modrm)),
11370 dis_buf);
11371 delta += 2+alen;
sewardj1001dc42005-02-21 08:25:55 +000011372 }
sewardje5e837c2008-11-04 11:31:44 +000011373 goto decode_success;
sewardj1001dc42005-02-21 08:25:55 +000011374 }
11375
sewardj4c328cf2005-05-05 12:05:54 +000011376 /* 66 0F 59 = MULPD -- mul 64Fx2 from R/M to R */
sewardjb4bf5882007-11-06 20:39:17 +000011377 if (have66noF2noF3(pfx)
11378 && (sz == 2 || /* ignore redundant REX.W */ sz == 8)
sewardj4c328cf2005-05-05 12:05:54 +000011379 && insn[0] == 0x0F && insn[1] == 0x59) {
sewardj2e28ac42008-12-04 00:05:12 +000011380 delta = dis_SSE_E_to_G_all( vbi, pfx, delta+2, "mulpd", Iop_Mul64Fx2 );
sewardj4c328cf2005-05-05 12:05:54 +000011381 goto decode_success;
11382 }
sewardj1001dc42005-02-21 08:25:55 +000011383
11384 /* F2 0F 59 = MULSD -- mul 64F0x2 from R/M to R */
sewardjb4bf5882007-11-06 20:39:17 +000011385 if (haveF2no66noF3(pfx)
11386 && (sz == 4 || /* ignore redundant REX.W */ sz == 8)
sewardj8d965312005-02-25 02:48:47 +000011387 && insn[0] == 0x0F && insn[1] == 0x59) {
sewardj2e28ac42008-12-04 00:05:12 +000011388 delta = dis_SSE_E_to_G_lo64( vbi, pfx, delta+2, "mulsd", Iop_Mul64F0x2 );
sewardj1001dc42005-02-21 08:25:55 +000011389 goto decode_success;
11390 }
11391
sewardj8d965312005-02-25 02:48:47 +000011392 /* 66 0F 56 = ORPD -- G = G and E */
11393 if (have66noF2noF3(pfx) && sz == 2
11394 && insn[0] == 0x0F && insn[1] == 0x56) {
sewardj2e28ac42008-12-04 00:05:12 +000011395 delta = dis_SSE_E_to_G_all( vbi, pfx, delta+2, "orpd", Iop_OrV128 );
sewardj8d965312005-02-25 02:48:47 +000011396 goto decode_success;
11397 }
11398
sewardj09717342005-05-05 21:34:02 +000011399 /* 66 0F C6 /r ib = SHUFPD -- shuffle packed F64s */
11400 if (have66noF2noF3(pfx) && sz == 2
11401 && insn[0] == 0x0F && insn[1] == 0xC6) {
11402 Int select;
11403 IRTemp sV = newTemp(Ity_V128);
11404 IRTemp dV = newTemp(Ity_V128);
11405 IRTemp s1 = newTemp(Ity_I64);
11406 IRTemp s0 = newTemp(Ity_I64);
11407 IRTemp d1 = newTemp(Ity_I64);
11408 IRTemp d0 = newTemp(Ity_I64);
11409
11410 modrm = insn[2];
11411 assign( dV, getXMMReg(gregOfRexRM(pfx,modrm)) );
11412
11413 if (epartIsReg(modrm)) {
11414 assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
11415 select = (Int)insn[3];
11416 delta += 2+2;
11417 DIP("shufpd $%d,%s,%s\n", select,
11418 nameXMMReg(eregOfRexRM(pfx,modrm)),
11419 nameXMMReg(gregOfRexRM(pfx,modrm)));
11420 } else {
sewardj2e28ac42008-12-04 00:05:12 +000011421 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 1 );
sewardj09717342005-05-05 21:34:02 +000011422 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
11423 select = (Int)insn[2+alen];
11424 delta += 3+alen;
11425 DIP("shufpd $%d,%s,%s\n", select,
11426 dis_buf,
11427 nameXMMReg(gregOfRexRM(pfx,modrm)));
11428 }
11429
11430 assign( d1, unop(Iop_V128HIto64, mkexpr(dV)) );
11431 assign( d0, unop(Iop_V128to64, mkexpr(dV)) );
11432 assign( s1, unop(Iop_V128HIto64, mkexpr(sV)) );
11433 assign( s0, unop(Iop_V128to64, mkexpr(sV)) );
11434
11435# define SELD(n) mkexpr((n)==0 ? d0 : d1)
11436# define SELS(n) mkexpr((n)==0 ? s0 : s1)
11437
11438 putXMMReg(
11439 gregOfRexRM(pfx,modrm),
11440 binop(Iop_64HLtoV128, SELS((select>>1)&1), SELD((select>>0)&1) )
11441 );
11442
11443# undef SELD
11444# undef SELS
11445
11446 goto decode_success;
11447 }
11448
sewardj97628592005-05-10 22:42:54 +000011449 /* 66 0F 51 = SQRTPD -- approx sqrt 64Fx2 from R/M to R */
11450 if (have66noF2noF3(pfx) && sz == 2
11451 && insn[0] == 0x0F && insn[1] == 0x51) {
sewardj2e28ac42008-12-04 00:05:12 +000011452 delta = dis_SSE_E_to_G_unary_all( vbi, pfx, delta+2,
sewardj97628592005-05-10 22:42:54 +000011453 "sqrtpd", Iop_Sqrt64Fx2 );
11454 goto decode_success;
11455 }
sewardj1001dc42005-02-21 08:25:55 +000011456
11457 /* F2 0F 51 = SQRTSD -- approx sqrt 64F0x2 from R/M to R */
11458 if (haveF2no66noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x51) {
11459 vassert(sz == 4);
sewardj2e28ac42008-12-04 00:05:12 +000011460 delta = dis_SSE_E_to_G_unary_lo64( vbi, pfx, delta+2,
sewardj1001dc42005-02-21 08:25:55 +000011461 "sqrtsd", Iop_Sqrt64F0x2 );
11462 goto decode_success;
11463 }
11464
sewardj4c328cf2005-05-05 12:05:54 +000011465 /* 66 0F 5C = SUBPD -- sub 64Fx2 from R/M to R */
11466 if (have66noF2noF3(pfx) && sz == 2
11467 && insn[0] == 0x0F && insn[1] == 0x5C) {
sewardj2e28ac42008-12-04 00:05:12 +000011468 delta = dis_SSE_E_to_G_all( vbi, pfx, delta+2, "subpd", Iop_Sub64Fx2 );
sewardj4c328cf2005-05-05 12:05:54 +000011469 goto decode_success;
11470 }
sewardj1001dc42005-02-21 08:25:55 +000011471
11472 /* F2 0F 5C = SUBSD -- sub 64F0x2 from R/M to R */
sewardjb4bf5882007-11-06 20:39:17 +000011473 if (haveF2no66noF3(pfx)
11474 && (sz == 4 || /* ignore redundant REX.W */ sz == 8)
11475 && insn[0] == 0x0F && insn[1] == 0x5C) {
sewardj2e28ac42008-12-04 00:05:12 +000011476 delta = dis_SSE_E_to_G_lo64( vbi, pfx, delta+2, "subsd", Iop_Sub64F0x2 );
sewardj1001dc42005-02-21 08:25:55 +000011477 goto decode_success;
11478 }
11479
sewardj1a01e652005-02-23 11:39:21 +000011480 /* 66 0F 15 = UNPCKHPD -- unpack and interleave high part F64s */
11481 /* 66 0F 14 = UNPCKLPD -- unpack and interleave low part F64s */
11482 /* These just appear to be special cases of SHUFPS */
11483 if (have66noF2noF3(pfx)
11484 && sz == 2 /* could be 8 if rex also present */
11485 && insn[0] == 0x0F && (insn[1] == 0x15 || insn[1] == 0x14)) {
11486 IRTemp s1 = newTemp(Ity_I64);
11487 IRTemp s0 = newTemp(Ity_I64);
11488 IRTemp d1 = newTemp(Ity_I64);
11489 IRTemp d0 = newTemp(Ity_I64);
11490 IRTemp sV = newTemp(Ity_V128);
11491 IRTemp dV = newTemp(Ity_V128);
sewardj1027dc22005-02-26 01:55:02 +000011492 Bool hi = toBool(insn[1] == 0x15);
sewardj1a01e652005-02-23 11:39:21 +000011493
11494 modrm = insn[2];
11495 assign( dV, getXMMReg(gregOfRexRM(pfx,modrm)) );
11496
11497 if (epartIsReg(modrm)) {
11498 assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
11499 delta += 2+1;
11500 DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
11501 nameXMMReg(eregOfRexRM(pfx,modrm)),
11502 nameXMMReg(gregOfRexRM(pfx,modrm)));
11503 } else {
sewardj2e28ac42008-12-04 00:05:12 +000011504 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj1a01e652005-02-23 11:39:21 +000011505 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
11506 delta += 2+alen;
11507 DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
11508 dis_buf,
11509 nameXMMReg(gregOfRexRM(pfx,modrm)));
11510 }
11511
11512 assign( d1, unop(Iop_V128HIto64, mkexpr(dV)) );
11513 assign( d0, unop(Iop_V128to64, mkexpr(dV)) );
11514 assign( s1, unop(Iop_V128HIto64, mkexpr(sV)) );
11515 assign( s0, unop(Iop_V128to64, mkexpr(sV)) );
11516
11517 if (hi) {
11518 putXMMReg( gregOfRexRM(pfx,modrm),
11519 binop(Iop_64HLtoV128, mkexpr(s1), mkexpr(d1)) );
11520 } else {
11521 putXMMReg( gregOfRexRM(pfx,modrm),
11522 binop(Iop_64HLtoV128, mkexpr(s0), mkexpr(d0)) );
11523 }
11524
11525 goto decode_success;
11526 }
sewardj9da16972005-02-21 13:58:26 +000011527
11528 /* 66 0F 57 = XORPD -- G = G xor E */
sewardj97628592005-05-10 22:42:54 +000011529 if (have66noF2noF3(pfx) && sz == 2
11530 && insn[0] == 0x0F && insn[1] == 0x57) {
sewardj2e28ac42008-12-04 00:05:12 +000011531 delta = dis_SSE_E_to_G_all( vbi, pfx, delta+2, "xorpd", Iop_XorV128 );
sewardj9da16972005-02-21 13:58:26 +000011532 goto decode_success;
11533 }
11534
sewardj97628592005-05-10 22:42:54 +000011535 /* 66 0F 6B = PACKSSDW */
11536 if (have66noF2noF3(pfx) && sz == 2
11537 && insn[0] == 0x0F && insn[1] == 0x6B) {
sewardj2e28ac42008-12-04 00:05:12 +000011538 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardj97628592005-05-10 22:42:54 +000011539 "packssdw", Iop_QNarrow32Sx4, True );
11540 goto decode_success;
11541 }
11542
11543 /* 66 0F 63 = PACKSSWB */
11544 if (have66noF2noF3(pfx) && sz == 2
11545 && insn[0] == 0x0F && insn[1] == 0x63) {
sewardj2e28ac42008-12-04 00:05:12 +000011546 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardj97628592005-05-10 22:42:54 +000011547 "packsswb", Iop_QNarrow16Sx8, True );
11548 goto decode_success;
11549 }
11550
11551 /* 66 0F 67 = PACKUSWB */
11552 if (have66noF2noF3(pfx) && sz == 2
11553 && insn[0] == 0x0F && insn[1] == 0x67) {
sewardj2e28ac42008-12-04 00:05:12 +000011554 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardj97628592005-05-10 22:42:54 +000011555 "packuswb", Iop_QNarrow16Ux8, True );
11556 goto decode_success;
11557 }
11558
11559 /* 66 0F FC = PADDB */
11560 if (have66noF2noF3(pfx) && sz == 2
11561 && insn[0] == 0x0F && insn[1] == 0xFC) {
sewardj2e28ac42008-12-04 00:05:12 +000011562 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardj97628592005-05-10 22:42:54 +000011563 "paddb", Iop_Add8x16, False );
11564 goto decode_success;
11565 }
11566
11567 /* 66 0F FE = PADDD */
11568 if (have66noF2noF3(pfx) && sz == 2
11569 && insn[0] == 0x0F && insn[1] == 0xFE) {
sewardj2e28ac42008-12-04 00:05:12 +000011570 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardj97628592005-05-10 22:42:54 +000011571 "paddd", Iop_Add32x4, False );
11572 goto decode_success;
11573 }
sewardj8711f662005-05-09 17:52:56 +000011574
11575 /* ***--- this is an MMX class insn introduced in SSE2 ---*** */
11576 /* 0F D4 = PADDQ -- add 64x1 */
11577 if (haveNo66noF2noF3(pfx) && sz == 4
11578 && insn[0] == 0x0F && insn[1] == 0xD4) {
11579 do_MMX_preamble();
11580 delta = dis_MMXop_regmem_to_reg (
sewardj2e28ac42008-12-04 00:05:12 +000011581 vbi, pfx, delta+2, insn[1], "paddq", False );
sewardj8711f662005-05-09 17:52:56 +000011582 goto decode_success;
11583 }
sewardj09717342005-05-05 21:34:02 +000011584
11585 /* 66 0F D4 = PADDQ */
11586 if (have66noF2noF3(pfx) && sz == 2
11587 && insn[0] == 0x0F && insn[1] == 0xD4) {
sewardj2e28ac42008-12-04 00:05:12 +000011588 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardj09717342005-05-05 21:34:02 +000011589 "paddq", Iop_Add64x2, False );
11590 goto decode_success;
11591 }
11592
sewardj5992bd02005-05-11 02:13:42 +000011593 /* 66 0F FD = PADDW */
11594 if (have66noF2noF3(pfx) && sz == 2
11595 && insn[0] == 0x0F && insn[1] == 0xFD) {
sewardj2e28ac42008-12-04 00:05:12 +000011596 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardj5992bd02005-05-11 02:13:42 +000011597 "paddw", Iop_Add16x8, False );
11598 goto decode_success;
11599 }
11600
11601 /* 66 0F EC = PADDSB */
11602 if (have66noF2noF3(pfx) && sz == 2
11603 && insn[0] == 0x0F && insn[1] == 0xEC) {
sewardj2e28ac42008-12-04 00:05:12 +000011604 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardj5992bd02005-05-11 02:13:42 +000011605 "paddsb", Iop_QAdd8Sx16, False );
11606 goto decode_success;
11607 }
11608
11609 /* 66 0F ED = PADDSW */
11610 if (have66noF2noF3(pfx) && sz == 2
11611 && insn[0] == 0x0F && insn[1] == 0xED) {
sewardj2e28ac42008-12-04 00:05:12 +000011612 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardj5992bd02005-05-11 02:13:42 +000011613 "paddsw", Iop_QAdd16Sx8, False );
11614 goto decode_success;
11615 }
11616
11617 /* 66 0F DC = PADDUSB */
11618 if (have66noF2noF3(pfx) && sz == 2
11619 && insn[0] == 0x0F && insn[1] == 0xDC) {
sewardj2e28ac42008-12-04 00:05:12 +000011620 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardj5992bd02005-05-11 02:13:42 +000011621 "paddusb", Iop_QAdd8Ux16, False );
11622 goto decode_success;
11623 }
11624
11625 /* 66 0F DD = PADDUSW */
11626 if (have66noF2noF3(pfx) && sz == 2
11627 && insn[0] == 0x0F && insn[1] == 0xDD) {
sewardj2e28ac42008-12-04 00:05:12 +000011628 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardj5992bd02005-05-11 02:13:42 +000011629 "paddusw", Iop_QAdd16Ux8, False );
11630 goto decode_success;
11631 }
sewardj09717342005-05-05 21:34:02 +000011632
11633 /* 66 0F DB = PAND */
11634 if (have66noF2noF3(pfx) && sz == 2
11635 && insn[0] == 0x0F && insn[1] == 0xDB) {
sewardj2e28ac42008-12-04 00:05:12 +000011636 delta = dis_SSE_E_to_G_all( vbi, pfx, delta+2, "pand", Iop_AndV128 );
sewardj09717342005-05-05 21:34:02 +000011637 goto decode_success;
11638 }
11639
sewardj5992bd02005-05-11 02:13:42 +000011640 /* 66 0F DF = PANDN */
11641 if (have66noF2noF3(pfx) && sz == 2
11642 && insn[0] == 0x0F && insn[1] == 0xDF) {
sewardj2e28ac42008-12-04 00:05:12 +000011643 delta = dis_SSE_E_to_G_all_invG( vbi, pfx, delta+2, "pandn", Iop_AndV128 );
sewardj5992bd02005-05-11 02:13:42 +000011644 goto decode_success;
11645 }
11646
11647 /* 66 0F E0 = PAVGB */
11648 if (have66noF2noF3(pfx) && sz == 2
11649 && insn[0] == 0x0F && insn[1] == 0xE0) {
sewardj2e28ac42008-12-04 00:05:12 +000011650 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardj5992bd02005-05-11 02:13:42 +000011651 "pavgb", Iop_Avg8Ux16, False );
11652 goto decode_success;
11653 }
11654
11655 /* 66 0F E3 = PAVGW */
11656 if (have66noF2noF3(pfx) && sz == 2
11657 && insn[0] == 0x0F && insn[1] == 0xE3) {
sewardj2e28ac42008-12-04 00:05:12 +000011658 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardj5992bd02005-05-11 02:13:42 +000011659 "pavgw", Iop_Avg16Ux8, False );
11660 goto decode_success;
11661 }
11662
11663 /* 66 0F 74 = PCMPEQB */
11664 if (have66noF2noF3(pfx) && sz == 2
11665 && insn[0] == 0x0F && insn[1] == 0x74) {
sewardj2e28ac42008-12-04 00:05:12 +000011666 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardj5992bd02005-05-11 02:13:42 +000011667 "pcmpeqb", Iop_CmpEQ8x16, False );
11668 goto decode_success;
11669 }
11670
11671 /* 66 0F 76 = PCMPEQD */
11672 if (have66noF2noF3(pfx) && sz == 2
11673 && insn[0] == 0x0F && insn[1] == 0x76) {
sewardj2e28ac42008-12-04 00:05:12 +000011674 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardj5992bd02005-05-11 02:13:42 +000011675 "pcmpeqd", Iop_CmpEQ32x4, False );
11676 goto decode_success;
11677 }
11678
11679 /* 66 0F 75 = PCMPEQW */
11680 if (have66noF2noF3(pfx) && sz == 2
11681 && insn[0] == 0x0F && insn[1] == 0x75) {
sewardj2e28ac42008-12-04 00:05:12 +000011682 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardj5992bd02005-05-11 02:13:42 +000011683 "pcmpeqw", Iop_CmpEQ16x8, False );
11684 goto decode_success;
11685 }
11686
11687 /* 66 0F 64 = PCMPGTB */
11688 if (have66noF2noF3(pfx) && sz == 2
11689 && insn[0] == 0x0F && insn[1] == 0x64) {
sewardj2e28ac42008-12-04 00:05:12 +000011690 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardj5992bd02005-05-11 02:13:42 +000011691 "pcmpgtb", Iop_CmpGT8Sx16, False );
11692 goto decode_success;
11693 }
11694
11695 /* 66 0F 66 = PCMPGTD */
11696 if (have66noF2noF3(pfx) && sz == 2
11697 && insn[0] == 0x0F && insn[1] == 0x66) {
sewardj2e28ac42008-12-04 00:05:12 +000011698 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardj5992bd02005-05-11 02:13:42 +000011699 "pcmpgtd", Iop_CmpGT32Sx4, False );
11700 goto decode_success;
11701 }
11702
11703 /* 66 0F 65 = PCMPGTW */
11704 if (have66noF2noF3(pfx) && sz == 2
11705 && insn[0] == 0x0F && insn[1] == 0x65) {
sewardj2e28ac42008-12-04 00:05:12 +000011706 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardj5992bd02005-05-11 02:13:42 +000011707 "pcmpgtw", Iop_CmpGT16Sx8, False );
11708 goto decode_success;
11709 }
sewardj97628592005-05-10 22:42:54 +000011710
11711 /* 66 0F C5 = PEXTRW -- extract 16-bit field from xmm(E) and put
11712 zero-extend of it in ireg(G). */
sewardj7bdd1bc2008-12-13 16:49:46 +000011713 if (have66noF2noF3(pfx)
11714 && (sz == 2 || /* ignore redundant REX.W */ sz == 8)
sewardj97628592005-05-10 22:42:54 +000011715 && insn[0] == 0x0F && insn[1] == 0xC5) {
11716 modrm = insn[2];
11717 if (epartIsReg(modrm)) {
11718 t5 = newTemp(Ity_V128);
11719 t4 = newTemp(Ity_I16);
11720 assign(t5, getXMMReg(eregOfRexRM(pfx,modrm)));
11721 breakup128to32s( t5, &t3, &t2, &t1, &t0 );
11722 switch (insn[3] & 7) {
11723 case 0: assign(t4, unop(Iop_32to16, mkexpr(t0))); break;
11724 case 1: assign(t4, unop(Iop_32HIto16, mkexpr(t0))); break;
11725 case 2: assign(t4, unop(Iop_32to16, mkexpr(t1))); break;
11726 case 3: assign(t4, unop(Iop_32HIto16, mkexpr(t1))); break;
11727 case 4: assign(t4, unop(Iop_32to16, mkexpr(t2))); break;
11728 case 5: assign(t4, unop(Iop_32HIto16, mkexpr(t2))); break;
11729 case 6: assign(t4, unop(Iop_32to16, mkexpr(t3))); break;
11730 case 7: assign(t4, unop(Iop_32HIto16, mkexpr(t3))); break;
11731 default: vassert(0);
11732 }
11733 putIReg32(gregOfRexRM(pfx,modrm), unop(Iop_16Uto32, mkexpr(t4)));
11734 DIP("pextrw $%d,%s,%s\n",
11735 (Int)insn[3], nameXMMReg(eregOfRexRM(pfx,modrm)),
11736 nameIReg32(gregOfRexRM(pfx,modrm)));
11737 delta += 4;
11738 goto decode_success;
11739 }
11740 /* else fall through */
11741 /* note, if memory case is ever filled in, there is 1 byte after
11742 amode */
11743 }
11744
11745 /* 66 0F C4 = PINSRW -- get 16 bits from E(mem or low half ireg) and
11746 put it into the specified lane of xmm(G). */
sewardj7bdd1bc2008-12-13 16:49:46 +000011747 if (have66noF2noF3(pfx)
11748 && (sz == 2 || /* ignore redundant REX.W */ sz == 8)
sewardj97628592005-05-10 22:42:54 +000011749 && insn[0] == 0x0F && insn[1] == 0xC4) {
11750 Int lane;
11751 t4 = newTemp(Ity_I16);
11752 modrm = insn[2];
11753
11754 if (epartIsReg(modrm)) {
11755 assign(t4, getIReg16(eregOfRexRM(pfx,modrm)));
11756 delta += 3+1;
11757 lane = insn[3+1-1];
11758 DIP("pinsrw $%d,%s,%s\n", (Int)lane,
11759 nameIReg16(eregOfRexRM(pfx,modrm)),
11760 nameXMMReg(gregOfRexRM(pfx,modrm)));
11761 } else {
sewardj2e28ac42008-12-04 00:05:12 +000011762 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf,
sewardj97628592005-05-10 22:42:54 +000011763 1/*byte after the amode*/ );
11764 delta += 3+alen;
11765 lane = insn[3+alen-1];
11766 assign(t4, loadLE(Ity_I16, mkexpr(addr)));
11767 DIP("pinsrw $%d,%s,%s\n", (Int)lane,
11768 dis_buf,
11769 nameXMMReg(gregOfRexRM(pfx,modrm)));
11770 }
11771
11772 putXMMRegLane16( gregOfRexRM(pfx,modrm), lane & 7, mkexpr(t4) );
11773 goto decode_success;
11774 }
11775
sewardjdb859032006-04-08 16:15:53 +000011776 /* 66 0F F5 = PMADDWD -- Multiply and add packed integers from
11777 E(xmm or mem) to G(xmm) */
11778 if (have66noF2noF3(pfx) && sz == 2
11779 && insn[0] == 0x0F && insn[1] == 0xF5) {
11780 IRTemp s1V = newTemp(Ity_V128);
11781 IRTemp s2V = newTemp(Ity_V128);
11782 IRTemp dV = newTemp(Ity_V128);
11783 IRTemp s1Hi = newTemp(Ity_I64);
11784 IRTemp s1Lo = newTemp(Ity_I64);
11785 IRTemp s2Hi = newTemp(Ity_I64);
11786 IRTemp s2Lo = newTemp(Ity_I64);
11787 IRTemp dHi = newTemp(Ity_I64);
11788 IRTemp dLo = newTemp(Ity_I64);
11789 modrm = insn[2];
11790 if (epartIsReg(modrm)) {
11791 assign( s1V, getXMMReg(eregOfRexRM(pfx,modrm)) );
11792 delta += 2+1;
11793 DIP("pmaddwd %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
11794 nameXMMReg(gregOfRexRM(pfx,modrm)));
11795 } else {
sewardj2e28ac42008-12-04 00:05:12 +000011796 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardjdb859032006-04-08 16:15:53 +000011797 assign( s1V, loadLE(Ity_V128, mkexpr(addr)) );
11798 delta += 2+alen;
11799 DIP("pmaddwd %s,%s\n", dis_buf,
11800 nameXMMReg(gregOfRexRM(pfx,modrm)));
11801 }
11802 assign( s2V, getXMMReg(gregOfRexRM(pfx,modrm)) );
11803 assign( s1Hi, unop(Iop_V128HIto64, mkexpr(s1V)) );
11804 assign( s1Lo, unop(Iop_V128to64, mkexpr(s1V)) );
11805 assign( s2Hi, unop(Iop_V128HIto64, mkexpr(s2V)) );
11806 assign( s2Lo, unop(Iop_V128to64, mkexpr(s2V)) );
11807 assign( dHi, mkIRExprCCall(
11808 Ity_I64, 0/*regparms*/,
11809 "amd64g_calculate_mmx_pmaddwd",
11810 &amd64g_calculate_mmx_pmaddwd,
11811 mkIRExprVec_2( mkexpr(s1Hi), mkexpr(s2Hi))
11812 ));
11813 assign( dLo, mkIRExprCCall(
11814 Ity_I64, 0/*regparms*/,
11815 "amd64g_calculate_mmx_pmaddwd",
11816 &amd64g_calculate_mmx_pmaddwd,
11817 mkIRExprVec_2( mkexpr(s1Lo), mkexpr(s2Lo))
11818 ));
11819 assign( dV, binop(Iop_64HLtoV128, mkexpr(dHi), mkexpr(dLo))) ;
11820 putXMMReg(gregOfRexRM(pfx,modrm), mkexpr(dV));
11821 goto decode_success;
11822 }
11823
sewardjadffcef2005-05-11 00:03:06 +000011824 /* 66 0F EE = PMAXSW -- 16x8 signed max */
11825 if (have66noF2noF3(pfx) && sz == 2
11826 && insn[0] == 0x0F && insn[1] == 0xEE) {
sewardj2e28ac42008-12-04 00:05:12 +000011827 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardjadffcef2005-05-11 00:03:06 +000011828 "pmaxsw", Iop_Max16Sx8, False );
11829 goto decode_success;
11830 }
11831
11832 /* 66 0F DE = PMAXUB -- 8x16 unsigned max */
11833 if (have66noF2noF3(pfx) && sz == 2
11834 && insn[0] == 0x0F && insn[1] == 0xDE) {
sewardj2e28ac42008-12-04 00:05:12 +000011835 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardjadffcef2005-05-11 00:03:06 +000011836 "pmaxub", Iop_Max8Ux16, False );
11837 goto decode_success;
11838 }
11839
11840 /* 66 0F EA = PMINSW -- 16x8 signed min */
11841 if (have66noF2noF3(pfx) && sz == 2
11842 && insn[0] == 0x0F && insn[1] == 0xEA) {
sewardj2e28ac42008-12-04 00:05:12 +000011843 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardjadffcef2005-05-11 00:03:06 +000011844 "pminsw", Iop_Min16Sx8, False );
11845 goto decode_success;
11846 }
11847
11848 /* 66 0F DA = PMINUB -- 8x16 unsigned min */
11849 if (have66noF2noF3(pfx) && sz == 2
11850 && insn[0] == 0x0F && insn[1] == 0xDA) {
sewardj2e28ac42008-12-04 00:05:12 +000011851 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardjadffcef2005-05-11 00:03:06 +000011852 "pminub", Iop_Min8Ux16, False );
11853 goto decode_success;
11854 }
11855
11856 /* 66 0F D7 = PMOVMSKB -- extract sign bits from each of 16 lanes in
11857 xmm(E), turn them into a byte, and put zero-extend of it in
11858 ireg(G). Doing this directly is just too cumbersome; give up
11859 therefore and call a helper. */
11860 /* UInt x86g_calculate_sse_pmovmskb ( ULong w64hi, ULong w64lo ); */
sewardj7bdd1bc2008-12-13 16:49:46 +000011861 if (have66noF2noF3(pfx)
11862 && (sz == 2 || /* ignore redundant REX.W */ sz == 8)
sewardjadffcef2005-05-11 00:03:06 +000011863 && insn[0] == 0x0F && insn[1] == 0xD7) {
11864 modrm = insn[2];
11865 if (epartIsReg(modrm)) {
11866 t0 = newTemp(Ity_I64);
11867 t1 = newTemp(Ity_I64);
11868 assign(t0, getXMMRegLane64(eregOfRexRM(pfx,modrm), 0));
11869 assign(t1, getXMMRegLane64(eregOfRexRM(pfx,modrm), 1));
11870 t5 = newTemp(Ity_I64);
11871 assign(t5, mkIRExprCCall(
11872 Ity_I64, 0/*regparms*/,
11873 "amd64g_calculate_sse_pmovmskb",
11874 &amd64g_calculate_sse_pmovmskb,
11875 mkIRExprVec_2( mkexpr(t1), mkexpr(t0) )));
11876 putIReg32(gregOfRexRM(pfx,modrm), unop(Iop_64to32,mkexpr(t5)));
11877 DIP("pmovmskb %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
11878 nameIReg32(gregOfRexRM(pfx,modrm)));
11879 delta += 3;
11880 goto decode_success;
11881 }
11882 /* else fall through */
11883 }
11884
11885 /* 66 0F E4 = PMULHUW -- 16x8 hi-half of unsigned widening multiply */
11886 if (have66noF2noF3(pfx) && sz == 2
11887 && insn[0] == 0x0F && insn[1] == 0xE4) {
sewardj2e28ac42008-12-04 00:05:12 +000011888 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardjadffcef2005-05-11 00:03:06 +000011889 "pmulhuw", Iop_MulHi16Ux8, False );
11890 goto decode_success;
11891 }
11892
11893 /* 66 0F E5 = PMULHW -- 16x8 hi-half of signed widening multiply */
11894 if (have66noF2noF3(pfx) && sz == 2
11895 && insn[0] == 0x0F && insn[1] == 0xE5) {
sewardj2e28ac42008-12-04 00:05:12 +000011896 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardjadffcef2005-05-11 00:03:06 +000011897 "pmulhw", Iop_MulHi16Sx8, False );
11898 goto decode_success;
11899 }
11900
11901 /* 66 0F D5 = PMULHL -- 16x8 multiply */
11902 if (have66noF2noF3(pfx) && sz == 2
11903 && insn[0] == 0x0F && insn[1] == 0xD5) {
sewardj2e28ac42008-12-04 00:05:12 +000011904 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardjadffcef2005-05-11 00:03:06 +000011905 "pmullw", Iop_Mul16x8, False );
11906 goto decode_success;
11907 }
11908
11909 /* ***--- this is an MMX class insn introduced in SSE2 ---*** */
11910 /* 0F F4 = PMULUDQ -- unsigned widening multiply of 32-lanes 0 x
11911 0 to form 64-bit result */
11912 if (haveNo66noF2noF3(pfx) && sz == 4
11913 && insn[0] == 0x0F && insn[1] == 0xF4) {
11914 IRTemp sV = newTemp(Ity_I64);
11915 IRTemp dV = newTemp(Ity_I64);
11916 t1 = newTemp(Ity_I32);
11917 t0 = newTemp(Ity_I32);
11918 modrm = insn[2];
11919
11920 do_MMX_preamble();
11921 assign( dV, getMMXReg(gregLO3ofRM(modrm)) );
11922
11923 if (epartIsReg(modrm)) {
11924 assign( sV, getMMXReg(eregLO3ofRM(modrm)) );
11925 delta += 2+1;
11926 DIP("pmuludq %s,%s\n", nameMMXReg(eregLO3ofRM(modrm)),
11927 nameMMXReg(gregLO3ofRM(modrm)));
11928 } else {
sewardj2e28ac42008-12-04 00:05:12 +000011929 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardjadffcef2005-05-11 00:03:06 +000011930 assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
11931 delta += 2+alen;
11932 DIP("pmuludq %s,%s\n", dis_buf,
11933 nameMMXReg(gregLO3ofRM(modrm)));
11934 }
11935
11936 assign( t0, unop(Iop_64to32, mkexpr(dV)) );
11937 assign( t1, unop(Iop_64to32, mkexpr(sV)) );
11938 putMMXReg( gregLO3ofRM(modrm),
11939 binop( Iop_MullU32, mkexpr(t0), mkexpr(t1) ) );
11940 goto decode_success;
11941 }
11942
11943 /* 66 0F F4 = PMULUDQ -- unsigned widening multiply of 32-lanes 0 x
11944 0 to form lower 64-bit half and lanes 2 x 2 to form upper 64-bit
11945 half */
11946 /* This is a really poor translation -- could be improved if
11947 performance critical */
11948 if (have66noF2noF3(pfx) && sz == 2
11949 && insn[0] == 0x0F && insn[1] == 0xF4) {
11950 IRTemp sV, dV;
11951 IRTemp s3, s2, s1, s0, d3, d2, d1, d0;
11952 sV = newTemp(Ity_V128);
11953 dV = newTemp(Ity_V128);
11954 s3 = s2 = s1 = s0 = d3 = d2 = d1 = d0 = IRTemp_INVALID;
11955 t1 = newTemp(Ity_I64);
11956 t0 = newTemp(Ity_I64);
11957 modrm = insn[2];
11958 assign( dV, getXMMReg(gregOfRexRM(pfx,modrm)) );
11959
11960 if (epartIsReg(modrm)) {
11961 assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
11962 delta += 2+1;
11963 DIP("pmuludq %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
11964 nameXMMReg(gregOfRexRM(pfx,modrm)));
11965 } else {
sewardj2e28ac42008-12-04 00:05:12 +000011966 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardjadffcef2005-05-11 00:03:06 +000011967 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
11968 delta += 2+alen;
11969 DIP("pmuludq %s,%s\n", dis_buf,
11970 nameXMMReg(gregOfRexRM(pfx,modrm)));
11971 }
11972
11973 breakup128to32s( dV, &d3, &d2, &d1, &d0 );
11974 breakup128to32s( sV, &s3, &s2, &s1, &s0 );
11975
11976 assign( t0, binop( Iop_MullU32, mkexpr(d0), mkexpr(s0)) );
11977 putXMMRegLane64( gregOfRexRM(pfx,modrm), 0, mkexpr(t0) );
11978 assign( t1, binop( Iop_MullU32, mkexpr(d2), mkexpr(s2)) );
11979 putXMMRegLane64( gregOfRexRM(pfx,modrm), 1, mkexpr(t1) );
11980 goto decode_success;
11981 }
sewardj09717342005-05-05 21:34:02 +000011982
11983 /* 66 0F EB = POR */
11984 if (have66noF2noF3(pfx) && sz == 2
11985 && insn[0] == 0x0F && insn[1] == 0xEB) {
sewardj2e28ac42008-12-04 00:05:12 +000011986 delta = dis_SSE_E_to_G_all( vbi, pfx, delta+2, "por", Iop_OrV128 );
sewardj09717342005-05-05 21:34:02 +000011987 goto decode_success;
11988 }
11989
sewardj59e96c12006-07-24 08:51:16 +000011990 /* 66 0F F6 = PSADBW -- 2 x (8x8 -> 48 zeroes ++ u16) Sum Abs Diffs
11991 from E(xmm or mem) to G(xmm) */
11992 if (have66noF2noF3(pfx) && sz == 2
11993 && insn[0] == 0x0F && insn[1] == 0xF6) {
11994 IRTemp s1V = newTemp(Ity_V128);
11995 IRTemp s2V = newTemp(Ity_V128);
11996 IRTemp dV = newTemp(Ity_V128);
11997 IRTemp s1Hi = newTemp(Ity_I64);
11998 IRTemp s1Lo = newTemp(Ity_I64);
11999 IRTemp s2Hi = newTemp(Ity_I64);
12000 IRTemp s2Lo = newTemp(Ity_I64);
12001 IRTemp dHi = newTemp(Ity_I64);
12002 IRTemp dLo = newTemp(Ity_I64);
12003 modrm = insn[2];
12004 if (epartIsReg(modrm)) {
12005 assign( s1V, getXMMReg(eregOfRexRM(pfx,modrm)) );
12006 delta += 2+1;
12007 DIP("psadbw %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
12008 nameXMMReg(gregOfRexRM(pfx,modrm)));
12009 } else {
sewardj2e28ac42008-12-04 00:05:12 +000012010 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj59e96c12006-07-24 08:51:16 +000012011 assign( s1V, loadLE(Ity_V128, mkexpr(addr)) );
12012 delta += 2+alen;
12013 DIP("psadbw %s,%s\n", dis_buf,
12014 nameXMMReg(gregOfRexRM(pfx,modrm)));
12015 }
12016 assign( s2V, getXMMReg(gregOfRexRM(pfx,modrm)) );
12017 assign( s1Hi, unop(Iop_V128HIto64, mkexpr(s1V)) );
12018 assign( s1Lo, unop(Iop_V128to64, mkexpr(s1V)) );
12019 assign( s2Hi, unop(Iop_V128HIto64, mkexpr(s2V)) );
12020 assign( s2Lo, unop(Iop_V128to64, mkexpr(s2V)) );
12021 assign( dHi, mkIRExprCCall(
12022 Ity_I64, 0/*regparms*/,
12023 "amd64g_calculate_mmx_psadbw",
12024 &amd64g_calculate_mmx_psadbw,
12025 mkIRExprVec_2( mkexpr(s1Hi), mkexpr(s2Hi))
12026 ));
12027 assign( dLo, mkIRExprCCall(
12028 Ity_I64, 0/*regparms*/,
12029 "amd64g_calculate_mmx_psadbw",
12030 &amd64g_calculate_mmx_psadbw,
12031 mkIRExprVec_2( mkexpr(s1Lo), mkexpr(s2Lo))
12032 ));
12033 assign( dV, binop(Iop_64HLtoV128, mkexpr(dHi), mkexpr(dLo))) ;
12034 putXMMReg(gregOfRexRM(pfx,modrm), mkexpr(dV));
12035 goto decode_success;
12036 }
12037
sewardjadffcef2005-05-11 00:03:06 +000012038 /* 66 0F 70 = PSHUFD -- rearrange 4x32 from E(xmm or mem) to G(xmm) */
12039 if (have66noF2noF3(pfx) && sz == 2
12040 && insn[0] == 0x0F && insn[1] == 0x70) {
12041 Int order;
12042 IRTemp sV, dV, s3, s2, s1, s0;
12043 s3 = s2 = s1 = s0 = IRTemp_INVALID;
12044 sV = newTemp(Ity_V128);
12045 dV = newTemp(Ity_V128);
12046 modrm = insn[2];
12047 if (epartIsReg(modrm)) {
12048 assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
12049 order = (Int)insn[3];
12050 delta += 3+1;
12051 DIP("pshufd $%d,%s,%s\n", order,
12052 nameXMMReg(eregOfRexRM(pfx,modrm)),
12053 nameXMMReg(gregOfRexRM(pfx,modrm)));
12054 } else {
sewardj2e28ac42008-12-04 00:05:12 +000012055 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf,
sewardjadffcef2005-05-11 00:03:06 +000012056 1/*byte after the amode*/ );
12057 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
12058 order = (Int)insn[2+alen];
12059 delta += 2+alen+1;
12060 DIP("pshufd $%d,%s,%s\n", order,
12061 dis_buf,
12062 nameXMMReg(gregOfRexRM(pfx,modrm)));
12063 }
12064 breakup128to32s( sV, &s3, &s2, &s1, &s0 );
12065
12066# define SEL(n) \
12067 ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
12068 assign(dV,
12069 mk128from32s( SEL((order>>6)&3), SEL((order>>4)&3),
12070 SEL((order>>2)&3), SEL((order>>0)&3) )
12071 );
12072 putXMMReg(gregOfRexRM(pfx,modrm), mkexpr(dV));
12073# undef SEL
12074 goto decode_success;
12075 }
12076
12077 /* F3 0F 70 = PSHUFHW -- rearrange upper half 4x16 from E(xmm or
12078 mem) to G(xmm), and copy lower half */
12079 if (haveF3no66noF2(pfx) && sz == 4
12080 && insn[0] == 0x0F && insn[1] == 0x70) {
12081 Int order;
12082 IRTemp sVhi, dVhi, sV, dV, s3, s2, s1, s0;
12083 s3 = s2 = s1 = s0 = IRTemp_INVALID;
12084 sV = newTemp(Ity_V128);
12085 dV = newTemp(Ity_V128);
12086 sVhi = newTemp(Ity_I64);
12087 dVhi = newTemp(Ity_I64);
12088 modrm = insn[2];
12089 if (epartIsReg(modrm)) {
12090 assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
12091 order = (Int)insn[3];
12092 delta += 3+1;
12093 DIP("pshufhw $%d,%s,%s\n", order,
12094 nameXMMReg(eregOfRexRM(pfx,modrm)),
12095 nameXMMReg(gregOfRexRM(pfx,modrm)));
12096 } else {
sewardj2e28ac42008-12-04 00:05:12 +000012097 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf,
sewardjadffcef2005-05-11 00:03:06 +000012098 1/*byte after the amode*/ );
12099 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
12100 order = (Int)insn[2+alen];
12101 delta += 2+alen+1;
12102 DIP("pshufhw $%d,%s,%s\n", order,
12103 dis_buf,
12104 nameXMMReg(gregOfRexRM(pfx,modrm)));
12105 }
12106 assign( sVhi, unop(Iop_V128HIto64, mkexpr(sV)) );
12107 breakup64to16s( sVhi, &s3, &s2, &s1, &s0 );
12108
12109# define SEL(n) \
12110 ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
12111 assign(dVhi,
12112 mk64from16s( SEL((order>>6)&3), SEL((order>>4)&3),
12113 SEL((order>>2)&3), SEL((order>>0)&3) )
12114 );
12115 assign(dV, binop( Iop_64HLtoV128,
12116 mkexpr(dVhi),
12117 unop(Iop_V128to64, mkexpr(sV))) );
12118 putXMMReg(gregOfRexRM(pfx,modrm), mkexpr(dV));
12119# undef SEL
12120 goto decode_success;
12121 }
12122
12123 /* F2 0F 70 = PSHUFLW -- rearrange lower half 4x16 from E(xmm or
12124 mem) to G(xmm), and copy upper half */
12125 if (haveF2no66noF3(pfx) && sz == 4
12126 && insn[0] == 0x0F && insn[1] == 0x70) {
12127 Int order;
12128 IRTemp sVlo, dVlo, sV, dV, s3, s2, s1, s0;
12129 s3 = s2 = s1 = s0 = IRTemp_INVALID;
12130 sV = newTemp(Ity_V128);
12131 dV = newTemp(Ity_V128);
12132 sVlo = newTemp(Ity_I64);
12133 dVlo = newTemp(Ity_I64);
12134 modrm = insn[2];
12135 if (epartIsReg(modrm)) {
12136 assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
12137 order = (Int)insn[3];
12138 delta += 3+1;
12139 DIP("pshuflw $%d,%s,%s\n", order,
12140 nameXMMReg(eregOfRexRM(pfx,modrm)),
12141 nameXMMReg(gregOfRexRM(pfx,modrm)));
12142 } else {
sewardj2e28ac42008-12-04 00:05:12 +000012143 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf,
sewardjadffcef2005-05-11 00:03:06 +000012144 1/*byte after the amode*/ );
12145 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
12146 order = (Int)insn[2+alen];
12147 delta += 2+alen+1;
12148 DIP("pshuflw $%d,%s,%s\n", order,
12149 dis_buf,
12150 nameXMMReg(gregOfRexRM(pfx,modrm)));
12151 }
12152 assign( sVlo, unop(Iop_V128to64, mkexpr(sV)) );
12153 breakup64to16s( sVlo, &s3, &s2, &s1, &s0 );
12154
12155# define SEL(n) \
12156 ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
12157 assign(dVlo,
12158 mk64from16s( SEL((order>>6)&3), SEL((order>>4)&3),
12159 SEL((order>>2)&3), SEL((order>>0)&3) )
12160 );
12161 assign(dV, binop( Iop_64HLtoV128,
12162 unop(Iop_V128HIto64, mkexpr(sV)),
12163 mkexpr(dVlo) ) );
12164 putXMMReg(gregOfRexRM(pfx,modrm), mkexpr(dV));
12165# undef SEL
12166 goto decode_success;
12167 }
12168
12169 /* 66 0F 72 /6 ib = PSLLD by immediate */
12170 if (have66noF2noF3(pfx) && sz == 2
12171 && insn[0] == 0x0F && insn[1] == 0x72
12172 && epartIsReg(insn[2])
12173 && gregLO3ofRM(insn[2]) == 6) {
12174 delta = dis_SSE_shiftE_imm( pfx, delta+2, "pslld", Iop_ShlN32x4 );
12175 goto decode_success;
12176 }
12177
12178 /* 66 0F F2 = PSLLD by E */
12179 if (have66noF2noF3(pfx) && sz == 2
12180 && insn[0] == 0x0F && insn[1] == 0xF2) {
sewardj2e28ac42008-12-04 00:05:12 +000012181 delta = dis_SSE_shiftG_byE( vbi, pfx, delta+2, "pslld", Iop_ShlN32x4 );
sewardjadffcef2005-05-11 00:03:06 +000012182 goto decode_success;
12183 }
sewardj97628592005-05-10 22:42:54 +000012184
12185 /* 66 0F 73 /7 ib = PSLLDQ by immediate */
12186 /* note, if mem case ever filled in, 1 byte after amode */
12187 if (have66noF2noF3(pfx) && sz == 2
12188 && insn[0] == 0x0F && insn[1] == 0x73
12189 && epartIsReg(insn[2])
12190 && gregLO3ofRM(insn[2]) == 7) {
12191 IRTemp sV, dV, hi64, lo64, hi64r, lo64r;
12192 Int imm = (Int)insn[3];
12193 Int reg = eregOfRexRM(pfx,insn[2]);
12194 DIP("pslldq $%d,%s\n", imm, nameXMMReg(reg));
12195 vassert(imm >= 0 && imm <= 255);
12196 delta += 4;
12197
12198 sV = newTemp(Ity_V128);
12199 dV = newTemp(Ity_V128);
12200 hi64 = newTemp(Ity_I64);
12201 lo64 = newTemp(Ity_I64);
12202 hi64r = newTemp(Ity_I64);
12203 lo64r = newTemp(Ity_I64);
12204
12205 if (imm >= 16) {
12206 putXMMReg(reg, mkV128(0x0000));
12207 goto decode_success;
12208 }
12209
12210 assign( sV, getXMMReg(reg) );
12211 assign( hi64, unop(Iop_V128HIto64, mkexpr(sV)) );
12212 assign( lo64, unop(Iop_V128to64, mkexpr(sV)) );
12213
12214 if (imm == 0) {
12215 assign( lo64r, mkexpr(lo64) );
12216 assign( hi64r, mkexpr(hi64) );
12217 }
12218 else
12219 if (imm == 8) {
12220 assign( lo64r, mkU64(0) );
12221 assign( hi64r, mkexpr(lo64) );
12222 }
12223 else
12224 if (imm > 8) {
12225 assign( lo64r, mkU64(0) );
12226 assign( hi64r, binop( Iop_Shl64,
12227 mkexpr(lo64),
12228 mkU8( 8*(imm-8) ) ));
12229 } else {
12230 assign( lo64r, binop( Iop_Shl64,
12231 mkexpr(lo64),
12232 mkU8(8 * imm) ));
12233 assign( hi64r,
12234 binop( Iop_Or64,
12235 binop(Iop_Shl64, mkexpr(hi64),
12236 mkU8(8 * imm)),
12237 binop(Iop_Shr64, mkexpr(lo64),
12238 mkU8(8 * (8 - imm)) )
12239 )
12240 );
12241 }
12242 assign( dV, binop(Iop_64HLtoV128, mkexpr(hi64r), mkexpr(lo64r)) );
12243 putXMMReg(reg, mkexpr(dV));
12244 goto decode_success;
12245 }
12246
sewardjadffcef2005-05-11 00:03:06 +000012247 /* 66 0F 73 /6 ib = PSLLQ by immediate */
12248 if (have66noF2noF3(pfx) && sz == 2
12249 && insn[0] == 0x0F && insn[1] == 0x73
12250 && epartIsReg(insn[2])
12251 && gregLO3ofRM(insn[2]) == 6) {
12252 delta = dis_SSE_shiftE_imm( pfx, delta+2, "psllq", Iop_ShlN64x2 );
12253 goto decode_success;
12254 }
12255
12256 /* 66 0F F3 = PSLLQ by E */
12257 if (have66noF2noF3(pfx) && sz == 2
12258 && insn[0] == 0x0F && insn[1] == 0xF3) {
sewardj2e28ac42008-12-04 00:05:12 +000012259 delta = dis_SSE_shiftG_byE( vbi, pfx, delta+2, "psllq", Iop_ShlN64x2 );
sewardjadffcef2005-05-11 00:03:06 +000012260 goto decode_success;
12261 }
12262
12263 /* 66 0F 71 /6 ib = PSLLW by immediate */
12264 if (have66noF2noF3(pfx) && sz == 2
12265 && insn[0] == 0x0F && insn[1] == 0x71
12266 && epartIsReg(insn[2])
12267 && gregLO3ofRM(insn[2]) == 6) {
12268 delta = dis_SSE_shiftE_imm( pfx, delta+2, "psllw", Iop_ShlN16x8 );
12269 goto decode_success;
12270 }
12271
12272 /* 66 0F F1 = PSLLW by E */
12273 if (have66noF2noF3(pfx) && sz == 2
12274 && insn[0] == 0x0F && insn[1] == 0xF1) {
sewardj2e28ac42008-12-04 00:05:12 +000012275 delta = dis_SSE_shiftG_byE( vbi, pfx, delta+2, "psllw", Iop_ShlN16x8 );
sewardjadffcef2005-05-11 00:03:06 +000012276 goto decode_success;
12277 }
12278
12279 /* 66 0F 72 /4 ib = PSRAD by immediate */
12280 if (have66noF2noF3(pfx) && sz == 2
12281 && insn[0] == 0x0F && insn[1] == 0x72
12282 && epartIsReg(insn[2])
12283 && gregLO3ofRM(insn[2]) == 4) {
12284 delta = dis_SSE_shiftE_imm( pfx, delta+2, "psrad", Iop_SarN32x4 );
12285 goto decode_success;
12286 }
12287
12288 /* 66 0F E2 = PSRAD by E */
12289 if (have66noF2noF3(pfx) && sz == 2
12290 && insn[0] == 0x0F && insn[1] == 0xE2) {
sewardj2e28ac42008-12-04 00:05:12 +000012291 delta = dis_SSE_shiftG_byE( vbi, pfx, delta+2, "psrad", Iop_SarN32x4 );
sewardjadffcef2005-05-11 00:03:06 +000012292 goto decode_success;
12293 }
12294
12295 /* 66 0F 71 /4 ib = PSRAW by immediate */
12296 if (have66noF2noF3(pfx) && sz == 2
12297 && insn[0] == 0x0F && insn[1] == 0x71
12298 && epartIsReg(insn[2])
12299 && gregLO3ofRM(insn[2]) == 4) {
12300 delta = dis_SSE_shiftE_imm( pfx, delta+2, "psraw", Iop_SarN16x8 );
12301 goto decode_success;
12302 }
12303
12304 /* 66 0F E1 = PSRAW by E */
12305 if (have66noF2noF3(pfx) && sz == 2
12306 && insn[0] == 0x0F && insn[1] == 0xE1) {
sewardj2e28ac42008-12-04 00:05:12 +000012307 delta = dis_SSE_shiftG_byE( vbi, pfx, delta+2, "psraw", Iop_SarN16x8 );
sewardjadffcef2005-05-11 00:03:06 +000012308 goto decode_success;
12309 }
12310
12311 /* 66 0F 72 /2 ib = PSRLD by immediate */
12312 if (have66noF2noF3(pfx) && sz == 2
12313 && insn[0] == 0x0F && insn[1] == 0x72
12314 && epartIsReg(insn[2])
12315 && gregLO3ofRM(insn[2]) == 2) {
12316 delta = dis_SSE_shiftE_imm( pfx, delta+2, "psrld", Iop_ShrN32x4 );
12317 goto decode_success;
12318 }
12319
12320 /* 66 0F D2 = PSRLD by E */
12321 if (have66noF2noF3(pfx) && sz == 2
12322 && insn[0] == 0x0F && insn[1] == 0xD2) {
sewardj2e28ac42008-12-04 00:05:12 +000012323 delta = dis_SSE_shiftG_byE( vbi, pfx, delta+2, "psrld", Iop_ShrN32x4 );
sewardjadffcef2005-05-11 00:03:06 +000012324 goto decode_success;
12325 }
sewardj97628592005-05-10 22:42:54 +000012326
12327 /* 66 0F 73 /3 ib = PSRLDQ by immediate */
12328 /* note, if mem case ever filled in, 1 byte after amode */
12329 if (have66noF2noF3(pfx) && sz == 2
12330 && insn[0] == 0x0F && insn[1] == 0x73
12331 && epartIsReg(insn[2])
12332 && gregLO3ofRM(insn[2]) == 3) {
12333 IRTemp sV, dV, hi64, lo64, hi64r, lo64r;
12334 Int imm = (Int)insn[3];
12335 Int reg = eregOfRexRM(pfx,insn[2]);
12336 DIP("psrldq $%d,%s\n", imm, nameXMMReg(reg));
12337 vassert(imm >= 0 && imm <= 255);
12338 delta += 4;
12339
12340 sV = newTemp(Ity_V128);
12341 dV = newTemp(Ity_V128);
12342 hi64 = newTemp(Ity_I64);
12343 lo64 = newTemp(Ity_I64);
12344 hi64r = newTemp(Ity_I64);
12345 lo64r = newTemp(Ity_I64);
12346
12347 if (imm >= 16) {
12348 putXMMReg(reg, mkV128(0x0000));
12349 goto decode_success;
12350 }
12351
12352 assign( sV, getXMMReg(reg) );
12353 assign( hi64, unop(Iop_V128HIto64, mkexpr(sV)) );
12354 assign( lo64, unop(Iop_V128to64, mkexpr(sV)) );
12355
12356 if (imm == 0) {
12357 assign( lo64r, mkexpr(lo64) );
12358 assign( hi64r, mkexpr(hi64) );
12359 }
12360 else
12361 if (imm == 8) {
12362 assign( hi64r, mkU64(0) );
12363 assign( lo64r, mkexpr(hi64) );
12364 }
12365 else
12366 if (imm > 8) {
12367 assign( hi64r, mkU64(0) );
12368 assign( lo64r, binop( Iop_Shr64,
12369 mkexpr(hi64),
12370 mkU8( 8*(imm-8) ) ));
12371 } else {
12372 assign( hi64r, binop( Iop_Shr64,
12373 mkexpr(hi64),
12374 mkU8(8 * imm) ));
12375 assign( lo64r,
12376 binop( Iop_Or64,
12377 binop(Iop_Shr64, mkexpr(lo64),
12378 mkU8(8 * imm)),
12379 binop(Iop_Shl64, mkexpr(hi64),
12380 mkU8(8 * (8 - imm)) )
12381 )
12382 );
12383 }
12384
12385 assign( dV, binop(Iop_64HLtoV128, mkexpr(hi64r), mkexpr(lo64r)) );
12386 putXMMReg(reg, mkexpr(dV));
12387 goto decode_success;
12388 }
sewardj09717342005-05-05 21:34:02 +000012389
12390 /* 66 0F 73 /2 ib = PSRLQ by immediate */
12391 if (have66noF2noF3(pfx) && sz == 2
12392 && insn[0] == 0x0F && insn[1] == 0x73
12393 && epartIsReg(insn[2])
12394 && gregLO3ofRM(insn[2]) == 2) {
12395 delta = dis_SSE_shiftE_imm( pfx, delta+2, "psrlq", Iop_ShrN64x2 );
12396 goto decode_success;
12397 }
12398
sewardjadffcef2005-05-11 00:03:06 +000012399 /* 66 0F D3 = PSRLQ by E */
12400 if (have66noF2noF3(pfx) && sz == 2
12401 && insn[0] == 0x0F && insn[1] == 0xD3) {
sewardj2e28ac42008-12-04 00:05:12 +000012402 delta = dis_SSE_shiftG_byE( vbi, pfx, delta+2, "psrlq", Iop_ShrN64x2 );
sewardjadffcef2005-05-11 00:03:06 +000012403 goto decode_success;
12404 }
12405
12406 /* 66 0F 71 /2 ib = PSRLW by immediate */
12407 if (have66noF2noF3(pfx) && sz == 2
12408 && insn[0] == 0x0F && insn[1] == 0x71
12409 && epartIsReg(insn[2])
12410 && gregLO3ofRM(insn[2]) == 2) {
12411 delta = dis_SSE_shiftE_imm( pfx, delta+2, "psrlw", Iop_ShrN16x8 );
12412 goto decode_success;
12413 }
12414
12415 /* 66 0F D1 = PSRLW by E */
12416 if (have66noF2noF3(pfx) && sz == 2
12417 && insn[0] == 0x0F && insn[1] == 0xD1) {
sewardj2e28ac42008-12-04 00:05:12 +000012418 delta = dis_SSE_shiftG_byE( vbi, pfx, delta+2, "psrlw", Iop_ShrN16x8 );
sewardjadffcef2005-05-11 00:03:06 +000012419 goto decode_success;
12420 }
sewardj97628592005-05-10 22:42:54 +000012421
12422 /* 66 0F F8 = PSUBB */
12423 if (have66noF2noF3(pfx) && sz == 2
12424 && insn[0] == 0x0F && insn[1] == 0xF8) {
sewardj2e28ac42008-12-04 00:05:12 +000012425 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardj97628592005-05-10 22:42:54 +000012426 "psubb", Iop_Sub8x16, False );
12427 goto decode_success;
12428 }
12429
12430 /* 66 0F FA = PSUBD */
12431 if (have66noF2noF3(pfx) && sz == 2
12432 && insn[0] == 0x0F && insn[1] == 0xFA) {
sewardj2e28ac42008-12-04 00:05:12 +000012433 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardj97628592005-05-10 22:42:54 +000012434 "psubd", Iop_Sub32x4, False );
12435 goto decode_success;
12436 }
sewardj8711f662005-05-09 17:52:56 +000012437
12438 /* ***--- this is an MMX class insn introduced in SSE2 ---*** */
12439 /* 0F FB = PSUBQ -- sub 64x1 */
12440 if (haveNo66noF2noF3(pfx) && sz == 4
12441 && insn[0] == 0x0F && insn[1] == 0xFB) {
12442 do_MMX_preamble();
12443 delta = dis_MMXop_regmem_to_reg (
sewardj2e28ac42008-12-04 00:05:12 +000012444 vbi, pfx, delta+2, insn[1], "psubq", False );
sewardj8711f662005-05-09 17:52:56 +000012445 goto decode_success;
12446 }
sewardj09717342005-05-05 21:34:02 +000012447
12448 /* 66 0F FB = PSUBQ */
12449 if (have66noF2noF3(pfx) && sz == 2
12450 && insn[0] == 0x0F && insn[1] == 0xFB) {
sewardj2e28ac42008-12-04 00:05:12 +000012451 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardj09717342005-05-05 21:34:02 +000012452 "psubq", Iop_Sub64x2, False );
12453 goto decode_success;
12454 }
12455
sewardj97628592005-05-10 22:42:54 +000012456 /* 66 0F F9 = PSUBW */
12457 if (have66noF2noF3(pfx) && sz == 2
12458 && insn[0] == 0x0F && insn[1] == 0xF9) {
sewardj2e28ac42008-12-04 00:05:12 +000012459 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardj97628592005-05-10 22:42:54 +000012460 "psubw", Iop_Sub16x8, False );
12461 goto decode_success;
12462 }
12463
12464 /* 66 0F E8 = PSUBSB */
12465 if (have66noF2noF3(pfx) && sz == 2
12466 && insn[0] == 0x0F && insn[1] == 0xE8) {
sewardj2e28ac42008-12-04 00:05:12 +000012467 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardj97628592005-05-10 22:42:54 +000012468 "psubsb", Iop_QSub8Sx16, False );
12469 goto decode_success;
12470 }
12471
12472 /* 66 0F E9 = PSUBSW */
12473 if (have66noF2noF3(pfx) && sz == 2
12474 && insn[0] == 0x0F && insn[1] == 0xE9) {
sewardj2e28ac42008-12-04 00:05:12 +000012475 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardj97628592005-05-10 22:42:54 +000012476 "psubsw", Iop_QSub16Sx8, False );
12477 goto decode_success;
12478 }
12479
12480 /* 66 0F D8 = PSUBSB */
12481 if (have66noF2noF3(pfx) && sz == 2
12482 && insn[0] == 0x0F && insn[1] == 0xD8) {
sewardj2e28ac42008-12-04 00:05:12 +000012483 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardj97628592005-05-10 22:42:54 +000012484 "psubusb", Iop_QSub8Ux16, False );
12485 goto decode_success;
12486 }
12487
12488 /* 66 0F D9 = PSUBSW */
12489 if (have66noF2noF3(pfx) && sz == 2
12490 && insn[0] == 0x0F && insn[1] == 0xD9) {
sewardj2e28ac42008-12-04 00:05:12 +000012491 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardj97628592005-05-10 22:42:54 +000012492 "psubusw", Iop_QSub16Ux8, False );
12493 goto decode_success;
12494 }
12495
12496 /* 66 0F 68 = PUNPCKHBW */
12497 if (have66noF2noF3(pfx) && sz == 2
12498 && insn[0] == 0x0F && insn[1] == 0x68) {
sewardj2e28ac42008-12-04 00:05:12 +000012499 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardj97628592005-05-10 22:42:54 +000012500 "punpckhbw",
12501 Iop_InterleaveHI8x16, True );
12502 goto decode_success;
12503 }
12504
12505 /* 66 0F 6A = PUNPCKHDQ */
12506 if (have66noF2noF3(pfx) && sz == 2
12507 && insn[0] == 0x0F && insn[1] == 0x6A) {
sewardj2e28ac42008-12-04 00:05:12 +000012508 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardj97628592005-05-10 22:42:54 +000012509 "punpckhdq",
12510 Iop_InterleaveHI32x4, True );
12511 goto decode_success;
12512 }
12513
12514 /* 66 0F 6D = PUNPCKHQDQ */
12515 if (have66noF2noF3(pfx) && sz == 2
12516 && insn[0] == 0x0F && insn[1] == 0x6D) {
sewardj2e28ac42008-12-04 00:05:12 +000012517 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardj97628592005-05-10 22:42:54 +000012518 "punpckhqdq",
12519 Iop_InterleaveHI64x2, True );
12520 goto decode_success;
12521 }
12522
12523 /* 66 0F 69 = PUNPCKHWD */
12524 if (have66noF2noF3(pfx) && sz == 2
12525 && insn[0] == 0x0F && insn[1] == 0x69) {
sewardj2e28ac42008-12-04 00:05:12 +000012526 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardj97628592005-05-10 22:42:54 +000012527 "punpckhwd",
12528 Iop_InterleaveHI16x8, True );
12529 goto decode_success;
12530 }
12531
12532 /* 66 0F 60 = PUNPCKLBW */
12533 if (have66noF2noF3(pfx) && sz == 2
12534 && insn[0] == 0x0F && insn[1] == 0x60) {
sewardj2e28ac42008-12-04 00:05:12 +000012535 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardj97628592005-05-10 22:42:54 +000012536 "punpcklbw",
12537 Iop_InterleaveLO8x16, True );
12538 goto decode_success;
12539 }
12540
12541 /* 66 0F 62 = PUNPCKLDQ */
12542 if (have66noF2noF3(pfx) && sz == 2
12543 && insn[0] == 0x0F && insn[1] == 0x62) {
sewardj2e28ac42008-12-04 00:05:12 +000012544 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardj97628592005-05-10 22:42:54 +000012545 "punpckldq",
12546 Iop_InterleaveLO32x4, True );
12547 goto decode_success;
12548 }
12549
12550 /* 66 0F 6C = PUNPCKLQDQ */
12551 if (have66noF2noF3(pfx) && sz == 2
12552 && insn[0] == 0x0F && insn[1] == 0x6C) {
sewardj2e28ac42008-12-04 00:05:12 +000012553 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardj97628592005-05-10 22:42:54 +000012554 "punpcklqdq",
12555 Iop_InterleaveLO64x2, True );
12556 goto decode_success;
12557 }
12558
12559 /* 66 0F 61 = PUNPCKLWD */
12560 if (have66noF2noF3(pfx) && sz == 2
12561 && insn[0] == 0x0F && insn[1] == 0x61) {
sewardj2e28ac42008-12-04 00:05:12 +000012562 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardj97628592005-05-10 22:42:54 +000012563 "punpcklwd",
12564 Iop_InterleaveLO16x8, True );
12565 goto decode_success;
12566 }
sewardj09717342005-05-05 21:34:02 +000012567
12568 /* 66 0F EF = PXOR */
12569 if (have66noF2noF3(pfx) && sz == 2
12570 && insn[0] == 0x0F && insn[1] == 0xEF) {
sewardj2e28ac42008-12-04 00:05:12 +000012571 delta = dis_SSE_E_to_G_all( vbi, pfx, delta+2, "pxor", Iop_XorV128 );
sewardj09717342005-05-05 21:34:02 +000012572 goto decode_success;
12573 }
12574
sewardjd20c8852005-01-20 20:04:07 +000012575//.. //-- /* FXSAVE/FXRSTOR m32 -- load/store the FPU/MMX/SSE state. */
12576//.. //-- if (insn[0] == 0x0F && insn[1] == 0xAE
12577//.. //-- && (!epartIsReg(insn[2]))
12578//.. //-- && (gregOfRM(insn[2]) == 1 || gregOfRM(insn[2]) == 0) ) {
12579//.. //-- Bool store = gregOfRM(insn[2]) == 0;
12580//.. //-- vg_assert(sz == 4);
12581//.. //-- pair = disAMode ( cb, sorb, eip+2, dis_buf );
12582//.. //-- t1 = LOW24(pair);
12583//.. //-- eip += 2+HI8(pair);
12584//.. //-- uInstr3(cb, store ? SSE2a_MemWr : SSE2a_MemRd, 512,
12585//.. //-- Lit16, (((UShort)insn[0]) << 8) | (UShort)insn[1],
12586//.. //-- Lit16, (UShort)insn[2],
12587//.. //-- TempReg, t1 );
12588//.. //-- DIP("fx%s %s\n", store ? "save" : "rstor", dis_buf );
12589//.. //-- goto decode_success;
12590//.. //-- }
sewardj3e616e62006-01-07 22:58:54 +000012591
12592 /* 0F AE /7 = CLFLUSH -- flush cache line */
12593 if (haveNo66noF2noF3(pfx) && sz == 4
12594 && insn[0] == 0x0F && insn[1] == 0xAE
12595 && !epartIsReg(insn[2]) && gregLO3ofRM(insn[2]) == 7) {
12596
12597 /* This is something of a hack. We need to know the size of the
12598 cache line containing addr. Since we don't (easily), assume
12599 256 on the basis that no real cache would have a line that
12600 big. It's safe to invalidate more stuff than we need, just
12601 inefficient. */
12602 ULong lineszB = 256ULL;
12603
sewardj2e28ac42008-12-04 00:05:12 +000012604 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj3e616e62006-01-07 22:58:54 +000012605 delta += 2+alen;
12606
12607 /* Round addr down to the start of the containing block. */
12608 stmt( IRStmt_Put(
12609 OFFB_TISTART,
12610 binop( Iop_And64,
12611 mkexpr(addr),
12612 mkU64( ~(lineszB-1) ))) );
12613
12614 stmt( IRStmt_Put(OFFB_TILEN, mkU64(lineszB) ) );
12615
sewardjdd40fdf2006-12-24 02:20:24 +000012616 irsb->jumpkind = Ijk_TInval;
12617 irsb->next = mkU64(guest_RIP_bbstart+delta);
sewardj3e616e62006-01-07 22:58:54 +000012618 dres.whatNext = Dis_StopHere;
12619
12620 DIP("clflush %s\n", dis_buf);
12621 goto decode_success;
12622 }
sewardjdf0e0022005-01-25 15:48:43 +000012623
sewardjdf0e0022005-01-25 15:48:43 +000012624 /* ---------------------------------------------------- */
12625 /* --- end of the SSE/SSE2 decoder. --- */
12626 /* ---------------------------------------------------- */
12627
sewardjfcf21f32006-08-04 14:51:19 +000012628 /* ---------------------------------------------------- */
12629 /* --- start of the SSE3 decoder. --- */
12630 /* ---------------------------------------------------- */
12631
12632 /* F3 0F 12 = MOVSLDUP -- move from E (mem or xmm) to G (xmm),
12633 duplicating some lanes (2:2:0:0). */
12634 /* F3 0F 16 = MOVSHDUP -- move from E (mem or xmm) to G (xmm),
12635 duplicating some lanes (3:3:1:1). */
12636 if (haveF3no66noF2(pfx) && sz == 4
12637 && insn[0] == 0x0F && (insn[1] == 0x12 || insn[1] == 0x16)) {
12638 IRTemp s3, s2, s1, s0;
12639 IRTemp sV = newTemp(Ity_V128);
12640 Bool isH = insn[1] == 0x16;
12641 s3 = s2 = s1 = s0 = IRTemp_INVALID;
12642
12643 modrm = insn[2];
12644 if (epartIsReg(modrm)) {
12645 assign( sV, getXMMReg( eregOfRexRM(pfx,modrm)) );
12646 DIP("movs%cdup %s,%s\n", isH ? 'h' : 'l',
12647 nameXMMReg(eregOfRexRM(pfx,modrm)),
12648 nameXMMReg(gregOfRexRM(pfx,modrm)));
12649 delta += 2+1;
12650 } else {
sewardj2e28ac42008-12-04 00:05:12 +000012651 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardjfcf21f32006-08-04 14:51:19 +000012652 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
12653 DIP("movs%cdup %s,%s\n", isH ? 'h' : 'l',
12654 dis_buf,
12655 nameXMMReg(gregOfRexRM(pfx,modrm)));
12656 delta += 2+alen;
12657 }
12658
12659 breakup128to32s( sV, &s3, &s2, &s1, &s0 );
12660 putXMMReg( gregOfRexRM(pfx,modrm),
12661 isH ? mk128from32s( s3, s3, s1, s1 )
12662 : mk128from32s( s2, s2, s0, s0 ) );
12663 goto decode_success;
12664 }
12665
12666 /* F2 0F 12 = MOVDDUP -- move from E (mem or xmm) to G (xmm),
12667 duplicating some lanes (0:1:0:1). */
sewardjb4bf5882007-11-06 20:39:17 +000012668 if (haveF2no66noF3(pfx)
12669 && (sz == 4 || /* ignore redundant REX.W */ sz == 8)
sewardjfcf21f32006-08-04 14:51:19 +000012670 && insn[0] == 0x0F && insn[1] == 0x12) {
12671 IRTemp sV = newTemp(Ity_V128);
12672 IRTemp d0 = newTemp(Ity_I64);
12673
12674 modrm = insn[2];
12675 if (epartIsReg(modrm)) {
12676 assign( sV, getXMMReg( eregOfRexRM(pfx,modrm)) );
12677 DIP("movddup %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
12678 nameXMMReg(gregOfRexRM(pfx,modrm)));
12679 delta += 2+1;
12680 assign ( d0, unop(Iop_V128to64, mkexpr(sV)) );
12681 } else {
sewardj2e28ac42008-12-04 00:05:12 +000012682 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardjfcf21f32006-08-04 14:51:19 +000012683 assign( d0, loadLE(Ity_I64, mkexpr(addr)) );
12684 DIP("movddup %s,%s\n", dis_buf,
12685 nameXMMReg(gregOfRexRM(pfx,modrm)));
12686 delta += 2+alen;
12687 }
12688
12689 putXMMReg( gregOfRexRM(pfx,modrm),
12690 binop(Iop_64HLtoV128,mkexpr(d0),mkexpr(d0)) );
12691 goto decode_success;
12692 }
12693
12694 /* F2 0F D0 = ADDSUBPS -- 32x4 +/-/+/- from E (mem or xmm) to G (xmm). */
12695 if (haveF2no66noF3(pfx) && sz == 4
12696 && insn[0] == 0x0F && insn[1] == 0xD0) {
12697 IRTemp a3, a2, a1, a0, s3, s2, s1, s0;
12698 IRTemp eV = newTemp(Ity_V128);
12699 IRTemp gV = newTemp(Ity_V128);
12700 IRTemp addV = newTemp(Ity_V128);
12701 IRTemp subV = newTemp(Ity_V128);
12702 a3 = a2 = a1 = a0 = s3 = s2 = s1 = s0 = IRTemp_INVALID;
12703
12704 modrm = insn[2];
12705 if (epartIsReg(modrm)) {
12706 assign( eV, getXMMReg( eregOfRexRM(pfx,modrm)) );
12707 DIP("addsubps %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
12708 nameXMMReg(gregOfRexRM(pfx,modrm)));
12709 delta += 2+1;
12710 } else {
sewardj2e28ac42008-12-04 00:05:12 +000012711 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardjfcf21f32006-08-04 14:51:19 +000012712 assign( eV, loadLE(Ity_V128, mkexpr(addr)) );
12713 DIP("addsubps %s,%s\n", dis_buf,
12714 nameXMMReg(gregOfRexRM(pfx,modrm)));
12715 delta += 2+alen;
12716 }
12717
12718 assign( gV, getXMMReg(gregOfRexRM(pfx,modrm)) );
12719
12720 assign( addV, binop(Iop_Add32Fx4, mkexpr(gV), mkexpr(eV)) );
12721 assign( subV, binop(Iop_Sub32Fx4, mkexpr(gV), mkexpr(eV)) );
12722
12723 breakup128to32s( addV, &a3, &a2, &a1, &a0 );
12724 breakup128to32s( subV, &s3, &s2, &s1, &s0 );
12725
12726 putXMMReg( gregOfRexRM(pfx,modrm), mk128from32s( a3, s2, a1, s0 ));
12727 goto decode_success;
12728 }
12729
12730 /* 66 0F D0 = ADDSUBPD -- 64x4 +/- from E (mem or xmm) to G (xmm). */
12731 if (have66noF2noF3(pfx) && sz == 2
12732 && insn[0] == 0x0F && insn[1] == 0xD0) {
12733 IRTemp eV = newTemp(Ity_V128);
12734 IRTemp gV = newTemp(Ity_V128);
12735 IRTemp addV = newTemp(Ity_V128);
12736 IRTemp subV = newTemp(Ity_V128);
12737 IRTemp a1 = newTemp(Ity_I64);
12738 IRTemp s0 = newTemp(Ity_I64);
12739
12740 modrm = insn[2];
12741 if (epartIsReg(modrm)) {
12742 assign( eV, getXMMReg( eregOfRexRM(pfx,modrm)) );
12743 DIP("addsubpd %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
12744 nameXMMReg(gregOfRexRM(pfx,modrm)));
12745 delta += 2+1;
12746 } else {
sewardj2e28ac42008-12-04 00:05:12 +000012747 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardjfcf21f32006-08-04 14:51:19 +000012748 assign( eV, loadLE(Ity_V128, mkexpr(addr)) );
12749 DIP("addsubpd %s,%s\n", dis_buf,
12750 nameXMMReg(gregOfRexRM(pfx,modrm)));
12751 delta += 2+alen;
12752 }
12753
12754 assign( gV, getXMMReg(gregOfRexRM(pfx,modrm)) );
12755
12756 assign( addV, binop(Iop_Add64Fx2, mkexpr(gV), mkexpr(eV)) );
12757 assign( subV, binop(Iop_Sub64Fx2, mkexpr(gV), mkexpr(eV)) );
12758
12759 assign( a1, unop(Iop_V128HIto64, mkexpr(addV) ));
12760 assign( s0, unop(Iop_V128to64, mkexpr(subV) ));
12761
12762 putXMMReg( gregOfRexRM(pfx,modrm),
12763 binop(Iop_64HLtoV128, mkexpr(a1), mkexpr(s0)) );
12764 goto decode_success;
12765 }
12766
12767 /* F2 0F 7D = HSUBPS -- 32x4 sub across from E (mem or xmm) to G (xmm). */
12768 /* F2 0F 7C = HADDPS -- 32x4 add across from E (mem or xmm) to G (xmm). */
12769 if (haveF2no66noF3(pfx) && sz == 4
12770 && insn[0] == 0x0F && (insn[1] == 0x7C || insn[1] == 0x7D)) {
12771 IRTemp e3, e2, e1, e0, g3, g2, g1, g0;
12772 IRTemp eV = newTemp(Ity_V128);
12773 IRTemp gV = newTemp(Ity_V128);
12774 IRTemp leftV = newTemp(Ity_V128);
12775 IRTemp rightV = newTemp(Ity_V128);
12776 Bool isAdd = insn[1] == 0x7C;
12777 HChar* str = isAdd ? "add" : "sub";
12778 e3 = e2 = e1 = e0 = g3 = g2 = g1 = g0 = IRTemp_INVALID;
12779
12780 modrm = insn[2];
12781 if (epartIsReg(modrm)) {
12782 assign( eV, getXMMReg( eregOfRexRM(pfx,modrm)) );
12783 DIP("h%sps %s,%s\n", str, nameXMMReg(eregOfRexRM(pfx,modrm)),
12784 nameXMMReg(gregOfRexRM(pfx,modrm)));
12785 delta += 2+1;
12786 } else {
sewardj2e28ac42008-12-04 00:05:12 +000012787 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardjfcf21f32006-08-04 14:51:19 +000012788 assign( eV, loadLE(Ity_V128, mkexpr(addr)) );
12789 DIP("h%sps %s,%s\n", str, dis_buf,
12790 nameXMMReg(gregOfRexRM(pfx,modrm)));
12791 delta += 2+alen;
12792 }
12793
12794 assign( gV, getXMMReg(gregOfRexRM(pfx,modrm)) );
12795
12796 breakup128to32s( eV, &e3, &e2, &e1, &e0 );
12797 breakup128to32s( gV, &g3, &g2, &g1, &g0 );
12798
12799 assign( leftV, mk128from32s( e2, e0, g2, g0 ) );
12800 assign( rightV, mk128from32s( e3, e1, g3, g1 ) );
12801
12802 putXMMReg( gregOfRexRM(pfx,modrm),
12803 binop(isAdd ? Iop_Add32Fx4 : Iop_Sub32Fx4,
12804 mkexpr(leftV), mkexpr(rightV) ) );
12805 goto decode_success;
12806 }
12807
12808 /* 66 0F 7D = HSUBPD -- 64x2 sub across from E (mem or xmm) to G (xmm). */
12809 /* 66 0F 7C = HADDPD -- 64x2 add across from E (mem or xmm) to G (xmm). */
12810 if (have66noF2noF3(pfx) && sz == 2
12811 && insn[0] == 0x0F && (insn[1] == 0x7C || insn[1] == 0x7D)) {
12812 IRTemp e1 = newTemp(Ity_I64);
12813 IRTemp e0 = newTemp(Ity_I64);
12814 IRTemp g1 = newTemp(Ity_I64);
12815 IRTemp g0 = newTemp(Ity_I64);
12816 IRTemp eV = newTemp(Ity_V128);
12817 IRTemp gV = newTemp(Ity_V128);
12818 IRTemp leftV = newTemp(Ity_V128);
12819 IRTemp rightV = newTemp(Ity_V128);
12820 Bool isAdd = insn[1] == 0x7C;
12821 HChar* str = isAdd ? "add" : "sub";
12822
12823 modrm = insn[2];
12824 if (epartIsReg(modrm)) {
12825 assign( eV, getXMMReg( eregOfRexRM(pfx,modrm)) );
12826 DIP("h%spd %s,%s\n", str, nameXMMReg(eregOfRexRM(pfx,modrm)),
12827 nameXMMReg(gregOfRexRM(pfx,modrm)));
12828 delta += 2+1;
12829 } else {
sewardj2e28ac42008-12-04 00:05:12 +000012830 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardjfcf21f32006-08-04 14:51:19 +000012831 assign( eV, loadLE(Ity_V128, mkexpr(addr)) );
12832 DIP("h%spd %s,%s\n", str, dis_buf,
12833 nameXMMReg(gregOfRexRM(pfx,modrm)));
12834 delta += 2+alen;
12835 }
12836
12837 assign( gV, getXMMReg(gregOfRexRM(pfx,modrm)) );
12838
12839 assign( e1, unop(Iop_V128HIto64, mkexpr(eV) ));
12840 assign( e0, unop(Iop_V128to64, mkexpr(eV) ));
12841 assign( g1, unop(Iop_V128HIto64, mkexpr(gV) ));
12842 assign( g0, unop(Iop_V128to64, mkexpr(gV) ));
12843
12844 assign( leftV, binop(Iop_64HLtoV128, mkexpr(e0),mkexpr(g0)) );
12845 assign( rightV, binop(Iop_64HLtoV128, mkexpr(e1),mkexpr(g1)) );
12846
12847 putXMMReg( gregOfRexRM(pfx,modrm),
12848 binop(isAdd ? Iop_Add64Fx2 : Iop_Sub64Fx2,
12849 mkexpr(leftV), mkexpr(rightV) ) );
12850 goto decode_success;
12851 }
12852
12853 /* F2 0F F0 = LDDQU -- move from E (mem or xmm) to G (xmm). */
12854 if (haveF2no66noF3(pfx) && sz == 4
12855 && insn[0] == 0x0F && insn[1] == 0xF0) {
12856 modrm = insn[2];
12857 if (epartIsReg(modrm)) {
12858 goto decode_failure;
12859 } else {
sewardj2e28ac42008-12-04 00:05:12 +000012860 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardjfcf21f32006-08-04 14:51:19 +000012861 putXMMReg( gregOfRexRM(pfx,modrm),
12862 loadLE(Ity_V128, mkexpr(addr)) );
12863 DIP("lddqu %s,%s\n", dis_buf,
12864 nameXMMReg(gregOfRexRM(pfx,modrm)));
12865 delta += 2+alen;
12866 }
12867 goto decode_success;
12868 }
12869
12870 /* ---------------------------------------------------- */
12871 /* --- end of the SSE3 decoder. --- */
12872 /* ---------------------------------------------------- */
12873
sewardjd166e282008-02-06 11:42:45 +000012874 /* ---------------------------------------------------- */
12875 /* --- start of the SSSE3 decoder. --- */
12876 /* ---------------------------------------------------- */
12877
12878 /* 0F 38 04 = PMADDUBSW -- Multiply and Add Packed Signed and
12879 Unsigned Bytes (MMX) */
12880 if (haveNo66noF2noF3(pfx)
12881 && sz == 4
12882 && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x04) {
12883 IRTemp sV = newTemp(Ity_I64);
12884 IRTemp dV = newTemp(Ity_I64);
12885 IRTemp sVoddsSX = newTemp(Ity_I64);
12886 IRTemp sVevensSX = newTemp(Ity_I64);
12887 IRTemp dVoddsZX = newTemp(Ity_I64);
12888 IRTemp dVevensZX = newTemp(Ity_I64);
12889
12890 modrm = insn[3];
12891 do_MMX_preamble();
12892 assign( dV, getMMXReg(gregLO3ofRM(modrm)) );
12893
12894 if (epartIsReg(modrm)) {
12895 assign( sV, getMMXReg(eregLO3ofRM(modrm)) );
12896 delta += 3+1;
12897 DIP("pmaddubsw %s,%s\n", nameMMXReg(eregLO3ofRM(modrm)),
12898 nameMMXReg(gregLO3ofRM(modrm)));
12899 } else {
sewardj2e28ac42008-12-04 00:05:12 +000012900 addr = disAMode ( &alen, vbi, pfx, delta+3, dis_buf, 0 );
sewardjd166e282008-02-06 11:42:45 +000012901 assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
12902 delta += 3+alen;
12903 DIP("pmaddubsw %s,%s\n", dis_buf,
12904 nameMMXReg(gregLO3ofRM(modrm)));
12905 }
12906
12907 /* compute dV unsigned x sV signed */
12908 assign( sVoddsSX,
12909 binop(Iop_SarN16x4, mkexpr(sV), mkU8(8)) );
12910 assign( sVevensSX,
12911 binop(Iop_SarN16x4,
12912 binop(Iop_ShlN16x4, mkexpr(sV), mkU8(8)),
12913 mkU8(8)) );
12914 assign( dVoddsZX,
12915 binop(Iop_ShrN16x4, mkexpr(dV), mkU8(8)) );
12916 assign( dVevensZX,
12917 binop(Iop_ShrN16x4,
12918 binop(Iop_ShlN16x4, mkexpr(dV), mkU8(8)),
12919 mkU8(8)) );
12920
12921 putMMXReg(
12922 gregLO3ofRM(modrm),
12923 binop(Iop_QAdd16Sx4,
12924 binop(Iop_Mul16x4, mkexpr(sVoddsSX), mkexpr(dVoddsZX)),
12925 binop(Iop_Mul16x4, mkexpr(sVevensSX), mkexpr(dVevensZX))
12926 )
12927 );
12928 goto decode_success;
12929 }
12930
12931 /* 66 0F 38 04 = PMADDUBSW -- Multiply and Add Packed Signed and
12932 Unsigned Bytes (XMM) */
12933 if (have66noF2noF3(pfx)
12934 && (sz == 2 || /*redundant REX.W*/ sz == 8)
12935 && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x04) {
12936 IRTemp sV = newTemp(Ity_V128);
12937 IRTemp dV = newTemp(Ity_V128);
12938 IRTemp sVoddsSX = newTemp(Ity_V128);
12939 IRTemp sVevensSX = newTemp(Ity_V128);
12940 IRTemp dVoddsZX = newTemp(Ity_V128);
12941 IRTemp dVevensZX = newTemp(Ity_V128);
12942
12943 modrm = insn[3];
12944 assign( dV, getXMMReg(gregOfRexRM(pfx,modrm)) );
12945
12946 if (epartIsReg(modrm)) {
12947 assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
12948 delta += 3+1;
12949 DIP("pmaddubsw %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
12950 nameXMMReg(gregOfRexRM(pfx,modrm)));
12951 } else {
sewardj2e28ac42008-12-04 00:05:12 +000012952 addr = disAMode ( &alen, vbi, pfx, delta+3, dis_buf, 0 );
sewardj150c9cd2008-02-09 01:16:02 +000012953 gen_SEGV_if_not_16_aligned( addr );
sewardjd166e282008-02-06 11:42:45 +000012954 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
12955 delta += 3+alen;
12956 DIP("pmaddubsw %s,%s\n", dis_buf,
12957 nameXMMReg(gregOfRexRM(pfx,modrm)));
12958 }
12959
12960 /* compute dV unsigned x sV signed */
12961 assign( sVoddsSX,
12962 binop(Iop_SarN16x8, mkexpr(sV), mkU8(8)) );
12963 assign( sVevensSX,
12964 binop(Iop_SarN16x8,
12965 binop(Iop_ShlN16x8, mkexpr(sV), mkU8(8)),
12966 mkU8(8)) );
12967 assign( dVoddsZX,
12968 binop(Iop_ShrN16x8, mkexpr(dV), mkU8(8)) );
12969 assign( dVevensZX,
12970 binop(Iop_ShrN16x8,
12971 binop(Iop_ShlN16x8, mkexpr(dV), mkU8(8)),
12972 mkU8(8)) );
12973
12974 putXMMReg(
12975 gregOfRexRM(pfx,modrm),
12976 binop(Iop_QAdd16Sx8,
12977 binop(Iop_Mul16x8, mkexpr(sVoddsSX), mkexpr(dVoddsZX)),
12978 binop(Iop_Mul16x8, mkexpr(sVevensSX), mkexpr(dVevensZX))
12979 )
12980 );
12981 goto decode_success;
12982 }
12983
12984 /* ***--- these are MMX class insns introduced in SSSE3 ---*** */
12985 /* 0F 38 03 = PHADDSW -- 16x4 signed qadd across from E (mem or
12986 mmx) and G to G (mmx). */
12987 /* 0F 38 07 = PHSUBSW -- 16x4 signed qsub across from E (mem or
12988 mmx) and G to G (mmx). */
12989 /* 0F 38 01 = PHADDW -- 16x4 add across from E (mem or mmx) and G
12990 to G (mmx). */
12991 /* 0F 38 05 = PHSUBW -- 16x4 sub across from E (mem or mmx) and G
12992 to G (mmx). */
12993 /* 0F 38 02 = PHADDD -- 32x2 add across from E (mem or mmx) and G
12994 to G (mmx). */
12995 /* 0F 38 06 = PHSUBD -- 32x2 sub across from E (mem or mmx) and G
12996 to G (mmx). */
12997
12998 if (haveNo66noF2noF3(pfx)
12999 && sz == 4
13000 && insn[0] == 0x0F && insn[1] == 0x38
13001 && (insn[2] == 0x03 || insn[2] == 0x07 || insn[2] == 0x01
13002 || insn[2] == 0x05 || insn[2] == 0x02 || insn[2] == 0x06)) {
13003 HChar* str = "???";
13004 IROp opV64 = Iop_INVALID;
13005 IROp opCatO = Iop_CatOddLanes16x4;
13006 IROp opCatE = Iop_CatEvenLanes16x4;
13007 IRTemp sV = newTemp(Ity_I64);
13008 IRTemp dV = newTemp(Ity_I64);
13009
13010 modrm = insn[3];
13011
13012 switch (insn[2]) {
13013 case 0x03: opV64 = Iop_QAdd16Sx4; str = "addsw"; break;
13014 case 0x07: opV64 = Iop_QSub16Sx4; str = "subsw"; break;
13015 case 0x01: opV64 = Iop_Add16x4; str = "addw"; break;
13016 case 0x05: opV64 = Iop_Sub16x4; str = "subw"; break;
13017 case 0x02: opV64 = Iop_Add32x2; str = "addd"; break;
13018 case 0x06: opV64 = Iop_Sub32x2; str = "subd"; break;
13019 default: vassert(0);
13020 }
13021 if (insn[2] == 0x02 || insn[2] == 0x06) {
13022 opCatO = Iop_InterleaveHI32x2;
13023 opCatE = Iop_InterleaveLO32x2;
13024 }
13025
13026 do_MMX_preamble();
13027 assign( dV, getMMXReg(gregLO3ofRM(modrm)) );
13028
13029 if (epartIsReg(modrm)) {
13030 assign( sV, getMMXReg(eregLO3ofRM(modrm)) );
13031 delta += 3+1;
13032 DIP("ph%s %s,%s\n", str, nameMMXReg(eregLO3ofRM(modrm)),
13033 nameMMXReg(gregLO3ofRM(modrm)));
13034 } else {
sewardj2e28ac42008-12-04 00:05:12 +000013035 addr = disAMode ( &alen, vbi, pfx, delta+3, dis_buf, 0 );
sewardjd166e282008-02-06 11:42:45 +000013036 assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
13037 delta += 3+alen;
13038 DIP("ph%s %s,%s\n", str, dis_buf,
13039 nameMMXReg(gregLO3ofRM(modrm)));
13040 }
13041
13042 putMMXReg(
13043 gregLO3ofRM(modrm),
13044 binop(opV64,
13045 binop(opCatE,mkexpr(sV),mkexpr(dV)),
13046 binop(opCatO,mkexpr(sV),mkexpr(dV))
13047 )
13048 );
13049 goto decode_success;
13050 }
13051
13052 /* 66 0F 38 03 = PHADDSW -- 16x8 signed qadd across from E (mem or
13053 xmm) and G to G (xmm). */
13054 /* 66 0F 38 07 = PHSUBSW -- 16x8 signed qsub across from E (mem or
13055 xmm) and G to G (xmm). */
13056 /* 66 0F 38 01 = PHADDW -- 16x8 add across from E (mem or xmm) and
13057 G to G (xmm). */
13058 /* 66 0F 38 05 = PHSUBW -- 16x8 sub across from E (mem or xmm) and
13059 G to G (xmm). */
13060 /* 66 0F 38 02 = PHADDD -- 32x4 add across from E (mem or xmm) and
13061 G to G (xmm). */
13062 /* 66 0F 38 06 = PHSUBD -- 32x4 sub across from E (mem or xmm) and
13063 G to G (xmm). */
13064
13065 if (have66noF2noF3(pfx)
13066 && (sz == 2 || /*redundant REX.W*/ sz == 8)
13067 && insn[0] == 0x0F && insn[1] == 0x38
13068 && (insn[2] == 0x03 || insn[2] == 0x07 || insn[2] == 0x01
13069 || insn[2] == 0x05 || insn[2] == 0x02 || insn[2] == 0x06)) {
13070 HChar* str = "???";
13071 IROp opV64 = Iop_INVALID;
13072 IROp opCatO = Iop_CatOddLanes16x4;
13073 IROp opCatE = Iop_CatEvenLanes16x4;
13074 IRTemp sV = newTemp(Ity_V128);
13075 IRTemp dV = newTemp(Ity_V128);
13076 IRTemp sHi = newTemp(Ity_I64);
13077 IRTemp sLo = newTemp(Ity_I64);
13078 IRTemp dHi = newTemp(Ity_I64);
13079 IRTemp dLo = newTemp(Ity_I64);
13080
13081 modrm = insn[3];
13082
13083 switch (insn[2]) {
13084 case 0x03: opV64 = Iop_QAdd16Sx4; str = "addsw"; break;
13085 case 0x07: opV64 = Iop_QSub16Sx4; str = "subsw"; break;
13086 case 0x01: opV64 = Iop_Add16x4; str = "addw"; break;
13087 case 0x05: opV64 = Iop_Sub16x4; str = "subw"; break;
13088 case 0x02: opV64 = Iop_Add32x2; str = "addd"; break;
13089 case 0x06: opV64 = Iop_Sub32x2; str = "subd"; break;
13090 default: vassert(0);
13091 }
13092 if (insn[2] == 0x02 || insn[2] == 0x06) {
13093 opCatO = Iop_InterleaveHI32x2;
13094 opCatE = Iop_InterleaveLO32x2;
13095 }
13096
13097 assign( dV, getXMMReg(gregOfRexRM(pfx,modrm)) );
13098
13099 if (epartIsReg(modrm)) {
13100 assign( sV, getXMMReg( eregOfRexRM(pfx,modrm)) );
13101 DIP("ph%s %s,%s\n", str, nameXMMReg(eregOfRexRM(pfx,modrm)),
13102 nameXMMReg(gregOfRexRM(pfx,modrm)));
13103 delta += 3+1;
13104 } else {
sewardj2e28ac42008-12-04 00:05:12 +000013105 addr = disAMode ( &alen, vbi, pfx, delta+3, dis_buf, 0 );
sewardj150c9cd2008-02-09 01:16:02 +000013106 gen_SEGV_if_not_16_aligned( addr );
sewardjd166e282008-02-06 11:42:45 +000013107 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
13108 DIP("ph%s %s,%s\n", str, dis_buf,
13109 nameXMMReg(gregOfRexRM(pfx,modrm)));
13110 delta += 3+alen;
13111 }
13112
13113 assign( dHi, unop(Iop_V128HIto64, mkexpr(dV)) );
13114 assign( dLo, unop(Iop_V128to64, mkexpr(dV)) );
13115 assign( sHi, unop(Iop_V128HIto64, mkexpr(sV)) );
13116 assign( sLo, unop(Iop_V128to64, mkexpr(sV)) );
13117
13118 /* This isn't a particularly efficient way to compute the
13119 result, but at least it avoids a proliferation of IROps,
13120 hence avoids complication all the backends. */
13121 putXMMReg(
13122 gregOfRexRM(pfx,modrm),
13123 binop(Iop_64HLtoV128,
13124 binop(opV64,
13125 binop(opCatE,mkexpr(sHi),mkexpr(sLo)),
13126 binop(opCatO,mkexpr(sHi),mkexpr(sLo))
13127 ),
13128 binop(opV64,
13129 binop(opCatE,mkexpr(dHi),mkexpr(dLo)),
13130 binop(opCatO,mkexpr(dHi),mkexpr(dLo))
13131 )
13132 )
13133 );
13134 goto decode_success;
13135 }
13136
13137 /* 0F 38 0B = PMULHRSW -- Packed Multiply High with Round and Scale
13138 (MMX) */
13139 if (haveNo66noF2noF3(pfx)
13140 && sz == 4
13141 && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x0B) {
13142 IRTemp sV = newTemp(Ity_I64);
13143 IRTemp dV = newTemp(Ity_I64);
13144
13145 modrm = insn[3];
13146 do_MMX_preamble();
13147 assign( dV, getMMXReg(gregLO3ofRM(modrm)) );
13148
13149 if (epartIsReg(modrm)) {
13150 assign( sV, getMMXReg(eregLO3ofRM(modrm)) );
13151 delta += 3+1;
13152 DIP("pmulhrsw %s,%s\n", nameMMXReg(eregLO3ofRM(modrm)),
13153 nameMMXReg(gregLO3ofRM(modrm)));
13154 } else {
sewardj2e28ac42008-12-04 00:05:12 +000013155 addr = disAMode ( &alen, vbi, pfx, delta+3, dis_buf, 0 );
sewardjd166e282008-02-06 11:42:45 +000013156 assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
13157 delta += 3+alen;
13158 DIP("pmulhrsw %s,%s\n", dis_buf,
13159 nameMMXReg(gregLO3ofRM(modrm)));
13160 }
13161
13162 putMMXReg(
13163 gregLO3ofRM(modrm),
13164 dis_PMULHRSW_helper( mkexpr(sV), mkexpr(dV) )
13165 );
13166 goto decode_success;
13167 }
13168
13169 /* 66 0F 38 0B = PMULHRSW -- Packed Multiply High with Round and
13170 Scale (XMM) */
13171 if (have66noF2noF3(pfx)
13172 && (sz == 2 || /*redundant REX.W*/ sz == 8)
13173 && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x0B) {
13174 IRTemp sV = newTemp(Ity_V128);
13175 IRTemp dV = newTemp(Ity_V128);
13176 IRTemp sHi = newTemp(Ity_I64);
13177 IRTemp sLo = newTemp(Ity_I64);
13178 IRTemp dHi = newTemp(Ity_I64);
13179 IRTemp dLo = newTemp(Ity_I64);
13180
13181 modrm = insn[3];
13182 assign( dV, getXMMReg(gregOfRexRM(pfx,modrm)) );
13183
13184 if (epartIsReg(modrm)) {
13185 assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
13186 delta += 3+1;
13187 DIP("pmulhrsw %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
13188 nameXMMReg(gregOfRexRM(pfx,modrm)));
13189 } else {
sewardj2e28ac42008-12-04 00:05:12 +000013190 addr = disAMode ( &alen, vbi, pfx, delta+3, dis_buf, 0 );
sewardj150c9cd2008-02-09 01:16:02 +000013191 gen_SEGV_if_not_16_aligned( addr );
sewardjd166e282008-02-06 11:42:45 +000013192 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
13193 delta += 3+alen;
13194 DIP("pmulhrsw %s,%s\n", dis_buf,
13195 nameXMMReg(gregOfRexRM(pfx,modrm)));
13196 }
13197
13198 assign( dHi, unop(Iop_V128HIto64, mkexpr(dV)) );
13199 assign( dLo, unop(Iop_V128to64, mkexpr(dV)) );
13200 assign( sHi, unop(Iop_V128HIto64, mkexpr(sV)) );
13201 assign( sLo, unop(Iop_V128to64, mkexpr(sV)) );
13202
13203 putXMMReg(
13204 gregOfRexRM(pfx,modrm),
13205 binop(Iop_64HLtoV128,
13206 dis_PMULHRSW_helper( mkexpr(sHi), mkexpr(dHi) ),
13207 dis_PMULHRSW_helper( mkexpr(sLo), mkexpr(dLo) )
13208 )
13209 );
13210 goto decode_success;
13211 }
13212
13213 /* 0F 38 08 = PSIGNB -- Packed Sign 8x8 (MMX) */
13214 /* 0F 38 09 = PSIGNW -- Packed Sign 16x4 (MMX) */
13215 /* 0F 38 09 = PSIGND -- Packed Sign 32x2 (MMX) */
13216 if (haveNo66noF2noF3(pfx)
13217 && sz == 4
13218 && insn[0] == 0x0F && insn[1] == 0x38
13219 && (insn[2] == 0x08 || insn[2] == 0x09 || insn[2] == 0x0A)) {
13220 IRTemp sV = newTemp(Ity_I64);
13221 IRTemp dV = newTemp(Ity_I64);
13222 HChar* str = "???";
13223 Int laneszB = 0;
13224
13225 switch (insn[2]) {
13226 case 0x08: laneszB = 1; str = "b"; break;
13227 case 0x09: laneszB = 2; str = "w"; break;
13228 case 0x0A: laneszB = 4; str = "d"; break;
13229 default: vassert(0);
13230 }
13231
13232 modrm = insn[3];
13233 do_MMX_preamble();
13234 assign( dV, getMMXReg(gregLO3ofRM(modrm)) );
13235
13236 if (epartIsReg(modrm)) {
13237 assign( sV, getMMXReg(eregLO3ofRM(modrm)) );
13238 delta += 3+1;
13239 DIP("psign%s %s,%s\n", str, nameMMXReg(eregLO3ofRM(modrm)),
13240 nameMMXReg(gregLO3ofRM(modrm)));
13241 } else {
sewardj2e28ac42008-12-04 00:05:12 +000013242 addr = disAMode ( &alen, vbi, pfx, delta+3, dis_buf, 0 );
sewardjd166e282008-02-06 11:42:45 +000013243 assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
13244 delta += 3+alen;
13245 DIP("psign%s %s,%s\n", str, dis_buf,
13246 nameMMXReg(gregLO3ofRM(modrm)));
13247 }
13248
13249 putMMXReg(
13250 gregLO3ofRM(modrm),
13251 dis_PSIGN_helper( mkexpr(sV), mkexpr(dV), laneszB )
13252 );
13253 goto decode_success;
13254 }
13255
13256 /* 66 0F 38 08 = PSIGNB -- Packed Sign 8x16 (XMM) */
13257 /* 66 0F 38 09 = PSIGNW -- Packed Sign 16x8 (XMM) */
13258 /* 66 0F 38 09 = PSIGND -- Packed Sign 32x4 (XMM) */
13259 if (have66noF2noF3(pfx)
13260 && (sz == 2 || /*redundant REX.W*/ sz == 8)
13261 && insn[0] == 0x0F && insn[1] == 0x38
13262 && (insn[2] == 0x08 || insn[2] == 0x09 || insn[2] == 0x0A)) {
13263 IRTemp sV = newTemp(Ity_V128);
13264 IRTemp dV = newTemp(Ity_V128);
13265 IRTemp sHi = newTemp(Ity_I64);
13266 IRTemp sLo = newTemp(Ity_I64);
13267 IRTemp dHi = newTemp(Ity_I64);
13268 IRTemp dLo = newTemp(Ity_I64);
13269 HChar* str = "???";
13270 Int laneszB = 0;
13271
13272 switch (insn[2]) {
13273 case 0x08: laneszB = 1; str = "b"; break;
13274 case 0x09: laneszB = 2; str = "w"; break;
13275 case 0x0A: laneszB = 4; str = "d"; break;
13276 default: vassert(0);
13277 }
13278
13279 modrm = insn[3];
13280 assign( dV, getXMMReg(gregOfRexRM(pfx,modrm)) );
13281
13282 if (epartIsReg(modrm)) {
13283 assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
13284 delta += 3+1;
13285 DIP("psign%s %s,%s\n", str, nameXMMReg(eregOfRexRM(pfx,modrm)),
13286 nameXMMReg(gregOfRexRM(pfx,modrm)));
13287 } else {
sewardj2e28ac42008-12-04 00:05:12 +000013288 addr = disAMode ( &alen, vbi, pfx, delta+3, dis_buf, 0 );
sewardj150c9cd2008-02-09 01:16:02 +000013289 gen_SEGV_if_not_16_aligned( addr );
sewardjd166e282008-02-06 11:42:45 +000013290 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
13291 delta += 3+alen;
13292 DIP("psign%s %s,%s\n", str, dis_buf,
13293 nameXMMReg(gregOfRexRM(pfx,modrm)));
13294 }
13295
13296 assign( dHi, unop(Iop_V128HIto64, mkexpr(dV)) );
13297 assign( dLo, unop(Iop_V128to64, mkexpr(dV)) );
13298 assign( sHi, unop(Iop_V128HIto64, mkexpr(sV)) );
13299 assign( sLo, unop(Iop_V128to64, mkexpr(sV)) );
13300
13301 putXMMReg(
13302 gregOfRexRM(pfx,modrm),
13303 binop(Iop_64HLtoV128,
13304 dis_PSIGN_helper( mkexpr(sHi), mkexpr(dHi), laneszB ),
13305 dis_PSIGN_helper( mkexpr(sLo), mkexpr(dLo), laneszB )
13306 )
13307 );
13308 goto decode_success;
13309 }
13310
13311 /* 0F 38 1C = PABSB -- Packed Absolute Value 8x8 (MMX) */
13312 /* 0F 38 1D = PABSW -- Packed Absolute Value 16x4 (MMX) */
13313 /* 0F 38 1E = PABSD -- Packed Absolute Value 32x2 (MMX) */
13314 if (haveNo66noF2noF3(pfx)
13315 && sz == 4
13316 && insn[0] == 0x0F && insn[1] == 0x38
13317 && (insn[2] == 0x1C || insn[2] == 0x1D || insn[2] == 0x1E)) {
13318 IRTemp sV = newTemp(Ity_I64);
13319 HChar* str = "???";
13320 Int laneszB = 0;
13321
13322 switch (insn[2]) {
13323 case 0x1C: laneszB = 1; str = "b"; break;
13324 case 0x1D: laneszB = 2; str = "w"; break;
13325 case 0x1E: laneszB = 4; str = "d"; break;
13326 default: vassert(0);
13327 }
13328
13329 modrm = insn[3];
13330 do_MMX_preamble();
13331
13332 if (epartIsReg(modrm)) {
13333 assign( sV, getMMXReg(eregLO3ofRM(modrm)) );
13334 delta += 3+1;
13335 DIP("pabs%s %s,%s\n", str, nameMMXReg(eregLO3ofRM(modrm)),
13336 nameMMXReg(gregLO3ofRM(modrm)));
13337 } else {
sewardj2e28ac42008-12-04 00:05:12 +000013338 addr = disAMode ( &alen, vbi, pfx, delta+3, dis_buf, 0 );
sewardjd166e282008-02-06 11:42:45 +000013339 assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
13340 delta += 3+alen;
13341 DIP("pabs%s %s,%s\n", str, dis_buf,
13342 nameMMXReg(gregLO3ofRM(modrm)));
13343 }
13344
13345 putMMXReg(
13346 gregLO3ofRM(modrm),
13347 dis_PABS_helper( mkexpr(sV), laneszB )
13348 );
13349 goto decode_success;
13350 }
13351
13352 /* 66 0F 38 1C = PABSB -- Packed Absolute Value 8x16 (XMM) */
13353 /* 66 0F 38 1D = PABSW -- Packed Absolute Value 16x8 (XMM) */
13354 /* 66 0F 38 1E = PABSD -- Packed Absolute Value 32x4 (XMM) */
13355 if (have66noF2noF3(pfx)
13356 && (sz == 2 || /*redundant REX.W*/ sz == 8)
13357 && insn[0] == 0x0F && insn[1] == 0x38
13358 && (insn[2] == 0x1C || insn[2] == 0x1D || insn[2] == 0x1E)) {
13359 IRTemp sV = newTemp(Ity_V128);
13360 IRTemp sHi = newTemp(Ity_I64);
13361 IRTemp sLo = newTemp(Ity_I64);
13362 HChar* str = "???";
13363 Int laneszB = 0;
13364
13365 switch (insn[2]) {
13366 case 0x1C: laneszB = 1; str = "b"; break;
13367 case 0x1D: laneszB = 2; str = "w"; break;
13368 case 0x1E: laneszB = 4; str = "d"; break;
13369 default: vassert(0);
13370 }
13371
13372 modrm = insn[3];
13373
13374 if (epartIsReg(modrm)) {
13375 assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
13376 delta += 3+1;
13377 DIP("pabs%s %s,%s\n", str, nameXMMReg(eregOfRexRM(pfx,modrm)),
13378 nameXMMReg(gregOfRexRM(pfx,modrm)));
13379 } else {
sewardj2e28ac42008-12-04 00:05:12 +000013380 addr = disAMode ( &alen, vbi, pfx, delta+3, dis_buf, 0 );
sewardj150c9cd2008-02-09 01:16:02 +000013381 gen_SEGV_if_not_16_aligned( addr );
sewardjd166e282008-02-06 11:42:45 +000013382 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
13383 delta += 3+alen;
13384 DIP("pabs%s %s,%s\n", str, dis_buf,
13385 nameXMMReg(gregOfRexRM(pfx,modrm)));
13386 }
13387
13388 assign( sHi, unop(Iop_V128HIto64, mkexpr(sV)) );
13389 assign( sLo, unop(Iop_V128to64, mkexpr(sV)) );
13390
13391 putXMMReg(
13392 gregOfRexRM(pfx,modrm),
13393 binop(Iop_64HLtoV128,
13394 dis_PABS_helper( mkexpr(sHi), laneszB ),
13395 dis_PABS_helper( mkexpr(sLo), laneszB )
13396 )
13397 );
13398 goto decode_success;
13399 }
13400
13401 /* 0F 3A 0F = PALIGNR -- Packed Align Right (MMX) */
13402 if (haveNo66noF2noF3(pfx) && sz == 4
13403 && insn[0] == 0x0F && insn[1] == 0x3A && insn[2] == 0x0F) {
13404 IRTemp sV = newTemp(Ity_I64);
13405 IRTemp dV = newTemp(Ity_I64);
13406 IRTemp res = newTemp(Ity_I64);
13407
13408 modrm = insn[3];
13409 do_MMX_preamble();
13410 assign( dV, getMMXReg(gregLO3ofRM(modrm)) );
13411
13412 if (epartIsReg(modrm)) {
13413 assign( sV, getMMXReg(eregLO3ofRM(modrm)) );
13414 d64 = (Long)insn[3+1];
13415 delta += 3+1+1;
13416 DIP("palignr $%d,%s,%s\n", (Int)d64,
13417 nameMMXReg(eregLO3ofRM(modrm)),
13418 nameMMXReg(gregLO3ofRM(modrm)));
13419 } else {
sewardjf30883e2009-03-19 23:43:43 +000013420 addr = disAMode ( &alen, vbi, pfx, delta+3, dis_buf, 1 );
sewardjd166e282008-02-06 11:42:45 +000013421 assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
13422 d64 = (Long)insn[3+alen];
13423 delta += 3+alen+1;
13424 DIP("palignr $%d%s,%s\n", (Int)d64,
13425 dis_buf,
13426 nameMMXReg(gregLO3ofRM(modrm)));
13427 }
13428
13429 if (d64 == 0) {
13430 assign( res, mkexpr(sV) );
13431 }
13432 else if (d64 >= 1 && d64 <= 7) {
13433 assign(res,
13434 binop(Iop_Or64,
13435 binop(Iop_Shr64, mkexpr(sV), mkU8(8*d64)),
13436 binop(Iop_Shl64, mkexpr(dV), mkU8(8*(8-d64))
13437 )));
13438 }
13439 else if (d64 == 8) {
13440 assign( res, mkexpr(dV) );
13441 }
13442 else if (d64 >= 9 && d64 <= 15) {
13443 assign( res, binop(Iop_Shr64, mkexpr(dV), mkU8(8*(d64-8))) );
13444 }
13445 else if (d64 >= 16 && d64 <= 255) {
13446 assign( res, mkU64(0) );
13447 }
13448 else
13449 vassert(0);
13450
13451 putMMXReg( gregLO3ofRM(modrm), mkexpr(res) );
13452 goto decode_success;
13453 }
13454
13455 /* 66 0F 3A 0F = PALIGNR -- Packed Align Right (XMM) */
13456 if (have66noF2noF3(pfx)
13457 && (sz == 2 || /*redundant REX.W*/ sz == 8)
13458 && insn[0] == 0x0F && insn[1] == 0x3A && insn[2] == 0x0F) {
13459 IRTemp sV = newTemp(Ity_V128);
13460 IRTemp dV = newTemp(Ity_V128);
13461 IRTemp sHi = newTemp(Ity_I64);
13462 IRTemp sLo = newTemp(Ity_I64);
13463 IRTemp dHi = newTemp(Ity_I64);
13464 IRTemp dLo = newTemp(Ity_I64);
13465 IRTemp rHi = newTemp(Ity_I64);
13466 IRTemp rLo = newTemp(Ity_I64);
13467
13468 modrm = insn[3];
13469 assign( dV, getXMMReg(gregOfRexRM(pfx,modrm)) );
13470
13471 if (epartIsReg(modrm)) {
13472 assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
13473 d64 = (Long)insn[3+1];
13474 delta += 3+1+1;
13475 DIP("palignr $%d,%s,%s\n", (Int)d64,
13476 nameXMMReg(eregOfRexRM(pfx,modrm)),
13477 nameXMMReg(gregOfRexRM(pfx,modrm)));
13478 } else {
sewardjf30883e2009-03-19 23:43:43 +000013479 addr = disAMode ( &alen, vbi, pfx, delta+3, dis_buf, 1 );
sewardj150c9cd2008-02-09 01:16:02 +000013480 gen_SEGV_if_not_16_aligned( addr );
sewardjd166e282008-02-06 11:42:45 +000013481 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
13482 d64 = (Long)insn[3+alen];
13483 delta += 3+alen+1;
13484 DIP("palignr $%d,%s,%s\n", (Int)d64,
13485 dis_buf,
13486 nameXMMReg(gregOfRexRM(pfx,modrm)));
13487 }
13488
13489 assign( dHi, unop(Iop_V128HIto64, mkexpr(dV)) );
13490 assign( dLo, unop(Iop_V128to64, mkexpr(dV)) );
13491 assign( sHi, unop(Iop_V128HIto64, mkexpr(sV)) );
13492 assign( sLo, unop(Iop_V128to64, mkexpr(sV)) );
13493
13494 if (d64 == 0) {
13495 assign( rHi, mkexpr(sHi) );
13496 assign( rLo, mkexpr(sLo) );
13497 }
13498 else if (d64 >= 1 && d64 <= 7) {
13499 assign( rHi, dis_PALIGNR_XMM_helper(dLo, sHi, d64) );
sewardj150c9cd2008-02-09 01:16:02 +000013500 assign( rLo, dis_PALIGNR_XMM_helper(sHi, sLo, d64) );
sewardjd166e282008-02-06 11:42:45 +000013501 }
13502 else if (d64 == 8) {
13503 assign( rHi, mkexpr(dLo) );
13504 assign( rLo, mkexpr(sHi) );
13505 }
13506 else if (d64 >= 9 && d64 <= 15) {
13507 assign( rHi, dis_PALIGNR_XMM_helper(dHi, dLo, d64-8) );
sewardj150c9cd2008-02-09 01:16:02 +000013508 assign( rLo, dis_PALIGNR_XMM_helper(dLo, sHi, d64-8) );
sewardjd166e282008-02-06 11:42:45 +000013509 }
13510 else if (d64 == 16) {
13511 assign( rHi, mkexpr(dHi) );
13512 assign( rLo, mkexpr(dLo) );
13513 }
13514 else if (d64 >= 17 && d64 <= 23) {
13515 assign( rHi, binop(Iop_Shr64, mkexpr(dHi), mkU8(8*(d64-16))) );
sewardj150c9cd2008-02-09 01:16:02 +000013516 assign( rLo, dis_PALIGNR_XMM_helper(dHi, dLo, d64-16) );
sewardjd166e282008-02-06 11:42:45 +000013517 }
13518 else if (d64 == 24) {
13519 assign( rHi, mkU64(0) );
13520 assign( rLo, mkexpr(dHi) );
13521 }
13522 else if (d64 >= 25 && d64 <= 31) {
13523 assign( rHi, mkU64(0) );
13524 assign( rLo, binop(Iop_Shr64, mkexpr(dHi), mkU8(8*(d64-24))) );
13525 }
13526 else if (d64 >= 32 && d64 <= 255) {
13527 assign( rHi, mkU64(0) );
13528 assign( rLo, mkU64(0) );
13529 }
13530 else
13531 vassert(0);
13532
13533 putXMMReg(
13534 gregOfRexRM(pfx,modrm),
13535 binop(Iop_64HLtoV128, mkexpr(rHi), mkexpr(rLo))
13536 );
13537 goto decode_success;
13538 }
13539
13540 /* 0F 38 00 = PSHUFB -- Packed Shuffle Bytes 8x8 (MMX) */
13541 if (haveNo66noF2noF3(pfx)
13542 && sz == 4
13543 && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x00) {
13544 IRTemp sV = newTemp(Ity_I64);
13545 IRTemp dV = newTemp(Ity_I64);
13546
13547 modrm = insn[3];
13548 do_MMX_preamble();
13549 assign( dV, getMMXReg(gregLO3ofRM(modrm)) );
13550
13551 if (epartIsReg(modrm)) {
13552 assign( sV, getMMXReg(eregLO3ofRM(modrm)) );
13553 delta += 3+1;
13554 DIP("pshufb %s,%s\n", nameMMXReg(eregLO3ofRM(modrm)),
13555 nameMMXReg(gregLO3ofRM(modrm)));
13556 } else {
sewardj2e28ac42008-12-04 00:05:12 +000013557 addr = disAMode ( &alen, vbi, pfx, delta+3, dis_buf, 0 );
sewardjd166e282008-02-06 11:42:45 +000013558 assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
13559 delta += 3+alen;
13560 DIP("pshufb %s,%s\n", dis_buf,
13561 nameMMXReg(gregLO3ofRM(modrm)));
13562 }
13563
13564 putMMXReg(
13565 gregLO3ofRM(modrm),
13566 binop(
13567 Iop_And64,
13568 /* permute the lanes */
13569 binop(
13570 Iop_Perm8x8,
13571 mkexpr(dV),
13572 binop(Iop_And64, mkexpr(sV), mkU64(0x0707070707070707ULL))
sewardj150c9cd2008-02-09 01:16:02 +000013573 ),
sewardjd166e282008-02-06 11:42:45 +000013574 /* mask off lanes which have (index & 0x80) == 0x80 */
13575 unop(Iop_Not64, binop(Iop_SarN8x8, mkexpr(sV), mkU8(7)))
13576 )
13577 );
13578 goto decode_success;
13579 }
13580
13581 /* 66 0F 38 00 = PSHUFB -- Packed Shuffle Bytes 8x16 (XMM) */
13582 if (have66noF2noF3(pfx)
13583 && (sz == 2 || /*redundant REX.W*/ sz == 8)
13584 && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x00) {
13585 IRTemp sV = newTemp(Ity_V128);
13586 IRTemp dV = newTemp(Ity_V128);
13587 IRTemp sHi = newTemp(Ity_I64);
13588 IRTemp sLo = newTemp(Ity_I64);
13589 IRTemp dHi = newTemp(Ity_I64);
13590 IRTemp dLo = newTemp(Ity_I64);
13591 IRTemp rHi = newTemp(Ity_I64);
13592 IRTemp rLo = newTemp(Ity_I64);
13593 IRTemp sevens = newTemp(Ity_I64);
13594 IRTemp mask0x80hi = newTemp(Ity_I64);
13595 IRTemp mask0x80lo = newTemp(Ity_I64);
13596 IRTemp maskBit3hi = newTemp(Ity_I64);
13597 IRTemp maskBit3lo = newTemp(Ity_I64);
13598 IRTemp sAnd7hi = newTemp(Ity_I64);
13599 IRTemp sAnd7lo = newTemp(Ity_I64);
13600 IRTemp permdHi = newTemp(Ity_I64);
13601 IRTemp permdLo = newTemp(Ity_I64);
13602
13603 modrm = insn[3];
13604 assign( dV, getXMMReg(gregOfRexRM(pfx,modrm)) );
13605
13606 if (epartIsReg(modrm)) {
13607 assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
13608 delta += 3+1;
13609 DIP("pshufb %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
13610 nameXMMReg(gregOfRexRM(pfx,modrm)));
13611 } else {
sewardj2e28ac42008-12-04 00:05:12 +000013612 addr = disAMode ( &alen, vbi, pfx, delta+3, dis_buf, 0 );
sewardj150c9cd2008-02-09 01:16:02 +000013613 gen_SEGV_if_not_16_aligned( addr );
sewardjd166e282008-02-06 11:42:45 +000013614 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
13615 delta += 3+alen;
13616 DIP("pshufb %s,%s\n", dis_buf,
13617 nameXMMReg(gregOfRexRM(pfx,modrm)));
13618 }
13619
13620 assign( dHi, unop(Iop_V128HIto64, mkexpr(dV)) );
13621 assign( dLo, unop(Iop_V128to64, mkexpr(dV)) );
13622 assign( sHi, unop(Iop_V128HIto64, mkexpr(sV)) );
13623 assign( sLo, unop(Iop_V128to64, mkexpr(sV)) );
13624
13625 assign( sevens, mkU64(0x0707070707070707ULL) );
13626
13627 /*
13628 mask0x80hi = Not(SarN8x8(sHi,7))
13629 maskBit3hi = SarN8x8(ShlN8x8(sHi,4),7)
13630 sAnd7hi = And(sHi,sevens)
13631 permdHi = Or( And(Perm8x8(dHi,sAnd7hi),maskBit3hi),
13632 And(Perm8x8(dLo,sAnd7hi),Not(maskBit3hi)) )
13633 rHi = And(permdHi,mask0x80hi)
13634 */
13635 assign(
13636 mask0x80hi,
13637 unop(Iop_Not64, binop(Iop_SarN8x8,mkexpr(sHi),mkU8(7))));
13638
13639 assign(
13640 maskBit3hi,
13641 binop(Iop_SarN8x8,
13642 binop(Iop_ShlN8x8,mkexpr(sHi),mkU8(4)),
13643 mkU8(7)));
13644
13645 assign(sAnd7hi, binop(Iop_And64,mkexpr(sHi),mkexpr(sevens)));
13646
13647 assign(
13648 permdHi,
13649 binop(
13650 Iop_Or64,
13651 binop(Iop_And64,
13652 binop(Iop_Perm8x8,mkexpr(dHi),mkexpr(sAnd7hi)),
13653 mkexpr(maskBit3hi)),
13654 binop(Iop_And64,
13655 binop(Iop_Perm8x8,mkexpr(dLo),mkexpr(sAnd7hi)),
13656 unop(Iop_Not64,mkexpr(maskBit3hi))) ));
13657
13658 assign(rHi, binop(Iop_And64,mkexpr(permdHi),mkexpr(mask0x80hi)) );
13659
13660 /* And the same for the lower half of the result. What fun. */
13661
13662 assign(
13663 mask0x80lo,
13664 unop(Iop_Not64, binop(Iop_SarN8x8,mkexpr(sLo),mkU8(7))));
13665
13666 assign(
13667 maskBit3lo,
13668 binop(Iop_SarN8x8,
13669 binop(Iop_ShlN8x8,mkexpr(sLo),mkU8(4)),
13670 mkU8(7)));
13671
13672 assign(sAnd7lo, binop(Iop_And64,mkexpr(sLo),mkexpr(sevens)));
13673
13674 assign(
13675 permdLo,
13676 binop(
13677 Iop_Or64,
13678 binop(Iop_And64,
13679 binop(Iop_Perm8x8,mkexpr(dHi),mkexpr(sAnd7lo)),
13680 mkexpr(maskBit3lo)),
13681 binop(Iop_And64,
13682 binop(Iop_Perm8x8,mkexpr(dLo),mkexpr(sAnd7lo)),
13683 unop(Iop_Not64,mkexpr(maskBit3lo))) ));
13684
13685 assign(rLo, binop(Iop_And64,mkexpr(permdLo),mkexpr(mask0x80lo)) );
13686
13687 putXMMReg(
13688 gregOfRexRM(pfx,modrm),
13689 binop(Iop_64HLtoV128, mkexpr(rHi), mkexpr(rLo))
13690 );
13691 goto decode_success;
13692 }
13693
13694 /* ---------------------------------------------------- */
13695 /* --- end of the SSSE3 decoder. --- */
13696 /* ---------------------------------------------------- */
13697
de5a70f5c2010-04-01 23:08:59 +000013698 /* ---------------------------------------------------- */
13699 /* --- start of the SSE4 decoder --- */
13700 /* ---------------------------------------------------- */
13701
13702 /* 66 0F 3A 0D /r ib = BLENDPD xmm1, xmm2/m128, imm8
13703 Blend Packed Double Precision Floating-Point Values (XMM) */
13704 if ( have66noF2noF3( pfx )
13705 && sz == 2
13706 && insn[0] == 0x0F && insn[1] == 0x3A && insn[2] == 0x0D ) {
13707
13708 Int imm8;
13709 UShort imm8_mask_16;
13710
13711 IRTemp dst_vec = newTemp(Ity_V128);
13712 IRTemp src_vec = newTemp(Ity_V128);
13713 IRTemp imm8_mask = newTemp(Ity_V128);
13714
13715 modrm = insn[3];
13716 assign( dst_vec, getXMMReg( gregOfRexRM(pfx, modrm) ) );
13717
13718 if ( epartIsReg( modrm ) ) {
13719 imm8 = (Int)insn[4];
13720 assign( src_vec, getXMMReg( eregOfRexRM(pfx, modrm) ) );
13721 delta += 3+1+1;
13722 DIP( "blendpd %s,%s,$%d\n",
13723 nameXMMReg( eregOfRexRM(pfx, modrm) ),
13724 nameXMMReg( gregOfRexRM(pfx, modrm) ),
13725 imm8 );
13726 } else {
13727 addr = disAMode( &alen, vbi, pfx, delta+3, dis_buf,
13728 1/* imm8 is 1 byte after the amode */ );
13729 assign( src_vec, loadLE( Ity_V128, mkexpr(addr) ) );
13730 imm8 = (Int)insn[2+alen+1];
13731 delta += 3+alen+1;
13732 DIP( "blendpd %s,%s,$%d\n",
13733 dis_buf, nameXMMReg( gregOfRexRM(pfx, modrm) ), imm8 );
13734 }
13735
13736 switch( imm8 & 3 ) {
13737 case 0: imm8_mask_16 = 0x0000; break;
13738 case 1: imm8_mask_16 = 0x00FF; break;
13739 case 2: imm8_mask_16 = 0xFF00; break;
13740 case 3: imm8_mask_16 = 0xFFFF; break;
13741 default: vassert(0); break;
13742 }
13743 assign( imm8_mask, mkV128( imm8_mask_16 ) );
13744
13745 putXMMReg( gregOfRexRM(pfx, modrm),
13746 binop( Iop_OrV128,
deb5afdbd2010-04-02 13:17:50 +000013747 binop( Iop_AndV128, mkexpr(src_vec), mkexpr(imm8_mask) ),
13748 binop( Iop_AndV128, mkexpr(dst_vec),
de5a70f5c2010-04-01 23:08:59 +000013749 unop( Iop_NotV128, mkexpr(imm8_mask) ) ) ) );
13750
13751 goto decode_success;
13752 }
13753
13754
deb5afdbd2010-04-02 13:17:50 +000013755 /* 66 0F 3A 0C /r ib = BLENDPS xmm1, xmm2/m128, imm8
13756 Blend Packed Single Precision Floating-Point Values (XMM) */
13757 if ( have66noF2noF3( pfx )
13758 && sz == 2
13759 && insn[0] == 0x0F && insn[1] == 0x3A && insn[2] == 0x0C ) {
13760
13761 Int imm8;
13762 IRTemp dst_vec = newTemp(Ity_V128);
13763 IRTemp src_vec = newTemp(Ity_V128);
13764
13765 modrm = insn[3];
13766
13767 assign( dst_vec, getXMMReg( gregOfRexRM(pfx, modrm) ) );
13768
13769 if ( epartIsReg( modrm ) ) {
13770 imm8 = (Int)insn[4];
13771 assign( src_vec, getXMMReg( eregOfRexRM(pfx, modrm) ) );
13772 delta += 3+1+1;
13773 DIP( "blendps %s,%s,$%d\n",
13774 nameXMMReg( eregOfRexRM(pfx, modrm) ),
13775 nameXMMReg( gregOfRexRM(pfx, modrm) ),
13776 imm8 );
13777 } else {
13778 addr = disAMode( &alen, vbi, pfx, delta+3, dis_buf,
13779 1/* imm8 is 1 byte after the amode */ );
13780 assign( src_vec, loadLE( Ity_V128, mkexpr(addr) ) );
13781 imm8 = (Int)insn[2+alen+1];
13782 delta += 3+alen+1;
13783 DIP( "blendpd %s,%s$%d\n",
13784 dis_buf, nameXMMReg( gregOfRexRM(pfx, modrm) ), imm8 );
13785 }
13786
13787 UShort imm8_perms[16] = { 0x0000, 0x000F, 0x00F0, 0x00FF, 0x0F00, 0x0F0F,
13788 0x0FF0, 0x0FFF, 0xF000, 0xF00F, 0xF0F0, 0xF0FF,
13789 0xFF00, 0xFF0F, 0xFFF0, 0xFFFF };
13790 IRTemp imm8_mask = newTemp(Ity_V128);
13791 assign( imm8_mask, mkV128( imm8_perms[ (imm8 & 15) ] ) );
13792
13793 putXMMReg( gregOfRexRM(pfx, modrm),
13794 binop( Iop_OrV128,
13795 binop( Iop_AndV128, mkexpr(src_vec), mkexpr(imm8_mask) ),
13796 binop( Iop_AndV128, mkexpr(dst_vec),
13797 unop( Iop_NotV128, mkexpr(imm8_mask) ) ) ) );
13798
13799 goto decode_success;
13800 }
13801
13802
sewardja1c1d9a2010-04-29 08:39:18 +000013803 /* 66 0F 3A 41 /r ib = DPPD xmm1, xmm2/m128, imm8
13804 Dot Product of Packed Double Precision Floating-Point Values (XMM) */
13805 if ( have66noF2noF3( pfx )
13806 && sz == 2
13807 && insn[0] == 0x0F && insn[1] == 0x3A && insn[2] == 0x41 ) {
13808
13809 Int imm8;
13810 IRTemp src_vec = newTemp(Ity_V128);
13811 IRTemp dst_vec = newTemp(Ity_V128);
13812 IRTemp and_vec = newTemp(Ity_V128);
13813 IRTemp sum_vec = newTemp(Ity_V128);
13814
13815 modrm = insn[3];
13816
13817 assign( dst_vec, getXMMReg( gregOfRexRM(pfx, modrm) ) );
13818
13819 if ( epartIsReg( modrm ) ) {
13820 imm8 = (Int)insn[4];
13821 assign( src_vec, getXMMReg( eregOfRexRM(pfx, modrm) ) );
13822 delta += 3+1+1;
13823 DIP( "dppd %s,%s,$%d\n",
13824 nameXMMReg( eregOfRexRM(pfx, modrm) ),
13825 nameXMMReg( gregOfRexRM(pfx, modrm) ),
13826 imm8 );
13827 } else {
13828 addr = disAMode( &alen, vbi, pfx, delta+3, dis_buf,
13829 1/* imm8 is 1 byte after the amode */ );
13830 assign( src_vec, loadLE( Ity_V128, mkexpr(addr) ) );
13831 imm8 = (Int)insn[2+alen+1];
13832 delta += 3+alen+1;
13833 DIP( "dppd %s,%s$%d\n",
13834 dis_buf, nameXMMReg( gregOfRexRM(pfx, modrm) ), imm8 );
13835 }
13836
13837 UShort imm8_perms[4] = { 0x0000, 0x00FF, 0xFF00, 0xFFFF };
13838
13839 assign( and_vec, binop( Iop_AndV128,
13840 binop( Iop_Mul64Fx2,
13841 mkexpr(dst_vec), mkexpr(src_vec) ),
13842 mkV128( imm8_perms[ ((imm8 >> 4) & 3) ] ) ) );
13843
13844 assign( sum_vec, binop( Iop_Add64F0x2,
13845 binop( Iop_InterleaveHI64x2,
13846 mkexpr(and_vec), mkexpr(and_vec) ),
13847 binop( Iop_InterleaveLO64x2,
13848 mkexpr(and_vec), mkexpr(and_vec) ) ) );
13849
13850 putXMMReg( gregOfRexRM( pfx, modrm ),
13851 binop( Iop_AndV128,
13852 binop( Iop_InterleaveLO64x2,
13853 mkexpr(sum_vec), mkexpr(sum_vec) ),
13854 mkV128( imm8_perms[ (imm8 & 3) ] ) ) );
13855
13856 goto decode_success;
13857 }
13858
13859
13860 /* 66 0F 3A 40 /r ib = DPPS xmm1, xmm2/m128, imm8
13861 Dot Product of Packed Single Precision Floating-Point Values (XMM) */
13862 if ( have66noF2noF3( pfx )
13863 && sz == 2
13864 && insn[0] == 0x0F
13865 && insn[1] == 0x3A
13866 && insn[2] == 0x40 ) {
13867
13868 Int imm8;
13869 IRTemp xmm1_vec = newTemp(Ity_V128);
13870 IRTemp xmm2_vec = newTemp(Ity_V128);
13871 IRTemp tmp_prod_vec = newTemp(Ity_V128);
13872 IRTemp prod_vec = newTemp(Ity_V128);
13873 IRTemp sum_vec = newTemp(Ity_V128);
13874 IRTemp v3, v2, v1, v0;
13875 v3 = v2 = v1 = v0 = IRTemp_INVALID;
13876
13877 modrm = insn[3];
13878
13879 assign( xmm1_vec, getXMMReg( gregOfRexRM(pfx, modrm) ) );
13880
13881 if ( epartIsReg( modrm ) ) {
13882 imm8 = (Int)insn[4];
13883 assign( xmm2_vec, getXMMReg( eregOfRexRM(pfx, modrm) ) );
13884 delta += 3+1+1;
13885 DIP( "dpps %s,%s,$%d\n",
13886 nameXMMReg( eregOfRexRM(pfx, modrm) ),
13887 nameXMMReg( gregOfRexRM(pfx, modrm) ),
13888 imm8 );
13889 } else {
13890 addr = disAMode( &alen, vbi, pfx, delta+3, dis_buf,
13891 1/* imm8 is 1 byte after the amode */ );
13892 assign( xmm2_vec, loadLE( Ity_V128, mkexpr(addr) ) );
13893 imm8 = (Int)insn[2+alen+1];
13894 delta += 3+alen+1;
13895 DIP( "dpps %s,%s$%d\n",
13896 dis_buf, nameXMMReg( gregOfRexRM(pfx, modrm) ), imm8 );
13897 }
13898
13899 UShort imm8_perms[16] = { 0x0000, 0x000F, 0x00F0, 0x00FF, 0x0F00,
13900 0x0F0F, 0x0FF0, 0x0FFF, 0xF000, 0xF00F,
13901 0xF0F0, 0xF0FF, 0xFF00, 0xFF0F, 0xFFF0, 0xFFFF };
13902
13903 assign( tmp_prod_vec,
13904 binop( Iop_AndV128,
13905 binop( Iop_Mul32Fx4, mkexpr(xmm1_vec), mkexpr(xmm2_vec) ),
13906 mkV128( imm8_perms[((imm8 >> 4)& 15)] ) ) );
13907 breakup128to32s( tmp_prod_vec, &v3, &v2, &v1, &v0 );
13908 assign( prod_vec, mk128from32s( v3, v1, v2, v0 ) );
13909
13910 assign( sum_vec, binop( Iop_Add32Fx4,
13911 binop( Iop_InterleaveHI32x4,
13912 mkexpr(prod_vec), mkexpr(prod_vec) ),
13913 binop( Iop_InterleaveLO32x4,
13914 mkexpr(prod_vec), mkexpr(prod_vec) ) ) );
13915
13916 putXMMReg( gregOfRexRM(pfx, modrm),
13917 binop( Iop_AndV128,
13918 binop( Iop_Add32Fx4,
13919 binop( Iop_InterleaveHI32x4,
13920 mkexpr(sum_vec), mkexpr(sum_vec) ),
13921 binop( Iop_InterleaveLO32x4,
13922 mkexpr(sum_vec), mkexpr(sum_vec) ) ),
13923 mkV128( imm8_perms[ (imm8 & 15) ] ) ) );
13924
13925 goto decode_success;
13926 }
13927
13928
de5a70f5c2010-04-01 23:08:59 +000013929 /* 66 0F 3A 21 /r ib = INSERTPS xmm1, xmm2/m32, imm8
13930 Insert Packed Single Precision Floating-Point Value (XMM) */
13931 if ( have66noF2noF3( pfx )
13932 && sz == 2
13933 && insn[0] == 0x0F && insn[1] == 0x3A && insn[2] == 0x21 ) {
13934
13935 Int imm8;
13936 Int imm8_count_s;
13937 Int imm8_count_d;
13938 Int imm8_zmask;
13939 IRTemp dstVec = newTemp(Ity_V128);
13940 IRTemp srcDWord = newTemp(Ity_I32);
13941
13942 modrm = insn[3];
13943
13944 assign( dstVec, getXMMReg( gregOfRexRM(pfx, modrm) ) );
13945
13946 if ( epartIsReg( modrm ) ) {
13947 IRTemp src_vec = newTemp(Ity_V128);
13948 assign( src_vec, getXMMReg( eregOfRexRM(pfx, modrm) ) );
13949
13950 IRTemp src_lane_0 = IRTemp_INVALID;
13951 IRTemp src_lane_1 = IRTemp_INVALID;
13952 IRTemp src_lane_2 = IRTemp_INVALID;
13953 IRTemp src_lane_3 = IRTemp_INVALID;
13954 breakup128to32s( src_vec,
13955 &src_lane_3, &src_lane_2, &src_lane_1, &src_lane_0 );
13956
13957 imm8 = (Int)insn[4];
13958 imm8_count_s = ((imm8 >> 6) & 3);
13959 switch( imm8_count_s ) {
13960 case 0: assign( srcDWord, mkexpr(src_lane_0) ); break;
13961 case 1: assign( srcDWord, mkexpr(src_lane_1) ); break;
13962 case 2: assign( srcDWord, mkexpr(src_lane_2) ); break;
13963 case 3: assign( srcDWord, mkexpr(src_lane_3) ); break;
13964 default: vassert(0); break;
13965 }
13966
13967 delta += 3+1+1;
13968 DIP( "insertps %s,%s,$%d\n",
13969 nameXMMReg( eregOfRexRM(pfx, modrm) ),
13970 nameXMMReg( gregOfRexRM(pfx, modrm) ),
13971 imm8 );
13972 } else {
13973 addr = disAMode( &alen, vbi, pfx, delta+3, dis_buf,
13974 1/* const imm8 is 1 byte after the amode */ );
13975 assign( srcDWord, loadLE( Ity_I32, mkexpr(addr) ) );
13976 imm8 = (Int)insn[2+alen+1];
13977 imm8_count_s = 0;
13978 delta += 3+alen+1;
13979 DIP( "insertps %s,%s,$%d\n",
13980 dis_buf, nameXMMReg( gregOfRexRM(pfx, modrm) ), imm8 );
13981 }
13982
13983 IRTemp dst_lane_0 = IRTemp_INVALID;
13984 IRTemp dst_lane_1 = IRTemp_INVALID;
13985 IRTemp dst_lane_2 = IRTemp_INVALID;
13986 IRTemp dst_lane_3 = IRTemp_INVALID;
13987 breakup128to32s( dstVec,
13988 &dst_lane_3, &dst_lane_2, &dst_lane_1, &dst_lane_0 );
13989
13990 imm8_count_d = ((imm8 >> 4) & 3);
13991 switch( imm8_count_d ) {
13992 case 0: dst_lane_0 = srcDWord; break;
13993 case 1: dst_lane_1 = srcDWord; break;
13994 case 2: dst_lane_2 = srcDWord; break;
13995 case 3: dst_lane_3 = srcDWord; break;
13996 default: vassert(0); break;
13997 }
13998
13999 imm8_zmask = (imm8 & 15);
14000 IRTemp zero_32 = newTemp(Ity_I32);
14001 assign( zero_32, mkU32(0) );
14002
14003 IRExpr* ire_vec_128 = mk128from32s(
14004 ((imm8_zmask & 8) == 8) ? zero_32 : dst_lane_3,
14005 ((imm8_zmask & 4) == 4) ? zero_32 : dst_lane_2,
14006 ((imm8_zmask & 2) == 2) ? zero_32 : dst_lane_1,
14007 ((imm8_zmask & 1) == 1) ? zero_32 : dst_lane_0 );
14008
14009 putXMMReg( gregOfRexRM(pfx, modrm), ire_vec_128 );
14010
14011 goto decode_success;
14012 }
14013
de5a70f5c2010-04-01 23:08:59 +000014014
deb5afdbd2010-04-02 13:17:50 +000014015 /* 66 0f 38 20 /r = PMOVSXBW xmm1, xmm2/m64
14016 Packed Move with Sign Extend from Byte to Word (XMM) */
de5a70f5c2010-04-01 23:08:59 +000014017 if ( have66noF2noF3( pfx )
14018 && sz == 2
14019 && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x20 ) {
14020
14021 modrm = insn[3];
14022
14023 IRTemp srcVec = newTemp(Ity_V128);
14024
14025 if ( epartIsReg( modrm ) ) {
14026 assign( srcVec, getXMMReg( eregOfRexRM(pfx, modrm) ) );
14027 delta += 3+1;
14028 DIP( "pmovsxbw %s,%s\n",
14029 nameXMMReg( eregOfRexRM(pfx, modrm) ),
14030 nameXMMReg( gregOfRexRM(pfx, modrm) ) );
14031 } else {
14032 addr = disAMode( &alen, vbi, pfx, delta+3, dis_buf, 0 );
14033 assign( srcVec,
14034 unop( Iop_64UtoV128, loadLE( Ity_I64, mkexpr(addr) ) ) );
14035 delta += 3+alen;
14036 DIP( "pmovsxbw %s,%s\n",
14037 dis_buf, nameXMMReg( gregOfRexRM(pfx, modrm) ) );
14038 }
14039
14040 putXMMReg( gregOfRexRM(pfx, modrm),
sewardj7cfc3062010-04-02 11:31:22 +000014041 binop( Iop_SarN16x8,
14042 binop( Iop_ShlN16x8,
de5a70f5c2010-04-01 23:08:59 +000014043 binop( Iop_InterleaveLO8x16,
14044 IRExpr_Const( IRConst_V128(0) ),
14045 mkexpr(srcVec) ),
14046 mkU8(8) ),
14047 mkU8(8) ) );
14048
14049 goto decode_success;
14050 }
de5a70f5c2010-04-01 23:08:59 +000014051
14052
14053 /* 66 0f 38 21 /r = PMOVSXBD xmm1, xmm2/m32
14054 Packed Move with Sign Extend from Byte to DWord (XMM) */
14055 if ( have66noF2noF3( pfx )
14056 && sz == 2
14057 && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x21 ) {
14058
14059 modrm = insn[3];
14060
14061 IRTemp srcVec = newTemp(Ity_V128);
14062
14063 if ( epartIsReg( modrm ) ) {
14064 assign( srcVec, getXMMReg( eregOfRexRM(pfx, modrm) ) );
14065 delta += 3+1;
14066 DIP( "pmovsxbd %s,%s\n",
14067 nameXMMReg( eregOfRexRM(pfx, modrm) ),
14068 nameXMMReg( gregOfRexRM(pfx, modrm) ) );
14069 } else {
14070 addr = disAMode( &alen, vbi, pfx, delta+3, dis_buf, 0 );
14071 assign( srcVec,
14072 unop( Iop_32UtoV128, loadLE( Ity_I32, mkexpr(addr) ) ) );
14073 delta += 3+alen;
14074 DIP( "pmovsxbd %s,%s\n",
14075 dis_buf, nameXMMReg( gregOfRexRM(pfx, modrm) ) );
14076 }
14077
14078 IRTemp zeroVec = newTemp(Ity_V128);
14079 assign( zeroVec, IRExpr_Const( IRConst_V128(0) ) );
14080
14081 putXMMReg( gregOfRexRM(pfx, modrm),
14082 binop( Iop_SarN32x4,
14083 binop( Iop_ShlN32x4,
14084 binop( Iop_InterleaveLO8x16,
14085 mkexpr(zeroVec),
14086 binop( Iop_InterleaveLO8x16,
14087 mkexpr(zeroVec),
14088 mkexpr(srcVec) ) ),
14089 mkU8(24) ), mkU8(24) ) );
14090
14091 goto decode_success;
14092 }
14093
14094
14095 /* 66 0f 38 22 /r = PMOVSXBQ xmm1, xmm2/m16
14096 Packed Move with Sign Extend from Byte to QWord (XMM) */
14097 if ( have66noF2noF3(pfx)
14098 && sz == 2
14099 && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x22 ) {
14100
14101 modrm = insn[3];
14102
14103 IRTemp srcBytes = newTemp(Ity_I16);
14104
14105 if ( epartIsReg(modrm) ) {
14106 assign( srcBytes, getXMMRegLane16( eregOfRexRM(pfx, modrm), 0 ) );
14107 delta += 3+1;
14108 DIP( "pmovsxbq %s,%s\n",
14109 nameXMMReg( eregOfRexRM(pfx, modrm) ),
14110 nameXMMReg( gregOfRexRM(pfx, modrm) ) );
14111 } else {
14112 addr = disAMode( &alen, vbi, pfx, delta+3, dis_buf, 0 );
14113 assign( srcBytes, loadLE( Ity_I16, mkexpr(addr) ) );
14114 delta += 3+alen;
14115 DIP( "pmovsxbq %s,%s\n",
14116 dis_buf, nameXMMReg( gregOfRexRM(pfx, modrm) ) );
14117 }
14118
14119 putXMMReg( gregOfRexRM( pfx, modrm ),
14120 binop( Iop_64HLtoV128,
14121 unop( Iop_8Sto64,
14122 unop( Iop_16HIto8,
14123 mkexpr(srcBytes) ) ),
14124 unop( Iop_8Sto64,
14125 unop( Iop_16to8, mkexpr(srcBytes) ) ) ) );
14126
14127 goto decode_success;
14128 }
14129
14130
14131 /* 66 0f 38 23 /r = PMOVSXWD xmm1, xmm2/m64
14132 Packed Move with Sign Extend from Word to DWord (XMM) */
14133 if ( have66noF2noF3( pfx )
14134 && sz == 2
14135 && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x23 ) {
14136
14137 modrm = insn[3];
14138
14139 IRTemp srcVec = newTemp(Ity_V128);
14140
14141 if ( epartIsReg(modrm) ) {
14142 assign( srcVec, getXMMReg( eregOfRexRM(pfx, modrm) ) );
14143 delta += 3+1;
14144 DIP( "pmovsxwd %s,%s\n",
14145 nameXMMReg( eregOfRexRM(pfx, modrm) ),
14146 nameXMMReg( gregOfRexRM(pfx, modrm) ) );
14147 } else {
14148 addr = disAMode( &alen, vbi, pfx, delta+3, dis_buf, 0 );
14149 assign( srcVec,
14150 unop( Iop_64UtoV128, loadLE( Ity_I64, mkexpr(addr) ) ) );
14151 delta += 3+alen;
14152 DIP( "pmovsxwd %s,%s\n",
14153 dis_buf, nameXMMReg( gregOfRexRM(pfx, modrm) ) );
14154 }
14155
14156 putXMMReg( gregOfRexRM(pfx, modrm),
14157 binop( Iop_SarN32x4,
14158 binop( Iop_ShlN32x4,
14159 binop( Iop_InterleaveLO16x8,
14160 IRExpr_Const( IRConst_V128(0) ),
14161 mkexpr(srcVec) ),
14162 mkU8(16) ),
14163 mkU8(16) ) );
14164
14165 goto decode_success;
14166 }
14167
14168
14169 /* 66 0f 38 24 /r = PMOVSXWQ xmm1, xmm2/m32
14170 Packed Move with Sign Extend from Word to QWord (XMM) */
14171 if ( have66noF2noF3( pfx )
14172 && sz == 2
14173 && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x24 ) {
14174
14175 modrm = insn[3];
14176
14177 IRTemp srcBytes = newTemp(Ity_I32);
14178
14179 if ( epartIsReg( modrm ) ) {
14180 assign( srcBytes, getXMMRegLane32( eregOfRexRM(pfx, modrm), 0 ) );
14181 delta += 3+1;
14182 DIP( "pmovsxwq %s,%s\n",
14183 nameXMMReg( eregOfRexRM(pfx, modrm) ),
14184 nameXMMReg( gregOfRexRM(pfx, modrm) ) );
14185 } else {
14186 addr = disAMode( &alen, vbi, pfx, delta+3, dis_buf, 0 );
14187 assign( srcBytes, loadLE( Ity_I32, mkexpr(addr) ) );
14188 delta += 3+alen;
14189 DIP( "pmovsxwq %s,%s\n",
14190 dis_buf, nameXMMReg( gregOfRexRM(pfx, modrm) ) );
14191 }
14192
14193 putXMMReg( gregOfRexRM( pfx, modrm ),
14194 binop( Iop_64HLtoV128,
14195 unop( Iop_16Sto64,
14196 unop( Iop_32HIto16, mkexpr(srcBytes) ) ),
14197 unop( Iop_16Sto64,
14198 unop( Iop_32to16, mkexpr(srcBytes) ) ) ) );
14199
14200 goto decode_success;
14201 }
14202
14203
14204 /* 66 0f 38 25 /r = PMOVSXDQ xmm1, xmm2/m64
14205 Packed Move with Sign Extend from Double Word to Quad Word (XMM) */
14206 if ( have66noF2noF3( pfx )
14207 && sz == 2
14208 && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x25 ) {
14209
14210 modrm = insn[3];
14211
14212 IRTemp srcBytes = newTemp(Ity_I64);
14213
14214 if ( epartIsReg(modrm) ) {
14215 assign( srcBytes, getXMMRegLane64( eregOfRexRM(pfx, modrm), 0 ) );
14216 delta += 3+1;
14217 DIP( "pmovsxdq %s,%s\n",
14218 nameXMMReg( eregOfRexRM(pfx, modrm) ),
14219 nameXMMReg( gregOfRexRM(pfx, modrm) ) );
14220 } else {
14221 addr = disAMode( &alen, vbi, pfx, delta+3, dis_buf, 0 );
14222 assign( srcBytes, loadLE( Ity_I64, mkexpr(addr) ) );
14223 delta += 3+alen;
14224 DIP( "pmovsxdq %s,%s\n",
14225 dis_buf, nameXMMReg( gregOfRexRM(pfx, modrm) ) );
14226 }
14227
14228 putXMMReg( gregOfRexRM(pfx, modrm),
14229 binop( Iop_64HLtoV128,
14230 unop( Iop_32Sto64,
14231 unop( Iop_64HIto32, mkexpr(srcBytes) ) ),
14232 unop( Iop_32Sto64,
14233 unop( Iop_64to32, mkexpr(srcBytes) ) ) ) );
14234
14235 goto decode_success;
14236 }
14237
14238
14239 /* 66 0f 38 30 /r = PMOVZXBW xmm1, xmm2/m64
14240 Packed Move with Zero Extend from Byte to Word (XMM) */
14241 if ( have66noF2noF3(pfx)
14242 && sz == 2
14243 && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x30 ) {
14244
14245 modrm = insn[3];
14246
14247 IRTemp srcVec = newTemp(Ity_V128);
14248
14249 if ( epartIsReg(modrm) ) {
14250 assign( srcVec, getXMMReg( eregOfRexRM(pfx, modrm) ) );
14251 delta += 3+1;
14252 DIP( "pmovzxbw %s,%s\n",
14253 nameXMMReg( eregOfRexRM(pfx, modrm) ),
14254 nameXMMReg( gregOfRexRM(pfx, modrm) ) );
14255 } else {
14256 addr = disAMode( &alen, vbi, pfx, delta+3, dis_buf, 0 );
14257 assign( srcVec,
14258 unop( Iop_64UtoV128, loadLE( Ity_I64, mkexpr(addr) ) ) );
14259 delta += 3+alen;
14260 DIP( "pmovzxbw %s,%s\n",
14261 dis_buf, nameXMMReg( gregOfRexRM(pfx, modrm) ) );
14262 }
14263
14264 putXMMReg( gregOfRexRM(pfx, modrm),
14265 binop( Iop_InterleaveLO8x16,
14266 IRExpr_Const( IRConst_V128(0) ), mkexpr(srcVec) ) );
14267
14268 goto decode_success;
14269 }
14270
14271
14272 /* 66 0f 38 31 /r = PMOVZXBD xmm1, xmm2/m32
14273 Packed Move with Zero Extend from Byte to DWord (XMM) */
14274 if ( have66noF2noF3( pfx )
14275 && sz == 2
14276 && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x31 ) {
14277
14278 modrm = insn[3];
14279
14280 IRTemp srcVec = newTemp(Ity_V128);
14281
14282 if ( epartIsReg(modrm) ) {
14283 assign( srcVec, getXMMReg( eregOfRexRM(pfx, modrm) ) );
14284 delta += 3+1;
14285 DIP( "pmovzxbd %s,%s\n",
14286 nameXMMReg( eregOfRexRM(pfx, modrm) ),
14287 nameXMMReg( gregOfRexRM(pfx, modrm) ) );
14288 } else {
14289 addr = disAMode( &alen, vbi, pfx, delta+3, dis_buf, 0 );
14290 assign( srcVec,
14291 unop( Iop_32UtoV128, loadLE( Ity_I32, mkexpr(addr) ) ) );
14292 delta += 3+alen;
14293 DIP( "pmovzxbd %s,%s\n",
14294 dis_buf, nameXMMReg( gregOfRexRM(pfx, modrm) ) );
14295 }
14296
14297 IRTemp zeroVec = newTemp(Ity_V128);
14298 assign( zeroVec, IRExpr_Const( IRConst_V128(0) ) );
14299
14300 putXMMReg( gregOfRexRM( pfx, modrm ),
14301 binop( Iop_InterleaveLO8x16,
14302 mkexpr(zeroVec),
14303 binop( Iop_InterleaveLO8x16,
14304 mkexpr(zeroVec), mkexpr(srcVec) ) ) );
14305
14306 goto decode_success;
14307 }
14308
14309
14310 /* 66 0f 38 32 /r = PMOVZXBQ xmm1, xmm2/m16
14311 Packed Move with Zero Extend from Byte to QWord (XMM) */
14312 if ( have66noF2noF3( pfx )
14313 && sz == 2
14314 && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x32 ) {
14315
14316 modrm = insn[3];
14317
14318 IRTemp srcVec = newTemp(Ity_V128);
14319
14320 if ( epartIsReg(modrm) ) {
14321 assign( srcVec, getXMMReg( eregOfRexRM(pfx, modrm) ) );
14322 delta += 3+1;
14323 DIP( "pmovzxbq %s,%s\n",
14324 nameXMMReg( eregOfRexRM(pfx, modrm) ),
14325 nameXMMReg( gregOfRexRM(pfx, modrm) ) );
14326 } else {
14327 addr = disAMode( &alen, vbi, pfx, delta+3, dis_buf, 0 );
14328 assign( srcVec,
14329 unop( Iop_32UtoV128,
14330 unop( Iop_16Uto32, loadLE( Ity_I16, mkexpr(addr) ) ) ) );
14331 delta += 3+alen;
14332 DIP( "pmovzxbq %s,%s\n",
14333 dis_buf, nameXMMReg( gregOfRexRM(pfx, modrm) ) );
14334 }
14335
14336 IRTemp zeroVec = newTemp(Ity_V128);
14337 assign( zeroVec, IRExpr_Const( IRConst_V128(0) ) );
14338
14339 putXMMReg( gregOfRexRM( pfx, modrm ),
14340 binop( Iop_InterleaveLO8x16,
14341 mkexpr(zeroVec),
14342 binop( Iop_InterleaveLO8x16,
14343 mkexpr(zeroVec),
14344 binop( Iop_InterleaveLO8x16,
14345 mkexpr(zeroVec), mkexpr(srcVec) ) ) ) );
14346
14347 goto decode_success;
14348 }
14349
14350
14351 /* 66 0f 38 33 /r = PMOVZXWD xmm1, xmm2/m64
14352 Packed Move with Zero Extend from Word to DWord (XMM) */
14353 if ( have66noF2noF3( pfx )
14354 && sz == 2
14355 && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x33 ) {
14356
14357 modrm = insn[3];
14358
14359 IRTemp srcVec = newTemp(Ity_V128);
14360
14361 if ( epartIsReg(modrm) ) {
14362 assign( srcVec, getXMMReg( eregOfRexRM(pfx, modrm) ) );
14363 delta += 3+1;
14364 DIP( "pmovzxwd %s,%s\n",
14365 nameXMMReg( eregOfRexRM(pfx, modrm) ),
14366 nameXMMReg( gregOfRexRM(pfx, modrm) ) );
14367 } else {
14368 addr = disAMode( &alen, vbi, pfx, delta+3, dis_buf, 0 );
14369 assign( srcVec,
14370 unop( Iop_64UtoV128, loadLE( Ity_I64, mkexpr(addr) ) ) );
14371 delta += 3+alen;
14372 DIP( "pmovzxwd %s,%s\n",
14373 dis_buf, nameXMMReg( gregOfRexRM(pfx, modrm) ) );
14374 }
14375
14376 putXMMReg( gregOfRexRM(pfx, modrm),
14377 binop( Iop_InterleaveLO16x8,
14378 IRExpr_Const( IRConst_V128(0) ),
14379 mkexpr(srcVec) ) );
14380
14381 goto decode_success;
14382 }
14383
14384
14385 /* 66 0f 38 34 /r = PMOVZXWQ xmm1, xmm2/m32
14386 Packed Move with Zero Extend from Word to QWord (XMM) */
14387 if ( have66noF2noF3( pfx )
14388 && sz == 2
14389 && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x34 ) {
14390
14391 modrm = insn[3];
14392
14393 IRTemp srcVec = newTemp(Ity_V128);
14394
14395 if ( epartIsReg( modrm ) ) {
14396 assign( srcVec, getXMMReg( eregOfRexRM(pfx, modrm) ) );
14397 delta += 3+1;
14398 DIP( "pmovzxwq %s,%s\n",
14399 nameXMMReg( eregOfRexRM(pfx, modrm) ),
14400 nameXMMReg( gregOfRexRM(pfx, modrm) ) );
14401 } else {
14402 addr = disAMode( &alen, vbi, pfx, delta+3, dis_buf, 0 );
14403 assign( srcVec,
14404 unop( Iop_32UtoV128, loadLE( Ity_I32, mkexpr(addr) ) ) );
14405 delta += 3+alen;
14406 DIP( "pmovzxwq %s,%s\n",
14407 dis_buf, nameXMMReg( gregOfRexRM(pfx, modrm) ) );
14408 }
14409
14410 IRTemp zeroVec = newTemp( Ity_V128 );
14411 assign( zeroVec, IRExpr_Const( IRConst_V128(0) ) );
14412
14413 putXMMReg( gregOfRexRM( pfx, modrm ),
14414 binop( Iop_InterleaveLO16x8,
14415 mkexpr(zeroVec),
14416 binop( Iop_InterleaveLO16x8,
14417 mkexpr(zeroVec), mkexpr(srcVec) ) ) );
14418
14419 goto decode_success;
14420 }
14421
14422
14423 /* 66 0f 38 35 /r = PMOVZXDQ xmm1, xmm2/m64
14424 Packed Move with Zero Extend from DWord to QWord (XMM) */
14425 if ( have66noF2noF3( pfx )
14426 && sz == 2
14427 && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x35 ) {
14428
14429 modrm = insn[3];
14430
14431 IRTemp srcVec = newTemp(Ity_V128);
14432
14433 if ( epartIsReg(modrm) ) {
14434 assign( srcVec, getXMMReg( eregOfRexRM(pfx, modrm) ) );
14435 delta += 3+1;
14436 DIP( "pmovzxdq %s,%s\n",
14437 nameXMMReg( eregOfRexRM(pfx, modrm) ),
14438 nameXMMReg( gregOfRexRM(pfx, modrm) ) );
14439 } else {
14440 addr = disAMode( &alen, vbi, pfx, delta+3, dis_buf, 0 );
14441 assign( srcVec,
14442 unop( Iop_64UtoV128, loadLE( Ity_I64, mkexpr(addr) ) ) );
14443 delta += 3+alen;
14444 DIP( "pmovzxdq %s,%s\n",
14445 dis_buf, nameXMMReg( gregOfRexRM(pfx, modrm) ) );
14446 }
14447
14448 putXMMReg( gregOfRexRM(pfx, modrm),
14449 binop( Iop_InterleaveLO32x4,
14450 IRExpr_Const( IRConst_V128(0) ),
14451 mkexpr(srcVec) ) );
14452
14453 goto decode_success;
14454 }
14455
14456
14457 /* ---------------------------------------------------- */
14458 /* --- end of the SSE4 decoder --- */
14459 /* ---------------------------------------------------- */
14460
sewardj7a240552005-01-28 21:37:12 +000014461 /*after_sse_decoders:*/
sewardjdf0e0022005-01-25 15:48:43 +000014462
14463 /* Get the primary opcode. */
sewardj8c332e22005-01-28 01:36:56 +000014464 opc = getUChar(delta); delta++;
sewardjdf0e0022005-01-25 15:48:43 +000014465
14466 /* We get here if the current insn isn't SSE, or this CPU doesn't
14467 support SSE. */
14468
14469 switch (opc) {
14470
14471 /* ------------------------ Control flow --------------- */
14472
sewardj47c2d4d2006-11-14 17:50:16 +000014473 case 0xC2: /* RET imm16 */
14474 if (have66orF2orF3(pfx)) goto decode_failure;
14475 d64 = getUDisp16(delta);
14476 delta += 2;
sewardj2e28ac42008-12-04 00:05:12 +000014477 dis_ret(vbi, d64);
sewardj47c2d4d2006-11-14 17:50:16 +000014478 dres.whatNext = Dis_StopHere;
14479 DIP("ret %lld\n", d64);
14480 break;
14481
sewardj2f959cc2005-01-26 01:19:35 +000014482 case 0xC3: /* RET */
sewardj47c2d4d2006-11-14 17:50:16 +000014483 if (have66orF2(pfx)) goto decode_failure;
sewardj55dbb262005-01-28 16:36:51 +000014484 /* F3 is acceptable on AMD. */
sewardj2e28ac42008-12-04 00:05:12 +000014485 dis_ret(vbi, 0);
sewardj9e6491a2005-07-02 19:24:10 +000014486 dres.whatNext = Dis_StopHere;
sewardje941eea2005-01-30 19:52:28 +000014487 DIP(haveF3(pfx) ? "rep ; ret\n" : "ret\n");
sewardj2f959cc2005-01-26 01:19:35 +000014488 break;
14489
sewardj3ca55a12005-01-27 16:06:23 +000014490 case 0xE8: /* CALL J4 */
14491 if (haveF2orF3(pfx)) goto decode_failure;
14492 d64 = getSDisp32(delta); delta += 4;
sewardj9e6491a2005-07-02 19:24:10 +000014493 d64 += (guest_RIP_bbstart+delta);
14494 /* (guest_RIP_bbstart+delta) == return-to addr, d64 == call-to addr */
sewardj3ca55a12005-01-27 16:06:23 +000014495 t1 = newTemp(Ity_I64);
14496 assign(t1, binop(Iop_Sub64, getIReg64(R_RSP), mkU64(8)));
14497 putIReg64(R_RSP, mkexpr(t1));
sewardj9e6491a2005-07-02 19:24:10 +000014498 storeLE( mkexpr(t1), mkU64(guest_RIP_bbstart+delta));
sewardj478646f2008-05-01 20:13:04 +000014499 t2 = newTemp(Ity_I64);
14500 assign(t2, mkU64((Addr64)d64));
sewardj2e28ac42008-12-04 00:05:12 +000014501 make_redzone_AbiHint(vbi, t1, t2/*nia*/, "call-d32");
sewardjc716aea2006-01-17 01:48:46 +000014502 if (resteerOkFn( callback_opaque, (Addr64)d64) ) {
sewardj3ca55a12005-01-27 16:06:23 +000014503 /* follow into the call target. */
sewardj984d9b12010-01-15 10:53:21 +000014504 dres.whatNext = Dis_ResteerU;
sewardj9e6491a2005-07-02 19:24:10 +000014505 dres.continueAt = d64;
sewardj3ca55a12005-01-27 16:06:23 +000014506 } else {
14507 jmp_lit(Ijk_Call,d64);
sewardj9e6491a2005-07-02 19:24:10 +000014508 dres.whatNext = Dis_StopHere;
sewardj3ca55a12005-01-27 16:06:23 +000014509 }
14510 DIP("call 0x%llx\n",d64);
14511 break;
14512
sewardjd20c8852005-01-20 20:04:07 +000014513//.. //-- case 0xC8: /* ENTER */
14514//.. //-- d32 = getUDisp16(eip); eip += 2;
sewardj8c332e22005-01-28 01:36:56 +000014515//.. //-- abyte = getUChar(delta); delta++;
sewardjd20c8852005-01-20 20:04:07 +000014516//.. //--
14517//.. //-- vg_assert(sz == 4);
14518//.. //-- vg_assert(abyte == 0);
14519//.. //--
14520//.. //-- t1 = newTemp(cb); t2 = newTemp(cb);
14521//.. //-- uInstr2(cb, GET, sz, ArchReg, R_EBP, TempReg, t1);
14522//.. //-- uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t2);
14523//.. //-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
14524//.. //-- uLiteral(cb, sz);
14525//.. //-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
14526//.. //-- uInstr2(cb, STORE, 4, TempReg, t1, TempReg, t2);
14527//.. //-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_EBP);
14528//.. //-- if (d32) {
14529//.. //-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
14530//.. //-- uLiteral(cb, d32);
14531//.. //-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
14532//.. //-- }
14533//.. //-- DIP("enter 0x%x, 0x%x", d32, abyte);
14534//.. //-- break;
sewardje1698952005-02-08 15:02:39 +000014535
14536 case 0xC9: /* LEAVE */
14537 /* In 64-bit mode this defaults to a 64-bit operand size. There
14538 is no way to encode a 32-bit variant. Hence sz==4 but we do
14539 it as if sz=8. */
14540 if (sz != 4)
14541 goto decode_failure;
14542 t1 = newTemp(Ity_I64);
14543 t2 = newTemp(Ity_I64);
14544 assign(t1, getIReg64(R_RBP));
14545 /* First PUT RSP looks redundant, but need it because RSP must
14546 always be up-to-date for Memcheck to work... */
14547 putIReg64(R_RSP, mkexpr(t1));
14548 assign(t2, loadLE(Ity_I64,mkexpr(t1)));
14549 putIReg64(R_RBP, mkexpr(t2));
14550 putIReg64(R_RSP, binop(Iop_Add64, mkexpr(t1), mkU64(8)) );
14551 DIP("leave\n");
14552 break;
14553
sewardjd20c8852005-01-20 20:04:07 +000014554//.. //-- /* ---------------- Misc weird-ass insns --------------- */
14555//.. //--
14556//.. //-- case 0x27: /* DAA */
14557//.. //-- case 0x2F: /* DAS */
14558//.. //-- t1 = newTemp(cb);
14559//.. //-- uInstr2(cb, GET, 1, ArchReg, R_AL, TempReg, t1);
14560//.. //-- /* Widen %AL to 32 bits, so it's all defined when we push it. */
14561//.. //-- uInstr1(cb, WIDEN, 4, TempReg, t1);
14562//.. //-- uWiden(cb, 1, False);
14563//.. //-- uInstr0(cb, CALLM_S, 0);
14564//.. //-- uInstr1(cb, PUSH, 4, TempReg, t1);
14565//.. //-- uInstr1(cb, CALLM, 0, Lit16,
14566//.. //-- opc == 0x27 ? VGOFF_(helper_DAA) : VGOFF_(helper_DAS) );
14567//.. //-- uFlagsRWU(cb, FlagsAC, FlagsSZACP, FlagO);
14568//.. //-- uInstr1(cb, POP, 4, TempReg, t1);
14569//.. //-- uInstr0(cb, CALLM_E, 0);
14570//.. //-- uInstr2(cb, PUT, 1, TempReg, t1, ArchReg, R_AL);
14571//.. //-- DIP(opc == 0x27 ? "daa\n" : "das\n");
14572//.. //-- break;
14573//.. //--
14574//.. //-- case 0x37: /* AAA */
14575//.. //-- case 0x3F: /* AAS */
14576//.. //-- t1 = newTemp(cb);
14577//.. //-- uInstr2(cb, GET, 2, ArchReg, R_EAX, TempReg, t1);
14578//.. //-- /* Widen %AL to 32 bits, so it's all defined when we push it. */
14579//.. //-- uInstr1(cb, WIDEN, 4, TempReg, t1);
14580//.. //-- uWiden(cb, 2, False);
14581//.. //-- uInstr0(cb, CALLM_S, 0);
14582//.. //-- uInstr1(cb, PUSH, 4, TempReg, t1);
14583//.. //-- uInstr1(cb, CALLM, 0, Lit16,
14584//.. //-- opc == 0x37 ? VGOFF_(helper_AAA) : VGOFF_(helper_AAS) );
14585//.. //-- uFlagsRWU(cb, FlagA, FlagsAC, FlagsEmpty);
14586//.. //-- uInstr1(cb, POP, 4, TempReg, t1);
14587//.. //-- uInstr0(cb, CALLM_E, 0);
14588//.. //-- uInstr2(cb, PUT, 2, TempReg, t1, ArchReg, R_EAX);
14589//.. //-- DIP(opc == 0x37 ? "aaa\n" : "aas\n");
14590//.. //-- break;
14591//.. //--
14592//.. //-- case 0xD4: /* AAM */
14593//.. //-- case 0xD5: /* AAD */
sewardj8c332e22005-01-28 01:36:56 +000014594//.. //-- d32 = getUChar(delta); delta++;
sewardjd20c8852005-01-20 20:04:07 +000014595//.. //-- if (d32 != 10) VG_(core_panic)("disInstr: AAM/AAD but base not 10 !");
14596//.. //-- t1 = newTemp(cb);
14597//.. //-- uInstr2(cb, GET, 2, ArchReg, R_EAX, TempReg, t1);
14598//.. //-- /* Widen %AX to 32 bits, so it's all defined when we push it. */
14599//.. //-- uInstr1(cb, WIDEN, 4, TempReg, t1);
14600//.. //-- uWiden(cb, 2, False);
14601//.. //-- uInstr0(cb, CALLM_S, 0);
14602//.. //-- uInstr1(cb, PUSH, 4, TempReg, t1);
14603//.. //-- uInstr1(cb, CALLM, 0, Lit16,
14604//.. //-- opc == 0xD4 ? VGOFF_(helper_AAM) : VGOFF_(helper_AAD) );
14605//.. //-- uFlagsRWU(cb, FlagsEmpty, FlagsSZP, FlagsEmpty);
14606//.. //-- uInstr1(cb, POP, 4, TempReg, t1);
14607//.. //-- uInstr0(cb, CALLM_E, 0);
14608//.. //-- uInstr2(cb, PUT, 2, TempReg, t1, ArchReg, R_EAX);
14609//.. //-- DIP(opc == 0xD4 ? "aam\n" : "aad\n");
14610//.. //-- break;
sewardj3ca55a12005-01-27 16:06:23 +000014611
14612 /* ------------------------ CWD/CDQ -------------------- */
14613
14614 case 0x98: /* CBW */
14615 if (haveF2orF3(pfx)) goto decode_failure;
14616 if (sz == 8) {
sewardj5b470602005-02-27 13:10:48 +000014617 putIRegRAX( 8, unop(Iop_32Sto64, getIRegRAX(4)) );
sewardje941eea2005-01-30 19:52:28 +000014618 DIP(/*"cdqe\n"*/"cltq");
14619 break;
14620 }
sewardj3ca55a12005-01-27 16:06:23 +000014621 if (sz == 4) {
sewardj5b470602005-02-27 13:10:48 +000014622 putIRegRAX( 4, unop(Iop_16Sto32, getIRegRAX(2)) );
sewardj7eaa7cf2005-01-31 18:55:22 +000014623 DIP("cwtl\n");
sewardje941eea2005-01-30 19:52:28 +000014624 break;
14625 }
sewardj3ca55a12005-01-27 16:06:23 +000014626 if (sz == 2) {
sewardj5b470602005-02-27 13:10:48 +000014627 putIRegRAX( 2, unop(Iop_8Sto16, getIRegRAX(1)) );
sewardj3ca55a12005-01-27 16:06:23 +000014628 DIP("cbw\n");
sewardj7bc00082005-03-27 05:08:32 +000014629 break;
sewardj3ca55a12005-01-27 16:06:23 +000014630 }
sewardje941eea2005-01-30 19:52:28 +000014631 goto decode_failure;
sewardj3ca55a12005-01-27 16:06:23 +000014632
14633 case 0x99: /* CWD/CDQ/CQO */
14634 if (haveF2orF3(pfx)) goto decode_failure;
14635 vassert(sz == 2 || sz == 4 || sz == 8);
14636 ty = szToITy(sz);
sewardj5b470602005-02-27 13:10:48 +000014637 putIRegRDX( sz,
14638 binop(mkSizedOp(ty,Iop_Sar8),
14639 getIRegRAX(sz),
14640 mkU8(sz == 2 ? 15 : (sz == 4 ? 31 : 63))) );
sewardje941eea2005-01-30 19:52:28 +000014641 DIP(sz == 2 ? "cwd\n"
sewardj5b470602005-02-27 13:10:48 +000014642 : (sz == 4 ? /*"cdq\n"*/ "cltd\n"
14643 : "cqo\n"));
sewardj3ca55a12005-01-27 16:06:23 +000014644 break;
14645
sewardj8d965312005-02-25 02:48:47 +000014646 /* ------------------------ FPU ops -------------------- */
14647
sewardj905edbd2007-04-07 12:25:37 +000014648 case 0x9E: /* SAHF */
14649 codegen_SAHF();
14650 DIP("sahf\n");
14651 break;
14652
14653 case 0x9F: /* LAHF */
14654 codegen_LAHF();
14655 DIP("lahf\n");
14656 break;
14657
sewardj6847d8c2005-05-12 19:21:55 +000014658 case 0x9B: /* FWAIT */
14659 /* ignore? */
14660 DIP("fwait\n");
14661 break;
sewardj8d965312005-02-25 02:48:47 +000014662
14663 case 0xD8:
14664 case 0xD9:
14665 case 0xDA:
14666 case 0xDB:
14667 case 0xDC:
14668 case 0xDD:
14669 case 0xDE:
sewardj5619f792007-03-11 19:34:13 +000014670 case 0xDF: {
14671 Bool redundantREXWok = False;
14672
14673 if (haveF2orF3(pfx))
14674 goto decode_failure;
14675
14676 /* kludge to tolerate redundant rex.w prefixes (should do this
14677 properly one day) */
14678 /* mono 1.1.18.1 produces 48 D9 FA, which is rex.w fsqrt */
14679 if ( (opc == 0xD9 && getUChar(delta+0) == 0xFA)/*fsqrt*/ )
14680 redundantREXWok = True;
14681
14682 if ( (sz == 4
14683 || (sz == 8 && redundantREXWok))
14684 && haveNo66noF2noF3(pfx)) {
sewardj270def42005-07-03 01:03:01 +000014685 Long delta0 = delta;
14686 Bool decode_OK = False;
sewardj2e28ac42008-12-04 00:05:12 +000014687 delta = dis_FPU ( &decode_OK, vbi, pfx, delta );
sewardj8d965312005-02-25 02:48:47 +000014688 if (!decode_OK) {
14689 delta = delta0;
14690 goto decode_failure;
14691 }
14692 break;
14693 } else {
14694 goto decode_failure;
14695 }
sewardj5619f792007-03-11 19:34:13 +000014696 }
sewardj8d965312005-02-25 02:48:47 +000014697
sewardj4fa325a2005-11-03 13:27:24 +000014698 /* ------------------------ INT ------------------------ */
14699
sewardjada80ba2007-03-12 00:43:59 +000014700 case 0xCC: /* INT 3 */
sewardj0f500042007-08-29 09:09:17 +000014701 jmp_lit(Ijk_SigTRAP, guest_RIP_bbstart + delta);
sewardjada80ba2007-03-12 00:43:59 +000014702 dres.whatNext = Dis_StopHere;
14703 DIP("int $0x3\n");
14704 break;
14705
sewardj4fa325a2005-11-03 13:27:24 +000014706 case 0xCD: { /* INT imm8 */
14707 IRJumpKind jk = Ijk_Boring;
14708 if (have66orF2orF3(pfx)) goto decode_failure;
14709 d64 = getUChar(delta); delta++;
14710 switch (d64) {
14711 case 32: jk = Ijk_Sys_int32; break;
14712 default: goto decode_failure;
14713 }
14714 guest_RIP_next_mustcheck = True;
14715 guest_RIP_next_assumed = guest_RIP_bbstart + delta;
14716 jmp_lit(jk, guest_RIP_next_assumed);
14717 /* It's important that all ArchRegs carry their up-to-date value
14718 at this point. So we declare an end-of-block here, which
14719 forces any TempRegs caching ArchRegs to be flushed. */
14720 dres.whatNext = Dis_StopHere;
14721 DIP("int $0x%02x\n", (UInt)d64);
14722 break;
14723 }
14724
sewardjf8c37f72005-02-07 18:55:29 +000014725 /* ------------------------ Jcond, byte offset --------- */
14726
14727 case 0xEB: /* Jb (jump, byte offset) */
sewardj5b470602005-02-27 13:10:48 +000014728 if (haveF2orF3(pfx)) goto decode_failure;
sewardjf8c37f72005-02-07 18:55:29 +000014729 if (sz != 4)
14730 goto decode_failure; /* JRS added 2004 July 11 */
sewardj9e6491a2005-07-02 19:24:10 +000014731 d64 = (guest_RIP_bbstart+delta+1) + getSDisp8(delta);
sewardjf8c37f72005-02-07 18:55:29 +000014732 delta++;
sewardjc716aea2006-01-17 01:48:46 +000014733 if (resteerOkFn(callback_opaque,d64)) {
sewardj984d9b12010-01-15 10:53:21 +000014734 dres.whatNext = Dis_ResteerU;
sewardj9e6491a2005-07-02 19:24:10 +000014735 dres.continueAt = d64;
sewardjf8c37f72005-02-07 18:55:29 +000014736 } else {
14737 jmp_lit(Ijk_Boring,d64);
sewardj9e6491a2005-07-02 19:24:10 +000014738 dres.whatNext = Dis_StopHere;
sewardjf8c37f72005-02-07 18:55:29 +000014739 }
14740 DIP("jmp-8 0x%llx\n", d64);
14741 break;
sewardj1389d4d2005-01-28 13:46:29 +000014742
14743 case 0xE9: /* Jv (jump, 16/32 offset) */
sewardj5b470602005-02-27 13:10:48 +000014744 if (haveF2orF3(pfx)) goto decode_failure;
sewardjf8c37f72005-02-07 18:55:29 +000014745 if (sz != 4)
14746 goto decode_failure; /* JRS added 2004 July 11 */
sewardj9e6491a2005-07-02 19:24:10 +000014747 d64 = (guest_RIP_bbstart+delta+sz) + getSDisp(sz,delta);
sewardj1389d4d2005-01-28 13:46:29 +000014748 delta += sz;
sewardjc716aea2006-01-17 01:48:46 +000014749 if (resteerOkFn(callback_opaque,d64)) {
sewardj984d9b12010-01-15 10:53:21 +000014750 dres.whatNext = Dis_ResteerU;
sewardj9e6491a2005-07-02 19:24:10 +000014751 dres.continueAt = d64;
sewardj1389d4d2005-01-28 13:46:29 +000014752 } else {
14753 jmp_lit(Ijk_Boring,d64);
sewardj9e6491a2005-07-02 19:24:10 +000014754 dres.whatNext = Dis_StopHere;
sewardj1389d4d2005-01-28 13:46:29 +000014755 }
14756 DIP("jmp 0x%llx\n", d64);
14757 break;
14758
sewardjf8c37f72005-02-07 18:55:29 +000014759 case 0x70:
14760 case 0x71:
14761 case 0x72: /* JBb/JNAEb (jump below) */
14762 case 0x73: /* JNBb/JAEb (jump not below) */
14763 case 0x74: /* JZb/JEb (jump zero) */
14764 case 0x75: /* JNZb/JNEb (jump not zero) */
14765 case 0x76: /* JBEb/JNAb (jump below or equal) */
14766 case 0x77: /* JNBEb/JAb (jump not below or equal) */
14767 case 0x78: /* JSb (jump negative) */
14768 case 0x79: /* JSb (jump not negative) */
14769 case 0x7A: /* JP (jump parity even) */
14770 case 0x7B: /* JNP/JPO (jump parity odd) */
14771 case 0x7C: /* JLb/JNGEb (jump less) */
14772 case 0x7D: /* JGEb/JNLb (jump greater or equal) */
14773 case 0x7E: /* JLEb/JNGb (jump less or equal) */
14774 case 0x7F: /* JGb/JNLEb (jump greater) */
sewardj984d9b12010-01-15 10:53:21 +000014775 { Long jmpDelta;
14776 HChar* comment = "";
sewardj5b470602005-02-27 13:10:48 +000014777 if (haveF2orF3(pfx)) goto decode_failure;
sewardj984d9b12010-01-15 10:53:21 +000014778 jmpDelta = getSDisp8(delta);
14779 vassert(-128 <= jmpDelta && jmpDelta < 128);
14780 d64 = (guest_RIP_bbstart+delta+1) + jmpDelta;
sewardjf8c37f72005-02-07 18:55:29 +000014781 delta++;
sewardj984d9b12010-01-15 10:53:21 +000014782 if (resteerCisOk
14783 && vex_control.guest_chase_cond
sewardj0d925b12010-01-17 15:47:01 +000014784 && (Addr64)d64 != (Addr64)guest_RIP_bbstart
sewardj984d9b12010-01-15 10:53:21 +000014785 && jmpDelta < 0
14786 && resteerOkFn( callback_opaque, d64) ) {
14787 /* Speculation: assume this backward branch is taken. So we
14788 need to emit a side-exit to the insn following this one,
14789 on the negation of the condition, and continue at the
sewardj0d925b12010-01-17 15:47:01 +000014790 branch target address (d64). If we wind up back at the
14791 first instruction of the trace, just stop; it's better to
14792 let the IR loop unroller handle that case. */
sewardj984d9b12010-01-15 10:53:21 +000014793 stmt( IRStmt_Exit(
14794 mk_amd64g_calculate_condition(
14795 (AMD64Condcode)(1 ^ (opc - 0x70))),
14796 Ijk_Boring,
14797 IRConst_U64(guest_RIP_bbstart+delta) ) );
14798 dres.whatNext = Dis_ResteerC;
14799 dres.continueAt = d64;
14800 comment = "(assumed taken)";
14801 }
14802 else
14803 if (resteerCisOk
14804 && vex_control.guest_chase_cond
sewardj0d925b12010-01-17 15:47:01 +000014805 && (Addr64)d64 != (Addr64)guest_RIP_bbstart
sewardj984d9b12010-01-15 10:53:21 +000014806 && jmpDelta >= 0
14807 && resteerOkFn( callback_opaque, guest_RIP_bbstart+delta ) ) {
14808 /* Speculation: assume this forward branch is not taken. So
14809 we need to emit a side-exit to d64 (the dest) and continue
14810 disassembling at the insn immediately following this
14811 one. */
14812 stmt( IRStmt_Exit(
14813 mk_amd64g_calculate_condition((AMD64Condcode)(opc - 0x70)),
14814 Ijk_Boring,
14815 IRConst_U64(d64) ) );
14816 dres.whatNext = Dis_ResteerC;
14817 dres.continueAt = guest_RIP_bbstart+delta;
14818 comment = "(assumed not taken)";
14819 }
14820 else {
14821 /* Conservative default translation - end the block at this
14822 point. */
14823 jcc_01( (AMD64Condcode)(opc - 0x70),
14824 guest_RIP_bbstart+delta,
14825 d64 );
14826 dres.whatNext = Dis_StopHere;
14827 }
14828 DIP("j%s-8 0x%llx %s\n", name_AMD64Condcode(opc - 0x70), d64, comment);
sewardjf8c37f72005-02-07 18:55:29 +000014829 break;
sewardj984d9b12010-01-15 10:53:21 +000014830 }
sewardjf8c37f72005-02-07 18:55:29 +000014831
sewardjc01c1fa2005-11-04 14:34:52 +000014832 case 0xE3:
14833 /* JRCXZ or JECXZ, depending address size override. */
14834 if (have66orF2orF3(pfx)) goto decode_failure;
sewardjfdfa8862005-10-05 16:58:23 +000014835 d64 = (guest_RIP_bbstart+delta+1) + getSDisp8(delta);
14836 delta++;
sewardjc01c1fa2005-11-04 14:34:52 +000014837 if (haveASO(pfx)) {
14838 /* 32-bit */
14839 stmt( IRStmt_Exit( binop(Iop_CmpEQ64,
14840 unop(Iop_32Uto64, getIReg32(R_RCX)),
14841 mkU64(0)),
14842 Ijk_Boring,
14843 IRConst_U64(d64))
14844 );
14845 DIP("jecxz 0x%llx\n", d64);
14846 } else {
14847 /* 64-bit */
14848 stmt( IRStmt_Exit( binop(Iop_CmpEQ64,
14849 getIReg64(R_RCX),
14850 mkU64(0)),
14851 Ijk_Boring,
14852 IRConst_U64(d64))
14853 );
14854 DIP("jrcxz 0x%llx\n", d64);
14855 }
sewardjfdfa8862005-10-05 16:58:23 +000014856 break;
sewardj6359f812005-07-20 10:15:34 +000014857
sewardje8f65252005-08-23 23:44:35 +000014858 case 0xE0: /* LOOPNE disp8: decrement count, jump if count != 0 && ZF==0 */
14859 case 0xE1: /* LOOPE disp8: decrement count, jump if count != 0 && ZF==1 */
14860 case 0xE2: /* LOOP disp8: decrement count, jump if count != 0 */
14861 { /* The docs say this uses rCX as a count depending on the
14862 address size override, not the operand one. Since we don't
14863 handle address size overrides, I guess that means RCX. */
14864 IRExpr* zbit = NULL;
14865 IRExpr* count = NULL;
14866 IRExpr* cond = NULL;
14867 HChar* xtra = NULL;
14868
14869 if (have66orF2orF3(pfx) || haveASO(pfx)) goto decode_failure;
14870 d64 = guest_RIP_bbstart+delta+1 + getSDisp8(delta);
14871 delta++;
14872 putIReg64(R_RCX, binop(Iop_Sub64, getIReg64(R_RCX), mkU64(1)));
14873
14874 count = getIReg64(R_RCX);
14875 cond = binop(Iop_CmpNE64, count, mkU64(0));
14876 switch (opc) {
14877 case 0xE2:
14878 xtra = "";
14879 break;
14880 case 0xE1:
14881 xtra = "e";
14882 zbit = mk_amd64g_calculate_condition( AMD64CondZ );
14883 cond = mkAnd1(cond, zbit);
14884 break;
14885 case 0xE0:
14886 xtra = "ne";
14887 zbit = mk_amd64g_calculate_condition( AMD64CondNZ );
14888 cond = mkAnd1(cond, zbit);
14889 break;
14890 default:
14891 vassert(0);
14892 }
14893 stmt( IRStmt_Exit(cond, Ijk_Boring, IRConst_U64(d64)) );
14894
14895 DIP("loop%s 0x%llx\n", xtra, d64);
14896 break;
14897 }
sewardj32b2bbe2005-01-28 00:50:10 +000014898
14899 /* ------------------------ IMUL ----------------------- */
14900
14901 case 0x69: /* IMUL Iv, Ev, Gv */
sewardj5b470602005-02-27 13:10:48 +000014902 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000014903 delta = dis_imul_I_E_G ( vbi, pfx, sz, delta, sz );
sewardj32b2bbe2005-01-28 00:50:10 +000014904 break;
sewardj7de0d3c2005-02-13 02:26:41 +000014905 case 0x6B: /* IMUL Ib, Ev, Gv */
sewardj2e28ac42008-12-04 00:05:12 +000014906 delta = dis_imul_I_E_G ( vbi, pfx, sz, delta, 1 );
sewardj7de0d3c2005-02-13 02:26:41 +000014907 break;
sewardj1389d4d2005-01-28 13:46:29 +000014908
14909 /* ------------------------ MOV ------------------------ */
14910
14911 case 0x88: /* MOV Gb,Eb */
sewardj5b470602005-02-27 13:10:48 +000014912 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000014913 delta = dis_mov_G_E(vbi, pfx, 1, delta);
sewardj1389d4d2005-01-28 13:46:29 +000014914 break;
14915
14916 case 0x89: /* MOV Gv,Ev */
sewardj5b470602005-02-27 13:10:48 +000014917 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000014918 delta = dis_mov_G_E(vbi, pfx, sz, delta);
sewardj1389d4d2005-01-28 13:46:29 +000014919 break;
14920
sewardjd0a12df2005-02-10 02:07:43 +000014921 case 0x8A: /* MOV Eb,Gb */
sewardj5b470602005-02-27 13:10:48 +000014922 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000014923 delta = dis_mov_E_G(vbi, pfx, 1, delta);
sewardjd0a12df2005-02-10 02:07:43 +000014924 break;
14925
sewardj1389d4d2005-01-28 13:46:29 +000014926 case 0x8B: /* MOV Ev,Gv */
sewardj5b470602005-02-27 13:10:48 +000014927 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000014928 delta = dis_mov_E_G(vbi, pfx, sz, delta);
sewardj1389d4d2005-01-28 13:46:29 +000014929 break;
14930
14931 case 0x8D: /* LEA M,Gv */
sewardj5b470602005-02-27 13:10:48 +000014932 if (haveF2orF3(pfx)) goto decode_failure;
sewardj1389d4d2005-01-28 13:46:29 +000014933 if (sz != 4 && sz != 8)
14934 goto decode_failure;
14935 modrm = getUChar(delta);
14936 if (epartIsReg(modrm))
14937 goto decode_failure;
14938 /* NOTE! this is the one place where a segment override prefix
14939 has no effect on the address calculation. Therefore we clear
14940 any segment override bits in pfx. */
sewardj2e28ac42008-12-04 00:05:12 +000014941 addr = disAMode ( &alen, vbi, clearSegBits(pfx), delta, dis_buf, 0 );
sewardj1389d4d2005-01-28 13:46:29 +000014942 delta += alen;
14943 /* This is a hack. But it isn't clear that really doing the
14944 calculation at 32 bits is really worth it. Hence for leal,
14945 do the full 64-bit calculation and then truncate it. */
sewardj5b470602005-02-27 13:10:48 +000014946 putIRegG( sz, pfx, modrm,
sewardj1389d4d2005-01-28 13:46:29 +000014947 sz == 4
14948 ? unop(Iop_64to32, mkexpr(addr))
14949 : mkexpr(addr)
14950 );
14951 DIP("lea%c %s, %s\n", nameISize(sz), dis_buf,
sewardj5b470602005-02-27 13:10:48 +000014952 nameIRegG(sz,pfx,modrm));
sewardj1389d4d2005-01-28 13:46:29 +000014953 break;
14954
sewardjd20c8852005-01-20 20:04:07 +000014955//.. case 0x8C: /* MOV Sw,Ew -- MOV from a SEGMENT REGISTER */
14956//.. delta = dis_mov_Sw_Ew(sorb, sz, delta);
14957//.. break;
14958//..
14959//.. case 0x8E: /* MOV Ew,Sw -- MOV to a SEGMENT REGISTER */
14960//.. delta = dis_mov_Ew_Sw(sorb, delta);
14961//.. break;
sewardj2bd97d12005-08-02 21:27:25 +000014962
14963 case 0xA0: /* MOV Ob,AL */
14964 if (have66orF2orF3(pfx)) goto decode_failure;
14965 sz = 1;
14966 /* Fall through ... */
sewardj87277cb2005-08-01 13:03:32 +000014967 case 0xA1: /* MOV Ov,eAX */
sewardj2bd97d12005-08-02 21:27:25 +000014968 if (sz != 8 && sz != 4 && sz != 2 && sz != 1)
14969 goto decode_failure;
sewardj87277cb2005-08-01 13:03:32 +000014970 d64 = getDisp64(delta);
14971 delta += 8;
14972 ty = szToITy(sz);
14973 addr = newTemp(Ity_I64);
sewardj2e28ac42008-12-04 00:05:12 +000014974 assign( addr, handleAddrOverrides(vbi, pfx, mkU64(d64)) );
sewardj87277cb2005-08-01 13:03:32 +000014975 putIRegRAX(sz, loadLE( ty, mkexpr(addr) ));
14976 DIP("mov%c %s0x%llx, %s\n", nameISize(sz),
sewardjc4356f02007-11-09 21:15:04 +000014977 segRegTxt(pfx), d64,
sewardj87277cb2005-08-01 13:03:32 +000014978 nameIRegRAX(sz));
14979 break;
14980
sewardj2bd97d12005-08-02 21:27:25 +000014981 case 0xA2: /* MOV AL,Ob */
14982 if (have66orF2orF3(pfx)) goto decode_failure;
14983 sz = 1;
14984 /* Fall through ... */
sewardj87277cb2005-08-01 13:03:32 +000014985 case 0xA3: /* MOV eAX,Ov */
sewardj2bd97d12005-08-02 21:27:25 +000014986 if (sz != 8 && sz != 4 && sz != 2 && sz != 1)
14987 goto decode_failure;
sewardj87277cb2005-08-01 13:03:32 +000014988 d64 = getDisp64(delta);
14989 delta += 8;
14990 ty = szToITy(sz);
14991 addr = newTemp(Ity_I64);
sewardj2e28ac42008-12-04 00:05:12 +000014992 assign( addr, handleAddrOverrides(vbi, pfx, mkU64(d64)) );
sewardj87277cb2005-08-01 13:03:32 +000014993 storeLE( mkexpr(addr), getIRegRAX(sz) );
14994 DIP("mov%c %s, %s0x%llx\n", nameISize(sz), nameIRegRAX(sz),
sewardjc4356f02007-11-09 21:15:04 +000014995 segRegTxt(pfx), d64);
sewardj87277cb2005-08-01 13:03:32 +000014996 break;
sewardjb095fba2005-02-13 14:13:04 +000014997
sewardj8711f662005-05-09 17:52:56 +000014998 /* XXXX be careful here with moves to AH/BH/CH/DH */
sewardj007e9ec2005-03-23 11:36:48 +000014999 case 0xB0: /* MOV imm,AL */
15000 case 0xB1: /* MOV imm,CL */
sewardjb095fba2005-02-13 14:13:04 +000015001 case 0xB2: /* MOV imm,DL */
sewardj007e9ec2005-03-23 11:36:48 +000015002 case 0xB3: /* MOV imm,BL */
15003 case 0xB4: /* MOV imm,AH */
15004 case 0xB5: /* MOV imm,CH */
15005 case 0xB6: /* MOV imm,DH */
sewardj31eecde2005-03-23 03:39:55 +000015006 case 0xB7: /* MOV imm,BH */
sewardj5b470602005-02-27 13:10:48 +000015007 if (haveF2orF3(pfx)) goto decode_failure;
sewardjb095fba2005-02-13 14:13:04 +000015008 d64 = getUChar(delta);
15009 delta += 1;
sewardj5b470602005-02-27 13:10:48 +000015010 putIRegRexB(1, pfx, opc-0xB0, mkU8(d64));
15011 DIP("movb $%lld,%s\n", d64, nameIRegRexB(1,pfx,opc-0xB0));
sewardjb095fba2005-02-13 14:13:04 +000015012 break;
sewardj1389d4d2005-01-28 13:46:29 +000015013
15014 case 0xB8: /* MOV imm,eAX */
15015 case 0xB9: /* MOV imm,eCX */
15016 case 0xBA: /* MOV imm,eDX */
15017 case 0xBB: /* MOV imm,eBX */
15018 case 0xBC: /* MOV imm,eSP */
15019 case 0xBD: /* MOV imm,eBP */
15020 case 0xBE: /* MOV imm,eSI */
15021 case 0xBF: /* MOV imm,eDI */
sewardj03b07cc2005-01-31 18:09:43 +000015022 /* This is the one-and-only place where 64-bit literals are
15023 allowed in the instruction stream. */
sewardj5b470602005-02-27 13:10:48 +000015024 if (haveF2orF3(pfx)) goto decode_failure;
sewardj03b07cc2005-01-31 18:09:43 +000015025 if (sz == 8) {
15026 d64 = getDisp64(delta);
sewardj7eaa7cf2005-01-31 18:55:22 +000015027 delta += 8;
sewardj5b470602005-02-27 13:10:48 +000015028 putIRegRexB(8, pfx, opc-0xB8, mkU64(d64));
sewardj227458e2005-01-31 19:04:50 +000015029 DIP("movabsq $%lld,%s\n", (Long)d64,
sewardj5b470602005-02-27 13:10:48 +000015030 nameIRegRexB(8,pfx,opc-0xB8));
sewardj03b07cc2005-01-31 18:09:43 +000015031 } else {
15032 d64 = getSDisp(imin(4,sz),delta);
15033 delta += imin(4,sz);
sewardj5b470602005-02-27 13:10:48 +000015034 putIRegRexB(sz, pfx, opc-0xB8,
15035 mkU(szToITy(sz), d64 & mkSizeMask(sz)));
sewardj227458e2005-01-31 19:04:50 +000015036 DIP("mov%c $%lld,%s\n", nameISize(sz),
15037 (Long)d64,
sewardj5b470602005-02-27 13:10:48 +000015038 nameIRegRexB(sz,pfx,opc-0xB8));
sewardj03b07cc2005-01-31 18:09:43 +000015039 }
sewardj1389d4d2005-01-28 13:46:29 +000015040 break;
15041
15042 case 0xC6: /* MOV Ib,Eb */
15043 sz = 1;
15044 goto do_Mov_I_E;
15045 case 0xC7: /* MOV Iv,Ev */
15046 goto do_Mov_I_E;
15047
15048 do_Mov_I_E:
sewardj5b470602005-02-27 13:10:48 +000015049 if (haveF2orF3(pfx)) goto decode_failure;
sewardj1389d4d2005-01-28 13:46:29 +000015050 modrm = getUChar(delta);
15051 if (epartIsReg(modrm)) {
sewardj1389d4d2005-01-28 13:46:29 +000015052 delta++; /* mod/rm byte */
15053 d64 = getSDisp(imin(4,sz),delta);
15054 delta += imin(4,sz);
sewardj5b470602005-02-27 13:10:48 +000015055 putIRegE(sz, pfx, modrm,
15056 mkU(szToITy(sz), d64 & mkSizeMask(sz)));
sewardj227458e2005-01-31 19:04:50 +000015057 DIP("mov%c $%lld, %s\n", nameISize(sz),
15058 (Long)d64,
sewardj5b470602005-02-27 13:10:48 +000015059 nameIRegE(sz,pfx,modrm));
sewardj1389d4d2005-01-28 13:46:29 +000015060 } else {
sewardj2e28ac42008-12-04 00:05:12 +000015061 addr = disAMode ( &alen, vbi, pfx, delta, dis_buf,
sewardj5b470602005-02-27 13:10:48 +000015062 /*xtra*/imin(4,sz) );
sewardj1389d4d2005-01-28 13:46:29 +000015063 delta += alen;
sewardje941eea2005-01-30 19:52:28 +000015064 d64 = getSDisp(imin(4,sz),delta);
sewardj1389d4d2005-01-28 13:46:29 +000015065 delta += imin(4,sz);
sewardje941eea2005-01-30 19:52:28 +000015066 storeLE(mkexpr(addr),
15067 mkU(szToITy(sz), d64 & mkSizeMask(sz)));
sewardj227458e2005-01-31 19:04:50 +000015068 DIP("mov%c $%lld, %s\n", nameISize(sz), (Long)d64, dis_buf);
sewardj1389d4d2005-01-28 13:46:29 +000015069 }
15070 break;
15071
sewardj5e525292005-01-28 15:13:10 +000015072 /* ------------------------ MOVx ------------------------ */
15073
15074 case 0x63: /* MOVSX */
sewardj5b470602005-02-27 13:10:48 +000015075 if (haveF2orF3(pfx)) goto decode_failure;
sewardj5e525292005-01-28 15:13:10 +000015076 if (haveREX(pfx) && 1==getRexW(pfx)) {
15077 vassert(sz == 8);
15078 /* movsx r/m32 to r64 */
15079 modrm = getUChar(delta);
15080 if (epartIsReg(modrm)) {
15081 delta++;
sewardj5b470602005-02-27 13:10:48 +000015082 putIRegG(8, pfx, modrm,
sewardj5e525292005-01-28 15:13:10 +000015083 unop(Iop_32Sto64,
sewardj5b470602005-02-27 13:10:48 +000015084 getIRegE(4, pfx, modrm)));
sewardj5e525292005-01-28 15:13:10 +000015085 DIP("movslq %s,%s\n",
sewardj5b470602005-02-27 13:10:48 +000015086 nameIRegE(4, pfx, modrm),
15087 nameIRegG(8, pfx, modrm));
sewardj5e525292005-01-28 15:13:10 +000015088 break;
15089 } else {
sewardj2e28ac42008-12-04 00:05:12 +000015090 addr = disAMode ( &alen, vbi, pfx, delta, dis_buf, 0 );
sewardj5e525292005-01-28 15:13:10 +000015091 delta += alen;
sewardj5b470602005-02-27 13:10:48 +000015092 putIRegG(8, pfx, modrm,
sewardj5e525292005-01-28 15:13:10 +000015093 unop(Iop_32Sto64,
15094 loadLE(Ity_I32, mkexpr(addr))));
15095 DIP("movslq %s,%s\n", dis_buf,
sewardj5b470602005-02-27 13:10:48 +000015096 nameIRegG(8, pfx, modrm));
sewardj5e525292005-01-28 15:13:10 +000015097 break;
15098 }
15099 } else {
15100 goto decode_failure;
15101 }
15102
sewardj4c328cf2005-05-05 12:05:54 +000015103 /* ------------------------ opl imm, A ----------------- */
15104
15105 case 0x04: /* ADD Ib, AL */
15106 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000015107 delta = dis_op_imm_A( 1, False, Iop_Add8, True, delta, "add" );
sewardj4c328cf2005-05-05 12:05:54 +000015108 break;
sewardj03b07cc2005-01-31 18:09:43 +000015109 case 0x05: /* ADD Iv, eAX */
sewardj5b470602005-02-27 13:10:48 +000015110 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000015111 delta = dis_op_imm_A(sz, False, Iop_Add8, True, delta, "add" );
sewardj03b07cc2005-01-31 18:09:43 +000015112 break;
15113
sewardj007e9ec2005-03-23 11:36:48 +000015114 case 0x0C: /* OR Ib, AL */
15115 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000015116 delta = dis_op_imm_A( 1, False, Iop_Or8, True, delta, "or" );
sewardj007e9ec2005-03-23 11:36:48 +000015117 break;
sewardj03b07cc2005-01-31 18:09:43 +000015118 case 0x0D: /* OR Iv, eAX */
sewardj5b470602005-02-27 13:10:48 +000015119 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000015120 delta = dis_op_imm_A( sz, False, Iop_Or8, True, delta, "or" );
sewardj03b07cc2005-01-31 18:09:43 +000015121 break;
15122
sewardj41c01092005-07-23 13:50:32 +000015123 case 0x14: /* ADC Ib, AL */
sewardj671da872007-11-15 23:30:16 +000015124 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000015125 delta = dis_op_imm_A( 1, True, Iop_Add8, True, delta, "adc" );
15126 break;
sewardjd20c8852005-01-20 20:04:07 +000015127//.. //-- case 0x15: /* ADC Iv, eAX */
15128//.. //-- delta = dis_op_imm_A( sz, ADC, True, delta, "adc" );
15129//.. //-- break;
sewardj5fadaf92006-05-12 20:45:59 +000015130
15131 case 0x1C: /* SBB Ib, AL */
15132 if (haveF2orF3(pfx)) goto decode_failure;
15133 delta = dis_op_imm_A( 1, True, Iop_Sub8, True, delta, "sbb" );
15134 break;
sewardjd20c8852005-01-20 20:04:07 +000015135//.. //-- case 0x1D: /* SBB Iv, eAX */
15136//.. //-- delta = dis_op_imm_A( sz, SBB, True, delta, "sbb" );
15137//.. //-- break;
15138//.. //--
sewardj007e9ec2005-03-23 11:36:48 +000015139 case 0x24: /* AND Ib, AL */
15140 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000015141 delta = dis_op_imm_A( 1, False, Iop_And8, True, delta, "and" );
sewardj007e9ec2005-03-23 11:36:48 +000015142 break;
sewardj3ca55a12005-01-27 16:06:23 +000015143 case 0x25: /* AND Iv, eAX */
15144 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000015145 delta = dis_op_imm_A( sz, False, Iop_And8, True, delta, "and" );
sewardj3ca55a12005-01-27 16:06:23 +000015146 break;
15147
sewardj137015d2005-03-27 04:01:15 +000015148 case 0x2C: /* SUB Ib, AL */
15149 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000015150 delta = dis_op_imm_A(1, False, Iop_Sub8, True, delta, "sub" );
sewardj137015d2005-03-27 04:01:15 +000015151 break;
sewardj03b07cc2005-01-31 18:09:43 +000015152 case 0x2D: /* SUB Iv, eAX */
sewardj5b470602005-02-27 13:10:48 +000015153 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000015154 delta = dis_op_imm_A( sz, False, Iop_Sub8, True, delta, "sub" );
sewardj03b07cc2005-01-31 18:09:43 +000015155 break;
15156
sewardj8eb804f2005-05-18 10:22:47 +000015157 case 0x34: /* XOR Ib, AL */
15158 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000015159 delta = dis_op_imm_A( 1, False, Iop_Xor8, True, delta, "xor" );
sewardj8eb804f2005-05-18 10:22:47 +000015160 break;
sewardj85520e42005-02-19 15:22:38 +000015161 case 0x35: /* XOR Iv, eAX */
sewardj5b470602005-02-27 13:10:48 +000015162 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000015163 delta = dis_op_imm_A( sz, False, Iop_Xor8, True, delta, "xor" );
sewardj85520e42005-02-19 15:22:38 +000015164 break;
sewardj03b07cc2005-01-31 18:09:43 +000015165
15166 case 0x3C: /* CMP Ib, AL */
15167 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000015168 delta = dis_op_imm_A( 1, False, Iop_Sub8, False, delta, "cmp" );
sewardj03b07cc2005-01-31 18:09:43 +000015169 break;
sewardj354e5c62005-01-27 20:12:52 +000015170 case 0x3D: /* CMP Iv, eAX */
15171 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000015172 delta = dis_op_imm_A( sz, False, Iop_Sub8, False, delta, "cmp" );
sewardj354e5c62005-01-27 20:12:52 +000015173 break;
15174
sewardj118b23e2005-01-29 02:14:44 +000015175 case 0xA8: /* TEST Ib, AL */
sewardj03b07cc2005-01-31 18:09:43 +000015176 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000015177 delta = dis_op_imm_A( 1, False, Iop_And8, False, delta, "test" );
sewardj118b23e2005-01-29 02:14:44 +000015178 break;
15179 case 0xA9: /* TEST Iv, eAX */
sewardj03b07cc2005-01-31 18:09:43 +000015180 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000015181 delta = dis_op_imm_A( sz, False, Iop_And8, False, delta, "test" );
sewardj118b23e2005-01-29 02:14:44 +000015182 break;
15183
15184 /* ------------------------ opl Ev, Gv ----------------- */
15185
sewardj03b07cc2005-01-31 18:09:43 +000015186 case 0x02: /* ADD Eb,Gb */
15187 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000015188 delta = dis_op2_E_G ( vbi, pfx, False, Iop_Add8, True, 1, delta, "add" );
sewardj03b07cc2005-01-31 18:09:43 +000015189 break;
sewardjdf0e0022005-01-25 15:48:43 +000015190 case 0x03: /* ADD Ev,Gv */
sewardj3ca55a12005-01-27 16:06:23 +000015191 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000015192 delta = dis_op2_E_G ( vbi, pfx, False, Iop_Add8, True, sz, delta, "add" );
sewardjdf0e0022005-01-25 15:48:43 +000015193 break;
15194
sewardj03b07cc2005-01-31 18:09:43 +000015195 case 0x0A: /* OR Eb,Gb */
sewardj5b470602005-02-27 13:10:48 +000015196 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000015197 delta = dis_op2_E_G ( vbi, pfx, False, Iop_Or8, True, 1, delta, "or" );
sewardj03b07cc2005-01-31 18:09:43 +000015198 break;
15199 case 0x0B: /* OR Ev,Gv */
sewardj5b470602005-02-27 13:10:48 +000015200 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000015201 delta = dis_op2_E_G ( vbi, pfx, False, Iop_Or8, True, sz, delta, "or" );
sewardj03b07cc2005-01-31 18:09:43 +000015202 break;
sewardj671da872007-11-15 23:30:16 +000015203
15204 case 0x12: /* ADC Eb,Gb */
15205 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000015206 delta = dis_op2_E_G ( vbi, pfx, True, Iop_Add8, True, 1, delta, "adc" );
sewardj671da872007-11-15 23:30:16 +000015207 break;
sewardj22cab062005-07-19 23:59:54 +000015208 case 0x13: /* ADC Ev,Gv */
sewardj671da872007-11-15 23:30:16 +000015209 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000015210 delta = dis_op2_E_G ( vbi, pfx, True, Iop_Add8, True, sz, delta, "adc" );
sewardj22cab062005-07-19 23:59:54 +000015211 break;
15212
sewardjf7d3b2e2010-02-28 04:53:07 +000015213 case 0x1A: /* SBB Eb,Gb */
15214 if (haveF2orF3(pfx)) goto decode_failure;
15215 delta = dis_op2_E_G ( vbi, pfx, True, Iop_Sub8, True, 1, delta, "sbb" );
15216 break;
sewardj7a06b852005-07-20 10:55:26 +000015217 case 0x1B: /* SBB Ev,Gv */
sewardj671da872007-11-15 23:30:16 +000015218 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000015219 delta = dis_op2_E_G ( vbi, pfx, True, Iop_Sub8, True, sz, delta, "sbb" );
sewardj7a06b852005-07-20 10:55:26 +000015220 break;
sewardj03b07cc2005-01-31 18:09:43 +000015221
15222 case 0x22: /* AND Eb,Gb */
15223 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000015224 delta = dis_op2_E_G ( vbi, pfx, False, Iop_And8, True, 1, delta, "and" );
sewardj03b07cc2005-01-31 18:09:43 +000015225 break;
15226 case 0x23: /* AND Ev,Gv */
15227 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000015228 delta = dis_op2_E_G ( vbi, pfx, False, Iop_And8, True, sz, delta, "and" );
sewardj03b07cc2005-01-31 18:09:43 +000015229 break;
15230
15231 case 0x2A: /* SUB Eb,Gb */
15232 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000015233 delta = dis_op2_E_G ( vbi, pfx, False, Iop_Sub8, True, 1, delta, "sub" );
sewardj03b07cc2005-01-31 18:09:43 +000015234 break;
sewardj118b23e2005-01-29 02:14:44 +000015235 case 0x2B: /* SUB Ev,Gv */
sewardj03b07cc2005-01-31 18:09:43 +000015236 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000015237 delta = dis_op2_E_G ( vbi, pfx, False, Iop_Sub8, True, sz, delta, "sub" );
sewardj118b23e2005-01-29 02:14:44 +000015238 break;
15239
sewardj03b07cc2005-01-31 18:09:43 +000015240 case 0x32: /* XOR Eb,Gb */
15241 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000015242 delta = dis_op2_E_G ( vbi, pfx, False, Iop_Xor8, True, 1, delta, "xor" );
sewardj03b07cc2005-01-31 18:09:43 +000015243 break;
15244 case 0x33: /* XOR Ev,Gv */
15245 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000015246 delta = dis_op2_E_G ( vbi, pfx, False, Iop_Xor8, True, sz, delta, "xor" );
sewardj03b07cc2005-01-31 18:09:43 +000015247 break;
15248
sewardjb095fba2005-02-13 14:13:04 +000015249 case 0x3A: /* CMP Eb,Gb */
15250 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000015251 delta = dis_op2_E_G ( vbi, pfx, False, Iop_Sub8, False, 1, delta, "cmp" );
sewardjb095fba2005-02-13 14:13:04 +000015252 break;
sewardj354e5c62005-01-27 20:12:52 +000015253 case 0x3B: /* CMP Ev,Gv */
15254 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000015255 delta = dis_op2_E_G ( vbi, pfx, False, Iop_Sub8, False, sz, delta, "cmp" );
sewardj354e5c62005-01-27 20:12:52 +000015256 break;
15257
sewardj118b23e2005-01-29 02:14:44 +000015258 case 0x84: /* TEST Eb,Gb */
sewardj03b07cc2005-01-31 18:09:43 +000015259 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000015260 delta = dis_op2_E_G ( vbi, pfx, False, Iop_And8, False, 1, delta, "test" );
sewardj118b23e2005-01-29 02:14:44 +000015261 break;
15262 case 0x85: /* TEST Ev,Gv */
sewardj03b07cc2005-01-31 18:09:43 +000015263 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000015264 delta = dis_op2_E_G ( vbi, pfx, False, Iop_And8, False, sz, delta, "test" );
sewardj118b23e2005-01-29 02:14:44 +000015265 break;
15266
15267 /* ------------------------ opl Gv, Ev ----------------- */
15268
sewardj85520e42005-02-19 15:22:38 +000015269 case 0x00: /* ADD Gb,Eb */
15270 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000015271 delta = dis_op2_G_E ( vbi, pfx, False, Iop_Add8, True, 1, delta, "add" );
sewardj85520e42005-02-19 15:22:38 +000015272 break;
sewardj3ca55a12005-01-27 16:06:23 +000015273 case 0x01: /* ADD Gv,Ev */
sewardj354e5c62005-01-27 20:12:52 +000015274 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000015275 delta = dis_op2_G_E ( vbi, pfx, False, Iop_Add8, True, sz, delta, "add" );
sewardj3ca55a12005-01-27 16:06:23 +000015276 break;
15277
sewardj03b07cc2005-01-31 18:09:43 +000015278 case 0x08: /* OR Gb,Eb */
15279 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000015280 delta = dis_op2_G_E ( vbi, pfx, False, Iop_Or8, True, 1, delta, "or" );
sewardj03b07cc2005-01-31 18:09:43 +000015281 break;
sewardj55dbb262005-01-28 16:36:51 +000015282 case 0x09: /* OR Gv,Ev */
15283 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000015284 delta = dis_op2_G_E ( vbi, pfx, False, Iop_Or8, True, sz, delta, "or" );
sewardj55dbb262005-01-28 16:36:51 +000015285 break;
15286
sewardj85520e42005-02-19 15:22:38 +000015287 case 0x10: /* ADC Gb,Eb */
15288 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000015289 delta = dis_op2_G_E ( vbi, pfx, True, Iop_Add8, True, 1, delta, "adc" );
sewardj85520e42005-02-19 15:22:38 +000015290 break;
15291 case 0x11: /* ADC Gv,Ev */
15292 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000015293 delta = dis_op2_G_E ( vbi, pfx, True, Iop_Add8, True, sz, delta, "adc" );
sewardj85520e42005-02-19 15:22:38 +000015294 break;
15295
15296 case 0x18: /* SBB Gb,Eb */
15297 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000015298 delta = dis_op2_G_E ( vbi, pfx, True, Iop_Sub8, True, 1, delta, "sbb" );
sewardj85520e42005-02-19 15:22:38 +000015299 break;
sewardj03b07cc2005-01-31 18:09:43 +000015300 case 0x19: /* SBB Gv,Ev */
sewardja6b93d12005-02-17 09:28:28 +000015301 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000015302 delta = dis_op2_G_E ( vbi, pfx, True, Iop_Sub8, True, sz, delta, "sbb" );
sewardj03b07cc2005-01-31 18:09:43 +000015303 break;
15304
sewardj85520e42005-02-19 15:22:38 +000015305 case 0x20: /* AND Gb,Eb */
15306 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000015307 delta = dis_op2_G_E ( vbi, pfx, False, Iop_And8, True, 1, delta, "and" );
sewardj85520e42005-02-19 15:22:38 +000015308 break;
sewardj3ca55a12005-01-27 16:06:23 +000015309 case 0x21: /* AND Gv,Ev */
sewardj354e5c62005-01-27 20:12:52 +000015310 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000015311 delta = dis_op2_G_E ( vbi, pfx, False, Iop_And8, True, sz, delta, "and" );
sewardj3ca55a12005-01-27 16:06:23 +000015312 break;
sewardj03b07cc2005-01-31 18:09:43 +000015313
15314 case 0x28: /* SUB Gb,Eb */
15315 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000015316 delta = dis_op2_G_E ( vbi, pfx, False, Iop_Sub8, True, 1, delta, "sub" );
sewardj03b07cc2005-01-31 18:09:43 +000015317 break;
sewardj118b23e2005-01-29 02:14:44 +000015318 case 0x29: /* SUB Gv,Ev */
sewardj03b07cc2005-01-31 18:09:43 +000015319 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000015320 delta = dis_op2_G_E ( vbi, pfx, False, Iop_Sub8, True, sz, delta, "sub" );
sewardj118b23e2005-01-29 02:14:44 +000015321 break;
15322
sewardjb095fba2005-02-13 14:13:04 +000015323 case 0x30: /* XOR Gb,Eb */
15324 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000015325 delta = dis_op2_G_E ( vbi, pfx, False, Iop_Xor8, True, 1, delta, "xor" );
sewardjb095fba2005-02-13 14:13:04 +000015326 break;
sewardj118b23e2005-01-29 02:14:44 +000015327 case 0x31: /* XOR Gv,Ev */
sewardj03b07cc2005-01-31 18:09:43 +000015328 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000015329 delta = dis_op2_G_E ( vbi, pfx, False, Iop_Xor8, True, sz, delta, "xor" );
sewardj118b23e2005-01-29 02:14:44 +000015330 break;
sewardj354e5c62005-01-27 20:12:52 +000015331
15332 case 0x38: /* CMP Gb,Eb */
15333 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000015334 delta = dis_op2_G_E ( vbi, pfx, False, Iop_Sub8, False, 1, delta, "cmp" );
sewardj354e5c62005-01-27 20:12:52 +000015335 break;
15336 case 0x39: /* CMP Gv,Ev */
15337 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000015338 delta = dis_op2_G_E ( vbi, pfx, False, Iop_Sub8, False, sz, delta, "cmp" );
sewardj354e5c62005-01-27 20:12:52 +000015339 break;
15340
sewardj55dbb262005-01-28 16:36:51 +000015341 /* ------------------------ POP ------------------------ */
15342
15343 case 0x58: /* POP eAX */
15344 case 0x59: /* POP eCX */
15345 case 0x5A: /* POP eDX */
15346 case 0x5B: /* POP eBX */
15347 case 0x5D: /* POP eBP */
15348 case 0x5E: /* POP eSI */
15349 case 0x5F: /* POP eDI */
15350 case 0x5C: /* POP eSP */
sewardj03b07cc2005-01-31 18:09:43 +000015351 if (haveF2orF3(pfx)) goto decode_failure;
sewardj55dbb262005-01-28 16:36:51 +000015352 vassert(sz == 2 || sz == 4 || sz == 8);
15353 if (sz == 4)
15354 sz = 8; /* there is no encoding for 32-bit pop in 64-bit mode */
15355 t1 = newTemp(szToITy(sz));
15356 t2 = newTemp(Ity_I64);
15357 assign(t2, getIReg64(R_RSP));
15358 assign(t1, loadLE(szToITy(sz),mkexpr(t2)));
15359 putIReg64(R_RSP, binop(Iop_Add64, mkexpr(t2), mkU64(sz)));
sewardj5b470602005-02-27 13:10:48 +000015360 putIRegRexB(sz, pfx, opc-0x58, mkexpr(t1));
15361 DIP("pop%c %s\n", nameISize(sz), nameIRegRexB(sz,pfx,opc-0x58));
sewardj55dbb262005-01-28 16:36:51 +000015362 break;
15363
sewardj85520e42005-02-19 15:22:38 +000015364 case 0x9D: /* POPF */
15365 /* Note. There is no encoding for a 32-bit popf in 64-bit mode.
15366 So sz==4 actually means sz==8. */
sewardj5b470602005-02-27 13:10:48 +000015367 if (haveF2orF3(pfx)) goto decode_failure;
sewardj85520e42005-02-19 15:22:38 +000015368 vassert(sz == 2 || sz == 4);
15369 if (sz == 4) sz = 8;
sewardj5b470602005-02-27 13:10:48 +000015370 if (sz != 8) goto decode_failure; // until we know a sz==2 test case exists
sewardj85520e42005-02-19 15:22:38 +000015371 t1 = newTemp(Ity_I64); t2 = newTemp(Ity_I64);
15372 assign(t2, getIReg64(R_RSP));
15373 assign(t1, widenUto64(loadLE(szToITy(sz),mkexpr(t2))));
15374 putIReg64(R_RSP, binop(Iop_Add64, mkexpr(t2), mkU64(sz)));
15375 /* t1 is the flag word. Mask out everything except OSZACP and
15376 set the flags thunk to AMD64G_CC_OP_COPY. */
15377 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(AMD64G_CC_OP_COPY) ));
15378 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
15379 stmt( IRStmt_Put( OFFB_CC_DEP1,
15380 binop(Iop_And64,
15381 mkexpr(t1),
15382 mkU64( AMD64G_CC_MASK_C | AMD64G_CC_MASK_P
15383 | AMD64G_CC_MASK_A | AMD64G_CC_MASK_Z
15384 | AMD64G_CC_MASK_S| AMD64G_CC_MASK_O )
15385 )
15386 )
15387 );
15388
15389 /* Also need to set the D flag, which is held in bit 10 of t1.
15390 If zero, put 1 in OFFB_DFLAG, else -1 in OFFB_DFLAG. */
15391 stmt( IRStmt_Put(
15392 OFFB_DFLAG,
15393 IRExpr_Mux0X(
15394 unop(Iop_32to8,
15395 unop(Iop_64to32,
15396 binop(Iop_And64,
15397 binop(Iop_Shr64, mkexpr(t1), mkU8(10)),
15398 mkU64(1)))),
15399 mkU64(1),
15400 mkU64(0xFFFFFFFFFFFFFFFFULL)))
15401 );
15402
15403 /* And set the ID flag */
15404 stmt( IRStmt_Put(
15405 OFFB_IDFLAG,
15406 IRExpr_Mux0X(
15407 unop(Iop_32to8,
15408 unop(Iop_64to32,
15409 binop(Iop_And64,
15410 binop(Iop_Shr64, mkexpr(t1), mkU8(21)),
15411 mkU64(1)))),
15412 mkU64(0),
15413 mkU64(1)))
15414 );
15415
15416 DIP("popf%c\n", nameISize(sz));
15417 break;
15418
sewardjd20c8852005-01-20 20:04:07 +000015419//.. case 0x61: /* POPA */
15420//.. /* This is almost certainly wrong for sz==2. So ... */
15421//.. if (sz != 4) goto decode_failure;
15422//..
15423//.. /* t5 is the old %ESP value. */
15424//.. t5 = newTemp(Ity_I32);
15425//.. assign( t5, getIReg(4, R_ESP) );
15426//..
15427//.. /* Reload all the registers, except %esp. */
15428//.. putIReg(4,R_EAX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(28)) ));
15429//.. putIReg(4,R_ECX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(24)) ));
15430//.. putIReg(4,R_EDX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(20)) ));
15431//.. putIReg(4,R_EBX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(16)) ));
15432//.. /* ignore saved %ESP */
15433//.. putIReg(4,R_EBP, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32( 8)) ));
15434//.. putIReg(4,R_ESI, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32( 4)) ));
15435//.. putIReg(4,R_EDI, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32( 0)) ));
15436//..
15437//.. /* and move %ESP back up */
15438//.. putIReg( 4, R_ESP, binop(Iop_Add32, mkexpr(t5), mkU32(8*4)) );
15439//..
15440//.. DIP("pusha%c\n", nameISize(sz));
15441//.. break;
sewardj432f8b62005-05-10 02:50:05 +000015442
15443 case 0x8F: { /* POPQ m64 / POPW m16 */
sewardj1bd14e72005-05-11 16:24:00 +000015444 Int len;
15445 UChar rm;
sewardj432f8b62005-05-10 02:50:05 +000015446 /* There is no encoding for 32-bit pop in 64-bit mode.
15447 So sz==4 actually means sz==8. */
15448 if (haveF2orF3(pfx)) goto decode_failure;
15449 vassert(sz == 2 || sz == 4);
15450 if (sz == 4) sz = 8;
15451 if (sz != 8) goto decode_failure; // until we know a sz==2 test case exists
15452
sewardj1bd14e72005-05-11 16:24:00 +000015453 rm = getUChar(delta);
sewardj432f8b62005-05-10 02:50:05 +000015454
15455 /* make sure this instruction is correct POP */
15456 if (epartIsReg(rm) || gregLO3ofRM(rm) != 0)
15457 goto decode_failure;
15458 /* and has correct size */
15459 vassert(sz == 8);
15460
15461 t1 = newTemp(Ity_I64);
15462 t3 = newTemp(Ity_I64);
15463 assign( t1, getIReg64(R_RSP) );
15464 assign( t3, loadLE(Ity_I64, mkexpr(t1)) );
15465
15466 /* Increase RSP; must be done before the STORE. Intel manual
15467 says: If the RSP register is used as a base register for
15468 addressing a destination operand in memory, the POP
15469 instruction computes the effective address of the operand
15470 after it increments the RSP register. */
15471 putIReg64(R_RSP, binop(Iop_Add64, mkexpr(t1), mkU64(sz)) );
15472
sewardj2e28ac42008-12-04 00:05:12 +000015473 addr = disAMode ( &len, vbi, pfx, delta, dis_buf, 0 );
sewardj432f8b62005-05-10 02:50:05 +000015474 storeLE( mkexpr(addr), mkexpr(t3) );
15475
15476 DIP("popl %s\n", dis_buf);
15477
15478 delta += len;
15479 break;
15480 }
15481
sewardjd20c8852005-01-20 20:04:07 +000015482//.. //-- case 0x1F: /* POP %DS */
15483//.. //-- dis_pop_segreg( cb, R_DS, sz ); break;
15484//.. //-- case 0x07: /* POP %ES */
15485//.. //-- dis_pop_segreg( cb, R_ES, sz ); break;
15486//.. //-- case 0x17: /* POP %SS */
15487//.. //-- dis_pop_segreg( cb, R_SS, sz ); break;
sewardj55dbb262005-01-28 16:36:51 +000015488
15489 /* ------------------------ PUSH ----------------------- */
15490
15491 case 0x50: /* PUSH eAX */
15492 case 0x51: /* PUSH eCX */
15493 case 0x52: /* PUSH eDX */
15494 case 0x53: /* PUSH eBX */
15495 case 0x55: /* PUSH eBP */
15496 case 0x56: /* PUSH eSI */
15497 case 0x57: /* PUSH eDI */
15498 case 0x54: /* PUSH eSP */
15499 /* This is the Right Way, in that the value to be pushed is
15500 established before %rsp is changed, so that pushq %rsp
15501 correctly pushes the old value. */
sewardj03b07cc2005-01-31 18:09:43 +000015502 if (haveF2orF3(pfx)) goto decode_failure;
sewardj55dbb262005-01-28 16:36:51 +000015503 vassert(sz == 2 || sz == 4 || sz == 8);
15504 if (sz == 4)
15505 sz = 8; /* there is no encoding for 32-bit push in 64-bit mode */
15506 ty = sz==2 ? Ity_I16 : Ity_I64;
15507 t1 = newTemp(ty);
15508 t2 = newTemp(Ity_I64);
sewardj5b470602005-02-27 13:10:48 +000015509 assign(t1, getIRegRexB(sz, pfx, opc-0x50));
sewardj55dbb262005-01-28 16:36:51 +000015510 assign(t2, binop(Iop_Sub64, getIReg64(R_RSP), mkU64(sz)));
15511 putIReg64(R_RSP, mkexpr(t2) );
15512 storeLE(mkexpr(t2),mkexpr(t1));
sewardj5b470602005-02-27 13:10:48 +000015513 DIP("push%c %s\n", nameISize(sz), nameIRegRexB(sz,pfx,opc-0x50));
sewardj55dbb262005-01-28 16:36:51 +000015514 break;
15515
sewardja6b93d12005-02-17 09:28:28 +000015516 case 0x68: /* PUSH Iv */
sewardj5b470602005-02-27 13:10:48 +000015517 if (haveF2orF3(pfx)) goto decode_failure;
sewardja6b93d12005-02-17 09:28:28 +000015518 /* Note, sz==4 is not possible in 64-bit mode. Hence ... */
15519 if (sz == 4) sz = 8;
15520 d64 = getSDisp(imin(4,sz),delta);
15521 delta += imin(4,sz);
15522 goto do_push_I;
sewardj909c06d2005-02-19 22:47:41 +000015523 case 0x6A: /* PUSH Ib, sign-extended to sz */
sewardj5b470602005-02-27 13:10:48 +000015524 if (haveF2orF3(pfx)) goto decode_failure;
sewardj909c06d2005-02-19 22:47:41 +000015525 /* Note, sz==4 is not possible in 64-bit mode. Hence ... */
15526 if (sz == 4) sz = 8;
15527 d64 = getSDisp8(delta); delta += 1;
15528 goto do_push_I;
sewardja6b93d12005-02-17 09:28:28 +000015529 do_push_I:
15530 ty = szToITy(sz);
sewardj909c06d2005-02-19 22:47:41 +000015531 t1 = newTemp(Ity_I64);
15532 t2 = newTemp(ty);
sewardja6b93d12005-02-17 09:28:28 +000015533 assign( t1, binop(Iop_Sub64,getIReg64(R_RSP),mkU64(sz)) );
15534 putIReg64(R_RSP, mkexpr(t1) );
sewardjb2da8ec2006-08-28 18:54:18 +000015535 /* stop mkU16 asserting if d32 is a negative 16-bit number
15536 (bug #132813) */
15537 if (ty == Ity_I16)
15538 d64 &= 0xFFFF;
sewardja6b93d12005-02-17 09:28:28 +000015539 storeLE( mkexpr(t1), mkU(ty,d64) );
sewardj1027dc22005-02-26 01:55:02 +000015540 DIP("push%c $%lld\n", nameISize(sz), (Long)d64);
sewardja6b93d12005-02-17 09:28:28 +000015541 break;
15542
sewardj85520e42005-02-19 15:22:38 +000015543 case 0x9C: /* PUSHF */ {
15544 /* Note. There is no encoding for a 32-bit pushf in 64-bit
15545 mode. So sz==4 actually means sz==8. */
sewardj11faabe2006-07-24 09:09:36 +000015546 /* 24 July 06: has also been seen with a redundant REX prefix,
15547 so must also allow sz==8. */
sewardj5b470602005-02-27 13:10:48 +000015548 if (haveF2orF3(pfx)) goto decode_failure;
sewardj11faabe2006-07-24 09:09:36 +000015549 vassert(sz == 2 || sz == 4 || sz == 8);
sewardj85520e42005-02-19 15:22:38 +000015550 if (sz == 4) sz = 8;
sewardj5b470602005-02-27 13:10:48 +000015551 if (sz != 8) goto decode_failure; // until we know a sz==2 test case exists
sewardj85520e42005-02-19 15:22:38 +000015552
15553 t1 = newTemp(Ity_I64);
15554 assign( t1, binop(Iop_Sub64,getIReg64(R_RSP),mkU64(sz)) );
15555 putIReg64(R_RSP, mkexpr(t1) );
15556
15557 t2 = newTemp(Ity_I64);
15558 assign( t2, mk_amd64g_calculate_rflags_all() );
15559
15560 /* Patch in the D flag. This can simply be a copy of bit 10 of
15561 baseBlock[OFFB_DFLAG]. */
15562 t3 = newTemp(Ity_I64);
15563 assign( t3, binop(Iop_Or64,
15564 mkexpr(t2),
15565 binop(Iop_And64,
15566 IRExpr_Get(OFFB_DFLAG,Ity_I64),
15567 mkU64(1<<10)))
15568 );
15569
15570 /* And patch in the ID flag. */
15571 t4 = newTemp(Ity_I64);
15572 assign( t4, binop(Iop_Or64,
15573 mkexpr(t3),
15574 binop(Iop_And64,
15575 binop(Iop_Shl64, IRExpr_Get(OFFB_IDFLAG,Ity_I64),
15576 mkU8(21)),
15577 mkU64(1<<21)))
15578 );
15579
15580 /* if sz==2, the stored value needs to be narrowed. */
15581 if (sz == 2)
15582 storeLE( mkexpr(t1), unop(Iop_32to16,
15583 unop(Iop_64to32,mkexpr(t4))) );
15584 else
15585 storeLE( mkexpr(t1), mkexpr(t4) );
15586
15587 DIP("pushf%c\n", nameISize(sz));
15588 break;
15589 }
15590
sewardjd20c8852005-01-20 20:04:07 +000015591//.. case 0x60: /* PUSHA */
15592//.. /* This is almost certainly wrong for sz==2. So ... */
15593//.. if (sz != 4) goto decode_failure;
15594//..
15595//.. /* This is the Right Way, in that the value to be pushed is
15596//.. established before %esp is changed, so that pusha
15597//.. correctly pushes the old %esp value. New value of %esp is
15598//.. pushed at start. */
15599//.. /* t0 is the %ESP value we're going to push. */
15600//.. t0 = newTemp(Ity_I32);
15601//.. assign( t0, getIReg(4, R_ESP) );
15602//..
15603//.. /* t5 will be the new %ESP value. */
15604//.. t5 = newTemp(Ity_I32);
15605//.. assign( t5, binop(Iop_Sub32, mkexpr(t0), mkU32(8*4)) );
15606//..
15607//.. /* Update guest state before prodding memory. */
15608//.. putIReg(4, R_ESP, mkexpr(t5));
15609//..
15610//.. /* Dump all the registers. */
15611//.. storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(28)), getIReg(4,R_EAX) );
15612//.. storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(24)), getIReg(4,R_ECX) );
15613//.. storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(20)), getIReg(4,R_EDX) );
15614//.. storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(16)), getIReg(4,R_EBX) );
15615//.. storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(12)), mkexpr(t0) /*esp*/);
15616//.. storeLE( binop(Iop_Add32,mkexpr(t5),mkU32( 8)), getIReg(4,R_EBP) );
15617//.. storeLE( binop(Iop_Add32,mkexpr(t5),mkU32( 4)), getIReg(4,R_ESI) );
15618//.. storeLE( binop(Iop_Add32,mkexpr(t5),mkU32( 0)), getIReg(4,R_EDI) );
15619//..
15620//.. DIP("pusha%c\n", nameISize(sz));
15621//.. break;
15622//..
15623//..
15624//.. //-- case 0x0E: /* PUSH %CS */
15625//.. //-- dis_push_segreg( cb, R_CS, sz ); break;
15626//.. //-- case 0x1E: /* PUSH %DS */
15627//.. //-- dis_push_segreg( cb, R_DS, sz ); break;
15628//.. //-- case 0x06: /* PUSH %ES */
15629//.. //-- dis_push_segreg( cb, R_ES, sz ); break;
15630//.. //-- case 0x16: /* PUSH %SS */
15631//.. //-- dis_push_segreg( cb, R_SS, sz ); break;
15632//..
15633//.. /* ------------------------ SCAS et al ----------------- */
15634//..
15635//.. case 0xA4: /* MOVS, no REP prefix */
15636//.. case 0xA5:
15637//.. dis_string_op( dis_MOVS, ( opc == 0xA4 ? 1 : sz ), "movs", sorb );
15638//.. break;
15639//..
15640//.. case 0xA6: /* CMPSb, no REP prefix */
15641//.. //-- case 0xA7:
15642//.. dis_string_op( dis_CMPS, ( opc == 0xA6 ? 1 : sz ), "cmps", sorb );
15643//.. break;
15644//.. //--
sewardjd20c8852005-01-20 20:04:07 +000015645//.. //--
sewardj0f99be62009-07-22 09:29:13 +000015646 case 0xAC: /* LODS, no REP prefix */
15647 case 0xAD:
15648 dis_string_op( dis_LODS, ( opc == 0xAC ? 1 : sz ), "lods", pfx );
15649 break;
sewardjd20c8852005-01-20 20:04:07 +000015650//..
15651//.. case 0xAE: /* SCAS, no REP prefix */
15652//.. case 0xAF:
15653//.. dis_string_op( dis_SCAS, ( opc == 0xAE ? 1 : sz ), "scas", sorb );
15654//.. break;
sewardjd0a12df2005-02-10 02:07:43 +000015655
15656
15657 case 0xFC: /* CLD */
sewardj5b470602005-02-27 13:10:48 +000015658 if (haveF2orF3(pfx)) goto decode_failure;
sewardjd0a12df2005-02-10 02:07:43 +000015659 stmt( IRStmt_Put( OFFB_DFLAG, mkU64(1)) );
15660 DIP("cld\n");
15661 break;
15662
sewardj909c06d2005-02-19 22:47:41 +000015663 case 0xFD: /* STD */
sewardj5b470602005-02-27 13:10:48 +000015664 if (haveF2orF3(pfx)) goto decode_failure;
sewardj909c06d2005-02-19 22:47:41 +000015665 stmt( IRStmt_Put( OFFB_DFLAG, mkU64(-1ULL)) );
15666 DIP("std\n");
15667 break;
15668
sewardj31804462006-05-12 20:15:33 +000015669 case 0xF8: /* CLC */
15670 case 0xF9: /* STC */
15671 case 0xF5: /* CMC */
15672 t0 = newTemp(Ity_I64);
15673 t1 = newTemp(Ity_I64);
15674 assign( t0, mk_amd64g_calculate_rflags_all() );
15675 switch (opc) {
15676 case 0xF8:
15677 assign( t1, binop(Iop_And64, mkexpr(t0),
15678 mkU64(~AMD64G_CC_MASK_C)));
15679 DIP("clc\n");
15680 break;
15681 case 0xF9:
15682 assign( t1, binop(Iop_Or64, mkexpr(t0),
15683 mkU64(AMD64G_CC_MASK_C)));
15684 DIP("stc\n");
15685 break;
15686 case 0xF5:
15687 assign( t1, binop(Iop_Xor64, mkexpr(t0),
15688 mkU64(AMD64G_CC_MASK_C)));
15689 DIP("cmc\n");
15690 break;
15691 default:
15692 vpanic("disInstr(x64)(clc/stc/cmc)");
15693 }
15694 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(AMD64G_CC_OP_COPY) ));
15695 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
15696 stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(t1) ));
15697 /* Set NDEP even though it isn't used. This makes redundant-PUT
15698 elimination of previous stores to this field work better. */
15699 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU64(0) ));
15700 break;
15701
sewardjd20c8852005-01-20 20:04:07 +000015702//.. /* REPNE prefix insn */
15703//.. case 0xF2: {
15704//.. Addr32 eip_orig = guest_eip_bbstart + delta - 1;
15705//.. vassert(sorb == 0);
sewardj8c332e22005-01-28 01:36:56 +000015706//.. abyte = getUChar(delta); delta++;
sewardjd20c8852005-01-20 20:04:07 +000015707//..
sewardj8c332e22005-01-28 01:36:56 +000015708//.. if (abyte == 0x66) { sz = 2; abyte = getUChar(delta); delta++; }
sewardjd20c8852005-01-20 20:04:07 +000015709//.. whatNext = Dis_StopHere;
15710//..
15711//.. switch (abyte) {
15712//.. /* According to the Intel manual, "repne movs" should never occur, but
15713//.. * in practice it has happened, so allow for it here... */
15714//.. case 0xA4: sz = 1; /* REPNE MOVS<sz> */
15715//.. goto decode_failure;
15716//.. //-- case 0xA5:
15717//.. // dis_REP_op ( CondNZ, dis_MOVS, sz, eip_orig,
15718//.. // guest_eip_bbstart+delta, "repne movs" );
15719//.. // break;
15720//.. //--
15721//.. //-- case 0xA6: sz = 1; /* REPNE CMPS<sz> */
15722//.. //-- case 0xA7:
15723//.. //-- dis_REP_op ( cb, CondNZ, dis_CMPS, sz, eip_orig, eip, "repne cmps" );
15724//.. //-- break;
15725//.. //--
15726//.. case 0xAE: sz = 1; /* REPNE SCAS<sz> */
15727//.. case 0xAF:
15728//.. dis_REP_op ( X86CondNZ, dis_SCAS, sz, eip_orig,
15729//.. guest_eip_bbstart+delta, "repne scas" );
15730//.. break;
15731//..
15732//.. default:
15733//.. goto decode_failure;
15734//.. }
15735//.. break;
15736//.. }
sewardjd0a12df2005-02-10 02:07:43 +000015737
sewardj909c06d2005-02-19 22:47:41 +000015738 /* ------ AE: SCAS variants ------ */
15739 case 0xAE:
15740 case 0xAF:
15741 /* F2 AE/AF: repne scasb/repne scas{w,l,q} */
sewardj42561ef2005-11-04 14:18:31 +000015742 if (haveASO(pfx))
15743 goto decode_failure;
sewardj85520e42005-02-19 15:22:38 +000015744 if (haveF2(pfx) && !haveF3(pfx)) {
15745 if (opc == 0xAE)
15746 sz = 1;
15747 dis_REP_op ( AMD64CondNZ, dis_SCAS, sz,
sewardj9e6491a2005-07-02 19:24:10 +000015748 guest_RIP_curr_instr,
15749 guest_RIP_bbstart+delta, "repne scas", pfx );
15750 dres.whatNext = Dis_StopHere;
sewardj85520e42005-02-19 15:22:38 +000015751 break;
15752 }
sewardj7d8f1372008-11-08 15:25:00 +000015753 /* F3 AE/AF: repe scasb/repe scas{w,l,q} */
15754 if (haveASO(pfx))
15755 goto decode_failure;
15756 if (!haveF2(pfx) && haveF3(pfx)) {
15757 if (opc == 0xAE)
15758 sz = 1;
15759 dis_REP_op ( AMD64CondZ, dis_SCAS, sz,
15760 guest_RIP_curr_instr,
15761 guest_RIP_bbstart+delta, "repe scas", pfx );
15762 dres.whatNext = Dis_StopHere;
15763 break;
15764 }
sewardj909c06d2005-02-19 22:47:41 +000015765 /* AE/AF: scasb/scas{w,l,q} */
15766 if (!haveF2(pfx) && !haveF3(pfx)) {
15767 if (opc == 0xAE)
15768 sz = 1;
15769 dis_string_op( dis_SCAS, sz, "scas", pfx );
15770 break;
15771 }
sewardj85520e42005-02-19 15:22:38 +000015772 goto decode_failure;
sewardjd0a12df2005-02-10 02:07:43 +000015773
sewardj909c06d2005-02-19 22:47:41 +000015774 /* ------ A6, A7: CMPS variants ------ */
15775 case 0xA6:
15776 case 0xA7:
15777 /* F3 A6/A7: repe cmps/rep cmps{w,l,q} */
sewardj42561ef2005-11-04 14:18:31 +000015778 if (haveASO(pfx))
15779 goto decode_failure;
sewardjd0a12df2005-02-10 02:07:43 +000015780 if (haveF3(pfx) && !haveF2(pfx)) {
15781 if (opc == 0xA6)
15782 sz = 1;
15783 dis_REP_op ( AMD64CondZ, dis_CMPS, sz,
sewardj9e6491a2005-07-02 19:24:10 +000015784 guest_RIP_curr_instr,
15785 guest_RIP_bbstart+delta, "repe cmps", pfx );
15786 dres.whatNext = Dis_StopHere;
sewardja6b93d12005-02-17 09:28:28 +000015787 break;
15788 }
15789 goto decode_failure;
15790
sewardj909c06d2005-02-19 22:47:41 +000015791 /* ------ AA, AB: STOS variants ------ */
15792 case 0xAA:
15793 case 0xAB:
15794 /* F3 AA/AB: rep stosb/rep stos{w,l,q} */
sewardj42561ef2005-11-04 14:18:31 +000015795 if (haveASO(pfx))
15796 goto decode_failure;
sewardja6b93d12005-02-17 09:28:28 +000015797 if (haveF3(pfx) && !haveF2(pfx)) {
sewardj909c06d2005-02-19 22:47:41 +000015798 if (opc == 0xAA)
15799 sz = 1;
sewardja6b93d12005-02-17 09:28:28 +000015800 dis_REP_op ( AMD64CondAlways, dis_STOS, sz,
sewardj9e6491a2005-07-02 19:24:10 +000015801 guest_RIP_curr_instr,
15802 guest_RIP_bbstart+delta, "rep stos", pfx );
15803 dres.whatNext = Dis_StopHere;
sewardj909c06d2005-02-19 22:47:41 +000015804 break;
15805 }
15806 /* AA/AB: stosb/stos{w,l,q} */
15807 if (!haveF3(pfx) && !haveF2(pfx)) {
15808 if (opc == 0xAA)
15809 sz = 1;
15810 dis_string_op( dis_STOS, sz, "stos", pfx );
sewardjd0a12df2005-02-10 02:07:43 +000015811 break;
15812 }
15813 goto decode_failure;
15814
sewardj909c06d2005-02-19 22:47:41 +000015815 /* ------ A4, A5: MOVS variants ------ */
15816 case 0xA4:
15817 case 0xA5:
15818 /* F3 A4: rep movsb */
sewardj42561ef2005-11-04 14:18:31 +000015819 if (haveASO(pfx))
15820 goto decode_failure;
sewardj909c06d2005-02-19 22:47:41 +000015821 if (haveF3(pfx) && !haveF2(pfx)) {
15822 if (opc == 0xA4)
15823 sz = 1;
15824 dis_REP_op ( AMD64CondAlways, dis_MOVS, sz,
sewardj9e6491a2005-07-02 19:24:10 +000015825 guest_RIP_curr_instr,
15826 guest_RIP_bbstart+delta, "rep movs", pfx );
15827 dres.whatNext = Dis_StopHere;
sewardj909c06d2005-02-19 22:47:41 +000015828 break;
15829 }
15830 /* A4: movsb */
15831 if (!haveF3(pfx) && !haveF2(pfx)) {
15832 if (opc == 0xA4)
15833 sz = 1;
15834 dis_string_op( dis_MOVS, sz, "movs", pfx );
15835 break;
15836 }
15837 goto decode_failure;
15838
sewardj7de0d3c2005-02-13 02:26:41 +000015839
15840 /* ------------------------ XCHG ----------------------- */
15841
sewardjc4356f02007-11-09 21:15:04 +000015842 /* XCHG reg,mem automatically asserts LOCK# even without a LOCK
15843 prefix. Therefore, surround it with a IRStmt_MBE(Imbe_BusLock)
15844 and IRStmt_MBE(Imbe_BusUnlock) pair. But be careful; if it is
15845 used with an explicit LOCK prefix, we don't want to end up with
15846 two IRStmt_MBE(Imbe_BusLock)s -- one made here and one made by
15847 the generic LOCK logic at the top of disInstr. */
sewardj1bf95982005-05-18 12:04:04 +000015848 case 0x86: /* XCHG Gb,Eb */
15849 sz = 1;
15850 /* Fall through ... */
sewardj7de0d3c2005-02-13 02:26:41 +000015851 case 0x87: /* XCHG Gv,Ev */
sewardj5b470602005-02-27 13:10:48 +000015852 if (haveF2orF3(pfx)) goto decode_failure;
sewardj7de0d3c2005-02-13 02:26:41 +000015853 modrm = getUChar(delta);
15854 ty = szToITy(sz);
15855 t1 = newTemp(ty); t2 = newTemp(ty);
15856 if (epartIsReg(modrm)) {
sewardj5b470602005-02-27 13:10:48 +000015857 assign(t1, getIRegE(sz, pfx, modrm));
15858 assign(t2, getIRegG(sz, pfx, modrm));
15859 putIRegG(sz, pfx, modrm, mkexpr(t1));
15860 putIRegE(sz, pfx, modrm, mkexpr(t2));
sewardj7de0d3c2005-02-13 02:26:41 +000015861 delta++;
15862 DIP("xchg%c %s, %s\n",
sewardj5b470602005-02-27 13:10:48 +000015863 nameISize(sz), nameIRegG(sz, pfx, modrm),
15864 nameIRegE(sz, pfx, modrm));
sewardj7de0d3c2005-02-13 02:26:41 +000015865 } else {
sewardje9d8a262009-07-01 08:06:34 +000015866 *expect_CAS = True;
sewardj2e28ac42008-12-04 00:05:12 +000015867 addr = disAMode ( &alen, vbi, pfx, delta, dis_buf, 0 );
sewardj5b470602005-02-27 13:10:48 +000015868 assign( t1, loadLE(ty, mkexpr(addr)) );
15869 assign( t2, getIRegG(sz, pfx, modrm) );
sewardje9d8a262009-07-01 08:06:34 +000015870 casLE( mkexpr(addr),
15871 mkexpr(t1), mkexpr(t2), guest_RIP_curr_instr );
sewardj5b470602005-02-27 13:10:48 +000015872 putIRegG( sz, pfx, modrm, mkexpr(t1) );
sewardj7de0d3c2005-02-13 02:26:41 +000015873 delta += alen;
15874 DIP("xchg%c %s, %s\n", nameISize(sz),
sewardj5b470602005-02-27 13:10:48 +000015875 nameIRegG(sz, pfx, modrm), dis_buf);
sewardj7de0d3c2005-02-13 02:26:41 +000015876 }
15877 break;
sewardj118b23e2005-01-29 02:14:44 +000015878
15879 case 0x90: /* XCHG eAX,eAX */
sewardjc8b26352005-07-20 09:23:13 +000015880 /* detect and handle F3 90 (rep nop) specially */
15881 if (!have66(pfx) && !haveF2(pfx) && haveF3(pfx)) {
15882 DIP("rep nop (P4 pause)\n");
15883 /* "observe" the hint. The Vex client needs to be careful not
15884 to cause very long delays as a result, though. */
15885 jmp_lit(Ijk_Yield, guest_RIP_bbstart+delta);
15886 dres.whatNext = Dis_StopHere;
15887 break;
15888 }
sewardj2d4fcd52005-05-18 11:47:47 +000015889 /* detect and handle NOPs specially */
15890 if (/* F2/F3 probably change meaning completely */
15891 !haveF2orF3(pfx)
15892 /* If REX.B is 1, we're not exchanging rAX with itself */
15893 && getRexB(pfx)==0 ) {
15894 DIP("nop\n");
15895 break;
15896 }
15897 /* else fall through to normal case. */
sewardja6b93d12005-02-17 09:28:28 +000015898 case 0x91: /* XCHG rAX,rCX */
15899 case 0x92: /* XCHG rAX,rDX */
15900 case 0x93: /* XCHG rAX,rBX */
15901 case 0x94: /* XCHG rAX,rSP */
15902 case 0x95: /* XCHG rAX,rBP */
15903 case 0x96: /* XCHG rAX,rSI */
15904 case 0x97: /* XCHG rAX,rDI */
sewardj2d4fcd52005-05-18 11:47:47 +000015905
15906 /* guard against mutancy */
sewardja6b93d12005-02-17 09:28:28 +000015907 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2d4fcd52005-05-18 11:47:47 +000015908
15909 /* sz == 2 could legitimately happen, but we don't handle it yet */
15910 if (sz == 2) goto decode_failure; /* awaiting test case */
15911
sewardja6b93d12005-02-17 09:28:28 +000015912 codegen_xchg_rAX_Reg ( pfx, sz, opc - 0x90 );
15913 break;
15914
sewardjd20c8852005-01-20 20:04:07 +000015915//.. //-- /* ------------------------ XLAT ----------------------- */
15916//.. //--
15917//.. //-- case 0xD7: /* XLAT */
15918//.. //-- t1 = newTemp(cb); t2 = newTemp(cb);
15919//.. //-- uInstr2(cb, GET, sz, ArchReg, R_EBX, TempReg, t1); /* get eBX */
sewardj42561ef2005-11-04 14:18:31 +000015920//.. //-- handleAddrOverrides( cb, sorb, t1 ); /* make t1 DS:eBX */
sewardjd20c8852005-01-20 20:04:07 +000015921//.. //-- uInstr2(cb, GET, 1, ArchReg, R_AL, TempReg, t2); /* get AL */
15922//.. //-- /* Widen %AL to 32 bits, so it's all defined when we add it. */
15923//.. //-- uInstr1(cb, WIDEN, 4, TempReg, t2);
15924//.. //-- uWiden(cb, 1, False);
15925//.. //-- uInstr2(cb, ADD, sz, TempReg, t2, TempReg, t1); /* add AL to eBX */
15926//.. //-- uInstr2(cb, LOAD, 1, TempReg, t1, TempReg, t2); /* get byte at t1 into t2 */
15927//.. //-- uInstr2(cb, PUT, 1, TempReg, t2, ArchReg, R_AL); /* put byte into AL */
15928//.. //--
15929//.. //-- DIP("xlat%c [ebx]\n", nameISize(sz));
15930//.. //-- break;
sewardjbb4396c2007-11-20 17:29:08 +000015931
15932 /* ------------------------ IN / OUT ----------------------- */
15933
15934 case 0xE4: /* IN imm8, AL */
15935 sz = 1;
15936 t1 = newTemp(Ity_I64);
15937 abyte = getUChar(delta); delta++;
15938 assign(t1, mkU64( abyte & 0xFF ));
15939 DIP("in%c $%d,%s\n", nameISize(sz), (Int)abyte, nameIRegRAX(sz));
15940 goto do_IN;
15941 case 0xE5: /* IN imm8, eAX */
15942 if (!(sz == 2 || sz == 4)) goto decode_failure;
15943 t1 = newTemp(Ity_I64);
15944 abyte = getUChar(delta); delta++;
15945 assign(t1, mkU64( abyte & 0xFF ));
15946 DIP("in%c $%d,%s\n", nameISize(sz), (Int)abyte, nameIRegRAX(sz));
15947 goto do_IN;
15948 case 0xEC: /* IN %DX, AL */
15949 sz = 1;
15950 t1 = newTemp(Ity_I64);
15951 assign(t1, unop(Iop_16Uto64, getIRegRDX(2)));
15952 DIP("in%c %s,%s\n", nameISize(sz), nameIRegRDX(2),
15953 nameIRegRAX(sz));
15954 goto do_IN;
15955 case 0xED: /* IN %DX, eAX */
15956 if (!(sz == 2 || sz == 4)) goto decode_failure;
15957 t1 = newTemp(Ity_I64);
15958 assign(t1, unop(Iop_16Uto64, getIRegRDX(2)));
15959 DIP("in%c %s,%s\n", nameISize(sz), nameIRegRDX(2),
15960 nameIRegRAX(sz));
15961 goto do_IN;
15962 do_IN: {
15963 /* At this point, sz indicates the width, and t1 is a 64-bit
15964 value giving port number. */
15965 IRDirty* d;
15966 if (haveF2orF3(pfx)) goto decode_failure;
15967 vassert(sz == 1 || sz == 2 || sz == 4);
15968 ty = szToITy(sz);
15969 t2 = newTemp(Ity_I64);
15970 d = unsafeIRDirty_1_N(
15971 t2,
15972 0/*regparms*/,
15973 "amd64g_dirtyhelper_IN",
15974 &amd64g_dirtyhelper_IN,
15975 mkIRExprVec_2( mkexpr(t1), mkU64(sz) )
15976 );
15977 /* do the call, dumping the result in t2. */
15978 stmt( IRStmt_Dirty(d) );
15979 putIRegRAX(sz, narrowTo( ty, mkexpr(t2) ) );
15980 break;
15981 }
15982
15983 case 0xE6: /* OUT AL, imm8 */
15984 sz = 1;
15985 t1 = newTemp(Ity_I64);
15986 abyte = getUChar(delta); delta++;
15987 assign( t1, mkU64( abyte & 0xFF ) );
15988 DIP("out%c %s,$%d\n", nameISize(sz), nameIRegRAX(sz), (Int)abyte);
15989 goto do_OUT;
15990 case 0xE7: /* OUT eAX, imm8 */
15991 if (!(sz == 2 || sz == 4)) goto decode_failure;
15992 t1 = newTemp(Ity_I64);
15993 abyte = getUChar(delta); delta++;
15994 assign( t1, mkU64( abyte & 0xFF ) );
15995 DIP("out%c %s,$%d\n", nameISize(sz), nameIRegRAX(sz), (Int)abyte);
15996 goto do_OUT;
15997 case 0xEE: /* OUT AL, %DX */
15998 sz = 1;
15999 t1 = newTemp(Ity_I64);
16000 assign( t1, unop(Iop_16Uto64, getIRegRDX(2)) );
16001 DIP("out%c %s,%s\n", nameISize(sz), nameIRegRAX(sz),
16002 nameIRegRDX(2));
16003 goto do_OUT;
16004 case 0xEF: /* OUT eAX, %DX */
16005 if (!(sz == 2 || sz == 4)) goto decode_failure;
16006 t1 = newTemp(Ity_I64);
16007 assign( t1, unop(Iop_16Uto64, getIRegRDX(2)) );
16008 DIP("out%c %s,%s\n", nameISize(sz), nameIRegRAX(sz),
16009 nameIRegRDX(2));
16010 goto do_OUT;
16011 do_OUT: {
16012 /* At this point, sz indicates the width, and t1 is a 64-bit
16013 value giving port number. */
16014 IRDirty* d;
16015 if (haveF2orF3(pfx)) goto decode_failure;
16016 vassert(sz == 1 || sz == 2 || sz == 4);
16017 ty = szToITy(sz);
16018 d = unsafeIRDirty_0_N(
16019 0/*regparms*/,
16020 "amd64g_dirtyhelper_OUT",
16021 &amd64g_dirtyhelper_OUT,
16022 mkIRExprVec_3( mkexpr(t1),
16023 widenUto64( getIRegRAX(sz) ),
16024 mkU64(sz) )
16025 );
16026 stmt( IRStmt_Dirty(d) );
16027 break;
16028 }
sewardj3ca55a12005-01-27 16:06:23 +000016029
16030 /* ------------------------ (Grp1 extensions) ---------- */
16031
16032 case 0x80: /* Grp1 Ib,Eb */
sewardj5b470602005-02-27 13:10:48 +000016033 if (haveF2orF3(pfx)) goto decode_failure;
sewardj8c332e22005-01-28 01:36:56 +000016034 modrm = getUChar(delta);
sewardj3ca55a12005-01-27 16:06:23 +000016035 am_sz = lengthAMode(pfx,delta);
16036 sz = 1;
16037 d_sz = 1;
16038 d64 = getSDisp8(delta + am_sz);
sewardj2e28ac42008-12-04 00:05:12 +000016039 delta = dis_Grp1 ( vbi, pfx, delta, modrm, am_sz, d_sz, sz, d64 );
sewardj3ca55a12005-01-27 16:06:23 +000016040 break;
16041
16042 case 0x81: /* Grp1 Iv,Ev */
16043 if (haveF2orF3(pfx)) goto decode_failure;
sewardj8c332e22005-01-28 01:36:56 +000016044 modrm = getUChar(delta);
sewardj3ca55a12005-01-27 16:06:23 +000016045 am_sz = lengthAMode(pfx,delta);
16046 d_sz = imin(sz,4);
16047 d64 = getSDisp(d_sz, delta + am_sz);
sewardj2e28ac42008-12-04 00:05:12 +000016048 delta = dis_Grp1 ( vbi, pfx, delta, modrm, am_sz, d_sz, sz, d64 );
sewardj3ca55a12005-01-27 16:06:23 +000016049 break;
16050
16051 case 0x83: /* Grp1 Ib,Ev */
16052 if (haveF2orF3(pfx)) goto decode_failure;
sewardj8c332e22005-01-28 01:36:56 +000016053 modrm = getUChar(delta);
sewardj3ca55a12005-01-27 16:06:23 +000016054 am_sz = lengthAMode(pfx,delta);
16055 d_sz = 1;
16056 d64 = getSDisp8(delta + am_sz);
sewardj2e28ac42008-12-04 00:05:12 +000016057 delta = dis_Grp1 ( vbi, pfx, delta, modrm, am_sz, d_sz, sz, d64 );
sewardj3ca55a12005-01-27 16:06:23 +000016058 break;
16059
sewardj118b23e2005-01-29 02:14:44 +000016060 /* ------------------------ (Grp2 extensions) ---------- */
sewardj03b07cc2005-01-31 18:09:43 +000016061
sewardjfd4203c2007-03-21 00:21:56 +000016062 case 0xC0: { /* Grp2 Ib,Eb */
16063 Bool decode_OK = True;
sewardj5b470602005-02-27 13:10:48 +000016064 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000016065 modrm = getUChar(delta);
16066 am_sz = lengthAMode(pfx,delta);
16067 d_sz = 1;
16068 d64 = getUChar(delta + am_sz);
16069 sz = 1;
sewardj2e28ac42008-12-04 00:05:12 +000016070 delta = dis_Grp2 ( vbi, pfx, delta, modrm, am_sz, d_sz, sz,
sewardjfd4203c2007-03-21 00:21:56 +000016071 mkU8(d64 & 0xFF), NULL, &decode_OK );
16072 if (!decode_OK) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000016073 break;
sewardjfd4203c2007-03-21 00:21:56 +000016074 }
16075 case 0xC1: { /* Grp2 Ib,Ev */
16076 Bool decode_OK = True;
sewardj5b470602005-02-27 13:10:48 +000016077 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000016078 modrm = getUChar(delta);
16079 am_sz = lengthAMode(pfx,delta);
16080 d_sz = 1;
16081 d64 = getUChar(delta + am_sz);
sewardj2e28ac42008-12-04 00:05:12 +000016082 delta = dis_Grp2 ( vbi, pfx, delta, modrm, am_sz, d_sz, sz,
sewardjfd4203c2007-03-21 00:21:56 +000016083 mkU8(d64 & 0xFF), NULL, &decode_OK );
16084 if (!decode_OK) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000016085 break;
sewardjfd4203c2007-03-21 00:21:56 +000016086 }
16087 case 0xD0: { /* Grp2 1,Eb */
16088 Bool decode_OK = True;
sewardj5b470602005-02-27 13:10:48 +000016089 if (haveF2orF3(pfx)) goto decode_failure;
sewardj03b07cc2005-01-31 18:09:43 +000016090 modrm = getUChar(delta);
16091 am_sz = lengthAMode(pfx,delta);
16092 d_sz = 0;
16093 d64 = 1;
16094 sz = 1;
sewardj2e28ac42008-12-04 00:05:12 +000016095 delta = dis_Grp2 ( vbi, pfx, delta, modrm, am_sz, d_sz, sz,
sewardjfd4203c2007-03-21 00:21:56 +000016096 mkU8(d64), NULL, &decode_OK );
16097 if (!decode_OK) goto decode_failure;
sewardj03b07cc2005-01-31 18:09:43 +000016098 break;
sewardjfd4203c2007-03-21 00:21:56 +000016099 }
16100 case 0xD1: { /* Grp2 1,Ev */
16101 Bool decode_OK = True;
sewardj5b470602005-02-27 13:10:48 +000016102 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000016103 modrm = getUChar(delta);
16104 am_sz = lengthAMode(pfx,delta);
16105 d_sz = 0;
16106 d64 = 1;
sewardj2e28ac42008-12-04 00:05:12 +000016107 delta = dis_Grp2 ( vbi, pfx, delta, modrm, am_sz, d_sz, sz,
sewardjfd4203c2007-03-21 00:21:56 +000016108 mkU8(d64), NULL, &decode_OK );
16109 if (!decode_OK) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000016110 break;
sewardjfd4203c2007-03-21 00:21:56 +000016111 }
16112 case 0xD2: { /* Grp2 CL,Eb */
16113 Bool decode_OK = True;
sewardj5b470602005-02-27 13:10:48 +000016114 if (haveF2orF3(pfx)) goto decode_failure;
sewardj85520e42005-02-19 15:22:38 +000016115 modrm = getUChar(delta);
16116 am_sz = lengthAMode(pfx,delta);
16117 d_sz = 0;
16118 sz = 1;
sewardj2e28ac42008-12-04 00:05:12 +000016119 delta = dis_Grp2 ( vbi, pfx, delta, modrm, am_sz, d_sz, sz,
sewardjfd4203c2007-03-21 00:21:56 +000016120 getIRegCL(), "%cl", &decode_OK );
16121 if (!decode_OK) goto decode_failure;
sewardj85520e42005-02-19 15:22:38 +000016122 break;
sewardjfd4203c2007-03-21 00:21:56 +000016123 }
16124 case 0xD3: { /* Grp2 CL,Ev */
16125 Bool decode_OK = True;
sewardj5b470602005-02-27 13:10:48 +000016126 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000016127 modrm = getUChar(delta);
16128 am_sz = lengthAMode(pfx,delta);
16129 d_sz = 0;
sewardj2e28ac42008-12-04 00:05:12 +000016130 delta = dis_Grp2 ( vbi, pfx, delta, modrm, am_sz, d_sz, sz,
sewardjfd4203c2007-03-21 00:21:56 +000016131 getIRegCL(), "%cl", &decode_OK );
16132 if (!decode_OK) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000016133 break;
sewardjfd4203c2007-03-21 00:21:56 +000016134 }
sewardj32b2bbe2005-01-28 00:50:10 +000016135
16136 /* ------------------------ (Grp3 extensions) ---------- */
16137
sewardjfd4203c2007-03-21 00:21:56 +000016138 case 0xF6: { /* Grp3 Eb */
16139 Bool decode_OK = True;
sewardj5b470602005-02-27 13:10:48 +000016140 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000016141 delta = dis_Grp3 ( vbi, pfx, 1, delta, &decode_OK );
sewardjfd4203c2007-03-21 00:21:56 +000016142 if (!decode_OK) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000016143 break;
sewardjfd4203c2007-03-21 00:21:56 +000016144 }
16145 case 0xF7: { /* Grp3 Ev */
16146 Bool decode_OK = True;
sewardj5b470602005-02-27 13:10:48 +000016147 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000016148 delta = dis_Grp3 ( vbi, pfx, sz, delta, &decode_OK );
sewardjfd4203c2007-03-21 00:21:56 +000016149 if (!decode_OK) goto decode_failure;
sewardj32b2bbe2005-01-28 00:50:10 +000016150 break;
sewardjfd4203c2007-03-21 00:21:56 +000016151 }
sewardj32b2bbe2005-01-28 00:50:10 +000016152
sewardj03b07cc2005-01-31 18:09:43 +000016153 /* ------------------------ (Grp4 extensions) ---------- */
16154
sewardjfd4203c2007-03-21 00:21:56 +000016155 case 0xFE: { /* Grp4 Eb */
16156 Bool decode_OK = True;
sewardj5b470602005-02-27 13:10:48 +000016157 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000016158 delta = dis_Grp4 ( vbi, pfx, delta, &decode_OK );
sewardjfd4203c2007-03-21 00:21:56 +000016159 if (!decode_OK) goto decode_failure;
sewardj03b07cc2005-01-31 18:09:43 +000016160 break;
sewardjfd4203c2007-03-21 00:21:56 +000016161 }
sewardj354e5c62005-01-27 20:12:52 +000016162
16163 /* ------------------------ (Grp5 extensions) ---------- */
16164
sewardjfd4203c2007-03-21 00:21:56 +000016165 case 0xFF: { /* Grp5 Ev */
16166 Bool decode_OK = True;
sewardj5b470602005-02-27 13:10:48 +000016167 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000016168 delta = dis_Grp5 ( vbi, pfx, sz, delta, &dres, &decode_OK );
sewardjfd4203c2007-03-21 00:21:56 +000016169 if (!decode_OK) goto decode_failure;
sewardj354e5c62005-01-27 20:12:52 +000016170 break;
sewardjfd4203c2007-03-21 00:21:56 +000016171 }
sewardj3ca55a12005-01-27 16:06:23 +000016172
16173 /* ------------------------ Escapes to 2-byte opcodes -- */
16174
16175 case 0x0F: {
sewardj8c332e22005-01-28 01:36:56 +000016176 opc = getUChar(delta); delta++;
sewardj3ca55a12005-01-27 16:06:23 +000016177 switch (opc) {
16178
sewardj1d511802005-03-27 17:59:45 +000016179 /* =-=-=-=-=-=-=-=-=- Grp8 =-=-=-=-=-=-=-=-=-=-=-= */
16180
16181 case 0xBA: { /* Grp8 Ib,Ev */
16182 Bool decode_OK = False;
16183 if (haveF2orF3(pfx)) goto decode_failure;
16184 modrm = getUChar(delta);
16185 am_sz = lengthAMode(pfx,delta);
16186 d64 = getSDisp8(delta + am_sz);
sewardj2e28ac42008-12-04 00:05:12 +000016187 delta = dis_Grp8_Imm ( vbi, pfx, delta, modrm, am_sz, sz, d64,
sewardj1d511802005-03-27 17:59:45 +000016188 &decode_OK );
16189 if (!decode_OK)
16190 goto decode_failure;
16191 break;
16192 }
16193
sewardjf53b7352005-04-06 20:01:56 +000016194 /* =-=-=-=-=-=-=-=-=- BSF/BSR -=-=-=-=-=-=-=-=-=-= */
16195
16196 case 0xBC: /* BSF Gv,Ev */
16197 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000016198 delta = dis_bs_E_G ( vbi, pfx, sz, delta, True );
sewardjf53b7352005-04-06 20:01:56 +000016199 break;
sewardj537cab02005-04-07 02:03:52 +000016200 case 0xBD: /* BSR Gv,Ev */
16201 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000016202 delta = dis_bs_E_G ( vbi, pfx, sz, delta, False );
sewardj537cab02005-04-07 02:03:52 +000016203 break;
sewardj82c9f2f2005-03-02 16:05:13 +000016204
16205 /* =-=-=-=-=-=-=-=-=- BSWAP -=-=-=-=-=-=-=-=-=-=-= */
16206
16207 case 0xC8: /* BSWAP %eax */
16208 case 0xC9:
16209 case 0xCA:
16210 case 0xCB:
16211 case 0xCC:
16212 case 0xCD:
16213 case 0xCE:
16214 case 0xCF: /* BSWAP %edi */
16215 if (haveF2orF3(pfx)) goto decode_failure;
16216 /* According to the AMD64 docs, this insn can have size 4 or
16217 8. */
16218 if (sz == 4) {
16219 t1 = newTemp(Ity_I32);
16220 t2 = newTemp(Ity_I32);
16221 assign( t1, getIRegRexB(4, pfx, opc-0xC8) );
16222 assign( t2,
16223 binop(Iop_Or32,
16224 binop(Iop_Shl32, mkexpr(t1), mkU8(24)),
16225 binop(Iop_Or32,
sewardj61408222006-08-16 00:25:28 +000016226 binop(Iop_And32, binop(Iop_Shl32, mkexpr(t1), mkU8(8)),
sewardj82c9f2f2005-03-02 16:05:13 +000016227 mkU32(0x00FF0000)),
16228 binop(Iop_Or32,
16229 binop(Iop_And32, binop(Iop_Shr32, mkexpr(t1), mkU8(8)),
16230 mkU32(0x0000FF00)),
16231 binop(Iop_And32, binop(Iop_Shr32, mkexpr(t1), mkU8(24)),
16232 mkU32(0x000000FF) )
16233 )))
16234 );
16235 putIRegRexB(4, pfx, opc-0xC8, mkexpr(t2));
16236 DIP("bswapl %s\n", nameIRegRexB(4, pfx, opc-0xC8));
16237 break;
sewardj98e9f342005-07-23 12:07:37 +000016238 }
16239 else if (sz == 8) {
sewardj61408222006-08-16 00:25:28 +000016240 IRTemp m8 = newTemp(Ity_I64);
16241 IRTemp s8 = newTemp(Ity_I64);
16242 IRTemp m16 = newTemp(Ity_I64);
16243 IRTemp s16 = newTemp(Ity_I64);
16244 IRTemp m32 = newTemp(Ity_I64);
sewardj98e9f342005-07-23 12:07:37 +000016245 t1 = newTemp(Ity_I64);
16246 t2 = newTemp(Ity_I64);
16247 assign( t1, getIRegRexB(8, pfx, opc-0xC8) );
16248
sewardj61408222006-08-16 00:25:28 +000016249 assign( m8, mkU64(0xFF00FF00FF00FF00ULL) );
16250 assign( s8,
16251 binop(Iop_Or64,
16252 binop(Iop_Shr64,
16253 binop(Iop_And64,mkexpr(t1),mkexpr(m8)),
16254 mkU8(8)),
16255 binop(Iop_And64,
16256 binop(Iop_Shl64,mkexpr(t1),mkU8(8)),
16257 mkexpr(m8))
16258 )
16259 );
sewardj98e9f342005-07-23 12:07:37 +000016260
sewardj61408222006-08-16 00:25:28 +000016261 assign( m16, mkU64(0xFFFF0000FFFF0000ULL) );
16262 assign( s16,
16263 binop(Iop_Or64,
16264 binop(Iop_Shr64,
16265 binop(Iop_And64,mkexpr(s8),mkexpr(m16)),
16266 mkU8(16)),
16267 binop(Iop_And64,
16268 binop(Iop_Shl64,mkexpr(s8),mkU8(16)),
16269 mkexpr(m16))
16270 )
16271 );
sewardj98e9f342005-07-23 12:07:37 +000016272
sewardj61408222006-08-16 00:25:28 +000016273 assign( m32, mkU64(0xFFFFFFFF00000000ULL) );
16274 assign( t2,
16275 binop(Iop_Or64,
16276 binop(Iop_Shr64,
16277 binop(Iop_And64,mkexpr(s16),mkexpr(m32)),
16278 mkU8(32)),
16279 binop(Iop_And64,
16280 binop(Iop_Shl64,mkexpr(s16),mkU8(32)),
16281 mkexpr(m32))
16282 )
16283 );
sewardj98e9f342005-07-23 12:07:37 +000016284
16285 putIRegRexB(8, pfx, opc-0xC8, mkexpr(t2));
16286 DIP("bswapq %s\n", nameIRegRexB(8, pfx, opc-0xC8));
16287 break;
sewardj82c9f2f2005-03-02 16:05:13 +000016288 } else {
16289 goto decode_failure;
16290 }
16291
sewardj9ed16802005-08-24 10:46:19 +000016292 /* =-=-=-=-=-=-=-=-=- BT/BTS/BTR/BTC =-=-=-=-=-=-= */
16293
sewardja7690fb2005-10-05 17:19:11 +000016294 /* All of these are possible at sizes 2, 4 and 8, but until a
16295 size 2 test case shows up, only handle sizes 4 and 8. */
sewardj9ed16802005-08-24 10:46:19 +000016296
16297 case 0xA3: /* BT Gv,Ev */
16298 if (haveF2orF3(pfx)) goto decode_failure;
sewardj25d23862006-05-12 17:47:21 +000016299 if (sz != 8 && sz != 4 && sz != 2) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000016300 delta = dis_bt_G_E ( vbi, pfx, sz, delta, BtOpNone );
sewardj9ed16802005-08-24 10:46:19 +000016301 break;
16302 case 0xB3: /* BTR Gv,Ev */
16303 if (haveF2orF3(pfx)) goto decode_failure;
sewardj25d23862006-05-12 17:47:21 +000016304 if (sz != 8 && sz != 4 && sz != 2) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000016305 delta = dis_bt_G_E ( vbi, pfx, sz, delta, BtOpReset );
sewardj9ed16802005-08-24 10:46:19 +000016306 break;
16307 case 0xAB: /* BTS Gv,Ev */
16308 if (haveF2orF3(pfx)) goto decode_failure;
sewardj25d23862006-05-12 17:47:21 +000016309 if (sz != 8 && sz != 4 && sz != 2) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000016310 delta = dis_bt_G_E ( vbi, pfx, sz, delta, BtOpSet );
sewardj9ed16802005-08-24 10:46:19 +000016311 break;
16312 case 0xBB: /* BTC Gv,Ev */
16313 if (haveF2orF3(pfx)) goto decode_failure;
sewardj25d23862006-05-12 17:47:21 +000016314 if (sz != 8 && sz != 4 && sz != 2) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000016315 delta = dis_bt_G_E ( vbi, pfx, sz, delta, BtOpComp );
sewardj9ed16802005-08-24 10:46:19 +000016316 break;
sewardj3ca55a12005-01-27 16:06:23 +000016317
16318 /* =-=-=-=-=-=-=-=-=- CMOV =-=-=-=-=-=-=-=-=-=-=-= */
16319
16320 case 0x40:
16321 case 0x41:
16322 case 0x42: /* CMOVBb/CMOVNAEb (cmov below) */
16323 case 0x43: /* CMOVNBb/CMOVAEb (cmov not below) */
16324 case 0x44: /* CMOVZb/CMOVEb (cmov zero) */
16325 case 0x45: /* CMOVNZb/CMOVNEb (cmov not zero) */
16326 case 0x46: /* CMOVBEb/CMOVNAb (cmov below or equal) */
16327 case 0x47: /* CMOVNBEb/CMOVAb (cmov not below or equal) */
16328 case 0x48: /* CMOVSb (cmov negative) */
16329 case 0x49: /* CMOVSb (cmov not negative) */
16330 case 0x4A: /* CMOVP (cmov parity even) */
16331 case 0x4B: /* CMOVNP (cmov parity odd) */
16332 case 0x4C: /* CMOVLb/CMOVNGEb (cmov less) */
16333 case 0x4D: /* CMOVGEb/CMOVNLb (cmov greater or equal) */
16334 case 0x4E: /* CMOVLEb/CMOVNGb (cmov less or equal) */
16335 case 0x4F: /* CMOVGb/CMOVNLEb (cmov greater) */
sewardj5b470602005-02-27 13:10:48 +000016336 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000016337 delta = dis_cmov_E_G(vbi, pfx, sz, (AMD64Condcode)(opc - 0x40), delta);
sewardj3ca55a12005-01-27 16:06:23 +000016338 break;
16339
sewardja6b93d12005-02-17 09:28:28 +000016340 /* =-=-=-=-=-=-=-=-=- CMPXCHG -=-=-=-=-=-=-=-=-=-= */
16341
sewardj7f45b2b2007-11-16 00:18:44 +000016342 case 0xB0: { /* CMPXCHG Gb,Eb */
16343 Bool ok = True;
16344 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000016345 delta = dis_cmpxchg_G_E ( &ok, vbi, pfx, 1, delta );
sewardj7f45b2b2007-11-16 00:18:44 +000016346 if (!ok) goto decode_failure;
16347 break;
16348 }
sewardjd0aa0a52006-08-17 01:20:01 +000016349 case 0xB1: { /* CMPXCHG Gv,Ev (allowed in 16,32,64 bit) */
16350 Bool ok = True;
sewardj5b470602005-02-27 13:10:48 +000016351 if (haveF2orF3(pfx)) goto decode_failure;
sewardjd0aa0a52006-08-17 01:20:01 +000016352 if (sz != 2 && sz != 4 && sz != 8) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000016353 delta = dis_cmpxchg_G_E ( &ok, vbi, pfx, sz, delta );
sewardjd0aa0a52006-08-17 01:20:01 +000016354 if (!ok) goto decode_failure;
sewardja6b93d12005-02-17 09:28:28 +000016355 break;
sewardjd0aa0a52006-08-17 01:20:01 +000016356 }
sewardje9d8a262009-07-01 08:06:34 +000016357
sewardjd0aa0a52006-08-17 01:20:01 +000016358 case 0xC7: { /* CMPXCHG8B Ev, CMPXCHG16B Ev */
sewardj1fb8c922009-07-12 12:56:53 +000016359 IRType elemTy = sz==4 ? Ity_I32 : Ity_I64;
16360 IRTemp expdHi = newTemp(elemTy);
16361 IRTemp expdLo = newTemp(elemTy);
16362 IRTemp dataHi = newTemp(elemTy);
16363 IRTemp dataLo = newTemp(elemTy);
16364 IRTemp oldHi = newTemp(elemTy);
16365 IRTemp oldLo = newTemp(elemTy);
16366 IRTemp flags_old = newTemp(Ity_I64);
16367 IRTemp flags_new = newTemp(Ity_I64);
16368 IRTemp success = newTemp(Ity_I1);
16369 IROp opOR = sz==4 ? Iop_Or32 : Iop_Or64;
16370 IROp opXOR = sz==4 ? Iop_Xor32 : Iop_Xor64;
16371 IROp opCasCmpEQ = sz==4 ? Iop_CasCmpEQ32 : Iop_CasCmpEQ64;
16372 IRExpr* zero = sz==4 ? mkU32(0) : mkU64(0);
16373 IRTemp expdHi64 = newTemp(Ity_I64);
16374 IRTemp expdLo64 = newTemp(Ity_I64);
sewardje9d8a262009-07-01 08:06:34 +000016375
16376 /* Translate this using a DCAS, even if there is no LOCK
16377 prefix. Life is too short to bother with generating two
16378 different translations for the with/without-LOCK-prefix
16379 cases. */
16380 *expect_CAS = True;
16381
16382 /* Decode, and generate address. */
sewardjd0aa0a52006-08-17 01:20:01 +000016383 if (have66orF2orF3(pfx)) goto decode_failure;
16384 if (sz != 4 && sz != 8) goto decode_failure;
sewardje9d8a262009-07-01 08:06:34 +000016385 if (sz == 8 && !(archinfo->hwcaps & VEX_HWCAPS_AMD64_CX16))
16386 goto decode_failure;
16387 modrm = getUChar(delta);
16388 if (epartIsReg(modrm)) goto decode_failure;
16389 if (gregLO3ofRM(modrm) != 1) goto decode_failure;
16390 addr = disAMode ( &alen, vbi, pfx, delta, dis_buf, 0 );
16391 delta += alen;
16392
16393 /* cmpxchg16b requires an alignment check. */
16394 if (sz == 8)
16395 gen_SEGV_if_not_16_aligned( addr );
16396
16397 /* Get the expected and new values. */
16398 assign( expdHi64, getIReg64(R_RDX) );
16399 assign( expdLo64, getIReg64(R_RAX) );
16400
16401 /* These are the correctly-sized expected and new values.
16402 However, we also get expdHi64/expdLo64 above as 64-bits
16403 regardless, because we will need them later in the 32-bit
16404 case (paradoxically). */
16405 assign( expdHi, sz==4 ? unop(Iop_64to32, mkexpr(expdHi64))
16406 : mkexpr(expdHi64) );
16407 assign( expdLo, sz==4 ? unop(Iop_64to32, mkexpr(expdLo64))
16408 : mkexpr(expdLo64) );
16409 assign( dataHi, sz==4 ? getIReg32(R_RCX) : getIReg64(R_RCX) );
16410 assign( dataLo, sz==4 ? getIReg32(R_RBX) : getIReg64(R_RBX) );
16411
16412 /* Do the DCAS */
16413 stmt( IRStmt_CAS(
16414 mkIRCAS( oldHi, oldLo,
16415 Iend_LE, mkexpr(addr),
16416 mkexpr(expdHi), mkexpr(expdLo),
16417 mkexpr(dataHi), mkexpr(dataLo)
16418 )));
16419
16420 /* success when oldHi:oldLo == expdHi:expdLo */
16421 assign( success,
sewardj1fb8c922009-07-12 12:56:53 +000016422 binop(opCasCmpEQ,
sewardje9d8a262009-07-01 08:06:34 +000016423 binop(opOR,
16424 binop(opXOR, mkexpr(oldHi), mkexpr(expdHi)),
16425 binop(opXOR, mkexpr(oldLo), mkexpr(expdLo))
16426 ),
16427 zero
16428 ));
16429
16430 /* If the DCAS is successful, that is to say oldHi:oldLo ==
16431 expdHi:expdLo, then put expdHi:expdLo back in RDX:RAX,
16432 which is where they came from originally. Both the actual
16433 contents of these two regs, and any shadow values, are
16434 unchanged. If the DCAS fails then we're putting into
16435 RDX:RAX the value seen in memory. */
16436 /* Now of course there's a complication in the 32-bit case
16437 (bah!): if the DCAS succeeds, we need to leave RDX:RAX
16438 unchanged; but if we use the same scheme as in the 64-bit
16439 case, we get hit by the standard rule that a write to the
16440 bottom 32 bits of an integer register zeros the upper 32
16441 bits. And so the upper halves of RDX and RAX mysteriously
16442 become zero. So we have to stuff back in the original
16443 64-bit values which we previously stashed in
16444 expdHi64:expdLo64, even if we're doing a cmpxchg8b. */
16445 /* It's just _so_ much fun ... */
16446 putIRegRDX( 8,
16447 IRExpr_Mux0X( unop(Iop_1Uto8, mkexpr(success)),
16448 sz == 4 ? unop(Iop_32Uto64, mkexpr(oldHi))
16449 : mkexpr(oldHi),
16450 mkexpr(expdHi64)
16451 ));
16452 putIRegRAX( 8,
16453 IRExpr_Mux0X( unop(Iop_1Uto8, mkexpr(success)),
16454 sz == 4 ? unop(Iop_32Uto64, mkexpr(oldLo))
16455 : mkexpr(oldLo),
16456 mkexpr(expdLo64)
16457 ));
16458
16459 /* Copy the success bit into the Z flag and leave the others
16460 unchanged */
16461 assign( flags_old, widenUto64(mk_amd64g_calculate_rflags_all()));
16462 assign(
16463 flags_new,
16464 binop(Iop_Or64,
16465 binop(Iop_And64, mkexpr(flags_old),
16466 mkU64(~AMD64G_CC_MASK_Z)),
16467 binop(Iop_Shl64,
16468 binop(Iop_And64,
16469 unop(Iop_1Uto64, mkexpr(success)), mkU64(1)),
16470 mkU8(AMD64G_CC_SHIFT_Z)) ));
16471
16472 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(AMD64G_CC_OP_COPY) ));
16473 stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(flags_new) ));
16474 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
16475 /* Set NDEP even though it isn't used. This makes
16476 redundant-PUT elimination of previous stores to this field
16477 work better. */
16478 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU64(0) ));
16479
16480 /* Sheesh. Aren't you glad it was me and not you that had to
16481 write and validate all this grunge? */
16482
16483 DIP("cmpxchg8b %s\n", dis_buf);
16484 break;
16485
sewardjd0aa0a52006-08-17 01:20:01 +000016486 }
16487
sewardjd0a12df2005-02-10 02:07:43 +000016488 /* =-=-=-=-=-=-=-=-=- CPUID -=-=-=-=-=-=-=-=-=-=-= */
16489
16490 case 0xA2: { /* CPUID */
16491 /* Uses dirty helper:
16492 void amd64g_dirtyhelper_CPUID ( VexGuestAMD64State* )
16493 declared to mod rax, wr rbx, rcx, rdx
16494 */
16495 IRDirty* d = NULL;
16496 HChar* fName = NULL;
16497 void* fAddr = NULL;
sewardj5b470602005-02-27 13:10:48 +000016498 if (haveF2orF3(pfx)) goto decode_failure;
sewardje9d8a262009-07-01 08:06:34 +000016499 if (archinfo->hwcaps == (VEX_HWCAPS_AMD64_SSE3
16500 |VEX_HWCAPS_AMD64_CX16)) {
16501 fName = "amd64g_dirtyhelper_CPUID_sse3_and_cx16";
16502 fAddr = &amd64g_dirtyhelper_CPUID_sse3_and_cx16;
16503 /* This is a Core-2-like machine */
sewardjd0a12df2005-02-10 02:07:43 +000016504 }
sewardje9d8a262009-07-01 08:06:34 +000016505 else {
16506 /* Give a CPUID for at least a baseline machine, no SSE2
16507 and no CX16 */
16508 fName = "amd64g_dirtyhelper_CPUID_baseline";
16509 fAddr = &amd64g_dirtyhelper_CPUID_baseline;
16510 }
sewardj5117ce12006-01-27 21:20:15 +000016511
sewardjd0a12df2005-02-10 02:07:43 +000016512 vassert(fName); vassert(fAddr);
16513 d = unsafeIRDirty_0_N ( 0/*regparms*/,
16514 fName, fAddr, mkIRExprVec_0() );
16515 /* declare guest state effects */
16516 d->needsBBP = True;
16517 d->nFxState = 4;
16518 d->fxState[0].fx = Ifx_Modify;
16519 d->fxState[0].offset = OFFB_RAX;
16520 d->fxState[0].size = 8;
16521 d->fxState[1].fx = Ifx_Write;
16522 d->fxState[1].offset = OFFB_RBX;
16523 d->fxState[1].size = 8;
sewardj32bfd3e2008-02-10 13:29:19 +000016524 d->fxState[2].fx = Ifx_Modify;
sewardjd0a12df2005-02-10 02:07:43 +000016525 d->fxState[2].offset = OFFB_RCX;
16526 d->fxState[2].size = 8;
16527 d->fxState[3].fx = Ifx_Write;
16528 d->fxState[3].offset = OFFB_RDX;
16529 d->fxState[3].size = 8;
16530 /* execute the dirty call, side-effecting guest state */
16531 stmt( IRStmt_Dirty(d) );
16532 /* CPUID is a serialising insn. So, just in case someone is
16533 using it as a memory fence ... */
sewardjc4356f02007-11-09 21:15:04 +000016534 stmt( IRStmt_MBE(Imbe_Fence) );
sewardjd0a12df2005-02-10 02:07:43 +000016535 DIP("cpuid\n");
16536 break;
16537 }
16538
sewardj5e525292005-01-28 15:13:10 +000016539 /* =-=-=-=-=-=-=-=-=- MOVZX, MOVSX =-=-=-=-=-=-=-= */
16540
16541 case 0xB6: /* MOVZXb Eb,Gv */
sewardj5b470602005-02-27 13:10:48 +000016542 if (haveF2orF3(pfx)) goto decode_failure;
sewardj5e525292005-01-28 15:13:10 +000016543 if (sz != 2 && sz != 4 && sz != 8)
16544 goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000016545 delta = dis_movx_E_G ( vbi, pfx, delta, 1, sz, False );
sewardj5e525292005-01-28 15:13:10 +000016546 break;
16547 case 0xB7: /* MOVZXw Ew,Gv */
sewardj5b470602005-02-27 13:10:48 +000016548 if (haveF2orF3(pfx)) goto decode_failure;
sewardj5e525292005-01-28 15:13:10 +000016549 if (sz != 4 && sz != 8)
16550 goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000016551 delta = dis_movx_E_G ( vbi, pfx, delta, 2, sz, False );
sewardj5e525292005-01-28 15:13:10 +000016552 break;
16553
sewardj03b07cc2005-01-31 18:09:43 +000016554 case 0xBE: /* MOVSXb Eb,Gv */
sewardj5b470602005-02-27 13:10:48 +000016555 if (haveF2orF3(pfx)) goto decode_failure;
sewardj82c9f2f2005-03-02 16:05:13 +000016556 if (sz != 2 && sz != 4 && sz != 8)
sewardj03b07cc2005-01-31 18:09:43 +000016557 goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000016558 delta = dis_movx_E_G ( vbi, pfx, delta, 1, sz, True );
sewardj03b07cc2005-01-31 18:09:43 +000016559 break;
16560 case 0xBF: /* MOVSXw Ew,Gv */
sewardj5b470602005-02-27 13:10:48 +000016561 if (haveF2orF3(pfx)) goto decode_failure;
sewardj03b07cc2005-01-31 18:09:43 +000016562 if (sz != 4 && sz != 8)
16563 goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000016564 delta = dis_movx_E_G ( vbi, pfx, delta, 2, sz, True );
sewardj03b07cc2005-01-31 18:09:43 +000016565 break;
16566
sewardjd20c8852005-01-20 20:04:07 +000016567//.. //-- /* =-=-=-=-=-=-=-=-=-=-= MOVNTI -=-=-=-=-=-=-=-=-= */
16568//.. //--
16569//.. //-- case 0xC3: /* MOVNTI Gv,Ev */
16570//.. //-- vg_assert(sz == 4);
16571//.. //-- modrm = getUChar(eip);
16572//.. //-- vg_assert(!epartIsReg(modrm));
16573//.. //-- t1 = newTemp(cb);
16574//.. //-- uInstr2(cb, GET, 4, ArchReg, gregOfRM(modrm), TempReg, t1);
16575//.. //-- pair = disAMode ( cb, sorb, eip, dis_buf );
16576//.. //-- t2 = LOW24(pair);
16577//.. //-- eip += HI8(pair);
16578//.. //-- uInstr2(cb, STORE, 4, TempReg, t1, TempReg, t2);
16579//.. //-- DIP("movnti %s,%s\n", nameIReg(4,gregOfRM(modrm)), dis_buf);
16580//.. //-- break;
sewardj32b2bbe2005-01-28 00:50:10 +000016581
16582 /* =-=-=-=-=-=-=-=-=- MUL/IMUL =-=-=-=-=-=-=-=-=-= */
16583
16584 case 0xAF: /* IMUL Ev, Gv */
sewardj5b470602005-02-27 13:10:48 +000016585 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000016586 delta = dis_mul_E_G ( vbi, pfx, sz, delta );
sewardj32b2bbe2005-01-28 00:50:10 +000016587 break;
16588
sewardjec387ca2006-08-01 18:36:25 +000016589 /* =-=-=-=-=-=-=-=-=- NOPs =-=-=-=-=-=-=-=-=-=-=-= */
16590
16591 case 0x1F:
16592 if (haveF2orF3(pfx)) goto decode_failure;
16593 modrm = getUChar(delta);
16594 if (epartIsReg(modrm)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000016595 addr = disAMode ( &alen, vbi, pfx, delta, dis_buf, 0 );
sewardjec387ca2006-08-01 18:36:25 +000016596 delta += alen;
16597 DIP("nop%c %s\n", nameISize(sz), dis_buf);
16598 break;
16599
sewardj1389d4d2005-01-28 13:46:29 +000016600 /* =-=-=-=-=-=-=-=-=- Jcond d32 -=-=-=-=-=-=-=-=-= */
16601 case 0x80:
16602 case 0x81:
16603 case 0x82: /* JBb/JNAEb (jump below) */
16604 case 0x83: /* JNBb/JAEb (jump not below) */
16605 case 0x84: /* JZb/JEb (jump zero) */
16606 case 0x85: /* JNZb/JNEb (jump not zero) */
16607 case 0x86: /* JBEb/JNAb (jump below or equal) */
16608 case 0x87: /* JNBEb/JAb (jump not below or equal) */
16609 case 0x88: /* JSb (jump negative) */
16610 case 0x89: /* JSb (jump not negative) */
16611 case 0x8A: /* JP (jump parity even) */
16612 case 0x8B: /* JNP/JPO (jump parity odd) */
16613 case 0x8C: /* JLb/JNGEb (jump less) */
16614 case 0x8D: /* JGEb/JNLb (jump greater or equal) */
16615 case 0x8E: /* JLEb/JNGb (jump less or equal) */
16616 case 0x8F: /* JGb/JNLEb (jump greater) */
sewardj984d9b12010-01-15 10:53:21 +000016617 { Long jmpDelta;
16618 HChar* comment = "";
sewardj5b470602005-02-27 13:10:48 +000016619 if (haveF2orF3(pfx)) goto decode_failure;
sewardj984d9b12010-01-15 10:53:21 +000016620 jmpDelta = getSDisp32(delta);
16621 d64 = (guest_RIP_bbstart+delta+4) + jmpDelta;
sewardj1389d4d2005-01-28 13:46:29 +000016622 delta += 4;
sewardj984d9b12010-01-15 10:53:21 +000016623 if (resteerCisOk
16624 && vex_control.guest_chase_cond
sewardj0d925b12010-01-17 15:47:01 +000016625 && (Addr64)d64 != (Addr64)guest_RIP_bbstart
sewardj984d9b12010-01-15 10:53:21 +000016626 && jmpDelta < 0
16627 && resteerOkFn( callback_opaque, d64) ) {
16628 /* Speculation: assume this backward branch is taken. So
16629 we need to emit a side-exit to the insn following this
16630 one, on the negation of the condition, and continue at
sewardj0d925b12010-01-17 15:47:01 +000016631 the branch target address (d64). If we wind up back at
16632 the first instruction of the trace, just stop; it's
16633 better to let the IR loop unroller handle that case. */
sewardj984d9b12010-01-15 10:53:21 +000016634 stmt( IRStmt_Exit(
16635 mk_amd64g_calculate_condition(
16636 (AMD64Condcode)(1 ^ (opc - 0x80))),
16637 Ijk_Boring,
16638 IRConst_U64(guest_RIP_bbstart+delta) ) );
16639 dres.whatNext = Dis_ResteerC;
16640 dres.continueAt = d64;
16641 comment = "(assumed taken)";
16642 }
16643 else
16644 if (resteerCisOk
16645 && vex_control.guest_chase_cond
sewardj0d925b12010-01-17 15:47:01 +000016646 && (Addr64)d64 != (Addr64)guest_RIP_bbstart
sewardj984d9b12010-01-15 10:53:21 +000016647 && jmpDelta >= 0
16648 && resteerOkFn( callback_opaque, guest_RIP_bbstart+delta ) ) {
16649 /* Speculation: assume this forward branch is not taken.
16650 So we need to emit a side-exit to d64 (the dest) and
16651 continue disassembling at the insn immediately
16652 following this one. */
16653 stmt( IRStmt_Exit(
sewardj0d925b12010-01-17 15:47:01 +000016654 mk_amd64g_calculate_condition((AMD64Condcode)
16655 (opc - 0x80)),
sewardj984d9b12010-01-15 10:53:21 +000016656 Ijk_Boring,
16657 IRConst_U64(d64) ) );
16658 dres.whatNext = Dis_ResteerC;
16659 dres.continueAt = guest_RIP_bbstart+delta;
16660 comment = "(assumed not taken)";
16661 }
16662 else {
16663 /* Conservative default translation - end the block at
16664 this point. */
16665 jcc_01( (AMD64Condcode)(opc - 0x80),
16666 guest_RIP_bbstart+delta,
16667 d64 );
16668 dres.whatNext = Dis_StopHere;
16669 }
16670 DIP("j%s-32 0x%llx %s\n", name_AMD64Condcode(opc - 0x80), d64, comment);
sewardj1389d4d2005-01-28 13:46:29 +000016671 break;
sewardj984d9b12010-01-15 10:53:21 +000016672 }
sewardj1389d4d2005-01-28 13:46:29 +000016673
sewardjb04a47c2005-08-10 12:27:46 +000016674 /* =-=-=-=-=-=-=-=-=- PREFETCH =-=-=-=-=-=-=-=-=-= */
16675 case 0x0D: /* 0F 0D /0 -- prefetch mem8 */
16676 /* 0F 0D /1 -- prefetchw mem8 */
16677 if (have66orF2orF3(pfx)) goto decode_failure;
16678 modrm = getUChar(delta);
16679 if (epartIsReg(modrm)) goto decode_failure;
16680 if (gregLO3ofRM(modrm) != 0 && gregLO3ofRM(modrm) != 1)
16681 goto decode_failure;
16682
sewardj2e28ac42008-12-04 00:05:12 +000016683 addr = disAMode ( &alen, vbi, pfx, delta, dis_buf, 0 );
sewardjb04a47c2005-08-10 12:27:46 +000016684 delta += alen;
16685
16686 switch (gregLO3ofRM(modrm)) {
16687 case 0: DIP("prefetch %s\n", dis_buf); break;
16688 case 1: DIP("prefetchw %s\n", dis_buf); break;
16689 default: vassert(0); /*NOTREACHED*/
16690 }
16691 break;
16692
sewardj31191072005-02-05 18:24:47 +000016693 /* =-=-=-=-=-=-=-=-=- RDTSC -=-=-=-=-=-=-=-=-=-=-= */
sewardjbc6af532005-08-23 23:16:51 +000016694 case 0x31: { /* RDTSC */
16695 IRTemp val = newTemp(Ity_I64);
16696 IRExpr** args = mkIRExprVec_0();
16697 IRDirty* d = unsafeIRDirty_1_N (
16698 val,
16699 0/*regparms*/,
16700 "amd64g_dirtyhelper_RDTSC",
16701 &amd64g_dirtyhelper_RDTSC,
16702 args
16703 );
16704 if (have66orF2orF3(pfx)) goto decode_failure;
16705 /* execute the dirty call, dumping the result in val. */
16706 stmt( IRStmt_Dirty(d) );
16707 putIRegRDX(4, unop(Iop_64HIto32, mkexpr(val)));
16708 putIRegRAX(4, unop(Iop_64to32, mkexpr(val)));
sewardj31191072005-02-05 18:24:47 +000016709 DIP("rdtsc\n");
16710 break;
sewardjbc6af532005-08-23 23:16:51 +000016711 }
sewardj31191072005-02-05 18:24:47 +000016712
sewardjd20c8852005-01-20 20:04:07 +000016713//.. /* =-=-=-=-=-=-=-=-=- PUSH/POP Sreg =-=-=-=-=-=-=-=-=-= */
16714//..
16715//.. case 0xA1: /* POP %FS */
16716//.. dis_pop_segreg( R_FS, sz ); break;
16717//.. case 0xA9: /* POP %GS */
16718//.. dis_pop_segreg( R_GS, sz ); break;
16719//..
16720//.. case 0xA0: /* PUSH %FS */
16721//.. dis_push_segreg( R_FS, sz ); break;
16722//.. case 0xA8: /* PUSH %GS */
16723//.. dis_push_segreg( R_GS, sz ); break;
sewardj118b23e2005-01-29 02:14:44 +000016724
16725 /* =-=-=-=-=-=-=-=-=- SETcc Eb =-=-=-=-=-=-=-=-=-= */
16726 case 0x90:
16727 case 0x91:
16728 case 0x92: /* set-Bb/set-NAEb (set if below) */
16729 case 0x93: /* set-NBb/set-AEb (set if not below) */
16730 case 0x94: /* set-Zb/set-Eb (set if zero) */
16731 case 0x95: /* set-NZb/set-NEb (set if not zero) */
16732 case 0x96: /* set-BEb/set-NAb (set if below or equal) */
16733 case 0x97: /* set-NBEb/set-Ab (set if not below or equal) */
16734 case 0x98: /* set-Sb (set if negative) */
16735 case 0x99: /* set-Sb (set if not negative) */
16736 case 0x9A: /* set-P (set if parity even) */
16737 case 0x9B: /* set-NP (set if parity odd) */
16738 case 0x9C: /* set-Lb/set-NGEb (set if less) */
16739 case 0x9D: /* set-GEb/set-NLb (set if greater or equal) */
16740 case 0x9E: /* set-LEb/set-NGb (set if less or equal) */
16741 case 0x9F: /* set-Gb/set-NLEb (set if greater) */
sewardj5b470602005-02-27 13:10:48 +000016742 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000016743 t1 = newTemp(Ity_I8);
16744 assign( t1, unop(Iop_1Uto8,mk_amd64g_calculate_condition(opc-0x90)) );
16745 modrm = getUChar(delta);
16746 if (epartIsReg(modrm)) {
16747 delta++;
sewardj5b470602005-02-27 13:10:48 +000016748 putIRegE(1, pfx, modrm, mkexpr(t1));
sewardj118b23e2005-01-29 02:14:44 +000016749 DIP("set%s %s\n", name_AMD64Condcode(opc-0x90),
sewardj5b470602005-02-27 13:10:48 +000016750 nameIRegE(1,pfx,modrm));
sewardj118b23e2005-01-29 02:14:44 +000016751 } else {
sewardj2e28ac42008-12-04 00:05:12 +000016752 addr = disAMode ( &alen, vbi, pfx, delta, dis_buf, 0 );
sewardj5cc00ff2005-03-27 04:48:32 +000016753 delta += alen;
16754 storeLE( mkexpr(addr), mkexpr(t1) );
16755 DIP("set%s %s\n", name_AMD64Condcode(opc-0x90), dis_buf);
sewardj118b23e2005-01-29 02:14:44 +000016756 }
16757 break;
16758
sewardj33ef9c22005-11-04 20:05:57 +000016759 /* =-=-=-=-=-=-=-=-=- SHLD/SHRD -=-=-=-=-=-=-=-=-= */
16760
sewardj1287ab42006-05-12 21:03:48 +000016761 case 0xA4: /* SHLDv imm8,Gv,Ev */
16762 modrm = getUChar(delta);
16763 d64 = delta + lengthAMode(pfx, delta);
16764 vex_sprintf(dis_buf, "$%d", (Int)getUChar(d64));
16765 delta = dis_SHLRD_Gv_Ev (
sewardj2e28ac42008-12-04 00:05:12 +000016766 vbi, pfx, delta, modrm, sz,
sewardj1287ab42006-05-12 21:03:48 +000016767 mkU8(getUChar(d64)), True, /* literal */
16768 dis_buf, True /* left */ );
16769 break;
sewardj33ef9c22005-11-04 20:05:57 +000016770 case 0xA5: /* SHLDv %cl,Gv,Ev */
16771 modrm = getUChar(delta);
16772 delta = dis_SHLRD_Gv_Ev (
sewardj2e28ac42008-12-04 00:05:12 +000016773 vbi, pfx, delta, modrm, sz,
sewardj33ef9c22005-11-04 20:05:57 +000016774 getIRegCL(), False, /* not literal */
16775 "%cl", True /* left */ );
16776 break;
16777
sewardj75ce3652005-11-04 20:49:36 +000016778 case 0xAC: /* SHRDv imm8,Gv,Ev */
16779 modrm = getUChar(delta);
16780 d64 = delta + lengthAMode(pfx, delta);
16781 vex_sprintf(dis_buf, "$%d", (Int)getUChar(d64));
16782 delta = dis_SHLRD_Gv_Ev (
sewardj2e28ac42008-12-04 00:05:12 +000016783 vbi, pfx, delta, modrm, sz,
sewardj75ce3652005-11-04 20:49:36 +000016784 mkU8(getUChar(d64)), True, /* literal */
16785 dis_buf, False /* right */ );
16786 break;
sewardj33ef9c22005-11-04 20:05:57 +000016787 case 0xAD: /* SHRDv %cl,Gv,Ev */
16788 modrm = getUChar(delta);
16789 delta = dis_SHLRD_Gv_Ev (
sewardj2e28ac42008-12-04 00:05:12 +000016790 vbi, pfx, delta, modrm, sz,
sewardj33ef9c22005-11-04 20:05:57 +000016791 getIRegCL(), False, /* not literal */
16792 "%cl", False /* right */);
16793 break;
sewardje1698952005-02-08 15:02:39 +000016794
16795 /* =-=-=-=-=-=-=-=-=- SYSCALL -=-=-=-=-=-=-=-=-=-= */
16796 case 0x05: /* SYSCALL */
sewardj9e6491a2005-07-02 19:24:10 +000016797 guest_RIP_next_mustcheck = True;
16798 guest_RIP_next_assumed = guest_RIP_bbstart + delta;
16799 putIReg64( R_RCX, mkU64(guest_RIP_next_assumed) );
sewardje1698952005-02-08 15:02:39 +000016800 /* It's important that all guest state is up-to-date
16801 at this point. So we declare an end-of-block here, which
16802 forces any cached guest state to be flushed. */
sewardj4fa325a2005-11-03 13:27:24 +000016803 jmp_lit(Ijk_Sys_syscall, guest_RIP_next_assumed);
16804 dres.whatNext = Dis_StopHere;
16805 DIP("syscall\n");
16806 break;
sewardje1698952005-02-08 15:02:39 +000016807
sewardjb4fd2e72005-03-23 13:34:11 +000016808 /* =-=-=-=-=-=-=-=-=- XADD -=-=-=-=-=-=-=-=-=-= */
16809
sewardj0d923d72008-05-13 21:21:16 +000016810 case 0xC0: { /* XADD Gb,Eb */
16811 Bool decode_OK = False;
sewardj2e28ac42008-12-04 00:05:12 +000016812 delta = dis_xadd_G_E ( &decode_OK, vbi, pfx, 1, delta );
sewardj0d923d72008-05-13 21:21:16 +000016813 if (!decode_OK)
16814 goto decode_failure;
16815 break;
16816 }
sewardjb4fd2e72005-03-23 13:34:11 +000016817 case 0xC1: { /* XADD Gv,Ev */
16818 Bool decode_OK = False;
sewardj2e28ac42008-12-04 00:05:12 +000016819 delta = dis_xadd_G_E ( &decode_OK, vbi, pfx, sz, delta );
sewardjb4fd2e72005-03-23 13:34:11 +000016820 if (!decode_OK)
16821 goto decode_failure;
16822 break;
16823 }
16824
sewardj8711f662005-05-09 17:52:56 +000016825 /* =-=-=-=-=-=-=-=-=- MMXery =-=-=-=-=-=-=-=-=-=-= */
16826
sewardj3d8107c2005-05-09 22:23:38 +000016827 case 0x71:
16828 case 0x72:
16829 case 0x73: /* PSLLgg/PSRAgg/PSRLgg mmxreg by imm8 */
16830
16831 case 0x6E: /* MOVD (src)ireg-or-mem, (dst)mmxreg */
16832 case 0x7E: /* MOVD (src)mmxreg, (dst)ireg-or-mem */
sewardj8711f662005-05-09 17:52:56 +000016833 case 0x7F: /* MOVQ (src)mmxreg, (dst)mmxreg-or-mem */
16834 case 0x6F: /* MOVQ (src)mmxreg-or-mem, (dst)mmxreg */
16835
16836 case 0xFC:
16837 case 0xFD:
16838 case 0xFE: /* PADDgg (src)mmxreg-or-mem, (dst)mmxreg */
16839
16840 case 0xEC:
16841 case 0xED: /* PADDSgg (src)mmxreg-or-mem, (dst)mmxreg */
16842
16843 case 0xDC:
16844 case 0xDD: /* PADDUSgg (src)mmxreg-or-mem, (dst)mmxreg */
16845
16846 case 0xF8:
16847 case 0xF9:
16848 case 0xFA: /* PSUBgg (src)mmxreg-or-mem, (dst)mmxreg */
16849
16850 case 0xE8:
16851 case 0xE9: /* PSUBSgg (src)mmxreg-or-mem, (dst)mmxreg */
16852
16853 case 0xD8:
16854 case 0xD9: /* PSUBUSgg (src)mmxreg-or-mem, (dst)mmxreg */
16855
16856 case 0xE5: /* PMULHW (src)mmxreg-or-mem, (dst)mmxreg */
16857 case 0xD5: /* PMULLW (src)mmxreg-or-mem, (dst)mmxreg */
16858
16859 case 0xF5: /* PMADDWD (src)mmxreg-or-mem, (dst)mmxreg */
16860
16861 case 0x74:
16862 case 0x75:
16863 case 0x76: /* PCMPEQgg (src)mmxreg-or-mem, (dst)mmxreg */
16864
16865 case 0x64:
16866 case 0x65:
16867 case 0x66: /* PCMPGTgg (src)mmxreg-or-mem, (dst)mmxreg */
16868
16869 case 0x6B: /* PACKSSDW (src)mmxreg-or-mem, (dst)mmxreg */
16870 case 0x63: /* PACKSSWB (src)mmxreg-or-mem, (dst)mmxreg */
16871 case 0x67: /* PACKUSWB (src)mmxreg-or-mem, (dst)mmxreg */
16872
16873 case 0x68:
16874 case 0x69:
16875 case 0x6A: /* PUNPCKHgg (src)mmxreg-or-mem, (dst)mmxreg */
16876
16877 case 0x60:
16878 case 0x61:
16879 case 0x62: /* PUNPCKLgg (src)mmxreg-or-mem, (dst)mmxreg */
16880
16881 case 0xDB: /* PAND (src)mmxreg-or-mem, (dst)mmxreg */
16882 case 0xDF: /* PANDN (src)mmxreg-or-mem, (dst)mmxreg */
16883 case 0xEB: /* POR (src)mmxreg-or-mem, (dst)mmxreg */
16884 case 0xEF: /* PXOR (src)mmxreg-or-mem, (dst)mmxreg */
16885
16886 case 0xF1: /* PSLLgg (src)mmxreg-or-mem, (dst)mmxreg */
16887 case 0xF2:
16888 case 0xF3:
16889
16890 case 0xD1: /* PSRLgg (src)mmxreg-or-mem, (dst)mmxreg */
16891 case 0xD2:
16892 case 0xD3:
16893
16894 case 0xE1: /* PSRAgg (src)mmxreg-or-mem, (dst)mmxreg */
16895 case 0xE2:
16896 {
sewardj270def42005-07-03 01:03:01 +000016897 Long delta0 = delta-1;
sewardj8711f662005-05-09 17:52:56 +000016898 Bool decode_OK = False;
16899
16900 /* If sz==2 this is SSE, and we assume sse idec has
16901 already spotted those cases by now. */
sewardj3d8107c2005-05-09 22:23:38 +000016902 if (sz != 4 && sz != 8)
sewardj8711f662005-05-09 17:52:56 +000016903 goto decode_failure;
16904 if (have66orF2orF3(pfx))
16905 goto decode_failure;
16906
sewardj2e28ac42008-12-04 00:05:12 +000016907 delta = dis_MMX ( &decode_OK, vbi, pfx, sz, delta-1 );
sewardj8711f662005-05-09 17:52:56 +000016908 if (!decode_OK) {
16909 delta = delta0;
16910 goto decode_failure;
16911 }
16912 break;
16913 }
16914
sewardjae84d782006-04-13 22:06:35 +000016915 case 0x0E: /* FEMMS */
sewardj8711f662005-05-09 17:52:56 +000016916 case 0x77: /* EMMS */
16917 if (sz != 4)
16918 goto decode_failure;
16919 do_EMMS_preamble();
sewardjae84d782006-04-13 22:06:35 +000016920 DIP("{f}emms\n");
sewardj8711f662005-05-09 17:52:56 +000016921 break;
sewardj3ca55a12005-01-27 16:06:23 +000016922
16923 /* =-=-=-=-=-=-=-=-=- unimp2 =-=-=-=-=-=-=-=-=-=-= */
16924
16925 default:
16926 goto decode_failure;
16927 } /* switch (opc) for the 2-byte opcodes */
16928 goto decode_success;
16929 } /* case 0x0F: of primary opcode */
sewardjdf0e0022005-01-25 15:48:43 +000016930
16931 /* ------------------------ ??? ------------------------ */
16932
16933 default:
16934 decode_failure:
16935 /* All decode failures end up here. */
16936 vex_printf("vex amd64->IR: unhandled instruction bytes: "
sewardjd166e282008-02-06 11:42:45 +000016937 "0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
sewardj8c332e22005-01-28 01:36:56 +000016938 (Int)getUChar(delta_start+0),
16939 (Int)getUChar(delta_start+1),
16940 (Int)getUChar(delta_start+2),
sewardjd166e282008-02-06 11:42:45 +000016941 (Int)getUChar(delta_start+3),
16942 (Int)getUChar(delta_start+4),
16943 (Int)getUChar(delta_start+5) );
sewardjdf0e0022005-01-25 15:48:43 +000016944
16945 /* Tell the dispatcher that this insn cannot be decoded, and so has
16946 not been executed, and (is currently) the next to be executed.
16947 RIP should be up-to-date since it made so at the start of each
16948 insn, but nevertheless be paranoid and update it again right
16949 now. */
sewardj9e6491a2005-07-02 19:24:10 +000016950 stmt( IRStmt_Put( OFFB_RIP, mkU64(guest_RIP_curr_instr) ) );
16951 jmp_lit(Ijk_NoDecode, guest_RIP_curr_instr);
16952 dres.whatNext = Dis_StopHere;
16953 dres.len = 0;
sewardje9d8a262009-07-01 08:06:34 +000016954 /* We also need to say that a CAS is not expected now, regardless
16955 of what it might have been set to at the start of the function,
16956 since the IR that we've emitted just above (to synthesis a
16957 SIGILL) does not involve any CAS, and presumably no other IR has
16958 been emitted for this (non-decoded) insn. */
16959 *expect_CAS = False;
sewardj9e6491a2005-07-02 19:24:10 +000016960 return dres;
sewardjdf0e0022005-01-25 15:48:43 +000016961
16962 } /* switch (opc) for the main (primary) opcode switch. */
16963
16964 decode_success:
16965 /* All decode successes end up here. */
16966 DIP("\n");
sewardj9e6491a2005-07-02 19:24:10 +000016967 dres.len = (Int)toUInt(delta - delta_start);
16968 return dres;
sewardjdf0e0022005-01-25 15:48:43 +000016969}
16970
16971#undef DIP
16972#undef DIS
sewardjd20c8852005-01-20 20:04:07 +000016973
sewardj9e6491a2005-07-02 19:24:10 +000016974
16975/*------------------------------------------------------------*/
16976/*--- Top-level fn ---*/
16977/*------------------------------------------------------------*/
16978
16979/* Disassemble a single instruction into IR. The instruction
16980 is located in host memory at &guest_code[delta]. */
16981
sewardjdd40fdf2006-12-24 02:20:24 +000016982DisResult disInstr_AMD64 ( IRSB* irsb_IN,
sewardj9e6491a2005-07-02 19:24:10 +000016983 Bool put_IP,
sewardjc716aea2006-01-17 01:48:46 +000016984 Bool (*resteerOkFn) ( void*, Addr64 ),
sewardj984d9b12010-01-15 10:53:21 +000016985 Bool resteerCisOk,
sewardjc716aea2006-01-17 01:48:46 +000016986 void* callback_opaque,
sewardj9e6491a2005-07-02 19:24:10 +000016987 UChar* guest_code_IN,
16988 Long delta,
16989 Addr64 guest_IP,
sewardja5f55da2006-04-30 23:37:32 +000016990 VexArch guest_arch,
sewardj9e6491a2005-07-02 19:24:10 +000016991 VexArchInfo* archinfo,
sewardjdd40fdf2006-12-24 02:20:24 +000016992 VexAbiInfo* abiinfo,
sewardj9e6491a2005-07-02 19:24:10 +000016993 Bool host_bigendian_IN )
16994{
sewardje9d8a262009-07-01 08:06:34 +000016995 Int i, x1, x2;
16996 Bool expect_CAS, has_CAS;
sewardj9e6491a2005-07-02 19:24:10 +000016997 DisResult dres;
16998
16999 /* Set globals (see top of this file) */
sewardja5f55da2006-04-30 23:37:32 +000017000 vassert(guest_arch == VexArchAMD64);
sewardj9e6491a2005-07-02 19:24:10 +000017001 guest_code = guest_code_IN;
sewardjdd40fdf2006-12-24 02:20:24 +000017002 irsb = irsb_IN;
sewardj9e6491a2005-07-02 19:24:10 +000017003 host_is_bigendian = host_bigendian_IN;
17004 guest_RIP_curr_instr = guest_IP;
17005 guest_RIP_bbstart = guest_IP - delta;
17006
17007 /* We'll consult these after doing disInstr_AMD64_WRK. */
17008 guest_RIP_next_assumed = 0;
17009 guest_RIP_next_mustcheck = False;
17010
sewardje9d8a262009-07-01 08:06:34 +000017011 x1 = irsb_IN->stmts_used;
17012 expect_CAS = False;
17013 dres = disInstr_AMD64_WRK ( &expect_CAS, put_IP, resteerOkFn,
sewardj984d9b12010-01-15 10:53:21 +000017014 resteerCisOk,
sewardje9d8a262009-07-01 08:06:34 +000017015 callback_opaque,
sewardjdd40fdf2006-12-24 02:20:24 +000017016 delta, archinfo, abiinfo );
sewardje9d8a262009-07-01 08:06:34 +000017017 x2 = irsb_IN->stmts_used;
17018 vassert(x2 >= x1);
sewardj9e6491a2005-07-02 19:24:10 +000017019
17020 /* If disInstr_AMD64_WRK tried to figure out the next rip, check it
17021 got it right. Failure of this assertion is serious and denotes
17022 a bug in disInstr. */
17023 if (guest_RIP_next_mustcheck
17024 && guest_RIP_next_assumed != guest_RIP_curr_instr + dres.len) {
17025 vex_printf("\n");
17026 vex_printf("assumed next %%rip = 0x%llx\n",
17027 guest_RIP_next_assumed );
17028 vex_printf(" actual next %%rip = 0x%llx\n",
17029 guest_RIP_curr_instr + dres.len );
sewardje9d8a262009-07-01 08:06:34 +000017030 vpanic("disInstr_AMD64: disInstr miscalculated next %rip");
17031 }
17032
17033 /* See comment at the top of disInstr_AMD64_WRK for meaning of
17034 expect_CAS. Here, we (sanity-)check for the presence/absence of
17035 IRCAS as directed by the returned expect_CAS value. */
17036 has_CAS = False;
17037 for (i = x1; i < x2; i++) {
17038 if (irsb_IN->stmts[i]->tag == Ist_CAS)
17039 has_CAS = True;
17040 }
17041
17042 if (expect_CAS != has_CAS) {
17043 /* inconsistency detected. re-disassemble the instruction so as
17044 to generate a useful error message; then assert. */
17045 vex_traceflags |= VEX_TRACE_FE;
17046 dres = disInstr_AMD64_WRK ( &expect_CAS, put_IP, resteerOkFn,
sewardj984d9b12010-01-15 10:53:21 +000017047 resteerCisOk,
sewardje9d8a262009-07-01 08:06:34 +000017048 callback_opaque,
17049 delta, archinfo, abiinfo );
17050 for (i = x1; i < x2; i++) {
17051 vex_printf("\t\t");
17052 ppIRStmt(irsb_IN->stmts[i]);
17053 vex_printf("\n");
17054 }
17055 /* Failure of this assertion is serious and denotes a bug in
17056 disInstr. */
17057 vpanic("disInstr_AMD64: inconsistency in LOCK prefix handling");
sewardj9e6491a2005-07-02 19:24:10 +000017058 }
17059
17060 return dres;
17061}
17062
17063
17064
sewardjd20c8852005-01-20 20:04:07 +000017065/*--------------------------------------------------------------------*/
sewardjcef7d3e2009-07-02 12:21:59 +000017066/*--- end guest_amd64_toIR.c ---*/
sewardjd20c8852005-01-20 20:04:07 +000017067/*--------------------------------------------------------------------*/