blob: 0b4748fe98bde988da20bf5d2f62e19e80d33296 [file] [log] [blame]
sewardjd20c8852005-01-20 20:04:07 +00001
2/*--------------------------------------------------------------------*/
sewardj752f9062010-05-03 21:38:49 +00003/*--- begin guest_amd64_toIR.c ---*/
sewardjd20c8852005-01-20 20:04:07 +00004/*--------------------------------------------------------------------*/
5
6/*
sewardj752f9062010-05-03 21:38:49 +00007 This file is part of Valgrind, a dynamic binary instrumentation
8 framework.
sewardjd20c8852005-01-20 20:04:07 +00009
sewardj752f9062010-05-03 21:38:49 +000010 Copyright (C) 2004-2010 OpenWorks LLP
11 info@open-works.net
sewardjd20c8852005-01-20 20:04:07 +000012
sewardj752f9062010-05-03 21:38:49 +000013 This program is free software; you can redistribute it and/or
14 modify it under the terms of the GNU General Public License as
15 published by the Free Software Foundation; either version 2 of the
16 License, or (at your option) any later version.
sewardjd20c8852005-01-20 20:04:07 +000017
sewardj752f9062010-05-03 21:38:49 +000018 This program is distributed in the hope that it will be useful, but
19 WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 General Public License for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software
25 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
sewardj7bd6ffe2005-08-03 16:07:36 +000026 02110-1301, USA.
27
sewardj752f9062010-05-03 21:38:49 +000028 The GNU General Public License is contained in the file COPYING.
sewardjd20c8852005-01-20 20:04:07 +000029
30 Neither the names of the U.S. Department of Energy nor the
31 University of California nor the names of its contributors may be
32 used to endorse or promote products derived from this software
33 without prior written permission.
sewardjd20c8852005-01-20 20:04:07 +000034*/
35
sewardje9d8a262009-07-01 08:06:34 +000036/* Translates AMD64 code to IR. */
sewardj9ff93bc2005-03-23 11:25:12 +000037
sewardj820611e2005-08-24 10:56:01 +000038/* TODO:
39
40 All Puts to CC_OP/CC_DEP1/CC_DEP2/CC_NDEP should really be checked
41 to ensure a 64-bit value is being written.
42
sewardje9d8a262009-07-01 08:06:34 +000043 x87 FP Limitations:
44
45 * all arithmetic done at 64 bits
46
47 * no FP exceptions, except for handling stack over/underflow
48
49 * FP rounding mode observed only for float->int conversions and
50 int->float conversions which could lose accuracy, and for
51 float-to-float rounding. For all other operations,
52 round-to-nearest is used, regardless.
53
54 * FP sin/cos/tan/sincos: C2 flag is always cleared. IOW the
55 simulation claims the argument is in-range (-2^63 <= arg <= 2^63)
56 even when it isn't.
57
58 * some of the FCOM cases could do with testing -- not convinced
59 that the args are the right way round.
60
61 * FSAVE does not re-initialise the FPU; it should do
62
63 * FINIT not only initialises the FPU environment, it also zeroes
64 all the FP registers. It should leave the registers unchanged.
65
66 RDTSC returns zero, always.
67
68 SAHF should cause eflags[1] == 1, and in fact it produces 0. As
69 per Intel docs this bit has no meaning anyway. Since PUSHF is the
70 only way to observe eflags[1], a proper fix would be to make that
71 bit be set by PUSHF.
72
73 This module uses global variables and so is not MT-safe (if that
74 should ever become relevant).
sewardj820611e2005-08-24 10:56:01 +000075*/
sewardj44d494d2005-01-20 20:26:33 +000076
sewardj42561ef2005-11-04 14:18:31 +000077/* Notes re address size overrides (0x67).
78
79 According to the AMD documentation (24594 Rev 3.09, Sept 2003,
80 "AMD64 Architecture Programmer's Manual Volume 3: General-Purpose
81 and System Instructions"), Section 1.2.3 ("Address-Size Override
82 Prefix"):
83
84 0x67 applies to all explicit memory references, causing the top
85 32 bits of the effective address to become zero.
86
87 0x67 has no effect on stack references (push/pop); these always
88 use a 64-bit address.
89
90 0x67 changes the interpretation of instructions which implicitly
91 reference RCX/RSI/RDI, so that in fact ECX/ESI/EDI are used
92 instead. These are:
93
94 cmp{s,sb,sw,sd,sq}
95 in{s,sb,sw,sd}
96 jcxz, jecxz, jrcxz
97 lod{s,sb,sw,sd,sq}
98 loop{,e,bz,be,z}
99 mov{s,sb,sw,sd,sq}
100 out{s,sb,sw,sd}
101 rep{,e,ne,nz}
102 sca{s,sb,sw,sd,sq}
103 sto{s,sb,sw,sd,sq}
104 xlat{,b} */
105
sewardjce02aa72006-01-12 12:27:58 +0000106/* "Special" instructions.
107
108 This instruction decoder can decode three special instructions
109 which mean nothing natively (are no-ops as far as regs/mem are
110 concerned) but have meaning for supporting Valgrind. A special
111 instruction is flagged by the 16-byte preamble 48C1C703 48C1C70D
112 48C1C73D 48C1C733 (in the standard interpretation, that means: rolq
113 $3, %rdi; rolq $13, %rdi; rolq $61, %rdi; rolq $51, %rdi).
114 Following that, one of the following 3 are allowed (standard
115 interpretation in parentheses):
116
117 4887DB (xchgq %rbx,%rbx) %RDX = client_request ( %RAX )
118 4887C9 (xchgq %rcx,%rcx) %RAX = guest_NRADDR
119 4887D2 (xchgq %rdx,%rdx) call-noredir *%RAX
120
121 Any other bytes following the 16-byte preamble are illegal and
122 constitute a failure in instruction decoding. This all assumes
123 that the preamble will never occur except in specific code
124 fragments designed for Valgrind to catch.
125
sewardje9d8a262009-07-01 08:06:34 +0000126 No prefixes may precede a "Special" instruction.
127*/
sewardjce02aa72006-01-12 12:27:58 +0000128
sewardje9d8a262009-07-01 08:06:34 +0000129/* casLE (implementation of lock-prefixed insns) and rep-prefixed
130 insns: the side-exit back to the start of the insn is done with
131 Ijk_Boring. This is quite wrong, it should be done with
132 Ijk_NoRedir, since otherwise the side exit, which is intended to
133 restart the instruction for whatever reason, could go somewhere
134 entirely else. Doing it right (with Ijk_NoRedir jumps) would make
135 no-redir jumps performance critical, at least for rep-prefixed
136 instructions, since all iterations thereof would involve such a
137 jump. It's not such a big deal with casLE since the side exit is
138 only taken if the CAS fails, that is, the location is contended,
139 which is relatively unlikely.
sewardj1fb8c922009-07-12 12:56:53 +0000140
141 Note also, the test for CAS success vs failure is done using
142 Iop_CasCmp{EQ,NE}{8,16,32,64} rather than the ordinary
143 Iop_Cmp{EQ,NE} equivalents. This is so as to tell Memcheck that it
144 shouldn't definedness-check these comparisons. See
145 COMMENT_ON_CasCmpEQ in memcheck/mc_translate.c for
146 background/rationale.
sewardje9d8a262009-07-01 08:06:34 +0000147*/
148
149/* LOCK prefixed instructions. These are translated using IR-level
150 CAS statements (IRCAS) and are believed to preserve atomicity, even
151 from the point of view of some other process racing against a
152 simulated one (presumably they communicate via a shared memory
153 segment).
154
155 Handlers which are aware of LOCK prefixes are:
156 dis_op2_G_E (add, or, adc, sbb, and, sub, xor)
157 dis_cmpxchg_G_E (cmpxchg)
158 dis_Grp1 (add, or, adc, sbb, and, sub, xor)
159 dis_Grp3 (not, neg)
160 dis_Grp4 (inc, dec)
161 dis_Grp5 (inc, dec)
162 dis_Grp8_Imm (bts, btc, btr)
163 dis_bt_G_E (bts, btc, btr)
164 dis_xadd_G_E (xadd)
165*/
166
sewardj44d494d2005-01-20 20:26:33 +0000167
168#include "libvex_basictypes.h"
169#include "libvex_ir.h"
170#include "libvex.h"
171#include "libvex_guest_amd64.h"
172
sewardjcef7d3e2009-07-02 12:21:59 +0000173#include "main_util.h"
174#include "main_globals.h"
175#include "guest_generic_bb_to_IR.h"
176#include "guest_generic_x87.h"
177#include "guest_amd64_defs.h"
sewardj44d494d2005-01-20 20:26:33 +0000178
179
sewardjecb94892005-01-21 14:26:37 +0000180/*------------------------------------------------------------*/
181/*--- Globals ---*/
182/*------------------------------------------------------------*/
183
sewardj9e6491a2005-07-02 19:24:10 +0000184/* These are set at the start of the translation of an insn, right
185 down in disInstr_AMD64, so that we don't have to pass them around
186 endlessly. They are all constant during the translation of any
187 given insn. */
sewardj4b744762005-02-07 15:02:25 +0000188
sewardjecb94892005-01-21 14:26:37 +0000189/* These are set at the start of the translation of a BB, so
190 that we don't have to pass them around endlessly. */
191
192/* We need to know this to do sub-register accesses correctly. */
sewardjecb94892005-01-21 14:26:37 +0000193static Bool host_is_bigendian;
194
sewardj9e6491a2005-07-02 19:24:10 +0000195/* Pointer to the guest code area (points to start of BB, not to the
196 insn being processed). */
sewardjb3a04292005-01-21 20:33:44 +0000197static UChar* guest_code;
198
sewardjdf0e0022005-01-25 15:48:43 +0000199/* The guest address corresponding to guest_code[0]. */
sewardj9e6491a2005-07-02 19:24:10 +0000200static Addr64 guest_RIP_bbstart;
sewardj4b744762005-02-07 15:02:25 +0000201
sewardjb3a04292005-01-21 20:33:44 +0000202/* The guest address for the instruction currently being
203 translated. */
sewardj9e6491a2005-07-02 19:24:10 +0000204static Addr64 guest_RIP_curr_instr;
sewardjecb94892005-01-21 14:26:37 +0000205
sewardjdd40fdf2006-12-24 02:20:24 +0000206/* The IRSB* into which we're generating code. */
207static IRSB* irsb;
sewardjecb94892005-01-21 14:26:37 +0000208
sewardj4b744762005-02-07 15:02:25 +0000209/* For ensuring that %rip-relative addressing is done right. A read
210 of %rip generates the address of the next instruction. It may be
211 that we don't conveniently know that inside disAMode(). For sanity
212 checking, if the next insn %rip is needed, we make a guess at what
213 it is, record that guess here, and set the accompanying Bool to
214 indicate that -- after this insn's decode is finished -- that guess
215 needs to be checked. */
216
217/* At the start of each insn decode, is set to (0, False).
218 After the decode, if _mustcheck is now True, _assumed is
219 checked. */
220
sewardj9e6491a2005-07-02 19:24:10 +0000221static Addr64 guest_RIP_next_assumed;
222static Bool guest_RIP_next_mustcheck;
sewardj4b744762005-02-07 15:02:25 +0000223
224
sewardjecb94892005-01-21 14:26:37 +0000225/*------------------------------------------------------------*/
226/*--- Helpers for constructing IR. ---*/
227/*------------------------------------------------------------*/
228
sewardjb3a04292005-01-21 20:33:44 +0000229/* Generate a new temporary of the given type. */
230static IRTemp newTemp ( IRType ty )
231{
sewardj496a58d2005-03-20 18:44:44 +0000232 vassert(isPlausibleIRType(ty));
sewardjdd40fdf2006-12-24 02:20:24 +0000233 return newIRTemp( irsb->tyenv, ty );
sewardjb3a04292005-01-21 20:33:44 +0000234}
235
sewardjdd40fdf2006-12-24 02:20:24 +0000236/* Add a statement to the list held by "irsb". */
sewardjecb94892005-01-21 14:26:37 +0000237static void stmt ( IRStmt* st )
238{
sewardjdd40fdf2006-12-24 02:20:24 +0000239 addStmtToIRSB( irsb, st );
sewardjecb94892005-01-21 14:26:37 +0000240}
sewardjb3a04292005-01-21 20:33:44 +0000241
242/* Generate a statement "dst := e". */
243static void assign ( IRTemp dst, IRExpr* e )
244{
sewardjdd40fdf2006-12-24 02:20:24 +0000245 stmt( IRStmt_WrTmp(dst, e) );
sewardjb3a04292005-01-21 20:33:44 +0000246}
247
sewardjecb94892005-01-21 14:26:37 +0000248static IRExpr* unop ( IROp op, IRExpr* a )
249{
250 return IRExpr_Unop(op, a);
251}
252
sewardjb3a04292005-01-21 20:33:44 +0000253static IRExpr* binop ( IROp op, IRExpr* a1, IRExpr* a2 )
254{
255 return IRExpr_Binop(op, a1, a2);
256}
257
sewardj4796d662006-02-05 16:06:26 +0000258static IRExpr* triop ( IROp op, IRExpr* a1, IRExpr* a2, IRExpr* a3 )
259{
260 return IRExpr_Triop(op, a1, a2, a3);
261}
262
sewardjdf0e0022005-01-25 15:48:43 +0000263static IRExpr* mkexpr ( IRTemp tmp )
264{
sewardjdd40fdf2006-12-24 02:20:24 +0000265 return IRExpr_RdTmp(tmp);
sewardjdf0e0022005-01-25 15:48:43 +0000266}
sewardjb3a04292005-01-21 20:33:44 +0000267
sewardj3ca55a12005-01-27 16:06:23 +0000268static IRExpr* mkU8 ( ULong i )
sewardjb3a04292005-01-21 20:33:44 +0000269{
270 vassert(i < 256);
sewardj3ca55a12005-01-27 16:06:23 +0000271 return IRExpr_Const(IRConst_U8( (UChar)i ));
sewardjb3a04292005-01-21 20:33:44 +0000272}
273
sewardj5e525292005-01-28 15:13:10 +0000274static IRExpr* mkU16 ( ULong i )
275{
276 vassert(i < 0x10000ULL);
277 return IRExpr_Const(IRConst_U16( (UShort)i ));
278}
sewardj3ca55a12005-01-27 16:06:23 +0000279
280static IRExpr* mkU32 ( ULong i )
281{
282 vassert(i < 0x100000000ULL);
283 return IRExpr_Const(IRConst_U32( (UInt)i ));
284}
sewardjb3a04292005-01-21 20:33:44 +0000285
286static IRExpr* mkU64 ( ULong i )
287{
288 return IRExpr_Const(IRConst_U64(i));
289}
sewardjecb94892005-01-21 14:26:37 +0000290
sewardj3ca55a12005-01-27 16:06:23 +0000291static IRExpr* mkU ( IRType ty, ULong i )
292{
293 switch (ty) {
294 case Ity_I8: return mkU8(i);
sewardj5e525292005-01-28 15:13:10 +0000295 case Ity_I16: return mkU16(i);
sewardj3ca55a12005-01-27 16:06:23 +0000296 case Ity_I32: return mkU32(i);
297 case Ity_I64: return mkU64(i);
298 default: vpanic("mkU(amd64)");
299 }
300}
301
sewardj5e525292005-01-28 15:13:10 +0000302static void storeLE ( IRExpr* addr, IRExpr* data )
303{
sewardje768e922009-11-26 17:17:37 +0000304 stmt( IRStmt_Store(Iend_LE, addr, data) );
sewardj5e525292005-01-28 15:13:10 +0000305}
306
sewardje768e922009-11-26 17:17:37 +0000307static IRExpr* loadLE ( IRType ty, IRExpr* addr )
sewardj5e525292005-01-28 15:13:10 +0000308{
sewardje768e922009-11-26 17:17:37 +0000309 return IRExpr_Load(Iend_LE, ty, addr);
sewardj5e525292005-01-28 15:13:10 +0000310}
311
312static IROp mkSizedOp ( IRType ty, IROp op8 )
313{
314 vassert(op8 == Iop_Add8 || op8 == Iop_Sub8
315 || op8 == Iop_Mul8
316 || op8 == Iop_Or8 || op8 == Iop_And8 || op8 == Iop_Xor8
317 || op8 == Iop_Shl8 || op8 == Iop_Shr8 || op8 == Iop_Sar8
318 || op8 == Iop_CmpEQ8 || op8 == Iop_CmpNE8
sewardj1fb8c922009-07-12 12:56:53 +0000319 || op8 == Iop_CasCmpNE8
sewardj5e525292005-01-28 15:13:10 +0000320 || op8 == Iop_Not8 );
321 switch (ty) {
322 case Ity_I8: return 0 +op8;
323 case Ity_I16: return 1 +op8;
324 case Ity_I32: return 2 +op8;
325 case Ity_I64: return 3 +op8;
326 default: vpanic("mkSizedOp(amd64)");
327 }
328}
329
330static
331IRExpr* doScalarWidening ( Int szSmall, Int szBig, Bool signd, IRExpr* src )
332{
333 if (szSmall == 1 && szBig == 4) {
334 return unop(signd ? Iop_8Sto32 : Iop_8Uto32, src);
335 }
336 if (szSmall == 1 && szBig == 2) {
337 return unop(signd ? Iop_8Sto16 : Iop_8Uto16, src);
338 }
339 if (szSmall == 2 && szBig == 4) {
340 return unop(signd ? Iop_16Sto32 : Iop_16Uto32, src);
341 }
342 if (szSmall == 1 && szBig == 8 && !signd) {
sewardje58967e2005-04-27 11:50:56 +0000343 return unop(Iop_8Uto64, src);
sewardj5e525292005-01-28 15:13:10 +0000344 }
sewardj03b07cc2005-01-31 18:09:43 +0000345 if (szSmall == 1 && szBig == 8 && signd) {
sewardje58967e2005-04-27 11:50:56 +0000346 return unop(Iop_8Sto64, src);
sewardj03b07cc2005-01-31 18:09:43 +0000347 }
sewardj5e525292005-01-28 15:13:10 +0000348 if (szSmall == 2 && szBig == 8 && !signd) {
sewardje58967e2005-04-27 11:50:56 +0000349 return unop(Iop_16Uto64, src);
sewardj5e525292005-01-28 15:13:10 +0000350 }
sewardj03b07cc2005-01-31 18:09:43 +0000351 if (szSmall == 2 && szBig == 8 && signd) {
sewardje58967e2005-04-27 11:50:56 +0000352 return unop(Iop_16Sto64, src);
sewardj03b07cc2005-01-31 18:09:43 +0000353 }
sewardj5e525292005-01-28 15:13:10 +0000354 vpanic("doScalarWidening(amd64)");
355}
356
357
sewardjecb94892005-01-21 14:26:37 +0000358
359/*------------------------------------------------------------*/
360/*--- Debugging output ---*/
361/*------------------------------------------------------------*/
362
sewardjb3a04292005-01-21 20:33:44 +0000363/* Bomb out if we can't handle something. */
364__attribute__ ((noreturn))
365static void unimplemented ( HChar* str )
366{
367 vex_printf("amd64toIR: unimplemented feature\n");
368 vpanic(str);
369}
370
sewardjecb94892005-01-21 14:26:37 +0000371#define DIP(format, args...) \
sewardj9e6491a2005-07-02 19:24:10 +0000372 if (vex_traceflags & VEX_TRACE_FE) \
sewardjecb94892005-01-21 14:26:37 +0000373 vex_printf(format, ## args)
374
375#define DIS(buf, format, args...) \
sewardj9e6491a2005-07-02 19:24:10 +0000376 if (vex_traceflags & VEX_TRACE_FE) \
sewardjecb94892005-01-21 14:26:37 +0000377 vex_sprintf(buf, format, ## args)
378
379
380/*------------------------------------------------------------*/
381/*--- Offsets of various parts of the amd64 guest state. ---*/
382/*------------------------------------------------------------*/
383
384#define OFFB_RAX offsetof(VexGuestAMD64State,guest_RAX)
385#define OFFB_RBX offsetof(VexGuestAMD64State,guest_RBX)
386#define OFFB_RCX offsetof(VexGuestAMD64State,guest_RCX)
387#define OFFB_RDX offsetof(VexGuestAMD64State,guest_RDX)
388#define OFFB_RSP offsetof(VexGuestAMD64State,guest_RSP)
389#define OFFB_RBP offsetof(VexGuestAMD64State,guest_RBP)
390#define OFFB_RSI offsetof(VexGuestAMD64State,guest_RSI)
391#define OFFB_RDI offsetof(VexGuestAMD64State,guest_RDI)
392#define OFFB_R8 offsetof(VexGuestAMD64State,guest_R8)
393#define OFFB_R9 offsetof(VexGuestAMD64State,guest_R9)
394#define OFFB_R10 offsetof(VexGuestAMD64State,guest_R10)
395#define OFFB_R11 offsetof(VexGuestAMD64State,guest_R11)
396#define OFFB_R12 offsetof(VexGuestAMD64State,guest_R12)
397#define OFFB_R13 offsetof(VexGuestAMD64State,guest_R13)
398#define OFFB_R14 offsetof(VexGuestAMD64State,guest_R14)
399#define OFFB_R15 offsetof(VexGuestAMD64State,guest_R15)
400
401#define OFFB_RIP offsetof(VexGuestAMD64State,guest_RIP)
402
sewardja6b93d12005-02-17 09:28:28 +0000403#define OFFB_FS_ZERO offsetof(VexGuestAMD64State,guest_FS_ZERO)
sewardjd660d412008-12-03 21:29:59 +0000404#define OFFB_GS_0x60 offsetof(VexGuestAMD64State,guest_GS_0x60)
sewardja6b93d12005-02-17 09:28:28 +0000405
sewardjecb94892005-01-21 14:26:37 +0000406#define OFFB_CC_OP offsetof(VexGuestAMD64State,guest_CC_OP)
407#define OFFB_CC_DEP1 offsetof(VexGuestAMD64State,guest_CC_DEP1)
408#define OFFB_CC_DEP2 offsetof(VexGuestAMD64State,guest_CC_DEP2)
409#define OFFB_CC_NDEP offsetof(VexGuestAMD64State,guest_CC_NDEP)
410
sewardj8d965312005-02-25 02:48:47 +0000411#define OFFB_FPREGS offsetof(VexGuestAMD64State,guest_FPREG[0])
412#define OFFB_FPTAGS offsetof(VexGuestAMD64State,guest_FPTAG[0])
sewardjd0a12df2005-02-10 02:07:43 +0000413#define OFFB_DFLAG offsetof(VexGuestAMD64State,guest_DFLAG)
sewardj85520e42005-02-19 15:22:38 +0000414#define OFFB_IDFLAG offsetof(VexGuestAMD64State,guest_IDFLAG)
sewardj8d965312005-02-25 02:48:47 +0000415#define OFFB_FTOP offsetof(VexGuestAMD64State,guest_FTOP)
sewardj25a85812005-05-08 23:03:48 +0000416#define OFFB_FC3210 offsetof(VexGuestAMD64State,guest_FC3210)
sewardjc49ce232005-02-25 13:03:03 +0000417#define OFFB_FPROUND offsetof(VexGuestAMD64State,guest_FPROUND)
sewardjd20c8852005-01-20 20:04:07 +0000418//..
419//.. #define OFFB_CS offsetof(VexGuestX86State,guest_CS)
420//.. #define OFFB_DS offsetof(VexGuestX86State,guest_DS)
421//.. #define OFFB_ES offsetof(VexGuestX86State,guest_ES)
422//.. #define OFFB_FS offsetof(VexGuestX86State,guest_FS)
423//.. #define OFFB_GS offsetof(VexGuestX86State,guest_GS)
424//.. #define OFFB_SS offsetof(VexGuestX86State,guest_SS)
425//.. #define OFFB_LDT offsetof(VexGuestX86State,guest_LDT)
426//.. #define OFFB_GDT offsetof(VexGuestX86State,guest_GDT)
sewardj1001dc42005-02-21 08:25:55 +0000427
428#define OFFB_SSEROUND offsetof(VexGuestAMD64State,guest_SSEROUND)
429#define OFFB_XMM0 offsetof(VexGuestAMD64State,guest_XMM0)
430#define OFFB_XMM1 offsetof(VexGuestAMD64State,guest_XMM1)
431#define OFFB_XMM2 offsetof(VexGuestAMD64State,guest_XMM2)
432#define OFFB_XMM3 offsetof(VexGuestAMD64State,guest_XMM3)
433#define OFFB_XMM4 offsetof(VexGuestAMD64State,guest_XMM4)
434#define OFFB_XMM5 offsetof(VexGuestAMD64State,guest_XMM5)
435#define OFFB_XMM6 offsetof(VexGuestAMD64State,guest_XMM6)
436#define OFFB_XMM7 offsetof(VexGuestAMD64State,guest_XMM7)
437#define OFFB_XMM8 offsetof(VexGuestAMD64State,guest_XMM8)
438#define OFFB_XMM9 offsetof(VexGuestAMD64State,guest_XMM9)
439#define OFFB_XMM10 offsetof(VexGuestAMD64State,guest_XMM10)
440#define OFFB_XMM11 offsetof(VexGuestAMD64State,guest_XMM11)
441#define OFFB_XMM12 offsetof(VexGuestAMD64State,guest_XMM12)
442#define OFFB_XMM13 offsetof(VexGuestAMD64State,guest_XMM13)
443#define OFFB_XMM14 offsetof(VexGuestAMD64State,guest_XMM14)
444#define OFFB_XMM15 offsetof(VexGuestAMD64State,guest_XMM15)
445
sewardjbcbb9de2005-03-27 02:22:32 +0000446#define OFFB_EMWARN offsetof(VexGuestAMD64State,guest_EMWARN)
sewardj3e616e62006-01-07 22:58:54 +0000447#define OFFB_TISTART offsetof(VexGuestAMD64State,guest_TISTART)
448#define OFFB_TILEN offsetof(VexGuestAMD64State,guest_TILEN)
sewardjdf0e0022005-01-25 15:48:43 +0000449
sewardjce02aa72006-01-12 12:27:58 +0000450#define OFFB_NRADDR offsetof(VexGuestAMD64State,guest_NRADDR)
451
sewardjdf0e0022005-01-25 15:48:43 +0000452
453/*------------------------------------------------------------*/
sewardjecb94892005-01-21 14:26:37 +0000454/*--- Helper bits and pieces for deconstructing the ---*/
455/*--- amd64 insn stream. ---*/
456/*------------------------------------------------------------*/
457
458/* This is the AMD64 register encoding -- integer regs. */
459#define R_RAX 0
460#define R_RCX 1
461#define R_RDX 2
462#define R_RBX 3
463#define R_RSP 4
464#define R_RBP 5
465#define R_RSI 6
466#define R_RDI 7
467#define R_R8 8
468#define R_R9 9
469#define R_R10 10
470#define R_R11 11
471#define R_R12 12
472#define R_R13 13
473#define R_R14 14
474#define R_R15 15
475
sewardjd20c8852005-01-20 20:04:07 +0000476//.. #define R_AL (0+R_EAX)
477//.. #define R_AH (4+R_EAX)
sewardjecb94892005-01-21 14:26:37 +0000478
479/* This is the Intel register encoding -- segment regs. */
480#define R_ES 0
481#define R_CS 1
482#define R_SS 2
483#define R_DS 3
484#define R_FS 4
485#define R_GS 5
486
487
sewardjb3a04292005-01-21 20:33:44 +0000488/* Various simple conversions */
489
490static ULong extend_s_8to64 ( UChar x )
491{
492 return (ULong)((((Long)x) << 56) >> 56);
493}
494
495static ULong extend_s_16to64 ( UShort x )
496{
497 return (ULong)((((Long)x) << 48) >> 48);
498}
499
500static ULong extend_s_32to64 ( UInt x )
501{
502 return (ULong)((((Long)x) << 32) >> 32);
503}
504
sewardjdf0e0022005-01-25 15:48:43 +0000505/* Figure out whether the mod and rm parts of a modRM byte refer to a
506 register or memory. If so, the byte will have the form 11XXXYYY,
507 where YYY is the register number. */
sewardj5b470602005-02-27 13:10:48 +0000508inline
sewardjdf0e0022005-01-25 15:48:43 +0000509static Bool epartIsReg ( UChar mod_reg_rm )
510{
sewardj7a240552005-01-28 21:37:12 +0000511 return toBool(0xC0 == (mod_reg_rm & 0xC0));
sewardjdf0e0022005-01-25 15:48:43 +0000512}
513
sewardj901ed122005-02-27 13:25:31 +0000514/* Extract the 'g' field from a modRM byte. This only produces 3
515 bits, which is not a complete register number. You should avoid
516 this function if at all possible. */
517inline
518static Int gregLO3ofRM ( UChar mod_reg_rm )
sewardjdf0e0022005-01-25 15:48:43 +0000519{
520 return (Int)( (mod_reg_rm >> 3) & 7 );
521}
522
sewardj8711f662005-05-09 17:52:56 +0000523/* Ditto the 'e' field of a modRM byte. */
524inline
525static Int eregLO3ofRM ( UChar mod_reg_rm )
526{
527 return (Int)(mod_reg_rm & 0x7);
528}
529
sewardjdf0e0022005-01-25 15:48:43 +0000530/* Get a 8/16/32-bit unsigned value out of the insn stream. */
531
sewardj270def42005-07-03 01:03:01 +0000532static UChar getUChar ( Long delta )
sewardjdf0e0022005-01-25 15:48:43 +0000533{
sewardj8c332e22005-01-28 01:36:56 +0000534 UChar v = guest_code[delta+0];
535 return v;
sewardjdf0e0022005-01-25 15:48:43 +0000536}
537
sewardj47c2d4d2006-11-14 17:50:16 +0000538static UInt getUDisp16 ( Long delta )
539{
540 UInt v = guest_code[delta+1]; v <<= 8;
541 v |= guest_code[delta+0];
542 return v & 0xFFFF;
543}
544
sewardj270def42005-07-03 01:03:01 +0000545//.. static UInt getUDisp ( Int size, Long delta )
sewardjd20c8852005-01-20 20:04:07 +0000546//.. {
547//.. switch (size) {
548//.. case 4: return getUDisp32(delta);
549//.. case 2: return getUDisp16(delta);
550//.. case 1: return getUChar(delta);
551//.. default: vpanic("getUDisp(x86)");
552//.. }
553//.. return 0; /*notreached*/
554//.. }
sewardjb3a04292005-01-21 20:33:44 +0000555
556
557/* Get a byte value out of the insn stream and sign-extend to 64
558 bits. */
sewardj270def42005-07-03 01:03:01 +0000559static Long getSDisp8 ( Long delta )
sewardjb3a04292005-01-21 20:33:44 +0000560{
561 return extend_s_8to64( guest_code[delta] );
562}
563
sewardj5e525292005-01-28 15:13:10 +0000564/* Get a 16-bit value out of the insn stream and sign-extend to 64
565 bits. */
sewardj270def42005-07-03 01:03:01 +0000566static Long getSDisp16 ( Long delta )
sewardj5e525292005-01-28 15:13:10 +0000567{
sewardj118b23e2005-01-29 02:14:44 +0000568 UInt v = guest_code[delta+1]; v <<= 8;
sewardj5e525292005-01-28 15:13:10 +0000569 v |= guest_code[delta+0];
sewardj118b23e2005-01-29 02:14:44 +0000570 return extend_s_16to64( (UShort)v );
sewardj5e525292005-01-28 15:13:10 +0000571}
572
sewardjb3a04292005-01-21 20:33:44 +0000573/* Get a 32-bit value out of the insn stream and sign-extend to 64
574 bits. */
sewardj270def42005-07-03 01:03:01 +0000575static Long getSDisp32 ( Long delta )
sewardjb3a04292005-01-21 20:33:44 +0000576{
577 UInt v = guest_code[delta+3]; v <<= 8;
578 v |= guest_code[delta+2]; v <<= 8;
579 v |= guest_code[delta+1]; v <<= 8;
580 v |= guest_code[delta+0];
581 return extend_s_32to64( v );
582}
583
sewardj03b07cc2005-01-31 18:09:43 +0000584/* Get a 64-bit value out of the insn stream. */
sewardj270def42005-07-03 01:03:01 +0000585static Long getDisp64 ( Long delta )
sewardj03b07cc2005-01-31 18:09:43 +0000586{
sewardj7eaa7cf2005-01-31 18:55:22 +0000587 ULong v = 0;
sewardj03b07cc2005-01-31 18:09:43 +0000588 v |= guest_code[delta+7]; v <<= 8;
589 v |= guest_code[delta+6]; v <<= 8;
590 v |= guest_code[delta+5]; v <<= 8;
591 v |= guest_code[delta+4]; v <<= 8;
592 v |= guest_code[delta+3]; v <<= 8;
593 v |= guest_code[delta+2]; v <<= 8;
594 v |= guest_code[delta+1]; v <<= 8;
595 v |= guest_code[delta+0];
596 return v;
597}
598
sewardj3ca55a12005-01-27 16:06:23 +0000599/* Note: because AMD64 doesn't allow 64-bit literals, it is an error
600 if this is called with size==8. Should not happen. */
sewardj270def42005-07-03 01:03:01 +0000601static Long getSDisp ( Int size, Long delta )
sewardj3ca55a12005-01-27 16:06:23 +0000602{
603 switch (size) {
604 case 4: return getSDisp32(delta);
sewardj5e525292005-01-28 15:13:10 +0000605 case 2: return getSDisp16(delta);
sewardj3ca55a12005-01-27 16:06:23 +0000606 case 1: return getSDisp8(delta);
607 default: vpanic("getSDisp(amd64)");
608 }
609}
610
sewardj1389d4d2005-01-28 13:46:29 +0000611static ULong mkSizeMask ( Int sz )
sewardj3ca55a12005-01-27 16:06:23 +0000612{
613 switch (sz) {
sewardj1389d4d2005-01-28 13:46:29 +0000614 case 1: return 0x00000000000000FFULL;
615 case 2: return 0x000000000000FFFFULL;
616 case 4: return 0x00000000FFFFFFFFULL;
sewardj3ca55a12005-01-27 16:06:23 +0000617 case 8: return 0xFFFFFFFFFFFFFFFFULL;
618 default: vpanic("mkSzMask(amd64)");
619 }
620}
621
622static Int imin ( Int a, Int b )
623{
624 return (a < b) ? a : b;
625}
sewardjecb94892005-01-21 14:26:37 +0000626
sewardj5b470602005-02-27 13:10:48 +0000627static IRType szToITy ( Int n )
628{
629 switch (n) {
630 case 1: return Ity_I8;
631 case 2: return Ity_I16;
632 case 4: return Ity_I32;
633 case 8: return Ity_I64;
sewardjf53b7352005-04-06 20:01:56 +0000634 default: vex_printf("\nszToITy(%d)\n", n);
635 vpanic("szToITy(amd64)");
sewardj5b470602005-02-27 13:10:48 +0000636 }
637}
638
sewardjecb94892005-01-21 14:26:37 +0000639
640/*------------------------------------------------------------*/
641/*--- For dealing with prefixes. ---*/
642/*------------------------------------------------------------*/
643
644/* The idea is to pass around an int holding a bitmask summarising
645 info from the prefixes seen on the current instruction, including
646 info from the REX byte. This info is used in various places, but
647 most especially when making sense of register fields in
648 instructions.
649
650 The top 16 bits of the prefix are 0x3141, just as a hacky way
651 to ensure it really is a valid prefix.
sewardjdf0e0022005-01-25 15:48:43 +0000652
653 Things you can safely assume about a well-formed prefix:
654 * at most one segment-override bit (CS,DS,ES,FS,GS,SS) is set.
sewardj5b470602005-02-27 13:10:48 +0000655 * if REX is not present then REXW,REXR,REXX,REXB will read
656 as zero.
sewardjdf0e0022005-01-25 15:48:43 +0000657 * F2 and F3 will not both be 1.
sewardjecb94892005-01-21 14:26:37 +0000658*/
659
660typedef UInt Prefix;
661
sewardj3ca55a12005-01-27 16:06:23 +0000662#define PFX_ASO (1<<0) /* address-size override present (0x67) */
663#define PFX_66 (1<<1) /* operand-size override-to-16 present (0x66) */
664#define PFX_REX (1<<2) /* REX byte present (0x40 to 0x4F) */
665#define PFX_REXW (1<<3) /* REX W bit, if REX present, else 0 */
666#define PFX_REXR (1<<4) /* REX R bit, if REX present, else 0 */
667#define PFX_REXX (1<<5) /* REX X bit, if REX present, else 0 */
668#define PFX_REXB (1<<6) /* REX B bit, if REX present, else 0 */
669#define PFX_LOCK (1<<7) /* bus LOCK prefix present (0xF0) */
670#define PFX_F2 (1<<8) /* REP/REPE/REPZ prefix present (0xF2) */
671#define PFX_F3 (1<<9) /* REPNE/REPNZ prefix present (0xF3) */
672#define PFX_CS (1<<10) /* CS segment prefix present (0x2E) */
673#define PFX_DS (1<<11) /* DS segment prefix present (0x3E) */
674#define PFX_ES (1<<12) /* ES segment prefix present (0x26) */
675#define PFX_FS (1<<13) /* FS segment prefix present (0x64) */
676#define PFX_GS (1<<14) /* GS segment prefix present (0x65) */
677#define PFX_SS (1<<15) /* SS segment prefix present (0x36) */
678
679#define PFX_EMPTY 0x31410000
sewardjecb94892005-01-21 14:26:37 +0000680
sewardjb3a04292005-01-21 20:33:44 +0000681static Bool IS_VALID_PFX ( Prefix pfx ) {
sewardj7a240552005-01-28 21:37:12 +0000682 return toBool((pfx & 0xFFFF0000) == PFX_EMPTY);
sewardjecb94892005-01-21 14:26:37 +0000683}
684
sewardjb3a04292005-01-21 20:33:44 +0000685static Bool haveREX ( Prefix pfx ) {
sewardj7a240552005-01-28 21:37:12 +0000686 return toBool(pfx & PFX_REX);
sewardjecb94892005-01-21 14:26:37 +0000687}
688
sewardj5e525292005-01-28 15:13:10 +0000689static Int getRexW ( Prefix pfx ) {
690 return (pfx & PFX_REXW) ? 1 : 0;
691}
sewardj901ed122005-02-27 13:25:31 +0000692/* Apparently unused.
sewardjdf0e0022005-01-25 15:48:43 +0000693static Int getRexR ( Prefix pfx ) {
694 return (pfx & PFX_REXR) ? 1 : 0;
695}
sewardj901ed122005-02-27 13:25:31 +0000696*/
sewardj5b470602005-02-27 13:10:48 +0000697static Int getRexX ( Prefix pfx ) {
698 return (pfx & PFX_REXX) ? 1 : 0;
699}
sewardjdf0e0022005-01-25 15:48:43 +0000700static Int getRexB ( Prefix pfx ) {
701 return (pfx & PFX_REXB) ? 1 : 0;
702}
703
sewardj3ca55a12005-01-27 16:06:23 +0000704/* Check a prefix doesn't have F2 or F3 set in it, since usually that
705 completely changes what instruction it really is. */
706static Bool haveF2orF3 ( Prefix pfx ) {
sewardj7a240552005-01-28 21:37:12 +0000707 return toBool((pfx & (PFX_F2|PFX_F3)) > 0);
sewardj3ca55a12005-01-27 16:06:23 +0000708}
sewardj55dbb262005-01-28 16:36:51 +0000709static Bool haveF2 ( Prefix pfx ) {
sewardj7a240552005-01-28 21:37:12 +0000710 return toBool((pfx & PFX_F2) > 0);
sewardj55dbb262005-01-28 16:36:51 +0000711}
712static Bool haveF3 ( Prefix pfx ) {
sewardj7a240552005-01-28 21:37:12 +0000713 return toBool((pfx & PFX_F3) > 0);
sewardj55dbb262005-01-28 16:36:51 +0000714}
sewardj6359f812005-07-20 10:15:34 +0000715
sewardjc8b26352005-07-20 09:23:13 +0000716static Bool have66 ( Prefix pfx ) {
717 return toBool((pfx & PFX_66) > 0);
718}
sewardj6359f812005-07-20 10:15:34 +0000719static Bool haveASO ( Prefix pfx ) {
720 return toBool((pfx & PFX_ASO) > 0);
721}
sewardjecb94892005-01-21 14:26:37 +0000722
sewardj1001dc42005-02-21 08:25:55 +0000723/* Return True iff pfx has 66 set and F2 and F3 clear */
724static Bool have66noF2noF3 ( Prefix pfx )
725{
726 return
sewardj8d965312005-02-25 02:48:47 +0000727 toBool((pfx & (PFX_66|PFX_F2|PFX_F3)) == PFX_66);
sewardj1001dc42005-02-21 08:25:55 +0000728}
729
730/* Return True iff pfx has F2 set and 66 and F3 clear */
731static Bool haveF2no66noF3 ( Prefix pfx )
732{
733 return
sewardj8d965312005-02-25 02:48:47 +0000734 toBool((pfx & (PFX_66|PFX_F2|PFX_F3)) == PFX_F2);
735}
736
737/* Return True iff pfx has F3 set and 66 and F2 clear */
738static Bool haveF3no66noF2 ( Prefix pfx )
739{
740 return
741 toBool((pfx & (PFX_66|PFX_F2|PFX_F3)) == PFX_F3);
sewardj1001dc42005-02-21 08:25:55 +0000742}
743
sewardjfd181282010-06-14 21:29:35 +0000744/* Return True iff pfx has F3 set and F2 clear */
745static Bool haveF3noF2 ( Prefix pfx )
746{
747 return
748 toBool((pfx & (PFX_F2|PFX_F3)) == PFX_F3);
749}
750
sewardj1001dc42005-02-21 08:25:55 +0000751/* Return True iff pfx has 66, F2 and F3 clear */
752static Bool haveNo66noF2noF3 ( Prefix pfx )
753{
754 return
sewardj8d965312005-02-25 02:48:47 +0000755 toBool((pfx & (PFX_66|PFX_F2|PFX_F3)) == 0);
sewardj1001dc42005-02-21 08:25:55 +0000756}
757
sewardj8711f662005-05-09 17:52:56 +0000758/* Return True iff pfx has any of 66, F2 and F3 set */
759static Bool have66orF2orF3 ( Prefix pfx )
760{
sewardjca673ab2005-05-11 10:03:08 +0000761 return toBool( ! haveNo66noF2noF3(pfx) );
sewardj8711f662005-05-09 17:52:56 +0000762}
763
sewardj47c2d4d2006-11-14 17:50:16 +0000764/* Return True iff pfx has 66 or F2 set */
765static Bool have66orF2 ( Prefix pfx )
766{
767 return toBool((pfx & (PFX_66|PFX_F2)) > 0);
768}
769
sewardj1389d4d2005-01-28 13:46:29 +0000770/* Clear all the segment-override bits in a prefix. */
771static Prefix clearSegBits ( Prefix p )
772{
sewardj1001dc42005-02-21 08:25:55 +0000773 return
774 p & ~(PFX_CS | PFX_DS | PFX_ES | PFX_FS | PFX_GS | PFX_SS);
775}
776
sewardj1389d4d2005-01-28 13:46:29 +0000777
sewardjecb94892005-01-21 14:26:37 +0000778/*------------------------------------------------------------*/
sewardj5b470602005-02-27 13:10:48 +0000779/*--- For dealing with integer registers ---*/
sewardjecb94892005-01-21 14:26:37 +0000780/*------------------------------------------------------------*/
781
sewardj5b470602005-02-27 13:10:48 +0000782/* This is somewhat complex. The rules are:
783
784 For 64, 32 and 16 bit register references, the e or g fields in the
785 modrm bytes supply the low 3 bits of the register number. The
786 fourth (most-significant) bit of the register number is supplied by
787 the REX byte, if it is present; else that bit is taken to be zero.
788
789 The REX.R bit supplies the high bit corresponding to the g register
790 field, and the REX.B bit supplies the high bit corresponding to the
791 e register field (when the mod part of modrm indicates that modrm's
792 e component refers to a register and not to memory).
793
794 The REX.X bit supplies a high register bit for certain registers
795 in SIB address modes, and is generally rarely used.
796
797 For 8 bit register references, the presence of the REX byte itself
798 has significance. If there is no REX present, then the 3-bit
799 number extracted from the modrm e or g field is treated as an index
800 into the sequence %al %cl %dl %bl %ah %ch %dh %bh -- that is, the
801 old x86 encoding scheme.
802
803 But if there is a REX present, the register reference is
804 interpreted in the same way as for 64/32/16-bit references: a high
805 bit is extracted from REX, giving a 4-bit number, and the denoted
806 register is the lowest 8 bits of the 16 integer registers denoted
807 by the number. In particular, values 3 through 7 of this sequence
808 do not refer to %ah %ch %dh %bh but instead to the lowest 8 bits of
809 %rsp %rbp %rsi %rdi.
810
811 The REX.W bit has no bearing at all on register numbers. Instead
812 its presence indicates that the operand size is to be overridden
813 from its default value (32 bits) to 64 bits instead. This is in
814 the same fashion that an 0x66 prefix indicates the operand size is
815 to be overridden from 32 bits down to 16 bits. When both REX.W and
816 0x66 are present there is a conflict, and REX.W takes precedence.
817
818 Rather than try to handle this complexity using a single huge
819 function, several smaller ones are provided. The aim is to make it
820 as difficult as possible to screw up register decoding in a subtle
821 and hard-to-track-down way.
822
823 Because these routines fish around in the host's memory (that is,
824 in the guest state area) for sub-parts of guest registers, their
825 correctness depends on the host's endianness. So far these
826 routines only work for little-endian hosts. Those for which
827 endianness is important have assertions to ensure sanity.
828*/
sewardjecb94892005-01-21 14:26:37 +0000829
830
sewardj5b470602005-02-27 13:10:48 +0000831/* About the simplest question you can ask: where do the 64-bit
832 integer registers live (in the guest state) ? */
sewardjecb94892005-01-21 14:26:37 +0000833
sewardj3ca55a12005-01-27 16:06:23 +0000834static Int integerGuestReg64Offset ( UInt reg )
sewardjb3a04292005-01-21 20:33:44 +0000835{
836 switch (reg) {
837 case R_RAX: return OFFB_RAX;
838 case R_RCX: return OFFB_RCX;
839 case R_RDX: return OFFB_RDX;
840 case R_RBX: return OFFB_RBX;
841 case R_RSP: return OFFB_RSP;
842 case R_RBP: return OFFB_RBP;
843 case R_RSI: return OFFB_RSI;
844 case R_RDI: return OFFB_RDI;
845 case R_R8: return OFFB_R8;
846 case R_R9: return OFFB_R9;
847 case R_R10: return OFFB_R10;
848 case R_R11: return OFFB_R11;
849 case R_R12: return OFFB_R12;
850 case R_R13: return OFFB_R13;
851 case R_R14: return OFFB_R14;
852 case R_R15: return OFFB_R15;
853 default: vpanic("integerGuestReg64Offset(amd64)");
854 }
855}
856
857
sewardj5b470602005-02-27 13:10:48 +0000858/* Produce the name of an integer register, for printing purposes.
859 reg is a number in the range 0 .. 15 that has been generated from a
860 3-bit reg-field number and a REX extension bit. irregular denotes
861 the case where sz==1 and no REX byte is present. */
sewardjecb94892005-01-21 14:26:37 +0000862
863static
sewardj5b470602005-02-27 13:10:48 +0000864HChar* nameIReg ( Int sz, UInt reg, Bool irregular )
sewardjecb94892005-01-21 14:26:37 +0000865{
sewardjecb94892005-01-21 14:26:37 +0000866 static HChar* ireg64_names[16]
867 = { "%rax", "%rcx", "%rdx", "%rbx", "%rsp", "%rbp", "%rsi", "%rdi",
868 "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15" };
869 static HChar* ireg32_names[16]
870 = { "%eax", "%ecx", "%edx", "%ebx", "%esp", "%ebp", "%esi", "%edi",
871 "%r8d", "%r9d", "%r10d","%r11d","%r12d","%r13d","%r14d","%r15d" };
872 static HChar* ireg16_names[16]
873 = { "%ax", "%cx", "%dx", "%bx", "%sp", "%bp", "%si", "%di",
874 "%r8w", "%r9w", "%r10w","%r11w","%r12w","%r13w","%r14w","%r15w" };
875 static HChar* ireg8_names[16]
876 = { "%al", "%cl", "%dl", "%bl", "%spl", "%bpl", "%sil", "%dil",
877 "%r8b", "%r9b", "%r10b","%r11b","%r12b","%r13b","%r14b","%r15b" };
sewardj5b470602005-02-27 13:10:48 +0000878 static HChar* ireg8_irregular[8]
sewardjecb94892005-01-21 14:26:37 +0000879 = { "%al", "%cl", "%dl", "%bl", "%ah", "%ch", "%dh", "%bh" };
880
sewardj5b470602005-02-27 13:10:48 +0000881 vassert(reg < 16);
882 if (sz == 1) {
883 if (irregular)
884 vassert(reg < 8);
885 } else {
886 vassert(irregular == False);
887 }
sewardjecb94892005-01-21 14:26:37 +0000888
889 switch (sz) {
sewardj5b470602005-02-27 13:10:48 +0000890 case 8: return ireg64_names[reg];
891 case 4: return ireg32_names[reg];
892 case 2: return ireg16_names[reg];
893 case 1: if (irregular) {
894 return ireg8_irregular[reg];
895 } else {
896 return ireg8_names[reg];
897 }
898 default: vpanic("nameIReg(amd64)");
sewardjecb94892005-01-21 14:26:37 +0000899 }
sewardjecb94892005-01-21 14:26:37 +0000900}
901
sewardj5b470602005-02-27 13:10:48 +0000902/* Using the same argument conventions as nameIReg, produce the
903 guest state offset of an integer register. */
sewardjb3a04292005-01-21 20:33:44 +0000904
sewardjecb94892005-01-21 14:26:37 +0000905static
sewardj5b470602005-02-27 13:10:48 +0000906Int offsetIReg ( Int sz, UInt reg, Bool irregular )
sewardjecb94892005-01-21 14:26:37 +0000907{
sewardj5b470602005-02-27 13:10:48 +0000908 vassert(reg < 16);
909 if (sz == 1) {
910 if (irregular)
911 vassert(reg < 8);
912 } else {
913 vassert(irregular == False);
sewardjecb94892005-01-21 14:26:37 +0000914 }
sewardj5b470602005-02-27 13:10:48 +0000915
916 /* Deal with irregular case -- sz==1 and no REX present */
917 if (sz == 1 && irregular) {
918 switch (reg) {
919 case R_RSP: return 1+ OFFB_RAX;
920 case R_RBP: return 1+ OFFB_RCX;
921 case R_RSI: return 1+ OFFB_RDX;
922 case R_RDI: return 1+ OFFB_RBX;
923 default: break; /* use the normal case */
924 }
sewardjecb94892005-01-21 14:26:37 +0000925 }
sewardj5b470602005-02-27 13:10:48 +0000926
927 /* Normal case */
928 return integerGuestReg64Offset(reg);
sewardjecb94892005-01-21 14:26:37 +0000929}
930
931
sewardj5b470602005-02-27 13:10:48 +0000932/* Read the %CL register :: Ity_I8, for shift/rotate operations. */
933
934static IRExpr* getIRegCL ( void )
935{
936 vassert(!host_is_bigendian);
937 return IRExpr_Get( OFFB_RCX, Ity_I8 );
938}
939
940
941/* Write to the %AH register. */
942
943static void putIRegAH ( IRExpr* e )
944{
945 vassert(!host_is_bigendian);
sewardjdd40fdf2006-12-24 02:20:24 +0000946 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I8);
sewardj5b470602005-02-27 13:10:48 +0000947 stmt( IRStmt_Put( OFFB_RAX+1, e ) );
948}
949
950
951/* Read/write various widths of %RAX, as it has various
952 special-purpose uses. */
953
954static HChar* nameIRegRAX ( Int sz )
955{
956 switch (sz) {
957 case 1: return "%al";
958 case 2: return "%ax";
959 case 4: return "%eax";
960 case 8: return "%rax";
961 default: vpanic("nameIRegRAX(amd64)");
962 }
963}
964
965static IRExpr* getIRegRAX ( Int sz )
966{
967 vassert(!host_is_bigendian);
968 switch (sz) {
969 case 1: return IRExpr_Get( OFFB_RAX, Ity_I8 );
970 case 2: return IRExpr_Get( OFFB_RAX, Ity_I16 );
sewardjef425db2010-01-11 10:46:18 +0000971 case 4: return unop(Iop_64to32, IRExpr_Get( OFFB_RAX, Ity_I64 ));
sewardj5b470602005-02-27 13:10:48 +0000972 case 8: return IRExpr_Get( OFFB_RAX, Ity_I64 );
973 default: vpanic("getIRegRAX(amd64)");
974 }
975}
976
977static void putIRegRAX ( Int sz, IRExpr* e )
978{
sewardjdd40fdf2006-12-24 02:20:24 +0000979 IRType ty = typeOfIRExpr(irsb->tyenv, e);
sewardj5b470602005-02-27 13:10:48 +0000980 vassert(!host_is_bigendian);
981 switch (sz) {
982 case 8: vassert(ty == Ity_I64);
983 stmt( IRStmt_Put( OFFB_RAX, e ));
984 break;
985 case 4: vassert(ty == Ity_I32);
986 stmt( IRStmt_Put( OFFB_RAX, unop(Iop_32Uto64,e) ));
987 break;
988 case 2: vassert(ty == Ity_I16);
989 stmt( IRStmt_Put( OFFB_RAX, e ));
990 break;
991 case 1: vassert(ty == Ity_I8);
992 stmt( IRStmt_Put( OFFB_RAX, e ));
993 break;
994 default: vpanic("putIRegRAX(amd64)");
995 }
996}
997
998
999/* Read/write various widths of %RDX, as it has various
1000 special-purpose uses. */
1001
sewardjbb4396c2007-11-20 17:29:08 +00001002static HChar* nameIRegRDX ( Int sz )
1003{
1004 switch (sz) {
1005 case 1: return "%dl";
1006 case 2: return "%dx";
1007 case 4: return "%edx";
1008 case 8: return "%rdx";
1009 default: vpanic("nameIRegRDX(amd64)");
1010 }
1011}
1012
sewardj5b470602005-02-27 13:10:48 +00001013static IRExpr* getIRegRDX ( Int sz )
1014{
1015 vassert(!host_is_bigendian);
1016 switch (sz) {
1017 case 1: return IRExpr_Get( OFFB_RDX, Ity_I8 );
1018 case 2: return IRExpr_Get( OFFB_RDX, Ity_I16 );
sewardjef425db2010-01-11 10:46:18 +00001019 case 4: return unop(Iop_64to32, IRExpr_Get( OFFB_RDX, Ity_I64 ));
sewardj5b470602005-02-27 13:10:48 +00001020 case 8: return IRExpr_Get( OFFB_RDX, Ity_I64 );
1021 default: vpanic("getIRegRDX(amd64)");
1022 }
1023}
1024
1025static void putIRegRDX ( Int sz, IRExpr* e )
1026{
1027 vassert(!host_is_bigendian);
sewardjdd40fdf2006-12-24 02:20:24 +00001028 vassert(typeOfIRExpr(irsb->tyenv, e) == szToITy(sz));
sewardj5b470602005-02-27 13:10:48 +00001029 switch (sz) {
1030 case 8: stmt( IRStmt_Put( OFFB_RDX, e ));
1031 break;
1032 case 4: stmt( IRStmt_Put( OFFB_RDX, unop(Iop_32Uto64,e) ));
1033 break;
1034 case 2: stmt( IRStmt_Put( OFFB_RDX, e ));
1035 break;
1036 case 1: stmt( IRStmt_Put( OFFB_RDX, e ));
1037 break;
1038 default: vpanic("putIRegRDX(amd64)");
1039 }
1040}
1041
1042
1043/* Simplistic functions to deal with the integer registers as a
1044 straightforward bank of 16 64-bit regs. */
sewardjb3a04292005-01-21 20:33:44 +00001045
1046static IRExpr* getIReg64 ( UInt regno )
1047{
1048 return IRExpr_Get( integerGuestReg64Offset(regno),
1049 Ity_I64 );
1050}
1051
sewardj2f959cc2005-01-26 01:19:35 +00001052static void putIReg64 ( UInt regno, IRExpr* e )
1053{
sewardjdd40fdf2006-12-24 02:20:24 +00001054 vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_I64);
sewardj2f959cc2005-01-26 01:19:35 +00001055 stmt( IRStmt_Put( integerGuestReg64Offset(regno), e ) );
1056}
1057
sewardjb3a04292005-01-21 20:33:44 +00001058static HChar* nameIReg64 ( UInt regno )
1059{
sewardj5b470602005-02-27 13:10:48 +00001060 return nameIReg( 8, regno, False );
sewardjb3a04292005-01-21 20:33:44 +00001061}
sewardj5b470602005-02-27 13:10:48 +00001062
1063
1064/* Simplistic functions to deal with the lower halves of integer
1065 registers as a straightforward bank of 16 32-bit regs. */
1066
1067static IRExpr* getIReg32 ( UInt regno )
1068{
1069 vassert(!host_is_bigendian);
sewardjef425db2010-01-11 10:46:18 +00001070 return unop(Iop_64to32,
1071 IRExpr_Get( integerGuestReg64Offset(regno),
1072 Ity_I64 ));
sewardj5b470602005-02-27 13:10:48 +00001073}
1074
1075static void putIReg32 ( UInt regno, IRExpr* e )
1076{
sewardjdd40fdf2006-12-24 02:20:24 +00001077 vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_I32);
sewardj5b470602005-02-27 13:10:48 +00001078 stmt( IRStmt_Put( integerGuestReg64Offset(regno),
1079 unop(Iop_32Uto64,e) ) );
1080}
1081
1082static HChar* nameIReg32 ( UInt regno )
1083{
1084 return nameIReg( 4, regno, False );
1085}
1086
1087
sewardja7ba8c42005-05-10 20:08:34 +00001088/* Simplistic functions to deal with the lower quarters of integer
1089 registers as a straightforward bank of 16 16-bit regs. */
1090
1091static IRExpr* getIReg16 ( UInt regno )
1092{
1093 vassert(!host_is_bigendian);
1094 return IRExpr_Get( integerGuestReg64Offset(regno),
1095 Ity_I16 );
1096}
1097
1098static HChar* nameIReg16 ( UInt regno )
1099{
1100 return nameIReg( 2, regno, False );
1101}
1102
1103
sewardj5b470602005-02-27 13:10:48 +00001104/* Sometimes what we know is a 3-bit register number, a REX byte, and
1105 which field of the REX byte is to be used to extend to a 4-bit
1106 number. These functions cater for that situation.
1107*/
1108static IRExpr* getIReg64rexX ( Prefix pfx, UInt lo3bits )
1109{
1110 vassert(lo3bits < 8);
1111 vassert(IS_VALID_PFX(pfx));
1112 return getIReg64( lo3bits | (getRexX(pfx) << 3) );
1113}
1114
1115static HChar* nameIReg64rexX ( Prefix pfx, UInt lo3bits )
1116{
1117 vassert(lo3bits < 8);
1118 vassert(IS_VALID_PFX(pfx));
1119 return nameIReg( 8, lo3bits | (getRexX(pfx) << 3), False );
1120}
1121
1122static HChar* nameIRegRexB ( Int sz, Prefix pfx, UInt lo3bits )
1123{
1124 vassert(lo3bits < 8);
1125 vassert(IS_VALID_PFX(pfx));
1126 vassert(sz == 8 || sz == 4 || sz == 2 || sz == 1);
1127 return nameIReg( sz, lo3bits | (getRexB(pfx) << 3),
sewardj397f88b2005-02-27 13:39:25 +00001128 toBool(sz==1 && !haveREX(pfx)) );
sewardj5b470602005-02-27 13:10:48 +00001129}
1130
1131static IRExpr* getIRegRexB ( Int sz, Prefix pfx, UInt lo3bits )
1132{
1133 vassert(lo3bits < 8);
1134 vassert(IS_VALID_PFX(pfx));
1135 vassert(sz == 8 || sz == 4 || sz == 2 || sz == 1);
sewardjef425db2010-01-11 10:46:18 +00001136 if (sz == 4) {
1137 sz = 8;
1138 return unop(Iop_64to32,
1139 IRExpr_Get(
1140 offsetIReg( sz, lo3bits | (getRexB(pfx) << 3),
1141 toBool(sz==1 && !haveREX(pfx)) ),
1142 szToITy(sz)
1143 )
1144 );
1145 } else {
1146 return IRExpr_Get(
1147 offsetIReg( sz, lo3bits | (getRexB(pfx) << 3),
1148 toBool(sz==1 && !haveREX(pfx)) ),
1149 szToITy(sz)
1150 );
1151 }
sewardj5b470602005-02-27 13:10:48 +00001152}
1153
1154static void putIRegRexB ( Int sz, Prefix pfx, UInt lo3bits, IRExpr* e )
1155{
1156 vassert(lo3bits < 8);
1157 vassert(IS_VALID_PFX(pfx));
sewardj98e9f342005-07-23 12:07:37 +00001158 vassert(sz == 8 || sz == 4 || sz == 2 || sz == 1);
sewardjdd40fdf2006-12-24 02:20:24 +00001159 vassert(typeOfIRExpr(irsb->tyenv, e) == szToITy(sz));
sewardj5b470602005-02-27 13:10:48 +00001160 stmt( IRStmt_Put(
1161 offsetIReg( sz, lo3bits | (getRexB(pfx) << 3),
sewardj397f88b2005-02-27 13:39:25 +00001162 toBool(sz==1 && !haveREX(pfx)) ),
sewardj5b470602005-02-27 13:10:48 +00001163 sz==4 ? unop(Iop_32Uto64,e) : e
1164 ));
1165}
1166
1167
1168/* Functions for getting register numbers from modrm bytes and REX
1169 when we don't have to consider the complexities of integer subreg
1170 accesses.
1171*/
1172/* Extract the g reg field from a modRM byte, and augment it using the
1173 REX.R bit from the supplied REX byte. The R bit usually is
1174 associated with the g register field.
1175*/
1176static UInt gregOfRexRM ( Prefix pfx, UChar mod_reg_rm )
1177{
1178 Int reg = (Int)( (mod_reg_rm >> 3) & 7 );
1179 reg += (pfx & PFX_REXR) ? 8 : 0;
1180 return reg;
1181}
1182
1183/* Extract the e reg field from a modRM byte, and augment it using the
1184 REX.B bit from the supplied REX byte. The B bit usually is
1185 associated with the e register field (when modrm indicates e is a
1186 register, that is).
1187*/
1188static UInt eregOfRexRM ( Prefix pfx, UChar mod_reg_rm )
1189{
1190 Int rm;
1191 vassert(epartIsReg(mod_reg_rm));
1192 rm = (Int)(mod_reg_rm & 0x7);
1193 rm += (pfx & PFX_REXB) ? 8 : 0;
1194 return rm;
1195}
1196
1197
1198/* General functions for dealing with integer register access. */
1199
1200/* Produce the guest state offset for a reference to the 'g' register
1201 field in a modrm byte, taking into account REX (or its absence),
1202 and the size of the access.
1203*/
1204static UInt offsetIRegG ( Int sz, Prefix pfx, UChar mod_reg_rm )
1205{
1206 UInt reg;
1207 vassert(!host_is_bigendian);
1208 vassert(IS_VALID_PFX(pfx));
1209 vassert(sz == 8 || sz == 4 || sz == 2 || sz == 1);
1210 reg = gregOfRexRM( pfx, mod_reg_rm );
sewardj397f88b2005-02-27 13:39:25 +00001211 return offsetIReg( sz, reg, toBool(sz == 1 && !haveREX(pfx)) );
sewardj5b470602005-02-27 13:10:48 +00001212}
1213
1214static
1215IRExpr* getIRegG ( Int sz, Prefix pfx, UChar mod_reg_rm )
1216{
sewardjef425db2010-01-11 10:46:18 +00001217 if (sz == 4) {
1218 sz = 8;
1219 return unop(Iop_64to32,
1220 IRExpr_Get( offsetIRegG( sz, pfx, mod_reg_rm ),
1221 szToITy(sz) ));
1222 } else {
1223 return IRExpr_Get( offsetIRegG( sz, pfx, mod_reg_rm ),
1224 szToITy(sz) );
1225 }
sewardj5b470602005-02-27 13:10:48 +00001226}
1227
1228static
1229void putIRegG ( Int sz, Prefix pfx, UChar mod_reg_rm, IRExpr* e )
1230{
sewardjdd40fdf2006-12-24 02:20:24 +00001231 vassert(typeOfIRExpr(irsb->tyenv,e) == szToITy(sz));
sewardj5b470602005-02-27 13:10:48 +00001232 if (sz == 4) {
1233 e = unop(Iop_32Uto64,e);
1234 }
1235 stmt( IRStmt_Put( offsetIRegG( sz, pfx, mod_reg_rm ), e ) );
1236}
1237
1238static
1239HChar* nameIRegG ( Int sz, Prefix pfx, UChar mod_reg_rm )
1240{
1241 return nameIReg( sz, gregOfRexRM(pfx,mod_reg_rm),
sewardj397f88b2005-02-27 13:39:25 +00001242 toBool(sz==1 && !haveREX(pfx)) );
sewardj5b470602005-02-27 13:10:48 +00001243}
1244
1245
1246/* Produce the guest state offset for a reference to the 'e' register
1247 field in a modrm byte, taking into account REX (or its absence),
1248 and the size of the access. eregOfRexRM will assert if mod_reg_rm
1249 denotes a memory access rather than a register access.
1250*/
1251static UInt offsetIRegE ( Int sz, Prefix pfx, UChar mod_reg_rm )
1252{
1253 UInt reg;
1254 vassert(!host_is_bigendian);
1255 vassert(IS_VALID_PFX(pfx));
1256 vassert(sz == 8 || sz == 4 || sz == 2 || sz == 1);
1257 reg = eregOfRexRM( pfx, mod_reg_rm );
sewardj397f88b2005-02-27 13:39:25 +00001258 return offsetIReg( sz, reg, toBool(sz == 1 && !haveREX(pfx)) );
sewardj5b470602005-02-27 13:10:48 +00001259}
1260
1261static
1262IRExpr* getIRegE ( Int sz, Prefix pfx, UChar mod_reg_rm )
1263{
sewardjef425db2010-01-11 10:46:18 +00001264 if (sz == 4) {
1265 sz = 8;
1266 return unop(Iop_64to32,
1267 IRExpr_Get( offsetIRegE( sz, pfx, mod_reg_rm ),
1268 szToITy(sz) ));
1269 } else {
1270 return IRExpr_Get( offsetIRegE( sz, pfx, mod_reg_rm ),
1271 szToITy(sz) );
1272 }
sewardj5b470602005-02-27 13:10:48 +00001273}
1274
1275static
1276void putIRegE ( Int sz, Prefix pfx, UChar mod_reg_rm, IRExpr* e )
1277{
sewardjdd40fdf2006-12-24 02:20:24 +00001278 vassert(typeOfIRExpr(irsb->tyenv,e) == szToITy(sz));
sewardj5b470602005-02-27 13:10:48 +00001279 if (sz == 4) {
1280 e = unop(Iop_32Uto64,e);
1281 }
1282 stmt( IRStmt_Put( offsetIRegE( sz, pfx, mod_reg_rm ), e ) );
1283}
1284
1285static
1286HChar* nameIRegE ( Int sz, Prefix pfx, UChar mod_reg_rm )
1287{
1288 return nameIReg( sz, eregOfRexRM(pfx,mod_reg_rm),
sewardj397f88b2005-02-27 13:39:25 +00001289 toBool(sz==1 && !haveREX(pfx)) );
sewardj5b470602005-02-27 13:10:48 +00001290}
1291
1292
1293/*------------------------------------------------------------*/
1294/*--- For dealing with XMM registers ---*/
1295/*------------------------------------------------------------*/
sewardjecb94892005-01-21 14:26:37 +00001296
sewardjd20c8852005-01-20 20:04:07 +00001297//.. static Int segmentGuestRegOffset ( UInt sreg )
1298//.. {
1299//.. switch (sreg) {
1300//.. case R_ES: return OFFB_ES;
1301//.. case R_CS: return OFFB_CS;
1302//.. case R_SS: return OFFB_SS;
1303//.. case R_DS: return OFFB_DS;
1304//.. case R_FS: return OFFB_FS;
1305//.. case R_GS: return OFFB_GS;
1306//.. default: vpanic("segmentGuestRegOffset(x86)");
1307//.. }
1308//.. }
sewardj1001dc42005-02-21 08:25:55 +00001309
1310static Int xmmGuestRegOffset ( UInt xmmreg )
1311{
1312 switch (xmmreg) {
1313 case 0: return OFFB_XMM0;
1314 case 1: return OFFB_XMM1;
1315 case 2: return OFFB_XMM2;
1316 case 3: return OFFB_XMM3;
1317 case 4: return OFFB_XMM4;
1318 case 5: return OFFB_XMM5;
1319 case 6: return OFFB_XMM6;
1320 case 7: return OFFB_XMM7;
1321 case 8: return OFFB_XMM8;
1322 case 9: return OFFB_XMM9;
1323 case 10: return OFFB_XMM10;
1324 case 11: return OFFB_XMM11;
1325 case 12: return OFFB_XMM12;
1326 case 13: return OFFB_XMM13;
1327 case 14: return OFFB_XMM14;
1328 case 15: return OFFB_XMM15;
1329 default: vpanic("xmmGuestRegOffset(amd64)");
1330 }
1331}
1332
sewardj97628592005-05-10 22:42:54 +00001333/* Lanes of vector registers are always numbered from zero being the
1334 least significant lane (rightmost in the register). */
1335
1336static Int xmmGuestRegLane16offset ( UInt xmmreg, Int laneno )
1337{
1338 /* Correct for little-endian host only. */
1339 vassert(!host_is_bigendian);
1340 vassert(laneno >= 0 && laneno < 8);
1341 return xmmGuestRegOffset( xmmreg ) + 2 * laneno;
1342}
sewardj8d965312005-02-25 02:48:47 +00001343
1344static Int xmmGuestRegLane32offset ( UInt xmmreg, Int laneno )
1345{
1346 /* Correct for little-endian host only. */
1347 vassert(!host_is_bigendian);
1348 vassert(laneno >= 0 && laneno < 4);
1349 return xmmGuestRegOffset( xmmreg ) + 4 * laneno;
1350}
sewardj1001dc42005-02-21 08:25:55 +00001351
1352static Int xmmGuestRegLane64offset ( UInt xmmreg, Int laneno )
1353{
1354 /* Correct for little-endian host only. */
1355 vassert(!host_is_bigendian);
1356 vassert(laneno >= 0 && laneno < 2);
1357 return xmmGuestRegOffset( xmmreg ) + 8 * laneno;
1358}
1359
sewardjd20c8852005-01-20 20:04:07 +00001360//.. static IRExpr* getSReg ( UInt sreg )
1361//.. {
1362//.. return IRExpr_Get( segmentGuestRegOffset(sreg), Ity_I16 );
1363//.. }
1364//..
1365//.. static void putSReg ( UInt sreg, IRExpr* e )
1366//.. {
sewardjdd40fdf2006-12-24 02:20:24 +00001367//.. vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_I16);
sewardjd20c8852005-01-20 20:04:07 +00001368//.. stmt( IRStmt_Put( segmentGuestRegOffset(sreg), e ) );
1369//.. }
sewardj1001dc42005-02-21 08:25:55 +00001370
1371static IRExpr* getXMMReg ( UInt xmmreg )
1372{
1373 return IRExpr_Get( xmmGuestRegOffset(xmmreg), Ity_V128 );
1374}
1375
1376static IRExpr* getXMMRegLane64 ( UInt xmmreg, Int laneno )
1377{
1378 return IRExpr_Get( xmmGuestRegLane64offset(xmmreg,laneno), Ity_I64 );
1379}
1380
sewardj18303862005-02-21 12:36:54 +00001381static IRExpr* getXMMRegLane64F ( UInt xmmreg, Int laneno )
1382{
1383 return IRExpr_Get( xmmGuestRegLane64offset(xmmreg,laneno), Ity_F64 );
1384}
1385
sewardj8d965312005-02-25 02:48:47 +00001386static IRExpr* getXMMRegLane32 ( UInt xmmreg, Int laneno )
1387{
1388 return IRExpr_Get( xmmGuestRegLane32offset(xmmreg,laneno), Ity_I32 );
1389}
1390
sewardjc49ce232005-02-25 13:03:03 +00001391static IRExpr* getXMMRegLane32F ( UInt xmmreg, Int laneno )
1392{
1393 return IRExpr_Get( xmmGuestRegLane32offset(xmmreg,laneno), Ity_F32 );
1394}
sewardj1001dc42005-02-21 08:25:55 +00001395
de5a70f5c2010-04-01 23:08:59 +00001396static IRExpr* getXMMRegLane16 ( UInt xmmreg, Int laneno )
1397{
1398 return IRExpr_Get( xmmGuestRegLane16offset(xmmreg,laneno), Ity_I16 );
1399}
1400
sewardj1001dc42005-02-21 08:25:55 +00001401static void putXMMReg ( UInt xmmreg, IRExpr* e )
1402{
sewardjdd40fdf2006-12-24 02:20:24 +00001403 vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_V128);
sewardj1001dc42005-02-21 08:25:55 +00001404 stmt( IRStmt_Put( xmmGuestRegOffset(xmmreg), e ) );
1405}
1406
1407static void putXMMRegLane64 ( UInt xmmreg, Int laneno, IRExpr* e )
1408{
sewardjdd40fdf2006-12-24 02:20:24 +00001409 vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_I64);
sewardj1001dc42005-02-21 08:25:55 +00001410 stmt( IRStmt_Put( xmmGuestRegLane64offset(xmmreg,laneno), e ) );
1411}
1412
sewardj1a01e652005-02-23 11:39:21 +00001413static void putXMMRegLane64F ( UInt xmmreg, Int laneno, IRExpr* e )
1414{
sewardjdd40fdf2006-12-24 02:20:24 +00001415 vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_F64);
sewardj1a01e652005-02-23 11:39:21 +00001416 stmt( IRStmt_Put( xmmGuestRegLane64offset(xmmreg,laneno), e ) );
1417}
1418
sewardj8d965312005-02-25 02:48:47 +00001419static void putXMMRegLane32F ( UInt xmmreg, Int laneno, IRExpr* e )
1420{
sewardjdd40fdf2006-12-24 02:20:24 +00001421 vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_F32);
sewardj8d965312005-02-25 02:48:47 +00001422 stmt( IRStmt_Put( xmmGuestRegLane32offset(xmmreg,laneno), e ) );
1423}
1424
1425static void putXMMRegLane32 ( UInt xmmreg, Int laneno, IRExpr* e )
1426{
sewardjdd40fdf2006-12-24 02:20:24 +00001427 vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_I32);
sewardj8d965312005-02-25 02:48:47 +00001428 stmt( IRStmt_Put( xmmGuestRegLane32offset(xmmreg,laneno), e ) );
1429}
1430
sewardj97628592005-05-10 22:42:54 +00001431static void putXMMRegLane16 ( UInt xmmreg, Int laneno, IRExpr* e )
1432{
sewardjdd40fdf2006-12-24 02:20:24 +00001433 vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_I16);
sewardj97628592005-05-10 22:42:54 +00001434 stmt( IRStmt_Put( xmmGuestRegLane16offset(xmmreg,laneno), e ) );
1435}
sewardj3ca55a12005-01-27 16:06:23 +00001436
sewardj1001dc42005-02-21 08:25:55 +00001437static IRExpr* mkV128 ( UShort mask )
1438{
1439 return IRExpr_Const(IRConst_V128(mask));
1440}
sewardjdf0e0022005-01-25 15:48:43 +00001441
sewardje8f65252005-08-23 23:44:35 +00001442static IRExpr* mkAnd1 ( IRExpr* x, IRExpr* y )
1443{
sewardjdd40fdf2006-12-24 02:20:24 +00001444 vassert(typeOfIRExpr(irsb->tyenv,x) == Ity_I1);
1445 vassert(typeOfIRExpr(irsb->tyenv,y) == Ity_I1);
sewardje8f65252005-08-23 23:44:35 +00001446 return unop(Iop_64to1,
1447 binop(Iop_And64,
1448 unop(Iop_1Uto64,x),
1449 unop(Iop_1Uto64,y)));
1450}
1451
sewardje9d8a262009-07-01 08:06:34 +00001452/* Generate a compare-and-swap operation, operating on memory at
1453 'addr'. The expected value is 'expVal' and the new value is
1454 'newVal'. If the operation fails, then transfer control (with a
1455 no-redir jump (XXX no -- see comment at top of this file)) to
1456 'restart_point', which is presumably the address of the guest
1457 instruction again -- retrying, essentially. */
1458static void casLE ( IRExpr* addr, IRExpr* expVal, IRExpr* newVal,
1459 Addr64 restart_point )
1460{
1461 IRCAS* cas;
1462 IRType tyE = typeOfIRExpr(irsb->tyenv, expVal);
1463 IRType tyN = typeOfIRExpr(irsb->tyenv, newVal);
1464 IRTemp oldTmp = newTemp(tyE);
1465 IRTemp expTmp = newTemp(tyE);
1466 vassert(tyE == tyN);
1467 vassert(tyE == Ity_I64 || tyE == Ity_I32
1468 || tyE == Ity_I16 || tyE == Ity_I8);
1469 assign(expTmp, expVal);
1470 cas = mkIRCAS( IRTemp_INVALID, oldTmp, Iend_LE, addr,
1471 NULL, mkexpr(expTmp), NULL, newVal );
1472 stmt( IRStmt_CAS(cas) );
1473 stmt( IRStmt_Exit(
sewardj1fb8c922009-07-12 12:56:53 +00001474 binop( mkSizedOp(tyE,Iop_CasCmpNE8),
1475 mkexpr(oldTmp), mkexpr(expTmp) ),
sewardje9d8a262009-07-01 08:06:34 +00001476 Ijk_Boring, /*Ijk_NoRedir*/
1477 IRConst_U64( restart_point )
1478 ));
1479}
1480
sewardj5b470602005-02-27 13:10:48 +00001481
sewardj118b23e2005-01-29 02:14:44 +00001482/*------------------------------------------------------------*/
sewardje8f65252005-08-23 23:44:35 +00001483/*--- Helpers for %rflags. ---*/
sewardj118b23e2005-01-29 02:14:44 +00001484/*------------------------------------------------------------*/
1485
1486/* -------------- Evaluating the flags-thunk. -------------- */
1487
1488/* Build IR to calculate all the eflags from stored
1489 CC_OP/CC_DEP1/CC_DEP2/CC_NDEP. Returns an expression ::
1490 Ity_I64. */
1491static IRExpr* mk_amd64g_calculate_rflags_all ( void )
1492{
1493 IRExpr** args
1494 = mkIRExprVec_4( IRExpr_Get(OFFB_CC_OP, Ity_I64),
1495 IRExpr_Get(OFFB_CC_DEP1, Ity_I64),
1496 IRExpr_Get(OFFB_CC_DEP2, Ity_I64),
1497 IRExpr_Get(OFFB_CC_NDEP, Ity_I64) );
1498 IRExpr* call
1499 = mkIRExprCCall(
1500 Ity_I64,
1501 0/*regparm*/,
1502 "amd64g_calculate_rflags_all", &amd64g_calculate_rflags_all,
1503 args
1504 );
1505 /* Exclude OP and NDEP from definedness checking. We're only
1506 interested in DEP1 and DEP2. */
1507 call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<3);
1508 return call;
1509}
sewardj3ca55a12005-01-27 16:06:23 +00001510
1511/* Build IR to calculate some particular condition from stored
1512 CC_OP/CC_DEP1/CC_DEP2/CC_NDEP. Returns an expression ::
1513 Ity_Bit. */
1514static IRExpr* mk_amd64g_calculate_condition ( AMD64Condcode cond )
1515{
1516 IRExpr** args
1517 = mkIRExprVec_5( mkU64(cond),
1518 IRExpr_Get(OFFB_CC_OP, Ity_I64),
1519 IRExpr_Get(OFFB_CC_DEP1, Ity_I64),
1520 IRExpr_Get(OFFB_CC_DEP2, Ity_I64),
1521 IRExpr_Get(OFFB_CC_NDEP, Ity_I64) );
1522 IRExpr* call
1523 = mkIRExprCCall(
1524 Ity_I64,
1525 0/*regparm*/,
1526 "amd64g_calculate_condition", &amd64g_calculate_condition,
1527 args
1528 );
1529 /* Exclude the requested condition, OP and NDEP from definedness
1530 checking. We're only interested in DEP1 and DEP2. */
1531 call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<1) | (1<<4);
sewardje58967e2005-04-27 11:50:56 +00001532 return unop(Iop_64to1, call);
sewardj3ca55a12005-01-27 16:06:23 +00001533}
sewardjdf0e0022005-01-25 15:48:43 +00001534
1535/* Build IR to calculate just the carry flag from stored
1536 CC_OP/CC_DEP1/CC_DEP2/CC_NDEP. Returns an expression :: Ity_I64. */
1537static IRExpr* mk_amd64g_calculate_rflags_c ( void )
1538{
1539 IRExpr** args
1540 = mkIRExprVec_4( IRExpr_Get(OFFB_CC_OP, Ity_I64),
1541 IRExpr_Get(OFFB_CC_DEP1, Ity_I64),
1542 IRExpr_Get(OFFB_CC_DEP2, Ity_I64),
1543 IRExpr_Get(OFFB_CC_NDEP, Ity_I64) );
1544 IRExpr* call
1545 = mkIRExprCCall(
1546 Ity_I64,
1547 0/*regparm*/,
1548 "amd64g_calculate_rflags_c", &amd64g_calculate_rflags_c,
1549 args
1550 );
1551 /* Exclude OP and NDEP from definedness checking. We're only
1552 interested in DEP1 and DEP2. */
1553 call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<3);
1554 return call;
1555}
1556
1557
1558/* -------------- Building the flags-thunk. -------------- */
1559
1560/* The machinery in this section builds the flag-thunk following a
1561 flag-setting operation. Hence the various setFlags_* functions.
1562*/
1563
1564static Bool isAddSub ( IROp op8 )
1565{
sewardj7a240552005-01-28 21:37:12 +00001566 return toBool(op8 == Iop_Add8 || op8 == Iop_Sub8);
sewardjdf0e0022005-01-25 15:48:43 +00001567}
1568
sewardj3ca55a12005-01-27 16:06:23 +00001569static Bool isLogic ( IROp op8 )
1570{
sewardj7a240552005-01-28 21:37:12 +00001571 return toBool(op8 == Iop_And8 || op8 == Iop_Or8 || op8 == Iop_Xor8);
sewardj3ca55a12005-01-27 16:06:23 +00001572}
sewardjdf0e0022005-01-25 15:48:43 +00001573
1574/* U-widen 8/16/32/64 bit int expr to 64. */
1575static IRExpr* widenUto64 ( IRExpr* e )
1576{
sewardjdd40fdf2006-12-24 02:20:24 +00001577 switch (typeOfIRExpr(irsb->tyenv,e)) {
sewardjdf0e0022005-01-25 15:48:43 +00001578 case Ity_I64: return e;
1579 case Ity_I32: return unop(Iop_32Uto64, e);
sewardje58967e2005-04-27 11:50:56 +00001580 case Ity_I16: return unop(Iop_16Uto64, e);
1581 case Ity_I8: return unop(Iop_8Uto64, e);
sewardj118b23e2005-01-29 02:14:44 +00001582 default: vpanic("widenUto64");
sewardjdf0e0022005-01-25 15:48:43 +00001583 }
1584}
1585
sewardj118b23e2005-01-29 02:14:44 +00001586/* S-widen 8/16/32/64 bit int expr to 32. */
1587static IRExpr* widenSto64 ( IRExpr* e )
1588{
sewardjdd40fdf2006-12-24 02:20:24 +00001589 switch (typeOfIRExpr(irsb->tyenv,e)) {
sewardj118b23e2005-01-29 02:14:44 +00001590 case Ity_I64: return e;
1591 case Ity_I32: return unop(Iop_32Sto64, e);
sewardje58967e2005-04-27 11:50:56 +00001592 case Ity_I16: return unop(Iop_16Sto64, e);
1593 case Ity_I8: return unop(Iop_8Sto64, e);
sewardj118b23e2005-01-29 02:14:44 +00001594 default: vpanic("widenSto64");
1595 }
1596}
sewardjdf0e0022005-01-25 15:48:43 +00001597
1598/* Narrow 8/16/32/64 bit int expr to 8/16/32/64. Clearly only some
1599 of these combinations make sense. */
1600static IRExpr* narrowTo ( IRType dst_ty, IRExpr* e )
1601{
sewardjdd40fdf2006-12-24 02:20:24 +00001602 IRType src_ty = typeOfIRExpr(irsb->tyenv,e);
sewardjdf0e0022005-01-25 15:48:43 +00001603 if (src_ty == dst_ty)
1604 return e;
1605 if (src_ty == Ity_I32 && dst_ty == Ity_I16)
1606 return unop(Iop_32to16, e);
1607 if (src_ty == Ity_I32 && dst_ty == Ity_I8)
1608 return unop(Iop_32to8, e);
sewardj118b23e2005-01-29 02:14:44 +00001609 if (src_ty == Ity_I64 && dst_ty == Ity_I32)
1610 return unop(Iop_64to32, e);
1611 if (src_ty == Ity_I64 && dst_ty == Ity_I16)
sewardje58967e2005-04-27 11:50:56 +00001612 return unop(Iop_64to16, e);
sewardj03b07cc2005-01-31 18:09:43 +00001613 if (src_ty == Ity_I64 && dst_ty == Ity_I8)
sewardje58967e2005-04-27 11:50:56 +00001614 return unop(Iop_64to8, e);
sewardjdf0e0022005-01-25 15:48:43 +00001615
1616 vex_printf("\nsrc, dst tys are: ");
1617 ppIRType(src_ty);
1618 vex_printf(", ");
1619 ppIRType(dst_ty);
1620 vex_printf("\n");
1621 vpanic("narrowTo(amd64)");
1622}
1623
1624
1625/* Set the flags thunk OP, DEP1 and DEP2 fields. The supplied op is
1626 auto-sized up to the real op. */
1627
1628static
1629void setFlags_DEP1_DEP2 ( IROp op8, IRTemp dep1, IRTemp dep2, IRType ty )
1630{
1631 Int ccOp = 0;
1632 switch (ty) {
1633 case Ity_I8: ccOp = 0; break;
1634 case Ity_I16: ccOp = 1; break;
1635 case Ity_I32: ccOp = 2; break;
1636 case Ity_I64: ccOp = 3; break;
1637 default: vassert(0);
1638 }
1639 switch (op8) {
1640 case Iop_Add8: ccOp += AMD64G_CC_OP_ADDB; break;
1641 case Iop_Sub8: ccOp += AMD64G_CC_OP_SUBB; break;
1642 default: ppIROp(op8);
1643 vpanic("setFlags_DEP1_DEP2(amd64)");
1644 }
1645 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(ccOp)) );
1646 stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto64(mkexpr(dep1))) );
1647 stmt( IRStmt_Put( OFFB_CC_DEP2, widenUto64(mkexpr(dep2))) );
1648}
1649
1650
1651/* Set the OP and DEP1 fields only, and write zero to DEP2. */
1652
1653static
1654void setFlags_DEP1 ( IROp op8, IRTemp dep1, IRType ty )
1655{
1656 Int ccOp = 0;
1657 switch (ty) {
1658 case Ity_I8: ccOp = 0; break;
1659 case Ity_I16: ccOp = 1; break;
1660 case Ity_I32: ccOp = 2; break;
1661 case Ity_I64: ccOp = 3; break;
1662 default: vassert(0);
1663 }
1664 switch (op8) {
1665 case Iop_Or8:
1666 case Iop_And8:
1667 case Iop_Xor8: ccOp += AMD64G_CC_OP_LOGICB; break;
1668 default: ppIROp(op8);
1669 vpanic("setFlags_DEP1(amd64)");
1670 }
1671 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(ccOp)) );
1672 stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto64(mkexpr(dep1))) );
1673 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0)) );
1674}
1675
1676
sewardj118b23e2005-01-29 02:14:44 +00001677/* For shift operations, we put in the result and the undershifted
1678 result. Except if the shift amount is zero, the thunk is left
1679 unchanged. */
1680
1681static void setFlags_DEP1_DEP2_shift ( IROp op64,
1682 IRTemp res,
1683 IRTemp resUS,
1684 IRType ty,
1685 IRTemp guard )
1686{
1687 Int ccOp = 0;
1688 switch (ty) {
1689 case Ity_I8: ccOp = 0; break;
1690 case Ity_I16: ccOp = 1; break;
1691 case Ity_I32: ccOp = 2; break;
1692 case Ity_I64: ccOp = 3; break;
1693 default: vassert(0);
1694 }
1695
1696 vassert(guard);
1697
1698 /* Both kinds of right shifts are handled by the same thunk
1699 operation. */
1700 switch (op64) {
1701 case Iop_Shr64:
1702 case Iop_Sar64: ccOp += AMD64G_CC_OP_SHRB; break;
1703 case Iop_Shl64: ccOp += AMD64G_CC_OP_SHLB; break;
1704 default: ppIROp(op64);
1705 vpanic("setFlags_DEP1_DEP2_shift(amd64)");
1706 }
1707
1708 /* DEP1 contains the result, DEP2 contains the undershifted value. */
1709 stmt( IRStmt_Put( OFFB_CC_OP,
1710 IRExpr_Mux0X( mkexpr(guard),
1711 IRExpr_Get(OFFB_CC_OP,Ity_I64),
1712 mkU64(ccOp))) );
1713 stmt( IRStmt_Put( OFFB_CC_DEP1,
1714 IRExpr_Mux0X( mkexpr(guard),
1715 IRExpr_Get(OFFB_CC_DEP1,Ity_I64),
1716 widenUto64(mkexpr(res)))) );
1717 stmt( IRStmt_Put( OFFB_CC_DEP2,
1718 IRExpr_Mux0X( mkexpr(guard),
1719 IRExpr_Get(OFFB_CC_DEP2,Ity_I64),
1720 widenUto64(mkexpr(resUS)))) );
1721}
sewardj354e5c62005-01-27 20:12:52 +00001722
1723
1724/* For the inc/dec case, we store in DEP1 the result value and in NDEP
1725 the former value of the carry flag, which unfortunately we have to
1726 compute. */
1727
1728static void setFlags_INC_DEC ( Bool inc, IRTemp res, IRType ty )
1729{
1730 Int ccOp = inc ? AMD64G_CC_OP_INCB : AMD64G_CC_OP_DECB;
1731
1732 switch (ty) {
1733 case Ity_I8: ccOp += 0; break;
1734 case Ity_I16: ccOp += 1; break;
1735 case Ity_I32: ccOp += 2; break;
1736 case Ity_I64: ccOp += 3; break;
1737 default: vassert(0);
1738 }
1739
1740 /* This has to come first, because calculating the C flag
1741 may require reading all four thunk fields. */
1742 stmt( IRStmt_Put( OFFB_CC_NDEP, mk_amd64g_calculate_rflags_c()) );
1743 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(ccOp)) );
sewardj478646f2008-05-01 20:13:04 +00001744 stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto64(mkexpr(res))) );
sewardj354e5c62005-01-27 20:12:52 +00001745 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0)) );
1746}
1747
1748
sewardj32b2bbe2005-01-28 00:50:10 +00001749/* Multiplies are pretty much like add and sub: DEP1 and DEP2 hold the
1750 two arguments. */
1751
1752static
1753void setFlags_MUL ( IRType ty, IRTemp arg1, IRTemp arg2, ULong base_op )
1754{
1755 switch (ty) {
1756 case Ity_I8:
1757 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(base_op+0) ) );
1758 break;
1759 case Ity_I16:
1760 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(base_op+1) ) );
1761 break;
1762 case Ity_I32:
1763 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(base_op+2) ) );
1764 break;
1765 case Ity_I64:
1766 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(base_op+3) ) );
1767 break;
1768 default:
1769 vpanic("setFlags_MUL(amd64)");
1770 }
1771 stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto64(mkexpr(arg1)) ));
1772 stmt( IRStmt_Put( OFFB_CC_DEP2, widenUto64(mkexpr(arg2)) ));
1773}
sewardj3ca55a12005-01-27 16:06:23 +00001774
1775
1776/* -------------- Condition codes. -------------- */
1777
1778/* Condition codes, using the AMD encoding. */
1779
sewardj8c332e22005-01-28 01:36:56 +00001780static HChar* name_AMD64Condcode ( AMD64Condcode cond )
sewardj3ca55a12005-01-27 16:06:23 +00001781{
1782 switch (cond) {
1783 case AMD64CondO: return "o";
1784 case AMD64CondNO: return "no";
1785 case AMD64CondB: return "b";
sewardje941eea2005-01-30 19:52:28 +00001786 case AMD64CondNB: return "ae"; /*"nb";*/
1787 case AMD64CondZ: return "e"; /*"z";*/
1788 case AMD64CondNZ: return "ne"; /*"nz";*/
sewardj3ca55a12005-01-27 16:06:23 +00001789 case AMD64CondBE: return "be";
sewardje941eea2005-01-30 19:52:28 +00001790 case AMD64CondNBE: return "a"; /*"nbe";*/
sewardj3ca55a12005-01-27 16:06:23 +00001791 case AMD64CondS: return "s";
1792 case AMD64CondNS: return "ns";
1793 case AMD64CondP: return "p";
1794 case AMD64CondNP: return "np";
1795 case AMD64CondL: return "l";
sewardje941eea2005-01-30 19:52:28 +00001796 case AMD64CondNL: return "ge"; /*"nl";*/
sewardj3ca55a12005-01-27 16:06:23 +00001797 case AMD64CondLE: return "le";
sewardje941eea2005-01-30 19:52:28 +00001798 case AMD64CondNLE: return "g"; /*"nle";*/
sewardj3ca55a12005-01-27 16:06:23 +00001799 case AMD64CondAlways: return "ALWAYS";
1800 default: vpanic("name_AMD64Condcode");
1801 }
1802}
1803
sewardj1389d4d2005-01-28 13:46:29 +00001804static
1805AMD64Condcode positiveIse_AMD64Condcode ( AMD64Condcode cond,
1806 /*OUT*/Bool* needInvert )
1807{
1808 vassert(cond >= AMD64CondO && cond <= AMD64CondNLE);
1809 if (cond & 1) {
1810 *needInvert = True;
1811 return cond-1;
1812 } else {
1813 *needInvert = False;
1814 return cond;
1815 }
1816}
sewardjdf0e0022005-01-25 15:48:43 +00001817
1818
1819/* -------------- Helpers for ADD/SUB with carry. -------------- */
1820
1821/* Given ta1, ta2 and tres, compute tres = ADC(ta1,ta2) and set flags
1822 appropriately.
sewardje9d8a262009-07-01 08:06:34 +00001823
1824 Optionally, generate a store for the 'tres' value. This can either
1825 be a normal store, or it can be a cas-with-possible-failure style
1826 store:
1827
1828 if taddr is IRTemp_INVALID, then no store is generated.
1829
1830 if taddr is not IRTemp_INVALID, then a store (using taddr as
1831 the address) is generated:
1832
1833 if texpVal is IRTemp_INVALID then a normal store is
1834 generated, and restart_point must be zero (it is irrelevant).
1835
1836 if texpVal is not IRTemp_INVALID then a cas-style store is
1837 generated. texpVal is the expected value, restart_point
1838 is the restart point if the store fails, and texpVal must
1839 have the same type as tres.
1840
sewardjdf0e0022005-01-25 15:48:43 +00001841*/
1842static void helper_ADC ( Int sz,
sewardje9d8a262009-07-01 08:06:34 +00001843 IRTemp tres, IRTemp ta1, IRTemp ta2,
1844 /* info about optional store: */
1845 IRTemp taddr, IRTemp texpVal, Addr32 restart_point )
sewardjdf0e0022005-01-25 15:48:43 +00001846{
1847 UInt thunkOp;
1848 IRType ty = szToITy(sz);
1849 IRTemp oldc = newTemp(Ity_I64);
1850 IRTemp oldcn = newTemp(ty);
1851 IROp plus = mkSizedOp(ty, Iop_Add8);
1852 IROp xor = mkSizedOp(ty, Iop_Xor8);
1853
sewardje9d8a262009-07-01 08:06:34 +00001854 vassert(typeOfIRTemp(irsb->tyenv, tres) == ty);
1855
sewardjdf0e0022005-01-25 15:48:43 +00001856 switch (sz) {
1857 case 8: thunkOp = AMD64G_CC_OP_ADCQ; break;
1858 case 4: thunkOp = AMD64G_CC_OP_ADCL; break;
1859 case 2: thunkOp = AMD64G_CC_OP_ADCW; break;
1860 case 1: thunkOp = AMD64G_CC_OP_ADCB; break;
1861 default: vassert(0);
1862 }
1863
1864 /* oldc = old carry flag, 0 or 1 */
1865 assign( oldc, binop(Iop_And64,
1866 mk_amd64g_calculate_rflags_c(),
1867 mkU64(1)) );
1868
1869 assign( oldcn, narrowTo(ty, mkexpr(oldc)) );
1870
1871 assign( tres, binop(plus,
1872 binop(plus,mkexpr(ta1),mkexpr(ta2)),
1873 mkexpr(oldcn)) );
1874
sewardje9d8a262009-07-01 08:06:34 +00001875 /* Possibly generate a store of 'tres' to 'taddr'. See comment at
1876 start of this function. */
1877 if (taddr != IRTemp_INVALID) {
1878 if (texpVal == IRTemp_INVALID) {
1879 vassert(restart_point == 0);
1880 storeLE( mkexpr(taddr), mkexpr(tres) );
1881 } else {
1882 vassert(typeOfIRTemp(irsb->tyenv, texpVal) == ty);
1883 /* .. and hence 'texpVal' has the same type as 'tres'. */
1884 casLE( mkexpr(taddr),
1885 mkexpr(texpVal), mkexpr(tres), restart_point );
1886 }
1887 }
1888
sewardjdf0e0022005-01-25 15:48:43 +00001889 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(thunkOp) ) );
sewardj820611e2005-08-24 10:56:01 +00001890 stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto64(mkexpr(ta1)) ));
1891 stmt( IRStmt_Put( OFFB_CC_DEP2, widenUto64(binop(xor, mkexpr(ta2),
1892 mkexpr(oldcn)) )) );
sewardjdf0e0022005-01-25 15:48:43 +00001893 stmt( IRStmt_Put( OFFB_CC_NDEP, mkexpr(oldc) ) );
1894}
1895
1896
1897/* Given ta1, ta2 and tres, compute tres = SBB(ta1,ta2) and set flags
sewardje9d8a262009-07-01 08:06:34 +00001898 appropriately. As with helper_ADC, possibly generate a store of
1899 the result -- see comments on helper_ADC for details.
sewardjdf0e0022005-01-25 15:48:43 +00001900*/
1901static void helper_SBB ( Int sz,
sewardje9d8a262009-07-01 08:06:34 +00001902 IRTemp tres, IRTemp ta1, IRTemp ta2,
1903 /* info about optional store: */
1904 IRTemp taddr, IRTemp texpVal, Addr32 restart_point )
sewardjdf0e0022005-01-25 15:48:43 +00001905{
1906 UInt thunkOp;
1907 IRType ty = szToITy(sz);
1908 IRTemp oldc = newTemp(Ity_I64);
1909 IRTemp oldcn = newTemp(ty);
1910 IROp minus = mkSizedOp(ty, Iop_Sub8);
1911 IROp xor = mkSizedOp(ty, Iop_Xor8);
1912
sewardje9d8a262009-07-01 08:06:34 +00001913 vassert(typeOfIRTemp(irsb->tyenv, tres) == ty);
1914
sewardjdf0e0022005-01-25 15:48:43 +00001915 switch (sz) {
1916 case 8: thunkOp = AMD64G_CC_OP_SBBQ; break;
1917 case 4: thunkOp = AMD64G_CC_OP_SBBL; break;
1918 case 2: thunkOp = AMD64G_CC_OP_SBBW; break;
1919 case 1: thunkOp = AMD64G_CC_OP_SBBB; break;
1920 default: vassert(0);
1921 }
1922
1923 /* oldc = old carry flag, 0 or 1 */
1924 assign( oldc, binop(Iop_And64,
1925 mk_amd64g_calculate_rflags_c(),
1926 mkU64(1)) );
1927
1928 assign( oldcn, narrowTo(ty, mkexpr(oldc)) );
1929
1930 assign( tres, binop(minus,
1931 binop(minus,mkexpr(ta1),mkexpr(ta2)),
1932 mkexpr(oldcn)) );
1933
sewardje9d8a262009-07-01 08:06:34 +00001934 /* Possibly generate a store of 'tres' to 'taddr'. See comment at
1935 start of this function. */
1936 if (taddr != IRTemp_INVALID) {
1937 if (texpVal == IRTemp_INVALID) {
1938 vassert(restart_point == 0);
1939 storeLE( mkexpr(taddr), mkexpr(tres) );
1940 } else {
1941 vassert(typeOfIRTemp(irsb->tyenv, texpVal) == ty);
1942 /* .. and hence 'texpVal' has the same type as 'tres'. */
1943 casLE( mkexpr(taddr),
1944 mkexpr(texpVal), mkexpr(tres), restart_point );
1945 }
1946 }
1947
sewardjdf0e0022005-01-25 15:48:43 +00001948 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(thunkOp) ) );
sewardj820611e2005-08-24 10:56:01 +00001949 stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto64(mkexpr(ta1) )) );
1950 stmt( IRStmt_Put( OFFB_CC_DEP2, widenUto64(binop(xor, mkexpr(ta2),
1951 mkexpr(oldcn)) )) );
sewardjdf0e0022005-01-25 15:48:43 +00001952 stmt( IRStmt_Put( OFFB_CC_NDEP, mkexpr(oldc) ) );
1953}
1954
1955
sewardj3ca55a12005-01-27 16:06:23 +00001956/* -------------- Helpers for disassembly printing. -------------- */
1957
1958static HChar* nameGrp1 ( Int opc_aux )
1959{
1960 static HChar* grp1_names[8]
1961 = { "add", "or", "adc", "sbb", "and", "sub", "xor", "cmp" };
1962 if (opc_aux < 0 || opc_aux > 7) vpanic("nameGrp1(amd64)");
1963 return grp1_names[opc_aux];
1964}
1965
sewardj118b23e2005-01-29 02:14:44 +00001966static HChar* nameGrp2 ( Int opc_aux )
1967{
1968 static HChar* grp2_names[8]
1969 = { "rol", "ror", "rcl", "rcr", "shl", "shr", "shl", "sar" };
sewardje941eea2005-01-30 19:52:28 +00001970 if (opc_aux < 0 || opc_aux > 7) vpanic("nameGrp2(amd64)");
sewardj118b23e2005-01-29 02:14:44 +00001971 return grp2_names[opc_aux];
1972}
1973
sewardj03b07cc2005-01-31 18:09:43 +00001974static HChar* nameGrp4 ( Int opc_aux )
1975{
1976 static HChar* grp4_names[8]
1977 = { "inc", "dec", "???", "???", "???", "???", "???", "???" };
1978 if (opc_aux < 0 || opc_aux > 1) vpanic("nameGrp4(amd64)");
1979 return grp4_names[opc_aux];
1980}
sewardj354e5c62005-01-27 20:12:52 +00001981
1982static HChar* nameGrp5 ( Int opc_aux )
1983{
1984 static HChar* grp5_names[8]
1985 = { "inc", "dec", "call*", "call*", "jmp*", "jmp*", "push", "???" };
1986 if (opc_aux < 0 || opc_aux > 6) vpanic("nameGrp5(amd64)");
1987 return grp5_names[opc_aux];
1988}
1989
sewardj1d511802005-03-27 17:59:45 +00001990static HChar* nameGrp8 ( Int opc_aux )
1991{
1992 static HChar* grp8_names[8]
1993 = { "???", "???", "???", "???", "bt", "bts", "btr", "btc" };
1994 if (opc_aux < 4 || opc_aux > 7) vpanic("nameGrp8(amd64)");
1995 return grp8_names[opc_aux];
1996}
1997
sewardjd20c8852005-01-20 20:04:07 +00001998//.. static HChar* nameSReg ( UInt sreg )
1999//.. {
2000//.. switch (sreg) {
2001//.. case R_ES: return "%es";
2002//.. case R_CS: return "%cs";
2003//.. case R_SS: return "%ss";
2004//.. case R_DS: return "%ds";
2005//.. case R_FS: return "%fs";
2006//.. case R_GS: return "%gs";
2007//.. default: vpanic("nameSReg(x86)");
2008//.. }
2009//.. }
sewardj8711f662005-05-09 17:52:56 +00002010
2011static HChar* nameMMXReg ( Int mmxreg )
2012{
2013 static HChar* mmx_names[8]
2014 = { "%mm0", "%mm1", "%mm2", "%mm3", "%mm4", "%mm5", "%mm6", "%mm7" };
2015 if (mmxreg < 0 || mmxreg > 7) vpanic("nameMMXReg(amd64,guest)");
2016 return mmx_names[mmxreg];
2017}
sewardj1001dc42005-02-21 08:25:55 +00002018
2019static HChar* nameXMMReg ( Int xmmreg )
2020{
2021 static HChar* xmm_names[16]
2022 = { "%xmm0", "%xmm1", "%xmm2", "%xmm3",
2023 "%xmm4", "%xmm5", "%xmm6", "%xmm7",
2024 "%xmm8", "%xmm9", "%xmm10", "%xmm11",
2025 "%xmm12", "%xmm13", "%xmm14", "%xmm15" };
2026 if (xmmreg < 0 || xmmreg > 15) vpanic("nameXMMReg(amd64)");
2027 return xmm_names[xmmreg];
2028}
2029
sewardjca673ab2005-05-11 10:03:08 +00002030static HChar* nameMMXGran ( Int gran )
sewardj8711f662005-05-09 17:52:56 +00002031{
2032 switch (gran) {
2033 case 0: return "b";
2034 case 1: return "w";
2035 case 2: return "d";
2036 case 3: return "q";
2037 default: vpanic("nameMMXGran(amd64,guest)");
2038 }
2039}
sewardjdf0e0022005-01-25 15:48:43 +00002040
sewardj8c332e22005-01-28 01:36:56 +00002041static HChar nameISize ( Int size )
sewardjdf0e0022005-01-25 15:48:43 +00002042{
2043 switch (size) {
2044 case 8: return 'q';
2045 case 4: return 'l';
2046 case 2: return 'w';
2047 case 1: return 'b';
2048 default: vpanic("nameISize(amd64)");
2049 }
2050}
2051
2052
2053/*------------------------------------------------------------*/
2054/*--- JMP helpers ---*/
2055/*------------------------------------------------------------*/
2056
2057static void jmp_lit( IRJumpKind kind, Addr64 d64 )
2058{
sewardjdd40fdf2006-12-24 02:20:24 +00002059 irsb->next = mkU64(d64);
2060 irsb->jumpkind = kind;
sewardjdf0e0022005-01-25 15:48:43 +00002061}
2062
sewardj2f959cc2005-01-26 01:19:35 +00002063static void jmp_treg( IRJumpKind kind, IRTemp t )
2064{
sewardjdd40fdf2006-12-24 02:20:24 +00002065 irsb->next = mkexpr(t);
2066 irsb->jumpkind = kind;
sewardj2f959cc2005-01-26 01:19:35 +00002067}
2068
sewardj1389d4d2005-01-28 13:46:29 +00002069static
2070void jcc_01 ( AMD64Condcode cond, Addr64 d64_false, Addr64 d64_true )
2071{
2072 Bool invert;
2073 AMD64Condcode condPos;
2074 condPos = positiveIse_AMD64Condcode ( cond, &invert );
2075 if (invert) {
2076 stmt( IRStmt_Exit( mk_amd64g_calculate_condition(condPos),
2077 Ijk_Boring,
2078 IRConst_U64(d64_false) ) );
sewardjdd40fdf2006-12-24 02:20:24 +00002079 irsb->next = mkU64(d64_true);
2080 irsb->jumpkind = Ijk_Boring;
sewardj1389d4d2005-01-28 13:46:29 +00002081 } else {
2082 stmt( IRStmt_Exit( mk_amd64g_calculate_condition(condPos),
2083 Ijk_Boring,
2084 IRConst_U64(d64_true) ) );
sewardjdd40fdf2006-12-24 02:20:24 +00002085 irsb->next = mkU64(d64_false);
2086 irsb->jumpkind = Ijk_Boring;
sewardj1389d4d2005-01-28 13:46:29 +00002087 }
2088}
sewardjb3a04292005-01-21 20:33:44 +00002089
sewardj478646f2008-05-01 20:13:04 +00002090/* Let new_rsp be the %rsp value after a call/return. Let nia be the
2091 guest address of the next instruction to be executed.
2092
2093 This function generates an AbiHint to say that -128(%rsp)
2094 .. -1(%rsp) should now be regarded as uninitialised.
sewardj5a9ffab2005-05-12 17:55:01 +00002095*/
sewardjaca070a2006-10-17 00:28:22 +00002096static
sewardj478646f2008-05-01 20:13:04 +00002097void make_redzone_AbiHint ( VexAbiInfo* vbi,
2098 IRTemp new_rsp, IRTemp nia, HChar* who )
sewardj5a9ffab2005-05-12 17:55:01 +00002099{
sewardjdd40fdf2006-12-24 02:20:24 +00002100 Int szB = vbi->guest_stack_redzone_size;
sewardjaca070a2006-10-17 00:28:22 +00002101 vassert(szB >= 0);
2102
2103 /* A bit of a kludge. Currently the only AbI we've guested AMD64
2104 for is ELF. So just check it's the expected 128 value
2105 (paranoia). */
2106 vassert(szB == 128);
2107
sewardj5a9ffab2005-05-12 17:55:01 +00002108 if (0) vex_printf("AbiHint: %s\n", who);
sewardjdd40fdf2006-12-24 02:20:24 +00002109 vassert(typeOfIRTemp(irsb->tyenv, new_rsp) == Ity_I64);
sewardj478646f2008-05-01 20:13:04 +00002110 vassert(typeOfIRTemp(irsb->tyenv, nia) == Ity_I64);
sewardjaca070a2006-10-17 00:28:22 +00002111 if (szB > 0)
2112 stmt( IRStmt_AbiHint(
2113 binop(Iop_Sub64, mkexpr(new_rsp), mkU64(szB)),
sewardj478646f2008-05-01 20:13:04 +00002114 szB,
2115 mkexpr(nia)
sewardjaca070a2006-10-17 00:28:22 +00002116 ));
sewardj5a9ffab2005-05-12 17:55:01 +00002117}
2118
sewardjb3a04292005-01-21 20:33:44 +00002119
2120/*------------------------------------------------------------*/
2121/*--- Disassembling addressing modes ---*/
2122/*------------------------------------------------------------*/
2123
2124static
sewardjc4356f02007-11-09 21:15:04 +00002125HChar* segRegTxt ( Prefix pfx )
sewardjb3a04292005-01-21 20:33:44 +00002126{
2127 if (pfx & PFX_CS) return "%cs:";
2128 if (pfx & PFX_DS) return "%ds:";
2129 if (pfx & PFX_ES) return "%es:";
2130 if (pfx & PFX_FS) return "%fs:";
2131 if (pfx & PFX_GS) return "%gs:";
2132 if (pfx & PFX_SS) return "%ss:";
2133 return ""; /* no override */
2134}
2135
2136
2137/* 'virtual' is an IRExpr* holding a virtual address. Convert it to a
2138 linear address by adding any required segment override as indicated
sewardj42561ef2005-11-04 14:18:31 +00002139 by sorb, and also dealing with any address size override
2140 present. */
sewardjb3a04292005-01-21 20:33:44 +00002141static
sewardj2e28ac42008-12-04 00:05:12 +00002142IRExpr* handleAddrOverrides ( VexAbiInfo* vbi,
2143 Prefix pfx, IRExpr* virtual )
sewardjb3a04292005-01-21 20:33:44 +00002144{
sewardj42561ef2005-11-04 14:18:31 +00002145 /* --- segment overrides --- */
sewardja6b93d12005-02-17 09:28:28 +00002146 if (pfx & PFX_FS) {
sewardj2e28ac42008-12-04 00:05:12 +00002147 if (vbi->guest_amd64_assume_fs_is_zero) {
2148 /* Note that this is a linux-kernel specific hack that relies
2149 on the assumption that %fs is always zero. */
2150 /* return virtual + guest_FS_ZERO. */
2151 virtual = binop(Iop_Add64, virtual,
2152 IRExpr_Get(OFFB_FS_ZERO, Ity_I64));
2153 } else {
2154 unimplemented("amd64 %fs segment override");
2155 }
sewardja6b93d12005-02-17 09:28:28 +00002156 }
sewardjb3a04292005-01-21 20:33:44 +00002157
sewardja6b93d12005-02-17 09:28:28 +00002158 if (pfx & PFX_GS) {
sewardj2e28ac42008-12-04 00:05:12 +00002159 if (vbi->guest_amd64_assume_gs_is_0x60) {
2160 /* Note that this is a darwin-kernel specific hack that relies
2161 on the assumption that %gs is always 0x60. */
2162 /* return virtual + guest_GS_0x60. */
2163 virtual = binop(Iop_Add64, virtual,
2164 IRExpr_Get(OFFB_GS_0x60, Ity_I64));
2165 } else {
2166 unimplemented("amd64 %gs segment override");
2167 }
sewardja6b93d12005-02-17 09:28:28 +00002168 }
2169
2170 /* cs, ds, es and ss are simply ignored in 64-bit mode. */
sewardj42561ef2005-11-04 14:18:31 +00002171
2172 /* --- address size override --- */
2173 if (haveASO(pfx))
2174 virtual = unop(Iop_32Uto64, unop(Iop_64to32, virtual));
2175
sewardja6b93d12005-02-17 09:28:28 +00002176 return virtual;
sewardjb3a04292005-01-21 20:33:44 +00002177}
sewardja6b93d12005-02-17 09:28:28 +00002178
sewardjd20c8852005-01-20 20:04:07 +00002179//.. {
2180//.. Int sreg;
2181//.. IRType hWordTy;
2182//.. IRTemp ldt_ptr, gdt_ptr, seg_selector, r64;
2183//..
2184//.. if (sorb == 0)
2185//.. /* the common case - no override */
2186//.. return virtual;
2187//..
2188//.. switch (sorb) {
2189//.. case 0x3E: sreg = R_DS; break;
2190//.. case 0x26: sreg = R_ES; break;
2191//.. case 0x64: sreg = R_FS; break;
2192//.. case 0x65: sreg = R_GS; break;
sewardj42561ef2005-11-04 14:18:31 +00002193//.. default: vpanic("handleAddrOverrides(x86,guest)");
sewardjd20c8852005-01-20 20:04:07 +00002194//.. }
2195//..
2196//.. hWordTy = sizeof(HWord)==4 ? Ity_I32 : Ity_I64;
2197//..
2198//.. seg_selector = newTemp(Ity_I32);
2199//.. ldt_ptr = newTemp(hWordTy);
2200//.. gdt_ptr = newTemp(hWordTy);
2201//.. r64 = newTemp(Ity_I64);
2202//..
2203//.. assign( seg_selector, unop(Iop_16Uto32, getSReg(sreg)) );
2204//.. assign( ldt_ptr, IRExpr_Get( OFFB_LDT, hWordTy ));
2205//.. assign( gdt_ptr, IRExpr_Get( OFFB_GDT, hWordTy ));
2206//..
2207//.. /*
2208//.. Call this to do the translation and limit checks:
2209//.. ULong x86g_use_seg_selector ( HWord ldt, HWord gdt,
2210//.. UInt seg_selector, UInt virtual_addr )
2211//.. */
2212//.. assign(
2213//.. r64,
2214//.. mkIRExprCCall(
2215//.. Ity_I64,
2216//.. 0/*regparms*/,
2217//.. "x86g_use_seg_selector",
2218//.. &x86g_use_seg_selector,
2219//.. mkIRExprVec_4( mkexpr(ldt_ptr), mkexpr(gdt_ptr),
2220//.. mkexpr(seg_selector), virtual)
2221//.. )
2222//.. );
2223//..
2224//.. /* If the high 32 of the result are non-zero, there was a
2225//.. failure in address translation. In which case, make a
2226//.. quick exit.
2227//.. */
2228//.. stmt(
2229//.. IRStmt_Exit(
2230//.. binop(Iop_CmpNE32, unop(Iop_64HIto32, mkexpr(r64)), mkU32(0)),
2231//.. Ijk_MapFail,
2232//.. IRConst_U32( guest_eip_curr_instr )
2233//.. )
2234//.. );
2235//..
2236//.. /* otherwise, here's the translated result. */
2237//.. return unop(Iop_64to32, mkexpr(r64));
2238//.. }
sewardjb3a04292005-01-21 20:33:44 +00002239
2240
2241/* Generate IR to calculate an address indicated by a ModRM and
2242 following SIB bytes. The expression, and the number of bytes in
2243 the address mode, are returned (the latter in *len). Note that
2244 this fn should not be called if the R/M part of the address denotes
2245 a register instead of memory. If print_codegen is true, text of
2246 the addressing mode is placed in buf.
2247
2248 The computed address is stored in a new tempreg, and the
sewardje1698952005-02-08 15:02:39 +00002249 identity of the tempreg is returned.
2250
2251 extra_bytes holds the number of bytes after the amode, as supplied
2252 by the caller. This is needed to make sense of %rip-relative
2253 addresses. Note that the value that *len is set to is only the
2254 length of the amode itself and does not include the value supplied
sewardj09717342005-05-05 21:34:02 +00002255 in extra_bytes.
sewardje1698952005-02-08 15:02:39 +00002256 */
sewardjb3a04292005-01-21 20:33:44 +00002257
2258static IRTemp disAMode_copy2tmp ( IRExpr* addr64 )
2259{
2260 IRTemp tmp = newTemp(Ity_I64);
2261 assign( tmp, addr64 );
2262 return tmp;
2263}
2264
2265static
sewardj2e28ac42008-12-04 00:05:12 +00002266IRTemp disAMode ( /*OUT*/Int* len,
2267 VexAbiInfo* vbi, Prefix pfx, Long delta,
2268 /*OUT*/HChar* buf, Int extra_bytes )
sewardjb3a04292005-01-21 20:33:44 +00002269{
sewardj8c332e22005-01-28 01:36:56 +00002270 UChar mod_reg_rm = getUChar(delta);
sewardjb3a04292005-01-21 20:33:44 +00002271 delta++;
2272
2273 buf[0] = (UChar)0;
sewardje1698952005-02-08 15:02:39 +00002274 vassert(extra_bytes >= 0 && extra_bytes < 10);
sewardjb3a04292005-01-21 20:33:44 +00002275
2276 /* squeeze out the reg field from mod_reg_rm, since a 256-entry
2277 jump table seems a bit excessive.
2278 */
sewardj7a240552005-01-28 21:37:12 +00002279 mod_reg_rm &= 0xC7; /* is now XX000YYY */
sewardj1027dc22005-02-26 01:55:02 +00002280 mod_reg_rm = toUChar(mod_reg_rm | (mod_reg_rm >> 3));
2281 /* is now XX0XXYYY */
sewardj7a240552005-01-28 21:37:12 +00002282 mod_reg_rm &= 0x1F; /* is now 000XXYYY */
sewardjb3a04292005-01-21 20:33:44 +00002283 switch (mod_reg_rm) {
2284
2285 /* REX.B==0: (%rax) .. (%rdi), not including (%rsp) or (%rbp).
2286 REX.B==1: (%r8) .. (%r15), not including (%r12) or (%r13).
2287 */
2288 case 0x00: case 0x01: case 0x02: case 0x03:
2289 /* ! 04 */ /* ! 05 */ case 0x06: case 0x07:
sewardj1027dc22005-02-26 01:55:02 +00002290 { UChar rm = toUChar(mod_reg_rm & 7);
sewardjc4356f02007-11-09 21:15:04 +00002291 DIS(buf, "%s(%s)", segRegTxt(pfx), nameIRegRexB(8,pfx,rm));
sewardjb3a04292005-01-21 20:33:44 +00002292 *len = 1;
2293 return disAMode_copy2tmp(
sewardj2e28ac42008-12-04 00:05:12 +00002294 handleAddrOverrides(vbi, pfx, getIRegRexB(8,pfx,rm)));
sewardjb3a04292005-01-21 20:33:44 +00002295 }
2296
2297 /* REX.B==0: d8(%rax) ... d8(%rdi), not including d8(%rsp)
2298 REX.B==1: d8(%r8) ... d8(%r15), not including d8(%r12)
2299 */
2300 case 0x08: case 0x09: case 0x0A: case 0x0B:
2301 /* ! 0C */ case 0x0D: case 0x0E: case 0x0F:
sewardj1027dc22005-02-26 01:55:02 +00002302 { UChar rm = toUChar(mod_reg_rm & 7);
sewardj8c332e22005-01-28 01:36:56 +00002303 Long d = getSDisp8(delta);
sewardj7eaa7cf2005-01-31 18:55:22 +00002304 if (d == 0) {
sewardjc4356f02007-11-09 21:15:04 +00002305 DIS(buf, "%s(%s)", segRegTxt(pfx), nameIRegRexB(8,pfx,rm));
sewardj7eaa7cf2005-01-31 18:55:22 +00002306 } else {
sewardjc4356f02007-11-09 21:15:04 +00002307 DIS(buf, "%s%lld(%s)", segRegTxt(pfx), d, nameIRegRexB(8,pfx,rm));
sewardj7eaa7cf2005-01-31 18:55:22 +00002308 }
sewardjb3a04292005-01-21 20:33:44 +00002309 *len = 2;
2310 return disAMode_copy2tmp(
sewardj2e28ac42008-12-04 00:05:12 +00002311 handleAddrOverrides(vbi, pfx,
sewardj5b470602005-02-27 13:10:48 +00002312 binop(Iop_Add64,getIRegRexB(8,pfx,rm),mkU64(d))));
sewardjb3a04292005-01-21 20:33:44 +00002313 }
2314
2315 /* REX.B==0: d32(%rax) ... d32(%rdi), not including d32(%rsp)
2316 REX.B==1: d32(%r8) ... d32(%r15), not including d32(%r12)
2317 */
2318 case 0x10: case 0x11: case 0x12: case 0x13:
2319 /* ! 14 */ case 0x15: case 0x16: case 0x17:
sewardj1027dc22005-02-26 01:55:02 +00002320 { UChar rm = toUChar(mod_reg_rm & 7);
sewardj227458e2005-01-31 19:04:50 +00002321 Long d = getSDisp32(delta);
sewardjc4356f02007-11-09 21:15:04 +00002322 DIS(buf, "%s%lld(%s)", segRegTxt(pfx), d, nameIRegRexB(8,pfx,rm));
sewardjb3a04292005-01-21 20:33:44 +00002323 *len = 5;
2324 return disAMode_copy2tmp(
sewardj2e28ac42008-12-04 00:05:12 +00002325 handleAddrOverrides(vbi, pfx,
sewardj5b470602005-02-27 13:10:48 +00002326 binop(Iop_Add64,getIRegRexB(8,pfx,rm),mkU64(d))));
sewardjb3a04292005-01-21 20:33:44 +00002327 }
2328
2329 /* REX.B==0: a register, %rax .. %rdi. This shouldn't happen. */
2330 /* REX.B==1: a register, %r8 .. %r16. This shouldn't happen. */
2331 case 0x18: case 0x19: case 0x1A: case 0x1B:
2332 case 0x1C: case 0x1D: case 0x1E: case 0x1F:
sewardj354e5c62005-01-27 20:12:52 +00002333 vpanic("disAMode(amd64): not an addr!");
sewardjb3a04292005-01-21 20:33:44 +00002334
sewardj9e6491a2005-07-02 19:24:10 +00002335 /* RIP + disp32. This assumes that guest_RIP_curr_instr is set
sewardjb3a04292005-01-21 20:33:44 +00002336 correctly at the start of handling each instruction. */
2337 case 0x05:
sewardj227458e2005-01-31 19:04:50 +00002338 { Long d = getSDisp32(delta);
sewardjb3a04292005-01-21 20:33:44 +00002339 *len = 5;
sewardjc4356f02007-11-09 21:15:04 +00002340 DIS(buf, "%s%lld(%%rip)", segRegTxt(pfx), d);
sewardj4b744762005-02-07 15:02:25 +00002341 /* We need to know the next instruction's start address.
2342 Try and figure out what it is, record the guess, and ask
2343 the top-level driver logic (bbToIR_AMD64) to check we
2344 guessed right, after the instruction is completely
2345 decoded. */
sewardj9e6491a2005-07-02 19:24:10 +00002346 guest_RIP_next_mustcheck = True;
2347 guest_RIP_next_assumed = guest_RIP_bbstart
sewardje1698952005-02-08 15:02:39 +00002348 + delta+4 + extra_bytes;
sewardjb3a04292005-01-21 20:33:44 +00002349 return disAMode_copy2tmp(
sewardj2e28ac42008-12-04 00:05:12 +00002350 handleAddrOverrides(vbi, pfx,
sewardj9e6491a2005-07-02 19:24:10 +00002351 binop(Iop_Add64, mkU64(guest_RIP_next_assumed),
sewardjb3a04292005-01-21 20:33:44 +00002352 mkU64(d))));
2353 }
sewardj3ca55a12005-01-27 16:06:23 +00002354
sewardj2f959cc2005-01-26 01:19:35 +00002355 case 0x04: {
2356 /* SIB, with no displacement. Special cases:
sewardj3ca55a12005-01-27 16:06:23 +00002357 -- %rsp cannot act as an index value.
2358 If index_r indicates %rsp, zero is used for the index.
2359 -- when mod is zero and base indicates RBP or R13, base is
2360 instead a 32-bit sign-extended literal.
sewardj2f959cc2005-01-26 01:19:35 +00002361 It's all madness, I tell you. Extract %index, %base and
2362 scale from the SIB byte. The value denoted is then:
sewardj3ca55a12005-01-27 16:06:23 +00002363 | %index == %RSP && (%base == %RBP || %base == %R13)
sewardj2f959cc2005-01-26 01:19:35 +00002364 = d32 following SIB byte
sewardj3ca55a12005-01-27 16:06:23 +00002365 | %index == %RSP && !(%base == %RBP || %base == %R13)
sewardj2f959cc2005-01-26 01:19:35 +00002366 = %base
sewardj3ca55a12005-01-27 16:06:23 +00002367 | %index != %RSP && (%base == %RBP || %base == %R13)
sewardj2f959cc2005-01-26 01:19:35 +00002368 = d32 following SIB byte + (%index << scale)
sewardj3ca55a12005-01-27 16:06:23 +00002369 | %index != %RSP && !(%base == %RBP || %base == %R13)
sewardj2f959cc2005-01-26 01:19:35 +00002370 = %base + (%index << scale)
2371 */
sewardj8c332e22005-01-28 01:36:56 +00002372 UChar sib = getUChar(delta);
sewardj1027dc22005-02-26 01:55:02 +00002373 UChar scale = toUChar((sib >> 6) & 3);
2374 UChar index_r = toUChar((sib >> 3) & 7);
2375 UChar base_r = toUChar(sib & 7);
sewardj3ca55a12005-01-27 16:06:23 +00002376 /* correct since #(R13) == 8 + #(RBP) */
sewardj7a240552005-01-28 21:37:12 +00002377 Bool base_is_BPor13 = toBool(base_r == R_RBP);
2378 Bool index_is_SP = toBool(index_r == R_RSP && 0==getRexX(pfx));
sewardj2f959cc2005-01-26 01:19:35 +00002379 delta++;
sewardjb3a04292005-01-21 20:33:44 +00002380
sewardj3ca55a12005-01-27 16:06:23 +00002381 if ((!index_is_SP) && (!base_is_BPor13)) {
sewardje941eea2005-01-30 19:52:28 +00002382 if (scale == 0) {
sewardjc4356f02007-11-09 21:15:04 +00002383 DIS(buf, "%s(%s,%s)", segRegTxt(pfx),
sewardj5b470602005-02-27 13:10:48 +00002384 nameIRegRexB(8,pfx,base_r),
2385 nameIReg64rexX(pfx,index_r));
sewardje941eea2005-01-30 19:52:28 +00002386 } else {
sewardjc4356f02007-11-09 21:15:04 +00002387 DIS(buf, "%s(%s,%s,%d)", segRegTxt(pfx),
sewardj5b470602005-02-27 13:10:48 +00002388 nameIRegRexB(8,pfx,base_r),
2389 nameIReg64rexX(pfx,index_r), 1<<scale);
sewardje941eea2005-01-30 19:52:28 +00002390 }
sewardj2f959cc2005-01-26 01:19:35 +00002391 *len = 2;
sewardj2f959cc2005-01-26 01:19:35 +00002392 return
2393 disAMode_copy2tmp(
sewardj2e28ac42008-12-04 00:05:12 +00002394 handleAddrOverrides(vbi, pfx,
sewardj3ca55a12005-01-27 16:06:23 +00002395 binop(Iop_Add64,
sewardj5b470602005-02-27 13:10:48 +00002396 getIRegRexB(8,pfx,base_r),
2397 binop(Iop_Shl64, getIReg64rexX(pfx,index_r),
sewardj2f959cc2005-01-26 01:19:35 +00002398 mkU8(scale)))));
2399 }
2400
sewardj3ca55a12005-01-27 16:06:23 +00002401 if ((!index_is_SP) && base_is_BPor13) {
sewardj227458e2005-01-31 19:04:50 +00002402 Long d = getSDisp32(delta);
sewardjc4356f02007-11-09 21:15:04 +00002403 DIS(buf, "%s%lld(,%s,%d)", segRegTxt(pfx), d,
sewardj5b470602005-02-27 13:10:48 +00002404 nameIReg64rexX(pfx,index_r), 1<<scale);
sewardj2f959cc2005-01-26 01:19:35 +00002405 *len = 6;
sewardj2f959cc2005-01-26 01:19:35 +00002406 return
2407 disAMode_copy2tmp(
sewardj2e28ac42008-12-04 00:05:12 +00002408 handleAddrOverrides(vbi, pfx,
sewardj3ca55a12005-01-27 16:06:23 +00002409 binop(Iop_Add64,
sewardj5b470602005-02-27 13:10:48 +00002410 binop(Iop_Shl64, getIReg64rexX(pfx,index_r),
sewardj3ca55a12005-01-27 16:06:23 +00002411 mkU8(scale)),
2412 mkU64(d))));
sewardj2f959cc2005-01-26 01:19:35 +00002413 }
2414
sewardj3ca55a12005-01-27 16:06:23 +00002415 if (index_is_SP && (!base_is_BPor13)) {
sewardjc4356f02007-11-09 21:15:04 +00002416 DIS(buf, "%s(%s)", segRegTxt(pfx), nameIRegRexB(8,pfx,base_r));
sewardj2f959cc2005-01-26 01:19:35 +00002417 *len = 2;
sewardj2f959cc2005-01-26 01:19:35 +00002418 return disAMode_copy2tmp(
sewardj2e28ac42008-12-04 00:05:12 +00002419 handleAddrOverrides(vbi, pfx, getIRegRexB(8,pfx,base_r)));
sewardj2f959cc2005-01-26 01:19:35 +00002420 }
2421
sewardj3ca55a12005-01-27 16:06:23 +00002422 if (index_is_SP && base_is_BPor13) {
sewardj227458e2005-01-31 19:04:50 +00002423 Long d = getSDisp32(delta);
sewardjc4356f02007-11-09 21:15:04 +00002424 DIS(buf, "%s%lld", segRegTxt(pfx), d);
sewardj2f959cc2005-01-26 01:19:35 +00002425 *len = 6;
sewardj2f959cc2005-01-26 01:19:35 +00002426 return disAMode_copy2tmp(
sewardj2e28ac42008-12-04 00:05:12 +00002427 handleAddrOverrides(vbi, pfx, mkU64(d)));
sewardj2f959cc2005-01-26 01:19:35 +00002428 }
2429
2430 vassert(0);
2431 }
sewardj3ca55a12005-01-27 16:06:23 +00002432
sewardj2f959cc2005-01-26 01:19:35 +00002433 /* SIB, with 8-bit displacement. Special cases:
2434 -- %esp cannot act as an index value.
2435 If index_r indicates %esp, zero is used for the index.
2436 Denoted value is:
2437 | %index == %ESP
2438 = d8 + %base
2439 | %index != %ESP
2440 = d8 + %base + (%index << scale)
2441 */
2442 case 0x0C: {
sewardj8c332e22005-01-28 01:36:56 +00002443 UChar sib = getUChar(delta);
sewardj1027dc22005-02-26 01:55:02 +00002444 UChar scale = toUChar((sib >> 6) & 3);
2445 UChar index_r = toUChar((sib >> 3) & 7);
2446 UChar base_r = toUChar(sib & 7);
sewardj8c332e22005-01-28 01:36:56 +00002447 Long d = getSDisp8(delta+1);
sewardj2f959cc2005-01-26 01:19:35 +00002448
sewardj3ca55a12005-01-27 16:06:23 +00002449 if (index_r == R_RSP && 0==getRexX(pfx)) {
sewardjc4356f02007-11-09 21:15:04 +00002450 DIS(buf, "%s%lld(%s)", segRegTxt(pfx),
sewardj5b470602005-02-27 13:10:48 +00002451 d, nameIRegRexB(8,pfx,base_r));
sewardj2f959cc2005-01-26 01:19:35 +00002452 *len = 3;
sewardj2f959cc2005-01-26 01:19:35 +00002453 return disAMode_copy2tmp(
sewardj2e28ac42008-12-04 00:05:12 +00002454 handleAddrOverrides(vbi, pfx,
sewardj5b470602005-02-27 13:10:48 +00002455 binop(Iop_Add64, getIRegRexB(8,pfx,base_r), mkU64(d)) ));
sewardj2f959cc2005-01-26 01:19:35 +00002456 } else {
sewardje941eea2005-01-30 19:52:28 +00002457 if (scale == 0) {
sewardjc4356f02007-11-09 21:15:04 +00002458 DIS(buf, "%s%lld(%s,%s)", segRegTxt(pfx), d,
sewardj5b470602005-02-27 13:10:48 +00002459 nameIRegRexB(8,pfx,base_r),
2460 nameIReg64rexX(pfx,index_r));
sewardje941eea2005-01-30 19:52:28 +00002461 } else {
sewardjc4356f02007-11-09 21:15:04 +00002462 DIS(buf, "%s%lld(%s,%s,%d)", segRegTxt(pfx), d,
sewardj5b470602005-02-27 13:10:48 +00002463 nameIRegRexB(8,pfx,base_r),
2464 nameIReg64rexX(pfx,index_r), 1<<scale);
sewardje941eea2005-01-30 19:52:28 +00002465 }
sewardj2f959cc2005-01-26 01:19:35 +00002466 *len = 3;
sewardj2f959cc2005-01-26 01:19:35 +00002467 return
2468 disAMode_copy2tmp(
sewardj2e28ac42008-12-04 00:05:12 +00002469 handleAddrOverrides(vbi, pfx,
sewardj3ca55a12005-01-27 16:06:23 +00002470 binop(Iop_Add64,
2471 binop(Iop_Add64,
sewardj5b470602005-02-27 13:10:48 +00002472 getIRegRexB(8,pfx,base_r),
sewardj3ca55a12005-01-27 16:06:23 +00002473 binop(Iop_Shl64,
sewardj5b470602005-02-27 13:10:48 +00002474 getIReg64rexX(pfx,index_r), mkU8(scale))),
sewardj3ca55a12005-01-27 16:06:23 +00002475 mkU64(d))));
sewardj2f959cc2005-01-26 01:19:35 +00002476 }
sewardj3ca55a12005-01-27 16:06:23 +00002477 vassert(0); /*NOTREACHED*/
sewardj2f959cc2005-01-26 01:19:35 +00002478 }
sewardj3ca55a12005-01-27 16:06:23 +00002479
sewardj2f959cc2005-01-26 01:19:35 +00002480 /* SIB, with 32-bit displacement. Special cases:
2481 -- %rsp cannot act as an index value.
2482 If index_r indicates %rsp, zero is used for the index.
2483 Denoted value is:
2484 | %index == %RSP
2485 = d32 + %base
2486 | %index != %RSP
2487 = d32 + %base + (%index << scale)
2488 */
2489 case 0x14: {
sewardj8c332e22005-01-28 01:36:56 +00002490 UChar sib = getUChar(delta);
sewardj1027dc22005-02-26 01:55:02 +00002491 UChar scale = toUChar((sib >> 6) & 3);
2492 UChar index_r = toUChar((sib >> 3) & 7);
2493 UChar base_r = toUChar(sib & 7);
sewardj8c332e22005-01-28 01:36:56 +00002494 Long d = getSDisp32(delta+1);
sewardj2f959cc2005-01-26 01:19:35 +00002495
2496 if (index_r == R_RSP && 0==getRexX(pfx)) {
sewardjc4356f02007-11-09 21:15:04 +00002497 DIS(buf, "%s%lld(%s)", segRegTxt(pfx),
sewardj5b470602005-02-27 13:10:48 +00002498 d, nameIRegRexB(8,pfx,base_r));
sewardj2f959cc2005-01-26 01:19:35 +00002499 *len = 6;
sewardj2f959cc2005-01-26 01:19:35 +00002500 return disAMode_copy2tmp(
sewardj2e28ac42008-12-04 00:05:12 +00002501 handleAddrOverrides(vbi, pfx,
sewardj5b470602005-02-27 13:10:48 +00002502 binop(Iop_Add64, getIRegRexB(8,pfx,base_r), mkU64(d)) ));
sewardj2f959cc2005-01-26 01:19:35 +00002503 } else {
sewardje941eea2005-01-30 19:52:28 +00002504 if (scale == 0) {
sewardjc4356f02007-11-09 21:15:04 +00002505 DIS(buf, "%s%lld(%s,%s)", segRegTxt(pfx), d,
sewardj5b470602005-02-27 13:10:48 +00002506 nameIRegRexB(8,pfx,base_r),
2507 nameIReg64rexX(pfx,index_r));
sewardje941eea2005-01-30 19:52:28 +00002508 } else {
sewardjc4356f02007-11-09 21:15:04 +00002509 DIS(buf, "%s%lld(%s,%s,%d)", segRegTxt(pfx), d,
sewardj5b470602005-02-27 13:10:48 +00002510 nameIRegRexB(8,pfx,base_r),
2511 nameIReg64rexX(pfx,index_r), 1<<scale);
sewardje941eea2005-01-30 19:52:28 +00002512 }
sewardj2f959cc2005-01-26 01:19:35 +00002513 *len = 6;
2514 return
2515 disAMode_copy2tmp(
sewardj2e28ac42008-12-04 00:05:12 +00002516 handleAddrOverrides(vbi, pfx,
sewardj2f959cc2005-01-26 01:19:35 +00002517 binop(Iop_Add64,
2518 binop(Iop_Add64,
sewardj5b470602005-02-27 13:10:48 +00002519 getIRegRexB(8,pfx,base_r),
sewardj2f959cc2005-01-26 01:19:35 +00002520 binop(Iop_Shl64,
sewardj5b470602005-02-27 13:10:48 +00002521 getIReg64rexX(pfx,index_r), mkU8(scale))),
sewardj2f959cc2005-01-26 01:19:35 +00002522 mkU64(d))));
2523 }
sewardj3ca55a12005-01-27 16:06:23 +00002524 vassert(0); /*NOTREACHED*/
sewardj2f959cc2005-01-26 01:19:35 +00002525 }
2526
sewardjb3a04292005-01-21 20:33:44 +00002527 default:
2528 vpanic("disAMode(amd64)");
2529 return 0; /*notreached*/
2530 }
2531}
2532
2533
sewardj3ca55a12005-01-27 16:06:23 +00002534/* Figure out the number of (insn-stream) bytes constituting the amode
2535 beginning at delta. Is useful for getting hold of literals beyond
2536 the end of the amode before it has been disassembled. */
2537
sewardj270def42005-07-03 01:03:01 +00002538static UInt lengthAMode ( Prefix pfx, Long delta )
sewardj3ca55a12005-01-27 16:06:23 +00002539{
sewardj8c332e22005-01-28 01:36:56 +00002540 UChar mod_reg_rm = getUChar(delta);
sewardj3ca55a12005-01-27 16:06:23 +00002541 delta++;
2542
2543 /* squeeze out the reg field from mod_reg_rm, since a 256-entry
2544 jump table seems a bit excessive.
2545 */
sewardj7a240552005-01-28 21:37:12 +00002546 mod_reg_rm &= 0xC7; /* is now XX000YYY */
sewardj1027dc22005-02-26 01:55:02 +00002547 mod_reg_rm = toUChar(mod_reg_rm | (mod_reg_rm >> 3));
2548 /* is now XX0XXYYY */
sewardj7a240552005-01-28 21:37:12 +00002549 mod_reg_rm &= 0x1F; /* is now 000XXYYY */
sewardj3ca55a12005-01-27 16:06:23 +00002550 switch (mod_reg_rm) {
2551
2552 /* REX.B==0: (%rax) .. (%rdi), not including (%rsp) or (%rbp).
2553 REX.B==1: (%r8) .. (%r15), not including (%r12) or (%r13).
2554 */
2555 case 0x00: case 0x01: case 0x02: case 0x03:
2556 /* ! 04 */ /* ! 05 */ case 0x06: case 0x07:
sewardj3ca55a12005-01-27 16:06:23 +00002557 return 1;
2558
2559 /* REX.B==0: d8(%rax) ... d8(%rdi), not including d8(%rsp)
2560 REX.B==1: d8(%r8) ... d8(%r15), not including d8(%r12)
2561 */
2562 case 0x08: case 0x09: case 0x0A: case 0x0B:
2563 /* ! 0C */ case 0x0D: case 0x0E: case 0x0F:
sewardj3ca55a12005-01-27 16:06:23 +00002564 return 2;
2565
2566 /* REX.B==0: d32(%rax) ... d32(%rdi), not including d32(%rsp)
2567 REX.B==1: d32(%r8) ... d32(%r15), not including d32(%r12)
2568 */
2569 case 0x10: case 0x11: case 0x12: case 0x13:
2570 /* ! 14 */ case 0x15: case 0x16: case 0x17:
sewardj3ca55a12005-01-27 16:06:23 +00002571 return 5;
2572
2573 /* REX.B==0: a register, %rax .. %rdi. This shouldn't happen. */
2574 /* REX.B==1: a register, %r8 .. %r16. This shouldn't happen. */
2575 /* Not an address, but still handled. */
2576 case 0x18: case 0x19: case 0x1A: case 0x1B:
2577 case 0x1C: case 0x1D: case 0x1E: case 0x1F:
2578 return 1;
2579
2580 /* RIP + disp32. */
2581 case 0x05:
sewardj3ca55a12005-01-27 16:06:23 +00002582 return 5;
2583
2584 case 0x04: {
2585 /* SIB, with no displacement. */
sewardj8c332e22005-01-28 01:36:56 +00002586 UChar sib = getUChar(delta);
sewardj1027dc22005-02-26 01:55:02 +00002587 UChar base_r = toUChar(sib & 7);
sewardj3ca55a12005-01-27 16:06:23 +00002588 /* correct since #(R13) == 8 + #(RBP) */
sewardj7a240552005-01-28 21:37:12 +00002589 Bool base_is_BPor13 = toBool(base_r == R_RBP);
sewardj3ca55a12005-01-27 16:06:23 +00002590
2591 if (base_is_BPor13) {
sewardj3ca55a12005-01-27 16:06:23 +00002592 return 6;
2593 } else {
sewardj3ca55a12005-01-27 16:06:23 +00002594 return 2;
2595 }
2596 }
2597
2598 /* SIB, with 8-bit displacement. */
2599 case 0x0C:
2600 return 3;
2601
2602 /* SIB, with 32-bit displacement. */
2603 case 0x14:
2604 return 6;
2605
2606 default:
2607 vpanic("lengthAMode(amd64)");
2608 return 0; /*notreached*/
2609 }
2610}
2611
2612
sewardjdf0e0022005-01-25 15:48:43 +00002613/*------------------------------------------------------------*/
2614/*--- Disassembling common idioms ---*/
2615/*------------------------------------------------------------*/
2616
sewardjdf0e0022005-01-25 15:48:43 +00002617/* Handle binary integer instructions of the form
2618 op E, G meaning
2619 op reg-or-mem, reg
2620 Is passed the a ptr to the modRM byte, the actual operation, and the
2621 data size. Returns the address advanced completely over this
2622 instruction.
2623
2624 E(src) is reg-or-mem
2625 G(dst) is reg.
2626
2627 If E is reg, --> GET %G, tmp
2628 OP %E, tmp
2629 PUT tmp, %G
2630
2631 If E is mem and OP is not reversible,
2632 --> (getAddr E) -> tmpa
2633 LD (tmpa), tmpa
2634 GET %G, tmp2
2635 OP tmpa, tmp2
2636 PUT tmp2, %G
2637
2638 If E is mem and OP is reversible
2639 --> (getAddr E) -> tmpa
2640 LD (tmpa), tmpa
2641 OP %G, tmpa
2642 PUT tmpa, %G
2643*/
2644static
sewardj2e28ac42008-12-04 00:05:12 +00002645ULong dis_op2_E_G ( VexAbiInfo* vbi,
2646 Prefix pfx,
sewardjdf0e0022005-01-25 15:48:43 +00002647 Bool addSubCarry,
2648 IROp op8,
2649 Bool keep,
2650 Int size,
sewardj270def42005-07-03 01:03:01 +00002651 Long delta0,
sewardj8c332e22005-01-28 01:36:56 +00002652 HChar* t_amd64opc )
sewardjdf0e0022005-01-25 15:48:43 +00002653{
2654 HChar dis_buf[50];
2655 Int len;
2656 IRType ty = szToITy(size);
2657 IRTemp dst1 = newTemp(ty);
2658 IRTemp src = newTemp(ty);
2659 IRTemp dst0 = newTemp(ty);
2660 UChar rm = getUChar(delta0);
2661 IRTemp addr = IRTemp_INVALID;
2662
2663 /* addSubCarry == True indicates the intended operation is
2664 add-with-carry or subtract-with-borrow. */
2665 if (addSubCarry) {
2666 vassert(op8 == Iop_Add8 || op8 == Iop_Sub8);
2667 vassert(keep);
2668 }
2669
2670 if (epartIsReg(rm)) {
sewardjdf0e0022005-01-25 15:48:43 +00002671 /* Specially handle XOR reg,reg, because that doesn't really
2672 depend on reg, and doing the obvious thing potentially
2673 generates a spurious value check failure due to the bogus
2674 dependency. */
sewardj5b470602005-02-27 13:10:48 +00002675 if ((op8 == Iop_Xor8 || (op8 == Iop_Sub8 && addSubCarry))
2676 && offsetIRegG(size,pfx,rm) == offsetIRegE(size,pfx,rm)) {
sewardj4f9847d2005-07-25 11:58:34 +00002677 if (False && op8 == Iop_Sub8)
sewardj5b470602005-02-27 13:10:48 +00002678 vex_printf("vex amd64->IR: sbb %%r,%%r optimisation(1)\n");
2679 putIRegG(size,pfx,rm, mkU(ty,0));
sewardjdf0e0022005-01-25 15:48:43 +00002680 }
sewardj5b470602005-02-27 13:10:48 +00002681
2682 assign( dst0, getIRegG(size,pfx,rm) );
2683 assign( src, getIRegE(size,pfx,rm) );
sewardjdf0e0022005-01-25 15:48:43 +00002684
2685 if (addSubCarry && op8 == Iop_Add8) {
sewardje9d8a262009-07-01 08:06:34 +00002686 helper_ADC( size, dst1, dst0, src,
2687 /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
sewardj5b470602005-02-27 13:10:48 +00002688 putIRegG(size, pfx, rm, mkexpr(dst1));
sewardjdf0e0022005-01-25 15:48:43 +00002689 } else
2690 if (addSubCarry && op8 == Iop_Sub8) {
sewardje9d8a262009-07-01 08:06:34 +00002691 helper_SBB( size, dst1, dst0, src,
2692 /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
sewardj5b470602005-02-27 13:10:48 +00002693 putIRegG(size, pfx, rm, mkexpr(dst1));
sewardjdf0e0022005-01-25 15:48:43 +00002694 } else {
2695 assign( dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
2696 if (isAddSub(op8))
2697 setFlags_DEP1_DEP2(op8, dst0, src, ty);
2698 else
2699 setFlags_DEP1(op8, dst1, ty);
2700 if (keep)
sewardj5b470602005-02-27 13:10:48 +00002701 putIRegG(size, pfx, rm, mkexpr(dst1));
sewardjdf0e0022005-01-25 15:48:43 +00002702 }
2703
2704 DIP("%s%c %s,%s\n", t_amd64opc, nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00002705 nameIRegE(size,pfx,rm),
2706 nameIRegG(size,pfx,rm));
sewardjdf0e0022005-01-25 15:48:43 +00002707 return 1+delta0;
2708 } else {
2709 /* E refers to memory */
sewardj2e28ac42008-12-04 00:05:12 +00002710 addr = disAMode ( &len, vbi, pfx, delta0, dis_buf, 0 );
sewardj5b470602005-02-27 13:10:48 +00002711 assign( dst0, getIRegG(size,pfx,rm) );
sewardjdf0e0022005-01-25 15:48:43 +00002712 assign( src, loadLE(szToITy(size), mkexpr(addr)) );
2713
2714 if (addSubCarry && op8 == Iop_Add8) {
sewardje9d8a262009-07-01 08:06:34 +00002715 helper_ADC( size, dst1, dst0, src,
2716 /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
sewardj5b470602005-02-27 13:10:48 +00002717 putIRegG(size, pfx, rm, mkexpr(dst1));
sewardjdf0e0022005-01-25 15:48:43 +00002718 } else
2719 if (addSubCarry && op8 == Iop_Sub8) {
sewardje9d8a262009-07-01 08:06:34 +00002720 helper_SBB( size, dst1, dst0, src,
2721 /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
sewardj5b470602005-02-27 13:10:48 +00002722 putIRegG(size, pfx, rm, mkexpr(dst1));
sewardjdf0e0022005-01-25 15:48:43 +00002723 } else {
2724 assign( dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
2725 if (isAddSub(op8))
2726 setFlags_DEP1_DEP2(op8, dst0, src, ty);
2727 else
2728 setFlags_DEP1(op8, dst1, ty);
2729 if (keep)
sewardj5b470602005-02-27 13:10:48 +00002730 putIRegG(size, pfx, rm, mkexpr(dst1));
sewardjdf0e0022005-01-25 15:48:43 +00002731 }
2732
2733 DIP("%s%c %s,%s\n", t_amd64opc, nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00002734 dis_buf, nameIRegG(size, pfx, rm));
sewardjdf0e0022005-01-25 15:48:43 +00002735 return len+delta0;
2736 }
2737}
2738
2739
2740
sewardj3ca55a12005-01-27 16:06:23 +00002741/* Handle binary integer instructions of the form
2742 op G, E meaning
2743 op reg, reg-or-mem
2744 Is passed the a ptr to the modRM byte, the actual operation, and the
2745 data size. Returns the address advanced completely over this
2746 instruction.
2747
2748 G(src) is reg.
2749 E(dst) is reg-or-mem
2750
2751 If E is reg, --> GET %E, tmp
2752 OP %G, tmp
2753 PUT tmp, %E
2754
2755 If E is mem, --> (getAddr E) -> tmpa
2756 LD (tmpa), tmpv
2757 OP %G, tmpv
2758 ST tmpv, (tmpa)
2759*/
2760static
sewardj2e28ac42008-12-04 00:05:12 +00002761ULong dis_op2_G_E ( VexAbiInfo* vbi,
2762 Prefix pfx,
sewardj8c332e22005-01-28 01:36:56 +00002763 Bool addSubCarry,
2764 IROp op8,
2765 Bool keep,
2766 Int size,
sewardj270def42005-07-03 01:03:01 +00002767 Long delta0,
sewardj8c332e22005-01-28 01:36:56 +00002768 HChar* t_amd64opc )
sewardj3ca55a12005-01-27 16:06:23 +00002769{
2770 HChar dis_buf[50];
2771 Int len;
2772 IRType ty = szToITy(size);
2773 IRTemp dst1 = newTemp(ty);
2774 IRTemp src = newTemp(ty);
2775 IRTemp dst0 = newTemp(ty);
sewardj8c332e22005-01-28 01:36:56 +00002776 UChar rm = getUChar(delta0);
sewardj3ca55a12005-01-27 16:06:23 +00002777 IRTemp addr = IRTemp_INVALID;
2778
2779 /* addSubCarry == True indicates the intended operation is
2780 add-with-carry or subtract-with-borrow. */
2781 if (addSubCarry) {
2782 vassert(op8 == Iop_Add8 || op8 == Iop_Sub8);
2783 vassert(keep);
2784 }
2785
2786 if (epartIsReg(rm)) {
2787 /* Specially handle XOR reg,reg, because that doesn't really
2788 depend on reg, and doing the obvious thing potentially
2789 generates a spurious value check failure due to the bogus
sewardj5b470602005-02-27 13:10:48 +00002790 dependency. Ditto SBB reg,reg. */
2791 if ((op8 == Iop_Xor8 || (op8 == Iop_Sub8 && addSubCarry))
2792 && offsetIRegG(size,pfx,rm) == offsetIRegE(size,pfx,rm)) {
2793 putIRegE(size,pfx,rm, mkU(ty,0));
sewardj3ca55a12005-01-27 16:06:23 +00002794 }
sewardj5b470602005-02-27 13:10:48 +00002795
2796 assign(dst0, getIRegE(size,pfx,rm));
2797 assign(src, getIRegG(size,pfx,rm));
sewardj3ca55a12005-01-27 16:06:23 +00002798
2799 if (addSubCarry && op8 == Iop_Add8) {
sewardje9d8a262009-07-01 08:06:34 +00002800 helper_ADC( size, dst1, dst0, src,
2801 /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
sewardj5b470602005-02-27 13:10:48 +00002802 putIRegE(size, pfx, rm, mkexpr(dst1));
sewardj3ca55a12005-01-27 16:06:23 +00002803 } else
2804 if (addSubCarry && op8 == Iop_Sub8) {
sewardje9d8a262009-07-01 08:06:34 +00002805 helper_SBB( size, dst1, dst0, src,
2806 /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
sewardj5b470602005-02-27 13:10:48 +00002807 putIRegE(size, pfx, rm, mkexpr(dst1));
sewardj3ca55a12005-01-27 16:06:23 +00002808 } else {
2809 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
2810 if (isAddSub(op8))
2811 setFlags_DEP1_DEP2(op8, dst0, src, ty);
2812 else
2813 setFlags_DEP1(op8, dst1, ty);
2814 if (keep)
sewardj5b470602005-02-27 13:10:48 +00002815 putIRegE(size, pfx, rm, mkexpr(dst1));
sewardj3ca55a12005-01-27 16:06:23 +00002816 }
2817
2818 DIP("%s%c %s,%s\n", t_amd64opc, nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00002819 nameIRegG(size,pfx,rm),
2820 nameIRegE(size,pfx,rm));
sewardj3ca55a12005-01-27 16:06:23 +00002821 return 1+delta0;
2822 }
2823
2824 /* E refers to memory */
2825 {
sewardj2e28ac42008-12-04 00:05:12 +00002826 addr = disAMode ( &len, vbi, pfx, delta0, dis_buf, 0 );
sewardj3ca55a12005-01-27 16:06:23 +00002827 assign(dst0, loadLE(ty,mkexpr(addr)));
sewardj5b470602005-02-27 13:10:48 +00002828 assign(src, getIRegG(size,pfx,rm));
sewardj3ca55a12005-01-27 16:06:23 +00002829
2830 if (addSubCarry && op8 == Iop_Add8) {
sewardje9d8a262009-07-01 08:06:34 +00002831 if (pfx & PFX_LOCK) {
2832 /* cas-style store */
2833 helper_ADC( size, dst1, dst0, src,
2834 /*store*/addr, dst0/*expVal*/, guest_RIP_curr_instr );
2835 } else {
2836 /* normal store */
2837 helper_ADC( size, dst1, dst0, src,
2838 /*store*/addr, IRTemp_INVALID, 0 );
2839 }
sewardj3ca55a12005-01-27 16:06:23 +00002840 } else
2841 if (addSubCarry && op8 == Iop_Sub8) {
sewardje9d8a262009-07-01 08:06:34 +00002842 if (pfx & PFX_LOCK) {
2843 /* cas-style store */
2844 helper_SBB( size, dst1, dst0, src,
2845 /*store*/addr, dst0/*expVal*/, guest_RIP_curr_instr );
2846 } else {
2847 /* normal store */
2848 helper_SBB( size, dst1, dst0, src,
2849 /*store*/addr, IRTemp_INVALID, 0 );
2850 }
sewardj3ca55a12005-01-27 16:06:23 +00002851 } else {
2852 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
sewardje9d8a262009-07-01 08:06:34 +00002853 if (keep) {
2854 if (pfx & PFX_LOCK) {
2855 if (0) vex_printf("locked case\n" );
2856 casLE( mkexpr(addr),
2857 mkexpr(dst0)/*expval*/,
2858 mkexpr(dst1)/*newval*/, guest_RIP_curr_instr );
2859 } else {
2860 if (0) vex_printf("nonlocked case\n");
2861 storeLE(mkexpr(addr), mkexpr(dst1));
2862 }
2863 }
sewardj3ca55a12005-01-27 16:06:23 +00002864 if (isAddSub(op8))
2865 setFlags_DEP1_DEP2(op8, dst0, src, ty);
2866 else
2867 setFlags_DEP1(op8, dst1, ty);
sewardj3ca55a12005-01-27 16:06:23 +00002868 }
2869
2870 DIP("%s%c %s,%s\n", t_amd64opc, nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00002871 nameIRegG(size,pfx,rm), dis_buf);
sewardj3ca55a12005-01-27 16:06:23 +00002872 return len+delta0;
2873 }
2874}
2875
2876
sewardj1389d4d2005-01-28 13:46:29 +00002877/* Handle move instructions of the form
2878 mov E, G meaning
2879 mov reg-or-mem, reg
2880 Is passed the a ptr to the modRM byte, and the data size. Returns
2881 the address advanced completely over this instruction.
2882
2883 E(src) is reg-or-mem
2884 G(dst) is reg.
2885
2886 If E is reg, --> GET %E, tmpv
2887 PUT tmpv, %G
2888
2889 If E is mem --> (getAddr E) -> tmpa
2890 LD (tmpa), tmpb
2891 PUT tmpb, %G
2892*/
2893static
sewardj2e28ac42008-12-04 00:05:12 +00002894ULong dis_mov_E_G ( VexAbiInfo* vbi,
2895 Prefix pfx,
sewardj1389d4d2005-01-28 13:46:29 +00002896 Int size,
sewardj270def42005-07-03 01:03:01 +00002897 Long delta0 )
sewardj1389d4d2005-01-28 13:46:29 +00002898{
2899 Int len;
2900 UChar rm = getUChar(delta0);
2901 HChar dis_buf[50];
2902
2903 if (epartIsReg(rm)) {
sewardj5b470602005-02-27 13:10:48 +00002904 putIRegG(size, pfx, rm, getIRegE(size, pfx, rm));
sewardje941eea2005-01-30 19:52:28 +00002905 DIP("mov%c %s,%s\n", nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00002906 nameIRegE(size,pfx,rm),
2907 nameIRegG(size,pfx,rm));
sewardj1389d4d2005-01-28 13:46:29 +00002908 return 1+delta0;
2909 }
2910
2911 /* E refers to memory */
2912 {
sewardj2e28ac42008-12-04 00:05:12 +00002913 IRTemp addr = disAMode ( &len, vbi, pfx, delta0, dis_buf, 0 );
sewardj5b470602005-02-27 13:10:48 +00002914 putIRegG(size, pfx, rm, loadLE(szToITy(size), mkexpr(addr)));
sewardj1389d4d2005-01-28 13:46:29 +00002915 DIP("mov%c %s,%s\n", nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00002916 dis_buf,
2917 nameIRegG(size,pfx,rm));
sewardj1389d4d2005-01-28 13:46:29 +00002918 return delta0+len;
2919 }
2920}
2921
2922
2923/* Handle move instructions of the form
2924 mov G, E meaning
2925 mov reg, reg-or-mem
2926 Is passed the a ptr to the modRM byte, and the data size. Returns
2927 the address advanced completely over this instruction.
2928
2929 G(src) is reg.
2930 E(dst) is reg-or-mem
2931
2932 If E is reg, --> GET %G, tmp
2933 PUT tmp, %E
2934
2935 If E is mem, --> (getAddr E) -> tmpa
2936 GET %G, tmpv
2937 ST tmpv, (tmpa)
2938*/
2939static
sewardj2e28ac42008-12-04 00:05:12 +00002940ULong dis_mov_G_E ( VexAbiInfo* vbi,
2941 Prefix pfx,
sewardj1389d4d2005-01-28 13:46:29 +00002942 Int size,
sewardj270def42005-07-03 01:03:01 +00002943 Long delta0 )
sewardj1389d4d2005-01-28 13:46:29 +00002944{
2945 Int len;
2946 UChar rm = getUChar(delta0);
2947 HChar dis_buf[50];
2948
2949 if (epartIsReg(rm)) {
sewardj5b470602005-02-27 13:10:48 +00002950 putIRegE(size, pfx, rm, getIRegG(size, pfx, rm));
sewardje941eea2005-01-30 19:52:28 +00002951 DIP("mov%c %s,%s\n", nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00002952 nameIRegG(size,pfx,rm),
2953 nameIRegE(size,pfx,rm));
sewardj1389d4d2005-01-28 13:46:29 +00002954 return 1+delta0;
2955 }
2956
2957 /* E refers to memory */
2958 {
sewardj2e28ac42008-12-04 00:05:12 +00002959 IRTemp addr = disAMode ( &len, vbi, pfx, delta0, dis_buf, 0 );
sewardj5b470602005-02-27 13:10:48 +00002960 storeLE( mkexpr(addr), getIRegG(size, pfx, rm) );
sewardj1389d4d2005-01-28 13:46:29 +00002961 DIP("mov%c %s,%s\n", nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00002962 nameIRegG(size,pfx,rm),
2963 dis_buf);
sewardj1389d4d2005-01-28 13:46:29 +00002964 return len+delta0;
2965 }
2966}
sewardj3ca55a12005-01-27 16:06:23 +00002967
2968
2969/* op $immediate, AL/AX/EAX/RAX. */
2970static
sewardj8c332e22005-01-28 01:36:56 +00002971ULong dis_op_imm_A ( Int size,
sewardj41c01092005-07-23 13:50:32 +00002972 Bool carrying,
sewardj8c332e22005-01-28 01:36:56 +00002973 IROp op8,
2974 Bool keep,
sewardj270def42005-07-03 01:03:01 +00002975 Long delta,
sewardj8c332e22005-01-28 01:36:56 +00002976 HChar* t_amd64opc )
sewardj3ca55a12005-01-27 16:06:23 +00002977{
2978 Int size4 = imin(size,4);
2979 IRType ty = szToITy(size);
2980 IRTemp dst0 = newTemp(ty);
2981 IRTemp src = newTemp(ty);
2982 IRTemp dst1 = newTemp(ty);
sewardj8c332e22005-01-28 01:36:56 +00002983 Long lit = getSDisp(size4,delta);
sewardj5b470602005-02-27 13:10:48 +00002984 assign(dst0, getIRegRAX(size));
sewardj1389d4d2005-01-28 13:46:29 +00002985 assign(src, mkU(ty,lit & mkSizeMask(size)));
sewardj41c01092005-07-23 13:50:32 +00002986
2987 if (isAddSub(op8) && !carrying) {
2988 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
sewardj3ca55a12005-01-27 16:06:23 +00002989 setFlags_DEP1_DEP2(op8, dst0, src, ty);
sewardj41c01092005-07-23 13:50:32 +00002990 }
sewardj3ca55a12005-01-27 16:06:23 +00002991 else
sewardj41c01092005-07-23 13:50:32 +00002992 if (isLogic(op8)) {
2993 vassert(!carrying);
2994 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
sewardj3ca55a12005-01-27 16:06:23 +00002995 setFlags_DEP1(op8, dst1, ty);
sewardj41c01092005-07-23 13:50:32 +00002996 }
sewardj3ca55a12005-01-27 16:06:23 +00002997 else
sewardj41c01092005-07-23 13:50:32 +00002998 if (op8 == Iop_Add8 && carrying) {
sewardje9d8a262009-07-01 08:06:34 +00002999 helper_ADC( size, dst1, dst0, src,
3000 /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
sewardj41c01092005-07-23 13:50:32 +00003001 }
3002 else
sewardj5fadaf92006-05-12 20:45:59 +00003003 if (op8 == Iop_Sub8 && carrying) {
sewardje9d8a262009-07-01 08:06:34 +00003004 helper_SBB( size, dst1, dst0, src,
3005 /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
sewardj5fadaf92006-05-12 20:45:59 +00003006 }
3007 else
sewardj41c01092005-07-23 13:50:32 +00003008 vpanic("dis_op_imm_A(amd64,guest)");
sewardj3ca55a12005-01-27 16:06:23 +00003009
3010 if (keep)
sewardj5b470602005-02-27 13:10:48 +00003011 putIRegRAX(size, mkexpr(dst1));
sewardj3ca55a12005-01-27 16:06:23 +00003012
3013 DIP("%s%c $%lld, %s\n", t_amd64opc, nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00003014 lit, nameIRegRAX(size));
sewardj3ca55a12005-01-27 16:06:23 +00003015 return delta+size4;
3016}
3017
3018
sewardj5e525292005-01-28 15:13:10 +00003019/* Sign- and Zero-extending moves. */
3020static
sewardj2e28ac42008-12-04 00:05:12 +00003021ULong dis_movx_E_G ( VexAbiInfo* vbi,
3022 Prefix pfx,
sewardj270def42005-07-03 01:03:01 +00003023 Long delta, Int szs, Int szd, Bool sign_extend )
sewardj5e525292005-01-28 15:13:10 +00003024{
3025 UChar rm = getUChar(delta);
3026 if (epartIsReg(rm)) {
sewardj5b470602005-02-27 13:10:48 +00003027 putIRegG(szd, pfx, rm,
sewardj5e525292005-01-28 15:13:10 +00003028 doScalarWidening(
3029 szs,szd,sign_extend,
sewardj5b470602005-02-27 13:10:48 +00003030 getIRegE(szs,pfx,rm)));
sewardj5e525292005-01-28 15:13:10 +00003031 DIP("mov%c%c%c %s,%s\n", sign_extend ? 's' : 'z',
3032 nameISize(szs),
3033 nameISize(szd),
sewardj5b470602005-02-27 13:10:48 +00003034 nameIRegE(szs,pfx,rm),
3035 nameIRegG(szd,pfx,rm));
sewardj5e525292005-01-28 15:13:10 +00003036 return 1+delta;
3037 }
3038
3039 /* E refers to memory */
3040 {
3041 Int len;
3042 HChar dis_buf[50];
sewardj2e28ac42008-12-04 00:05:12 +00003043 IRTemp addr = disAMode ( &len, vbi, pfx, delta, dis_buf, 0 );
sewardj5b470602005-02-27 13:10:48 +00003044 putIRegG(szd, pfx, rm,
sewardj5e525292005-01-28 15:13:10 +00003045 doScalarWidening(
3046 szs,szd,sign_extend,
3047 loadLE(szToITy(szs),mkexpr(addr))));
3048 DIP("mov%c%c%c %s,%s\n", sign_extend ? 's' : 'z',
3049 nameISize(szs),
3050 nameISize(szd),
3051 dis_buf,
sewardj5b470602005-02-27 13:10:48 +00003052 nameIRegG(szd,pfx,rm));
sewardj5e525292005-01-28 15:13:10 +00003053 return len+delta;
3054 }
3055}
sewardj32b2bbe2005-01-28 00:50:10 +00003056
3057
sewardj03b07cc2005-01-31 18:09:43 +00003058/* Generate code to divide ArchRegs RDX:RAX / EDX:EAX / DX:AX / AX by
3059 the 64 / 32 / 16 / 8 bit quantity in the given IRTemp. */
sewardj32b2bbe2005-01-28 00:50:10 +00003060static
3061void codegen_div ( Int sz, IRTemp t, Bool signed_divide )
3062{
sewardj03b07cc2005-01-31 18:09:43 +00003063 /* special-case the 64-bit case */
3064 if (sz == 8) {
3065 IROp op = signed_divide ? Iop_DivModS128to64
3066 : Iop_DivModU128to64;
sewardja6b93d12005-02-17 09:28:28 +00003067 IRTemp src128 = newTemp(Ity_I128);
3068 IRTemp dst128 = newTemp(Ity_I128);
sewardj03b07cc2005-01-31 18:09:43 +00003069 assign( src128, binop(Iop_64HLto128,
sewardja6b93d12005-02-17 09:28:28 +00003070 getIReg64(R_RDX),
3071 getIReg64(R_RAX)) );
sewardj03b07cc2005-01-31 18:09:43 +00003072 assign( dst128, binop(op, mkexpr(src128), mkexpr(t)) );
sewardja6b93d12005-02-17 09:28:28 +00003073 putIReg64( R_RAX, unop(Iop_128to64,mkexpr(dst128)) );
3074 putIReg64( R_RDX, unop(Iop_128HIto64,mkexpr(dst128)) );
sewardj03b07cc2005-01-31 18:09:43 +00003075 } else {
3076 IROp op = signed_divide ? Iop_DivModS64to32
3077 : Iop_DivModU64to32;
3078 IRTemp src64 = newTemp(Ity_I64);
3079 IRTemp dst64 = newTemp(Ity_I64);
3080 switch (sz) {
sewardj85520e42005-02-19 15:22:38 +00003081 case 4:
sewardj5b470602005-02-27 13:10:48 +00003082 assign( src64,
3083 binop(Iop_32HLto64, getIRegRDX(4), getIRegRAX(4)) );
3084 assign( dst64,
3085 binop(op, mkexpr(src64), mkexpr(t)) );
3086 putIRegRAX( 4, unop(Iop_64to32,mkexpr(dst64)) );
3087 putIRegRDX( 4, unop(Iop_64HIto32,mkexpr(dst64)) );
sewardj85520e42005-02-19 15:22:38 +00003088 break;
3089 case 2: {
3090 IROp widen3264 = signed_divide ? Iop_32Sto64 : Iop_32Uto64;
3091 IROp widen1632 = signed_divide ? Iop_16Sto32 : Iop_16Uto32;
3092 assign( src64, unop(widen3264,
3093 binop(Iop_16HLto32,
sewardj5b470602005-02-27 13:10:48 +00003094 getIRegRDX(2),
3095 getIRegRAX(2))) );
sewardj85520e42005-02-19 15:22:38 +00003096 assign( dst64, binop(op, mkexpr(src64), unop(widen1632,mkexpr(t))) );
sewardj5b470602005-02-27 13:10:48 +00003097 putIRegRAX( 2, unop(Iop_32to16,unop(Iop_64to32,mkexpr(dst64))) );
3098 putIRegRDX( 2, unop(Iop_32to16,unop(Iop_64HIto32,mkexpr(dst64))) );
sewardj85520e42005-02-19 15:22:38 +00003099 break;
3100 }
3101 case 1: {
3102 IROp widen3264 = signed_divide ? Iop_32Sto64 : Iop_32Uto64;
3103 IROp widen1632 = signed_divide ? Iop_16Sto32 : Iop_16Uto32;
3104 IROp widen816 = signed_divide ? Iop_8Sto16 : Iop_8Uto16;
3105 assign( src64, unop(widen3264,
sewardj5b470602005-02-27 13:10:48 +00003106 unop(widen1632, getIRegRAX(2))) );
sewardj85520e42005-02-19 15:22:38 +00003107 assign( dst64,
3108 binop(op, mkexpr(src64),
3109 unop(widen1632, unop(widen816, mkexpr(t)))) );
sewardj5b470602005-02-27 13:10:48 +00003110 putIRegRAX( 1, unop(Iop_16to8,
3111 unop(Iop_32to16,
3112 unop(Iop_64to32,mkexpr(dst64)))) );
3113 putIRegAH( unop(Iop_16to8,
3114 unop(Iop_32to16,
3115 unop(Iop_64HIto32,mkexpr(dst64)))) );
sewardj85520e42005-02-19 15:22:38 +00003116 break;
3117 }
3118 default:
3119 vpanic("codegen_div(amd64)");
sewardj03b07cc2005-01-31 18:09:43 +00003120 }
sewardj32b2bbe2005-01-28 00:50:10 +00003121 }
3122}
sewardj3ca55a12005-01-27 16:06:23 +00003123
3124static
sewardj2e28ac42008-12-04 00:05:12 +00003125ULong dis_Grp1 ( VexAbiInfo* vbi,
3126 Prefix pfx,
sewardj270def42005-07-03 01:03:01 +00003127 Long delta, UChar modrm,
sewardj227458e2005-01-31 19:04:50 +00003128 Int am_sz, Int d_sz, Int sz, Long d64 )
sewardj3ca55a12005-01-27 16:06:23 +00003129{
3130 Int len;
3131 HChar dis_buf[50];
3132 IRType ty = szToITy(sz);
3133 IRTemp dst1 = newTemp(ty);
3134 IRTemp src = newTemp(ty);
3135 IRTemp dst0 = newTemp(ty);
3136 IRTemp addr = IRTemp_INVALID;
3137 IROp op8 = Iop_INVALID;
sewardj1389d4d2005-01-28 13:46:29 +00003138 ULong mask = mkSizeMask(sz);
sewardj3ca55a12005-01-27 16:06:23 +00003139
sewardj901ed122005-02-27 13:25:31 +00003140 switch (gregLO3ofRM(modrm)) {
sewardj3ca55a12005-01-27 16:06:23 +00003141 case 0: op8 = Iop_Add8; break; case 1: op8 = Iop_Or8; break;
3142 case 2: break; // ADC
3143 case 3: break; // SBB
3144 case 4: op8 = Iop_And8; break; case 5: op8 = Iop_Sub8; break;
3145 case 6: op8 = Iop_Xor8; break; case 7: op8 = Iop_Sub8; break;
sewardjfd4203c2007-03-21 00:21:56 +00003146 /*NOTREACHED*/
sewardj3ca55a12005-01-27 16:06:23 +00003147 default: vpanic("dis_Grp1(amd64): unhandled case");
3148 }
3149
3150 if (epartIsReg(modrm)) {
3151 vassert(am_sz == 1);
3152
sewardj5b470602005-02-27 13:10:48 +00003153 assign(dst0, getIRegE(sz,pfx,modrm));
sewardj227458e2005-01-31 19:04:50 +00003154 assign(src, mkU(ty,d64 & mask));
sewardj3ca55a12005-01-27 16:06:23 +00003155
sewardj901ed122005-02-27 13:25:31 +00003156 if (gregLO3ofRM(modrm) == 2 /* ADC */) {
sewardje9d8a262009-07-01 08:06:34 +00003157 helper_ADC( sz, dst1, dst0, src,
3158 /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
sewardj3ca55a12005-01-27 16:06:23 +00003159 } else
sewardj901ed122005-02-27 13:25:31 +00003160 if (gregLO3ofRM(modrm) == 3 /* SBB */) {
sewardje9d8a262009-07-01 08:06:34 +00003161 helper_SBB( sz, dst1, dst0, src,
3162 /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
sewardj3ca55a12005-01-27 16:06:23 +00003163 } else {
3164 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
3165 if (isAddSub(op8))
3166 setFlags_DEP1_DEP2(op8, dst0, src, ty);
3167 else
3168 setFlags_DEP1(op8, dst1, ty);
3169 }
3170
sewardj901ed122005-02-27 13:25:31 +00003171 if (gregLO3ofRM(modrm) < 7)
sewardj5b470602005-02-27 13:10:48 +00003172 putIRegE(sz, pfx, modrm, mkexpr(dst1));
sewardj3ca55a12005-01-27 16:06:23 +00003173
3174 delta += (am_sz + d_sz);
sewardje941eea2005-01-30 19:52:28 +00003175 DIP("%s%c $%lld, %s\n",
sewardj901ed122005-02-27 13:25:31 +00003176 nameGrp1(gregLO3ofRM(modrm)), nameISize(sz), d64,
sewardj5b470602005-02-27 13:10:48 +00003177 nameIRegE(sz,pfx,modrm));
sewardj3ca55a12005-01-27 16:06:23 +00003178 } else {
sewardj2e28ac42008-12-04 00:05:12 +00003179 addr = disAMode ( &len, vbi, pfx, delta, dis_buf, /*xtra*/d_sz );
sewardj3ca55a12005-01-27 16:06:23 +00003180
3181 assign(dst0, loadLE(ty,mkexpr(addr)));
sewardj227458e2005-01-31 19:04:50 +00003182 assign(src, mkU(ty,d64 & mask));
sewardj3ca55a12005-01-27 16:06:23 +00003183
sewardj901ed122005-02-27 13:25:31 +00003184 if (gregLO3ofRM(modrm) == 2 /* ADC */) {
sewardje9d8a262009-07-01 08:06:34 +00003185 if (pfx & PFX_LOCK) {
3186 /* cas-style store */
3187 helper_ADC( sz, dst1, dst0, src,
3188 /*store*/addr, dst0/*expVal*/, guest_RIP_curr_instr );
3189 } else {
3190 /* normal store */
3191 helper_ADC( sz, dst1, dst0, src,
3192 /*store*/addr, IRTemp_INVALID, 0 );
3193 }
sewardj3ca55a12005-01-27 16:06:23 +00003194 } else
sewardj901ed122005-02-27 13:25:31 +00003195 if (gregLO3ofRM(modrm) == 3 /* SBB */) {
sewardje9d8a262009-07-01 08:06:34 +00003196 if (pfx & PFX_LOCK) {
3197 /* cas-style store */
3198 helper_SBB( sz, dst1, dst0, src,
3199 /*store*/addr, dst0/*expVal*/, guest_RIP_curr_instr );
3200 } else {
3201 /* normal store */
3202 helper_SBB( sz, dst1, dst0, src,
3203 /*store*/addr, IRTemp_INVALID, 0 );
3204 }
sewardj3ca55a12005-01-27 16:06:23 +00003205 } else {
3206 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
sewardje9d8a262009-07-01 08:06:34 +00003207 if (gregLO3ofRM(modrm) < 7) {
3208 if (pfx & PFX_LOCK) {
3209 casLE( mkexpr(addr), mkexpr(dst0)/*expVal*/,
3210 mkexpr(dst1)/*newVal*/,
3211 guest_RIP_curr_instr );
3212 } else {
3213 storeLE(mkexpr(addr), mkexpr(dst1));
3214 }
3215 }
sewardj3ca55a12005-01-27 16:06:23 +00003216 if (isAddSub(op8))
3217 setFlags_DEP1_DEP2(op8, dst0, src, ty);
3218 else
3219 setFlags_DEP1(op8, dst1, ty);
3220 }
3221
sewardj3ca55a12005-01-27 16:06:23 +00003222 delta += (len+d_sz);
sewardje941eea2005-01-30 19:52:28 +00003223 DIP("%s%c $%lld, %s\n",
sewardj901ed122005-02-27 13:25:31 +00003224 nameGrp1(gregLO3ofRM(modrm)), nameISize(sz),
sewardj227458e2005-01-31 19:04:50 +00003225 d64, dis_buf);
sewardj3ca55a12005-01-27 16:06:23 +00003226 }
3227 return delta;
3228}
3229
3230
sewardj118b23e2005-01-29 02:14:44 +00003231/* Group 2 extended opcodes. shift_expr must be an 8-bit typed
3232 expression. */
3233
3234static
sewardj2e28ac42008-12-04 00:05:12 +00003235ULong dis_Grp2 ( VexAbiInfo* vbi,
3236 Prefix pfx,
sewardj270def42005-07-03 01:03:01 +00003237 Long delta, UChar modrm,
sewardj118b23e2005-01-29 02:14:44 +00003238 Int am_sz, Int d_sz, Int sz, IRExpr* shift_expr,
sewardjfd4203c2007-03-21 00:21:56 +00003239 HChar* shift_expr_txt, Bool* decode_OK )
sewardj118b23e2005-01-29 02:14:44 +00003240{
3241 /* delta on entry points at the modrm byte. */
3242 HChar dis_buf[50];
3243 Int len;
sewardjb5e5c6d2007-01-12 20:29:01 +00003244 Bool isShift, isRotate, isRotateC;
sewardj118b23e2005-01-29 02:14:44 +00003245 IRType ty = szToITy(sz);
3246 IRTemp dst0 = newTemp(ty);
3247 IRTemp dst1 = newTemp(ty);
3248 IRTemp addr = IRTemp_INVALID;
3249
sewardjfd4203c2007-03-21 00:21:56 +00003250 *decode_OK = True;
3251
sewardj118b23e2005-01-29 02:14:44 +00003252 vassert(sz == 1 || sz == 2 || sz == 4 || sz == 8);
3253
3254 /* Put value to shift/rotate in dst0. */
3255 if (epartIsReg(modrm)) {
sewardj5b470602005-02-27 13:10:48 +00003256 assign(dst0, getIRegE(sz, pfx, modrm));
sewardj118b23e2005-01-29 02:14:44 +00003257 delta += (am_sz + d_sz);
3258 } else {
sewardj2e28ac42008-12-04 00:05:12 +00003259 addr = disAMode ( &len, vbi, pfx, delta, dis_buf, /*xtra*/d_sz );
sewardj118b23e2005-01-29 02:14:44 +00003260 assign(dst0, loadLE(ty,mkexpr(addr)));
3261 delta += len + d_sz;
3262 }
3263
3264 isShift = False;
sewardj901ed122005-02-27 13:25:31 +00003265 switch (gregLO3ofRM(modrm)) { case 4: case 5: case 7: isShift = True; }
sewardj118b23e2005-01-29 02:14:44 +00003266
3267 isRotate = False;
sewardj901ed122005-02-27 13:25:31 +00003268 switch (gregLO3ofRM(modrm)) { case 0: case 1: isRotate = True; }
sewardj118b23e2005-01-29 02:14:44 +00003269
sewardjb5e5c6d2007-01-12 20:29:01 +00003270 isRotateC = False;
3271 switch (gregLO3ofRM(modrm)) { case 2: case 3: isRotateC = True; }
sewardj118b23e2005-01-29 02:14:44 +00003272
sewardjfd4203c2007-03-21 00:21:56 +00003273 if (gregLO3ofRM(modrm) == 6) {
3274 *decode_OK = False;
3275 return delta;
3276 }
3277
sewardjb5e5c6d2007-01-12 20:29:01 +00003278 if (!isShift && !isRotate && !isRotateC) {
sewardjfd4203c2007-03-21 00:21:56 +00003279 /*NOTREACHED*/
sewardj118b23e2005-01-29 02:14:44 +00003280 vpanic("dis_Grp2(Reg): unhandled case(amd64)");
3281 }
3282
sewardjb5e5c6d2007-01-12 20:29:01 +00003283 if (isRotateC) {
sewardj112b0992005-07-23 13:19:32 +00003284 /* Call a helper; this insn is so ridiculous it does not deserve
3285 better. One problem is, the helper has to calculate both the
3286 new value and the new flags. This is more than 64 bits, and
3287 there is no way to return more than 64 bits from the helper.
3288 Hence the crude and obvious solution is to call it twice,
3289 using the sign of the sz field to indicate whether it is the
3290 value or rflags result we want.
3291 */
sewardjb5e5c6d2007-01-12 20:29:01 +00003292 Bool left = toBool(gregLO3ofRM(modrm) == 2);
sewardj112b0992005-07-23 13:19:32 +00003293 IRExpr** argsVALUE;
3294 IRExpr** argsRFLAGS;
3295
3296 IRTemp new_value = newTemp(Ity_I64);
3297 IRTemp new_rflags = newTemp(Ity_I64);
3298 IRTemp old_rflags = newTemp(Ity_I64);
3299
3300 assign( old_rflags, widenUto64(mk_amd64g_calculate_rflags_all()) );
3301
3302 argsVALUE
3303 = mkIRExprVec_4( widenUto64(mkexpr(dst0)), /* thing to rotate */
3304 widenUto64(shift_expr), /* rotate amount */
3305 mkexpr(old_rflags),
3306 mkU64(sz) );
3307 assign( new_value,
3308 mkIRExprCCall(
3309 Ity_I64,
3310 0/*regparm*/,
sewardjb5e5c6d2007-01-12 20:29:01 +00003311 left ? "amd64g_calculate_RCL" : "amd64g_calculate_RCR",
3312 left ? &amd64g_calculate_RCL : &amd64g_calculate_RCR,
sewardj112b0992005-07-23 13:19:32 +00003313 argsVALUE
3314 )
3315 );
3316
3317 argsRFLAGS
3318 = mkIRExprVec_4( widenUto64(mkexpr(dst0)), /* thing to rotate */
3319 widenUto64(shift_expr), /* rotate amount */
3320 mkexpr(old_rflags),
3321 mkU64(-sz) );
3322 assign( new_rflags,
3323 mkIRExprCCall(
3324 Ity_I64,
3325 0/*regparm*/,
sewardjb5e5c6d2007-01-12 20:29:01 +00003326 left ? "amd64g_calculate_RCL" : "amd64g_calculate_RCR",
3327 left ? &amd64g_calculate_RCL : &amd64g_calculate_RCR,
sewardj112b0992005-07-23 13:19:32 +00003328 argsRFLAGS
3329 )
3330 );
3331
3332 assign( dst1, narrowTo(ty, mkexpr(new_value)) );
3333 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(AMD64G_CC_OP_COPY) ));
3334 stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(new_rflags) ));
3335 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
3336 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU64(0) ));
sewardj118b23e2005-01-29 02:14:44 +00003337 }
3338
sewardj112b0992005-07-23 13:19:32 +00003339 else
sewardj118b23e2005-01-29 02:14:44 +00003340 if (isShift) {
3341
3342 IRTemp pre64 = newTemp(Ity_I64);
3343 IRTemp res64 = newTemp(Ity_I64);
3344 IRTemp res64ss = newTemp(Ity_I64);
3345 IRTemp shift_amt = newTemp(Ity_I8);
sewardj1027dc22005-02-26 01:55:02 +00003346 UChar mask = toUChar(sz==8 ? 63 : 31);
sewardj118b23e2005-01-29 02:14:44 +00003347 IROp op64;
3348
sewardj901ed122005-02-27 13:25:31 +00003349 switch (gregLO3ofRM(modrm)) {
sewardj118b23e2005-01-29 02:14:44 +00003350 case 4: op64 = Iop_Shl64; break;
3351 case 5: op64 = Iop_Shr64; break;
3352 case 7: op64 = Iop_Sar64; break;
sewardjfd4203c2007-03-21 00:21:56 +00003353 /*NOTREACHED*/
sewardj118b23e2005-01-29 02:14:44 +00003354 default: vpanic("dis_Grp2:shift"); break;
3355 }
3356
3357 /* Widen the value to be shifted to 64 bits, do the shift, and
3358 narrow back down. This seems surprisingly long-winded, but
3359 unfortunately the AMD semantics requires that 8/16/32-bit
3360 shifts give defined results for shift values all the way up
sewardj03c96e82005-02-19 18:12:45 +00003361 to 32, and this seems the simplest way to do it. It has the
sewardj118b23e2005-01-29 02:14:44 +00003362 advantage that the only IR level shifts generated are of 64
3363 bit values, and the shift amount is guaranteed to be in the
3364 range 0 .. 63, thereby observing the IR semantics requiring
sewardj03c96e82005-02-19 18:12:45 +00003365 all shift values to be in the range 0 .. 2^word_size-1.
sewardj118b23e2005-01-29 02:14:44 +00003366
sewardj03c96e82005-02-19 18:12:45 +00003367 Therefore the shift amount is masked with 63 for 64-bit shifts
3368 and 31 for all others.
3369 */
3370 /* shift_amt = shift_expr & MASK, regardless of operation size */
3371 assign( shift_amt, binop(Iop_And8, shift_expr, mkU8(mask)) );
sewardj118b23e2005-01-29 02:14:44 +00003372
sewardj03c96e82005-02-19 18:12:45 +00003373 /* suitably widen the value to be shifted to 64 bits. */
sewardj118b23e2005-01-29 02:14:44 +00003374 assign( pre64, op64==Iop_Sar64 ? widenSto64(mkexpr(dst0))
3375 : widenUto64(mkexpr(dst0)) );
3376
3377 /* res64 = pre64 `shift` shift_amt */
3378 assign( res64, binop(op64, mkexpr(pre64), mkexpr(shift_amt)) );
3379
sewardj03c96e82005-02-19 18:12:45 +00003380 /* res64ss = pre64 `shift` ((shift_amt - 1) & MASK) */
sewardj118b23e2005-01-29 02:14:44 +00003381 assign( res64ss,
3382 binop(op64,
3383 mkexpr(pre64),
3384 binop(Iop_And8,
3385 binop(Iop_Sub8,
3386 mkexpr(shift_amt), mkU8(1)),
sewardj03c96e82005-02-19 18:12:45 +00003387 mkU8(mask))) );
sewardj118b23e2005-01-29 02:14:44 +00003388
3389 /* Build the flags thunk. */
3390 setFlags_DEP1_DEP2_shift(op64, res64, res64ss, ty, shift_amt);
3391
3392 /* Narrow the result back down. */
3393 assign( dst1, narrowTo(ty, mkexpr(res64)) );
3394
3395 } /* if (isShift) */
3396
3397 else
3398 if (isRotate) {
3399 Int ccOp = ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1
3400 : (ty==Ity_I32 ? 2 : 3));
sewardj901ed122005-02-27 13:25:31 +00003401 Bool left = toBool(gregLO3ofRM(modrm) == 0);
sewardj118b23e2005-01-29 02:14:44 +00003402 IRTemp rot_amt = newTemp(Ity_I8);
3403 IRTemp rot_amt64 = newTemp(Ity_I8);
3404 IRTemp oldFlags = newTemp(Ity_I64);
sewardj1027dc22005-02-26 01:55:02 +00003405 UChar mask = toUChar(sz==8 ? 63 : 31);
sewardj118b23e2005-01-29 02:14:44 +00003406
3407 /* rot_amt = shift_expr & mask */
3408 /* By masking the rotate amount thusly, the IR-level Shl/Shr
3409 expressions never shift beyond the word size and thus remain
3410 well defined. */
sewardj03c96e82005-02-19 18:12:45 +00003411 assign(rot_amt64, binop(Iop_And8, shift_expr, mkU8(mask)));
sewardj118b23e2005-01-29 02:14:44 +00003412
3413 if (ty == Ity_I64)
3414 assign(rot_amt, mkexpr(rot_amt64));
3415 else
3416 assign(rot_amt, binop(Iop_And8, mkexpr(rot_amt64), mkU8(8*sz-1)));
3417
3418 if (left) {
3419
3420 /* dst1 = (dst0 << rot_amt) | (dst0 >>u (wordsize-rot_amt)) */
3421 assign(dst1,
3422 binop( mkSizedOp(ty,Iop_Or8),
3423 binop( mkSizedOp(ty,Iop_Shl8),
3424 mkexpr(dst0),
3425 mkexpr(rot_amt)
3426 ),
3427 binop( mkSizedOp(ty,Iop_Shr8),
3428 mkexpr(dst0),
3429 binop(Iop_Sub8,mkU8(8*sz), mkexpr(rot_amt))
3430 )
3431 )
3432 );
3433 ccOp += AMD64G_CC_OP_ROLB;
3434
3435 } else { /* right */
3436
3437 /* dst1 = (dst0 >>u rot_amt) | (dst0 << (wordsize-rot_amt)) */
3438 assign(dst1,
3439 binop( mkSizedOp(ty,Iop_Or8),
3440 binop( mkSizedOp(ty,Iop_Shr8),
3441 mkexpr(dst0),
3442 mkexpr(rot_amt)
3443 ),
3444 binop( mkSizedOp(ty,Iop_Shl8),
3445 mkexpr(dst0),
3446 binop(Iop_Sub8,mkU8(8*sz), mkexpr(rot_amt))
3447 )
3448 )
3449 );
3450 ccOp += AMD64G_CC_OP_RORB;
3451
3452 }
3453
3454 /* dst1 now holds the rotated value. Build flag thunk. We
3455 need the resulting value for this, and the previous flags.
3456 Except don't set it if the rotate count is zero. */
3457
3458 assign(oldFlags, mk_amd64g_calculate_rflags_all());
3459
3460 /* CC_DEP1 is the rotated value. CC_NDEP is flags before. */
3461 stmt( IRStmt_Put( OFFB_CC_OP,
3462 IRExpr_Mux0X( mkexpr(rot_amt64),
3463 IRExpr_Get(OFFB_CC_OP,Ity_I64),
3464 mkU64(ccOp))) );
3465 stmt( IRStmt_Put( OFFB_CC_DEP1,
3466 IRExpr_Mux0X( mkexpr(rot_amt64),
3467 IRExpr_Get(OFFB_CC_DEP1,Ity_I64),
3468 widenUto64(mkexpr(dst1)))) );
3469 stmt( IRStmt_Put( OFFB_CC_DEP2,
3470 IRExpr_Mux0X( mkexpr(rot_amt64),
3471 IRExpr_Get(OFFB_CC_DEP2,Ity_I64),
3472 mkU64(0))) );
3473 stmt( IRStmt_Put( OFFB_CC_NDEP,
3474 IRExpr_Mux0X( mkexpr(rot_amt64),
3475 IRExpr_Get(OFFB_CC_NDEP,Ity_I64),
3476 mkexpr(oldFlags))) );
3477 } /* if (isRotate) */
3478
3479 /* Save result, and finish up. */
3480 if (epartIsReg(modrm)) {
sewardj5b470602005-02-27 13:10:48 +00003481 putIRegE(sz, pfx, modrm, mkexpr(dst1));
sewardj118b23e2005-01-29 02:14:44 +00003482 if (vex_traceflags & VEX_TRACE_FE) {
3483 vex_printf("%s%c ",
sewardj901ed122005-02-27 13:25:31 +00003484 nameGrp2(gregLO3ofRM(modrm)), nameISize(sz) );
sewardj118b23e2005-01-29 02:14:44 +00003485 if (shift_expr_txt)
3486 vex_printf("%s", shift_expr_txt);
3487 else
3488 ppIRExpr(shift_expr);
sewardj5b470602005-02-27 13:10:48 +00003489 vex_printf(", %s\n", nameIRegE(sz,pfx,modrm));
sewardj118b23e2005-01-29 02:14:44 +00003490 }
3491 } else {
3492 storeLE(mkexpr(addr), mkexpr(dst1));
3493 if (vex_traceflags & VEX_TRACE_FE) {
3494 vex_printf("%s%c ",
sewardj901ed122005-02-27 13:25:31 +00003495 nameGrp2(gregLO3ofRM(modrm)), nameISize(sz) );
sewardj118b23e2005-01-29 02:14:44 +00003496 if (shift_expr_txt)
3497 vex_printf("%s", shift_expr_txt);
3498 else
3499 ppIRExpr(shift_expr);
3500 vex_printf(", %s\n", dis_buf);
3501 }
3502 }
3503 return delta;
3504}
3505
3506
sewardj1d511802005-03-27 17:59:45 +00003507/* Group 8 extended opcodes (but BT/BTS/BTC/BTR only). */
3508static
sewardj2e28ac42008-12-04 00:05:12 +00003509ULong dis_Grp8_Imm ( VexAbiInfo* vbi,
3510 Prefix pfx,
sewardj270def42005-07-03 01:03:01 +00003511 Long delta, UChar modrm,
sewardj1d511802005-03-27 17:59:45 +00003512 Int am_sz, Int sz, ULong src_val,
3513 Bool* decode_OK )
3514{
3515 /* src_val denotes a d8.
3516 And delta on entry points at the modrm byte. */
sewardj118b23e2005-01-29 02:14:44 +00003517
sewardj1d511802005-03-27 17:59:45 +00003518 IRType ty = szToITy(sz);
3519 IRTemp t2 = newTemp(Ity_I64);
3520 IRTemp t2m = newTemp(Ity_I64);
3521 IRTemp t_addr = IRTemp_INVALID;
3522 HChar dis_buf[50];
3523 ULong mask;
sewardj9b967672005-02-08 11:13:09 +00003524
sewardj1d511802005-03-27 17:59:45 +00003525 /* we're optimists :-) */
3526 *decode_OK = True;
3527
3528 /* Limit src_val -- the bit offset -- to something within a word.
3529 The Intel docs say that literal offsets larger than a word are
3530 masked in this way. */
3531 switch (sz) {
3532 case 2: src_val &= 15; break;
3533 case 4: src_val &= 31; break;
sewardj537cab02005-04-07 02:03:52 +00003534 case 8: src_val &= 63; break;
sewardj1d511802005-03-27 17:59:45 +00003535 default: *decode_OK = False; return delta;
3536 }
3537
3538 /* Invent a mask suitable for the operation. */
3539 switch (gregLO3ofRM(modrm)) {
sewardj74b4f892005-05-06 01:43:56 +00003540 case 4: /* BT */ mask = 0; break;
3541 case 5: /* BTS */ mask = 1ULL << src_val; break;
3542 case 6: /* BTR */ mask = ~(1ULL << src_val); break;
3543 case 7: /* BTC */ mask = 1ULL << src_val; break;
sewardj1d511802005-03-27 17:59:45 +00003544 /* If this needs to be extended, probably simplest to make a
3545 new function to handle the other cases (0 .. 3). The
3546 Intel docs do however not indicate any use for 0 .. 3, so
3547 we don't expect this to happen. */
3548 default: *decode_OK = False; return delta;
3549 }
3550
3551 /* Fetch the value to be tested and modified into t2, which is
3552 64-bits wide regardless of sz. */
3553 if (epartIsReg(modrm)) {
3554 vassert(am_sz == 1);
3555 assign( t2, widenUto64(getIRegE(sz, pfx, modrm)) );
3556 delta += (am_sz + 1);
3557 DIP("%s%c $0x%llx, %s\n", nameGrp8(gregLO3ofRM(modrm)),
3558 nameISize(sz),
3559 src_val, nameIRegE(sz,pfx,modrm));
3560 } else {
3561 Int len;
sewardj2e28ac42008-12-04 00:05:12 +00003562 t_addr = disAMode ( &len, vbi, pfx, delta, dis_buf, 1 );
sewardj1d511802005-03-27 17:59:45 +00003563 delta += (len+1);
3564 assign( t2, widenUto64(loadLE(ty, mkexpr(t_addr))) );
3565 DIP("%s%c $0x%llx, %s\n", nameGrp8(gregLO3ofRM(modrm)),
3566 nameISize(sz),
3567 src_val, dis_buf);
3568 }
3569
sewardj1d511802005-03-27 17:59:45 +00003570 /* Compute the new value into t2m, if non-BT. */
3571 switch (gregLO3ofRM(modrm)) {
3572 case 4: /* BT */
3573 break;
3574 case 5: /* BTS */
3575 assign( t2m, binop(Iop_Or64, mkU64(mask), mkexpr(t2)) );
3576 break;
3577 case 6: /* BTR */
3578 assign( t2m, binop(Iop_And64, mkU64(mask), mkexpr(t2)) );
3579 break;
3580 case 7: /* BTC */
3581 assign( t2m, binop(Iop_Xor64, mkU64(mask), mkexpr(t2)) );
3582 break;
3583 default:
sewardje9d8a262009-07-01 08:06:34 +00003584 /*NOTREACHED*/ /*the previous switch guards this*/
sewardj1d511802005-03-27 17:59:45 +00003585 vassert(0);
3586 }
3587
3588 /* Write the result back, if non-BT. */
3589 if (gregLO3ofRM(modrm) != 4 /* BT */) {
3590 if (epartIsReg(modrm)) {
3591 putIRegE(sz, pfx, modrm, narrowTo(ty, mkexpr(t2m)));
3592 } else {
sewardje9d8a262009-07-01 08:06:34 +00003593 if (pfx & PFX_LOCK) {
3594 casLE( mkexpr(t_addr),
3595 narrowTo(ty, mkexpr(t2))/*expd*/,
3596 narrowTo(ty, mkexpr(t2m))/*new*/,
3597 guest_RIP_curr_instr );
3598 } else {
3599 storeLE(mkexpr(t_addr), narrowTo(ty, mkexpr(t2m)));
3600 }
sewardj1d511802005-03-27 17:59:45 +00003601 }
3602 }
3603
sewardje9d8a262009-07-01 08:06:34 +00003604 /* Copy relevant bit from t2 into the carry flag. */
3605 /* Flags: C=selected bit, O,S,Z,A,P undefined, so are set to zero. */
3606 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(AMD64G_CC_OP_COPY) ));
3607 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
3608 stmt( IRStmt_Put(
3609 OFFB_CC_DEP1,
3610 binop(Iop_And64,
3611 binop(Iop_Shr64, mkexpr(t2), mkU8(src_val)),
3612 mkU64(1))
3613 ));
3614 /* Set NDEP even though it isn't used. This makes redundant-PUT
3615 elimination of previous stores to this field work better. */
3616 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU64(0) ));
3617
sewardj1d511802005-03-27 17:59:45 +00003618 return delta;
3619}
sewardj9b967672005-02-08 11:13:09 +00003620
3621
3622/* Signed/unsigned widening multiply. Generate IR to multiply the
3623 value in RAX/EAX/AX/AL by the given IRTemp, and park the result in
3624 RDX:RAX/EDX:EAX/DX:AX/AX.
3625*/
3626static void codegen_mulL_A_D ( Int sz, Bool syned,
sewardj1027dc22005-02-26 01:55:02 +00003627 IRTemp tmp, HChar* tmp_txt )
sewardj9b967672005-02-08 11:13:09 +00003628{
3629 IRType ty = szToITy(sz);
3630 IRTemp t1 = newTemp(ty);
3631
sewardj5b470602005-02-27 13:10:48 +00003632 assign( t1, getIRegRAX(sz) );
sewardj9b967672005-02-08 11:13:09 +00003633
3634 switch (ty) {
3635 case Ity_I64: {
3636 IRTemp res128 = newTemp(Ity_I128);
3637 IRTemp resHi = newTemp(Ity_I64);
3638 IRTemp resLo = newTemp(Ity_I64);
3639 IROp mulOp = syned ? Iop_MullS64 : Iop_MullU64;
sewardj8bdb89a2005-05-05 21:46:50 +00003640 UInt tBaseOp = syned ? AMD64G_CC_OP_SMULB : AMD64G_CC_OP_UMULB;
sewardj9b967672005-02-08 11:13:09 +00003641 setFlags_MUL ( Ity_I64, t1, tmp, tBaseOp );
3642 assign( res128, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
3643 assign( resHi, unop(Iop_128HIto64,mkexpr(res128)));
3644 assign( resLo, unop(Iop_128to64,mkexpr(res128)));
sewardj5b470602005-02-27 13:10:48 +00003645 putIReg64(R_RDX, mkexpr(resHi));
3646 putIReg64(R_RAX, mkexpr(resLo));
sewardj9b967672005-02-08 11:13:09 +00003647 break;
3648 }
sewardj85520e42005-02-19 15:22:38 +00003649 case Ity_I32: {
3650 IRTemp res64 = newTemp(Ity_I64);
3651 IRTemp resHi = newTemp(Ity_I32);
3652 IRTemp resLo = newTemp(Ity_I32);
3653 IROp mulOp = syned ? Iop_MullS32 : Iop_MullU32;
3654 UInt tBaseOp = syned ? AMD64G_CC_OP_SMULB : AMD64G_CC_OP_UMULB;
3655 setFlags_MUL ( Ity_I32, t1, tmp, tBaseOp );
3656 assign( res64, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
3657 assign( resHi, unop(Iop_64HIto32,mkexpr(res64)));
3658 assign( resLo, unop(Iop_64to32,mkexpr(res64)));
sewardj5b470602005-02-27 13:10:48 +00003659 putIRegRDX(4, mkexpr(resHi));
3660 putIRegRAX(4, mkexpr(resLo));
sewardj85520e42005-02-19 15:22:38 +00003661 break;
3662 }
3663 case Ity_I16: {
3664 IRTemp res32 = newTemp(Ity_I32);
3665 IRTemp resHi = newTemp(Ity_I16);
3666 IRTemp resLo = newTemp(Ity_I16);
3667 IROp mulOp = syned ? Iop_MullS16 : Iop_MullU16;
3668 UInt tBaseOp = syned ? AMD64G_CC_OP_SMULB : AMD64G_CC_OP_UMULB;
3669 setFlags_MUL ( Ity_I16, t1, tmp, tBaseOp );
3670 assign( res32, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
3671 assign( resHi, unop(Iop_32HIto16,mkexpr(res32)));
3672 assign( resLo, unop(Iop_32to16,mkexpr(res32)));
sewardj5b470602005-02-27 13:10:48 +00003673 putIRegRDX(2, mkexpr(resHi));
3674 putIRegRAX(2, mkexpr(resLo));
sewardj85520e42005-02-19 15:22:38 +00003675 break;
3676 }
3677 case Ity_I8: {
3678 IRTemp res16 = newTemp(Ity_I16);
3679 IRTemp resHi = newTemp(Ity_I8);
3680 IRTemp resLo = newTemp(Ity_I8);
3681 IROp mulOp = syned ? Iop_MullS8 : Iop_MullU8;
3682 UInt tBaseOp = syned ? AMD64G_CC_OP_SMULB : AMD64G_CC_OP_UMULB;
3683 setFlags_MUL ( Ity_I8, t1, tmp, tBaseOp );
3684 assign( res16, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
3685 assign( resHi, unop(Iop_16HIto8,mkexpr(res16)));
3686 assign( resLo, unop(Iop_16to8,mkexpr(res16)));
sewardj5b470602005-02-27 13:10:48 +00003687 putIRegRAX(2, mkexpr(res16));
sewardj85520e42005-02-19 15:22:38 +00003688 break;
3689 }
sewardj9b967672005-02-08 11:13:09 +00003690 default:
sewardj85520e42005-02-19 15:22:38 +00003691 ppIRType(ty);
sewardj9b967672005-02-08 11:13:09 +00003692 vpanic("codegen_mulL_A_D(amd64)");
3693 }
3694 DIP("%s%c %s\n", syned ? "imul" : "mul", nameISize(sz), tmp_txt);
3695}
sewardj32b2bbe2005-01-28 00:50:10 +00003696
3697
3698/* Group 3 extended opcodes. */
3699static
sewardj2e28ac42008-12-04 00:05:12 +00003700ULong dis_Grp3 ( VexAbiInfo* vbi,
3701 Prefix pfx, Int sz, Long delta, Bool* decode_OK )
sewardj32b2bbe2005-01-28 00:50:10 +00003702{
sewardj227458e2005-01-31 19:04:50 +00003703 Long d64;
sewardj32b2bbe2005-01-28 00:50:10 +00003704 UChar modrm;
3705 HChar dis_buf[50];
3706 Int len;
3707 IRTemp addr;
3708 IRType ty = szToITy(sz);
3709 IRTemp t1 = newTemp(ty);
sewardj55dbb262005-01-28 16:36:51 +00003710 IRTemp dst1, src, dst0;
sewardjfd4203c2007-03-21 00:21:56 +00003711 *decode_OK = True;
sewardj8c332e22005-01-28 01:36:56 +00003712 modrm = getUChar(delta);
sewardj32b2bbe2005-01-28 00:50:10 +00003713 if (epartIsReg(modrm)) {
sewardj901ed122005-02-27 13:25:31 +00003714 switch (gregLO3ofRM(modrm)) {
sewardj118b23e2005-01-29 02:14:44 +00003715 case 0: { /* TEST */
3716 delta++;
3717 d64 = getSDisp(imin(4,sz), delta);
3718 delta += imin(4,sz);
3719 dst1 = newTemp(ty);
3720 assign(dst1, binop(mkSizedOp(ty,Iop_And8),
sewardj5b470602005-02-27 13:10:48 +00003721 getIRegE(sz,pfx,modrm),
sewardj03b07cc2005-01-31 18:09:43 +00003722 mkU(ty, d64 & mkSizeMask(sz))));
sewardj118b23e2005-01-29 02:14:44 +00003723 setFlags_DEP1( Iop_And8, dst1, ty );
sewardj7eaa7cf2005-01-31 18:55:22 +00003724 DIP("test%c $%lld, %s\n",
sewardj118b23e2005-01-29 02:14:44 +00003725 nameISize(sz), d64,
sewardj5b470602005-02-27 13:10:48 +00003726 nameIRegE(sz, pfx, modrm));
sewardj118b23e2005-01-29 02:14:44 +00003727 break;
3728 }
sewardjfd4203c2007-03-21 00:21:56 +00003729 case 1:
3730 *decode_OK = False;
3731 return delta;
sewardj55dbb262005-01-28 16:36:51 +00003732 case 2: /* NOT */
3733 delta++;
sewardj5b470602005-02-27 13:10:48 +00003734 putIRegE(sz, pfx, modrm,
3735 unop(mkSizedOp(ty,Iop_Not8),
3736 getIRegE(sz, pfx, modrm)));
sewardj55dbb262005-01-28 16:36:51 +00003737 DIP("not%c %s\n", nameISize(sz),
sewardj5b470602005-02-27 13:10:48 +00003738 nameIRegE(sz, pfx, modrm));
sewardj55dbb262005-01-28 16:36:51 +00003739 break;
3740 case 3: /* NEG */
3741 delta++;
3742 dst0 = newTemp(ty);
3743 src = newTemp(ty);
3744 dst1 = newTemp(ty);
3745 assign(dst0, mkU(ty,0));
sewardj5b470602005-02-27 13:10:48 +00003746 assign(src, getIRegE(sz, pfx, modrm));
sewardj2e28ac42008-12-04 00:05:12 +00003747 assign(dst1, binop(mkSizedOp(ty,Iop_Sub8), mkexpr(dst0),
3748 mkexpr(src)));
sewardj55dbb262005-01-28 16:36:51 +00003749 setFlags_DEP1_DEP2(Iop_Sub8, dst0, src, ty);
sewardj5b470602005-02-27 13:10:48 +00003750 putIRegE(sz, pfx, modrm, mkexpr(dst1));
3751 DIP("neg%c %s\n", nameISize(sz), nameIRegE(sz, pfx, modrm));
sewardj55dbb262005-01-28 16:36:51 +00003752 break;
sewardj9b967672005-02-08 11:13:09 +00003753 case 4: /* MUL (unsigned widening) */
3754 delta++;
3755 src = newTemp(ty);
sewardj5b470602005-02-27 13:10:48 +00003756 assign(src, getIRegE(sz,pfx,modrm));
sewardj9b967672005-02-08 11:13:09 +00003757 codegen_mulL_A_D ( sz, False, src,
sewardj5b470602005-02-27 13:10:48 +00003758 nameIRegE(sz,pfx,modrm) );
sewardj9b967672005-02-08 11:13:09 +00003759 break;
sewardj85520e42005-02-19 15:22:38 +00003760 case 5: /* IMUL (signed widening) */
3761 delta++;
3762 src = newTemp(ty);
sewardj5b470602005-02-27 13:10:48 +00003763 assign(src, getIRegE(sz,pfx,modrm));
sewardj85520e42005-02-19 15:22:38 +00003764 codegen_mulL_A_D ( sz, True, src,
sewardj5b470602005-02-27 13:10:48 +00003765 nameIRegE(sz,pfx,modrm) );
sewardj85520e42005-02-19 15:22:38 +00003766 break;
sewardj03b07cc2005-01-31 18:09:43 +00003767 case 6: /* DIV */
3768 delta++;
sewardj5b470602005-02-27 13:10:48 +00003769 assign( t1, getIRegE(sz, pfx, modrm) );
sewardj03b07cc2005-01-31 18:09:43 +00003770 codegen_div ( sz, t1, False );
3771 DIP("div%c %s\n", nameISize(sz),
sewardj5b470602005-02-27 13:10:48 +00003772 nameIRegE(sz, pfx, modrm));
sewardj03b07cc2005-01-31 18:09:43 +00003773 break;
sewardj32b2bbe2005-01-28 00:50:10 +00003774 case 7: /* IDIV */
3775 delta++;
sewardj5b470602005-02-27 13:10:48 +00003776 assign( t1, getIRegE(sz, pfx, modrm) );
sewardj32b2bbe2005-01-28 00:50:10 +00003777 codegen_div ( sz, t1, True );
3778 DIP("idiv%c %s\n", nameISize(sz),
sewardj5b470602005-02-27 13:10:48 +00003779 nameIRegE(sz, pfx, modrm));
sewardj32b2bbe2005-01-28 00:50:10 +00003780 break;
3781 default:
sewardjfd4203c2007-03-21 00:21:56 +00003782 /*NOTREACHED*/
3783 vpanic("Grp3(amd64,R)");
sewardj32b2bbe2005-01-28 00:50:10 +00003784 }
3785 } else {
sewardj2e28ac42008-12-04 00:05:12 +00003786 addr = disAMode ( &len, vbi, pfx, delta, dis_buf,
sewardj7de0d3c2005-02-13 02:26:41 +00003787 /* we have to inform disAMode of any immediate
3788 bytes used */
sewardj901ed122005-02-27 13:25:31 +00003789 gregLO3ofRM(modrm)==0/*TEST*/
sewardj7de0d3c2005-02-13 02:26:41 +00003790 ? imin(4,sz)
3791 : 0
3792 );
sewardj32b2bbe2005-01-28 00:50:10 +00003793 t1 = newTemp(ty);
3794 delta += len;
3795 assign(t1, loadLE(ty,mkexpr(addr)));
sewardj901ed122005-02-27 13:25:31 +00003796 switch (gregLO3ofRM(modrm)) {
sewardj03b07cc2005-01-31 18:09:43 +00003797 case 0: { /* TEST */
3798 d64 = getSDisp(imin(4,sz), delta);
3799 delta += imin(4,sz);
3800 dst1 = newTemp(ty);
3801 assign(dst1, binop(mkSizedOp(ty,Iop_And8),
3802 mkexpr(t1),
3803 mkU(ty, d64 & mkSizeMask(sz))));
3804 setFlags_DEP1( Iop_And8, dst1, ty );
3805 DIP("test%c $%lld, %s\n", nameISize(sz), d64, dis_buf);
3806 break;
3807 }
sewardjfd4203c2007-03-21 00:21:56 +00003808 case 1:
3809 *decode_OK = False;
3810 return delta;
sewardj82c9f2f2005-03-02 16:05:13 +00003811 case 2: /* NOT */
sewardje9d8a262009-07-01 08:06:34 +00003812 dst1 = newTemp(ty);
3813 assign(dst1, unop(mkSizedOp(ty,Iop_Not8), mkexpr(t1)));
3814 if (pfx & PFX_LOCK) {
3815 casLE( mkexpr(addr), mkexpr(t1)/*expd*/, mkexpr(dst1)/*new*/,
3816 guest_RIP_curr_instr );
3817 } else {
3818 storeLE( mkexpr(addr), mkexpr(dst1) );
3819 }
sewardj82c9f2f2005-03-02 16:05:13 +00003820 DIP("not%c %s\n", nameISize(sz), dis_buf);
3821 break;
sewardj7de0d3c2005-02-13 02:26:41 +00003822 case 3: /* NEG */
3823 dst0 = newTemp(ty);
3824 src = newTemp(ty);
3825 dst1 = newTemp(ty);
3826 assign(dst0, mkU(ty,0));
3827 assign(src, mkexpr(t1));
sewardj2e28ac42008-12-04 00:05:12 +00003828 assign(dst1, binop(mkSizedOp(ty,Iop_Sub8), mkexpr(dst0),
3829 mkexpr(src)));
sewardje9d8a262009-07-01 08:06:34 +00003830 if (pfx & PFX_LOCK) {
3831 casLE( mkexpr(addr), mkexpr(t1)/*expd*/, mkexpr(dst1)/*new*/,
3832 guest_RIP_curr_instr );
3833 } else {
3834 storeLE( mkexpr(addr), mkexpr(dst1) );
3835 }
sewardj7de0d3c2005-02-13 02:26:41 +00003836 setFlags_DEP1_DEP2(Iop_Sub8, dst0, src, ty);
sewardj7de0d3c2005-02-13 02:26:41 +00003837 DIP("neg%c %s\n", nameISize(sz), dis_buf);
3838 break;
sewardj31eecde2005-03-23 03:39:55 +00003839 case 4: /* MUL (unsigned widening) */
3840 codegen_mulL_A_D ( sz, False, t1, dis_buf );
3841 break;
sewardj3aba9eb2005-03-30 23:20:47 +00003842 case 5: /* IMUL */
3843 codegen_mulL_A_D ( sz, True, t1, dis_buf );
3844 break;
sewardj1001dc42005-02-21 08:25:55 +00003845 case 6: /* DIV */
3846 codegen_div ( sz, t1, False );
3847 DIP("div%c %s\n", nameISize(sz), dis_buf);
3848 break;
sewardj82c9f2f2005-03-02 16:05:13 +00003849 case 7: /* IDIV */
3850 codegen_div ( sz, t1, True );
3851 DIP("idiv%c %s\n", nameISize(sz), dis_buf);
3852 break;
sewardj32b2bbe2005-01-28 00:50:10 +00003853 default:
sewardjfd4203c2007-03-21 00:21:56 +00003854 /*NOTREACHED*/
3855 vpanic("Grp3(amd64,M)");
sewardj32b2bbe2005-01-28 00:50:10 +00003856 }
3857 }
3858 return delta;
3859}
3860
3861
sewardj03b07cc2005-01-31 18:09:43 +00003862/* Group 4 extended opcodes. */
3863static
sewardj2e28ac42008-12-04 00:05:12 +00003864ULong dis_Grp4 ( VexAbiInfo* vbi,
3865 Prefix pfx, Long delta, Bool* decode_OK )
sewardj03b07cc2005-01-31 18:09:43 +00003866{
3867 Int alen;
3868 UChar modrm;
3869 HChar dis_buf[50];
3870 IRType ty = Ity_I8;
3871 IRTemp t1 = newTemp(ty);
3872 IRTemp t2 = newTemp(ty);
3873
sewardjfd4203c2007-03-21 00:21:56 +00003874 *decode_OK = True;
3875
sewardj03b07cc2005-01-31 18:09:43 +00003876 modrm = getUChar(delta);
3877 if (epartIsReg(modrm)) {
sewardj5b470602005-02-27 13:10:48 +00003878 assign(t1, getIRegE(1, pfx, modrm));
sewardj901ed122005-02-27 13:25:31 +00003879 switch (gregLO3ofRM(modrm)) {
sewardj85520e42005-02-19 15:22:38 +00003880 case 0: /* INC */
3881 assign(t2, binop(Iop_Add8, mkexpr(t1), mkU8(1)));
sewardj5b470602005-02-27 13:10:48 +00003882 putIRegE(1, pfx, modrm, mkexpr(t2));
sewardj85520e42005-02-19 15:22:38 +00003883 setFlags_INC_DEC( True, t2, ty );
3884 break;
sewardj03b07cc2005-01-31 18:09:43 +00003885 case 1: /* DEC */
3886 assign(t2, binop(Iop_Sub8, mkexpr(t1), mkU8(1)));
sewardj5b470602005-02-27 13:10:48 +00003887 putIRegE(1, pfx, modrm, mkexpr(t2));
sewardj03b07cc2005-01-31 18:09:43 +00003888 setFlags_INC_DEC( False, t2, ty );
3889 break;
3890 default:
sewardjfd4203c2007-03-21 00:21:56 +00003891 *decode_OK = False;
3892 return delta;
sewardj03b07cc2005-01-31 18:09:43 +00003893 }
3894 delta++;
sewardj901ed122005-02-27 13:25:31 +00003895 DIP("%sb %s\n", nameGrp4(gregLO3ofRM(modrm)),
sewardj5b470602005-02-27 13:10:48 +00003896 nameIRegE(1, pfx, modrm));
sewardj03b07cc2005-01-31 18:09:43 +00003897 } else {
sewardj2e28ac42008-12-04 00:05:12 +00003898 IRTemp addr = disAMode ( &alen, vbi, pfx, delta, dis_buf, 0 );
sewardj03b07cc2005-01-31 18:09:43 +00003899 assign( t1, loadLE(ty, mkexpr(addr)) );
sewardj901ed122005-02-27 13:25:31 +00003900 switch (gregLO3ofRM(modrm)) {
sewardj007e9ec2005-03-23 11:36:48 +00003901 case 0: /* INC */
3902 assign(t2, binop(Iop_Add8, mkexpr(t1), mkU8(1)));
sewardje9d8a262009-07-01 08:06:34 +00003903 if (pfx & PFX_LOCK) {
3904 casLE( mkexpr(addr), mkexpr(t1)/*expd*/, mkexpr(t2)/*new*/,
3905 guest_RIP_curr_instr );
3906 } else {
3907 storeLE( mkexpr(addr), mkexpr(t2) );
3908 }
sewardj007e9ec2005-03-23 11:36:48 +00003909 setFlags_INC_DEC( True, t2, ty );
3910 break;
3911 case 1: /* DEC */
3912 assign(t2, binop(Iop_Sub8, mkexpr(t1), mkU8(1)));
sewardje9d8a262009-07-01 08:06:34 +00003913 if (pfx & PFX_LOCK) {
3914 casLE( mkexpr(addr), mkexpr(t1)/*expd*/, mkexpr(t2)/*new*/,
3915 guest_RIP_curr_instr );
3916 } else {
3917 storeLE( mkexpr(addr), mkexpr(t2) );
3918 }
sewardj007e9ec2005-03-23 11:36:48 +00003919 setFlags_INC_DEC( False, t2, ty );
3920 break;
sewardj03b07cc2005-01-31 18:09:43 +00003921 default:
sewardjfd4203c2007-03-21 00:21:56 +00003922 *decode_OK = False;
3923 return delta;
sewardj03b07cc2005-01-31 18:09:43 +00003924 }
3925 delta += alen;
sewardj901ed122005-02-27 13:25:31 +00003926 DIP("%sb %s\n", nameGrp4(gregLO3ofRM(modrm)), dis_buf);
sewardj03b07cc2005-01-31 18:09:43 +00003927 }
3928 return delta;
3929}
sewardj354e5c62005-01-27 20:12:52 +00003930
3931
3932/* Group 5 extended opcodes. */
3933static
sewardjdd40fdf2006-12-24 02:20:24 +00003934ULong dis_Grp5 ( VexAbiInfo* vbi,
sewardjfd4203c2007-03-21 00:21:56 +00003935 Prefix pfx, Int sz, Long delta,
3936 DisResult* dres, Bool* decode_OK )
sewardj354e5c62005-01-27 20:12:52 +00003937{
3938 Int len;
3939 UChar modrm;
3940 HChar dis_buf[50];
3941 IRTemp addr = IRTemp_INVALID;
3942 IRType ty = szToITy(sz);
3943 IRTemp t1 = newTemp(ty);
3944 IRTemp t2 = IRTemp_INVALID;
sewardj03b07cc2005-01-31 18:09:43 +00003945 IRTemp t3 = IRTemp_INVALID;
sewardj7eaa7cf2005-01-31 18:55:22 +00003946 Bool showSz = True;
sewardj354e5c62005-01-27 20:12:52 +00003947
sewardjfd4203c2007-03-21 00:21:56 +00003948 *decode_OK = True;
3949
sewardj8c332e22005-01-28 01:36:56 +00003950 modrm = getUChar(delta);
sewardj354e5c62005-01-27 20:12:52 +00003951 if (epartIsReg(modrm)) {
sewardj5b470602005-02-27 13:10:48 +00003952 assign(t1, getIRegE(sz,pfx,modrm));
sewardj901ed122005-02-27 13:25:31 +00003953 switch (gregLO3ofRM(modrm)) {
sewardj32b2bbe2005-01-28 00:50:10 +00003954 case 0: /* INC */
3955 t2 = newTemp(ty);
3956 assign(t2, binop(mkSizedOp(ty,Iop_Add8),
3957 mkexpr(t1), mkU(ty,1)));
3958 setFlags_INC_DEC( True, t2, ty );
sewardj5b470602005-02-27 13:10:48 +00003959 putIRegE(sz,pfx,modrm, mkexpr(t2));
sewardj32b2bbe2005-01-28 00:50:10 +00003960 break;
3961 case 1: /* DEC */
3962 t2 = newTemp(ty);
3963 assign(t2, binop(mkSizedOp(ty,Iop_Sub8),
3964 mkexpr(t1), mkU(ty,1)));
3965 setFlags_INC_DEC( False, t2, ty );
sewardj5b470602005-02-27 13:10:48 +00003966 putIRegE(sz,pfx,modrm, mkexpr(t2));
sewardj32b2bbe2005-01-28 00:50:10 +00003967 break;
sewardj354e5c62005-01-27 20:12:52 +00003968 case 2: /* call Ev */
sewardj03b07cc2005-01-31 18:09:43 +00003969 /* Ignore any sz value and operate as if sz==8. */
sewardjd7a544b2007-11-19 00:39:23 +00003970 if (!(sz == 4 || sz == 8)) goto unhandled;
sewardj03b07cc2005-01-31 18:09:43 +00003971 sz = 8;
3972 t3 = newTemp(Ity_I64);
sewardj5b470602005-02-27 13:10:48 +00003973 assign(t3, getIRegE(sz,pfx,modrm));
sewardj03b07cc2005-01-31 18:09:43 +00003974 t2 = newTemp(Ity_I64);
3975 assign(t2, binop(Iop_Sub64, getIReg64(R_RSP), mkU64(8)));
3976 putIReg64(R_RSP, mkexpr(t2));
sewardj9e6491a2005-07-02 19:24:10 +00003977 storeLE( mkexpr(t2), mkU64(guest_RIP_bbstart+delta+1));
sewardj478646f2008-05-01 20:13:04 +00003978 make_redzone_AbiHint(vbi, t2, t3/*nia*/, "call-Ev(reg)");
sewardj03b07cc2005-01-31 18:09:43 +00003979 jmp_treg(Ijk_Call,t3);
sewardj9e6491a2005-07-02 19:24:10 +00003980 dres->whatNext = Dis_StopHere;
sewardj7eaa7cf2005-01-31 18:55:22 +00003981 showSz = False;
sewardj354e5c62005-01-27 20:12:52 +00003982 break;
sewardj354e5c62005-01-27 20:12:52 +00003983 case 4: /* jmp Ev */
sewardj03b07cc2005-01-31 18:09:43 +00003984 /* Ignore any sz value and operate as if sz==8. */
sewardjd7a544b2007-11-19 00:39:23 +00003985 if (!(sz == 4 || sz == 8)) goto unhandled;
sewardj03b07cc2005-01-31 18:09:43 +00003986 sz = 8;
3987 t3 = newTemp(Ity_I64);
sewardj5b470602005-02-27 13:10:48 +00003988 assign(t3, getIRegE(sz,pfx,modrm));
sewardj03b07cc2005-01-31 18:09:43 +00003989 jmp_treg(Ijk_Boring,t3);
sewardj9e6491a2005-07-02 19:24:10 +00003990 dres->whatNext = Dis_StopHere;
sewardj7eaa7cf2005-01-31 18:55:22 +00003991 showSz = False;
sewardj354e5c62005-01-27 20:12:52 +00003992 break;
sewardj354e5c62005-01-27 20:12:52 +00003993 default:
sewardjfd4203c2007-03-21 00:21:56 +00003994 *decode_OK = False;
3995 return delta;
sewardj354e5c62005-01-27 20:12:52 +00003996 }
3997 delta++;
sewardj901ed122005-02-27 13:25:31 +00003998 DIP("%s%c %s\n", nameGrp5(gregLO3ofRM(modrm)),
sewardj7eaa7cf2005-01-31 18:55:22 +00003999 showSz ? nameISize(sz) : ' ',
sewardj5b470602005-02-27 13:10:48 +00004000 nameIRegE(sz, pfx, modrm));
sewardj354e5c62005-01-27 20:12:52 +00004001 } else {
sewardj2e28ac42008-12-04 00:05:12 +00004002 addr = disAMode ( &len, vbi, pfx, delta, dis_buf, 0 );
sewardj901ed122005-02-27 13:25:31 +00004003 if (gregLO3ofRM(modrm) != 2 && gregLO3ofRM(modrm) != 4
4004 && gregLO3ofRM(modrm) != 6) {
sewardj03b07cc2005-01-31 18:09:43 +00004005 assign(t1, loadLE(ty,mkexpr(addr)));
sewardj909c06d2005-02-19 22:47:41 +00004006 }
sewardj901ed122005-02-27 13:25:31 +00004007 switch (gregLO3ofRM(modrm)) {
sewardj354e5c62005-01-27 20:12:52 +00004008 case 0: /* INC */
sewardj354e5c62005-01-27 20:12:52 +00004009 t2 = newTemp(ty);
4010 assign(t2, binop(mkSizedOp(ty,Iop_Add8),
4011 mkexpr(t1), mkU(ty,1)));
sewardje9d8a262009-07-01 08:06:34 +00004012 if (pfx & PFX_LOCK) {
4013 casLE( mkexpr(addr),
4014 mkexpr(t1), mkexpr(t2), guest_RIP_curr_instr );
4015 } else {
4016 storeLE(mkexpr(addr),mkexpr(t2));
4017 }
sewardj354e5c62005-01-27 20:12:52 +00004018 setFlags_INC_DEC( True, t2, ty );
sewardj354e5c62005-01-27 20:12:52 +00004019 break;
sewardj354e5c62005-01-27 20:12:52 +00004020 case 1: /* DEC */
4021 t2 = newTemp(ty);
4022 assign(t2, binop(mkSizedOp(ty,Iop_Sub8),
4023 mkexpr(t1), mkU(ty,1)));
sewardje9d8a262009-07-01 08:06:34 +00004024 if (pfx & PFX_LOCK) {
4025 casLE( mkexpr(addr),
4026 mkexpr(t1), mkexpr(t2), guest_RIP_curr_instr );
4027 } else {
4028 storeLE(mkexpr(addr),mkexpr(t2));
4029 }
sewardj354e5c62005-01-27 20:12:52 +00004030 setFlags_INC_DEC( False, t2, ty );
sewardj354e5c62005-01-27 20:12:52 +00004031 break;
4032 case 2: /* call Ev */
sewardj03b07cc2005-01-31 18:09:43 +00004033 /* Ignore any sz value and operate as if sz==8. */
sewardjd7a544b2007-11-19 00:39:23 +00004034 if (!(sz == 4 || sz == 8)) goto unhandled;
sewardj7eaa7cf2005-01-31 18:55:22 +00004035 sz = 8;
sewardj03b07cc2005-01-31 18:09:43 +00004036 t3 = newTemp(Ity_I64);
4037 assign(t3, loadLE(Ity_I64,mkexpr(addr)));
4038 t2 = newTemp(Ity_I64);
4039 assign(t2, binop(Iop_Sub64, getIReg64(R_RSP), mkU64(8)));
4040 putIReg64(R_RSP, mkexpr(t2));
sewardj9e6491a2005-07-02 19:24:10 +00004041 storeLE( mkexpr(t2), mkU64(guest_RIP_bbstart+delta+len));
sewardj478646f2008-05-01 20:13:04 +00004042 make_redzone_AbiHint(vbi, t2, t3/*nia*/, "call-Ev(mem)");
sewardj03b07cc2005-01-31 18:09:43 +00004043 jmp_treg(Ijk_Call,t3);
sewardj9e6491a2005-07-02 19:24:10 +00004044 dres->whatNext = Dis_StopHere;
sewardj7eaa7cf2005-01-31 18:55:22 +00004045 showSz = False;
sewardj354e5c62005-01-27 20:12:52 +00004046 break;
sewardj354e5c62005-01-27 20:12:52 +00004047 case 4: /* JMP Ev */
sewardj03b07cc2005-01-31 18:09:43 +00004048 /* Ignore any sz value and operate as if sz==8. */
sewardjd7a544b2007-11-19 00:39:23 +00004049 if (!(sz == 4 || sz == 8)) goto unhandled;
sewardj7eaa7cf2005-01-31 18:55:22 +00004050 sz = 8;
sewardj03b07cc2005-01-31 18:09:43 +00004051 t3 = newTemp(Ity_I64);
4052 assign(t3, loadLE(Ity_I64,mkexpr(addr)));
4053 jmp_treg(Ijk_Boring,t3);
sewardj9e6491a2005-07-02 19:24:10 +00004054 dres->whatNext = Dis_StopHere;
sewardj7eaa7cf2005-01-31 18:55:22 +00004055 showSz = False;
sewardj354e5c62005-01-27 20:12:52 +00004056 break;
sewardj354e5c62005-01-27 20:12:52 +00004057 case 6: /* PUSH Ev */
sewardja6b93d12005-02-17 09:28:28 +00004058 /* There is no encoding for 32-bit operand size; hence ... */
4059 if (sz == 4) sz = 8;
sewardjd7a544b2007-11-19 00:39:23 +00004060 if (!(sz == 8 || sz == 2)) goto unhandled;
sewardj909c06d2005-02-19 22:47:41 +00004061 if (sz == 8) {
4062 t3 = newTemp(Ity_I64);
4063 assign(t3, loadLE(Ity_I64,mkexpr(addr)));
4064 t2 = newTemp(Ity_I64);
4065 assign( t2, binop(Iop_Sub64,getIReg64(R_RSP),mkU64(sz)) );
4066 putIReg64(R_RSP, mkexpr(t2) );
4067 storeLE( mkexpr(t2), mkexpr(t3) );
4068 break;
4069 } else {
4070 goto unhandled; /* awaiting test case */
4071 }
sewardj354e5c62005-01-27 20:12:52 +00004072 default:
sewardja6b93d12005-02-17 09:28:28 +00004073 unhandled:
sewardjfd4203c2007-03-21 00:21:56 +00004074 *decode_OK = False;
4075 return delta;
sewardj354e5c62005-01-27 20:12:52 +00004076 }
4077 delta += len;
sewardj901ed122005-02-27 13:25:31 +00004078 DIP("%s%c %s\n", nameGrp5(gregLO3ofRM(modrm)),
sewardj7eaa7cf2005-01-31 18:55:22 +00004079 showSz ? nameISize(sz) : ' ',
4080 dis_buf);
sewardj354e5c62005-01-27 20:12:52 +00004081 }
4082 return delta;
4083}
4084
4085
sewardjd0a12df2005-02-10 02:07:43 +00004086/*------------------------------------------------------------*/
4087/*--- Disassembling string ops (including REP prefixes) ---*/
4088/*------------------------------------------------------------*/
4089
4090/* Code shared by all the string ops */
4091static
4092void dis_string_op_increment ( Int sz, IRTemp t_inc )
4093{
4094 UChar logSz;
4095 if (sz == 8 || sz == 4 || sz == 2) {
4096 logSz = 1;
4097 if (sz == 4) logSz = 2;
4098 if (sz == 8) logSz = 3;
4099 assign( t_inc,
4100 binop(Iop_Shl64, IRExpr_Get( OFFB_DFLAG, Ity_I64 ),
4101 mkU8(logSz) ) );
4102 } else {
4103 assign( t_inc,
4104 IRExpr_Get( OFFB_DFLAG, Ity_I64 ) );
4105 }
4106}
4107
sewardj909c06d2005-02-19 22:47:41 +00004108static
4109void dis_string_op( void (*dis_OP)( Int, IRTemp ),
4110 Int sz, HChar* name, Prefix pfx )
4111{
4112 IRTemp t_inc = newTemp(Ity_I64);
4113 /* Really we ought to inspect the override prefixes, but we don't.
4114 The following assertion catches any resulting sillyness. */
4115 vassert(pfx == clearSegBits(pfx));
4116 dis_string_op_increment(sz, t_inc);
4117 dis_OP( sz, t_inc );
4118 DIP("%s%c\n", name, nameISize(sz));
4119}
4120
4121static
4122void dis_MOVS ( Int sz, IRTemp t_inc )
4123{
4124 IRType ty = szToITy(sz);
4125 IRTemp td = newTemp(Ity_I64); /* RDI */
4126 IRTemp ts = newTemp(Ity_I64); /* RSI */
4127
4128 assign( td, getIReg64(R_RDI) );
4129 assign( ts, getIReg64(R_RSI) );
4130
4131 storeLE( mkexpr(td), loadLE(ty,mkexpr(ts)) );
4132
4133 putIReg64( R_RDI, binop(Iop_Add64, mkexpr(td), mkexpr(t_inc)) );
4134 putIReg64( R_RSI, binop(Iop_Add64, mkexpr(ts), mkexpr(t_inc)) );
4135}
4136
sewardj0f99be62009-07-22 09:29:13 +00004137static
4138void dis_LODS ( Int sz, IRTemp t_inc )
4139{
4140 IRType ty = szToITy(sz);
4141 IRTemp ts = newTemp(Ity_I64); /* RSI */
4142
4143 assign( ts, getIReg64(R_RSI) );
4144
4145 putIRegRAX ( sz, loadLE(ty, mkexpr(ts)) );
4146
4147 putIReg64( R_RSI, binop(Iop_Add64, mkexpr(ts), mkexpr(t_inc)) );
4148}
sewardja6b93d12005-02-17 09:28:28 +00004149
4150static
4151void dis_STOS ( Int sz, IRTemp t_inc )
4152{
4153 IRType ty = szToITy(sz);
4154 IRTemp ta = newTemp(ty); /* rAX */
4155 IRTemp td = newTemp(Ity_I64); /* RDI */
4156
sewardj5b470602005-02-27 13:10:48 +00004157 assign( ta, getIRegRAX(sz) );
sewardja6b93d12005-02-17 09:28:28 +00004158
4159 assign( td, getIReg64(R_RDI) );
4160
4161 storeLE( mkexpr(td), mkexpr(ta) );
4162
4163 putIReg64( R_RDI, binop(Iop_Add64, mkexpr(td), mkexpr(t_inc)) );
4164}
sewardjd0a12df2005-02-10 02:07:43 +00004165
4166static
4167void dis_CMPS ( Int sz, IRTemp t_inc )
4168{
4169 IRType ty = szToITy(sz);
4170 IRTemp tdv = newTemp(ty); /* (RDI) */
4171 IRTemp tsv = newTemp(ty); /* (RSI) */
4172 IRTemp td = newTemp(Ity_I64); /* RDI */
4173 IRTemp ts = newTemp(Ity_I64); /* RSI */
4174
4175 assign( td, getIReg64(R_RDI) );
4176
4177 assign( ts, getIReg64(R_RSI) );
4178
4179 assign( tdv, loadLE(ty,mkexpr(td)) );
4180
4181 assign( tsv, loadLE(ty,mkexpr(ts)) );
4182
4183 setFlags_DEP1_DEP2 ( Iop_Sub8, tsv, tdv, ty );
4184
4185 putIReg64(R_RDI, binop(Iop_Add64, mkexpr(td), mkexpr(t_inc)) );
4186
4187 putIReg64(R_RSI, binop(Iop_Add64, mkexpr(ts), mkexpr(t_inc)) );
4188}
4189
sewardj85520e42005-02-19 15:22:38 +00004190static
4191void dis_SCAS ( Int sz, IRTemp t_inc )
4192{
4193 IRType ty = szToITy(sz);
4194 IRTemp ta = newTemp(ty); /* rAX */
4195 IRTemp td = newTemp(Ity_I64); /* RDI */
4196 IRTemp tdv = newTemp(ty); /* (RDI) */
4197
sewardj5b470602005-02-27 13:10:48 +00004198 assign( ta, getIRegRAX(sz) );
sewardj85520e42005-02-19 15:22:38 +00004199
4200 assign( td, getIReg64(R_RDI) );
4201
4202 assign( tdv, loadLE(ty,mkexpr(td)) );
4203
4204 setFlags_DEP1_DEP2 ( Iop_Sub8, ta, tdv, ty );
4205
4206 putIReg64(R_RDI, binop(Iop_Add64, mkexpr(td), mkexpr(t_inc)) );
4207}
sewardjd0a12df2005-02-10 02:07:43 +00004208
4209
4210/* Wrap the appropriate string op inside a REP/REPE/REPNE. We assume
4211 the insn is the last one in the basic block, and so emit a jump to
4212 the next insn, rather than just falling through. */
4213static
4214void dis_REP_op ( AMD64Condcode cond,
4215 void (*dis_OP)(Int, IRTemp),
sewardj909c06d2005-02-19 22:47:41 +00004216 Int sz, Addr64 rip, Addr64 rip_next, HChar* name,
4217 Prefix pfx )
sewardjd0a12df2005-02-10 02:07:43 +00004218{
4219 IRTemp t_inc = newTemp(Ity_I64);
4220 IRTemp tc = newTemp(Ity_I64); /* RCX */
4221
sewardj909c06d2005-02-19 22:47:41 +00004222 /* Really we ought to inspect the override prefixes, but we don't.
4223 The following assertion catches any resulting sillyness. */
4224 vassert(pfx == clearSegBits(pfx));
4225
sewardjd0a12df2005-02-10 02:07:43 +00004226 assign( tc, getIReg64(R_RCX) );
4227
4228 stmt( IRStmt_Exit( binop(Iop_CmpEQ64,mkexpr(tc),mkU64(0)),
4229 Ijk_Boring,
4230 IRConst_U64(rip_next) ) );
4231
4232 putIReg64(R_RCX, binop(Iop_Sub64, mkexpr(tc), mkU64(1)) );
4233
4234 dis_string_op_increment(sz, t_inc);
4235 dis_OP (sz, t_inc);
4236
4237 if (cond == AMD64CondAlways) {
4238 jmp_lit(Ijk_Boring,rip);
4239 } else {
4240 stmt( IRStmt_Exit( mk_amd64g_calculate_condition(cond),
4241 Ijk_Boring,
4242 IRConst_U64(rip) ) );
4243 jmp_lit(Ijk_Boring,rip_next);
4244 }
4245 DIP("%s%c\n", name, nameISize(sz));
4246}
sewardj32b2bbe2005-01-28 00:50:10 +00004247
4248
4249/*------------------------------------------------------------*/
4250/*--- Arithmetic, etc. ---*/
4251/*------------------------------------------------------------*/
4252
4253/* IMUL E, G. Supplied eip points to the modR/M byte. */
4254static
sewardj2e28ac42008-12-04 00:05:12 +00004255ULong dis_mul_E_G ( VexAbiInfo* vbi,
4256 Prefix pfx,
sewardj32b2bbe2005-01-28 00:50:10 +00004257 Int size,
sewardj270def42005-07-03 01:03:01 +00004258 Long delta0 )
sewardj32b2bbe2005-01-28 00:50:10 +00004259{
4260 Int alen;
4261 HChar dis_buf[50];
sewardj8c332e22005-01-28 01:36:56 +00004262 UChar rm = getUChar(delta0);
sewardj32b2bbe2005-01-28 00:50:10 +00004263 IRType ty = szToITy(size);
4264 IRTemp te = newTemp(ty);
4265 IRTemp tg = newTemp(ty);
4266 IRTemp resLo = newTemp(ty);
4267
sewardj5b470602005-02-27 13:10:48 +00004268 assign( tg, getIRegG(size, pfx, rm) );
sewardj32b2bbe2005-01-28 00:50:10 +00004269 if (epartIsReg(rm)) {
sewardj5b470602005-02-27 13:10:48 +00004270 assign( te, getIRegE(size, pfx, rm) );
sewardj32b2bbe2005-01-28 00:50:10 +00004271 } else {
sewardj2e28ac42008-12-04 00:05:12 +00004272 IRTemp addr = disAMode( &alen, vbi, pfx, delta0, dis_buf, 0 );
sewardj32b2bbe2005-01-28 00:50:10 +00004273 assign( te, loadLE(ty,mkexpr(addr)) );
4274 }
4275
4276 setFlags_MUL ( ty, te, tg, AMD64G_CC_OP_SMULB );
4277
4278 assign( resLo, binop( mkSizedOp(ty, Iop_Mul8), mkexpr(te), mkexpr(tg) ) );
4279
sewardj5b470602005-02-27 13:10:48 +00004280 putIRegG(size, pfx, rm, mkexpr(resLo) );
sewardj32b2bbe2005-01-28 00:50:10 +00004281
4282 if (epartIsReg(rm)) {
4283 DIP("imul%c %s, %s\n", nameISize(size),
sewardj901ed122005-02-27 13:25:31 +00004284 nameIRegE(size,pfx,rm),
4285 nameIRegG(size,pfx,rm));
sewardj32b2bbe2005-01-28 00:50:10 +00004286 return 1+delta0;
4287 } else {
4288 DIP("imul%c %s, %s\n", nameISize(size),
4289 dis_buf,
sewardj901ed122005-02-27 13:25:31 +00004290 nameIRegG(size,pfx,rm));
sewardj32b2bbe2005-01-28 00:50:10 +00004291 return alen+delta0;
4292 }
4293}
4294
4295
4296/* IMUL I * E -> G. Supplied rip points to the modR/M byte. */
4297static
sewardj2e28ac42008-12-04 00:05:12 +00004298ULong dis_imul_I_E_G ( VexAbiInfo* vbi,
4299 Prefix pfx,
sewardj32b2bbe2005-01-28 00:50:10 +00004300 Int size,
sewardj270def42005-07-03 01:03:01 +00004301 Long delta,
sewardj32b2bbe2005-01-28 00:50:10 +00004302 Int litsize )
4303{
4304 Long d64;
4305 Int alen;
4306 HChar dis_buf[50];
sewardj8c332e22005-01-28 01:36:56 +00004307 UChar rm = getUChar(delta);
sewardj32b2bbe2005-01-28 00:50:10 +00004308 IRType ty = szToITy(size);
4309 IRTemp te = newTemp(ty);
4310 IRTemp tl = newTemp(ty);
4311 IRTemp resLo = newTemp(ty);
4312
sewardj85520e42005-02-19 15:22:38 +00004313 vassert(/*size == 1 ||*/ size == 2 || size == 4 || size == 8);
sewardj32b2bbe2005-01-28 00:50:10 +00004314
4315 if (epartIsReg(rm)) {
sewardj5b470602005-02-27 13:10:48 +00004316 assign(te, getIRegE(size, pfx, rm));
sewardj32b2bbe2005-01-28 00:50:10 +00004317 delta++;
4318 } else {
sewardj2e28ac42008-12-04 00:05:12 +00004319 IRTemp addr = disAMode( &alen, vbi, pfx, delta, dis_buf,
sewardj7de0d3c2005-02-13 02:26:41 +00004320 imin(4,litsize) );
sewardj32b2bbe2005-01-28 00:50:10 +00004321 assign(te, loadLE(ty, mkexpr(addr)));
4322 delta += alen;
4323 }
4324 d64 = getSDisp(imin(4,litsize),delta);
4325 delta += imin(4,litsize);
4326
sewardj1389d4d2005-01-28 13:46:29 +00004327 d64 &= mkSizeMask(size);
sewardj32b2bbe2005-01-28 00:50:10 +00004328 assign(tl, mkU(ty,d64));
4329
4330 assign( resLo, binop( mkSizedOp(ty, Iop_Mul8), mkexpr(te), mkexpr(tl) ));
4331
4332 setFlags_MUL ( ty, te, tl, AMD64G_CC_OP_SMULB );
4333
sewardj5b470602005-02-27 13:10:48 +00004334 putIRegG(size, pfx, rm, mkexpr(resLo));
sewardj32b2bbe2005-01-28 00:50:10 +00004335
4336 DIP("imul%c $%lld, %s, %s\n",
4337 nameISize(size), d64,
sewardj5b470602005-02-27 13:10:48 +00004338 ( epartIsReg(rm) ? nameIRegE(size,pfx,rm) : dis_buf ),
4339 nameIRegG(size,pfx,rm) );
sewardj32b2bbe2005-01-28 00:50:10 +00004340 return delta;
4341}
4342
4343
sewardjfd181282010-06-14 21:29:35 +00004344/* Generate an IR sequence to do a popcount operation on the supplied
4345 IRTemp, and return a new IRTemp holding the result. 'ty' may be
4346 Ity_I16, Ity_I32 or Ity_I64 only. */
4347static IRTemp gen_POPCOUNT ( IRType ty, IRTemp src )
4348{
4349 Int i;
4350 if (ty == Ity_I16) {
4351 IRTemp old = IRTemp_INVALID;
4352 IRTemp nyu = IRTemp_INVALID;
4353 IRTemp mask[4], shift[4];
4354 for (i = 0; i < 4; i++) {
4355 mask[i] = newTemp(ty);
4356 shift[i] = 1 << i;
4357 }
4358 assign(mask[0], mkU16(0x5555));
4359 assign(mask[1], mkU16(0x3333));
4360 assign(mask[2], mkU16(0x0F0F));
4361 assign(mask[3], mkU16(0x00FF));
4362 old = src;
4363 for (i = 0; i < 4; i++) {
4364 nyu = newTemp(ty);
4365 assign(nyu,
4366 binop(Iop_Add16,
4367 binop(Iop_And16,
4368 mkexpr(old),
4369 mkexpr(mask[i])),
4370 binop(Iop_And16,
4371 binop(Iop_Shr16, mkexpr(old), mkU8(shift[i])),
4372 mkexpr(mask[i]))));
4373 old = nyu;
4374 }
4375 return nyu;
4376 }
4377 if (ty == Ity_I32) {
4378 IRTemp old = IRTemp_INVALID;
4379 IRTemp nyu = IRTemp_INVALID;
4380 IRTemp mask[5], shift[5];
4381 for (i = 0; i < 5; i++) {
4382 mask[i] = newTemp(ty);
4383 shift[i] = 1 << i;
4384 }
4385 assign(mask[0], mkU32(0x55555555));
4386 assign(mask[1], mkU32(0x33333333));
4387 assign(mask[2], mkU32(0x0F0F0F0F));
4388 assign(mask[3], mkU32(0x00FF00FF));
4389 assign(mask[4], mkU32(0x0000FFFF));
4390 old = src;
4391 for (i = 0; i < 5; i++) {
4392 nyu = newTemp(ty);
4393 assign(nyu,
4394 binop(Iop_Add32,
4395 binop(Iop_And32,
4396 mkexpr(old),
4397 mkexpr(mask[i])),
4398 binop(Iop_And32,
4399 binop(Iop_Shr32, mkexpr(old), mkU8(shift[i])),
4400 mkexpr(mask[i]))));
4401 old = nyu;
4402 }
4403 return nyu;
4404 }
4405 if (ty == Ity_I64) {
4406 IRTemp old = IRTemp_INVALID;
4407 IRTemp nyu = IRTemp_INVALID;
4408 IRTemp mask[6], shift[6];
4409 for (i = 0; i < 6; i++) {
4410 mask[i] = newTemp(ty);
4411 shift[i] = 1 << i;
4412 }
4413 assign(mask[0], mkU64(0x5555555555555555ULL));
4414 assign(mask[1], mkU64(0x3333333333333333ULL));
4415 assign(mask[2], mkU64(0x0F0F0F0F0F0F0F0FULL));
4416 assign(mask[3], mkU64(0x00FF00FF00FF00FFULL));
4417 assign(mask[4], mkU64(0x0000FFFF0000FFFFULL));
4418 assign(mask[5], mkU64(0x00000000FFFFFFFFULL));
4419 old = src;
4420 for (i = 0; i < 6; i++) {
4421 nyu = newTemp(ty);
4422 assign(nyu,
4423 binop(Iop_Add64,
4424 binop(Iop_And64,
4425 mkexpr(old),
4426 mkexpr(mask[i])),
4427 binop(Iop_And64,
4428 binop(Iop_Shr64, mkexpr(old), mkU8(shift[i])),
4429 mkexpr(mask[i]))));
4430 old = nyu;
4431 }
4432 return nyu;
4433 }
4434 /*NOTREACHED*/
4435 vassert(0);
4436}
4437
4438
sewardjbcbb9de2005-03-27 02:22:32 +00004439/*------------------------------------------------------------*/
4440/*--- ---*/
4441/*--- x87 FLOATING POINT INSTRUCTIONS ---*/
4442/*--- ---*/
4443/*------------------------------------------------------------*/
4444
4445/* --- Helper functions for dealing with the register stack. --- */
4446
4447/* --- Set the emulation-warning pseudo-register. --- */
4448
4449static void put_emwarn ( IRExpr* e /* :: Ity_I32 */ )
4450{
sewardjdd40fdf2006-12-24 02:20:24 +00004451 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I32);
sewardjbcbb9de2005-03-27 02:22:32 +00004452 stmt( IRStmt_Put( OFFB_EMWARN, e ) );
4453}
sewardj8d965312005-02-25 02:48:47 +00004454
4455/* --- Produce an IRExpr* denoting a 64-bit QNaN. --- */
4456
4457static IRExpr* mkQNaN64 ( void )
4458{
4459 /* QNaN is 0 2047 1 0(51times)
4460 == 0b 11111111111b 1 0(51times)
4461 == 0x7FF8 0000 0000 0000
4462 */
4463 return IRExpr_Const(IRConst_F64i(0x7FF8000000000000ULL));
4464}
4465
4466/* --------- Get/put the top-of-stack pointer :: Ity_I32 --------- */
4467
4468static IRExpr* get_ftop ( void )
4469{
4470 return IRExpr_Get( OFFB_FTOP, Ity_I32 );
4471}
4472
4473static void put_ftop ( IRExpr* e )
4474{
sewardjdd40fdf2006-12-24 02:20:24 +00004475 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I32);
sewardj8d965312005-02-25 02:48:47 +00004476 stmt( IRStmt_Put( OFFB_FTOP, e ) );
4477}
4478
sewardj25a85812005-05-08 23:03:48 +00004479/* --------- Get/put the C3210 bits. --------- */
4480
4481static IRExpr* /* :: Ity_I64 */ get_C3210 ( void )
4482{
4483 return IRExpr_Get( OFFB_FC3210, Ity_I64 );
4484}
4485
4486static void put_C3210 ( IRExpr* e /* :: Ity_I64 */ )
4487{
sewardjdd40fdf2006-12-24 02:20:24 +00004488 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I64);
sewardj25a85812005-05-08 23:03:48 +00004489 stmt( IRStmt_Put( OFFB_FC3210, e ) );
4490}
sewardjc49ce232005-02-25 13:03:03 +00004491
4492/* --------- Get/put the FPU rounding mode. --------- */
4493static IRExpr* /* :: Ity_I32 */ get_fpround ( void )
4494{
4495 return unop(Iop_64to32, IRExpr_Get( OFFB_FPROUND, Ity_I64 ));
4496}
4497
sewardj5e205372005-05-09 02:57:08 +00004498static void put_fpround ( IRExpr* /* :: Ity_I32 */ e )
4499{
sewardjdd40fdf2006-12-24 02:20:24 +00004500 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I32);
sewardj5e205372005-05-09 02:57:08 +00004501 stmt( IRStmt_Put( OFFB_FPROUND, unop(Iop_32Uto64,e) ) );
4502}
sewardjc49ce232005-02-25 13:03:03 +00004503
4504
4505/* --------- Synthesise a 2-bit FPU rounding mode. --------- */
4506/* Produces a value in 0 .. 3, which is encoded as per the type
4507 IRRoundingMode. Since the guest_FPROUND value is also encoded as
4508 per IRRoundingMode, we merely need to get it and mask it for
4509 safety.
4510*/
4511static IRExpr* /* :: Ity_I32 */ get_roundingmode ( void )
4512{
4513 return binop( Iop_And32, get_fpround(), mkU32(3) );
4514}
sewardj8d965312005-02-25 02:48:47 +00004515
sewardj4796d662006-02-05 16:06:26 +00004516static IRExpr* /* :: Ity_I32 */ get_FAKE_roundingmode ( void )
4517{
4518 return mkU32(Irrm_NEAREST);
4519}
4520
sewardj8d965312005-02-25 02:48:47 +00004521
4522/* --------- Get/set FP register tag bytes. --------- */
4523
4524/* Given i, and some expression e, generate 'ST_TAG(i) = e'. */
4525
4526static void put_ST_TAG ( Int i, IRExpr* value )
4527{
sewardjdd40fdf2006-12-24 02:20:24 +00004528 IRRegArray* descr;
4529 vassert(typeOfIRExpr(irsb->tyenv, value) == Ity_I8);
4530 descr = mkIRRegArray( OFFB_FPTAGS, Ity_I8, 8 );
sewardj8d965312005-02-25 02:48:47 +00004531 stmt( IRStmt_PutI( descr, get_ftop(), i, value ) );
4532}
4533
4534/* Given i, generate an expression yielding 'ST_TAG(i)'. This will be
4535 zero to indicate "Empty" and nonzero to indicate "NonEmpty". */
4536
4537static IRExpr* get_ST_TAG ( Int i )
4538{
sewardjdd40fdf2006-12-24 02:20:24 +00004539 IRRegArray* descr = mkIRRegArray( OFFB_FPTAGS, Ity_I8, 8 );
sewardj8d965312005-02-25 02:48:47 +00004540 return IRExpr_GetI( descr, get_ftop(), i );
4541}
4542
4543
4544/* --------- Get/set FP registers. --------- */
4545
4546/* Given i, and some expression e, emit 'ST(i) = e' and set the
4547 register's tag to indicate the register is full. The previous
4548 state of the register is not checked. */
4549
4550static void put_ST_UNCHECKED ( Int i, IRExpr* value )
4551{
sewardjdd40fdf2006-12-24 02:20:24 +00004552 IRRegArray* descr;
4553 vassert(typeOfIRExpr(irsb->tyenv, value) == Ity_F64);
4554 descr = mkIRRegArray( OFFB_FPREGS, Ity_F64, 8 );
sewardj8d965312005-02-25 02:48:47 +00004555 stmt( IRStmt_PutI( descr, get_ftop(), i, value ) );
4556 /* Mark the register as in-use. */
4557 put_ST_TAG(i, mkU8(1));
4558}
4559
4560/* Given i, and some expression e, emit
4561 ST(i) = is_full(i) ? NaN : e
4562 and set the tag accordingly.
4563*/
4564
4565static void put_ST ( Int i, IRExpr* value )
4566{
4567 put_ST_UNCHECKED( i,
4568 IRExpr_Mux0X( get_ST_TAG(i),
4569 /* 0 means empty */
4570 value,
4571 /* non-0 means full */
4572 mkQNaN64()
4573 )
4574 );
4575}
4576
4577
4578/* Given i, generate an expression yielding 'ST(i)'. */
4579
4580static IRExpr* get_ST_UNCHECKED ( Int i )
4581{
sewardjdd40fdf2006-12-24 02:20:24 +00004582 IRRegArray* descr = mkIRRegArray( OFFB_FPREGS, Ity_F64, 8 );
sewardj8d965312005-02-25 02:48:47 +00004583 return IRExpr_GetI( descr, get_ftop(), i );
4584}
4585
4586
4587/* Given i, generate an expression yielding
4588 is_full(i) ? ST(i) : NaN
4589*/
4590
4591static IRExpr* get_ST ( Int i )
4592{
4593 return
4594 IRExpr_Mux0X( get_ST_TAG(i),
4595 /* 0 means empty */
4596 mkQNaN64(),
4597 /* non-0 means full */
4598 get_ST_UNCHECKED(i));
4599}
4600
4601
4602/* Adjust FTOP downwards by one register. */
4603
4604static void fp_push ( void )
4605{
4606 put_ftop( binop(Iop_Sub32, get_ftop(), mkU32(1)) );
4607}
4608
4609/* Adjust FTOP upwards by one register, and mark the vacated register
4610 as empty. */
4611
4612static void fp_pop ( void )
4613{
4614 put_ST_TAG(0, mkU8(0));
4615 put_ftop( binop(Iop_Add32, get_ftop(), mkU32(1)) );
4616}
4617
sewardj25a85812005-05-08 23:03:48 +00004618/* Clear the C2 bit of the FPU status register, for
4619 sin/cos/tan/sincos. */
4620
4621static void clear_C2 ( void )
4622{
4623 put_C3210( binop(Iop_And64, get_C3210(), mkU64(~AMD64G_FC_MASK_C2)) );
4624}
sewardj48a89d82005-05-06 11:50:13 +00004625
sewardj7c2d2822006-03-07 00:22:02 +00004626/* Invent a plausible-looking FPU status word value:
4627 ((ftop & 7) << 11) | (c3210 & 0x4700)
4628 */
4629static IRExpr* get_FPU_sw ( void )
4630{
4631 return
4632 unop(Iop_32to16,
4633 binop(Iop_Or32,
4634 binop(Iop_Shl32,
4635 binop(Iop_And32, get_ftop(), mkU32(7)),
4636 mkU8(11)),
4637 binop(Iop_And32, unop(Iop_64to32, get_C3210()),
4638 mkU32(0x4700))
4639 ));
4640}
4641
sewardj48a89d82005-05-06 11:50:13 +00004642
4643/* ------------------------------------------------------- */
4644/* Given all that stack-mangling junk, we can now go ahead
4645 and describe FP instructions.
4646*/
4647
4648/* ST(0) = ST(0) `op` mem64/32(addr)
4649 Need to check ST(0)'s tag on read, but not on write.
4650*/
4651static
sewardjca673ab2005-05-11 10:03:08 +00004652void fp_do_op_mem_ST_0 ( IRTemp addr, HChar* op_txt, HChar* dis_buf,
sewardj48a89d82005-05-06 11:50:13 +00004653 IROp op, Bool dbl )
4654{
4655 DIP("f%s%c %s\n", op_txt, dbl?'l':'s', dis_buf);
4656 if (dbl) {
4657 put_ST_UNCHECKED(0,
sewardj4796d662006-02-05 16:06:26 +00004658 triop( op,
4659 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardj48a89d82005-05-06 11:50:13 +00004660 get_ST(0),
4661 loadLE(Ity_F64,mkexpr(addr))
4662 ));
4663 } else {
4664 put_ST_UNCHECKED(0,
sewardj4796d662006-02-05 16:06:26 +00004665 triop( op,
4666 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardj48a89d82005-05-06 11:50:13 +00004667 get_ST(0),
4668 unop(Iop_F32toF64, loadLE(Ity_F32,mkexpr(addr)))
4669 ));
4670 }
4671}
sewardj7bc00082005-03-27 05:08:32 +00004672
4673
4674/* ST(0) = mem64/32(addr) `op` ST(0)
4675 Need to check ST(0)'s tag on read, but not on write.
4676*/
4677static
4678void fp_do_oprev_mem_ST_0 ( IRTemp addr, HChar* op_txt, HChar* dis_buf,
4679 IROp op, Bool dbl )
4680{
4681 DIP("f%s%c %s\n", op_txt, dbl?'l':'s', dis_buf);
4682 if (dbl) {
4683 put_ST_UNCHECKED(0,
sewardj4796d662006-02-05 16:06:26 +00004684 triop( op,
4685 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardj7bc00082005-03-27 05:08:32 +00004686 loadLE(Ity_F64,mkexpr(addr)),
4687 get_ST(0)
4688 ));
4689 } else {
4690 put_ST_UNCHECKED(0,
sewardj4796d662006-02-05 16:06:26 +00004691 triop( op,
4692 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardj7bc00082005-03-27 05:08:32 +00004693 unop(Iop_F32toF64, loadLE(Ity_F32,mkexpr(addr))),
4694 get_ST(0)
4695 ));
4696 }
4697}
sewardj37d52572005-02-25 14:22:12 +00004698
4699
4700/* ST(dst) = ST(dst) `op` ST(src).
4701 Check dst and src tags when reading but not on write.
4702*/
4703static
4704void fp_do_op_ST_ST ( HChar* op_txt, IROp op, UInt st_src, UInt st_dst,
4705 Bool pop_after )
4706{
sewardj1027dc22005-02-26 01:55:02 +00004707 DIP("f%s%s st(%u), st(%u)\n", op_txt, pop_after?"p":"", st_src, st_dst );
sewardj37d52572005-02-25 14:22:12 +00004708 put_ST_UNCHECKED(
4709 st_dst,
sewardj4796d662006-02-05 16:06:26 +00004710 triop( op,
4711 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4712 get_ST(st_dst),
4713 get_ST(st_src) )
sewardj37d52572005-02-25 14:22:12 +00004714 );
4715 if (pop_after)
4716 fp_pop();
4717}
4718
sewardj137015d2005-03-27 04:01:15 +00004719/* ST(dst) = ST(src) `op` ST(dst).
4720 Check dst and src tags when reading but not on write.
4721*/
4722static
4723void fp_do_oprev_ST_ST ( HChar* op_txt, IROp op, UInt st_src, UInt st_dst,
4724 Bool pop_after )
4725{
4726 DIP("f%s%s st(%u), st(%u)\n", op_txt, pop_after?"p":"", st_src, st_dst );
4727 put_ST_UNCHECKED(
4728 st_dst,
sewardj4796d662006-02-05 16:06:26 +00004729 triop( op,
4730 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4731 get_ST(st_src),
4732 get_ST(st_dst) )
sewardj137015d2005-03-27 04:01:15 +00004733 );
4734 if (pop_after)
4735 fp_pop();
4736}
sewardjc49ce232005-02-25 13:03:03 +00004737
4738/* %rflags(Z,P,C) = UCOMI( st(0), st(i) ) */
4739static void fp_do_ucomi_ST0_STi ( UInt i, Bool pop_after )
4740{
sewardj1027dc22005-02-26 01:55:02 +00004741 DIP("fucomi%s %%st(0),%%st(%u)\n", pop_after ? "p" : "", i);
sewardjc49ce232005-02-25 13:03:03 +00004742 /* This is a bit of a hack (and isn't really right). It sets
4743 Z,P,C,O correctly, but forces A and S to zero, whereas the Intel
4744 documentation implies A and S are unchanged.
4745 */
4746 /* It's also fishy in that it is used both for COMIP and
4747 UCOMIP, and they aren't the same (although similar). */
4748 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(AMD64G_CC_OP_COPY) ));
4749 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
4750 stmt( IRStmt_Put(
4751 OFFB_CC_DEP1,
4752 binop( Iop_And64,
4753 unop( Iop_32Uto64,
4754 binop(Iop_CmpF64, get_ST(0), get_ST(i))),
4755 mkU64(0x45)
4756 )));
4757 if (pop_after)
4758 fp_pop();
4759}
sewardj8d965312005-02-25 02:48:47 +00004760
4761
sewardjb707d102007-07-11 22:49:26 +00004762/* returns
4763 32to16( if e32 <s -32768 || e32 >s 32767 then -32768 else e32 )
4764*/
4765static IRExpr* x87ishly_qnarrow_32_to_16 ( IRExpr* e32 )
4766{
4767 IRTemp t32 = newTemp(Ity_I32);
4768 assign( t32, e32 );
4769 return
4770 IRExpr_Mux0X(
4771 unop(Iop_1Uto8,
4772 binop(Iop_CmpLT64U,
4773 unop(Iop_32Uto64,
4774 binop(Iop_Add32, mkexpr(t32), mkU32(32768))),
4775 mkU64(65536))),
4776 mkU16( 0x8000 ),
4777 unop(Iop_32to16, mkexpr(t32)));
4778}
4779
4780
sewardj8d965312005-02-25 02:48:47 +00004781static
sewardjb4fd2e72005-03-23 13:34:11 +00004782ULong dis_FPU ( /*OUT*/Bool* decode_ok,
sewardj2e28ac42008-12-04 00:05:12 +00004783 VexAbiInfo* vbi, Prefix pfx, Long delta )
sewardj8d965312005-02-25 02:48:47 +00004784{
4785 Int len;
4786 UInt r_src, r_dst;
4787 HChar dis_buf[50];
4788 IRTemp t1, t2;
4789
4790 /* On entry, delta points at the second byte of the insn (the modrm
4791 byte).*/
4792 UChar first_opcode = getUChar(delta-1);
4793 UChar modrm = getUChar(delta+0);
4794
sewardj37d52572005-02-25 14:22:12 +00004795 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xD8 opcodes +-+-+-+-+-+-+-+ */
4796
4797 if (first_opcode == 0xD8) {
4798 if (modrm < 0xC0) {
4799
4800 /* bits 5,4,3 are an opcode extension, and the modRM also
4801 specifies an address. */
sewardj2e28ac42008-12-04 00:05:12 +00004802 IRTemp addr = disAMode( &len, vbi, pfx, delta, dis_buf, 0 );
sewardj7bc00082005-03-27 05:08:32 +00004803 delta += len;
sewardj37d52572005-02-25 14:22:12 +00004804
sewardj901ed122005-02-27 13:25:31 +00004805 switch (gregLO3ofRM(modrm)) {
sewardj37d52572005-02-25 14:22:12 +00004806
sewardj48a89d82005-05-06 11:50:13 +00004807 case 0: /* FADD single-real */
4808 fp_do_op_mem_ST_0 ( addr, "add", dis_buf, Iop_AddF64, False );
4809 break;
4810
sewardje6939f02005-05-07 01:01:24 +00004811 case 1: /* FMUL single-real */
4812 fp_do_op_mem_ST_0 ( addr, "mul", dis_buf, Iop_MulF64, False );
4813 break;
4814
sewardjd20c8852005-01-20 20:04:07 +00004815//.. case 2: /* FCOM single-real */
4816//.. DIP("fcoms %s\n", dis_buf);
4817//.. /* This forces C1 to zero, which isn't right. */
4818//.. put_C3210(
4819//.. binop( Iop_And32,
4820//.. binop(Iop_Shl32,
4821//.. binop(Iop_CmpF64,
4822//.. get_ST(0),
4823//.. unop(Iop_F32toF64,
4824//.. loadLE(Ity_F32,mkexpr(addr)))),
4825//.. mkU8(8)),
4826//.. mkU32(0x4500)
4827//.. ));
4828//.. break;
4829//..
4830//.. case 3: /* FCOMP single-real */
4831//.. DIP("fcomps %s\n", dis_buf);
4832//.. /* This forces C1 to zero, which isn't right. */
4833//.. put_C3210(
4834//.. binop( Iop_And32,
4835//.. binop(Iop_Shl32,
4836//.. binop(Iop_CmpF64,
4837//.. get_ST(0),
4838//.. unop(Iop_F32toF64,
4839//.. loadLE(Ity_F32,mkexpr(addr)))),
4840//.. mkU8(8)),
4841//.. mkU32(0x4500)
4842//.. ));
4843//.. fp_pop();
4844//.. break;
sewardje6939f02005-05-07 01:01:24 +00004845
4846 case 4: /* FSUB single-real */
4847 fp_do_op_mem_ST_0 ( addr, "sub", dis_buf, Iop_SubF64, False );
4848 break;
sewardj7bc00082005-03-27 05:08:32 +00004849
4850 case 5: /* FSUBR single-real */
4851 fp_do_oprev_mem_ST_0 ( addr, "subr", dis_buf, Iop_SubF64, False );
4852 break;
4853
sewardje6939f02005-05-07 01:01:24 +00004854 case 6: /* FDIV single-real */
4855 fp_do_op_mem_ST_0 ( addr, "div", dis_buf, Iop_DivF64, False );
4856 break;
4857
4858 case 7: /* FDIVR single-real */
4859 fp_do_oprev_mem_ST_0 ( addr, "divr", dis_buf, Iop_DivF64, False );
4860 break;
sewardj37d52572005-02-25 14:22:12 +00004861
4862 default:
sewardj901ed122005-02-27 13:25:31 +00004863 vex_printf("unhandled opc_aux = 0x%2x\n", gregLO3ofRM(modrm));
sewardj37d52572005-02-25 14:22:12 +00004864 vex_printf("first_opcode == 0xD8\n");
4865 goto decode_fail;
4866 }
4867 } else {
4868 delta++;
4869 switch (modrm) {
4870
4871 case 0xC0 ... 0xC7: /* FADD %st(?),%st(0) */
4872 fp_do_op_ST_ST ( "add", Iop_AddF64, modrm - 0xC0, 0, False );
4873 break;
4874
sewardj137015d2005-03-27 04:01:15 +00004875 case 0xC8 ... 0xCF: /* FMUL %st(?),%st(0) */
4876 fp_do_op_ST_ST ( "mul", Iop_MulF64, modrm - 0xC8, 0, False );
4877 break;
4878
sewardj1859ecd2007-02-23 08:48:22 +00004879 /* Dunno if this is right */
4880 case 0xD0 ... 0xD7: /* FCOM %st(?),%st(0) */
4881 r_dst = (UInt)modrm - 0xD0;
4882 DIP("fcom %%st(0),%%st(%d)\n", r_dst);
4883 /* This forces C1 to zero, which isn't right. */
4884 put_C3210(
4885 unop(Iop_32Uto64,
4886 binop( Iop_And32,
4887 binop(Iop_Shl32,
4888 binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
4889 mkU8(8)),
4890 mkU32(0x4500)
4891 )));
4892 break;
4893
sewardj90e2e4b2007-05-04 09:41:24 +00004894 /* Dunno if this is right */
4895 case 0xD8 ... 0xDF: /* FCOMP %st(?),%st(0) */
4896 r_dst = (UInt)modrm - 0xD8;
4897 DIP("fcomp %%st(0),%%st(%d)\n", r_dst);
4898 /* This forces C1 to zero, which isn't right. */
4899 put_C3210(
4900 unop(Iop_32Uto64,
4901 binop( Iop_And32,
4902 binop(Iop_Shl32,
4903 binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
4904 mkU8(8)),
4905 mkU32(0x4500)
4906 )));
4907 fp_pop();
4908 break;
4909
sewardj137015d2005-03-27 04:01:15 +00004910 case 0xE0 ... 0xE7: /* FSUB %st(?),%st(0) */
4911 fp_do_op_ST_ST ( "sub", Iop_SubF64, modrm - 0xE0, 0, False );
4912 break;
4913
sewardje6939f02005-05-07 01:01:24 +00004914 case 0xE8 ... 0xEF: /* FSUBR %st(?),%st(0) */
4915 fp_do_oprev_ST_ST ( "subr", Iop_SubF64, modrm - 0xE8, 0, False );
4916 break;
sewardj137015d2005-03-27 04:01:15 +00004917
4918 case 0xF0 ... 0xF7: /* FDIV %st(?),%st(0) */
4919 fp_do_op_ST_ST ( "div", Iop_DivF64, modrm - 0xF0, 0, False );
4920 break;
4921
sewardj48a89d82005-05-06 11:50:13 +00004922 case 0xF8 ... 0xFF: /* FDIVR %st(?),%st(0) */
4923 fp_do_oprev_ST_ST ( "divr", Iop_DivF64, modrm - 0xF8, 0, False );
4924 break;
sewardj37d52572005-02-25 14:22:12 +00004925
4926 default:
4927 goto decode_fail;
4928 }
4929 }
4930 }
sewardj8d965312005-02-25 02:48:47 +00004931
4932 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xD9 opcodes +-+-+-+-+-+-+-+ */
sewardj37d52572005-02-25 14:22:12 +00004933 else
sewardj8d965312005-02-25 02:48:47 +00004934 if (first_opcode == 0xD9) {
4935 if (modrm < 0xC0) {
4936
4937 /* bits 5,4,3 are an opcode extension, and the modRM also
4938 specifies an address. */
sewardj2e28ac42008-12-04 00:05:12 +00004939 IRTemp addr = disAMode( &len, vbi, pfx, delta, dis_buf, 0 );
sewardj8d965312005-02-25 02:48:47 +00004940 delta += len;
4941
sewardj901ed122005-02-27 13:25:31 +00004942 switch (gregLO3ofRM(modrm)) {
sewardj8d965312005-02-25 02:48:47 +00004943
sewardjc49ce232005-02-25 13:03:03 +00004944 case 0: /* FLD single-real */
4945 DIP("flds %s\n", dis_buf);
4946 fp_push();
4947 put_ST(0, unop(Iop_F32toF64,
4948 loadLE(Ity_F32, mkexpr(addr))));
4949 break;
4950
4951 case 2: /* FST single-real */
4952 DIP("fsts %s\n", dis_buf);
4953 storeLE(mkexpr(addr),
4954 binop(Iop_F64toF32, get_roundingmode(), get_ST(0)));
4955 break;
4956
4957 case 3: /* FSTP single-real */
4958 DIP("fstps %s\n", dis_buf);
4959 storeLE(mkexpr(addr),
4960 binop(Iop_F64toF32, get_roundingmode(), get_ST(0)));
4961 fp_pop();
4962 break;
4963
sewardj4017a3b2005-06-13 12:17:27 +00004964 case 4: { /* FLDENV m28 */
4965 /* Uses dirty helper:
4966 VexEmWarn amd64g_do_FLDENV ( VexGuestX86State*, HWord ) */
4967 IRTemp ew = newTemp(Ity_I32);
4968 IRTemp w64 = newTemp(Ity_I64);
4969 IRDirty* d = unsafeIRDirty_0_N (
4970 0/*regparms*/,
4971 "amd64g_dirtyhelper_FLDENV",
4972 &amd64g_dirtyhelper_FLDENV,
4973 mkIRExprVec_1( mkexpr(addr) )
4974 );
4975 d->needsBBP = True;
4976 d->tmp = w64;
4977 /* declare we're reading memory */
4978 d->mFx = Ifx_Read;
4979 d->mAddr = mkexpr(addr);
4980 d->mSize = 28;
4981
4982 /* declare we're writing guest state */
4983 d->nFxState = 4;
4984
4985 d->fxState[0].fx = Ifx_Write;
4986 d->fxState[0].offset = OFFB_FTOP;
4987 d->fxState[0].size = sizeof(UInt);
4988
4989 d->fxState[1].fx = Ifx_Write;
4990 d->fxState[1].offset = OFFB_FPTAGS;
4991 d->fxState[1].size = 8 * sizeof(UChar);
4992
4993 d->fxState[2].fx = Ifx_Write;
4994 d->fxState[2].offset = OFFB_FPROUND;
4995 d->fxState[2].size = sizeof(ULong);
4996
4997 d->fxState[3].fx = Ifx_Write;
4998 d->fxState[3].offset = OFFB_FC3210;
4999 d->fxState[3].size = sizeof(ULong);
5000
5001 stmt( IRStmt_Dirty(d) );
5002
5003 /* ew contains any emulation warning we may need to
5004 issue. If needed, side-exit to the next insn,
5005 reporting the warning, so that Valgrind's dispatcher
5006 sees the warning. */
5007 assign(ew, unop(Iop_64to32,mkexpr(w64)) );
5008 put_emwarn( mkexpr(ew) );
5009 stmt(
5010 IRStmt_Exit(
5011 binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
5012 Ijk_EmWarn,
sewardj9e6491a2005-07-02 19:24:10 +00005013 IRConst_U64( guest_RIP_bbstart+delta )
sewardj4017a3b2005-06-13 12:17:27 +00005014 )
5015 );
5016
5017 DIP("fldenv %s\n", dis_buf);
5018 break;
5019 }
sewardj5e205372005-05-09 02:57:08 +00005020
5021 case 5: {/* FLDCW */
5022 /* The only thing we observe in the control word is the
5023 rounding mode. Therefore, pass the 16-bit value
5024 (x87 native-format control word) to a clean helper,
5025 getting back a 64-bit value, the lower half of which
5026 is the FPROUND value to store, and the upper half of
5027 which is the emulation-warning token which may be
5028 generated.
5029 */
5030 /* ULong amd64h_check_fldcw ( ULong ); */
5031 IRTemp t64 = newTemp(Ity_I64);
5032 IRTemp ew = newTemp(Ity_I32);
5033 DIP("fldcw %s\n", dis_buf);
5034 assign( t64, mkIRExprCCall(
5035 Ity_I64, 0/*regparms*/,
5036 "amd64g_check_fldcw",
5037 &amd64g_check_fldcw,
5038 mkIRExprVec_1(
5039 unop( Iop_16Uto64,
5040 loadLE(Ity_I16, mkexpr(addr)))
5041 )
5042 )
5043 );
5044
5045 put_fpround( unop(Iop_64to32, mkexpr(t64)) );
5046 assign( ew, unop(Iop_64HIto32, mkexpr(t64) ) );
5047 put_emwarn( mkexpr(ew) );
5048 /* Finally, if an emulation warning was reported,
5049 side-exit to the next insn, reporting the warning,
5050 so that Valgrind's dispatcher sees the warning. */
5051 stmt(
5052 IRStmt_Exit(
5053 binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
5054 Ijk_EmWarn,
sewardj9e6491a2005-07-02 19:24:10 +00005055 IRConst_U64( guest_RIP_bbstart+delta )
sewardj5e205372005-05-09 02:57:08 +00005056 )
5057 );
5058 break;
5059 }
5060
sewardj4017a3b2005-06-13 12:17:27 +00005061 case 6: { /* FNSTENV m28 */
5062 /* Uses dirty helper:
5063 void amd64g_do_FSTENV ( VexGuestAMD64State*, HWord ) */
5064 IRDirty* d = unsafeIRDirty_0_N (
5065 0/*regparms*/,
5066 "amd64g_dirtyhelper_FSTENV",
5067 &amd64g_dirtyhelper_FSTENV,
5068 mkIRExprVec_1( mkexpr(addr) )
5069 );
5070 d->needsBBP = True;
5071 /* declare we're writing memory */
5072 d->mFx = Ifx_Write;
5073 d->mAddr = mkexpr(addr);
5074 d->mSize = 28;
5075
5076 /* declare we're reading guest state */
5077 d->nFxState = 4;
5078
5079 d->fxState[0].fx = Ifx_Read;
5080 d->fxState[0].offset = OFFB_FTOP;
5081 d->fxState[0].size = sizeof(UInt);
5082
5083 d->fxState[1].fx = Ifx_Read;
5084 d->fxState[1].offset = OFFB_FPTAGS;
5085 d->fxState[1].size = 8 * sizeof(UChar);
5086
5087 d->fxState[2].fx = Ifx_Read;
5088 d->fxState[2].offset = OFFB_FPROUND;
5089 d->fxState[2].size = sizeof(ULong);
5090
5091 d->fxState[3].fx = Ifx_Read;
5092 d->fxState[3].offset = OFFB_FC3210;
5093 d->fxState[3].size = sizeof(ULong);
5094
5095 stmt( IRStmt_Dirty(d) );
5096
5097 DIP("fnstenv %s\n", dis_buf);
5098 break;
5099 }
sewardj5e205372005-05-09 02:57:08 +00005100
5101 case 7: /* FNSTCW */
5102 /* Fake up a native x87 FPU control word. The only
5103 thing it depends on is FPROUND[1:0], so call a clean
5104 helper to cook it up. */
sewardj4017a3b2005-06-13 12:17:27 +00005105 /* ULong amd64g_create_fpucw ( ULong fpround ) */
sewardj5e205372005-05-09 02:57:08 +00005106 DIP("fnstcw %s\n", dis_buf);
5107 storeLE(
5108 mkexpr(addr),
5109 unop( Iop_64to16,
5110 mkIRExprCCall(
5111 Ity_I64, 0/*regp*/,
5112 "amd64g_create_fpucw", &amd64g_create_fpucw,
5113 mkIRExprVec_1( unop(Iop_32Uto64, get_fpround()) )
5114 )
5115 )
5116 );
5117 break;
sewardj8d965312005-02-25 02:48:47 +00005118
5119 default:
sewardj901ed122005-02-27 13:25:31 +00005120 vex_printf("unhandled opc_aux = 0x%2x\n", gregLO3ofRM(modrm));
sewardj8d965312005-02-25 02:48:47 +00005121 vex_printf("first_opcode == 0xD9\n");
5122 goto decode_fail;
5123 }
5124
5125 } else {
5126 delta++;
5127 switch (modrm) {
5128
sewardjc49ce232005-02-25 13:03:03 +00005129 case 0xC0 ... 0xC7: /* FLD %st(?) */
5130 r_src = (UInt)modrm - 0xC0;
sewardj1027dc22005-02-26 01:55:02 +00005131 DIP("fld %%st(%u)\n", r_src);
sewardjc49ce232005-02-25 13:03:03 +00005132 t1 = newTemp(Ity_F64);
5133 assign(t1, get_ST(r_src));
5134 fp_push();
5135 put_ST(0, mkexpr(t1));
5136 break;
sewardj8d965312005-02-25 02:48:47 +00005137
5138 case 0xC8 ... 0xCF: /* FXCH %st(?) */
5139 r_src = (UInt)modrm - 0xC8;
sewardj1027dc22005-02-26 01:55:02 +00005140 DIP("fxch %%st(%u)\n", r_src);
sewardj8d965312005-02-25 02:48:47 +00005141 t1 = newTemp(Ity_F64);
5142 t2 = newTemp(Ity_F64);
5143 assign(t1, get_ST(0));
5144 assign(t2, get_ST(r_src));
5145 put_ST_UNCHECKED(0, mkexpr(t2));
5146 put_ST_UNCHECKED(r_src, mkexpr(t1));
5147 break;
5148
5149 case 0xE0: /* FCHS */
5150 DIP("fchs\n");
5151 put_ST_UNCHECKED(0, unop(Iop_NegF64, get_ST(0)));
5152 break;
5153
sewardj137015d2005-03-27 04:01:15 +00005154 case 0xE1: /* FABS */
5155 DIP("fabs\n");
5156 put_ST_UNCHECKED(0, unop(Iop_AbsF64, get_ST(0)));
5157 break;
5158
sewardj4f9847d2005-07-25 11:58:34 +00005159 case 0xE5: { /* FXAM */
5160 /* This is an interesting one. It examines %st(0),
5161 regardless of whether the tag says it's empty or not.
5162 Here, just pass both the tag (in our format) and the
5163 value (as a double, actually a ULong) to a helper
5164 function. */
5165 IRExpr** args
5166 = mkIRExprVec_2( unop(Iop_8Uto64, get_ST_TAG(0)),
5167 unop(Iop_ReinterpF64asI64,
5168 get_ST_UNCHECKED(0)) );
5169 put_C3210(mkIRExprCCall(
5170 Ity_I64,
5171 0/*regparm*/,
5172 "amd64g_calculate_FXAM", &amd64g_calculate_FXAM,
5173 args
5174 ));
5175 DIP("fxam\n");
5176 break;
5177 }
sewardjc49ce232005-02-25 13:03:03 +00005178
5179 case 0xE8: /* FLD1 */
5180 DIP("fld1\n");
5181 fp_push();
5182 /* put_ST(0, IRExpr_Const(IRConst_F64(1.0))); */
5183 put_ST(0, IRExpr_Const(IRConst_F64i(0x3ff0000000000000ULL)));
5184 break;
5185
sewardj6847d8c2005-05-12 19:21:55 +00005186 case 0xE9: /* FLDL2T */
5187 DIP("fldl2t\n");
5188 fp_push();
5189 /* put_ST(0, IRExpr_Const(IRConst_F64(3.32192809488736234781))); */
5190 put_ST(0, IRExpr_Const(IRConst_F64i(0x400a934f0979a371ULL)));
5191 break;
5192
5193 case 0xEA: /* FLDL2E */
5194 DIP("fldl2e\n");
5195 fp_push();
5196 /* put_ST(0, IRExpr_Const(IRConst_F64(1.44269504088896340739))); */
5197 put_ST(0, IRExpr_Const(IRConst_F64i(0x3ff71547652b82feULL)));
5198 break;
5199
5200 case 0xEB: /* FLDPI */
5201 DIP("fldpi\n");
5202 fp_push();
5203 /* put_ST(0, IRExpr_Const(IRConst_F64(3.14159265358979323851))); */
5204 put_ST(0, IRExpr_Const(IRConst_F64i(0x400921fb54442d18ULL)));
5205 break;
5206
5207 case 0xEC: /* FLDLG2 */
5208 DIP("fldlg2\n");
5209 fp_push();
5210 /* put_ST(0, IRExpr_Const(IRConst_F64(0.301029995663981143))); */
5211 put_ST(0, IRExpr_Const(IRConst_F64i(0x3fd34413509f79ffULL)));
5212 break;
5213
5214 case 0xED: /* FLDLN2 */
5215 DIP("fldln2\n");
5216 fp_push();
5217 /* put_ST(0, IRExpr_Const(IRConst_F64(0.69314718055994530942))); */
5218 put_ST(0, IRExpr_Const(IRConst_F64i(0x3fe62e42fefa39efULL)));
5219 break;
sewardjc49ce232005-02-25 13:03:03 +00005220
5221 case 0xEE: /* FLDZ */
5222 DIP("fldz\n");
5223 fp_push();
5224 /* put_ST(0, IRExpr_Const(IRConst_F64(0.0))); */
5225 put_ST(0, IRExpr_Const(IRConst_F64i(0x0000000000000000ULL)));
5226 break;
5227
sewardj25a85812005-05-08 23:03:48 +00005228 case 0xF0: /* F2XM1 */
5229 DIP("f2xm1\n");
sewardj4796d662006-02-05 16:06:26 +00005230 put_ST_UNCHECKED(0,
5231 binop(Iop_2xm1F64,
5232 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
5233 get_ST(0)));
sewardj25a85812005-05-08 23:03:48 +00005234 break;
5235
5236 case 0xF1: /* FYL2X */
5237 DIP("fyl2x\n");
sewardj4796d662006-02-05 16:06:26 +00005238 put_ST_UNCHECKED(1,
5239 triop(Iop_Yl2xF64,
5240 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
5241 get_ST(1),
5242 get_ST(0)));
sewardj25a85812005-05-08 23:03:48 +00005243 fp_pop();
5244 break;
5245
sewardj5e205372005-05-09 02:57:08 +00005246 case 0xF2: /* FPTAN */
5247 DIP("ftan\n");
sewardj4796d662006-02-05 16:06:26 +00005248 put_ST_UNCHECKED(0,
5249 binop(Iop_TanF64,
5250 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
5251 get_ST(0)));
sewardj5e205372005-05-09 02:57:08 +00005252 fp_push();
5253 put_ST(0, IRExpr_Const(IRConst_F64(1.0)));
5254 clear_C2(); /* HACK */
5255 break;
sewardj25a85812005-05-08 23:03:48 +00005256
5257 case 0xF3: /* FPATAN */
5258 DIP("fpatan\n");
sewardj4796d662006-02-05 16:06:26 +00005259 put_ST_UNCHECKED(1,
5260 triop(Iop_AtanF64,
5261 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
5262 get_ST(1),
5263 get_ST(0)));
sewardj25a85812005-05-08 23:03:48 +00005264 fp_pop();
5265 break;
5266
sewardj879cee02006-03-07 01:15:50 +00005267 case 0xF4: { /* FXTRACT */
5268 IRTemp argF = newTemp(Ity_F64);
5269 IRTemp sigF = newTemp(Ity_F64);
5270 IRTemp expF = newTemp(Ity_F64);
5271 IRTemp argI = newTemp(Ity_I64);
5272 IRTemp sigI = newTemp(Ity_I64);
5273 IRTemp expI = newTemp(Ity_I64);
5274 DIP("fxtract\n");
5275 assign( argF, get_ST(0) );
5276 assign( argI, unop(Iop_ReinterpF64asI64, mkexpr(argF)));
5277 assign( sigI,
5278 mkIRExprCCall(
5279 Ity_I64, 0/*regparms*/,
5280 "x86amd64g_calculate_FXTRACT",
5281 &x86amd64g_calculate_FXTRACT,
5282 mkIRExprVec_2( mkexpr(argI),
5283 mkIRExpr_HWord(0)/*sig*/ ))
5284 );
5285 assign( expI,
5286 mkIRExprCCall(
5287 Ity_I64, 0/*regparms*/,
5288 "x86amd64g_calculate_FXTRACT",
5289 &x86amd64g_calculate_FXTRACT,
5290 mkIRExprVec_2( mkexpr(argI),
5291 mkIRExpr_HWord(1)/*exp*/ ))
5292 );
5293 assign( sigF, unop(Iop_ReinterpI64asF64, mkexpr(sigI)) );
5294 assign( expF, unop(Iop_ReinterpI64asF64, mkexpr(expI)) );
5295 /* exponent */
5296 put_ST_UNCHECKED(0, mkexpr(expF) );
5297 fp_push();
5298 /* significand */
5299 put_ST(0, mkexpr(sigF) );
5300 break;
5301 }
5302
sewardj4970e4e2008-10-11 10:07:55 +00005303 case 0xF5: { /* FPREM1 -- IEEE compliant */
5304 IRTemp a1 = newTemp(Ity_F64);
5305 IRTemp a2 = newTemp(Ity_F64);
5306 DIP("fprem1\n");
5307 /* Do FPREM1 twice, once to get the remainder, and once
5308 to get the C3210 flag values. */
5309 assign( a1, get_ST(0) );
5310 assign( a2, get_ST(1) );
5311 put_ST_UNCHECKED(0,
5312 triop(Iop_PRem1F64,
5313 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
5314 mkexpr(a1),
5315 mkexpr(a2)));
5316 put_C3210(
5317 unop(Iop_32Uto64,
5318 triop(Iop_PRem1C3210F64,
5319 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
5320 mkexpr(a1),
5321 mkexpr(a2)) ));
5322 break;
5323 }
sewardj6847d8c2005-05-12 19:21:55 +00005324
5325 case 0xF7: /* FINCSTP */
5326 DIP("fincstp\n");
5327 put_ftop( binop(Iop_Add32, get_ftop(), mkU32(1)) );
5328 break;
5329
sewardjf4c803b2006-09-11 11:07:34 +00005330 case 0xF8: { /* FPREM -- not IEEE compliant */
5331 IRTemp a1 = newTemp(Ity_F64);
5332 IRTemp a2 = newTemp(Ity_F64);
5333 DIP("fprem\n");
5334 /* Do FPREM twice, once to get the remainder, and once
5335 to get the C3210 flag values. */
5336 assign( a1, get_ST(0) );
5337 assign( a2, get_ST(1) );
5338 put_ST_UNCHECKED(0,
5339 triop(Iop_PRemF64,
5340 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
5341 mkexpr(a1),
5342 mkexpr(a2)));
5343 put_C3210(
5344 unop(Iop_32Uto64,
5345 triop(Iop_PRemC3210F64,
5346 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
5347 mkexpr(a1),
5348 mkexpr(a2)) ));
5349 break;
5350 }
5351
sewardj5e205372005-05-09 02:57:08 +00005352 case 0xF9: /* FYL2XP1 */
5353 DIP("fyl2xp1\n");
sewardj4796d662006-02-05 16:06:26 +00005354 put_ST_UNCHECKED(1,
5355 triop(Iop_Yl2xp1F64,
5356 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
5357 get_ST(1),
5358 get_ST(0)));
sewardj5e205372005-05-09 02:57:08 +00005359 fp_pop();
5360 break;
sewardje6939f02005-05-07 01:01:24 +00005361
5362 case 0xFA: /* FSQRT */
5363 DIP("fsqrt\n");
sewardj4796d662006-02-05 16:06:26 +00005364 put_ST_UNCHECKED(0,
5365 binop(Iop_SqrtF64,
5366 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
5367 get_ST(0)));
sewardje6939f02005-05-07 01:01:24 +00005368 break;
5369
sewardj25a85812005-05-08 23:03:48 +00005370 case 0xFB: { /* FSINCOS */
5371 IRTemp a1 = newTemp(Ity_F64);
5372 assign( a1, get_ST(0) );
5373 DIP("fsincos\n");
sewardj4796d662006-02-05 16:06:26 +00005374 put_ST_UNCHECKED(0,
5375 binop(Iop_SinF64,
5376 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
5377 mkexpr(a1)));
sewardj25a85812005-05-08 23:03:48 +00005378 fp_push();
sewardj4796d662006-02-05 16:06:26 +00005379 put_ST(0,
5380 binop(Iop_CosF64,
5381 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
5382 mkexpr(a1)));
sewardj25a85812005-05-08 23:03:48 +00005383 clear_C2(); /* HACK */
5384 break;
5385 }
5386
5387 case 0xFC: /* FRNDINT */
5388 DIP("frndint\n");
5389 put_ST_UNCHECKED(0,
sewardjb183b852006-02-03 16:08:03 +00005390 binop(Iop_RoundF64toInt, get_roundingmode(), get_ST(0)) );
sewardj25a85812005-05-08 23:03:48 +00005391 break;
5392
5393 case 0xFD: /* FSCALE */
5394 DIP("fscale\n");
sewardj4796d662006-02-05 16:06:26 +00005395 put_ST_UNCHECKED(0,
5396 triop(Iop_ScaleF64,
5397 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
5398 get_ST(0),
5399 get_ST(1)));
sewardj25a85812005-05-08 23:03:48 +00005400 break;
5401
5402 case 0xFE: /* FSIN */
5403 DIP("fsin\n");
sewardj4796d662006-02-05 16:06:26 +00005404 put_ST_UNCHECKED(0,
5405 binop(Iop_SinF64,
5406 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
5407 get_ST(0)));
sewardj25a85812005-05-08 23:03:48 +00005408 clear_C2(); /* HACK */
5409 break;
5410
5411 case 0xFF: /* FCOS */
5412 DIP("fcos\n");
sewardj4796d662006-02-05 16:06:26 +00005413 put_ST_UNCHECKED(0,
5414 binop(Iop_CosF64,
5415 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
5416 get_ST(0)));
sewardj25a85812005-05-08 23:03:48 +00005417 clear_C2(); /* HACK */
5418 break;
sewardj8d965312005-02-25 02:48:47 +00005419
5420 default:
5421 goto decode_fail;
5422 }
5423 }
5424 }
5425
5426 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDA opcodes +-+-+-+-+-+-+-+ */
5427 else
5428 if (first_opcode == 0xDA) {
5429
5430 if (modrm < 0xC0) {
5431
5432 /* bits 5,4,3 are an opcode extension, and the modRM also
5433 specifies an address. */
sewardj6847d8c2005-05-12 19:21:55 +00005434 IROp fop;
sewardj2e28ac42008-12-04 00:05:12 +00005435 IRTemp addr = disAMode( &len, vbi, pfx, delta, dis_buf, 0 );
sewardj8d965312005-02-25 02:48:47 +00005436 delta += len;
sewardj901ed122005-02-27 13:25:31 +00005437 switch (gregLO3ofRM(modrm)) {
sewardj8d965312005-02-25 02:48:47 +00005438
sewardj6847d8c2005-05-12 19:21:55 +00005439 case 0: /* FIADD m32int */ /* ST(0) += m32int */
5440 DIP("fiaddl %s\n", dis_buf);
5441 fop = Iop_AddF64;
5442 goto do_fop_m32;
5443
5444 case 1: /* FIMUL m32int */ /* ST(0) *= m32int */
5445 DIP("fimull %s\n", dis_buf);
5446 fop = Iop_MulF64;
5447 goto do_fop_m32;
5448
5449 case 4: /* FISUB m32int */ /* ST(0) -= m32int */
5450 DIP("fisubl %s\n", dis_buf);
5451 fop = Iop_SubF64;
5452 goto do_fop_m32;
5453
5454 case 5: /* FISUBR m32int */ /* ST(0) = m32int - ST(0) */
5455 DIP("fisubrl %s\n", dis_buf);
5456 fop = Iop_SubF64;
5457 goto do_foprev_m32;
5458
5459 case 6: /* FIDIV m32int */ /* ST(0) /= m32int */
5460 DIP("fisubl %s\n", dis_buf);
5461 fop = Iop_DivF64;
5462 goto do_fop_m32;
5463
5464 case 7: /* FIDIVR m32int */ /* ST(0) = m32int / ST(0) */
5465 DIP("fidivrl %s\n", dis_buf);
5466 fop = Iop_DivF64;
5467 goto do_foprev_m32;
5468
5469 do_fop_m32:
5470 put_ST_UNCHECKED(0,
sewardj4796d662006-02-05 16:06:26 +00005471 triop(fop,
5472 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardj6847d8c2005-05-12 19:21:55 +00005473 get_ST(0),
sewardj6c299f32009-12-31 18:00:12 +00005474 unop(Iop_I32StoF64,
sewardj6847d8c2005-05-12 19:21:55 +00005475 loadLE(Ity_I32, mkexpr(addr)))));
5476 break;
5477
5478 do_foprev_m32:
5479 put_ST_UNCHECKED(0,
sewardj4796d662006-02-05 16:06:26 +00005480 triop(fop,
5481 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardj6c299f32009-12-31 18:00:12 +00005482 unop(Iop_I32StoF64,
sewardj6847d8c2005-05-12 19:21:55 +00005483 loadLE(Ity_I32, mkexpr(addr))),
5484 get_ST(0)));
5485 break;
sewardj8d965312005-02-25 02:48:47 +00005486
5487 default:
sewardj901ed122005-02-27 13:25:31 +00005488 vex_printf("unhandled opc_aux = 0x%2x\n", gregLO3ofRM(modrm));
sewardj8d965312005-02-25 02:48:47 +00005489 vex_printf("first_opcode == 0xDA\n");
5490 goto decode_fail;
5491 }
5492
5493 } else {
5494
5495 delta++;
5496 switch (modrm) {
5497
sewardj48a89d82005-05-06 11:50:13 +00005498 case 0xC0 ... 0xC7: /* FCMOVB ST(i), ST(0) */
5499 r_src = (UInt)modrm - 0xC0;
sewardjca673ab2005-05-11 10:03:08 +00005500 DIP("fcmovb %%st(%u), %%st(0)\n", r_src);
sewardj48a89d82005-05-06 11:50:13 +00005501 put_ST_UNCHECKED(0,
5502 IRExpr_Mux0X(
5503 unop(Iop_1Uto8,
5504 mk_amd64g_calculate_condition(AMD64CondB)),
5505 get_ST(0), get_ST(r_src)) );
5506 break;
sewardj8d965312005-02-25 02:48:47 +00005507
5508 case 0xC8 ... 0xCF: /* FCMOVE(Z) ST(i), ST(0) */
5509 r_src = (UInt)modrm - 0xC8;
sewardj1027dc22005-02-26 01:55:02 +00005510 DIP("fcmovz %%st(%u), %%st(0)\n", r_src);
sewardj8d965312005-02-25 02:48:47 +00005511 put_ST_UNCHECKED(0,
5512 IRExpr_Mux0X(
5513 unop(Iop_1Uto8,
5514 mk_amd64g_calculate_condition(AMD64CondZ)),
5515 get_ST(0), get_ST(r_src)) );
5516 break;
5517
sewardj37d52572005-02-25 14:22:12 +00005518 case 0xD0 ... 0xD7: /* FCMOVBE ST(i), ST(0) */
5519 r_src = (UInt)modrm - 0xD0;
sewardj1027dc22005-02-26 01:55:02 +00005520 DIP("fcmovbe %%st(%u), %%st(0)\n", r_src);
sewardj37d52572005-02-25 14:22:12 +00005521 put_ST_UNCHECKED(0,
5522 IRExpr_Mux0X(
5523 unop(Iop_1Uto8,
5524 mk_amd64g_calculate_condition(AMD64CondBE)),
5525 get_ST(0), get_ST(r_src)) );
5526 break;
5527
sewardj25a85812005-05-08 23:03:48 +00005528 case 0xD8 ... 0xDF: /* FCMOVU ST(i), ST(0) */
5529 r_src = (UInt)modrm - 0xD8;
5530 DIP("fcmovu %%st(%u), %%st(0)\n", r_src);
5531 put_ST_UNCHECKED(0,
5532 IRExpr_Mux0X(
5533 unop(Iop_1Uto8,
5534 mk_amd64g_calculate_condition(AMD64CondP)),
5535 get_ST(0), get_ST(r_src)) );
5536 break;
5537
sewardje7f277a2008-04-28 21:05:33 +00005538 case 0xE9: /* FUCOMPP %st(0),%st(1) */
5539 DIP("fucompp %%st(0),%%st(1)\n");
5540 /* This forces C1 to zero, which isn't right. */
5541 put_C3210(
5542 unop(Iop_32Uto64,
5543 binop( Iop_And32,
5544 binop(Iop_Shl32,
5545 binop(Iop_CmpF64, get_ST(0), get_ST(1)),
5546 mkU8(8)),
5547 mkU32(0x4500)
5548 )));
5549 fp_pop();
5550 fp_pop();
5551 break;
sewardj8d965312005-02-25 02:48:47 +00005552
5553 default:
5554 goto decode_fail;
5555 }
5556
5557 }
5558 }
5559
sewardjc49ce232005-02-25 13:03:03 +00005560 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDB opcodes +-+-+-+-+-+-+-+ */
5561 else
5562 if (first_opcode == 0xDB) {
5563 if (modrm < 0xC0) {
5564
5565 /* bits 5,4,3 are an opcode extension, and the modRM also
5566 specifies an address. */
sewardj2e28ac42008-12-04 00:05:12 +00005567 IRTemp addr = disAMode( &len, vbi, pfx, delta, dis_buf, 0 );
sewardjc49ce232005-02-25 13:03:03 +00005568 delta += len;
5569
sewardj901ed122005-02-27 13:25:31 +00005570 switch (gregLO3ofRM(modrm)) {
sewardjc49ce232005-02-25 13:03:03 +00005571
sewardj5cc00ff2005-03-27 04:48:32 +00005572 case 0: /* FILD m32int */
5573 DIP("fildl %s\n", dis_buf);
5574 fp_push();
sewardj6c299f32009-12-31 18:00:12 +00005575 put_ST(0, unop(Iop_I32StoF64,
sewardj5cc00ff2005-03-27 04:48:32 +00005576 loadLE(Ity_I32, mkexpr(addr))));
5577 break;
5578
sewardjfcf21f32006-08-04 14:51:19 +00005579 case 1: /* FISTTPL m32 (SSE3) */
5580 DIP("fisttpl %s\n", dis_buf);
5581 storeLE( mkexpr(addr),
sewardj6c299f32009-12-31 18:00:12 +00005582 binop(Iop_F64toI32S, mkU32(Irrm_ZERO), get_ST(0)) );
sewardjfcf21f32006-08-04 14:51:19 +00005583 fp_pop();
5584 break;
5585
sewardj6847d8c2005-05-12 19:21:55 +00005586 case 2: /* FIST m32 */
5587 DIP("fistl %s\n", dis_buf);
5588 storeLE( mkexpr(addr),
sewardj6c299f32009-12-31 18:00:12 +00005589 binop(Iop_F64toI32S, get_roundingmode(), get_ST(0)) );
sewardj6847d8c2005-05-12 19:21:55 +00005590 break;
sewardj37d52572005-02-25 14:22:12 +00005591
5592 case 3: /* FISTP m32 */
5593 DIP("fistpl %s\n", dis_buf);
5594 storeLE( mkexpr(addr),
sewardj6c299f32009-12-31 18:00:12 +00005595 binop(Iop_F64toI32S, get_roundingmode(), get_ST(0)) );
sewardj37d52572005-02-25 14:22:12 +00005596 fp_pop();
5597 break;
5598
sewardj924215b2005-03-26 21:50:31 +00005599 case 5: { /* FLD extended-real */
5600 /* Uses dirty helper:
5601 ULong amd64g_loadF80le ( ULong )
5602 addr holds the address. First, do a dirty call to
5603 get hold of the data. */
5604 IRTemp val = newTemp(Ity_I64);
5605 IRExpr** args = mkIRExprVec_1 ( mkexpr(addr) );
5606
5607 IRDirty* d = unsafeIRDirty_1_N (
5608 val,
5609 0/*regparms*/,
sewardj8707fef2005-08-23 23:26:37 +00005610 "amd64g_dirtyhelper_loadF80le",
5611 &amd64g_dirtyhelper_loadF80le,
sewardj924215b2005-03-26 21:50:31 +00005612 args
5613 );
5614 /* declare that we're reading memory */
5615 d->mFx = Ifx_Read;
5616 d->mAddr = mkexpr(addr);
5617 d->mSize = 10;
5618
5619 /* execute the dirty call, dumping the result in val. */
5620 stmt( IRStmt_Dirty(d) );
5621 fp_push();
5622 put_ST(0, unop(Iop_ReinterpI64asF64, mkexpr(val)));
5623
5624 DIP("fldt %s\n", dis_buf);
5625 break;
5626 }
5627
5628 case 7: { /* FSTP extended-real */
5629 /* Uses dirty helper:
5630 void amd64g_storeF80le ( ULong addr, ULong data )
5631 */
5632 IRExpr** args
5633 = mkIRExprVec_2( mkexpr(addr),
5634 unop(Iop_ReinterpF64asI64, get_ST(0)) );
5635
5636 IRDirty* d = unsafeIRDirty_0_N (
5637 0/*regparms*/,
sewardj8707fef2005-08-23 23:26:37 +00005638 "amd64g_dirtyhelper_storeF80le",
5639 &amd64g_dirtyhelper_storeF80le,
sewardj924215b2005-03-26 21:50:31 +00005640 args
5641 );
5642 /* declare we're writing memory */
5643 d->mFx = Ifx_Write;
5644 d->mAddr = mkexpr(addr);
5645 d->mSize = 10;
5646
5647 /* execute the dirty call. */
5648 stmt( IRStmt_Dirty(d) );
5649 fp_pop();
5650
5651 DIP("fstpt\n %s", dis_buf);
5652 break;
5653 }
sewardjc49ce232005-02-25 13:03:03 +00005654
5655 default:
sewardj901ed122005-02-27 13:25:31 +00005656 vex_printf("unhandled opc_aux = 0x%2x\n", gregLO3ofRM(modrm));
sewardjc49ce232005-02-25 13:03:03 +00005657 vex_printf("first_opcode == 0xDB\n");
5658 goto decode_fail;
5659 }
5660
5661 } else {
5662
5663 delta++;
5664 switch (modrm) {
5665
sewardj48a89d82005-05-06 11:50:13 +00005666 case 0xC0 ... 0xC7: /* FCMOVNB ST(i), ST(0) */
5667 r_src = (UInt)modrm - 0xC0;
sewardjca673ab2005-05-11 10:03:08 +00005668 DIP("fcmovnb %%st(%u), %%st(0)\n", r_src);
sewardj48a89d82005-05-06 11:50:13 +00005669 put_ST_UNCHECKED(0,
5670 IRExpr_Mux0X(
5671 unop(Iop_1Uto8,
5672 mk_amd64g_calculate_condition(AMD64CondNB)),
5673 get_ST(0), get_ST(r_src)) );
5674 break;
sewardj924215b2005-03-26 21:50:31 +00005675
5676 case 0xC8 ... 0xCF: /* FCMOVNE(NZ) ST(i), ST(0) */
5677 r_src = (UInt)modrm - 0xC8;
sewardj40e144d2005-03-28 00:46:27 +00005678 DIP("fcmovnz %%st(%u), %%st(0)\n", r_src);
sewardj137015d2005-03-27 04:01:15 +00005679 put_ST_UNCHECKED(
5680 0,
5681 IRExpr_Mux0X(
5682 unop(Iop_1Uto8,
5683 mk_amd64g_calculate_condition(AMD64CondNZ)),
5684 get_ST(0),
5685 get_ST(r_src)
5686 )
5687 );
sewardj924215b2005-03-26 21:50:31 +00005688 break;
5689
sewardj137015d2005-03-27 04:01:15 +00005690 case 0xD0 ... 0xD7: /* FCMOVNBE ST(i), ST(0) */
5691 r_src = (UInt)modrm - 0xD0;
sewardj40e144d2005-03-28 00:46:27 +00005692 DIP("fcmovnbe %%st(%u), %%st(0)\n", r_src);
sewardj137015d2005-03-27 04:01:15 +00005693 put_ST_UNCHECKED(
5694 0,
5695 IRExpr_Mux0X(
5696 unop(Iop_1Uto8,
5697 mk_amd64g_calculate_condition(AMD64CondNBE)),
5698 get_ST(0),
5699 get_ST(r_src)
5700 )
5701 );
5702 break;
5703
sewardj3368e102006-03-06 19:05:07 +00005704 case 0xD8 ... 0xDF: /* FCMOVNU ST(i), ST(0) */
5705 r_src = (UInt)modrm - 0xD8;
5706 DIP("fcmovnu %%st(%u), %%st(0)\n", r_src);
5707 put_ST_UNCHECKED(
5708 0,
5709 IRExpr_Mux0X(
5710 unop(Iop_1Uto8,
5711 mk_amd64g_calculate_condition(AMD64CondNP)),
5712 get_ST(0),
5713 get_ST(r_src)
5714 )
5715 );
5716 break;
5717
sewardj4e1a1e92005-05-25 00:44:13 +00005718 case 0xE2:
5719 DIP("fnclex\n");
5720 break;
5721
sewardj0585a032005-11-05 02:55:06 +00005722 case 0xE3: {
5723 /* Uses dirty helper:
5724 void amd64g_do_FINIT ( VexGuestAMD64State* ) */
5725 IRDirty* d = unsafeIRDirty_0_N (
5726 0/*regparms*/,
5727 "amd64g_dirtyhelper_FINIT",
5728 &amd64g_dirtyhelper_FINIT,
5729 mkIRExprVec_0()
5730 );
5731 d->needsBBP = True;
5732
5733 /* declare we're writing guest state */
5734 d->nFxState = 5;
5735
5736 d->fxState[0].fx = Ifx_Write;
5737 d->fxState[0].offset = OFFB_FTOP;
5738 d->fxState[0].size = sizeof(UInt);
5739
5740 d->fxState[1].fx = Ifx_Write;
5741 d->fxState[1].offset = OFFB_FPREGS;
5742 d->fxState[1].size = 8 * sizeof(ULong);
5743
5744 d->fxState[2].fx = Ifx_Write;
5745 d->fxState[2].offset = OFFB_FPTAGS;
5746 d->fxState[2].size = 8 * sizeof(UChar);
5747
5748 d->fxState[3].fx = Ifx_Write;
5749 d->fxState[3].offset = OFFB_FPROUND;
5750 d->fxState[3].size = sizeof(ULong);
5751
5752 d->fxState[4].fx = Ifx_Write;
5753 d->fxState[4].offset = OFFB_FC3210;
5754 d->fxState[4].size = sizeof(ULong);
5755
5756 stmt( IRStmt_Dirty(d) );
5757
5758 DIP("fninit\n");
5759 break;
5760 }
sewardjc49ce232005-02-25 13:03:03 +00005761
5762 case 0xE8 ... 0xEF: /* FUCOMI %st(0),%st(?) */
5763 fp_do_ucomi_ST0_STi( (UInt)modrm - 0xE8, False );
5764 break;
5765
sewardj48a89d82005-05-06 11:50:13 +00005766 case 0xF0 ... 0xF7: /* FCOMI %st(0),%st(?) */
5767 fp_do_ucomi_ST0_STi( (UInt)modrm - 0xF0, False );
5768 break;
sewardjc49ce232005-02-25 13:03:03 +00005769
5770 default:
5771 goto decode_fail;
5772 }
5773 }
5774 }
5775
sewardj137015d2005-03-27 04:01:15 +00005776 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDC opcodes +-+-+-+-+-+-+-+ */
5777 else
5778 if (first_opcode == 0xDC) {
5779 if (modrm < 0xC0) {
5780
sewardj434e0692005-03-27 17:36:08 +00005781 /* bits 5,4,3 are an opcode extension, and the modRM also
5782 specifies an address. */
sewardj2e28ac42008-12-04 00:05:12 +00005783 IRTemp addr = disAMode( &len, vbi, pfx, delta, dis_buf, 0 );
sewardj434e0692005-03-27 17:36:08 +00005784 delta += len;
5785
5786 switch (gregLO3ofRM(modrm)) {
5787
sewardje6939f02005-05-07 01:01:24 +00005788 case 0: /* FADD double-real */
5789 fp_do_op_mem_ST_0 ( addr, "add", dis_buf, Iop_AddF64, True );
5790 break;
5791
5792 case 1: /* FMUL double-real */
5793 fp_do_op_mem_ST_0 ( addr, "mul", dis_buf, Iop_MulF64, True );
5794 break;
5795
sewardjd20c8852005-01-20 20:04:07 +00005796//.. case 2: /* FCOM double-real */
5797//.. DIP("fcoml %s\n", dis_buf);
5798//.. /* This forces C1 to zero, which isn't right. */
5799//.. put_C3210(
5800//.. binop( Iop_And32,
5801//.. binop(Iop_Shl32,
5802//.. binop(Iop_CmpF64,
5803//.. get_ST(0),
5804//.. loadLE(Ity_F64,mkexpr(addr))),
5805//.. mkU8(8)),
5806//.. mkU32(0x4500)
5807//.. ));
5808//.. break;
sewardj566d2c72005-08-10 11:43:42 +00005809
5810 case 3: /* FCOMP double-real */
5811 DIP("fcompl %s\n", dis_buf);
5812 /* This forces C1 to zero, which isn't right. */
5813 put_C3210(
5814 unop(Iop_32Uto64,
5815 binop( Iop_And32,
5816 binop(Iop_Shl32,
5817 binop(Iop_CmpF64,
5818 get_ST(0),
5819 loadLE(Ity_F64,mkexpr(addr))),
5820 mkU8(8)),
5821 mkU32(0x4500)
5822 )));
5823 fp_pop();
5824 break;
sewardje6939f02005-05-07 01:01:24 +00005825
5826 case 4: /* FSUB double-real */
5827 fp_do_op_mem_ST_0 ( addr, "sub", dis_buf, Iop_SubF64, True );
5828 break;
sewardj434e0692005-03-27 17:36:08 +00005829
5830 case 5: /* FSUBR double-real */
5831 fp_do_oprev_mem_ST_0 ( addr, "subr", dis_buf, Iop_SubF64, True );
5832 break;
5833
sewardje6939f02005-05-07 01:01:24 +00005834 case 6: /* FDIV double-real */
5835 fp_do_op_mem_ST_0 ( addr, "div", dis_buf, Iop_DivF64, True );
5836 break;
5837
5838 case 7: /* FDIVR double-real */
5839 fp_do_oprev_mem_ST_0 ( addr, "divr", dis_buf, Iop_DivF64, True );
5840 break;
sewardj434e0692005-03-27 17:36:08 +00005841
5842 default:
5843 vex_printf("unhandled opc_aux = 0x%2x\n", gregLO3ofRM(modrm));
5844 vex_printf("first_opcode == 0xDC\n");
5845 goto decode_fail;
5846 }
sewardj137015d2005-03-27 04:01:15 +00005847
5848 } else {
5849
5850 delta++;
5851 switch (modrm) {
5852
5853 case 0xC0 ... 0xC7: /* FADD %st(0),%st(?) */
5854 fp_do_op_ST_ST ( "add", Iop_AddF64, 0, modrm - 0xC0, False );
5855 break;
5856
sewardj7bc00082005-03-27 05:08:32 +00005857 case 0xC8 ... 0xCF: /* FMUL %st(0),%st(?) */
5858 fp_do_op_ST_ST ( "mul", Iop_MulF64, 0, modrm - 0xC8, False );
5859 break;
5860
sewardj434e0692005-03-27 17:36:08 +00005861 case 0xE0 ... 0xE7: /* FSUBR %st(0),%st(?) */
5862 fp_do_oprev_ST_ST ( "subr", Iop_SubF64, 0, modrm - 0xE0, False );
5863 break;
5864
sewardje6939f02005-05-07 01:01:24 +00005865 case 0xE8 ... 0xEF: /* FSUB %st(0),%st(?) */
5866 fp_do_op_ST_ST ( "sub", Iop_SubF64, 0, modrm - 0xE8, False );
5867 break;
5868
5869 case 0xF0 ... 0xF7: /* FDIVR %st(0),%st(?) */
5870 fp_do_oprev_ST_ST ( "divr", Iop_DivF64, 0, modrm - 0xF0, False );
5871 break;
sewardj137015d2005-03-27 04:01:15 +00005872
5873 case 0xF8 ... 0xFF: /* FDIV %st(0),%st(?) */
5874 fp_do_op_ST_ST ( "div", Iop_DivF64, 0, modrm - 0xF8, False );
5875 break;
5876
5877 default:
5878 goto decode_fail;
5879 }
5880
5881 }
5882 }
sewardj8d965312005-02-25 02:48:47 +00005883
5884 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDD opcodes +-+-+-+-+-+-+-+ */
5885 else
5886 if (first_opcode == 0xDD) {
5887
5888 if (modrm < 0xC0) {
5889
5890 /* bits 5,4,3 are an opcode extension, and the modRM also
5891 specifies an address. */
sewardj2e28ac42008-12-04 00:05:12 +00005892 IRTemp addr = disAMode( &len, vbi, pfx, delta, dis_buf, 0 );
sewardj8d965312005-02-25 02:48:47 +00005893 delta += len;
5894
sewardj901ed122005-02-27 13:25:31 +00005895 switch (gregLO3ofRM(modrm)) {
sewardj8d965312005-02-25 02:48:47 +00005896
5897 case 0: /* FLD double-real */
5898 DIP("fldl %s\n", dis_buf);
5899 fp_push();
sewardjaf1ceca2005-06-30 23:31:27 +00005900 put_ST(0, loadLE(Ity_F64, mkexpr(addr)));
sewardj8d965312005-02-25 02:48:47 +00005901 break;
5902
sewardjfcf21f32006-08-04 14:51:19 +00005903 case 1: /* FISTTPQ m64 (SSE3) */
5904 DIP("fistppll %s\n", dis_buf);
5905 storeLE( mkexpr(addr),
sewardj6c299f32009-12-31 18:00:12 +00005906 binop(Iop_F64toI64S, mkU32(Irrm_ZERO), get_ST(0)) );
sewardjfcf21f32006-08-04 14:51:19 +00005907 fp_pop();
5908 break;
5909
sewardjc49ce232005-02-25 13:03:03 +00005910 case 2: /* FST double-real */
5911 DIP("fstl %s\n", dis_buf);
5912 storeLE(mkexpr(addr), get_ST(0));
5913 break;
sewardj8d965312005-02-25 02:48:47 +00005914
5915 case 3: /* FSTP double-real */
5916 DIP("fstpl %s\n", dis_buf);
5917 storeLE(mkexpr(addr), get_ST(0));
5918 fp_pop();
5919 break;
5920
sewardjd20c8852005-01-20 20:04:07 +00005921//.. case 4: { /* FRSTOR m108 */
5922//.. /* Uses dirty helper:
5923//.. VexEmWarn x86g_do_FRSTOR ( VexGuestX86State*, Addr32 ) */
5924//.. IRTemp ew = newTemp(Ity_I32);
5925//.. IRDirty* d = unsafeIRDirty_0_N (
5926//.. 0/*regparms*/,
5927//.. "x86g_dirtyhelper_FRSTOR",
5928//.. &x86g_dirtyhelper_FRSTOR,
5929//.. mkIRExprVec_1( mkexpr(addr) )
5930//.. );
5931//.. d->needsBBP = True;
5932//.. d->tmp = ew;
5933//.. /* declare we're reading memory */
5934//.. d->mFx = Ifx_Read;
5935//.. d->mAddr = mkexpr(addr);
5936//.. d->mSize = 108;
5937//..
5938//.. /* declare we're writing guest state */
5939//.. d->nFxState = 5;
5940//..
5941//.. d->fxState[0].fx = Ifx_Write;
5942//.. d->fxState[0].offset = OFFB_FTOP;
5943//.. d->fxState[0].size = sizeof(UInt);
5944//..
5945//.. d->fxState[1].fx = Ifx_Write;
5946//.. d->fxState[1].offset = OFFB_FPREGS;
5947//.. d->fxState[1].size = 8 * sizeof(ULong);
5948//..
5949//.. d->fxState[2].fx = Ifx_Write;
5950//.. d->fxState[2].offset = OFFB_FPTAGS;
5951//.. d->fxState[2].size = 8 * sizeof(UChar);
5952//..
5953//.. d->fxState[3].fx = Ifx_Write;
5954//.. d->fxState[3].offset = OFFB_FPROUND;
5955//.. d->fxState[3].size = sizeof(UInt);
5956//..
5957//.. d->fxState[4].fx = Ifx_Write;
5958//.. d->fxState[4].offset = OFFB_FC3210;
5959//.. d->fxState[4].size = sizeof(UInt);
5960//..
5961//.. stmt( IRStmt_Dirty(d) );
5962//..
5963//.. /* ew contains any emulation warning we may need to
5964//.. issue. If needed, side-exit to the next insn,
5965//.. reporting the warning, so that Valgrind's dispatcher
5966//.. sees the warning. */
5967//.. put_emwarn( mkexpr(ew) );
5968//.. stmt(
5969//.. IRStmt_Exit(
5970//.. binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
5971//.. Ijk_EmWarn,
5972//.. IRConst_U32( ((Addr32)guest_eip_bbstart)+delta)
5973//.. )
5974//.. );
5975//..
5976//.. DIP("frstor %s\n", dis_buf);
5977//.. break;
5978//.. }
5979//..
5980//.. case 6: { /* FNSAVE m108 */
5981//.. /* Uses dirty helper:
5982//.. void x86g_do_FSAVE ( VexGuestX86State*, UInt ) */
5983//.. IRDirty* d = unsafeIRDirty_0_N (
5984//.. 0/*regparms*/,
5985//.. "x86g_dirtyhelper_FSAVE",
5986//.. &x86g_dirtyhelper_FSAVE,
5987//.. mkIRExprVec_1( mkexpr(addr) )
5988//.. );
5989//.. d->needsBBP = True;
5990//.. /* declare we're writing memory */
5991//.. d->mFx = Ifx_Write;
5992//.. d->mAddr = mkexpr(addr);
5993//.. d->mSize = 108;
5994//..
5995//.. /* declare we're reading guest state */
5996//.. d->nFxState = 5;
5997//..
5998//.. d->fxState[0].fx = Ifx_Read;
5999//.. d->fxState[0].offset = OFFB_FTOP;
6000//.. d->fxState[0].size = sizeof(UInt);
6001//..
6002//.. d->fxState[1].fx = Ifx_Read;
6003//.. d->fxState[1].offset = OFFB_FPREGS;
6004//.. d->fxState[1].size = 8 * sizeof(ULong);
6005//..
6006//.. d->fxState[2].fx = Ifx_Read;
6007//.. d->fxState[2].offset = OFFB_FPTAGS;
6008//.. d->fxState[2].size = 8 * sizeof(UChar);
6009//..
6010//.. d->fxState[3].fx = Ifx_Read;
6011//.. d->fxState[3].offset = OFFB_FPROUND;
6012//.. d->fxState[3].size = sizeof(UInt);
6013//..
6014//.. d->fxState[4].fx = Ifx_Read;
6015//.. d->fxState[4].offset = OFFB_FC3210;
6016//.. d->fxState[4].size = sizeof(UInt);
6017//..
6018//.. stmt( IRStmt_Dirty(d) );
6019//..
6020//.. DIP("fnsave %s\n", dis_buf);
6021//.. break;
6022//.. }
sewardj8d965312005-02-25 02:48:47 +00006023
sewardj7c2d2822006-03-07 00:22:02 +00006024 case 7: { /* FNSTSW m16 */
6025 IRExpr* sw = get_FPU_sw();
sewardjdd40fdf2006-12-24 02:20:24 +00006026 vassert(typeOfIRExpr(irsb->tyenv, sw) == Ity_I16);
sewardj7c2d2822006-03-07 00:22:02 +00006027 storeLE( mkexpr(addr), sw );
6028 DIP("fnstsw %s\n", dis_buf);
6029 break;
6030 }
6031
sewardj8d965312005-02-25 02:48:47 +00006032 default:
sewardj901ed122005-02-27 13:25:31 +00006033 vex_printf("unhandled opc_aux = 0x%2x\n", gregLO3ofRM(modrm));
sewardj8d965312005-02-25 02:48:47 +00006034 vex_printf("first_opcode == 0xDD\n");
6035 goto decode_fail;
6036 }
6037 } else {
6038 delta++;
6039 switch (modrm) {
6040
sewardj6847d8c2005-05-12 19:21:55 +00006041 case 0xC0 ... 0xC7: /* FFREE %st(?) */
6042 r_dst = (UInt)modrm - 0xC0;
6043 DIP("ffree %%st(%u)\n", r_dst);
6044 put_ST_TAG ( r_dst, mkU8(0) );
6045 break;
6046
sewardjbfabcc42005-08-08 09:58:05 +00006047 case 0xD0 ... 0xD7: /* FST %st(0),%st(?) */
6048 r_dst = (UInt)modrm - 0xD0;
sewardjc7cd2142005-09-09 22:31:49 +00006049 DIP("fst %%st(0),%%st(%u)\n", r_dst);
sewardjbfabcc42005-08-08 09:58:05 +00006050 /* P4 manual says: "If the destination operand is a
6051 non-empty register, the invalid-operation exception
6052 is not generated. Hence put_ST_UNCHECKED. */
6053 put_ST_UNCHECKED(r_dst, get_ST(0));
6054 break;
sewardj8d965312005-02-25 02:48:47 +00006055
6056 case 0xD8 ... 0xDF: /* FSTP %st(0),%st(?) */
6057 r_dst = (UInt)modrm - 0xD8;
sewardj1027dc22005-02-26 01:55:02 +00006058 DIP("fstp %%st(0),%%st(%u)\n", r_dst);
sewardj8d965312005-02-25 02:48:47 +00006059 /* P4 manual says: "If the destination operand is a
6060 non-empty register, the invalid-operation exception
6061 is not generated. Hence put_ST_UNCHECKED. */
6062 put_ST_UNCHECKED(r_dst, get_ST(0));
6063 fp_pop();
6064 break;
6065
sewardjfb6c1792005-10-05 17:58:32 +00006066 case 0xE0 ... 0xE7: /* FUCOM %st(0),%st(?) */
6067 r_dst = (UInt)modrm - 0xE0;
sewardj62d05432005-10-29 22:30:47 +00006068 DIP("fucom %%st(0),%%st(%u)\n", r_dst);
sewardjfb6c1792005-10-05 17:58:32 +00006069 /* This forces C1 to zero, which isn't right. */
6070 put_C3210(
6071 unop(Iop_32Uto64,
6072 binop( Iop_And32,
6073 binop(Iop_Shl32,
6074 binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
6075 mkU8(8)),
6076 mkU32(0x4500)
6077 )));
6078 break;
6079
sewardj9fb2f472005-11-05 01:12:18 +00006080 case 0xE8 ... 0xEF: /* FUCOMP %st(0),%st(?) */
6081 r_dst = (UInt)modrm - 0xE8;
sewardj43f45732005-11-05 13:04:34 +00006082 DIP("fucomp %%st(0),%%st(%u)\n", r_dst);
sewardj9fb2f472005-11-05 01:12:18 +00006083 /* This forces C1 to zero, which isn't right. */
6084 put_C3210(
6085 unop(Iop_32Uto64,
6086 binop( Iop_And32,
6087 binop(Iop_Shl32,
6088 binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
6089 mkU8(8)),
6090 mkU32(0x4500)
6091 )));
6092 fp_pop();
6093 break;
sewardj8d965312005-02-25 02:48:47 +00006094
6095 default:
6096 goto decode_fail;
6097 }
6098 }
6099 }
6100
sewardj137015d2005-03-27 04:01:15 +00006101 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDE opcodes +-+-+-+-+-+-+-+ */
6102 else
6103 if (first_opcode == 0xDE) {
6104
6105 if (modrm < 0xC0) {
6106
sewardj6847d8c2005-05-12 19:21:55 +00006107 /* bits 5,4,3 are an opcode extension, and the modRM also
6108 specifies an address. */
6109 IROp fop;
sewardj2e28ac42008-12-04 00:05:12 +00006110 IRTemp addr = disAMode( &len, vbi, pfx, delta, dis_buf, 0 );
sewardj6847d8c2005-05-12 19:21:55 +00006111 delta += len;
6112
6113 switch (gregLO3ofRM(modrm)) {
6114
6115 case 0: /* FIADD m16int */ /* ST(0) += m16int */
6116 DIP("fiaddw %s\n", dis_buf);
6117 fop = Iop_AddF64;
6118 goto do_fop_m16;
6119
6120 case 1: /* FIMUL m16int */ /* ST(0) *= m16int */
6121 DIP("fimulw %s\n", dis_buf);
6122 fop = Iop_MulF64;
6123 goto do_fop_m16;
6124
6125 case 4: /* FISUB m16int */ /* ST(0) -= m16int */
6126 DIP("fisubw %s\n", dis_buf);
6127 fop = Iop_SubF64;
6128 goto do_fop_m16;
6129
6130 case 5: /* FISUBR m16int */ /* ST(0) = m16int - ST(0) */
6131 DIP("fisubrw %s\n", dis_buf);
6132 fop = Iop_SubF64;
6133 goto do_foprev_m16;
6134
6135 case 6: /* FIDIV m16int */ /* ST(0) /= m16int */
6136 DIP("fisubw %s\n", dis_buf);
6137 fop = Iop_DivF64;
6138 goto do_fop_m16;
6139
6140 case 7: /* FIDIVR m16int */ /* ST(0) = m16int / ST(0) */
6141 DIP("fidivrw %s\n", dis_buf);
6142 fop = Iop_DivF64;
6143 goto do_foprev_m16;
6144
6145 do_fop_m16:
6146 put_ST_UNCHECKED(0,
sewardj4796d662006-02-05 16:06:26 +00006147 triop(fop,
6148 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardj6847d8c2005-05-12 19:21:55 +00006149 get_ST(0),
sewardj6c299f32009-12-31 18:00:12 +00006150 unop(Iop_I32StoF64,
sewardj6847d8c2005-05-12 19:21:55 +00006151 unop(Iop_16Sto32,
6152 loadLE(Ity_I16, mkexpr(addr))))));
6153 break;
6154
6155 do_foprev_m16:
6156 put_ST_UNCHECKED(0,
sewardj4796d662006-02-05 16:06:26 +00006157 triop(fop,
6158 get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
sewardj6c299f32009-12-31 18:00:12 +00006159 unop(Iop_I32StoF64,
sewardj6847d8c2005-05-12 19:21:55 +00006160 unop(Iop_16Sto32,
6161 loadLE(Ity_I16, mkexpr(addr)))),
6162 get_ST(0)));
6163 break;
6164
6165 default:
6166 vex_printf("unhandled opc_aux = 0x%2x\n", gregLO3ofRM(modrm));
6167 vex_printf("first_opcode == 0xDE\n");
6168 goto decode_fail;
6169 }
sewardj137015d2005-03-27 04:01:15 +00006170
6171 } else {
6172
6173 delta++;
6174 switch (modrm) {
6175
6176 case 0xC0 ... 0xC7: /* FADDP %st(0),%st(?) */
6177 fp_do_op_ST_ST ( "add", Iop_AddF64, 0, modrm - 0xC0, True );
6178 break;
6179
6180 case 0xC8 ... 0xCF: /* FMULP %st(0),%st(?) */
6181 fp_do_op_ST_ST ( "mul", Iop_MulF64, 0, modrm - 0xC8, True );
6182 break;
6183
sewardj1859ecd2007-02-23 08:48:22 +00006184 case 0xD9: /* FCOMPP %st(0),%st(1) */
6185 DIP("fcompp %%st(0),%%st(1)\n");
6186 /* This forces C1 to zero, which isn't right. */
6187 put_C3210(
6188 unop(Iop_32Uto64,
6189 binop( Iop_And32,
6190 binop(Iop_Shl32,
6191 binop(Iop_CmpF64, get_ST(0), get_ST(1)),
6192 mkU8(8)),
6193 mkU32(0x4500)
6194 )));
6195 fp_pop();
6196 fp_pop();
6197 break;
sewardj137015d2005-03-27 04:01:15 +00006198
6199 case 0xE0 ... 0xE7: /* FSUBRP %st(0),%st(?) */
6200 fp_do_oprev_ST_ST ( "subr", Iop_SubF64, 0, modrm - 0xE0, True );
6201 break;
6202
6203 case 0xE8 ... 0xEF: /* FSUBP %st(0),%st(?) */
6204 fp_do_op_ST_ST ( "sub", Iop_SubF64, 0, modrm - 0xE8, True );
6205 break;
6206
6207 case 0xF0 ... 0xF7: /* FDIVRP %st(0),%st(?) */
6208 fp_do_oprev_ST_ST ( "divr", Iop_DivF64, 0, modrm - 0xF0, True );
6209 break;
6210
6211 case 0xF8 ... 0xFF: /* FDIVP %st(0),%st(?) */
6212 fp_do_op_ST_ST ( "div", Iop_DivF64, 0, modrm - 0xF8, True );
6213 break;
6214
6215 default:
6216 goto decode_fail;
6217 }
6218
6219 }
6220 }
sewardjc49ce232005-02-25 13:03:03 +00006221
6222 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDF opcodes +-+-+-+-+-+-+-+ */
6223 else
6224 if (first_opcode == 0xDF) {
6225
6226 if (modrm < 0xC0) {
6227
6228 /* bits 5,4,3 are an opcode extension, and the modRM also
6229 specifies an address. */
sewardj2e28ac42008-12-04 00:05:12 +00006230 IRTemp addr = disAMode( &len, vbi, pfx, delta, dis_buf, 0 );
sewardjc49ce232005-02-25 13:03:03 +00006231 delta += len;
6232
sewardj901ed122005-02-27 13:25:31 +00006233 switch (gregLO3ofRM(modrm)) {
sewardjc49ce232005-02-25 13:03:03 +00006234
sewardj434e0692005-03-27 17:36:08 +00006235 case 0: /* FILD m16int */
6236 DIP("fildw %s\n", dis_buf);
6237 fp_push();
sewardj6c299f32009-12-31 18:00:12 +00006238 put_ST(0, unop(Iop_I32StoF64,
sewardj434e0692005-03-27 17:36:08 +00006239 unop(Iop_16Sto32,
6240 loadLE(Ity_I16, mkexpr(addr)))));
6241 break;
6242
sewardjfcf21f32006-08-04 14:51:19 +00006243 case 1: /* FISTTPS m16 (SSE3) */
6244 DIP("fisttps %s\n", dis_buf);
6245 storeLE( mkexpr(addr),
sewardjb707d102007-07-11 22:49:26 +00006246 x87ishly_qnarrow_32_to_16(
sewardj6c299f32009-12-31 18:00:12 +00006247 binop(Iop_F64toI32S, mkU32(Irrm_ZERO), get_ST(0)) ));
sewardjfcf21f32006-08-04 14:51:19 +00006248 fp_pop();
6249 break;
6250
sewardj9f5c8fd2010-05-10 20:08:12 +00006251 case 2: /* FIST m16 */
6252 DIP("fists %s\n", dis_buf);
6253 storeLE( mkexpr(addr),
6254 x87ishly_qnarrow_32_to_16(
6255 binop(Iop_F64toI32S, get_roundingmode(), get_ST(0)) ));
6256 break;
sewardj6847d8c2005-05-12 19:21:55 +00006257
sewardjb707d102007-07-11 22:49:26 +00006258 case 3: /* FISTP m16 */
6259 DIP("fistps %s\n", dis_buf);
6260 storeLE( mkexpr(addr),
6261 x87ishly_qnarrow_32_to_16(
sewardj6c299f32009-12-31 18:00:12 +00006262 binop(Iop_F64toI32S, get_roundingmode(), get_ST(0)) ));
sewardjb707d102007-07-11 22:49:26 +00006263 fp_pop();
6264 break;
sewardj37d52572005-02-25 14:22:12 +00006265
6266 case 5: /* FILD m64 */
6267 DIP("fildll %s\n", dis_buf);
6268 fp_push();
sewardj6c299f32009-12-31 18:00:12 +00006269 put_ST(0, binop(Iop_I64StoF64,
sewardj37d52572005-02-25 14:22:12 +00006270 get_roundingmode(),
6271 loadLE(Ity_I64, mkexpr(addr))));
6272 break;
6273
sewardj6847d8c2005-05-12 19:21:55 +00006274 case 7: /* FISTP m64 */
6275 DIP("fistpll %s\n", dis_buf);
6276 storeLE( mkexpr(addr),
sewardj6c299f32009-12-31 18:00:12 +00006277 binop(Iop_F64toI64S, get_roundingmode(), get_ST(0)) );
sewardj6847d8c2005-05-12 19:21:55 +00006278 fp_pop();
6279 break;
sewardjc49ce232005-02-25 13:03:03 +00006280
6281 default:
sewardj901ed122005-02-27 13:25:31 +00006282 vex_printf("unhandled opc_aux = 0x%2x\n", gregLO3ofRM(modrm));
sewardjc49ce232005-02-25 13:03:03 +00006283 vex_printf("first_opcode == 0xDF\n");
6284 goto decode_fail;
6285 }
6286
6287 } else {
6288
6289 delta++;
6290 switch (modrm) {
6291
6292 case 0xC0: /* FFREEP %st(0) */
6293 DIP("ffreep %%st(%d)\n", 0);
6294 put_ST_TAG ( 0, mkU8(0) );
6295 fp_pop();
6296 break;
6297
sewardj4f9847d2005-07-25 11:58:34 +00006298 case 0xE0: /* FNSTSW %ax */
6299 DIP("fnstsw %%ax\n");
6300 /* Invent a plausible-looking FPU status word value and
6301 dump it in %AX:
6302 ((ftop & 7) << 11) | (c3210 & 0x4700)
6303 */
6304 putIRegRAX(
6305 2,
6306 unop(Iop_32to16,
6307 binop(Iop_Or32,
6308 binop(Iop_Shl32,
6309 binop(Iop_And32, get_ftop(), mkU32(7)),
6310 mkU8(11)),
6311 binop(Iop_And32,
6312 unop(Iop_64to32, get_C3210()),
6313 mkU32(0x4700))
6314 )));
6315 break;
sewardj924215b2005-03-26 21:50:31 +00006316
6317 case 0xE8 ... 0xEF: /* FUCOMIP %st(0),%st(?) */
6318 fp_do_ucomi_ST0_STi( (UInt)modrm - 0xE8, True );
6319 break;
6320
sewardj48a89d82005-05-06 11:50:13 +00006321 case 0xF0 ... 0xF7: /* FCOMIP %st(0),%st(?) */
6322 /* not really right since COMIP != UCOMIP */
6323 fp_do_ucomi_ST0_STi( (UInt)modrm - 0xF0, True );
6324 break;
sewardjc49ce232005-02-25 13:03:03 +00006325
6326 default:
6327 goto decode_fail;
6328 }
6329 }
6330
6331 }
sewardj8d965312005-02-25 02:48:47 +00006332
6333 else
sewardj137015d2005-03-27 04:01:15 +00006334 goto decode_fail;
sewardj8d965312005-02-25 02:48:47 +00006335
6336 *decode_ok = True;
6337 return delta;
6338
6339 decode_fail:
6340 *decode_ok = False;
6341 return delta;
6342}
6343
6344
sewardj8711f662005-05-09 17:52:56 +00006345/*------------------------------------------------------------*/
6346/*--- ---*/
6347/*--- MMX INSTRUCTIONS ---*/
6348/*--- ---*/
6349/*------------------------------------------------------------*/
6350
6351/* Effect of MMX insns on x87 FPU state (table 11-2 of
6352 IA32 arch manual, volume 3):
6353
6354 Read from, or write to MMX register (viz, any insn except EMMS):
6355 * All tags set to Valid (non-empty) -- FPTAGS[i] := nonzero
6356 * FP stack pointer set to zero
6357
6358 EMMS:
6359 * All tags set to Invalid (empty) -- FPTAGS[i] := zero
6360 * FP stack pointer set to zero
6361*/
6362
6363static void do_MMX_preamble ( void )
6364{
sewardjdd40fdf2006-12-24 02:20:24 +00006365 Int i;
6366 IRRegArray* descr = mkIRRegArray( OFFB_FPTAGS, Ity_I8, 8 );
6367 IRExpr* zero = mkU32(0);
6368 IRExpr* tag1 = mkU8(1);
sewardj8711f662005-05-09 17:52:56 +00006369 put_ftop(zero);
6370 for (i = 0; i < 8; i++)
6371 stmt( IRStmt_PutI( descr, zero, i, tag1 ) );
6372}
6373
6374static void do_EMMS_preamble ( void )
6375{
sewardjdd40fdf2006-12-24 02:20:24 +00006376 Int i;
6377 IRRegArray* descr = mkIRRegArray( OFFB_FPTAGS, Ity_I8, 8 );
6378 IRExpr* zero = mkU32(0);
6379 IRExpr* tag0 = mkU8(0);
sewardj8711f662005-05-09 17:52:56 +00006380 put_ftop(zero);
6381 for (i = 0; i < 8; i++)
6382 stmt( IRStmt_PutI( descr, zero, i, tag0 ) );
6383}
6384
6385
6386static IRExpr* getMMXReg ( UInt archreg )
6387{
6388 vassert(archreg < 8);
6389 return IRExpr_Get( OFFB_FPREGS + 8 * archreg, Ity_I64 );
6390}
6391
6392
6393static void putMMXReg ( UInt archreg, IRExpr* e )
6394{
6395 vassert(archreg < 8);
sewardjdd40fdf2006-12-24 02:20:24 +00006396 vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_I64);
sewardj8711f662005-05-09 17:52:56 +00006397 stmt( IRStmt_Put( OFFB_FPREGS + 8 * archreg, e ) );
6398}
6399
6400
6401/* Helper for non-shift MMX insns. Note this is incomplete in the
6402 sense that it does not first call do_MMX_preamble() -- that is the
6403 responsibility of its caller. */
6404
6405static
sewardj2e28ac42008-12-04 00:05:12 +00006406ULong dis_MMXop_regmem_to_reg ( VexAbiInfo* vbi,
6407 Prefix pfx,
6408 Long delta,
6409 UChar opc,
6410 HChar* name,
6411 Bool show_granularity )
sewardj8711f662005-05-09 17:52:56 +00006412{
6413 HChar dis_buf[50];
6414 UChar modrm = getUChar(delta);
6415 Bool isReg = epartIsReg(modrm);
6416 IRExpr* argL = NULL;
6417 IRExpr* argR = NULL;
6418 IRExpr* argG = NULL;
6419 IRExpr* argE = NULL;
6420 IRTemp res = newTemp(Ity_I64);
6421
6422 Bool invG = False;
6423 IROp op = Iop_INVALID;
6424 void* hAddr = NULL;
sewardjca673ab2005-05-11 10:03:08 +00006425 HChar* hName = NULL;
sewardj8711f662005-05-09 17:52:56 +00006426 Bool eLeft = False;
6427
6428# define XXX(_name) do { hAddr = &_name; hName = #_name; } while (0)
6429
6430 switch (opc) {
6431 /* Original MMX ones */
6432 case 0xFC: op = Iop_Add8x8; break;
6433 case 0xFD: op = Iop_Add16x4; break;
6434 case 0xFE: op = Iop_Add32x2; break;
6435
6436 case 0xEC: op = Iop_QAdd8Sx8; break;
6437 case 0xED: op = Iop_QAdd16Sx4; break;
6438
6439 case 0xDC: op = Iop_QAdd8Ux8; break;
6440 case 0xDD: op = Iop_QAdd16Ux4; break;
6441
6442 case 0xF8: op = Iop_Sub8x8; break;
6443 case 0xF9: op = Iop_Sub16x4; break;
6444 case 0xFA: op = Iop_Sub32x2; break;
6445
6446 case 0xE8: op = Iop_QSub8Sx8; break;
6447 case 0xE9: op = Iop_QSub16Sx4; break;
6448
6449 case 0xD8: op = Iop_QSub8Ux8; break;
6450 case 0xD9: op = Iop_QSub16Ux4; break;
6451
6452 case 0xE5: op = Iop_MulHi16Sx4; break;
6453 case 0xD5: op = Iop_Mul16x4; break;
6454 case 0xF5: XXX(amd64g_calculate_mmx_pmaddwd); break;
6455
6456 case 0x74: op = Iop_CmpEQ8x8; break;
6457 case 0x75: op = Iop_CmpEQ16x4; break;
6458 case 0x76: op = Iop_CmpEQ32x2; break;
6459
6460 case 0x64: op = Iop_CmpGT8Sx8; break;
6461 case 0x65: op = Iop_CmpGT16Sx4; break;
6462 case 0x66: op = Iop_CmpGT32Sx2; break;
6463
6464 case 0x6B: op = Iop_QNarrow32Sx2; eLeft = True; break;
6465 case 0x63: op = Iop_QNarrow16Sx4; eLeft = True; break;
6466 case 0x67: op = Iop_QNarrow16Ux4; eLeft = True; break;
6467
6468 case 0x68: op = Iop_InterleaveHI8x8; eLeft = True; break;
6469 case 0x69: op = Iop_InterleaveHI16x4; eLeft = True; break;
6470 case 0x6A: op = Iop_InterleaveHI32x2; eLeft = True; break;
6471
6472 case 0x60: op = Iop_InterleaveLO8x8; eLeft = True; break;
6473 case 0x61: op = Iop_InterleaveLO16x4; eLeft = True; break;
6474 case 0x62: op = Iop_InterleaveLO32x2; eLeft = True; break;
6475
6476 case 0xDB: op = Iop_And64; break;
6477 case 0xDF: op = Iop_And64; invG = True; break;
6478 case 0xEB: op = Iop_Or64; break;
6479 case 0xEF: /* Possibly do better here if argL and argR are the
6480 same reg */
6481 op = Iop_Xor64; break;
6482
6483 /* Introduced in SSE1 */
6484 case 0xE0: op = Iop_Avg8Ux8; break;
6485 case 0xE3: op = Iop_Avg16Ux4; break;
6486 case 0xEE: op = Iop_Max16Sx4; break;
6487 case 0xDE: op = Iop_Max8Ux8; break;
6488 case 0xEA: op = Iop_Min16Sx4; break;
6489 case 0xDA: op = Iop_Min8Ux8; break;
6490 case 0xE4: op = Iop_MulHi16Ux4; break;
sewardja7ba8c42005-05-10 20:08:34 +00006491 case 0xF6: XXX(amd64g_calculate_mmx_psadbw); break;
sewardj8711f662005-05-09 17:52:56 +00006492
6493 /* Introduced in SSE2 */
6494 case 0xD4: op = Iop_Add64; break;
6495 case 0xFB: op = Iop_Sub64; break;
6496
6497 default:
6498 vex_printf("\n0x%x\n", (Int)opc);
6499 vpanic("dis_MMXop_regmem_to_reg");
6500 }
6501
6502# undef XXX
6503
6504 argG = getMMXReg(gregLO3ofRM(modrm));
6505 if (invG)
6506 argG = unop(Iop_Not64, argG);
6507
6508 if (isReg) {
6509 delta++;
6510 argE = getMMXReg(eregLO3ofRM(modrm));
6511 } else {
6512 Int len;
sewardj2e28ac42008-12-04 00:05:12 +00006513 IRTemp addr = disAMode( &len, vbi, pfx, delta, dis_buf, 0 );
sewardj8711f662005-05-09 17:52:56 +00006514 delta += len;
6515 argE = loadLE(Ity_I64, mkexpr(addr));
6516 }
6517
6518 if (eLeft) {
6519 argL = argE;
6520 argR = argG;
6521 } else {
6522 argL = argG;
6523 argR = argE;
6524 }
6525
6526 if (op != Iop_INVALID) {
6527 vassert(hName == NULL);
6528 vassert(hAddr == NULL);
6529 assign(res, binop(op, argL, argR));
6530 } else {
6531 vassert(hName != NULL);
6532 vassert(hAddr != NULL);
6533 assign( res,
6534 mkIRExprCCall(
6535 Ity_I64,
6536 0/*regparms*/, hName, hAddr,
6537 mkIRExprVec_2( argL, argR )
6538 )
6539 );
6540 }
6541
6542 putMMXReg( gregLO3ofRM(modrm), mkexpr(res) );
6543
6544 DIP("%s%s %s, %s\n",
6545 name, show_granularity ? nameMMXGran(opc & 3) : "",
6546 ( isReg ? nameMMXReg(eregLO3ofRM(modrm)) : dis_buf ),
6547 nameMMXReg(gregLO3ofRM(modrm)) );
6548
6549 return delta;
6550}
6551
6552
6553/* Vector by scalar shift of G by the amount specified at the bottom
6554 of E. This is a straight copy of dis_SSE_shiftG_byE. */
6555
sewardj2e28ac42008-12-04 00:05:12 +00006556static ULong dis_MMX_shiftG_byE ( VexAbiInfo* vbi,
6557 Prefix pfx, Long delta,
sewardj8711f662005-05-09 17:52:56 +00006558 HChar* opname, IROp op )
6559{
6560 HChar dis_buf[50];
6561 Int alen, size;
6562 IRTemp addr;
6563 Bool shl, shr, sar;
6564 UChar rm = getUChar(delta);
6565 IRTemp g0 = newTemp(Ity_I64);
6566 IRTemp g1 = newTemp(Ity_I64);
6567 IRTemp amt = newTemp(Ity_I64);
6568 IRTemp amt8 = newTemp(Ity_I8);
6569
6570 if (epartIsReg(rm)) {
6571 assign( amt, getMMXReg(eregLO3ofRM(rm)) );
6572 DIP("%s %s,%s\n", opname,
6573 nameMMXReg(eregLO3ofRM(rm)),
6574 nameMMXReg(gregLO3ofRM(rm)) );
6575 delta++;
6576 } else {
sewardj2e28ac42008-12-04 00:05:12 +00006577 addr = disAMode ( &alen, vbi, pfx, delta, dis_buf, 0 );
sewardj8711f662005-05-09 17:52:56 +00006578 assign( amt, loadLE(Ity_I64, mkexpr(addr)) );
6579 DIP("%s %s,%s\n", opname,
6580 dis_buf,
6581 nameMMXReg(gregLO3ofRM(rm)) );
6582 delta += alen;
6583 }
6584 assign( g0, getMMXReg(gregLO3ofRM(rm)) );
6585 assign( amt8, unop(Iop_64to8, mkexpr(amt)) );
6586
6587 shl = shr = sar = False;
6588 size = 0;
6589 switch (op) {
6590 case Iop_ShlN16x4: shl = True; size = 32; break;
6591 case Iop_ShlN32x2: shl = True; size = 32; break;
6592 case Iop_Shl64: shl = True; size = 64; break;
6593 case Iop_ShrN16x4: shr = True; size = 16; break;
6594 case Iop_ShrN32x2: shr = True; size = 32; break;
6595 case Iop_Shr64: shr = True; size = 64; break;
6596 case Iop_SarN16x4: sar = True; size = 16; break;
6597 case Iop_SarN32x2: sar = True; size = 32; break;
6598 default: vassert(0);
6599 }
6600
6601 if (shl || shr) {
6602 assign(
6603 g1,
6604 IRExpr_Mux0X(
6605 unop(Iop_1Uto8,binop(Iop_CmpLT64U,mkexpr(amt),mkU64(size))),
6606 mkU64(0),
6607 binop(op, mkexpr(g0), mkexpr(amt8))
6608 )
6609 );
6610 } else
6611 if (sar) {
6612 assign(
6613 g1,
6614 IRExpr_Mux0X(
6615 unop(Iop_1Uto8,binop(Iop_CmpLT64U,mkexpr(amt),mkU64(size))),
6616 binop(op, mkexpr(g0), mkU8(size-1)),
6617 binop(op, mkexpr(g0), mkexpr(amt8))
6618 )
6619 );
6620 } else {
6621 vassert(0);
6622 }
6623
6624 putMMXReg( gregLO3ofRM(rm), mkexpr(g1) );
6625 return delta;
6626}
6627
6628
sewardj3d8107c2005-05-09 22:23:38 +00006629/* Vector by scalar shift of E by an immediate byte. This is a
6630 straight copy of dis_SSE_shiftE_imm. */
6631
6632static
sewardj270def42005-07-03 01:03:01 +00006633ULong dis_MMX_shiftE_imm ( Long delta, HChar* opname, IROp op )
sewardj3d8107c2005-05-09 22:23:38 +00006634{
6635 Bool shl, shr, sar;
6636 UChar rm = getUChar(delta);
6637 IRTemp e0 = newTemp(Ity_I64);
6638 IRTemp e1 = newTemp(Ity_I64);
6639 UChar amt, size;
6640 vassert(epartIsReg(rm));
6641 vassert(gregLO3ofRM(rm) == 2
6642 || gregLO3ofRM(rm) == 4 || gregLO3ofRM(rm) == 6);
sewardjca673ab2005-05-11 10:03:08 +00006643 amt = getUChar(delta+1);
sewardj3d8107c2005-05-09 22:23:38 +00006644 delta += 2;
6645 DIP("%s $%d,%s\n", opname,
6646 (Int)amt,
6647 nameMMXReg(eregLO3ofRM(rm)) );
6648
6649 assign( e0, getMMXReg(eregLO3ofRM(rm)) );
6650
6651 shl = shr = sar = False;
6652 size = 0;
6653 switch (op) {
6654 case Iop_ShlN16x4: shl = True; size = 16; break;
6655 case Iop_ShlN32x2: shl = True; size = 32; break;
6656 case Iop_Shl64: shl = True; size = 64; break;
6657 case Iop_SarN16x4: sar = True; size = 16; break;
6658 case Iop_SarN32x2: sar = True; size = 32; break;
6659 case Iop_ShrN16x4: shr = True; size = 16; break;
6660 case Iop_ShrN32x2: shr = True; size = 32; break;
6661 case Iop_Shr64: shr = True; size = 64; break;
6662 default: vassert(0);
6663 }
6664
6665 if (shl || shr) {
6666 assign( e1, amt >= size
6667 ? mkU64(0)
6668 : binop(op, mkexpr(e0), mkU8(amt))
6669 );
6670 } else
6671 if (sar) {
6672 assign( e1, amt >= size
6673 ? binop(op, mkexpr(e0), mkU8(size-1))
6674 : binop(op, mkexpr(e0), mkU8(amt))
6675 );
6676 } else {
6677 vassert(0);
6678 }
6679
6680 putMMXReg( eregLO3ofRM(rm), mkexpr(e1) );
6681 return delta;
6682}
sewardj8711f662005-05-09 17:52:56 +00006683
6684
6685/* Completely handle all MMX instructions except emms. */
6686
6687static
sewardj2e28ac42008-12-04 00:05:12 +00006688ULong dis_MMX ( Bool* decode_ok,
6689 VexAbiInfo* vbi, Prefix pfx, Int sz, Long delta )
sewardj8711f662005-05-09 17:52:56 +00006690{
6691 Int len;
6692 UChar modrm;
6693 HChar dis_buf[50];
6694 UChar opc = getUChar(delta);
6695 delta++;
6696
6697 /* dis_MMX handles all insns except emms. */
6698 do_MMX_preamble();
6699
6700 switch (opc) {
6701
sewardj3d8107c2005-05-09 22:23:38 +00006702 case 0x6E:
6703 if (sz == 4) {
6704 /* MOVD (src)ireg32-or-mem32 (E), (dst)mmxreg (G)*/
6705 modrm = getUChar(delta);
6706 if (epartIsReg(modrm)) {
6707 delta++;
6708 putMMXReg(
6709 gregLO3ofRM(modrm),
6710 binop( Iop_32HLto64,
6711 mkU32(0),
6712 getIReg32(eregOfRexRM(pfx,modrm)) ) );
6713 DIP("movd %s, %s\n",
6714 nameIReg32(eregOfRexRM(pfx,modrm)),
6715 nameMMXReg(gregLO3ofRM(modrm)));
6716 } else {
sewardj2e28ac42008-12-04 00:05:12 +00006717 IRTemp addr = disAMode( &len, vbi, pfx, delta, dis_buf, 0 );
sewardj3d8107c2005-05-09 22:23:38 +00006718 delta += len;
6719 putMMXReg(
6720 gregLO3ofRM(modrm),
6721 binop( Iop_32HLto64,
6722 mkU32(0),
6723 loadLE(Ity_I32, mkexpr(addr)) ) );
6724 DIP("movd %s, %s\n", dis_buf, nameMMXReg(gregLO3ofRM(modrm)));
6725 }
6726 }
6727 else
6728 if (sz == 8) {
6729 /* MOVD (src)ireg64-or-mem64 (E), (dst)mmxreg (G)*/
6730 modrm = getUChar(delta);
6731 if (epartIsReg(modrm)) {
6732 delta++;
6733 putMMXReg( gregLO3ofRM(modrm),
6734 getIReg64(eregOfRexRM(pfx,modrm)) );
6735 DIP("movd %s, %s\n",
6736 nameIReg64(eregOfRexRM(pfx,modrm)),
6737 nameMMXReg(gregLO3ofRM(modrm)));
6738 } else {
sewardj2e28ac42008-12-04 00:05:12 +00006739 IRTemp addr = disAMode( &len, vbi, pfx, delta, dis_buf, 0 );
sewardj3d8107c2005-05-09 22:23:38 +00006740 delta += len;
6741 putMMXReg( gregLO3ofRM(modrm),
6742 loadLE(Ity_I64, mkexpr(addr)) );
6743 DIP("movd{64} %s, %s\n", dis_buf, nameMMXReg(gregLO3ofRM(modrm)));
6744 }
6745 }
6746 else {
6747 goto mmx_decode_failure;
6748 }
6749 break;
6750
6751 case 0x7E:
6752 if (sz == 4) {
6753 /* MOVD (src)mmxreg (G), (dst)ireg32-or-mem32 (E) */
6754 modrm = getUChar(delta);
6755 if (epartIsReg(modrm)) {
6756 delta++;
6757 putIReg32( eregOfRexRM(pfx,modrm),
6758 unop(Iop_64to32, getMMXReg(gregLO3ofRM(modrm)) ) );
6759 DIP("movd %s, %s\n",
6760 nameMMXReg(gregLO3ofRM(modrm)),
6761 nameIReg32(eregOfRexRM(pfx,modrm)));
6762 } else {
sewardj2e28ac42008-12-04 00:05:12 +00006763 IRTemp addr = disAMode( &len, vbi, pfx, delta, dis_buf, 0 );
sewardj3d8107c2005-05-09 22:23:38 +00006764 delta += len;
6765 storeLE( mkexpr(addr),
6766 unop(Iop_64to32, getMMXReg(gregLO3ofRM(modrm)) ) );
6767 DIP("movd %s, %s\n", nameMMXReg(gregLO3ofRM(modrm)), dis_buf);
6768 }
6769 }
6770 else
6771 if (sz == 8) {
6772 /* MOVD (src)mmxreg (G), (dst)ireg64-or-mem64 (E) */
6773 modrm = getUChar(delta);
6774 if (epartIsReg(modrm)) {
6775 delta++;
6776 putIReg64( eregOfRexRM(pfx,modrm),
6777 getMMXReg(gregLO3ofRM(modrm)) );
6778 DIP("movd %s, %s\n",
6779 nameMMXReg(gregLO3ofRM(modrm)),
6780 nameIReg64(eregOfRexRM(pfx,modrm)));
6781 } else {
sewardj2e28ac42008-12-04 00:05:12 +00006782 IRTemp addr = disAMode( &len, vbi, pfx, delta, dis_buf, 0 );
sewardj3d8107c2005-05-09 22:23:38 +00006783 delta += len;
6784 storeLE( mkexpr(addr),
6785 getMMXReg(gregLO3ofRM(modrm)) );
6786 DIP("movd{64} %s, %s\n", nameMMXReg(gregLO3ofRM(modrm)), dis_buf);
6787 }
6788 } else {
6789 goto mmx_decode_failure;
6790 }
6791 break;
sewardj8711f662005-05-09 17:52:56 +00006792
6793 case 0x6F:
6794 /* MOVQ (src)mmxreg-or-mem, (dst)mmxreg */
sewardj7bdd1bc2008-12-13 16:49:46 +00006795 if (sz != 4
6796 && /*ignore redundant REX.W*/!(sz==8 && haveNo66noF2noF3(pfx)))
sewardj8711f662005-05-09 17:52:56 +00006797 goto mmx_decode_failure;
6798 modrm = getUChar(delta);
6799 if (epartIsReg(modrm)) {
6800 delta++;
6801 putMMXReg( gregLO3ofRM(modrm), getMMXReg(eregLO3ofRM(modrm)) );
6802 DIP("movq %s, %s\n",
6803 nameMMXReg(eregLO3ofRM(modrm)),
6804 nameMMXReg(gregLO3ofRM(modrm)));
6805 } else {
sewardj2e28ac42008-12-04 00:05:12 +00006806 IRTemp addr = disAMode( &len, vbi, pfx, delta, dis_buf, 0 );
sewardj8711f662005-05-09 17:52:56 +00006807 delta += len;
6808 putMMXReg( gregLO3ofRM(modrm), loadLE(Ity_I64, mkexpr(addr)) );
6809 DIP("movq %s, %s\n",
6810 dis_buf, nameMMXReg(gregLO3ofRM(modrm)));
6811 }
6812 break;
6813
6814 case 0x7F:
6815 /* MOVQ (src)mmxreg, (dst)mmxreg-or-mem */
sewardj7bdd1bc2008-12-13 16:49:46 +00006816 if (sz != 4
6817 && /*ignore redundant REX.W*/!(sz==8 && haveNo66noF2noF3(pfx)))
sewardj8711f662005-05-09 17:52:56 +00006818 goto mmx_decode_failure;
6819 modrm = getUChar(delta);
6820 if (epartIsReg(modrm)) {
6821 /* Fall through. The assembler doesn't appear to generate
6822 these. */
6823 goto mmx_decode_failure;
6824 } else {
sewardj2e28ac42008-12-04 00:05:12 +00006825 IRTemp addr = disAMode( &len, vbi, pfx, delta, dis_buf, 0 );
sewardj8711f662005-05-09 17:52:56 +00006826 delta += len;
6827 storeLE( mkexpr(addr), getMMXReg(gregLO3ofRM(modrm)) );
6828 DIP("mov(nt)q %s, %s\n",
6829 nameMMXReg(gregLO3ofRM(modrm)), dis_buf);
6830 }
6831 break;
6832
6833 case 0xFC:
6834 case 0xFD:
6835 case 0xFE: /* PADDgg (src)mmxreg-or-mem, (dst)mmxreg */
6836 if (sz != 4)
6837 goto mmx_decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +00006838 delta = dis_MMXop_regmem_to_reg ( vbi, pfx, delta, opc, "padd", True );
sewardj8711f662005-05-09 17:52:56 +00006839 break;
6840
6841 case 0xEC:
6842 case 0xED: /* PADDSgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj7bdd1bc2008-12-13 16:49:46 +00006843 if (sz != 4
6844 && /*ignore redundant REX.W*/!(sz==8 && haveNo66noF2noF3(pfx)))
sewardj8711f662005-05-09 17:52:56 +00006845 goto mmx_decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +00006846 delta = dis_MMXop_regmem_to_reg ( vbi, pfx, delta, opc, "padds", True );
sewardj8711f662005-05-09 17:52:56 +00006847 break;
6848
6849 case 0xDC:
6850 case 0xDD: /* PADDUSgg (src)mmxreg-or-mem, (dst)mmxreg */
6851 if (sz != 4)
6852 goto mmx_decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +00006853 delta = dis_MMXop_regmem_to_reg ( vbi, pfx, delta, opc, "paddus", True );
sewardj8711f662005-05-09 17:52:56 +00006854 break;
6855
6856 case 0xF8:
6857 case 0xF9:
6858 case 0xFA: /* PSUBgg (src)mmxreg-or-mem, (dst)mmxreg */
6859 if (sz != 4)
6860 goto mmx_decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +00006861 delta = dis_MMXop_regmem_to_reg ( vbi, pfx, delta, opc, "psub", True );
sewardj8711f662005-05-09 17:52:56 +00006862 break;
6863
6864 case 0xE8:
6865 case 0xE9: /* PSUBSgg (src)mmxreg-or-mem, (dst)mmxreg */
6866 if (sz != 4)
6867 goto mmx_decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +00006868 delta = dis_MMXop_regmem_to_reg ( vbi, pfx, delta, opc, "psubs", True );
sewardj8711f662005-05-09 17:52:56 +00006869 break;
6870
6871 case 0xD8:
6872 case 0xD9: /* PSUBUSgg (src)mmxreg-or-mem, (dst)mmxreg */
6873 if (sz != 4)
6874 goto mmx_decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +00006875 delta = dis_MMXop_regmem_to_reg ( vbi, pfx, delta, opc, "psubus", True );
sewardj8711f662005-05-09 17:52:56 +00006876 break;
6877
6878 case 0xE5: /* PMULHW (src)mmxreg-or-mem, (dst)mmxreg */
6879 if (sz != 4)
6880 goto mmx_decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +00006881 delta = dis_MMXop_regmem_to_reg ( vbi, pfx, delta, opc, "pmulhw", False );
sewardj8711f662005-05-09 17:52:56 +00006882 break;
6883
6884 case 0xD5: /* PMULLW (src)mmxreg-or-mem, (dst)mmxreg */
6885 if (sz != 4)
6886 goto mmx_decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +00006887 delta = dis_MMXop_regmem_to_reg ( vbi, pfx, delta, opc, "pmullw", False );
sewardj8711f662005-05-09 17:52:56 +00006888 break;
6889
6890 case 0xF5: /* PMADDWD (src)mmxreg-or-mem, (dst)mmxreg */
6891 vassert(sz == 4);
sewardj2e28ac42008-12-04 00:05:12 +00006892 delta = dis_MMXop_regmem_to_reg ( vbi, pfx, delta, opc, "pmaddwd", False );
sewardj8711f662005-05-09 17:52:56 +00006893 break;
6894
6895 case 0x74:
6896 case 0x75:
6897 case 0x76: /* PCMPEQgg (src)mmxreg-or-mem, (dst)mmxreg */
6898 if (sz != 4)
6899 goto mmx_decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +00006900 delta = dis_MMXop_regmem_to_reg ( vbi, pfx, delta, opc, "pcmpeq", True );
sewardj8711f662005-05-09 17:52:56 +00006901 break;
6902
6903 case 0x64:
6904 case 0x65:
6905 case 0x66: /* PCMPGTgg (src)mmxreg-or-mem, (dst)mmxreg */
6906 if (sz != 4)
6907 goto mmx_decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +00006908 delta = dis_MMXop_regmem_to_reg ( vbi, pfx, delta, opc, "pcmpgt", True );
sewardj8711f662005-05-09 17:52:56 +00006909 break;
6910
6911 case 0x6B: /* PACKSSDW (src)mmxreg-or-mem, (dst)mmxreg */
6912 if (sz != 4)
6913 goto mmx_decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +00006914 delta = dis_MMXop_regmem_to_reg ( vbi, pfx, delta, opc, "packssdw", False );
sewardj8711f662005-05-09 17:52:56 +00006915 break;
6916
6917 case 0x63: /* PACKSSWB (src)mmxreg-or-mem, (dst)mmxreg */
6918 if (sz != 4)
6919 goto mmx_decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +00006920 delta = dis_MMXop_regmem_to_reg ( vbi, pfx, delta, opc, "packsswb", False );
sewardj8711f662005-05-09 17:52:56 +00006921 break;
6922
6923 case 0x67: /* PACKUSWB (src)mmxreg-or-mem, (dst)mmxreg */
6924 if (sz != 4)
6925 goto mmx_decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +00006926 delta = dis_MMXop_regmem_to_reg ( vbi, pfx, delta, opc, "packuswb", False );
sewardj8711f662005-05-09 17:52:56 +00006927 break;
6928
6929 case 0x68:
6930 case 0x69:
6931 case 0x6A: /* PUNPCKHgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj23063322009-01-24 10:34:19 +00006932 if (sz != 4
6933 && /*ignore redundant REX.W*/!(sz==8 && haveNo66noF2noF3(pfx)))
sewardj8711f662005-05-09 17:52:56 +00006934 goto mmx_decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +00006935 delta = dis_MMXop_regmem_to_reg ( vbi, pfx, delta, opc, "punpckh", True );
sewardj8711f662005-05-09 17:52:56 +00006936 break;
6937
6938 case 0x60:
6939 case 0x61:
6940 case 0x62: /* PUNPCKLgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj7bdd1bc2008-12-13 16:49:46 +00006941 if (sz != 4
6942 && /*ignore redundant REX.W*/!(sz==8 && haveNo66noF2noF3(pfx)))
sewardj8711f662005-05-09 17:52:56 +00006943 goto mmx_decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +00006944 delta = dis_MMXop_regmem_to_reg ( vbi, pfx, delta, opc, "punpckl", True );
sewardj8711f662005-05-09 17:52:56 +00006945 break;
6946
6947 case 0xDB: /* PAND (src)mmxreg-or-mem, (dst)mmxreg */
6948 if (sz != 4)
6949 goto mmx_decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +00006950 delta = dis_MMXop_regmem_to_reg ( vbi, pfx, delta, opc, "pand", False );
sewardj8711f662005-05-09 17:52:56 +00006951 break;
6952
6953 case 0xDF: /* PANDN (src)mmxreg-or-mem, (dst)mmxreg */
6954 if (sz != 4)
6955 goto mmx_decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +00006956 delta = dis_MMXop_regmem_to_reg ( vbi, pfx, delta, opc, "pandn", False );
sewardj8711f662005-05-09 17:52:56 +00006957 break;
6958
6959 case 0xEB: /* POR (src)mmxreg-or-mem, (dst)mmxreg */
6960 if (sz != 4)
6961 goto mmx_decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +00006962 delta = dis_MMXop_regmem_to_reg ( vbi, pfx, delta, opc, "por", False );
sewardj8711f662005-05-09 17:52:56 +00006963 break;
6964
6965 case 0xEF: /* PXOR (src)mmxreg-or-mem, (dst)mmxreg */
6966 if (sz != 4)
6967 goto mmx_decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +00006968 delta = dis_MMXop_regmem_to_reg ( vbi, pfx, delta, opc, "pxor", False );
sewardj8711f662005-05-09 17:52:56 +00006969 break;
6970
sewardj2e28ac42008-12-04 00:05:12 +00006971# define SHIFT_BY_REG(_name,_op) \
6972 delta = dis_MMX_shiftG_byE(vbi, pfx, delta, _name, _op); \
sewardj8711f662005-05-09 17:52:56 +00006973 break;
6974
6975 /* PSLLgg (src)mmxreg-or-mem, (dst)mmxreg */
6976 case 0xF1: SHIFT_BY_REG("psllw", Iop_ShlN16x4);
6977 case 0xF2: SHIFT_BY_REG("pslld", Iop_ShlN32x2);
6978 case 0xF3: SHIFT_BY_REG("psllq", Iop_Shl64);
6979
6980 /* PSRLgg (src)mmxreg-or-mem, (dst)mmxreg */
6981 case 0xD1: SHIFT_BY_REG("psrlw", Iop_ShrN16x4);
6982 case 0xD2: SHIFT_BY_REG("psrld", Iop_ShrN32x2);
6983 case 0xD3: SHIFT_BY_REG("psrlq", Iop_Shr64);
6984
6985 /* PSRAgg (src)mmxreg-or-mem, (dst)mmxreg */
6986 case 0xE1: SHIFT_BY_REG("psraw", Iop_SarN16x4);
6987 case 0xE2: SHIFT_BY_REG("psrad", Iop_SarN32x2);
6988
6989# undef SHIFT_BY_REG
sewardj3d8107c2005-05-09 22:23:38 +00006990
6991 case 0x71:
6992 case 0x72:
6993 case 0x73: {
6994 /* (sz==4): PSLLgg/PSRAgg/PSRLgg mmxreg by imm8 */
sewardjca673ab2005-05-11 10:03:08 +00006995 UChar byte2, subopc;
sewardj3d8107c2005-05-09 22:23:38 +00006996 if (sz != 4)
6997 goto mmx_decode_failure;
sewardjca673ab2005-05-11 10:03:08 +00006998 byte2 = getUChar(delta); /* amode / sub-opcode */
6999 subopc = toUChar( (byte2 >> 3) & 7 );
sewardj3d8107c2005-05-09 22:23:38 +00007000
7001# define SHIFT_BY_IMM(_name,_op) \
7002 do { delta = dis_MMX_shiftE_imm(delta,_name,_op); \
7003 } while (0)
7004
7005 if (subopc == 2 /*SRL*/ && opc == 0x71)
7006 SHIFT_BY_IMM("psrlw", Iop_ShrN16x4);
7007 else if (subopc == 2 /*SRL*/ && opc == 0x72)
7008 SHIFT_BY_IMM("psrld", Iop_ShrN32x2);
7009 else if (subopc == 2 /*SRL*/ && opc == 0x73)
7010 SHIFT_BY_IMM("psrlq", Iop_Shr64);
7011
7012 else if (subopc == 4 /*SAR*/ && opc == 0x71)
7013 SHIFT_BY_IMM("psraw", Iop_SarN16x4);
7014 else if (subopc == 4 /*SAR*/ && opc == 0x72)
7015 SHIFT_BY_IMM("psrad", Iop_SarN32x2);
7016
7017 else if (subopc == 6 /*SHL*/ && opc == 0x71)
7018 SHIFT_BY_IMM("psllw", Iop_ShlN16x4);
7019 else if (subopc == 6 /*SHL*/ && opc == 0x72)
7020 SHIFT_BY_IMM("pslld", Iop_ShlN32x2);
7021 else if (subopc == 6 /*SHL*/ && opc == 0x73)
7022 SHIFT_BY_IMM("psllq", Iop_Shl64);
7023
7024 else goto mmx_decode_failure;
7025
7026# undef SHIFT_BY_IMM
7027 break;
7028 }
sewardj8711f662005-05-09 17:52:56 +00007029
sewardj02f79f12007-09-01 18:59:53 +00007030 case 0xF7: {
7031 IRTemp addr = newTemp(Ity_I64);
7032 IRTemp regD = newTemp(Ity_I64);
7033 IRTemp regM = newTemp(Ity_I64);
7034 IRTemp mask = newTemp(Ity_I64);
7035 IRTemp olddata = newTemp(Ity_I64);
7036 IRTemp newdata = newTemp(Ity_I64);
7037
7038 modrm = getUChar(delta);
7039 if (sz != 4 || (!epartIsReg(modrm)))
7040 goto mmx_decode_failure;
7041 delta++;
7042
sewardj2e28ac42008-12-04 00:05:12 +00007043 assign( addr, handleAddrOverrides( vbi, pfx, getIReg64(R_RDI) ));
sewardj02f79f12007-09-01 18:59:53 +00007044 assign( regM, getMMXReg( eregLO3ofRM(modrm) ));
7045 assign( regD, getMMXReg( gregLO3ofRM(modrm) ));
7046 assign( mask, binop(Iop_SarN8x8, mkexpr(regM), mkU8(7)) );
7047 assign( olddata, loadLE( Ity_I64, mkexpr(addr) ));
7048 assign( newdata,
7049 binop(Iop_Or64,
7050 binop(Iop_And64,
7051 mkexpr(regD),
7052 mkexpr(mask) ),
7053 binop(Iop_And64,
7054 mkexpr(olddata),
7055 unop(Iop_Not64, mkexpr(mask)))) );
7056 storeLE( mkexpr(addr), mkexpr(newdata) );
7057 DIP("maskmovq %s,%s\n", nameMMXReg( eregLO3ofRM(modrm) ),
7058 nameMMXReg( gregLO3ofRM(modrm) ) );
7059 break;
7060 }
7061
sewardj8711f662005-05-09 17:52:56 +00007062 /* --- MMX decode failure --- */
7063 default:
7064 mmx_decode_failure:
7065 *decode_ok = False;
7066 return delta; /* ignored */
7067
7068 }
7069
7070 *decode_ok = True;
7071 return delta;
7072}
7073
7074
sewardj33ef9c22005-11-04 20:05:57 +00007075/*------------------------------------------------------------*/
7076/*--- More misc arithmetic and other obscure insns. ---*/
7077/*------------------------------------------------------------*/
7078
7079/* Generate base << amt with vacated places filled with stuff
7080 from xtra. amt guaranteed in 0 .. 63. */
7081static
7082IRExpr* shiftL64_with_extras ( IRTemp base, IRTemp xtra, IRTemp amt )
7083{
7084 /* if amt == 0
7085 then base
7086 else (base << amt) | (xtra >>u (64-amt))
7087 */
7088 return
7089 IRExpr_Mux0X(
7090 mkexpr(amt),
7091 mkexpr(base),
7092 binop(Iop_Or64,
7093 binop(Iop_Shl64, mkexpr(base), mkexpr(amt)),
7094 binop(Iop_Shr64, mkexpr(xtra),
7095 binop(Iop_Sub8, mkU8(64), mkexpr(amt)))
7096 )
7097 );
7098}
7099
7100/* Generate base >>u amt with vacated places filled with stuff
7101 from xtra. amt guaranteed in 0 .. 63. */
7102static
7103IRExpr* shiftR64_with_extras ( IRTemp xtra, IRTemp base, IRTemp amt )
7104{
7105 /* if amt == 0
7106 then base
7107 else (base >>u amt) | (xtra << (64-amt))
7108 */
7109 return
7110 IRExpr_Mux0X(
7111 mkexpr(amt),
7112 mkexpr(base),
7113 binop(Iop_Or64,
7114 binop(Iop_Shr64, mkexpr(base), mkexpr(amt)),
7115 binop(Iop_Shl64, mkexpr(xtra),
7116 binop(Iop_Sub8, mkU8(64), mkexpr(amt)))
7117 )
7118 );
7119}
7120
7121/* Double length left and right shifts. Apparently only required in
7122 v-size (no b- variant). */
7123static
sewardj2e28ac42008-12-04 00:05:12 +00007124ULong dis_SHLRD_Gv_Ev ( VexAbiInfo* vbi,
7125 Prefix pfx,
sewardj33ef9c22005-11-04 20:05:57 +00007126 Long delta, UChar modrm,
7127 Int sz,
7128 IRExpr* shift_amt,
7129 Bool amt_is_literal,
sewardjf5268432005-11-05 02:58:55 +00007130 HChar* shift_amt_txt,
sewardj33ef9c22005-11-04 20:05:57 +00007131 Bool left_shift )
7132{
7133 /* shift_amt :: Ity_I8 is the amount to shift. shift_amt_txt is used
7134 for printing it. And eip on entry points at the modrm byte. */
7135 Int len;
7136 HChar dis_buf[50];
7137
7138 IRType ty = szToITy(sz);
7139 IRTemp gsrc = newTemp(ty);
7140 IRTemp esrc = newTemp(ty);
7141 IRTemp addr = IRTemp_INVALID;
7142 IRTemp tmpSH = newTemp(Ity_I8);
7143 IRTemp tmpSS = newTemp(Ity_I8);
7144 IRTemp tmp64 = IRTemp_INVALID;
7145 IRTemp res64 = IRTemp_INVALID;
7146 IRTemp rss64 = IRTemp_INVALID;
7147 IRTemp resTy = IRTemp_INVALID;
7148 IRTemp rssTy = IRTemp_INVALID;
7149 Int mask = sz==8 ? 63 : 31;
7150
7151 vassert(sz == 2 || sz == 4 || sz == 8);
7152
7153 /* The E-part is the destination; this is shifted. The G-part
7154 supplies bits to be shifted into the E-part, but is not
7155 changed.
7156
7157 If shifting left, form a double-length word with E at the top
7158 and G at the bottom, and shift this left. The result is then in
7159 the high part.
7160
7161 If shifting right, form a double-length word with G at the top
7162 and E at the bottom, and shift this right. The result is then
7163 at the bottom. */
7164
7165 /* Fetch the operands. */
7166
7167 assign( gsrc, getIRegG(sz, pfx, modrm) );
7168
7169 if (epartIsReg(modrm)) {
7170 delta++;
7171 assign( esrc, getIRegE(sz, pfx, modrm) );
7172 DIP("sh%cd%c %s, %s, %s\n",
7173 ( left_shift ? 'l' : 'r' ), nameISize(sz),
7174 shift_amt_txt,
7175 nameIRegG(sz, pfx, modrm), nameIRegE(sz, pfx, modrm));
7176 } else {
sewardj2e28ac42008-12-04 00:05:12 +00007177 addr = disAMode ( &len, vbi, pfx, delta, dis_buf,
sewardj75ce3652005-11-04 20:49:36 +00007178 /* # bytes following amode */
7179 amt_is_literal ? 1 : 0 );
sewardj33ef9c22005-11-04 20:05:57 +00007180 delta += len;
7181 assign( esrc, loadLE(ty, mkexpr(addr)) );
7182 DIP("sh%cd%c %s, %s, %s\n",
7183 ( left_shift ? 'l' : 'r' ), nameISize(sz),
7184 shift_amt_txt,
7185 nameIRegG(sz, pfx, modrm), dis_buf);
7186 }
7187
7188 /* Calculate the masked shift amount (tmpSH), the masked subshift
7189 amount (tmpSS), the shifted value (res64) and the subshifted
7190 value (rss64). */
7191
7192 assign( tmpSH, binop(Iop_And8, shift_amt, mkU8(mask)) );
7193 assign( tmpSS, binop(Iop_And8,
7194 binop(Iop_Sub8, mkexpr(tmpSH), mkU8(1) ),
7195 mkU8(mask)));
7196
7197 tmp64 = newTemp(Ity_I64);
7198 res64 = newTemp(Ity_I64);
7199 rss64 = newTemp(Ity_I64);
7200
7201 if (sz == 2 || sz == 4) {
7202
7203 /* G is xtra; E is data */
7204 /* what a freaking nightmare: */
7205 if (sz == 4 && left_shift) {
7206 assign( tmp64, binop(Iop_32HLto64, mkexpr(esrc), mkexpr(gsrc)) );
7207 assign( res64,
7208 binop(Iop_Shr64,
7209 binop(Iop_Shl64, mkexpr(tmp64), mkexpr(tmpSH)),
7210 mkU8(32)) );
7211 assign( rss64,
7212 binop(Iop_Shr64,
7213 binop(Iop_Shl64, mkexpr(tmp64), mkexpr(tmpSS)),
7214 mkU8(32)) );
7215 }
7216 else
7217 if (sz == 4 && !left_shift) {
7218 assign( tmp64, binop(Iop_32HLto64, mkexpr(gsrc), mkexpr(esrc)) );
7219 assign( res64, binop(Iop_Shr64, mkexpr(tmp64), mkexpr(tmpSH)) );
7220 assign( rss64, binop(Iop_Shr64, mkexpr(tmp64), mkexpr(tmpSS)) );
7221 }
7222 else
7223 if (sz == 2 && left_shift) {
7224 assign( tmp64,
7225 binop(Iop_32HLto64,
7226 binop(Iop_16HLto32, mkexpr(esrc), mkexpr(gsrc)),
7227 binop(Iop_16HLto32, mkexpr(gsrc), mkexpr(gsrc))
7228 ));
7229 /* result formed by shifting [esrc'gsrc'gsrc'gsrc] */
7230 assign( res64,
7231 binop(Iop_Shr64,
7232 binop(Iop_Shl64, mkexpr(tmp64), mkexpr(tmpSH)),
7233 mkU8(48)) );
7234 /* subshift formed by shifting [esrc'0000'0000'0000] */
7235 assign( rss64,
7236 binop(Iop_Shr64,
7237 binop(Iop_Shl64,
7238 binop(Iop_Shl64, unop(Iop_16Uto64, mkexpr(esrc)),
7239 mkU8(48)),
7240 mkexpr(tmpSS)),
7241 mkU8(48)) );
7242 }
7243 else
7244 if (sz == 2 && !left_shift) {
7245 assign( tmp64,
7246 binop(Iop_32HLto64,
7247 binop(Iop_16HLto32, mkexpr(gsrc), mkexpr(gsrc)),
7248 binop(Iop_16HLto32, mkexpr(gsrc), mkexpr(esrc))
7249 ));
7250 /* result formed by shifting [gsrc'gsrc'gsrc'esrc] */
7251 assign( res64, binop(Iop_Shr64, mkexpr(tmp64), mkexpr(tmpSH)) );
7252 /* subshift formed by shifting [0000'0000'0000'esrc] */
7253 assign( rss64, binop(Iop_Shr64,
7254 unop(Iop_16Uto64, mkexpr(esrc)),
7255 mkexpr(tmpSS)) );
7256 }
7257
7258 } else {
7259
7260 vassert(sz == 8);
7261 if (left_shift) {
7262 assign( res64, shiftL64_with_extras( esrc, gsrc, tmpSH ));
7263 assign( rss64, shiftL64_with_extras( esrc, gsrc, tmpSS ));
7264 } else {
7265 assign( res64, shiftR64_with_extras( gsrc, esrc, tmpSH ));
7266 assign( rss64, shiftR64_with_extras( gsrc, esrc, tmpSS ));
7267 }
7268
7269 }
7270
7271 resTy = newTemp(ty);
7272 rssTy = newTemp(ty);
7273 assign( resTy, narrowTo(ty, mkexpr(res64)) );
7274 assign( rssTy, narrowTo(ty, mkexpr(rss64)) );
7275
7276 /* Put result back and write the flags thunk. */
7277 setFlags_DEP1_DEP2_shift ( left_shift ? Iop_Shl64 : Iop_Sar64,
7278 resTy, rssTy, ty, tmpSH );
7279
7280 if (epartIsReg(modrm)) {
7281 putIRegE(sz, pfx, modrm, mkexpr(resTy));
7282 } else {
7283 storeLE( mkexpr(addr), mkexpr(resTy) );
7284 }
7285
7286 if (amt_is_literal) delta++;
7287 return delta;
7288}
sewardj9ed16802005-08-24 10:46:19 +00007289
7290
7291/* Handle BT/BTS/BTR/BTC Gv, Ev. Apparently b-size is not
7292 required. */
7293
7294typedef enum { BtOpNone, BtOpSet, BtOpReset, BtOpComp } BtOp;
7295
7296static HChar* nameBtOp ( BtOp op )
7297{
7298 switch (op) {
7299 case BtOpNone: return "";
7300 case BtOpSet: return "s";
7301 case BtOpReset: return "r";
7302 case BtOpComp: return "c";
7303 default: vpanic("nameBtOp(amd64)");
7304 }
7305}
7306
7307
7308static
sewardj2e28ac42008-12-04 00:05:12 +00007309ULong dis_bt_G_E ( VexAbiInfo* vbi,
7310 Prefix pfx, Int sz, Long delta, BtOp op )
sewardj9ed16802005-08-24 10:46:19 +00007311{
7312 HChar dis_buf[50];
7313 UChar modrm;
7314 Int len;
7315 IRTemp t_fetched, t_bitno0, t_bitno1, t_bitno2, t_addr0,
sewardje9d8a262009-07-01 08:06:34 +00007316 t_addr1, t_rsp, t_mask, t_new;
sewardj9ed16802005-08-24 10:46:19 +00007317
7318 vassert(sz == 2 || sz == 4 || sz == 8);
7319
7320 t_fetched = t_bitno0 = t_bitno1 = t_bitno2
sewardje9d8a262009-07-01 08:06:34 +00007321 = t_addr0 = t_addr1 = t_rsp
7322 = t_mask = t_new = IRTemp_INVALID;
sewardj9ed16802005-08-24 10:46:19 +00007323
7324 t_fetched = newTemp(Ity_I8);
sewardje9d8a262009-07-01 08:06:34 +00007325 t_new = newTemp(Ity_I8);
sewardj9ed16802005-08-24 10:46:19 +00007326 t_bitno0 = newTemp(Ity_I64);
7327 t_bitno1 = newTemp(Ity_I64);
7328 t_bitno2 = newTemp(Ity_I8);
7329 t_addr1 = newTemp(Ity_I64);
7330 modrm = getUChar(delta);
7331
7332 assign( t_bitno0, widenSto64(getIRegG(sz, pfx, modrm)) );
7333
7334 if (epartIsReg(modrm)) {
7335 delta++;
7336 /* Get it onto the client's stack. */
7337 t_rsp = newTemp(Ity_I64);
7338 t_addr0 = newTemp(Ity_I64);
7339
7340 assign( t_rsp, binop(Iop_Sub64, getIReg64(R_RSP), mkU64(sz)) );
7341 putIReg64(R_RSP, mkexpr(t_rsp));
7342
7343 storeLE( mkexpr(t_rsp), getIRegE(sz, pfx, modrm) );
7344
7345 /* Make t_addr0 point at it. */
7346 assign( t_addr0, mkexpr(t_rsp) );
7347
7348 /* Mask out upper bits of the shift amount, since we're doing a
7349 reg. */
7350 assign( t_bitno1, binop(Iop_And64,
7351 mkexpr(t_bitno0),
7352 mkU64(sz == 8 ? 63 : sz == 4 ? 31 : 15)) );
7353
7354 } else {
sewardj2e28ac42008-12-04 00:05:12 +00007355 t_addr0 = disAMode ( &len, vbi, pfx, delta, dis_buf, 0 );
sewardj9ed16802005-08-24 10:46:19 +00007356 delta += len;
7357 assign( t_bitno1, mkexpr(t_bitno0) );
7358 }
7359
7360 /* At this point: t_addr0 is the address being operated on. If it
7361 was a reg, we will have pushed it onto the client's stack.
7362 t_bitno1 is the bit number, suitably masked in the case of a
7363 reg. */
7364
7365 /* Now the main sequence. */
7366 assign( t_addr1,
7367 binop(Iop_Add64,
7368 mkexpr(t_addr0),
7369 binop(Iop_Sar64, mkexpr(t_bitno1), mkU8(3))) );
7370
7371 /* t_addr1 now holds effective address */
7372
7373 assign( t_bitno2,
7374 unop(Iop_64to8,
7375 binop(Iop_And64, mkexpr(t_bitno1), mkU64(7))) );
7376
7377 /* t_bitno2 contains offset of bit within byte */
7378
7379 if (op != BtOpNone) {
7380 t_mask = newTemp(Ity_I8);
7381 assign( t_mask, binop(Iop_Shl8, mkU8(1), mkexpr(t_bitno2)) );
7382 }
7383
7384 /* t_mask is now a suitable byte mask */
7385
7386 assign( t_fetched, loadLE(Ity_I8, mkexpr(t_addr1)) );
7387
7388 if (op != BtOpNone) {
7389 switch (op) {
sewardje9d8a262009-07-01 08:06:34 +00007390 case BtOpSet:
7391 assign( t_new,
7392 binop(Iop_Or8, mkexpr(t_fetched), mkexpr(t_mask)) );
sewardj9ed16802005-08-24 10:46:19 +00007393 break;
sewardje9d8a262009-07-01 08:06:34 +00007394 case BtOpComp:
7395 assign( t_new,
7396 binop(Iop_Xor8, mkexpr(t_fetched), mkexpr(t_mask)) );
sewardj9ed16802005-08-24 10:46:19 +00007397 break;
sewardje9d8a262009-07-01 08:06:34 +00007398 case BtOpReset:
7399 assign( t_new,
7400 binop(Iop_And8, mkexpr(t_fetched),
7401 unop(Iop_Not8, mkexpr(t_mask))) );
sewardj9ed16802005-08-24 10:46:19 +00007402 break;
7403 default:
7404 vpanic("dis_bt_G_E(amd64)");
7405 }
sewardje9d8a262009-07-01 08:06:34 +00007406 if ((pfx & PFX_LOCK) && !epartIsReg(modrm)) {
7407 casLE( mkexpr(t_addr1), mkexpr(t_fetched)/*expd*/,
7408 mkexpr(t_new)/*new*/,
7409 guest_RIP_curr_instr );
7410 } else {
7411 storeLE( mkexpr(t_addr1), mkexpr(t_new) );
7412 }
sewardj9ed16802005-08-24 10:46:19 +00007413 }
sewardje9d8a262009-07-01 08:06:34 +00007414
sewardj9ed16802005-08-24 10:46:19 +00007415 /* Side effect done; now get selected bit into Carry flag */
7416 /* Flags: C=selected bit, O,S,Z,A,P undefined, so are set to zero. */
7417 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(AMD64G_CC_OP_COPY) ));
7418 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
7419 stmt( IRStmt_Put(
7420 OFFB_CC_DEP1,
7421 binop(Iop_And64,
7422 binop(Iop_Shr64,
7423 unop(Iop_8Uto64, mkexpr(t_fetched)),
7424 mkexpr(t_bitno2)),
7425 mkU64(1)))
7426 );
7427 /* Set NDEP even though it isn't used. This makes redundant-PUT
7428 elimination of previous stores to this field work better. */
7429 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU64(0) ));
7430
7431 /* Move reg operand from stack back to reg */
7432 if (epartIsReg(modrm)) {
sewardje9d8a262009-07-01 08:06:34 +00007433 /* t_rsp still points at it. */
sewardj25d23862006-05-12 17:47:21 +00007434 /* only write the reg if actually modifying it; doing otherwise
7435 zeroes the top half erroneously when doing btl due to
7436 standard zero-extend rule */
sewardje9d8a262009-07-01 08:06:34 +00007437 if (op != BtOpNone)
sewardj25d23862006-05-12 17:47:21 +00007438 putIRegE(sz, pfx, modrm, loadLE(szToITy(sz), mkexpr(t_rsp)) );
sewardj9ed16802005-08-24 10:46:19 +00007439 putIReg64(R_RSP, binop(Iop_Add64, mkexpr(t_rsp), mkU64(sz)) );
7440 }
7441
7442 DIP("bt%s%c %s, %s\n",
7443 nameBtOp(op), nameISize(sz), nameIRegG(sz, pfx, modrm),
7444 ( epartIsReg(modrm) ? nameIRegE(sz, pfx, modrm) : dis_buf ) );
7445
7446 return delta;
7447}
sewardjf53b7352005-04-06 20:01:56 +00007448
7449
7450
7451/* Handle BSF/BSR. Only v-size seems necessary. */
7452static
sewardj2e28ac42008-12-04 00:05:12 +00007453ULong dis_bs_E_G ( VexAbiInfo* vbi,
7454 Prefix pfx, Int sz, Long delta, Bool fwds )
sewardjf53b7352005-04-06 20:01:56 +00007455{
7456 Bool isReg;
7457 UChar modrm;
7458 HChar dis_buf[50];
7459
7460 IRType ty = szToITy(sz);
7461 IRTemp src = newTemp(ty);
7462 IRTemp dst = newTemp(ty);
7463 IRTemp src64 = newTemp(Ity_I64);
7464 IRTemp dst64 = newTemp(Ity_I64);
7465 IRTemp src8 = newTemp(Ity_I8);
7466
7467 vassert(sz == 8 || sz == 4 || sz == 2);
7468
7469 modrm = getUChar(delta);
7470 isReg = epartIsReg(modrm);
7471 if (isReg) {
7472 delta++;
7473 assign( src, getIRegE(sz, pfx, modrm) );
7474 } else {
7475 Int len;
sewardj2e28ac42008-12-04 00:05:12 +00007476 IRTemp addr = disAMode( &len, vbi, pfx, delta, dis_buf, 0 );
sewardjf53b7352005-04-06 20:01:56 +00007477 delta += len;
7478 assign( src, loadLE(ty, mkexpr(addr)) );
7479 }
7480
7481 DIP("bs%c%c %s, %s\n",
7482 fwds ? 'f' : 'r', nameISize(sz),
7483 ( isReg ? nameIRegE(sz, pfx, modrm) : dis_buf ),
7484 nameIRegG(sz, pfx, modrm));
7485
7486 /* First, widen src to 64 bits if it is not already. */
7487 assign( src64, widenUto64(mkexpr(src)) );
7488
7489 /* Generate an 8-bit expression which is zero iff the
7490 original is zero, and nonzero otherwise */
7491 assign( src8,
7492 unop(Iop_1Uto8,
7493 binop(Iop_CmpNE64,
7494 mkexpr(src64), mkU64(0))) );
7495
7496 /* Flags: Z is 1 iff source value is zero. All others
7497 are undefined -- we force them to zero. */
7498 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(AMD64G_CC_OP_COPY) ));
7499 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
7500 stmt( IRStmt_Put(
7501 OFFB_CC_DEP1,
7502 IRExpr_Mux0X( mkexpr(src8),
7503 /* src==0 */
7504 mkU64(AMD64G_CC_MASK_Z),
7505 /* src!=0 */
7506 mkU64(0)
7507 )
7508 ));
7509 /* Set NDEP even though it isn't used. This makes redundant-PUT
7510 elimination of previous stores to this field work better. */
7511 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU64(0) ));
7512
7513 /* Result: iff source value is zero, we can't use
7514 Iop_Clz64/Iop_Ctz64 as they have no defined result in that case.
7515 But anyway, amd64 semantics say the result is undefined in
7516 such situations. Hence handle the zero case specially. */
7517
7518 /* Bleh. What we compute:
7519
7520 bsf64: if src == 0 then {dst is unchanged}
7521 else Ctz64(src)
7522
7523 bsr64: if src == 0 then {dst is unchanged}
7524 else 63 - Clz64(src)
7525
7526 bsf32: if src == 0 then {dst is unchanged}
7527 else Ctz64(32Uto64(src))
7528
7529 bsr32: if src == 0 then {dst is unchanged}
7530 else 63 - Clz64(32Uto64(src))
7531
7532 bsf16: if src == 0 then {dst is unchanged}
7533 else Ctz64(32Uto64(16Uto32(src)))
7534
7535 bsr16: if src == 0 then {dst is unchanged}
7536 else 63 - Clz64(32Uto64(16Uto32(src)))
7537 */
7538
7539 /* The main computation, guarding against zero. */
7540 assign( dst64,
7541 IRExpr_Mux0X(
7542 mkexpr(src8),
7543 /* src == 0 -- leave dst unchanged */
7544 widenUto64( getIRegG( sz, pfx, modrm ) ),
7545 /* src != 0 */
7546 fwds ? unop(Iop_Ctz64, mkexpr(src64))
7547 : binop(Iop_Sub64,
7548 mkU64(63),
7549 unop(Iop_Clz64, mkexpr(src64)))
7550 )
7551 );
7552
7553 if (sz == 2)
sewardje58967e2005-04-27 11:50:56 +00007554 assign( dst, unop(Iop_64to16, mkexpr(dst64)) );
sewardjf53b7352005-04-06 20:01:56 +00007555 else
7556 if (sz == 4)
7557 assign( dst, unop(Iop_64to32, mkexpr(dst64)) );
7558 else
7559 assign( dst, mkexpr(dst64) );
7560
7561 /* dump result back */
7562 putIRegG( sz, pfx, modrm, mkexpr(dst) );
7563
7564 return delta;
7565}
sewardja6b93d12005-02-17 09:28:28 +00007566
7567
7568/* swap rAX with the reg specified by reg and REX.B */
7569static
sewardj5b470602005-02-27 13:10:48 +00007570void codegen_xchg_rAX_Reg ( Prefix pfx, Int sz, UInt regLo3 )
sewardja6b93d12005-02-17 09:28:28 +00007571{
7572 IRType ty = szToITy(sz);
7573 IRTemp t1 = newTemp(ty);
7574 IRTemp t2 = newTemp(ty);
sewardj2d4fcd52005-05-18 11:47:47 +00007575 vassert(sz == 4 || sz == 8);
sewardj5b470602005-02-27 13:10:48 +00007576 vassert(regLo3 < 8);
sewardj2d4fcd52005-05-18 11:47:47 +00007577 if (sz == 8) {
7578 assign( t1, getIReg64(R_RAX) );
7579 assign( t2, getIRegRexB(8, pfx, regLo3) );
7580 putIReg64( R_RAX, mkexpr(t2) );
7581 putIRegRexB(8, pfx, regLo3, mkexpr(t1) );
7582 } else {
7583 assign( t1, getIReg32(R_RAX) );
7584 assign( t2, getIRegRexB(4, pfx, regLo3) );
7585 putIReg32( R_RAX, mkexpr(t2) );
7586 putIRegRexB(4, pfx, regLo3, mkexpr(t1) );
7587 }
sewardja6b93d12005-02-17 09:28:28 +00007588 DIP("xchg%c %s, %s\n",
sewardj5b470602005-02-27 13:10:48 +00007589 nameISize(sz), nameIRegRAX(sz),
sewardj2d4fcd52005-05-18 11:47:47 +00007590 nameIRegRexB(sz,pfx, regLo3));
sewardja6b93d12005-02-17 09:28:28 +00007591}
7592
7593
sewardj905edbd2007-04-07 12:25:37 +00007594static
7595void codegen_SAHF ( void )
7596{
7597 /* Set the flags to:
7598 (amd64g_calculate_flags_all() & AMD64G_CC_MASK_O)
7599 -- retain the old O flag
7600 | (%AH & (AMD64G_CC_MASK_S|AMD64G_CC_MASK_Z|AMD64G_CC_MASK_A
7601 |AMD64G_CC_MASK_P|AMD64G_CC_MASK_C)
7602 */
7603 ULong mask_SZACP = AMD64G_CC_MASK_S|AMD64G_CC_MASK_Z|AMD64G_CC_MASK_A
7604 |AMD64G_CC_MASK_C|AMD64G_CC_MASK_P;
7605 IRTemp oldflags = newTemp(Ity_I64);
7606 assign( oldflags, mk_amd64g_calculate_rflags_all() );
7607 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(AMD64G_CC_OP_COPY) ));
7608 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU64(0) ));
7609 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
7610 stmt( IRStmt_Put( OFFB_CC_DEP1,
7611 binop(Iop_Or64,
7612 binop(Iop_And64, mkexpr(oldflags), mkU64(AMD64G_CC_MASK_O)),
7613 binop(Iop_And64,
7614 binop(Iop_Shr64, getIReg64(R_RAX), mkU8(8)),
7615 mkU64(mask_SZACP))
7616 )
7617 ));
7618}
7619
7620
7621static
7622void codegen_LAHF ( void )
7623{
7624 /* AH <- EFLAGS(SF:ZF:0:AF:0:PF:1:CF) */
7625 IRExpr* rax_with_hole;
7626 IRExpr* new_byte;
7627 IRExpr* new_rax;
7628 ULong mask_SZACP = AMD64G_CC_MASK_S|AMD64G_CC_MASK_Z|AMD64G_CC_MASK_A
7629 |AMD64G_CC_MASK_C|AMD64G_CC_MASK_P;
7630
7631 IRTemp flags = newTemp(Ity_I64);
7632 assign( flags, mk_amd64g_calculate_rflags_all() );
7633
7634 rax_with_hole
7635 = binop(Iop_And64, getIReg64(R_RAX), mkU64(~0xFF00ULL));
7636 new_byte
7637 = binop(Iop_Or64, binop(Iop_And64, mkexpr(flags), mkU64(mask_SZACP)),
7638 mkU64(1<<1));
7639 new_rax
7640 = binop(Iop_Or64, rax_with_hole,
7641 binop(Iop_Shl64, new_byte, mkU8(8)));
7642 putIReg64(R_RAX, new_rax);
7643}
7644
sewardja6b93d12005-02-17 09:28:28 +00007645
7646static
sewardjd0aa0a52006-08-17 01:20:01 +00007647ULong dis_cmpxchg_G_E ( /*OUT*/Bool* ok,
sewardj2e28ac42008-12-04 00:05:12 +00007648 VexAbiInfo* vbi,
sewardjd0aa0a52006-08-17 01:20:01 +00007649 Prefix pfx,
7650 Int size,
7651 Long delta0 )
sewardja6b93d12005-02-17 09:28:28 +00007652{
7653 HChar dis_buf[50];
7654 Int len;
7655
7656 IRType ty = szToITy(size);
7657 IRTemp acc = newTemp(ty);
7658 IRTemp src = newTemp(ty);
7659 IRTemp dest = newTemp(ty);
7660 IRTemp dest2 = newTemp(ty);
7661 IRTemp acc2 = newTemp(ty);
7662 IRTemp cond8 = newTemp(Ity_I8);
7663 IRTemp addr = IRTemp_INVALID;
7664 UChar rm = getUChar(delta0);
7665
sewardje9d8a262009-07-01 08:06:34 +00007666 /* There are 3 cases to consider:
7667
7668 reg-reg: ignore any lock prefix, generate sequence based
7669 on Mux0X
7670
7671 reg-mem, not locked: ignore any lock prefix, generate sequence
7672 based on Mux0X
7673
7674 reg-mem, locked: use IRCAS
7675 */
7676
sewardja6b93d12005-02-17 09:28:28 +00007677 if (epartIsReg(rm)) {
sewardje9d8a262009-07-01 08:06:34 +00007678 /* case 1 */
sewardjd0aa0a52006-08-17 01:20:01 +00007679 *ok = False;
7680 return delta0;
7681 /* awaiting test case */
sewardj5b470602005-02-27 13:10:48 +00007682 assign( dest, getIRegE(size, pfx, rm) );
sewardja6b93d12005-02-17 09:28:28 +00007683 delta0++;
sewardje9d8a262009-07-01 08:06:34 +00007684 assign( src, getIRegG(size, pfx, rm) );
7685 assign( acc, getIRegRAX(size) );
7686 setFlags_DEP1_DEP2(Iop_Sub8, acc, dest, ty);
7687 assign( cond8, unop(Iop_1Uto8, mk_amd64g_calculate_condition(AMD64CondZ)) );
7688 assign( dest2, IRExpr_Mux0X(mkexpr(cond8), mkexpr(dest), mkexpr(src)) );
7689 assign( acc2, IRExpr_Mux0X(mkexpr(cond8), mkexpr(dest), mkexpr(acc)) );
7690 putIRegRAX(size, mkexpr(acc2));
7691 putIRegE(size, pfx, rm, mkexpr(dest2));
sewardja6b93d12005-02-17 09:28:28 +00007692 DIP("cmpxchg%c %s,%s\n", nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00007693 nameIRegG(size,pfx,rm),
7694 nameIRegE(size,pfx,rm) );
sewardje9d8a262009-07-01 08:06:34 +00007695 }
7696 else if (!epartIsReg(rm) && !(pfx & PFX_LOCK)) {
7697 /* case 2 */
sewardj2e28ac42008-12-04 00:05:12 +00007698 addr = disAMode ( &len, vbi, pfx, delta0, dis_buf, 0 );
sewardja6b93d12005-02-17 09:28:28 +00007699 assign( dest, loadLE(ty, mkexpr(addr)) );
7700 delta0 += len;
sewardje9d8a262009-07-01 08:06:34 +00007701 assign( src, getIRegG(size, pfx, rm) );
7702 assign( acc, getIRegRAX(size) );
7703 setFlags_DEP1_DEP2(Iop_Sub8, acc, dest, ty);
7704 assign( cond8, unop(Iop_1Uto8, mk_amd64g_calculate_condition(AMD64CondZ)) );
7705 assign( dest2, IRExpr_Mux0X(mkexpr(cond8), mkexpr(dest), mkexpr(src)) );
7706 assign( acc2, IRExpr_Mux0X(mkexpr(cond8), mkexpr(dest), mkexpr(acc)) );
7707 putIRegRAX(size, mkexpr(acc2));
7708 storeLE( mkexpr(addr), mkexpr(dest2) );
sewardja6b93d12005-02-17 09:28:28 +00007709 DIP("cmpxchg%c %s,%s\n", nameISize(size),
sewardj5b470602005-02-27 13:10:48 +00007710 nameIRegG(size,pfx,rm), dis_buf);
sewardja6b93d12005-02-17 09:28:28 +00007711 }
sewardje9d8a262009-07-01 08:06:34 +00007712 else if (!epartIsReg(rm) && (pfx & PFX_LOCK)) {
7713 /* case 3 */
7714 /* src is new value. acc is expected value. dest is old value.
7715 Compute success from the output of the IRCAS, and steer the
7716 new value for RAX accordingly: in case of success, RAX is
7717 unchanged. */
7718 addr = disAMode ( &len, vbi, pfx, delta0, dis_buf, 0 );
7719 delta0 += len;
7720 assign( src, getIRegG(size, pfx, rm) );
7721 assign( acc, getIRegRAX(size) );
7722 stmt( IRStmt_CAS(
7723 mkIRCAS( IRTemp_INVALID, dest, Iend_LE, mkexpr(addr),
7724 NULL, mkexpr(acc), NULL, mkexpr(src) )
7725 ));
7726 setFlags_DEP1_DEP2(Iop_Sub8, acc, dest, ty);
7727 assign( cond8, unop(Iop_1Uto8, mk_amd64g_calculate_condition(AMD64CondZ)) );
7728 assign( acc2, IRExpr_Mux0X(mkexpr(cond8), mkexpr(dest), mkexpr(acc)) );
7729 putIRegRAX(size, mkexpr(acc2));
sewardj40d1d212009-07-12 13:01:17 +00007730 DIP("cmpxchg%c %s,%s\n", nameISize(size),
7731 nameIRegG(size,pfx,rm), dis_buf);
sewardja6b93d12005-02-17 09:28:28 +00007732 }
sewardje9d8a262009-07-01 08:06:34 +00007733 else vassert(0);
sewardja6b93d12005-02-17 09:28:28 +00007734
sewardjd0aa0a52006-08-17 01:20:01 +00007735 *ok = True;
sewardja6b93d12005-02-17 09:28:28 +00007736 return delta0;
7737}
7738
sewardj3ca55a12005-01-27 16:06:23 +00007739
7740/* Handle conditional move instructions of the form
7741 cmovcc E(reg-or-mem), G(reg)
7742
7743 E(src) is reg-or-mem
7744 G(dst) is reg.
7745
7746 If E is reg, --> GET %E, tmps
7747 GET %G, tmpd
7748 CMOVcc tmps, tmpd
7749 PUT tmpd, %G
7750
7751 If E is mem --> (getAddr E) -> tmpa
7752 LD (tmpa), tmps
7753 GET %G, tmpd
7754 CMOVcc tmps, tmpd
7755 PUT tmpd, %G
7756*/
7757static
sewardj2e28ac42008-12-04 00:05:12 +00007758ULong dis_cmov_E_G ( VexAbiInfo* vbi,
7759 Prefix pfx,
sewardj3ca55a12005-01-27 16:06:23 +00007760 Int sz,
7761 AMD64Condcode cond,
sewardj270def42005-07-03 01:03:01 +00007762 Long delta0 )
sewardj3ca55a12005-01-27 16:06:23 +00007763{
sewardj8c332e22005-01-28 01:36:56 +00007764 UChar rm = getUChar(delta0);
sewardj3ca55a12005-01-27 16:06:23 +00007765 HChar dis_buf[50];
7766 Int len;
7767
7768 IRType ty = szToITy(sz);
7769 IRTemp tmps = newTemp(ty);
7770 IRTemp tmpd = newTemp(ty);
7771
7772 if (epartIsReg(rm)) {
sewardj5b470602005-02-27 13:10:48 +00007773 assign( tmps, getIRegE(sz, pfx, rm) );
7774 assign( tmpd, getIRegG(sz, pfx, rm) );
sewardj3ca55a12005-01-27 16:06:23 +00007775
sewardj5b470602005-02-27 13:10:48 +00007776 putIRegG( sz, pfx, rm,
sewardj3ca55a12005-01-27 16:06:23 +00007777 IRExpr_Mux0X( unop(Iop_1Uto8,
7778 mk_amd64g_calculate_condition(cond)),
7779 mkexpr(tmpd),
7780 mkexpr(tmps) )
7781 );
sewardje941eea2005-01-30 19:52:28 +00007782 DIP("cmov%s %s,%s\n", name_AMD64Condcode(cond),
sewardj5b470602005-02-27 13:10:48 +00007783 nameIRegE(sz,pfx,rm),
7784 nameIRegG(sz,pfx,rm));
sewardj3ca55a12005-01-27 16:06:23 +00007785 return 1+delta0;
7786 }
7787
7788 /* E refers to memory */
7789 {
sewardj2e28ac42008-12-04 00:05:12 +00007790 IRTemp addr = disAMode ( &len, vbi, pfx, delta0, dis_buf, 0 );
sewardj3ca55a12005-01-27 16:06:23 +00007791 assign( tmps, loadLE(ty, mkexpr(addr)) );
sewardj5b470602005-02-27 13:10:48 +00007792 assign( tmpd, getIRegG(sz, pfx, rm) );
sewardj3ca55a12005-01-27 16:06:23 +00007793
sewardj5b470602005-02-27 13:10:48 +00007794 putIRegG( sz, pfx, rm,
sewardj3ca55a12005-01-27 16:06:23 +00007795 IRExpr_Mux0X( unop(Iop_1Uto8,
7796 mk_amd64g_calculate_condition(cond)),
7797 mkexpr(tmpd),
7798 mkexpr(tmps) )
7799 );
7800
sewardj7eaa7cf2005-01-31 18:55:22 +00007801 DIP("cmov%s %s,%s\n", name_AMD64Condcode(cond),
7802 dis_buf,
sewardj5b470602005-02-27 13:10:48 +00007803 nameIRegG(sz,pfx,rm));
sewardj3ca55a12005-01-27 16:06:23 +00007804 return len+delta0;
7805 }
7806}
7807
7808
sewardjb4fd2e72005-03-23 13:34:11 +00007809static
7810ULong dis_xadd_G_E ( /*OUT*/Bool* decode_ok,
sewardj2e28ac42008-12-04 00:05:12 +00007811 VexAbiInfo* vbi,
sewardj270def42005-07-03 01:03:01 +00007812 Prefix pfx, Int sz, Long delta0 )
sewardjb4fd2e72005-03-23 13:34:11 +00007813{
7814 Int len;
7815 UChar rm = getUChar(delta0);
7816 HChar dis_buf[50];
7817
7818 IRType ty = szToITy(sz);
7819 IRTemp tmpd = newTemp(ty);
7820 IRTemp tmpt0 = newTemp(ty);
7821 IRTemp tmpt1 = newTemp(ty);
sewardje9d8a262009-07-01 08:06:34 +00007822
7823 /* There are 3 cases to consider:
7824
sewardjc2433a82010-05-10 20:51:22 +00007825 reg-reg: ignore any lock prefix,
7826 generate 'naive' (non-atomic) sequence
sewardje9d8a262009-07-01 08:06:34 +00007827
7828 reg-mem, not locked: ignore any lock prefix, generate 'naive'
7829 (non-atomic) sequence
7830
7831 reg-mem, locked: use IRCAS
7832 */
sewardjb4fd2e72005-03-23 13:34:11 +00007833
7834 if (epartIsReg(rm)) {
sewardje9d8a262009-07-01 08:06:34 +00007835 /* case 1 */
sewardjc2433a82010-05-10 20:51:22 +00007836 assign( tmpd, getIRegE(sz, pfx, rm) );
7837 assign( tmpt0, getIRegG(sz, pfx, rm) );
7838 assign( tmpt1, binop(mkSizedOp(ty,Iop_Add8),
7839 mkexpr(tmpd), mkexpr(tmpt0)) );
7840 setFlags_DEP1_DEP2( Iop_Add8, tmpd, tmpt0, ty );
7841 putIRegG(sz, pfx, rm, mkexpr(tmpd));
7842 putIRegE(sz, pfx, rm, mkexpr(tmpt1));
7843 DIP("xadd%c %s, %s\n",
7844 nameISize(sz), nameIRegG(sz,pfx,rm),
7845 nameIRegE(sz,pfx,rm));
7846 *decode_ok = True;
7847 return 1+delta0;
sewardje9d8a262009-07-01 08:06:34 +00007848 }
7849 else if (!epartIsReg(rm) && !(pfx & PFX_LOCK)) {
7850 /* case 2 */
sewardj2e28ac42008-12-04 00:05:12 +00007851 IRTemp addr = disAMode ( &len, vbi, pfx, delta0, dis_buf, 0 );
sewardjb4fd2e72005-03-23 13:34:11 +00007852 assign( tmpd, loadLE(ty, mkexpr(addr)) );
7853 assign( tmpt0, getIRegG(sz, pfx, rm) );
sewardje9d8a262009-07-01 08:06:34 +00007854 assign( tmpt1, binop(mkSizedOp(ty,Iop_Add8),
7855 mkexpr(tmpd), mkexpr(tmpt0)) );
sewardjb4fd2e72005-03-23 13:34:11 +00007856 setFlags_DEP1_DEP2( Iop_Add8, tmpd, tmpt0, ty );
7857 storeLE( mkexpr(addr), mkexpr(tmpt1) );
7858 putIRegG(sz, pfx, rm, mkexpr(tmpd));
7859 DIP("xadd%c %s, %s\n",
7860 nameISize(sz), nameIRegG(sz,pfx,rm), dis_buf);
sewardje9d8a262009-07-01 08:06:34 +00007861 *decode_ok = True;
sewardjb4fd2e72005-03-23 13:34:11 +00007862 return len+delta0;
7863 }
sewardje9d8a262009-07-01 08:06:34 +00007864 else if (!epartIsReg(rm) && (pfx & PFX_LOCK)) {
7865 /* case 3 */
7866 IRTemp addr = disAMode ( &len, vbi, pfx, delta0, dis_buf, 0 );
7867 assign( tmpd, loadLE(ty, mkexpr(addr)) );
7868 assign( tmpt0, getIRegG(sz, pfx, rm) );
7869 assign( tmpt1, binop(mkSizedOp(ty,Iop_Add8),
7870 mkexpr(tmpd), mkexpr(tmpt0)) );
7871 casLE( mkexpr(addr), mkexpr(tmpd)/*expVal*/,
7872 mkexpr(tmpt1)/*newVal*/, guest_RIP_curr_instr );
7873 setFlags_DEP1_DEP2( Iop_Add8, tmpd, tmpt0, ty );
7874 putIRegG(sz, pfx, rm, mkexpr(tmpd));
7875 DIP("xadd%c %s, %s\n",
7876 nameISize(sz), nameIRegG(sz,pfx,rm), dis_buf);
7877 *decode_ok = True;
7878 return len+delta0;
7879 }
7880 /*UNREACHED*/
7881 vassert(0);
sewardjb4fd2e72005-03-23 13:34:11 +00007882}
7883
sewardjd20c8852005-01-20 20:04:07 +00007884//.. /* Move 16 bits from Ew (ireg or mem) to G (a segment register). */
7885//..
7886//.. static
sewardj270def42005-07-03 01:03:01 +00007887//.. UInt dis_mov_Ew_Sw ( UChar sorb, Long delta0 )
sewardjd20c8852005-01-20 20:04:07 +00007888//.. {
7889//.. Int len;
7890//.. IRTemp addr;
sewardj8c332e22005-01-28 01:36:56 +00007891//.. UChar rm = getUChar(delta0);
sewardjd20c8852005-01-20 20:04:07 +00007892//.. HChar dis_buf[50];
7893//..
7894//.. if (epartIsReg(rm)) {
7895//.. putSReg( gregOfRM(rm), getIReg(2, eregOfRM(rm)) );
7896//.. DIP("movw %s,%s\n", nameIReg(2,eregOfRM(rm)), nameSReg(gregOfRM(rm)));
7897//.. return 1+delta0;
7898//.. } else {
7899//.. addr = disAMode ( &len, sorb, delta0, dis_buf );
7900//.. putSReg( gregOfRM(rm), loadLE(Ity_I16, mkexpr(addr)) );
7901//.. DIP("movw %s,%s\n", dis_buf, nameSReg(gregOfRM(rm)));
7902//.. return len+delta0;
7903//.. }
7904//.. }
7905//..
7906//.. /* Move 16 bits from G (a segment register) to Ew (ireg or mem). If
7907//.. dst is ireg and sz==4, zero out top half of it. */
7908//..
7909//.. static
7910//.. UInt dis_mov_Sw_Ew ( UChar sorb,
7911//.. Int sz,
7912//.. UInt delta0 )
7913//.. {
7914//.. Int len;
7915//.. IRTemp addr;
sewardj8c332e22005-01-28 01:36:56 +00007916//.. UChar rm = getUChar(delta0);
sewardjd20c8852005-01-20 20:04:07 +00007917//.. HChar dis_buf[50];
7918//..
7919//.. vassert(sz == 2 || sz == 4);
7920//..
7921//.. if (epartIsReg(rm)) {
7922//.. if (sz == 4)
7923//.. putIReg(4, eregOfRM(rm), unop(Iop_16Uto32, getSReg(gregOfRM(rm))));
7924//.. else
7925//.. putIReg(2, eregOfRM(rm), getSReg(gregOfRM(rm)));
7926//..
7927//.. DIP("mov %s,%s\n", nameSReg(gregOfRM(rm)), nameIReg(sz,eregOfRM(rm)));
7928//.. return 1+delta0;
7929//.. } else {
7930//.. addr = disAMode ( &len, sorb, delta0, dis_buf );
7931//.. storeLE( mkexpr(addr), getSReg(gregOfRM(rm)) );
7932//.. DIP("mov %s,%s\n", nameSReg(gregOfRM(rm)), dis_buf);
7933//.. return len+delta0;
7934//.. }
7935//.. }
7936//..
7937//..
7938//.. static
7939//.. void dis_push_segreg ( UInt sreg, Int sz )
7940//.. {
7941//.. IRTemp t1 = newTemp(Ity_I16);
7942//.. IRTemp ta = newTemp(Ity_I32);
7943//.. vassert(sz == 2 || sz == 4);
7944//..
7945//.. assign( t1, getSReg(sreg) );
7946//.. assign( ta, binop(Iop_Sub32, getIReg(4, R_ESP), mkU32(sz)) );
7947//.. putIReg(4, R_ESP, mkexpr(ta));
7948//.. storeLE( mkexpr(ta), mkexpr(t1) );
7949//..
7950//.. DIP("pushw %s\n", nameSReg(sreg));
7951//.. }
7952//..
7953//.. static
7954//.. void dis_pop_segreg ( UInt sreg, Int sz )
7955//.. {
7956//.. IRTemp t1 = newTemp(Ity_I16);
7957//.. IRTemp ta = newTemp(Ity_I32);
7958//.. vassert(sz == 2 || sz == 4);
7959//..
7960//.. assign( ta, getIReg(4, R_ESP) );
7961//.. assign( t1, loadLE(Ity_I16, mkexpr(ta)) );
7962//..
7963//.. putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(ta), mkU32(sz)) );
7964//.. putSReg( sreg, mkexpr(t1) );
7965//.. DIP("pop %s\n", nameSReg(sreg));
7966//.. }
sewardj2f959cc2005-01-26 01:19:35 +00007967
7968static
sewardjdd40fdf2006-12-24 02:20:24 +00007969void dis_ret ( VexAbiInfo* vbi, ULong d64 )
sewardj2f959cc2005-01-26 01:19:35 +00007970{
7971 IRTemp t1 = newTemp(Ity_I64);
7972 IRTemp t2 = newTemp(Ity_I64);
sewardj5a9ffab2005-05-12 17:55:01 +00007973 IRTemp t3 = newTemp(Ity_I64);
sewardj2f959cc2005-01-26 01:19:35 +00007974 assign(t1, getIReg64(R_RSP));
7975 assign(t2, loadLE(Ity_I64,mkexpr(t1)));
sewardj5a9ffab2005-05-12 17:55:01 +00007976 assign(t3, binop(Iop_Add64, mkexpr(t1), mkU64(8+d64)));
7977 putIReg64(R_RSP, mkexpr(t3));
sewardj478646f2008-05-01 20:13:04 +00007978 make_redzone_AbiHint(vbi, t3, t2/*nia*/, "ret");
sewardj2f959cc2005-01-26 01:19:35 +00007979 jmp_treg(Ijk_Ret,t2);
7980}
7981
sewardj5b470602005-02-27 13:10:48 +00007982
sewardj1001dc42005-02-21 08:25:55 +00007983/*------------------------------------------------------------*/
7984/*--- SSE/SSE2/SSE3 helpers ---*/
7985/*------------------------------------------------------------*/
7986
7987/* Worker function; do not call directly.
7988 Handles full width G = G `op` E and G = (not G) `op` E.
7989*/
7990
sewardj8d965312005-02-25 02:48:47 +00007991static ULong dis_SSE_E_to_G_all_wrk (
sewardj2e28ac42008-12-04 00:05:12 +00007992 VexAbiInfo* vbi,
sewardj270def42005-07-03 01:03:01 +00007993 Prefix pfx, Long delta,
sewardj8d965312005-02-25 02:48:47 +00007994 HChar* opname, IROp op,
7995 Bool invertG
7996 )
sewardj9da16972005-02-21 13:58:26 +00007997{
7998 HChar dis_buf[50];
7999 Int alen;
8000 IRTemp addr;
8001 UChar rm = getUChar(delta);
8002 IRExpr* gpart
8003 = invertG ? unop(Iop_NotV128, getXMMReg(gregOfRexRM(pfx,rm)))
8004 : getXMMReg(gregOfRexRM(pfx,rm));
8005 if (epartIsReg(rm)) {
8006 putXMMReg( gregOfRexRM(pfx,rm),
8007 binop(op, gpart,
8008 getXMMReg(eregOfRexRM(pfx,rm))) );
8009 DIP("%s %s,%s\n", opname,
8010 nameXMMReg(eregOfRexRM(pfx,rm)),
8011 nameXMMReg(gregOfRexRM(pfx,rm)) );
8012 return delta+1;
8013 } else {
sewardj2e28ac42008-12-04 00:05:12 +00008014 addr = disAMode ( &alen, vbi, pfx, delta, dis_buf, 0 );
sewardj9da16972005-02-21 13:58:26 +00008015 putXMMReg( gregOfRexRM(pfx,rm),
8016 binop(op, gpart,
8017 loadLE(Ity_V128, mkexpr(addr))) );
8018 DIP("%s %s,%s\n", opname,
8019 dis_buf,
8020 nameXMMReg(gregOfRexRM(pfx,rm)) );
8021 return delta+alen;
8022 }
8023}
8024
8025
8026/* All lanes SSE binary operation, G = G `op` E. */
8027
8028static
sewardj2e28ac42008-12-04 00:05:12 +00008029ULong dis_SSE_E_to_G_all ( VexAbiInfo* vbi,
8030 Prefix pfx, Long delta,
sewardj8d965312005-02-25 02:48:47 +00008031 HChar* opname, IROp op )
sewardj9da16972005-02-21 13:58:26 +00008032{
sewardj2e28ac42008-12-04 00:05:12 +00008033 return dis_SSE_E_to_G_all_wrk( vbi, pfx, delta, opname, op, False );
sewardj9da16972005-02-21 13:58:26 +00008034}
8035
sewardj8d965312005-02-25 02:48:47 +00008036/* All lanes SSE binary operation, G = (not G) `op` E. */
8037
8038static
sewardj2e28ac42008-12-04 00:05:12 +00008039ULong dis_SSE_E_to_G_all_invG ( VexAbiInfo* vbi,
8040 Prefix pfx, Long delta,
sewardj8d965312005-02-25 02:48:47 +00008041 HChar* opname, IROp op )
8042{
sewardj2e28ac42008-12-04 00:05:12 +00008043 return dis_SSE_E_to_G_all_wrk( vbi, pfx, delta, opname, op, True );
sewardj8d965312005-02-25 02:48:47 +00008044}
8045
8046
8047/* Lowest 32-bit lane only SSE binary operation, G = G `op` E. */
8048
sewardj2e28ac42008-12-04 00:05:12 +00008049static ULong dis_SSE_E_to_G_lo32 ( VexAbiInfo* vbi,
8050 Prefix pfx, Long delta,
sewardj8d965312005-02-25 02:48:47 +00008051 HChar* opname, IROp op )
8052{
8053 HChar dis_buf[50];
8054 Int alen;
8055 IRTemp addr;
8056 UChar rm = getUChar(delta);
sewardj9c9ee3d2005-02-26 01:17:42 +00008057 IRExpr* gpart = getXMMReg(gregOfRexRM(pfx,rm));
sewardj8d965312005-02-25 02:48:47 +00008058 if (epartIsReg(rm)) {
sewardj9c9ee3d2005-02-26 01:17:42 +00008059 putXMMReg( gregOfRexRM(pfx,rm),
sewardj8d965312005-02-25 02:48:47 +00008060 binop(op, gpart,
8061 getXMMReg(eregOfRexRM(pfx,rm))) );
8062 DIP("%s %s,%s\n", opname,
8063 nameXMMReg(eregOfRexRM(pfx,rm)),
8064 nameXMMReg(gregOfRexRM(pfx,rm)) );
8065 return delta+1;
8066 } else {
8067 /* We can only do a 32-bit memory read, so the upper 3/4 of the
8068 E operand needs to be made simply of zeroes. */
8069 IRTemp epart = newTemp(Ity_V128);
sewardj2e28ac42008-12-04 00:05:12 +00008070 addr = disAMode ( &alen, vbi, pfx, delta, dis_buf, 0 );
sewardj8d965312005-02-25 02:48:47 +00008071 assign( epart, unop( Iop_32UtoV128,
8072 loadLE(Ity_I32, mkexpr(addr))) );
8073 putXMMReg( gregOfRexRM(pfx,rm),
8074 binop(op, gpart, mkexpr(epart)) );
8075 DIP("%s %s,%s\n", opname,
8076 dis_buf,
8077 nameXMMReg(gregOfRexRM(pfx,rm)) );
8078 return delta+alen;
8079 }
8080}
sewardj1001dc42005-02-21 08:25:55 +00008081
8082
8083/* Lower 64-bit lane only SSE binary operation, G = G `op` E. */
8084
sewardj2e28ac42008-12-04 00:05:12 +00008085static ULong dis_SSE_E_to_G_lo64 ( VexAbiInfo* vbi,
8086 Prefix pfx, Long delta,
sewardj8d965312005-02-25 02:48:47 +00008087 HChar* opname, IROp op )
sewardj1001dc42005-02-21 08:25:55 +00008088{
8089 HChar dis_buf[50];
8090 Int alen;
8091 IRTemp addr;
8092 UChar rm = getUChar(delta);
8093 IRExpr* gpart = getXMMReg(gregOfRexRM(pfx,rm));
8094 if (epartIsReg(rm)) {
8095 putXMMReg( gregOfRexRM(pfx,rm),
8096 binop(op, gpart,
8097 getXMMReg(eregOfRexRM(pfx,rm))) );
8098 DIP("%s %s,%s\n", opname,
8099 nameXMMReg(eregOfRexRM(pfx,rm)),
8100 nameXMMReg(gregOfRexRM(pfx,rm)) );
8101 return delta+1;
8102 } else {
8103 /* We can only do a 64-bit memory read, so the upper half of the
8104 E operand needs to be made simply of zeroes. */
8105 IRTemp epart = newTemp(Ity_V128);
sewardj2e28ac42008-12-04 00:05:12 +00008106 addr = disAMode ( &alen, vbi, pfx, delta, dis_buf, 0 );
sewardj1001dc42005-02-21 08:25:55 +00008107 assign( epart, unop( Iop_64UtoV128,
8108 loadLE(Ity_I64, mkexpr(addr))) );
8109 putXMMReg( gregOfRexRM(pfx,rm),
8110 binop(op, gpart, mkexpr(epart)) );
8111 DIP("%s %s,%s\n", opname,
8112 dis_buf,
8113 nameXMMReg(gregOfRexRM(pfx,rm)) );
8114 return delta+alen;
8115 }
8116}
8117
8118
sewardja7ba8c42005-05-10 20:08:34 +00008119/* All lanes unary SSE operation, G = op(E). */
8120
8121static ULong dis_SSE_E_to_G_unary_all (
sewardj2e28ac42008-12-04 00:05:12 +00008122 VexAbiInfo* vbi,
sewardj270def42005-07-03 01:03:01 +00008123 Prefix pfx, Long delta,
sewardja7ba8c42005-05-10 20:08:34 +00008124 HChar* opname, IROp op
8125 )
8126{
8127 HChar dis_buf[50];
8128 Int alen;
8129 IRTemp addr;
8130 UChar rm = getUChar(delta);
8131 if (epartIsReg(rm)) {
8132 putXMMReg( gregOfRexRM(pfx,rm),
8133 unop(op, getXMMReg(eregOfRexRM(pfx,rm))) );
8134 DIP("%s %s,%s\n", opname,
8135 nameXMMReg(eregOfRexRM(pfx,rm)),
8136 nameXMMReg(gregOfRexRM(pfx,rm)) );
8137 return delta+1;
8138 } else {
sewardj2e28ac42008-12-04 00:05:12 +00008139 addr = disAMode ( &alen, vbi, pfx, delta, dis_buf, 0 );
sewardja7ba8c42005-05-10 20:08:34 +00008140 putXMMReg( gregOfRexRM(pfx,rm),
8141 unop(op, loadLE(Ity_V128, mkexpr(addr))) );
8142 DIP("%s %s,%s\n", opname,
8143 dis_buf,
8144 nameXMMReg(gregOfRexRM(pfx,rm)) );
8145 return delta+alen;
8146 }
8147}
8148
8149
8150/* Lowest 32-bit lane only unary SSE operation, G = op(E). */
8151
8152static ULong dis_SSE_E_to_G_unary_lo32 (
sewardj2e28ac42008-12-04 00:05:12 +00008153 VexAbiInfo* vbi,
sewardj270def42005-07-03 01:03:01 +00008154 Prefix pfx, Long delta,
sewardja7ba8c42005-05-10 20:08:34 +00008155 HChar* opname, IROp op
8156 )
8157{
8158 /* First we need to get the old G value and patch the low 32 bits
8159 of the E operand into it. Then apply op and write back to G. */
8160 HChar dis_buf[50];
8161 Int alen;
8162 IRTemp addr;
8163 UChar rm = getUChar(delta);
8164 IRTemp oldG0 = newTemp(Ity_V128);
8165 IRTemp oldG1 = newTemp(Ity_V128);
8166
8167 assign( oldG0, getXMMReg(gregOfRexRM(pfx,rm)) );
8168
8169 if (epartIsReg(rm)) {
8170 assign( oldG1,
8171 binop( Iop_SetV128lo32,
8172 mkexpr(oldG0),
8173 getXMMRegLane32(eregOfRexRM(pfx,rm), 0)) );
8174 putXMMReg( gregOfRexRM(pfx,rm), unop(op, mkexpr(oldG1)) );
8175 DIP("%s %s,%s\n", opname,
8176 nameXMMReg(eregOfRexRM(pfx,rm)),
8177 nameXMMReg(gregOfRexRM(pfx,rm)) );
8178 return delta+1;
8179 } else {
sewardj2e28ac42008-12-04 00:05:12 +00008180 addr = disAMode ( &alen, vbi, pfx, delta, dis_buf, 0 );
sewardja7ba8c42005-05-10 20:08:34 +00008181 assign( oldG1,
8182 binop( Iop_SetV128lo32,
8183 mkexpr(oldG0),
8184 loadLE(Ity_I32, mkexpr(addr)) ));
8185 putXMMReg( gregOfRexRM(pfx,rm), unop(op, mkexpr(oldG1)) );
8186 DIP("%s %s,%s\n", opname,
8187 dis_buf,
8188 nameXMMReg(gregOfRexRM(pfx,rm)) );
8189 return delta+alen;
8190 }
8191}
sewardj1001dc42005-02-21 08:25:55 +00008192
8193
8194/* Lowest 64-bit lane only unary SSE operation, G = op(E). */
8195
sewardj8d965312005-02-25 02:48:47 +00008196static ULong dis_SSE_E_to_G_unary_lo64 (
sewardj2e28ac42008-12-04 00:05:12 +00008197 VexAbiInfo* vbi,
sewardj270def42005-07-03 01:03:01 +00008198 Prefix pfx, Long delta,
sewardj8d965312005-02-25 02:48:47 +00008199 HChar* opname, IROp op
8200 )
sewardj1001dc42005-02-21 08:25:55 +00008201{
8202 /* First we need to get the old G value and patch the low 64 bits
8203 of the E operand into it. Then apply op and write back to G. */
8204 HChar dis_buf[50];
8205 Int alen;
8206 IRTemp addr;
8207 UChar rm = getUChar(delta);
8208 IRTemp oldG0 = newTemp(Ity_V128);
8209 IRTemp oldG1 = newTemp(Ity_V128);
8210
8211 assign( oldG0, getXMMReg(gregOfRexRM(pfx,rm)) );
8212
8213 if (epartIsReg(rm)) {
8214 assign( oldG1,
8215 binop( Iop_SetV128lo64,
8216 mkexpr(oldG0),
8217 getXMMRegLane64(eregOfRexRM(pfx,rm), 0)) );
8218 putXMMReg( gregOfRexRM(pfx,rm), unop(op, mkexpr(oldG1)) );
8219 DIP("%s %s,%s\n", opname,
8220 nameXMMReg(eregOfRexRM(pfx,rm)),
8221 nameXMMReg(gregOfRexRM(pfx,rm)) );
8222 return delta+1;
8223 } else {
sewardj2e28ac42008-12-04 00:05:12 +00008224 addr = disAMode ( &alen, vbi, pfx, delta, dis_buf, 0 );
sewardj1001dc42005-02-21 08:25:55 +00008225 assign( oldG1,
8226 binop( Iop_SetV128lo64,
8227 mkexpr(oldG0),
8228 loadLE(Ity_I64, mkexpr(addr)) ));
8229 putXMMReg( gregOfRexRM(pfx,rm), unop(op, mkexpr(oldG1)) );
8230 DIP("%s %s,%s\n", opname,
8231 dis_buf,
8232 nameXMMReg(gregOfRexRM(pfx,rm)) );
8233 return delta+alen;
8234 }
8235}
8236
8237
sewardj09717342005-05-05 21:34:02 +00008238/* SSE integer binary operation:
8239 G = G `op` E (eLeft == False)
8240 G = E `op` G (eLeft == True)
8241*/
8242static ULong dis_SSEint_E_to_G(
sewardj2e28ac42008-12-04 00:05:12 +00008243 VexAbiInfo* vbi,
sewardj270def42005-07-03 01:03:01 +00008244 Prefix pfx, Long delta,
sewardj09717342005-05-05 21:34:02 +00008245 HChar* opname, IROp op,
8246 Bool eLeft
8247 )
8248{
8249 HChar dis_buf[50];
8250 Int alen;
8251 IRTemp addr;
8252 UChar rm = getUChar(delta);
8253 IRExpr* gpart = getXMMReg(gregOfRexRM(pfx,rm));
8254 IRExpr* epart = NULL;
8255 if (epartIsReg(rm)) {
8256 epart = getXMMReg(eregOfRexRM(pfx,rm));
8257 DIP("%s %s,%s\n", opname,
8258 nameXMMReg(eregOfRexRM(pfx,rm)),
8259 nameXMMReg(gregOfRexRM(pfx,rm)) );
8260 delta += 1;
8261 } else {
sewardj2e28ac42008-12-04 00:05:12 +00008262 addr = disAMode ( &alen, vbi, pfx, delta, dis_buf, 0 );
sewardj09717342005-05-05 21:34:02 +00008263 epart = loadLE(Ity_V128, mkexpr(addr));
8264 DIP("%s %s,%s\n", opname,
8265 dis_buf,
8266 nameXMMReg(gregOfRexRM(pfx,rm)) );
8267 delta += alen;
8268 }
8269 putXMMReg( gregOfRexRM(pfx,rm),
8270 eLeft ? binop(op, epart, gpart)
8271 : binop(op, gpart, epart) );
8272 return delta;
8273}
sewardj8d965312005-02-25 02:48:47 +00008274
8275
8276/* Helper for doing SSE FP comparisons. */
8277
8278static void findSSECmpOp ( Bool* needNot, IROp* op,
8279 Int imm8, Bool all_lanes, Int sz )
8280{
8281 imm8 &= 7;
8282 *needNot = False;
8283 *op = Iop_INVALID;
8284 if (imm8 >= 4) {
8285 *needNot = True;
8286 imm8 -= 4;
8287 }
8288
8289 if (sz == 4 && all_lanes) {
8290 switch (imm8) {
8291 case 0: *op = Iop_CmpEQ32Fx4; return;
8292 case 1: *op = Iop_CmpLT32Fx4; return;
8293 case 2: *op = Iop_CmpLE32Fx4; return;
8294 case 3: *op = Iop_CmpUN32Fx4; return;
8295 default: break;
8296 }
8297 }
8298 if (sz == 4 && !all_lanes) {
8299 switch (imm8) {
8300 case 0: *op = Iop_CmpEQ32F0x4; return;
8301 case 1: *op = Iop_CmpLT32F0x4; return;
8302 case 2: *op = Iop_CmpLE32F0x4; return;
8303 case 3: *op = Iop_CmpUN32F0x4; return;
8304 default: break;
8305 }
8306 }
8307 if (sz == 8 && all_lanes) {
8308 switch (imm8) {
8309 case 0: *op = Iop_CmpEQ64Fx2; return;
8310 case 1: *op = Iop_CmpLT64Fx2; return;
8311 case 2: *op = Iop_CmpLE64Fx2; return;
8312 case 3: *op = Iop_CmpUN64Fx2; return;
8313 default: break;
8314 }
8315 }
8316 if (sz == 8 && !all_lanes) {
8317 switch (imm8) {
8318 case 0: *op = Iop_CmpEQ64F0x2; return;
8319 case 1: *op = Iop_CmpLT64F0x2; return;
8320 case 2: *op = Iop_CmpLE64F0x2; return;
8321 case 3: *op = Iop_CmpUN64F0x2; return;
8322 default: break;
8323 }
8324 }
8325 vpanic("findSSECmpOp(amd64,guest)");
8326}
8327
sewardjab9055b2006-01-01 13:17:38 +00008328/* Handles SSE 32F/64F comparisons. */
sewardj8d965312005-02-25 02:48:47 +00008329
sewardj2e28ac42008-12-04 00:05:12 +00008330static ULong dis_SSEcmp_E_to_G ( VexAbiInfo* vbi,
8331 Prefix pfx, Long delta,
sewardj8d965312005-02-25 02:48:47 +00008332 HChar* opname, Bool all_lanes, Int sz )
8333{
8334 HChar dis_buf[50];
8335 Int alen, imm8;
8336 IRTemp addr;
8337 Bool needNot = False;
8338 IROp op = Iop_INVALID;
8339 IRTemp plain = newTemp(Ity_V128);
8340 UChar rm = getUChar(delta);
8341 UShort mask = 0;
8342 vassert(sz == 4 || sz == 8);
8343 if (epartIsReg(rm)) {
8344 imm8 = getUChar(delta+1);
8345 findSSECmpOp(&needNot, &op, imm8, all_lanes, sz);
8346 assign( plain, binop(op, getXMMReg(gregOfRexRM(pfx,rm)),
8347 getXMMReg(eregOfRexRM(pfx,rm))) );
8348 delta += 2;
8349 DIP("%s $%d,%s,%s\n", opname,
8350 (Int)imm8,
8351 nameXMMReg(eregOfRexRM(pfx,rm)),
8352 nameXMMReg(gregOfRexRM(pfx,rm)) );
8353 } else {
sewardj2e28ac42008-12-04 00:05:12 +00008354 addr = disAMode ( &alen, vbi, pfx, delta, dis_buf, 1 );
sewardj8d965312005-02-25 02:48:47 +00008355 imm8 = getUChar(delta+alen);
8356 findSSECmpOp(&needNot, &op, imm8, all_lanes, sz);
sewardjab9055b2006-01-01 13:17:38 +00008357 assign( plain,
8358 binop(
8359 op,
8360 getXMMReg(gregOfRexRM(pfx,rm)),
8361 all_lanes ? loadLE(Ity_V128, mkexpr(addr))
8362 : sz == 8 ? unop( Iop_64UtoV128, loadLE(Ity_I64, mkexpr(addr)))
8363 : /*sz==4*/ unop( Iop_32UtoV128, loadLE(Ity_I32, mkexpr(addr)))
8364 )
8365 );
sewardj8d965312005-02-25 02:48:47 +00008366 delta += alen+1;
8367 DIP("%s $%d,%s,%s\n", opname,
8368 (Int)imm8,
8369 dis_buf,
8370 nameXMMReg(gregOfRexRM(pfx,rm)) );
8371 }
8372
8373 if (needNot && all_lanes) {
sewardj9c9ee3d2005-02-26 01:17:42 +00008374 putXMMReg( gregOfRexRM(pfx,rm),
sewardj8d965312005-02-25 02:48:47 +00008375 unop(Iop_NotV128, mkexpr(plain)) );
8376 }
8377 else
8378 if (needNot && !all_lanes) {
sewardj1027dc22005-02-26 01:55:02 +00008379 mask = toUShort(sz==4 ? 0x000F : 0x00FF);
sewardj8d965312005-02-25 02:48:47 +00008380 putXMMReg( gregOfRexRM(pfx,rm),
8381 binop(Iop_XorV128, mkexpr(plain), mkV128(mask)) );
8382 }
8383 else {
8384 putXMMReg( gregOfRexRM(pfx,rm), mkexpr(plain) );
8385 }
8386
8387 return delta;
8388}
8389
8390
sewardjadffcef2005-05-11 00:03:06 +00008391/* Vector by scalar shift of G by the amount specified at the bottom
8392 of E. */
8393
sewardj2e28ac42008-12-04 00:05:12 +00008394static ULong dis_SSE_shiftG_byE ( VexAbiInfo* vbi,
8395 Prefix pfx, Long delta,
sewardjadffcef2005-05-11 00:03:06 +00008396 HChar* opname, IROp op )
8397{
8398 HChar dis_buf[50];
8399 Int alen, size;
8400 IRTemp addr;
8401 Bool shl, shr, sar;
8402 UChar rm = getUChar(delta);
8403 IRTemp g0 = newTemp(Ity_V128);
8404 IRTemp g1 = newTemp(Ity_V128);
8405 IRTemp amt = newTemp(Ity_I32);
8406 IRTemp amt8 = newTemp(Ity_I8);
8407 if (epartIsReg(rm)) {
8408 assign( amt, getXMMRegLane32(eregOfRexRM(pfx,rm), 0) );
8409 DIP("%s %s,%s\n", opname,
8410 nameXMMReg(eregOfRexRM(pfx,rm)),
8411 nameXMMReg(gregOfRexRM(pfx,rm)) );
8412 delta++;
8413 } else {
sewardj2e28ac42008-12-04 00:05:12 +00008414 addr = disAMode ( &alen, vbi, pfx, delta, dis_buf, 0 );
sewardjadffcef2005-05-11 00:03:06 +00008415 assign( amt, loadLE(Ity_I32, mkexpr(addr)) );
8416 DIP("%s %s,%s\n", opname,
8417 dis_buf,
8418 nameXMMReg(gregOfRexRM(pfx,rm)) );
8419 delta += alen;
8420 }
8421 assign( g0, getXMMReg(gregOfRexRM(pfx,rm)) );
8422 assign( amt8, unop(Iop_32to8, mkexpr(amt)) );
8423
8424 shl = shr = sar = False;
8425 size = 0;
8426 switch (op) {
8427 case Iop_ShlN16x8: shl = True; size = 32; break;
8428 case Iop_ShlN32x4: shl = True; size = 32; break;
8429 case Iop_ShlN64x2: shl = True; size = 64; break;
8430 case Iop_SarN16x8: sar = True; size = 16; break;
8431 case Iop_SarN32x4: sar = True; size = 32; break;
8432 case Iop_ShrN16x8: shr = True; size = 16; break;
8433 case Iop_ShrN32x4: shr = True; size = 32; break;
8434 case Iop_ShrN64x2: shr = True; size = 64; break;
8435 default: vassert(0);
8436 }
8437
8438 if (shl || shr) {
8439 assign(
8440 g1,
8441 IRExpr_Mux0X(
8442 unop(Iop_1Uto8,
8443 binop(Iop_CmpLT64U, unop(Iop_32Uto64,mkexpr(amt)), mkU64(size))),
8444 mkV128(0x0000),
8445 binop(op, mkexpr(g0), mkexpr(amt8))
8446 )
8447 );
8448 } else
8449 if (sar) {
8450 assign(
8451 g1,
8452 IRExpr_Mux0X(
8453 unop(Iop_1Uto8,
8454 binop(Iop_CmpLT64U, unop(Iop_32Uto64,mkexpr(amt)), mkU64(size))),
8455 binop(op, mkexpr(g0), mkU8(size-1)),
8456 binop(op, mkexpr(g0), mkexpr(amt8))
8457 )
8458 );
8459 } else {
8460 vassert(0);
8461 }
8462
8463 putXMMReg( gregOfRexRM(pfx,rm), mkexpr(g1) );
8464 return delta;
8465}
sewardj09717342005-05-05 21:34:02 +00008466
8467
8468/* Vector by scalar shift of E by an immediate byte. */
8469
8470static
8471ULong dis_SSE_shiftE_imm ( Prefix pfx,
sewardj270def42005-07-03 01:03:01 +00008472 Long delta, HChar* opname, IROp op )
sewardj09717342005-05-05 21:34:02 +00008473{
8474 Bool shl, shr, sar;
8475 UChar rm = getUChar(delta);
8476 IRTemp e0 = newTemp(Ity_V128);
8477 IRTemp e1 = newTemp(Ity_V128);
8478 UChar amt, size;
8479 vassert(epartIsReg(rm));
8480 vassert(gregLO3ofRM(rm) == 2
8481 || gregLO3ofRM(rm) == 4 || gregLO3ofRM(rm) == 6);
sewardjca673ab2005-05-11 10:03:08 +00008482 amt = getUChar(delta+1);
sewardj09717342005-05-05 21:34:02 +00008483 delta += 2;
8484 DIP("%s $%d,%s\n", opname,
8485 (Int)amt,
8486 nameXMMReg(eregOfRexRM(pfx,rm)) );
8487 assign( e0, getXMMReg(eregOfRexRM(pfx,rm)) );
8488
8489 shl = shr = sar = False;
8490 size = 0;
8491 switch (op) {
8492 case Iop_ShlN16x8: shl = True; size = 16; break;
8493 case Iop_ShlN32x4: shl = True; size = 32; break;
8494 case Iop_ShlN64x2: shl = True; size = 64; break;
8495 case Iop_SarN16x8: sar = True; size = 16; break;
8496 case Iop_SarN32x4: sar = True; size = 32; break;
8497 case Iop_ShrN16x8: shr = True; size = 16; break;
8498 case Iop_ShrN32x4: shr = True; size = 32; break;
8499 case Iop_ShrN64x2: shr = True; size = 64; break;
8500 default: vassert(0);
8501 }
8502
8503 if (shl || shr) {
8504 assign( e1, amt >= size
8505 ? mkV128(0x0000)
8506 : binop(op, mkexpr(e0), mkU8(amt))
8507 );
8508 } else
8509 if (sar) {
8510 assign( e1, amt >= size
8511 ? binop(op, mkexpr(e0), mkU8(size-1))
8512 : binop(op, mkexpr(e0), mkU8(amt))
8513 );
8514 } else {
8515 vassert(0);
8516 }
8517
8518 putXMMReg( eregOfRexRM(pfx,rm), mkexpr(e1) );
8519 return delta;
8520}
sewardj1a01e652005-02-23 11:39:21 +00008521
8522
8523/* Get the current SSE rounding mode. */
8524
8525static IRExpr* /* :: Ity_I32 */ get_sse_roundingmode ( void )
8526{
8527 return
8528 unop( Iop_64to32,
8529 binop( Iop_And64,
8530 IRExpr_Get( OFFB_SSEROUND, Ity_I64 ),
8531 mkU64(3) ));
8532}
8533
sewardjbcbb9de2005-03-27 02:22:32 +00008534static void put_sse_roundingmode ( IRExpr* sseround )
8535{
sewardjdd40fdf2006-12-24 02:20:24 +00008536 vassert(typeOfIRExpr(irsb->tyenv, sseround) == Ity_I32);
sewardjbcbb9de2005-03-27 02:22:32 +00008537 stmt( IRStmt_Put( OFFB_SSEROUND,
8538 unop(Iop_32Uto64,sseround) ) );
8539}
8540
sewardja7ba8c42005-05-10 20:08:34 +00008541/* Break a 128-bit value up into four 32-bit ints. */
8542
8543static void breakup128to32s ( IRTemp t128,
8544 /*OUTs*/
8545 IRTemp* t3, IRTemp* t2,
8546 IRTemp* t1, IRTemp* t0 )
8547{
8548 IRTemp hi64 = newTemp(Ity_I64);
8549 IRTemp lo64 = newTemp(Ity_I64);
8550 assign( hi64, unop(Iop_V128HIto64, mkexpr(t128)) );
8551 assign( lo64, unop(Iop_V128to64, mkexpr(t128)) );
8552
8553 vassert(t0 && *t0 == IRTemp_INVALID);
8554 vassert(t1 && *t1 == IRTemp_INVALID);
8555 vassert(t2 && *t2 == IRTemp_INVALID);
8556 vassert(t3 && *t3 == IRTemp_INVALID);
8557
8558 *t0 = newTemp(Ity_I32);
8559 *t1 = newTemp(Ity_I32);
8560 *t2 = newTemp(Ity_I32);
8561 *t3 = newTemp(Ity_I32);
8562 assign( *t0, unop(Iop_64to32, mkexpr(lo64)) );
8563 assign( *t1, unop(Iop_64HIto32, mkexpr(lo64)) );
8564 assign( *t2, unop(Iop_64to32, mkexpr(hi64)) );
8565 assign( *t3, unop(Iop_64HIto32, mkexpr(hi64)) );
8566}
8567
8568/* Construct a 128-bit value from four 32-bit ints. */
8569
8570static IRExpr* mk128from32s ( IRTemp t3, IRTemp t2,
8571 IRTemp t1, IRTemp t0 )
8572{
8573 return
8574 binop( Iop_64HLtoV128,
8575 binop(Iop_32HLto64, mkexpr(t3), mkexpr(t2)),
8576 binop(Iop_32HLto64, mkexpr(t1), mkexpr(t0))
8577 );
8578}
8579
8580/* Break a 64-bit value up into four 16-bit ints. */
8581
8582static void breakup64to16s ( IRTemp t64,
8583 /*OUTs*/
8584 IRTemp* t3, IRTemp* t2,
8585 IRTemp* t1, IRTemp* t0 )
8586{
8587 IRTemp hi32 = newTemp(Ity_I32);
8588 IRTemp lo32 = newTemp(Ity_I32);
8589 assign( hi32, unop(Iop_64HIto32, mkexpr(t64)) );
8590 assign( lo32, unop(Iop_64to32, mkexpr(t64)) );
8591
8592 vassert(t0 && *t0 == IRTemp_INVALID);
8593 vassert(t1 && *t1 == IRTemp_INVALID);
8594 vassert(t2 && *t2 == IRTemp_INVALID);
8595 vassert(t3 && *t3 == IRTemp_INVALID);
8596
8597 *t0 = newTemp(Ity_I16);
8598 *t1 = newTemp(Ity_I16);
8599 *t2 = newTemp(Ity_I16);
8600 *t3 = newTemp(Ity_I16);
8601 assign( *t0, unop(Iop_32to16, mkexpr(lo32)) );
8602 assign( *t1, unop(Iop_32HIto16, mkexpr(lo32)) );
8603 assign( *t2, unop(Iop_32to16, mkexpr(hi32)) );
8604 assign( *t3, unop(Iop_32HIto16, mkexpr(hi32)) );
8605}
8606
8607/* Construct a 64-bit value from four 16-bit ints. */
8608
8609static IRExpr* mk64from16s ( IRTemp t3, IRTemp t2,
8610 IRTemp t1, IRTemp t0 )
8611{
8612 return
8613 binop( Iop_32HLto64,
8614 binop(Iop_16HLto32, mkexpr(t3), mkexpr(t2)),
8615 binop(Iop_16HLto32, mkexpr(t1), mkexpr(t0))
8616 );
8617}
sewardjdf0e0022005-01-25 15:48:43 +00008618
8619
sewardjd166e282008-02-06 11:42:45 +00008620/* Helper for the SSSE3 (not SSE3) PMULHRSW insns. Given two 64-bit
8621 values (aa,bb), computes, for each of the 4 16-bit lanes:
8622
8623 (((aa_lane *s32 bb_lane) >>u 14) + 1) >>u 1
8624*/
8625static IRExpr* dis_PMULHRSW_helper ( IRExpr* aax, IRExpr* bbx )
8626{
8627 IRTemp aa = newTemp(Ity_I64);
8628 IRTemp bb = newTemp(Ity_I64);
8629 IRTemp aahi32s = newTemp(Ity_I64);
8630 IRTemp aalo32s = newTemp(Ity_I64);
8631 IRTemp bbhi32s = newTemp(Ity_I64);
8632 IRTemp bblo32s = newTemp(Ity_I64);
8633 IRTemp rHi = newTemp(Ity_I64);
8634 IRTemp rLo = newTemp(Ity_I64);
8635 IRTemp one32x2 = newTemp(Ity_I64);
8636 assign(aa, aax);
8637 assign(bb, bbx);
8638 assign( aahi32s,
8639 binop(Iop_SarN32x2,
8640 binop(Iop_InterleaveHI16x4, mkexpr(aa), mkexpr(aa)),
8641 mkU8(16) ));
8642 assign( aalo32s,
8643 binop(Iop_SarN32x2,
8644 binop(Iop_InterleaveLO16x4, mkexpr(aa), mkexpr(aa)),
8645 mkU8(16) ));
8646 assign( bbhi32s,
8647 binop(Iop_SarN32x2,
8648 binop(Iop_InterleaveHI16x4, mkexpr(bb), mkexpr(bb)),
8649 mkU8(16) ));
8650 assign( bblo32s,
8651 binop(Iop_SarN32x2,
8652 binop(Iop_InterleaveLO16x4, mkexpr(bb), mkexpr(bb)),
8653 mkU8(16) ));
8654 assign(one32x2, mkU64( (1ULL << 32) + 1 ));
8655 assign(
8656 rHi,
8657 binop(
8658 Iop_ShrN32x2,
8659 binop(
8660 Iop_Add32x2,
8661 binop(
8662 Iop_ShrN32x2,
8663 binop(Iop_Mul32x2, mkexpr(aahi32s), mkexpr(bbhi32s)),
8664 mkU8(14)
8665 ),
8666 mkexpr(one32x2)
8667 ),
8668 mkU8(1)
8669 )
8670 );
8671 assign(
8672 rLo,
8673 binop(
8674 Iop_ShrN32x2,
8675 binop(
8676 Iop_Add32x2,
8677 binop(
8678 Iop_ShrN32x2,
8679 binop(Iop_Mul32x2, mkexpr(aalo32s), mkexpr(bblo32s)),
8680 mkU8(14)
8681 ),
8682 mkexpr(one32x2)
8683 ),
8684 mkU8(1)
8685 )
8686 );
8687 return
8688 binop(Iop_CatEvenLanes16x4, mkexpr(rHi), mkexpr(rLo));
8689}
8690
8691/* Helper for the SSSE3 (not SSE3) PSIGN{B,W,D} insns. Given two 64-bit
8692 values (aa,bb), computes, for each lane:
8693
8694 if aa_lane < 0 then - bb_lane
8695 else if aa_lane > 0 then bb_lane
8696 else 0
8697*/
8698static IRExpr* dis_PSIGN_helper ( IRExpr* aax, IRExpr* bbx, Int laneszB )
8699{
8700 IRTemp aa = newTemp(Ity_I64);
8701 IRTemp bb = newTemp(Ity_I64);
8702 IRTemp zero = newTemp(Ity_I64);
8703 IRTemp bbNeg = newTemp(Ity_I64);
8704 IRTemp negMask = newTemp(Ity_I64);
8705 IRTemp posMask = newTemp(Ity_I64);
8706 IROp opSub = Iop_INVALID;
8707 IROp opCmpGTS = Iop_INVALID;
8708
8709 switch (laneszB) {
8710 case 1: opSub = Iop_Sub8x8; opCmpGTS = Iop_CmpGT8Sx8; break;
8711 case 2: opSub = Iop_Sub16x4; opCmpGTS = Iop_CmpGT16Sx4; break;
8712 case 4: opSub = Iop_Sub32x2; opCmpGTS = Iop_CmpGT32Sx2; break;
8713 default: vassert(0);
8714 }
8715
8716 assign( aa, aax );
8717 assign( bb, bbx );
8718 assign( zero, mkU64(0) );
8719 assign( bbNeg, binop(opSub, mkexpr(zero), mkexpr(bb)) );
8720 assign( negMask, binop(opCmpGTS, mkexpr(zero), mkexpr(aa)) );
8721 assign( posMask, binop(opCmpGTS, mkexpr(aa), mkexpr(zero)) );
8722
8723 return
8724 binop(Iop_Or64,
8725 binop(Iop_And64, mkexpr(bb), mkexpr(posMask)),
8726 binop(Iop_And64, mkexpr(bbNeg), mkexpr(negMask)) );
8727
8728}
8729
8730/* Helper for the SSSE3 (not SSE3) PABS{B,W,D} insns. Given a 64-bit
8731 value aa, computes, for each lane
8732
8733 if aa < 0 then -aa else aa
8734
8735 Note that the result is interpreted as unsigned, so that the
8736 absolute value of the most negative signed input can be
8737 represented.
8738*/
8739static IRExpr* dis_PABS_helper ( IRExpr* aax, Int laneszB )
8740{
8741 IRTemp aa = newTemp(Ity_I64);
8742 IRTemp zero = newTemp(Ity_I64);
8743 IRTemp aaNeg = newTemp(Ity_I64);
8744 IRTemp negMask = newTemp(Ity_I64);
8745 IRTemp posMask = newTemp(Ity_I64);
8746 IROp opSub = Iop_INVALID;
8747 IROp opSarN = Iop_INVALID;
8748
8749 switch (laneszB) {
8750 case 1: opSub = Iop_Sub8x8; opSarN = Iop_SarN8x8; break;
8751 case 2: opSub = Iop_Sub16x4; opSarN = Iop_SarN16x4; break;
8752 case 4: opSub = Iop_Sub32x2; opSarN = Iop_SarN32x2; break;
8753 default: vassert(0);
8754 }
8755
8756 assign( aa, aax );
8757 assign( negMask, binop(opSarN, mkexpr(aa), mkU8(8*laneszB-1)) );
8758 assign( posMask, unop(Iop_Not64, mkexpr(negMask)) );
8759 assign( zero, mkU64(0) );
8760 assign( aaNeg, binop(opSub, mkexpr(zero), mkexpr(aa)) );
8761 return
8762 binop(Iop_Or64,
8763 binop(Iop_And64, mkexpr(aa), mkexpr(posMask)),
8764 binop(Iop_And64, mkexpr(aaNeg), mkexpr(negMask)) );
8765}
8766
8767static IRExpr* dis_PALIGNR_XMM_helper ( IRTemp hi64,
8768 IRTemp lo64, Long byteShift )
8769{
8770 vassert(byteShift >= 1 && byteShift <= 7);
8771 return
8772 binop(Iop_Or64,
8773 binop(Iop_Shl64, mkexpr(hi64), mkU8(8*(8-byteShift))),
8774 binop(Iop_Shr64, mkexpr(lo64), mkU8(8*byteShift))
8775 );
8776}
8777
sewardj150c9cd2008-02-09 01:16:02 +00008778/* Generate a SIGSEGV followed by a restart of the current instruction
8779 if effective_addr is not 16-aligned. This is required behaviour
8780 for some SSE3 instructions and all 128-bit SSSE3 instructions.
8781 This assumes that guest_RIP_curr_instr is set correctly! */
8782static void gen_SEGV_if_not_16_aligned ( IRTemp effective_addr )
8783{
8784 stmt(
8785 IRStmt_Exit(
8786 binop(Iop_CmpNE64,
8787 binop(Iop_And64,mkexpr(effective_addr),mkU64(0xF)),
8788 mkU64(0)),
8789 Ijk_SigSEGV,
8790 IRConst_U64(guest_RIP_curr_instr)
8791 )
8792 );
8793}
8794
sewardjd166e282008-02-06 11:42:45 +00008795
sewardjc4356f02007-11-09 21:15:04 +00008796/* Helper for deciding whether a given insn (starting at the opcode
8797 byte) may validly be used with a LOCK prefix. The following insns
8798 may be used with LOCK when their destination operand is in memory.
sewardje9d8a262009-07-01 08:06:34 +00008799 AFAICS this is exactly the same for both 32-bit and 64-bit mode.
sewardjc4356f02007-11-09 21:15:04 +00008800
sewardje9d8a262009-07-01 08:06:34 +00008801 ADD 80 /0, 81 /0, 82 /0, 83 /0, 00, 01
8802 OR 80 /1, 81 /1, 82 /x, 83 /1, 08, 09
8803 ADC 80 /2, 81 /2, 82 /2, 83 /2, 10, 11
8804 SBB 81 /3, 81 /3, 82 /x, 83 /3, 18, 19
8805 AND 80 /4, 81 /4, 82 /x, 83 /4, 20, 21
8806 SUB 80 /5, 81 /5, 82 /x, 83 /5, 28, 29
8807 XOR 80 /6, 81 /6, 82 /x, 83 /6, 30, 31
sewardjc4356f02007-11-09 21:15:04 +00008808
8809 DEC FE /1, FF /1
8810 INC FE /0, FF /0
8811
8812 NEG F6 /3, F7 /3
8813 NOT F6 /2, F7 /2
8814
sewardje9d8a262009-07-01 08:06:34 +00008815 XCHG 86, 87
sewardjc4356f02007-11-09 21:15:04 +00008816
8817 BTC 0F BB, 0F BA /7
8818 BTR 0F B3, 0F BA /6
8819 BTS 0F AB, 0F BA /5
8820
8821 CMPXCHG 0F B0, 0F B1
8822 CMPXCHG8B 0F C7 /1
8823
8824 XADD 0F C0, 0F C1
sewardje9d8a262009-07-01 08:06:34 +00008825
8826 ------------------------------
8827
8828 80 /0 = addb $imm8, rm8
8829 81 /0 = addl $imm32, rm32 and addw $imm16, rm16
8830 82 /0 = addb $imm8, rm8
8831 83 /0 = addl $simm8, rm32 and addw $simm8, rm16
8832
8833 00 = addb r8, rm8
8834 01 = addl r32, rm32 and addw r16, rm16
8835
8836 Same for ADD OR ADC SBB AND SUB XOR
8837
8838 FE /1 = dec rm8
8839 FF /1 = dec rm32 and dec rm16
8840
8841 FE /0 = inc rm8
8842 FF /0 = inc rm32 and inc rm16
8843
8844 F6 /3 = neg rm8
8845 F7 /3 = neg rm32 and neg rm16
8846
8847 F6 /2 = not rm8
8848 F7 /2 = not rm32 and not rm16
8849
8850 0F BB = btcw r16, rm16 and btcl r32, rm32
8851 OF BA /7 = btcw $imm8, rm16 and btcw $imm8, rm32
8852
8853 Same for BTS, BTR
sewardjc4356f02007-11-09 21:15:04 +00008854*/
8855static Bool can_be_used_with_LOCK_prefix ( UChar* opc )
8856{
8857 switch (opc[0]) {
sewardje9d8a262009-07-01 08:06:34 +00008858 case 0x00: case 0x01: case 0x08: case 0x09:
8859 case 0x10: case 0x11: case 0x18: case 0x19:
8860 case 0x20: case 0x21: case 0x28: case 0x29:
8861 case 0x30: case 0x31:
8862 if (!epartIsReg(opc[1]))
8863 return True;
8864 break;
sewardjc4356f02007-11-09 21:15:04 +00008865
sewardje9d8a262009-07-01 08:06:34 +00008866 case 0x80: case 0x81: case 0x82: case 0x83:
8867 if (gregLO3ofRM(opc[1]) >= 0 && gregLO3ofRM(opc[1]) <= 6
8868 && !epartIsReg(opc[1]))
sewardjc4356f02007-11-09 21:15:04 +00008869 return True;
8870 break;
8871
8872 case 0xFE: case 0xFF:
sewardje9d8a262009-07-01 08:06:34 +00008873 if (gregLO3ofRM(opc[1]) >= 0 && gregLO3ofRM(opc[1]) <= 1
8874 && !epartIsReg(opc[1]))
sewardjc4356f02007-11-09 21:15:04 +00008875 return True;
8876 break;
8877
8878 case 0xF6: case 0xF7:
sewardje9d8a262009-07-01 08:06:34 +00008879 if (gregLO3ofRM(opc[1]) >= 2 && gregLO3ofRM(opc[1]) <= 3
8880 && !epartIsReg(opc[1]))
sewardjc4356f02007-11-09 21:15:04 +00008881 return True;
8882 break;
8883
8884 case 0x86: case 0x87:
sewardje9d8a262009-07-01 08:06:34 +00008885 if (!epartIsReg(opc[1]))
8886 return True;
8887 break;
sewardjc4356f02007-11-09 21:15:04 +00008888
8889 case 0x0F: {
8890 switch (opc[1]) {
8891 case 0xBB: case 0xB3: case 0xAB:
sewardje9d8a262009-07-01 08:06:34 +00008892 if (!epartIsReg(opc[2]))
8893 return True;
8894 break;
sewardjc4356f02007-11-09 21:15:04 +00008895 case 0xBA:
sewardje9d8a262009-07-01 08:06:34 +00008896 if (gregLO3ofRM(opc[2]) >= 5 && gregLO3ofRM(opc[2]) <= 7
8897 && !epartIsReg(opc[2]))
sewardjc4356f02007-11-09 21:15:04 +00008898 return True;
8899 break;
8900 case 0xB0: case 0xB1:
sewardje9d8a262009-07-01 08:06:34 +00008901 if (!epartIsReg(opc[2]))
8902 return True;
8903 break;
sewardjc4356f02007-11-09 21:15:04 +00008904 case 0xC7:
sewardje9d8a262009-07-01 08:06:34 +00008905 if (gregLO3ofRM(opc[2]) == 1 && !epartIsReg(opc[2]) )
sewardjc4356f02007-11-09 21:15:04 +00008906 return True;
8907 break;
8908 case 0xC0: case 0xC1:
sewardje9d8a262009-07-01 08:06:34 +00008909 if (!epartIsReg(opc[2]))
8910 return True;
8911 break;
sewardjc4356f02007-11-09 21:15:04 +00008912 default:
8913 break;
8914 } /* switch (opc[1]) */
8915 break;
8916 }
8917
8918 default:
8919 break;
8920 } /* switch (opc[0]) */
8921
8922 return False;
8923}
8924
8925
sewardjdf0e0022005-01-25 15:48:43 +00008926/*------------------------------------------------------------*/
8927/*--- Disassemble a single instruction ---*/
8928/*------------------------------------------------------------*/
8929
sewardj9e6491a2005-07-02 19:24:10 +00008930/* Disassemble a single instruction into IR. The instruction is
8931 located in host memory at &guest_code[delta]. */
sewardjdf0e0022005-01-25 15:48:43 +00008932
sewardj9e6491a2005-07-02 19:24:10 +00008933static
8934DisResult disInstr_AMD64_WRK (
sewardje9d8a262009-07-01 08:06:34 +00008935 /*OUT*/Bool* expect_CAS,
sewardj9e6491a2005-07-02 19:24:10 +00008936 Bool put_IP,
sewardjc716aea2006-01-17 01:48:46 +00008937 Bool (*resteerOkFn) ( /*opaque*/void*, Addr64 ),
sewardj984d9b12010-01-15 10:53:21 +00008938 Bool resteerCisOk,
sewardjc716aea2006-01-17 01:48:46 +00008939 void* callback_opaque,
sewardj9e6491a2005-07-02 19:24:10 +00008940 Long delta64,
sewardjaca070a2006-10-17 00:28:22 +00008941 VexArchInfo* archinfo,
sewardj2e28ac42008-12-04 00:05:12 +00008942 VexAbiInfo* vbi
sewardj9e6491a2005-07-02 19:24:10 +00008943 )
sewardjdf0e0022005-01-25 15:48:43 +00008944{
8945 IRType ty;
sewardja7ba8c42005-05-10 20:08:34 +00008946 IRTemp addr, t0, t1, t2, t3, t4, t5, t6;
sewardjdf0e0022005-01-25 15:48:43 +00008947 Int alen;
sewardjbb4396c2007-11-20 17:29:08 +00008948 UChar opc, modrm, abyte, pre;
sewardj1027dc22005-02-26 01:55:02 +00008949 Long d64;
sewardjdf0e0022005-01-25 15:48:43 +00008950 HChar dis_buf[50];
8951 Int am_sz, d_sz, n, n_prefixes;
sewardj9e6491a2005-07-02 19:24:10 +00008952 DisResult dres;
sewardja6b93d12005-02-17 09:28:28 +00008953 UChar* insn; /* used in SSE decoders */
sewardjdf0e0022005-01-25 15:48:43 +00008954
sewardj9e6491a2005-07-02 19:24:10 +00008955 /* The running delta */
8956 Long delta = delta64;
8957
sewardjdf0e0022005-01-25 15:48:43 +00008958 /* Holds eip at the start of the insn, so that we can print
8959 consistent error messages for unimplemented insns. */
sewardj270def42005-07-03 01:03:01 +00008960 Long delta_start = delta;
sewardjdf0e0022005-01-25 15:48:43 +00008961
8962 /* sz denotes the nominal data-op size of the insn; we change it to
8963 2 if an 0x66 prefix is seen and 8 if REX.W is 1. In case of
8964 conflict REX.W takes precedence. */
8965 Int sz = 4;
8966
sewardj3ca55a12005-01-27 16:06:23 +00008967 /* pfx holds the summary of prefixes. */
8968 Prefix pfx = PFX_EMPTY;
sewardjdf0e0022005-01-25 15:48:43 +00008969
sewardj9e6491a2005-07-02 19:24:10 +00008970 /* Set result defaults. */
8971 dres.whatNext = Dis_Continue;
8972 dres.len = 0;
8973 dres.continueAt = 0;
sewardjdf0e0022005-01-25 15:48:43 +00008974
sewardje9d8a262009-07-01 08:06:34 +00008975 *expect_CAS = False;
8976
sewardj9e6491a2005-07-02 19:24:10 +00008977 vassert(guest_RIP_next_assumed == 0);
8978 vassert(guest_RIP_next_mustcheck == False);
sewardj4b744762005-02-07 15:02:25 +00008979
sewardja7ba8c42005-05-10 20:08:34 +00008980 addr = t0 = t1 = t2 = t3 = t4 = t5 = t6 = IRTemp_INVALID;
sewardjdf0e0022005-01-25 15:48:43 +00008981
sewardj9e6491a2005-07-02 19:24:10 +00008982 DIP("\t0x%llx: ", guest_RIP_bbstart+delta);
8983
8984 /* We may be asked to update the guest RIP before going further. */
8985 if (put_IP)
8986 stmt( IRStmt_Put( OFFB_RIP, mkU64(guest_RIP_curr_instr)) );
sewardjdf0e0022005-01-25 15:48:43 +00008987
sewardjce02aa72006-01-12 12:27:58 +00008988 /* Spot "Special" instructions (see comment at top of file). */
sewardjdf0e0022005-01-25 15:48:43 +00008989 {
8990 UChar* code = (UChar*)(guest_code + delta);
sewardjce02aa72006-01-12 12:27:58 +00008991 /* Spot the 16-byte preamble:
8992 48C1C703 rolq $3, %rdi
8993 48C1C70D rolq $13, %rdi
8994 48C1C73D rolq $61, %rdi
8995 48C1C733 rolq $51, %rdi
sewardjdf0e0022005-01-25 15:48:43 +00008996 */
sewardjce02aa72006-01-12 12:27:58 +00008997 if (code[ 0] == 0x48 && code[ 1] == 0xC1 && code[ 2] == 0xC7
8998 && code[ 3] == 0x03 &&
8999 code[ 4] == 0x48 && code[ 5] == 0xC1 && code[ 6] == 0xC7
9000 && code[ 7] == 0x0D &&
9001 code[ 8] == 0x48 && code[ 9] == 0xC1 && code[10] == 0xC7
9002 && code[11] == 0x3D &&
9003 code[12] == 0x48 && code[13] == 0xC1 && code[14] == 0xC7
9004 && code[15] == 0x33) {
9005 /* Got a "Special" instruction preamble. Which one is it? */
9006 if (code[16] == 0x48 && code[17] == 0x87
9007 && code[18] == 0xDB /* xchgq %rbx,%rbx */) {
9008 /* %RDX = client_request ( %RAX ) */
9009 DIP("%%rdx = client_request ( %%rax )\n");
9010 delta += 19;
9011 jmp_lit(Ijk_ClientReq, guest_RIP_bbstart+delta);
9012 dres.whatNext = Dis_StopHere;
9013 goto decode_success;
9014 }
9015 else
9016 if (code[16] == 0x48 && code[17] == 0x87
9017 && code[18] == 0xC9 /* xchgq %rcx,%rcx */) {
9018 /* %RAX = guest_NRADDR */
9019 DIP("%%rax = guest_NRADDR\n");
9020 delta += 19;
9021 putIRegRAX(8, IRExpr_Get( OFFB_NRADDR, Ity_I64 ));
9022 goto decode_success;
9023 }
9024 else
9025 if (code[16] == 0x48 && code[17] == 0x87
9026 && code[18] == 0xD2 /* xchgq %rdx,%rdx */) {
9027 /* call-noredir *%RAX */
9028 DIP("call-noredir *%%rax\n");
9029 delta += 19;
9030 t1 = newTemp(Ity_I64);
9031 assign(t1, getIRegRAX(8));
9032 t2 = newTemp(Ity_I64);
9033 assign(t2, binop(Iop_Sub64, getIReg64(R_RSP), mkU64(8)));
9034 putIReg64(R_RSP, mkexpr(t2));
9035 storeLE( mkexpr(t2), mkU64(guest_RIP_bbstart+delta));
9036 jmp_treg(Ijk_NoRedir,t1);
9037 dres.whatNext = Dis_StopHere;
9038 goto decode_success;
9039 }
9040 /* We don't know what it is. */
9041 goto decode_failure;
9042 /*NOTREACHED*/
sewardjdf0e0022005-01-25 15:48:43 +00009043 }
9044 }
9045
9046 /* Eat prefixes, summarising the result in pfx and sz, and rejecting
9047 as many invalid combinations as possible. */
9048 n_prefixes = 0;
9049 while (True) {
sewardj54477e32007-08-23 18:53:59 +00009050 if (n_prefixes > 7) goto decode_failure;
sewardj8c332e22005-01-28 01:36:56 +00009051 pre = getUChar(delta);
sewardjdf0e0022005-01-25 15:48:43 +00009052 switch (pre) {
9053 case 0x66: pfx |= PFX_66; break;
9054 case 0x67: pfx |= PFX_ASO; break;
9055 case 0xF2: pfx |= PFX_F2; break;
9056 case 0xF3: pfx |= PFX_F3; break;
sewardje9d8a262009-07-01 08:06:34 +00009057 case 0xF0: pfx |= PFX_LOCK; *expect_CAS = True; break;
sewardjdf0e0022005-01-25 15:48:43 +00009058 case 0x2E: pfx |= PFX_CS; break;
9059 case 0x3E: pfx |= PFX_DS; break;
9060 case 0x26: pfx |= PFX_ES; break;
9061 case 0x64: pfx |= PFX_FS; break;
9062 case 0x65: pfx |= PFX_GS; break;
9063 case 0x36: pfx |= PFX_SS; break;
9064 case 0x40 ... 0x4F:
9065 pfx |= PFX_REX;
9066 if (pre & (1<<3)) pfx |= PFX_REXW;
9067 if (pre & (1<<2)) pfx |= PFX_REXR;
9068 if (pre & (1<<1)) pfx |= PFX_REXX;
9069 if (pre & (1<<0)) pfx |= PFX_REXB;
9070 break;
9071 default:
9072 goto not_a_prefix;
9073 }
9074 n_prefixes++;
9075 delta++;
9076 }
9077
9078 not_a_prefix:
sewardjdf0e0022005-01-25 15:48:43 +00009079
sewardj42561ef2005-11-04 14:18:31 +00009080 /* Dump invalid combinations */
sewardjdf0e0022005-01-25 15:48:43 +00009081 n = 0;
9082 if (pfx & PFX_F2) n++;
9083 if (pfx & PFX_F3) n++;
sewardj3ca55a12005-01-27 16:06:23 +00009084 if (n > 1)
9085 goto decode_failure; /* can't have both */
sewardjdf0e0022005-01-25 15:48:43 +00009086
9087 n = 0;
9088 if (pfx & PFX_CS) n++;
9089 if (pfx & PFX_DS) n++;
9090 if (pfx & PFX_ES) n++;
9091 if (pfx & PFX_FS) n++;
9092 if (pfx & PFX_GS) n++;
9093 if (pfx & PFX_SS) n++;
sewardj3ca55a12005-01-27 16:06:23 +00009094 if (n > 1)
9095 goto decode_failure; /* multiple seg overrides == illegal */
sewardjdf0e0022005-01-25 15:48:43 +00009096
sewardjceccb292009-01-22 20:40:22 +00009097 /* We have a %fs prefix. Reject it if there's no evidence in 'vbi'
9098 that we should accept it. */
9099 if ((pfx & PFX_FS) && !vbi->guest_amd64_assume_fs_is_zero)
9100 goto decode_failure;
9101
9102 /* Ditto for %gs prefixes. */
9103 if ((pfx & PFX_GS) && !vbi->guest_amd64_assume_gs_is_0x60)
9104 goto decode_failure;
sewardj42561ef2005-11-04 14:18:31 +00009105
sewardjdf0e0022005-01-25 15:48:43 +00009106 /* Set up sz. */
9107 sz = 4;
9108 if (pfx & PFX_66) sz = 2;
9109 if ((pfx & PFX_REX) && (pfx & PFX_REXW)) sz = 8;
9110
sewardje9d8a262009-07-01 08:06:34 +00009111 /* Now we should be looking at the primary opcode byte or the
9112 leading F2 or F3. Check that any LOCK prefix is actually
9113 allowed. */
sewardjc4356f02007-11-09 21:15:04 +00009114
sewardj9ff93bc2005-03-23 11:25:12 +00009115 if (pfx & PFX_LOCK) {
sewardjc4356f02007-11-09 21:15:04 +00009116 if (can_be_used_with_LOCK_prefix( (UChar*)&guest_code[delta] )) {
sewardjc4356f02007-11-09 21:15:04 +00009117 DIP("lock ");
9118 } else {
sewardje9d8a262009-07-01 08:06:34 +00009119 *expect_CAS = False;
sewardjc4356f02007-11-09 21:15:04 +00009120 goto decode_failure;
9121 }
sewardjdf0e0022005-01-25 15:48:43 +00009122 }
9123
sewardja6b93d12005-02-17 09:28:28 +00009124
9125 /* ---------------------------------------------------- */
sewardj09717342005-05-05 21:34:02 +00009126 /* --- The SSE/SSE2 decoder. --- */
sewardja6b93d12005-02-17 09:28:28 +00009127 /* ---------------------------------------------------- */
9128
9129 /* What did I do to deserve SSE ? Perhaps I was really bad in a
9130 previous life? */
9131
sewardj09717342005-05-05 21:34:02 +00009132 /* Note, this doesn't handle SSE3 right now. All amd64s support
9133 SSE2 as a minimum so there is no point distinguishing SSE1 vs
9134 SSE2. */
9135
sewardja6b93d12005-02-17 09:28:28 +00009136 insn = (UChar*)&guest_code[delta];
9137
sewardj5abcfe62007-01-10 04:59:33 +00009138 /* FXSAVE is spuriously at the start here only because it is
9139 thusly placed in guest-x86/toIR.c. */
9140
9141 /* 0F AE /0 = FXSAVE m512 -- write x87 and SSE state to memory.
9142 Note that REX.W 0F AE /0 writes a slightly different format and
9143 we don't handle that here. */
9144 if (haveNo66noF2noF3(pfx) && sz == 4
9145 && insn[0] == 0x0F && insn[1] == 0xAE
9146 && !epartIsReg(insn[2]) && gregOfRexRM(pfx,insn[2]) == 0) {
9147 IRDirty* d;
9148 modrm = getUChar(delta+2);
9149 vassert(sz == 4);
9150 vassert(!epartIsReg(modrm));
9151 /* REX.W must not be set. That should be assured us by sz == 4
9152 above. */
9153 vassert(!(pfx & PFX_REXW));
9154
sewardj2e28ac42008-12-04 00:05:12 +00009155 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj5abcfe62007-01-10 04:59:33 +00009156 delta += 2+alen;
9157
9158 DIP("fxsave %s\n", dis_buf);
9159
9160 /* Uses dirty helper:
9161 void amd64g_do_FXSAVE ( VexGuestAMD64State*, UInt ) */
9162 d = unsafeIRDirty_0_N (
9163 0/*regparms*/,
9164 "amd64g_dirtyhelper_FXSAVE",
9165 &amd64g_dirtyhelper_FXSAVE,
9166 mkIRExprVec_1( mkexpr(addr) )
9167 );
9168 d->needsBBP = True;
9169
9170 /* declare we're writing memory */
9171 d->mFx = Ifx_Write;
9172 d->mAddr = mkexpr(addr);
9173 d->mSize = 512;
9174
9175 /* declare we're reading guest state */
9176 d->nFxState = 7;
9177
9178 d->fxState[0].fx = Ifx_Read;
9179 d->fxState[0].offset = OFFB_FTOP;
9180 d->fxState[0].size = sizeof(UInt);
9181
9182 d->fxState[1].fx = Ifx_Read;
9183 d->fxState[1].offset = OFFB_FPREGS;
9184 d->fxState[1].size = 8 * sizeof(ULong);
9185
9186 d->fxState[2].fx = Ifx_Read;
9187 d->fxState[2].offset = OFFB_FPTAGS;
9188 d->fxState[2].size = 8 * sizeof(UChar);
9189
9190 d->fxState[3].fx = Ifx_Read;
9191 d->fxState[3].offset = OFFB_FPROUND;
9192 d->fxState[3].size = sizeof(ULong);
9193
9194 d->fxState[4].fx = Ifx_Read;
9195 d->fxState[4].offset = OFFB_FC3210;
9196 d->fxState[4].size = sizeof(ULong);
9197
9198 d->fxState[5].fx = Ifx_Read;
9199 d->fxState[5].offset = OFFB_XMM0;
9200 d->fxState[5].size = 16 * sizeof(U128);
9201
9202 d->fxState[6].fx = Ifx_Read;
9203 d->fxState[6].offset = OFFB_SSEROUND;
9204 d->fxState[6].size = sizeof(ULong);
9205
9206 /* Be paranoid ... this assertion tries to ensure the 16 %xmm
9207 images are packed back-to-back. If not, the value of
9208 d->fxState[5].size is wrong. */
9209 vassert(16 == sizeof(U128));
9210 vassert(OFFB_XMM15 == (OFFB_XMM0 + 15 * 16));
9211
9212 stmt( IRStmt_Dirty(d) );
9213
9214 goto decode_success;
9215 }
9216
9217 /* ------ SSE decoder main ------ */
sewardj432f8b62005-05-10 02:50:05 +00009218
9219 /* 0F 58 = ADDPS -- add 32Fx4 from R/M to R */
9220 if (haveNo66noF2noF3(pfx) && sz == 4
9221 && insn[0] == 0x0F && insn[1] == 0x58) {
sewardj2e28ac42008-12-04 00:05:12 +00009222 delta = dis_SSE_E_to_G_all( vbi, pfx, delta+2, "addps", Iop_Add32Fx4 );
sewardj432f8b62005-05-10 02:50:05 +00009223 goto decode_success;
9224 }
sewardj8d965312005-02-25 02:48:47 +00009225
9226 /* F3 0F 58 = ADDSS -- add 32F0x4 from R/M to R */
9227 if (haveF3no66noF2(pfx) && sz == 4
9228 && insn[0] == 0x0F && insn[1] == 0x58) {
sewardj2e28ac42008-12-04 00:05:12 +00009229 delta = dis_SSE_E_to_G_lo32( vbi, pfx, delta+2, "addss", Iop_Add32F0x4 );
sewardj8d965312005-02-25 02:48:47 +00009230 goto decode_success;
9231 }
9232
sewardj3aba9eb2005-03-30 23:20:47 +00009233 /* 0F 55 = ANDNPS -- G = (not G) and E */
9234 if (haveNo66noF2noF3(pfx) && sz == 4
9235 && insn[0] == 0x0F && insn[1] == 0x55) {
sewardj2e28ac42008-12-04 00:05:12 +00009236 delta = dis_SSE_E_to_G_all_invG( vbi, pfx, delta+2, "andnps", Iop_AndV128 );
sewardj3aba9eb2005-03-30 23:20:47 +00009237 goto decode_success;
9238 }
sewardj37d52572005-02-25 14:22:12 +00009239
9240 /* 0F 54 = ANDPS -- G = G and E */
9241 if (haveNo66noF2noF3(pfx) && sz == 4
9242 && insn[0] == 0x0F && insn[1] == 0x54) {
sewardj2e28ac42008-12-04 00:05:12 +00009243 delta = dis_SSE_E_to_G_all( vbi, pfx, delta+2, "andps", Iop_AndV128 );
sewardj37d52572005-02-25 14:22:12 +00009244 goto decode_success;
9245 }
9246
sewardj432f8b62005-05-10 02:50:05 +00009247 /* 0F C2 = CMPPS -- 32Fx4 comparison from R/M to R */
9248 if (haveNo66noF2noF3(pfx) && sz == 4
9249 && insn[0] == 0x0F && insn[1] == 0xC2) {
sewardj2e28ac42008-12-04 00:05:12 +00009250 delta = dis_SSEcmp_E_to_G( vbi, pfx, delta+2, "cmpps", True, 4 );
sewardj432f8b62005-05-10 02:50:05 +00009251 goto decode_success;
9252 }
sewardj3aba9eb2005-03-30 23:20:47 +00009253
9254 /* F3 0F C2 = CMPSS -- 32F0x4 comparison from R/M to R */
9255 if (haveF3no66noF2(pfx) && sz == 4
9256 && insn[0] == 0x0F && insn[1] == 0xC2) {
sewardj2e28ac42008-12-04 00:05:12 +00009257 delta = dis_SSEcmp_E_to_G( vbi, pfx, delta+2, "cmpss", False, 4 );
sewardj3aba9eb2005-03-30 23:20:47 +00009258 goto decode_success;
9259 }
sewardjc49ce232005-02-25 13:03:03 +00009260
9261 /* 0F 2F = COMISS -- 32F0x4 comparison G,E, and set ZCP */
9262 /* 0F 2E = UCOMISS -- 32F0x4 comparison G,E, and set ZCP */
9263 if (haveNo66noF2noF3(pfx) && sz == 4
9264 && insn[0] == 0x0F && (insn[1] == 0x2F || insn[1] == 0x2E)) {
9265 IRTemp argL = newTemp(Ity_F32);
9266 IRTemp argR = newTemp(Ity_F32);
9267 modrm = getUChar(delta+2);
9268 if (epartIsReg(modrm)) {
9269 assign( argR, getXMMRegLane32F( eregOfRexRM(pfx,modrm),
9270 0/*lowest lane*/ ) );
9271 delta += 2+1;
9272 DIP("%scomiss %s,%s\n", insn[1]==0x2E ? "u" : "",
9273 nameXMMReg(eregOfRexRM(pfx,modrm)),
9274 nameXMMReg(gregOfRexRM(pfx,modrm)) );
9275 } else {
sewardj2e28ac42008-12-04 00:05:12 +00009276 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardjc49ce232005-02-25 13:03:03 +00009277 assign( argR, loadLE(Ity_F32, mkexpr(addr)) );
9278 delta += 2+alen;
9279 DIP("%scomiss %s,%s\n", insn[1]==0x2E ? "u" : "",
9280 dis_buf,
9281 nameXMMReg(gregOfRexRM(pfx,modrm)) );
9282 }
9283 assign( argL, getXMMRegLane32F( gregOfRexRM(pfx,modrm),
9284 0/*lowest lane*/ ) );
9285
9286 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(AMD64G_CC_OP_COPY) ));
9287 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
9288 stmt( IRStmt_Put(
9289 OFFB_CC_DEP1,
9290 binop( Iop_And64,
9291 unop( Iop_32Uto64,
9292 binop(Iop_CmpF64,
9293 unop(Iop_F32toF64,mkexpr(argL)),
9294 unop(Iop_F32toF64,mkexpr(argR)))),
9295 mkU64(0x45)
9296 )));
9297
9298 goto decode_success;
9299 }
9300
sewardj432f8b62005-05-10 02:50:05 +00009301 /* 0F 2A = CVTPI2PS -- convert 2 x I32 in mem/mmx to 2 x F32 in low
9302 half xmm */
9303 if (haveNo66noF2noF3(pfx) && sz == 4
9304 && insn[0] == 0x0F && insn[1] == 0x2A) {
9305 IRTemp arg64 = newTemp(Ity_I64);
9306 IRTemp rmode = newTemp(Ity_I32);
9307
9308 modrm = getUChar(delta+2);
9309 do_MMX_preamble();
9310 if (epartIsReg(modrm)) {
9311 assign( arg64, getMMXReg(eregLO3ofRM(modrm)) );
9312 delta += 2+1;
9313 DIP("cvtpi2ps %s,%s\n", nameMMXReg(eregLO3ofRM(modrm)),
9314 nameXMMReg(gregOfRexRM(pfx,modrm)));
9315 } else {
sewardj2e28ac42008-12-04 00:05:12 +00009316 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj432f8b62005-05-10 02:50:05 +00009317 assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
9318 delta += 2+alen;
9319 DIP("cvtpi2ps %s,%s\n", dis_buf,
9320 nameXMMReg(gregOfRexRM(pfx,modrm)) );
9321 }
9322
9323 assign( rmode, get_sse_roundingmode() );
9324
9325 putXMMRegLane32F(
9326 gregOfRexRM(pfx,modrm), 0,
9327 binop(Iop_F64toF32,
9328 mkexpr(rmode),
sewardj6c299f32009-12-31 18:00:12 +00009329 unop(Iop_I32StoF64,
sewardj432f8b62005-05-10 02:50:05 +00009330 unop(Iop_64to32, mkexpr(arg64)) )) );
9331
9332 putXMMRegLane32F(
9333 gregOfRexRM(pfx,modrm), 1,
9334 binop(Iop_F64toF32,
9335 mkexpr(rmode),
sewardj6c299f32009-12-31 18:00:12 +00009336 unop(Iop_I32StoF64,
sewardj432f8b62005-05-10 02:50:05 +00009337 unop(Iop_64HIto32, mkexpr(arg64)) )) );
9338
9339 goto decode_success;
9340 }
sewardj8d965312005-02-25 02:48:47 +00009341
9342 /* F3 0F 2A = CVTSI2SS
9343 -- sz==4: convert I32 in mem/ireg to F32 in low quarter xmm
9344 -- sz==8: convert I64 in mem/ireg to F32 in low quarter xmm */
9345 if (haveF3no66noF2(pfx) && (sz == 4 || sz == 8)
9346 && insn[0] == 0x0F && insn[1] == 0x2A) {
9347
9348 IRTemp rmode = newTemp(Ity_I32);
9349 assign( rmode, get_sse_roundingmode() );
9350 modrm = getUChar(delta+2);
9351
9352 if (sz == 4) {
9353 IRTemp arg32 = newTemp(Ity_I32);
9354 if (epartIsReg(modrm)) {
sewardj5b470602005-02-27 13:10:48 +00009355 assign( arg32, getIReg32(eregOfRexRM(pfx,modrm)) );
sewardj8d965312005-02-25 02:48:47 +00009356 delta += 2+1;
sewardj5b470602005-02-27 13:10:48 +00009357 DIP("cvtsi2ss %s,%s\n", nameIReg32(eregOfRexRM(pfx,modrm)),
sewardj8d965312005-02-25 02:48:47 +00009358 nameXMMReg(gregOfRexRM(pfx,modrm)));
9359 } else {
sewardj2e28ac42008-12-04 00:05:12 +00009360 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj8d965312005-02-25 02:48:47 +00009361 assign( arg32, loadLE(Ity_I32, mkexpr(addr)) );
9362 delta += 2+alen;
9363 DIP("cvtsi2ss %s,%s\n", dis_buf,
9364 nameXMMReg(gregOfRexRM(pfx,modrm)) );
9365 }
9366 putXMMRegLane32F(
9367 gregOfRexRM(pfx,modrm), 0,
9368 binop(Iop_F64toF32,
9369 mkexpr(rmode),
sewardj6c299f32009-12-31 18:00:12 +00009370 unop(Iop_I32StoF64, mkexpr(arg32)) ) );
sewardj8d965312005-02-25 02:48:47 +00009371 } else {
9372 /* sz == 8 */
9373 IRTemp arg64 = newTemp(Ity_I64);
9374 if (epartIsReg(modrm)) {
sewardj5b470602005-02-27 13:10:48 +00009375 assign( arg64, getIReg64(eregOfRexRM(pfx,modrm)) );
sewardj8d965312005-02-25 02:48:47 +00009376 delta += 2+1;
sewardj5b470602005-02-27 13:10:48 +00009377 DIP("cvtsi2ssq %s,%s\n", nameIReg64(eregOfRexRM(pfx,modrm)),
sewardj8d965312005-02-25 02:48:47 +00009378 nameXMMReg(gregOfRexRM(pfx,modrm)));
9379 } else {
sewardj2e28ac42008-12-04 00:05:12 +00009380 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj82c9f2f2005-03-02 16:05:13 +00009381 assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
9382 delta += 2+alen;
9383 DIP("cvtsi2ssq %s,%s\n", dis_buf,
9384 nameXMMReg(gregOfRexRM(pfx,modrm)) );
sewardj8d965312005-02-25 02:48:47 +00009385 }
9386 putXMMRegLane32F(
9387 gregOfRexRM(pfx,modrm), 0,
9388 binop(Iop_F64toF32,
9389 mkexpr(rmode),
sewardj6c299f32009-12-31 18:00:12 +00009390 binop(Iop_I64StoF64, mkexpr(rmode), mkexpr(arg64)) ) );
sewardj8d965312005-02-25 02:48:47 +00009391 }
9392
9393 goto decode_success;
9394 }
9395
sewardj432f8b62005-05-10 02:50:05 +00009396 /* 0F 2D = CVTPS2PI -- convert 2 x F32 in mem/low half xmm to 2 x
9397 I32 in mmx, according to prevailing SSE rounding mode */
sewardja7ba8c42005-05-10 20:08:34 +00009398 /* 0F 2C = CVTTPS2PI -- convert 2 x F32 in mem/low half xmm to 2 x
9399 I32 in mmx, rounding towards zero */
sewardj432f8b62005-05-10 02:50:05 +00009400 if (haveNo66noF2noF3(pfx) && sz == 4
sewardja7ba8c42005-05-10 20:08:34 +00009401 && insn[0] == 0x0F && (insn[1] == 0x2D || insn[1] == 0x2C)) {
sewardj432f8b62005-05-10 02:50:05 +00009402 IRTemp dst64 = newTemp(Ity_I64);
9403 IRTemp rmode = newTemp(Ity_I32);
9404 IRTemp f32lo = newTemp(Ity_F32);
9405 IRTemp f32hi = newTemp(Ity_F32);
9406 Bool r2zero = toBool(insn[1] == 0x2C);
9407
9408 do_MMX_preamble();
9409 modrm = getUChar(delta+2);
9410
9411 if (epartIsReg(modrm)) {
9412 delta += 2+1;
9413 assign(f32lo, getXMMRegLane32F(eregOfRexRM(pfx,modrm), 0));
9414 assign(f32hi, getXMMRegLane32F(eregOfRexRM(pfx,modrm), 1));
9415 DIP("cvt%sps2pi %s,%s\n", r2zero ? "t" : "",
9416 nameXMMReg(eregOfRexRM(pfx,modrm)),
9417 nameMMXReg(gregLO3ofRM(modrm)));
9418 } else {
sewardj2e28ac42008-12-04 00:05:12 +00009419 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj432f8b62005-05-10 02:50:05 +00009420 assign(f32lo, loadLE(Ity_F32, mkexpr(addr)));
9421 assign(f32hi, loadLE(Ity_F32, binop( Iop_Add64,
9422 mkexpr(addr),
9423 mkU64(4) )));
9424 delta += 2+alen;
9425 DIP("cvt%sps2pi %s,%s\n", r2zero ? "t" : "",
9426 dis_buf,
9427 nameMMXReg(gregLO3ofRM(modrm)));
9428 }
9429
9430 if (r2zero) {
9431 assign(rmode, mkU32((UInt)Irrm_ZERO) );
9432 } else {
9433 assign( rmode, get_sse_roundingmode() );
9434 }
9435
9436 assign(
9437 dst64,
9438 binop( Iop_32HLto64,
sewardj6c299f32009-12-31 18:00:12 +00009439 binop( Iop_F64toI32S,
sewardj432f8b62005-05-10 02:50:05 +00009440 mkexpr(rmode),
9441 unop( Iop_F32toF64, mkexpr(f32hi) ) ),
sewardj6c299f32009-12-31 18:00:12 +00009442 binop( Iop_F64toI32S,
sewardj432f8b62005-05-10 02:50:05 +00009443 mkexpr(rmode),
9444 unop( Iop_F32toF64, mkexpr(f32lo) ) )
9445 )
9446 );
9447
9448 putMMXReg(gregLO3ofRM(modrm), mkexpr(dst64));
9449 goto decode_success;
9450 }
9451
9452 /* F3 0F 2D = CVTSS2SI
9453 when sz==4 -- convert F32 in mem/low quarter xmm to I32 in ireg,
9454 according to prevailing SSE rounding mode
9455 when sz==8 -- convert F32 in mem/low quarter xmm to I64 in ireg,
9456 according to prevailing SSE rounding mode
9457 */
sewardj82c9f2f2005-03-02 16:05:13 +00009458 /* F3 0F 2C = CVTTSS2SI
9459 when sz==4 -- convert F32 in mem/low quarter xmm to I32 in ireg,
9460 truncating towards zero
9461 when sz==8 -- convert F32 in mem/low quarter xmm to I64 in ireg,
9462 truncating towards zero
9463 */
9464 if (haveF3no66noF2(pfx)
9465 && insn[0] == 0x0F
sewardj432f8b62005-05-10 02:50:05 +00009466 && (insn[1] == 0x2D || insn[1] == 0x2C)) {
sewardj82c9f2f2005-03-02 16:05:13 +00009467 IRTemp rmode = newTemp(Ity_I32);
9468 IRTemp f32lo = newTemp(Ity_F32);
9469 Bool r2zero = toBool(insn[1] == 0x2C);
9470 vassert(sz == 4 || sz == 8);
9471
9472 modrm = getUChar(delta+2);
9473 if (epartIsReg(modrm)) {
9474 delta += 2+1;
9475 assign(f32lo, getXMMRegLane32F(eregOfRexRM(pfx,modrm), 0));
9476 DIP("cvt%sss2si %s,%s\n", r2zero ? "t" : "",
9477 nameXMMReg(eregOfRexRM(pfx,modrm)),
9478 nameIReg(sz, gregOfRexRM(pfx,modrm), False));
9479 } else {
sewardj2e28ac42008-12-04 00:05:12 +00009480 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj82c9f2f2005-03-02 16:05:13 +00009481 assign(f32lo, loadLE(Ity_F32, mkexpr(addr)));
9482 delta += 2+alen;
9483 DIP("cvt%sss2si %s,%s\n", r2zero ? "t" : "",
9484 dis_buf,
9485 nameIReg(sz, gregOfRexRM(pfx,modrm), False));
9486 }
9487
9488 if (r2zero) {
9489 assign( rmode, mkU32((UInt)Irrm_ZERO) );
9490 } else {
9491 assign( rmode, get_sse_roundingmode() );
9492 }
9493
9494 if (sz == 4) {
9495 putIReg32( gregOfRexRM(pfx,modrm),
sewardj6c299f32009-12-31 18:00:12 +00009496 binop( Iop_F64toI32S,
sewardj82c9f2f2005-03-02 16:05:13 +00009497 mkexpr(rmode),
9498 unop(Iop_F32toF64, mkexpr(f32lo))) );
9499 } else {
9500 putIReg64( gregOfRexRM(pfx,modrm),
sewardj6c299f32009-12-31 18:00:12 +00009501 binop( Iop_F64toI64S,
sewardj82c9f2f2005-03-02 16:05:13 +00009502 mkexpr(rmode),
9503 unop(Iop_F32toF64, mkexpr(f32lo))) );
9504 }
9505
9506 goto decode_success;
9507 }
9508
sewardj432f8b62005-05-10 02:50:05 +00009509 /* 0F 5E = DIVPS -- div 32Fx4 from R/M to R */
9510 if (haveNo66noF2noF3(pfx) && sz == 4
9511 && insn[0] == 0x0F && insn[1] == 0x5E) {
sewardj2e28ac42008-12-04 00:05:12 +00009512 delta = dis_SSE_E_to_G_all( vbi, pfx, delta+2, "divps", Iop_Div32Fx4 );
sewardj432f8b62005-05-10 02:50:05 +00009513 goto decode_success;
9514 }
sewardjc49ce232005-02-25 13:03:03 +00009515
9516 /* F3 0F 5E = DIVSS -- div 32F0x4 from R/M to R */
9517 if (haveF3no66noF2(pfx) && sz == 4
9518 && insn[0] == 0x0F && insn[1] == 0x5E) {
sewardj2e28ac42008-12-04 00:05:12 +00009519 delta = dis_SSE_E_to_G_lo32( vbi, pfx, delta+2, "divss", Iop_Div32F0x4 );
sewardjc49ce232005-02-25 13:03:03 +00009520 goto decode_success;
9521 }
9522
sewardjbcbb9de2005-03-27 02:22:32 +00009523 /* 0F AE /2 = LDMXCSR m32 -- load %mxcsr */
9524 if (insn[0] == 0x0F && insn[1] == 0xAE
9525 && haveNo66noF2noF3(pfx)
9526 && !epartIsReg(insn[2]) && gregLO3ofRM(insn[2]) == 2) {
9527
9528 IRTemp t64 = newTemp(Ity_I64);
9529 IRTemp ew = newTemp(Ity_I32);
9530
9531 vassert(sz == 4);
sewardj2e28ac42008-12-04 00:05:12 +00009532 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardjbcbb9de2005-03-27 02:22:32 +00009533 delta += 2+alen;
9534 DIP("ldmxcsr %s\n", dis_buf);
9535
9536 /* The only thing we observe in %mxcsr is the rounding mode.
9537 Therefore, pass the 32-bit value (SSE native-format control
9538 word) to a clean helper, getting back a 64-bit value, the
9539 lower half of which is the SSEROUND value to store, and the
9540 upper half of which is the emulation-warning token which may
9541 be generated.
9542 */
9543 /* ULong amd64h_check_ldmxcsr ( ULong ); */
9544 assign( t64, mkIRExprCCall(
9545 Ity_I64, 0/*regparms*/,
9546 "amd64g_check_ldmxcsr",
9547 &amd64g_check_ldmxcsr,
9548 mkIRExprVec_1(
9549 unop(Iop_32Uto64,
9550 loadLE(Ity_I32, mkexpr(addr))
9551 )
9552 )
9553 )
9554 );
9555
9556 put_sse_roundingmode( unop(Iop_64to32, mkexpr(t64)) );
9557 assign( ew, unop(Iop_64HIto32, mkexpr(t64) ) );
9558 put_emwarn( mkexpr(ew) );
9559 /* Finally, if an emulation warning was reported, side-exit to
9560 the next insn, reporting the warning, so that Valgrind's
9561 dispatcher sees the warning. */
9562 stmt(
9563 IRStmt_Exit(
9564 binop(Iop_CmpNE64, unop(Iop_32Uto64,mkexpr(ew)), mkU64(0)),
9565 Ijk_EmWarn,
sewardj9e6491a2005-07-02 19:24:10 +00009566 IRConst_U64(guest_RIP_bbstart+delta)
sewardjbcbb9de2005-03-27 02:22:32 +00009567 )
9568 );
9569 goto decode_success;
9570 }
9571
sewardj02f79f12007-09-01 18:59:53 +00009572 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9573 /* 0F F7 = MASKMOVQ -- 8x8 masked store */
9574 if (haveNo66noF2noF3(pfx) && sz == 4
9575 && insn[0] == 0x0F && insn[1] == 0xF7) {
9576 Bool ok = False;
sewardj2e28ac42008-12-04 00:05:12 +00009577 delta = dis_MMX( &ok, vbi, pfx, sz, delta+1 );
sewardj02f79f12007-09-01 18:59:53 +00009578 if (!ok)
9579 goto decode_failure;
9580 goto decode_success;
9581 }
9582
sewardj432f8b62005-05-10 02:50:05 +00009583 /* 0F 5F = MAXPS -- max 32Fx4 from R/M to R */
9584 if (haveNo66noF2noF3(pfx) && sz == 4
9585 && insn[0] == 0x0F && insn[1] == 0x5F) {
sewardj2e28ac42008-12-04 00:05:12 +00009586 delta = dis_SSE_E_to_G_all( vbi, pfx, delta+2, "maxps", Iop_Max32Fx4 );
sewardj432f8b62005-05-10 02:50:05 +00009587 goto decode_success;
9588 }
sewardj37d52572005-02-25 14:22:12 +00009589
9590 /* F3 0F 5F = MAXSS -- max 32F0x4 from R/M to R */
9591 if (haveF3no66noF2(pfx) && sz == 4
9592 && insn[0] == 0x0F && insn[1] == 0x5F) {
sewardj2e28ac42008-12-04 00:05:12 +00009593 delta = dis_SSE_E_to_G_lo32( vbi, pfx, delta+2, "maxss", Iop_Max32F0x4 );
sewardj37d52572005-02-25 14:22:12 +00009594 goto decode_success;
9595 }
9596
sewardj432f8b62005-05-10 02:50:05 +00009597 /* 0F 5D = MINPS -- min 32Fx4 from R/M to R */
9598 if (haveNo66noF2noF3(pfx) && sz == 4
9599 && insn[0] == 0x0F && insn[1] == 0x5D) {
sewardj2e28ac42008-12-04 00:05:12 +00009600 delta = dis_SSE_E_to_G_all( vbi, pfx, delta+2, "minps", Iop_Min32Fx4 );
sewardj432f8b62005-05-10 02:50:05 +00009601 goto decode_success;
9602 }
sewardj37d52572005-02-25 14:22:12 +00009603
9604 /* F3 0F 5D = MINSS -- min 32F0x4 from R/M to R */
9605 if (haveF3no66noF2(pfx) && sz == 4
9606 && insn[0] == 0x0F && insn[1] == 0x5D) {
sewardj2e28ac42008-12-04 00:05:12 +00009607 delta = dis_SSE_E_to_G_lo32( vbi, pfx, delta+2, "minss", Iop_Min32F0x4 );
sewardj37d52572005-02-25 14:22:12 +00009608 goto decode_success;
9609 }
sewardj8d965312005-02-25 02:48:47 +00009610
9611 /* 0F 28 = MOVAPS -- move from E (mem or xmm) to G (xmm). */
9612 /* 0F 10 = MOVUPS -- move from E (mem or xmm) to G (xmm). */
sewardjb4bf5882007-11-06 20:39:17 +00009613 if (haveNo66noF2noF3(pfx)
9614 && (sz == 4 || /* ignore redundant REX.W */ sz == 8)
sewardj8d965312005-02-25 02:48:47 +00009615 && insn[0] == 0x0F && (insn[1] == 0x28 || insn[1] == 0x10)) {
9616 modrm = getUChar(delta+2);
9617 if (epartIsReg(modrm)) {
9618 putXMMReg( gregOfRexRM(pfx,modrm),
9619 getXMMReg( eregOfRexRM(pfx,modrm) ));
9620 DIP("mov[ua]ps %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
9621 nameXMMReg(gregOfRexRM(pfx,modrm)));
9622 delta += 2+1;
9623 } else {
sewardj2e28ac42008-12-04 00:05:12 +00009624 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj8d965312005-02-25 02:48:47 +00009625 putXMMReg( gregOfRexRM(pfx,modrm),
9626 loadLE(Ity_V128, mkexpr(addr)) );
9627 DIP("mov[ua]ps %s,%s\n", dis_buf,
9628 nameXMMReg(gregOfRexRM(pfx,modrm)));
9629 delta += 2+alen;
9630 }
9631 goto decode_success;
9632 }
sewardj1001dc42005-02-21 08:25:55 +00009633
9634 /* 0F 29 = MOVAPS -- move from G (xmm) to E (mem or xmm). */
sewardj446d2672005-06-10 11:04:52 +00009635 /* 0F 11 = MOVUPS -- move from G (xmm) to E (mem or xmm). */
sewardjb4bf5882007-11-06 20:39:17 +00009636 if (haveNo66noF2noF3(pfx)
9637 && (sz == 4 || /* ignore redundant REX.W */ sz == 8)
sewardj446d2672005-06-10 11:04:52 +00009638 && insn[0] == 0x0F && (insn[1] == 0x29 || insn[1] == 0x11)) {
sewardj1001dc42005-02-21 08:25:55 +00009639 modrm = getUChar(delta+2);
9640 if (epartIsReg(modrm)) {
9641 /* fall through; awaiting test case */
9642 } else {
sewardj2e28ac42008-12-04 00:05:12 +00009643 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj1001dc42005-02-21 08:25:55 +00009644 storeLE( mkexpr(addr), getXMMReg(gregOfRexRM(pfx,modrm)) );
sewardj446d2672005-06-10 11:04:52 +00009645 DIP("mov[ua]ps %s,%s\n", nameXMMReg(gregOfRexRM(pfx,modrm)),
9646 dis_buf );
sewardj1001dc42005-02-21 08:25:55 +00009647 delta += 2+alen;
9648 goto decode_success;
9649 }
9650 }
9651
sewardj432f8b62005-05-10 02:50:05 +00009652 /* 0F 16 = MOVHPS -- move from mem to high half of XMM. */
9653 /* 0F 16 = MOVLHPS -- move from lo half to hi half of XMM. */
sewardjb4bf5882007-11-06 20:39:17 +00009654 if (haveNo66noF2noF3(pfx)
9655 && (sz == 4 || /* ignore redundant REX.W */ sz == 8)
sewardj432f8b62005-05-10 02:50:05 +00009656 && insn[0] == 0x0F && insn[1] == 0x16) {
9657 modrm = getUChar(delta+2);
9658 if (epartIsReg(modrm)) {
9659 delta += 2+1;
9660 putXMMRegLane64( gregOfRexRM(pfx,modrm), 1/*upper lane*/,
9661 getXMMRegLane64( eregOfRexRM(pfx,modrm), 0 ) );
9662 DIP("movhps %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
9663 nameXMMReg(gregOfRexRM(pfx,modrm)));
9664 } else {
sewardj2e28ac42008-12-04 00:05:12 +00009665 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj432f8b62005-05-10 02:50:05 +00009666 delta += 2+alen;
9667 putXMMRegLane64( gregOfRexRM(pfx,modrm), 1/*upper lane*/,
9668 loadLE(Ity_I64, mkexpr(addr)) );
9669 DIP("movhps %s,%s\n", dis_buf,
9670 nameXMMReg( gregOfRexRM(pfx,modrm) ));
9671 }
9672 goto decode_success;
9673 }
9674
9675 /* 0F 17 = MOVHPS -- move from high half of XMM to mem. */
sewardjb4bf5882007-11-06 20:39:17 +00009676 if (haveNo66noF2noF3(pfx)
9677 && (sz == 4 || /* ignore redundant REX.W */ sz == 8)
sewardj432f8b62005-05-10 02:50:05 +00009678 && insn[0] == 0x0F && insn[1] == 0x17) {
9679 if (!epartIsReg(insn[2])) {
9680 delta += 2;
sewardj2e28ac42008-12-04 00:05:12 +00009681 addr = disAMode ( &alen, vbi, pfx, delta, dis_buf, 0 );
sewardj432f8b62005-05-10 02:50:05 +00009682 delta += alen;
9683 storeLE( mkexpr(addr),
9684 getXMMRegLane64( gregOfRexRM(pfx,insn[2]),
9685 1/*upper lane*/ ) );
9686 DIP("movhps %s,%s\n", nameXMMReg( gregOfRexRM(pfx,insn[2]) ),
9687 dis_buf);
9688 goto decode_success;
9689 }
9690 /* else fall through */
9691 }
9692
9693 /* 0F 12 = MOVLPS -- move from mem to low half of XMM. */
9694 /* OF 12 = MOVHLPS -- from from hi half to lo half of XMM. */
sewardjb4bf5882007-11-06 20:39:17 +00009695 if (haveNo66noF2noF3(pfx)
9696 && (sz == 4 || /* ignore redundant REX.W */ sz == 8)
sewardj432f8b62005-05-10 02:50:05 +00009697 && insn[0] == 0x0F && insn[1] == 0x12) {
9698 modrm = getUChar(delta+2);
9699 if (epartIsReg(modrm)) {
9700 delta += 2+1;
9701 putXMMRegLane64( gregOfRexRM(pfx,modrm),
9702 0/*lower lane*/,
9703 getXMMRegLane64( eregOfRexRM(pfx,modrm), 1 ));
9704 DIP("movhlps %s, %s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
9705 nameXMMReg(gregOfRexRM(pfx,modrm)));
9706 } else {
sewardj2e28ac42008-12-04 00:05:12 +00009707 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj432f8b62005-05-10 02:50:05 +00009708 delta += 2+alen;
9709 putXMMRegLane64( gregOfRexRM(pfx,modrm), 0/*lower lane*/,
9710 loadLE(Ity_I64, mkexpr(addr)) );
9711 DIP("movlps %s, %s\n",
9712 dis_buf, nameXMMReg( gregOfRexRM(pfx,modrm) ));
9713 }
9714 goto decode_success;
9715 }
9716
9717 /* 0F 13 = MOVLPS -- move from low half of XMM to mem. */
sewardjb4bf5882007-11-06 20:39:17 +00009718 if (haveNo66noF2noF3(pfx)
9719 && (sz == 4 || /* ignore redundant REX.W */ sz == 8)
sewardj432f8b62005-05-10 02:50:05 +00009720 && insn[0] == 0x0F && insn[1] == 0x13) {
9721 if (!epartIsReg(insn[2])) {
9722 delta += 2;
sewardj2e28ac42008-12-04 00:05:12 +00009723 addr = disAMode ( &alen, vbi, pfx, delta, dis_buf, 0 );
sewardj432f8b62005-05-10 02:50:05 +00009724 delta += alen;
9725 storeLE( mkexpr(addr),
9726 getXMMRegLane64( gregOfRexRM(pfx,insn[2]),
9727 0/*lower lane*/ ) );
9728 DIP("movlps %s, %s\n", nameXMMReg( gregOfRexRM(pfx,insn[2]) ),
9729 dis_buf);
9730 goto decode_success;
9731 }
9732 /* else fall through */
9733 }
9734
sewardja7ba8c42005-05-10 20:08:34 +00009735 /* 0F 50 = MOVMSKPS - move 4 sign bits from 4 x F32 in xmm(E)
9736 to 4 lowest bits of ireg(G) */
sewardjae84d782006-04-13 22:06:35 +00009737 if (haveNo66noF2noF3(pfx) && (sz == 4 || sz == 8)
sewardja7ba8c42005-05-10 20:08:34 +00009738 && insn[0] == 0x0F && insn[1] == 0x50) {
sewardjae84d782006-04-13 22:06:35 +00009739 /* sz == 8 is a kludge to handle insns with REX.W redundantly
9740 set to 1, which has been known to happen:
sewardjb4bf5882007-11-06 20:39:17 +00009741
sewardjae84d782006-04-13 22:06:35 +00009742 4c 0f 50 d9 rex64X movmskps %xmm1,%r11d
sewardjb4bf5882007-11-06 20:39:17 +00009743
9744 20071106: Intel docs say that REX.W isn't redundant: when
9745 present, a 64-bit register is written; when not present, only
9746 the 32-bit half is written. However, testing on a Core2
9747 machine suggests the entire 64 bit register is written
9748 irrespective of the status of REX.W. That could be because
9749 of the default rule that says "if the lower half of a 32-bit
9750 register is written, the upper half is zeroed". By using
9751 putIReg32 here we inadvertantly produce the same behaviour as
9752 the Core2, for the same reason -- putIReg32 implements said
9753 rule.
9754
9755 AMD docs give no indication that REX.W is even valid for this
9756 insn. */
sewardja7ba8c42005-05-10 20:08:34 +00009757 modrm = getUChar(delta+2);
9758 if (epartIsReg(modrm)) {
9759 Int src;
9760 t0 = newTemp(Ity_I32);
9761 t1 = newTemp(Ity_I32);
9762 t2 = newTemp(Ity_I32);
9763 t3 = newTemp(Ity_I32);
9764 delta += 2+1;
9765 src = eregOfRexRM(pfx,modrm);
9766 assign( t0, binop( Iop_And32,
9767 binop(Iop_Shr32, getXMMRegLane32(src,0), mkU8(31)),
9768 mkU32(1) ));
9769 assign( t1, binop( Iop_And32,
9770 binop(Iop_Shr32, getXMMRegLane32(src,1), mkU8(30)),
9771 mkU32(2) ));
9772 assign( t2, binop( Iop_And32,
9773 binop(Iop_Shr32, getXMMRegLane32(src,2), mkU8(29)),
9774 mkU32(4) ));
9775 assign( t3, binop( Iop_And32,
9776 binop(Iop_Shr32, getXMMRegLane32(src,3), mkU8(28)),
9777 mkU32(8) ));
9778 putIReg32( gregOfRexRM(pfx,modrm),
9779 binop(Iop_Or32,
9780 binop(Iop_Or32, mkexpr(t0), mkexpr(t1)),
9781 binop(Iop_Or32, mkexpr(t2), mkexpr(t3))
9782 )
9783 );
9784 DIP("movmskps %s,%s\n", nameXMMReg(src),
9785 nameIReg32(gregOfRexRM(pfx,modrm)));
9786 goto decode_success;
9787 }
9788 /* else fall through */
9789 }
9790
sewardj612be432005-05-11 02:55:54 +00009791 /* 66 0F 2B = MOVNTPD -- for us, just a plain SSE store. */
sewardja7ba8c42005-05-10 20:08:34 +00009792 /* 0F 2B = MOVNTPS -- for us, just a plain SSE store. */
sewardj612be432005-05-11 02:55:54 +00009793 if ( ( (haveNo66noF2noF3(pfx) && sz == 4)
9794 || (have66noF2noF3(pfx) && sz == 2)
9795 )
9796 && insn[0] == 0x0F && insn[1] == 0x2B) {
sewardja7ba8c42005-05-10 20:08:34 +00009797 modrm = getUChar(delta+2);
9798 if (!epartIsReg(modrm)) {
sewardj2e28ac42008-12-04 00:05:12 +00009799 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardja7ba8c42005-05-10 20:08:34 +00009800 storeLE( mkexpr(addr), getXMMReg(gregOfRexRM(pfx,modrm)) );
sewardj612be432005-05-11 02:55:54 +00009801 DIP("movntp%s %s,%s\n", sz==2 ? "d" : "s",
9802 dis_buf,
9803 nameXMMReg(gregOfRexRM(pfx,modrm)));
sewardja7ba8c42005-05-10 20:08:34 +00009804 delta += 2+alen;
9805 goto decode_success;
9806 }
9807 /* else fall through */
9808 }
9809
9810 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9811 /* 0F E7 = MOVNTQ -- for us, just a plain MMX store. Note, the
9812 Intel manual does not say anything about the usual business of
9813 the FP reg tags getting trashed whenever an MMX insn happens.
9814 So we just leave them alone.
9815 */
9816 if (haveNo66noF2noF3(pfx) && sz == 4
9817 && insn[0] == 0x0F && insn[1] == 0xE7) {
9818 modrm = getUChar(delta+2);
9819 if (!epartIsReg(modrm)) {
9820 /* do_MMX_preamble(); Intel docs don't specify this */
sewardj2e28ac42008-12-04 00:05:12 +00009821 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardja7ba8c42005-05-10 20:08:34 +00009822 storeLE( mkexpr(addr), getMMXReg(gregLO3ofRM(modrm)) );
9823 DIP("movntq %s,%s\n", dis_buf,
9824 nameMMXReg(gregLO3ofRM(modrm)));
9825 delta += 2+alen;
9826 goto decode_success;
9827 }
9828 /* else fall through */
9829 }
sewardj8d965312005-02-25 02:48:47 +00009830
9831 /* F3 0F 10 = MOVSS -- move 32 bits from E (mem or lo 1/4 xmm) to G
9832 (lo 1/4 xmm). If E is mem, upper 3/4 of G is zeroed out. */
sewardjb4bf5882007-11-06 20:39:17 +00009833 if (haveF3no66noF2(pfx)
sewardj7bdd1bc2008-12-13 16:49:46 +00009834 && (sz == 4 || /* ignore redundant REX.W */ sz == 8)
sewardj8d965312005-02-25 02:48:47 +00009835 && insn[0] == 0x0F && insn[1] == 0x10) {
9836 modrm = getUChar(delta+2);
9837 if (epartIsReg(modrm)) {
9838 putXMMRegLane32( gregOfRexRM(pfx,modrm), 0,
9839 getXMMRegLane32( eregOfRexRM(pfx,modrm), 0 ));
9840 DIP("movss %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
9841 nameXMMReg(gregOfRexRM(pfx,modrm)));
9842 delta += 2+1;
9843 } else {
sewardj2e28ac42008-12-04 00:05:12 +00009844 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj8d965312005-02-25 02:48:47 +00009845 putXMMReg( gregOfRexRM(pfx,modrm), mkV128(0) );
9846 putXMMRegLane32( gregOfRexRM(pfx,modrm), 0,
9847 loadLE(Ity_I32, mkexpr(addr)) );
9848 DIP("movss %s,%s\n", dis_buf,
9849 nameXMMReg(gregOfRexRM(pfx,modrm)));
9850 delta += 2+alen;
9851 }
9852 goto decode_success;
9853 }
9854
9855 /* F3 0F 11 = MOVSS -- move 32 bits from G (lo 1/4 xmm) to E (mem
9856 or lo 1/4 xmm). */
9857 if (haveF3no66noF2(pfx) && sz == 4
9858 && insn[0] == 0x0F && insn[1] == 0x11) {
9859 modrm = getUChar(delta+2);
9860 if (epartIsReg(modrm)) {
9861 /* fall through, we don't yet have a test case */
9862 } else {
sewardj2e28ac42008-12-04 00:05:12 +00009863 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj8d965312005-02-25 02:48:47 +00009864 storeLE( mkexpr(addr),
9865 getXMMRegLane32(gregOfRexRM(pfx,modrm), 0) );
9866 DIP("movss %s,%s\n", nameXMMReg(gregOfRexRM(pfx,modrm)),
9867 dis_buf);
9868 delta += 2+alen;
9869 goto decode_success;
9870 }
9871 }
9872
sewardj432f8b62005-05-10 02:50:05 +00009873 /* 0F 59 = MULPS -- mul 32Fx4 from R/M to R */
9874 if (haveNo66noF2noF3(pfx) && sz == 4
9875 && insn[0] == 0x0F && insn[1] == 0x59) {
sewardj2e28ac42008-12-04 00:05:12 +00009876 delta = dis_SSE_E_to_G_all( vbi, pfx, delta+2, "mulps", Iop_Mul32Fx4 );
sewardj432f8b62005-05-10 02:50:05 +00009877 goto decode_success;
9878 }
sewardj8d965312005-02-25 02:48:47 +00009879
9880 /* F3 0F 59 = MULSS -- mul 32F0x4 from R/M to R */
9881 if (haveF3no66noF2(pfx) && sz == 4
9882 && insn[0] == 0x0F && insn[1] == 0x59) {
sewardj2e28ac42008-12-04 00:05:12 +00009883 delta = dis_SSE_E_to_G_lo32( vbi, pfx, delta+2, "mulss", Iop_Mul32F0x4 );
sewardj8d965312005-02-25 02:48:47 +00009884 goto decode_success;
9885 }
9886
sewardj3aba9eb2005-03-30 23:20:47 +00009887 /* 0F 56 = ORPS -- G = G and E */
9888 if (haveNo66noF2noF3(pfx) && sz == 4
9889 && insn[0] == 0x0F && insn[1] == 0x56) {
sewardj2e28ac42008-12-04 00:05:12 +00009890 delta = dis_SSE_E_to_G_all( vbi, pfx, delta+2, "orps", Iop_OrV128 );
sewardj3aba9eb2005-03-30 23:20:47 +00009891 goto decode_success;
9892 }
9893
sewardja7ba8c42005-05-10 20:08:34 +00009894 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9895 /* 0F E0 = PAVGB -- 8x8 unsigned Packed Average, with rounding */
9896 if (haveNo66noF2noF3(pfx) && sz == 4
9897 && insn[0] == 0x0F && insn[1] == 0xE0) {
9898 do_MMX_preamble();
9899 delta = dis_MMXop_regmem_to_reg (
sewardj2e28ac42008-12-04 00:05:12 +00009900 vbi, pfx, delta+2, insn[1], "pavgb", False );
sewardja7ba8c42005-05-10 20:08:34 +00009901 goto decode_success;
9902 }
9903
9904 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9905 /* 0F E3 = PAVGW -- 16x4 unsigned Packed Average, with rounding */
9906 if (haveNo66noF2noF3(pfx) && sz == 4
9907 && insn[0] == 0x0F && insn[1] == 0xE3) {
9908 do_MMX_preamble();
9909 delta = dis_MMXop_regmem_to_reg (
sewardj2e28ac42008-12-04 00:05:12 +00009910 vbi, pfx, delta+2, insn[1], "pavgw", False );
sewardja7ba8c42005-05-10 20:08:34 +00009911 goto decode_success;
9912 }
9913
9914 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9915 /* 0F C5 = PEXTRW -- extract 16-bit field from mmx(E) and put
9916 zero-extend of it in ireg(G). */
sewardj9e234f62006-09-11 14:37:27 +00009917 if (haveNo66noF2noF3(pfx) && (sz == 4 || sz == 8)
sewardja7ba8c42005-05-10 20:08:34 +00009918 && insn[0] == 0x0F && insn[1] == 0xC5) {
9919 modrm = insn[2];
9920 if (epartIsReg(modrm)) {
9921 IRTemp sV = newTemp(Ity_I64);
9922 t5 = newTemp(Ity_I16);
9923 do_MMX_preamble();
9924 assign(sV, getMMXReg(eregLO3ofRM(modrm)));
9925 breakup64to16s( sV, &t3, &t2, &t1, &t0 );
9926 switch (insn[3] & 3) {
9927 case 0: assign(t5, mkexpr(t0)); break;
9928 case 1: assign(t5, mkexpr(t1)); break;
9929 case 2: assign(t5, mkexpr(t2)); break;
9930 case 3: assign(t5, mkexpr(t3)); break;
9931 default: vassert(0);
9932 }
sewardj9e234f62006-09-11 14:37:27 +00009933 if (sz == 8)
9934 putIReg64(gregOfRexRM(pfx,modrm), unop(Iop_16Uto64, mkexpr(t5)));
9935 else
9936 putIReg32(gregOfRexRM(pfx,modrm), unop(Iop_16Uto32, mkexpr(t5)));
sewardja7ba8c42005-05-10 20:08:34 +00009937 DIP("pextrw $%d,%s,%s\n",
9938 (Int)insn[3], nameMMXReg(eregLO3ofRM(modrm)),
sewardj9e234f62006-09-11 14:37:27 +00009939 sz==8 ? nameIReg64(gregOfRexRM(pfx,modrm))
9940 : nameIReg32(gregOfRexRM(pfx,modrm))
9941 );
sewardja7ba8c42005-05-10 20:08:34 +00009942 delta += 4;
9943 goto decode_success;
9944 }
9945 /* else fall through */
9946 /* note, for anyone filling in the mem case: this insn has one
9947 byte after the amode and therefore you must pass 1 as the
9948 last arg to disAMode */
9949 }
9950
9951 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9952 /* 0F C4 = PINSRW -- get 16 bits from E(mem or low half ireg) and
9953 put it into the specified lane of mmx(G). */
9954 if (haveNo66noF2noF3(pfx) && sz == 4
9955 && insn[0] == 0x0F && insn[1] == 0xC4) {
9956 /* Use t0 .. t3 to hold the 4 original 16-bit lanes of the
9957 mmx reg. t4 is the new lane value. t5 is the original
9958 mmx value. t6 is the new mmx value. */
9959 Int lane;
9960 t4 = newTemp(Ity_I16);
9961 t5 = newTemp(Ity_I64);
9962 t6 = newTemp(Ity_I64);
9963 modrm = insn[2];
9964 do_MMX_preamble();
9965
9966 assign(t5, getMMXReg(gregLO3ofRM(modrm)));
9967 breakup64to16s( t5, &t3, &t2, &t1, &t0 );
9968
9969 if (epartIsReg(modrm)) {
9970 assign(t4, getIReg16(eregOfRexRM(pfx,modrm)));
9971 delta += 3+1;
9972 lane = insn[3+1-1];
9973 DIP("pinsrw $%d,%s,%s\n", (Int)lane,
9974 nameIReg16(eregOfRexRM(pfx,modrm)),
9975 nameMMXReg(gregLO3ofRM(modrm)));
9976 } else {
sewardj2e28ac42008-12-04 00:05:12 +00009977 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 1 );
sewardja7ba8c42005-05-10 20:08:34 +00009978 delta += 3+alen;
9979 lane = insn[3+alen-1];
9980 assign(t4, loadLE(Ity_I16, mkexpr(addr)));
9981 DIP("pinsrw $%d,%s,%s\n", (Int)lane,
9982 dis_buf,
9983 nameMMXReg(gregLO3ofRM(modrm)));
9984 }
9985
9986 switch (lane & 3) {
9987 case 0: assign(t6, mk64from16s(t3,t2,t1,t4)); break;
9988 case 1: assign(t6, mk64from16s(t3,t2,t4,t0)); break;
9989 case 2: assign(t6, mk64from16s(t3,t4,t1,t0)); break;
9990 case 3: assign(t6, mk64from16s(t4,t2,t1,t0)); break;
9991 default: vassert(0);
9992 }
9993 putMMXReg(gregLO3ofRM(modrm), mkexpr(t6));
9994 goto decode_success;
9995 }
9996
9997 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9998 /* 0F EE = PMAXSW -- 16x4 signed max */
9999 if (haveNo66noF2noF3(pfx) && sz == 4
10000 && insn[0] == 0x0F && insn[1] == 0xEE) {
10001 do_MMX_preamble();
10002 delta = dis_MMXop_regmem_to_reg (
sewardj2e28ac42008-12-04 00:05:12 +000010003 vbi, pfx, delta+2, insn[1], "pmaxsw", False );
sewardja7ba8c42005-05-10 20:08:34 +000010004 goto decode_success;
10005 }
10006
10007 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
10008 /* 0F DE = PMAXUB -- 8x8 unsigned max */
10009 if (haveNo66noF2noF3(pfx) && sz == 4
10010 && insn[0] == 0x0F && insn[1] == 0xDE) {
10011 do_MMX_preamble();
10012 delta = dis_MMXop_regmem_to_reg (
sewardj2e28ac42008-12-04 00:05:12 +000010013 vbi, pfx, delta+2, insn[1], "pmaxub", False );
sewardja7ba8c42005-05-10 20:08:34 +000010014 goto decode_success;
10015 }
10016
10017 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
10018 /* 0F EA = PMINSW -- 16x4 signed min */
10019 if (haveNo66noF2noF3(pfx) && sz == 4
10020 && insn[0] == 0x0F && insn[1] == 0xEA) {
10021 do_MMX_preamble();
10022 delta = dis_MMXop_regmem_to_reg (
sewardj2e28ac42008-12-04 00:05:12 +000010023 vbi, pfx, delta+2, insn[1], "pminsw", False );
sewardja7ba8c42005-05-10 20:08:34 +000010024 goto decode_success;
10025 }
10026
10027 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
10028 /* 0F DA = PMINUB -- 8x8 unsigned min */
10029 if (haveNo66noF2noF3(pfx) && sz == 4
10030 && insn[0] == 0x0F && insn[1] == 0xDA) {
10031 do_MMX_preamble();
10032 delta = dis_MMXop_regmem_to_reg (
sewardj2e28ac42008-12-04 00:05:12 +000010033 vbi, pfx, delta+2, insn[1], "pminub", False );
sewardja7ba8c42005-05-10 20:08:34 +000010034 goto decode_success;
10035 }
10036
10037 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
10038 /* 0F D7 = PMOVMSKB -- extract sign bits from each of 8 lanes in
10039 mmx(G), turn them into a byte, and put zero-extend of it in
10040 ireg(G). */
10041 if (haveNo66noF2noF3(pfx) && sz == 4
10042 && insn[0] == 0x0F && insn[1] == 0xD7) {
10043 modrm = insn[2];
10044 if (epartIsReg(modrm)) {
10045 do_MMX_preamble();
10046 t0 = newTemp(Ity_I64);
10047 t1 = newTemp(Ity_I64);
10048 assign(t0, getMMXReg(eregLO3ofRM(modrm)));
10049 assign(t1, mkIRExprCCall(
10050 Ity_I64, 0/*regparms*/,
10051 "amd64g_calculate_mmx_pmovmskb",
10052 &amd64g_calculate_mmx_pmovmskb,
10053 mkIRExprVec_1(mkexpr(t0))));
10054 putIReg32(gregOfRexRM(pfx,modrm), unop(Iop_64to32,mkexpr(t1)));
10055 DIP("pmovmskb %s,%s\n", nameMMXReg(eregLO3ofRM(modrm)),
10056 nameIReg32(gregOfRexRM(pfx,modrm)));
10057 delta += 3;
10058 goto decode_success;
10059 }
10060 /* else fall through */
10061 }
10062
10063 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
10064 /* 0F E4 = PMULUH -- 16x4 hi-half of unsigned widening multiply */
10065 if (haveNo66noF2noF3(pfx) && sz == 4
10066 && insn[0] == 0x0F && insn[1] == 0xE4) {
10067 do_MMX_preamble();
10068 delta = dis_MMXop_regmem_to_reg (
sewardj2e28ac42008-12-04 00:05:12 +000010069 vbi, pfx, delta+2, insn[1], "pmuluh", False );
sewardja7ba8c42005-05-10 20:08:34 +000010070 goto decode_success;
10071 }
sewardja6b93d12005-02-17 09:28:28 +000010072
10073 /* 0F 18 /0 = PREFETCHNTA -- prefetch into caches, */
10074 /* 0F 18 /1 = PREFETCH0 -- with various different hints */
10075 /* 0F 18 /2 = PREFETCH1 */
10076 /* 0F 18 /3 = PREFETCH2 */
10077 if (insn[0] == 0x0F && insn[1] == 0x18
sewardjbcbb9de2005-03-27 02:22:32 +000010078 && haveNo66noF2noF3(pfx)
sewardja6b93d12005-02-17 09:28:28 +000010079 && !epartIsReg(insn[2])
sewardj901ed122005-02-27 13:25:31 +000010080 && gregLO3ofRM(insn[2]) >= 0 && gregLO3ofRM(insn[2]) <= 3) {
sewardja6b93d12005-02-17 09:28:28 +000010081 HChar* hintstr = "??";
10082
10083 modrm = getUChar(delta+2);
10084 vassert(!epartIsReg(modrm));
10085
sewardj2e28ac42008-12-04 00:05:12 +000010086 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardja6b93d12005-02-17 09:28:28 +000010087 delta += 2+alen;
10088
sewardj901ed122005-02-27 13:25:31 +000010089 switch (gregLO3ofRM(modrm)) {
sewardja6b93d12005-02-17 09:28:28 +000010090 case 0: hintstr = "nta"; break;
10091 case 1: hintstr = "t0"; break;
10092 case 2: hintstr = "t1"; break;
10093 case 3: hintstr = "t2"; break;
10094 default: vassert(0);
10095 }
10096
10097 DIP("prefetch%s %s\n", hintstr, dis_buf);
10098 goto decode_success;
10099 }
10100
sewardja7ba8c42005-05-10 20:08:34 +000010101 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
10102 /* 0F F6 = PSADBW -- sum of 8Ux8 absolute differences */
10103 if (haveNo66noF2noF3(pfx) && sz == 4
10104 && insn[0] == 0x0F && insn[1] == 0xF6) {
10105 do_MMX_preamble();
10106 delta = dis_MMXop_regmem_to_reg (
sewardj2e28ac42008-12-04 00:05:12 +000010107 vbi, pfx, delta+2, insn[1], "psadbw", False );
sewardja7ba8c42005-05-10 20:08:34 +000010108 goto decode_success;
10109 }
10110
10111 /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
10112 /* 0F 70 = PSHUFW -- rearrange 4x16 from E(mmx or mem) to G(mmx) */
10113 if (haveNo66noF2noF3(pfx) && sz == 4
10114 && insn[0] == 0x0F && insn[1] == 0x70) {
10115 Int order;
10116 IRTemp sV, dV, s3, s2, s1, s0;
10117 s3 = s2 = s1 = s0 = IRTemp_INVALID;
10118 sV = newTemp(Ity_I64);
10119 dV = newTemp(Ity_I64);
10120 do_MMX_preamble();
10121 modrm = insn[2];
10122 if (epartIsReg(modrm)) {
10123 assign( sV, getMMXReg(eregLO3ofRM(modrm)) );
10124 order = (Int)insn[3];
10125 delta += 2+2;
10126 DIP("pshufw $%d,%s,%s\n", order,
10127 nameMMXReg(eregLO3ofRM(modrm)),
10128 nameMMXReg(gregLO3ofRM(modrm)));
10129 } else {
sewardj2e28ac42008-12-04 00:05:12 +000010130 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf,
sewardja7ba8c42005-05-10 20:08:34 +000010131 1/*extra byte after amode*/ );
10132 assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
10133 order = (Int)insn[2+alen];
10134 delta += 3+alen;
10135 DIP("pshufw $%d,%s,%s\n", order,
10136 dis_buf,
10137 nameMMXReg(gregLO3ofRM(modrm)));
10138 }
10139 breakup64to16s( sV, &s3, &s2, &s1, &s0 );
10140# define SEL(n) \
10141 ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
10142 assign(dV,
10143 mk64from16s( SEL((order>>6)&3), SEL((order>>4)&3),
10144 SEL((order>>2)&3), SEL((order>>0)&3) )
10145 );
10146 putMMXReg(gregLO3ofRM(modrm), mkexpr(dV));
10147# undef SEL
10148 goto decode_success;
10149 }
10150
10151 /* 0F 53 = RCPPS -- approx reciprocal 32Fx4 from R/M to R */
10152 if (haveNo66noF2noF3(pfx) && sz == 4
10153 && insn[0] == 0x0F && insn[1] == 0x53) {
sewardj2e28ac42008-12-04 00:05:12 +000010154 delta = dis_SSE_E_to_G_unary_all( vbi, pfx, delta+2,
sewardja7ba8c42005-05-10 20:08:34 +000010155 "rcpps", Iop_Recip32Fx4 );
10156 goto decode_success;
10157 }
10158
10159 /* F3 0F 53 = RCPSS -- approx reciprocal 32F0x4 from R/M to R */
10160 if (haveF3no66noF2(pfx) && sz == 4
10161 && insn[0] == 0x0F && insn[1] == 0x53) {
sewardj2e28ac42008-12-04 00:05:12 +000010162 delta = dis_SSE_E_to_G_unary_lo32( vbi, pfx, delta+2,
sewardja7ba8c42005-05-10 20:08:34 +000010163 "rcpss", Iop_Recip32F0x4 );
10164 goto decode_success;
10165 }
10166
10167 /* 0F 52 = RSQRTPS -- approx reciprocal sqrt 32Fx4 from R/M to R */
10168 if (haveNo66noF2noF3(pfx) && sz == 4
10169 && insn[0] == 0x0F && insn[1] == 0x52) {
sewardj2e28ac42008-12-04 00:05:12 +000010170 delta = dis_SSE_E_to_G_unary_all( vbi, pfx, delta+2,
sewardja7ba8c42005-05-10 20:08:34 +000010171 "rsqrtps", Iop_RSqrt32Fx4 );
10172 goto decode_success;
10173 }
10174
10175 /* F3 0F 52 = RSQRTSS -- approx reciprocal sqrt 32F0x4 from R/M to R */
10176 if (haveF3no66noF2(pfx) && sz == 4
10177 && insn[0] == 0x0F && insn[1] == 0x52) {
sewardj2e28ac42008-12-04 00:05:12 +000010178 delta = dis_SSE_E_to_G_unary_lo32( vbi, pfx, delta+2,
sewardja7ba8c42005-05-10 20:08:34 +000010179 "rsqrtss", Iop_RSqrt32F0x4 );
10180 goto decode_success;
10181 }
sewardjf53b7352005-04-06 20:01:56 +000010182
10183 /* 0F AE /7 = SFENCE -- flush pending operations to memory */
10184 if (haveNo66noF2noF3(pfx)
10185 && insn[0] == 0x0F && insn[1] == 0xAE
10186 && epartIsReg(insn[2]) && gregLO3ofRM(insn[2]) == 7
10187 && sz == 4) {
10188 delta += 3;
10189 /* Insert a memory fence. It's sometimes important that these
10190 are carried through to the generated code. */
sewardjc4356f02007-11-09 21:15:04 +000010191 stmt( IRStmt_MBE(Imbe_Fence) );
sewardjf53b7352005-04-06 20:01:56 +000010192 DIP("sfence\n");
10193 goto decode_success;
10194 }
10195
sewardja7ba8c42005-05-10 20:08:34 +000010196 /* 0F C6 /r ib = SHUFPS -- shuffle packed F32s */
10197 if (haveNo66noF2noF3(pfx) && sz == 4
10198 && insn[0] == 0x0F && insn[1] == 0xC6) {
10199 Int select;
10200 IRTemp sV, dV;
10201 IRTemp s3, s2, s1, s0, d3, d2, d1, d0;
10202 sV = newTemp(Ity_V128);
10203 dV = newTemp(Ity_V128);
10204 s3 = s2 = s1 = s0 = d3 = d2 = d1 = d0 = IRTemp_INVALID;
10205 modrm = insn[2];
10206 assign( dV, getXMMReg(gregOfRexRM(pfx,modrm)) );
10207
10208 if (epartIsReg(modrm)) {
10209 assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
10210 select = (Int)insn[3];
10211 delta += 2+2;
10212 DIP("shufps $%d,%s,%s\n", select,
10213 nameXMMReg(eregOfRexRM(pfx,modrm)),
10214 nameXMMReg(gregOfRexRM(pfx,modrm)));
10215 } else {
sewardj2e28ac42008-12-04 00:05:12 +000010216 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf,
sewardja7ba8c42005-05-10 20:08:34 +000010217 1/*byte at end of insn*/ );
10218 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
10219 select = (Int)insn[2+alen];
10220 delta += 3+alen;
10221 DIP("shufps $%d,%s,%s\n", select,
10222 dis_buf,
10223 nameXMMReg(gregOfRexRM(pfx,modrm)));
10224 }
10225
10226 breakup128to32s( dV, &d3, &d2, &d1, &d0 );
10227 breakup128to32s( sV, &s3, &s2, &s1, &s0 );
10228
10229# define SELD(n) ((n)==0 ? d0 : ((n)==1 ? d1 : ((n)==2 ? d2 : d3)))
10230# define SELS(n) ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
10231
10232 putXMMReg(
10233 gregOfRexRM(pfx,modrm),
10234 mk128from32s( SELS((select>>6)&3), SELS((select>>4)&3),
10235 SELD((select>>2)&3), SELD((select>>0)&3) )
10236 );
10237
10238# undef SELD
10239# undef SELS
10240
10241 goto decode_success;
10242 }
10243
10244 /* 0F 51 = SQRTPS -- approx sqrt 32Fx4 from R/M to R */
10245 if (haveNo66noF2noF3(pfx) && sz == 4
10246 && insn[0] == 0x0F && insn[1] == 0x51) {
sewardj2e28ac42008-12-04 00:05:12 +000010247 delta = dis_SSE_E_to_G_unary_all( vbi, pfx, delta+2,
sewardja7ba8c42005-05-10 20:08:34 +000010248 "sqrtps", Iop_Sqrt32Fx4 );
10249 goto decode_success;
10250 }
10251
10252 /* F3 0F 51 = SQRTSS -- approx sqrt 32F0x4 from R/M to R */
10253 if (haveF3no66noF2(pfx) && sz == 4
10254 && insn[0] == 0x0F && insn[1] == 0x51) {
sewardj2e28ac42008-12-04 00:05:12 +000010255 delta = dis_SSE_E_to_G_unary_lo32( vbi, pfx, delta+2,
sewardja7ba8c42005-05-10 20:08:34 +000010256 "sqrtss", Iop_Sqrt32F0x4 );
10257 goto decode_success;
10258 }
sewardjbcbb9de2005-03-27 02:22:32 +000010259
10260 /* 0F AE /3 = STMXCSR m32 -- store %mxcsr */
10261 if (insn[0] == 0x0F && insn[1] == 0xAE
10262 && haveNo66noF2noF3(pfx)
10263 && !epartIsReg(insn[2]) && gregLO3ofRM(insn[2]) == 3) {
10264
10265 vassert(sz == 4);
sewardj2e28ac42008-12-04 00:05:12 +000010266 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardjbcbb9de2005-03-27 02:22:32 +000010267 delta += 2+alen;
10268
10269 /* Fake up a native SSE mxcsr word. The only thing it depends
10270 on is SSEROUND[1:0], so call a clean helper to cook it up.
10271 */
10272 /* ULong amd64h_create_mxcsr ( ULong sseround ) */
10273 DIP("stmxcsr %s\n", dis_buf);
10274 storeLE(
10275 mkexpr(addr),
10276 unop(Iop_64to32,
10277 mkIRExprCCall(
10278 Ity_I64, 0/*regp*/,
10279 "amd64g_create_mxcsr", &amd64g_create_mxcsr,
10280 mkIRExprVec_1( unop(Iop_32Uto64,get_sse_roundingmode()) )
10281 )
10282 )
10283 );
10284 goto decode_success;
10285 }
10286
sewardj432f8b62005-05-10 02:50:05 +000010287 /* 0F 5C = SUBPS -- sub 32Fx4 from R/M to R */
10288 if (haveNo66noF2noF3(pfx) && sz == 4
10289 && insn[0] == 0x0F && insn[1] == 0x5C) {
sewardj2e28ac42008-12-04 00:05:12 +000010290 delta = dis_SSE_E_to_G_all( vbi, pfx, delta+2, "subps", Iop_Sub32Fx4 );
sewardj432f8b62005-05-10 02:50:05 +000010291 goto decode_success;
10292 }
sewardj8d965312005-02-25 02:48:47 +000010293
10294 /* F3 0F 5C = SUBSS -- sub 32F0x4 from R/M to R */
10295 if (haveF3no66noF2(pfx) && sz == 4
10296 && insn[0] == 0x0F && insn[1] == 0x5C) {
sewardj2e28ac42008-12-04 00:05:12 +000010297 delta = dis_SSE_E_to_G_lo32( vbi, pfx, delta+2, "subss", Iop_Sub32F0x4 );
sewardj8d965312005-02-25 02:48:47 +000010298 goto decode_success;
10299 }
10300
sewardja7ba8c42005-05-10 20:08:34 +000010301 /* 0F 15 = UNPCKHPS -- unpack and interleave high part F32s */
10302 /* 0F 14 = UNPCKLPS -- unpack and interleave low part F32s */
10303 /* These just appear to be special cases of SHUFPS */
10304 if (haveNo66noF2noF3(pfx) && sz == 4
10305 && insn[0] == 0x0F && (insn[1] == 0x15 || insn[1] == 0x14)) {
10306 IRTemp sV, dV;
10307 IRTemp s3, s2, s1, s0, d3, d2, d1, d0;
sewardjca673ab2005-05-11 10:03:08 +000010308 Bool hi = toBool(insn[1] == 0x15);
sewardja7ba8c42005-05-10 20:08:34 +000010309 sV = newTemp(Ity_V128);
10310 dV = newTemp(Ity_V128);
10311 s3 = s2 = s1 = s0 = d3 = d2 = d1 = d0 = IRTemp_INVALID;
10312 modrm = insn[2];
10313 assign( dV, getXMMReg(gregOfRexRM(pfx,modrm)) );
10314
10315 if (epartIsReg(modrm)) {
10316 assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
10317 delta += 2+1;
10318 DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
10319 nameXMMReg(eregOfRexRM(pfx,modrm)),
10320 nameXMMReg(gregOfRexRM(pfx,modrm)));
10321 } else {
sewardj2e28ac42008-12-04 00:05:12 +000010322 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardja7ba8c42005-05-10 20:08:34 +000010323 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
10324 delta += 2+alen;
10325 DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
10326 dis_buf,
10327 nameXMMReg(gregOfRexRM(pfx,modrm)));
10328 }
10329
10330 breakup128to32s( dV, &d3, &d2, &d1, &d0 );
10331 breakup128to32s( sV, &s3, &s2, &s1, &s0 );
10332
10333 if (hi) {
10334 putXMMReg( gregOfRexRM(pfx,modrm), mk128from32s( s3, d3, s2, d2 ) );
10335 } else {
10336 putXMMReg( gregOfRexRM(pfx,modrm), mk128from32s( s1, d1, s0, d0 ) );
10337 }
10338
10339 goto decode_success;
10340 }
sewardj8d965312005-02-25 02:48:47 +000010341
10342 /* 0F 57 = XORPS -- G = G and E */
10343 if (haveNo66noF2noF3(pfx) && sz == 4
10344 && insn[0] == 0x0F && insn[1] == 0x57) {
sewardj2e28ac42008-12-04 00:05:12 +000010345 delta = dis_SSE_E_to_G_all( vbi, pfx, delta+2, "xorps", Iop_XorV128 );
sewardj8d965312005-02-25 02:48:47 +000010346 goto decode_success;
10347 }
10348
sewardj5992bd02005-05-11 02:13:42 +000010349 /* ---------------------------------------------------- */
10350 /* --- end of the SSE decoder. --- */
10351 /* ---------------------------------------------------- */
10352
10353 /* ---------------------------------------------------- */
10354 /* --- start of the SSE2 decoder. --- */
10355 /* ---------------------------------------------------- */
sewardj4c328cf2005-05-05 12:05:54 +000010356
10357 /* 66 0F 58 = ADDPD -- add 32Fx4 from R/M to R */
sewardjb4bf5882007-11-06 20:39:17 +000010358 if (have66noF2noF3(pfx)
10359 && (sz == 2 || /* ignore redundant REX.W */ sz == 8)
sewardj4c328cf2005-05-05 12:05:54 +000010360 && insn[0] == 0x0F && insn[1] == 0x58) {
sewardj2e28ac42008-12-04 00:05:12 +000010361 delta = dis_SSE_E_to_G_all( vbi, pfx, delta+2, "addpd", Iop_Add64Fx2 );
sewardj4c328cf2005-05-05 12:05:54 +000010362 goto decode_success;
10363 }
sewardj1001dc42005-02-21 08:25:55 +000010364
10365 /* F2 0F 58 = ADDSD -- add 64F0x2 from R/M to R */
sewardjb4bf5882007-11-06 20:39:17 +000010366 if (haveF2no66noF3(pfx)
10367 && (sz == 4 || /* ignore redundant REX.W */ sz == 8)
10368 && insn[0] == 0x0F && insn[1] == 0x58) {
sewardj2e28ac42008-12-04 00:05:12 +000010369 delta = dis_SSE_E_to_G_lo64( vbi, pfx, delta+2, "addsd", Iop_Add64F0x2 );
sewardj1001dc42005-02-21 08:25:55 +000010370 goto decode_success;
10371 }
10372
sewardj8d965312005-02-25 02:48:47 +000010373 /* 66 0F 55 = ANDNPD -- G = (not G) and E */
10374 if (have66noF2noF3(pfx) && sz == 2
10375 && insn[0] == 0x0F && insn[1] == 0x55) {
sewardj2e28ac42008-12-04 00:05:12 +000010376 delta = dis_SSE_E_to_G_all_invG( vbi, pfx, delta+2, "andnpd", Iop_AndV128 );
sewardj8d965312005-02-25 02:48:47 +000010377 goto decode_success;
10378 }
sewardj1a01e652005-02-23 11:39:21 +000010379
10380 /* 66 0F 54 = ANDPD -- G = G and E */
10381 if (have66noF2noF3(pfx) && sz == 2
10382 && insn[0] == 0x0F && insn[1] == 0x54) {
sewardj2e28ac42008-12-04 00:05:12 +000010383 delta = dis_SSE_E_to_G_all( vbi, pfx, delta+2, "andpd", Iop_AndV128 );
sewardj1a01e652005-02-23 11:39:21 +000010384 goto decode_success;
10385 }
10386
sewardj97628592005-05-10 22:42:54 +000010387 /* 66 0F C2 = CMPPD -- 64Fx2 comparison from R/M to R */
10388 if (have66noF2noF3(pfx) && sz == 2
10389 && insn[0] == 0x0F && insn[1] == 0xC2) {
sewardj2e28ac42008-12-04 00:05:12 +000010390 delta = dis_SSEcmp_E_to_G( vbi, pfx, delta+2, "cmppd", True, 8 );
sewardj97628592005-05-10 22:42:54 +000010391 goto decode_success;
10392 }
sewardj8d965312005-02-25 02:48:47 +000010393
10394 /* F2 0F C2 = CMPSD -- 64F0x2 comparison from R/M to R */
10395 if (haveF2no66noF3(pfx) && sz == 4
10396 && insn[0] == 0x0F && insn[1] == 0xC2) {
sewardj2e28ac42008-12-04 00:05:12 +000010397 delta = dis_SSEcmp_E_to_G( vbi, pfx, delta+2, "cmpsd", False, 8 );
sewardj8d965312005-02-25 02:48:47 +000010398 goto decode_success;
10399 }
sewardj18303862005-02-21 12:36:54 +000010400
10401 /* 66 0F 2F = COMISD -- 64F0x2 comparison G,E, and set ZCP */
10402 /* 66 0F 2E = UCOMISD -- 64F0x2 comparison G,E, and set ZCP */
sewardjc49ce232005-02-25 13:03:03 +000010403 if (have66noF2noF3(pfx) && sz == 2
sewardj18303862005-02-21 12:36:54 +000010404 && insn[0] == 0x0F && (insn[1] == 0x2F || insn[1] == 0x2E)) {
10405 IRTemp argL = newTemp(Ity_F64);
10406 IRTemp argR = newTemp(Ity_F64);
10407 modrm = getUChar(delta+2);
10408 if (epartIsReg(modrm)) {
10409 assign( argR, getXMMRegLane64F( eregOfRexRM(pfx,modrm),
10410 0/*lowest lane*/ ) );
10411 delta += 2+1;
10412 DIP("%scomisd %s,%s\n", insn[1]==0x2E ? "u" : "",
10413 nameXMMReg(eregOfRexRM(pfx,modrm)),
10414 nameXMMReg(gregOfRexRM(pfx,modrm)) );
10415 } else {
sewardj2e28ac42008-12-04 00:05:12 +000010416 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj18303862005-02-21 12:36:54 +000010417 assign( argR, loadLE(Ity_F64, mkexpr(addr)) );
10418 delta += 2+alen;
10419 DIP("%scomisd %s,%s\n", insn[1]==0x2E ? "u" : "",
10420 dis_buf,
10421 nameXMMReg(gregOfRexRM(pfx,modrm)) );
10422 }
10423 assign( argL, getXMMRegLane64F( gregOfRexRM(pfx,modrm),
10424 0/*lowest lane*/ ) );
10425
10426 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(AMD64G_CC_OP_COPY) ));
10427 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
10428 stmt( IRStmt_Put(
10429 OFFB_CC_DEP1,
10430 binop( Iop_And64,
10431 unop( Iop_32Uto64,
10432 binop(Iop_CmpF64, mkexpr(argL), mkexpr(argR)) ),
10433 mkU64(0x45)
10434 )));
10435
10436 goto decode_success;
10437 }
10438
sewardj09717342005-05-05 21:34:02 +000010439 /* F3 0F E6 = CVTDQ2PD -- convert 2 x I32 in mem/lo half xmm to 2 x
10440 F64 in xmm(G) */
10441 if (haveF3no66noF2(pfx) && insn[0] == 0x0F && insn[1] == 0xE6) {
10442 IRTemp arg64 = newTemp(Ity_I64);
10443 if (sz != 4) goto decode_failure;
10444
10445 modrm = getUChar(delta+2);
10446 if (epartIsReg(modrm)) {
10447 assign( arg64, getXMMRegLane64(eregOfRexRM(pfx,modrm), 0) );
10448 delta += 2+1;
10449 DIP("cvtdq2pd %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
10450 nameXMMReg(gregOfRexRM(pfx,modrm)));
10451 } else {
sewardj2e28ac42008-12-04 00:05:12 +000010452 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj09717342005-05-05 21:34:02 +000010453 assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
10454 delta += 2+alen;
10455 DIP("cvtdq2pd %s,%s\n", dis_buf,
10456 nameXMMReg(gregOfRexRM(pfx,modrm)) );
10457 }
10458
10459 putXMMRegLane64F(
10460 gregOfRexRM(pfx,modrm), 0,
sewardj6c299f32009-12-31 18:00:12 +000010461 unop(Iop_I32StoF64, unop(Iop_64to32, mkexpr(arg64)))
sewardj09717342005-05-05 21:34:02 +000010462 );
10463
10464 putXMMRegLane64F(
10465 gregOfRexRM(pfx,modrm), 1,
sewardj6c299f32009-12-31 18:00:12 +000010466 unop(Iop_I32StoF64, unop(Iop_64HIto32, mkexpr(arg64)))
sewardj09717342005-05-05 21:34:02 +000010467 );
10468
10469 goto decode_success;
10470 }
10471
sewardj5992bd02005-05-11 02:13:42 +000010472 /* 0F 5B = CVTDQ2PS -- convert 4 x I32 in mem/xmm to 4 x F32 in
10473 xmm(G) */
10474 if (haveNo66noF2noF3(pfx) && sz == 4
10475 && insn[0] == 0x0F && insn[1] == 0x5B) {
sewardj09717342005-05-05 21:34:02 +000010476 IRTemp argV = newTemp(Ity_V128);
10477 IRTemp rmode = newTemp(Ity_I32);
sewardj09717342005-05-05 21:34:02 +000010478
10479 modrm = getUChar(delta+2);
10480 if (epartIsReg(modrm)) {
10481 assign( argV, getXMMReg(eregOfRexRM(pfx,modrm)) );
10482 delta += 2+1;
sewardj5992bd02005-05-11 02:13:42 +000010483 DIP("cvtdq2ps %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
sewardj09717342005-05-05 21:34:02 +000010484 nameXMMReg(gregOfRexRM(pfx,modrm)));
10485 } else {
sewardj2e28ac42008-12-04 00:05:12 +000010486 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj5992bd02005-05-11 02:13:42 +000010487 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
sewardj09717342005-05-05 21:34:02 +000010488 delta += 2+alen;
sewardj5992bd02005-05-11 02:13:42 +000010489 DIP("cvtdq2ps %s,%s\n", dis_buf,
sewardj09717342005-05-05 21:34:02 +000010490 nameXMMReg(gregOfRexRM(pfx,modrm)) );
10491 }
10492
10493 assign( rmode, get_sse_roundingmode() );
sewardj5992bd02005-05-11 02:13:42 +000010494 breakup128to32s( argV, &t3, &t2, &t1, &t0 );
10495
10496# define CVT(_t) binop( Iop_F64toF32, \
10497 mkexpr(rmode), \
sewardj6c299f32009-12-31 18:00:12 +000010498 unop(Iop_I32StoF64,mkexpr(_t)))
sewardj5992bd02005-05-11 02:13:42 +000010499
10500 putXMMRegLane32F( gregOfRexRM(pfx,modrm), 3, CVT(t3) );
10501 putXMMRegLane32F( gregOfRexRM(pfx,modrm), 2, CVT(t2) );
10502 putXMMRegLane32F( gregOfRexRM(pfx,modrm), 1, CVT(t1) );
10503 putXMMRegLane32F( gregOfRexRM(pfx,modrm), 0, CVT(t0) );
10504
10505# undef CVT
10506
10507 goto decode_success;
10508 }
10509
10510 /* 66 0F E6 = CVTTPD2DQ -- convert 2 x F64 in mem/xmm to 2 x I32 in
10511 lo half xmm(G), and zero upper half, rounding towards zero */
10512 /* F2 0F E6 = CVTPD2DQ -- convert 2 x F64 in mem/xmm to 2 x I32 in
10513 lo half xmm(G), according to prevailing rounding mode, and zero
10514 upper half */
10515 if ( ( (haveF2no66noF3(pfx) && sz == 4)
10516 || (have66noF2noF3(pfx) && sz == 2)
10517 )
10518 && insn[0] == 0x0F && insn[1] == 0xE6) {
10519 IRTemp argV = newTemp(Ity_V128);
10520 IRTemp rmode = newTemp(Ity_I32);
10521 Bool r2zero = toBool(sz == 2);
10522
10523 modrm = getUChar(delta+2);
10524 if (epartIsReg(modrm)) {
10525 assign( argV, getXMMReg(eregOfRexRM(pfx,modrm)) );
10526 delta += 2+1;
10527 DIP("cvt%spd2dq %s,%s\n", r2zero ? "t" : "",
10528 nameXMMReg(eregOfRexRM(pfx,modrm)),
10529 nameXMMReg(gregOfRexRM(pfx,modrm)));
10530 } else {
sewardj2e28ac42008-12-04 00:05:12 +000010531 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj5992bd02005-05-11 02:13:42 +000010532 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
10533 delta += 2+alen;
10534 DIP("cvt%spd2dq %s,%s\n", r2zero ? "t" : "",
10535 dis_buf,
10536 nameXMMReg(gregOfRexRM(pfx,modrm)) );
10537 }
10538
10539 if (r2zero) {
10540 assign(rmode, mkU32((UInt)Irrm_ZERO) );
10541 } else {
10542 assign( rmode, get_sse_roundingmode() );
10543 }
10544
sewardj09717342005-05-05 21:34:02 +000010545 t0 = newTemp(Ity_F64);
10546 t1 = newTemp(Ity_F64);
10547 assign( t0, unop(Iop_ReinterpI64asF64,
10548 unop(Iop_V128to64, mkexpr(argV))) );
10549 assign( t1, unop(Iop_ReinterpI64asF64,
10550 unop(Iop_V128HIto64, mkexpr(argV))) );
10551
sewardj6c299f32009-12-31 18:00:12 +000010552# define CVT(_t) binop( Iop_F64toI32S, \
sewardj09717342005-05-05 21:34:02 +000010553 mkexpr(rmode), \
10554 mkexpr(_t) )
10555
10556 putXMMRegLane32( gregOfRexRM(pfx,modrm), 3, mkU32(0) );
10557 putXMMRegLane32( gregOfRexRM(pfx,modrm), 2, mkU32(0) );
10558 putXMMRegLane32( gregOfRexRM(pfx,modrm), 1, CVT(t1) );
10559 putXMMRegLane32( gregOfRexRM(pfx,modrm), 0, CVT(t0) );
10560
10561# undef CVT
10562
10563 goto decode_success;
10564 }
10565
sewardj5992bd02005-05-11 02:13:42 +000010566 /* 66 0F 2D = CVTPD2PI -- convert 2 x F64 in mem/xmm to 2 x
10567 I32 in mmx, according to prevailing SSE rounding mode */
10568 /* 66 0F 2C = CVTTPD2PI -- convert 2 x F64 in mem/xmm to 2 x
10569 I32 in mmx, rounding towards zero */
10570 if (have66noF2noF3(pfx) && sz == 2
10571 && insn[0] == 0x0F && (insn[1] == 0x2D || insn[1] == 0x2C)) {
10572 IRTemp dst64 = newTemp(Ity_I64);
10573 IRTemp rmode = newTemp(Ity_I32);
10574 IRTemp f64lo = newTemp(Ity_F64);
10575 IRTemp f64hi = newTemp(Ity_F64);
sewardjca673ab2005-05-11 10:03:08 +000010576 Bool r2zero = toBool(insn[1] == 0x2C);
sewardj5992bd02005-05-11 02:13:42 +000010577
10578 do_MMX_preamble();
10579 modrm = getUChar(delta+2);
10580
10581 if (epartIsReg(modrm)) {
10582 delta += 2+1;
10583 assign(f64lo, getXMMRegLane64F(eregOfRexRM(pfx,modrm), 0));
10584 assign(f64hi, getXMMRegLane64F(eregOfRexRM(pfx,modrm), 1));
10585 DIP("cvt%spd2pi %s,%s\n", r2zero ? "t" : "",
10586 nameXMMReg(eregOfRexRM(pfx,modrm)),
10587 nameMMXReg(gregLO3ofRM(modrm)));
10588 } else {
sewardj2e28ac42008-12-04 00:05:12 +000010589 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj5992bd02005-05-11 02:13:42 +000010590 assign(f64lo, loadLE(Ity_F64, mkexpr(addr)));
10591 assign(f64hi, loadLE(Ity_F64, binop( Iop_Add64,
10592 mkexpr(addr),
10593 mkU64(8) )));
10594 delta += 2+alen;
10595 DIP("cvt%spf2pi %s,%s\n", r2zero ? "t" : "",
10596 dis_buf,
10597 nameMMXReg(gregLO3ofRM(modrm)));
10598 }
10599
10600 if (r2zero) {
10601 assign(rmode, mkU32((UInt)Irrm_ZERO) );
10602 } else {
10603 assign( rmode, get_sse_roundingmode() );
10604 }
10605
10606 assign(
10607 dst64,
10608 binop( Iop_32HLto64,
sewardj6c299f32009-12-31 18:00:12 +000010609 binop( Iop_F64toI32S, mkexpr(rmode), mkexpr(f64hi) ),
10610 binop( Iop_F64toI32S, mkexpr(rmode), mkexpr(f64lo) )
sewardj5992bd02005-05-11 02:13:42 +000010611 )
10612 );
10613
10614 putMMXReg(gregLO3ofRM(modrm), mkexpr(dst64));
10615 goto decode_success;
10616 }
10617
10618 /* 66 0F 5A = CVTPD2PS -- convert 2 x F64 in mem/xmm to 2 x F32 in
10619 lo half xmm(G), rounding according to prevailing SSE rounding
10620 mode, and zero upper half */
10621 /* Note, this is practically identical to CVTPD2DQ. It would have
10622 been nicer to merge them together, but the insn[] offsets differ
10623 by one. */
10624 if (have66noF2noF3(pfx) && sz == 2
10625 && insn[0] == 0x0F && insn[1] == 0x5A) {
10626 IRTemp argV = newTemp(Ity_V128);
10627 IRTemp rmode = newTemp(Ity_I32);
10628
10629 modrm = getUChar(delta+2);
10630 if (epartIsReg(modrm)) {
10631 assign( argV, getXMMReg(eregOfRexRM(pfx,modrm)) );
10632 delta += 2+1;
10633 DIP("cvtpd2ps %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
10634 nameXMMReg(gregOfRexRM(pfx,modrm)));
10635 } else {
sewardj2e28ac42008-12-04 00:05:12 +000010636 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj5992bd02005-05-11 02:13:42 +000010637 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
10638 delta += 2+alen;
10639 DIP("cvtpd2ps %s,%s\n", dis_buf,
10640 nameXMMReg(gregOfRexRM(pfx,modrm)) );
10641 }
10642
10643 assign( rmode, get_sse_roundingmode() );
10644 t0 = newTemp(Ity_F64);
10645 t1 = newTemp(Ity_F64);
10646 assign( t0, unop(Iop_ReinterpI64asF64,
10647 unop(Iop_V128to64, mkexpr(argV))) );
10648 assign( t1, unop(Iop_ReinterpI64asF64,
10649 unop(Iop_V128HIto64, mkexpr(argV))) );
10650
10651# define CVT(_t) binop( Iop_F64toF32, \
10652 mkexpr(rmode), \
10653 mkexpr(_t) )
10654
10655 putXMMRegLane32( gregOfRexRM(pfx,modrm), 3, mkU32(0) );
10656 putXMMRegLane32( gregOfRexRM(pfx,modrm), 2, mkU32(0) );
10657 putXMMRegLane32F( gregOfRexRM(pfx,modrm), 1, CVT(t1) );
10658 putXMMRegLane32F( gregOfRexRM(pfx,modrm), 0, CVT(t0) );
10659
10660# undef CVT
10661
10662 goto decode_success;
10663 }
10664
10665 /* 66 0F 2A = CVTPI2PD -- convert 2 x I32 in mem/mmx to 2 x F64 in
10666 xmm(G) */
10667 if (have66noF2noF3(pfx) && sz == 2
10668 && insn[0] == 0x0F && insn[1] == 0x2A) {
10669 IRTemp arg64 = newTemp(Ity_I64);
10670
10671 modrm = getUChar(delta+2);
sewardj5992bd02005-05-11 02:13:42 +000010672 if (epartIsReg(modrm)) {
sewardj30a20e92010-02-21 20:40:53 +000010673 /* Only switch to MMX mode if the source is a MMX register.
10674 This is inconsistent with all other instructions which
10675 convert between XMM and (M64 or MMX), which always switch
10676 to MMX mode even if 64-bit operand is M64 and not MMX. At
10677 least, that's what the Intel docs seem to me to say.
10678 Fixes #210264. */
10679 do_MMX_preamble();
sewardj5992bd02005-05-11 02:13:42 +000010680 assign( arg64, getMMXReg(eregLO3ofRM(modrm)) );
10681 delta += 2+1;
10682 DIP("cvtpi2pd %s,%s\n", nameMMXReg(eregLO3ofRM(modrm)),
10683 nameXMMReg(gregOfRexRM(pfx,modrm)));
10684 } else {
sewardj2e28ac42008-12-04 00:05:12 +000010685 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj5992bd02005-05-11 02:13:42 +000010686 assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
10687 delta += 2+alen;
10688 DIP("cvtpi2pd %s,%s\n", dis_buf,
10689 nameXMMReg(gregOfRexRM(pfx,modrm)) );
10690 }
10691
10692 putXMMRegLane64F(
10693 gregOfRexRM(pfx,modrm), 0,
sewardj6c299f32009-12-31 18:00:12 +000010694 unop(Iop_I32StoF64, unop(Iop_64to32, mkexpr(arg64)) )
sewardj5992bd02005-05-11 02:13:42 +000010695 );
10696
10697 putXMMRegLane64F(
10698 gregOfRexRM(pfx,modrm), 1,
sewardj6c299f32009-12-31 18:00:12 +000010699 unop(Iop_I32StoF64, unop(Iop_64HIto32, mkexpr(arg64)) )
sewardj5992bd02005-05-11 02:13:42 +000010700 );
10701
10702 goto decode_success;
10703 }
10704
10705 /* F3 0F 5B = CVTTPS2DQ -- convert 4 x F32 in mem/xmm to 4 x I32 in
10706 xmm(G), rounding towards zero */
10707 /* 66 0F 5B = CVTPS2DQ -- convert 4 x F32 in mem/xmm to 4 x I32 in
10708 xmm(G), as per the prevailing rounding mode */
10709 if ( ( (have66noF2noF3(pfx) && sz == 2)
10710 || (haveF3no66noF2(pfx) && sz == 4)
10711 )
10712 && insn[0] == 0x0F && insn[1] == 0x5B) {
10713 IRTemp argV = newTemp(Ity_V128);
10714 IRTemp rmode = newTemp(Ity_I32);
10715 Bool r2zero = toBool(sz == 4);
10716
10717 modrm = getUChar(delta+2);
10718 if (epartIsReg(modrm)) {
10719 assign( argV, getXMMReg(eregOfRexRM(pfx,modrm)) );
10720 delta += 2+1;
10721 DIP("cvtps2dq %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
10722 nameXMMReg(gregOfRexRM(pfx,modrm)));
10723 } else {
sewardj2e28ac42008-12-04 00:05:12 +000010724 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj5992bd02005-05-11 02:13:42 +000010725 assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
10726 delta += 2+alen;
10727 DIP("cvtps2dq %s,%s\n", dis_buf,
10728 nameXMMReg(gregOfRexRM(pfx,modrm)) );
10729 }
10730
10731 if (r2zero) {
10732 assign( rmode, mkU32((UInt)Irrm_ZERO) );
10733 } else {
10734 assign( rmode, get_sse_roundingmode() );
10735 }
10736
10737 breakup128to32s( argV, &t3, &t2, &t1, &t0 );
10738
10739 /* This is less than ideal. If it turns out to be a performance
10740 bottleneck it can be improved. */
10741# define CVT(_t) \
sewardj6c299f32009-12-31 18:00:12 +000010742 binop( Iop_F64toI32S, \
sewardj5992bd02005-05-11 02:13:42 +000010743 mkexpr(rmode), \
10744 unop( Iop_F32toF64, \
10745 unop( Iop_ReinterpI32asF32, mkexpr(_t))) )
10746
10747 putXMMRegLane32( gregOfRexRM(pfx,modrm), 3, CVT(t3) );
10748 putXMMRegLane32( gregOfRexRM(pfx,modrm), 2, CVT(t2) );
10749 putXMMRegLane32( gregOfRexRM(pfx,modrm), 1, CVT(t1) );
10750 putXMMRegLane32( gregOfRexRM(pfx,modrm), 0, CVT(t0) );
10751
10752# undef CVT
10753
10754 goto decode_success;
10755 }
10756
10757 /* 0F 5A = CVTPS2PD -- convert 2 x F32 in low half mem/xmm to 2 x
10758 F64 in xmm(G). */
10759 if (haveNo66noF2noF3(pfx) && sz == 4
10760 && insn[0] == 0x0F && insn[1] == 0x5A) {
10761 IRTemp f32lo = newTemp(Ity_F32);
10762 IRTemp f32hi = newTemp(Ity_F32);
10763
10764 modrm = getUChar(delta+2);
10765 if (epartIsReg(modrm)) {
10766 assign( f32lo, getXMMRegLane32F(eregOfRexRM(pfx,modrm), 0) );
10767 assign( f32hi, getXMMRegLane32F(eregOfRexRM(pfx,modrm), 1) );
10768 delta += 2+1;
10769 DIP("cvtps2pd %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
10770 nameXMMReg(gregOfRexRM(pfx,modrm)));
10771 } else {
sewardj2e28ac42008-12-04 00:05:12 +000010772 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj5992bd02005-05-11 02:13:42 +000010773 assign( f32lo, loadLE(Ity_F32, mkexpr(addr)) );
10774 assign( f32hi, loadLE(Ity_F32,
10775 binop(Iop_Add64,mkexpr(addr),mkU64(4))) );
10776 delta += 2+alen;
10777 DIP("cvtps2pd %s,%s\n", dis_buf,
10778 nameXMMReg(gregOfRexRM(pfx,modrm)) );
10779 }
10780
10781 putXMMRegLane64F( gregOfRexRM(pfx,modrm), 1,
10782 unop(Iop_F32toF64, mkexpr(f32hi)) );
10783 putXMMRegLane64F( gregOfRexRM(pfx,modrm), 0,
10784 unop(Iop_F32toF64, mkexpr(f32lo)) );
10785
10786 goto decode_success;
10787 }
10788
10789 /* F2 0F 2D = CVTSD2SI
10790 when sz==4 -- convert F64 in mem/low half xmm to I32 in ireg,
10791 according to prevailing SSE rounding mode
10792 when sz==8 -- convert F64 in mem/low half xmm to I64 in ireg,
10793 according to prevailing SSE rounding mode
10794 */
sewardj1a01e652005-02-23 11:39:21 +000010795 /* F2 0F 2C = CVTTSD2SI
10796 when sz==4 -- convert F64 in mem/low half xmm to I32 in ireg,
10797 truncating towards zero
10798 when sz==8 -- convert F64 in mem/low half xmm to I64 in ireg,
10799 truncating towards zero
10800 */
10801 if (haveF2no66noF3(pfx)
10802 && insn[0] == 0x0F
sewardj5992bd02005-05-11 02:13:42 +000010803 && (insn[1] == 0x2D || insn[1] == 0x2C)) {
sewardj1a01e652005-02-23 11:39:21 +000010804 IRTemp rmode = newTemp(Ity_I32);
10805 IRTemp f64lo = newTemp(Ity_F64);
sewardj1027dc22005-02-26 01:55:02 +000010806 Bool r2zero = toBool(insn[1] == 0x2C);
sewardj1a01e652005-02-23 11:39:21 +000010807 vassert(sz == 4 || sz == 8);
10808
10809 modrm = getUChar(delta+2);
10810 if (epartIsReg(modrm)) {
10811 delta += 2+1;
10812 assign(f64lo, getXMMRegLane64F(eregOfRexRM(pfx,modrm), 0));
10813 DIP("cvt%ssd2si %s,%s\n", r2zero ? "t" : "",
10814 nameXMMReg(eregOfRexRM(pfx,modrm)),
sewardj5b470602005-02-27 13:10:48 +000010815 nameIReg(sz, gregOfRexRM(pfx,modrm), False));
sewardj1a01e652005-02-23 11:39:21 +000010816 } else {
sewardj2e28ac42008-12-04 00:05:12 +000010817 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj1a01e652005-02-23 11:39:21 +000010818 assign(f64lo, loadLE(Ity_F64, mkexpr(addr)));
10819 delta += 2+alen;
10820 DIP("cvt%ssd2si %s,%s\n", r2zero ? "t" : "",
10821 dis_buf,
sewardj5b470602005-02-27 13:10:48 +000010822 nameIReg(sz, gregOfRexRM(pfx,modrm), False));
sewardj1a01e652005-02-23 11:39:21 +000010823 }
10824
10825 if (r2zero) {
10826 assign( rmode, mkU32((UInt)Irrm_ZERO) );
10827 } else {
10828 assign( rmode, get_sse_roundingmode() );
10829 }
10830
10831 if (sz == 4) {
sewardj5b470602005-02-27 13:10:48 +000010832 putIReg32( gregOfRexRM(pfx,modrm),
sewardj6c299f32009-12-31 18:00:12 +000010833 binop( Iop_F64toI32S, mkexpr(rmode), mkexpr(f64lo)) );
sewardj1a01e652005-02-23 11:39:21 +000010834 } else {
sewardj5b470602005-02-27 13:10:48 +000010835 putIReg64( gregOfRexRM(pfx,modrm),
sewardj6c299f32009-12-31 18:00:12 +000010836 binop( Iop_F64toI64S, mkexpr(rmode), mkexpr(f64lo)) );
sewardj1a01e652005-02-23 11:39:21 +000010837 }
10838
10839 goto decode_success;
10840 }
10841
sewardj8d965312005-02-25 02:48:47 +000010842 /* F2 0F 5A = CVTSD2SS -- convert F64 in mem/low half xmm to F32 in
10843 low 1/4 xmm(G), according to prevailing SSE rounding mode */
10844 if (haveF2no66noF3(pfx) && sz == 4
10845 && insn[0] == 0x0F && insn[1] == 0x5A) {
10846 IRTemp rmode = newTemp(Ity_I32);
10847 IRTemp f64lo = newTemp(Ity_F64);
10848 vassert(sz == 4);
10849
10850 modrm = getUChar(delta+2);
10851 if (epartIsReg(modrm)) {
10852 delta += 2+1;
10853 assign(f64lo, getXMMRegLane64F(eregOfRexRM(pfx,modrm), 0));
10854 DIP("cvtsd2ss %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
10855 nameXMMReg(gregOfRexRM(pfx,modrm)));
10856 } else {
sewardj2e28ac42008-12-04 00:05:12 +000010857 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj8d965312005-02-25 02:48:47 +000010858 assign(f64lo, loadLE(Ity_F64, mkexpr(addr)));
10859 delta += 2+alen;
10860 DIP("cvtsd2ss %s,%s\n", dis_buf,
10861 nameXMMReg(gregOfRexRM(pfx,modrm)));
10862 }
10863
10864 assign( rmode, get_sse_roundingmode() );
10865 putXMMRegLane32F(
10866 gregOfRexRM(pfx,modrm), 0,
10867 binop( Iop_F64toF32, mkexpr(rmode), mkexpr(f64lo) )
10868 );
10869
10870 goto decode_success;
10871 }
sewardj1a01e652005-02-23 11:39:21 +000010872
10873 /* F2 0F 2A = CVTSI2SD
10874 when sz==4 -- convert I32 in mem/ireg to F64 in low half xmm
10875 when sz==8 -- convert I64 in mem/ireg to F64 in low half xmm
10876 */
sewardj8d965312005-02-25 02:48:47 +000010877 if (haveF2no66noF3(pfx) && (sz == 4 || sz == 8)
10878 && insn[0] == 0x0F && insn[1] == 0x2A) {
sewardj1a01e652005-02-23 11:39:21 +000010879 modrm = getUChar(delta+2);
10880
10881 if (sz == 4) {
10882 IRTemp arg32 = newTemp(Ity_I32);
10883 if (epartIsReg(modrm)) {
sewardj5b470602005-02-27 13:10:48 +000010884 assign( arg32, getIReg32(eregOfRexRM(pfx,modrm)) );
sewardj1a01e652005-02-23 11:39:21 +000010885 delta += 2+1;
sewardj5b470602005-02-27 13:10:48 +000010886 DIP("cvtsi2sd %s,%s\n", nameIReg32(eregOfRexRM(pfx,modrm)),
sewardj1a01e652005-02-23 11:39:21 +000010887 nameXMMReg(gregOfRexRM(pfx,modrm)));
10888 } else {
sewardj2e28ac42008-12-04 00:05:12 +000010889 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj1a01e652005-02-23 11:39:21 +000010890 assign( arg32, loadLE(Ity_I32, mkexpr(addr)) );
10891 delta += 2+alen;
10892 DIP("cvtsi2sd %s,%s\n", dis_buf,
10893 nameXMMReg(gregOfRexRM(pfx,modrm)) );
10894 }
10895 putXMMRegLane64F( gregOfRexRM(pfx,modrm), 0,
sewardj6c299f32009-12-31 18:00:12 +000010896 unop(Iop_I32StoF64, mkexpr(arg32))
sewardj1a01e652005-02-23 11:39:21 +000010897 );
10898 } else {
10899 /* sz == 8 */
10900 IRTemp arg64 = newTemp(Ity_I64);
10901 if (epartIsReg(modrm)) {
sewardj5b470602005-02-27 13:10:48 +000010902 assign( arg64, getIReg64(eregOfRexRM(pfx,modrm)) );
sewardj1a01e652005-02-23 11:39:21 +000010903 delta += 2+1;
sewardj5b470602005-02-27 13:10:48 +000010904 DIP("cvtsi2sdq %s,%s\n", nameIReg64(eregOfRexRM(pfx,modrm)),
sewardj8d965312005-02-25 02:48:47 +000010905 nameXMMReg(gregOfRexRM(pfx,modrm)));
sewardj1a01e652005-02-23 11:39:21 +000010906 } else {
sewardj2e28ac42008-12-04 00:05:12 +000010907 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj1a01e652005-02-23 11:39:21 +000010908 assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
10909 delta += 2+alen;
sewardj8d965312005-02-25 02:48:47 +000010910 DIP("cvtsi2sdq %s,%s\n", dis_buf,
10911 nameXMMReg(gregOfRexRM(pfx,modrm)) );
sewardj1a01e652005-02-23 11:39:21 +000010912 }
10913 putXMMRegLane64F(
10914 gregOfRexRM(pfx,modrm),
10915 0,
sewardj6c299f32009-12-31 18:00:12 +000010916 binop( Iop_I64StoF64,
sewardj1a01e652005-02-23 11:39:21 +000010917 get_sse_roundingmode(),
10918 mkexpr(arg64)
10919 )
10920 );
10921
10922 }
10923
10924 goto decode_success;
10925 }
10926
sewardjc49ce232005-02-25 13:03:03 +000010927 /* F3 0F 5A = CVTSS2SD -- convert F32 in mem/low 1/4 xmm to F64 in
10928 low half xmm(G) */
10929 if (haveF3no66noF2(pfx) && sz == 4
10930 && insn[0] == 0x0F && insn[1] == 0x5A) {
10931 IRTemp f32lo = newTemp(Ity_F32);
10932
10933 modrm = getUChar(delta+2);
10934 if (epartIsReg(modrm)) {
10935 delta += 2+1;
10936 assign(f32lo, getXMMRegLane32F(eregOfRexRM(pfx,modrm), 0));
10937 DIP("cvtss2sd %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
10938 nameXMMReg(gregOfRexRM(pfx,modrm)));
10939 } else {
sewardj2e28ac42008-12-04 00:05:12 +000010940 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardjc49ce232005-02-25 13:03:03 +000010941 assign(f32lo, loadLE(Ity_F32, mkexpr(addr)));
10942 delta += 2+alen;
10943 DIP("cvtss2sd %s,%s\n", dis_buf,
10944 nameXMMReg(gregOfRexRM(pfx,modrm)));
10945 }
10946
10947 putXMMRegLane64F( gregOfRexRM(pfx,modrm), 0,
10948 unop( Iop_F32toF64, mkexpr(f32lo) ) );
10949
10950 goto decode_success;
10951 }
10952
sewardj5992bd02005-05-11 02:13:42 +000010953 /* 66 0F 5E = DIVPD -- div 64Fx2 from R/M to R */
10954 if (have66noF2noF3(pfx) && sz == 2
10955 && insn[0] == 0x0F && insn[1] == 0x5E) {
sewardj2e28ac42008-12-04 00:05:12 +000010956 delta = dis_SSE_E_to_G_all( vbi, pfx, delta+2, "divpd", Iop_Div64Fx2 );
sewardj5992bd02005-05-11 02:13:42 +000010957 goto decode_success;
10958 }
sewardj1001dc42005-02-21 08:25:55 +000010959
10960 /* F2 0F 5E = DIVSD -- div 64F0x2 from R/M to R */
10961 if (haveF2no66noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x5E) {
10962 vassert(sz == 4);
sewardj2e28ac42008-12-04 00:05:12 +000010963 delta = dis_SSE_E_to_G_lo64( vbi, pfx, delta+2, "divsd", Iop_Div64F0x2 );
sewardj1001dc42005-02-21 08:25:55 +000010964 goto decode_success;
10965 }
10966
sewardj5992bd02005-05-11 02:13:42 +000010967 /* 0F AE /5 = LFENCE -- flush pending operations to memory */
10968 /* 0F AE /6 = MFENCE -- flush pending operations to memory */
10969 if (haveNo66noF2noF3(pfx) && sz == 4
10970 && insn[0] == 0x0F && insn[1] == 0xAE
10971 && epartIsReg(insn[2])
10972 && (gregLO3ofRM(insn[2]) == 5 || gregLO3ofRM(insn[2]) == 6)) {
10973 delta += 3;
10974 /* Insert a memory fence. It's sometimes important that these
10975 are carried through to the generated code. */
sewardjc4356f02007-11-09 21:15:04 +000010976 stmt( IRStmt_MBE(Imbe_Fence) );
sewardj5992bd02005-05-11 02:13:42 +000010977 DIP("%sfence\n", gregLO3ofRM(insn[2])==5 ? "l" : "m");
10978 goto decode_success;
10979 }
10980
10981 /* 66 0F 5F = MAXPD -- max 64Fx2 from R/M to R */
10982 if (have66noF2noF3(pfx) && sz == 2
10983 && insn[0] == 0x0F && insn[1] == 0x5F) {
sewardj2e28ac42008-12-04 00:05:12 +000010984 delta = dis_SSE_E_to_G_all( vbi, pfx, delta+2, "maxpd", Iop_Max64Fx2 );
sewardj5992bd02005-05-11 02:13:42 +000010985 goto decode_success;
10986 }
sewardj1a01e652005-02-23 11:39:21 +000010987
10988 /* F2 0F 5F = MAXSD -- max 64F0x2 from R/M to R */
10989 if (haveF2no66noF3(pfx) && sz == 4
10990 && insn[0] == 0x0F && insn[1] == 0x5F) {
sewardj2e28ac42008-12-04 00:05:12 +000010991 delta = dis_SSE_E_to_G_lo64( vbi, pfx, delta+2, "maxsd", Iop_Max64F0x2 );
sewardj1a01e652005-02-23 11:39:21 +000010992 goto decode_success;
10993 }
10994
sewardj5992bd02005-05-11 02:13:42 +000010995 /* 66 0F 5D = MINPD -- min 64Fx2 from R/M to R */
10996 if (have66noF2noF3(pfx) && sz == 2
10997 && insn[0] == 0x0F && insn[1] == 0x5D) {
sewardj2e28ac42008-12-04 00:05:12 +000010998 delta = dis_SSE_E_to_G_all( vbi, pfx, delta+2, "minpd", Iop_Min64Fx2 );
sewardj5992bd02005-05-11 02:13:42 +000010999 goto decode_success;
11000 }
sewardjc49ce232005-02-25 13:03:03 +000011001
11002 /* F2 0F 5D = MINSD -- min 64F0x2 from R/M to R */
11003 if (haveF2no66noF3(pfx) && sz == 4
11004 && insn[0] == 0x0F && insn[1] == 0x5D) {
sewardj2e28ac42008-12-04 00:05:12 +000011005 delta = dis_SSE_E_to_G_lo64( vbi, pfx, delta+2, "minsd", Iop_Min64F0x2 );
sewardjc49ce232005-02-25 13:03:03 +000011006 goto decode_success;
11007 }
sewardj8d965312005-02-25 02:48:47 +000011008
11009 /* 66 0F 28 = MOVAPD -- move from E (mem or xmm) to G (xmm). */
11010 /* 66 0F 10 = MOVUPD -- move from E (mem or xmm) to G (xmm). */
11011 /* 66 0F 6F = MOVDQA -- move from E (mem or xmm) to G (xmm). */
sewardjb4bf5882007-11-06 20:39:17 +000011012 if (have66noF2noF3(pfx)
11013 && (sz == 2 || /* ignore redundant REX.W */ sz == 8)
sewardj8d965312005-02-25 02:48:47 +000011014 && insn[0] == 0x0F
11015 && (insn[1] == 0x28 || insn[1] == 0x10 || insn[1] == 0x6F)) {
11016 HChar* wot = insn[1]==0x28 ? "apd" :
11017 insn[1]==0x10 ? "upd" : "dqa";
11018 modrm = getUChar(delta+2);
11019 if (epartIsReg(modrm)) {
11020 putXMMReg( gregOfRexRM(pfx,modrm),
11021 getXMMReg( eregOfRexRM(pfx,modrm) ));
11022 DIP("mov%s %s,%s\n", wot, nameXMMReg(eregOfRexRM(pfx,modrm)),
11023 nameXMMReg(gregOfRexRM(pfx,modrm)));
11024 delta += 2+1;
11025 } else {
sewardj2e28ac42008-12-04 00:05:12 +000011026 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj8d965312005-02-25 02:48:47 +000011027 putXMMReg( gregOfRexRM(pfx,modrm),
11028 loadLE(Ity_V128, mkexpr(addr)) );
11029 DIP("mov%s %s,%s\n", wot, dis_buf,
11030 nameXMMReg(gregOfRexRM(pfx,modrm)));
11031 delta += 2+alen;
11032 }
11033 goto decode_success;
11034 }
11035
sewardj4c328cf2005-05-05 12:05:54 +000011036 /* 66 0F 29 = MOVAPD -- move from G (xmm) to E (mem or xmm). */
sewardj240fd862005-11-01 18:59:38 +000011037 /* 66 0F 11 = MOVUPD -- move from G (xmm) to E (mem or xmm). */
11038 if (have66noF2noF3(pfx) && insn[0] == 0x0F
11039 && (insn[1] == 0x29 || insn[1] == 0x11)) {
sewardj4c328cf2005-05-05 12:05:54 +000011040 modrm = getUChar(delta+2);
11041 if (epartIsReg(modrm)) {
11042 /* fall through; awaiting test case */
11043 } else {
sewardj2e28ac42008-12-04 00:05:12 +000011044 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj4c328cf2005-05-05 12:05:54 +000011045 storeLE( mkexpr(addr), getXMMReg(gregOfRexRM(pfx,modrm)) );
sewardj240fd862005-11-01 18:59:38 +000011046 DIP("mov[ua]pd %s,%s\n", nameXMMReg(gregOfRexRM(pfx,modrm)),
11047 dis_buf );
sewardj4c328cf2005-05-05 12:05:54 +000011048 delta += 2+alen;
11049 goto decode_success;
11050 }
11051 }
11052
sewardj09717342005-05-05 21:34:02 +000011053 /* 66 0F 6E = MOVD from ireg32/m32 to xmm lo 1/4, zeroing high 3/4 of xmm. */
11054 /* or from ireg64/m64 to xmm lo 1/2, zeroing high 1/2 of xmm. */
11055 if (have66noF2noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x6E) {
sewardj97628592005-05-10 22:42:54 +000011056 vassert(sz == 2 || sz == 8);
11057 if (sz == 2) sz = 4;
sewardj09717342005-05-05 21:34:02 +000011058 modrm = getUChar(delta+2);
11059 if (epartIsReg(modrm)) {
11060 delta += 2+1;
11061 if (sz == 4) {
sewardj09717342005-05-05 21:34:02 +000011062 putXMMReg(
11063 gregOfRexRM(pfx,modrm),
11064 unop( Iop_32UtoV128, getIReg32(eregOfRexRM(pfx,modrm)) )
11065 );
11066 DIP("movd %s, %s\n", nameIReg32(eregOfRexRM(pfx,modrm)),
11067 nameXMMReg(gregOfRexRM(pfx,modrm)));
11068 } else {
11069 putXMMReg(
11070 gregOfRexRM(pfx,modrm),
11071 unop( Iop_64UtoV128, getIReg64(eregOfRexRM(pfx,modrm)) )
11072 );
11073 DIP("movq %s, %s\n", nameIReg64(eregOfRexRM(pfx,modrm)),
11074 nameXMMReg(gregOfRexRM(pfx,modrm)));
11075 }
11076 } else {
sewardj2e28ac42008-12-04 00:05:12 +000011077 addr = disAMode( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj09717342005-05-05 21:34:02 +000011078 delta += 2+alen;
11079 putXMMReg(
11080 gregOfRexRM(pfx,modrm),
11081 sz == 4
11082 ? unop( Iop_32UtoV128,loadLE(Ity_I32, mkexpr(addr)) )
11083 : unop( Iop_64UtoV128,loadLE(Ity_I64, mkexpr(addr)) )
11084 );
11085 DIP("mov%c %s, %s\n", sz == 4 ? 'd' : 'q', dis_buf,
11086 nameXMMReg(gregOfRexRM(pfx,modrm)));
11087 }
11088 goto decode_success;
11089 }
11090
11091 /* 66 0F 7E = MOVD from xmm low 1/4 to ireg32 or m32. */
11092 /* or from xmm low 1/2 to ireg64 or m64. */
11093 if (have66noF2noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x7E) {
11094 if (sz == 2) sz = 4;
11095 vassert(sz == 4 || sz == 8);
11096 modrm = getUChar(delta+2);
11097 if (epartIsReg(modrm)) {
11098 delta += 2+1;
11099 if (sz == 4) {
11100 putIReg32( eregOfRexRM(pfx,modrm),
11101 getXMMRegLane32(gregOfRexRM(pfx,modrm), 0) );
11102 DIP("movd %s, %s\n", nameXMMReg(gregOfRexRM(pfx,modrm)),
11103 nameIReg32(eregOfRexRM(pfx,modrm)));
11104 } else {
11105 putIReg64( eregOfRexRM(pfx,modrm),
11106 getXMMRegLane64(gregOfRexRM(pfx,modrm), 0) );
11107 DIP("movq %s, %s\n", nameXMMReg(gregOfRexRM(pfx,modrm)),
11108 nameIReg64(eregOfRexRM(pfx,modrm)));
11109 }
11110 } else {
sewardj2e28ac42008-12-04 00:05:12 +000011111 addr = disAMode( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj09717342005-05-05 21:34:02 +000011112 delta += 2+alen;
11113 storeLE( mkexpr(addr),
11114 sz == 4
11115 ? getXMMRegLane32(gregOfRexRM(pfx,modrm),0)
11116 : getXMMRegLane64(gregOfRexRM(pfx,modrm),0) );
11117 DIP("mov%c %s, %s\n", sz == 4 ? 'd' : 'q',
11118 nameXMMReg(gregOfRexRM(pfx,modrm)), dis_buf);
11119 }
11120 goto decode_success;
11121 }
11122
11123 /* 66 0F 7F = MOVDQA -- move from G (xmm) to E (mem or xmm). */
11124 if (have66noF2noF3(pfx) && sz == 2
11125 && insn[0] == 0x0F && insn[1] == 0x7F) {
11126 modrm = getUChar(delta+2);
11127 if (epartIsReg(modrm)) {
11128 delta += 2+1;
11129 putXMMReg( eregOfRexRM(pfx,modrm),
11130 getXMMReg(gregOfRexRM(pfx,modrm)) );
11131 DIP("movdqa %s, %s\n", nameXMMReg(gregOfRexRM(pfx,modrm)),
11132 nameXMMReg(eregOfRexRM(pfx,modrm)));
11133 } else {
sewardj2e28ac42008-12-04 00:05:12 +000011134 addr = disAMode( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj09717342005-05-05 21:34:02 +000011135 delta += 2+alen;
11136 storeLE( mkexpr(addr), getXMMReg(gregOfRexRM(pfx,modrm)) );
11137 DIP("movdqa %s, %s\n", nameXMMReg(gregOfRexRM(pfx,modrm)), dis_buf);
11138 }
11139 goto decode_success;
11140 }
11141
sewardj612be432005-05-11 02:55:54 +000011142 /* F3 0F 6F = MOVDQU -- move from E (mem or xmm) to G (xmm). */
11143 if (haveF3no66noF2(pfx) && sz == 4
11144 && insn[0] == 0x0F && insn[1] == 0x6F) {
11145 modrm = getUChar(delta+2);
11146 if (epartIsReg(modrm)) {
11147 putXMMReg( gregOfRexRM(pfx,modrm),
11148 getXMMReg( eregOfRexRM(pfx,modrm) ));
11149 DIP("movdqu %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
11150 nameXMMReg(gregOfRexRM(pfx,modrm)));
11151 delta += 2+1;
11152 } else {
sewardj2e28ac42008-12-04 00:05:12 +000011153 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj612be432005-05-11 02:55:54 +000011154 putXMMReg( gregOfRexRM(pfx,modrm),
11155 loadLE(Ity_V128, mkexpr(addr)) );
11156 DIP("movdqu %s,%s\n", dis_buf,
11157 nameXMMReg(gregOfRexRM(pfx,modrm)));
11158 delta += 2+alen;
11159 }
11160 goto decode_success;
11161 }
11162
11163 /* F3 0F 7F = MOVDQU -- move from G (xmm) to E (mem or xmm). */
11164 if (haveF3no66noF2(pfx) && sz == 4
11165 && insn[0] == 0x0F && insn[1] == 0x7F) {
11166 modrm = getUChar(delta+2);
11167 if (epartIsReg(modrm)) {
11168 goto decode_failure; /* awaiting test case */
11169 delta += 2+1;
11170 putXMMReg( eregOfRexRM(pfx,modrm),
11171 getXMMReg(gregOfRexRM(pfx,modrm)) );
11172 DIP("movdqu %s, %s\n", nameXMMReg(gregOfRexRM(pfx,modrm)),
11173 nameXMMReg(eregOfRexRM(pfx,modrm)));
11174 } else {
sewardj2e28ac42008-12-04 00:05:12 +000011175 addr = disAMode( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj612be432005-05-11 02:55:54 +000011176 delta += 2+alen;
11177 storeLE( mkexpr(addr), getXMMReg(gregOfRexRM(pfx,modrm)) );
11178 DIP("movdqu %s, %s\n", nameXMMReg(gregOfRexRM(pfx,modrm)), dis_buf);
11179 }
11180 goto decode_success;
11181 }
11182
11183 /* F2 0F D6 = MOVDQ2Q -- move from E (lo half xmm, not mem) to G (mmx). */
11184 if (haveF2no66noF3(pfx) && sz == 4
11185 && insn[0] == 0x0F && insn[1] == 0xD6) {
11186 modrm = getUChar(delta+2);
11187 if (epartIsReg(modrm)) {
11188 do_MMX_preamble();
11189 putMMXReg( gregLO3ofRM(modrm),
11190 getXMMRegLane64( eregOfRexRM(pfx,modrm), 0 ));
11191 DIP("movdq2q %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
11192 nameMMXReg(gregLO3ofRM(modrm)));
11193 delta += 2+1;
11194 goto decode_success;
11195 } else {
11196 /* apparently no mem case for this insn */
11197 goto decode_failure;
11198 }
11199 }
sewardj4c328cf2005-05-05 12:05:54 +000011200
11201 /* 66 0F 16 = MOVHPD -- move from mem to high half of XMM. */
11202 /* These seems identical to MOVHPS. This instruction encoding is
11203 completely crazy. */
11204 if (have66noF2noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x16) {
11205 modrm = getUChar(delta+2);
11206 if (epartIsReg(modrm)) {
11207 /* fall through; apparently reg-reg is not possible */
11208 } else {
sewardj2e28ac42008-12-04 00:05:12 +000011209 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj4c328cf2005-05-05 12:05:54 +000011210 delta += 2+alen;
11211 putXMMRegLane64( gregOfRexRM(pfx,modrm), 1/*upper lane*/,
11212 loadLE(Ity_I64, mkexpr(addr)) );
11213 DIP("movhpd %s,%s\n", dis_buf,
11214 nameXMMReg( gregOfRexRM(pfx,modrm) ));
11215 goto decode_success;
11216 }
11217 }
11218
11219 /* 66 0F 17 = MOVHPD -- move from high half of XMM to mem. */
11220 /* Again, this seems identical to MOVHPS. */
11221 if (have66noF2noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x17) {
11222 if (!epartIsReg(insn[2])) {
11223 delta += 2;
sewardj2e28ac42008-12-04 00:05:12 +000011224 addr = disAMode ( &alen, vbi, pfx, delta, dis_buf, 0 );
sewardj4c328cf2005-05-05 12:05:54 +000011225 delta += alen;
11226 storeLE( mkexpr(addr),
11227 getXMMRegLane64( gregOfRexRM(pfx,insn[2]),
11228 1/*upper lane*/ ) );
11229 DIP("movhpd %s,%s\n", nameXMMReg( gregOfRexRM(pfx,insn[2]) ),
11230 dis_buf);
11231 goto decode_success;
11232 }
11233 /* else fall through */
11234 }
sewardj1001dc42005-02-21 08:25:55 +000011235
11236 /* 66 0F 12 = MOVLPD -- move from mem to low half of XMM. */
11237 /* Identical to MOVLPS ? */
11238 if (have66noF2noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x12) {
11239 modrm = getUChar(delta+2);
11240 if (epartIsReg(modrm)) {
11241 /* fall through; apparently reg-reg is not possible */
11242 } else {
sewardj2e28ac42008-12-04 00:05:12 +000011243 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj1001dc42005-02-21 08:25:55 +000011244 delta += 2+alen;
11245 putXMMRegLane64( gregOfRexRM(pfx,modrm),
11246 0/*lower lane*/,
11247 loadLE(Ity_I64, mkexpr(addr)) );
11248 DIP("movlpd %s, %s\n",
11249 dis_buf, nameXMMReg( gregOfRexRM(pfx,modrm) ));
11250 goto decode_success;
11251 }
11252 }
11253
sewardj4c328cf2005-05-05 12:05:54 +000011254 /* 66 0F 13 = MOVLPD -- move from low half of XMM to mem. */
11255 /* Identical to MOVLPS ? */
11256 if (have66noF2noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x13) {
11257 modrm = getUChar(delta+2);
11258 if (!epartIsReg(modrm)) {
sewardj2e28ac42008-12-04 00:05:12 +000011259 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj4c328cf2005-05-05 12:05:54 +000011260 delta += 2+alen;
11261 storeLE( mkexpr(addr),
11262 getXMMRegLane64( gregOfRexRM(pfx,modrm),
11263 0/*lower lane*/ ) );
11264 DIP("movlpd %s, %s\n", nameXMMReg( gregOfRexRM(pfx,modrm) ),
11265 dis_buf);
11266 goto decode_success;
11267 }
11268 /* else fall through */
11269 }
11270
sewardj612be432005-05-11 02:55:54 +000011271 /* 66 0F 50 = MOVMSKPD - move 2 sign bits from 2 x F64 in xmm(E) to
11272 2 lowest bits of ireg(G) */
sewardjae84d782006-04-13 22:06:35 +000011273 if (have66noF2noF3(pfx) && (sz == 2 || sz == 8)
sewardj612be432005-05-11 02:55:54 +000011274 && insn[0] == 0x0F && insn[1] == 0x50) {
sewardjae84d782006-04-13 22:06:35 +000011275 /* sz == 8 is a kludge to handle insns with REX.W redundantly
11276 set to 1, which has been known to happen:
11277 66 4c 0f 50 d9 rex64X movmskpd %xmm1,%r11d
sewardjb4bf5882007-11-06 20:39:17 +000011278 20071106: see further comments on MOVMSKPS implementation above.
sewardjae84d782006-04-13 22:06:35 +000011279 */
sewardj612be432005-05-11 02:55:54 +000011280 modrm = getUChar(delta+2);
11281 if (epartIsReg(modrm)) {
11282 Int src;
11283 t0 = newTemp(Ity_I32);
11284 t1 = newTemp(Ity_I32);
11285 delta += 2+1;
11286 src = eregOfRexRM(pfx,modrm);
11287 assign( t0, binop( Iop_And32,
11288 binop(Iop_Shr32, getXMMRegLane32(src,1), mkU8(31)),
11289 mkU32(1) ));
11290 assign( t1, binop( Iop_And32,
11291 binop(Iop_Shr32, getXMMRegLane32(src,3), mkU8(30)),
11292 mkU32(2) ));
11293 putIReg32( gregOfRexRM(pfx,modrm),
11294 binop(Iop_Or32, mkexpr(t0), mkexpr(t1))
11295 );
11296 DIP("movmskpd %s,%s\n", nameXMMReg(src),
11297 nameIReg32(gregOfRexRM(pfx,modrm)));
11298 goto decode_success;
11299 }
11300 /* else fall through */
11301 goto decode_failure;
11302 }
11303
sewardj02f79f12007-09-01 18:59:53 +000011304 /* 66 0F F7 = MASKMOVDQU -- store selected bytes of double quadword */
11305 if (have66noF2noF3(pfx) && sz == 2
11306 && insn[0] == 0x0F && insn[1] == 0xF7) {
11307 modrm = getUChar(delta+2);
11308 if (epartIsReg(modrm)) {
11309 IRTemp regD = newTemp(Ity_V128);
11310 IRTemp mask = newTemp(Ity_V128);
11311 IRTemp olddata = newTemp(Ity_V128);
11312 IRTemp newdata = newTemp(Ity_V128);
11313 addr = newTemp(Ity_I64);
11314
sewardj2e28ac42008-12-04 00:05:12 +000011315 assign( addr, handleAddrOverrides( vbi, pfx, getIReg64(R_RDI) ));
sewardj02f79f12007-09-01 18:59:53 +000011316 assign( regD, getXMMReg( gregOfRexRM(pfx,modrm) ));
11317
11318 /* Unfortunately can't do the obvious thing with SarN8x16
11319 here since that can't be re-emitted as SSE2 code - no such
11320 insn. */
11321 assign(
11322 mask,
11323 binop(Iop_64HLtoV128,
11324 binop(Iop_SarN8x8,
11325 getXMMRegLane64( eregOfRexRM(pfx,modrm), 1 ),
11326 mkU8(7) ),
11327 binop(Iop_SarN8x8,
11328 getXMMRegLane64( eregOfRexRM(pfx,modrm), 0 ),
11329 mkU8(7) ) ));
11330 assign( olddata, loadLE( Ity_V128, mkexpr(addr) ));
11331 assign( newdata,
11332 binop(Iop_OrV128,
11333 binop(Iop_AndV128,
11334 mkexpr(regD),
11335 mkexpr(mask) ),
11336 binop(Iop_AndV128,
11337 mkexpr(olddata),
11338 unop(Iop_NotV128, mkexpr(mask)))) );
11339 storeLE( mkexpr(addr), mkexpr(newdata) );
11340
11341 delta += 2+1;
11342 DIP("maskmovdqu %s,%s\n", nameXMMReg( eregOfRexRM(pfx,modrm) ),
11343 nameXMMReg( gregOfRexRM(pfx,modrm) ) );
11344 goto decode_success;
11345 }
11346 /* else fall through */
11347 }
11348
sewardj612be432005-05-11 02:55:54 +000011349 /* 66 0F E7 = MOVNTDQ -- for us, just a plain SSE store. */
11350 if (have66noF2noF3(pfx) && sz == 2
11351 && insn[0] == 0x0F && insn[1] == 0xE7) {
11352 modrm = getUChar(delta+2);
11353 if (!epartIsReg(modrm)) {
sewardj2e28ac42008-12-04 00:05:12 +000011354 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj612be432005-05-11 02:55:54 +000011355 storeLE( mkexpr(addr), getXMMReg(gregOfRexRM(pfx,modrm)) );
11356 DIP("movntdq %s,%s\n", dis_buf,
11357 nameXMMReg(gregOfRexRM(pfx,modrm)));
11358 delta += 2+alen;
11359 goto decode_success;
11360 }
11361 /* else fall through */
11362 goto decode_failure;
11363 }
sewardjf53b7352005-04-06 20:01:56 +000011364
11365 /* 0F C3 = MOVNTI -- for us, just a plain ireg store. */
11366 if (haveNo66noF2noF3(pfx) &&
11367 insn[0] == 0x0F && insn[1] == 0xC3) {
11368 vassert(sz == 4 || sz == 8);
11369 modrm = getUChar(delta+2);
11370 if (!epartIsReg(modrm)) {
sewardj2e28ac42008-12-04 00:05:12 +000011371 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardjf53b7352005-04-06 20:01:56 +000011372 storeLE( mkexpr(addr), getIRegG(sz, pfx, modrm) );
11373 DIP("movnti %s,%s\n", dis_buf,
11374 nameIRegG(sz, pfx, modrm));
11375 delta += 2+alen;
11376 goto decode_success;
11377 }
11378 /* else fall through */
11379 }
sewardj5cc00ff2005-03-27 04:48:32 +000011380
11381 /* 66 0F D6 = MOVQ -- move 64 bits from G (lo half xmm) to E (mem
11382 or lo half xmm). */
sewardjb4bf5882007-11-06 20:39:17 +000011383 if (have66noF2noF3(pfx)
11384 && (sz == 2 || /* ignore redundant REX.W */ sz == 8)
11385 && insn[0] == 0x0F && insn[1] == 0xD6) {
sewardj5cc00ff2005-03-27 04:48:32 +000011386 modrm = getUChar(delta+2);
11387 if (epartIsReg(modrm)) {
11388 /* fall through, awaiting test case */
sewardj94a48b22005-05-14 11:17:25 +000011389 /* dst: lo half copied, hi half zeroed */
sewardj5cc00ff2005-03-27 04:48:32 +000011390 } else {
sewardj2e28ac42008-12-04 00:05:12 +000011391 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj5cc00ff2005-03-27 04:48:32 +000011392 storeLE( mkexpr(addr),
11393 getXMMRegLane64( gregOfRexRM(pfx,modrm), 0 ));
11394 DIP("movq %s,%s\n", nameXMMReg(gregOfRexRM(pfx,modrm)), dis_buf );
11395 delta += 2+alen;
11396 goto decode_success;
11397 }
11398 }
11399
sewardj612be432005-05-11 02:55:54 +000011400 /* F3 0F D6 = MOVQ2DQ -- move from E (mmx) to G (lo half xmm, zero
11401 hi half). */
11402 if (haveF3no66noF2(pfx) && sz == 4
11403 && insn[0] == 0x0F && insn[1] == 0xD6) {
11404 modrm = getUChar(delta+2);
11405 if (epartIsReg(modrm)) {
11406 do_MMX_preamble();
11407 putXMMReg( gregOfRexRM(pfx,modrm),
11408 unop(Iop_64UtoV128, getMMXReg( eregLO3ofRM(modrm) )) );
11409 DIP("movq2dq %s,%s\n", nameMMXReg(eregLO3ofRM(modrm)),
11410 nameXMMReg(gregOfRexRM(pfx,modrm)));
11411 delta += 2+1;
11412 goto decode_success;
11413 } else {
11414 /* apparently no mem case for this insn */
11415 goto decode_failure;
11416 }
11417 }
11418
11419 /* F3 0F 7E = MOVQ -- move 64 bits from E (mem or lo half xmm) to
sewardj94a48b22005-05-14 11:17:25 +000011420 G (lo half xmm). Upper half of G is zeroed out. */
sewardj1001dc42005-02-21 08:25:55 +000011421 /* F2 0F 10 = MOVSD -- move 64 bits from E (mem or lo half xmm) to
11422 G (lo half xmm). If E is mem, upper half of G is zeroed out.
sewardj94a48b22005-05-14 11:17:25 +000011423 If E is reg, upper half of G is unchanged. */
sewardjb4bf5882007-11-06 20:39:17 +000011424 if ( (haveF2no66noF3(pfx)
11425 && (sz == 4 || /* ignore redundant REX.W */ sz == 8)
sewardj612be432005-05-11 02:55:54 +000011426 && insn[0] == 0x0F && insn[1] == 0x10)
sewardj5cc00ff2005-03-27 04:48:32 +000011427 ||
sewardjb4bf5882007-11-06 20:39:17 +000011428 (haveF3no66noF2(pfx)
11429 && (sz == 4 || /* ignore redundant REX.W */ sz == 8)
sewardj612be432005-05-11 02:55:54 +000011430 && insn[0] == 0x0F && insn[1] == 0x7E)
sewardj1001dc42005-02-21 08:25:55 +000011431 ) {
sewardj1001dc42005-02-21 08:25:55 +000011432 modrm = getUChar(delta+2);
11433 if (epartIsReg(modrm)) {
11434 putXMMRegLane64( gregOfRexRM(pfx,modrm), 0,
11435 getXMMRegLane64( eregOfRexRM(pfx,modrm), 0 ));
sewardj94a48b22005-05-14 11:17:25 +000011436 if (insn[1] == 0x7E/*MOVQ*/) {
11437 /* zero bits 127:64 */
11438 putXMMRegLane64( gregOfRexRM(pfx,modrm), 1, mkU64(0) );
11439 }
sewardj1001dc42005-02-21 08:25:55 +000011440 DIP("movsd %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
11441 nameXMMReg(gregOfRexRM(pfx,modrm)));
11442 delta += 2+1;
11443 } else {
sewardj2e28ac42008-12-04 00:05:12 +000011444 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj1001dc42005-02-21 08:25:55 +000011445 putXMMReg( gregOfRexRM(pfx,modrm), mkV128(0) );
11446 putXMMRegLane64( gregOfRexRM(pfx,modrm), 0,
11447 loadLE(Ity_I64, mkexpr(addr)) );
11448 DIP("movsd %s,%s\n", dis_buf,
11449 nameXMMReg(gregOfRexRM(pfx,modrm)));
11450 delta += 2+alen;
11451 }
11452 goto decode_success;
11453 }
11454
11455 /* F2 0F 11 = MOVSD -- move 64 bits from G (lo half xmm) to E (mem
11456 or lo half xmm). */
sewardjb4bf5882007-11-06 20:39:17 +000011457 if (haveF2no66noF3(pfx)
11458 && (sz == 4 || /* ignore redundant REX.W */ sz == 8)
sewardj8d965312005-02-25 02:48:47 +000011459 && insn[0] == 0x0F && insn[1] == 0x11) {
sewardj1001dc42005-02-21 08:25:55 +000011460 modrm = getUChar(delta+2);
11461 if (epartIsReg(modrm)) {
sewardje5e837c2008-11-04 11:31:44 +000011462 putXMMRegLane64( eregOfRexRM(pfx,modrm), 0,
11463 getXMMRegLane64( gregOfRexRM(pfx,modrm), 0 ));
11464 DIP("movsd %s,%s\n", nameXMMReg(gregOfRexRM(pfx,modrm)),
11465 nameXMMReg(eregOfRexRM(pfx,modrm)));
11466 delta += 2+1;
sewardj1001dc42005-02-21 08:25:55 +000011467 } else {
sewardj2e28ac42008-12-04 00:05:12 +000011468 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj1001dc42005-02-21 08:25:55 +000011469 storeLE( mkexpr(addr),
11470 getXMMRegLane64(gregOfRexRM(pfx,modrm), 0) );
11471 DIP("movsd %s,%s\n", nameXMMReg(gregOfRexRM(pfx,modrm)),
11472 dis_buf);
11473 delta += 2+alen;
sewardj1001dc42005-02-21 08:25:55 +000011474 }
sewardje5e837c2008-11-04 11:31:44 +000011475 goto decode_success;
sewardj1001dc42005-02-21 08:25:55 +000011476 }
11477
sewardj4c328cf2005-05-05 12:05:54 +000011478 /* 66 0F 59 = MULPD -- mul 64Fx2 from R/M to R */
sewardjb4bf5882007-11-06 20:39:17 +000011479 if (have66noF2noF3(pfx)
11480 && (sz == 2 || /* ignore redundant REX.W */ sz == 8)
sewardj4c328cf2005-05-05 12:05:54 +000011481 && insn[0] == 0x0F && insn[1] == 0x59) {
sewardj2e28ac42008-12-04 00:05:12 +000011482 delta = dis_SSE_E_to_G_all( vbi, pfx, delta+2, "mulpd", Iop_Mul64Fx2 );
sewardj4c328cf2005-05-05 12:05:54 +000011483 goto decode_success;
11484 }
sewardj1001dc42005-02-21 08:25:55 +000011485
11486 /* F2 0F 59 = MULSD -- mul 64F0x2 from R/M to R */
sewardjb4bf5882007-11-06 20:39:17 +000011487 if (haveF2no66noF3(pfx)
11488 && (sz == 4 || /* ignore redundant REX.W */ sz == 8)
sewardj8d965312005-02-25 02:48:47 +000011489 && insn[0] == 0x0F && insn[1] == 0x59) {
sewardj2e28ac42008-12-04 00:05:12 +000011490 delta = dis_SSE_E_to_G_lo64( vbi, pfx, delta+2, "mulsd", Iop_Mul64F0x2 );
sewardj1001dc42005-02-21 08:25:55 +000011491 goto decode_success;
11492 }
11493
sewardj8d965312005-02-25 02:48:47 +000011494 /* 66 0F 56 = ORPD -- G = G and E */
11495 if (have66noF2noF3(pfx) && sz == 2
11496 && insn[0] == 0x0F && insn[1] == 0x56) {
sewardj2e28ac42008-12-04 00:05:12 +000011497 delta = dis_SSE_E_to_G_all( vbi, pfx, delta+2, "orpd", Iop_OrV128 );
sewardj8d965312005-02-25 02:48:47 +000011498 goto decode_success;
11499 }
11500
sewardj09717342005-05-05 21:34:02 +000011501 /* 66 0F C6 /r ib = SHUFPD -- shuffle packed F64s */
11502 if (have66noF2noF3(pfx) && sz == 2
11503 && insn[0] == 0x0F && insn[1] == 0xC6) {
11504 Int select;
11505 IRTemp sV = newTemp(Ity_V128);
11506 IRTemp dV = newTemp(Ity_V128);
11507 IRTemp s1 = newTemp(Ity_I64);
11508 IRTemp s0 = newTemp(Ity_I64);
11509 IRTemp d1 = newTemp(Ity_I64);
11510 IRTemp d0 = newTemp(Ity_I64);
11511
11512 modrm = insn[2];
11513 assign( dV, getXMMReg(gregOfRexRM(pfx,modrm)) );
11514
11515 if (epartIsReg(modrm)) {
11516 assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
11517 select = (Int)insn[3];
11518 delta += 2+2;
11519 DIP("shufpd $%d,%s,%s\n", select,
11520 nameXMMReg(eregOfRexRM(pfx,modrm)),
11521 nameXMMReg(gregOfRexRM(pfx,modrm)));
11522 } else {
sewardj2e28ac42008-12-04 00:05:12 +000011523 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 1 );
sewardj09717342005-05-05 21:34:02 +000011524 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
11525 select = (Int)insn[2+alen];
11526 delta += 3+alen;
11527 DIP("shufpd $%d,%s,%s\n", select,
11528 dis_buf,
11529 nameXMMReg(gregOfRexRM(pfx,modrm)));
11530 }
11531
11532 assign( d1, unop(Iop_V128HIto64, mkexpr(dV)) );
11533 assign( d0, unop(Iop_V128to64, mkexpr(dV)) );
11534 assign( s1, unop(Iop_V128HIto64, mkexpr(sV)) );
11535 assign( s0, unop(Iop_V128to64, mkexpr(sV)) );
11536
11537# define SELD(n) mkexpr((n)==0 ? d0 : d1)
11538# define SELS(n) mkexpr((n)==0 ? s0 : s1)
11539
11540 putXMMReg(
11541 gregOfRexRM(pfx,modrm),
11542 binop(Iop_64HLtoV128, SELS((select>>1)&1), SELD((select>>0)&1) )
11543 );
11544
11545# undef SELD
11546# undef SELS
11547
11548 goto decode_success;
11549 }
11550
sewardj97628592005-05-10 22:42:54 +000011551 /* 66 0F 51 = SQRTPD -- approx sqrt 64Fx2 from R/M to R */
11552 if (have66noF2noF3(pfx) && sz == 2
11553 && insn[0] == 0x0F && insn[1] == 0x51) {
sewardj2e28ac42008-12-04 00:05:12 +000011554 delta = dis_SSE_E_to_G_unary_all( vbi, pfx, delta+2,
sewardj97628592005-05-10 22:42:54 +000011555 "sqrtpd", Iop_Sqrt64Fx2 );
11556 goto decode_success;
11557 }
sewardj1001dc42005-02-21 08:25:55 +000011558
11559 /* F2 0F 51 = SQRTSD -- approx sqrt 64F0x2 from R/M to R */
11560 if (haveF2no66noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x51) {
11561 vassert(sz == 4);
sewardj2e28ac42008-12-04 00:05:12 +000011562 delta = dis_SSE_E_to_G_unary_lo64( vbi, pfx, delta+2,
sewardj1001dc42005-02-21 08:25:55 +000011563 "sqrtsd", Iop_Sqrt64F0x2 );
11564 goto decode_success;
11565 }
11566
sewardj4c328cf2005-05-05 12:05:54 +000011567 /* 66 0F 5C = SUBPD -- sub 64Fx2 from R/M to R */
11568 if (have66noF2noF3(pfx) && sz == 2
11569 && insn[0] == 0x0F && insn[1] == 0x5C) {
sewardj2e28ac42008-12-04 00:05:12 +000011570 delta = dis_SSE_E_to_G_all( vbi, pfx, delta+2, "subpd", Iop_Sub64Fx2 );
sewardj4c328cf2005-05-05 12:05:54 +000011571 goto decode_success;
11572 }
sewardj1001dc42005-02-21 08:25:55 +000011573
11574 /* F2 0F 5C = SUBSD -- sub 64F0x2 from R/M to R */
sewardjb4bf5882007-11-06 20:39:17 +000011575 if (haveF2no66noF3(pfx)
11576 && (sz == 4 || /* ignore redundant REX.W */ sz == 8)
11577 && insn[0] == 0x0F && insn[1] == 0x5C) {
sewardj2e28ac42008-12-04 00:05:12 +000011578 delta = dis_SSE_E_to_G_lo64( vbi, pfx, delta+2, "subsd", Iop_Sub64F0x2 );
sewardj1001dc42005-02-21 08:25:55 +000011579 goto decode_success;
11580 }
11581
sewardj1a01e652005-02-23 11:39:21 +000011582 /* 66 0F 15 = UNPCKHPD -- unpack and interleave high part F64s */
11583 /* 66 0F 14 = UNPCKLPD -- unpack and interleave low part F64s */
11584 /* These just appear to be special cases of SHUFPS */
11585 if (have66noF2noF3(pfx)
11586 && sz == 2 /* could be 8 if rex also present */
11587 && insn[0] == 0x0F && (insn[1] == 0x15 || insn[1] == 0x14)) {
11588 IRTemp s1 = newTemp(Ity_I64);
11589 IRTemp s0 = newTemp(Ity_I64);
11590 IRTemp d1 = newTemp(Ity_I64);
11591 IRTemp d0 = newTemp(Ity_I64);
11592 IRTemp sV = newTemp(Ity_V128);
11593 IRTemp dV = newTemp(Ity_V128);
sewardj1027dc22005-02-26 01:55:02 +000011594 Bool hi = toBool(insn[1] == 0x15);
sewardj1a01e652005-02-23 11:39:21 +000011595
11596 modrm = insn[2];
11597 assign( dV, getXMMReg(gregOfRexRM(pfx,modrm)) );
11598
11599 if (epartIsReg(modrm)) {
11600 assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
11601 delta += 2+1;
11602 DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
11603 nameXMMReg(eregOfRexRM(pfx,modrm)),
11604 nameXMMReg(gregOfRexRM(pfx,modrm)));
11605 } else {
sewardj2e28ac42008-12-04 00:05:12 +000011606 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj1a01e652005-02-23 11:39:21 +000011607 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
11608 delta += 2+alen;
11609 DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
11610 dis_buf,
11611 nameXMMReg(gregOfRexRM(pfx,modrm)));
11612 }
11613
11614 assign( d1, unop(Iop_V128HIto64, mkexpr(dV)) );
11615 assign( d0, unop(Iop_V128to64, mkexpr(dV)) );
11616 assign( s1, unop(Iop_V128HIto64, mkexpr(sV)) );
11617 assign( s0, unop(Iop_V128to64, mkexpr(sV)) );
11618
11619 if (hi) {
11620 putXMMReg( gregOfRexRM(pfx,modrm),
11621 binop(Iop_64HLtoV128, mkexpr(s1), mkexpr(d1)) );
11622 } else {
11623 putXMMReg( gregOfRexRM(pfx,modrm),
11624 binop(Iop_64HLtoV128, mkexpr(s0), mkexpr(d0)) );
11625 }
11626
11627 goto decode_success;
11628 }
sewardj9da16972005-02-21 13:58:26 +000011629
11630 /* 66 0F 57 = XORPD -- G = G xor E */
sewardj97628592005-05-10 22:42:54 +000011631 if (have66noF2noF3(pfx) && sz == 2
11632 && insn[0] == 0x0F && insn[1] == 0x57) {
sewardj2e28ac42008-12-04 00:05:12 +000011633 delta = dis_SSE_E_to_G_all( vbi, pfx, delta+2, "xorpd", Iop_XorV128 );
sewardj9da16972005-02-21 13:58:26 +000011634 goto decode_success;
11635 }
11636
sewardj97628592005-05-10 22:42:54 +000011637 /* 66 0F 6B = PACKSSDW */
11638 if (have66noF2noF3(pfx) && sz == 2
11639 && insn[0] == 0x0F && insn[1] == 0x6B) {
sewardj2e28ac42008-12-04 00:05:12 +000011640 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardj97628592005-05-10 22:42:54 +000011641 "packssdw", Iop_QNarrow32Sx4, True );
11642 goto decode_success;
11643 }
11644
11645 /* 66 0F 63 = PACKSSWB */
11646 if (have66noF2noF3(pfx) && sz == 2
11647 && insn[0] == 0x0F && insn[1] == 0x63) {
sewardj2e28ac42008-12-04 00:05:12 +000011648 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardj97628592005-05-10 22:42:54 +000011649 "packsswb", Iop_QNarrow16Sx8, True );
11650 goto decode_success;
11651 }
11652
11653 /* 66 0F 67 = PACKUSWB */
11654 if (have66noF2noF3(pfx) && sz == 2
11655 && insn[0] == 0x0F && insn[1] == 0x67) {
sewardj2e28ac42008-12-04 00:05:12 +000011656 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardj97628592005-05-10 22:42:54 +000011657 "packuswb", Iop_QNarrow16Ux8, True );
11658 goto decode_success;
11659 }
11660
11661 /* 66 0F FC = PADDB */
11662 if (have66noF2noF3(pfx) && sz == 2
11663 && insn[0] == 0x0F && insn[1] == 0xFC) {
sewardj2e28ac42008-12-04 00:05:12 +000011664 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardj97628592005-05-10 22:42:54 +000011665 "paddb", Iop_Add8x16, False );
11666 goto decode_success;
11667 }
11668
11669 /* 66 0F FE = PADDD */
11670 if (have66noF2noF3(pfx) && sz == 2
11671 && insn[0] == 0x0F && insn[1] == 0xFE) {
sewardj2e28ac42008-12-04 00:05:12 +000011672 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardj97628592005-05-10 22:42:54 +000011673 "paddd", Iop_Add32x4, False );
11674 goto decode_success;
11675 }
sewardj8711f662005-05-09 17:52:56 +000011676
11677 /* ***--- this is an MMX class insn introduced in SSE2 ---*** */
11678 /* 0F D4 = PADDQ -- add 64x1 */
11679 if (haveNo66noF2noF3(pfx) && sz == 4
11680 && insn[0] == 0x0F && insn[1] == 0xD4) {
11681 do_MMX_preamble();
11682 delta = dis_MMXop_regmem_to_reg (
sewardj2e28ac42008-12-04 00:05:12 +000011683 vbi, pfx, delta+2, insn[1], "paddq", False );
sewardj8711f662005-05-09 17:52:56 +000011684 goto decode_success;
11685 }
sewardj09717342005-05-05 21:34:02 +000011686
11687 /* 66 0F D4 = PADDQ */
11688 if (have66noF2noF3(pfx) && sz == 2
11689 && insn[0] == 0x0F && insn[1] == 0xD4) {
sewardj2e28ac42008-12-04 00:05:12 +000011690 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardj09717342005-05-05 21:34:02 +000011691 "paddq", Iop_Add64x2, False );
11692 goto decode_success;
11693 }
11694
sewardj5992bd02005-05-11 02:13:42 +000011695 /* 66 0F FD = PADDW */
11696 if (have66noF2noF3(pfx) && sz == 2
11697 && insn[0] == 0x0F && insn[1] == 0xFD) {
sewardj2e28ac42008-12-04 00:05:12 +000011698 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardj5992bd02005-05-11 02:13:42 +000011699 "paddw", Iop_Add16x8, False );
11700 goto decode_success;
11701 }
11702
11703 /* 66 0F EC = PADDSB */
11704 if (have66noF2noF3(pfx) && sz == 2
11705 && insn[0] == 0x0F && insn[1] == 0xEC) {
sewardj2e28ac42008-12-04 00:05:12 +000011706 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardj5992bd02005-05-11 02:13:42 +000011707 "paddsb", Iop_QAdd8Sx16, False );
11708 goto decode_success;
11709 }
11710
11711 /* 66 0F ED = PADDSW */
11712 if (have66noF2noF3(pfx) && sz == 2
11713 && insn[0] == 0x0F && insn[1] == 0xED) {
sewardj2e28ac42008-12-04 00:05:12 +000011714 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardj5992bd02005-05-11 02:13:42 +000011715 "paddsw", Iop_QAdd16Sx8, False );
11716 goto decode_success;
11717 }
11718
11719 /* 66 0F DC = PADDUSB */
11720 if (have66noF2noF3(pfx) && sz == 2
11721 && insn[0] == 0x0F && insn[1] == 0xDC) {
sewardj2e28ac42008-12-04 00:05:12 +000011722 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardj5992bd02005-05-11 02:13:42 +000011723 "paddusb", Iop_QAdd8Ux16, False );
11724 goto decode_success;
11725 }
11726
11727 /* 66 0F DD = PADDUSW */
11728 if (have66noF2noF3(pfx) && sz == 2
11729 && insn[0] == 0x0F && insn[1] == 0xDD) {
sewardj2e28ac42008-12-04 00:05:12 +000011730 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardj5992bd02005-05-11 02:13:42 +000011731 "paddusw", Iop_QAdd16Ux8, False );
11732 goto decode_success;
11733 }
sewardj09717342005-05-05 21:34:02 +000011734
11735 /* 66 0F DB = PAND */
11736 if (have66noF2noF3(pfx) && sz == 2
11737 && insn[0] == 0x0F && insn[1] == 0xDB) {
sewardj2e28ac42008-12-04 00:05:12 +000011738 delta = dis_SSE_E_to_G_all( vbi, pfx, delta+2, "pand", Iop_AndV128 );
sewardj09717342005-05-05 21:34:02 +000011739 goto decode_success;
11740 }
11741
sewardj5992bd02005-05-11 02:13:42 +000011742 /* 66 0F DF = PANDN */
11743 if (have66noF2noF3(pfx) && sz == 2
11744 && insn[0] == 0x0F && insn[1] == 0xDF) {
sewardj2e28ac42008-12-04 00:05:12 +000011745 delta = dis_SSE_E_to_G_all_invG( vbi, pfx, delta+2, "pandn", Iop_AndV128 );
sewardj5992bd02005-05-11 02:13:42 +000011746 goto decode_success;
11747 }
11748
11749 /* 66 0F E0 = PAVGB */
11750 if (have66noF2noF3(pfx) && sz == 2
11751 && insn[0] == 0x0F && insn[1] == 0xE0) {
sewardj2e28ac42008-12-04 00:05:12 +000011752 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardj5992bd02005-05-11 02:13:42 +000011753 "pavgb", Iop_Avg8Ux16, False );
11754 goto decode_success;
11755 }
11756
11757 /* 66 0F E3 = PAVGW */
11758 if (have66noF2noF3(pfx) && sz == 2
11759 && insn[0] == 0x0F && insn[1] == 0xE3) {
sewardj2e28ac42008-12-04 00:05:12 +000011760 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardj5992bd02005-05-11 02:13:42 +000011761 "pavgw", Iop_Avg16Ux8, False );
11762 goto decode_success;
11763 }
11764
11765 /* 66 0F 74 = PCMPEQB */
11766 if (have66noF2noF3(pfx) && sz == 2
11767 && insn[0] == 0x0F && insn[1] == 0x74) {
sewardj2e28ac42008-12-04 00:05:12 +000011768 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardj5992bd02005-05-11 02:13:42 +000011769 "pcmpeqb", Iop_CmpEQ8x16, False );
11770 goto decode_success;
11771 }
11772
11773 /* 66 0F 76 = PCMPEQD */
11774 if (have66noF2noF3(pfx) && sz == 2
11775 && insn[0] == 0x0F && insn[1] == 0x76) {
sewardj2e28ac42008-12-04 00:05:12 +000011776 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardj5992bd02005-05-11 02:13:42 +000011777 "pcmpeqd", Iop_CmpEQ32x4, False );
11778 goto decode_success;
11779 }
11780
11781 /* 66 0F 75 = PCMPEQW */
11782 if (have66noF2noF3(pfx) && sz == 2
11783 && insn[0] == 0x0F && insn[1] == 0x75) {
sewardj2e28ac42008-12-04 00:05:12 +000011784 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardj5992bd02005-05-11 02:13:42 +000011785 "pcmpeqw", Iop_CmpEQ16x8, False );
11786 goto decode_success;
11787 }
11788
11789 /* 66 0F 64 = PCMPGTB */
11790 if (have66noF2noF3(pfx) && sz == 2
11791 && insn[0] == 0x0F && insn[1] == 0x64) {
sewardj2e28ac42008-12-04 00:05:12 +000011792 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardj5992bd02005-05-11 02:13:42 +000011793 "pcmpgtb", Iop_CmpGT8Sx16, False );
11794 goto decode_success;
11795 }
11796
11797 /* 66 0F 66 = PCMPGTD */
11798 if (have66noF2noF3(pfx) && sz == 2
11799 && insn[0] == 0x0F && insn[1] == 0x66) {
sewardj2e28ac42008-12-04 00:05:12 +000011800 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardj5992bd02005-05-11 02:13:42 +000011801 "pcmpgtd", Iop_CmpGT32Sx4, False );
11802 goto decode_success;
11803 }
11804
11805 /* 66 0F 65 = PCMPGTW */
11806 if (have66noF2noF3(pfx) && sz == 2
11807 && insn[0] == 0x0F && insn[1] == 0x65) {
sewardj2e28ac42008-12-04 00:05:12 +000011808 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardj5992bd02005-05-11 02:13:42 +000011809 "pcmpgtw", Iop_CmpGT16Sx8, False );
11810 goto decode_success;
11811 }
sewardj97628592005-05-10 22:42:54 +000011812
11813 /* 66 0F C5 = PEXTRW -- extract 16-bit field from xmm(E) and put
11814 zero-extend of it in ireg(G). */
sewardj7bdd1bc2008-12-13 16:49:46 +000011815 if (have66noF2noF3(pfx)
11816 && (sz == 2 || /* ignore redundant REX.W */ sz == 8)
sewardj97628592005-05-10 22:42:54 +000011817 && insn[0] == 0x0F && insn[1] == 0xC5) {
11818 modrm = insn[2];
11819 if (epartIsReg(modrm)) {
11820 t5 = newTemp(Ity_V128);
11821 t4 = newTemp(Ity_I16);
11822 assign(t5, getXMMReg(eregOfRexRM(pfx,modrm)));
11823 breakup128to32s( t5, &t3, &t2, &t1, &t0 );
11824 switch (insn[3] & 7) {
11825 case 0: assign(t4, unop(Iop_32to16, mkexpr(t0))); break;
11826 case 1: assign(t4, unop(Iop_32HIto16, mkexpr(t0))); break;
11827 case 2: assign(t4, unop(Iop_32to16, mkexpr(t1))); break;
11828 case 3: assign(t4, unop(Iop_32HIto16, mkexpr(t1))); break;
11829 case 4: assign(t4, unop(Iop_32to16, mkexpr(t2))); break;
11830 case 5: assign(t4, unop(Iop_32HIto16, mkexpr(t2))); break;
11831 case 6: assign(t4, unop(Iop_32to16, mkexpr(t3))); break;
11832 case 7: assign(t4, unop(Iop_32HIto16, mkexpr(t3))); break;
11833 default: vassert(0);
11834 }
11835 putIReg32(gregOfRexRM(pfx,modrm), unop(Iop_16Uto32, mkexpr(t4)));
11836 DIP("pextrw $%d,%s,%s\n",
11837 (Int)insn[3], nameXMMReg(eregOfRexRM(pfx,modrm)),
11838 nameIReg32(gregOfRexRM(pfx,modrm)));
11839 delta += 4;
11840 goto decode_success;
11841 }
11842 /* else fall through */
11843 /* note, if memory case is ever filled in, there is 1 byte after
11844 amode */
11845 }
11846
11847 /* 66 0F C4 = PINSRW -- get 16 bits from E(mem or low half ireg) and
11848 put it into the specified lane of xmm(G). */
sewardj7bdd1bc2008-12-13 16:49:46 +000011849 if (have66noF2noF3(pfx)
11850 && (sz == 2 || /* ignore redundant REX.W */ sz == 8)
sewardj97628592005-05-10 22:42:54 +000011851 && insn[0] == 0x0F && insn[1] == 0xC4) {
11852 Int lane;
11853 t4 = newTemp(Ity_I16);
11854 modrm = insn[2];
11855
11856 if (epartIsReg(modrm)) {
11857 assign(t4, getIReg16(eregOfRexRM(pfx,modrm)));
11858 delta += 3+1;
11859 lane = insn[3+1-1];
11860 DIP("pinsrw $%d,%s,%s\n", (Int)lane,
11861 nameIReg16(eregOfRexRM(pfx,modrm)),
11862 nameXMMReg(gregOfRexRM(pfx,modrm)));
11863 } else {
sewardj2e28ac42008-12-04 00:05:12 +000011864 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf,
sewardj97628592005-05-10 22:42:54 +000011865 1/*byte after the amode*/ );
11866 delta += 3+alen;
11867 lane = insn[3+alen-1];
11868 assign(t4, loadLE(Ity_I16, mkexpr(addr)));
11869 DIP("pinsrw $%d,%s,%s\n", (Int)lane,
11870 dis_buf,
11871 nameXMMReg(gregOfRexRM(pfx,modrm)));
11872 }
11873
11874 putXMMRegLane16( gregOfRexRM(pfx,modrm), lane & 7, mkexpr(t4) );
11875 goto decode_success;
11876 }
11877
sewardjdb859032006-04-08 16:15:53 +000011878 /* 66 0F F5 = PMADDWD -- Multiply and add packed integers from
11879 E(xmm or mem) to G(xmm) */
11880 if (have66noF2noF3(pfx) && sz == 2
11881 && insn[0] == 0x0F && insn[1] == 0xF5) {
11882 IRTemp s1V = newTemp(Ity_V128);
11883 IRTemp s2V = newTemp(Ity_V128);
11884 IRTemp dV = newTemp(Ity_V128);
11885 IRTemp s1Hi = newTemp(Ity_I64);
11886 IRTemp s1Lo = newTemp(Ity_I64);
11887 IRTemp s2Hi = newTemp(Ity_I64);
11888 IRTemp s2Lo = newTemp(Ity_I64);
11889 IRTemp dHi = newTemp(Ity_I64);
11890 IRTemp dLo = newTemp(Ity_I64);
11891 modrm = insn[2];
11892 if (epartIsReg(modrm)) {
11893 assign( s1V, getXMMReg(eregOfRexRM(pfx,modrm)) );
11894 delta += 2+1;
11895 DIP("pmaddwd %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
11896 nameXMMReg(gregOfRexRM(pfx,modrm)));
11897 } else {
sewardj2e28ac42008-12-04 00:05:12 +000011898 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardjdb859032006-04-08 16:15:53 +000011899 assign( s1V, loadLE(Ity_V128, mkexpr(addr)) );
11900 delta += 2+alen;
11901 DIP("pmaddwd %s,%s\n", dis_buf,
11902 nameXMMReg(gregOfRexRM(pfx,modrm)));
11903 }
11904 assign( s2V, getXMMReg(gregOfRexRM(pfx,modrm)) );
11905 assign( s1Hi, unop(Iop_V128HIto64, mkexpr(s1V)) );
11906 assign( s1Lo, unop(Iop_V128to64, mkexpr(s1V)) );
11907 assign( s2Hi, unop(Iop_V128HIto64, mkexpr(s2V)) );
11908 assign( s2Lo, unop(Iop_V128to64, mkexpr(s2V)) );
11909 assign( dHi, mkIRExprCCall(
11910 Ity_I64, 0/*regparms*/,
11911 "amd64g_calculate_mmx_pmaddwd",
11912 &amd64g_calculate_mmx_pmaddwd,
11913 mkIRExprVec_2( mkexpr(s1Hi), mkexpr(s2Hi))
11914 ));
11915 assign( dLo, mkIRExprCCall(
11916 Ity_I64, 0/*regparms*/,
11917 "amd64g_calculate_mmx_pmaddwd",
11918 &amd64g_calculate_mmx_pmaddwd,
11919 mkIRExprVec_2( mkexpr(s1Lo), mkexpr(s2Lo))
11920 ));
11921 assign( dV, binop(Iop_64HLtoV128, mkexpr(dHi), mkexpr(dLo))) ;
11922 putXMMReg(gregOfRexRM(pfx,modrm), mkexpr(dV));
11923 goto decode_success;
11924 }
11925
sewardjadffcef2005-05-11 00:03:06 +000011926 /* 66 0F EE = PMAXSW -- 16x8 signed max */
11927 if (have66noF2noF3(pfx) && sz == 2
11928 && insn[0] == 0x0F && insn[1] == 0xEE) {
sewardj2e28ac42008-12-04 00:05:12 +000011929 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardjadffcef2005-05-11 00:03:06 +000011930 "pmaxsw", Iop_Max16Sx8, False );
11931 goto decode_success;
11932 }
11933
11934 /* 66 0F DE = PMAXUB -- 8x16 unsigned max */
11935 if (have66noF2noF3(pfx) && sz == 2
11936 && insn[0] == 0x0F && insn[1] == 0xDE) {
sewardj2e28ac42008-12-04 00:05:12 +000011937 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardjadffcef2005-05-11 00:03:06 +000011938 "pmaxub", Iop_Max8Ux16, False );
11939 goto decode_success;
11940 }
11941
11942 /* 66 0F EA = PMINSW -- 16x8 signed min */
11943 if (have66noF2noF3(pfx) && sz == 2
11944 && insn[0] == 0x0F && insn[1] == 0xEA) {
sewardj2e28ac42008-12-04 00:05:12 +000011945 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardjadffcef2005-05-11 00:03:06 +000011946 "pminsw", Iop_Min16Sx8, False );
11947 goto decode_success;
11948 }
11949
11950 /* 66 0F DA = PMINUB -- 8x16 unsigned min */
11951 if (have66noF2noF3(pfx) && sz == 2
11952 && insn[0] == 0x0F && insn[1] == 0xDA) {
sewardj2e28ac42008-12-04 00:05:12 +000011953 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardjadffcef2005-05-11 00:03:06 +000011954 "pminub", Iop_Min8Ux16, False );
11955 goto decode_success;
11956 }
11957
11958 /* 66 0F D7 = PMOVMSKB -- extract sign bits from each of 16 lanes in
11959 xmm(E), turn them into a byte, and put zero-extend of it in
11960 ireg(G). Doing this directly is just too cumbersome; give up
11961 therefore and call a helper. */
11962 /* UInt x86g_calculate_sse_pmovmskb ( ULong w64hi, ULong w64lo ); */
sewardj7bdd1bc2008-12-13 16:49:46 +000011963 if (have66noF2noF3(pfx)
11964 && (sz == 2 || /* ignore redundant REX.W */ sz == 8)
sewardjadffcef2005-05-11 00:03:06 +000011965 && insn[0] == 0x0F && insn[1] == 0xD7) {
11966 modrm = insn[2];
11967 if (epartIsReg(modrm)) {
11968 t0 = newTemp(Ity_I64);
11969 t1 = newTemp(Ity_I64);
11970 assign(t0, getXMMRegLane64(eregOfRexRM(pfx,modrm), 0));
11971 assign(t1, getXMMRegLane64(eregOfRexRM(pfx,modrm), 1));
11972 t5 = newTemp(Ity_I64);
11973 assign(t5, mkIRExprCCall(
11974 Ity_I64, 0/*regparms*/,
11975 "amd64g_calculate_sse_pmovmskb",
11976 &amd64g_calculate_sse_pmovmskb,
11977 mkIRExprVec_2( mkexpr(t1), mkexpr(t0) )));
11978 putIReg32(gregOfRexRM(pfx,modrm), unop(Iop_64to32,mkexpr(t5)));
11979 DIP("pmovmskb %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
11980 nameIReg32(gregOfRexRM(pfx,modrm)));
11981 delta += 3;
11982 goto decode_success;
11983 }
11984 /* else fall through */
11985 }
11986
11987 /* 66 0F E4 = PMULHUW -- 16x8 hi-half of unsigned widening multiply */
11988 if (have66noF2noF3(pfx) && sz == 2
11989 && insn[0] == 0x0F && insn[1] == 0xE4) {
sewardj2e28ac42008-12-04 00:05:12 +000011990 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardjadffcef2005-05-11 00:03:06 +000011991 "pmulhuw", Iop_MulHi16Ux8, False );
11992 goto decode_success;
11993 }
11994
11995 /* 66 0F E5 = PMULHW -- 16x8 hi-half of signed widening multiply */
11996 if (have66noF2noF3(pfx) && sz == 2
11997 && insn[0] == 0x0F && insn[1] == 0xE5) {
sewardj2e28ac42008-12-04 00:05:12 +000011998 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardjadffcef2005-05-11 00:03:06 +000011999 "pmulhw", Iop_MulHi16Sx8, False );
12000 goto decode_success;
12001 }
12002
12003 /* 66 0F D5 = PMULHL -- 16x8 multiply */
12004 if (have66noF2noF3(pfx) && sz == 2
12005 && insn[0] == 0x0F && insn[1] == 0xD5) {
sewardj2e28ac42008-12-04 00:05:12 +000012006 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardjadffcef2005-05-11 00:03:06 +000012007 "pmullw", Iop_Mul16x8, False );
12008 goto decode_success;
12009 }
12010
12011 /* ***--- this is an MMX class insn introduced in SSE2 ---*** */
12012 /* 0F F4 = PMULUDQ -- unsigned widening multiply of 32-lanes 0 x
12013 0 to form 64-bit result */
12014 if (haveNo66noF2noF3(pfx) && sz == 4
12015 && insn[0] == 0x0F && insn[1] == 0xF4) {
12016 IRTemp sV = newTemp(Ity_I64);
12017 IRTemp dV = newTemp(Ity_I64);
12018 t1 = newTemp(Ity_I32);
12019 t0 = newTemp(Ity_I32);
12020 modrm = insn[2];
12021
12022 do_MMX_preamble();
12023 assign( dV, getMMXReg(gregLO3ofRM(modrm)) );
12024
12025 if (epartIsReg(modrm)) {
12026 assign( sV, getMMXReg(eregLO3ofRM(modrm)) );
12027 delta += 2+1;
12028 DIP("pmuludq %s,%s\n", nameMMXReg(eregLO3ofRM(modrm)),
12029 nameMMXReg(gregLO3ofRM(modrm)));
12030 } else {
sewardj2e28ac42008-12-04 00:05:12 +000012031 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardjadffcef2005-05-11 00:03:06 +000012032 assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
12033 delta += 2+alen;
12034 DIP("pmuludq %s,%s\n", dis_buf,
12035 nameMMXReg(gregLO3ofRM(modrm)));
12036 }
12037
12038 assign( t0, unop(Iop_64to32, mkexpr(dV)) );
12039 assign( t1, unop(Iop_64to32, mkexpr(sV)) );
12040 putMMXReg( gregLO3ofRM(modrm),
12041 binop( Iop_MullU32, mkexpr(t0), mkexpr(t1) ) );
12042 goto decode_success;
12043 }
12044
12045 /* 66 0F F4 = PMULUDQ -- unsigned widening multiply of 32-lanes 0 x
12046 0 to form lower 64-bit half and lanes 2 x 2 to form upper 64-bit
12047 half */
12048 /* This is a really poor translation -- could be improved if
12049 performance critical */
12050 if (have66noF2noF3(pfx) && sz == 2
12051 && insn[0] == 0x0F && insn[1] == 0xF4) {
12052 IRTemp sV, dV;
12053 IRTemp s3, s2, s1, s0, d3, d2, d1, d0;
12054 sV = newTemp(Ity_V128);
12055 dV = newTemp(Ity_V128);
12056 s3 = s2 = s1 = s0 = d3 = d2 = d1 = d0 = IRTemp_INVALID;
12057 t1 = newTemp(Ity_I64);
12058 t0 = newTemp(Ity_I64);
12059 modrm = insn[2];
12060 assign( dV, getXMMReg(gregOfRexRM(pfx,modrm)) );
12061
12062 if (epartIsReg(modrm)) {
12063 assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
12064 delta += 2+1;
12065 DIP("pmuludq %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
12066 nameXMMReg(gregOfRexRM(pfx,modrm)));
12067 } else {
sewardj2e28ac42008-12-04 00:05:12 +000012068 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardjadffcef2005-05-11 00:03:06 +000012069 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
12070 delta += 2+alen;
12071 DIP("pmuludq %s,%s\n", dis_buf,
12072 nameXMMReg(gregOfRexRM(pfx,modrm)));
12073 }
12074
12075 breakup128to32s( dV, &d3, &d2, &d1, &d0 );
12076 breakup128to32s( sV, &s3, &s2, &s1, &s0 );
12077
12078 assign( t0, binop( Iop_MullU32, mkexpr(d0), mkexpr(s0)) );
12079 putXMMRegLane64( gregOfRexRM(pfx,modrm), 0, mkexpr(t0) );
12080 assign( t1, binop( Iop_MullU32, mkexpr(d2), mkexpr(s2)) );
12081 putXMMRegLane64( gregOfRexRM(pfx,modrm), 1, mkexpr(t1) );
12082 goto decode_success;
12083 }
sewardj09717342005-05-05 21:34:02 +000012084
12085 /* 66 0F EB = POR */
12086 if (have66noF2noF3(pfx) && sz == 2
12087 && insn[0] == 0x0F && insn[1] == 0xEB) {
sewardj2e28ac42008-12-04 00:05:12 +000012088 delta = dis_SSE_E_to_G_all( vbi, pfx, delta+2, "por", Iop_OrV128 );
sewardj09717342005-05-05 21:34:02 +000012089 goto decode_success;
12090 }
12091
sewardj59e96c12006-07-24 08:51:16 +000012092 /* 66 0F F6 = PSADBW -- 2 x (8x8 -> 48 zeroes ++ u16) Sum Abs Diffs
12093 from E(xmm or mem) to G(xmm) */
12094 if (have66noF2noF3(pfx) && sz == 2
12095 && insn[0] == 0x0F && insn[1] == 0xF6) {
12096 IRTemp s1V = newTemp(Ity_V128);
12097 IRTemp s2V = newTemp(Ity_V128);
12098 IRTemp dV = newTemp(Ity_V128);
12099 IRTemp s1Hi = newTemp(Ity_I64);
12100 IRTemp s1Lo = newTemp(Ity_I64);
12101 IRTemp s2Hi = newTemp(Ity_I64);
12102 IRTemp s2Lo = newTemp(Ity_I64);
12103 IRTemp dHi = newTemp(Ity_I64);
12104 IRTemp dLo = newTemp(Ity_I64);
12105 modrm = insn[2];
12106 if (epartIsReg(modrm)) {
12107 assign( s1V, getXMMReg(eregOfRexRM(pfx,modrm)) );
12108 delta += 2+1;
12109 DIP("psadbw %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
12110 nameXMMReg(gregOfRexRM(pfx,modrm)));
12111 } else {
sewardj2e28ac42008-12-04 00:05:12 +000012112 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj59e96c12006-07-24 08:51:16 +000012113 assign( s1V, loadLE(Ity_V128, mkexpr(addr)) );
12114 delta += 2+alen;
12115 DIP("psadbw %s,%s\n", dis_buf,
12116 nameXMMReg(gregOfRexRM(pfx,modrm)));
12117 }
12118 assign( s2V, getXMMReg(gregOfRexRM(pfx,modrm)) );
12119 assign( s1Hi, unop(Iop_V128HIto64, mkexpr(s1V)) );
12120 assign( s1Lo, unop(Iop_V128to64, mkexpr(s1V)) );
12121 assign( s2Hi, unop(Iop_V128HIto64, mkexpr(s2V)) );
12122 assign( s2Lo, unop(Iop_V128to64, mkexpr(s2V)) );
12123 assign( dHi, mkIRExprCCall(
12124 Ity_I64, 0/*regparms*/,
12125 "amd64g_calculate_mmx_psadbw",
12126 &amd64g_calculate_mmx_psadbw,
12127 mkIRExprVec_2( mkexpr(s1Hi), mkexpr(s2Hi))
12128 ));
12129 assign( dLo, mkIRExprCCall(
12130 Ity_I64, 0/*regparms*/,
12131 "amd64g_calculate_mmx_psadbw",
12132 &amd64g_calculate_mmx_psadbw,
12133 mkIRExprVec_2( mkexpr(s1Lo), mkexpr(s2Lo))
12134 ));
12135 assign( dV, binop(Iop_64HLtoV128, mkexpr(dHi), mkexpr(dLo))) ;
12136 putXMMReg(gregOfRexRM(pfx,modrm), mkexpr(dV));
12137 goto decode_success;
12138 }
12139
sewardjadffcef2005-05-11 00:03:06 +000012140 /* 66 0F 70 = PSHUFD -- rearrange 4x32 from E(xmm or mem) to G(xmm) */
12141 if (have66noF2noF3(pfx) && sz == 2
12142 && insn[0] == 0x0F && insn[1] == 0x70) {
12143 Int order;
12144 IRTemp sV, dV, s3, s2, s1, s0;
12145 s3 = s2 = s1 = s0 = IRTemp_INVALID;
12146 sV = newTemp(Ity_V128);
12147 dV = newTemp(Ity_V128);
12148 modrm = insn[2];
12149 if (epartIsReg(modrm)) {
12150 assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
12151 order = (Int)insn[3];
12152 delta += 3+1;
12153 DIP("pshufd $%d,%s,%s\n", order,
12154 nameXMMReg(eregOfRexRM(pfx,modrm)),
12155 nameXMMReg(gregOfRexRM(pfx,modrm)));
12156 } else {
sewardj2e28ac42008-12-04 00:05:12 +000012157 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf,
sewardjadffcef2005-05-11 00:03:06 +000012158 1/*byte after the amode*/ );
12159 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
12160 order = (Int)insn[2+alen];
12161 delta += 2+alen+1;
12162 DIP("pshufd $%d,%s,%s\n", order,
12163 dis_buf,
12164 nameXMMReg(gregOfRexRM(pfx,modrm)));
12165 }
12166 breakup128to32s( sV, &s3, &s2, &s1, &s0 );
12167
12168# define SEL(n) \
12169 ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
12170 assign(dV,
12171 mk128from32s( SEL((order>>6)&3), SEL((order>>4)&3),
12172 SEL((order>>2)&3), SEL((order>>0)&3) )
12173 );
12174 putXMMReg(gregOfRexRM(pfx,modrm), mkexpr(dV));
12175# undef SEL
12176 goto decode_success;
12177 }
12178
12179 /* F3 0F 70 = PSHUFHW -- rearrange upper half 4x16 from E(xmm or
12180 mem) to G(xmm), and copy lower half */
12181 if (haveF3no66noF2(pfx) && sz == 4
12182 && insn[0] == 0x0F && insn[1] == 0x70) {
12183 Int order;
12184 IRTemp sVhi, dVhi, sV, dV, s3, s2, s1, s0;
12185 s3 = s2 = s1 = s0 = IRTemp_INVALID;
12186 sV = newTemp(Ity_V128);
12187 dV = newTemp(Ity_V128);
12188 sVhi = newTemp(Ity_I64);
12189 dVhi = newTemp(Ity_I64);
12190 modrm = insn[2];
12191 if (epartIsReg(modrm)) {
12192 assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
12193 order = (Int)insn[3];
12194 delta += 3+1;
12195 DIP("pshufhw $%d,%s,%s\n", order,
12196 nameXMMReg(eregOfRexRM(pfx,modrm)),
12197 nameXMMReg(gregOfRexRM(pfx,modrm)));
12198 } else {
sewardj2e28ac42008-12-04 00:05:12 +000012199 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf,
sewardjadffcef2005-05-11 00:03:06 +000012200 1/*byte after the amode*/ );
12201 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
12202 order = (Int)insn[2+alen];
12203 delta += 2+alen+1;
12204 DIP("pshufhw $%d,%s,%s\n", order,
12205 dis_buf,
12206 nameXMMReg(gregOfRexRM(pfx,modrm)));
12207 }
12208 assign( sVhi, unop(Iop_V128HIto64, mkexpr(sV)) );
12209 breakup64to16s( sVhi, &s3, &s2, &s1, &s0 );
12210
12211# define SEL(n) \
12212 ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
12213 assign(dVhi,
12214 mk64from16s( SEL((order>>6)&3), SEL((order>>4)&3),
12215 SEL((order>>2)&3), SEL((order>>0)&3) )
12216 );
12217 assign(dV, binop( Iop_64HLtoV128,
12218 mkexpr(dVhi),
12219 unop(Iop_V128to64, mkexpr(sV))) );
12220 putXMMReg(gregOfRexRM(pfx,modrm), mkexpr(dV));
12221# undef SEL
12222 goto decode_success;
12223 }
12224
12225 /* F2 0F 70 = PSHUFLW -- rearrange lower half 4x16 from E(xmm or
12226 mem) to G(xmm), and copy upper half */
12227 if (haveF2no66noF3(pfx) && sz == 4
12228 && insn[0] == 0x0F && insn[1] == 0x70) {
12229 Int order;
12230 IRTemp sVlo, dVlo, sV, dV, s3, s2, s1, s0;
12231 s3 = s2 = s1 = s0 = IRTemp_INVALID;
12232 sV = newTemp(Ity_V128);
12233 dV = newTemp(Ity_V128);
12234 sVlo = newTemp(Ity_I64);
12235 dVlo = newTemp(Ity_I64);
12236 modrm = insn[2];
12237 if (epartIsReg(modrm)) {
12238 assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
12239 order = (Int)insn[3];
12240 delta += 3+1;
12241 DIP("pshuflw $%d,%s,%s\n", order,
12242 nameXMMReg(eregOfRexRM(pfx,modrm)),
12243 nameXMMReg(gregOfRexRM(pfx,modrm)));
12244 } else {
sewardj2e28ac42008-12-04 00:05:12 +000012245 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf,
sewardjadffcef2005-05-11 00:03:06 +000012246 1/*byte after the amode*/ );
12247 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
12248 order = (Int)insn[2+alen];
12249 delta += 2+alen+1;
12250 DIP("pshuflw $%d,%s,%s\n", order,
12251 dis_buf,
12252 nameXMMReg(gregOfRexRM(pfx,modrm)));
12253 }
12254 assign( sVlo, unop(Iop_V128to64, mkexpr(sV)) );
12255 breakup64to16s( sVlo, &s3, &s2, &s1, &s0 );
12256
12257# define SEL(n) \
12258 ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
12259 assign(dVlo,
12260 mk64from16s( SEL((order>>6)&3), SEL((order>>4)&3),
12261 SEL((order>>2)&3), SEL((order>>0)&3) )
12262 );
12263 assign(dV, binop( Iop_64HLtoV128,
12264 unop(Iop_V128HIto64, mkexpr(sV)),
12265 mkexpr(dVlo) ) );
12266 putXMMReg(gregOfRexRM(pfx,modrm), mkexpr(dV));
12267# undef SEL
12268 goto decode_success;
12269 }
12270
12271 /* 66 0F 72 /6 ib = PSLLD by immediate */
12272 if (have66noF2noF3(pfx) && sz == 2
12273 && insn[0] == 0x0F && insn[1] == 0x72
12274 && epartIsReg(insn[2])
12275 && gregLO3ofRM(insn[2]) == 6) {
12276 delta = dis_SSE_shiftE_imm( pfx, delta+2, "pslld", Iop_ShlN32x4 );
12277 goto decode_success;
12278 }
12279
12280 /* 66 0F F2 = PSLLD by E */
12281 if (have66noF2noF3(pfx) && sz == 2
12282 && insn[0] == 0x0F && insn[1] == 0xF2) {
sewardj2e28ac42008-12-04 00:05:12 +000012283 delta = dis_SSE_shiftG_byE( vbi, pfx, delta+2, "pslld", Iop_ShlN32x4 );
sewardjadffcef2005-05-11 00:03:06 +000012284 goto decode_success;
12285 }
sewardj97628592005-05-10 22:42:54 +000012286
12287 /* 66 0F 73 /7 ib = PSLLDQ by immediate */
12288 /* note, if mem case ever filled in, 1 byte after amode */
12289 if (have66noF2noF3(pfx) && sz == 2
12290 && insn[0] == 0x0F && insn[1] == 0x73
12291 && epartIsReg(insn[2])
12292 && gregLO3ofRM(insn[2]) == 7) {
12293 IRTemp sV, dV, hi64, lo64, hi64r, lo64r;
12294 Int imm = (Int)insn[3];
12295 Int reg = eregOfRexRM(pfx,insn[2]);
12296 DIP("pslldq $%d,%s\n", imm, nameXMMReg(reg));
12297 vassert(imm >= 0 && imm <= 255);
12298 delta += 4;
12299
12300 sV = newTemp(Ity_V128);
12301 dV = newTemp(Ity_V128);
12302 hi64 = newTemp(Ity_I64);
12303 lo64 = newTemp(Ity_I64);
12304 hi64r = newTemp(Ity_I64);
12305 lo64r = newTemp(Ity_I64);
12306
12307 if (imm >= 16) {
12308 putXMMReg(reg, mkV128(0x0000));
12309 goto decode_success;
12310 }
12311
12312 assign( sV, getXMMReg(reg) );
12313 assign( hi64, unop(Iop_V128HIto64, mkexpr(sV)) );
12314 assign( lo64, unop(Iop_V128to64, mkexpr(sV)) );
12315
12316 if (imm == 0) {
12317 assign( lo64r, mkexpr(lo64) );
12318 assign( hi64r, mkexpr(hi64) );
12319 }
12320 else
12321 if (imm == 8) {
12322 assign( lo64r, mkU64(0) );
12323 assign( hi64r, mkexpr(lo64) );
12324 }
12325 else
12326 if (imm > 8) {
12327 assign( lo64r, mkU64(0) );
12328 assign( hi64r, binop( Iop_Shl64,
12329 mkexpr(lo64),
12330 mkU8( 8*(imm-8) ) ));
12331 } else {
12332 assign( lo64r, binop( Iop_Shl64,
12333 mkexpr(lo64),
12334 mkU8(8 * imm) ));
12335 assign( hi64r,
12336 binop( Iop_Or64,
12337 binop(Iop_Shl64, mkexpr(hi64),
12338 mkU8(8 * imm)),
12339 binop(Iop_Shr64, mkexpr(lo64),
12340 mkU8(8 * (8 - imm)) )
12341 )
12342 );
12343 }
12344 assign( dV, binop(Iop_64HLtoV128, mkexpr(hi64r), mkexpr(lo64r)) );
12345 putXMMReg(reg, mkexpr(dV));
12346 goto decode_success;
12347 }
12348
sewardjadffcef2005-05-11 00:03:06 +000012349 /* 66 0F 73 /6 ib = PSLLQ by immediate */
12350 if (have66noF2noF3(pfx) && sz == 2
12351 && insn[0] == 0x0F && insn[1] == 0x73
12352 && epartIsReg(insn[2])
12353 && gregLO3ofRM(insn[2]) == 6) {
12354 delta = dis_SSE_shiftE_imm( pfx, delta+2, "psllq", Iop_ShlN64x2 );
12355 goto decode_success;
12356 }
12357
12358 /* 66 0F F3 = PSLLQ by E */
12359 if (have66noF2noF3(pfx) && sz == 2
12360 && insn[0] == 0x0F && insn[1] == 0xF3) {
sewardj2e28ac42008-12-04 00:05:12 +000012361 delta = dis_SSE_shiftG_byE( vbi, pfx, delta+2, "psllq", Iop_ShlN64x2 );
sewardjadffcef2005-05-11 00:03:06 +000012362 goto decode_success;
12363 }
12364
12365 /* 66 0F 71 /6 ib = PSLLW by immediate */
12366 if (have66noF2noF3(pfx) && sz == 2
12367 && insn[0] == 0x0F && insn[1] == 0x71
12368 && epartIsReg(insn[2])
12369 && gregLO3ofRM(insn[2]) == 6) {
12370 delta = dis_SSE_shiftE_imm( pfx, delta+2, "psllw", Iop_ShlN16x8 );
12371 goto decode_success;
12372 }
12373
12374 /* 66 0F F1 = PSLLW by E */
12375 if (have66noF2noF3(pfx) && sz == 2
12376 && insn[0] == 0x0F && insn[1] == 0xF1) {
sewardj2e28ac42008-12-04 00:05:12 +000012377 delta = dis_SSE_shiftG_byE( vbi, pfx, delta+2, "psllw", Iop_ShlN16x8 );
sewardjadffcef2005-05-11 00:03:06 +000012378 goto decode_success;
12379 }
12380
12381 /* 66 0F 72 /4 ib = PSRAD by immediate */
12382 if (have66noF2noF3(pfx) && sz == 2
12383 && insn[0] == 0x0F && insn[1] == 0x72
12384 && epartIsReg(insn[2])
12385 && gregLO3ofRM(insn[2]) == 4) {
12386 delta = dis_SSE_shiftE_imm( pfx, delta+2, "psrad", Iop_SarN32x4 );
12387 goto decode_success;
12388 }
12389
12390 /* 66 0F E2 = PSRAD by E */
12391 if (have66noF2noF3(pfx) && sz == 2
12392 && insn[0] == 0x0F && insn[1] == 0xE2) {
sewardj2e28ac42008-12-04 00:05:12 +000012393 delta = dis_SSE_shiftG_byE( vbi, pfx, delta+2, "psrad", Iop_SarN32x4 );
sewardjadffcef2005-05-11 00:03:06 +000012394 goto decode_success;
12395 }
12396
12397 /* 66 0F 71 /4 ib = PSRAW by immediate */
12398 if (have66noF2noF3(pfx) && sz == 2
12399 && insn[0] == 0x0F && insn[1] == 0x71
12400 && epartIsReg(insn[2])
12401 && gregLO3ofRM(insn[2]) == 4) {
12402 delta = dis_SSE_shiftE_imm( pfx, delta+2, "psraw", Iop_SarN16x8 );
12403 goto decode_success;
12404 }
12405
12406 /* 66 0F E1 = PSRAW by E */
12407 if (have66noF2noF3(pfx) && sz == 2
12408 && insn[0] == 0x0F && insn[1] == 0xE1) {
sewardj2e28ac42008-12-04 00:05:12 +000012409 delta = dis_SSE_shiftG_byE( vbi, pfx, delta+2, "psraw", Iop_SarN16x8 );
sewardjadffcef2005-05-11 00:03:06 +000012410 goto decode_success;
12411 }
12412
12413 /* 66 0F 72 /2 ib = PSRLD by immediate */
12414 if (have66noF2noF3(pfx) && sz == 2
12415 && insn[0] == 0x0F && insn[1] == 0x72
12416 && epartIsReg(insn[2])
12417 && gregLO3ofRM(insn[2]) == 2) {
12418 delta = dis_SSE_shiftE_imm( pfx, delta+2, "psrld", Iop_ShrN32x4 );
12419 goto decode_success;
12420 }
12421
12422 /* 66 0F D2 = PSRLD by E */
12423 if (have66noF2noF3(pfx) && sz == 2
12424 && insn[0] == 0x0F && insn[1] == 0xD2) {
sewardj2e28ac42008-12-04 00:05:12 +000012425 delta = dis_SSE_shiftG_byE( vbi, pfx, delta+2, "psrld", Iop_ShrN32x4 );
sewardjadffcef2005-05-11 00:03:06 +000012426 goto decode_success;
12427 }
sewardj97628592005-05-10 22:42:54 +000012428
12429 /* 66 0F 73 /3 ib = PSRLDQ by immediate */
12430 /* note, if mem case ever filled in, 1 byte after amode */
12431 if (have66noF2noF3(pfx) && sz == 2
12432 && insn[0] == 0x0F && insn[1] == 0x73
12433 && epartIsReg(insn[2])
12434 && gregLO3ofRM(insn[2]) == 3) {
12435 IRTemp sV, dV, hi64, lo64, hi64r, lo64r;
12436 Int imm = (Int)insn[3];
12437 Int reg = eregOfRexRM(pfx,insn[2]);
12438 DIP("psrldq $%d,%s\n", imm, nameXMMReg(reg));
12439 vassert(imm >= 0 && imm <= 255);
12440 delta += 4;
12441
12442 sV = newTemp(Ity_V128);
12443 dV = newTemp(Ity_V128);
12444 hi64 = newTemp(Ity_I64);
12445 lo64 = newTemp(Ity_I64);
12446 hi64r = newTemp(Ity_I64);
12447 lo64r = newTemp(Ity_I64);
12448
12449 if (imm >= 16) {
12450 putXMMReg(reg, mkV128(0x0000));
12451 goto decode_success;
12452 }
12453
12454 assign( sV, getXMMReg(reg) );
12455 assign( hi64, unop(Iop_V128HIto64, mkexpr(sV)) );
12456 assign( lo64, unop(Iop_V128to64, mkexpr(sV)) );
12457
12458 if (imm == 0) {
12459 assign( lo64r, mkexpr(lo64) );
12460 assign( hi64r, mkexpr(hi64) );
12461 }
12462 else
12463 if (imm == 8) {
12464 assign( hi64r, mkU64(0) );
12465 assign( lo64r, mkexpr(hi64) );
12466 }
12467 else
12468 if (imm > 8) {
12469 assign( hi64r, mkU64(0) );
12470 assign( lo64r, binop( Iop_Shr64,
12471 mkexpr(hi64),
12472 mkU8( 8*(imm-8) ) ));
12473 } else {
12474 assign( hi64r, binop( Iop_Shr64,
12475 mkexpr(hi64),
12476 mkU8(8 * imm) ));
12477 assign( lo64r,
12478 binop( Iop_Or64,
12479 binop(Iop_Shr64, mkexpr(lo64),
12480 mkU8(8 * imm)),
12481 binop(Iop_Shl64, mkexpr(hi64),
12482 mkU8(8 * (8 - imm)) )
12483 )
12484 );
12485 }
12486
12487 assign( dV, binop(Iop_64HLtoV128, mkexpr(hi64r), mkexpr(lo64r)) );
12488 putXMMReg(reg, mkexpr(dV));
12489 goto decode_success;
12490 }
sewardj09717342005-05-05 21:34:02 +000012491
12492 /* 66 0F 73 /2 ib = PSRLQ by immediate */
12493 if (have66noF2noF3(pfx) && sz == 2
12494 && insn[0] == 0x0F && insn[1] == 0x73
12495 && epartIsReg(insn[2])
12496 && gregLO3ofRM(insn[2]) == 2) {
12497 delta = dis_SSE_shiftE_imm( pfx, delta+2, "psrlq", Iop_ShrN64x2 );
12498 goto decode_success;
12499 }
12500
sewardjadffcef2005-05-11 00:03:06 +000012501 /* 66 0F D3 = PSRLQ by E */
12502 if (have66noF2noF3(pfx) && sz == 2
12503 && insn[0] == 0x0F && insn[1] == 0xD3) {
sewardj2e28ac42008-12-04 00:05:12 +000012504 delta = dis_SSE_shiftG_byE( vbi, pfx, delta+2, "psrlq", Iop_ShrN64x2 );
sewardjadffcef2005-05-11 00:03:06 +000012505 goto decode_success;
12506 }
12507
12508 /* 66 0F 71 /2 ib = PSRLW by immediate */
12509 if (have66noF2noF3(pfx) && sz == 2
12510 && insn[0] == 0x0F && insn[1] == 0x71
12511 && epartIsReg(insn[2])
12512 && gregLO3ofRM(insn[2]) == 2) {
12513 delta = dis_SSE_shiftE_imm( pfx, delta+2, "psrlw", Iop_ShrN16x8 );
12514 goto decode_success;
12515 }
12516
12517 /* 66 0F D1 = PSRLW by E */
12518 if (have66noF2noF3(pfx) && sz == 2
12519 && insn[0] == 0x0F && insn[1] == 0xD1) {
sewardj2e28ac42008-12-04 00:05:12 +000012520 delta = dis_SSE_shiftG_byE( vbi, pfx, delta+2, "psrlw", Iop_ShrN16x8 );
sewardjadffcef2005-05-11 00:03:06 +000012521 goto decode_success;
12522 }
sewardj97628592005-05-10 22:42:54 +000012523
12524 /* 66 0F F8 = PSUBB */
12525 if (have66noF2noF3(pfx) && sz == 2
12526 && insn[0] == 0x0F && insn[1] == 0xF8) {
sewardj2e28ac42008-12-04 00:05:12 +000012527 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardj97628592005-05-10 22:42:54 +000012528 "psubb", Iop_Sub8x16, False );
12529 goto decode_success;
12530 }
12531
12532 /* 66 0F FA = PSUBD */
12533 if (have66noF2noF3(pfx) && sz == 2
12534 && insn[0] == 0x0F && insn[1] == 0xFA) {
sewardj2e28ac42008-12-04 00:05:12 +000012535 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardj97628592005-05-10 22:42:54 +000012536 "psubd", Iop_Sub32x4, False );
12537 goto decode_success;
12538 }
sewardj8711f662005-05-09 17:52:56 +000012539
12540 /* ***--- this is an MMX class insn introduced in SSE2 ---*** */
12541 /* 0F FB = PSUBQ -- sub 64x1 */
12542 if (haveNo66noF2noF3(pfx) && sz == 4
12543 && insn[0] == 0x0F && insn[1] == 0xFB) {
12544 do_MMX_preamble();
12545 delta = dis_MMXop_regmem_to_reg (
sewardj2e28ac42008-12-04 00:05:12 +000012546 vbi, pfx, delta+2, insn[1], "psubq", False );
sewardj8711f662005-05-09 17:52:56 +000012547 goto decode_success;
12548 }
sewardj09717342005-05-05 21:34:02 +000012549
12550 /* 66 0F FB = PSUBQ */
12551 if (have66noF2noF3(pfx) && sz == 2
12552 && insn[0] == 0x0F && insn[1] == 0xFB) {
sewardj2e28ac42008-12-04 00:05:12 +000012553 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardj09717342005-05-05 21:34:02 +000012554 "psubq", Iop_Sub64x2, False );
12555 goto decode_success;
12556 }
12557
sewardj97628592005-05-10 22:42:54 +000012558 /* 66 0F F9 = PSUBW */
12559 if (have66noF2noF3(pfx) && sz == 2
12560 && insn[0] == 0x0F && insn[1] == 0xF9) {
sewardj2e28ac42008-12-04 00:05:12 +000012561 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardj97628592005-05-10 22:42:54 +000012562 "psubw", Iop_Sub16x8, False );
12563 goto decode_success;
12564 }
12565
12566 /* 66 0F E8 = PSUBSB */
12567 if (have66noF2noF3(pfx) && sz == 2
12568 && insn[0] == 0x0F && insn[1] == 0xE8) {
sewardj2e28ac42008-12-04 00:05:12 +000012569 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardj97628592005-05-10 22:42:54 +000012570 "psubsb", Iop_QSub8Sx16, False );
12571 goto decode_success;
12572 }
12573
12574 /* 66 0F E9 = PSUBSW */
12575 if (have66noF2noF3(pfx) && sz == 2
12576 && insn[0] == 0x0F && insn[1] == 0xE9) {
sewardj2e28ac42008-12-04 00:05:12 +000012577 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardj97628592005-05-10 22:42:54 +000012578 "psubsw", Iop_QSub16Sx8, False );
12579 goto decode_success;
12580 }
12581
12582 /* 66 0F D8 = PSUBSB */
12583 if (have66noF2noF3(pfx) && sz == 2
12584 && insn[0] == 0x0F && insn[1] == 0xD8) {
sewardj2e28ac42008-12-04 00:05:12 +000012585 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardj97628592005-05-10 22:42:54 +000012586 "psubusb", Iop_QSub8Ux16, False );
12587 goto decode_success;
12588 }
12589
12590 /* 66 0F D9 = PSUBSW */
12591 if (have66noF2noF3(pfx) && sz == 2
12592 && insn[0] == 0x0F && insn[1] == 0xD9) {
sewardj2e28ac42008-12-04 00:05:12 +000012593 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardj97628592005-05-10 22:42:54 +000012594 "psubusw", Iop_QSub16Ux8, False );
12595 goto decode_success;
12596 }
12597
12598 /* 66 0F 68 = PUNPCKHBW */
12599 if (have66noF2noF3(pfx) && sz == 2
12600 && insn[0] == 0x0F && insn[1] == 0x68) {
sewardj2e28ac42008-12-04 00:05:12 +000012601 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardj97628592005-05-10 22:42:54 +000012602 "punpckhbw",
12603 Iop_InterleaveHI8x16, True );
12604 goto decode_success;
12605 }
12606
12607 /* 66 0F 6A = PUNPCKHDQ */
12608 if (have66noF2noF3(pfx) && sz == 2
12609 && insn[0] == 0x0F && insn[1] == 0x6A) {
sewardj2e28ac42008-12-04 00:05:12 +000012610 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardj97628592005-05-10 22:42:54 +000012611 "punpckhdq",
12612 Iop_InterleaveHI32x4, True );
12613 goto decode_success;
12614 }
12615
12616 /* 66 0F 6D = PUNPCKHQDQ */
12617 if (have66noF2noF3(pfx) && sz == 2
12618 && insn[0] == 0x0F && insn[1] == 0x6D) {
sewardj2e28ac42008-12-04 00:05:12 +000012619 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardj97628592005-05-10 22:42:54 +000012620 "punpckhqdq",
12621 Iop_InterleaveHI64x2, True );
12622 goto decode_success;
12623 }
12624
12625 /* 66 0F 69 = PUNPCKHWD */
12626 if (have66noF2noF3(pfx) && sz == 2
12627 && insn[0] == 0x0F && insn[1] == 0x69) {
sewardj2e28ac42008-12-04 00:05:12 +000012628 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardj97628592005-05-10 22:42:54 +000012629 "punpckhwd",
12630 Iop_InterleaveHI16x8, True );
12631 goto decode_success;
12632 }
12633
12634 /* 66 0F 60 = PUNPCKLBW */
12635 if (have66noF2noF3(pfx) && sz == 2
12636 && insn[0] == 0x0F && insn[1] == 0x60) {
sewardj2e28ac42008-12-04 00:05:12 +000012637 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardj97628592005-05-10 22:42:54 +000012638 "punpcklbw",
12639 Iop_InterleaveLO8x16, True );
12640 goto decode_success;
12641 }
12642
12643 /* 66 0F 62 = PUNPCKLDQ */
12644 if (have66noF2noF3(pfx) && sz == 2
12645 && insn[0] == 0x0F && insn[1] == 0x62) {
sewardj2e28ac42008-12-04 00:05:12 +000012646 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardj97628592005-05-10 22:42:54 +000012647 "punpckldq",
12648 Iop_InterleaveLO32x4, True );
12649 goto decode_success;
12650 }
12651
12652 /* 66 0F 6C = PUNPCKLQDQ */
12653 if (have66noF2noF3(pfx) && sz == 2
12654 && insn[0] == 0x0F && insn[1] == 0x6C) {
sewardj2e28ac42008-12-04 00:05:12 +000012655 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardj97628592005-05-10 22:42:54 +000012656 "punpcklqdq",
12657 Iop_InterleaveLO64x2, True );
12658 goto decode_success;
12659 }
12660
12661 /* 66 0F 61 = PUNPCKLWD */
12662 if (have66noF2noF3(pfx) && sz == 2
12663 && insn[0] == 0x0F && insn[1] == 0x61) {
sewardj2e28ac42008-12-04 00:05:12 +000012664 delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
sewardj97628592005-05-10 22:42:54 +000012665 "punpcklwd",
12666 Iop_InterleaveLO16x8, True );
12667 goto decode_success;
12668 }
sewardj09717342005-05-05 21:34:02 +000012669
12670 /* 66 0F EF = PXOR */
12671 if (have66noF2noF3(pfx) && sz == 2
12672 && insn[0] == 0x0F && insn[1] == 0xEF) {
sewardj2e28ac42008-12-04 00:05:12 +000012673 delta = dis_SSE_E_to_G_all( vbi, pfx, delta+2, "pxor", Iop_XorV128 );
sewardj09717342005-05-05 21:34:02 +000012674 goto decode_success;
12675 }
12676
sewardjd20c8852005-01-20 20:04:07 +000012677//.. //-- /* FXSAVE/FXRSTOR m32 -- load/store the FPU/MMX/SSE state. */
12678//.. //-- if (insn[0] == 0x0F && insn[1] == 0xAE
12679//.. //-- && (!epartIsReg(insn[2]))
12680//.. //-- && (gregOfRM(insn[2]) == 1 || gregOfRM(insn[2]) == 0) ) {
12681//.. //-- Bool store = gregOfRM(insn[2]) == 0;
12682//.. //-- vg_assert(sz == 4);
12683//.. //-- pair = disAMode ( cb, sorb, eip+2, dis_buf );
12684//.. //-- t1 = LOW24(pair);
12685//.. //-- eip += 2+HI8(pair);
12686//.. //-- uInstr3(cb, store ? SSE2a_MemWr : SSE2a_MemRd, 512,
12687//.. //-- Lit16, (((UShort)insn[0]) << 8) | (UShort)insn[1],
12688//.. //-- Lit16, (UShort)insn[2],
12689//.. //-- TempReg, t1 );
12690//.. //-- DIP("fx%s %s\n", store ? "save" : "rstor", dis_buf );
12691//.. //-- goto decode_success;
12692//.. //-- }
sewardj3e616e62006-01-07 22:58:54 +000012693
12694 /* 0F AE /7 = CLFLUSH -- flush cache line */
12695 if (haveNo66noF2noF3(pfx) && sz == 4
12696 && insn[0] == 0x0F && insn[1] == 0xAE
12697 && !epartIsReg(insn[2]) && gregLO3ofRM(insn[2]) == 7) {
12698
12699 /* This is something of a hack. We need to know the size of the
12700 cache line containing addr. Since we don't (easily), assume
12701 256 on the basis that no real cache would have a line that
12702 big. It's safe to invalidate more stuff than we need, just
12703 inefficient. */
12704 ULong lineszB = 256ULL;
12705
sewardj2e28ac42008-12-04 00:05:12 +000012706 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardj3e616e62006-01-07 22:58:54 +000012707 delta += 2+alen;
12708
12709 /* Round addr down to the start of the containing block. */
12710 stmt( IRStmt_Put(
12711 OFFB_TISTART,
12712 binop( Iop_And64,
12713 mkexpr(addr),
12714 mkU64( ~(lineszB-1) ))) );
12715
12716 stmt( IRStmt_Put(OFFB_TILEN, mkU64(lineszB) ) );
12717
sewardjdd40fdf2006-12-24 02:20:24 +000012718 irsb->jumpkind = Ijk_TInval;
12719 irsb->next = mkU64(guest_RIP_bbstart+delta);
sewardj3e616e62006-01-07 22:58:54 +000012720 dres.whatNext = Dis_StopHere;
12721
12722 DIP("clflush %s\n", dis_buf);
12723 goto decode_success;
12724 }
sewardjdf0e0022005-01-25 15:48:43 +000012725
sewardjdf0e0022005-01-25 15:48:43 +000012726 /* ---------------------------------------------------- */
12727 /* --- end of the SSE/SSE2 decoder. --- */
12728 /* ---------------------------------------------------- */
12729
sewardjfcf21f32006-08-04 14:51:19 +000012730 /* ---------------------------------------------------- */
12731 /* --- start of the SSE3 decoder. --- */
12732 /* ---------------------------------------------------- */
12733
12734 /* F3 0F 12 = MOVSLDUP -- move from E (mem or xmm) to G (xmm),
12735 duplicating some lanes (2:2:0:0). */
12736 /* F3 0F 16 = MOVSHDUP -- move from E (mem or xmm) to G (xmm),
12737 duplicating some lanes (3:3:1:1). */
12738 if (haveF3no66noF2(pfx) && sz == 4
12739 && insn[0] == 0x0F && (insn[1] == 0x12 || insn[1] == 0x16)) {
12740 IRTemp s3, s2, s1, s0;
12741 IRTemp sV = newTemp(Ity_V128);
12742 Bool isH = insn[1] == 0x16;
12743 s3 = s2 = s1 = s0 = IRTemp_INVALID;
12744
12745 modrm = insn[2];
12746 if (epartIsReg(modrm)) {
12747 assign( sV, getXMMReg( eregOfRexRM(pfx,modrm)) );
12748 DIP("movs%cdup %s,%s\n", isH ? 'h' : 'l',
12749 nameXMMReg(eregOfRexRM(pfx,modrm)),
12750 nameXMMReg(gregOfRexRM(pfx,modrm)));
12751 delta += 2+1;
12752 } else {
sewardj2e28ac42008-12-04 00:05:12 +000012753 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardjfcf21f32006-08-04 14:51:19 +000012754 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
12755 DIP("movs%cdup %s,%s\n", isH ? 'h' : 'l',
12756 dis_buf,
12757 nameXMMReg(gregOfRexRM(pfx,modrm)));
12758 delta += 2+alen;
12759 }
12760
12761 breakup128to32s( sV, &s3, &s2, &s1, &s0 );
12762 putXMMReg( gregOfRexRM(pfx,modrm),
12763 isH ? mk128from32s( s3, s3, s1, s1 )
12764 : mk128from32s( s2, s2, s0, s0 ) );
12765 goto decode_success;
12766 }
12767
12768 /* F2 0F 12 = MOVDDUP -- move from E (mem or xmm) to G (xmm),
12769 duplicating some lanes (0:1:0:1). */
sewardjb4bf5882007-11-06 20:39:17 +000012770 if (haveF2no66noF3(pfx)
12771 && (sz == 4 || /* ignore redundant REX.W */ sz == 8)
sewardjfcf21f32006-08-04 14:51:19 +000012772 && insn[0] == 0x0F && insn[1] == 0x12) {
12773 IRTemp sV = newTemp(Ity_V128);
12774 IRTemp d0 = newTemp(Ity_I64);
12775
12776 modrm = insn[2];
12777 if (epartIsReg(modrm)) {
12778 assign( sV, getXMMReg( eregOfRexRM(pfx,modrm)) );
12779 DIP("movddup %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
12780 nameXMMReg(gregOfRexRM(pfx,modrm)));
12781 delta += 2+1;
12782 assign ( d0, unop(Iop_V128to64, mkexpr(sV)) );
12783 } else {
sewardj2e28ac42008-12-04 00:05:12 +000012784 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardjfcf21f32006-08-04 14:51:19 +000012785 assign( d0, loadLE(Ity_I64, mkexpr(addr)) );
12786 DIP("movddup %s,%s\n", dis_buf,
12787 nameXMMReg(gregOfRexRM(pfx,modrm)));
12788 delta += 2+alen;
12789 }
12790
12791 putXMMReg( gregOfRexRM(pfx,modrm),
12792 binop(Iop_64HLtoV128,mkexpr(d0),mkexpr(d0)) );
12793 goto decode_success;
12794 }
12795
12796 /* F2 0F D0 = ADDSUBPS -- 32x4 +/-/+/- from E (mem or xmm) to G (xmm). */
12797 if (haveF2no66noF3(pfx) && sz == 4
12798 && insn[0] == 0x0F && insn[1] == 0xD0) {
12799 IRTemp a3, a2, a1, a0, s3, s2, s1, s0;
12800 IRTemp eV = newTemp(Ity_V128);
12801 IRTemp gV = newTemp(Ity_V128);
12802 IRTemp addV = newTemp(Ity_V128);
12803 IRTemp subV = newTemp(Ity_V128);
12804 a3 = a2 = a1 = a0 = s3 = s2 = s1 = s0 = IRTemp_INVALID;
12805
12806 modrm = insn[2];
12807 if (epartIsReg(modrm)) {
12808 assign( eV, getXMMReg( eregOfRexRM(pfx,modrm)) );
12809 DIP("addsubps %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
12810 nameXMMReg(gregOfRexRM(pfx,modrm)));
12811 delta += 2+1;
12812 } else {
sewardj2e28ac42008-12-04 00:05:12 +000012813 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardjfcf21f32006-08-04 14:51:19 +000012814 assign( eV, loadLE(Ity_V128, mkexpr(addr)) );
12815 DIP("addsubps %s,%s\n", dis_buf,
12816 nameXMMReg(gregOfRexRM(pfx,modrm)));
12817 delta += 2+alen;
12818 }
12819
12820 assign( gV, getXMMReg(gregOfRexRM(pfx,modrm)) );
12821
12822 assign( addV, binop(Iop_Add32Fx4, mkexpr(gV), mkexpr(eV)) );
12823 assign( subV, binop(Iop_Sub32Fx4, mkexpr(gV), mkexpr(eV)) );
12824
12825 breakup128to32s( addV, &a3, &a2, &a1, &a0 );
12826 breakup128to32s( subV, &s3, &s2, &s1, &s0 );
12827
12828 putXMMReg( gregOfRexRM(pfx,modrm), mk128from32s( a3, s2, a1, s0 ));
12829 goto decode_success;
12830 }
12831
12832 /* 66 0F D0 = ADDSUBPD -- 64x4 +/- from E (mem or xmm) to G (xmm). */
12833 if (have66noF2noF3(pfx) && sz == 2
12834 && insn[0] == 0x0F && insn[1] == 0xD0) {
12835 IRTemp eV = newTemp(Ity_V128);
12836 IRTemp gV = newTemp(Ity_V128);
12837 IRTemp addV = newTemp(Ity_V128);
12838 IRTemp subV = newTemp(Ity_V128);
12839 IRTemp a1 = newTemp(Ity_I64);
12840 IRTemp s0 = newTemp(Ity_I64);
12841
12842 modrm = insn[2];
12843 if (epartIsReg(modrm)) {
12844 assign( eV, getXMMReg( eregOfRexRM(pfx,modrm)) );
12845 DIP("addsubpd %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
12846 nameXMMReg(gregOfRexRM(pfx,modrm)));
12847 delta += 2+1;
12848 } else {
sewardj2e28ac42008-12-04 00:05:12 +000012849 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardjfcf21f32006-08-04 14:51:19 +000012850 assign( eV, loadLE(Ity_V128, mkexpr(addr)) );
12851 DIP("addsubpd %s,%s\n", dis_buf,
12852 nameXMMReg(gregOfRexRM(pfx,modrm)));
12853 delta += 2+alen;
12854 }
12855
12856 assign( gV, getXMMReg(gregOfRexRM(pfx,modrm)) );
12857
12858 assign( addV, binop(Iop_Add64Fx2, mkexpr(gV), mkexpr(eV)) );
12859 assign( subV, binop(Iop_Sub64Fx2, mkexpr(gV), mkexpr(eV)) );
12860
12861 assign( a1, unop(Iop_V128HIto64, mkexpr(addV) ));
12862 assign( s0, unop(Iop_V128to64, mkexpr(subV) ));
12863
12864 putXMMReg( gregOfRexRM(pfx,modrm),
12865 binop(Iop_64HLtoV128, mkexpr(a1), mkexpr(s0)) );
12866 goto decode_success;
12867 }
12868
12869 /* F2 0F 7D = HSUBPS -- 32x4 sub across from E (mem or xmm) to G (xmm). */
12870 /* F2 0F 7C = HADDPS -- 32x4 add across from E (mem or xmm) to G (xmm). */
12871 if (haveF2no66noF3(pfx) && sz == 4
12872 && insn[0] == 0x0F && (insn[1] == 0x7C || insn[1] == 0x7D)) {
12873 IRTemp e3, e2, e1, e0, g3, g2, g1, g0;
12874 IRTemp eV = newTemp(Ity_V128);
12875 IRTemp gV = newTemp(Ity_V128);
12876 IRTemp leftV = newTemp(Ity_V128);
12877 IRTemp rightV = newTemp(Ity_V128);
12878 Bool isAdd = insn[1] == 0x7C;
12879 HChar* str = isAdd ? "add" : "sub";
12880 e3 = e2 = e1 = e0 = g3 = g2 = g1 = g0 = IRTemp_INVALID;
12881
12882 modrm = insn[2];
12883 if (epartIsReg(modrm)) {
12884 assign( eV, getXMMReg( eregOfRexRM(pfx,modrm)) );
12885 DIP("h%sps %s,%s\n", str, nameXMMReg(eregOfRexRM(pfx,modrm)),
12886 nameXMMReg(gregOfRexRM(pfx,modrm)));
12887 delta += 2+1;
12888 } else {
sewardj2e28ac42008-12-04 00:05:12 +000012889 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardjfcf21f32006-08-04 14:51:19 +000012890 assign( eV, loadLE(Ity_V128, mkexpr(addr)) );
12891 DIP("h%sps %s,%s\n", str, dis_buf,
12892 nameXMMReg(gregOfRexRM(pfx,modrm)));
12893 delta += 2+alen;
12894 }
12895
12896 assign( gV, getXMMReg(gregOfRexRM(pfx,modrm)) );
12897
12898 breakup128to32s( eV, &e3, &e2, &e1, &e0 );
12899 breakup128to32s( gV, &g3, &g2, &g1, &g0 );
12900
12901 assign( leftV, mk128from32s( e2, e0, g2, g0 ) );
12902 assign( rightV, mk128from32s( e3, e1, g3, g1 ) );
12903
12904 putXMMReg( gregOfRexRM(pfx,modrm),
12905 binop(isAdd ? Iop_Add32Fx4 : Iop_Sub32Fx4,
12906 mkexpr(leftV), mkexpr(rightV) ) );
12907 goto decode_success;
12908 }
12909
12910 /* 66 0F 7D = HSUBPD -- 64x2 sub across from E (mem or xmm) to G (xmm). */
12911 /* 66 0F 7C = HADDPD -- 64x2 add across from E (mem or xmm) to G (xmm). */
12912 if (have66noF2noF3(pfx) && sz == 2
12913 && insn[0] == 0x0F && (insn[1] == 0x7C || insn[1] == 0x7D)) {
12914 IRTemp e1 = newTemp(Ity_I64);
12915 IRTemp e0 = newTemp(Ity_I64);
12916 IRTemp g1 = newTemp(Ity_I64);
12917 IRTemp g0 = newTemp(Ity_I64);
12918 IRTemp eV = newTemp(Ity_V128);
12919 IRTemp gV = newTemp(Ity_V128);
12920 IRTemp leftV = newTemp(Ity_V128);
12921 IRTemp rightV = newTemp(Ity_V128);
12922 Bool isAdd = insn[1] == 0x7C;
12923 HChar* str = isAdd ? "add" : "sub";
12924
12925 modrm = insn[2];
12926 if (epartIsReg(modrm)) {
12927 assign( eV, getXMMReg( eregOfRexRM(pfx,modrm)) );
12928 DIP("h%spd %s,%s\n", str, nameXMMReg(eregOfRexRM(pfx,modrm)),
12929 nameXMMReg(gregOfRexRM(pfx,modrm)));
12930 delta += 2+1;
12931 } else {
sewardj2e28ac42008-12-04 00:05:12 +000012932 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardjfcf21f32006-08-04 14:51:19 +000012933 assign( eV, loadLE(Ity_V128, mkexpr(addr)) );
12934 DIP("h%spd %s,%s\n", str, dis_buf,
12935 nameXMMReg(gregOfRexRM(pfx,modrm)));
12936 delta += 2+alen;
12937 }
12938
12939 assign( gV, getXMMReg(gregOfRexRM(pfx,modrm)) );
12940
12941 assign( e1, unop(Iop_V128HIto64, mkexpr(eV) ));
12942 assign( e0, unop(Iop_V128to64, mkexpr(eV) ));
12943 assign( g1, unop(Iop_V128HIto64, mkexpr(gV) ));
12944 assign( g0, unop(Iop_V128to64, mkexpr(gV) ));
12945
12946 assign( leftV, binop(Iop_64HLtoV128, mkexpr(e0),mkexpr(g0)) );
12947 assign( rightV, binop(Iop_64HLtoV128, mkexpr(e1),mkexpr(g1)) );
12948
12949 putXMMReg( gregOfRexRM(pfx,modrm),
12950 binop(isAdd ? Iop_Add64Fx2 : Iop_Sub64Fx2,
12951 mkexpr(leftV), mkexpr(rightV) ) );
12952 goto decode_success;
12953 }
12954
12955 /* F2 0F F0 = LDDQU -- move from E (mem or xmm) to G (xmm). */
12956 if (haveF2no66noF3(pfx) && sz == 4
12957 && insn[0] == 0x0F && insn[1] == 0xF0) {
12958 modrm = insn[2];
12959 if (epartIsReg(modrm)) {
12960 goto decode_failure;
12961 } else {
sewardj2e28ac42008-12-04 00:05:12 +000012962 addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
sewardjfcf21f32006-08-04 14:51:19 +000012963 putXMMReg( gregOfRexRM(pfx,modrm),
12964 loadLE(Ity_V128, mkexpr(addr)) );
12965 DIP("lddqu %s,%s\n", dis_buf,
12966 nameXMMReg(gregOfRexRM(pfx,modrm)));
12967 delta += 2+alen;
12968 }
12969 goto decode_success;
12970 }
12971
12972 /* ---------------------------------------------------- */
12973 /* --- end of the SSE3 decoder. --- */
12974 /* ---------------------------------------------------- */
12975
sewardjd166e282008-02-06 11:42:45 +000012976 /* ---------------------------------------------------- */
12977 /* --- start of the SSSE3 decoder. --- */
12978 /* ---------------------------------------------------- */
12979
12980 /* 0F 38 04 = PMADDUBSW -- Multiply and Add Packed Signed and
12981 Unsigned Bytes (MMX) */
12982 if (haveNo66noF2noF3(pfx)
12983 && sz == 4
12984 && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x04) {
12985 IRTemp sV = newTemp(Ity_I64);
12986 IRTemp dV = newTemp(Ity_I64);
12987 IRTemp sVoddsSX = newTemp(Ity_I64);
12988 IRTemp sVevensSX = newTemp(Ity_I64);
12989 IRTemp dVoddsZX = newTemp(Ity_I64);
12990 IRTemp dVevensZX = newTemp(Ity_I64);
12991
12992 modrm = insn[3];
12993 do_MMX_preamble();
12994 assign( dV, getMMXReg(gregLO3ofRM(modrm)) );
12995
12996 if (epartIsReg(modrm)) {
12997 assign( sV, getMMXReg(eregLO3ofRM(modrm)) );
12998 delta += 3+1;
12999 DIP("pmaddubsw %s,%s\n", nameMMXReg(eregLO3ofRM(modrm)),
13000 nameMMXReg(gregLO3ofRM(modrm)));
13001 } else {
sewardj2e28ac42008-12-04 00:05:12 +000013002 addr = disAMode ( &alen, vbi, pfx, delta+3, dis_buf, 0 );
sewardjd166e282008-02-06 11:42:45 +000013003 assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
13004 delta += 3+alen;
13005 DIP("pmaddubsw %s,%s\n", dis_buf,
13006 nameMMXReg(gregLO3ofRM(modrm)));
13007 }
13008
13009 /* compute dV unsigned x sV signed */
13010 assign( sVoddsSX,
13011 binop(Iop_SarN16x4, mkexpr(sV), mkU8(8)) );
13012 assign( sVevensSX,
13013 binop(Iop_SarN16x4,
13014 binop(Iop_ShlN16x4, mkexpr(sV), mkU8(8)),
13015 mkU8(8)) );
13016 assign( dVoddsZX,
13017 binop(Iop_ShrN16x4, mkexpr(dV), mkU8(8)) );
13018 assign( dVevensZX,
13019 binop(Iop_ShrN16x4,
13020 binop(Iop_ShlN16x4, mkexpr(dV), mkU8(8)),
13021 mkU8(8)) );
13022
13023 putMMXReg(
13024 gregLO3ofRM(modrm),
13025 binop(Iop_QAdd16Sx4,
13026 binop(Iop_Mul16x4, mkexpr(sVoddsSX), mkexpr(dVoddsZX)),
13027 binop(Iop_Mul16x4, mkexpr(sVevensSX), mkexpr(dVevensZX))
13028 )
13029 );
13030 goto decode_success;
13031 }
13032
13033 /* 66 0F 38 04 = PMADDUBSW -- Multiply and Add Packed Signed and
13034 Unsigned Bytes (XMM) */
13035 if (have66noF2noF3(pfx)
13036 && (sz == 2 || /*redundant REX.W*/ sz == 8)
13037 && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x04) {
13038 IRTemp sV = newTemp(Ity_V128);
13039 IRTemp dV = newTemp(Ity_V128);
13040 IRTemp sVoddsSX = newTemp(Ity_V128);
13041 IRTemp sVevensSX = newTemp(Ity_V128);
13042 IRTemp dVoddsZX = newTemp(Ity_V128);
13043 IRTemp dVevensZX = newTemp(Ity_V128);
13044
13045 modrm = insn[3];
13046 assign( dV, getXMMReg(gregOfRexRM(pfx,modrm)) );
13047
13048 if (epartIsReg(modrm)) {
13049 assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
13050 delta += 3+1;
13051 DIP("pmaddubsw %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
13052 nameXMMReg(gregOfRexRM(pfx,modrm)));
13053 } else {
sewardj2e28ac42008-12-04 00:05:12 +000013054 addr = disAMode ( &alen, vbi, pfx, delta+3, dis_buf, 0 );
sewardj150c9cd2008-02-09 01:16:02 +000013055 gen_SEGV_if_not_16_aligned( addr );
sewardjd166e282008-02-06 11:42:45 +000013056 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
13057 delta += 3+alen;
13058 DIP("pmaddubsw %s,%s\n", dis_buf,
13059 nameXMMReg(gregOfRexRM(pfx,modrm)));
13060 }
13061
13062 /* compute dV unsigned x sV signed */
13063 assign( sVoddsSX,
13064 binop(Iop_SarN16x8, mkexpr(sV), mkU8(8)) );
13065 assign( sVevensSX,
13066 binop(Iop_SarN16x8,
13067 binop(Iop_ShlN16x8, mkexpr(sV), mkU8(8)),
13068 mkU8(8)) );
13069 assign( dVoddsZX,
13070 binop(Iop_ShrN16x8, mkexpr(dV), mkU8(8)) );
13071 assign( dVevensZX,
13072 binop(Iop_ShrN16x8,
13073 binop(Iop_ShlN16x8, mkexpr(dV), mkU8(8)),
13074 mkU8(8)) );
13075
13076 putXMMReg(
13077 gregOfRexRM(pfx,modrm),
13078 binop(Iop_QAdd16Sx8,
13079 binop(Iop_Mul16x8, mkexpr(sVoddsSX), mkexpr(dVoddsZX)),
13080 binop(Iop_Mul16x8, mkexpr(sVevensSX), mkexpr(dVevensZX))
13081 )
13082 );
13083 goto decode_success;
13084 }
13085
13086 /* ***--- these are MMX class insns introduced in SSSE3 ---*** */
13087 /* 0F 38 03 = PHADDSW -- 16x4 signed qadd across from E (mem or
13088 mmx) and G to G (mmx). */
13089 /* 0F 38 07 = PHSUBSW -- 16x4 signed qsub across from E (mem or
13090 mmx) and G to G (mmx). */
13091 /* 0F 38 01 = PHADDW -- 16x4 add across from E (mem or mmx) and G
13092 to G (mmx). */
13093 /* 0F 38 05 = PHSUBW -- 16x4 sub across from E (mem or mmx) and G
13094 to G (mmx). */
13095 /* 0F 38 02 = PHADDD -- 32x2 add across from E (mem or mmx) and G
13096 to G (mmx). */
13097 /* 0F 38 06 = PHSUBD -- 32x2 sub across from E (mem or mmx) and G
13098 to G (mmx). */
13099
13100 if (haveNo66noF2noF3(pfx)
13101 && sz == 4
13102 && insn[0] == 0x0F && insn[1] == 0x38
13103 && (insn[2] == 0x03 || insn[2] == 0x07 || insn[2] == 0x01
13104 || insn[2] == 0x05 || insn[2] == 0x02 || insn[2] == 0x06)) {
13105 HChar* str = "???";
13106 IROp opV64 = Iop_INVALID;
13107 IROp opCatO = Iop_CatOddLanes16x4;
13108 IROp opCatE = Iop_CatEvenLanes16x4;
13109 IRTemp sV = newTemp(Ity_I64);
13110 IRTemp dV = newTemp(Ity_I64);
13111
13112 modrm = insn[3];
13113
13114 switch (insn[2]) {
13115 case 0x03: opV64 = Iop_QAdd16Sx4; str = "addsw"; break;
13116 case 0x07: opV64 = Iop_QSub16Sx4; str = "subsw"; break;
13117 case 0x01: opV64 = Iop_Add16x4; str = "addw"; break;
13118 case 0x05: opV64 = Iop_Sub16x4; str = "subw"; break;
13119 case 0x02: opV64 = Iop_Add32x2; str = "addd"; break;
13120 case 0x06: opV64 = Iop_Sub32x2; str = "subd"; break;
13121 default: vassert(0);
13122 }
13123 if (insn[2] == 0x02 || insn[2] == 0x06) {
13124 opCatO = Iop_InterleaveHI32x2;
13125 opCatE = Iop_InterleaveLO32x2;
13126 }
13127
13128 do_MMX_preamble();
13129 assign( dV, getMMXReg(gregLO3ofRM(modrm)) );
13130
13131 if (epartIsReg(modrm)) {
13132 assign( sV, getMMXReg(eregLO3ofRM(modrm)) );
13133 delta += 3+1;
13134 DIP("ph%s %s,%s\n", str, nameMMXReg(eregLO3ofRM(modrm)),
13135 nameMMXReg(gregLO3ofRM(modrm)));
13136 } else {
sewardj2e28ac42008-12-04 00:05:12 +000013137 addr = disAMode ( &alen, vbi, pfx, delta+3, dis_buf, 0 );
sewardjd166e282008-02-06 11:42:45 +000013138 assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
13139 delta += 3+alen;
13140 DIP("ph%s %s,%s\n", str, dis_buf,
13141 nameMMXReg(gregLO3ofRM(modrm)));
13142 }
13143
13144 putMMXReg(
13145 gregLO3ofRM(modrm),
13146 binop(opV64,
13147 binop(opCatE,mkexpr(sV),mkexpr(dV)),
13148 binop(opCatO,mkexpr(sV),mkexpr(dV))
13149 )
13150 );
13151 goto decode_success;
13152 }
13153
13154 /* 66 0F 38 03 = PHADDSW -- 16x8 signed qadd across from E (mem or
13155 xmm) and G to G (xmm). */
13156 /* 66 0F 38 07 = PHSUBSW -- 16x8 signed qsub across from E (mem or
13157 xmm) and G to G (xmm). */
13158 /* 66 0F 38 01 = PHADDW -- 16x8 add across from E (mem or xmm) and
13159 G to G (xmm). */
13160 /* 66 0F 38 05 = PHSUBW -- 16x8 sub across from E (mem or xmm) and
13161 G to G (xmm). */
13162 /* 66 0F 38 02 = PHADDD -- 32x4 add across from E (mem or xmm) and
13163 G to G (xmm). */
13164 /* 66 0F 38 06 = PHSUBD -- 32x4 sub across from E (mem or xmm) and
13165 G to G (xmm). */
13166
13167 if (have66noF2noF3(pfx)
13168 && (sz == 2 || /*redundant REX.W*/ sz == 8)
13169 && insn[0] == 0x0F && insn[1] == 0x38
13170 && (insn[2] == 0x03 || insn[2] == 0x07 || insn[2] == 0x01
13171 || insn[2] == 0x05 || insn[2] == 0x02 || insn[2] == 0x06)) {
13172 HChar* str = "???";
13173 IROp opV64 = Iop_INVALID;
13174 IROp opCatO = Iop_CatOddLanes16x4;
13175 IROp opCatE = Iop_CatEvenLanes16x4;
13176 IRTemp sV = newTemp(Ity_V128);
13177 IRTemp dV = newTemp(Ity_V128);
13178 IRTemp sHi = newTemp(Ity_I64);
13179 IRTemp sLo = newTemp(Ity_I64);
13180 IRTemp dHi = newTemp(Ity_I64);
13181 IRTemp dLo = newTemp(Ity_I64);
13182
13183 modrm = insn[3];
13184
13185 switch (insn[2]) {
13186 case 0x03: opV64 = Iop_QAdd16Sx4; str = "addsw"; break;
13187 case 0x07: opV64 = Iop_QSub16Sx4; str = "subsw"; break;
13188 case 0x01: opV64 = Iop_Add16x4; str = "addw"; break;
13189 case 0x05: opV64 = Iop_Sub16x4; str = "subw"; break;
13190 case 0x02: opV64 = Iop_Add32x2; str = "addd"; break;
13191 case 0x06: opV64 = Iop_Sub32x2; str = "subd"; break;
13192 default: vassert(0);
13193 }
13194 if (insn[2] == 0x02 || insn[2] == 0x06) {
13195 opCatO = Iop_InterleaveHI32x2;
13196 opCatE = Iop_InterleaveLO32x2;
13197 }
13198
13199 assign( dV, getXMMReg(gregOfRexRM(pfx,modrm)) );
13200
13201 if (epartIsReg(modrm)) {
13202 assign( sV, getXMMReg( eregOfRexRM(pfx,modrm)) );
13203 DIP("ph%s %s,%s\n", str, nameXMMReg(eregOfRexRM(pfx,modrm)),
13204 nameXMMReg(gregOfRexRM(pfx,modrm)));
13205 delta += 3+1;
13206 } else {
sewardj2e28ac42008-12-04 00:05:12 +000013207 addr = disAMode ( &alen, vbi, pfx, delta+3, dis_buf, 0 );
sewardj150c9cd2008-02-09 01:16:02 +000013208 gen_SEGV_if_not_16_aligned( addr );
sewardjd166e282008-02-06 11:42:45 +000013209 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
13210 DIP("ph%s %s,%s\n", str, dis_buf,
13211 nameXMMReg(gregOfRexRM(pfx,modrm)));
13212 delta += 3+alen;
13213 }
13214
13215 assign( dHi, unop(Iop_V128HIto64, mkexpr(dV)) );
13216 assign( dLo, unop(Iop_V128to64, mkexpr(dV)) );
13217 assign( sHi, unop(Iop_V128HIto64, mkexpr(sV)) );
13218 assign( sLo, unop(Iop_V128to64, mkexpr(sV)) );
13219
13220 /* This isn't a particularly efficient way to compute the
13221 result, but at least it avoids a proliferation of IROps,
13222 hence avoids complication all the backends. */
13223 putXMMReg(
13224 gregOfRexRM(pfx,modrm),
13225 binop(Iop_64HLtoV128,
13226 binop(opV64,
13227 binop(opCatE,mkexpr(sHi),mkexpr(sLo)),
13228 binop(opCatO,mkexpr(sHi),mkexpr(sLo))
13229 ),
13230 binop(opV64,
13231 binop(opCatE,mkexpr(dHi),mkexpr(dLo)),
13232 binop(opCatO,mkexpr(dHi),mkexpr(dLo))
13233 )
13234 )
13235 );
13236 goto decode_success;
13237 }
13238
13239 /* 0F 38 0B = PMULHRSW -- Packed Multiply High with Round and Scale
13240 (MMX) */
13241 if (haveNo66noF2noF3(pfx)
13242 && sz == 4
13243 && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x0B) {
13244 IRTemp sV = newTemp(Ity_I64);
13245 IRTemp dV = newTemp(Ity_I64);
13246
13247 modrm = insn[3];
13248 do_MMX_preamble();
13249 assign( dV, getMMXReg(gregLO3ofRM(modrm)) );
13250
13251 if (epartIsReg(modrm)) {
13252 assign( sV, getMMXReg(eregLO3ofRM(modrm)) );
13253 delta += 3+1;
13254 DIP("pmulhrsw %s,%s\n", nameMMXReg(eregLO3ofRM(modrm)),
13255 nameMMXReg(gregLO3ofRM(modrm)));
13256 } else {
sewardj2e28ac42008-12-04 00:05:12 +000013257 addr = disAMode ( &alen, vbi, pfx, delta+3, dis_buf, 0 );
sewardjd166e282008-02-06 11:42:45 +000013258 assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
13259 delta += 3+alen;
13260 DIP("pmulhrsw %s,%s\n", dis_buf,
13261 nameMMXReg(gregLO3ofRM(modrm)));
13262 }
13263
13264 putMMXReg(
13265 gregLO3ofRM(modrm),
13266 dis_PMULHRSW_helper( mkexpr(sV), mkexpr(dV) )
13267 );
13268 goto decode_success;
13269 }
13270
13271 /* 66 0F 38 0B = PMULHRSW -- Packed Multiply High with Round and
13272 Scale (XMM) */
13273 if (have66noF2noF3(pfx)
13274 && (sz == 2 || /*redundant REX.W*/ sz == 8)
13275 && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x0B) {
13276 IRTemp sV = newTemp(Ity_V128);
13277 IRTemp dV = newTemp(Ity_V128);
13278 IRTemp sHi = newTemp(Ity_I64);
13279 IRTemp sLo = newTemp(Ity_I64);
13280 IRTemp dHi = newTemp(Ity_I64);
13281 IRTemp dLo = newTemp(Ity_I64);
13282
13283 modrm = insn[3];
13284 assign( dV, getXMMReg(gregOfRexRM(pfx,modrm)) );
13285
13286 if (epartIsReg(modrm)) {
13287 assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
13288 delta += 3+1;
13289 DIP("pmulhrsw %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
13290 nameXMMReg(gregOfRexRM(pfx,modrm)));
13291 } else {
sewardj2e28ac42008-12-04 00:05:12 +000013292 addr = disAMode ( &alen, vbi, pfx, delta+3, dis_buf, 0 );
sewardj150c9cd2008-02-09 01:16:02 +000013293 gen_SEGV_if_not_16_aligned( addr );
sewardjd166e282008-02-06 11:42:45 +000013294 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
13295 delta += 3+alen;
13296 DIP("pmulhrsw %s,%s\n", dis_buf,
13297 nameXMMReg(gregOfRexRM(pfx,modrm)));
13298 }
13299
13300 assign( dHi, unop(Iop_V128HIto64, mkexpr(dV)) );
13301 assign( dLo, unop(Iop_V128to64, mkexpr(dV)) );
13302 assign( sHi, unop(Iop_V128HIto64, mkexpr(sV)) );
13303 assign( sLo, unop(Iop_V128to64, mkexpr(sV)) );
13304
13305 putXMMReg(
13306 gregOfRexRM(pfx,modrm),
13307 binop(Iop_64HLtoV128,
13308 dis_PMULHRSW_helper( mkexpr(sHi), mkexpr(dHi) ),
13309 dis_PMULHRSW_helper( mkexpr(sLo), mkexpr(dLo) )
13310 )
13311 );
13312 goto decode_success;
13313 }
13314
13315 /* 0F 38 08 = PSIGNB -- Packed Sign 8x8 (MMX) */
13316 /* 0F 38 09 = PSIGNW -- Packed Sign 16x4 (MMX) */
13317 /* 0F 38 09 = PSIGND -- Packed Sign 32x2 (MMX) */
13318 if (haveNo66noF2noF3(pfx)
13319 && sz == 4
13320 && insn[0] == 0x0F && insn[1] == 0x38
13321 && (insn[2] == 0x08 || insn[2] == 0x09 || insn[2] == 0x0A)) {
13322 IRTemp sV = newTemp(Ity_I64);
13323 IRTemp dV = newTemp(Ity_I64);
13324 HChar* str = "???";
13325 Int laneszB = 0;
13326
13327 switch (insn[2]) {
13328 case 0x08: laneszB = 1; str = "b"; break;
13329 case 0x09: laneszB = 2; str = "w"; break;
13330 case 0x0A: laneszB = 4; str = "d"; break;
13331 default: vassert(0);
13332 }
13333
13334 modrm = insn[3];
13335 do_MMX_preamble();
13336 assign( dV, getMMXReg(gregLO3ofRM(modrm)) );
13337
13338 if (epartIsReg(modrm)) {
13339 assign( sV, getMMXReg(eregLO3ofRM(modrm)) );
13340 delta += 3+1;
13341 DIP("psign%s %s,%s\n", str, nameMMXReg(eregLO3ofRM(modrm)),
13342 nameMMXReg(gregLO3ofRM(modrm)));
13343 } else {
sewardj2e28ac42008-12-04 00:05:12 +000013344 addr = disAMode ( &alen, vbi, pfx, delta+3, dis_buf, 0 );
sewardjd166e282008-02-06 11:42:45 +000013345 assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
13346 delta += 3+alen;
13347 DIP("psign%s %s,%s\n", str, dis_buf,
13348 nameMMXReg(gregLO3ofRM(modrm)));
13349 }
13350
13351 putMMXReg(
13352 gregLO3ofRM(modrm),
13353 dis_PSIGN_helper( mkexpr(sV), mkexpr(dV), laneszB )
13354 );
13355 goto decode_success;
13356 }
13357
13358 /* 66 0F 38 08 = PSIGNB -- Packed Sign 8x16 (XMM) */
13359 /* 66 0F 38 09 = PSIGNW -- Packed Sign 16x8 (XMM) */
13360 /* 66 0F 38 09 = PSIGND -- Packed Sign 32x4 (XMM) */
13361 if (have66noF2noF3(pfx)
13362 && (sz == 2 || /*redundant REX.W*/ sz == 8)
13363 && insn[0] == 0x0F && insn[1] == 0x38
13364 && (insn[2] == 0x08 || insn[2] == 0x09 || insn[2] == 0x0A)) {
13365 IRTemp sV = newTemp(Ity_V128);
13366 IRTemp dV = newTemp(Ity_V128);
13367 IRTemp sHi = newTemp(Ity_I64);
13368 IRTemp sLo = newTemp(Ity_I64);
13369 IRTemp dHi = newTemp(Ity_I64);
13370 IRTemp dLo = newTemp(Ity_I64);
13371 HChar* str = "???";
13372 Int laneszB = 0;
13373
13374 switch (insn[2]) {
13375 case 0x08: laneszB = 1; str = "b"; break;
13376 case 0x09: laneszB = 2; str = "w"; break;
13377 case 0x0A: laneszB = 4; str = "d"; break;
13378 default: vassert(0);
13379 }
13380
13381 modrm = insn[3];
13382 assign( dV, getXMMReg(gregOfRexRM(pfx,modrm)) );
13383
13384 if (epartIsReg(modrm)) {
13385 assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
13386 delta += 3+1;
13387 DIP("psign%s %s,%s\n", str, nameXMMReg(eregOfRexRM(pfx,modrm)),
13388 nameXMMReg(gregOfRexRM(pfx,modrm)));
13389 } else {
sewardj2e28ac42008-12-04 00:05:12 +000013390 addr = disAMode ( &alen, vbi, pfx, delta+3, dis_buf, 0 );
sewardj150c9cd2008-02-09 01:16:02 +000013391 gen_SEGV_if_not_16_aligned( addr );
sewardjd166e282008-02-06 11:42:45 +000013392 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
13393 delta += 3+alen;
13394 DIP("psign%s %s,%s\n", str, dis_buf,
13395 nameXMMReg(gregOfRexRM(pfx,modrm)));
13396 }
13397
13398 assign( dHi, unop(Iop_V128HIto64, mkexpr(dV)) );
13399 assign( dLo, unop(Iop_V128to64, mkexpr(dV)) );
13400 assign( sHi, unop(Iop_V128HIto64, mkexpr(sV)) );
13401 assign( sLo, unop(Iop_V128to64, mkexpr(sV)) );
13402
13403 putXMMReg(
13404 gregOfRexRM(pfx,modrm),
13405 binop(Iop_64HLtoV128,
13406 dis_PSIGN_helper( mkexpr(sHi), mkexpr(dHi), laneszB ),
13407 dis_PSIGN_helper( mkexpr(sLo), mkexpr(dLo), laneszB )
13408 )
13409 );
13410 goto decode_success;
13411 }
13412
13413 /* 0F 38 1C = PABSB -- Packed Absolute Value 8x8 (MMX) */
13414 /* 0F 38 1D = PABSW -- Packed Absolute Value 16x4 (MMX) */
13415 /* 0F 38 1E = PABSD -- Packed Absolute Value 32x2 (MMX) */
13416 if (haveNo66noF2noF3(pfx)
13417 && sz == 4
13418 && insn[0] == 0x0F && insn[1] == 0x38
13419 && (insn[2] == 0x1C || insn[2] == 0x1D || insn[2] == 0x1E)) {
13420 IRTemp sV = newTemp(Ity_I64);
13421 HChar* str = "???";
13422 Int laneszB = 0;
13423
13424 switch (insn[2]) {
13425 case 0x1C: laneszB = 1; str = "b"; break;
13426 case 0x1D: laneszB = 2; str = "w"; break;
13427 case 0x1E: laneszB = 4; str = "d"; break;
13428 default: vassert(0);
13429 }
13430
13431 modrm = insn[3];
13432 do_MMX_preamble();
13433
13434 if (epartIsReg(modrm)) {
13435 assign( sV, getMMXReg(eregLO3ofRM(modrm)) );
13436 delta += 3+1;
13437 DIP("pabs%s %s,%s\n", str, nameMMXReg(eregLO3ofRM(modrm)),
13438 nameMMXReg(gregLO3ofRM(modrm)));
13439 } else {
sewardj2e28ac42008-12-04 00:05:12 +000013440 addr = disAMode ( &alen, vbi, pfx, delta+3, dis_buf, 0 );
sewardjd166e282008-02-06 11:42:45 +000013441 assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
13442 delta += 3+alen;
13443 DIP("pabs%s %s,%s\n", str, dis_buf,
13444 nameMMXReg(gregLO3ofRM(modrm)));
13445 }
13446
13447 putMMXReg(
13448 gregLO3ofRM(modrm),
13449 dis_PABS_helper( mkexpr(sV), laneszB )
13450 );
13451 goto decode_success;
13452 }
13453
13454 /* 66 0F 38 1C = PABSB -- Packed Absolute Value 8x16 (XMM) */
13455 /* 66 0F 38 1D = PABSW -- Packed Absolute Value 16x8 (XMM) */
13456 /* 66 0F 38 1E = PABSD -- Packed Absolute Value 32x4 (XMM) */
13457 if (have66noF2noF3(pfx)
13458 && (sz == 2 || /*redundant REX.W*/ sz == 8)
13459 && insn[0] == 0x0F && insn[1] == 0x38
13460 && (insn[2] == 0x1C || insn[2] == 0x1D || insn[2] == 0x1E)) {
13461 IRTemp sV = newTemp(Ity_V128);
13462 IRTemp sHi = newTemp(Ity_I64);
13463 IRTemp sLo = newTemp(Ity_I64);
13464 HChar* str = "???";
13465 Int laneszB = 0;
13466
13467 switch (insn[2]) {
13468 case 0x1C: laneszB = 1; str = "b"; break;
13469 case 0x1D: laneszB = 2; str = "w"; break;
13470 case 0x1E: laneszB = 4; str = "d"; break;
13471 default: vassert(0);
13472 }
13473
13474 modrm = insn[3];
13475
13476 if (epartIsReg(modrm)) {
13477 assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
13478 delta += 3+1;
13479 DIP("pabs%s %s,%s\n", str, nameXMMReg(eregOfRexRM(pfx,modrm)),
13480 nameXMMReg(gregOfRexRM(pfx,modrm)));
13481 } else {
sewardj2e28ac42008-12-04 00:05:12 +000013482 addr = disAMode ( &alen, vbi, pfx, delta+3, dis_buf, 0 );
sewardj150c9cd2008-02-09 01:16:02 +000013483 gen_SEGV_if_not_16_aligned( addr );
sewardjd166e282008-02-06 11:42:45 +000013484 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
13485 delta += 3+alen;
13486 DIP("pabs%s %s,%s\n", str, dis_buf,
13487 nameXMMReg(gregOfRexRM(pfx,modrm)));
13488 }
13489
13490 assign( sHi, unop(Iop_V128HIto64, mkexpr(sV)) );
13491 assign( sLo, unop(Iop_V128to64, mkexpr(sV)) );
13492
13493 putXMMReg(
13494 gregOfRexRM(pfx,modrm),
13495 binop(Iop_64HLtoV128,
13496 dis_PABS_helper( mkexpr(sHi), laneszB ),
13497 dis_PABS_helper( mkexpr(sLo), laneszB )
13498 )
13499 );
13500 goto decode_success;
13501 }
13502
13503 /* 0F 3A 0F = PALIGNR -- Packed Align Right (MMX) */
13504 if (haveNo66noF2noF3(pfx) && sz == 4
13505 && insn[0] == 0x0F && insn[1] == 0x3A && insn[2] == 0x0F) {
13506 IRTemp sV = newTemp(Ity_I64);
13507 IRTemp dV = newTemp(Ity_I64);
13508 IRTemp res = newTemp(Ity_I64);
13509
13510 modrm = insn[3];
13511 do_MMX_preamble();
13512 assign( dV, getMMXReg(gregLO3ofRM(modrm)) );
13513
13514 if (epartIsReg(modrm)) {
13515 assign( sV, getMMXReg(eregLO3ofRM(modrm)) );
13516 d64 = (Long)insn[3+1];
13517 delta += 3+1+1;
13518 DIP("palignr $%d,%s,%s\n", (Int)d64,
13519 nameMMXReg(eregLO3ofRM(modrm)),
13520 nameMMXReg(gregLO3ofRM(modrm)));
13521 } else {
sewardjf30883e2009-03-19 23:43:43 +000013522 addr = disAMode ( &alen, vbi, pfx, delta+3, dis_buf, 1 );
sewardjd166e282008-02-06 11:42:45 +000013523 assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
13524 d64 = (Long)insn[3+alen];
13525 delta += 3+alen+1;
13526 DIP("palignr $%d%s,%s\n", (Int)d64,
13527 dis_buf,
13528 nameMMXReg(gregLO3ofRM(modrm)));
13529 }
13530
13531 if (d64 == 0) {
13532 assign( res, mkexpr(sV) );
13533 }
13534 else if (d64 >= 1 && d64 <= 7) {
13535 assign(res,
13536 binop(Iop_Or64,
13537 binop(Iop_Shr64, mkexpr(sV), mkU8(8*d64)),
13538 binop(Iop_Shl64, mkexpr(dV), mkU8(8*(8-d64))
13539 )));
13540 }
13541 else if (d64 == 8) {
13542 assign( res, mkexpr(dV) );
13543 }
13544 else if (d64 >= 9 && d64 <= 15) {
13545 assign( res, binop(Iop_Shr64, mkexpr(dV), mkU8(8*(d64-8))) );
13546 }
13547 else if (d64 >= 16 && d64 <= 255) {
13548 assign( res, mkU64(0) );
13549 }
13550 else
13551 vassert(0);
13552
13553 putMMXReg( gregLO3ofRM(modrm), mkexpr(res) );
13554 goto decode_success;
13555 }
13556
13557 /* 66 0F 3A 0F = PALIGNR -- Packed Align Right (XMM) */
13558 if (have66noF2noF3(pfx)
13559 && (sz == 2 || /*redundant REX.W*/ sz == 8)
13560 && insn[0] == 0x0F && insn[1] == 0x3A && insn[2] == 0x0F) {
13561 IRTemp sV = newTemp(Ity_V128);
13562 IRTemp dV = newTemp(Ity_V128);
13563 IRTemp sHi = newTemp(Ity_I64);
13564 IRTemp sLo = newTemp(Ity_I64);
13565 IRTemp dHi = newTemp(Ity_I64);
13566 IRTemp dLo = newTemp(Ity_I64);
13567 IRTemp rHi = newTemp(Ity_I64);
13568 IRTemp rLo = newTemp(Ity_I64);
13569
13570 modrm = insn[3];
13571 assign( dV, getXMMReg(gregOfRexRM(pfx,modrm)) );
13572
13573 if (epartIsReg(modrm)) {
13574 assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
13575 d64 = (Long)insn[3+1];
13576 delta += 3+1+1;
13577 DIP("palignr $%d,%s,%s\n", (Int)d64,
13578 nameXMMReg(eregOfRexRM(pfx,modrm)),
13579 nameXMMReg(gregOfRexRM(pfx,modrm)));
13580 } else {
sewardjf30883e2009-03-19 23:43:43 +000013581 addr = disAMode ( &alen, vbi, pfx, delta+3, dis_buf, 1 );
sewardj150c9cd2008-02-09 01:16:02 +000013582 gen_SEGV_if_not_16_aligned( addr );
sewardjd166e282008-02-06 11:42:45 +000013583 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
13584 d64 = (Long)insn[3+alen];
13585 delta += 3+alen+1;
13586 DIP("palignr $%d,%s,%s\n", (Int)d64,
13587 dis_buf,
13588 nameXMMReg(gregOfRexRM(pfx,modrm)));
13589 }
13590
13591 assign( dHi, unop(Iop_V128HIto64, mkexpr(dV)) );
13592 assign( dLo, unop(Iop_V128to64, mkexpr(dV)) );
13593 assign( sHi, unop(Iop_V128HIto64, mkexpr(sV)) );
13594 assign( sLo, unop(Iop_V128to64, mkexpr(sV)) );
13595
13596 if (d64 == 0) {
13597 assign( rHi, mkexpr(sHi) );
13598 assign( rLo, mkexpr(sLo) );
13599 }
13600 else if (d64 >= 1 && d64 <= 7) {
13601 assign( rHi, dis_PALIGNR_XMM_helper(dLo, sHi, d64) );
sewardj150c9cd2008-02-09 01:16:02 +000013602 assign( rLo, dis_PALIGNR_XMM_helper(sHi, sLo, d64) );
sewardjd166e282008-02-06 11:42:45 +000013603 }
13604 else if (d64 == 8) {
13605 assign( rHi, mkexpr(dLo) );
13606 assign( rLo, mkexpr(sHi) );
13607 }
13608 else if (d64 >= 9 && d64 <= 15) {
13609 assign( rHi, dis_PALIGNR_XMM_helper(dHi, dLo, d64-8) );
sewardj150c9cd2008-02-09 01:16:02 +000013610 assign( rLo, dis_PALIGNR_XMM_helper(dLo, sHi, d64-8) );
sewardjd166e282008-02-06 11:42:45 +000013611 }
13612 else if (d64 == 16) {
13613 assign( rHi, mkexpr(dHi) );
13614 assign( rLo, mkexpr(dLo) );
13615 }
13616 else if (d64 >= 17 && d64 <= 23) {
13617 assign( rHi, binop(Iop_Shr64, mkexpr(dHi), mkU8(8*(d64-16))) );
sewardj150c9cd2008-02-09 01:16:02 +000013618 assign( rLo, dis_PALIGNR_XMM_helper(dHi, dLo, d64-16) );
sewardjd166e282008-02-06 11:42:45 +000013619 }
13620 else if (d64 == 24) {
13621 assign( rHi, mkU64(0) );
13622 assign( rLo, mkexpr(dHi) );
13623 }
13624 else if (d64 >= 25 && d64 <= 31) {
13625 assign( rHi, mkU64(0) );
13626 assign( rLo, binop(Iop_Shr64, mkexpr(dHi), mkU8(8*(d64-24))) );
13627 }
13628 else if (d64 >= 32 && d64 <= 255) {
13629 assign( rHi, mkU64(0) );
13630 assign( rLo, mkU64(0) );
13631 }
13632 else
13633 vassert(0);
13634
13635 putXMMReg(
13636 gregOfRexRM(pfx,modrm),
13637 binop(Iop_64HLtoV128, mkexpr(rHi), mkexpr(rLo))
13638 );
13639 goto decode_success;
13640 }
13641
13642 /* 0F 38 00 = PSHUFB -- Packed Shuffle Bytes 8x8 (MMX) */
13643 if (haveNo66noF2noF3(pfx)
13644 && sz == 4
13645 && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x00) {
13646 IRTemp sV = newTemp(Ity_I64);
13647 IRTemp dV = newTemp(Ity_I64);
13648
13649 modrm = insn[3];
13650 do_MMX_preamble();
13651 assign( dV, getMMXReg(gregLO3ofRM(modrm)) );
13652
13653 if (epartIsReg(modrm)) {
13654 assign( sV, getMMXReg(eregLO3ofRM(modrm)) );
13655 delta += 3+1;
13656 DIP("pshufb %s,%s\n", nameMMXReg(eregLO3ofRM(modrm)),
13657 nameMMXReg(gregLO3ofRM(modrm)));
13658 } else {
sewardj2e28ac42008-12-04 00:05:12 +000013659 addr = disAMode ( &alen, vbi, pfx, delta+3, dis_buf, 0 );
sewardjd166e282008-02-06 11:42:45 +000013660 assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
13661 delta += 3+alen;
13662 DIP("pshufb %s,%s\n", dis_buf,
13663 nameMMXReg(gregLO3ofRM(modrm)));
13664 }
13665
13666 putMMXReg(
13667 gregLO3ofRM(modrm),
13668 binop(
13669 Iop_And64,
13670 /* permute the lanes */
13671 binop(
13672 Iop_Perm8x8,
13673 mkexpr(dV),
13674 binop(Iop_And64, mkexpr(sV), mkU64(0x0707070707070707ULL))
sewardj150c9cd2008-02-09 01:16:02 +000013675 ),
sewardjd166e282008-02-06 11:42:45 +000013676 /* mask off lanes which have (index & 0x80) == 0x80 */
13677 unop(Iop_Not64, binop(Iop_SarN8x8, mkexpr(sV), mkU8(7)))
13678 )
13679 );
13680 goto decode_success;
13681 }
13682
13683 /* 66 0F 38 00 = PSHUFB -- Packed Shuffle Bytes 8x16 (XMM) */
13684 if (have66noF2noF3(pfx)
13685 && (sz == 2 || /*redundant REX.W*/ sz == 8)
13686 && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x00) {
13687 IRTemp sV = newTemp(Ity_V128);
13688 IRTemp dV = newTemp(Ity_V128);
13689 IRTemp sHi = newTemp(Ity_I64);
13690 IRTemp sLo = newTemp(Ity_I64);
13691 IRTemp dHi = newTemp(Ity_I64);
13692 IRTemp dLo = newTemp(Ity_I64);
13693 IRTemp rHi = newTemp(Ity_I64);
13694 IRTemp rLo = newTemp(Ity_I64);
13695 IRTemp sevens = newTemp(Ity_I64);
13696 IRTemp mask0x80hi = newTemp(Ity_I64);
13697 IRTemp mask0x80lo = newTemp(Ity_I64);
13698 IRTemp maskBit3hi = newTemp(Ity_I64);
13699 IRTemp maskBit3lo = newTemp(Ity_I64);
13700 IRTemp sAnd7hi = newTemp(Ity_I64);
13701 IRTemp sAnd7lo = newTemp(Ity_I64);
13702 IRTemp permdHi = newTemp(Ity_I64);
13703 IRTemp permdLo = newTemp(Ity_I64);
13704
13705 modrm = insn[3];
13706 assign( dV, getXMMReg(gregOfRexRM(pfx,modrm)) );
13707
13708 if (epartIsReg(modrm)) {
13709 assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
13710 delta += 3+1;
13711 DIP("pshufb %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
13712 nameXMMReg(gregOfRexRM(pfx,modrm)));
13713 } else {
sewardj2e28ac42008-12-04 00:05:12 +000013714 addr = disAMode ( &alen, vbi, pfx, delta+3, dis_buf, 0 );
sewardj150c9cd2008-02-09 01:16:02 +000013715 gen_SEGV_if_not_16_aligned( addr );
sewardjd166e282008-02-06 11:42:45 +000013716 assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
13717 delta += 3+alen;
13718 DIP("pshufb %s,%s\n", dis_buf,
13719 nameXMMReg(gregOfRexRM(pfx,modrm)));
13720 }
13721
13722 assign( dHi, unop(Iop_V128HIto64, mkexpr(dV)) );
13723 assign( dLo, unop(Iop_V128to64, mkexpr(dV)) );
13724 assign( sHi, unop(Iop_V128HIto64, mkexpr(sV)) );
13725 assign( sLo, unop(Iop_V128to64, mkexpr(sV)) );
13726
13727 assign( sevens, mkU64(0x0707070707070707ULL) );
13728
13729 /*
13730 mask0x80hi = Not(SarN8x8(sHi,7))
13731 maskBit3hi = SarN8x8(ShlN8x8(sHi,4),7)
13732 sAnd7hi = And(sHi,sevens)
13733 permdHi = Or( And(Perm8x8(dHi,sAnd7hi),maskBit3hi),
13734 And(Perm8x8(dLo,sAnd7hi),Not(maskBit3hi)) )
13735 rHi = And(permdHi,mask0x80hi)
13736 */
13737 assign(
13738 mask0x80hi,
13739 unop(Iop_Not64, binop(Iop_SarN8x8,mkexpr(sHi),mkU8(7))));
13740
13741 assign(
13742 maskBit3hi,
13743 binop(Iop_SarN8x8,
13744 binop(Iop_ShlN8x8,mkexpr(sHi),mkU8(4)),
13745 mkU8(7)));
13746
13747 assign(sAnd7hi, binop(Iop_And64,mkexpr(sHi),mkexpr(sevens)));
13748
13749 assign(
13750 permdHi,
13751 binop(
13752 Iop_Or64,
13753 binop(Iop_And64,
13754 binop(Iop_Perm8x8,mkexpr(dHi),mkexpr(sAnd7hi)),
13755 mkexpr(maskBit3hi)),
13756 binop(Iop_And64,
13757 binop(Iop_Perm8x8,mkexpr(dLo),mkexpr(sAnd7hi)),
13758 unop(Iop_Not64,mkexpr(maskBit3hi))) ));
13759
13760 assign(rHi, binop(Iop_And64,mkexpr(permdHi),mkexpr(mask0x80hi)) );
13761
13762 /* And the same for the lower half of the result. What fun. */
13763
13764 assign(
13765 mask0x80lo,
13766 unop(Iop_Not64, binop(Iop_SarN8x8,mkexpr(sLo),mkU8(7))));
13767
13768 assign(
13769 maskBit3lo,
13770 binop(Iop_SarN8x8,
13771 binop(Iop_ShlN8x8,mkexpr(sLo),mkU8(4)),
13772 mkU8(7)));
13773
13774 assign(sAnd7lo, binop(Iop_And64,mkexpr(sLo),mkexpr(sevens)));
13775
13776 assign(
13777 permdLo,
13778 binop(
13779 Iop_Or64,
13780 binop(Iop_And64,
13781 binop(Iop_Perm8x8,mkexpr(dHi),mkexpr(sAnd7lo)),
13782 mkexpr(maskBit3lo)),
13783 binop(Iop_And64,
13784 binop(Iop_Perm8x8,mkexpr(dLo),mkexpr(sAnd7lo)),
13785 unop(Iop_Not64,mkexpr(maskBit3lo))) ));
13786
13787 assign(rLo, binop(Iop_And64,mkexpr(permdLo),mkexpr(mask0x80lo)) );
13788
13789 putXMMReg(
13790 gregOfRexRM(pfx,modrm),
13791 binop(Iop_64HLtoV128, mkexpr(rHi), mkexpr(rLo))
13792 );
13793 goto decode_success;
13794 }
13795
13796 /* ---------------------------------------------------- */
13797 /* --- end of the SSSE3 decoder. --- */
13798 /* ---------------------------------------------------- */
13799
de5a70f5c2010-04-01 23:08:59 +000013800 /* ---------------------------------------------------- */
13801 /* --- start of the SSE4 decoder --- */
13802 /* ---------------------------------------------------- */
13803
13804 /* 66 0F 3A 0D /r ib = BLENDPD xmm1, xmm2/m128, imm8
13805 Blend Packed Double Precision Floating-Point Values (XMM) */
13806 if ( have66noF2noF3( pfx )
13807 && sz == 2
13808 && insn[0] == 0x0F && insn[1] == 0x3A && insn[2] == 0x0D ) {
13809
13810 Int imm8;
13811 UShort imm8_mask_16;
13812
13813 IRTemp dst_vec = newTemp(Ity_V128);
13814 IRTemp src_vec = newTemp(Ity_V128);
13815 IRTemp imm8_mask = newTemp(Ity_V128);
13816
13817 modrm = insn[3];
13818 assign( dst_vec, getXMMReg( gregOfRexRM(pfx, modrm) ) );
13819
13820 if ( epartIsReg( modrm ) ) {
13821 imm8 = (Int)insn[4];
13822 assign( src_vec, getXMMReg( eregOfRexRM(pfx, modrm) ) );
13823 delta += 3+1+1;
sewardj38523e92010-04-29 08:48:09 +000013824 DIP( "blendpd $%d, %s,%s\n", imm8,
de5a70f5c2010-04-01 23:08:59 +000013825 nameXMMReg( eregOfRexRM(pfx, modrm) ),
sewardj38523e92010-04-29 08:48:09 +000013826 nameXMMReg( gregOfRexRM(pfx, modrm) ) );
de5a70f5c2010-04-01 23:08:59 +000013827 } 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;
sewardj38523e92010-04-29 08:48:09 +000013833 DIP( "blendpd $%d, %s,%s\n",
13834 imm8, dis_buf, nameXMMReg( gregOfRexRM(pfx, modrm) ) );
de5a70f5c2010-04-01 23:08:59 +000013835 }
13836
13837 switch( imm8 & 3 ) {
13838 case 0: imm8_mask_16 = 0x0000; break;
13839 case 1: imm8_mask_16 = 0x00FF; break;
13840 case 2: imm8_mask_16 = 0xFF00; break;
13841 case 3: imm8_mask_16 = 0xFFFF; break;
13842 default: vassert(0); break;
13843 }
13844 assign( imm8_mask, mkV128( imm8_mask_16 ) );
13845
13846 putXMMReg( gregOfRexRM(pfx, modrm),
13847 binop( Iop_OrV128,
deb5afdbd2010-04-02 13:17:50 +000013848 binop( Iop_AndV128, mkexpr(src_vec), mkexpr(imm8_mask) ),
13849 binop( Iop_AndV128, mkexpr(dst_vec),
de5a70f5c2010-04-01 23:08:59 +000013850 unop( Iop_NotV128, mkexpr(imm8_mask) ) ) ) );
13851
13852 goto decode_success;
13853 }
13854
13855
deb5afdbd2010-04-02 13:17:50 +000013856 /* 66 0F 3A 0C /r ib = BLENDPS xmm1, xmm2/m128, imm8
13857 Blend Packed Single Precision Floating-Point Values (XMM) */
13858 if ( have66noF2noF3( pfx )
13859 && sz == 2
13860 && insn[0] == 0x0F && insn[1] == 0x3A && insn[2] == 0x0C ) {
13861
13862 Int imm8;
13863 IRTemp dst_vec = newTemp(Ity_V128);
13864 IRTemp src_vec = newTemp(Ity_V128);
13865
13866 modrm = insn[3];
13867
13868 assign( dst_vec, getXMMReg( gregOfRexRM(pfx, modrm) ) );
13869
13870 if ( epartIsReg( modrm ) ) {
sewardje76895d2010-04-29 08:46:38 +000013871 imm8 = (Int)insn[3+1];
deb5afdbd2010-04-02 13:17:50 +000013872 assign( src_vec, getXMMReg( eregOfRexRM(pfx, modrm) ) );
13873 delta += 3+1+1;
sewardj38523e92010-04-29 08:48:09 +000013874 DIP( "blendps $%d, %s,%s\n", imm8,
deb5afdbd2010-04-02 13:17:50 +000013875 nameXMMReg( eregOfRexRM(pfx, modrm) ),
sewardj38523e92010-04-29 08:48:09 +000013876 nameXMMReg( gregOfRexRM(pfx, modrm) ) );
deb5afdbd2010-04-02 13:17:50 +000013877 } else {
13878 addr = disAMode( &alen, vbi, pfx, delta+3, dis_buf,
13879 1/* imm8 is 1 byte after the amode */ );
13880 assign( src_vec, loadLE( Ity_V128, mkexpr(addr) ) );
sewardje76895d2010-04-29 08:46:38 +000013881 imm8 = (Int)insn[3+alen];
deb5afdbd2010-04-02 13:17:50 +000013882 delta += 3+alen+1;
sewardj38523e92010-04-29 08:48:09 +000013883 DIP( "blendpd $%d, %s,%s\n",
13884 imm8, dis_buf, nameXMMReg( gregOfRexRM(pfx, modrm) ) );
deb5afdbd2010-04-02 13:17:50 +000013885 }
13886
13887 UShort imm8_perms[16] = { 0x0000, 0x000F, 0x00F0, 0x00FF, 0x0F00, 0x0F0F,
13888 0x0FF0, 0x0FFF, 0xF000, 0xF00F, 0xF0F0, 0xF0FF,
13889 0xFF00, 0xFF0F, 0xFFF0, 0xFFFF };
13890 IRTemp imm8_mask = newTemp(Ity_V128);
13891 assign( imm8_mask, mkV128( imm8_perms[ (imm8 & 15) ] ) );
13892
13893 putXMMReg( gregOfRexRM(pfx, modrm),
13894 binop( Iop_OrV128,
13895 binop( Iop_AndV128, mkexpr(src_vec), mkexpr(imm8_mask) ),
13896 binop( Iop_AndV128, mkexpr(dst_vec),
13897 unop( Iop_NotV128, mkexpr(imm8_mask) ) ) ) );
13898
13899 goto decode_success;
13900 }
13901
13902
sewardja1c1d9a2010-04-29 08:39:18 +000013903 /* 66 0F 3A 41 /r ib = DPPD xmm1, xmm2/m128, imm8
13904 Dot Product of Packed Double Precision Floating-Point Values (XMM) */
13905 if ( have66noF2noF3( pfx )
13906 && sz == 2
13907 && insn[0] == 0x0F && insn[1] == 0x3A && insn[2] == 0x41 ) {
13908
13909 Int imm8;
13910 IRTemp src_vec = newTemp(Ity_V128);
13911 IRTemp dst_vec = newTemp(Ity_V128);
13912 IRTemp and_vec = newTemp(Ity_V128);
13913 IRTemp sum_vec = newTemp(Ity_V128);
13914
13915 modrm = insn[3];
13916
13917 assign( dst_vec, getXMMReg( gregOfRexRM(pfx, modrm) ) );
13918
13919 if ( epartIsReg( modrm ) ) {
13920 imm8 = (Int)insn[4];
13921 assign( src_vec, getXMMReg( eregOfRexRM(pfx, modrm) ) );
13922 delta += 3+1+1;
sewardj38523e92010-04-29 08:48:09 +000013923 DIP( "dppd $%d, %s,%s\n", imm8,
sewardja1c1d9a2010-04-29 08:39:18 +000013924 nameXMMReg( eregOfRexRM(pfx, modrm) ),
sewardj38523e92010-04-29 08:48:09 +000013925 nameXMMReg( gregOfRexRM(pfx, modrm) ) );
sewardja1c1d9a2010-04-29 08:39:18 +000013926 } else {
13927 addr = disAMode( &alen, vbi, pfx, delta+3, dis_buf,
13928 1/* imm8 is 1 byte after the amode */ );
13929 assign( src_vec, loadLE( Ity_V128, mkexpr(addr) ) );
13930 imm8 = (Int)insn[2+alen+1];
13931 delta += 3+alen+1;
sewardj38523e92010-04-29 08:48:09 +000013932 DIP( "dppd $%d, %s,%s\n",
13933 imm8, dis_buf, nameXMMReg( gregOfRexRM(pfx, modrm) ) );
sewardja1c1d9a2010-04-29 08:39:18 +000013934 }
13935
13936 UShort imm8_perms[4] = { 0x0000, 0x00FF, 0xFF00, 0xFFFF };
13937
13938 assign( and_vec, binop( Iop_AndV128,
13939 binop( Iop_Mul64Fx2,
13940 mkexpr(dst_vec), mkexpr(src_vec) ),
13941 mkV128( imm8_perms[ ((imm8 >> 4) & 3) ] ) ) );
13942
13943 assign( sum_vec, binop( Iop_Add64F0x2,
13944 binop( Iop_InterleaveHI64x2,
13945 mkexpr(and_vec), mkexpr(and_vec) ),
13946 binop( Iop_InterleaveLO64x2,
13947 mkexpr(and_vec), mkexpr(and_vec) ) ) );
13948
13949 putXMMReg( gregOfRexRM( pfx, modrm ),
13950 binop( Iop_AndV128,
13951 binop( Iop_InterleaveLO64x2,
13952 mkexpr(sum_vec), mkexpr(sum_vec) ),
13953 mkV128( imm8_perms[ (imm8 & 3) ] ) ) );
13954
13955 goto decode_success;
13956 }
13957
13958
13959 /* 66 0F 3A 40 /r ib = DPPS xmm1, xmm2/m128, imm8
13960 Dot Product of Packed Single Precision Floating-Point Values (XMM) */
13961 if ( have66noF2noF3( pfx )
13962 && sz == 2
13963 && insn[0] == 0x0F
13964 && insn[1] == 0x3A
13965 && insn[2] == 0x40 ) {
13966
13967 Int imm8;
13968 IRTemp xmm1_vec = newTemp(Ity_V128);
13969 IRTemp xmm2_vec = newTemp(Ity_V128);
13970 IRTemp tmp_prod_vec = newTemp(Ity_V128);
13971 IRTemp prod_vec = newTemp(Ity_V128);
13972 IRTemp sum_vec = newTemp(Ity_V128);
13973 IRTemp v3, v2, v1, v0;
13974 v3 = v2 = v1 = v0 = IRTemp_INVALID;
13975
13976 modrm = insn[3];
13977
13978 assign( xmm1_vec, getXMMReg( gregOfRexRM(pfx, modrm) ) );
13979
13980 if ( epartIsReg( modrm ) ) {
13981 imm8 = (Int)insn[4];
13982 assign( xmm2_vec, getXMMReg( eregOfRexRM(pfx, modrm) ) );
13983 delta += 3+1+1;
sewardj38523e92010-04-29 08:48:09 +000013984 DIP( "dpps $%d, %s,%s\n", imm8,
sewardja1c1d9a2010-04-29 08:39:18 +000013985 nameXMMReg( eregOfRexRM(pfx, modrm) ),
sewardj38523e92010-04-29 08:48:09 +000013986 nameXMMReg( gregOfRexRM(pfx, modrm) ) );
sewardja1c1d9a2010-04-29 08:39:18 +000013987 } else {
13988 addr = disAMode( &alen, vbi, pfx, delta+3, dis_buf,
13989 1/* imm8 is 1 byte after the amode */ );
13990 assign( xmm2_vec, loadLE( Ity_V128, mkexpr(addr) ) );
13991 imm8 = (Int)insn[2+alen+1];
13992 delta += 3+alen+1;
sewardj38523e92010-04-29 08:48:09 +000013993 DIP( "dpps $%d, %s,%s\n",
13994 imm8, dis_buf, nameXMMReg( gregOfRexRM(pfx, modrm) ) );
sewardja1c1d9a2010-04-29 08:39:18 +000013995 }
13996
13997 UShort imm8_perms[16] = { 0x0000, 0x000F, 0x00F0, 0x00FF, 0x0F00,
13998 0x0F0F, 0x0FF0, 0x0FFF, 0xF000, 0xF00F,
13999 0xF0F0, 0xF0FF, 0xFF00, 0xFF0F, 0xFFF0, 0xFFFF };
14000
14001 assign( tmp_prod_vec,
14002 binop( Iop_AndV128,
14003 binop( Iop_Mul32Fx4, mkexpr(xmm1_vec), mkexpr(xmm2_vec) ),
14004 mkV128( imm8_perms[((imm8 >> 4)& 15)] ) ) );
14005 breakup128to32s( tmp_prod_vec, &v3, &v2, &v1, &v0 );
14006 assign( prod_vec, mk128from32s( v3, v1, v2, v0 ) );
14007
14008 assign( sum_vec, binop( Iop_Add32Fx4,
14009 binop( Iop_InterleaveHI32x4,
14010 mkexpr(prod_vec), mkexpr(prod_vec) ),
14011 binop( Iop_InterleaveLO32x4,
14012 mkexpr(prod_vec), mkexpr(prod_vec) ) ) );
14013
14014 putXMMReg( gregOfRexRM(pfx, modrm),
14015 binop( Iop_AndV128,
14016 binop( Iop_Add32Fx4,
14017 binop( Iop_InterleaveHI32x4,
14018 mkexpr(sum_vec), mkexpr(sum_vec) ),
14019 binop( Iop_InterleaveLO32x4,
14020 mkexpr(sum_vec), mkexpr(sum_vec) ) ),
14021 mkV128( imm8_perms[ (imm8 & 15) ] ) ) );
14022
14023 goto decode_success;
14024 }
14025
14026
de5a70f5c2010-04-01 23:08:59 +000014027 /* 66 0F 3A 21 /r ib = INSERTPS xmm1, xmm2/m32, imm8
14028 Insert Packed Single Precision Floating-Point Value (XMM) */
14029 if ( have66noF2noF3( pfx )
14030 && sz == 2
14031 && insn[0] == 0x0F && insn[1] == 0x3A && insn[2] == 0x21 ) {
14032
14033 Int imm8;
14034 Int imm8_count_s;
14035 Int imm8_count_d;
14036 Int imm8_zmask;
14037 IRTemp dstVec = newTemp(Ity_V128);
14038 IRTemp srcDWord = newTemp(Ity_I32);
14039
14040 modrm = insn[3];
14041
14042 assign( dstVec, getXMMReg( gregOfRexRM(pfx, modrm) ) );
14043
14044 if ( epartIsReg( modrm ) ) {
14045 IRTemp src_vec = newTemp(Ity_V128);
14046 assign( src_vec, getXMMReg( eregOfRexRM(pfx, modrm) ) );
14047
14048 IRTemp src_lane_0 = IRTemp_INVALID;
14049 IRTemp src_lane_1 = IRTemp_INVALID;
14050 IRTemp src_lane_2 = IRTemp_INVALID;
14051 IRTemp src_lane_3 = IRTemp_INVALID;
14052 breakup128to32s( src_vec,
14053 &src_lane_3, &src_lane_2, &src_lane_1, &src_lane_0 );
14054
14055 imm8 = (Int)insn[4];
14056 imm8_count_s = ((imm8 >> 6) & 3);
14057 switch( imm8_count_s ) {
14058 case 0: assign( srcDWord, mkexpr(src_lane_0) ); break;
14059 case 1: assign( srcDWord, mkexpr(src_lane_1) ); break;
14060 case 2: assign( srcDWord, mkexpr(src_lane_2) ); break;
14061 case 3: assign( srcDWord, mkexpr(src_lane_3) ); break;
14062 default: vassert(0); break;
14063 }
14064
14065 delta += 3+1+1;
sewardj38523e92010-04-29 08:48:09 +000014066 DIP( "insertps $%d, %s,%s\n", imm8,
de5a70f5c2010-04-01 23:08:59 +000014067 nameXMMReg( eregOfRexRM(pfx, modrm) ),
sewardj38523e92010-04-29 08:48:09 +000014068 nameXMMReg( gregOfRexRM(pfx, modrm) ) );
de5a70f5c2010-04-01 23:08:59 +000014069 } else {
14070 addr = disAMode( &alen, vbi, pfx, delta+3, dis_buf,
14071 1/* const imm8 is 1 byte after the amode */ );
14072 assign( srcDWord, loadLE( Ity_I32, mkexpr(addr) ) );
14073 imm8 = (Int)insn[2+alen+1];
14074 imm8_count_s = 0;
14075 delta += 3+alen+1;
sewardj38523e92010-04-29 08:48:09 +000014076 DIP( "insertps $%d, %s,%s\n",
14077 imm8, dis_buf, nameXMMReg( gregOfRexRM(pfx, modrm) ) );
de5a70f5c2010-04-01 23:08:59 +000014078 }
14079
14080 IRTemp dst_lane_0 = IRTemp_INVALID;
14081 IRTemp dst_lane_1 = IRTemp_INVALID;
14082 IRTemp dst_lane_2 = IRTemp_INVALID;
14083 IRTemp dst_lane_3 = IRTemp_INVALID;
14084 breakup128to32s( dstVec,
14085 &dst_lane_3, &dst_lane_2, &dst_lane_1, &dst_lane_0 );
14086
14087 imm8_count_d = ((imm8 >> 4) & 3);
14088 switch( imm8_count_d ) {
14089 case 0: dst_lane_0 = srcDWord; break;
14090 case 1: dst_lane_1 = srcDWord; break;
14091 case 2: dst_lane_2 = srcDWord; break;
14092 case 3: dst_lane_3 = srcDWord; break;
14093 default: vassert(0); break;
14094 }
14095
14096 imm8_zmask = (imm8 & 15);
14097 IRTemp zero_32 = newTemp(Ity_I32);
14098 assign( zero_32, mkU32(0) );
14099
14100 IRExpr* ire_vec_128 = mk128from32s(
14101 ((imm8_zmask & 8) == 8) ? zero_32 : dst_lane_3,
14102 ((imm8_zmask & 4) == 4) ? zero_32 : dst_lane_2,
14103 ((imm8_zmask & 2) == 2) ? zero_32 : dst_lane_1,
14104 ((imm8_zmask & 1) == 1) ? zero_32 : dst_lane_0 );
14105
14106 putXMMReg( gregOfRexRM(pfx, modrm), ire_vec_128 );
14107
14108 goto decode_success;
14109 }
14110
de5a70f5c2010-04-01 23:08:59 +000014111
sewardje76895d2010-04-29 08:46:38 +000014112 /* 66 0F 3A 14 /r ib = PEXTRB r/m16, xmm, imm8
14113 Extract Byte from xmm, store in mem or zero-extend + store in gen.reg. (XMM) */
14114 if ( have66noF2noF3( pfx )
14115 && sz == 2
14116 && insn[0] == 0x0F && insn[1] == 0x3A && insn[2] == 0x14 ) {
14117
14118 Int imm8;
14119 IRTemp xmm_vec = newTemp(Ity_V128);
14120 IRTemp sel_lane = newTemp(Ity_I32);
14121 IRTemp shr_lane = newTemp(Ity_I32);
14122
14123 modrm = insn[3];
14124 assign( xmm_vec, getXMMReg( gregOfRexRM(pfx,modrm) ) );
14125 breakup128to32s( xmm_vec, &t3, &t2, &t1, &t0 );
14126
14127 if ( epartIsReg( modrm ) ) {
14128 imm8 = (Int)insn[3+1];
14129 } else {
14130 addr = disAMode( &alen, vbi, pfx, delta+3, dis_buf, 1 );
14131 imm8 = (Int)insn[3+alen];
14132 }
14133 switch( (imm8 >> 2) & 3 ) {
14134 case 0: assign( sel_lane, mkexpr(t0) ); break;
14135 case 1: assign( sel_lane, mkexpr(t1) ); break;
14136 case 2: assign( sel_lane, mkexpr(t2) ); break;
14137 case 3: assign( sel_lane, mkexpr(t3) ); break;
14138 default: vassert(0);
14139 }
14140 assign( shr_lane,
14141 binop( Iop_Shr32, mkexpr(sel_lane), mkU8(((imm8 & 3)*8)) ) );
14142
14143 if ( epartIsReg( modrm ) ) {
14144 putIReg64( eregOfRexRM(pfx,modrm),
14145 unop( Iop_32Uto64,
14146 binop(Iop_And32, mkexpr(shr_lane), mkU32(255)) ) );
14147
14148 delta += 3+1+1;
sewardj38523e92010-04-29 08:48:09 +000014149 DIP( "pextrb $%d, %s,%s\n", imm8,
14150 nameXMMReg( gregOfRexRM(pfx, modrm) ),
14151 nameIReg64( eregOfRexRM(pfx, modrm) ) );
sewardje76895d2010-04-29 08:46:38 +000014152 } else {
14153 storeLE( mkexpr(addr), unop(Iop_32to8, mkexpr(shr_lane) ) );
14154 delta += 3+alen+1;
sewardj38523e92010-04-29 08:48:09 +000014155 DIP( "$%d, pextrb %s,%s\n",
14156 imm8, nameXMMReg( gregOfRexRM(pfx, modrm) ), dis_buf );
sewardje76895d2010-04-29 08:46:38 +000014157 }
14158
14159 goto decode_success;
14160 }
14161
14162
14163 /* 66 0F 3A 16 /r ib = PEXTRD reg/mem32, xmm2, imm8
14164 Extract Doubleword int from xmm reg and store in gen.reg or mem. (XMM)
14165 Note that this insn has the same opcodes as PEXTRQ, but
14166 here the REX.W bit is _not_ present */
14167 if ( have66noF2noF3( pfx )
14168 && sz == 2 /* REX.W is _not_ present */
14169 && insn[0] == 0x0F && insn[1] == 0x3A && insn[2] == 0x16 ) {
14170
14171 Int imm8_10;
14172 IRTemp xmm_vec = newTemp(Ity_V128);
14173 IRTemp src_dword = newTemp(Ity_I32);
14174
14175 modrm = insn[3];
14176 assign( xmm_vec, getXMMReg( gregOfRexRM(pfx,modrm) ) );
14177 breakup128to32s( xmm_vec, &t3, &t2, &t1, &t0 );
14178
14179 if ( epartIsReg( modrm ) ) {
14180 imm8_10 = (Int)(insn[3+1] & 3);
14181 } else {
14182 addr = disAMode( &alen, vbi, pfx, delta+3, dis_buf, 1 );
14183 imm8_10 = (Int)(insn[3+alen] & 3);
14184 }
14185
14186 switch ( imm8_10 ) {
14187 case 0: assign( src_dword, mkexpr(t0) ); break;
14188 case 1: assign( src_dword, mkexpr(t1) ); break;
14189 case 2: assign( src_dword, mkexpr(t2) ); break;
14190 case 3: assign( src_dword, mkexpr(t3) ); break;
14191 default: vassert(0);
14192 }
14193
14194 if ( epartIsReg( modrm ) ) {
14195 putIReg32( eregOfRexRM(pfx,modrm), mkexpr(src_dword) );
14196 delta += 3+1+1;
sewardj38523e92010-04-29 08:48:09 +000014197 DIP( "pextrd $%d, %s,%s\n", imm8_10,
sewardje76895d2010-04-29 08:46:38 +000014198 nameXMMReg( gregOfRexRM(pfx, modrm) ),
sewardj38523e92010-04-29 08:48:09 +000014199 nameIReg32( eregOfRexRM(pfx, modrm) ) );
sewardje76895d2010-04-29 08:46:38 +000014200 } else {
14201 storeLE( mkexpr(addr), mkexpr(src_dword) );
14202 delta += 3+alen+1;
sewardj38523e92010-04-29 08:48:09 +000014203 DIP( "pextrd $%d, %s,%s\n",
14204 imm8_10, nameXMMReg( gregOfRexRM(pfx, modrm) ), dis_buf );
sewardje76895d2010-04-29 08:46:38 +000014205 }
14206
14207 goto decode_success;
14208 }
14209
14210
14211 /* 66 REX.W 0F 3A 16 /r ib = PEXTRQ reg/mem64, xmm2, imm8
14212 Extract Quadword int from xmm reg and store in gen.reg or mem. (XMM)
14213 Note that this insn has the same opcodes as PEXTRD, but
14214 here the REX.W bit is present */
14215 if ( have66noF2noF3( pfx )
14216 && sz == 8 /* REX.W is present */
14217 && insn[0] == 0x0F && insn[1] == 0x3A && insn[2] == 0x16 ) {
14218
14219 Int imm8_0;
14220 IRTemp xmm_vec = newTemp(Ity_V128);
14221 IRTemp src_qword = newTemp(Ity_I64);
14222
14223 modrm = insn[3];
14224 assign( xmm_vec, getXMMReg( gregOfRexRM(pfx,modrm) ) );
14225
14226 if ( epartIsReg( modrm ) ) {
14227 imm8_0 = (Int)(insn[3+1] & 1);
14228 } else {
14229 addr = disAMode( &alen, vbi, pfx, delta+3, dis_buf, 1 );
14230 imm8_0 = (Int)(insn[3+alen] & 1);
14231 }
14232 switch ( imm8_0 ) {
14233 case 0: assign( src_qword, unop(Iop_V128to64, mkexpr(xmm_vec)) ); break;
14234 case 1: assign( src_qword, unop(Iop_V128HIto64, mkexpr(xmm_vec)) ); break;
14235 default: vassert(0);
14236 }
14237
14238 if ( epartIsReg( modrm ) ) {
14239 putIReg64( eregOfRexRM(pfx,modrm), mkexpr(src_qword) );
14240 delta += 3+1+1;
sewardj38523e92010-04-29 08:48:09 +000014241 DIP( "pextrq $%d, %s,%s\n", imm8_0,
sewardje76895d2010-04-29 08:46:38 +000014242 nameXMMReg( gregOfRexRM(pfx, modrm) ),
sewardj38523e92010-04-29 08:48:09 +000014243 nameIReg64( eregOfRexRM(pfx, modrm) ) );
sewardje76895d2010-04-29 08:46:38 +000014244 } else {
14245 storeLE( mkexpr(addr), mkexpr(src_qword) );
14246 delta += 3+alen+1;
sewardj38523e92010-04-29 08:48:09 +000014247 DIP( "pextrq $%d, %s,%s\n",
14248 imm8_0, nameXMMReg( gregOfRexRM(pfx, modrm) ), dis_buf );
sewardje76895d2010-04-29 08:46:38 +000014249 }
14250
14251 goto decode_success;
14252 }
14253
14254
14255 /* 66 0F 3A 15 /r ib = PEXTRW r/m16, xmm, imm8
14256 Extract Word from xmm, store in mem or zero-extend + store in gen.reg. (XMM) */
14257 if ( have66noF2noF3( pfx )
14258 && sz == 2
14259 && insn[0] == 0x0F && insn[1] == 0x3A && insn[2] == 0x15 ) {
14260
14261 Int imm8_20;
14262 IRTemp xmm_vec = newTemp(Ity_V128);
14263 IRTemp src_word = newTemp(Ity_I16);
14264
14265 modrm = insn[3];
14266 assign( xmm_vec, getXMMReg( gregOfRexRM(pfx,modrm) ) );
14267 breakup128to32s( xmm_vec, &t3, &t2, &t1, &t0 );
14268
14269 if ( epartIsReg( modrm ) ) {
14270 imm8_20 = (Int)(insn[3+1] & 7);
14271 } else {
14272 addr = disAMode( &alen, vbi, pfx, delta+3, dis_buf, 1 );
14273 imm8_20 = (Int)(insn[3+alen] & 7);
14274 }
14275
14276 switch ( imm8_20 ) {
14277 case 0: assign( src_word, unop(Iop_32to16, mkexpr(t0)) ); break;
14278 case 1: assign( src_word, unop(Iop_32HIto16, mkexpr(t0)) ); break;
14279 case 2: assign( src_word, unop(Iop_32to16, mkexpr(t1)) ); break;
14280 case 3: assign( src_word, unop(Iop_32HIto16, mkexpr(t1)) ); break;
14281 case 4: assign( src_word, unop(Iop_32to16, mkexpr(t2)) ); break;
14282 case 5: assign( src_word, unop(Iop_32HIto16, mkexpr(t2)) ); break;
14283 case 6: assign( src_word, unop(Iop_32to16, mkexpr(t3)) ); break;
14284 case 7: assign( src_word, unop(Iop_32HIto16, mkexpr(t3)) ); break;
14285 default: vassert(0);
14286 }
14287
14288 if ( epartIsReg( modrm ) ) {
14289 putIReg64( eregOfRexRM(pfx,modrm), unop(Iop_16Uto64, mkexpr(src_word)) );
14290 delta += 3+1+1;
sewardj38523e92010-04-29 08:48:09 +000014291 DIP( "pextrw $%d, %s,%s\n", imm8_20,
sewardje76895d2010-04-29 08:46:38 +000014292 nameXMMReg( gregOfRexRM(pfx, modrm) ),
sewardj38523e92010-04-29 08:48:09 +000014293 nameIReg64( eregOfRexRM(pfx, modrm) ) );
sewardje76895d2010-04-29 08:46:38 +000014294 } else {
14295 storeLE( mkexpr(addr), mkexpr(src_word) );
14296 delta += 3+alen+1;
sewardj38523e92010-04-29 08:48:09 +000014297 DIP( "pextrw $%d, %s,%s\n",
14298 imm8_20, nameXMMReg( gregOfRexRM(pfx, modrm) ), dis_buf );
sewardje76895d2010-04-29 08:46:38 +000014299 }
14300
14301 goto decode_success;
14302 }
14303
14304
sewardje53a5e02010-04-29 08:50:09 +000014305 /* 66 REX.W 0F 3A 22 /r ib = PINSRQ xmm1, r/m64, imm8
14306 Extract Quadword int from gen.reg/mem64 and insert into xmm1 */
14307 if ( have66noF2noF3( pfx )
14308 && sz == 8 /* REX.W is present */
14309 && insn[0] == 0x0F && insn[1] == 0x3A && insn[2] == 0x22 ) {
14310
14311 Int imm8_0;
14312 IRTemp src_elems = newTemp(Ity_I64);
14313 IRTemp src_vec = newTemp(Ity_V128);
14314
14315 modrm = insn[3];
14316
14317 if ( epartIsReg( modrm ) ) {
14318 imm8_0 = (Int)(insn[3+1] & 1);
14319 assign( src_elems, getIReg64( eregOfRexRM(pfx,modrm) ) );
14320 delta += 3+1+1;
14321 DIP( "pinsrq $%d, %s,%s\n", imm8_0,
14322 nameIReg64( eregOfRexRM(pfx, modrm) ),
14323 nameXMMReg( gregOfRexRM(pfx, modrm) ) );
14324 } else {
14325 addr = disAMode( &alen, vbi, pfx, delta+3, dis_buf, 1 );
14326 imm8_0 = (Int)(insn[3+alen] & 1);
14327 assign( src_elems, loadLE( Ity_I64, mkexpr(addr) ) );
14328 delta += 3+alen+1;
14329 DIP( "pinsrq $%d, %s,%s\n",
14330 imm8_0, dis_buf, nameXMMReg( gregOfRexRM(pfx, modrm) ) );
14331 }
14332
14333 UShort mask = 0;
14334 if ( imm8_0 == 0 ) {
14335 mask = 0xFF00;
14336 assign( src_vec, binop( Iop_64HLtoV128, mkU64(0), mkexpr(src_elems) ) );
14337 } else {
14338 mask = 0x00FF;
14339 assign( src_vec, binop( Iop_64HLtoV128, mkexpr(src_elems), mkU64(0) ) );
14340 }
14341
14342 putXMMReg( gregOfRexRM(pfx, modrm),
14343 binop( Iop_OrV128, mkexpr(src_vec),
14344 binop( Iop_AndV128,
14345 getXMMReg( gregOfRexRM(pfx, modrm) ),
14346 mkV128(mask) ) ) );
14347
14348 goto decode_success;
14349 }
14350
14351
sewardjfd181282010-06-14 21:29:35 +000014352 /* 66 no-REX.W 0F 3A 22 /r ib = PINSRD xmm1, r/m32, imm8
14353 Extract Doubleword int from gen.reg/mem32 and insert into xmm1 */
14354 if ( have66noF2noF3( pfx )
14355 && sz == 2 /* REX.W is NOT present */
14356 && insn[0] == 0x0F && insn[1] == 0x3A && insn[2] == 0x22 ) {
14357
14358 Int imm8_10;
14359 IRTemp src_elems = newTemp(Ity_I32);
14360 IRTemp src_vec = newTemp(Ity_V128);
14361 IRTemp z32 = newTemp(Ity_I32);
14362
14363 modrm = insn[3];
14364
14365 if ( epartIsReg( modrm ) ) {
14366 imm8_10 = (Int)(insn[3+1] & 3);
14367 assign( src_elems, getIReg32( eregOfRexRM(pfx,modrm) ) );
14368 delta += 3+1+1;
14369 DIP( "pinsrd $%d, %s,%s\n", imm8_10,
14370 nameIReg32( eregOfRexRM(pfx, modrm) ),
14371 nameXMMReg( gregOfRexRM(pfx, modrm) ) );
14372 } else {
14373 addr = disAMode( &alen, vbi, pfx, delta+3, dis_buf, 1 );
14374 imm8_10 = (Int)(insn[3+alen] & 3);
14375 assign( src_elems, loadLE( Ity_I32, mkexpr(addr) ) );
14376 delta += 3+alen+1;
14377 DIP( "pinsrd $%d, %s,%s\n",
14378 imm8_10, dis_buf, nameXMMReg( gregOfRexRM(pfx, modrm) ) );
14379 }
14380
14381 assign(z32, mkU32(0));
14382
14383 UShort mask = 0;
14384 switch (imm8_10) {
14385 case 3: mask = 0x0FFF;
14386 assign(src_vec, mk128from32s(src_elems, z32, z32, z32));
14387 break;
14388 case 2: mask = 0xF0FF;
14389 assign(src_vec, mk128from32s(z32, src_elems, z32, z32));
14390 break;
14391 case 1: mask = 0xFF0F;
14392 assign(src_vec, mk128from32s(z32, z32, src_elems, z32));
14393 break;
14394 case 0: mask = 0xFFF0;
14395 assign(src_vec, mk128from32s(z32, z32, z32, src_elems));
14396 break;
14397 default: vassert(0);
14398 }
14399
14400 putXMMReg( gregOfRexRM(pfx, modrm),
14401 binop( Iop_OrV128, mkexpr(src_vec),
14402 binop( Iop_AndV128,
14403 getXMMReg( gregOfRexRM(pfx, modrm) ),
14404 mkV128(mask) ) ) );
14405
14406 goto decode_success;
14407 }
14408
14409
sewardj733d5892010-04-29 08:42:37 +000014410 /* 66 0F 38 3D /r = PMAXSD xmm1, xmm2/m128
14411 Maximum of Packed Signed Double Word Integers (XMM)
14412 --
14413 66 0F 38 39 /r = PMINSD xmm1, xmm2/m128
14414 Minimum of Packed Signed Double Word Integers (XMM) */
14415 if ( have66noF2noF3( pfx )
14416 && sz == 2
14417 && insn[0] == 0x0F && insn[1] == 0x38
14418 && ( (insn[2] == 0x3D) || (insn[2] == 0x39) ) ) {
14419
14420 IRTemp reg_vec = newTemp(Ity_V128);
14421 IRTemp rom_vec = newTemp(Ity_V128);
14422 IRTemp mask_vec = newTemp(Ity_V128);
14423
14424 Bool isPMAX = (insn[2] == 0x3D) ? True : False;
14425
14426 HChar* str = isPMAX ? "pmaxsd" : "pminsd";
14427
14428 modrm = insn[3];
14429 assign( reg_vec, getXMMReg( gregOfRexRM(pfx, modrm) ) );
14430
14431 if ( epartIsReg( modrm ) ) {
14432 assign( rom_vec, getXMMReg( eregOfRexRM(pfx, modrm) ) );
14433 delta += 3+1;
14434 DIP( "%s %s,%s\n", str,
14435 nameXMMReg( eregOfRexRM(pfx, modrm) ),
14436 nameXMMReg( gregOfRexRM(pfx, modrm) ) );
14437 } else {
14438 addr = disAMode( &alen, vbi, pfx, delta+3, dis_buf, 0 );
14439 assign( rom_vec, loadLE( Ity_V128, mkexpr(addr) ) );
14440 delta += 3+alen;
14441 DIP( "%s %s,%s\n", str, dis_buf, nameXMMReg( gregOfRexRM(pfx, modrm) ) );
14442 }
14443
14444 assign( mask_vec, binop( Iop_CmpGT32Sx4, mkexpr(reg_vec), mkexpr(rom_vec) ) );
14445
14446 IRTemp max_min_vec = newTemp(Ity_V128);
14447 if ( isPMAX ) {
14448 assign( max_min_vec,
14449 binop( Iop_OrV128,
14450 binop( Iop_AndV128, mkexpr(rom_vec),
sewardj733d5892010-04-29 08:42:37 +000014451 unop( Iop_NotV128, mkexpr(mask_vec) ) ),
14452 binop( Iop_AndV128, mkexpr(reg_vec), mkexpr(mask_vec) ) ) );
14453 } else {
14454 assign( max_min_vec,
14455 binop( Iop_OrV128,
14456 binop( Iop_AndV128, mkexpr(reg_vec),
14457 unop( Iop_NotV128, mkexpr(mask_vec) ) ),
14458 binop( Iop_AndV128, mkexpr(rom_vec), mkexpr(mask_vec) ) ) );
14459 }
14460
14461 putXMMReg( gregOfRexRM(pfx, modrm), mkexpr(max_min_vec) );
14462
14463 goto decode_success;
14464 }
14465
14466
sewardj2febc602010-04-29 08:52:00 +000014467 /* 66 0F 38 3F /r = PMAXUD xmm1, xmm2/m128
sewardjfd181282010-06-14 21:29:35 +000014468 Maximum of Packed Unsigned Doubleword Integers (XMM)
14469 66 0F 38 3B /r = PMINUD xmm1, xmm2/m128
14470 Minimum of Packed Unsigned Doubleword Integers (XMM) */
sewardj2febc602010-04-29 08:52:00 +000014471 if ( have66noF2noF3( pfx )
14472 && sz == 2
sewardjfd181282010-06-14 21:29:35 +000014473 && insn[0] == 0x0F && insn[1] == 0x38
14474 && (insn[2] == 0x3F || insn[2] == 0x3B)) {
sewardj2febc602010-04-29 08:52:00 +000014475
sewardjfd181282010-06-14 21:29:35 +000014476 Bool is_max = insn[2] == 0x3F;
sewardj2febc602010-04-29 08:52:00 +000014477 IRTemp reg_vec = newTemp(Ity_V128);
14478 IRTemp rom_vec = newTemp(Ity_V128);
14479 IRTemp mask_vec = newTemp(Ity_V128);
14480 IRTemp and_vec = newTemp(Ity_V128);
14481 IRTemp not_vec = newTemp(Ity_V128);
sewardjfd181282010-06-14 21:29:35 +000014482
sewardj2febc602010-04-29 08:52:00 +000014483 modrm = insn[3];
14484 assign( reg_vec, getXMMReg( gregOfRexRM(pfx, modrm) ) );
14485
14486 if ( epartIsReg( modrm ) ) {
14487 assign( rom_vec, getXMMReg( eregOfRexRM(pfx, modrm) ) );
14488 delta += 3+1;
sewardjfd181282010-06-14 21:29:35 +000014489 DIP( "p%sud %s,%s\n",
14490 is_max ? "max" : "min",
sewardj2febc602010-04-29 08:52:00 +000014491 nameXMMReg( eregOfRexRM(pfx, modrm) ),
14492 nameXMMReg( gregOfRexRM(pfx, modrm) ) );
14493 } else {
14494 addr = disAMode( &alen, vbi, pfx, delta+3, dis_buf, 0 );
14495 assign( rom_vec, loadLE( Ity_V128, mkexpr(addr) ) );
14496 delta += 3+alen;
sewardjfd181282010-06-14 21:29:35 +000014497 DIP( "p%sd %s,%s\n",
14498 is_max ? "max" : "min",
14499 dis_buf, nameXMMReg( gregOfRexRM(pfx, modrm) ) );
sewardj2febc602010-04-29 08:52:00 +000014500 }
14501
14502 /* the foll. simulates Iop_CmpGT32Ux4 (not implemented)
14503 c.f. Hacker's Delight, S2-11, p.23 */
14504 assign( mask_vec,
14505 binop( Iop_XorV128,
14506 binop( Iop_XorV128,
14507 binop( Iop_CmpGT32Sx4, mkexpr(reg_vec), mkexpr(rom_vec) ),
14508 binop( Iop_SarN32x4, mkexpr(reg_vec), mkU8(31) ) ),
14509 binop( Iop_SarN32x4, mkexpr(rom_vec), mkU8(31) ) ) );
14510
sewardjfd181282010-06-14 21:29:35 +000014511 assign( and_vec,
14512 binop( Iop_AndV128, mkexpr(is_max ? reg_vec : rom_vec),
14513 mkexpr(mask_vec) ) );
14514 assign( not_vec,
14515 binop( Iop_AndV128, mkexpr(is_max ? rom_vec : reg_vec),
14516 unop( Iop_NotV128, mkexpr(mask_vec) ) ) );
sewardj2febc602010-04-29 08:52:00 +000014517
14518 putXMMReg( gregOfRexRM(pfx, modrm),
14519 binop( Iop_OrV128, mkexpr(not_vec), mkexpr(and_vec) ) );
14520
14521 goto decode_success;
14522 }
14523
14524
deb5afdbd2010-04-02 13:17:50 +000014525 /* 66 0f 38 20 /r = PMOVSXBW xmm1, xmm2/m64
14526 Packed Move with Sign Extend from Byte to Word (XMM) */
de5a70f5c2010-04-01 23:08:59 +000014527 if ( have66noF2noF3( pfx )
14528 && sz == 2
14529 && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x20 ) {
14530
14531 modrm = insn[3];
14532
14533 IRTemp srcVec = newTemp(Ity_V128);
14534
14535 if ( epartIsReg( modrm ) ) {
14536 assign( srcVec, getXMMReg( eregOfRexRM(pfx, modrm) ) );
14537 delta += 3+1;
14538 DIP( "pmovsxbw %s,%s\n",
14539 nameXMMReg( eregOfRexRM(pfx, modrm) ),
14540 nameXMMReg( gregOfRexRM(pfx, modrm) ) );
14541 } else {
14542 addr = disAMode( &alen, vbi, pfx, delta+3, dis_buf, 0 );
14543 assign( srcVec,
14544 unop( Iop_64UtoV128, loadLE( Ity_I64, mkexpr(addr) ) ) );
14545 delta += 3+alen;
14546 DIP( "pmovsxbw %s,%s\n",
14547 dis_buf, nameXMMReg( gregOfRexRM(pfx, modrm) ) );
14548 }
14549
14550 putXMMReg( gregOfRexRM(pfx, modrm),
sewardj7cfc3062010-04-02 11:31:22 +000014551 binop( Iop_SarN16x8,
14552 binop( Iop_ShlN16x8,
de5a70f5c2010-04-01 23:08:59 +000014553 binop( Iop_InterleaveLO8x16,
14554 IRExpr_Const( IRConst_V128(0) ),
14555 mkexpr(srcVec) ),
14556 mkU8(8) ),
14557 mkU8(8) ) );
14558
14559 goto decode_success;
14560 }
de5a70f5c2010-04-01 23:08:59 +000014561
14562
14563 /* 66 0f 38 21 /r = PMOVSXBD xmm1, xmm2/m32
14564 Packed Move with Sign Extend from Byte to DWord (XMM) */
14565 if ( have66noF2noF3( pfx )
14566 && sz == 2
14567 && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x21 ) {
14568
14569 modrm = insn[3];
14570
14571 IRTemp srcVec = newTemp(Ity_V128);
14572
14573 if ( epartIsReg( modrm ) ) {
14574 assign( srcVec, getXMMReg( eregOfRexRM(pfx, modrm) ) );
14575 delta += 3+1;
14576 DIP( "pmovsxbd %s,%s\n",
14577 nameXMMReg( eregOfRexRM(pfx, modrm) ),
14578 nameXMMReg( gregOfRexRM(pfx, modrm) ) );
14579 } else {
14580 addr = disAMode( &alen, vbi, pfx, delta+3, dis_buf, 0 );
14581 assign( srcVec,
14582 unop( Iop_32UtoV128, loadLE( Ity_I32, mkexpr(addr) ) ) );
14583 delta += 3+alen;
14584 DIP( "pmovsxbd %s,%s\n",
14585 dis_buf, nameXMMReg( gregOfRexRM(pfx, modrm) ) );
14586 }
14587
14588 IRTemp zeroVec = newTemp(Ity_V128);
14589 assign( zeroVec, IRExpr_Const( IRConst_V128(0) ) );
14590
14591 putXMMReg( gregOfRexRM(pfx, modrm),
14592 binop( Iop_SarN32x4,
14593 binop( Iop_ShlN32x4,
14594 binop( Iop_InterleaveLO8x16,
14595 mkexpr(zeroVec),
14596 binop( Iop_InterleaveLO8x16,
14597 mkexpr(zeroVec),
14598 mkexpr(srcVec) ) ),
14599 mkU8(24) ), mkU8(24) ) );
14600
14601 goto decode_success;
14602 }
14603
14604
14605 /* 66 0f 38 22 /r = PMOVSXBQ xmm1, xmm2/m16
14606 Packed Move with Sign Extend from Byte to QWord (XMM) */
14607 if ( have66noF2noF3(pfx)
14608 && sz == 2
14609 && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x22 ) {
14610
14611 modrm = insn[3];
14612
14613 IRTemp srcBytes = newTemp(Ity_I16);
14614
14615 if ( epartIsReg(modrm) ) {
14616 assign( srcBytes, getXMMRegLane16( eregOfRexRM(pfx, modrm), 0 ) );
14617 delta += 3+1;
14618 DIP( "pmovsxbq %s,%s\n",
14619 nameXMMReg( eregOfRexRM(pfx, modrm) ),
14620 nameXMMReg( gregOfRexRM(pfx, modrm) ) );
14621 } else {
14622 addr = disAMode( &alen, vbi, pfx, delta+3, dis_buf, 0 );
14623 assign( srcBytes, loadLE( Ity_I16, mkexpr(addr) ) );
14624 delta += 3+alen;
14625 DIP( "pmovsxbq %s,%s\n",
14626 dis_buf, nameXMMReg( gregOfRexRM(pfx, modrm) ) );
14627 }
14628
14629 putXMMReg( gregOfRexRM( pfx, modrm ),
14630 binop( Iop_64HLtoV128,
14631 unop( Iop_8Sto64,
14632 unop( Iop_16HIto8,
14633 mkexpr(srcBytes) ) ),
14634 unop( Iop_8Sto64,
14635 unop( Iop_16to8, mkexpr(srcBytes) ) ) ) );
14636
14637 goto decode_success;
14638 }
14639
14640
14641 /* 66 0f 38 23 /r = PMOVSXWD xmm1, xmm2/m64
14642 Packed Move with Sign Extend from Word to DWord (XMM) */
14643 if ( have66noF2noF3( pfx )
14644 && sz == 2
14645 && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x23 ) {
14646
14647 modrm = insn[3];
14648
14649 IRTemp srcVec = newTemp(Ity_V128);
14650
14651 if ( epartIsReg(modrm) ) {
14652 assign( srcVec, getXMMReg( eregOfRexRM(pfx, modrm) ) );
14653 delta += 3+1;
14654 DIP( "pmovsxwd %s,%s\n",
14655 nameXMMReg( eregOfRexRM(pfx, modrm) ),
14656 nameXMMReg( gregOfRexRM(pfx, modrm) ) );
14657 } else {
14658 addr = disAMode( &alen, vbi, pfx, delta+3, dis_buf, 0 );
14659 assign( srcVec,
14660 unop( Iop_64UtoV128, loadLE( Ity_I64, mkexpr(addr) ) ) );
14661 delta += 3+alen;
14662 DIP( "pmovsxwd %s,%s\n",
14663 dis_buf, nameXMMReg( gregOfRexRM(pfx, modrm) ) );
14664 }
14665
14666 putXMMReg( gregOfRexRM(pfx, modrm),
14667 binop( Iop_SarN32x4,
14668 binop( Iop_ShlN32x4,
14669 binop( Iop_InterleaveLO16x8,
14670 IRExpr_Const( IRConst_V128(0) ),
14671 mkexpr(srcVec) ),
14672 mkU8(16) ),
14673 mkU8(16) ) );
14674
14675 goto decode_success;
14676 }
14677
14678
14679 /* 66 0f 38 24 /r = PMOVSXWQ xmm1, xmm2/m32
14680 Packed Move with Sign Extend from Word to QWord (XMM) */
14681 if ( have66noF2noF3( pfx )
14682 && sz == 2
14683 && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x24 ) {
14684
14685 modrm = insn[3];
14686
14687 IRTemp srcBytes = newTemp(Ity_I32);
14688
14689 if ( epartIsReg( modrm ) ) {
14690 assign( srcBytes, getXMMRegLane32( eregOfRexRM(pfx, modrm), 0 ) );
14691 delta += 3+1;
14692 DIP( "pmovsxwq %s,%s\n",
14693 nameXMMReg( eregOfRexRM(pfx, modrm) ),
14694 nameXMMReg( gregOfRexRM(pfx, modrm) ) );
14695 } else {
14696 addr = disAMode( &alen, vbi, pfx, delta+3, dis_buf, 0 );
14697 assign( srcBytes, loadLE( Ity_I32, mkexpr(addr) ) );
14698 delta += 3+alen;
14699 DIP( "pmovsxwq %s,%s\n",
14700 dis_buf, nameXMMReg( gregOfRexRM(pfx, modrm) ) );
14701 }
14702
14703 putXMMReg( gregOfRexRM( pfx, modrm ),
14704 binop( Iop_64HLtoV128,
14705 unop( Iop_16Sto64,
14706 unop( Iop_32HIto16, mkexpr(srcBytes) ) ),
14707 unop( Iop_16Sto64,
14708 unop( Iop_32to16, mkexpr(srcBytes) ) ) ) );
14709
14710 goto decode_success;
14711 }
14712
14713
14714 /* 66 0f 38 25 /r = PMOVSXDQ xmm1, xmm2/m64
14715 Packed Move with Sign Extend from Double Word to Quad Word (XMM) */
14716 if ( have66noF2noF3( pfx )
14717 && sz == 2
14718 && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x25 ) {
14719
14720 modrm = insn[3];
14721
14722 IRTemp srcBytes = newTemp(Ity_I64);
14723
14724 if ( epartIsReg(modrm) ) {
14725 assign( srcBytes, getXMMRegLane64( eregOfRexRM(pfx, modrm), 0 ) );
14726 delta += 3+1;
14727 DIP( "pmovsxdq %s,%s\n",
14728 nameXMMReg( eregOfRexRM(pfx, modrm) ),
14729 nameXMMReg( gregOfRexRM(pfx, modrm) ) );
14730 } else {
14731 addr = disAMode( &alen, vbi, pfx, delta+3, dis_buf, 0 );
14732 assign( srcBytes, loadLE( Ity_I64, mkexpr(addr) ) );
14733 delta += 3+alen;
14734 DIP( "pmovsxdq %s,%s\n",
14735 dis_buf, nameXMMReg( gregOfRexRM(pfx, modrm) ) );
14736 }
14737
14738 putXMMReg( gregOfRexRM(pfx, modrm),
14739 binop( Iop_64HLtoV128,
14740 unop( Iop_32Sto64,
14741 unop( Iop_64HIto32, mkexpr(srcBytes) ) ),
14742 unop( Iop_32Sto64,
14743 unop( Iop_64to32, mkexpr(srcBytes) ) ) ) );
14744
14745 goto decode_success;
14746 }
14747
14748
14749 /* 66 0f 38 30 /r = PMOVZXBW xmm1, xmm2/m64
14750 Packed Move with Zero Extend from Byte to Word (XMM) */
14751 if ( have66noF2noF3(pfx)
14752 && sz == 2
14753 && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x30 ) {
14754
14755 modrm = insn[3];
14756
14757 IRTemp srcVec = newTemp(Ity_V128);
14758
14759 if ( epartIsReg(modrm) ) {
14760 assign( srcVec, getXMMReg( eregOfRexRM(pfx, modrm) ) );
14761 delta += 3+1;
14762 DIP( "pmovzxbw %s,%s\n",
14763 nameXMMReg( eregOfRexRM(pfx, modrm) ),
14764 nameXMMReg( gregOfRexRM(pfx, modrm) ) );
14765 } else {
14766 addr = disAMode( &alen, vbi, pfx, delta+3, dis_buf, 0 );
14767 assign( srcVec,
14768 unop( Iop_64UtoV128, loadLE( Ity_I64, mkexpr(addr) ) ) );
14769 delta += 3+alen;
14770 DIP( "pmovzxbw %s,%s\n",
14771 dis_buf, nameXMMReg( gregOfRexRM(pfx, modrm) ) );
14772 }
14773
14774 putXMMReg( gregOfRexRM(pfx, modrm),
14775 binop( Iop_InterleaveLO8x16,
14776 IRExpr_Const( IRConst_V128(0) ), mkexpr(srcVec) ) );
14777
14778 goto decode_success;
14779 }
14780
14781
14782 /* 66 0f 38 31 /r = PMOVZXBD xmm1, xmm2/m32
14783 Packed Move with Zero Extend from Byte to DWord (XMM) */
14784 if ( have66noF2noF3( pfx )
14785 && sz == 2
14786 && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x31 ) {
14787
14788 modrm = insn[3];
14789
14790 IRTemp srcVec = newTemp(Ity_V128);
14791
14792 if ( epartIsReg(modrm) ) {
14793 assign( srcVec, getXMMReg( eregOfRexRM(pfx, modrm) ) );
14794 delta += 3+1;
14795 DIP( "pmovzxbd %s,%s\n",
14796 nameXMMReg( eregOfRexRM(pfx, modrm) ),
14797 nameXMMReg( gregOfRexRM(pfx, modrm) ) );
14798 } else {
14799 addr = disAMode( &alen, vbi, pfx, delta+3, dis_buf, 0 );
14800 assign( srcVec,
14801 unop( Iop_32UtoV128, loadLE( Ity_I32, mkexpr(addr) ) ) );
14802 delta += 3+alen;
14803 DIP( "pmovzxbd %s,%s\n",
14804 dis_buf, nameXMMReg( gregOfRexRM(pfx, modrm) ) );
14805 }
14806
14807 IRTemp zeroVec = newTemp(Ity_V128);
14808 assign( zeroVec, IRExpr_Const( IRConst_V128(0) ) );
14809
14810 putXMMReg( gregOfRexRM( pfx, modrm ),
14811 binop( Iop_InterleaveLO8x16,
14812 mkexpr(zeroVec),
14813 binop( Iop_InterleaveLO8x16,
14814 mkexpr(zeroVec), mkexpr(srcVec) ) ) );
14815
14816 goto decode_success;
14817 }
14818
14819
14820 /* 66 0f 38 32 /r = PMOVZXBQ xmm1, xmm2/m16
14821 Packed Move with Zero Extend from Byte to QWord (XMM) */
14822 if ( have66noF2noF3( pfx )
14823 && sz == 2
14824 && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x32 ) {
14825
14826 modrm = insn[3];
14827
14828 IRTemp srcVec = newTemp(Ity_V128);
14829
14830 if ( epartIsReg(modrm) ) {
14831 assign( srcVec, getXMMReg( eregOfRexRM(pfx, modrm) ) );
14832 delta += 3+1;
14833 DIP( "pmovzxbq %s,%s\n",
14834 nameXMMReg( eregOfRexRM(pfx, modrm) ),
14835 nameXMMReg( gregOfRexRM(pfx, modrm) ) );
14836 } else {
14837 addr = disAMode( &alen, vbi, pfx, delta+3, dis_buf, 0 );
14838 assign( srcVec,
14839 unop( Iop_32UtoV128,
14840 unop( Iop_16Uto32, loadLE( Ity_I16, mkexpr(addr) ) ) ) );
14841 delta += 3+alen;
14842 DIP( "pmovzxbq %s,%s\n",
14843 dis_buf, nameXMMReg( gregOfRexRM(pfx, modrm) ) );
14844 }
14845
14846 IRTemp zeroVec = newTemp(Ity_V128);
14847 assign( zeroVec, IRExpr_Const( IRConst_V128(0) ) );
14848
14849 putXMMReg( gregOfRexRM( pfx, modrm ),
14850 binop( Iop_InterleaveLO8x16,
14851 mkexpr(zeroVec),
14852 binop( Iop_InterleaveLO8x16,
14853 mkexpr(zeroVec),
14854 binop( Iop_InterleaveLO8x16,
14855 mkexpr(zeroVec), mkexpr(srcVec) ) ) ) );
14856
14857 goto decode_success;
14858 }
14859
14860
14861 /* 66 0f 38 33 /r = PMOVZXWD xmm1, xmm2/m64
14862 Packed Move with Zero Extend from Word to DWord (XMM) */
14863 if ( have66noF2noF3( pfx )
14864 && sz == 2
14865 && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x33 ) {
14866
14867 modrm = insn[3];
14868
14869 IRTemp srcVec = newTemp(Ity_V128);
14870
14871 if ( epartIsReg(modrm) ) {
14872 assign( srcVec, getXMMReg( eregOfRexRM(pfx, modrm) ) );
14873 delta += 3+1;
14874 DIP( "pmovzxwd %s,%s\n",
14875 nameXMMReg( eregOfRexRM(pfx, modrm) ),
14876 nameXMMReg( gregOfRexRM(pfx, modrm) ) );
14877 } else {
14878 addr = disAMode( &alen, vbi, pfx, delta+3, dis_buf, 0 );
14879 assign( srcVec,
14880 unop( Iop_64UtoV128, loadLE( Ity_I64, mkexpr(addr) ) ) );
14881 delta += 3+alen;
14882 DIP( "pmovzxwd %s,%s\n",
14883 dis_buf, nameXMMReg( gregOfRexRM(pfx, modrm) ) );
14884 }
14885
14886 putXMMReg( gregOfRexRM(pfx, modrm),
14887 binop( Iop_InterleaveLO16x8,
14888 IRExpr_Const( IRConst_V128(0) ),
14889 mkexpr(srcVec) ) );
14890
14891 goto decode_success;
14892 }
14893
14894
14895 /* 66 0f 38 34 /r = PMOVZXWQ xmm1, xmm2/m32
14896 Packed Move with Zero Extend from Word to QWord (XMM) */
14897 if ( have66noF2noF3( pfx )
14898 && sz == 2
14899 && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x34 ) {
14900
14901 modrm = insn[3];
14902
14903 IRTemp srcVec = newTemp(Ity_V128);
14904
14905 if ( epartIsReg( modrm ) ) {
14906 assign( srcVec, getXMMReg( eregOfRexRM(pfx, modrm) ) );
14907 delta += 3+1;
14908 DIP( "pmovzxwq %s,%s\n",
14909 nameXMMReg( eregOfRexRM(pfx, modrm) ),
14910 nameXMMReg( gregOfRexRM(pfx, modrm) ) );
14911 } else {
14912 addr = disAMode( &alen, vbi, pfx, delta+3, dis_buf, 0 );
14913 assign( srcVec,
14914 unop( Iop_32UtoV128, loadLE( Ity_I32, mkexpr(addr) ) ) );
14915 delta += 3+alen;
14916 DIP( "pmovzxwq %s,%s\n",
14917 dis_buf, nameXMMReg( gregOfRexRM(pfx, modrm) ) );
14918 }
14919
14920 IRTemp zeroVec = newTemp( Ity_V128 );
14921 assign( zeroVec, IRExpr_Const( IRConst_V128(0) ) );
14922
14923 putXMMReg( gregOfRexRM( pfx, modrm ),
14924 binop( Iop_InterleaveLO16x8,
14925 mkexpr(zeroVec),
14926 binop( Iop_InterleaveLO16x8,
14927 mkexpr(zeroVec), mkexpr(srcVec) ) ) );
14928
14929 goto decode_success;
14930 }
14931
14932
14933 /* 66 0f 38 35 /r = PMOVZXDQ xmm1, xmm2/m64
14934 Packed Move with Zero Extend from DWord to QWord (XMM) */
14935 if ( have66noF2noF3( pfx )
14936 && sz == 2
14937 && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x35 ) {
14938
14939 modrm = insn[3];
14940
14941 IRTemp srcVec = newTemp(Ity_V128);
14942
14943 if ( epartIsReg(modrm) ) {
14944 assign( srcVec, getXMMReg( eregOfRexRM(pfx, modrm) ) );
14945 delta += 3+1;
14946 DIP( "pmovzxdq %s,%s\n",
14947 nameXMMReg( eregOfRexRM(pfx, modrm) ),
14948 nameXMMReg( gregOfRexRM(pfx, modrm) ) );
14949 } else {
14950 addr = disAMode( &alen, vbi, pfx, delta+3, dis_buf, 0 );
14951 assign( srcVec,
14952 unop( Iop_64UtoV128, loadLE( Ity_I64, mkexpr(addr) ) ) );
14953 delta += 3+alen;
14954 DIP( "pmovzxdq %s,%s\n",
14955 dis_buf, nameXMMReg( gregOfRexRM(pfx, modrm) ) );
14956 }
14957
14958 putXMMReg( gregOfRexRM(pfx, modrm),
14959 binop( Iop_InterleaveLO32x4,
14960 IRExpr_Const( IRConst_V128(0) ),
14961 mkexpr(srcVec) ) );
14962
14963 goto decode_success;
14964 }
14965
14966
sewardjfd181282010-06-14 21:29:35 +000014967 /* F3 0F B8 = POPCNT{W,L,Q}
14968 Count the number of 1 bits in a register
14969 */
14970 if (haveF3noF2(pfx) /* so both 66 and 48 are possibilities */
14971 && insn[0] == 0x0F && insn[1] == 0xB8) {
14972 vassert(sz == 2 || sz == 4 || sz == 8);
14973 /*IRType*/ ty = szToITy(sz);
14974 IRTemp src = newTemp(ty);
14975 modrm = insn[2];
14976 if (epartIsReg(modrm)) {
14977 assign(src, getIRegE(sz, pfx, modrm));
14978 delta += 2+1;
14979 DIP("popcnt%c %s, %s\n", nameISize(sz), nameIRegE(sz, pfx, modrm),
14980 nameIRegG(sz, pfx, modrm));
14981 } else {
14982 addr = disAMode( &alen, vbi, pfx, delta+2, dis_buf, 0);
14983 assign(src, loadLE(ty, mkexpr(addr)));
14984 delta += 2+alen;
14985 DIP("popcnt%c %s, %s\n", nameISize(sz), dis_buf,
14986 nameIRegG(sz, pfx, modrm));
14987 }
14988
14989 IRTemp result = gen_POPCOUNT(ty, src);
14990 putIRegG(sz, pfx, modrm, mkexpr(result));
14991
14992 // Update flags. This is pretty lame .. perhaps can do better
14993 // if this turns out to be performance critical.
14994 // O S A C P are cleared. Z is set if SRC == 0.
14995 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(AMD64G_CC_OP_COPY) ));
14996 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
14997 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU64(0) ));
14998 stmt( IRStmt_Put( OFFB_CC_DEP1,
14999 binop(Iop_Shl64,
15000 unop(Iop_1Uto64,
15001 binop(Iop_CmpEQ64,
15002 widenUto64(mkexpr(src)),
15003 mkU64(0))),
15004 mkU8(AMD64G_CC_SHIFT_Z))));
15005
15006 goto decode_success;
15007 }
15008
15009
de5a70f5c2010-04-01 23:08:59 +000015010 /* ---------------------------------------------------- */
15011 /* --- end of the SSE4 decoder --- */
15012 /* ---------------------------------------------------- */
15013
sewardj7a240552005-01-28 21:37:12 +000015014 /*after_sse_decoders:*/
sewardjdf0e0022005-01-25 15:48:43 +000015015
15016 /* Get the primary opcode. */
sewardj8c332e22005-01-28 01:36:56 +000015017 opc = getUChar(delta); delta++;
sewardjdf0e0022005-01-25 15:48:43 +000015018
15019 /* We get here if the current insn isn't SSE, or this CPU doesn't
15020 support SSE. */
15021
15022 switch (opc) {
15023
15024 /* ------------------------ Control flow --------------- */
15025
sewardj47c2d4d2006-11-14 17:50:16 +000015026 case 0xC2: /* RET imm16 */
15027 if (have66orF2orF3(pfx)) goto decode_failure;
15028 d64 = getUDisp16(delta);
15029 delta += 2;
sewardj2e28ac42008-12-04 00:05:12 +000015030 dis_ret(vbi, d64);
sewardj47c2d4d2006-11-14 17:50:16 +000015031 dres.whatNext = Dis_StopHere;
15032 DIP("ret %lld\n", d64);
15033 break;
15034
sewardj2f959cc2005-01-26 01:19:35 +000015035 case 0xC3: /* RET */
sewardj47c2d4d2006-11-14 17:50:16 +000015036 if (have66orF2(pfx)) goto decode_failure;
sewardj55dbb262005-01-28 16:36:51 +000015037 /* F3 is acceptable on AMD. */
sewardj2e28ac42008-12-04 00:05:12 +000015038 dis_ret(vbi, 0);
sewardj9e6491a2005-07-02 19:24:10 +000015039 dres.whatNext = Dis_StopHere;
sewardje941eea2005-01-30 19:52:28 +000015040 DIP(haveF3(pfx) ? "rep ; ret\n" : "ret\n");
sewardj2f959cc2005-01-26 01:19:35 +000015041 break;
15042
sewardj3ca55a12005-01-27 16:06:23 +000015043 case 0xE8: /* CALL J4 */
15044 if (haveF2orF3(pfx)) goto decode_failure;
15045 d64 = getSDisp32(delta); delta += 4;
sewardj9e6491a2005-07-02 19:24:10 +000015046 d64 += (guest_RIP_bbstart+delta);
15047 /* (guest_RIP_bbstart+delta) == return-to addr, d64 == call-to addr */
sewardj3ca55a12005-01-27 16:06:23 +000015048 t1 = newTemp(Ity_I64);
15049 assign(t1, binop(Iop_Sub64, getIReg64(R_RSP), mkU64(8)));
15050 putIReg64(R_RSP, mkexpr(t1));
sewardj9e6491a2005-07-02 19:24:10 +000015051 storeLE( mkexpr(t1), mkU64(guest_RIP_bbstart+delta));
sewardj478646f2008-05-01 20:13:04 +000015052 t2 = newTemp(Ity_I64);
15053 assign(t2, mkU64((Addr64)d64));
sewardj2e28ac42008-12-04 00:05:12 +000015054 make_redzone_AbiHint(vbi, t1, t2/*nia*/, "call-d32");
sewardjc716aea2006-01-17 01:48:46 +000015055 if (resteerOkFn( callback_opaque, (Addr64)d64) ) {
sewardj3ca55a12005-01-27 16:06:23 +000015056 /* follow into the call target. */
sewardj984d9b12010-01-15 10:53:21 +000015057 dres.whatNext = Dis_ResteerU;
sewardj9e6491a2005-07-02 19:24:10 +000015058 dres.continueAt = d64;
sewardj3ca55a12005-01-27 16:06:23 +000015059 } else {
15060 jmp_lit(Ijk_Call,d64);
sewardj9e6491a2005-07-02 19:24:10 +000015061 dres.whatNext = Dis_StopHere;
sewardj3ca55a12005-01-27 16:06:23 +000015062 }
15063 DIP("call 0x%llx\n",d64);
15064 break;
15065
sewardjd20c8852005-01-20 20:04:07 +000015066//.. //-- case 0xC8: /* ENTER */
15067//.. //-- d32 = getUDisp16(eip); eip += 2;
sewardj8c332e22005-01-28 01:36:56 +000015068//.. //-- abyte = getUChar(delta); delta++;
sewardjd20c8852005-01-20 20:04:07 +000015069//.. //--
15070//.. //-- vg_assert(sz == 4);
15071//.. //-- vg_assert(abyte == 0);
15072//.. //--
15073//.. //-- t1 = newTemp(cb); t2 = newTemp(cb);
15074//.. //-- uInstr2(cb, GET, sz, ArchReg, R_EBP, TempReg, t1);
15075//.. //-- uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t2);
15076//.. //-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
15077//.. //-- uLiteral(cb, sz);
15078//.. //-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
15079//.. //-- uInstr2(cb, STORE, 4, TempReg, t1, TempReg, t2);
15080//.. //-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_EBP);
15081//.. //-- if (d32) {
15082//.. //-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
15083//.. //-- uLiteral(cb, d32);
15084//.. //-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
15085//.. //-- }
15086//.. //-- DIP("enter 0x%x, 0x%x", d32, abyte);
15087//.. //-- break;
sewardje1698952005-02-08 15:02:39 +000015088
15089 case 0xC9: /* LEAVE */
15090 /* In 64-bit mode this defaults to a 64-bit operand size. There
15091 is no way to encode a 32-bit variant. Hence sz==4 but we do
15092 it as if sz=8. */
15093 if (sz != 4)
15094 goto decode_failure;
15095 t1 = newTemp(Ity_I64);
15096 t2 = newTemp(Ity_I64);
15097 assign(t1, getIReg64(R_RBP));
15098 /* First PUT RSP looks redundant, but need it because RSP must
15099 always be up-to-date for Memcheck to work... */
15100 putIReg64(R_RSP, mkexpr(t1));
15101 assign(t2, loadLE(Ity_I64,mkexpr(t1)));
15102 putIReg64(R_RBP, mkexpr(t2));
15103 putIReg64(R_RSP, binop(Iop_Add64, mkexpr(t1), mkU64(8)) );
15104 DIP("leave\n");
15105 break;
15106
sewardjd20c8852005-01-20 20:04:07 +000015107//.. //-- /* ---------------- Misc weird-ass insns --------------- */
15108//.. //--
15109//.. //-- case 0x27: /* DAA */
15110//.. //-- case 0x2F: /* DAS */
15111//.. //-- t1 = newTemp(cb);
15112//.. //-- uInstr2(cb, GET, 1, ArchReg, R_AL, TempReg, t1);
15113//.. //-- /* Widen %AL to 32 bits, so it's all defined when we push it. */
15114//.. //-- uInstr1(cb, WIDEN, 4, TempReg, t1);
15115//.. //-- uWiden(cb, 1, False);
15116//.. //-- uInstr0(cb, CALLM_S, 0);
15117//.. //-- uInstr1(cb, PUSH, 4, TempReg, t1);
15118//.. //-- uInstr1(cb, CALLM, 0, Lit16,
15119//.. //-- opc == 0x27 ? VGOFF_(helper_DAA) : VGOFF_(helper_DAS) );
15120//.. //-- uFlagsRWU(cb, FlagsAC, FlagsSZACP, FlagO);
15121//.. //-- uInstr1(cb, POP, 4, TempReg, t1);
15122//.. //-- uInstr0(cb, CALLM_E, 0);
15123//.. //-- uInstr2(cb, PUT, 1, TempReg, t1, ArchReg, R_AL);
15124//.. //-- DIP(opc == 0x27 ? "daa\n" : "das\n");
15125//.. //-- break;
15126//.. //--
15127//.. //-- case 0x37: /* AAA */
15128//.. //-- case 0x3F: /* AAS */
15129//.. //-- t1 = newTemp(cb);
15130//.. //-- uInstr2(cb, GET, 2, ArchReg, R_EAX, TempReg, t1);
15131//.. //-- /* Widen %AL to 32 bits, so it's all defined when we push it. */
15132//.. //-- uInstr1(cb, WIDEN, 4, TempReg, t1);
15133//.. //-- uWiden(cb, 2, False);
15134//.. //-- uInstr0(cb, CALLM_S, 0);
15135//.. //-- uInstr1(cb, PUSH, 4, TempReg, t1);
15136//.. //-- uInstr1(cb, CALLM, 0, Lit16,
15137//.. //-- opc == 0x37 ? VGOFF_(helper_AAA) : VGOFF_(helper_AAS) );
15138//.. //-- uFlagsRWU(cb, FlagA, FlagsAC, FlagsEmpty);
15139//.. //-- uInstr1(cb, POP, 4, TempReg, t1);
15140//.. //-- uInstr0(cb, CALLM_E, 0);
15141//.. //-- uInstr2(cb, PUT, 2, TempReg, t1, ArchReg, R_EAX);
15142//.. //-- DIP(opc == 0x37 ? "aaa\n" : "aas\n");
15143//.. //-- break;
15144//.. //--
15145//.. //-- case 0xD4: /* AAM */
15146//.. //-- case 0xD5: /* AAD */
sewardj8c332e22005-01-28 01:36:56 +000015147//.. //-- d32 = getUChar(delta); delta++;
sewardjd20c8852005-01-20 20:04:07 +000015148//.. //-- if (d32 != 10) VG_(core_panic)("disInstr: AAM/AAD but base not 10 !");
15149//.. //-- t1 = newTemp(cb);
15150//.. //-- uInstr2(cb, GET, 2, ArchReg, R_EAX, TempReg, t1);
15151//.. //-- /* Widen %AX to 32 bits, so it's all defined when we push it. */
15152//.. //-- uInstr1(cb, WIDEN, 4, TempReg, t1);
15153//.. //-- uWiden(cb, 2, False);
15154//.. //-- uInstr0(cb, CALLM_S, 0);
15155//.. //-- uInstr1(cb, PUSH, 4, TempReg, t1);
15156//.. //-- uInstr1(cb, CALLM, 0, Lit16,
15157//.. //-- opc == 0xD4 ? VGOFF_(helper_AAM) : VGOFF_(helper_AAD) );
15158//.. //-- uFlagsRWU(cb, FlagsEmpty, FlagsSZP, FlagsEmpty);
15159//.. //-- uInstr1(cb, POP, 4, TempReg, t1);
15160//.. //-- uInstr0(cb, CALLM_E, 0);
15161//.. //-- uInstr2(cb, PUT, 2, TempReg, t1, ArchReg, R_EAX);
15162//.. //-- DIP(opc == 0xD4 ? "aam\n" : "aad\n");
15163//.. //-- break;
sewardj3ca55a12005-01-27 16:06:23 +000015164
15165 /* ------------------------ CWD/CDQ -------------------- */
15166
15167 case 0x98: /* CBW */
15168 if (haveF2orF3(pfx)) goto decode_failure;
15169 if (sz == 8) {
sewardj5b470602005-02-27 13:10:48 +000015170 putIRegRAX( 8, unop(Iop_32Sto64, getIRegRAX(4)) );
sewardje941eea2005-01-30 19:52:28 +000015171 DIP(/*"cdqe\n"*/"cltq");
15172 break;
15173 }
sewardj3ca55a12005-01-27 16:06:23 +000015174 if (sz == 4) {
sewardj5b470602005-02-27 13:10:48 +000015175 putIRegRAX( 4, unop(Iop_16Sto32, getIRegRAX(2)) );
sewardj7eaa7cf2005-01-31 18:55:22 +000015176 DIP("cwtl\n");
sewardje941eea2005-01-30 19:52:28 +000015177 break;
15178 }
sewardj3ca55a12005-01-27 16:06:23 +000015179 if (sz == 2) {
sewardj5b470602005-02-27 13:10:48 +000015180 putIRegRAX( 2, unop(Iop_8Sto16, getIRegRAX(1)) );
sewardj3ca55a12005-01-27 16:06:23 +000015181 DIP("cbw\n");
sewardj7bc00082005-03-27 05:08:32 +000015182 break;
sewardj3ca55a12005-01-27 16:06:23 +000015183 }
sewardje941eea2005-01-30 19:52:28 +000015184 goto decode_failure;
sewardj3ca55a12005-01-27 16:06:23 +000015185
15186 case 0x99: /* CWD/CDQ/CQO */
15187 if (haveF2orF3(pfx)) goto decode_failure;
15188 vassert(sz == 2 || sz == 4 || sz == 8);
15189 ty = szToITy(sz);
sewardj5b470602005-02-27 13:10:48 +000015190 putIRegRDX( sz,
15191 binop(mkSizedOp(ty,Iop_Sar8),
15192 getIRegRAX(sz),
15193 mkU8(sz == 2 ? 15 : (sz == 4 ? 31 : 63))) );
sewardje941eea2005-01-30 19:52:28 +000015194 DIP(sz == 2 ? "cwd\n"
sewardj5b470602005-02-27 13:10:48 +000015195 : (sz == 4 ? /*"cdq\n"*/ "cltd\n"
15196 : "cqo\n"));
sewardj3ca55a12005-01-27 16:06:23 +000015197 break;
15198
sewardj8d965312005-02-25 02:48:47 +000015199 /* ------------------------ FPU ops -------------------- */
15200
sewardj905edbd2007-04-07 12:25:37 +000015201 case 0x9E: /* SAHF */
15202 codegen_SAHF();
15203 DIP("sahf\n");
15204 break;
15205
15206 case 0x9F: /* LAHF */
15207 codegen_LAHF();
15208 DIP("lahf\n");
15209 break;
15210
sewardj6847d8c2005-05-12 19:21:55 +000015211 case 0x9B: /* FWAIT */
15212 /* ignore? */
15213 DIP("fwait\n");
15214 break;
sewardj8d965312005-02-25 02:48:47 +000015215
15216 case 0xD8:
15217 case 0xD9:
15218 case 0xDA:
15219 case 0xDB:
15220 case 0xDC:
15221 case 0xDD:
15222 case 0xDE:
sewardj5619f792007-03-11 19:34:13 +000015223 case 0xDF: {
15224 Bool redundantREXWok = False;
15225
15226 if (haveF2orF3(pfx))
15227 goto decode_failure;
15228
15229 /* kludge to tolerate redundant rex.w prefixes (should do this
15230 properly one day) */
15231 /* mono 1.1.18.1 produces 48 D9 FA, which is rex.w fsqrt */
15232 if ( (opc == 0xD9 && getUChar(delta+0) == 0xFA)/*fsqrt*/ )
15233 redundantREXWok = True;
15234
15235 if ( (sz == 4
15236 || (sz == 8 && redundantREXWok))
15237 && haveNo66noF2noF3(pfx)) {
sewardj270def42005-07-03 01:03:01 +000015238 Long delta0 = delta;
15239 Bool decode_OK = False;
sewardj2e28ac42008-12-04 00:05:12 +000015240 delta = dis_FPU ( &decode_OK, vbi, pfx, delta );
sewardj8d965312005-02-25 02:48:47 +000015241 if (!decode_OK) {
15242 delta = delta0;
15243 goto decode_failure;
15244 }
15245 break;
15246 } else {
15247 goto decode_failure;
15248 }
sewardj5619f792007-03-11 19:34:13 +000015249 }
sewardj8d965312005-02-25 02:48:47 +000015250
sewardj4fa325a2005-11-03 13:27:24 +000015251 /* ------------------------ INT ------------------------ */
15252
sewardjada80ba2007-03-12 00:43:59 +000015253 case 0xCC: /* INT 3 */
sewardj0f500042007-08-29 09:09:17 +000015254 jmp_lit(Ijk_SigTRAP, guest_RIP_bbstart + delta);
sewardjada80ba2007-03-12 00:43:59 +000015255 dres.whatNext = Dis_StopHere;
15256 DIP("int $0x3\n");
15257 break;
15258
sewardj4fa325a2005-11-03 13:27:24 +000015259 case 0xCD: { /* INT imm8 */
15260 IRJumpKind jk = Ijk_Boring;
15261 if (have66orF2orF3(pfx)) goto decode_failure;
15262 d64 = getUChar(delta); delta++;
15263 switch (d64) {
15264 case 32: jk = Ijk_Sys_int32; break;
15265 default: goto decode_failure;
15266 }
15267 guest_RIP_next_mustcheck = True;
15268 guest_RIP_next_assumed = guest_RIP_bbstart + delta;
15269 jmp_lit(jk, guest_RIP_next_assumed);
15270 /* It's important that all ArchRegs carry their up-to-date value
15271 at this point. So we declare an end-of-block here, which
15272 forces any TempRegs caching ArchRegs to be flushed. */
15273 dres.whatNext = Dis_StopHere;
15274 DIP("int $0x%02x\n", (UInt)d64);
15275 break;
15276 }
15277
sewardjf8c37f72005-02-07 18:55:29 +000015278 /* ------------------------ Jcond, byte offset --------- */
15279
15280 case 0xEB: /* Jb (jump, byte offset) */
sewardj5b470602005-02-27 13:10:48 +000015281 if (haveF2orF3(pfx)) goto decode_failure;
sewardjf8c37f72005-02-07 18:55:29 +000015282 if (sz != 4)
15283 goto decode_failure; /* JRS added 2004 July 11 */
sewardj9e6491a2005-07-02 19:24:10 +000015284 d64 = (guest_RIP_bbstart+delta+1) + getSDisp8(delta);
sewardjf8c37f72005-02-07 18:55:29 +000015285 delta++;
sewardjc716aea2006-01-17 01:48:46 +000015286 if (resteerOkFn(callback_opaque,d64)) {
sewardj984d9b12010-01-15 10:53:21 +000015287 dres.whatNext = Dis_ResteerU;
sewardj9e6491a2005-07-02 19:24:10 +000015288 dres.continueAt = d64;
sewardjf8c37f72005-02-07 18:55:29 +000015289 } else {
15290 jmp_lit(Ijk_Boring,d64);
sewardj9e6491a2005-07-02 19:24:10 +000015291 dres.whatNext = Dis_StopHere;
sewardjf8c37f72005-02-07 18:55:29 +000015292 }
15293 DIP("jmp-8 0x%llx\n", d64);
15294 break;
sewardj1389d4d2005-01-28 13:46:29 +000015295
15296 case 0xE9: /* Jv (jump, 16/32 offset) */
sewardj5b470602005-02-27 13:10:48 +000015297 if (haveF2orF3(pfx)) goto decode_failure;
sewardjf8c37f72005-02-07 18:55:29 +000015298 if (sz != 4)
15299 goto decode_failure; /* JRS added 2004 July 11 */
sewardj9e6491a2005-07-02 19:24:10 +000015300 d64 = (guest_RIP_bbstart+delta+sz) + getSDisp(sz,delta);
sewardj1389d4d2005-01-28 13:46:29 +000015301 delta += sz;
sewardjc716aea2006-01-17 01:48:46 +000015302 if (resteerOkFn(callback_opaque,d64)) {
sewardj984d9b12010-01-15 10:53:21 +000015303 dres.whatNext = Dis_ResteerU;
sewardj9e6491a2005-07-02 19:24:10 +000015304 dres.continueAt = d64;
sewardj1389d4d2005-01-28 13:46:29 +000015305 } else {
15306 jmp_lit(Ijk_Boring,d64);
sewardj9e6491a2005-07-02 19:24:10 +000015307 dres.whatNext = Dis_StopHere;
sewardj1389d4d2005-01-28 13:46:29 +000015308 }
15309 DIP("jmp 0x%llx\n", d64);
15310 break;
15311
sewardjf8c37f72005-02-07 18:55:29 +000015312 case 0x70:
15313 case 0x71:
15314 case 0x72: /* JBb/JNAEb (jump below) */
15315 case 0x73: /* JNBb/JAEb (jump not below) */
15316 case 0x74: /* JZb/JEb (jump zero) */
15317 case 0x75: /* JNZb/JNEb (jump not zero) */
15318 case 0x76: /* JBEb/JNAb (jump below or equal) */
15319 case 0x77: /* JNBEb/JAb (jump not below or equal) */
15320 case 0x78: /* JSb (jump negative) */
15321 case 0x79: /* JSb (jump not negative) */
15322 case 0x7A: /* JP (jump parity even) */
15323 case 0x7B: /* JNP/JPO (jump parity odd) */
15324 case 0x7C: /* JLb/JNGEb (jump less) */
15325 case 0x7D: /* JGEb/JNLb (jump greater or equal) */
15326 case 0x7E: /* JLEb/JNGb (jump less or equal) */
15327 case 0x7F: /* JGb/JNLEb (jump greater) */
sewardj984d9b12010-01-15 10:53:21 +000015328 { Long jmpDelta;
15329 HChar* comment = "";
sewardj5b470602005-02-27 13:10:48 +000015330 if (haveF2orF3(pfx)) goto decode_failure;
sewardj984d9b12010-01-15 10:53:21 +000015331 jmpDelta = getSDisp8(delta);
15332 vassert(-128 <= jmpDelta && jmpDelta < 128);
15333 d64 = (guest_RIP_bbstart+delta+1) + jmpDelta;
sewardjf8c37f72005-02-07 18:55:29 +000015334 delta++;
sewardj984d9b12010-01-15 10:53:21 +000015335 if (resteerCisOk
15336 && vex_control.guest_chase_cond
sewardj0d925b12010-01-17 15:47:01 +000015337 && (Addr64)d64 != (Addr64)guest_RIP_bbstart
sewardj984d9b12010-01-15 10:53:21 +000015338 && jmpDelta < 0
15339 && resteerOkFn( callback_opaque, d64) ) {
15340 /* Speculation: assume this backward branch is taken. So we
15341 need to emit a side-exit to the insn following this one,
15342 on the negation of the condition, and continue at the
sewardj0d925b12010-01-17 15:47:01 +000015343 branch target address (d64). If we wind up back at the
15344 first instruction of the trace, just stop; it's better to
15345 let the IR loop unroller handle that case. */
sewardj984d9b12010-01-15 10:53:21 +000015346 stmt( IRStmt_Exit(
15347 mk_amd64g_calculate_condition(
15348 (AMD64Condcode)(1 ^ (opc - 0x70))),
15349 Ijk_Boring,
15350 IRConst_U64(guest_RIP_bbstart+delta) ) );
15351 dres.whatNext = Dis_ResteerC;
15352 dres.continueAt = d64;
15353 comment = "(assumed taken)";
15354 }
15355 else
15356 if (resteerCisOk
15357 && vex_control.guest_chase_cond
sewardj0d925b12010-01-17 15:47:01 +000015358 && (Addr64)d64 != (Addr64)guest_RIP_bbstart
sewardj984d9b12010-01-15 10:53:21 +000015359 && jmpDelta >= 0
15360 && resteerOkFn( callback_opaque, guest_RIP_bbstart+delta ) ) {
15361 /* Speculation: assume this forward branch is not taken. So
15362 we need to emit a side-exit to d64 (the dest) and continue
15363 disassembling at the insn immediately following this
15364 one. */
15365 stmt( IRStmt_Exit(
15366 mk_amd64g_calculate_condition((AMD64Condcode)(opc - 0x70)),
15367 Ijk_Boring,
15368 IRConst_U64(d64) ) );
15369 dres.whatNext = Dis_ResteerC;
15370 dres.continueAt = guest_RIP_bbstart+delta;
15371 comment = "(assumed not taken)";
15372 }
15373 else {
15374 /* Conservative default translation - end the block at this
15375 point. */
15376 jcc_01( (AMD64Condcode)(opc - 0x70),
15377 guest_RIP_bbstart+delta,
15378 d64 );
15379 dres.whatNext = Dis_StopHere;
15380 }
15381 DIP("j%s-8 0x%llx %s\n", name_AMD64Condcode(opc - 0x70), d64, comment);
sewardjf8c37f72005-02-07 18:55:29 +000015382 break;
sewardj984d9b12010-01-15 10:53:21 +000015383 }
sewardjf8c37f72005-02-07 18:55:29 +000015384
sewardjc01c1fa2005-11-04 14:34:52 +000015385 case 0xE3:
15386 /* JRCXZ or JECXZ, depending address size override. */
15387 if (have66orF2orF3(pfx)) goto decode_failure;
sewardjfdfa8862005-10-05 16:58:23 +000015388 d64 = (guest_RIP_bbstart+delta+1) + getSDisp8(delta);
15389 delta++;
sewardjc01c1fa2005-11-04 14:34:52 +000015390 if (haveASO(pfx)) {
15391 /* 32-bit */
15392 stmt( IRStmt_Exit( binop(Iop_CmpEQ64,
15393 unop(Iop_32Uto64, getIReg32(R_RCX)),
15394 mkU64(0)),
15395 Ijk_Boring,
15396 IRConst_U64(d64))
15397 );
15398 DIP("jecxz 0x%llx\n", d64);
15399 } else {
15400 /* 64-bit */
15401 stmt( IRStmt_Exit( binop(Iop_CmpEQ64,
15402 getIReg64(R_RCX),
15403 mkU64(0)),
15404 Ijk_Boring,
15405 IRConst_U64(d64))
15406 );
15407 DIP("jrcxz 0x%llx\n", d64);
15408 }
sewardjfdfa8862005-10-05 16:58:23 +000015409 break;
sewardj6359f812005-07-20 10:15:34 +000015410
sewardje8f65252005-08-23 23:44:35 +000015411 case 0xE0: /* LOOPNE disp8: decrement count, jump if count != 0 && ZF==0 */
15412 case 0xE1: /* LOOPE disp8: decrement count, jump if count != 0 && ZF==1 */
15413 case 0xE2: /* LOOP disp8: decrement count, jump if count != 0 */
15414 { /* The docs say this uses rCX as a count depending on the
15415 address size override, not the operand one. Since we don't
15416 handle address size overrides, I guess that means RCX. */
15417 IRExpr* zbit = NULL;
15418 IRExpr* count = NULL;
15419 IRExpr* cond = NULL;
15420 HChar* xtra = NULL;
15421
15422 if (have66orF2orF3(pfx) || haveASO(pfx)) goto decode_failure;
15423 d64 = guest_RIP_bbstart+delta+1 + getSDisp8(delta);
15424 delta++;
15425 putIReg64(R_RCX, binop(Iop_Sub64, getIReg64(R_RCX), mkU64(1)));
15426
15427 count = getIReg64(R_RCX);
15428 cond = binop(Iop_CmpNE64, count, mkU64(0));
15429 switch (opc) {
15430 case 0xE2:
15431 xtra = "";
15432 break;
15433 case 0xE1:
15434 xtra = "e";
15435 zbit = mk_amd64g_calculate_condition( AMD64CondZ );
sewardj733d5892010-04-29 08:42:37 +000015436 cond = mkAnd1(cond, zbit);
sewardje8f65252005-08-23 23:44:35 +000015437 break;
15438 case 0xE0:
15439 xtra = "ne";
15440 zbit = mk_amd64g_calculate_condition( AMD64CondNZ );
sewardj733d5892010-04-29 08:42:37 +000015441 cond = mkAnd1(cond, zbit);
sewardje8f65252005-08-23 23:44:35 +000015442 break;
15443 default:
15444 vassert(0);
15445 }
15446 stmt( IRStmt_Exit(cond, Ijk_Boring, IRConst_U64(d64)) );
15447
15448 DIP("loop%s 0x%llx\n", xtra, d64);
15449 break;
15450 }
sewardj32b2bbe2005-01-28 00:50:10 +000015451
15452 /* ------------------------ IMUL ----------------------- */
15453
15454 case 0x69: /* IMUL Iv, Ev, Gv */
sewardj5b470602005-02-27 13:10:48 +000015455 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000015456 delta = dis_imul_I_E_G ( vbi, pfx, sz, delta, sz );
sewardj32b2bbe2005-01-28 00:50:10 +000015457 break;
sewardj7de0d3c2005-02-13 02:26:41 +000015458 case 0x6B: /* IMUL Ib, Ev, Gv */
sewardj2e28ac42008-12-04 00:05:12 +000015459 delta = dis_imul_I_E_G ( vbi, pfx, sz, delta, 1 );
sewardj7de0d3c2005-02-13 02:26:41 +000015460 break;
sewardj1389d4d2005-01-28 13:46:29 +000015461
15462 /* ------------------------ MOV ------------------------ */
15463
15464 case 0x88: /* MOV Gb,Eb */
sewardj5b470602005-02-27 13:10:48 +000015465 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000015466 delta = dis_mov_G_E(vbi, pfx, 1, delta);
sewardj1389d4d2005-01-28 13:46:29 +000015467 break;
15468
15469 case 0x89: /* MOV Gv,Ev */
sewardj5b470602005-02-27 13:10:48 +000015470 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000015471 delta = dis_mov_G_E(vbi, pfx, sz, delta);
sewardj1389d4d2005-01-28 13:46:29 +000015472 break;
15473
sewardjd0a12df2005-02-10 02:07:43 +000015474 case 0x8A: /* MOV Eb,Gb */
sewardj5b470602005-02-27 13:10:48 +000015475 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000015476 delta = dis_mov_E_G(vbi, pfx, 1, delta);
sewardjd0a12df2005-02-10 02:07:43 +000015477 break;
15478
sewardj1389d4d2005-01-28 13:46:29 +000015479 case 0x8B: /* MOV Ev,Gv */
sewardj5b470602005-02-27 13:10:48 +000015480 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000015481 delta = dis_mov_E_G(vbi, pfx, sz, delta);
sewardj1389d4d2005-01-28 13:46:29 +000015482 break;
15483
15484 case 0x8D: /* LEA M,Gv */
sewardj5b470602005-02-27 13:10:48 +000015485 if (haveF2orF3(pfx)) goto decode_failure;
sewardj1389d4d2005-01-28 13:46:29 +000015486 if (sz != 4 && sz != 8)
15487 goto decode_failure;
15488 modrm = getUChar(delta);
15489 if (epartIsReg(modrm))
15490 goto decode_failure;
15491 /* NOTE! this is the one place where a segment override prefix
15492 has no effect on the address calculation. Therefore we clear
15493 any segment override bits in pfx. */
sewardj2e28ac42008-12-04 00:05:12 +000015494 addr = disAMode ( &alen, vbi, clearSegBits(pfx), delta, dis_buf, 0 );
sewardj1389d4d2005-01-28 13:46:29 +000015495 delta += alen;
15496 /* This is a hack. But it isn't clear that really doing the
15497 calculation at 32 bits is really worth it. Hence for leal,
15498 do the full 64-bit calculation and then truncate it. */
sewardj5b470602005-02-27 13:10:48 +000015499 putIRegG( sz, pfx, modrm,
sewardj1389d4d2005-01-28 13:46:29 +000015500 sz == 4
15501 ? unop(Iop_64to32, mkexpr(addr))
15502 : mkexpr(addr)
15503 );
15504 DIP("lea%c %s, %s\n", nameISize(sz), dis_buf,
sewardj5b470602005-02-27 13:10:48 +000015505 nameIRegG(sz,pfx,modrm));
sewardj1389d4d2005-01-28 13:46:29 +000015506 break;
15507
sewardjd20c8852005-01-20 20:04:07 +000015508//.. case 0x8C: /* MOV Sw,Ew -- MOV from a SEGMENT REGISTER */
15509//.. delta = dis_mov_Sw_Ew(sorb, sz, delta);
15510//.. break;
15511//..
15512//.. case 0x8E: /* MOV Ew,Sw -- MOV to a SEGMENT REGISTER */
15513//.. delta = dis_mov_Ew_Sw(sorb, delta);
15514//.. break;
sewardj2bd97d12005-08-02 21:27:25 +000015515
15516 case 0xA0: /* MOV Ob,AL */
15517 if (have66orF2orF3(pfx)) goto decode_failure;
15518 sz = 1;
15519 /* Fall through ... */
sewardj87277cb2005-08-01 13:03:32 +000015520 case 0xA1: /* MOV Ov,eAX */
sewardj2bd97d12005-08-02 21:27:25 +000015521 if (sz != 8 && sz != 4 && sz != 2 && sz != 1)
15522 goto decode_failure;
sewardj87277cb2005-08-01 13:03:32 +000015523 d64 = getDisp64(delta);
15524 delta += 8;
15525 ty = szToITy(sz);
15526 addr = newTemp(Ity_I64);
sewardj2e28ac42008-12-04 00:05:12 +000015527 assign( addr, handleAddrOverrides(vbi, pfx, mkU64(d64)) );
sewardj87277cb2005-08-01 13:03:32 +000015528 putIRegRAX(sz, loadLE( ty, mkexpr(addr) ));
15529 DIP("mov%c %s0x%llx, %s\n", nameISize(sz),
sewardjc4356f02007-11-09 21:15:04 +000015530 segRegTxt(pfx), d64,
sewardj87277cb2005-08-01 13:03:32 +000015531 nameIRegRAX(sz));
15532 break;
15533
sewardj2bd97d12005-08-02 21:27:25 +000015534 case 0xA2: /* MOV AL,Ob */
15535 if (have66orF2orF3(pfx)) goto decode_failure;
15536 sz = 1;
15537 /* Fall through ... */
sewardj87277cb2005-08-01 13:03:32 +000015538 case 0xA3: /* MOV eAX,Ov */
sewardj2bd97d12005-08-02 21:27:25 +000015539 if (sz != 8 && sz != 4 && sz != 2 && sz != 1)
15540 goto decode_failure;
sewardj87277cb2005-08-01 13:03:32 +000015541 d64 = getDisp64(delta);
15542 delta += 8;
15543 ty = szToITy(sz);
15544 addr = newTemp(Ity_I64);
sewardj2e28ac42008-12-04 00:05:12 +000015545 assign( addr, handleAddrOverrides(vbi, pfx, mkU64(d64)) );
sewardj87277cb2005-08-01 13:03:32 +000015546 storeLE( mkexpr(addr), getIRegRAX(sz) );
15547 DIP("mov%c %s, %s0x%llx\n", nameISize(sz), nameIRegRAX(sz),
sewardjc4356f02007-11-09 21:15:04 +000015548 segRegTxt(pfx), d64);
sewardj87277cb2005-08-01 13:03:32 +000015549 break;
sewardjb095fba2005-02-13 14:13:04 +000015550
sewardj8711f662005-05-09 17:52:56 +000015551 /* XXXX be careful here with moves to AH/BH/CH/DH */
sewardj007e9ec2005-03-23 11:36:48 +000015552 case 0xB0: /* MOV imm,AL */
15553 case 0xB1: /* MOV imm,CL */
sewardjb095fba2005-02-13 14:13:04 +000015554 case 0xB2: /* MOV imm,DL */
sewardj007e9ec2005-03-23 11:36:48 +000015555 case 0xB3: /* MOV imm,BL */
15556 case 0xB4: /* MOV imm,AH */
15557 case 0xB5: /* MOV imm,CH */
15558 case 0xB6: /* MOV imm,DH */
sewardj31eecde2005-03-23 03:39:55 +000015559 case 0xB7: /* MOV imm,BH */
sewardj5b470602005-02-27 13:10:48 +000015560 if (haveF2orF3(pfx)) goto decode_failure;
sewardjb095fba2005-02-13 14:13:04 +000015561 d64 = getUChar(delta);
15562 delta += 1;
sewardj5b470602005-02-27 13:10:48 +000015563 putIRegRexB(1, pfx, opc-0xB0, mkU8(d64));
15564 DIP("movb $%lld,%s\n", d64, nameIRegRexB(1,pfx,opc-0xB0));
sewardjb095fba2005-02-13 14:13:04 +000015565 break;
sewardj1389d4d2005-01-28 13:46:29 +000015566
15567 case 0xB8: /* MOV imm,eAX */
15568 case 0xB9: /* MOV imm,eCX */
15569 case 0xBA: /* MOV imm,eDX */
15570 case 0xBB: /* MOV imm,eBX */
15571 case 0xBC: /* MOV imm,eSP */
15572 case 0xBD: /* MOV imm,eBP */
15573 case 0xBE: /* MOV imm,eSI */
15574 case 0xBF: /* MOV imm,eDI */
sewardj03b07cc2005-01-31 18:09:43 +000015575 /* This is the one-and-only place where 64-bit literals are
15576 allowed in the instruction stream. */
sewardj5b470602005-02-27 13:10:48 +000015577 if (haveF2orF3(pfx)) goto decode_failure;
sewardj03b07cc2005-01-31 18:09:43 +000015578 if (sz == 8) {
15579 d64 = getDisp64(delta);
sewardj7eaa7cf2005-01-31 18:55:22 +000015580 delta += 8;
sewardj5b470602005-02-27 13:10:48 +000015581 putIRegRexB(8, pfx, opc-0xB8, mkU64(d64));
sewardj227458e2005-01-31 19:04:50 +000015582 DIP("movabsq $%lld,%s\n", (Long)d64,
sewardj5b470602005-02-27 13:10:48 +000015583 nameIRegRexB(8,pfx,opc-0xB8));
sewardj03b07cc2005-01-31 18:09:43 +000015584 } else {
15585 d64 = getSDisp(imin(4,sz),delta);
15586 delta += imin(4,sz);
sewardj5b470602005-02-27 13:10:48 +000015587 putIRegRexB(sz, pfx, opc-0xB8,
15588 mkU(szToITy(sz), d64 & mkSizeMask(sz)));
sewardj227458e2005-01-31 19:04:50 +000015589 DIP("mov%c $%lld,%s\n", nameISize(sz),
15590 (Long)d64,
sewardj5b470602005-02-27 13:10:48 +000015591 nameIRegRexB(sz,pfx,opc-0xB8));
sewardj03b07cc2005-01-31 18:09:43 +000015592 }
sewardj1389d4d2005-01-28 13:46:29 +000015593 break;
15594
15595 case 0xC6: /* MOV Ib,Eb */
15596 sz = 1;
15597 goto do_Mov_I_E;
15598 case 0xC7: /* MOV Iv,Ev */
15599 goto do_Mov_I_E;
15600
15601 do_Mov_I_E:
sewardj5b470602005-02-27 13:10:48 +000015602 if (haveF2orF3(pfx)) goto decode_failure;
sewardj1389d4d2005-01-28 13:46:29 +000015603 modrm = getUChar(delta);
15604 if (epartIsReg(modrm)) {
sewardj1389d4d2005-01-28 13:46:29 +000015605 delta++; /* mod/rm byte */
15606 d64 = getSDisp(imin(4,sz),delta);
15607 delta += imin(4,sz);
sewardj5b470602005-02-27 13:10:48 +000015608 putIRegE(sz, pfx, modrm,
15609 mkU(szToITy(sz), d64 & mkSizeMask(sz)));
sewardj227458e2005-01-31 19:04:50 +000015610 DIP("mov%c $%lld, %s\n", nameISize(sz),
15611 (Long)d64,
sewardj5b470602005-02-27 13:10:48 +000015612 nameIRegE(sz,pfx,modrm));
sewardj1389d4d2005-01-28 13:46:29 +000015613 } else {
sewardj2e28ac42008-12-04 00:05:12 +000015614 addr = disAMode ( &alen, vbi, pfx, delta, dis_buf,
sewardj5b470602005-02-27 13:10:48 +000015615 /*xtra*/imin(4,sz) );
sewardj1389d4d2005-01-28 13:46:29 +000015616 delta += alen;
sewardje941eea2005-01-30 19:52:28 +000015617 d64 = getSDisp(imin(4,sz),delta);
sewardj1389d4d2005-01-28 13:46:29 +000015618 delta += imin(4,sz);
sewardje941eea2005-01-30 19:52:28 +000015619 storeLE(mkexpr(addr),
15620 mkU(szToITy(sz), d64 & mkSizeMask(sz)));
sewardj227458e2005-01-31 19:04:50 +000015621 DIP("mov%c $%lld, %s\n", nameISize(sz), (Long)d64, dis_buf);
sewardj1389d4d2005-01-28 13:46:29 +000015622 }
15623 break;
15624
sewardj5e525292005-01-28 15:13:10 +000015625 /* ------------------------ MOVx ------------------------ */
15626
15627 case 0x63: /* MOVSX */
sewardj5b470602005-02-27 13:10:48 +000015628 if (haveF2orF3(pfx)) goto decode_failure;
sewardj5e525292005-01-28 15:13:10 +000015629 if (haveREX(pfx) && 1==getRexW(pfx)) {
15630 vassert(sz == 8);
15631 /* movsx r/m32 to r64 */
15632 modrm = getUChar(delta);
15633 if (epartIsReg(modrm)) {
15634 delta++;
sewardj5b470602005-02-27 13:10:48 +000015635 putIRegG(8, pfx, modrm,
sewardj5e525292005-01-28 15:13:10 +000015636 unop(Iop_32Sto64,
sewardj5b470602005-02-27 13:10:48 +000015637 getIRegE(4, pfx, modrm)));
sewardj5e525292005-01-28 15:13:10 +000015638 DIP("movslq %s,%s\n",
sewardj5b470602005-02-27 13:10:48 +000015639 nameIRegE(4, pfx, modrm),
15640 nameIRegG(8, pfx, modrm));
sewardj5e525292005-01-28 15:13:10 +000015641 break;
15642 } else {
sewardj2e28ac42008-12-04 00:05:12 +000015643 addr = disAMode ( &alen, vbi, pfx, delta, dis_buf, 0 );
sewardj5e525292005-01-28 15:13:10 +000015644 delta += alen;
sewardj5b470602005-02-27 13:10:48 +000015645 putIRegG(8, pfx, modrm,
sewardj5e525292005-01-28 15:13:10 +000015646 unop(Iop_32Sto64,
15647 loadLE(Ity_I32, mkexpr(addr))));
15648 DIP("movslq %s,%s\n", dis_buf,
sewardj5b470602005-02-27 13:10:48 +000015649 nameIRegG(8, pfx, modrm));
sewardj5e525292005-01-28 15:13:10 +000015650 break;
15651 }
15652 } else {
15653 goto decode_failure;
15654 }
15655
sewardj4c328cf2005-05-05 12:05:54 +000015656 /* ------------------------ opl imm, A ----------------- */
15657
15658 case 0x04: /* ADD Ib, AL */
15659 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000015660 delta = dis_op_imm_A( 1, False, Iop_Add8, True, delta, "add" );
sewardj4c328cf2005-05-05 12:05:54 +000015661 break;
sewardj03b07cc2005-01-31 18:09:43 +000015662 case 0x05: /* ADD Iv, eAX */
sewardj5b470602005-02-27 13:10:48 +000015663 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000015664 delta = dis_op_imm_A(sz, False, Iop_Add8, True, delta, "add" );
sewardj03b07cc2005-01-31 18:09:43 +000015665 break;
15666
sewardj007e9ec2005-03-23 11:36:48 +000015667 case 0x0C: /* OR Ib, AL */
15668 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000015669 delta = dis_op_imm_A( 1, False, Iop_Or8, True, delta, "or" );
sewardj007e9ec2005-03-23 11:36:48 +000015670 break;
sewardj03b07cc2005-01-31 18:09:43 +000015671 case 0x0D: /* OR Iv, eAX */
sewardj5b470602005-02-27 13:10:48 +000015672 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000015673 delta = dis_op_imm_A( sz, False, Iop_Or8, True, delta, "or" );
sewardj03b07cc2005-01-31 18:09:43 +000015674 break;
15675
sewardj41c01092005-07-23 13:50:32 +000015676 case 0x14: /* ADC Ib, AL */
sewardj671da872007-11-15 23:30:16 +000015677 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000015678 delta = dis_op_imm_A( 1, True, Iop_Add8, True, delta, "adc" );
15679 break;
sewardjd20c8852005-01-20 20:04:07 +000015680//.. //-- case 0x15: /* ADC Iv, eAX */
15681//.. //-- delta = dis_op_imm_A( sz, ADC, True, delta, "adc" );
15682//.. //-- break;
sewardj5fadaf92006-05-12 20:45:59 +000015683
15684 case 0x1C: /* SBB Ib, AL */
15685 if (haveF2orF3(pfx)) goto decode_failure;
15686 delta = dis_op_imm_A( 1, True, Iop_Sub8, True, delta, "sbb" );
15687 break;
sewardjd20c8852005-01-20 20:04:07 +000015688//.. //-- case 0x1D: /* SBB Iv, eAX */
15689//.. //-- delta = dis_op_imm_A( sz, SBB, True, delta, "sbb" );
15690//.. //-- break;
15691//.. //--
sewardj007e9ec2005-03-23 11:36:48 +000015692 case 0x24: /* AND Ib, AL */
15693 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000015694 delta = dis_op_imm_A( 1, False, Iop_And8, True, delta, "and" );
sewardj007e9ec2005-03-23 11:36:48 +000015695 break;
sewardj3ca55a12005-01-27 16:06:23 +000015696 case 0x25: /* AND Iv, eAX */
15697 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000015698 delta = dis_op_imm_A( sz, False, Iop_And8, True, delta, "and" );
sewardj3ca55a12005-01-27 16:06:23 +000015699 break;
15700
sewardj137015d2005-03-27 04:01:15 +000015701 case 0x2C: /* SUB Ib, AL */
15702 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000015703 delta = dis_op_imm_A(1, False, Iop_Sub8, True, delta, "sub" );
sewardj137015d2005-03-27 04:01:15 +000015704 break;
sewardj03b07cc2005-01-31 18:09:43 +000015705 case 0x2D: /* SUB Iv, eAX */
sewardj5b470602005-02-27 13:10:48 +000015706 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000015707 delta = dis_op_imm_A( sz, False, Iop_Sub8, True, delta, "sub" );
sewardj03b07cc2005-01-31 18:09:43 +000015708 break;
15709
sewardj8eb804f2005-05-18 10:22:47 +000015710 case 0x34: /* XOR Ib, AL */
15711 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000015712 delta = dis_op_imm_A( 1, False, Iop_Xor8, True, delta, "xor" );
sewardj8eb804f2005-05-18 10:22:47 +000015713 break;
sewardj85520e42005-02-19 15:22:38 +000015714 case 0x35: /* XOR Iv, eAX */
sewardj5b470602005-02-27 13:10:48 +000015715 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000015716 delta = dis_op_imm_A( sz, False, Iop_Xor8, True, delta, "xor" );
sewardj85520e42005-02-19 15:22:38 +000015717 break;
sewardj03b07cc2005-01-31 18:09:43 +000015718
15719 case 0x3C: /* CMP Ib, AL */
15720 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000015721 delta = dis_op_imm_A( 1, False, Iop_Sub8, False, delta, "cmp" );
sewardj03b07cc2005-01-31 18:09:43 +000015722 break;
sewardj354e5c62005-01-27 20:12:52 +000015723 case 0x3D: /* CMP Iv, eAX */
15724 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000015725 delta = dis_op_imm_A( sz, False, Iop_Sub8, False, delta, "cmp" );
sewardj354e5c62005-01-27 20:12:52 +000015726 break;
15727
sewardj118b23e2005-01-29 02:14:44 +000015728 case 0xA8: /* TEST Ib, AL */
sewardj03b07cc2005-01-31 18:09:43 +000015729 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000015730 delta = dis_op_imm_A( 1, False, Iop_And8, False, delta, "test" );
sewardj118b23e2005-01-29 02:14:44 +000015731 break;
15732 case 0xA9: /* TEST Iv, eAX */
sewardj03b07cc2005-01-31 18:09:43 +000015733 if (haveF2orF3(pfx)) goto decode_failure;
sewardj41c01092005-07-23 13:50:32 +000015734 delta = dis_op_imm_A( sz, False, Iop_And8, False, delta, "test" );
sewardj118b23e2005-01-29 02:14:44 +000015735 break;
15736
15737 /* ------------------------ opl Ev, Gv ----------------- */
15738
sewardj03b07cc2005-01-31 18:09:43 +000015739 case 0x02: /* ADD Eb,Gb */
15740 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000015741 delta = dis_op2_E_G ( vbi, pfx, False, Iop_Add8, True, 1, delta, "add" );
sewardj03b07cc2005-01-31 18:09:43 +000015742 break;
sewardjdf0e0022005-01-25 15:48:43 +000015743 case 0x03: /* ADD Ev,Gv */
sewardj3ca55a12005-01-27 16:06:23 +000015744 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000015745 delta = dis_op2_E_G ( vbi, pfx, False, Iop_Add8, True, sz, delta, "add" );
sewardjdf0e0022005-01-25 15:48:43 +000015746 break;
15747
sewardj03b07cc2005-01-31 18:09:43 +000015748 case 0x0A: /* OR Eb,Gb */
sewardj5b470602005-02-27 13:10:48 +000015749 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000015750 delta = dis_op2_E_G ( vbi, pfx, False, Iop_Or8, True, 1, delta, "or" );
sewardj03b07cc2005-01-31 18:09:43 +000015751 break;
15752 case 0x0B: /* OR Ev,Gv */
sewardj5b470602005-02-27 13:10:48 +000015753 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000015754 delta = dis_op2_E_G ( vbi, pfx, False, Iop_Or8, True, sz, delta, "or" );
sewardj03b07cc2005-01-31 18:09:43 +000015755 break;
sewardj671da872007-11-15 23:30:16 +000015756
15757 case 0x12: /* ADC Eb,Gb */
15758 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000015759 delta = dis_op2_E_G ( vbi, pfx, True, Iop_Add8, True, 1, delta, "adc" );
sewardj671da872007-11-15 23:30:16 +000015760 break;
sewardj22cab062005-07-19 23:59:54 +000015761 case 0x13: /* ADC Ev,Gv */
sewardj671da872007-11-15 23:30:16 +000015762 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000015763 delta = dis_op2_E_G ( vbi, pfx, True, Iop_Add8, True, sz, delta, "adc" );
sewardj22cab062005-07-19 23:59:54 +000015764 break;
15765
sewardjf7d3b2e2010-02-28 04:53:07 +000015766 case 0x1A: /* SBB Eb,Gb */
15767 if (haveF2orF3(pfx)) goto decode_failure;
15768 delta = dis_op2_E_G ( vbi, pfx, True, Iop_Sub8, True, 1, delta, "sbb" );
15769 break;
sewardj7a06b852005-07-20 10:55:26 +000015770 case 0x1B: /* SBB Ev,Gv */
sewardj671da872007-11-15 23:30:16 +000015771 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000015772 delta = dis_op2_E_G ( vbi, pfx, True, Iop_Sub8, True, sz, delta, "sbb" );
sewardj7a06b852005-07-20 10:55:26 +000015773 break;
sewardj03b07cc2005-01-31 18:09:43 +000015774
15775 case 0x22: /* AND Eb,Gb */
15776 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000015777 delta = dis_op2_E_G ( vbi, pfx, False, Iop_And8, True, 1, delta, "and" );
sewardj03b07cc2005-01-31 18:09:43 +000015778 break;
15779 case 0x23: /* AND Ev,Gv */
15780 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000015781 delta = dis_op2_E_G ( vbi, pfx, False, Iop_And8, True, sz, delta, "and" );
sewardj03b07cc2005-01-31 18:09:43 +000015782 break;
15783
15784 case 0x2A: /* SUB Eb,Gb */
15785 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000015786 delta = dis_op2_E_G ( vbi, pfx, False, Iop_Sub8, True, 1, delta, "sub" );
sewardj03b07cc2005-01-31 18:09:43 +000015787 break;
sewardj118b23e2005-01-29 02:14:44 +000015788 case 0x2B: /* SUB Ev,Gv */
sewardj03b07cc2005-01-31 18:09:43 +000015789 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000015790 delta = dis_op2_E_G ( vbi, pfx, False, Iop_Sub8, True, sz, delta, "sub" );
sewardj118b23e2005-01-29 02:14:44 +000015791 break;
15792
sewardj03b07cc2005-01-31 18:09:43 +000015793 case 0x32: /* XOR Eb,Gb */
15794 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000015795 delta = dis_op2_E_G ( vbi, pfx, False, Iop_Xor8, True, 1, delta, "xor" );
sewardj03b07cc2005-01-31 18:09:43 +000015796 break;
15797 case 0x33: /* XOR Ev,Gv */
15798 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000015799 delta = dis_op2_E_G ( vbi, pfx, False, Iop_Xor8, True, sz, delta, "xor" );
sewardj03b07cc2005-01-31 18:09:43 +000015800 break;
15801
sewardjb095fba2005-02-13 14:13:04 +000015802 case 0x3A: /* CMP Eb,Gb */
15803 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000015804 delta = dis_op2_E_G ( vbi, pfx, False, Iop_Sub8, False, 1, delta, "cmp" );
sewardjb095fba2005-02-13 14:13:04 +000015805 break;
sewardj354e5c62005-01-27 20:12:52 +000015806 case 0x3B: /* CMP Ev,Gv */
15807 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000015808 delta = dis_op2_E_G ( vbi, pfx, False, Iop_Sub8, False, sz, delta, "cmp" );
sewardj354e5c62005-01-27 20:12:52 +000015809 break;
15810
sewardj118b23e2005-01-29 02:14:44 +000015811 case 0x84: /* TEST Eb,Gb */
sewardj03b07cc2005-01-31 18:09:43 +000015812 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000015813 delta = dis_op2_E_G ( vbi, pfx, False, Iop_And8, False, 1, delta, "test" );
sewardj118b23e2005-01-29 02:14:44 +000015814 break;
15815 case 0x85: /* TEST Ev,Gv */
sewardj03b07cc2005-01-31 18:09:43 +000015816 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000015817 delta = dis_op2_E_G ( vbi, pfx, False, Iop_And8, False, sz, delta, "test" );
sewardj118b23e2005-01-29 02:14:44 +000015818 break;
15819
15820 /* ------------------------ opl Gv, Ev ----------------- */
15821
sewardj85520e42005-02-19 15:22:38 +000015822 case 0x00: /* ADD Gb,Eb */
15823 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000015824 delta = dis_op2_G_E ( vbi, pfx, False, Iop_Add8, True, 1, delta, "add" );
sewardj85520e42005-02-19 15:22:38 +000015825 break;
sewardj3ca55a12005-01-27 16:06:23 +000015826 case 0x01: /* ADD Gv,Ev */
sewardj354e5c62005-01-27 20:12:52 +000015827 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000015828 delta = dis_op2_G_E ( vbi, pfx, False, Iop_Add8, True, sz, delta, "add" );
sewardj3ca55a12005-01-27 16:06:23 +000015829 break;
15830
sewardj03b07cc2005-01-31 18:09:43 +000015831 case 0x08: /* OR Gb,Eb */
15832 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000015833 delta = dis_op2_G_E ( vbi, pfx, False, Iop_Or8, True, 1, delta, "or" );
sewardj03b07cc2005-01-31 18:09:43 +000015834 break;
sewardj55dbb262005-01-28 16:36:51 +000015835 case 0x09: /* OR Gv,Ev */
15836 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000015837 delta = dis_op2_G_E ( vbi, pfx, False, Iop_Or8, True, sz, delta, "or" );
sewardj55dbb262005-01-28 16:36:51 +000015838 break;
15839
sewardj85520e42005-02-19 15:22:38 +000015840 case 0x10: /* ADC Gb,Eb */
15841 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000015842 delta = dis_op2_G_E ( vbi, pfx, True, Iop_Add8, True, 1, delta, "adc" );
sewardj85520e42005-02-19 15:22:38 +000015843 break;
15844 case 0x11: /* ADC Gv,Ev */
15845 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000015846 delta = dis_op2_G_E ( vbi, pfx, True, Iop_Add8, True, sz, delta, "adc" );
sewardj85520e42005-02-19 15:22:38 +000015847 break;
15848
15849 case 0x18: /* SBB Gb,Eb */
15850 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000015851 delta = dis_op2_G_E ( vbi, pfx, True, Iop_Sub8, True, 1, delta, "sbb" );
sewardj85520e42005-02-19 15:22:38 +000015852 break;
sewardj03b07cc2005-01-31 18:09:43 +000015853 case 0x19: /* SBB Gv,Ev */
sewardja6b93d12005-02-17 09:28:28 +000015854 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000015855 delta = dis_op2_G_E ( vbi, pfx, True, Iop_Sub8, True, sz, delta, "sbb" );
sewardj03b07cc2005-01-31 18:09:43 +000015856 break;
15857
sewardj85520e42005-02-19 15:22:38 +000015858 case 0x20: /* AND Gb,Eb */
15859 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000015860 delta = dis_op2_G_E ( vbi, pfx, False, Iop_And8, True, 1, delta, "and" );
sewardj85520e42005-02-19 15:22:38 +000015861 break;
sewardj3ca55a12005-01-27 16:06:23 +000015862 case 0x21: /* AND Gv,Ev */
sewardj354e5c62005-01-27 20:12:52 +000015863 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000015864 delta = dis_op2_G_E ( vbi, pfx, False, Iop_And8, True, sz, delta, "and" );
sewardj3ca55a12005-01-27 16:06:23 +000015865 break;
sewardj03b07cc2005-01-31 18:09:43 +000015866
15867 case 0x28: /* SUB Gb,Eb */
15868 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000015869 delta = dis_op2_G_E ( vbi, pfx, False, Iop_Sub8, True, 1, delta, "sub" );
sewardj03b07cc2005-01-31 18:09:43 +000015870 break;
sewardj118b23e2005-01-29 02:14:44 +000015871 case 0x29: /* SUB Gv,Ev */
sewardj03b07cc2005-01-31 18:09:43 +000015872 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000015873 delta = dis_op2_G_E ( vbi, pfx, False, Iop_Sub8, True, sz, delta, "sub" );
sewardj118b23e2005-01-29 02:14:44 +000015874 break;
15875
sewardjb095fba2005-02-13 14:13:04 +000015876 case 0x30: /* XOR Gb,Eb */
15877 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000015878 delta = dis_op2_G_E ( vbi, pfx, False, Iop_Xor8, True, 1, delta, "xor" );
sewardjb095fba2005-02-13 14:13:04 +000015879 break;
sewardj118b23e2005-01-29 02:14:44 +000015880 case 0x31: /* XOR Gv,Ev */
sewardj03b07cc2005-01-31 18:09:43 +000015881 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000015882 delta = dis_op2_G_E ( vbi, pfx, False, Iop_Xor8, True, sz, delta, "xor" );
sewardj118b23e2005-01-29 02:14:44 +000015883 break;
sewardj354e5c62005-01-27 20:12:52 +000015884
15885 case 0x38: /* CMP Gb,Eb */
15886 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000015887 delta = dis_op2_G_E ( vbi, pfx, False, Iop_Sub8, False, 1, delta, "cmp" );
sewardj354e5c62005-01-27 20:12:52 +000015888 break;
15889 case 0x39: /* CMP Gv,Ev */
15890 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000015891 delta = dis_op2_G_E ( vbi, pfx, False, Iop_Sub8, False, sz, delta, "cmp" );
sewardj354e5c62005-01-27 20:12:52 +000015892 break;
15893
sewardj55dbb262005-01-28 16:36:51 +000015894 /* ------------------------ POP ------------------------ */
15895
15896 case 0x58: /* POP eAX */
15897 case 0x59: /* POP eCX */
15898 case 0x5A: /* POP eDX */
15899 case 0x5B: /* POP eBX */
15900 case 0x5D: /* POP eBP */
15901 case 0x5E: /* POP eSI */
15902 case 0x5F: /* POP eDI */
15903 case 0x5C: /* POP eSP */
sewardj03b07cc2005-01-31 18:09:43 +000015904 if (haveF2orF3(pfx)) goto decode_failure;
sewardj55dbb262005-01-28 16:36:51 +000015905 vassert(sz == 2 || sz == 4 || sz == 8);
15906 if (sz == 4)
15907 sz = 8; /* there is no encoding for 32-bit pop in 64-bit mode */
15908 t1 = newTemp(szToITy(sz));
15909 t2 = newTemp(Ity_I64);
15910 assign(t2, getIReg64(R_RSP));
15911 assign(t1, loadLE(szToITy(sz),mkexpr(t2)));
15912 putIReg64(R_RSP, binop(Iop_Add64, mkexpr(t2), mkU64(sz)));
sewardj5b470602005-02-27 13:10:48 +000015913 putIRegRexB(sz, pfx, opc-0x58, mkexpr(t1));
15914 DIP("pop%c %s\n", nameISize(sz), nameIRegRexB(sz,pfx,opc-0x58));
sewardj55dbb262005-01-28 16:36:51 +000015915 break;
15916
sewardj85520e42005-02-19 15:22:38 +000015917 case 0x9D: /* POPF */
15918 /* Note. There is no encoding for a 32-bit popf in 64-bit mode.
15919 So sz==4 actually means sz==8. */
sewardj5b470602005-02-27 13:10:48 +000015920 if (haveF2orF3(pfx)) goto decode_failure;
sewardj85520e42005-02-19 15:22:38 +000015921 vassert(sz == 2 || sz == 4);
15922 if (sz == 4) sz = 8;
sewardj5b470602005-02-27 13:10:48 +000015923 if (sz != 8) goto decode_failure; // until we know a sz==2 test case exists
sewardj85520e42005-02-19 15:22:38 +000015924 t1 = newTemp(Ity_I64); t2 = newTemp(Ity_I64);
15925 assign(t2, getIReg64(R_RSP));
15926 assign(t1, widenUto64(loadLE(szToITy(sz),mkexpr(t2))));
15927 putIReg64(R_RSP, binop(Iop_Add64, mkexpr(t2), mkU64(sz)));
15928 /* t1 is the flag word. Mask out everything except OSZACP and
15929 set the flags thunk to AMD64G_CC_OP_COPY. */
15930 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(AMD64G_CC_OP_COPY) ));
15931 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
15932 stmt( IRStmt_Put( OFFB_CC_DEP1,
15933 binop(Iop_And64,
15934 mkexpr(t1),
15935 mkU64( AMD64G_CC_MASK_C | AMD64G_CC_MASK_P
15936 | AMD64G_CC_MASK_A | AMD64G_CC_MASK_Z
15937 | AMD64G_CC_MASK_S| AMD64G_CC_MASK_O )
15938 )
15939 )
15940 );
15941
15942 /* Also need to set the D flag, which is held in bit 10 of t1.
15943 If zero, put 1 in OFFB_DFLAG, else -1 in OFFB_DFLAG. */
15944 stmt( IRStmt_Put(
15945 OFFB_DFLAG,
15946 IRExpr_Mux0X(
15947 unop(Iop_32to8,
15948 unop(Iop_64to32,
15949 binop(Iop_And64,
15950 binop(Iop_Shr64, mkexpr(t1), mkU8(10)),
15951 mkU64(1)))),
15952 mkU64(1),
15953 mkU64(0xFFFFFFFFFFFFFFFFULL)))
15954 );
15955
15956 /* And set the ID flag */
15957 stmt( IRStmt_Put(
15958 OFFB_IDFLAG,
15959 IRExpr_Mux0X(
15960 unop(Iop_32to8,
15961 unop(Iop_64to32,
15962 binop(Iop_And64,
15963 binop(Iop_Shr64, mkexpr(t1), mkU8(21)),
15964 mkU64(1)))),
15965 mkU64(0),
15966 mkU64(1)))
15967 );
15968
15969 DIP("popf%c\n", nameISize(sz));
15970 break;
15971
sewardjd20c8852005-01-20 20:04:07 +000015972//.. case 0x61: /* POPA */
15973//.. /* This is almost certainly wrong for sz==2. So ... */
15974//.. if (sz != 4) goto decode_failure;
15975//..
15976//.. /* t5 is the old %ESP value. */
15977//.. t5 = newTemp(Ity_I32);
15978//.. assign( t5, getIReg(4, R_ESP) );
15979//..
15980//.. /* Reload all the registers, except %esp. */
15981//.. putIReg(4,R_EAX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(28)) ));
15982//.. putIReg(4,R_ECX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(24)) ));
15983//.. putIReg(4,R_EDX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(20)) ));
15984//.. putIReg(4,R_EBX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(16)) ));
15985//.. /* ignore saved %ESP */
15986//.. putIReg(4,R_EBP, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32( 8)) ));
15987//.. putIReg(4,R_ESI, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32( 4)) ));
15988//.. putIReg(4,R_EDI, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32( 0)) ));
15989//..
15990//.. /* and move %ESP back up */
15991//.. putIReg( 4, R_ESP, binop(Iop_Add32, mkexpr(t5), mkU32(8*4)) );
15992//..
15993//.. DIP("pusha%c\n", nameISize(sz));
15994//.. break;
sewardj432f8b62005-05-10 02:50:05 +000015995
15996 case 0x8F: { /* POPQ m64 / POPW m16 */
sewardj1bd14e72005-05-11 16:24:00 +000015997 Int len;
15998 UChar rm;
sewardj432f8b62005-05-10 02:50:05 +000015999 /* There is no encoding for 32-bit pop in 64-bit mode.
16000 So sz==4 actually means sz==8. */
16001 if (haveF2orF3(pfx)) goto decode_failure;
16002 vassert(sz == 2 || sz == 4);
16003 if (sz == 4) sz = 8;
16004 if (sz != 8) goto decode_failure; // until we know a sz==2 test case exists
16005
sewardj1bd14e72005-05-11 16:24:00 +000016006 rm = getUChar(delta);
sewardj432f8b62005-05-10 02:50:05 +000016007
16008 /* make sure this instruction is correct POP */
16009 if (epartIsReg(rm) || gregLO3ofRM(rm) != 0)
16010 goto decode_failure;
16011 /* and has correct size */
16012 vassert(sz == 8);
16013
16014 t1 = newTemp(Ity_I64);
16015 t3 = newTemp(Ity_I64);
16016 assign( t1, getIReg64(R_RSP) );
16017 assign( t3, loadLE(Ity_I64, mkexpr(t1)) );
16018
16019 /* Increase RSP; must be done before the STORE. Intel manual
16020 says: If the RSP register is used as a base register for
16021 addressing a destination operand in memory, the POP
16022 instruction computes the effective address of the operand
16023 after it increments the RSP register. */
16024 putIReg64(R_RSP, binop(Iop_Add64, mkexpr(t1), mkU64(sz)) );
16025
sewardj2e28ac42008-12-04 00:05:12 +000016026 addr = disAMode ( &len, vbi, pfx, delta, dis_buf, 0 );
sewardj432f8b62005-05-10 02:50:05 +000016027 storeLE( mkexpr(addr), mkexpr(t3) );
16028
16029 DIP("popl %s\n", dis_buf);
16030
16031 delta += len;
16032 break;
16033 }
16034
sewardjd20c8852005-01-20 20:04:07 +000016035//.. //-- case 0x1F: /* POP %DS */
16036//.. //-- dis_pop_segreg( cb, R_DS, sz ); break;
16037//.. //-- case 0x07: /* POP %ES */
16038//.. //-- dis_pop_segreg( cb, R_ES, sz ); break;
16039//.. //-- case 0x17: /* POP %SS */
16040//.. //-- dis_pop_segreg( cb, R_SS, sz ); break;
sewardj55dbb262005-01-28 16:36:51 +000016041
16042 /* ------------------------ PUSH ----------------------- */
16043
16044 case 0x50: /* PUSH eAX */
16045 case 0x51: /* PUSH eCX */
16046 case 0x52: /* PUSH eDX */
16047 case 0x53: /* PUSH eBX */
16048 case 0x55: /* PUSH eBP */
16049 case 0x56: /* PUSH eSI */
16050 case 0x57: /* PUSH eDI */
16051 case 0x54: /* PUSH eSP */
16052 /* This is the Right Way, in that the value to be pushed is
16053 established before %rsp is changed, so that pushq %rsp
16054 correctly pushes the old value. */
sewardj03b07cc2005-01-31 18:09:43 +000016055 if (haveF2orF3(pfx)) goto decode_failure;
sewardj55dbb262005-01-28 16:36:51 +000016056 vassert(sz == 2 || sz == 4 || sz == 8);
16057 if (sz == 4)
16058 sz = 8; /* there is no encoding for 32-bit push in 64-bit mode */
16059 ty = sz==2 ? Ity_I16 : Ity_I64;
16060 t1 = newTemp(ty);
16061 t2 = newTemp(Ity_I64);
sewardj5b470602005-02-27 13:10:48 +000016062 assign(t1, getIRegRexB(sz, pfx, opc-0x50));
sewardj55dbb262005-01-28 16:36:51 +000016063 assign(t2, binop(Iop_Sub64, getIReg64(R_RSP), mkU64(sz)));
16064 putIReg64(R_RSP, mkexpr(t2) );
16065 storeLE(mkexpr(t2),mkexpr(t1));
sewardj5b470602005-02-27 13:10:48 +000016066 DIP("push%c %s\n", nameISize(sz), nameIRegRexB(sz,pfx,opc-0x50));
sewardj55dbb262005-01-28 16:36:51 +000016067 break;
16068
sewardja6b93d12005-02-17 09:28:28 +000016069 case 0x68: /* PUSH Iv */
sewardj5b470602005-02-27 13:10:48 +000016070 if (haveF2orF3(pfx)) goto decode_failure;
sewardja6b93d12005-02-17 09:28:28 +000016071 /* Note, sz==4 is not possible in 64-bit mode. Hence ... */
16072 if (sz == 4) sz = 8;
16073 d64 = getSDisp(imin(4,sz),delta);
16074 delta += imin(4,sz);
16075 goto do_push_I;
sewardj909c06d2005-02-19 22:47:41 +000016076 case 0x6A: /* PUSH Ib, sign-extended to sz */
sewardj5b470602005-02-27 13:10:48 +000016077 if (haveF2orF3(pfx)) goto decode_failure;
sewardj909c06d2005-02-19 22:47:41 +000016078 /* Note, sz==4 is not possible in 64-bit mode. Hence ... */
16079 if (sz == 4) sz = 8;
16080 d64 = getSDisp8(delta); delta += 1;
16081 goto do_push_I;
sewardja6b93d12005-02-17 09:28:28 +000016082 do_push_I:
16083 ty = szToITy(sz);
sewardj909c06d2005-02-19 22:47:41 +000016084 t1 = newTemp(Ity_I64);
16085 t2 = newTemp(ty);
sewardja6b93d12005-02-17 09:28:28 +000016086 assign( t1, binop(Iop_Sub64,getIReg64(R_RSP),mkU64(sz)) );
16087 putIReg64(R_RSP, mkexpr(t1) );
sewardjb2da8ec2006-08-28 18:54:18 +000016088 /* stop mkU16 asserting if d32 is a negative 16-bit number
16089 (bug #132813) */
16090 if (ty == Ity_I16)
16091 d64 &= 0xFFFF;
sewardja6b93d12005-02-17 09:28:28 +000016092 storeLE( mkexpr(t1), mkU(ty,d64) );
sewardj1027dc22005-02-26 01:55:02 +000016093 DIP("push%c $%lld\n", nameISize(sz), (Long)d64);
sewardja6b93d12005-02-17 09:28:28 +000016094 break;
16095
sewardj85520e42005-02-19 15:22:38 +000016096 case 0x9C: /* PUSHF */ {
16097 /* Note. There is no encoding for a 32-bit pushf in 64-bit
16098 mode. So sz==4 actually means sz==8. */
sewardj11faabe2006-07-24 09:09:36 +000016099 /* 24 July 06: has also been seen with a redundant REX prefix,
16100 so must also allow sz==8. */
sewardj5b470602005-02-27 13:10:48 +000016101 if (haveF2orF3(pfx)) goto decode_failure;
sewardj11faabe2006-07-24 09:09:36 +000016102 vassert(sz == 2 || sz == 4 || sz == 8);
sewardj85520e42005-02-19 15:22:38 +000016103 if (sz == 4) sz = 8;
sewardj5b470602005-02-27 13:10:48 +000016104 if (sz != 8) goto decode_failure; // until we know a sz==2 test case exists
sewardj85520e42005-02-19 15:22:38 +000016105
16106 t1 = newTemp(Ity_I64);
16107 assign( t1, binop(Iop_Sub64,getIReg64(R_RSP),mkU64(sz)) );
16108 putIReg64(R_RSP, mkexpr(t1) );
16109
16110 t2 = newTemp(Ity_I64);
16111 assign( t2, mk_amd64g_calculate_rflags_all() );
16112
16113 /* Patch in the D flag. This can simply be a copy of bit 10 of
16114 baseBlock[OFFB_DFLAG]. */
16115 t3 = newTemp(Ity_I64);
16116 assign( t3, binop(Iop_Or64,
16117 mkexpr(t2),
16118 binop(Iop_And64,
16119 IRExpr_Get(OFFB_DFLAG,Ity_I64),
16120 mkU64(1<<10)))
16121 );
16122
16123 /* And patch in the ID flag. */
16124 t4 = newTemp(Ity_I64);
16125 assign( t4, binop(Iop_Or64,
16126 mkexpr(t3),
16127 binop(Iop_And64,
16128 binop(Iop_Shl64, IRExpr_Get(OFFB_IDFLAG,Ity_I64),
16129 mkU8(21)),
16130 mkU64(1<<21)))
16131 );
16132
16133 /* if sz==2, the stored value needs to be narrowed. */
16134 if (sz == 2)
16135 storeLE( mkexpr(t1), unop(Iop_32to16,
16136 unop(Iop_64to32,mkexpr(t4))) );
16137 else
16138 storeLE( mkexpr(t1), mkexpr(t4) );
16139
16140 DIP("pushf%c\n", nameISize(sz));
16141 break;
16142 }
16143
sewardjd20c8852005-01-20 20:04:07 +000016144//.. case 0x60: /* PUSHA */
16145//.. /* This is almost certainly wrong for sz==2. So ... */
16146//.. if (sz != 4) goto decode_failure;
16147//..
16148//.. /* This is the Right Way, in that the value to be pushed is
16149//.. established before %esp is changed, so that pusha
16150//.. correctly pushes the old %esp value. New value of %esp is
16151//.. pushed at start. */
16152//.. /* t0 is the %ESP value we're going to push. */
16153//.. t0 = newTemp(Ity_I32);
16154//.. assign( t0, getIReg(4, R_ESP) );
16155//..
16156//.. /* t5 will be the new %ESP value. */
16157//.. t5 = newTemp(Ity_I32);
16158//.. assign( t5, binop(Iop_Sub32, mkexpr(t0), mkU32(8*4)) );
16159//..
16160//.. /* Update guest state before prodding memory. */
16161//.. putIReg(4, R_ESP, mkexpr(t5));
16162//..
16163//.. /* Dump all the registers. */
16164//.. storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(28)), getIReg(4,R_EAX) );
16165//.. storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(24)), getIReg(4,R_ECX) );
16166//.. storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(20)), getIReg(4,R_EDX) );
16167//.. storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(16)), getIReg(4,R_EBX) );
16168//.. storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(12)), mkexpr(t0) /*esp*/);
16169//.. storeLE( binop(Iop_Add32,mkexpr(t5),mkU32( 8)), getIReg(4,R_EBP) );
16170//.. storeLE( binop(Iop_Add32,mkexpr(t5),mkU32( 4)), getIReg(4,R_ESI) );
16171//.. storeLE( binop(Iop_Add32,mkexpr(t5),mkU32( 0)), getIReg(4,R_EDI) );
16172//..
16173//.. DIP("pusha%c\n", nameISize(sz));
16174//.. break;
16175//..
16176//..
16177//.. //-- case 0x0E: /* PUSH %CS */
16178//.. //-- dis_push_segreg( cb, R_CS, sz ); break;
16179//.. //-- case 0x1E: /* PUSH %DS */
16180//.. //-- dis_push_segreg( cb, R_DS, sz ); break;
16181//.. //-- case 0x06: /* PUSH %ES */
16182//.. //-- dis_push_segreg( cb, R_ES, sz ); break;
16183//.. //-- case 0x16: /* PUSH %SS */
16184//.. //-- dis_push_segreg( cb, R_SS, sz ); break;
16185//..
16186//.. /* ------------------------ SCAS et al ----------------- */
16187//..
16188//.. case 0xA4: /* MOVS, no REP prefix */
16189//.. case 0xA5:
16190//.. dis_string_op( dis_MOVS, ( opc == 0xA4 ? 1 : sz ), "movs", sorb );
16191//.. break;
16192//..
16193//.. case 0xA6: /* CMPSb, no REP prefix */
16194//.. //-- case 0xA7:
16195//.. dis_string_op( dis_CMPS, ( opc == 0xA6 ? 1 : sz ), "cmps", sorb );
16196//.. break;
16197//.. //--
sewardjd20c8852005-01-20 20:04:07 +000016198//.. //--
sewardj0f99be62009-07-22 09:29:13 +000016199 case 0xAC: /* LODS, no REP prefix */
16200 case 0xAD:
16201 dis_string_op( dis_LODS, ( opc == 0xAC ? 1 : sz ), "lods", pfx );
16202 break;
sewardjd20c8852005-01-20 20:04:07 +000016203//..
16204//.. case 0xAE: /* SCAS, no REP prefix */
16205//.. case 0xAF:
16206//.. dis_string_op( dis_SCAS, ( opc == 0xAE ? 1 : sz ), "scas", sorb );
16207//.. break;
sewardjd0a12df2005-02-10 02:07:43 +000016208
16209
16210 case 0xFC: /* CLD */
sewardj5b470602005-02-27 13:10:48 +000016211 if (haveF2orF3(pfx)) goto decode_failure;
sewardjd0a12df2005-02-10 02:07:43 +000016212 stmt( IRStmt_Put( OFFB_DFLAG, mkU64(1)) );
16213 DIP("cld\n");
16214 break;
16215
sewardj909c06d2005-02-19 22:47:41 +000016216 case 0xFD: /* STD */
sewardj5b470602005-02-27 13:10:48 +000016217 if (haveF2orF3(pfx)) goto decode_failure;
sewardj909c06d2005-02-19 22:47:41 +000016218 stmt( IRStmt_Put( OFFB_DFLAG, mkU64(-1ULL)) );
16219 DIP("std\n");
16220 break;
16221
sewardj31804462006-05-12 20:15:33 +000016222 case 0xF8: /* CLC */
16223 case 0xF9: /* STC */
16224 case 0xF5: /* CMC */
16225 t0 = newTemp(Ity_I64);
16226 t1 = newTemp(Ity_I64);
16227 assign( t0, mk_amd64g_calculate_rflags_all() );
16228 switch (opc) {
16229 case 0xF8:
16230 assign( t1, binop(Iop_And64, mkexpr(t0),
16231 mkU64(~AMD64G_CC_MASK_C)));
16232 DIP("clc\n");
16233 break;
16234 case 0xF9:
16235 assign( t1, binop(Iop_Or64, mkexpr(t0),
16236 mkU64(AMD64G_CC_MASK_C)));
16237 DIP("stc\n");
16238 break;
16239 case 0xF5:
16240 assign( t1, binop(Iop_Xor64, mkexpr(t0),
16241 mkU64(AMD64G_CC_MASK_C)));
16242 DIP("cmc\n");
16243 break;
16244 default:
16245 vpanic("disInstr(x64)(clc/stc/cmc)");
16246 }
16247 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(AMD64G_CC_OP_COPY) ));
16248 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
16249 stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(t1) ));
16250 /* Set NDEP even though it isn't used. This makes redundant-PUT
16251 elimination of previous stores to this field work better. */
16252 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU64(0) ));
16253 break;
16254
sewardjd20c8852005-01-20 20:04:07 +000016255//.. /* REPNE prefix insn */
16256//.. case 0xF2: {
16257//.. Addr32 eip_orig = guest_eip_bbstart + delta - 1;
16258//.. vassert(sorb == 0);
sewardj8c332e22005-01-28 01:36:56 +000016259//.. abyte = getUChar(delta); delta++;
sewardjd20c8852005-01-20 20:04:07 +000016260//..
sewardj8c332e22005-01-28 01:36:56 +000016261//.. if (abyte == 0x66) { sz = 2; abyte = getUChar(delta); delta++; }
sewardjd20c8852005-01-20 20:04:07 +000016262//.. whatNext = Dis_StopHere;
16263//..
16264//.. switch (abyte) {
16265//.. /* According to the Intel manual, "repne movs" should never occur, but
16266//.. * in practice it has happened, so allow for it here... */
16267//.. case 0xA4: sz = 1; /* REPNE MOVS<sz> */
16268//.. goto decode_failure;
16269//.. //-- case 0xA5:
16270//.. // dis_REP_op ( CondNZ, dis_MOVS, sz, eip_orig,
16271//.. // guest_eip_bbstart+delta, "repne movs" );
16272//.. // break;
16273//.. //--
16274//.. //-- case 0xA6: sz = 1; /* REPNE CMPS<sz> */
16275//.. //-- case 0xA7:
16276//.. //-- dis_REP_op ( cb, CondNZ, dis_CMPS, sz, eip_orig, eip, "repne cmps" );
16277//.. //-- break;
16278//.. //--
16279//.. case 0xAE: sz = 1; /* REPNE SCAS<sz> */
16280//.. case 0xAF:
16281//.. dis_REP_op ( X86CondNZ, dis_SCAS, sz, eip_orig,
16282//.. guest_eip_bbstart+delta, "repne scas" );
16283//.. break;
16284//..
16285//.. default:
16286//.. goto decode_failure;
16287//.. }
16288//.. break;
16289//.. }
sewardjd0a12df2005-02-10 02:07:43 +000016290
sewardj909c06d2005-02-19 22:47:41 +000016291 /* ------ AE: SCAS variants ------ */
16292 case 0xAE:
16293 case 0xAF:
16294 /* F2 AE/AF: repne scasb/repne scas{w,l,q} */
sewardj42561ef2005-11-04 14:18:31 +000016295 if (haveASO(pfx))
16296 goto decode_failure;
sewardj85520e42005-02-19 15:22:38 +000016297 if (haveF2(pfx) && !haveF3(pfx)) {
16298 if (opc == 0xAE)
16299 sz = 1;
16300 dis_REP_op ( AMD64CondNZ, dis_SCAS, sz,
sewardj9e6491a2005-07-02 19:24:10 +000016301 guest_RIP_curr_instr,
16302 guest_RIP_bbstart+delta, "repne scas", pfx );
16303 dres.whatNext = Dis_StopHere;
sewardj85520e42005-02-19 15:22:38 +000016304 break;
16305 }
sewardj7d8f1372008-11-08 15:25:00 +000016306 /* F3 AE/AF: repe scasb/repe scas{w,l,q} */
16307 if (haveASO(pfx))
16308 goto decode_failure;
16309 if (!haveF2(pfx) && haveF3(pfx)) {
16310 if (opc == 0xAE)
16311 sz = 1;
16312 dis_REP_op ( AMD64CondZ, dis_SCAS, sz,
16313 guest_RIP_curr_instr,
16314 guest_RIP_bbstart+delta, "repe scas", pfx );
16315 dres.whatNext = Dis_StopHere;
16316 break;
16317 }
sewardj909c06d2005-02-19 22:47:41 +000016318 /* AE/AF: scasb/scas{w,l,q} */
16319 if (!haveF2(pfx) && !haveF3(pfx)) {
16320 if (opc == 0xAE)
16321 sz = 1;
16322 dis_string_op( dis_SCAS, sz, "scas", pfx );
16323 break;
16324 }
sewardj85520e42005-02-19 15:22:38 +000016325 goto decode_failure;
sewardjd0a12df2005-02-10 02:07:43 +000016326
sewardj909c06d2005-02-19 22:47:41 +000016327 /* ------ A6, A7: CMPS variants ------ */
16328 case 0xA6:
16329 case 0xA7:
16330 /* F3 A6/A7: repe cmps/rep cmps{w,l,q} */
sewardj42561ef2005-11-04 14:18:31 +000016331 if (haveASO(pfx))
16332 goto decode_failure;
sewardjd0a12df2005-02-10 02:07:43 +000016333 if (haveF3(pfx) && !haveF2(pfx)) {
16334 if (opc == 0xA6)
16335 sz = 1;
16336 dis_REP_op ( AMD64CondZ, dis_CMPS, sz,
sewardj9e6491a2005-07-02 19:24:10 +000016337 guest_RIP_curr_instr,
16338 guest_RIP_bbstart+delta, "repe cmps", pfx );
16339 dres.whatNext = Dis_StopHere;
sewardja6b93d12005-02-17 09:28:28 +000016340 break;
16341 }
16342 goto decode_failure;
16343
sewardj909c06d2005-02-19 22:47:41 +000016344 /* ------ AA, AB: STOS variants ------ */
16345 case 0xAA:
16346 case 0xAB:
16347 /* F3 AA/AB: rep stosb/rep stos{w,l,q} */
sewardj42561ef2005-11-04 14:18:31 +000016348 if (haveASO(pfx))
16349 goto decode_failure;
sewardja6b93d12005-02-17 09:28:28 +000016350 if (haveF3(pfx) && !haveF2(pfx)) {
sewardj909c06d2005-02-19 22:47:41 +000016351 if (opc == 0xAA)
16352 sz = 1;
sewardja6b93d12005-02-17 09:28:28 +000016353 dis_REP_op ( AMD64CondAlways, dis_STOS, sz,
sewardj9e6491a2005-07-02 19:24:10 +000016354 guest_RIP_curr_instr,
16355 guest_RIP_bbstart+delta, "rep stos", pfx );
16356 dres.whatNext = Dis_StopHere;
sewardj909c06d2005-02-19 22:47:41 +000016357 break;
16358 }
16359 /* AA/AB: stosb/stos{w,l,q} */
16360 if (!haveF3(pfx) && !haveF2(pfx)) {
16361 if (opc == 0xAA)
16362 sz = 1;
16363 dis_string_op( dis_STOS, sz, "stos", pfx );
sewardjd0a12df2005-02-10 02:07:43 +000016364 break;
16365 }
16366 goto decode_failure;
16367
sewardj909c06d2005-02-19 22:47:41 +000016368 /* ------ A4, A5: MOVS variants ------ */
16369 case 0xA4:
16370 case 0xA5:
16371 /* F3 A4: rep movsb */
sewardj42561ef2005-11-04 14:18:31 +000016372 if (haveASO(pfx))
16373 goto decode_failure;
sewardj909c06d2005-02-19 22:47:41 +000016374 if (haveF3(pfx) && !haveF2(pfx)) {
16375 if (opc == 0xA4)
16376 sz = 1;
16377 dis_REP_op ( AMD64CondAlways, dis_MOVS, sz,
sewardj9e6491a2005-07-02 19:24:10 +000016378 guest_RIP_curr_instr,
16379 guest_RIP_bbstart+delta, "rep movs", pfx );
16380 dres.whatNext = Dis_StopHere;
sewardj909c06d2005-02-19 22:47:41 +000016381 break;
16382 }
16383 /* A4: movsb */
16384 if (!haveF3(pfx) && !haveF2(pfx)) {
16385 if (opc == 0xA4)
16386 sz = 1;
16387 dis_string_op( dis_MOVS, sz, "movs", pfx );
16388 break;
16389 }
16390 goto decode_failure;
16391
sewardj7de0d3c2005-02-13 02:26:41 +000016392
16393 /* ------------------------ XCHG ----------------------- */
16394
sewardjc4356f02007-11-09 21:15:04 +000016395 /* XCHG reg,mem automatically asserts LOCK# even without a LOCK
16396 prefix. Therefore, surround it with a IRStmt_MBE(Imbe_BusLock)
16397 and IRStmt_MBE(Imbe_BusUnlock) pair. But be careful; if it is
16398 used with an explicit LOCK prefix, we don't want to end up with
16399 two IRStmt_MBE(Imbe_BusLock)s -- one made here and one made by
16400 the generic LOCK logic at the top of disInstr. */
sewardj1bf95982005-05-18 12:04:04 +000016401 case 0x86: /* XCHG Gb,Eb */
16402 sz = 1;
16403 /* Fall through ... */
sewardj7de0d3c2005-02-13 02:26:41 +000016404 case 0x87: /* XCHG Gv,Ev */
sewardj5b470602005-02-27 13:10:48 +000016405 if (haveF2orF3(pfx)) goto decode_failure;
sewardj7de0d3c2005-02-13 02:26:41 +000016406 modrm = getUChar(delta);
16407 ty = szToITy(sz);
16408 t1 = newTemp(ty); t2 = newTemp(ty);
16409 if (epartIsReg(modrm)) {
sewardj5b470602005-02-27 13:10:48 +000016410 assign(t1, getIRegE(sz, pfx, modrm));
16411 assign(t2, getIRegG(sz, pfx, modrm));
16412 putIRegG(sz, pfx, modrm, mkexpr(t1));
16413 putIRegE(sz, pfx, modrm, mkexpr(t2));
sewardj7de0d3c2005-02-13 02:26:41 +000016414 delta++;
16415 DIP("xchg%c %s, %s\n",
sewardj5b470602005-02-27 13:10:48 +000016416 nameISize(sz), nameIRegG(sz, pfx, modrm),
16417 nameIRegE(sz, pfx, modrm));
sewardj7de0d3c2005-02-13 02:26:41 +000016418 } else {
sewardje9d8a262009-07-01 08:06:34 +000016419 *expect_CAS = True;
sewardj2e28ac42008-12-04 00:05:12 +000016420 addr = disAMode ( &alen, vbi, pfx, delta, dis_buf, 0 );
sewardj5b470602005-02-27 13:10:48 +000016421 assign( t1, loadLE(ty, mkexpr(addr)) );
16422 assign( t2, getIRegG(sz, pfx, modrm) );
sewardje9d8a262009-07-01 08:06:34 +000016423 casLE( mkexpr(addr),
16424 mkexpr(t1), mkexpr(t2), guest_RIP_curr_instr );
sewardj5b470602005-02-27 13:10:48 +000016425 putIRegG( sz, pfx, modrm, mkexpr(t1) );
sewardj7de0d3c2005-02-13 02:26:41 +000016426 delta += alen;
16427 DIP("xchg%c %s, %s\n", nameISize(sz),
sewardj5b470602005-02-27 13:10:48 +000016428 nameIRegG(sz, pfx, modrm), dis_buf);
sewardj7de0d3c2005-02-13 02:26:41 +000016429 }
16430 break;
sewardj118b23e2005-01-29 02:14:44 +000016431
16432 case 0x90: /* XCHG eAX,eAX */
sewardjc8b26352005-07-20 09:23:13 +000016433 /* detect and handle F3 90 (rep nop) specially */
16434 if (!have66(pfx) && !haveF2(pfx) && haveF3(pfx)) {
16435 DIP("rep nop (P4 pause)\n");
16436 /* "observe" the hint. The Vex client needs to be careful not
16437 to cause very long delays as a result, though. */
16438 jmp_lit(Ijk_Yield, guest_RIP_bbstart+delta);
16439 dres.whatNext = Dis_StopHere;
16440 break;
16441 }
sewardj2d4fcd52005-05-18 11:47:47 +000016442 /* detect and handle NOPs specially */
16443 if (/* F2/F3 probably change meaning completely */
16444 !haveF2orF3(pfx)
16445 /* If REX.B is 1, we're not exchanging rAX with itself */
16446 && getRexB(pfx)==0 ) {
16447 DIP("nop\n");
16448 break;
16449 }
16450 /* else fall through to normal case. */
sewardja6b93d12005-02-17 09:28:28 +000016451 case 0x91: /* XCHG rAX,rCX */
16452 case 0x92: /* XCHG rAX,rDX */
16453 case 0x93: /* XCHG rAX,rBX */
16454 case 0x94: /* XCHG rAX,rSP */
16455 case 0x95: /* XCHG rAX,rBP */
16456 case 0x96: /* XCHG rAX,rSI */
16457 case 0x97: /* XCHG rAX,rDI */
sewardj2d4fcd52005-05-18 11:47:47 +000016458
16459 /* guard against mutancy */
sewardja6b93d12005-02-17 09:28:28 +000016460 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2d4fcd52005-05-18 11:47:47 +000016461
16462 /* sz == 2 could legitimately happen, but we don't handle it yet */
16463 if (sz == 2) goto decode_failure; /* awaiting test case */
16464
sewardja6b93d12005-02-17 09:28:28 +000016465 codegen_xchg_rAX_Reg ( pfx, sz, opc - 0x90 );
16466 break;
16467
sewardjd20c8852005-01-20 20:04:07 +000016468//.. //-- /* ------------------------ XLAT ----------------------- */
16469//.. //--
16470//.. //-- case 0xD7: /* XLAT */
16471//.. //-- t1 = newTemp(cb); t2 = newTemp(cb);
16472//.. //-- uInstr2(cb, GET, sz, ArchReg, R_EBX, TempReg, t1); /* get eBX */
sewardj42561ef2005-11-04 14:18:31 +000016473//.. //-- handleAddrOverrides( cb, sorb, t1 ); /* make t1 DS:eBX */
sewardjd20c8852005-01-20 20:04:07 +000016474//.. //-- uInstr2(cb, GET, 1, ArchReg, R_AL, TempReg, t2); /* get AL */
16475//.. //-- /* Widen %AL to 32 bits, so it's all defined when we add it. */
16476//.. //-- uInstr1(cb, WIDEN, 4, TempReg, t2);
16477//.. //-- uWiden(cb, 1, False);
16478//.. //-- uInstr2(cb, ADD, sz, TempReg, t2, TempReg, t1); /* add AL to eBX */
16479//.. //-- uInstr2(cb, LOAD, 1, TempReg, t1, TempReg, t2); /* get byte at t1 into t2 */
16480//.. //-- uInstr2(cb, PUT, 1, TempReg, t2, ArchReg, R_AL); /* put byte into AL */
16481//.. //--
16482//.. //-- DIP("xlat%c [ebx]\n", nameISize(sz));
16483//.. //-- break;
sewardjbb4396c2007-11-20 17:29:08 +000016484
16485 /* ------------------------ IN / OUT ----------------------- */
16486
16487 case 0xE4: /* IN imm8, AL */
16488 sz = 1;
16489 t1 = newTemp(Ity_I64);
16490 abyte = getUChar(delta); delta++;
16491 assign(t1, mkU64( abyte & 0xFF ));
16492 DIP("in%c $%d,%s\n", nameISize(sz), (Int)abyte, nameIRegRAX(sz));
16493 goto do_IN;
16494 case 0xE5: /* IN imm8, eAX */
16495 if (!(sz == 2 || sz == 4)) goto decode_failure;
16496 t1 = newTemp(Ity_I64);
16497 abyte = getUChar(delta); delta++;
16498 assign(t1, mkU64( abyte & 0xFF ));
16499 DIP("in%c $%d,%s\n", nameISize(sz), (Int)abyte, nameIRegRAX(sz));
16500 goto do_IN;
16501 case 0xEC: /* IN %DX, AL */
16502 sz = 1;
16503 t1 = newTemp(Ity_I64);
16504 assign(t1, unop(Iop_16Uto64, getIRegRDX(2)));
16505 DIP("in%c %s,%s\n", nameISize(sz), nameIRegRDX(2),
16506 nameIRegRAX(sz));
16507 goto do_IN;
16508 case 0xED: /* IN %DX, eAX */
16509 if (!(sz == 2 || sz == 4)) goto decode_failure;
16510 t1 = newTemp(Ity_I64);
16511 assign(t1, unop(Iop_16Uto64, getIRegRDX(2)));
16512 DIP("in%c %s,%s\n", nameISize(sz), nameIRegRDX(2),
16513 nameIRegRAX(sz));
16514 goto do_IN;
16515 do_IN: {
16516 /* At this point, sz indicates the width, and t1 is a 64-bit
16517 value giving port number. */
16518 IRDirty* d;
16519 if (haveF2orF3(pfx)) goto decode_failure;
16520 vassert(sz == 1 || sz == 2 || sz == 4);
16521 ty = szToITy(sz);
16522 t2 = newTemp(Ity_I64);
16523 d = unsafeIRDirty_1_N(
16524 t2,
16525 0/*regparms*/,
16526 "amd64g_dirtyhelper_IN",
16527 &amd64g_dirtyhelper_IN,
16528 mkIRExprVec_2( mkexpr(t1), mkU64(sz) )
16529 );
16530 /* do the call, dumping the result in t2. */
16531 stmt( IRStmt_Dirty(d) );
16532 putIRegRAX(sz, narrowTo( ty, mkexpr(t2) ) );
16533 break;
16534 }
16535
16536 case 0xE6: /* OUT AL, imm8 */
16537 sz = 1;
16538 t1 = newTemp(Ity_I64);
16539 abyte = getUChar(delta); delta++;
16540 assign( t1, mkU64( abyte & 0xFF ) );
16541 DIP("out%c %s,$%d\n", nameISize(sz), nameIRegRAX(sz), (Int)abyte);
16542 goto do_OUT;
16543 case 0xE7: /* OUT eAX, imm8 */
16544 if (!(sz == 2 || sz == 4)) goto decode_failure;
16545 t1 = newTemp(Ity_I64);
16546 abyte = getUChar(delta); delta++;
16547 assign( t1, mkU64( abyte & 0xFF ) );
16548 DIP("out%c %s,$%d\n", nameISize(sz), nameIRegRAX(sz), (Int)abyte);
16549 goto do_OUT;
16550 case 0xEE: /* OUT AL, %DX */
16551 sz = 1;
16552 t1 = newTemp(Ity_I64);
16553 assign( t1, unop(Iop_16Uto64, getIRegRDX(2)) );
16554 DIP("out%c %s,%s\n", nameISize(sz), nameIRegRAX(sz),
16555 nameIRegRDX(2));
16556 goto do_OUT;
16557 case 0xEF: /* OUT eAX, %DX */
16558 if (!(sz == 2 || sz == 4)) goto decode_failure;
16559 t1 = newTemp(Ity_I64);
16560 assign( t1, unop(Iop_16Uto64, getIRegRDX(2)) );
16561 DIP("out%c %s,%s\n", nameISize(sz), nameIRegRAX(sz),
16562 nameIRegRDX(2));
16563 goto do_OUT;
16564 do_OUT: {
16565 /* At this point, sz indicates the width, and t1 is a 64-bit
16566 value giving port number. */
16567 IRDirty* d;
16568 if (haveF2orF3(pfx)) goto decode_failure;
16569 vassert(sz == 1 || sz == 2 || sz == 4);
16570 ty = szToITy(sz);
16571 d = unsafeIRDirty_0_N(
16572 0/*regparms*/,
16573 "amd64g_dirtyhelper_OUT",
16574 &amd64g_dirtyhelper_OUT,
16575 mkIRExprVec_3( mkexpr(t1),
16576 widenUto64( getIRegRAX(sz) ),
16577 mkU64(sz) )
16578 );
16579 stmt( IRStmt_Dirty(d) );
16580 break;
16581 }
sewardj3ca55a12005-01-27 16:06:23 +000016582
16583 /* ------------------------ (Grp1 extensions) ---------- */
16584
16585 case 0x80: /* Grp1 Ib,Eb */
sewardj5b470602005-02-27 13:10:48 +000016586 if (haveF2orF3(pfx)) goto decode_failure;
sewardj8c332e22005-01-28 01:36:56 +000016587 modrm = getUChar(delta);
sewardj3ca55a12005-01-27 16:06:23 +000016588 am_sz = lengthAMode(pfx,delta);
16589 sz = 1;
16590 d_sz = 1;
16591 d64 = getSDisp8(delta + am_sz);
sewardj2e28ac42008-12-04 00:05:12 +000016592 delta = dis_Grp1 ( vbi, pfx, delta, modrm, am_sz, d_sz, sz, d64 );
sewardj3ca55a12005-01-27 16:06:23 +000016593 break;
16594
16595 case 0x81: /* Grp1 Iv,Ev */
16596 if (haveF2orF3(pfx)) goto decode_failure;
sewardj8c332e22005-01-28 01:36:56 +000016597 modrm = getUChar(delta);
sewardj3ca55a12005-01-27 16:06:23 +000016598 am_sz = lengthAMode(pfx,delta);
16599 d_sz = imin(sz,4);
16600 d64 = getSDisp(d_sz, delta + am_sz);
sewardj2e28ac42008-12-04 00:05:12 +000016601 delta = dis_Grp1 ( vbi, pfx, delta, modrm, am_sz, d_sz, sz, d64 );
sewardj3ca55a12005-01-27 16:06:23 +000016602 break;
16603
16604 case 0x83: /* Grp1 Ib,Ev */
16605 if (haveF2orF3(pfx)) goto decode_failure;
sewardj8c332e22005-01-28 01:36:56 +000016606 modrm = getUChar(delta);
sewardj3ca55a12005-01-27 16:06:23 +000016607 am_sz = lengthAMode(pfx,delta);
16608 d_sz = 1;
16609 d64 = getSDisp8(delta + am_sz);
sewardj2e28ac42008-12-04 00:05:12 +000016610 delta = dis_Grp1 ( vbi, pfx, delta, modrm, am_sz, d_sz, sz, d64 );
sewardj3ca55a12005-01-27 16:06:23 +000016611 break;
16612
sewardj118b23e2005-01-29 02:14:44 +000016613 /* ------------------------ (Grp2 extensions) ---------- */
sewardj03b07cc2005-01-31 18:09:43 +000016614
sewardjfd4203c2007-03-21 00:21:56 +000016615 case 0xC0: { /* Grp2 Ib,Eb */
16616 Bool decode_OK = True;
sewardj5b470602005-02-27 13:10:48 +000016617 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000016618 modrm = getUChar(delta);
16619 am_sz = lengthAMode(pfx,delta);
16620 d_sz = 1;
16621 d64 = getUChar(delta + am_sz);
16622 sz = 1;
sewardj2e28ac42008-12-04 00:05:12 +000016623 delta = dis_Grp2 ( vbi, pfx, delta, modrm, am_sz, d_sz, sz,
sewardjfd4203c2007-03-21 00:21:56 +000016624 mkU8(d64 & 0xFF), NULL, &decode_OK );
16625 if (!decode_OK) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000016626 break;
sewardjfd4203c2007-03-21 00:21:56 +000016627 }
16628 case 0xC1: { /* Grp2 Ib,Ev */
16629 Bool decode_OK = True;
sewardj5b470602005-02-27 13:10:48 +000016630 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000016631 modrm = getUChar(delta);
16632 am_sz = lengthAMode(pfx,delta);
16633 d_sz = 1;
16634 d64 = getUChar(delta + am_sz);
sewardj2e28ac42008-12-04 00:05:12 +000016635 delta = dis_Grp2 ( vbi, pfx, delta, modrm, am_sz, d_sz, sz,
sewardjfd4203c2007-03-21 00:21:56 +000016636 mkU8(d64 & 0xFF), NULL, &decode_OK );
16637 if (!decode_OK) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000016638 break;
sewardjfd4203c2007-03-21 00:21:56 +000016639 }
16640 case 0xD0: { /* Grp2 1,Eb */
16641 Bool decode_OK = True;
sewardj5b470602005-02-27 13:10:48 +000016642 if (haveF2orF3(pfx)) goto decode_failure;
sewardj03b07cc2005-01-31 18:09:43 +000016643 modrm = getUChar(delta);
16644 am_sz = lengthAMode(pfx,delta);
16645 d_sz = 0;
16646 d64 = 1;
16647 sz = 1;
sewardj2e28ac42008-12-04 00:05:12 +000016648 delta = dis_Grp2 ( vbi, pfx, delta, modrm, am_sz, d_sz, sz,
sewardjfd4203c2007-03-21 00:21:56 +000016649 mkU8(d64), NULL, &decode_OK );
16650 if (!decode_OK) goto decode_failure;
sewardj03b07cc2005-01-31 18:09:43 +000016651 break;
sewardjfd4203c2007-03-21 00:21:56 +000016652 }
16653 case 0xD1: { /* Grp2 1,Ev */
16654 Bool decode_OK = True;
sewardj5b470602005-02-27 13:10:48 +000016655 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000016656 modrm = getUChar(delta);
16657 am_sz = lengthAMode(pfx,delta);
16658 d_sz = 0;
16659 d64 = 1;
sewardj2e28ac42008-12-04 00:05:12 +000016660 delta = dis_Grp2 ( vbi, pfx, delta, modrm, am_sz, d_sz, sz,
sewardjfd4203c2007-03-21 00:21:56 +000016661 mkU8(d64), NULL, &decode_OK );
16662 if (!decode_OK) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000016663 break;
sewardjfd4203c2007-03-21 00:21:56 +000016664 }
16665 case 0xD2: { /* Grp2 CL,Eb */
16666 Bool decode_OK = True;
sewardj5b470602005-02-27 13:10:48 +000016667 if (haveF2orF3(pfx)) goto decode_failure;
sewardj85520e42005-02-19 15:22:38 +000016668 modrm = getUChar(delta);
16669 am_sz = lengthAMode(pfx,delta);
16670 d_sz = 0;
16671 sz = 1;
sewardj2e28ac42008-12-04 00:05:12 +000016672 delta = dis_Grp2 ( vbi, pfx, delta, modrm, am_sz, d_sz, sz,
sewardjfd4203c2007-03-21 00:21:56 +000016673 getIRegCL(), "%cl", &decode_OK );
16674 if (!decode_OK) goto decode_failure;
sewardj85520e42005-02-19 15:22:38 +000016675 break;
sewardjfd4203c2007-03-21 00:21:56 +000016676 }
16677 case 0xD3: { /* Grp2 CL,Ev */
16678 Bool decode_OK = True;
sewardj5b470602005-02-27 13:10:48 +000016679 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000016680 modrm = getUChar(delta);
16681 am_sz = lengthAMode(pfx,delta);
16682 d_sz = 0;
sewardj2e28ac42008-12-04 00:05:12 +000016683 delta = dis_Grp2 ( vbi, pfx, delta, modrm, am_sz, d_sz, sz,
sewardjfd4203c2007-03-21 00:21:56 +000016684 getIRegCL(), "%cl", &decode_OK );
16685 if (!decode_OK) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000016686 break;
sewardjfd4203c2007-03-21 00:21:56 +000016687 }
sewardj32b2bbe2005-01-28 00:50:10 +000016688
16689 /* ------------------------ (Grp3 extensions) ---------- */
16690
sewardjfd4203c2007-03-21 00:21:56 +000016691 case 0xF6: { /* Grp3 Eb */
16692 Bool decode_OK = True;
sewardj5b470602005-02-27 13:10:48 +000016693 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000016694 delta = dis_Grp3 ( vbi, pfx, 1, delta, &decode_OK );
sewardjfd4203c2007-03-21 00:21:56 +000016695 if (!decode_OK) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000016696 break;
sewardjfd4203c2007-03-21 00:21:56 +000016697 }
16698 case 0xF7: { /* Grp3 Ev */
16699 Bool decode_OK = True;
sewardj5b470602005-02-27 13:10:48 +000016700 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000016701 delta = dis_Grp3 ( vbi, pfx, sz, delta, &decode_OK );
sewardjfd4203c2007-03-21 00:21:56 +000016702 if (!decode_OK) goto decode_failure;
sewardj32b2bbe2005-01-28 00:50:10 +000016703 break;
sewardjfd4203c2007-03-21 00:21:56 +000016704 }
sewardj32b2bbe2005-01-28 00:50:10 +000016705
sewardj03b07cc2005-01-31 18:09:43 +000016706 /* ------------------------ (Grp4 extensions) ---------- */
16707
sewardjfd4203c2007-03-21 00:21:56 +000016708 case 0xFE: { /* Grp4 Eb */
16709 Bool decode_OK = True;
sewardj5b470602005-02-27 13:10:48 +000016710 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000016711 delta = dis_Grp4 ( vbi, pfx, delta, &decode_OK );
sewardjfd4203c2007-03-21 00:21:56 +000016712 if (!decode_OK) goto decode_failure;
sewardj03b07cc2005-01-31 18:09:43 +000016713 break;
sewardjfd4203c2007-03-21 00:21:56 +000016714 }
sewardj354e5c62005-01-27 20:12:52 +000016715
16716 /* ------------------------ (Grp5 extensions) ---------- */
16717
sewardjfd4203c2007-03-21 00:21:56 +000016718 case 0xFF: { /* Grp5 Ev */
16719 Bool decode_OK = True;
sewardj5b470602005-02-27 13:10:48 +000016720 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000016721 delta = dis_Grp5 ( vbi, pfx, sz, delta, &dres, &decode_OK );
sewardjfd4203c2007-03-21 00:21:56 +000016722 if (!decode_OK) goto decode_failure;
sewardj354e5c62005-01-27 20:12:52 +000016723 break;
sewardjfd4203c2007-03-21 00:21:56 +000016724 }
sewardj3ca55a12005-01-27 16:06:23 +000016725
16726 /* ------------------------ Escapes to 2-byte opcodes -- */
16727
16728 case 0x0F: {
sewardj8c332e22005-01-28 01:36:56 +000016729 opc = getUChar(delta); delta++;
sewardj3ca55a12005-01-27 16:06:23 +000016730 switch (opc) {
16731
sewardj1d511802005-03-27 17:59:45 +000016732 /* =-=-=-=-=-=-=-=-=- Grp8 =-=-=-=-=-=-=-=-=-=-=-= */
16733
16734 case 0xBA: { /* Grp8 Ib,Ev */
16735 Bool decode_OK = False;
16736 if (haveF2orF3(pfx)) goto decode_failure;
16737 modrm = getUChar(delta);
16738 am_sz = lengthAMode(pfx,delta);
16739 d64 = getSDisp8(delta + am_sz);
sewardj2e28ac42008-12-04 00:05:12 +000016740 delta = dis_Grp8_Imm ( vbi, pfx, delta, modrm, am_sz, sz, d64,
sewardj1d511802005-03-27 17:59:45 +000016741 &decode_OK );
16742 if (!decode_OK)
16743 goto decode_failure;
16744 break;
16745 }
16746
sewardjf53b7352005-04-06 20:01:56 +000016747 /* =-=-=-=-=-=-=-=-=- BSF/BSR -=-=-=-=-=-=-=-=-=-= */
16748
16749 case 0xBC: /* BSF Gv,Ev */
16750 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000016751 delta = dis_bs_E_G ( vbi, pfx, sz, delta, True );
sewardjf53b7352005-04-06 20:01:56 +000016752 break;
sewardj537cab02005-04-07 02:03:52 +000016753 case 0xBD: /* BSR Gv,Ev */
16754 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000016755 delta = dis_bs_E_G ( vbi, pfx, sz, delta, False );
sewardj537cab02005-04-07 02:03:52 +000016756 break;
sewardj82c9f2f2005-03-02 16:05:13 +000016757
16758 /* =-=-=-=-=-=-=-=-=- BSWAP -=-=-=-=-=-=-=-=-=-=-= */
16759
16760 case 0xC8: /* BSWAP %eax */
16761 case 0xC9:
16762 case 0xCA:
16763 case 0xCB:
16764 case 0xCC:
16765 case 0xCD:
16766 case 0xCE:
16767 case 0xCF: /* BSWAP %edi */
16768 if (haveF2orF3(pfx)) goto decode_failure;
16769 /* According to the AMD64 docs, this insn can have size 4 or
16770 8. */
16771 if (sz == 4) {
16772 t1 = newTemp(Ity_I32);
16773 t2 = newTemp(Ity_I32);
16774 assign( t1, getIRegRexB(4, pfx, opc-0xC8) );
16775 assign( t2,
16776 binop(Iop_Or32,
16777 binop(Iop_Shl32, mkexpr(t1), mkU8(24)),
16778 binop(Iop_Or32,
sewardj61408222006-08-16 00:25:28 +000016779 binop(Iop_And32, binop(Iop_Shl32, mkexpr(t1), mkU8(8)),
sewardj82c9f2f2005-03-02 16:05:13 +000016780 mkU32(0x00FF0000)),
16781 binop(Iop_Or32,
16782 binop(Iop_And32, binop(Iop_Shr32, mkexpr(t1), mkU8(8)),
16783 mkU32(0x0000FF00)),
16784 binop(Iop_And32, binop(Iop_Shr32, mkexpr(t1), mkU8(24)),
16785 mkU32(0x000000FF) )
16786 )))
16787 );
16788 putIRegRexB(4, pfx, opc-0xC8, mkexpr(t2));
16789 DIP("bswapl %s\n", nameIRegRexB(4, pfx, opc-0xC8));
16790 break;
sewardj98e9f342005-07-23 12:07:37 +000016791 }
16792 else if (sz == 8) {
sewardj61408222006-08-16 00:25:28 +000016793 IRTemp m8 = newTemp(Ity_I64);
16794 IRTemp s8 = newTemp(Ity_I64);
16795 IRTemp m16 = newTemp(Ity_I64);
16796 IRTemp s16 = newTemp(Ity_I64);
16797 IRTemp m32 = newTemp(Ity_I64);
sewardj98e9f342005-07-23 12:07:37 +000016798 t1 = newTemp(Ity_I64);
16799 t2 = newTemp(Ity_I64);
16800 assign( t1, getIRegRexB(8, pfx, opc-0xC8) );
16801
sewardj61408222006-08-16 00:25:28 +000016802 assign( m8, mkU64(0xFF00FF00FF00FF00ULL) );
16803 assign( s8,
16804 binop(Iop_Or64,
16805 binop(Iop_Shr64,
16806 binop(Iop_And64,mkexpr(t1),mkexpr(m8)),
16807 mkU8(8)),
16808 binop(Iop_And64,
16809 binop(Iop_Shl64,mkexpr(t1),mkU8(8)),
16810 mkexpr(m8))
16811 )
16812 );
sewardj98e9f342005-07-23 12:07:37 +000016813
sewardj61408222006-08-16 00:25:28 +000016814 assign( m16, mkU64(0xFFFF0000FFFF0000ULL) );
16815 assign( s16,
16816 binop(Iop_Or64,
16817 binop(Iop_Shr64,
16818 binop(Iop_And64,mkexpr(s8),mkexpr(m16)),
16819 mkU8(16)),
16820 binop(Iop_And64,
16821 binop(Iop_Shl64,mkexpr(s8),mkU8(16)),
16822 mkexpr(m16))
16823 )
16824 );
sewardj98e9f342005-07-23 12:07:37 +000016825
sewardj61408222006-08-16 00:25:28 +000016826 assign( m32, mkU64(0xFFFFFFFF00000000ULL) );
16827 assign( t2,
16828 binop(Iop_Or64,
16829 binop(Iop_Shr64,
16830 binop(Iop_And64,mkexpr(s16),mkexpr(m32)),
16831 mkU8(32)),
16832 binop(Iop_And64,
16833 binop(Iop_Shl64,mkexpr(s16),mkU8(32)),
16834 mkexpr(m32))
16835 )
16836 );
sewardj98e9f342005-07-23 12:07:37 +000016837
16838 putIRegRexB(8, pfx, opc-0xC8, mkexpr(t2));
16839 DIP("bswapq %s\n", nameIRegRexB(8, pfx, opc-0xC8));
16840 break;
sewardj82c9f2f2005-03-02 16:05:13 +000016841 } else {
16842 goto decode_failure;
16843 }
16844
sewardj9ed16802005-08-24 10:46:19 +000016845 /* =-=-=-=-=-=-=-=-=- BT/BTS/BTR/BTC =-=-=-=-=-=-= */
16846
sewardja7690fb2005-10-05 17:19:11 +000016847 /* All of these are possible at sizes 2, 4 and 8, but until a
16848 size 2 test case shows up, only handle sizes 4 and 8. */
sewardj9ed16802005-08-24 10:46:19 +000016849
16850 case 0xA3: /* BT Gv,Ev */
16851 if (haveF2orF3(pfx)) goto decode_failure;
sewardj25d23862006-05-12 17:47:21 +000016852 if (sz != 8 && sz != 4 && sz != 2) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000016853 delta = dis_bt_G_E ( vbi, pfx, sz, delta, BtOpNone );
sewardj9ed16802005-08-24 10:46:19 +000016854 break;
16855 case 0xB3: /* BTR Gv,Ev */
16856 if (haveF2orF3(pfx)) goto decode_failure;
sewardj25d23862006-05-12 17:47:21 +000016857 if (sz != 8 && sz != 4 && sz != 2) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000016858 delta = dis_bt_G_E ( vbi, pfx, sz, delta, BtOpReset );
sewardj9ed16802005-08-24 10:46:19 +000016859 break;
16860 case 0xAB: /* BTS Gv,Ev */
16861 if (haveF2orF3(pfx)) goto decode_failure;
sewardj25d23862006-05-12 17:47:21 +000016862 if (sz != 8 && sz != 4 && sz != 2) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000016863 delta = dis_bt_G_E ( vbi, pfx, sz, delta, BtOpSet );
sewardj9ed16802005-08-24 10:46:19 +000016864 break;
16865 case 0xBB: /* BTC Gv,Ev */
16866 if (haveF2orF3(pfx)) goto decode_failure;
sewardj25d23862006-05-12 17:47:21 +000016867 if (sz != 8 && sz != 4 && sz != 2) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000016868 delta = dis_bt_G_E ( vbi, pfx, sz, delta, BtOpComp );
sewardj9ed16802005-08-24 10:46:19 +000016869 break;
sewardj3ca55a12005-01-27 16:06:23 +000016870
16871 /* =-=-=-=-=-=-=-=-=- CMOV =-=-=-=-=-=-=-=-=-=-=-= */
16872
16873 case 0x40:
16874 case 0x41:
16875 case 0x42: /* CMOVBb/CMOVNAEb (cmov below) */
16876 case 0x43: /* CMOVNBb/CMOVAEb (cmov not below) */
16877 case 0x44: /* CMOVZb/CMOVEb (cmov zero) */
16878 case 0x45: /* CMOVNZb/CMOVNEb (cmov not zero) */
16879 case 0x46: /* CMOVBEb/CMOVNAb (cmov below or equal) */
16880 case 0x47: /* CMOVNBEb/CMOVAb (cmov not below or equal) */
16881 case 0x48: /* CMOVSb (cmov negative) */
16882 case 0x49: /* CMOVSb (cmov not negative) */
16883 case 0x4A: /* CMOVP (cmov parity even) */
16884 case 0x4B: /* CMOVNP (cmov parity odd) */
16885 case 0x4C: /* CMOVLb/CMOVNGEb (cmov less) */
16886 case 0x4D: /* CMOVGEb/CMOVNLb (cmov greater or equal) */
16887 case 0x4E: /* CMOVLEb/CMOVNGb (cmov less or equal) */
16888 case 0x4F: /* CMOVGb/CMOVNLEb (cmov greater) */
sewardj5b470602005-02-27 13:10:48 +000016889 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000016890 delta = dis_cmov_E_G(vbi, pfx, sz, (AMD64Condcode)(opc - 0x40), delta);
sewardj3ca55a12005-01-27 16:06:23 +000016891 break;
16892
sewardja6b93d12005-02-17 09:28:28 +000016893 /* =-=-=-=-=-=-=-=-=- CMPXCHG -=-=-=-=-=-=-=-=-=-= */
16894
sewardj7f45b2b2007-11-16 00:18:44 +000016895 case 0xB0: { /* CMPXCHG Gb,Eb */
16896 Bool ok = True;
16897 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000016898 delta = dis_cmpxchg_G_E ( &ok, vbi, pfx, 1, delta );
sewardj7f45b2b2007-11-16 00:18:44 +000016899 if (!ok) goto decode_failure;
16900 break;
16901 }
sewardjd0aa0a52006-08-17 01:20:01 +000016902 case 0xB1: { /* CMPXCHG Gv,Ev (allowed in 16,32,64 bit) */
16903 Bool ok = True;
sewardj5b470602005-02-27 13:10:48 +000016904 if (haveF2orF3(pfx)) goto decode_failure;
sewardjd0aa0a52006-08-17 01:20:01 +000016905 if (sz != 2 && sz != 4 && sz != 8) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000016906 delta = dis_cmpxchg_G_E ( &ok, vbi, pfx, sz, delta );
sewardjd0aa0a52006-08-17 01:20:01 +000016907 if (!ok) goto decode_failure;
sewardja6b93d12005-02-17 09:28:28 +000016908 break;
sewardjd0aa0a52006-08-17 01:20:01 +000016909 }
sewardje9d8a262009-07-01 08:06:34 +000016910
sewardjd0aa0a52006-08-17 01:20:01 +000016911 case 0xC7: { /* CMPXCHG8B Ev, CMPXCHG16B Ev */
sewardj1fb8c922009-07-12 12:56:53 +000016912 IRType elemTy = sz==4 ? Ity_I32 : Ity_I64;
16913 IRTemp expdHi = newTemp(elemTy);
16914 IRTemp expdLo = newTemp(elemTy);
16915 IRTemp dataHi = newTemp(elemTy);
16916 IRTemp dataLo = newTemp(elemTy);
16917 IRTemp oldHi = newTemp(elemTy);
16918 IRTemp oldLo = newTemp(elemTy);
16919 IRTemp flags_old = newTemp(Ity_I64);
16920 IRTemp flags_new = newTemp(Ity_I64);
16921 IRTemp success = newTemp(Ity_I1);
16922 IROp opOR = sz==4 ? Iop_Or32 : Iop_Or64;
16923 IROp opXOR = sz==4 ? Iop_Xor32 : Iop_Xor64;
16924 IROp opCasCmpEQ = sz==4 ? Iop_CasCmpEQ32 : Iop_CasCmpEQ64;
16925 IRExpr* zero = sz==4 ? mkU32(0) : mkU64(0);
16926 IRTemp expdHi64 = newTemp(Ity_I64);
16927 IRTemp expdLo64 = newTemp(Ity_I64);
sewardje9d8a262009-07-01 08:06:34 +000016928
16929 /* Translate this using a DCAS, even if there is no LOCK
16930 prefix. Life is too short to bother with generating two
16931 different translations for the with/without-LOCK-prefix
16932 cases. */
16933 *expect_CAS = True;
16934
16935 /* Decode, and generate address. */
sewardjd0aa0a52006-08-17 01:20:01 +000016936 if (have66orF2orF3(pfx)) goto decode_failure;
16937 if (sz != 4 && sz != 8) goto decode_failure;
sewardje9d8a262009-07-01 08:06:34 +000016938 if (sz == 8 && !(archinfo->hwcaps & VEX_HWCAPS_AMD64_CX16))
16939 goto decode_failure;
16940 modrm = getUChar(delta);
16941 if (epartIsReg(modrm)) goto decode_failure;
16942 if (gregLO3ofRM(modrm) != 1) goto decode_failure;
16943 addr = disAMode ( &alen, vbi, pfx, delta, dis_buf, 0 );
16944 delta += alen;
16945
16946 /* cmpxchg16b requires an alignment check. */
16947 if (sz == 8)
16948 gen_SEGV_if_not_16_aligned( addr );
16949
16950 /* Get the expected and new values. */
16951 assign( expdHi64, getIReg64(R_RDX) );
16952 assign( expdLo64, getIReg64(R_RAX) );
16953
16954 /* These are the correctly-sized expected and new values.
16955 However, we also get expdHi64/expdLo64 above as 64-bits
16956 regardless, because we will need them later in the 32-bit
16957 case (paradoxically). */
16958 assign( expdHi, sz==4 ? unop(Iop_64to32, mkexpr(expdHi64))
16959 : mkexpr(expdHi64) );
16960 assign( expdLo, sz==4 ? unop(Iop_64to32, mkexpr(expdLo64))
16961 : mkexpr(expdLo64) );
16962 assign( dataHi, sz==4 ? getIReg32(R_RCX) : getIReg64(R_RCX) );
16963 assign( dataLo, sz==4 ? getIReg32(R_RBX) : getIReg64(R_RBX) );
16964
16965 /* Do the DCAS */
16966 stmt( IRStmt_CAS(
16967 mkIRCAS( oldHi, oldLo,
16968 Iend_LE, mkexpr(addr),
16969 mkexpr(expdHi), mkexpr(expdLo),
16970 mkexpr(dataHi), mkexpr(dataLo)
16971 )));
16972
16973 /* success when oldHi:oldLo == expdHi:expdLo */
16974 assign( success,
sewardj1fb8c922009-07-12 12:56:53 +000016975 binop(opCasCmpEQ,
sewardje9d8a262009-07-01 08:06:34 +000016976 binop(opOR,
16977 binop(opXOR, mkexpr(oldHi), mkexpr(expdHi)),
16978 binop(opXOR, mkexpr(oldLo), mkexpr(expdLo))
16979 ),
16980 zero
16981 ));
16982
16983 /* If the DCAS is successful, that is to say oldHi:oldLo ==
16984 expdHi:expdLo, then put expdHi:expdLo back in RDX:RAX,
16985 which is where they came from originally. Both the actual
16986 contents of these two regs, and any shadow values, are
16987 unchanged. If the DCAS fails then we're putting into
16988 RDX:RAX the value seen in memory. */
16989 /* Now of course there's a complication in the 32-bit case
16990 (bah!): if the DCAS succeeds, we need to leave RDX:RAX
16991 unchanged; but if we use the same scheme as in the 64-bit
16992 case, we get hit by the standard rule that a write to the
16993 bottom 32 bits of an integer register zeros the upper 32
16994 bits. And so the upper halves of RDX and RAX mysteriously
16995 become zero. So we have to stuff back in the original
16996 64-bit values which we previously stashed in
16997 expdHi64:expdLo64, even if we're doing a cmpxchg8b. */
16998 /* It's just _so_ much fun ... */
16999 putIRegRDX( 8,
17000 IRExpr_Mux0X( unop(Iop_1Uto8, mkexpr(success)),
17001 sz == 4 ? unop(Iop_32Uto64, mkexpr(oldHi))
17002 : mkexpr(oldHi),
17003 mkexpr(expdHi64)
17004 ));
17005 putIRegRAX( 8,
17006 IRExpr_Mux0X( unop(Iop_1Uto8, mkexpr(success)),
17007 sz == 4 ? unop(Iop_32Uto64, mkexpr(oldLo))
17008 : mkexpr(oldLo),
17009 mkexpr(expdLo64)
17010 ));
17011
17012 /* Copy the success bit into the Z flag and leave the others
17013 unchanged */
17014 assign( flags_old, widenUto64(mk_amd64g_calculate_rflags_all()));
17015 assign(
17016 flags_new,
17017 binop(Iop_Or64,
17018 binop(Iop_And64, mkexpr(flags_old),
17019 mkU64(~AMD64G_CC_MASK_Z)),
17020 binop(Iop_Shl64,
17021 binop(Iop_And64,
17022 unop(Iop_1Uto64, mkexpr(success)), mkU64(1)),
17023 mkU8(AMD64G_CC_SHIFT_Z)) ));
17024
17025 stmt( IRStmt_Put( OFFB_CC_OP, mkU64(AMD64G_CC_OP_COPY) ));
17026 stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(flags_new) ));
17027 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
17028 /* Set NDEP even though it isn't used. This makes
17029 redundant-PUT elimination of previous stores to this field
17030 work better. */
17031 stmt( IRStmt_Put( OFFB_CC_NDEP, mkU64(0) ));
17032
17033 /* Sheesh. Aren't you glad it was me and not you that had to
17034 write and validate all this grunge? */
17035
17036 DIP("cmpxchg8b %s\n", dis_buf);
17037 break;
17038
sewardjd0aa0a52006-08-17 01:20:01 +000017039 }
17040
sewardjd0a12df2005-02-10 02:07:43 +000017041 /* =-=-=-=-=-=-=-=-=- CPUID -=-=-=-=-=-=-=-=-=-=-= */
17042
17043 case 0xA2: { /* CPUID */
17044 /* Uses dirty helper:
17045 void amd64g_dirtyhelper_CPUID ( VexGuestAMD64State* )
17046 declared to mod rax, wr rbx, rcx, rdx
17047 */
17048 IRDirty* d = NULL;
17049 HChar* fName = NULL;
17050 void* fAddr = NULL;
sewardj5b470602005-02-27 13:10:48 +000017051 if (haveF2orF3(pfx)) goto decode_failure;
sewardje9d8a262009-07-01 08:06:34 +000017052 if (archinfo->hwcaps == (VEX_HWCAPS_AMD64_SSE3
17053 |VEX_HWCAPS_AMD64_CX16)) {
17054 fName = "amd64g_dirtyhelper_CPUID_sse3_and_cx16";
17055 fAddr = &amd64g_dirtyhelper_CPUID_sse3_and_cx16;
17056 /* This is a Core-2-like machine */
sewardjd0a12df2005-02-10 02:07:43 +000017057 }
sewardje9d8a262009-07-01 08:06:34 +000017058 else {
17059 /* Give a CPUID for at least a baseline machine, no SSE2
17060 and no CX16 */
17061 fName = "amd64g_dirtyhelper_CPUID_baseline";
17062 fAddr = &amd64g_dirtyhelper_CPUID_baseline;
17063 }
sewardj5117ce12006-01-27 21:20:15 +000017064
sewardjd0a12df2005-02-10 02:07:43 +000017065 vassert(fName); vassert(fAddr);
17066 d = unsafeIRDirty_0_N ( 0/*regparms*/,
17067 fName, fAddr, mkIRExprVec_0() );
17068 /* declare guest state effects */
17069 d->needsBBP = True;
17070 d->nFxState = 4;
17071 d->fxState[0].fx = Ifx_Modify;
17072 d->fxState[0].offset = OFFB_RAX;
17073 d->fxState[0].size = 8;
17074 d->fxState[1].fx = Ifx_Write;
17075 d->fxState[1].offset = OFFB_RBX;
17076 d->fxState[1].size = 8;
sewardj32bfd3e2008-02-10 13:29:19 +000017077 d->fxState[2].fx = Ifx_Modify;
sewardjd0a12df2005-02-10 02:07:43 +000017078 d->fxState[2].offset = OFFB_RCX;
17079 d->fxState[2].size = 8;
17080 d->fxState[3].fx = Ifx_Write;
17081 d->fxState[3].offset = OFFB_RDX;
17082 d->fxState[3].size = 8;
17083 /* execute the dirty call, side-effecting guest state */
17084 stmt( IRStmt_Dirty(d) );
17085 /* CPUID is a serialising insn. So, just in case someone is
17086 using it as a memory fence ... */
sewardjc4356f02007-11-09 21:15:04 +000017087 stmt( IRStmt_MBE(Imbe_Fence) );
sewardjd0a12df2005-02-10 02:07:43 +000017088 DIP("cpuid\n");
17089 break;
17090 }
17091
sewardj5e525292005-01-28 15:13:10 +000017092 /* =-=-=-=-=-=-=-=-=- MOVZX, MOVSX =-=-=-=-=-=-=-= */
17093
17094 case 0xB6: /* MOVZXb Eb,Gv */
sewardj5b470602005-02-27 13:10:48 +000017095 if (haveF2orF3(pfx)) goto decode_failure;
sewardj5e525292005-01-28 15:13:10 +000017096 if (sz != 2 && sz != 4 && sz != 8)
17097 goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000017098 delta = dis_movx_E_G ( vbi, pfx, delta, 1, sz, False );
sewardj5e525292005-01-28 15:13:10 +000017099 break;
17100 case 0xB7: /* MOVZXw Ew,Gv */
sewardj5b470602005-02-27 13:10:48 +000017101 if (haveF2orF3(pfx)) goto decode_failure;
sewardj5e525292005-01-28 15:13:10 +000017102 if (sz != 4 && sz != 8)
17103 goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000017104 delta = dis_movx_E_G ( vbi, pfx, delta, 2, sz, False );
sewardj5e525292005-01-28 15:13:10 +000017105 break;
17106
sewardj03b07cc2005-01-31 18:09:43 +000017107 case 0xBE: /* MOVSXb Eb,Gv */
sewardj5b470602005-02-27 13:10:48 +000017108 if (haveF2orF3(pfx)) goto decode_failure;
sewardj82c9f2f2005-03-02 16:05:13 +000017109 if (sz != 2 && sz != 4 && sz != 8)
sewardj03b07cc2005-01-31 18:09:43 +000017110 goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000017111 delta = dis_movx_E_G ( vbi, pfx, delta, 1, sz, True );
sewardj03b07cc2005-01-31 18:09:43 +000017112 break;
17113 case 0xBF: /* MOVSXw Ew,Gv */
sewardj5b470602005-02-27 13:10:48 +000017114 if (haveF2orF3(pfx)) goto decode_failure;
sewardj03b07cc2005-01-31 18:09:43 +000017115 if (sz != 4 && sz != 8)
17116 goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000017117 delta = dis_movx_E_G ( vbi, pfx, delta, 2, sz, True );
sewardj03b07cc2005-01-31 18:09:43 +000017118 break;
17119
sewardjd20c8852005-01-20 20:04:07 +000017120//.. //-- /* =-=-=-=-=-=-=-=-=-=-= MOVNTI -=-=-=-=-=-=-=-=-= */
17121//.. //--
17122//.. //-- case 0xC3: /* MOVNTI Gv,Ev */
17123//.. //-- vg_assert(sz == 4);
17124//.. //-- modrm = getUChar(eip);
17125//.. //-- vg_assert(!epartIsReg(modrm));
17126//.. //-- t1 = newTemp(cb);
17127//.. //-- uInstr2(cb, GET, 4, ArchReg, gregOfRM(modrm), TempReg, t1);
17128//.. //-- pair = disAMode ( cb, sorb, eip, dis_buf );
17129//.. //-- t2 = LOW24(pair);
17130//.. //-- eip += HI8(pair);
17131//.. //-- uInstr2(cb, STORE, 4, TempReg, t1, TempReg, t2);
17132//.. //-- DIP("movnti %s,%s\n", nameIReg(4,gregOfRM(modrm)), dis_buf);
17133//.. //-- break;
sewardj32b2bbe2005-01-28 00:50:10 +000017134
17135 /* =-=-=-=-=-=-=-=-=- MUL/IMUL =-=-=-=-=-=-=-=-=-= */
17136
17137 case 0xAF: /* IMUL Ev, Gv */
sewardj5b470602005-02-27 13:10:48 +000017138 if (haveF2orF3(pfx)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000017139 delta = dis_mul_E_G ( vbi, pfx, sz, delta );
sewardj32b2bbe2005-01-28 00:50:10 +000017140 break;
17141
sewardjec387ca2006-08-01 18:36:25 +000017142 /* =-=-=-=-=-=-=-=-=- NOPs =-=-=-=-=-=-=-=-=-=-=-= */
17143
17144 case 0x1F:
17145 if (haveF2orF3(pfx)) goto decode_failure;
17146 modrm = getUChar(delta);
17147 if (epartIsReg(modrm)) goto decode_failure;
sewardj2e28ac42008-12-04 00:05:12 +000017148 addr = disAMode ( &alen, vbi, pfx, delta, dis_buf, 0 );
sewardjec387ca2006-08-01 18:36:25 +000017149 delta += alen;
17150 DIP("nop%c %s\n", nameISize(sz), dis_buf);
17151 break;
17152
sewardj1389d4d2005-01-28 13:46:29 +000017153 /* =-=-=-=-=-=-=-=-=- Jcond d32 -=-=-=-=-=-=-=-=-= */
17154 case 0x80:
17155 case 0x81:
17156 case 0x82: /* JBb/JNAEb (jump below) */
17157 case 0x83: /* JNBb/JAEb (jump not below) */
17158 case 0x84: /* JZb/JEb (jump zero) */
17159 case 0x85: /* JNZb/JNEb (jump not zero) */
17160 case 0x86: /* JBEb/JNAb (jump below or equal) */
17161 case 0x87: /* JNBEb/JAb (jump not below or equal) */
17162 case 0x88: /* JSb (jump negative) */
17163 case 0x89: /* JSb (jump not negative) */
17164 case 0x8A: /* JP (jump parity even) */
17165 case 0x8B: /* JNP/JPO (jump parity odd) */
17166 case 0x8C: /* JLb/JNGEb (jump less) */
17167 case 0x8D: /* JGEb/JNLb (jump greater or equal) */
17168 case 0x8E: /* JLEb/JNGb (jump less or equal) */
17169 case 0x8F: /* JGb/JNLEb (jump greater) */
sewardj984d9b12010-01-15 10:53:21 +000017170 { Long jmpDelta;
17171 HChar* comment = "";
sewardj5b470602005-02-27 13:10:48 +000017172 if (haveF2orF3(pfx)) goto decode_failure;
sewardj984d9b12010-01-15 10:53:21 +000017173 jmpDelta = getSDisp32(delta);
17174 d64 = (guest_RIP_bbstart+delta+4) + jmpDelta;
sewardj1389d4d2005-01-28 13:46:29 +000017175 delta += 4;
sewardj984d9b12010-01-15 10:53:21 +000017176 if (resteerCisOk
17177 && vex_control.guest_chase_cond
sewardj0d925b12010-01-17 15:47:01 +000017178 && (Addr64)d64 != (Addr64)guest_RIP_bbstart
sewardj984d9b12010-01-15 10:53:21 +000017179 && jmpDelta < 0
17180 && resteerOkFn( callback_opaque, d64) ) {
17181 /* Speculation: assume this backward branch is taken. So
17182 we need to emit a side-exit to the insn following this
17183 one, on the negation of the condition, and continue at
sewardj0d925b12010-01-17 15:47:01 +000017184 the branch target address (d64). If we wind up back at
17185 the first instruction of the trace, just stop; it's
17186 better to let the IR loop unroller handle that case. */
sewardj984d9b12010-01-15 10:53:21 +000017187 stmt( IRStmt_Exit(
17188 mk_amd64g_calculate_condition(
17189 (AMD64Condcode)(1 ^ (opc - 0x80))),
17190 Ijk_Boring,
17191 IRConst_U64(guest_RIP_bbstart+delta) ) );
17192 dres.whatNext = Dis_ResteerC;
17193 dres.continueAt = d64;
17194 comment = "(assumed taken)";
17195 }
17196 else
17197 if (resteerCisOk
17198 && vex_control.guest_chase_cond
sewardj0d925b12010-01-17 15:47:01 +000017199 && (Addr64)d64 != (Addr64)guest_RIP_bbstart
sewardj984d9b12010-01-15 10:53:21 +000017200 && jmpDelta >= 0
17201 && resteerOkFn( callback_opaque, guest_RIP_bbstart+delta ) ) {
17202 /* Speculation: assume this forward branch is not taken.
17203 So we need to emit a side-exit to d64 (the dest) and
17204 continue disassembling at the insn immediately
17205 following this one. */
17206 stmt( IRStmt_Exit(
sewardj0d925b12010-01-17 15:47:01 +000017207 mk_amd64g_calculate_condition((AMD64Condcode)
17208 (opc - 0x80)),
sewardj984d9b12010-01-15 10:53:21 +000017209 Ijk_Boring,
17210 IRConst_U64(d64) ) );
17211 dres.whatNext = Dis_ResteerC;
17212 dres.continueAt = guest_RIP_bbstart+delta;
17213 comment = "(assumed not taken)";
17214 }
17215 else {
17216 /* Conservative default translation - end the block at
17217 this point. */
17218 jcc_01( (AMD64Condcode)(opc - 0x80),
17219 guest_RIP_bbstart+delta,
17220 d64 );
17221 dres.whatNext = Dis_StopHere;
17222 }
17223 DIP("j%s-32 0x%llx %s\n", name_AMD64Condcode(opc - 0x80), d64, comment);
sewardj1389d4d2005-01-28 13:46:29 +000017224 break;
sewardj984d9b12010-01-15 10:53:21 +000017225 }
sewardj1389d4d2005-01-28 13:46:29 +000017226
sewardjb04a47c2005-08-10 12:27:46 +000017227 /* =-=-=-=-=-=-=-=-=- PREFETCH =-=-=-=-=-=-=-=-=-= */
17228 case 0x0D: /* 0F 0D /0 -- prefetch mem8 */
17229 /* 0F 0D /1 -- prefetchw mem8 */
17230 if (have66orF2orF3(pfx)) goto decode_failure;
17231 modrm = getUChar(delta);
17232 if (epartIsReg(modrm)) goto decode_failure;
17233 if (gregLO3ofRM(modrm) != 0 && gregLO3ofRM(modrm) != 1)
17234 goto decode_failure;
17235
sewardj2e28ac42008-12-04 00:05:12 +000017236 addr = disAMode ( &alen, vbi, pfx, delta, dis_buf, 0 );
sewardjb04a47c2005-08-10 12:27:46 +000017237 delta += alen;
17238
17239 switch (gregLO3ofRM(modrm)) {
17240 case 0: DIP("prefetch %s\n", dis_buf); break;
17241 case 1: DIP("prefetchw %s\n", dis_buf); break;
17242 default: vassert(0); /*NOTREACHED*/
17243 }
17244 break;
17245
sewardj31191072005-02-05 18:24:47 +000017246 /* =-=-=-=-=-=-=-=-=- RDTSC -=-=-=-=-=-=-=-=-=-=-= */
sewardjbc6af532005-08-23 23:16:51 +000017247 case 0x31: { /* RDTSC */
17248 IRTemp val = newTemp(Ity_I64);
17249 IRExpr** args = mkIRExprVec_0();
17250 IRDirty* d = unsafeIRDirty_1_N (
17251 val,
17252 0/*regparms*/,
17253 "amd64g_dirtyhelper_RDTSC",
17254 &amd64g_dirtyhelper_RDTSC,
17255 args
17256 );
17257 if (have66orF2orF3(pfx)) goto decode_failure;
17258 /* execute the dirty call, dumping the result in val. */
17259 stmt( IRStmt_Dirty(d) );
17260 putIRegRDX(4, unop(Iop_64HIto32, mkexpr(val)));
17261 putIRegRAX(4, unop(Iop_64to32, mkexpr(val)));
sewardj31191072005-02-05 18:24:47 +000017262 DIP("rdtsc\n");
17263 break;
sewardjbc6af532005-08-23 23:16:51 +000017264 }
sewardj31191072005-02-05 18:24:47 +000017265
sewardjd20c8852005-01-20 20:04:07 +000017266//.. /* =-=-=-=-=-=-=-=-=- PUSH/POP Sreg =-=-=-=-=-=-=-=-=-= */
17267//..
17268//.. case 0xA1: /* POP %FS */
17269//.. dis_pop_segreg( R_FS, sz ); break;
17270//.. case 0xA9: /* POP %GS */
17271//.. dis_pop_segreg( R_GS, sz ); break;
17272//..
17273//.. case 0xA0: /* PUSH %FS */
17274//.. dis_push_segreg( R_FS, sz ); break;
17275//.. case 0xA8: /* PUSH %GS */
17276//.. dis_push_segreg( R_GS, sz ); break;
sewardj118b23e2005-01-29 02:14:44 +000017277
17278 /* =-=-=-=-=-=-=-=-=- SETcc Eb =-=-=-=-=-=-=-=-=-= */
17279 case 0x90:
17280 case 0x91:
17281 case 0x92: /* set-Bb/set-NAEb (set if below) */
17282 case 0x93: /* set-NBb/set-AEb (set if not below) */
17283 case 0x94: /* set-Zb/set-Eb (set if zero) */
17284 case 0x95: /* set-NZb/set-NEb (set if not zero) */
17285 case 0x96: /* set-BEb/set-NAb (set if below or equal) */
17286 case 0x97: /* set-NBEb/set-Ab (set if not below or equal) */
17287 case 0x98: /* set-Sb (set if negative) */
17288 case 0x99: /* set-Sb (set if not negative) */
17289 case 0x9A: /* set-P (set if parity even) */
17290 case 0x9B: /* set-NP (set if parity odd) */
17291 case 0x9C: /* set-Lb/set-NGEb (set if less) */
17292 case 0x9D: /* set-GEb/set-NLb (set if greater or equal) */
17293 case 0x9E: /* set-LEb/set-NGb (set if less or equal) */
17294 case 0x9F: /* set-Gb/set-NLEb (set if greater) */
sewardj5b470602005-02-27 13:10:48 +000017295 if (haveF2orF3(pfx)) goto decode_failure;
sewardj118b23e2005-01-29 02:14:44 +000017296 t1 = newTemp(Ity_I8);
17297 assign( t1, unop(Iop_1Uto8,mk_amd64g_calculate_condition(opc-0x90)) );
17298 modrm = getUChar(delta);
17299 if (epartIsReg(modrm)) {
17300 delta++;
sewardj5b470602005-02-27 13:10:48 +000017301 putIRegE(1, pfx, modrm, mkexpr(t1));
sewardj118b23e2005-01-29 02:14:44 +000017302 DIP("set%s %s\n", name_AMD64Condcode(opc-0x90),
sewardj5b470602005-02-27 13:10:48 +000017303 nameIRegE(1,pfx,modrm));
sewardj118b23e2005-01-29 02:14:44 +000017304 } else {
sewardj2e28ac42008-12-04 00:05:12 +000017305 addr = disAMode ( &alen, vbi, pfx, delta, dis_buf, 0 );
sewardj5cc00ff2005-03-27 04:48:32 +000017306 delta += alen;
17307 storeLE( mkexpr(addr), mkexpr(t1) );
17308 DIP("set%s %s\n", name_AMD64Condcode(opc-0x90), dis_buf);
sewardj118b23e2005-01-29 02:14:44 +000017309 }
17310 break;
17311
sewardj33ef9c22005-11-04 20:05:57 +000017312 /* =-=-=-=-=-=-=-=-=- SHLD/SHRD -=-=-=-=-=-=-=-=-= */
17313
sewardj1287ab42006-05-12 21:03:48 +000017314 case 0xA4: /* SHLDv imm8,Gv,Ev */
17315 modrm = getUChar(delta);
17316 d64 = delta + lengthAMode(pfx, delta);
17317 vex_sprintf(dis_buf, "$%d", (Int)getUChar(d64));
17318 delta = dis_SHLRD_Gv_Ev (
sewardj2e28ac42008-12-04 00:05:12 +000017319 vbi, pfx, delta, modrm, sz,
sewardj1287ab42006-05-12 21:03:48 +000017320 mkU8(getUChar(d64)), True, /* literal */
17321 dis_buf, True /* left */ );
17322 break;
sewardj33ef9c22005-11-04 20:05:57 +000017323 case 0xA5: /* SHLDv %cl,Gv,Ev */
17324 modrm = getUChar(delta);
17325 delta = dis_SHLRD_Gv_Ev (
sewardj2e28ac42008-12-04 00:05:12 +000017326 vbi, pfx, delta, modrm, sz,
sewardj33ef9c22005-11-04 20:05:57 +000017327 getIRegCL(), False, /* not literal */
17328 "%cl", True /* left */ );
17329 break;
17330
sewardj75ce3652005-11-04 20:49:36 +000017331 case 0xAC: /* SHRDv imm8,Gv,Ev */
17332 modrm = getUChar(delta);
17333 d64 = delta + lengthAMode(pfx, delta);
17334 vex_sprintf(dis_buf, "$%d", (Int)getUChar(d64));
17335 delta = dis_SHLRD_Gv_Ev (
sewardj2e28ac42008-12-04 00:05:12 +000017336 vbi, pfx, delta, modrm, sz,
sewardj75ce3652005-11-04 20:49:36 +000017337 mkU8(getUChar(d64)), True, /* literal */
17338 dis_buf, False /* right */ );
17339 break;
sewardj33ef9c22005-11-04 20:05:57 +000017340 case 0xAD: /* SHRDv %cl,Gv,Ev */
17341 modrm = getUChar(delta);
17342 delta = dis_SHLRD_Gv_Ev (
sewardj2e28ac42008-12-04 00:05:12 +000017343 vbi, pfx, delta, modrm, sz,
sewardj33ef9c22005-11-04 20:05:57 +000017344 getIRegCL(), False, /* not literal */
17345 "%cl", False /* right */);
17346 break;
sewardje1698952005-02-08 15:02:39 +000017347
17348 /* =-=-=-=-=-=-=-=-=- SYSCALL -=-=-=-=-=-=-=-=-=-= */
17349 case 0x05: /* SYSCALL */
sewardj9e6491a2005-07-02 19:24:10 +000017350 guest_RIP_next_mustcheck = True;
17351 guest_RIP_next_assumed = guest_RIP_bbstart + delta;
17352 putIReg64( R_RCX, mkU64(guest_RIP_next_assumed) );
sewardje1698952005-02-08 15:02:39 +000017353 /* It's important that all guest state is up-to-date
17354 at this point. So we declare an end-of-block here, which
17355 forces any cached guest state to be flushed. */
sewardj4fa325a2005-11-03 13:27:24 +000017356 jmp_lit(Ijk_Sys_syscall, guest_RIP_next_assumed);
17357 dres.whatNext = Dis_StopHere;
17358 DIP("syscall\n");
17359 break;
sewardje1698952005-02-08 15:02:39 +000017360
sewardjb4fd2e72005-03-23 13:34:11 +000017361 /* =-=-=-=-=-=-=-=-=- XADD -=-=-=-=-=-=-=-=-=-= */
17362
sewardj0d923d72008-05-13 21:21:16 +000017363 case 0xC0: { /* XADD Gb,Eb */
17364 Bool decode_OK = False;
sewardj2e28ac42008-12-04 00:05:12 +000017365 delta = dis_xadd_G_E ( &decode_OK, vbi, pfx, 1, delta );
sewardj0d923d72008-05-13 21:21:16 +000017366 if (!decode_OK)
17367 goto decode_failure;
17368 break;
17369 }
sewardjb4fd2e72005-03-23 13:34:11 +000017370 case 0xC1: { /* XADD Gv,Ev */
17371 Bool decode_OK = False;
sewardj2e28ac42008-12-04 00:05:12 +000017372 delta = dis_xadd_G_E ( &decode_OK, vbi, pfx, sz, delta );
sewardjb4fd2e72005-03-23 13:34:11 +000017373 if (!decode_OK)
17374 goto decode_failure;
17375 break;
17376 }
17377
sewardj8711f662005-05-09 17:52:56 +000017378 /* =-=-=-=-=-=-=-=-=- MMXery =-=-=-=-=-=-=-=-=-=-= */
17379
sewardj3d8107c2005-05-09 22:23:38 +000017380 case 0x71:
17381 case 0x72:
17382 case 0x73: /* PSLLgg/PSRAgg/PSRLgg mmxreg by imm8 */
17383
17384 case 0x6E: /* MOVD (src)ireg-or-mem, (dst)mmxreg */
17385 case 0x7E: /* MOVD (src)mmxreg, (dst)ireg-or-mem */
sewardj8711f662005-05-09 17:52:56 +000017386 case 0x7F: /* MOVQ (src)mmxreg, (dst)mmxreg-or-mem */
17387 case 0x6F: /* MOVQ (src)mmxreg-or-mem, (dst)mmxreg */
17388
17389 case 0xFC:
17390 case 0xFD:
17391 case 0xFE: /* PADDgg (src)mmxreg-or-mem, (dst)mmxreg */
17392
17393 case 0xEC:
17394 case 0xED: /* PADDSgg (src)mmxreg-or-mem, (dst)mmxreg */
17395
17396 case 0xDC:
17397 case 0xDD: /* PADDUSgg (src)mmxreg-or-mem, (dst)mmxreg */
17398
17399 case 0xF8:
17400 case 0xF9:
17401 case 0xFA: /* PSUBgg (src)mmxreg-or-mem, (dst)mmxreg */
17402
17403 case 0xE8:
17404 case 0xE9: /* PSUBSgg (src)mmxreg-or-mem, (dst)mmxreg */
17405
17406 case 0xD8:
17407 case 0xD9: /* PSUBUSgg (src)mmxreg-or-mem, (dst)mmxreg */
17408
17409 case 0xE5: /* PMULHW (src)mmxreg-or-mem, (dst)mmxreg */
17410 case 0xD5: /* PMULLW (src)mmxreg-or-mem, (dst)mmxreg */
17411
17412 case 0xF5: /* PMADDWD (src)mmxreg-or-mem, (dst)mmxreg */
17413
17414 case 0x74:
17415 case 0x75:
17416 case 0x76: /* PCMPEQgg (src)mmxreg-or-mem, (dst)mmxreg */
17417
17418 case 0x64:
17419 case 0x65:
17420 case 0x66: /* PCMPGTgg (src)mmxreg-or-mem, (dst)mmxreg */
17421
17422 case 0x6B: /* PACKSSDW (src)mmxreg-or-mem, (dst)mmxreg */
17423 case 0x63: /* PACKSSWB (src)mmxreg-or-mem, (dst)mmxreg */
17424 case 0x67: /* PACKUSWB (src)mmxreg-or-mem, (dst)mmxreg */
17425
17426 case 0x68:
17427 case 0x69:
17428 case 0x6A: /* PUNPCKHgg (src)mmxreg-or-mem, (dst)mmxreg */
17429
17430 case 0x60:
17431 case 0x61:
17432 case 0x62: /* PUNPCKLgg (src)mmxreg-or-mem, (dst)mmxreg */
17433
17434 case 0xDB: /* PAND (src)mmxreg-or-mem, (dst)mmxreg */
17435 case 0xDF: /* PANDN (src)mmxreg-or-mem, (dst)mmxreg */
17436 case 0xEB: /* POR (src)mmxreg-or-mem, (dst)mmxreg */
17437 case 0xEF: /* PXOR (src)mmxreg-or-mem, (dst)mmxreg */
17438
17439 case 0xF1: /* PSLLgg (src)mmxreg-or-mem, (dst)mmxreg */
17440 case 0xF2:
17441 case 0xF3:
17442
17443 case 0xD1: /* PSRLgg (src)mmxreg-or-mem, (dst)mmxreg */
17444 case 0xD2:
17445 case 0xD3:
17446
17447 case 0xE1: /* PSRAgg (src)mmxreg-or-mem, (dst)mmxreg */
17448 case 0xE2:
17449 {
sewardj270def42005-07-03 01:03:01 +000017450 Long delta0 = delta-1;
sewardj8711f662005-05-09 17:52:56 +000017451 Bool decode_OK = False;
17452
17453 /* If sz==2 this is SSE, and we assume sse idec has
17454 already spotted those cases by now. */
sewardj3d8107c2005-05-09 22:23:38 +000017455 if (sz != 4 && sz != 8)
sewardj8711f662005-05-09 17:52:56 +000017456 goto decode_failure;
17457 if (have66orF2orF3(pfx))
17458 goto decode_failure;
17459
sewardj2e28ac42008-12-04 00:05:12 +000017460 delta = dis_MMX ( &decode_OK, vbi, pfx, sz, delta-1 );
sewardj8711f662005-05-09 17:52:56 +000017461 if (!decode_OK) {
17462 delta = delta0;
17463 goto decode_failure;
17464 }
17465 break;
17466 }
17467
sewardjae84d782006-04-13 22:06:35 +000017468 case 0x0E: /* FEMMS */
sewardj8711f662005-05-09 17:52:56 +000017469 case 0x77: /* EMMS */
17470 if (sz != 4)
17471 goto decode_failure;
17472 do_EMMS_preamble();
sewardjae84d782006-04-13 22:06:35 +000017473 DIP("{f}emms\n");
sewardj8711f662005-05-09 17:52:56 +000017474 break;
sewardj3ca55a12005-01-27 16:06:23 +000017475
sewardjb9dc2432010-06-07 16:22:22 +000017476 /* =-=-=-=-=-=-=-=-=- SGDT and SIDT =-=-=-=-=-=-=-=-=-=-= */
17477 case 0x01: /* 0F 01 /0 -- SGDT */
17478 /* 0F 01 /1 -- SIDT */
17479 {
17480 /* This is really revolting, but ... since each processor
17481 (core) only has one IDT and one GDT, just let the guest
17482 see it (pass-through semantics). I can't see any way to
17483 construct a faked-up value, so don't bother to try. */
17484 modrm = getUChar(delta);
17485 addr = disAMode ( &alen, vbi, pfx, delta, dis_buf, 0 );
17486 delta += alen;
17487 if (epartIsReg(modrm)) goto decode_failure;
17488 if (gregLO3ofRM(modrm) != 0 && gregLO3ofRM(modrm) != 1)
17489 goto decode_failure;
17490 switch (gregLO3ofRM(modrm)) {
17491 case 0: DIP("sgdt %s\n", dis_buf); break;
17492 case 1: DIP("sidt %s\n", dis_buf); break;
17493 default: vassert(0); /*NOTREACHED*/
17494 }
17495
17496 IRDirty* d = unsafeIRDirty_0_N (
17497 0/*regparms*/,
17498 "amd64g_dirtyhelper_SxDT",
17499 &amd64g_dirtyhelper_SxDT,
17500 mkIRExprVec_2( mkexpr(addr),
17501 mkU64(gregLO3ofRM(modrm)) )
17502 );
17503 /* declare we're writing memory */
17504 d->mFx = Ifx_Write;
17505 d->mAddr = mkexpr(addr);
17506 d->mSize = 6;
17507 stmt( IRStmt_Dirty(d) );
17508 break;
17509 }
17510
sewardj3ca55a12005-01-27 16:06:23 +000017511 /* =-=-=-=-=-=-=-=-=- unimp2 =-=-=-=-=-=-=-=-=-=-= */
17512
17513 default:
17514 goto decode_failure;
17515 } /* switch (opc) for the 2-byte opcodes */
17516 goto decode_success;
17517 } /* case 0x0F: of primary opcode */
sewardjdf0e0022005-01-25 15:48:43 +000017518
17519 /* ------------------------ ??? ------------------------ */
17520
17521 default:
17522 decode_failure:
17523 /* All decode failures end up here. */
17524 vex_printf("vex amd64->IR: unhandled instruction bytes: "
sewardjd166e282008-02-06 11:42:45 +000017525 "0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
sewardj8c332e22005-01-28 01:36:56 +000017526 (Int)getUChar(delta_start+0),
17527 (Int)getUChar(delta_start+1),
17528 (Int)getUChar(delta_start+2),
sewardjd166e282008-02-06 11:42:45 +000017529 (Int)getUChar(delta_start+3),
17530 (Int)getUChar(delta_start+4),
17531 (Int)getUChar(delta_start+5) );
sewardjdf0e0022005-01-25 15:48:43 +000017532
17533 /* Tell the dispatcher that this insn cannot be decoded, and so has
17534 not been executed, and (is currently) the next to be executed.
17535 RIP should be up-to-date since it made so at the start of each
17536 insn, but nevertheless be paranoid and update it again right
17537 now. */
sewardj9e6491a2005-07-02 19:24:10 +000017538 stmt( IRStmt_Put( OFFB_RIP, mkU64(guest_RIP_curr_instr) ) );
17539 jmp_lit(Ijk_NoDecode, guest_RIP_curr_instr);
17540 dres.whatNext = Dis_StopHere;
17541 dres.len = 0;
sewardje9d8a262009-07-01 08:06:34 +000017542 /* We also need to say that a CAS is not expected now, regardless
17543 of what it might have been set to at the start of the function,
17544 since the IR that we've emitted just above (to synthesis a
17545 SIGILL) does not involve any CAS, and presumably no other IR has
17546 been emitted for this (non-decoded) insn. */
17547 *expect_CAS = False;
sewardj9e6491a2005-07-02 19:24:10 +000017548 return dres;
sewardjdf0e0022005-01-25 15:48:43 +000017549
17550 } /* switch (opc) for the main (primary) opcode switch. */
17551
17552 decode_success:
17553 /* All decode successes end up here. */
17554 DIP("\n");
sewardj9e6491a2005-07-02 19:24:10 +000017555 dres.len = (Int)toUInt(delta - delta_start);
17556 return dres;
sewardjdf0e0022005-01-25 15:48:43 +000017557}
17558
17559#undef DIP
17560#undef DIS
sewardjd20c8852005-01-20 20:04:07 +000017561
sewardj9e6491a2005-07-02 19:24:10 +000017562
17563/*------------------------------------------------------------*/
17564/*--- Top-level fn ---*/
17565/*------------------------------------------------------------*/
17566
17567/* Disassemble a single instruction into IR. The instruction
17568 is located in host memory at &guest_code[delta]. */
17569
sewardjdd40fdf2006-12-24 02:20:24 +000017570DisResult disInstr_AMD64 ( IRSB* irsb_IN,
sewardj9e6491a2005-07-02 19:24:10 +000017571 Bool put_IP,
sewardjc716aea2006-01-17 01:48:46 +000017572 Bool (*resteerOkFn) ( void*, Addr64 ),
sewardj984d9b12010-01-15 10:53:21 +000017573 Bool resteerCisOk,
sewardjc716aea2006-01-17 01:48:46 +000017574 void* callback_opaque,
sewardj9e6491a2005-07-02 19:24:10 +000017575 UChar* guest_code_IN,
17576 Long delta,
17577 Addr64 guest_IP,
sewardja5f55da2006-04-30 23:37:32 +000017578 VexArch guest_arch,
sewardj9e6491a2005-07-02 19:24:10 +000017579 VexArchInfo* archinfo,
sewardjdd40fdf2006-12-24 02:20:24 +000017580 VexAbiInfo* abiinfo,
sewardj9e6491a2005-07-02 19:24:10 +000017581 Bool host_bigendian_IN )
17582{
sewardje9d8a262009-07-01 08:06:34 +000017583 Int i, x1, x2;
17584 Bool expect_CAS, has_CAS;
sewardj9e6491a2005-07-02 19:24:10 +000017585 DisResult dres;
17586
17587 /* Set globals (see top of this file) */
sewardja5f55da2006-04-30 23:37:32 +000017588 vassert(guest_arch == VexArchAMD64);
sewardj9e6491a2005-07-02 19:24:10 +000017589 guest_code = guest_code_IN;
sewardjdd40fdf2006-12-24 02:20:24 +000017590 irsb = irsb_IN;
sewardj9e6491a2005-07-02 19:24:10 +000017591 host_is_bigendian = host_bigendian_IN;
17592 guest_RIP_curr_instr = guest_IP;
17593 guest_RIP_bbstart = guest_IP - delta;
17594
17595 /* We'll consult these after doing disInstr_AMD64_WRK. */
17596 guest_RIP_next_assumed = 0;
17597 guest_RIP_next_mustcheck = False;
17598
sewardje9d8a262009-07-01 08:06:34 +000017599 x1 = irsb_IN->stmts_used;
17600 expect_CAS = False;
17601 dres = disInstr_AMD64_WRK ( &expect_CAS, put_IP, resteerOkFn,
sewardj984d9b12010-01-15 10:53:21 +000017602 resteerCisOk,
sewardje9d8a262009-07-01 08:06:34 +000017603 callback_opaque,
sewardjdd40fdf2006-12-24 02:20:24 +000017604 delta, archinfo, abiinfo );
sewardje9d8a262009-07-01 08:06:34 +000017605 x2 = irsb_IN->stmts_used;
17606 vassert(x2 >= x1);
sewardj9e6491a2005-07-02 19:24:10 +000017607
17608 /* If disInstr_AMD64_WRK tried to figure out the next rip, check it
17609 got it right. Failure of this assertion is serious and denotes
17610 a bug in disInstr. */
17611 if (guest_RIP_next_mustcheck
17612 && guest_RIP_next_assumed != guest_RIP_curr_instr + dres.len) {
17613 vex_printf("\n");
17614 vex_printf("assumed next %%rip = 0x%llx\n",
17615 guest_RIP_next_assumed );
17616 vex_printf(" actual next %%rip = 0x%llx\n",
17617 guest_RIP_curr_instr + dres.len );
sewardje9d8a262009-07-01 08:06:34 +000017618 vpanic("disInstr_AMD64: disInstr miscalculated next %rip");
17619 }
17620
17621 /* See comment at the top of disInstr_AMD64_WRK for meaning of
17622 expect_CAS. Here, we (sanity-)check for the presence/absence of
17623 IRCAS as directed by the returned expect_CAS value. */
17624 has_CAS = False;
17625 for (i = x1; i < x2; i++) {
17626 if (irsb_IN->stmts[i]->tag == Ist_CAS)
17627 has_CAS = True;
17628 }
17629
17630 if (expect_CAS != has_CAS) {
17631 /* inconsistency detected. re-disassemble the instruction so as
17632 to generate a useful error message; then assert. */
17633 vex_traceflags |= VEX_TRACE_FE;
17634 dres = disInstr_AMD64_WRK ( &expect_CAS, put_IP, resteerOkFn,
sewardj984d9b12010-01-15 10:53:21 +000017635 resteerCisOk,
sewardje9d8a262009-07-01 08:06:34 +000017636 callback_opaque,
17637 delta, archinfo, abiinfo );
17638 for (i = x1; i < x2; i++) {
17639 vex_printf("\t\t");
17640 ppIRStmt(irsb_IN->stmts[i]);
17641 vex_printf("\n");
17642 }
17643 /* Failure of this assertion is serious and denotes a bug in
17644 disInstr. */
17645 vpanic("disInstr_AMD64: inconsistency in LOCK prefix handling");
sewardj9e6491a2005-07-02 19:24:10 +000017646 }
17647
17648 return dres;
17649}
17650
17651
17652
sewardjd20c8852005-01-20 20:04:07 +000017653/*--------------------------------------------------------------------*/
sewardjcef7d3e2009-07-02 12:21:59 +000017654/*--- end guest_amd64_toIR.c ---*/
sewardjd20c8852005-01-20 20:04:07 +000017655/*--------------------------------------------------------------------*/